// types.bux — Type system definitions and factories
module Types {

// ---------------------------------------------------------------------------
// TypeKind constants
// ---------------------------------------------------------------------------

const tyUnknown: int = 0;
const tyVoid: int = 1;
const tyBool: int = 2;
const tyBool8: int = 3;
const tyBool16: int = 4;
const tyBool32: int = 5;
const tyChar8: int = 6;
const tyChar16: int = 7;
const tyChar32: int = 8;
const tyStr: int = 9;
const tyInt8: int = 10;
const tyInt16: int = 11;
const tyInt32: int = 12;
const tyInt64: int = 13;
const tyInt: int = 14;
const tyUInt8: int = 15;
const tyUInt16: int = 16;
const tyUInt32: int = 17;
const tyUInt64: int = 18;
const tyUInt: int = 19;
const tyFloat32: int = 20;
const tyFloat64: int = 21;
const tyPointer: int = 22;
const tySlice: int = 23;
const tyRange: int = 24;
const tyTuple: int = 25;
const tyNamed: int = 26;
const tyTypeParam: int = 27;
const tyFunc: int = 28;

// ---------------------------------------------------------------------------
// Type struct
// ---------------------------------------------------------------------------

struct Type {
    kind: int;
    name: String;
    // inner types stored as array of pointers (simplified)
    innerKind1: int;
    innerName1: String;
    innerKind2: int;
    innerName2: String;
    innerKind3: int;
    innerName3: String;
    innerCount: int;
}

// ---------------------------------------------------------------------------
// Factories
// ---------------------------------------------------------------------------

func Type_MakeUnknown() -> Type {
    return Type { kind: tyUnknown, name: "", innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

func Type_MakeVoid() -> Type {
    return Type { kind: tyVoid, name: "void", innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

func Type_MakeBool() -> Type {
    return Type { kind: tyBool, name: "bool", innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

func Type_MakeInt() -> Type {
    return Type { kind: tyInt, name: "int", innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

func Type_MakeInt64() -> Type {
    return Type { kind: tyInt64, name: "int64", innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

func Type_MakeUInt() -> Type {
    return Type { kind: tyUInt, name: "uint", innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

func Type_MakeFloat64() -> Type {
    return Type { kind: tyFloat64, name: "float64", innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

func Type_MakeStr() -> Type {
    return Type { kind: tyStr, name: "String", innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

func Type_MakePointer(pointee: Type) -> Type {
    return Type { kind: tyPointer, name: "", innerCount: 1,
        innerKind1: pointee.kind, innerName1: pointee.name,
        innerKind2: 0, innerName2: "", innerKind3: 0, innerName3: "" };
}

func Type_MakeNamed(name: String) -> Type {
    return Type { kind: tyNamed, name: name, innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

func Type_MakeTypeParam(name: String) -> Type {
    return Type { kind: tyTypeParam, name: name, innerCount: 0,
        innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
        innerKind3: 0, innerName3: "" };
}

// ---------------------------------------------------------------------------
// Predicates
// ---------------------------------------------------------------------------

func Type_IsNumeric(t: Type) -> bool {
    let k: int = t.kind;
    if k == tyInt8 || k == tyInt16 || k == tyInt32 || k == tyInt64 || k == tyInt { return true; }
    if k == tyUInt8 || k == tyUInt16 || k == tyUInt32 || k == tyUInt64 || k == tyUInt { return true; }
    if k == tyFloat32 || k == tyFloat64 { return true; }
    if k == tyUnknown || k == tyNamed || k == tyTypeParam { return true; }
    return false;
}

func Type_IsInteger(t: Type) -> bool {
    let k: int = t.kind;
    if k == tyInt8 || k == tyInt16 || k == tyInt32 || k == tyInt64 || k == tyInt { return true; }
    if k == tyUInt8 || k == tyUInt16 || k == tyUInt32 || k == tyUInt64 || k == tyUInt { return true; }
    if k == tyUnknown || k == tyNamed || k == tyTypeParam { return true; }
    return false;
}

func Type_IsBool(t: Type) -> bool {
    let k: int = t.kind;
    return k == tyBool || k == tyBool8 || k == tyBool16 || k == tyBool32;
}

func Type_IsPointer(t: Type) -> bool {
    return t.kind == tyPointer;
}

func Type_IsSlice(t: Type) -> bool {
    return t.kind == tySlice;
}

// ---------------------------------------------------------------------------
// Comparison (structural, limited to kind + name for simplicity)
// ---------------------------------------------------------------------------

func Type_Eq(a: Type, b: Type) -> bool {
    if a.kind != b.kind { return false; }
    if a.kind == tyNamed || a.kind == tyTypeParam {
        return String_Eq(a.name, b.name);
    }
    return true;
}

// ---------------------------------------------------------------------------
// toString
// ---------------------------------------------------------------------------

func Type_ToString(t: Type) -> String {
    if t.kind == tyVoid { return "void"; }
    if t.kind == tyBool { return "bool"; }
    if t.kind == tyStr { return "String"; }
    if t.kind == tyInt { return "int"; }
    if t.kind == tyInt64 { return "int64"; }
    if t.kind == tyUInt { return "uint"; }
    if t.kind == tyFloat64 { return "float64"; }
    if t.kind == tyNamed { return t.name; }
    if t.kind == tyTypeParam { return t.name; }
    if t.kind == tyPointer { return String_Concat("*", t.innerName1); }
    if t.kind == tyFunc { return t.name; }
    return "?";
}
}
