// 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", ...) 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_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); };