{-# 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 forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"bool"
  Type a
Int8      -> TypeSpec -> Type
C.TypeSpec forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"int8_t"
  Type a
Int16     -> TypeSpec -> Type
C.TypeSpec forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"int16_t"
  Type a
Int32     -> TypeSpec -> Type
C.TypeSpec forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"int32_t"
  Type a
Int64     -> TypeSpec -> Type
C.TypeSpec forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"int64_t"
  Type a
Word8     -> TypeSpec -> Type
C.TypeSpec forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"uint8_t"
  Type a
Word16    -> TypeSpec -> Type
C.TypeSpec forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"uint16_t"
  Type a
Word32    -> TypeSpec -> Type
C.TypeSpec forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.TypedefName Ident
"uint32_t"
  Type a
Word64    -> TypeSpec -> Type
C.TypeSpec 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 (forall a. Type a -> Type
transType Type t
ty') Maybe Expr
len
    where
      len :: Maybe Expr
len = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Integer -> Expr
C.LitInt forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) t. KnownNat n => Type (Array n t) -> Int
typeLength Type a
ty
  Struct a
s  -> TypeSpec -> Type
C.TypeSpec forall a b. (a -> b) -> a -> b
$ Ident -> TypeSpec
C.Struct (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 forall a b. (a -> b) -> a -> b
$ forall a. Type a -> Type
transType Type t
ty'
transLocalVarDeclType Type a
ty          = 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 forall a b. (a -> b) -> a -> b
$ forall a. Type a -> Type
transType Type a
ty