ww: rename toolchain to w-prefix + hare-style build/run/test driver
Plan 9-style w-prefix on the per-arch tools, disambiguating from the
real Plan 9 6c/6a/6l in ref/plan9front/:
cmd/wwc/ → cmd/wcc/ libwwc.a → libwcc.a
cmd/6{c,a,l} → cmd/w6{c,a,l} binary names too
test/wwc/ → test/wcc/ 6 test files w/ w6 prefix
selfhost/cmd mirror in lockstep
bootstrap/amd64/{w6c,w6a,w6l} snapshot binaries (gitignored)
WW_6{C,A,L} → WW_W6{C,A,L} env-var overrides
Plan 9 source-tree refs ("Plan 9 6c shape", ref/plan9front/, etc.)
preserved. Hare-style driver, both C and ww sides:
ww test [path] discover *_test.ww in a directory module, run
each; single-file mode for `ww test foo.ww`
Module-by-name `ww build foo` resolves to foo.ww or foo/foo.ww
via search path (cwd : -I dirs : $WW_LIB)
Default-to-cwd `ww build` / `ww test` build the cwd module
Run pass-through `ww run path arg1 arg2` reaches the program
lib/os: getcwd (79) and getdents64 (217) syscalls power `.` resolution
and directory enumeration on the ww side.
Makefile: wwstage tool deps now include lib/os/os.ww (+ lib/strconv
for wwdump_ww) so lib/* edits force their rebuild instead of leaving
stale binaries — surfaced when test 995 first failed against a stale
w6c_ww built before the lib/os additions.
Test 993 byte-identical parity gate (C-side ww vs ww-side ww_ww on a
build corpus) stays green; all 19 tests pass.
This commit is contained in:
335
selfhost/cmd/wcc/ast.ww
Normal file
335
selfhost/cmd/wcc/ast.ww
Normal file
@@ -0,0 +1,335 @@
|
||||
// selfhost/cmd/wcc/ast.ww — port of cmd/wcc/ast.c (Node defs + printer).
|
||||
//
|
||||
// Status: AST printer is fully ported. Constructor `newnode` is here.
|
||||
// The parser (parse.ww) is currently minimal — see its file header.
|
||||
//
|
||||
// Calling-convention shim: same as tok/lex — `node` is too big to pass
|
||||
// by value (8 *node pointers + 2 strs + a few ints), so callers always
|
||||
// hand around `*node`. Only `newnode` allocates and returns a *node.
|
||||
|
||||
use os;
|
||||
use strconv;
|
||||
use mem;
|
||||
use tok;
|
||||
|
||||
// ---- Nkind ------------------------------------------------------------
|
||||
//
|
||||
// Mirror of cmd/wcc/ww.h Nkind. Values must stay numerically equal so
|
||||
// the AST diff probe in 990_selfhost works.
|
||||
|
||||
def N_NONE: i32 = 0;
|
||||
|
||||
def N_INTLIT: i32 = 1;
|
||||
def N_FLOATLIT: i32 = 2;
|
||||
def N_STRLIT: i32 = 3;
|
||||
def N_RUNELIT: i32 = 4;
|
||||
def N_TRUE: i32 = 5;
|
||||
def N_FALSE: i32 = 6;
|
||||
def N_NIL: i32 = 7;
|
||||
def N_IDENT: i32 = 8;
|
||||
|
||||
def N_BIN: i32 = 9;
|
||||
def N_UN: i32 = 10;
|
||||
def N_CALL: i32 = 11;
|
||||
def N_INDEX: i32 = 12;
|
||||
def N_DOT: i32 = 13;
|
||||
def N_CAST: i32 = 14;
|
||||
def N_STRUCTLIT:i32 = 15;
|
||||
def N_ARRLIT: i32 = 16;
|
||||
def N_FIELD: i32 = 17;
|
||||
def N_ASSIGN: i32 = 18;
|
||||
def N_ALLOC: i32 = 19;
|
||||
def N_FREE: i32 = 20;
|
||||
def N_RECV: i32 = 21;
|
||||
def N_SLICE: i32 = 22;
|
||||
def N_SPREAD: i32 = 23;
|
||||
|
||||
def N_BLOCK: i32 = 24;
|
||||
def N_EXPRSTMT: i32 = 25;
|
||||
def N_LET: i32 = 26;
|
||||
def N_RETURN: i32 = 27;
|
||||
def N_IF: i32 = 28;
|
||||
def N_FOR: i32 = 29;
|
||||
def N_FORRANGE: i32 = 30;
|
||||
def N_DEFER: i32 = 31;
|
||||
def N_BREAK: i32 = 32;
|
||||
def N_CONTINUE: i32 = 33;
|
||||
def N_SWITCH: i32 = 34;
|
||||
def N_CASE: i32 = 35;
|
||||
|
||||
def N_FILE: i32 = 36;
|
||||
def N_USE: i32 = 37;
|
||||
def N_DEF: i32 = 38;
|
||||
def N_TYPEDECL: i32 = 39;
|
||||
def N_FNDECL: i32 = 40;
|
||||
def N_PARAM: i32 = 41;
|
||||
|
||||
def N_TNAME: i32 = 42;
|
||||
def N_TPTR: i32 = 43;
|
||||
def N_TSLICE: i32 = 44;
|
||||
def N_TARRAY: i32 = 45;
|
||||
def N_TFN: i32 = 46;
|
||||
def N_TSTRUCT: i32 = 47;
|
||||
def N_TFIELD: i32 = 48;
|
||||
def N_TCHAN: i32 = 49;
|
||||
|
||||
def N_ATTR: i32 = 50;
|
||||
def N_TTUPLE: i32 = 51;
|
||||
def N_TTAGGED: i32 = 52;
|
||||
def N_TUPLE: i32 = 53;
|
||||
def N_MATCH: i32 = 54;
|
||||
def N_MCASE: i32 = 55;
|
||||
def N_TRYPROP: i32 = 56;
|
||||
def N_TRYUNW: i32 = 57;
|
||||
def N_MLET: i32 = 58;
|
||||
def N_MASSIGN: i32 = 59;
|
||||
|
||||
def N_LAST: i32 = 60;
|
||||
|
||||
// ---- Node -------------------------------------------------------------
|
||||
|
||||
type node = struct {
|
||||
kind: i32,
|
||||
file: str,
|
||||
line: i32,
|
||||
col: i32,
|
||||
op: i32, // for N_BIN / N_UN / N_ASSIGN
|
||||
str: str,
|
||||
uval: u64,
|
||||
fval: f64,
|
||||
lhs: *node,
|
||||
rhs: *node,
|
||||
cond: *node,
|
||||
body: *node,
|
||||
els: *node,
|
||||
list: *node,
|
||||
next: *node,
|
||||
attr: *node,
|
||||
exported: i32, // bool — `export` keyword present
|
||||
type_: *void, // filled in by checker; type.ww treats it as *tinfo
|
||||
tsuffix: str, // typed numeric literal suffix ("i32", "u64", ...)
|
||||
};
|
||||
|
||||
export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = {
|
||||
let n: *node = amalloc(a, 192u64): *node; // 192 ≥ struct size
|
||||
n.kind = k;
|
||||
n.file = file;
|
||||
n.line = line;
|
||||
n.col = col;
|
||||
return n;
|
||||
};
|
||||
|
||||
// ---- printer ----------------------------------------------------------
|
||||
|
||||
fn nkname(k: i32) str = {
|
||||
if (k == N_NONE) { return "none"; };
|
||||
if (k == N_INTLIT) { return "int"; };
|
||||
if (k == N_FLOATLIT) { return "float"; };
|
||||
if (k == N_STRLIT) { return "str"; };
|
||||
if (k == N_RUNELIT) { return "rune"; };
|
||||
if (k == N_TRUE) { return "true"; };
|
||||
if (k == N_FALSE) { return "false"; };
|
||||
if (k == N_NIL) { return "nil"; };
|
||||
if (k == N_IDENT) { return "id"; };
|
||||
if (k == N_BIN) { return "bin"; };
|
||||
if (k == N_UN) { return "un"; };
|
||||
if (k == N_CALL) { return "call"; };
|
||||
if (k == N_INDEX) { return "index"; };
|
||||
if (k == N_DOT) { return "dot"; };
|
||||
if (k == N_CAST) { return "cast"; };
|
||||
if (k == N_STRUCTLIT) { return "structlit"; };
|
||||
if (k == N_ARRLIT) { return "arrlit"; };
|
||||
if (k == N_FIELD) { return "field"; };
|
||||
if (k == N_ASSIGN) { return "assign"; };
|
||||
if (k == N_ALLOC) { return "alloc"; };
|
||||
if (k == N_FREE) { return "free"; };
|
||||
if (k == N_RECV) { return "recv"; };
|
||||
if (k == N_SLICE) { return "slice"; };
|
||||
if (k == N_SPREAD) { return "spread"; };
|
||||
if (k == N_BLOCK) { return "block"; };
|
||||
if (k == N_EXPRSTMT) { return "exprstmt"; };
|
||||
if (k == N_LET) { return "let"; };
|
||||
if (k == N_RETURN) { return "return"; };
|
||||
if (k == N_IF) { return "if"; };
|
||||
if (k == N_FOR) { return "for"; };
|
||||
if (k == N_FORRANGE) { return "forrange"; };
|
||||
if (k == N_DEFER) { return "defer"; };
|
||||
if (k == N_BREAK) { return "break"; };
|
||||
if (k == N_CONTINUE) { return "continue"; };
|
||||
if (k == N_SWITCH) { return "switch"; };
|
||||
if (k == N_CASE) { return "case"; };
|
||||
if (k == N_FILE) { return "file"; };
|
||||
if (k == N_USE) { return "use"; };
|
||||
if (k == N_DEF) { return "def"; };
|
||||
if (k == N_TYPEDECL) { return "typedecl"; };
|
||||
if (k == N_FNDECL) { return "fn"; };
|
||||
if (k == N_PARAM) { return "param"; };
|
||||
if (k == N_TNAME) { return "tname"; };
|
||||
if (k == N_TPTR) { return "tptr"; };
|
||||
if (k == N_TSLICE) { return "tslice"; };
|
||||
if (k == N_TARRAY) { return "tarray"; };
|
||||
if (k == N_TFN) { return "tfn"; };
|
||||
if (k == N_TSTRUCT) { return "tstruct"; };
|
||||
if (k == N_TFIELD) { return "tfield"; };
|
||||
if (k == N_TCHAN) { return "tchan"; };
|
||||
if (k == N_ATTR) { return "attr"; };
|
||||
if (k == N_TTUPLE) { return "ttuple"; };
|
||||
if (k == N_TTAGGED) { return "ttagged"; };
|
||||
if (k == N_TUPLE) { return "tuple"; };
|
||||
if (k == N_MATCH) { return "match"; };
|
||||
if (k == N_MCASE) { return "mcase"; };
|
||||
if (k == N_TRYPROP) { return "tryprop"; };
|
||||
if (k == N_TRYUNW) { return "tryunw"; };
|
||||
if (k == N_MLET) { return "mlet"; };
|
||||
if (k == N_MASSIGN) { return "massign"; };
|
||||
if (k == N_LAST) { return "last"; };
|
||||
return "?";
|
||||
};
|
||||
|
||||
fn ind(fd: i32, d: i32) void = {
|
||||
let i: i32 = 0;
|
||||
for (i < d) {
|
||||
os.write(fd, " ".ptr, 2u64);
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
fn putc1(fd: i32, b: u8) void = {
|
||||
let buf: [1]u8;
|
||||
buf[0] = b;
|
||||
os.write(fd, buf.ptr, 1u64);
|
||||
};
|
||||
|
||||
fn putq(fd: i32, s: str) void = {
|
||||
putc1(fd, 34u8); // '"'
|
||||
let i: i32 = 0;
|
||||
for (i < s.len) {
|
||||
let c: u8 = s[i];
|
||||
if (c == 34u8) { // '"'
|
||||
os.write(fd, "\\\"".ptr, 2u64);
|
||||
} else { if (c == 92u8) { // '\\'
|
||||
os.write(fd, "\\\\".ptr, 2u64);
|
||||
} else { if (c == 10u8) { // '\n'
|
||||
os.write(fd, "\\n".ptr, 2u64);
|
||||
} else { if (c == 9u8) { // '\t'
|
||||
os.write(fd, "\\t".ptr, 2u64);
|
||||
} else { if (c < 32u8) {
|
||||
let hi: u8 = c >> 4u8;
|
||||
let lo: u8 = c & 15u8;
|
||||
let h: u8 = 0u8;
|
||||
let l: u8 = 0u8;
|
||||
if (hi < 10u8) { h = hi + 48u8; } else { h = (hi - 10u8) + 97u8; };
|
||||
if (lo < 10u8) { l = lo + 48u8; } else { l = (lo - 10u8) + 97u8; };
|
||||
let buf: [4]u8;
|
||||
buf[0] = 92u8;
|
||||
buf[1] = 120u8;
|
||||
buf[2] = h;
|
||||
buf[3] = l;
|
||||
os.write(fd, buf.ptr, 4u64);
|
||||
} else {
|
||||
putc1(fd, c);
|
||||
};};};};};
|
||||
i += 1;
|
||||
};
|
||||
putc1(fd, 34u8);
|
||||
};
|
||||
|
||||
fn pr(fd: i32, n: *node, d: i32) void = {
|
||||
if (n == nil) {
|
||||
ind(fd, d);
|
||||
os.write(fd, "()\n".ptr, 3u64);
|
||||
return;
|
||||
};
|
||||
ind(fd, d);
|
||||
putc1(fd, 40u8); // '('
|
||||
let nm: str = nkname(n.kind);
|
||||
os.write(fd, nm.ptr, nm.len: u64);
|
||||
|
||||
if (n.kind == N_INTLIT) {
|
||||
putc1(fd, 32u8);
|
||||
let buf: [32]u8;
|
||||
let m: i32 = strconv.u64toa(buf[0:32], n.uval);
|
||||
os.write(fd, buf.ptr, m: u64);
|
||||
} else { if (n.kind == N_RUNELIT) {
|
||||
putc1(fd, 32u8);
|
||||
let buf: [32]u8;
|
||||
let m: i32 = strconv.u64toa(buf[0:32], n.uval);
|
||||
os.write(fd, buf.ptr, m: u64);
|
||||
} else { if (
|
||||
n.kind == N_STRLIT ||
|
||||
n.kind == N_IDENT ||
|
||||
n.kind == N_USE ||
|
||||
n.kind == N_DOT ||
|
||||
n.kind == N_DEF ||
|
||||
n.kind == N_TYPEDECL ||
|
||||
n.kind == N_FNDECL ||
|
||||
n.kind == N_PARAM ||
|
||||
n.kind == N_LET ||
|
||||
n.kind == N_TNAME ||
|
||||
n.kind == N_TFIELD ||
|
||||
n.kind == N_FIELD ||
|
||||
n.kind == N_ATTR
|
||||
) {
|
||||
// Match C ast.c: print the str field whenever it's non-nil,
|
||||
// even if its length is zero (e.g. an empty STRLIT prints
|
||||
// `(str ""`).
|
||||
let s: str = n.str;
|
||||
if (s.ptr != nil) {
|
||||
putc1(fd, 32u8);
|
||||
putq(fd, s);
|
||||
};
|
||||
} else { if (
|
||||
n.kind == N_BIN ||
|
||||
n.kind == N_UN ||
|
||||
n.kind == N_ASSIGN
|
||||
) {
|
||||
putc1(fd, 32u8);
|
||||
let on: str = tokname(n.op);
|
||||
os.write(fd, on.ptr, on.len: u64);
|
||||
};};};};
|
||||
|
||||
if (n.kind == N_FNDECL) {
|
||||
if (n.exported != 0) { os.write(fd, " export".ptr, 7u64); };
|
||||
};
|
||||
if (n.kind == N_DEF) {
|
||||
if (n.exported != 0) { os.write(fd, " export".ptr, 7u64); };
|
||||
};
|
||||
if (n.kind == N_TYPEDECL) {
|
||||
if (n.exported != 0) { os.write(fd, " export".ptr, 7u64); };
|
||||
};
|
||||
putc1(fd, 10u8); // '\n'
|
||||
|
||||
if (n.attr != nil) {
|
||||
ind(fd, d + 1);
|
||||
os.write(fd, "(@\n".ptr, 3u64);
|
||||
let m: *node = n.attr;
|
||||
for (m != nil) {
|
||||
pr(fd, m, d + 2);
|
||||
m = m.next;
|
||||
};
|
||||
ind(fd, d + 1);
|
||||
os.write(fd, ")\n".ptr, 2u64);
|
||||
};
|
||||
if (n.lhs != nil) { pr(fd, n.lhs, d + 1); };
|
||||
if (n.rhs != nil) { pr(fd, n.rhs, d + 1); };
|
||||
if (n.cond != nil) { pr(fd, n.cond, d + 1); };
|
||||
if (n.body != nil) { pr(fd, n.body, d + 1); };
|
||||
if (n.els != nil) { pr(fd, n.els, d + 1); };
|
||||
if (n.list != nil) {
|
||||
ind(fd, d + 1);
|
||||
os.write(fd, "(list\n".ptr, 6u64);
|
||||
let m: *node = n.list;
|
||||
for (m != nil) {
|
||||
pr(fd, m, d + 2);
|
||||
m = m.next;
|
||||
};
|
||||
ind(fd, d + 1);
|
||||
os.write(fd, ")\n".ptr, 2u64);
|
||||
};
|
||||
ind(fd, d);
|
||||
os.write(fd, ")\n".ptr, 2u64);
|
||||
};
|
||||
|
||||
export fn astprint(fd: i32, n: *node) void = {
|
||||
pr(fd, n, 0);
|
||||
};
|
||||
Reference in New Issue
Block a user