content: {-# LANGUAGE DeriveDataTypeable #-}
  module IntLit (IntLit(..),
                 ilDec, ilSizedDec, ilHex, ilSizedHex, ilBin, ilSizedBin,
                 showVeriIntLit, showSizedVeriIntLit
                ) where
  
  import IntegerUtil(integerFormatPref, integerToString)
  import PPrint
  import PVPrint
  import Eval
  import ErrorUtil(internalError)
  import qualified Data.Generics as Generic
  
  data IntLit = IntLit { ilWidth :: Maybe Integer,
                         ilBase  :: Integer,
                         ilValue :: Integer }
                deriving (Generic.Data, Generic.Typeable)
  
  
  
  ilDec :: Integer -> IntLit
  ilDec i = IntLit { ilWidth = Nothing, ilBase = 10, ilValue = i }
  
  ilSizedDec :: Integer -> Integer -> IntLit
  ilSizedDec w i = IntLit { ilWidth = Just w, ilBase = 10, ilValue = i }
  
  ilHex :: Integer -> IntLit
  ilHex i = IntLit { ilWidth = Nothing, ilBase = 16, ilValue = i }
  
  ilSizedHex :: Integer -> Integer -> IntLit
  ilSizedHex w i = IntLit { ilWidth = Just w, ilBase = 16, ilValue = i }
  
  ilBin :: Integer -> IntLit
  ilBin i = IntLit { ilWidth = Nothing, ilBase = 2,  ilValue = i }
  
  ilSizedBin :: Integer -> Integer -> IntLit
  ilSizedBin w i = IntLit { ilWidth = Just w, ilBase = 2, ilValue = i }
  
  
  instance Eq IntLit where
       IntLit { ilValue = i1 } == IntLit { ilValue = i2 }  =  i1 == i2
       IntLit { ilValue = i1 } /= IntLit { ilValue = i2 }  =  i1 /= i2
  
  instance Ord IntLit where
       IntLit { ilValue = i1 } <= IntLit { ilValue = i2 }  =  i1 <= i2
       IntLit { ilValue = i1 } <  IntLit { ilValue = i2 }  =  i1 <  i2
       IntLit { ilValue = i1 } >= IntLit { ilValue = i2 }  =  i1 >= i2
       IntLit { ilValue = i1 } >  IntLit { ilValue = i2 }  =  i1 >  i2
       IntLit { ilValue = i1 } `compare` IntLit { ilValue = i2 }  =  i1 `compare` i2
  
  instance Show IntLit where
       showsPrec _ (IntLit { ilValue = i, ilWidth = mw, ilBase = b }) s =
           -- width of 0 means don't pad with leading zeros
           integerFormatPref 0 b i ++ s
  
  instance PPrint IntLit where
       pPrint d p i = text (show i)
  
  instance Hyper IntLit where
       hyper (IntLit x1 x2 x3) y = hyper3 x1 x2 x3 y
  
  -- --------------------
  
  instance PVPrint IntLit where
       pvPrint d p (IntLit { ilValue = i, ilWidth = w, ilBase = b }) =
           text $ intFormat w b i
  
  intFormat :: Maybe Integer -> Integer -> Integer -> String
  intFormat mwidth base value | value < 0 = '-' : intFormat mwidth base (-value)
  intFormat mwidth  2 value = sizeFormat mwidth ++ "'b" ++ digitsFormat  2 value
  intFormat mwidth  8 value = sizeFormat mwidth ++ "'o" ++ digitsFormat  8 value
  intFormat mwidth 16 value = sizeFormat mwidth ++ "'h" ++ digitsFormat 16 value
  intFormat Nothing 10 value = digitsFormat 10 value
  intFormat mwidth 10 value = sizeFormat mwidth ++ "'d" ++ digitsFormat 10 value
  intFormat mwidth base value =
      internalError ("bad radix to intFormat: " ++ show base)
  
  sizeFormat :: Maybe Integer -> String
  sizeFormat Nothing = ""
  sizeFormat (Just width) = integerToString 10 width
  
  digitsFormat :: Integer -> Integer -> String
  digitsFormat base value = integerToString (fromInteger base) value
  
  -- --------------------
  
  showSizedVeriIntLit :: Integer -> IntLit -> String
  showSizedVeriIntLit sz (IntLit { ilValue = i, ilBase = b }) =
      -- XXX we could check whether the value has a width
      -- XXX and error if it doesn't match the given width
      intFormat (Just sz) b i
  
  showVeriIntLit :: IntLit -> String
  showVeriIntLit (IntLit { ilValue = i, ilWidth = w, ilBase = b }) =
      intFormat w b i
  
  -- --------------------
  