attoparsec 0.12.0.0 → 0.12.1.0
raw patch · 8 files changed
+197/−117 lines, 8 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Data.Attoparsec.Combinator: atEnd :: Chunk t => Parser t Bool
+ Data.Attoparsec.Combinator: endOfInput :: Chunk t => Parser t ()
+ Data.Attoparsec.Combinator: satisfyElem :: Chunk t => (ChunkElem t -> Bool) -> Parser t (ChunkElem t)
+ Data.Attoparsec.Types: chunkElemToChar :: Chunk c => c -> ChunkElem c -> Char
+ Data.Attoparsec.Types: class Monoid c => Chunk c
- Data.Attoparsec.ByteString: atEnd :: Parser Bool
+ Data.Attoparsec.ByteString: atEnd :: Chunk t => Parser t Bool
- Data.Attoparsec.ByteString: endOfInput :: Parser ()
+ Data.Attoparsec.ByteString: endOfInput :: Chunk t => Parser t ()
- Data.Attoparsec.ByteString.Char8: atEnd :: Parser Bool
+ Data.Attoparsec.ByteString.Char8: atEnd :: Chunk t => Parser t Bool
- Data.Attoparsec.ByteString.Char8: endOfInput :: Parser ()
+ Data.Attoparsec.ByteString.Char8: endOfInput :: Chunk t => Parser t ()
- Data.Attoparsec.Text: atEnd :: Parser Bool
+ Data.Attoparsec.Text: atEnd :: Chunk t => Parser t Bool
- Data.Attoparsec.Text: endOfInput :: Parser ()
+ Data.Attoparsec.Text: endOfInput :: Chunk t => Parser t ()
Files
- Data/Attoparsec/ByteString/Internal.hs +2/−52
- Data/Attoparsec/Combinator.hs +4/−0
- Data/Attoparsec/Internal.hs +125/−3
- Data/Attoparsec/Internal/Types.hs +56/−10
- Data/Attoparsec/Text/Internal.hs +1/−50
- Data/Attoparsec/Types.hs +2/−1
- attoparsec.cabal +1/−1
- changelog.md +6/−0
Data/Attoparsec/ByteString/Internal.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE BangPatterns, OverloadedStrings, RecordWildCards #-}+{-# LANGUAGE BangPatterns, GADTs, OverloadedStrings, RecordWildCards #-} -- | -- Module : Data.Attoparsec.ByteString.Internal -- Copyright : Bryan O'Sullivan 2007-2014@@ -70,6 +70,7 @@ import Data.Attoparsec.ByteString.Buffer (Buffer, buffer) import Data.Attoparsec.ByteString.FastSet (charClass, memberWord8) import Data.Attoparsec.Combinator ((<?>))+import Data.Attoparsec.Internal import Data.Attoparsec.Internal.Fhthagn (inlinePerformIO) import Data.Attoparsec.Internal.Types hiding (Parser, Failure, Success) import Data.ByteString (ByteString)@@ -467,51 +468,6 @@ -- Non-recursive so the bounds check can be inlined: {-# INLINE ensure #-} --- | Ask for input. If we receive any, pass it to a success--- continuation, otherwise to a failure continuation.-prompt :: Buffer -> Pos -> More- -> (Buffer -> Pos -> More -> IResult ByteString r)- -> (Buffer -> Pos -> More -> IResult ByteString r)- -> IResult ByteString r-prompt t pos _more lose succ = Partial $ \s ->- if B.null s- then lose t pos Complete- else succ (Buf.pappend t s) pos Incomplete---- | Immediately demand more input via a 'Partial' continuation--- result.-demandInput :: Parser ()-demandInput = T.Parser $ \t pos more lose succ ->- case more of- Complete -> lose t pos more [] "not enough input"- _ -> let lose' t' pos' more' = lose t' pos' more' [] "not enough input"- succ' t' pos' more' = succ t' pos' more' ()- in prompt t pos more lose' succ'---- | This parser always succeeds. It returns 'True' if any input is--- available either immediately or on demand, and 'False' if the end--- of all input has been reached.-wantInput :: Parser Bool-wantInput = T.Parser $ \t pos more _lose succ ->- case () of- _ | lengthAtLeast pos 1 t -> succ t pos more True- | more == Complete -> succ t pos more False- | otherwise -> let lose' t' pos' more' = succ t' pos' more' False- succ' t' pos' more' = succ t' pos' more' True- in prompt t pos more lose' succ'-{-# INLINE wantInput #-}---- | Match only if all input has been consumed.-endOfInput :: Parser ()-endOfInput = T.Parser $ \t pos more lose succ ->- case () of- _| lengthAtLeast pos 1 t -> lose t pos more [] "endOfInput"- | more == Complete -> succ t pos more ()- | otherwise ->- let lose' t' pos' more' _ctx _msg = succ t' pos' more' ()- succ' t' pos' more' _a = lose t' pos' more' [] "endOfInput"- in runParser demandInput t pos more lose' succ'- -- | Return both the result of a parse and the portion of the input -- that was consumed while it was being parsed. match :: Parser a -> Parser (ByteString, a)@@ -519,12 +475,6 @@ let succ' t' pos' more' a = succ t' pos' more' (substring pos (pos'-pos) t', a) in runParser p t pos more lose succ'---- | Return an indication of whether the end of input has been--- reached.-atEnd :: Parser Bool-atEnd = not <$> wantInput-{-# INLINE atEnd #-} lengthAtLeast :: Pos -> Int -> Buffer -> Bool lengthAtLeast (Pos pos) n bs = Buf.length bs >= pos + n
Data/Attoparsec/Combinator.hs view
@@ -30,12 +30,16 @@ , skipMany1 , eitherP , feed+ , satisfyElem+ , endOfInput+ , atEnd ) where import Control.Applicative (Alternative(..), Applicative(..), empty, liftA2, many, (<|>), (*>), (<$>)) import Control.Monad (MonadPlus(..)) import Data.Attoparsec.Internal.Types (Parser(..), IResult(..))+import Data.Attoparsec.Internal (endOfInput, atEnd, satisfyElem) import Data.ByteString (ByteString) import Data.Monoid (Monoid(mappend)) import Data.Text (Text)
Data/Attoparsec/Internal.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP, BangPatterns, ScopedTypeVariables #-} -- | -- Module : Data.Attoparsec.Internal -- Copyright : Bryan O'Sullivan 2007-2014@@ -12,10 +12,20 @@ -- library. module Data.Attoparsec.Internal- (- compareResults+ ( compareResults+ , prompt+ , demandInput+ , wantInput+ , endOfInput+ , atEnd+ , satisfyElem ) where +import Control.Applicative ((<$>))+#if __GLASGOW_HASKELL__ >= 700+import Data.ByteString (ByteString)+import Data.Text (Text)+#endif import Data.Attoparsec.Internal.Types import Prelude hiding (succ) @@ -31,3 +41,115 @@ Just (t0 == t1 && r0 == r1) compareResults (Partial _) (Partial _) = Nothing compareResults _ _ = Just False++-- | Ask for input. If we receive any, pass it to a success+-- continuation, otherwise to a failure continuation.+prompt :: Chunk t+ => State t -> Pos -> More+ -> (State t -> Pos -> More -> IResult t r)+ -> (State t -> Pos -> More -> IResult t r)+ -> IResult t r+prompt t pos _more lose succ = Partial $ \s ->+ if nullChunk s+ then lose t pos Complete+ else succ (pappendChunk t s) pos Incomplete+#if __GLASGOW_HASKELL__ >= 700+{-# SPECIALIZE prompt :: State ByteString -> Pos -> More+ -> (State ByteString -> Pos -> More+ -> IResult ByteString r)+ -> (State ByteString -> Pos -> More+ -> IResult ByteString r)+ -> IResult ByteString r #-}+{-# SPECIALIZE prompt :: State Text -> Pos -> More+ -> (State Text -> Pos -> More -> IResult Text r)+ -> (State Text -> Pos -> More -> IResult Text r)+ -> IResult Text r #-}+#endif++-- | Immediately demand more input via a 'Partial' continuation+-- result.+demandInput :: Chunk t => Parser t ()+demandInput = Parser $ \t pos more lose succ ->+ case more of+ Complete -> lose t pos more [] "not enough input"+ _ -> let lose' t' pos' more' = lose t' pos' more' [] "not enough input"+ succ' t' pos' more' = succ t' pos' more' ()+ in prompt t pos more lose' succ'+#if __GLASGOW_HASKELL__ >= 700+{-# SPECIALIZE demandInput :: Parser ByteString () #-}+{-# SPECIALIZE demandInput :: Parser Text () #-}+#endif++-- | This parser always succeeds. It returns 'True' if any input is+-- available either immediately or on demand, and 'False' if the end+-- of all input has been reached.+wantInput :: forall t . Chunk t => Parser t Bool+wantInput = Parser $ \t pos more _lose succ ->+ case () of+ _ | pos < atBufferEnd (undefined :: t) t -> succ t pos more True+ | more == Complete -> succ t pos more False+ | otherwise -> let lose' t' pos' more' = succ t' pos' more' False+ succ' t' pos' more' = succ t' pos' more' True+ in prompt t pos more lose' succ'+{-# INLINE wantInput #-}++-- | Match only if all input has been consumed.+endOfInput :: forall t . Chunk t => Parser t ()+endOfInput = Parser $ \t pos more lose succ ->+ case () of+ _| pos < atBufferEnd (undefined :: t) t -> lose t pos more [] "endOfInput"+ | more == Complete -> succ t pos more ()+ | otherwise ->+ let lose' t' pos' more' _ctx _msg = succ t' pos' more' ()+ succ' t' pos' more' _a = lose t' pos' more' [] "endOfInput"+ in runParser demandInput t pos more lose' succ'+#if __GLASGOW_HASKELL__ >= 700+{-# SPECIALIZE endOfInput :: Parser ByteString () #-}+{-# SPECIALIZE endOfInput :: Parser Text () #-}+#endif++-- | Return an indication of whether the end of input has been+-- reached.+atEnd :: Chunk t => Parser t Bool+atEnd = not <$> wantInput+{-# INLINE atEnd #-}++satisfySuspended :: forall t r . Chunk t+ => (ChunkElem t -> Bool)+ -> State t -> Pos -> More+ -> Failure t (State t) r+ -> Success t (State t) (ChunkElem t) r+ -> IResult t r+satisfySuspended p t pos more lose succ =+ runParser (demandInput >> go) t pos more lose succ+ where go = Parser $ \t' pos' more' lose' succ' ->+ case bufferElemAt (undefined :: t) pos' t' of+ Just (e, l) | p e -> succ' t' (pos' + Pos l) more' e+ | otherwise -> lose' t' pos' more' [] "satisfyElem"+ Nothing -> runParser (demandInput >> go) t' pos' more' lose' succ'+#if __GLASGOW_HASKELL__ >= 700+{-# SPECIALIZE satisfySuspended :: (ChunkElem ByteString -> Bool)+ -> State ByteString -> Pos -> More+ -> Failure ByteString (State ByteString) r+ -> Success ByteString (State ByteString)+ (ChunkElem ByteString) r+ -> IResult ByteString r #-}+{-# SPECIALIZE satisfySuspended :: (ChunkElem Text -> Bool)+ -> State Text -> Pos -> More+ -> Failure Text (State Text) r+ -> Success Text (State Text)+ (ChunkElem Text) r+ -> IResult Text r #-}+#endif++-- | The parser @satisfyElem p@ succeeds for any chunk element for which the+-- predicate @p@ returns 'True'. Returns the element that is+-- actually parsed.+satisfyElem :: forall t . Chunk t+ => (ChunkElem t -> Bool) -> Parser t (ChunkElem t)+satisfyElem p = Parser $ \t pos more lose succ ->+ case bufferElemAt (undefined :: t) pos t of+ Just (e, l) | p e -> succ t (pos + Pos l) more e+ | otherwise -> lose t pos more [] "satisfyElem"+ Nothing -> satisfySuspended p t pos more lose succ+{-# INLINE satisfyElem #-}
Data/Attoparsec/Internal/Types.hs view
@@ -15,21 +15,27 @@ module Data.Attoparsec.Internal.Types ( Parser(..)- , Input(..)+ , State , Failure , Success , Pos(..) , IResult(..) , More(..) , (<>)+ , Chunk(..) ) where import Control.Applicative (Alternative(..), Applicative(..), (<$>)) import Control.DeepSeq (NFData(rnf)) import Control.Monad (MonadPlus(..))+import Data.Word (Word8) import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import Data.ByteString.Internal (w2c) import Data.Monoid (Monoid(..)) import Data.Text (Text)+import qualified Data.Text as Text+import Data.Text.Unsafe (Iter(..)) import Prelude hiding (getChar, succ) import qualified Data.Attoparsec.ByteString.Buffer as B import qualified Data.Attoparsec.Text.Buffer as T@@ -96,21 +102,16 @@ -- -- * 'Alternative', which follows 'MonadPlus'. newtype Parser i a = Parser {- runParser :: forall r. Input i =>+ runParser :: forall r. State i -> Pos -> More -> Failure i (State i) r -> Success i (State i) a r -> IResult i r } -class Input i where- type State i :: *--instance Input ByteString where- type State ByteString = B.Buffer--instance Input Text where- type State Text = T.Buffer+type family State i+type instance State ByteString = B.Buffer+type instance State Text = T.Buffer type Failure i t r = t -> Pos -> More -> [String] -> String -> IResult i r@@ -202,3 +203,48 @@ (<>) :: (Monoid m) => m -> m -> m (<>) = mappend {-# INLINE (<>) #-}++-- | A common interface for input chunks.+class Monoid c => Chunk c where+ type ChunkElem c+ -- | Test if the chunk is empty.+ nullChunk :: c -> Bool+ -- | Append chunk to a buffer.+ pappendChunk :: State c -> c -> State c+ -- | Position at the end of a buffer. The first argument is ignored.+ atBufferEnd :: c -> State c -> Pos+ -- | Return the buffer element at the given position along with its length.+ bufferElemAt :: c -> Pos -> State c -> Maybe (ChunkElem c, Int)+ -- | Map an element to the corresponding character.+ -- The first argument is ignored.+ chunkElemToChar :: c -> ChunkElem c -> Char++instance Chunk ByteString where+ type ChunkElem ByteString = Word8+ nullChunk = BS.null+ {-# INLINE nullChunk #-}+ pappendChunk = B.pappend+ {-# INLINE pappendChunk #-}+ atBufferEnd _ = Pos . B.length+ {-# INLINE atBufferEnd #-}+ bufferElemAt _ (Pos i) buf+ | i < B.length buf = Just (B.unsafeIndex buf i, 1)+ | otherwise = Nothing+ {-# INLINE bufferElemAt #-}+ chunkElemToChar _ = w2c+ {-# INLINE chunkElemToChar #-}++instance Chunk Text where+ type ChunkElem Text = Char+ nullChunk = Text.null+ {-# INLINE nullChunk #-}+ pappendChunk = T.pappend+ {-# INLINE pappendChunk #-}+ atBufferEnd _ = Pos . T.length+ {-# INLINE atBufferEnd #-}+ bufferElemAt _ (Pos i) buf+ | i < T.length buf = let Iter c l = T.iter buf i in Just (c, l)+ | otherwise = Nothing+ {-# INLINE bufferElemAt #-}+ chunkElemToChar _ = id+ {-# INLINE chunkElemToChar #-}
Data/Attoparsec/Text/Internal.hs view
@@ -68,6 +68,7 @@ import Control.Applicative ((<|>), (<$>)) import Control.Monad (when) import Data.Attoparsec.Combinator ((<?>))+import Data.Attoparsec.Internal import Data.Attoparsec.Internal.Types hiding (Parser, Failure, Success) import qualified Data.Attoparsec.Text.Buffer as Buf import Data.Attoparsec.Text.Buffer (Buffer, buffer)@@ -478,50 +479,6 @@ -- Non-recursive so the bounds check can be inlined: {-# INLINE ensure #-} --- | Ask for input. If we receive any, pass it to a success--- continuation, otherwise to a failure continuation.-prompt :: Buffer -> Pos -> More- -> (Buffer -> Pos -> More -> IResult Text r)- -> (Buffer -> Pos -> More -> IResult Text r)- -> IResult Text r-prompt t pos _more lose succ = Partial $ \s ->- if T.null s- then lose t pos Complete- else succ (Buf.pappend t s) pos Incomplete---- | Immediately demand more input via a 'Partial' continuation--- result.-demandInput :: Parser ()-demandInput = T.Parser $ \t pos more lose succ ->- case more of- Complete -> lose t pos more [] "not enough input"- _ -> let lose' t' pos' more' = lose t' pos' more' [] "not enough input"- succ' t' pos' more' = succ t' pos' more' ()- in prompt t pos more lose' succ'---- | This parser always succeeds. It returns 'True' if any input is--- available either immediately or on demand, and 'False' if the end--- of all input has been reached.-wantInput :: Parser Bool-wantInput = T.Parser $ \t pos more _lose succ ->- case () of- _ | pos < lengthOf t -> succ t pos more True- | more == Complete -> succ t pos more False- | otherwise -> let lose' t' pos' more' = succ t' pos' more' False- succ' t' pos' more' = succ t' pos' more' True- in prompt t pos more lose' succ'---- | Match only if all input has been consumed.-endOfInput :: Parser ()-endOfInput = T.Parser $ \t pos more lose succ ->- case () of- _| pos < lengthOf t -> lose t pos more [] "endOfInput"- | more == Complete -> succ t pos more ()- | otherwise ->- let lose' t' pos' more' _ctx _msg = succ t' pos' more' ()- succ' t' pos' more' _a = lose t' pos' more' [] "endOfInput"- in runParser demandInput t pos more lose' succ'- -- | Return both the result of a parse and the portion of the input -- that was consumed while it was being parsed. match :: Parser a -> Parser (Text, a)@@ -529,12 +486,6 @@ let succ' t' pos' more' a = succ t' pos' more' (substring pos (pos'-pos) t', a) in runParser p t pos more lose succ'---- | Return an indication of whether the end of input has been--- reached.-atEnd :: Parser Bool-atEnd = not <$> wantInput-{-# INLINE atEnd #-} lengthAtLeast :: Pos -> Int -> Buffer -> Maybe Pos lengthAtLeast pos n t = go 0 (fromPos pos)
Data/Attoparsec/Types.hs view
@@ -14,6 +14,7 @@ ( Parser , IResult(..)+ , Chunk(chunkElemToChar) ) where -import Data.Attoparsec.Internal.Types (Parser(..), IResult(..))+import Data.Attoparsec.Internal.Types (Parser(..), IResult(..), Chunk(..))
attoparsec.cabal view
@@ -1,5 +1,5 @@ name: attoparsec-version: 0.12.0.0+version: 0.12.1.0 license: BSD3 license-file: LICENSE category: Text, Parsing
changelog.md view
@@ -1,3 +1,9 @@+0.12.1.0++* Now compatible with GHC 7.9++* Reintroduced the Chunk class, used by the parsers package+ 0.12.0.0 * A new internal representation makes almost all real-world parsers