    {-# 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