4-- Module : Streamly.Internal.Data.Parser.ParserD
5-- Copyright : (c) 2020 Composewell Technologies
6-- License : BSD-3-Clause
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
11-- Direct style parser implementation with stream fusion.
13module Streamly.Internal.Data.Parser.ParserD
21 -- * Conversion to/from ParserK
25 -- * Downgrade to Fold
28 -- First order parsers
46 -- Parsers chained in series, if one parser terminates the composition
47 -- terminates. Currently we are using folds to collect the output of the
48 -- parsers but we can use Parsers instead of folds to make the composition
49 -- more powerful. For example, we can do:
51 -- sliceSepByMax cond n p = sliceBy cond (take n p)
52 -- sliceSepByBetween cond m n p = sliceBy cond (takeBetween m n p)
53 -- takeWhileBetween cond m n p = takeWhile cond (takeBetween m n p)
55 -- Grab a sequence of input elements without inspecting them
57 -- , take -- take -- takeBetween 0 n
58 -- , takeLE1 -- take1 -- takeBetween 1 n
59 , takeEQ -- takeBetween n n
60 , takeGE -- takeBetween n maxBound
62 -- Grab a sequence of input elements by inspecting them
68 -- , sliceSepByBetween
72 -- , frameSepBy -- parse frames escaped by an escape char/sequence
78 , groupByRollingEither
81 -- , prefixOf -- match any prefix of a given string
82 -- , suffixOf -- match any suffix of a given string
83 -- , infixOf -- match any substring of a given string
90 -- Second order parsers (parsers using parsers)
91 -- * Binary Combinators
93 -- ** Sequential Applicative
97 -- ** Parallel Applicatives
101 -- , teeTill -- like manyTill but parallel
103 -- ** Sequential Interleaving
104 -- Use two folds, run a primary parser, its rejected values go to the
108 -- ** Sequential Alternative
111 -- ** Parallel Alternatives
116 -- * N-ary Combinators
117 -- ** Sequential Collection
121 -- ** Sequential Repetition
124 -- , countBetweenTill
130 -- -- ** Special cases
131 -- XXX traditional implmentations of these may be of limited use. For
132 -- example, consider parsing lines separated by "\r\n". The main parser
133 -- will have to detect and exclude the sequence "\r\n" anyway so that we
134 -- can apply the "sep" parser.
136 -- We can instead implement these as special cases of deintercalate.
147 -- A simple and stupid impl would be to just convert the stream to an array
148 -- and give the array reference to all consumers. The array can be grown on
149 -- demand by any consumer and truncated when nonbody needs it.
151 -- -- ** Distribute to collection
152 -- -- ** Distribute to repetition
154 -- -- ** Interleaved collection
157 -- -- ** Interleaved repetition
158 -- repeat one parser and when it fails run an error recovery parser
159 -- e.g. to find a key frame in the stream after an error
161 -- ** Collection of Alternatives
164 -- , fastestN -- first N successful in time
165 -- , choiceN -- first N successful in position
166 , choice -- first successful in position
168 -- -- ** Repeated Alternatives
169 -- , retryMax -- try N times
170 -- , retryUntil -- try until successful
171 -- , retryUntilN -- try until successful n times
175import Control.Exception (assert, Exception)
176import Control.Monad (when)
177import Control.Monad.Catch (MonadCatch, MonadThrow(..))
178import Fusion.Plugin.Types (Fuse(..))
179import Streamly.Internal.Data.Fold.Type (Fold(..))
180import Streamly.Internal.Data.SVar.Type (defState)
181import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
183import qualified Streamly.Internal.Data.Fold.Type as FL
184import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
187 (any, all, take, takeWhile, sequence, concatMap, maybe, either, span)
188import Streamly.Internal.Data.Parser.ParserD.Tee
189import Streamly.Internal.Data.Parser.ParserD.Type
194-- >>> :set -package streamly
195-- >>> import Prelude hiding ()
196-- >>> import qualified Streamly.Prelude as Stream
197-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream
198-- >>> import qualified Streamly.Data.Fold as Fold
199-- >>> import qualified Streamly.Internal.Data.Parser as Parser
201-------------------------------------------------------------------------------
202-- Downgrade a parser to a Fold
203-------------------------------------------------------------------------------
205data ParserToFoldError =
213instance Exception ParserToFoldError
215-- | See 'Streamly.Internal.Data.Parser.toFold'.
220toFold :: MonadThrow m => Parser m a b -> Fold m a b
221toFold (Parser pstep pinitial pextract) = Fold step initial pextract
228 IPartial s -> return $ FL.Partial s
229 IDone b -> return $ FL.Done b
230 IError err -> throwM $ InitialError err
235 Partial 0 s -> return $ FL.Partial s
236 Continue 0 s -> return $ FL.Partial s
237 Done 0 b -> return $ FL.Done b
238 Partial n _ -> throwM $ PartialError n
239 Continue n _ -> throwM $ ContinueError n
240 Done n _ -> throwM $ DoneError n
241 Error err -> throwM $ ErrorError err
243-------------------------------------------------------------------------------
244-- Upgrade folds to parses
245-------------------------------------------------------------------------------
247-- | See 'Streamly.Internal.Data.Parser.fromFold'.
251{-# INLINE fromFold #-}
252fromFold :: Monad m => Fold m a b -> Parser m a b
253fromFold (Fold fstep finitial fextract) = Parser step initial fextract
261 FL.Partial s1 -> IPartial s1
268 FL.Partial s1 -> Partial 0 s1
269 FL.Done b -> Done 0 b
271-------------------------------------------------------------------------------
273-------------------------------------------------------------------------------
275-- | See 'Streamly.Internal.Data.Parser.peek'.
280peek :: MonadThrow m => Parser m a a
281peek = Parser step initial extract
285 initial = return $ IPartial ()
287 step () a = return $ Done 1 a
289 extract () = throwM $ ParseError "peek: end of input"
291-- | See 'Streamly.Internal.Data.Parser.eof'.
296eof :: Monad m => Parser m a ()
297eof = Parser step initial return
301 initial = return $ IPartial ()
303 step () _ = return $ Error "eof: not at end of input"
305-- | See 'Streamly.Internal.Data.Parser.satisfy'.
309{-# INLINE satisfy #-}
310satisfy :: MonadThrow m => (a -> Bool) -> Parser m a a
311satisfy predicate = Parser step initial extract
315 initial = return $ IPartial ()
320 else Error "satisfy: predicate failed"
322 extract _ = throwM $ ParseError "satisfy: end of input"
324-- | See 'Streamly.Internal.Data.Parser.next'.
329next :: Monad m => Parser m a (Maybe a)
330next = Parser step initial extract
332 initial = pure $ IPartial ()
333 step _ a = pure $ Done 0 (Just a)
334 extract _ = pure Nothing
336-- | See 'Streamly.Internal.Data.Parser.maybe'.
341maybe :: MonadThrow m => (a -> Maybe b) -> Parser m a b
342maybe parserF = Parser step initial extract
346 initial = return $ IPartial ()
351 Nothing -> Error "maybe: predicate failed"
353 extract _ = throwM $ ParseError "maybe: end of input"
355-- | See 'Streamly.Internal.Data.Parser.either'.
360either :: MonadThrow m => (a -> Either String b) -> Parser m a b
361either parserF = Parser step initial extract
365 initial = return $ IPartial ()
370 Left err -> Error $ "either: " ++ err
372 extract _ = throwM $ ParseError "either: end of input"
374-------------------------------------------------------------------------------
376-------------------------------------------------------------------------------
378-- Required to fuse "take" with "many" in "chunksOf", for ghc-9.x
379{-# ANN type Tuple'Fused Fuse #-}
380data Tuple'Fused a b = Tuple'Fused !a !b deriving Show
382-- | See 'Streamly.Internal.Data.Parser.takeBetween'.
386{-# INLINE takeBetween #-}
387takeBetween :: MonadCatch m => Int -> Int -> Fold m a b -> Parser m a b
388takeBetween low high (Fold fstep finitial fextract) =
390 Parser step initial (extract streamErr)
395 "takeBetween: Expecting alteast " ++ show low
396 ++ " elements, got " ++ show i
399 "takeBetween: lower bound - " ++ show low
400 ++ " is greater than higher bound - " ++ show high
402 foldErr :: Int -> String
404 "takeBetween: the collecting fold terminated after"
405 ++ " consuming" ++ show i ++ " elements"
406 ++ " minimum" ++ show low ++ " elements needed"
408 -- Exactly the same as snext except different constructors, we can possibly
409 -- deduplicate the two.
415 let s1 = Tuple'Fused i1 s
417 -- XXX ideally this should be a Continue instead
418 then return $ IPartial s1
419 else IDone <$> extract foldErr s1
424 else IError (foldErr i1)
427 when (low >= 0 && high >= 0 && low > high)
428 $ throwM $ ParseError invalidRange
430 finitial >>= inext (-1)
432 -- Keep the impl same as inext
438 let s1 = Tuple'Fused i1 s
440 then return $ Continue 0 s1
441 else Done 0 <$> extract foldErr s1
446 else Error (foldErr i1)
448 step (Tuple'Fused i s) a = fstep s a >>= snext i
450 extract f (Tuple'Fused i s)
451 | i >= low && i <= high = fextract s
452 | otherwise = throwM $ ParseError (f i)
454-- | See 'Streamly.Internal.Data.Parser.takeEQ'.
459takeEQ :: MonadThrow m => Int -> Fold m a b -> Parser m a b
460takeEQ n (Fold fstep finitial fextract) = Parser step initial extract
469 FL.Partial s -> IPartial $ Tuple' 0 s
474 $ "takeEQ: Expecting exactly " ++ show cnt
475 ++ " elements, fold terminated without"
476 ++ " consuming any elements"
483 FL.Partial s -> Continue 0 $ Tuple' i1 s
486 $ "takeEQ: Expecting exactly " ++ show cnt
487 ++ " elements, fold terminated on " ++ show i1
492 FL.Partial s -> fextract s
493 FL.Done b -> return b
494 -- XXX we should not reach here when initial returns Step type
495 -- reachable only when n == 0
496 | otherwise = Done 1 <$> fextract r
503 | i == 0 && cnt == 0 = fextract r
507 $ "takeEQ: Expecting exactly " ++ show cnt
508 ++ " elements, input terminated on " ++ show i
510-- | See 'Streamly.Internal.Data.Parser.takeGE'.
515takeGE :: MonadThrow m => Int -> Fold m a b -> Parser m a b
516takeGE n (Fold fstep finitial fextract) = Parser step initial extract
524 FL.Partial s -> IPartial $ Tuple' 0 s
529 $ "takeGE: Expecting at least " ++ show cnt
530 ++ " elements, fold terminated without"
531 ++ " consuming any elements"
538 FL.Partial s -> Continue 0 $ Tuple' i1 s
541 $ "takeGE: Expecting at least " ++ show cnt
542 ++ " elements, fold terminated on " ++ show i1
547 FL.Partial s -> Partial 0 $ Tuple' i1 s
548 FL.Done b -> Done 0 b
555 | i >= cnt = fextract r
559 $ "takeGE: Expecting at least " ++ show cnt
560 ++ " elements, input terminated on " ++ show i
562-- | See 'Streamly.Internal.Data.Parser.takeWhile'.
566{-# INLINE takeWhile #-}
567takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
568takeWhile predicate (Fold fstep finitial fextract) =
569 Parser step initial fextract
576 FL.Partial s -> IPartial s
585 FL.Partial s1 -> Partial 0 s1
586 FL.Done b -> Done 0 b
587 else Done 1 <$> fextract s
589-- | See 'Streamly.Internal.Data.Parser.takeWhile1'.
593{-# INLINE takeWhile1 #-}
594takeWhile1 :: MonadThrow m => (a -> Bool) -> Fold m a b -> Parser m a b
595takeWhile1 predicate (Fold fstep finitial fextract) =
596 Parser step initial extract
603 FL.Partial s -> IPartial (Left s)
606 $ "takeWhile1: fold terminated without consuming:"
609 {-# INLINE process #-}
614 FL.Partial s1 -> Partial 0 (Right s1)
615 FL.Done b -> Done 0 b
620 else return $ Error "takeWhile1: predicate failed on first element"
628 extract (Left _) = throwM $ ParseError "takeWhile1: end of input"
629 extract (Right s) = fextract s
631-- | See 'Streamly.Internal.Data.Parser.sliceSepByP'.
635sliceSepByP :: MonadCatch m =>
636 (a -> Bool) -> Parser m a b -> Parser m a b
637sliceSepByP cond (Parser pstep pinitial pextract) =
639 Parser step initial pextract
652-- | See 'Streamly.Internal.Data.Parser.sliceBeginWith'.
656data SliceBeginWithState s = Left' s | Right' s
658{-# INLINE sliceBeginWith #-}
659sliceBeginWith :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
660sliceBeginWith cond (Fold fstep finitial fextract) =
662 Parser step initial extract
670 FL.Partial s -> IPartial (Left' s)
671 FL.Done _ -> IError "sliceBeginWith : bad finitial"
673 {-# INLINE process #-}
678 FL.Partial s1 -> Partial 0 (Right' s1)
679 FL.Done b -> Done 0 b
684 else error $ "sliceBeginWith : slice begins with an element which "
685 ++ "fails the predicate"
689 else Done 1 <$> fextract s
691 extract (Left' s) = fextract s
692 extract (Right' s) = fextract s
694data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
696-- | See 'Streamly.Internal.Data.Parser.wordBy'.
700wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
701wordBy predicate (Fold fstep finitial fextract) = Parser step initial extract
705 {-# INLINE worder #-}
710 FL.Partial s1 -> Partial 0 $ WBWord s1
711 FL.Done b -> Done 0 b
717 FL.Partial s -> IPartial $ WBLeft s
723 else return $ Partial 0 $ WBLeft s
729 return $ Partial 0 $ WBRight b
732 $ if not (predicate a)
734 else Partial 0 $ WBRight b
736 extract (WBLeft s) = fextract s
737 extract (WBWord s) = fextract s
738 extract (WBRight b) = return b
740{-# ANN type GroupByState Fuse #-}
743 | GroupByGrouping !a !s
745-- | See 'Streamly.Internal.Data.Parser.groupBy'.
747{-# INLINE groupBy #-}
748groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
749groupBy eq (Fold fstep finitial fextract) = Parser step initial extract
753 {-# INLINE grouper #-}
758 FL.Done b -> Done 0 b
759 FL.Partial s1 -> Partial 0 (GroupByGrouping a0 s1)
765 FL.Partial s -> IPartial $ GroupByInit s
768 step (GroupByInit s) a = grouper s a a
769 step (GroupByGrouping a0 s) a =
772 else Done 1 <$> fextract s
774 extract (GroupByInit s) = fextract s
775 extract (GroupByGrouping _ s) = fextract s
777-- | See 'Streamly.Internal.Data.Parser.groupByRolling'.
779{-# INLINE groupByRolling #-}
780groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
781groupByRolling eq (Fold fstep finitial fextract) = Parser step initial extract
785 {-# INLINE grouper #-}
790 FL.Done b -> Done 0 b
791 FL.Partial s1 -> Partial 0 (GroupByGrouping a s1)
797 FL.Partial s -> IPartial $ GroupByInit s
800 step (GroupByInit s) a = grouper s a
801 step (GroupByGrouping a0 s) a =
804 else Done 1 <$> fextract s
806 extract (GroupByInit s) = fextract s
807 extract (GroupByGrouping _ s) = fextract s
809{-# ANN type GroupByStatePair Fuse #-}
810data GroupByStatePair a s1 s2
811 = GroupByInitPair !s1 !s2
812 | GroupByGroupingPair !a !s1 !s2
813 | GroupByGroupingPairL !a !s1 !s2
814 | GroupByGroupingPairR !a !s1 !s2
816{-# INLINE groupByRollingEither #-}
817groupByRollingEither :: MonadCatch m =>
818 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (Either b c)
821 (Fold fstep1 finitial1 fextract1)
822 (Fold fstep2 finitial2 fextract2) = Parser step initial extract
826 {-# INLINE grouper #-}
828 return $ Continue 0 (GroupByGroupingPair a s1 s2)
830 {-# INLINE grouperL2 #-}
831 grouperL2 s1 s2 a = do
835 FL.Done b -> Done 0 (Left b)
836 FL.Partial s11 -> Partial 0 (GroupByGroupingPairL a s11 s2)
838 {-# INLINE grouperL #-}
839 grouperL s1 s2 a0 a = do
842 FL.Done b -> return $ Done 0 (Left b)
843 FL.Partial s11 -> grouperL2 s11 s2 a
845 {-# INLINE grouperR2 #-}
846 grouperR2 s1 s2 a = do
850 FL.Done b -> Done 0 (Right b)
851 FL.Partial s21 -> Partial 0 (GroupByGroupingPairR a s1 s21)
853 {-# INLINE grouperR #-}
854 grouperR s1 s2 a0 a = do
857 FL.Done b -> return $ Done 0 (Right b)
858 FL.Partial s21 -> grouperR2 s1 s21 a
867 FL.Partial s2 -> IPartial $ GroupByInitPair s1 s2
868 FL.Done b -> IDone (Right b)
869 FL.Done b -> IDone (Left b)
871 step (GroupByInitPair s1 s2) a = grouper s1 s2 a
873 step (GroupByGroupingPair a0 s1 s2) a =
875 then grouperL s1 s2 a0 a
876 else grouperR s1 s2 a0 a
878 step (GroupByGroupingPairL a0 s1 s2) a =
880 then grouperL2 s1 s2 a
881 else Done 1 . Left <$> fextract1 s1
883 step (GroupByGroupingPairR a0 s1 s2) a =
885 then grouperR2 s1 s2 a
886 else Done 1 . Right <$> fextract2 s2
888 extract (GroupByInitPair s1 _) = Left <$> fextract1 s1
889 extract (GroupByGroupingPairL _ s1 _) = Left <$> fextract1 s1
890 extract (GroupByGroupingPairR _ _ s2) = Right <$> fextract2 s2
891 extract (GroupByGroupingPair a s1 _) = do
894 FL.Done b -> return $ Left b
895 FL.Partial s11 -> Left <$> fextract1 s11
897-- XXX use an Unfold instead of a list?
898-- XXX custom combinators for matching list, array and stream?
899-- XXX rename to listBy?
901-- | See 'Streamly.Internal.Data.Parser.eqBy'.
906eqBy :: MonadThrow m => (a -> a -> Bool) -> [a] -> Parser m a ()
907eqBy cmp str = Parser step initial extract
911 -- XXX Should return IDone in initial for [] case
912 initial = return $ IPartial str
914 step [] _ = return $ Done 0 ()
919 else Error "eqBy: failed, yet to match the last element"
925 $ "eqBy: failed, yet to match "
926 ++ show (length xs + 1) ++ " elements"
931 $ "eqBy: end of input, yet to match "
932 ++ show (length xs) ++ " elements"
934-- XXX rename to streamBy?
935-- | Like eqBy but uses a stream instead of a list
936{-# INLINE matchBy #-}
937matchBy :: MonadThrow m => (a -> a -> Bool) -> D.Stream m a -> Parser m a ()
938matchBy cmp (D.Stream sstep state) = Parser step initial extract
943 r <- sstep defState state
945 D.Yield x s -> return $ IPartial (Just x, s)
946 D.Stop -> return $ IDone ()
947 -- Need Skip/Continue in initial to loop right here
948 D.Skip s -> return $ IPartial (Nothing, s)
950 step (Just x, st) a =
953 r <- sstep defState st
956 D.Yield x1 s -> Continue 0 (Just x1, s)
958 D.Skip s -> Continue 1 (Nothing, s)
959 else return $ Error "match: mismtach occurred"
960 step (Nothing, st) a = do
961 r <- sstep defState st
966 then Continue 0 (Nothing, s)
967 else Error "match: mismatch occurred"
969 D.Skip s -> Continue 1 (Nothing, s)
971 extract _ = throwM $ ParseError "match: end of input"
973--------------------------------------------------------------------------------
975--------------------------------------------------------------------------------
977-- | @span p f1 f2@ composes folds @f1@ and @f2@ such that @f1@ consumes the
978-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
982-- > let span_ p xs = Stream.parse (Parser.span p Fold.toList Fold.toList) $ Stream.fromList xs
984-- > span_ (< 1) [1,2,3]
987-- > span_ (< 2) [1,2,3]
990-- > span_ (< 4) [1,2,3]
997span :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
998span p f1 f2 = noErrorUnsafeSplitWith (,) (takeWhile p f1) (fromFold f2)
1000-- | Break the input stream into two groups, the first group takes the input as
1001-- long as the predicate applied to the first element of the stream and next
1002-- input element holds 'True', the second group takes the rest of the input.
1006{-# INLINE spanBy #-}
1009 => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
1010spanBy eq f1 f2 = noErrorUnsafeSplitWith (,) (groupBy eq f1) (fromFold f2)
1012-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
1013-- predicate is applied to the previous and the next input elements.
1016{-# INLINE spanByRolling #-}
1019 => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
1020spanByRolling eq f1 f2 =
1021 noErrorUnsafeSplitWith (,) (groupByRolling eq f1) (fromFold f2)
1023-------------------------------------------------------------------------------
1025-------------------------------------------------------------------------------
1027-- | See 'Streamly.Internal.Data.Parser.takeP'.
1031takeP :: Monad m => Int -> Parser m a b -> Parser m a b
1032takeP lim (Parser pstep pinitial pextract) = Parser step initial extract
1041 then return $ IPartial $ Tuple' 0 s
1042 else IDone <$> pextract s
1043 IDone b -> return $ IDone b
1044 IError e -> return $ IError e
1046 step (Tuple' cnt r) a = do
1047 assert (cnt < lim) (return ())
1052 assert (cnt1 >= 0) (return ())
1054 then return $ Partial 0 $ Tuple' cnt1 s
1055 else Done 0 <$> pextract s
1057 assert (cnt1 >= 0) (return ())
1059 then return $ Continue 0 $ Tuple' cnt1 s
1060 -- XXX This should error out?
1061 -- If designed properly, this will probably error out.
1062 -- "pextract" should error out
1066 -- This is a tricky case, we have the following options:
1067 -- 1. Done 0 with extract as you have written
1068 -- 2. Done n, will require buffering elements
1069 -- 3. Use a backtracking fold and not a parser, once we have
1070 -- backtracking in folds
1071 else Done 0 <$> pextract s
1073 let taken = cnt1 - n
1074 assert (taken >= 0) (return ())
1075 return $ Partial n $ Tuple' taken s
1077 let taken = cnt1 - n
1078 assert (taken >= 0) (return ())
1079 return $ Continue n $ Tuple' taken s
1080 Done n b -> return $ Done n b
1081 Error str -> return $ Error str
1083 extract (Tuple' _ r) = pextract r
1085-- | See 'Streamly.Internal.Data.Parser.lookahead'.
1089{-# INLINE lookAhead #-}
1090lookAhead :: MonadThrow m => Parser m a b -> Parser m a b
1091lookAhead (Parser step1 initial1 _) = Parser step initial extract
1097 return $ case res of
1098 IPartial s -> IPartial (Tuple' 0 s)
1100 IError e -> IError e
1102 step (Tuple' cnt st) a = do
1107 Partial n s -> Continue n (Tuple' (cnt1 - n) s)
1108 Continue n s -> Continue n (Tuple' (cnt1 - n) s)
1109 Done _ b -> Done cnt1 b
1110 Error err -> Error err
1112 -- XXX returning an error let's us backtrack. To implement it in a way so
1113 -- that it terminates on eof without an error then we need a way to
1114 -- backtrack on eof, that will require extract to return 'Step' type.
1115 extract (Tuple' n _) =
1118 $ "lookAhead: end of input after consuming "
1119 ++ show n ++ " elements"
1121-------------------------------------------------------------------------------
1123-------------------------------------------------------------------------------
1125-- | See 'Streamly.Internal.Data.Parser.deintercalate'.
1129{-# INLINE deintercalate #-}
1132 Fold m a y -> Parser m x a
1133 -> Fold m b z -> Parser m x b
1134 -> Parser m x (y, z)
1135deintercalate = undefined
1137-------------------------------------------------------------------------------
1138-- Sequential Collection
1139-------------------------------------------------------------------------------
1141-- | See 'Streamly.Internal.Data.Parser.sequence'.
1145{-# INLINE sequence #-}
1148 Fold m b c -> t (Parser m a b) -> Parser m a c
1149sequence _f _p = undefined
1151-------------------------------------------------------------------------------
1152-- Alternative Collection
1153-------------------------------------------------------------------------------
1155-- | See 'Streamly.Internal.Data.Parser.choice'.
1159{-# INLINE choice #-}
1160choice :: (MonadCatch m, Foldable t) => t (Parser m a b) -> Parser m a b
1161choice = foldl1 shortest
1163-------------------------------------------------------------------------------
1164-- Sequential Repetition
1165-------------------------------------------------------------------------------
1167-- | See 'Streamly.Internal.Data.Parser.many'.
1172many :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1174-- many = countBetween 0 maxBound
1176-- | See 'Streamly.Internal.Data.Parser.some'.
1181some :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1183-- some f p = many (takeGE 1 f) p
1184-- many = countBetween 1 maxBound
1186-- | See 'Streamly.Internal.Data.Parser.countBetween'.
1190{-# INLINE countBetween #-}
1193 Int -> Int -> Parser m a b -> Fold m b c -> Parser m a c
1194countBetween _m _n _p = undefined
1195-- countBetween m n p f = many (takeBetween m n f) p
1197-- | See 'Streamly.Internal.Data.Parser.count'.
1204 Int -> Parser m a b -> Fold m b c -> Parser m a c
1205count n = countBetween n n
1206-- count n f p = many (takeEQ n f) p
1208data ManyTillState fs sr sl
1209 = ManyTillR Int fs sr
1210 | ManyTillL Int fs sl
1212-- | See 'Streamly.Internal.Data.Parser.manyTill'.
1216{-# INLINE manyTill #-}
1217manyTill :: MonadCatch m
1218 => Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1219manyTill (Fold fstep finitial fextract)
1220 (Parser stepL initialL extractL)
1221 (Parser stepR initialR _) =
1222 Parser step initial extract
1226 -- Caution: Mutual recursion
1228 scrutL fs p c d e = do
1231 IPartial sl -> return $ c (ManyTillL 0 fs sl)
1235 FL.Partial fs1 -> scrutR fs1 p c d e
1236 FL.Done fb -> return $ d fb
1237 IError err -> return $ e err
1239 scrutR fs p c d e = do
1242 IPartial sr -> return $ p (ManyTillR 0 fs sr)
1243 IDone _ -> d <$> fextract fs
1244 IError _ -> scrutL fs p c d e
1249 FL.Partial fs -> scrutR fs IPartial IPartial IDone IError
1250 FL.Done b -> return $ IDone b
1252 step (ManyTillR cnt fs st) a = do
1255 Partial n s -> return $ Partial n (ManyTillR 0 fs s)
1257 assert (cnt + 1 - n >= 0) (return ())
1258 return $ Continue n (ManyTillR (cnt + 1 - n) fs s)
1266 return $ Continue (cnt + 1) (ManyTillL 0 fs sl)
1274 FL.Partial fs1 -> scrutR fs1 p c d Error
1275 FL.Done fb -> return $ Done cnt1 fb
1276 IError err -> return $ Error err
1277 -- XXX the cnt is being used only by the assert
1278 step (ManyTillL cnt fs st) a = do
1281 Partial n s -> return $ Partial n (ManyTillL 0 fs s)
1283 assert (cnt + 1 - n >= 0) (return ())
1284 return $ Continue n (ManyTillL (cnt + 1 - n) fs s)
1289 scrutR s (Partial n) (Continue n) (Done n) Error
1290 FL.Done b1 -> return $ Done n b1
1291 Error err -> return $ Error err
1293 extract (ManyTillL _ fs sR) = do
1294 res <- extractL sR >>= fstep fs
1296 FL.Partial s -> fextract s
1297 FL.Done b -> return b
1298 extract (ManyTillR _ fs _) = fextract fs
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list