-- | This module contains the definitions for a generic parser, without-- running state. These are the parts that are shared between the Plain-- and Lazy variations. Do not import this module directly, but only-- via T.P.Poly.Plain or T.P.Poly.Lazy.moduleText.ParserCombinators.Poly.Parser(-- * The Parser datatypeParser(P)-- datatype, instance of: Functor, Monad, PolyParse,Result(..)-- internal to the Parser Monad.-- ** Basic parsers,next-- :: Parser t t,eof-- :: Parser t (),satisfy-- :: (t->Bool) -> Parser t t,onFail-- :: Parser t a -> Parser t a -> Parser t a-- ** Re-parsing,reparse-- :: [t] -> Parser t ())whereimportText.ParserCombinators.Poly.BaseimportText.ParserCombinators.Poly.Result-- | This @Parser@ datatype is a fairly generic parsing monad with error-- reporting. It can be used for arbitrary token types, not just-- String input. (If you require a running state, use module Poly.State-- instead)newtypeParserta=P([t]->Result[t]a)instanceFunctor(Parsert)wherefmapf(Pp)=P(fmapf.p)instanceMonad(Parsert)wherereturnx=P(\ts->Successtsx)faile=P(\ts->Failuretse)(Pf)>>=g=P(continue.f)wherecontinue(Successtsx)=let(Pg')=gxing'tscontinue(Committed(Committedr))=continue(Committedr)continue(Committedr)=Committed(continuer)continue(Failuretse)=FailuretseinstanceCommitment(Parsert)wherecommit(Pp)=P(Committed.p)(Pp)`adjustErr`f=P(adjust.p)whereadjust(Failureze)=Failurez(fe)adjust(Committedr)=Committed(adjustr)adjustgood=goodoneOf'=accum[]whereaccumerrs[]=fail("failed to parse any of the possible choices:\n"++indent2(concatMapshowErr(reverseerrs)))accumerrs((e,Pp):ps)=P(\ts->caseptsofFailure_err->let(Pp)=accum((e,err):errs)psinptsr@(Successza)->rr@(Committed_)->r)showErr(name,err)=name++":\n"++indent2errinfixl6`onFail`-- not sure about precedence 6?-- | @p `onFail` q@ means parse p, unless p fails, in which case-- parse q instead.-- Can be chained together to give multiple attempts to parse something.-- (Note that q could itself be a failing parser, e.g. to change the error-- message from that defined in p to something different.)-- However, a severe failure in p cannot be ignored.onFail::Parserta->Parserta->Parserta(Pp)`onFail`(Pq)=P(\ts->continuets$pts)wherecontinuets(Failureze)=qts-- continue _ (Committed r) = r -- no, remain Committedcontinue_r=r-------------------------------------------------------------------------- | Simply return the next token in the input tokenstream.next::Parserttnext=P(\ts->casetsof[]->Failure[]"Ran out of input (EOF)"(t:ts')->Successts't)-- | Succeed if the end of file/input has been reached, fail otherwise.eof::Parsert()eof=P(\ts->casetsof[]->Success[]()(t:ts')->Failurets"Expected end of input (EOF)")-- | Return the next token if it satisfies the given predicate.satisfy::(t->Bool)->Parserttsatisfypred=do{x<-next;ifpredxthenreturnxelsefail"Parse.satisfy: failed"}-------------------------------------------------------------------------- | Push some tokens back onto the front of the input stream and reparse.-- This is useful e.g. for recursively expanding macros. When the-- user-parser recognises a macro use, it can lookup the macro-- expansion from the parse state, lex it, and then stuff the-- lexed expansion back down into the parser.reparse::[t]->Parsert()reparsets=P(\inp->Success(ts++inp)())------------------------------------------------------------------------