{-# LANGUAGE BangPatterns, GeneralizedNewtypeDeriving, OverloadedStrings,
Rank2Types, RecordWildCards, TypeFamilies #-}-- |-- Module : Data.Attoparsec.Internal.Types-- Copyright : Bryan O'Sullivan 2007-2015-- License : BSD3---- Maintainer : bos@serpentine.com-- Stability : experimental-- Portability : unknown---- Simple, efficient parser combinators, loosely based on the Parsec-- library.moduleData.Attoparsec.Internal.Types(Parser(..),State,Failure,Success,Pos(..),IResult(..),More(..),(<>),Chunk(..))whereimportControl.ApplicativeasApp(Applicative(..),(<$>))importControl.Applicative(Alternative(..))importControl.DeepSeq(NFData(rnf))importControl.Monad(MonadPlus(..))importqualifiedControl.Monad.FailasFail(MonadFail(..))importData.MonoidasMon(Monoid(..))importData.Semigroup(Semigroup(..))importData.Word(Word8)importData.ByteString(ByteString)importqualifiedData.ByteStringasBSimportData.ByteString.Internal(w2c)importData.Text(Text)importqualifiedData.TextasTextimportData.Text.Unsafe(Iter(..))importPreludehiding(getChar,succ)importqualifiedData.Attoparsec.ByteString.BufferasBimportqualifiedData.Attoparsec.Text.BufferasTnewtypePos=Pos{fromPos::Int}deriving(Eq,Ord,Show,Num)-- | The result of a parse. This is parameterised over the type @i@-- of string that was processed.---- This type is an instance of 'Functor', where 'fmap' transforms the-- value in a 'Done' result.dataIResultir=Faili[String]String-- ^ The parse failed. The @i@ parameter is the input that had-- not yet been consumed when the failure occurred. The-- @[@'String'@]@ is a list of contexts in which the error-- occurred. The 'String' is the message describing the error, if-- any.|Partial(i->IResultir)-- ^ Supply this continuation with more input so that the parser-- can resume. To indicate that no more input is available, pass-- an empty string to the continuation.---- __Note__: if you get a 'Partial' result, do not call its-- continuation more than once.|Doneir-- ^ The parse succeeded. The @i@ parameter is the input that had-- not yet been consumed (if any) when the parse succeeded.instance(Showi,Showr)=>Show(IResultir)whereshowsPrecdir=showParen(d>10)$caseirof(Failtstkmsg)->showString"Fail".ft.fstk.fmsg(Partial_)->showString"Partial _"(Donetr)->showString"Done".ft.frwheref::Showa=>a->ShowSfx=showChar' '.showsPrec11xinstance(NFDatai,NFDatar)=>NFData(IResultir)wherernf(Failtstkmsg)=rnft`seq`rnfstk`seq`rnfmsgrnf(Partial_)=()rnf(Donetr)=rnft`seq`rnfr{-# INLINE rnf #-}instanceFunctor(IResulti)wherefmap_(Failtstkmsg)=Failtstkmsgfmapf(Partialk)=Partial(fmapf.k)fmapf(Donetr)=Donet(fr)-- | The core parser type. This is parameterised over the type @i@-- of string being processed.---- This type is an instance of the following classes:---- * 'Monad', where 'fail' throws an exception (i.e. fails) with an-- error message.---- * 'Functor' and 'Applicative', which follow the usual definitions.---- * 'MonadPlus', where 'mzero' fails (with no error message) and-- 'mplus' executes the right-hand parser if the left-hand one-- fails. When the parser on the right executes, the input is reset-- to the same state as the parser on the left started with. (In-- other words, attoparsec is a backtracking parser that supports-- arbitrary lookahead.)---- * 'Alternative', which follows 'MonadPlus'.newtypeParseria=Parser{runParser::forallr.Statei->Pos->More->Failurei(Statei)r->Successi(Statei)ar->IResultir}typefamilyStateitypeinstanceStateByteString=B.BuffertypeinstanceStateText=T.BuffertypeFailureitr=t->Pos->More->[String]->String->IResultirtypeSuccessitar=t->Pos->More->a->IResultir-- | Have we read all available input?dataMore=Complete|Incompletederiving(Eq,Show)instanceSemigroupMorewherec@Complete<>_=c_<>m=minstanceMon.MonoidMorewheremappend=(<>)mempty=IncompleteinstanceMonad(Parseri)wherefail=Fail.fail{-# INLINE fail #-}return=App.pure{-# INLINE return #-}m>>=k=Parser$\t!posmorelosesucc->letsucc't'!pos'more'a=runParser(ka)t'pos'more'losesuccinrunParsermtposmorelosesucc'{-# INLINE (>>=) #-}(>>)=(*>){-# INLINE (>>) #-}instanceFail.MonadFail(Parseri)wherefailerr=Parser$\tposmorelose_succ->losetposmore[]msgwheremsg="Failed reading: "++err{-# INLINE fail #-}plus::Parseria->Parseria->Parseriaplusfg=Parser$\tposmorelosesucc->letlose't'_pos'more'_ctx_msg=runParsergt'posmore'losesuccinrunParserftposmorelose'succinstanceMonadPlus(Parseri)wheremzero=fail"mzero"{-# INLINE mzero #-}mplus=plusinstanceFunctor(Parseri)wherefmapfp=Parser$\tposmorelosesucc->letsucc't'pos'more'a=succt'pos'more'(fa)inrunParserptposmorelosesucc'{-# INLINE fmap #-}apP::Parseri(a->b)->Parseria->ParseribapPde=dob<-da<-ereturn(ba){-# INLINE apP #-}instanceApplicative(Parseri)wherepurev=Parser$\tposmore_losesucc->succtposmorev{-# INLINE pure #-}(<*>)=apP{-# INLINE (<*>) #-}m*>k=m>>=\_->k{-# INLINE (*>) #-}x<*y=x>>=\a->y>>purea{-# INLINE (<*) #-}instanceSemigroup(Parseria)where(<>)=plus{-# INLINE (<>) #-}instanceMonoid(Parseria)wheremempty=fail"mempty"{-# INLINE mempty #-}mappend=(<>){-# INLINE mappend #-}instanceAlternative(Parseri)whereempty=fail"empty"{-# INLINE empty #-}(<|>)=plus{-# INLINE (<|>) #-}manyv=many_vwheremany_v=some_v<|>pure[]some_v=(:)App.<$>v<*>many_v{-# INLINE many #-}somev=some_vwheremany_v=some_v<|>pure[]some_v=(:)<$>v<*>many_v{-# INLINE some #-}-- | A common interface for input chunks.classMonoidc=>ChunkcwheretypeChunkElemc-- | Test if the chunk is empty.nullChunk::c->Bool-- | Append chunk to a buffer.pappendChunk::Statec->c->Statec-- | Position at the end of a buffer. The first argument is ignored.atBufferEnd::c->Statec->Pos-- | Return the buffer element at the given position along with its length.bufferElemAt::c->Pos->Statec->Maybe(ChunkElemc,Int)-- | Map an element to the corresponding character.-- The first argument is ignored.chunkElemToChar::c->ChunkElemc->CharinstanceChunkByteStringwheretypeChunkElemByteString=Word8nullChunk=BS.null{-# INLINE nullChunk #-}pappendChunk=B.pappend{-# INLINE pappendChunk #-}atBufferEnd_=Pos.B.length{-# INLINE atBufferEnd #-}bufferElemAt_(Posi)buf|i<B.lengthbuf=Just(B.unsafeIndexbufi,1)|otherwise=Nothing{-# INLINE bufferElemAt #-}chunkElemToChar_=w2c{-# INLINE chunkElemToChar #-}instanceChunkTextwheretypeChunkElemText=CharnullChunk=Text.null{-# INLINE nullChunk #-}pappendChunk=T.pappend{-# INLINE pappendChunk #-}atBufferEnd_=Pos.T.length{-# INLINE atBufferEnd #-}bufferElemAt_(Posi)buf|i<T.lengthbuf=letItercl=T.iterbufiinJust(c,l)|otherwise=Nothing{-# INLINE bufferElemAt #-}chunkElemToChar_=id{-# INLINE chunkElemToChar #-}