lib/ww/lex: kwlookup if-ladder -> [N]str parallel-table linear scan (kwtab, rides #18/#8)
Replace kwlookup's 30-arm streqn if-ladder with two parallel module-level tables — kwnames: [30]str + kwkinds: [30]tkind — scanned linearly via strings.compare, and delete the hand-rolled streqn. Rides #18 (module- level [N]str static-init + relocations) for the kwnames data and #8 ([N]enum element sizing) for the kwkinds[i] read, which is itself the construct that surfaced the #8 elemsizeofc/array-init-store miscompile. Two parallel arrays rather than a [N]kwent array-of-struct: a str inside an aggregate element is the filed #18 follow-up. Mirrors the C twin cmd/wcc/tok.c kwlookup (N=30, linear, no hash). Source re-applied on top of the #8 cgen fix and regenerated fresh: the wwstage-compiled toktest now runs correctly (exit 0, no segfault) where pre-#8 it smashed the frame on the local [N]tkind init store.
This commit is contained in:
@@ -6386,6 +6386,7 @@ package lex;
|
||||
|
||||
import os;
|
||||
import strconv;
|
||||
import strings;
|
||||
|
||||
// ---- tkind ------------------------------------------------------------
|
||||
// Mirror of the C `Tkind` enum in cmd/wcc/ww.h. Numeric values are
|
||||
@@ -6522,50 +6523,46 @@ type tok = struct {
|
||||
|
||||
// ---- keyword lookup ---------------------------------------------------
|
||||
|
||||
fn streqn(a: *u8, b: str, n: i32) bool = {
|
||||
if (b.len != n) { return false; };
|
||||
let i: i32 = 0;
|
||||
for (i < n) {
|
||||
if (a[i] != b[i]) { return false; };
|
||||
i += 1;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
// keep alphabetised, so kwlookup is easy to read — mirrors the C twin
|
||||
// cmd/wcc/tok.c:18-47. Two parallel arrays, not a [N]kwent array-of-
|
||||
// struct: a str *inside* an aggregate element is the filed #18 follow-up
|
||||
// (str-in-aggregate). `let`, not `def`: #18's module-level [N]str static
|
||||
// init is scoped to the DATAW (`let`) directive (A_DATAR needs a DATAW
|
||||
// holder); `def [N]str` is the same filed follow-up. kwkinds is a plain
|
||||
// [N]tkind enum byte-array (pre-#18 path). Explicit [30], NOT [_]:
|
||||
// [_] static-init silently miscompiles to a zero-length array in-tree
|
||||
// (probe at cc69daf — len() returns 0, no diagnostic); filed bug.
|
||||
let kwnames: [30]str = [
|
||||
"as", "break", "case", "chan", "const", "continue", "def", "defer",
|
||||
"else", "enum", "export", "false", "fn", "for", "if", "is",
|
||||
"import", "let", "match", "nil", "package", "proc", "return",
|
||||
"static", "struct", "switch", "true", "type", "void", "yield",
|
||||
];
|
||||
let kwkinds: [30]tkind = [
|
||||
tkind.TK_AS, tkind.TK_BREAK, tkind.TK_CASE, tkind.TK_CHAN,
|
||||
tkind.TK_CONST, tkind.TK_CONTINUE, tkind.TK_DEF, tkind.TK_DEFER,
|
||||
tkind.TK_ELSE, tkind.TK_ENUM, tkind.TK_EXPORT, tkind.TK_FALSE,
|
||||
tkind.TK_FN, tkind.TK_FOR, tkind.TK_IF, tkind.TK_IS,
|
||||
tkind.TK_USE, tkind.TK_LET, tkind.TK_MATCH, tkind.TK_NIL,
|
||||
tkind.TK_MODULE, tkind.TK_PROC, tkind.TK_RETURN, tkind.TK_STATIC,
|
||||
tkind.TK_STRUCT, tkind.TK_SWITCH, tkind.TK_TRUE, tkind.TK_TYPE,
|
||||
tkind.TK_VOID, tkind.TK_YIELD,
|
||||
];
|
||||
|
||||
// kwlookup — returns the matching TK_* keyword kind for a byte run,
|
||||
// or tkind.TK_NONE if it's an ordinary identifier. Linear search over a
|
||||
// small alphabetised list, matching cmd/wcc/tok.c.
|
||||
// or tkind.TK_NONE if it's an ordinary identifier. Linear scan over the
|
||||
// table, matching cmd/wcc/tok.c:kwlookup (N=30, no hash).
|
||||
export fn kwlookup(p: *u8, n: i32) tkind = {
|
||||
if (streqn(p, "as", n)) { return tkind.TK_AS; };
|
||||
if (streqn(p, "break", n)) { return tkind.TK_BREAK; };
|
||||
if (streqn(p, "case", n)) { return tkind.TK_CASE; };
|
||||
if (streqn(p, "chan", n)) { return tkind.TK_CHAN; };
|
||||
if (streqn(p, "const", n)) { return tkind.TK_CONST; };
|
||||
if (streqn(p, "continue", n)) { return tkind.TK_CONTINUE; };
|
||||
if (streqn(p, "def", n)) { return tkind.TK_DEF; };
|
||||
if (streqn(p, "defer", n)) { return tkind.TK_DEFER; };
|
||||
if (streqn(p, "else", n)) { return tkind.TK_ELSE; };
|
||||
if (streqn(p, "enum", n)) { return tkind.TK_ENUM; };
|
||||
if (streqn(p, "export", n)) { return tkind.TK_EXPORT; };
|
||||
if (streqn(p, "false", n)) { return tkind.TK_FALSE; };
|
||||
if (streqn(p, "fn", n)) { return tkind.TK_FN; };
|
||||
if (streqn(p, "for", n)) { return tkind.TK_FOR; };
|
||||
if (streqn(p, "if", n)) { return tkind.TK_IF; };
|
||||
if (streqn(p, "is", n)) { return tkind.TK_IS; };
|
||||
if (streqn(p, "let", n)) { return tkind.TK_LET; };
|
||||
if (streqn(p, "import", n)) { return tkind.TK_USE; };
|
||||
if (streqn(p, "match", n)) { return tkind.TK_MATCH; };
|
||||
if (streqn(p, "nil", n)) { return tkind.TK_NIL; };
|
||||
if (streqn(p, "package", n)) { return tkind.TK_MODULE; };
|
||||
if (streqn(p, "proc", n)) { return tkind.TK_PROC; };
|
||||
if (streqn(p, "return", n)) { return tkind.TK_RETURN; };
|
||||
if (streqn(p, "static", n)) { return tkind.TK_STATIC; };
|
||||
if (streqn(p, "struct", n)) { return tkind.TK_STRUCT; };
|
||||
if (streqn(p, "switch", n)) { return tkind.TK_SWITCH; };
|
||||
if (streqn(p, "true", n)) { return tkind.TK_TRUE; };
|
||||
if (streqn(p, "type", n)) { return tkind.TK_TYPE; };
|
||||
if (streqn(p, "void", n)) { return tkind.TK_VOID; };
|
||||
if (streqn(p, "yield", n)) { return tkind.TK_YIELD; };
|
||||
let cand: str;
|
||||
cand.ptr = p;
|
||||
cand.len = n;
|
||||
let i: i32 = 0;
|
||||
for (i < len(kwnames)) {
|
||||
if (strings.compare(cand, kwnames[i]) == 0) {
|
||||
return kwkinds[i];
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
return tkind.TK_NONE;
|
||||
};
|
||||
|
||||
|
||||
@@ -6386,6 +6386,7 @@ package lex;
|
||||
|
||||
import os;
|
||||
import strconv;
|
||||
import strings;
|
||||
|
||||
// ---- tkind ------------------------------------------------------------
|
||||
// Mirror of the C `Tkind` enum in cmd/wcc/ww.h. Numeric values are
|
||||
@@ -6522,50 +6523,46 @@ type tok = struct {
|
||||
|
||||
// ---- keyword lookup ---------------------------------------------------
|
||||
|
||||
fn streqn(a: *u8, b: str, n: i32) bool = {
|
||||
if (b.len != n) { return false; };
|
||||
let i: i32 = 0;
|
||||
for (i < n) {
|
||||
if (a[i] != b[i]) { return false; };
|
||||
i += 1;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
// keep alphabetised, so kwlookup is easy to read — mirrors the C twin
|
||||
// cmd/wcc/tok.c:18-47. Two parallel arrays, not a [N]kwent array-of-
|
||||
// struct: a str *inside* an aggregate element is the filed #18 follow-up
|
||||
// (str-in-aggregate). `let`, not `def`: #18's module-level [N]str static
|
||||
// init is scoped to the DATAW (`let`) directive (A_DATAR needs a DATAW
|
||||
// holder); `def [N]str` is the same filed follow-up. kwkinds is a plain
|
||||
// [N]tkind enum byte-array (pre-#18 path). Explicit [30], NOT [_]:
|
||||
// [_] static-init silently miscompiles to a zero-length array in-tree
|
||||
// (probe at cc69daf — len() returns 0, no diagnostic); filed bug.
|
||||
let kwnames: [30]str = [
|
||||
"as", "break", "case", "chan", "const", "continue", "def", "defer",
|
||||
"else", "enum", "export", "false", "fn", "for", "if", "is",
|
||||
"import", "let", "match", "nil", "package", "proc", "return",
|
||||
"static", "struct", "switch", "true", "type", "void", "yield",
|
||||
];
|
||||
let kwkinds: [30]tkind = [
|
||||
tkind.TK_AS, tkind.TK_BREAK, tkind.TK_CASE, tkind.TK_CHAN,
|
||||
tkind.TK_CONST, tkind.TK_CONTINUE, tkind.TK_DEF, tkind.TK_DEFER,
|
||||
tkind.TK_ELSE, tkind.TK_ENUM, tkind.TK_EXPORT, tkind.TK_FALSE,
|
||||
tkind.TK_FN, tkind.TK_FOR, tkind.TK_IF, tkind.TK_IS,
|
||||
tkind.TK_USE, tkind.TK_LET, tkind.TK_MATCH, tkind.TK_NIL,
|
||||
tkind.TK_MODULE, tkind.TK_PROC, tkind.TK_RETURN, tkind.TK_STATIC,
|
||||
tkind.TK_STRUCT, tkind.TK_SWITCH, tkind.TK_TRUE, tkind.TK_TYPE,
|
||||
tkind.TK_VOID, tkind.TK_YIELD,
|
||||
];
|
||||
|
||||
// kwlookup — returns the matching TK_* keyword kind for a byte run,
|
||||
// or tkind.TK_NONE if it's an ordinary identifier. Linear search over a
|
||||
// small alphabetised list, matching cmd/wcc/tok.c.
|
||||
// or tkind.TK_NONE if it's an ordinary identifier. Linear scan over the
|
||||
// table, matching cmd/wcc/tok.c:kwlookup (N=30, no hash).
|
||||
export fn kwlookup(p: *u8, n: i32) tkind = {
|
||||
if (streqn(p, "as", n)) { return tkind.TK_AS; };
|
||||
if (streqn(p, "break", n)) { return tkind.TK_BREAK; };
|
||||
if (streqn(p, "case", n)) { return tkind.TK_CASE; };
|
||||
if (streqn(p, "chan", n)) { return tkind.TK_CHAN; };
|
||||
if (streqn(p, "const", n)) { return tkind.TK_CONST; };
|
||||
if (streqn(p, "continue", n)) { return tkind.TK_CONTINUE; };
|
||||
if (streqn(p, "def", n)) { return tkind.TK_DEF; };
|
||||
if (streqn(p, "defer", n)) { return tkind.TK_DEFER; };
|
||||
if (streqn(p, "else", n)) { return tkind.TK_ELSE; };
|
||||
if (streqn(p, "enum", n)) { return tkind.TK_ENUM; };
|
||||
if (streqn(p, "export", n)) { return tkind.TK_EXPORT; };
|
||||
if (streqn(p, "false", n)) { return tkind.TK_FALSE; };
|
||||
if (streqn(p, "fn", n)) { return tkind.TK_FN; };
|
||||
if (streqn(p, "for", n)) { return tkind.TK_FOR; };
|
||||
if (streqn(p, "if", n)) { return tkind.TK_IF; };
|
||||
if (streqn(p, "is", n)) { return tkind.TK_IS; };
|
||||
if (streqn(p, "let", n)) { return tkind.TK_LET; };
|
||||
if (streqn(p, "import", n)) { return tkind.TK_USE; };
|
||||
if (streqn(p, "match", n)) { return tkind.TK_MATCH; };
|
||||
if (streqn(p, "nil", n)) { return tkind.TK_NIL; };
|
||||
if (streqn(p, "package", n)) { return tkind.TK_MODULE; };
|
||||
if (streqn(p, "proc", n)) { return tkind.TK_PROC; };
|
||||
if (streqn(p, "return", n)) { return tkind.TK_RETURN; };
|
||||
if (streqn(p, "static", n)) { return tkind.TK_STATIC; };
|
||||
if (streqn(p, "struct", n)) { return tkind.TK_STRUCT; };
|
||||
if (streqn(p, "switch", n)) { return tkind.TK_SWITCH; };
|
||||
if (streqn(p, "true", n)) { return tkind.TK_TRUE; };
|
||||
if (streqn(p, "type", n)) { return tkind.TK_TYPE; };
|
||||
if (streqn(p, "void", n)) { return tkind.TK_VOID; };
|
||||
if (streqn(p, "yield", n)) { return tkind.TK_YIELD; };
|
||||
let cand: str;
|
||||
cand.ptr = p;
|
||||
cand.len = n;
|
||||
let i: i32 = 0;
|
||||
for (i < len(kwnames)) {
|
||||
if (strings.compare(cand, kwnames[i]) == 0) {
|
||||
return kwkinds[i];
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
return tkind.TK_NONE;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user