@@ -103,14 +103,14 @@ module Data.Attoparsec.Text
103103 , I.atEnd
104104 ) where
105105
106−import Control.Applicative ((<$>), (*>), (<*), (<|>))
106+import Control.Applicative (pure, (<$>), (*>), (<*), (<|>))
107107import Data.Attoparsec.Combinator
108108import Data.Attoparsec.Number (Number(..))
109+import Data.Scientific (Scientific, scientific, coefficient, base10Exponent)
109110import Data.Attoparsec.Text.Internal ((<?>), Parser, Result, parse, takeWhile1)
110111import Data.Bits (Bits, (.|.), shiftL)
111112import Data.Char (isAlpha, isDigit, isSpace, ord)
112113import Data.Int (Int8, Int16, Int32, Int64)
113−import Data.Ratio ((%))
114114import Data.Text (Text)
115115import Data.Word (Word8, Word16, Word32, Word64, Word)
116116import qualified Data.Attoparsec.Internal as I
@@ -343,8 +343,8 @@ rational :: Fractional a => Parser a
343343{-# SPECIALIZE rational :: Parser Double #-}
344344{-# SPECIALIZE rational :: Parser Float #-}
345345{-# SPECIALIZE rational :: Parser Rational #-}
346−rational = floaty $ \real frac fracDenom -> fromRational $
347− real % 1 + frac % fracDenom
346+{-# SPECIALIZE rational :: Parser Scientific #-}
347+rational = scientifically realToFrac
348348
349349-- | Parse a rational number.
350350--
@@ -362,12 +362,7 @@ rational = floaty $ \real frac fracDenom -> fromRational $
362362-- This function does not accept string representations of \"NaN\" or
363363-- \"Infinity\".
364364double :: Parser Double
365−double = floaty asDouble
366−
367−asDouble :: Integer -> Integer -> Integer -> Double
368−asDouble real frac fracDenom =
369− fromIntegral real + fromIntegral frac / fromIntegral fracDenom
370−{-# INLINE asDouble #-}
365+double = rational
371366
372367-- | Parse a number, attempting to preserve both speed and precision.
373368--
@@ -381,11 +376,34 @@ asDouble real frac fracDenom =
381376-- This function does not accept string representations of \"NaN\" or
382377-- \"Infinity\".
383378number :: Parser Number
384−number = floaty $ \real frac fracDenom ->
385− if frac == 0 && fracDenom == 0
386− then I real
387− else D (asDouble real frac fracDenom)
388−{-# INLINE number #-}
379+number = scientifically $ \s ->
380+ let e = base10Exponent s
381+ c = coefficient s
382+ in if e >= 0
383+ then I (c * 10 ^ e)
384+ else D (fromInteger c / 10 ^ negate e)
385+
386+{-# INLINE scientifically #-}
387+scientifically :: (Scientific -> a) -> Parser a
388+scientifically h = do
389+ !positive <- ((== '+') <$> I.satisfy (\c -> c == '-' || c == '+')) <|>
390+ pure True
391+
392+ n <- decimal
393+
394+ let f fracDigits = scientific (T.foldl' step n fracDigits)
395+ (negate $ T.length fracDigits)
396+ step a c = a * 10 + fromIntegral (ord c - 48)
397+
398+ s <- (I.satisfy (=='.') *> (f <$> I.takeWhile isDigit)) <|>
399+ pure (scientific n 0)
400+
401+ let !signedCoeff | positive = coefficient s
402+ | otherwise = negate $ coefficient s
403+
404+ (I.satisfy (\c -> c == 'e' || c == 'E') *>
405+ fmap (h . scientific signedCoeff . (base10Exponent s +)) (signed decimal)) <|>
406+ return (h $ scientific signedCoeff (base10Exponent s))
389407
390408-- | Parse a single digit, as recognised by 'isDigit'.
391409digit :: Parser Char
@@ -433,31 +451,3 @@ s .*> f = I.string s *> f
433451-- | Type-specialized version of '<*' for 'Text'.
434452(<*.) :: Parser a -> Text -> Parser a
435453f <*. s = f <* I.string s
436−
437−data T = T !Integer !Int
438−
439−floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a
440−{-# INLINE floaty #-}
441−floaty f = do
442− !positive <- ((== '+') <$> I.satisfy (\c -> c == '-' || c == '+')) <|>
443− return True
444− real <- decimal
445− let tryFraction = do
446− _ <- I.satisfy (=='.')
447− ds <- I.takeWhile isDigit
448− case I.parseOnly decimal ds of
449− Right n -> return $ T n (T.length ds)
450− _ -> fail "no digits after decimal"
451− T fraction fracDigits <- tryFraction <|> return (T 0 0)
452− let e c = c == 'e' || c == 'E'
453− power <- (I.satisfy e *> signed decimal) <|> return (0::Int)
454− let n = if fracDigits == 0
455− then if power == 0
456− then fromIntegral real
457− else fromIntegral real * (10 ^^ power)
458− else if power == 0
459− then f real fraction (10 ^ fracDigits)
460− else f real fraction (10 ^ fracDigits) * (10 ^^ power)
461− return $ if positive
462− then n
463− else -n