{-# LANGUAGE ScopedTypeVariables #-}

module Ivory.Language.BoundedInteger where

import           Text.Printf

import           Ivory.Language.Proxy
import qualified Ivory.Language.Syntax as I
import           Ivory.Language.Type

--------------------------------------------------------------------------------

-- | It is an error if a constant implicitly underflows/overflows.
boundedFromInteger :: forall a b . (Num a, IvoryType a, Bounded b, Integral b)
                   => (I.Expr -> a) -> b -> Integer -> a
boundedFromInteger constr _ i
  | i > snd bounds
  = error $ printf "The constant %d is too large to cast to type %s." i tyStr
  | i < fst bounds
  = error $ printf "The constant %d is too small to cast to type %s." i tyStr
  | otherwise
  = constr (fromInteger i)
  where
  ty     = ivoryType (Proxy :: Proxy a)
  tyStr  = show ty
  bounds :: (Integer, Integer)
  bounds = (fromIntegral (minBound :: b), fromIntegral (maxBound :: b))