lib/ww/lex: fputq + tokprint if-ladders -> switch (Wave-2 structural)
fputq: 6-deep escape if/else -> switch (c); named escapes \\ " \n \t \r as explicit cases, empty-label default folds the control-char arms into (c<' '||c==127)->fputhex2 else fputcbyte, mirroring cmd/wcc/tok.c:172. tokprint: 4-deep kind if-ladder -> switch (t.kind) with comma-cases (IDENT,STR,ERR -> fputq; INT,RUNE -> u64tos; default -> nothing), mirroring tok.c:194. toktest gains @test tokprint_cases: drives tokprint over a temp fd and packs every fputq escape (\\ " \n \t \r, c<0x20, c==0x7f, printable) into a TK_STR text — branches 990_selfhost's corpus never reaches. w6c + wwdump combined.ww regenerated.
This commit is contained in:
@@ -337,33 +337,17 @@ fn fputq(fd: i32, p: *u8, n: i32) void = {
|
||||
let i: i32 = 0;
|
||||
for (i < n) {
|
||||
let c: u8 = p[i];
|
||||
if (c == '\\') {
|
||||
fputsstr(fd, "\\\\");
|
||||
} else {
|
||||
if (c == '"') {
|
||||
fputsstr(fd, "\\\"");
|
||||
switch (c) {
|
||||
case '\\': fputsstr(fd, "\\\\");
|
||||
case '"': fputsstr(fd, "\\\"");
|
||||
case '\n': fputsstr(fd, "\\n");
|
||||
case '\t': fputsstr(fd, "\\t");
|
||||
case '\r': fputsstr(fd, "\\r");
|
||||
case:
|
||||
if (c < ' ' || c == 127u8) {
|
||||
fputhex2(fd, c);
|
||||
} else {
|
||||
if (c == '\n') {
|
||||
fputsstr(fd, "\\n");
|
||||
} else {
|
||||
if (c == '\t') {
|
||||
fputsstr(fd, "\\t");
|
||||
} else {
|
||||
if (c == '\r') {
|
||||
fputsstr(fd, "\\r");
|
||||
} else {
|
||||
if (c < ' ') {
|
||||
fputhex2(fd, c);
|
||||
} else {
|
||||
if (c == 127u8) {
|
||||
fputhex2(fd, c);
|
||||
} else {
|
||||
fputcbyte(fd, c);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
fputcbyte(fd, c);
|
||||
};
|
||||
};
|
||||
i += 1;
|
||||
@@ -397,24 +381,15 @@ export fn tokprint(fd: i32, t: *tok) void = {
|
||||
fputcbyte(fd, ' ');
|
||||
fputsstr(fd, tokname(t.kind));
|
||||
|
||||
if (t.kind == tkind.TK_IDENT) {
|
||||
switch (t.kind) {
|
||||
case tkind.TK_IDENT, tkind.TK_STR, tkind.TK_ERR:
|
||||
fputcbyte(fd, ' ');
|
||||
fputq(fd, ttext.ptr, ttext.len);
|
||||
} else { if (t.kind == tkind.TK_STR) {
|
||||
fputcbyte(fd, ' ');
|
||||
fputq(fd, ttext.ptr, ttext.len);
|
||||
} else { if (t.kind == tkind.TK_ERR) {
|
||||
fputcbyte(fd, ' ');
|
||||
fputq(fd, ttext.ptr, ttext.len);
|
||||
} else { if (t.kind == tkind.TK_INT) {
|
||||
case tkind.TK_INT, tkind.TK_RUNE:
|
||||
fputcbyte(fd, ' ');
|
||||
let us: str = strconv.u64tos(t.uval, strconv.base.DEC);
|
||||
os.write(fd, us.ptr, us.len: u64);
|
||||
} else { if (t.kind == tkind.TK_RUNE) {
|
||||
fputcbyte(fd, ' ');
|
||||
let us: str = strconv.u64tos(t.uval, strconv.base.DEC);
|
||||
os.write(fd, us.ptr, us.len: u64);
|
||||
};};};};};
|
||||
};
|
||||
// tkind.TK_FLOAT is intentionally not handled here — %g formatting
|
||||
// won't byte-match across implementations. Diff fixtures must
|
||||
// be float-free until we implement a stable float formatter.
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
// toktest — functional-equivalence pin for [[tokname]] and
|
||||
// [[kwlookup]] after the if-ladder → switch fold (struct fold S1).
|
||||
// toktest — functional-equivalence pin for [[tokname]], [[kwlookup]]
|
||||
// (struct fold S1) and [[tokprint]]/fputq (struct fold S9, the
|
||||
// if-ladder → switch folds in tok.ww).
|
||||
// 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.
|
||||
// tokprint is driven over a temp file: it pins the kind-dispatch
|
||||
// switch (STR/IDENT/ERR vs INT/RUNE vs the value-less default) and,
|
||||
// through the STR text, fputq's full escape switch (\\, ", \n, \t,
|
||||
// \r, the c<0x20 and c==0x7f \xNN arms, and the printable tail) —
|
||||
// branches the 990_selfhost corpus does not exercise (source tokens
|
||||
// hold raw `\`+`n`, never a literal control byte).
|
||||
// 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).
|
||||
@@ -171,8 +178,76 @@ fn checkkw(s: str, want: tkind) void = {
|
||||
signalled = 231; checkkw("fns", tkind.TK_NONE);
|
||||
};
|
||||
|
||||
// checkprint — tokprint `t` to a freshly-rewound fd, read the bytes
|
||||
// back, and assert they equal `want`. The fd is RDWR; we lseek to 0
|
||||
// before each write so earlier (possibly longer) content past want.len
|
||||
// is irrelevant — only want.len bytes from offset 0 are compared.
|
||||
fn checkprint(fd: i32, t: *tok, want: str) void = {
|
||||
if (os.lseek(fd, 0i64, os.whence.SET) != 0i64) { fail(); };
|
||||
tokprint(fd, t);
|
||||
if (os.lseek(fd, 0i64, os.whence.SET) != 0i64) { fail(); };
|
||||
let rbuf: [256]u8;
|
||||
let z: i32 = 0;
|
||||
for (z < 256) { rbuf[z] = 0u8; z += 1; };
|
||||
let rd: i64 = os.read(fd, &rbuf[0], want.len: u64);
|
||||
if (rd != want.len: i64) { fail(); };
|
||||
let j: i32 = 0;
|
||||
for (j < want.len) {
|
||||
if (rbuf[j] != want.ptr[j]) { fail(); };
|
||||
j += 1;
|
||||
};
|
||||
};
|
||||
|
||||
// One token per fputq/tokprint dispatch branch. The STR text packs
|
||||
// every fputq escape: \\ " \n \t \r, a c<0x20 byte (0x01), c==0x7f,
|
||||
// and a printable ('A'). `want` spells the exact emitted line.
|
||||
@test fn tokprint_cases() void = {
|
||||
let flags: os.flag = os.flag.RDWR | os.flag.CREATE | os.flag.TRUNC;
|
||||
let fd: i32 = os.open("/tmp/ww_s9_tok.tmp", flags, 384i32);
|
||||
if (fd < 0) { fail(); };
|
||||
|
||||
let t: tok;
|
||||
t.file = "t";
|
||||
t.line = 1;
|
||||
t.col = 1;
|
||||
|
||||
signalled = 300;
|
||||
t.kind = tkind.TK_STR;
|
||||
t.text = "\\\"\n\t\r\x01\x7fA";
|
||||
checkprint(fd, &t, "t:1:1 STR \"\\\\\\\"\\n\\t\\r\\x01\\x7fA\"\n");
|
||||
|
||||
signalled = 301;
|
||||
t.kind = tkind.TK_IDENT;
|
||||
t.text = "name";
|
||||
checkprint(fd, &t, "t:1:1 IDENT \"name\"\n");
|
||||
|
||||
signalled = 302;
|
||||
t.kind = tkind.TK_ERR;
|
||||
t.text = "oops";
|
||||
checkprint(fd, &t, "t:1:1 ERR \"oops\"\n");
|
||||
|
||||
signalled = 303;
|
||||
t.kind = tkind.TK_INT;
|
||||
t.uval = 42u64;
|
||||
checkprint(fd, &t, "t:1:1 INT 42\n");
|
||||
|
||||
signalled = 304;
|
||||
t.kind = tkind.TK_RUNE;
|
||||
t.uval = 65u64;
|
||||
checkprint(fd, &t, "t:1:1 RUNE 65\n");
|
||||
|
||||
// Default arm: a kind outside the switch appends no value.
|
||||
signalled = 305;
|
||||
t.kind = tkind.TK_NONE;
|
||||
checkprint(fd, &t, "t:1:1 <none>\n");
|
||||
|
||||
if (os.close(fd) != 0) { fail(); };
|
||||
if (os.remove("/tmp/ww_s9_tok.tmp") != 0) { fail(); };
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; tokname_cases();
|
||||
signalled = 2; kwlookup_cases();
|
||||
signalled = 3; tokprint_cases();
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -6710,33 +6710,17 @@ fn fputq(fd: i32, p: *u8, n: i32) void = {
|
||||
let i: i32 = 0;
|
||||
for (i < n) {
|
||||
let c: u8 = p[i];
|
||||
if (c == '\\') {
|
||||
fputsstr(fd, "\\\\");
|
||||
} else {
|
||||
if (c == '"') {
|
||||
fputsstr(fd, "\\\"");
|
||||
switch (c) {
|
||||
case '\\': fputsstr(fd, "\\\\");
|
||||
case '"': fputsstr(fd, "\\\"");
|
||||
case '\n': fputsstr(fd, "\\n");
|
||||
case '\t': fputsstr(fd, "\\t");
|
||||
case '\r': fputsstr(fd, "\\r");
|
||||
case:
|
||||
if (c < ' ' || c == 127u8) {
|
||||
fputhex2(fd, c);
|
||||
} else {
|
||||
if (c == '\n') {
|
||||
fputsstr(fd, "\\n");
|
||||
} else {
|
||||
if (c == '\t') {
|
||||
fputsstr(fd, "\\t");
|
||||
} else {
|
||||
if (c == '\r') {
|
||||
fputsstr(fd, "\\r");
|
||||
} else {
|
||||
if (c < ' ') {
|
||||
fputhex2(fd, c);
|
||||
} else {
|
||||
if (c == 127u8) {
|
||||
fputhex2(fd, c);
|
||||
} else {
|
||||
fputcbyte(fd, c);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
fputcbyte(fd, c);
|
||||
};
|
||||
};
|
||||
i += 1;
|
||||
@@ -6770,24 +6754,15 @@ export fn tokprint(fd: i32, t: *tok) void = {
|
||||
fputcbyte(fd, ' ');
|
||||
fputsstr(fd, tokname(t.kind));
|
||||
|
||||
if (t.kind == tkind.TK_IDENT) {
|
||||
switch (t.kind) {
|
||||
case tkind.TK_IDENT, tkind.TK_STR, tkind.TK_ERR:
|
||||
fputcbyte(fd, ' ');
|
||||
fputq(fd, ttext.ptr, ttext.len);
|
||||
} else { if (t.kind == tkind.TK_STR) {
|
||||
fputcbyte(fd, ' ');
|
||||
fputq(fd, ttext.ptr, ttext.len);
|
||||
} else { if (t.kind == tkind.TK_ERR) {
|
||||
fputcbyte(fd, ' ');
|
||||
fputq(fd, ttext.ptr, ttext.len);
|
||||
} else { if (t.kind == tkind.TK_INT) {
|
||||
case tkind.TK_INT, tkind.TK_RUNE:
|
||||
fputcbyte(fd, ' ');
|
||||
let us: str = strconv.u64tos(t.uval, strconv.base.DEC);
|
||||
os.write(fd, us.ptr, us.len: u64);
|
||||
} else { if (t.kind == tkind.TK_RUNE) {
|
||||
fputcbyte(fd, ' ');
|
||||
let us: str = strconv.u64tos(t.uval, strconv.base.DEC);
|
||||
os.write(fd, us.ptr, us.len: u64);
|
||||
};};};};};
|
||||
};
|
||||
// tkind.TK_FLOAT is intentionally not handled here — %g formatting
|
||||
// won't byte-match across implementations. Diff fixtures must
|
||||
// be float-free until we implement a stable float formatter.
|
||||
|
||||
@@ -6710,33 +6710,17 @@ fn fputq(fd: i32, p: *u8, n: i32) void = {
|
||||
let i: i32 = 0;
|
||||
for (i < n) {
|
||||
let c: u8 = p[i];
|
||||
if (c == '\\') {
|
||||
fputsstr(fd, "\\\\");
|
||||
} else {
|
||||
if (c == '"') {
|
||||
fputsstr(fd, "\\\"");
|
||||
switch (c) {
|
||||
case '\\': fputsstr(fd, "\\\\");
|
||||
case '"': fputsstr(fd, "\\\"");
|
||||
case '\n': fputsstr(fd, "\\n");
|
||||
case '\t': fputsstr(fd, "\\t");
|
||||
case '\r': fputsstr(fd, "\\r");
|
||||
case:
|
||||
if (c < ' ' || c == 127u8) {
|
||||
fputhex2(fd, c);
|
||||
} else {
|
||||
if (c == '\n') {
|
||||
fputsstr(fd, "\\n");
|
||||
} else {
|
||||
if (c == '\t') {
|
||||
fputsstr(fd, "\\t");
|
||||
} else {
|
||||
if (c == '\r') {
|
||||
fputsstr(fd, "\\r");
|
||||
} else {
|
||||
if (c < ' ') {
|
||||
fputhex2(fd, c);
|
||||
} else {
|
||||
if (c == 127u8) {
|
||||
fputhex2(fd, c);
|
||||
} else {
|
||||
fputcbyte(fd, c);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
fputcbyte(fd, c);
|
||||
};
|
||||
};
|
||||
i += 1;
|
||||
@@ -6770,24 +6754,15 @@ export fn tokprint(fd: i32, t: *tok) void = {
|
||||
fputcbyte(fd, ' ');
|
||||
fputsstr(fd, tokname(t.kind));
|
||||
|
||||
if (t.kind == tkind.TK_IDENT) {
|
||||
switch (t.kind) {
|
||||
case tkind.TK_IDENT, tkind.TK_STR, tkind.TK_ERR:
|
||||
fputcbyte(fd, ' ');
|
||||
fputq(fd, ttext.ptr, ttext.len);
|
||||
} else { if (t.kind == tkind.TK_STR) {
|
||||
fputcbyte(fd, ' ');
|
||||
fputq(fd, ttext.ptr, ttext.len);
|
||||
} else { if (t.kind == tkind.TK_ERR) {
|
||||
fputcbyte(fd, ' ');
|
||||
fputq(fd, ttext.ptr, ttext.len);
|
||||
} else { if (t.kind == tkind.TK_INT) {
|
||||
case tkind.TK_INT, tkind.TK_RUNE:
|
||||
fputcbyte(fd, ' ');
|
||||
let us: str = strconv.u64tos(t.uval, strconv.base.DEC);
|
||||
os.write(fd, us.ptr, us.len: u64);
|
||||
} else { if (t.kind == tkind.TK_RUNE) {
|
||||
fputcbyte(fd, ' ');
|
||||
let us: str = strconv.u64tos(t.uval, strconv.base.DEC);
|
||||
os.write(fd, us.ptr, us.len: u64);
|
||||
};};};};};
|
||||
};
|
||||
// tkind.TK_FLOAT is intentionally not handled here — %g formatting
|
||||
// won't byte-match across implementations. Diff fixtures must
|
||||
// be float-free until we implement a stable float formatter.
|
||||
|
||||
Reference in New Issue
Block a user