@@ -128,8 +128,7 @@ module Streamly.Internal.Data.Parser
128 , takeFramedBy_
128 , takeFramedBy_
129 , takeFramedByEsc_
129 , takeFramedByEsc_
130 , takeFramedByGeneric
130 , takeFramedByGeneric
131− -- , wordByQuoted
131+ , wordFramedBy
132− -- , wordByQuotedEsc
134 -- | Unimplemented
133 -- | Unimplemented
@@ -252,6 +251,7 @@ import qualified Streamly.Internal.Data.Parser.ParserK.Type as K
252-- >>> :set -package streamly
251-- >>> :set -package streamly
253-- >>> import Prelude hiding (any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either, filter)
252-- >>> import Prelude hiding (any, all, dropWhile, take, takeWhile, sequence, concatMap, maybe, either, filter)
254-- >>> import Control.Applicative ((<|>))
253-- >>> import Control.Applicative ((<|>))
254+-- >>> import Data.Char (isSpace)
255-- >>> import qualified Streamly.Prelude as Stream
255-- >>> import qualified Streamly.Prelude as Stream
256-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, parseMany)
256-- >>> import qualified Streamly.Internal.Data.Stream.IsStream as Stream (parse, parseMany)
257-- >>> import qualified Streamly.Internal.Data.Fold as Fold
257-- >>> import qualified Streamly.Internal.Data.Fold as Fold
@@ -661,6 +661,7 @@ dropWhile p = takeWhile p FL.drain
661-- Separators
661-- Separators
662-------------------------------------------------------------------------------
662-------------------------------------------------------------------------------
664+-- XXX We can remove Maybe from esc
664{-# INLINE takeFramedByGeneric #-}
665{-# INLINE takeFramedByGeneric #-}
665takeFramedByGeneric :: MonadCatch m =>
666takeFramedByGeneric :: MonadCatch m =>
666 Maybe (a -> Bool)
667 Maybe (a -> Bool)
@@ -823,6 +824,8 @@ takeFramedBy_ isBegin isEnd f = D.toParserK $ D.takeFramedBy_ isBegin isEnd f
823-- * Stops - when it finds a word separator after a non-word element
824-- * Stops - when it finds a word separator after a non-word element
824-- * Fails - never.
825-- * Fails - never.
827+-- >>> wordBy = Parser.wordFramedBy (const False) (const False) (const False)
827-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
830-- S.wordsBy pred f = S.parseMany (PR.wordBy pred f)
@@ -831,6 +834,37 @@ takeFramedBy_ isBegin isEnd f = D.toParserK $ D.takeFramedBy_ isBegin isEnd f
831wordBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
834wordBy :: MonadCatch m => (a -> Bool) -> Fold m a b -> Parser m a b
832wordBy f = D.toParserK . D.wordBy f
835wordBy f = D.toParserK . D.wordBy f
837+-- | Like 'wordBy' but treats anything inside a pair of quotes as a single
838+-- word, the quotes can be escaped by an escape character. Recursive quotes
839+-- are possible if quote begin and end characters are different, quotes must be
840+-- balanced. Outermost quotes are stripped.
842+-- >>> braces = Parser.wordFramedBy (== '\\') (== '{') (== '}') isSpace Fold.toList
843+-- >>> Stream.parse braces $ Stream.fromList "{ab} cd"
845+-- >>> Stream.parse braces $ Stream.fromList "{ab}{cd}"
847+-- >>> Stream.parse braces $ Stream.fromList "a{b} cd"
849+-- >>> Stream.parse braces $ Stream.fromList "a{{b}} cd"
852+-- >>> quotes = Parser.wordFramedBy (== '\\') (== '"') (== '"') isSpace Fold.toList
853+-- >>> Stream.parse quotes $ Stream.fromList "\"a\"\"b\""
857+{-# INLINE wordFramedBy #-}
858+wordFramedBy :: MonadCatch m =>
859+ (a -> Bool) -- ^ Escape
860+ -> (a -> Bool) -- ^ left quote
861+ -> (a -> Bool) -- ^ right quote
862+ -> (a -> Bool) -- ^ word seperator
865+wordFramedBy isEsc isBegin isEnd isSpc =
866+ D.toParserK . D.wordFramedBy isEsc isBegin isEnd isSpc
834-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
868-- | Given an input stream @[a,b,c,...]@ and a comparison function @cmp@, the
835-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
869-- parser assigns the element @a@ to the first group, then if @a \`cmp` b@ is
836-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'
870-- 'True' @b@ is also assigned to the same group. If @a \`cmp` c@ is 'True'