77-- Stability : experimental
88-- Portability : GHC
99
10- {-# LANGUAGE CPP #-}
10+ {-# OPTIONS_GHC -Wno-orphans #-}
1111
12- {-# LANGUAGE OverloadedLists #-}
13-
14- module Streamly.Internal.Data.Json.Stream
15- ( parseJson )
12+ module Streamly.Internal.Data.Json.Stream
13+ ( parseJson
14+ , parseJsonEOF
15+ )
1616where
1717
1818import Control.Monad (when )
1919import Control.Monad.Catch (MonadCatch )
20- import Data.Bits (testBit )
2120import Data.Char (chr , ord )
2221import Data.Functor.Identity (runIdentity )
2322import Data.Word (Word8 )
@@ -30,6 +29,7 @@ import qualified Data.Scientific as Sci
3029import Streamly.Internal.Data.Parser.ParserD (Parser )
3130import Streamly.Internal.Data.Array (Array )
3231import Streamly.Internal.Data.Fold.Types (Fold (.. ))
32+ import Streamly.Internal.Data.Strict (Tuple' (.. ))
3333import qualified Streamly.Internal.Data.Parser as PR
3434import qualified Streamly.Internal.Data.Parser.ParserD as P
3535import qualified Streamly.Internal.Data.Array as A
@@ -56,27 +56,12 @@ import qualified Streamly.Data.Fold as FL
5656#define C_n 110
5757#define C_t 116
5858
59+ backslash , zero , minus , plus :: Word8
5960backslash = 92 :: Word8
60- close_curly = 125 :: Word8
61- close_square = 93 :: Word8
62- comma = 44 :: Word8
63- double_quote = 34 :: Word8
64- open_curly = 123 :: Word8
65- open_square = 91 :: Word8
66- colon = 58 :: Word8
67- c_0 = 48 :: Word8
68- c_9 = 57 :: Word8
69- c_A = 65 :: Word8
70- c_F = 70 :: Word8
71- c_a = 97 :: Word8
72- c_f = 102 :: Word8
73- c_n = 110 :: Word8
74- c_t = 116 :: Word8
7561zero = 48 :: Word8
7662minus = 45 :: Word8
7763plus = 43 :: Word8
7864
79-
8065instance Enum a => Hashable (A. Array a ) where
8166 hash arr = fromIntegral $ runIdentity $ IUF. fold A. read IFL. rollingHash arr
8267 hashWithSalt salt arr = fromIntegral $ runIdentity $
@@ -99,46 +84,33 @@ data Value
9984 | Null
10085 deriving (Eq , Show )
10186
102- {-# INLINE pushToFold #-}
103- pushToFold :: Monad m => Fold m a b -> a -> Fold m a b
104- pushToFold (Fold step initial extract) a = Fold step initial' extract
105- where
106- initial' = do
107- s <- initial
108- step s a
109-
11087{-# INLINE skipSpace #-}
11188skipSpace :: MonadCatch m => Parser m Word8 ()
11289skipSpace =
11390 P. takeWhile
11491 (\ w -> w == 0x20 || w == 0x0a || w == 0x0d || w == 0x09 )
11592 FL. drain
11693
117- {-# INLINE spaceAround #-}
118- spaceAround :: MonadCatch m => Parser m Word8 b -> Parser m Word8 b
119- spaceAround parseInBetween = do
120- skipSpace
121- between <- parseInBetween
122- skipSpace
123- return between
124-
12594{-# INLINE skip #-}
12695skip :: MonadCatch m => Int -> Parser m a ()
12796skip n = P. take n FL. drain
12897
12998{-# INLINE string #-}
99+
130100string :: MonadCatch m => String -> Parser m Word8 ()
131101string = P. eqBy (==) . map (fromIntegral . ord)
132102
133103{-# INLINE match #-}
134104match :: MonadCatch m => Word8 -> Parser m Word8 ()
135105match w = P. eqBy (==) [w]
136106
107+ {-# SPECIALISE foldToInteger :: Monad m => Int -> Fold m Word8 Int #-}
108+ {-# SPECIALISE foldToInteger :: Monad m => Integer -> Fold m Word8 Integer #-}
137109{-# INLINE foldToInteger #-}
138- foldToInteger :: Monad m => Fold m Word8 Integer
139- foldToInteger = Fold step initial extract
110+ foldToInteger :: ( Num a , Monad m ) => a -> Fold m Word8 a
111+ foldToInteger begin = Fold step initial extract
140112 where
141- initial = return 0
113+ initial = return begin
142114
143115 step s a = return $ s * 10 + fromIntegral (a - 48 )
144116
@@ -147,10 +119,20 @@ foldToInteger = Fold step initial extract
147119{-# INLINE parseDecimal0 #-}
148120parseDecimal0 :: MonadCatch m => Parser m Word8 Integer
149121parseDecimal0 = do
150- h <- P. peek
151- n <- P. peek
152- when (h == zero && n - 48 > 9 ) $ P. die " Leading zero in a number is not accepted in JSON."
153- P. takeWhile1 (\ w -> w - 48 <= 9 ) foldToInteger
122+ z <- P. peek
123+ n <- P. takeWhile1 (\ w -> w - 48 <= 9 ) (foldToInteger 0 )
124+ when (z == zero && n /= 0 ) $ do
125+ P. die $ " Leading zero in a number is not accepted in JSON."
126+ return n
127+
128+ {-# INLINE parseDecimal #-}
129+ parseDecimal :: MonadCatch m => Parser m Word8 Int
130+ parseDecimal = do
131+ sign <- P. peek
132+ let positive = sign == plus || sign /= minus
133+ pr = P. takeWhile1 (\ w -> w - 48 <= 9 ) (foldToInteger 0 )
134+ when (sign == plus || sign == minus) (skip 1 )
135+ if positive then pr else negate <$> pr
154136
155137{-# INLINE parseJsonNumber #-}
156138parseJsonNumber :: MonadCatch m => Parser m Word8 Scientific
@@ -159,8 +141,24 @@ parseJsonNumber = do
159141 let positive = sign == plus || sign /= minus
160142 when (sign == plus || sign == minus) (skip 1 )
161143 n <- parseDecimal0
162- let signedCoeff = if positive then n else (- n)
163- return (Sci. scientific signedCoeff 0 )
144+ dot <- P. peekMaybe
145+ Tuple' c e <-
146+ case dot of
147+ Just 46 -> do
148+ skip 1
149+ P. takeWhile1
150+ (\ w -> w - 48 <= 9 )
151+ (Tuple' <$> foldToInteger n <*> FL. length )
152+ _ -> return $ Tuple' n 0
153+
154+ let signedCoeff = if positive then c else (- c)
155+ mex <- P. peekMaybe
156+ case mex of
157+ Just ex
158+ | ex == 101 || ex == 69 -> do
159+ skip 1
160+ Sci. scientific signedCoeff . (e + ) <$> parseDecimal
161+ _ -> return (Sci. scientific signedCoeff e)
164162
165163{-# INLINE parseJsonString #-}
166164parseJsonString :: MonadCatch m => Parser m Word8 JsonString
@@ -170,19 +168,24 @@ parseJsonString = do
170168 w <- P. peek
171169 case w of
172170 DOUBLE_QUOTE -> skip 1 >> return s
171+ BACKSLASH -> (fmap (s <> ) escapeParseJsonString) <* skip 1
173172 _ -> do
174- P. die $ [(chr . fromIntegral ) w] ++ " Not yet implemented to handle escape sequences in String."
173+ P. die $ [(chr . fromIntegral ) w] ++ " : String without end."
174+
175+ {-# INLINE escapeParseJsonString #-}
176+ escapeParseJsonString :: MonadCatch m => Parser m Word8 JsonString
177+ escapeParseJsonString = P. scan startState go (Uni. foldUtf8With A. unsafeWrite)
178+ where
179+ startState = False
180+ go s a
181+ | s = Just False
182+ | a == DOUBLE_QUOTE = Nothing
183+ | otherwise =
184+ let a' = a == backslash
185+ in Just a'
175186
176187{-# INLINE parseJsonValue #-}
177188parseJsonValue :: MonadCatch m => Parser m Word8 Value
178- {- parseJsonValue = skipSpace >>
179- (Object <$> parseJsonObject)
180- `P.alt` (Array <$> parseJsonArray)
181- `P.alt` (String <$> parseJsonString)
182- `P.alt` (Number <$> parseJsonNumber)
183- `P.alt` (Bool True <$ string "true")
184- `P.alt` (Bool False <$ string "false")
185- `P.alt` (Null <$ string "null") -}
186189parseJsonValue = do
187190 skipSpace
188191 w <- P. peek
@@ -230,13 +233,55 @@ parseJsonArray = do
230233 match CLOSE_SQUARE
231234 return jsonValues
232235
236+ {-# INLINE parseJsonEOF #-}
237+ parseJsonEOF :: MonadCatch m => PR. Parser m Word8 Value
238+ parseJsonEOF =
239+ P. toParserK $ do
240+ v <- parseJsonValue
241+ skipSpace
242+ P. eof
243+ return v
244+
233245{-# INLINE parseJson #-}
234246parseJson :: MonadCatch m => PR. Parser m Word8 Value
235- -- parseJson = P.toParserK (spaceAround $ (Object <$> parseJsonObject) `P.alt` (Array <$> parseJsonArray))
236- parseJson = P. toParserK $ do
237- skipSpace
238- w <- P. peek
239- case w of
240- OPEN_CURLY -> Object <$> parseJsonObject
241- OPEN_SQUARE -> Array <$> parseJsonArray
242- _ -> P. die $ " Encountered " ++ [chr . fromIntegral $ w] ++ " when expection [ or {."
247+ parseJson = P. toParserK $ parseJsonValue
248+
249+ {-
250+
251+ {- # INLINE pushToFold #-}
252+ pushToFold :: Monad m => Fold m a b -> a -> Fold m a b
253+ pushToFold (Fold step initial extract) a = Fold step initial' extract
254+ where
255+ initial' = do
256+ s <- initial
257+ step s a
258+
259+ sepBy1 ::
260+ MonadCatch m
261+ => Fold m a c
262+ -> Parser m Word8 a
263+ -> Parser m Word8 sep
264+ -> Parser m Word8 c
265+ sepBy1 fl p sep = do
266+ a <- p
267+ P.many (pushToFold fl a) (sep >> p)
268+
269+ sepBy ::
270+ MonadCatch m
271+ => Fold m a c
272+ -> Parser m Word8 a
273+ -> Parser m Word8 sep
274+ -> Parser m Word8 c
275+ sepBy fl@(Fold _ initial extract) p sep =
276+ sepBy1 fl p sep `P.alt` P.yieldM (initial >>= extract)
277+
278+ parseJsonValue = skipSpace >>
279+ (Object <$> parseJsonObject)
280+ `P.alt` (Array <$> parseJsonArray)
281+ `P.alt` (String <$> parseJsonString)
282+ `P.alt` (Number <$> parseJsonNumber)
283+ `P.alt` (Bool True <$ string "true")
284+ `P.alt` (Bool False <$ string "false")
285+ `P.alt` (Null <$ string "null")
286+
287+ -}
0 commit comments