wcc: match-as-expression with yield
`match (e) { ... }` can now sit in expression position, with each
arm using `yield expr;` to produce the match's value:
let v = match (r) {
case let n: i32 => yield n + 1;
case let s: str => yield s.len: i32 + 100;
};
TK_YIELD keyword + N_YIELD AST node, both appended at the tail of
their enums to keep prior numeric values byte-stable for the
wwdump-diff gates.
Checker: cexpr for N_MATCH walks each arm's body looking for the
first N_YIELD; the match's type is the unified yield type (or
ty_void if no yield, preserving the statement-form semantics).
Mismatched arm yields are flagged.
Cgen: a yield-target stack (separate from the loop break stack)
holds each enclosing match's end label. N_YIELD evaluates its
expression into AX (and BX for str) and JMPs to the topmost entry.
cgmatch pushes its end label on entry and pops on exit.
Selfhost mirror: lib/ww/lex/tok.ww kwtab+name, lib/ww/ast.ww
N_YIELD def+print, lib/ww/parse/stmt.ww yield-stmt; selfhost cgen
adds a yieldbuf to the cgen struct and a cgyield helper. Verified
end-to-end: a yield-using program compiled via the wwstage cgen
matches the C-cgen build's exit code.
This commit is contained in:
@@ -41,9 +41,26 @@ fn cgstmt(c: *cgen, n: *node) void = {
|
||||
if (k == N_BREAK) { cgbreak(c, n); return; };
|
||||
if (k == N_CONTINUE) { cgcontinue(c, n); return; };
|
||||
|
||||
if (k == N_YIELD) { cgyield(c, n); return; };
|
||||
|
||||
c.lastwasreturn = 0;
|
||||
};
|
||||
|
||||
fn cgyield(c: *cgen, n: *node) void = {
|
||||
// Evaluate the value into AX (and BX for str), then JMP to the
|
||||
// enclosing match's end label. Falls through silently if there
|
||||
// is no active match — should be a checker error eventually.
|
||||
if (n.lhs != nil) { cgexpr(c, n.lhs); };
|
||||
if (c.yieldtop > 0) {
|
||||
let tgt: str = c.yieldbuf[c.yieldtop - 1];
|
||||
emitline("\tJMP\t");
|
||||
emitline(tgt);
|
||||
emitline("\n");
|
||||
};
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
|
||||
fn cgblock(c: *cgen, n: *node) void = {
|
||||
let s: *node = n.list;
|
||||
for (s != nil) {
|
||||
|
||||
Reference in New Issue
Block a user