on 5d096df help sign in
3621 lines 121 kB history raw
1{-# LANGUAGE CPP #-}
2-- |
3-- Module : Streamly.Internal.Data.Parser
4-- Copyright : (c) 2020 Composewell Technologies
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
8-- Portability : GHC
10module Streamly.Internal.Data.Parser
11 (
12 -- * Setup
13 -- | To execute the code examples provided in this module in ghci, please
14 -- run the following commands first.
15 --
16 -- $setup
18 module Streamly.Internal.Data.Parser.Type
19 --, module Streamly.Internal.Data.Parser.Tee
21 -- * Types
22 , Parser (..)
23 , ParseError (..)
24 , Step (..)
25 , Initial (..)
27 -- * Downgrade to Fold
28 , toFold
30 -- First order parsers
31 -- * Accumulators
32 , fromFold
33 , fromFoldMaybe
35 -- * Map on input
36 , postscan
38 -- * Element parsers
39 , peek
41 -- All of these can be expressed in terms of either
42 , one
43 , oneEq
44 , oneNotEq
45 , oneOf
46 , noneOf
47 , eof
48 , satisfy
49 , maybe
50 , either
52 -- * Sequence parsers (tokenizers)
53 --
54 -- | Parsers chained in series, if one parser terminates the composition
55 -- terminates. Currently we are using folds to collect the output of the
56 -- parsers but we can use Parsers instead of folds to make the composition
57 -- more powerful. For example, we can do:
58 --
59 -- takeEndByOrMax cond n p = takeEndBy cond (take n p)
60 -- takeEndByBetween cond m n p = takeEndBy cond (takeBetween m n p)
61 -- takeWhileBetween cond m n p = takeWhile cond (takeBetween m n p)
62 , lookAhead
64 -- ** By length
65 -- | Grab a sequence of input elements without inspecting them
66 , takeBetween
67 -- , take -- takeBetween 0 n
68 , takeEQ -- takeBetween n n
69 , takeGE -- takeBetween n maxBound
70 -- , takeGE1 -- take1 -- takeBetween 1 n
71 , takeP
73 -- Grab a sequence of input elements by inspecting them
74 -- ** Exact match
75 , listEq
76 , listEqBy
77 , streamEqBy
78 , subsequenceBy
80 -- ** By predicate
81 , takeWhile
82 , takeWhileP
83 , takeWhile1
84 , dropWhile
86 -- ** Separated by elements
87 -- | Separator could be in prefix postion ('takeStartBy'), or suffix
88 -- position ('takeEndBy'). See 'deintercalate', 'sepBy' etc for infix
89 -- separator parsing, also see 'intersperseQuotedBy' fold.
91 -- These can be implemented modularly with refolds, using takeWhile and
92 -- satisfy.
93 , takeEndBy
94 , takeEndBy_
95 , takeEndByEsc
96 -- , takeEndByEsc_
97 , takeStartBy
98 , takeStartBy_
99 , takeEitherSepBy
100 , wordBy
102 -- ** Grouped by element comparison
103 , groupBy
104 , groupByRolling
105 , groupByRollingEither
107 -- ** Framed by elements
108 -- | Also see 'intersperseQuotedBy' fold.
109 -- Framed by a one or more ocurrences of a separator around a word like
110 -- spaces or quotes. No nesting.
111 , wordFramedBy -- XXX Remove this? Covered by wordWithQuotes?
112 , wordWithQuotes
113 , wordKeepQuotes
114 , wordProcessQuotes
116 -- Framed by separate start and end characters, potentially nested.
117 -- blockWithQuotes allows quotes inside a block. However,
118 -- takeFramedByGeneric can be used to express takeStartBy, takeEndBy and
119 -- block with escaping.
120 -- , takeFramedBy
121 , takeFramedBy_
122 , takeFramedByEsc_
123 , takeFramedByGeneric
124 , blockWithQuotes
126 -- Matching strings
127 -- , prefixOf -- match any prefix of a given string
128 -- , suffixOf -- match any suffix of a given string
129 -- , infixOf -- match any substring of a given string
131 -- ** Spanning
132 , span
133 , spanBy
134 , spanByRolling
136 -- Second order parsers (parsers using parsers)
137 -- * Binary Combinators
138 {-
139 -- ** Parallel Applicatives
140 , teeWith
141 , teeWithFst
142 , teeWithMin
143 -- , teeTill -- like manyTill but parallel
144 -}
146 {-
147 -- ** Parallel Alternatives
148 , shortest
149 , longest
150 -- , fastest
151 -}
153 -- * N-ary Combinators
154 -- ** Sequential Collection
155 , sequence
157 -- ** Sequential Repetition
158 , count
159 , countBetween
160 -- , countBetweenTill
161 , manyP
162 , many
163 , some
165 -- ** Interleaved Repetition
166 -- Use two folds, run a primary parser, its rejected values go to the
167 -- secondary parser.
168 , deintercalate
169 , deintercalate1
170 , deintercalateAll
171 -- , deintercalatePrefix
172 -- , deintercalateSuffix
174 -- *** Special cases
175 -- | TODO: traditional implmentations of these may be of limited use. For
176 -- example, consider parsing lines separated by @\\r\\n@. The main parser
177 -- will have to detect and exclude the sequence @\\r\\n@ anyway so that we
178 -- can apply the "sep" parser.
179 --
180 -- We can instead implement these as special cases of deintercalate.
181 --
182 -- @
183 -- , endBy
184 -- , sepEndBy
185 -- , beginBy
186 -- , sepBeginBy
187 -- , sepAroundBy
188 -- @
189 , sepBy1
190 , sepBy
191 , sepByAll
193 , manyTillP
194 , manyTill
195 , manyThen
197 -- -- * Distribution
198 --
199 -- A simple and stupid impl would be to just convert the stream to an array
200 -- and give the array reference to all consumers. The array can be grown on
201 -- demand by any consumer and truncated when nonbody needs it.
202 --
203 -- -- ** Distribute to collection
204 -- -- ** Distribute to repetition
206 -- ** Interleaved collection
207 -- |
208 --
209 -- 1. Round robin
210 -- 2. Priority based
211 , roundRobin
213 -- -- ** Interleaved repetition
214 -- repeat one parser and when it fails run an error recovery parser
215 -- e.g. to find a key frame in the stream after an error
217 -- ** Collection of Alternatives
218 -- | Unimplemented
219 --
220 -- @
221 -- , shortestN
222 -- , longestN
223 -- , fastestN -- first N successful in time
224 -- , choiceN -- first N successful in position
225 -- @
226 -- , choice -- first successful in position
228 -- ** Repeated Alternatives
229 , retryMaxTotal
230 , retryMaxSuccessive
231 , retry
233 -- ** Zipping Input
234 , zipWithM
235 , zip
236 , indexed
237 , makeIndexFilter
238 , sampleFromthen
240 -- * Deprecated
241 , next
242 )
243where
245#include "inline.hs"
246#include "assert.hs"
248import Control.Monad (when)
249import Data.Bifunctor (first)
250import Fusion.Plugin.Types (Fuse(..))
251import Streamly.Internal.Data.Fold.Type (Fold(..))
252import Streamly.Internal.Data.SVar.Type (defState)
253import Streamly.Internal.Data.Either.Strict (Either'(..))
254import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
255import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
256import Streamly.Internal.Data.Stream.Type (Stream)
258import qualified Data.Foldable as Foldable
259import qualified Streamly.Internal.Data.Fold.Type as FL
260import qualified Streamly.Internal.Data.Stream.Type as D
261import qualified Streamly.Internal.Data.Stream.Generate as D
263import Streamly.Internal.Data.Parser.Type
264--import Streamly.Internal.Data.Parser.Tee -- It's empty
266import Prelude hiding
267 (any, all, take, takeWhile, sequence, concatMap, maybe, either, span
268 , zip, filter, dropWhile)
270#include "DocTestDataParser.hs"
272-------------------------------------------------------------------------------
273-- Downgrade a parser to a Fold
274-------------------------------------------------------------------------------
276-- | Make a 'Fold' from a 'Parser'. The fold just throws an exception if the
277-- parser fails or tries to backtrack.
278--
279-- This can be useful in combinators that accept a Fold and we know that a
280-- Parser cannot fail or failure exception is acceptable as there is no way to
281-- recover.
282--
283-- /Pre-release/
284--
285{-# INLINE toFold #-}
286toFold :: Monad m => Parser a m b -> Fold m a b
287toFold (Parser pstep pinitial pextract) = Fold step initial extract final
289 where
291 initial = do
292 r <- pinitial
293 case r of
294 IPartial s -> return $ FL.Partial s
295 IDone b -> return $ FL.Done b
296 IError err ->
297 error $ "toFold: parser throws error in initial" ++ err
299 perror n = error $ "toFold: parser backtracks in Partial: " ++ show n
300 cerror n = error $ "toFold: parser backtracks in Continue: " ++ show n
301 derror n = error $ "toFold: parser backtracks in Done: " ++ show n
302 eerror err = error $ "toFold: parser throws error: " ++ err
304 step st a = do
305 r <- pstep st a
306 case r of
307 Partial 0 s -> return $ FL.Partial s
308 Continue 0 s -> return $ FL.Partial s
309 Done 0 b -> return $ FL.Done b
310 Partial n _ -> perror n
311 Continue n _ -> cerror n
312 Done n _ -> derror n
313 Error err -> eerror err
315 extract = error "toFold: parser cannot be used for scanning"
317 final st = do
318 r <- pextract st
319 case r of
320 Done 0 b -> return b
321 Partial n _ -> perror n
322 Continue n _ -> cerror n
323 Done n _ -> derror n
324 Error err -> eerror err
326-------------------------------------------------------------------------------
327-- Upgrade folds to parses
328-------------------------------------------------------------------------------
330-- | Make a 'Parser' from a 'Fold'. This parser sends all of its input to the
331-- fold.
332--
333{-# INLINE fromFold #-}
334fromFold :: Monad m => Fold m a b -> Parser a m b
335fromFold (Fold fstep finitial _ ffinal) = Parser step initial extract
337 where
339 initial = do
340 res <- finitial
341 return
342 $ case res of
343 FL.Partial s1 -> IPartial s1
344 FL.Done b -> IDone b
346 step s a = do
347 res <- fstep s a
348 return
349 $ case res of
350 FL.Partial s1 -> Partial 0 s1
351 FL.Done b -> Done 0 b
353 extract = fmap (Done 0) . ffinal
355-- | Convert a Maybe returning fold to an error returning parser. The first
356-- argument is the error message that the parser would return when the fold
357-- returns Nothing.
358--
359-- /Pre-release/
360--
361{-# INLINE fromFoldMaybe #-}
362fromFoldMaybe :: Monad m => String -> Fold m a (Maybe b) -> Parser a m b
363fromFoldMaybe errMsg (Fold fstep finitial _ ffinal) =
364 Parser step initial extract
366 where
368 initial = do
369 res <- finitial
370 return
371 $ case res of
372 FL.Partial s1 -> IPartial s1
373 FL.Done b ->
374 case b of
375 Just x -> IDone x
376 Nothing -> IError errMsg
378 step s a = do
379 res <- fstep s a
380 return
381 $ case res of
382 FL.Partial s1 -> Partial 0 s1
383 FL.Done b ->
384 case b of
385 Just x -> Done 0 x
386 Nothing -> Error errMsg
388 extract s = do
389 res <- ffinal s
390 case res of
391 Just x -> return $ Done 0 x
392 Nothing -> return $ Error errMsg
394-------------------------------------------------------------------------------
395-- Failing Parsers
396-------------------------------------------------------------------------------
398-- | Peek the head element of a stream, without consuming it. Fails if it
399-- encounters end of input.
400--
401-- >>> Stream.parse ((,) <$> Parser.peek <*> Parser.satisfy (> 0)) $ Stream.fromList [1]
402-- Right (1,1)
403--
404-- @
405-- peek = lookAhead (satisfy True)
406-- @
407--
408{-# INLINE peek #-}
409peek :: Monad m => Parser a m a
410peek = Parser step initial extract
412 where
414 initial = return $ IPartial ()
416 step () a = return $ Done 1 a
418 extract () = return $ Error "peek: end of input"
420-- | Succeeds if we are at the end of input, fails otherwise.
421--
422-- >>> Stream.parse ((,) <$> Parser.satisfy (> 0) <*> Parser.eof) $ Stream.fromList [1]
423-- Right (1,())
424--
425{-# INLINE eof #-}
426eof :: Monad m => Parser a m ()
427eof = Parser step initial extract
429 where
431 initial = return $ IPartial ()
433 step () _ = return $ Error "eof: not at end of input"
435 extract () = return $ Done 0 ()
437-- | Return the next element of the input. Returns 'Nothing'
438-- on end of input. Also known as 'head'.
439--
440-- /Pre-release/
441--
442{-# DEPRECATED next "Please use \"fromFold Fold.one\" instead" #-}
443{-# INLINE next #-}
444next :: Monad m => Parser a m (Maybe a)
445next = Parser step initial extract
447 where
449 initial = pure $ IPartial ()
451 step () a = pure $ Done 0 (Just a)
453 extract () = pure $ Done 0 Nothing
455-- | Map an 'Either' returning function on the next element in the stream. If
456-- the function returns 'Left err', the parser fails with the error message
457-- @err@ otherwise returns the 'Right' value.
458--
459-- /Pre-release/
460--
461{-# INLINE either #-}
462either :: Monad m => (a -> Either String b) -> Parser a m b
463either f = Parser step initial extract
465 where
467 initial = return $ IPartial ()
469 step () a = return $
470 case f a of
471 Right b -> Done 0 b
472 Left err -> Error err
474 extract () = return $ Error "end of input"
476-- | Map a 'Maybe' returning function on the next element in the stream. The
477-- parser fails if the function returns 'Nothing' otherwise returns the 'Just'
478-- value.
479--
480-- >>> toEither = Maybe.maybe (Left "maybe: predicate failed") Right
481-- >>> maybe f = Parser.either (toEither . f)
482--
483-- >>> maybe f = Parser.fromFoldMaybe "maybe: predicate failed" (Fold.maybe f)
484--
485-- /Pre-release/
486--
487{-# INLINE maybe #-}
488maybe :: Monad m => (a -> Maybe b) -> Parser a m b
489-- maybe f = either (Maybe.maybe (Left "maybe: predicate failed") Right . f)
490maybe parserF = Parser step initial extract
492 where
494 initial = return $ IPartial ()
496 step () a = return $
497 case parserF a of
498 Just b -> Done 0 b
499 Nothing -> Error "maybe: predicate failed"
501 extract () = return $ Error "maybe: end of input"
503-- | Returns the next element if it passes the predicate, fails otherwise.
504--
505-- >>> Stream.parse (Parser.satisfy (== 1)) $ Stream.fromList [1,0,1]
506-- Right 1
507--
508-- >>> toMaybe f x = if f x then Just x else Nothing
509-- >>> satisfy f = Parser.maybe (toMaybe f)
510--
511{-# INLINE satisfy #-}
512satisfy :: Monad m => (a -> Bool) -> Parser a m a
513-- satisfy predicate = maybe (\a -> if predicate a then Just a else Nothing)
514satisfy predicate = Parser step initial extract
516 where
518 initial = return $ IPartial ()
520 step () a = return $
521 if predicate a
522 then Done 0 a
523 else Error "satisfy: predicate failed"
525 extract () = return $ Error "satisfy: end of input"
527-- | Consume one element from the head of the stream. Fails if it encounters
528-- end of input.
529--
530-- >>> one = Parser.satisfy $ const True
531--
532{-# INLINE one #-}
533one :: Monad m => Parser a m a
534one = satisfy $ const True
536-- Alternate names: "only", "onlyThis".
538-- | Match a specific element.
539--
540-- >>> oneEq x = Parser.satisfy (== x)
541--
542{-# INLINE oneEq #-}
543oneEq :: (Monad m, Eq a) => a -> Parser a m a
544oneEq x = satisfy (== x)
546-- Alternate names: "exclude", "notThis".
548-- | Match anything other than the supplied element.
549--
550-- >>> oneNotEq x = Parser.satisfy (/= x)
551--
552{-# INLINE oneNotEq #-}
553oneNotEq :: (Monad m, Eq a) => a -> Parser a m a
554oneNotEq x = satisfy (/= x)
556-- | Match any one of the elements in the supplied list.
557--
558-- >>> oneOf xs = Parser.satisfy (`Foldable.elem` xs)
559--
560-- When performance matters a pattern matching predicate could be more
561-- efficient than a 'Foldable' datatype:
562--
563-- @
564-- let p x =
565-- case x of
566-- 'a' -> True
567-- 'e' -> True
568-- _ -> False
569-- in satisfy p
570-- @
571--
572-- GHC may use a binary search instead of linear search in the list.
573-- Alternatively, you can also use an array instead of list for storage and
574-- search.
575--
576{-# INLINE oneOf #-}
577oneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
578oneOf xs = satisfy (`Foldable.elem` xs)
580-- | See performance notes in 'oneOf'.
581--
582-- >>> noneOf xs = Parser.satisfy (`Foldable.notElem` xs)
583--
584{-# INLINE noneOf #-}
585noneOf :: (Monad m, Eq a, Foldable f) => f a -> Parser a m a
586noneOf xs = satisfy (`Foldable.notElem` xs)
588-------------------------------------------------------------------------------
589-- Taking elements
590-------------------------------------------------------------------------------
592-- Required to fuse "take" with "many" in "chunksOf", for ghc-9.x
593{-# ANN type Tuple'Fused Fuse #-}
594data Tuple'Fused a b = Tuple'Fused !a !b deriving Show
596-- | @takeBetween m n@ takes a minimum of @m@ and a maximum of @n@ input
597-- elements and folds them using the supplied fold.
598--
599-- Stops after @n@ elements.
600-- Fails if the stream ends before @m@ elements could be taken.
601--
602-- Examples: -
603--
604-- @
605-- >>> :{
606-- takeBetween' low high ls = Stream.parse prsr (Stream.fromList ls)
607-- where prsr = Parser.takeBetween low high Fold.toList
608-- :}
609--
610-- @
611--
612-- >>> takeBetween' 2 4 [1, 2, 3, 4, 5]
613-- Right [1,2,3,4]
614--
615-- >>> takeBetween' 2 4 [1, 2]
616-- Right [1,2]
617--
618-- >>> takeBetween' 2 4 [1]
619-- Left (ParseError "takeBetween: Expecting alteast 2 elements, got 1")
620--
621-- >>> takeBetween' 0 0 [1, 2]
622-- Right []
623--
624-- >>> takeBetween' 0 1 []
625-- Right []
626--
627-- @takeBetween@ is the most general take operation, other take operations can
628-- be defined in terms of takeBetween. For example:
629--
630-- >>> take n = Parser.takeBetween 0 n
631-- >>> takeEQ n = Parser.takeBetween n n
632-- >>> takeGE n = Parser.takeBetween n maxBound
633--
634-- /Pre-release/
635--
636{-# INLINE takeBetween #-}
637takeBetween :: Monad m => Int -> Int -> Fold m a b -> Parser a m b
638takeBetween low high (Fold fstep finitial _ ffinal) =
640 Parser step initial (extract streamErr)
642 where
644 streamErr i =
645 "takeBetween: Expecting alteast " ++ show low
646 ++ " elements, got " ++ show i
648 invalidRange =
649 "takeBetween: lower bound - " ++ show low
650 ++ " is greater than higher bound - " ++ show high
652 foldErr :: Int -> String
653 foldErr i =
654 "takeBetween: the collecting fold terminated after"
655 ++ " consuming" ++ show i ++ " elements"
656 ++ " minimum" ++ show low ++ " elements needed"
658 -- Exactly the same as snext except different constructors, we can possibly
659 -- deduplicate the two.
660 {-# INLINE inext #-}
661 inext i res =
662 let i1 = i + 1
663 in case res of
664 FL.Partial s -> do
665 let s1 = Tuple'Fused i1 s
666 if i1 < high
667 -- XXX ideally this should be a Continue instead
668 then return $ IPartial s1
669 else iextract foldErr s1
670 FL.Done b ->
671 return
672 $ if i1 >= low
673 then IDone b
674 else IError (foldErr i1)
676 initial = do
677 when (low >= 0 && high >= 0 && low > high)
678 $ error invalidRange
680 finitial >>= inext (-1)
682 -- Keep the impl same as inext
683 {-# INLINE snext #-}
684 snext i res =
685 let i1 = i + 1
686 in case res of
687 FL.Partial s -> do
688 let s1 = Tuple'Fused i1 s
689 if i1 < low
690 then return $ Continue 0 s1
691 else if i1 < high
692 then return $ Partial 0 s1
693 else fmap (Done 0) (ffinal s)
694 FL.Done b ->
695 return
696 $ if i1 >= low
697 then Done 0 b
698 else Error (foldErr i1)
700 step (Tuple'Fused i s) a = fstep s a >>= snext i
702 extract f (Tuple'Fused i s)
703 | i >= low && i <= high = fmap (Done 0) (ffinal s)
704 | otherwise = return $ Error (f i)
706 -- XXX Need to make Initial return type Step to deduplicate this
707 iextract f (Tuple'Fused i s)
708 | i >= low && i <= high = fmap IDone (ffinal s)
709 | otherwise = return $ IError (f i)
711-- | Stops after taking exactly @n@ input elements.
712--
713-- * Stops - after consuming @n@ elements.
714-- * Fails - if the stream or the collecting fold ends before it can collect
715-- exactly @n@ elements.
716--
717-- >>> Stream.parse (Parser.takeEQ 2 Fold.toList) $ Stream.fromList [1,0,1]
718-- Right [1,0]
719--
720-- >>> Stream.parse (Parser.takeEQ 4 Fold.toList) $ Stream.fromList [1,0,1]
721-- Left (ParseError "takeEQ: Expecting exactly 4 elements, input terminated on 3")
722--
723{-# INLINE takeEQ #-}
724takeEQ :: Monad m => Int -> Fold m a b -> Parser a m b
725takeEQ n (Fold fstep finitial _ ffinal) = Parser step initial extract
727 where
729 initial = do
730 res <- finitial
731 case res of
732 FL.Partial s ->
733 if n > 0
734 then return $ IPartial $ Tuple'Fused 1 s
735 else fmap IDone (ffinal s)
736 FL.Done b -> return $
737 if n > 0
738 then IError
739 $ "takeEQ: Expecting exactly " ++ show n
740 ++ " elements, fold terminated without"
741 ++ " consuming any elements"
742 else IDone b
744 step (Tuple'Fused i1 r) a = do
745 res <- fstep r a
746 if n > i1
747 then
748 return
749 $ case res of
750 FL.Partial s -> Continue 0 $ Tuple'Fused (i1 + 1) s
751 FL.Done _ ->
752 Error
753 $ "takeEQ: Expecting exactly " ++ show n
754 ++ " elements, fold terminated on " ++ show i1
755 else
756 -- assert (n == i1)
757 Done 0
758 <$> case res of
759 FL.Partial s -> ffinal s
760 FL.Done b -> return b
762 extract (Tuple'Fused i _) =
763 -- Using the count "i" in the message below causes large performance
764 -- regression unless we use Fuse annotation on Tuple.
765 return
766 $ Error
767 $ "takeEQ: Expecting exactly " ++ show n
768 ++ " elements, input terminated on " ++ show (i - 1)
770{-# ANN type TakeGEState Fuse #-}
771data TakeGEState s =
772 TakeGELT !Int !s
773 | TakeGEGE !s
775-- | Take at least @n@ input elements, but can collect more.
776--
777-- * Stops - when the collecting fold stops.
778-- * Fails - if the stream or the collecting fold ends before producing @n@
779-- elements.
780--
781-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1]
782-- Left (ParseError "takeGE: Expecting at least 4 elements, input terminated on 3")
783--
784-- >>> Stream.parse (Parser.takeGE 4 Fold.toList) $ Stream.fromList [1,0,1,0,1]
785-- Right [1,0,1,0,1]
786--
787-- /Pre-release/
788--
789{-# INLINE takeGE #-}
790takeGE :: Monad m => Int -> Fold m a b -> Parser a m b
791takeGE n (Fold fstep finitial _ ffinal) = Parser step initial extract
793 where
795 initial = do
796 res <- finitial
797 case res of
798 FL.Partial s ->
799 if n > 0
800 then return $ IPartial $ TakeGELT 1 s
801 else return $ IPartial $ TakeGEGE s
802 FL.Done b -> return $
803 if n > 0
804 then IError
805 $ "takeGE: Expecting at least " ++ show n
806 ++ " elements, fold terminated without"
807 ++ " consuming any elements"
808 else IDone b
810 step (TakeGELT i1 r) a = do
811 res <- fstep r a
812 if n > i1
813 then
814 return
815 $ case res of
816 FL.Partial s -> Continue 0 $ TakeGELT (i1 + 1) s
817 FL.Done _ ->
818 Error
819 $ "takeGE: Expecting at least " ++ show n
820 ++ " elements, fold terminated on " ++ show i1
821 else
822 -- assert (n <= i1)
823 return
824 $ case res of
825 FL.Partial s -> Partial 0 $ TakeGEGE s
826 FL.Done b -> Done 0 b
827 step (TakeGEGE r) a = do
828 res <- fstep r a
829 return
830 $ case res of
831 FL.Partial s -> Partial 0 $ TakeGEGE s
832 FL.Done b -> Done 0 b
834 extract (TakeGELT i _) =
835 return
836 $ Error
837 $ "takeGE: Expecting at least " ++ show n
838 ++ " elements, input terminated on " ++ show (i - 1)
839 extract (TakeGEGE r) = fmap (Done 0) $ ffinal r
841-------------------------------------------------------------------------------
842-- Conditional splitting
843-------------------------------------------------------------------------------
845-- XXX We should perhaps use only takeWhileP and rename it to takeWhile.
847-- | Like 'takeWhile' but uses a 'Parser' instead of a 'Fold' to collect the
848-- input. The combinator stops when the condition fails or if the collecting
849-- parser stops.
850--
851-- Other interesting parsers can be implemented in terms of this parser:
852--
853-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
854-- >>> takeWhileBetween cond m n p = Parser.takeWhileP cond (Parser.takeBetween m n p)
855--
856-- Stops: when the condition fails or the collecting parser stops.
857-- Fails: when the collecting parser fails.
858--
859-- /Pre-release/
860--
861{-# INLINE takeWhileP #-}
862takeWhileP :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
863takeWhileP predicate (Parser pstep pinitial pextract) =
864 Parser step pinitial pextract
866 where
868 step s a =
869 if predicate a
870 then pstep s a
871 else do
872 r <- pextract s
873 -- XXX need a map on count
874 case r of
875 Error err -> return $ Error err
876 Done n s1 -> return $ Done (n + 1) s1
877 Partial _ _ -> error "Bug: takeWhileP: Partial in extract"
878 Continue n s1 -> return $ Continue (n + 1) s1
880-- | Collect stream elements until an element fails the predicate. The element
881-- on which the predicate fails is returned back to the input stream.
882--
883-- * Stops - when the predicate fails or the collecting fold stops.
884-- * Fails - never.
885--
886-- >>> Stream.parse (Parser.takeWhile (== 0) Fold.toList) $ Stream.fromList [0,0,1,0,1]
887-- Right [0,0]
888--
889-- >>> takeWhile cond f = Parser.takeWhileP cond (Parser.fromFold f)
890--
891-- We can implement a @breakOn@ using 'takeWhile':
892--
893-- @
894-- breakOn p = takeWhile (not p)
895-- @
896--
897{-# INLINE takeWhile #-}
898takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
899-- takeWhile cond f = takeWhileP cond (fromFold f)
900takeWhile predicate (Fold fstep finitial _ ffinal) =
901 Parser step initial extract
903 where
905 initial = do
906 res <- finitial
907 return $ case res of
908 FL.Partial s -> IPartial s
909 FL.Done b -> IDone b
911 step s a =
912 if predicate a
913 then do
914 fres <- fstep s a
915 return
916 $ case fres of
917 FL.Partial s1 -> Partial 0 s1
918 FL.Done b -> Done 0 b
919 else Done 1 <$> ffinal s
921 extract s = fmap (Done 0) (ffinal s)
923{-
924-- XXX This may not be composable because of the b argument. We can instead
925-- return a "Reparse b a m b" so that those can be composed.
926{-# INLINE takeWhile1X #-}
927takeWhile1 :: Monad m => b -> (a -> Bool) -> Refold m b a b -> Parser a m b
928-- We can implement this using satisfy and takeWhile. We can use "satisfy
929-- p", fold the result with the refold and then use the "takeWhile p" and
930-- fold that using the refold.
931takeWhile1 acc cond f = undefined
932-}
934-- | Like 'takeWhile' but takes at least one element otherwise fails.
935--
936-- >>> takeWhile1 cond p = Parser.takeWhileP cond (Parser.takeBetween 1 maxBound p)
937--
938{-# INLINE takeWhile1 #-}
939takeWhile1 :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
940-- takeWhile1 cond f = takeWhileP cond (takeBetween 1 maxBound f)
941takeWhile1 predicate (Fold fstep finitial _ ffinal) =
942 Parser step initial extract
944 where
946 initial = do
947 res <- finitial
948 return $ case res of
949 FL.Partial s -> IPartial (Left' s)
950 FL.Done _ ->
951 IError
952 $ "takeWhile1: fold terminated without consuming:"
953 ++ " any element"
955 {-# INLINE process #-}
956 process s a = do
957 res <- fstep s a
958 return
959 $ case res of
960 FL.Partial s1 -> Partial 0 (Right' s1)
961 FL.Done b -> Done 0 b
963 step (Left' s) a =
964 if predicate a
965 then process s a
966 else return $ Error "takeWhile1: predicate failed on first element"
967 step (Right' s) a =
968 if predicate a
969 then process s a
970 else do
971 b <- ffinal s
972 return $ Done 1 b
974 extract (Left' _) = return $ Error "takeWhile1: end of input"
975 extract (Right' s) = fmap (Done 0) (ffinal s)
977-- | Drain the input as long as the predicate succeeds, running the effects and
978-- discarding the results.
979--
980-- This is also called @skipWhile@ in some parsing libraries.
981--
982-- >>> dropWhile p = Parser.takeWhile p Fold.drain
983--
984{-# INLINE dropWhile #-}
985dropWhile :: Monad m => (a -> Bool) -> Parser a m ()
986dropWhile p = takeWhile p FL.drain
988-------------------------------------------------------------------------------
989-- Separators
990-------------------------------------------------------------------------------
992{-# ANN type FramedEscState Fuse #-}
993data FramedEscState s =
994 FrameEscInit !s | FrameEscGo !s !Int | FrameEscEsc !s !Int
996-- XXX We can remove Maybe from esc
997{-# INLINE takeFramedByGeneric #-}
998takeFramedByGeneric :: Monad m =>
999 Maybe (a -> Bool) -- is escape char?
1000 -> Maybe (a -> Bool) -- is frame begin?
1001 -> Maybe (a -> Bool) -- is frame end?
1002 -> Fold m a b
1003 -> Parser a m b
1004takeFramedByGeneric esc begin end (Fold fstep finitial _ ffinal) =
1006 Parser step initial extract
1008 where
1010 initial = do
1011 res <- finitial
1012 return $
1013 case res of
1014 FL.Partial s -> IPartial (FrameEscInit s)
1015 FL.Done _ ->
1016 error "takeFramedByGeneric: fold done without input"
1018 {-# INLINE process #-}
1019 process s a n = do
1020 res <- fstep s a
1021 return
1022 $ case res of
1023 FL.Partial s1 -> Continue 0 (FrameEscGo s1 n)
1024 FL.Done b -> Done 0 b
1026 {-# INLINE processNoEsc #-}
1027 processNoEsc s a n =
1028 case end of
1029 Just isEnd ->
1030 case begin of
1031 Just isBegin ->
1032 -- takeFramedBy case
1033 if isEnd a
1034 then
1035 if n == 0
1036 then Done 0 <$> ffinal s
1037 else process s a (n - 1)
1038 else
1039 let n1 = if isBegin a then n + 1 else n
1040 in process s a n1
1041 Nothing -> -- takeEndBy case
1042 if isEnd a
1043 then Done 0 <$> ffinal s
1044 else process s a n
1045 Nothing -> -- takeStartBy case
1046 case begin of
1047 Just isBegin ->
1048 if isBegin a
1049 then Done 0 <$> ffinal s
1050 else process s a n
1051 Nothing ->
1052 error $ "takeFramedByGeneric: "
1053 ++ "Both begin and end frame predicate missing"
1055 {-# INLINE processCheckEsc #-}
1056 processCheckEsc s a n =
1057 case esc of
1058 Just isEsc ->
1059 if isEsc a
1060 then return $ Partial 0 $ FrameEscEsc s n
1061 else processNoEsc s a n
1062 Nothing -> processNoEsc s a n
1064 step (FrameEscInit s) a =
1065 case begin of
1066 Just isBegin ->
1067 if isBegin a
1068 then return $ Partial 0 (FrameEscGo s 0)
1069 else return $ Error "takeFramedByGeneric: missing frame start"
1070 Nothing ->
1071 case end of
1072 Just isEnd ->
1073 if isEnd a
1074 then Done 0 <$> ffinal s
1075 else processCheckEsc s a 0
1076 Nothing ->
1077 error "Both begin and end frame predicate missing"
1078 step (FrameEscGo s n) a = processCheckEsc s a n
1079 step (FrameEscEsc s n) a = process s a n
1081 err = return . Error
1083 extract (FrameEscInit _) =
1084 err "takeFramedByGeneric: empty token"
1085 extract (FrameEscGo s _) =
1086 case begin of
1087 Just _ ->
1088 case end of
1089 Nothing -> fmap (Done 0) $ ffinal s
1090 Just _ -> err "takeFramedByGeneric: missing frame end"
1091 Nothing -> err "takeFramedByGeneric: missing closing frame"
1092 extract (FrameEscEsc _ _) = err "takeFramedByGeneric: trailing escape"
1094data BlockParseState s =
1095 BlockInit !s
1096 | BlockUnquoted !Int !s
1097 | BlockQuoted !Int !s
1098 | BlockQuotedEsc !Int !s
1100-- Blocks can be of different types e.g. {} or (). We only parse from the
1101-- perspective of the outermost block type. The nesting of that block are
1102-- checked. Any other block types nested inside it are opaque to us and can be
1103-- parsed when the contents of the block are parsed.
1105-- XXX Put a limit on nest level to keep the API safe.
1107-- | Parse a block enclosed within open, close brackets. Block contents may be
1108-- quoted, brackets inside quotes are ignored. Quoting characters can be used
1109-- within quotes if escaped. A block can have a nested block inside it.
1111-- Quote begin and end chars are the same. Block brackets and quote chars must
1112-- not overlap. Block start and end brackets must be different for nesting
1113-- blocks within blocks.
1115-- >>> p = Parser.blockWithQuotes (== '\\') (== '"') '{' '}' Fold.toList
1116-- >>> Stream.parse p $ Stream.fromList "{msg: \"hello world\"}"
1117-- Right "msg: \"hello world\""
1119{-# INLINE blockWithQuotes #-}
1120blockWithQuotes :: (Monad m, Eq a) =>
1121 (a -> Bool) -- ^ escape char
1122 -> (a -> Bool) -- ^ quote char, to quote inside brackets
1123 -> a -- ^ Block opening bracket
1124 -> a -- ^ Block closing bracket
1125 -> Fold m a b
1126 -> Parser a m b
1127blockWithQuotes isEsc isQuote bopen bclose
1128 (Fold fstep finitial _ ffinal) =
1129 Parser step initial extract
1131 where
1133 initial = do
1134 res <- finitial
1135 return $
1136 case res of
1137 FL.Partial s -> IPartial (BlockInit s)
1138 FL.Done _ ->
1139 error "blockWithQuotes: fold finished without input"
1141 {-# INLINE process #-}
1142 process s a nextState = do
1143 res <- fstep s a
1144 return
1145 $ case res of
1146 FL.Partial s1 -> Continue 0 (nextState s1)
1147 FL.Done b -> Done 0 b
1149 step (BlockInit s) a =
1150 return
1151 $ if a == bopen
1152 then Continue 0 $ BlockUnquoted 1 s
1153 else Error "blockWithQuotes: missing block start"
1154 step (BlockUnquoted level s) a
1155 | a == bopen = process s a (BlockUnquoted (level + 1))
1156 | a == bclose =
1157 if level == 1
1158 then fmap (Done 0) (ffinal s)
1159 else process s a (BlockUnquoted (level - 1))
1160 | isQuote a = process s a (BlockQuoted level)
1161 | otherwise = process s a (BlockUnquoted level)
1162 step (BlockQuoted level s) a
1163 | isEsc a = process s a (BlockQuotedEsc level)
1164 | otherwise =
1165 if isQuote a
1166 then process s a (BlockUnquoted level)
1167 else process s a (BlockQuoted level)
1168 step (BlockQuotedEsc level s) a = process s a (BlockQuoted level)
1170 err = return . Error
1172 extract (BlockInit s) = fmap (Done 0) $ ffinal s
1173 extract (BlockUnquoted level _) =
1174 err $ "blockWithQuotes: finished at block nest level " ++ show level
1175 extract (BlockQuoted level _) =
1176 err $ "blockWithQuotes: finished, inside an unfinished quote, "
1177 ++ "at block nest level " ++ show level
1178 extract (BlockQuotedEsc level _) =
1179 err $ "blockWithQuotes: finished, inside an unfinished quote, "
1180 ++ "after an escape char, at block nest level " ++ show level
1182-- | @takeEndBy cond parser@ parses a token that ends by a separator chosen by
1183-- the supplied predicate. The separator is also taken with the token.
1185-- This can be combined with other parsers to implement other interesting
1186-- parsers as follows:
1188-- >>> takeEndByLE cond n p = Parser.takeEndBy cond (Parser.fromFold $ Fold.take n p)
1189-- >>> takeEndByBetween cond m n p = Parser.takeEndBy cond (Parser.takeBetween m n p)
1191-- >>> takeEndBy = Parser.takeEndByEsc (const False)
1193-- See also "Streamly.Data.Fold.takeEndBy". Unlike the fold, the collecting
1194-- parser in the takeEndBy parser can decide whether to fail or not if the
1195-- stream does not end with separator.
1197-- /Pre-release/
1199{-# INLINE takeEndBy #-}
1200takeEndBy :: Monad m => (a -> Bool) -> Parser a m b -> Parser a m b
1201-- takeEndBy = takeEndByEsc (const False)
1202takeEndBy cond (Parser pstep pinitial pextract) =
1204 Parser step initial pextract
1206 where
1208 initial = pinitial
1210 step s a = do
1211 res <- pstep s a
1212 if not (cond a)
1213 then return res
1214 else extractStep pextract res
1216-- | Like 'takeEndBy' but the separator elements can be escaped using an
1217-- escape char determined by the first predicate. The escape characters are
1218-- removed.
1220-- /pre-release/
1221{-# INLINE takeEndByEsc #-}
1222takeEndByEsc :: Monad m =>
1223 (a -> Bool) -> (a -> Bool) -> Parser a m b -> Parser a m b
1224takeEndByEsc isEsc isSep (Parser pstep pinitial pextract) =
1226 Parser step initial extract
1228 where
1230 initial = first Left' <$> pinitial
1232 step (Left' s) a = do
1233 if isEsc a
1234 then return $ Partial 0 $ Right' s
1235 else do
1236 res <- pstep s a
1237 if not (isSep a)
1238 then return $ first Left' res
1239 else fmap (first Left') $ extractStep pextract res
1241 step (Right' s) a = do
1242 res <- pstep s a
1243 return $ first Left' res
1245 extract (Left' s) = fmap (first Left') $ pextract s
1246 extract (Right' _) =
1247 return $ Error "takeEndByEsc: trailing escape"
1249-- | Like 'takeEndBy' but the separator is dropped.
1251-- See also "Streamly.Data.Fold.takeEndBy_".
1253-- /Pre-release/
1255{-# INLINE takeEndBy_ #-}
1256takeEndBy_ :: (a -> Bool) -> Parser a m b -> Parser a m b
1258takeEndBy_ isEnd p =
1259 takeFramedByGeneric Nothing Nothing (Just isEnd) (toFold p)
1261takeEndBy_ cond (Parser pstep pinitial pextract) =
1263 Parser step pinitial pextract
1265 where
1267 step s a =
1268 if cond a
1269 then pextract s
1270 else pstep s a
1272-- | Take either the separator or the token. Separator is a Left value and
1273-- token is Right value.
1275-- /Unimplemented/
1276{-# INLINE takeEitherSepBy #-}
1277takeEitherSepBy :: -- Monad m =>
1278 (a -> Bool) -> Fold m (Either a b) c -> Parser a m c
1279takeEitherSepBy _cond = undefined -- D.toParserK . D.takeEitherSepBy cond
1281-- | Parse a token that starts with an element chosen by the predicate. The
1282-- parser fails if the input does not start with the selected element.
1284-- * Stops - when the predicate succeeds in non-leading position.
1285-- * Fails - when the predicate fails in the leading position.
1287-- >>> splitWithPrefix p f = Stream.parseMany (Parser.takeStartBy p f)
1289-- Examples: -
1291-- >>> p = Parser.takeStartBy (== ',') Fold.toList
1292-- >>> leadingComma = Stream.parse p . Stream.fromList
1293-- >>> leadingComma "a,b"
1294-- Left (ParseError "takeStartBy: missing frame start")
1295-- ...
1296-- >>> leadingComma ",,"
1297-- Right ","
1298-- >>> leadingComma ",a,b"
1299-- Right ",a"
1300-- >>> leadingComma ""
1301-- Right ""
1303-- /Pre-release/
1305{-# INLINE takeStartBy #-}
1306takeStartBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1307takeStartBy cond (Fold fstep finitial _ ffinal) =
1309 Parser step initial extract
1311 where
1313 initial = do
1314 res <- finitial
1315 return $
1316 case res of
1317 FL.Partial s -> IPartial (Left' s)
1318 FL.Done _ -> IError "takeStartBy: fold done without input"
1320 {-# INLINE process #-}
1321 process s a = do
1322 res <- fstep s a
1323 return
1324 $ case res of
1325 FL.Partial s1 -> Partial 0 (Right' s1)
1326 FL.Done b -> Done 0 b
1328 step (Left' s) a =
1329 if cond a
1330 then process s a
1331 else return $ Error "takeStartBy: missing frame start"
1332 step (Right' s) a =
1333 if not (cond a)
1334 then process s a
1335 else Done 1 <$> ffinal s
1337 extract (Left' s) = fmap (Done 0) $ ffinal s
1338 extract (Right' s) = fmap (Done 0) $ ffinal s
1340-- | Like 'takeStartBy' but drops the separator.
1342-- >>> takeStartBy_ isBegin = Parser.takeFramedByGeneric Nothing (Just isBegin) Nothing
1344{-# INLINE takeStartBy_ #-}
1345takeStartBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1346takeStartBy_ isBegin = takeFramedByGeneric Nothing (Just isBegin) Nothing
1348-- | @takeFramedByEsc_ isEsc isBegin isEnd fold@ parses a token framed using a
1349-- begin and end predicate, and an escape character. The frame begin and end
1350-- characters lose their special meaning if preceded by the escape character.
1352-- Nested frames are allowed if begin and end markers are different, nested
1353-- frames must be balanced unless escaped, nested frame markers are emitted as
1354-- it is.
1356-- For example,
1358-- >>> p = Parser.takeFramedByEsc_ (== '\\') (== '{') (== '}') Fold.toList
1359-- >>> Stream.parse p $ Stream.fromList "{hello}"
1360-- Right "hello"
1361-- >>> Stream.parse p $ Stream.fromList "{hello {world}}"
1362-- Right "hello {world}"
1363-- >>> Stream.parse p $ Stream.fromList "{hello \\{world}"
1364-- Right "hello {world"
1365-- >>> Stream.parse p $ Stream.fromList "{hello {world}"
1366-- Left (ParseError "takeFramedByEsc_: missing frame end")
1368-- /Pre-release/
1369{-# INLINE takeFramedByEsc_ #-}
1370takeFramedByEsc_ :: Monad m =>
1371 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1372-- takeFramedByEsc_ isEsc isEnd p =
1373-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
1374takeFramedByEsc_ isEsc isBegin isEnd (Fold fstep finitial _ ffinal ) =
1376 Parser step initial extract
1378 where
1380 initial = do
1381 res <- finitial
1382 return $
1383 case res of
1384 FL.Partial s -> IPartial (FrameEscInit s)
1385 FL.Done _ ->
1386 error "takeFramedByEsc_: fold done without input"
1388 {-# INLINE process #-}
1389 process s a n = do
1390 res <- fstep s a
1391 return
1392 $ case res of
1393 FL.Partial s1 -> Continue 0 (FrameEscGo s1 n)
1394 FL.Done b -> Done 0 b
1396 step (FrameEscInit s) a =
1397 if isBegin a
1398 then return $ Partial 0 (FrameEscGo s 0)
1399 else return $ Error "takeFramedByEsc_: missing frame start"
1400 step (FrameEscGo s n) a =
1401 if isEsc a
1402 then return $ Partial 0 $ FrameEscEsc s n
1403 else do
1404 if not (isEnd a)
1405 then
1406 let n1 = if isBegin a then n + 1 else n
1407 in process s a n1
1408 else
1409 if n == 0
1410 then Done 0 <$> ffinal s
1411 else process s a (n - 1)
1412 step (FrameEscEsc s n) a = process s a n
1414 err = return . Error
1416 extract (FrameEscInit _) = err "takeFramedByEsc_: empty token"
1417 extract (FrameEscGo _ _) = err "takeFramedByEsc_: missing frame end"
1418 extract (FrameEscEsc _ _) = err "takeFramedByEsc_: trailing escape"
1420data FramedState s = FrameInit !s | FrameGo !s Int
1422-- | @takeFramedBy_ isBegin isEnd fold@ parses a token framed by a begin and an
1423-- end predicate.
1425-- >>> takeFramedBy_ = Parser.takeFramedByEsc_ (const False)
1427{-# INLINE takeFramedBy_ #-}
1428takeFramedBy_ :: Monad m =>
1429 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser a m b
1430-- takeFramedBy_ isBegin isEnd =
1431-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
1432takeFramedBy_ isBegin isEnd (Fold fstep finitial _ ffinal) =
1434 Parser step initial extract
1436 where
1438 initial = do
1439 res <- finitial
1440 return $
1441 case res of
1442 FL.Partial s -> IPartial (FrameInit s)
1443 FL.Done _ ->
1444 error "takeFramedBy_: fold done without input"
1446 {-# INLINE process #-}
1447 process s a n = do
1448 res <- fstep s a
1449 return
1450 $ case res of
1451 FL.Partial s1 -> Continue 0 (FrameGo s1 n)
1452 FL.Done b -> Done 0 b
1454 step (FrameInit s) a =
1455 if isBegin a
1456 then return $ Continue 0 (FrameGo s 0)
1457 else return $ Error "takeFramedBy_: missing frame start"
1458 step (FrameGo s n) a
1459 | not (isEnd a) =
1460 let n1 = if isBegin a then n + 1 else n
1461 in process s a n1
1462 | n == 0 = Done 0 <$> ffinal s
1463 | otherwise = process s a (n - 1)
1465 err = return . Error
1467 extract (FrameInit _) = err "takeFramedBy_: empty token"
1468 extract (FrameGo _ _) = err "takeFramedBy_: missing frame end"
1470-------------------------------------------------------------------------------
1471-- Grouping and words
1472-------------------------------------------------------------------------------
1474data WordByState s b = WBLeft !s | WBWord !s | WBRight !b
1476-- Note we can also get words using something like:
1477-- sepBy FL.toList (takeWhile (not . p) Fold.toList) (dropWhile p)
1479-- But that won't be as efficient and ergonomic.
1481-- | Like 'splitOn' but strips leading, trailing, and repeated separators.
1482-- Therefore, @".a..b."@ having '.' as the separator would be parsed as
1483-- @["a","b"]@. In other words, its like parsing words from whitespace
1484-- separated text.
1486-- * Stops - when it finds a word separator after a non-word element
1487-- * Fails - never.
1489-- >>> wordBy = Parser.wordFramedBy (const False) (const False) (const False)
1491-- @
1492-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
1493-- @
1495{-# INLINE wordBy #-}
1496wordBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser a m b
1497wordBy predicate (Fold fstep finitial _ ffinal) = Parser step initial extract
1499 where
1501 {-# INLINE worder #-}
1502 worder s a = do
1503 res <- fstep s a
1504 return
1505 $ case res of
1506 FL.Partial s1 -> Partial 0 $ WBWord s1
1507 FL.Done b -> Done 0 b
1509 initial = do
1510 res <- finitial
1511 return
1512 $ case res of
1513 FL.Partial s -> IPartial $ WBLeft s
1514 FL.Done b -> IDone b
1516 step (WBLeft s) a =
1517 if not (predicate a)
1518 then worder s a
1519 else return $ Partial 0 $ WBLeft s
1520 step (WBWord s) a =
1521 if not (predicate a)
1522 then worder s a
1523 else do
1524 b <- ffinal s
1525 return $ Partial 0 $ WBRight b
1526 step (WBRight b) a =
1527 return
1528 $ if not (predicate a)
1529 then Done 1 b
1530 else Partial 0 $ WBRight b
1532 extract (WBLeft s) = fmap (Done 0) $ ffinal s
1533 extract (WBWord s) = fmap (Done 0) $ ffinal s
1534 extract (WBRight b) = return (Done 0 b)
1536data WordFramedState s b =
1537 WordFramedSkipPre !s
1538 | WordFramedWord !s !Int
1539 | WordFramedEsc !s !Int
1540 | WordFramedSkipPost !b
1542-- | Like 'wordBy' but treats anything inside a pair of quotes as a single
1543-- word, the quotes can be escaped by an escape character. Recursive quotes
1544-- are possible if quote begin and end characters are different, quotes must be
1545-- balanced. Outermost quotes are stripped.
1547-- >>> braces = Parser.wordFramedBy (== '\\') (== '{') (== '}') isSpace Fold.toList
1548-- >>> Stream.parse braces $ Stream.fromList "{ab} cd"
1549-- Right "ab"
1550-- >>> Stream.parse braces $ Stream.fromList "{ab}{cd}"
1551-- Right "abcd"
1552-- >>> Stream.parse braces $ Stream.fromList "a{b} cd"
1553-- Right "ab"
1554-- >>> Stream.parse braces $ Stream.fromList "a{{b}} cd"
1555-- Right "a{b}"
1557-- >>> quotes = Parser.wordFramedBy (== '\\') (== '"') (== '"') isSpace Fold.toList
1558-- >>> Stream.parse quotes $ Stream.fromList "\"a\"\"b\""
1559-- Right "ab"
1561{-# INLINE wordFramedBy #-}
1562wordFramedBy :: Monad m =>
1563 (a -> Bool) -- ^ Matches escape elem?
1564 -> (a -> Bool) -- ^ Matches left quote?
1565 -> (a -> Bool) -- ^ matches right quote?
1566 -> (a -> Bool) -- ^ matches word separator?
1567 -> Fold m a b
1568 -> Parser a m b
1569wordFramedBy isEsc isBegin isEnd isSep
1570 (Fold fstep finitial _ ffinal) =
1571 Parser step initial extract
1573 where
1575 initial = do
1576 res <- finitial
1577 return $
1578 case res of
1579 FL.Partial s -> IPartial (WordFramedSkipPre s)
1580 FL.Done _ ->
1581 error "wordFramedBy: fold done without input"
1583 {-# INLINE process #-}
1584 process s a n = do
1585 res <- fstep s a
1586 return
1587 $ case res of
1588 FL.Partial s1 -> Continue 0 (WordFramedWord s1 n)
1589 FL.Done b -> Done 0 b
1591 step (WordFramedSkipPre s) a
1592 | isEsc a = return $ Continue 0 $ WordFramedEsc s 0
1593 | isSep a = return $ Partial 0 $ WordFramedSkipPre s
1594 | isBegin a = return $ Continue 0 $ WordFramedWord s 1
1595 | isEnd a =
1596 return $ Error "wordFramedBy: missing frame start"
1597 | otherwise = process s a 0
1598 step (WordFramedWord s n) a
1599 | isEsc a = return $ Continue 0 $ WordFramedEsc s n
1600 | n == 0 && isSep a = do
1601 b <- ffinal s
1602 return $ Partial 0 $ WordFramedSkipPost b
1603 | otherwise = do
1604 -- We need to use different order for checking begin and end for
1605 -- the n == 0 and n == 1 case so that when the begin and end
1606 -- character is the same we treat the one after begin as end.
1607 if n == 0
1608 then
1609 -- Need to check isBegin first
1610 if isBegin a
1611 then return $ Continue 0 $ WordFramedWord s 1
1612 else if isEnd a
1613 then return $ Error "wordFramedBy: missing frame start"
1614 else process s a n
1615 else
1616 -- Need to check isEnd first
1617 if isEnd a
1618 then
1619 if n == 1
1620 then return $ Continue 0 $ WordFramedWord s 0
1621 else process s a (n - 1)
1622 else if isBegin a
1623 then process s a (n + 1)
1624 else process s a n
1625 step (WordFramedEsc s n) a = process s a n
1626 step (WordFramedSkipPost b) a =
1627 return
1628 $ if not (isSep a)
1629 then Done 1 b
1630 else Partial 0 $ WordFramedSkipPost b
1632 err = return . Error
1634 extract (WordFramedSkipPre s) = fmap (Done 0) $ ffinal s
1635 extract (WordFramedWord s n) =
1636 if n == 0
1637 then fmap (Done 0) $ ffinal s
1638 else err "wordFramedBy: missing frame end"
1639 extract (WordFramedEsc _ _) =
1640 err "wordFramedBy: trailing escape"
1641 extract (WordFramedSkipPost b) = return (Done 0 b)
1643data WordQuotedState s b a =
1644 WordQuotedSkipPre !s
1645 | WordUnquotedWord !s
1646 | WordQuotedWord !s !Int !a !a
1647 | WordUnquotedEsc !s
1648 | WordQuotedEsc !s !Int !a !a
1649 | WordQuotedSkipPost !b
1651-- | Quote and bracket aware word splitting with escaping. Like 'wordBy' but
1652-- word separators within specified quotes or brackets are ignored. Quotes and
1653-- escape characters can be processed. If the end quote is different from the
1654-- start quote it is called a bracket. The following quoting rules apply:
1656-- * In an unquoted string a character may be preceded by an escape character.
1657-- The escape character is removed and the character following it is treated
1658-- literally with no special meaning e.g. e.g. h\ e\ l\ l\ o is a single word,
1659-- \n is same as n.
1660-- * Any part of the word can be placed within quotes. Inside quotes all
1661-- characters are treated literally with no special meaning. Quoting character
1662-- itself cannot be used within quotes unless escape processing within quotes
1663-- is applied to allow it.
1664-- * Optionally escape processing for quoted part can be specified. Escape
1665-- character has no special meaning inside quotes unless it is followed by a
1666-- character that has a escape translation specified, in that case the escape
1667-- character is removed, and the specified translation is applied to the
1668-- character following it. This can be used to escape the quoting character
1669-- itself within quotes.
1670-- * There can be multiple quoting characters, when a quote starts, all other
1671-- quoting characters within that quote lose any special meaning until the
1672-- quote is closed.
1673-- * A starting quote char without an ending char generates a parse error. An
1674-- ending bracket char without a corresponding bracket begin is ignored.
1675-- * Brackets can be nested.
1677-- We should note that unquoted and quoted escape processing are different. In
1678-- unquoted part escape character is always removed. In quoted part it is
1679-- removed only if followed by a special meaning character. This is consistent
1680-- with how shell performs escape processing.
1682-- Examples of quotes - "double quotes", 'single quotes', (parens), {braces},
1683-- ((nested) brackets).
1685-- Example:
1687-- >>> :{
1688-- >>> q x =
1689-- >>> case x of
1690-- >>> '"' -> Just x
1691-- >>> '\'' -> Just x
1692-- >>> _ -> Nothing
1693-- >>> :}
1695-- >>> p = Parser.wordKeepQuotes (== '\\') q isSpace Fold.toList
1696-- >>> Stream.parse p $ Stream.fromList "a\"b'c\";'d\"e'f ghi"
1697-- Right "a\"b'c\";'d\"e'f"
1699-- Note that outer quotes and backslashes from the input string are consumed by
1700-- Haskell, therefore, the actual input string passed to the parser is:
1701-- a"b'c";'d"e'f ghi
1703-- Similarly, when printing, double quotes are escaped by Haskell.
1705-- Limitations:
1707-- Shell like quote processing can be performed by using quote char specific
1708-- escape processing, single quotes with no escapes, and double quotes with
1709-- escapes.
1711-- JSON string processing can also be achieved except the "\uXXXX" style
1712-- escaping for Unicode characters.
1714{-# INLINE wordWithQuotes #-}
1715wordWithQuotes :: (Monad m, Eq a) =>
1716 Bool -- ^ Retain the quotes and escape chars in the output
1717 -> (a -> a -> Maybe a) -- ^ quote char -> escaped char -> translated char
1718 -> a -- ^ Matches an escape elem?
1719 -> (a -> Maybe a) -- ^ If left quote, return right quote, else Nothing.
1720 -> (a -> Bool) -- ^ Matches a word separator?
1721 -> Fold m a b
1722 -> Parser a m b
1723wordWithQuotes keepQuotes tr escChar toRight isSep
1724 (Fold fstep finitial _ ffinal) =
1725 Parser step initial extract
1727 where
1729 -- Can be used to generate parse error for a bracket end without a bracket
1730 -- begin.
1731 isInvalid = const False
1733 isEsc = (== escChar)
1735 initial = do
1736 res <- finitial
1737 return $
1738 case res of
1739 FL.Partial s -> IPartial (WordQuotedSkipPre s)
1740 FL.Done _ ->
1741 error "wordKeepQuotes: fold done without input"
1743 {-# INLINE processQuoted #-}
1744 processQuoted s a n ql qr = do
1745 res <- fstep s a
1746 return
1747 $ case res of
1748 FL.Partial s1 -> Continue 0 (WordQuotedWord s1 n ql qr)
1749 FL.Done b -> Done 0 b
1751 {-# INLINE processUnquoted #-}
1752 processUnquoted s a = do
1753 res <- fstep s a
1754 return
1755 $ case res of
1756 FL.Partial s1 -> Continue 0 (WordUnquotedWord s1)
1757 FL.Done b -> Done 0 b
1759 step (WordQuotedSkipPre s) a
1760 | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1761 | isSep a = return $ Partial 0 $ WordQuotedSkipPre s
1762 | otherwise =
1763 case toRight a of
1764 Just qr ->
1765 if keepQuotes
1766 then processQuoted s a 1 a qr
1767 else return $ Continue 0 $ WordQuotedWord s 1 a qr
1768 Nothing
1769 | isInvalid a ->
1770 return $ Error "wordKeepQuotes: invalid unquoted char"
1771 | otherwise -> processUnquoted s a
1772 step (WordUnquotedWord s) a
1773 | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1774 | isSep a = do
1775 b <- ffinal s
1776 return $ Partial 0 $ WordQuotedSkipPost b
1777 | otherwise = do
1778 case toRight a of
1779 Just qr ->
1780 if keepQuotes
1781 then processQuoted s a 1 a qr
1782 else return $ Continue 0 $ WordQuotedWord s 1 a qr
1783 Nothing ->
1784 if isInvalid a
1785 then return $ Error "wordKeepQuotes: invalid unquoted char"
1786 else processUnquoted s a
1787 step (WordQuotedWord s n ql qr) a
1788 | isEsc a = return $ Continue 0 $ WordQuotedEsc s n ql qr
1789 {-
1790 -- XXX Will this ever occur? Will n ever be 0?
1791 | n == 0 && isSep a = do
1792 b <- fextract s
1793 return $ Partial 0 $ WordQuotedSkipPost b
1794 -}
1795 | otherwise = do
1796 if a == qr
1797 then
1798 if n == 1
1799 then if keepQuotes
1800 then processUnquoted s a
1801 else return $ Continue 0 $ WordUnquotedWord s
1802 else processQuoted s a (n - 1) ql qr
1803 else if a == ql
1804 then processQuoted s a (n + 1) ql qr
1805 else processQuoted s a n ql qr
1806 step (WordUnquotedEsc s) a = processUnquoted s a
1807 step (WordQuotedEsc s n ql qr) a =
1808 case tr ql a of
1809 Nothing -> do
1810 res <- fstep s escChar
1811 case res of
1812 FL.Partial s1 -> processQuoted s1 a n ql qr
1813 FL.Done b -> return $ Done 0 b
1814 Just x -> processQuoted s x n ql qr
1815 step (WordQuotedSkipPost b) a =
1816 return
1817 $ if not (isSep a)
1818 then Done 1 b
1819 else Partial 0 $ WordQuotedSkipPost b
1821 err = return . Error
1823 extract (WordQuotedSkipPre s) = fmap (Done 0) $ ffinal s
1824 extract (WordUnquotedWord s) = fmap (Done 0) $ ffinal s
1825 extract (WordQuotedWord s n _ _) =
1826 if n == 0
1827 then fmap (Done 0) $ ffinal s
1828 else err "wordWithQuotes: missing frame end"
1829 extract WordQuotedEsc {} =
1830 err "wordWithQuotes: trailing escape"
1831 extract (WordUnquotedEsc _) =
1832 err "wordWithQuotes: trailing escape"
1833 extract (WordQuotedSkipPost b) = return (Done 0 b)
1835-- | 'wordWithQuotes' without processing the quotes and escape function
1836-- supplied to escape the quote char within a quote. Can be used to parse words
1837-- keeping the quotes and escapes intact.
1839-- >>> wordKeepQuotes = Parser.wordWithQuotes True (\_ _ -> Nothing)
1841{-# INLINE wordKeepQuotes #-}
1842wordKeepQuotes :: (Monad m, Eq a) =>
1843 a -- ^ Escape char
1844 -> (a -> Maybe a) -- ^ If left quote, return right quote, else Nothing.
1845 -> (a -> Bool) -- ^ Matches a word separator?
1846 -> Fold m a b
1847 -> Parser a m b
1848wordKeepQuotes =
1849 -- Escape the quote char itself
1850 wordWithQuotes True (\q x -> if q == x then Just x else Nothing)
1852-- See the "Quoting Rules" section in the "bash" manual page for a primer on
1853-- how quotes are used by shells.
1855-- | 'wordWithQuotes' with quote processing applied and escape function
1856-- supplied to escape the quote char within a quote. Can be ysed to parse words
1857-- and processing the quoting and escaping at the same time.
1859-- >>> wordProcessQuotes = Parser.wordWithQuotes False (\_ _ -> Nothing)
1861{-# INLINE wordProcessQuotes #-}
1862wordProcessQuotes :: (Monad m, Eq a) =>
1863 a -- ^ Escape char
1864 -> (a -> Maybe a) -- ^ If left quote, return right quote, else Nothing.
1865 -> (a -> Bool) -- ^ Matches a word separator?
1866 -> Fold m a b
1867 -> Parser a m b
1868wordProcessQuotes =
1869 -- Escape the quote char itself
1870 wordWithQuotes False (\q x -> if q == x then Just x else Nothing)
1872{-# ANN type GroupByState Fuse #-}
1873data GroupByState a s
1874 = GroupByInit !s
1875 | GroupByGrouping !a !s
1877-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
1878-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
1879-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
1880-- then @c@ is also assigned to the same group and so on. When the comparison
1881-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
1882-- the result of the fold is the result of the parser.
1884-- * Stops - when the comparison fails.
1885-- * Fails - never.
1887-- >>> :{
1888-- runGroupsBy eq =
1889-- Stream.fold Fold.toList
1890-- . Stream.parseMany (Parser.groupBy eq Fold.toList)
1891-- . Stream.fromList
1892-- :}
1894-- >>> runGroupsBy (<) []
1895-- []
1897-- >>> runGroupsBy (<) [1]
1898-- [Right [1]]
1900-- >>> runGroupsBy (<) [3, 5, 4, 1, 2, 0]
1901-- [Right [3,5,4],Right [1,2],Right [0]]
1903{-# INLINE groupBy #-}
1904groupBy :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1905groupBy eq (Fold fstep finitial _ ffinal) = Parser step initial extract
1907 where
1909 {-# INLINE grouper #-}
1910 grouper s a0 a = do
1911 res <- fstep s a
1912 return
1913 $ case res of
1914 FL.Done b -> Done 0 b
1915 FL.Partial s1 -> Partial 0 (GroupByGrouping a0 s1)
1917 initial = do
1918 res <- finitial
1919 return
1920 $ case res of
1921 FL.Partial s -> IPartial $ GroupByInit s
1922 FL.Done b -> IDone b
1924 step (GroupByInit s) a = grouper s a a
1925 step (GroupByGrouping a0 s) a =
1926 if eq a0 a
1927 then grouper s a0 a
1928 else Done 1 <$> ffinal s
1930 extract (GroupByInit s) = fmap (Done 0) $ ffinal s
1931 extract (GroupByGrouping _ s) = fmap (Done 0) $ ffinal s
1933-- | Unlike 'groupBy' this combinator performs a rolling comparison of two
1934-- successive elements in the input stream. Assuming the input stream
1935-- is @[a,b,c,...]@ and the comparison function is @cmp@, the parser
1936-- first assigns the element @a@ to the first group, then if @a \`cmp` b@ is
1937-- 'True' @b@ is also assigned to the same group. If @b \`cmp` c@ is 'True'
1938-- then @c@ is also assigned to the same group and so on. When the comparison
1939-- fails the parser is terminated. Each group is folded using the 'Fold' @f@ and
1940-- the result of the fold is the result of the parser.
1942-- * Stops - when the comparison fails.
1943-- * Fails - never.
1945-- >>> :{
1946-- runGroupsByRolling eq =
1947-- Stream.fold Fold.toList
1948-- . Stream.parseMany (Parser.groupByRolling eq Fold.toList)
1949-- . Stream.fromList
1950-- :}
1952-- >>> runGroupsByRolling (<) []
1953-- []
1955-- >>> runGroupsByRolling (<) [1]
1956-- [Right [1]]
1958-- >>> runGroupsByRolling (<) [3, 5, 4, 1, 2, 0]
1959-- [Right [3,5],Right [4],Right [1,2],Right [0]]
1961-- /Pre-release/
1963{-# INLINE groupByRolling #-}
1964groupByRolling :: Monad m => (a -> a -> Bool) -> Fold m a b -> Parser a m b
1965groupByRolling eq (Fold fstep finitial _ ffinal) = Parser step initial extract
1967 where
1969 {-# INLINE grouper #-}
1970 grouper s a = do
1971 res <- fstep s a
1972 return
1973 $ case res of
1974 FL.Done b -> Done 0 b
1975 FL.Partial s1 -> Partial 0 (GroupByGrouping a s1)
1977 initial = do
1978 res <- finitial
1979 return
1980 $ case res of
1981 FL.Partial s -> IPartial $ GroupByInit s
1982 FL.Done b -> IDone b
1984 step (GroupByInit s) a = grouper s a
1985 step (GroupByGrouping a0 s) a =
1986 if eq a0 a
1987 then grouper s a
1988 else Done 1 <$> ffinal s
1990 extract (GroupByInit s) = fmap (Done 0) $ ffinal s
1991 extract (GroupByGrouping _ s) = fmap (Done 0) $ ffinal s
1993{-# ANN type GroupByStatePair Fuse #-}
1994data GroupByStatePair a s1 s2
1995 = GroupByInitPair !s1 !s2
1996 | GroupByGroupingPair !a !s1 !s2
1997 | GroupByGroupingPairL !a !s1 !s2
1998 | GroupByGroupingPairR !a !s1 !s2
2000-- | Like 'groupByRolling', but if the predicate is 'True' then collects using
2001-- the first fold as long as the predicate holds 'True', if the predicate is
2002-- 'False' collects using the second fold as long as it remains 'False'.
2003-- Returns 'Left' for the first case and 'Right' for the second case.
2005-- For example, if we want to detect sorted sequences in a stream, both
2006-- ascending and descending cases we can use 'groupByRollingEither (<=)
2007-- Fold.toList Fold.toList'.
2009-- /Pre-release/
2010{-# INLINE groupByRollingEither #-}
2011groupByRollingEither :: Monad m =>
2012 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (Either b c)
2013groupByRollingEither
2014 eq
2015 (Fold fstep1 finitial1 _ ffinal1)
2016 (Fold fstep2 finitial2 _ ffinal2) = Parser step initial extract
2018 where
2020 {-# INLINE grouper #-}
2021 grouper s1 s2 a = do
2022 return $ Continue 0 (GroupByGroupingPair a s1 s2)
2024 {-# INLINE grouperL2 #-}
2025 grouperL2 s1 s2 a = do
2026 res <- fstep1 s1 a
2027 return
2028 $ case res of
2029 FL.Done b -> Done 0 (Left b)
2030 FL.Partial s11 -> Partial 0 (GroupByGroupingPairL a s11 s2)
2032 {-# INLINE grouperL #-}
2033 grouperL s1 s2 a0 a = do
2034 res <- fstep1 s1 a0
2035 case res of
2036 FL.Done b -> return $ Done 0 (Left b)
2037 FL.Partial s11 -> grouperL2 s11 s2 a
2039 {-# INLINE grouperR2 #-}
2040 grouperR2 s1 s2 a = do
2041 res <- fstep2 s2 a
2042 return
2043 $ case res of
2044 FL.Done b -> Done 0 (Right b)
2045 FL.Partial s21 -> Partial 0 (GroupByGroupingPairR a s1 s21)
2047 {-# INLINE grouperR #-}
2048 grouperR s1 s2 a0 a = do
2049 res <- fstep2 s2 a0
2050 case res of
2051 FL.Done b -> return $ Done 0 (Right b)
2052 FL.Partial s21 -> grouperR2 s1 s21 a
2054 initial = do
2055 res1 <- finitial1
2056 res2 <- finitial2
2057 return
2058 $ case res1 of
2059 FL.Partial s1 ->
2060 case res2 of
2061 FL.Partial s2 -> IPartial $ GroupByInitPair s1 s2
2062 FL.Done b -> IDone (Right b)
2063 FL.Done b -> IDone (Left b)
2065 step (GroupByInitPair s1 s2) a = grouper s1 s2 a
2067 step (GroupByGroupingPair a0 s1 s2) a =
2068 if not (eq a0 a)
2069 then grouperL s1 s2 a0 a
2070 else grouperR s1 s2 a0 a
2072 step (GroupByGroupingPairL a0 s1 s2) a =
2073 if not (eq a0 a)
2074 then grouperL2 s1 s2 a
2075 else Done 1 . Left <$> ffinal1 s1
2077 step (GroupByGroupingPairR a0 s1 s2) a =
2078 if eq a0 a
2079 then grouperR2 s1 s2 a
2080 else Done 1 . Right <$> ffinal2 s2
2082 extract (GroupByInitPair s1 _) = Done 0 . Left <$> ffinal1 s1
2083 extract (GroupByGroupingPairL _ s1 _) = Done 0 . Left <$> ffinal1 s1
2084 extract (GroupByGroupingPairR _ _ s2) = Done 0 . Right <$> ffinal2 s2
2085 extract (GroupByGroupingPair a s1 _) = do
2086 res <- fstep1 s1 a
2087 case res of
2088 FL.Done b -> return $ Done 0 (Left b)
2089 FL.Partial s11 -> Done 0 . Left <$> ffinal1 s11
2091-- XXX use an Unfold instead of a list?
2092-- XXX custom combinators for matching list, array and stream?
2093-- XXX rename to listBy?
2095-- | Match the given sequence of elements using the given comparison function.
2096-- Returns the original sequence if successful.
2098-- Definition:
2100-- >>> listEqBy cmp xs = Parser.streamEqBy cmp (Stream.fromList xs) *> Parser.fromPure xs
2102-- Examples:
2104-- >>> Stream.parse (Parser.listEqBy (==) "string") $ Stream.fromList "string"
2105-- Right "string"
2107-- >>> Stream.parse (Parser.listEqBy (==) "mismatch") $ Stream.fromList "match"
2108-- Left (ParseError "streamEqBy: mismtach occurred")
2110{-# INLINE listEqBy #-}
2111listEqBy :: Monad m => (a -> a -> Bool) -> [a] -> Parser a m [a]
2112listEqBy cmp xs = streamEqByInternal cmp (D.fromList xs) *> fromPure xs
2114listEqBy cmp str = Parser step initial extract
2116 where
2118 -- XXX Should return IDone in initial for [] case
2119 initial = return $ IPartial str
2121 step [] _ = return $ Done 0 str
2122 step [x] a =
2123 return
2124 $ if x `cmp` a
2125 then Done 0 str
2126 else Error "listEqBy: failed, yet to match the last element"
2127 step (x:xs) a =
2128 return
2129 $ if x `cmp` a
2130 then Continue 0 xs
2131 else Error
2132 $ "listEqBy: failed, yet to match "
2133 ++ show (length xs + 1) ++ " elements"
2135 extract xs =
2136 return
2137 $ Error
2138 $ "listEqBy: end of input, yet to match "
2139 ++ show (length xs) ++ " elements"
2142{-# INLINE streamEqByInternal #-}
2143streamEqByInternal :: Monad m => (a -> a -> Bool) -> D.Stream m a -> Parser a m ()
2144streamEqByInternal cmp (D.Stream sstep state) = Parser step initial extract
2146 where
2148 initial = do
2149 r <- sstep defState state
2150 case r of
2151 D.Yield x s -> return $ IPartial (Just' x, s)
2152 D.Stop -> return $ IDone ()
2153 -- Need Skip/Continue in initial to loop right here
2154 D.Skip s -> return $ IPartial (Nothing', s)
2156 step (Just' x, st) a =
2157 if x `cmp` a
2158 then do
2159 r <- sstep defState st
2160 return
2161 $ case r of
2162 D.Yield x1 s -> Continue 0 (Just' x1, s)
2163 D.Stop -> Done 0 ()
2164 D.Skip s -> Continue 1 (Nothing', s)
2165 else return $ Error "streamEqBy: mismtach occurred"
2166 step (Nothing', st) a = do
2167 r <- sstep defState st
2168 return
2169 $ case r of
2170 D.Yield x s -> do
2171 if x `cmp` a
2172 then Continue 0 (Nothing', s)
2173 else Error "streamEqBy: mismatch occurred"
2174 D.Stop -> Done 1 ()
2175 D.Skip s -> Continue 1 (Nothing', s)
2177 extract _ = return $ Error "streamEqBy: end of input"
2179-- | Like 'listEqBy' but uses a stream instead of a list and does not return
2180-- the stream.
2182{-# INLINE streamEqBy #-}
2183streamEqBy :: Monad m => (a -> a -> Bool) -> D.Stream m a -> Parser a m ()
2184-- XXX Somehow composing this with "*>" is much faster on the microbenchmark.
2185-- Need to investigate why.
2186streamEqBy cmp stream = streamEqByInternal cmp stream *> fromPure ()
2188-- Rename to "list".
2189-- | Match the input sequence with the supplied list and return it if
2190-- successful.
2192-- >>> listEq = Parser.listEqBy (==)
2194{-# INLINE listEq #-}
2195listEq :: (Monad m, Eq a) => [a] -> Parser a m [a]
2196listEq = listEqBy (==)
2198-- | Match if the input stream is a subsequence of the argument stream i.e. all
2199-- the elements of the input stream occur, in order, in the argument stream.
2200-- The elements do not have to occur consecutively. A sequence is considered a
2201-- subsequence of itself.
2202{-# INLINE subsequenceBy #-}
2203subsequenceBy :: -- Monad m =>
2204 (a -> a -> Bool) -> Stream m a -> Parser a m ()
2205subsequenceBy = undefined
2208-- Should go in Data.Parser.Regex in streamly package so that it can depend on
2209-- regex backends.
2210{-# INLINE regexPosix #-}
2211regexPosix :: -- Monad m =>
2212 Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
2213regexPosix = undefined
2215{-# INLINE regexPCRE #-}
2216regexPCRE :: -- Monad m =>
2217 Regex -> Parser m a (Maybe (Array (MatchOffset, MatchLength)))
2218regexPCRE = undefined
2221-------------------------------------------------------------------------------
2222-- Transformations on input
2223-------------------------------------------------------------------------------
2225-- Initial needs a "Continue" constructor to implement scans on parsers. As a
2226-- parser can always return a Continue in initial when we feed the fold's
2227-- initial result to it. We can work this around for postscan by introducing an
2228-- initial state and calling "initial" only on the first input.
2230-- | Stateful scan on the input of a parser using a Fold.
2232-- /Unimplemented/
2234{-# INLINE postscan #-}
2235postscan :: -- Monad m =>
2236 Fold m a b -> Parser b m c -> Parser a m c
2237postscan = undefined
2239{-# INLINE zipWithM #-}
2240zipWithM :: Monad m =>
2241 (a -> b -> m c) -> D.Stream m a -> Fold m c x -> Parser b m x
2242zipWithM zf (D.Stream sstep state) (Fold fstep finitial _ ffinal) =
2243 Parser step initial extract
2245 where
2247 initial = do
2248 fres <- finitial
2249 case fres of
2250 FL.Partial fs -> do
2251 r <- sstep defState state
2252 case r of
2253 D.Yield x s -> return $ IPartial (Just' x, s, fs)
2254 D.Stop -> do
2255 x <- ffinal fs
2256 return $ IDone x
2257 -- Need Skip/Continue in initial to loop right here
2258 D.Skip s -> return $ IPartial (Nothing', s, fs)
2259 FL.Done x -> return $ IDone x
2261 step (Just' a, st, fs) b = do
2262 c <- zf a b
2263 fres <- fstep fs c
2264 case fres of
2265 FL.Partial fs1 -> do
2266 r <- sstep defState st
2267 case r of
2268 D.Yield x1 s -> return $ Continue 0 (Just' x1, s, fs1)
2269 D.Stop -> do
2270 x <- ffinal fs1
2271 return $ Done 0 x
2272 D.Skip s -> return $ Continue 1 (Nothing', s, fs1)
2273 FL.Done x -> return $ Done 0 x
2274 step (Nothing', st, fs) b = do
2275 r <- sstep defState st
2276 case r of
2277 D.Yield a s -> do
2278 c <- zf a b
2279 fres <- fstep fs c
2280 case fres of
2281 FL.Partial fs1 ->
2282 return $ Continue 0 (Nothing', s, fs1)
2283 FL.Done x -> return $ Done 0 x
2284 D.Stop -> do
2285 x <- ffinal fs
2286 return $ Done 1 x
2287 D.Skip s -> return $ Continue 1 (Nothing', s, fs)
2289 extract _ = return $ Error "zipWithM: end of input"
2291-- | Zip the input of a fold with a stream.
2293-- /Pre-release/
2295{-# INLINE zip #-}
2296zip :: Monad m => D.Stream m a -> Fold m (a, b) x -> Parser b m x
2297zip = zipWithM (curry return)
2299-- | Pair each element of a fold input with its index, starting from index 0.
2301-- /Pre-release/
2302{-# INLINE indexed #-}
2303indexed :: forall m a b. Monad m => Fold m (Int, a) b -> Parser a m b
2304indexed = zip (D.enumerateFromIntegral 0 :: D.Stream m Int)
2306-- | @makeIndexFilter indexer filter predicate@ generates a fold filtering
2307-- function using a fold indexing function that attaches an index to each input
2308-- element and a filtering function that filters using @(index, element) ->
2309-- Bool) as predicate.
2311-- For example:
2313-- @
2314-- filterWithIndex = makeIndexFilter indexed filter
2315-- filterWithAbsTime = makeIndexFilter timestamped filter
2316-- filterWithRelTime = makeIndexFilter timeIndexed filter
2317-- @
2319-- /Pre-release/
2320{-# INLINE makeIndexFilter #-}
2321makeIndexFilter ::
2322 (Fold m (s, a) b -> Parser a m b)
2323 -> (((s, a) -> Bool) -> Fold m (s, a) b -> Fold m (s, a) b)
2324 -> (((s, a) -> Bool) -> Fold m a b -> Parser a m b)
2325makeIndexFilter f comb g = f . comb g . FL.lmap snd
2327-- | @sampleFromthen offset stride@ samples the element at @offset@ index and
2328-- then every element at strides of @stride@.
2330-- /Pre-release/
2331{-# INLINE sampleFromthen #-}
2332sampleFromthen :: Monad m => Int -> Int -> Fold m a b -> Parser a m b
2333sampleFromthen offset size =
2334 makeIndexFilter indexed FL.filter (\(i, _) -> (i + offset) `mod` size == 0)
2336--------------------------------------------------------------------------------
2337--- Spanning
2338--------------------------------------------------------------------------------
2340-- | @span p f1 f2@ composes folds @f1@ and @f2@ such that @f1@ consumes the
2341-- input as long as the predicate @p@ is 'True'. @f2@ consumes the rest of the
2342-- input.
2344-- @
2345-- > let span_ p xs = Stream.parse (Parser.span p Fold.toList Fold.toList) $ Stream.fromList xs
2347-- > span_ (< 1) [1,2,3]
2348-- ([],[1,2,3])
2350-- > span_ (< 2) [1,2,3]
2351-- ([1],[2,3])
2353-- > span_ (< 4) [1,2,3]
2354-- ([1,2,3],[])
2356-- @
2358-- /Pre-release/
2359{-# INLINE span #-}
2360span :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (b, c)
2361span p f1 f2 = noErrorUnsafeSplitWith (,) (takeWhile p f1) (fromFold f2)
2363-- | Break the input stream into two groups, the first group takes the input as
2364-- long as the predicate applied to the first element of the stream and next
2365-- input element holds 'True', the second group takes the rest of the input.
2367-- /Pre-release/
2369{-# INLINE spanBy #-}
2370spanBy ::
2371 Monad m
2372 => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (b, c)
2373spanBy eq f1 f2 = noErrorUnsafeSplitWith (,) (groupBy eq f1) (fromFold f2)
2375-- | Like 'spanBy' but applies the predicate in a rolling fashion i.e.
2376-- predicate is applied to the previous and the next input elements.
2378-- /Pre-release/
2379{-# INLINE spanByRolling #-}
2380spanByRolling ::
2381 Monad m
2382 => (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser a m (b, c)
2383spanByRolling eq f1 f2 =
2384 noErrorUnsafeSplitWith (,) (groupByRolling eq f1) (fromFold f2)
2386-------------------------------------------------------------------------------
2387-- nested parsers
2388-------------------------------------------------------------------------------
2390-- | Takes at-most @n@ input elements.
2392-- * Stops - when the collecting parser stops.
2393-- * Fails - when the collecting parser fails.
2395-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
2396-- Right [1,2]
2398-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
2399-- Left (ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4")
2401-- /Internal/
2402{-# INLINE takeP #-}
2403takeP :: Monad m => Int -> Parser a m b -> Parser a m b
2404takeP lim (Parser pstep pinitial pextract) = Parser step initial extract
2406 where
2408 initial = do
2409 res <- pinitial
2410 case res of
2411 IPartial s ->
2412 if lim > 0
2413 then return $ IPartial $ Tuple' 0 s
2414 else iextract s
2415 IDone b -> return $ IDone b
2416 IError e -> return $ IError e
2418 step (Tuple' cnt r) a = do
2419 assertM(cnt < lim)
2420 res <- pstep r a
2421 let cnt1 = cnt + 1
2422 case res of
2423 Partial 0 s -> do
2424 assertM(cnt1 >= 0)
2425 if cnt1 < lim
2426 then return $ Partial 0 $ Tuple' cnt1 s
2427 else do
2428 r1 <- pextract s
2429 return $ case r1 of
2430 Done n b -> Done n b
2431 Continue n s1 -> Continue n (Tuple' (cnt1 - n) s1)
2432 Error err -> Error err
2433 Partial _ _ -> error "takeP: Partial in extract"
2435 Continue 0 s -> do
2436 assertM(cnt1 >= 0)
2437 if cnt1 < lim
2438 then return $ Continue 0 $ Tuple' cnt1 s
2439 else do
2440 r1 <- pextract s
2441 return $ case r1 of
2442 Done n b -> Done n b
2443 Continue n s1 -> Continue n (Tuple' (cnt1 - n) s1)
2444 Error err -> Error err
2445 Partial _ _ -> error "takeP: Partial in extract"
2446 Partial n s -> do
2447 let taken = cnt1 - n
2448 assertM(taken >= 0)
2449 return $ Partial n $ Tuple' taken s
2450 Continue n s -> do
2451 let taken = cnt1 - n
2452 assertM(taken >= 0)
2453 return $ Continue n $ Tuple' taken s
2454 Done n b -> return $ Done n b
2455 Error str -> return $ Error str
2457 extract (Tuple' cnt r) = do
2458 r1 <- pextract r
2459 return $ case r1 of
2460 Done n b -> Done n b
2461 Continue n s1 -> Continue n (Tuple' (cnt - n) s1)
2462 Error err -> Error err
2463 Partial _ _ -> error "takeP: Partial in extract"
2465 -- XXX Need to make the Initial type Step to remove this
2466 iextract s = do
2467 r <- pextract s
2468 return $ case r of
2469 Done _ b -> IDone b
2470 Error err -> IError err
2471 _ -> error "Bug: takeP invalid state in initial"
2473-- | Run a parser without consuming the input.
2475{-# INLINE lookAhead #-}
2476lookAhead :: Monad m => Parser a m b -> Parser a m b
2477lookAhead (Parser step1 initial1 _) = Parser step initial extract
2479 where
2481 initial = do
2482 res <- initial1
2483 return $ case res of
2484 IPartial s -> IPartial (Tuple'Fused 0 s)
2485 IDone b -> IDone b
2486 IError e -> IError e
2488 step (Tuple'Fused cnt st) a = do
2489 r <- step1 st a
2490 let cnt1 = cnt + 1
2491 return
2492 $ case r of
2493 Partial n s -> Continue n (Tuple'Fused (cnt1 - n) s)
2494 Continue n s -> Continue n (Tuple'Fused (cnt1 - n) s)
2495 Done _ b -> Done cnt1 b
2496 Error err -> Error err
2498 -- XXX returning an error let's us backtrack. To implement it in a way so
2499 -- that it terminates on eof without an error then we need a way to
2500 -- backtrack on eof, that will require extract to return 'Step' type.
2501 extract (Tuple'Fused n _) =
2502 return
2503 $ Error
2504 $ "lookAhead: end of input after consuming "
2505 ++ show n ++ " elements"
2507-------------------------------------------------------------------------------
2508-- Interleaving
2509-------------------------------------------------------------------------------
2511-- To deinterleave we can chain two parsers one behind the other. The input is
2512-- given to the first parser and the input definitively rejected by the first
2513-- parser is given to the second parser.
2515-- We can either have the parsers themselves buffer the input or use the shared
2516-- global buffer to hold it until none of the parsers need it. When the first
2517-- parser returns Skip (i.e. rewind) we let the second parser consume the
2518-- rejected input and when it is done we move the cursor forward to the first
2519-- parser again. This will require a "move forward" command as well.
2521-- To implement grep we can use three parsers, one to find the pattern, one
2522-- to store the context behind the pattern and one to store the context in
2523-- front of the pattern. When a match occurs we need to emit the accumulator of
2524-- all the three parsers. One parser can count the line numbers to provide the
2525-- line number info.
2527{-# ANN type DeintercalateAllState Fuse #-}
2528data DeintercalateAllState fs sp ss =
2529 DeintercalateAllInitL !fs
2530 | DeintercalateAllL !fs !sp
2531 | DeintercalateAllInitR !fs
2532 | DeintercalateAllR !fs !ss
2534-- XXX rename this to intercalate
2536-- Having deintercalateAll for accepting or rejecting entire input could be
2537-- useful. For example, in case of JSON parsing we get an entire block of
2538-- key-value pairs which we need to verify. This version may be simpler, more
2539-- efficient. We could implement this as a stream operation like parseMany.
2541-- XXX Also, it may be a good idea to provide a parse driver for a fold. For
2542-- example, in case of csv parsing as we are feeding a line to a fold we can
2543-- parse it.
2545-- | Like 'deintercalate' but the entire input must satisfy the pattern
2546-- otherwise the parser fails. This is many times faster than deintercalate.
2548-- >>> p1 = Parser.takeWhile1 (not . (== '+')) Fold.toList
2549-- >>> p2 = Parser.satisfy (== '+')
2550-- >>> p = Parser.deintercalateAll p1 p2 Fold.toList
2551-- >>> Stream.parse p $ Stream.fromList ""
2552-- Right []
2553-- >>> Stream.parse p $ Stream.fromList "1"
2554-- Right [Left "1"]
2555-- >>> Stream.parse p $ Stream.fromList "1+"
2556-- Left (ParseError "takeWhile1: end of input")
2557-- >>> Stream.parse p $ Stream.fromList "1+2+3"
2558-- Right [Left "1",Right '+',Left "2",Right '+',Left "3"]
2560{-# INLINE deintercalateAll #-}
2561deintercalateAll :: Monad m =>
2562 Parser a m x
2563 -> Parser a m y
2564 -> Fold m (Either x y) z
2565 -> Parser a m z
2566deintercalateAll
2567 (Parser stepL initialL extractL)
2568 (Parser stepR initialR _)
2569 (Fold fstep finitial _ ffinal) = Parser step initial extract
2571 where
2573 errMsg p status =
2574 error $ "deintercalate: " ++ p ++ " parser cannot "
2575 ++ status ++ " without input"
2577 initial = do
2578 res <- finitial
2579 case res of
2580 FL.Partial fs -> return $ IPartial $ DeintercalateAllInitL fs
2581 FL.Done c -> return $ IDone c
2583 {-# INLINE processL #-}
2584 processL foldAction n nextState = do
2585 fres <- foldAction
2586 case fres of
2587 FL.Partial fs1 -> return $ Partial n (nextState fs1)
2588 FL.Done c -> return $ Done n c
2590 {-# INLINE runStepL #-}
2591 runStepL fs sL a = do
2592 r <- stepL sL a
2593 case r of
2594 Partial n s -> return $ Partial n (DeintercalateAllL fs s)
2595 Continue n s -> return $ Continue n (DeintercalateAllL fs s)
2596 Done n b ->
2597 processL (fstep fs (Left b)) n DeintercalateAllInitR
2598 Error err -> return $ Error err
2600 {-# INLINE processR #-}
2601 processR foldAction n = do
2602 fres <- foldAction
2603 case fres of
2604 FL.Partial fs1 -> do
2605 res <- initialL
2606 case res of
2607 IPartial ps -> return $ Partial n (DeintercalateAllL fs1 ps)
2608 IDone _ -> errMsg "left" "succeed"
2609 IError _ -> errMsg "left" "fail"
2610 FL.Done c -> return $ Done n c
2612 {-# INLINE runStepR #-}
2613 runStepR fs sR a = do
2614 r <- stepR sR a
2615 case r of
2616 Partial n s -> return $ Partial n (DeintercalateAllR fs s)
2617 Continue n s -> return $ Continue n (DeintercalateAllR fs s)
2618 Done n b -> processR (fstep fs (Right b)) n
2619 Error err -> return $ Error err
2621 step (DeintercalateAllInitL fs) a = do
2622 res <- initialL
2623 case res of
2624 IPartial s -> runStepL fs s a
2625 IDone _ -> errMsg "left" "succeed"
2626 IError _ -> errMsg "left" "fail"
2627 step (DeintercalateAllL fs sL) a = runStepL fs sL a
2628 step (DeintercalateAllInitR fs) a = do
2629 res <- initialR
2630 case res of
2631 IPartial s -> runStepR fs s a
2632 IDone _ -> errMsg "right" "succeed"
2633 IError _ -> errMsg "right" "fail"
2634 step (DeintercalateAllR fs sR) a = runStepR fs sR a
2636 {-# INLINE extractResult #-}
2637 extractResult n fs r = do
2638 res <- fstep fs r
2639 case res of
2640 FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
2641 FL.Done c -> return (Done n c)
2642 extract (DeintercalateAllInitL fs) = fmap (Done 0) $ ffinal fs
2643 extract (DeintercalateAllL fs sL) = do
2644 r <- extractL sL
2645 case r of
2646 Done n b -> extractResult n fs (Left b)
2647 Error err -> return $ Error err
2648 Continue n s -> return $ Continue n (DeintercalateAllL fs s)
2649 Partial _ _ -> error "Partial in extract"
2650 extract (DeintercalateAllInitR fs) = fmap (Done 0) $ ffinal fs
2651 extract (DeintercalateAllR _ _) =
2652 return $ Error "deintercalateAll: input ended at 'Right' value"
2654{-# ANN type DeintercalateState Fuse #-}
2655data DeintercalateState b fs sp ss =
2656 DeintercalateInitL !fs
2657 | DeintercalateL !Int !fs !sp
2658 | DeintercalateInitR !fs
2659 | DeintercalateR !Int !fs !ss
2660 | DeintercalateRL !Int !b !fs !sp
2662-- XXX Add tests that the next character that we take after running a parser is
2663-- correct. Especially for the parsers that maintain a count. In the stream
2664-- finished case (extract) as well as not finished case.
2666-- | Apply two parsers alternately to an input stream. The input stream is
2667-- considered an interleaving of two patterns. The two parsers represent the
2668-- two patterns. Parsing starts at the first parser and stops at the first
2669-- parser. It can be used to parse a infix style pattern e.g. p1 p2 p1 . Empty
2670-- input or single parse of the first parser is accepted.
2672-- >>> p1 = Parser.takeWhile1 (not . (== '+')) Fold.toList
2673-- >>> p2 = Parser.satisfy (== '+')
2674-- >>> p = Parser.deintercalate p1 p2 Fold.toList
2675-- >>> Stream.parse p $ Stream.fromList ""
2676-- Right []
2677-- >>> Stream.parse p $ Stream.fromList "1"
2678-- Right [Left "1"]
2679-- >>> Stream.parse p $ Stream.fromList "1+"
2680-- Right [Left "1"]
2681-- >>> Stream.parse p $ Stream.fromList "1+2+3"
2682-- Right [Left "1",Right '+',Left "2",Right '+',Left "3"]
2684{-# INLINE deintercalate #-}
2685deintercalate :: Monad m =>
2686 Parser a m x
2687 -> Parser a m y
2688 -> Fold m (Either x y) z
2689 -> Parser a m z
2690deintercalate
2691 (Parser stepL initialL extractL)
2692 (Parser stepR initialR _)
2693 (Fold fstep finitial _ ffinal) = Parser step initial extract
2695 where
2697 errMsg p status =
2698 error $ "deintercalate: " ++ p ++ " parser cannot "
2699 ++ status ++ " without input"
2701 initial = do
2702 res <- finitial
2703 case res of
2704 FL.Partial fs -> return $ IPartial $ DeintercalateInitL fs
2705 FL.Done c -> return $ IDone c
2707 {-# INLINE processL #-}
2708 processL foldAction n nextState = do
2709 fres <- foldAction
2710 case fres of
2711 FL.Partial fs1 -> return $ Partial n (nextState fs1)
2712 FL.Done c -> return $ Done n c
2714 {-# INLINE runStepL #-}
2715 runStepL cnt fs sL a = do
2716 let cnt1 = cnt + 1
2717 r <- stepL sL a
2718 case r of
2719 Partial n s -> return $ Continue n (DeintercalateL (cnt1 - n) fs s)
2720 Continue n s -> return $ Continue n (DeintercalateL (cnt1 - n) fs s)
2721 Done n b ->
2722 processL (fstep fs (Left b)) n DeintercalateInitR
2723 Error _ -> do
2724 xs <- ffinal fs
2725 return $ Done cnt1 xs
2727 {-# INLINE processR #-}
2728 processR cnt b fs n = do
2729 res <- initialL
2730 case res of
2731 IPartial ps -> return $ Continue n (DeintercalateRL cnt b fs ps)
2732 IDone _ -> errMsg "left" "succeed"
2733 IError _ -> errMsg "left" "fail"
2735 {-# INLINE runStepR #-}
2736 runStepR cnt fs sR a = do
2737 let cnt1 = cnt + 1
2738 r <- stepR sR a
2739 case r of
2740 Partial n s -> return $ Continue n (DeintercalateR (cnt1 - n) fs s)
2741 Continue n s -> return $ Continue n (DeintercalateR (cnt1 - n) fs s)
2742 Done n b -> processR (cnt1 - n) b fs n
2743 Error _ -> do
2744 xs <- ffinal fs
2745 return $ Done cnt1 xs
2747 step (DeintercalateInitL fs) a = do
2748 res <- initialL
2749 case res of
2750 IPartial s -> runStepL 0 fs s a
2751 IDone _ -> errMsg "left" "succeed"
2752 IError _ -> errMsg "left" "fail"
2753 step (DeintercalateL cnt fs sL) a = runStepL cnt fs sL a
2754 step (DeintercalateInitR fs) a = do
2755 res <- initialR
2756 case res of
2757 IPartial s -> runStepR 0 fs s a
2758 IDone _ -> errMsg "right" "succeed"
2759 IError _ -> errMsg "right" "fail"
2760 step (DeintercalateR cnt fs sR) a = runStepR cnt fs sR a
2761 step (DeintercalateRL cnt bR fs sL) a = do
2762 let cnt1 = cnt + 1
2763 r <- stepL sL a
2764 case r of
2765 Partial n s -> return $ Continue n (DeintercalateRL (cnt1 - n) bR fs s)
2766 Continue n s -> return $ Continue n (DeintercalateRL (cnt1 - n) bR fs s)
2767 Done n bL -> do
2768 res <- fstep fs (Right bR)
2769 case res of
2770 FL.Partial fs1 -> do
2771 fres <- fstep fs1 (Left bL)
2772 case fres of
2773 FL.Partial fs2 ->
2774 return $ Partial n (DeintercalateInitR fs2)
2775 FL.Done c -> return $ Done n c
2776 -- XXX We could have the fold accept pairs of (bR, bL)
2777 FL.Done _ -> error "Fold terminated consuming partial input"
2778 Error _ -> do
2779 xs <- ffinal fs
2780 return $ Done cnt1 xs
2782 {-# INLINE extractResult #-}
2783 extractResult n fs r = do
2784 res <- fstep fs r
2785 case res of
2786 FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
2787 FL.Done c -> return (Done n c)
2789 extract (DeintercalateInitL fs) = fmap (Done 0) $ ffinal fs
2790 extract (DeintercalateL cnt fs sL) = do
2791 r <- extractL sL
2792 case r of
2793 Done n b -> extractResult n fs (Left b)
2794 Continue n s -> return $ Continue n (DeintercalateL (cnt - n) fs s)
2795 Partial _ _ -> error "Partial in extract"
2796 Error _ -> do
2797 xs <- ffinal fs
2798 return $ Done cnt xs
2799 extract (DeintercalateInitR fs) = fmap (Done 0) $ ffinal fs
2800 extract (DeintercalateR cnt fs _) = fmap (Done cnt) $ ffinal fs
2801 extract (DeintercalateRL cnt bR fs sL) = do
2802 r <- extractL sL
2803 case r of
2804 Done n bL -> do
2805 res <- fstep fs (Right bR)
2806 case res of
2807 FL.Partial fs1 -> extractResult n fs1 (Left bL)
2808 FL.Done _ -> error "Fold terminated consuming partial input"
2809 Continue n s -> return $ Continue n (DeintercalateRL (cnt - n) bR fs s)
2810 Partial _ _ -> error "Partial in extract"
2811 Error _ -> do
2812 xs <- ffinal fs
2813 return $ Done cnt xs
2815{-# ANN type Deintercalate1State Fuse #-}
2816data Deintercalate1State b fs sp ss =
2817 Deintercalate1InitL !Int !fs !sp
2818 | Deintercalate1InitR !fs
2819 | Deintercalate1R !Int !fs !ss
2820 | Deintercalate1RL !Int !b !fs !sp
2822-- | Apply two parsers alternately to an input stream. The input stream is
2823-- considered an interleaving of two patterns. The two parsers represent the
2824-- two patterns. Parsing starts at the first parser and stops at the first
2825-- parser. It can be used to parse a infix style pattern e.g. p1 p2 p1 . Empty
2826-- input or single parse of the first parser is accepted.
2828-- >>> p1 = Parser.takeWhile1 (not . (== '+')) Fold.toList
2829-- >>> p2 = Parser.satisfy (== '+')
2830-- >>> p = Parser.deintercalate1 p1 p2 Fold.toList
2831-- >>> Stream.parse p $ Stream.fromList ""
2832-- Left (ParseError "takeWhile1: end of input")
2833-- >>> Stream.parse p $ Stream.fromList "1"
2834-- Right [Left "1"]
2835-- >>> Stream.parse p $ Stream.fromList "1+"
2836-- Right [Left "1"]
2837-- >>> Stream.parse p $ Stream.fromList "1+2+3"
2838-- Right [Left "1",Right '+',Left "2",Right '+',Left "3"]
2840{-# INLINE deintercalate1 #-}
2841deintercalate1 :: Monad m =>
2842 Parser a m x
2843 -> Parser a m y
2844 -> Fold m (Either x y) z
2845 -> Parser a m z
2846deintercalate1
2847 (Parser stepL initialL extractL)
2848 (Parser stepR initialR _)
2849 (Fold fstep finitial _ ffinal) = Parser step initial extract
2851 where
2853 errMsg p status =
2854 error $ "deintercalate: " ++ p ++ " parser cannot "
2855 ++ status ++ " without input"
2857 initial = do
2858 res <- finitial
2859 case res of
2860 FL.Partial fs -> do
2861 pres <- initialL
2862 case pres of
2863 IPartial s -> return $ IPartial $ Deintercalate1InitL 0 fs s
2864 IDone _ -> errMsg "left" "succeed"
2865 IError _ -> errMsg "left" "fail"
2866 FL.Done c -> return $ IDone c
2868 {-# INLINE processL #-}
2869 processL foldAction n nextState = do
2870 fres <- foldAction
2871 case fres of
2872 FL.Partial fs1 -> return $ Partial n (nextState fs1)
2873 FL.Done c -> return $ Done n c
2875 {-# INLINE runStepInitL #-}
2876 runStepInitL cnt fs sL a = do
2877 let cnt1 = cnt + 1
2878 r <- stepL sL a
2879 case r of
2880 Partial n s -> return $ Continue n (Deintercalate1InitL (cnt1 - n) fs s)
2881 Continue n s -> return $ Continue n (Deintercalate1InitL (cnt1 - n) fs s)
2882 Done n b ->
2883 processL (fstep fs (Left b)) n Deintercalate1InitR
2884 Error err -> return $ Error err
2886 {-# INLINE processR #-}
2887 processR cnt b fs n = do
2888 res <- initialL
2889 case res of
2890 IPartial ps -> return $ Continue n (Deintercalate1RL cnt b fs ps)
2891 IDone _ -> errMsg "left" "succeed"
2892 IError _ -> errMsg "left" "fail"
2894 {-# INLINE runStepR #-}
2895 runStepR cnt fs sR a = do
2896 let cnt1 = cnt + 1
2897 r <- stepR sR a
2898 case r of
2899 Partial n s -> return $ Continue n (Deintercalate1R (cnt1 - n) fs s)
2900 Continue n s -> return $ Continue n (Deintercalate1R (cnt1 - n) fs s)
2901 Done n b -> processR (cnt1 - n) b fs n
2902 Error _ -> do
2903 xs <- ffinal fs
2904 return $ Done cnt1 xs
2906 step (Deintercalate1InitL cnt fs sL) a = runStepInitL cnt fs sL a
2907 step (Deintercalate1InitR fs) a = do
2908 res <- initialR
2909 case res of
2910 IPartial s -> runStepR 0 fs s a
2911 IDone _ -> errMsg "right" "succeed"
2912 IError _ -> errMsg "right" "fail"
2913 step (Deintercalate1R cnt fs sR) a = runStepR cnt fs sR a
2914 step (Deintercalate1RL cnt bR fs sL) a = do
2915 let cnt1 = cnt + 1
2916 r <- stepL sL a
2917 case r of
2918 Partial n s -> return $ Continue n (Deintercalate1RL (cnt1 - n) bR fs s)
2919 Continue n s -> return $ Continue n (Deintercalate1RL (cnt1 - n) bR fs s)
2920 Done n bL -> do
2921 res <- fstep fs (Right bR)
2922 case res of
2923 FL.Partial fs1 -> do
2924 fres <- fstep fs1 (Left bL)
2925 case fres of
2926 FL.Partial fs2 ->
2927 return $ Partial n (Deintercalate1InitR fs2)
2928 FL.Done c -> return $ Done n c
2929 -- XXX We could have the fold accept pairs of (bR, bL)
2930 FL.Done _ -> error "Fold terminated consuming partial input"
2931 Error _ -> do
2932 xs <- ffinal fs
2933 return $ Done cnt1 xs
2935 {-# INLINE extractResult #-}
2936 extractResult n fs r = do
2937 res <- fstep fs r
2938 case res of
2939 FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
2940 FL.Done c -> return (Done n c)
2942 extract (Deintercalate1InitL cnt fs sL) = do
2943 r <- extractL sL
2944 case r of
2945 Done n b -> extractResult n fs (Left b)
2946 Continue n s -> return $ Continue n (Deintercalate1InitL (cnt - n) fs s)
2947 Partial _ _ -> error "Partial in extract"
2948 Error err -> return $ Error err
2949 extract (Deintercalate1InitR fs) = fmap (Done 0) $ ffinal fs
2950 extract (Deintercalate1R cnt fs _) = fmap (Done cnt) $ ffinal fs
2951 extract (Deintercalate1RL cnt bR fs sL) = do
2952 r <- extractL sL
2953 case r of
2954 Done n bL -> do
2955 res <- fstep fs (Right bR)
2956 case res of
2957 FL.Partial fs1 -> extractResult n fs1 (Left bL)
2958 FL.Done _ -> error "Fold terminated consuming partial input"
2959 Continue n s -> return $ Continue n (Deintercalate1RL (cnt - n) bR fs s)
2960 Partial _ _ -> error "Partial in extract"
2961 Error _ -> do
2962 xs <- ffinal fs
2963 return $ Done cnt xs
2965{-# ANN type SepByState Fuse #-}
2966data SepByState fs sp ss =
2967 SepByInitL !fs
2968 | SepByL !Int !fs !sp
2969 | SepByInitR !fs
2970 | SepByR !Int !fs !ss
2972-- | Apply two parsers alternately to an input stream. Parsing starts at the
2973-- first parser and stops at the first parser. The output of the first parser
2974-- is emiited and the output of the second parser is discarded. It can be used
2975-- to parse a infix style pattern e.g. p1 p2 p1 . Empty input or single parse
2976-- of the first parser is accepted.
2978-- Definitions:
2980-- >>> sepBy p1 p2 f = Parser.deintercalate p1 p2 (Fold.catLefts f)
2981-- >>> sepBy p1 p2 f = Parser.sepBy1 p1 p2 f <|> Parser.fromEffect (Fold.extractM f)
2983-- Examples:
2985-- >>> p1 = Parser.takeWhile1 (not . (== '+')) Fold.toList
2986-- >>> p2 = Parser.satisfy (== '+')
2987-- >>> p = Parser.sepBy p1 p2 Fold.toList
2988-- >>> Stream.parse p $ Stream.fromList ""
2989-- Right []
2990-- >>> Stream.parse p $ Stream.fromList "1"
2991-- Right ["1"]
2992-- >>> Stream.parse p $ Stream.fromList "1+"
2993-- Right ["1"]
2994-- >>> Stream.parse p $ Stream.fromList "1+2+3"
2995-- Right ["1","2","3"]
2997{-# INLINE sepBy #-}
2998sepBy :: Monad m =>
2999 Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3000-- This has similar performance as the custom impl below.
3001-- sepBy p1 p2 f = deintercalate p1 p2 (FL.catLefts f)
3002sepBy
3003 (Parser stepL initialL extractL)
3004 (Parser stepR initialR _)
3005 (Fold fstep finitial _ ffinal) = Parser step initial extract
3007 where
3009 errMsg p status =
3010 error $ "sepBy: " ++ p ++ " parser cannot "
3011 ++ status ++ " without input"
3013 initial = do
3014 res <- finitial
3015 case res of
3016 FL.Partial fs -> return $ IPartial $ SepByInitL fs
3017 FL.Done c -> return $ IDone c
3019 {-# INLINE processL #-}
3020 processL foldAction n nextState = do
3021 fres <- foldAction
3022 case fres of
3023 FL.Partial fs1 -> return $ Partial n (nextState fs1)
3024 FL.Done c -> return $ Done n c
3026 {-# INLINE runStepL #-}
3027 runStepL cnt fs sL a = do
3028 let cnt1 = cnt + 1
3029 r <- stepL sL a
3030 case r of
3031 Partial n s -> return $ Continue n (SepByL (cnt1 - n) fs s)
3032 Continue n s -> return $ Continue n (SepByL (cnt1 - n) fs s)
3033 Done n b ->
3034 processL (fstep fs b) n SepByInitR
3035 Error _ -> do
3036 xs <- ffinal fs
3037 return $ Done cnt1 xs
3039 {-# INLINE processR #-}
3040 processR cnt fs n = do
3041 res <- initialL
3042 case res of
3043 IPartial ps -> return $ Continue n (SepByL cnt fs ps)
3044 IDone _ -> errMsg "left" "succeed"
3045 IError _ -> errMsg "left" "fail"
3047 {-# INLINE runStepR #-}
3048 runStepR cnt fs sR a = do
3049 let cnt1 = cnt + 1
3050 r <- stepR sR a
3051 case r of
3052 Partial n s -> return $ Continue n (SepByR (cnt1 - n) fs s)
3053 Continue n s -> return $ Continue n (SepByR (cnt1 - n) fs s)
3054 Done n _ -> processR (cnt1 - n) fs n
3055 Error _ -> do
3056 xs <- ffinal fs
3057 return $ Done cnt1 xs
3059 step (SepByInitL fs) a = do
3060 res <- initialL
3061 case res of
3062 IPartial s -> runStepL 0 fs s a
3063 IDone _ -> errMsg "left" "succeed"
3064 IError _ -> errMsg "left" "fail"
3065 step (SepByL cnt fs sL) a = runStepL cnt fs sL a
3066 step (SepByInitR fs) a = do
3067 res <- initialR
3068 case res of
3069 IPartial s -> runStepR 0 fs s a
3070 IDone _ -> errMsg "right" "succeed"
3071 IError _ -> errMsg "right" "fail"
3072 step (SepByR cnt fs sR) a = runStepR cnt fs sR a
3074 {-# INLINE extractResult #-}
3075 extractResult n fs r = do
3076 res <- fstep fs r
3077 case res of
3078 FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3079 FL.Done c -> return (Done n c)
3081 extract (SepByInitL fs) = fmap (Done 0) $ ffinal fs
3082 extract (SepByL cnt fs sL) = do
3083 r <- extractL sL
3084 case r of
3085 Done n b -> extractResult n fs b
3086 Continue n s -> return $ Continue n (SepByL (cnt - n) fs s)
3087 Partial _ _ -> error "Partial in extract"
3088 Error _ -> do
3089 xs <- ffinal fs
3090 return $ Done cnt xs
3091 extract (SepByInitR fs) = fmap (Done 0) $ ffinal fs
3092 extract (SepByR cnt fs _) = fmap (Done cnt) $ ffinal fs
3094-- | Non-backtracking version of sepBy. Several times faster.
3095{-# INLINE sepByAll #-}
3096sepByAll :: Monad m =>
3097 Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3098sepByAll p1 p2 f = deintercalateAll p1 p2 (FL.catLefts f)
3100-- XXX This can be implemented using refold, parse one and then continue
3101-- collecting the rest in that.
3103{-# ANN type SepBy1State Fuse #-}
3104data SepBy1State fs sp ss =
3105 SepBy1InitL !Int !fs sp
3106 | SepBy1L !Int !fs !sp
3107 | SepBy1InitR !fs
3108 | SepBy1R !Int !fs !ss
3111{-# INLINE sepBy1 #-}
3112sepBy1 :: Monad m =>
3113 Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3114sepBy1 p sep sink = do
3115 x <- p
3116 f <- fromEffect $ FL.reduce sink
3117 f1 <- fromEffect $ FL.snoc f x
3118 many (sep >> p) f1
3121-- | Like 'sepBy' but requires at least one successful parse.
3123-- Definition:
3125-- >>> sepBy1 p1 p2 f = Parser.deintercalate1 p1 p2 (Fold.catLefts f)
3127-- Examples:
3129-- >>> p1 = Parser.takeWhile1 (not . (== '+')) Fold.toList
3130-- >>> p2 = Parser.satisfy (== '+')
3131-- >>> p = Parser.sepBy1 p1 p2 Fold.toList
3132-- >>> Stream.parse p $ Stream.fromList ""
3133-- Left (ParseError "takeWhile1: end of input")
3134-- >>> Stream.parse p $ Stream.fromList "1"
3135-- Right ["1"]
3136-- >>> Stream.parse p $ Stream.fromList "1+"
3137-- Right ["1"]
3138-- >>> Stream.parse p $ Stream.fromList "1+2+3"
3139-- Right ["1","2","3"]
3141{-# INLINE sepBy1 #-}
3142sepBy1 :: Monad m =>
3143 Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3144sepBy1
3145 (Parser stepL initialL extractL)
3146 (Parser stepR initialR _)
3147 (Fold fstep finitial _ ffinal) = Parser step initial extract
3149 where
3151 errMsg p status =
3152 error $ "sepBy: " ++ p ++ " parser cannot "
3153 ++ status ++ " without input"
3155 initial = do
3156 res <- finitial
3157 case res of
3158 FL.Partial fs -> do
3159 pres <- initialL
3160 case pres of
3161 IPartial s -> return $ IPartial $ SepBy1InitL 0 fs s
3162 IDone _ -> errMsg "left" "succeed"
3163 IError _ -> errMsg "left" "fail"
3164 FL.Done c -> return $ IDone c
3166 {-# INLINE processL #-}
3167 processL foldAction n nextState = do
3168 fres <- foldAction
3169 case fres of
3170 FL.Partial fs1 -> return $ Partial n (nextState fs1)
3171 FL.Done c -> return $ Done n c
3173 {-# INLINE runStepInitL #-}
3174 runStepInitL cnt fs sL a = do
3175 let cnt1 = cnt + 1
3176 r <- stepL sL a
3177 case r of
3178 Partial n s -> return $ Continue n (SepBy1InitL (cnt1 - n) fs s)
3179 Continue n s -> return $ Continue n (SepBy1InitL (cnt1 - n) fs s)
3180 Done n b ->
3181 processL (fstep fs b) n SepBy1InitR
3182 Error err -> return $ Error err
3184 {-# INLINE runStepL #-}
3185 runStepL cnt fs sL a = do
3186 let cnt1 = cnt + 1
3187 r <- stepL sL a
3188 case r of
3189 Partial n s -> return $ Continue n (SepBy1L (cnt1 - n) fs s)
3190 Continue n s -> return $ Continue n (SepBy1L (cnt1 - n) fs s)
3191 Done n b ->
3192 processL (fstep fs b) n SepBy1InitR
3193 Error _ -> do
3194 xs <- ffinal fs
3195 return $ Done cnt1 xs
3197 {-# INLINE processR #-}
3198 processR cnt fs n = do
3199 res <- initialL
3200 case res of
3201 IPartial ps -> return $ Continue n (SepBy1L cnt fs ps)
3202 IDone _ -> errMsg "left" "succeed"
3203 IError _ -> errMsg "left" "fail"
3205 {-# INLINE runStepR #-}
3206 runStepR cnt fs sR a = do
3207 let cnt1 = cnt + 1
3208 r <- stepR sR a
3209 case r of
3210 Partial n s -> return $ Continue n (SepBy1R (cnt1 - n) fs s)
3211 Continue n s -> return $ Continue n (SepBy1R (cnt1 - n) fs s)
3212 Done n _ -> processR (cnt1 - n) fs n
3213 Error _ -> do
3214 xs <- ffinal fs
3215 return $ Done cnt1 xs
3217 step (SepBy1InitL cnt fs sL) a = runStepInitL cnt fs sL a
3218 step (SepBy1L cnt fs sL) a = runStepL cnt fs sL a
3219 step (SepBy1InitR fs) a = do
3220 res <- initialR
3221 case res of
3222 IPartial s -> runStepR 0 fs s a
3223 IDone _ -> errMsg "right" "succeed"
3224 IError _ -> errMsg "right" "fail"
3225 step (SepBy1R cnt fs sR) a = runStepR cnt fs sR a
3227 {-# INLINE extractResult #-}
3228 extractResult n fs r = do
3229 res <- fstep fs r
3230 case res of
3231 FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3232 FL.Done c -> return (Done n c)
3234 extract (SepBy1InitL cnt fs sL) = do
3235 r <- extractL sL
3236 case r of
3237 Done n b -> extractResult n fs b
3238 Continue n s -> return $ Continue n (SepBy1InitL (cnt - n) fs s)
3239 Partial _ _ -> error "Partial in extract"
3240 Error err -> return $ Error err
3241 extract (SepBy1L cnt fs sL) = do
3242 r <- extractL sL
3243 case r of
3244 Done n b -> extractResult n fs b
3245 Continue n s -> return $ Continue n (SepBy1L (cnt - n) fs s)
3246 Partial _ _ -> error "Partial in extract"
3247 Error _ -> do
3248 xs <- ffinal fs
3249 return $ Done cnt xs
3250 extract (SepBy1InitR fs) = fmap (Done 0) $ ffinal fs
3251 extract (SepBy1R cnt fs _) = fmap (Done cnt) $ ffinal fs
3253-------------------------------------------------------------------------------
3254-- Interleaving a collection of parsers
3255-------------------------------------------------------------------------------
3257-- | Apply a collection of parsers to an input stream in a round robin fashion.
3258-- Each parser is applied until it stops and then we repeat starting with the
3259-- the first parser again.
3261-- /Unimplemented/
3263{-# INLINE roundRobin #-}
3264roundRobin :: -- (Foldable t, Monad m) =>
3265 t (Parser a m b) -> Fold m b c -> Parser a m c
3266roundRobin _ps _f = undefined
3268-------------------------------------------------------------------------------
3269-- Sequential Collection
3270-------------------------------------------------------------------------------
3272-- | @sequence f p@ collects sequential parses of parsers in a
3273-- serial stream @p@ using the fold @f@. Fails if the input ends or any
3274-- of the parsers fail.
3276-- /Pre-release/
3278{-# INLINE sequence #-}
3279sequence :: Monad m =>
3280 D.Stream m (Parser a m b) -> Fold m b c -> Parser a m c
3281sequence (D.Stream sstep sstate) (Fold fstep finitial _ ffinal) =
3282 Parser step initial extract
3284 where
3286 initial = do
3287 fres <- finitial
3288 case fres of
3289 FL.Partial fs -> return $ IPartial (Nothing', sstate, fs)
3290 FL.Done c -> return $ IDone c
3292 -- state does not contain any parser
3293 -- yield a new parser from the stream
3294 step (Nothing', ss, fs) _ = do
3295 sres <- sstep defState ss
3296 case sres of
3297 D.Yield p ss1 -> return $ Continue 1 (Just' p, ss1, fs)
3298 D.Stop -> do
3299 c <- ffinal fs
3300 return $ Done 1 c
3301 D.Skip ss1 -> return $ Continue 1 (Nothing', ss1, fs)
3303 -- state holds a parser that may or may not have been
3304 -- initialized. pinit holds the initial parser state
3305 -- or modified parser state respectively
3306 step (Just' (Parser pstep pinit pextr), ss, fs) a = do
3307 ps <- pinit
3308 case ps of
3309 IPartial ps1 -> do
3310 pres <- pstep ps1 a
3311 case pres of
3312 Partial n ps2 ->
3313 let newP =
3314 Just' $ Parser pstep (return $ IPartial ps2) pextr
3315 in return $ Partial n (newP, ss, fs)
3316 Continue n ps2 ->
3317 let newP =
3318 Just' $ Parser pstep (return $ IPartial ps2) pextr
3319 in return $ Continue n (newP, ss, fs)
3320 Done n b -> do
3321 fres <- fstep fs b
3322 case fres of
3323 FL.Partial fs1 ->
3324 return $ Partial n (Nothing', ss, fs1)
3325 FL.Done c -> return $ Done n c
3326 Error msg -> return $ Error msg
3327 IDone b -> do
3328 fres <- fstep fs b
3329 case fres of
3330 FL.Partial fs1 ->
3331 return $ Partial 1 (Nothing', ss, fs1)
3332 FL.Done c -> return $ Done 1 c
3333 IError err -> return $ Error err
3335 extract (Nothing', _, fs) = fmap (Done 0) $ ffinal fs
3336 extract (Just' (Parser pstep pinit pextr), ss, fs) = do
3337 ps <- pinit
3338 case ps of
3339 IPartial ps1 -> do
3340 r <- pextr ps1
3341 case r of
3342 Done n b -> do
3343 res <- fstep fs b
3344 case res of
3345 FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3346 FL.Done c -> return (Done n c)
3347 Error err -> return $ Error err
3348 Continue n s -> return $ Continue n (Just' (Parser pstep (return (IPartial s)) pextr), ss, fs)
3349 Partial _ _ -> error "Partial in extract"
3350 IDone b -> do
3351 fres <- fstep fs b
3352 case fres of
3353 FL.Partial fs1 -> fmap (Done 0) $ ffinal fs1
3354 FL.Done c -> return (Done 0 c)
3355 IError err -> return $ Error err
3357-------------------------------------------------------------------------------
3358-- Alternative Collection
3359-------------------------------------------------------------------------------
3362-- | @choice parsers@ applies the @parsers@ in order and returns the first
3363-- successful parse.
3365-- This is same as 'asum' but more efficient.
3367-- /Broken/
3369{-# INLINE choice #-}
3370choice :: (MonadCatch m, Foldable t) => t (Parser a m b) -> Parser a m b
3371choice = foldl1 shortest
3374-------------------------------------------------------------------------------
3375-- Sequential Repetition
3376-------------------------------------------------------------------------------
3378-- | Like 'many' but uses a 'Parser' instead of a 'Fold' to collect the
3379-- results. Parsing stops or fails if the collecting parser stops or fails.
3381-- /Unimplemented/
3383{-# INLINE manyP #-}
3384manyP :: -- MonadCatch m =>
3385 Parser a m b -> Parser b m c -> Parser a m c
3386manyP _p _f = undefined
3388-- | Collect zero or more parses. Apply the supplied parser repeatedly on the
3389-- input stream and push the parse results to a downstream fold.
3391-- Stops: when the downstream fold stops or the parser fails.
3392-- Fails: never, produces zero or more results.
3394-- >>> many = Parser.countBetween 0 maxBound
3396-- Compare with 'Control.Applicative.many'.
3398{-# INLINE many #-}
3399many :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
3400many = splitMany
3401-- many = countBetween 0 maxBound
3403-- Note: many1 would perhaps be a better name for this and consistent with
3404-- other names like takeWhile1. But we retain the name "some" for
3405-- compatibility.
3407-- | Collect one or more parses. Apply the supplied parser repeatedly on the
3408-- input stream and push the parse results to a downstream fold.
3410-- Stops: when the downstream fold stops or the parser fails.
3411-- Fails: if it stops without producing a single result.
3413-- >>> some p f = Parser.manyP p (Parser.takeGE 1 f)
3414-- >>> some = Parser.countBetween 1 maxBound
3416-- Compare with 'Control.Applicative.some'.
3418{-# INLINE some #-}
3419some :: Monad m => Parser a m b -> Fold m b c -> Parser a m c
3420some = splitSome
3421-- some p f = manyP p (takeGE 1 f)
3422-- some = countBetween 1 maxBound
3424-- | @countBetween m n f p@ collects between @m@ and @n@ sequential parses of
3425-- parser @p@ using the fold @f@. Stop after collecting @n@ results. Fails if
3426-- the input ends or the parser fails before @m@ results are collected.
3428-- >>> countBetween m n p f = Parser.manyP p (Parser.takeBetween m n f)
3430-- /Unimplemented/
3432{-# INLINE countBetween #-}
3433countBetween :: -- MonadCatch m =>
3434 Int -> Int -> Parser a m b -> Fold m b c -> Parser a m c
3435countBetween _m _n _p = undefined
3436-- countBetween m n p f = manyP p (takeBetween m n f)
3438-- | @count n f p@ collects exactly @n@ sequential parses of parser @p@ using
3439-- the fold @f@. Fails if the input ends or the parser fails before @n@
3440-- results are collected.
3442-- >>> count n = Parser.countBetween n n
3443-- >>> count n p f = Parser.manyP p (Parser.takeEQ n f)
3445-- /Unimplemented/
3447{-# INLINE count #-}
3448count :: -- MonadCatch m =>
3449 Int -> Parser a m b -> Fold m b c -> Parser a m c
3450count n = countBetween n n
3451-- count n p f = manyP p (takeEQ n f)
3453-- | Like 'manyTill' but uses a 'Parser' to collect the results instead of a
3454-- 'Fold'. Parsing stops or fails if the collecting parser stops or fails.
3456-- We can implemnent parsers like the following using 'manyTillP':
3458-- @
3459-- countBetweenTill m n f p = manyTillP (takeBetween m n f) p
3460-- @
3462-- /Unimplemented/
3464{-# INLINE manyTillP #-}
3465manyTillP :: -- Monad m =>
3466 Parser a m b -> Parser a m x -> Parser b m c -> Parser a m c
3467manyTillP _p1 _p2 _f = undefined
3468 -- D.toParserK $ D.manyTillP (D.fromParserK p1) (D.fromParserK p2) f
3470{-# ANN type ManyTillState Fuse #-}
3471data ManyTillState fs sr sl
3472 = ManyTillR !Int !fs !sr
3473 | ManyTillL !fs !sl
3475-- | @manyTill chunking test f@ tries the parser @test@ on the input, if @test@
3476-- fails it backtracks and tries @chunking@, after @chunking@ succeeds @test@ is
3477-- tried again and so on. The parser stops when @test@ succeeds. The output of
3478-- @test@ is discarded and the output of @chunking@ is accumulated by the
3479-- supplied fold. The parser fails if @chunking@ fails.
3481-- Stops when the fold @f@ stops.
3483{-# INLINE manyTill #-}
3484manyTill :: Monad m
3485 => Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3486manyTill (Parser stepL initialL extractL)
3487 (Parser stepR initialR _)
3488 (Fold fstep finitial _ ffinal) =
3489 Parser step initial extract
3491 where
3493 -- Caution: Mutual recursion
3495 scrutL fs p c d e = do
3496 resL <- initialL
3497 case resL of
3498 IPartial sl -> return $ c (ManyTillL fs sl)
3499 IDone bl -> do
3500 fr <- fstep fs bl
3501 case fr of
3502 FL.Partial fs1 -> scrutR fs1 p c d e
3503 FL.Done fb -> return $ d fb
3504 IError err -> return $ e err
3506 scrutR fs p c d e = do
3507 resR <- initialR
3508 case resR of
3509 IPartial sr -> return $ p (ManyTillR 0 fs sr)
3510 IDone _ -> d <$> ffinal fs
3511 IError _ -> scrutL fs p c d e
3513 initial = do
3514 res <- finitial
3515 case res of
3516 FL.Partial fs -> scrutR fs IPartial IPartial IDone IError
3517 FL.Done b -> return $ IDone b
3519 step (ManyTillR cnt fs st) a = do
3520 r <- stepR st a
3521 case r of
3522 Partial n s -> return $ Partial n (ManyTillR 0 fs s)
3523 Continue n s -> do
3524 assertM(cnt + 1 - n >= 0)
3525 return $ Continue n (ManyTillR (cnt + 1 - n) fs s)
3526 Done n _ -> do
3527 b <- ffinal fs
3528 return $ Done n b
3529 Error _ -> do
3530 resL <- initialL
3531 case resL of
3532 IPartial sl ->
3533 return $ Continue (cnt + 1) (ManyTillL fs sl)
3534 IDone bl -> do
3535 fr <- fstep fs bl
3536 let cnt1 = cnt + 1
3537 case fr of
3538 FL.Partial fs1 ->
3539 scrutR
3540 fs1
3541 (Partial cnt1)
3542 (Continue cnt1)
3543 (Done cnt1)
3544 Error
3545 FL.Done fb -> return $ Done cnt1 fb
3546 IError err -> return $ Error err
3547 step (ManyTillL fs st) a = do
3548 r <- stepL st a
3549 case r of
3550 Partial n s -> return $ Partial n (ManyTillL fs s)
3551 Continue n s -> return $ Continue n (ManyTillL fs s)
3552 Done n b -> do
3553 fs1 <- fstep fs b
3554 case fs1 of
3555 FL.Partial s ->
3556 scrutR s (Partial n) (Continue n) (Done n) Error
3557 FL.Done b1 -> return $ Done n b1
3558 Error err -> return $ Error err
3560 extract (ManyTillL fs sR) = do
3561 res <- extractL sR
3562 case res of
3563 Done n b -> do
3564 r <- fstep fs b
3565 case r of
3566 FL.Partial fs1 -> fmap (Done n) $ ffinal fs1
3567 FL.Done c -> return (Done n c)
3568 Error err -> return $ Error err
3569 Continue n s -> return $ Continue n (ManyTillL fs s)
3570 Partial _ _ -> error "Partial in extract"
3571 extract (ManyTillR _ fs _) = fmap (Done 0) $ ffinal fs
3573-- | @manyThen f collect recover@ repeats the parser @collect@ on the input and
3574-- collects the output in the supplied fold. If the the parser @collect@ fails,
3575-- parser @recover@ is run until it stops and then we start repeating the
3576-- parser @collect@ again. The parser fails if the recovery parser fails.
3578-- For example, this can be used to find a key frame in a video stream after an
3579-- error.
3581-- /Unimplemented/
3583{-# INLINE manyThen #-}
3584manyThen :: -- (Foldable t, Monad m) =>
3585 Parser a m b -> Parser a m x -> Fold m b c -> Parser a m c
3586manyThen _parser _recover _f = undefined
3588-------------------------------------------------------------------------------
3589-- Repeated Alternatives
3590-------------------------------------------------------------------------------
3592-- | Keep trying a parser up to a maximum of @n@ failures. When the parser
3593-- fails the input consumed till now is dropped and the new instance is tried
3594-- on the fresh input.
3596-- /Unimplemented/
3598{-# INLINE retryMaxTotal #-}
3599retryMaxTotal :: -- (Monad m) =>
3600 Int -> Parser a m b -> Fold m b c -> Parser a m c
3601retryMaxTotal _n _p _f = undefined
3603-- | Like 'retryMaxTotal' but aborts after @n@ successive failures.
3605-- /Unimplemented/
3607{-# INLINE retryMaxSuccessive #-}
3608retryMaxSuccessive :: -- (Monad m) =>
3609 Int -> Parser a m b -> Fold m b c -> Parser a m c
3610retryMaxSuccessive _n _p _f = undefined
3612-- | Keep trying a parser until it succeeds. When the parser fails the input
3613-- consumed till now is dropped and the new instance is tried on the fresh
3614-- input.
3616-- /Unimplemented/
3618{-# INLINE retry #-}
3619retry :: -- (Monad m) =>
3620 Parser a m b -> Parser a m b
3621retry _p = undefined