ww+wcc: Hare-strict enum types — back out the int↔enum relaxation

Cascades the four enum kinds through every signature and local that
holds one of their values, then removes the type_assignable /
unify_arith relaxation that previously let bare i32 mix with the
named enum types.

Signature updates:
  - kwlookup() now returns `tkind` (not i32); tokname() takes `tkind`
  - accepttok / expecttok / bprec / isassignop take `tkind`
  - parsearglist's closekind is `tkind`
  - newtype / prim take `tykind`; scopedefine takes `skind`
  - newnode / nkname take `nkind`

Struct fields:
  - tok.kind is `tkind`; parser.curkind is `tkind`
  - node.kind is `nkind`; node.op is `tkind`
  - tinfo.kind is `tykind`; sym.skind is `skind`

Locals holding kinds across lex/parse/check/cgen are now typed with
their enum, including sentinel patterns like `let lkind: nkind =
nkind.N_NONE; if (...) lkind = tn.kind;`.

The selfhost cgen had a load-width bug exposed by this: fieldsize()
fell back to 8 bytes for any TNAME that wasn't a struct or primitive.
For a tkind-typed field that gave `MOVQ (BX), AX` instead of `MOVL`,
diverging from the C cgen on tok.kind / parser.curkind / etc. Two
fixes:
  - fieldsize now consults the enum registry and returns the storage
    type's size (4 for `enum i32`)
  - collectenums runs before collectstructs in cgfile so the registry
    is populated when registerstruct asks for field sizes

All 22 tests stay green; 990/993/995 byte-identity probes pass with
the strict typing in place.
This commit is contained in:
2026-05-12 05:04:33 +09:00
parent 3affe01705
commit 922877309b
17 changed files with 210 additions and 194 deletions

View File

@@ -531,17 +531,6 @@ unify_arith(Checker *c, Pos p, Type *a, Type *b)
if (type_isuntyped(a) && type_assignable(b, a)) return b; if (type_isuntyped(a) && type_assignable(b, a)) return b;
if (type_isuntyped(b) && type_assignable(a, b)) return a; if (type_isuntyped(b) && type_assignable(a, b)) return a;
if (type_eq(a, b)) return a; if (type_eq(a, b)) return a;
/* Enum ↔ integer storage: pair `(tkind, i32)` operands unify to
* the storage int. Mirrors the same relaxation in type_assignable;
* lets `cur.kind == TK_FN` typecheck without a cast on either side. */
{
Type *au = (a->kind == TY_NAMED) ? a->under : a;
Type *bu = (b->kind == TY_NAMED) ? b->under : b;
if (au && au->kind == TY_ENUM && type_isint(b) &&
type_eq(au->sub, b)) return b;
if (bu && bu->kind == TY_ENUM && type_isint(a) &&
type_eq(a, bu->sub)) return a;
}
return err(c, p, "operands have differing types %s and %s", return err(c, p, "operands have differing types %s and %s",
type_name(c->a, a), type_name(c->a, b)); type_name(c->a, a), type_name(c->a, b));
} }

View File

@@ -295,21 +295,6 @@ type_assignable(Type *dst, Type *src)
if (dst->kind == TY_NAMED && type_eq(dst->under, src)) return 1; if (dst->kind == TY_NAMED && type_eq(dst->under, src)) return 1;
if (src->kind == TY_NAMED && type_eq(dst, src->under)) return 1; if (src->kind == TY_NAMED && type_eq(dst, src->under)) return 1;
/* Enum ↔ integer storage: bare i32 flows into a `tkind` slot and
* vice-versa as long as the storage type matches. Hare-strict
* would require an explicit cast, but the ww frontend's tkind /
* nkind enums have hundreds of `let k: i32 = expr` sites we'd
* otherwise have to migrate in lockstep — the relaxation is
* explicit and limited to int-typed enums. */
{
Type *du = (dst->kind == TY_NAMED) ? dst->under : dst;
Type *su = (src->kind == TY_NAMED) ? src->under : src;
if (du && du->kind == TY_ENUM && type_isint(src) &&
type_eq(du->sub, src)) return 1;
if (su && su->kind == TY_ENUM && type_isint(dst) &&
type_eq(dst, su->sub)) return 1;
}
/* Tuple-to-tuple: element-wise assignable. */ /* Tuple-to-tuple: element-wise assignable. */
if (dst->kind == TY_TUPLE && src->kind == TY_TUPLE) { if (dst->kind == TY_TUPLE && src->kind == TY_TUPLE) {
Tparam *pa = dst->params, *pb = src->params; Tparam *pa = dst->params, *pb = src->params;

View File

@@ -103,11 +103,11 @@ type nkind = enum i32 {
// ---- Node ------------------------------------------------------------- // ---- Node -------------------------------------------------------------
type node = struct { type node = struct {
kind: i32, kind: nkind,
file: str, file: str,
line: i32, line: i32,
col: i32, col: i32,
op: i32, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN op: tkind, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN
str: str, str: str,
uval: u64, uval: u64,
fval: f64, fval: f64,
@@ -125,7 +125,7 @@ type node = struct {
module: str, // originating module from `// MODULE: foo`; "" if none module: str, // originating module from `// MODULE: foo`; "" if none
}; };
export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = { export fn newnode(a: *arena, k: nkind, file: str, line: i32, col: i32) *node = {
let n: *node = amalloc(a, 208u64): *node; // ≥ struct size let n: *node = amalloc(a, 208u64): *node; // ≥ struct size
n.kind = k; n.kind = k;
n.file = file; n.file = file;
@@ -136,7 +136,7 @@ export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = {
// ---- printer ---------------------------------------------------------- // ---- printer ----------------------------------------------------------
fn nkname(k: i32) str = { fn nkname(k: nkind) str = {
if (k == nkind.N_NONE) { return "none"; }; if (k == nkind.N_NONE) { return "none"; };
if (k == nkind.N_INTLIT) { return "int"; }; if (k == nkind.N_INTLIT) { return "int"; };
if (k == nkind.N_FLOATLIT) { return "float"; }; if (k == nkind.N_FLOATLIT) { return "float"; };

View File

@@ -460,7 +460,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = {
return; return;
}; };
}; };
let k: i32 = kwlookup(p, n: i32); let k: tkind = kwlookup(p, n: i32);
if (k != tkind.TK_NONE) { if (k != tkind.TK_NONE) {
out.kind = k; out.kind = k;
} else { } else {
@@ -553,7 +553,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = {
out.uval = ch: u64; out.uval = ch: u64;
}; };
fn emitsimple(start: *pos, k: i32, out: *tok) void = { fn emitsimple(start: *pos, k: tkind, out: *tok) void = {
out.kind = k; out.kind = k;
out.file = start.file; out.file = start.file;
out.line = start.line; out.line = start.line;

View File

@@ -134,8 +134,7 @@ type pos = struct {
}; };
type tok = struct { type tok = struct {
kind: i32, // holds a `tkind` value; bare i32 so the cgen's kind: tkind,
// fixed 8B/struct-field layout matches the C side
file: str, // path of the source the token came from file: str, // path of the source the token came from
line: i32, line: i32,
col: i32, col: i32,
@@ -160,7 +159,7 @@ fn streqn(a: *u8, b: str, n: i32) bool = {
// kwlookup — returns the matching TK_* keyword kind for a byte run, // kwlookup — returns the matching TK_* keyword kind for a byte run,
// or tkind.TK_NONE if it's an ordinary identifier. Linear search over a // or tkind.TK_NONE if it's an ordinary identifier. Linear search over a
// small alphabetised list, matching cmd/wcc/tok.c. // small alphabetised list, matching cmd/wcc/tok.c.
export fn kwlookup(p: *u8, n: i32) i32 = { export fn kwlookup(p: *u8, n: i32) tkind = {
if (streqn(p, "as", n)) { return tkind.TK_AS; }; if (streqn(p, "as", n)) { return tkind.TK_AS; };
if (streqn(p, "break", n)) { return tkind.TK_BREAK; }; if (streqn(p, "break", n)) { return tkind.TK_BREAK; };
if (streqn(p, "case", n)) { return tkind.TK_CASE; }; if (streqn(p, "case", n)) { return tkind.TK_CASE; };
@@ -198,7 +197,7 @@ export fn kwlookup(p: *u8, n: i32) i32 = {
// Returns the canonical printable spelling for a token kind. Matches // Returns the canonical printable spelling for a token kind. Matches
// the C tokname()'s output exactly so wwdump output diffs cleanly. // the C tokname()'s output exactly so wwdump output diffs cleanly.
export fn tokname(k: i32) str = { export fn tokname(k: tkind) str = {
if (k == tkind.TK_NONE) { return "<none>"; }; if (k == tkind.TK_NONE) { return "<none>"; };
if (k == tkind.TK_EOF) { return "EOF"; }; if (k == tkind.TK_EOF) { return "EOF"; };
if (k == tkind.TK_ERR) { return "ERR"; }; if (k == tkind.TK_ERR) { return "ERR"; };

View File

@@ -199,7 +199,7 @@ fn parseprimary(p: *parser) *node = {
return newnode(p.a, nkind.N_NONE, pf, pl, pc); return newnode(p.a, nkind.N_NONE, pf, pl, pc);
}; };
fn parsearglist(p: *parser, closekind: i32, headout: **node) void = { fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = {
*headout = nil; *headout = nil;
if (p.curkind == closekind) { return; }; if (p.curkind == closekind) { return; };
let head: *node = nil; let head: *node = nil;
@@ -355,7 +355,7 @@ fn parseunary(p: *parser) *node = {
let pf: str = p.curfile; let pf: str = p.curfile;
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
let k: i32 = p.curkind; let k: tkind = p.curkind;
if (k == tkind.TK_MINUS) { if (k == tkind.TK_MINUS) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc);
@@ -398,7 +398,7 @@ fn parseunary(p: *parser) *node = {
fn parsebin(p: *parser, lhs: *node, minp: i32) *node = { fn parsebin(p: *parser, lhs: *node, minp: i32) *node = {
let cur: *node = lhs; let cur: *node = lhs;
for (true) { for (true) {
let op: i32 = p.curkind; let op: tkind = p.curkind;
let pr: i32 = bprec(op); let pr: i32 = bprec(op);
if (pr == 0) { return cur; }; if (pr == 0) { return cur; };
if (pr < minp) { return cur; }; if (pr < minp) { return cur; };
@@ -425,7 +425,7 @@ fn parseexpr(p: *parser) *node = {
let pf: str = p.curfile; let pf: str = p.curfile;
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
let op: i32 = p.curkind; let op: tkind = p.curkind;
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc); let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc);
n.op = op; n.op = op;

View File

@@ -24,7 +24,7 @@ type parser = struct {
// nocast: while inside `[...]` we treat ':' as the slice // nocast: while inside `[...]` we treat ':' as the slice
// separator, not the cast operator. Mirrors parse.c's flag. // separator, not the cast operator. Mirrors parse.c's flag.
nocast: i32, nocast: i32,
curkind: i32, // holds a `tkind` value (relaxation lets it mix) curkind: tkind,
curfile: str, curfile: str,
curline: i32, curline: i32,
curcol: i32, curcol: i32,
@@ -53,7 +53,7 @@ export fn parserinit(p: *parser, a: *arena, l: *lex) void = {
fn advance(p: *parser) void = { refill(p); }; fn advance(p: *parser) void = { refill(p); };
fn accepttok(p: *parser, k: i32) bool = { fn accepttok(p: *parser, k: tkind) bool = {
if (p.curkind == k) { advance(p); return true; }; if (p.curkind == k) { advance(p); return true; };
return false; return false;
}; };
@@ -66,7 +66,7 @@ fn errmsg(p: *parser, msg: str) void = {
p.errs += 1; p.errs += 1;
}; };
fn expecttok(p: *parser, k: i32, what: str) bool = { fn expecttok(p: *parser, k: tkind, what: str) bool = {
if (p.curkind == k) { advance(p); return true; }; if (p.curkind == k) { advance(p); return true; };
errmsg(p, what); errmsg(p, what);
return false; return false;
@@ -313,7 +313,7 @@ fn parsetype(p: *parser) *node = {
// and the ?/! try operators are not yet wired — they'll arrive as the // and the ?/! try operators are not yet wired — they'll arrive as the
// AST diff fixture grows to need them. // AST diff fixture grows to need them.
fn bprec(k: i32) i32 = { fn bprec(k: tkind) i32 = {
if (k == tkind.TK_OR) { return 1; }; if (k == tkind.TK_OR) { return 1; };
if (k == tkind.TK_AND) { return 2; }; if (k == tkind.TK_AND) { return 2; };
if (k == tkind.TK_EQ) { return 3; }; if (k == tkind.TK_EQ) { return 3; };
@@ -335,7 +335,7 @@ fn bprec(k: i32) i32 = {
return 0; return 0;
}; };
fn isassignop(k: i32) bool = { fn isassignop(k: tkind) bool = {
if (k == tkind.TK_ASSIGN) { return true; }; if (k == tkind.TK_ASSIGN) { return true; };
if (k == tkind.TK_PLUSEQ) { return true; }; if (k == tkind.TK_PLUSEQ) { return true; };
if (k == tkind.TK_MINUSEQ) { return true; }; if (k == tkind.TK_MINUSEQ) { return true; };

View File

@@ -22,7 +22,7 @@ type skind = enum i32 {
type sym = struct { type sym = struct {
name: str, name: str,
skind: i32, skind: skind,
type_: *tinfo, type_: *tinfo,
decl: *node, decl: *node,
exported: i32, exported: i32,
@@ -98,7 +98,7 @@ export fn scopelookup(s: *scope, name: str) *sym = {
return nil; return nil;
}; };
export fn scopedefine(s: *scope, name: str, k: i32, t: *tinfo, decl: *node) *sym = { export fn scopedefine(s: *scope, name: str, k: skind, t: *tinfo, decl: *node) *sym = {
if (scopelookuplocal(s, name) != nil) { return nil; }; if (scopelookuplocal(s, name) != nil) { return nil; };
let sy: *sym = amalloc(s.a, 80u64): *sym; let sy: *sym = amalloc(s.a, 80u64): *sym;
sy.name = name; sy.name = name;

View File

@@ -74,7 +74,7 @@ type tparam = struct {
}; };
type tinfo = struct { type tinfo = struct {
kind: i32, kind: tykind,
size: u64, size: u64,
align: u64, align: u64,
sub: *tinfo, // ptr/slice/array/chan element sub: *tinfo, // ptr/slice/array/chan element
@@ -120,13 +120,13 @@ type tctx = struct {
// ---- constructors ----------------------------------------------------- // ---- constructors -----------------------------------------------------
export fn newtype(a: *arena, k: i32) *tinfo = { export fn newtype(a: *arena, k: tykind) *tinfo = {
let t: *tinfo = amalloc(a, 96u64): *tinfo; let t: *tinfo = amalloc(a, 96u64): *tinfo;
t.kind = k; t.kind = k;
return t; return t;
}; };
fn prim(a: *arena, k: i32, nm: str, sz: u64, al: u64) *tinfo = { fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = {
let t: *tinfo = newtype(a, k); let t: *tinfo = newtype(a, k);
t.name = nm; t.name = nm;
t.size = sz; t.size = sz;
@@ -216,7 +216,7 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = {
export fn typeisint(t: *tinfo) bool = { export fn typeisint(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_I8) { return true; }; if (k == tykind.TY_I8) { return true; };
if (k == tykind.TY_I16) { return true; }; if (k == tykind.TY_I16) { return true; };
if (k == tykind.TY_I32) { return true; }; if (k == tykind.TY_I32) { return true; };
@@ -238,7 +238,7 @@ export fn typeisint(t: *tinfo) bool = {
export fn typeisfloat(t: *tinfo) bool = { export fn typeisfloat(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_F32) { return true; }; if (k == tykind.TY_F32) { return true; };
if (k == tykind.TY_F64) { return true; }; if (k == tykind.TY_F64) { return true; };
if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; };
@@ -253,7 +253,7 @@ export fn typeisnum(t: *tinfo) bool = {
export fn typeisunsigned(t: *tinfo) bool = { export fn typeisunsigned(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_U8) { return true; }; if (k == tykind.TY_U8) { return true; };
if (k == tykind.TY_U16) { return true; }; if (k == tykind.TY_U16) { return true; };
if (k == tykind.TY_U32) { return true; }; if (k == tykind.TY_U32) { return true; };
@@ -266,7 +266,7 @@ export fn typeisunsigned(t: *tinfo) bool = {
export fn typeisuntyped(t: *tinfo) bool = { export fn typeisuntyped(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_UNTYPED_INT) { return true; }; if (k == tykind.TY_UNTYPED_INT) { return true; };
if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; };
if (k == tykind.TY_UNTYPED_STR) { return true; }; if (k == tykind.TY_UNTYPED_STR) { return true; };
@@ -282,7 +282,7 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = {
if (a == nil) { return false; }; if (a == nil) { return false; };
if (b == nil) { return false; }; if (b == nil) { return false; };
if (a.kind != b.kind) { return false; }; if (a.kind != b.kind) { return false; };
let k: i32 = a.kind; let k: tykind = a.kind;
if (k == tykind.TY_PTR) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_PTR) { return typeeq(a.sub, b.sub); };
if (k == tykind.TY_SLICE) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_SLICE) { return typeeq(a.sub, b.sub); };
if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); };

View File

@@ -581,8 +581,7 @@ type pos = struct {
}; };
type tok = struct { type tok = struct {
kind: i32, // holds a `tkind` value; bare i32 so the cgen's kind: tkind,
// fixed 8B/struct-field layout matches the C side
file: str, // path of the source the token came from file: str, // path of the source the token came from
line: i32, line: i32,
col: i32, col: i32,
@@ -607,7 +606,7 @@ fn streqn(a: *u8, b: str, n: i32) bool = {
// kwlookup — returns the matching TK_* keyword kind for a byte run, // kwlookup — returns the matching TK_* keyword kind for a byte run,
// or tkind.TK_NONE if it's an ordinary identifier. Linear search over a // or tkind.TK_NONE if it's an ordinary identifier. Linear search over a
// small alphabetised list, matching cmd/wcc/tok.c. // small alphabetised list, matching cmd/wcc/tok.c.
export fn kwlookup(p: *u8, n: i32) i32 = { export fn kwlookup(p: *u8, n: i32) tkind = {
if (streqn(p, "as", n)) { return tkind.TK_AS; }; if (streqn(p, "as", n)) { return tkind.TK_AS; };
if (streqn(p, "break", n)) { return tkind.TK_BREAK; }; if (streqn(p, "break", n)) { return tkind.TK_BREAK; };
if (streqn(p, "case", n)) { return tkind.TK_CASE; }; if (streqn(p, "case", n)) { return tkind.TK_CASE; };
@@ -645,7 +644,7 @@ export fn kwlookup(p: *u8, n: i32) i32 = {
// Returns the canonical printable spelling for a token kind. Matches // Returns the canonical printable spelling for a token kind. Matches
// the C tokname()'s output exactly so wwdump output diffs cleanly. // the C tokname()'s output exactly so wwdump output diffs cleanly.
export fn tokname(k: i32) str = { export fn tokname(k: tkind) str = {
if (k == tkind.TK_NONE) { return "<none>"; }; if (k == tkind.TK_NONE) { return "<none>"; };
if (k == tkind.TK_EOF) { return "EOF"; }; if (k == tkind.TK_EOF) { return "EOF"; };
if (k == tkind.TK_ERR) { return "ERR"; }; if (k == tkind.TK_ERR) { return "ERR"; };
@@ -1421,7 +1420,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = {
return; return;
}; };
}; };
let k: i32 = kwlookup(p, n: i32); let k: tkind = kwlookup(p, n: i32);
if (k != tkind.TK_NONE) { if (k != tkind.TK_NONE) {
out.kind = k; out.kind = k;
} else { } else {
@@ -1514,7 +1513,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = {
out.uval = ch: u64; out.uval = ch: u64;
}; };
fn emitsimple(start: *pos, k: i32, out: *tok) void = { fn emitsimple(start: *pos, k: tkind, out: *tok) void = {
out.kind = k; out.kind = k;
out.file = start.file; out.file = start.file;
out.line = start.line; out.line = start.line;
@@ -1766,11 +1765,11 @@ type nkind = enum i32 {
// ---- Node ------------------------------------------------------------- // ---- Node -------------------------------------------------------------
type node = struct { type node = struct {
kind: i32, kind: nkind,
file: str, file: str,
line: i32, line: i32,
col: i32, col: i32,
op: i32, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN op: tkind, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN
str: str, str: str,
uval: u64, uval: u64,
fval: f64, fval: f64,
@@ -1788,7 +1787,7 @@ type node = struct {
module: str, // originating module from `// MODULE: foo`; "" if none module: str, // originating module from `// MODULE: foo`; "" if none
}; };
export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = { export fn newnode(a: *arena, k: nkind, file: str, line: i32, col: i32) *node = {
let n: *node = amalloc(a, 208u64): *node; // ≥ struct size let n: *node = amalloc(a, 208u64): *node; // ≥ struct size
n.kind = k; n.kind = k;
n.file = file; n.file = file;
@@ -1799,7 +1798,7 @@ export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = {
// ---- printer ---------------------------------------------------------- // ---- printer ----------------------------------------------------------
fn nkname(k: i32) str = { fn nkname(k: nkind) str = {
if (k == nkind.N_NONE) { return "none"; }; if (k == nkind.N_NONE) { return "none"; };
if (k == nkind.N_INTLIT) { return "int"; }; if (k == nkind.N_INTLIT) { return "int"; };
if (k == nkind.N_FLOATLIT) { return "float"; }; if (k == nkind.N_FLOATLIT) { return "float"; };
@@ -2222,7 +2221,7 @@ fn parseprimary(p: *parser) *node = {
return newnode(p.a, nkind.N_NONE, pf, pl, pc); return newnode(p.a, nkind.N_NONE, pf, pl, pc);
}; };
fn parsearglist(p: *parser, closekind: i32, headout: **node) void = { fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = {
*headout = nil; *headout = nil;
if (p.curkind == closekind) { return; }; if (p.curkind == closekind) { return; };
let head: *node = nil; let head: *node = nil;
@@ -2378,7 +2377,7 @@ fn parseunary(p: *parser) *node = {
let pf: str = p.curfile; let pf: str = p.curfile;
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
let k: i32 = p.curkind; let k: tkind = p.curkind;
if (k == tkind.TK_MINUS) { if (k == tkind.TK_MINUS) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc);
@@ -2421,7 +2420,7 @@ fn parseunary(p: *parser) *node = {
fn parsebin(p: *parser, lhs: *node, minp: i32) *node = { fn parsebin(p: *parser, lhs: *node, minp: i32) *node = {
let cur: *node = lhs; let cur: *node = lhs;
for (true) { for (true) {
let op: i32 = p.curkind; let op: tkind = p.curkind;
let pr: i32 = bprec(op); let pr: i32 = bprec(op);
if (pr == 0) { return cur; }; if (pr == 0) { return cur; };
if (pr < minp) { return cur; }; if (pr < minp) { return cur; };
@@ -2448,7 +2447,7 @@ fn parseexpr(p: *parser) *node = {
let pf: str = p.curfile; let pf: str = p.curfile;
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
let op: i32 = p.curkind; let op: tkind = p.curkind;
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc); let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc);
n.op = op; n.op = op;
@@ -2933,7 +2932,7 @@ type parser = struct {
// nocast: while inside `[...]` we treat ':' as the slice // nocast: while inside `[...]` we treat ':' as the slice
// separator, not the cast operator. Mirrors parse.c's flag. // separator, not the cast operator. Mirrors parse.c's flag.
nocast: i32, nocast: i32,
curkind: i32, // holds a `tkind` value (relaxation lets it mix) curkind: tkind,
curfile: str, curfile: str,
curline: i32, curline: i32,
curcol: i32, curcol: i32,
@@ -2962,7 +2961,7 @@ export fn parserinit(p: *parser, a: *arena, l: *lex) void = {
fn advance(p: *parser) void = { refill(p); }; fn advance(p: *parser) void = { refill(p); };
fn accepttok(p: *parser, k: i32) bool = { fn accepttok(p: *parser, k: tkind) bool = {
if (p.curkind == k) { advance(p); return true; }; if (p.curkind == k) { advance(p); return true; };
return false; return false;
}; };
@@ -2975,7 +2974,7 @@ fn errmsg(p: *parser, msg: str) void = {
p.errs += 1; p.errs += 1;
}; };
fn expecttok(p: *parser, k: i32, what: str) bool = { fn expecttok(p: *parser, k: tkind, what: str) bool = {
if (p.curkind == k) { advance(p); return true; }; if (p.curkind == k) { advance(p); return true; };
errmsg(p, what); errmsg(p, what);
return false; return false;
@@ -3222,7 +3221,7 @@ fn parsetype(p: *parser) *node = {
// and the ?/! try operators are not yet wired — they'll arrive as the // and the ?/! try operators are not yet wired — they'll arrive as the
// AST diff fixture grows to need them. // AST diff fixture grows to need them.
fn bprec(k: i32) i32 = { fn bprec(k: tkind) i32 = {
if (k == tkind.TK_OR) { return 1; }; if (k == tkind.TK_OR) { return 1; };
if (k == tkind.TK_AND) { return 2; }; if (k == tkind.TK_AND) { return 2; };
if (k == tkind.TK_EQ) { return 3; }; if (k == tkind.TK_EQ) { return 3; };
@@ -3244,7 +3243,7 @@ fn bprec(k: i32) i32 = {
return 0; return 0;
}; };
fn isassignop(k: i32) bool = { fn isassignop(k: tkind) bool = {
if (k == tkind.TK_ASSIGN) { return true; }; if (k == tkind.TK_ASSIGN) { return true; };
if (k == tkind.TK_PLUSEQ) { return true; }; if (k == tkind.TK_PLUSEQ) { return true; };
if (k == tkind.TK_MINUSEQ) { return true; }; if (k == tkind.TK_MINUSEQ) { return true; };
@@ -3402,7 +3401,7 @@ type tparam = struct {
}; };
type tinfo = struct { type tinfo = struct {
kind: i32, kind: tykind,
size: u64, size: u64,
align: u64, align: u64,
sub: *tinfo, // ptr/slice/array/chan element sub: *tinfo, // ptr/slice/array/chan element
@@ -3448,13 +3447,13 @@ type tctx = struct {
// ---- constructors ----------------------------------------------------- // ---- constructors -----------------------------------------------------
export fn newtype(a: *arena, k: i32) *tinfo = { export fn newtype(a: *arena, k: tykind) *tinfo = {
let t: *tinfo = amalloc(a, 96u64): *tinfo; let t: *tinfo = amalloc(a, 96u64): *tinfo;
t.kind = k; t.kind = k;
return t; return t;
}; };
fn prim(a: *arena, k: i32, nm: str, sz: u64, al: u64) *tinfo = { fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = {
let t: *tinfo = newtype(a, k); let t: *tinfo = newtype(a, k);
t.name = nm; t.name = nm;
t.size = sz; t.size = sz;
@@ -3544,7 +3543,7 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = {
export fn typeisint(t: *tinfo) bool = { export fn typeisint(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_I8) { return true; }; if (k == tykind.TY_I8) { return true; };
if (k == tykind.TY_I16) { return true; }; if (k == tykind.TY_I16) { return true; };
if (k == tykind.TY_I32) { return true; }; if (k == tykind.TY_I32) { return true; };
@@ -3566,7 +3565,7 @@ export fn typeisint(t: *tinfo) bool = {
export fn typeisfloat(t: *tinfo) bool = { export fn typeisfloat(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_F32) { return true; }; if (k == tykind.TY_F32) { return true; };
if (k == tykind.TY_F64) { return true; }; if (k == tykind.TY_F64) { return true; };
if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; };
@@ -3581,7 +3580,7 @@ export fn typeisnum(t: *tinfo) bool = {
export fn typeisunsigned(t: *tinfo) bool = { export fn typeisunsigned(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_U8) { return true; }; if (k == tykind.TY_U8) { return true; };
if (k == tykind.TY_U16) { return true; }; if (k == tykind.TY_U16) { return true; };
if (k == tykind.TY_U32) { return true; }; if (k == tykind.TY_U32) { return true; };
@@ -3594,7 +3593,7 @@ export fn typeisunsigned(t: *tinfo) bool = {
export fn typeisuntyped(t: *tinfo) bool = { export fn typeisuntyped(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_UNTYPED_INT) { return true; }; if (k == tykind.TY_UNTYPED_INT) { return true; };
if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; };
if (k == tykind.TY_UNTYPED_STR) { return true; }; if (k == tykind.TY_UNTYPED_STR) { return true; };
@@ -3610,7 +3609,7 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = {
if (a == nil) { return false; }; if (a == nil) { return false; };
if (b == nil) { return false; }; if (b == nil) { return false; };
if (a.kind != b.kind) { return false; }; if (a.kind != b.kind) { return false; };
let k: i32 = a.kind; let k: tykind = a.kind;
if (k == tykind.TY_PTR) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_PTR) { return typeeq(a.sub, b.sub); };
if (k == tykind.TY_SLICE) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_SLICE) { return typeeq(a.sub, b.sub); };
if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); };
@@ -3693,7 +3692,7 @@ type skind = enum i32 {
type sym = struct { type sym = struct {
name: str, name: str,
skind: i32, skind: skind,
type_: *tinfo, type_: *tinfo,
decl: *node, decl: *node,
exported: i32, exported: i32,
@@ -3769,7 +3768,7 @@ export fn scopelookup(s: *scope, name: str) *sym = {
return nil; return nil;
}; };
export fn scopedefine(s: *scope, name: str, k: i32, t: *tinfo, decl: *node) *sym = { export fn scopedefine(s: *scope, name: str, k: skind, t: *tinfo, decl: *node) *sym = {
if (scopelookuplocal(s, name) != nil) { return nil; }; if (scopelookuplocal(s, name) != nil) { return nil; };
let sy: *sym = amalloc(s.a, 80u64): *sym; let sy: *sym = amalloc(s.a, 80u64): *sym;
sy.name = name; sy.name = name;
@@ -3857,7 +3856,7 @@ fn seedprimitives(c: *checker) void = {
// the name so forward references resolve. // the name so forward references resolve.
fn installdecl(c: *checker, d: *node) void = { fn installdecl(c: *checker, d: *node) void = {
if (d == nil) { return; }; if (d == nil) { return; };
let k: i32 = d.kind; let k: nkind = d.kind;
let nm: str = d.str; let nm: str = d.str;
if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; }; if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; };
if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; }; if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; };
@@ -3876,7 +3875,7 @@ fn installdecl(c: *checker, d: *node) void = {
// the same pass — they need the same scope state. // the same pass — they need the same scope state.
fn resolvewalk(c: *checker, n: *node) void = { fn resolvewalk(c: *checker, n: *node) void = {
if (n == nil) { return; }; if (n == nil) { return; };
let k: i32 = n.kind; let k: nkind = n.kind;
// Typed checks fire on the way down so the scrutinee/operand // Typed checks fire on the way down so the scrutinee/operand
// is examined before the arm bodies install new bindings. // is examined before the arm bodies install new bindings.
@@ -4042,7 +4041,7 @@ fn typeeqast(a: *node, b: *node) bool = {
if (aa == nil) { return bb == nil; }; if (aa == nil) { return bb == nil; };
if (bb == nil) { return false; }; if (bb == nil) { return false; };
if (aa.kind != bb.kind) { return false; }; if (aa.kind != bb.kind) { return false; };
let k: i32 = aa.kind; let k: nkind = aa.kind;
if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); }; if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); };
if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); }; if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); };
if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); }; if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); };
@@ -4131,7 +4130,7 @@ fn mktname(c: *checker, nm: str) *node = {
// field access into non-primitive types, etc). // field access into non-primitive types, etc).
fn exprtype(c: *checker, e: *node) *node = { fn exprtype(c: *checker, e: *node) *node = {
if (e == nil) { return nil; }; if (e == nil) { return nil; };
let k: i32 = e.kind; let k: nkind = e.kind;
if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); }; if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); };
if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); }; if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); };
if (k == nkind.N_STRLIT) { return mktname(c, "str"); }; if (k == nkind.N_STRLIT) { return mktname(c, "str"); };
@@ -4689,7 +4688,7 @@ export fn checkfile(c: *checker, file: *node) void = {
// Pass 2: walk decl bodies/types and resolve identifiers. // Pass 2: walk decl bodies/types and resolve identifiers.
d = file.list; d = file.list;
for (d != nil) { for (d != nil) {
let k: i32 = d.kind; let k: nkind = d.kind;
if (k == nkind.N_FNDECL) { if (k == nkind.N_FNDECL) {
if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type
resolvefnbody(c, d); resolvefnbody(c, d);
@@ -4863,7 +4862,7 @@ fn pushargsrev(c: *cgen, arg: *node) i32 = {
fn nodeisslice(c: *cgen, n: *node) bool = { fn nodeisslice(c: *cgen, n: *node) bool = {
if (n == nil) { return false; }; if (n == nil) { return false; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_IDENT) { if (k == nkind.N_IDENT) {
let nm: str = n.str; let nm: str = n.str;
let lc: *local = localfindnode(c, nm); let lc: *local = localfindnode(c, nm);
@@ -4879,7 +4878,7 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
// (str args take two slots: ptr + len). // (str args take two slots: ptr + len).
fn nodeisstr(c: *cgen, n: *node) bool = { fn nodeisstr(c: *cgen, n: *node) bool = {
if (n == nil) { return false; }; if (n == nil) { return false; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_STRLIT) { return true; }; if (k == nkind.N_STRLIT) { return true; };
if (k == nkind.N_IDENT) { if (k == nkind.N_IDENT) {
let nm: str = n.str; let nm: str = n.str;
@@ -4920,7 +4919,7 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
let lc: *local = localfindnode(c, base.str); let lc: *local = localfindnode(c, base.str);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TNAME) { sname = tn.str; };
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
@@ -4989,7 +4988,7 @@ fn typenodeisunsigned(t: *node) bool = {
// false here even when their *slot* rounds up to 8. // false here even when their *slot* rounds up to 8.
fn typeis8byteprimitive(c: *cgen, t: *node) bool = { fn typeis8byteprimitive(c: *cgen, t: *node) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: nkind = t.kind;
if (k == nkind.N_TPTR) { return true; }; if (k == nkind.N_TPTR) { return true; };
if (k == nkind.N_TFN) { return true; }; if (k == nkind.N_TFN) { return true; };
if (k == nkind.N_TCHAN) { return true; }; if (k == nkind.N_TCHAN) { return true; };
@@ -5081,7 +5080,7 @@ fn indexbaseesz(c: *cgen, base: *node) i32 = {
}; };
// Generic struct field: if it's *T, element size is T's size. // Generic struct field: if it's *T, element size is T's size.
let lkind: i32 = tn.kind; let lkind: nkind = tn.kind;
let sname: str; let sname: str;
sname.ptr = nil; sname.len = 0; sname.ptr = nil; sname.len = 0;
if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TNAME) { sname = tn.str; };
@@ -5180,7 +5179,7 @@ fn dotinnerstructptr(c: *cgen, n: *node) *node = {
// bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback). // bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback).
fn elemsizeof(t: *node) i32 = { fn elemsizeof(t: *node) i32 = {
if (t == nil) { return 1; }; if (t == nil) { return 1; };
let k: i32 = t.kind; let k: nkind = t.kind;
let elem: *node = nil; let elem: *node = nil;
if (k == nkind.N_TPTR) { elem = t.lhs; }; if (k == nkind.N_TPTR) { elem = t.lhs; };
if (k == nkind.N_TSLICE) { elem = t.lhs; }; if (k == nkind.N_TSLICE) { elem = t.lhs; };
@@ -5216,7 +5215,7 @@ fn elemsizeof(t: *node) i32 = {
// being wrong here is byte-different asm vs C, not bad runtime. // being wrong here is byte-different asm vs C, not bad runtime.
fn nodeisunsigned(c: *cgen, n: *node) bool = { fn nodeisunsigned(c: *cgen, n: *node) bool = {
if (n == nil) { return false; }; if (n == nil) { return false; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_IDENT) { if (k == nkind.N_IDENT) {
let nm: str = n.str; let nm: str = n.str;
let lc: *local = localfindnode(c, nm); let lc: *local = localfindnode(c, nm);
@@ -5232,7 +5231,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = {
let lc: *local = localfindnode(c, bn); let lc: *local = localfindnode(c, bn);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
let sname: str; let sname: str;
sname.ptr = nil; sname.len = 0; sname.ptr = nil; sname.len = 0;
@@ -5394,7 +5393,7 @@ export fn letslotsize(c: *cgen, n: *node) i32 = {
fn slotsize(c: *cgen, typn: *node) i32 = { fn slotsize(c: *cgen, typn: *node) i32 = {
if (typn == nil) { return 8; }; if (typn == nil) { return 8; };
let k: i32 = typn.kind; let k: nkind = typn.kind;
if (k == nkind.N_TPTR) { return 8; }; if (k == nkind.N_TPTR) { return 8; };
if (k == nkind.N_TFN) { return 8; }; if (k == nkind.N_TFN) { return 8; };
if (k == nkind.N_TCHAN) { return 8; }; if (k == nkind.N_TCHAN) { return 8; };
@@ -5481,7 +5480,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
// only round to 8 for stack slots, not struct interiors). // only round to 8 for stack slots, not struct interiors).
fn fieldsize(c: *cgen, tnode: *node) i32 = { fn fieldsize(c: *cgen, tnode: *node) i32 = {
if (tnode == nil) { return 8; }; if (tnode == nil) { return 8; };
let k: i32 = tnode.kind; let k: nkind = tnode.kind;
if (k == nkind.N_TNAME) { if (k == nkind.N_TNAME) {
let nm: str = tnode.str; let nm: str = tnode.str;
if (streq(nm, "str")) { return 16; }; if (streq(nm, "str")) { return 16; };
@@ -5489,6 +5488,18 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = {
if (ps > 0) { return ps; }; if (ps > 0) { return ps; };
let si: *structinfo = structlookup(c, nm); let si: *structinfo = structlookup(c, nm);
if (si != nil) { return si.totsize; }; if (si != nil) { return si.totsize; };
// Enum: size of its storage type. Mirrors the C cgen, which
// reads Type.size off the TY_ENUM (which inherits from .sub).
let en: *enumtype = enumlookup(c, nm);
if (en != nil) {
if (en.storage != nil) {
if (en.storage.kind == nkind.N_TNAME) {
let sps: i32 = primsize(en.storage.str);
if (sps > 0) { return sps; };
};
};
return 4; // default storage is i32
};
return 8; return 8;
}; };
if (k == nkind.N_TPTR) { return 8; }; if (k == nkind.N_TPTR) { return 8; };
@@ -5739,7 +5750,7 @@ use strconv;
fn cgexpr(c: *cgen, n: *node) void = { fn cgexpr(c: *cgen, n: *node) void = {
if (n == nil) { return; }; if (n == nil) { return; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_INTLIT) { if (k == nkind.N_INTLIT) {
// Print signed (i64), not unsigned (u64). C cgen uses // Print signed (i64), not unsigned (u64). C cgen uses
@@ -5974,7 +5985,7 @@ fn cgtypetest(c: *cgen, n: *node) void = {
// through the cast pass-through too). // through the cast pass-through too).
fn isenumexpr(c: *cgen, e: *node) bool = { fn isenumexpr(c: *cgen, e: *node) bool = {
if (e == nil) { return false; }; if (e == nil) { return false; };
let k: i32 = e.kind; let k: nkind = e.kind;
if (k == nkind.N_DOT) { if (k == nkind.N_DOT) {
if (e.lhs != nil) { if (e.lhs != nil) {
if (e.lhs.kind == nkind.N_IDENT) { if (e.lhs.kind == nkind.N_IDENT) {
@@ -6367,7 +6378,7 @@ fn cgdot(c: *cgen, n: *node) void = {
let lc: *local = localfindnode(c, nm); let lc: *local = localfindnode(c, nm);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
// Pointer-to-struct: deref then field load. // Pointer-to-struct: deref then field load.
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
@@ -6524,7 +6535,7 @@ fn cgdot(c: *cgen, n: *node) void = {
// pointed-to header. C cgen does the same. // pointed-to header. C cgen does the same.
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
let inner: *node = tn.lhs; let inner: *node = tn.lhs;
let innerkind: i32 = -1; let innerkind: nkind = nkind.N_NONE;
if (inner != nil) { innerkind = inner.kind; }; if (inner != nil) { innerkind = inner.kind; };
let innerstr: bool = false; let innerstr: bool = false;
if (innerkind == nkind.N_TNAME) { if (innerkind == nkind.N_TNAME) {
@@ -6788,7 +6799,7 @@ fn cgcall(c: *cgen, n: *node) void = {
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
if (tn != nil) { if (tn != nil) {
let lkind: i32 = tn.kind; let lkind: nkind = tn.kind;
let sname: str; let sname: str;
sname.ptr = nil; sname.len = 0; sname.ptr = nil; sname.len = 0;
if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TNAME) { sname = tn.str; };
@@ -7008,7 +7019,7 @@ fn cgassign(c: *cgen, n: *node) void = {
let lc: *local = localfindnode(c, bn); let lc: *local = localfindnode(c, bn);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
// Pointer-to-struct: deref then store. // Pointer-to-struct: deref then store.
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
@@ -7114,7 +7125,7 @@ fn cgassign(c: *cgen, n: *node) void = {
if (delta >= 0) { if (delta >= 0) {
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
let inner: *node = tn.lhs; let inner: *node = tn.lhs;
let innerkind: i32 = -1; let innerkind: nkind = nkind.N_NONE;
if (inner != nil) { innerkind = inner.kind; }; if (inner != nil) { innerkind = inner.kind; };
let innerstr: bool = false; let innerstr: bool = false;
if (innerkind == nkind.N_TNAME) { if (innerkind == nkind.N_TNAME) {
@@ -7322,7 +7333,7 @@ use strconv;
fn cgstmt(c: *cgen, n: *node) void = { fn cgstmt(c: *cgen, n: *node) void = {
if (n == nil) { return; }; if (n == nil) { return; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_BLOCK) { cgblock(c, n); return; }; if (k == nkind.N_BLOCK) { cgblock(c, n); return; };
@@ -8306,8 +8317,11 @@ export fn cgfile(c: *cgen, file: *node) void = {
c.strlits = nil; c.strlits = nil;
c.strlitseq = 0; c.strlitseq = 0;
collectaliases(c, file); collectaliases(c, file);
collectstructs(c, file); // Enums must register before structs — fieldsize on a tkind-typed
// field needs the enum's storage size, otherwise it falls back to
// 8 (wrong load width).
collectenums(c, file); collectenums(c, file);
collectstructs(c, file);
collectdefs(c, file); collectdefs(c, file);
collectfnrets(c, file); collectfnrets(c, file);
fficollect(c, file); fficollect(c, file);
@@ -8417,7 +8431,7 @@ fn aliaslookup(c: *cgen, name: str) *node = {
fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
if (e == nil) { return false; }; if (e == nil) { return false; };
let k: i32 = e.kind; let k: nkind = e.kind;
if (k == nkind.N_INTLIT) { *out = e.uval; return true; }; if (k == nkind.N_INTLIT) { *out = e.uval; return true; };
if (k == nkind.N_RUNELIT) { *out = e.uval; return true; }; if (k == nkind.N_RUNELIT) { *out = e.uval; return true; };
if (k == nkind.N_TRUE) { *out = 1u64; return true; }; if (k == nkind.N_TRUE) { *out = 1u64; return true; };
@@ -8438,7 +8452,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
let b: u64; let b: u64;
if (!enumevalmember(prev, e.lhs, &a)) { return false; }; if (!enumevalmember(prev, e.lhs, &a)) { return false; };
if (!enumevalmember(prev, e.rhs, &b)) { return false; }; if (!enumevalmember(prev, e.rhs, &b)) { return false; };
let op: i32 = e.op; let op: tkind = e.op;
if (op == tkind.TK_PLUS) { *out = a + b; return true; }; if (op == tkind.TK_PLUS) { *out = a + b; return true; };
if (op == tkind.TK_MINUS) { *out = a - b; return true; }; if (op == tkind.TK_MINUS) { *out = a - b; return true; };
if (op == tkind.TK_STAR) { *out = a * b; return true; }; if (op == tkind.TK_STAR) { *out = a * b; return true; };
@@ -8460,7 +8474,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
if (k == nkind.N_UN) { if (k == nkind.N_UN) {
let v: u64; let v: u64;
if (!enumevalmember(prev, e.lhs, &v)) { return false; }; if (!enumevalmember(prev, e.lhs, &v)) { return false; };
let op: i32 = e.op; let op: tkind = e.op;
if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; }; if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; };
if (op == tkind.TK_TILDE) { *out = ~v; return true; }; if (op == tkind.TK_TILDE) { *out = ~v; return true; };
if (op == tkind.TK_PLUS) { *out = v; return true; }; if (op == tkind.TK_PLUS) { *out = v; return true; };

View File

@@ -89,7 +89,7 @@ fn aliaslookup(c: *cgen, name: str) *node = {
fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
if (e == nil) { return false; }; if (e == nil) { return false; };
let k: i32 = e.kind; let k: nkind = e.kind;
if (k == nkind.N_INTLIT) { *out = e.uval; return true; }; if (k == nkind.N_INTLIT) { *out = e.uval; return true; };
if (k == nkind.N_RUNELIT) { *out = e.uval; return true; }; if (k == nkind.N_RUNELIT) { *out = e.uval; return true; };
if (k == nkind.N_TRUE) { *out = 1u64; return true; }; if (k == nkind.N_TRUE) { *out = 1u64; return true; };
@@ -110,7 +110,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
let b: u64; let b: u64;
if (!enumevalmember(prev, e.lhs, &a)) { return false; }; if (!enumevalmember(prev, e.lhs, &a)) { return false; };
if (!enumevalmember(prev, e.rhs, &b)) { return false; }; if (!enumevalmember(prev, e.rhs, &b)) { return false; };
let op: i32 = e.op; let op: tkind = e.op;
if (op == tkind.TK_PLUS) { *out = a + b; return true; }; if (op == tkind.TK_PLUS) { *out = a + b; return true; };
if (op == tkind.TK_MINUS) { *out = a - b; return true; }; if (op == tkind.TK_MINUS) { *out = a - b; return true; };
if (op == tkind.TK_STAR) { *out = a * b; return true; }; if (op == tkind.TK_STAR) { *out = a * b; return true; };
@@ -132,7 +132,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
if (k == nkind.N_UN) { if (k == nkind.N_UN) {
let v: u64; let v: u64;
if (!enumevalmember(prev, e.lhs, &v)) { return false; }; if (!enumevalmember(prev, e.lhs, &v)) { return false; };
let op: i32 = e.op; let op: tkind = e.op;
if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; }; if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; };
if (op == tkind.TK_TILDE) { *out = ~v; return true; }; if (op == tkind.TK_TILDE) { *out = ~v; return true; };
if (op == tkind.TK_PLUS) { *out = v; return true; }; if (op == tkind.TK_PLUS) { *out = v; return true; };

View File

@@ -278,8 +278,11 @@ export fn cgfile(c: *cgen, file: *node) void = {
c.strlits = nil; c.strlits = nil;
c.strlitseq = 0; c.strlitseq = 0;
collectaliases(c, file); collectaliases(c, file);
collectstructs(c, file); // Enums must register before structs — fieldsize on a tkind-typed
// field needs the enum's storage size, otherwise it falls back to
// 8 (wrong load width).
collectenums(c, file); collectenums(c, file);
collectstructs(c, file);
collectdefs(c, file); collectdefs(c, file);
collectfnrets(c, file); collectfnrets(c, file);
fficollect(c, file); fficollect(c, file);

View File

@@ -22,7 +22,7 @@ use strconv;
fn cgexpr(c: *cgen, n: *node) void = { fn cgexpr(c: *cgen, n: *node) void = {
if (n == nil) { return; }; if (n == nil) { return; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_INTLIT) { if (k == nkind.N_INTLIT) {
// Print signed (i64), not unsigned (u64). C cgen uses // Print signed (i64), not unsigned (u64). C cgen uses
@@ -257,7 +257,7 @@ fn cgtypetest(c: *cgen, n: *node) void = {
// through the cast pass-through too). // through the cast pass-through too).
fn isenumexpr(c: *cgen, e: *node) bool = { fn isenumexpr(c: *cgen, e: *node) bool = {
if (e == nil) { return false; }; if (e == nil) { return false; };
let k: i32 = e.kind; let k: nkind = e.kind;
if (k == nkind.N_DOT) { if (k == nkind.N_DOT) {
if (e.lhs != nil) { if (e.lhs != nil) {
if (e.lhs.kind == nkind.N_IDENT) { if (e.lhs.kind == nkind.N_IDENT) {
@@ -650,7 +650,7 @@ fn cgdot(c: *cgen, n: *node) void = {
let lc: *local = localfindnode(c, nm); let lc: *local = localfindnode(c, nm);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
// Pointer-to-struct: deref then field load. // Pointer-to-struct: deref then field load.
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
@@ -807,7 +807,7 @@ fn cgdot(c: *cgen, n: *node) void = {
// pointed-to header. C cgen does the same. // pointed-to header. C cgen does the same.
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
let inner: *node = tn.lhs; let inner: *node = tn.lhs;
let innerkind: i32 = -1; let innerkind: nkind = nkind.N_NONE;
if (inner != nil) { innerkind = inner.kind; }; if (inner != nil) { innerkind = inner.kind; };
let innerstr: bool = false; let innerstr: bool = false;
if (innerkind == nkind.N_TNAME) { if (innerkind == nkind.N_TNAME) {
@@ -1071,7 +1071,7 @@ fn cgcall(c: *cgen, n: *node) void = {
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
if (tn != nil) { if (tn != nil) {
let lkind: i32 = tn.kind; let lkind: nkind = tn.kind;
let sname: str; let sname: str;
sname.ptr = nil; sname.len = 0; sname.ptr = nil; sname.len = 0;
if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TNAME) { sname = tn.str; };
@@ -1291,7 +1291,7 @@ fn cgassign(c: *cgen, n: *node) void = {
let lc: *local = localfindnode(c, bn); let lc: *local = localfindnode(c, bn);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
// Pointer-to-struct: deref then store. // Pointer-to-struct: deref then store.
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
@@ -1397,7 +1397,7 @@ fn cgassign(c: *cgen, n: *node) void = {
if (delta >= 0) { if (delta >= 0) {
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
let inner: *node = tn.lhs; let inner: *node = tn.lhs;
let innerkind: i32 = -1; let innerkind: nkind = nkind.N_NONE;
if (inner != nil) { innerkind = inner.kind; }; if (inner != nil) { innerkind = inner.kind; };
let innerstr: bool = false; let innerstr: bool = false;
if (innerkind == nkind.N_TNAME) { if (innerkind == nkind.N_TNAME) {

View File

@@ -20,7 +20,7 @@ use strconv;
fn cgstmt(c: *cgen, n: *node) void = { fn cgstmt(c: *cgen, n: *node) void = {
if (n == nil) { return; }; if (n == nil) { return; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_BLOCK) { cgblock(c, n); return; }; if (k == nkind.N_BLOCK) { cgblock(c, n); return; };

View File

@@ -153,7 +153,7 @@ fn pushargsrev(c: *cgen, arg: *node) i32 = {
fn nodeisslice(c: *cgen, n: *node) bool = { fn nodeisslice(c: *cgen, n: *node) bool = {
if (n == nil) { return false; }; if (n == nil) { return false; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_IDENT) { if (k == nkind.N_IDENT) {
let nm: str = n.str; let nm: str = n.str;
let lc: *local = localfindnode(c, nm); let lc: *local = localfindnode(c, nm);
@@ -169,7 +169,7 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
// (str args take two slots: ptr + len). // (str args take two slots: ptr + len).
fn nodeisstr(c: *cgen, n: *node) bool = { fn nodeisstr(c: *cgen, n: *node) bool = {
if (n == nil) { return false; }; if (n == nil) { return false; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_STRLIT) { return true; }; if (k == nkind.N_STRLIT) { return true; };
if (k == nkind.N_IDENT) { if (k == nkind.N_IDENT) {
let nm: str = n.str; let nm: str = n.str;
@@ -210,7 +210,7 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
let lc: *local = localfindnode(c, base.str); let lc: *local = localfindnode(c, base.str);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TNAME) { sname = tn.str; };
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
@@ -279,7 +279,7 @@ fn typenodeisunsigned(t: *node) bool = {
// false here even when their *slot* rounds up to 8. // false here even when their *slot* rounds up to 8.
fn typeis8byteprimitive(c: *cgen, t: *node) bool = { fn typeis8byteprimitive(c: *cgen, t: *node) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: nkind = t.kind;
if (k == nkind.N_TPTR) { return true; }; if (k == nkind.N_TPTR) { return true; };
if (k == nkind.N_TFN) { return true; }; if (k == nkind.N_TFN) { return true; };
if (k == nkind.N_TCHAN) { return true; }; if (k == nkind.N_TCHAN) { return true; };
@@ -371,7 +371,7 @@ fn indexbaseesz(c: *cgen, base: *node) i32 = {
}; };
// Generic struct field: if it's *T, element size is T's size. // Generic struct field: if it's *T, element size is T's size.
let lkind: i32 = tn.kind; let lkind: nkind = tn.kind;
let sname: str; let sname: str;
sname.ptr = nil; sname.len = 0; sname.ptr = nil; sname.len = 0;
if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TNAME) { sname = tn.str; };
@@ -470,7 +470,7 @@ fn dotinnerstructptr(c: *cgen, n: *node) *node = {
// bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback). // bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback).
fn elemsizeof(t: *node) i32 = { fn elemsizeof(t: *node) i32 = {
if (t == nil) { return 1; }; if (t == nil) { return 1; };
let k: i32 = t.kind; let k: nkind = t.kind;
let elem: *node = nil; let elem: *node = nil;
if (k == nkind.N_TPTR) { elem = t.lhs; }; if (k == nkind.N_TPTR) { elem = t.lhs; };
if (k == nkind.N_TSLICE) { elem = t.lhs; }; if (k == nkind.N_TSLICE) { elem = t.lhs; };
@@ -506,7 +506,7 @@ fn elemsizeof(t: *node) i32 = {
// being wrong here is byte-different asm vs C, not bad runtime. // being wrong here is byte-different asm vs C, not bad runtime.
fn nodeisunsigned(c: *cgen, n: *node) bool = { fn nodeisunsigned(c: *cgen, n: *node) bool = {
if (n == nil) { return false; }; if (n == nil) { return false; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_IDENT) { if (k == nkind.N_IDENT) {
let nm: str = n.str; let nm: str = n.str;
let lc: *local = localfindnode(c, nm); let lc: *local = localfindnode(c, nm);
@@ -522,7 +522,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = {
let lc: *local = localfindnode(c, bn); let lc: *local = localfindnode(c, bn);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
let sname: str; let sname: str;
sname.ptr = nil; sname.len = 0; sname.ptr = nil; sname.len = 0;
@@ -684,7 +684,7 @@ export fn letslotsize(c: *cgen, n: *node) i32 = {
fn slotsize(c: *cgen, typn: *node) i32 = { fn slotsize(c: *cgen, typn: *node) i32 = {
if (typn == nil) { return 8; }; if (typn == nil) { return 8; };
let k: i32 = typn.kind; let k: nkind = typn.kind;
if (k == nkind.N_TPTR) { return 8; }; if (k == nkind.N_TPTR) { return 8; };
if (k == nkind.N_TFN) { return 8; }; if (k == nkind.N_TFN) { return 8; };
if (k == nkind.N_TCHAN) { return 8; }; if (k == nkind.N_TCHAN) { return 8; };
@@ -771,7 +771,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
// only round to 8 for stack slots, not struct interiors). // only round to 8 for stack slots, not struct interiors).
fn fieldsize(c: *cgen, tnode: *node) i32 = { fn fieldsize(c: *cgen, tnode: *node) i32 = {
if (tnode == nil) { return 8; }; if (tnode == nil) { return 8; };
let k: i32 = tnode.kind; let k: nkind = tnode.kind;
if (k == nkind.N_TNAME) { if (k == nkind.N_TNAME) {
let nm: str = tnode.str; let nm: str = tnode.str;
if (streq(nm, "str")) { return 16; }; if (streq(nm, "str")) { return 16; };
@@ -779,6 +779,18 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = {
if (ps > 0) { return ps; }; if (ps > 0) { return ps; };
let si: *structinfo = structlookup(c, nm); let si: *structinfo = structlookup(c, nm);
if (si != nil) { return si.totsize; }; if (si != nil) { return si.totsize; };
// Enum: size of its storage type. Mirrors the C cgen, which
// reads Type.size off the TY_ENUM (which inherits from .sub).
let en: *enumtype = enumlookup(c, nm);
if (en != nil) {
if (en.storage != nil) {
if (en.storage.kind == nkind.N_TNAME) {
let sps: i32 = primsize(en.storage.str);
if (sps > 0) { return sps; };
};
};
return 4; // default storage is i32
};
return 8; return 8;
}; };
if (k == nkind.N_TPTR) { return 8; }; if (k == nkind.N_TPTR) { return 8; };

View File

@@ -68,7 +68,7 @@ fn seedprimitives(c: *checker) void = {
// the name so forward references resolve. // the name so forward references resolve.
fn installdecl(c: *checker, d: *node) void = { fn installdecl(c: *checker, d: *node) void = {
if (d == nil) { return; }; if (d == nil) { return; };
let k: i32 = d.kind; let k: nkind = d.kind;
let nm: str = d.str; let nm: str = d.str;
if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; }; if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; };
if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; }; if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; };
@@ -87,7 +87,7 @@ fn installdecl(c: *checker, d: *node) void = {
// the same pass — they need the same scope state. // the same pass — they need the same scope state.
fn resolvewalk(c: *checker, n: *node) void = { fn resolvewalk(c: *checker, n: *node) void = {
if (n == nil) { return; }; if (n == nil) { return; };
let k: i32 = n.kind; let k: nkind = n.kind;
// Typed checks fire on the way down so the scrutinee/operand // Typed checks fire on the way down so the scrutinee/operand
// is examined before the arm bodies install new bindings. // is examined before the arm bodies install new bindings.
@@ -253,7 +253,7 @@ fn typeeqast(a: *node, b: *node) bool = {
if (aa == nil) { return bb == nil; }; if (aa == nil) { return bb == nil; };
if (bb == nil) { return false; }; if (bb == nil) { return false; };
if (aa.kind != bb.kind) { return false; }; if (aa.kind != bb.kind) { return false; };
let k: i32 = aa.kind; let k: nkind = aa.kind;
if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); }; if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); };
if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); }; if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); };
if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); }; if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); };
@@ -342,7 +342,7 @@ fn mktname(c: *checker, nm: str) *node = {
// field access into non-primitive types, etc). // field access into non-primitive types, etc).
fn exprtype(c: *checker, e: *node) *node = { fn exprtype(c: *checker, e: *node) *node = {
if (e == nil) { return nil; }; if (e == nil) { return nil; };
let k: i32 = e.kind; let k: nkind = e.kind;
if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); }; if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); };
if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); }; if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); };
if (k == nkind.N_STRLIT) { return mktname(c, "str"); }; if (k == nkind.N_STRLIT) { return mktname(c, "str"); };
@@ -900,7 +900,7 @@ export fn checkfile(c: *checker, file: *node) void = {
// Pass 2: walk decl bodies/types and resolve identifiers. // Pass 2: walk decl bodies/types and resolve identifiers.
d = file.list; d = file.list;
for (d != nil) { for (d != nil) {
let k: i32 = d.kind; let k: nkind = d.kind;
if (k == nkind.N_FNDECL) { if (k == nkind.N_FNDECL) {
if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type
resolvefnbody(c, d); resolvefnbody(c, d);

View File

@@ -581,8 +581,7 @@ type pos = struct {
}; };
type tok = struct { type tok = struct {
kind: i32, // holds a `tkind` value; bare i32 so the cgen's kind: tkind,
// fixed 8B/struct-field layout matches the C side
file: str, // path of the source the token came from file: str, // path of the source the token came from
line: i32, line: i32,
col: i32, col: i32,
@@ -607,7 +606,7 @@ fn streqn(a: *u8, b: str, n: i32) bool = {
// kwlookup — returns the matching TK_* keyword kind for a byte run, // kwlookup — returns the matching TK_* keyword kind for a byte run,
// or tkind.TK_NONE if it's an ordinary identifier. Linear search over a // or tkind.TK_NONE if it's an ordinary identifier. Linear search over a
// small alphabetised list, matching cmd/wcc/tok.c. // small alphabetised list, matching cmd/wcc/tok.c.
export fn kwlookup(p: *u8, n: i32) i32 = { export fn kwlookup(p: *u8, n: i32) tkind = {
if (streqn(p, "as", n)) { return tkind.TK_AS; }; if (streqn(p, "as", n)) { return tkind.TK_AS; };
if (streqn(p, "break", n)) { return tkind.TK_BREAK; }; if (streqn(p, "break", n)) { return tkind.TK_BREAK; };
if (streqn(p, "case", n)) { return tkind.TK_CASE; }; if (streqn(p, "case", n)) { return tkind.TK_CASE; };
@@ -645,7 +644,7 @@ export fn kwlookup(p: *u8, n: i32) i32 = {
// Returns the canonical printable spelling for a token kind. Matches // Returns the canonical printable spelling for a token kind. Matches
// the C tokname()'s output exactly so wwdump output diffs cleanly. // the C tokname()'s output exactly so wwdump output diffs cleanly.
export fn tokname(k: i32) str = { export fn tokname(k: tkind) str = {
if (k == tkind.TK_NONE) { return "<none>"; }; if (k == tkind.TK_NONE) { return "<none>"; };
if (k == tkind.TK_EOF) { return "EOF"; }; if (k == tkind.TK_EOF) { return "EOF"; };
if (k == tkind.TK_ERR) { return "ERR"; }; if (k == tkind.TK_ERR) { return "ERR"; };
@@ -1421,7 +1420,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = {
return; return;
}; };
}; };
let k: i32 = kwlookup(p, n: i32); let k: tkind = kwlookup(p, n: i32);
if (k != tkind.TK_NONE) { if (k != tkind.TK_NONE) {
out.kind = k; out.kind = k;
} else { } else {
@@ -1514,7 +1513,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = {
out.uval = ch: u64; out.uval = ch: u64;
}; };
fn emitsimple(start: *pos, k: i32, out: *tok) void = { fn emitsimple(start: *pos, k: tkind, out: *tok) void = {
out.kind = k; out.kind = k;
out.file = start.file; out.file = start.file;
out.line = start.line; out.line = start.line;
@@ -1766,11 +1765,11 @@ type nkind = enum i32 {
// ---- Node ------------------------------------------------------------- // ---- Node -------------------------------------------------------------
type node = struct { type node = struct {
kind: i32, kind: nkind,
file: str, file: str,
line: i32, line: i32,
col: i32, col: i32,
op: i32, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN op: tkind, // for nkind.N_BIN / nkind.N_UN / nkind.N_ASSIGN
str: str, str: str,
uval: u64, uval: u64,
fval: f64, fval: f64,
@@ -1788,7 +1787,7 @@ type node = struct {
module: str, // originating module from `// MODULE: foo`; "" if none module: str, // originating module from `// MODULE: foo`; "" if none
}; };
export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = { export fn newnode(a: *arena, k: nkind, file: str, line: i32, col: i32) *node = {
let n: *node = amalloc(a, 208u64): *node; // ≥ struct size let n: *node = amalloc(a, 208u64): *node; // ≥ struct size
n.kind = k; n.kind = k;
n.file = file; n.file = file;
@@ -1799,7 +1798,7 @@ export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = {
// ---- printer ---------------------------------------------------------- // ---- printer ----------------------------------------------------------
fn nkname(k: i32) str = { fn nkname(k: nkind) str = {
if (k == nkind.N_NONE) { return "none"; }; if (k == nkind.N_NONE) { return "none"; };
if (k == nkind.N_INTLIT) { return "int"; }; if (k == nkind.N_INTLIT) { return "int"; };
if (k == nkind.N_FLOATLIT) { return "float"; }; if (k == nkind.N_FLOATLIT) { return "float"; };
@@ -2222,7 +2221,7 @@ fn parseprimary(p: *parser) *node = {
return newnode(p.a, nkind.N_NONE, pf, pl, pc); return newnode(p.a, nkind.N_NONE, pf, pl, pc);
}; };
fn parsearglist(p: *parser, closekind: i32, headout: **node) void = { fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = {
*headout = nil; *headout = nil;
if (p.curkind == closekind) { return; }; if (p.curkind == closekind) { return; };
let head: *node = nil; let head: *node = nil;
@@ -2378,7 +2377,7 @@ fn parseunary(p: *parser) *node = {
let pf: str = p.curfile; let pf: str = p.curfile;
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
let k: i32 = p.curkind; let k: tkind = p.curkind;
if (k == tkind.TK_MINUS) { if (k == tkind.TK_MINUS) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc);
@@ -2421,7 +2420,7 @@ fn parseunary(p: *parser) *node = {
fn parsebin(p: *parser, lhs: *node, minp: i32) *node = { fn parsebin(p: *parser, lhs: *node, minp: i32) *node = {
let cur: *node = lhs; let cur: *node = lhs;
for (true) { for (true) {
let op: i32 = p.curkind; let op: tkind = p.curkind;
let pr: i32 = bprec(op); let pr: i32 = bprec(op);
if (pr == 0) { return cur; }; if (pr == 0) { return cur; };
if (pr < minp) { return cur; }; if (pr < minp) { return cur; };
@@ -2448,7 +2447,7 @@ fn parseexpr(p: *parser) *node = {
let pf: str = p.curfile; let pf: str = p.curfile;
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
let op: i32 = p.curkind; let op: tkind = p.curkind;
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc); let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc);
n.op = op; n.op = op;
@@ -2933,7 +2932,7 @@ type parser = struct {
// nocast: while inside `[...]` we treat ':' as the slice // nocast: while inside `[...]` we treat ':' as the slice
// separator, not the cast operator. Mirrors parse.c's flag. // separator, not the cast operator. Mirrors parse.c's flag.
nocast: i32, nocast: i32,
curkind: i32, // holds a `tkind` value (relaxation lets it mix) curkind: tkind,
curfile: str, curfile: str,
curline: i32, curline: i32,
curcol: i32, curcol: i32,
@@ -2962,7 +2961,7 @@ export fn parserinit(p: *parser, a: *arena, l: *lex) void = {
fn advance(p: *parser) void = { refill(p); }; fn advance(p: *parser) void = { refill(p); };
fn accepttok(p: *parser, k: i32) bool = { fn accepttok(p: *parser, k: tkind) bool = {
if (p.curkind == k) { advance(p); return true; }; if (p.curkind == k) { advance(p); return true; };
return false; return false;
}; };
@@ -2975,7 +2974,7 @@ fn errmsg(p: *parser, msg: str) void = {
p.errs += 1; p.errs += 1;
}; };
fn expecttok(p: *parser, k: i32, what: str) bool = { fn expecttok(p: *parser, k: tkind, what: str) bool = {
if (p.curkind == k) { advance(p); return true; }; if (p.curkind == k) { advance(p); return true; };
errmsg(p, what); errmsg(p, what);
return false; return false;
@@ -3222,7 +3221,7 @@ fn parsetype(p: *parser) *node = {
// and the ?/! try operators are not yet wired — they'll arrive as the // and the ?/! try operators are not yet wired — they'll arrive as the
// AST diff fixture grows to need them. // AST diff fixture grows to need them.
fn bprec(k: i32) i32 = { fn bprec(k: tkind) i32 = {
if (k == tkind.TK_OR) { return 1; }; if (k == tkind.TK_OR) { return 1; };
if (k == tkind.TK_AND) { return 2; }; if (k == tkind.TK_AND) { return 2; };
if (k == tkind.TK_EQ) { return 3; }; if (k == tkind.TK_EQ) { return 3; };
@@ -3244,7 +3243,7 @@ fn bprec(k: i32) i32 = {
return 0; return 0;
}; };
fn isassignop(k: i32) bool = { fn isassignop(k: tkind) bool = {
if (k == tkind.TK_ASSIGN) { return true; }; if (k == tkind.TK_ASSIGN) { return true; };
if (k == tkind.TK_PLUSEQ) { return true; }; if (k == tkind.TK_PLUSEQ) { return true; };
if (k == tkind.TK_MINUSEQ) { return true; }; if (k == tkind.TK_MINUSEQ) { return true; };
@@ -3402,7 +3401,7 @@ type tparam = struct {
}; };
type tinfo = struct { type tinfo = struct {
kind: i32, kind: tykind,
size: u64, size: u64,
align: u64, align: u64,
sub: *tinfo, // ptr/slice/array/chan element sub: *tinfo, // ptr/slice/array/chan element
@@ -3448,13 +3447,13 @@ type tctx = struct {
// ---- constructors ----------------------------------------------------- // ---- constructors -----------------------------------------------------
export fn newtype(a: *arena, k: i32) *tinfo = { export fn newtype(a: *arena, k: tykind) *tinfo = {
let t: *tinfo = amalloc(a, 96u64): *tinfo; let t: *tinfo = amalloc(a, 96u64): *tinfo;
t.kind = k; t.kind = k;
return t; return t;
}; };
fn prim(a: *arena, k: i32, nm: str, sz: u64, al: u64) *tinfo = { fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = {
let t: *tinfo = newtype(a, k); let t: *tinfo = newtype(a, k);
t.name = nm; t.name = nm;
t.size = sz; t.size = sz;
@@ -3544,7 +3543,7 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = {
export fn typeisint(t: *tinfo) bool = { export fn typeisint(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_I8) { return true; }; if (k == tykind.TY_I8) { return true; };
if (k == tykind.TY_I16) { return true; }; if (k == tykind.TY_I16) { return true; };
if (k == tykind.TY_I32) { return true; }; if (k == tykind.TY_I32) { return true; };
@@ -3566,7 +3565,7 @@ export fn typeisint(t: *tinfo) bool = {
export fn typeisfloat(t: *tinfo) bool = { export fn typeisfloat(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_F32) { return true; }; if (k == tykind.TY_F32) { return true; };
if (k == tykind.TY_F64) { return true; }; if (k == tykind.TY_F64) { return true; };
if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; };
@@ -3581,7 +3580,7 @@ export fn typeisnum(t: *tinfo) bool = {
export fn typeisunsigned(t: *tinfo) bool = { export fn typeisunsigned(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_U8) { return true; }; if (k == tykind.TY_U8) { return true; };
if (k == tykind.TY_U16) { return true; }; if (k == tykind.TY_U16) { return true; };
if (k == tykind.TY_U32) { return true; }; if (k == tykind.TY_U32) { return true; };
@@ -3594,7 +3593,7 @@ export fn typeisunsigned(t: *tinfo) bool = {
export fn typeisuntyped(t: *tinfo) bool = { export fn typeisuntyped(t: *tinfo) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: tykind = t.kind;
if (k == tykind.TY_UNTYPED_INT) { return true; }; if (k == tykind.TY_UNTYPED_INT) { return true; };
if (k == tykind.TY_UNTYPED_FLOAT) { return true; }; if (k == tykind.TY_UNTYPED_FLOAT) { return true; };
if (k == tykind.TY_UNTYPED_STR) { return true; }; if (k == tykind.TY_UNTYPED_STR) { return true; };
@@ -3610,7 +3609,7 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = {
if (a == nil) { return false; }; if (a == nil) { return false; };
if (b == nil) { return false; }; if (b == nil) { return false; };
if (a.kind != b.kind) { return false; }; if (a.kind != b.kind) { return false; };
let k: i32 = a.kind; let k: tykind = a.kind;
if (k == tykind.TY_PTR) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_PTR) { return typeeq(a.sub, b.sub); };
if (k == tykind.TY_SLICE) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_SLICE) { return typeeq(a.sub, b.sub); };
if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); }; if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); };
@@ -3693,7 +3692,7 @@ type skind = enum i32 {
type sym = struct { type sym = struct {
name: str, name: str,
skind: i32, skind: skind,
type_: *tinfo, type_: *tinfo,
decl: *node, decl: *node,
exported: i32, exported: i32,
@@ -3769,7 +3768,7 @@ export fn scopelookup(s: *scope, name: str) *sym = {
return nil; return nil;
}; };
export fn scopedefine(s: *scope, name: str, k: i32, t: *tinfo, decl: *node) *sym = { export fn scopedefine(s: *scope, name: str, k: skind, t: *tinfo, decl: *node) *sym = {
if (scopelookuplocal(s, name) != nil) { return nil; }; if (scopelookuplocal(s, name) != nil) { return nil; };
let sy: *sym = amalloc(s.a, 80u64): *sym; let sy: *sym = amalloc(s.a, 80u64): *sym;
sy.name = name; sy.name = name;
@@ -3857,7 +3856,7 @@ fn seedprimitives(c: *checker) void = {
// the name so forward references resolve. // the name so forward references resolve.
fn installdecl(c: *checker, d: *node) void = { fn installdecl(c: *checker, d: *node) void = {
if (d == nil) { return; }; if (d == nil) { return; };
let k: i32 = d.kind; let k: nkind = d.kind;
let nm: str = d.str; let nm: str = d.str;
if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; }; if (k == nkind.N_USE) { scopedefine(c.top, nm, skind.SK_USE, nil, d); return; };
if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; }; if (k == nkind.N_DEF) { scopedefine(c.top, nm, skind.SK_DEF, nil, d); return; };
@@ -3876,7 +3875,7 @@ fn installdecl(c: *checker, d: *node) void = {
// the same pass — they need the same scope state. // the same pass — they need the same scope state.
fn resolvewalk(c: *checker, n: *node) void = { fn resolvewalk(c: *checker, n: *node) void = {
if (n == nil) { return; }; if (n == nil) { return; };
let k: i32 = n.kind; let k: nkind = n.kind;
// Typed checks fire on the way down so the scrutinee/operand // Typed checks fire on the way down so the scrutinee/operand
// is examined before the arm bodies install new bindings. // is examined before the arm bodies install new bindings.
@@ -4042,7 +4041,7 @@ fn typeeqast(a: *node, b: *node) bool = {
if (aa == nil) { return bb == nil; }; if (aa == nil) { return bb == nil; };
if (bb == nil) { return false; }; if (bb == nil) { return false; };
if (aa.kind != bb.kind) { return false; }; if (aa.kind != bb.kind) { return false; };
let k: i32 = aa.kind; let k: nkind = aa.kind;
if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); }; if (k == nkind.N_TNAME) { return streq(aa.str, bb.str); };
if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); }; if (k == nkind.N_TPTR) { return typeeqast(aa.lhs, bb.lhs); };
if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); }; if (k == nkind.N_TSLICE){ return typeeqast(aa.lhs, bb.lhs); };
@@ -4131,7 +4130,7 @@ fn mktname(c: *checker, nm: str) *node = {
// field access into non-primitive types, etc). // field access into non-primitive types, etc).
fn exprtype(c: *checker, e: *node) *node = { fn exprtype(c: *checker, e: *node) *node = {
if (e == nil) { return nil; }; if (e == nil) { return nil; };
let k: i32 = e.kind; let k: nkind = e.kind;
if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); }; if (k == nkind.N_INTLIT) { return mktname(c, "untyped_int"); };
if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); }; if (k == nkind.N_FLOATLIT) { return mktname(c, "untyped_float"); };
if (k == nkind.N_STRLIT) { return mktname(c, "str"); }; if (k == nkind.N_STRLIT) { return mktname(c, "str"); };
@@ -4689,7 +4688,7 @@ export fn checkfile(c: *checker, file: *node) void = {
// Pass 2: walk decl bodies/types and resolve identifiers. // Pass 2: walk decl bodies/types and resolve identifiers.
d = file.list; d = file.list;
for (d != nil) { for (d != nil) {
let k: i32 = d.kind; let k: nkind = d.kind;
if (k == nkind.N_FNDECL) { if (k == nkind.N_FNDECL) {
if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type
resolvefnbody(c, d); resolvefnbody(c, d);
@@ -4863,7 +4862,7 @@ fn pushargsrev(c: *cgen, arg: *node) i32 = {
fn nodeisslice(c: *cgen, n: *node) bool = { fn nodeisslice(c: *cgen, n: *node) bool = {
if (n == nil) { return false; }; if (n == nil) { return false; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_IDENT) { if (k == nkind.N_IDENT) {
let nm: str = n.str; let nm: str = n.str;
let lc: *local = localfindnode(c, nm); let lc: *local = localfindnode(c, nm);
@@ -4879,7 +4878,7 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
// (str args take two slots: ptr + len). // (str args take two slots: ptr + len).
fn nodeisstr(c: *cgen, n: *node) bool = { fn nodeisstr(c: *cgen, n: *node) bool = {
if (n == nil) { return false; }; if (n == nil) { return false; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_STRLIT) { return true; }; if (k == nkind.N_STRLIT) { return true; };
if (k == nkind.N_IDENT) { if (k == nkind.N_IDENT) {
let nm: str = n.str; let nm: str = n.str;
@@ -4920,7 +4919,7 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
let lc: *local = localfindnode(c, base.str); let lc: *local = localfindnode(c, base.str);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TNAME) { sname = tn.str; };
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
@@ -4989,7 +4988,7 @@ fn typenodeisunsigned(t: *node) bool = {
// false here even when their *slot* rounds up to 8. // false here even when their *slot* rounds up to 8.
fn typeis8byteprimitive(c: *cgen, t: *node) bool = { fn typeis8byteprimitive(c: *cgen, t: *node) bool = {
if (t == nil) { return false; }; if (t == nil) { return false; };
let k: i32 = t.kind; let k: nkind = t.kind;
if (k == nkind.N_TPTR) { return true; }; if (k == nkind.N_TPTR) { return true; };
if (k == nkind.N_TFN) { return true; }; if (k == nkind.N_TFN) { return true; };
if (k == nkind.N_TCHAN) { return true; }; if (k == nkind.N_TCHAN) { return true; };
@@ -5081,7 +5080,7 @@ fn indexbaseesz(c: *cgen, base: *node) i32 = {
}; };
// Generic struct field: if it's *T, element size is T's size. // Generic struct field: if it's *T, element size is T's size.
let lkind: i32 = tn.kind; let lkind: nkind = tn.kind;
let sname: str; let sname: str;
sname.ptr = nil; sname.len = 0; sname.ptr = nil; sname.len = 0;
if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TNAME) { sname = tn.str; };
@@ -5180,7 +5179,7 @@ fn dotinnerstructptr(c: *cgen, n: *node) *node = {
// bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback). // bool/str-byte, 8 otherwise — same shape as C cgen's esz fallback).
fn elemsizeof(t: *node) i32 = { fn elemsizeof(t: *node) i32 = {
if (t == nil) { return 1; }; if (t == nil) { return 1; };
let k: i32 = t.kind; let k: nkind = t.kind;
let elem: *node = nil; let elem: *node = nil;
if (k == nkind.N_TPTR) { elem = t.lhs; }; if (k == nkind.N_TPTR) { elem = t.lhs; };
if (k == nkind.N_TSLICE) { elem = t.lhs; }; if (k == nkind.N_TSLICE) { elem = t.lhs; };
@@ -5216,7 +5215,7 @@ fn elemsizeof(t: *node) i32 = {
// being wrong here is byte-different asm vs C, not bad runtime. // being wrong here is byte-different asm vs C, not bad runtime.
fn nodeisunsigned(c: *cgen, n: *node) bool = { fn nodeisunsigned(c: *cgen, n: *node) bool = {
if (n == nil) { return false; }; if (n == nil) { return false; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_IDENT) { if (k == nkind.N_IDENT) {
let nm: str = n.str; let nm: str = n.str;
let lc: *local = localfindnode(c, nm); let lc: *local = localfindnode(c, nm);
@@ -5232,7 +5231,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = {
let lc: *local = localfindnode(c, bn); let lc: *local = localfindnode(c, bn);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
let sname: str; let sname: str;
sname.ptr = nil; sname.len = 0; sname.ptr = nil; sname.len = 0;
@@ -5394,7 +5393,7 @@ export fn letslotsize(c: *cgen, n: *node) i32 = {
fn slotsize(c: *cgen, typn: *node) i32 = { fn slotsize(c: *cgen, typn: *node) i32 = {
if (typn == nil) { return 8; }; if (typn == nil) { return 8; };
let k: i32 = typn.kind; let k: nkind = typn.kind;
if (k == nkind.N_TPTR) { return 8; }; if (k == nkind.N_TPTR) { return 8; };
if (k == nkind.N_TFN) { return 8; }; if (k == nkind.N_TFN) { return 8; };
if (k == nkind.N_TCHAN) { return 8; }; if (k == nkind.N_TCHAN) { return 8; };
@@ -5481,7 +5480,7 @@ fn slotsize(c: *cgen, typn: *node) i32 = {
// only round to 8 for stack slots, not struct interiors). // only round to 8 for stack slots, not struct interiors).
fn fieldsize(c: *cgen, tnode: *node) i32 = { fn fieldsize(c: *cgen, tnode: *node) i32 = {
if (tnode == nil) { return 8; }; if (tnode == nil) { return 8; };
let k: i32 = tnode.kind; let k: nkind = tnode.kind;
if (k == nkind.N_TNAME) { if (k == nkind.N_TNAME) {
let nm: str = tnode.str; let nm: str = tnode.str;
if (streq(nm, "str")) { return 16; }; if (streq(nm, "str")) { return 16; };
@@ -5489,6 +5488,18 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = {
if (ps > 0) { return ps; }; if (ps > 0) { return ps; };
let si: *structinfo = structlookup(c, nm); let si: *structinfo = structlookup(c, nm);
if (si != nil) { return si.totsize; }; if (si != nil) { return si.totsize; };
// Enum: size of its storage type. Mirrors the C cgen, which
// reads Type.size off the TY_ENUM (which inherits from .sub).
let en: *enumtype = enumlookup(c, nm);
if (en != nil) {
if (en.storage != nil) {
if (en.storage.kind == nkind.N_TNAME) {
let sps: i32 = primsize(en.storage.str);
if (sps > 0) { return sps; };
};
};
return 4; // default storage is i32
};
return 8; return 8;
}; };
if (k == nkind.N_TPTR) { return 8; }; if (k == nkind.N_TPTR) { return 8; };
@@ -5739,7 +5750,7 @@ use strconv;
fn cgexpr(c: *cgen, n: *node) void = { fn cgexpr(c: *cgen, n: *node) void = {
if (n == nil) { return; }; if (n == nil) { return; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_INTLIT) { if (k == nkind.N_INTLIT) {
// Print signed (i64), not unsigned (u64). C cgen uses // Print signed (i64), not unsigned (u64). C cgen uses
@@ -5974,7 +5985,7 @@ fn cgtypetest(c: *cgen, n: *node) void = {
// through the cast pass-through too). // through the cast pass-through too).
fn isenumexpr(c: *cgen, e: *node) bool = { fn isenumexpr(c: *cgen, e: *node) bool = {
if (e == nil) { return false; }; if (e == nil) { return false; };
let k: i32 = e.kind; let k: nkind = e.kind;
if (k == nkind.N_DOT) { if (k == nkind.N_DOT) {
if (e.lhs != nil) { if (e.lhs != nil) {
if (e.lhs.kind == nkind.N_IDENT) { if (e.lhs.kind == nkind.N_IDENT) {
@@ -6367,7 +6378,7 @@ fn cgdot(c: *cgen, n: *node) void = {
let lc: *local = localfindnode(c, nm); let lc: *local = localfindnode(c, nm);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
// Pointer-to-struct: deref then field load. // Pointer-to-struct: deref then field load.
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
@@ -6524,7 +6535,7 @@ fn cgdot(c: *cgen, n: *node) void = {
// pointed-to header. C cgen does the same. // pointed-to header. C cgen does the same.
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
let inner: *node = tn.lhs; let inner: *node = tn.lhs;
let innerkind: i32 = -1; let innerkind: nkind = nkind.N_NONE;
if (inner != nil) { innerkind = inner.kind; }; if (inner != nil) { innerkind = inner.kind; };
let innerstr: bool = false; let innerstr: bool = false;
if (innerkind == nkind.N_TNAME) { if (innerkind == nkind.N_TNAME) {
@@ -6788,7 +6799,7 @@ fn cgcall(c: *cgen, n: *node) void = {
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
if (tn != nil) { if (tn != nil) {
let lkind: i32 = tn.kind; let lkind: nkind = tn.kind;
let sname: str; let sname: str;
sname.ptr = nil; sname.len = 0; sname.ptr = nil; sname.len = 0;
if (lkind == nkind.N_TNAME) { sname = tn.str; }; if (lkind == nkind.N_TNAME) { sname = tn.str; };
@@ -7008,7 +7019,7 @@ fn cgassign(c: *cgen, n: *node) void = {
let lc: *local = localfindnode(c, bn); let lc: *local = localfindnode(c, bn);
if (lc != nil) { if (lc != nil) {
let tn: *node = lc.tnode; let tn: *node = lc.tnode;
let lkind: i32 = -1; let lkind: nkind = nkind.N_NONE;
if (tn != nil) { lkind = tn.kind; }; if (tn != nil) { lkind = tn.kind; };
// Pointer-to-struct: deref then store. // Pointer-to-struct: deref then store.
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
@@ -7114,7 +7125,7 @@ fn cgassign(c: *cgen, n: *node) void = {
if (delta >= 0) { if (delta >= 0) {
if (lkind == nkind.N_TPTR) { if (lkind == nkind.N_TPTR) {
let inner: *node = tn.lhs; let inner: *node = tn.lhs;
let innerkind: i32 = -1; let innerkind: nkind = nkind.N_NONE;
if (inner != nil) { innerkind = inner.kind; }; if (inner != nil) { innerkind = inner.kind; };
let innerstr: bool = false; let innerstr: bool = false;
if (innerkind == nkind.N_TNAME) { if (innerkind == nkind.N_TNAME) {
@@ -7322,7 +7333,7 @@ use strconv;
fn cgstmt(c: *cgen, n: *node) void = { fn cgstmt(c: *cgen, n: *node) void = {
if (n == nil) { return; }; if (n == nil) { return; };
let k: i32 = n.kind; let k: nkind = n.kind;
if (k == nkind.N_BLOCK) { cgblock(c, n); return; }; if (k == nkind.N_BLOCK) { cgblock(c, n); return; };
@@ -8306,8 +8317,11 @@ export fn cgfile(c: *cgen, file: *node) void = {
c.strlits = nil; c.strlits = nil;
c.strlitseq = 0; c.strlitseq = 0;
collectaliases(c, file); collectaliases(c, file);
collectstructs(c, file); // Enums must register before structs — fieldsize on a tkind-typed
// field needs the enum's storage size, otherwise it falls back to
// 8 (wrong load width).
collectenums(c, file); collectenums(c, file);
collectstructs(c, file);
collectdefs(c, file); collectdefs(c, file);
collectfnrets(c, file); collectfnrets(c, file);
fficollect(c, file); fficollect(c, file);
@@ -8417,7 +8431,7 @@ fn aliaslookup(c: *cgen, name: str) *node = {
fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = { fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
if (e == nil) { return false; }; if (e == nil) { return false; };
let k: i32 = e.kind; let k: nkind = e.kind;
if (k == nkind.N_INTLIT) { *out = e.uval; return true; }; if (k == nkind.N_INTLIT) { *out = e.uval; return true; };
if (k == nkind.N_RUNELIT) { *out = e.uval; return true; }; if (k == nkind.N_RUNELIT) { *out = e.uval; return true; };
if (k == nkind.N_TRUE) { *out = 1u64; return true; }; if (k == nkind.N_TRUE) { *out = 1u64; return true; };
@@ -8438,7 +8452,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
let b: u64; let b: u64;
if (!enumevalmember(prev, e.lhs, &a)) { return false; }; if (!enumevalmember(prev, e.lhs, &a)) { return false; };
if (!enumevalmember(prev, e.rhs, &b)) { return false; }; if (!enumevalmember(prev, e.rhs, &b)) { return false; };
let op: i32 = e.op; let op: tkind = e.op;
if (op == tkind.TK_PLUS) { *out = a + b; return true; }; if (op == tkind.TK_PLUS) { *out = a + b; return true; };
if (op == tkind.TK_MINUS) { *out = a - b; return true; }; if (op == tkind.TK_MINUS) { *out = a - b; return true; };
if (op == tkind.TK_STAR) { *out = a * b; return true; }; if (op == tkind.TK_STAR) { *out = a * b; return true; };
@@ -8460,7 +8474,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
if (k == nkind.N_UN) { if (k == nkind.N_UN) {
let v: u64; let v: u64;
if (!enumevalmember(prev, e.lhs, &v)) { return false; }; if (!enumevalmember(prev, e.lhs, &v)) { return false; };
let op: i32 = e.op; let op: tkind = e.op;
if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; }; if (op == tkind.TK_MINUS) { *out = (-(v: i64)): u64; return true; };
if (op == tkind.TK_TILDE) { *out = ~v; return true; }; if (op == tkind.TK_TILDE) { *out = ~v; return true; };
if (op == tkind.TK_PLUS) { *out = v; return true; }; if (op == tkind.TK_PLUS) { *out = v; return true; };