@@ -1,15 +1,15 @@
1−{-# LANGUAGE BangPatterns, Rank2Types, OverloadedStrings,
1+{-# LANGUAGE BangPatterns, CPP, GADTs, OverloadedStrings, RankNTypes,
2− RecordWildCards, MagicHash, UnboxedTuples #-}
2+ RecordWildCards #-}
4-- Module : Data.Attoparsec.ByteString.Internal
4-- Module : Data.Attoparsec.ByteString.Internal
5−-- Copyright : Bryan O'Sullivan 2007-2011
5+-- Copyright : Bryan O'Sullivan 2007-2015
6-- License : BSD3
6-- License : BSD3
8-- Maintainer : bos@serpentine.com
8-- Maintainer : bos@serpentine.com
9-- Stability : experimental
9-- Stability : experimental
10-- Portability : unknown
10-- Portability : unknown
12−-- Simple, efficient parser combinators for 'B.ByteString' strings,
12+-- Simple, efficient parser combinators for 'ByteString' strings,
13-- loosely based on the Parsec library.
13-- loosely based on the Parsec library.
15module Data.Attoparsec.ByteString.Internal
15module Data.Attoparsec.ByteString.Internal
@@ -47,7 +47,7 @@ module Data.Attoparsec.ByteString.Internal
47 -- * Efficient string handling
47 -- * Efficient string handling
48 , skipWhile
48 , skipWhile
50− , stringTransform
50+ , stringCI
53 , runScanner
53 , runScanner
@@ -66,17 +66,25 @@ module Data.Attoparsec.ByteString.Internal
69+#if !MIN_VERSION_base(4,8,0)
69−import Control.Applicative ((<|>), (<$>))
70+import Control.Applicative ((<$>))
72+import Control.Applicative ((<|>))
70import Control.Monad (when)
73import Control.Monad (when)
74+import Data.Attoparsec.ByteString.Buffer (Buffer, buffer)
71import Data.Attoparsec.ByteString.FastSet (charClass, memberWord8)
75import Data.Attoparsec.ByteString.FastSet (charClass, memberWord8)
72import Data.Attoparsec.Combinator ((<?>))
76import Data.Attoparsec.Combinator ((<?>))
77+import Data.Attoparsec.Internal
78+import Data.Attoparsec.Internal.Fhthagn (inlinePerformIO)
73import Data.Attoparsec.Internal.Types hiding (Parser, Failure, Success)
79import Data.Attoparsec.Internal.Types hiding (Parser, Failure, Success)
80+import Data.ByteString (ByteString)
81+import Data.List (intercalate)
74import Data.Word (Word8)
82import Data.Word (Word8)
75import Foreign.ForeignPtr (withForeignPtr)
83import Foreign.ForeignPtr (withForeignPtr)
76import Foreign.Ptr (castPtr, minusPtr, plusPtr)
84import Foreign.Ptr (castPtr, minusPtr, plusPtr)
77import Foreign.Storable (Storable(peek, sizeOf))
85import Foreign.Storable (Storable(peek, sizeOf))
78import Prelude hiding (getChar, succ, take, takeWhile)
86import Prelude hiding (getChar, succ, take, takeWhile)
79−import Data.ByteString (ByteString)
87+import qualified Data.Attoparsec.ByteString.Buffer as Buf
80import qualified Data.Attoparsec.Internal.Types as T
88import qualified Data.Attoparsec.Internal.Types as T
81import qualified Data.ByteString as B8
89import qualified Data.ByteString as B8
82import qualified Data.ByteString.Char8 as B
90import qualified Data.ByteString.Char8 as B
@@ -84,13 +92,10 @@ import qualified Data.ByteString.Internal as B
84import qualified Data.ByteString.Lazy as L
92import qualified Data.ByteString.Lazy as L
85import qualified Data.ByteString.Unsafe as B
93import qualified Data.ByteString.Unsafe as B
87−import GHC.Base (realWorld#)
88−import GHC.IO (IO(IO))
90−type Parser = T.Parser B.ByteString
95+type Parser = T.Parser ByteString
91−type Result = IResult B.ByteString
96+type Result = IResult ByteString
92−type Failure r = T.Failure B.ByteString r
97+type Failure r = T.Failure ByteString Buffer r
93−type Success a r = T.Success B.ByteString a r
98+type Success a r = T.Success ByteString Buffer a r
95-- | The parser @satisfy p@ succeeds for any byte for which the
100-- | The parser @satisfy p@ succeeds for any byte for which the
96-- predicate @p@ returns 'True'. Returns the byte that is actually
101-- predicate @p@ returns 'True'. Returns the byte that is actually
@@ -100,8 +105,7 @@ type Success a r = T.Success B.ByteString a r
100-- > where isDigit w = w >= 48 && w <= 57
105-- > where isDigit w = w >= 48 && w <= 57
101satisfy :: (Word8 -> Bool) -> Parser Word8
106satisfy :: (Word8 -> Bool) -> Parser Word8
102satisfy p = do
107satisfy p = do
103− c <- ensure 1
108+ h <- peekWord8'
104− let !h = B.unsafeHead c
106 then advance 1 >> return h
110 then advance 1 >> return h
107 else fail "satisfy"
111 else fail "satisfy"
@@ -114,8 +118,8 @@ satisfy p = do
114-- > where isDigit w = w >= 48 && w <= 57
118-- > where isDigit w = w >= 48 && w <= 57
115skip :: (Word8 -> Bool) -> Parser ()
119skip :: (Word8 -> Bool) -> Parser ()
116skip p = do
120skip p = do
117− s <- ensure 1
121+ h <- peekWord8'
118− if p (B.unsafeHead s)
122+ if p h
119 then advance 1
123 then advance 1
120 else fail "skip"
124 else fail "skip"
@@ -124,8 +128,8 @@ skip p = do
124-- parser returns the transformed byte that was parsed.
128-- parser returns the transformed byte that was parsed.
125satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Parser a
129satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Parser a
126satisfyWith f p = do
130satisfyWith f p = do
127− s <- ensure 1
131+ h <- peekWord8'
128− let c = f $! B.unsafeHead s
132+ let c = f h
130 then advance 1 >> return c
134 then advance 1 >> return c
131 else fail "satisfyWith"
135 else fail "satisfyWith"
@@ -137,22 +141,15 @@ storable = hack undefined
137 hack :: Storable b => b -> Parser b
141 hack :: Storable b => b -> Parser b
138 hack dummy = do
142 hack dummy = do
139 (fp,o,_) <- B.toForeignPtr `fmap` take (sizeOf dummy)
143 (fp,o,_) <- B.toForeignPtr `fmap` take (sizeOf dummy)
140− return . B.inlinePerformIO . withForeignPtr fp $ \p ->
144+ return . inlinePerformIO . withForeignPtr fp $ \p ->
141 peek (castPtr $ p `plusPtr` o)
145 peek (castPtr $ p `plusPtr` o)
143−-- | Consume @n@ bytes of input, but succeed only if the predicate
147+-- | Consume exactly @n@ bytes of input.
145−takeWith :: Int -> (B.ByteString -> Bool) -> Parser B.ByteString
148+take :: Int -> Parser ByteString
146−takeWith n0 p = do
149+take n0 = do
147 let n = max n0 0
150 let n = max n0 0
148 s <- ensure n
151 s <- ensure n
150− then advance n >> return s
152+ advance n >> return s
151− else fail "takeWith"
153−-- | Consume exactly @n@ bytes of input.
154−take :: Int -> Parser B.ByteString
155−take n = takeWith n (const True)
156{-# INLINE take #-}
153{-# INLINE take #-}
158-- | @string s@ parses a sequence of bytes that identically match
155-- | @string s@ parses a sequence of bytes that identically match
@@ -168,16 +165,62 @@ take n = takeWith n (const True)
169-- The reason for its failure is that the first branch is a
166-- The reason for its failure is that the first branch is a
170-- partial match, and will consume the letters @\'f\'@ and @\'o\'@
167-- partial match, and will consume the letters @\'f\'@ and @\'o\'@
171−-- before failing. In Attoparsec, the above parser will /succeed/ on
168+-- before failing. In attoparsec, the above parser will /succeed/ on
172-- that input, because the failed first branch will consume nothing.
169-- that input, because the failed first branch will consume nothing.
173−string :: B.ByteString -> Parser B.ByteString
170+string :: ByteString -> Parser ByteString
174−string s = takeWith (B.length s) (==s)
171+string s = string_ (stringSuspended id) id s
175{-# INLINE string #-}
172{-# INLINE string #-}
177−stringTransform :: (B.ByteString -> B.ByteString) -> B.ByteString
174+-- ASCII-specific but fast, oh yes.
178− -> Parser B.ByteString
175+toLower :: Word8 -> Word8
179−stringTransform f s = takeWith (B.length s) ((==f s) . f)
176+toLower w | w >= 65 && w <= 90 = w + 32
180−{-# INLINE stringTransform #-}
177+ | otherwise = w
179+-- | Satisfy a literal string, ignoring case.
180+stringCI :: ByteString -> Parser ByteString
181+stringCI s = string_ (stringSuspended lower) lower s
182+ where lower = B8.map toLower
183+{-# INLINE stringCI #-}
185+string_ :: (forall r. ByteString -> ByteString -> Buffer -> Pos -> More
186+ -> Failure r -> Success ByteString r -> Result r)
187+ -> (ByteString -> ByteString)
188+ -> ByteString -> Parser ByteString
189+string_ suspended f s0 = T.Parser $ \t pos more lose succ ->
192+ in if lengthAtLeast pos n t
193+ then let t' = substring pos (Pos n) t
195+ then succ t (pos + Pos n) more t'
196+ else lose t pos more [] "string"
197+ else let t' = Buf.unsafeDrop (fromPos pos) t
198+ in if f t' `B.isPrefixOf` s
199+ then suspended s (B.drop (B.length t') s) t pos more lose succ
200+ else lose t pos more [] "string"
201+{-# INLINE string_ #-}
203+stringSuspended :: (ByteString -> ByteString)
204+ -> ByteString -> ByteString -> Buffer -> Pos -> More
206+ -> Success ByteString r
208+stringSuspended f s0 s t pos more lose succ =
209+ runParser (demandInput_ >>= go) t pos more lose succ
210+ where go s'0 = T.Parser $ \t' pos' more' lose' succ' ->
215+ then if B.unsafeTake m s' == s
216+ then let o = Pos (B.length s0)
217+ in succ' t' (pos' + o) more'
218+ (substring pos' o t')
219+ else lose' t' pos' more' [] "string"
220+ else if s' == B.unsafeTake n s
221+ then stringSuspended f s0 (B.unsafeDrop n s)
222+ t' pos' more' lose' succ'
223+ else lose' t' pos' more' [] "string"
182-- | Skip past input for as long as the predicate returns 'True'.
225-- | Skip past input for as long as the predicate returns 'True'.
183skipWhile :: (Word8 -> Bool) -> Parser ()
226skipWhile :: (Word8 -> Bool) -> Parser ()
@@ -185,11 +228,8 @@ skipWhile p = go
187 t <- B8.takeWhile p <$> get
230 t <- B8.takeWhile p <$> get
188− advance (B.length t)
231+ continue <- inputSpansChunks (B.length t)
189− eoc <- endOfChunk
232+ when continue go
193{-# INLINE skipWhile #-}
233{-# INLINE skipWhile #-}
195-- | Consume input as long as the predicate returns 'False'
235-- | Consume input as long as the predicate returns 'False'
@@ -202,7 +242,7 @@ skipWhile p = go
202-- combinators such as 'Control.Applicative.many', because such
242-- combinators such as 'Control.Applicative.many', because such
203-- parsers loop until a failure occurs. Careless use will thus result
243-- parsers loop until a failure occurs. Careless use will thus result
204-- in an infinite loop.
244-- in an infinite loop.
205−takeTill :: (Word8 -> Bool) -> Parser B.ByteString
245+takeTill :: (Word8 -> Bool) -> Parser ByteString
206takeTill p = takeWhile (not . p)
246takeTill p = takeWhile (not . p)
207{-# INLINE takeTill #-}
247{-# INLINE takeTill #-}
@@ -216,23 +256,27 @@ takeTill p = takeWhile (not . p)
216-- combinators such as 'Control.Applicative.many', because such
256-- combinators such as 'Control.Applicative.many', because such
217-- parsers loop until a failure occurs. Careless use will thus result
257-- parsers loop until a failure occurs. Careless use will thus result
218-- in an infinite loop.
258-- in an infinite loop.
219−takeWhile :: (Word8 -> Bool) -> Parser B.ByteString
259+takeWhile :: (Word8 -> Bool) -> Parser ByteString
220−takeWhile p = (B.concat . reverse) `fmap` go []
260+takeWhile p = do
261+ s <- B8.takeWhile p <$> get
262+ continue <- inputSpansChunks (B.length s)
264+ then takeWhileAcc p [s]
266+{-# INLINE takeWhile #-}
268+takeWhileAcc :: (Word8 -> Bool) -> [ByteString] -> Parser ByteString
222 go acc = do
271 go acc = do
223 s <- B8.takeWhile p <$> get
272 s <- B8.takeWhile p <$> get
224− advance (B.length s)
273+ continue <- inputSpansChunks (B.length s)
225− eoc <- endOfChunk
274+ if continue
230− then go (s:acc)
275+ then go (s:acc)
231− else return (s:acc)
276+ else return $ concatReverse (s:acc)
232− else return (s:acc)
277+{-# INLINE takeWhileAcc #-}
233−{-# INLINE takeWhile #-}
235−takeRest :: Parser [B.ByteString]
279+takeRest :: Parser [ByteString]
236takeRest = go []
280takeRest = go []
238 go acc = do
282 go acc = do
@@ -245,7 +289,7 @@ takeRest = go []
245 else return (reverse acc)
289 else return (reverse acc)
247-- | Consume all remaining input and return it as a single string.
291-- | Consume all remaining input and return it as a single string.
248−takeByteString :: Parser B.ByteString
292+takeByteString :: Parser ByteString
249takeByteString = B.concat `fmap` takeRest
293takeByteString = B.concat `fmap` takeRest
251-- | Consume all remaining input and return it as a single string.
295-- | Consume all remaining input and return it as a single string.
@@ -254,7 +298,7 @@ takeLazyByteString = L.fromChunks `fmap` takeRest
255data T s = T {-# UNPACK #-} !Int s
299data T s = T {-# UNPACK #-} !Int s
257−scan_ :: (s -> [B.ByteString] -> Parser r) -> s -> (s -> Word8 -> Maybe s)
301+scan_ :: (s -> [ByteString] -> Parser r) -> s -> (s -> Word8 -> Maybe s)
258 -> Parser r
302 -> Parser r
259scan_ f s0 p = go [] s0
303scan_ f s0 p = go [] s0
@@ -275,14 +319,9 @@ scan_ f s0 p = go [] s0
275 bs <- get
319 bs <- get
276 let T i s' = inlinePerformIO $ scanner bs
320 let T i s' = inlinePerformIO $ scanner bs
277 !h = B.unsafeTake i bs
321 !h = B.unsafeTake i bs
278− advance i
322+ continue <- inputSpansChunks i
279− eoc <- endOfChunk
323+ if continue
284− then go (h:acc) s'
324+ then go (h:acc) s'
286 else f s' (h:acc)
325 else f s' (h:acc)
287{-# INLINE scan_ #-}
326{-# INLINE scan_ #-}
@@ -298,17 +337,14 @@ scan_ f s0 p = go [] s0
298-- combinators such as 'Control.Applicative.many', because such
337-- combinators such as 'Control.Applicative.many', because such
299-- parsers loop until a failure occurs. Careless use will thus result
338-- parsers loop until a failure occurs. Careless use will thus result
300-- in an infinite loop.
339-- in an infinite loop.
301−scan :: s -> (s -> Word8 -> Maybe s) -> Parser B.ByteString
340+scan :: s -> (s -> Word8 -> Maybe s) -> Parser ByteString
302−scan = scan_ $ \_ chunks ->
341+scan = scan_ $ \_ chunks -> return $! concatReverse chunks
305− xs -> return $! B.concat $ reverse xs
306{-# INLINE scan #-}
342{-# INLINE scan #-}
308-- | Like 'scan', but generalized to return the final state of the
344-- | Like 'scan', but generalized to return the final state of the
309-- scanner.
345-- scanner.
310−runScanner :: s -> (s -> Word8 -> Maybe s) -> Parser (B.ByteString, s)
346+runScanner :: s -> (s -> Word8 -> Maybe s) -> Parser (ByteString, s)
311−runScanner = scan_ $ \s xs -> return (B.concat (reverse xs), s)
347+runScanner = scan_ $ \s xs -> let !sx = concatReverse xs in return (sx, s)
312{-# INLINE runScanner #-}
348{-# INLINE runScanner #-}
314-- | Consume input as long as the predicate returns 'True', and return
350-- | Consume input as long as the predicate returns 'True', and return
@@ -317,7 +353,7 @@ runScanner = scan_ $ \s xs -> return (B.concat (reverse xs), s)
317-- This parser requires the predicate to succeed on at least one byte
353-- This parser requires the predicate to succeed on at least one byte
318-- of input: it will fail if the predicate never returns 'True' or if
354-- of input: it will fail if the predicate never returns 'True' or if
319-- there is no input left.
355-- there is no input left.
320−takeWhile1 :: (Word8 -> Bool) -> Parser B.ByteString
356+takeWhile1 :: (Word8 -> Bool) -> Parser ByteString
321takeWhile1 p = do
357takeWhile1 p = do
322 (`when` demandInput) =<< endOfChunk
358 (`when` demandInput) =<< endOfChunk
323 s <- B8.takeWhile p <$> get
359 s <- B8.takeWhile p <$> get
@@ -328,8 +364,9 @@ takeWhile1 p = do
328 advance len
364 advance len
329 eoc <- endOfChunk
365 eoc <- endOfChunk
331− then (s<>) `fmap` takeWhile p
367+ then takeWhileAcc p [s]
332 else return s
368 else return s
369+{-# INLINE takeWhile1 #-}
334-- | Match any byte in a set.
371-- | Match any byte in a set.
@@ -377,13 +414,13 @@ notWord8 c = satisfy (/= c) <?> "not " ++ show c
377peekWord8 :: Parser (Maybe Word8)
414peekWord8 :: Parser (Maybe Word8)
378peekWord8 = T.Parser $ \t pos@(Pos pos_) more _lose succ ->
415peekWord8 = T.Parser $ \t pos@(Pos pos_) more _lose succ ->
379 case () of
416 case () of
380− _| pos_ < B.length t ->
417+ _| pos_ < Buf.length t ->
381− let !w = B.unsafeIndex t pos_
418+ let !w = Buf.unsafeIndex t pos_
382 in succ t pos more (Just w)
419 in succ t pos more (Just w)
383 | more == Complete ->
420 | more == Complete ->
384 succ t pos more Nothing
421 succ t pos more Nothing
385 | otherwise ->
422 | otherwise ->
386− let succ' t' pos' more' = let !w = B.unsafeIndex t pos_
423+ let succ' t' pos' more' = let !w = Buf.unsafeIndex t' pos_
387 in succ t' pos' more' (Just w)
424 in succ t' pos' more' (Just w)
388 lose' t' pos' more' = succ t' pos' more' Nothing
425 lose' t' pos' more' = succ t' pos' more' Nothing
389 in prompt t pos more lose' succ'
426 in prompt t pos more lose' succ'
@@ -392,9 +429,11 @@ peekWord8 = T.Parser $ \t pos@(Pos pos_) more _lose succ ->
392-- | Match any byte, to perform lookahead. Does not consume any
429-- | Match any byte, to perform lookahead. Does not consume any
393-- input, but will fail if end of input has been reached.
430-- input, but will fail if end of input has been reached.
394peekWord8' :: Parser Word8
431peekWord8' :: Parser Word8
395−peekWord8' = do
432+peekWord8' = T.Parser $ \t pos more lose succ ->
396− s <- ensure 1
433+ if lengthAtLeast pos 1 t
397− return $! B.unsafeHead s
434+ then succ t pos more (Buf.unsafeIndex t (fromPos pos))
435+ else let succ' t' pos' more' bs' = succ t' pos' more' $! B.unsafeHead bs'
436+ in ensureSuspended 1 t pos more lose succ'
398{-# INLINE peekWord8' #-}
437{-# INLINE peekWord8' #-}
400-- | Match either a single newline character @\'\\n\'@, or a carriage
439-- | Match either a single newline character @\'\\n\'@, or a carriage
@@ -404,51 +443,62 @@ endOfLine = (word8 10 >> return ()) <|> (string "\r\n" >> return ())
405-- | Terminal failure continuation.
444-- | Terminal failure continuation.
406failK :: Failure a
445failK :: Failure a
407−failK t (Pos pos) _more stack msg = Fail (B.unsafeDrop pos t) stack msg
446+failK t (Pos pos) _more stack msg = Fail (Buf.unsafeDrop pos t) stack msg
408{-# INLINE failK #-}
447{-# INLINE failK #-}
410-- | Terminal success continuation.
449-- | Terminal success continuation.
411successK :: Success a a
450successK :: Success a a
412−successK t (Pos pos) _more a = Done (B.unsafeDrop pos t) a
451+successK t (Pos pos) _more a = Done (Buf.unsafeDrop pos t) a
413{-# INLINE successK #-}
452{-# INLINE successK #-}
415-- | Run a parser.
454-- | Run a parser.
416−parse :: Parser a -> B.ByteString -> Result a
455+parse :: Parser a -> ByteString -> Result a
417−parse m s = T.runParser m s (Pos 0) Incomplete failK successK
456+parse m s = T.runParser m (buffer s) (Pos 0) Incomplete failK successK
418{-# INLINE parse #-}
457{-# INLINE parse #-}
420-- | Run a parser that cannot be resupplied via a 'Partial' result.
459-- | Run a parser that cannot be resupplied via a 'Partial' result.
461+-- This function does not force a parser to consume all of its input.
462+-- Instead, any residual input will be discarded. To force a parser
463+-- to consume all of its input, use something like this:
466+--'parseOnly' (myParser 'Control.Applicative.<*' 'endOfInput')
421−parseOnly :: Parser a -> B.ByteString -> Either String a
468+parseOnly :: Parser a -> ByteString -> Either String a
422−parseOnly m s = case T.runParser m s (Pos 0) Complete failK successK of
469+parseOnly m s = case T.runParser m (buffer s) (Pos 0) Complete failK successK of
470+ Fail _ [] err -> Left err
423− Fail _ _ err -> Left err
471+ Fail _ ctxs err -> Left (intercalate " > " ctxs ++ ": " ++ err)
424− Done _ a -> Right a
472+ Done _ a -> Right a
425− _ -> error "parseOnly: impossible error!"
473+ _ -> error "parseOnly: impossible error!"
426{-# INLINE parseOnly #-}
474{-# INLINE parseOnly #-}
428−-- | Just like unsafePerformIO, but we inline it. Big performance gains as
429−-- it exposes lots of things to further inlining. /Very unsafe/. In
430−-- particular, you should do no memory allocation inside an
431−-- 'inlinePerformIO' block. On Hugs this is just @unsafePerformIO@.
432−inlinePerformIO :: IO a -> a
433−inlinePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
434−{-# INLINE inlinePerformIO #-}
436get :: Parser ByteString
476get :: Parser ByteString
437get = T.Parser $ \t pos more _lose succ ->
477get = T.Parser $ \t pos more _lose succ ->
438− succ t pos more (B.unsafeDrop (fromPos pos) t)
478+ succ t pos more (Buf.unsafeDrop (fromPos pos) t)
439{-# INLINE get #-}
479{-# INLINE get #-}
441endOfChunk :: Parser Bool
481endOfChunk :: Parser Bool
442endOfChunk = T.Parser $ \t pos more _lose succ ->
482endOfChunk = T.Parser $ \t pos more _lose succ ->
443− succ t pos more (fromPos pos == B.length t)
483+ succ t pos more (fromPos pos == Buf.length t)
444{-# INLINE endOfChunk #-}
484{-# INLINE endOfChunk #-}
486+inputSpansChunks :: Int -> Parser Bool
487+inputSpansChunks i = T.Parser $ \t pos_ more _lose succ ->
488+ let pos = pos_ + Pos i
489+ in if fromPos pos < Buf.length t || more == Complete
490+ then succ t pos more False
491+ else let lose' t' pos' more' = succ t' pos' more' False
492+ succ' t' pos' more' = succ t' pos' more' True
493+ in prompt t pos more lose' succ'
494+{-# INLINE inputSpansChunks #-}
446advance :: Int -> Parser ()
496advance :: Int -> Parser ()
447advance n = T.Parser $ \t pos more _lose succ ->
497advance n = T.Parser $ \t pos more _lose succ ->
448 succ t (pos + Pos n) more ()
498 succ t (pos + Pos n) more ()
449{-# INLINE advance #-}
499{-# INLINE advance #-}
451−ensureSuspended :: Int -> ByteString -> Pos -> More
501+ensureSuspended :: Int -> Buffer -> Pos -> More
452 -> Failure r
502 -> Failure r
453 -> Success ByteString r
503 -> Success ByteString r
454 -> Result r
504 -> Result r
@@ -467,52 +517,8 @@ ensure n = T.Parser $ \t pos more lose succ ->
467 then succ t pos more (substring pos (Pos n) t)
517 then succ t pos more (substring pos (Pos n) t)
468 -- The uncommon case is kept out-of-line to reduce code size:
518 -- The uncommon case is kept out-of-line to reduce code size:
469 else ensureSuspended n t pos more lose succ
519 else ensureSuspended n t pos more lose succ
470−-- Non-recursive so the bounds check can be inlined:
471{-# INLINE ensure #-}
520{-# INLINE ensure #-}
473−-- | Ask for input. If we receive any, pass it to a success
474−-- continuation, otherwise to a failure continuation.
475−prompt :: ByteString -> Pos -> More
476− -> (ByteString -> Pos -> More -> IResult ByteString r)
477− -> (ByteString -> Pos -> More -> IResult ByteString r)
478− -> IResult ByteString r
479−prompt t pos _more lose succ = Partial $ \s ->
481− then lose t pos Complete
482− else succ (t <> s) pos Incomplete
484−-- | Immediately demand more input via a 'Partial' continuation
486−demandInput :: Parser ()
487−demandInput = T.Parser $ \t pos more lose succ ->
489− Complete -> lose t pos more [] "not enough input"
490− _ -> let lose' t' pos' more' = lose t' pos' more' [] "not enough input"
491− succ' t' pos' more' = succ t' pos' more' ()
492− in prompt t pos more lose' succ'
494−-- | This parser always succeeds. It returns 'True' if any input is
495−-- available either immediately or on demand, and 'False' if the end
496−-- of all input has been reached.
497−wantInput :: Parser Bool
498−wantInput = T.Parser $ \t pos more _lose succ ->
500− _ | lengthAtLeast pos 1 t -> succ t pos more True
501− | more == Complete -> succ t pos more False
502− | otherwise -> let lose' t' pos' more' = succ t' pos' more' False
503− succ' t' pos' more' = succ t' pos' more' True
504− in prompt t pos more lose' succ'
505−-- | Match only if all input has been consumed.
506−endOfInput :: Parser ()
507−endOfInput = T.Parser $ \t pos more lose succ ->
509− _| lengthAtLeast pos 1 t -> lose t pos more [] "endOfInput"
510− | more == Complete -> succ t pos more ()
512− let lose' t' pos' more' _ctx _msg = succ t' pos' more' ()
513− succ' t' pos' more' _a = lose t' pos' more' [] "endOfInput"
514− in runParser demandInput t pos more lose' succ'
516-- | Return both the result of a parse and the portion of the input
522-- | Return both the result of a parse and the portion of the input
517-- that was consumed while it was being parsed.
523-- that was consumed while it was being parsed.
518match :: Parser a -> Parser (ByteString, a)
524match :: Parser a -> Parser (ByteString, a)
@@ -521,16 +527,10 @@ match p = T.Parser $ \t pos more lose succ ->
521 succ t' pos' more' (substring pos (pos'-pos) t', a)
527 succ t' pos' more' (substring pos (pos'-pos) t', a)
522 in runParser p t pos more lose succ'
528 in runParser p t pos more lose succ'
524−-- | Return an indication of whether the end of input has been
527−atEnd = not <$> wantInput
530−lengthAtLeast :: Pos -> Int -> ByteString -> Bool
530+lengthAtLeast :: Pos -> Int -> Buffer -> Bool
531−lengthAtLeast (Pos pos) n bs = B.length bs >= pos + n
531+lengthAtLeast (Pos pos) n bs = Buf.length bs >= pos + n
532{-# INLINE lengthAtLeast #-}
532{-# INLINE lengthAtLeast #-}
534−substring :: Pos -> Pos -> ByteString -> ByteString
534+substring :: Pos -> Pos -> Buffer -> ByteString
535−substring (Pos pos) (Pos n) bs = B.unsafeTake n (B.unsafeDrop pos bs)
535+substring (Pos pos) (Pos n) = Buf.substring pos n
536{-# INLINE substring #-}
536{-# INLINE substring #-}