moduleText.ParserCombinators.Poly.NoLeak.Plain(-- * The Parser datatypeParser(P)-- datatype, instance of: Functor, Monad, PolyParse,runParser-- :: Parser t a -> [t] -> (Either String a, [t])-- ** basic parsers,next-- :: Parser t t,satisfy-- :: (t->Bool) -> Parser t t-- ** re-parsing,reparse-- :: [t] -> Parser t ()-- * Re-export all more general combinators,moduleText.ParserCombinators.Poly.Base)whereimportText.ParserCombinators.Poly.Base-- | 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 PolyState-- instead)newtypeParserta=P([t]->Result[t]a)-- A return type like Either, that distinguishes not only between-- right and wrong answers, but also has commitment, so that a failure-- cannot be undone.dataResultza=Successza|FailurezString|Committed(Resultza)instanceFunctor(Resultz)wherefmapf(Successza)=Successz(fa)fmapf(Failureze)=Failurezefmapf(Committedr)=Committed(fmapfr)-- | Apply a parser to an input token sequence.runParser::Parserta->[t]->(EitherStringa,[t])runParser(Pp)=resultToEither.pwhereresultToEither::Resultza->(EitherStringa,z)resultToEither(Successza)=(Righta,z)resultToEither(Failureze)=(Lefte,z)resultToEither(Committedr)=resultToEitherrinstanceFunctor(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)=FailuretseinstancePolyParse(Parsert)wherecommit(Pp)=P(Committed.p)(Pp)`adjustErr`f=P(adjust.p)whereadjust(Failureze)=Failurez(fe)adjust(Committedr)=Committed(adjustr)adjustgood=good(Pp)`onFail`(Pq)=P(\ts->continuets$pts)wherecontinuets(Failureze)=qts-- continue _ (Committed r) = r -- no, remain Committedcontinue_r=roneOf'=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"++indent2err------------------------------------------------------------------------next::Parserttnext=P(\ts->casetsof[]->Failure[]"Ran out of input (EOF)"(t:ts')->Successts't)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)())------------------------------------------------------------------------