{-# LANGUAGE CPP #-}
-- |
--
-- Builders for 'JNumber'
--
module Waargonaut.Encode.Builder.JNumber
  ( jNumberBuilder
  ) where

import           Control.Lens                    (review)

import qualified Data.Digit                      as D
import           Data.List.NonEmpty              (NonEmpty)

#if !MIN_VERSION_base(4,11,0)
import           Data.Monoid                     ((<>))
#endif


import           Waargonaut.Types.JNumber        (E (..), Exp (..), Frac (..),
                                                  JNumber (..), jIntToDigits)

import           Waargonaut.Encode.Builder.Types (Builder (..))

-- $setup
-- >>> :set -XOverloadedStrings
-- >>> import Data.List.NonEmpty (NonEmpty ((:|)))
-- >>> import Data.Digit (DecDigit(..))
-- >>> import qualified Data.Digit as D
-- >>> import Data.Text.Lazy.Builder (toLazyText)
-- >>> import Waargonaut.Encode.Builder (textBuilder)
-- >>> import Waargonaut.Types.JNumber (JInt' (JIntInt))
--

getExpSymbol
  :: Monoid b
  => Builder t b
  -> Maybe Bool
  -> b
getExpSymbol :: Builder t b -> Maybe Bool -> b
getExpSymbol Builder t b
bldr (Just Bool
True)  = Builder t b -> Char -> b
forall t b. Builder t b -> Char -> b
fromChar Builder t b
bldr Char
'-'
getExpSymbol Builder t b
bldr (Just Bool
False) = Builder t b -> Char -> b
forall t b. Builder t b -> Char -> b
fromChar Builder t b
bldr Char
'+'
getExpSymbol Builder t b
_    Maybe Bool
_            = b
forall a. Monoid a => a
mempty

eBuilder
  :: Monoid b
  => Builder t b
  -> E
  -> b
eBuilder :: Builder t b -> E -> b
eBuilder Builder t b
bldr E
Ee = Builder t b -> Char -> b
forall t b. Builder t b -> Char -> b
fromChar Builder t b
bldr Char
'e'
eBuilder Builder t b
bldr E
EE = Builder t b -> Char -> b
forall t b. Builder t b -> Char -> b
fromChar Builder t b
bldr Char
'E'

fracBuilder :: Monoid b => Builder t b -> Frac -> b
fracBuilder :: Builder t b -> Frac -> b
fracBuilder Builder t b
bldr (Frac NonEmpty DecDigit
digs) = Builder t b -> NonEmpty DecDigit -> b
forall b t. Monoid b => Builder t b -> NonEmpty DecDigit -> b
digitsBuilder Builder t b
bldr NonEmpty DecDigit
digs

digitsBuilder
  :: Monoid b
  => Builder t b
  -> NonEmpty D.DecDigit
  -> b
digitsBuilder :: Builder t b -> NonEmpty DecDigit -> b
digitsBuilder Builder t b
bldr =
  (DecDigit -> b) -> NonEmpty DecDigit -> b
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (Builder t b -> Int -> b
forall t b. Builder t b -> Int -> b
fromInt Builder t b
bldr (Int -> b) -> (DecDigit -> Int) -> DecDigit -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AReview Int DecDigit -> DecDigit -> Int
forall b (m :: * -> *) t. MonadReader b m => AReview t b -> m t
review AReview Int DecDigit
forall a d. (Integral a, Decimal d) => Prism' a d
D.integralDecimal)

-- | Builder for the exponent portion.
expBuilder
  :: Monoid b
  => Builder t b
  -> Exp
  -> b
expBuilder :: Builder t b -> Exp -> b
expBuilder Builder t b
bldr (Exp E
e Maybe Bool
sign NonEmpty DecDigit
digs) =
  Builder t b -> E -> b
forall b t. Monoid b => Builder t b -> E -> b
eBuilder Builder t b
bldr E
e b -> b -> b
forall a. Semigroup a => a -> a -> a
<> Builder t b -> Maybe Bool -> b
forall b t. Monoid b => Builder t b -> Maybe Bool -> b
getExpSymbol Builder t b
bldr Maybe Bool
sign b -> b -> b
forall a. Semigroup a => a -> a -> a
<> Builder t b -> NonEmpty DecDigit -> b
forall b t. Monoid b => Builder t b -> NonEmpty DecDigit -> b
digitsBuilder Builder t b
bldr NonEmpty DecDigit
digs

-- | Printing of JNumbers
--
-- >>> toLazyText $ jNumberBuilder textBuilder (JNumber {_minus = False, _numberint = JIntInt D.DecDigit3 [], _frac = Just (Frac (D.DecDigit4 :| [D.DecDigit5])), _expn = Just (Exp {_ex = Ee, _minusplus = Just False, _expdigits = D.DecDigit1 :| [D.DecDigit0]})})
-- "3.45e+10"
--
-- >>> toLazyText $ jNumberBuilder textBuilder (JNumber {_minus = True, _numberint = JIntInt D.DecDigit3 [], _frac = Just (Frac (D.DecDigit4 :| [D.DecDigit5])), _expn = Just (Exp {_ex = Ee, _minusplus = Just True, _expdigits = D.DecDigit0 :| [D.x2]})})
-- "-3.45e-02"
--
-- >>> toLazyText $ jNumberBuilder textBuilder (JNumber {_minus = False, _numberint = JIntInt D.DecDigit0 [D.DecDigit0], _frac = Nothing, _expn = Nothing})
-- "00"
--
jNumberBuilder
  :: Monoid b
  => Builder t b
  -> JNumber
  -> b
jNumberBuilder :: Builder t b -> JNumber -> b
jNumberBuilder Builder t b
bldr (JNumber Bool
sign JInt
digs Maybe Frac
mfrac Maybe Exp
mexp) =
  b
s b -> b -> b
forall a. Semigroup a => a -> a -> a
<> b
digits b -> b -> b
forall a. Semigroup a => a -> a -> a
<> b
frac' b -> b -> b
forall a. Semigroup a => a -> a -> a
<> b
expo
  where
    s :: b
s      = if Bool
sign then Builder t b -> Char -> b
forall t b. Builder t b -> Char -> b
fromChar Builder t b
bldr Char
'-' else b
forall a. Monoid a => a
mempty
    digits :: b
digits = Builder t b -> NonEmpty DecDigit -> b
forall b t. Monoid b => Builder t b -> NonEmpty DecDigit -> b
digitsBuilder Builder t b
bldr (NonEmpty DecDigit -> b)
-> (JInt -> NonEmpty DecDigit) -> JInt -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JInt -> NonEmpty DecDigit
jIntToDigits (JInt -> b) -> JInt -> b
forall a b. (a -> b) -> a -> b
$ JInt
digs
    frac' :: b
frac'  = (Frac -> b) -> Maybe Frac -> b
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (b -> b -> b
forall a. Monoid a => a -> a -> a
mappend (Builder t b -> Char -> b
forall t b. Builder t b -> Char -> b
fromChar Builder t b
bldr Char
'.') (b -> b) -> (Frac -> b) -> Frac -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder t b -> Frac -> b
forall b t. Monoid b => Builder t b -> Frac -> b
fracBuilder Builder t b
bldr) Maybe Frac
mfrac
    expo :: b
expo   = (Exp -> b) -> Maybe Exp -> b
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (Builder t b -> Exp -> b
forall b t. Monoid b => Builder t b -> Exp -> b
expBuilder Builder t b
bldr) Maybe Exp
mexp