on master help sign in
Add takeP combinator
c375be2Adithya Kumar
src/Streamly/Internal/Data/Parser.hs+17
@@ -78,6 +78,7 @@ module Streamly.Internal.Data.Parser
78 , takeGE -- takeBetween n maxBound
78 , takeGE -- takeBetween n maxBound
79
79
80 -- Grab a sequence of input elements by inspecting them
80 -- Grab a sequence of input elements by inspecting them
81+ , takeP
81 , lookAhead
82 , lookAhead
82 , takeWhileP
83 , takeWhileP
83 , takeWhile
84 , takeWhile
@@ -852,6 +853,22 @@ longest p1 p2 = K.toParserK $ D.longest (K.fromParserK p1) (K.fromParserK p2)
852lookAhead :: MonadCatch m => Parser m a b -> Parser m a b
853lookAhead :: MonadCatch m => Parser m a b -> Parser m a b
853lookAhead p = K.toParserK $ D.lookAhead $ K.fromParserK p
854lookAhead p = K.toParserK $ D.lookAhead $ K.fromParserK p
854
855
856+-- | Takes at-most @n@ input elements.
857+--
858+-- * Stops - when the collecting parser stops.
859+-- * Fails - when the collecting parser fails.
860+--
861+-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 2 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
862+-- [1, 2]
863+--
864+-- >>> Stream.parse (Parser.takeP 4 (Parser.takeEQ 5 Fold.toList)) $ Stream.fromList [1, 2, 3, 4, 5]
865+-- *** Exception: ParseError "takeEQ: Expecting exactly 5 elements, input terminated on 4"
866+--
867+-- /Internal/
868+{-# INLINE takeP #-}
869+takeP :: MonadCatch m => Int -> Parser m a b -> Parser m a b
870+takeP i p = K.toParserK $ D.takeP i $ K.fromParserK p
871+
855-------------------------------------------------------------------------------
872-------------------------------------------------------------------------------
856-- Interleaving
873-- Interleaving
857-------------------------------------------------------------------------------
874-------------------------------------------------------------------------------
src/Streamly/Internal/Data/Parser/ParserD.hs+51
@@ -52,6 +52,7 @@ module Streamly.Internal.Data.Parser.ParserD
52 , takeGE -- takeBetween n maxBound
52 , takeGE -- takeBetween n maxBound
53
53
54 -- Grab a sequence of input elements by inspecting them
54 -- Grab a sequence of input elements by inspecting them
55+ , takeP
55 , lookAhead
56 , lookAhead
56 , takeWhile
57 , takeWhile
57 , takeWhile1
58 , takeWhile1
@@ -814,6 +815,56 @@ spanByRolling eq f1 f2 =
814-- nested parsers
815-- nested parsers
815-------------------------------------------------------------------------------
816-------------------------------------------------------------------------------
816
817
818+-- | See 'Streamly.Internal.Data.Parser.takeP'.
819+--
820+-- /Internal/
821+{-# INLINE takeP #-}
822+takeP :: Monad m => Int -> Parser m a b -> Parser m a b
823+takeP lim (Parser pstep pinitial pextract) = Parser step initial extract
824+
825+ where
826+
827+ initial = do
828+ res <- pinitial
829+ case res of
830+ IPartial s ->
831+ if lim > 0
832+ then return $ IPartial $ Tuple' 0 s
833+ else IDone <$> pextract s
834+ IDone b -> return $ IDone b
835+ IError e -> return $ IError e
836+
837+ step (Tuple' cnt r) a = do
838+ assert (cnt < lim) (return ())
839+ res <- pstep r a
840+ let cnt1 = cnt + 1
841+ case res of
842+ Partial 0 s -> do
843+ assert (cnt1 >= 0) (return ())
844+ if cnt1 < lim
845+ then return $ Partial 0 $ Tuple' cnt1 s
846+ else Done 0 <$> pextract s
847+ Continue 0 s -> do
848+ assert (cnt1 >= 0) (return ())
849+ if cnt1 < lim
850+ then return $ Continue 0 $ Tuple' cnt1 s
851+ -- XXX This should error out?
852+ -- If designed properly, this will probably error out.
853+ -- "pextract" should error out
854+ else Done 0 <$> pextract s
855+ Partial n s -> do
856+ let taken = cnt1 - n
857+ assert (taken >= 0) (return ())
858+ return $ Partial n $ Tuple' taken s
859+ Continue n s -> do
860+ let taken = cnt1 - n
861+ assert (taken >= 0) (return ())
862+ return $ Continue n $ Tuple' taken s
863+ Done n b -> return $ Done n b
864+ Error str -> return $ Error str
865+
866+ extract (Tuple' _ r) = pextract r
867+
817-- | See 'Streamly.Internal.Data.Parser.lookahead'.
868-- | See 'Streamly.Internal.Data.Parser.lookahead'.
818--
869--
819-- /Pre-release/
870-- /Pre-release/