1#if __GLASGOW_HASKELL__ >= 800
2{-# OPTIONS_GHC -Wno-orphans #-}
6-- Module : Streamly.Internal.Data.Parser
7-- Copyright : (c) 2020 Composewell Technologies
8-- License : BSD-3-Clause
9-- Maintainer : streamly@composewell.com
10-- Stability : experimental
13-- Fast backtracking parsers with stream fusion and native streaming
16-- 'Applicative' and 'Control.Applicative.Alternative' type class based
17-- combinators from the
18-- <http://hackage.haskell.org/package/parser-combinators parser-combinators>
19-- package can also be used with the 'Parser' type. However, there are two
20-- important differences between @parser-combinators@ and the equivalent ones
21-- provided in this module in terms of performance:
23-- 1) @parser-combinators@ use plain Haskell lists to collect the results, in a
24-- strict Monad like IO, the results are necessarily buffered before they can
25-- be consumed. This may not perform optimally in streaming applications
26-- processing large amounts of data. Equivalent combinators in this module can
27-- consume the results of parsing using a 'Fold', thus providing a scalability
28-- and a composable consumer.
30-- 2) Several combinators in this module can be many times faster because of
31-- stream fusion. For example, 'Streamly.Internal.Data.Parser.many' combinator
32-- in this module is much faster than the 'Control.Applicative.many' combinator
33-- of 'Control.Applicative.Alternative' type class.
37-- Failing parsers in this module throw the 'D.ParseError' exception.
41-- As far as possible, try that the names of the combinators in this module are
44-- * <https://hackage.haskell.org/package/base/docs/Text-ParserCombinators-ReadP.html base/Text.ParserCombinators.ReadP>
45-- * <http://hackage.haskell.org/package/parser-combinators parser-combinators>
46-- * <http://hackage.haskell.org/package/megaparsec megaparsec>
47-- * <http://hackage.haskell.org/package/attoparsec attoparsec>
48-- * <http://hackage.haskell.org/package/parsec parsec>
50module Streamly.Internal.Data.Parser
56 -- First order parsers
73 -- | Parsers chained in series, if one parser terminates the composition
76 -- | Grab a sequence of input elements without inspecting them
78 , take -- takeBetween 0 n
80 , takeEQ -- takeBetween n n
81 , takeGE -- takeBetween n maxBound
83 -- Grab a sequence of input elements by inspecting them
104 -- , prefixOf -- match any prefix of a given string
105 -- , suffixOf -- match any suffix of a given string
106 -- , infixOf -- match any substring of a given string
109 -- Second order parsers (parsers using parsers)
110 -- * Binary Combinators
112 -- ** Sequential Applicative
116 -- ** Parallel Applicatives
120 -- , teeTill -- like manyTill but parallel
122 -- ** Sequential Interleaving
123 -- Use two folds, run a primary parser, its rejected values go to the
127 -- ** Sequential Alternative
130 -- ** Parallel Alternatives
135 -- * N-ary Combinators
136 -- ** Sequential Collection
140 -- ** Sequential Repetition
152 -- | TODO: traditional implmentations of these may be of limited use. For
153 -- example, consider parsing lines separated by @\\r\\n@. The main parser
154 -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
155 -- can apply the "sep" parser.
157 -- We can instead implement these as special cases of deintercalate.
170 -- | A simple and stupid impl would be to just convert the stream to an
171 -- array and give the array reference to all consumers. The array can be
172 -- grown on demand by any consumer and truncated when nonbody needs it.
174 -- ** Distribute to collection
175 -- ** Distribute to repetition
177 -- ** Interleaved collection
184 -- ** Collection of Alternatives
190 -- , fastestN -- first N successful in time
191 -- , choiceN -- first N successful in position
193 , choice -- first successful in position
195 -- ** Repeated Alternatives
202import Control.Monad.Catch (MonadCatch)
204 hiding (any, all, take, takeWhile, sequence, concatMap)
206import Streamly.Internal.Data.Fold.Types (Fold(..))
207import Streamly.Internal.Data.Parser.ParserK.Types (Parser)
209import qualified Streamly.Internal.Data.Parser.ParserD as D
210import qualified Streamly.Internal.Data.Parser.ParserK.Types as K
212-------------------------------------------------------------------------------
213-- Upgrade folds to parses
214-------------------------------------------------------------------------------
216-- | Make a 'Parser' from a 'Fold'.
220{-# INLINE fromFold #-}
221fromFold :: MonadCatch m => Fold m a b -> Parser m a b
222fromFold = D.toParserK . D.fromFold
224-------------------------------------------------------------------------------
225-- Terminating but not failing folds
226-------------------------------------------------------------------------------
229-- >>> S.parse (PR.any (== 0)) $ S.fromList [1,0,1]
233any :: MonadCatch m => (a -> Bool) -> Parser m a Bool
234any = D.toParserK . D.any
237-- >>> S.parse (PR.all (== 0)) $ S.fromList [1,0,1]
241all :: MonadCatch m => (a -> Bool) -> Parser m a Bool
242all = D.toParserK . D.all
244-- This is the dual of stream "yield".
246-- | A parser that always yields a pure value without consuming any input.
250{-# INLINE [3] yield #-}
251yield :: MonadCatch m => b -> Parser m a b
252yield = D.toParserK . D.yield
253{-# RULES "yield fallback to CPS" [2]
254 forall a. D.toParserK (D.yield a) = K.yield a #-}
256-- This is the dual of stream "yieldM".
258-- | A parser that always yields the result of an effectful action without
259-- consuming any input.
264yieldM :: MonadCatch m => m b -> Parser m a b
265yieldM = D.toParserK . D.yieldM
267-- This is the dual of "nil".
269-- | A parser that always fails with an error message without consuming
274{-# INLINE [3] die #-}
275die :: MonadCatch m => String -> Parser m a b
276die = D.toParserK . D.die
277{-# RULES "die fallback to CPS" [2]
278 forall a. D.toParserK (D.die a) = K.die a #-}
280-- This is the dual of "nilM".
282-- | A parser that always fails with an effectful error message and without
283-- consuming any input.
288dieM :: MonadCatch m => m String -> Parser m a b
289dieM = D.toParserK . D.dieM
291-------------------------------------------------------------------------------
293-------------------------------------------------------------------------------
295-- | Peek the head element of a stream, without consuming it. Fails if it
296-- encounters end of input.
298-- >>> S.parse ((,) <$> PR.peek <*> PR.satisfy (> 0)) $ S.fromList [1]
302-- peek = lookAhead (satisfy True)
308peek :: MonadCatch m => Parser m a a
309peek = D.toParserK D.peek
311-- | Succeeds if we are at the end of input, fails otherwise.
313-- >>> S.parse ((,) <$> PR.satisfy (> 0) <*> PR.eof) $ S.fromList [1]
319eof :: MonadCatch m => Parser m a ()
320eof = D.toParserK D.eof
322-- | Returns the next element if it passes the predicate, fails otherwise.
324-- >>> S.parse (PR.satisfy (== 1)) $ S.fromList [1,0,1]
329{-# INLINE satisfy #-}
330satisfy :: MonadCatch m => (a -> Bool) -> Parser m a a
331satisfy = D.toParserK . D.satisfy
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.
343-- @takeBetween@ is the most general take operation, other take operations can
344-- be defined in terms of takeBetween. For example:
347-- take = takeBetween 0 n -- equivalent of takeLE
348-- take1 = takeBetween 1 n -- equivalent of takeLE1
349-- takeEQ = takeBetween n n
350-- takeGE = takeBetween n maxBound
355{-# INLINE takeBetween #-}
356takeBetween :: -- MonadCatch m =>
357 Int -> Int -> Fold m a b -> Parser m a b
358takeBetween _m _n = undefined -- D.toParserK . D.takeBetween m n
362-- Note: this is called takeP in some parser libraries.
364-- TODO Once we have terminating folds, this Parse should get replaced by Fold.
365-- Alternatively, we can name it "chunkOf" and the corresponding time domain
366-- combinator as "intervalOf" or even "chunk" and "interval".
368-- | Take at most @n@ input elements and fold them using the supplied fold.
370-- Stops after @n@ elements.
373-- >>> S.parse (PR.take 1 FL.toList) $ S.fromList [1]
376-- >>> S.parse (PR.take (-1) FL.toList) $ S.fromList [1]
380-- S.chunksOf n f = S.parseMany (FL.take n f)
386take :: MonadCatch m => Int -> Fold m a b -> Parser m a b
387take n = D.toParserK . D.take n
389-- | Stops after taking exactly @n@ input elements.
391-- * Stops - after @n@ elements.
392-- * Fails - if the stream ends before it can collect @n@ elements.
394-- >>> S.parse (PR.takeEQ 4 FL.toList) $ S.fromList [1,0,1]
395-- > "takeEQ: Expecting exactly 4 elements, got 3"
400takeEQ :: MonadCatch m => Int -> Fold m a b -> Parser m a b
401takeEQ n = D.toParserK . D.takeEQ n
403-- | Take at least @n@ input elements, but can collect more.
406-- * Fails - if the stream end before producing @n@ elements.
408-- >>> S.parse (PR.takeGE 4 FL.toList) $ S.fromList [1,0,1]
409-- > "takeGE: Expecting at least 4 elements, got only 3"
411-- >>> S.parse (PR.takeGE 4 FL.toList) $ S.fromList [1,0,1,0,1]
417takeGE :: MonadCatch m => Int -> Fold m a b -> Parser m a b
418takeGE n = D.toParserK . D.takeGE n
421-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
423-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
424-- input. The combinator stops when the condition fails or if the collecting
427-- This is a generalized version of takeWhile, for example 'takeWhile1' can be
428-- implemented in terms of this:
431-- takeWhile1 cond p = takeWhile cond (takeBetween 1 maxBound p)
434-- Stops: when the condition fails or the collecting parser stops.
435-- Fails: when the collecting parser fails.
439{-# INLINE takeWhileP #-}
440takeWhileP :: -- MonadCatch m =>
441 (a -> Bool) -> Parser m a b -> Parser m a b
442takeWhileP _cond = undefined -- D.toParserK . D.takeWhileP cond
444-- | Collect stream elements until an element fails the predicate. The element
445-- on which the predicate fails is returned back to the input stream.
447-- * Stops - when the predicate fails.
450-- >>> S.parse (PR.takeWhile (== 0) FL.toList) $ S.fromList [0,0,1,0,1]
453-- We can implement a @breakOn@ using 'takeWhile':
456-- breakOn p = takeWhile (not p)
461{-# INLINE takeWhile #-}
462takeWhile :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
463takeWhile cond = D.toParserK . D.takeWhile cond
465-- | Like 'takeWhile' but takes at least one element otherwise fails.
469{-# INLINE takeWhile1 #-}
470takeWhile1 :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
471takeWhile1 cond = D.toParserK . D.takeWhile1 cond
473-- | Like 'sliceSepBy' but uses a 'Parser' instead of a 'Fold' to collect the
474-- input. @sliceSepByP cond parser@ parses a slice of the input using @parser@
475-- until @cond@ succeeds or the parser stops.
477-- This is a generalized slicing parser which can be used to implement other
481-- sliceSepByMax cond n p = sliceBy cond (take n p)
482-- sliceSepByBetween cond m n p = sliceBy cond (takeBetween m n p)
487{-# INLINABLE sliceSepByP #-}
488sliceSepByP :: -- MonadCatch m =>
489 (a -> Bool) -> Parser m a b -> Parser m a b
490sliceSepByP _cond = undefined -- D.toParserK . D.sliceSepByP cond
492-- Note: Keep this consistent with S.splitOn. In fact we should eliminate
493-- S.splitOn in favor of the parser.
495-- | Split on an infixed separator element, dropping the separator. Splits the
496-- stream on separator elements determined by the supplied predicate, separator
497-- is considered as infixed between two segments, if one side of the separator
498-- is missing then it is parsed as an empty stream. The supplied 'Fold' is
499-- applied on the split segments. With '-' representing non-separator elements
500-- and '.' as separator, 'splitOn' splits as follows:
503-- "--.--" => "--" "--"
508-- @PR.sliceSepBy (== x)@ is an inverse of @S.intercalate (S.yield x)@
510-- Let's use the following definition for illustration:
512-- > splitOn p = PR.many FL.toList $ PR.sliceSepBy p (FL.toList)
513-- > splitOn' p = S.parse (splitOn p) . S.fromList
515-- >>> splitOn' (== '.') ""
518-- >>> splitOn' (== '.') "."
521-- >>> splitOn' (== '.') ".a"
524-- >>> splitOn' (== '.') "a."
527-- >>> splitOn' (== '.') "a.b"
530-- >>> splitOn' (== '.') "a..b"
533-- * Stops - when the predicate succeeds.
537{-# INLINABLE sliceSepBy #-}
538sliceSepBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
539sliceSepBy cond = D.toParserK . D.sliceSepBy cond
541-- | Like 'sliceSepBy' but does not drop the separator element, instead
542-- separator is emitted as a separate element in the output.
545{-# INLINABLE sliceSepWith #-}
546sliceSepWith :: -- MonadCatch m =>
547 (a -> Bool) -> Fold m a b -> Parser m a b
548sliceSepWith _cond = undefined -- D.toParserK . D.sliceSepBy cond
550-- | Collect stream elements until an element succeeds the predicate. Also take
551-- the element on which the predicate succeeded. The succeeding element is
552-- treated as a suffix separator which is kept in the output segement.
554-- * Stops - when the predicate succeeds.
557-- S.splitWithSuffix pred f = S.parseMany (PR.sliceEndWith pred f)
561{-# INLINABLE sliceEndWith #-}
564 (a -> Bool) -> Fold m a b -> Parser m a b
565sliceEndWith = undefined
567-- | Collect stream elements until an elements passes the predicate, return the
568-- last element on which the predicate succeeded back to the input stream. If
569-- the predicate succeeds on the first element itself then it is kept in the
570-- stream and we continue collecting. The succeeding element is treated as a
571-- prefix separator which is kept in the output segement.
573-- * Stops - when the predicate succeeds in non-leading position.
576-- S.splitWithPrefix pred f = S.parseMany (PR.sliceBeginWith pred f)
580{-# INLINABLE sliceBeginWith #-}
583 (a -> Bool) -> Fold m a b -> Parser m a b
584sliceBeginWith = undefined
586-- | Like 'sliceSepBy' but terminates a parse even before the separator
587-- is encountered if its size exceeds the specified maximum limit.
589-- > take n = PR.sliceSepByMax (const True) n
590-- > sliceSepBy p = PR.sliceSepByMax p maxBound
592-- Let's use the following definitions for illustration:
594-- > splitOn p n = PR.many FL.toList $ PR.sliceSepByMax p n (FL.toList)
595-- > splitOn' p n = S.parse (splitOn p n) . S.fromList
597-- >>> splitOn' (== '.') 0 ""
600-- >>> splitOn' (== '.') 0 "a"
601-- infinite list of empty strings
603-- >>> splitOn' (== '.') 3 "hello.world"
604-- ["hel","lo","wor","ld"]
606-- If the separator is found and the limit is reached at the same time then it
607-- behaves just like 'sliceSepBy' i.e. the separator is dropped.
609-- >>> splitOn' (== '.') 0 "."
612-- >>> splitOn' (== '.') 0 ".."
615-- * Stops - when the predicate succeeds or the limit is reached.
619{-# INLINABLE sliceSepByMax #-}
620sliceSepByMax :: MonadCatch m
621 => (a -> Bool) -> Int -> Fold m a b -> Parser m a b
622sliceSepByMax cond cnt = D.toParserK . D.sliceSepByMax cond cnt
624-- | Like 'sliceSepBy' but the separator elements can be escaped using an
625-- escape char determined by the second predicate.
628{-# INLINABLE escapedSliceSepBy #-}
629escapedSliceSepBy :: -- MonadCatch m =>
630 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
631escapedSliceSepBy _cond _esc = undefined
632 -- D.toParserK . D.escapedSliceSepBy cond esc
634-- | @escapedFrameBy begin end escape@ parses a string framed using @begin@ and
635-- @end@ as the frame begin and end marker elements and @escape@ as an escaping
636-- element to escape the occurrence of the framing elements within the frame.
637-- Nested frames are allowed, but nesting is removed when parsing.
641-- >>> escapedFrameBy (== '{') (== '}') (== '\\') S.toList $ S.fromList "{hello}"
644-- >>> escapedFrameBy (== '{') (== '}') (== '\\') S.toList $ S.fromList "{hello {world}}"
647-- >>> escapedFrameBy (== '{') (== '}') (== '\\') S.toList $ S.fromList "{hello \\{world\\}}"
650-- >>> escapedFrameBy (== '{') (== '}') (== '\\') S.toList $ S.fromList "{hello {world}"
651-- > ParseError "Unterminated '{'"
654{-# INLINABLE escapedFrameBy #-}
655escapedFrameBy :: -- MonadCatch m =>
656 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
657escapedFrameBy _begin _end _escape _p = undefined
658 -- D.toParserK . D.frameBy begin end escape p
660-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
661-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
662-- @["a","b"]@. In other words, its like parsing words from whitespace
665-- * Stops - when it finds a word separator after a non-word element
669-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
674{-# INLINABLE wordBy #-}
677 (a -> Bool) -> Fold m a b -> Parser m a b
680-- | @groupBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
681-- first group, then if @a \`cmp` b@ is 'True' @b@ is also assigned to the same
682-- group. If @a \`cmp` c@ is 'True' then @c@ is also assigned to the same
683-- group and so on. When the comparison fails a new group is started. Each
684-- group is folded using the 'Fold' @f@ and the result of the fold is emitted
685-- in the output stream.
687-- * Stops - when the comparison fails.
691-- S.groupsBy cmp f = S.parseMany (PR.groupBy cmp f)
696{-# INLINABLE groupBy #-}
699 (a -> a -> Bool) -> Fold m a b -> Parser m a b
702-- | Match the given sequence of elements using the given comparison function.
704-- >>> S.parse $ S.eqBy (==) "string" $ S.fromList "string"
706-- >>> S.parse $ S.eqBy (==) "mismatch" $ S.fromList "match"
707-- > *** Exception: ParseError "eqBy: failed, yet to match 7 elements"
712eqBy :: MonadCatch m => (a -> a -> Bool) -> [a] -> Parser m a ()
713eqBy cmp = D.toParserK . D.eqBy cmp
715-------------------------------------------------------------------------------
717-------------------------------------------------------------------------------
719-- | Sequential parser application. Apply two parsers sequentially to an input
720-- stream. The input is provided to the first parser, when it is done the
721-- remaining input is provided to the second parser. If both the parsers
722-- succeed their outputs are combined using the supplied function. The
723-- operation fails if any of the parsers fail.
725-- Note: This is a parsing dual of appending streams using
726-- 'Streamly.Prelude.serial', it splits the streams using two parsers and zips
729-- This implementation is strict in the second argument, therefore, the
730-- following will fail:
732-- >>> S.parse (PR.splitWith const (PR.satisfy (> 0)) undefined) $ S.fromList [1]
734-- Compare with 'Applicative' instance method '<*>'. This implementation allows
735-- stream fusion but has quadratic complexity. This can fuse with other
736-- operations and can be faster than 'Applicative' instance for small number
737-- (less than 8) of compositions.
741{-# INLINE splitWith #-}
742splitWith :: MonadCatch m
743 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
745 D.toParserK $ D.splitWith f (D.fromParserK p1) (D.fromParserK p2)
747-- | Sequential parser application ignoring the output of the first parser.
748-- Apply two parsers sequentially to an input stream. The input is provided to
749-- the first parser, when it is done the remaining input is provided to the
750-- second parser. The output of the parser is the output of the second parser.
751-- The operation fails if any of the parsers fail.
753-- This implementation is strict in the second argument, therefore, the
754-- following will fail:
756-- >>> S.parse (split_ (PR.satisfy (> 0)) undefined) $ S.fromList [1]
758-- Compare with 'Applicative' instance method '*>'. This implementation allows
759-- stream fusion but has quadratic complexity. This can fuse with other
760-- operations, and can be faster than 'Applicative' instance for small
761-- number (less than 8) of compositions.
766split_ :: MonadCatch m => Parser m x a -> Parser m x b -> Parser m x b
767split_ p1 p2 = D.toParserK $ D.split_ (D.fromParserK p1) (D.fromParserK p2)
769-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
770-- of them succeed or anyone of them fails and combines their output using @f@.
771-- The parser succeeds if both the parsers succeed.
775{-# INLINE teeWith #-}
776teeWith :: MonadCatch m
777 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
779 D.toParserK $ D.teeWith f (D.fromParserK p1) (D.fromParserK p2)
781-- | Like 'teeWith' but ends parsing and zips the results, if available,
782-- whenever the first parser ends.
786{-# INLINE teeWithFst #-}
787teeWithFst :: MonadCatch m
788 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
790 D.toParserK $ D.teeWithFst f (D.fromParserK p1) (D.fromParserK p2)
792-- | Like 'teeWith' but ends parsing and zips the results, if available,
793-- whenever any of the parsers ends or fails.
797{-# INLINE teeWithMin #-}
798teeWithMin :: MonadCatch m
799 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
801 D.toParserK $ D.teeWithMin f (D.fromParserK p1) (D.fromParserK p2)
803-- | Sequential alternative. Apply the input to the first parser and return the
804-- result if the parser succeeds. If the first parser fails then backtrack and
805-- apply the same input to the second parser and return the result.
807-- Note: This implementation is not lazy in the second argument. The following
810-- >>> S.parse (PR.satisfy (> 0) `PR.alt` undefined) $ S.fromList [1..10]
812-- Compare with 'Alternative' instance method '<|>'. This implementation allows
813-- stream fusion but has quadratic complexity. This can fuse with other
814-- operations and can be much faster than 'Alternative' instance for small
815-- number (less than 8) of alternatives.
820alt :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
821alt p1 p2 = D.toParserK $ D.alt (D.fromParserK p1) (D.fromParserK p2)
823-- | Shortest alternative. Apply both parsers in parallel but choose the result
824-- from the one which consumed least input i.e. take the shortest succeeding
829{-# INLINE shortest #-}
830shortest :: MonadCatch m
831 => Parser m x a -> Parser m x a -> Parser m x a
832shortest p1 p2 = D.toParserK $ D.shortest (D.fromParserK p1) (D.fromParserK p2)
834-- | Longest alternative. Apply both parsers in parallel but choose the result
835-- from the one which consumed more input i.e. take the longest succeeding
840{-# INLINE longest #-}
841longest :: MonadCatch m
842 => Parser m x a -> Parser m x a -> Parser m x a
843longest p1 p2 = D.toParserK $ D.longest (D.fromParserK p1) (D.fromParserK p2)
845-- | Run a parser without consuming the input.
849{-# INLINE lookAhead #-}
850lookAhead :: MonadCatch m => Parser m a b -> Parser m a b
851lookAhead p = D.toParserK $ D.lookAhead $ D.fromParserK p
853-------------------------------------------------------------------------------
855-------------------------------------------------------------------------------
857-- To deinterleave we can chain two parsers one behind the other. The input is
858-- given to the first parser and the input definitively rejected by the first
859-- parser is given to the second parser.
861-- We can either have the parsers themselves buffer the input or use the shared
862-- global buffer to hold it until none of the parsers need it. When the first
863-- parser returns Skip (i.e. rewind) we let the second parser consume the
864-- rejected input and when it is done we move the cursor forward to the first
865-- parser again. This will require a "move forward" command as well.
867-- To implement grep we can use three parsers, one to find the pattern, one
868-- to store the context behind the pattern and one to store the context in
869-- front of the pattern. When a match occurs we need to emit the accumulator of
870-- all the three parsers. One parser can count the line numbers to provide the
873-- | Apply two parsers alternately to an input stream. The input stream is
874-- considered an interleaving of two patterns. The two parsers represent the
877-- This undoes a "gintercalate" of two streams.
881{-# INLINE deintercalate #-}
884 Fold m a y -> Parser m x a
885 -> Fold m b z -> Parser m x b
887deintercalate = undefined
889-------------------------------------------------------------------------------
890-- Sequential Collection
891-------------------------------------------------------------------------------
893-- | @sequence f t@ collects sequential parses of parsers in the container @t@
894-- using the fold @f@. Fails if the input ends or any of the parsers fail.
896-- This is same as 'Data.Traversable.sequence' but more efficient.
900{-# INLINE sequence #-}
903 Fold m b c -> t (Parser m a b) -> Parser m a c
904sequence _f _p = undefined
906-- | Map a 'Parser' returning function on the result of a 'Parser'.
908-- Compare with 'Monad' instance method '>>='. This implementation allows
909-- stream fusion but has quadratic complexity. This can fuse with other
910-- operations and can be much faster than 'Monad' instance for small number
911-- (less than 8) of compositions.
915{-# INLINE concatMap #-}
916concatMap :: MonadCatch m
917 => (b -> Parser m a c) -> Parser m a b -> Parser m a c
918concatMap f p = D.toParserK $ D.concatMap (D.fromParserK . f) (D.fromParserK p)
920-------------------------------------------------------------------------------
921-- Alternative Collection
922-------------------------------------------------------------------------------
924-- | @choice parsers@ applies the @parsers@ in order and returns the first
927-- This is same as 'asum' but more efficient.
934 t (Parser m a b) -> Parser m a b
935choice _ps = undefined
937-------------------------------------------------------------------------------
938-- Sequential Repetition
939-------------------------------------------------------------------------------
942-- TODO "many" is essentially a Fold because it cannot fail. So it can be
943-- downgraded to a Fold. Or we can make the return type a Fold instead and
944-- upgrade that to a parser when needed.
946-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
947-- results. Parsing stops or fails if the collecting parser stops or fails.
952manyP :: -- MonadCatch m =>
953 Parser m b c -> Parser m a b -> Parser m a c
954manyP _f _p = undefined -- D.toParserK $ D.manyP f (D.fromParserK p)
956-- | Collect zero or more parses. Apply the parser repeatedly on the input
957-- stream, stop when the parser fails, accumulate zero or more parse results
958-- using the supplied 'Fold'. This parser never fails, in case the first
959-- application of parser fails it returns an empty result.
961-- Compare with 'Control.Applicative.many'.
966many :: MonadCatch m => Fold m b c -> Parser m a b -> Parser m a c
967many f p = D.toParserK $ D.many f (D.fromParserK p)
968-- many = countBetween 0 maxBound
970-- | Collect one or more parses. Apply the supplied parser repeatedly on the
971-- input stream and accumulate the parse results as long as the parser
972-- succeeds, stop when it fails. This parser fails if not even one result is
975-- Compare with 'Control.Applicative.some'.
980some :: MonadCatch m => Fold m b c -> Parser m a b -> Parser m a c
981some f p = D.toParserK $ D.some f (D.fromParserK p)
982-- some f p = manyP (takeGE 1 f) p
983-- many = countBetween 1 maxBound
985-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
986-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
987-- the input ends or the parser fails before @m@ results are collected.
991{-# INLINE countBetween #-}
994 Int -> Int -> Fold m b c -> Parser m a b -> Parser m a c
995countBetween _m _n _f = undefined
996-- countBetween m n f p = manyP (takeBetween m n f) p
998-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
999-- the fold @f@. Fails if the input ends or the parser fails before @n@
1000-- results are collected.
1007 Int -> Fold m b c -> Parser m a b -> Parser m a c
1008count n = countBetween n n
1009-- count n f p = manyP (takeEQ n f) p
1011-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
1012-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
1014-- We can implemnent parsers like the following using 'manyTillP':
1017-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
1022{-# INLINE manyTillP #-}
1023manyTillP :: -- MonadCatch m =>
1024 Parser m b c -> Parser m a b -> Parser m a x -> Parser m a c
1025manyTillP _f _p1 _p2 = undefined
1026 -- D.toParserK $ D.manyTillP f (D.fromParserK p1) (D.fromParserK p2)
1028-- | @manyTill f collect test@ tries the parser @test@ on the input, if @test@
1029-- fails it backtracks and tries @collect@, after @collect@ succeeds @test@ is
1030-- tried again and so on. The parser stops when @test@ succeeds. The output of
1031-- @test@ is discarded and the output of @collect@ is accumulated by the
1032-- supplied fold. The parser fails if @collect@ fails.
1036{-# INLINE manyTill #-}
1037manyTill :: MonadCatch m
1038 => Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1040 D.toParserK $ D.manyTill f (D.fromParserK p1) (D.fromParserK p2)
1042-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
1043-- collects the output in the supplied fold. If the the parser @collect@ fails,
1044-- parser @recover@ is run until it stops and then we start repeating the
1045-- parser @collect@ again. The parser fails if the recovery parser fails.
1047-- For example, this can be used to find a key frame in a video stream after an
1052{-# INLINE manyThen #-}
1053manyThen :: -- (Foldable t, MonadCatch m) =>
1054 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1055manyThen _f _parser _recover = undefined
1057-------------------------------------------------------------------------------
1058-- Interleaving a collection of parsers
1059-------------------------------------------------------------------------------
1061-- | Apply a collection of parsers to an input stream in a round robin fashion.
1062-- Each parser is applied until it stops and then we repeat starting with the
1063-- the first parser again.
1067{-# INLINE roundRobin #-}
1068roundRobin :: -- (Foldable t, MonadCatch m) =>
1069 Fold m b c -> t (Parser m a b) -> Parser m a c
1070roundRobin _f _ps = undefined
1072-------------------------------------------------------------------------------
1073-- Repeated Alternatives
1074-------------------------------------------------------------------------------
1076-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
1077-- fails the input consumed till now is dropped and the new instance is tried
1078-- on the fresh input.
1082{-# INLINE retryMaxTotal #-}
1083retryMaxTotal :: -- (MonadCatch m) =>
1084 Int -> Fold m b c -> Parser m a b -> Parser m a c
1085retryMaxTotal _n _f _p = undefined
1087-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
1091{-# INLINE retryMaxSuccessive #-}
1092retryMaxSuccessive :: -- (MonadCatch m) =>
1093 Int -> Fold m b c -> Parser m a b -> Parser m a c
1094retryMaxSuccessive _n _f _p = undefined
1096-- | Keep trying a parser until it succeeds. When the parser fails the input
1097-- consumed till now is dropped and the new instance is tried on the fresh
1103retry :: -- (MonadCatch m) =>
1104 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