{-# LANGUAGE GADTs #-}

-- | Translate Copilot Core expressions and operators to C99.
module Copilot.Compile.C99.Type
    ( transType
    , transLocalVarDeclType
    , transTypeName
    )
  where

-- External imports
import qualified Language.C99.Simple as C

-- Internal imports: Copilot
import Copilot.Core ( Type (..), typeLength, typeName )

-- | Translate a Copilot type to a C99 type.
transType :: Type a -> C.Type
transType :: forall a. Type a -> Type
transType Type a
ty = case Type a
ty of
  Type a
Bool      -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"bool"
  Type a
Int8      -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"int8_t"
  Type a
Int16     -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"int16_t"
  Type a
Int32     -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"int32_t"
  Type a
Int64     -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"int64_t"
  Type a
Word8     -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"uint8_t"
  Type a
Word16    -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"uint16_t"
  Type a
Word32    -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"uint32_t"
  Type a
Word64    -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"uint64_t"
  Type a
Float     -> TypeSpec -> Type
C.TypeSpec TypeSpec
C.Float
  Type a
Double    -> TypeSpec -> Type
C.TypeSpec TypeSpec
C.Double
  Array Type t
ty' -> Type -> Maybe Expr -> Type
C.Array (Type t -> Type
forall a. Type a -> Type
transType Type t
ty') Maybe Expr
len
    where
      len :: Maybe Expr
len = Expr -> Maybe Expr
forall a. a -> Maybe a
Just (Expr -> Maybe Expr) -> Expr -> Maybe Expr
forall a b. (a -> b) -> a -> b
$ Integer -> Expr
C.LitInt (Integer -> Expr) -> Integer -> Expr
forall a b. (a -> b) -> a -> b
$ Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Integer) -> Int -> Integer
forall a b. (a -> b) -> a -> b
$ Type (Array n t) -> Int
forall (n :: Nat) t. KnownNat n => Type (Array n t) -> Int
typeLength Type a
Type (Array n t)
ty
  Struct a
s  -> TypeSpec -> Type
C.TypeSpec (TypeSpec -> Type) -> TypeSpec -> Type
forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.Struct (a -> Ident
forall a. Struct a => a -> Ident
typeName a
s)

-- | Translate a Copilot type to a valid (local) variable declaration C99 type.
--
-- If the type denotes an array, translate it to a pointer to whatever the
-- array holds. This special case is needed when the type is used for a local
-- variable declaration. We treat global variables differently (we generate
-- list initializers).
transLocalVarDeclType :: Type a -> C.Type
transLocalVarDeclType :: forall a. Type a -> Type
transLocalVarDeclType (Array Type t
ty') = Type -> Type
C.Ptr (Type -> Type) -> Type -> Type
forall a b. (a -> b) -> a -> b
$ Type t -> Type
forall a. Type a -> Type
transType Type t
ty'
transLocalVarDeclType Type a
ty          = Type a -> Type
forall a. Type a -> Type
transType Type a
ty

-- | Translate a Copilot type intro a C typename
transTypeName :: Type a -> C.TypeName
transTypeName :: forall a. Type a -> TypeName
transTypeName Type a
ty = Type -> TypeName
C.TypeName (Type -> TypeName) -> Type -> TypeName
forall a b. (a -> b) -> a -> b
$ Type a -> Type
forall a. Type a -> Type
transType Type a
ty