on master help sign in
Add YieldB (yield and backtrack) constructor
2c9feb4Harendra Kumar
benchmark/Streamly/Benchmark/Data/Parser.hs+1−3
@@ -207,6 +207,7 @@ o_1_space_serial_parse value =
207 , benchIOSink value "splitWith (all,any)" $ splitWithAllAny value
207 , benchIOSink value "splitWith (all,any)" $ splitWithAllAny value
208 , benchIOSink value "many" many
208 , benchIOSink value "many" many
209 , benchIOSink value "some" some
209 , benchIOSink value "some" some
210+ , benchIOSink value "manyTill" $ manyTill value
210 , benchIOSink value "tee (all,any)" $ teeAllAny value
211 , benchIOSink value "tee (all,any)" $ teeAllAny value
211 , benchIOSink value "teeFst (all,any)" $ teeFstAllAny value
212 , benchIOSink value "teeFst (all,any)" $ teeFstAllAny value
212 , benchIOSink value "shortest (all,any)" $ shortestAllAny value
213 , benchIOSink value "shortest (all,any)" $ shortestAllAny value
@@ -230,9 +231,6 @@ o_n_heap_serial_parse value =
230 -- XXX why O(n)?
231 -- XXX why O(n)?
231 , benchIOSink value "choice" $ choice value
232 , benchIOSink value "choice" $ choice value
232
233
233− -- XXX this should get better with "yield with backtrack" fix
234− , benchIOSink value "manyTill" $ manyTill value
235−
236 -- These show non-linear time complexity.
234 -- These show non-linear time complexity.
237 -- They accumulate the results in a list.
235 -- They accumulate the results in a list.
238 , benchIOSink value "manyAlt" manyAlt
236 , benchIOSink value "manyAlt" manyAlt
benchmark/Streamly/Benchmark/Data/ParserD.hs+1−3
@@ -186,6 +186,7 @@ o_1_space_serial_parse value =
186 , benchIOSink value "split (all,any)" $ splitAllAny value
186 , benchIOSink value "split (all,any)" $ splitAllAny value
187 , benchIOSink value "many" many
187 , benchIOSink value "many" many
188 , benchIOSink value "some" some
188 , benchIOSink value "some" some
189+ , benchIOSink value "manyTill" $ manyTill value
189 , benchIOSink value "tee (all,any)" $ teeAllAny value
190 , benchIOSink value "tee (all,any)" $ teeAllAny value
190 , benchIOSink value "teeFst (all,any)" $ teeFstAllAny value
191 , benchIOSink value "teeFst (all,any)" $ teeFstAllAny value
191 , benchIOSink value "shortest (all,any)" $ shortestAllAny value
192 , benchIOSink value "shortest (all,any)" $ shortestAllAny value
@@ -198,9 +199,6 @@ o_n_heap_serial_parse value =
198 -- lookahead benchmark holds the entire input till end
199 -- lookahead benchmark holds the entire input till end
199 benchIOSink value "lookAhead" $ lookAhead value
200 benchIOSink value "lookAhead" $ lookAhead value
200
201
201− -- XXX this should get better with "yield with backtrack" fix
202− , benchIOSink value "manyTill" $ manyTill value
203−
204 -- These show non-linear time complexity
202 -- These show non-linear time complexity
205 -- They accumulate the results in a list.
203 -- They accumulate the results in a list.
206 , benchIOSink value "manyAlt" manyAlt
204 , benchIOSink value "manyAlt" manyAlt
src/Streamly/Internal/Data/Parser/ParserD.hs+4−3
@@ -587,6 +587,7 @@ lookAhead (Parser step1 initial1 _) =
587 let cnt1 = cnt + 1
587 let cnt1 = cnt + 1
588 return $ case r of
588 return $ case r of
589 Yield _ s -> Skip 0 (Tuple' cnt1 s)
589 Yield _ s -> Skip 0 (Tuple' cnt1 s)
590+ YieldB n s -> Skip n (Tuple' (cnt1 - n) s)
590 Skip n s -> Skip n (Tuple' (cnt1 - n) s)
591 Skip n s -> Skip n (Tuple' (cnt1 - n) s)
591 Stop _ b -> Stop cnt1 b
592 Stop _ b -> Stop cnt1 b
592 Error err -> Error err
593 Error err -> Error err
@@ -710,6 +711,7 @@ manyTill (Fold fstep finitial fextract)
710 r <- stepR st a
711 r <- stepR st a
711 case r of
712 case r of
712 Yield n s -> return $ Yield n (ManyTillR 0 fs s)
713 Yield n s -> return $ Yield n (ManyTillR 0 fs s)
714+ YieldB n s -> return $ YieldB n (ManyTillR 0 fs s)
713 Skip n s -> do
715 Skip n s -> do
714 assert (cnt + 1 - n >= 0) (return ())
716 assert (cnt + 1 - n >= 0) (return ())
715 return $ Skip n (ManyTillR (cnt + 1 - n) fs s)
717 return $ Skip n (ManyTillR (cnt + 1 - n) fs s)
@@ -724,13 +726,12 @@ manyTill (Fold fstep finitial fextract)
724 r <- stepL st a
726 r <- stepL st a
725 case r of
727 case r of
726 Yield n s -> return $ Yield n (ManyTillL fs s)
728 Yield n s -> return $ Yield n (ManyTillL fs s)
729+ YieldB n s -> return $ YieldB n (ManyTillL fs s)
727 Skip n s -> return $ Skip n (ManyTillL fs s)
730 Skip n s -> return $ Skip n (ManyTillL fs s)
728 Stop n b -> do
731 Stop n b -> do
729 fs1 <- fstep fs b
732 fs1 <- fstep fs b
730 l <- initialR
733 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)
734 Error err -> return $ Error err
735 Error err -> return $ Error err
735
736
736 extract (ManyTillL fs sR) = extractL sR >>= fstep fs >>= fextract
737 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
55-- Distribute input to two parsers and collect both results
55-- Distribute input to two parsers and collect both results
56-------------------------------------------------------------------------------
56-------------------------------------------------------------------------------
57
57
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+--
58{-# ANN type StepState Fuse #-}
89{-# ANN type StepState Fuse #-}
59data StepState s a = StepState s | StepResult a
90data StepState s a = StepState s | StepResult a
60
91
61−-- XXX Use a Zipper structure for buffering?
62−--
63-- | State of the pair of parsers in a tee composition
92-- | State of the pair of parsers in a tee composition
64-- Note: strictness annotation is important for fusing the constructors
93-- Note: strictness annotation is important for fusing the constructors
65{-# ANN type TeeState Fuse #-}
94{-# ANN type TeeState Fuse #-}
@@ -70,19 +99,9 @@ data TeeState sL sR x a b =
70{-# ANN type Res Fuse #-}
99{-# ANN type Res Fuse #-}
71data Res = Yld Int | Stp Int | Skp | Err String
100data Res = Yld Int | Stp Int | Skp | Err String
72
101
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−--
83-- | See 'Streamly.Internal.Data.Parser.teeWith'.
102-- | See 'Streamly.Internal.Data.Parser.teeWith'.
84--
103--
85−-- /Internal/
104+-- /Broken/
86--
105--
87{-# INLINE teeWith #-}
106{-# INLINE teeWith #-}
88teeWith :: Monad m
107teeWith :: Monad m
@@ -109,6 +128,10 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
109 let buf1 = x:buf
128 let buf1 = x:buf
110 return (buf1, r, inp11, inp21)
129 return (buf1, r, inp11, inp21)
111
130
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+ --
112 -- consume one input item and return the next state of the fold
135 -- consume one input item and return the next state of the fold
113 {-# INLINE useStream #-}
136 {-# INLINE useStream #-}
114 useStream buf inp1 inp2 stp st y = do
137 useStream buf inp1 inp2 stp st y = do
@@ -117,6 +140,11 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
117 Yield n s ->
140 Yield n s ->
118 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
141 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
119 in assert (n <= length buf1) (return (state, Yld n))
142 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))
120 Stop n b ->
148 Stop n b ->
121 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
149 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
122 in assert (n <= length buf1) (return (state, Stp n))
150 in assert (n <= length buf1) (return (state, Stp n))
@@ -200,7 +228,7 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
200
228
201-- | See 'Streamly.Internal.Data.Parser.teeWithFst'.
229-- | See 'Streamly.Internal.Data.Parser.teeWithFst'.
202--
230--
203−-- /Internal/
231+-- /Broken/
204--
232--
205{-# INLINE teeWithFst #-}
233{-# INLINE teeWithFst #-}
206teeWithFst :: Monad m
234teeWithFst :: Monad m
@@ -236,6 +264,7 @@ teeWithFst zf (Parser stepL initialL extractL)
236 Yield n s ->
264 Yield n s ->
237 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
265 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
238 in assert (n <= length buf1) (return (state, Yld n))
266 in assert (n <= length buf1) (return (state, Yld n))
267+ YieldB _ _ -> undefined
239 Stop n b ->
268 Stop n b ->
240 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
269 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
241 in assert (n <= length buf1) (return (state, Stp n))
270 in assert (n <= length buf1) (return (state, Stp n))
@@ -323,7 +352,7 @@ teeWithMin = undefined
323
352
324-- | See 'Streamly.Internal.Data.Parser.shortest'.
353-- | See 'Streamly.Internal.Data.Parser.shortest'.
325--
354--
326−-- /Internal/
355+-- /Broken/
327--
356--
328{-# INLINE shortest #-}
357{-# INLINE shortest #-}
329shortest :: Monad m => Parser m x a -> Parser m x a -> Parser m x a
358shortest :: 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 _) =
357 Yield n s ->
386 Yield n s ->
358 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
387 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
359 in assert (n <= length buf1) (return (state, Yld n))
388 in assert (n <= length buf1) (return (state, Yld n))
389+ YieldB _ _ -> undefined
360 Stop n b ->
390 Stop n b ->
361 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
391 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
362 in assert (n <= length buf1) (return (state, Stp n))
392 in assert (n <= length buf1) (return (state, Stp n))
@@ -399,7 +429,7 @@ shortest (Parser stepL initialL extractL) (Parser stepR initialR _) =
399
429
400-- | See 'Streamly.Internal.Data.Parser.longest'.
430-- | See 'Streamly.Internal.Data.Parser.longest'.
401--
431--
402−-- /Internal/
432+-- /Broken/
403--
433--
404{-# INLINE longest #-}
434{-# INLINE longest #-}
405longest :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
435longest :: 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) =
433 Yield n s ->
463 Yield n s ->
434 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
464 let state = (Prelude.take n buf1, StepState s, inp11, inp21)
435 in assert (n <= length buf1) (return (state, Yld n))
465 in assert (n <= length buf1) (return (state, Yld n))
466+ YieldB _ _ -> undefined
436 Stop n b ->
467 Stop n b ->
437 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
468 let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
438 in assert (n <= length buf1) (return (state, Stp n))
469 in assert (n <= length buf1) (return (state, Stp n))
src/Streamly/Internal/Data/Parser/ParserD/Types.hs+61−34
@@ -40,9 +40,12 @@
40-- 'Step' functor provides the following commands to the fold driver
40-- 'Step' functor provides the following commands to the fold driver
41-- corresponding to the use cases outlined in the previous para:
41-- corresponding to the use cases outlined in the previous para:
42--
42--
43−-- 1. 'Skip': hold (buffer) the input or go back to a previous position in the stream
43+-- 1. 'Skip': buffer the current input and go back to a previous
44−-- 2. 'Yield', 'Stop': tell how much input is unconsumed
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
45−-- 3. 'Error': indicates that the parser has failed without a result
48+-- 4. 'Error': indicates that the parser has failed without a result
46--
49--
47-- = How a Parser Works?
50-- = How a Parser Works?
48--
51--
@@ -78,7 +81,7 @@
78--
81--
79-- = Error Handling
82-- = Error Handling
80--
83--
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
82-- 'Stop' or an 'Error' return value. In an 'Alternative' composition an error
85-- 'Stop' or an 'Error' return value. In an 'Alternative' composition an error
83-- return can make the composed parser backtrack and try another parser.
86-- return can make the composed parser backtrack and try another parser.
84--
87--
@@ -159,33 +162,47 @@ import Streamly.Internal.Data.Strict (Tuple3'(..))
159{-# ANN type Step Fuse #-}
162{-# ANN type Step Fuse #-}
160data Step s b =
163data Step s b =
161 Yield Int s
164 Yield Int s
165+ -- ^ Trim the backtracking buffer keeping only most recent @n@ items.
162− -- ^ @Yield offset state@ indicates that the parser has yielded a new
166+ -- @Yield n state@ indicates that the parser has yielded a new result
163− -- result which is a point of no return. The result can be extracted
167+ -- which is a point of no return. The result can be extracted using
164− -- using @extract@. The driver drops the buffer except @offset@ elements
168+ -- @extract@. The driver drops the buffer except @n@ most recent
165− -- before the current position in stream. The rule is that if a parser
169+ -- elements. The rule is that if a parser has yielded at least once it
166− -- has yielded at least once it cannot return a failure result.
170+ -- cannot return a failure result.
167−
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
168 | Skip Int s
180 | Skip Int s
181+ -- ^ Go back by @n@ items in the input buffer.
169− -- ^ @Skip offset state@ indicates that the parser has consumed the current
182+ -- @Skip n state@ indicates that the parser has consumed the current input
170− -- input but no new result has been generated. A new @state@ is generated.
183+ -- but no new result has been generated. A new @state@ is generated.
171 -- However, if we use @extract@ on @state@ it will generate a result from
184 -- 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
185+ -- the previous @Yield@. When @n@ is non-zero it is a backward offset from
173− -- from the current position in the stream from which the driver will feed
186+ -- the current position in the stream from which the driver will replay the
174− -- the next input to the parser. The offset cannot be beyond the latest
187+ -- input to the parser. The offset cannot be beyond the latest point of no
175− -- point of no return created by @Yield@.
188+ -- return created by @Yield@.
176
189
177 | Stop Int b
190 | Stop Int b
191+ -- ^ Trim the backtracking buffer keeping only most recent @n@ items.
178− -- ^ @Stop offset result@ asks the driver to stop driving the parser
192+ -- @Stop n result@ asks the driver to stop driving the parser because it
179− -- because it has reached a fixed point and further input will not change
193+ -- has reached a fixed point and further input will not change the result.
180− -- the result. @offset@ is the count of unused elements which includes the
194+ -- @n@ is the count of unused input elements which includes the element on
181− -- element on which 'Stop' occurred.
195+ -- which 'Stop' occurred.
196+
182 | Error String
197 | Error String
198+ -- ^ Go back to the start of the backtracking buffer.
183− -- ^ An error makes the parser backtrack to the last checkpoint and try
199+ -- An error makes the parser backtrack to the last checkpoint and try
184 -- another alternative.
200 -- another alternative.
185
201
186instance Functor (Step s) where
202instance Functor (Step s) where
187 {-# INLINE fmap #-}
203 {-# INLINE fmap #-}
188 fmap _ (Yield n s) = Yield n s
204 fmap _ (Yield n s) = Yield n s
205+ fmap _ (YieldB n s) = YieldB n s
189 fmap _ (Skip n s) = Skip n s
206 fmap _ (Skip n s) = Skip n s
190 fmap f (Stop n b) = Stop n (f b)
207 fmap f (Stop n b) = Stop n (f b)
191 fmap _ (Error err) = Error err
208 fmap _ (Error err) = Error err
@@ -282,9 +299,12 @@ splitWith func (Parser stepL initialL extractL)
282 step (SeqParseL st) a = do
299 step (SeqParseL st) a = do
283 r <- stepL st a
300 r <- stepL st a
284 case r of
301 case r of
285− -- Note: this leads to buffering even if we are not in an
302+ -- Note: We need to buffer the input for a possible Alternative
286− -- Alternative composition.
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.
287 Yield _ s -> return $ Skip 0 (SeqParseL s)
306 Yield _ s -> return $ Skip 0 (SeqParseL s)
307+ YieldB n s -> return $ Skip n (SeqParseL s)
288 Skip n s -> return $ Skip n (SeqParseL s)
308 Skip n s -> return $ Skip n (SeqParseL s)
289 Stop n b -> Skip n <$> (SeqParseR (func b) <$> initialR)
309 Stop n b -> Skip n <$> (SeqParseR (func b) <$> initialR)
290 Error err -> return $ Error err
310 Error err -> return $ Error err
@@ -293,6 +313,7 @@ splitWith func (Parser stepL initialL extractL)
293 r <- stepR st a
313 r <- stepR st a
294 return $ case r of
314 return $ case r of
295 Yield n s -> Yield n (SeqParseR f s)
315 Yield n s -> Yield n (SeqParseR f s)
316+ YieldB n s -> YieldB n (SeqParseR f s)
296 Skip n s -> Skip n (SeqParseR f s)
317 Skip n s -> Skip n (SeqParseR f s)
297 Stop n b -> Stop n (f b)
318 Stop n b -> Stop n (f b)
298 Error err -> Error err
319 Error err -> Error err
@@ -328,6 +349,7 @@ split_ (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
328 -- Note: this leads to buffering even if we are not in an
349 -- Note: this leads to buffering even if we are not in an
329 -- Alternative composition.
350 -- Alternative composition.
330 Yield _ s -> Skip 0 (SeqAL s)
351 Yield _ s -> Skip 0 (SeqAL s)
352+ YieldB n s -> Skip n (SeqAL s)
331 Skip n s -> Skip n (SeqAL s)
353 Skip n s -> Skip n (SeqAL s)
332 Stop n _ -> Skip n (SeqAR i)
354 Stop n _ -> Skip n (SeqAR i)
333 -- XXX should we sequence initialR monadically?
355 -- XXX should we sequence initialR monadically?
@@ -336,6 +358,7 @@ split_ (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
336 step (SeqAR st) a = do
358 step (SeqAR st) a = do
337 (\r -> case r of
359 (\r -> case r of
338 Yield n s -> Yield n (SeqAR s)
360 Yield n s -> Yield n (SeqAR s)
361+ YieldB n s -> YieldB n (SeqAR s)
339 Skip n s -> Skip n (SeqAR s)
362 Skip n s -> Skip n (SeqAR s)
340 Stop n b -> Stop n b
363 Stop n b -> Stop n b
341 Error err -> Error err) <$> stepR st a
364 Error err -> Error err) <$> stepR st a
@@ -390,6 +413,7 @@ alt (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
390 r <- stepL st a
413 r <- stepL st a
391 case r of
414 case r of
392 Yield n s -> return $ Yield n (AltParseL 0 s)
415 Yield n s -> return $ Yield n (AltParseL 0 s)
416+ YieldB n s -> return $ YieldB n (AltParseL 0 s)
393 Skip n s -> do
417 Skip n s -> do
394 assert (cnt + 1 - n >= 0) (return ())
418 assert (cnt + 1 - n >= 0) (return ())
395 return $ Skip n (AltParseL (cnt + 1 - n) s)
419 return $ Skip n (AltParseL (cnt + 1 - n) s)
@@ -402,6 +426,7 @@ alt (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
402 r <- stepR st a
426 r <- stepR st a
403 return $ case r of
427 return $ case r of
404 Yield n s -> Yield n (AltParseR s)
428 Yield n s -> Yield n (AltParseR s)
429+ YieldB n s -> YieldB n (AltParseR s)
405 Skip n s -> Skip n (AltParseR s)
430 Skip n s -> Skip n (AltParseR s)
406 Stop n b -> Stop n b
431 Stop n b -> Stop n b
407 Error err -> Error err
432 Error err -> Error err
@@ -431,14 +456,16 @@ splitMany (Fold fstep finitial fextract) (Parser step1 initial1 extract1) =
431 let cnt1 = cnt + 1
456 let cnt1 = cnt + 1
432 case r of
457 case r of
433 Yield _ s -> return $ Skip 0 (Tuple3' s cnt1 fs)
458 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)
434 Skip n s -> do
462 Skip n s -> do
435 assert (cnt1 - n >= 0) (return ())
463 assert (cnt1 - n >= 0) (return ())
436 return $ Skip n (Tuple3' s (cnt1 - n) fs)
464 return $ Skip n (Tuple3' s (cnt1 - n) fs)
437 Stop n b -> do
465 Stop n b -> do
438 s <- initial1
466 s <- initial1
439 fs1 <- fstep fs b
467 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)
442 Error _ -> do
469 Error _ -> do
443 xs <- fextract fs
470 xs <- fextract fs
444 return $ Stop cnt1 xs
471 return $ Stop cnt1 xs
@@ -471,31 +498,28 @@ splitSome (Fold fstep finitial fextract) (Parser step1 initial1 extract1) =
471 r <- step1 st a
498 r <- step1 st a
472 case r of
499 case r of
473 Yield _ s -> return $ Skip 0 (Tuple3' s undefined (Left fs))
500 Yield _ s -> return $ Skip 0 (Tuple3' s undefined (Left fs))
501+ YieldB n s -> return $ Skip n (Tuple3' s undefined (Left fs))
474 Skip n s -> return $ Skip n (Tuple3' s undefined (Left fs))
502 Skip n s -> return $ Skip n (Tuple3' s undefined (Left fs))
475 Stop n b -> do
503 Stop n b -> do
476 s <- initial1
504 s <- initial1
477 fs1 <- fstep fs b
505 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))
485 Error err -> return $ Error err
507 Error err -> return $ Error err
486 step (Tuple3' st cnt (Right fs)) a = do
508 step (Tuple3' st cnt (Right fs)) a = do
487 r <- step1 st a
509 r <- step1 st a
488 let cnt1 = cnt + 1
510 let cnt1 = cnt + 1
489 case r of
511 case r of
490 Yield _ s -> return $ Yield 0 (Tuple3' s cnt1 (Right fs))
512 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))
491 Skip n s -> do
516 Skip n s -> do
492 assert (cnt1 - n >= 0) (return ())
517 assert (cnt1 - n >= 0) (return ())
493 return $ Skip n (Tuple3' s (cnt1 - n) (Right fs))
518 return $ Skip n (Tuple3' s (cnt1 - n) (Right fs))
494 Stop n b -> do
519 Stop n b -> do
495 s <- initial1
520 s <- initial1
496 fs1 <- fstep fs b
521 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))
499 Error _ -> Stop cnt1 <$> fextract fs
523 Error _ -> Stop cnt1 <$> fextract fs
500
524
501 -- XXX The "try" may impact performance if this parser is used as a scan
525 -- 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
575 r <- stepL st a
599 r <- stepL st a
576 return $ case r of
600 return $ case r of
577 Yield _ s -> Skip 0 (ConcatParseL s)
601 Yield _ s -> Skip 0 (ConcatParseL s)
602+ YieldB n s -> Skip n (ConcatParseL s)
578 Skip n s -> Skip n (ConcatParseL s)
603 Skip n s -> Skip n (ConcatParseL s)
579 Stop n b -> Skip n (ConcatParseR (func b))
604 Stop n b -> Skip n (ConcatParseR (func b))
580 Error err -> Error err
605 Error err -> Error err
@@ -585,6 +610,8 @@ concatMap func (Parser stepL initialL extractL) = Parser step initial extract
585 return $ case r of
610 return $ case r of
586 Yield n s ->
611 Yield n s ->
587 Yield n (ConcatParseR (Parser stepR (return s) extractR))
612 Yield n (ConcatParseR (Parser stepR (return s) extractR))
613+ YieldB n s ->
614+ YieldB n (ConcatParseR (Parser stepR (return s) extractR))
588 Skip n s ->
615 Skip n s ->
589 Skip n (ConcatParseR (Parser stepR (return s) extractR))
616 Skip n (ConcatParseR (Parser stepR (return s) extractR))
590 Stop n b -> Stop n b
617 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
998 PR.Yield n pst1 -> do
998 PR.Yield n pst1 -> do
999 assert (n <= length (x:buf)) (return ())
999 assert (n <= length (x:buf)) (return ())
1000 go SPEC s (Prelude.take n (x:buf)) pst1
1000 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
1001 PR.Skip 0 pst1 -> go SPEC s (x:buf) pst1
1006 PR.Skip 0 pst1 -> go SPEC s (x:buf) pst1
1002 PR.Skip n pst1 -> do
1007 PR.Skip n pst1 -> do
1003 assert (n <= length (x:buf)) (return ())
1008 assert (n <= length (x:buf)) (return ())
@@ -1017,6 +1022,11 @@ parselMx' pstep initial extract (Stream step state) = do
1017 PR.Yield n pst1 -> do
1022 PR.Yield n pst1 -> do
1018 assert (n <= length (x:buf)) (return ())
1023 assert (n <= length (x:buf)) (return ())
1019 gobuf SPEC s (Prelude.take n (x:buf)) xs pst1
1024 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
1020 PR.Skip 0 pst1 -> gobuf SPEC s (x:buf) xs pst1
1030 PR.Skip 0 pst1 -> gobuf SPEC s (x:buf) xs pst1
1021 PR.Skip n pst1 -> do
1031 PR.Skip n pst1 -> do
1022 assert (n <= length (x:buf)) (return ())
1032 assert (n <= length (x:buf)) (return ())
@@ -1073,6 +1083,11 @@ parseMany (PRD.Parser pstep initial extract) (Stream step state) =
1073 assert (n <= length (x:buf)) (return ())
1083 assert (n <= length (x:buf)) (return ())
1074 let buf1 = Prelude.take n (x:buf)
1084 let buf1 = Prelude.take n (x:buf)
1075 return $ Skip $ ParseChunksStream s buf1 pst1
1085 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
1076 -- PR.Skip 0 pst1 ->
1091 -- PR.Skip 0 pst1 ->
1077 -- return $ Skip $ ParseChunksStream s (x:buf) pst1
1092 -- return $ Skip $ ParseChunksStream s (x:buf) pst1
1078 PR.Skip n pst1 -> do
1093 PR.Skip n pst1 -> do
@@ -1107,6 +1122,11 @@ parseMany (PRD.Parser pstep initial extract) (Stream step state) =
1107 assert (n <= length (x:buf)) (return ())
1122 assert (n <= length (x:buf)) (return ())
1108 let buf1 = Prelude.take n (x:buf)
1123 let buf1 = Prelude.take n (x:buf)
1109 return $ Skip $ ParseChunksBuf xs s buf1 pst1
1124 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
1110 -- PR.Skip 0 pst1 -> return $ Skip $ ParseChunksBuf xs s (x:buf) pst1
1130 -- PR.Skip 0 pst1 -> return $ Skip $ ParseChunksBuf xs s (x:buf) pst1
1111 PR.Skip n pst1 -> do
1131 PR.Skip n pst1 -> do
1112 assert (n <= length (x:buf)) (return ())
1132 assert (n <= length (x:buf)) (return ())
@@ -1172,6 +1192,12 @@ parseIterate func seed (Stream step state) =
1172 let buf1 = Prelude.take n (x:buf)
1192 let buf1 = Prelude.take n (x:buf)
1173 return $ Skip $ ConcatParseStream s buf1
1193 return $ Skip $ ConcatParseStream s buf1
1174 (PRD.Parser pstep (return pst1) extract)
1194 (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)
1175 -- PR.Skip 0 pst1 ->
1201 -- PR.Skip 0 pst1 ->
1176 -- return $ Skip $ ConcatParseStream s (x:buf) pst1
1202 -- return $ Skip $ ConcatParseStream s (x:buf) pst1
1177 PR.Skip n pst1 -> do
1203 PR.Skip n pst1 -> do
@@ -1211,6 +1237,12 @@ parseIterate func seed (Stream step state) =
1211 let buf1 = Prelude.take n (x:buf)
1237 let buf1 = Prelude.take n (x:buf)
1212 return $ Skip $ ConcatParseBuf xs s buf1
1238 return $ Skip $ ConcatParseBuf xs s buf1
1213 (PRD.Parser pstep (return pst1) extract)
1239 (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)
1214 -- PR.Skip 0 pst1 -> return $ Skip $ ConcatParseBuf xs s (x:buf) pst1
1246 -- PR.Skip 0 pst1 -> return $ Skip $ ConcatParseBuf xs s (x:buf) pst1
1215 PR.Skip n pst1 -> do
1247 PR.Skip n pst1 -> do
1216 assert (n <= length (x:buf)) (return ())
1248 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) =
224 PR.Yield n pst1 -> do
224 PR.Yield n pst1 -> do
225 assert (n <= length (x:buf)) (return ())
225 assert (n <= length (x:buf)) (return ())
226 go r (Prelude.take n (x:buf)) (return pst1)
226 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)
227 PR.Skip 0 pst1 -> go r (x:buf) (return pst1)
232 PR.Skip 0 pst1 -> go r (x:buf) (return pst1)
228 PR.Skip n pst1 -> do
233 PR.Skip n pst1 -> do
229 assert (n <= length (x:buf)) (return ())
234 assert (n <= length (x:buf)) (return ())
@@ -248,6 +253,11 @@ parse pstep initial extract (Zipper [] ls rs stream) =
248 PR.Yield n pst1 -> do
253 PR.Yield n pst1 -> do
249 assert (n <= length (x:buf)) (return ())
254 assert (n <= length (x:buf)) (return ())
250 gobuf s (Prelude.take n (x:buf)) xs (return pst1)
255 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)
251 PR.Skip 0 pst1 -> gobuf s (x:buf) xs (return pst1)
261 PR.Skip 0 pst1 -> gobuf s (x:buf) xs (return pst1)
252 PR.Skip n pst1 -> do
262 PR.Skip n pst1 -> do
253 assert (n <= length (x:buf)) (return ())
263 assert (n <= length (x:buf)) (return ())
@@ -289,6 +299,11 @@ parse pstep initial extract (Zipper (cp:cps) ls rs stream) =
289 PR.Yield n pst1 -> do
299 PR.Yield n pst1 -> do
290 assert (n <= length (x:buf)) (return ())
300 assert (n <= length (x:buf)) (return ())
291 go cnt1 r (x:buf) (return pst1)
301 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)
292 PR.Skip 0 pst1 -> go cnt1 r (x:buf) (return pst1)
307 PR.Skip 0 pst1 -> go cnt1 r (x:buf) (return pst1)
293 PR.Skip n pst1 -> do
308 PR.Skip n pst1 -> do
294 assert (n <= length (x:buf)) (return ())
309 assert (n <= length (x:buf)) (return ())
@@ -320,6 +335,11 @@ parse pstep initial extract (Zipper (cp:cps) ls rs stream) =
320 PR.Yield n pst1 -> do
335 PR.Yield n pst1 -> do
321 assert (n <= length (x:buf)) (return ())
336 assert (n <= length (x:buf)) (return ())
322 gobuf cnt1 s (x:buf) xs (return pst1)
337 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)
323 PR.Skip 0 pst1 -> gobuf cnt1 s (x:buf) xs (return pst1)
343 PR.Skip 0 pst1 -> gobuf cnt1 s (x:buf) xs (return pst1)
324 PR.Skip n pst1 -> do
344 PR.Skip n pst1 -> do
325 assert (n <= length (x:buf)) (return ())
345 assert (n <= length (x:buf)) (return ())