lib/ww/lex: tokname if-ladder -> switch (Wave-2 structural)

Fold the ~88-arm `if (k == tkind.TK_X) return "..."` ladder in tokname
to a single `switch (k)` with the terminal `return "<?>"` as the
fall-past default. kwlookup stays an if-ladder: it dispatches on
streqn() string compares over distinct literals, which a value-switch
can't express.

Not byte-id-neutral (if-chain -> switch dispatch changes the asm), so
the ladder->switch equivalence is pinned by a new table-driven test:
lib/ww/lex/toktest.ww drives tokname over every tkind plus the
out-of-band "<?>" fallback, and kwlookup over every keyword plus
non-keywords, wired as 904_tok_run (same `ww run` @test shape as
904_ascii_run). The 990_selfhost wwdump diff only covers kinds that
appear in its corpus.

Regenerates the w6c + wwdump combined.ww amalgamations (tokname region
only).
This commit is contained in:
2026-06-02 21:58:39 +09:00
parent 79e647b34d
commit e027d3eec4
6 changed files with 505 additions and 265 deletions

View File

@@ -443,7 +443,7 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \
$(BIN)/test_sort_run \
$(BIN)/test_bufio_run $(BIN)/test_random_run \
$(BIN)/test_asserttyped_gap \
$(BIN)/test_ascii_run
$(BIN)/test_ascii_run $(BIN)/test_tok_run
$(BIN)/test_smoke: test/wcc/000_smoke.c $(LIB)/libwcc.a | $(BIN)
$(CC) $(CFLAGS) $(INCS) -o $@ $< -L$(LIB) -lwcc
@@ -1508,6 +1508,10 @@ $(BIN)/test_ascii_run: test/wcc/904_ascii_run.c $(BIN)/ww $(BIN)/w6c \
$(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_tok_run: test/wcc/904_tok_run.c $(BIN)/ww $(BIN)/w6c \
$(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<
$(BIN)/test_decimal_run: test/wcc/922_decimal_run.c $(BIN)/ww $(BIN)/w6c \
$(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
$(CC) $(CFLAGS) -o $@ $<

View File

@@ -202,102 +202,104 @@ export fn kwlookup(p: *u8, n: i32) tkind = {
// the C tokname()'s output exactly so wwdump output diffs cleanly.
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"; };
if (k == tkind.TK_IDENT) { return "IDENT"; };
if (k == tkind.TK_INT) { return "INT"; };
if (k == tkind.TK_FLOAT) { return "FLOAT"; };
if (k == tkind.TK_RUNE) { return "RUNE"; };
if (k == tkind.TK_STR) { return "STR"; };
switch (k) {
case tkind.TK_NONE: return "<none>";
case tkind.TK_EOF: return "EOF";
case tkind.TK_ERR: return "ERR";
case tkind.TK_IDENT: return "IDENT";
case tkind.TK_INT: return "INT";
case tkind.TK_FLOAT: return "FLOAT";
case tkind.TK_RUNE: return "RUNE";
case tkind.TK_STR: return "STR";
if (k == tkind.TK_FN) { return "fn"; };
if (k == tkind.TK_LET) { return "let"; };
if (k == tkind.TK_DEF) { return "def"; };
if (k == tkind.TK_IF) { return "if"; };
if (k == tkind.TK_ELSE) { return "else"; };
if (k == tkind.TK_FOR) { return "for"; };
if (k == tkind.TK_SWITCH) { return "switch"; };
if (k == tkind.TK_CASE) { return "case"; };
if (k == tkind.TK_RETURN) { return "return"; };
if (k == tkind.TK_USE) { return "import"; };
if (k == tkind.TK_TYPE) { return "type"; };
if (k == tkind.TK_STRUCT) { return "struct"; };
if (k == tkind.TK_DEFER) { return "defer"; };
if (k == tkind.TK_BREAK) { return "break"; };
if (k == tkind.TK_CONTINUE) { return "continue"; };
if (k == tkind.TK_EXPORT) { return "export"; };
if (k == tkind.TK_PROC) { return "proc"; };
if (k == tkind.TK_CHAN) { return "chan"; };
if (k == tkind.TK_NIL) { return "nil"; };
if (k == tkind.TK_TRUE) { return "true"; };
if (k == tkind.TK_FALSE) { return "false"; };
if (k == tkind.TK_AS) { return "as"; };
if (k == tkind.TK_IS) { return "is"; };
if (k == tkind.TK_VOID) { return "void"; };
if (k == tkind.TK_YIELD) { return "yield"; };
if (k == tkind.TK_STATIC) { return "static"; };
if (k == tkind.TK_MATCH) { return "match"; };
if (k == tkind.TK_CONST) { return "const"; };
if (k == tkind.TK_UNDER) { return "_"; };
if (k == tkind.TK_ENUM) { return "enum"; };
if (k == tkind.TK_MODULE) { return "package"; };
case tkind.TK_FN: return "fn";
case tkind.TK_LET: return "let";
case tkind.TK_DEF: return "def";
case tkind.TK_IF: return "if";
case tkind.TK_ELSE: return "else";
case tkind.TK_FOR: return "for";
case tkind.TK_SWITCH: return "switch";
case tkind.TK_CASE: return "case";
case tkind.TK_RETURN: return "return";
case tkind.TK_USE: return "import";
case tkind.TK_TYPE: return "type";
case tkind.TK_STRUCT: return "struct";
case tkind.TK_DEFER: return "defer";
case tkind.TK_BREAK: return "break";
case tkind.TK_CONTINUE: return "continue";
case tkind.TK_EXPORT: return "export";
case tkind.TK_PROC: return "proc";
case tkind.TK_CHAN: return "chan";
case tkind.TK_NIL: return "nil";
case tkind.TK_TRUE: return "true";
case tkind.TK_FALSE: return "false";
case tkind.TK_AS: return "as";
case tkind.TK_IS: return "is";
case tkind.TK_VOID: return "void";
case tkind.TK_YIELD: return "yield";
case tkind.TK_STATIC: return "static";
case tkind.TK_MATCH: return "match";
case tkind.TK_CONST: return "const";
case tkind.TK_UNDER: return "_";
case tkind.TK_ENUM: return "enum";
case tkind.TK_MODULE: return "package";
if (k == tkind.TK_LPAREN) { return "("; };
if (k == tkind.TK_RPAREN) { return ")"; };
if (k == tkind.TK_LBRACE) { return "{"; };
if (k == tkind.TK_RBRACE) { return "}"; };
if (k == tkind.TK_LBRACK) { return "["; };
if (k == tkind.TK_RBRACK) { return "]"; };
if (k == tkind.TK_COMMA) { return ","; };
if (k == tkind.TK_SEMI) { return ";"; };
if (k == tkind.TK_COLON) { return ":"; };
if (k == tkind.TK_DOT) { return "."; };
if (k == tkind.TK_ELLIPSIS) { return "..."; };
if (k == tkind.TK_DOTDOT) { return ".."; };
if (k == tkind.TK_AT) { return "@"; };
if (k == tkind.TK_QUESTION) { return "?"; };
case tkind.TK_LPAREN: return "(";
case tkind.TK_RPAREN: return ")";
case tkind.TK_LBRACE: return "{";
case tkind.TK_RBRACE: return "}";
case tkind.TK_LBRACK: return "[";
case tkind.TK_RBRACK: return "]";
case tkind.TK_COMMA: return ",";
case tkind.TK_SEMI: return ";";
case tkind.TK_COLON: return ":";
case tkind.TK_DOT: return ".";
case tkind.TK_ELLIPSIS: return "...";
case tkind.TK_DOTDOT: return "..";
case tkind.TK_AT: return "@";
case tkind.TK_QUESTION: return "?";
if (k == tkind.TK_ASSIGN) { return "="; };
if (k == tkind.TK_PLUSEQ) { return "+="; };
if (k == tkind.TK_MINUSEQ) { return "-="; };
if (k == tkind.TK_STAREQ) { return "*="; };
if (k == tkind.TK_SLASHEQ) { return "/="; };
if (k == tkind.TK_PERCENTEQ) { return "%="; };
if (k == tkind.TK_AMPEQ) { return "&="; };
if (k == tkind.TK_PIPEEQ) { return "|="; };
if (k == tkind.TK_CARETEQ) { return "^="; };
if (k == tkind.TK_LSHIFTEQ) { return "<<="; };
if (k == tkind.TK_RSHIFTEQ) { return ">>="; };
case tkind.TK_ASSIGN: return "=";
case tkind.TK_PLUSEQ: return "+=";
case tkind.TK_MINUSEQ: return "-=";
case tkind.TK_STAREQ: return "*=";
case tkind.TK_SLASHEQ: return "/=";
case tkind.TK_PERCENTEQ: return "%=";
case tkind.TK_AMPEQ: return "&=";
case tkind.TK_PIPEEQ: return "|=";
case tkind.TK_CARETEQ: return "^=";
case tkind.TK_LSHIFTEQ: return "<<=";
case tkind.TK_RSHIFTEQ: return ">>=";
if (k == tkind.TK_PLUS) { return "+"; };
if (k == tkind.TK_MINUS) { return "-"; };
if (k == tkind.TK_STAR) { return "*"; };
if (k == tkind.TK_SLASH) { return "/"; };
if (k == tkind.TK_PERCENT) { return "%"; };
if (k == tkind.TK_AMP) { return "&"; };
if (k == tkind.TK_PIPE) { return "|"; };
if (k == tkind.TK_CARET) { return "^"; };
if (k == tkind.TK_TILDE) { return "~"; };
if (k == tkind.TK_LSHIFT) { return "<<"; };
if (k == tkind.TK_RSHIFT) { return ">>"; };
case tkind.TK_PLUS: return "+";
case tkind.TK_MINUS: return "-";
case tkind.TK_STAR: return "*";
case tkind.TK_SLASH: return "/";
case tkind.TK_PERCENT: return "%";
case tkind.TK_AMP: return "&";
case tkind.TK_PIPE: return "|";
case tkind.TK_CARET: return "^";
case tkind.TK_TILDE: return "~";
case tkind.TK_LSHIFT: return "<<";
case tkind.TK_RSHIFT: return ">>";
if (k == tkind.TK_EQ) { return "=="; };
if (k == tkind.TK_NEQ) { return "!="; };
if (k == tkind.TK_LT) { return "<"; };
if (k == tkind.TK_LE) { return "<="; };
if (k == tkind.TK_GT) { return ">"; };
if (k == tkind.TK_GE) { return ">="; };
case tkind.TK_EQ: return "==";
case tkind.TK_NEQ: return "!=";
case tkind.TK_LT: return "<";
case tkind.TK_LE: return "<=";
case tkind.TK_GT: return ">";
case tkind.TK_GE: return ">=";
if (k == tkind.TK_AND) { return "&&"; };
if (k == tkind.TK_OR) { return "||"; };
if (k == tkind.TK_NOT) { return "!"; };
case tkind.TK_AND: return "&&";
case tkind.TK_OR: return "||";
case tkind.TK_NOT: return "!";
if (k == tkind.TK_LARROW) { return "<-"; };
if (k == tkind.TK_ARROW) { return "->"; };
if (k == tkind.TK_FATARROW) { return "=>"; };
case tkind.TK_LARROW: return "<-";
case tkind.TK_ARROW: return "->";
case tkind.TK_FATARROW: return "=>";
if (k == tkind.TK_LAST) { return "<last>"; };
case tkind.TK_LAST: return "<last>";
};
return "<?>";
};

178
lib/ww/lex/toktest.ww Normal file
View File

@@ -0,0 +1,178 @@
// toktest — functional-equivalence pin for [[tokname]] and
// [[kwlookup]] after the if-ladder → switch fold (struct fold S1).
// Run with `ww run -I lib/ww/lex lib/ww/lex/toktest.ww`.
//
// tokname is checked against every tkind value (the full ladder the
// switch replaced, plus the unknown-kind fallback); kwlookup is
// checked against every keyword it recognises plus a non-keyword.
// A non-zero exit pinpoints the failing row (signalled + 10), same
// convention as asciitest. `package main` + bare `import tok/lex`
// mirrors wwdump (the only other external lex consumer).
package main;
import os;
import tok;
import lex;
let signalled: i32 = 0;
fn fail() void = { os.exit(signalled + 10); };
fn checkname(k: tkind, want: str) void = {
if (tokname(k) != want) { fail(); };
};
// One row per tkind value — same string the if-ladder returned. The
// final row pins the unknown-kind fallback ("<?>").
@test fn tokname_cases() void = {
signalled = 100; checkname(tkind.TK_NONE, "<none>");
signalled = 101; checkname(tkind.TK_EOF, "EOF");
signalled = 102; checkname(tkind.TK_ERR, "ERR");
signalled = 103; checkname(tkind.TK_IDENT, "IDENT");
signalled = 104; checkname(tkind.TK_INT, "INT");
signalled = 105; checkname(tkind.TK_FLOAT, "FLOAT");
signalled = 106; checkname(tkind.TK_RUNE, "RUNE");
signalled = 107; checkname(tkind.TK_STR, "STR");
signalled = 108; checkname(tkind.TK_FN, "fn");
signalled = 109; checkname(tkind.TK_LET, "let");
signalled = 110; checkname(tkind.TK_DEF, "def");
signalled = 111; checkname(tkind.TK_IF, "if");
signalled = 112; checkname(tkind.TK_ELSE, "else");
signalled = 113; checkname(tkind.TK_FOR, "for");
signalled = 114; checkname(tkind.TK_SWITCH, "switch");
signalled = 115; checkname(tkind.TK_CASE, "case");
signalled = 116; checkname(tkind.TK_RETURN, "return");
signalled = 117; checkname(tkind.TK_USE, "import");
signalled = 118; checkname(tkind.TK_TYPE, "type");
signalled = 119; checkname(tkind.TK_STRUCT, "struct");
signalled = 120; checkname(tkind.TK_DEFER, "defer");
signalled = 121; checkname(tkind.TK_BREAK, "break");
signalled = 122; checkname(tkind.TK_CONTINUE, "continue");
signalled = 123; checkname(tkind.TK_EXPORT, "export");
signalled = 124; checkname(tkind.TK_PROC, "proc");
signalled = 125; checkname(tkind.TK_CHAN, "chan");
signalled = 126; checkname(tkind.TK_NIL, "nil");
signalled = 127; checkname(tkind.TK_TRUE, "true");
signalled = 128; checkname(tkind.TK_FALSE, "false");
signalled = 129; checkname(tkind.TK_AS, "as");
signalled = 130; checkname(tkind.TK_IS, "is");
signalled = 131; checkname(tkind.TK_VOID, "void");
signalled = 132; checkname(tkind.TK_YIELD, "yield");
signalled = 133; checkname(tkind.TK_STATIC, "static");
signalled = 134; checkname(tkind.TK_MATCH, "match");
signalled = 135; checkname(tkind.TK_CONST, "const");
signalled = 136; checkname(tkind.TK_UNDER, "_");
signalled = 137; checkname(tkind.TK_ENUM, "enum");
signalled = 138; checkname(tkind.TK_MODULE, "package");
signalled = 139; checkname(tkind.TK_LPAREN, "(");
signalled = 140; checkname(tkind.TK_RPAREN, ")");
signalled = 141; checkname(tkind.TK_LBRACE, "{");
signalled = 142; checkname(tkind.TK_RBRACE, "}");
signalled = 143; checkname(tkind.TK_LBRACK, "[");
signalled = 144; checkname(tkind.TK_RBRACK, "]");
signalled = 145; checkname(tkind.TK_COMMA, ",");
signalled = 146; checkname(tkind.TK_SEMI, ";");
signalled = 147; checkname(tkind.TK_COLON, ":");
signalled = 148; checkname(tkind.TK_DOT, ".");
signalled = 149; checkname(tkind.TK_ELLIPSIS, "...");
signalled = 150; checkname(tkind.TK_DOTDOT, "..");
signalled = 151; checkname(tkind.TK_AT, "@");
signalled = 152; checkname(tkind.TK_QUESTION, "?");
signalled = 153; checkname(tkind.TK_ASSIGN, "=");
signalled = 154; checkname(tkind.TK_PLUSEQ, "+=");
signalled = 155; checkname(tkind.TK_MINUSEQ, "-=");
signalled = 156; checkname(tkind.TK_STAREQ, "*=");
signalled = 157; checkname(tkind.TK_SLASHEQ, "/=");
signalled = 158; checkname(tkind.TK_PERCENTEQ, "%=");
signalled = 159; checkname(tkind.TK_AMPEQ, "&=");
signalled = 160; checkname(tkind.TK_PIPEEQ, "|=");
signalled = 161; checkname(tkind.TK_CARETEQ, "^=");
signalled = 162; checkname(tkind.TK_LSHIFTEQ, "<<=");
signalled = 163; checkname(tkind.TK_RSHIFTEQ, ">>=");
signalled = 164; checkname(tkind.TK_PLUS, "+");
signalled = 165; checkname(tkind.TK_MINUS, "-");
signalled = 166; checkname(tkind.TK_STAR, "*");
signalled = 167; checkname(tkind.TK_SLASH, "/");
signalled = 168; checkname(tkind.TK_PERCENT, "%");
signalled = 169; checkname(tkind.TK_AMP, "&");
signalled = 170; checkname(tkind.TK_PIPE, "|");
signalled = 171; checkname(tkind.TK_CARET, "^");
signalled = 172; checkname(tkind.TK_TILDE, "~");
signalled = 173; checkname(tkind.TK_LSHIFT, "<<");
signalled = 174; checkname(tkind.TK_RSHIFT, ">>");
signalled = 175; checkname(tkind.TK_EQ, "==");
signalled = 176; checkname(tkind.TK_NEQ, "!=");
signalled = 177; checkname(tkind.TK_LT, "<");
signalled = 178; checkname(tkind.TK_LE, "<=");
signalled = 179; checkname(tkind.TK_GT, ">");
signalled = 180; checkname(tkind.TK_GE, ">=");
signalled = 181; checkname(tkind.TK_AND, "&&");
signalled = 182; checkname(tkind.TK_OR, "||");
signalled = 183; checkname(tkind.TK_NOT, "!");
signalled = 184; checkname(tkind.TK_LARROW, "<-");
signalled = 185; checkname(tkind.TK_ARROW, "->");
signalled = 186; checkname(tkind.TK_FATARROW, "=>");
signalled = 187; checkname(tkind.TK_LAST, "<last>");
// Unknown kind → the post-switch fallback. TK_LAST is the highest
// named value (87); 88 is out of band, exercising the "<?>" tail.
signalled = 188; checkname(88: tkind, "<?>");
};
fn checkkw(s: str, want: tkind) void = {
if (kwlookup(s.ptr, s.len) != want) { fail(); };
};
// Every keyword kwlookup recognises (mirrors the streqn ladder), plus
// non-keywords that must fall through to TK_NONE.
@test fn kwlookup_cases() void = {
signalled = 200; checkkw("as", tkind.TK_AS);
signalled = 201; checkkw("break", tkind.TK_BREAK);
signalled = 202; checkkw("case", tkind.TK_CASE);
signalled = 203; checkkw("chan", tkind.TK_CHAN);
signalled = 204; checkkw("const", tkind.TK_CONST);
signalled = 205; checkkw("continue", tkind.TK_CONTINUE);
signalled = 206; checkkw("def", tkind.TK_DEF);
signalled = 207; checkkw("defer", tkind.TK_DEFER);
signalled = 208; checkkw("else", tkind.TK_ELSE);
signalled = 209; checkkw("enum", tkind.TK_ENUM);
signalled = 210; checkkw("export", tkind.TK_EXPORT);
signalled = 211; checkkw("false", tkind.TK_FALSE);
signalled = 212; checkkw("fn", tkind.TK_FN);
signalled = 213; checkkw("for", tkind.TK_FOR);
signalled = 214; checkkw("if", tkind.TK_IF);
signalled = 215; checkkw("is", tkind.TK_IS);
signalled = 216; checkkw("let", tkind.TK_LET);
signalled = 217; checkkw("import", tkind.TK_USE);
signalled = 218; checkkw("match", tkind.TK_MATCH);
signalled = 219; checkkw("nil", tkind.TK_NIL);
signalled = 220; checkkw("package", tkind.TK_MODULE);
signalled = 221; checkkw("proc", tkind.TK_PROC);
signalled = 222; checkkw("return", tkind.TK_RETURN);
signalled = 223; checkkw("static", tkind.TK_STATIC);
signalled = 224; checkkw("struct", tkind.TK_STRUCT);
signalled = 225; checkkw("switch", tkind.TK_SWITCH);
signalled = 226; checkkw("true", tkind.TK_TRUE);
signalled = 227; checkkw("type", tkind.TK_TYPE);
signalled = 228; checkkw("void", tkind.TK_VOID);
signalled = 229; checkkw("yield", tkind.TK_YIELD);
// Non-keywords fall through to TK_NONE — an ordinary identifier and
// a near-miss prefix of a real keyword.
signalled = 230; checkkw("xyzzy", tkind.TK_NONE);
signalled = 231; checkkw("fns", tkind.TK_NONE);
};
export fn main() i32 = {
signalled = 1; tokname_cases();
signalled = 2; kwlookup_cases();
return 0;
};

View File

@@ -6579,102 +6579,104 @@ export fn kwlookup(p: *u8, n: i32) tkind = {
// the C tokname()'s output exactly so wwdump output diffs cleanly.
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"; };
if (k == tkind.TK_IDENT) { return "IDENT"; };
if (k == tkind.TK_INT) { return "INT"; };
if (k == tkind.TK_FLOAT) { return "FLOAT"; };
if (k == tkind.TK_RUNE) { return "RUNE"; };
if (k == tkind.TK_STR) { return "STR"; };
switch (k) {
case tkind.TK_NONE: return "<none>";
case tkind.TK_EOF: return "EOF";
case tkind.TK_ERR: return "ERR";
case tkind.TK_IDENT: return "IDENT";
case tkind.TK_INT: return "INT";
case tkind.TK_FLOAT: return "FLOAT";
case tkind.TK_RUNE: return "RUNE";
case tkind.TK_STR: return "STR";
if (k == tkind.TK_FN) { return "fn"; };
if (k == tkind.TK_LET) { return "let"; };
if (k == tkind.TK_DEF) { return "def"; };
if (k == tkind.TK_IF) { return "if"; };
if (k == tkind.TK_ELSE) { return "else"; };
if (k == tkind.TK_FOR) { return "for"; };
if (k == tkind.TK_SWITCH) { return "switch"; };
if (k == tkind.TK_CASE) { return "case"; };
if (k == tkind.TK_RETURN) { return "return"; };
if (k == tkind.TK_USE) { return "import"; };
if (k == tkind.TK_TYPE) { return "type"; };
if (k == tkind.TK_STRUCT) { return "struct"; };
if (k == tkind.TK_DEFER) { return "defer"; };
if (k == tkind.TK_BREAK) { return "break"; };
if (k == tkind.TK_CONTINUE) { return "continue"; };
if (k == tkind.TK_EXPORT) { return "export"; };
if (k == tkind.TK_PROC) { return "proc"; };
if (k == tkind.TK_CHAN) { return "chan"; };
if (k == tkind.TK_NIL) { return "nil"; };
if (k == tkind.TK_TRUE) { return "true"; };
if (k == tkind.TK_FALSE) { return "false"; };
if (k == tkind.TK_AS) { return "as"; };
if (k == tkind.TK_IS) { return "is"; };
if (k == tkind.TK_VOID) { return "void"; };
if (k == tkind.TK_YIELD) { return "yield"; };
if (k == tkind.TK_STATIC) { return "static"; };
if (k == tkind.TK_MATCH) { return "match"; };
if (k == tkind.TK_CONST) { return "const"; };
if (k == tkind.TK_UNDER) { return "_"; };
if (k == tkind.TK_ENUM) { return "enum"; };
if (k == tkind.TK_MODULE) { return "package"; };
case tkind.TK_FN: return "fn";
case tkind.TK_LET: return "let";
case tkind.TK_DEF: return "def";
case tkind.TK_IF: return "if";
case tkind.TK_ELSE: return "else";
case tkind.TK_FOR: return "for";
case tkind.TK_SWITCH: return "switch";
case tkind.TK_CASE: return "case";
case tkind.TK_RETURN: return "return";
case tkind.TK_USE: return "import";
case tkind.TK_TYPE: return "type";
case tkind.TK_STRUCT: return "struct";
case tkind.TK_DEFER: return "defer";
case tkind.TK_BREAK: return "break";
case tkind.TK_CONTINUE: return "continue";
case tkind.TK_EXPORT: return "export";
case tkind.TK_PROC: return "proc";
case tkind.TK_CHAN: return "chan";
case tkind.TK_NIL: return "nil";
case tkind.TK_TRUE: return "true";
case tkind.TK_FALSE: return "false";
case tkind.TK_AS: return "as";
case tkind.TK_IS: return "is";
case tkind.TK_VOID: return "void";
case tkind.TK_YIELD: return "yield";
case tkind.TK_STATIC: return "static";
case tkind.TK_MATCH: return "match";
case tkind.TK_CONST: return "const";
case tkind.TK_UNDER: return "_";
case tkind.TK_ENUM: return "enum";
case tkind.TK_MODULE: return "package";
if (k == tkind.TK_LPAREN) { return "("; };
if (k == tkind.TK_RPAREN) { return ")"; };
if (k == tkind.TK_LBRACE) { return "{"; };
if (k == tkind.TK_RBRACE) { return "}"; };
if (k == tkind.TK_LBRACK) { return "["; };
if (k == tkind.TK_RBRACK) { return "]"; };
if (k == tkind.TK_COMMA) { return ","; };
if (k == tkind.TK_SEMI) { return ";"; };
if (k == tkind.TK_COLON) { return ":"; };
if (k == tkind.TK_DOT) { return "."; };
if (k == tkind.TK_ELLIPSIS) { return "..."; };
if (k == tkind.TK_DOTDOT) { return ".."; };
if (k == tkind.TK_AT) { return "@"; };
if (k == tkind.TK_QUESTION) { return "?"; };
case tkind.TK_LPAREN: return "(";
case tkind.TK_RPAREN: return ")";
case tkind.TK_LBRACE: return "{";
case tkind.TK_RBRACE: return "}";
case tkind.TK_LBRACK: return "[";
case tkind.TK_RBRACK: return "]";
case tkind.TK_COMMA: return ",";
case tkind.TK_SEMI: return ";";
case tkind.TK_COLON: return ":";
case tkind.TK_DOT: return ".";
case tkind.TK_ELLIPSIS: return "...";
case tkind.TK_DOTDOT: return "..";
case tkind.TK_AT: return "@";
case tkind.TK_QUESTION: return "?";
if (k == tkind.TK_ASSIGN) { return "="; };
if (k == tkind.TK_PLUSEQ) { return "+="; };
if (k == tkind.TK_MINUSEQ) { return "-="; };
if (k == tkind.TK_STAREQ) { return "*="; };
if (k == tkind.TK_SLASHEQ) { return "/="; };
if (k == tkind.TK_PERCENTEQ) { return "%="; };
if (k == tkind.TK_AMPEQ) { return "&="; };
if (k == tkind.TK_PIPEEQ) { return "|="; };
if (k == tkind.TK_CARETEQ) { return "^="; };
if (k == tkind.TK_LSHIFTEQ) { return "<<="; };
if (k == tkind.TK_RSHIFTEQ) { return ">>="; };
case tkind.TK_ASSIGN: return "=";
case tkind.TK_PLUSEQ: return "+=";
case tkind.TK_MINUSEQ: return "-=";
case tkind.TK_STAREQ: return "*=";
case tkind.TK_SLASHEQ: return "/=";
case tkind.TK_PERCENTEQ: return "%=";
case tkind.TK_AMPEQ: return "&=";
case tkind.TK_PIPEEQ: return "|=";
case tkind.TK_CARETEQ: return "^=";
case tkind.TK_LSHIFTEQ: return "<<=";
case tkind.TK_RSHIFTEQ: return ">>=";
if (k == tkind.TK_PLUS) { return "+"; };
if (k == tkind.TK_MINUS) { return "-"; };
if (k == tkind.TK_STAR) { return "*"; };
if (k == tkind.TK_SLASH) { return "/"; };
if (k == tkind.TK_PERCENT) { return "%"; };
if (k == tkind.TK_AMP) { return "&"; };
if (k == tkind.TK_PIPE) { return "|"; };
if (k == tkind.TK_CARET) { return "^"; };
if (k == tkind.TK_TILDE) { return "~"; };
if (k == tkind.TK_LSHIFT) { return "<<"; };
if (k == tkind.TK_RSHIFT) { return ">>"; };
case tkind.TK_PLUS: return "+";
case tkind.TK_MINUS: return "-";
case tkind.TK_STAR: return "*";
case tkind.TK_SLASH: return "/";
case tkind.TK_PERCENT: return "%";
case tkind.TK_AMP: return "&";
case tkind.TK_PIPE: return "|";
case tkind.TK_CARET: return "^";
case tkind.TK_TILDE: return "~";
case tkind.TK_LSHIFT: return "<<";
case tkind.TK_RSHIFT: return ">>";
if (k == tkind.TK_EQ) { return "=="; };
if (k == tkind.TK_NEQ) { return "!="; };
if (k == tkind.TK_LT) { return "<"; };
if (k == tkind.TK_LE) { return "<="; };
if (k == tkind.TK_GT) { return ">"; };
if (k == tkind.TK_GE) { return ">="; };
case tkind.TK_EQ: return "==";
case tkind.TK_NEQ: return "!=";
case tkind.TK_LT: return "<";
case tkind.TK_LE: return "<=";
case tkind.TK_GT: return ">";
case tkind.TK_GE: return ">=";
if (k == tkind.TK_AND) { return "&&"; };
if (k == tkind.TK_OR) { return "||"; };
if (k == tkind.TK_NOT) { return "!"; };
case tkind.TK_AND: return "&&";
case tkind.TK_OR: return "||";
case tkind.TK_NOT: return "!";
if (k == tkind.TK_LARROW) { return "<-"; };
if (k == tkind.TK_ARROW) { return "->"; };
if (k == tkind.TK_FATARROW) { return "=>"; };
case tkind.TK_LARROW: return "<-";
case tkind.TK_ARROW: return "->";
case tkind.TK_FATARROW: return "=>";
if (k == tkind.TK_LAST) { return "<last>"; };
case tkind.TK_LAST: return "<last>";
};
return "<?>";
};

View File

@@ -6579,102 +6579,104 @@ export fn kwlookup(p: *u8, n: i32) tkind = {
// the C tokname()'s output exactly so wwdump output diffs cleanly.
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"; };
if (k == tkind.TK_IDENT) { return "IDENT"; };
if (k == tkind.TK_INT) { return "INT"; };
if (k == tkind.TK_FLOAT) { return "FLOAT"; };
if (k == tkind.TK_RUNE) { return "RUNE"; };
if (k == tkind.TK_STR) { return "STR"; };
switch (k) {
case tkind.TK_NONE: return "<none>";
case tkind.TK_EOF: return "EOF";
case tkind.TK_ERR: return "ERR";
case tkind.TK_IDENT: return "IDENT";
case tkind.TK_INT: return "INT";
case tkind.TK_FLOAT: return "FLOAT";
case tkind.TK_RUNE: return "RUNE";
case tkind.TK_STR: return "STR";
if (k == tkind.TK_FN) { return "fn"; };
if (k == tkind.TK_LET) { return "let"; };
if (k == tkind.TK_DEF) { return "def"; };
if (k == tkind.TK_IF) { return "if"; };
if (k == tkind.TK_ELSE) { return "else"; };
if (k == tkind.TK_FOR) { return "for"; };
if (k == tkind.TK_SWITCH) { return "switch"; };
if (k == tkind.TK_CASE) { return "case"; };
if (k == tkind.TK_RETURN) { return "return"; };
if (k == tkind.TK_USE) { return "import"; };
if (k == tkind.TK_TYPE) { return "type"; };
if (k == tkind.TK_STRUCT) { return "struct"; };
if (k == tkind.TK_DEFER) { return "defer"; };
if (k == tkind.TK_BREAK) { return "break"; };
if (k == tkind.TK_CONTINUE) { return "continue"; };
if (k == tkind.TK_EXPORT) { return "export"; };
if (k == tkind.TK_PROC) { return "proc"; };
if (k == tkind.TK_CHAN) { return "chan"; };
if (k == tkind.TK_NIL) { return "nil"; };
if (k == tkind.TK_TRUE) { return "true"; };
if (k == tkind.TK_FALSE) { return "false"; };
if (k == tkind.TK_AS) { return "as"; };
if (k == tkind.TK_IS) { return "is"; };
if (k == tkind.TK_VOID) { return "void"; };
if (k == tkind.TK_YIELD) { return "yield"; };
if (k == tkind.TK_STATIC) { return "static"; };
if (k == tkind.TK_MATCH) { return "match"; };
if (k == tkind.TK_CONST) { return "const"; };
if (k == tkind.TK_UNDER) { return "_"; };
if (k == tkind.TK_ENUM) { return "enum"; };
if (k == tkind.TK_MODULE) { return "package"; };
case tkind.TK_FN: return "fn";
case tkind.TK_LET: return "let";
case tkind.TK_DEF: return "def";
case tkind.TK_IF: return "if";
case tkind.TK_ELSE: return "else";
case tkind.TK_FOR: return "for";
case tkind.TK_SWITCH: return "switch";
case tkind.TK_CASE: return "case";
case tkind.TK_RETURN: return "return";
case tkind.TK_USE: return "import";
case tkind.TK_TYPE: return "type";
case tkind.TK_STRUCT: return "struct";
case tkind.TK_DEFER: return "defer";
case tkind.TK_BREAK: return "break";
case tkind.TK_CONTINUE: return "continue";
case tkind.TK_EXPORT: return "export";
case tkind.TK_PROC: return "proc";
case tkind.TK_CHAN: return "chan";
case tkind.TK_NIL: return "nil";
case tkind.TK_TRUE: return "true";
case tkind.TK_FALSE: return "false";
case tkind.TK_AS: return "as";
case tkind.TK_IS: return "is";
case tkind.TK_VOID: return "void";
case tkind.TK_YIELD: return "yield";
case tkind.TK_STATIC: return "static";
case tkind.TK_MATCH: return "match";
case tkind.TK_CONST: return "const";
case tkind.TK_UNDER: return "_";
case tkind.TK_ENUM: return "enum";
case tkind.TK_MODULE: return "package";
if (k == tkind.TK_LPAREN) { return "("; };
if (k == tkind.TK_RPAREN) { return ")"; };
if (k == tkind.TK_LBRACE) { return "{"; };
if (k == tkind.TK_RBRACE) { return "}"; };
if (k == tkind.TK_LBRACK) { return "["; };
if (k == tkind.TK_RBRACK) { return "]"; };
if (k == tkind.TK_COMMA) { return ","; };
if (k == tkind.TK_SEMI) { return ";"; };
if (k == tkind.TK_COLON) { return ":"; };
if (k == tkind.TK_DOT) { return "."; };
if (k == tkind.TK_ELLIPSIS) { return "..."; };
if (k == tkind.TK_DOTDOT) { return ".."; };
if (k == tkind.TK_AT) { return "@"; };
if (k == tkind.TK_QUESTION) { return "?"; };
case tkind.TK_LPAREN: return "(";
case tkind.TK_RPAREN: return ")";
case tkind.TK_LBRACE: return "{";
case tkind.TK_RBRACE: return "}";
case tkind.TK_LBRACK: return "[";
case tkind.TK_RBRACK: return "]";
case tkind.TK_COMMA: return ",";
case tkind.TK_SEMI: return ";";
case tkind.TK_COLON: return ":";
case tkind.TK_DOT: return ".";
case tkind.TK_ELLIPSIS: return "...";
case tkind.TK_DOTDOT: return "..";
case tkind.TK_AT: return "@";
case tkind.TK_QUESTION: return "?";
if (k == tkind.TK_ASSIGN) { return "="; };
if (k == tkind.TK_PLUSEQ) { return "+="; };
if (k == tkind.TK_MINUSEQ) { return "-="; };
if (k == tkind.TK_STAREQ) { return "*="; };
if (k == tkind.TK_SLASHEQ) { return "/="; };
if (k == tkind.TK_PERCENTEQ) { return "%="; };
if (k == tkind.TK_AMPEQ) { return "&="; };
if (k == tkind.TK_PIPEEQ) { return "|="; };
if (k == tkind.TK_CARETEQ) { return "^="; };
if (k == tkind.TK_LSHIFTEQ) { return "<<="; };
if (k == tkind.TK_RSHIFTEQ) { return ">>="; };
case tkind.TK_ASSIGN: return "=";
case tkind.TK_PLUSEQ: return "+=";
case tkind.TK_MINUSEQ: return "-=";
case tkind.TK_STAREQ: return "*=";
case tkind.TK_SLASHEQ: return "/=";
case tkind.TK_PERCENTEQ: return "%=";
case tkind.TK_AMPEQ: return "&=";
case tkind.TK_PIPEEQ: return "|=";
case tkind.TK_CARETEQ: return "^=";
case tkind.TK_LSHIFTEQ: return "<<=";
case tkind.TK_RSHIFTEQ: return ">>=";
if (k == tkind.TK_PLUS) { return "+"; };
if (k == tkind.TK_MINUS) { return "-"; };
if (k == tkind.TK_STAR) { return "*"; };
if (k == tkind.TK_SLASH) { return "/"; };
if (k == tkind.TK_PERCENT) { return "%"; };
if (k == tkind.TK_AMP) { return "&"; };
if (k == tkind.TK_PIPE) { return "|"; };
if (k == tkind.TK_CARET) { return "^"; };
if (k == tkind.TK_TILDE) { return "~"; };
if (k == tkind.TK_LSHIFT) { return "<<"; };
if (k == tkind.TK_RSHIFT) { return ">>"; };
case tkind.TK_PLUS: return "+";
case tkind.TK_MINUS: return "-";
case tkind.TK_STAR: return "*";
case tkind.TK_SLASH: return "/";
case tkind.TK_PERCENT: return "%";
case tkind.TK_AMP: return "&";
case tkind.TK_PIPE: return "|";
case tkind.TK_CARET: return "^";
case tkind.TK_TILDE: return "~";
case tkind.TK_LSHIFT: return "<<";
case tkind.TK_RSHIFT: return ">>";
if (k == tkind.TK_EQ) { return "=="; };
if (k == tkind.TK_NEQ) { return "!="; };
if (k == tkind.TK_LT) { return "<"; };
if (k == tkind.TK_LE) { return "<="; };
if (k == tkind.TK_GT) { return ">"; };
if (k == tkind.TK_GE) { return ">="; };
case tkind.TK_EQ: return "==";
case tkind.TK_NEQ: return "!=";
case tkind.TK_LT: return "<";
case tkind.TK_LE: return "<=";
case tkind.TK_GT: return ">";
case tkind.TK_GE: return ">=";
if (k == tkind.TK_AND) { return "&&"; };
if (k == tkind.TK_OR) { return "||"; };
if (k == tkind.TK_NOT) { return "!"; };
case tkind.TK_AND: return "&&";
case tkind.TK_OR: return "||";
case tkind.TK_NOT: return "!";
if (k == tkind.TK_LARROW) { return "<-"; };
if (k == tkind.TK_ARROW) { return "->"; };
if (k == tkind.TK_FATARROW) { return "=>"; };
case tkind.TK_LARROW: return "<-";
case tkind.TK_ARROW: return "->";
case tkind.TK_FATARROW: return "=>";
if (k == tkind.TK_LAST) { return "<last>"; };
case tkind.TK_LAST: return "<last>";
};
return "<?>";
};

52
test/wcc/904_tok_run.c Normal file
View File

@@ -0,0 +1,52 @@
/*
* 904_tok_run — execute the lib/ww/lex tokname/kwlookup @test fixture
* under the C-side `ww run` driver and assert exit 0.
*
* Same thin-wrapper shape as 904_ascii_run / 967_bytes_run: toktest.ww
* carries its own `export fn main()` that drives the @test fns and
* signals which case failed via the exit code. This pins tokname's
* if-ladder -> switch fold (every tkind + the unknown-kind fallback),
* which the 990_selfhost wwdump diff only covers for kinds that appear
* in its corpus.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return 1;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
const char *src = "lib/ww/lex/toktest.ww";
char path[1024], cmd[2048];
snprintf(path, sizeof path, "%s/%s", cwd, src);
snprintf(cmd, sizeof cmd, "%s/ww run %s", bin, path);
int rc = runwait(cmd);
if (rc != 0) {
fprintf(stderr, "tok_run FAIL: %s exited %d\n", src, rc);
return 1;
}
printf("tok_run: %s ok\n", src);
return 0;
}