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:
@@ -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(b) && type_assignable(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",
|
||||
type_name(c->a, a), type_name(c->a, b));
|
||||
}
|
||||
|
||||
@@ -295,21 +295,6 @@ type_assignable(Type *dst, Type *src)
|
||||
if (dst->kind == TY_NAMED && type_eq(dst->under, src)) 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. */
|
||||
if (dst->kind == TY_TUPLE && src->kind == TY_TUPLE) {
|
||||
Tparam *pa = dst->params, *pb = src->params;
|
||||
|
||||
@@ -103,11 +103,11 @@ type nkind = enum i32 {
|
||||
// ---- Node -------------------------------------------------------------
|
||||
|
||||
type node = struct {
|
||||
kind: i32,
|
||||
kind: nkind,
|
||||
file: str,
|
||||
line: 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,
|
||||
uval: u64,
|
||||
fval: f64,
|
||||
@@ -125,7 +125,7 @@ type node = struct {
|
||||
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
|
||||
n.kind = k;
|
||||
n.file = file;
|
||||
@@ -136,7 +136,7 @@ export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = {
|
||||
|
||||
// ---- printer ----------------------------------------------------------
|
||||
|
||||
fn nkname(k: i32) str = {
|
||||
fn nkname(k: nkind) str = {
|
||||
if (k == nkind.N_NONE) { return "none"; };
|
||||
if (k == nkind.N_INTLIT) { return "int"; };
|
||||
if (k == nkind.N_FLOATLIT) { return "float"; };
|
||||
|
||||
@@ -460,7 +460,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = {
|
||||
return;
|
||||
};
|
||||
};
|
||||
let k: i32 = kwlookup(p, n: i32);
|
||||
let k: tkind = kwlookup(p, n: i32);
|
||||
if (k != tkind.TK_NONE) {
|
||||
out.kind = k;
|
||||
} else {
|
||||
@@ -553,7 +553,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = {
|
||||
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.file = start.file;
|
||||
out.line = start.line;
|
||||
|
||||
@@ -134,8 +134,7 @@ type pos = struct {
|
||||
};
|
||||
|
||||
type tok = struct {
|
||||
kind: i32, // holds a `tkind` value; bare i32 so the cgen's
|
||||
// fixed 8B/struct-field layout matches the C side
|
||||
kind: tkind,
|
||||
file: str, // path of the source the token came from
|
||||
line: 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,
|
||||
// or tkind.TK_NONE if it's an ordinary identifier. Linear search over a
|
||||
// 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, "break", n)) { return tkind.TK_BREAK; };
|
||||
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
|
||||
// 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_EOF) { return "EOF"; };
|
||||
if (k == tkind.TK_ERR) { return "ERR"; };
|
||||
|
||||
@@ -199,7 +199,7 @@ fn parseprimary(p: *parser) *node = {
|
||||
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;
|
||||
if (p.curkind == closekind) { return; };
|
||||
let head: *node = nil;
|
||||
@@ -355,7 +355,7 @@ fn parseunary(p: *parser) *node = {
|
||||
let pf: str = p.curfile;
|
||||
let pl: i32 = p.curline;
|
||||
let pc: i32 = p.curcol;
|
||||
let k: i32 = p.curkind;
|
||||
let k: tkind = p.curkind;
|
||||
if (k == tkind.TK_MINUS) {
|
||||
advance(p);
|
||||
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 = {
|
||||
let cur: *node = lhs;
|
||||
for (true) {
|
||||
let op: i32 = p.curkind;
|
||||
let op: tkind = p.curkind;
|
||||
let pr: i32 = bprec(op);
|
||||
if (pr == 0) { return cur; };
|
||||
if (pr < minp) { return cur; };
|
||||
@@ -425,7 +425,7 @@ fn parseexpr(p: *parser) *node = {
|
||||
let pf: str = p.curfile;
|
||||
let pl: i32 = p.curline;
|
||||
let pc: i32 = p.curcol;
|
||||
let op: i32 = p.curkind;
|
||||
let op: tkind = p.curkind;
|
||||
advance(p);
|
||||
let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc);
|
||||
n.op = op;
|
||||
|
||||
@@ -24,7 +24,7 @@ type parser = struct {
|
||||
// nocast: while inside `[...]` we treat ':' as the slice
|
||||
// separator, not the cast operator. Mirrors parse.c's flag.
|
||||
nocast: i32,
|
||||
curkind: i32, // holds a `tkind` value (relaxation lets it mix)
|
||||
curkind: tkind,
|
||||
curfile: str,
|
||||
curline: 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 accepttok(p: *parser, k: i32) bool = {
|
||||
fn accepttok(p: *parser, k: tkind) bool = {
|
||||
if (p.curkind == k) { advance(p); return true; };
|
||||
return false;
|
||||
};
|
||||
@@ -66,7 +66,7 @@ fn errmsg(p: *parser, msg: str) void = {
|
||||
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; };
|
||||
errmsg(p, what);
|
||||
return false;
|
||||
@@ -313,7 +313,7 @@ fn parsetype(p: *parser) *node = {
|
||||
// and the ?/! try operators are not yet wired — they'll arrive as the
|
||||
// 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_AND) { return 2; };
|
||||
if (k == tkind.TK_EQ) { return 3; };
|
||||
@@ -335,7 +335,7 @@ fn bprec(k: i32) i32 = {
|
||||
return 0;
|
||||
};
|
||||
|
||||
fn isassignop(k: i32) bool = {
|
||||
fn isassignop(k: tkind) bool = {
|
||||
if (k == tkind.TK_ASSIGN) { return true; };
|
||||
if (k == tkind.TK_PLUSEQ) { return true; };
|
||||
if (k == tkind.TK_MINUSEQ) { return true; };
|
||||
|
||||
@@ -22,7 +22,7 @@ type skind = enum i32 {
|
||||
|
||||
type sym = struct {
|
||||
name: str,
|
||||
skind: i32,
|
||||
skind: skind,
|
||||
type_: *tinfo,
|
||||
decl: *node,
|
||||
exported: i32,
|
||||
@@ -98,7 +98,7 @@ export fn scopelookup(s: *scope, name: str) *sym = {
|
||||
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; };
|
||||
let sy: *sym = amalloc(s.a, 80u64): *sym;
|
||||
sy.name = name;
|
||||
|
||||
@@ -74,7 +74,7 @@ type tparam = struct {
|
||||
};
|
||||
|
||||
type tinfo = struct {
|
||||
kind: i32,
|
||||
kind: tykind,
|
||||
size: u64,
|
||||
align: u64,
|
||||
sub: *tinfo, // ptr/slice/array/chan element
|
||||
@@ -120,13 +120,13 @@ type tctx = struct {
|
||||
|
||||
// ---- constructors -----------------------------------------------------
|
||||
|
||||
export fn newtype(a: *arena, k: i32) *tinfo = {
|
||||
export fn newtype(a: *arena, k: tykind) *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 = {
|
||||
fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = {
|
||||
let t: *tinfo = newtype(a, k);
|
||||
t.name = nm;
|
||||
t.size = sz;
|
||||
@@ -216,7 +216,7 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = {
|
||||
|
||||
export fn typeisint(t: *tinfo) bool = {
|
||||
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_I16) { 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 = {
|
||||
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_F64) { 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 = {
|
||||
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_U16) { 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 = {
|
||||
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_FLOAT) { 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 (b == nil) { 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_SLICE) { return typeeq(a.sub, b.sub); };
|
||||
if (k == tykind.TY_CHAN) { return typeeq(a.sub, b.sub); };
|
||||
|
||||
@@ -581,8 +581,7 @@ type pos = struct {
|
||||
};
|
||||
|
||||
type tok = struct {
|
||||
kind: i32, // holds a `tkind` value; bare i32 so the cgen's
|
||||
// fixed 8B/struct-field layout matches the C side
|
||||
kind: tkind,
|
||||
file: str, // path of the source the token came from
|
||||
line: 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,
|
||||
// or tkind.TK_NONE if it's an ordinary identifier. Linear search over a
|
||||
// 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, "break", n)) { return tkind.TK_BREAK; };
|
||||
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
|
||||
// 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_EOF) { return "EOF"; };
|
||||
if (k == tkind.TK_ERR) { return "ERR"; };
|
||||
@@ -1421,7 +1420,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = {
|
||||
return;
|
||||
};
|
||||
};
|
||||
let k: i32 = kwlookup(p, n: i32);
|
||||
let k: tkind = kwlookup(p, n: i32);
|
||||
if (k != tkind.TK_NONE) {
|
||||
out.kind = k;
|
||||
} else {
|
||||
@@ -1514,7 +1513,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = {
|
||||
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.file = start.file;
|
||||
out.line = start.line;
|
||||
@@ -1766,11 +1765,11 @@ type nkind = enum i32 {
|
||||
// ---- Node -------------------------------------------------------------
|
||||
|
||||
type node = struct {
|
||||
kind: i32,
|
||||
kind: nkind,
|
||||
file: str,
|
||||
line: 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,
|
||||
uval: u64,
|
||||
fval: f64,
|
||||
@@ -1788,7 +1787,7 @@ type node = struct {
|
||||
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
|
||||
n.kind = k;
|
||||
n.file = file;
|
||||
@@ -1799,7 +1798,7 @@ export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = {
|
||||
|
||||
// ---- printer ----------------------------------------------------------
|
||||
|
||||
fn nkname(k: i32) str = {
|
||||
fn nkname(k: nkind) str = {
|
||||
if (k == nkind.N_NONE) { return "none"; };
|
||||
if (k == nkind.N_INTLIT) { return "int"; };
|
||||
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);
|
||||
};
|
||||
|
||||
fn parsearglist(p: *parser, closekind: i32, headout: **node) void = {
|
||||
fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = {
|
||||
*headout = nil;
|
||||
if (p.curkind == closekind) { return; };
|
||||
let head: *node = nil;
|
||||
@@ -2378,7 +2377,7 @@ fn parseunary(p: *parser) *node = {
|
||||
let pf: str = p.curfile;
|
||||
let pl: i32 = p.curline;
|
||||
let pc: i32 = p.curcol;
|
||||
let k: i32 = p.curkind;
|
||||
let k: tkind = p.curkind;
|
||||
if (k == tkind.TK_MINUS) {
|
||||
advance(p);
|
||||
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 = {
|
||||
let cur: *node = lhs;
|
||||
for (true) {
|
||||
let op: i32 = p.curkind;
|
||||
let op: tkind = p.curkind;
|
||||
let pr: i32 = bprec(op);
|
||||
if (pr == 0) { return cur; };
|
||||
if (pr < minp) { return cur; };
|
||||
@@ -2448,7 +2447,7 @@ fn parseexpr(p: *parser) *node = {
|
||||
let pf: str = p.curfile;
|
||||
let pl: i32 = p.curline;
|
||||
let pc: i32 = p.curcol;
|
||||
let op: i32 = p.curkind;
|
||||
let op: tkind = p.curkind;
|
||||
advance(p);
|
||||
let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc);
|
||||
n.op = op;
|
||||
@@ -2933,7 +2932,7 @@ type parser = struct {
|
||||
// nocast: while inside `[...]` we treat ':' as the slice
|
||||
// separator, not the cast operator. Mirrors parse.c's flag.
|
||||
nocast: i32,
|
||||
curkind: i32, // holds a `tkind` value (relaxation lets it mix)
|
||||
curkind: tkind,
|
||||
curfile: str,
|
||||
curline: 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 accepttok(p: *parser, k: i32) bool = {
|
||||
fn accepttok(p: *parser, k: tkind) bool = {
|
||||
if (p.curkind == k) { advance(p); return true; };
|
||||
return false;
|
||||
};
|
||||
@@ -2975,7 +2974,7 @@ fn errmsg(p: *parser, msg: str) void = {
|
||||
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; };
|
||||
errmsg(p, what);
|
||||
return false;
|
||||
@@ -3222,7 +3221,7 @@ fn parsetype(p: *parser) *node = {
|
||||
// and the ?/! try operators are not yet wired — they'll arrive as the
|
||||
// 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_AND) { return 2; };
|
||||
if (k == tkind.TK_EQ) { return 3; };
|
||||
@@ -3244,7 +3243,7 @@ fn bprec(k: i32) i32 = {
|
||||
return 0;
|
||||
};
|
||||
|
||||
fn isassignop(k: i32) bool = {
|
||||
fn isassignop(k: tkind) bool = {
|
||||
if (k == tkind.TK_ASSIGN) { return true; };
|
||||
if (k == tkind.TK_PLUSEQ) { return true; };
|
||||
if (k == tkind.TK_MINUSEQ) { return true; };
|
||||
@@ -3402,7 +3401,7 @@ type tparam = struct {
|
||||
};
|
||||
|
||||
type tinfo = struct {
|
||||
kind: i32,
|
||||
kind: tykind,
|
||||
size: u64,
|
||||
align: u64,
|
||||
sub: *tinfo, // ptr/slice/array/chan element
|
||||
@@ -3448,13 +3447,13 @@ type tctx = struct {
|
||||
|
||||
// ---- constructors -----------------------------------------------------
|
||||
|
||||
export fn newtype(a: *arena, k: i32) *tinfo = {
|
||||
export fn newtype(a: *arena, k: tykind) *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 = {
|
||||
fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = {
|
||||
let t: *tinfo = newtype(a, k);
|
||||
t.name = nm;
|
||||
t.size = sz;
|
||||
@@ -3544,7 +3543,7 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = {
|
||||
|
||||
export fn typeisint(t: *tinfo) bool = {
|
||||
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_I16) { 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 = {
|
||||
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_F64) { 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 = {
|
||||
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_U16) { 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 = {
|
||||
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_FLOAT) { 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 (b == nil) { 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_SLICE) { 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 {
|
||||
name: str,
|
||||
skind: i32,
|
||||
skind: skind,
|
||||
type_: *tinfo,
|
||||
decl: *node,
|
||||
exported: i32,
|
||||
@@ -3769,7 +3768,7 @@ export fn scopelookup(s: *scope, name: str) *sym = {
|
||||
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; };
|
||||
let sy: *sym = amalloc(s.a, 80u64): *sym;
|
||||
sy.name = name;
|
||||
@@ -3857,7 +3856,7 @@ fn seedprimitives(c: *checker) void = {
|
||||
// the name so forward references resolve.
|
||||
fn installdecl(c: *checker, d: *node) void = {
|
||||
if (d == nil) { return; };
|
||||
let k: i32 = d.kind;
|
||||
let k: nkind = d.kind;
|
||||
let nm: str = d.str;
|
||||
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; };
|
||||
@@ -3876,7 +3875,7 @@ fn installdecl(c: *checker, d: *node) void = {
|
||||
// the same pass — they need the same scope state.
|
||||
fn resolvewalk(c: *checker, n: *node) void = {
|
||||
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
|
||||
// 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 (bb == nil) { 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_TPTR) { 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).
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
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_FLOATLIT) { return mktname(c, "untyped_float"); };
|
||||
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.
|
||||
d = file.list;
|
||||
for (d != nil) {
|
||||
let k: i32 = d.kind;
|
||||
let k: nkind = d.kind;
|
||||
if (k == nkind.N_FNDECL) {
|
||||
if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type
|
||||
resolvefnbody(c, d);
|
||||
@@ -4863,7 +4862,7 @@ fn pushargsrev(c: *cgen, arg: *node) i32 = {
|
||||
|
||||
fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||
if (n == nil) { return false; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_IDENT) {
|
||||
let nm: str = n.str;
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
@@ -4879,7 +4878,7 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||
// (str args take two slots: ptr + len).
|
||||
fn nodeisstr(c: *cgen, n: *node) bool = {
|
||||
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_IDENT) {
|
||||
let nm: str = n.str;
|
||||
@@ -4920,7 +4919,7 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
||||
let lc: *local = localfindnode(c, base.str);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
if (lkind == nkind.N_TNAME) { sname = tn.str; };
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
@@ -4989,7 +4988,7 @@ fn typenodeisunsigned(t: *node) bool = {
|
||||
// false here even when their *slot* rounds up to 8.
|
||||
fn typeis8byteprimitive(c: *cgen, t: *node) bool = {
|
||||
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_TFN) { 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.
|
||||
let lkind: i32 = tn.kind;
|
||||
let lkind: nkind = tn.kind;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
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).
|
||||
fn elemsizeof(t: *node) i32 = {
|
||||
if (t == nil) { return 1; };
|
||||
let k: i32 = t.kind;
|
||||
let k: nkind = t.kind;
|
||||
let elem: *node = nil;
|
||||
if (k == nkind.N_TPTR) { 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.
|
||||
fn nodeisunsigned(c: *cgen, n: *node) bool = {
|
||||
if (n == nil) { return false; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_IDENT) {
|
||||
let nm: str = n.str;
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
@@ -5232,7 +5231,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = {
|
||||
let lc: *local = localfindnode(c, bn);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
let sname: str;
|
||||
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 = {
|
||||
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_TFN) { 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).
|
||||
fn fieldsize(c: *cgen, tnode: *node) i32 = {
|
||||
if (tnode == nil) { return 8; };
|
||||
let k: i32 = tnode.kind;
|
||||
let k: nkind = tnode.kind;
|
||||
if (k == nkind.N_TNAME) {
|
||||
let nm: str = tnode.str;
|
||||
if (streq(nm, "str")) { return 16; };
|
||||
@@ -5489,6 +5488,18 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = {
|
||||
if (ps > 0) { return ps; };
|
||||
let si: *structinfo = structlookup(c, nm);
|
||||
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;
|
||||
};
|
||||
if (k == nkind.N_TPTR) { return 8; };
|
||||
@@ -5739,7 +5750,7 @@ use strconv;
|
||||
|
||||
fn cgexpr(c: *cgen, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
|
||||
if (k == nkind.N_INTLIT) {
|
||||
// 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).
|
||||
fn isenumexpr(c: *cgen, e: *node) bool = {
|
||||
if (e == nil) { return false; };
|
||||
let k: i32 = e.kind;
|
||||
let k: nkind = e.kind;
|
||||
if (k == nkind.N_DOT) {
|
||||
if (e.lhs != nil) {
|
||||
if (e.lhs.kind == nkind.N_IDENT) {
|
||||
@@ -6367,7 +6378,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
// Pointer-to-struct: deref then field load.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
@@ -6524,7 +6535,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// pointed-to header. C cgen does the same.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let innerkind: i32 = -1;
|
||||
let innerkind: nkind = nkind.N_NONE;
|
||||
if (inner != nil) { innerkind = inner.kind; };
|
||||
let innerstr: bool = false;
|
||||
if (innerkind == nkind.N_TNAME) {
|
||||
@@ -6788,7 +6799,7 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
if (tn != nil) {
|
||||
let lkind: i32 = tn.kind;
|
||||
let lkind: nkind = tn.kind;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
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);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
// Pointer-to-struct: deref then store.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
@@ -7114,7 +7125,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (delta >= 0) {
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let innerkind: i32 = -1;
|
||||
let innerkind: nkind = nkind.N_NONE;
|
||||
if (inner != nil) { innerkind = inner.kind; };
|
||||
let innerstr: bool = false;
|
||||
if (innerkind == nkind.N_TNAME) {
|
||||
@@ -7322,7 +7333,7 @@ use strconv;
|
||||
|
||||
fn cgstmt(c: *cgen, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
|
||||
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.strlitseq = 0;
|
||||
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);
|
||||
collectstructs(c, file);
|
||||
collectdefs(c, file);
|
||||
collectfnrets(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 = {
|
||||
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_RUNELIT) { *out = e.uval; 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;
|
||||
if (!enumevalmember(prev, e.lhs, &a)) { 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_MINUS) { *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) {
|
||||
let v: u64;
|
||||
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_TILDE) { *out = ~v; return true; };
|
||||
if (op == tkind.TK_PLUS) { *out = v; return true; };
|
||||
|
||||
@@ -89,7 +89,7 @@ fn aliaslookup(c: *cgen, name: str) *node = {
|
||||
|
||||
fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
|
||||
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_RUNELIT) { *out = e.uval; 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;
|
||||
if (!enumevalmember(prev, e.lhs, &a)) { 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_MINUS) { *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) {
|
||||
let v: u64;
|
||||
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_TILDE) { *out = ~v; return true; };
|
||||
if (op == tkind.TK_PLUS) { *out = v; return true; };
|
||||
|
||||
@@ -278,8 +278,11 @@ export fn cgfile(c: *cgen, file: *node) void = {
|
||||
c.strlits = nil;
|
||||
c.strlitseq = 0;
|
||||
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);
|
||||
collectstructs(c, file);
|
||||
collectdefs(c, file);
|
||||
collectfnrets(c, file);
|
||||
fficollect(c, file);
|
||||
|
||||
@@ -22,7 +22,7 @@ use strconv;
|
||||
|
||||
fn cgexpr(c: *cgen, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
|
||||
if (k == nkind.N_INTLIT) {
|
||||
// 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).
|
||||
fn isenumexpr(c: *cgen, e: *node) bool = {
|
||||
if (e == nil) { return false; };
|
||||
let k: i32 = e.kind;
|
||||
let k: nkind = e.kind;
|
||||
if (k == nkind.N_DOT) {
|
||||
if (e.lhs != nil) {
|
||||
if (e.lhs.kind == nkind.N_IDENT) {
|
||||
@@ -650,7 +650,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
// Pointer-to-struct: deref then field load.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
@@ -807,7 +807,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// pointed-to header. C cgen does the same.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let innerkind: i32 = -1;
|
||||
let innerkind: nkind = nkind.N_NONE;
|
||||
if (inner != nil) { innerkind = inner.kind; };
|
||||
let innerstr: bool = false;
|
||||
if (innerkind == nkind.N_TNAME) {
|
||||
@@ -1071,7 +1071,7 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
if (tn != nil) {
|
||||
let lkind: i32 = tn.kind;
|
||||
let lkind: nkind = tn.kind;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
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);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
// Pointer-to-struct: deref then store.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
@@ -1397,7 +1397,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (delta >= 0) {
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let innerkind: i32 = -1;
|
||||
let innerkind: nkind = nkind.N_NONE;
|
||||
if (inner != nil) { innerkind = inner.kind; };
|
||||
let innerstr: bool = false;
|
||||
if (innerkind == nkind.N_TNAME) {
|
||||
|
||||
@@ -20,7 +20,7 @@ use strconv;
|
||||
|
||||
fn cgstmt(c: *cgen, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
|
||||
if (k == nkind.N_BLOCK) { cgblock(c, n); return; };
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ fn pushargsrev(c: *cgen, arg: *node) i32 = {
|
||||
|
||||
fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||
if (n == nil) { return false; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_IDENT) {
|
||||
let nm: str = n.str;
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
@@ -169,7 +169,7 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||
// (str args take two slots: ptr + len).
|
||||
fn nodeisstr(c: *cgen, n: *node) bool = {
|
||||
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_IDENT) {
|
||||
let nm: str = n.str;
|
||||
@@ -210,7 +210,7 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
||||
let lc: *local = localfindnode(c, base.str);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
if (lkind == nkind.N_TNAME) { sname = tn.str; };
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
@@ -279,7 +279,7 @@ fn typenodeisunsigned(t: *node) bool = {
|
||||
// false here even when their *slot* rounds up to 8.
|
||||
fn typeis8byteprimitive(c: *cgen, t: *node) bool = {
|
||||
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_TFN) { 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.
|
||||
let lkind: i32 = tn.kind;
|
||||
let lkind: nkind = tn.kind;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
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).
|
||||
fn elemsizeof(t: *node) i32 = {
|
||||
if (t == nil) { return 1; };
|
||||
let k: i32 = t.kind;
|
||||
let k: nkind = t.kind;
|
||||
let elem: *node = nil;
|
||||
if (k == nkind.N_TPTR) { 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.
|
||||
fn nodeisunsigned(c: *cgen, n: *node) bool = {
|
||||
if (n == nil) { return false; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_IDENT) {
|
||||
let nm: str = n.str;
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
@@ -522,7 +522,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = {
|
||||
let lc: *local = localfindnode(c, bn);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
let sname: str;
|
||||
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 = {
|
||||
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_TFN) { 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).
|
||||
fn fieldsize(c: *cgen, tnode: *node) i32 = {
|
||||
if (tnode == nil) { return 8; };
|
||||
let k: i32 = tnode.kind;
|
||||
let k: nkind = tnode.kind;
|
||||
if (k == nkind.N_TNAME) {
|
||||
let nm: str = tnode.str;
|
||||
if (streq(nm, "str")) { return 16; };
|
||||
@@ -779,6 +779,18 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = {
|
||||
if (ps > 0) { return ps; };
|
||||
let si: *structinfo = structlookup(c, nm);
|
||||
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;
|
||||
};
|
||||
if (k == nkind.N_TPTR) { return 8; };
|
||||
|
||||
@@ -68,7 +68,7 @@ fn seedprimitives(c: *checker) void = {
|
||||
// the name so forward references resolve.
|
||||
fn installdecl(c: *checker, d: *node) void = {
|
||||
if (d == nil) { return; };
|
||||
let k: i32 = d.kind;
|
||||
let k: nkind = d.kind;
|
||||
let nm: str = d.str;
|
||||
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; };
|
||||
@@ -87,7 +87,7 @@ fn installdecl(c: *checker, d: *node) void = {
|
||||
// the same pass — they need the same scope state.
|
||||
fn resolvewalk(c: *checker, n: *node) void = {
|
||||
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
|
||||
// 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 (bb == nil) { 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_TPTR) { 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).
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
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_FLOATLIT) { return mktname(c, "untyped_float"); };
|
||||
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.
|
||||
d = file.list;
|
||||
for (d != nil) {
|
||||
let k: i32 = d.kind;
|
||||
let k: nkind = d.kind;
|
||||
if (k == nkind.N_FNDECL) {
|
||||
if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type
|
||||
resolvefnbody(c, d);
|
||||
|
||||
@@ -581,8 +581,7 @@ type pos = struct {
|
||||
};
|
||||
|
||||
type tok = struct {
|
||||
kind: i32, // holds a `tkind` value; bare i32 so the cgen's
|
||||
// fixed 8B/struct-field layout matches the C side
|
||||
kind: tkind,
|
||||
file: str, // path of the source the token came from
|
||||
line: 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,
|
||||
// or tkind.TK_NONE if it's an ordinary identifier. Linear search over a
|
||||
// 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, "break", n)) { return tkind.TK_BREAK; };
|
||||
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
|
||||
// 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_EOF) { return "EOF"; };
|
||||
if (k == tkind.TK_ERR) { return "ERR"; };
|
||||
@@ -1421,7 +1420,7 @@ fn lexident(l: *lex, start: *pos, out: *tok) void = {
|
||||
return;
|
||||
};
|
||||
};
|
||||
let k: i32 = kwlookup(p, n: i32);
|
||||
let k: tkind = kwlookup(p, n: i32);
|
||||
if (k != tkind.TK_NONE) {
|
||||
out.kind = k;
|
||||
} else {
|
||||
@@ -1514,7 +1513,7 @@ fn lexrune(l: *lex, start: *pos, out: *tok) void = {
|
||||
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.file = start.file;
|
||||
out.line = start.line;
|
||||
@@ -1766,11 +1765,11 @@ type nkind = enum i32 {
|
||||
// ---- Node -------------------------------------------------------------
|
||||
|
||||
type node = struct {
|
||||
kind: i32,
|
||||
kind: nkind,
|
||||
file: str,
|
||||
line: 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,
|
||||
uval: u64,
|
||||
fval: f64,
|
||||
@@ -1788,7 +1787,7 @@ type node = struct {
|
||||
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
|
||||
n.kind = k;
|
||||
n.file = file;
|
||||
@@ -1799,7 +1798,7 @@ export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = {
|
||||
|
||||
// ---- printer ----------------------------------------------------------
|
||||
|
||||
fn nkname(k: i32) str = {
|
||||
fn nkname(k: nkind) str = {
|
||||
if (k == nkind.N_NONE) { return "none"; };
|
||||
if (k == nkind.N_INTLIT) { return "int"; };
|
||||
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);
|
||||
};
|
||||
|
||||
fn parsearglist(p: *parser, closekind: i32, headout: **node) void = {
|
||||
fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = {
|
||||
*headout = nil;
|
||||
if (p.curkind == closekind) { return; };
|
||||
let head: *node = nil;
|
||||
@@ -2378,7 +2377,7 @@ fn parseunary(p: *parser) *node = {
|
||||
let pf: str = p.curfile;
|
||||
let pl: i32 = p.curline;
|
||||
let pc: i32 = p.curcol;
|
||||
let k: i32 = p.curkind;
|
||||
let k: tkind = p.curkind;
|
||||
if (k == tkind.TK_MINUS) {
|
||||
advance(p);
|
||||
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 = {
|
||||
let cur: *node = lhs;
|
||||
for (true) {
|
||||
let op: i32 = p.curkind;
|
||||
let op: tkind = p.curkind;
|
||||
let pr: i32 = bprec(op);
|
||||
if (pr == 0) { return cur; };
|
||||
if (pr < minp) { return cur; };
|
||||
@@ -2448,7 +2447,7 @@ fn parseexpr(p: *parser) *node = {
|
||||
let pf: str = p.curfile;
|
||||
let pl: i32 = p.curline;
|
||||
let pc: i32 = p.curcol;
|
||||
let op: i32 = p.curkind;
|
||||
let op: tkind = p.curkind;
|
||||
advance(p);
|
||||
let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc);
|
||||
n.op = op;
|
||||
@@ -2933,7 +2932,7 @@ type parser = struct {
|
||||
// nocast: while inside `[...]` we treat ':' as the slice
|
||||
// separator, not the cast operator. Mirrors parse.c's flag.
|
||||
nocast: i32,
|
||||
curkind: i32, // holds a `tkind` value (relaxation lets it mix)
|
||||
curkind: tkind,
|
||||
curfile: str,
|
||||
curline: 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 accepttok(p: *parser, k: i32) bool = {
|
||||
fn accepttok(p: *parser, k: tkind) bool = {
|
||||
if (p.curkind == k) { advance(p); return true; };
|
||||
return false;
|
||||
};
|
||||
@@ -2975,7 +2974,7 @@ fn errmsg(p: *parser, msg: str) void = {
|
||||
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; };
|
||||
errmsg(p, what);
|
||||
return false;
|
||||
@@ -3222,7 +3221,7 @@ fn parsetype(p: *parser) *node = {
|
||||
// and the ?/! try operators are not yet wired — they'll arrive as the
|
||||
// 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_AND) { return 2; };
|
||||
if (k == tkind.TK_EQ) { return 3; };
|
||||
@@ -3244,7 +3243,7 @@ fn bprec(k: i32) i32 = {
|
||||
return 0;
|
||||
};
|
||||
|
||||
fn isassignop(k: i32) bool = {
|
||||
fn isassignop(k: tkind) bool = {
|
||||
if (k == tkind.TK_ASSIGN) { return true; };
|
||||
if (k == tkind.TK_PLUSEQ) { return true; };
|
||||
if (k == tkind.TK_MINUSEQ) { return true; };
|
||||
@@ -3402,7 +3401,7 @@ type tparam = struct {
|
||||
};
|
||||
|
||||
type tinfo = struct {
|
||||
kind: i32,
|
||||
kind: tykind,
|
||||
size: u64,
|
||||
align: u64,
|
||||
sub: *tinfo, // ptr/slice/array/chan element
|
||||
@@ -3448,13 +3447,13 @@ type tctx = struct {
|
||||
|
||||
// ---- constructors -----------------------------------------------------
|
||||
|
||||
export fn newtype(a: *arena, k: i32) *tinfo = {
|
||||
export fn newtype(a: *arena, k: tykind) *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 = {
|
||||
fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = {
|
||||
let t: *tinfo = newtype(a, k);
|
||||
t.name = nm;
|
||||
t.size = sz;
|
||||
@@ -3544,7 +3543,7 @@ export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = {
|
||||
|
||||
export fn typeisint(t: *tinfo) bool = {
|
||||
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_I16) { 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 = {
|
||||
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_F64) { 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 = {
|
||||
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_U16) { 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 = {
|
||||
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_FLOAT) { 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 (b == nil) { 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_SLICE) { 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 {
|
||||
name: str,
|
||||
skind: i32,
|
||||
skind: skind,
|
||||
type_: *tinfo,
|
||||
decl: *node,
|
||||
exported: i32,
|
||||
@@ -3769,7 +3768,7 @@ export fn scopelookup(s: *scope, name: str) *sym = {
|
||||
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; };
|
||||
let sy: *sym = amalloc(s.a, 80u64): *sym;
|
||||
sy.name = name;
|
||||
@@ -3857,7 +3856,7 @@ fn seedprimitives(c: *checker) void = {
|
||||
// the name so forward references resolve.
|
||||
fn installdecl(c: *checker, d: *node) void = {
|
||||
if (d == nil) { return; };
|
||||
let k: i32 = d.kind;
|
||||
let k: nkind = d.kind;
|
||||
let nm: str = d.str;
|
||||
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; };
|
||||
@@ -3876,7 +3875,7 @@ fn installdecl(c: *checker, d: *node) void = {
|
||||
// the same pass — they need the same scope state.
|
||||
fn resolvewalk(c: *checker, n: *node) void = {
|
||||
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
|
||||
// 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 (bb == nil) { 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_TPTR) { 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).
|
||||
fn exprtype(c: *checker, e: *node) *node = {
|
||||
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_FLOATLIT) { return mktname(c, "untyped_float"); };
|
||||
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.
|
||||
d = file.list;
|
||||
for (d != nil) {
|
||||
let k: i32 = d.kind;
|
||||
let k: nkind = d.kind;
|
||||
if (k == nkind.N_FNDECL) {
|
||||
if (d.lhs != nil) { resolvewalk(c, d.lhs); }; // return type
|
||||
resolvefnbody(c, d);
|
||||
@@ -4863,7 +4862,7 @@ fn pushargsrev(c: *cgen, arg: *node) i32 = {
|
||||
|
||||
fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||
if (n == nil) { return false; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_IDENT) {
|
||||
let nm: str = n.str;
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
@@ -4879,7 +4878,7 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||
// (str args take two slots: ptr + len).
|
||||
fn nodeisstr(c: *cgen, n: *node) bool = {
|
||||
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_IDENT) {
|
||||
let nm: str = n.str;
|
||||
@@ -4920,7 +4919,7 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
||||
let lc: *local = localfindnode(c, base.str);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
if (lkind == nkind.N_TNAME) { sname = tn.str; };
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
@@ -4989,7 +4988,7 @@ fn typenodeisunsigned(t: *node) bool = {
|
||||
// false here even when their *slot* rounds up to 8.
|
||||
fn typeis8byteprimitive(c: *cgen, t: *node) bool = {
|
||||
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_TFN) { 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.
|
||||
let lkind: i32 = tn.kind;
|
||||
let lkind: nkind = tn.kind;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
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).
|
||||
fn elemsizeof(t: *node) i32 = {
|
||||
if (t == nil) { return 1; };
|
||||
let k: i32 = t.kind;
|
||||
let k: nkind = t.kind;
|
||||
let elem: *node = nil;
|
||||
if (k == nkind.N_TPTR) { 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.
|
||||
fn nodeisunsigned(c: *cgen, n: *node) bool = {
|
||||
if (n == nil) { return false; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_IDENT) {
|
||||
let nm: str = n.str;
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
@@ -5232,7 +5231,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = {
|
||||
let lc: *local = localfindnode(c, bn);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
let sname: str;
|
||||
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 = {
|
||||
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_TFN) { 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).
|
||||
fn fieldsize(c: *cgen, tnode: *node) i32 = {
|
||||
if (tnode == nil) { return 8; };
|
||||
let k: i32 = tnode.kind;
|
||||
let k: nkind = tnode.kind;
|
||||
if (k == nkind.N_TNAME) {
|
||||
let nm: str = tnode.str;
|
||||
if (streq(nm, "str")) { return 16; };
|
||||
@@ -5489,6 +5488,18 @@ fn fieldsize(c: *cgen, tnode: *node) i32 = {
|
||||
if (ps > 0) { return ps; };
|
||||
let si: *structinfo = structlookup(c, nm);
|
||||
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;
|
||||
};
|
||||
if (k == nkind.N_TPTR) { return 8; };
|
||||
@@ -5739,7 +5750,7 @@ use strconv;
|
||||
|
||||
fn cgexpr(c: *cgen, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
|
||||
if (k == nkind.N_INTLIT) {
|
||||
// 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).
|
||||
fn isenumexpr(c: *cgen, e: *node) bool = {
|
||||
if (e == nil) { return false; };
|
||||
let k: i32 = e.kind;
|
||||
let k: nkind = e.kind;
|
||||
if (k == nkind.N_DOT) {
|
||||
if (e.lhs != nil) {
|
||||
if (e.lhs.kind == nkind.N_IDENT) {
|
||||
@@ -6367,7 +6378,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
// Pointer-to-struct: deref then field load.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
@@ -6524,7 +6535,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// pointed-to header. C cgen does the same.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let innerkind: i32 = -1;
|
||||
let innerkind: nkind = nkind.N_NONE;
|
||||
if (inner != nil) { innerkind = inner.kind; };
|
||||
let innerstr: bool = false;
|
||||
if (innerkind == nkind.N_TNAME) {
|
||||
@@ -6788,7 +6799,7 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
if (tn != nil) {
|
||||
let lkind: i32 = tn.kind;
|
||||
let lkind: nkind = tn.kind;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
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);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: i32 = -1;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
// Pointer-to-struct: deref then store.
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
@@ -7114,7 +7125,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (delta >= 0) {
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let innerkind: i32 = -1;
|
||||
let innerkind: nkind = nkind.N_NONE;
|
||||
if (inner != nil) { innerkind = inner.kind; };
|
||||
let innerstr: bool = false;
|
||||
if (innerkind == nkind.N_TNAME) {
|
||||
@@ -7322,7 +7333,7 @@ use strconv;
|
||||
|
||||
fn cgstmt(c: *cgen, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
let k: i32 = n.kind;
|
||||
let k: nkind = n.kind;
|
||||
|
||||
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.strlitseq = 0;
|
||||
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);
|
||||
collectstructs(c, file);
|
||||
collectdefs(c, file);
|
||||
collectfnrets(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 = {
|
||||
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_RUNELIT) { *out = e.uval; 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;
|
||||
if (!enumevalmember(prev, e.lhs, &a)) { 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_MINUS) { *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) {
|
||||
let v: u64;
|
||||
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_TILDE) { *out = ~v; return true; };
|
||||
if (op == tkind.TK_PLUS) { *out = v; return true; };
|
||||
|
||||
Reference in New Issue
Block a user