@@ -53,8 +53,9 @@ import qualified Data.Scientific as Sci
5353import Data.Aeson.Parser.Unescape (unescapeText)
5454
5555#if MIN_VERSION_ghc_prim(0,3,1)
56−import GHC.Base (Int#, (==#), isTrue#, word2Int#)
56+import GHC.Base (Int#, (==#), isTrue#, word2Int#, orI#, andI#)
5757import GHC.Word (Word8(W8#))
58+import qualified Data.Text.Encoding as TE
5859#endif
5960
6061#define BACKSLASH 92
@@ -207,23 +208,39 @@ jstring = A.word8 DOUBLE_QUOTE *> jstring_
207208jstring_ :: Parser Text
208209{-# INLINE jstring_ #-}
209210jstring_ = {-# SCC "jstring_" #-} do
211+#if MIN_VERSION_ghc_prim(0,3,1)
212+ (s, S _ escaped) <- A.runScanner startState go <* A.anyWord8
213+ -- We escape only if there are
214+ -- non-ascii (over 7bit) characters or backslash present.
215+ --
216+ -- Note: if/when text will have fast ascii -> text conversion
217+ -- (e.g. uses utf8 encoding) we can have further speedup.
218+ if isTrue# escaped
219+ then case unescapeText s of
220+ Right r -> return r
221+ Left err -> fail $ show err
222+ else return (TE.decodeUtf8 s)
223+ where
224+ startState = S 0# 0#
225+ go (S skip escaped) (W8# c)
226+ | isTrue# skip = Just (S 0# escaped')
227+ | isTrue# (w ==# 34#) = Nothing -- double quote
228+ | otherwise = Just (S skip' escaped')
229+ where
230+ w = word2Int# c
231+ skip' = w ==# 92# -- backslash
232+ escaped' = escaped
233+ `orI#` (w `andI#` 0x80# ==# 0x80#) -- c >= 0x80
234+ `orI#` skip'
235+ `orI#` (w `andI#` 0x1f# ==# w) -- c < 0x20
236+
237+data S = S Int# Int#
238+#else
210239 s <- A.scan startState go <* A.anyWord8
211240 case unescapeText s of
212241 Right r -> return r
213242 Left err -> fail $ show err
214243 where
215−#if MIN_VERSION_ghc_prim(0,3,1)
216− startState = S 0#
217− go (S a) (W8# c)
218− | isTrue# a = Just (S 0#)
219− | isTrue# (word2Int# c ==# 34#) = Nothing -- double quote
220− | otherwise = let a' = word2Int# c ==# 92# -- backslash
221− in Just (S a')
222−
223−data S = S Int#
224−-- This hint will no longer trigger once hlint > 1.9.41 is released.
225−{-# ANN S ("HLint: ignore Use newtype instead of data" :: String) #-}
226−#else
227244 startState = False
228245 go a c
229246 | a = Just False