Commits

Bryan O'Sullivan committed 4f58d24

Generalize scan on ByteString to runScanner

The name is by analogy to State.

The issue is gh-8.

  • Participants
  • Parent commits d034933

Comments (0)

Files changed (1)

File Data/Attoparsec/ByteString/Internal.hs

     , stringTransform
     , take
     , scan
+    , runScanner
     , takeWhile
     , takeWhile1
     , takeTill
 
 data T s = T {-# UNPACK #-} !Int s
 
--- | 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
--- returns 'Nothing' or the input ends.
---
--- This parser does not fail.  It will return an empty string if the
--- predicate returns 'Nothing' on the first byte of 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.
-scan :: s -> (s -> Word8 -> Maybe s) -> Parser B.ByteString
-scan s0 p = do
-  chunks <- go [] s0
-  case chunks of
-    [x] -> return x
-    xs  -> return $! B.concat $ reverse xs
+scan_ :: (s -> [B.ByteString] -> Parser r) -> s -> (s -> Word8 -> Maybe s)
+         -> Parser r
+scan_ f s0 p = go [] s0
  where
   go acc s1 = do
     let scanner (B.PS fp off len) =
         input <- wantInput
         if input
           then go (h:acc) s'
-          else return (h:acc)
-      else return (h:acc)
+          else f s' (h:acc)
+      else f s' (h:acc)
+{-# INLINE scan_ #-}
+
+-- | 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
+-- returns 'Nothing' or the input ends.
+--
+-- This parser does not fail.  It will return an empty string if the
+-- predicate returns 'Nothing' on the first byte of 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.
+scan :: s -> (s -> Word8 -> Maybe s) -> Parser B.ByteString
+scan = scan_ $ \_ chunks ->
+  case chunks of
+    [x] -> return x
+    xs  -> return $! B.concat $ reverse xs
 {-# INLINE scan #-}
 
+-- | Like 'scan', but generalized to return the final state of the
+-- scanner.
+runScanner :: s -> (s -> Word8 -> Maybe s) -> Parser (B.ByteString, s)
+runScanner = scan_ $ \s xs -> return (B.concat (reverse xs), s)
+{-# INLINE runScanner #-}
+
 -- | Consume input as long as the predicate returns 'True', and return
 -- the consumed input.
 --