{-# LANGUAGE BangPatterns, CPP, GeneralizedNewtypeDeriving, OverloadedStrings,
Rank2Types, RecordWildCards, TypeFamilies #-}-- |-- Module : Data.Attoparsec.Internal.Types-- Copyright : Bryan O'Sullivan 2007-2011-- 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(..),Failure,Success,IResult(..),Input(..),Added(..),More(..),addS,(<>),Chunk(..))whereimportControl.Applicative(Alternative(..),Applicative(..),(<$>))importControl.DeepSeq(NFData(rnf))importControl.Monad(MonadPlus(..))importData.ByteString(ByteString)importData.ByteString.Internal(w2c)importData.Monoid(Monoid(..))importData.Text(Text)importData.Word(Word8)importPreludehiding(getChar,take,takeWhile)importqualifiedData.ByteStringasBSimportqualifiedData.ByteString.UnsafeasBSimportqualifiedData.TextasTimportqualifiedData.Text.UnsafeasT-- | The result of a parse. This is parameterised over the type @t@-- of string that was processed.---- This type is an instance of 'Functor', where 'fmap' transforms the-- value in a 'Done' result.dataIResulttr=Failt[String]String-- ^ The parse failed. The 't' 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(t->IResulttr)-- ^ Supply this continuation with more input so that-- the parser can resume. To indicate that no more-- input is available, use an empty string.|Donetr-- ^ The parse succeeded. The 't' parameter is the-- input that had not yet been consumed (if any) when-- the parse succeeded.instance(Showt,Showr)=>Show(IResulttr)whereshow(Failtstkmsg)="Fail "++showt++" "++showstk++" "++showmsgshow(Partial_)="Partial _"show(Donetr)="Done "++showt++" "++showrinstance(NFDatat,NFDatar)=>NFData(IResulttr)wherernf(Failtstkmsg)=rnft`seq`rnfstk`seq`rnfmsgrnf(Partial_)=()rnf(Donetr)=rnft`seq`rnfr{-# INLINE rnf #-}fmapR::(a->b)->IResultta->IResulttbfmapR_(Failtstkmsg)=FailtstkmsgfmapRf(Partialk)=Partial(fmapRf.k)fmapRf(Donetr)=Donet(fr)instanceFunctor(IResultt)wherefmap=fmapR{-# INLINE fmap #-}newtypeInputt=I{unI::t}deriving(Monoid)newtypeAddedt=A{unA::t}deriving(Monoid)-- | The core parser type. This is parameterised over the type @t@ 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'.newtypeParserta=Parser{runParser::forallr.Inputt->Addedt->More->Failuretr->Successtar->IResulttr}typeFailuretr=Inputt->Addedt->More->[String]->String->IResulttrtypeSuccesstar=Inputt->Addedt->More->a->IResulttr-- | Have we read all available input?dataMore=Complete|Incompletederiving(Eq,Show)instanceMonoidMorewheremappendc@Complete_=cmappend_m=mmempty=IncompleteaddS::(Monoidt)=>Inputt->Addedt->More->Inputt->Addedt->More->(Inputt->Addedt->More->r)->raddSi0a0m0_i1a1m1f=let!i=i0<>I(unAa1)a=a0<>a1!m=m0<>m1infiam{-# INLINE addS #-}bindP::Parserta->(a->Parsertb)->ParsertbbindPmg=Parser$\i0a0m0kfks->runParsermi0a0m0kf$\i1a1m1a->runParser(ga)i1a1m1kfks{-# INLINE bindP #-}returnP::a->ParsertareturnPa=Parser(\i0a0m0_kfks->ksi0a0m0a){-# INLINE returnP #-}instanceMonad(Parsert)wherereturn=returnP(>>=)=bindPfail=failDescnoAdds::(Monoidt)=>Inputt->Addedt->More->(Inputt->Addedt->More->r)->rnoAddsi0_a0m0f=fi0memptym0{-# INLINE noAdds #-}plus::(Monoidt)=>Parserta->Parserta->Parsertaplusab=Parser$\i0a0m0kfks->letkf'i1a1m1__=addSi0a0m0i1a1m1$\i2a2m2->runParserbi2a2m2kfksks'i1a1m1=ksi1(a0<>a1)m1innoAddsi0a0m0$\i2a2m2->runParserai2a2m2kf'ks'instance(Monoidt)=>MonadPlus(Parsert)wheremzero=failDesc"mzero"{-# INLINE mzero #-}mplus=plusfmapP::(a->b)->Parserta->ParsertbfmapPpm=Parser$\i0a0m0fk->runParsermi0a0m0f$\i1a1s1a->ki1a1s1(pa){-# INLINE fmapP #-}instanceFunctor(Parsert)wherefmap=fmapP{-# INLINE fmap #-}apP::Parsert(a->b)->Parserta->ParsertbapPde=dob<-da<-ereturn(ba){-# INLINE apP #-}instanceApplicative(Parsert)wherepure=returnP{-# INLINE pure #-}(<*>)=apP{-# INLINE (<*>) #-}#if MIN_VERSION_base(4,2,0)-- These definitions are equal to the defaults, but this-- way the optimizer doesn't have to work so hard to figure-- that out.(*>)=(>>){-# INLINE (*>) #-}x<*y=x>>=\a->y>>returna{-# INLINE (<*) #-}#endifinstance(Monoidt)=>Monoid(Parserta)wheremempty=failDesc"mempty"{-# INLINE mempty #-}mappend=plus{-# INLINE mappend #-}instance(Monoidt)=>Alternative(Parsert)whereempty=failDesc"empty"{-# INLINE empty #-}(<|>)=plus{-# INLINE (<|>) #-}#if MIN_VERSION_base(4,2,0)manyv=many_vwheremany_v=some_v<|>pure[]some_v=(:)<$>v<*>many_v{-# INLINE many #-}somev=some_vwheremany_v=some_v<|>pure[]some_v=(:)<$>v<*>many_v{-# INLINE some #-}#endiffailDesc::String->ParsertafailDescerr=Parser(\i0a0m0kf_ks->kfi0a0m0[]msg)wheremsg="Failed reading: "++err{-# INLINE failDesc #-}(<>)::(Monoidm)=>m->m->m(<>)=mappend{-# INLINE (<>) #-}-- | A common interface for input chunks.classMonoidc=>ChunkcwheretypeChunkElemc-- | Test if the chunk is empty.nullChunk::c->Bool-- | Get the head element of a non-empty chunk.unsafeChunkHead::c->ChunkElemc-- | Get the tail of a non-empty chunk.unsafeChunkTail::c->c-- | Check if the chunk has the length of at least @n@ elements.chunkLengthAtLeast::c->Int->Bool-- | Map an element to the corresponding character.-- The first argument is ignored.chunkElemToChar::c->ChunkElemc->CharinstanceChunkByteStringwheretypeChunkElemByteString=Word8nullChunk=BS.null{-# INLINE nullChunk #-}unsafeChunkHead=BS.unsafeHead{-# INLINE unsafeChunkHead #-}unsafeChunkTail=BS.unsafeTail{-# INLINE unsafeChunkTail #-}chunkLengthAtLeastbsn=BS.lengthbs>=n{-# INLINE chunkLengthAtLeast #-}chunkElemToChar=constw2c{-# INLINE chunkElemToChar #-}instanceChunkTextwheretypeChunkElemText=CharnullChunk=T.null{-# INLINE nullChunk #-}unsafeChunkHead=T.unsafeHead{-# INLINE unsafeChunkHead #-}unsafeChunkTail=T.unsafeTail{-# INLINE unsafeChunkTail #-}chunkLengthAtLeasttn=T.lengthWord16t`quot`2>=n||T.lengtht>=n{-# INLINE chunkLengthAtLeast #-}chunkElemToChar=constid{-# INLINE chunkElemToChar #-}