on master help sign in
Add YieldB (yield and backtrack) constructor

This fixes an issue in many/some/manyTill combinators.

commit2c9feb48eff608f5728f2a7ac4db6095be0669b7 authorHarendra Kumar <harendra@composewell.com> dateTue 21 Apr 2020, 17:57 (6 years ago) parent633c55e
7 files changed+166−59
benchmark/Streamly/Benchmark/Data/Parser.hs+1−3 benchmark/Streamly/Benchmark/Data/ParserD.hs+1−3 src/Streamly/Internal/Data/Parser/ParserD.hs+4−3 src/Streamly/Internal/Data/Parser/ParserD/Tee.hs+47−16 src/Streamly/Internal/Data/Parser/ParserD/Types.hs+61−34 src/Streamly/Internal/Data/Stream/StreamD.hs+32 src/Streamly/Internal/Data/Zipper.hs+20
benchmark/Streamly/Benchmark/Data/Parser.hs+1−3
@@ -207,6 +207,7 @@ o_1_space_serial_parse value =
207207 , benchIOSink value "splitWith (all,any)" $ splitWithAllAny value
208208 , benchIOSink value "many" many
209209 , benchIOSink value "some" some
210+ , benchIOSink value "manyTill" $ manyTill value
210211 , benchIOSink value "tee (all,any)" $ teeAllAny value
211212 , benchIOSink value "teeFst (all,any)" $ teeFstAllAny value
212213 , benchIOSink value "shortest (all,any)" $ shortestAllAny value
@@ -230,9 +231,6 @@ o_n_heap_serial_parse value =
230231 -- XXX why O(n)?
231232 , benchIOSink value "choice" $ choice value
232233
233− -- XXX this should get better with "yield with backtrack" fix
234− , benchIOSink value "manyTill" $ manyTill value
235−
236234 -- These show non-linear time complexity.
237235 -- They accumulate the results in a list.
238236 , benchIOSink value "manyAlt" manyAlt
benchmark/Streamly/Benchmark/Data/ParserD.hs+1−3
@@ -186,6 +186,7 @@ o_1_space_serial_parse value =
186186 , benchIOSink value "split (all,any)" $ splitAllAny value
187187 , benchIOSink value "many" many
188188 , benchIOSink value "some" some
189+ , benchIOSink value "manyTill" $ manyTill value
189190 , benchIOSink value "tee (all,any)" $ teeAllAny value
190191 , benchIOSink value "teeFst (all,any)" $ teeFstAllAny value
191192 , benchIOSink value "shortest (all,any)" $ shortestAllAny value
@@ -198,9 +199,6 @@ o_n_heap_serial_parse value =
198199 -- lookahead benchmark holds the entire input till end
199200 benchIOSink value "lookAhead" $ lookAhead value
200201
201− -- XXX this should get better with "yield with backtrack" fix
202− , benchIOSink value "manyTill" $ manyTill value
203−
204202 -- These show non-linear time complexity
205203 -- They accumulate the results in a list.
206204 , benchIOSink value "manyAlt" manyAlt
src/Streamly/Internal/Data/Parser/ParserD.hs+4−3
@@ -587,6 +587,7 @@ lookAhead (Parser step1 initial1 _) =
587587 let cnt1 = cnt + 1
588588 return $ case r of
589589 Yield _ s -> Skip 0 (Tuple' cnt1 s)
590+ YieldB n s -> Skip n (Tuple' (cnt1 - n) s)
590591 Skip n s -> Skip n (Tuple' (cnt1 - n) s)
591592 Stop _ b -> Stop cnt1 b
592593 Error err -> Error err
@@ -710,6 +711,7 @@ manyTill (Fold fstep finitial fextract)
710711 r <- stepR st a
711712 case r of
712713 Yield n s -> return $ Yield n (ManyTillR 0 fs s)
714+ YieldB n s -> return $ YieldB n (ManyTillR 0 fs s)
713715 Skip n s -> do
714716 assert (cnt + 1 - n >= 0) (return ())
715717 return $ Skip n (ManyTillR (cnt + 1 - n) fs s)
@@ -724,13 +726,12 @@ manyTill (Fold fstep finitial fextract)
724726 r <- stepL st a
725727 case r of
726728 Yield n s -> return $ Yield n (ManyTillL fs s)
729+ YieldB n s -> return $ YieldB n (ManyTillL fs s)
727730 Skip n s -> return $ Skip n (ManyTillL fs s)
728731 Stop n b -> do
729732 fs1 <- fstep fs b
730733 l <- initialR
731− -- XXX we need a yield with backtrack here
732− -- return $ Yield n (ManyTillR 0 fs1 l)
733− return $ Skip n (ManyTillR 0 fs1 l)
734+ return $ YieldB n (ManyTillR 0 fs1 l)
734735 Error err -> return $ Error err
735736
736737 extract (ManyTillL fs sR) = extractL sR >>= fstep fs >>= fextract
src/Streamly/Internal/Data/Parser/ParserD/Tee.hs+47−16
@@ -55,11 +55,40 @@ import Streamly.Internal.Data.Parser.ParserD.Types
5555-- Distribute input to two parsers and collect both results
5656-------------------------------------------------------------------------------
5757
58+-- When the input stream is distributed to two parsers, both the parsers can
59+-- backtrack independently. Therefore, we need separate buffer state for each
60+-- parser.
61+--
62+-- ParserK
63+--
64+-- We can keep the state of each parser in the zipper and pass around that
65+-- zipper to the parsers. Each parser can consume from the zipper and then pass
66+-- around the zipper to the other parser.
67+--
68+-- ParserD
69+--
70+-- In the approach we have taken here, the driver pushes one element at a time
71+-- to the tee and each of the parsers in the tee may buffer it independently
72+-- for backtracking. So they do not need to depend on the original stream
73+-- source for individual parser backtracking. Problem arises when both the
74+-- parsers backtrack and they do not need any input from the driver rather they
75+-- must consume from their buffers. For such situation we may need a
76+-- "Skip/Continue" style driver command from the tee so that the driver runs
77+-- the tee without providing it any input. Or we may need a local driver loop
78+-- until new input is to be demanded from the input stream.
79+--
80+-- When the tee errors out or stops, the tee driver may have to backtrack by
81+-- the specified amount (or the tee must return the leftover input). Therefore,
82+-- the tee driver also has to buffer, this leads to triple buffering.
83+--
84+-- When the tee stops we need to determine the backtracking amount from the
85+-- leftover of both the parsers. Since both the parsers may have consumed
86+-- different lengths of the stream we consider the maximum of the two as
87+-- consumed.
88+--
5889{-# ANN type StepState Fuse #-}
5990data StepState s a = StepState s | StepResult a
6091
61−-- XXX Use a Zipper structure for buffering?
62−--
6392-- | State of the pair of parsers in a tee composition
6493-- Note: strictness annotation is important for fusing the constructors
6594{-# ANN type TeeState Fuse #-}
@@ -70,19 +99,9 @@ data TeeState sL sR x a b =
7099{-# ANN type Res Fuse #-}
71100data Res = Yld Int | Stp Int | Skp | Err String
72101
73−-- XXX: With the current "Step" semantics, it is hard to write, and not sure
74−-- how useful, an efficient teeWith that returns a correct unused input count.
75−--
76−-- XXX Teeing a parser with a Fold could be more useful and simpler to
77−-- implement. A fold never fails or backtracks so we do not need to buffer the
78−-- input for the fold. It can be useful in, for example, maintaining the line
79−-- and column number position to report for errors. We can always have the
80−-- line/column fold running in parallel with the main parser, whenever an error
81−-- occurs we can zip the error with the context fold.
82−--
83102-- | See 'Streamly.Internal.Data.Parser.teeWith'.
84103--
85−-- /Internal/
104+-- /Broken/
86105--
87106{-# INLINE teeWith #-}
88107teeWith :: Monad m
@@ -109,6 +128,10 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
109128 let buf1 = x:buf
110129 return (buf1, r, inp11, inp21)
111130
131+ -- XXX This is currently broken, even though both the parsers need to
132+ -- consume from their buffers after backtracking the driver would still be
133+ -- pushing more input to the buffers.
134+ --
112135 -- consume one input item and return the next state of the fold
113136 {-# INLINE useStream #-}
114137 useStream buf inp1 inp2 stp st y = do
@@ -117,6 +140,11 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
117140 Yield n s ->
118141 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
119142 in assert (n <= length buf1) (return (state, Yld n))
143+ YieldB n s ->
144+ let src0 = Prelude.take n buf1
145+ src = Prelude.reverse src0
146+ state = ([], StepState s, src ++ inp11, inp21)
147+ in assert (n <= length buf1) (return (state, Yld n))
120148 Stop n b ->
121149 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
122150 in assert (n <= length buf1) (return (state, Stp n))
@@ -200,7 +228,7 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
200228
201229-- | See 'Streamly.Internal.Data.Parser.teeWithFst'.
202230--
203−-- /Internal/
231+-- /Broken/
204232--
205233{-# INLINE teeWithFst #-}
206234teeWithFst :: Monad m
@@ -236,6 +264,7 @@ teeWithFst zf (Parser stepL initialL extractL)
236264 Yield n s ->
237265 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
238266 in assert (n <= length buf1) (return (state, Yld n))
267+ YieldB _ _ -> undefined
239268 Stop n b ->
240269 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
241270 in assert (n <= length buf1) (return (state, Stp n))
@@ -323,7 +352,7 @@ teeWithMin = undefined
323352
324353-- | See 'Streamly.Internal.Data.Parser.shortest'.
325354--
326−-- /Internal/
355+-- /Broken/
327356--
328357{-# INLINE shortest #-}
329358shortest :: Monad m => Parser m x a -> Parser m x a -> Parser m x a
@@ -357,6 +386,7 @@ shortest (Parser stepL initialL extractL) (Parser stepR initialR _) =
357386 Yield n s ->
358387 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
359388 in assert (n <= length buf1) (return (state, Yld n))
389+ YieldB _ _ -> undefined
360390 Stop n b ->
361391 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
362392 in assert (n <= length buf1) (return (state, Stp n))
@@ -399,7 +429,7 @@ shortest (Parser stepL initialL extractL) (Parser stepR initialR _) =
399429
400430-- | See 'Streamly.Internal.Data.Parser.longest'.
401431--
402−-- /Internal/
432+-- /Broken/
403433--
404434{-# INLINE longest #-}
405435longest :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
@@ -433,6 +463,7 @@ longest (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
433463 Yield n s ->
434464 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
435465 in assert (n <= length buf1) (return (state, Yld n))
466+ YieldB _ _ -> undefined
436467 Stop n b ->
437468 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
438469 in assert (n <= length buf1) (return (state, Stp n))
src/Streamly/Internal/Data/Parser/ParserD/Types.hs+61−34
@@ -40,9 +40,12 @@
4040-- 'Step' functor provides the following commands to the fold driver
4141-- corresponding to the use cases outlined in the previous para:
4242--
43−-- 1. 'Skip': hold (buffer) the input or go back to a previous position in the stream
44−-- 2. 'Yield', 'Stop': tell how much input is unconsumed
45−-- 3. 'Error': indicates that the parser has failed without a result
43+-- 1. 'Skip': buffer the current input and go back to a previous
44+-- position in the stream
45+-- 2. 'Yield': buffer the current input and go back to a previous
46+-- position in the stream, drop the buffer before that position.
47+-- 3. 'Stop': parser succeeded, returns how much input was leftover
48+-- 4. 'Error': indicates that the parser has failed without a result
4649--
4750-- = How a Parser Works?
4851--
@@ -78,7 +81,7 @@
7881--
7982-- = Error Handling
8083--
81−-- When a parser's @step@ function is invoked it may iterminate by either a
84+-- When a parser's @step@ function is invoked it may terminate by either a
8285-- 'Stop' or an 'Error' return value. In an 'Alternative' composition an error
8386-- return can make the composed parser backtrack and try another parser.
8487--
@@ -159,33 +162,47 @@ import Streamly.Internal.Data.Strict (Tuple3'(..))
159162{-# ANN type Step Fuse #-}
160163data Step s b =
161164 Yield Int s
162− -- ^ @Yield offset state@ indicates that the parser has yielded a new
163− -- result which is a point of no return. The result can be extracted
164− -- using @extract@. The driver drops the buffer except @offset@ elements
165− -- before the current position in stream. The rule is that if a parser
166− -- has yielded at least once it cannot return a failure result.
167−
165+ -- ^ Trim the backtracking buffer keeping only most recent @n@ items.
166+ -- @Yield n state@ indicates that the parser has yielded a new result
167+ -- which is a point of no return. The result can be extracted using
168+ -- @extract@. The driver drops the buffer except @n@ most recent
169+ -- elements. The rule is that if a parser has yielded at least once it
170+ -- cannot return a failure result.
171+
172+ | YieldB Int s
173+ -- ^ Go back by @n@ items in the input buffer and drop the rest.
174+ -- @YieldB n state@ indicates that the parser has yielded a new result
175+ -- which is a point of no return. The result can be extracted using
176+ -- @extract@. The driver moves back the current position of the cursor by
177+ -- @n@ elements and drops any buffer before that.
178+
179+ -- only rewind
168180 | Skip Int s
169− -- ^ @Skip offset state@ indicates that the parser has consumed the current
170− -- input but no new result has been generated. A new @state@ is generated.
181+ -- ^ Go back by @n@ items in the input buffer.
182+ -- @Skip n state@ indicates that the parser has consumed the current input
183+ -- but no new result has been generated. A new @state@ is generated.
171184 -- However, if we use @extract@ on @state@ it will generate a result from
172− -- the previous @Yield@. When @offset@ is non-zero it is a backward offset
173− -- from the current position in the stream from which the driver will feed
174− -- the next input to the parser. The offset cannot be beyond the latest
175− -- point of no return created by @Yield@.
185+ -- the previous @Yield@. When @n@ is non-zero it is a backward offset from
186+ -- the current position in the stream from which the driver will replay the
187+ -- input to the parser. The offset cannot be beyond the latest point of no
188+ -- return created by @Yield@.
176189
177190 | Stop Int b
178− -- ^ @Stop offset result@ asks the driver to stop driving the parser
179− -- because it has reached a fixed point and further input will not change
180− -- the result. @offset@ is the count of unused elements which includes the
181− -- element on which 'Stop' occurred.
191+ -- ^ Trim the backtracking buffer keeping only most recent @n@ items.
192+ -- @Stop n result@ asks the driver to stop driving the parser because it
193+ -- has reached a fixed point and further input will not change the result.
194+ -- @n@ is the count of unused input elements which includes the element on
195+ -- which 'Stop' occurred.
196+
182197 | Error String
183− -- ^ An error makes the parser backtrack to the last checkpoint and try
198+ -- ^ Go back to the start of the backtracking buffer.
199+ -- An error makes the parser backtrack to the last checkpoint and try
184200 -- another alternative.
185201
186202instance Functor (Step s) where
187203 {-# INLINE fmap #-}
188204 fmap _ (Yield n s) = Yield n s
205+ fmap _ (YieldB n s) = YieldB n s
189206 fmap _ (Skip n s) = Skip n s
190207 fmap f (Stop n b) = Stop n (f b)
191208 fmap _ (Error err) = Error err
@@ -282,9 +299,12 @@ splitWith func (Parser stepL initialL extractL)
282299 step (SeqParseL st) a = do
283300 r <- stepL st a
284301 case r of
285− -- Note: this leads to buffering even if we are not in an
286− -- Alternative composition.
302+ -- Note: We need to buffer the input for a possible Alternative
303+ -- e.g. in ((,) <$> p1 <*> p2) <|> p3, if p2 fails we have to
304+ -- backtrack and start running p3. So we need to keep the input
305+ -- buffered until we know that the applicative cannot fail.
287306 Yield _ s -> return $ Skip 0 (SeqParseL s)
307+ YieldB n s -> return $ Skip n (SeqParseL s)
288308 Skip n s -> return $ Skip n (SeqParseL s)
289309 Stop n b -> Skip n <$> (SeqParseR (func b) <$> initialR)
290310 Error err -> return $ Error err
@@ -293,6 +313,7 @@ splitWith func (Parser stepL initialL extractL)
293313 r <- stepR st a
294314 return $ case r of
295315 Yield n s -> Yield n (SeqParseR f s)
316+ YieldB n s -> YieldB n (SeqParseR f s)
296317 Skip n s -> Skip n (SeqParseR f s)
297318 Stop n b -> Stop n (f b)
298319 Error err -> Error err
@@ -328,6 +349,7 @@ split_ (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
328349 -- Note: this leads to buffering even if we are not in an
329350 -- Alternative composition.
330351 Yield _ s -> Skip 0 (SeqAL s)
352+ YieldB n s -> Skip n (SeqAL s)
331353 Skip n s -> Skip n (SeqAL s)
332354 Stop n _ -> Skip n (SeqAR i)
333355 -- XXX should we sequence initialR monadically?
@@ -336,6 +358,7 @@ split_ (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
336358 step (SeqAR st) a = do
337359 (\r -> case r of
338360 Yield n s -> Yield n (SeqAR s)
361+ YieldB n s -> YieldB n (SeqAR s)
339362 Skip n s -> Skip n (SeqAR s)
340363 Stop n b -> Stop n b
341364 Error err -> Error err) <$> stepR st a
@@ -390,6 +413,7 @@ alt (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
390413 r <- stepL st a
391414 case r of
392415 Yield n s -> return $ Yield n (AltParseL 0 s)
416+ YieldB n s -> return $ YieldB n (AltParseL 0 s)
393417 Skip n s -> do
394418 assert (cnt + 1 - n >= 0) (return ())
395419 return $ Skip n (AltParseL (cnt + 1 - n) s)
@@ -402,6 +426,7 @@ alt (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
402426 r <- stepR st a
403427 return $ case r of
404428 Yield n s -> Yield n (AltParseR s)
429+ YieldB n s -> YieldB n (AltParseR s)
405430 Skip n s -> Skip n (AltParseR s)
406431 Stop n b -> Stop n b
407432 Error err -> Error err
@@ -431,14 +456,16 @@ splitMany (Fold fstep finitial fextract) (Parser step1 initial1 extract1) =
431456 let cnt1 = cnt + 1
432457 case r of
433458 Yield _ s -> return $ Skip 0 (Tuple3' s cnt1 fs)
459+ YieldB n s -> do
460+ assert (cnt1 - n >= 0) (return ())
461+ return $ Skip n (Tuple3' s (cnt1 - n) fs)
434462 Skip n s -> do
435463 assert (cnt1 - n >= 0) (return ())
436464 return $ Skip n (Tuple3' s (cnt1 - n) fs)
437465 Stop n b -> do
438466 s <- initial1
439467 fs1 <- fstep fs b
440− -- XXX we need to yield and backtrack here
441− return $ Skip n (Tuple3' s 0 fs1)
468+ return $ YieldB n (Tuple3' s 0 fs1)
442469 Error _ -> do
443470 xs <- fextract fs
444471 return $ Stop cnt1 xs
@@ -471,31 +498,28 @@ splitSome (Fold fstep finitial fextract) (Parser step1 initial1 extract1) =
471498 r <- step1 st a
472499 case r of
473500 Yield _ s -> return $ Skip 0 (Tuple3' s undefined (Left fs))
501+ YieldB n s -> return $ Skip n (Tuple3' s undefined (Left fs))
474502 Skip n s -> return $ Skip n (Tuple3' s undefined (Left fs))
475503 Stop n b -> do
476504 s <- initial1
477505 fs1 <- fstep fs b
478− -- XXX this is also a yield point, we will never fail beyond
479− -- this point. If we do not yield then if an error occurs after
480− -- this then we will backtrack to the previous yield point
481− -- instead of this point which is wrong.
482− --
483− -- so we need a yield with backtrack
484− return $ Skip n (Tuple3' s 0 (Right fs1))
506+ return $ YieldB n (Tuple3' s 0 (Right fs1))
485507 Error err -> return $ Error err
486508 step (Tuple3' st cnt (Right fs)) a = do
487509 r <- step1 st a
488510 let cnt1 = cnt + 1
489511 case r of
490512 Yield _ s -> return $ Yield 0 (Tuple3' s cnt1 (Right fs))
513+ YieldB n s -> do
514+ assert (cnt1 - n >= 0) (return ())
515+ return $ YieldB n (Tuple3' s (cnt1 - n) (Right fs))
491516 Skip n s -> do
492517 assert (cnt1 - n >= 0) (return ())
493518 return $ Skip n (Tuple3' s (cnt1 - n) (Right fs))
494519 Stop n b -> do
495520 s <- initial1
496521 fs1 <- fstep fs b
497− -- XXX we need to yield here but also backtrack
498− return $ Skip n (Tuple3' s 0 (Right fs1))
522+ return $ YieldB n (Tuple3' s 0 (Right fs1))
499523 Error _ -> Stop cnt1 <$> fextract fs
500524
501525 -- XXX The "try" may impact performance if this parser is used as a scan
@@ -575,6 +599,7 @@ concatMap func (Parser stepL initialL extractL) = Parser step initial extract
575599 r <- stepL st a
576600 return $ case r of
577601 Yield _ s -> Skip 0 (ConcatParseL s)
602+ YieldB n s -> Skip n (ConcatParseL s)
578603 Skip n s -> Skip n (ConcatParseL s)
579604 Stop n b -> Skip n (ConcatParseR (func b))
580605 Error err -> Error err
@@ -585,6 +610,8 @@ concatMap func (Parser stepL initialL extractL) = Parser step initial extract
585610 return $ case r of
586611 Yield n s ->
587612 Yield n (ConcatParseR (Parser stepR (return s) extractR))
613+ YieldB n s ->
614+ YieldB n (ConcatParseR (Parser stepR (return s) extractR))
588615 Skip n s ->
589616 Skip n (ConcatParseR (Parser stepR (return s) extractR))
590617 Stop n b -> Stop n b
src/Streamly/Internal/Data/Stream/StreamD.hs+32
@@ -998,6 +998,11 @@ parselMx' pstep initial extract (Stream step state) = do
998998 PR.Yield n pst1 -> do
999999 assert (n <= length (x:buf)) (return ())
10001000 go SPEC s (Prelude.take n (x:buf)) pst1
1001+ PR.YieldB n pst1 -> do
1002+ assert (n <= length (x:buf)) (return ())
1003+ let src0 = Prelude.take n (x:buf)
1004+ src = Prelude.reverse src0
1005+ gobuf SPEC s [] src pst1
10011006 PR.Skip 0 pst1 -> go SPEC s (x:buf) pst1
10021007 PR.Skip n pst1 -> do
10031008 assert (n <= length (x:buf)) (return ())
@@ -1017,6 +1022,11 @@ parselMx' pstep initial extract (Stream step state) = do
10171022 PR.Yield n pst1 -> do
10181023 assert (n <= length (x:buf)) (return ())
10191024 gobuf SPEC s (Prelude.take n (x:buf)) xs pst1
1025+ PR.YieldB n pst1 -> do
1026+ assert (n <= length (x:buf)) (return ())
1027+ let src0 = Prelude.take n (x:buf)
1028+ src = Prelude.reverse src0
1029+ gobuf SPEC s [] src pst1
10201030 PR.Skip 0 pst1 -> gobuf SPEC s (x:buf) xs pst1
10211031 PR.Skip n pst1 -> do
10221032 assert (n <= length (x:buf)) (return ())
@@ -1073,6 +1083,11 @@ parseMany (PRD.Parser pstep initial extract) (Stream step state) =
10731083 assert (n <= length (x:buf)) (return ())
10741084 let buf1 = Prelude.take n (x:buf)
10751085 return $ Skip $ ParseChunksStream s buf1 pst1
1086+ PR.YieldB n pst1 -> do
1087+ assert (n <= length (x:buf)) (return ())
1088+ let src0 = Prelude.take n (x:buf)
1089+ src = Prelude.reverse src0
1090+ return $ Skip $ ParseChunksBuf src s [] pst1
10761091 -- PR.Skip 0 pst1 ->
10771092 -- return $ Skip $ ParseChunksStream s (x:buf) pst1
10781093 PR.Skip n pst1 -> do
@@ -1107,6 +1122,11 @@ parseMany (PRD.Parser pstep initial extract) (Stream step state) =
11071122 assert (n <= length (x:buf)) (return ())
11081123 let buf1 = Prelude.take n (x:buf)
11091124 return $ Skip $ ParseChunksBuf xs s buf1 pst1
1125+ PR.YieldB n pst1 -> do
1126+ assert (n <= length (x:buf)) (return ())
1127+ let src0 = Prelude.take n (x:buf)
1128+ src = Prelude.reverse src0
1129+ return $ Skip $ ParseChunksBuf src s [] pst1
11101130 -- PR.Skip 0 pst1 -> return $ Skip $ ParseChunksBuf xs s (x:buf) pst1
11111131 PR.Skip n pst1 -> do
11121132 assert (n <= length (x:buf)) (return ())
@@ -1172,6 +1192,12 @@ parseIterate func seed (Stream step state) =
11721192 let buf1 = Prelude.take n (x:buf)
11731193 return $ Skip $ ConcatParseStream s buf1
11741194 (PRD.Parser pstep (return pst1) extract)
1195+ PR.YieldB n pst1 -> do
1196+ assert (n <= length (x:buf)) (return ())
1197+ let src0 = Prelude.take n (x:buf)
1198+ src = Prelude.reverse src0
1199+ return $ Skip $ ConcatParseBuf src s []
1200+ (PRD.Parser pstep (return pst1) extract)
11751201 -- PR.Skip 0 pst1 ->
11761202 -- return $ Skip $ ConcatParseStream s (x:buf) pst1
11771203 PR.Skip n pst1 -> do
@@ -1211,6 +1237,12 @@ parseIterate func seed (Stream step state) =
12111237 let buf1 = Prelude.take n (x:buf)
12121238 return $ Skip $ ConcatParseBuf xs s buf1
12131239 (PRD.Parser pstep (return pst1) extract)
1240+ PR.YieldB n pst1 -> do
1241+ assert (n <= length (x:buf)) (return ())
1242+ let src0 = Prelude.take n (x:buf)
1243+ src = Prelude.reverse src0
1244+ return $ Skip $ ConcatParseBuf src s []
1245+ (PRD.Parser pstep (return pst1) extract)
12141246 -- PR.Skip 0 pst1 -> return $ Skip $ ConcatParseBuf xs s (x:buf) pst1
12151247 PR.Skip n pst1 -> do
12161248 assert (n <= length (x:buf)) (return ())
src/Streamly/Internal/Data/Zipper.hs+20
@@ -224,6 +224,11 @@ parse pstep initial extract (Zipper [] ls rs stream) =
224224 PR.Yield n pst1 -> do
225225 assert (n <= length (x:buf)) (return ())
226226 go r (Prelude.take n (x:buf)) (return pst1)
227+ PR.YieldB n pst1 -> do
228+ assert (n <= length (x:buf)) (return ())
229+ let src0 = Prelude.take n (x:buf)
230+ src = Prelude.reverse src0
231+ gobuf r [] src (return pst1)
227232 PR.Skip 0 pst1 -> go r (x:buf) (return pst1)
228233 PR.Skip n pst1 -> do
229234 assert (n <= length (x:buf)) (return ())
@@ -248,6 +253,11 @@ parse pstep initial extract (Zipper [] ls rs stream) =
248253 PR.Yield n pst1 -> do
249254 assert (n <= length (x:buf)) (return ())
250255 gobuf s (Prelude.take n (x:buf)) xs (return pst1)
256+ PR.YieldB n pst1 -> do
257+ assert (n <= length (x:buf)) (return ())
258+ let src0 = Prelude.take n (x:buf)
259+ src = Prelude.reverse src0
260+ gobuf s [] src (return pst1)
251261 PR.Skip 0 pst1 -> gobuf s (x:buf) xs (return pst1)
252262 PR.Skip n pst1 -> do
253263 assert (n <= length (x:buf)) (return ())
@@ -289,6 +299,11 @@ parse pstep initial extract (Zipper (cp:cps) ls rs stream) =
289299 PR.Yield n pst1 -> do
290300 assert (n <= length (x:buf)) (return ())
291301 go cnt1 r (x:buf) (return pst1)
302+ PR.YieldB n pst1 -> do
303+ assert (n <= length (x:buf)) (return ())
304+ let src0 = Prelude.take n (x:buf)
305+ src = Prelude.reverse src0
306+ gobuf (cnt1 - n) r [] src (return pst1)
292307 PR.Skip 0 pst1 -> go cnt1 r (x:buf) (return pst1)
293308 PR.Skip n pst1 -> do
294309 assert (n <= length (x:buf)) (return ())
@@ -320,6 +335,11 @@ parse pstep initial extract (Zipper (cp:cps) ls rs stream) =
320335 PR.Yield n pst1 -> do
321336 assert (n <= length (x:buf)) (return ())
322337 gobuf cnt1 s (x:buf) xs (return pst1)
338+ PR.YieldB n pst1 -> do
339+ assert (n <= length (x:buf)) (return ())
340+ let src0 = Prelude.take n (x:buf)
341+ src = Prelude.reverse src0
342+ gobuf (cnt1 - n) s [] src (return pst1)
323343 PR.Skip 0 pst1 -> gobuf cnt1 s (x:buf) xs (return pst1)
324344 PR.Skip n pst1 -> do
325345 assert (n <= length (x:buf)) (return ())