@@ -83,6 +83,7 @@ module Streamly.Internal.Data.Parser.ParserD
8383 -- Words and grouping
8484 , wordBy
8585 , wordFramedBy
86+ , wordQuotedBy
8687 , groupBy
8788 , groupByRolling
8889 , groupByRollingEither
@@ -1123,6 +1124,107 @@ wordFramedBy isEsc isBegin isEnd isSep
11231124 err "wordFramedBy: trailing escape"
11241125 extract (WordFramedSkipPost b) = return b
11251126
1127+data WordQuotedState s b a =
1128+ WordQuotedSkipPre !s
1129+ | WordUnquotedWord !s
1130+ | WordQuotedWord !s !Int a
1131+ | WordUnquotedEsc !s
1132+ | WordQuotedEsc !s !Int a
1133+ | WordQuotedSkipPost !b
1134+
1135+{-# INLINE wordQuotedBy #-}
1136+wordQuotedBy :: (MonadCatch m, Eq a) =>
1137+ (a -> Bool) -- ^ Escape
1138+ -> (a -> Bool) -- ^ left quote
1139+ -> (a -> Bool) -- ^ right quote
1140+ -> (a -> a) -- ^ get right quote from the left quote
1141+ -> (a -> Bool) -- ^ word seperator
1142+ -> Fold m a b
1143+ -> Parser m a b
1144+wordQuotedBy isEsc isBegin isEnd toRight isSep
1145+ (Fold fstep finitial fextract) =
1146+ Parser step initial extract
1147+
1148+ where
1149+
1150+ initial = do
1151+ res <- finitial
1152+ return $
1153+ case res of
1154+ FL.Partial s -> IPartial (WordQuotedSkipPre s)
1155+ FL.Done _ ->
1156+ error "wordQuotedBy: fold done without input"
1157+
1158+ {-# INLINE process #-}
1159+ process s a n q = do
1160+ res <- fstep s a
1161+ return
1162+ $ case res of
1163+ FL.Partial s1 -> Continue 0 (WordQuotedWord s1 n q)
1164+ FL.Done b -> Done 0 b
1165+
1166+ {-# INLINE processUnquoted #-}
1167+ processUnquoted s a = do
1168+ res <- fstep s a
1169+ return
1170+ $ case res of
1171+ FL.Partial s1 -> Continue 0 (WordUnquotedWord s1)
1172+ FL.Done b -> Done 0 b
1173+
1174+ step (WordQuotedSkipPre s) a
1175+ | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1176+ | isSep a = return $ Partial 0 $ WordQuotedSkipPre s
1177+ | isBegin a = return $ Continue 0 $ WordQuotedWord s 1 a
1178+ | isEnd a =
1179+ return $ Error "wordQuotedBy: missing frame start"
1180+ | otherwise = processUnquoted s a
1181+ step (WordUnquotedWord s) a
1182+ | isEsc a = return $ Continue 0 $ WordUnquotedEsc s
1183+ | isSep a = do
1184+ b <- fextract s
1185+ return $ Partial 0 $ WordQuotedSkipPost b
1186+ | otherwise = do
1187+ if isBegin a
1188+ then return $ Continue 0 $ WordQuotedWord s 1 a
1189+ else if isEnd a
1190+ then return $ Error "wordQuotedBy: missing frame start"
1191+ else processUnquoted s a
1192+ step (WordQuotedWord s n q) a
1193+ | isEsc a = return $ Continue 0 $ WordQuotedEsc s n q
1194+ | n == 0 && isSep a = do
1195+ b <- fextract s
1196+ return $ Partial 0 $ WordQuotedSkipPost b
1197+ | otherwise = do
1198+ if a == toRight q
1199+ then
1200+ if n == 1
1201+ then return $ Continue 0 $ WordUnquotedWord s
1202+ else process s a (n - 1) q
1203+ else if a == q
1204+ then process s a (n + 1) q
1205+ else process s a n q
1206+ step (WordUnquotedEsc s) a = processUnquoted s a
1207+ step (WordQuotedEsc s n q) a = process s a n q
1208+ step (WordQuotedSkipPost b) a =
1209+ return
1210+ $ if not (isSep a)
1211+ then Done 1 b
1212+ else Partial 0 $ WordQuotedSkipPost b
1213+
1214+ err = throwM . ParseError
1215+
1216+ extract (WordQuotedSkipPre s) = fextract s
1217+ extract (WordUnquotedWord s) = fextract s
1218+ extract (WordQuotedWord s n _) =
1219+ if n == 0
1220+ then fextract s
1221+ else err "wordQuotedBy: missing frame end"
1222+ extract WordQuotedEsc {} =
1223+ err "wordQuotedBy: trailing escape"
1224+ extract (WordUnquotedEsc _) =
1225+ err "wordQuotedBy: trailing escape"
1226+ extract (WordQuotedSkipPost b) = return b
1227+
11261228{-# ANN type GroupByState Fuse #-}
11271229data GroupByState a s
11281230 = GroupByInit !s