1{-# OPTIONS_GHC -Wno-orphans #-}
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
11-- Fast backtracking parsers with stream fusion and native streaming
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:
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.
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.
35-- Failing parsers in this module throw the 'D.ParseError' exception.
39-- As far as possible, try that the names of the combinators in this module are
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
54 -- * Downgrade to Fold
57 -- First order parsers
77 -- All of these can be expressed in terms of either
88 -- * Sequence parsers (tokenizers)
90 -- | Parsers chained in series, if one parser terminates the composition
96 -- | Grab a sequence of input elements without inspecting them
98 -- , take -- takeBetween 0 n
99 , takeEQ -- takeBetween n n
100 , takeGE -- takeBetween n maxBound
103 -- Grab a sequence of input elements by inspecting them
131 , groupByRollingEither
137 , takeFramedByGeneric
144 -- , prefixOf -- match any prefix of a given string
145 -- , suffixOf -- match any suffix of a given string
146 -- , infixOf -- match any substring of a given string
149 -- Second order parsers (parsers using parsers)
150 -- * Binary Combinators
152 -- ** Sequential Applicative
157 -- ** Parallel Applicatives
161 -- , teeTill -- like manyTill but parallel
164 -- ** Sequential Interleaving
165 -- Use two folds, run a primary parser, its rejected values go to the
168 -- , deintercalatePrefix
169 -- , deintercalateSuffix
172 -- | TODO: traditional implmentations of these may be of limited use. For
173 -- example, consider parsing lines separated by @\\r\\n@. The main parser
174 -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
175 -- can apply the "sep" parser.
177 -- We can instead implement these as special cases of deintercalate.
189 -- ** Sequential Alternative
193 -- ** Parallel Alternatives
199 -- * N-ary Combinators
200 -- ** Sequential Collection
204 -- ** Sequential Repetition
217 -- | A simple and stupid impl would be to just convert the stream to an
218 -- array and give the array reference to all consumers. The array can be
219 -- grown on demand by any consumer and truncated when nonbody needs it.
221 -- ** Distribute to collection
222 -- ** Distribute to repetition
224 -- ** Interleaved collection
231 -- ** Collection of Alternatives
237 -- , fastestN -- first N successful in time
238 -- , choiceN -- first N successful in position
240 -- , choice -- first successful in position
242 -- ** Repeated Alternatives
252import Streamly.Internal.Data.Fold.Type (Fold(..))
253import Streamly.Internal.Data.Parser.ParserK.Type (Parser)
254import Streamly.Internal.Data.Stream.Type (Stream)
256import qualified Data.Foldable as Foldable
257import qualified Streamly.Internal.Data.Fold.Type as FL
258import qualified Streamly.Internal.Data.Parser.ParserD as D
259import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
260import qualified Streamly.Internal.Data.Stream.Type as Stream
263 ( any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either
269-- >>> import Prelude hiding (any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either, filter)
270-- >>> import Control.Applicative ((<|>))
271-- >>> import Data.Char (isSpace)
272-- >>> import qualified Data.Maybe as Maybe
273-- >>> import qualified Data.Foldable as Foldable
274-- >>> import qualified Streamly.Data.Stream as Stream
275-- >>> import qualified Streamly.Internal.Data.Stream as Stream (parse, parseMany)
276-- >>> import qualified Streamly.Internal.Data.Fold as Fold
277-- >>> import qualified Streamly.Internal.Data.Parser as Parser
279-------------------------------------------------------------------------------
280-- Downgrade a parser to a Fold
281-------------------------------------------------------------------------------
283-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
284-- parser fails or tries to backtrack.
286-- This can be useful in combinators that accept a Fold and we know that a
287-- Parser cannot fail or failure exception is acceptable as there is no way to
293toFold :: Monad m => Parser a m b -> Fold m a b
294toFold p = D.toFold $ D.fromParserK p
296-------------------------------------------------------------------------------
297-- Upgrade folds to parses
298-------------------------------------------------------------------------------
300-- | Make a 'Parser' from a 'Fold'.
302{-# INLINE fromFold #-}
303fromFold :: Monad m => Fold m a b -> Parser a m b
304fromFold = D.toParserK . D.fromFold
306-- | Convert a Maybe returning fold to an error returning parser. The first
307-- argument is the error message that the parser would return when the fold
312{-# INLINE fromFoldMaybe #-}
313fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser a m b
314fromFoldMaybe err = D.toParserK . D.fromFoldMaybe err
316-------------------------------------------------------------------------------
317-- Terminating but not failing folds
318-------------------------------------------------------------------------------
320-- This is the dual of stream "fromPure".
322-- | A parser that always yields a pure value without consuming any input.
324{-# INLINE [3] fromPure #-}
325fromPure :: Monad m => b -> Parser a m b
326fromPure = D.toParserK . D.fromPure
327{-# RULES "fromPure fallback to CPS" [2]
328 forall a. D.toParserK (D.fromPure a) = K.fromPure a #-}
330-- This is the dual of stream "fromEffect".
332-- | A parser that always yields the result of an effectful action without
333-- consuming any input.
335{-# INLINE fromEffect #-}
336fromEffect :: Monad m => m b -> Parser a m b
337fromEffect = K.fromEffect -- D.toParserK . D.fromEffect
339-- This is the dual of "nil".
341-- | A parser that always fails with an error message without consuming
344{-# INLINE [3] die #-}
345die :: Monad m => String -> Parser a m 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".
352-- | A parser that always fails with an effectful error message and without
353-- consuming any input.
358dieM :: Monad m => m String -> Parser a m b
359dieM = D.toParserK . D.dieM
361-------------------------------------------------------------------------------
363-------------------------------------------------------------------------------
365-- | @lmap f parser@ maps the function @f@ on the input of the parser.
367-- >>> Stream.parse (Parser.lmap (\x -> x * x) (Parser.fromFold Fold.sum)) (Stream.enumerateFromTo 1 100)
370-- > lmap = Parser.lmapM return
373lmap :: Monad m => (a -> b) -> Parser b m r -> Parser a m r
374lmap f p = D.toParserK $ D.lmap f $ D.fromParserK p
376-- | @lmapM f parser@ maps the monadic function @f@ on the input of the parser.
379lmapM :: Monad m => (a -> m b) -> Parser b m r -> Parser a m r
380lmapM f p = D.toParserK $ D.lmapM f $ D.fromParserK p
382-- | @rmapM f parser@ maps the monadic function @f@ on the output of the parser.
386rmapM :: Monad m => (b -> m c) -> Parser a m b -> Parser a m c
387rmapM f p = D.toParserK $ D.rmapM f $ D.fromParserK p
389-- | Include only those elements that pass a predicate.
391-- >>> Stream.parse (Parser.filter (> 5) (Parser.fromFold Fold.sum)) $ Stream.fromList [1..10]
395filter :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
396filter f p = D.toParserK $ D.filter f $ D.fromParserK p
398-------------------------------------------------------------------------------
400-------------------------------------------------------------------------------
402-- | Peek the head element of a stream, without consuming it. Fails if it
403-- encounters end of input.
405-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
409-- peek = lookAhead (satisfy True)
413peek :: Monad m => Parser a m a
414peek = D.toParserK D.peek
416-- | Succeeds if we are at the end of input, fails otherwise.
418-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
422eof :: Monad m => Parser a m ()
423eof = D.toParserK D.eof
425-- | Returns the next element if it passes the predicate, fails otherwise.
427-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
430-- >>> toMaybe f x = if f x then Just x else Nothing
431-- >>> satisfy f = Parser.maybe (toMaybe f)
433{-# INLINE satisfy #-}
434satisfy :: Monad m => (a -> Bool) -> Parser a m a
435satisfy = D.toParserK . D.satisfy
437-- | Consume one element from the head of the stream. Fails if it encounters
440-- >>> one = Parser.satisfy $ const True
443one :: Monad m => Parser a m a
444one = satisfy $ const True
446-- Alternate names: "only", "onlyThis".
448-- | Match a specific element.
450-- >>> oneEq x = Parser.satisfy (== x)
453oneEq :: (Monad m, Eq a) => a -> Parser a m a
454oneEq x = satisfy (== x)
456-- Alternate names: "exclude", "notThis".
458-- | Match anything other than the supplied element.
460-- >>> oneNotEq x = Parser.satisfy (/= x)
462{-# INLINE oneNotEq #-}
463oneNotEq :: (Monad m, Eq a) => a -> Parser a m a
464oneNotEq x = satisfy (/= x)
466-- | Match any one of the elements in the supplied list.
468-- >>> oneOf xs = Parser.satisfy (`Foldable.elem` xs)
470-- When performance matters a pattern matching predicate could be more
471-- efficient than a 'Foldable' datatype:
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
487oneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
488oneOf xs = satisfy (`Foldable.elem` xs)
490-- | See performance notes in 'oneOf'.
492-- >>> noneOf xs = Parser.satisfy (`Foldable.notElem` xs)
495noneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
496noneOf xs = satisfy (`Foldable.notElem` xs)
498-- | Return the next element of the input. Returns 'Nothing'
499-- on end of input. Also known as 'head'.
503{-# DEPRECATED next "Please use \"fromFold Fold.one\" instead" #-}
505next :: Monad m => Parser a m (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'
512-- >>> toEither = Maybe.maybe (Left "maybe: predicate failed") Right
513-- >>> maybe f = Parser.either (toEither . f)
515-- >>> maybe f = Parser.fromFoldMaybe "maybe: predicate failed" (Fold.maybe f)
520maybe :: Monad m => (a -> Maybe b) -> Parser a m 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.
530either :: Monad m => (a -> Either String b) -> Parser a m b
531either = D.toParserK . D.either
533-------------------------------------------------------------------------------
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.
540-- Stops after @n@ elements.
541-- Fails if the stream ends before @m@ elements could be taken.
547-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
548-- where prsr = Parser.takeBetween low high Fold.toList
553-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
556-- >>> takeBetween' 2 4 [1, 2]
559-- >>> takeBetween' 2 4 [1]
560-- Left (ParseError "takeBetween: Expecting alteast 2 elements, got 1")
562-- >>> takeBetween' 0 0 [1, 2]
565-- >>> takeBetween' 0 1 []
568-- @takeBetween@ is the most general take operation, other take operations can
569-- be defined in terms of takeBetween. For example:
571-- >>> take n = Parser.takeBetween 0 n
572-- >>> takeEQ n = Parser.takeBetween n n
573-- >>> takeGE n = Parser.takeBetween n maxBound
577{-# INLINE takeBetween #-}
578takeBetween :: Monad m =>
579 Int -> Int -> Fold m a b -> Parser a m b
580takeBetween m n = D.toParserK . D.takeBetween m n
582-- | Stops after taking exactly @n@ input elements.
584-- * Stops - after consuming @n@ elements.
585-- * Fails - if the stream or the collecting fold ends before it can collect
586-- exactly @n@ elements.
588-- >>> Stream.parse (Parser.takeEQ 4 Fold.toList) $ Stream.fromList [1,0,1]
589-- Left (ParseError "takeEQ: Expecting exactly 4 elements, input terminated on 3")
592takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
593takeEQ n = D.toParserK . D.takeEQ n
595-- | Take at least @n@ input elements, but can collect more.
597-- * Stops - when the collecting fold stops.
598-- * Fails - if the stream or the collecting fold ends before producing @n@
601-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1]
602-- Left (ParseError "takeGE: Expecting at least 4 elements, input terminated on 3")
604-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
610takeGE :: Monad m => Int -> Fold m a b -> Parser a m b
611takeGE n = D.toParserK . D.takeGE n
613-------------------------------------------------------------------------------
614-- Take until a condition
615-------------------------------------------------------------------------------
618-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
620-- XXX We should perhaps use only takeWhileP and rename it to takeWhile.
622-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
623-- input. The combinator stops when the condition fails or if the collecting
626-- Other interesting parsers can be implemented in terms of this parser:
628-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
629-- >>> takeWhileBetween cond m n p = Parser.takeWhileP cond (Parser.takeBetween m n p)
631-- Stops: when the condition fails or the collecting parser stops.
632-- Fails: when the collecting parser fails.
636{-# INLINE takeWhileP #-}
637takeWhileP :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
638takeWhileP cond p = D.toParserK $ D.takeWhileP cond (D.fromParserK p)
640-- | Collect stream elements until an element fails the predicate. The element
641-- on which the predicate fails is returned back to the input stream.
643-- * Stops - when the predicate fails or the collecting fold stops.
646-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
649-- >>> takeWhile cond f = Parser.takeWhileP cond (Parser.fromFold f)
651-- We can implement a @breakOn@ using 'takeWhile':
654-- breakOn p = takeWhile (not p)
657{-# INLINE takeWhile #-}
658takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
659takeWhile cond = D.toParserK . D.takeWhile cond
660-- takeWhile cond f = takeWhileP cond (fromFold f)
662-- | Like 'takeWhile' but takes at least one element otherwise fails.
664-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
666{-# INLINE takeWhile1 #-}
667takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
668takeWhile1 cond = D.toParserK . D.takeWhile1 cond
669-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
671-- | Drain the input as long as the predicate succeeds, running the effects and
672-- discarding the results.
674-- This is also called @skipWhile@ in some parsing libraries.
676-- >>> dropWhile p = Parser.takeWhile p Fold.drain
678{-# INLINE dropWhile #-}
679dropWhile :: Monad m => (a -> Bool) -> Parser a m ()
680dropWhile p = takeWhile p FL.drain
682-------------------------------------------------------------------------------
684-------------------------------------------------------------------------------
686-- XXX We can remove Maybe from esc
687{-# INLINE takeFramedByGeneric #-}
688takeFramedByGeneric :: Monad m =>
694takeFramedByGeneric esc begin end f =
695 D.toParserK $ D.takeFramedByGeneric esc begin end f
697-- | @takeEndBy cond parser@ parses a token that ends by a separator chosen by
698-- the supplied predicate. The separator is also taken with the token.
700-- This can be combined with other parsers to implement other interesting
701-- parsers as follows:
703-- >>> takeEndByLE cond n p = Parser.takeEndBy cond (Parser.fromFold $ Fold.take n p)
704-- >>> takeEndByBetween cond m n p = Parser.takeEndBy cond (Parser.takeBetween m n p)
706-- >>> takeEndBy = Parser.takeEndByEsc (const False)
708-- See also "Streamly.Data.Fold.takeEndBy". Unlike the fold, the collecting
709-- parser in the takeEndBy parser can decide whether to fail or not if the
710-- stream does not end with separator.
714{-# INLINE takeEndBy #-}
715takeEndBy :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
716takeEndBy cond = D.toParserK . D.takeEndBy cond . D.fromParserK
717-- takeEndBy = takeEndByEsc (const False)
719-- | Like 'takeEndBy' but the separator is dropped.
721-- See also "Streamly.Data.Fold.takeEndBy_".
725{-# INLINE takeEndBy_ #-}
726takeEndBy_ :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
727takeEndBy_ cond = D.toParserK . D.takeEndBy_ cond . D.fromParserK
730 takeFramedByGeneric Nothing Nothing (Just isEnd) (toFold p)
733-- | Take either the separator or the token. Separator is a Left value and
734-- token is Right value.
737{-# INLINE takeEitherSepBy #-}
738takeEitherSepBy :: -- Monad m =>
739 (a -> Bool) -> Fold m (Either a b) c -> Parser a m c
740takeEitherSepBy _cond = undefined -- D.toParserK . D.takeEitherSepBy cond
742-- | Parse a token that starts with an element chosen by the predicate. The
743-- parser fails if the input does not start with the selected element.
745-- * Stops - when the predicate succeeds in non-leading position.
746-- * Fails - when the predicate fails in the leading position.
748-- >>> splitWithPrefix p f = Stream.parseMany (Parser.takeStartBy p f)
752-- >>> p = Parser.takeStartBy (== ',') Fold.toList
753-- >>> leadingComma = Stream.parse p . Stream.fromList
754-- >>> leadingComma "a,b"
755-- Left (ParseError "takeStartBy: missing frame start")
757-- >>> leadingComma ",,"
759-- >>> leadingComma ",a,b"
761-- >>> leadingComma ""
766{-# INLINE takeStartBy #-}
767takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
768takeStartBy cond = D.toParserK . D.takeStartBy cond
770-- | Like 'takeStartBy' but drops the separator.
772-- >>> takeStartBy_ isBegin = Parser.takeFramedByGeneric Nothing (Just isBegin) Nothing
774{-# INLINE takeStartBy_ #-}
775takeStartBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
776takeStartBy_ isBegin = takeFramedByGeneric Nothing (Just isBegin) Nothing
778-------------------------------------------------------------------------------
779-- Quoting and Escaping
780-------------------------------------------------------------------------------
782-- | Like 'takeEndBy' but the separator elements can be escaped using an
783-- escape char determined by the first predicate. The escape characters are
787{-# INLINE takeEndByEsc #-}
788takeEndByEsc :: Monad m =>
789 (a -> Bool) -> (a -> Bool) -> Parser a m b -> Parser a m b
790takeEndByEsc isEsc isEnd p =
791 D.toParserK $ D.takeEndByEsc isEsc isEnd (D.fromParserK p)
793-- | @takeFramedByEsc_ isEsc isBegin isEnd fold@ parses a token framed using a
794-- begin and end predicate, and an escape character. The frame begin and end
795-- characters lose their special meaning if preceded by the escape character.
797-- Nested frames are allowed if begin and end markers are different, nested
798-- frames must be balanced unless escaped, nested frame markers are emitted as
803-- >>> p = Parser.takeFramedByEsc_ (== '\\') (== '{') (== '}') Fold.toList
804-- >>> Stream.parse p $ Stream.fromList "{hello}"
806-- >>> Stream.parse p $ Stream.fromList "{hello {world}}"
807-- Right "hello {world}"
808-- >>> Stream.parse p $ Stream.fromList "{hello \\{world}"
809-- Right "hello {world"
810-- >>> Stream.parse p $ Stream.fromList "{hello {world}"
811-- Left (ParseError "takeFramedByEsc_: missing frame end")
814{-# INLINE takeFramedByEsc_ #-}
815takeFramedByEsc_ :: Monad m =>
816 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
817takeFramedByEsc_ isEsc isBegin isEnd f =
818 D.toParserK $ D.takeFramedByEsc_ isEsc isBegin isEnd f
819-- takeEndByEsc_ isEsc isEnd p =
820-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
822-- | @takeFramedBy_ isBegin isEnd fold@ parses a token framed by a begin and an
825-- >>> takeFramedBy_ = Parser.takeFramedByEsc_ (const False)
827{-# INLINE takeFramedBy_ #-}
828takeFramedBy_ :: Monad m =>
829 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
830takeFramedBy_ isBegin isEnd f = D.toParserK $ D.takeFramedBy_ isBegin isEnd f
831-- takeFramedBy_ isBegin isEnd =
832-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
834-------------------------------------------------------------------------------
836-------------------------------------------------------------------------------
838-- Note we can also get words using something like:
839-- sepBy FL.toList (takeWhile (not . p) Fold.toList) (dropWhile p)
841-- But that won't be as efficient and ergonomic.
843-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
844-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
845-- @["a","b"]@. In other words, its like parsing words from whitespace
848-- * Stops - when it finds a word separator after a non-word element
851-- >>> wordBy = Parser.wordFramedBy (const False) (const False) (const False)
854-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
858wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
859wordBy f = D.toParserK . D.wordBy f
861-- | Like 'wordBy' but treats anything inside a pair of quotes as a single
862-- word, the quotes can be escaped by an escape character. Recursive quotes
863-- are possible if quote begin and end characters are different, quotes must be
864-- balanced. Outermost quotes are stripped.
866-- >>> braces = Parser.wordFramedBy (== '\\') (== '{') (== '}') isSpace Fold.toList
867-- >>> Stream.parse braces $ Stream.fromList "{ab} cd"
869-- >>> Stream.parse braces $ Stream.fromList "{ab}{cd}"
871-- >>> Stream.parse braces $ Stream.fromList "a{b} cd"
873-- >>> Stream.parse braces $ Stream.fromList "a{{b}} cd"
876-- >>> quotes = Parser.wordFramedBy (== '\\') (== '"') (== '"') isSpace Fold.toList
877-- >>> Stream.parse quotes $ Stream.fromList "\"a\"\"b\""
880{-# INLINE wordFramedBy #-}
881wordFramedBy :: Monad m =>
882 (a -> Bool) -- ^ Escape
883 -> (a -> Bool) -- ^ left quote
884 -> (a -> Bool) -- ^ right quote
885 -> (a -> Bool) -- ^ word seperator
888wordFramedBy isEsc isBegin isEnd isSpc =
889 D.toParserK . D.wordFramedBy isEsc isBegin isEnd isSpc
891-- | Like 'wordFramedBy' but the closing quote is determined by the opening
892-- quote. The first quote begin starts a quote that is closed by its
893-- corresponding closing quote.
895-- 'wordFramedBy' and 'wordQuotedBy' both allow multiple quote characters based
896-- on the predicates but 'wordQuotedBy' always fixes the quote at the first
897-- occurrence and then it is closed only by the corresponding closing quote.
898-- Therefore, other quoting characters can be embedded inside it as normal
899-- characters. On the other hand, 'wordFramedBy' would close the quote as soon
900-- as it encounters any of the closing quotes.
902-- >>> q = (`elem` ['"', '\''])
903-- >>> p kQ = Parser.wordQuotedBy kQ (== '\\') q q id isSpace Fold.toList
905-- >>> Stream.parse (p False) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
908-- >>> Stream.parse (p True) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
909-- Right "a\"b'c\";'d\"e'f"
911{-# INLINE wordQuotedBy #-}
912wordQuotedBy :: (Monad m, Eq a) =>
913 Bool -- ^ keep the quotes in the output
914 -> (a -> Bool) -- ^ Escape
915 -> (a -> Bool) -- ^ left quote
916 -> (a -> Bool) -- ^ right quote
917 -> (a -> a) -- ^ get right quote from left quote
918 -> (a -> Bool) -- ^ word seperator
921wordQuotedBy keepQuotes isEsc isBegin isEnd toRight isSpc =
922 D.toParserK . D.wordQuotedBy keepQuotes isEsc isBegin isEnd toRight isSpc
924-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
925-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
926-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
927-- then @c@ is also assigned to the same group and so on. When the comparison
928-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
929-- the result of the fold is the result of the parser.
931-- * Stops - when the comparison fails.
936-- Stream.fold Fold.toList
937-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
941-- >>> runGroupsBy (<) []
944-- >>> runGroupsBy (<) [1]
947-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
948-- [Right [3,5,4],Right [1,2],Right [0]]
950{-# INLINE groupBy #-}
951groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
952groupBy eq = D.toParserK . D.groupBy eq
954-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
955-- successive elements in the input stream. Assuming the input stream
956-- is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
957-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
958-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
959-- then @c@ is also assigned to the same group and so on. When the comparison
960-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
961-- the result of the fold is the result of the parser.
963-- * Stops - when the comparison fails.
967-- runGroupsByRolling eq =
968-- Stream.fold Fold.toList
969-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
973-- >>> runGroupsByRolling (<) []
976-- >>> runGroupsByRolling (<) [1]
979-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
980-- [Right [3,5],Right [4],Right [1,2],Right [0]]
984{-# INLINE groupByRolling #-}
985groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
986groupByRolling eq = D.toParserK . D.groupByRolling eq
988-- | Like 'groupByRolling', but if the predicate is 'True' then collects using
989-- the first fold as long as the predicate holds 'True', if the predicate is
990-- 'False' collects using the second fold as long as it remains 'False'.
991-- Returns 'Left' for the first case and 'Right' for the second case.
993-- For example, if we want to detect sorted sequences in a stream, both
994-- ascending and descending cases we can use 'groupByRollingEither (<=)
995-- Fold.toList Fold.toList'.
998{-# INLINE groupByRollingEither #-}
999groupByRollingEither :: Monad m =>
1000 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
1001groupByRollingEither eq f1 = D.toParserK . D.groupByRollingEither eq f1
1003-- | Like 'listEqBy' but uses a stream instead of a list and does not return
1006-- See also: "Streamly.Data.Stream.streamEqBy"
1008{-# INLINE streamEqBy #-}
1009streamEqBy :: Monad m => (a -> a -> Bool) -> Stream m a -> Parser a m ()
1010streamEqBy cmp = D.toParserK . D.streamEqBy cmp . Stream.toStreamD
1012-- | Match the given sequence of elements using the given comparison function.
1013-- Returns the original sequence if successful.
1017-- >>> listEqBy cmp xs = Parser.streamEqBy cmp (Stream.fromList xs) *> Parser.fromPure xs
1021-- >>> Stream.parse (Parser.listEqBy (==) "string") $ Stream.fromList "string"
1024-- >>> Stream.parse (Parser.listEqBy (==) "mismatch") $ Stream.fromList "match"
1025-- Left (ParseError "streamEqBy: mismtach occurred")
1027{-# INLINE listEqBy #-}
1028listEqBy :: Monad m => (a -> a -> Bool) -> [a] -> Parser a m [a]
1029-- listEqBy cmp xs = D.toParserK (D.listEqBy cmp xs)
1030listEqBy cmp xs = streamEqBy cmp (Stream.fromList xs) *> fromPure xs
1033-- | Match the input sequence with the supplied list and return it if
1036-- >>> listEq = Parser.listEqBy (==)
1038{-# INLINE listEq #-}
1039listEq :: (Monad m, Eq a) => [a] -> Parser a m [a]
1040listEq = listEqBy (==)
1042-- | Match if the input stream is a subsequence of the argument stream i.e. all
1043-- the elements of the input stream occur, in order, in the argument stream.
1044-- The elements do not have to occur consecutively. A sequence is considered a
1045-- subsequence of itself.
1046{-# INLINE subsequenceBy #-}
1047subsequenceBy :: -- Monad m =>
1048 (a -> a -> Bool) -> Stream m a -> Parser a m ()
1049subsequenceBy = undefined
1052-- Should go in Data.Parser.Regex in streamly package so that it can depend on
1054{-# INLINE regexPosix #-}
1055regexPosix :: -- Monad m =>
1056 Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
1057regexPosix = undefined
1059{-# INLINE regexPCRE #-}
1060regexPCRE :: -- Monad m =>
1061 Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
1062regexPCRE = undefined
1065-------------------------------------------------------------------------------
1067-------------------------------------------------------------------------------
1069-- | Sequential parser application. Apply two parsers sequentially to an input
1070-- stream. The input is provided to the first parser, when it is done the
1071-- remaining input is provided to the second parser. If both the parsers
1072-- succeed their outputs are combined using the supplied function. The
1073-- operation fails if any of the parsers fail.
1075-- Note: This is a parsing dual of appending streams using
1076-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and zips
1079-- This implementation is strict in the second argument, therefore, the
1080-- following will fail:
1082-- >>> Stream.parse (Parser.splitWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
1083-- *** Exception: Prelude.undefined
1086-- Compare with 'Applicative' instance method '<*>'. This implementation allows
1087-- stream fusion but has quadratic complexity. This can fuse with other
1088-- operations and can be faster than 'Applicative' instance for small number
1089-- (less than 8) of compositions.
1091-- Many combinators can be expressed using @splitWith@ and other parser
1092-- primitives. Some common idioms are described below,
1095-- span :: (a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
1096-- span pred f1 f2 = splitWith (,) ('takeWhile' pred f1) ('fromFold' f2)
1100-- spanBy :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
1101-- spanBy eq f1 f2 = splitWith (,) ('groupBy' eq f1) ('fromFold' f2)
1105-- spanByRolling :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
1106-- spanByRolling eq f1 f2 = splitWith (,) ('groupByRolling' eq f1) ('fromFold' f2)
1111{-# INLINE splitWith #-}
1113 => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1115 D.toParserK $ D.splitWith f (D.fromParserK p1) (D.fromParserK p2)
1117-- | Sequential parser application ignoring the output of the first parser.
1118-- Apply two parsers sequentially to an input stream. The input is provided to
1119-- the first parser, when it is done the remaining input is provided to the
1120-- second parser. The output of the parser is the output of the second parser.
1121-- The operation fails if any of the parsers fail.
1123-- This implementation is strict in the second argument, therefore, the
1124-- following will fail:
1126-- >>> Stream.parse (Parser.split_ (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
1127-- *** Exception: Prelude.undefined
1130-- Compare with 'Applicative' instance method '*>'. This implementation allows
1131-- stream fusion but has quadratic complexity. This can fuse with other
1132-- operations, and can be faster than 'Applicative' instance for small
1133-- number (less than 8) of compositions.
1137{-# INLINE split_ #-}
1138split_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
1139split_ p1 p2 = D.toParserK $ D.split_ (D.fromParserK p1) (D.fromParserK p2)
1142-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
1143-- of them succeed or anyone of them fails and combines their output using @f@.
1144-- The parser succeeds if both the parsers succeed.
1148{-# INLINE teeWith #-}
1150 => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1152 D.toParserK $ D.teeWith f (D.fromParserK p1) (D.fromParserK p2)
1154-- | Like 'teeWith' but ends parsing and zips the results, if available,
1155-- whenever the first parser ends.
1159{-# INLINE teeWithFst #-}
1160teeWithFst :: Monad m
1161 => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1163 D.toParserK $ D.teeWithFst f (D.fromParserK p1) (D.fromParserK p2)
1165-- | Like 'teeWith' but ends parsing and zips the results, if available,
1166-- whenever any of the parsers ends or fails.
1170{-# INLINE teeWithMin #-}
1171teeWithMin :: Monad m
1172 => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1174 D.toParserK $ D.teeWithMin f (D.fromParserK p1) (D.fromParserK p2)
1177-- | Sequential alternative. Apply the input to the first parser and return the
1178-- result if the parser succeeds. If the first parser fails then backtrack and
1179-- apply the same input to the second parser and return the result.
1181-- Note: This implementation is not lazy in the second argument. The following
1184-- >>> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
1187-- Compare with 'Alternative' instance method '<|>'. This implementation allows
1188-- stream fusion but has quadratic complexity. This can fuse with other
1189-- operations and can be much faster than 'Alternative' instance for small
1190-- number (less than 8) of alternatives.
1195alt :: Monad m => Parser x m a -> Parser x m a -> Parser x m a
1196alt p1 p2 = D.toParserK $ D.alt (D.fromParserK p1) (D.fromParserK p2)
1199-- | Shortest alternative. Apply both parsers in parallel but choose the result
1200-- from the one which consumed least input i.e. take the shortest succeeding
1205{-# INLINE shortest #-}
1207 => Parser x m a -> Parser x m a -> Parser x m a
1208shortest p1 p2 = D.toParserK $ D.shortest (D.fromParserK p1) (D.fromParserK p2)
1210-- | Longest alternative. Apply both parsers in parallel but choose the result
1211-- from the one which consumed more input i.e. take the longest succeeding
1216{-# INLINE longest #-}
1218 => Parser x m a -> Parser x m a -> Parser x m a
1219longest p1 p2 = D.toParserK $ D.longest (D.fromParserK p1) (D.fromParserK p2)
1222-- | Run a parser without consuming the input.
1224{-# INLINE lookAhead #-}
1225lookAhead :: Monad m => Parser a m b -> Parser a m b
1226lookAhead p = D.toParserK $ D.lookAhead $ D.fromParserK p
1228-- | Takes at-most @n@ input elements.
1230-- * Stops - when the collecting parser stops.
1231-- * Fails - when the collecting parser fails.
1233-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
1236-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
1237-- Left (ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4")
1241takeP :: Monad m => Int -> Parser a m b -> Parser a m b
1242takeP i p = D.toParserK $ D.takeP i $ D.fromParserK p
1244-------------------------------------------------------------------------------
1245-- Sequential Collection
1246-------------------------------------------------------------------------------
1248-- | @concatSequence f p@ collects sequential parses of parsers in a
1249-- serial stream @p@ using the fold @f@. Fails if the input ends or any
1250-- of the parsers fail.
1252-- An even more efficient implementation can use ParserD type Parser in
1257{-# INLINE concatSequence #-}
1260 Fold m b c -> Stream m (Parser a m b) -> Parser a m c
1262 let sp = fmap D.fromParserK $ Stream.toStreamD p
1263 in D.toParserK $ D.sequence sp f
1265-- | Map a 'Parser' returning function on the result of a 'Parser'.
1267-- Compare with 'Monad' instance method '>>='. This implementation allows
1268-- stream fusion but has quadratic complexity. This can fuse with other
1269-- operations and can be much faster than 'Monad' instance for small number
1270-- (less than 8) of compositions.
1274{-# INLINE concatMap #-}
1276 => (b -> Parser a m c) -> Parser a m b -> Parser a m c
1277concatMap f p = D.toParserK $ D.concatMap (D.fromParserK . f) (D.fromParserK p)
1280-------------------------------------------------------------------------------
1281-- Alternative Collection
1282-------------------------------------------------------------------------------
1284-- | @choice parsers@ applies the @parsers@ in order and returns the first
1287-- This is same as 'asum' but more efficient.
1291{-# INLINE choice #-}
1293 (Functor t, Foldable t, Monad m) => t (Parser a m b) -> Parser a m b
1294choice ps = D.toParserK $ D.choice $ D.fromParserK <$> ps
1297-------------------------------------------------------------------------------
1298-- Sequential Repetition
1299-------------------------------------------------------------------------------
1301-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
1302-- results. Parsing stops or fails if the collecting parser stops or fails.
1307manyP :: -- Monad m =>
1308 Parser a m b -> Parser b m c -> Parser a m c
1309manyP _p _f = undefined -- D.toParserK $ D.manyP (D.fromParserK p) f
1311-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
1312-- input stream and push the parse results to a downstream fold.
1314-- Stops: when the downstream fold stops or the parser fails.
1315-- Fails: never, produces zero or more results.
1317-- >>> many = Parser.countBetween 0 maxBound
1319-- Compare with 'Control.Applicative.many'.
1322many :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1323many p f = D.toParserK $ D.many (D.fromParserK p) f
1325-- Note: many1 would perhaps be a better name for this and consistent with
1326-- other names like takeWhile1. But we retain the name "some" for
1329-- | Collect one or more parses. Apply the supplied parser repeatedly on the
1330-- input stream and push the parse results to a downstream fold.
1332-- Stops: when the downstream fold stops or the parser fails.
1333-- Fails: if it stops without producing a single result.
1335-- >>> some p f = Parser.manyP p (Parser.takeGE 1 f)
1336-- >>> some = Parser.countBetween 1 maxBound
1338-- Compare with 'Control.Applicative.some'.
1341some :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1342some p f = D.toParserK $ D.some (D.fromParserK p) f
1343-- some p f = manyP p (takeGE 1 f)
1344-- some = countBetween 1 maxBound
1346-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
1347-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
1348-- the input ends or the parser fails before @m@ results are collected.
1350-- >>> countBetween m n p f = Parser.manyP p (Parser.takeBetween m n f)
1354{-# INLINE countBetween #-}
1355countBetween :: -- Monad m =>
1356 Int -> Int -> Parser a m b -> Fold m b c -> Parser a m c
1357countBetween _m _n _p = undefined
1358-- countBetween m n p f = manyP p (takeBetween m n f)
1360-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
1361-- the fold @f@. Fails if the input ends or the parser fails before @n@
1362-- results are collected.
1364-- >>> count n = Parser.countBetween n n
1365-- >>> count n p f = Parser.manyP p (Parser.takeEQ n f)
1370count :: -- Monad m =>
1371 Int -> Parser a m b -> Fold m b c -> Parser a m c
1372count n = countBetween n n
1373-- count n p f = manyP p (takeEQ n f)
1375-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
1376-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
1378-- We can implemnent parsers like the following using 'manyTillP':
1381-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
1386{-# INLINE manyTillP #-}
1387manyTillP :: -- Monad m =>
1388 Parser a m b -> Parser a m x -> Parser b m c -> Parser a m c
1389manyTillP _p1 _p2 _f = undefined
1390 -- D.toParserK $ D.manyTillP (D.fromParserK p1) (D.fromParserK p2) f
1392-- | @manyTill chunking test f@ tries the parser @test@ on the input, if @test@
1393-- fails it backtracks and tries @chunking@, after @chunking@ succeeds @test@ is
1394-- tried again and so on. The parser stops when @test@ succeeds. The output of
1395-- @test@ is discarded and the output of @chunking@ is accumulated by the
1396-- supplied fold. The parser fails if @chunking@ fails.
1398-- Stops when the fold @f@ stops.
1400{-# INLINE manyTill #-}
1402 => Parser a m b -- ^ Chunking parser. Parses chunks of input.
1403 -> Parser a m x -- ^ Test parser. Parsing stops when this parser succeeds
1404 -- else backtract and run the chunking parser.
1405 -> Fold m b c -- ^ Folds the output of the chunking parser.
1407manyTill collect test f =
1408 D.toParserK $ D.manyTill (D.fromParserK collect) (D.fromParserK test) f
1410-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
1411-- collects the output in the supplied fold. If the the parser @collect@ fails,
1412-- parser @recover@ is run until it stops and then we start repeating the
1413-- parser @collect@ again. The parser fails if the recovery parser fails.
1415-- For example, this can be used to find a key frame in a video stream after an
1420{-# INLINE manyThen #-}
1421manyThen :: -- (Foldable t, Monad m) =>
1422 Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
1423manyThen _parser _recover _f = undefined
1425-------------------------------------------------------------------------------
1427-------------------------------------------------------------------------------
1429-- To deinterleave we can chain two parsers one behind the other. The input is
1430-- given to the first parser and the input definitively rejected by the first
1431-- parser is given to the second parser.
1433-- We can either have the parsers themselves buffer the input or use the shared
1434-- global buffer to hold it until none of the parsers need it. When the first
1435-- parser returns Skip (i.e. rewind) we let the second parser consume the
1436-- rejected input and when it is done we move the cursor forward to the first
1437-- parser again. This will require a "move forward" command as well.
1439-- To implement grep we can use three parsers, one to find the pattern, one
1440-- to store the context behind the pattern and one to store the context in
1441-- front of the pattern. When a match occurs we need to emit the accumulator of
1442-- all the three parsers. One parser can count the line numbers to provide the
1445-- XXX rename this to intercalate
1446-- | Apply two parsers alternately to an input stream. The input stream is
1447-- considered an interleaving of two patterns. The two parsers represent the
1450{-# INLINE deintercalate #-}
1451deintercalate :: Monad m =>
1454 -> Fold m (Either x y) z
1456deintercalate contentL contentR sink =
1459 (D.fromParserK contentL) (D.fromParserK contentR) sink
1461-- | Parse items separated by a separator parsed by the supplied parser. At
1462-- least one item must be present for the parser to succeed.
1464-- Note that this can go in infinite loop if both the parsers fail on some
1465-- input. Detection of that would make the implementation more complex.
1467{-# INLINE sepBy1 #-}
1469 Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
1470sepBy1 p sep sink = do
1472 f <- fromEffect $ FL.reduce sink
1473 f1 <- fromEffect $ FL.snoc f x
1476-- | Run the content parser first, when it is done, the separator parser is
1477-- run, when it is done content parser is run again and so on. If none of the
1478-- parsers consumes an input then parser returns a failure.
1480-- >>> sepBy p1 p2 sink = Parser.deintercalate p1 p2 (Fold.catLefts sink)
1481-- >>> sepBy content sep sink = Parser.sepBy1 content sep sink <|> return mempty
1485 Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
1486sepBy content sep sink =
1487 D.toParserK $ D.sepBy (D.fromParserK content) (D.fromParserK sep) sink
1488-- sepBy sink = deintercalate (FL.catLefts sink)
1490-------------------------------------------------------------------------------
1491-- Interleaving a collection of parsers
1492-------------------------------------------------------------------------------
1494-- | Apply a collection of parsers to an input stream in a round robin fashion.
1495-- Each parser is applied until it stops and then we repeat starting with the
1496-- the first parser again.
1500{-# INLINE roundRobin #-}
1501roundRobin :: -- (Foldable t, Monad m) =>
1502 t (Parser a m b) -> Fold m b c -> Parser a m c
1503roundRobin _ps _f = undefined
1505-------------------------------------------------------------------------------
1506-- Repeated Alternatives
1507-------------------------------------------------------------------------------
1509-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
1510-- fails the input consumed till now is dropped and the new instance is tried
1511-- on the fresh input.
1515{-# INLINE retryMaxTotal #-}
1516retryMaxTotal :: -- (Monad m) =>
1517 Int -> Parser a m b -> Fold m b c -> Parser a m c
1518retryMaxTotal _n _p _f = undefined
1520-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
1524{-# INLINE retryMaxSuccessive #-}
1525retryMaxSuccessive :: -- (Monad m) =>
1526 Int -> Parser a m b -> Fold m b c -> Parser a m c
1527retryMaxSuccessive _n _p _f = undefined
1529-- | Keep trying a parser until it succeeds. When the parser fails the input
1530-- consumed till now is dropped and the new instance is tried on the fresh
1536retry :: -- (Monad m) =>
1537 Parser a m b -> Parser a m b
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list