selfhost: mirror enum tokens + AST + parsetype branch

Parses byte-identical to the C frontend on enum sources (verified
via `diff` of wwdump vs wwdump_ww -a on an enum-using fixture).
The selfhost side reserves the slot in the AST and TY_* enums so
later check.ww and cgen mirror work doesn't shift numeric IDs.

Codegen-side enum support (member-value folding in cgdot, enum↔int
pass-through in cgtypeassert) is deferred — current selfhost sources
don't use enum, so 990_selfhost / 995_self_rebuild stay green.

main.combined.ww in wwdump/ and w6c/ regenerated by `ww build` as
a side effect of `make wwstage`.
This commit is contained in:
2026-05-12 04:20:59 +09:00
parent 34817eedcd
commit 5bf30f209c
7 changed files with 1161 additions and 6 deletions

View File

@@ -192,6 +192,40 @@ fn parsetype(p: *parser) *node = {
return n;
};
if (p.curkind == TK_ENUM) {
// `enum [storage] { NAME [= expr], ... }`
// Storage defaults to i32 (lhs == nil). Each member is an
// N_TENUMMEMBER with str=name and lhs = value expr or nil
// (auto-increment when omitted).
advance(p);
let n: *node = newnode(p.a, N_TENUM, pf, pl, pc);
if (p.curkind != TK_LBRACE) {
n.lhs = parsetype(p);
};
expecttok(p, TK_LBRACE, "expected '{' after enum");
let mhead: *node = nil;
let mtail: *node = nil;
for (p.curkind != TK_RBRACE) {
if (p.curkind == TK_EOF) { break; };
let mpf: str = p.curfile;
let mpl: i32 = p.curline;
let mpc: i32 = p.curcol;
let m: *node = newnode(p.a, N_TENUMMEMBER, mpf, mpl, mpc);
let mid: str;
expectident(p, &mid);
m.str = mid;
if (accepttok(p, TK_ASSIGN)) {
m.lhs = parseexpr(p);
};
if (mhead == nil) { mhead = m; mtail = m; }
else { mtail.next = m; mtail = m; };
if (!accepttok(p, TK_COMMA)) { break; };
};
expecttok(p, TK_RBRACE, "expected '}' after enum members");
n.list = mhead;
return n;
};
if (p.curkind == TK_VOID) {
// `void` keyword in type-expr context — emit as N_TNAME so
// resolution treats it like any other primitive name.