attoparsec 0.10.1.1 → 0.10.2.0
raw patch · 12 files changed
+279/−26 lines, 12 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Attoparsec.ByteString: peekWord8 :: Parser (Maybe Word8)
+ Data.Attoparsec.ByteString.Char8: (.*>) :: ByteString -> Parser a -> Parser a
+ Data.Attoparsec.ByteString.Char8: (<*.) :: Parser a -> ByteString -> Parser a
+ Data.Attoparsec.ByteString.Char8: peekChar :: Parser (Maybe Char)
+ Data.Attoparsec.ByteString.Lazy: instance NFData r => NFData (Result r)
+ Data.Attoparsec.Text: (.*>) :: Text -> Parser a -> Parser a
+ Data.Attoparsec.Text: (<*.) :: Parser a -> Text -> Parser a
+ Data.Attoparsec.Text: peekChar :: Parser (Maybe Char)
+ Data.Attoparsec.Text.Lazy: instance NFData r => NFData (Result r)
Files
- Data/Attoparsec/ByteString.hs +1/−0
- Data/Attoparsec/ByteString/Char8.hs +45/−2
- Data/Attoparsec/ByteString/Internal.hs +17/−1
- Data/Attoparsec/ByteString/Lazy.hs +11/−0
- Data/Attoparsec/Text.hs +38/−9
- Data/Attoparsec/Text/Internal.hs +44/−7
- Data/Attoparsec/Text/Lazy.hs +6/−0
- attoparsec.cabal +7/−5
- benchmarks/Benchmarks.hs +74/−0
- benchmarks/attoparsec-benchmarks.cabal +18/−0
- tests/QC/ByteString.hs +7/−1
- tests/QC/Text.hs +11/−1
Data/Attoparsec/ByteString.hs view
@@ -46,6 +46,7 @@ , I.word8 , I.anyWord8 , I.notWord8+ , I.peekWord8 , I.satisfy , I.satisfyWith , I.skip
Data/Attoparsec/ByteString/Char8.hs view
@@ -44,6 +44,7 @@ , char8 , anyChar , notChar+ , peekChar , satisfy -- ** Special character parsers@@ -75,6 +76,11 @@ , takeWhile1 , takeTill + -- ** String combinators+ -- $specalt+ , (.*>)+ , (<*.)+ -- ** Consume all remaining input , I.takeByteString , I.takeLazyByteString@@ -98,7 +104,7 @@ , I.atEnd ) where -import Control.Applicative ((*>), (<$>), (<|>))+import Control.Applicative ((*>), (<*), (<$>), (<|>)) import Data.Attoparsec.ByteString.FastSet (charClass, memberChar) import Data.Attoparsec.ByteString.Internal (Parser, (<?>)) import Data.Attoparsec.Combinator@@ -214,6 +220,16 @@ anyChar = satisfy $ const True {-# INLINE anyChar #-} +-- | Match any character. Returns 'Nothing' if end of input has been+-- reached. Does not consume any input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+peekChar :: Parser (Maybe Char)+peekChar = (fmap w2c) `fmap` I.peekWord8+{-# INLINE peekChar #-}+ -- | Fast predicate for matching ASCII space characters. -- -- /Note/: This predicate only gives correct answers for the ASCII@@ -327,6 +343,33 @@ skipSpace = I.skipWhile isSpace_w8 {-# INLINE skipSpace #-} +-- $specalt+--+-- The '.*>' and '<*.' combinators are intended for use with the+-- @OverloadedStrings@ language extension. They simplify the common+-- task of matching a statically known string, then immediately+-- parsing something else.+--+-- An example makes this easier to understand:+--+-- @{-\# LANGUAGE OverloadedStrings #-}+--+-- shoeSize = \"Shoe size: \" '.*>' 'decimal'+-- @+--+-- If we were to try to use '*>' above instead, the type checker would+-- not be able to tell which 'IsString' instance to use for the text+-- in quotes. We would have to be explicit, using either a type+-- signature or the 'I.string' parser.++-- | Type-specialized version of '*>' for 'B.ByteString'.+(.*>) :: B.ByteString -> Parser a -> Parser a+s .*> f = I.string s *> f++-- | Type-specialized version of '<*' for 'B.ByteString'.+(<*.) :: Parser a -> B.ByteString -> Parser a+f <*. s = f <* I.string s+ -- | A predicate that matches either a carriage return @\'\\r\'@ or -- newline @\'\\n\'@ character. isEndOfLine :: Word8 -> Bool@@ -408,7 +451,7 @@ -- >rational "3.1" == Done 3.1 "" -- >rational "3e4" == Done 30000.0 "" -- >rational "3.1e4" == Done 31000.0, ""-+-- -- Examples with behaviour identical to 'read': -- -- >rational ".3" == Fail "input does not start with a digit"
Data/Attoparsec/ByteString/Internal.hs view
@@ -33,6 +33,7 @@ , skip , word8 , notWord8+ , peekWord8 -- ** Byte classes , inClass@@ -58,7 +59,6 @@ -- * State observation and manipulation functions , endOfInput , atEnd- , ensure -- * Utilities , endOfLine@@ -399,6 +399,22 @@ notWord8 :: Word8 -> Parser Word8 notWord8 c = satisfy (/= c) <?> "not " ++ show c {-# INLINE notWord8 #-}++-- | Match any byte. Returns 'Nothing' if end of input has been+-- reached. Does not consume any input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+peekWord8 :: Parser (Maybe Word8)+peekWord8 = T.Parser $ \i0 a0 m0 _kf ks ->+ let ks' i a m = let w = B.unsafeHead (unI i)+ in w `seq` ks i a m (Just w)+ kf' i a m = ks i a m Nothing+ in if B.null (unI i0)+ then prompt i0 a0 m0 kf' ks'+ else ks' i0 a0 m0+{-# INLINE peekWord8 #-} -- | Match only if all input has been consumed. endOfInput :: Parser ()
Data/Attoparsec/ByteString/Lazy.hs view
@@ -33,6 +33,7 @@ , eitherResult ) where +import Control.DeepSeq (NFData(rnf)) import Data.ByteString.Lazy.Internal (ByteString(..), chunk) import qualified Data.ByteString as B import qualified Data.Attoparsec.ByteString as A@@ -52,6 +53,16 @@ -- ^ The parse succeeded. The 'ByteString' is the -- input that had not yet been consumed (if any) when -- the parse succeeded.++instance NFData r => NFData (Result r) where+ rnf (Fail bs ctxs msg) = rnfBS bs `seq` rnf ctxs `seq` rnf msg+ rnf (Done bs r) = rnfBS bs `seq` rnf r+ {-# INLINE rnf #-}++rnfBS :: ByteString -> ()+rnfBS (Chunk _ xs) = rnfBS xs+rnfBS Empty = ()+{-# INLINE rnfBS #-} instance Show r => Show (Result r) where show (Fail bs stk msg) =
Data/Attoparsec/Text.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BangPatterns, FlexibleInstances, TypeSynonymInstances #-}+ -- | -- Module : Data.Attoparsec.Text -- Copyright : Bryan O'Sullivan 2011@@ -50,6 +51,7 @@ , I.satisfy , I.satisfyWith , I.skip+ , I.peekChar -- ** Special character parsers , digit@@ -62,7 +64,7 @@ -- * Efficient string handling , I.string- , stringCI+ , I.stringCI , skipSpace , I.skipWhile , I.scan@@ -71,6 +73,11 @@ , I.takeWhile1 , I.takeTill + -- ** String combinators+ -- $specalt+ , (.*>)+ , (<*.)+ -- ** Consume all remaining input , I.takeText , I.takeLazyText@@ -94,7 +101,7 @@ , I.atEnd ) where -import Control.Applicative ((<$>), (*>), (<|>))+import Control.Applicative ((<$>), (*>), (<*), (<|>)) import Data.Attoparsec.Combinator import Data.Attoparsec.Number (Number(..)) import Data.Attoparsec.Text.Internal ((<?>), Parser, Result, parse, takeWhile1)@@ -316,7 +323,7 @@ -- >rational "3.1" == Done 3.1 "" -- >rational "3e4" == Done 30000.0 "" -- >rational "3.1e4" == Done 31000.0, ""-+-- -- Examples with behaviour identical to 'read': -- -- >rational ".3" == Fail "input does not start with a digit"@@ -392,15 +399,37 @@ space = I.satisfy isSpace <?> "space" {-# INLINE space #-} --- | Satisfy a literal string, ignoring case.-stringCI :: Text -> Parser Text-stringCI = I.stringTransform T.toCaseFold-{-# INLINE stringCI #-}- -- | Skip over white space. skipSpace :: Parser () skipSpace = I.skipWhile isSpace {-# INLINE skipSpace #-}++-- $specalt+--+-- The '.*>' and '<*.' combinators are intended for use with the+-- @OverloadedStrings@ language extension. They simplify the common+-- task of matching a statically known string, then immediately+-- parsing something else.+--+-- An example makes this easier to understand:+--+-- @{-\# LANGUAGE OverloadedStrings #-}+--+-- shoeSize = \"Shoe size: \" '.*>' 'decimal'+-- @+--+-- If we were to try to use '*>' above instead, the type checker would+-- not be able to tell which 'IsString' instance to use for the text+-- in quotes. We would have to be explicit, using either a type+-- signature or the 'I.string' parser.++-- | Type-specialized version of '*>' for 'Text'.+(.*>) :: Text -> Parser a -> Parser a+s .*> f = I.string s *> f++-- | Type-specialized version of '<*' for 'Text'.+(<*.) :: Parser a -> Text -> Parser a+f <*. s = f <* I.string s data T = T !Integer !Int
Data/Attoparsec/Text/Internal.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE BangPatterns, Rank2Types, OverloadedStrings, RecordWildCards #-}+{-# LANGUAGE BangPatterns, FlexibleInstances, OverloadedStrings, Rank2Types,+ RecordWildCards, TypeSynonymInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} -- | -- Module : Data.Attoparsec.Text.Internal -- Copyright : Bryan O'Sullivan 2011@@ -33,6 +35,7 @@ , skip , char , notChar+ , peekChar -- ** Character classes , inClass@@ -41,7 +44,7 @@ -- * Efficient string handling , skipWhile , string- , stringTransform+ , stringCI , take , scan , takeWhile@@ -55,7 +58,6 @@ -- * State observation and manipulation functions , endOfInput , atEnd- , ensure -- * Utilities , endOfLine@@ -65,6 +67,7 @@ import Control.Monad (when) import Data.Attoparsec.Combinator import Data.Attoparsec.Internal.Types hiding (Parser, Input, Added, Failure, Success)+import Data.String (IsString(..)) import Data.Text (Text) import Prelude hiding (getChar, take, takeWhile) import qualified Data.Attoparsec.Internal.Types as T@@ -79,6 +82,9 @@ type Failure r = T.Failure Text r type Success a r = T.Success Text a r +instance IsString (Parser Text) where+ fromString = string . T.pack+ -- | If at least @n@ characters of input are available, return the -- current input, otherwise fail. ensure :: Int -> Parser Text@@ -219,10 +225,25 @@ string s = takeWith (T.length s) (==s) {-# INLINE string #-} -stringTransform :: (Text -> Text) -> Text- -> Parser Text-stringTransform f s = takeWith (T.length s) ((==f s) . f)-{-# INLINE stringTransform #-}+-- | Satisfy a literal string, ignoring case.+--+-- Note: this function is currently quite inefficient. Unicode case+-- folding can change the length of a string (\"ß\" becomes+-- "ss"), which makes a simple, efficient implementation tricky. We+-- have (for now) chosen simplicity over efficiency.+stringCI :: Text -> Parser Text+stringCI s = go 0+ where+ go !n+ | n > T.length fs = fail "stringCI"+ | otherwise = do+ t <- ensure n+ let h = unsafeTake n t+ if T.toCaseFold h == fs+ then put (unsafeDrop n t) >> return h+ else go (n+1)+ fs = T.toCaseFold s+{-# INLINE stringCI #-} -- | Skip past input for as long as the predicate returns 'True'. skipWhile :: (Char -> Bool) -> Parser ()@@ -381,6 +402,22 @@ notChar :: Char -> Parser Char notChar c = satisfy (/= c) <?> "not " ++ show c {-# INLINE notChar #-}++-- | Match any character. Returns 'Nothing' if end of input has been+-- reached. Does not consume any input.+--+-- /Note/: Because this parser does not fail, do not use it with+-- combinators such as 'many', because such parsers loop until a+-- failure occurs. Careless use will thus result in an infinite loop.+peekChar :: Parser (Maybe Char)+peekChar = T.Parser $ \i0 a0 m0 _kf ks ->+ let ks' i a m = let w = unsafeHead (unI i)+ in w `seq` ks i a m (Just w)+ kf' i a m = ks i a m Nothing+ in if T.null (unI i0)+ then prompt i0 a0 m0 kf' ks'+ else ks' i0 a0 m0+{-# INLINE peekChar #-} -- | Match only if all input has been consumed. endOfInput :: Parser ()
Data/Attoparsec/Text/Lazy.hs view
@@ -33,6 +33,7 @@ , eitherResult ) where +import Control.DeepSeq (NFData(rnf)) import Data.Text.Lazy.Internal (Text(..), chunk) import qualified Data.Attoparsec.Internal.Types as T import qualified Data.Attoparsec.Text as A@@ -56,6 +57,11 @@ show (Fail bs stk msg) = "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg show (Done bs r) = "Done " ++ show bs ++ " " ++ show r++instance NFData r => NFData (Result r) where+ rnf (Fail bs ctxs msg) = rnf bs `seq` rnf ctxs `seq` rnf msg+ rnf (Done bs r) = rnf bs `seq` rnf r+ {-# INLINE rnf #-} fmapR :: (a -> b) -> Result a -> Result b fmapR _ (Fail st stk msg) = Fail st stk msg
attoparsec.cabal view
@@ -1,5 +1,5 @@ name: attoparsec-version: 0.10.1.1+version: 0.10.2.0 license: BSD3 license-file: LICENSE category: Text, Parsing@@ -17,15 +17,17 @@ efficiently with network protocols and complicated text/binary file formats. extra-source-files:+ README.markdown+ benchmarks/Benchmarks.hs benchmarks/Makefile- benchmarks/med.txt.bz2 benchmarks/Tiny.hs+ benchmarks/attoparsec-benchmarks.cabal+ benchmarks/med.txt.bz2 examples/Makefile examples/Parsec_RFC2616.hs- examples/rfc2616.c examples/RFC2616.hs examples/TestRFC2616.hs- README.markdown+ examples/rfc2616.c tests/Makefile tests/QC.hs tests/QC/*.hs@@ -61,7 +63,7 @@ Data.Attoparsec.Internal.Types Data.Attoparsec.Text.FastSet Data.Attoparsec.Text.Internal- ghc-options: -Wall+ ghc-options: -O2 -Wall if flag(developer) ghc-prof-options: -auto-all
+ benchmarks/Benchmarks.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE BangPatterns #-}++import Control.Applicative+import Control.DeepSeq (NFData(rnf))+import Criterion.Main (bench, bgroup, defaultMain, nf, whnf)+import Data.ByteString.Internal (ByteString(..))+import Data.Char+import Text.Parsec.Text ()+import Text.Parsec.Text.Lazy ()+import qualified Data.Attoparsec.ByteString as AB+import qualified Data.Attoparsec.ByteString.Char8 as AC+import qualified Data.Attoparsec.ByteString.Lazy as ABL+import qualified Data.Attoparsec.Text as AT+import qualified Data.Attoparsec.Text.Lazy as ATL+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC+import qualified Data.ByteString.Lazy as BL+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Text.Parsec as P++instance NFData ByteString where+ rnf (PS _ _ _) = ()++instance NFData P.ParseError where+ rnf = rnf . show++chunksOf :: Int -> [a] -> [[a]]+chunksOf k = go+ where go xs = case splitAt k xs of+ ([],_) -> []+ (y, ys) -> y : go ys++fromLazy :: BL.ByteString -> B.ByteString+fromLazy = B.concat . BL.toChunks++main = do+ let s = take 1024 . cycle $ ['a'..'z'] ++ ['A'..'Z']+ !b = BC.pack s+ !bl = BL.fromChunks . map BC.pack . chunksOf 4 $ s+ !t = T.pack s+ !tl = TL.fromChunks . map T.pack . chunksOf 4 $ s+ defaultMain [+ bgroup "many" [+ bgroup "attoparsec" [+ bench "B" $ nf (AB.parse (many (AC.satisfy AC.isAlpha_ascii))) b+ , bench "BL" $ nf (ABL.parse (many (AC.satisfy AC.isAlpha_ascii))) bl+ , bench "T" $ nf (AT.parse (many (AT.satisfy AC.isAlpha_ascii))) t+ , bench "TL" $ nf (ATL.parse (many (AT.satisfy AC.isAlpha_ascii))) tl+ ]+ , bgroup "parsec" [+ bench "S" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") s+ , bench "B" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") b+ , bench "BL" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") bl+ , bench "T" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") t+ , bench "TL" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") tl+ ]+ ]+ , bgroup "comparison" [+ bgroup "many-vs-takeWhile" [+ bench "many" $ nf (AB.parse (many (AC.satisfy AC.isAlpha_ascii))) b+ , bench "takeWhile" $ nf (AB.parse (AC.takeWhile AC.isAlpha_ascii)) b+ ]+ , bgroup "letter-vs-isAlpha" [+ bench "letter" $ nf (AB.parse (many AC.letter_ascii)) b+ , bench "isAlpha" $ nf (AB.parse (many (AC.satisfy AC.isAlpha_ascii))) b+ ]+ ]+ , bgroup "takeWhile" [+ bench "isAlpha" $ nf (ABL.parse (AC.takeWhile isAlpha)) bl+ , bench "isAlpha_ascii" $ nf (ABL.parse (AC.takeWhile AC.isAlpha_ascii)) bl+ , bench "isAlpha_iso8859_15" $ nf (ABL.parse (AC.takeWhile AC.isAlpha_iso8859_15)) bl+ ]+ ]
+ benchmarks/attoparsec-benchmarks.cabal view
@@ -0,0 +1,18 @@+-- These benchmarks are not intended to be installed.+-- So don't install 'em.++name: attoparsec-benchmarks+version: 0+cabal-version: >=1.2+build-type: Simple++executable attoparsec-benchmarks+ main-is: Benchmarks.hs+ build-depends:+ attoparsec,+ base,+ bytestring,+ criterion >= 0.5,+ deepseq == 1.1.*,+ parsec >= 3.1.2,+ text
tests/QC/ByteString.hs view
@@ -2,7 +2,7 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} module QC.ByteString (tests) where -import Control.Applicative ((<$>))+import Control.Applicative ((<$>), (<*>)) import Prelude hiding (takeWhile) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.QuickCheck@@ -48,6 +48,11 @@ where v = L.head bs bs = L.pack s +peekWord8 s+ | L.null s = p == Just (Nothing, s)+ | otherwise = p == Just (Just (L.head s), s)+ where p = maybeP ((,) <$> P.peekWord8 <*> P.takeLazyByteString) s+ string s t = maybeP (P.string s') (s `L.append` t) == Just s' where s' = toStrict s @@ -94,6 +99,7 @@ testProperty "word8" word8, testProperty "notWord8" notWord8, testProperty "anyWord8" anyWord8,+ testProperty "peekWord8" peekWord8, testProperty "string" string, testProperty "skipWhile" skipWhile, testProperty "takeCount" takeCount,
tests/QC/Text.hs view
@@ -2,7 +2,7 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} module QC.Text (tests) where -import Control.Applicative ((<$>))+import Control.Applicative ((<$>), (<*>)) import Prelude hiding (takeWhile) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.QuickCheck@@ -48,9 +48,17 @@ where v = L.head bs bs = L.pack s +peekChar s+ | L.null s = p == Just (Nothing, s)+ | otherwise = p == Just (Just (L.head s), s)+ where p = maybeP ((,) <$> P.peekChar <*> P.takeLazyText) s+ string s t = maybeP (P.string s') (s `L.append` t) == Just s' where s' = toStrict s +stringCI s = P.parseOnly (P.stringCI fs) s == Right s+ where fs = T.toCaseFold s+ toStrict = T.concat . L.toChunks skipWhile w s =@@ -94,7 +102,9 @@ testProperty "char" char, testProperty "notChar" notChar, testProperty "anyChar" anyChar,+ testProperty "peekChar" peekChar, testProperty "string" string,+ testProperty "stringCI" stringCI, testProperty "skipWhile" skipWhile, testProperty "takeCount" takeCount, testProperty "takeWhile" takeWhile,