strconv: graduate to (T | invalid | overflow); add void expression
`type invalid = i32` (payload: byte index of first bad rune; mirrors
Hare's strconv::invalid = !size) and `type overflow = void` (Hare's
overflow = !void). stoi64/stou64 now return these instead of the
str-error placeholder. atoi64 dropped — lib/CLAUDE.md says graduate
in one go, don't keep both shapes around.
To produce the void variant payload, `void` is now a real
expression literal (TK_VOID kw, N_VOIDLIT). It evaluates to ty_void;
codegen emits MOVQ $0, AX. Both kinds are appended at the tail of
their enums to keep prior numeric values byte-stable for the
wwdump-diff fixtures.
check_file reorder: USE declarations are now installed in pass 1
alongside the type-decl placeholders so dotted type references
(`strconv.invalid` from a typedecl body) resolve. DEF/FN/LET silently
overwrite a USE-occupied slot — matches the old behavior where USE
silently no-op'd when a same-name fn/def existed (the conflict
manifested in selfhost main.combined.ww at `use parse;` colliding
with `export fn parse(a)`).
selfhost mirror: lib/ww/lex/tok.ww kwtab+name; lib/ww/ast.ww
N_VOIDLIT def+print; lib/ww/parse/{expr,parse}.ww TK_VOID handling;
selfhost/cmd/wcc/cgenexpr.ww N_VOIDLIT codegen.
This commit is contained in:
@@ -88,8 +88,9 @@ def N_MASSIGN: i32 = 59;
|
||||
// 990_selfhost test diffs astprint against the C side byte-for-byte.
|
||||
def N_TYPETEST: i32 = 60;
|
||||
def N_TYPEASSERT: i32 = 61;
|
||||
def N_VOIDLIT: i32 = 62;
|
||||
|
||||
def N_LAST: i32 = 62;
|
||||
def N_LAST: i32 = 63;
|
||||
|
||||
// ---- Node -------------------------------------------------------------
|
||||
|
||||
@@ -190,6 +191,7 @@ fn nkname(k: i32) str = {
|
||||
if (k == N_MASSIGN) { return "massign"; };
|
||||
if (k == N_TYPETEST) { return "typetest"; };
|
||||
if (k == N_TYPEASSERT) { return "typeassert"; };
|
||||
if (k == N_VOIDLIT) { return "voidlit"; };
|
||||
if (k == N_LAST) { return "last"; };
|
||||
return "?";
|
||||
};
|
||||
|
||||
@@ -108,9 +108,10 @@ def TK_FATARROW: i32 = 81;
|
||||
// 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_IS: i32 = 82;
|
||||
def TK_VOID: i32 = 83;
|
||||
|
||||
def TK_LAST: i32 = 83;
|
||||
def TK_LAST: i32 = 84;
|
||||
|
||||
// ---- Pos / Tok --------------------------------------------------------
|
||||
//
|
||||
@@ -181,6 +182,7 @@ export fn kwlookup(p: *u8, n: i32) i32 = {
|
||||
if (streqn(p, "true", n)) { return TK_TRUE; };
|
||||
if (streqn(p, "type", n)) { return TK_TYPE; };
|
||||
if (streqn(p, "use", n)) { return TK_USE; };
|
||||
if (streqn(p, "void", n)) { return TK_VOID; };
|
||||
return TK_NONE;
|
||||
};
|
||||
|
||||
@@ -222,6 +224,7 @@ export fn tokname(k: i32) str = {
|
||||
if (k == TK_FALSE) { return "false"; };
|
||||
if (k == TK_AS) { return "as"; };
|
||||
if (k == TK_IS) { return "is"; };
|
||||
if (k == TK_VOID) { return "void"; };
|
||||
if (k == TK_STATIC) { return "static"; };
|
||||
if (k == TK_MATCH) { return "match"; };
|
||||
if (k == TK_CONST) { return "const"; };
|
||||
|
||||
@@ -52,6 +52,10 @@ fn parseprimary(p: *parser) *node = {
|
||||
advance(p);
|
||||
return newnode(p.a, N_NIL, pf, pl, pc);
|
||||
};
|
||||
if (p.curkind == TK_VOID) {
|
||||
advance(p);
|
||||
return newnode(p.a, N_VOIDLIT, pf, pl, pc);
|
||||
};
|
||||
if (p.curkind == TK_UNDER) {
|
||||
// Bare `_` — valid only as a discard lvalue. Emit an N_IDENT
|
||||
// with empty str; the checker rejects it outside lvalue
|
||||
|
||||
@@ -164,6 +164,15 @@ fn parsetype(p: *parser) *node = {
|
||||
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.
|
||||
let n: *node = newnode(p.a, N_TNAME, pf, pl, pc);
|
||||
n.str = "void";
|
||||
advance(p);
|
||||
return n;
|
||||
};
|
||||
|
||||
if (p.curkind == TK_IDENT) {
|
||||
let n: *node = newnode(p.a, N_TNAME, pf, pl, pc);
|
||||
n.str = p.curtext;
|
||||
|
||||
Reference in New Issue
Block a user