on a322c07 help sign in
1134 lines 37 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 -- First order parsers
55 -- * Accumulators
56 , fromFold
57 , fromPure
58 , fromEffect
59 , die
60 , dieM
62 -- * Element parsers
63 , peek
64 , eof
65 , satisfy
66 , maybe
67 , either
69 -- * Sequence parsers
70 --
71 -- | Parsers chained in series, if one parser terminates the composition
72 -- terminates.
74 -- | Grab a sequence of input elements without inspecting them
75 , takeBetween
76 -- , take -- takeBetween 0 n
77 , takeEQ -- takeBetween n n
78 , takeGE -- takeBetween n maxBound
80 -- Grab a sequence of input elements by inspecting them
81 , takeP
82 , lookAhead
83 , takeWhileP
84 , takeWhile
85 -- $takeWhile
86 , takeWhile1
87 , drainWhile
89 , sliceSepByP
90 , sliceBeginWith
91 , sliceSepWith
92 , escapedSliceSepBy
93 , escapedFrameBy
94 , wordBy
95 , groupBy
96 , groupByRolling
97 , eqBy
98 -- | Unimplemented
99 --
100 -- @
101 -- , prefixOf -- match any prefix of a given string
102 -- , suffixOf -- match any suffix of a given string
103 -- , infixOf -- match any substring of a given string
104 -- @
106 -- Second order parsers (parsers using parsers)
107 -- * Binary Combinators
109 -- ** Sequential Applicative
110 , serialWith
111 , split_
113 -- ** Parallel Applicatives
114 , teeWith
115 , teeWithFst
116 , teeWithMin
117 -- , teeTill -- like manyTill but parallel
119 -- ** Sequential Interleaving
120 -- Use two folds, run a primary parser, its rejected values go to the
121 -- secondary parser.
122 , deintercalate
124 -- ** Sequential Alternative
125 , alt
127 -- ** Parallel Alternatives
128 , shortest
129 , longest
130 -- , fastest
132 -- * N-ary Combinators
133 -- ** Sequential Collection
134 , concatSequence
135 , concatMap
137 -- ** Sequential Repetition
138 , count
139 , countBetween
141 , manyP
142 , many
143 , some
144 , manyTillP
145 , manyTill
146 , manyThen
148 -- ** Special cases
149 -- | TODO: traditional implmentations of these may be of limited use. For
150 -- example, consider parsing lines separated by @\\r\\n@. The main parser
151 -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
152 -- can apply the "sep" parser.
153 --
154 -- We can instead implement these as special cases of deintercalate.
155 --
156 -- @
157 -- , endBy
158 -- , sepBy
159 -- , sepEndBy
160 -- , beginBy
161 -- , sepBeginBy
162 -- , sepAroundBy
163 -- @
165 -- * Distribution
166 --
167 -- | A simple and stupid impl would be to just convert the stream to an
168 -- array and give the array reference to all consumers. The array can be
169 -- grown on demand by any consumer and truncated when nonbody needs it.
171 -- ** Distribute to collection
172 -- ** Distribute to repetition
174 -- ** Interleaved collection
175 -- |
176 --
177 -- 1. Round robin
178 -- 2. Priority based
179 , roundRobin
181 -- ** Collection of Alternatives
182 -- | Unimplemented
183 --
184 -- @
185 -- , shortestN
186 -- , longestN
187 -- , fastestN -- first N successful in time
188 -- , choiceN -- first N successful in position
189 -- @
190 , choice -- first successful in position
192 -- ** Repeated Alternatives
193 , retryMaxTotal
194 , retryMaxSuccessive
195 , retry
196 )
197where
199import Control.Monad.Catch (MonadCatch)
200import Prelude
201 hiding (any, all, take, takeWhile, sequence, concatMap, maybe, either)
203import Streamly.Internal.Data.Fold.Type (Fold(..))
204import Streamly.Internal.Data.Parser.ParserK.Type (Parser)
206import qualified Streamly.Internal.Data.Fold.Type as FL
207import qualified Streamly.Internal.Data.Parser.ParserD as D
208import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
210--
211-- $setup
212-- >>> :m
213-- >>> import Prelude hiding (any, all, take, takeWhile, sequence, concatMap, maybe, either)
214-- >>> import qualified Streamly.Prelude as Stream
215-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, parseMany)
216-- >>> import qualified Streamly.Data.Fold as Fold
217-- >>> import qualified Streamly.Internal.Data.Parser as Parser
219-------------------------------------------------------------------------------
220-- Upgrade folds to parses
221-------------------------------------------------------------------------------
222--
223-- | Make a 'Parser' from a 'Fold'.
224--
225-- /Pre-release/
226--
227{-# INLINE fromFold #-}
228fromFold :: MonadCatch m => Fold m a b -> Parser m a b
229fromFold = K.toParserK . D.fromFold
231-------------------------------------------------------------------------------
232-- Terminating but not failing folds
233-------------------------------------------------------------------------------
234--
235-- This is the dual of stream "fromPure".
236--
237-- | A parser that always yields a pure value without consuming any input.
238--
239-- /Pre-release/
240--
241{-# INLINE [3] fromPure #-}
242fromPure :: MonadCatch m => b -> Parser m a b
243fromPure = K.toParserK . D.fromPure
244{-# RULES "fromPure fallback to CPS" [2]
245 forall a. K.toParserK (D.fromPure a) = K.fromPure a #-}
247-- This is the dual of stream "fromEffect".
248--
249-- | A parser that always yields the result of an effectful action without
250-- consuming any input.
251--
252-- /Pre-release/
253--
254{-# INLINE fromEffect #-}
255fromEffect :: MonadCatch m => m b -> Parser m a b
256fromEffect = K.fromEffect -- K.toParserK . D.fromEffect
258-- This is the dual of "nil".
259--
260-- | A parser that always fails with an error message without consuming
261-- any input.
262--
263-- /Pre-release/
264--
265{-# INLINE [3] die #-}
266die :: MonadCatch m => String -> Parser m a b
267die = K.toParserK . D.die
268{-# RULES "die fallback to CPS" [2]
269 forall a. K.toParserK (D.die a) = K.die a #-}
271-- This is the dual of "nilM".
272--
273-- | A parser that always fails with an effectful error message and without
274-- consuming any input.
275--
276-- /Pre-release/
277--
278{-# INLINE dieM #-}
279dieM :: MonadCatch m => m String -> Parser m a b
280dieM = K.toParserK . D.dieM
282-------------------------------------------------------------------------------
283-- Failing Parsers
284-------------------------------------------------------------------------------
286-- | Peek the head element of a stream, without consuming it. Fails if it
287-- encounters end of input.
288--
289-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
290-- (1,1)
291--
292-- @
293-- peek = lookAhead (satisfy True)
294-- @
295--
296-- /Pre-release/
297--
298{-# INLINE peek #-}
299peek :: MonadCatch m => Parser m a a
300peek = K.toParserK D.peek
302-- | Succeeds if we are at the end of input, fails otherwise.
303--
304-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
305-- (1,())
306--
307-- /Pre-release/
308--
309{-# INLINE eof #-}
310eof :: MonadCatch m => Parser m a ()
311eof = K.toParserK D.eof
313-- | Returns the next element if it passes the predicate, fails otherwise.
314--
315-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
316-- 1
317--
318-- /Pre-release/
319--
320{-# INLINE satisfy #-}
321satisfy :: MonadCatch m => (a -> Bool) -> Parser m a a
322satisfy = K.toParserK . D.satisfy
324-- | Map a 'Maybe' returning function on the next element in the stream. The
325-- parser fails if the function returns 'Nothing' otherwise returns the 'Just'
326-- value.
327--
328-- /Pre-release/
329--
330{-# INLINE maybe #-}
331maybe :: MonadCatch m => (a -> Maybe b) -> Parser m a b
332maybe = K.toParserK . D.maybe
334-- | Map an 'Either' returning function on the next element in the stream. If
335-- the function returns 'Left err', the parser fails with the error message
336-- @err@ otherwise returns the 'Right' value.
337--
338-- /Pre-release/
339--
340{-# INLINE either #-}
341either :: MonadCatch m => (a -> Either String b) -> Parser m a b
342either = K.toParserK . D.either
344-------------------------------------------------------------------------------
345-- Taking elements
346-------------------------------------------------------------------------------
348-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
349-- elements and folds them using the supplied fold.
350--
351-- Stops after @n@ elements.
352-- Fails if the stream ends before @m@ elements could be taken.
353--
354-- Examples: -
355--
356-- @
357-- >>> :{
358-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
359-- where prsr = Parser.takeBetween low high Fold.toList
360-- :}
361--
362-- @
363--
364-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
365-- [1,2,3,4]
366--
367-- >>> takeBetween' 2 4 [1, 2]
368-- [1,2]
369--
370-- >>> takeBetween' 2 4 [1]
371-- *** Exception: ParseError "takeBetween: Expecting alteast 2 elements, got 1"
372--
373-- >>> takeBetween' 0 0 [1, 2]
374-- []
375--
376-- >>> takeBetween' 0 1 []
377-- []
378--
379-- @takeBetween@ is the most general take operation, other take operations can
380-- be defined in terms of takeBetween. For example:
381--
382-- @
383-- take = takeBetween 0 n -- equivalent of take
384-- take1 = takeBetween 1 n -- equivalent of takeLE1
385-- takeEQ = takeBetween n n
386-- takeGE = takeBetween n maxBound
387-- @
388--
389-- /Pre-release/
390--
391{-# INLINE takeBetween #-}
392takeBetween :: MonadCatch m =>
393 Int -> Int -> Fold m a b -> Parser m a b
394takeBetween m n = K.toParserK . D.takeBetween m n
396-- | Stops after taking exactly @n@ input elements.
397--
398-- * Stops - after consuming @n@ elements.
399-- * Fails - if the stream or the collecting fold ends before it can collect
400-- exactly @n@ elements.
401--
402-- >>> Stream.parse (Parser.takeEQ 4 Fold.toList) $ Stream.fromList [1,0,1]
403-- *** Exception: ParseError "takeEQ: Expecting exactly 4 elements, input terminated on 3"
404--
405-- /Pre-release/
406--
407{-# INLINE takeEQ #-}
408takeEQ :: MonadCatch m => Int -> Fold m a b -> Parser m a b
409takeEQ n = K.toParserK . D.takeEQ n
411-- | Take at least @n@ input elements, but can collect more.
412--
413-- * Stops - when the collecting fold stops.
414-- * Fails - if the stream or the collecting fold ends before producing @n@
415-- elements.
416--
417-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1]
418-- *** Exception: ParseError "takeGE: Expecting at least 4 elements, input terminated on 3"
419--
420-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
421-- [1,0,1,0,1]
422--
423-- /Pre-release/
424--
425{-# INLINE takeGE #-}
426takeGE :: MonadCatch m => Int -> Fold m a b -> Parser m a b
427takeGE n = K.toParserK . D.takeGE n
429-- $takeWhile
430-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
432-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
433-- input. The combinator stops when the condition fails or if the collecting
434-- parser stops.
435--
436-- This is a generalized version of takeWhile, for example 'takeWhile1' can be
437-- implemented in terms of this:
438--
439-- @
440-- takeWhile1 cond p = takeWhile cond (takeBetween 1 maxBound p)
441-- @
442--
443-- Stops: when the condition fails or the collecting parser stops.
444-- Fails: when the collecting parser fails.
445--
446-- /Unimplemented/
447--
448{-# INLINE takeWhileP #-}
449takeWhileP :: -- MonadCatch m =>
450 (a -> Bool) -> Parser m a b -> Parser m a b
451takeWhileP _cond = undefined -- K.toParserK . D.takeWhileP cond
453-- | Collect stream elements until an element fails the predicate. The element
454-- on which the predicate fails is returned back to the input stream.
455--
456-- * Stops - when the predicate fails or the collecting fold stops.
457-- * Fails - never.
458--
459-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
460-- [0,0]
461--
462-- We can implement a @breakOn@ using 'takeWhile':
463--
464-- @
465-- breakOn p = takeWhile (not p)
466-- @
467--
468-- /Pre-release/
469--
470{-# INLINE takeWhile #-}
471takeWhile :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
472takeWhile cond = K.toParserK . D.takeWhile cond
474-- | Like 'takeWhile' but takes at least one element otherwise fails.
475--
476-- /Pre-release/
477--
478{-# INLINE takeWhile1 #-}
479takeWhile1 :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
480takeWhile1 cond = K.toParserK . D.takeWhile1 cond
482-- | Drain the input as long as the predicate succeeds, running the effects and
483-- discarding the results.
484--
485-- This is also called @skipWhile@ in some parsing libraries.
486--
487-- /Pre-release/
488--
489{-# INLINE drainWhile #-}
490drainWhile :: MonadCatch m => (a -> Bool) -> Parser m a ()
491drainWhile p = takeWhile p FL.drain
493-- | @sliceSepByP cond parser@ parses a slice of the input using @parser@ until
494-- @cond@ succeeds or the parser stops.
495--
496-- This is a generalized slicing parser which can be used to implement other
497-- parsers e.g.:
498--
499-- @
500-- sliceSepByMax cond n p = sliceSepByP cond (take n p)
501-- sliceSepByBetween cond m n p = sliceSepByP cond (takeBetween m n p)
502-- @
503--
504-- /Pre-release/
505--
506{-# INLINABLE sliceSepByP #-}
507sliceSepByP ::
508 MonadCatch m =>
509 (a -> Bool) -> Parser m a b -> Parser m a b
510sliceSepByP cond = K.toParserK . D.sliceSepByP cond . K.fromParserK
512-- | Like 'sliceSepBy' but does not drop the separator element, instead
513-- separator is emitted as a separate element in the output.
514--
515-- /Unimplemented/
516{-# INLINABLE sliceSepWith #-}
517sliceSepWith :: -- MonadCatch m =>
518 (a -> Bool) -> Fold m a b -> Parser m a b
519sliceSepWith _cond = undefined -- K.toParserK . D.sliceSepBy cond
521-- | Collect stream elements until an elements passes the predicate, return the
522-- last element on which the predicate succeeded back to the input stream. If
523-- the predicate succeeds on the first element itself then the parser does not
524-- terminate there. The succeeding element in the leading position
525-- is treated as a prefix separator which is kept in the output segment.
526--
527-- * Stops - when the predicate succeeds in non-leading position.
528-- * Fails - never.
529--
530-- S.splitWithPrefix pred f = S.parseMany (PR.sliceBeginWith pred f)
531--
532-- Examples: -
533--
534-- >>> :{
535-- sliceBeginWithOdd ls = Stream.parse prsr (Stream.fromList ls)
536-- where prsr = Parser.sliceBeginWith odd Fold.toList
537-- :}
538--
539--
540-- >>> sliceBeginWithOdd [2, 4, 6, 3]
541-- *** Exception: sliceBeginWith : slice begins with an element which fails the predicate
542-- ...
543--
544-- >>> sliceBeginWithOdd [3, 5, 7, 4]
545-- [3]
546--
547-- >>> sliceBeginWithOdd [3, 4, 6, 8, 5]
548-- [3,4,6,8]
549--
550-- >>> sliceBeginWithOdd []
551-- []
552--
553-- /Pre-release/
554--
555{-# INLINABLE sliceBeginWith #-}
556sliceBeginWith ::
557 MonadCatch m =>
558 (a -> Bool) -> Fold m a b -> Parser m a b
559sliceBeginWith cond = K.toParserK . D.sliceBeginWith cond
561-- | Like 'sliceSepBy' but the separator elements can be escaped using an
562-- escape char determined by the second predicate.
563--
564-- /Unimplemented/
565{-# INLINABLE escapedSliceSepBy #-}
566escapedSliceSepBy :: -- MonadCatch m =>
567 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
568escapedSliceSepBy _cond _esc = undefined
569 -- K.toParserK . D.escapedSliceSepBy cond esc
571-- | @escapedFrameBy begin end escape@ parses a string framed using @begin@ and
572-- @end@ as the frame begin and end marker elements and @escape@ as an escaping
573-- element to escape the occurrence of the framing elements within the frame.
574-- Nested frames are allowed, but nesting is removed when parsing.
575--
576-- For example,
577--
578-- @
579-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello}"
580-- "hello"
581--
582-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello {world}}"
583-- "hello world"
584--
585-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello \\{world\\}}"
586-- "hello {world}"
587--
588-- > Stream.parse (Parser.escapedFrameBy (== '{') (== '}') (== '\\') Fold.toList) $ Stream.fromList "{hello {world}"
589-- ParseError "Unterminated '{'"
590--
591-- @
592--
593-- /Unimplemented/
594{-# INLINABLE escapedFrameBy #-}
595escapedFrameBy :: -- MonadCatch m =>
596 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
597escapedFrameBy _begin _end _escape _p = undefined
598 -- K.toParserK . D.frameBy begin end escape p
600-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
601-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
602-- @["a","b"]@. In other words, its like parsing words from whitespace
603-- separated text.
604--
605-- * Stops - when it finds a word separator after a non-word element
606-- * Fails - never.
607--
608-- @
609-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
610-- @
611--
612{-# INLINE wordBy #-}
613wordBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
614wordBy f = K.toParserK . D.wordBy f
616-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
617-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
618-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
619-- then @c@ is also assigned to the same group and so on. When the comparison
620-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
621-- the result of the fold is the result of the parser.
622--
623-- * Stops - when the comparison fails.
624-- * Fails - never.
625--
626-- >>> :{
627-- runGroupsBy eq =
628-- Stream.toList
629-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
630-- . Stream.fromList
631-- :}
632--
633-- >>> runGroupsBy (<) []
634-- []
635--
636-- >>> runGroupsBy (<) [1]
637-- [[1]]
638--
639-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
640-- [[3,5,4],[1,2],[0]]
641--
642-- /Pre-release/
643--
644{-# INLINABLE groupBy #-}
645groupBy :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
646groupBy eq = K.toParserK . D.groupBy eq
648-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
649-- successive elements in the input stream. Assuming the input stream to the
650-- parser is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
651-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
652-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
653-- then @c@ is also assigned to the same group and so on. When the comparison
654-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
655-- the result of the fold is the result of the parser.
656--
657-- * Stops - when the comparison fails.
658-- * Fails - never.
659--
660-- >>> :{
661-- runGroupsByRolling eq =
662-- Stream.toList
663-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
664-- . Stream.fromList
665-- :}
666--
667-- >>> runGroupsByRolling (<) []
668-- []
669--
670-- >>> runGroupsByRolling (<) [1]
671-- [[1]]
672--
673-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
674-- [[3,5],[4],[1,2],[0]]
675--
676-- /Pre-release/
677--
678{-# INLINABLE groupByRolling #-}
679groupByRolling :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
680groupByRolling eq = K.toParserK . D.groupByRolling eq
682-- | Match the given sequence of elements using the given comparison function.
683--
684-- >>> Stream.parse (Parser.eqBy (==) "string") $ Stream.fromList "string"
685--
686-- >>> Stream.parse (Parser.eqBy (==) "mismatch") $ Stream.fromList "match"
687-- *** Exception: ParseError "eqBy: failed, yet to match 7 elements"
688--
689-- /Pre-release/
690--
691{-# INLINE eqBy #-}
692eqBy :: MonadCatch m => (a -> a -> Bool) -> [a] -> Parser m a ()
693eqBy cmp = K.toParserK . D.eqBy cmp
695-------------------------------------------------------------------------------
696-- nested parsers
697-------------------------------------------------------------------------------
699-- | Sequential parser application. Apply two parsers sequentially to an input
700-- stream. The input is provided to the first parser, when it is done the
701-- remaining input is provided to the second parser. If both the parsers
702-- succeed their outputs are combined using the supplied function. The
703-- operation fails if any of the parsers fail.
704--
705-- Note: This is a parsing dual of appending streams using
706-- 'Streamly.Prelude.serial', it splits the streams using two parsers and zips
707-- the results.
708--
709-- This implementation is strict in the second argument, therefore, the
710-- following will fail:
711--
712-- >>> Stream.parse (Parser.serialWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
713-- *** Exception: Prelude.undefined
714-- ...
715--
716-- Compare with 'Applicative' instance method '<*>'. This implementation allows
717-- stream fusion but has quadratic complexity. This can fuse with other
718-- operations and can be faster than 'Applicative' instance for small number
719-- (less than 8) of compositions.
720--
721-- Many combinators can be expressed using @serialWith@ and other parser
722-- primitives. Some common idioms are described below,
723--
724-- @
725-- span :: (a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
726-- span pred f1 f2 = serialWith (,) ('takeWhile' pred f1) ('fromFold' f2)
727-- @
728--
729-- @
730-- spanBy :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
731-- spanBy eq f1 f2 = serialWith (,) ('groupBy' eq f1) ('fromFold' f2)
732-- @
733--
734-- @
735-- spanByRolling :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
736-- spanByRolling eq f1 f2 = serialWith (,) ('groupByRolling' eq f1) ('fromFold' f2)
737-- @
738--
739-- /Pre-release/
740--
741{-# INLINE serialWith #-}
742serialWith :: MonadCatch m
743 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
744serialWith f p1 p2 =
745 K.toParserK $ D.serialWith f (K.fromParserK p1) (K.fromParserK p2)
747-- | Sequential parser application ignoring the output of the first parser.
748-- Apply two parsers sequentially to an input stream. The input is provided to
749-- the first parser, when it is done the remaining input is provided to the
750-- second parser. The output of the parser is the output of the second parser.
751-- The operation fails if any of the parsers fail.
752--
753-- This implementation is strict in the second argument, therefore, the
754-- following will fail:
755--
756-- >>> Stream.parse (Parser.split_ (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
757-- *** Exception: Prelude.undefined
758-- ...
759--
760-- Compare with 'Applicative' instance method '*>'. This implementation allows
761-- stream fusion but has quadratic complexity. This can fuse with other
762-- operations, and can be faster than 'Applicative' instance for small
763-- number (less than 8) of compositions.
764--
765-- /Pre-release/
766--
767{-# INLINE split_ #-}
768split_ :: MonadCatch m => Parser m x a -> Parser m x b -> Parser m x b
769split_ p1 p2 = K.toParserK $ D.split_ (K.fromParserK p1) (K.fromParserK p2)
771-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
772-- of them succeed or anyone of them fails and combines their output using @f@.
773-- The parser succeeds if both the parsers succeed.
774--
775-- /Pre-release/
776--
777{-# INLINE teeWith #-}
778teeWith :: MonadCatch m
779 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
780teeWith f p1 p2 =
781 K.toParserK $ D.teeWith f (K.fromParserK p1) (K.fromParserK p2)
783-- | Like 'teeWith' but ends parsing and zips the results, if available,
784-- whenever the first parser ends.
785--
786-- /Pre-release/
787--
788{-# INLINE teeWithFst #-}
789teeWithFst :: MonadCatch m
790 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
791teeWithFst f p1 p2 =
792 K.toParserK $ D.teeWithFst f (K.fromParserK p1) (K.fromParserK p2)
794-- | Like 'teeWith' but ends parsing and zips the results, if available,
795-- whenever any of the parsers ends or fails.
796--
797-- /Unimplemented/
798--
799{-# INLINE teeWithMin #-}
800teeWithMin :: MonadCatch m
801 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
802teeWithMin f p1 p2 =
803 K.toParserK $ D.teeWithMin f (K.fromParserK p1) (K.fromParserK p2)
805-- | Sequential alternative. Apply the input to the first parser and return the
806-- result if the parser succeeds. If the first parser fails then backtrack and
807-- apply the same input to the second parser and return the result.
808--
809-- Note: This implementation is not lazy in the second argument. The following
810-- will fail:
811--
812-- >>> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
813-- 1
814--
815-- Compare with 'Alternative' instance method '<|>'. This implementation allows
816-- stream fusion but has quadratic complexity. This can fuse with other
817-- operations and can be much faster than 'Alternative' instance for small
818-- number (less than 8) of alternatives.
819--
820-- /Pre-release/
821--
822{-# INLINE alt #-}
823alt :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
824alt p1 p2 = K.toParserK $ D.alt (K.fromParserK p1) (K.fromParserK p2)
826-- | Shortest alternative. Apply both parsers in parallel but choose the result
827-- from the one which consumed least input i.e. take the shortest succeeding
828-- parse.
829--
830-- /Pre-release/
831--
832{-# INLINE shortest #-}
833shortest :: MonadCatch m
834 => Parser m x a -> Parser m x a -> Parser m x a
835shortest p1 p2 = K.toParserK $ D.shortest (K.fromParserK p1) (K.fromParserK p2)
837-- | Longest alternative. Apply both parsers in parallel but choose the result
838-- from the one which consumed more input i.e. take the longest succeeding
839-- parse.
840--
841-- /Pre-release/
842--
843{-# INLINE longest #-}
844longest :: MonadCatch m
845 => Parser m x a -> Parser m x a -> Parser m x a
846longest p1 p2 = K.toParserK $ D.longest (K.fromParserK p1) (K.fromParserK p2)
848-- | Run a parser without consuming the input.
849--
850-- /Pre-release/
851--
852{-# INLINE lookAhead #-}
853lookAhead :: MonadCatch m => Parser m a b -> Parser m a b
854lookAhead p = K.toParserK $ D.lookAhead $ K.fromParserK p
856-- | Takes at-most @n@ input elements.
857--
858-- * Stops - when the collecting parser stops.
859-- * Fails - when the collecting parser fails.
860--
861-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
862-- [1,2]
863--
864-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
865-- *** Exception: ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4"
866--
867-- /Internal/
868{-# INLINE takeP #-}
869takeP :: MonadCatch m => Int -> Parser m a b -> Parser m a b
870takeP i p = K.toParserK $ D.takeP i $ K.fromParserK p
872-------------------------------------------------------------------------------
873-- Interleaving
874-------------------------------------------------------------------------------
875--
876-- To deinterleave we can chain two parsers one behind the other. The input is
877-- given to the first parser and the input definitively rejected by the first
878-- parser is given to the second parser.
879--
880-- We can either have the parsers themselves buffer the input or use the shared
881-- global buffer to hold it until none of the parsers need it. When the first
882-- parser returns Skip (i.e. rewind) we let the second parser consume the
883-- rejected input and when it is done we move the cursor forward to the first
884-- parser again. This will require a "move forward" command as well.
885--
886-- To implement grep we can use three parsers, one to find the pattern, one
887-- to store the context behind the pattern and one to store the context in
888-- front of the pattern. When a match occurs we need to emit the accumulator of
889-- all the three parsers. One parser can count the line numbers to provide the
890-- line number info.
891--
892-- | Apply two parsers alternately to an input stream. The input stream is
893-- considered an interleaving of two patterns. The two parsers represent the
894-- two patterns.
895--
896-- This undoes a "gintercalate" of two streams.
897--
898-- /Unimplemented/
899--
900{-# INLINE deintercalate #-}
901deintercalate ::
902 -- Monad m =>
903 Fold m a y -> Parser m x a
904 -> Fold m b z -> Parser m x b
905 -> Parser m x (y, z)
906deintercalate = undefined
908-------------------------------------------------------------------------------
909-- Sequential Collection
910-------------------------------------------------------------------------------
911--
912-- | @concatSequence f t@ collects sequential parses of parsers in the
913-- container @t@ using the fold @f@. Fails if the input ends or any of the
914-- parsers fail.
915--
916-- This is same as 'Data.Traversable.sequence' but more efficient.
917--
918-- /Unimplemented/
919--
920{-# INLINE concatSequence #-}
921concatSequence ::
922 -- Foldable t =>
923 Fold m b c -> t (Parser m a b) -> Parser m a c
924concatSequence _f _p = undefined
926-- | Map a 'Parser' returning function on the result of a 'Parser'.
927--
928-- Compare with 'Monad' instance method '>>='. This implementation allows
929-- stream fusion but has quadratic complexity. This can fuse with other
930-- operations and can be much faster than 'Monad' instance for small number
931-- (less than 8) of compositions.
932--
933-- /Pre-release/
934--
935{-# INLINE concatMap #-}
936concatMap :: MonadCatch m
937 => (b -> Parser m a c) -> Parser m a b -> Parser m a c
938concatMap f p = K.toParserK $ D.concatMap (K.fromParserK . f) (K.fromParserK p)
940-------------------------------------------------------------------------------
941-- Alternative Collection
942-------------------------------------------------------------------------------
943--
944-- | @choice parsers@ applies the @parsers@ in order and returns the first
945-- successful parse.
946--
947-- This is same as 'asum' but more efficient.
948--
949-- /Broken/
950--
951{-# INLINE choice #-}
952choice ::
953 (Functor t, Foldable t, MonadCatch m) => t (Parser m a b) -> Parser m a b
954choice ps = K.toParserK $ D.choice $ K.fromParserK <$> ps
956-------------------------------------------------------------------------------
957-- Sequential Repetition
958-------------------------------------------------------------------------------
959--
960-- $many
961-- TODO "many" is essentially a Fold because it cannot fail. So it can be
962-- downgraded to a Fold. Or we can make the return type a Fold instead and
963-- upgrade that to a parser when needed.
965-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
966-- results. Parsing stops or fails if the collecting parser stops or fails.
967--
968-- /Unimplemented/
969--
970{-# INLINE manyP #-}
971manyP :: -- MonadCatch m =>
972 Parser m a b -> Parser m b c -> Parser m a c
973manyP _p _f = undefined -- K.toParserK $ D.manyP (K.fromParserK p) f
975-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
976-- input stream and push the parse results to a downstream fold.
977--
978-- Stops: when the downstream fold stops or the parser fails.
979-- Fails: never, produces zero or more results.
980--
981-- Compare with 'Control.Applicative.many'.
982--
983-- /Pre-release/
984--
985{-# INLINE many #-}
986many :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
987many p f = K.toParserK $ D.many (K.fromParserK p) f
988-- many = countBetween 0 maxBound
990-- Note: many1 would perhaps be a better name for this and consistent with
991-- other names like takeWhile1. But we retain the name "some" for
992-- compatibility.
993--
994-- | Collect one or more parses. Apply the supplied parser repeatedly on the
995-- input stream and push the parse results to a downstream fold.
996--
997-- Stops: when the downstream fold stops or the parser fails.
998-- Fails: if it stops without producing a single result.
999--
1000-- @some fld parser = manyP (takeGE 1 fld) parser@
1002-- Compare with 'Control.Applicative.some'.
1004-- /Pre-release/
1006{-# INLINE some #-}
1007some :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1008some p f = K.toParserK $ D.some (K.fromParserK p) f
1009-- some p f = manyP p (takeGE 1 f)
1010-- many = countBetween 1 maxBound
1012-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
1013-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
1014-- the input ends or the parser fails before @m@ results are collected.
1016-- /Unimplemented/
1018{-# INLINE countBetween #-}
1019countBetween ::
1020 -- MonadCatch m =>
1021 Int -> Int -> Parser m a b -> Fold m b c -> Parser m a c
1022countBetween _m _n _p = undefined
1023-- countBetween m n p f = manyP (takeBetween m n f) p
1025-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
1026-- the fold @f@. Fails if the input ends or the parser fails before @n@
1027-- results are collected.
1029-- /Unimplemented/
1031{-# INLINE count #-}
1032count ::
1033 -- MonadCatch m =>
1034 Int -> Parser m a b -> Fold m b c -> Parser m a c
1035count n = countBetween n n
1036-- count n p f = manyP (takeEQ n f) p
1038-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
1039-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
1041-- We can implemnent parsers like the following using 'manyTillP':
1043-- @
1044-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
1045-- @
1047-- /Unimplemented/
1049{-# INLINE manyTillP #-}
1050manyTillP :: -- MonadCatch m =>
1051 Parser m a b -> Parser m a x -> Parser m b c -> Parser m a c
1052manyTillP _p1 _p2 _f = undefined
1053 -- K.toParserK $ D.manyTillP (K.fromParserK p1) (K.fromParserK p2) f
1055-- | @manyTill f collect test@ tries the parser @test@ on the input, if @test@
1056-- fails it backtracks and tries @collect@, after @collect@ succeeds @test@ is
1057-- tried again and so on. The parser stops when @test@ succeeds. The output of
1058-- @test@ is discarded and the output of @collect@ is accumulated by the
1059-- supplied fold. The parser fails if @collect@ fails.
1061-- Stops when the fold @f@ stops.
1063-- /Pre-release/
1065{-# INLINE manyTill #-}
1066manyTill :: MonadCatch m
1067 => Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1068manyTill p1 p2 f =
1069 K.toParserK $ D.manyTill f (K.fromParserK p1) (K.fromParserK p2)
1071-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
1072-- collects the output in the supplied fold. If the the parser @collect@ fails,
1073-- parser @recover@ is run until it stops and then we start repeating the
1074-- parser @collect@ again. The parser fails if the recovery parser fails.
1076-- For example, this can be used to find a key frame in a video stream after an
1077-- error.
1079-- /Unimplemented/
1081{-# INLINE manyThen #-}
1082manyThen :: -- (Foldable t, MonadCatch m) =>
1083 Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1084manyThen _parser _recover _f = undefined
1086-------------------------------------------------------------------------------
1087-- Interleaving a collection of parsers
1088-------------------------------------------------------------------------------
1090-- | Apply a collection of parsers to an input stream in a round robin fashion.
1091-- Each parser is applied until it stops and then we repeat starting with the
1092-- the first parser again.
1094-- /Unimplemented/
1096{-# INLINE roundRobin #-}
1097roundRobin :: -- (Foldable t, MonadCatch m) =>
1098 t (Parser m a b) -> Fold m b c -> Parser m a c
1099roundRobin _ps _f = undefined
1101-------------------------------------------------------------------------------
1102-- Repeated Alternatives
1103-------------------------------------------------------------------------------
1105-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
1106-- fails the input consumed till now is dropped and the new instance is tried
1107-- on the fresh input.
1109-- /Unimplemented/
1111{-# INLINE retryMaxTotal #-}
1112retryMaxTotal :: -- (MonadCatch m) =>
1113 Int -> Parser m a b -> Fold m b c -> Parser m a c
1114retryMaxTotal _n _p _f = undefined
1116-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
1118-- /Unimplemented/
1120{-# INLINE retryMaxSuccessive #-}
1121retryMaxSuccessive :: -- (MonadCatch m) =>
1122 Int -> Parser m a b -> Fold m b c -> Parser m a c
1123retryMaxSuccessive _n _p _f = undefined
1125-- | Keep trying a parser until it succeeds. When the parser fails the input
1126-- consumed till now is dropped and the new instance is tried on the fresh
1127-- input.
1129-- /Unimplemented/
1131{-# INLINE retry #-}
1132retry :: -- (MonadCatch m) =>
1133 Parser m a b -> Parser m a b
1134retry _p = undefined