@@ -1,4 +1,5 @@
1−{-# LANGUAGE CPP #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3-- Somehow uni-pattern match using "let" produces better optimized code
4-- Somehow uni-pattern match using "let" produces better optimized code
4-- compared to using cases and using explicit "error" messages in unreachable
5-- compared to using cases and using explicit "error" messages in unreachable
@@ -25,37 +26,52 @@
26module Streamly.Internal.Data.Parser.Tee
27module Streamly.Internal.Data.Parser.Tee
28− -- Parallel parsers
29+ -- Parallel zipped
30 , teeWithFst
31 , teeWithFst
31 , teeWithMin
32 , teeWithMin
34+ -- Parallel alternatives
35import Control.Exception (assert)
40import Control.Exception (assert)
41+import Control.Monad.Catch (MonadCatch, try)
36import Prelude
42import Prelude
37 hiding (any, all, takeWhile)
43 hiding (any, all, takeWhile)
39import Fusion.Plugin.Types (Fuse(..))
45import Fusion.Plugin.Types (Fuse(..))
40−import Streamly.Internal.Data.Parser.Types (Parser(..), Step(..))
46+import Streamly.Internal.Data.Parser.Types (Parser(..), Step(..), ParseError)
42-------------------------------------------------------------------------------
48-------------------------------------------------------------------------------
43−-- Distributing Parsers
49+-- Distribute input to two parsers and collect both results
44-------------------------------------------------------------------------------
50-------------------------------------------------------------------------------
46data StepState s a = StepState s | StepResult a
52data StepState s a = StepState s | StepResult a
54+-- XXX Use a Zipper structure for buffering?
48-- | State of the pair of parsers in a tee composition
56-- | State of the pair of parsers in a tee composition
49-- Note: strictness annotation is important for fusing the constructors
57-- Note: strictness annotation is important for fusing the constructors
50{-# ANN type TeeState Fuse #-}
58{-# ANN type TeeState Fuse #-}
51data TeeState sL sR x a b =
59data TeeState sL sR x a b =
60+-- @TeePair (past buffer, parser state, future-buffer1, future-buffer2) ...@
52 TeePair !([x], StepState sL a, [x], [x]) !([x], StepState sR b, [x], [x])
61 TeePair !([x], StepState sL a, [x], [x]) !([x], StepState sR b, [x], [x])
54−data Res = Yld Int | Stp Int | Skp
63+data Res = Yld Int | Stp Int | Skp | Err String
56-- XXX: With the current "Step" semantics, it is hard to write, and not sure
65-- XXX: With the current "Step" semantics, it is hard to write, and not sure
57-- how useful, an efficient teeWith that returns a correct unused input count.
66-- how useful, an efficient teeWith that returns a correct unused input count.
68+-- XXX Teeing a parser with a Fold could be more useful and simpler to
69+-- implement. A fold never fails or backtracks so we do not need to buffer the
70+-- input for the fold. It can be useful in, for example, maintaining the line
71+-- and column number position to report for errors. We can always have the
72+-- line/column fold running in parallel with the main parser, whenever an error
73+-- occurs we can zip the error with the context fold.
59-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
75-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
60-- of them succeed or fail and combines their output using @f@. The parser
76-- of them succeed or fail and combines their output using @f@. The parser
61-- succeeds if both the parsers succeed.
77-- succeeds if both the parsers succeed.
@@ -104,6 +120,7 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
104 src = Prelude.reverse src0
120 src = Prelude.reverse src0
105 state = (buf2, StepState s, src ++ inp11, inp21)
121 state = (buf2, StepState s, src ++ inp11, inp21)
106 in assert (n <= length buf1) (return (state, Skp))
122 in assert (n <= length buf1) (return (state, Skp))
123+ Error err -> return (undefined, Err err)
108 {-# INLINE_LATE step #-}
125 {-# INLINE_LATE step #-}
109 step (TeePair (bufL, StepState sL, inpL1, inpL2)
126 step (TeePair (bufL, StepState sL, inpL1, inpL2)
@@ -121,6 +138,8 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
121 let (_, StepResult rL, _, _) = l
138 let (_, StepResult rL, _, _) = l
122 (_, StepResult rR, _, _) = r
139 (_, StepResult rR, _, _) = r
123 in Stop (min n1 n2) (zf rL rR)
140 in Stop (min n1 n2) (zf rL rR)
141+ (Err err, _) -> Error err
142+ (_, Err err) -> Error err
124 _ -> Skip 0 next
143 _ -> Skip 0 next
126 step (TeePair (bufL, StepState sL, inpL1, inpL2)
145 step (TeePair (bufL, StepState sL, inpL1, inpL2)
@@ -137,6 +156,7 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
137 let (_, StepResult rL, _, _) = l
156 let (_, StepResult rL, _, _) = l
138 in Stop n (zf rL rR)
157 in Stop n (zf rL rR)
139 Skp -> Skip 0 next
158 Skp -> Skip 0 next
159+ Err err -> Error err
141 step (TeePair l@(_, StepResult rL, _, _)
161 step (TeePair l@(_, StepResult rL, _, _)
142 (bufR, StepState sR, inpR1, inpR2)) x = do
162 (bufR, StepState sR, inpR1, inpR2)) x = do
@@ -152,28 +172,25 @@ teeWith zf (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
152 let (_, StepResult rR, _, _) = r
172 let (_, StepResult rR, _, _) = r
153 in Stop n (zf rL rR)
173 in Stop n (zf rL rR)
154 Skp -> Skip 0 next
174 Skp -> Skip 0 next
175+ Err err -> Error err
156 step _ _ = undefined
177 step _ _ = undefined
158− {-# INLINE extractBoth #-}
159− extractBoth sL sR = do
164 {-# INLINE_LATE extract #-}
179 {-# INLINE_LATE extract #-}
165 extract st =
180 extract st =
166 case st of
181 case st of
167− TeePair (_, StepState sL, _, _) (_, StepState sR, _, _) ->
182+ TeePair (_, StepState sL, _, _) (_, StepState sR, _, _) -> do
168− extractBoth sL sR
183+ rL <- extractL sL
169− TeePair (_, StepState sL, _, _) (_, StepResult rR, _, _) -> do
186+ TeePair (_, StepState sL, _, _) (_, StepResult rR, _, _) -> do
170− rL <- extractL sL
187+ rL <- extractL sL
171− return $ zf rL rR
188+ return $ zf rL rR
172− TeePair (_, StepResult rL, _, _) (_, StepState sR, _, _) -> do
189+ TeePair (_, StepResult rL, _, _) (_, StepState sR, _, _) -> do
173− rR <- extractR sR
190+ rR <- extractR sR
174− return $ zf rL rR
191+ return $ zf rL rR
175− TeePair (_, StepResult rL, _, _) (_, StepResult rR, _, _) ->
192+ TeePair (_, StepResult rL, _, _) (_, StepResult rR, _, _) ->
176− return $ zf rL rR
193+ return $ zf rL rR
178-- | Like 'teeWith' but ends parsing and zips the results, if available,
195-- | Like 'teeWith' but ends parsing and zips the results, if available,
179-- whenever the first parser ends.
196-- whenever the first parser ends.
@@ -223,6 +240,7 @@ teeWithFst zf (Parser stepL initialL extractL)
223 src = Prelude.reverse src0
240 src = Prelude.reverse src0
224 state = (buf2, StepState s, src ++ inp11, inp21)
241 state = (buf2, StepState s, src ++ inp11, inp21)
225 in assert (n <= length buf1) (return (state, Skp))
242 in assert (n <= length buf1) (return (state, Skp))
243+ Error err -> return (undefined, Err err)
227 {-# INLINE_LATE step #-}
245 {-# INLINE_LATE step #-}
228 step (TeePair (bufL, StepState sL, inpL1, inpL2)
246 step (TeePair (bufL, StepState sL, inpL1, inpL2)
@@ -250,6 +268,8 @@ teeWithFst zf (Parser stepL initialL extractL)
250 return $ Stop n1 (zf rL rR)
268 return $ Stop n1 (zf rL rR)
251 (Yld n1, Yld n2) -> return $ Yield (min n1 n2) next
269 (Yld n1, Yld n2) -> return $ Yield (min n1 n2) next
252 (Yld n1, Stp n2) -> return $ Yield (min n1 n2) next
270 (Yld n1, Stp n2) -> return $ Yield (min n1 n2) next
271+ (Err err, _) -> return $ Error err
272+ (_, Err err) -> return $ Error err
253 _ -> return $ Skip 0 next
273 _ -> return $ Skip 0 next
255 step (TeePair (bufL, StepState sL, inpL1, inpL2)
275 step (TeePair (bufL, StepState sL, inpL1, inpL2)
@@ -266,24 +286,21 @@ teeWithFst zf (Parser stepL initialL extractL)
266 let (_, StepResult rL, _, _) = l
286 let (_, StepResult rL, _, _) = l
267 in Stop n (zf rL rR)
287 in Stop n (zf rL rR)
268 Skp -> Skip 0 next
288 Skp -> Skip 0 next
289+ Err err -> Error err
270 step _ _ = undefined
291 step _ _ = undefined
272− {-# INLINE extractBoth #-}
273− extractBoth sL sR = do
278 {-# INLINE_LATE extract #-}
293 {-# INLINE_LATE extract #-}
279 extract st =
294 extract st =
280 case st of
295 case st of
281− TeePair (_, StepState sL, _, _) (_, StepState sR, _, _) ->
296+ TeePair (_, StepState sL, _, _) (_, StepState sR, _, _) -> do
282− extractBoth sL sR
297+ rL <- extractL sL
283− TeePair (_, StepState sL, _, _) (_, StepResult rR, _, _) -> do
300+ TeePair (_, StepState sL, _, _) (_, StepResult rR, _, _) -> do
284− rL <- extractL sL
301+ rL <- extractL sL
285− return $ zf rL rR
302+ return $ zf rL rR
286− _ -> error "unreachable"
303+ _ -> error "unreachable"
288-- | Like 'teeWith' but ends parsing and zips the results, if available,
305-- | Like 'teeWith' but ends parsing and zips the results, if available,
289-- whenever any of the parsers ends or fails.
306-- whenever any of the parsers ends or fails.
@@ -295,3 +312,211 @@ teeWithMin ::
295 -- Monad m =>
312 -- Monad m =>
296 (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
313 (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
297teeWithMin = undefined
314teeWithMin = undefined
316+-------------------------------------------------------------------------------
317+-- Distribute input to two parsers and choose one result
318+-------------------------------------------------------------------------------
320+-- | Shortest alternative. Apply both parsers in parallel but choose the result
321+-- from the one which consumed least input i.e. take the shortest succeeding
326+{-# INLINE shortest #-}
327+shortest :: Monad m => Parser m x a -> Parser m x a -> Parser m x a
328+shortest (Parser stepL initialL extractL) (Parser stepR initialR _) =
329+ Parser step initial extract
333+ {-# INLINE_LATE initial #-}
337+ return $ TeePair ([], StepState sL, [], []) ([], StepState sR, [], [])
339+ {-# INLINE consume #-}
340+ consume buf inp1 inp2 stp st y = do
341+ let (x, inp11, inp21) =
344+ z : [] -> (z, reverse (x:inp2), [])
345+ z : zs -> (z, zs, x:inp2)
348+ return (buf1, r, inp11, inp21)
350+ -- consume one input item and return the next state of the fold
351+ {-# INLINE useStream #-}
352+ useStream buf inp1 inp2 stp st y = do
353+ (buf1, r, inp11, inp21) <- consume buf inp1 inp2 stp st y
356+ let state = (Prelude.take n buf1, StepState s, inp11, inp21)
357+ in assert (n <= length buf1) (return (state, Yld n))
359+ let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
360+ in assert (n <= length buf1) (return (state, Stp n))
361+ -- Skip 0 s -> (buf1, Right s, inp11, inp21)
363+ let (src0, buf2) = splitAt n buf1
364+ src = Prelude.reverse src0
365+ state = (buf2, StepState s, src ++ inp11, inp21)
366+ in assert (n <= length buf1) (return (state, Skp))
367+ Error err -> return (undefined, Err err)
369+ -- XXX Even if a parse finished earlier it may not be shortest if the other
370+ -- parser finishes later but returns a lot of unconsumed input. Our current
371+ -- criterion of shortest is whichever parse decided to stop earlier.
372+ {-# INLINE_LATE step #-}
373+ step (TeePair (bufL, StepState sL, inpL1, inpL2)
374+ (bufR, StepState sR, inpR1, inpR2)) x = do
375+ (l,stL) <- useStream bufL inpL1 inpL2 stepL sL x
376+ (r,stR) <- useStream bufR inpR1 inpR2 stepR sR x
377+ let next = TeePair l r
378+ return $ case (stL,stR) of
380+ let (_, StepResult rL, _, _) = l
383+ let (_, StepResult rR, _, _) = r
385+ (Yld n1, Yld n2) -> Yield (min n1 n2) next
386+ (Err err, _) -> Error err
387+ (_, Err err) -> Error err
390+ step _ _ = undefined
392+ {-# INLINE_LATE extract #-}
395+ TeePair (_, StepState sL, _, _) _ -> extractL sL
396+ _ -> error "unreachable"
398+-- | Longest alternative. Apply both parsers in parallel but choose the result
399+-- from the one which consumed more input i.e. take the longest succeeding
404+{-# INLINE longest #-}
405+longest :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
406+longest (Parser stepL initialL extractL) (Parser stepR initialR extractR) =
407+ Parser step initial extract
411+ {-# INLINE_LATE initial #-}
415+ return $ TeePair ([], StepState sL, [], []) ([], StepState sR, [], [])
417+ {-# INLINE consume #-}
418+ consume buf inp1 inp2 stp st y = do
419+ let (x, inp11, inp21) =
422+ z : [] -> (z, reverse (x:inp2), [])
423+ z : zs -> (z, zs, x:inp2)
426+ return (buf1, r, inp11, inp21)
428+ -- consume one input item and return the next state of the fold
429+ {-# INLINE useStream #-}
430+ useStream buf inp1 inp2 stp st y = do
431+ (buf1, r, inp11, inp21) <- consume buf inp1 inp2 stp st y
434+ let state = (Prelude.take n buf1, StepState s, inp11, inp21)
435+ in assert (n <= length buf1) (return (state, Yld n))
437+ let state = (Prelude.take n buf1, StepResult b, inp11, inp21)
438+ in assert (n <= length buf1) (return (state, Stp n))
439+ -- Skip 0 s -> (buf1, Right s, inp11, inp21)
441+ let (src0, buf2) = splitAt n buf1
442+ src = Prelude.reverse src0
443+ state = (buf2, StepState s, src ++ inp11, inp21)
444+ in assert (n <= length buf1) (return (state, Skp))
445+ Error err -> return (undefined, Err err)
447+ {-# INLINE_LATE step #-}
448+ step (TeePair (bufL, StepState sL, inpL1, inpL2)
449+ (bufR, StepState sR, inpR1, inpR2)) x = do
450+ (l,stL) <- useStream bufL inpL1 inpL2 stepL sL x
451+ (r,stR) <- useStream bufR inpR1 inpR2 stepR sR x
452+ let next = TeePair l r
453+ return $ case (stL,stR) of
454+ (Yld n1, Yld n2) -> Yield (min n1 n2) next
455+ (Yld n1, Stp n2) -> Yield (min n1 n2) next
456+ (Stp n1, Yld n2) -> Yield (min n1 n2) next
458+ let (_, StepResult rL, _, _) = l
459+ (_, StepResult rR, _, _) = r
460+ in Stop (max n1 n2) (if n1 >= n2 then rL else rR)
461+ (Err err, _) -> Error err
462+ (_, Err err) -> Error err
465+ -- XXX the parser that finishes last may not be the longest because it may
466+ -- return a lot of unused input which makes it shorter. Our current
467+ -- criterion of deciding longest is based on whoever decides to finish
468+ -- last and not whoever consumed more input.
470+ -- To actually know who made more progress we need to keep an account of
471+ -- how many items are unconsumed since the last yield.
473+ step (TeePair (bufL, StepState sL, inpL1, inpL2)
474+ r@(_, StepResult _, _, _)) x = do
475+ (l,stL) <- useStream bufL inpL1 inpL2 stepL sL x
476+ let next = TeePair l r
477+ return $ case stL of
478+ Yld n -> Yield n next
480+ let (_, StepResult rL, _, _) = l
483+ Err err -> Error err
485+ step (TeePair l@(_, StepResult _, _, _)
486+ (bufR, StepState sR, inpR1, inpR2)) x = do
487+ (r, stR) <- useStream bufR inpR1 inpR2 stepR sR x
488+ let next = TeePair l r
489+ return $ case stR of
490+ Yld n -> Yield n next
492+ let (_, StepResult rR, _, _) = r
495+ Err err -> Error err
497+ step _ _ = undefined
499+ {-# INLINE_LATE extract #-}
501+ -- XXX When results are partial we may not be able to precisely compare
502+ -- which parser has made more progress till now. One way to do that is
503+ -- to figure out the actually consumed input up to the last yield.
506+ TeePair (_, StepState sL, _, _) (_, StepState sR, _, _) -> do
507+ r <- try $ extractL sL
509+ Left (_ :: ParseError) -> extractR sR
511+ TeePair (_, StepState sL, _, _) (_, StepResult rR, _, _) -> do
512+ r <- try $ extractL sL
514+ Left (_ :: ParseError) -> return rR
516+ TeePair (_, StepResult rL, _, _) (_, StepState sR, _, _) -> do
517+ r <- try $ extractR sR
519+ Left (_ :: ParseError) -> return rL
521+ TeePair (_, StepResult _, _, _) (_, StepResult _, _, _) ->