on master help sign in
Remove the rewrite rule based Parser wrapper layer

Now we have explicit "Parser" and "ParserK" types for direct style and CPS parsers, respectively. The programmer can use either type depending on the use case.

commit36bbd3bc1c524767866ca79add5d679cf536ecfb authorHarendra Kumar <harendra@composewell.com> dateSat 4 Feb 2023, 07:54 (4 years ago) parent8629a0e
22 files changed+2614−1750
benchmark/Streamly/Benchmark/Data/Parser.hs+16−60 benchmark/Streamly/Benchmark/Data/Parser/ParserK.hs+48−7 core/src/Streamly/Data/Parser.hs+31 core/src/Streamly/Data/Parser/ParserK.hs+54 core/src/Streamly/Internal/Data/Fold/Chunked.hs+1−1 core/src/Streamly/Internal/Data/Parser.hs+4−1534 core/src/Streamly/Internal/Data/Parser/Chunked/Type.hs+2 core/src/Streamly/Internal/Data/Parser/ParserD.hs+780−104 core/src/Streamly/Internal/Data/Parser/ParserD/Type.hs+103−18 core/src/Streamly/Internal/Data/Parser/ParserDK.hs+1544 core/src/Streamly/Internal/Data/Parser/ParserK/Type.hs+4−1 core/src/Streamly/Internal/Data/Producer/Source.hs+2−2 core/src/Streamly/Internal/Data/Stream/Chunked.hs+2−2 core/src/Streamly/Internal/Data/Stream/StreamD/Eliminate.hs+2−2 core/src/Streamly/Internal/Data/Stream/StreamD/Nesting.hs+2−2 core/src/Streamly/Internal/Data/Stream/StreamK.hs+1−1 core/src/Streamly/Internal/Serialize/FromBytes.hs+7−7 core/src/Streamly/Internal/Unicode/Stream.hs+1−1 core/streamly-core.cabal+2 src/Streamly/Internal/Data/Stream/IsStream/Eliminate.hs+2−2 src/Streamly/Internal/Data/Stream/IsStream/Reduce.hs+3−4 test/Streamly/Test/Data/Parser.hs+3−2
benchmark/Streamly/Benchmark/Data/Parser.hs+16−60
@@ -18,7 +18,6 @@ module Main
1818 ) where
1919
2020import Control.DeepSeq (NFData(..))
21−import Data.Foldable (asum)
2221import Data.Functor (($>))
2322import Data.Monoid (Sum(..))
2423import GHC.Magic (inline)
@@ -30,8 +29,6 @@ import Streamly.Internal.Data.Stream.StreamD (Stream)
3029import Prelude hiding
3130 (any, all, take, sequence, sequence_, sequenceA, takeWhile, dropWhile)
3231
33−import qualified Data.Traversable as TR
34−import qualified Data.Foldable as F
3532import qualified Control.Applicative as AP
3633import qualified Streamly.FileSystem.Handle as Handle
3734import qualified Streamly.Internal.Data.Array as Array
@@ -113,18 +110,6 @@ benchIOSink value name f =
113110-- Parsers
114111-------------------------------------------------------------------------------
115112
116−{-# INLINE one #-}
117−one :: Monad m => Int -> Stream m Int -> m (Either ParseError (Maybe Int))
118−one value = Stream.parse p
119−
120− where
121−
122− p = do
123− m <- PR.fromFold Fold.one
124− case m of
125− Just i -> if i >= value then pure m else p
126− Nothing -> pure Nothing
127−
128113{-# INLINE takeBetween #-}
129114takeBetween :: Monad m => Int -> Stream m a -> m (Either ParseError ())
130115takeBetween value = Stream.parse (PR.takeBetween 0 value Fold.drain)
@@ -187,14 +172,20 @@ wordBy :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
187172wordBy value = Stream.parse (PR.wordBy (>= value) Fold.drain)
188173
189174{-# INLINE sepByWords #-}
190−sepByWords :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
191−sepByWords _ = Stream.parse (wrds even Fold.drain)
175+sepByWords :: Monad m => Stream m Int -> m (Either ParseError ())
176+sepByWords = Stream.parse (wrds even Fold.drain)
192177 where
193178 wrds p = PR.sepBy (PR.takeWhile (not . p) Fold.drain) (PR.dropWhile p)
194179
180+-- Returning a list to compare with the sepBy1 in ParserK
181+{-# INLINE sepBy1 #-}
182+sepBy1 :: Monad m => Stream m Int -> m (Either ParseError [Int])
183+sepBy1 xs = do
184+ Stream.parse (PR.sepBy1 (PR.satisfy odd) (PR.satisfy even) Fold.toList) xs
185+
195186{-# INLINE sepByWords1 #-}
196−sepByWords1 :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
197−sepByWords1 _ = Stream.parse (wrds even Fold.drain)
187+sepByWords1 :: Monad m => Stream m Int -> m (Either ParseError ())
188+sepByWords1 = Stream.parse (wrds even Fold.drain)
198189 where
199190 wrds p = PR.sepBy1 (PR.takeWhile (not . p) Fold.drain) (PR.dropWhile p)
200191
@@ -368,34 +359,6 @@ lookAhead :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
368359lookAhead value =
369360 Stream.parse (PR.lookAhead (PR.takeWhile (<= value) Fold.drain) $> ())
370361
371−{-# INLINE sequenceA #-}
372−sequenceA :: Monad m => Int -> Stream m Int -> m Int
373−sequenceA value xs = do
374− x <- Stream.parse (TR.sequenceA (replicate value (PR.satisfy (> 0)))) xs
375− return $ length x
376−
377−{-# INLINE sequenceA_ #-}
378−sequenceA_ :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
379−sequenceA_ value =
380− Stream.parse (F.sequenceA_ $ replicate value (PR.satisfy (> 0)))
381−
382−{-# INLINE sequence #-}
383−sequence :: Monad m => Int -> Stream m Int -> m Int
384−sequence value xs = do
385− x <- Stream.parse (TR.sequence (replicate value (PR.satisfy (> 0)))) xs
386− return $ length x
387−
388−{-# INLINE sequence_ #-}
389−sequence_ :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
390−sequence_ value =
391− Stream.parse (F.sequence_ $ replicate value (PR.satisfy (> 0)))
392−
393−{-# INLINE choiceAsum #-}
394−choiceAsum :: Monad m => Int -> Stream m Int -> m (Either ParseError Int)
395−choiceAsum value =
396− Stream.parse (asum (replicate value (PR.satisfy (< 0)))
397− AP.<|> PR.satisfy (> 0))
398−
399362{-
400363{-# INLINE choice #-}
401364choice :: Monad m => Int -> Stream m Int -> m (Either ParseError Int)
@@ -429,7 +392,8 @@ parseIterate n =
429392
430393{-# INLINE concatSequence #-}
431394concatSequence :: Monad m => Stream m Int -> m (Either ParseError ())
432−concatSequence = Stream.parse $ PR.concatSequence Fold.drain $ Stream.repeat PR.one
395+concatSequence =
396+ Stream.parse $ PR.sequence (Stream.repeat PR.one) Fold.drain
433397
434398{-# INLINE parseManyGroupBy #-}
435399parseManyGroupBy :: Monad m => (Int -> Int -> Bool) -> Stream m Int -> m ()
@@ -449,8 +413,7 @@ instance NFData ParseError where
449413
450414o_1_space_serial :: Int -> [Benchmark]
451415o_1_space_serial value =
452− [ benchIOSink value "one (fold)" $ one value
453− , benchIOSink value "takeBetween" $ takeBetween value
416+ [ benchIOSink value "takeBetween" $ takeBetween value
454417 , benchIOSink value "takeEQ" $ takeEQ value
455418 , benchIOSink value "takeWhile" $ takeWhile value
456419 , benchIOSink value "takeWhileP" $ takeWhileP value
@@ -462,8 +425,9 @@ o_1_space_serial value =
462425 , benchIOSink value "groupBy" $ groupBy
463426 , benchIOSink value "groupByRolling" $ groupByRolling
464427 , benchIOSink value "wordBy" $ wordBy value
465− , benchIOSink value "sepBy (words)" $ sepByWords value
466− , benchIOSink value "sepBy1 (words)" $ sepByWords1 value
428+ , benchIOSink value "sepBy (words)" sepByWords
429+ , benchIOSink value "sepBy1" sepBy1
430+ , benchIOSink value "sepBy1 (words)" sepByWords1
467431 , benchIOSink value "deintercalate" $ deintercalate value
468432 , benchIOSink value "splitAp" $ splitAp value
469433 , benchIOSink value "splitApBefore" $ splitApBefore value
@@ -513,17 +477,9 @@ o_n_heap_serial value =
513477 -- lookahead benchmark holds the entire input till end
514478 benchIOSink value "lookAhead" $ lookAhead value
515479
516− -- accumulates the results in a list
517− , benchIOSink value "sequence" $ sequence value
518− , benchIOSink value "sequenceA" $ sequenceA value
519−
520− -- XXX why should this take O(n) heap, it discards the results?
521− , benchIOSink value "sequence_" $ sequence_ value
522− , benchIOSink value "sequenceA_" $ sequenceA_ value
523480 -- non-linear time complexity (parserD)
524481 , benchIOSink value "split_" $ split_ value
525482 -- XXX why O(n) heap?
526− , benchIOSink value "choice (asum)" $ choiceAsum value
527483 -- , benchIOSink value "choice" $ choice value
528484
529485 -- These show non-linear time complexity.
benchmark/Streamly/Benchmark/Data/Parser/ParserK.hs+48−7
@@ -19,11 +19,13 @@ import Data.Foldable (asum)
1919import Streamly.Internal.Data.Parser (ParseError(..))
2020import Streamly.Internal.Data.Stream.StreamD (Stream)
2121import System.Random (randomRIO)
22−import Prelude hiding (any, all, take, sequence, sequenceA, takeWhile)
22+import Prelude hiding
23+ (any, all, take, sequence, sequence_, sequenceA, takeWhile)
2324
2425import qualified Control.Applicative as AP
2526import qualified Data.Foldable as F
2627import qualified Data.Traversable as TR
28+import qualified Streamly.Data.Parser.ParserK as ParserK
2729import qualified Streamly.Internal.Data.Fold as FL
2830import qualified Streamly.Internal.Data.Parser.ParserK.Type as PR
2931import qualified Streamly.Internal.Data.Parser.ParserD as PRD
@@ -59,11 +61,19 @@ benchIOSink value name f =
5961-- Parsers
6062-------------------------------------------------------------------------------
6163
62−#ifdef FROM_PARSERK
63−#define PARSE_OP (Stream.parseD . PRD.fromParserK)
64−#else
65−#define PARSE_OP Stream.parse
66−#endif
64+#define PARSE_OP (Stream.parse . PRD.fromParserK)
65+
66+{-# INLINE one #-}
67+one :: Monad m => Int -> Stream m Int -> m (Either ParseError (Maybe Int))
68+one value = Stream.parse (ParserK.toParser p)
69+
70+ where
71+
72+ p = do
73+ m <- ParserK.fromFold FL.one
74+ case m of
75+ Just i -> if i >= value then pure m else p
76+ Nothing -> pure Nothing
6777
6878{-# INLINE satisfy #-}
6979satisfy :: Monad m => (a -> Bool) -> PR.Parser a m a
@@ -106,6 +116,13 @@ sequence value xs = do
106116 x <- PARSE_OP (TR.sequence list) xs
107117 return $ Prelude.length x
108118
119+{-# INLINE sequence_ #-}
120+sequence_ :: Monad m => Int -> Stream m Int -> m (Either ParseError ())
121+sequence_ value =
122+ let parser = satisfy (> 0)
123+ list = Prelude.replicate value parser
124+ in PARSE_OP (F.sequence_ list)
125+
109126{-# INLINE manyAlt #-}
110127manyAlt :: Monad m => Stream m Int -> m Int
111128manyAlt xs = do
@@ -141,17 +158,40 @@ o_1_space_serial value =
141158 , benchIOSink value "splitApp" $ splitApp value
142159 ]
143160
161+{-# INLINE sepBy1 #-}
162+sepBy1 :: Monad m => Stream m Int -> m Int
163+sepBy1 xs = do
164+ x <- PARSE_OP (parser (satisfy odd) (satisfy even)) xs
165+ return $ Prelude.length x
166+
167+ where
168+
169+ parser p sep = do
170+ x <- p
171+ fmap (x :) $ AP.many (sep >> p)
172+
144173-- O(n) heap beacuse of accumulation of the list in strict IO monad?
145174o_n_heap_serial :: Int -> [Benchmark]
146175o_n_heap_serial value =
147− [ benchIOSink value "sequenceA" $ sequenceA value
176+ [
177+ -- accumulates the results in a list
178+ -- XXX why should this take O(n) heap, it discards the results?
179+ benchIOSink value "sequence_" $ sequence_ value
148180 , benchIOSink value "sequenceA_" $ sequenceA_ value
149181 , benchIOSink value "sequence" $ sequence value
182+ , benchIOSink value "sequenceA" $ sequenceA value
150183 , benchIOSink value "manyAlt" manyAlt
184+ , benchIOSink value "sepBy1" sepBy1
151185 , benchIOSink value "someAlt" someAlt
152186 , benchIOSink value "choice" $ choice value
153187 ]
154188
189+-- O(n) heap beacuse of accumulation of the list in strict IO monad?
190+o_1_space_recursive :: Int -> [Benchmark]
191+o_1_space_recursive value =
192+ [ benchIOSink value "one (recursive)" $ one value
193+ ]
194+
155195-------------------------------------------------------------------------------
156196-- Driver
157197-------------------------------------------------------------------------------
@@ -163,5 +203,6 @@ main = runWithCLIOpts defaultStreamSize allBenchmarks
163203
164204 allBenchmarks value =
165205 [ bgroup (o_1_space_prefix moduleName) (o_1_space_serial value)
206+ , bgroup (o_1_space_prefix moduleName) (o_1_space_recursive value)
166207 , bgroup (o_n_heap_prefix moduleName) (o_n_heap_serial value)
167208 ]
core/src/Streamly/Data/Parser.hs+31
@@ -17,6 +17,37 @@
1717-- (which should be the case almost always) you can just use 'fromEffect' to
1818-- execute the lower layer monad effects.
1919--
20+-- == Performance Notes
21+--
22+-- This module is designed for fusion, inline the operations in this module for
23+-- fusion to occur, avoid using these operations in recursive calls, avoid
24+-- operations like 'sequence', 'asum' on these parsers. If you need these then
25+-- use the 'ParserK' module instead.
26+--
27+-- The 'Parser' type represents a stream consumer by composing state as data
28+-- which enables stream fusion. Stream fusion generates a tight loop without
29+-- any constructor allocations between the stages, providing C like performance
30+-- for the loop. Stream fusion works when multiple functions are combined in a
31+-- pipeline statically. Therefore, the operations in this module must be
32+-- inlined and must not be used recursively to allow for stream fusion.
33+--
34+-- Using the 'Parser' type parsing operations like 'one', 'splitWith' etc.
35+-- degrade quadratically (O(n^2)) when combined many times. If you need to
36+-- combine these operations, say more than 50 times in a single loop, then you
37+-- should use the continuation style parser type 'ParserK' instead. Also, if
38+-- you need to use these operations in a recursive loop you should use
39+-- 'ParserK' instead.
40+--
41+-- The 'ParserK' type represents a stream consumer by composing function calls,
42+-- therefore, a function call overhead is incurred at each composition. It is
43+-- quite fast in general but may be a few times slower than a fused parser.
44+-- However, it allows for scalable dynamic composition especially parsers can
45+-- be used in recursive calls. Using the 'ParserK' type operations like
46+-- 'splitWith' provide linear (O(n)) performance with respect to the number of
47+-- compositions..
48+--
49+-- 'Parser' and 'ParserK' types can be interconverted.
50+--
2051module Streamly.Data.Parser
2152 (
2253 -- * Parser Type
core/src/Streamly/Data/Parser/ParserK.hsnew file+54
@@ -0,0 +1,54 @@
1+-- |
2+-- Module : Streamly.Data.Parser.ParserK
3+-- Copyright : (c) 2023 Composewell Technologies
4+-- License : BSD-3-Clause
5+-- Maintainer : streamly@composewell.com
6+-- Stability : pre-release
7+-- Portability : GHC
8+--
9+-- Parsers using Continuation Passing Style (CPS). See notes in
10+-- "Streamly.Data.Parser" module to know when to use this module.
11+--
12+-- To run a 'ParserK' convert it to a 'Parser' and then run it.
13+--
14+module Streamly.Data.Parser.ParserK
15+ (
16+ -- * Parser Type
17+ ParserK
18+ , Parser
19+
20+ -- * Parsers
21+ -- ** Conversions
22+ , fromFold
23+ , fromParser
24+ , toParser
25+
26+ -- ** Without Input
27+ , fromPure
28+ , fromEffect
29+ , die
30+ )
31+
32+where
33+
34+import Streamly.Internal.Data.Fold (Fold)
35+import Streamly.Internal.Data.Parser.ParserK.Type
36+import qualified Streamly.Internal.Data.Parser.ParserD as ParserD
37+
38+-- | Convert a 'Fold' to a 'ParserK'.
39+--
40+{-# INLINE fromFold #-}
41+fromFold :: Monad m => Fold m a b -> ParserK a m b
42+fromFold = ParserD.toParserK . ParserD.fromFold
43+
44+-- | Convert a 'Parser' to a 'ParserK'.
45+--
46+{-# INLINE fromParser #-}
47+fromParser :: Monad m => ParserD.Parser a m b -> ParserK a m b
48+fromParser = ParserD.toParserK
49+
50+-- | Convert a 'ParserK' to a 'Parser'.
51+--
52+{-# INLINE toParser #-}
53+toParser :: Monad m => ParserK a m b -> ParserD.Parser a m b
54+toParser = ParserD.fromParserK
core/src/Streamly/Internal/Data/Fold/Chunked.hs+1−1
@@ -182,7 +182,7 @@ fromParserD (ParserD.Parser step1 initial1 extract1) =
182182{-# INLINE fromParser #-}
183183fromParser :: forall m a b. (MonadIO m, Unbox a) =>
184184 Parser.Parser a m b -> ChunkFold m a b
185−fromParser = fromParserD . ParserD.fromParserK
185+fromParser = fromParserD
186186
187187-- | Adapt an array stream fold.
188188--
core/src/Streamly/Internal/Data/Parser.hs+4−1534
@@ -1,1544 +1,14 @@
1−{-# OPTIONS_GHC -Wno-orphans #-}
2−
31-- |
42-- Module : Streamly.Internal.Data.Parser
5−-- Copyright : (c) 2020 Composewell Technologies
3+-- Copyright : (c) 2019 Composewell Technologies
64-- License : BSD-3-Clause
75-- Maintainer : streamly@composewell.com
8−-- Stability : pre-release
6+-- Stability : experimental
97-- Portability : GHC
108--
11−-- Fast backtracking parsers with stream fusion and native streaming
12−-- capability.
13−--
14−-- 'Applicative' and 'Control.Applicative.Alternative' type class based
15−-- combinators from the
16−-- <http://hackage.haskell.org/package/parser-combinators parser-combinators>
17−-- package can also be used with the 'Parser' type. However, there are two
18−-- important differences between @parser-combinators@ and the equivalent ones
19−-- provided in this module in terms of performance:
20−--
21−-- 1) @parser-combinators@ use plain Haskell lists to collect the results, in a
22−-- strict Monad like IO, the results are necessarily buffered before they can
23−-- be consumed. This may not perform optimally in streaming applications
24−-- processing large amounts of data. Equivalent combinators in this module can
25−-- consume the results of parsing using a 'Fold', thus providing a scalability
26−-- and a composable consumer.
27−--
28−-- 2) Several combinators in this module can be many times faster because of
29−-- stream fusion. For example, 'Streamly.Internal.Data.Parser.many' combinator
30−-- in this module is much faster than the 'Control.Applicative.many' combinator
31−-- of 'Control.Applicative.Alternative' type class.
32−--
33−-- = Errors
34−--
35−-- Failing parsers in this module throw the 'D.ParseError' exception.
36−--
37−-- = Naming
38−--
39−-- As far as possible, try that the names of the combinators in this module are
40−-- consistent with:
41−--
42−-- * <https://hackage.haskell.org/package/base/docs/Text-ParserCombinators-ReadP.html base/Text.ParserCombinators.ReadP>
43−-- * <http://hackage.haskell.org/package/parser-combinators parser-combinators>
44−-- * <http://hackage.haskell.org/package/megaparsec megaparsec>
45−-- * <http://hackage.haskell.org/package/attoparsec attoparsec>
46−-- * <http://hackage.haskell.org/package/parsec parsec>
47−
489module Streamly.Internal.Data.Parser
49− (
50− K.Parser (..)
51− , D.ParseError (..)
52− , D.Step (..)
53−
54− -- * Downgrade to Fold
55− , toFold
56−
57− -- First order parsers
58− -- * Accumulators
59− , fromFold
60− , fromFoldMaybe
61− , fromPure
62− , fromEffect
63− , die
64− , dieM
65−
66− -- * Map on input
67− , lmap
68− , lmapM
69− , filter
70−
71− -- * Map on output
72− , rmapM
73−
74− -- * Element parsers
75− , peek
76−
77− -- All of these can be expressed in terms of either
78− , one
79− , oneEq
80− , oneNotEq
81− , oneOf
82− , noneOf
83− , eof
84− , satisfy
85− , maybe
86− , either
87−
88− -- * Sequence parsers (tokenizers)
89− --
90− -- | Parsers chained in series, if one parser terminates the composition
91− -- terminates.
92−
93− , lookAhead
94−
95− -- ** By length
96− -- | Grab a sequence of input elements without inspecting them
97− , takeBetween
98− -- , take -- takeBetween 0 n
99− , takeEQ -- takeBetween n n
100− , takeGE -- takeBetween n maxBound
101− , takeP
102−
103− -- Grab a sequence of input elements by inspecting them
104− -- ** Exact match
105− , listEq
106− , listEqBy
107− , streamEqBy
108− , subsequenceBy
109−
110− -- ** By predicate
111− , takeWhileP
112− , takeWhile
113− -- $takeWhile
114− , takeWhile1
115− , dropWhile
116−
117− -- ** Separators
118− , takeEndBy
119− , takeEndBy_
120− , takeEndByEsc
121− -- , takeEndByEsc_
122− , takeStartBy
123− , takeStartBy_
124− , takeEitherSepBy
125− , wordBy
126− -- , wordByEsc
127−
128− -- ** By comparing
129− , groupBy
130− , groupByRolling
131− , groupByRollingEither
132−
133− -- ** Framing
134− -- , takeFramedBy
135− , takeFramedBy_
136− , takeFramedByEsc_
137− , takeFramedByGeneric
138− , wordFramedBy
139− , wordQuotedBy
140−
141− -- | Unimplemented
142− --
143− -- @
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
147− -- @
148−
149− -- Second order parsers (parsers using parsers)
150− -- * Binary Combinators
151−
152− -- ** Sequential Applicative
153− , splitWith
154− , split_
155−
156−{-
157− -- ** Parallel Applicatives
158− , teeWith
159− , teeWithFst
160− , teeWithMin
161− -- , teeTill -- like manyTill but parallel
162−-}
163−
164− -- ** Sequential Interleaving
165− -- Use two folds, run a primary parser, its rejected values go to the
166− -- secondary parser.
167− , deintercalate
168− -- , deintercalatePrefix
169− -- , deintercalateSuffix
170−
171− -- *** Special cases
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.
176− --
177− -- We can instead implement these as special cases of deintercalate.
178− --
179− -- @
180− -- , endBy
181− -- , sepEndBy
182− -- , beginBy
183− -- , sepBeginBy
184− -- , sepAroundBy
185− -- @
186− , sepBy1
187− , sepBy
188−
189− -- ** Sequential Alternative
190− , alt
191−
192−{-
193− -- ** Parallel Alternatives
194− , shortest
195− , longest
196− -- , fastest
197−-}
198−
199− -- * N-ary Combinators
200− -- ** Sequential Collection
201− , concatSequence
202− , concatMap
203−
204− -- ** Sequential Repetition
205− , count
206− , countBetween
207−
208− , manyP
209− , many
210− , some
211− , manyTillP
212− , manyTill
213− , manyThen
214−
215− -- * Distribution
216− --
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.
220−
221− -- ** Distribute to collection
222− -- ** Distribute to repetition
223−
224− -- ** Interleaved collection
225− -- |
226− --
227− -- 1. Round robin
228− -- 2. Priority based
229− , roundRobin
230−
231− -- ** Collection of Alternatives
232− -- | Unimplemented
233− --
234− -- @
235− -- , shortestN
236− -- , longestN
237− -- , fastestN -- first N successful in time
238− -- , choiceN -- first N successful in position
239− -- @
240− -- , choice -- first successful in position
241−
242− -- ** Repeated Alternatives
243− , retryMaxTotal
244− , retryMaxSuccessive
245− , retry
246−
247− -- * Deprecated
248− , next
10+ ( module Streamly.Internal.Data.Parser.ParserD
24911 )
25012where
25113
252−import Streamly.Internal.Data.Fold.Type (Fold(..))
253−import Streamly.Internal.Data.Parser.ParserK.Type (Parser)
254−
255−import qualified Data.Foldable as Foldable
256−import qualified Streamly.Internal.Data.Fold.Type as FL
257−import qualified Streamly.Internal.Data.Parser.ParserD as D
258−import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
259−
260−#ifdef USE_STREAMK
261−import Streamly.Internal.Data.StreamK (Stream)
262−import qualified Streamly.Internal.Data.StreamK as Stream
263−#else
264−import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
265−import qualified Streamly.Internal.Data.Stream.StreamD.Type as Stream
266−#endif
267−
268−import Prelude hiding
269− ( any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either
270− , filter )
271−
272−--
273−-- $setup
274−-- >>> :m
275−-- >>> import Prelude hiding (any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either, filter)
276−-- >>> import Control.Applicative ((<|>))
277−-- >>> import Data.Char (isSpace)
278−-- >>> import qualified Data.Maybe as Maybe
279−-- >>> import qualified Data.Foldable as Foldable
280−-- >>> import qualified Streamly.Data.Stream as Stream
281−-- >>> import qualified Streamly.Internal.Data.Stream as Stream (parse, parseMany)
282−-- >>> import qualified Streamly.Internal.Data.Fold as Fold
283−-- >>> import qualified Streamly.Internal.Data.Parser as Parser
284−
285−-------------------------------------------------------------------------------
286−-- Downgrade a parser to a Fold
287−-------------------------------------------------------------------------------
288−--
289−-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
290−-- parser fails or tries to backtrack.
291−--
292−-- This can be useful in combinators that accept a Fold and we know that a
293−-- Parser cannot fail or failure exception is acceptable as there is no way to
294−-- recover.
295−--
296−-- /Pre-release/
297−--
298−{-# INLINE toFold #-}
299−toFold :: Monad m => Parser a m b -> Fold m a b
300−toFold p = D.toFold $ D.fromParserK p
301−
302−-------------------------------------------------------------------------------
303−-- Upgrade folds to parses
304−-------------------------------------------------------------------------------
305−--
306−-- | Make a 'Parser' from a 'Fold'.
307−--
308−{-# INLINE fromFold #-}
309−fromFold :: Monad m => Fold m a b -> Parser a m b
310−fromFold = D.toParserK . D.fromFold
311−
312−-- | Convert a Maybe returning fold to an error returning parser. The first
313−-- argument is the error message that the parser would return when the fold
314−-- returns Nothing.
315−--
316−-- /Pre-release/
317−--
318−{-# INLINE fromFoldMaybe #-}
319−fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser a m b
320−fromFoldMaybe err = D.toParserK . D.fromFoldMaybe err
321−
322−-------------------------------------------------------------------------------
323−-- Terminating but not failing folds
324−-------------------------------------------------------------------------------
325−--
326−-- This is the dual of stream "fromPure".
327−--
328−-- | A parser that always yields a pure value without consuming any input.
329−--
330−{-# INLINE [3] fromPure #-}
331−fromPure :: Monad m => b -> Parser a m b
332−fromPure = D.toParserK . D.fromPure
333−{-# RULES "fromPure fallback to CPS" [2]
334− forall a. D.toParserK (D.fromPure a) = K.fromPure a #-}
335−
336−-- This is the dual of stream "fromEffect".
337−--
338−-- | A parser that always yields the result of an effectful action without
339−-- consuming any input.
340−--
341−{-# INLINE fromEffect #-}
342−fromEffect :: Monad m => m b -> Parser a m b
343−fromEffect = K.fromEffect -- D.toParserK . D.fromEffect
344−
345−-- This is the dual of "nil".
346−--
347−-- | A parser that always fails with an error message without consuming
348−-- any input.
349−--
350−{-# INLINE [3] die #-}
351−die :: Monad m => String -> Parser a m b
352−die = D.toParserK . D.die
353−{-# RULES "die fallback to CPS" [2]
354− forall a. D.toParserK (D.die a) = K.die a #-}
355−
356−-- This is the dual of "nilM".
357−--
358−-- | A parser that always fails with an effectful error message and without
359−-- consuming any input.
360−--
361−-- /Pre-release/
362−--
363−{-# INLINE dieM #-}
364−dieM :: Monad m => m String -> Parser a m b
365−dieM = D.toParserK . D.dieM
366−
367−-------------------------------------------------------------------------------
368−-- Map on input
369−-------------------------------------------------------------------------------
370−
371−-- | @lmap f parser@ maps the function @f@ on the input of the parser.
372−--
373−-- >>> Stream.parse (Parser.lmap (\x -> x * x) (Parser.fromFold Fold.sum)) (Stream.enumerateFromTo 1 100)
374−-- Right 338350
375−--
376−-- > lmap = Parser.lmapM return
377−--
378−{-# INLINE lmap #-}
379−lmap :: Monad m => (a -> b) -> Parser b m r -> Parser a m r
380−lmap f p = D.toParserK $ D.lmap f $ D.fromParserK p
381−
382−-- | @lmapM f parser@ maps the monadic function @f@ on the input of the parser.
383−--
384−{-# INLINE lmapM #-}
385−lmapM :: Monad m => (a -> m b) -> Parser b m r -> Parser a m r
386−lmapM f p = D.toParserK $ D.lmapM f $ D.fromParserK p
387−
388−-- | @rmapM f parser@ maps the monadic function @f@ on the output of the parser.
389−--
390−-- >>> rmap = fmap
391−{-# INLINE rmapM #-}
392−rmapM :: Monad m => (b -> m c) -> Parser a m b -> Parser a m c
393−rmapM f p = D.toParserK $ D.rmapM f $ D.fromParserK p
394−
395−-- | Include only those elements that pass a predicate.
396−--
397−-- >>> Stream.parse (Parser.filter (> 5) (Parser.fromFold Fold.sum)) $ Stream.fromList [1..10]
398−-- Right 40
399−--
400−{-# INLINE filter #-}
401−filter :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
402−filter f p = D.toParserK $ D.filter f $ D.fromParserK p
403−
404−-------------------------------------------------------------------------------
405−-- Failing Parsers
406−-------------------------------------------------------------------------------
407−
408−-- | Peek the head element of a stream, without consuming it. Fails if it
409−-- encounters end of input.
410−--
411−-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
412−-- Right (1,1)
413−--
414−-- @
415−-- peek = lookAhead (satisfy True)
416−-- @
417−--
418−{-# INLINE peek #-}
419−peek :: Monad m => Parser a m a
420−peek = D.toParserK D.peek
421−
422−-- | Succeeds if we are at the end of input, fails otherwise.
423−--
424−-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
425−-- Right (1,())
426−--
427−{-# INLINE eof #-}
428−eof :: Monad m => Parser a m ()
429−eof = D.toParserK D.eof
430−
431−-- | Returns the next element if it passes the predicate, fails otherwise.
432−--
433−-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
434−-- Right 1
435−--
436−-- >>> toMaybe f x = if f x then Just x else Nothing
437−-- >>> satisfy f = Parser.maybe (toMaybe f)
438−--
439−{-# INLINE satisfy #-}
440−satisfy :: Monad m => (a -> Bool) -> Parser a m a
441−satisfy = D.toParserK . D.satisfy
442−
443−-- | Consume one element from the head of the stream. Fails if it encounters
444−-- end of input.
445−--
446−-- >>> one = Parser.satisfy $ const True
447−--
448−{-# INLINE one #-}
449−one :: Monad m => Parser a m a
450−one = satisfy $ const True
451−
452−-- Alternate names: "only", "onlyThis".
453−
454−-- | Match a specific element.
455−--
456−-- >>> oneEq x = Parser.satisfy (== x)
457−--
458−{-# INLINE oneEq #-}
459−oneEq :: (Monad m, Eq a) => a -> Parser a m a
460−oneEq x = satisfy (== x)
461−
462−-- Alternate names: "exclude", "notThis".
463−
464−-- | Match anything other than the supplied element.
465−--
466−-- >>> oneNotEq x = Parser.satisfy (/= x)
467−--
468−{-# INLINE oneNotEq #-}
469−oneNotEq :: (Monad m, Eq a) => a -> Parser a m a
470−oneNotEq x = satisfy (/= x)
471−
472−-- | Match any one of the elements in the supplied list.
473−--
474−-- >>> oneOf xs = Parser.satisfy (`Foldable.elem` xs)
475−--
476−-- When performance matters a pattern matching predicate could be more
477−-- efficient than a 'Foldable' datatype:
478−--
479−-- @
480−-- let p x =
481−-- case x of
482−-- 'a' -> True
483−-- 'e' -> True
484−-- _ -> False
485−-- in satisfy p
486−-- @
487−--
488−-- GHC may use a binary search instead of linear search in the list.
489−-- Alternatively, you can also use an array instead of list for storage and
490−-- search.
491−--
492−{-# INLINE oneOf #-}
493−oneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
494−oneOf xs = satisfy (`Foldable.elem` xs)
495−
496−-- | See performance notes in 'oneOf'.
497−--
498−-- >>> noneOf xs = Parser.satisfy (`Foldable.notElem` xs)
499−--
500−{-# INLINE noneOf #-}
501−noneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
502−noneOf xs = satisfy (`Foldable.notElem` xs)
503−
504−-- | Return the next element of the input. Returns 'Nothing'
505−-- on end of input. Also known as 'head'.
506−--
507−-- /Pre-release/
508−--
509−{-# DEPRECATED next "Please use \"fromFold Fold.one\" instead" #-}
510−{-# INLINE next #-}
511−next :: Monad m => Parser a m (Maybe a)
512−next = D.toParserK D.next
513−
514−-- | Map a 'Maybe' returning function on the next element in the stream. The
515−-- parser fails if the function returns 'Nothing' otherwise returns the 'Just'
516−-- value.
517−--
518−-- >>> toEither = Maybe.maybe (Left "maybe: predicate failed") Right
519−-- >>> maybe f = Parser.either (toEither . f)
520−--
521−-- >>> maybe f = Parser.fromFoldMaybe "maybe: predicate failed" (Fold.maybe f)
522−--
523−-- /Pre-release/
524−--
525−{-# INLINE maybe #-}
526−maybe :: Monad m => (a -> Maybe b) -> Parser a m b
527−maybe = D.toParserK . D.maybe
528−
529−-- | Map an 'Either' returning function on the next element in the stream. If
530−-- the function returns 'Left err', the parser fails with the error message
531−-- @err@ otherwise returns the 'Right' value.
532−--
533−-- /Pre-release/
534−--
535−{-# INLINE either #-}
536−either :: Monad m => (a -> Either String b) -> Parser a m b
537−either = D.toParserK . D.either
538−
539−-------------------------------------------------------------------------------
540−-- Taking elements
541−-------------------------------------------------------------------------------
542−
543−-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
544−-- elements and folds them using the supplied fold.
545−--
546−-- Stops after @n@ elements.
547−-- Fails if the stream ends before @m@ elements could be taken.
548−--
549−-- Examples: -
550−--
551−-- @
552−-- >>> :{
553−-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
554−-- where prsr = Parser.takeBetween low high Fold.toList
555−-- :}
556−--
557−-- @
558−--
559−-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
560−-- Right [1,2,3,4]
561−--
562−-- >>> takeBetween' 2 4 [1, 2]
563−-- Right [1,2]
564−--
565−-- >>> takeBetween' 2 4 [1]
566−-- Left (ParseError "takeBetween: Expecting alteast 2 elements, got 1")
567−--
568−-- >>> takeBetween' 0 0 [1, 2]
569−-- Right []
570−--
571−-- >>> takeBetween' 0 1 []
572−-- Right []
573−--
574−-- @takeBetween@ is the most general take operation, other take operations can
575−-- be defined in terms of takeBetween. For example:
576−--
577−-- >>> take n = Parser.takeBetween 0 n
578−-- >>> takeEQ n = Parser.takeBetween n n
579−-- >>> takeGE n = Parser.takeBetween n maxBound
580−--
581−-- /Pre-release/
582−--
583−{-# INLINE takeBetween #-}
584−takeBetween :: Monad m =>
585− Int -> Int -> Fold m a b -> Parser a m b
586−takeBetween m n = D.toParserK . D.takeBetween m n
587−
588−-- | Stops after taking exactly @n@ input elements.
589−--
590−-- * Stops - after consuming @n@ elements.
591−-- * Fails - if the stream or the collecting fold ends before it can collect
592−-- exactly @n@ elements.
593−--
594−-- >>> Stream.parse (Parser.takeEQ 4 Fold.toList) $ Stream.fromList [1,0,1]
595−-- Left (ParseError "takeEQ: Expecting exactly 4 elements, input terminated on 3")
596−--
597−{-# INLINE takeEQ #-}
598−takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
599−takeEQ n = D.toParserK . D.takeEQ n
600−
601−-- | Take at least @n@ input elements, but can collect more.
602−--
603−-- * Stops - when the collecting fold stops.
604−-- * Fails - if the stream or the collecting fold ends before producing @n@
605−-- elements.
606−--
607−-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1]
608−-- Left (ParseError "takeGE: Expecting at least 4 elements, input terminated on 3")
609−--
610−-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
611−-- Right [1,0,1,0,1]
612−--
613−-- /Pre-release/
614−--
615−{-# INLINE takeGE #-}
616−takeGE :: Monad m => Int -> Fold m a b -> Parser a m b
617−takeGE n = D.toParserK . D.takeGE n
618−
619−-------------------------------------------------------------------------------
620−-- Take until a condition
621−-------------------------------------------------------------------------------
622−
623−-- $takeWhile
624−-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
625−
626−-- XXX We should perhaps use only takeWhileP and rename it to takeWhile.
627−--
628−-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
629−-- input. The combinator stops when the condition fails or if the collecting
630−-- parser stops.
631−--
632−-- Other interesting parsers can be implemented in terms of this parser:
633−--
634−-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
635−-- >>> takeWhileBetween cond m n p = Parser.takeWhileP cond (Parser.takeBetween m n p)
636−--
637−-- Stops: when the condition fails or the collecting parser stops.
638−-- Fails: when the collecting parser fails.
639−--
640−-- /Pre-release/
641−--
642−{-# INLINE takeWhileP #-}
643−takeWhileP :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
644−takeWhileP cond p = D.toParserK $ D.takeWhileP cond (D.fromParserK p)
645−
646−-- | Collect stream elements until an element fails the predicate. The element
647−-- on which the predicate fails is returned back to the input stream.
648−--
649−-- * Stops - when the predicate fails or the collecting fold stops.
650−-- * Fails - never.
651−--
652−-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
653−-- Right [0,0]
654−--
655−-- >>> takeWhile cond f = Parser.takeWhileP cond (Parser.fromFold f)
656−--
657−-- We can implement a @breakOn@ using 'takeWhile':
658−--
659−-- @
660−-- breakOn p = takeWhile (not p)
661−-- @
662−--
663−{-# INLINE takeWhile #-}
664−takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
665−takeWhile cond = D.toParserK . D.takeWhile cond
666−-- takeWhile cond f = takeWhileP cond (fromFold f)
667−
668−-- | Like 'takeWhile' but takes at least one element otherwise fails.
669−--
670−-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
671−--
672−{-# INLINE takeWhile1 #-}
673−takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
674−takeWhile1 cond = D.toParserK . D.takeWhile1 cond
675−-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
676−
677−-- | Drain the input as long as the predicate succeeds, running the effects and
678−-- discarding the results.
679−--
680−-- This is also called @skipWhile@ in some parsing libraries.
681−--
682−-- >>> dropWhile p = Parser.takeWhile p Fold.drain
683−--
684−{-# INLINE dropWhile #-}
685−dropWhile :: Monad m => (a -> Bool) -> Parser a m ()
686−dropWhile p = takeWhile p FL.drain
687−
688−-------------------------------------------------------------------------------
689−-- Separators
690−-------------------------------------------------------------------------------
691−
692−-- XXX We can remove Maybe from esc
693−{-# INLINE takeFramedByGeneric #-}
694−takeFramedByGeneric :: Monad m =>
695− Maybe (a -> Bool)
696− -> Maybe (a -> Bool)
697− -> Maybe (a -> Bool)
698− -> Fold m a b
699− -> Parser a m b
700−takeFramedByGeneric esc begin end f =
701− D.toParserK $ D.takeFramedByGeneric esc begin end f
702−
703−-- | @takeEndBy cond parser@ parses a token that ends by a separator chosen by
704−-- the supplied predicate. The separator is also taken with the token.
705−--
706−-- This can be combined with other parsers to implement other interesting
707−-- parsers as follows:
708−--
709−-- >>> takeEndByLE cond n p = Parser.takeEndBy cond (Parser.fromFold $ Fold.take n p)
710−-- >>> takeEndByBetween cond m n p = Parser.takeEndBy cond (Parser.takeBetween m n p)
711−--
712−-- >>> takeEndBy = Parser.takeEndByEsc (const False)
713−--
714−-- See also "Streamly.Data.Fold.takeEndBy". Unlike the fold, the collecting
715−-- parser in the takeEndBy parser can decide whether to fail or not if the
716−-- stream does not end with separator.
717−--
718−-- /Pre-release/
719−--
720−{-# INLINE takeEndBy #-}
721−takeEndBy :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
722−takeEndBy cond = D.toParserK . D.takeEndBy cond . D.fromParserK
723−-- takeEndBy = takeEndByEsc (const False)
724−
725−-- | Like 'takeEndBy' but the separator is dropped.
726−--
727−-- See also "Streamly.Data.Fold.takeEndBy_".
728−--
729−-- /Pre-release/
730−--
731−{-# INLINE takeEndBy_ #-}
732−takeEndBy_ :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
733−takeEndBy_ cond = D.toParserK . D.takeEndBy_ cond . D.fromParserK
734−{-
735−takeEndBy_ isEnd p =
736− takeFramedByGeneric Nothing Nothing (Just isEnd) (toFold p)
737−-}
738−
739−-- | Take either the separator or the token. Separator is a Left value and
740−-- token is Right value.
741−--
742−-- /Unimplemented/
743−{-# INLINE takeEitherSepBy #-}
744−takeEitherSepBy :: -- Monad m =>
745− (a -> Bool) -> Fold m (Either a b) c -> Parser a m c
746−takeEitherSepBy _cond = undefined -- D.toParserK . D.takeEitherSepBy cond
747−
748−-- | Parse a token that starts with an element chosen by the predicate. The
749−-- parser fails if the input does not start with the selected element.
750−--
751−-- * Stops - when the predicate succeeds in non-leading position.
752−-- * Fails - when the predicate fails in the leading position.
753−--
754−-- >>> splitWithPrefix p f = Stream.parseMany (Parser.takeStartBy p f)
755−--
756−-- Examples: -
757−--
758−-- >>> p = Parser.takeStartBy (== ',') Fold.toList
759−-- >>> leadingComma = Stream.parse p . Stream.fromList
760−-- >>> leadingComma "a,b"
761−-- Left (ParseError "takeStartBy: missing frame start")
762−-- ...
763−-- >>> leadingComma ",,"
764−-- Right ","
765−-- >>> leadingComma ",a,b"
766−-- Right ",a"
767−-- >>> leadingComma ""
768−-- Right ""
769−--
770−-- /Pre-release/
771−--
772−{-# INLINE takeStartBy #-}
773−takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
774−takeStartBy cond = D.toParserK . D.takeStartBy cond
775−
776−-- | Like 'takeStartBy' but drops the separator.
777−--
778−-- >>> takeStartBy_ isBegin = Parser.takeFramedByGeneric Nothing (Just isBegin) Nothing
779−--
780−{-# INLINE takeStartBy_ #-}
781−takeStartBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
782−takeStartBy_ isBegin = takeFramedByGeneric Nothing (Just isBegin) Nothing
783−
784−-------------------------------------------------------------------------------
785−-- Quoting and Escaping
786−-------------------------------------------------------------------------------
787−
788−-- | Like 'takeEndBy' but the separator elements can be escaped using an
789−-- escape char determined by the first predicate. The escape characters are
790−-- removed.
791−--
792−-- /pre-release/
793−{-# INLINE takeEndByEsc #-}
794−takeEndByEsc :: Monad m =>
795− (a -> Bool) -> (a -> Bool) -> Parser a m b -> Parser a m b
796−takeEndByEsc isEsc isEnd p =
797− D.toParserK $ D.takeEndByEsc isEsc isEnd (D.fromParserK p)
798−
799−-- | @takeFramedByEsc_ isEsc isBegin isEnd fold@ parses a token framed using a
800−-- begin and end predicate, and an escape character. The frame begin and end
801−-- characters lose their special meaning if preceded by the escape character.
802−--
803−-- Nested frames are allowed if begin and end markers are different, nested
804−-- frames must be balanced unless escaped, nested frame markers are emitted as
805−-- it is.
806−--
807−-- For example,
808−--
809−-- >>> p = Parser.takeFramedByEsc_ (== '\\') (== '{') (== '}') Fold.toList
810−-- >>> Stream.parse p $ Stream.fromList "{hello}"
811−-- Right "hello"
812−-- >>> Stream.parse p $ Stream.fromList "{hello {world}}"
813−-- Right "hello {world}"
814−-- >>> Stream.parse p $ Stream.fromList "{hello \\{world}"
815−-- Right "hello {world"
816−-- >>> Stream.parse p $ Stream.fromList "{hello {world}"
817−-- Left (ParseError "takeFramedByEsc_: missing frame end")
818−--
819−-- /Pre-release/
820−{-# INLINE takeFramedByEsc_ #-}
821−takeFramedByEsc_ :: Monad m =>
822− (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
823−takeFramedByEsc_ isEsc isBegin isEnd f =
824− D.toParserK $ D.takeFramedByEsc_ isEsc isBegin isEnd f
825−-- takeEndByEsc_ isEsc isEnd p =
826−-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
827−
828−-- | @takeFramedBy_ isBegin isEnd fold@ parses a token framed by a begin and an
829−-- end predicate.
830−--
831−-- >>> takeFramedBy_ = Parser.takeFramedByEsc_ (const False)
832−--
833−{-# INLINE takeFramedBy_ #-}
834−takeFramedBy_ :: Monad m =>
835− (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
836−takeFramedBy_ isBegin isEnd f = D.toParserK $ D.takeFramedBy_ isBegin isEnd f
837−-- takeFramedBy_ isBegin isEnd =
838−-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
839−
840−-------------------------------------------------------------------------------
841−-- Grouping and words
842−-------------------------------------------------------------------------------
843−
844−-- Note we can also get words using something like:
845−-- sepBy FL.toList (takeWhile (not . p) Fold.toList) (dropWhile p)
846−--
847−-- But that won't be as efficient and ergonomic.
848−--
849−-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
850−-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
851−-- @["a","b"]@. In other words, its like parsing words from whitespace
852−-- separated text.
853−--
854−-- * Stops - when it finds a word separator after a non-word element
855−-- * Fails - never.
856−--
857−-- >>> wordBy = Parser.wordFramedBy (const False) (const False) (const False)
858−--
859−-- @
860−-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
861−-- @
862−--
863−{-# INLINE wordBy #-}
864−wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
865−wordBy f = D.toParserK . D.wordBy f
866−
867−-- | Like 'wordBy' but treats anything inside a pair of quotes as a single
868−-- word, the quotes can be escaped by an escape character. Recursive quotes
869−-- are possible if quote begin and end characters are different, quotes must be
870−-- balanced. Outermost quotes are stripped.
871−--
872−-- >>> braces = Parser.wordFramedBy (== '\\') (== '{') (== '}') isSpace Fold.toList
873−-- >>> Stream.parse braces $ Stream.fromList "{ab} cd"
874−-- Right "ab"
875−-- >>> Stream.parse braces $ Stream.fromList "{ab}{cd}"
876−-- Right "abcd"
877−-- >>> Stream.parse braces $ Stream.fromList "a{b} cd"
878−-- Right "ab"
879−-- >>> Stream.parse braces $ Stream.fromList "a{{b}} cd"
880−-- Right "a{b}"
881−--
882−-- >>> quotes = Parser.wordFramedBy (== '\\') (== '"') (== '"') isSpace Fold.toList
883−-- >>> Stream.parse quotes $ Stream.fromList "\"a\"\"b\""
884−-- Right "ab"
885−--
886−{-# INLINE wordFramedBy #-}
887−wordFramedBy :: Monad m =>
888− (a -> Bool) -- ^ Escape
889− -> (a -> Bool) -- ^ left quote
890− -> (a -> Bool) -- ^ right quote
891− -> (a -> Bool) -- ^ word seperator
892− -> Fold m a b
893− -> Parser a m b
894−wordFramedBy isEsc isBegin isEnd isSpc =
895− D.toParserK . D.wordFramedBy isEsc isBegin isEnd isSpc
896−
897−-- | Like 'wordFramedBy' but the closing quote is determined by the opening
898−-- quote. The first quote begin starts a quote that is closed by its
899−-- corresponding closing quote.
900−--
901−-- 'wordFramedBy' and 'wordQuotedBy' both allow multiple quote characters based
902−-- on the predicates but 'wordQuotedBy' always fixes the quote at the first
903−-- occurrence and then it is closed only by the corresponding closing quote.
904−-- Therefore, other quoting characters can be embedded inside it as normal
905−-- characters. On the other hand, 'wordFramedBy' would close the quote as soon
906−-- as it encounters any of the closing quotes.
907−--
908−-- >>> q = (`elem` ['"', '\''])
909−-- >>> p kQ = Parser.wordQuotedBy kQ (== '\\') q q id isSpace Fold.toList
910−--
911−-- >>> Stream.parse (p False) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
912−-- Right "ab'c;d\"ef"
913−--
914−-- >>> Stream.parse (p True) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
915−-- Right "a\"b'c\";'d\"e'f"
916−--
917−{-# INLINE wordQuotedBy #-}
918−wordQuotedBy :: (Monad m, Eq a) =>
919− Bool -- ^ keep the quotes in the output
920− -> (a -> Bool) -- ^ Escape
921− -> (a -> Bool) -- ^ left quote
922− -> (a -> Bool) -- ^ right quote
923− -> (a -> a) -- ^ get right quote from left quote
924− -> (a -> Bool) -- ^ word seperator
925− -> Fold m a b
926− -> Parser a m b
927−wordQuotedBy keepQuotes isEsc isBegin isEnd toRight isSpc =
928− D.toParserK . D.wordQuotedBy keepQuotes isEsc isBegin isEnd toRight isSpc
929−
930−-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
931−-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
932−-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
933−-- then @c@ is also assigned to the same group and so on. When the comparison
934−-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
935−-- the result of the fold is the result of the parser.
936−--
937−-- * Stops - when the comparison fails.
938−-- * Fails - never.
939−--
940−-- >>> :{
941−-- runGroupsBy eq =
942−-- Stream.fold Fold.toList
943−-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
944−-- . Stream.fromList
945−-- :}
946−--
947−-- >>> runGroupsBy (<) []
948−-- []
949−--
950−-- >>> runGroupsBy (<) [1]
951−-- [Right [1]]
952−--
953−-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
954−-- [Right [3,5,4],Right [1,2],Right [0]]
955−--
956−{-# INLINE groupBy #-}
957−groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
958−groupBy eq = D.toParserK . D.groupBy eq
959−
960−-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
961−-- successive elements in the input stream. Assuming the input stream
962−-- is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
963−-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
964−-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
965−-- then @c@ is also assigned to the same group and so on. When the comparison
966−-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
967−-- the result of the fold is the result of the parser.
968−--
969−-- * Stops - when the comparison fails.
970−-- * Fails - never.
971−--
972−-- >>> :{
973−-- runGroupsByRolling eq =
974−-- Stream.fold Fold.toList
975−-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
976−-- . Stream.fromList
977−-- :}
978−--
979−-- >>> runGroupsByRolling (<) []
980−-- []
981−--
982−-- >>> runGroupsByRolling (<) [1]
983−-- [Right [1]]
984−--
985−-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
986−-- [Right [3,5],Right [4],Right [1,2],Right [0]]
987−--
988−-- /Pre-release/
989−--
990−{-# INLINE groupByRolling #-}
991−groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
992−groupByRolling eq = D.toParserK . D.groupByRolling eq
993−
994−-- | Like 'groupByRolling', but if the predicate is 'True' then collects using
995−-- the first fold as long as the predicate holds 'True', if the predicate is
996−-- 'False' collects using the second fold as long as it remains 'False'.
997−-- Returns 'Left' for the first case and 'Right' for the second case.
998−--
999−-- For example, if we want to detect sorted sequences in a stream, both
1000−-- ascending and descending cases we can use 'groupByRollingEither (<=)
1001−-- Fold.toList Fold.toList'.
1002−--
1003−-- /Pre-release/
1004−{-# INLINE groupByRollingEither #-}
1005−groupByRollingEither :: Monad m =>
1006− (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
1007−groupByRollingEither eq f1 = D.toParserK . D.groupByRollingEither eq f1
1008−
1009−-- | Like 'listEqBy' but uses a stream instead of a list and does not return
1010−-- the stream.
1011−--
1012−-- See also: "Streamly.Data.Stream.streamEqBy"
1013−--
1014−{-# INLINE streamEqBy #-}
1015−streamEqBy :: Monad m => (a -> a -> Bool) -> Stream m a -> Parser a m ()
1016−streamEqBy cmp = D.toParserK . D.streamEqBy cmp
1017−
1018−-- | Match the given sequence of elements using the given comparison function.
1019−-- Returns the original sequence if successful.
1020−--
1021−-- Definition:
1022−--
1023−-- >>> listEqBy cmp xs = Parser.streamEqBy cmp (Stream.fromList xs) *> Parser.fromPure xs
1024−--
1025−-- Examples:
1026−--
1027−-- >>> Stream.parse (Parser.listEqBy (==) "string") $ Stream.fromList "string"
1028−-- Right "string"
1029−--
1030−-- >>> Stream.parse (Parser.listEqBy (==) "mismatch") $ Stream.fromList "match"
1031−-- Left (ParseError "streamEqBy: mismtach occurred")
1032−--
1033−{-# INLINE listEqBy #-}
1034−listEqBy :: Monad m => (a -> a -> Bool) -> [a] -> Parser a m [a]
1035−-- listEqBy cmp xs = D.toParserK (D.listEqBy cmp xs)
1036−listEqBy cmp xs = streamEqBy cmp (Stream.fromList xs) *> fromPure xs
1037−
1038−-- Rename to "list".
1039−-- | Match the input sequence with the supplied list and return it if
1040−-- successful.
1041−--
1042−-- >>> listEq = Parser.listEqBy (==)
1043−--
1044−{-# INLINE listEq #-}
1045−listEq :: (Monad m, Eq a) => [a] -> Parser a m [a]
1046−listEq = listEqBy (==)
1047−
1048−-- | Match if the input stream is a subsequence of the argument stream i.e. all
1049−-- the elements of the input stream occur, in order, in the argument stream.
1050−-- The elements do not have to occur consecutively. A sequence is considered a
1051−-- subsequence of itself.
1052−{-# INLINE subsequenceBy #-}
1053−subsequenceBy :: -- Monad m =>
1054− (a -> a -> Bool) -> Stream m a -> Parser a m ()
1055−subsequenceBy = undefined
1056−
1057−{-
1058−-- Should go in Data.Parser.Regex in streamly package so that it can depend on
1059−-- regex backends.
1060−{-# INLINE regexPosix #-}
1061−regexPosix :: -- Monad m =>
1062− Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
1063−regexPosix = undefined
1064−
1065−{-# INLINE regexPCRE #-}
1066−regexPCRE :: -- Monad m =>
1067− Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
1068−regexPCRE = undefined
1069−-}
1070−
1071−-------------------------------------------------------------------------------
1072−-- nested parsers
1073−-------------------------------------------------------------------------------
1074−
1075−-- | Sequential parser application. Apply two parsers sequentially to an input
1076−-- stream. The input is provided to the first parser, when it is done the
1077−-- remaining input is provided to the second parser. If both the parsers
1078−-- succeed their outputs are combined using the supplied function. The
1079−-- operation fails if any of the parsers fail.
1080−--
1081−-- Note: This is a parsing dual of appending streams using
1082−-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and zips
1083−-- the results.
1084−--
1085−-- This implementation is strict in the second argument, therefore, the
1086−-- following will fail:
1087−--
1088−-- >>> Stream.parse (Parser.splitWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
1089−-- *** Exception: Prelude.undefined
1090−-- ...
1091−--
1092−-- Compare with 'Applicative' instance method '<*>'. This implementation allows
1093−-- stream fusion but has quadratic complexity. This can fuse with other
1094−-- operations and can be faster than 'Applicative' instance for small number
1095−-- (less than 8) of compositions.
1096−--
1097−-- Many combinators can be expressed using @splitWith@ and other parser
1098−-- primitives. Some common idioms are described below,
1099−--
1100−-- @
1101−-- span :: (a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
1102−-- span pred f1 f2 = splitWith (,) ('takeWhile' pred f1) ('fromFold' f2)
1103−-- @
1104−--
1105−-- @
1106−-- spanBy :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
1107−-- spanBy eq f1 f2 = splitWith (,) ('groupBy' eq f1) ('fromFold' f2)
1108−-- @
1109−--
1110−-- @
1111−-- spanByRolling :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
1112−-- spanByRolling eq f1 f2 = splitWith (,) ('groupByRolling' eq f1) ('fromFold' f2)
1113−-- @
1114−--
1115−-- /Pre-release/
1116−--
1117−{-# INLINE splitWith #-}
1118−splitWith :: Monad m
1119− => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1120−splitWith f p1 p2 =
1121− D.toParserK $ D.splitWith f (D.fromParserK p1) (D.fromParserK p2)
1122−
1123−-- | Sequential parser application ignoring the output of the first parser.
1124−-- Apply two parsers sequentially to an input stream. The input is provided to
1125−-- the first parser, when it is done the remaining input is provided to the
1126−-- second parser. The output of the parser is the output of the second parser.
1127−-- The operation fails if any of the parsers fail.
1128−--
1129−-- This implementation is strict in the second argument, therefore, the
1130−-- following will fail:
1131−--
1132−-- >>> Stream.parse (Parser.split_ (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
1133−-- *** Exception: Prelude.undefined
1134−-- ...
1135−--
1136−-- Compare with 'Applicative' instance method '*>'. This implementation allows
1137−-- stream fusion but has quadratic complexity. This can fuse with other
1138−-- operations, and can be faster than 'Applicative' instance for small
1139−-- number (less than 8) of compositions.
1140−--
1141−-- /Pre-release/
1142−--
1143−{-# INLINE split_ #-}
1144−split_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
1145−split_ p1 p2 = D.toParserK $ D.split_ (D.fromParserK p1) (D.fromParserK p2)
1146−
1147−{-
1148−-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
1149−-- of them succeed or anyone of them fails and combines their output using @f@.
1150−-- The parser succeeds if both the parsers succeed.
1151−--
1152−-- /Pre-release/
1153−--
1154−{-# INLINE teeWith #-}
1155−teeWith :: Monad m
1156− => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1157−teeWith f p1 p2 =
1158− D.toParserK $ D.teeWith f (D.fromParserK p1) (D.fromParserK p2)
1159−
1160−-- | Like 'teeWith' but ends parsing and zips the results, if available,
1161−-- whenever the first parser ends.
1162−--
1163−-- /Pre-release/
1164−--
1165−{-# INLINE teeWithFst #-}
1166−teeWithFst :: Monad m
1167− => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1168−teeWithFst f p1 p2 =
1169− D.toParserK $ D.teeWithFst f (D.fromParserK p1) (D.fromParserK p2)
1170−
1171−-- | Like 'teeWith' but ends parsing and zips the results, if available,
1172−-- whenever any of the parsers ends or fails.
1173−--
1174−-- /Unimplemented/
1175−--
1176−{-# INLINE teeWithMin #-}
1177−teeWithMin :: Monad m
1178− => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1179−teeWithMin f p1 p2 =
1180− D.toParserK $ D.teeWithMin f (D.fromParserK p1) (D.fromParserK p2)
1181−-}
1182−
1183−-- | Sequential alternative. Apply the input to the first parser and return the
1184−-- result if the parser succeeds. If the first parser fails then backtrack and
1185−-- apply the same input to the second parser and return the result.
1186−--
1187−-- Note: This implementation is not lazy in the second argument. The following
1188−-- will fail:
1189−--
1190−-- >>> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
1191−-- Right 1
1192−--
1193−-- Compare with 'Alternative' instance method '<|>'. This implementation allows
1194−-- stream fusion but has quadratic complexity. This can fuse with other
1195−-- operations and can be much faster than 'Alternative' instance for small
1196−-- number (less than 8) of alternatives.
1197−--
1198−-- /Pre-release/
1199−--
1200−{-# INLINE alt #-}
1201−alt :: Monad m => Parser x m a -> Parser x m a -> Parser x m a
1202−alt p1 p2 = D.toParserK $ D.alt (D.fromParserK p1) (D.fromParserK p2)
1203−
1204−{-
1205−-- | Shortest alternative. Apply both parsers in parallel but choose the result
1206−-- from the one which consumed least input i.e. take the shortest succeeding
1207−-- parse.
1208−--
1209−-- /Pre-release/
1210−--
1211−{-# INLINE shortest #-}
1212−shortest :: Monad m
1213− => Parser x m a -> Parser x m a -> Parser x m a
1214−shortest p1 p2 = D.toParserK $ D.shortest (D.fromParserK p1) (D.fromParserK p2)
1215−
1216−-- | Longest alternative. Apply both parsers in parallel but choose the result
1217−-- from the one which consumed more input i.e. take the longest succeeding
1218−-- parse.
1219−--
1220−-- /Pre-release/
1221−--
1222−{-# INLINE longest #-}
1223−longest :: Monad m
1224− => Parser x m a -> Parser x m a -> Parser x m a
1225−longest p1 p2 = D.toParserK $ D.longest (D.fromParserK p1) (D.fromParserK p2)
1226−-}
1227−
1228−-- | Run a parser without consuming the input.
1229−--
1230−{-# INLINE lookAhead #-}
1231−lookAhead :: Monad m => Parser a m b -> Parser a m b
1232−lookAhead p = D.toParserK $ D.lookAhead $ D.fromParserK p
1233−
1234−-- | Takes at-most @n@ input elements.
1235−--
1236−-- * Stops - when the collecting parser stops.
1237−-- * Fails - when the collecting parser fails.
1238−--
1239−-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
1240−-- Right [1,2]
1241−--
1242−-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
1243−-- Left (ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4")
1244−--
1245−-- /Internal/
1246−{-# INLINE takeP #-}
1247−takeP :: Monad m => Int -> Parser a m b -> Parser a m b
1248−takeP i p = D.toParserK $ D.takeP i $ D.fromParserK p
1249−
1250−-------------------------------------------------------------------------------
1251−-- Sequential Collection
1252−-------------------------------------------------------------------------------
1253−--
1254−-- | @concatSequence f p@ collects sequential parses of parsers in a
1255−-- serial stream @p@ using the fold @f@. Fails if the input ends or any
1256−-- of the parsers fail.
1257−--
1258−-- An even more efficient implementation can use ParserD type Parser in
1259−-- the stream.
1260−--
1261−-- /Pre-release/
1262−--
1263−{-# INLINE concatSequence #-}
1264−concatSequence ::
1265− Monad m =>
1266− Fold m b c -> Stream m (Parser a m b) -> Parser a m c
1267−concatSequence f p =
1268− let sp = fmap D.fromParserK p
1269− in D.toParserK $ D.sequence sp f
1270−
1271−-- | Map a 'Parser' returning function on the result of a 'Parser'.
1272−--
1273−-- Compare with 'Monad' instance method '>>='. This implementation allows
1274−-- stream fusion but has quadratic complexity. This can fuse with other
1275−-- operations and can be much faster than 'Monad' instance for small number
1276−-- (less than 8) of compositions.
1277−--
1278−-- /Pre-release/
1279−--
1280−{-# INLINE concatMap #-}
1281−concatMap :: Monad m
1282− => (b -> Parser a m c) -> Parser a m b -> Parser a m c
1283−concatMap f p = D.toParserK $ D.concatMap (D.fromParserK . f) (D.fromParserK p)
1284−
1285−{-
1286−-------------------------------------------------------------------------------
1287−-- Alternative Collection
1288−-------------------------------------------------------------------------------
1289−--
1290−-- | @choice parsers@ applies the @parsers@ in order and returns the first
1291−-- successful parse.
1292−--
1293−-- This is same as 'asum' but more efficient.
1294−--
1295−-- /Broken/
1296−--
1297−{-# INLINE choice #-}
1298−choice ::
1299− (Functor t, Foldable t, Monad m) => t (Parser a m b) -> Parser a m b
1300−choice ps = D.toParserK $ D.choice $ D.fromParserK <$> ps
1301−-}
1302−
1303−-------------------------------------------------------------------------------
1304−-- Sequential Repetition
1305−-------------------------------------------------------------------------------
1306−
1307−-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
1308−-- results. Parsing stops or fails if the collecting parser stops or fails.
1309−--
1310−-- /Unimplemented/
1311−--
1312−{-# INLINE manyP #-}
1313−manyP :: -- Monad m =>
1314− Parser a m b -> Parser b m c -> Parser a m c
1315−manyP _p _f = undefined -- D.toParserK $ D.manyP (D.fromParserK p) f
1316−
1317−-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
1318−-- input stream and push the parse results to a downstream fold.
1319−--
1320−-- Stops: when the downstream fold stops or the parser fails.
1321−-- Fails: never, produces zero or more results.
1322−--
1323−-- >>> many = Parser.countBetween 0 maxBound
1324−--
1325−-- Compare with 'Control.Applicative.many'.
1326−--
1327−{-# INLINE many #-}
1328−many :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1329−many p f = D.toParserK $ D.many (D.fromParserK p) f
1330−
1331−-- Note: many1 would perhaps be a better name for this and consistent with
1332−-- other names like takeWhile1. But we retain the name "some" for
1333−-- compatibility.
1334−--
1335−-- | Collect one or more parses. Apply the supplied parser repeatedly on the
1336−-- input stream and push the parse results to a downstream fold.
1337−--
1338−-- Stops: when the downstream fold stops or the parser fails.
1339−-- Fails: if it stops without producing a single result.
1340−--
1341−-- >>> some p f = Parser.manyP p (Parser.takeGE 1 f)
1342−-- >>> some = Parser.countBetween 1 maxBound
1343−--
1344−-- Compare with 'Control.Applicative.some'.
1345−--
1346−{-# INLINE some #-}
1347−some :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1348−some p f = D.toParserK $ D.some (D.fromParserK p) f
1349−-- some p f = manyP p (takeGE 1 f)
1350−-- some = countBetween 1 maxBound
1351−
1352−-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
1353−-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
1354−-- the input ends or the parser fails before @m@ results are collected.
1355−--
1356−-- >>> countBetween m n p f = Parser.manyP p (Parser.takeBetween m n f)
1357−--
1358−-- /Unimplemented/
1359−--
1360−{-# INLINE countBetween #-}
1361−countBetween :: -- Monad m =>
1362− Int -> Int -> Parser a m b -> Fold m b c -> Parser a m c
1363−countBetween _m _n _p = undefined
1364−-- countBetween m n p f = manyP p (takeBetween m n f)
1365−
1366−-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
1367−-- the fold @f@. Fails if the input ends or the parser fails before @n@
1368−-- results are collected.
1369−--
1370−-- >>> count n = Parser.countBetween n n
1371−-- >>> count n p f = Parser.manyP p (Parser.takeEQ n f)
1372−--
1373−-- /Unimplemented/
1374−--
1375−{-# INLINE count #-}
1376−count :: -- Monad m =>
1377− Int -> Parser a m b -> Fold m b c -> Parser a m c
1378−count n = countBetween n n
1379−-- count n p f = manyP p (takeEQ n f)
1380−
1381−-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
1382−-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
1383−--
1384−-- We can implemnent parsers like the following using 'manyTillP':
1385−--
1386−-- @
1387−-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
1388−-- @
1389−--
1390−-- /Unimplemented/
1391−--
1392−{-# INLINE manyTillP #-}
1393−manyTillP :: -- Monad m =>
1394− Parser a m b -> Parser a m x -> Parser b m c -> Parser a m c
1395−manyTillP _p1 _p2 _f = undefined
1396− -- D.toParserK $ D.manyTillP (D.fromParserK p1) (D.fromParserK p2) f
1397−
1398−-- | @manyTill chunking test f@ tries the parser @test@ on the input, if @test@
1399−-- fails it backtracks and tries @chunking@, after @chunking@ succeeds @test@ is
1400−-- tried again and so on. The parser stops when @test@ succeeds. The output of
1401−-- @test@ is discarded and the output of @chunking@ is accumulated by the
1402−-- supplied fold. The parser fails if @chunking@ fails.
1403−--
1404−-- Stops when the fold @f@ stops.
1405−--
1406−{-# INLINE manyTill #-}
1407−manyTill :: Monad m
1408− => Parser a m b -- ^ Chunking parser. Parses chunks of input.
1409− -> Parser a m x -- ^ Test parser. Parsing stops when this parser succeeds
1410− -- else backtract and run the chunking parser.
1411− -> Fold m b c -- ^ Folds the output of the chunking parser.
1412− -> Parser a m c
1413−manyTill collect test f =
1414− D.toParserK $ D.manyTill (D.fromParserK collect) (D.fromParserK test) f
1415−
1416−-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
1417−-- collects the output in the supplied fold. If the the parser @collect@ fails,
1418−-- parser @recover@ is run until it stops and then we start repeating the
1419−-- parser @collect@ again. The parser fails if the recovery parser fails.
1420−--
1421−-- For example, this can be used to find a key frame in a video stream after an
1422−-- error.
1423−--
1424−-- /Unimplemented/
1425−--
1426−{-# INLINE manyThen #-}
1427−manyThen :: -- (Foldable t, Monad m) =>
1428− Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
1429−manyThen _parser _recover _f = undefined
1430−
1431−-------------------------------------------------------------------------------
1432−-- Interleaving
1433−-------------------------------------------------------------------------------
1434−--
1435−-- To deinterleave we can chain two parsers one behind the other. The input is
1436−-- given to the first parser and the input definitively rejected by the first
1437−-- parser is given to the second parser.
1438−--
1439−-- We can either have the parsers themselves buffer the input or use the shared
1440−-- global buffer to hold it until none of the parsers need it. When the first
1441−-- parser returns Skip (i.e. rewind) we let the second parser consume the
1442−-- rejected input and when it is done we move the cursor forward to the first
1443−-- parser again. This will require a "move forward" command as well.
1444−--
1445−-- To implement grep we can use three parsers, one to find the pattern, one
1446−-- to store the context behind the pattern and one to store the context in
1447−-- front of the pattern. When a match occurs we need to emit the accumulator of
1448−-- all the three parsers. One parser can count the line numbers to provide the
1449−-- line number info.
1450−
1451−-- XXX rename this to intercalate
1452−-- | Apply two parsers alternately to an input stream. The input stream is
1453−-- considered an interleaving of two patterns. The two parsers represent the
1454−-- two patterns.
1455−--
1456−{-# INLINE deintercalate #-}
1457−deintercalate :: Monad m =>
1458− Parser a m x
1459− -> Parser a m y
1460− -> Fold m (Either x y) z
1461− -> Parser a m z
1462−deintercalate contentL contentR sink =
1463− D.toParserK
1464− $ D.deintercalate
1465− (D.fromParserK contentL) (D.fromParserK contentR) sink
1466−
1467−-- | Parse items separated by a separator parsed by the supplied parser. At
1468−-- least one item must be present for the parser to succeed.
1469−--
1470−-- Note that this can go in infinite loop if both the parsers fail on some
1471−-- input. Detection of that would make the implementation more complex.
1472−--
1473−{-# INLINE sepBy1 #-}
1474−sepBy1 :: Monad m =>
1475− Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
1476−sepBy1 p sep sink = do
1477− x <- p
1478− f <- fromEffect $ FL.reduce sink
1479− f1 <- fromEffect $ FL.snoc f x
1480− many (sep >> p) f1
1481−
1482−-- | Run the content parser first, when it is done, the separator parser is
1483−-- run, when it is done content parser is run again and so on. If none of the
1484−-- parsers consumes an input then parser returns a failure.
1485−--
1486−-- >>> sepBy p1 p2 sink = Parser.deintercalate p1 p2 (Fold.catLefts sink)
1487−-- >>> sepBy content sep sink = Parser.sepBy1 content sep sink <|> return mempty
1488−--
1489−{-# INLINE sepBy #-}
1490−sepBy :: Monad m =>
1491− Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
1492−sepBy content sep sink =
1493− D.toParserK $ D.sepBy (D.fromParserK content) (D.fromParserK sep) sink
1494−-- sepBy sink = deintercalate (FL.catLefts sink)
1495−
1496−-------------------------------------------------------------------------------
1497−-- Interleaving a collection of parsers
1498−-------------------------------------------------------------------------------
1499−--
1500−-- | Apply a collection of parsers to an input stream in a round robin fashion.
1501−-- Each parser is applied until it stops and then we repeat starting with the
1502−-- the first parser again.
1503−--
1504−-- /Unimplemented/
1505−--
1506−{-# INLINE roundRobin #-}
1507−roundRobin :: -- (Foldable t, Monad m) =>
1508− t (Parser a m b) -> Fold m b c -> Parser a m c
1509−roundRobin _ps _f = undefined
1510−
1511−-------------------------------------------------------------------------------
1512−-- Repeated Alternatives
1513−-------------------------------------------------------------------------------
1514−
1515−-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
1516−-- fails the input consumed till now is dropped and the new instance is tried
1517−-- on the fresh input.
1518−--
1519−-- /Unimplemented/
1520−--
1521−{-# INLINE retryMaxTotal #-}
1522−retryMaxTotal :: -- (Monad m) =>
1523− Int -> Parser a m b -> Fold m b c -> Parser a m c
1524−retryMaxTotal _n _p _f = undefined
1525−
1526−-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
1527−--
1528−-- /Unimplemented/
1529−--
1530−{-# INLINE retryMaxSuccessive #-}
1531−retryMaxSuccessive :: -- (Monad m) =>
1532− Int -> Parser a m b -> Fold m b c -> Parser a m c
1533−retryMaxSuccessive _n _p _f = undefined
1534−
1535−-- | Keep trying a parser until it succeeds. When the parser fails the input
1536−-- consumed till now is dropped and the new instance is tried on the fresh
1537−-- input.
1538−--
1539−-- /Unimplemented/
1540−--
1541−{-# INLINE retry #-}
1542−retry :: -- (Monad m) =>
1543− Parser a m b -> Parser a m b
1544−retry _p = undefined
14+import Streamly.Internal.Data.Parser.ParserD
core/src/Streamly/Internal/Data/Parser/Chunked/Type.hs+2
@@ -57,6 +57,8 @@ data Step a m r =
5757 -- Array a -> m (Step a m r), m (Step a m r)
5858 -- XXX The Array is the only difference from element parser, we can pass
5959 -- this as parameter?
60+ -- XXX Unify element and chunked parser, by using the argument as
61+ -- None | Single a | Chunk (Array a).
6062 | Partial !Int (Maybe (Array a) -> m (Step a m r))
6163 | Continue !Int (Maybe (Array a) -> m (Step a m r))
6264 | Error !Int String
core/src/Streamly/Internal/Data/Parser/ParserD.hs+780−104
@@ -1,5 +1,3 @@
1−#include "inline.hs"
2−
31-- |
42-- Module : Streamly.Internal.Data.Parser.ParserD
53-- Copyright : (c) 2020 Composewell Technologies
@@ -8,7 +6,42 @@
86-- Stability : experimental
97-- Portability : GHC
108--
11−-- Direct style parser implementation with stream fusion.
9+-- Fast backtracking parsers with stream fusion and native streaming
10+-- capability.
11+--
12+-- 'Applicative' and 'Control.Applicative.Alternative' type class based
13+-- combinators from the
14+-- <http://hackage.haskell.org/package/parser-combinators parser-combinators>
15+-- package can also be used with the 'Parser' type. However, there are two
16+-- important differences between @parser-combinators@ and the equivalent ones
17+-- provided in this module in terms of performance:
18+--
19+-- 1) @parser-combinators@ use plain Haskell lists to collect the results, in a
20+-- strict Monad like IO, the results are necessarily buffered before they can
21+-- be consumed. This may not perform optimally in streaming applications
22+-- processing large amounts of data. Equivalent combinators in this module can
23+-- consume the results of parsing using a 'Fold', thus providing a scalability
24+-- and a composable consumer.
25+--
26+-- 2) Several combinators in this module can be many times faster because of
27+-- stream fusion. For example, 'Streamly.Internal.Data.Parser.many' combinator
28+-- in this module is much faster than the 'Control.Applicative.many' combinator
29+-- of 'Control.Applicative.Alternative' type class.
30+--
31+-- = Errors
32+--
33+-- Failing parsers in this module throw the 'D.ParseError' exception.
34+--
35+-- = Naming
36+--
37+-- As far as possible, try that the names of the combinators in this module are
38+-- consistent with:
39+--
40+-- * <https://hackage.haskell.org/package/base/docs/Text-ParserCombinators-ReadP.html base/Text.ParserCombinators.ReadP>
41+-- * <http://hackage.haskell.org/package/parser-combinators parser-combinators>
42+-- * <http://hackage.haskell.org/package/megaparsec megaparsec>
43+-- * <http://hackage.haskell.org/package/attoparsec attoparsec>
44+-- * <http://hackage.haskell.org/package/parsec parsec>
1245
1346module Streamly.Internal.Data.Parser.ParserD
1447 (
@@ -16,7 +49,6 @@ module Streamly.Internal.Data.Parser.ParserD
1649 , ParseError (..)
1750 , Step (..)
1851 , Initial (..)
19− , rmapM
2052
2153 -- * Conversion to/from ParserK
2254 , fromParserK
@@ -40,17 +72,26 @@ module Streamly.Internal.Data.Parser.ParserD
4072 , postscan
4173 , filter
4274
75+ -- * Map on output
76+ , rmapM
77+
4378 -- * Element parsers
4479 , peek
80+
81+ -- All of these can be expressed in terms of either
82+ , one
83+ , oneEq
84+ , oneNotEq
85+ , oneOf
86+ , noneOf
4587 , eof
4688 , satisfy
47− , next
4889 , maybe
4990 , either
5091
51− -- * Sequence parsers
92+ -- * Sequence parsers (tokenizers)
5293 --
53− -- Parsers chained in series, if one parser terminates the composition
94+ -- | Parsers chained in series, if one parser terminates the composition
5495 -- terminates. Currently we are using folds to collect the output of the
5596 -- parsers but we can use Parsers instead of folds to make the composition
5697 -- more powerful. For example, we can do:
@@ -58,41 +99,54 @@ module Streamly.Internal.Data.Parser.ParserD
5899 -- takeEndByOrMax cond n p = takeEndBy cond (take n p)
59100 -- takeEndByBetween cond m n p = takeEndBy cond (takeBetween m n p)
60101 -- takeWhileBetween cond m n p = takeWhile cond (takeBetween m n p)
102+ , lookAhead
61103
62− -- Grab a sequence of input elements without inspecting them
104+ -- ** By length
105+ -- | Grab a sequence of input elements without inspecting them
63106 , takeBetween
64− -- , take -- take -- takeBetween 0 n
107+ -- , take -- takeBetween 0 n
65108 , takeEQ -- takeBetween n n
66109 , takeGE -- takeBetween n maxBound
67110 -- , takeGE1 -- take1 -- takeBetween 1 n
68111 , takeP
69112
70113 -- Grab a sequence of input elements by inspecting them
71− , lookAhead
114+ -- ** Exact match
115+ , listEq
116+ , listEqBy
117+ , streamEqBy
118+ , subsequenceBy
119+
120+ -- ** By predicate
72121 , takeWhile
73122 , takeWhileP
74123 , takeWhile1
124+ , dropWhile
75125
76− -- Separators
126+ -- ** Separators
77127 , takeEndBy
78128 , takeEndBy_
79129 , takeEndByEsc
130+ -- , takeEndByEsc_
80131 , takeStartBy
132+ , takeStartBy_
133+ , takeEitherSepBy
134+ , wordBy
135+
136+ -- ** By comparing
137+ , groupBy
138+ , groupByRolling
139+ , groupByRollingEither
140+
141+ -- ** Framing
142+ -- , takeFramedBy
81143 , takeFramedBy_
82144 , takeFramedByEsc_
83145 , takeFramedByGeneric
84−
85− -- Words and grouping
86− , wordBy
87146 , wordFramedBy
88147 , wordQuotedBy
89− , groupBy
90− , groupByRolling
91− , groupByRollingEither
92148
93149 -- Matching strings
94− , listEqBy
95− , streamEqBy
96150 -- , prefixOf -- match any prefix of a given string
97151 -- , suffixOf -- match any suffix of a given string
98152 -- , infixOf -- match any substring of a given string
@@ -121,6 +175,25 @@ module Streamly.Internal.Data.Parser.ParserD
121175 -- Use two folds, run a primary parser, its rejected values go to the
122176 -- secondary parser.
123177 , deintercalate
178+ -- , deintercalatePrefix
179+ -- , deintercalateSuffix
180+
181+ -- *** Special cases
182+ -- | TODO: traditional implmentations of these may be of limited use. For
183+ -- example, consider parsing lines separated by @\\r\\n@. The main parser
184+ -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
185+ -- can apply the "sep" parser.
186+ --
187+ -- We can instead implement these as special cases of deintercalate.
188+ --
189+ -- @
190+ -- , endBy
191+ -- , sepEndBy
192+ -- , beginBy
193+ -- , sepBeginBy
194+ -- , sepAroundBy
195+ -- @
196+ , sepBy1
124197 , sepBy
125198
126199 -- ** Sequential Alternative
@@ -132,6 +205,7 @@ module Streamly.Internal.Data.Parser.ParserD
132205 , longest
133206 -- , fastest
134207 -}
208+
135209 -- * N-ary Combinators
136210 -- ** Sequential Collection
137211 , sequence
@@ -142,25 +216,12 @@ module Streamly.Internal.Data.Parser.ParserD
142216 , countBetween
143217 -- , countBetweenTill
144218
145− , many
146219 , manyP
220+ , many
147221 , some
222+ , manyTillP
148223 , manyTill
149−
150− -- -- ** Special cases
151− -- XXX traditional implmentations of these may be of limited use. For
152− -- example, consider parsing lines separated by "\r\n". The main parser
153− -- will have to detect and exclude the sequence "\r\n" anyway so that we
154− -- can apply the "sep" parser.
155− --
156− -- We can instead implement these as special cases of deintercalate.
157− --
158− -- , endBy
159− -- , sepBy
160− -- , sepEndBy
161− -- , beginBy
162− -- , sepBeginBy
163− -- , sepAroundBy
224+ , manyThen
164225
165226 -- -- * Distribution
166227 --
@@ -171,24 +232,32 @@ module Streamly.Internal.Data.Parser.ParserD
171232 -- -- ** Distribute to collection
172233 -- -- ** Distribute to repetition
173234
174− -- -- ** Interleaved collection
175− -- Round robin
176− -- Priority based
235+ -- ** Interleaved collection
236+ -- |
237+ --
238+ -- 1. Round robin
239+ -- 2. Priority based
240+ , roundRobin
241+
177242 -- -- ** Interleaved repetition
178243 -- repeat one parser and when it fails run an error recovery parser
179244 -- e.g. to find a key frame in the stream after an error
180245
181246 -- ** Collection of Alternatives
247+ -- | Unimplemented
248+ --
249+ -- @
182250 -- , shortestN
183251 -- , longestN
184252 -- , fastestN -- first N successful in time
185253 -- , choiceN -- first N successful in position
254+ -- @
186255 -- , choice -- first successful in position
187256
188− -- -- ** Repeated Alternatives
189− -- , retryMax -- try N times
190− -- , retryUntil -- try until successful
191− -- , retryUntilN -- try until successful n times
257+ -- ** Repeated Alternatives
258+ , retryMaxTotal
259+ , retryMaxSuccessive
260+ , retry
192261
193262 -- ** Zipping Input
194263 , zipWithM
@@ -196,9 +265,13 @@ module Streamly.Internal.Data.Parser.ParserD
196265 , indexed
197266 , makeIndexFilter
198267 , sampleFromthen
268+
269+ -- * Deprecated
270+ , next
199271 )
200272where
201273
274+#include "inline.hs"
202275#include "assert.hs"
203276
204277import Control.Monad (when)
@@ -209,14 +282,16 @@ import Streamly.Internal.Data.SVar.Type (defState)
209282import Streamly.Internal.Data.Either.Strict (Either'(..))
210283import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
211284import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
285+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
212286
287+import qualified Data.Foldable as Foldable
213288import qualified Streamly.Internal.Data.Fold.Type as FL
214289import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
215290import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
216291
217292import Prelude hiding
218293 (any, all, take, takeWhile, sequence, concatMap, maybe, either, span
219− , zip, filter)
294+ , zip, filter, dropWhile)
220295-- import Streamly.Internal.Data.Parser.ParserD.Tee
221296import Streamly.Internal.Data.Parser.ParserD.Type
222297
@@ -224,19 +299,27 @@ import Streamly.Internal.Data.Parser.ParserD.Type
224299-- $setup
225300-- >>> :m
226301-- >>> import Prelude hiding ()
302+-- >>> import Control.Applicative
303+-- >>> import Data.Char (isSpace)
304+-- >>> import qualified Data.Foldable as Foldable
227305-- >>> import qualified Data.Maybe as Maybe
228306-- >>> import qualified Streamly.Data.Stream as Stream
229307-- >>> import qualified Streamly.Internal.Data.Stream as Stream
230−-- >>> import qualified Streamly.Data.Fold as Fold
308+-- >>> import qualified Streamly.Internal.Data.Fold as Fold
231309-- >>> import qualified Streamly.Internal.Data.Parser as Parser
232310
233311-------------------------------------------------------------------------------
234312-- Downgrade a parser to a Fold
235313-------------------------------------------------------------------------------
236314
237−-- | See 'Streamly.Internal.Data.Parser.toFold'.
315+-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
316+-- parser fails or tries to backtrack.
238317--
239−-- /Internal/
318+-- This can be useful in combinators that accept a Fold and we know that a
319+-- Parser cannot fail or failure exception is acceptable as there is no way to
320+-- recover.
321+--
322+-- /Pre-release/
240323--
241324{-# INLINE toFold #-}
242325toFold :: Monad m => Parser a m b -> Fold m a b
@@ -280,10 +363,8 @@ toFold (Parser pstep pinitial pextract) = Fold step initial extract
280363-------------------------------------------------------------------------------
281364-- Upgrade folds to parses
282365-------------------------------------------------------------------------------
283−--
284−-- | See 'Streamly.Internal.Data.Parser.fromFold'.
285−--
286−-- /Pre-release/
366+
367+-- | Make a 'Parser' from a 'Fold'.
287368--
288369{-# INLINE fromFold #-}
289370fromFold :: Monad m => Fold m a b -> Parser a m b
@@ -307,7 +388,9 @@ fromFold (Fold fstep finitial fextract) = Parser step initial extract
307388
308389 extract = fmap (Done 0) . fextract
309390
310−-- | Convert Maybe returning folds to error returning parsers.
391+-- | Convert a Maybe returning fold to an error returning parser. The first
392+-- argument is the error message that the parser would return when the fold
393+-- returns Nothing.
311394--
312395-- /Pre-release/
313396--
@@ -348,9 +431,15 @@ fromFoldMaybe errMsg (Fold fstep finitial fextract) =
348431-- Failing Parsers
349432-------------------------------------------------------------------------------
350433
351−-- | See 'Streamly.Internal.Data.Parser.peek'.
434+-- | Peek the head element of a stream, without consuming it. Fails if it
435+-- encounters end of input.
352436--
353−-- /Pre-release/
437+-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
438+-- Right (1,1)
439+--
440+-- @
441+-- peek = lookAhead (satisfy True)
442+-- @
354443--
355444{-# INLINE peek #-}
356445peek :: Monad m => Parser a m a
@@ -364,9 +453,10 @@ peek = Parser step initial extract
364453
365454 extract () = return $ Error "peek: end of input"
366455
367−-- | See 'Streamly.Internal.Data.Parser.eof'.
456+-- | Succeeds if we are at the end of input, fails otherwise.
368457--
369−-- /Pre-release/
458+-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
459+-- Right (1,())
370460--
371461{-# INLINE eof #-}
372462eof :: Monad m => Parser a m ()
@@ -380,10 +470,12 @@ eof = Parser step initial extract
380470
381471 extract () = return $ Done 0 ()
382472
383−-- | See 'Streamly.Internal.Data.Parser.next'.
473+-- | Return the next element of the input. Returns 'Nothing'
474+-- on end of input. Also known as 'head'.
384475--
385476-- /Pre-release/
386477--
478+{-# DEPRECATED next "Please use \"fromFold Fold.one\" instead" #-}
387479{-# INLINE next #-}
388480next :: Monad m => Parser a m (Maybe a)
389481next = Parser step initial extract
@@ -396,7 +488,9 @@ next = Parser step initial extract
396488
397489 extract () = pure $ Done 0 Nothing
398490
399−-- | See 'Streamly.Internal.Data.Parser.either'.
491+-- | Map an 'Either' returning function on the next element in the stream. If
492+-- the function returns 'Left err', the parser fails with the error message
493+-- @err@ otherwise returns the 'Right' value.
400494--
401495-- /Pre-release/
402496--
@@ -415,11 +509,15 @@ either f = Parser step initial extract
415509
416510 extract () = return $ Error "end of input"
417511
418−-- | See 'Streamly.Internal.Data.Parser.maybe'.
512+-- | Map a 'Maybe' returning function on the next element in the stream. The
513+-- parser fails if the function returns 'Nothing' otherwise returns the 'Just'
514+-- value.
419515--
420516-- >>> toEither = Maybe.maybe (Left "maybe: predicate failed") Right
421517-- >>> maybe f = Parser.either (toEither . f)
422518--
519+-- >>> maybe f = Parser.fromFoldMaybe "maybe: predicate failed" (Fold.maybe f)
520+--
423521-- /Pre-release/
424522--
425523{-# INLINE maybe #-}
@@ -438,13 +536,14 @@ maybe parserF = Parser step initial extract
438536
439537 extract () = return $ Error "maybe: end of input"
440538
441−-- | See 'Streamly.Internal.Data.Parser.satisfy'.
539+-- | Returns the next element if it passes the predicate, fails otherwise.
540+--
541+-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
542+-- Right 1
442543--
443544-- >>> toMaybe f x = if f x then Just x else Nothing
444545-- >>> satisfy f = Parser.maybe (toMaybe f)
445546--
446−-- /Pre-release/
447−--
448547{-# INLINE satisfy #-}
449548satisfy :: Monad m => (a -> Bool) -> Parser a m a
450549-- satisfy predicate = maybe (\a -> if predicate a then Just a else Nothing)
@@ -461,6 +560,67 @@ satisfy predicate = Parser step initial extract
461560
462561 extract () = return $ Error "satisfy: end of input"
463562
563+-- | Consume one element from the head of the stream. Fails if it encounters
564+-- end of input.
565+--
566+-- >>> one = Parser.satisfy $ const True
567+--
568+{-# INLINE one #-}
569+one :: Monad m => Parser a m a
570+one = satisfy $ const True
571+
572+-- Alternate names: "only", "onlyThis".
573+
574+-- | Match a specific element.
575+--
576+-- >>> oneEq x = Parser.satisfy (== x)
577+--
578+{-# INLINE oneEq #-}
579+oneEq :: (Monad m, Eq a) => a -> Parser a m a
580+oneEq x = satisfy (== x)
581+
582+-- Alternate names: "exclude", "notThis".
583+
584+-- | Match anything other than the supplied element.
585+--
586+-- >>> oneNotEq x = Parser.satisfy (/= x)
587+--
588+{-# INLINE oneNotEq #-}
589+oneNotEq :: (Monad m, Eq a) => a -> Parser a m a
590+oneNotEq x = satisfy (/= x)
591+
592+-- | Match any one of the elements in the supplied list.
593+--
594+-- >>> oneOf xs = Parser.satisfy (`Foldable.elem` xs)
595+--
596+-- When performance matters a pattern matching predicate could be more
597+-- efficient than a 'Foldable' datatype:
598+--
599+-- @
600+-- let p x =
601+-- case x of
602+-- 'a' -> True
603+-- 'e' -> True
604+-- _ -> False
605+-- in satisfy p
606+-- @
607+--
608+-- GHC may use a binary search instead of linear search in the list.
609+-- Alternatively, you can also use an array instead of list for storage and
610+-- search.
611+--
612+{-# INLINE oneOf #-}
613+oneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
614+oneOf xs = satisfy (`Foldable.elem` xs)
615+
616+-- | See performance notes in 'oneOf'.
617+--
618+-- >>> noneOf xs = Parser.satisfy (`Foldable.notElem` xs)
619+--
620+{-# INLINE noneOf #-}
621+noneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
622+noneOf xs = satisfy (`Foldable.notElem` xs)
623+
464624-------------------------------------------------------------------------------
465625-- Taking elements
466626-------------------------------------------------------------------------------
@@ -469,7 +629,43 @@ satisfy predicate = Parser step initial extract
469629{-# ANN type Tuple'Fused Fuse #-}
470630data Tuple'Fused a b = Tuple'Fused !a !b deriving Show
471631
472−-- | See 'Streamly.Internal.Data.Parser.takeBetween'.
632+-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
633+-- elements and folds them using the supplied fold.
634+--
635+-- Stops after @n@ elements.
636+-- Fails if the stream ends before @m@ elements could be taken.
637+--
638+-- Examples: -
639+--
640+-- @
641+-- >>> :{
642+-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
643+-- where prsr = Parser.takeBetween low high Fold.toList
644+-- :}
645+--
646+-- @
647+--
648+-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
649+-- Right [1,2,3,4]
650+--
651+-- >>> takeBetween' 2 4 [1, 2]
652+-- Right [1,2]
653+--
654+-- >>> takeBetween' 2 4 [1]
655+-- Left (ParseError "takeBetween: Expecting alteast 2 elements, got 1")
656+--
657+-- >>> takeBetween' 0 0 [1, 2]
658+-- Right []
659+--
660+-- >>> takeBetween' 0 1 []
661+-- Right []
662+--
663+-- @takeBetween@ is the most general take operation, other take operations can
664+-- be defined in terms of takeBetween. For example:
665+--
666+-- >>> take n = Parser.takeBetween 0 n
667+-- >>> takeEQ n = Parser.takeBetween n n
668+-- >>> takeGE n = Parser.takeBetween n maxBound
473669--
474670-- /Pre-release/
475671--
@@ -546,9 +742,14 @@ takeBetween low high (Fold fstep finitial fextract) =
546742 | i >= low && i <= high = fmap IDone (fextract s)
547743 | otherwise = return $ IError (f i)
548744
549−-- | See 'Streamly.Internal.Data.Parser.takeEQ'.
745+-- | Stops after taking exactly @n@ input elements.
550746--
551−-- /Pre-release/
747+-- * Stops - after consuming @n@ elements.
748+-- * Fails - if the stream or the collecting fold ends before it can collect
749+-- exactly @n@ elements.
750+--
751+-- >>> Stream.parse (Parser.takeEQ 4 Fold.toList) $ Stream.fromList [1,0,1]
752+-- Left (ParseError "takeEQ: Expecting exactly 4 elements, input terminated on 3")
552753--
553754{-# INLINE takeEQ #-}
554755takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
@@ -602,7 +803,17 @@ takeEQ n (Fold fstep finitial fextract) = Parser step initial extract
602803 $ "takeEQ: Expecting exactly " ++ show cnt
603804 ++ " elements, input terminated on " ++ show i
604805
605−-- | See 'Streamly.Internal.Data.Parser.takeGE'.
806+-- | Take at least @n@ input elements, but can collect more.
807+--
808+-- * Stops - when the collecting fold stops.
809+-- * Fails - if the stream or the collecting fold ends before producing @n@
810+-- elements.
811+--
812+-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1]
813+-- Left (ParseError "takeGE: Expecting at least 4 elements, input terminated on 3")
814+--
815+-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
816+-- Right [1,0,1,0,1]
606817--
607818-- /Pre-release/
608819--
@@ -659,7 +870,19 @@ takeGE n (Fold fstep finitial fextract) = Parser step initial extract
659870-- Conditional splitting
660871-------------------------------------------------------------------------------
661872
662−-- | See 'Streamly.Internal.Data.Parser.takeWhileP'.
873+-- XXX We should perhaps use only takeWhileP and rename it to takeWhile.
874+
875+-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
876+-- input. The combinator stops when the condition fails or if the collecting
877+-- parser stops.
878+--
879+-- Other interesting parsers can be implemented in terms of this parser:
880+--
881+-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
882+-- >>> takeWhileBetween cond m n p = Parser.takeWhileP cond (Parser.takeBetween m n p)
883+--
884+-- Stops: when the condition fails or the collecting parser stops.
885+-- Fails: when the collecting parser fails.
663886--
664887-- /Pre-release/
665888--
@@ -682,12 +905,26 @@ takeWhileP predicate (Parser pstep pinitial pextract) =
682905 Partial _ _ -> error "Bug: takeWhileP: Partial in extract"
683906 Continue n s1 -> return $ Continue (n + 1) s1
684907
685−-- | See 'Streamly.Internal.Data.Parser.takeWhile'.
908+-- | Collect stream elements until an element fails the predicate. The element
909+-- on which the predicate fails is returned back to the input stream.
686910--
687−-- /Pre-release/
911+-- * Stops - when the predicate fails or the collecting fold stops.
912+-- * Fails - never.
913+--
914+-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
915+-- Right [0,0]
916+--
917+-- >>> takeWhile cond f = Parser.takeWhileP cond (Parser.fromFold f)
918+--
919+-- We can implement a @breakOn@ using 'takeWhile':
920+--
921+-- @
922+-- breakOn p = takeWhile (not p)
923+-- @
688924--
689925{-# INLINE takeWhile #-}
690926takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
927+-- takeWhile cond f = takeWhileP cond (fromFold f)
691928takeWhile predicate (Fold fstep finitial fextract) =
692929 Parser step initial extract
693930
@@ -711,12 +948,13 @@ takeWhile predicate (Fold fstep finitial fextract) =
711948
712949 extract s = fmap (Done 0) (fextract s)
713950
714−-- | See 'Streamly.Internal.Data.Parser.takeWhile1'.
951+-- | Like 'takeWhile' but takes at least one element otherwise fails.
715952--
716−-- /Pre-release/
953+-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
717954--
718955{-# INLINE takeWhile1 #-}
719956takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
957+-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
720958takeWhile1 predicate (Fold fstep finitial fextract) =
721959 Parser step initial extract
722960
@@ -753,6 +991,17 @@ takeWhile1 predicate (Fold fstep finitial fextract) =
753991 extract (Left' _) = return $ Error "takeWhile1: end of input"
754992 extract (Right' s) = fmap (Done 0) (fextract s)
755993
994+-- | Drain the input as long as the predicate succeeds, running the effects and
995+-- discarding the results.
996+--
997+-- This is also called @skipWhile@ in some parsing libraries.
998+--
999+-- >>> dropWhile p = Parser.takeWhile p Fold.drain
1000+--
1001+{-# INLINE dropWhile #-}
1002+dropWhile :: Monad m => (a -> Bool) -> Parser a m ()
1003+dropWhile p = takeWhile p FL.drain
1004+
7561005-------------------------------------------------------------------------------
7571006-- Separators
7581007-------------------------------------------------------------------------------
@@ -760,6 +1009,7 @@ takeWhile1 predicate (Fold fstep finitial fextract) =
7601009data FramedEscState s =
7611010 FrameEscInit !s | FrameEscGo !s !Int | FrameEscEsc !s !Int
7621011
1012+-- XXX We can remove Maybe from esc
7631013{-# INLINE takeFramedByGeneric #-}
7641014takeFramedByGeneric :: Monad m =>
7651015 Maybe (a -> Bool)
@@ -857,12 +1107,26 @@ takeFramedByGeneric esc begin end (Fold fstep finitial fextract) =
8571107 Nothing -> err "takeFramedByGeneric: missing closing frame"
8581108 extract (FrameEscEsc _ _) = err "takeFramedByGeneric: trailing escape"
8591109
860−-- | See 'Streamly.Internal.Data.Parser.takeEndBy'.
1110+-- | @takeEndBy cond parser@ parses a token that ends by a separator chosen by
1111+-- the supplied predicate. The separator is also taken with the token.
1112+--
1113+-- This can be combined with other parsers to implement other interesting
1114+-- parsers as follows:
1115+--
1116+-- >>> takeEndByLE cond n p = Parser.takeEndBy cond (Parser.fromFold $ Fold.take n p)
1117+-- >>> takeEndByBetween cond m n p = Parser.takeEndBy cond (Parser.takeBetween m n p)
1118+--
1119+-- >>> takeEndBy = Parser.takeEndByEsc (const False)
1120+--
1121+-- See also "Streamly.Data.Fold.takeEndBy". Unlike the fold, the collecting
1122+-- parser in the takeEndBy parser can decide whether to fail or not if the
1123+-- stream does not end with separator.
8611124--
8621125-- /Pre-release/
8631126--
8641127{-# INLINE takeEndBy #-}
8651128takeEndBy :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
1129+-- takeEndBy = takeEndByEsc (const False)
8661130takeEndBy cond (Parser pstep pinitial pextract) =
8671131
8681132 Parser step initial pextract
@@ -877,10 +1141,11 @@ takeEndBy cond (Parser pstep pinitial pextract) =
8771141 then return res
8781142 else extractStep pextract res
8791143
880−-- | See 'Streamly.Internal.Data.Parser.takeEndByEsc'.
881−--
882−-- /Pre-release/
1144+-- | Like 'takeEndBy' but the separator elements can be escaped using an
1145+-- escape char determined by the first predicate. The escape characters are
1146+-- removed.
8831147--
1148+-- /pre-release/
8841149{-# INLINE takeEndByEsc #-}
8851150takeEndByEsc :: Monad m =>
8861151 (a -> Bool) -> (a -> Bool) -> Parser a m b -> Parser a m b
@@ -909,12 +1174,18 @@ takeEndByEsc isEsc isSep (Parser pstep pinitial pextract) =
9091174 extract (Right' _) =
9101175 return $ Error "takeEndByEsc: trailing escape"
9111176
912−-- | See 'Streamly.Internal.Data.Parser.takeEndBy_'.
1177+-- | Like 'takeEndBy' but the separator is dropped.
1178+--
1179+-- See also "Streamly.Data.Fold.takeEndBy_".
9131180--
9141181-- /Pre-release/
9151182--
9161183{-# INLINE takeEndBy_ #-}
9171184takeEndBy_ :: (a -> Bool) -> Parser a m b -> Parser a m b
1185+{-
1186+takeEndBy_ isEnd p =
1187+ takeFramedByGeneric Nothing Nothing (Just isEnd) (toFold p)
1188+-}
9181189takeEndBy_ cond (Parser pstep pinitial pextract) =
9191190
9201191 Parser step pinitial pextract
@@ -926,11 +1197,39 @@ takeEndBy_ cond (Parser pstep pinitial pextract) =
9261197 then pextract s
9271198 else pstep s a
9281199
929−-- | See 'Streamly.Internal.Data.Parser.takeStartBy'.
1200+-- | Take either the separator or the token. Separator is a Left value and
1201+-- token is Right value.
1202+--
1203+-- /Unimplemented/
1204+{-# INLINE takeEitherSepBy #-}
1205+takeEitherSepBy :: -- Monad m =>
1206+ (a -> Bool) -> Fold m (Either a b) c -> Parser a m c
1207+takeEitherSepBy _cond = undefined -- D.toParserK . D.takeEitherSepBy cond
1208+
1209+-- | Parse a token that starts with an element chosen by the predicate. The
1210+-- parser fails if the input does not start with the selected element.
1211+--
1212+-- * Stops - when the predicate succeeds in non-leading position.
1213+-- * Fails - when the predicate fails in the leading position.
1214+--
1215+-- >>> splitWithPrefix p f = Stream.parseMany (Parser.takeStartBy p f)
1216+--
1217+-- Examples: -
1218+--
1219+-- >>> p = Parser.takeStartBy (== ',') Fold.toList
1220+-- >>> leadingComma = Stream.parse p . Stream.fromList
1221+-- >>> leadingComma "a,b"
1222+-- Left (ParseError "takeStartBy: missing frame start")
1223+-- ...
1224+-- >>> leadingComma ",,"
1225+-- Right ","
1226+-- >>> leadingComma ",a,b"
1227+-- Right ",a"
1228+-- >>> leadingComma ""
1229+-- Right ""
9301230--
9311231-- /Pre-release/
9321232--
933−
9341233{-# INLINE takeStartBy #-}
9351234takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
9361235takeStartBy cond (Fold fstep finitial fextract) =
@@ -966,9 +1265,40 @@ takeStartBy cond (Fold fstep finitial fextract) =
9661265 extract (Left' s) = fmap (Done 0) $ fextract s
9671266 extract (Right' s) = fmap (Done 0) $ fextract s
9681267
1268+-- | Like 'takeStartBy' but drops the separator.
1269+--
1270+-- >>> takeStartBy_ isBegin = Parser.takeFramedByGeneric Nothing (Just isBegin) Nothing
1271+--
1272+{-# INLINE takeStartBy_ #-}
1273+takeStartBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1274+takeStartBy_ isBegin = takeFramedByGeneric Nothing (Just isBegin) Nothing
1275+
1276+-- | @takeFramedByEsc_ isEsc isBegin isEnd fold@ parses a token framed using a
1277+-- begin and end predicate, and an escape character. The frame begin and end
1278+-- characters lose their special meaning if preceded by the escape character.
1279+--
1280+-- Nested frames are allowed if begin and end markers are different, nested
1281+-- frames must be balanced unless escaped, nested frame markers are emitted as
1282+-- it is.
1283+--
1284+-- For example,
1285+--
1286+-- >>> p = Parser.takeFramedByEsc_ (== '\\') (== '{') (== '}') Fold.toList
1287+-- >>> Stream.parse p $ Stream.fromList "{hello}"
1288+-- Right "hello"
1289+-- >>> Stream.parse p $ Stream.fromList "{hello {world}}"
1290+-- Right "hello {world}"
1291+-- >>> Stream.parse p $ Stream.fromList "{hello \\{world}"
1292+-- Right "hello {world"
1293+-- >>> Stream.parse p $ Stream.fromList "{hello {world}"
1294+-- Left (ParseError "takeFramedByEsc_: missing frame end")
1295+--
1296+-- /Pre-release/
9691297{-# INLINE takeFramedByEsc_ #-}
9701298takeFramedByEsc_ :: Monad m =>
9711299 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1300+-- takeFramedByEsc_ isEsc isEnd p =
1301+-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
9721302takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial fextract) =
9731303
9741304 Parser step initial extract
@@ -1017,9 +1347,16 @@ takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial fextract) =
10171347
10181348data FramedState s = FrameInit !s | FrameGo !s Int
10191349
1350+-- | @takeFramedBy_ isBegin isEnd fold@ parses a token framed by a begin and an
1351+-- end predicate.
1352+--
1353+-- >>> takeFramedBy_ = Parser.takeFramedByEsc_ (const False)
1354+--
10201355{-# INLINE takeFramedBy_ #-}
10211356takeFramedBy_ :: Monad m =>
10221357 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1358+-- takeFramedBy_ isBegin isEnd =
1359+-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
10231360takeFramedBy_ isBegin isEnd (Fold fstep finitial fextract) =
10241361
10251362 Parser step initial extract
@@ -1064,8 +1401,24 @@ takeFramedBy_ isBegin isEnd (Fold fstep finitial fextract) =
10641401
10651402data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
10661403
1067−-- | See 'Streamly.Internal.Data.Parser.wordBy'.
1404+-- Note we can also get words using something like:
1405+-- sepBy FL.toList (takeWhile (not . p) Fold.toList) (dropWhile p)
1406+--
1407+-- But that won't be as efficient and ergonomic.
1408+
1409+-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
1410+-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
1411+-- @["a","b"]@. In other words, its like parsing words from whitespace
1412+-- separated text.
10681413--
1414+-- * Stops - when it finds a word separator after a non-word element
1415+-- * Fails - never.
1416+--
1417+-- >>> wordBy = Parser.wordFramedBy (const False) (const False) (const False)
1418+--
1419+-- @
1420+-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
1421+-- @
10691422--
10701423{-# INLINE wordBy #-}
10711424wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
@@ -1114,7 +1467,24 @@ data WordFramedState s b =
11141467 | WordFramedEsc !s !Int
11151468 | WordFramedSkipPost !b
11161469
1117−-- | See 'Streamly.Internal.Data.Parser.wordFramedBy'
1470+-- | Like 'wordBy' but treats anything inside a pair of quotes as a single
1471+-- word, the quotes can be escaped by an escape character. Recursive quotes
1472+-- are possible if quote begin and end characters are different, quotes must be
1473+-- balanced. Outermost quotes are stripped.
1474+--
1475+-- >>> braces = Parser.wordFramedBy (== '\\') (== '{') (== '}') isSpace Fold.toList
1476+-- >>> Stream.parse braces $ Stream.fromList "{ab} cd"
1477+-- Right "ab"
1478+-- >>> Stream.parse braces $ Stream.fromList "{ab}{cd}"
1479+-- Right "abcd"
1480+-- >>> Stream.parse braces $ Stream.fromList "a{b} cd"
1481+-- Right "ab"
1482+-- >>> Stream.parse braces $ Stream.fromList "a{{b}} cd"
1483+-- Right "a{b}"
1484+--
1485+-- >>> quotes = Parser.wordFramedBy (== '\\') (== '"') (== '"') isSpace Fold.toList
1486+-- >>> Stream.parse quotes $ Stream.fromList "\"a\"\"b\""
1487+-- Right "ab"
11181488--
11191489{-# INLINE wordFramedBy #-}
11201490wordFramedBy :: Monad m =>
@@ -1206,6 +1576,26 @@ data WordQuotedState s b a =
12061576 | WordQuotedEsc !s !Int a
12071577 | WordQuotedSkipPost !b
12081578
1579+-- | Like 'wordFramedBy' but the closing quote is determined by the opening
1580+-- quote. The first quote begin starts a quote that is closed by its
1581+-- corresponding closing quote.
1582+--
1583+-- 'wordFramedBy' and 'wordQuotedBy' both allow multiple quote characters based
1584+-- on the predicates but 'wordQuotedBy' always fixes the quote at the first
1585+-- occurrence and then it is closed only by the corresponding closing quote.
1586+-- Therefore, other quoting characters can be embedded inside it as normal
1587+-- characters. On the other hand, 'wordFramedBy' would close the quote as soon
1588+-- as it encounters any of the closing quotes.
1589+--
1590+-- >>> q = (`elem` ['"', '\''])
1591+-- >>> p kQ = Parser.wordQuotedBy kQ (== '\\') q q id isSpace Fold.toList
1592+--
1593+-- >>> Stream.parse (p False) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
1594+-- Right "ab'c;d\"ef"
1595+--
1596+-- >>> Stream.parse (p True) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
1597+-- Right "a\"b'c\";'d\"e'f"
1598+--
12091599{-# INLINE wordQuotedBy #-}
12101600wordQuotedBy :: (Monad m, Eq a) =>
12111601 Bool -- ^ keep the quotes in the output
@@ -1313,7 +1703,31 @@ data GroupByState a s
13131703 = GroupByInit !s
13141704 | GroupByGrouping !a !s
13151705
1316−-- | See 'Streamly.Internal.Data.Parser.groupBy'.
1706+-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
1707+-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
1708+-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
1709+-- then @c@ is also assigned to the same group and so on. When the comparison
1710+-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
1711+-- the result of the fold is the result of the parser.
1712+--
1713+-- * Stops - when the comparison fails.
1714+-- * Fails - never.
1715+--
1716+-- >>> :{
1717+-- runGroupsBy eq =
1718+-- Stream.fold Fold.toList
1719+-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
1720+-- . Stream.fromList
1721+-- :}
1722+--
1723+-- >>> runGroupsBy (<) []
1724+-- []
1725+--
1726+-- >>> runGroupsBy (<) [1]
1727+-- [Right [1]]
1728+--
1729+-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
1730+-- [Right [3,5,4],Right [1,2],Right [0]]
13171731--
13181732{-# INLINE groupBy #-}
13191733groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
@@ -1345,7 +1759,35 @@ groupBy eq (Fold fstep finitial fextract) = Parser step initial extract
13451759 extract (GroupByInit s) = fmap (Done 0) $ fextract s
13461760 extract (GroupByGrouping _ s) = fmap (Done 0) $ fextract s
13471761
1348−-- | See 'Streamly.Internal.Data.Parser.groupByRolling'.
1762+-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
1763+-- successive elements in the input stream. Assuming the input stream
1764+-- is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
1765+-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
1766+-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
1767+-- then @c@ is also assigned to the same group and so on. When the comparison
1768+-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
1769+-- the result of the fold is the result of the parser.
1770+--
1771+-- * Stops - when the comparison fails.
1772+-- * Fails - never.
1773+--
1774+-- >>> :{
1775+-- runGroupsByRolling eq =
1776+-- Stream.fold Fold.toList
1777+-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
1778+-- . Stream.fromList
1779+-- :}
1780+--
1781+-- >>> runGroupsByRolling (<) []
1782+-- []
1783+--
1784+-- >>> runGroupsByRolling (<) [1]
1785+-- [Right [1]]
1786+--
1787+-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
1788+-- [Right [3,5],Right [4],Right [1,2],Right [0]]
1789+--
1790+-- /Pre-release/
13491791--
13501792{-# INLINE groupByRolling #-}
13511793groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
@@ -1384,6 +1826,16 @@ data GroupByStatePair a s1 s2
13841826 | GroupByGroupingPairL !a !s1 !s2
13851827 | GroupByGroupingPairR !a !s1 !s2
13861828
1829+-- | Like 'groupByRolling', but if the predicate is 'True' then collects using
1830+-- the first fold as long as the predicate holds 'True', if the predicate is
1831+-- 'False' collects using the second fold as long as it remains 'False'.
1832+-- Returns 'Left' for the first case and 'Right' for the second case.
1833+--
1834+-- For example, if we want to detect sorted sequences in a stream, both
1835+-- ascending and descending cases we can use 'groupByRollingEither (<=)
1836+-- Fold.toList Fold.toList'.
1837+--
1838+-- /Pre-release/
13871839{-# INLINE groupByRollingEither #-}
13881840groupByRollingEither :: Monad m =>
13891841 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
@@ -1468,13 +1920,26 @@ groupByRollingEither
14681920-- XXX use an Unfold instead of a list?
14691921-- XXX custom combinators for matching list, array and stream?
14701922-- XXX rename to listBy?
1923+
1924+-- | Match the given sequence of elements using the given comparison function.
1925+-- Returns the original sequence if successful.
14711926--
1472−-- | See 'Streamly.Internal.Data.Parser.streamEqBy'.
1927+-- Definition:
14731928--
1474−-- /Pre-release/
1929+-- >>> listEqBy cmp xs = Parser.streamEqBy cmp (Stream.fromList xs) *> Parser.fromPure xs
1930+--
1931+-- Examples:
1932+--
1933+-- >>> Stream.parse (Parser.listEqBy (==) "string") $ Stream.fromList "string"
1934+-- Right "string"
1935+--
1936+-- >>> Stream.parse (Parser.listEqBy (==) "mismatch") $ Stream.fromList "match"
1937+-- Left (ParseError "streamEqBy: mismtach occurred")
14751938--
14761939{-# INLINE listEqBy #-}
14771940listEqBy :: Monad m => (a -> a -> Bool) -> [a] -> Parser a m [a]
1941+listEqBy cmp xs = streamEqBy cmp (D.fromList xs) *> fromPure xs
1942+{-
14781943listEqBy cmp str = Parser step initial extract
14791944
14801945 where
@@ -1501,8 +1966,13 @@ listEqBy cmp str = Parser step initial extract
15011966 $ Error
15021967 $ "listEqBy: end of input, yet to match "
15031968 ++ show (length xs) ++ " elements"
1969+-}
15041970
1505−-- | Like 'listEqBy' but uses a stream instead of a list
1971+-- | Like 'listEqBy' but uses a stream instead of a list and does not return
1972+-- the stream.
1973+--
1974+-- See also: "Streamly.Data.Stream.streamEqBy"
1975+--
15061976{-# INLINE streamEqBy #-}
15071977streamEqBy :: Monad m => (a -> a -> Bool) -> D.Stream m a -> Parser a m ()
15081978streamEqBy cmp (D.Stream sstep state) = Parser step initial extract
@@ -1540,6 +2010,39 @@ streamEqBy cmp (D.Stream sstep state) = Parser step initial extract
15402010
15412011 extract _ = return $ Error "streamEqBy: end of input"
15422012
2013+-- Rename to "list".
2014+-- | Match the input sequence with the supplied list and return it if
2015+-- successful.
2016+--
2017+-- >>> listEq = Parser.listEqBy (==)
2018+--
2019+{-# INLINE listEq #-}
2020+listEq :: (Monad m, Eq a) => [a] -> Parser a m [a]
2021+listEq = listEqBy (==)
2022+
2023+-- | Match if the input stream is a subsequence of the argument stream i.e. all
2024+-- the elements of the input stream occur, in order, in the argument stream.
2025+-- The elements do not have to occur consecutively. A sequence is considered a
2026+-- subsequence of itself.
2027+{-# INLINE subsequenceBy #-}
2028+subsequenceBy :: -- Monad m =>
2029+ (a -> a -> Bool) -> Stream m a -> Parser a m ()
2030+subsequenceBy = undefined
2031+
2032+{-
2033+-- Should go in Data.Parser.Regex in streamly package so that it can depend on
2034+-- regex backends.
2035+{-# INLINE regexPosix #-}
2036+regexPosix :: -- Monad m =>
2037+ Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
2038+regexPosix = undefined
2039+
2040+{-# INLINE regexPCRE #-}
2041+regexPCRE :: -- Monad m =>
2042+ Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
2043+regexPCRE = undefined
2044+-}
2045+
15432046-------------------------------------------------------------------------------
15442047-- Transformations on input
15452048-------------------------------------------------------------------------------
@@ -1548,7 +2051,7 @@ streamEqBy cmp (D.Stream sstep state) = Parser step initial extract
15482051-- parser can always return a Continue in initial when we feed the fold's
15492052-- initial result to it. We can work this around for postscan by introducing an
15502053-- initial state and calling "initial" only on the first input.
1551−--
2054+
15522055-- | Stateful scan on the input of a parser using a Fold.
15532056--
15542057-- /Unimplemented/
@@ -1709,7 +2212,16 @@ spanByRolling eq f1 f2 =
17092212-- nested parsers
17102213-------------------------------------------------------------------------------
17112214
1712−-- | See 'Streamly.Internal.Data.Parser.takeP'.
2215+-- | Takes at-most @n@ input elements.
2216+--
2217+-- * Stops - when the collecting parser stops.
2218+-- * Fails - when the collecting parser fails.
2219+--
2220+-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
2221+-- Right [1,2]
2222+--
2223+-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
2224+-- Left (ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4")
17132225--
17142226-- /Internal/
17152227{-# INLINE takeP #-}
@@ -1783,9 +2295,7 @@ takeP lim (Parser pstep pinitial pextract) = Parser step initial extract
17832295 Error err -> IError err
17842296 _ -> error "Bug: takeP invalid state in initial"
17852297
1786−-- | See 'Streamly.Internal.Data.Parser.lookahead'.
1787−--
1788−-- /Pre-release/
2298+-- | Run a parser without consuming the input.
17892299--
17902300{-# INLINE lookAhead #-}
17912301lookAhead :: Monad m => Parser a m b -> Parser a m b
@@ -1822,14 +2332,32 @@ lookAhead (Parser step1 initial1 _) = Parser step initial extract
18222332-------------------------------------------------------------------------------
18232333-- Interleaving
18242334-------------------------------------------------------------------------------
2335+--
2336+-- To deinterleave we can chain two parsers one behind the other. The input is
2337+-- given to the first parser and the input definitively rejected by the first
2338+-- parser is given to the second parser.
2339+--
2340+-- We can either have the parsers themselves buffer the input or use the shared
2341+-- global buffer to hold it until none of the parsers need it. When the first
2342+-- parser returns Skip (i.e. rewind) we let the second parser consume the
2343+-- rejected input and when it is done we move the cursor forward to the first
2344+-- parser again. This will require a "move forward" command as well.
2345+--
2346+-- To implement grep we can use three parsers, one to find the pattern, one
2347+-- to store the context behind the pattern and one to store the context in
2348+-- front of the pattern. When a match occurs we need to emit the accumulator of
2349+-- all the three parsers. One parser can count the line numbers to provide the
2350+-- line number info.
18252351
18262352data DeintercalateState fs sp ss =
18272353 DeintercalateL !fs !sp
18282354 | DeintercalateR !fs !ss !Bool
18292355
1830−-- | See 'Streamly.Internal.Data.Parser.deintercalate'.
1831−--
1832−-- /Internal/
2356+-- XXX rename this to intercalate
2357+
2358+-- | Apply two parsers alternately to an input stream. The input stream is
2359+-- considered an interleaving of two patterns. The two parsers represent the
2360+-- two patterns.
18332361--
18342362{-# INLINE deintercalate #-}
18352363deintercalate :: Monad m =>
@@ -1926,8 +2454,13 @@ data SepByState fs sp ss =
19262454 SepByInit !fs !sp
19272455 | SepBySeparator !fs !ss !Bool
19282456
1929−-- This is a special case of deintercalate and can be easily implemented in
1930−-- terms of deintercalate.
2457+-- | Run the content parser first, when it is done, the separator parser is
2458+-- run, when it is done content parser is run again and so on. If none of the
2459+-- parsers consumes an input then parser returns a failure.
2460+--
2461+-- >>> sepBy p1 p2 sink = Parser.deintercalate p1 p2 (Fold.catLefts sink)
2462+-- >>> sepBy content sep sink = Parser.sepBy1 content sep sink <|> return mempty
2463+--
19312464{-# INLINE sepBy #-}
19322465sepBy :: Monad m =>
19332466 Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
@@ -2000,11 +2533,49 @@ sepBy
20002533
20012534 extract (SepBySeparator fs _ _) = fmap (Done 0) $ fextract fs
20022535
2536+-- XXX This can be implemented using refold, parse one and then continue
2537+-- collecting the rest in that.
2538+
2539+-- | Parse items separated by a separator parsed by the supplied parser. At
2540+-- least one item must be present for the parser to succeed.
2541+--
2542+-- Note that this can go in infinite loop if both the parsers fail on some
2543+-- input. Detection of that would make the implementation more complex.
2544+--
2545+{-# INLINE sepBy1 #-}
2546+sepBy1 :: Monad m =>
2547+ Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
2548+sepBy1 p sep sink = do
2549+ x <- p
2550+ f <- fromEffect $ FL.reduce sink
2551+ f1 <- fromEffect $ FL.snoc f x
2552+ many (sep >> p) f1
2553+
2554+-------------------------------------------------------------------------------
2555+-- Interleaving a collection of parsers
2556+-------------------------------------------------------------------------------
2557+--
2558+-- | Apply a collection of parsers to an input stream in a round robin fashion.
2559+-- Each parser is applied until it stops and then we repeat starting with the
2560+-- the first parser again.
2561+--
2562+-- /Unimplemented/
2563+--
2564+{-# INLINE roundRobin #-}
2565+roundRobin :: -- (Foldable t, Monad m) =>
2566+ t (Parser a m b) -> Fold m b c -> Parser a m c
2567+roundRobin _ps _f = undefined
2568+
20032569-------------------------------------------------------------------------------
20042570-- Sequential Collection
20052571-------------------------------------------------------------------------------
2572+
2573+-- | @sequence f p@ collects sequential parses of parsers in a
2574+-- serial stream @p@ using the fold @f@. Fails if the input ends or any
2575+-- of the parsers fail.
2576+--
2577+-- /Pre-release/
20062578--
2007−-- | See 'Streamly.Internal.Data.Parser.sequence'.
20082579{-# INLINE sequence #-}
20092580sequence :: Monad m =>
20102581 D.Stream m (Parser a m b) -> Fold m b c -> Parser a m c
@@ -2089,7 +2660,10 @@ sequence (D.Stream sstep sstate) (Fold fstep finitial fextract) =
20892660-------------------------------------------------------------------------------
20902661
20912662{-
2092−-- | See 'Streamly.Internal.Data.Parser.choice'.
2663+-- | @choice parsers@ applies the @parsers@ in order and returns the first
2664+-- successful parse.
2665+--
2666+-- This is same as 'asum' but more efficient.
20932667--
20942668-- /Broken/
20952669--
@@ -2102,23 +2676,45 @@ choice = foldl1 shortest
21022676-- Sequential Repetition
21032677-------------------------------------------------------------------------------
21042678
2679+-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
2680+-- results. Parsing stops or fails if the collecting parser stops or fails.
2681+--
2682+-- /Unimplemented/
2683+--
21052684{-# INLINE manyP #-}
21062685manyP :: -- MonadCatch m =>
21072686 Parser a m b -> Parser b m c -> Parser a m c
21082687manyP _p _f = undefined
21092688
2110−-- | See 'Streamly.Internal.Data.Parser.many'.
2689+-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
2690+-- input stream and push the parse results to a downstream fold.
21112691--
2112−-- /Pre-release/
2692+-- Stops: when the downstream fold stops or the parser fails.
2693+-- Fails: never, produces zero or more results.
2694+--
2695+-- >>> many = Parser.countBetween 0 maxBound
2696+--
2697+-- Compare with 'Control.Applicative.many'.
21132698--
21142699{-# INLINE many #-}
21152700many :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
21162701many = splitMany
21172702-- many = countBetween 0 maxBound
21182703
2119−-- | See 'Streamly.Internal.Data.Parser.some'.
2704+-- Note: many1 would perhaps be a better name for this and consistent with
2705+-- other names like takeWhile1. But we retain the name "some" for
2706+-- compatibility.
2707+
2708+-- | Collect one or more parses. Apply the supplied parser repeatedly on the
2709+-- input stream and push the parse results to a downstream fold.
21202710--
2121−-- /Pre-release/
2711+-- Stops: when the downstream fold stops or the parser fails.
2712+-- Fails: if it stops without producing a single result.
2713+--
2714+-- >>> some p f = Parser.manyP p (Parser.takeGE 1 f)
2715+-- >>> some = Parser.countBetween 1 maxBound
2716+--
2717+-- Compare with 'Control.Applicative.some'.
21222718--
21232719{-# INLINE some #-}
21242720some :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
@@ -2126,7 +2722,11 @@ some = splitSome
21262722-- some p f = manyP p (takeGE 1 f)
21272723-- some = countBetween 1 maxBound
21282724
2129−-- | See 'Streamly.Internal.Data.Parser.countBetween'.
2725+-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
2726+-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
2727+-- the input ends or the parser fails before @m@ results are collected.
2728+--
2729+-- >>> countBetween m n p f = Parser.manyP p (Parser.takeBetween m n f)
21302730--
21312731-- /Unimplemented/
21322732--
@@ -2136,7 +2736,12 @@ countBetween :: -- MonadCatch m =>
21362736countBetween _m _n _p = undefined
21372737-- countBetween m n p f = manyP p (takeBetween m n f)
21382738
2139−-- | See 'Streamly.Internal.Data.Parser.count'.
2739+-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
2740+-- the fold @f@. Fails if the input ends or the parser fails before @n@
2741+-- results are collected.
2742+--
2743+-- >>> count n = Parser.countBetween n n
2744+-- >>> count n p f = Parser.manyP p (Parser.takeEQ n f)
21402745--
21412746-- /Unimplemented/
21422747--
@@ -2146,13 +2751,34 @@ count :: -- MonadCatch m =>
21462751count n = countBetween n n
21472752-- count n p f = manyP p (takeEQ n f)
21482753
2754+-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
2755+-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
2756+--
2757+-- We can implemnent parsers like the following using 'manyTillP':
2758+--
2759+-- @
2760+-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
2761+-- @
2762+--
2763+-- /Unimplemented/
2764+--
2765+{-# INLINE manyTillP #-}
2766+manyTillP :: -- Monad m =>
2767+ Parser a m b -> Parser a m x -> Parser b m c -> Parser a m c
2768+manyTillP _p1 _p2 _f = undefined
2769+ -- D.toParserK $ D.manyTillP (D.fromParserK p1) (D.fromParserK p2) f
2770+
21492771data ManyTillState fs sr sl
21502772 = ManyTillR Int fs sr
21512773 | ManyTillL Int fs sl
21522774
2153−-- | See 'Streamly.Internal.Data.Parser.manyTill'.
2775+-- | @manyTill chunking test f@ tries the parser @test@ on the input, if @test@
2776+-- fails it backtracks and tries @chunking@, after @chunking@ succeeds @test@ is
2777+-- tried again and so on. The parser stops when @test@ succeeds. The output of
2778+-- @test@ is discarded and the output of @chunking@ is accumulated by the
2779+-- supplied fold. The parser fails if @chunking@ fails.
21542780--
2155−-- /Pre-release/
2781+-- Stops when the fold @f@ stops.
21562782--
21572783{-# INLINE manyTill #-}
21582784manyTill :: Monad m
@@ -2245,3 +2871,53 @@ manyTill (Parser stepL initialL extractL)
22452871 return $ Continue n (ManyTillL 0 fs s)
22462872 Partial _ _ -> error "Partial in extract"
22472873 extract (ManyTillR _ fs _) = fmap (Done 0) $ fextract fs
2874+
2875+-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
2876+-- collects the output in the supplied fold. If the the parser @collect@ fails,
2877+-- parser @recover@ is run until it stops and then we start repeating the
2878+-- parser @collect@ again. The parser fails if the recovery parser fails.
2879+--
2880+-- For example, this can be used to find a key frame in a video stream after an
2881+-- error.
2882+--
2883+-- /Unimplemented/
2884+--
2885+{-# INLINE manyThen #-}
2886+manyThen :: -- (Foldable t, Monad m) =>
2887+ Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
2888+manyThen _parser _recover _f = undefined
2889+
2890+-------------------------------------------------------------------------------
2891+-- Repeated Alternatives
2892+-------------------------------------------------------------------------------
2893+
2894+-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
2895+-- fails the input consumed till now is dropped and the new instance is tried
2896+-- on the fresh input.
2897+--
2898+-- /Unimplemented/
2899+--
2900+{-# INLINE retryMaxTotal #-}
2901+retryMaxTotal :: -- (Monad m) =>
2902+ Int -> Parser a m b -> Fold m b c -> Parser a m c
2903+retryMaxTotal _n _p _f = undefined
2904+
2905+-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
2906+--
2907+-- /Unimplemented/
2908+--
2909+{-# INLINE retryMaxSuccessive #-}
2910+retryMaxSuccessive :: -- (Monad m) =>
2911+ Int -> Parser a m b -> Fold m b c -> Parser a m c
2912+retryMaxSuccessive _n _p _f = undefined
2913+
2914+-- | Keep trying a parser until it succeeds. When the parser fails the input
2915+-- consumed till now is dropped and the new instance is tried on the fresh
2916+-- input.
2917+--
2918+-- /Unimplemented/
2919+--
2920+{-# INLINE retry #-}
2921+retry :: -- (Monad m) =>
2922+ Parser a m b -> Parser a m b
2923+retry _p = undefined
core/src/Streamly/Internal/Data/Parser/ParserD/Type.hs+103−18
@@ -214,6 +214,7 @@ import Fusion.Plugin.Types (Fuse(..))
214214import Streamly.Internal.Data.Fold.Type (Fold(..), toList)
215215import Streamly.Internal.Data.Tuple.Strict (Tuple3'(..))
216216
217+import qualified Control.Monad.Fail as Fail
217218import qualified Streamly.Internal.Data.Fold.Type as FL
218219import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
219220
@@ -224,6 +225,7 @@ import Prelude hiding (concatMap, filter)
224225-- >>> import Control.Applicative ((<|>))
225226-- >>> import Data.Bifunctor (second)
226227-- >>> import Prelude hiding (concatMap)
228+-- >>> import qualified Streamly.Data.Fold as Fold
227229-- >>> import qualified Streamly.Data.Stream as Stream
228230-- >>> import qualified Streamly.Internal.Data.Stream as Stream (parse)
229231-- >>> import qualified Streamly.Internal.Data.Parser as Parser
@@ -625,9 +627,9 @@ fromParserK parser = Parser step initial extract
625627-- Mapping on the output
626628------------------------------------------------------------------------------
627629
628−-- | Map a monadic function on the output of a parser.
630+-- | @rmapM f parser@ maps the monadic function @f@ on the output of the parser.
629631--
630−-- /Pre-release/
632+-- >>> rmap = fmap
631633{-# INLINE rmapM #-}
632634rmapM :: Monad m => (b -> m c) -> Parser a m b -> Parser a m c
633635rmapM f (Parser step initial extract) =
@@ -644,17 +646,14 @@ rmapM f (Parser step initial extract) =
644646 IError err -> return $ IError err
645647 step1 s a = step s a >>= mapMStep f
646648
647−-- | See 'Streamly.Internal.Data.Parser.fromPure'.
648−--
649−-- /Pre-release/
649+-- | A parser that always yields a pure value without consuming any input.
650650--
651651{-# INLINE_NORMAL fromPure #-}
652652fromPure :: Monad m => b -> Parser a m b
653653fromPure b = Parser undefined (pure $ IDone b) undefined
654654
655−-- | See 'Streamly.Internal.Data.Parser.fromEffect'.
656−--
657−-- /Pre-release/
655+-- | A parser that always yields the result of an effectful action without
656+-- consuming any input.
658657--
659658{-# INLINE fromEffect #-}
660659fromEffect :: Monad m => m b -> Parser a m b
@@ -667,14 +666,52 @@ fromEffect b = Parser undefined (IDone <$> b) undefined
667666{-# ANN type SeqParseState Fuse #-}
668667data SeqParseState sl f sr = SeqParseL sl | SeqParseR f sr
669668
670−-- | See 'Streamly.Internal.Data.Parser.splitWith'.
671−--
672669-- Note: this implementation of splitWith is fast because of stream fusion but
673670-- has quadratic time complexity, because each composition adds a new branch
674671-- that each subsequent parse's input element has to go through, therefore, it
675672-- cannot scale to a large number of compositions. After around 100
676673-- compositions the performance starts dipping rapidly beyond a CPS style
677674-- unfused implementation.
675+
676+-- | Sequential parser application. Apply two parsers sequentially to an input
677+-- stream. The input is provided to the first parser, when it is done the
678+-- remaining input is provided to the second parser. If both the parsers
679+-- succeed their outputs are combined using the supplied function. The
680+-- operation fails if any of the parsers fail.
681+--
682+-- Note: This is a parsing dual of appending streams using
683+-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and zips
684+-- the results.
685+--
686+-- This implementation is strict in the second argument, therefore, the
687+-- following will fail:
688+--
689+-- >>> Stream.parse (Parser.splitWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
690+-- *** Exception: Prelude.undefined
691+-- ...
692+--
693+-- Compare with 'Applicative' instance method '<*>'. This implementation allows
694+-- stream fusion but has quadratic complexity. This can fuse with other
695+-- operations and can be faster than 'Applicative' instance for small number
696+-- (less than 8) of compositions.
697+--
698+-- Many combinators can be expressed using @splitWith@ and other parser
699+-- primitives. Some common idioms are described below,
700+--
701+-- @
702+-- span :: (a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
703+-- span pred f1 f2 = splitWith (,) ('takeWhile' pred f1) ('fromFold' f2)
704+-- @
705+--
706+-- @
707+-- spanBy :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
708+-- spanBy eq f1 f2 = splitWith (,) ('groupBy' eq f1) ('fromFold' f2)
709+-- @
710+--
711+-- @
712+-- spanByRolling :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
713+-- spanByRolling eq f1 f2 = splitWith (,) ('groupByRolling' eq f1) ('fromFold' f2)
714+-- @
678715--
679716-- /Pre-release/
680717--
@@ -824,7 +861,24 @@ noErrorUnsafeSplitWith func (Parser stepL initialL extractL)
824861data SeqAState sl sr = SeqAL sl | SeqAR sr
825862
826863-- This turns out to be slightly faster than splitWith
827−-- | See 'Streamly.Internal.Data.Parser.split_'.
864+
865+-- | Sequential parser application ignoring the output of the first parser.
866+-- Apply two parsers sequentially to an input stream. The input is provided to
867+-- the first parser, when it is done the remaining input is provided to the
868+-- second parser. The output of the parser is the output of the second parser.
869+-- The operation fails if any of the parsers fail.
870+--
871+-- This implementation is strict in the second argument, therefore, the
872+-- following will fail:
873+--
874+-- >>> Stream.parse (Parser.split_ (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
875+-- *** Exception: Prelude.undefined
876+-- ...
877+--
878+-- Compare with 'Applicative' instance method '*>'. This implementation allows
879+-- stream fusion but has quadratic complexity. This can fuse with other
880+-- operations, and can be faster than 'Applicative' instance for small
881+-- number (less than 8) of compositions.
828882--
829883-- /Pre-release/
830884--
@@ -962,7 +1016,20 @@ data AltParseState sl sr = AltParseL Int sl | AltParseR sr
9621016-- each subsequent alternative's input element has to go through, therefore, it
9631017-- cannot scale to a large number of compositions
9641018
965−-- | See 'Streamly.Internal.Data.Parser.alt'.
1019+-- | Sequential alternative. Apply the input to the first parser and return the
1020+-- result if the parser succeeds. If the first parser fails then backtrack and
1021+-- apply the same input to the second parser and return the result.
1022+--
1023+-- Note: This implementation is not lazy in the second argument. The following
1024+-- will fail:
1025+--
1026+-- >> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
1027+-- *** Exception: Prelude.undefined
1028+--
1029+-- Compare with ParserK 'Alternative' instance method '<|>'. This
1030+-- implementation allows stream fusion but has quadratic complexity. This can
1031+-- fuse with other operations and can be much faster than 'Alternative'
1032+-- instance for small number (less than 8) of alternatives.
9661033--
9671034-- /Time Complexity:/ O(n^2) where n is the number of compositions.
9681035--
@@ -1263,15 +1330,15 @@ splitSome (Parser step1 initial1 extract1) (Fold fstep finitial fextract) =
12631330 assertM(n == cnt)
12641331 return (Continue n (Tuple3' s1 0 (Right fs)))
12651332
1266−-- | See 'Streamly.Internal.Data.Parser.die'.
1267−--
1268−-- /Pre-release/
1333+-- | A parser that always fails with an error message without consuming
1334+-- any input.
12691335--
12701336{-# INLINE_NORMAL die #-}
12711337die :: Monad m => String -> Parser a m b
12721338die err = Parser undefined (pure (IError err)) undefined
12731339
1274−-- | See 'Streamly.Internal.Data.Parser.dieM'.
1340+-- | A parser that always fails with an effectful error message and without
1341+-- consuming any input.
12751342--
12761343-- /Pre-release/
12771344--
@@ -1292,7 +1359,7 @@ dieM err = Parser undefined (IError <$> err) undefined
12921359-- Note: The implementation of '<|>' is not lazy in the second
12931360-- argument. The following code will fail:
12941361--
1295−-- >>> Stream.parse (ParserD.toParserK $ ParserD.satisfy (> 0) <|> undefined) $ Stream.fromList [1..10]
1362+-- >>> Stream.parse (ParserD.satisfy (> 0) <|> undefined) $ Stream.fromList [1..10]
12961363-- *** Exception: Prelude.undefined
12971364-- ...
12981365--
@@ -1314,7 +1381,7 @@ data ConcatParseState sl m a b =
13141381 ConcatParseL sl
13151382 | forall s. ConcatParseR (s -> a -> m (Step s b)) s (s -> m (Step s b))
13161383
1317−-- | See 'Streamly.Internal.Data.Parser.concatMap'.
1384+-- | Map a 'Parser' returning function on the result of a 'Parser'.
13181385--
13191386-- /Pre-release/
13201387--
@@ -1469,6 +1536,10 @@ instance Monad m => Monad (Parser a m) where
14691536 {-# INLINE (>>) #-}
14701537 (>>) = (*>)
14711538
1539+instance Monad m => Fail.MonadFail (Parser a m) where
1540+ {-# INLINE fail #-}
1541+ fail = die
1542+
14721543-- | See documentation of 'Streamly.Internal.Data.Parser.ParserK.Type.Parser'.
14731544--
14741545instance Monad m => MonadPlus (Parser a m) where
@@ -1486,6 +1557,13 @@ instance (Monad m, MonadIO m) => MonadIO (Parser a m) where
14861557-- Mapping on input
14871558------------------------------------------------------------------------------
14881559
1560+-- | @lmap f parser@ maps the function @f@ on the input of the parser.
1561+--
1562+-- >>> Stream.parse (Parser.lmap (\x -> x * x) (Parser.fromFold Fold.sum)) (Stream.enumerateFromTo 1 100)
1563+-- Right 338350
1564+--
1565+-- > lmap = Parser.lmapM return
1566+--
14891567{-# INLINE lmap #-}
14901568lmap :: (a -> b) -> Parser b m r -> Parser a m r
14911569lmap f (Parser step begin done) = Parser step1 begin done
@@ -1494,6 +1572,8 @@ lmap f (Parser step begin done) = Parser step1 begin done
14941572
14951573 step1 x a = step x (f a)
14961574
1575+-- | @lmapM f parser@ maps the monadic function @f@ on the input of the parser.
1576+--
14971577{-# INLINE lmapM #-}
14981578lmapM :: Monad m => (a -> m b) -> Parser b m r -> Parser a m r
14991579lmapM f (Parser step begin done) = Parser step1 begin done
@@ -1502,6 +1582,11 @@ lmapM f (Parser step begin done) = Parser step1 begin done
15021582
15031583 step1 x a = f a >>= step x
15041584
1585+-- | Include only those elements that pass a predicate.
1586+--
1587+-- >>> Stream.parse (Parser.filter (> 5) (Parser.fromFold Fold.sum)) $ Stream.fromList [1..10]
1588+-- Right 40
1589+--
15051590{-# INLINE filter #-}
15061591filter :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
15071592filter f (Parser step initial extract) = Parser step1 initial extract
core/src/Streamly/Internal/Data/Parser/ParserDK.hsnew file+1544
@@ -0,0 +1,1544 @@
1+{-# OPTIONS_GHC -Wno-orphans #-}
2+
3+-- |
4+-- Module : Streamly.Internal.Data.Parser
5+-- Copyright : (c) 2020 Composewell Technologies
6+-- License : BSD-3-Clause
7+-- Maintainer : streamly@composewell.com
8+-- Stability : pre-release
9+-- Portability : GHC
10+--
11+-- Fast backtracking parsers with stream fusion and native streaming
12+-- capability.
13+--
14+-- 'Applicative' and 'Control.Applicative.Alternative' type class based
15+-- combinators from the
16+-- <http://hackage.haskell.org/package/parser-combinators parser-combinators>
17+-- package can also be used with the 'Parser' type. However, there are two
18+-- important differences between @parser-combinators@ and the equivalent ones
19+-- provided in this module in terms of performance:
20+--
21+-- 1) @parser-combinators@ use plain Haskell lists to collect the results, in a
22+-- strict Monad like IO, the results are necessarily buffered before they can
23+-- be consumed. This may not perform optimally in streaming applications
24+-- processing large amounts of data. Equivalent combinators in this module can
25+-- consume the results of parsing using a 'Fold', thus providing a scalability
26+-- and a composable consumer.
27+--
28+-- 2) Several combinators in this module can be many times faster because of
29+-- stream fusion. For example, 'Streamly.Internal.Data.Parser.many' combinator
30+-- in this module is much faster than the 'Control.Applicative.many' combinator
31+-- of 'Control.Applicative.Alternative' type class.
32+--
33+-- = Errors
34+--
35+-- Failing parsers in this module throw the 'D.ParseError' exception.
36+--
37+-- = Naming
38+--
39+-- As far as possible, try that the names of the combinators in this module are
40+-- consistent with:
41+--
42+-- * <https://hackage.haskell.org/package/base/docs/Text-ParserCombinators-ReadP.html base/Text.ParserCombinators.ReadP>
43+-- * <http://hackage.haskell.org/package/parser-combinators parser-combinators>
44+-- * <http://hackage.haskell.org/package/megaparsec megaparsec>
45+-- * <http://hackage.haskell.org/package/attoparsec attoparsec>
46+-- * <http://hackage.haskell.org/package/parsec parsec>
47+
48+module Streamly.Internal.Data.Parser
49+ (
50+ K.Parser (..)
51+ , D.ParseError (..)
52+ , D.Step (..)
53+
54+ -- * Downgrade to Fold
55+ , toFold
56+
57+ -- First order parsers
58+ -- * Accumulators
59+ , fromFold
60+ , fromFoldMaybe
61+ , fromPure
62+ , fromEffect
63+ , die
64+ , dieM
65+
66+ -- * Map on input
67+ , lmap
68+ , lmapM
69+ , filter
70+
71+ -- * Map on output
72+ , rmapM
73+
74+ -- * Element parsers
75+ , peek
76+
77+ -- All of these can be expressed in terms of either
78+ , one
79+ , oneEq
80+ , oneNotEq
81+ , oneOf
82+ , noneOf
83+ , eof
84+ , satisfy
85+ , maybe
86+ , either
87+
88+ -- * Sequence parsers (tokenizers)
89+ --
90+ -- | Parsers chained in series, if one parser terminates the composition
91+ -- terminates.
92+
93+ , lookAhead
94+
95+ -- ** By length
96+ -- | Grab a sequence of input elements without inspecting them
97+ , takeBetween
98+ -- , take -- takeBetween 0 n
99+ , takeEQ -- takeBetween n n
100+ , takeGE -- takeBetween n maxBound
101+ , takeP
102+
103+ -- Grab a sequence of input elements by inspecting them
104+ -- ** Exact match
105+ , listEq
106+ , listEqBy
107+ , streamEqBy
108+ , subsequenceBy
109+
110+ -- ** By predicate
111+ , takeWhileP
112+ , takeWhile
113+ -- $takeWhile
114+ , takeWhile1
115+ , dropWhile
116+
117+ -- ** Separators
118+ , takeEndBy
119+ , takeEndBy_
120+ , takeEndByEsc
121+ -- , takeEndByEsc_
122+ , takeStartBy
123+ , takeStartBy_
124+ , takeEitherSepBy
125+ , wordBy
126+ -- , wordByEsc
127+
128+ -- ** By comparing
129+ , groupBy
130+ , groupByRolling
131+ , groupByRollingEither
132+
133+ -- ** Framing
134+ -- , takeFramedBy
135+ , takeFramedBy_
136+ , takeFramedByEsc_
137+ , takeFramedByGeneric
138+ , wordFramedBy
139+ , wordQuotedBy
140+
141+ -- | Unimplemented
142+ --
143+ -- @
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
147+ -- @
148+
149+ -- Second order parsers (parsers using parsers)
150+ -- * Binary Combinators
151+
152+ -- ** Sequential Applicative
153+ , splitWith
154+ , split_
155+
156+{-
157+ -- ** Parallel Applicatives
158+ , teeWith
159+ , teeWithFst
160+ , teeWithMin
161+ -- , teeTill -- like manyTill but parallel
162+-}
163+
164+ -- ** Sequential Interleaving
165+ -- Use two folds, run a primary parser, its rejected values go to the
166+ -- secondary parser.
167+ , deintercalate
168+ -- , deintercalatePrefix
169+ -- , deintercalateSuffix
170+
171+ -- *** Special cases
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.
176+ --
177+ -- We can instead implement these as special cases of deintercalate.
178+ --
179+ -- @
180+ -- , endBy
181+ -- , sepEndBy
182+ -- , beginBy
183+ -- , sepBeginBy
184+ -- , sepAroundBy
185+ -- @
186+ , sepBy1
187+ , sepBy
188+
189+ -- ** Sequential Alternative
190+ , alt
191+
192+{-
193+ -- ** Parallel Alternatives
194+ , shortest
195+ , longest
196+ -- , fastest
197+-}
198+
199+ -- * N-ary Combinators
200+ -- ** Sequential Collection
201+ , concatSequence
202+ , concatMap
203+
204+ -- ** Sequential Repetition
205+ , count
206+ , countBetween
207+
208+ , manyP
209+ , many
210+ , some
211+ , manyTillP
212+ , manyTill
213+ , manyThen
214+
215+ -- * Distribution
216+ --
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.
220+
221+ -- ** Distribute to collection
222+ -- ** Distribute to repetition
223+
224+ -- ** Interleaved collection
225+ -- |
226+ --
227+ -- 1. Round robin
228+ -- 2. Priority based
229+ , roundRobin
230+
231+ -- ** Collection of Alternatives
232+ -- | Unimplemented
233+ --
234+ -- @
235+ -- , shortestN
236+ -- , longestN
237+ -- , fastestN -- first N successful in time
238+ -- , choiceN -- first N successful in position
239+ -- @
240+ -- , choice -- first successful in position
241+
242+ -- ** Repeated Alternatives
243+ , retryMaxTotal
244+ , retryMaxSuccessive
245+ , retry
246+
247+ -- * Deprecated
248+ , next
249+ )
250+where
251+
252+import Streamly.Internal.Data.Fold.Type (Fold(..))
253+import Streamly.Internal.Data.Parser.ParserK.Type (Parser)
254+
255+import qualified Data.Foldable as Foldable
256+import qualified Streamly.Internal.Data.Fold.Type as FL
257+import qualified Streamly.Internal.Data.Parser.ParserD as D
258+import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
259+
260+#ifdef USE_STREAMK
261+import Streamly.Internal.Data.StreamK (Stream)
262+import qualified Streamly.Internal.Data.StreamK as Stream
263+#else
264+import Streamly.Internal.Data.Stream.StreamD.Type (Stream)
265+import qualified Streamly.Internal.Data.Stream.StreamD.Type as Stream
266+#endif
267+
268+import Prelude hiding
269+ ( any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either
270+ , filter )
271+
272+--
273+-- $setup
274+-- >>> :m
275+-- >>> import Prelude hiding (any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either, filter)
276+-- >>> import Control.Applicative ((<|>))
277+-- >>> import Data.Char (isSpace)
278+-- >>> import qualified Data.Maybe as Maybe
279+-- >>> import qualified Data.Foldable as Foldable
280+-- >>> import qualified Streamly.Data.Stream as Stream
281+-- >>> import qualified Streamly.Internal.Data.Stream as Stream (parse, parseMany)
282+-- >>> import qualified Streamly.Internal.Data.Fold as Fold
283+-- >>> import qualified Streamly.Internal.Data.Parser as Parser
284+
285+-------------------------------------------------------------------------------
286+-- Downgrade a parser to a Fold
287+-------------------------------------------------------------------------------
288+--
289+-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
290+-- parser fails or tries to backtrack.
291+--
292+-- This can be useful in combinators that accept a Fold and we know that a
293+-- Parser cannot fail or failure exception is acceptable as there is no way to
294+-- recover.
295+--
296+-- /Pre-release/
297+--
298+{-# INLINE toFold #-}
299+toFold :: Monad m => Parser a m b -> Fold m a b
300+toFold p = D.toFold $ D.fromParserK p
301+
302+-------------------------------------------------------------------------------
303+-- Upgrade folds to parses
304+-------------------------------------------------------------------------------
305+--
306+-- | Make a 'Parser' from a 'Fold'.
307+--
308+{-# INLINE fromFold #-}
309+fromFold :: Monad m => Fold m a b -> Parser a m b
310+fromFold = D.toParserK . D.fromFold
311+
312+-- | Convert a Maybe returning fold to an error returning parser. The first
313+-- argument is the error message that the parser would return when the fold
314+-- returns Nothing.
315+--
316+-- /Pre-release/
317+--
318+{-# INLINE fromFoldMaybe #-}
319+fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser a m b
320+fromFoldMaybe err = D.toParserK . D.fromFoldMaybe err
321+
322+-------------------------------------------------------------------------------
323+-- Terminating but not failing folds
324+-------------------------------------------------------------------------------
325+--
326+-- This is the dual of stream "fromPure".
327+--
328+-- | A parser that always yields a pure value without consuming any input.
329+--
330+{-# INLINE [3] fromPure #-}
331+fromPure :: Monad m => b -> Parser a m b
332+fromPure = D.toParserK . D.fromPure
333+{-# RULES "fromPure fallback to CPS" [2]
334+ forall a. D.toParserK (D.fromPure a) = K.fromPure a #-}
335+
336+-- This is the dual of stream "fromEffect".
337+--
338+-- | A parser that always yields the result of an effectful action without
339+-- consuming any input.
340+--
341+{-# INLINE fromEffect #-}
342+fromEffect :: Monad m => m b -> Parser a m b
343+fromEffect = K.fromEffect -- D.toParserK . D.fromEffect
344+
345+-- This is the dual of "nil".
346+--
347+-- | A parser that always fails with an error message without consuming
348+-- any input.
349+--
350+{-# INLINE [3] die #-}
351+die :: Monad m => String -> Parser a m b
352+die = D.toParserK . D.die
353+{-# RULES "die fallback to CPS" [2]
354+ forall a. D.toParserK (D.die a) = K.die a #-}
355+
356+-- This is the dual of "nilM".
357+--
358+-- | A parser that always fails with an effectful error message and without
359+-- consuming any input.
360+--
361+-- /Pre-release/
362+--
363+{-# INLINE dieM #-}
364+dieM :: Monad m => m String -> Parser a m b
365+dieM = D.toParserK . D.dieM
366+
367+-------------------------------------------------------------------------------
368+-- Map on input
369+-------------------------------------------------------------------------------
370+
371+-- | @lmap f parser@ maps the function @f@ on the input of the parser.
372+--
373+-- >>> Stream.parse (Parser.lmap (\x -> x * x) (Parser.fromFold Fold.sum)) (Stream.enumerateFromTo 1 100)
374+-- Right 338350
375+--
376+-- > lmap = Parser.lmapM return
377+--
378+{-# INLINE lmap #-}
379+lmap :: Monad m => (a -> b) -> Parser b m r -> Parser a m r
380+lmap f p = D.toParserK $ D.lmap f $ D.fromParserK p
381+
382+-- | @lmapM f parser@ maps the monadic function @f@ on the input of the parser.
383+--
384+{-# INLINE lmapM #-}
385+lmapM :: Monad m => (a -> m b) -> Parser b m r -> Parser a m r
386+lmapM f p = D.toParserK $ D.lmapM f $ D.fromParserK p
387+
388+-- | @rmapM f parser@ maps the monadic function @f@ on the output of the parser.
389+--
390+-- >>> rmap = fmap
391+{-# INLINE rmapM #-}
392+rmapM :: Monad m => (b -> m c) -> Parser a m b -> Parser a m c
393+rmapM f p = D.toParserK $ D.rmapM f $ D.fromParserK p
394+
395+-- | Include only those elements that pass a predicate.
396+--
397+-- >>> Stream.parse (Parser.filter (> 5) (Parser.fromFold Fold.sum)) $ Stream.fromList [1..10]
398+-- Right 40
399+--
400+{-# INLINE filter #-}
401+filter :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
402+filter f p = D.toParserK $ D.filter f $ D.fromParserK p
403+
404+-------------------------------------------------------------------------------
405+-- Failing Parsers
406+-------------------------------------------------------------------------------
407+
408+-- | Peek the head element of a stream, without consuming it. Fails if it
409+-- encounters end of input.
410+--
411+-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
412+-- Right (1,1)
413+--
414+-- @
415+-- peek = lookAhead (satisfy True)
416+-- @
417+--
418+{-# INLINE peek #-}
419+peek :: Monad m => Parser a m a
420+peek = D.toParserK D.peek
421+
422+-- | Succeeds if we are at the end of input, fails otherwise.
423+--
424+-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
425+-- Right (1,())
426+--
427+{-# INLINE eof #-}
428+eof :: Monad m => Parser a m ()
429+eof = D.toParserK D.eof
430+
431+-- | Returns the next element if it passes the predicate, fails otherwise.
432+--
433+-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
434+-- Right 1
435+--
436+-- >>> toMaybe f x = if f x then Just x else Nothing
437+-- >>> satisfy f = Parser.maybe (toMaybe f)
438+--
439+{-# INLINE satisfy #-}
440+satisfy :: Monad m => (a -> Bool) -> Parser a m a
441+satisfy = D.toParserK . D.satisfy
442+
443+-- | Consume one element from the head of the stream. Fails if it encounters
444+-- end of input.
445+--
446+-- >>> one = Parser.satisfy $ const True
447+--
448+{-# INLINE one #-}
449+one :: Monad m => Parser a m a
450+one = satisfy $ const True
451+
452+-- Alternate names: "only", "onlyThis".
453+
454+-- | Match a specific element.
455+--
456+-- >>> oneEq x = Parser.satisfy (== x)
457+--
458+{-# INLINE oneEq #-}
459+oneEq :: (Monad m, Eq a) => a -> Parser a m a
460+oneEq x = satisfy (== x)
461+
462+-- Alternate names: "exclude", "notThis".
463+
464+-- | Match anything other than the supplied element.
465+--
466+-- >>> oneNotEq x = Parser.satisfy (/= x)
467+--
468+{-# INLINE oneNotEq #-}
469+oneNotEq :: (Monad m, Eq a) => a -> Parser a m a
470+oneNotEq x = satisfy (/= x)
471+
472+-- | Match any one of the elements in the supplied list.
473+--
474+-- >>> oneOf xs = Parser.satisfy (`Foldable.elem` xs)
475+--
476+-- When performance matters a pattern matching predicate could be more
477+-- efficient than a 'Foldable' datatype:
478+--
479+-- @
480+-- let p x =
481+-- case x of
482+-- 'a' -> True
483+-- 'e' -> True
484+-- _ -> False
485+-- in satisfy p
486+-- @
487+--
488+-- GHC may use a binary search instead of linear search in the list.
489+-- Alternatively, you can also use an array instead of list for storage and
490+-- search.
491+--
492+{-# INLINE oneOf #-}
493+oneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
494+oneOf xs = satisfy (`Foldable.elem` xs)
495+
496+-- | See performance notes in 'oneOf'.
497+--
498+-- >>> noneOf xs = Parser.satisfy (`Foldable.notElem` xs)
499+--
500+{-# INLINE noneOf #-}
501+noneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
502+noneOf xs = satisfy (`Foldable.notElem` xs)
503+
504+-- | Return the next element of the input. Returns 'Nothing'
505+-- on end of input. Also known as 'head'.
506+--
507+-- /Pre-release/
508+--
509+{-# DEPRECATED next "Please use \"fromFold Fold.one\" instead" #-}
510+{-# INLINE next #-}
511+next :: Monad m => Parser a m (Maybe a)
512+next = D.toParserK D.next
513+
514+-- | Map a 'Maybe' returning function on the next element in the stream. The
515+-- parser fails if the function returns 'Nothing' otherwise returns the 'Just'
516+-- value.
517+--
518+-- >>> toEither = Maybe.maybe (Left "maybe: predicate failed") Right
519+-- >>> maybe f = Parser.either (toEither . f)
520+--
521+-- >>> maybe f = Parser.fromFoldMaybe "maybe: predicate failed" (Fold.maybe f)
522+--
523+-- /Pre-release/
524+--
525+{-# INLINE maybe #-}
526+maybe :: Monad m => (a -> Maybe b) -> Parser a m b
527+maybe = D.toParserK . D.maybe
528+
529+-- | Map an 'Either' returning function on the next element in the stream. If
530+-- the function returns 'Left err', the parser fails with the error message
531+-- @err@ otherwise returns the 'Right' value.
532+--
533+-- /Pre-release/
534+--
535+{-# INLINE either #-}
536+either :: Monad m => (a -> Either String b) -> Parser a m b
537+either = D.toParserK . D.either
538+
539+-------------------------------------------------------------------------------
540+-- Taking elements
541+-------------------------------------------------------------------------------
542+
543+-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
544+-- elements and folds them using the supplied fold.
545+--
546+-- Stops after @n@ elements.
547+-- Fails if the stream ends before @m@ elements could be taken.
548+--
549+-- Examples: -
550+--
551+-- @
552+-- >>> :{
553+-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
554+-- where prsr = Parser.takeBetween low high Fold.toList
555+-- :}
556+--
557+-- @
558+--
559+-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
560+-- Right [1,2,3,4]
561+--
562+-- >>> takeBetween' 2 4 [1, 2]
563+-- Right [1,2]
564+--
565+-- >>> takeBetween' 2 4 [1]
566+-- Left (ParseError "takeBetween: Expecting alteast 2 elements, got 1")
567+--
568+-- >>> takeBetween' 0 0 [1, 2]
569+-- Right []
570+--
571+-- >>> takeBetween' 0 1 []
572+-- Right []
573+--
574+-- @takeBetween@ is the most general take operation, other take operations can
575+-- be defined in terms of takeBetween. For example:
576+--
577+-- >>> take n = Parser.takeBetween 0 n
578+-- >>> takeEQ n = Parser.takeBetween n n
579+-- >>> takeGE n = Parser.takeBetween n maxBound
580+--
581+-- /Pre-release/
582+--
583+{-# INLINE takeBetween #-}
584+takeBetween :: Monad m =>
585+ Int -> Int -> Fold m a b -> Parser a m b
586+takeBetween m n = D.toParserK . D.takeBetween m n
587+
588+-- | Stops after taking exactly @n@ input elements.
589+--
590+-- * Stops - after consuming @n@ elements.
591+-- * Fails - if the stream or the collecting fold ends before it can collect
592+-- exactly @n@ elements.
593+--
594+-- >>> Stream.parse (Parser.takeEQ 4 Fold.toList) $ Stream.fromList [1,0,1]
595+-- Left (ParseError "takeEQ: Expecting exactly 4 elements, input terminated on 3")
596+--
597+{-# INLINE takeEQ #-}
598+takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
599+takeEQ n = D.toParserK . D.takeEQ n
600+
601+-- | Take at least @n@ input elements, but can collect more.
602+--
603+-- * Stops - when the collecting fold stops.
604+-- * Fails - if the stream or the collecting fold ends before producing @n@
605+-- elements.
606+--
607+-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1]
608+-- Left (ParseError "takeGE: Expecting at least 4 elements, input terminated on 3")
609+--
610+-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
611+-- Right [1,0,1,0,1]
612+--
613+-- /Pre-release/
614+--
615+{-# INLINE takeGE #-}
616+takeGE :: Monad m => Int -> Fold m a b -> Parser a m b
617+takeGE n = D.toParserK . D.takeGE n
618+
619+-------------------------------------------------------------------------------
620+-- Take until a condition
621+-------------------------------------------------------------------------------
622+
623+-- $takeWhile
624+-- Note: This is called @takeWhileP@ and @munch@ in some parser libraries.
625+
626+-- XXX We should perhaps use only takeWhileP and rename it to takeWhile.
627+--
628+-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
629+-- input. The combinator stops when the condition fails or if the collecting
630+-- parser stops.
631+--
632+-- Other interesting parsers can be implemented in terms of this parser:
633+--
634+-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
635+-- >>> takeWhileBetween cond m n p = Parser.takeWhileP cond (Parser.takeBetween m n p)
636+--
637+-- Stops: when the condition fails or the collecting parser stops.
638+-- Fails: when the collecting parser fails.
639+--
640+-- /Pre-release/
641+--
642+{-# INLINE takeWhileP #-}
643+takeWhileP :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
644+takeWhileP cond p = D.toParserK $ D.takeWhileP cond (D.fromParserK p)
645+
646+-- | Collect stream elements until an element fails the predicate. The element
647+-- on which the predicate fails is returned back to the input stream.
648+--
649+-- * Stops - when the predicate fails or the collecting fold stops.
650+-- * Fails - never.
651+--
652+-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
653+-- Right [0,0]
654+--
655+-- >>> takeWhile cond f = Parser.takeWhileP cond (Parser.fromFold f)
656+--
657+-- We can implement a @breakOn@ using 'takeWhile':
658+--
659+-- @
660+-- breakOn p = takeWhile (not p)
661+-- @
662+--
663+{-# INLINE takeWhile #-}
664+takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
665+takeWhile cond = D.toParserK . D.takeWhile cond
666+-- takeWhile cond f = takeWhileP cond (fromFold f)
667+
668+-- | Like 'takeWhile' but takes at least one element otherwise fails.
669+--
670+-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
671+--
672+{-# INLINE takeWhile1 #-}
673+takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
674+takeWhile1 cond = D.toParserK . D.takeWhile1 cond
675+-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
676+
677+-- | Drain the input as long as the predicate succeeds, running the effects and
678+-- discarding the results.
679+--
680+-- This is also called @skipWhile@ in some parsing libraries.
681+--
682+-- >>> dropWhile p = Parser.takeWhile p Fold.drain
683+--
684+{-# INLINE dropWhile #-}
685+dropWhile :: Monad m => (a -> Bool) -> Parser a m ()
686+dropWhile p = takeWhile p FL.drain
687+
688+-------------------------------------------------------------------------------
689+-- Separators
690+-------------------------------------------------------------------------------
691+
692+-- XXX We can remove Maybe from esc
693+{-# INLINE takeFramedByGeneric #-}
694+takeFramedByGeneric :: Monad m =>
695+ Maybe (a -> Bool)
696+ -> Maybe (a -> Bool)
697+ -> Maybe (a -> Bool)
698+ -> Fold m a b
699+ -> Parser a m b
700+takeFramedByGeneric esc begin end f =
701+ D.toParserK $ D.takeFramedByGeneric esc begin end f
702+
703+-- | @takeEndBy cond parser@ parses a token that ends by a separator chosen by
704+-- the supplied predicate. The separator is also taken with the token.
705+--
706+-- This can be combined with other parsers to implement other interesting
707+-- parsers as follows:
708+--
709+-- >>> takeEndByLE cond n p = Parser.takeEndBy cond (Parser.fromFold $ Fold.take n p)
710+-- >>> takeEndByBetween cond m n p = Parser.takeEndBy cond (Parser.takeBetween m n p)
711+--
712+-- >>> takeEndBy = Parser.takeEndByEsc (const False)
713+--
714+-- See also "Streamly.Data.Fold.takeEndBy". Unlike the fold, the collecting
715+-- parser in the takeEndBy parser can decide whether to fail or not if the
716+-- stream does not end with separator.
717+--
718+-- /Pre-release/
719+--
720+{-# INLINE takeEndBy #-}
721+takeEndBy :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
722+takeEndBy cond = D.toParserK . D.takeEndBy cond . D.fromParserK
723+-- takeEndBy = takeEndByEsc (const False)
724+
725+-- | Like 'takeEndBy' but the separator is dropped.
726+--
727+-- See also "Streamly.Data.Fold.takeEndBy_".
728+--
729+-- /Pre-release/
730+--
731+{-# INLINE takeEndBy_ #-}
732+takeEndBy_ :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
733+takeEndBy_ cond = D.toParserK . D.takeEndBy_ cond . D.fromParserK
734+{-
735+takeEndBy_ isEnd p =
736+ takeFramedByGeneric Nothing Nothing (Just isEnd) (toFold p)
737+-}
738+
739+-- | Take either the separator or the token. Separator is a Left value and
740+-- token is Right value.
741+--
742+-- /Unimplemented/
743+{-# INLINE takeEitherSepBy #-}
744+takeEitherSepBy :: -- Monad m =>
745+ (a -> Bool) -> Fold m (Either a b) c -> Parser a m c
746+takeEitherSepBy _cond = undefined -- D.toParserK . D.takeEitherSepBy cond
747+
748+-- | Parse a token that starts with an element chosen by the predicate. The
749+-- parser fails if the input does not start with the selected element.
750+--
751+-- * Stops - when the predicate succeeds in non-leading position.
752+-- * Fails - when the predicate fails in the leading position.
753+--
754+-- >>> splitWithPrefix p f = Stream.parseMany (Parser.takeStartBy p f)
755+--
756+-- Examples: -
757+--
758+-- >>> p = Parser.takeStartBy (== ',') Fold.toList
759+-- >>> leadingComma = Stream.parse p . Stream.fromList
760+-- >>> leadingComma "a,b"
761+-- Left (ParseError "takeStartBy: missing frame start")
762+-- ...
763+-- >>> leadingComma ",,"
764+-- Right ","
765+-- >>> leadingComma ",a,b"
766+-- Right ",a"
767+-- >>> leadingComma ""
768+-- Right ""
769+--
770+-- /Pre-release/
771+--
772+{-# INLINE takeStartBy #-}
773+takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
774+takeStartBy cond = D.toParserK . D.takeStartBy cond
775+
776+-- | Like 'takeStartBy' but drops the separator.
777+--
778+-- >>> takeStartBy_ isBegin = Parser.takeFramedByGeneric Nothing (Just isBegin) Nothing
779+--
780+{-# INLINE takeStartBy_ #-}
781+takeStartBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
782+takeStartBy_ isBegin = takeFramedByGeneric Nothing (Just isBegin) Nothing
783+
784+-------------------------------------------------------------------------------
785+-- Quoting and Escaping
786+-------------------------------------------------------------------------------
787+
788+-- | Like 'takeEndBy' but the separator elements can be escaped using an
789+-- escape char determined by the first predicate. The escape characters are
790+-- removed.
791+--
792+-- /pre-release/
793+{-# INLINE takeEndByEsc #-}
794+takeEndByEsc :: Monad m =>
795+ (a -> Bool) -> (a -> Bool) -> Parser a m b -> Parser a m b
796+takeEndByEsc isEsc isEnd p =
797+ D.toParserK $ D.takeEndByEsc isEsc isEnd (D.fromParserK p)
798+
799+-- | @takeFramedByEsc_ isEsc isBegin isEnd fold@ parses a token framed using a
800+-- begin and end predicate, and an escape character. The frame begin and end
801+-- characters lose their special meaning if preceded by the escape character.
802+--
803+-- Nested frames are allowed if begin and end markers are different, nested
804+-- frames must be balanced unless escaped, nested frame markers are emitted as
805+-- it is.
806+--
807+-- For example,
808+--
809+-- >>> p = Parser.takeFramedByEsc_ (== '\\') (== '{') (== '}') Fold.toList
810+-- >>> Stream.parse p $ Stream.fromList "{hello}"
811+-- Right "hello"
812+-- >>> Stream.parse p $ Stream.fromList "{hello {world}}"
813+-- Right "hello {world}"
814+-- >>> Stream.parse p $ Stream.fromList "{hello \\{world}"
815+-- Right "hello {world"
816+-- >>> Stream.parse p $ Stream.fromList "{hello {world}"
817+-- Left (ParseError "takeFramedByEsc_: missing frame end")
818+--
819+-- /Pre-release/
820+{-# INLINE takeFramedByEsc_ #-}
821+takeFramedByEsc_ :: Monad m =>
822+ (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
823+takeFramedByEsc_ isEsc isBegin isEnd f =
824+ D.toParserK $ D.takeFramedByEsc_ isEsc isBegin isEnd f
825+-- takeEndByEsc_ isEsc isEnd p =
826+-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
827+
828+-- | @takeFramedBy_ isBegin isEnd fold@ parses a token framed by a begin and an
829+-- end predicate.
830+--
831+-- >>> takeFramedBy_ = Parser.takeFramedByEsc_ (const False)
832+--
833+{-# INLINE takeFramedBy_ #-}
834+takeFramedBy_ :: Monad m =>
835+ (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
836+takeFramedBy_ isBegin isEnd f = D.toParserK $ D.takeFramedBy_ isBegin isEnd f
837+-- takeFramedBy_ isBegin isEnd =
838+-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
839+
840+-------------------------------------------------------------------------------
841+-- Grouping and words
842+-------------------------------------------------------------------------------
843+
844+-- Note we can also get words using something like:
845+-- sepBy FL.toList (takeWhile (not . p) Fold.toList) (dropWhile p)
846+--
847+-- But that won't be as efficient and ergonomic.
848+--
849+-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
850+-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
851+-- @["a","b"]@. In other words, its like parsing words from whitespace
852+-- separated text.
853+--
854+-- * Stops - when it finds a word separator after a non-word element
855+-- * Fails - never.
856+--
857+-- >>> wordBy = Parser.wordFramedBy (const False) (const False) (const False)
858+--
859+-- @
860+-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
861+-- @
862+--
863+{-# INLINE wordBy #-}
864+wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
865+wordBy f = D.toParserK . D.wordBy f
866+
867+-- | Like 'wordBy' but treats anything inside a pair of quotes as a single
868+-- word, the quotes can be escaped by an escape character. Recursive quotes
869+-- are possible if quote begin and end characters are different, quotes must be
870+-- balanced. Outermost quotes are stripped.
871+--
872+-- >>> braces = Parser.wordFramedBy (== '\\') (== '{') (== '}') isSpace Fold.toList
873+-- >>> Stream.parse braces $ Stream.fromList "{ab} cd"
874+-- Right "ab"
875+-- >>> Stream.parse braces $ Stream.fromList "{ab}{cd}"
876+-- Right "abcd"
877+-- >>> Stream.parse braces $ Stream.fromList "a{b} cd"
878+-- Right "ab"
879+-- >>> Stream.parse braces $ Stream.fromList "a{{b}} cd"
880+-- Right "a{b}"
881+--
882+-- >>> quotes = Parser.wordFramedBy (== '\\') (== '"') (== '"') isSpace Fold.toList
883+-- >>> Stream.parse quotes $ Stream.fromList "\"a\"\"b\""
884+-- Right "ab"
885+--
886+{-# INLINE wordFramedBy #-}
887+wordFramedBy :: Monad m =>
888+ (a -> Bool) -- ^ Escape
889+ -> (a -> Bool) -- ^ left quote
890+ -> (a -> Bool) -- ^ right quote
891+ -> (a -> Bool) -- ^ word seperator
892+ -> Fold m a b
893+ -> Parser a m b
894+wordFramedBy isEsc isBegin isEnd isSpc =
895+ D.toParserK . D.wordFramedBy isEsc isBegin isEnd isSpc
896+
897+-- | Like 'wordFramedBy' but the closing quote is determined by the opening
898+-- quote. The first quote begin starts a quote that is closed by its
899+-- corresponding closing quote.
900+--
901+-- 'wordFramedBy' and 'wordQuotedBy' both allow multiple quote characters based
902+-- on the predicates but 'wordQuotedBy' always fixes the quote at the first
903+-- occurrence and then it is closed only by the corresponding closing quote.
904+-- Therefore, other quoting characters can be embedded inside it as normal
905+-- characters. On the other hand, 'wordFramedBy' would close the quote as soon
906+-- as it encounters any of the closing quotes.
907+--
908+-- >>> q = (`elem` ['"', '\''])
909+-- >>> p kQ = Parser.wordQuotedBy kQ (== '\\') q q id isSpace Fold.toList
910+--
911+-- >>> Stream.parse (p False) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
912+-- Right "ab'c;d\"ef"
913+--
914+-- >>> Stream.parse (p True) $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
915+-- Right "a\"b'c\";'d\"e'f"
916+--
917+{-# INLINE wordQuotedBy #-}
918+wordQuotedBy :: (Monad m, Eq a) =>
919+ Bool -- ^ keep the quotes in the output
920+ -> (a -> Bool) -- ^ Escape
921+ -> (a -> Bool) -- ^ left quote
922+ -> (a -> Bool) -- ^ right quote
923+ -> (a -> a) -- ^ get right quote from left quote
924+ -> (a -> Bool) -- ^ word seperator
925+ -> Fold m a b
926+ -> Parser a m b
927+wordQuotedBy keepQuotes isEsc isBegin isEnd toRight isSpc =
928+ D.toParserK . D.wordQuotedBy keepQuotes isEsc isBegin isEnd toRight isSpc
929+
930+-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
931+-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
932+-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
933+-- then @c@ is also assigned to the same group and so on. When the comparison
934+-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
935+-- the result of the fold is the result of the parser.
936+--
937+-- * Stops - when the comparison fails.
938+-- * Fails - never.
939+--
940+-- >>> :{
941+-- runGroupsBy eq =
942+-- Stream.fold Fold.toList
943+-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
944+-- . Stream.fromList
945+-- :}
946+--
947+-- >>> runGroupsBy (<) []
948+-- []
949+--
950+-- >>> runGroupsBy (<) [1]
951+-- [Right [1]]
952+--
953+-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
954+-- [Right [3,5,4],Right [1,2],Right [0]]
955+--
956+{-# INLINE groupBy #-}
957+groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
958+groupBy eq = D.toParserK . D.groupBy eq
959+
960+-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
961+-- successive elements in the input stream. Assuming the input stream
962+-- is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
963+-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
964+-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
965+-- then @c@ is also assigned to the same group and so on. When the comparison
966+-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
967+-- the result of the fold is the result of the parser.
968+--
969+-- * Stops - when the comparison fails.
970+-- * Fails - never.
971+--
972+-- >>> :{
973+-- runGroupsByRolling eq =
974+-- Stream.fold Fold.toList
975+-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
976+-- . Stream.fromList
977+-- :}
978+--
979+-- >>> runGroupsByRolling (<) []
980+-- []
981+--
982+-- >>> runGroupsByRolling (<) [1]
983+-- [Right [1]]
984+--
985+-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
986+-- [Right [3,5],Right [4],Right [1,2],Right [0]]
987+--
988+-- /Pre-release/
989+--
990+{-# INLINE groupByRolling #-}
991+groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
992+groupByRolling eq = D.toParserK . D.groupByRolling eq
993+
994+-- | Like 'groupByRolling', but if the predicate is 'True' then collects using
995+-- the first fold as long as the predicate holds 'True', if the predicate is
996+-- 'False' collects using the second fold as long as it remains 'False'.
997+-- Returns 'Left' for the first case and 'Right' for the second case.
998+--
999+-- For example, if we want to detect sorted sequences in a stream, both
1000+-- ascending and descending cases we can use 'groupByRollingEither (<=)
1001+-- Fold.toList Fold.toList'.
1002+--
1003+-- /Pre-release/
1004+{-# INLINE groupByRollingEither #-}
1005+groupByRollingEither :: Monad m =>
1006+ (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
1007+groupByRollingEither eq f1 = D.toParserK . D.groupByRollingEither eq f1
1008+
1009+-- | Like 'listEqBy' but uses a stream instead of a list and does not return
1010+-- the stream.
1011+--
1012+-- See also: "Streamly.Data.Stream.streamEqBy"
1013+--
1014+{-# INLINE streamEqBy #-}
1015+streamEqBy :: Monad m => (a -> a -> Bool) -> Stream m a -> Parser a m ()
1016+streamEqBy cmp = D.toParserK . D.streamEqBy cmp
1017+
1018+-- | Match the given sequence of elements using the given comparison function.
1019+-- Returns the original sequence if successful.
1020+--
1021+-- Definition:
1022+--
1023+-- >>> listEqBy cmp xs = Parser.streamEqBy cmp (Stream.fromList xs) *> Parser.fromPure xs
1024+--
1025+-- Examples:
1026+--
1027+-- >>> Stream.parse (Parser.listEqBy (==) "string") $ Stream.fromList "string"
1028+-- Right "string"
1029+--
1030+-- >>> Stream.parse (Parser.listEqBy (==) "mismatch") $ Stream.fromList "match"
1031+-- Left (ParseError "streamEqBy: mismtach occurred")
1032+--
1033+{-# INLINE listEqBy #-}
1034+listEqBy :: Monad m => (a -> a -> Bool) -> [a] -> Parser a m [a]
1035+-- listEqBy cmp xs = D.toParserK (D.listEqBy cmp xs)
1036+listEqBy cmp xs = streamEqBy cmp (Stream.fromList xs) *> fromPure xs
1037+
1038+-- Rename to "list".
1039+-- | Match the input sequence with the supplied list and return it if
1040+-- successful.
1041+--
1042+-- >>> listEq = Parser.listEqBy (==)
1043+--
1044+{-# INLINE listEq #-}
1045+listEq :: (Monad m, Eq a) => [a] -> Parser a m [a]
1046+listEq = listEqBy (==)
1047+
1048+-- | Match if the input stream is a subsequence of the argument stream i.e. all
1049+-- the elements of the input stream occur, in order, in the argument stream.
1050+-- The elements do not have to occur consecutively. A sequence is considered a
1051+-- subsequence of itself.
1052+{-# INLINE subsequenceBy #-}
1053+subsequenceBy :: -- Monad m =>
1054+ (a -> a -> Bool) -> Stream m a -> Parser a m ()
1055+subsequenceBy = undefined
1056+
1057+{-
1058+-- Should go in Data.Parser.Regex in streamly package so that it can depend on
1059+-- regex backends.
1060+{-# INLINE regexPosix #-}
1061+regexPosix :: -- Monad m =>
1062+ Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
1063+regexPosix = undefined
1064+
1065+{-# INLINE regexPCRE #-}
1066+regexPCRE :: -- Monad m =>
1067+ Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
1068+regexPCRE = undefined
1069+-}
1070+
1071+-------------------------------------------------------------------------------
1072+-- nested parsers
1073+-------------------------------------------------------------------------------
1074+
1075+-- | Sequential parser application. Apply two parsers sequentially to an input
1076+-- stream. The input is provided to the first parser, when it is done the
1077+-- remaining input is provided to the second parser. If both the parsers
1078+-- succeed their outputs are combined using the supplied function. The
1079+-- operation fails if any of the parsers fail.
1080+--
1081+-- Note: This is a parsing dual of appending streams using
1082+-- 'Streamly.Data.Stream.append', it splits the streams using two parsers and zips
1083+-- the results.
1084+--
1085+-- This implementation is strict in the second argument, therefore, the
1086+-- following will fail:
1087+--
1088+-- >>> Stream.parse (Parser.splitWith const (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
1089+-- *** Exception: Prelude.undefined
1090+-- ...
1091+--
1092+-- Compare with 'Applicative' instance method '<*>'. This implementation allows
1093+-- stream fusion but has quadratic complexity. This can fuse with other
1094+-- operations and can be faster than 'Applicative' instance for small number
1095+-- (less than 8) of compositions.
1096+--
1097+-- Many combinators can be expressed using @splitWith@ and other parser
1098+-- primitives. Some common idioms are described below,
1099+--
1100+-- @
1101+-- span :: (a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
1102+-- span pred f1 f2 = splitWith (,) ('takeWhile' pred f1) ('fromFold' f2)
1103+-- @
1104+--
1105+-- @
1106+-- spanBy :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
1107+-- spanBy eq f1 f2 = splitWith (,) ('groupBy' eq f1) ('fromFold' f2)
1108+-- @
1109+--
1110+-- @
1111+-- spanByRolling :: (a -> a -> Bool) -> Fold m a b -> Fold m a b -> Parser a m b
1112+-- spanByRolling eq f1 f2 = splitWith (,) ('groupByRolling' eq f1) ('fromFold' f2)
1113+-- @
1114+--
1115+-- /Pre-release/
1116+--
1117+{-# INLINE splitWith #-}
1118+splitWith :: Monad m
1119+ => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1120+splitWith f p1 p2 =
1121+ D.toParserK $ D.splitWith f (D.fromParserK p1) (D.fromParserK p2)
1122+
1123+-- | Sequential parser application ignoring the output of the first parser.
1124+-- Apply two parsers sequentially to an input stream. The input is provided to
1125+-- the first parser, when it is done the remaining input is provided to the
1126+-- second parser. The output of the parser is the output of the second parser.
1127+-- The operation fails if any of the parsers fail.
1128+--
1129+-- This implementation is strict in the second argument, therefore, the
1130+-- following will fail:
1131+--
1132+-- >>> Stream.parse (Parser.split_ (Parser.satisfy (> 0)) undefined) $ Stream.fromList [1]
1133+-- *** Exception: Prelude.undefined
1134+-- ...
1135+--
1136+-- Compare with 'Applicative' instance method '*>'. This implementation allows
1137+-- stream fusion but has quadratic complexity. This can fuse with other
1138+-- operations, and can be faster than 'Applicative' instance for small
1139+-- number (less than 8) of compositions.
1140+--
1141+-- /Pre-release/
1142+--
1143+{-# INLINE split_ #-}
1144+split_ :: Monad m => Parser x m a -> Parser x m b -> Parser x m b
1145+split_ p1 p2 = D.toParserK $ D.split_ (D.fromParserK p1) (D.fromParserK p2)
1146+
1147+{-
1148+-- | @teeWith f p1 p2@ distributes its input to both @p1@ and @p2@ until both
1149+-- of them succeed or anyone of them fails and combines their output using @f@.
1150+-- The parser succeeds if both the parsers succeed.
1151+--
1152+-- /Pre-release/
1153+--
1154+{-# INLINE teeWith #-}
1155+teeWith :: Monad m
1156+ => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1157+teeWith f p1 p2 =
1158+ D.toParserK $ D.teeWith f (D.fromParserK p1) (D.fromParserK p2)
1159+
1160+-- | Like 'teeWith' but ends parsing and zips the results, if available,
1161+-- whenever the first parser ends.
1162+--
1163+-- /Pre-release/
1164+--
1165+{-# INLINE teeWithFst #-}
1166+teeWithFst :: Monad m
1167+ => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1168+teeWithFst f p1 p2 =
1169+ D.toParserK $ D.teeWithFst f (D.fromParserK p1) (D.fromParserK p2)
1170+
1171+-- | Like 'teeWith' but ends parsing and zips the results, if available,
1172+-- whenever any of the parsers ends or fails.
1173+--
1174+-- /Unimplemented/
1175+--
1176+{-# INLINE teeWithMin #-}
1177+teeWithMin :: Monad m
1178+ => (a -> b -> c) -> Parser x m a -> Parser x m b -> Parser x m c
1179+teeWithMin f p1 p2 =
1180+ D.toParserK $ D.teeWithMin f (D.fromParserK p1) (D.fromParserK p2)
1181+-}
1182+
1183+-- | Sequential alternative. Apply the input to the first parser and return the
1184+-- result if the parser succeeds. If the first parser fails then backtrack and
1185+-- apply the same input to the second parser and return the result.
1186+--
1187+-- Note: This implementation is not lazy in the second argument. The following
1188+-- will fail:
1189+--
1190+-- >>> Stream.parse (Parser.satisfy (> 0) `Parser.alt` undefined) $ Stream.fromList [1..10]
1191+-- Right 1
1192+--
1193+-- Compare with 'Alternative' instance method '<|>'. This implementation allows
1194+-- stream fusion but has quadratic complexity. This can fuse with other
1195+-- operations and can be much faster than 'Alternative' instance for small
1196+-- number (less than 8) of alternatives.
1197+--
1198+-- /Pre-release/
1199+--
1200+{-# INLINE alt #-}
1201+alt :: Monad m => Parser x m a -> Parser x m a -> Parser x m a
1202+alt p1 p2 = D.toParserK $ D.alt (D.fromParserK p1) (D.fromParserK p2)
1203+
1204+{-
1205+-- | Shortest alternative. Apply both parsers in parallel but choose the result
1206+-- from the one which consumed least input i.e. take the shortest succeeding
1207+-- parse.
1208+--
1209+-- /Pre-release/
1210+--
1211+{-# INLINE shortest #-}
1212+shortest :: Monad m
1213+ => Parser x m a -> Parser x m a -> Parser x m a
1214+shortest p1 p2 = D.toParserK $ D.shortest (D.fromParserK p1) (D.fromParserK p2)
1215+
1216+-- | Longest alternative. Apply both parsers in parallel but choose the result
1217+-- from the one which consumed more input i.e. take the longest succeeding
1218+-- parse.
1219+--
1220+-- /Pre-release/
1221+--
1222+{-# INLINE longest #-}
1223+longest :: Monad m
1224+ => Parser x m a -> Parser x m a -> Parser x m a
1225+longest p1 p2 = D.toParserK $ D.longest (D.fromParserK p1) (D.fromParserK p2)
1226+-}
1227+
1228+-- | Run a parser without consuming the input.
1229+--
1230+{-# INLINE lookAhead #-}
1231+lookAhead :: Monad m => Parser a m b -> Parser a m b
1232+lookAhead p = D.toParserK $ D.lookAhead $ D.fromParserK p
1233+
1234+-- | Takes at-most @n@ input elements.
1235+--
1236+-- * Stops - when the collecting parser stops.
1237+-- * Fails - when the collecting parser fails.
1238+--
1239+-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
1240+-- Right [1,2]
1241+--
1242+-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
1243+-- Left (ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4")
1244+--
1245+-- /Internal/
1246+{-# INLINE takeP #-}
1247+takeP :: Monad m => Int -> Parser a m b -> Parser a m b
1248+takeP i p = D.toParserK $ D.takeP i $ D.fromParserK p
1249+
1250+-------------------------------------------------------------------------------
1251+-- Sequential Collection
1252+-------------------------------------------------------------------------------
1253+--
1254+-- | @concatSequence f p@ collects sequential parses of parsers in a
1255+-- serial stream @p@ using the fold @f@. Fails if the input ends or any
1256+-- of the parsers fail.
1257+--
1258+-- An even more efficient implementation can use ParserD type Parser in
1259+-- the stream.
1260+--
1261+-- /Pre-release/
1262+--
1263+{-# INLINE concatSequence #-}
1264+concatSequence ::
1265+ Monad m =>
1266+ Fold m b c -> Stream m (Parser a m b) -> Parser a m c
1267+concatSequence f p =
1268+ let sp = fmap D.fromParserK p
1269+ in D.toParserK $ D.sequence sp f
1270+
1271+-- | Map a 'Parser' returning function on the result of a 'Parser'.
1272+--
1273+-- Compare with 'Monad' instance method '>>='. This implementation allows
1274+-- stream fusion but has quadratic complexity. This can fuse with other
1275+-- operations and can be much faster than 'Monad' instance for small number
1276+-- (less than 8) of compositions.
1277+--
1278+-- /Pre-release/
1279+--
1280+{-# INLINE concatMap #-}
1281+concatMap :: Monad m
1282+ => (b -> Parser a m c) -> Parser a m b -> Parser a m c
1283+concatMap f p = D.toParserK $ D.concatMap (D.fromParserK . f) (D.fromParserK p)
1284+
1285+{-
1286+-------------------------------------------------------------------------------
1287+-- Alternative Collection
1288+-------------------------------------------------------------------------------
1289+--
1290+-- | @choice parsers@ applies the @parsers@ in order and returns the first
1291+-- successful parse.
1292+--
1293+-- This is same as 'asum' but more efficient.
1294+--
1295+-- /Broken/
1296+--
1297+{-# INLINE choice #-}
1298+choice ::
1299+ (Functor t, Foldable t, Monad m) => t (Parser a m b) -> Parser a m b
1300+choice ps = D.toParserK $ D.choice $ D.fromParserK <$> ps
1301+-}
1302+
1303+-------------------------------------------------------------------------------
1304+-- Sequential Repetition
1305+-------------------------------------------------------------------------------
1306+
1307+-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
1308+-- results. Parsing stops or fails if the collecting parser stops or fails.
1309+--
1310+-- /Unimplemented/
1311+--
1312+{-# INLINE manyP #-}
1313+manyP :: -- Monad m =>
1314+ Parser a m b -> Parser b m c -> Parser a m c
1315+manyP _p _f = undefined -- D.toParserK $ D.manyP (D.fromParserK p) f
1316+
1317+-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
1318+-- input stream and push the parse results to a downstream fold.
1319+--
1320+-- Stops: when the downstream fold stops or the parser fails.
1321+-- Fails: never, produces zero or more results.
1322+--
1323+-- >>> many = Parser.countBetween 0 maxBound
1324+--
1325+-- Compare with 'Control.Applicative.many'.
1326+--
1327+{-# INLINE many #-}
1328+many :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1329+many p f = D.toParserK $ D.many (D.fromParserK p) f
1330+
1331+-- Note: many1 would perhaps be a better name for this and consistent with
1332+-- other names like takeWhile1. But we retain the name "some" for
1333+-- compatibility.
1334+--
1335+-- | Collect one or more parses. Apply the supplied parser repeatedly on the
1336+-- input stream and push the parse results to a downstream fold.
1337+--
1338+-- Stops: when the downstream fold stops or the parser fails.
1339+-- Fails: if it stops without producing a single result.
1340+--
1341+-- >>> some p f = Parser.manyP p (Parser.takeGE 1 f)
1342+-- >>> some = Parser.countBetween 1 maxBound
1343+--
1344+-- Compare with 'Control.Applicative.some'.
1345+--
1346+{-# INLINE some #-}
1347+some :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
1348+some p f = D.toParserK $ D.some (D.fromParserK p) f
1349+-- some p f = manyP p (takeGE 1 f)
1350+-- some = countBetween 1 maxBound
1351+
1352+-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
1353+-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
1354+-- the input ends or the parser fails before @m@ results are collected.
1355+--
1356+-- >>> countBetween m n p f = Parser.manyP p (Parser.takeBetween m n f)
1357+--
1358+-- /Unimplemented/
1359+--
1360+{-# INLINE countBetween #-}
1361+countBetween :: -- Monad m =>
1362+ Int -> Int -> Parser a m b -> Fold m b c -> Parser a m c
1363+countBetween _m _n _p = undefined
1364+-- countBetween m n p f = manyP p (takeBetween m n f)
1365+
1366+-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
1367+-- the fold @f@. Fails if the input ends or the parser fails before @n@
1368+-- results are collected.
1369+--
1370+-- >>> count n = Parser.countBetween n n
1371+-- >>> count n p f = Parser.manyP p (Parser.takeEQ n f)
1372+--
1373+-- /Unimplemented/
1374+--
1375+{-# INLINE count #-}
1376+count :: -- Monad m =>
1377+ Int -> Parser a m b -> Fold m b c -> Parser a m c
1378+count n = countBetween n n
1379+-- count n p f = manyP p (takeEQ n f)
1380+
1381+-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
1382+-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
1383+--
1384+-- We can implemnent parsers like the following using 'manyTillP':
1385+--
1386+-- @
1387+-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
1388+-- @
1389+--
1390+-- /Unimplemented/
1391+--
1392+{-# INLINE manyTillP #-}
1393+manyTillP :: -- Monad m =>
1394+ Parser a m b -> Parser a m x -> Parser b m c -> Parser a m c
1395+manyTillP _p1 _p2 _f = undefined
1396+ -- D.toParserK $ D.manyTillP (D.fromParserK p1) (D.fromParserK p2) f
1397+
1398+-- | @manyTill chunking test f@ tries the parser @test@ on the input, if @test@
1399+-- fails it backtracks and tries @chunking@, after @chunking@ succeeds @test@ is
1400+-- tried again and so on. The parser stops when @test@ succeeds. The output of
1401+-- @test@ is discarded and the output of @chunking@ is accumulated by the
1402+-- supplied fold. The parser fails if @chunking@ fails.
1403+--
1404+-- Stops when the fold @f@ stops.
1405+--
1406+{-# INLINE manyTill #-}
1407+manyTill :: Monad m
1408+ => Parser a m b -- ^ Chunking parser. Parses chunks of input.
1409+ -> Parser a m x -- ^ Test parser. Parsing stops when this parser succeeds
1410+ -- else backtract and run the chunking parser.
1411+ -> Fold m b c -- ^ Folds the output of the chunking parser.
1412+ -> Parser a m c
1413+manyTill collect test f =
1414+ D.toParserK $ D.manyTill (D.fromParserK collect) (D.fromParserK test) f
1415+
1416+-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
1417+-- collects the output in the supplied fold. If the the parser @collect@ fails,
1418+-- parser @recover@ is run until it stops and then we start repeating the
1419+-- parser @collect@ again. The parser fails if the recovery parser fails.
1420+--
1421+-- For example, this can be used to find a key frame in a video stream after an
1422+-- error.
1423+--
1424+-- /Unimplemented/
1425+--
1426+{-# INLINE manyThen #-}
1427+manyThen :: -- (Foldable t, Monad m) =>
1428+ Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
1429+manyThen _parser _recover _f = undefined
1430+
1431+-------------------------------------------------------------------------------
1432+-- Interleaving
1433+-------------------------------------------------------------------------------
1434+--
1435+-- To deinterleave we can chain two parsers one behind the other. The input is
1436+-- given to the first parser and the input definitively rejected by the first
1437+-- parser is given to the second parser.
1438+--
1439+-- We can either have the parsers themselves buffer the input or use the shared
1440+-- global buffer to hold it until none of the parsers need it. When the first
1441+-- parser returns Skip (i.e. rewind) we let the second parser consume the
1442+-- rejected input and when it is done we move the cursor forward to the first
1443+-- parser again. This will require a "move forward" command as well.
1444+--
1445+-- To implement grep we can use three parsers, one to find the pattern, one
1446+-- to store the context behind the pattern and one to store the context in
1447+-- front of the pattern. When a match occurs we need to emit the accumulator of
1448+-- all the three parsers. One parser can count the line numbers to provide the
1449+-- line number info.
1450+
1451+-- XXX rename this to intercalate
1452+-- | Apply two parsers alternately to an input stream. The input stream is
1453+-- considered an interleaving of two patterns. The two parsers represent the
1454+-- two patterns.
1455+--
1456+{-# INLINE deintercalate #-}
1457+deintercalate :: Monad m =>
1458+ Parser a m x
1459+ -> Parser a m y
1460+ -> Fold m (Either x y) z
1461+ -> Parser a m z
1462+deintercalate contentL contentR sink =
1463+ D.toParserK
1464+ $ D.deintercalate
1465+ (D.fromParserK contentL) (D.fromParserK contentR) sink
1466+
1467+-- | Parse items separated by a separator parsed by the supplied parser. At
1468+-- least one item must be present for the parser to succeed.
1469+--
1470+-- Note that this can go in infinite loop if both the parsers fail on some
1471+-- input. Detection of that would make the implementation more complex.
1472+--
1473+{-# INLINE sepBy1 #-}
1474+sepBy1 :: Monad m =>
1475+ Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
1476+sepBy1 p sep sink = do
1477+ x <- p
1478+ f <- fromEffect $ FL.reduce sink
1479+ f1 <- fromEffect $ FL.snoc f x
1480+ many (sep >> p) f1
1481+
1482+-- | Run the content parser first, when it is done, the separator parser is
1483+-- run, when it is done content parser is run again and so on. If none of the
1484+-- parsers consumes an input then parser returns a failure.
1485+--
1486+-- >>> sepBy p1 p2 sink = Parser.deintercalate p1 p2 (Fold.catLefts sink)
1487+-- >>> sepBy content sep sink = Parser.sepBy1 content sep sink <|> return mempty
1488+--
1489+{-# INLINE sepBy #-}
1490+sepBy :: Monad m =>
1491+ Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
1492+sepBy content sep sink =
1493+ D.toParserK $ D.sepBy (D.fromParserK content) (D.fromParserK sep) sink
1494+-- sepBy sink = deintercalate (FL.catLefts sink)
1495+
1496+-------------------------------------------------------------------------------
1497+-- Interleaving a collection of parsers
1498+-------------------------------------------------------------------------------
1499+--
1500+-- | Apply a collection of parsers to an input stream in a round robin fashion.
1501+-- Each parser is applied until it stops and then we repeat starting with the
1502+-- the first parser again.
1503+--
1504+-- /Unimplemented/
1505+--
1506+{-# INLINE roundRobin #-}
1507+roundRobin :: -- (Foldable t, Monad m) =>
1508+ t (Parser a m b) -> Fold m b c -> Parser a m c
1509+roundRobin _ps _f = undefined
1510+
1511+-------------------------------------------------------------------------------
1512+-- Repeated Alternatives
1513+-------------------------------------------------------------------------------
1514+
1515+-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
1516+-- fails the input consumed till now is dropped and the new instance is tried
1517+-- on the fresh input.
1518+--
1519+-- /Unimplemented/
1520+--
1521+{-# INLINE retryMaxTotal #-}
1522+retryMaxTotal :: -- (Monad m) =>
1523+ Int -> Parser a m b -> Fold m b c -> Parser a m c
1524+retryMaxTotal _n _p _f = undefined
1525+
1526+-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
1527+--
1528+-- /Unimplemented/
1529+--
1530+{-# INLINE retryMaxSuccessive #-}
1531+retryMaxSuccessive :: -- (Monad m) =>
1532+ Int -> Parser a m b -> Fold m b c -> Parser a m c
1533+retryMaxSuccessive _n _p _f = undefined
1534+
1535+-- | Keep trying a parser until it succeeds. When the parser fails the input
1536+-- consumed till now is dropped and the new instance is tried on the fresh
1537+-- input.
1538+--
1539+-- /Unimplemented/
1540+--
1541+{-# INLINE retry #-}
1542+retry :: -- (Monad m) =>
1543+ Parser a m b -> Parser a m b
1544+retry _p = undefined
core/src/Streamly/Internal/Data/Parser/ParserK/Type.hs+4−1
@@ -20,7 +20,8 @@ module Streamly.Internal.Data.Parser.ParserK.Type
2020 (
2121 Step (..)
2222 , Parse (..)
23− , Parser (..)
23+ , Parser (..) -- XXX Stop exporting this
24+ , ParserK
2425 , fromPure
2526 , fromEffect
2627 , die
@@ -101,6 +102,8 @@ newtype Parser a m b = MkParser
101102 -> m (Step m a r)
102103 }
103104
105+type ParserK = Parser
106+
104107-------------------------------------------------------------------------------
105108-- Functor
106109-------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Producer/Source.hs+2−2
@@ -282,7 +282,7 @@ parseManyD parser reader = Producer step return return
282282-- /Pre-release/
283283{-# INLINE parseMany #-}
284284parseMany :: Monad m =>
285− ParserK.Parser a m b
285+ ParserD.Parser a m b
286286 -> Producer m (Source x a) a
287287 -> Producer m (Source x a) (Either ParseError b)
288−parseMany parser = parseManyD (ParserD.fromParserK parser)
288+parseMany = parseManyD
core/src/Streamly/Internal/Data/Stream/Chunked.hs+2−2
@@ -96,7 +96,7 @@ import qualified Streamly.Internal.Data.Array.Mut.Stream as AS
9696import qualified Streamly.Internal.Data.Fold.Type as FL (Fold(..), Step(..))
9797import qualified Streamly.Internal.Data.Parser as PR
9898import qualified Streamly.Internal.Data.Parser.ParserD as PRD
99− (Parser(..), Initial(..), fromParserK)
99+ (Parser(..), Initial(..))
100100import qualified Streamly.Internal.Data.Stream.StreamD as D
101101import qualified Streamly.Internal.Data.Stream.StreamK as K
102102
@@ -789,7 +789,7 @@ parseBreak ::
789789parseBreak p s =
790790 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
791791-}
792−parseBreak p = parseBreakK (PRD.fromParserK p)
792+parseBreak = parseBreakK
793793
794794-------------------------------------------------------------------------------
795795-- Elimination - Running Array Folds and parsers
core/src/Streamly/Internal/Data/Stream/StreamD/Eliminate.hs+2−2
@@ -181,7 +181,7 @@ parseD parser strm = do
181181--
182182{-# INLINE [3] parse #-}
183183parse :: Monad m => PR.Parser a m b -> Stream m a -> m (Either ParseError b)
184−parse = parseD . PRD.fromParserK
184+parse = parseD
185185
186186-- | Run a 'Parse' over a stream and return rest of the Stream.
187187{-# INLINE_NORMAL parseBreakD #-}
@@ -347,7 +347,7 @@ parseBreakD (PRD.Parser pstep initial extract) stream@(Stream step state) = do
347347--
348348{-# INLINE parseBreak #-}
349349parseBreak :: Monad m => PR.Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
350−parseBreak p = parseBreakD (PRD.fromParserK p)
350+parseBreak = parseBreakD
351351
352352------------------------------------------------------------------------------
353353-- Specialized Folds
core/src/Streamly/Internal/Data/Stream/StreamD/Nesting.hs+2−2
@@ -1620,7 +1620,7 @@ parseMany
16201620 => PR.Parser a m b
16211621 -> Stream m a
16221622 -> Stream m (Either ParseError b)
1623−parseMany p = parseManyD (PRD.fromParserK p)
1623+parseMany = parseManyD
16241624
16251625-- | Apply a stream of parsers to an input stream and emit the results in the
16261626-- output stream.
@@ -1890,7 +1890,7 @@ parseIterate
18901890 -> b
18911891 -> Stream m a
18921892 -> Stream m (Either ParseError b)
1893−parseIterate f = parseIterateD (PRD.fromParserK . f)
1893+parseIterate = parseIterateD
18941894
18951895------------------------------------------------------------------------------
18961896-- Grouping
core/src/Streamly/Internal/Data/Stream/StreamK.hs+1−1
@@ -1231,7 +1231,7 @@ parseBreakD (PR.Parser pstep initial extract) stream = do
12311231{-# INLINE parseBreak #-}
12321232parseBreak :: Monad m =>
12331233 Parser.Parser a m b -> Stream m a -> m (Either ParseError b, Stream m a)
1234−parseBreak p = parseBreakD (PR.fromParserK p)
1234+parseBreak = parseBreakD
12351235
12361236{-# INLINE parse #-}
12371237parse :: Monad m =>
core/src/Streamly/Internal/Serialize/FromBytes.hs+7−7
@@ -54,7 +54,7 @@ import qualified Streamly.Internal.Data.Array as A
5454import qualified Streamly.Internal.Data.Parser as PR
5555 (fromPure, either, satisfy, takeEQ)
5656import qualified Streamly.Internal.Data.Parser.ParserD as PRD
57− (Parser(..), Initial(..), Step(..), toParserK)
57+ (Parser(..), Initial(..), Step(..))
5858
5959-- Note: The () type does not need to have an on-disk representation in theory.
6060-- But we use a concrete representation for it so that we count how many ()
@@ -155,7 +155,7 @@ word16beD = PRD.Parser step initial extract
155155--
156156{-# INLINE word16be #-}
157157word16be :: Monad m => Parser Word8 m Word16
158−word16be = PRD.toParserK word16beD
158+word16be = word16beD
159159
160160-- | Little endian (LSB first) Word16
161161{-# INLINE word16leD #-}
@@ -180,7 +180,7 @@ word16leD = PRD.Parser step initial extract
180180--
181181{-# INLINE word16le #-}
182182word16le :: Monad m => Parser Word8 m Word16
183−word16le = PRD.toParserK word16leD
183+word16le = word16leD
184184
185185-- | Big endian (MSB first) Word32
186186{-# INLINE word32beD #-}
@@ -207,7 +207,7 @@ word32beD = PRD.Parser step initial extract
207207--
208208{-# INLINE word32be #-}
209209word32be :: Monad m => Parser Word8 m Word32
210−word32be = PRD.toParserK word32beD
210+word32be = word32beD
211211
212212-- | Little endian (LSB first) Word32
213213{-# INLINE word32leD #-}
@@ -233,7 +233,7 @@ word32leD = PRD.Parser step initial extract
233233--
234234{-# INLINE word32le #-}
235235word32le :: Monad m => Parser Word8 m Word32
236−word32le = PRD.toParserK word32leD
236+word32le = word32leD
237237
238238-- | Big endian (MSB first) Word64
239239{-# INLINE word64beD #-}
@@ -260,7 +260,7 @@ word64beD = PRD.Parser step initial extract
260260--
261261{-# INLINE word64be #-}
262262word64be :: Monad m => Parser Word8 m Word64
263−word64be = PRD.toParserK word64beD
263+word64be = word64beD
264264
265265-- | Little endian (LSB first) Word64
266266{-# INLINE word64leD #-}
@@ -286,7 +286,7 @@ word64leD = PRD.Parser step initial extract
286286--
287287{-# INLINE word64le #-}
288288word64le :: Monad m => Parser Word8 m Word64
289−word64le = PRD.toParserK word64leD
289+word64le = word64leD
290290
291291{-# INLINE int8 #-}
292292int8 :: Monad m => Parser Word8 m Int8
core/src/Streamly/Internal/Unicode/Stream.hs+1−1
@@ -540,7 +540,7 @@ writeCharUtf8' = ParserD.toFold (parseCharUtf8WithD ErrorOnCodingFailure)
540540{-# INLINE parseCharUtf8With #-}
541541parseCharUtf8With ::
542542 Monad m => CodingFailureMode -> Parser.Parser Word8 m Char
543−parseCharUtf8With = ParserD.toParserK . parseCharUtf8WithD
543+parseCharUtf8With = parseCharUtf8WithD
544544
545545-- XXX write it as a parser and use parseMany to decode a stream, need to check
546546-- if that preserves the same performance. Or we can use a resumable parser
core/streamly-core.cabal+2
@@ -390,6 +390,7 @@ library
390390 , Streamly.Data.Array.Mut
391391 , Streamly.Data.Fold
392392 , Streamly.Data.Parser
393+ , Streamly.Data.Parser.ParserK
393394 , Streamly.Data.Stream
394395 , Streamly.Data.Stream.StreamK
395396 , Streamly.Data.Unfold
@@ -419,6 +420,7 @@ library
419420 , Streamly.Internal.Data.Stream.Cross
420421 , Streamly.Internal.Data.List
421422 , Streamly.Data.Stream.Zip
423+ , Streamly.Internal.Data.Parser.ParserDK
422424
423425 build-depends:
424426 -- streamly-base
src/Streamly/Internal/Data/Stream/IsStream/Eliminate.hs+2−2
@@ -382,7 +382,7 @@ parseD p = D.parseD p . toStreamD
382382-- /Internal/
383383{-# INLINE parseK #-}
384384parseK :: Monad m => PRK.Parser a m b -> SerialT m a -> m (Either PRD.ParseError b)
385−parseK = parse
385+parseK p = parse (PRD.fromParserK p)
386386
387387-- | Parse a stream using the supplied 'Parser'.
388388--
@@ -404,7 +404,7 @@ parseK = parse
404404--
405405{-# INLINE [3] parse #-}
406406parse :: Monad m => Parser a m b -> SerialT m a -> m (Either PRD.ParseError b)
407−parse = parseD . PRD.fromParserK
407+parse = parseD
408408
409409------------------------------------------------------------------------------
410410-- Specific Fold Functions
src/Streamly/Internal/Data/Stream/IsStream/Reduce.hs+3−4
@@ -189,8 +189,7 @@ import qualified Streamly.Internal.Data.Array.Type as A
189189import qualified Streamly.Internal.Data.Fold as FL
190190 (Fold, Step(..), takeEndBy_, takeEndBy, catMaybes, take)
191191import qualified Streamly.Internal.Data.IsMap as IsMap
192−import qualified Streamly.Internal.Data.Parser.ParserD as PRD
193− (Parser(..), fromParserK)
192+import qualified Streamly.Internal.Data.Parser.ParserD as PRD (Parser(..))
194193import qualified Streamly.Internal.Data.Stream.IsStream.Type as IsStream
195194import qualified Streamly.Internal.Data.Stream.StreamD as D
196195 ( foldMany
@@ -388,7 +387,7 @@ parseMany
388387 -> t m a
389388 -> t m (Either ParseError b)
390389parseMany p m =
391− fromStreamD $ D.parseManyD (PRD.fromParserK p) (toStreamD m)
390+ fromStreamD $ D.parseManyD p (toStreamD m)
392391
393392-- | Same as parseMany but for StreamD streams.
394393--
@@ -456,7 +455,7 @@ parseIterate
456455 -> t m a
457456 -> t m (Either ParseError b)
458457parseIterate f i m = fromStreamD $
459− D.parseIterateD (PRD.fromParserK . f) i (toStreamD m)
458+ D.parseIterateD f i (toStreamD m)
460459
461460------------------------------------------------------------------------------
462461-- Grouping
test/Streamly/Test/Data/Parser.hs+3−2
@@ -13,6 +13,7 @@ import Test.QuickCheck.Monadic (monadicIO, assert, run)
1313
1414import Prelude hiding (sequence)
1515
16+import qualified Control.Monad.Fail as Fail
1617import qualified Data.List as List
1718import qualified Prelude
1819import qualified Streamly.Internal.Data.Array as A
@@ -97,7 +98,7 @@ dieM =
9798parserFail :: Property
9899parserFail =
99100 property $
100− case runIdentity $ S.parse (fail err) (S.fromList [0 :: Int]) of
101+ case runIdentity $ S.parse (Fail.fail err) (S.fromList [0 :: Int]) of
101102 Right _ -> False
102103 Left (ParseError e) -> err == e
103104 where
@@ -255,7 +256,7 @@ takeGE =
255256 let
256257 list_length = Prelude.length ls
257258 in
258− case runIdentity $S.parse (P.takeGE n FL.toList) (S.fromList ls) of
259+ case runIdentity $ S.parse (P.takeGE n FL.toList) (S.fromList ls) of
259260 Right parsed_list ->
260261 if n <= list_length
261262 then checkListEqual parsed_list ls