moduleText.Email.Parser(addrSpec,localPart,domainPart,EmailAddress,toByteString)whereimportControl.ApplicativeimportqualifiedData.ByteString.Char8asBSimportData.ByteString(ByteString)importData.Char(chr)importData.Attoparsec.ByteString.Char8importData.Attoparsec.Combinator-- | Represents an email address.dataEmailAddress=EmailAddressByteStringByteStringderiving(Eq,Ord)instanceShowEmailAddresswhereshow=BS.unpack.toByteString-- | Converts an email address back to a ByteStringtoByteString(EmailAddressld)=BS.concat[l,BS.singleton'@',d]-- | Extracts the local part of an email address. localPart::EmailAddress->ByteStringlocalPart(EmailAddresslocal_)=local-- | Extracts the domain part of an email address.domainPart::EmailAddress->ByteStringdomainPart(EmailAddress_domain)=domain-- | A parser for email addresses.addrSpec=dolocalPart<-localchar'@'domainPart<-domainendOfInputreturn(EmailAddresslocalPartdomainPart)local=dottedAtomsdomain=dottedAtoms<|>domainLiteraldottedAtoms=BS.intercalate(BS.singleton'.')<$>(optionalcfws*>(atom<|>quotedString)<*optionalcfws)`sepBy1`(char'.')atom=takeWhile1isAtomTextisAtomTextx=isAlphaNumx||inClass"!#$%&'*+/=?^_`{|}~-"xdomainLiteral=(BS.cons'['.flipBS.snoc']'.BS.concat)<$>(between(optionalcfws*>char'[')(char']'<*optionalcfws)$many(optionalfws>>takeWhile1isDomainText)<*optionalfws)isDomainTextx=inClass"\33-\90\94-\126"x||isObsNoWsCtlxquotedString=(\x->BS.concat$[BS.singleton'"',BS.concatx,BS.singleton'"'])<$>(between(char'"')(char'"')$many(optionalfws>>quotedContent)<*optionalfws)quotedContent=takeWhile1isQuotedText<|>quotedPairisQuotedTextx=inClass"\33\35-\91\93-\126"x||isObsNoWsCtlxquotedPair=(BS.cons'\\'.BS.singleton)<$>(char'\\'*>(vchar<|>wsp<|>lf<|>cr<|>obsNoWsCtl<|>nullChar))cfws=ignore$many(comment<|>fws)fws::Parser()fws=ignore$ignore(wsp1>>optional(crlf>>wsp1))<|>ignore(many1(crlf>>wsp1))ignore::Parsera->Parser()ignorex=x>>return()betweenlrx=l*>x<*rcomment::Parser()comment=ignore((between(char'(')(char')')$many(ignorecommentContent<|>fws)))commentContent=skipWhile1isCommentText<|>ignorequotedPair<|>commentisCommentTextx=inClass"\33-\39\42-\91\93-\126"x||isObsNoWsCtlxnullChar=char'\0'skipWhile1x=satisfyx>>skipWhilexwsp1=skipWhile1isWspwsp=satisfyisWspisWspx=x==' '||x=='\t'isAlphaNumx=isDigitx||isAlpha_asciixcr=char'\r'lf=char'\n'crlf=cr>>lf>>return()isVchar=inClass"\x21-\x7e"vchar=satisfyisVcharisObsNoWsCtl=inClass"\1-\8\11-\12\14-\31\127"obsNoWsCtl=satisfyisObsNoWsCtl