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