on master help sign in
Implement sepBy more efficiently
commit1c81cd7b7a893ec86aea0f867d033bc41b52f0fc authorHarendra Kumar <harendra@composewell.com> dateThu 5 May 2022, 10:41 (4 years ago) parent4676d68
2 files changed+85−4
core/src/Streamly/Internal/Data/Parser.hs+14−4 core/src/Streamly/Internal/Data/Parser/ParserD.hs+71
core/src/Streamly/Internal/Data/Parser.hs+14−4
@@ -219,7 +219,6 @@ module Streamly.Internal.Data.Parser
219219 )
220220where
221221
222−import Control.Applicative ((<|>))
223222import Control.Monad.Catch (MonadCatch, MonadThrow)
224223import Data.Functor (($>))
225224import Prelude hiding
@@ -238,6 +237,7 @@ import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
238237-- >>> :m
239238-- >>> :set -package streamly
240239-- >>> import Prelude hiding (any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either, filter)
240+-- >>> import Control.Applicative ((<|>))
241241-- >>> import qualified Streamly.Prelude as Stream
242242-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, parseMany)
243243-- >>> import qualified Streamly.Data.Fold as Fold
@@ -1276,6 +1276,10 @@ deintercalate = undefined
12761276
12771277-- | Parse items separated by a separator parsed by the supplied parser. At
12781278-- least one item must be present for the parser to succeed.
1279+--
1280+-- Note that this can go in infinite loop if both the parsers fail on some
1281+-- input. Detection of that would make the implementation more complex.
1282+--
12791283{-# INLINE sepBy1 #-}
12801284sepBy1 :: MonadCatch m =>
12811285 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
@@ -1285,11 +1289,17 @@ sepBy1 sink p sep = do
12851289 f1 <- fromEffect $ FL.snoc f x
12861290 many (sep >> p) f1
12871291
1288−-- | sepBy1 or empty, does not fail.
1292+-- | Run the content parser first, when it is done, the separator parser is
1293+-- run, when it is done content parser is run again and so on. If none of the
1294+-- parsers consumes an input then parser returns a failure.
1295+--
1296+-- >>> sepBy sink content sep = Parser.sepBy1 sink content sep <|> return mempty
1297+--
12891298{-# INLINE sepBy #-}
1290−sepBy :: (MonadCatch m, Monoid c) =>
1299+sepBy :: MonadCatch m =>
12911300 Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1292−sepBy sink p sep = sepBy1 sink p sep <|> return mempty
1301+sepBy sink content sep =
1302+ D.toParserK $ D.sepBy sink (D.fromParserK content) (D.fromParserK sep)
12931303
12941304-------------------------------------------------------------------------------
12951305-- Interleaving a collection of parsers
core/src/Streamly/Internal/Data/Parser/ParserD.hs+71
@@ -111,6 +111,7 @@ module Streamly.Internal.Data.Parser.ParserD
111111 -- Use two folds, run a primary parser, its rejected values go to the
112112 -- secondary parser.
113113 , deintercalate
114+ , sepBy
114115
115116 -- ** Sequential Alternative
116117 , alt
@@ -1258,6 +1259,76 @@ deintercalate ::
12581259 -> Parser m x (y, z)
12591260deintercalate = undefined
12601261
1262+data SepByState fs sp ss =
1263+ SepByInit fs sp
1264+ | SepBySeparator fs ss Bool
1265+
1266+{-# INLINE sepBy #-}
1267+sepBy :: MonadCatch m =>
1268+ Fold m b c -> Parser m a b -> Parser m a x -> Parser m a c
1269+sepBy
1270+ (Fold fstep finitial fextract)
1271+ (Parser pstep pinitial pextract)
1272+ (Parser sstep sinitial _) = Parser step initial extract
1273+
1274+ where
1275+
1276+ errMsg p status =
1277+ error $ "sepBy: " ++ p ++ " parser cannot "
1278+ ++ status ++ " without input"
1279+
1280+ initial = do
1281+ res <- finitial
1282+ case res of
1283+ FL.Partial fs -> do
1284+ resP <- pinitial
1285+ case resP of
1286+ IPartial sp -> return $ IPartial $ SepByInit fs sp
1287+ IDone _ -> errMsg "content" "succeed"
1288+ IError _ -> errMsg "content" "fail"
1289+ FL.Done b -> return $ IDone b
1290+
1291+ step (SepByInit fs sp) a = do
1292+ r <- pstep sp a
1293+ case r of
1294+ Partial n s -> return $ Partial n (SepByInit fs s)
1295+ Continue n s -> return $ Continue n (SepByInit fs s)
1296+ Done n b -> do
1297+ fres <- fstep fs b
1298+ case fres of
1299+ FL.Partial fs1 -> do
1300+ resS <- sinitial
1301+ case resS of
1302+ IPartial ss ->
1303+ return $ Partial n (SepBySeparator fs1 ss False)
1304+ IDone _ -> errMsg "separator" "succeed"
1305+ IError _ -> errMsg "separator" "fail"
1306+ FL.Done c -> return $ Done n c
1307+ Error err -> return $ Error err
1308+ step (SepBySeparator fs ss consumed) a = do
1309+ r <- sstep ss a
1310+ case r of
1311+ Partial n s -> return $ Partial n (SepBySeparator fs s True)
1312+ Continue n s -> return $ Continue n (SepBySeparator fs s True)
1313+ Done n _ ->
1314+ if consumed
1315+ then do
1316+ resP <- pinitial
1317+ case resP of
1318+ IPartial sp -> return $ Partial n $ SepByInit fs sp
1319+ IDone _ -> errMsg "content" "succeed"
1320+ IError _ -> errMsg "content" "fail"
1321+ else return $ Error "sepBy: infinite loop"
1322+ Error err -> return $ Error err
1323+
1324+ extract (SepByInit fs sp) = do
1325+ r <- pextract sp
1326+ res <- fstep fs r
1327+ case res of
1328+ FL.Partial fs1 -> fextract fs1
1329+ FL.Done c -> return c
1330+ extract (SepBySeparator fs _ _) = fextract fs
1331+
12611332-------------------------------------------------------------------------------
12621333-- Sequential Collection
12631334-------------------------------------------------------------------------------