on master help sign in
Add sepBy1 and sepBy
commit7f38a19a0f0d58d7924073e0e12f5d8df7ac95de authorHarendra Kumar <harendra@composewell.com> dateWed 4 May 2022, 00:36 (4 years ago) parent5a6a292
1 file changed+58−37
core/src/Streamly/Internal/Data/Parser.hs+58−37
core/src/Streamly/Internal/Data/Parser.hs+58−37
@@ -165,7 +165,8 @@ module Streamly.Internal.Data.Parser
165165 --
166166 -- @
167167 -- , endBy
168− -- , sepBy
168+ , sepBy1
169+ , sepBy
169170 -- , sepEndBy
170171 -- , beginBy
171172 -- , sepBeginBy
@@ -206,6 +207,7 @@ module Streamly.Internal.Data.Parser
206207 )
207208where
208209
210+import Control.Applicative ((<|>))
209211import Control.Monad.Catch (MonadCatch, MonadThrow)
210212import Prelude hiding
211213 (any, all, take, takeWhile, sequence, concatMap, maybe, either, filter)
@@ -764,6 +766,8 @@ groupByRollingEither :: MonadCatch m =>
764766 (a -> a -> Bool) -> Fold m a b -> Fold m a c -> Parser m a (Either b c)
765767groupByRollingEither eq f1 = D.toParserK . D.groupByRollingEither eq f1
766768
769+-- XXX Use a stream instead of a list so that we can use any container type.
770+
767771-- | Match the given sequence of elements using the given comparison function.
768772--
769773-- >>> Stream.parse (Parser.eqBy (==) "string") $ Stream.fromList "string"
@@ -954,42 +958,6 @@ lookAhead p = D.toParserK $ D.lookAhead $ D.fromParserK p
954958takeP :: MonadCatch m => Int -> Parser m a b -> Parser m a b
955959takeP i p = D.toParserK $ D.takeP i $ D.fromParserK p
956960
957−-------------------------------------------------------------------------------
958−-- Interleaving
959−-------------------------------------------------------------------------------
960−--
961−-- To deinterleave we can chain two parsers one behind the other. The input is
962−-- given to the first parser and the input definitively rejected by the first
963−-- parser is given to the second parser.
964−--
965−-- We can either have the parsers themselves buffer the input or use the shared
966−-- global buffer to hold it until none of the parsers need it. When the first
967−-- parser returns Skip (i.e. rewind) we let the second parser consume the
968−-- rejected input and when it is done we move the cursor forward to the first
969−-- parser again. This will require a "move forward" command as well.
970−--
971−-- To implement grep we can use three parsers, one to find the pattern, one
972−-- to store the context behind the pattern and one to store the context in
973−-- front of the pattern. When a match occurs we need to emit the accumulator of
974−-- all the three parsers. One parser can count the line numbers to provide the
975−-- line number info.
976−--
977−-- | Apply two parsers alternately to an input stream. The input stream is
978−-- considered an interleaving of two patterns. The two parsers represent the
979−-- two patterns.
980−--
981−-- This undoes a "gintercalate" of two streams.
982−--
983−-- /Unimplemented/
984−--
985−{-# INLINE deintercalate #-}
986−deintercalate ::
987− -- Monad m =>
988− Fold m a y -> Parser m x a
989− -> Fold m b z -> Parser m x b
990− -> Parser m x (y, z)
991−deintercalate = undefined
992−
993961-------------------------------------------------------------------------------
994962-- Sequential Collection
995963-------------------------------------------------------------------------------
@@ -1168,6 +1136,59 @@ manyThen :: -- (Foldable t, MonadCatch m) =>
11681136 Parser m a b -> Parser m a x -> Fold m b c -> Parser m a c
11691137manyThen _parser _recover _f = undefined
11701138
1139+-------------------------------------------------------------------------------
1140+-- Interleaving
1141+-------------------------------------------------------------------------------
1142+--
1143+-- To deinterleave we can chain two parsers one behind the other. The input is
1144+-- given to the first parser and the input definitively rejected by the first
1145+-- parser is given to the second parser.
1146+--
1147+-- We can either have the parsers themselves buffer the input or use the shared
1148+-- global buffer to hold it until none of the parsers need it. When the first
1149+-- parser returns Skip (i.e. rewind) we let the second parser consume the
1150+-- rejected input and when it is done we move the cursor forward to the first
1151+-- parser again. This will require a "move forward" command as well.
1152+--
1153+-- To implement grep we can use three parsers, one to find the pattern, one
1154+-- to store the context behind the pattern and one to store the context in
1155+-- front of the pattern. When a match occurs we need to emit the accumulator of
1156+-- all the three parsers. One parser can count the line numbers to provide the
1157+-- line number info.
1158+--
1159+-- | Apply two parsers alternately to an input stream. The input stream is
1160+-- considered an interleaving of two patterns. The two parsers represent the
1161+-- two patterns.
1162+--
1163+-- This undoes a "gintercalate" of two streams.
1164+--
1165+-- /Unimplemented/
1166+--
1167+{-# INLINE deintercalate #-}
1168+deintercalate ::
1169+ -- Monad m =>
1170+ Fold m a y -> Parser m x a
1171+ -> Fold m b z -> Parser m x b
1172+ -> Parser m x (y, z)
1173+deintercalate = undefined
1174+
1175+-- | Parse items separated by a separator parsed by the supplied parser. At
1176+-- least one item must be present for the parser to succeed.
1177+{-# INLINE sepBy1 #-}
1178+sepBy1 :: MonadCatch m =>
1179+ Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1180+sepBy1 sink p sep = do
1181+ x <- p
1182+ f <- fromEffect $ FL.initialize sink
1183+ f1 <- fromEffect $ FL.snoc f x
1184+ many (sep >> p) f1
1185+
1186+-- | sepBy1 or empty, does not fail.
1187+{-# INLINE sepBy #-}
1188+sepBy :: (MonadCatch m, Monoid c) =>
1189+ Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1190+sepBy sink p sep = sepBy1 sink p sep <|> return mempty
1191+
11711192-------------------------------------------------------------------------------
11721193-- Interleaving a collection of parsers
11731194-------------------------------------------------------------------------------