1{-# OPTIONS_GHC -Wno-orphans #-}
4-- Module : Streamly.Internal.Data.Parser
5-- Copyright : (c) 2020 Composewell Technologies
6-- License : BSD-3-Clause
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
11-- Fast backtracking parsers with stream fusion and native streaming
14-- 'Applicative' and 'Control.Applicative.Alternative' type class based
15-- combinators from the
16-- <http://hackage.haskell.org/package/parser-combinators parser-combinators>
17-- package can also be used with the 'Parser' type. However, there are two
18-- important differences between @parser-combinators@ and the equivalent ones
19-- provided in this module in terms of performance:
21-- 1) @parser-combinators@ use plain Haskell lists to collect the results, in a
22-- strict Monad like IO, the results are necessarily buffered before they can
23-- be consumed. This may not perform optimally in streaming applications
24-- processing large amounts of data. Equivalent combinators in this module can
25-- consume the results of parsing using a 'Fold', thus providing a scalability
26-- and a composable consumer.
28-- 2) Several combinators in this module can be many times faster because of
29-- stream fusion. For example, 'Streamly.Internal.Data.Parser.many' combinator
30-- in this module is much faster than the 'Control.Applicative.many' combinator
31-- of 'Control.Applicative.Alternative' type class.
35-- Failing parsers in this module throw the 'D.ParseError' exception.
39-- As far as possible, try that the names of the combinators in this module are
42-- * <https://hackage.haskell.org/package/base/docs/Text-ParserCombinators-ReadP.html base/Text.ParserCombinators.ReadP>
43-- * <http://hackage.haskell.org/package/parser-combinators parser-combinators>
44-- * <http://hackage.haskell.org/package/megaparsec megaparsec>
45-- * <http://hackage.haskell.org/package/attoparsec attoparsec>
46-- * <http://hackage.haskell.org/package/parsec parsec>
48module Streamly.Internal.Data.Parser
54 -- First order parsers
71 -- | Parsers chained in series, if one parser terminates the composition
74 -- | Grab a sequence of input elements without inspecting them
76 -- , take -- takeBetween 0 n
77 , takeEQ -- takeBetween n n
78 , takeGE -- takeBetween n maxBound
80 -- Grab a sequence of input elements by inspecting them
99 -- , prefixOf -- match any prefix of a given string
100 -- , suffixOf -- match any suffix of a given string
101 -- , infixOf -- match any substring of a given string
104 -- Second order parsers (parsers using parsers)
105 -- * Binary Combinators
107 -- ** Sequential Applicative
111 -- ** Parallel Applicatives
115 -- , teeTill -- like manyTill but parallel
117 -- ** Sequential Interleaving
118 -- Use two folds, run a primary parser, its rejected values go to the
122 -- ** Sequential Alternative
125 -- ** Parallel Alternatives
130 -- * N-ary Combinators
131 -- ** Sequential Collection
135 -- ** Sequential Repetition
147 -- | TODO: traditional implmentations of these may be of limited use. For
148 -- example, consider parsing lines separated by @\\r\\n@. The main parser
149 -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
150 -- can apply the "sep" parser.
152 -- We can instead implement these as special cases of deintercalate.
165 -- | A simple and stupid impl would be to just convert the stream to an
166 -- array and give the array reference to all consumers. The array can be
167 -- grown on demand by any consumer and truncated when nonbody needs it.
169 -- ** Distribute to collection
170 -- ** Distribute to repetition
172 -- ** Interleaved collection
179 -- ** Collection of Alternatives
185 -- , fastestN -- first N successful in time
186 -- , choiceN -- first N successful in position
188 , choice -- first successful in position
190 -- ** Repeated Alternatives
197import Control.Monad.Catch (MonadCatch)
199 hiding (any, all, take, takeWhile, sequence, concatMap, maybe, either)
201import Streamly.Internal.Data.Fold.Types (Fold(..))
202import Streamly.Internal.Data.Parser.ParserK.Types (Parser)
204import qualified Streamly.Internal.Data.Fold as FL
205import qualified Streamly.Internal.Data.Parser.ParserD as D
206import qualified Streamly.Internal.Data.Parser.ParserK.Types as K
208-------------------------------------------------------------------------------
209-- Upgrade folds to parses
210-------------------------------------------------------------------------------
212-- | Make a 'Parser' from a 'Fold'.
216{-# INLINE fromFold #-}
217fromFold :: MonadCatch m => Fold m a b -> Parser m a b
218fromFold = K.toParserK . D.fromFold
220-------------------------------------------------------------------------------
221-- Terminating but not failing folds
222-------------------------------------------------------------------------------
224-- This is the dual of stream "yield".
226-- | A parser that always yields a pure value without consuming any input.
230{-# INLINE [3] yield #-}
231yield :: MonadCatch m => b -> Parser m a b
232yield = K.toParserK . D.yield
233{-# RULES "yield fallback to CPS" [2]
234 forall a. K.toParserK (D.yield a) = K.yield a #-}
236-- This is the dual of stream "yieldM".
238-- | A parser that always yields the result of an effectful action without
239-- consuming any input.
244yieldM :: MonadCatch m => m b -> Parser m a b
245yieldM = K.yieldM -- K.toParserK . D.yieldM
247-- This is the dual of "nil".
249-- | A parser that always fails with an error message without consuming
254{-# INLINE [3] die #-}
255die :: MonadCatch m => String -> Parser m a b
256die = K.toParserK . D.die
257{-# RULES "die fallback to CPS" [2]
258 forall a. K.toParserK (D.die a) = K.die a #-}
260-- This is the dual of "nilM".
262-- | A parser that always fails with an effectful error message and without
263-- consuming any input.
268dieM :: MonadCatch m => m String -> Parser m a b
269dieM = K.toParserK . D.dieM
271-------------------------------------------------------------------------------
273-------------------------------------------------------------------------------
275-- | Peek the head element of a stream, without consuming it. Fails if it
276-- encounters end of input.
278-- >>> S.parse ((,) <$> PR.peek <*> PR.satisfy (> 0)) $ S.fromList [1]
282-- peek = lookAhead (satisfy True)
288peek :: MonadCatch m => Parser m a a
289peek = K.toParserK D.peek
291-- | Succeeds if we are at the end of input, fails otherwise.
293-- >>> S.parse ((,) <$> PR.satisfy (> 0) <*> PR.eof) $ S.fromList [1]
299eof :: MonadCatch m => Parser m a ()
300eof = K.toParserK D.eof
302-- | Returns the next element if it passes the predicate, fails otherwise.
304-- >>> S.parse (PR.satisfy (== 1)) $ S.fromList [1,0,1]
309{-# INLINE satisfy #-}
310satisfy :: MonadCatch m => (a -> Bool) -> Parser m a a
311satisfy = K.toParserK . D.satisfy
313-- | Map a 'Maybe' returning function on the next element in the stream. The
314-- parser fails if the function returns 'Nothing' otherwise returns the 'Just'
320maybe :: MonadCatch m => (a -> Maybe b) -> Parser m a b
321maybe = K.toParserK . D.maybe
323-- | Map an 'Either' returning function on the next element in the stream. If
324-- the function returns 'Left err', the parser fails with the error message
325-- @err@ otherwise returns the 'Right' value.
330either :: MonadCatch m => (a -> Either String b) -> Parser m a b
331either = K.toParserK . D.either
333-------------------------------------------------------------------------------
335-------------------------------------------------------------------------------
337-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
338-- elements and folds them using the supplied fold.
340-- Stops after @n@ elements.
341-- Fails if the stream ends before @m@ elements could be taken.
346-- takeBetween' low high ls = S.parse prsr (S.fromList ls)
347-- where prsr = P.takeBetween low high FL.toList
350-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
353-- >>> takeBetween' 2 4 [1, 2]
356-- >>> takeBetween' 2 4 [1]
357-- > ParseError "takeBetween: Expecting alteast 2 elements, got 1"
359-- >>> takeBetween' 0 0 [1, 2]
362-- >>> takeBetween' 0 1 []
365-- @takeBetween@ is the most general take operation, other take operations can
366-- be defined in terms of takeBetween. For example:
369-- take = takeBetween 0 n -- equivalent of takeLE
370-- take1 = takeBetween 1 n -- equivalent of takeLE1
371-- takeEQ = takeBetween n n
372-- takeGE = takeBetween n maxBound
377{-# INLINE takeBetween #-}
378takeBetween :: MonadCatch m =>
379 Int -> Int -> Fold m a b -> Parser m a b
380takeBetween m n = K.toParserK . D.takeBetween m n
382-- | Stops after taking exactly @n@ input elements.
384-- * Stops - after consuming @n@ elements.
385-- * Fails - if the stream or the collecting fold ends before it can collect
386-- exactly @n@ elements.
388-- >>> S.parse (PR.takeEQ 4 FL.toList) $ S.fromList [1,0,1]
389-- > "takeEQ: Expecting exactly 4 elements, got 3"
394takeEQ :: MonadCatch m => Int -> Fold m a b -> Parser m a b
395takeEQ n = K.toParserK . D.takeEQ n
397-- | Take at least @n@ input elements, but can collect more.
399-- * Stops - when the collecting fold stops.
400-- * Fails - if the stream or the collecting fold ends before producing @n@
403-- >>> S.parse (PR.takeGE 4 FL.toList) $ S.fromList [1,0,1]
404-- > "takeGE: Expecting at least 4 elements, got only 3"
406-- >>> S.parse (PR.takeGE 4 FL.toList) $ S.fromList [1,0,1,0,1]
412takeGE :: MonadCatch m => Int -> Fold m a b -> Parser m a b
413takeGE n = K.toParserK . D.takeGE n
416-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
418-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
419-- input. The combinator stops when the condition fails or if the collecting
422-- This is a generalized version of takeWhile, for example 'takeWhile1' can be
423-- implemented in terms of this:
426-- takeWhile1 cond p = takeWhile cond (takeBetween 1 maxBound p)
429-- Stops: when the condition fails or the collecting parser stops.
430-- Fails: when the collecting parser fails.
434{-# INLINE takeWhileP #-}
435takeWhileP :: -- MonadCatch m =>
436 (a -> Bool) -> Parser m a b -> Parser m a b
437takeWhileP _cond = undefined -- K.toParserK . D.takeWhileP cond
439-- | Collect stream elements until an element fails the predicate. The element
440-- on which the predicate fails is returned back to the input stream.
442-- * Stops - when the predicate fails or the collecting fold stops.
445-- >>> S.parse (PR.takeWhile (== 0) FL.toList) $ S.fromList [0,0,1,0,1]
448-- We can implement a @breakOn@ using 'takeWhile':
451-- breakOn p = takeWhile (not p)
456{-# INLINE takeWhile #-}
457takeWhile :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
458takeWhile cond = K.toParserK . D.takeWhile cond
460-- | Like 'takeWhile' but takes at least one element otherwise fails.
464{-# INLINE takeWhile1 #-}
465takeWhile1 :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
466takeWhile1 cond = K.toParserK . D.takeWhile1 cond
468-- | Drain the input as long as the predicate succeeds, running the effects and
469-- discarding the results.
471-- This is also called @skipWhile@ in some parsing libraries.
475{-# INLINE drainWhile #-}
476drainWhile :: MonadCatch m => (a -> Bool) -> Parser m a ()
477drainWhile p = takeWhile p FL.drain
479-- | @sliceSepBy cond parser@ parses a slice of the input using @parser@ until
480-- @cond@ succeeds or the parser stops.
482-- This is a generalized slicing parser which can be used to implement other
486-- sliceSepByMax cond n p = sliceBy cond (take n p)
487-- sliceSepByBetween cond m n p = sliceBy cond (takeBetween m n p)
492{-# INLINABLE sliceSepBy #-}
493sliceSepBy :: -- MonadCatch m =>
494 (a -> Bool) -> Parser m a b -> Parser m a b
495sliceSepBy _cond = undefined -- K.toParserK . D.sliceSepBy cond
497-- | Like 'sliceSepBy' but does not drop the separator element, instead
498-- separator is emitted as a separate element in the output.
501{-# INLINABLE sliceSepWith #-}
502sliceSepWith :: -- MonadCatch m =>
503 (a -> Bool) -> Fold m a b -> Parser m a b
504sliceSepWith _cond = undefined -- K.toParserK . D.sliceSepBy cond
506-- | Collect stream elements until an elements passes the predicate, return the
507-- last element on which the predicate succeeded back to the input stream. If
508-- the predicate succeeds on the first element itself then it is kept in the
509-- stream and we continue collecting. The succeeding element is treated as a
510-- prefix separator which is kept in the output segement.
512-- * Stops - when the predicate succeeds in non-leading position.
515-- S.splitWithPrefix pred f = S.parseMany (PR.sliceBeginWith pred f)
519{-# INLINABLE sliceBeginWith #-}
522 (a -> Bool) -> Fold m a b -> Parser m a b
523sliceBeginWith = undefined
525-- | Like 'sliceSepBy' but the separator elements can be escaped using an
526-- escape char determined by the second predicate.
529{-# INLINABLE escapedSliceSepBy #-}
530escapedSliceSepBy :: -- MonadCatch m =>
531 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
532escapedSliceSepBy _cond _esc = undefined
533 -- K.toParserK . D.escapedSliceSepBy cond esc
535-- | @escapedFrameBy begin end escape@ parses a string framed using @begin@ and
536-- @end@ as the frame begin and end marker elements and @escape@ as an escaping
537-- element to escape the occurrence of the framing elements within the frame.
538-- Nested frames are allowed, but nesting is removed when parsing.
542-- >>> escapedFrameBy (== '{') (== '}') (== '\\') S.toList $ S.fromList "{hello}"
545-- >>> escapedFrameBy (== '{') (== '}') (== '\\') S.toList $ S.fromList "{hello {world}}"
548-- >>> escapedFrameBy (== '{') (== '}') (== '\\') S.toList $ S.fromList "{hello \\{world\\}}"
551-- >>> escapedFrameBy (== '{') (== '}') (== '\\') S.toList $ S.fromList "{hello {world}"
552-- > ParseError "Unterminated '{'"
555{-# INLINABLE escapedFrameBy #-}
556escapedFrameBy :: -- MonadCatch m =>
557 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
558escapedFrameBy _begin _end _escape _p = undefined
559 -- K.toParserK . D.frameBy begin end escape p
561-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
562-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
563-- @["a","b"]@. In other words, its like parsing words from whitespace
566-- * Stops - when it finds a word separator after a non-word element
570-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
574wordBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
575wordBy f = K.toParserK . D.wordBy f
577-- | @groupBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
578-- first group, then if @a \`cmp` b@ is 'True' @b@ is also assigned to the same
579-- group. If @a \`cmp` c@ is 'True' then @c@ is also assigned to the same
580-- group and so on. When the comparison fails a new group is started. Each
581-- group is folded using the 'Fold' @f@ and the result of the fold is emitted
582-- in the output stream.
584-- * Stops - when the comparison fails.
588-- S.groupsBy cmp f = S.parseMany (PR.groupBy cmp f)
593{-# INLINABLE groupBy #-}
594groupBy :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
595groupBy cmp = K.toParserK . D.groupBy cmp
597-- | Match the given sequence of elements using the given comparison function.
599-- >>> S.parse $ S.eqBy (==) "string" $ S.fromList "string"
601-- >>> S.parse $ S.eqBy (==) "mismatch" $ S.fromList "match"
602-- > *** Exception: ParseError "eqBy: failed, yet to match 7 elements"
607eqBy :: MonadCatch m => (a -> a -> Bool) -> [a] -> Parser m a ()
608eqBy cmp = K.toParserK . D.eqBy cmp
610-------------------------------------------------------------------------------
612-------------------------------------------------------------------------------
614-- | Sequential parser application. Apply two parsers sequentially to an input
615-- stream. The input is provided to the first parser, when it is done the
616-- remaining input is provided to the second parser. If both the parsers
617-- succeed their outputs are combined using the supplied function. The
618-- operation fails if any of the parsers fail.
620-- Note: This is a parsing dual of appending streams using
621-- 'Streamly.Prelude.serial', it splits the streams using two parsers and zips
624-- This implementation is strict in the second argument, therefore, the
625-- following will fail:
627-- >>> S.parse (PR.splitWith const (PR.satisfy (> 0)) undefined) $ S.fromList [1]
629-- Compare with 'Applicative' instance method '<*>'. This implementation allows
630-- stream fusion but has quadratic complexity. This can fuse with other
631-- operations and can be faster than 'Applicative' instance for small number
632-- (less than 8) of compositions.
636{-# INLINE splitWith #-}
637splitWith :: MonadCatch m
638 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
640 K.toParserK $ D.splitWith f (K.fromParserK p1) (K.fromParserK p2)
642-- | Sequential parser application ignoring the output of the first parser.
643-- Apply two parsers sequentially to an input stream. The input is provided to
644-- the first parser, when it is done the remaining input is provided to the
645-- second parser. The output of the parser is the output of the second parser.
646-- The operation fails if any of the parsers fail.
648-- This implementation is strict in the second argument, therefore, the
649-- following will fail:
651-- >>> S.parse (split_ (PR.satisfy (> 0)) undefined) $ S.fromList [1]
653-- Compare with 'Applicative' instance method '*>'. This implementation allows
654-- stream fusion but has quadratic complexity. This can fuse with other
655-- operations, and can be faster than 'Applicative' instance for small
656-- number (less than 8) of compositions.
661split_ :: MonadCatch m => Parser m x a -> Parser m x b -> Parser m x b
662split_ p1 p2 = K.toParserK $ D.split_ (K.fromParserK p1) (K.fromParserK p2)
664-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
665-- of them succeed or anyone of them fails and combines their output using @f@.
666-- The parser succeeds if both the parsers succeed.
670{-# INLINE teeWith #-}
671teeWith :: MonadCatch m
672 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
674 K.toParserK $ D.teeWith f (K.fromParserK p1) (K.fromParserK p2)
676-- | Like 'teeWith' but ends parsing and zips the results, if available,
677-- whenever the first parser ends.
681{-# INLINE teeWithFst #-}
682teeWithFst :: MonadCatch m
683 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
685 K.toParserK $ D.teeWithFst f (K.fromParserK p1) (K.fromParserK p2)
687-- | Like 'teeWith' but ends parsing and zips the results, if available,
688-- whenever any of the parsers ends or fails.
692{-# INLINE teeWithMin #-}
693teeWithMin :: MonadCatch m
694 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
696 K.toParserK $ D.teeWithMin f (K.fromParserK p1) (K.fromParserK p2)
698-- | Sequential alternative. Apply the input to the first parser and return the
699-- result if the parser succeeds. If the first parser fails then backtrack and
700-- apply the same input to the second parser and return the result.
702-- Note: This implementation is not lazy in the second argument. The following
705-- >>> S.parse (PR.satisfy (> 0) `PR.alt` undefined) $ S.fromList [1..10]
707-- Compare with 'Alternative' instance method '<|>'. This implementation allows
708-- stream fusion but has quadratic complexity. This can fuse with other
709-- operations and can be much faster than 'Alternative' instance for small
710-- number (less than 8) of alternatives.
715alt :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
716alt p1 p2 = K.toParserK $ D.alt (K.fromParserK p1) (K.fromParserK p2)
718-- | Shortest alternative. Apply both parsers in parallel but choose the result
719-- from the one which consumed least input i.e. take the shortest succeeding
724{-# INLINE shortest #-}
725shortest :: MonadCatch m
726 => Parser m x a -> Parser m x a -> Parser m x a
727shortest p1 p2 = K.toParserK $ D.shortest (K.fromParserK p1) (K.fromParserK p2)
729-- | Longest alternative. Apply both parsers in parallel but choose the result
730-- from the one which consumed more input i.e. take the longest succeeding
735{-# INLINE longest #-}
736longest :: MonadCatch m
737 => Parser m x a -> Parser m x a -> Parser m x a
738longest p1 p2 = K.toParserK $ D.longest (K.fromParserK p1) (K.fromParserK p2)
740-- | Run a parser without consuming the input.
744{-# INLINE lookAhead #-}
745lookAhead :: MonadCatch m => Parser m a b -> Parser m a b
746lookAhead p = K.toParserK $ D.lookAhead $ K.fromParserK p
748-------------------------------------------------------------------------------
750-------------------------------------------------------------------------------
752-- To deinterleave we can chain two parsers one behind the other. The input is
753-- given to the first parser and the input definitively rejected by the first
754-- parser is given to the second parser.
756-- We can either have the parsers themselves buffer the input or use the shared
757-- global buffer to hold it until none of the parsers need it. When the first
758-- parser returns Skip (i.e. rewind) we let the second parser consume the
759-- rejected input and when it is done we move the cursor forward to the first
760-- parser again. This will require a "move forward" command as well.
762-- To implement grep we can use three parsers, one to find the pattern, one
763-- to store the context behind the pattern and one to store the context in
764-- front of the pattern. When a match occurs we need to emit the accumulator of
765-- all the three parsers. One parser can count the line numbers to provide the
768-- | Apply two parsers alternately to an input stream. The input stream is
769-- considered an interleaving of two patterns. The two parsers represent the
772-- This undoes a "gintercalate" of two streams.
776{-# INLINE deintercalate #-}
779 Fold m a y -> Parser m x a
780 -> Fold m b z -> Parser m x b
782deintercalate = undefined
784-------------------------------------------------------------------------------
785-- Sequential Collection
786-------------------------------------------------------------------------------
788-- | @concatSequence f t@ collects sequential parses of parsers in the
789-- container @t@ using the fold @f@. Fails if the input ends or any of the
792-- This is same as 'Data.Traversable.sequence' but more efficient.
796{-# INLINE concatSequence #-}
799 Fold m b c -> t (Parser m a b) -> Parser m a c
800concatSequence _f _p = undefined
802-- | Map a 'Parser' returning function on the result of a 'Parser'.
804-- Compare with 'Monad' instance method '>>='. This implementation allows
805-- stream fusion but has quadratic complexity. This can fuse with other
806-- operations and can be much faster than 'Monad' instance for small number
807-- (less than 8) of compositions.
811{-# INLINE concatMap #-}
812concatMap :: MonadCatch m
813 => (b -> Parser m a c) -> Parser m a b -> Parser m a c
814concatMap f p = K.toParserK $ D.concatMap (K.fromParserK . f) (K.fromParserK p)
816-------------------------------------------------------------------------------
817-- Alternative Collection
818-------------------------------------------------------------------------------
820-- | @choice parsers@ applies the @parsers@ in order and returns the first
823-- This is same as 'asum' but more efficient.
830 t (Parser m a b) -> Parser m a b
831choice _ps = undefined
833-------------------------------------------------------------------------------
834-- Sequential Repetition
835-------------------------------------------------------------------------------
838-- TODO "many" is essentially a Fold because it cannot fail. So it can be
839-- downgraded to a Fold. Or we can make the return type a Fold instead and
840-- upgrade that to a parser when needed.
842-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
843-- results. Parsing stops or fails if the collecting parser stops or fails.
848manyP :: -- MonadCatch m =>
849 Parser m b c -> Parser m a b -> Parser m a c
850manyP _f _p = undefined -- K.toParserK $ D.manyP f (K.fromParserK p)
852-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
853-- input stream and push the parse results to a downstream fold.
855-- Stops: when the downstream fold stops or the parser fails.
856-- Fails: never, produces zero or more results.
858-- Compare with 'Control.Applicative.many'.
863many :: MonadCatch m => Fold m b c -> Parser m a b -> Parser m a c
864many f p = K.toParserK $ D.many f (K.fromParserK p)
865-- many = countBetween 0 maxBound
867-- Note: many1 would perhaps be a better name for this and consistent with
868-- other names like takeWhile1. But we retain the name "some" for
871-- | Collect one or more parses. Apply the supplied parser repeatedly on the
872-- input stream and push the parse results to a downstream fold.
874-- Stops: when the downstream fold stops or the parser fails.
875-- Fails: if it stops without producing a single result.
877-- @some fld parser = many (takeGE 1 fld) parser@
879-- Compare with 'Control.Applicative.some'.
884some :: MonadCatch m => Fold m b c -> Parser m a b -> Parser m a c
885some f p = K.toParserK $ D.some f (K.fromParserK p)
886-- some f p = manyP (takeGE 1 f) p
887-- many = countBetween 1 maxBound
889-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
890-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
891-- the input ends or the parser fails before @m@ results are collected.
895{-# INLINE countBetween #-}
898 Int -> Int -> Fold m b c -> Parser m a b -> Parser m a c
899countBetween _m _n _f = undefined
900-- countBetween m n f p = manyP (takeBetween m n f) p
902-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
903-- the fold @f@. Fails if the input ends or the parser fails before @n@
904-- results are collected.
911 Int -> Fold m b c -> Parser m a b -> Parser m a c
912count n = countBetween n n
913-- count n f p = manyP (takeEQ n f) p
915-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
916-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
918-- We can implemnent parsers like the following using 'manyTillP':
921-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
926{-# INLINE manyTillP #-}
927manyTillP :: -- MonadCatch m =>
928 Parser m b c -> Parser m a b -> Parser m a x -> Parser m a c
929manyTillP _f _p1 _p2 = undefined
930 -- K.toParserK $ D.manyTillP f (K.fromParserK p1) (K.fromParserK p2)
932-- | @manyTill f collect test@ tries the parser @test@ on the input, if @test@
933-- fails it backtracks and tries @collect@, after @collect@ succeeds @test@ is
934-- tried again and so on. The parser stops when @test@ succeeds. The output of
935-- @test@ is discarded and the output of @collect@ is accumulated by the
936-- supplied fold. The parser fails if @collect@ fails.
938-- Stops when the fold @f@ stops.
942{-# INLINE manyTill #-}
943manyTill :: MonadCatch m
944 => Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
946 K.toParserK $ D.manyTill f (K.fromParserK p1) (K.fromParserK p2)
948-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
949-- collects the output in the supplied fold. If the the parser @collect@ fails,
950-- parser @recover@ is run until it stops and then we start repeating the
951-- parser @collect@ again. The parser fails if the recovery parser fails.
953-- For example, this can be used to find a key frame in a video stream after an
958{-# INLINE manyThen #-}
959manyThen :: -- (Foldable t, MonadCatch m) =>
960 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
961manyThen _f _parser _recover = undefined
963-------------------------------------------------------------------------------
964-- Interleaving a collection of parsers
965-------------------------------------------------------------------------------
967-- | Apply a collection of parsers to an input stream in a round robin fashion.
968-- Each parser is applied until it stops and then we repeat starting with the
969-- the first parser again.
973{-# INLINE roundRobin #-}
974roundRobin :: -- (Foldable t, MonadCatch m) =>
975 Fold m b c -> t (Parser m a b) -> Parser m a c
976roundRobin _f _ps = undefined
978-------------------------------------------------------------------------------
979-- Repeated Alternatives
980-------------------------------------------------------------------------------
982-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
983-- fails the input consumed till now is dropped and the new instance is tried
984-- on the fresh input.
988{-# INLINE retryMaxTotal #-}
989retryMaxTotal :: -- (MonadCatch m) =>
990 Int -> Fold m b c -> Parser m a b -> Parser m a c
991retryMaxTotal _n _f _p = undefined
993-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
997{-# INLINE retryMaxSuccessive #-}
998retryMaxSuccessive :: -- (MonadCatch m) =>
999 Int -> Fold m b c -> Parser m a b -> Parser m a c
1000retryMaxSuccessive _n _f _p = undefined
1002-- | Keep trying a parser until it succeeds. When the parser fails the input
1003-- consumed till now is dropped and the new instance is tried on the fresh
1009retry :: -- (MonadCatch m) =>
1010 Parser m a b -> Parser m a b
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list