on master help sign in
Add takeFramedByGeneric parser
commitef2ea11176d7d2afc2994c19eb41f61084670e2c authorHarendra Kumar <harendra@composewell.com> dateSun 8 May 2022, 21:38 (4 years ago) parent6100419
2 files changed+129−6
core/src/Streamly/Internal/Data/Parser.hs+31−6 core/src/Streamly/Internal/Data/Parser/ParserD.hs+98
core/src/Streamly/Internal/Data/Parser.hs+31−6
@@ -127,6 +127,7 @@ module Streamly.Internal.Data.Parser
127127 -- , takeFramedBy
128128 , takeFramedBy_
129129 , takeFramedByEsc_
130+ , takeFramedByGeneric
130131 -- , wordByQuoted
131132 -- , wordByQuotedEsc
132133
@@ -660,7 +661,17 @@ dropWhile p = takeWhile p FL.drain
660661-- Separators
661662-------------------------------------------------------------------------------
662663
663−-- | @takeEndBy_ cond parser@ parses a token that ends by a separator chosen by
664+{-# INLINE takeFramedByGeneric #-}
665+takeFramedByGeneric :: MonadCatch m =>
666+ Maybe (a -> Bool)
667+ -> Maybe (a -> Bool)
668+ -> Maybe (a -> Bool)
669+ -> Fold m a b
670+ -> Parser m a b
671+takeFramedByGeneric esc begin end f =
672+ D.toParserK $ D.takeFramedByGeneric esc begin end f
673+
674+-- | @takeEndBy cond parser@ parses a token that ends by a separator chosen by
664675-- the supplied predicate. The separator is also taken with the token.
665676--
666677-- This can be combined with other parsers to implement other interesting
@@ -669,6 +680,8 @@ dropWhile p = takeWhile p FL.drain
669680-- >>> takeEndByLE cond n p = Parser.takeEndBy cond (Parser.fromFold $ Fold.take n p)
670681-- >>> takeEndByBetween cond m n p = Parser.takeEndBy cond (Parser.takeBetween m n p)
671682--
683+-- >>> takeEndBy = Parser.takeEndByEsc (const False)
684+--
672685-- See also "Streamly.Data.Fold.takeEndBy".
673686--
674687-- /Pre-release/
@@ -676,6 +689,7 @@ dropWhile p = takeWhile p FL.drain
676689{-# INLINE takeEndBy #-}
677690takeEndBy :: MonadCatch m => (a -> Bool) -> Parser m a b -> Parser m a b
678691takeEndBy cond = D.toParserK . D.takeEndBy cond . D.fromParserK
692+-- takeEndBy = takeEndByEsc (const False)
679693
680694-- | Like 'takeEndBy' but the separator is dropped.
681695--
@@ -686,6 +700,10 @@ takeEndBy cond = D.toParserK . D.takeEndBy cond . D.fromParserK
686700{-# INLINE takeEndBy_ #-}
687701takeEndBy_ :: MonadCatch m => (a -> Bool) -> Parser m a b -> Parser m a b
688702takeEndBy_ cond = D.toParserK . D.takeEndBy_ cond . D.fromParserK
703+{-
704+takeEndBy_ isEnd p =
705+ takeFramedByGeneric Nothing Nothing (Just isEnd) (toFold p)
706+-}
689707
690708-- | Take either the separator or the token. Separator is a Left value and
691709-- token is Right value.
@@ -724,6 +742,12 @@ takeEitherSepBy _cond = undefined -- D.toParserK . D.takeEitherSepBy cond
724742takeStartBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
725743takeStartBy cond = D.toParserK . D.takeStartBy cond
726744
745+{-
746+{-# INLINE takeStartBy_ #-}
747+takeStartBy_ :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
748+takeStartBy_ isBegin = takeFramedByGeneric Nothing (Just isBegin) Nothing
749+-}
750+
727751-------------------------------------------------------------------------------
728752-- Quoting and Escaping
729753-------------------------------------------------------------------------------
@@ -732,14 +756,12 @@ takeStartBy cond = D.toParserK . D.takeStartBy cond
732756-- escape char determined by the first predicate. The escape characters are
733757-- removed.
734758--
735−-- >>> takeEndBy = Parser.takeEndByEsc (const False)
736−--
737759-- /pre-release/
738760{-# INLINE takeEndByEsc #-}
739761takeEndByEsc :: MonadCatch m =>
740762 (a -> Bool) -> (a -> Bool) -> Parser m a b -> Parser m a b
741−takeEndByEsc isEsc isSep p =
742− D.toParserK $ D.takeEndByEsc isEsc isSep (D.fromParserK p)
763+takeEndByEsc isEsc isEnd p =
764+ D.toParserK $ D.takeEndByEsc isEsc isEnd (D.fromParserK p)
743765
744766-- | @takeFramedByEsc_ isEsc isBegin isEnd fold@ parses a token framed using a
745767-- begin and end predicate, and an escape character. The frame begin and end
@@ -767,6 +789,8 @@ takeFramedByEsc_ :: MonadCatch m =>
767789 (a -> Bool) -> (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
768790takeFramedByEsc_ isEsc isBegin isEnd f =
769791 D.toParserK $ D.takeFramedByEsc_ isEsc isBegin isEnd f
792+-- takeEndByEsc_ isEsc isEnd p =
793+-- takeFramedByGeneric (Just isEsc) Nothing (Just isEnd) (toFold p)
770794
771795-- | @takeFramedBy_ isBegin isEnd fold@ parses a token framed by a begin and an
772796-- end predicate.
@@ -777,7 +801,8 @@ takeFramedByEsc_ isEsc isBegin isEnd f =
777801takeFramedBy_ :: MonadCatch m =>
778802 (a -> Bool) -> (a -> Bool) -> Fold m a b -> Parser m a b
779803takeFramedBy_ isBegin isEnd f = D.toParserK $ D.takeFramedBy_ isBegin isEnd f
780−-- takeFramedBy_ = takeFramedByEsc_ (const False)
804+-- takeFramedBy_ isBegin isEnd =
805+-- takeFramedByGeneric (Just (const False)) (Just isBegin) (Just isEnd)
781806
782807-------------------------------------------------------------------------------
783808-- Grouping and words
core/src/Streamly/Internal/Data/Parser/ParserD.hs+98
@@ -78,6 +78,7 @@ module Streamly.Internal.Data.Parser.ParserD
7878 , takeStartBy
7979 , takeFramedBy_
8080 , takeFramedByEsc_
81+ , takeFramedByGeneric
8182
8283 -- Words and grouping
8384 , wordBy
@@ -676,6 +677,103 @@ takeWhile1 predicate (Fold fstep finitial fextract) =
676677-- Separators
677678-------------------------------------------------------------------------------
678679
680+{-# INLINE takeFramedByGeneric #-}
681+takeFramedByGeneric :: MonadThrow m =>
682+ Maybe (a -> Bool)
683+ -> Maybe (a -> Bool)
684+ -> Maybe (a -> Bool)
685+ -> Fold m a b
686+ -> Parser m a b
687+takeFramedByGeneric esc begin end (Fold fstep finitial fextract) =
688+
689+ Parser step initial extract
690+
691+ where
692+
693+ initial = do
694+ res <- finitial
695+ return $
696+ case res of
697+ FL.Partial s -> IPartial (FrameEscInit s)
698+ FL.Done _ ->
699+ error "takeFramedByGeneric: fold done without input"
700+
701+ {-# INLINE process #-}
702+ process s a n = do
703+ res <- fstep s a
704+ return
705+ $ case res of
706+ FL.Partial s1 -> Continue 0 (FrameEscGo s1 n)
707+ FL.Done b -> Done 0 b
708+
709+ {-# INLINE processNoEsc #-}
710+ processNoEsc s a n =
711+ case end of
712+ Just isEnd ->
713+ case begin of
714+ Just isBegin ->
715+ -- takeFramedBy case
716+ if isEnd a
717+ then
718+ if n == 0
719+ then Done 0 <$> fextract s
720+ else process s a (n - 1)
721+ else
722+ let n1 = if isBegin a then n + 1 else n
723+ in process s a n1
724+ Nothing -> -- takeEndBy case
725+ if isEnd a
726+ then Done 0 <$> fextract s
727+ else process s a n
728+ Nothing -> -- takeStartBy case
729+ case begin of
730+ Just isBegin ->
731+ if isBegin a
732+ then Done 0 <$> fextract s
733+ else process s a n
734+ Nothing ->
735+ error $ "takeFramedByGeneric: "
736+ ++ "Both begin and end frame predicate missing"
737+
738+ {-# INLINE processCheckEsc #-}
739+ processCheckEsc s a n =
740+ case esc of
741+ Just isEsc ->
742+ if isEsc a
743+ then return $ Partial 0 $ FrameEscEsc s n
744+ else processNoEsc s a n
745+ Nothing -> processNoEsc s a n
746+
747+ step (FrameEscInit s) a =
748+ case begin of
749+ Just isBegin ->
750+ if isBegin a
751+ then return $ Partial 0 (FrameEscGo s 0)
752+ else return $ Error "takeFramedByGeneric: missing frame start"
753+ Nothing ->
754+ case end of
755+ Just isEnd ->
756+ if isEnd a
757+ then Done 0 <$> fextract s
758+ else processCheckEsc s a 0
759+ Nothing ->
760+ error "Both begin and end frame predicate missing"
761+ step (FrameEscGo s n) a = processCheckEsc s a n
762+ step (FrameEscEsc s n) a = process s a n
763+
764+ err = throwM . ParseError
765+
766+ extract (FrameEscInit _) =
767+ err "takeFramedByGeneric: empty token"
768+ extract (FrameEscGo s _) =
769+ case begin of
770+ Just _ ->
771+ case end of
772+ Nothing -> fextract s
773+ Just _ -> err "takeFramedByGeneric: missing frame end"
774+ Nothing -> err "takeFramedByGeneric: missing closing frame"
775+ extract (FrameEscEsc _ _) = err "takeFramedByGeneric: trailing escape"
776+
679777-- | See 'Streamly.Internal.Data.Parser.takeEndBy'.
680778--
681779-- /Pre-release/