! Copyright (C) 2014 Roberto López ! See http://factorcode.org/license.txt for BSD license. USING: kernel accessors formatting peg peg.ebnf strings sequences present sequences.deep continuations ; IN: email [[ ignore ]] Letter = [a-zA-Z] Digit = [0-9] Atom = (Letter|Digit|[)(!#$%&'*+/=?^_`{|}~-])+ => [[ >string ast-atom boa ]] Escape-char = "\\" => [[ 92 ]] | "\\n" => [[ 10 ]] | "\\r" => [[ 13 ]] | "\\t" => [[ 9 ]] String-char = (Escape-char | !('"') .)* => [[ >string ]] String = '"' String-char '"' => [[ concat ast-string boa ]] Special = "(" | ")" | "<" | ">" | "@" | "," | ":" | "\" | '"' | "." | "[" | "]" Tok = Spaces ( Atom | String | Special ) Toks = Tok* Spaces ;EBNF PRIVATE> TUPLE: email local domain ; C: email M: email present [ local>> ] [ domain>> ] bi "@" swap 3append ; TUPLE: mailbox name email ; C: mailbox M: mailbox present [ name>> present ] [ email>> present ] [ name>> ] tri [ "%s <%s>" sprintf ] [ nip ] if ; EBNF: email-ebnf tokenizer = default nl = "\r" "\n" | "\n" tokenizer = Atom = . ?[ ast-atom? ]? => [[ value>> ]] String = . ?[ ast-string? ]? => [[ value>> ]] Word = Atom | String Phrase = Word ( Word )* => [[ flatten " " join ]] Local-Part = Word ("." Word)* => [[ flatten concat ]] Domain-Ref = Atom Sub-Domain = Domain-Ref Domain = Sub-Domain ("." Sub-Domain)* => [[ flatten concat ]] Addr-Spec = Local-Part:l "@" Domain:d => [[ l d ]] Route-Addr = "<" Addr-Spec:as ">" => [[ as ]] Named-Addr-Spec = Phrase? Route-Addr => [[ first2 ]] Mailbox = Addr-Spec => [[ f swap ]] | Named-Addr-Spec ;EBNF : >mailbox ( string -- mailbox/f ) [ email-ebnf ] [ 2drop f ] recover ;