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
51 -- Parsers chained in series, if one parser terminates the composition
52 -- terminates. Currently we are using folds to collect the output of the
53 -- parsers but we can use Parsers instead of folds to make the composition
54 -- more powerful. For example, we can do:
56 -- sliceSepByMax cond n p = sliceBy cond (take n p)
57 -- sliceSepByBetween cond m n p = sliceBy cond (takeBetween m n p)
58 -- takeWhileBetween cond m n p = takeWhile cond (takeBetween m n p)
60 -- Grab a sequence of input elements without inspecting them
62 -- , take -- take -- takeBetween 0 n
63 -- , takeLE1 -- take1 -- takeBetween 1 n
64 , takeEQ -- takeBetween n n
65 , takeGE -- takeBetween n maxBound
67 -- Grab a sequence of input elements by inspecting them
73 -- , sliceSepByBetween
77 -- , frameSepBy -- parse frames escaped by an escape char/sequence
83 , groupByRollingEither
86 -- , prefixOf -- match any prefix of a given string
87 -- , suffixOf -- match any suffix of a given string
88 -- , infixOf -- match any substring of a given string
95 -- Second order parsers (parsers using parsers)
96 -- * Binary Combinators
98 -- ** Sequential Applicative
102 -- ** Parallel Applicatives
106 -- , teeTill -- like manyTill but parallel
108 -- ** Sequential Interleaving
109 -- Use two folds, run a primary parser, its rejected values go to the
113 -- ** Sequential Alternative
116 -- ** Parallel Alternatives
121 -- * N-ary Combinators
122 -- ** Sequential Collection
126 -- ** Sequential Repetition
129 -- , countBetweenTill
135 -- -- ** Special cases
136 -- XXX traditional implmentations of these may be of limited use. For
137 -- example, consider parsing lines separated by "\r\n". The main parser
138 -- will have to detect and exclude the sequence "\r\n" anyway so that we
139 -- can apply the "sep" parser.
141 -- We can instead implement these as special cases of deintercalate.
152 -- A simple and stupid impl would be to just convert the stream to an array
153 -- and give the array reference to all consumers. The array can be grown on
154 -- demand by any consumer and truncated when nonbody needs it.
156 -- -- ** Distribute to collection
157 -- -- ** Distribute to repetition
159 -- -- ** Interleaved collection
162 -- -- ** Interleaved repetition
163 -- repeat one parser and when it fails run an error recovery parser
164 -- e.g. to find a key frame in the stream after an error
166 -- ** Collection of Alternatives
169 -- , fastestN -- first N successful in time
170 -- , choiceN -- first N successful in position
171 , choice -- first successful in position
173 -- -- ** Repeated Alternatives
174 -- , retryMax -- try N times
175 -- , retryUntil -- try until successful
176 -- , retryUntilN -- try until successful n times
180import Control.Exception (assert, Exception)
181import Control.Monad (when)
182import Control.Monad.Catch (MonadCatch, MonadThrow(..))
183import Fusion.Plugin.Types (Fuse(..))
184import Streamly.Internal.Data.Fold.Type (Fold(..))
185import Streamly.Internal.Data.SVar.Type (defState)
186import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
188import qualified Streamly.Internal.Data.Fold.Type as FL
189import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
192 (any, all, take, takeWhile, sequence, concatMap, maybe, either, span)
193import Streamly.Internal.Data.Parser.ParserD.Tee
194import Streamly.Internal.Data.Parser.ParserD.Type
199-- >>> :set -package streamly
200-- >>> import Prelude hiding ()
201-- >>> import qualified Streamly.Prelude as Stream
202-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream
203-- >>> import qualified Streamly.Data.Fold as Fold
204-- >>> import qualified Streamly.Internal.Data.Parser as Parser
206-------------------------------------------------------------------------------
207-- Downgrade a parser to a Fold
208-------------------------------------------------------------------------------
210data ParserToFoldError =
218instance Exception ParserToFoldError
220-- | See 'Streamly.Internal.Data.Parser.toFold'.
225toFold :: MonadThrow m => Parser m a b -> Fold m a b
226toFold (Parser pstep pinitial pextract) = Fold step initial pextract
233 IPartial s -> return $ FL.Partial s
234 IDone b -> return $ FL.Done b
235 IError err -> throwM $ InitialError err
240 Partial 0 s -> return $ FL.Partial s
241 Continue 0 s -> return $ FL.Partial s
242 Done 0 b -> return $ FL.Done b
243 Partial n _ -> throwM $ PartialError n
244 Continue n _ -> throwM $ ContinueError n
245 Done n _ -> throwM $ DoneError n
246 Error err -> throwM $ ErrorError err
248-------------------------------------------------------------------------------
249-- Upgrade folds to parses
250-------------------------------------------------------------------------------
252-- | See 'Streamly.Internal.Data.Parser.fromFold'.
256{-# INLINE fromFold #-}
257fromFold :: Monad m => Fold m a b -> Parser m a b
258fromFold (Fold fstep finitial fextract) = Parser step initial fextract
266 FL.Partial s1 -> IPartial s1
273 FL.Partial s1 -> Partial 0 s1
274 FL.Done b -> Done 0 b
276-------------------------------------------------------------------------------
278-------------------------------------------------------------------------------
280-- | See 'Streamly.Internal.Data.Parser.peek'.
285peek :: MonadThrow m => Parser m a a
286peek = Parser step initial extract
290 initial = return $ IPartial ()
292 step () a = return $ Done 1 a
294 extract () = throwM $ ParseError "peek: end of input"
296-- | See 'Streamly.Internal.Data.Parser.eof'.
301eof :: Monad m => Parser m a ()
302eof = Parser step initial return
306 initial = return $ IPartial ()
308 step () _ = return $ Error "eof: not at end of input"
310-- | See 'Streamly.Internal.Data.Parser.satisfy'.
314{-# INLINE satisfy #-}
315satisfy :: MonadThrow m => (a -> Bool) -> Parser m a a
316satisfy predicate = Parser step initial extract
320 initial = return $ IPartial ()
325 else Error "satisfy: predicate failed"
327 extract _ = throwM $ ParseError "satisfy: end of input"
329-- | See 'Streamly.Internal.Data.Parser.next'.
334next :: Monad m => Parser m a (Maybe a)
335next = Parser step initial extract
337 initial = pure $ IPartial ()
338 step _ a = pure $ Done 0 (Just a)
339 extract _ = pure Nothing
341-- | See 'Streamly.Internal.Data.Parser.maybe'.
346maybe :: MonadThrow m => (a -> Maybe b) -> Parser m a b
347maybe parserF = Parser step initial extract
351 initial = return $ IPartial ()
356 Nothing -> Error "maybe: predicate failed"
358 extract _ = throwM $ ParseError "maybe: end of input"
360-- | See 'Streamly.Internal.Data.Parser.either'.
365either :: MonadThrow m => (a -> Either String b) -> Parser m a b
366either parserF = Parser step initial extract
370 initial = return $ IPartial ()
375 Left err -> Error $ "either: " ++ err
377 extract _ = throwM $ ParseError "either: end of input"
379-------------------------------------------------------------------------------
381-------------------------------------------------------------------------------
383-- Required to fuse "take" with "many" in "chunksOf", for ghc-9.x
384{-# ANN type Tuple'Fused Fuse #-}
385data Tuple'Fused a b = Tuple'Fused !a !b deriving Show
387-- | See 'Streamly.Internal.Data.Parser.takeBetween'.
391{-# INLINE takeBetween #-}
392takeBetween :: MonadCatch m => Int -> Int -> Fold m a b -> Parser m a b
393takeBetween low high (Fold fstep finitial fextract) =
395 Parser step initial (extract streamErr)
400 "takeBetween: Expecting alteast " ++ show low
401 ++ " elements, got " ++ show i
404 "takeBetween: lower bound - " ++ show low
405 ++ " is greater than higher bound - " ++ show high
407 foldErr :: Int -> String
409 "takeBetween: the collecting fold terminated after"
410 ++ " consuming" ++ show i ++ " elements"
411 ++ " minimum" ++ show low ++ " elements needed"
413 -- Exactly the same as snext except different constructors, we can possibly
414 -- deduplicate the two.
420 let s1 = Tuple'Fused i1 s
422 -- XXX ideally this should be a Continue instead
423 then return $ IPartial s1
424 else IDone <$> extract foldErr s1
429 else IError (foldErr i1)
432 when (low >= 0 && high >= 0 && low > high)
433 $ throwM $ ParseError invalidRange
435 finitial >>= inext (-1)
437 -- Keep the impl same as inext
443 let s1 = Tuple'Fused i1 s
445 then return $ Continue 0 s1
446 else Done 0 <$> extract foldErr s1
451 else Error (foldErr i1)
453 step (Tuple'Fused i s) a = fstep s a >>= snext i
455 extract f (Tuple'Fused i s)
456 | i >= low && i <= high = fextract s
457 | otherwise = throwM $ ParseError (f i)
459-- | See 'Streamly.Internal.Data.Parser.takeEQ'.
464takeEQ :: MonadThrow m => Int -> Fold m a b -> Parser m a b
465takeEQ n (Fold fstep finitial fextract) = Parser step initial extract
474 FL.Partial s -> IPartial $ Tuple' 0 s
479 $ "takeEQ: Expecting exactly " ++ show cnt
480 ++ " elements, fold terminated without"
481 ++ " consuming any elements"
488 FL.Partial s -> Continue 0 $ Tuple' i1 s
491 $ "takeEQ: Expecting exactly " ++ show cnt
492 ++ " elements, fold terminated on " ++ show i1
497 FL.Partial s -> fextract s
498 FL.Done b -> return b
499 -- XXX we should not reach here when initial returns Step type
500 -- reachable only when n == 0
501 | otherwise = Done 1 <$> fextract r
508 | i == 0 && cnt == 0 = fextract r
512 $ "takeEQ: Expecting exactly " ++ show cnt
513 ++ " elements, input terminated on " ++ show i
515-- | See 'Streamly.Internal.Data.Parser.takeGE'.
520takeGE :: MonadThrow m => Int -> Fold m a b -> Parser m a b
521takeGE n (Fold fstep finitial fextract) = Parser step initial extract
529 FL.Partial s -> IPartial $ Tuple' 0 s
534 $ "takeGE: Expecting at least " ++ show cnt
535 ++ " elements, fold terminated without"
536 ++ " consuming any elements"
543 FL.Partial s -> Continue 0 $ Tuple' i1 s
546 $ "takeGE: Expecting at least " ++ show cnt
547 ++ " elements, fold terminated on " ++ show i1
552 FL.Partial s -> Partial 0 $ Tuple' i1 s
553 FL.Done b -> Done 0 b
560 | i >= cnt = fextract r
564 $ "takeGE: Expecting at least " ++ show cnt
565 ++ " elements, input terminated on " ++ show i
567-- | See 'Streamly.Internal.Data.Parser.takeWhile'.
571{-# INLINE takeWhile #-}
572takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
573takeWhile predicate (Fold fstep finitial fextract) =
574 Parser step initial fextract
581 FL.Partial s -> IPartial s
590 FL.Partial s1 -> Partial 0 s1
591 FL.Done b -> Done 0 b
592 else Done 1 <$> fextract s
594-- | See 'Streamly.Internal.Data.Parser.takeWhile1'.
598{-# INLINE takeWhile1 #-}
599takeWhile1 :: MonadThrow m => (a -> Bool) -> Fold m a b -> Parser m a b
600takeWhile1 predicate (Fold fstep finitial fextract) =
601 Parser step initial extract
608 FL.Partial s -> IPartial (Left s)
611 $ "takeWhile1: fold terminated without consuming:"
614 {-# INLINE process #-}
619 FL.Partial s1 -> Partial 0 (Right s1)
620 FL.Done b -> Done 0 b
625 else return $ Error "takeWhile1: predicate failed on first element"
633 extract (Left _) = throwM $ ParseError "takeWhile1: end of input"
634 extract (Right s) = fextract s
636-- | See 'Streamly.Internal.Data.Parser.sliceSepByP'.
640sliceSepByP :: MonadCatch m =>
641 (a -> Bool) -> Parser m a b -> Parser m a b
642sliceSepByP cond (Parser pstep pinitial pextract) =
644 Parser step initial pextract
657-- | See 'Streamly.Internal.Data.Parser.sliceBeginWith'.
661data SliceBeginWithState s = Left' s | Right' s
663{-# INLINE sliceBeginWith #-}
664sliceBeginWith :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
665sliceBeginWith cond (Fold fstep finitial fextract) =
667 Parser step initial extract
675 FL.Partial s -> IPartial (Left' s)
676 FL.Done _ -> IError "sliceBeginWith : bad finitial"
678 {-# INLINE process #-}
683 FL.Partial s1 -> Partial 0 (Right' s1)
684 FL.Done b -> Done 0 b
689 else error $ "sliceBeginWith : slice begins with an element which "
690 ++ "fails the predicate"
694 else Done 1 <$> fextract s
696 extract (Left' s) = fextract s
697 extract (Right' s) = fextract s
699data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
701-- | See 'Streamly.Internal.Data.Parser.wordBy'.
705wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
706wordBy predicate (Fold fstep finitial fextract) = Parser step initial extract
710 {-# INLINE worder #-}
715 FL.Partial s1 -> Partial 0 $ WBWord s1
716 FL.Done b -> Done 0 b
722 FL.Partial s -> IPartial $ WBLeft s
728 else return $ Partial 0 $ WBLeft s
734 return $ Partial 0 $ WBRight b
737 $ if not (predicate a)
739 else Partial 0 $ WBRight b
741 extract (WBLeft s) = fextract s
742 extract (WBWord s) = fextract s
743 extract (WBRight b) = return b
745{-# ANN type GroupByState Fuse #-}
748 | GroupByGrouping !a !s
750-- | See 'Streamly.Internal.Data.Parser.groupBy'.
752{-# INLINE groupBy #-}
753groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
754groupBy eq (Fold fstep finitial fextract) = Parser step initial extract
758 {-# INLINE grouper #-}
763 FL.Done b -> Done 0 b
764 FL.Partial s1 -> Partial 0 (GroupByGrouping a0 s1)
770 FL.Partial s -> IPartial $ GroupByInit s
773 step (GroupByInit s) a = grouper s a a
774 step (GroupByGrouping a0 s) a =
777 else Done 1 <$> fextract s
779 extract (GroupByInit s) = fextract s
780 extract (GroupByGrouping _ s) = fextract s
782-- | See 'Streamly.Internal.Data.Parser.groupByRolling'.
784{-# INLINE groupByRolling #-}
785groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
786groupByRolling eq (Fold fstep finitial fextract) = Parser step initial extract
790 {-# INLINE grouper #-}
795 FL.Done b -> Done 0 b
796 FL.Partial s1 -> Partial 0 (GroupByGrouping a s1)
802 FL.Partial s -> IPartial $ GroupByInit s
805 step (GroupByInit s) a = grouper s a
806 step (GroupByGrouping a0 s) a =
809 else Done 1 <$> fextract s
811 extract (GroupByInit s) = fextract s
812 extract (GroupByGrouping _ s) = fextract s
814{-# ANN type GroupByStatePair Fuse #-}
815data GroupByStatePair a s1 s2
816 = GroupByInitPair !s1 !s2
817 | GroupByGroupingPair !a !s1 !s2
818 | GroupByGroupingPairL !a !s1 !s2
819 | GroupByGroupingPairR !a !s1 !s2
821{-# INLINE groupByRollingEither #-}
822groupByRollingEither :: MonadCatch m =>
823 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (Either b c)
826 (Fold fstep1 finitial1 fextract1)
827 (Fold fstep2 finitial2 fextract2) = Parser step initial extract
831 {-# INLINE grouper #-}
833 return $ Continue 0 (GroupByGroupingPair a s1 s2)
835 {-# INLINE grouperL2 #-}
836 grouperL2 s1 s2 a = do
840 FL.Done b -> Done 0 (Left b)
841 FL.Partial s11 -> Partial 0 (GroupByGroupingPairL a s11 s2)
843 {-# INLINE grouperL #-}
844 grouperL s1 s2 a0 a = do
847 FL.Done b -> return $ Done 0 (Left b)
848 FL.Partial s11 -> grouperL2 s11 s2 a
850 {-# INLINE grouperR2 #-}
851 grouperR2 s1 s2 a = do
855 FL.Done b -> Done 0 (Right b)
856 FL.Partial s21 -> Partial 0 (GroupByGroupingPairR a s1 s21)
858 {-# INLINE grouperR #-}
859 grouperR s1 s2 a0 a = do
862 FL.Done b -> return $ Done 0 (Right b)
863 FL.Partial s21 -> grouperR2 s1 s21 a
872 FL.Partial s2 -> IPartial $ GroupByInitPair s1 s2
873 FL.Done b -> IDone (Right b)
874 FL.Done b -> IDone (Left b)
876 step (GroupByInitPair s1 s2) a = grouper s1 s2 a
878 step (GroupByGroupingPair a0 s1 s2) a =
880 then grouperL s1 s2 a0 a
881 else grouperR s1 s2 a0 a
883 step (GroupByGroupingPairL a0 s1 s2) a =
885 then grouperL2 s1 s2 a
886 else Done 1 . Left <$> fextract1 s1
888 step (GroupByGroupingPairR a0 s1 s2) a =
890 then grouperR2 s1 s2 a
891 else Done 1 . Right <$> fextract2 s2
893 extract (GroupByInitPair s1 _) = Left <$> fextract1 s1
894 extract (GroupByGroupingPairL _ s1 _) = Left <$> fextract1 s1
895 extract (GroupByGroupingPairR _ _ s2) = Right <$> fextract2 s2
896 extract (GroupByGroupingPair a s1 _) = do
899 FL.Done b -> return $ Left b
900 FL.Partial s11 -> Left <$> fextract1 s11
902-- XXX use an Unfold instead of a list?
903-- XXX custom combinators for matching list, array and stream?
904-- XXX rename to listBy?
906-- | See 'Streamly.Internal.Data.Parser.eqBy'.
911eqBy :: MonadThrow m => (a -> a -> Bool) -> [a] -> Parser m a ()
912eqBy cmp str = Parser step initial extract
916 -- XXX Should return IDone in initial for [] case
917 initial = return $ IPartial str
919 step [] _ = return $ Done 0 ()
924 else Error "eqBy: failed, yet to match the last element"
930 $ "eqBy: failed, yet to match "
931 ++ show (length xs + 1) ++ " elements"
936 $ "eqBy: end of input, yet to match "
937 ++ show (length xs) ++ " elements"
939-- XXX rename to streamBy?
940-- | Like eqBy but uses a stream instead of a list
941{-# INLINE matchBy #-}
942matchBy :: MonadThrow m => (a -> a -> Bool) -> D.Stream m a -> Parser m a ()
943matchBy cmp (D.Stream sstep state) = Parser step initial extract
948 r <- sstep defState state
950 D.Yield x s -> return $ IPartial (Just x, s)
951 D.Stop -> return $ IDone ()
952 -- Need Skip/Continue in initial to loop right here
953 D.Skip s -> return $ IPartial (Nothing, s)
955 step (Just x, st) a =
958 r <- sstep defState st
961 D.Yield x1 s -> Continue 0 (Just x1, s)
963 D.Skip s -> Continue 1 (Nothing, s)
964 else return $ Error "match: mismtach occurred"
965 step (Nothing, st) a = do
966 r <- sstep defState st
971 then Continue 0 (Nothing, s)
972 else Error "match: mismatch occurred"
974 D.Skip s -> Continue 1 (Nothing, s)
976 extract _ = throwM $ ParseError "match: end of input"
978--------------------------------------------------------------------------------
980--------------------------------------------------------------------------------
982-- | @span p f1 f2@ composes folds @f1@ and @f2@ such that @f1@ consumes the
983-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
987-- > let span_ p xs = Stream.parse (Parser.span p Fold.toList Fold.toList) $ Stream.fromList xs
989-- > span_ (< 1) [1,2,3]
992-- > span_ (< 2) [1,2,3]
995-- > span_ (< 4) [1,2,3]
1002span :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
1003span p f1 f2 = noErrorUnsafeSplitWith (,) (takeWhile p f1) (fromFold f2)
1005-- | Break the input stream into two groups, the first group takes the input as
1006-- long as the predicate applied to the first element of the stream and next
1007-- input element holds 'True', the second group takes the rest of the input.
1011{-# INLINE spanBy #-}
1014 => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
1015spanBy eq f1 f2 = noErrorUnsafeSplitWith (,) (groupBy eq f1) (fromFold f2)
1017-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
1018-- predicate is applied to the previous and the next input elements.
1021{-# INLINE spanByRolling #-}
1024 => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
1025spanByRolling eq f1 f2 =
1026 noErrorUnsafeSplitWith (,) (groupByRolling eq f1) (fromFold f2)
1028-------------------------------------------------------------------------------
1030-------------------------------------------------------------------------------
1032-- | See 'Streamly.Internal.Data.Parser.takeP'.
1036takeP :: Monad m => Int -> Parser m a b -> Parser m a b
1037takeP lim (Parser pstep pinitial pextract) = Parser step initial extract
1046 then return $ IPartial $ Tuple' 0 s
1047 else IDone <$> pextract s
1048 IDone b -> return $ IDone b
1049 IError e -> return $ IError e
1051 step (Tuple' cnt r) a = do
1052 assert (cnt < lim) (return ())
1057 assert (cnt1 >= 0) (return ())
1059 then return $ Partial 0 $ Tuple' cnt1 s
1060 else Done 0 <$> pextract s
1062 assert (cnt1 >= 0) (return ())
1064 then return $ Continue 0 $ Tuple' cnt1 s
1065 -- XXX This should error out?
1066 -- If designed properly, this will probably error out.
1067 -- "pextract" should error out
1071 -- This is a tricky case, we have the following options:
1072 -- 1. Done 0 with extract as you have written
1073 -- 2. Done n, will require buffering elements
1074 -- 3. Use a backtracking fold and not a parser, once we have
1075 -- backtracking in folds
1076 else Done 0 <$> pextract s
1078 let taken = cnt1 - n
1079 assert (taken >= 0) (return ())
1080 return $ Partial n $ Tuple' taken s
1082 let taken = cnt1 - n
1083 assert (taken >= 0) (return ())
1084 return $ Continue n $ Tuple' taken s
1085 Done n b -> return $ Done n b
1086 Error str -> return $ Error str
1088 extract (Tuple' _ r) = pextract r
1090-- | See 'Streamly.Internal.Data.Parser.lookahead'.
1094{-# INLINE lookAhead #-}
1095lookAhead :: MonadThrow m => Parser m a b -> Parser m a b
1096lookAhead (Parser step1 initial1 _) = Parser step initial extract
1102 return $ case res of
1103 IPartial s -> IPartial (Tuple' 0 s)
1105 IError e -> IError e
1107 step (Tuple' cnt st) a = do
1112 Partial n s -> Continue n (Tuple' (cnt1 - n) s)
1113 Continue n s -> Continue n (Tuple' (cnt1 - n) s)
1114 Done _ b -> Done cnt1 b
1115 Error err -> Error err
1117 -- XXX returning an error let's us backtrack. To implement it in a way so
1118 -- that it terminates on eof without an error then we need a way to
1119 -- backtrack on eof, that will require extract to return 'Step' type.
1120 extract (Tuple' n _) =
1123 $ "lookAhead: end of input after consuming "
1124 ++ show n ++ " elements"
1126-------------------------------------------------------------------------------
1128-------------------------------------------------------------------------------
1130-- | See 'Streamly.Internal.Data.Parser.deintercalate'.
1134{-# INLINE deintercalate #-}
1137 Fold m a y -> Parser m x a
1138 -> Fold m b z -> Parser m x b
1139 -> Parser m x (y, z)
1140deintercalate = undefined
1142-------------------------------------------------------------------------------
1143-- Sequential Collection
1144-------------------------------------------------------------------------------
1146-- | See 'Streamly.Internal.Data.Parser.sequence'.
1150{-# INLINE sequence #-}
1153 Fold m b c -> t (Parser m a b) -> Parser m a c
1154sequence _f _p = undefined
1156-------------------------------------------------------------------------------
1157-- Alternative Collection
1158-------------------------------------------------------------------------------
1160-- | See 'Streamly.Internal.Data.Parser.choice'.
1164{-# INLINE choice #-}
1165choice :: (MonadCatch m, Foldable t) => t (Parser m a b) -> Parser m a b
1166choice = foldl1 shortest
1168-------------------------------------------------------------------------------
1169-- Sequential Repetition
1170-------------------------------------------------------------------------------
1172-- | See 'Streamly.Internal.Data.Parser.many'.
1177many :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1179-- many = countBetween 0 maxBound
1181-- | See 'Streamly.Internal.Data.Parser.some'.
1186some :: MonadCatch m => Parser m a b -> Fold m b c -> Parser m a c
1188-- some f p = many (takeGE 1 f) p
1189-- many = countBetween 1 maxBound
1191-- | See 'Streamly.Internal.Data.Parser.countBetween'.
1195{-# INLINE countBetween #-}
1198 Int -> Int -> Parser m a b -> Fold m b c -> Parser m a c
1199countBetween _m _n _p = undefined
1200-- countBetween m n p f = many (takeBetween m n f) p
1202-- | See 'Streamly.Internal.Data.Parser.count'.
1209 Int -> Parser m a b -> Fold m b c -> Parser m a c
1210count n = countBetween n n
1211-- count n f p = many (takeEQ n f) p
1213data ManyTillState fs sr sl
1214 = ManyTillR Int fs sr
1215 | ManyTillL Int fs sl
1217-- | See 'Streamly.Internal.Data.Parser.manyTill'.
1221{-# INLINE manyTill #-}
1222manyTill :: MonadCatch m
1223 => Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1224manyTill (Fold fstep finitial fextract)
1225 (Parser stepL initialL extractL)
1226 (Parser stepR initialR _) =
1227 Parser step initial extract
1231 -- Caution: Mutual recursion
1233 scrutL fs p c d e = do
1236 IPartial sl -> return $ c (ManyTillL 0 fs sl)
1240 FL.Partial fs1 -> scrutR fs1 p c d e
1241 FL.Done fb -> return $ d fb
1242 IError err -> return $ e err
1244 scrutR fs p c d e = do
1247 IPartial sr -> return $ p (ManyTillR 0 fs sr)
1248 IDone _ -> d <$> fextract fs
1249 IError _ -> scrutL fs p c d e
1254 FL.Partial fs -> scrutR fs IPartial IPartial IDone IError
1255 FL.Done b -> return $ IDone b
1257 step (ManyTillR cnt fs st) a = do
1260 Partial n s -> return $ Partial n (ManyTillR 0 fs s)
1262 assert (cnt + 1 - n >= 0) (return ())
1263 return $ Continue n (ManyTillR (cnt + 1 - n) fs s)
1271 return $ Continue (cnt + 1) (ManyTillL 0 fs sl)
1279 FL.Partial fs1 -> scrutR fs1 p c d Error
1280 FL.Done fb -> return $ Done cnt1 fb
1281 IError err -> return $ Error err
1282 -- XXX the cnt is being used only by the assert
1283 step (ManyTillL cnt fs st) a = do
1286 Partial n s -> return $ Partial n (ManyTillL 0 fs s)
1288 assert (cnt + 1 - n >= 0) (return ())
1289 return $ Continue n (ManyTillL (cnt + 1 - n) fs s)
1294 scrutR s (Partial n) (Continue n) (Done n) Error
1295 FL.Done b1 -> return $ Done n b1
1296 Error err -> return $ Error err
1298 extract (ManyTillL _ fs sR) = do
1299 res <- extractL sR >>= fstep fs
1301 FL.Partial s -> fextract s
1302 FL.Done b -> return b
1303 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