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