ww: add Hare-style is/as postfix ops on tagged unions
`e is T` returns bool (variant tag == T's index); `e as T` unwraps to T or exit(1) on mismatch. Postfix, same precedence as `:` cast. TK_IS / N_TYPETEST / N_TYPEASSERT appended at the tail of their enums so every prior numeric value stays unchanged — the 990_selfhost wwdump-diff stays byte-clean. Cgen mirrors the match-case slot-based load (tag at +0, value at +8/+16), so an N_IDENT tagged-union local works just like a match scrutinee. Selfhost cgen inlines the slot resolution because the wwstage cgen drops sign bits on `*i32` output parameters in this position. Renames `errors.is` -> `errors.equal` (the only naming collision; the existing comment already noted it shared shape with strings.equal/bytes.equal).
This commit is contained in:
@@ -84,7 +84,12 @@ def N_TRYUNW: i32 = 57;
|
||||
def N_MLET: i32 = 58;
|
||||
def N_MASSIGN: i32 = 59;
|
||||
|
||||
def N_LAST: i32 = 60;
|
||||
// Appended at the tail to keep all prior N_* values stable. The
|
||||
// 990_selfhost test diffs astprint against the C side byte-for-byte.
|
||||
def N_TYPETEST: i32 = 60;
|
||||
def N_TYPEASSERT: i32 = 61;
|
||||
|
||||
def N_LAST: i32 = 62;
|
||||
|
||||
// ---- Node -------------------------------------------------------------
|
||||
|
||||
@@ -183,6 +188,8 @@ fn nkname(k: i32) str = {
|
||||
if (k == N_TRYUNW) { return "tryunw"; };
|
||||
if (k == N_MLET) { return "mlet"; };
|
||||
if (k == N_MASSIGN) { return "massign"; };
|
||||
if (k == N_TYPETEST) { return "typetest"; };
|
||||
if (k == N_TYPEASSERT) { return "typeassert"; };
|
||||
if (k == N_LAST) { return "last"; };
|
||||
return "?";
|
||||
};
|
||||
|
||||
@@ -105,7 +105,12 @@ def TK_LARROW: i32 = 79;
|
||||
def TK_ARROW: i32 = 80;
|
||||
def TK_FATARROW: i32 = 81;
|
||||
|
||||
def TK_LAST: i32 = 82;
|
||||
// Appended at the tail (not grouped with the keyword block) so every
|
||||
// pre-existing TK_* value stays unchanged — the 990_selfhost test
|
||||
// diffs wwdump output against the C side, byte for byte.
|
||||
def TK_IS: i32 = 82;
|
||||
|
||||
def TK_LAST: i32 = 83;
|
||||
|
||||
// ---- Pos / Tok --------------------------------------------------------
|
||||
//
|
||||
@@ -164,6 +169,7 @@ export fn kwlookup(p: *u8, n: i32) i32 = {
|
||||
if (streqn(p, "fn", n)) { return TK_FN; };
|
||||
if (streqn(p, "for", n)) { return TK_FOR; };
|
||||
if (streqn(p, "if", n)) { return TK_IF; };
|
||||
if (streqn(p, "is", n)) { return TK_IS; };
|
||||
if (streqn(p, "let", n)) { return TK_LET; };
|
||||
if (streqn(p, "match", n)) { return TK_MATCH; };
|
||||
if (streqn(p, "nil", n)) { return TK_NIL; };
|
||||
@@ -215,6 +221,7 @@ export fn tokname(k: i32) str = {
|
||||
if (k == TK_TRUE) { return "true"; };
|
||||
if (k == TK_FALSE) { return "false"; };
|
||||
if (k == TK_AS) { return "as"; };
|
||||
if (k == TK_IS) { return "is"; };
|
||||
if (k == TK_STATIC) { return "static"; };
|
||||
if (k == TK_MATCH) { return "match"; };
|
||||
if (k == TK_CONST) { return "const"; };
|
||||
|
||||
@@ -306,6 +306,26 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
|
||||
cur = n;
|
||||
continue;
|
||||
};
|
||||
// Hare-style postfix:
|
||||
// `e as T` — assert lhs is variant T (abort otherwise) → T
|
||||
// `e is T` — bool: does lhs currently hold variant T?
|
||||
// Same precedence level as the `:` cast.
|
||||
if (p.curkind == TK_AS) {
|
||||
advance(p);
|
||||
let n: *node = newnode(p.a, N_TYPEASSERT, pf, pl, pc);
|
||||
n.lhs = cur;
|
||||
n.rhs = parsetype(p);
|
||||
cur = n;
|
||||
continue;
|
||||
};
|
||||
if (p.curkind == TK_IS) {
|
||||
advance(p);
|
||||
let n: *node = newnode(p.a, N_TYPETEST, pf, pl, pc);
|
||||
n.lhs = cur;
|
||||
n.rhs = parsetype(p);
|
||||
cur = n;
|
||||
continue;
|
||||
};
|
||||
break;
|
||||
};
|
||||
return cur;
|
||||
|
||||
Reference in New Issue
Block a user