attoparsec 0.8.4.0 → 0.8.5.0
raw patch · 6 files changed
+542/−185 lines, 6 filesdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: base
API changes (from Hackage documentation)
- Data.Attoparsec: ensure :: Int -> Parser ()
- Data.Attoparsec: instance Functor Result
- Data.Attoparsec: instance Show r => Show (Result r)
- Data.Attoparsec.Char8: ensure :: Int -> Parser ()
+ Data.Attoparsec: atEnd :: Parser Bool
+ Data.Attoparsec: parseOnly :: Parser a -> ByteString -> Either String a
+ Data.Attoparsec: takeByteString :: Parser ByteString
+ Data.Attoparsec: takeLazyByteString :: Parser ByteString
+ Data.Attoparsec.Char8: D :: {-# UNPACK #-} !Double -> Number
+ Data.Attoparsec.Char8: I :: !Integer -> Number
+ Data.Attoparsec.Char8: atEnd :: Parser Bool
+ Data.Attoparsec.Char8: data Number
+ Data.Attoparsec.Char8: number :: Parser Number
+ Data.Attoparsec.Char8: takeByteString :: Parser ByteString
+ Data.Attoparsec.Char8: takeLazyByteString :: Parser ByteString
+ Data.Attoparsec.Number: D :: {-# UNPACK #-} !Double -> Number
+ Data.Attoparsec.Number: I :: !Integer -> Number
+ Data.Attoparsec.Number: data Number
+ Data.Attoparsec.Number: instance Data Number
+ Data.Attoparsec.Number: instance Eq Number
+ Data.Attoparsec.Number: instance Fractional Number
+ Data.Attoparsec.Number: instance Num Number
+ Data.Attoparsec.Number: instance Ord Number
+ Data.Attoparsec.Number: instance Real Number
+ Data.Attoparsec.Number: instance RealFrac Number
+ Data.Attoparsec.Number: instance Show Number
+ Data.Attoparsec.Number: instance Typeable Number
+ Data.Attoparsec.Zepto: atEnd :: Parser Bool
+ Data.Attoparsec.Zepto: data Parser a
+ Data.Attoparsec.Zepto: instance Alternative Parser
+ Data.Attoparsec.Zepto: instance Applicative Parser
+ Data.Attoparsec.Zepto: instance Functor Parser
+ Data.Attoparsec.Zepto: instance Monad Parser
+ Data.Attoparsec.Zepto: instance MonadPlus Parser
+ Data.Attoparsec.Zepto: instance Monoid (Parser a)
+ Data.Attoparsec.Zepto: parse :: Parser a -> ByteString -> Either String a
+ Data.Attoparsec.Zepto: string :: ByteString -> Parser ()
+ Data.Attoparsec.Zepto: take :: Int -> Parser ByteString
+ Data.Attoparsec.Zepto: takeWhile :: (Word8 -> Bool) -> Parser ByteString
- Data.Attoparsec: Done :: !ByteString -> r -> Result r
+ Data.Attoparsec: Done :: ByteString -> r -> Result r
- Data.Attoparsec: Fail :: !ByteString -> [String] -> String -> Result r
+ Data.Attoparsec: Fail :: ByteString -> [String] -> String -> Result r
- Data.Attoparsec.Char8: Done :: !ByteString -> r -> Result r
+ Data.Attoparsec.Char8: Done :: ByteString -> r -> Result r
- Data.Attoparsec.Char8: Fail :: !ByteString -> [String] -> String -> Result r
+ Data.Attoparsec.Char8: Fail :: ByteString -> [String] -> String -> Result r
- Data.Attoparsec.Char8: hexadecimal :: Integral a => Parser a
+ Data.Attoparsec.Char8: hexadecimal :: (Integral a, Bits a) => Parser a
- Data.Attoparsec.Char8: rational :: RealFloat a => Parser a
+ Data.Attoparsec.Char8: rational :: Fractional a => Parser a
Files
- Data/Attoparsec.hs +44/−50
- Data/Attoparsec/Char8.hs +43/−15
- Data/Attoparsec/Internal.hs +193/−118
- Data/Attoparsec/Number.hs +112/−0
- Data/Attoparsec/Zepto.hs +146/−0
- attoparsec.cabal +4/−2
Data/Attoparsec.hs view
@@ -15,6 +15,9 @@ -- * Differences from Parsec -- $parsec + -- * Incremental input+ -- $incremental+ -- * Performance considerations -- $performance @@ -28,6 +31,7 @@ -- * Running parsers , parse , feed+ , I.parseOnly , parseWith , parseTest @@ -61,14 +65,19 @@ , I.takeWhile1 , I.takeTill + -- ** Consume all remaining input+ , I.takeByteString+ , I.takeLazyByteString+ -- * State observation and manipulation functions , I.endOfInput- , I.ensure+ , I.atEnd ) where import Data.Attoparsec.Combinator import qualified Data.Attoparsec.Internal as I import qualified Data.ByteString as B+import Data.Attoparsec.Internal (Result(..), parse) -- $parsec --@@ -84,12 +93,11 @@ -- * Much of the performance advantage of Attoparsec is gained via -- high-performance parsers such as 'I.takeWhile' and 'I.string'. -- If you use complicated combinators that return lists of bytes or--- characters, there really isn't much performance difference the--- two libraries.+-- characters, there is less performance difference between the two+-- libraries. -- -- * Unlike Parsec 3, Attoparsec does not support being used as a--- monad transformer. This is mostly a matter of the implementor--- not having needed that functionality.+-- monad transformer. -- -- * Attoparsec is specialised to deal only with strict 'B.ByteString' -- input. Efficiency concernts rule out both lists and lazy@@ -97,12 +105,37 @@ -- allow consumption of very large input without a large footprint. -- For this need, Attoparsec's incremental input provides an -- excellent substitute, with much more control over when input--- takes place.+-- takes place. If you must use lazy bytestrings, see the 'Lazy'+-- module, which feeds lazy chunks to a regular parser. -- -- * Parsec parsers can produce more helpful error messages than -- Attoparsec parsers. This is a matter of focus: Attoparsec avoids -- the extra book-keeping in favour of higher performance. +-- $incremental+--+-- Attoparsec supports incremental input, meaning that you can feed it+-- a bytestring that represents only part of the expected total amount+-- of data to parse. If your parser reaches the end of a fragment of+-- input and could consume more input, it will suspend parsing and+-- return a 'Partial' continuation.+--+-- Supplying the 'Partial' continuation with another bytestring will+-- resume parsing at the point where it was suspended. You must be+-- prepared for the result of the resumed parse to be another+-- 'Partial' continuation.+--+-- To indicate that you have no more input, supply the 'Partial'+-- continuation with an empty bytestring.+--+-- Remember that some parsing combinators will not return a result+-- until they reach the end of input. They may thus cause 'Partial'+-- results to be returned.+--+-- If you do not need support for incremental input, consider using+-- the 'I.parseOnly' function to run your parser. It will never+-- prompt for more input.+ -- $performance -- -- If you write an Attoparsec-based parser carefully, it can be@@ -146,57 +179,18 @@ -- The 'Result' type is an instance of 'Functor', where 'fmap' -- transforms the value in a 'Done' result. --- | The result of a parse.-data Result r = Fail !B.ByteString [String] String- -- ^ The parse failed. The 'B.ByteString' 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 (B.ByteString -> Result r)- -- ^ Supply this continuation with more input so that- -- the parser can resume. To indicate that no more- -- input is available, use an 'B.empty' string.- | Done !B.ByteString r- -- ^ The parse succeeded. The 'B.ByteString' is the- -- input that had not yet been consumed (if any) when- -- the parse succeeded.--instance Show r => Show (Result r) where- show (Fail bs stk msg) =- "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg- show (Partial _) = "Partial _"- show (Done bs r) = "Done " ++ show bs ++ " " ++ show r- -- | If a parser has returned a 'Partial' result, supply it with more -- input. feed :: Result r -> B.ByteString -> Result r feed f@(Fail _ _ _) _ = f feed (Partial k) d = k d feed (Done bs r) d = Done (B.append bs d) r--fmapR :: (a -> b) -> Result a -> Result b-fmapR _ (Fail st stk msg) = Fail st stk msg-fmapR f (Partial k) = Partial (fmapR f . k)-fmapR f (Done bs r) = Done bs (f r)--instance Functor Result where- fmap = fmapR+{-# INLINE feed #-} -- | Run a parser and print its result to standard output. parseTest :: (Show a) => I.Parser a -> B.ByteString -> IO () parseTest p s = print (parse p s) -translate :: I.Result a -> Result a-translate (I.Fail st stk msg) = Fail (I.input st) stk msg-translate (I.Partial k) = Partial (translate . k)-translate (I.Done st r) = Done (I.input st) r---- | Run a parser and return its result.-parse :: I.Parser a -> B.ByteString -> Result a-parse m s = translate (I.parse m s)-{-# INLINE parse #-}- -- | Run a parser with an initial input string, and a monadic action -- that can supply more input if needed. parseWith :: Monad m =>@@ -208,10 +202,10 @@ -> B.ByteString -- ^ Initial input for the parser. -> m (Result a)-parseWith refill p s = step $ I.parse p s- where step (I.Fail st stk msg) = return $! Fail (I.input st) stk msg- step (I.Partial k) = (step . k) =<< refill- step (I.Done st r) = return $! Done (I.input st) r+parseWith refill p s = step $ parse p s+ where step (Partial k) = (step . k) =<< refill+ step r = return r+{-# INLINE parseWith #-} -- | Convert a 'Result' value to a 'Maybe' value. A 'Partial' result -- is treated as failure.
Data/Attoparsec/Char8.hs view
@@ -69,6 +69,10 @@ , takeWhile1 , takeTill + -- ** Consume all remaining input+ , I.takeByteString+ , I.takeLazyByteString+ -- * Text parsing , I.endOfLine , isEndOfLine@@ -79,17 +83,21 @@ , hexadecimal , signed , double+ , Number(..)+ , number , rational -- * State observation and manipulation functions , I.endOfInput- , I.ensure+ , I.atEnd ) where import Control.Applicative ((*>), (<$>), (<|>)) import Data.Attoparsec.Combinator import Data.Attoparsec.FastSet (charClass, memberChar) import Data.Attoparsec.Internal (Parser, (<?>))+import Data.Attoparsec.Number (Number(..))+import Data.Bits (Bits, (.|.), shiftL) import Data.ByteString.Internal (c2w, w2c) import Data.Ratio ((%)) import Data.String (IsString(..))@@ -328,14 +336,16 @@ -- @\'a\'@ through @\'f\'@ may be upper or lower case. -- -- This parser does not accept a leading @\"0x\"@ string.-hexadecimal :: Integral a => Parser a+hexadecimal :: (Integral a, Bits a) => Parser a {-# SPECIALISE hexadecimal :: Parser Int #-} hexadecimal = B8.foldl' step 0 `fmap` I.takeWhile1 isHexDigit- where isHexDigit w = (w >= 48 && w <= 57) || (x >= 97 && x <= 102)- where x = toLower w- step a w | w >= 48 && w <= 57 = a * 16 + fromIntegral (w - 48)- | otherwise = a * 16 + fromIntegral (x - 87)- where x = toLower w+ where+ isHexDigit w = (w >= 48 && w <= 57) ||+ (w >= 97 && w <= 102) ||+ (w >= 65 && w <= 90)+ step a w | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)+ | w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)+ | otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55) -- | Parse and decode an unsigned decimal number. decimal :: Integral a => Parser a@@ -379,7 +389,7 @@ -- -- >rational "3.foo" == Done 3.0 ".foo" -- >rational "3e" == Done 3.0 "e"-rational :: RealFloat a => Parser a+rational :: Fractional a => Parser a {-# SPECIALIZE rational :: Parser Double #-} rational = floaty $ \real frac fracDenom -> fromRational $ real % 1 + frac % fracDenom@@ -397,11 +407,29 @@ -- around the 15th decimal place. For 0.001% of numbers, this -- function will lose precision at the 13th or 14th decimal place. double :: Parser Double-double = floaty $ \real frac fracDenom ->- fromIntegral real +- fromIntegral frac / fromIntegral fracDenom+double = floaty asDouble -floaty :: RealFloat a => (Integer -> Integer -> Integer -> a) -> Parser a+asDouble :: Integer -> Integer -> Integer -> Double+asDouble real frac fracDenom =+ fromIntegral real + fromIntegral frac / fromIntegral fracDenom+{-# INLINE asDouble #-}++-- | Parse a number, attempting to preserve both speed and precision.+--+-- The syntax accepted by this parser is the same as for 'rational'.+--+-- /Note/: This function is almost ten times faster than 'rational'.+-- On integral inputs, it gives perfectly accurate answers, and on+-- floating point inputs, it is slightly less accurate than+-- 'rational'.+number :: Parser Number+number = floaty $ \real frac fracDenom ->+ if frac == 0 && fracDenom == 0+ then I real+ else D (asDouble real frac fracDenom)+{-# INLINE number #-}++floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a {-# INLINE floaty #-} floaty f = do let minus = 45@@ -429,7 +457,7 @@ else if power == 0 then f real fraction (10 ^ fracDigits) else f real fraction (10 ^ fracDigits) * (10 ^^ power)- return $! if sign == plus- then n- else -n+ return $ if sign == plus+ then n+ else -n
Data/Attoparsec/Internal.hs view
@@ -3,7 +3,7 @@ -- Module : Data.Attoparsec.Internal -- Copyright : Bryan O'Sullivan 2007-2010 -- License : BSD3--- +-- -- Maintainer : bos@serpentine.com -- Stability : experimental -- Portability : unknown@@ -16,10 +16,10 @@ -- * Parser types Parser , Result(..)- , S(input) -- * Running parsers , parse+ , parseOnly -- * Combinators , (<?>)@@ -51,8 +51,13 @@ , takeWhile1 , takeTill + -- ** Consume all remaining input+ , takeByteString+ , takeLazyByteString+ -- * State observation and manipulation functions , endOfInput+ , atEnd , ensure -- * Utilities@@ -74,62 +79,78 @@ import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Internal as B import qualified Data.ByteString.Unsafe as B+import qualified Data.ByteString.Lazy as L -data Result r = Fail S [String] String+-- | The result of a parse.+data Result r = Fail B.ByteString [String] String+ -- ^ The parse failed. The 'B.ByteString' 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 (B.ByteString -> Result r)- | Done S r+ -- ^ Supply this continuation with more input so that+ -- the parser can resume. To indicate that no more+ -- input is available, use an 'B.empty' string.+ | Done B.ByteString r+ -- ^ The parse succeeded. The 'B.ByteString' is the+ -- input that had not yet been consumed (if any) when+ -- the parse succeeded. +instance Show r => Show (Result r) where+ show (Fail bs stk msg) =+ "Fail " ++ show bs ++ " " ++ show stk ++ " " ++ show msg+ show (Partial _) = "Partial _"+ show (Done bs r) = "Done " ++ show bs ++ " " ++ show r++fmapR :: (a -> b) -> Result a -> Result b+fmapR _ (Fail st stk msg) = Fail st stk msg+fmapR f (Partial k) = Partial (fmapR f . k)+fmapR f (Done bs r) = Done bs (f r)++instance Functor Result where+ fmap = fmapR++newtype Input = I {unI :: B.ByteString}+newtype Added = A {unA :: B.ByteString}+ -- | The 'Parser' type is a monad. newtype Parser a = Parser {- runParser :: forall r. S+ runParser :: forall r. Input -> Added -> More -> Failure r -> Success a r -> Result r } -type Failure r = S -> [String] -> String -> Result r-type Success a r = S -> a -> Result r+type Failure r = Input -> Added -> More -> [String] -> String -> Result r+type Success a r = Input -> Added -> More -> a -> Result r -- | Have we read all available input? data More = Complete | Incomplete deriving (Eq, Show) -plusMore :: More -> More -> More-plusMore Complete _ = Complete-plusMore _ Complete = Complete-plusMore _ _ = Incomplete-{-# INLINE plusMore #-}--instance Monoid More where- mempty = Incomplete- mappend = plusMore--data S = S {- input :: !B.ByteString- , _added :: B.ByteString- , more :: !More- } deriving (Show)--instance Show r => Show (Result r) where- show (Fail _ stack msg) = "Fail " ++ show stack ++ " " ++ show msg- show (Partial _) = "Partial _"- show (Done bs r) = "Done " ++ show bs ++ " " ++ show r--addS :: S -> S -> S-addS (S s0 a0 c0) (S _s1 a1 c1) = S (s0 +++ a1) (a0 +++ a1) (mappend c0 c1)+addS :: Input -> Added -> More+ -> Input -> Added -> More+ -> (Input -> Added -> More -> r) -> r+addS i0 a0 m0 _i1 a1 m1 f =+ let !i = I (unI i0 +++ unA a1)+ a = A (unA a0 +++ unA a1)+ m = m0 <> m1+ in f i a m+ where+ Complete <> _ = Complete+ _ <> Complete = Complete+ _ <> _ = Incomplete {-# INLINE addS #-} -instance Monoid S where- mempty = S B.empty B.empty Incomplete- mappend = addS- bindP :: Parser a -> (a -> Parser b) -> Parser b bindP m g =- Parser (\st0 kf ks -> runParser m st0 kf (\s a -> runParser (g a) s kf ks))+ Parser $ \i0 a0 m0 kf ks -> runParser m i0 a0 m0 kf $+ \i1 a1 m1 a -> runParser (g a) i1 a1 m1 kf ks {-# INLINE bindP #-} returnP :: a -> Parser a-returnP a = Parser (\st0 _kf ks -> ks st0 a)+returnP a = Parser (\i0 a0 m0 _kf ks -> ks i0 a0 m0 a) {-# INLINE returnP #-} instance Monad Parser where@@ -137,15 +158,16 @@ (>>=) = bindP fail = failDesc -noAdds :: S -> S-noAdds (S s0 _a0 c0) = S s0 B.empty c0+noAdds :: Input -> Added -> More+ -> (Input -> Added -> More -> r) -> r+noAdds i0 _a0 m0 f = f i0 (A B.empty) m0 {-# INLINE noAdds #-} plus :: Parser a -> Parser a -> Parser a-plus a b = Parser $ \st0 kf ks ->- let kf' st1 _ _ = runParser b (mappend st0 st1) kf ks- !st2 = noAdds st0- in runParser a st2 kf' ks+plus a b = Parser $ \i0 a0 m0 kf ks ->+ let kf' i1 a1 m1 _ _ = addS i0 a0 m0 i1 a1 m1 $+ \ i2 a2 m2 -> runParser b i2 a2 m2 kf ks+ in noAdds i0 a0 m0 $ \i2 a2 m2 -> runParser a i2 a2 m2 kf' ks {-# INLINE plus #-} instance MonadPlus Parser where@@ -154,7 +176,8 @@ mplus = plus fmapP :: (a -> b) -> Parser a -> Parser b-fmapP p m = Parser (\st0 f k -> runParser m st0 f (\s a -> k s (p a)))+fmapP p m = Parser $ \i0 a0 m0 f k ->+ runParser m i0 a0 m0 f $ \i1 a1 s1 a -> k i1 a1 s1 (p a) {-# INLINE fmapP #-} instance Functor Parser where@@ -170,7 +193,7 @@ instance Applicative Parser where pure = returnP (<*>) = apP- + -- These definitions are equal to the defaults, but this -- way the optimizer doesn't have to work so hard to figure -- that out.@@ -188,48 +211,56 @@ (<|>) = plus failDesc :: String -> Parser a-failDesc err = Parser (\st0 kf _ks -> kf st0 [] msg)+failDesc err = Parser (\i0 a0 m0 kf _ks -> kf i0 a0 m0 [] msg) where msg = "Failed reading: " ++ err {-# INLINE failDesc #-} --- | Succeed only if at least @n@ bytes of input are available.-ensure :: Int -> Parser ()-ensure n = Parser $ \st0@(S s0 _a0 _c0) kf ks ->- if B.length s0 >= n- then ks st0 ()- else runParser (demandInput >> ensure n) st0 kf ks+-- | If at least @n@ bytes of input are available, return the current+-- input, otherwise fail.+ensure :: Int -> Parser B.ByteString+ensure !n = Parser $ \i0 a0 m0 kf ks ->+ if B.length (unI i0) >= n+ then ks i0 a0 m0 (unI i0)+ else runParser (demandInput >> ensure n) i0 a0 m0 kf ks -- | Ask for input. If we receive any, pass it to a success -- continuation, otherwise to a failure continuation.-prompt :: S -> (S -> Result r) -> (S -> Result r) -> Result r-prompt (S s0 a0 _c0) kf ks = Partial $ \s ->+prompt :: Input -> Added -> More+ -> (Input -> Added -> More -> Result r)+ -> (Input -> Added -> More -> Result r)+ -> Result r+prompt i0 a0 _m0 kf ks = Partial $ \s -> if B.null s- then kf $! S s0 a0 Complete- else ks $! S (s0 +++ s) (a0 +++ s) Incomplete+ then kf i0 a0 Complete+ else ks (I (unI i0 +++ s)) (A (unA a0 +++ s)) Incomplete -- | Immediately demand more input via a 'Partial' continuation -- result. demandInput :: Parser ()-demandInput = Parser $ \st0 kf ks ->- if more st0 == Complete- then kf st0 ["demandInput"] "not enough bytes"- else prompt st0 (\st -> kf st ["demandInput"] "not enough bytes") (`ks` ())+demandInput = Parser $ \i0 a0 m0 kf ks ->+ if m0 == Complete+ then kf i0 a0 m0 ["demandInput"] "not enough bytes"+ else let kf' i a m = kf i a m ["demandInput"] "not enough bytes"+ ks' i a m = ks i a m ()+ in prompt i0 a0 m0 kf' ks' -- | 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 = Parser $ \st0@(S s0 _a0 c0) _kf ks ->+wantInput = Parser $ \i0 a0 m0 _kf ks -> case () of- _ | not (B.null s0) -> ks st0 True- | c0 == Complete -> ks st0 False- | otherwise -> prompt st0 (`ks` False) (`ks` True)+ _ | not (B.null (unI i0)) -> ks i0 a0 m0 True+ | m0 == Complete -> ks i0 a0 m0 False+ | otherwise -> let kf' i a m = ks i a m False+ ks' i a m = ks i a m True+ in prompt i0 a0 m0 kf' ks' get :: Parser B.ByteString-get = Parser (\st0 _kf ks -> ks st0 (input st0))+get = Parser $ \i0 a0 m0 _kf ks -> ks i0 a0 m0 (unI i0) put :: B.ByteString -> Parser ()-put s = Parser (\(S _s0 a0 c0) _kf ks -> ks (S s a0 c0) ())+put s = Parser $ \_i0 a0 m0 _kf ks -> ks (I s) a0 m0 () (+++) :: B.ByteString -> B.ByteString -> B.ByteString (+++) = B.append@@ -243,8 +274,10 @@ -- lookahead. The downside to using this combinator is that it can -- retain input for longer than is desirable. try :: Parser a -> Parser a-try p = Parser $ \st0 kf ks ->- runParser p (noAdds st0) (kf . mappend st0) ks+try p = Parser $ \i0 a0 m0 kf ks ->+ noAdds i0 a0 m0 $ \i1 a1 m1 ->+ let kf' i2 a2 m2 = addS i0 a0 m0 i2 a2 m2 kf+ in runParser p i1 a1 m1 kf' ks -- | The parser @satisfy p@ succeeds for any byte for which the -- predicate @p@ returns 'True'. Returns the byte that is actually@@ -254,8 +287,7 @@ -- > where isDigit w = w >= 48 && w <= 57 satisfy :: (Word8 -> Bool) -> Parser Word8 satisfy p = do- ensure 1- s <- get+ s <- ensure 1 let w = B.unsafeHead s if p w then put (B.unsafeTail s) >> return w@@ -268,8 +300,7 @@ -- > where isDigit w = w >= 48 && w <= 57 skip :: (Word8 -> Bool) -> Parser () skip p = do- ensure 1- s <- get+ s <- ensure 1 if p (B.unsafeHead s) then put (B.unsafeTail s) else fail "skip"@@ -279,8 +310,7 @@ -- parser returns the transformed byte that was parsed. satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Parser a satisfyWith f p = do- ensure 1- s <- get+ s <- ensure 1 let c = f (B.unsafeHead s) if p c then put (B.unsafeTail s) >> return c@@ -292,14 +322,14 @@ hack :: Storable b => b -> Parser b hack dummy = do (fp,o,_) <- B.toForeignPtr `fmapP` take (sizeOf dummy)- return . B.inlinePerformIO . withForeignPtr fp $ \p -> peek (castPtr $ p `plusPtr` o)+ return . B.inlinePerformIO . withForeignPtr fp $ \p ->+ peek (castPtr $ p `plusPtr` o) -- | Consume @n@ bytes of input, but succeed only if the predicate -- returns 'True'. takeWith :: Int -> (B.ByteString -> Bool) -> Parser B.ByteString takeWith n p = do- ensure n- s <- get+ s <- ensure n let (h,t) = B.splitAt n s if p h then put t >> return h@@ -339,11 +369,11 @@ skipWhile p = go where go = do- input <- wantInput- when input $ do- t <- B8.dropWhile p <$> get- put t- when (B.null t) go+ t <- B8.dropWhile p <$> get+ put t+ when (B.null t) $ do+ input <- wantInput+ when input go {-# INLINE skipWhile #-} -- | Consume input as long as the predicate returns 'False'@@ -372,16 +402,36 @@ takeWhile p = (B.concat . reverse) `fmap` go [] where go acc = do- input <- wantInput- if input+ (h,t) <- B8.span p <$> get+ put t+ if B.null t then do- (h,t) <- B8.span p <$> get- put t- if B.null t+ input <- wantInput+ if input then go (h:acc) else return (h:acc)- else return acc+ else return (h:acc) +takeRest :: Parser [B.ByteString]+takeRest = go []+ where+ go acc = do+ input <- wantInput+ if input+ then do+ s <- get+ put B.empty+ go (s:acc)+ else return (reverse acc)++-- | Consume all remaining input and return it as a single string.+takeByteString :: Parser B.ByteString+takeByteString = B.concat `fmap` takeRest++-- | Consume all remaining input and return it as a single string.+takeLazyByteString :: Parser L.ByteString+takeLazyByteString = L.fromChunks `fmap` takeRest+ -- | A stateful scanner. The predicate consumes and transforms a -- state argument, and each transformed state is passed to successive -- invocations of the predicate on each byte of the input until one@@ -394,29 +444,33 @@ -- combinators such as 'many', because such parsers loop until a -- failure occurs. Careless use will thus result in an infinite loop. scan :: s -> (s -> Word8 -> Maybe s) -> Parser B.ByteString-scan s0 p = (B.concat . reverse) `fmap` go [] s0+scan s0 p = do+ chunks <- go [] s0+ case chunks of+ [x] -> return x+ xs -> return . B.concat . reverse $ xs where go acc s1 = do- input <- wantInput- if input+ let scanner (B.PS fp off len) =+ withForeignPtr fp $ \ptr -> do+ let inner !i !s | i == off+len = done (i-off) s+ | otherwise = do+ w <- peekByteOff ptr i+ case p s w of+ Just s' -> inner (i+1) s'+ Nothing -> done (i-off) s+ done !i !s = return (B.PS fp off i, B.PS fp (off+i) (len-i),s)+ inner off s1+ (h,t,s') <- (unsafePerformIO . scanner) <$> get+ put t+ if B.null t then do- let scanner (B.PS fp off len) =- withForeignPtr fp $ \ptr -> do- let inner !i !s | i == off+len = return (i-off,s)- | otherwise = do- w <- peekByteOff ptr i- case p s w of- Just s' -> inner (i+1) s'- Nothing -> return (i-off,s)- (i,s') <- inner off s1- return (B.PS fp off i, B.PS fp (off+i) (len-i),s')- (h,t,s') <- (unsafePerformIO . scanner) <$> get- put t- if B.null t+ input <- wantInput+ if input then go (h:acc) s' else return (h:acc)- else return acc-{-# INLINE scan #-} + else return (h:acc)+{-# INLINE scan #-} -- | Consume input as long as the predicate returns 'True', and return -- the consumed input.@@ -471,15 +525,24 @@ -- | Match only if all input has been consumed. endOfInput :: Parser ()-endOfInput = Parser $ \st0@S{..} kf ks ->- if B.null input- then if more == Complete- then ks st0 ()- else let kf' st1 _ _ = ks (mappend st0 st1) ()- ks' st1 _ = kf (mappend st0 st1) [] "endOfInput"- in runParser demandInput st0 kf' ks'- else kf st0 [] "endOfInput"- +endOfInput = Parser $ \i0 a0 m0 kf ks ->+ if B.null (unI i0)+ then if m0 == Complete+ then ks i0 a0 m0 ()+ else let kf' i1 a1 m1 _ _ = addS i0 a0 m0 i1 a1 m1 $+ \ i2 a2 m2 -> ks i2 a2 m2 ()+ ks' i1 a1 m1 _ = addS i0 a0 m0 i1 a1 m1 $+ \ i2 a2 m2 -> kf i2 a2 m2 []+ "endOfInput"+ in runParser demandInput i0 a0 m0 kf' ks'+ else kf i0 a0 m0 [] "endOfInput"++-- | Return an indication of whether the end of input has been+-- reached.+atEnd :: Parser Bool+atEnd = not <$> wantInput+{-# INLINE atEnd #-}+ -- | Match either a single newline character @\'\\n\'@, or a carriage -- return followed by a newline character @\"\\r\\n\"@. endOfLine :: Parser ()@@ -489,19 +552,31 @@ (<?>) :: Parser a -> String -- ^ the name to use if parsing fails -> Parser a-p <?> msg = Parser $ \s kf ks -> runParser p s (\s' strs m -> kf s' (msg:strs) m) ks+p <?> msg0 = Parser $ \i0 a0 m0 kf ks ->+ let kf' i a m strs msg = kf i a m (msg0:strs) msg+ in runParser p i0 a0 m0 kf' ks {-# INLINE (<?>) #-} infix 0 <?> -- | Terminal failure continuation. failK :: Failure a-failK st0 stack msg = Fail st0 stack msg+failK i0 _a0 _m0 stack msg = Fail (unI i0) stack msg+{-# INLINE failK #-} -- | Terminal success continuation. successK :: Success a a-successK state a = Done state a+successK i0 _a0 _m0 a = Done (unI i0) a+{-# INLINE successK #-} -- | Run a parser. parse :: Parser a -> B.ByteString -> Result a-parse m s = runParser m (S s B.empty Incomplete) failK successK+parse m s = runParser m (I s) (A B.empty) Incomplete failK successK {-# INLINE parse #-}++-- | Run a parser that cannot be resupplied via a 'Partial' result.+parseOnly :: Parser a -> B.ByteString -> Either String a+parseOnly m s = case runParser m (I s) (A B.empty) Complete failK successK of+ Fail _ _ err -> Left err+ Done _ a -> Right a+ _ -> error "parseOnly: impossible error!"+{-# INLINE parseOnly #-}
+ Data/Attoparsec/Number.hs view
@@ -0,0 +1,112 @@+{-# LANGUAGE DeriveDataTypeable #-}+-- |+-- Module : Data.Attoparsec.Number+-- Copyright : Bryan O'Sullivan 2011+-- License : BSD3+--+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- A simple number type, useful for parsing both exact and inexact+-- quantities without losing much precision.+module Data.Attoparsec.Number+ (+ Number(..)+ ) where++import Data.Data (Data)+import Data.Function (on)+import Data.Typeable (Typeable)++-- | A numeric type that can represent integers accurately, and+-- floating point numbers to the precision of a 'Double'.+data Number = I !Integer+ | D {-# UNPACK #-} !Double+ deriving (Typeable, Data)++instance Show Number where+ show (I a) = show a+ show (D a) = show a++binop :: (Integer -> Integer -> a) -> (Double -> Double -> a)+ -> Number -> Number -> a+binop _ d (D a) (D b) = d a b+binop i _ (I a) (I b) = i a b+binop _ d (D a) (I b) = d a (fromIntegral b)+binop _ d (I a) (D b) = d (fromIntegral a) b+{-# INLINE binop #-}++instance Eq Number where+ (==) = binop (==) (==)+ {-# INLINE (==) #-}++ (/=) = binop (/=) (/=)+ {-# INLINE (/=) #-}++instance Ord Number where+ (<) = binop (<) (<)+ {-# INLINE (<) #-}++ (>) = binop (>) (>)+ {-# INLINE (>) #-}++instance Num Number where+ (+) = binop (((I$!).) . (+)) (((D$!).) . (+))+ {-# INLINE (+) #-}++ (-) = binop (((I$!).) . (-)) (((D$!).) . (-))+ {-# INLINE (-) #-}++ (*) = binop (((I$!).) . (+)) (((D$!).) . (+))+ {-# INLINE (*) #-}++ abs (I a) = I $! abs a+ abs (D a) = D $! abs a+ {-# INLINE abs #-}++ negate (I a) = I $! negate a+ negate (D a) = D $! negate a+ {-# INLINE negate #-}++ signum (I a) = I $! signum a+ signum (D a) = D $! signum a+ {-# INLINE signum #-}++ fromInteger = (I$!) . fromInteger+ {-# INLINE fromInteger #-}++instance Real Number where+ toRational (I a) = fromIntegral a+ toRational (D a) = toRational a+ {-# INLINE toRational #-}++instance Fractional Number where+ fromRational = (D$!) . fromRational+ {-# INLINE fromRational #-}++ (/) = binop (((D$!).) . (/) `on` fromIntegral)+ (((D$!).) . (/))+ {-# INLINE (/) #-}++ recip (I a) = D $! recip (fromIntegral a)+ recip (D a) = D $! recip a+ {-# INLINE recip #-}++instance RealFrac Number where+ properFraction (I a) = (fromIntegral a,0)+ properFraction (D a) = case properFraction a of+ (i,d) -> (i,D d)+ {-# INLINE properFraction #-}+ truncate (I a) = fromIntegral a+ truncate (D a) = truncate a+ {-# INLINE truncate #-}+ round (I a) = fromIntegral a+ round (D a) = round a+ {-# INLINE round #-}+ ceiling (I a) = fromIntegral a+ ceiling (D a) = ceiling a+ {-# INLINE ceiling #-}+ floor (I a) = fromIntegral a+ floor (D a) = floor a+ {-# INLINE floor #-}
+ Data/Attoparsec/Zepto.hs view
@@ -0,0 +1,146 @@+{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples #-}++-- |+-- Module : Data.Attoparsec.Zepto+-- Copyright : Bryan O'Sullivan 2011+-- License : BSD3+-- +-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : unknown+--+-- A tiny, highly specialized combinator parser for 'B.ByteString'+-- strings.+--+-- While the main Attoparsec module generally performs well, this+-- module is particularly fast for simple non-recursive loops that+-- should not normally result in failed parses.+--+-- /Warning/: on more complex inputs involving recursion or failure,+-- parsers based on this module may be as much as /ten times slower/+-- than regular Attoparsec! You should /only/ use this module when you+-- have benchmarks that prove that its use speeds your code up.+module Data.Attoparsec.Zepto+ (+ Parser+ , parse+ , atEnd+ , string+ , take+ , takeWhile+ ) where++import Data.Word (Word8)+import Control.Applicative+import Control.Monad+import Data.Monoid+import qualified Data.ByteString as B+import qualified Data.ByteString.Unsafe as B+import Data.ByteString (ByteString)+import Prelude hiding (take, takeWhile)++newtype S = S {+ input :: ByteString+ }++data Result a = Fail String+ | OK !a++-- | A simple parser.+--+-- This monad is strict in its state, and the monadic bind operator+-- ('>>=') evaluates each result to weak head normal form before+-- passing it along.+newtype Parser a = Parser {+ runParser :: S -> (# Result a, S #)+ }++instance Functor Parser where+ fmap f m = Parser $ \s -> case runParser m s of+ (# OK a, s' #) -> (# OK (f a), s' #)+ (# Fail err, s' #) -> (# Fail err, s' #)+ {-# INLINE fmap #-}++instance Monad Parser where+ return a = Parser $ \s -> (# OK a, s #)+ {-# INLINE return #-}++ m >>= k = Parser $ \s -> case runParser m s of+ (# OK a, s' #) -> runParser (k a) s'+ (# Fail err, s' #) -> (# Fail err, s' #)+ {-# INLINE (>>=) #-}++ fail msg = Parser $ \s -> (# Fail msg, s #)++instance MonadPlus Parser where+ mzero = fail "mzero"+ {-# INLINE mzero #-}++ mplus a b = Parser $ \s ->+ case runParser a s of+ (# ok@(OK _), s' #) -> (# ok, s' #)+ (# _, _ #) -> case runParser b s of+ (# ok@(OK _), s'' #) -> (# ok, s'' #)+ (# err, s'' #) -> (# err, s'' #)+ {-# INLINE mplus #-}++instance Applicative Parser where+ pure = return+ (<*>) = ap++gets :: (S -> a) -> Parser a+gets f = Parser $ \s -> (# OK (f s), s #)+{-# INLINE gets #-}++put :: S -> Parser ()+put s = Parser $ \_ -> (# OK (), s #)+{-# INLINE put #-}++-- | Run a parser.+parse :: Parser a -> ByteString -> Either String a+parse p bs = case runParser p (S bs) of+ (# OK a, _ #) -> Right a+ (# Fail err, _ #) -> Left err++instance Monoid (Parser a) where+ mempty = fail "mempty"+ {-# INLINE mempty #-}+ mappend = mplus++instance Alternative Parser where+ empty = fail "empty"+ {-# INLINE empty #-}+ (<|>) = mplus++-- | Consume input while the predicate returns 'True'.+takeWhile :: (Word8 -> Bool) -> Parser ByteString+takeWhile p = do+ (h,t) <- gets (B.span p . input)+ put (S t)+ return h+{-# INLINE takeWhile #-}++-- | Consume @n@ bytes of input.+take :: Int -> Parser ByteString+take !n = do+ s <- gets input+ if B.length s >= n+ then put (S (B.unsafeDrop n s)) >> return (B.unsafeTake n s)+ else fail "insufficient input"+{-# INLINE take #-}++-- | Match a string exactly.+string :: ByteString -> Parser ()+string s = do+ i <- gets input+ if s `B.isPrefixOf` i+ then put (S (B.unsafeDrop (B.length s) i)) >> return ()+ else fail "string"+{-# INLINE string #-}++-- | Indicate whether the end of the input has been reached.+atEnd :: Parser Bool+atEnd = do+ i <- gets input+ return $! B.null i+{-# INLINE atEnd #-}
attoparsec.cabal view
@@ -1,12 +1,12 @@ name: attoparsec-version: 0.8.4.0+version: 0.8.5.0 license: BSD3 license-file: LICENSE category: Text, Parsing author: Bryan O'Sullivan <bos@serpentine.com> maintainer: Bryan O'Sullivan <bos@serpentine.com> stability: experimental-tested-with: GHC == 6.10.4, GHC == 6.12.1+tested-with: GHC == 6.10.4, GHC == 6.12.3, GHC == 7.0.1 synopsis: Fast combinator parsing for bytestrings cabal-version: >= 1.6 homepage: http://bitbucket.org/bos/attoparsec@@ -58,6 +58,8 @@ Data.Attoparsec.Combinator Data.Attoparsec.FastSet Data.Attoparsec.Lazy+ Data.Attoparsec.Number+ Data.Attoparsec.Zepto other-modules: Data.Attoparsec.Internal ghc-options: -Wall