2{-# LANGUAGE RankNTypes #-}
3{-# LANGUAGE ScopedTypeVariables #-}
6-- Module : Streamly.Internal.Data.Parser
7-- Copyright : (c) 2020 Composewell Technologies
9-- Maintainer : streamly@composewell.com
10-- Stability : experimental
15module Streamly.Internal.Data.Parser
48 hiding (any, all, takeWhile)
50import Streamly.Internal.Data.Fold.Types (Fold(..))
51import Streamly.Internal.Data.Parser.Tee (teeWith, teeWithFst, teeWithMin)
52import Streamly.Internal.Data.Parser.Types (Parser(..), Step(..))
54import Streamly.Internal.Data.Strict
56-------------------------------------------------------------------------------
57-- Upgrade folds to parses
58-------------------------------------------------------------------------------
60-- | The resulting parse never terminates and never errors out.
62{-# INLINE fromFold #-}
63fromFold :: Monad m => Fold m a b -> Parser m a b
64fromFold (Fold fstep finitial fextract) = Parser step finitial fextract
68 step s a = Yield 0 <$> fstep s a
70-------------------------------------------------------------------------------
71-- Terminating but not failing folds
72-------------------------------------------------------------------------------
75-- >>> S.parse (PR.any (== 0)) $ S.fromList [1,0,1]
79any :: Monad m => (a -> Bool) -> Parser m a Bool
80any predicate = Parser step initial return
84 initial = return False
95-- >>> S.parse (PR.all (== 0)) $ S.fromList [1,0,1]
99all :: Monad m => (a -> Bool) -> Parser m a Bool
100all predicate = Parser step initial return
104 initial = return True
114-------------------------------------------------------------------------------
116-------------------------------------------------------------------------------
118-- XXX can we use a "cmp" operation in a common implementation?
120-- | Stops after taking exactly @n@ input elements.
122-- * Stops - after @n@ elements.
123-- * Fails - if the stream ends before it can collect @n@ elements.
125-- >>> S.parse (PR.takeExact 4 FL.toList) $ S.fromList [1,0,1]
126-- > Left "takeEQ: Expecting exactly 4 elements, got 3"
131takeEQ :: Monad m => Int -> Fold m a b -> Parser m a b
132takeEQ n (Fold fstep finitial fextract) = Parser step initial extract
136 initial = Tuple' 0 <$> finitial
138 step (Tuple' i r) a = do
142 if i1 < n then return (Skip 0 s1) else Stop 0 <$> fextract res
144 extract (Tuple' i r) =
152 "takeEQ: Expecting exactly " ++ show n
153 ++ " elements, got " ++ show i
155-- | Take at least @n@ input elements, but can collect more.
158-- * Fails - if the stream end before producing @n@ elements.
160-- >>> S.parse (PR.takeGE 4 FL.toList) $ S.fromList [1,0,1]
161-- > Left "takeGE: Expecting at least 4 elements, got only 3"
163-- >>> S.parse (PR.takeGE 4 FL.toList) $ S.fromList [1,0,1,0,1]
164-- > Right [1,0,1,0,1]
169takeGE :: Monad m => Int -> Fold m a b -> Parser m a b
170takeGE n (Fold fstep finitial fextract) = Parser step initial extract
174 initial = Tuple' 0 <$> finitial
176 step (Tuple' i r) a = do
185 extract (Tuple' i r) = fmap f (fextract r)
190 "takeGE: Expecting at least " ++ show n
191 ++ " elements, got only " ++ show i
198-- | Take until the predicate fails. The element on which the predicate fails
199-- is returned back to the input stream.
201-- * Stops - when the predicate fails.
204-- >>> S.parse (PR.takeWhile (== 0) FL.toList) $ S.fromList [0,0,1,0,1]
208-- breakOn p = takeWhile (not p)
213{-# INLINE takeWhile #-}
214takeWhile :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
215takeWhile predicate (Fold fstep finitial fextract) =
216 Parser step initial fextract
224 then Yield 0 <$> fstep s a
225 else Stop 1 <$> fextract s
227-- | Keep taking elements until the predicate succeeds. Drop the succeeding
230-- * Stops - when the predicate succeeds.
233-- >>> S.parse (PR.sepBy (== 1) FL.toList) $ S.fromList [0,0,1,0,1]
236-- >>> S.toList $ S.splitParse (PR.sepBy (== 1) FL.toList) $ S.fromList [0,0,1,0,1]
239-- S.splitOn pred f = S.splitParse (PR.sepBy pred f)
243{-# INLINABLE sepBy #-}
244sepBy :: Monad m => (a -> Bool) -> Fold m a b -> Parser m a b
245sepBy predicate (Fold fstep finitial fextract) =
246 Parser step initial fextract
253 then Yield 0 <$> fstep s a
254 else Stop 0 <$> fextract s
256-- | Keep taking elements until the predicate succeeds. Take the succeeding
259-- * Stops - when the predicate succeeds.
262-- S.splitWithSuffix pred f = S.splitParse (PR.sepWithSuffix pred f)
266{-# INLINABLE sepWithSuffix #-}
269 (a -> Bool) -> Fold m a b -> Parser m a b
270sepWithSuffix = undefined
272-- | Keep taking elements until the predicate succeeds. Return the succeeding
273-- element back to the input.
275-- * Stops - when the predicate succeeds.
278-- S.splitWithPrefix pred f = S.splitParse (PR.sepWithPrefix pred f)
282{-# INLINABLE sepWithPrefix #-}
285 (a -> Bool) -> Fold m a b -> Parser m a b
286sepWithPrefix = undefined
288-- | Split using a condition or a count whichever occurs first. This is a
289-- hybrid of 'splitOn' and 'take'. The element on which the condition succeeds
294{-# INLINABLE sepByMax #-}
296 => (a -> Bool) -> Int -> Fold m a b -> Parser m a b
297sepByMax predicate count (Fold fstep finitial fextract) =
298 Parser step initial extract
302 initial = Tuple' 0 <$> finitial
303 step (Tuple' i r) a = do
307 if not (predicate a) && i1 < count
308 then return $ Yield 0 s1
312 extract (Tuple' _ r) = fextract r
314-- | Like 'splitOn' after stripping leading, trailing, and repeated separators.
315-- Therefore, @".a..b."@ with '.' as the separator would be parsed as
316-- @["a","b"]@. In other words, its like parsing words from whitespace
319-- * Stops - when it finds a word separator after a non-word element
322-- S.wordsBy pred f = S.splitParse (PR.wordBy pred f)
326{-# INLINABLE wordBy #-}
329 (a -> Bool) -> Fold m a b -> Parser m a b
332-- | @group cmp f $ S.fromList [a,b,c,...]@ assigns the element @a@ to the
333-- first group, if @a \`cmp` b@ is 'True' then @b@ is also assigned to the same
334-- group. If @a \`cmp` c@ is 'True' then @c@ is also assigned to the same
335-- group and so on. When the comparison fails a new group is started. Each
336-- group is folded using the fold @f@ and the result of the fold is emitted in
339-- * Stops - when the group ends.
342-- S.groupsBy cmp f = S.splitParse (PR.groupBy cmp f)
346{-# INLINABLE groupBy #-}
349 (a -> a -> Bool) -> Fold m a b -> Parser m a b
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list