on master help sign in
Copy-paste and adapt the scientific function from attoparsec
commitae70879b704a2a201fc22d69f7126f09ad489271 authorBryan O'Sullivan <bryano@fb.com> dateFri 28 Oct 2016, 14:53 (10 years ago) parent8cd2b5a
1 file changed+41−1
Data/Aeson/Parser/Internal.hs+41−1
Data/Aeson/Parser/Internal.hs+41−1
@@ -36,8 +36,11 @@ module Data.Aeson.Parser.Internal
3636import Prelude ()
3737import Prelude.Compat
3838
39+import Control.Applicative ((<|>))
40+import Control.Monad (void, when)
3941import Data.Aeson.Types.Internal (IResult(..), JSONPath, Result(..), Value(..))
40−import Data.Attoparsec.ByteString.Char8 (Parser, char, endOfInput, scientific, skipSpace, string)
42+import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDigit_w8, signed, skipSpace, string)
43+import Data.Scientific (Scientific)
4144import Data.Text (Text)
4245import Data.Vector as Vector (Vector, empty, fromListN, reverse)
4346import qualified Data.Attoparsec.ByteString as A
@@ -45,6 +48,7 @@ import qualified Data.Attoparsec.Lazy as L
4548import qualified Data.ByteString as B
4649import qualified Data.ByteString.Lazy as L
4750import qualified Data.HashMap.Strict as H
51+import qualified Data.Scientific as Sci
4852import Data.Aeson.Parser.Unescape
4953
5054#if MIN_VERSION_ghc_prim(0,3,1)
@@ -289,3 +293,39 @@ jsonEOF = json <* skipSpace <* endOfInput
289293-- end-of-input. See also: 'json''.
290294jsonEOF' :: Parser Value
291295jsonEOF' = json' <* skipSpace <* endOfInput
296+
297+------------------ Copy-pasted and adapted from attoparsec ------------------
298+
299+-- A strict pair
300+data SP = SP !Integer {-# UNPACK #-}!Int
301+
302+{-# INLINE scientific #-}
303+scientific :: Parser Scientific
304+scientific = do
305+ let minus = 45
306+ plus = 43
307+ sign <- A.peekWord8'
308+ let !positive = sign == plus || sign /= minus
309+ when (sign == plus || sign == minus) $
310+ void A.anyWord8
311+
312+ n <- decimal
313+
314+ let f fracDigits = SP (B.foldl' step n fracDigits)
315+ (negate $ B.length fracDigits)
316+ step a w = a * 10 + fromIntegral (w - 48)
317+
318+ dotty <- A.peekWord8
319+ -- '.' -> ascii 46
320+ SP c e <- case dotty of
321+ Just 46 -> A.anyWord8 *> (f <$> A.takeWhile isDigit_w8)
322+ _ -> pure (SP n 0)
323+
324+ let !signedCoeff | positive = c
325+ | otherwise = -c
326+
327+ let littleE = 101
328+ bigE = 69
329+ (A.satisfy (\ex -> ex == littleE || ex == bigE) *>
330+ fmap (Sci.scientific signedCoeff . (e +)) (signed decimal)) <|>
331+ return (Sci.scientific signedCoeff e)