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:
@@ -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"; };
|
||||
|
||||
Reference in New Issue
Block a user