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