-- * State observation and manipulation functions

import Data.Attoparsec.FastSet (charClass, memberChar)

import Data.Attoparsec.Internal (Parser, (<?>))

import Data.ByteString.Internal (c2w, w2c)

import Data.String (IsString(..))

import Prelude hiding (takeWhile)

isHorizontalSpace w = w == 32 || w == 9

{-# INLINE isHorizontalSpace #-}

--- | Parse a Double. The position counter is not updated.

-double = numeric "Double" readDouble

-- | Parse and decode an unsigned hexadecimal number. The hex digits

-- @\'a\'@ through @\'f\'@ may be upper or lower case.

-- | Parse and decode an unsigned decimal number.

decimal :: Integral a => Parser a

{-# SPECIALISE decimal :: Parser Int #-}

+{-# SPECIALISE decimal :: Parser Integer #-}

decimal = B8.foldl' step 0 `fmap` I.takeWhile1 isDig

where isDig w = w >= 48 && w <= 57

step a w = a * 10 + fromIntegral (w - 48)

signed p = (negate <$> (char8 '-' *> p))

+data T = T !Integer !Int

+-- | Parse a rational number.

+-- This parser accepts an optional leading sign character, followed by

+-- at least one decimal digit. The syntax similar to that accepted by

+-- the 'read' function, with the exception that a trailing @\'.\'@ or

+-- @\'e\'@ /not/ followed by a number is not consumed.

+-- Examples with behaviour identical to 'read', if you feed an empty

+-- continuation to the first result:

+-- >rational "3" == Done 3.0 ""

+-- >rational "3.1" == Done 3.1 ""

+-- >rational "3e4" == Done 30000.0 ""

+-- >rational "3.1e4" == Done 31000.0, ""

+-- Examples with behaviour identical to 'read':

+-- >rational ".3" == Fail "input does not start with a digit"

+-- >rational "e3" == Fail "input does not start with a digit"

+-- Examples of differences from 'read':

+-- >rational "3.foo" == Done 3.0 ".foo"

+-- >rational "3e" == Done 3.0 "e"

+rational :: RealFloat a => Parser a

+{-# SPECIALIZE rational :: Parser Double #-}

+rational = floaty $ \real frac fracDenom -> fromRational $

+ real % 1 + frac % fracDenom

+-- | Parse a rational number.

+-- The syntax accepted by this parser is the same as for 'rational'.

+-- /Note/: This function is almost ten times faster than 'rational',

+-- but is slightly less accurate.

+-- The 'Double' type supports about 16 decimal places of accuracy.

+-- For 94.2% of numbers, this function and 'rational' give identical

+-- results, but for the remaining 5.8%, this function loses precision

+-- around the 15th decimal place. For 0.001% of numbers, this

+-- function will lose precision at the 13th or 14th decimal place.

+double = floaty $ \real frac fracDenom ->

+ fromIntegral frac / fromIntegral fracDenom

+floaty :: RealFloat a => (Integer -> Integer -> Integer -> a) -> Parser a

+ sign <- I.satisfy (\c -> c == minus || c == plus) <|> return plus

+ ds <- I.takeWhile isDigit_w8

+ case (case I.parse decimal ds of

+ I.Partial k -> k B.empty

+ I.Done _ n -> return $ T n (B.length ds)

+ _ -> fail "no digits after decimal"

+ T fraction fracDigits <- tryFraction <|> return (T 0 0)

+ e w = w == littleE || w == bigE

+ power <- (I.satisfy e *> signed decimal) <|> return (0::Int)

+ let n = if fracDigits == 0

+ else fromIntegral real * (10 ^^ power)

+ then f real fraction (10 ^ fracDigits)

+ else f real fraction (10 ^ fracDigits) * (10 ^^ power)

+ return $! if sign == plus