on b52ed84 help sign in
871 lines 28 kB history raw
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE RankNTypes #-}
3{-# LANGUAGE ScopedTypeVariables #-}
5#if __GLASGOW_HASKELL__ >= 800
6{-# OPTIONS_GHC -Wno-orphans #-}
7#endif
9-- |
10-- Module : Streamly.Internal.Data.Parser
11-- Copyright : (c) 2020 Composewell Technologies
12-- License : BSD-3-Clause
13-- Maintainer : streamly@composewell.com
14-- Stability : experimental
15-- Portability : GHC
16--
17-- Fast backtracking parsers with stream fusion and native streaming
18-- capability.
19--
20-- 'Applicative' and 'Control.Applicative.Alternative' type class based
21-- combinators from the
22-- <http://hackage.haskell.org/package/parser-combinators parser-combinators>
23-- package can also be used with the 'Parser' type. However, there are two
24-- important differences between @parser-combinators@ and the equivalent ones
25-- provided in this module in terms of performance:
26--
27-- 1) @parser-combinators@ use plain Haskell lists to collect the results, in a
28-- strict Monad like IO, the results are necessarily buffered before they can
29-- be consumed. This may not perform optimally in streaming applications
30-- processing large amounts of data. Equivalent combinators in this module can
31-- consume the results of parsing using a 'Fold', thus providing a scalability
32-- and a composable consumer.
33--
34-- 2) Several combinators in this module can be many times faster because of
35-- stream fusion. For example, 'Streamly.Internal.Data.Parser.many' combinator
36-- in this module is much faster than the 'Control.Applicative.many' combinator
37-- of 'Control.Applicative.Alternative' type class.
38--
39-- = Errors
40--
41-- Failing parsers in this module throw the 'D.ParseError' exception.
42--
43-- = Naming
44--
45-- As far as possible, try that the names of the combinators in this module are
46-- consistent with:
47--
48-- * <https://hackage.haskell.org/package/base/docs/Text-ParserCombinators-ReadP.html base/Text.ParserCombinators.ReadP>
49-- * <http://hackage.haskell.org/package/parser-combinators parser-combinators>
50-- * <http://hackage.haskell.org/package/megaparsec megaparsec>
51-- * <http://hackage.haskell.org/package/attoparsec attoparsec>
52-- * <http://hackage.haskell.org/package/parsec parsec>
54module Streamly.Internal.Data.Parser
55 (
56 K.Parser (..)
57 , D.ParseError (..)
58 , D.Step (..)
60 -- First order parsers
61 -- * Accumulators
62 , fromFold
63 , any
64 , all
65 , yield
66 , yieldM
67 , die
68 , dieM
70 -- * Element parsers
71 , peek
72 , eof
73 , satisfy
75 -- * Sequence parsers
76 --
77 -- | Parsers chained in series, if one parser terminates the composition
78 -- terminates.
79 --
80 -- TODO: Currently we are using folds to collect the output of the parsers
81 -- but we can use Parsers instead of folds to make the composition more
82 -- powerful. For example, we can do:
83 --
84 -- @
85 -- sliceSepByMax cond n p = sliceBy cond (take n p)
86 -- sliceSepByBetween cond m n p = sliceBy cond (takeBetween m n p)
87 -- takeWhileBetween cond m n p = takeWhile cond (takeBetween m n p)
88 -- @
89 --
90 -- TODO: Like toList fold we can have toNonEmpty Parser to fold to a
91 -- nonempty list. If we cannot collect even one element the parser will
92 -- fail. toNonEmpty can be used in takeWhile to implement takeWhile1.
94 -- | Grab a sequence of input elements without inspecting them
95 , take
96 -- $take
97 -- | Unimplemented
98 --
99 -- @
100 -- , takeBetween
101 -- , takeLE -- take -- takeBetween 0 n
102 -- , takeLE1 -- take1 -- takeBetween 1 n
103 -- @
104 , takeEQ -- takeBetween n n
105 , takeGE -- takeBetween n maxBound
107 -- Grab a sequence of input elements by inspecting them
108 , lookAhead
109 , takeWhile
110 -- $takeWhile
111 , takeWhile1
112 , sliceSepBy
113 , sliceSepByMax
114 -- | Unimplemented
115 --
116 -- @
117 -- , sliceSepByBetween
118 -- @
119 , sliceEndWith
120 , sliceBeginWith
121 -- | Unimplemented
122 --
123 -- @
124 -- , sliceSepWith
125 --
126 -- , frameSepBy -- parse frames escaped by an escape char/sequence
127 -- , frameEndWith
128 -- @
129 , wordBy
130 , groupBy
131 , eqBy
132 -- | Unimplemented
133 --
134 -- @
135 -- , prefixOf -- match any prefix of a given string
136 -- , suffixOf -- match any suffix of a given string
137 -- , infixOf -- match any substring of a given string
138 -- @
140 -- Second order parsers (parsers using parsers)
141 -- * Binary Combinators
143 -- ** Sequential Applicative
144 , splitWith
145 , split_
147 -- ** Parallel Applicatives
148 , teeWith
149 , teeWithFst
150 , teeWithMin
151 -- , teeTill -- like manyTill but parallel
153 -- ** Sequential Interleaving
154 -- Use two folds, run a primary parser, its rejected values go to the
155 -- secondary parser.
156 , deintercalate
158 -- ** Sequential Alternative
159 , alt
161 -- ** Parallel Alternatives
162 , shortest
163 , longest
164 -- , fastest
166 -- * N-ary Combinators
167 -- ** Sequential Collection
168 , sequence
169 , concatMap
171 -- ** Sequential Repetition
172 , count
173 , countBetween
174 -- , countBetweenTill
176 , many
177 , some
178 , manyTill
180 -- ** Special cases
181 -- | TODO: traditional implmentations of these may be of limited use. For
182 -- example, consider parsing lines separated by @\\r\\n@. The main parser
183 -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
184 -- can apply the "sep" parser.
185 --
186 -- We can instead implement these as special cases of deintercalate.
187 --
188 -- @
189 -- , endBy
190 -- , sepBy
191 -- , sepEndBy
192 -- , beginBy
193 -- , sepBeginBy
194 -- , sepAroundBy
195 -- @
197 -- * Distribution
198 --
199 -- | A simple and stupid impl would be to just convert the stream to an
200 -- array and give the array reference to all consumers. The array can be
201 -- grown on demand by any consumer and truncated when nonbody needs it.
203 -- ** Distribute to collection
204 -- ** Distribute to repetition
206 -- ** Interleaved collection
207 -- |
208 --
209 -- 1. Round robin
210 -- 2. Priority based
212 -- ** Interleaved repetition
213 -- | repeat one parser and when it fails run an error recovery parser
214 -- e.g. to find a key frame in the stream after an error
216 -- ** Collection of Alternatives
217 -- | Unimplemented
218 --
219 -- @
220 -- , shortestN
221 -- , longestN
222 -- , fastestN -- first N successful in time
223 -- , choiceN -- first N successful in position
224 -- @
225 , choice -- first successful in position
227 -- ** Repeated Alternatives
228 -- |
229 --
230 -- @
231 -- , retryMax -- try N times
232 -- , retryUntil -- try until successful
233 -- , retryUntilN -- try until successful n times
234 -- @
235 )
236where
238import Control.Monad.Catch (MonadCatch)
239import Prelude
240 hiding (any, all, take, takeWhile, sequence, concatMap)
242import Streamly.Internal.Data.Fold.Types (Fold(..))
243import Streamly.Internal.Data.Parser.ParserK.Types (Parser)
245import qualified Streamly.Internal.Data.Parser.ParserD as D
246import qualified Streamly.Internal.Data.Parser.ParserK.Types as K
248-------------------------------------------------------------------------------
249-- Upgrade folds to parses
250-------------------------------------------------------------------------------
251--
252-- | Make a 'Parser' from a 'Fold'.
253--
254-- /Internal/
255--
256{-# INLINE fromFold #-}
257fromFold :: MonadCatch m => Fold m a b -> Parser m a b
258fromFold = D.toParserK . D.fromFold
260-------------------------------------------------------------------------------
261-- Terminating but not failing folds
262-------------------------------------------------------------------------------
263--
264-- |
265-- >>> S.parse (PR.any (== 0)) $ S.fromList [1,0,1]
266-- > True
267--
268{-# INLINE any #-}
269any :: MonadCatch m => (a -> Bool) -> Parser m a Bool
270any = D.toParserK . D.any
272-- |
273-- >>> S.parse (PR.all (== 0)) $ S.fromList [1,0,1]
274-- > False
275--
276{-# INLINE all #-}
277all :: MonadCatch m => (a -> Bool) -> Parser m a Bool
278all = D.toParserK . D.all
280-- This is the dual of stream "yield".
281--
282-- | A parser that always yields a pure value without consuming any input.
283--
284-- /Internal/
285--
286{-# INLINE [3] yield #-}
287yield :: MonadCatch m => b -> Parser m a b
288yield = D.toParserK . D.yield
289{-# RULES "yield fallback to CPS" [2]
290 forall a. D.toParserK (D.yield a) = K.yield a #-}
292-- This is the dual of stream "yieldM".
293--
294-- | A parser that always yields the result of an effectful action without
295-- consuming any input.
296--
297-- /Internal/
298--
299{-# INLINE yieldM #-}
300yieldM :: MonadCatch m => m b -> Parser m a b
301yieldM = D.toParserK . D.yieldM
303-- This is the dual of "nil".
304--
305-- | A parser that always fails with an error message without consuming
306-- any input.
307--
308-- /Internal/
309--
310{-# INLINE [3] die #-}
311die :: MonadCatch m => String -> Parser m a b
312die = D.toParserK . D.die
313{-# RULES "die fallback to CPS" [2]
314 forall a. D.toParserK (D.die a) = K.die a #-}
316-- This is the dual of "nilM".
317--
318-- | A parser that always fails with an effectful error message and without
319-- consuming any input.
320--
321-- /Internal/
322--
323{-# INLINE dieM #-}
324dieM :: MonadCatch m => m String -> Parser m a b
325dieM = D.toParserK . D.dieM
327-------------------------------------------------------------------------------
328-- Failing Parsers
329-------------------------------------------------------------------------------
331-- | Peek the head element of a stream, without consuming it. Fails if it
332-- encounters end of input.
333--
334-- >>> S.parse ((,) <$> PR.peek <*> PR.satisfy (> 0)) $ S.fromList [1]
335-- (1,1)
336--
337-- @
338-- peek = lookAhead (satisfy True)
339-- @
340--
341-- /Internal/
342--
343{-# INLINE peek #-}
344peek :: MonadCatch m => Parser m a a
345peek = D.toParserK D.peek
347-- | Succeeds if we are at the end of input, fails otherwise.
348--
349-- >>> S.parse ((,) <$> PR.satisfy (> 0) <*> PR.eof) $ S.fromList [1]
350-- > (1,())
351--
352-- /Internal/
353--
354{-# INLINE eof #-}
355eof :: MonadCatch m => Parser m a ()
356eof = D.toParserK D.eof
358-- | Returns the next element if it passes the predicate, fails otherwise.
359--
360-- >>> S.parse (PR.satisfy (== 1)) $ S.fromList [1,0,1]
361-- > 1
362--
363-- /Internal/
364--
365{-# INLINE satisfy #-}
366satisfy :: MonadCatch m => (a -> Bool) -> Parser m a a
367satisfy = D.toParserK . D.satisfy
369-------------------------------------------------------------------------------
370-- Taking elements
371-------------------------------------------------------------------------------
372--
373-- $take
374-- Note: this is called takeP in some parser libraries.
375--
376-- TODO Once we have terminating folds, this Parse should get replaced by Fold.
377-- Alternatively, we can name it "chunkOf" and the corresponding time domain
378-- combinator as "intervalOf" or even "chunk" and "interval".
380-- | Take at most @n@ input elements and fold them using the supplied fold.
381--
382-- Stops after @n@ elements.
383-- Never fails.
384--
385-- >>> S.parse (PR.take 1 FL.toList) $ S.fromList [1]
386-- [1]
387--
388-- @
389-- S.chunksOf n f = S.splitParse (FL.take n f)
390-- @
391--
392-- /Internal/
393--
394{-# INLINE take #-}
395take :: MonadCatch m => Int -> Fold m a b -> Parser m a b
396take n = D.toParserK . D.take n
398-- | Stops after taking exactly @n@ input elements.
399--
400-- * Stops - after @n@ elements.
401-- * Fails - if the stream ends before it can collect @n@ elements.
402--
403-- >>> S.parse (PR.takeEQ 4 FL.toList) $ S.fromList [1,0,1]
404-- > "takeEQ: Expecting exactly 4 elements, got 3"
405--
406-- /Internal/
407--
408{-# INLINE takeEQ #-}
409takeEQ :: MonadCatch m => Int -> Fold m a b -> Parser m a b
410takeEQ n = D.toParserK . D.takeEQ n
412-- | Take at least @n@ input elements, but can collect more.
413--
414-- * Stops - never.
415-- * Fails - if the stream end before producing @n@ elements.
416--
417-- >>> S.parse (PR.takeGE 4 FL.toList) $ S.fromList [1,0,1]
418-- > "takeGE: Expecting at least 4 elements, got only 3"
419--
420-- >>> S.parse (PR.takeGE 4 FL.toList) $ S.fromList [1,0,1,0,1]
421-- > [1,0,1,0,1]
422--
423-- /Internal/
424--
425{-# INLINE takeGE #-}
426takeGE :: MonadCatch m => Int -> Fold m a b -> Parser m a b
427takeGE n = D.toParserK . D.takeGE n
429-- $takeWhile
430-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
432-- | Collect stream elements until an element fails the predicate. The element
433-- on which the predicate fails is returned back to the input stream.
434--
435-- * Stops - when the predicate fails.
436-- * Fails - never.
437--
438-- >>> S.parse (PR.takeWhile (== 0) FL.toList) $ S.fromList [0,0,1,0,1]
439-- > [0,0]
440--
441-- We can implement a @breakOn@ using 'takeWhile':
442--
443-- @
444-- breakOn p = takeWhile (not p)
445-- @
446--
447-- /Internal/
448--
449{-# INLINE takeWhile #-}
450takeWhile :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
451takeWhile cond = D.toParserK . D.takeWhile cond
453-- | Like 'takeWhile' but takes at least one element otherwise fails.
454--
455-- /Internal/
456--
457{-# INLINE takeWhile1 #-}
458takeWhile1 :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
459takeWhile1 cond = D.toParserK . D.takeWhile1 cond
461-- | Collect stream elements until an element succeeds the predicate. Drop the
462-- element on which the predicate succeeded. The succeeding element is treated
463-- as an infix separator which is dropped from the output.
464--
465-- * Stops - when the predicate succeeds.
466-- * Fails - never.
467--
468-- >>> S.parse (PR.sliceSepBy (== 1) FL.toList) $ S.fromList [0,0,1,0,1]
469-- > [0,0]
470--
471-- S.splitOn pred f = S.splitParse (PR.sliceSepBy pred f)
472--
473-- >>> S.toList $ S.splitParse (PR.sliceSepBy (== 1) FL.toList) $ S.fromList [0,0,1,0,1]
474-- > [[0,0],[0],[]]
475--
476-- /Internal/
477--
478{-# INLINABLE sliceSepBy #-}
479sliceSepBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
480sliceSepBy cond = D.toParserK . D.sliceSepBy cond
482-- | Collect stream elements until an element succeeds the predicate. Also take
483-- the element on which the predicate succeeded. The succeeding element is
484-- treated as a suffix separator which is kept in the output segement.
485--
486-- * Stops - when the predicate succeeds.
487-- * Fails - never.
488--
489-- S.splitWithSuffix pred f = S.splitParse (PR.sliceEndWith pred f)
490--
491-- /Unimplemented/
492--
493{-# INLINABLE sliceEndWith #-}
494sliceEndWith ::
495 -- Monad m =>
496 (a -> Bool) -> Fold m a b -> Parser m a b
497sliceEndWith = undefined
499-- | Collect stream elements until an elements passes the predicate, return the
500-- last element on which the predicate succeeded back to the input stream. If
501-- the predicate succeeds on the first element itself then it is kept in the
502-- stream and we continue collecting. The succeeding element is treated as a
503-- prefix separator which is kept in the output segement.
504--
505-- * Stops - when the predicate succeeds in non-leading position.
506-- * Fails - never.
507--
508-- S.splitWithPrefix pred f = S.splitParse (PR.sliceBeginWith pred f)
509--
510-- /Unimplemented/
511--
512{-# INLINABLE sliceBeginWith #-}
513sliceBeginWith ::
514 -- Monad m =>
515 (a -> Bool) -> Fold m a b -> Parser m a b
516sliceBeginWith = undefined
518-- | Split using a condition or a count whichever occurs first. This is a
519-- hybrid of 'splitOn' and 'take'. The element on which the condition succeeds
520-- is dropped.
521--
522-- /Internal/
523--
524{-# INLINABLE sliceSepByMax #-}
525sliceSepByMax :: MonadCatch m
526 => (a -> Bool) -> Int -> Fold m a b -> Parser m a b
527sliceSepByMax cond cnt = D.toParserK . D.sliceSepByMax cond cnt
529-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
530-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
531-- @["a","b"]@. In other words, its like parsing words from whitespace
532-- separated text.
533--
534-- * Stops - when it finds a word separator after a non-word element
535-- * Fails - never.
536--
537-- @
538-- S.wordsBy pred f = S.splitParse (PR.wordBy pred f)
539-- @
540--
541-- /Unimplemented/
542--
543{-# INLINABLE wordBy #-}
544wordBy ::
545 -- Monad m =>
546 (a -> Bool) -> Fold m a b -> Parser m a b
547wordBy = undefined
549-- | @groupBy cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
550-- first group, then if @a \`cmp` b@ is 'True' @b@ is also assigned to the same
551-- group. If @a \`cmp` c@ is 'True' then @c@ is also assigned to the same
552-- group and so on. When the comparison fails a new group is started. Each
553-- group is folded using the 'Fold' @f@ and the result of the fold is emitted
554-- in the output stream.
555--
556-- * Stops - when the comparison fails.
557-- * Fails - never.
558--
559-- @
560-- S.groupsBy cmp f = S.splitParse (PR.groupBy cmp f)
561-- @
562--
563-- /Unimplemented/
564--
565{-# INLINABLE groupBy #-}
566groupBy ::
567 -- Monad m =>
568 (a -> a -> Bool) -> Fold m a b -> Parser m a b
569groupBy = undefined
571-- | Match the given sequence of elements using the given comparison function.
572--
573-- /Internal/
574--
575{-# INLINE eqBy #-}
576eqBy :: MonadCatch m => (a -> a -> Bool) -> [a] -> Parser m a ()
577eqBy cmp = D.toParserK . D.eqBy cmp
579-------------------------------------------------------------------------------
580-- nested parsers
581-------------------------------------------------------------------------------
583-- | Sequential parser application. Apply two parsers sequentially to an input
584-- stream. The input is provided to the first parser, when it is done the
585-- remaining input is provided to the second parser. If both the parsers
586-- succeed their outputs are combined using the supplied function. The
587-- operation fails if any of the parsers fail.
588--
589-- Note: This is a parsing dual of appending streams using
590-- 'Streamly.Prelude.serial', it splits the streams using two parsers and zips
591-- the results.
592--
593-- This implementation is strict in the second argument, therefore, the
594-- following will fail:
595--
596-- >>> S.parse (PR.splitWith const (PR.satisfy (> 0)) undefined) $ S.fromList [1]
597--
598-- Compare with 'Applicative' instance method '<*>'. This implementation allows
599-- stream fusion but has quadratic complexity. This can fuse with other
600-- operations and can be faster than 'Applicative' instance for small number
601-- (less than 8) of compositions.
602--
603-- /Internal/
604--
605{-# INLINE splitWith #-}
606splitWith :: MonadCatch m
607 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
608splitWith f p1 p2 =
609 D.toParserK $ D.splitWith f (D.fromParserK p1) (D.fromParserK p2)
611-- | Sequential parser application ignoring the output of the first parser.
612-- Apply two parsers sequentially to an input stream. The input is provided to
613-- the first parser, when it is done the remaining input is provided to the
614-- second parser. The output of the parser is the output of the second parser.
615-- The operation fails if any of the parsers fail.
616--
617-- This implementation is strict in the second argument, therefore, the
618-- following will fail:
619--
620-- >>> S.parse (split_ (PR.satisfy (> 0)) undefined) $ S.fromList [1]
621--
622-- Compare with 'Applicative' instance method '*>'. This implementation allows
623-- stream fusion but has quadratic complexity. This can fuse with other
624-- operations, and can be faster than 'Applicative' instance for small
625-- number (less than 8) of compositions.
626--
627-- /Internal/
628--
629{-# INLINE split_ #-}
630split_ :: MonadCatch m => Parser m x a -> Parser m x b -> Parser m x b
631split_ p1 p2 = D.toParserK $ D.split_ (D.fromParserK p1) (D.fromParserK p2)
633-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
634-- of them succeed or anyone of them fails and combines their output using @f@.
635-- The parser succeeds if both the parsers succeed.
636--
637-- /Internal/
638--
639{-# INLINE teeWith #-}
640teeWith :: MonadCatch m
641 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
642teeWith f p1 p2 =
643 D.toParserK $ D.teeWith f (D.fromParserK p1) (D.fromParserK p2)
645-- | Like 'teeWith' but ends parsing and zips the results, if available,
646-- whenever the first parser ends.
647--
648-- /Internal/
649--
650{-# INLINE teeWithFst #-}
651teeWithFst :: MonadCatch m
652 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
653teeWithFst f p1 p2 =
654 D.toParserK $ D.teeWithFst f (D.fromParserK p1) (D.fromParserK p2)
656-- | Like 'teeWith' but ends parsing and zips the results, if available,
657-- whenever any of the parsers ends or fails.
658--
659-- /Unimplemented/
660--
661{-# INLINE teeWithMin #-}
662teeWithMin :: MonadCatch m
663 => (a -> b -> c) -> Parser m x a -> Parser m x b -> Parser m x c
664teeWithMin f p1 p2 =
665 D.toParserK $ D.teeWithMin f (D.fromParserK p1) (D.fromParserK p2)
667-- | Sequential alternative. Apply the input to the first parser and return the
668-- result if the parser succeeds. If the first parser fails then backtrack and
669-- apply the same input to the second parser and return the result.
670--
671-- Note: This implementation is not lazy in the second argument. The following
672-- will fail:
673--
674-- >>> S.parse (PR.satisfy (> 0) `PR.alt` undefined) $ S.fromList [1..10]
675--
676-- Compare with 'Alternative' instance method '<|>'. This implementation allows
677-- stream fusion but has quadratic complexity. This can fuse with other
678-- operations and can be much faster than 'Alternative' instance for small
679-- number (less than 8) of alternatives.
680--
681-- /Internal/
682--
683{-# INLINE alt #-}
684alt :: MonadCatch m => Parser m x a -> Parser m x a -> Parser m x a
685alt p1 p2 = D.toParserK $ D.alt (D.fromParserK p1) (D.fromParserK p2)
687-- | Shortest alternative. Apply both parsers in parallel but choose the result
688-- from the one which consumed least input i.e. take the shortest succeeding
689-- parse.
690--
691-- /Internal/
692--
693{-# INLINE shortest #-}
694shortest :: MonadCatch m
695 => Parser m x a -> Parser m x a -> Parser m x a
696shortest p1 p2 = D.toParserK $ D.shortest (D.fromParserK p1) (D.fromParserK p2)
698-- | Longest alternative. Apply both parsers in parallel but choose the result
699-- from the one which consumed more input i.e. take the longest succeeding
700-- parse.
701--
702-- /Internal/
703--
704{-# INLINE longest #-}
705longest :: MonadCatch m
706 => Parser m x a -> Parser m x a -> Parser m x a
707longest p1 p2 = D.toParserK $ D.longest (D.fromParserK p1) (D.fromParserK p2)
709-- | Run a parser without consuming the input.
710--
711-- /Internal/
712--
713{-# INLINE lookAhead #-}
714lookAhead :: MonadCatch m => Parser m a b -> Parser m a b
715lookAhead p = D.toParserK $ D.lookAhead $ D.fromParserK p
717-------------------------------------------------------------------------------
718-- Interleaving
719-------------------------------------------------------------------------------
720--
721-- To deinterleave we can chain two parsers one behind the other. The input is
722-- given to the first parser and the input definitively rejected by the first
723-- parser is given to the second parser.
724--
725-- We can either have the parsers themselves buffer the input or use the shared
726-- global buffer to hold it until none of the parsers need it. When the first
727-- parser returns Skip (i.e. rewind) we let the second parser consume the
728-- rejected input and when it is done we move the cursor forward to the first
729-- parser again. This will require a "move forward" command as well.
730--
731-- To implement grep we can use three parsers, one to find the pattern, one
732-- to store the context behind the pattern and one to store the context in
733-- front of the pattern. When a match occurs we need to emit the accumulator of
734-- all the three parsers. One parser can count the line numbers to provide the
735-- line number info.
736--
737-- | Apply two parsers alternately to an input stream. The input stream is
738-- considered an interleaving of two patterns. The two parsers represent the
739-- two patterns.
740--
741-- This undoes a "gintercalate" of two streams.
742--
743-- /Unimplemented/
744--
745{-# INLINE deintercalate #-}
746deintercalate ::
747 -- Monad m =>
748 Fold m a y -> Parser m x a
749 -> Fold m b z -> Parser m x b
750 -> Parser m x (y, z)
751deintercalate = undefined
753-------------------------------------------------------------------------------
754-- Sequential Collection
755-------------------------------------------------------------------------------
756--
757-- | @sequence f t@ collects sequential parses of parsers in the container @t@
758-- using the fold @f@. Fails if the input ends or any of the parsers fail.
759--
760-- /Unimplemented/
761--
762{-# INLINE sequence #-}
763sequence ::
764 -- Foldable t =>
765 Fold m b c -> t (Parser m a b) -> Parser m a c
766sequence _f _p = undefined
768-- | Map a 'Parser' returning function on the result of a 'Parser'.
769--
770-- Compare with 'Monad' instance method '>>='. This implementation allows
771-- stream fusion but has quadratic complexity. This can fuse with other
772-- operations and can be much faster than 'Monad' instance for small number
773-- (less than 8) of compositions.
774--
775-- /Internal/
776--
777{-# INLINE concatMap #-}
778concatMap :: MonadCatch m
779 => (b -> Parser m a c) -> Parser m a b -> Parser m a c
780concatMap f p = D.toParserK $ D.concatMap (D.fromParserK . f) (D.fromParserK p)
782-------------------------------------------------------------------------------
783-- Alternative Collection
784-------------------------------------------------------------------------------
785--
786-- | @choice parsers@ applies the @parsers@ in order and returns the first
787-- successful parse.
788--
789{-# INLINE choice #-}
790choice ::
791 -- Foldable t =>
792 t (Parser m a b) -> Parser m a b
793choice _ps = undefined
795-------------------------------------------------------------------------------
796-- Sequential Repetition
797-------------------------------------------------------------------------------
798--
799-- $many
800-- TODO "many" is essentially a Fold because it cannot fail. So it can be
801-- downgraded to a Fold. Or we can make the return type a Fold instead and
802-- upgrade that to a parser when needed.
804-- | Collect zero or more parses. Apply the parser repeatedly on the input
805-- stream, stop when the parser fails, accumulate zero or more parse results
806-- using the supplied 'Fold'. This parser never fails, in case the first
807-- application of parser fails it returns an empty result.
808--
809-- Compare with 'Control.Applicative.many'.
810--
811-- /Internal/
812--
813{-# INLINE many #-}
814many :: MonadCatch m => Fold m b c -> Parser m a b -> Parser m a c
815many f p = D.toParserK $ D.many f (D.fromParserK p)
816-- many = countBetween 0 maxBound
818-- | Collect one or more parses. Apply the supplied parser repeatedly on the
819-- input stream and accumulate the parse results as long as the parser
820-- succeeds, stop when it fails. This parser fails if not even one result is
821-- collected.
822--
823-- Compare with 'Control.Applicative.some'.
824--
825-- /Internal/
826--
827{-# INLINE some #-}
828some :: MonadCatch m => Fold m b c -> Parser m a b -> Parser m a c
829some f p = D.toParserK $ D.some f (D.fromParserK p)
830-- some f p = many (takeGE 1 f) p
831-- many = countBetween 1 maxBound
833-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
834-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
835-- the input ends or the parser fails before @m@ results are collected.
836--
837-- /Unimplemented/
838--
839{-# INLINE countBetween #-}
840countBetween ::
841 -- MonadCatch m =>
842 Int -> Int -> Fold m b c -> Parser m a b -> Parser m a c
843countBetween _m _n _f = undefined
844-- countBetween m n f p = many (takeBetween m n f) p
846-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
847-- the fold @f@. Fails if the input ends or the parser fails before @n@
848-- results are collected.
849--
850-- /Unimplemented/
851--
852{-# INLINE count #-}
853count ::
854 -- MonadCatch m =>
855 Int -> Fold m b c -> Parser m a b -> Parser m a c
856count n = countBetween n n
857-- count n f p = many (takeEQ n f) p
859-- | @manyTill f collect test@ tries the parser @test@ on the input, if @test@
860-- fails it backtracks and tries @collect@, after @collect@ succeeds @test@ is
861-- tried again and so on. The parser stops when @test@ succeeds. The output of
862-- @test@ is discarded and the output of @collect@ is accumulated by the
863-- supplied fold. The parser fails if @collect@ fails.
864--
865-- /Internal/
866--
867{-# INLINE manyTill #-}
868manyTill :: MonadCatch m
869 => Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
870manyTill f p1 p2 =
871 D.toParserK $ D.manyTill f (D.fromParserK p1) (D.fromParserK p2)