Files
ww/lib/ww/ast.ww
Hojun-Cho 1ac1d985f6 lib: rename stdlib surface to Hare names; add endian/math
Sweeping rename so the lib/ surface mirrors Hare's stdlib spellings.
- ascii: rune-taking predicates; ishex -> isxdigit
- bufio: rinit -> init; take1/takeline -> readbyte/readline
- bytes: indexsub -> index
- encoding/utf8: runelen -> runesz
- errors: eEOF/eShortRead/... -> eof/underread/...
- fmt: errln -> errorln; println/fprintln return i64
- os: readfull/writefull -> readall/writeall; unlink -> remove
- path: isabs -> abs; drop lastindex (now strings.rbyteindex)
- strconv: u64toa/i64toa -> u64tos/i64tos; parse64/parseu64 -> stoi64/stou64
- strings: drop len/isempty; equal -> compare; indexbyte -> byteindex; +rbyteindex
- types: drop numeric helpers (moved to math)
- new lib/endian (htonu16/ntohu16), lib/math (absi32/absi64)
- net: drop htons (use endian.htonu16)

Callers in selfhost/, lib/ww/, cmd/w6c/cgen.c, and test/wcc/700_e2e.c
updated to match.
2026-05-12 00:45:18 +09:00

344 lines
9.4 KiB
Plaintext

// lib/ww/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;
// Appended at the tail to keep all prior N_* values stable. The
// 990_selfhost test diffs astprint against the C side byte-for-byte.
def N_TYPETEST: i32 = 60;
def N_TYPEASSERT: i32 = 61;
def N_LAST: i32 = 62;
// ---- 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", ...)
module: str, // originating module from `// MODULE: foo`; "" if none
};
export fn newnode(a: *arena, k: i32, file: str, line: i32, col: i32) *node = {
let n: *node = amalloc(a, 208u64): *node; // ≥ 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_TYPETEST) { return "typetest"; };
if (k == N_TYPEASSERT) { return "typeassert"; };
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.u64tos(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.u64tos(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);
};