on master help sign in
Rename some parsers and add some TBD and comments
commitf51bbb25bde5b40a2f2e0d2b5547c329e0fb081b authorHarendra Kumar <harendra@composewell.com> dateThu 9 Apr 2020, 14:28 (7 years ago) parente6d4570
2 files changed+148−42
benchmark/Streamly/Benchmark/FileIO/Stream.hs+1−1 src/Streamly/Internal/Data/Parser.hs+147−41
benchmark/Streamly/Benchmark/FileIO/Stream.hs+1−1
@@ -612,7 +612,7 @@ inspect $ 'splitOnSuffix `hasNoType` ''D.ConcatMapUState
612612{-# INLINE splitParseSepBy #-}
613613splitParseSepBy :: Handle -> IO Int
614614splitParseSepBy inh =
615− (S.length $ IP.splitParse (PR.sepBy (== lf) FL.drain)
615+ (S.length $ IP.splitParse (PR.sliceSepBy (== lf) FL.drain)
616616 (S.unfold FH.read inh)) -- >>= print
617617
618618-- | Words by space
src/Streamly/Internal/Data/Parser.hs+147−41
@@ -33,8 +33,8 @@
3333-- Failing parsers in this module throw the 'ParseError' exception.
3434
3535-- XXX As far as possible, try that the combinators in this module and in
36−-- "parser-combinators/parsec/megaparsec/attoparsec" have consistent names.
37−-- takeP/takeWhileP?
36+-- "Text.ParserCombinators.ReadP/parser-combinators/parsec/megaparsec/attoparsec"
37+-- have consistent names. takeP/takeWhileP/munch?
3838
3939module Streamly.Internal.Data.Parser
4040 (
@@ -56,6 +56,16 @@ module Streamly.Internal.Data.Parser
5656 , satisfy
5757
5858 -- * Sequence parsers
59+ --
60+ -- Parsers chained in series, if one parser terminates the composition
61+ -- terminates. Currently we are using folds to collect the output of the
62+ -- parsers but we can use Parsers instead of folds to make the composition
63+ -- more powerful. For example, we can do:
64+ --
65+ -- sliceSepByMax cond n p = sliceBy cond (take n p)
66+ -- sliceSepByBetween cond m n p = sliceBy cond (takeBetween m n p)
67+ -- takeWhileBetween cond m n p = takeWhile cond (takeBetween m n p)
68+ --
5969 -- Grab a sequence of input elements without inspecting them
6070 , take
6171 -- , takeBetween
@@ -67,13 +77,17 @@ module Streamly.Internal.Data.Parser
6777 -- Grab a sequence of input elements by inspecting them
6878 , lookAhead
6979 , takeWhile
70− -- , takeWhileBetween
7180 , takeWhile1
72− , sepBy
73− , sepByMax
74− -- , sepByBetween
75− , sepWithSuffix
76− , sepWithPrefix
81+ , sliceSepBy
82+ , sliceSepByMax
83+ -- , sliceSepByBetween
84+ , sliceEndWith
85+ , sliceBeginWith
86+ -- , sliceSepWith
87+ --
88+ -- , frameSepBy -- parse frames escaped by an escape char/sequence
89+ -- , frameEndWith
90+ --
7791 , wordBy
7892 , groupBy
7993 , eqBy
@@ -84,41 +98,80 @@ module Streamly.Internal.Data.Parser
8498 -- Second order parsers (parsers using parsers)
8599 -- * Binary Combinators
86100
87− -- Parallel parsers
101+ -- ** Sequential Applicative
102+ , splitWith
103+
104+ -- ** Parallel Applicatives
88105 , teeWith
89106 , teeWithFst
90107 , teeWithMin
108+ -- , teeTill -- like manyTill but parallel
109+
110+ -- ** Sequential Interleaving
111+ -- Use two folds, run a primary parser, its rejected values go to the
112+ -- secondary parser.
113+ , deintercalate
91114
92− -- Alternatives
115+ -- ** Parallel Alternatives
93116 , shortest
94117 , longest
95118 -- , fastest
96119
97120 -- * N-ary Combinators
98− -- N-ary split applicative
99− -- Run n actions in sequence
121+ -- ** Sequential Collection
100122 , sequence
101123
102− -- Repeat the same action in sequence
103− -- , splitLE
104− -- , splitEQ -- splitN/takeN/parseN = replicateM n
105− -- , splitGE -- splitEQ n, splitMany
124+ -- ** Sequential Repetition
106125 , count
107126 , countBetween
108− , many -- splitMany/takeMany/parseMany
109− -- = splitGE 0 = countBetween 0 maxBound
110− , some -- splitMany1/takeMany1/parseMany1
111− -- = splitGE 1 = countBetween 1 maxBound
112−
113127 -- , countBetweenTill
114− , manyTill -- splitBreakOn, manyTill, parseBreakOn
115128
116− -- Run n actions in parallel
129+ , many
130+ , some
131+ , manyTill
132+
133+ -- -- ** Special cases
134+ -- XXX traditional implmentations of these may be of limited use. For
135+ -- example, consider parsing lines separated by "\r\n". The main parser
136+ -- will have to detect and exclude the sequence "\r\n" anyway so that we
137+ -- can apply the "sep" parser.
138+ --
139+ -- We can instead implement these as special cases of deintercalate.
140+ --
141+ -- , endBy
142+ -- , sepBy
143+ -- , sepEndBy
144+ -- , beginBy
145+ -- , sepBeginBy
146+ -- , sepAroundBy
147+
148+ -- -- * Distribution
149+ --
150+ -- A simple and stupid impl would be to just convert the stream to an array
151+ -- and give the array reference to all consumers. The array can be grown on
152+ -- demand by any consumer and truncated when nonbody needs it.
153+ --
154+ -- -- ** Distribute to collection
155+ -- -- ** Distribute to repetition
156+
157+ -- -- ** Interleaved collection
158+ -- Round robin
159+ -- Priority based
160+ -- -- ** Interleaved repetition
161+ -- repeat one parser and when it fails run an error recovery parser
162+ -- e.g. to find a key frame in the stream after an error
163+
164+ -- ** Collection of Alternatives
117165 -- , shortestN
118166 -- , longestN
119167 -- , fastestN -- first N successful in time
168+ -- , choiceN -- first N successful in position
120169 , choice -- first successful in position
121− -- , choiceN -- first N successful
170+
171+ -- -- ** Repeated Alternatives
172+ -- , retryMax -- try N times
173+ -- , retryUntil -- try until successful
174+ -- , retryUntilN -- try until successful n times
122175 )
123176where
124177
@@ -449,19 +502,19 @@ takeWhile1 predicate (Fold fstep finitial fextract) =
449502-- * Stops - when the predicate succeeds.
450503-- * Fails - never.
451504--
452−-- >>> S.parse (PR.sepBy (== 1) FL.toList) $ S.fromList [0,0,1,0,1]
505+-- >>> S.parse (PR.sliceSepBy (== 1) FL.toList) $ S.fromList [0,0,1,0,1]
453506-- > [0,0]
454507--
455−-- S.splitOn pred f = S.splitParse (PR.sepBy pred f)
508+-- S.splitOn pred f = S.splitParse (PR.sliceSepBy pred f)
456509--
457−-- >>> S.toList $ S.splitParse (PR.sepBy (== 1) FL.toList) $ S.fromList [0,0,1,0,1]
510+-- >>> S.toList $ S.splitParse (PR.sliceSepBy (== 1) FL.toList) $ S.fromList [0,0,1,0,1]
458511-- > [[0,0],[0],[]]
459512--
460513-- /Internal/
461514--
462−{-# INLINABLE sepBy #-}
463−sepBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
464−sepBy predicate (Fold fstep finitial fextract) =
515+{-# INLINABLE sliceSepBy #-}
516+sliceSepBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
517+sliceSepBy predicate (Fold fstep finitial fextract) =
465518 Parser step initial fextract
466519
467520 where
@@ -479,15 +532,15 @@ sepBy predicate (Fold fstep finitial fextract) =
479532-- * Stops - when the predicate succeeds.
480533-- * Fails - never.
481534--
482−-- S.splitWithSuffix pred f = S.splitParse (PR.sepWithSuffix pred f)
535+-- S.splitWithSuffix pred f = S.splitParse (PR.sliceEndWith pred f)
483536--
484537-- /Unimplemented/
485538--
486−{-# INLINABLE sepWithSuffix #-}
487−sepWithSuffix ::
539+{-# INLINABLE sliceEndWith #-}
540+sliceEndWith ::
488541 -- Monad m =>
489542 (a -> Bool) -> Fold m a b -> Parser m a b
490−sepWithSuffix = undefined
543+sliceEndWith = undefined
491544
492545-- | Collect stream elements until an elements passes the predicate, return the
493546-- last element on which the predicate succeeded back to the input stream. If
@@ -498,15 +551,15 @@ sepWithSuffix = undefined
498551-- * Stops - when the predicate succeeds in non-leading position.
499552-- * Fails - never.
500553--
501−-- S.splitWithPrefix pred f = S.splitParse (PR.sepWithPrefix pred f)
554+-- S.splitWithPrefix pred f = S.splitParse (PR.sliceBeginWith pred f)
502555--
503556-- /Unimplemented/
504557--
505−{-# INLINABLE sepWithPrefix #-}
506−sepWithPrefix ::
558+{-# INLINABLE sliceBeginWith #-}
559+sliceBeginWith ::
507560 -- Monad m =>
508561 (a -> Bool) -> Fold m a b -> Parser m a b
509−sepWithPrefix = undefined
562+sliceBeginWith = undefined
510563
511564-- | Split using a condition or a count whichever occurs first. This is a
512565-- hybrid of 'splitOn' and 'take'. The element on which the condition succeeds
@@ -514,10 +567,10 @@ sepWithPrefix = undefined
514567--
515568-- /Internal/
516569--
517−{-# INLINABLE sepByMax #-}
518−sepByMax :: Monad m
570+{-# INLINABLE sliceSepByMax #-}
571+sliceSepByMax :: Monad m
519572 => (a -> Bool) -> Int -> Fold m a b -> Parser m a b
520−sepByMax predicate cnt (Fold fstep finitial fextract) =
573+sliceSepByMax predicate cnt (Fold fstep finitial fextract) =
521574 Parser step initial extract
522575
523576 where
@@ -634,6 +687,46 @@ lookAhead (Parser step1 initial1 _) =
634687 extract (Tuple' n _) = throwM $ ParseError $
635688 "lookAhead: end of input after consuming " ++ show n ++ " elements"
636689
690+-------------------------------------------------------------------------------
691+-- Interleaving
692+-------------------------------------------------------------------------------
693+--
694+-- To deinterleave we can chain two parsers one behind the other. The input is
695+-- given to the first parser and the input definitively rejected by the first
696+-- parser is given to the second parser.
697+--
698+-- We can either have the parsers themselves buffer the input or use the shared
699+-- global buffer to hold it until none of the parsers need it. When the first
700+-- parser returns Skip (i.e. rewind) we let the second parser consume the
701+-- rejected input and when it is done we move the cursor forward to the first
702+-- parser again. This will require a "move forward" command as well.
703+--
704+-- To implement grep we can use three parsers, one to find the pattern, one
705+-- to store the context behind the pattern and one to store the context in
706+-- front of the pattern. When a match occurs we need to emit the accumulator of
707+-- all the three parsers. One parser can count the line numbers to provide the
708+-- line number info.
709+--
710+-- | Apply two parsers alternately to an input stream. The input stream is
711+-- considered an interleaving of two patterns. The two parsers represent the
712+-- two patterns.
713+--
714+-- This undoes a "gintercalate" of two streams.
715+--
716+-- /Unimplemented/
717+--
718+{-# INLINE deintercalate #-}
719+deintercalate ::
720+ -- Monad m =>
721+ Fold m a y -> Parser m x a
722+ -> Fold m b z -> Parser m x b
723+ -> Parser m x (y, z)
724+deintercalate = undefined
725+
726+-------------------------------------------------------------------------------
727+-- Sequential Collection
728+-------------------------------------------------------------------------------
729+--
637730-- | @sequence f t@ collects sequential parses of parsers in the container @t@
638731-- using the fold @f@. Fails if the input ends or any of the parsers fail.
639732--
@@ -645,6 +738,10 @@ sequence ::
645738 Fold m b c -> t (Parser m a b) -> Parser m a c
646739sequence _f _p = undefined
647740
741+-------------------------------------------------------------------------------
742+-- Alternative Collection
743+-------------------------------------------------------------------------------
744+--
648745-- | @choice parsers@ applies the @parsers@ in order and returns the first
649746-- successful parse.
650747--
@@ -654,6 +751,10 @@ choice ::
654751 t (Parser m a b) -> Parser m a b
655752choice _ps = undefined
656753
754+-------------------------------------------------------------------------------
755+-- Sequential Repetition
756+-------------------------------------------------------------------------------
757+--
657758-- XXX "many" is essentially a Fold because it cannot fail. So it can be
658759-- downgraded to a Fold. Or we can make the return type a Fold instead and
659760-- upgrade that to a parser when needed.
@@ -670,6 +771,7 @@ choice _ps = undefined
670771{-# INLINE many #-}
671772many :: MonadCatch m => Fold m b c -> Parser m a b -> Parser m a c
672773many = splitMany
774+-- many = countBetween 0 maxBound
673775
674776-- | Collect one or more parses. Apply the supplied parser repeatedly on the
675777-- input stream and accumulate the parse results as long as the parser
@@ -683,6 +785,8 @@ many = splitMany
683785{-# INLINE some #-}
684786some :: MonadCatch m => Fold m b c -> Parser m a b -> Parser m a c
685787some = splitSome
788+-- some f p = many (takeGE 1 f) p
789+-- many = countBetween 1 maxBound
686790
687791-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
688792-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
@@ -695,6 +799,7 @@ countBetween ::
695799 -- MonadCatch m =>
696800 Int -> Int -> Fold m b c -> Parser m a b -> Parser m a c
697801countBetween _m _n _f = undefined
802+-- countBetween m n f p = many (takeBetween m n f) p
698803
699804-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
700805-- the fold @f@. Fails if the input ends or the parser fails before @n@
@@ -707,6 +812,7 @@ count ::
707812 -- MonadCatch m =>
708813 Int -> Fold m b c -> Parser m a b -> Parser m a c
709814count n = countBetween n n
815+-- count n f p = many (takeEQ n f) p
710816
711817data ManyTillState fs sr sl = ManyTillR Int fs sr | ManyTillL fs sl
712818