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