use v6.d.PREVIEW; unit module MaildirIndexer::Parser; use MaildirIndexer::Email; my @separators = ( "\x0a\x0d\x0a\x0d", "\x0d\x0a\x0d\x0a", "\x0a\x0a", "\x0d\x0d", ); my grammar Message { regex TOP { } token newline { [\x0d\x0a] | [\x0a\x0d] | \x0a | \x0d } token separator { @separators } token body { .* } regex headers {
+ % } regex header { \: \h* || } token name { <-[:\s]>+ } regex value { + % [ \h+] } token line { \N* } token junk { \N+ } } my class Message-actions { has $.path = IO; method TOP($/) { make MaildirIndexer::Email.new( headers => $/.made, body => $/.Str, path => $.path, ); } method headers($/) { make %( flat |$/
ยป.made ); } method header($/) { make $/ ?? () !! ( $/.Str.lc => $/.made ); } method value($/) { make $/.join(' ') } } multi parse-email(IO::Path:D $p --> MaildirIndexer::Email) is export { return parse-email($p.slurp(:enc), path => $p); } multi parse-email(IO::Path:D $p, :$headers-only! --> MaildirIndexer::Email) is export { return parse-email( $p.lines( :enc, :nl-in(@separators), :!chomp, )[0], path => $p, ); } multi parse-email(IO::Socket::Async:D $s --> MaildirIndexer::Email) is export { my $string; react { whenever $s.Supply(:enc) { $string ~= $_; done if $string ~~ /@separators/; } } return parse-email($string); } multi parse-email(Str:D $email-str, :$path = IO --> MaildirIndexer::Email) is export { CATCH { warn .perl; return Nil }; with Message.parse($email-str,:actions(Message-actions.new(:$path))) { return .made; } return Nil; }