on bc0da07 help sign in
1512 lines 50 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 , fromFoldMaybe
61 , fromPure
62 , fromEffect
63 , die
64 , dieM
66 -- * Map on input
67 , lmap
68 , lmapM
69 , filter
71 -- * Element parsers
72 , peek
74 -- All of these can be expressed in terms of either
75 , one
76 , element
77 , except
78 , oneOf
79 , noneOf
80 , eof
81 , satisfy
82 , maybe
83 , either
85 -- * Sequence parsers (tokenizers)
86 --
87 -- | Parsers chained in series, if one parser terminates the composition
88 -- terminates.
90 , lookAhead
92 -- ** By length
93 -- | Grab a sequence of input elements without inspecting them
94 , takeBetween
95 -- , take -- takeBetween 0 n
96 , takeEQ -- takeBetween n n
97 , takeGE -- takeBetween n maxBound
98 , takeP
100 -- Grab a sequence of input elements by inspecting them
101 -- ** Exact match
102 , eqBy
103 , list
105 -- ** By predicate
106 , takeWhileP
107 , takeWhile
108 -- $takeWhile
109 , takeWhile1
110 , dropWhile
112 -- ** Separators
113 , takeEndBy
114 , takeEndBy_
115 , takeEndByEsc
116 -- , takeEndByEsc_
117 , takeStartBy
118 , takeStartBy_
119 , takeEitherSepBy
120 , wordBy
121 -- , wordByEsc
123 -- ** By comparing
124 , groupBy
125 , groupByRolling
126 , groupByRollingEither
128 -- ** Framing
129 -- , takeFramedBy
130 , takeFramedBy_
131 , takeFramedByEsc_
132 , takeFramedByGeneric
133 , wordFramedBy
134 , wordQuotedBy
136 -- | Unimplemented
137 --
138 -- @
139 -- , prefixOf -- match any prefix of a given string
140 -- , suffixOf -- match any suffix of a given string
141 -- , infixOf -- match any substring of a given string
142 -- @
144 -- Second order parsers (parsers using parsers)
145 -- * Binary Combinators
147 -- ** Sequential Applicative
148 , serialWith
149 , split_
151 -- ** Parallel Applicatives
152 , teeWith
153 , teeWithFst
154 , teeWithMin
155 -- , teeTill -- like manyTill but parallel
157 -- ** Sequential Interleaving
158 -- Use two folds, run a primary parser, its rejected values go to the
159 -- secondary parser.
160 , deintercalate
161 -- , deintercalatePrefix
162 -- , deintercalateSuffix
164 -- *** Special cases
165 -- | TODO: traditional implmentations of these may be of limited use. For
166 -- example, consider parsing lines separated by @\\r\\n@. The main parser
167 -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
168 -- can apply the "sep" parser.
169 --
170 -- We can instead implement these as special cases of deintercalate.
171 --
172 -- @
173 -- , endBy
174 -- , sepEndBy
175 -- , beginBy
176 -- , sepBeginBy
177 -- , sepAroundBy
178 -- @
179 , sepBy1
180 , sepBy
182 -- ** Sequential Alternative
183 , alt
185 -- ** Parallel Alternatives
186 , shortest
187 , longest
188 -- , fastest
190 -- * N-ary Combinators
191 -- ** Sequential Collection
192 , concatSequence
193 , concatMap
195 -- ** Sequential Repetition
196 , count
197 , countBetween
199 , manyP
200 , many
201 , some
202 , manyTillP
203 , manyTill
204 , manyThen
206 -- * Distribution
207 --
208 -- | A simple and stupid impl would be to just convert the stream to an
209 -- array and give the array reference to all consumers. The array can be
210 -- grown on demand by any consumer and truncated when nonbody needs it.
212 -- ** Distribute to collection
213 -- ** Distribute to repetition
215 -- ** Interleaved collection
216 -- |
217 --
218 -- 1. Round robin
219 -- 2. Priority based
220 , roundRobin
222 -- ** Collection of Alternatives
223 -- | Unimplemented
224 --
225 -- @
226 -- , shortestN
227 -- , longestN
228 -- , fastestN -- first N successful in time
229 -- , choiceN -- first N successful in position
230 -- @
231 , choice -- first successful in position
233 -- ** Repeated Alternatives
234 , retryMaxTotal
235 , retryMaxSuccessive
236 , retry
238 -- * Deprecated
239 , next
240 )
241where
243import Control.Monad.Catch (MonadCatch, MonadThrow)
244import Data.Functor (($>))
245import Prelude hiding
246 ( any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either
247 , filter )
249import Streamly.Internal.Data.Fold.Type (Fold(..))
250import Streamly.Internal.Data.Parser.ParserK.Type (Parser)
251import Streamly.Internal.Data.Stream.Type (Stream)
253import qualified Streamly.Internal.Data.Fold.Type as FL
254import qualified Streamly.Internal.Data.Parser.ParserD as D
255import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
256import qualified Streamly.Internal.Data.Stream.Type as Stream
258--
259-- $setup
260-- >>> :m
261-- >>> :set -package streamly
262-- >>> import Prelude hiding (any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either, filter)
263-- >>> import Control.Applicative ((<|>))
264-- >>> import Data.Char (isSpace)
265-- >>> import qualified Data.Maybe as Maybe
266-- >>> import qualified Streamly.Prelude as Stream
267-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, parseMany)
268-- >>> import qualified Streamly.Internal.Data.Fold as Fold
269-- >>> import qualified Streamly.Internal.Data.Parser as Parser
271-------------------------------------------------------------------------------
272-- Downgrade a parser to a Fold
273-------------------------------------------------------------------------------
274--
275-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
276-- parser fails or tries to backtrack.
277--
278-- This can be useful in combinators that accept a Fold and we know that a
279-- Parser cannot fail or failure exception is acceptable as there is no way to
280-- recover.
281--
282-- /Pre-release/
283--
284{-# INLINE toFold #-}
285toFold :: MonadThrow m => Parser m a b -> Fold m a b
286toFold p = D.toFold $ D.fromParserK p
288-------------------------------------------------------------------------------
289-- Upgrade folds to parses
290-------------------------------------------------------------------------------
291--
292-- | Make a 'Parser' from a 'Fold'.
293--
294-- /Pre-release/
295--
296{-# INLINE fromFold #-}
297fromFold :: MonadCatch m => Fold m a b -> Parser m a b
298fromFold = D.toParserK . D.fromFold
300-- | Convert a Maybe returning fold to an error returning parser. The first
301-- argument is the error message that the parser would return when the fold
302-- returns Nothing.
303--
304-- /Pre-release/
305--
306{-# INLINE fromFoldMaybe #-}
307fromFoldMaybe :: MonadCatch m => String -> Fold m a (Maybe b) -> Parser m a b
308fromFoldMaybe err = D.toParserK . D.fromFoldMaybe err
310-------------------------------------------------------------------------------
311-- Terminating but not failing folds
312-------------------------------------------------------------------------------
313--
314-- This is the dual of stream "fromPure".
315--
316-- | A parser that always yields a pure value without consuming any input.
317--
318-- /Pre-release/
319--
320{-# INLINE [3] fromPure #-}
321fromPure :: MonadCatch m => b -> Parser m a b
322fromPure = D.toParserK . D.fromPure
323{-# RULES "fromPure fallback to CPS" [2]
324 forall a. D.toParserK (D.fromPure a) = K.fromPure a #-}
326-- This is the dual of stream "fromEffect".
327--
328-- | A parser that always yields the result of an effectful action without
329-- consuming any input.
330--
331-- /Pre-release/
332--
333{-# INLINE fromEffect #-}
334fromEffect :: MonadCatch m => m b -> Parser m a b
335fromEffect = K.fromEffect -- D.toParserK . D.fromEffect
337-- This is the dual of "nil".
338--
339-- | A parser that always fails with an error message without consuming
340-- any input.
341--
342-- /Pre-release/
343--
344{-# INLINE [3] die #-}
345die :: MonadCatch m => String -> Parser m a b
346die = D.toParserK . D.die
347{-# RULES "die fallback to CPS" [2]
348 forall a. D.toParserK (D.die a) = K.die a #-}
350-- This is the dual of "nilM".
351--
352-- | A parser that always fails with an effectful error message and without
353-- consuming any input.
354--
355-- /Pre-release/
356--
357{-# INLINE dieM #-}
358dieM :: MonadCatch m => m String -> Parser m a b
359dieM = D.toParserK . D.dieM
361-------------------------------------------------------------------------------
362-- Map on input
363-------------------------------------------------------------------------------
365-- | @lmap f parser@ maps the function @f@ on the input of the parser.
366--
367-- >>> Stream.parse (Parser.lmap (\x -> x * x) (Parser.fromFold Fold.sum)) (Stream.enumerateFromTo 1 100)
368-- 338350
369--
370-- > lmap = Parser.lmapM return
371--
372-- /Internal/
373{-# INLINE lmap #-}
374lmap :: MonadCatch m => (a -> b) -> Parser m b r -> Parser m a r
375lmap f p = D.toParserK $ D.lmap f $ D.fromParserK p
377-- | @lmapM f parser@ maps the monadic function @f@ on the input of the parser.
378--
379-- /Internal/
380{-# INLINE lmapM #-}
381lmapM :: MonadCatch m => (a -> m b) -> Parser m b r -> Parser m a r
382lmapM f p = D.toParserK $ D.lmapM f $ D.fromParserK p
384-- | Include only those elements that pass a predicate.
385--
386-- >>> Stream.parse (Parser.filter (> 5) (Parser.fromFold Fold.sum)) $ Stream.fromList [1..10]
387-- 40
388--
389-- /Internal/
390{-# INLINE filter #-}
391filter :: MonadCatch m => (a -> Bool) -> Parser m a b -> Parser m a b
392filter f p = D.toParserK $ D.filter f $ D.fromParserK p
394-------------------------------------------------------------------------------
395-- Failing Parsers
396-------------------------------------------------------------------------------
398-- | Peek the head element of a stream, without consuming it. Fails if it
399-- encounters end of input.
400--
401-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
402-- (1,1)
403--
404-- @
405-- peek = lookAhead (satisfy True)
406-- @
407--
408-- /Pre-release/
409--
410{-# INLINE peek #-}
411peek :: MonadCatch m => Parser m a a
412peek = D.toParserK D.peek
414-- | Succeeds if we are at the end of input, fails otherwise.
415--
416-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
417-- (1,())
418--
419-- /Pre-release/
420--
421{-# INLINE eof #-}
422eof :: MonadCatch m => Parser m a ()
423eof = D.toParserK D.eof
425-- | Returns the next element if it passes the predicate, fails otherwise.
426--
427-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
428-- 1
429--
430-- >>> toMaybe f x = if f x then Just x else Nothing
431-- >>> satisfy f = Parser.maybe (toMaybe f)
432--
433-- /Pre-release/
434--
435{-# INLINE satisfy #-}
436satisfy :: MonadCatch m => (a -> Bool) -> Parser m a a
437satisfy = D.toParserK . D.satisfy
439-- | Consume one element from the head of the stream. Fails if it encounters
440-- end of input.
441--
442-- >>> one = Parser.satisfy $ const True
443--
444-- /Pre-release/
445--
446{-# INLINE one #-}
447one :: MonadCatch m => Parser m a a
448one = satisfy $ const True
450-- | Match a specific element.
451--
452-- >>> element x = Parser.satisfy (== x)
453--
454{-# INLINE element #-}
455element :: (MonadCatch m, Eq a) => a -> Parser m a a
456element x = satisfy (== x)
458-- | Match anything other than the supplied element.
459--
460-- >>> except x = Parser.satisfy (/= x)
461--
462{-# INLINE except #-}
463except :: (MonadCatch m, Eq a) => a -> Parser m a a
464except x = satisfy (/= x)
466-- | Match any one of the elements in the supplied list.
467--
468-- >>> oneOf xs = Parser.satisfy (`elem` xs)
469--
470-- When performance matters a pattern matching predicate could be more
471-- efficient than a list:
472--
473-- @
474-- let p x =
475-- case x of
476-- 'a' -> True
477-- 'e' -> True
478-- _ -> False
479-- in satisfy p
480-- @
481--
482-- GHC may use a binary search instead of linear search in the list.
483-- Alternatively, you can also use an array instead of list for storage and
484-- search.
485--
486{-# INLINE oneOf #-}
487oneOf :: (MonadCatch m, Eq a) => [a] -> Parser m a a
488oneOf xs = satisfy (`elem` xs)
490-- | See performance notes in 'oneOf'.
491--
492-- >>> noneOf xs = Parser.satisfy (`notElem` xs)
493--
494{-# INLINE noneOf #-}
495noneOf :: (MonadCatch m, Eq a) => [a] -> Parser m a a
496noneOf xs = satisfy (`notElem` xs)
498-- | Return the next element of the input. Returns 'Nothing'
499-- on end of input. Also known as 'head'.
500--
501-- /Pre-release/
502--
503{-# DEPRECATED next "Please use \"fromFold Fold.one\" instead" #-}
504{-# INLINE next #-}
505next :: MonadCatch m => Parser m a (Maybe a)
506next = D.toParserK D.next
508-- | Map a 'Maybe' returning function on the next element in the stream. The
509-- parser fails if the function returns 'Nothing' otherwise returns the 'Just'
510-- value.
511--
512-- >>> toEither = Maybe.maybe (Left "maybe: predicate failed") Right
513-- >>> maybe f = Parser.either (toEither . f)
514--
515-- >>> maybe f = Parser.fromFoldMaybe "maybe: predicate failed" (Fold.maybe f)
516--
517-- /Pre-release/
518--
519{-# INLINE maybe #-}
520maybe :: MonadCatch m => (a -> Maybe b) -> Parser m a b
521maybe = D.toParserK . D.maybe
523-- | Map an 'Either' returning function on the next element in the stream. If
524-- the function returns 'Left err', the parser fails with the error message
525-- @err@ otherwise returns the 'Right' value.
526--
527-- /Pre-release/
528--
529{-# INLINE either #-}
530either :: MonadCatch m => (a -> Either String b) -> Parser m a b
531either = D.toParserK . D.either
533-------------------------------------------------------------------------------
534-- Taking elements
535-------------------------------------------------------------------------------
537-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
538-- elements and folds them using the supplied fold.
539--
540-- Stops after @n@ elements.
541-- Fails if the stream ends before @m@ elements could be taken.
542--
543-- Examples: -
544--
545-- @
546-- >>> :{
547-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
548-- where prsr = Parser.takeBetween low high Fold.toList
549-- :}
550--
551-- @
552--
553-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
554-- [1,2,3,4]
555--
556-- >>> takeBetween' 2 4 [1, 2]
557-- [1,2]
558--
559-- >>> takeBetween' 2 4 [1]
560-- *** Exception: ParseError "takeBetween: Expecting alteast 2 elements, got 1"
561--
562-- >>> takeBetween' 0 0 [1, 2]
563-- []
564--
565-- >>> takeBetween' 0 1 []
566-- []
567--
568-- @takeBetween@ is the most general take operation, other take operations can
569-- be defined in terms of takeBetween. For example:
570--
571-- >>> take n = Parser.takeBetween 0 n
572-- >>> takeEQ n = Parser.takeBetween n n
573-- >>> takeGE n = Parser.takeBetween n maxBound
574--
575-- /Pre-release/
576--
577{-# INLINE takeBetween #-}
578takeBetween :: MonadCatch m =>
579 Int -> Int -> Fold m a b -> Parser m a b
580takeBetween m n = D.toParserK . D.takeBetween m n
582-- | Stops after taking exactly @n@ input elements.
583--
584-- * Stops - after consuming @n@ elements.
585-- * Fails - if the stream or the collecting fold ends before it can collect
586-- exactly @n@ elements.
587--
588-- >>> Stream.parse (Parser.takeEQ 4 Fold.toList) $ Stream.fromList [1,0,1]
589-- *** Exception: ParseError "takeEQ: Expecting exactly 4 elements, input terminated on 3"
590--
591-- /Pre-release/
592--
593{-# INLINE takeEQ #-}
594takeEQ :: MonadCatch m => Int -> Fold m a b -> Parser m a b
595takeEQ n = D.toParserK . D.takeEQ n
597-- | Take at least @n@ input elements, but can collect more.
598--
599-- * Stops - when the collecting fold stops.
600-- * Fails - if the stream or the collecting fold ends before producing @n@
601-- elements.
602--
603-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1]
604-- *** Exception: ParseError "takeGE: Expecting at least 4 elements, input terminated on 3"
605--
606-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
607-- [1,0,1,0,1]
608--
609-- /Pre-release/
610--
611{-# INLINE takeGE #-}
612takeGE :: MonadCatch m => Int -> Fold m a b -> Parser m a b
613takeGE n = D.toParserK . D.takeGE n
615-------------------------------------------------------------------------------
616-- Take until a condition
617-------------------------------------------------------------------------------
619-- $takeWhile
620-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
622-- XXX We should perhaps use only takeWhileP and rename it to takeWhile.
623--
624-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
625-- input. The combinator stops when the condition fails or if the collecting
626-- parser stops.
627--
628-- Other interesting parsers can be implemented in terms of this parser:
629--
630-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
631-- >>> takeWhileBetween cond m n p = Parser.takeWhileP cond (Parser.takeBetween m n p)
632--
633-- Stops: when the condition fails or the collecting parser stops.
634-- Fails: when the collecting parser fails.
635--
636-- /Pre-release/
637--
638{-# INLINE takeWhileP #-}
639takeWhileP :: MonadCatch m => (a -> Bool) -> Parser m a b -> Parser m a b
640takeWhileP cond p = D.toParserK $ D.takeWhileP cond (D.fromParserK p)
642-- | Collect stream elements until an element fails the predicate. The element
643-- on which the predicate fails is returned back to the input stream.
644--
645-- * Stops - when the predicate fails or the collecting fold stops.
646-- * Fails - never.
647--
648-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
649-- [0,0]
650--
651-- >>> takeWhile cond f = Parser.takeWhileP cond (Parser.fromFold f)
652--
653-- We can implement a @breakOn@ using 'takeWhile':
654--
655-- @
656-- breakOn p = takeWhile (not p)
657-- @
658--
659-- /Pre-release/
660--
661{-# INLINE takeWhile #-}
662takeWhile :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
663takeWhile cond = D.toParserK . D.takeWhile cond
664-- takeWhile cond f = takeWhileP cond (fromFold f)
666-- | Like 'takeWhile' but takes at least one element otherwise fails.
667--
668-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
669--
670-- /Pre-release/
671--
672{-# INLINE takeWhile1 #-}
673takeWhile1 :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
674takeWhile1 cond = D.toParserK . D.takeWhile1 cond
675-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
677-- | Drain the input as long as the predicate succeeds, running the effects and
678-- discarding the results.
679--
680-- This is also called @skipWhile@ in some parsing libraries.
681--
682-- >>> dropWhile p = Parser.takeWhile p Fold.drain
683--
684-- /Pre-release/
685--
686{-# INLINE dropWhile #-}
687dropWhile :: MonadCatch m => (a -> Bool) -> Parser m a ()
688dropWhile p = takeWhile p FL.drain
690-------------------------------------------------------------------------------
691-- Separators
692-------------------------------------------------------------------------------
694-- XXX We can remove Maybe from esc
695{-# INLINE takeFramedByGeneric #-}
696takeFramedByGeneric :: MonadCatch m =>
697 Maybe (a -> Bool)
698 -> Maybe (a -> Bool)
699 -> Maybe (a -> Bool)
700 -> Fold m a b
701 -> Parser m a b
702takeFramedByGeneric esc begin end f =
703 D.toParserK $ D.takeFramedByGeneric esc begin end f
705-- | @takeEndBy cond parser@ parses a token that ends by a separator chosen by
706-- the supplied predicate. The separator is also taken with the token.
707--
708-- This can be combined with other parsers to implement other interesting
709-- parsers as follows:
710--
711-- >>> takeEndByLE cond n p = Parser.takeEndBy cond (Parser.fromFold $ Fold.take n p)
712-- >>> takeEndByBetween cond m n p = Parser.takeEndBy cond (Parser.takeBetween m n p)
713--
714-- >>> takeEndBy = Parser.takeEndByEsc (const False)
715--
716-- See also "Streamly.Data.Fold.takeEndBy". Unlike the fold, the collecting
717-- parser in the takeEndBy parser can decide whether to fail or not if the
718-- stream does not end with separator.
719--
720-- /Pre-release/
721--
722{-# INLINE takeEndBy #-}
723takeEndBy :: MonadCatch m => (a -> Bool) -> Parser m a b -> Parser m a b
724takeEndBy cond = D.toParserK . D.takeEndBy cond . D.fromParserK
725-- takeEndBy = takeEndByEsc (const False)
727-- | Like 'takeEndBy' but the separator is dropped.
728--
729-- See also "Streamly.Data.Fold.takeEndBy_".
730--
731-- /Pre-release/
732--
733{-# INLINE takeEndBy_ #-}
734takeEndBy_ :: MonadCatch m => (a -> Bool) -> Parser m a b -> Parser m a b
735takeEndBy_ cond = D.toParserK . D.takeEndBy_ cond . D.fromParserK
736{-
737takeEndBy_ isEnd p =
738 takeFramedByGeneric Nothing Nothing (Just isEnd) (toFold p)
739-}
741-- | Take either the separator or the token. Separator is a Left value and
742-- token is Right value.
743--
744-- /Unimplemented/
745{-# INLINE takeEitherSepBy #-}
746takeEitherSepBy :: -- MonadCatch m =>
747 (a -> Bool) -> Fold m (Either a b) c -> Parser m a c
748takeEitherSepBy _cond = undefined -- D.toParserK . D.takeEitherSepBy cond
750-- | Parse a token that starts with an element chosen by the predicate. The
751-- parser fails if the input does not start with the selected element.
752--
753-- * Stops - when the predicate succeeds in non-leading position.
754-- * Fails - when the predicate fails in the leading position.
755--
756-- >>> splitWithPrefix p f = Stream.parseMany (Parser.takeStartBy p f)
757--
758-- Examples: -
759--
760-- >>> p = Parser.takeStartBy (== ',') Fold.toList
761-- >>> leadingComma = Stream.parse p . Stream.fromList
762-- >>> leadingComma "a,b"
763-- *** Exception: ParseError "takeStartBy: missing frame start"
764-- ...
765-- >>> leadingComma ",,"
766-- ","
767-- >>> leadingComma ",a,b"
768-- ",a"
769-- >>> leadingComma ""
770-- ""
771--
772-- /Pre-release/
773--
774{-# INLINE takeStartBy #-}
775takeStartBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
776takeStartBy cond = D.toParserK . D.takeStartBy cond
778-- | Like 'takeStartBy' but drops the separator.
779--
780-- >>> takeStartBy_ isBegin = Parser.takeFramedByGeneric Nothing (Just isBegin) Nothing
781--
782{-# INLINE takeStartBy_ #-}
783takeStartBy_ :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
784takeStartBy_ isBegin = takeFramedByGeneric Nothing (Just isBegin) Nothing
786-------------------------------------------------------------------------------
787-- Quoting and Escaping
788-------------------------------------------------------------------------------
790-- | Like 'takeEndBy' but the separator elements can be escaped using an
791-- escape char determined by the first predicate. The escape characters are
792-- removed.
793--
794-- /pre-release/
795{-# INLINE takeEndByEsc #-}
796takeEndByEsc :: MonadCatch m =>
797 (a -> Bool) -> (a -> Bool) -> Parser m a b -> Parser m a b
798takeEndByEsc isEsc isEnd p =
799 D.toParserK $ D.takeEndByEsc isEsc isEnd (D.fromParserK p)
801-- | @takeFramedByEsc_ isEsc isBegin isEnd fold@ parses a token framed using a
802-- begin and end predicate, and an escape character. The frame begin and end
803-- characters lose their special meaning if preceded by the escape character.
804--
805-- Nested frames are allowed if begin and end markers are different, nested
806-- frames must be balanced unless escaped, nested frame markers are emitted as
807-- it is.
808--
809-- For example,
810--
811-- >>> p = Parser.takeFramedByEsc_ (== '\\') (== '{') (== '}') Fold.toList
812-- >>> Stream.parse p $ Stream.fromList "{hello}"
813-- "hello"
814-- >>> Stream.parse p $ Stream.fromList "{hello {world}}"
815-- "hello {world}"
816-- >>> Stream.parse p $ Stream.fromList "{hello \\{world}"
817-- "hello {world"
818-- >>> Stream.parse p $ Stream.fromList "{hello {world}"
819-- *** Exception: ParseError "takeFramedByEsc_: missing frame end"
820--
821-- /Pre-release/
822{-# INLINE takeFramedByEsc_ #-}
823takeFramedByEsc_ :: MonadCatch m =>
824 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
825takeFramedByEsc_ isEsc isBegin isEnd f =
826 D.toParserK $ D.takeFramedByEsc_ isEsc isBegin isEnd f
827-- takeEndByEsc_ isEsc isEnd p =
828-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
830-- | @takeFramedBy_ isBegin isEnd fold@ parses a token framed by a begin and an
831-- end predicate.
832--
833-- >>> takeFramedBy_ = Parser.takeFramedByEsc_ (const False)
834--
835{-# INLINE takeFramedBy_ #-}
836takeFramedBy_ :: MonadCatch m =>
837 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
838takeFramedBy_ isBegin isEnd f = D.toParserK $ D.takeFramedBy_ isBegin isEnd f
839-- takeFramedBy_ isBegin isEnd =
840-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
842-------------------------------------------------------------------------------
843-- Grouping and words
844-------------------------------------------------------------------------------
846-- Note we can also get words using something like:
847-- sepBy FL.toList (takeWhile (not . p) Fold.toList) (dropWhile p)
848--
849-- But that won't be as efficient and ergonomic.
850--
851-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
852-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
853-- @["a","b"]@. In other words, its like parsing words from whitespace
854-- separated text.
855--
856-- * Stops - when it finds a word separator after a non-word element
857-- * Fails - never.
858--
859-- >>> wordBy = Parser.wordFramedBy (const False) (const False) (const False)
860--
861-- @
862-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
863-- @
864--
865{-# INLINE wordBy #-}
866wordBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
867wordBy f = D.toParserK . D.wordBy f
869-- | Like 'wordBy' but treats anything inside a pair of quotes as a single
870-- word, the quotes can be escaped by an escape character. Recursive quotes
871-- are possible if quote begin and end characters are different, quotes must be
872-- balanced. Outermost quotes are stripped.
873--
874-- >>> braces = Parser.wordFramedBy (== '\\') (== '{') (== '}') isSpace Fold.toList
875-- >>> Stream.parse braces $ Stream.fromList "{ab} cd"
876-- "ab"
877-- >>> Stream.parse braces $ Stream.fromList "{ab}{cd}"
878-- "abcd"
879-- >>> Stream.parse braces $ Stream.fromList "a{b} cd"
880-- "ab"
881-- >>> Stream.parse braces $ Stream.fromList "a{{b}} cd"
882-- "a{b}"
883--
884-- >>> quotes = Parser.wordFramedBy (== '\\') (== '"') (== '"') isSpace Fold.toList
885-- >>> Stream.parse quotes $ Stream.fromList "\"a\"\"b\""
886-- "ab"
887--
888-- /Pre-release/
889{-# INLINE wordFramedBy #-}
890wordFramedBy :: MonadCatch m =>
891 (a -> Bool) -- ^ Escape
892 -> (a -> Bool) -- ^ left quote
893 -> (a -> Bool) -- ^ right quote
894 -> (a -> Bool) -- ^ word seperator
895 -> Fold m a b
896 -> Parser m a b
897wordFramedBy isEsc isBegin isEnd isSpc =
898 D.toParserK . D.wordFramedBy isEsc isBegin isEnd isSpc
900-- | Like 'wordFramedBy' but the closing quote is determined by the opening
901-- quote. The first quote begin starts a quote that is closed by its
902-- corresponding closing quote.
903--
904-- 'wordFramedBy' and 'wordQuotedBy' both allow multiple quote characters based
905-- on the predicates but 'wordQuotedBy' always fixes the quote at the first
906-- occurrence and then it is closed only by the corresponding closing quote.
907-- Therefore, other quoting characters can be embedded inside it as normal
908-- characters. On the other hand, 'wordFramedBy' would close the quote as soon
909-- as it encounters any of the closing quotes.
910--
911-- >>> q = (`elem` ['"', '\''])
912-- >>> p kQ = Parser.wordQuotedBy kQ (== '\\') q q id isSpace Fold.toList
913--
914-- >>> Stream.parse (p False) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
915-- "ab'c;d\"ef"
916--
917-- >>> Stream.parse (p True) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
918-- "a\"b'c\";'d\"e'f"
919--
920{-# INLINE wordQuotedBy #-}
921wordQuotedBy :: (MonadCatch m, Eq a) =>
922 Bool -- ^ keep the quotes in the output
923 -> (a -> Bool) -- ^ Escape
924 -> (a -> Bool) -- ^ left quote
925 -> (a -> Bool) -- ^ right quote
926 -> (a -> a) -- ^ get right quote from left quote
927 -> (a -> Bool) -- ^ word seperator
928 -> Fold m a b
929 -> Parser m a b
930wordQuotedBy keepQuotes isEsc isBegin isEnd toRight isSpc =
931 D.toParserK . D.wordQuotedBy keepQuotes isEsc isBegin isEnd toRight isSpc
933-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
934-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
935-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
936-- then @c@ is also assigned to the same group and so on. When the comparison
937-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
938-- the result of the fold is the result of the parser.
939--
940-- * Stops - when the comparison fails.
941-- * Fails - never.
942--
943-- >>> :{
944-- runGroupsBy eq =
945-- Stream.toList
946-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
947-- . Stream.fromList
948-- :}
949--
950-- >>> runGroupsBy (<) []
951-- []
952--
953-- >>> runGroupsBy (<) [1]
954-- [[1]]
955--
956-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
957-- [[3,5,4],[1,2],[0]]
958--
959-- /Pre-release/
960--
961{-# INLINE groupBy #-}
962groupBy :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
963groupBy eq = D.toParserK . D.groupBy eq
965-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
966-- successive elements in the input stream. Assuming the input stream
967-- is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
968-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
969-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
970-- then @c@ is also assigned to the same group and so on. When the comparison
971-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
972-- the result of the fold is the result of the parser.
973--
974-- * Stops - when the comparison fails.
975-- * Fails - never.
976--
977-- >>> :{
978-- runGroupsByRolling eq =
979-- Stream.toList
980-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
981-- . Stream.fromList
982-- :}
983--
984-- >>> runGroupsByRolling (<) []
985-- []
986--
987-- >>> runGroupsByRolling (<) [1]
988-- [[1]]
989--
990-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
991-- [[3,5],[4],[1,2],[0]]
992--
993-- /Pre-release/
994--
995{-# INLINE groupByRolling #-}
996groupByRolling :: MonadCatch m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
997groupByRolling eq = D.toParserK . D.groupByRolling eq
999-- | Like 'groupByRolling', but if the predicate is 'True' then collects using
1000-- the first fold as long as the predicate holds 'True', if the predicate is
1001-- 'False' collects using the second fold as long as it remains 'False'.
1002-- Returns 'Left' for the first case and 'Right' for the second case.
1004-- For example, if we want to detect sorted sequences in a stream, both
1005-- ascending and descending cases we can use 'groupByRollingEither (<=)
1006-- Fold.toList Fold.toList'.
1008-- /Unimplemented/
1009{-# INLINE groupByRollingEither #-}
1010groupByRollingEither :: MonadCatch m =>
1011 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (Either b c)
1012groupByRollingEither eq f1 = D.toParserK . D.groupByRollingEither eq f1
1014-- XXX Use a stream instead of a list so that we can use any container type.
1016-- | Match the given sequence of elements using the given comparison function.
1018-- >>> Stream.parse (Parser.eqBy (==) "string") $ Stream.fromList "string"
1020-- >>> Stream.parse (Parser.eqBy (==) "mismatch") $ Stream.fromList "match"
1021-- *** Exception: ParseError "eqBy: failed, yet to match 7 elements"
1023-- /Pre-release/
1025{-# INLINE eqBy #-}
1026eqBy :: MonadCatch m => (a -> a -> Bool) -> [a] -> Parser m a ()
1027eqBy cmp = D.toParserK . D.eqBy cmp
1029-- | Match the input sequence with the supplied list and return it if
1030-- successful.
1032-- /Pre-release/
1033{-# INLINE list #-}
1034list :: (MonadCatch m, Eq a) => [a] -> Parser m a [a]
1035list xs = eqBy (==) xs $> xs
1037-------------------------------------------------------------------------------
1038-- nested parsers
1039-------------------------------------------------------------------------------
1041-- | Sequential parser application. Apply two parsers sequentially to an input
1042-- stream. The input is provided to the first parser, when it is done the
1043-- remaining input is provided to the second parser. If both the parsers
1044-- succeed their outputs are combined using the supplied function. The
1045-- operation fails if any of the parsers fail.
1047-- Note: This is a parsing dual of appending streams using
1048-- 'Streamly.Prelude.serial', it splits the streams using two parsers and zips
1049-- the results.
1051-- This implementation is strict in the second argument, therefore, the
1052-- following will fail:
1054-- >>> Stream.parse (Parser.serialWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
1055-- *** Exception: Prelude.undefined
1056-- ...
1058-- Compare with 'Applicative' instance method '<*>'. This implementation allows
1059-- stream fusion but has quadratic complexity. This can fuse with other
1060-- operations and can be faster than 'Applicative' instance for small number
1061-- (less than 8) of compositions.
1063-- Many combinators can be expressed using @serialWith@ and other parser
1064-- primitives. Some common idioms are described below,
1066-- @
1067-- span :: (a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
1068-- span pred f1 f2 = serialWith (,) ('takeWhile' pred f1) ('fromFold' f2)
1069-- @
1071-- @
1072-- spanBy :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
1073-- spanBy eq f1 f2 = serialWith (,) ('groupBy' eq f1) ('fromFold' f2)
1074-- @
1076-- @
1077-- spanByRolling :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser m a b
1078-- spanByRolling eq f1 f2 = serialWith (,) ('groupByRolling' eq f1) ('fromFold' f2)
1079-- @
1081-- /Pre-release/
1083{-# INLINE serialWith #-}
1084serialWith :: MonadCatch m
1085 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
1086serialWith f p1 p2 =
1087 D.toParserK $ D.serialWith f (D.fromParserK p1) (D.fromParserK p2)
1089-- | Sequential parser application ignoring the output of the first parser.
1090-- Apply two parsers sequentially to an input stream. The input is provided to
1091-- the first parser, when it is done the remaining input is provided to the
1092-- second parser. The output of the parser is the output of the second parser.
1093-- The operation fails if any of the parsers fail.
1095-- This implementation is strict in the second argument, therefore, the
1096-- following will fail:
1098-- >>> Stream.parse (Parser.split_ (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
1099-- *** Exception: Prelude.undefined
1100-- ...
1102-- Compare with 'Applicative' instance method '*>'. This implementation allows
1103-- stream fusion but has quadratic complexity. This can fuse with other
1104-- operations, and can be faster than 'Applicative' instance for small
1105-- number (less than 8) of compositions.
1107-- /Pre-release/
1109{-# INLINE split_ #-}
1110split_ :: MonadCatch m => Parser m x a -> Parser m x b -> Parser m x b
1111split_ p1 p2 = D.toParserK $ D.split_ (D.fromParserK p1) (D.fromParserK p2)
1113-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
1114-- of them succeed or anyone of them fails and combines their output using @f@.
1115-- The parser succeeds if both the parsers succeed.
1117-- /Pre-release/
1119{-# INLINE teeWith #-}
1120teeWith :: MonadCatch m
1121 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
1122teeWith f p1 p2 =
1123 D.toParserK $ D.teeWith f (D.fromParserK p1) (D.fromParserK p2)
1125-- | Like 'teeWith' but ends parsing and zips the results, if available,
1126-- whenever the first parser ends.
1128-- /Pre-release/
1130{-# INLINE teeWithFst #-}
1131teeWithFst :: MonadCatch m
1132 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
1133teeWithFst f p1 p2 =
1134 D.toParserK $ D.teeWithFst f (D.fromParserK p1) (D.fromParserK p2)
1136-- | Like 'teeWith' but ends parsing and zips the results, if available,
1137-- whenever any of the parsers ends or fails.
1139-- /Unimplemented/
1141{-# INLINE teeWithMin #-}
1142teeWithMin :: MonadCatch m
1143 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
1144teeWithMin f p1 p2 =
1145 D.toParserK $ D.teeWithMin f (D.fromParserK p1) (D.fromParserK p2)
1147-- | Sequential alternative. Apply the input to the first parser and return the
1148-- result if the parser succeeds. If the first parser fails then backtrack and
1149-- apply the same input to the second parser and return the result.
1151-- Note: This implementation is not lazy in the second argument. The following
1152-- will fail:
1154-- >>> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
1155-- 1
1157-- Compare with 'Alternative' instance method '<|>'. This implementation allows
1158-- stream fusion but has quadratic complexity. This can fuse with other
1159-- operations and can be much faster than 'Alternative' instance for small
1160-- number (less than 8) of alternatives.
1162-- /Pre-release/
1164{-# INLINE alt #-}
1165alt :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
1166alt p1 p2 = D.toParserK $ D.alt (D.fromParserK p1) (D.fromParserK p2)
1168-- | Shortest alternative. Apply both parsers in parallel but choose the result
1169-- from the one which consumed least input i.e. take the shortest succeeding
1170-- parse.
1172-- /Pre-release/
1174{-# INLINE shortest #-}
1175shortest :: MonadCatch m
1176 => Parser m x a -> Parser m x a -> Parser m x a
1177shortest p1 p2 = D.toParserK $ D.shortest (D.fromParserK p1) (D.fromParserK p2)
1179-- | Longest alternative. Apply both parsers in parallel but choose the result
1180-- from the one which consumed more input i.e. take the longest succeeding
1181-- parse.
1183-- /Pre-release/
1185{-# INLINE longest #-}
1186longest :: MonadCatch m
1187 => Parser m x a -> Parser m x a -> Parser m x a
1188longest p1 p2 = D.toParserK $ D.longest (D.fromParserK p1) (D.fromParserK p2)
1190-- | Run a parser without consuming the input.
1192-- /Pre-release/
1194{-# INLINE lookAhead #-}
1195lookAhead :: MonadCatch m => Parser m a b -> Parser m a b
1196lookAhead p = D.toParserK $ D.lookAhead $ D.fromParserK p
1198-- | Takes at-most @n@ input elements.
1200-- * Stops - when the collecting parser stops.
1201-- * Fails - when the collecting parser fails.
1203-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
1204-- [1,2]
1206-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
1207-- *** Exception: ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4"
1209-- /Internal/
1210{-# INLINE takeP #-}
1211takeP :: MonadCatch m => Int -> Parser m a b -> Parser m a b
1212takeP i p = D.toParserK $ D.takeP i $ D.fromParserK p
1214-------------------------------------------------------------------------------
1215-- Sequential Collection
1216-------------------------------------------------------------------------------
1218-- | @concatSequence f p@ collects sequential parses of parsers in a
1219-- serial stream @p@ using the fold @f@. Fails if the input ends or any
1220-- of the parsers fail.
1222-- An even more efficient implementation can use ParserD type Parser in
1223-- the stream.
1225-- /Pre-release/
1227{-# INLINE concatSequence #-}
1228concatSequence ::
1229 MonadCatch m =>
1230 Fold m b c -> Stream m (Parser m a b) -> Parser m a c
1231concatSequence f p =
1232 let sp = fmap D.fromParserK $ Stream.toStreamD p
1233 in D.toParserK $ D.sequence f sp
1235-- | Map a 'Parser' returning function on the result of a 'Parser'.
1237-- Compare with 'Monad' instance method '>>='. This implementation allows
1238-- stream fusion but has quadratic complexity. This can fuse with other
1239-- operations and can be much faster than 'Monad' instance for small number
1240-- (less than 8) of compositions.
1242-- /Pre-release/
1244{-# INLINE concatMap #-}
1245concatMap :: MonadCatch m
1246 => (b -> Parser m a c) -> Parser m a b -> Parser m a c
1247concatMap f p = D.toParserK $ D.concatMap (D.fromParserK . f) (D.fromParserK p)
1249-------------------------------------------------------------------------------
1250-- Alternative Collection
1251-------------------------------------------------------------------------------
1253-- | @choice parsers@ applies the @parsers@ in order and returns the first
1254-- successful parse.
1256-- This is same as 'asum' but more efficient.
1258-- /Broken/
1260{-# INLINE choice #-}
1261choice ::
1262 (Functor t, Foldable t, MonadCatch m) => t (Parser m a b) -> Parser m a b
1263choice ps = D.toParserK $ D.choice $ D.fromParserK <$> ps
1265-------------------------------------------------------------------------------
1266-- Sequential Repetition
1267-------------------------------------------------------------------------------
1269-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
1270-- results. Parsing stops or fails if the collecting parser stops or fails.
1272-- /Unimplemented/
1274{-# INLINE manyP #-}
1275manyP :: -- MonadCatch m =>
1276 Parser m a b -> Parser m b c -> Parser m a c
1277manyP _p _f = undefined -- D.toParserK $ D.manyP (D.fromParserK p) f
1279-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
1280-- input stream and push the parse results to a downstream fold.
1282-- Stops: when the downstream fold stops or the parser fails.
1283-- Fails: never, produces zero or more results.
1285-- >>> many = Parser.countBetween 0 maxBound
1287-- Compare with 'Control.Applicative.many'.
1289-- /Pre-release/
1291{-# INLINE many #-}
1292many :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1293many p f = D.toParserK $ D.many (D.fromParserK p) f
1295-- Note: many1 would perhaps be a better name for this and consistent with
1296-- other names like takeWhile1. But we retain the name "some" for
1297-- compatibility.
1299-- | Collect one or more parses. Apply the supplied parser repeatedly on the
1300-- input stream and push the parse results to a downstream fold.
1302-- Stops: when the downstream fold stops or the parser fails.
1303-- Fails: if it stops without producing a single result.
1305-- >>> some p f = Parser.manyP p (Parser.takeGE 1 f)
1306-- >>> some = Parser.countBetween 1 maxBound
1308-- Compare with 'Control.Applicative.some'.
1310-- /Pre-release/
1312{-# INLINE some #-}
1313some :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1314some p f = D.toParserK $ D.some (D.fromParserK p) f
1315-- some p f = manyP p (takeGE 1 f)
1316-- some = countBetween 1 maxBound
1318-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
1319-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
1320-- the input ends or the parser fails before @m@ results are collected.
1322-- >>> countBetween m n p f = Parser.manyP p (Parser.takeBetween m n f)
1324-- /Unimplemented/
1326{-# INLINE countBetween #-}
1327countBetween :: -- MonadCatch m =>
1328 Int -> Int -> Parser m a b -> Fold m b c -> Parser m a c
1329countBetween _m _n _p = undefined
1330-- countBetween m n p f = manyP p (takeBetween m n f)
1332-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
1333-- the fold @f@. Fails if the input ends or the parser fails before @n@
1334-- results are collected.
1336-- >>> count n = Parser.countBetween n n
1337-- >>> count n p f = Parser.manyP p (Parser.takeEQ n f)
1339-- /Unimplemented/
1341{-# INLINE count #-}
1342count :: -- MonadCatch m =>
1343 Int -> Parser m a b -> Fold m b c -> Parser m a c
1344count n = countBetween n n
1345-- count n p f = manyP p (takeEQ n f)
1347-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
1348-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
1350-- We can implemnent parsers like the following using 'manyTillP':
1352-- @
1353-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
1354-- @
1356-- /Unimplemented/
1358{-# INLINE manyTillP #-}
1359manyTillP :: -- MonadCatch m =>
1360 Parser m a b -> Parser m a x -> Parser m b c -> Parser m a c
1361manyTillP _p1 _p2 _f = undefined
1362 -- D.toParserK $ D.manyTillP (D.fromParserK p1) (D.fromParserK p2) f
1364-- | @manyTill f collect test@ tries the parser @test@ on the input, if @test@
1365-- fails it backtracks and tries @collect@, after @collect@ succeeds @test@ is
1366-- tried again and so on. The parser stops when @test@ succeeds. The output of
1367-- @test@ is discarded and the output of @collect@ is accumulated by the
1368-- supplied fold. The parser fails if @collect@ fails.
1370-- Stops when the fold @f@ stops.
1372-- /Pre-release/
1374{-# INLINE manyTill #-}
1375manyTill :: MonadCatch m
1376 => Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1377manyTill p1 p2 f =
1378 D.toParserK $ D.manyTill f (D.fromParserK p1) (D.fromParserK p2)
1380-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
1381-- collects the output in the supplied fold. If the the parser @collect@ fails,
1382-- parser @recover@ is run until it stops and then we start repeating the
1383-- parser @collect@ again. The parser fails if the recovery parser fails.
1385-- For example, this can be used to find a key frame in a video stream after an
1386-- error.
1388-- /Unimplemented/
1390{-# INLINE manyThen #-}
1391manyThen :: -- (Foldable t, MonadCatch m) =>
1392 Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1393manyThen _parser _recover _f = undefined
1395-------------------------------------------------------------------------------
1396-- Interleaving
1397-------------------------------------------------------------------------------
1399-- To deinterleave we can chain two parsers one behind the other. The input is
1400-- given to the first parser and the input definitively rejected by the first
1401-- parser is given to the second parser.
1403-- We can either have the parsers themselves buffer the input or use the shared
1404-- global buffer to hold it until none of the parsers need it. When the first
1405-- parser returns Skip (i.e. rewind) we let the second parser consume the
1406-- rejected input and when it is done we move the cursor forward to the first
1407-- parser again. This will require a "move forward" command as well.
1409-- To implement grep we can use three parsers, one to find the pattern, one
1410-- to store the context behind the pattern and one to store the context in
1411-- front of the pattern. When a match occurs we need to emit the accumulator of
1412-- all the three parsers. One parser can count the line numbers to provide the
1413-- line number info.
1415-- XXX rename this to intercalate
1416-- | Apply two parsers alternately to an input stream. The input stream is
1417-- considered an interleaving of two patterns. The two parsers represent the
1418-- two patterns.
1420-- This undoes a "gintercalate" of two streams.
1422-- /Pre-release/
1424{-# INLINE deintercalate #-}
1425deintercalate :: MonadCatch m =>
1426 Fold m (Either x y) z
1427 -> Parser m a x
1428 -> Parser m a y
1429 -> Parser m a z
1430deintercalate sink contentL contentR =
1431 D.toParserK
1432 $ D.deintercalate
1433 sink (D.fromParserK contentL) (D.fromParserK contentR)
1435-- | Parse items separated by a separator parsed by the supplied parser. At
1436-- least one item must be present for the parser to succeed.
1438-- Note that this can go in infinite loop if both the parsers fail on some
1439-- input. Detection of that would make the implementation more complex.
1441{-# INLINE sepBy1 #-}
1442sepBy1 :: MonadCatch m =>
1443 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1444sepBy1 sink p sep = do
1445 x <- p
1446 f <- fromEffect $ FL.initialize sink
1447 f1 <- fromEffect $ FL.snoc f x
1448 many (sep >> p) f1
1450-- | Run the content parser first, when it is done, the separator parser is
1451-- run, when it is done content parser is run again and so on. If none of the
1452-- parsers consumes an input then parser returns a failure.
1454-- >>> sepBy sink = Parser.deintercalate (Fold.lefts sink)
1455-- >>> sepBy sink content sep = Parser.sepBy1 sink content sep <|> return mempty
1457{-# INLINE sepBy #-}
1458sepBy :: MonadCatch m =>
1459 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1460sepBy sink content sep =
1461 D.toParserK $ D.sepBy sink (D.fromParserK content) (D.fromParserK sep)
1462-- sepBy sink = deintercalate (FL.lefts sink)
1464-------------------------------------------------------------------------------
1465-- Interleaving a collection of parsers
1466-------------------------------------------------------------------------------
1468-- | Apply a collection of parsers to an input stream in a round robin fashion.
1469-- Each parser is applied until it stops and then we repeat starting with the
1470-- the first parser again.
1472-- /Unimplemented/
1474{-# INLINE roundRobin #-}
1475roundRobin :: -- (Foldable t, MonadCatch m) =>
1476 t (Parser m a b) -> Fold m b c -> Parser m a c
1477roundRobin _ps _f = undefined
1479-------------------------------------------------------------------------------
1480-- Repeated Alternatives
1481-------------------------------------------------------------------------------
1483-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
1484-- fails the input consumed till now is dropped and the new instance is tried
1485-- on the fresh input.
1487-- /Unimplemented/
1489{-# INLINE retryMaxTotal #-}
1490retryMaxTotal :: -- (MonadCatch m) =>
1491 Int -> Parser m a b -> Fold m b c -> Parser m a c
1492retryMaxTotal _n _p _f = undefined
1494-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
1496-- /Unimplemented/
1498{-# INLINE retryMaxSuccessive #-}
1499retryMaxSuccessive :: -- (MonadCatch m) =>
1500 Int -> Parser m a b -> Fold m b c -> Parser m a c
1501retryMaxSuccessive _n _p _f = undefined
1503-- | Keep trying a parser until it succeeds. When the parser fails the input
1504-- consumed till now is dropped and the new instance is tried on the fresh
1505-- input.
1507-- /Unimplemented/
1509{-# INLINE retry #-}
1510retry :: -- (MonadCatch m) =>
1511 Parser m a b -> Parser m a b
1512retry _p = undefined