// 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 (ty_void, ty_i32, …); 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, ty_void: *tinfo, ty_bool: *tinfo, ty_rune: *tinfo, ty_i8: *tinfo, ty_i16: *tinfo, ty_i32: *tinfo, ty_i64: *tinfo, ty_u8: *tinfo, ty_u16: *tinfo, ty_u32: *tinfo, ty_u64: *tinfo, ty_int: *tinfo, ty_uint: *tinfo, ty_uintptr: *tinfo, ty_f32: *tinfo, ty_f64: *tinfo, ty_str: *tinfo, ty_err: *tinfo, ty_untyped_int: *tinfo, ty_untyped_float: *tinfo, ty_untyped_str: *tinfo, ty_untyped_rune: *tinfo, ty_untyped_bool: *tinfo, ty_untyped_nil: *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.ty_void = prim(a, TY_VOID, "void", 0u64, 1u64); c.ty_bool = prim(a, TY_BOOL, "bool", 1u64, 1u64); c.ty_rune = prim(a, TY_RUNE, "rune", 4u64, 4u64); c.ty_i8 = prim(a, TY_I8, "i8", 1u64, 1u64); c.ty_i16 = prim(a, TY_I16, "i16", 2u64, 2u64); c.ty_i32 = prim(a, TY_I32, "i32", 4u64, 4u64); c.ty_i64 = prim(a, TY_I64, "i64", 8u64, 8u64); c.ty_u8 = prim(a, TY_U8, "u8", 1u64, 1u64); c.ty_u16 = prim(a, TY_U16, "u16", 2u64, 2u64); c.ty_u32 = prim(a, TY_U32, "u32", 4u64, 4u64); c.ty_u64 = prim(a, TY_U64, "u64", 8u64, 8u64); c.ty_int = prim(a, TY_INT, "int", 8u64, 8u64); c.ty_uint = prim(a, TY_UINT, "uint", 8u64, 8u64); c.ty_uintptr= prim(a, TY_UINTPTR, "uintptr", 8u64, 8u64); c.ty_f32 = prim(a, TY_F32, "f32", 4u64, 4u64); c.ty_f64 = prim(a, TY_F64, "f64", 8u64, 8u64); c.ty_str = prim(a, TY_STR, "str", 16u64, 8u64); c.ty_err = prim(a, TY_ERR, "", 0u64, 1u64); c.ty_untyped_int = prim(a, TY_UNTYPED_INT, "untyped_int", 0u64, 1u64); c.ty_untyped_float = prim(a, TY_UNTYPED_FLOAT, "untyped_float", 0u64, 1u64); c.ty_untyped_str = prim(a, TY_UNTYPED_STR, "untyped_str", 0u64, 1u64); c.ty_untyped_rune = prim(a, TY_UNTYPED_RUNE, "untyped_rune", 0u64, 1u64); c.ty_untyped_bool = prim(a, TY_UNTYPED_BOOL, "untyped_bool", 0u64, 1u64); c.ty_untyped_nil = prim(a, TY_UNTYPED_NIL, "untyped_nil", 0u64, 1u64); }; export fn type_ptr(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 type_slice(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 type_array(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 type_chan(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 type_named(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 type_isint(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 type_isint(t.under); }; return false; }; export fn type_isfloat(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 type_isfloat(t.under); }; return false; }; export fn type_isnum(t: *tinfo) bool = { if (type_isint(t)) { return true; }; return type_isfloat(t); }; export fn type_isunsigned(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 type_isunsigned(t.under); }; return false; }; export fn type_isuntyped(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; }; // type_eq — structural equality. Named types compare nominally. export fn type_eq(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 type_eq(a.sub, b.sub); }; if (k == TY_SLICE) { return type_eq(a.sub, b.sub); }; if (k == TY_CHAN) { return type_eq(a.sub, b.sub); }; if (k == TY_ARRAY) { if (a.alen != b.alen) { return false; }; return type_eq(a.sub, b.sub); }; if (k == TY_FN) { if (a.variadic != b.variadic) { return false; }; if (!type_eq(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 (!type_eq(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 (!type_eq(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 (!type_eq(pa.type_, pb.type_)) { return false; }; pa = pa.tnext; pb = pb.tnext; }; return true; }; return true; // primitives match by kind alone };