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 : pre-release
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 -- * Downgrade to Fold
57 -- First order parsers
80 -- | Parsers chained in series, if one parser terminates the composition
83 -- | Grab a sequence of input elements without inspecting them
85 -- , take -- takeBetween 0 n
86 , takeEQ -- takeBetween n n
87 , takeGE -- takeBetween n maxBound
90 -- Grab a sequence of input elements by inspecting them
103 -- Quoting and Escaping
107 -- Words and grouping
111 , groupByRollingEither
117 -- , prefixOf -- match any prefix of a given string
118 -- , suffixOf -- match any suffix of a given string
119 -- , infixOf -- match any substring of a given string
122 -- Second order parsers (parsers using parsers)
123 -- * Binary Combinators
125 -- ** Sequential Applicative
129 -- ** Parallel Applicatives
133 -- , teeTill -- like manyTill but parallel
135 -- ** Sequential Interleaving
136 -- Use two folds, run a primary parser, its rejected values go to the
140 -- ** Sequential Alternative
143 -- ** Parallel Alternatives
148 -- * N-ary Combinators
149 -- ** Sequential Collection
153 -- ** Sequential Repetition
165 -- | TODO: traditional implmentations of these may be of limited use. For
166 -- example, consider parsing lines separated by @\\r\\n@. The main parser
167 -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
168 -- can apply the "sep" parser.
170 -- We can instead implement these as special cases of deintercalate.
184 -- | A simple and stupid impl would be to just convert the stream to an
185 -- array and give the array reference to all consumers. The array can be
186 -- grown on demand by any consumer and truncated when nonbody needs it.
188 -- ** Distribute to collection
189 -- ** Distribute to repetition
191 -- ** Interleaved collection
198 -- ** Collection of Alternatives
204 -- , fastestN -- first N successful in time
205 -- , choiceN -- first N successful in position
207 , choice -- first successful in position
209 -- ** Repeated Alternatives
216import Control.Applicative ((<|>))
217import Control.Monad.Catch (MonadCatch, MonadThrow)
219 (any, all, take, takeWhile, sequence, concatMap, maybe, either, filter)
221import Streamly.Internal.Data.Fold.Type (Fold(..))
222import Streamly.Internal.Data.Parser.ParserK.Type (Parser)
224import qualified Streamly.Internal.Data.Fold.Type as FL
225import qualified Streamly.Internal.Data.Parser.ParserD as D
226import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
231-- >>> :set -package streamly
232-- >>> import Prelude hiding (any, all, take, takeWhile, sequence, concatMap, maybe, either)
233-- >>> import qualified Streamly.Prelude as Stream
234-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, parseMany)
235-- >>> import qualified Streamly.Data.Fold as Fold
236-- >>> import qualified Streamly.Internal.Data.Parser as Parser
238-------------------------------------------------------------------------------
239-- Downgrade a parser to a Fold
240-------------------------------------------------------------------------------
242-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
243-- parser fails or tries to backtrack.
245-- This can be useful in combinators that accept a Fold and we know that a
246-- Parser cannot fail or failure exception is acceptable as there is no way to
252toFold :: MonadThrow m => Parser m a b -> Fold m a b
253toFold p = D.toFold $ D.fromParserK p
255-------------------------------------------------------------------------------
256-- Upgrade folds to parses
257-------------------------------------------------------------------------------
259-- | Make a 'Parser' from a 'Fold'.
263{-# INLINE fromFold #-}
264fromFold :: MonadCatch m => Fold m a b -> Parser m a b
265fromFold = D.toParserK . D.fromFold
267-------------------------------------------------------------------------------
268-- Terminating but not failing folds
269-------------------------------------------------------------------------------
271-- This is the dual of stream "fromPure".
273-- | A parser that always yields a pure value without consuming any input.
277{-# INLINE [3] fromPure #-}
278fromPure :: MonadCatch m => b -> Parser m a b
279fromPure = D.toParserK . D.fromPure
280{-# RULES "fromPure fallback to CPS" [2]
281 forall a. D.toParserK (D.fromPure a) = K.fromPure a #-}
283-- This is the dual of stream "fromEffect".
285-- | A parser that always yields the result of an effectful action without
286-- consuming any input.
290{-# INLINE fromEffect #-}
291fromEffect :: MonadCatch m => m b -> Parser m a b
292fromEffect = K.fromEffect -- D.toParserK . D.fromEffect
294-- This is the dual of "nil".
296-- | A parser that always fails with an error message without consuming
301{-# INLINE [3] die #-}
302die :: MonadCatch m => String -> Parser m a b
303die = D.toParserK . D.die
304{-# RULES "die fallback to CPS" [2]
305 forall a. D.toParserK (D.die a) = K.die a #-}
307-- This is the dual of "nilM".
309-- | A parser that always fails with an effectful error message and without
310-- consuming any input.
315dieM :: MonadCatch m => m String -> Parser m a b
316dieM = D.toParserK . D.dieM
318-------------------------------------------------------------------------------
320-------------------------------------------------------------------------------
322-- | @lmap f parser@ maps the function @f@ on the input of the parser.
324-- >>> Stream.parse (Parser.lmap (\x -> x * x) (Parser.fromFold Fold.sum)) (Stream.enumerateFromTo 1 100)
327-- > lmap = Parser.lmapM return
331lmap :: MonadCatch m => (a -> b) -> Parser m b r -> Parser m a r
332lmap f p = D.toParserK $ D.lmap f $ D.fromParserK p
334-- | @lmapM f parser@ maps the monadic function @f@ on the input of the parser.
338lmapM :: MonadCatch m => (a -> m b) -> Parser m b r -> Parser m a r
339lmapM f p = D.toParserK $ D.lmapM f $ D.fromParserK p
341-- | Include only those elements that pass a predicate.
343-- >>> Stream.parse (Parser.filter (> 5) (Parser.fromFold Fold.sum)) $ Stream.fromList [1..10]
348filter :: MonadCatch m => (a -> Bool) -> Parser m a b -> Parser m a b
349filter f p = D.toParserK $ D.filter f $ D.fromParserK p
351-------------------------------------------------------------------------------
353-------------------------------------------------------------------------------
355-- | Peek the head element of a stream, without consuming it. Fails if it
356-- encounters end of input.
358-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
362-- peek = lookAhead (satisfy True)
368peek :: MonadCatch m => Parser m a a
369peek = D.toParserK D.peek
371-- | Succeeds if we are at the end of input, fails otherwise.
373-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
379eof :: MonadCatch m => Parser m a ()
380eof = D.toParserK D.eof
382-- | Returns the next element if it passes the predicate, fails otherwise.
384-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
389{-# INLINE satisfy #-}
390satisfy :: MonadCatch m => (a -> Bool) -> Parser m a a
391satisfy = D.toParserK . D.satisfy
393-- | Return the next element of the input. Returns 'Nothing'
394-- on end of input. Also known as 'head'.
399next :: MonadCatch m => Parser m a (Maybe a)
400next = D.toParserK D.next
402-- | Map a 'Maybe' returning function on the next element in the stream. The
403-- parser fails if the function returns 'Nothing' otherwise returns the 'Just'
409maybe :: MonadCatch m => (a -> Maybe b) -> Parser m a b
410maybe = D.toParserK . D.maybe
412-- | Map an 'Either' returning function on the next element in the stream. If
413-- the function returns 'Left err', the parser fails with the error message
414-- @err@ otherwise returns the 'Right' value.
419either :: MonadCatch m => (a -> Either String b) -> Parser m a b
420either = D.toParserK . D.either
422-------------------------------------------------------------------------------
424-------------------------------------------------------------------------------
426-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
427-- elements and folds them using the supplied fold.
429-- Stops after @n@ elements.
430-- Fails if the stream ends before @m@ elements could be taken.
436-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
437-- where prsr = Parser.takeBetween low high Fold.toList
442-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
445-- >>> takeBetween' 2 4 [1, 2]
448-- >>> takeBetween' 2 4 [1]
449-- *** Exception: ParseError "takeBetween: Expecting alteast 2 elements, got 1"
451-- >>> takeBetween' 0 0 [1, 2]
454-- >>> takeBetween' 0 1 []
457-- @takeBetween@ is the most general take operation, other take operations can
458-- be defined in terms of takeBetween. For example:
461-- take = takeBetween 0 n -- equivalent of take
462-- take1 = takeBetween 1 n -- equivalent of takeLE1
463-- takeEQ = takeBetween n n
464-- takeGE = takeBetween n maxBound
469{-# INLINE takeBetween #-}
470takeBetween :: MonadCatch m =>
471 Int -> Int -> Fold m a b -> Parser m a b
472takeBetween m n = D.toParserK . D.takeBetween m n
474-- | Stops after taking exactly @n@ input elements.
476-- * Stops - after consuming @n@ elements.
477-- * Fails - if the stream or the collecting fold ends before it can collect
478-- exactly @n@ elements.
480-- >>> Stream.parse (Parser.takeEQ 4 Fold.toList) $ Stream.fromList [1,0,1]
481-- *** Exception: ParseError "takeEQ: Expecting exactly 4 elements, input terminated on 3"
486takeEQ :: MonadCatch m => Int -> Fold m a b -> Parser m a b
487takeEQ n = D.toParserK . D.takeEQ n
489-- | Take at least @n@ input elements, but can collect more.
491-- * Stops - when the collecting fold stops.
492-- * Fails - if the stream or the collecting fold ends before producing @n@
495-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1]
496-- *** Exception: ParseError "takeGE: Expecting at least 4 elements, input terminated on 3"
498-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
504takeGE :: MonadCatch m => Int -> Fold m a b -> Parser m a b
505takeGE n = D.toParserK . D.takeGE n
507-------------------------------------------------------------------------------
508-- Take until a condition
509-------------------------------------------------------------------------------
512-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
514-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
515-- input. The combinator stops when the condition fails or if the collecting
518-- This is a generalized version of takeWhile, for example 'takeWhile1' can be
519-- implemented in terms of this:
522-- takeWhile1 cond p = takeWhile cond (takeBetween 1 maxBound p)
525-- Stops: when the condition fails or the collecting parser stops.
526-- Fails: when the collecting parser fails.
530{-# INLINE takeWhileP #-}
531takeWhileP :: -- MonadCatch m =>
532 (a -> Bool) -> Parser m a b -> Parser m a b
533takeWhileP _cond = undefined -- D.toParserK . D.takeWhileP cond
535-- | Collect stream elements until an element fails the predicate. The element
536-- on which the predicate fails is returned back to the input stream.
538-- * Stops - when the predicate fails or the collecting fold stops.
541-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
544-- We can implement a @breakOn@ using 'takeWhile':
547-- breakOn p = takeWhile (not p)
552{-# INLINE takeWhile #-}
553takeWhile :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
554takeWhile cond = D.toParserK . D.takeWhile cond
556-- | Like 'takeWhile' but takes at least one element otherwise fails.
560{-# INLINE takeWhile1 #-}
561takeWhile1 :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
562takeWhile1 cond = D.toParserK . D.takeWhile1 cond
564-- | Drain the input as long as the predicate succeeds, running the effects and
565-- discarding the results.
567-- This is also called @skipWhile@ in some parsing libraries.
571{-# INLINE drainWhile #-}
572drainWhile :: MonadCatch m => (a -> Bool) -> Parser m a ()
573drainWhile p = takeWhile p FL.drain
575-------------------------------------------------------------------------------
577-------------------------------------------------------------------------------
579-- | @sliceSepByP cond parser@ parses a slice of the input using @parser@ until
580-- @cond@ succeeds or the parser stops.
582-- This is a generalized slicing parser which can be used to implement other
586-- sliceSepByMax cond n p = sliceSepByP cond (take n p)
587-- sliceSepByBetween cond m n p = sliceSepByP cond (takeBetween m n p)
592{-# INLINE sliceSepByP #-}
595 (a -> Bool) -> Parser m a b -> Parser m a b
596sliceSepByP cond = D.toParserK . D.sliceSepByP cond . D.fromParserK
598-- | Like 'sliceSepBy' but does not drop the separator element, instead
599-- separator is emitted as a separate element in the output.
602{-# INLINE sliceSepWith #-}
603sliceSepWith :: -- MonadCatch m =>
604 (a -> Bool) -> Fold m a b -> Parser m a b
605sliceSepWith _cond = undefined -- D.toParserK . D.sliceSepBy cond
607-- | Collect stream elements until an elements passes the predicate, return the
608-- last element on which the predicate succeeded back to the input stream. If
609-- the predicate succeeds on the first element itself then the parser does not
610-- terminate there. The succeeding element in the leading position
611-- is treated as a prefix separator which is kept in the output segment.
613-- * Stops - when the predicate succeeds in non-leading position.
616-- S.splitWithPrefix pred f = S.parseMany (PR.sliceBeginWith pred f)
621-- sliceBeginWithOdd ls = Stream.parse prsr (Stream.fromList ls)
622-- where prsr = Parser.sliceBeginWith odd Fold.toList
626-- >>> sliceBeginWithOdd [2, 4, 6, 3]
627-- *** Exception: sliceBeginWith : slice begins with an element which fails the predicate
630-- >>> sliceBeginWithOdd [3, 5, 7, 4]
633-- >>> sliceBeginWithOdd [3, 4, 6, 8, 5]
636-- >>> sliceBeginWithOdd []
641{-# INLINE sliceBeginWith #-}
644 (a -> Bool) -> Fold m a b -> Parser m a b
645sliceBeginWith cond = D.toParserK . D.sliceBeginWith cond
647-------------------------------------------------------------------------------
648-- Quoting and Escaping
649-------------------------------------------------------------------------------
651-- | Like 'sliceSepBy' but the separator elements can be escaped using an
652-- escape char determined by the second predicate.
655{-# INLINE escapedSliceSepBy #-}
656escapedSliceSepBy :: -- MonadCatch m =>
657 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
658escapedSliceSepBy _cond _esc = undefined
659 -- D.toParserK . D.escapedSliceSepBy cond esc
661-- | @escapedFrameBy begin end escape@ parses a string framed using @begin@ and
662-- @end@ as the frame begin and end marker elements and @escape@ as an escaping
663-- element to escape the occurrence of the framing elements within the frame.
664-- Nested frames are allowed, but nesting is removed when parsing.
669-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello}"
672-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello {world}}"
675-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello \\{world\\}}"
678-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello {world}"
679-- ParseError "Unterminated '{'"
684{-# INLINE escapedFrameBy #-}
685escapedFrameBy :: -- MonadCatch m =>
686 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
687escapedFrameBy _begin _end _escape _p = undefined
688 -- D.toParserK . D.frameBy begin end escape p
690-------------------------------------------------------------------------------
692-------------------------------------------------------------------------------
694-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
695-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
696-- @["a","b"]@. In other words, its like parsing words from whitespace
699-- * Stops - when it finds a word separator after a non-word element
703-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
707wordBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
708wordBy f = D.toParserK . D.wordBy f
710-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
711-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
712-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
713-- then @c@ is also assigned to the same group and so on. When the comparison
714-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
715-- the result of the fold is the result of the parser.
717-- * Stops - when the comparison fails.
723-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
727-- >>> runGroupsBy (<) []
730-- >>> runGroupsBy (<) [1]
733-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
734-- [[3,5,4],[1,2],[0]]
738{-# INLINE groupBy #-}
739groupBy :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
740groupBy eq = D.toParserK . D.groupBy eq
742-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
743-- successive elements in the input stream. Assuming the input stream
744-- is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
745-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
746-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
747-- then @c@ is also assigned to the same group and so on. When the comparison
748-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
749-- the result of the fold is the result of the parser.
751-- * Stops - when the comparison fails.
755-- runGroupsByRolling eq =
757-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
761-- >>> runGroupsByRolling (<) []
764-- >>> runGroupsByRolling (<) [1]
767-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
768-- [[3,5],[4],[1,2],[0]]
772{-# INLINE groupByRolling #-}
773groupByRolling :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
774groupByRolling eq = D.toParserK . D.groupByRolling eq
776-- | Like 'groupByRolling', but if the predicate is 'True' then collects using
777-- the first fold as long as the predicate holds 'True', if the predicate is
778-- 'False' collects using the second fold as long as it remains 'False'.
779-- Returns 'Left' for the first case and 'Right' for the second case.
781-- For example, if we want to detect sorted sequences in a stream, both
782-- ascending and descending cases we can use 'groupByRollingEither (<=)
783-- Fold.toList Fold.toList'.
786{-# INLINE groupByRollingEither #-}
787groupByRollingEither :: MonadCatch m =>
788 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (Either b c)
789groupByRollingEither eq f1 = D.toParserK . D.groupByRollingEither eq f1
791-- XXX Use a stream instead of a list so that we can use any container type.
793-- | Match the given sequence of elements using the given comparison function.
795-- >>> Stream.parse (Parser.eqBy (==) "string") $ Stream.fromList "string"
797-- >>> Stream.parse (Parser.eqBy (==) "mismatch") $ Stream.fromList "match"
798-- *** Exception: ParseError "eqBy: failed, yet to match 7 elements"
803eqBy :: MonadCatch m => (a -> a -> Bool) -> [a] -> Parser m a ()
804eqBy cmp = D.toParserK . D.eqBy cmp
806-------------------------------------------------------------------------------
808-------------------------------------------------------------------------------
810-- | Sequential parser application. Apply two parsers sequentially to an input
811-- stream. The input is provided to the first parser, when it is done the
812-- remaining input is provided to the second parser. If both the parsers
813-- succeed their outputs are combined using the supplied function. The
814-- operation fails if any of the parsers fail.
816-- Note: This is a parsing dual of appending streams using
817-- 'Streamly.Prelude.serial', it splits the streams using two parsers and zips
820-- This implementation is strict in the second argument, therefore, the
821-- following will fail:
823-- >>> Stream.parse (Parser.serialWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
824-- *** Exception: Prelude.undefined
827-- Compare with 'Applicative' instance method '<*>'. This implementation allows
828-- stream fusion but has quadratic complexity. This can fuse with other
829-- operations and can be faster than 'Applicative' instance for small number
830-- (less than 8) of compositions.
832-- Many combinators can be expressed using @serialWith@ and other parser
833-- primitives. Some common idioms are described below,
836-- span :: (a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
837-- span pred f1 f2 = serialWith (,) ('takeWhile' pred f1) ('fromFold' f2)
841-- spanBy :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
842-- spanBy eq f1 f2 = serialWith (,) ('groupBy' eq f1) ('fromFold' f2)
846-- spanByRolling :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
847-- spanByRolling eq f1 f2 = serialWith (,) ('groupByRolling' eq f1) ('fromFold' f2)
852{-# INLINE serialWith #-}
853serialWith :: MonadCatch m
854 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
856 D.toParserK $ D.serialWith f (D.fromParserK p1) (D.fromParserK p2)
858-- | Sequential parser application ignoring the output of the first parser.
859-- Apply two parsers sequentially to an input stream. The input is provided to
860-- the first parser, when it is done the remaining input is provided to the
861-- second parser. The output of the parser is the output of the second parser.
862-- The operation fails if any of the parsers fail.
864-- This implementation is strict in the second argument, therefore, the
865-- following will fail:
867-- >>> Stream.parse (Parser.split_ (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
868-- *** Exception: Prelude.undefined
871-- Compare with 'Applicative' instance method '*>'. This implementation allows
872-- stream fusion but has quadratic complexity. This can fuse with other
873-- operations, and can be faster than 'Applicative' instance for small
874-- number (less than 8) of compositions.
879split_ :: MonadCatch m => Parser m x a -> Parser m x b -> Parser m x b
880split_ p1 p2 = D.toParserK $ D.split_ (D.fromParserK p1) (D.fromParserK p2)
882-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
883-- of them succeed or anyone of them fails and combines their output using @f@.
884-- The parser succeeds if both the parsers succeed.
888{-# INLINE teeWith #-}
889teeWith :: MonadCatch m
890 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
892 D.toParserK $ D.teeWith f (D.fromParserK p1) (D.fromParserK p2)
894-- | Like 'teeWith' but ends parsing and zips the results, if available,
895-- whenever the first parser ends.
899{-# INLINE teeWithFst #-}
900teeWithFst :: MonadCatch m
901 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
903 D.toParserK $ D.teeWithFst f (D.fromParserK p1) (D.fromParserK p2)
905-- | Like 'teeWith' but ends parsing and zips the results, if available,
906-- whenever any of the parsers ends or fails.
910{-# INLINE teeWithMin #-}
911teeWithMin :: MonadCatch m
912 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
914 D.toParserK $ D.teeWithMin f (D.fromParserK p1) (D.fromParserK p2)
916-- | Sequential alternative. Apply the input to the first parser and return the
917-- result if the parser succeeds. If the first parser fails then backtrack and
918-- apply the same input to the second parser and return the result.
920-- Note: This implementation is not lazy in the second argument. The following
923-- >>> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
926-- Compare with 'Alternative' instance method '<|>'. This implementation allows
927-- stream fusion but has quadratic complexity. This can fuse with other
928-- operations and can be much faster than 'Alternative' instance for small
929-- number (less than 8) of alternatives.
934alt :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
935alt p1 p2 = D.toParserK $ D.alt (D.fromParserK p1) (D.fromParserK p2)
937-- | Shortest alternative. Apply both parsers in parallel but choose the result
938-- from the one which consumed least input i.e. take the shortest succeeding
943{-# INLINE shortest #-}
944shortest :: MonadCatch m
945 => Parser m x a -> Parser m x a -> Parser m x a
946shortest p1 p2 = D.toParserK $ D.shortest (D.fromParserK p1) (D.fromParserK p2)
948-- | Longest alternative. Apply both parsers in parallel but choose the result
949-- from the one which consumed more input i.e. take the longest succeeding
954{-# INLINE longest #-}
955longest :: MonadCatch m
956 => Parser m x a -> Parser m x a -> Parser m x a
957longest p1 p2 = D.toParserK $ D.longest (D.fromParserK p1) (D.fromParserK p2)
959-- | Run a parser without consuming the input.
963{-# INLINE lookAhead #-}
964lookAhead :: MonadCatch m => Parser m a b -> Parser m a b
965lookAhead p = D.toParserK $ D.lookAhead $ D.fromParserK p
967-- | Takes at-most @n@ input elements.
969-- * Stops - when the collecting parser stops.
970-- * Fails - when the collecting parser fails.
972-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
975-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
976-- *** Exception: ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4"
980takeP :: MonadCatch m => Int -> Parser m a b -> Parser m a b
981takeP i p = D.toParserK $ D.takeP i $ D.fromParserK p
983-------------------------------------------------------------------------------
984-- Sequential Collection
985-------------------------------------------------------------------------------
987-- | @concatSequence f t@ collects sequential parses of parsers in the
988-- container @t@ using the fold @f@. Fails if the input ends or any of the
991-- This is same as 'Data.Traversable.sequence' but more efficient.
995{-# INLINE concatSequence #-}
998 Fold m b c -> t (Parser m a b) -> Parser m a c
999concatSequence _f _p = undefined
1001-- | Map a 'Parser' returning function on the result of a 'Parser'.
1003-- Compare with 'Monad' instance method '>>='. This implementation allows
1004-- stream fusion but has quadratic complexity. This can fuse with other
1005-- operations and can be much faster than 'Monad' instance for small number
1006-- (less than 8) of compositions.
1010{-# INLINE concatMap #-}
1011concatMap :: MonadCatch m
1012 => (b -> Parser m a c) -> Parser m a b -> Parser m a c
1013concatMap f p = D.toParserK $ D.concatMap (D.fromParserK . f) (D.fromParserK p)
1015-------------------------------------------------------------------------------
1016-- Alternative Collection
1017-------------------------------------------------------------------------------
1019-- | @choice parsers@ applies the @parsers@ in order and returns the first
1022-- This is same as 'asum' but more efficient.
1026{-# INLINE choice #-}
1028 (Functor t, Foldable t, MonadCatch m) => t (Parser m a b) -> Parser m a b
1029choice ps = D.toParserK $ D.choice $ D.fromParserK <$> ps
1031-------------------------------------------------------------------------------
1032-- Sequential Repetition
1033-------------------------------------------------------------------------------
1036-- TODO "many" is essentially a Fold because it cannot fail. So it can be
1037-- downgraded to a Fold. Or we can make the return type a Fold instead and
1038-- upgrade that to a parser when needed.
1040-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
1041-- results. Parsing stops or fails if the collecting parser stops or fails.
1046manyP :: -- MonadCatch m =>
1047 Parser m a b -> Parser m b c -> Parser m a c
1048manyP _p _f = undefined -- D.toParserK $ D.manyP (D.fromParserK p) f
1050-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
1051-- input stream and push the parse results to a downstream fold.
1053-- Stops: when the downstream fold stops or the parser fails.
1054-- Fails: never, produces zero or more results.
1056-- Compare with 'Control.Applicative.many'.
1061many :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1062many p f = D.toParserK $ D.many (D.fromParserK p) f
1063-- many = countBetween 0 maxBound
1065-- Note: many1 would perhaps be a better name for this and consistent with
1066-- other names like takeWhile1. But we retain the name "some" for
1069-- | Collect one or more parses. Apply the supplied parser repeatedly on the
1070-- input stream and push the parse results to a downstream fold.
1072-- Stops: when the downstream fold stops or the parser fails.
1073-- Fails: if it stops without producing a single result.
1075-- @some fld parser = manyP (takeGE 1 fld) parser@
1077-- Compare with 'Control.Applicative.some'.
1082some :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1083some p f = D.toParserK $ D.some (D.fromParserK p) f
1084-- some p f = manyP p (takeGE 1 f)
1085-- many = countBetween 1 maxBound
1087-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
1088-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
1089-- the input ends or the parser fails before @m@ results are collected.
1093{-# INLINE countBetween #-}
1096 Int -> Int -> Parser m a b -> Fold m b c -> Parser m a c
1097countBetween _m _n _p = undefined
1098-- countBetween m n p f = manyP (takeBetween m n f) p
1100-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
1101-- the fold @f@. Fails if the input ends or the parser fails before @n@
1102-- results are collected.
1109 Int -> Parser m a b -> Fold m b c -> Parser m a c
1110count n = countBetween n n
1111-- count n p f = manyP (takeEQ n f) p
1113-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
1114-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
1116-- We can implemnent parsers like the following using 'manyTillP':
1119-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
1124{-# INLINE manyTillP #-}
1125manyTillP :: -- MonadCatch m =>
1126 Parser m a b -> Parser m a x -> Parser m b c -> Parser m a c
1127manyTillP _p1 _p2 _f = undefined
1128 -- D.toParserK $ D.manyTillP (D.fromParserK p1) (D.fromParserK p2) f
1130-- | @manyTill f collect test@ tries the parser @test@ on the input, if @test@
1131-- fails it backtracks and tries @collect@, after @collect@ succeeds @test@ is
1132-- tried again and so on. The parser stops when @test@ succeeds. The output of
1133-- @test@ is discarded and the output of @collect@ is accumulated by the
1134-- supplied fold. The parser fails if @collect@ fails.
1136-- Stops when the fold @f@ stops.
1140{-# INLINE manyTill #-}
1141manyTill :: MonadCatch m
1142 => Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1144 D.toParserK $ D.manyTill f (D.fromParserK p1) (D.fromParserK p2)
1146-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
1147-- collects the output in the supplied fold. If the the parser @collect@ fails,
1148-- parser @recover@ is run until it stops and then we start repeating the
1149-- parser @collect@ again. The parser fails if the recovery parser fails.
1151-- For example, this can be used to find a key frame in a video stream after an
1156{-# INLINE manyThen #-}
1157manyThen :: -- (Foldable t, MonadCatch m) =>
1158 Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1159manyThen _parser _recover _f = undefined
1161-------------------------------------------------------------------------------
1163-------------------------------------------------------------------------------
1165-- To deinterleave we can chain two parsers one behind the other. The input is
1166-- given to the first parser and the input definitively rejected by the first
1167-- parser is given to the second parser.
1169-- We can either have the parsers themselves buffer the input or use the shared
1170-- global buffer to hold it until none of the parsers need it. When the first
1171-- parser returns Skip (i.e. rewind) we let the second parser consume the
1172-- rejected input and when it is done we move the cursor forward to the first
1173-- parser again. This will require a "move forward" command as well.
1175-- To implement grep we can use three parsers, one to find the pattern, one
1176-- to store the context behind the pattern and one to store the context in
1177-- front of the pattern. When a match occurs we need to emit the accumulator of
1178-- all the three parsers. One parser can count the line numbers to provide the
1181-- | Apply two parsers alternately to an input stream. The input stream is
1182-- considered an interleaving of two patterns. The two parsers represent the
1185-- This undoes a "gintercalate" of two streams.
1189{-# INLINE deintercalate #-}
1192 Fold m a y -> Parser m x a
1193 -> Fold m b z -> Parser m x b
1194 -> Parser m x (y, z)
1195deintercalate = undefined
1197-- | Parse items separated by a separator parsed by the supplied parser. At
1198-- least one item must be present for the parser to succeed.
1199{-# INLINE sepBy1 #-}
1200sepBy1 :: MonadCatch m =>
1201 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1202sepBy1 sink p sep = do
1204 f <- fromEffect $ FL.initialize sink
1205 f1 <- fromEffect $ FL.snoc f x
1208-- | sepBy1 or empty, does not fail.
1210sepBy :: (MonadCatch m, Monoid c) =>
1211 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1212sepBy sink p sep = sepBy1 sink p sep <|> return mempty
1214-------------------------------------------------------------------------------
1215-- Interleaving a collection of parsers
1216-------------------------------------------------------------------------------
1218-- | Apply a collection of parsers to an input stream in a round robin fashion.
1219-- Each parser is applied until it stops and then we repeat starting with the
1220-- the first parser again.
1224{-# INLINE roundRobin #-}
1225roundRobin :: -- (Foldable t, MonadCatch m) =>
1226 t (Parser m a b) -> Fold m b c -> Parser m a c
1227roundRobin _ps _f = undefined
1229-------------------------------------------------------------------------------
1230-- Repeated Alternatives
1231-------------------------------------------------------------------------------
1233-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
1234-- fails the input consumed till now is dropped and the new instance is tried
1235-- on the fresh input.
1239{-# INLINE retryMaxTotal #-}
1240retryMaxTotal :: -- (MonadCatch m) =>
1241 Int -> Parser m a b -> Fold m b c -> Parser m a c
1242retryMaxTotal _n _p _f = undefined
1244-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
1248{-# INLINE retryMaxSuccessive #-}
1249retryMaxSuccessive :: -- (MonadCatch m) =>
1250 Int -> Parser m a b -> Fold m b c -> Parser m a c
1251retryMaxSuccessive _n _p _f = undefined
1253-- | Keep trying a parser until it succeeds. When the parser fails the input
1254-- consumed till now is dropped and the new instance is tried on the fresh
1260retry :: -- (MonadCatch m) =>
1261 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