@@ -58,6 +58,7 @@ import Data.Aeson.Types.Internal (IResult(..), JSONPath, Object, Result(..), Val
5858import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDigit_w8, signed, string)
5959import Data.Function (fix)
6060import Data.Functor.Compat (($>))
61+import Data.Bits (testBit)
6162import Data.Scientific (Scientific)
6263import Data.Text (Text)
6364import Data.Vector (Vector)
@@ -323,7 +324,18 @@ jstring = A.word8 DOUBLE_QUOTE *> jstring_
323324-- | Parse a string without a leading quote.
324325jstring_ :: Parser Text
325326{-# INLINE jstring_ #-}
326−jstring_ = {-# SCC "jstring_" #-} do
327+jstring_ = do
328+ s <- A.takeWhile (\w -> w /= DOUBLE_QUOTE && w /= BACKSLASH && not (testBit w 7))
329+ let txt = TE.decodeUtf8 s
330+ w <- A.peekWord8
331+ case w of
332+ Nothing -> fail "string without end"
333+ Just DOUBLE_QUOTE -> A.anyWord8 *> return txt
334+ _ -> jstringSlow s
335+
336+jstringSlow :: B.ByteString -> Parser Text
337+{-# INLINE jstringSlow #-}
338+jstringSlow s' = {-# SCC "jstringSlow" #-} do
327339#if MIN_VERSION_ghc_prim(0,3,1)
328340 (s, S _ escaped) <- A.runScanner startState go <* A.anyWord8
329341 -- We escape only if there are
@@ -332,10 +344,10 @@ jstring_ = {-# SCC "jstring_" #-} do
332344 -- Note: if/when text will have fast ascii -> text conversion
333345 -- (e.g. uses utf8 encoding) we can have further speedup.
334346 if isTrue# escaped
335− then case unescapeText s of
347+ then case unescapeText (s' <> s) of
336348 Right r -> return r
337349 Left err -> fail $ show err
338− else return (TE.decodeUtf8 s)
350+ else return (TE.decodeUtf8 (s' <> s))
339351 where
340352 startState = S 0# 0#
341353 go (S skip escaped) (W8# c)
@@ -353,7 +365,7 @@ jstring_ = {-# SCC "jstring_" #-} do
353365data S = S Int# Int#
354366#else
355367 s <- A.scan startState go <* A.anyWord8
356− case unescapeText s of
368+ case unescapeText (s' <> s) of
357369 Right r -> return r
358370 Left err -> fail $ show err
359371 where