git.iko.soy/typeable/attoparsec
on master help sign in
Generalize scan on Text to runScanner

The name is by analogy to State. This fixes gh-8.

commit98339a8c481769ce36469587bce1dcc047856778 authorBryan O'Sullivan <bos@serpentine.com> dateFri 14 Feb 2014, 17:25 (13 years ago) parent4624b0b
1 file changed+28−18
Data/Attoparsec/Text/Internal.hs+28−18
Data/Attoparsec/Text/Internal.hs+28−18
@@ -49,6 +49,7 @@ module Data.Attoparsec.Text.Internal
4949 , asciiCI
5050 , take
5151 , scan
52+ , runScanner
5253 , takeWhile
5354 , takeWhile1
5455 , takeTill
@@ -277,6 +278,26 @@ takeLazyText = L.fromChunks `fmap` takeRest
277278data Scan s = Continue s
278279 | Finished {-# UNPACK #-} !Int T.Text
279280
281+scan_ :: (s -> [Text] -> Parser r) -> s -> (s -> Char -> Maybe s) -> Parser r
282+scan_ f s0 p = go [] s0
283+ where
284+ scanner s !n t =
285+ case T.uncons t of
286+ Just (c,t') -> case p s c of
287+ Just s' -> scanner s' (n+1) t'
288+ Nothing -> Finished n t
289+ Nothing -> Continue s
290+ go acc s = do
291+ input <- get
292+ case scanner s 0 input of
293+ Continue s' -> do put T.empty
294+ more <- wantInput
295+ if more
296+ then go (input : acc) s'
297+ else f s' (input : acc)
298+ Finished n t -> put t >> f s (T.take n input : acc)
299+{-# INLINE scan_ #-}
300+
280301-- | A stateful scanner. The predicate consumes and transforms a
281302-- state argument, and each transformed state is passed to successive
282303-- invocations of the predicate on each character of the input until one
@@ -289,29 +310,18 @@ data Scan s = Continue s
289310-- combinators such as 'many', because such parsers loop until a
290311-- failure occurs. Careless use will thus result in an infinite loop.
291312scan :: s -> (s -> Char -> Maybe s) -> Parser Text
292−scan s0 p = do
293− chunks <- go [] s0
313+scan = scan_ $ \_ chunks ->
294314 case chunks of
295315 [x] -> return x
296316 xs -> return . T.concat . reverse $ xs
297− where
298− scanner s !n t =
299− case T.uncons t of
300− Just (c,t') -> case p s c of
301− Just s' -> scanner s' (n+1) t'
302− Nothing -> Finished n t
303− Nothing -> Continue s
304− go acc s = do
305− input <- get
306− case scanner s 0 input of
307− Continue s' -> do put T.empty
308− more <- wantInput
309− if more
310− then go (input : acc) s'
311− else return (input : acc)
312− Finished n t -> put t >> return (T.take n input : acc)
313317{-# INLINE scan #-}
314318
319+-- | Like 'scan', but generalized to return the final state of the
320+-- scanner.
321+runScanner :: s -> (s -> Char -> Maybe s) -> Parser (Text, s)
322+runScanner = scan_ $ \s xs -> return (T.concat (reverse xs), s)
323+{-# INLINE runScanner #-}
324+
315325-- | Consume input as long as the predicate returns 'True', and return
316326-- the consumed input.
317327--