module Argo.Type.Number where

import qualified Argo.Decoder as Decoder
import qualified Argo.Literal as Literal
import qualified Control.Applicative as Applicative
import qualified Control.DeepSeq as DeepSeq
import qualified Control.Monad as Monad
import qualified Data.Bool as Bool
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Builder as Builder
import qualified Data.Maybe as Maybe
import qualified Data.Word as Word

data Number
    = Number Integer Integer
    deriving (Number -> Number -> Bool
(Number -> Number -> Bool)
-> (Number -> Number -> Bool) -> Eq Number
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Number -> Number -> Bool
$c/= :: Number -> Number -> Bool
== :: Number -> Number -> Bool
$c== :: Number -> Number -> Bool
Eq, Int -> Number -> ShowS
[Number] -> ShowS
Number -> String
(Int -> Number -> ShowS)
-> (Number -> String) -> ([Number] -> ShowS) -> Show Number
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Number] -> ShowS
$cshowList :: [Number] -> ShowS
show :: Number -> String
$cshow :: Number -> String
showsPrec :: Int -> Number -> ShowS
$cshowsPrec :: Int -> Number -> ShowS
Show)

instance DeepSeq.NFData Number where
    rnf :: Number -> ()
rnf (Number Integer
x Integer
y) = Integer -> () -> ()
forall a b. NFData a => a -> b -> b
DeepSeq.deepseq Integer
x (() -> ()) -> () -> ()
forall a b. (a -> b) -> a -> b
$ Integer -> ()
forall a. NFData a => a -> ()
DeepSeq.rnf Integer
y

normalize :: Number -> Number
normalize :: Number -> Number
normalize (Number Integer
x Integer
y) =
    if Integer
x Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0
    then Integer -> Integer -> Number
Number Integer
0 Integer
0
    else let (Integer
q, Integer
r) = Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
quotRem Integer
x Integer
10 in if Integer
r Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0
    then Number -> Number
normalize (Number -> Number) -> Number -> Number
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Number
Number Integer
q (Integer
y Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1)
    else Integer -> Integer -> Number
Number Integer
x Integer
y

encode :: Number -> Builder.Builder
encode :: Number -> Builder
encode (Number Integer
x Integer
y) =
    if Integer
y Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0
    then Integer -> Builder
Builder.integerDec Integer
x
    else Integer -> Builder
Builder.integerDec Integer
x
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Word8 -> Builder
Builder.word8 Word8
Literal.latinSmallLetterE
        Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Integer -> Builder
Builder.integerDec Integer
y

decode :: Decoder.Decoder Number
decode :: Decoder Number
decode = do
    Bool
ni <- (Maybe () -> Bool) -> Decoder (Maybe ()) -> Decoder Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe () -> Bool
forall a. Maybe a -> Bool
Maybe.isJust (Decoder (Maybe ()) -> Decoder Bool)
-> (Decoder () -> Decoder (Maybe ())) -> Decoder () -> Decoder Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Decoder () -> Decoder (Maybe ())
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Applicative.optional (Decoder () -> Decoder Bool) -> Decoder () -> Decoder Bool
forall a b. (a -> b) -> a -> b
$ Word8 -> Decoder ()
Decoder.word8 Word8
Literal.hyphenMinus
    ByteString
i <- (Word8 -> Bool) -> Decoder ByteString
Decoder.takeWhile1 Word8 -> Bool
Decoder.isDigit
    Bool -> Decoder () -> Decoder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
Monad.when (ByteString -> Int
ByteString.length ByteString
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1 Bool -> Bool -> Bool
&& Word8 -> ByteString -> Maybe Int
ByteString.elemIndex Word8
Literal.digitZero ByteString
i Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Maybe Int
forall a. a -> Maybe a
Just Int
0)
        (Decoder () -> Decoder ()) -> Decoder () -> Decoder ()
forall a b. (a -> b) -> a -> b
$ String -> Decoder ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"leading zero"
    ByteString
f <- (Maybe ByteString -> ByteString)
-> Decoder (Maybe ByteString) -> Decoder ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
Maybe.fromMaybe ByteString
ByteString.empty) (Decoder (Maybe ByteString) -> Decoder ByteString)
-> (Decoder ByteString -> Decoder (Maybe ByteString))
-> Decoder ByteString
-> Decoder ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Decoder ByteString -> Decoder (Maybe ByteString)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Applicative.optional (Decoder ByteString -> Decoder ByteString)
-> Decoder ByteString -> Decoder ByteString
forall a b. (a -> b) -> a -> b
$ do
        Word8 -> Decoder ()
Decoder.word8 Word8
Literal.fullStop
        (Word8 -> Bool) -> Decoder ByteString
Decoder.takeWhile1 Word8 -> Bool
Decoder.isDigit
    (Bool
ne, ByteString
e) <- (Maybe (Bool, ByteString) -> (Bool, ByteString))
-> Decoder (Maybe (Bool, ByteString)) -> Decoder (Bool, ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Bool, ByteString)
-> Maybe (Bool, ByteString) -> (Bool, ByteString)
forall a. a -> Maybe a -> a
Maybe.fromMaybe (Bool
False, ByteString
ByteString.empty)) (Decoder (Maybe (Bool, ByteString)) -> Decoder (Bool, ByteString))
-> (Decoder (Bool, ByteString)
    -> Decoder (Maybe (Bool, ByteString)))
-> Decoder (Bool, ByteString)
-> Decoder (Bool, ByteString)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Decoder (Bool, ByteString) -> Decoder (Maybe (Bool, ByteString))
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Applicative.optional (Decoder (Bool, ByteString) -> Decoder (Bool, ByteString))
-> Decoder (Bool, ByteString) -> Decoder (Bool, ByteString)
forall a b. (a -> b) -> a -> b
$ do
        Decoder Word8 -> Decoder ()
forall (f :: * -> *) a. Functor f => f a -> f ()
Monad.void
            (Decoder Word8 -> Decoder ())
-> ((Word8 -> Bool) -> Decoder Word8)
-> (Word8 -> Bool)
-> Decoder ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Bool) -> Decoder Word8
Decoder.satisfy
            ((Word8 -> Bool) -> Decoder ()) -> (Word8 -> Bool) -> Decoder ()
forall a b. (a -> b) -> a -> b
$ \ Word8
x -> Word8
x Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
Literal.latinSmallLetterE Bool -> Bool -> Bool
|| Word8
x Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
Literal.latinCapitalLetterE
        Bool
ne <- (Maybe Word8 -> Bool) -> Decoder (Maybe Word8) -> Decoder Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Maybe Word8 -> Maybe Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8 -> Maybe Word8
forall a. a -> Maybe a
Just Word8
Literal.hyphenMinus)
            (Decoder (Maybe Word8) -> Decoder Bool)
-> ((Word8 -> Bool) -> Decoder (Maybe Word8))
-> (Word8 -> Bool)
-> Decoder Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Decoder Word8 -> Decoder (Maybe Word8)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
Applicative.optional
            (Decoder Word8 -> Decoder (Maybe Word8))
-> ((Word8 -> Bool) -> Decoder Word8)
-> (Word8 -> Bool)
-> Decoder (Maybe Word8)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word8 -> Bool) -> Decoder Word8
Decoder.satisfy
            ((Word8 -> Bool) -> Decoder Bool)
-> (Word8 -> Bool) -> Decoder Bool
forall a b. (a -> b) -> a -> b
$ \ Word8
x -> Word8
x Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
Literal.hyphenMinus Bool -> Bool -> Bool
|| Word8
x Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
Literal.plusSign
        ByteString
e <- (Word8 -> Bool) -> Decoder ByteString
Decoder.takeWhile1 Word8 -> Bool
Decoder.isDigit
        (Bool, ByteString) -> Decoder (Bool, ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool
ne, ByteString
e)
    Decoder ()
Decoder.spaces
    Number -> Decoder Number
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Number -> Decoder Number)
-> (Number -> Number) -> Number -> Decoder Number
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Number -> Number
normalize (Number -> Decoder Number) -> Number -> Decoder Number
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Number
Number
        (Bool -> Integer -> Integer
negateIf Bool
ni (Integer -> Integer) -> Integer -> Integer
forall a b. (a -> b) -> a -> b
$ (ByteString -> Integer
fromDigits ByteString
i Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ ByteString -> Int
ByteString.length ByteString
f) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ ByteString -> Integer
fromDigits ByteString
f)
        (Bool -> Integer -> Integer
negateIf Bool
ne (ByteString -> Integer
fromDigits ByteString
e) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Int -> Integer
intToInteger (ByteString -> Int
ByteString.length ByteString
f))

negateIf :: Bool -> Integer -> Integer
negateIf :: Bool -> Integer -> Integer
negateIf = (Integer -> Integer)
-> (Integer -> Integer) -> Bool -> Integer -> Integer
forall a. a -> a -> Bool -> a
Bool.bool Integer -> Integer
forall a. a -> a
id Integer -> Integer
forall a. Num a => a -> a
negate

fromDigits :: ByteString.ByteString -> Integer
fromDigits :: ByteString -> Integer
fromDigits = (Integer -> Word8 -> Integer) -> Integer -> ByteString -> Integer
forall a. (a -> Word8 -> a) -> a -> ByteString -> a
ByteString.foldl' (\ Integer
a Word8
e -> (Integer
a Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
10) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Word8 -> Integer
word8ToInteger (Word8
e Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30)) Integer
0

intToInteger :: Int -> Integer
intToInteger :: Int -> Integer
intToInteger = Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral

word8ToInteger :: Word.Word8 -> Integer
word8ToInteger :: Word8 -> Integer
word8ToInteger = Word8 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral