@@ -2,12 +2,9 @@
2{-# LANGUAGE CPP #-}
2{-# LANGUAGE CPP #-}
3{-# LANGUAGE NoImplicitPrelude #-}
3{-# LANGUAGE NoImplicitPrelude #-}
4{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
5−#if MIN_VERSION_ghc_prim(0,3,1)
6−{-# LANGUAGE MagicHash #-}
8#if __GLASGOW_HASKELL__ <= 710 && __GLASGOW_HASKELL__ >= 706
5#if __GLASGOW_HASKELL__ <= 710 && __GLASGOW_HASKELL__ >= 706
9-- Work around a compiler bug
6-- Work around a compiler bug
10−{-# OPTIONS_GHC -fsimpl-tick-factor=200 #-}
7+{-# OPTIONS_GHC -fsimpl-tick-factor=300 #-}
13-- Module: Data.Aeson.Parser.Internal
10-- Module: Data.Aeson.Parser.Internal
@@ -58,8 +55,10 @@ import Data.Aeson.Types.Internal (IResult(..), JSONPath, Object, Result(..), Val
58import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDigit_w8, signed, string)
55import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDigit_w8, signed, string)
59import Data.Function (fix)
56import Data.Function (fix)
60import Data.Functor.Compat (($>))
57import Data.Functor.Compat (($>))
58+import Data.Bits (testBit)
61import Data.Scientific (Scientific)
59import Data.Scientific (Scientific)
62import Data.Text (Text)
60import Data.Text (Text)
61+import qualified Data.Text.Encoding as TE
63import Data.Vector (Vector)
62import Data.Vector (Vector)
64import qualified Data.Vector as Vector (empty, fromList, fromListN, reverse)
63import qualified Data.Vector as Vector (empty, fromList, fromListN, reverse)
65import qualified Data.Attoparsec.ByteString as A
64import qualified Data.Attoparsec.ByteString as A
@@ -71,12 +70,6 @@ import qualified Data.HashMap.Strict as H
71import qualified Data.Scientific as Sci
70import qualified Data.Scientific as Sci
72import Data.Aeson.Parser.Unescape (unescapeText)
71import Data.Aeson.Parser.Unescape (unescapeText)
74−#if MIN_VERSION_ghc_prim(0,3,1)
75−import GHC.Base (Int#, (==#), isTrue#, word2Int#, orI#, andI#)
76−import GHC.Word (Word8(W8#))
77−import qualified Data.Text.Encoding as TE
80#define BACKSLASH 92
73#define BACKSLASH 92
81#define CLOSE_CURLY 125
74#define CLOSE_CURLY 125
82#define CLOSE_SQUARE 93
75#define CLOSE_SQUARE 93
@@ -323,37 +316,20 @@ jstring = A.word8 DOUBLE_QUOTE *> jstring_
323-- | Parse a string without a leading quote.
316-- | Parse a string without a leading quote.
324jstring_ :: Parser Text
317jstring_ :: Parser Text
325{-# INLINE jstring_ #-}
318{-# INLINE jstring_ #-}
326−jstring_ = {-# SCC "jstring_" #-} do
319+jstring_ = do
327−#if MIN_VERSION_ghc_prim(0,3,1)
320+ s <- A.takeWhile (\w -> w /= DOUBLE_QUOTE && w /= BACKSLASH && not (testBit w 7))
328− (s, S _ escaped) <- A.runScanner startState go <* A.anyWord8
321+ let txt = TE.decodeUtf8 s
329− -- We escape only if there are
322+ w <- A.peekWord8
330− -- non-ascii (over 7bit) characters or backslash present.
332− -- Note: if/when text will have fast ascii -> text conversion
333− -- (e.g. uses utf8 encoding) we can have further speedup.
335− then case unescapeText s of
323+ case w of
336− Right r -> return r
324+ Nothing -> fail "string without end"
337− Left err -> fail $ show err
325+ Just DOUBLE_QUOTE -> A.anyWord8 $> txt
338− else return (TE.decodeUtf8 s)
326+ _ -> jstringSlow s
340− startState = S 0# 0#
328+jstringSlow :: B.ByteString -> Parser Text
341− go (S skip escaped) (W8# c)
329+{-# INLINE jstringSlow #-}
342− | isTrue# skip = Just (S 0# escaped')
330+jstringSlow s' = {-# SCC "jstringSlow" #-} do
343− | isTrue# (w ==# 34#) = Nothing -- double quote
344− | otherwise = Just (S skip' escaped')
347− skip' = w ==# 92# -- backslash
349− `orI#` (w `andI#` 0x80# ==# 0x80#) -- c >= 0x80
351− `orI#` (w `andI#` 0x1f# ==# w) -- c < 0x20
355 s <- A.scan startState go <* A.anyWord8
331 s <- A.scan startState go <* A.anyWord8
356− case unescapeText s of
332+ case unescapeText (B.append s' s) of
357 Right r -> return r
333 Right r -> return r
358 Left err -> fail $ show err
334 Left err -> fail $ show err
@@ -364,7 +340,6 @@ data S = S Int# Int#
364 | otherwise = let a' = c == backslash
340 | otherwise = let a' = c == backslash
365 in Just a'
341 in Just a'
366 where backslash = BACKSLASH
342 where backslash = BACKSLASH
369decodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString -> Maybe a
344decodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString -> Maybe a
370decodeWith p to s =
345decodeWith p to s =