on master help sign in
Implement fromParserK

We need to pause and continue the continuations to be able to run the parser in steps which is required by the ParserD representation.

commitd80d5e0a3b6aa5dbd0cdefda38976572e43f7e60 authorHarendra Kumar <harendra@composewell.com> dateSun 12 Jul 2020, 20:32 (6 years ago) parent4d5ab4e
4 files changed+376−229
src/Streamly/Internal/Data/Parser/ParserD.hs+39−9 src/Streamly/Internal/Data/Parser/ParserK/Types.hs+289−33 src/Streamly/Internal/Data/Zipper.hs+41−183 src/Streamly/Internal/Prelude.hs+7−4
src/Streamly/Internal/Data/Parser/ParserD.hs+39−9
@@ -199,22 +199,52 @@ fromFold (Fold fstep finitial fextract) = Parser step finitial fextract
199199{-# INLINE_LATE toParserK #-}
200200toParserK :: MonadCatch m => Parser m a b -> K.Parser m a b
201201toParserK (Parser step initial extract) =
202− K.MkParser $ \inp yieldk ->
203− Z.parse step initial extract inp >>= yieldk
204−
202+ K.MkParser $ K.parse step initial extract
203+
204+-- XXX The CPS style parsers use a zipper buffering the data, if a parserD is
205+-- driving the parserK then it would also be buffering the same data. For
206+-- ParserD, instead of maintaining the buffer in the common driver, each parser
207+-- can have its own buffering and we can return the unconsumed buffer in the
208+-- end. That way the zipper is maintained by the parser. If the parser fails
209+-- then it has to return all of the input. It is anyway maintained by
210+-- intermediate level parsers in a composition, so the only difference would be
211+-- that even the leaf levels parsers would do it. If we abstract the zipper
212+-- maintainance then it may not be too unwieldy.
213+--
205214-- | Convert a CPS style 'K.Parser' to a direct style 'Parser'.
206215--
207216-- /Unimplemented/
208217--
209−{-# NOINLINE fromParserK #-}
210−fromParserK :: Monad m => K.Parser m a b -> Parser m a b
211−fromParserK _ = Parser step initial extract
218+{-# INLINE_LATE fromParserK #-}
219+fromParserK :: MonadThrow m => K.Parser m a b -> Parser m a b
220+fromParserK parser = Parser step initial extract
212221
213222 where
214223
215− initial = return ()
216− step () _ = error "fromParserK: unimplemented"
217− extract () = error "fromParserK: unimplemented"
224+ initial = return Nothing
225+
226+ step Nothing a = do
227+ let yieldk _ (K.Done b) =
228+ -- let leftover = 0 -- XXX get it from the zipper
229+ return $ K.Stop b
230+ yieldk _ K.Continue = error "Bug: fromParserK: got Continue"
231+ yieldk _ (K.Error e) = return $ K.Failed e
232+ r <- K.runParser parser (Z.append a Z.nil) yieldk
233+ case r of
234+ K.Stop b -> return $ Done 0 b
235+ K.Failed e -> return $ Error e
236+ -- XXX we can use the zipper state here to pare down the driver
237+ -- buffer
238+ K.Pause cont -> return $ Partial 0 $ Just cont
239+ step (Just cont) a = do
240+ r <- cont (Just a)
241+ case r of
242+ K.Stop b -> return $ Done 0 b
243+ K.Failed e -> return $ Error e
244+ K.Pause cont1 -> return $ Partial 0 $ Just cont1
245+
246+ extract Nothing = throwM $ ParseError "end of input"
247+ extract (Just cont) = K.extractParse cont
218248
219249#ifndef DISABLE_FUSION
220250{-# RULES "fromParserK/toParserK fusion" [2]
src/Streamly/Internal/Data/Parser/ParserK/Types.hs+289−33
@@ -20,31 +20,98 @@
2020
2121module Streamly.Internal.Data.Parser.ParserK.Types
2222 (
23− Parser (..)
23+ Parse (..)
24+ , Driver (..)
25+ , Parser (..)
26+ , extractParse
2427 , yield
2528 , die
29+
30+ -- * Parsing
31+ , parse
2632 )
2733where
2834
29−import Control.Monad (MonadPlus(..), ap)
3035import Control.Applicative (Alternative(..))
31−import Streamly.Internal.Data.Zipper (Zipper)
32−import qualified Streamly.Internal.Data.Zipper as Z
33−
36+import Control.Exception (assert, Exception(..))
37+import Control.Monad (MonadPlus(..), ap)
38+import Control.Monad.Catch (MonadCatch, MonadThrow(..), try)
3439#if MIN_VERSION_base(4,9,0)
3540import qualified Control.Monad.Fail as Fail
3641#endif
42+#if !(MIN_VERSION_base(4,10,0))
43+import Data.Semigroup ((<>))
44+#endif
45+import Streamly.Internal.Data.Zipper (Zipper (..))
46+import Streamly.Internal.Data.SVar (defState)
47+import Prelude hiding (splitAt)
48+
49+import qualified Streamly.Internal.Data.Zipper as Z
50+import qualified Streamly.Internal.Data.Parser.ParserD.Types as PD
51+import qualified Streamly.Internal.Data.Stream.StreamK as K
3752
38−newtype Parser m a b =
39− MkParser { runParser :: forall r.
40− Zipper m a -> ((Zipper m a, Either String b) -> m r) -> m r }
53+-- | The parse driver result. The driver may stop with a final result, pause
54+-- with a continuation to resume, or fail with an error.
55+--
56+-- /Internal/
57+--
58+data Driver m a r =
59+ Stop r
60+ -- XXX we can use a "resume" and a "stop" continuations instead of Maybe.
61+ -- measure if that works any better.
62+ | Pause (Maybe a -> m (Driver m a r))
63+ | Failed String
64+
65+instance Functor m => Functor (Driver m a) where
66+ fmap f (Stop r) = Stop (f r)
67+ fmap f (Pause yld) = Pause (fmap (fmap f) . yld)
68+ fmap _ (Failed e) = Failed e
69+
70+-- The parser's result.
71+--
72+-- /Internal/
73+--
74+data Parse b =
75+ Done !b -- Done, no more input needed
76+ | Continue -- No result, need more input
77+ | Error !String -- Failed
78+
79+instance Functor Parse where
80+ fmap f (Done b) = Done (f b)
81+ fmap _ Continue = Continue
82+ fmap _ (Error e) = Error e
83+
84+-- | A continuation passing style parser representation. The parser is supplied
85+-- with a 'Zipper' with an initial input, and a continuation to consume the
86+-- parse result. The Zipper is threaded around as a state and maintains the
87+-- parser backtracking buffer.
88+--
89+newtype Parser m a b = MkParser
90+ { runParser :: forall r.
91+ Zipper m a
92+ -> (Zipper m a -> Parse b -> m (Driver m a r))
93+ -> m (Driver m a r)
94+ }
4195
42−-- | Maps a function over the output of the fold.
96+-- | When there is no more input to feed, extract the result from the Parser.
97+--
98+-- /Internal/
99+--
100+extractParse :: MonadThrow m => (Maybe a -> m (Driver m a b)) -> m b
101+extractParse cont = do
102+ r <- cont Nothing
103+ case r of
104+ Stop b -> return b
105+ Pause _ -> error "Bug: extractParse got Pause"
106+ Failed e -> throwM $ PD.ParseError e
107+
108+-- | Maps a function over the output of the parser.
43109--
44110instance Functor m => Functor (Parser m a) where
45111 {-# INLINE fmap #-}
46− fmap f parser =
47− MkParser $ \inp yieldk -> runParser parser inp (yieldk . fmap (fmap f))
112+ fmap f parser = MkParser $ \zipper yieldk ->
113+ let yld z res = yieldk z (fmap f res)
114+ in runParser parser zipper yld
48115
49116-- | See 'Streamly.Internal.Data.Parser.yield'.
50117--
@@ -52,7 +119,7 @@ instance Functor m => Functor (Parser m a) where
52119--
53120{-# INLINE yield #-}
54121yield :: b -> Parser m a b
55−yield b = MkParser (\inp yieldk -> yieldk (inp, Right b))
122+yield b = MkParser (\zipper yieldk -> yieldk zipper (Done b))
56123
57124-------------------------------------------------------------------------------
58125-- Sequential applicative
@@ -70,18 +137,19 @@ instance Monad m => Applicative (Parser m a) where
70137 (<*>) = ap
71138
72139 {-# INLINE (*>) #-}
73− m1 *> m2 = MkParser $ \inp yieldk ->
74− let yield1 (z, b) = case b of
75− Right _ -> runParser m2 z yieldk
76− Left err -> runParser (die err) z yieldk
77− in runParser m1 inp yield1
140+ m1 *> m2 = MkParser $ \zipper yieldk ->
141+ let yield1 z (Done _) = runParser m2 z yieldk
142+ yield1 z Continue = yieldk z Continue
143+ yield1 z (Error e) = yieldk z (Error e)
144+ in runParser m1 zipper yield1
78145
79146 {-# INLINE (<*) #-}
80− m1 <* m2 = MkParser $ \inp yieldk ->
81− let yield1 (z, b) = case b of
82− Right _ -> runParser m2 z (\(z1, _) -> yieldk (z1, b))
83− Left err -> runParser (die err) z yieldk
84− in runParser m1 inp yield1
147+ m1 <* m2 = MkParser $ \zipper yieldk ->
148+ let
149+ yield1 z (Done b) = runParser m2 z $ \z1 _ -> yieldk z1 (Done b)
150+ yield1 z Continue = yieldk z Continue
151+ yield1 z (Error e) = yieldk z (Error e)
152+ in runParser m1 zipper yield1
85153
86154-- | See 'Streamly.Internal.Data.Parser.die'.
87155--
@@ -89,7 +157,7 @@ instance Monad m => Applicative (Parser m a) where
89157--
90158{-# INLINE die #-}
91159die :: String -> Parser m a b
92−die err = MkParser (\z yieldk -> yieldk (z, Left err))
160+die err = MkParser (\z yieldk -> yieldk z (Error err))
93161
94162-- | Monad composition can be used for lookbehind parsers, we can make the
95163-- future parses depend on the previously parsed values.
@@ -138,11 +206,12 @@ instance Monad m => Monad (Parser m a) where
138206 return = pure
139207
140208 {-# INLINE (>>=) #-}
141− m >>= k = MkParser $ \inp yieldk ->
142− let yield1 (z, b) = case b of
143− Right x -> runParser (k x) z yieldk
144− Left err -> runParser (die err) z yieldk
145− in runParser m inp yield1
209+ m >>= k = MkParser $ \zipper yieldk ->
210+ let
211+ yield1 z (Done b) = runParser (k b) z yieldk
212+ yield1 z Continue = yieldk z Continue
213+ yield1 z (Error e) = yieldk z (Error e)
214+ in runParser m zipper yield1
146215
147216#if !(MIN_VERSION_base(4,13,0))
148217 -- This is redefined instead of just being Fail.fail to be
@@ -175,11 +244,11 @@ instance Monad m => Alternative (Parser m a) where
175244 empty = die "empty"
176245
177246 {-# INLINE (<|>) #-}
178− m1 <|> m2 = MkParser $ \inp yieldk ->
179− let yield1 (z, b) = case b of
180− Right _ -> yieldk (Z.release z, b)
181− Left _ -> runParser m2 (Z.restore z) yieldk
182− in runParser m1 (Z.checkpoint inp) yield1
247+ m1 <|> m2 = MkParser $ \zipper yieldk ->
248+ let yield1 z (Done b) = yieldk (Z.release z) (Done b)
249+ yield1 z Continue = yieldk z Continue
250+ yield1 z (Error _) = runParser m2 (Z.restore z) yieldk
251+ in runParser m1 (Z.checkpoint zipper) yield1
183252
184253 -- some and many are implemented here instead of using default definitions
185254 -- so that we can use INLINE on them. It gives 50% performance improvement.
@@ -211,3 +280,190 @@ instance Monad m => MonadPlus (Parser m a) where
211280
212281 {-# INLINE mplus #-}
213282 mplus = (<|>)
283+
284+-------------------------------------------------------------------------------
285+-- Parse driver for a Zipper
286+-------------------------------------------------------------------------------
287+
288+-- Inlined definition. Without the inline "serially/parser/take" benchmark
289+-- degrades and splitParse does not fuse. Even using "inline" at the callsite
290+-- does not help.
291+{-# INLINE splitAt #-}
292+splitAt :: Int -> [a] -> ([a],[a])
293+splitAt n ls
294+ | n <= 0 = ([], ls)
295+ | otherwise = splitAt' n ls
296+ where
297+ splitAt' :: Int -> [a] -> ([a], [a])
298+ splitAt' _ [] = ([], [])
299+ splitAt' 1 (x:xs) = ([x], xs)
300+ splitAt' m (x:xs) = (x:xs', xs'')
301+ where
302+ (xs', xs'') = splitAt' (m - 1) xs
303+
304+-- | Parse a stream zipper using a direct style parser's @step@, @initial@ and
305+-- @extract@ functions.
306+--
307+{-# INLINE_NORMAL parse #-}
308+parse
309+ :: MonadCatch m
310+ => (s -> a -> m (PD.Step s b))
311+ -> m s
312+ -> (s -> m b)
313+ -> Zipper m a
314+ -> (Zipper m a -> Parse b -> m (Driver m a r))
315+ -> m (Driver m a r)
316+
317+-- The case when no checkpoints exist
318+parse pstep initial extract (Zipper [] backward forward stream) cont =
319+ case forward of
320+ -- Stop if stream is nil
321+ [] -> goStream stream backward initial
322+ _ -> goBuf stream backward forward initial
323+
324+ where
325+
326+ -- Pauses if no input was generated by the stream and returns a
327+ -- continuation. If the continuation is called with Nothing then it stops
328+ -- and returns the result.
329+ {-# INLINE goStream #-}
330+ goStream st back !acc =
331+ -- XXX We do not need to wrap the element in a stream we can process it
332+ -- directly.
333+ let parseCont (Just x) = goStream (K.yield x) back acc
334+ parseCont Nothing = do
335+ pst <- acc
336+ r <- try $ extract pst
337+ case r of
338+ Left (e :: PD.ParseError) ->
339+ cont Z.nil (Error (displayException e))
340+ Right b -> cont Z.nil (Done b)
341+ stop = return $ Pause parseCont
342+ single x = yieldk x K.nil
343+ yieldk x r = do
344+ acc1 <- acc >>= \b -> pstep b x
345+ case acc1 of
346+ PD.Partial 0 pst1 -> goStream r [] (return pst1)
347+ PD.Partial n pst1 -> do
348+ assert (n <= length (x:back)) (return ())
349+ let src0 = Prelude.take n (x:back)
350+ src = Prelude.reverse src0
351+ goBuf r [] src (return pst1)
352+ PD.Continue 0 pst1 -> goStream r (x:back) (return pst1)
353+ PD.Continue n pst1 -> do
354+ assert (n <= length (x:back)) (return ())
355+ let (src0, buf1) = splitAt n (x:back)
356+ src = Prelude.reverse src0
357+ goBuf r buf1 src (return pst1)
358+ PD.Done n b -> do
359+ assert (n <= length (x:back)) (return ())
360+ let (src0, buf1) = splitAt n (x:back)
361+ src = Prelude.reverse src0
362+ cont (Zipper [] buf1 src r) (Done b)
363+ PD.Error err -> cont (Zipper [] (x:back) [] r) (Error err)
364+ in K.foldStream defState yieldk single stop st
365+
366+ goBuf s back [] !pst = goStream s back pst
367+ goBuf s back (x:xs) !pst = do
368+ r <- pst
369+ pRes <- pstep r x
370+ case pRes of
371+ PD.Partial 0 pst1 ->
372+ goBuf s [] xs (return pst1)
373+ PD.Partial n pst1 -> do
374+ assert (n <= length (x:back)) (return ())
375+ let src0 = Prelude.take n (x:back)
376+ src = Prelude.reverse src0
377+ goBuf s [] (src ++ xs) (return pst1)
378+ PD.Continue 0 pst1 -> goBuf s (x:back) xs (return pst1)
379+ PD.Continue n pst1 -> do
380+ assert (n <= length (x:back)) (return ())
381+ let (src0, buf1) = splitAt n (x:back)
382+ src = Prelude.reverse src0 ++ xs
383+ goBuf s buf1 src (return pst1)
384+ PD.Done n b -> do
385+ assert (n <= length (x:back)) (return ())
386+ let (src0, buf1) = splitAt n (x:back)
387+ src = Prelude.reverse src0 ++ xs
388+ cont (Zipper [] buf1 src s) (Done b)
389+ PD.Error err -> cont (Zipper [] (x:back) xs s) (Error err)
390+
391+-- The case when checkpoints exist
392+-- XXX code duplication alert!
393+parse pstep initial extract (Zipper (cp:cps) backward forward stream) cont =
394+ case forward of
395+ [] -> goStream 0 stream backward initial
396+ _ -> goBuf 0 stream backward forward initial
397+
398+ where
399+
400+ {-# INLINE goStream #-}
401+ goStream cnt st back !acc =
402+ let parseCont (Just x) = goStream cnt (K.yield x) back acc
403+ parseCont Nothing = do
404+ pst <- acc
405+ r <- try $ extract pst
406+ case r of
407+ Left (e :: PD.ParseError) ->
408+ cont Z.nil (Error (displayException e))
409+ Right b -> cont Z.nil (Done b)
410+ stop = return $ Pause parseCont
411+ single x = yieldk x K.nil
412+ yieldk x r = do
413+ acc1 <- acc >>= \b -> pstep b x
414+ let cnt1 = cnt + 1
415+ case acc1 of
416+ PD.Partial 0 pst1 ->
417+ goStream cnt1 r [] (return pst1)
418+ PD.Partial n pst1 -> do
419+ assert (n <= length (x:back)) (return ())
420+ let src0 = Prelude.take n (x:back)
421+ src = Prelude.reverse src0
422+ goBuf (cnt1 - n) r [] src (return pst1)
423+ PD.Continue 0 pst1 -> goStream cnt1 r (x:back) (return pst1)
424+ PD.Continue n pst1 -> do
425+ assert (n <= length (x:back)) (return ())
426+ let (src0, buf1) = splitAt n (x:back)
427+ src = Prelude.reverse src0
428+ assert (cnt1 - n >= 0) (return ())
429+ goBuf (cnt1 - n) r buf1 src (return pst1)
430+ PD.Done n b -> do
431+ assert (n <= length (x:back)) (return ())
432+ let (src0, buf1) = splitAt n (x:back)
433+ src = Prelude.reverse src0
434+ assert (cp + cnt1 - n >= 0) (return ())
435+ cont (Zipper (cp + cnt1 - n : cps) buf1 src r)
436+ (Done b)
437+ PD.Error err ->
438+ cont (Zipper (cp + cnt1 : cps) (x:back) [] r)
439+ (Error err)
440+ in K.foldStream defState yieldk single stop st
441+
442+ goBuf cnt s back [] !pst = goStream cnt s back pst
443+ goBuf cnt s back (x:xs) !pst = do
444+ r <- pst
445+ pRes <- pstep r x
446+ let cnt1 = cnt + 1
447+ case pRes of
448+ PD.Partial 0 pst1 ->
449+ goBuf cnt1 s [] xs (return pst1)
450+ PD.Partial n pst1 -> do
451+ assert (n <= length (x:back)) (return ())
452+ let src0 = Prelude.take n (x:back)
453+ src = Prelude.reverse src0
454+ goBuf (cnt1 - n) s [] (src ++ xs) (return pst1)
455+ PD.Continue 0 pst1 -> goBuf cnt1 s (x:back) xs (return pst1)
456+ PD.Continue n pst1 -> do
457+ assert (n <= length (x:back)) (return ())
458+ let (src0, buf1) = splitAt n (x:back)
459+ src = Prelude.reverse src0 ++ xs
460+ assert (cnt1 - n >= 0) (return ())
461+ goBuf (cnt1 - n) s buf1 src (return pst1)
462+ PD.Done n b -> do
463+ assert (n <= length (x:back)) (return ())
464+ let (src0, buf1) = splitAt n (x:back)
465+ src = Prelude.reverse src0 ++ xs
466+ assert (cp + cnt1 - n >= 0) (return ())
467+ cont (Zipper (cp + cnt1 - n : cps) buf1 src s) (Done b)
468+ PD.Error err ->
469+ cont (Zipper (cp + cnt1 : cps) (x:back) xs s) (Error err)
src/Streamly/Internal/Data/Zipper.hs+41−183
@@ -52,25 +52,24 @@ module Streamly.Internal.Data.Zipper
5252 , fromStream
5353 , fromList
5454
55+ -- * Updating
56+ , append
57+
5558 -- * Checkpointing
5659 , checkpoint
5760 , release
5861 , restore
59−
60− -- * Parsing
61− , parse
6262 )
6363where
6464
65−import Control.Exception (assert, Exception(..))
66−import Control.Monad.Catch (MonadCatch, try)
67−-- import GHC.Types (SPEC(..))
65+import Control.Exception (assert)
66+#if !(MIN_VERSION_base(4,13,0))
67+import Data.Semigroup ((<>))
68+#endif
6869import Prelude hiding (splitAt)
6970
7071import Streamly.Internal.Data.Stream.StreamK.Type (Stream(..))
71−import Streamly.Internal.Data.SVar (defState)
7272
73−import qualified Streamly.Internal.Data.Parser.ParserD.Types as PR
7473import qualified Streamly.Internal.Data.Stream.StreamK as K
7574
7675-------------------------------------------------------------------------------
@@ -95,7 +94,11 @@ import qualified Streamly.Internal.Data.Stream.StreamK as K
9594--
9695-- /Internal/
9796--
98−data Zipper m a = Zipper [Int] [a] [a] (Stream m a)
97+data Zipper m a = Zipper
98+ [Int] -- checkpoints
99+ [a] -- past buffered inputs (for backtracking)
100+ [a] -- future buffered inputs (created by backtracking)
101+ (Stream m a) -- stream input to use after buffer is over
99102
100103-------------------------------------------------------------------------------
101104-- Construction
@@ -125,6 +128,23 @@ fromStream = Zipper [] [] []
125128fromList :: [a] -> Zipper m a
126129fromList xs = Zipper [] [] xs K.nil
127130
131+-------------------------------------------------------------------------------
132+-- Updating
133+-------------------------------------------------------------------------------
134+
135+-- | Add an element at the tail of the Zipper.
136+--
137+-- /Internal/
138+--
139+{-# INLINE append #-}
140+append :: a -> Zipper m a -> Zipper m a
141+append x (Zipper checkpoints backward forward stream) =
142+ Zipper checkpoints backward forward (stream <> K.yield x)
143+
144+-------------------------------------------------------------------------------
145+-- Checkpointing
146+-------------------------------------------------------------------------------
147+
128148-- | Add a checkpoint to the Zipper so that we do not release the buffer beyond
129149-- the checkpoint.
130150--
@@ -149,23 +169,8 @@ release (Zipper (n:cps) xs ys stream) =
149169 [] -> assert (n == length xs) $ Zipper [] [] ys stream
150170 cp:rest -> Zipper ((cp + n) : rest) xs ys stream
151171
152−-- | Rewind to restore the cursor to the latest checkpoint.
153−--
154−-- /Internal/
172+-- XXX recheck this, and unify with the definition in StreamD and ParserK
155173--
156−{-# INLINE restore #-}
157−restore :: Zipper m a -> Zipper m a
158−restore (Zipper [] _ _ _) = error "Bug: restore, no checkpoint exists!"
159−restore (Zipper (n:cps) xs ys stream) =
160− assert (n <= length xs) $
161− let (src0, buf1) = splitAt n xs
162− src = Prelude.reverse src0
163− in Zipper cps buf1 (src ++ ys) stream
164−
165−-------------------------------------------------------------------------------
166−-- Parse driver for a Zipper
167−-------------------------------------------------------------------------------
168−
169174-- Inlined definition. Without the inline "serially/parser/take" benchmark
170175-- degrades and splitParse does not fuse. Even using "inline" at the callsite
171176-- does not help.
@@ -182,162 +187,15 @@ splitAt n ls
182187 where
183188 (xs', xs'') = splitAt' (m - 1) xs
184189
185−-- | Parse a stream zipper using a parser's @step@, @initial@ and @extract@
186−-- functions.
190+-- | Rewind to restore the cursor to the latest checkpoint.
187191--
188−{-# INLINE_NORMAL parse #-}
189−parse
190− :: MonadCatch m
191− => (s -> a -> m (PR.Step s b))
192− -> m s
193− -> (s -> m b)
194− -> Zipper m a
195− -> m (Zipper m a, Either String b)
196−
197−-- The case when no checkpoints exist
198−parse pstep initial extract (Zipper [] ls rs stream) =
199− case rs of
200− [] -> go stream ls initial
201− _ -> gobuf stream ls rs initial
202−
203− where
204−
205− {-# INLINE go #-}
206− go st buf !acc =
207− let stop = do
208− pst <- acc
209− r <- try $ extract pst
210− return $ case r of
211− Left (e :: PR.ParseError) ->
212− (nil, Left (displayException e))
213− Right b -> (nil, Right b)
214− single x = yieldk x K.nil
215− yieldk x r = do
216− acc1 <- acc >>= \b -> pstep b x
217− case acc1 of
218− PR.Partial 0 pst1 -> go r [] (return pst1)
219− PR.Partial n pst1 -> do
220− assert (n <= length (x:buf)) (return ())
221− let src0 = Prelude.take n (x:buf)
222− src = Prelude.reverse src0
223− gobuf r [] src (return pst1)
224− PR.Continue 0 pst1 -> go r (x:buf) (return pst1)
225− PR.Continue n pst1 -> do
226− assert (n <= length (x:buf)) (return ())
227− let (src0, buf1) = splitAt n (x:buf)
228− src = Prelude.reverse src0
229− gobuf r buf1 src (return pst1)
230− PR.Done n b -> do
231− assert (n <= length (x:buf)) (return ())
232− let (src0, buf1) = splitAt n (x:buf)
233− src = Prelude.reverse src0
234− return (Zipper [] buf1 src r, Right b)
235− PR.Error err ->
236− return (Zipper [] (x:buf) [] r, Left err)
237− in K.foldStream defState yieldk single stop st
238−
239− gobuf s buf [] !pst = go s buf pst
240− gobuf s buf (x:xs) !pst = do
241− r <- pst
242− pRes <- pstep r x
243− case pRes of
244− PR.Partial 0 pst1 ->
245− gobuf s [] xs (return pst1)
246− PR.Partial n pst1 -> do
247− assert (n <= length (x:buf)) (return ())
248− let src0 = Prelude.take n (x:buf)
249− src = Prelude.reverse src0
250− gobuf s [] (src ++ xs) (return pst1)
251− PR.Continue 0 pst1 -> gobuf s (x:buf) xs (return pst1)
252− PR.Continue n pst1 -> do
253− assert (n <= length (x:buf)) (return ())
254− let (src0, buf1) = splitAt n (x:buf)
255− src = Prelude.reverse src0 ++ xs
256− gobuf s buf1 src (return pst1)
257− PR.Done n b -> do
258− assert (n <= length (x:buf)) (return ())
259− let (src0, buf1) = splitAt n (x:buf)
260− src = Prelude.reverse src0 ++ xs
261− return (Zipper [] buf1 src s, Right b)
262− PR.Error err ->
263− return (Zipper [] (x:buf) xs s, Left err)
264−
265−-- The case when checkpoints exist
266−-- XXX code duplication alert!
267−parse pstep initial extract (Zipper (cp:cps) ls rs stream) =
268− case rs of
269− [] -> go 0 stream ls initial
270− _ -> gobuf 0 stream ls rs initial
271−
272− where
273−
274− {-# INLINE go #-}
275− go cnt st buf !acc =
276− let stop = do
277− pst <- acc
278− r <- try $ extract pst
279− return $ case r of
280− Left (e :: PR.ParseError) ->
281− (nil, Left (displayException e))
282− Right b -> (nil, Right b)
283− single x = yieldk x K.nil
284− yieldk x r = do
285− acc1 <- acc >>= \b -> pstep b x
286− let cnt1 = cnt + 1
287− case acc1 of
288− PR.Partial 0 pst1 ->
289− go cnt1 r [] (return pst1)
290− PR.Partial n pst1 -> do
291− assert (n <= length (x:buf)) (return ())
292− let src0 = Prelude.take n (x:buf)
293− src = Prelude.reverse src0
294− gobuf (cnt1 - n) r [] src (return pst1)
295− PR.Continue 0 pst1 -> go cnt1 r (x:buf) (return pst1)
296− PR.Continue n pst1 -> do
297− assert (n <= length (x:buf)) (return ())
298− let (src0, buf1) = splitAt n (x:buf)
299− src = Prelude.reverse src0
300− assert (cnt1 - n >= 0) (return ())
301− gobuf (cnt1 - n) r buf1 src (return pst1)
302− PR.Done n b -> do
303− assert (n <= length (x:buf)) (return ())
304− let (src0, buf1) = splitAt n (x:buf)
305− src = Prelude.reverse src0
306− assert (cp + cnt1 - n >= 0) (return ())
307− return ( Zipper (cp + cnt1 - n : cps) buf1 src r
308− , Right b
309− )
310− PR.Error err ->
311− return ( Zipper (cp + cnt1 : cps) (x:buf) [] r
312− , Left err
313− )
314− in K.foldStream defState yieldk single stop st
315−
316− gobuf cnt s buf [] !pst = go cnt s buf pst
317− gobuf cnt s buf (x:xs) !pst = do
318− r <- pst
319− pRes <- pstep r x
320− let cnt1 = cnt + 1
321− case pRes of
322− PR.Partial 0 pst1 ->
323− gobuf cnt1 s [] xs (return pst1)
324− PR.Partial n pst1 -> do
325− assert (n <= length (x:buf)) (return ())
326− let src0 = Prelude.take n (x:buf)
327− src = Prelude.reverse src0
328− gobuf (cnt1 - n) s [] (src ++ xs) (return pst1)
329− PR.Continue 0 pst1 -> gobuf cnt1 s (x:buf) xs (return pst1)
330− PR.Continue n pst1 -> do
331− assert (n <= length (x:buf)) (return ())
332− let (src0, buf1) = splitAt n (x:buf)
333− src = Prelude.reverse src0 ++ xs
334− assert (cnt1 - n >= 0) (return ())
335− gobuf (cnt1 - n) s buf1 src (return pst1)
336− PR.Done n b -> do
337− assert (n <= length (x:buf)) (return ())
338− let (src0, buf1) = splitAt n (x:buf)
339− src = Prelude.reverse src0 ++ xs
340− assert (cp + cnt1 - n >= 0) (return ())
341− return (Zipper (cp + cnt1 - n : cps) buf1 src s, Right b)
342− PR.Error err ->
343− return (Zipper (cp + cnt1 : cps) (x:buf) xs s, Left err)
192+-- /Internal/
193+--
194+{-# INLINE restore #-}
195+restore :: Zipper m a -> Zipper m a
196+restore (Zipper [] _ _ _) = error "Bug: restore, no checkpoint exists!"
197+restore (Zipper (n:cps) xs ys stream) =
198+ assert (n <= length xs) $
199+ let (src0, buf1) = splitAt n xs
200+ src = Prelude.reverse src0
201+ in Zipper cps buf1 (src ++ ys) stream
src/Streamly/Internal/Prelude.hs+7−4
@@ -1368,11 +1368,14 @@ parseD (PRD.Parser step initial extract) = P.parselMx' step initial extract
13681368{-# INLINE parseK #-}
13691369parseK :: MonadThrow m => PRK.Parser m a b -> SerialT m a -> m b
13701370parseK parser xs = do
1371− r <- PRK.runParser parser (ZR.fromStream $ K.toStream xs)
1372− (\(_, b) -> return b)
1371+ let yieldk _ (PRK.Done b) = return $ PRK.Stop b
1372+ yieldk _ PRK.Continue = error "Bug: fromParserK: got Continue"
1373+ yieldk _ (PRK.Error e) = return $ PRK.Failed e
1374+ r <- PRK.runParser parser (ZR.fromStream $ K.toStream xs) yieldk
13731375 case r of
1374− Left err -> throwM (PRD.ParseError err)
1375− Right b -> return b
1376+ PRK.Stop b -> return b
1377+ PRK.Failed err -> throwM (PRD.ParseError err)
1378+ PRK.Pause cont -> PRK.extractParse cont
13761379
13771380-- | Parse a stream using the supplied 'Parser'.
13781381--