Current section

Files

Jump to
blop lib imap parser.ex
Raw

lib/imap/parser.ex

defmodule Blop.Parser do
@external_resource "priv/imap.abnf"
use AbnfParsec,
abnf_file: "priv/imap.abnf",
transform: %{
"text" => {:reduce, {List, :to_string, []}},
"atom" => {:reduce, {List, :to_string, []}},
"tag" => {:reduce, {List, :to_string, []}},
"mailbox" => {:reduce, {List, :to_string, []}},
"date-year" => {:reduce, {List, :to_string, []}},
"date-day-fixed" => {:reduce, {List, :to_string, []}},
"time" => {:reduce, {List, :to_string, []}},
"zone" => {:reduce, {List, :to_string, []}},
"quoted" => {:reduce, {List, :to_string, []}},
"astring" => {:reduce, {List, :to_string, []}}
},
unbox: [
"TEXT-CHAR",
"ATOM-CHAR",
"ASTRING-CHAR",
"QUOTED-CHAR",
"astring",
"nstring",
"string",
"resp-text-code",
"text",
"quoted",
"digit-nz",
"CHAR8",
"nil"
],
unwrap: [
"flag",
"atom",
"mailbox",
"number",
"date-year",
"date-month",
"date-day-fixed",
"time",
"zone"
],
skip: ["nz-number", "number", "literal"],
ignore: ["SP", "CRLF", "DQUOTE"]
defparsec :number,
integer(min: 1) |> unwrap_and_tag(:number)
defparsec :nz_number,
integer(min: 1) |> unwrap_and_tag(:nz_number)
defcombinatorp :literal_text,
repeat_while(ascii_char([{:not, 0}]), {:not_end_of_literal, []})
|> reduce({List, :to_string, []})
defparsec :literal,
ignore(string("{"))
|> parsec(:number)
|> ignore(string("}"))
|> post_traverse({:set_literal_size, []})
|> ignore(parsec(:crlf))
|> parsec(:literal_text)
|> tag(:literal)
defp set_literal_size(rest, [number: number] = args, context, _, _) do
{rest, args, Map.put(context, :literal_size, number)}
end
defp not_end_of_literal(_rest, %{literal_size: 0} = context, _, _) do
{:halt, Map.delete(context, :literal_size)}
end
defp not_end_of_literal(_rest, %{literal_size: size} = context, _, _) when size > 0 do
{:cont, %{context | literal_size: size - 1}}
end
end