attoparsec 0.12.1.1 → 0.12.1.2
raw patch · 8 files changed
+117/−17 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Data/Attoparsec/ByteString/Buffer.hs +2/−1
- Data/Attoparsec/Internal.hs +2/−12
- Data/Attoparsec/Text/Buffer.hs +3/−2
- attoparsec.cabal +5/−2
- changelog.md +11/−0
- tests/QC.hs +2/−0
- tests/QC/Rechunked.hs +55/−0
- tests/QC/Simple.hs +37/−0
Data/Attoparsec/ByteString/Buffer.hs view
@@ -65,6 +65,7 @@ import GHC.ForeignPtr (mallocPlainForeignPtrBytes) import Prelude hiding (length) +-- If _cap is zero, this buffer is empty. data Buffer = Buf { _fp :: {-# UNPACK #-} !(ForeignPtr Word8) , _off :: {-# UNPACK #-} !Int@@ -96,7 +97,7 @@ mconcat xs = foldl1' mappend xs pappend :: Buffer -> ByteString -> Buffer-pappend (Buf _ _ _ 0 _) (PS fp off len) = Buf fp off len 0 0+pappend (Buf _ _ _ 0 _) bs = buffer bs pappend buf (PS fp off len) = append buf fp off len append :: Buffer -> ForeignPtr a -> Int -> Int -> Buffer
Data/Attoparsec/Internal.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, BangPatterns, ScopedTypeVariables #-}+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-} -- | -- Module : Data.Attoparsec.Internal -- Copyright : Bryan O'Sullivan 2007-2014@@ -22,11 +22,9 @@ ) where import Control.Applicative ((<$>))-#if __GLASGOW_HASKELL__ >= 700+import Data.Attoparsec.Internal.Types import Data.ByteString (ByteString) import Data.Text (Text)-#endif-import Data.Attoparsec.Internal.Types import Prelude hiding (succ) -- | Compare two 'IResult' values for equality.@@ -53,7 +51,6 @@ 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)@@ -64,7 +61,6 @@ -> (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.@@ -75,10 +71,8 @@ _ -> 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@@ -103,10 +97,8 @@ 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.@@ -127,7 +119,6 @@ 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@@ -140,7 +131,6 @@ -> 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
Data/Attoparsec/Text/Buffer.hs view
@@ -51,6 +51,7 @@ import Prelude hiding (length) import qualified Data.Text.Array as A +-- If _cap is zero, this buffer is empty. data Buffer = Buf { _arr :: {-# UNPACK #-} !A.Array , _off :: {-# UNPACK #-} !Int@@ -82,8 +83,8 @@ mconcat xs = foldl1' mappend xs pappend :: Buffer -> Text -> Buffer-pappend (Buf _ _ _ 0 _) (Text arr off len) = Buf arr off len 0 0-pappend buf (Text arr off len) = append buf arr off len+pappend (Buf _ _ _ 0 _) t = buffer t+pappend buf (Text arr off len) = append buf arr off len append :: Buffer -> A.Array -> Int -> Int -> Buffer append (Buf arr0 off0 len0 cap0 gen0) !arr1 !off1 !len1 = runST $ do
attoparsec.cabal view
@@ -1,5 +1,5 @@ name: attoparsec-version: 0.12.1.1+version: 0.12.1.2 license: BSD3 license-file: LICENSE category: Text, Parsing@@ -84,6 +84,8 @@ QC.ByteString QC.Combinator QC.Common+ QC.Rechunked+ QC.Simple QC.Text ghc-options:@@ -101,7 +103,8 @@ scientific, test-framework >= 0.8.0.2, test-framework-quickcheck2 >= 0.3.0.3,- text+ text,+ vector benchmark benchmarks type: exitcode-stdio-1.0
changelog.md view
@@ -1,3 +1,14 @@+0.12.1.2++* Fixed the incorrect tracking of capacity if the initial buffer was+ empty (https://github.com/bos/attoparsec/issues/75)++0.12.1.1++* Fixed a data corruption bug that occurred under some circumstances+ if a buffer grew after prompting for more input+ (https://github.com/bos/attoparsec/issues/74)+ 0.12.1.0 * Now compatible with GHC 7.9
tests/QC.hs view
@@ -4,6 +4,7 @@ import qualified QC.Buffer as Buffer import qualified QC.ByteString as ByteString import qualified QC.Combinator as Combinator+import qualified QC.Simple as Simple import qualified QC.Text as Text import Test.Framework (defaultMain, testGroup) @@ -13,5 +14,6 @@ testGroup "bs" ByteString.tests , testGroup "buf" Buffer.tests , testGroup "combinator" Combinator.tests+ , testGroup "simple" Simple.tests , testGroup "text" Text.tests ]
+ tests/QC/Rechunked.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE BangPatterns #-}++module QC.Rechunked (+ rechunkBS+ , rechunkT+ ) where++import Control.Monad (forM, forM_)+import Control.Monad.ST (runST)+import Data.List (unfoldr)+import Test.QuickCheck (Gen, choose)+import qualified Data.ByteString as B+import qualified Data.Text as T+import qualified Data.Vector as V+import qualified Data.Vector.Generic as G+import qualified Data.Vector.Generic.Mutable as M++rechunkBS :: B.ByteString -> Gen [B.ByteString]+rechunkBS = fmap (map B.copy) . rechunk_ B.splitAt B.length++rechunkT :: T.Text -> Gen [T.Text]+rechunkT = fmap (map T.copy) . rechunk_ T.splitAt T.length++rechunk_ :: (Int -> a -> (a,a)) -> (a -> Int) -> a -> Gen [a]+rechunk_ split len xs = (unfoldr go . (,) xs) `fmap` rechunkSizes (len xs)+ where go (b,r:rs) = Just (h, (t,rs))+ where (h,t) = split r b+ go (_,_) = Nothing++rechunkSizes :: Int -> Gen [Int]+rechunkSizes n0 = shuffle =<< loop [] (0:repeat 1) n0+ where loop _ [] _ = error "it's 2014, where's my Stream type?"+ loop acc (lb:lbs) n+ | n <= 0 = shuffle (reverse acc)+ | otherwise = do+ !i <- choose (lb,n)+ loop (i:acc) lbs (n-i)++shuffle :: [Int] -> Gen [Int]+shuffle (0:xs) = (0:) `fmap` shuffle xs+shuffle xs = fisherYates xs++fisherYates :: [a] -> Gen [a]+fisherYates xs = (V.toList . V.backpermute v) `fmap` swapIndices (G.length v)+ where+ v = V.fromList xs+ swapIndices n0 = do+ swaps <- forM [0..n] $ \i -> ((,) i) `fmap` choose (i,n)+ return (runST (swapAll swaps))+ where+ n = n0 - 1+ swapAll ijs = do+ mv <- G.unsafeThaw (G.enumFromTo 0 n :: V.Vector Int)+ forM_ ijs $ uncurry (M.swap mv)+ G.unsafeFreeze mv
+ tests/QC/Simple.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}++module QC.Simple (+ tests+ ) where++import Control.Applicative ((<|>))+import Data.ByteString (ByteString)+import Data.List (foldl')+import Data.Maybe (fromMaybe)+import QC.Rechunked (rechunkBS)+import Test.Framework (Test)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck (Property, counterexample, forAll)+import qualified Data.Attoparsec.ByteString.Char8 as A++t_issue75 = expect issue75 "ab" (A.Done "" "b")++issue75 :: A.Parser ByteString+issue75 = "a" >> ("b" <|> "")++expect :: (Show r, Eq r) => A.Parser r -> ByteString -> A.Result r -> Property+expect p input wanted =+ forAll (rechunkBS input) $ \in' ->+ let result = parse p in'+ in counterexample (show result ++ " /= " ++ show wanted) $+ fromMaybe False (A.compareResults result wanted)++parse :: A.Parser r -> [ByteString] -> A.Result r+parse p (x:xs) = foldl' A.feed (A.parse p x) xs+parse p [] = A.parse p ""++tests :: [Test]+tests = [+ testProperty "issue75" t_issue75+ ]