@@ -1,15 +1,14 @@
1−{-# LANGUAGE BangPatterns, CPP, GADTs, OverloadedStrings, RankNTypes,
1+{-# LANGUAGE BangPatterns, OverloadedStrings, RecordWildCards #-}
4-- Module : Data.Attoparsec.ByteString.Internal
3-- Module : Data.Attoparsec.ByteString.Internal
5−-- Copyright : Bryan O'Sullivan 2007-2015
4+-- Copyright : Bryan O'Sullivan 2007-2014
6-- License : BSD3
5-- License : BSD3
8-- Maintainer : bos@serpentine.com
7-- Maintainer : bos@serpentine.com
9-- Stability : experimental
8-- Stability : experimental
10-- Portability : unknown
9-- Portability : unknown
12−-- Simple, efficient parser combinators for 'ByteString' strings,
11+-- Simple, efficient parser combinators for 'B.ByteString' strings,
13-- loosely based on the Parsec library.
12-- loosely based on the Parsec library.
15module Data.Attoparsec.ByteString.Internal
14module Data.Attoparsec.ByteString.Internal
@@ -47,7 +46,7 @@ module Data.Attoparsec.ByteString.Internal
47 -- * Efficient string handling
46 -- * Efficient string handling
48 , skipWhile
47 , skipWhile
50− , stringCI
49+ , stringTransform
53 , runScanner
52 , runScanner
@@ -66,25 +65,18 @@ module Data.Attoparsec.ByteString.Internal
69−#if !MIN_VERSION_base(4,8,0)
70−import Control.Applicative ((<$>))
68+import Control.Applicative ((<|>), (<$>))
72−import Control.Applicative ((<|>))
73import Control.Monad (when)
69import Control.Monad (when)
74−import Data.Attoparsec.ByteString.Buffer (Buffer, buffer)
75import Data.Attoparsec.ByteString.FastSet (charClass, memberWord8)
70import Data.Attoparsec.ByteString.FastSet (charClass, memberWord8)
71+import Data.Attoparsec.ByteString.Fhthagn (inlinePerformIO)
76import Data.Attoparsec.Combinator ((<?>))
72import Data.Attoparsec.Combinator ((<?>))
77−import Data.Attoparsec.Internal
78−import Data.Attoparsec.Internal.Fhthagn (inlinePerformIO)
79import Data.Attoparsec.Internal.Types hiding (Parser, Failure, Success)
73import Data.Attoparsec.Internal.Types hiding (Parser, Failure, Success)
80−import Data.ByteString (ByteString)
81−import Data.List (intercalate)
82import Data.Word (Word8)
74import Data.Word (Word8)
83import Foreign.ForeignPtr (withForeignPtr)
75import Foreign.ForeignPtr (withForeignPtr)
84import Foreign.Ptr (castPtr, minusPtr, plusPtr)
76import Foreign.Ptr (castPtr, minusPtr, plusPtr)
85import Foreign.Storable (Storable(peek, sizeOf))
77import Foreign.Storable (Storable(peek, sizeOf))
86import Prelude hiding (getChar, succ, take, takeWhile)
78import Prelude hiding (getChar, succ, take, takeWhile)
87−import qualified Data.Attoparsec.ByteString.Buffer as Buf
79+import Data.ByteString (ByteString)
88import qualified Data.Attoparsec.Internal.Types as T
80import qualified Data.Attoparsec.Internal.Types as T
89import qualified Data.ByteString as B8
81import qualified Data.ByteString as B8
90import qualified Data.ByteString.Char8 as B
82import qualified Data.ByteString.Char8 as B
@@ -92,10 +84,10 @@ import qualified Data.ByteString.Internal as B
92import qualified Data.ByteString.Lazy as L
84import qualified Data.ByteString.Lazy as L
93import qualified Data.ByteString.Unsafe as B
85import qualified Data.ByteString.Unsafe as B
95−type Parser = T.Parser ByteString
87+type Parser = T.Parser B.ByteString B.ByteString
96−type Result = IResult ByteString
88+type Result = IResult B.ByteString B.ByteString
97−type Failure r = T.Failure ByteString Buffer r
89+type Failure r = T.Failure B.ByteString B.ByteString r
98−type Success a r = T.Success ByteString Buffer a r
90+type Success a r = T.Success B.ByteString B.ByteString a r
100-- | The parser @satisfy p@ succeeds for any byte for which the
92-- | The parser @satisfy p@ succeeds for any byte for which the
101-- predicate @p@ returns 'True'. Returns the byte that is actually
93-- predicate @p@ returns 'True'. Returns the byte that is actually
@@ -141,15 +133,22 @@ storable = hack undefined
141 hack :: Storable b => b -> Parser b
133 hack :: Storable b => b -> Parser b
142 hack dummy = do
134 hack dummy = do
143 (fp,o,_) <- B.toForeignPtr `fmap` take (sizeOf dummy)
135 (fp,o,_) <- B.toForeignPtr `fmap` take (sizeOf dummy)
144− return . inlinePerformIO . withForeignPtr fp $ \p ->
136+ return . B.inlinePerformIO . withForeignPtr fp $ \p ->
145 peek (castPtr $ p `plusPtr` o)
137 peek (castPtr $ p `plusPtr` o)
147−-- | Consume exactly @n@ bytes of input.
139+-- | Consume @n@ bytes of input, but succeed only if the predicate
148−take :: Int -> Parser ByteString
141+takeWith :: Int -> (B.ByteString -> Bool) -> Parser B.ByteString
149−take n0 = do
142+takeWith n0 p = do
150 let n = max n0 0
143 let n = max n0 0
151 s <- ensure n
144 s <- ensure n
152− advance n >> return s
146+ then advance n >> return s
147+ else fail "takeWith"
149+-- | Consume exactly @n@ bytes of input.
150+take :: Int -> Parser B.ByteString
151+take n = takeWith n (const True)
153{-# INLINE take #-}
152{-# INLINE take #-}
155-- | @string s@ parses a sequence of bytes that identically match
154-- | @string s@ parses a sequence of bytes that identically match
@@ -165,62 +164,16 @@ take n0 = do
166-- The reason for its failure is that the first branch is a
165-- The reason for its failure is that the first branch is a
167-- partial match, and will consume the letters @\'f\'@ and @\'o\'@
166-- partial match, and will consume the letters @\'f\'@ and @\'o\'@
168−-- before failing. In attoparsec, the above parser will /succeed/ on
167+-- before failing. In Attoparsec, the above parser will /succeed/ on
169-- that input, because the failed first branch will consume nothing.
168-- that input, because the failed first branch will consume nothing.
170−string :: ByteString -> Parser ByteString
169+string :: B.ByteString -> Parser B.ByteString
171−string s = string_ (stringSuspended id) id s
170+string s = takeWith (B.length s) (==s)
172{-# INLINE string #-}
171{-# INLINE string #-}
174−-- ASCII-specific but fast, oh yes.
173+stringTransform :: (B.ByteString -> B.ByteString) -> B.ByteString
175−toLower :: Word8 -> Word8
174+ -> Parser B.ByteString
176−toLower w | w >= 65 && w <= 90 = w + 32
175+stringTransform f s = takeWith (B.length s) ((==f s) . f)
177− | otherwise = w
176+{-# INLINE stringTransform #-}
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"
225-- | Skip past input for as long as the predicate returns 'True'.
178-- | Skip past input for as long as the predicate returns 'True'.
226skipWhile :: (Word8 -> Bool) -> Parser ()
179skipWhile :: (Word8 -> Bool) -> Parser ()
@@ -228,8 +181,11 @@ skipWhile p = go
230 t <- B8.takeWhile p <$> get
183 t <- B8.takeWhile p <$> get
231− continue <- inputSpansChunks (B.length t)
184+ advance (B.length t)
232− when continue go
185+ eoc <- endOfChunk
233{-# INLINE skipWhile #-}
189{-# INLINE skipWhile #-}
235-- | Consume input as long as the predicate returns 'False'
191-- | Consume input as long as the predicate returns 'False'
@@ -242,7 +198,7 @@ skipWhile p = go
242-- combinators such as 'Control.Applicative.many', because such
198-- combinators such as 'Control.Applicative.many', because such
243-- parsers loop until a failure occurs. Careless use will thus result
199-- parsers loop until a failure occurs. Careless use will thus result
244-- in an infinite loop.
200-- in an infinite loop.
245−takeTill :: (Word8 -> Bool) -> Parser ByteString
201+takeTill :: (Word8 -> Bool) -> Parser B.ByteString
246takeTill p = takeWhile (not . p)
202takeTill p = takeWhile (not . p)
247{-# INLINE takeTill #-}
203{-# INLINE takeTill #-}
@@ -256,27 +212,23 @@ takeTill p = takeWhile (not . p)
256-- combinators such as 'Control.Applicative.many', because such
212-- combinators such as 'Control.Applicative.many', because such
257-- parsers loop until a failure occurs. Careless use will thus result
213-- parsers loop until a failure occurs. Careless use will thus result
258-- in an infinite loop.
214-- in an infinite loop.
259−takeWhile :: (Word8 -> Bool) -> Parser ByteString
215+takeWhile :: (Word8 -> Bool) -> Parser B.ByteString
260−takeWhile p = do
216+takeWhile p = (B.concat . reverse) `fmap` go []
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
271 go acc = do
218 go acc = do
272 s <- B8.takeWhile p <$> get
219 s <- B8.takeWhile p <$> get
273− continue <- inputSpansChunks (B.length s)
220+ advance (B.length s)
274− if continue
221+ eoc <- endOfChunk
275− then go (s:acc)
226+ then go (s:acc)
276− else return $ concatReverse (s:acc)
227+ else return (s:acc)
277−{-# INLINE takeWhileAcc #-}
228+ else return (s:acc)
229+{-# INLINE takeWhile #-}
279−takeRest :: Parser [ByteString]
231+takeRest :: Parser [B.ByteString]
280takeRest = go []
232takeRest = go []
282 go acc = do
234 go acc = do
@@ -289,7 +241,7 @@ takeRest = go []
289 else return (reverse acc)
241 else return (reverse acc)
291-- | Consume all remaining input and return it as a single string.
243-- | Consume all remaining input and return it as a single string.
292−takeByteString :: Parser ByteString
244+takeByteString :: Parser B.ByteString
293takeByteString = B.concat `fmap` takeRest
245takeByteString = B.concat `fmap` takeRest
295-- | Consume all remaining input and return it as a single string.
247-- | Consume all remaining input and return it as a single string.
@@ -298,7 +250,7 @@ takeLazyByteString = L.fromChunks `fmap` takeRest
299data T s = T {-# UNPACK #-} !Int s
251data T s = T {-# UNPACK #-} !Int s
301−scan_ :: (s -> [ByteString] -> Parser r) -> s -> (s -> Word8 -> Maybe s)
253+scan_ :: (s -> [B.ByteString] -> Parser r) -> s -> (s -> Word8 -> Maybe s)
302 -> Parser r
254 -> Parser r
303scan_ f s0 p = go [] s0
255scan_ f s0 p = go [] s0
@@ -319,9 +271,14 @@ scan_ f s0 p = go [] s0
319 bs <- get
271 bs <- get
320 let T i s' = inlinePerformIO $ scanner bs
272 let T i s' = inlinePerformIO $ scanner bs
321 !h = B.unsafeTake i bs
273 !h = B.unsafeTake i bs
322− continue <- inputSpansChunks i
274+ advance i
323− if continue
275+ eoc <- endOfChunk
324− then go (h:acc) s'
280+ then go (h:acc) s'
325 else f s' (h:acc)
282 else f s' (h:acc)
326{-# INLINE scan_ #-}
283{-# INLINE scan_ #-}
@@ -337,14 +294,17 @@ scan_ f s0 p = go [] s0
337-- combinators such as 'Control.Applicative.many', because such
294-- combinators such as 'Control.Applicative.many', because such
338-- parsers loop until a failure occurs. Careless use will thus result
295-- parsers loop until a failure occurs. Careless use will thus result
339-- in an infinite loop.
296-- in an infinite loop.
340−scan :: s -> (s -> Word8 -> Maybe s) -> Parser ByteString
297+scan :: s -> (s -> Word8 -> Maybe s) -> Parser B.ByteString
341−scan = scan_ $ \_ chunks -> return $! concatReverse chunks
298+scan = scan_ $ \_ chunks ->
301+ xs -> return $! B.concat $ reverse xs
342{-# INLINE scan #-}
302{-# INLINE scan #-}
344-- | Like 'scan', but generalized to return the final state of the
304-- | Like 'scan', but generalized to return the final state of the
345-- scanner.
305-- scanner.
346−runScanner :: s -> (s -> Word8 -> Maybe s) -> Parser (ByteString, s)
306+runScanner :: s -> (s -> Word8 -> Maybe s) -> Parser (B.ByteString, s)
347−runScanner = scan_ $ \s xs -> let !sx = concatReverse xs in return (sx, s)
307+runScanner = scan_ $ \s xs -> return (B.concat (reverse xs), s)
348{-# INLINE runScanner #-}
308{-# INLINE runScanner #-}
350-- | Consume input as long as the predicate returns 'True', and return
310-- | Consume input as long as the predicate returns 'True', and return
@@ -353,7 +313,7 @@ runScanner = scan_ $ \s xs -> let !sx = concatReverse xs in return (sx, s)
353-- This parser requires the predicate to succeed on at least one byte
313-- This parser requires the predicate to succeed on at least one byte
354-- of input: it will fail if the predicate never returns 'True' or if
314-- of input: it will fail if the predicate never returns 'True' or if
355-- there is no input left.
315-- there is no input left.
356−takeWhile1 :: (Word8 -> Bool) -> Parser ByteString
316+takeWhile1 :: (Word8 -> Bool) -> Parser B.ByteString
357takeWhile1 p = do
317takeWhile1 p = do
358 (`when` demandInput) =<< endOfChunk
318 (`when` demandInput) =<< endOfChunk
359 s <- B8.takeWhile p <$> get
319 s <- B8.takeWhile p <$> get
@@ -364,9 +324,8 @@ takeWhile1 p = do
364 advance len
324 advance len
365 eoc <- endOfChunk
325 eoc <- endOfChunk
367− then takeWhileAcc p [s]
327+ then (s<>) `fmap` takeWhile p
368 else return s
328 else return s
369−{-# INLINE takeWhile1 #-}
371-- | Match any byte in a set.
330-- | Match any byte in a set.
@@ -414,13 +373,13 @@ notWord8 c = satisfy (/= c) <?> "not " ++ show c
414peekWord8 :: Parser (Maybe Word8)
373peekWord8 :: Parser (Maybe Word8)
415peekWord8 = T.Parser $ \t pos@(Pos pos_) more _lose succ ->
374peekWord8 = T.Parser $ \t pos@(Pos pos_) more _lose succ ->
416 case () of
375 case () of
417− _| pos_ < Buf.length t ->
376+ _| pos_ < B.length t ->
418− let !w = Buf.unsafeIndex t pos_
377+ let !w = B.unsafeIndex t pos_
419 in succ t pos more (Just w)
378 in succ t pos more (Just w)
420 | more == Complete ->
379 | more == Complete ->
421 succ t pos more Nothing
380 succ t pos more Nothing
422 | otherwise ->
381 | otherwise ->
423− let succ' t' pos' more' = let !w = Buf.unsafeIndex t' pos_
382+ let succ' t' pos' more' = let !w = B.unsafeIndex t pos_
424 in succ t' pos' more' (Just w)
383 in succ t' pos' more' (Just w)
425 lose' t' pos' more' = succ t' pos' more' Nothing
384 lose' t' pos' more' = succ t' pos' more' Nothing
426 in prompt t pos more lose' succ'
385 in prompt t pos more lose' succ'
@@ -431,7 +390,7 @@ peekWord8 = T.Parser $ \t pos@(Pos pos_) more _lose succ ->
431peekWord8' :: Parser Word8
390peekWord8' :: Parser Word8
432peekWord8' = T.Parser $ \t pos more lose succ ->
391peekWord8' = T.Parser $ \t pos more lose succ ->
433 if lengthAtLeast pos 1 t
392 if lengthAtLeast pos 1 t
434− then succ t pos more (Buf.unsafeIndex t (fromPos pos))
393+ then succ t pos more (B.unsafeIndex t (fromPos pos))
435 else let succ' t' pos' more' bs' = succ t' pos' more' $! B.unsafeHead bs'
394 else let succ' t' pos' more' bs' = succ t' pos' more' $! B.unsafeHead bs'
436 in ensureSuspended 1 t pos more lose succ'
395 in ensureSuspended 1 t pos more lose succ'
437{-# INLINE peekWord8' #-}
396{-# INLINE peekWord8' #-}
@@ -443,62 +402,43 @@ endOfLine = (word8 10 >> return ()) <|> (string "\r\n" >> return ())
444-- | Terminal failure continuation.
403-- | Terminal failure continuation.
445failK :: Failure a
404failK :: Failure a
446−failK t (Pos pos) _more stack msg = Fail (Buf.unsafeDrop pos t) stack msg
405+failK t (Pos pos) _more stack msg = Fail (B.unsafeDrop pos t) stack msg
447{-# INLINE failK #-}
406{-# INLINE failK #-}
449-- | Terminal success continuation.
408-- | Terminal success continuation.
450successK :: Success a a
409successK :: Success a a
451−successK t (Pos pos) _more a = Done (Buf.unsafeDrop pos t) a
410+successK t (Pos pos) _more a = Done (B.unsafeDrop pos t) a
452{-# INLINE successK #-}
411{-# INLINE successK #-}
454-- | Run a parser.
413-- | Run a parser.
455−parse :: Parser a -> ByteString -> Result a
414+parse :: Parser a -> B.ByteString -> Result a
456−parse m s = T.runParser m (buffer s) (Pos 0) Incomplete failK successK
415+parse m s = T.runParser m s (Pos 0) Incomplete failK successK
457{-# INLINE parse #-}
416{-# INLINE parse #-}
459-- | Run a parser that cannot be resupplied via a 'Partial' result.
418-- | 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')
468−parseOnly :: Parser a -> ByteString -> Either String a
419+parseOnly :: Parser a -> B.ByteString -> Either String a
469−parseOnly m s = case T.runParser m (buffer s) (Pos 0) Complete failK successK of
420+parseOnly m s = case T.runParser m s (Pos 0) Complete failK successK of
470− Fail _ [] err -> Left err
471− Fail _ ctxs err -> Left (intercalate " > " ctxs ++ ": " ++ err)
421+ Fail _ _ err -> Left err
472− Done _ a -> Right a
422+ Done _ a -> Right a
473− _ -> error "parseOnly: impossible error!"
423+ _ -> error "parseOnly: impossible error!"
474{-# INLINE parseOnly #-}
424{-# INLINE parseOnly #-}
476get :: Parser ByteString
426get :: Parser ByteString
477get = T.Parser $ \t pos more _lose succ ->
427get = T.Parser $ \t pos more _lose succ ->
478− succ t pos more (Buf.unsafeDrop (fromPos pos) t)
428+ succ t pos more (B.unsafeDrop (fromPos pos) t)
479{-# INLINE get #-}
429{-# INLINE get #-}
481endOfChunk :: Parser Bool
431endOfChunk :: Parser Bool
482endOfChunk = T.Parser $ \t pos more _lose succ ->
432endOfChunk = T.Parser $ \t pos more _lose succ ->
483− succ t pos more (fromPos pos == Buf.length t)
433+ succ t pos more (fromPos pos == B.length t)
484{-# INLINE endOfChunk #-}
434{-# 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 #-}
496advance :: Int -> Parser ()
436advance :: Int -> Parser ()
497advance n = T.Parser $ \t pos more _lose succ ->
437advance n = T.Parser $ \t pos more _lose succ ->
498 succ t (pos + Pos n) more ()
438 succ t (pos + Pos n) more ()
499{-# INLINE advance #-}
439{-# INLINE advance #-}
501−ensureSuspended :: Int -> Buffer -> Pos -> More
441+ensureSuspended :: Int -> ByteString -> Pos -> More
502 -> Failure r
442 -> Failure r
503 -> Success ByteString r
443 -> Success ByteString r
504 -> Result r
444 -> Result r
@@ -517,8 +457,54 @@ ensure n = T.Parser $ \t pos more lose succ ->
517 then succ t pos more (substring pos (Pos n) t)
457 then succ t pos more (substring pos (Pos n) t)
518 -- The uncommon case is kept out-of-line to reduce code size:
458 -- The uncommon case is kept out-of-line to reduce code size:
519 else ensureSuspended n t pos more lose succ
459 else ensureSuspended n t pos more lose succ
460+-- Non-recursive so the bounds check can be inlined:
520{-# INLINE ensure #-}
461{-# INLINE ensure #-}
463+-- | Ask for input. If we receive any, pass it to a success
464+-- continuation, otherwise to a failure continuation.
465+prompt :: ByteString -> Pos -> More
466+ -> (ByteString -> Pos -> More -> IResult ByteString ByteString r)
467+ -> (ByteString -> Pos -> More -> IResult ByteString ByteString r)
468+ -> IResult ByteString ByteString r
469+prompt t pos _more lose succ = Partial $ \s ->
471+ then lose t pos Complete
472+ else succ (t <> s) pos Incomplete
474+-- | Immediately demand more input via a 'Partial' continuation
476+demandInput :: Parser ()
477+demandInput = T.Parser $ \t pos more lose succ ->
479+ Complete -> lose t pos more [] "not enough input"
480+ _ -> let lose' t' pos' more' = lose t' pos' more' [] "not enough input"
481+ succ' t' pos' more' = succ t' pos' more' ()
482+ in prompt t pos more lose' succ'
484+-- | This parser always succeeds. It returns 'True' if any input is
485+-- available either immediately or on demand, and 'False' if the end
486+-- of all input has been reached.
487+wantInput :: Parser Bool
488+wantInput = T.Parser $ \t pos more _lose succ ->
490+ _ | lengthAtLeast pos 1 t -> succ t pos more True
491+ | more == Complete -> succ t pos more False
492+ | otherwise -> let lose' t' pos' more' = succ t' pos' more' False
493+ succ' t' pos' more' = succ t' pos' more' True
494+ in prompt t pos more lose' succ'
495+{-# INLINE wantInput #-}
497+-- | Match only if all input has been consumed.
498+endOfInput :: Parser ()
499+endOfInput = T.Parser $ \t pos more lose succ ->
501+ _| lengthAtLeast pos 1 t -> lose t pos more [] "endOfInput"
502+ | more == Complete -> succ t pos more ()
504+ let lose' t' pos' more' _ctx _msg = succ t' pos' more' ()
505+ succ' t' pos' more' _a = lose t' pos' more' [] "endOfInput"
506+ in runParser demandInput t pos more lose' succ'
522-- | Return both the result of a parse and the portion of the input
508-- | Return both the result of a parse and the portion of the input
523-- that was consumed while it was being parsed.
509-- that was consumed while it was being parsed.
524match :: Parser a -> Parser (ByteString, a)
510match :: Parser a -> Parser (ByteString, a)
@@ -527,10 +513,16 @@ match p = T.Parser $ \t pos more lose succ ->
527 succ t' pos' more' (substring pos (pos'-pos) t', a)
513 succ t' pos' more' (substring pos (pos'-pos) t', a)
528 in runParser p t pos more lose succ'
514 in runParser p t pos more lose succ'
516+-- | Return an indication of whether the end of input has been
519+atEnd = not <$> wantInput
530−lengthAtLeast :: Pos -> Int -> Buffer -> Bool
522+lengthAtLeast :: Pos -> Int -> ByteString -> Bool
531−lengthAtLeast (Pos pos) n bs = Buf.length bs >= pos + n
523+lengthAtLeast (Pos pos) n bs = B.length bs >= pos + n
532{-# INLINE lengthAtLeast #-}
524{-# INLINE lengthAtLeast #-}
534−substring :: Pos -> Pos -> Buffer -> ByteString
526+substring :: Pos -> Pos -> ByteString -> ByteString
535−substring (Pos pos) (Pos n) = Buf.substring pos n
527+substring (Pos pos) (Pos n) bs = B.unsafeTake n (B.unsafeDrop pos bs)
536{-# INLINE substring #-}
528{-# INLINE substring #-}