on d3b4e36 help sign in
1262 lines 41 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 , lookAhead
92 , takeWhileP
93 , takeWhile
94 -- $takeWhile
95 , takeWhile1
96 , drainWhile
98 -- Separators
99 , sliceSepByP
100 , sliceBeginWith
101 , sliceSepWith
103 -- Quoting and Escaping
104 , escapedSliceSepBy
105 , escapedFrameBy
107 -- Words and grouping
108 , wordBy
109 , groupBy
110 , groupByRolling
111 , groupByRollingEither
112 , eqBy
114 -- | Unimplemented
115 --
116 -- @
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
120 -- @
122 -- Second order parsers (parsers using parsers)
123 -- * Binary Combinators
125 -- ** Sequential Applicative
126 , serialWith
127 , split_
129 -- ** Parallel Applicatives
130 , teeWith
131 , teeWithFst
132 , teeWithMin
133 -- , teeTill -- like manyTill but parallel
135 -- ** Sequential Interleaving
136 -- Use two folds, run a primary parser, its rejected values go to the
137 -- secondary parser.
138 , deintercalate
140 -- ** Sequential Alternative
141 , alt
143 -- ** Parallel Alternatives
144 , shortest
145 , longest
146 -- , fastest
148 -- * N-ary Combinators
149 -- ** Sequential Collection
150 , concatSequence
151 , concatMap
153 -- ** Sequential Repetition
154 , count
155 , countBetween
157 , manyP
158 , many
159 , some
160 , manyTillP
161 , manyTill
162 , manyThen
164 -- ** Special cases
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.
169 --
170 -- We can instead implement these as special cases of deintercalate.
171 --
172 -- @
173 -- , endBy
174 , sepBy1
175 , sepBy
176 -- , sepEndBy
177 -- , beginBy
178 -- , sepBeginBy
179 -- , sepAroundBy
180 -- @
182 -- * Distribution
183 --
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
192 -- |
193 --
194 -- 1. Round robin
195 -- 2. Priority based
196 , roundRobin
198 -- ** Collection of Alternatives
199 -- | Unimplemented
200 --
201 -- @
202 -- , shortestN
203 -- , longestN
204 -- , fastestN -- first N successful in time
205 -- , choiceN -- first N successful in position
206 -- @
207 , choice -- first successful in position
209 -- ** Repeated Alternatives
210 , retryMaxTotal
211 , retryMaxSuccessive
212 , retry
213 )
214where
216import Control.Applicative ((<|>))
217import Control.Monad.Catch (MonadCatch, MonadThrow)
218import Prelude hiding
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
228--
229-- $setup
230-- >>> :m
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-------------------------------------------------------------------------------
241--
242-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
243-- parser fails or tries to backtrack.
244--
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
247-- recover.
248--
249-- /Pre-release/
250--
251{-# INLINE toFold #-}
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-------------------------------------------------------------------------------
258--
259-- | Make a 'Parser' from a 'Fold'.
260--
261-- /Pre-release/
262--
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-------------------------------------------------------------------------------
270--
271-- This is the dual of stream "fromPure".
272--
273-- | A parser that always yields a pure value without consuming any input.
274--
275-- /Pre-release/
276--
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".
284--
285-- | A parser that always yields the result of an effectful action without
286-- consuming any input.
287--
288-- /Pre-release/
289--
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".
295--
296-- | A parser that always fails with an error message without consuming
297-- any input.
298--
299-- /Pre-release/
300--
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".
308--
309-- | A parser that always fails with an effectful error message and without
310-- consuming any input.
311--
312-- /Pre-release/
313--
314{-# INLINE dieM #-}
315dieM :: MonadCatch m => m String -> Parser m a b
316dieM = D.toParserK . D.dieM
318-------------------------------------------------------------------------------
319-- Map on input
320-------------------------------------------------------------------------------
322-- | @lmap f parser@ maps the function @f@ on the input of the parser.
323--
324-- >>> Stream.parse (Parser.lmap (\x -> x * x) (Parser.fromFold Fold.sum)) (Stream.enumerateFromTo 1 100)
325-- 338350
326--
327-- > lmap = Parser.lmapM return
328--
329-- /Internal/
330{-# INLINE lmap #-}
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.
335--
336-- /Internal/
337{-# INLINE lmapM #-}
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.
342--
343-- >>> Stream.parse (Parser.filter (> 5) (Parser.fromFold Fold.sum)) $ Stream.fromList [1..10]
344-- 40
345--
346-- /Internal/
347{-# INLINE filter #-}
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-------------------------------------------------------------------------------
352-- Failing Parsers
353-------------------------------------------------------------------------------
355-- | Peek the head element of a stream, without consuming it. Fails if it
356-- encounters end of input.
357--
358-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
359-- (1,1)
360--
361-- @
362-- peek = lookAhead (satisfy True)
363-- @
364--
365-- /Pre-release/
366--
367{-# INLINE peek #-}
368peek :: MonadCatch m => Parser m a a
369peek = D.toParserK D.peek
371-- | Succeeds if we are at the end of input, fails otherwise.
372--
373-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
374-- (1,())
375--
376-- /Pre-release/
377--
378{-# INLINE eof #-}
379eof :: MonadCatch m => Parser m a ()
380eof = D.toParserK D.eof
382-- | Returns the next element if it passes the predicate, fails otherwise.
383--
384-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
385-- 1
386--
387-- /Pre-release/
388--
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'.
395--
396-- /Pre-release/
397--
398{-# INLINE next #-}
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'
404-- value.
405--
406-- /Pre-release/
407--
408{-# INLINE maybe #-}
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.
415--
416-- /Pre-release/
417--
418{-# INLINE either #-}
419either :: MonadCatch m => (a -> Either String b) -> Parser m a b
420either = D.toParserK . D.either
422-------------------------------------------------------------------------------
423-- Taking elements
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.
428--
429-- Stops after @n@ elements.
430-- Fails if the stream ends before @m@ elements could be taken.
431--
432-- Examples: -
433--
434-- @
435-- >>> :{
436-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
437-- where prsr = Parser.takeBetween low high Fold.toList
438-- :}
439--
440-- @
441--
442-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
443-- [1,2,3,4]
444--
445-- >>> takeBetween' 2 4 [1, 2]
446-- [1,2]
447--
448-- >>> takeBetween' 2 4 [1]
449-- *** Exception: ParseError "takeBetween: Expecting alteast 2 elements, got 1"
450--
451-- >>> takeBetween' 0 0 [1, 2]
452-- []
453--
454-- >>> takeBetween' 0 1 []
455-- []
456--
457-- @takeBetween@ is the most general take operation, other take operations can
458-- be defined in terms of takeBetween. For example:
459--
460-- @
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
465-- @
466--
467-- /Pre-release/
468--
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.
475--
476-- * Stops - after consuming @n@ elements.
477-- * Fails - if the stream or the collecting fold ends before it can collect
478-- exactly @n@ elements.
479--
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"
482--
483-- /Pre-release/
484--
485{-# INLINE takeEQ #-}
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.
490--
491-- * Stops - when the collecting fold stops.
492-- * Fails - if the stream or the collecting fold ends before producing @n@
493-- elements.
494--
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"
497--
498-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
499-- [1,0,1,0,1]
500--
501-- /Pre-release/
502--
503{-# INLINE takeGE #-}
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-------------------------------------------------------------------------------
511-- $takeWhile
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
516-- parser stops.
517--
518-- This is a generalized version of takeWhile, for example 'takeWhile1' can be
519-- implemented in terms of this:
520--
521-- @
522-- takeWhile1 cond p = takeWhile cond (takeBetween 1 maxBound p)
523-- @
524--
525-- Stops: when the condition fails or the collecting parser stops.
526-- Fails: when the collecting parser fails.
527--
528-- /Unimplemented/
529--
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.
537--
538-- * Stops - when the predicate fails or the collecting fold stops.
539-- * Fails - never.
540--
541-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
542-- [0,0]
543--
544-- We can implement a @breakOn@ using 'takeWhile':
545--
546-- @
547-- breakOn p = takeWhile (not p)
548-- @
549--
550-- /Pre-release/
551--
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.
557--
558-- /Pre-release/
559--
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.
566--
567-- This is also called @skipWhile@ in some parsing libraries.
568--
569-- /Pre-release/
570--
571{-# INLINE drainWhile #-}
572drainWhile :: MonadCatch m => (a -> Bool) -> Parser m a ()
573drainWhile p = takeWhile p FL.drain
575-------------------------------------------------------------------------------
576-- Separators
577-------------------------------------------------------------------------------
579-- | @sliceSepByP cond parser@ parses a slice of the input using @parser@ until
580-- @cond@ succeeds or the parser stops.
581--
582-- This is a generalized slicing parser which can be used to implement other
583-- parsers e.g.:
584--
585-- @
586-- sliceSepByMax cond n p = sliceSepByP cond (take n p)
587-- sliceSepByBetween cond m n p = sliceSepByP cond (takeBetween m n p)
588-- @
589--
590-- /Pre-release/
591--
592{-# INLINE sliceSepByP #-}
593sliceSepByP ::
594 MonadCatch m =>
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.
600--
601-- /Unimplemented/
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.
612--
613-- * Stops - when the predicate succeeds in non-leading position.
614-- * Fails - never.
615--
616-- S.splitWithPrefix pred f = S.parseMany (PR.sliceBeginWith pred f)
617--
618-- Examples: -
619--
620-- >>> :{
621-- sliceBeginWithOdd ls = Stream.parse prsr (Stream.fromList ls)
622-- where prsr = Parser.sliceBeginWith odd Fold.toList
623-- :}
624--
625--
626-- >>> sliceBeginWithOdd [2, 4, 6, 3]
627-- *** Exception: sliceBeginWith : slice begins with an element which fails the predicate
628-- ...
629--
630-- >>> sliceBeginWithOdd [3, 5, 7, 4]
631-- [3]
632--
633-- >>> sliceBeginWithOdd [3, 4, 6, 8, 5]
634-- [3,4,6,8]
635--
636-- >>> sliceBeginWithOdd []
637-- []
638--
639-- /Pre-release/
640--
641{-# INLINE sliceBeginWith #-}
642sliceBeginWith ::
643 MonadCatch m =>
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.
653--
654-- /Unimplemented/
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.
665--
666-- For example,
667--
668-- @
669-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello}"
670-- "hello"
671--
672-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello {world}}"
673-- "hello world"
674--
675-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello \\{world\\}}"
676-- "hello {world}"
677--
678-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello {world}"
679-- ParseError "Unterminated '{'"
680--
681-- @
682--
683-- /Unimplemented/
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-------------------------------------------------------------------------------
691-- Grouping and words
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
697-- separated text.
698--
699-- * Stops - when it finds a word separator after a non-word element
700-- * Fails - never.
701--
702-- @
703-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
704-- @
705--
706{-# INLINE wordBy #-}
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.
716--
717-- * Stops - when the comparison fails.
718-- * Fails - never.
719--
720-- >>> :{
721-- runGroupsBy eq =
722-- Stream.toList
723-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
724-- . Stream.fromList
725-- :}
726--
727-- >>> runGroupsBy (<) []
728-- []
729--
730-- >>> runGroupsBy (<) [1]
731-- [[1]]
732--
733-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
734-- [[3,5,4],[1,2],[0]]
735--
736-- /Pre-release/
737--
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.
750--
751-- * Stops - when the comparison fails.
752-- * Fails - never.
753--
754-- >>> :{
755-- runGroupsByRolling eq =
756-- Stream.toList
757-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
758-- . Stream.fromList
759-- :}
760--
761-- >>> runGroupsByRolling (<) []
762-- []
763--
764-- >>> runGroupsByRolling (<) [1]
765-- [[1]]
766--
767-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
768-- [[3,5],[4],[1,2],[0]]
769--
770-- /Pre-release/
771--
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.
780--
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'.
784--
785-- /Unimplemented/
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.
794--
795-- >>> Stream.parse (Parser.eqBy (==) "string") $ Stream.fromList "string"
796--
797-- >>> Stream.parse (Parser.eqBy (==) "mismatch") $ Stream.fromList "match"
798-- *** Exception: ParseError "eqBy: failed, yet to match 7 elements"
799--
800-- /Pre-release/
801--
802{-# INLINE eqBy #-}
803eqBy :: MonadCatch m => (a -> a -> Bool) -> [a] -> Parser m a ()
804eqBy cmp = D.toParserK . D.eqBy cmp
806-------------------------------------------------------------------------------
807-- nested parsers
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.
815--
816-- Note: This is a parsing dual of appending streams using
817-- 'Streamly.Prelude.serial', it splits the streams using two parsers and zips
818-- the results.
819--
820-- This implementation is strict in the second argument, therefore, the
821-- following will fail:
822--
823-- >>> Stream.parse (Parser.serialWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
824-- *** Exception: Prelude.undefined
825-- ...
826--
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.
831--
832-- Many combinators can be expressed using @serialWith@ and other parser
833-- primitives. Some common idioms are described below,
834--
835-- @
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)
838-- @
839--
840-- @
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)
843-- @
844--
845-- @
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)
848-- @
849--
850-- /Pre-release/
851--
852{-# INLINE serialWith #-}
853serialWith :: MonadCatch m
854 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
855serialWith f p1 p2 =
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.
863--
864-- This implementation is strict in the second argument, therefore, the
865-- following will fail:
866--
867-- >>> Stream.parse (Parser.split_ (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
868-- *** Exception: Prelude.undefined
869-- ...
870--
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.
875--
876-- /Pre-release/
877--
878{-# INLINE split_ #-}
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.
885--
886-- /Pre-release/
887--
888{-# INLINE teeWith #-}
889teeWith :: MonadCatch m
890 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
891teeWith f p1 p2 =
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.
896--
897-- /Pre-release/
898--
899{-# INLINE teeWithFst #-}
900teeWithFst :: MonadCatch m
901 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
902teeWithFst f p1 p2 =
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.
907--
908-- /Unimplemented/
909--
910{-# INLINE teeWithMin #-}
911teeWithMin :: MonadCatch m
912 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
913teeWithMin f p1 p2 =
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.
919--
920-- Note: This implementation is not lazy in the second argument. The following
921-- will fail:
922--
923-- >>> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
924-- 1
925--
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.
930--
931-- /Pre-release/
932--
933{-# INLINE alt #-}
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
939-- parse.
940--
941-- /Pre-release/
942--
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
950-- parse.
951--
952-- /Pre-release/
953--
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.
960--
961-- /Pre-release/
962--
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.
968--
969-- * Stops - when the collecting parser stops.
970-- * Fails - when the collecting parser fails.
971--
972-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
973-- [1,2]
974--
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"
977--
978-- /Internal/
979{-# INLINE takeP #-}
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-------------------------------------------------------------------------------
986--
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
989-- parsers fail.
990--
991-- This is same as 'Data.Traversable.sequence' but more efficient.
992--
993-- /Unimplemented/
994--
995{-# INLINE concatSequence #-}
996concatSequence ::
997 -- Foldable t =>
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.
1008-- /Pre-release/
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
1020-- successful parse.
1022-- This is same as 'asum' but more efficient.
1024-- /Broken/
1026{-# INLINE choice #-}
1027choice ::
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-------------------------------------------------------------------------------
1035-- $many
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.
1043-- /Unimplemented/
1045{-# INLINE manyP #-}
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'.
1058-- /Pre-release/
1060{-# INLINE 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
1067-- compatibility.
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'.
1079-- /Pre-release/
1081{-# INLINE 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.
1091-- /Unimplemented/
1093{-# INLINE countBetween #-}
1094countBetween ::
1095 -- MonadCatch m =>
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.
1104-- /Unimplemented/
1106{-# INLINE count #-}
1107count ::
1108 -- MonadCatch m =>
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':
1118-- @
1119-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
1120-- @
1122-- /Unimplemented/
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.
1138-- /Pre-release/
1140{-# INLINE manyTill #-}
1141manyTill :: MonadCatch m
1142 => Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1143manyTill p1 p2 f =
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
1152-- error.
1154-- /Unimplemented/
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-------------------------------------------------------------------------------
1162-- Interleaving
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
1179-- line number info.
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
1183-- two patterns.
1185-- This undoes a "gintercalate" of two streams.
1187-- /Unimplemented/
1189{-# INLINE deintercalate #-}
1190deintercalate ::
1191 -- Monad m =>
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
1203 x <- p
1204 f <- fromEffect $ FL.initialize sink
1205 f1 <- fromEffect $ FL.snoc f x
1206 many (sep >> p) f1
1208-- | sepBy1 or empty, does not fail.
1209{-# INLINE sepBy #-}
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.
1222-- /Unimplemented/
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.
1237-- /Unimplemented/
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.
1246-- /Unimplemented/
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
1255-- input.
1257-- /Unimplemented/
1259{-# INLINE retry #-}
1260retry :: -- (MonadCatch m) =>
1261 Parser m a b -> Parser m a b
1262retry _p = undefined