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
53 -- Parsers chained in series, if one parser terminates the composition
54 -- terminates. Currently we are using folds to collect the output of the
55 -- parsers but we can use Parsers instead of folds to make the composition
56 -- more powerful. For example, we can do:
58 -- takeEndByOrMax cond n p = takeEndBy cond (take n p)
59 -- takeEndByBetween cond m n p = takeEndBy cond (takeBetween m n p)
60 -- takeWhileBetween cond m n p = takeWhile cond (takeBetween m n p)
62 -- Grab a sequence of input elements without inspecting them
64 -- , take -- take -- takeBetween 0 n
65 , takeEQ -- takeBetween n n
66 , takeGE -- takeBetween n maxBound
67 -- , takeGE1 -- take1 -- takeBetween 1 n
70 -- Grab a sequence of input elements by inspecting them
91 , groupByRollingEither
96 -- , prefixOf -- match any prefix of a given string
97 -- , suffixOf -- match any suffix of a given string
98 -- , infixOf -- match any substring of a given string
105 -- Second order parsers (parsers using parsers)
106 -- * Binary Combinators
108 -- ** Sequential Applicative
113 -- ** Parallel Applicatives
117 -- , teeTill -- like manyTill but parallel
120 -- ** Sequential Interleaving
121 -- Use two folds, run a primary parser, its rejected values go to the
126 -- ** Sequential Alternative
130 -- ** Parallel Alternatives
135 -- * N-ary Combinators
136 -- ** Sequential Collection
140 -- ** Sequential Repetition
143 -- , countBetweenTill
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.
156 -- We can instead implement these as special cases of deintercalate.
167 -- A simple and stupid impl would be to just convert the stream to an array
168 -- and give the array reference to all consumers. The array can be grown on
169 -- demand by any consumer and truncated when nonbody needs it.
171 -- -- ** Distribute to collection
172 -- -- ** Distribute to repetition
174 -- -- ** Interleaved collection
177 -- -- ** Interleaved repetition
178 -- repeat one parser and when it fails run an error recovery parser
179 -- e.g. to find a key frame in the stream after an error
181 -- ** Collection of Alternatives
184 -- , fastestN -- first N successful in time
185 -- , choiceN -- first N successful in position
186 -- , choice -- first successful in position
188 -- -- ** Repeated Alternatives
189 -- , retryMax -- try N times
190 -- , retryUntil -- try until successful
191 -- , retryUntilN -- try until successful n times
204import Control.Monad (when)
205import Data.Bifunctor (first)
206import Fusion.Plugin.Types (Fuse(..))
207import Streamly.Internal.Data.Fold.Type (Fold(..))
208import Streamly.Internal.Data.SVar.Type (defState)
209import Streamly.Internal.Data.Either.Strict (Either'(..))
210import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
211import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
213import qualified Streamly.Internal.Data.Fold.Type as FL
214import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
215import qualified Streamly.Internal.Data.Stream.StreamD.Generate as D
218 (any, all, take, takeWhile, sequence, concatMap, maybe, either, span
220-- import Streamly.Internal.Data.Parser.ParserD.Tee
221import Streamly.Internal.Data.Parser.ParserD.Type
226-- >>> :set -package streamly
227-- >>> import Prelude hiding ()
228-- >>> import qualified Data.Maybe as Maybe
229-- >>> import qualified Streamly.Data.Stream as Stream
230-- >>> import qualified Streamly.Internal.Data.Stream as Stream
231-- >>> import qualified Streamly.Data.Fold as Fold
232-- >>> import qualified Streamly.Internal.Data.Parser as Parser
234-------------------------------------------------------------------------------
235-- Downgrade a parser to a Fold
236-------------------------------------------------------------------------------
238-- | See 'Streamly.Internal.Data.Parser.toFold'.
243toFold :: Monad m => Parser m a b -> Fold m a b
244toFold (Parser pstep pinitial pextract) = Fold step initial extract
251 IPartial s -> return $ FL.Partial s
252 IDone b -> return $ FL.Done b
254 error $ "toFold: parser throws error in initial" ++ err
256 perror n = error $ "toFold: parser backtracks in Partial: " ++ show n
257 cerror n = error $ "toFold: parser backtracks in Continue: " ++ show n
258 derror n = error $ "toFold: parser backtracks in Done: " ++ show n
259 eerror err = error $ "toFold: parser throws error: " ++ err
264 Partial 0 s -> return $ FL.Partial s
265 Continue 0 s -> return $ FL.Partial s
266 Done 0 b -> return $ FL.Done b
267 Partial n _ -> perror n
268 Continue n _ -> cerror n
270 Error err -> eerror err
276 Partial n _ -> perror n
277 Continue n _ -> cerror n
279 Error err -> eerror err
281-------------------------------------------------------------------------------
282-- Upgrade folds to parses
283-------------------------------------------------------------------------------
285-- | See 'Streamly.Internal.Data.Parser.fromFold'.
289{-# INLINE fromFold #-}
290fromFold :: Monad m => Fold m a b -> Parser m a b
291fromFold (Fold fstep finitial fextract) = Parser step initial extract
299 FL.Partial s1 -> IPartial s1
306 FL.Partial s1 -> Partial 0 s1
307 FL.Done b -> Done 0 b
309 extract = fmap (Done 0) . fextract
311-- | Convert Maybe returning folds to error returning parsers.
315{-# INLINE fromFoldMaybe #-}
316fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser m a b
317fromFoldMaybe errMsg (Fold fstep finitial fextract) =
318 Parser step initial extract
326 FL.Partial s1 -> IPartial s1
330 Nothing -> IError errMsg
336 FL.Partial s1 -> Partial 0 s1
340 Nothing -> Error errMsg
345 Just x -> return $ Done 0 x
346 Nothing -> return $ Error errMsg
348-------------------------------------------------------------------------------
350-------------------------------------------------------------------------------
352-- | See 'Streamly.Internal.Data.Parser.peek'.
357peek :: Monad m => Parser m a a
358peek = Parser step initial extract
362 initial = return $ IPartial ()
364 step () a = return $ Done 1 a
366 extract () = return $ Error "peek: end of input"
368-- | See 'Streamly.Internal.Data.Parser.eof'.
373eof :: Monad m => Parser m a ()
374eof = Parser step initial extract
378 initial = return $ IPartial ()
380 step () _ = return $ Error "eof: not at end of input"
382 extract () = return $ Done 0 ()
384-- | See 'Streamly.Internal.Data.Parser.next'.
389next :: Monad m => Parser m a (Maybe a)
390next = Parser step initial extract
394 initial = pure $ IPartial ()
396 step () a = pure $ Done 0 (Just a)
398 extract () = pure $ Done 0 Nothing
400-- | See 'Streamly.Internal.Data.Parser.either'.
405either :: Monad m => (a -> Either String b) -> Parser m a b
406either f = Parser step initial extract
410 initial = return $ IPartial ()
415 Left err -> Error err
417 extract () = return $ Error "end of input"
419-- | See 'Streamly.Internal.Data.Parser.maybe'.
421-- >>> toEither = Maybe.maybe (Left "maybe: predicate failed") Right
422-- >>> maybe f = Parser.either (toEither . f)
427maybe :: Monad m => (a -> Maybe b) -> Parser m a b
428-- maybe f = either (Maybe.maybe (Left "maybe: predicate failed") Right . f)
429maybe parserF = Parser step initial extract
433 initial = return $ IPartial ()
438 Nothing -> Error "maybe: predicate failed"
440 extract () = return $ Error "maybe: end of input"
442-- | See 'Streamly.Internal.Data.Parser.satisfy'.
444-- >>> toMaybe f x = if f x then Just x else Nothing
445-- >>> satisfy f = Parser.maybe (toMaybe f)
449{-# INLINE satisfy #-}
450satisfy :: Monad m => (a -> Bool) -> Parser m a a
451-- satisfy predicate = maybe (\a -> if predicate a then Just a else Nothing)
452satisfy predicate = Parser step initial extract
456 initial = return $ IPartial ()
461 else Error "satisfy: predicate failed"
463 extract () = return $ Error "satisfy: end of input"
465-------------------------------------------------------------------------------
467-------------------------------------------------------------------------------
469-- Required to fuse "take" with "many" in "chunksOf", for ghc-9.x
470{-# ANN type Tuple'Fused Fuse #-}
471data Tuple'Fused a b = Tuple'Fused !a !b deriving Show
473-- | See 'Streamly.Internal.Data.Parser.takeBetween'.
477{-# INLINE takeBetween #-}
478takeBetween :: Monad m => Int -> Int -> Fold m a b -> Parser m a b
479takeBetween low high (Fold fstep finitial fextract) =
481 Parser step initial (extract streamErr)
486 "takeBetween: Expecting alteast " ++ show low
487 ++ " elements, got " ++ show i
490 "takeBetween: lower bound - " ++ show low
491 ++ " is greater than higher bound - " ++ show high
493 foldErr :: Int -> String
495 "takeBetween: the collecting fold terminated after"
496 ++ " consuming" ++ show i ++ " elements"
497 ++ " minimum" ++ show low ++ " elements needed"
499 -- Exactly the same as snext except different constructors, we can possibly
500 -- deduplicate the two.
506 let s1 = Tuple'Fused i1 s
508 -- XXX ideally this should be a Continue instead
509 then return $ IPartial s1
510 else iextract foldErr s1
515 else IError (foldErr i1)
518 when (low >= 0 && high >= 0 && low > high)
521 finitial >>= inext (-1)
523 -- Keep the impl same as inext
529 let s1 = Tuple'Fused i1 s
531 then return $ Continue 0 s1
532 else extract foldErr s1
537 else Error (foldErr i1)
539 step (Tuple'Fused i s) a = fstep s a >>= snext i
541 extract f (Tuple'Fused i s)
542 | i >= low && i <= high = fmap (Done 0) (fextract s)
543 | otherwise = return $ Error (f i)
545 -- XXX Need to make Initial return type Step to deduplicate this
546 iextract f (Tuple'Fused i s)
547 | i >= low && i <= high = fmap IDone (fextract s)
548 | otherwise = return $ IError (f i)
550-- | See 'Streamly.Internal.Data.Parser.takeEQ'.
555takeEQ :: Monad m => Int -> Fold m a b -> Parser m a b
556takeEQ n (Fold fstep finitial fextract) = Parser step initial extract
565 FL.Partial s -> IPartial $ Tuple' 0 s
570 $ "takeEQ: Expecting exactly " ++ show cnt
571 ++ " elements, fold terminated without"
572 ++ " consuming any elements"
579 FL.Partial s -> Continue 0 $ Tuple' i1 s
582 $ "takeEQ: Expecting exactly " ++ show cnt
583 ++ " elements, fold terminated on " ++ show i1
588 FL.Partial s -> fextract s
589 FL.Done b -> return b
590 -- XXX we should not reach here when initial returns Step type
591 -- reachable only when n == 0
592 | otherwise = Done 1 <$> fextract r
599 | i == 0 && cnt == 0 = fmap (Done 0) $ fextract r
603 $ "takeEQ: Expecting exactly " ++ show cnt
604 ++ " elements, input terminated on " ++ show i
606-- | See 'Streamly.Internal.Data.Parser.takeGE'.
611takeGE :: Monad m => Int -> Fold m a b -> Parser m a b
612takeGE n (Fold fstep finitial fextract) = Parser step initial extract
621 FL.Partial s -> IPartial $ Tuple' 0 s
626 $ "takeGE: Expecting at least " ++ show cnt
627 ++ " elements, fold terminated without"
628 ++ " consuming any elements"
635 FL.Partial s -> Continue 0 $ Tuple' i1 s
638 $ "takeGE: Expecting at least " ++ show cnt
639 ++ " elements, fold terminated on " ++ show i1
644 FL.Partial s -> Partial 0 $ Tuple' i1 s
645 FL.Done b -> Done 0 b
652 | i >= cnt = fmap (Done 0) $ fextract r
656 $ "takeGE: Expecting at least " ++ show cnt
657 ++ " elements, input terminated on " ++ show i
659-------------------------------------------------------------------------------
660-- Conditional splitting
661-------------------------------------------------------------------------------
663-- | See 'Streamly.Internal.Data.Parser.takeWhileP'.
667{-# INLINE takeWhileP #-}
668takeWhileP :: Monad m => (a -> Bool) -> Parser m a b -> Parser m a b
669takeWhileP predicate (Parser pstep pinitial pextract) =
670 Parser step pinitial pextract
679 -- XXX need a map on count
681 Error err -> return $ Error err
682 Done n s1 -> return $ Done (n + 1) s1
683 Partial _ _ -> error "Bug: takeWhileP: Partial in extract"
684 Continue n s1 -> return $ Continue (n + 1) s1
686-- | See 'Streamly.Internal.Data.Parser.takeWhile'.
690{-# INLINE takeWhile #-}
691takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
692takeWhile predicate (Fold fstep finitial fextract) =
693 Parser step initial extract
700 FL.Partial s -> IPartial s
709 FL.Partial s1 -> Partial 0 s1
710 FL.Done b -> Done 0 b
711 else Done 1 <$> fextract s
713 extract s = fmap (Done 0) (fextract s)
715-- | See 'Streamly.Internal.Data.Parser.takeWhile1'.
719{-# INLINE takeWhile1 #-}
720takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
721takeWhile1 predicate (Fold fstep finitial fextract) =
722 Parser step initial extract
729 FL.Partial s -> IPartial (Left' s)
732 $ "takeWhile1: fold terminated without consuming:"
735 {-# INLINE process #-}
740 FL.Partial s1 -> Partial 0 (Right' s1)
741 FL.Done b -> Done 0 b
746 else return $ Error "takeWhile1: predicate failed on first element"
754 extract (Left' _) = return $ Error "takeWhile1: end of input"
755 extract (Right' s) = fmap (Done 0) (fextract s)
757-------------------------------------------------------------------------------
759-------------------------------------------------------------------------------
761data FramedEscState s =
762 FrameEscInit !s | FrameEscGo !s !Int | FrameEscEsc !s !Int
764{-# INLINE takeFramedByGeneric #-}
765takeFramedByGeneric :: Monad m =>
771takeFramedByGeneric esc begin end (Fold fstep finitial fextract) =
773 Parser step initial extract
781 FL.Partial s -> IPartial (FrameEscInit s)
783 error "takeFramedByGeneric: fold done without input"
785 {-# INLINE process #-}
790 FL.Partial s1 -> Continue 0 (FrameEscGo s1 n)
791 FL.Done b -> Done 0 b
793 {-# INLINE processNoEsc #-}
803 then Done 0 <$> fextract s
804 else process s a (n - 1)
806 let n1 = if isBegin a then n + 1 else n
808 Nothing -> -- takeEndBy case
810 then Done 0 <$> fextract s
812 Nothing -> -- takeStartBy case
816 then Done 0 <$> fextract s
819 error $ "takeFramedByGeneric: "
820 ++ "Both begin and end frame predicate missing"
822 {-# INLINE processCheckEsc #-}
823 processCheckEsc s a n =
827 then return $ Partial 0 $ FrameEscEsc s n
828 else processNoEsc s a n
829 Nothing -> processNoEsc s a n
831 step (FrameEscInit s) a =
835 then return $ Partial 0 (FrameEscGo s 0)
836 else return $ Error "takeFramedByGeneric: missing frame start"
841 then Done 0 <$> fextract s
842 else processCheckEsc s a 0
844 error "Both begin and end frame predicate missing"
845 step (FrameEscGo s n) a = processCheckEsc s a n
846 step (FrameEscEsc s n) a = process s a n
850 extract (FrameEscInit _) =
851 err "takeFramedByGeneric: empty token"
852 extract (FrameEscGo s _) =
856 Nothing -> fmap (Done 0) $ fextract s
857 Just _ -> err "takeFramedByGeneric: missing frame end"
858 Nothing -> err "takeFramedByGeneric: missing closing frame"
859 extract (FrameEscEsc _ _) = err "takeFramedByGeneric: trailing escape"
861-- | See 'Streamly.Internal.Data.Parser.takeEndBy'.
865{-# INLINE takeEndBy #-}
866takeEndBy :: Monad m => (a -> Bool) -> Parser m a b -> Parser m a b
867takeEndBy cond (Parser pstep pinitial pextract) =
869 Parser step initial pextract
879 else extractStep pextract res
881-- | See 'Streamly.Internal.Data.Parser.takeEndByEsc'.
885{-# INLINE takeEndByEsc #-}
886takeEndByEsc :: Monad m =>
887 (a -> Bool) -> (a -> Bool) -> Parser m a b -> Parser m a b
888takeEndByEsc isEsc isSep (Parser pstep pinitial pextract) =
890 Parser step initial extract
894 initial = first Left' <$> pinitial
896 step (Left' s) a = do
898 then return $ Partial 0 $ Right' s
902 then return $ first Left' res
903 else fmap (first Left') $ extractStep pextract res
905 step (Right' s) a = do
907 return $ first Left' res
909 extract (Left' s) = fmap (first Left') $ pextract s
911 return $ Error "takeEndByEsc: trailing escape"
913-- | See 'Streamly.Internal.Data.Parser.takeEndBy_'.
917{-# INLINE takeEndBy_ #-}
918takeEndBy_ :: (a -> Bool) -> Parser m a b -> Parser m a b
919takeEndBy_ cond (Parser pstep pinitial pextract) =
921 Parser step pinitial pextract
930-- | See 'Streamly.Internal.Data.Parser.takeStartBy'.
935{-# INLINE takeStartBy #-}
936takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
937takeStartBy cond (Fold fstep finitial fextract) =
939 Parser step initial extract
947 FL.Partial s -> IPartial (Left' s)
948 FL.Done _ -> IError "takeStartBy: fold done without input"
950 {-# INLINE process #-}
955 FL.Partial s1 -> Partial 0 (Right' s1)
956 FL.Done b -> Done 0 b
961 else return $ Error "takeStartBy: missing frame start"
965 else Done 1 <$> fextract s
967 extract (Left' s) = fmap (Done 0) $ fextract s
968 extract (Right' s) = fmap (Done 0) $ fextract s
970{-# INLINE takeFramedByEsc_ #-}
971takeFramedByEsc_ :: Monad m =>
972 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
973takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial fextract) =
975 Parser step initial extract
983 FL.Partial s -> IPartial (FrameEscInit s)
985 error "takeFramedByEsc_: fold done without input"
987 {-# INLINE process #-}
992 FL.Partial s1 -> Continue 0 (FrameEscGo s1 n)
993 FL.Done b -> Done 0 b
995 step (FrameEscInit s) a =
997 then return $ Partial 0 (FrameEscGo s 0)
998 else return $ Error "takeFramedByEsc_: missing frame start"
999 step (FrameEscGo s n) a =
1001 then return $ Partial 0 $ FrameEscEsc s n
1005 let n1 = if isBegin a then n + 1 else n
1009 then Done 0 <$> fextract s
1010 else process s a (n - 1)
1011 step (FrameEscEsc s n) a = process s a n
1013 err = return . Error
1015 extract (FrameEscInit _) = err "takeFramedByEsc_: empty token"
1016 extract (FrameEscGo _ _) = err "takeFramedByEsc_: missing frame end"
1017 extract (FrameEscEsc _ _) = err "takeFramedByEsc_: trailing escape"
1019data FramedState s = FrameInit !s | FrameGo !s Int
1021{-# INLINE takeFramedBy_ #-}
1022takeFramedBy_ :: Monad m =>
1023 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
1024takeFramedBy_ isBegin isEnd (Fold fstep finitial fextract) =
1026 Parser step initial extract
1034 FL.Partial s -> IPartial (FrameInit s)
1036 error "takeFramedBy_: fold done without input"
1038 {-# INLINE process #-}
1043 FL.Partial s1 -> Continue 0 (FrameGo s1 n)
1044 FL.Done b -> Done 0 b
1046 step (FrameInit s) a =
1048 then return $ Continue 0 (FrameGo s 0)
1049 else return $ Error "takeFramedBy_: missing frame start"
1050 step (FrameGo s n) a
1052 let n1 = if isBegin a then n + 1 else n
1054 | n == 0 = Done 0 <$> fextract s
1055 | otherwise = process s a (n - 1)
1057 err = return . Error
1059 extract (FrameInit _) = err "takeFramedBy_: empty token"
1060 extract (FrameGo _ _) = err "takeFramedBy_: missing frame end"
1062-------------------------------------------------------------------------------
1063-- Grouping and words
1064-------------------------------------------------------------------------------
1066data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
1068-- | See 'Streamly.Internal.Data.Parser.wordBy'.
1071{-# INLINE wordBy #-}
1072wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
1073wordBy predicate (Fold fstep finitial fextract) = Parser step initial extract
1077 {-# INLINE worder #-}
1082 FL.Partial s1 -> Partial 0 $ WBWord s1
1083 FL.Done b -> Done 0 b
1089 FL.Partial s -> IPartial $ WBLeft s
1090 FL.Done b -> IDone b
1093 if not (predicate a)
1095 else return $ Partial 0 $ WBLeft s
1097 if not (predicate a)
1101 return $ Partial 0 $ WBRight b
1102 step (WBRight b) a =
1104 $ if not (predicate a)
1106 else Partial 0 $ WBRight b
1108 extract (WBLeft s) = fmap (Done 0) $ fextract s
1109 extract (WBWord s) = fmap (Done 0) $ fextract s
1110 extract (WBRight b) = return (Done 0 b)
1112data WordFramedState s b =
1113 WordFramedSkipPre !s
1114 | WordFramedWord !s !Int
1115 | WordFramedEsc !s !Int
1116 | WordFramedSkipPost !b
1118-- | See 'Streamly.Internal.Data.Parser.wordFramedBy'
1120{-# INLINE wordFramedBy #-}
1121wordFramedBy :: Monad m =>
1122 (a -> Bool) -- ^ Escape
1123 -> (a -> Bool) -- ^ left quote
1124 -> (a -> Bool) -- ^ right quote
1125 -> (a -> Bool) -- ^ word seperator
1128wordFramedBy isEsc isBegin isEnd isSep
1129 (Fold fstep finitial fextract) =
1130 Parser step initial extract
1138 FL.Partial s -> IPartial (WordFramedSkipPre s)
1140 error "wordFramedBy: fold done without input"
1142 {-# INLINE process #-}
1147 FL.Partial s1 -> Continue 0 (WordFramedWord s1 n)
1148 FL.Done b -> Done 0 b
1150 step (WordFramedSkipPre s) a
1151 | isEsc a = return $ Continue 0 $ WordFramedEsc s 0
1152 | isSep a = return $ Partial 0 $ WordFramedSkipPre s
1153 | isBegin a = return $ Continue 0 $ WordFramedWord s 1
1155 return $ Error "wordFramedBy: missing frame start"
1156 | otherwise = process s a 0
1157 step (WordFramedWord s n) a
1158 | isEsc a = return $ Continue 0 $ WordFramedEsc s n
1159 | n == 0 && isSep a = do
1161 return $ Partial 0 $ WordFramedSkipPost b
1163 -- We need to use different order for checking begin and end for
1164 -- the n == 0 and n == 1 case so that when the begin and end
1165 -- character is the same we treat the one after begin as end.
1168 -- Need to check isBegin first
1170 then return $ Continue 0 $ WordFramedWord s 1
1172 then return $ Error "wordFramedBy: missing frame start"
1175 -- Need to check isEnd first
1179 then return $ Continue 0 $ WordFramedWord s 0
1180 else process s a (n - 1)
1182 then process s a (n + 1)
1184 step (WordFramedEsc s n) a = process s a n
1185 step (WordFramedSkipPost b) a =
1189 else Partial 0 $ WordFramedSkipPost b
1191 err = return . Error
1193 extract (WordFramedSkipPre s) = fmap (Done 0) $ fextract s
1194 extract (WordFramedWord s n) =
1196 then fmap (Done 0) $ fextract s
1197 else err "wordFramedBy: missing frame end"
1198 extract (WordFramedEsc _ _) =
1199 err "wordFramedBy: trailing escape"
1200 extract (WordFramedSkipPost b) = return (Done 0 b)
1202data WordQuotedState s b a =
1203 WordQuotedSkipPre !s
1204 | WordUnquotedWord !s
1205 | WordQuotedWord !s !Int a
1206 | WordUnquotedEsc !s
1207 | WordQuotedEsc !s !Int a
1208 | WordQuotedSkipPost !b
1210{-# INLINE wordQuotedBy #-}
1211wordQuotedBy :: (Monad m, Eq a) =>
1212 Bool -- ^ keep the quotes in the output
1213 -> (a -> Bool) -- ^ Escape
1214 -> (a -> Bool) -- ^ left quote
1215 -> (a -> Bool) -- ^ right quote
1216 -> (a -> a) -- ^ get right quote from the left quote
1217 -> (a -> Bool) -- ^ word seperator
1220wordQuotedBy keepQuotes isEsc isBegin isEnd toRight isSep
1221 (Fold fstep finitial fextract) =
1222 Parser step initial extract
1230 FL.Partial s -> IPartial (WordQuotedSkipPre s)
1232 error "wordQuotedBy: fold done without input"
1234 {-# INLINE process #-}
1235 process s a n q = do
1239 FL.Partial s1 -> Continue 0 (WordQuotedWord s1 n q)
1240 FL.Done b -> Done 0 b
1242 {-# INLINE processUnquoted #-}
1243 processUnquoted s a = do
1247 FL.Partial s1 -> Continue 0 (WordUnquotedWord s1)
1248 FL.Done b -> Done 0 b
1250 step (WordQuotedSkipPre s) a
1251 | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1252 | isSep a = return $ Partial 0 $ WordQuotedSkipPre s
1255 then process s a 1 a
1256 else return $ Continue 0 $ WordQuotedWord s 1 a
1258 return $ Error "wordQuotedBy: missing frame start"
1259 | otherwise = processUnquoted s a
1260 step (WordUnquotedWord s) a
1261 | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1264 return $ Partial 0 $ WordQuotedSkipPost b
1268 then process s a 1 a
1269 else return $ Continue 0 $ WordQuotedWord s 1 a
1271 then return $ Error "wordQuotedBy: missing frame start"
1272 else processUnquoted s a
1273 step (WordQuotedWord s n q) a
1274 | isEsc a = return $ Continue 0 $ WordQuotedEsc s n q
1275 -- XXX Will this ever occur? Will n ever be 0?
1276 | n == 0 && isSep a = do
1278 return $ Partial 0 $ WordQuotedSkipPost b
1284 then processUnquoted s a
1285 else return $ Continue 0 $ WordUnquotedWord s
1286 else process s a (n - 1) q
1288 then process s a (n + 1) q
1289 else process s a n q
1290 step (WordUnquotedEsc s) a = processUnquoted s a
1291 step (WordQuotedEsc s n q) a = process s a n q
1292 step (WordQuotedSkipPost b) a =
1296 else Partial 0 $ WordQuotedSkipPost b
1298 err = return . Error
1300 extract (WordQuotedSkipPre s) = fmap (Done 0) $ fextract s
1301 extract (WordUnquotedWord s) = fmap (Done 0) $ fextract s
1302 extract (WordQuotedWord s n _) =
1304 then fmap (Done 0) $ fextract s
1305 else err "wordQuotedBy: missing frame end"
1306 extract WordQuotedEsc {} =
1307 err "wordQuotedBy: trailing escape"
1308 extract (WordUnquotedEsc _) =
1309 err "wordQuotedBy: trailing escape"
1310 extract (WordQuotedSkipPost b) = return (Done 0 b)
1312{-# ANN type GroupByState Fuse #-}
1313data GroupByState a s
1315 | GroupByGrouping !a !s
1317-- | See 'Streamly.Internal.Data.Parser.groupBy'.
1319{-# INLINE groupBy #-}
1320groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
1321groupBy eq (Fold fstep finitial fextract) = Parser step initial extract
1325 {-# INLINE grouper #-}
1330 FL.Done b -> Done 0 b
1331 FL.Partial s1 -> Partial 0 (GroupByGrouping a0 s1)
1337 FL.Partial s -> IPartial $ GroupByInit s
1338 FL.Done b -> IDone b
1340 step (GroupByInit s) a = grouper s a a
1341 step (GroupByGrouping a0 s) a =
1344 else Done 1 <$> fextract s
1346 extract (GroupByInit s) = fmap (Done 0) $ fextract s
1347 extract (GroupByGrouping _ s) = fmap (Done 0) $ fextract s
1349-- | See 'Streamly.Internal.Data.Parser.groupByRolling'.
1351{-# INLINE groupByRolling #-}
1352groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser m a b
1353groupByRolling eq (Fold fstep finitial fextract) = Parser step initial extract
1357 {-# INLINE grouper #-}
1362 FL.Done b -> Done 0 b
1363 FL.Partial s1 -> Partial 0 (GroupByGrouping a s1)
1369 FL.Partial s -> IPartial $ GroupByInit s
1370 FL.Done b -> IDone b
1372 step (GroupByInit s) a = grouper s a
1373 step (GroupByGrouping a0 s) a =
1376 else Done 1 <$> fextract s
1378 extract (GroupByInit s) = fmap (Done 0) $ fextract s
1379 extract (GroupByGrouping _ s) = fmap (Done 0) $ fextract s
1381{-# ANN type GroupByStatePair Fuse #-}
1382data GroupByStatePair a s1 s2
1383 = GroupByInitPair !s1 !s2
1384 | GroupByGroupingPair !a !s1 !s2
1385 | GroupByGroupingPairL !a !s1 !s2
1386 | GroupByGroupingPairR !a !s1 !s2
1388{-# INLINE groupByRollingEither #-}
1389groupByRollingEither :: Monad m =>
1390 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (Either b c)
1393 (Fold fstep1 finitial1 fextract1)
1394 (Fold fstep2 finitial2 fextract2) = Parser step initial extract
1398 {-# INLINE grouper #-}
1399 grouper s1 s2 a = do
1400 return $ Continue 0 (GroupByGroupingPair a s1 s2)
1402 {-# INLINE grouperL2 #-}
1403 grouperL2 s1 s2 a = do
1407 FL.Done b -> Done 0 (Left b)
1408 FL.Partial s11 -> Partial 0 (GroupByGroupingPairL a s11 s2)
1410 {-# INLINE grouperL #-}
1411 grouperL s1 s2 a0 a = do
1414 FL.Done b -> return $ Done 0 (Left b)
1415 FL.Partial s11 -> grouperL2 s11 s2 a
1417 {-# INLINE grouperR2 #-}
1418 grouperR2 s1 s2 a = do
1422 FL.Done b -> Done 0 (Right b)
1423 FL.Partial s21 -> Partial 0 (GroupByGroupingPairR a s1 s21)
1425 {-# INLINE grouperR #-}
1426 grouperR s1 s2 a0 a = do
1429 FL.Done b -> return $ Done 0 (Right b)
1430 FL.Partial s21 -> grouperR2 s1 s21 a
1439 FL.Partial s2 -> IPartial $ GroupByInitPair s1 s2
1440 FL.Done b -> IDone (Right b)
1441 FL.Done b -> IDone (Left b)
1443 step (GroupByInitPair s1 s2) a = grouper s1 s2 a
1445 step (GroupByGroupingPair a0 s1 s2) a =
1447 then grouperL s1 s2 a0 a
1448 else grouperR s1 s2 a0 a
1450 step (GroupByGroupingPairL a0 s1 s2) a =
1452 then grouperL2 s1 s2 a
1453 else Done 1 . Left <$> fextract1 s1
1455 step (GroupByGroupingPairR a0 s1 s2) a =
1457 then grouperR2 s1 s2 a
1458 else Done 1 . Right <$> fextract2 s2
1460 extract (GroupByInitPair s1 _) = Done 0 . Left <$> fextract1 s1
1461 extract (GroupByGroupingPairL _ s1 _) = Done 0 . Left <$> fextract1 s1
1462 extract (GroupByGroupingPairR _ _ s2) = Done 0 . Right <$> fextract2 s2
1463 extract (GroupByGroupingPair a s1 _) = do
1466 FL.Done b -> return $ Done 0 (Left b)
1467 FL.Partial s11 -> Done 0 . Left <$> fextract1 s11
1469-- XXX use an Unfold instead of a list?
1470-- XXX custom combinators for matching list, array and stream?
1471-- XXX rename to listBy?
1473-- | See 'Streamly.Internal.Data.Parser.eqBy'.
1477{-# INLINE listEqBy #-}
1478listEqBy :: Monad m => (a -> a -> Bool) -> [a] -> Parser m a [a]
1479listEqBy cmp str = Parser step initial extract
1483 -- XXX Should return IDone in initial for [] case
1484 initial = return $ IPartial str
1486 step [] _ = return $ Done 0 str
1491 else Error "listEqBy: failed, yet to match the last element"
1497 $ "listEqBy: failed, yet to match "
1498 ++ show (length xs + 1) ++ " elements"
1503 $ "listEqBy: end of input, yet to match "
1504 ++ show (length xs) ++ " elements"
1506-- | Like 'listEqBy' but uses a stream instead of a list
1508eqBy :: Monad m => (a -> a -> Bool) -> D.Stream m a -> Parser m a ()
1509eqBy cmp (D.Stream sstep state) = Parser step initial extract
1514 r <- sstep defState state
1516 D.Yield x s -> return $ IPartial (Just' x, s)
1517 D.Stop -> return $ IDone ()
1518 -- Need Skip/Continue in initial to loop right here
1519 D.Skip s -> return $ IPartial (Nothing', s)
1521 step (Just' x, st) a =
1524 r <- sstep defState st
1527 D.Yield x1 s -> Continue 0 (Just' x1, s)
1529 D.Skip s -> Continue 1 (Nothing', s)
1530 else return $ Error "eqBy: mismtach occurred"
1531 step (Nothing', st) a = do
1532 r <- sstep defState st
1537 then Continue 0 (Nothing', s)
1538 else Error "eqBy: mismatch occurred"
1540 D.Skip s -> Continue 1 (Nothing', s)
1542 extract _ = return $ Error "eqBy: end of input"
1544-------------------------------------------------------------------------------
1545-- Transformations on input
1546-------------------------------------------------------------------------------
1548-- Initial needs a "Continue" constructor to implement scans on parsers. As a
1549-- parser can always return a Continue in initial when we feed the fold's
1550-- initial result to it. We can work this around for postscan by introducing an
1551-- initial state and calling "initial" only on the first input.
1553-- | Stateful scan on the input of a parser using a Fold.
1557{-# INLINE postscan #-}
1558postscan :: -- Monad m =>
1559 Fold m a b -> Parser m b c -> Parser m a c
1562{-# INLINE zipWithM #-}
1563zipWithM :: Monad m =>
1564 (a -> b -> m c) -> D.Stream m a -> Fold m c x -> Parser m b x
1565zipWithM zf (D.Stream sstep state) (Fold fstep finitial fextract) =
1566 Parser step initial extract
1574 r <- sstep defState state
1576 D.Yield x s -> return $ IPartial (Just' x, s, fs)
1580 -- Need Skip/Continue in initial to loop right here
1581 D.Skip s -> return $ IPartial (Nothing', s, fs)
1582 FL.Done x -> return $ IDone x
1584 step (Just' a, st, fs) b = do
1588 FL.Partial fs1 -> do
1589 r <- sstep defState st
1591 D.Yield x1 s -> return $ Continue 0 (Just' x1, s, fs1)
1595 D.Skip s -> return $ Continue 1 (Nothing', s, fs1)
1596 FL.Done x -> return $ Done 0 x
1597 step (Nothing', st, fs) b = do
1598 r <- sstep defState st
1605 return $ Continue 0 (Nothing', s, fs1)
1606 FL.Done x -> return $ Done 0 x
1610 D.Skip s -> return $ Continue 1 (Nothing', s, fs)
1612 extract _ = return $ Error "zipWithM: end of input"
1614-- | Zip the input of a fold with a stream.
1619zip :: Monad m => D.Stream m a -> Fold m (a, b) x -> Parser m b x
1620zip = zipWithM (curry return)
1622-- | Pair each element of a fold input with its index, starting from index 0.
1625{-# INLINE indexed #-}
1626indexed :: forall m a b. Monad m => Fold m (Int, a) b -> Parser m a b
1627indexed = zip (D.enumerateFromIntegral 0 :: D.Stream m Int)
1629-- | @makeIndexFilter indexer filter predicate@ generates a fold filtering
1630-- function using a fold indexing function that attaches an index to each input
1631-- element and a filtering function that filters using @(index, element) ->
1632-- Bool) as predicate.
1637-- filterWithIndex = makeIndexFilter indexed filter
1638-- filterWithAbsTime = makeIndexFilter timestamped filter
1639-- filterWithRelTime = makeIndexFilter timeIndexed filter
1643{-# INLINE makeIndexFilter #-}
1645 (Fold m (s, a) b -> Parser m a b)
1646 -> (((s, a) -> Bool) -> Fold m (s, a) b -> Fold m (s, a) b)
1647 -> (((s, a) -> Bool) -> Fold m a b -> Parser m a b)
1648makeIndexFilter f comb g = f . comb g . FL.lmap snd
1650-- | @sampleFromthen offset stride@ samples the element at @offset@ index and
1651-- then every element at strides of @stride@.
1654{-# INLINE sampleFromthen #-}
1655sampleFromthen :: Monad m => Int -> Int -> Fold m a b -> Parser m a b
1656sampleFromthen offset size =
1657 makeIndexFilter indexed FL.filter (\(i, _) -> (i + offset) `mod` size == 0)
1659--------------------------------------------------------------------------------
1661--------------------------------------------------------------------------------
1663-- | @span p f1 f2@ composes folds @f1@ and @f2@ such that @f1@ consumes the
1664-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
1668-- > let span_ p xs = Stream.parse (Parser.span p Fold.toList Fold.toList) $ Stream.fromList xs
1670-- > span_ (< 1) [1,2,3]
1673-- > span_ (< 2) [1,2,3]
1676-- > span_ (< 4) [1,2,3]
1683span :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
1684span p f1 f2 = noErrorUnsafeSplitWith (,) (takeWhile p f1) (fromFold f2)
1686-- | Break the input stream into two groups, the first group takes the input as
1687-- long as the predicate applied to the first element of the stream and next
1688-- input element holds 'True', the second group takes the rest of the input.
1692{-# INLINE spanBy #-}
1695 => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
1696spanBy eq f1 f2 = noErrorUnsafeSplitWith (,) (groupBy eq f1) (fromFold f2)
1698-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
1699-- predicate is applied to the previous and the next input elements.
1702{-# INLINE spanByRolling #-}
1705 => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (b, c)
1706spanByRolling eq f1 f2 =
1707 noErrorUnsafeSplitWith (,) (groupByRolling eq f1) (fromFold f2)
1709-------------------------------------------------------------------------------
1711-------------------------------------------------------------------------------
1713-- | See 'Streamly.Internal.Data.Parser.takeP'.
1717takeP :: Monad m => Int -> Parser m a b -> Parser m a b
1718takeP lim (Parser pstep pinitial pextract) = Parser step initial extract
1727 then return $ IPartial $ Tuple' 0 s
1729 IDone b -> return $ IDone b
1730 IError e -> return $ IError e
1732 step (Tuple' cnt r) a = do
1740 then return $ Partial 0 $ Tuple' cnt1 s
1744 Done n b -> Done n b
1745 Continue n s1 -> Continue n (Tuple' (cnt1 - n) s1)
1746 Error err -> Error err
1747 Partial _ _ -> error "takeP: Partial in extract"
1752 then return $ Continue 0 $ Tuple' cnt1 s
1756 Done n b -> Done n b
1757 Continue n s1 -> Continue n (Tuple' (cnt1 - n) s1)
1758 Error err -> Error err
1759 Partial _ _ -> error "takeP: Partial in extract"
1761 let taken = cnt1 - n
1763 return $ Partial n $ Tuple' taken s
1765 let taken = cnt1 - n
1767 return $ Continue n $ Tuple' taken s
1768 Done n b -> return $ Done n b
1769 Error str -> return $ Error str
1771 extract (Tuple' cnt r) = do
1774 Done n b -> Done n b
1775 Continue n s1 -> Continue n (Tuple' (cnt - n) s1)
1776 Error err -> Error err
1777 Partial _ _ -> error "takeP: Partial in extract"
1779 -- XXX Need to make the Initial type Step to remove this
1784 Error err -> IError err
1785 _ -> error "Bug: takeP invalid state in initial"
1787-- | See 'Streamly.Internal.Data.Parser.lookahead'.
1791{-# INLINE lookAhead #-}
1792lookAhead :: Monad m => Parser m a b -> Parser m a b
1793lookAhead (Parser step1 initial1 _) = Parser step initial extract
1799 return $ case res of
1800 IPartial s -> IPartial (Tuple' 0 s)
1802 IError e -> IError e
1804 step (Tuple' cnt st) a = do
1809 Partial n s -> Continue n (Tuple' (cnt1 - n) s)
1810 Continue n s -> Continue n (Tuple' (cnt1 - n) s)
1811 Done _ b -> Done cnt1 b
1812 Error err -> Error err
1814 -- XXX returning an error let's us backtrack. To implement it in a way so
1815 -- that it terminates on eof without an error then we need a way to
1816 -- backtrack on eof, that will require extract to return 'Step' type.
1817 extract (Tuple' n _) =
1820 $ "lookAhead: end of input after consuming "
1821 ++ show n ++ " elements"
1823-------------------------------------------------------------------------------
1825-------------------------------------------------------------------------------
1827data DeintercalateState fs sp ss =
1828 DeintercalateL !fs !sp
1829 | DeintercalateR !fs !ss !Bool
1831-- | See 'Streamly.Internal.Data.Parser.deintercalate'.
1835{-# INLINE deintercalate #-}
1836deintercalate :: Monad m =>
1839 -> Fold m (Either x y) z
1842 (Parser stepL initialL extractL)
1843 (Parser stepR initialR extractR)
1844 (Fold fstep finitial fextract) = Parser step initial extract
1849 error $ "deintercalate: " ++ p ++ " parser cannot "
1850 ++ status ++ " without input"
1858 IPartial sL -> return $ IPartial $ DeintercalateL fs sL
1859 IDone _ -> errMsg "left" "succeed"
1860 IError _ -> errMsg "left" "fail"
1861 FL.Done c -> return $ IDone c
1863 step (DeintercalateL fs sL) a = do
1866 Partial n s -> return $ Partial n (DeintercalateL fs s)
1867 Continue n s -> return $ Continue n (DeintercalateL fs s)
1869 fres <- fstep fs (Left b)
1871 FL.Partial fs1 -> do
1876 $ Partial n (DeintercalateR fs1 sR False)
1877 IDone _ -> errMsg "right" "succeed"
1878 IError _ -> errMsg "right" "fail"
1879 FL.Done c -> return $ Done n c
1880 Error err -> return $ Error err
1881 step (DeintercalateR fs sR consumed) a = do
1884 Partial n s -> return $ Partial n (DeintercalateR fs s True)
1885 Continue n s -> return $ Continue n (DeintercalateR fs s True)
1889 fres <- fstep fs (Right b)
1891 FL.Partial fs1 -> do
1895 return $ Partial n $ DeintercalateL fs1 sL
1896 IDone _ -> errMsg "left" "succeed"
1897 IError _ -> errMsg "left" "fail"
1898 FL.Done c -> return $ Done n c
1899 else error "deintercalate: infinite loop"
1900 Error err -> return $ Error err
1902 {-# INLINE processResult #-}
1903 processResult n fs r = do
1906 FL.Partial fs1 -> fmap (Done n) $ fextract fs1
1907 FL.Done c -> return (Done n c)
1909 extract (DeintercalateL fs sL) = do
1912 Done n b -> processResult n fs (Left b)
1913 Error err -> return $ Error err
1914 Continue n s -> return $ Continue n (DeintercalateL fs s)
1915 Partial _ _ -> error "Partial in extract"
1917 extract (DeintercalateR fs sR consumed) = do
1920 Done n b -> processResult n fs (Right b)
1921 Error err -> return $ Error err
1922 -- XXX Review consumed
1923 Continue n s -> return $ Continue n (DeintercalateR fs s consumed)
1924 Partial _ _ -> error "Partial in extract"
1926data SepByState fs sp ss =
1928 | SepBySeparator !fs !ss !Bool
1930-- This is a special case of deintercalate and can be easily implemented in
1931-- terms of deintercalate.
1934 Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
1936 (Parser pstep pinitial pextract)
1937 (Parser sstep sinitial _)
1938 (Fold fstep finitial fextract) = Parser step initial extract
1943 error $ "sepBy: " ++ p ++ " parser cannot "
1944 ++ status ++ " without input"
1952 IPartial sp -> return $ IPartial $ SepByInit fs sp
1953 IDone _ -> errMsg "content" "succeed"
1954 IError _ -> errMsg "content" "fail"
1955 FL.Done b -> return $ IDone b
1957 step (SepByInit fs sp) a = do
1960 Partial n s -> return $ Partial n (SepByInit fs s)
1961 Continue n s -> return $ Continue n (SepByInit fs s)
1965 FL.Partial fs1 -> do
1969 return $ Partial n (SepBySeparator fs1 ss False)
1970 IDone _ -> errMsg "separator" "succeed"
1971 IError _ -> errMsg "separator" "fail"
1972 FL.Done c -> return $ Done n c
1973 Error err -> return $ Error err
1974 step (SepBySeparator fs ss consumed) a = do
1977 Partial n s -> return $ Partial n (SepBySeparator fs s True)
1978 Continue n s -> return $ Continue n (SepBySeparator fs s True)
1984 IPartial sp -> return $ Partial n $ SepByInit fs sp
1985 IDone _ -> errMsg "content" "succeed"
1986 IError _ -> errMsg "content" "fail"
1987 else error "sepBy: infinite loop"
1988 Error err -> return $ Error err
1990 extract (SepByInit fs sp) = do
1996 FL.Partial fs1 -> fmap (Done n) $ fextract fs1
1997 FL.Done c -> return (Done n c)
1998 Error err -> return $ Error err
1999 Continue n s -> return $ Continue n (SepByInit fs s)
2000 Partial _ _ -> error "Partial in extract"
2002 extract (SepBySeparator fs _ _) = fmap (Done 0) $ fextract fs
2004-------------------------------------------------------------------------------
2005-- Sequential Collection
2006-------------------------------------------------------------------------------
2008-- | See 'Streamly.Internal.Data.Parser.sequence'.
2009{-# INLINE sequence #-}
2010sequence :: Monad m =>
2011 D.Stream m (Parser m a b) -> Fold m b c -> Parser m a c
2012sequence (D.Stream sstep sstate) (Fold fstep finitial fextract) =
2013 Parser step initial extract
2020 FL.Partial fs -> return $ IPartial (Nothing', sstate, fs)
2021 FL.Done c -> return $ IDone c
2023 -- state does not contain any parser
2024 -- yield a new parser from the stream
2025 step (Nothing', ss, fs) _ = do
2026 sres <- sstep defState ss
2028 D.Yield p ss1 -> return $ Continue 1 (Just' p, ss1, fs)
2032 D.Skip ss1 -> return $ Continue 1 (Nothing', ss1, fs)
2034 -- state holds a parser that may or may not have been
2035 -- initialized. pinit holds the initial parser state
2036 -- or modified parser state respectively
2037 step (Just' (Parser pstep pinit pextr), ss, fs) a = do
2045 Just' $ Parser pstep (return $ IPartial ps2) pextr
2046 in return $ Partial n (newP, ss, fs)
2049 Just' $ Parser pstep (return $ IPartial ps2) pextr
2050 in return $ Continue n (newP, ss, fs)
2055 return $ Partial n (Nothing', ss, fs1)
2056 FL.Done c -> return $ Done n c
2057 Error msg -> return $ Error msg
2062 return $ Partial 1 (Nothing', ss, fs1)
2063 FL.Done c -> return $ Done 1 c
2064 IError err -> return $ Error err
2066 extract (Nothing', _, fs) = fmap (Done 0) $ fextract fs
2067 extract (Just' (Parser pstep pinit pextr), ss, fs) = do
2076 FL.Partial fs1 -> fmap (Done n) $ fextract fs1
2077 FL.Done c -> return (Done n c)
2078 Error err -> return $ Error err
2079 Continue n s -> return $ Continue n (Just' (Parser pstep (return (IPartial s)) pextr), ss, fs)
2080 Partial _ _ -> error "Partial in extract"
2084 FL.Partial fs1 -> fmap (Done 0) $ fextract fs1
2085 FL.Done c -> return (Done 0 c)
2086 IError err -> return $ Error err
2088-------------------------------------------------------------------------------
2089-- Alternative Collection
2090-------------------------------------------------------------------------------
2093-- | See 'Streamly.Internal.Data.Parser.choice'.
2097{-# INLINE choice #-}
2098choice :: (MonadCatch m, Foldable t) => t (Parser m a b) -> Parser m a b
2099choice = foldl1 shortest
2102-------------------------------------------------------------------------------
2103-- Sequential Repetition
2104-------------------------------------------------------------------------------
2107manyP :: -- MonadCatch m =>
2108 Parser m a b -> Parser m b c -> Parser m a c
2109manyP _p _f = undefined
2111-- | See 'Streamly.Internal.Data.Parser.many'.
2116many :: Monad m => Parser m a b -> Fold m b c -> Parser m a c
2118-- many = countBetween 0 maxBound
2120-- | See 'Streamly.Internal.Data.Parser.some'.
2125some :: Monad m => Parser m a b -> Fold m b c -> Parser m a c
2127-- some p f = manyP p (takeGE 1 f)
2128-- some = countBetween 1 maxBound
2130-- | See 'Streamly.Internal.Data.Parser.countBetween'.
2134{-# INLINE countBetween #-}
2135countBetween :: -- MonadCatch m =>
2136 Int -> Int -> Parser m a b -> Fold m b c -> Parser m a c
2137countBetween _m _n _p = undefined
2138-- countBetween m n p f = manyP p (takeBetween m n f)
2140-- | See 'Streamly.Internal.Data.Parser.count'.
2145count :: -- MonadCatch m =>
2146 Int -> Parser m a b -> Fold m b c -> Parser m a c
2147count n = countBetween n n
2148-- count n p f = manyP p (takeEQ n f)
2150data ManyTillState fs sr sl
2151 = ManyTillR Int fs sr
2152 | ManyTillL Int fs sl
2154-- | See 'Streamly.Internal.Data.Parser.manyTill'.
2158{-# INLINE manyTill #-}
2160 => Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
2161manyTill (Parser stepL initialL extractL)
2162 (Parser stepR initialR _)
2163 (Fold fstep finitial fextract) =
2164 Parser step initial extract
2168 -- Caution: Mutual recursion
2170 scrutL fs p c d e = do
2173 IPartial sl -> return $ c (ManyTillL 0 fs sl)
2177 FL.Partial fs1 -> scrutR fs1 p c d e
2178 FL.Done fb -> return $ d fb
2179 IError err -> return $ e err
2181 scrutR fs p c d e = do
2184 IPartial sr -> return $ p (ManyTillR 0 fs sr)
2185 IDone _ -> d <$> fextract fs
2186 IError _ -> scrutL fs p c d e
2191 FL.Partial fs -> scrutR fs IPartial IPartial IDone IError
2192 FL.Done b -> return $ IDone b
2194 step (ManyTillR cnt fs st) a = do
2197 Partial n s -> return $ Partial n (ManyTillR 0 fs s)
2199 assertM(cnt + 1 - n >= 0)
2200 return $ Continue n (ManyTillR (cnt + 1 - n) fs s)
2208 return $ Continue (cnt + 1) (ManyTillL 0 fs sl)
2216 FL.Partial fs1 -> scrutR fs1 p c d Error
2217 FL.Done fb -> return $ Done cnt1 fb
2218 IError err -> return $ Error err
2219 -- XXX the cnt is being used only by the assert
2220 step (ManyTillL cnt fs st) a = do
2223 Partial n s -> return $ Partial n (ManyTillL 0 fs s)
2225 assertM(cnt + 1 - n >= 0)
2226 return $ Continue n (ManyTillL (cnt + 1 - n) fs s)
2231 scrutR s (Partial n) (Continue n) (Done n) Error
2232 FL.Done b1 -> return $ Done n b1
2233 Error err -> return $ Error err
2235 extract (ManyTillL cnt fs sR) = do
2241 FL.Partial fs1 -> fmap (Done n) $ fextract fs1
2242 FL.Done c -> return (Done n c)
2243 Error err -> return $ Error err
2246 return $ Continue n (ManyTillL 0 fs s)
2247 Partial _ _ -> error "Partial in extract"
2248 extract (ManyTillR _ fs _) = fmap (Done 0) $ 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