// selfhost/cmd/wcc/type.ww — port of cmd/wcc/type.c. // // Status: full structural port. The C version uses module-globals for // the primitive types (tyvoid, tyi32, …); ww doesn't have writable // global storage yet, so we bundle the primitives into a `tctx` that // the checker passes around explicitly. typesinit fills the tctx // once per arena. use os; use mem; // ---- TypeKind --------------------------------------------------------- // Numeric values must stay aligned with cmd/wcc/ww.h TypeKind so the // next diff signal (typed-AST printer / cgen) can compare across the // two implementations. def TY_NONE: i32 = 0; def TY_VOID: i32 = 1; def TY_BOOL: i32 = 2; def TY_RUNE: i32 = 3; def TY_I8: i32 = 4; def TY_I16: i32 = 5; def TY_I32: i32 = 6; def TY_I64: i32 = 7; def TY_U8: i32 = 8; def TY_U16: i32 = 9; def TY_U32: i32 = 10; def TY_U64: i32 = 11; def TY_UINT: i32 = 12; def TY_INT: i32 = 13; def TY_UINTPTR: i32 = 14; def TY_F32: i32 = 15; def TY_F64: i32 = 16; def TY_STR: i32 = 17; def TY_PTR: i32 = 18; def TY_SLICE: i32 = 19; def TY_ARRAY: i32 = 20; def TY_STRUCT: i32 = 21; def TY_FN: i32 = 22; def TY_CHAN: i32 = 23; def TY_NAMED: i32 = 24; def TY_TUPLE: i32 = 25; def TY_TAGGED: i32 = 26; def TY_ERR: i32 = 27; def TY_UNTYPED_INT: i32 = 28; def TY_UNTYPED_FLOAT: i32 = 29; def TY_UNTYPED_STR: i32 = 30; def TY_UNTYPED_RUNE: i32 = 31; def TY_UNTYPED_BOOL: i32 = 32; def TY_UNTYPED_NIL: i32 = 33; // ---- tinfo / tfield / tparam ----------------------------------------- type tfield = struct { name: str, type_: *tinfo, offset: u64, tnext: *tfield, }; type tparam = struct { name: str, type_: *tinfo, tnext: *tparam, }; type tinfo = struct { kind: i32, size: u64, align: u64, sub: *tinfo, // ptr/slice/array/chan element alen: u64, fields: *tfield, params: *tparam, ret: *tinfo, variadic: i32, name: str, under: *tinfo, }; // ---- tctx — the box of primitive types ------------------------------- type tctx = struct { a: *arena, tyvoid: *tinfo, tybool: *tinfo, tyrune: *tinfo, tyi8: *tinfo, tyi16: *tinfo, tyi32: *tinfo, tyi64: *tinfo, tyu8: *tinfo, tyu16: *tinfo, tyu32: *tinfo, tyu64: *tinfo, tyint: *tinfo, tyuint: *tinfo, tyuintptr: *tinfo, tyf32: *tinfo, tyf64: *tinfo, tystr: *tinfo, tyerr: *tinfo, tyuntypedint: *tinfo, tyuntypedfloat: *tinfo, tyuntypedstr: *tinfo, tyuntypedrune: *tinfo, tyuntypedbool: *tinfo, tyuntypednil: *tinfo, }; // ---- constructors ----------------------------------------------------- export fn newtype(a: *arena, k: i32) *tinfo = { let t: *tinfo = amalloc(a, 96u64): *tinfo; t.kind = k; return t; }; fn prim(a: *arena, k: i32, nm: str, sz: u64, al: u64) *tinfo = { let t: *tinfo = newtype(a, k); t.name = nm; t.size = sz; if (al > 0u64) { t.align = al; } else { t.align = sz; }; return t; }; export fn typesinit(c: *tctx, a: *arena) void = { c.a = a; c.tyvoid = prim(a, TY_VOID, "void", 0u64, 1u64); c.tybool = prim(a, TY_BOOL, "bool", 1u64, 1u64); c.tyrune = prim(a, TY_RUNE, "rune", 4u64, 4u64); c.tyi8 = prim(a, TY_I8, "i8", 1u64, 1u64); c.tyi16 = prim(a, TY_I16, "i16", 2u64, 2u64); c.tyi32 = prim(a, TY_I32, "i32", 4u64, 4u64); c.tyi64 = prim(a, TY_I64, "i64", 8u64, 8u64); c.tyu8 = prim(a, TY_U8, "u8", 1u64, 1u64); c.tyu16 = prim(a, TY_U16, "u16", 2u64, 2u64); c.tyu32 = prim(a, TY_U32, "u32", 4u64, 4u64); c.tyu64 = prim(a, TY_U64, "u64", 8u64, 8u64); c.tyint = prim(a, TY_INT, "int", 8u64, 8u64); c.tyuint = prim(a, TY_UINT, "uint", 8u64, 8u64); c.tyuintptr= prim(a, TY_UINTPTR, "uintptr", 8u64, 8u64); c.tyf32 = prim(a, TY_F32, "f32", 4u64, 4u64); c.tyf64 = prim(a, TY_F64, "f64", 8u64, 8u64); c.tystr = prim(a, TY_STR, "str", 16u64, 8u64); c.tyerr = prim(a, TY_ERR, "", 0u64, 1u64); c.tyuntypedint = prim(a, TY_UNTYPED_INT, "untyped_int", 0u64, 1u64); c.tyuntypedfloat = prim(a, TY_UNTYPED_FLOAT, "untyped_float", 0u64, 1u64); c.tyuntypedstr = prim(a, TY_UNTYPED_STR, "untyped_str", 0u64, 1u64); c.tyuntypedrune = prim(a, TY_UNTYPED_RUNE, "untyped_rune", 0u64, 1u64); c.tyuntypedbool = prim(a, TY_UNTYPED_BOOL, "untyped_bool", 0u64, 1u64); c.tyuntypednil = prim(a, TY_UNTYPED_NIL, "untyped_nil", 0u64, 1u64); }; export fn typeptr(a: *arena, sub: *tinfo) *tinfo = { let t: *tinfo = newtype(a, TY_PTR); t.sub = sub; t.size = 8u64; t.align = 8u64; return t; }; export fn typeslice(a: *arena, sub: *tinfo) *tinfo = { let t: *tinfo = newtype(a, TY_SLICE); t.sub = sub; t.size = 24u64; t.align = 8u64; return t; }; export fn typearray(a: *arena, sub: *tinfo, n: u64) *tinfo = { let t: *tinfo = newtype(a, TY_ARRAY); t.sub = sub; t.alen = n; if (sub != nil) { t.size = sub.size * n; t.align = sub.align; } else { t.align = 1u64; }; return t; }; export fn typechan(a: *arena, sub: *tinfo) *tinfo = { let t: *tinfo = newtype(a, TY_CHAN); t.sub = sub; t.size = 8u64; t.align = 8u64; return t; }; export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = { let t: *tinfo = newtype(a, TY_NAMED); t.name = name; t.under = under; if (under != nil) { t.size = under.size; t.align = under.align; }; return t; }; // ---- predicates ------------------------------------------------------- export fn typeisint(t: *tinfo) bool = { if (t == nil) { return false; }; let k: i32 = t.kind; if (k == TY_I8) { return true; }; if (k == TY_I16) { return true; }; if (k == TY_I32) { return true; }; if (k == TY_I64) { return true; }; if (k == TY_U8) { return true; }; if (k == TY_U16) { return true; }; if (k == TY_U32) { return true; }; if (k == TY_U64) { return true; }; if (k == TY_INT) { return true; }; if (k == TY_UINT){ return true; }; if (k == TY_UINTPTR) { return true; }; if (k == TY_RUNE){ return true; }; if (k == TY_UNTYPED_INT) { return true; }; if (k == TY_UNTYPED_RUNE) { return true; }; if (k == TY_NAMED) { return typeisint(t.under); }; return false; }; export fn typeisfloat(t: *tinfo) bool = { if (t == nil) { return false; }; let k: i32 = t.kind; if (k == TY_F32) { return true; }; if (k == TY_F64) { return true; }; if (k == TY_UNTYPED_FLOAT) { return true; }; if (k == TY_NAMED) { return typeisfloat(t.under); }; return false; }; export fn typeisnum(t: *tinfo) bool = { if (typeisint(t)) { return true; }; return typeisfloat(t); }; export fn typeisunsigned(t: *tinfo) bool = { if (t == nil) { return false; }; let k: i32 = t.kind; if (k == TY_U8) { return true; }; if (k == TY_U16) { return true; }; if (k == TY_U32) { return true; }; if (k == TY_U64) { return true; }; if (k == TY_UINT){ return true; }; if (k == TY_UINTPTR) { return true; }; if (k == TY_NAMED) { return typeisunsigned(t.under); }; return false; }; export fn typeisuntyped(t: *tinfo) bool = { if (t == nil) { return false; }; let k: i32 = t.kind; if (k == TY_UNTYPED_INT) { return true; }; if (k == TY_UNTYPED_FLOAT) { return true; }; if (k == TY_UNTYPED_STR) { return true; }; if (k == TY_UNTYPED_RUNE) { return true; }; if (k == TY_UNTYPED_BOOL) { return true; }; if (k == TY_UNTYPED_NIL) { return true; }; return false; }; // typeeq — structural equality. Named types compare nominally. export fn typeeq(a: *tinfo, b: *tinfo) bool = { if (a == b) { return true; }; if (a == nil) { return false; }; if (b == nil) { return false; }; if (a.kind != b.kind) { return false; }; let k: i32 = a.kind; if (k == TY_PTR) { return typeeq(a.sub, b.sub); }; if (k == TY_SLICE) { return typeeq(a.sub, b.sub); }; if (k == TY_CHAN) { return typeeq(a.sub, b.sub); }; if (k == TY_ARRAY) { if (a.alen != b.alen) { return false; }; return typeeq(a.sub, b.sub); }; if (k == TY_FN) { if (a.variadic != b.variadic) { return false; }; if (!typeeq(a.ret, b.ret)) { return false; }; let pa: *tparam = a.params; let pb: *tparam = b.params; for (true) { if (pa == nil) { if (pb == nil) { return true; }; return false; }; if (pb == nil) { return false; }; if (!typeeq(pa.type_, pb.type_)) { return false; }; pa = pa.tnext; pb = pb.tnext; }; return true; }; if (k == TY_STRUCT) { let fa: *tfield = a.fields; let fb: *tfield = b.fields; for (true) { if (fa == nil) { if (fb == nil) { return true; }; return false; }; if (fb == nil) { return false; }; let na: str = fa.name; let nb: str = fb.name; if (na.len != nb.len) { return false; }; let i: i32 = 0; for (i < na.len) { if (na[i] != nb[i]) { return false; }; i += 1; }; if (!typeeq(fa.type_, fb.type_)) { return false; }; fa = fa.tnext; fb = fb.tnext; }; return true; }; if (k == TY_NAMED) { return false; }; // nominal: only same ptr if (k == TY_TUPLE) { let pa: *tparam = a.params; let pb: *tparam = b.params; for (true) { if (pa == nil) { if (pb == nil) { return true; }; return false; }; if (pb == nil) { return false; }; if (!typeeq(pa.type_, pb.type_)) { return false; }; pa = pa.tnext; pb = pb.tnext; }; return true; }; return true; // primitives match by kind alone };