on 62e9f2e help sign in
1272 lines 42 kB history raw
1{-# OPTIONS_GHC -Wno-orphans #-}
3-- |
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
9-- Portability : GHC
10--
11-- Fast backtracking parsers with stream fusion and native streaming
12-- capability.
13--
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:
20--
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.
27--
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.
32--
33-- = Errors
34--
35-- Failing parsers in this module throw the 'D.ParseError' exception.
36--
37-- = Naming
38--
39-- As far as possible, try that the names of the combinators in this module are
40-- consistent with:
41--
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
49 (
50 K.Parser (..)
51 , D.ParseError (..)
52 , D.Step (..)
54 -- * Downgrade to Fold
55 , toFold
57 -- First order parsers
58 -- * Accumulators
59 , fromFold
60 , fromPure
61 , fromEffect
62 , die
63 , dieM
65 -- * Map on input
66 , lmap
67 , lmapM
68 , filter
70 -- * Element parsers
71 , peek
72 , eof
73 , satisfy
74 , next
75 , maybe
76 , either
78 -- * Sequence parsers
79 --
80 -- | Parsers chained in series, if one parser terminates the composition
81 -- terminates.
83 -- | Grab a sequence of input elements without inspecting them
84 , takeBetween
85 -- , take -- takeBetween 0 n
86 , takeEQ -- takeBetween n n
87 , takeGE -- takeBetween n maxBound
88 , takeP
90 -- Grab a sequence of input elements by inspecting them
91 , eqBy
92 , list
93 , lookAhead
94 , takeWhileP
95 , takeWhile
96 -- $takeWhile
97 , takeWhile1
98 , drainWhile
100 -- Separators
101 , sliceSepByP
102 , sliceBeginWith
103 , sliceSepWith
105 -- Quoting and Escaping
106 , escapedSliceSepBy
107 , escapedFrameBy
109 -- Words and grouping
110 , wordBy
111 , groupBy
112 , groupByRolling
113 , groupByRollingEither
115 -- | Unimplemented
116 --
117 -- @
118 -- , prefixOf -- match any prefix of a given string
119 -- , suffixOf -- match any suffix of a given string
120 -- , infixOf -- match any substring of a given string
121 -- @
123 -- Second order parsers (parsers using parsers)
124 -- * Binary Combinators
126 -- ** Sequential Applicative
127 , serialWith
128 , split_
130 -- ** Parallel Applicatives
131 , teeWith
132 , teeWithFst
133 , teeWithMin
134 -- , teeTill -- like manyTill but parallel
136 -- ** Sequential Interleaving
137 -- Use two folds, run a primary parser, its rejected values go to the
138 -- secondary parser.
139 , deintercalate
141 -- ** Sequential Alternative
142 , alt
144 -- ** Parallel Alternatives
145 , shortest
146 , longest
147 -- , fastest
149 -- * N-ary Combinators
150 -- ** Sequential Collection
151 , concatSequence
152 , concatMap
154 -- ** Sequential Repetition
155 , count
156 , countBetween
158 , manyP
159 , many
160 , some
161 , manyTillP
162 , manyTill
163 , manyThen
165 -- ** Special cases
166 -- | TODO: traditional implmentations of these may be of limited use. For
167 -- example, consider parsing lines separated by @\\r\\n@. The main parser
168 -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
169 -- can apply the "sep" parser.
170 --
171 -- We can instead implement these as special cases of deintercalate.
172 --
173 -- @
174 -- , endBy
175 , sepBy1
176 , sepBy
177 -- , sepEndBy
178 -- , beginBy
179 -- , sepBeginBy
180 -- , sepAroundBy
181 -- @
183 -- * Distribution
184 --
185 -- | A simple and stupid impl would be to just convert the stream to an
186 -- array and give the array reference to all consumers. The array can be
187 -- grown on demand by any consumer and truncated when nonbody needs it.
189 -- ** Distribute to collection
190 -- ** Distribute to repetition
192 -- ** Interleaved collection
193 -- |
194 --
195 -- 1. Round robin
196 -- 2. Priority based
197 , roundRobin
199 -- ** Collection of Alternatives
200 -- | Unimplemented
201 --
202 -- @
203 -- , shortestN
204 -- , longestN
205 -- , fastestN -- first N successful in time
206 -- , choiceN -- first N successful in position
207 -- @
208 , choice -- first successful in position
210 -- ** Repeated Alternatives
211 , retryMaxTotal
212 , retryMaxSuccessive
213 , retry
214 )
215where
217import Control.Applicative ((<|>))
218import Control.Monad.Catch (MonadCatch, MonadThrow)
219import Data.Functor (($>))
220import Prelude hiding
221 (any, all, take, takeWhile, sequence, concatMap, maybe, either, filter)
223import Streamly.Internal.Data.Fold.Type (Fold(..))
224import Streamly.Internal.Data.Parser.ParserK.Type (Parser)
226import qualified Streamly.Internal.Data.Fold.Type as FL
227import qualified Streamly.Internal.Data.Parser.ParserD as D
228import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
230--
231-- $setup
232-- >>> :m
233-- >>> :set -package streamly
234-- >>> import Prelude hiding (any, all, take, takeWhile, sequence, concatMap, maybe, either)
235-- >>> import qualified Streamly.Prelude as Stream
236-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, parseMany)
237-- >>> import qualified Streamly.Data.Fold as Fold
238-- >>> import qualified Streamly.Internal.Data.Parser as Parser
240-------------------------------------------------------------------------------
241-- Downgrade a parser to a Fold
242-------------------------------------------------------------------------------
243--
244-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
245-- parser fails or tries to backtrack.
246--
247-- This can be useful in combinators that accept a Fold and we know that a
248-- Parser cannot fail or failure exception is acceptable as there is no way to
249-- recover.
250--
251-- /Pre-release/
252--
253{-# INLINE toFold #-}
254toFold :: MonadThrow m => Parser m a b -> Fold m a b
255toFold p = D.toFold $ D.fromParserK p
257-------------------------------------------------------------------------------
258-- Upgrade folds to parses
259-------------------------------------------------------------------------------
260--
261-- | Make a 'Parser' from a 'Fold'.
262--
263-- /Pre-release/
264--
265{-# INLINE fromFold #-}
266fromFold :: MonadCatch m => Fold m a b -> Parser m a b
267fromFold = D.toParserK . D.fromFold
269-------------------------------------------------------------------------------
270-- Terminating but not failing folds
271-------------------------------------------------------------------------------
272--
273-- This is the dual of stream "fromPure".
274--
275-- | A parser that always yields a pure value without consuming any input.
276--
277-- /Pre-release/
278--
279{-# INLINE [3] fromPure #-}
280fromPure :: MonadCatch m => b -> Parser m a b
281fromPure = D.toParserK . D.fromPure
282{-# RULES "fromPure fallback to CPS" [2]
283 forall a. D.toParserK (D.fromPure a) = K.fromPure a #-}
285-- This is the dual of stream "fromEffect".
286--
287-- | A parser that always yields the result of an effectful action without
288-- consuming any input.
289--
290-- /Pre-release/
291--
292{-# INLINE fromEffect #-}
293fromEffect :: MonadCatch m => m b -> Parser m a b
294fromEffect = K.fromEffect -- D.toParserK . D.fromEffect
296-- This is the dual of "nil".
297--
298-- | A parser that always fails with an error message without consuming
299-- any input.
300--
301-- /Pre-release/
302--
303{-# INLINE [3] die #-}
304die :: MonadCatch m => String -> Parser m a b
305die = D.toParserK . D.die
306{-# RULES "die fallback to CPS" [2]
307 forall a. D.toParserK (D.die a) = K.die a #-}
309-- This is the dual of "nilM".
310--
311-- | A parser that always fails with an effectful error message and without
312-- consuming any input.
313--
314-- /Pre-release/
315--
316{-# INLINE dieM #-}
317dieM :: MonadCatch m => m String -> Parser m a b
318dieM = D.toParserK . D.dieM
320-------------------------------------------------------------------------------
321-- Map on input
322-------------------------------------------------------------------------------
324-- | @lmap f parser@ maps the function @f@ on the input of the parser.
325--
326-- >>> Stream.parse (Parser.lmap (\x -> x * x) (Parser.fromFold Fold.sum)) (Stream.enumerateFromTo 1 100)
327-- 338350
328--
329-- > lmap = Parser.lmapM return
330--
331-- /Internal/
332{-# INLINE lmap #-}
333lmap :: MonadCatch m => (a -> b) -> Parser m b r -> Parser m a r
334lmap f p = D.toParserK $ D.lmap f $ D.fromParserK p
336-- | @lmapM f parser@ maps the monadic function @f@ on the input of the parser.
337--
338-- /Internal/
339{-# INLINE lmapM #-}
340lmapM :: MonadCatch m => (a -> m b) -> Parser m b r -> Parser m a r
341lmapM f p = D.toParserK $ D.lmapM f $ D.fromParserK p
343-- | Include only those elements that pass a predicate.
344--
345-- >>> Stream.parse (Parser.filter (> 5) (Parser.fromFold Fold.sum)) $ Stream.fromList [1..10]
346-- 40
347--
348-- /Internal/
349{-# INLINE filter #-}
350filter :: MonadCatch m => (a -> Bool) -> Parser m a b -> Parser m a b
351filter f p = D.toParserK $ D.filter f $ D.fromParserK p
353-------------------------------------------------------------------------------
354-- Failing Parsers
355-------------------------------------------------------------------------------
357-- | Peek the head element of a stream, without consuming it. Fails if it
358-- encounters end of input.
359--
360-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
361-- (1,1)
362--
363-- @
364-- peek = lookAhead (satisfy True)
365-- @
366--
367-- /Pre-release/
368--
369{-# INLINE peek #-}
370peek :: MonadCatch m => Parser m a a
371peek = D.toParserK D.peek
373-- | Succeeds if we are at the end of input, fails otherwise.
374--
375-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
376-- (1,())
377--
378-- /Pre-release/
379--
380{-# INLINE eof #-}
381eof :: MonadCatch m => Parser m a ()
382eof = D.toParserK D.eof
384-- | Returns the next element if it passes the predicate, fails otherwise.
385--
386-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
387-- 1
388--
389-- /Pre-release/
390--
391{-# INLINE satisfy #-}
392satisfy :: MonadCatch m => (a -> Bool) -> Parser m a a
393satisfy = D.toParserK . D.satisfy
395-- | Return the next element of the input. Returns 'Nothing'
396-- on end of input. Also known as 'head'.
397--
398-- /Pre-release/
399--
400{-# INLINE next #-}
401next :: MonadCatch m => Parser m a (Maybe a)
402next = D.toParserK D.next
404-- | Map a 'Maybe' returning function on the next element in the stream. The
405-- parser fails if the function returns 'Nothing' otherwise returns the 'Just'
406-- value.
407--
408-- /Pre-release/
409--
410{-# INLINE maybe #-}
411maybe :: MonadCatch m => (a -> Maybe b) -> Parser m a b
412maybe = D.toParserK . D.maybe
414-- | Map an 'Either' returning function on the next element in the stream. If
415-- the function returns 'Left err', the parser fails with the error message
416-- @err@ otherwise returns the 'Right' value.
417--
418-- /Pre-release/
419--
420{-# INLINE either #-}
421either :: MonadCatch m => (a -> Either String b) -> Parser m a b
422either = D.toParserK . D.either
424-------------------------------------------------------------------------------
425-- Taking elements
426-------------------------------------------------------------------------------
428-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
429-- elements and folds them using the supplied fold.
430--
431-- Stops after @n@ elements.
432-- Fails if the stream ends before @m@ elements could be taken.
433--
434-- Examples: -
435--
436-- @
437-- >>> :{
438-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
439-- where prsr = Parser.takeBetween low high Fold.toList
440-- :}
441--
442-- @
443--
444-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
445-- [1,2,3,4]
446--
447-- >>> takeBetween' 2 4 [1, 2]
448-- [1,2]
449--
450-- >>> takeBetween' 2 4 [1]
451-- *** Exception: ParseError "takeBetween: Expecting alteast 2 elements, got 1"
452--
453-- >>> takeBetween' 0 0 [1, 2]
454-- []
455--
456-- >>> takeBetween' 0 1 []
457-- []
458--
459-- @takeBetween@ is the most general take operation, other take operations can
460-- be defined in terms of takeBetween. For example:
461--
462-- @
463-- take = takeBetween 0 n -- equivalent of take
464-- take1 = takeBetween 1 n -- equivalent of takeLE1
465-- takeEQ = takeBetween n n
466-- takeGE = takeBetween n maxBound
467-- @
468--
469-- /Pre-release/
470--
471{-# INLINE takeBetween #-}
472takeBetween :: MonadCatch m =>
473 Int -> Int -> Fold m a b -> Parser m a b
474takeBetween m n = D.toParserK . D.takeBetween m n
476-- | Stops after taking exactly @n@ input elements.
477--
478-- * Stops - after consuming @n@ elements.
479-- * Fails - if the stream or the collecting fold ends before it can collect
480-- exactly @n@ elements.
481--
482-- >>> Stream.parse (Parser.takeEQ 4 Fold.toList) $ Stream.fromList [1,0,1]
483-- *** Exception: ParseError "takeEQ: Expecting exactly 4 elements, input terminated on 3"
484--
485-- /Pre-release/
486--
487{-# INLINE takeEQ #-}
488takeEQ :: MonadCatch m => Int -> Fold m a b -> Parser m a b
489takeEQ n = D.toParserK . D.takeEQ n
491-- | Take at least @n@ input elements, but can collect more.
492--
493-- * Stops - when the collecting fold stops.
494-- * Fails - if the stream or the collecting fold ends before producing @n@
495-- elements.
496--
497-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1]
498-- *** Exception: ParseError "takeGE: Expecting at least 4 elements, input terminated on 3"
499--
500-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
501-- [1,0,1,0,1]
502--
503-- /Pre-release/
504--
505{-# INLINE takeGE #-}
506takeGE :: MonadCatch m => Int -> Fold m a b -> Parser m a b
507takeGE n = D.toParserK . D.takeGE n
509-------------------------------------------------------------------------------
510-- Take until a condition
511-------------------------------------------------------------------------------
513-- $takeWhile
514-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
516-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
517-- input. The combinator stops when the condition fails or if the collecting
518-- parser stops.
519--
520-- This is a generalized version of takeWhile, for example 'takeWhile1' can be
521-- implemented in terms of this:
522--
523-- @
524-- takeWhile1 cond p = takeWhile cond (takeBetween 1 maxBound p)
525-- @
526--
527-- Stops: when the condition fails or the collecting parser stops.
528-- Fails: when the collecting parser fails.
529--
530-- /Unimplemented/
531--
532{-# INLINE takeWhileP #-}
533takeWhileP :: -- MonadCatch m =>
534 (a -> Bool) -> Parser m a b -> Parser m a b
535takeWhileP _cond = undefined -- D.toParserK . D.takeWhileP cond
537-- | Collect stream elements until an element fails the predicate. The element
538-- on which the predicate fails is returned back to the input stream.
539--
540-- * Stops - when the predicate fails or the collecting fold stops.
541-- * Fails - never.
542--
543-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
544-- [0,0]
545--
546-- We can implement a @breakOn@ using 'takeWhile':
547--
548-- @
549-- breakOn p = takeWhile (not p)
550-- @
551--
552-- /Pre-release/
553--
554{-# INLINE takeWhile #-}
555takeWhile :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
556takeWhile cond = D.toParserK . D.takeWhile cond
558-- | Like 'takeWhile' but takes at least one element otherwise fails.
559--
560-- /Pre-release/
561--
562{-# INLINE takeWhile1 #-}
563takeWhile1 :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
564takeWhile1 cond = D.toParserK . D.takeWhile1 cond
566-- | Drain the input as long as the predicate succeeds, running the effects and
567-- discarding the results.
568--
569-- This is also called @skipWhile@ in some parsing libraries.
570--
571-- /Pre-release/
572--
573{-# INLINE drainWhile #-}
574drainWhile :: MonadCatch m => (a -> Bool) -> Parser m a ()
575drainWhile p = takeWhile p FL.drain
577-------------------------------------------------------------------------------
578-- Separators
579-------------------------------------------------------------------------------
581-- | @sliceSepByP cond parser@ parses a slice of the input using @parser@ until
582-- @cond@ succeeds or the parser stops.
583--
584-- This is a generalized slicing parser which can be used to implement other
585-- parsers e.g.:
586--
587-- @
588-- sliceSepByMax cond n p = sliceSepByP cond (take n p)
589-- sliceSepByBetween cond m n p = sliceSepByP cond (takeBetween m n p)
590-- @
591--
592-- /Pre-release/
593--
594{-# INLINE sliceSepByP #-}
595sliceSepByP ::
596 MonadCatch m =>
597 (a -> Bool) -> Parser m a b -> Parser m a b
598sliceSepByP cond = D.toParserK . D.sliceSepByP cond . D.fromParserK
600-- | Like 'sliceSepBy' but does not drop the separator element, instead
601-- separator is emitted as a separate element in the output.
602--
603-- /Unimplemented/
604{-# INLINE sliceSepWith #-}
605sliceSepWith :: -- MonadCatch m =>
606 (a -> Bool) -> Fold m a b -> Parser m a b
607sliceSepWith _cond = undefined -- D.toParserK . D.sliceSepBy cond
609-- | Collect stream elements until an elements passes the predicate, return the
610-- last element on which the predicate succeeded back to the input stream. If
611-- the predicate succeeds on the first element itself then the parser does not
612-- terminate there. The succeeding element in the leading position
613-- is treated as a prefix separator which is kept in the output segment.
614--
615-- * Stops - when the predicate succeeds in non-leading position.
616-- * Fails - never.
617--
618-- S.splitWithPrefix pred f = S.parseMany (PR.sliceBeginWith pred f)
619--
620-- Examples: -
621--
622-- >>> :{
623-- sliceBeginWithOdd ls = Stream.parse prsr (Stream.fromList ls)
624-- where prsr = Parser.sliceBeginWith odd Fold.toList
625-- :}
626--
627--
628-- >>> sliceBeginWithOdd [2, 4, 6, 3]
629-- *** Exception: sliceBeginWith : slice begins with an element which fails the predicate
630-- ...
631--
632-- >>> sliceBeginWithOdd [3, 5, 7, 4]
633-- [3]
634--
635-- >>> sliceBeginWithOdd [3, 4, 6, 8, 5]
636-- [3,4,6,8]
637--
638-- >>> sliceBeginWithOdd []
639-- []
640--
641-- /Pre-release/
642--
643{-# INLINE sliceBeginWith #-}
644sliceBeginWith ::
645 MonadCatch m =>
646 (a -> Bool) -> Fold m a b -> Parser m a b
647sliceBeginWith cond = D.toParserK . D.sliceBeginWith cond
649-------------------------------------------------------------------------------
650-- Quoting and Escaping
651-------------------------------------------------------------------------------
653-- | Like 'sliceSepBy' but the separator elements can be escaped using an
654-- escape char determined by the second predicate.
655--
656-- /Unimplemented/
657{-# INLINE escapedSliceSepBy #-}
658escapedSliceSepBy :: -- MonadCatch m =>
659 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
660escapedSliceSepBy _cond _esc = undefined
661 -- D.toParserK . D.escapedSliceSepBy cond esc
663-- | @escapedFrameBy begin end escape@ parses a string framed using @begin@ and
664-- @end@ as the frame begin and end marker elements and @escape@ as an escaping
665-- element to escape the occurrence of the framing elements within the frame.
666-- Nested frames are allowed, but nesting is removed when parsing.
667--
668-- For example,
669--
670-- @
671-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello}"
672-- "hello"
673--
674-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello {world}}"
675-- "hello world"
676--
677-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello \\{world\\}}"
678-- "hello {world}"
679--
680-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello {world}"
681-- ParseError "Unterminated '{'"
682--
683-- @
684--
685-- /Unimplemented/
686{-# INLINE escapedFrameBy #-}
687escapedFrameBy :: -- MonadCatch m =>
688 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
689escapedFrameBy _begin _end _escape _p = undefined
690 -- D.toParserK . D.frameBy begin end escape p
692-------------------------------------------------------------------------------
693-- Grouping and words
694-------------------------------------------------------------------------------
696-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
697-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
698-- @["a","b"]@. In other words, its like parsing words from whitespace
699-- separated text.
700--
701-- * Stops - when it finds a word separator after a non-word element
702-- * Fails - never.
703--
704-- @
705-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
706-- @
707--
708{-# INLINE wordBy #-}
709wordBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
710wordBy f = D.toParserK . D.wordBy f
712-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
713-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
714-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
715-- then @c@ is also assigned to the same group and so on. When the comparison
716-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
717-- the result of the fold is the result of the parser.
718--
719-- * Stops - when the comparison fails.
720-- * Fails - never.
721--
722-- >>> :{
723-- runGroupsBy eq =
724-- Stream.toList
725-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
726-- . Stream.fromList
727-- :}
728--
729-- >>> runGroupsBy (<) []
730-- []
731--
732-- >>> runGroupsBy (<) [1]
733-- [[1]]
734--
735-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
736-- [[3,5,4],[1,2],[0]]
737--
738-- /Pre-release/
739--
740{-# INLINE groupBy #-}
741groupBy :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
742groupBy eq = D.toParserK . D.groupBy eq
744-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
745-- successive elements in the input stream. Assuming the input stream
746-- is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
747-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
748-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
749-- then @c@ is also assigned to the same group and so on. When the comparison
750-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
751-- the result of the fold is the result of the parser.
752--
753-- * Stops - when the comparison fails.
754-- * Fails - never.
755--
756-- >>> :{
757-- runGroupsByRolling eq =
758-- Stream.toList
759-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
760-- . Stream.fromList
761-- :}
762--
763-- >>> runGroupsByRolling (<) []
764-- []
765--
766-- >>> runGroupsByRolling (<) [1]
767-- [[1]]
768--
769-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
770-- [[3,5],[4],[1,2],[0]]
771--
772-- /Pre-release/
773--
774{-# INLINE groupByRolling #-}
775groupByRolling :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
776groupByRolling eq = D.toParserK . D.groupByRolling eq
778-- | Like 'groupByRolling', but if the predicate is 'True' then collects using
779-- the first fold as long as the predicate holds 'True', if the predicate is
780-- 'False' collects using the second fold as long as it remains 'False'.
781-- Returns 'Left' for the first case and 'Right' for the second case.
782--
783-- For example, if we want to detect sorted sequences in a stream, both
784-- ascending and descending cases we can use 'groupByRollingEither (<=)
785-- Fold.toList Fold.toList'.
786--
787-- /Unimplemented/
788{-# INLINE groupByRollingEither #-}
789groupByRollingEither :: MonadCatch m =>
790 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (Either b c)
791groupByRollingEither eq f1 = D.toParserK . D.groupByRollingEither eq f1
793-- XXX Use a stream instead of a list so that we can use any container type.
795-- | Match the given sequence of elements using the given comparison function.
796--
797-- >>> Stream.parse (Parser.eqBy (==) "string") $ Stream.fromList "string"
798--
799-- >>> Stream.parse (Parser.eqBy (==) "mismatch") $ Stream.fromList "match"
800-- *** Exception: ParseError "eqBy: failed, yet to match 7 elements"
801--
802-- /Pre-release/
803--
804{-# INLINE eqBy #-}
805eqBy :: MonadCatch m => (a -> a -> Bool) -> [a] -> Parser m a ()
806eqBy cmp = D.toParserK . D.eqBy cmp
808-- | Match the input sequence with the supplied list and return it if
809-- successful.
810--
811-- /Pre-release/
812{-# INLINE list #-}
813list :: (MonadCatch m, Eq a) => [a] -> Parser m a [a]
814list xs = eqBy (==) xs $> xs
816-------------------------------------------------------------------------------
817-- nested parsers
818-------------------------------------------------------------------------------
820-- | Sequential parser application. Apply two parsers sequentially to an input
821-- stream. The input is provided to the first parser, when it is done the
822-- remaining input is provided to the second parser. If both the parsers
823-- succeed their outputs are combined using the supplied function. The
824-- operation fails if any of the parsers fail.
825--
826-- Note: This is a parsing dual of appending streams using
827-- 'Streamly.Prelude.serial', it splits the streams using two parsers and zips
828-- the results.
829--
830-- This implementation is strict in the second argument, therefore, the
831-- following will fail:
832--
833-- >>> Stream.parse (Parser.serialWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
834-- *** Exception: Prelude.undefined
835-- ...
836--
837-- Compare with 'Applicative' instance method '<*>'. This implementation allows
838-- stream fusion but has quadratic complexity. This can fuse with other
839-- operations and can be faster than 'Applicative' instance for small number
840-- (less than 8) of compositions.
841--
842-- Many combinators can be expressed using @serialWith@ and other parser
843-- primitives. Some common idioms are described below,
844--
845-- @
846-- span :: (a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
847-- span pred f1 f2 = serialWith (,) ('takeWhile' pred f1) ('fromFold' f2)
848-- @
849--
850-- @
851-- spanBy :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
852-- spanBy eq f1 f2 = serialWith (,) ('groupBy' eq f1) ('fromFold' f2)
853-- @
854--
855-- @
856-- spanByRolling :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
857-- spanByRolling eq f1 f2 = serialWith (,) ('groupByRolling' eq f1) ('fromFold' f2)
858-- @
859--
860-- /Pre-release/
861--
862{-# INLINE serialWith #-}
863serialWith :: MonadCatch m
864 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
865serialWith f p1 p2 =
866 D.toParserK $ D.serialWith f (D.fromParserK p1) (D.fromParserK p2)
868-- | Sequential parser application ignoring the output of the first parser.
869-- Apply two parsers sequentially to an input stream. The input is provided to
870-- the first parser, when it is done the remaining input is provided to the
871-- second parser. The output of the parser is the output of the second parser.
872-- The operation fails if any of the parsers fail.
873--
874-- This implementation is strict in the second argument, therefore, the
875-- following will fail:
876--
877-- >>> Stream.parse (Parser.split_ (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
878-- *** Exception: Prelude.undefined
879-- ...
880--
881-- Compare with 'Applicative' instance method '*>'. This implementation allows
882-- stream fusion but has quadratic complexity. This can fuse with other
883-- operations, and can be faster than 'Applicative' instance for small
884-- number (less than 8) of compositions.
885--
886-- /Pre-release/
887--
888{-# INLINE split_ #-}
889split_ :: MonadCatch m => Parser m x a -> Parser m x b -> Parser m x b
890split_ p1 p2 = D.toParserK $ D.split_ (D.fromParserK p1) (D.fromParserK p2)
892-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
893-- of them succeed or anyone of them fails and combines their output using @f@.
894-- The parser succeeds if both the parsers succeed.
895--
896-- /Pre-release/
897--
898{-# INLINE teeWith #-}
899teeWith :: MonadCatch m
900 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
901teeWith f p1 p2 =
902 D.toParserK $ D.teeWith f (D.fromParserK p1) (D.fromParserK p2)
904-- | Like 'teeWith' but ends parsing and zips the results, if available,
905-- whenever the first parser ends.
906--
907-- /Pre-release/
908--
909{-# INLINE teeWithFst #-}
910teeWithFst :: MonadCatch m
911 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
912teeWithFst f p1 p2 =
913 D.toParserK $ D.teeWithFst f (D.fromParserK p1) (D.fromParserK p2)
915-- | Like 'teeWith' but ends parsing and zips the results, if available,
916-- whenever any of the parsers ends or fails.
917--
918-- /Unimplemented/
919--
920{-# INLINE teeWithMin #-}
921teeWithMin :: MonadCatch m
922 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
923teeWithMin f p1 p2 =
924 D.toParserK $ D.teeWithMin f (D.fromParserK p1) (D.fromParserK p2)
926-- | Sequential alternative. Apply the input to the first parser and return the
927-- result if the parser succeeds. If the first parser fails then backtrack and
928-- apply the same input to the second parser and return the result.
929--
930-- Note: This implementation is not lazy in the second argument. The following
931-- will fail:
932--
933-- >>> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
934-- 1
935--
936-- Compare with 'Alternative' instance method '<|>'. This implementation allows
937-- stream fusion but has quadratic complexity. This can fuse with other
938-- operations and can be much faster than 'Alternative' instance for small
939-- number (less than 8) of alternatives.
940--
941-- /Pre-release/
942--
943{-# INLINE alt #-}
944alt :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
945alt p1 p2 = D.toParserK $ D.alt (D.fromParserK p1) (D.fromParserK p2)
947-- | Shortest alternative. Apply both parsers in parallel but choose the result
948-- from the one which consumed least input i.e. take the shortest succeeding
949-- parse.
950--
951-- /Pre-release/
952--
953{-# INLINE shortest #-}
954shortest :: MonadCatch m
955 => Parser m x a -> Parser m x a -> Parser m x a
956shortest p1 p2 = D.toParserK $ D.shortest (D.fromParserK p1) (D.fromParserK p2)
958-- | Longest alternative. Apply both parsers in parallel but choose the result
959-- from the one which consumed more input i.e. take the longest succeeding
960-- parse.
961--
962-- /Pre-release/
963--
964{-# INLINE longest #-}
965longest :: MonadCatch m
966 => Parser m x a -> Parser m x a -> Parser m x a
967longest p1 p2 = D.toParserK $ D.longest (D.fromParserK p1) (D.fromParserK p2)
969-- | Run a parser without consuming the input.
970--
971-- /Pre-release/
972--
973{-# INLINE lookAhead #-}
974lookAhead :: MonadCatch m => Parser m a b -> Parser m a b
975lookAhead p = D.toParserK $ D.lookAhead $ D.fromParserK p
977-- | Takes at-most @n@ input elements.
978--
979-- * Stops - when the collecting parser stops.
980-- * Fails - when the collecting parser fails.
981--
982-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
983-- [1,2]
984--
985-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
986-- *** Exception: ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4"
987--
988-- /Internal/
989{-# INLINE takeP #-}
990takeP :: MonadCatch m => Int -> Parser m a b -> Parser m a b
991takeP i p = D.toParserK $ D.takeP i $ D.fromParserK p
993-------------------------------------------------------------------------------
994-- Sequential Collection
995-------------------------------------------------------------------------------
996--
997-- | @concatSequence f t@ collects sequential parses of parsers in the
998-- container @t@ using the fold @f@. Fails if the input ends or any of the
999-- parsers fail.
1001-- This is same as 'Data.Traversable.sequence' but more efficient.
1003-- /Unimplemented/
1005{-# INLINE concatSequence #-}
1006concatSequence ::
1007 -- Foldable t =>
1008 Fold m b c -> t (Parser m a b) -> Parser m a c
1009concatSequence _f _p = undefined
1011-- | Map a 'Parser' returning function on the result of a 'Parser'.
1013-- Compare with 'Monad' instance method '>>='. This implementation allows
1014-- stream fusion but has quadratic complexity. This can fuse with other
1015-- operations and can be much faster than 'Monad' instance for small number
1016-- (less than 8) of compositions.
1018-- /Pre-release/
1020{-# INLINE concatMap #-}
1021concatMap :: MonadCatch m
1022 => (b -> Parser m a c) -> Parser m a b -> Parser m a c
1023concatMap f p = D.toParserK $ D.concatMap (D.fromParserK . f) (D.fromParserK p)
1025-------------------------------------------------------------------------------
1026-- Alternative Collection
1027-------------------------------------------------------------------------------
1029-- | @choice parsers@ applies the @parsers@ in order and returns the first
1030-- successful parse.
1032-- This is same as 'asum' but more efficient.
1034-- /Broken/
1036{-# INLINE choice #-}
1037choice ::
1038 (Functor t, Foldable t, MonadCatch m) => t (Parser m a b) -> Parser m a b
1039choice ps = D.toParserK $ D.choice $ D.fromParserK <$> ps
1041-------------------------------------------------------------------------------
1042-- Sequential Repetition
1043-------------------------------------------------------------------------------
1045-- $many
1046-- TODO "many" is essentially a Fold because it cannot fail. So it can be
1047-- downgraded to a Fold. Or we can make the return type a Fold instead and
1048-- upgrade that to a parser when needed.
1050-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
1051-- results. Parsing stops or fails if the collecting parser stops or fails.
1053-- /Unimplemented/
1055{-# INLINE manyP #-}
1056manyP :: -- MonadCatch m =>
1057 Parser m a b -> Parser m b c -> Parser m a c
1058manyP _p _f = undefined -- D.toParserK $ D.manyP (D.fromParserK p) f
1060-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
1061-- input stream and push the parse results to a downstream fold.
1063-- Stops: when the downstream fold stops or the parser fails.
1064-- Fails: never, produces zero or more results.
1066-- Compare with 'Control.Applicative.many'.
1068-- /Pre-release/
1070{-# INLINE many #-}
1071many :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1072many p f = D.toParserK $ D.many (D.fromParserK p) f
1073-- many = countBetween 0 maxBound
1075-- Note: many1 would perhaps be a better name for this and consistent with
1076-- other names like takeWhile1. But we retain the name "some" for
1077-- compatibility.
1079-- | Collect one or more parses. Apply the supplied parser repeatedly on the
1080-- input stream and push the parse results to a downstream fold.
1082-- Stops: when the downstream fold stops or the parser fails.
1083-- Fails: if it stops without producing a single result.
1085-- @some fld parser = manyP (takeGE 1 fld) parser@
1087-- Compare with 'Control.Applicative.some'.
1089-- /Pre-release/
1091{-# INLINE some #-}
1092some :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1093some p f = D.toParserK $ D.some (D.fromParserK p) f
1094-- some p f = manyP p (takeGE 1 f)
1095-- many = countBetween 1 maxBound
1097-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
1098-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
1099-- the input ends or the parser fails before @m@ results are collected.
1101-- /Unimplemented/
1103{-# INLINE countBetween #-}
1104countBetween ::
1105 -- MonadCatch m =>
1106 Int -> Int -> Parser m a b -> Fold m b c -> Parser m a c
1107countBetween _m _n _p = undefined
1108-- countBetween m n p f = manyP (takeBetween m n f) p
1110-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
1111-- the fold @f@. Fails if the input ends or the parser fails before @n@
1112-- results are collected.
1114-- /Unimplemented/
1116{-# INLINE count #-}
1117count ::
1118 -- MonadCatch m =>
1119 Int -> Parser m a b -> Fold m b c -> Parser m a c
1120count n = countBetween n n
1121-- count n p f = manyP (takeEQ n f) p
1123-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
1124-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
1126-- We can implemnent parsers like the following using 'manyTillP':
1128-- @
1129-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
1130-- @
1132-- /Unimplemented/
1134{-# INLINE manyTillP #-}
1135manyTillP :: -- MonadCatch m =>
1136 Parser m a b -> Parser m a x -> Parser m b c -> Parser m a c
1137manyTillP _p1 _p2 _f = undefined
1138 -- D.toParserK $ D.manyTillP (D.fromParserK p1) (D.fromParserK p2) f
1140-- | @manyTill f collect test@ tries the parser @test@ on the input, if @test@
1141-- fails it backtracks and tries @collect@, after @collect@ succeeds @test@ is
1142-- tried again and so on. The parser stops when @test@ succeeds. The output of
1143-- @test@ is discarded and the output of @collect@ is accumulated by the
1144-- supplied fold. The parser fails if @collect@ fails.
1146-- Stops when the fold @f@ stops.
1148-- /Pre-release/
1150{-# INLINE manyTill #-}
1151manyTill :: MonadCatch m
1152 => Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1153manyTill p1 p2 f =
1154 D.toParserK $ D.manyTill f (D.fromParserK p1) (D.fromParserK p2)
1156-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
1157-- collects the output in the supplied fold. If the the parser @collect@ fails,
1158-- parser @recover@ is run until it stops and then we start repeating the
1159-- parser @collect@ again. The parser fails if the recovery parser fails.
1161-- For example, this can be used to find a key frame in a video stream after an
1162-- error.
1164-- /Unimplemented/
1166{-# INLINE manyThen #-}
1167manyThen :: -- (Foldable t, MonadCatch m) =>
1168 Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1169manyThen _parser _recover _f = undefined
1171-------------------------------------------------------------------------------
1172-- Interleaving
1173-------------------------------------------------------------------------------
1175-- To deinterleave we can chain two parsers one behind the other. The input is
1176-- given to the first parser and the input definitively rejected by the first
1177-- parser is given to the second parser.
1179-- We can either have the parsers themselves buffer the input or use the shared
1180-- global buffer to hold it until none of the parsers need it. When the first
1181-- parser returns Skip (i.e. rewind) we let the second parser consume the
1182-- rejected input and when it is done we move the cursor forward to the first
1183-- parser again. This will require a "move forward" command as well.
1185-- To implement grep we can use three parsers, one to find the pattern, one
1186-- to store the context behind the pattern and one to store the context in
1187-- front of the pattern. When a match occurs we need to emit the accumulator of
1188-- all the three parsers. One parser can count the line numbers to provide the
1189-- line number info.
1191-- | Apply two parsers alternately to an input stream. The input stream is
1192-- considered an interleaving of two patterns. The two parsers represent the
1193-- two patterns.
1195-- This undoes a "gintercalate" of two streams.
1197-- /Unimplemented/
1199{-# INLINE deintercalate #-}
1200deintercalate ::
1201 -- Monad m =>
1202 Fold m a y -> Parser m x a
1203 -> Fold m b z -> Parser m x b
1204 -> Parser m x (y, z)
1205deintercalate = undefined
1207-- | Parse items separated by a separator parsed by the supplied parser. At
1208-- least one item must be present for the parser to succeed.
1209{-# INLINE sepBy1 #-}
1210sepBy1 :: MonadCatch m =>
1211 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1212sepBy1 sink p sep = do
1213 x <- p
1214 f <- fromEffect $ FL.initialize sink
1215 f1 <- fromEffect $ FL.snoc f x
1216 many (sep >> p) f1
1218-- | sepBy1 or empty, does not fail.
1219{-# INLINE sepBy #-}
1220sepBy :: (MonadCatch m, Monoid c) =>
1221 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1222sepBy sink p sep = sepBy1 sink p sep <|> return mempty
1224-------------------------------------------------------------------------------
1225-- Interleaving a collection of parsers
1226-------------------------------------------------------------------------------
1228-- | Apply a collection of parsers to an input stream in a round robin fashion.
1229-- Each parser is applied until it stops and then we repeat starting with the
1230-- the first parser again.
1232-- /Unimplemented/
1234{-# INLINE roundRobin #-}
1235roundRobin :: -- (Foldable t, MonadCatch m) =>
1236 t (Parser m a b) -> Fold m b c -> Parser m a c
1237roundRobin _ps _f = undefined
1239-------------------------------------------------------------------------------
1240-- Repeated Alternatives
1241-------------------------------------------------------------------------------
1243-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
1244-- fails the input consumed till now is dropped and the new instance is tried
1245-- on the fresh input.
1247-- /Unimplemented/
1249{-# INLINE retryMaxTotal #-}
1250retryMaxTotal :: -- (MonadCatch m) =>
1251 Int -> Parser m a b -> Fold m b c -> Parser m a c
1252retryMaxTotal _n _p _f = undefined
1254-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
1256-- /Unimplemented/
1258{-# INLINE retryMaxSuccessive #-}
1259retryMaxSuccessive :: -- (MonadCatch m) =>
1260 Int -> Parser m a b -> Fold m b c -> Parser m a c
1261retryMaxSuccessive _n _p _f = undefined
1263-- | Keep trying a parser until it succeeds. When the parser fails the input
1264-- consumed till now is dropped and the new instance is tried on the fresh
1265-- input.
1267-- /Unimplemented/
1269{-# INLINE retry #-}
1270retry :: -- (MonadCatch m) =>
1271 Parser m a b -> Parser m a b
1272retry _p = undefined