{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Data.SBV.Core.Kind (Kind(..), HasKind(..), constructUKind) where
import qualified Data.Generics as G (Data(..), DataType, dataTypeName, dataTypeOf, tyconUQname, dataTypeConstrs, constrFields)
import Data.Int
import Data.Word
import Data.SBV.Core.AlgReals
data Kind = KBool
| KBounded !Bool !Int
| KUnbounded
| KReal
| KUserSort String (Either String [String])
| KFloat
| KDouble
kindRank :: Kind -> Either Int (Either (Bool, Int) String)
kindRank KBool = Left 0
kindRank (KBounded b i) = Right (Left (b, i))
kindRank KUnbounded = Left 1
kindRank KReal = Left 2
kindRank (KUserSort s _) = Right (Right s)
kindRank KFloat = Left 3
kindRank KDouble = Left 4
{-# INLINE kindRank #-}
instance Eq Kind where
k1 == k2 = kindRank k1 == kindRank k2
instance Ord Kind where
k1 `compare` k2 = kindRank k1 `compare` kindRank k2
instance Show Kind where
show KBool = "SBool"
show (KBounded False n) = "SWord" ++ show n
show (KBounded True n) = "SInt" ++ show n
show KUnbounded = "SInteger"
show KReal = "SReal"
show (KUserSort s _) = s
show KFloat = "SFloat"
show KDouble = "SDouble"
instance Eq G.DataType where
a == b = G.tyconUQname (G.dataTypeName a) == G.tyconUQname (G.dataTypeName b)
instance Ord G.DataType where
a `compare` b = G.tyconUQname (G.dataTypeName a) `compare` G.tyconUQname (G.dataTypeName b)
kindHasSign :: Kind -> Bool
kindHasSign k =
case k of
KBool -> False
KBounded b _ -> b
KUnbounded -> True
KReal -> True
KFloat -> True
KDouble -> True
KUserSort{} -> False
constructUKind :: forall a. (Read a, G.Data a) => a -> Kind
constructUKind a = KUserSort sortName mbEnumFields
where dataType = G.dataTypeOf a
sortName = G.tyconUQname . G.dataTypeName $ dataType
constrs = G.dataTypeConstrs dataType
isEnumeration = not (null constrs) && all (null . G.constrFields) constrs
mbEnumFields
| isEnumeration = check constrs []
| True = Left $ sortName ++ "is not a finite non-empty enumeration"
check [] sofar = Right $ reverse sofar
check (c:cs) sofar = case checkConstr c of
Nothing -> check cs (show c : sofar)
Just s -> Left $ sortName ++ "." ++ show c ++ ": " ++ s
checkConstr c = case (reads (show c) :: [(a, String)]) of
((_, "") : _) -> Nothing
_ -> Just "not a nullary constructor"
class HasKind a where
kindOf :: a -> Kind
hasSign :: a -> Bool
intSizeOf :: a -> Int
isBoolean :: a -> Bool
isBounded :: a -> Bool
isReal :: a -> Bool
isFloat :: a -> Bool
isDouble :: a -> Bool
isInteger :: a -> Bool
isUninterpreted :: a -> Bool
showType :: a -> String
hasSign x = kindHasSign (kindOf x)
intSizeOf x = case kindOf x of
KBool -> error "SBV.HasKind.intSizeOf((S)Bool)"
KBounded _ s -> s
KUnbounded -> error "SBV.HasKind.intSizeOf((S)Integer)"
KReal -> error "SBV.HasKind.intSizeOf((S)Real)"
KFloat -> error "SBV.HasKind.intSizeOf((S)Float)"
KDouble -> error "SBV.HasKind.intSizeOf((S)Double)"
KUserSort s _ -> error $ "SBV.HasKind.intSizeOf: Uninterpreted sort: " ++ s
isBoolean x | KBool{} <- kindOf x = True
| True = False
isBounded x | KBounded{} <- kindOf x = True
| True = False
isReal x | KReal{} <- kindOf x = True
| True = False
isFloat x | KFloat{} <- kindOf x = True
| True = False
isDouble x | KDouble{} <- kindOf x = True
| True = False
isInteger x | KUnbounded{} <- kindOf x = True
| True = False
isUninterpreted x | KUserSort{} <- kindOf x = True
| True = False
showType = show . kindOf
default kindOf :: (Read a, G.Data a) => a -> Kind
kindOf = constructUKind
instance HasKind Bool where kindOf _ = KBool
instance HasKind Int8 where kindOf _ = KBounded True 8
instance HasKind Word8 where kindOf _ = KBounded False 8
instance HasKind Int16 where kindOf _ = KBounded True 16
instance HasKind Word16 where kindOf _ = KBounded False 16
instance HasKind Int32 where kindOf _ = KBounded True 32
instance HasKind Word32 where kindOf _ = KBounded False 32
instance HasKind Int64 where kindOf _ = KBounded True 64
instance HasKind Word64 where kindOf _ = KBounded False 64
instance HasKind Integer where kindOf _ = KUnbounded
instance HasKind AlgReal where kindOf _ = KReal
instance HasKind Float where kindOf _ = KFloat
instance HasKind Double where kindOf _ = KDouble
instance HasKind Kind where
kindOf = id