lib/ww + wcc + w6c + wwdump: strip *arena cascade (γ-6)

amalloc has 0 callers post-γ-2; the *arena threaded through
newnode/newscope/newtype/prim/typesinit/type{ptr,slice,array,chan,
named}/lexinit/parserinit/joindotted/checkinit/arenau64tos/cgeninit
and the scope.a / tctx.a / lex.a / parser.a / checker.a / cgen.a
fields are vestigial.

Drop `import mem;` from 15 files, remove six struct fields, strip
*arena from 14 signatures, update ~120 call sites across lib/ww +
wcc + w6c + wwdump. selfhost/test/sym_link.ww fixture drops the
newarena/freearena probe; still exits 42 on scopedefine/scopelookup.
Both main.combined.ww auto-regenerated.

Comments retidied: typ.ww "once per arena" → "once per program";
parse.ww drops "arena-build" qualifier on joindotted; sym.ww drops
mem-sibling-imports rationale.

Verified 132/132 incl. 994_w6c_ww + 995_self_rebuild byte-identity
(the primary symmetric-stages gate).
This commit is contained in:
2026-05-21 13:01:57 +09:00
parent f83e65b82a
commit 353dffb5e8
19 changed files with 543 additions and 824 deletions

View File

@@ -11,7 +11,6 @@ package ww;
import os; import os;
import strconv; import strconv;
import mem;
import tok; import tok;
// ---- Nkind ------------------------------------------------------------ // ---- Nkind ------------------------------------------------------------
@@ -127,7 +126,7 @@ type node = struct {
nmod: str, // originating module from `// MODULE: foo`; "" if none nmod: str, // originating module from `// MODULE: foo`; "" if none
}; };
export fn newnode(a: *arena, k: nkind, file: str, line: i32, col: i32) *node = { export fn newnode(k: nkind, file: str, line: i32, col: i32) *node = {
// fval cast-init: 990's wwdump TK_FLOAT diff requires this file // fval cast-init: 990's wwdump TK_FLOAT diff requires this file
// to tokenise identically through C and ww (lex.ww:382 has the // to tokenise identically through C and ww (lex.ww:382 has the
// same workaround for the cstage %g-formats vs ww-skips divergence). // same workaround for the cstage %g-formats vs ww-skips divergence).

View File

@@ -17,7 +17,6 @@ package lex;
// callers `import lex;` (which dir-enums lib/ww/lex/). // callers `import lex;` (which dir-enums lib/ww/lex/).
import os; import os;
import ascii; import ascii;
import mem;
import strings; import strings;
// isidstart / isidpart — identifier classification. Lexer-local // isidstart / isidpart — identifier classification. Lexer-local
@@ -55,18 +54,16 @@ type lex = struct {
lpos: u64, lpos: u64,
line: i32, line: i32,
col: i32, col: i32,
a: *arena,
errs: i32, errs: i32,
}; };
export fn lexinit(l: *lex, a: *arena, file: str, src: *u8, len: u64) void = { export fn lexinit(l: *lex, file: str, src: *u8, len: u64) void = {
l.file = file; l.file = file;
l.src = src; l.src = src;
l.srclen = len; l.srclen = len;
l.lpos = 0u64; l.lpos = 0u64;
l.line = 1; l.line = 1;
l.col = 1; l.col = 1;
l.a = a;
l.errs = 0; l.errs = 0;
}; };

View File

@@ -3,7 +3,6 @@
package parse; package parse;
import os; import os;
import mem;
import tok; import tok;
// `import encoding.utf8;` — the driver resolves the dotted path to // `import encoding.utf8;` — the driver resolves the dotted path to
@@ -16,7 +15,7 @@ fn parseuse(p: *parser) *node = {
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
advance(p); // past `use` advance(p); // past `use`
let n: *node = newnode(p.a, nkind.N_USE, pf, pl, pc); let n: *node = newnode(nkind.N_USE, pf, pl, pc);
n.nmod = p.curmod; n.nmod = p.curmod;
let leaf: str; let leaf: str;
expectident(p, &leaf); expectident(p, &leaf);
@@ -34,7 +33,7 @@ fn parsedef(p: *parser, exported: i32) *node = {
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
advance(p); // past `def` advance(p); // past `def`
let n: *node = newnode(p.a, nkind.N_DEF, pf, pl, pc); let n: *node = newnode(nkind.N_DEF, pf, pl, pc);
n.nmod = p.curmod; n.nmod = p.curmod;
let id: str; let id: str;
expectident(p, &id); expectident(p, &id);
@@ -57,7 +56,7 @@ fn parselet(p: *parser, exported: i32) *node = {
let is_const: i32 = 0; let is_const: i32 = 0;
if (p.curkind == tkind.TK_CONST) { is_const = 1; }; if (p.curkind == tkind.TK_CONST) { is_const = 1; };
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_LET, pf, pl, pc); let n: *node = newnode(nkind.N_LET, pf, pl, pc);
n.nmod = p.curmod; n.nmod = p.curmod;
let id: str; let id: str;
expectbindname(p, &id); expectbindname(p, &id);
@@ -82,7 +81,7 @@ fn parseattrs(p: *parser) *node = {
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
advance(p); advance(p);
let a: *node = newnode(p.a, nkind.N_ATTR, pf, pl, pc); let a: *node = newnode(nkind.N_ATTR, pf, pl, pc);
let id: str; let id: str;
expectident(p, &id); expectident(p, &id);
a.str = id; a.str = id;
@@ -108,7 +107,7 @@ fn parseparams(p: *parser) *node = {
let pf: str = p.curfile; let pf: str = p.curfile;
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
let n: *node = newnode(p.a, nkind.N_PARAM, pf, pl, pc); let n: *node = newnode(nkind.N_PARAM, pf, pl, pc);
// Param form: (IDENT|'_') ':' type. Anonymous-type-only params // Param form: (IDENT|'_') ':' type. Anonymous-type-only params
// (used in fn type expressions) aren't yet wired here. // (used in fn type expressions) aren't yet wired here.
let id: str; let id: str;
@@ -138,7 +137,7 @@ fn parsefn(p: *parser, exported: i32, attrs: *node) *node = {
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
advance(p); // past `fn` advance(p); // past `fn`
let n: *node = newnode(p.a, nkind.N_FNDECL, pf, pl, pc); let n: *node = newnode(nkind.N_FNDECL, pf, pl, pc);
n.nmod = p.curmod; n.nmod = p.curmod;
let id: str; let id: str;
expectident(p, &id); expectident(p, &id);
@@ -168,7 +167,7 @@ fn parsetypedecl(p: *parser, exported: i32) *node = {
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
advance(p); // past `type` advance(p); // past `type`
let n: *node = newnode(p.a, nkind.N_TYPEDECL, pf, pl, pc); let n: *node = newnode(nkind.N_TYPEDECL, pf, pl, pc);
n.nmod = p.curmod; n.nmod = p.curmod;
let id: str; let id: str;
expectident(p, &id); expectident(p, &id);

View File

@@ -3,7 +3,6 @@
package parse; package parse;
import os; import os;
import mem;
import tok; import tok;
// streqlocal — str-to-str compare. Inlined here to avoid a cross- // streqlocal — str-to-str compare. Inlined here to avoid a cross-
@@ -24,7 +23,7 @@ fn parseprimary(p: *parser) *node = {
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
if (p.curkind == tkind.TK_INT) { if (p.curkind == tkind.TK_INT) {
let n: *node = newnode(p.a, nkind.N_INTLIT, pf, pl, pc); let n: *node = newnode(nkind.N_INTLIT, pf, pl, pc);
n.uval = p.curuval; n.uval = p.curuval;
n.str = p.curtext; n.str = p.curtext;
// Plumb the typed-int suffix (`42i64`, `3u8`) through to // Plumb the typed-int suffix (`42i64`, `3u8`) through to
@@ -38,7 +37,7 @@ fn parseprimary(p: *parser) *node = {
return n; return n;
}; };
if (p.curkind == tkind.TK_FLOAT) { if (p.curkind == tkind.TK_FLOAT) {
let n: *node = newnode(p.a, nkind.N_FLOATLIT, pf, pl, pc); let n: *node = newnode(nkind.N_FLOATLIT, pf, pl, pc);
n.fval = p.curfval; n.fval = p.curfval;
// uval carries the IEEE 754 bit pattern — the lexer sets // uval carries the IEEE 754 bit pattern — the lexer sets
// both, and cgen consumers prefer the integer view so they // both, and cgen consumers prefer the integer view so they
@@ -50,32 +49,32 @@ fn parseprimary(p: *parser) *node = {
return n; return n;
}; };
if (p.curkind == tkind.TK_STR) { if (p.curkind == tkind.TK_STR) {
let n: *node = newnode(p.a, nkind.N_STRLIT, pf, pl, pc); let n: *node = newnode(nkind.N_STRLIT, pf, pl, pc);
n.str = p.curtext; n.str = p.curtext;
advance(p); advance(p);
return n; return n;
}; };
if (p.curkind == tkind.TK_RUNE) { if (p.curkind == tkind.TK_RUNE) {
let n: *node = newnode(p.a, nkind.N_RUNELIT, pf, pl, pc); let n: *node = newnode(nkind.N_RUNELIT, pf, pl, pc);
n.uval = p.curuval; n.uval = p.curuval;
advance(p); advance(p);
return n; return n;
}; };
if (p.curkind == tkind.TK_TRUE) { if (p.curkind == tkind.TK_TRUE) {
advance(p); advance(p);
return newnode(p.a, nkind.N_TRUE, pf, pl, pc); return newnode(nkind.N_TRUE, pf, pl, pc);
}; };
if (p.curkind == tkind.TK_FALSE) { if (p.curkind == tkind.TK_FALSE) {
advance(p); advance(p);
return newnode(p.a, nkind.N_FALSE, pf, pl, pc); return newnode(nkind.N_FALSE, pf, pl, pc);
}; };
if (p.curkind == tkind.TK_NIL) { if (p.curkind == tkind.TK_NIL) {
advance(p); advance(p);
return newnode(p.a, nkind.N_NIL, pf, pl, pc); return newnode(nkind.N_NIL, pf, pl, pc);
}; };
if (p.curkind == tkind.TK_VOID) { if (p.curkind == tkind.TK_VOID) {
advance(p); advance(p);
return newnode(p.a, nkind.N_VOIDLIT, pf, pl, pc); return newnode(nkind.N_VOIDLIT, pf, pl, pc);
}; };
if (p.curkind == tkind.TK_UNDER) { if (p.curkind == tkind.TK_UNDER) {
// Bare `_` — valid only as a discard lvalue. Emit an N_IDENT // Bare `_` — valid only as a discard lvalue. Emit an N_IDENT
@@ -83,14 +82,14 @@ fn parseprimary(p: *parser) *node = {
// already 0); the checker rejects it outside lvalue // already 0); the checker rejects it outside lvalue
// positions. // positions.
advance(p); advance(p);
return newnode(p.a, nkind.N_IDENT, pf, pl, pc); return newnode(nkind.N_IDENT, pf, pl, pc);
}; };
if (p.curkind == tkind.TK_LBRACK) { if (p.curkind == tkind.TK_LBRACK) {
// Array literal `[a, b, c]` or `[v, w...]` (repeat suffix). // Array literal `[a, b, c]` or `[v, w...]` (repeat suffix).
// The repeat marker is an nkind.N_FIELD node with str = "..." // The repeat marker is an nkind.N_FIELD node with str = "..."
// appended to the element list so cgen can detect it. // appended to the element list so cgen can detect it.
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_ARRLIT, pf, pl, pc); let n: *node = newnode(nkind.N_ARRLIT, pf, pl, pc);
let head: *node = nil; let head: *node = nil;
let tail: *node = nil; let tail: *node = nil;
for (p.curkind != tkind.TK_RBRACK) { for (p.curkind != tkind.TK_RBRACK) {
@@ -99,7 +98,7 @@ fn parseprimary(p: *parser) *node = {
if (head == nil) { head = e; tail = e; } if (head == nil) { head = e; tail = e; }
else { tail.next = e; tail = e; }; else { tail.next = e; tail = e; };
if (accepttok(p, tkind.TK_ELLIPSIS)) { if (accepttok(p, tkind.TK_ELLIPSIS)) {
let rep: *node = newnode(p.a, nkind.N_FIELD, let rep: *node = newnode(nkind.N_FIELD,
p.curfile, p.curline, p.curcol); p.curfile, p.curline, p.curcol);
rep.str = "..."; rep.str = "...";
tail.next = rep; tail.next = rep;
@@ -117,7 +116,7 @@ fn parseprimary(p: *parser) *node = {
let e: *node = parseexpr(p); let e: *node = parseexpr(p);
// Tuple literal: (a, b, ...) // Tuple literal: (a, b, ...)
if (accepttok(p, tkind.TK_COMMA)) { if (accepttok(p, tkind.TK_COMMA)) {
let t: *node = newnode(p.a, nkind.N_TUPLE, pf, pl, pc); let t: *node = newnode(nkind.N_TUPLE, pf, pl, pc);
t.list = e; t.list = e;
let tail: *node = e; let tail: *node = e;
for (true) { for (true) {
@@ -134,7 +133,7 @@ fn parseprimary(p: *parser) *node = {
return e; return e;
}; };
if (p.curkind == tkind.TK_IDENT) { if (p.curkind == tkind.TK_IDENT) {
let n: *node = newnode(p.a, nkind.N_IDENT, pf, pl, pc); let n: *node = newnode(nkind.N_IDENT, pf, pl, pc);
n.str = p.curtext; n.str = p.curtext;
advance(p); advance(p);
// `IDENT {` — struct literal. Disambiguate: only consume as a // `IDENT {` — struct literal. Disambiguate: only consume as a
@@ -145,7 +144,7 @@ fn parseprimary(p: *parser) *node = {
// own paren/cond, so this is safe. // own paren/cond, so this is safe.
if (p.curkind == tkind.TK_LBRACE) { if (p.curkind == tkind.TK_LBRACE) {
advance(p); advance(p);
let s: *node = newnode(p.a, nkind.N_STRUCTLIT, pf, pl, pc); let s: *node = newnode(nkind.N_STRUCTLIT, pf, pl, pc);
s.lhs = n; s.lhs = n;
let head: *node = nil; let head: *node = nil;
let tail: *node = nil; let tail: *node = nil;
@@ -165,7 +164,7 @@ fn parseprimary(p: *parser) *node = {
expectident(p, &id); expectident(p, &id);
expecttok(p, tkind.TK_ASSIGN, "expected '=' in struct lit field"); expecttok(p, tkind.TK_ASSIGN, "expected '=' in struct lit field");
let v: *node = parseexpr(p); let v: *node = parseexpr(p);
let f: *node = newnode(p.a, nkind.N_FIELD, fpf, fpl, fpc); let f: *node = newnode(nkind.N_FIELD, fpf, fpl, fpc);
f.str = id; f.str = id;
f.lhs = v; f.lhs = v;
if (head == nil) { head = f; tail = f; } if (head == nil) { head = f; tail = f; }
@@ -182,7 +181,7 @@ fn parseprimary(p: *parser) *node = {
// match (e) { case let v: T => stmt; case T => stmt; case => stmt; }; // match (e) { case let v: T => stmt; case T => stmt; case => stmt; };
advance(p); advance(p);
expecttok(p, tkind.TK_LPAREN, "expected '(' after match"); expecttok(p, tkind.TK_LPAREN, "expected '(' after match");
let m: *node = newnode(p.a, nkind.N_MATCH, pf, pl, pc); let m: *node = newnode(nkind.N_MATCH, pf, pl, pc);
m.lhs = parseexpr(p); m.lhs = parseexpr(p);
expecttok(p, tkind.TK_RPAREN, "expected ')' after match scrutinee"); expecttok(p, tkind.TK_RPAREN, "expected ')' after match scrutinee");
expecttok(p, tkind.TK_LBRACE, "expected '{' to open match body"); expecttok(p, tkind.TK_LBRACE, "expected '{' to open match body");
@@ -193,7 +192,7 @@ fn parseprimary(p: *parser) *node = {
let cl: i32 = p.curline; let cl: i32 = p.curline;
let cc: i32 = p.curcol; let cc: i32 = p.curcol;
advance(p); // past `case` advance(p); // past `case`
let mc: *node = newnode(p.a, nkind.N_MCASE, cf, cl, cc); let mc: *node = newnode(nkind.N_MCASE, cf, cl, cc);
if (p.curkind == tkind.TK_LET) { if (p.curkind == tkind.TK_LET) {
advance(p); advance(p);
let id: str; let id: str;
@@ -215,7 +214,7 @@ fn parseprimary(p: *parser) *node = {
}; };
errmsg(p, "expected expression"); errmsg(p, "expected expression");
advance(p); advance(p);
return newnode(p.a, nkind.N_NONE, pf, pl, pc); return newnode(nkind.N_NONE, pf, pl, pc);
}; };
fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = { fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = {
@@ -229,7 +228,7 @@ fn parsearglist(p: *parser, closekind: tkind, headout: **node) void = {
// marker the callee/builtin can iterate over. Mirrors // marker the callee/builtin can iterate over. Mirrors
// cmd/wcc/parse.c. The only consumer today is `append`. // cmd/wcc/parse.c. The only consumer today is `append`.
if (accepttok(p, tkind.TK_ELLIPSIS)) { if (accepttok(p, tkind.TK_ELLIPSIS)) {
let sp: *node = newnode(p.a, nkind.N_SPREAD, e.file, e.line, e.col); let sp: *node = newnode(nkind.N_SPREAD, e.file, e.line, e.col);
sp.lhs = e; sp.lhs = e;
e = sp; e = sp;
}; };
@@ -249,7 +248,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
if (p.curkind == tkind.TK_LPAREN) { if (p.curkind == tkind.TK_LPAREN) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_CALL, pf, pl, pc); let n: *node = newnode(nkind.N_CALL, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
// size(T)/align(T): the single arg is a type expression, // size(T)/align(T): the single arg is a type expression,
// not a regular expression. Special-case at the parser. // not a regular expression. Special-case at the parser.
@@ -274,7 +273,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
// `[ : hi ]` — slice with implicit lo = 0. // `[ : hi ]` — slice with implicit lo = 0.
if (p.curkind == tkind.TK_COLON) { if (p.curkind == tkind.TK_COLON) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_SLICE, pf, pl, pc); let n: *node = newnode(nkind.N_SLICE, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
if (p.curkind != tkind.TK_RBRACK) { if (p.curkind != tkind.TK_RBRACK) {
n.cond = parseexpr(p); n.cond = parseexpr(p);
@@ -291,7 +290,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
p.nocast = prev; p.nocast = prev;
if (p.curkind == tkind.TK_COLON) { if (p.curkind == tkind.TK_COLON) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_SLICE, pf, pl, pc); let n: *node = newnode(nkind.N_SLICE, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
n.rhs = e; n.rhs = e;
if (p.curkind != tkind.TK_RBRACK) { if (p.curkind != tkind.TK_RBRACK) {
@@ -301,7 +300,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
cur = n; cur = n;
continue; continue;
}; };
let n: *node = newnode(p.a, nkind.N_INDEX, pf, pl, pc); let n: *node = newnode(nkind.N_INDEX, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
n.rhs = e; n.rhs = e;
expecttok(p, tkind.TK_RBRACK, "expected ']' after index"); expecttok(p, tkind.TK_RBRACK, "expected ']' after index");
@@ -310,7 +309,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
}; };
if (p.curkind == tkind.TK_DOT) { if (p.curkind == tkind.TK_DOT) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_DOT, pf, pl, pc); let n: *node = newnode(nkind.N_DOT, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
// Hare-style tuple field access: `t.0`, `t.1`. The // Hare-style tuple field access: `t.0`, `t.1`. The
// numeric literal becomes the field name string so the // numeric literal becomes the field name string so the
@@ -331,7 +330,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
return cur; return cur;
}; };
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_CAST, pf, pl, pc); let n: *node = newnode(nkind.N_CAST, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
n.rhs = parsetype(p); n.rhs = parsetype(p);
cur = n; cur = n;
@@ -343,7 +342,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
// Same precedence level as the `:` cast. // Same precedence level as the `:` cast.
if (p.curkind == tkind.TK_AS) { if (p.curkind == tkind.TK_AS) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_TYPEASSERT, pf, pl, pc); let n: *node = newnode(nkind.N_TYPEASSERT, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
n.rhs = parsetype(p); n.rhs = parsetype(p);
cur = n; cur = n;
@@ -351,7 +350,7 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
}; };
if (p.curkind == tkind.TK_IS) { if (p.curkind == tkind.TK_IS) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_TYPETEST, pf, pl, pc); let n: *node = newnode(nkind.N_TYPETEST, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
n.rhs = parsetype(p); n.rhs = parsetype(p);
cur = n; cur = n;
@@ -361,14 +360,14 @@ fn parsepostfix(p: *parser, lhs: *node) *node = {
// `e!` — abort on error variant. // `e!` — abort on error variant.
if (p.curkind == tkind.TK_QUESTION) { if (p.curkind == tkind.TK_QUESTION) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_TRYPROP, pf, pl, pc); let n: *node = newnode(nkind.N_TRYPROP, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
cur = n; cur = n;
continue; continue;
}; };
if (p.curkind == tkind.TK_NOT) { if (p.curkind == tkind.TK_NOT) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_TRYUNW, pf, pl, pc); let n: *node = newnode(nkind.N_TRYUNW, pf, pl, pc);
n.lhs = cur; n.lhs = cur;
cur = n; cur = n;
continue; continue;
@@ -385,37 +384,37 @@ fn parseunary(p: *parser) *node = {
let k: tkind = p.curkind; let k: tkind = p.curkind;
if (k == tkind.TK_MINUS) { if (k == tkind.TK_MINUS) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); let n: *node = newnode(nkind.N_UN, pf, pl, pc);
n.op = tkind.TK_MINUS; n.lhs = parseunary(p); n.op = tkind.TK_MINUS; n.lhs = parseunary(p);
return n; return n;
}; };
if (k == tkind.TK_PLUS) { if (k == tkind.TK_PLUS) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); let n: *node = newnode(nkind.N_UN, pf, pl, pc);
n.op = tkind.TK_PLUS; n.lhs = parseunary(p); n.op = tkind.TK_PLUS; n.lhs = parseunary(p);
return n; return n;
}; };
if (k == tkind.TK_NOT) { if (k == tkind.TK_NOT) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); let n: *node = newnode(nkind.N_UN, pf, pl, pc);
n.op = tkind.TK_NOT; n.lhs = parseunary(p); n.op = tkind.TK_NOT; n.lhs = parseunary(p);
return n; return n;
}; };
if (k == tkind.TK_TILDE) { if (k == tkind.TK_TILDE) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); let n: *node = newnode(nkind.N_UN, pf, pl, pc);
n.op = tkind.TK_TILDE; n.lhs = parseunary(p); n.op = tkind.TK_TILDE; n.lhs = parseunary(p);
return n; return n;
}; };
if (k == tkind.TK_STAR) { if (k == tkind.TK_STAR) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); let n: *node = newnode(nkind.N_UN, pf, pl, pc);
n.op = tkind.TK_STAR; n.lhs = parseunary(p); n.op = tkind.TK_STAR; n.lhs = parseunary(p);
return n; return n;
}; };
if (k == tkind.TK_AMP) { if (k == tkind.TK_AMP) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_UN, pf, pl, pc); let n: *node = newnode(nkind.N_UN, pf, pl, pc);
n.op = tkind.TK_AMP; n.lhs = parseunary(p); n.op = tkind.TK_AMP; n.lhs = parseunary(p);
return n; return n;
}; };
@@ -439,7 +438,7 @@ fn parsebin(p: *parser, lhs: *node, minp: i32) *node = {
if (np <= pr) { break; }; if (np <= pr) { break; };
rhs = parsebin(p, rhs, np); rhs = parsebin(p, rhs, np);
}; };
let n: *node = newnode(p.a, nkind.N_BIN, pf, pl, pc); let n: *node = newnode(nkind.N_BIN, pf, pl, pc);
n.op = op; n.lhs = cur; n.rhs = rhs; n.op = op; n.lhs = cur; n.rhs = rhs;
cur = n; cur = n;
}; };
@@ -454,7 +453,7 @@ fn parseexpr(p: *parser) *node = {
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
let op: tkind = p.curkind; let op: tkind = p.curkind;
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_ASSIGN, pf, pl, pc); let n: *node = newnode(nkind.N_ASSIGN, pf, pl, pc);
n.op = op; n.op = op;
n.lhs = e; n.lhs = e;
n.rhs = parseexpr(p); // right-associative n.rhs = parseexpr(p); // right-associative

View File

@@ -16,12 +16,10 @@ package parse;
// dir-enum when callers `import parse;` (which dir-enums // dir-enum when callers `import parse;` (which dir-enums
// lib/ww/parse/). // lib/ww/parse/).
import os; import os;
import mem;
import tok; import tok;
type parser = struct { type parser = struct {
l: *lex, l: *lex,
a: *arena,
errs: i32, errs: i32,
// nocast: while inside `[...]` we treat ':' as the slice // nocast: while inside `[...]` we treat ':' as the slice
// separator, not the cast operator. Mirrors parse.c's flag. // separator, not the cast operator. Mirrors parse.c's flag.
@@ -60,9 +58,8 @@ fn refill(p: *parser) void = {
p.curtsuffix = t.tsuffix; p.curtsuffix = t.tsuffix;
}; };
export fn parserinit(p: *parser, a: *arena, l: *lex) void = { export fn parserinit(p: *parser, l: *lex) void = {
p.l = l; p.l = l;
p.a = a;
p.errs = 0; p.errs = 0;
p.nocast = 0; p.nocast = 0;
refill(p); refill(p);
@@ -120,10 +117,10 @@ fn expectbindname(p: *parser, into: *str) bool = {
// Other forms (slice, array, struct, fn, chan, tuple, tagged) will // Other forms (slice, array, struct, fn, chan, tuple, tagged) will
// land in subsequent commits. // land in subsequent commits.
// joindotted — arena-build "head.tail" for dotted type-name path // joindotted — build "head.tail" for dotted type-name path
// collapse. Mirrors aprintf in C parser; pulled local to avoid a // collapse. Mirrors aprintf in C parser; pulled local to avoid a
// cross-module dependency. // cross-module dependency.
fn joindotted(a: *arena, head: str, tail: str) str = { fn joindotted(head: str, tail: str) str = {
let n: u64 = head.len: u64 + 1u64 + tail.len: u64; let n: u64 = head.len: u64 + 1u64 + tail.len: u64;
let buf: []u8 = alloc([], n + 1u64)!; let buf: []u8 = alloc([], n + 1u64)!;
let i: u64 = 0u64; let i: u64 = 0u64;
@@ -148,14 +145,14 @@ fn parsetype(p: *parser) *node = {
if (p.curkind == tkind.TK_NOT) { if (p.curkind == tkind.TK_NOT) {
// `!T` — Hare error-flagged type wrapper. // `!T` — Hare error-flagged type wrapper.
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_TBANG, pf, pl, pc); let n: *node = newnode(nkind.N_TBANG, pf, pl, pc);
n.lhs = parsetype(p); n.lhs = parsetype(p);
return n; return n;
}; };
if (p.curkind == tkind.TK_STAR) { if (p.curkind == tkind.TK_STAR) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_TPTR, pf, pl, pc); let n: *node = newnode(nkind.N_TPTR, pf, pl, pc);
n.lhs = parsetype(p); n.lhs = parsetype(p);
return n; return n;
}; };
@@ -164,11 +161,11 @@ fn parsetype(p: *parser) *node = {
advance(p); advance(p);
if (p.curkind == tkind.TK_RBRACK) { if (p.curkind == tkind.TK_RBRACK) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_TSLICE, pf, pl, pc); let n: *node = newnode(nkind.N_TSLICE, pf, pl, pc);
n.lhs = parsetype(p); n.lhs = parsetype(p);
return n; return n;
}; };
let n: *node = newnode(p.a, nkind.N_TARRAY, pf, pl, pc); let n: *node = newnode(nkind.N_TARRAY, pf, pl, pc);
// `[_]T` — length inferred from initialiser. n.rhs stays nil // `[_]T` — length inferred from initialiser. n.rhs stays nil
// as the sentinel; the cgen path for nkind.N_LET fills it from the // as the sentinel; the cgen path for nkind.N_LET fills it from the
// array literal's element count. // array literal's element count.
@@ -185,7 +182,7 @@ fn parsetype(p: *parser) *node = {
if (p.curkind == tkind.TK_STRUCT) { if (p.curkind == tkind.TK_STRUCT) {
advance(p); advance(p);
expecttok(p, tkind.TK_LBRACE, "expected '{' after struct"); expecttok(p, tkind.TK_LBRACE, "expected '{' after struct");
let n: *node = newnode(p.a, nkind.N_TSTRUCT, pf, pl, pc); let n: *node = newnode(nkind.N_TSTRUCT, pf, pl, pc);
let fhead: *node = nil; let fhead: *node = nil;
let ftail: *node = nil; let ftail: *node = nil;
for (p.curkind != tkind.TK_RBRACE) { for (p.curkind != tkind.TK_RBRACE) {
@@ -193,7 +190,7 @@ fn parsetype(p: *parser) *node = {
let fpf: str = p.curfile; let fpf: str = p.curfile;
let fpl: i32 = p.curline; let fpl: i32 = p.curline;
let fpc: i32 = p.curcol; let fpc: i32 = p.curcol;
let f: *node = newnode(p.a, nkind.N_TFIELD, fpf, fpl, fpc); let f: *node = newnode(nkind.N_TFIELD, fpf, fpl, fpc);
let fid: str; let fid: str;
expectident(p, &fid); expectident(p, &fid);
f.str = fid; f.str = fid;
@@ -214,7 +211,7 @@ fn parsetype(p: *parser) *node = {
// nkind.N_TENUMMEMBER with str=name and lhs = value expr or nil // nkind.N_TENUMMEMBER with str=name and lhs = value expr or nil
// (auto-increment when omitted). // (auto-increment when omitted).
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_TENUM, pf, pl, pc); let n: *node = newnode(nkind.N_TENUM, pf, pl, pc);
if (p.curkind != tkind.TK_LBRACE) { if (p.curkind != tkind.TK_LBRACE) {
n.lhs = parsetype(p); n.lhs = parsetype(p);
}; };
@@ -226,7 +223,7 @@ fn parsetype(p: *parser) *node = {
let mpf: str = p.curfile; let mpf: str = p.curfile;
let mpl: i32 = p.curline; let mpl: i32 = p.curline;
let mpc: i32 = p.curcol; let mpc: i32 = p.curcol;
let m: *node = newnode(p.a, nkind.N_TENUMMEMBER, mpf, mpl, mpc); let m: *node = newnode(nkind.N_TENUMMEMBER, mpf, mpl, mpc);
let mid: str; let mid: str;
expectident(p, &mid); expectident(p, &mid);
m.str = mid; m.str = mid;
@@ -245,14 +242,14 @@ fn parsetype(p: *parser) *node = {
if (p.curkind == tkind.TK_VOID) { if (p.curkind == tkind.TK_VOID) {
// `void` keyword in type-expr context — emit as nkind.N_TNAME so // `void` keyword in type-expr context — emit as nkind.N_TNAME so
// resolution treats it like any other primitive name. // resolution treats it like any other primitive name.
let n: *node = newnode(p.a, nkind.N_TNAME, pf, pl, pc); let n: *node = newnode(nkind.N_TNAME, pf, pl, pc);
n.str = "void"; n.str = "void";
advance(p); advance(p);
return n; return n;
}; };
if (p.curkind == tkind.TK_IDENT) { if (p.curkind == tkind.TK_IDENT) {
let n: *node = newnode(p.a, nkind.N_TNAME, pf, pl, pc); let n: *node = newnode(nkind.N_TNAME, pf, pl, pc);
let acc: str = p.curtext; let acc: str = p.curtext;
advance(p); advance(p);
// Dotted path collapse: pkg.Type → single TNAME with the // Dotted path collapse: pkg.Type → single TNAME with the
@@ -260,7 +257,7 @@ fn parsetype(p: *parser) *node = {
for (p.curkind == tkind.TK_DOT) { for (p.curkind == tkind.TK_DOT) {
advance(p); advance(p);
if (p.curkind != tkind.TK_IDENT) { break; }; if (p.curkind != tkind.TK_IDENT) { break; };
acc = joindotted(p.a, acc, p.curtext); acc = joindotted(acc, p.curtext);
advance(p); advance(p);
}; };
n.str = acc; n.str = acc;
@@ -280,7 +277,7 @@ fn parsetype(p: *parser) *node = {
let first: *node = parsetype(p); let first: *node = parsetype(p);
if (firstspread) { first.op = tkind.TK_ELLIPSIS; }; if (firstspread) { first.op = tkind.TK_ELLIPSIS; };
if (accepttok(p, tkind.TK_PIPE)) { if (accepttok(p, tkind.TK_PIPE)) {
let n: *node = newnode(p.a, nkind.N_TTAGGED, pf, pl, pc); let n: *node = newnode(nkind.N_TTAGGED, pf, pl, pc);
let head: *node = first; let head: *node = first;
let tail: *node = first; let tail: *node = first;
for (true) { for (true) {
@@ -302,7 +299,7 @@ fn parsetype(p: *parser) *node = {
expecttok(p, tkind.TK_RPAREN, "expected ')' after parenthesised type"); expecttok(p, tkind.TK_RPAREN, "expected ')' after parenthesised type");
return first; return first;
}; };
let n: *node = newnode(p.a, nkind.N_TTUPLE, pf, pl, pc); let n: *node = newnode(nkind.N_TTUPLE, pf, pl, pc);
let head: *node = first; let head: *node = first;
let tail: *node = first; let tail: *node = first;
for (true) { for (true) {
@@ -320,7 +317,7 @@ fn parsetype(p: *parser) *node = {
if (p.curkind == tkind.TK_FN) { if (p.curkind == tkind.TK_FN) {
advance(p); advance(p);
expecttok(p, tkind.TK_LPAREN, "expected '(' after fn in type"); expecttok(p, tkind.TK_LPAREN, "expected '(' after fn in type");
let n: *node = newnode(p.a, nkind.N_TFN, pf, pl, pc); let n: *node = newnode(nkind.N_TFN, pf, pl, pc);
// Anonymous-or-named params: parseparams handles named only; // Anonymous-or-named params: parseparams handles named only;
// for fn-type expressions the C parser allows IDENT-less // for fn-type expressions the C parser allows IDENT-less
// (anonymous) params. Stub: only named params for now. // (anonymous) params. Stub: only named params for now.
@@ -332,7 +329,7 @@ fn parsetype(p: *parser) *node = {
errmsg(p, "expected type"); errmsg(p, "expected type");
advance(p); advance(p);
return newnode(p.a, nkind.N_TNAME, pf, pl, pc); return newnode(nkind.N_TNAME, pf, pl, pc);
}; };
// ---- expressions (Pratt) --------------------------------------------- // ---- expressions (Pratt) ---------------------------------------------
@@ -383,7 +380,7 @@ fn isassignop(k: tkind) bool = {
// are resolved by the two-pass checker — no body-less prototypes needed. // are resolved by the two-pass checker — no body-less prototypes needed.
export fn parsefile(p: *parser) *node = { export fn parsefile(p: *parser) *node = {
let f: *node = newnode(p.a, nkind.N_FILE, p.curfile, p.curline, p.curcol); let f: *node = newnode(nkind.N_FILE, p.curfile, p.curline, p.curcol);
let head: *node = nil; let head: *node = nil;
let tail: *node = nil; let tail: *node = nil;
for (p.curkind != tkind.TK_EOF) { for (p.curkind != tkind.TK_EOF) {

View File

@@ -3,7 +3,6 @@
package parse; package parse;
import os; import os;
import mem;
import tok; import tok;
fn parseletlocal(p: *parser) *node = { fn parseletlocal(p: *parser) *node = {
@@ -20,14 +19,14 @@ fn parseletlocal(p: *parser) *node = {
// doesn't allow types here, but cmd/wcc/parse.c does). // doesn't allow types here, but cmd/wcc/parse.c does).
if (p.curkind == tkind.TK_LPAREN) { if (p.curkind == tkind.TK_LPAREN) {
advance(p); advance(p);
let m: *node = newnode(p.a, nkind.N_MLET, pf, pl, pc); let m: *node = newnode(nkind.N_MLET, pf, pl, pc);
let head: *node = nil; let head: *node = nil;
let tail: *node = nil; let tail: *node = nil;
for (true) { for (true) {
let lpf: str = p.curfile; let lpf: str = p.curfile;
let lpl: i32 = p.curline; let lpl: i32 = p.curline;
let lpc: i32 = p.curcol; let lpc: i32 = p.curcol;
let l: *node = newnode(p.a, nkind.N_LET, lpf, lpl, lpc); let l: *node = newnode(nkind.N_LET, lpf, lpl, lpc);
let id: str; let id: str;
expectbindname(p, &id); expectbindname(p, &id);
l.str = id; l.str = id;
@@ -50,7 +49,7 @@ fn parseletlocal(p: *parser) *node = {
return m; return m;
}; };
let n: *node = newnode(p.a, nkind.N_LET, pf, pl, pc); let n: *node = newnode(nkind.N_LET, pf, pl, pc);
let id: str; let id: str;
expectbindname(p, &id); expectbindname(p, &id);
n.str = id; n.str = id;
@@ -61,14 +60,14 @@ fn parseletlocal(p: *parser) *node = {
// Collects (name, type) pairs, then '=' rhs. Each binding gets // Collects (name, type) pairs, then '=' rhs. Each binding gets
// its own nkind.N_LET; the wrapping nkind.N_MLET carries the rhs. // its own nkind.N_LET; the wrapping nkind.N_MLET carries the rhs.
if (p.curkind == tkind.TK_COMMA) { if (p.curkind == tkind.TK_COMMA) {
let m: *node = newnode(p.a, nkind.N_MLET, pf, pl, pc); let m: *node = newnode(nkind.N_MLET, pf, pl, pc);
let head: *node = n; let head: *node = n;
let tail: *node = n; let tail: *node = n;
for (accepttok(p, tkind.TK_COMMA)) { for (accepttok(p, tkind.TK_COMMA)) {
let lpf: str = p.curfile; let lpf: str = p.curfile;
let lpl: i32 = p.curline; let lpl: i32 = p.curline;
let lpc: i32 = p.curcol; let lpc: i32 = p.curcol;
let l: *node = newnode(p.a, nkind.N_LET, lpf, lpl, lpc); let l: *node = newnode(nkind.N_LET, lpf, lpl, lpc);
let id2: str; let id2: str;
expectbindname(p, &id2); expectbindname(p, &id2);
l.str = id2; l.str = id2;
@@ -100,7 +99,7 @@ fn parseblock(p: *parser) *node = {
let pl: i32 = p.curline; let pl: i32 = p.curline;
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
expecttok(p, tkind.TK_LBRACE, "expected '{' to open block"); expecttok(p, tkind.TK_LBRACE, "expected '{' to open block");
let blk: *node = newnode(p.a, nkind.N_BLOCK, pf, pl, pc); let blk: *node = newnode(nkind.N_BLOCK, pf, pl, pc);
let head: *node = nil; let head: *node = nil;
let tail: *node = nil; let tail: *node = nil;
for (p.curkind != tkind.TK_RBRACE) { for (p.curkind != tkind.TK_RBRACE) {
@@ -122,7 +121,7 @@ fn parseif(p: *parser) *node = {
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
advance(p); // past `if` advance(p); // past `if`
expecttok(p, tkind.TK_LPAREN, "expected '(' after if"); expecttok(p, tkind.TK_LPAREN, "expected '(' after if");
let n: *node = newnode(p.a, nkind.N_IF, pf, pl, pc); let n: *node = newnode(nkind.N_IF, pf, pl, pc);
n.cond = parseexpr(p); n.cond = parseexpr(p);
expecttok(p, tkind.TK_RPAREN, "expected ')' after if condition"); expecttok(p, tkind.TK_RPAREN, "expected ')' after if condition");
n.body = parseblock(p); n.body = parseblock(p);
@@ -162,7 +161,7 @@ fn parsefor(p: *parser) *node = {
let npf: str = p.curfile; let npf: str = p.curfile;
let npl: i32 = p.curline; let npl: i32 = p.curline;
let npc: i32 = p.curcol; let npc: i32 = p.curcol;
let e: *node = newnode(p.a, nkind.N_IDENT, npf, npl, npc); let e: *node = newnode(nkind.N_IDENT, npf, npl, npc);
let nm: str; let nm: str;
expectbindname(p, &nm); expectbindname(p, &nm);
e.str = nm; e.str = nm;
@@ -173,7 +172,7 @@ fn parsefor(p: *parser) *node = {
}; };
expecttok(p, tkind.TK_RPAREN, "expected ')' in for-range names"); expecttok(p, tkind.TK_RPAREN, "expected ')' in for-range names");
expecttok(p, tkind.TK_DOTDOT, "expected '..' after for-range names"); expecttok(p, tkind.TK_DOTDOT, "expected '..' after for-range names");
let rng: *node = newnode(p.a, nkind.N_FORRANGE, pf, pl, pc); let rng: *node = newnode(nkind.N_FORRANGE, pf, pl, pc);
rng.list = names; rng.list = names;
rng.lhs = parseexpr(p); rng.lhs = parseexpr(p);
expecttok(p, tkind.TK_RPAREN, "expected ')' after for"); expecttok(p, tkind.TK_RPAREN, "expected ')' after for");
@@ -198,7 +197,7 @@ fn parsefor(p: *parser) *node = {
if (p.curkind == tkind.TK_DOTDOT) { if (p.curkind == tkind.TK_DOTDOT) {
advance(p); advance(p);
let rng: *node = newnode(p.a, nkind.N_FORRANGE, pf, pl, pc); let rng: *node = newnode(nkind.N_FORRANGE, pf, pl, pc);
rng.str = nm; // "" for `_` rng.str = nm; // "" for `_`
rng.lhs = parseexpr(p); rng.lhs = parseexpr(p);
expecttok(p, tkind.TK_RPAREN, "expected ')' after for"); expecttok(p, tkind.TK_RPAREN, "expected ')' after for");
@@ -209,12 +208,12 @@ fn parsefor(p: *parser) *node = {
// Not a range — finish the let manually and continue as // Not a range — finish the let manually and continue as
// a 3-clause for-init. // a 3-clause for-init.
let first: *node = newnode(p.a, nkind.N_LET, lpf, lpl, lpc); let first: *node = newnode(nkind.N_LET, lpf, lpl, lpc);
first.str = nm; first.str = nm;
if (accepttok(p, tkind.TK_COLON)) { first.lhs = parsetype(p); }; if (accepttok(p, tkind.TK_COLON)) { first.lhs = parsetype(p); };
if (accepttok(p, tkind.TK_ASSIGN)) { first.rhs = parseexpr(p); }; if (accepttok(p, tkind.TK_ASSIGN)) { first.rhs = parseexpr(p); };
expecttok(p, tkind.TK_SEMI, "expected ';' after for-init let"); expecttok(p, tkind.TK_SEMI, "expected ';' after for-init let");
let n: *node = newnode(p.a, nkind.N_FOR, pf, pl, pc); let n: *node = newnode(nkind.N_FOR, pf, pl, pc);
n.lhs = first; n.lhs = first;
n.cond = parseexpr(p); n.cond = parseexpr(p);
expecttok(p, tkind.TK_SEMI, "expected ';' after for cond"); expecttok(p, tkind.TK_SEMI, "expected ';' after for cond");
@@ -229,7 +228,7 @@ fn parsefor(p: *parser) *node = {
}; };
// for (cond) or for (cond; post) // for (cond) or for (cond; post)
let n: *node = newnode(p.a, nkind.N_FOR, pf, pl, pc); let n: *node = newnode(nkind.N_FOR, pf, pl, pc);
let first: *node = parseexpr(p); let first: *node = parseexpr(p);
if (accepttok(p, tkind.TK_SEMI)) { if (accepttok(p, tkind.TK_SEMI)) {
n.cond = first; n.cond = first;
@@ -253,7 +252,7 @@ fn parseswitch(p: *parser) *node = {
let pc: i32 = p.curcol; let pc: i32 = p.curcol;
advance(p); // past `switch` advance(p); // past `switch`
expecttok(p, tkind.TK_LPAREN, "expected '(' after switch"); expecttok(p, tkind.TK_LPAREN, "expected '(' after switch");
let n: *node = newnode(p.a, nkind.N_SWITCH, pf, pl, pc); let n: *node = newnode(nkind.N_SWITCH, pf, pl, pc);
n.lhs = parseexpr(p); n.lhs = parseexpr(p);
expecttok(p, tkind.TK_RPAREN, "expected ')' after switch expression"); expecttok(p, tkind.TK_RPAREN, "expected ')' after switch expression");
expecttok(p, tkind.TK_LBRACE, "expected '{' to open switch body"); expecttok(p, tkind.TK_LBRACE, "expected '{' to open switch body");
@@ -264,7 +263,7 @@ fn parseswitch(p: *parser) *node = {
let cpl: i32 = p.curline; let cpl: i32 = p.curline;
let cpc: i32 = p.curcol; let cpc: i32 = p.curcol;
advance(p); // past `case` advance(p); // past `case`
let cs: *node = newnode(p.a, nkind.N_CASE, cpf, cpl, cpc); let cs: *node = newnode(nkind.N_CASE, cpf, cpl, cpc);
let eh: *node = nil; let eh: *node = nil;
let et: *node = nil; let et: *node = nil;
if (p.curkind != tkind.TK_COLON) { if (p.curkind != tkind.TK_COLON) {
@@ -292,7 +291,7 @@ fn parseswitch(p: *parser) *node = {
bt = s; bt = s;
}; };
}; };
let blk: *node = newnode(p.a, nkind.N_BLOCK, cpf, cpl, cpc); let blk: *node = newnode(nkind.N_BLOCK, cpf, cpl, cpc);
blk.list = bh; blk.list = bh;
cs.body = blk; cs.body = blk;
if (head == nil) { head = cs; } if (head == nil) { head = cs; }
@@ -337,13 +336,13 @@ fn parsestmt(p: *parser) *node = {
}; };
if (p.curkind == tkind.TK_RETURN) { if (p.curkind == tkind.TK_RETURN) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_RETURN, pf, pl, pc); let n: *node = newnode(nkind.N_RETURN, pf, pl, pc);
if (p.curkind != tkind.TK_SEMI) { if (p.curkind != tkind.TK_SEMI) {
let first: *node = parseexpr(p); let first: *node = parseexpr(p);
// Hare-style multi-value: `return a, b;` becomes a // Hare-style multi-value: `return a, b;` becomes a
// tuple expression so codegen sees one rvalue. // tuple expression so codegen sees one rvalue.
if (p.curkind == tkind.TK_COMMA) { if (p.curkind == tkind.TK_COMMA) {
let t: *node = newnode(p.a, nkind.N_TUPLE, pf, pl, pc); let t: *node = newnode(nkind.N_TUPLE, pf, pl, pc);
t.list = first; t.list = first;
let tail: *node = first; let tail: *node = first;
for (accepttok(p, tkind.TK_COMMA)) { for (accepttok(p, tkind.TK_COMMA)) {
@@ -361,14 +360,14 @@ fn parsestmt(p: *parser) *node = {
}; };
if (p.curkind == tkind.TK_DEFER) { if (p.curkind == tkind.TK_DEFER) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_DEFER, pf, pl, pc); let n: *node = newnode(nkind.N_DEFER, pf, pl, pc);
n.lhs = parseexpr(p); n.lhs = parseexpr(p);
expecttok(p, tkind.TK_SEMI, "expected ';' after defer"); expecttok(p, tkind.TK_SEMI, "expected ';' after defer");
return n; return n;
}; };
if (p.curkind == tkind.TK_YIELD) { if (p.curkind == tkind.TK_YIELD) {
advance(p); advance(p);
let n: *node = newnode(p.a, nkind.N_YIELD, pf, pl, pc); let n: *node = newnode(nkind.N_YIELD, pf, pl, pc);
n.lhs = parseexpr(p); n.lhs = parseexpr(p);
expecttok(p, tkind.TK_SEMI, "expected ';' after yield"); expecttok(p, tkind.TK_SEMI, "expected ';' after yield");
return n; return n;
@@ -376,12 +375,12 @@ fn parsestmt(p: *parser) *node = {
if (p.curkind == tkind.TK_BREAK) { if (p.curkind == tkind.TK_BREAK) {
advance(p); advance(p);
expecttok(p, tkind.TK_SEMI, "expected ';' after break"); expecttok(p, tkind.TK_SEMI, "expected ';' after break");
return newnode(p.a, nkind.N_BREAK, pf, pl, pc); return newnode(nkind.N_BREAK, pf, pl, pc);
}; };
if (p.curkind == tkind.TK_CONTINUE) { if (p.curkind == tkind.TK_CONTINUE) {
advance(p); advance(p);
expecttok(p, tkind.TK_SEMI, "expected ';' after continue"); expecttok(p, tkind.TK_SEMI, "expected ';' after continue");
return newnode(p.a, nkind.N_CONTINUE, pf, pl, pc); return newnode(nkind.N_CONTINUE, pf, pl, pc);
}; };
// expression statement, or tuple-destructure multi-assign: // expression statement, or tuple-destructure multi-assign:
// a, b = expr; // a, b = expr;
@@ -391,7 +390,7 @@ fn parsestmt(p: *parser) *node = {
// consume — parseexpr would absorb it. // consume — parseexpr would absorb it.
let e: *node = parseexpr(p); let e: *node = parseexpr(p);
if (p.curkind == tkind.TK_COMMA) { if (p.curkind == tkind.TK_COMMA) {
let m: *node = newnode(p.a, nkind.N_MASSIGN, pf, pl, pc); let m: *node = newnode(nkind.N_MASSIGN, pf, pl, pc);
let head: *node = e; let head: *node = e;
let tail: *node = e; let tail: *node = e;
for (p.curkind == tkind.TK_COMMA) { for (p.curkind == tkind.TK_COMMA) {
@@ -406,7 +405,7 @@ fn parsestmt(p: *parser) *node = {
expecttok(p, tkind.TK_SEMI, "expected ';' after multi-assign"); expecttok(p, tkind.TK_SEMI, "expected ';' after multi-assign");
return m; return m;
}; };
let n: *node = newnode(p.a, nkind.N_EXPRSTMT, pf, pl, pc); let n: *node = newnode(nkind.N_EXPRSTMT, pf, pl, pc);
n.lhs = e; n.lhs = e;
expecttok(p, tkind.TK_SEMI, "expected ';' after expression statement"); expecttok(p, tkind.TK_SEMI, "expected ';' after expression statement");
return n; return n;

View File

@@ -6,10 +6,6 @@
package ww; package ww;
// Sibling imports (typ, ast) auto-resolve via task #22 dir-enum
// when callers `import ww;` or pull all three separately.
import mem;
// Symbol kinds — must stay numerically aligned with cmd/wcc/ww.h Skind. // Symbol kinds — must stay numerically aligned with cmd/wcc/ww.h Skind.
type skind = enum i32 { type skind = enum i32 {
SK_NONE = 0, SK_NONE = 0,
@@ -47,7 +43,6 @@ type scope = struct {
last: *sym, last: *sym,
buckets: **sym, // length = NBUCKETS buckets: **sym, // length = NBUCKETS
nbuckets: i32, nbuckets: i32,
a: *arena,
}; };
// FNV-1a 64 — same hash the C side uses, so bucket distribution is // FNV-1a 64 — same hash the C side uses, so bucket distribution is
@@ -64,9 +59,9 @@ fn hashstr(s: str) u64 = {
return h; return h;
}; };
export fn newscope(a: *arena, parent: *scope) *scope = { export fn newscope(parent: *scope) *scope = {
let buckets_sl: []*sym = alloc([], NBUCKETS: u64)!; let buckets_sl: []*sym = alloc([], NBUCKETS: u64)!;
let s: *scope = alloc(scope{parent=parent, first=nil, last=nil, buckets=buckets_sl.ptr, nbuckets=NBUCKETS, a=a})!; let s: *scope = alloc(scope{parent=parent, first=nil, last=nil, buckets=buckets_sl.ptr, nbuckets=NBUCKETS})!;
return s; return s;
}; };

View File

@@ -4,12 +4,11 @@
// the primitive types (tyvoid, tyi32, …); ww doesn't have writable // the primitive types (tyvoid, tyi32, …); ww doesn't have writable
// global storage yet, so we bundle the primitives into a `tctx` that // global storage yet, so we bundle the primitives into a `tctx` that
// the checker passes around explicitly. typesinit fills the tctx // the checker passes around explicitly. typesinit fills the tctx
// once per arena. // once per program.
package ww; package ww;
import os; import os;
import mem;
// ---- TypeKind --------------------------------------------------------- // ---- TypeKind ---------------------------------------------------------
// Numeric values must stay aligned with cmd/wcc/ww.h TypeKind so the // Numeric values must stay aligned with cmd/wcc/ww.h TypeKind so the
@@ -118,7 +117,6 @@ type tinfocacheent = struct {
// ---- tctx — the box of primitive types ------------------------------- // ---- tctx — the box of primitive types -------------------------------
type tctx = struct { type tctx = struct {
a: *arena,
tyvoid: *tinfo, tyvoid: *tinfo,
tybool: *tinfo, tybool: *tinfo,
tyrune: *tinfo, tyrune: *tinfo,
@@ -149,13 +147,13 @@ type tctx = struct {
// ---- constructors ----------------------------------------------------- // ---- constructors -----------------------------------------------------
export fn newtype(a: *arena, k: tykind) *tinfo = { export fn newtype(k: tykind) *tinfo = {
let t: *tinfo = alloc(tinfo{kind=k, size=0u64, align=0u64, sub=nil, alen=0u64, fields=nil, params=nil, ret=nil, variadic=0, nullable=0, name="", under=nil, slotsize=0u64})!; let t: *tinfo = alloc(tinfo{kind=k, size=0u64, align=0u64, sub=nil, alen=0u64, fields=nil, params=nil, ret=nil, variadic=0, nullable=0, name="", under=nil, slotsize=0u64})!;
return t; return t;
}; };
fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = { fn prim(k: tykind, nm: str, sz: u64, al: u64) *tinfo = {
let t: *tinfo = newtype(a, k); let t: *tinfo = newtype(k);
t.name = nm; t.name = nm;
t.size = sz; t.size = sz;
if (al > 0u64) { t.align = al; } else { t.align = sz; }; if (al > 0u64) { t.align = al; } else { t.align = sz; };
@@ -163,38 +161,37 @@ fn prim(a: *arena, k: tykind, nm: str, sz: u64, al: u64) *tinfo = {
return t; return t;
}; };
export fn typesinit(c: *tctx, a: *arena) void = { export fn typesinit(c: *tctx) void = {
c.a = a; c.tyvoid = prim(tykind.TY_VOID, "void", 0u64, 1u64);
c.tyvoid = prim(a, tykind.TY_VOID, "void", 0u64, 1u64); c.tybool = prim(tykind.TY_BOOL, "bool", 1u64, 1u64);
c.tybool = prim(a, tykind.TY_BOOL, "bool", 1u64, 1u64); c.tyrune = prim(tykind.TY_RUNE, "rune", 4u64, 4u64);
c.tyrune = prim(a, tykind.TY_RUNE, "rune", 4u64, 4u64); c.tyi8 = prim(tykind.TY_I8, "i8", 1u64, 1u64);
c.tyi8 = prim(a, tykind.TY_I8, "i8", 1u64, 1u64); c.tyi16 = prim(tykind.TY_I16, "i16", 2u64, 2u64);
c.tyi16 = prim(a, tykind.TY_I16, "i16", 2u64, 2u64); c.tyi32 = prim(tykind.TY_I32, "i32", 4u64, 4u64);
c.tyi32 = prim(a, tykind.TY_I32, "i32", 4u64, 4u64); c.tyi64 = prim(tykind.TY_I64, "i64", 8u64, 8u64);
c.tyi64 = prim(a, tykind.TY_I64, "i64", 8u64, 8u64); c.tyu8 = prim(tykind.TY_U8, "u8", 1u64, 1u64);
c.tyu8 = prim(a, tykind.TY_U8, "u8", 1u64, 1u64); c.tyu16 = prim(tykind.TY_U16, "u16", 2u64, 2u64);
c.tyu16 = prim(a, tykind.TY_U16, "u16", 2u64, 2u64); c.tyu32 = prim(tykind.TY_U32, "u32", 4u64, 4u64);
c.tyu32 = prim(a, tykind.TY_U32, "u32", 4u64, 4u64); c.tyu64 = prim(tykind.TY_U64, "u64", 8u64, 8u64);
c.tyu64 = prim(a, tykind.TY_U64, "u64", 8u64, 8u64); c.tyint = prim(tykind.TY_INT, "int", 8u64, 8u64);
c.tyint = prim(a, tykind.TY_INT, "int", 8u64, 8u64); c.tyuint = prim(tykind.TY_UINT, "uint", 8u64, 8u64);
c.tyuint = prim(a, tykind.TY_UINT, "uint", 8u64, 8u64); c.tyuintptr= prim(tykind.TY_UINTPTR, "uintptr", 8u64, 8u64);
c.tyuintptr= prim(a, tykind.TY_UINTPTR, "uintptr", 8u64, 8u64); c.tyf32 = prim(tykind.TY_F32, "f32", 4u64, 4u64);
c.tyf32 = prim(a, tykind.TY_F32, "f32", 4u64, 4u64); c.tyf64 = prim(tykind.TY_F64, "f64", 8u64, 8u64);
c.tyf64 = prim(a, tykind.TY_F64, "f64", 8u64, 8u64); c.tystr = prim(tykind.TY_STR, "str", 16u64, 8u64); // sizelint-ok: SSoT for tystr (#64)
c.tystr = prim(a, tykind.TY_STR, "str", 16u64, 8u64); // sizelint-ok: SSoT for tystr (#64) c.tyerr = prim(tykind.TY_ERR, "<err>", 0u64, 1u64);
c.tyerr = prim(a, tykind.TY_ERR, "<err>", 0u64, 1u64); c.tynever = prim(tykind.TY_NEVER, "never", 0u64, 1u64);
c.tynever = prim(a, tykind.TY_NEVER, "never", 0u64, 1u64);
c.tyuntypedint = prim(a, tykind.TY_UNTYPED_INT, "untyped_int", 0u64, 1u64); c.tyuntypedint = prim(tykind.TY_UNTYPED_INT, "untyped_int", 0u64, 1u64);
c.tyuntypedfloat = prim(a, tykind.TY_UNTYPED_FLOAT, "untyped_float", 0u64, 1u64); c.tyuntypedfloat = prim(tykind.TY_UNTYPED_FLOAT, "untyped_float", 0u64, 1u64);
c.tyuntypedstr = prim(a, tykind.TY_UNTYPED_STR, "untyped_str", 0u64, 1u64); c.tyuntypedstr = prim(tykind.TY_UNTYPED_STR, "untyped_str", 0u64, 1u64);
c.tyuntypedrune = prim(a, tykind.TY_UNTYPED_RUNE, "untyped_rune", 0u64, 1u64); c.tyuntypedrune = prim(tykind.TY_UNTYPED_RUNE, "untyped_rune", 0u64, 1u64);
c.tyuntypedbool = prim(a, tykind.TY_UNTYPED_BOOL, "untyped_bool", 0u64, 1u64); c.tyuntypedbool = prim(tykind.TY_UNTYPED_BOOL, "untyped_bool", 0u64, 1u64);
c.tyuntypednil = prim(a, tykind.TY_UNTYPED_NIL, "untyped_nil", 0u64, 1u64); c.tyuntypednil = prim(tykind.TY_UNTYPED_NIL, "untyped_nil", 0u64, 1u64);
}; };
export fn typeptr(a: *arena, sub: *tinfo) *tinfo = { export fn typeptr(sub: *tinfo) *tinfo = {
let t: *tinfo = newtype(a, tykind.TY_PTR); let t: *tinfo = newtype(tykind.TY_PTR);
t.sub = sub; t.sub = sub;
t.size = 8u64; t.size = 8u64;
t.align = 8u64; t.align = 8u64;
@@ -202,8 +199,8 @@ export fn typeptr(a: *arena, sub: *tinfo) *tinfo = {
return t; return t;
}; };
export fn typeslice(a: *arena, sub: *tinfo) *tinfo = { export fn typeslice(sub: *tinfo) *tinfo = {
let t: *tinfo = newtype(a, tykind.TY_SLICE); let t: *tinfo = newtype(tykind.TY_SLICE);
t.sub = sub; t.sub = sub;
t.size = 24u64; // sizelint-ok: SSoT for slice header (#64) t.size = 24u64; // sizelint-ok: SSoT for slice header (#64)
t.align = 8u64; t.align = 8u64;
@@ -211,8 +208,8 @@ export fn typeslice(a: *arena, sub: *tinfo) *tinfo = {
return t; return t;
}; };
export fn typearray(a: *arena, sub: *tinfo, n: u64) *tinfo = { export fn typearray(sub: *tinfo, n: u64) *tinfo = {
let t: *tinfo = newtype(a, tykind.TY_ARRAY); let t: *tinfo = newtype(tykind.TY_ARRAY);
t.sub = sub; t.sub = sub;
t.alen = n; t.alen = n;
if (sub != nil) { if (sub != nil) {
@@ -229,8 +226,8 @@ export fn typearray(a: *arena, sub: *tinfo, n: u64) *tinfo = {
return t; return t;
}; };
export fn typechan(a: *arena, sub: *tinfo) *tinfo = { export fn typechan(sub: *tinfo) *tinfo = {
let t: *tinfo = newtype(a, tykind.TY_CHAN); let t: *tinfo = newtype(tykind.TY_CHAN);
t.sub = sub; t.sub = sub;
t.size = 8u64; t.size = 8u64;
t.align = 8u64; t.align = 8u64;
@@ -238,8 +235,8 @@ export fn typechan(a: *arena, sub: *tinfo) *tinfo = {
return t; return t;
}; };
export fn typenamed(a: *arena, name: str, under: *tinfo) *tinfo = { export fn typenamed(name: str, under: *tinfo) *tinfo = {
let t: *tinfo = newtype(a, tykind.TY_NAMED); let t: *tinfo = newtype(tykind.TY_NAMED);
t.name = name; t.name = name;
t.under = under; t.under = under;
if (under != nil) { if (under != nil) {

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,6 @@ package main;
import os; import os;
import rt; import rt;
import mem;
import strings; import strings;
import tok; import tok;
import lex; import lex;
@@ -135,7 +134,6 @@ export fn main(argc: i32, argv: **u8) i32 = {
os.close(ofd); os.close(ofd);
}; };
let ar: *arena = newarena();
let nlen: u64 = cstrlen(src); let nlen: u64 = cstrlen(src);
let view: str; let view: str;
view.ptr = src; view.ptr = src;
@@ -143,10 +141,10 @@ export fn main(argc: i32, argv: **u8) i32 = {
let fname: str = strings.dup(view); let fname: str = strings.dup(view);
let l: lex; let l: lex;
lexinit(&l, ar, fname, buf, blen); lexinit(&l, fname, buf, blen);
let ps: parser; let ps: parser;
parserinit(&ps, ar, &l); parserinit(&ps, &l);
let f: *node = parsefile(&ps); let f: *node = parsefile(&ps);
// Gate cgen on parse-stage errors. Mirrors cmd/w6c/main.c's // Gate cgen on parse-stage errors. Mirrors cmd/w6c/main.c's
// `if (l.errs || p.errs) return 1;` — broken AST otherwise reaches // `if (l.errs || p.errs) return 1;` — broken AST otherwise reaches
@@ -160,14 +158,14 @@ export fn main(argc: i32, argv: **u8) i32 = {
// enum↔int reinterpret, #53 N_BLOCK scoping, #55 nominal-first variant // enum↔int reinterpret, #53 N_BLOCK scoping, #55 nominal-first variant
// compare, #56 bare-leaf same-module preference. // compare, #56 bare-leaf same-module preference.
let tc: tctx; let tc: tctx;
typesinit(&tc, ar); typesinit(&tc);
let ck: checker; let ck: checker;
checkinit(&ck, ar, &tc); checkinit(&ck, &tc);
checkfile(&ck, f); checkfile(&ck, f);
if (ck.errs > 0) { return 1; }; if (ck.errs > 0) { return 1; };
let cg: cgen; let cg: cgen;
cgeninit(&cg, ar); cgeninit(&cg);
cgfile(&cg, f); cgfile(&cg, f);
return 0; return 0;
}; };

View File

@@ -25,7 +25,6 @@
package wcc; package wcc;
import os; import os;
import mem;
import ast; import ast;
import tok; import tok;
import typ; import typ;
@@ -68,9 +67,9 @@ fn collectaliases(c: *cgen, file: *node) void = {
// same-module / any-match passes in aliaslookup then let a local // same-module / any-match passes in aliaslookup then let a local
// `type nomem = !void;` shadow this fallback within its module. // `type nomem = !void;` shadow this fallback within its module.
let empty: str; let empty: str;
let tnvoid: *node = newnode(c.a, nkind.N_TNAME, empty, 0, 0); let tnvoid: *node = newnode(nkind.N_TNAME, empty, 0, 0);
tnvoid.str = "void"; tnvoid.str = "void";
let bang: *node = newnode(c.a, nkind.N_TBANG, empty, 0, 0); let bang: *node = newnode(nkind.N_TBANG, empty, 0, 0);
bang.lhs = tnvoid; bang.lhs = tnvoid;
let nomemal: *aliasent = alloc(aliasent{aname="nomem", amod=empty, target=bang, aanext=nil})!; let nomemal: *aliasent = alloc(aliasent{aname="nomem", amod=empty, target=bang, aanext=nil})!;
c.aliases = nomemal; c.aliases = nomemal;
@@ -435,7 +434,6 @@ def LOOP_MAX: i32 = 16;
def DEFER_MAX: i32 = 16; def DEFER_MAX: i32 = 16;
type cgen = struct { type cgen = struct {
a: *arena,
locals: *local, locals: *local,
// atlocals — persistent registry of `@`-prefix scratch slots // atlocals — persistent registry of `@`-prefix scratch slots
// for the current fn. cgblock save/restores c.locals to scope // for the current fn. cgblock save/restores c.locals to scope
@@ -522,8 +520,7 @@ type letvar = struct {
lvnext: *letvar, lvnext: *letvar,
}; };
fn cgeninit(c: *cgen, a: *arena) void = { fn cgeninit(c: *cgen) void = {
c.a = a;
c.locals = nil; c.locals = nil;
c.atlocals = nil; c.atlocals = nil;
c.frame = 0; c.frame = 0;

View File

@@ -13,7 +13,6 @@
package wcc; package wcc;
import os; import os;
import mem;
import ast; import ast;
import tok; import tok;
import typ; import typ;
@@ -339,7 +338,7 @@ fn cgfnparams(c: *cgen, params: *node) void = {
}; };
fn cgfn(c: *cgen, fn_: *node) void = { fn cgfn(c: *cgen, fn_: *node) void = {
cgeninit(c, c.a); cgeninit(c);
c.fnname = fn_.str; c.fnname = fn_.str;
c.curmod = fn_.nmod; c.curmod = fn_.nmod;
c.fnret = fn_.lhs; c.fnret = fn_.lhs;

View File

@@ -15,7 +15,6 @@
package wcc; package wcc;
import os; import os;
import mem;
import ast; import ast;
import tok; import tok;
import typ; import typ;
@@ -3172,7 +3171,7 @@ fn cgcall(c: *cgen, n: *node) void = {
emitline("\tMOVQ\tAX, "); emitline("\tMOVQ\tAX, ");
emitoff((soff + 16): i64); emitoff((soff + 16): i64);
emitline("(BP)\n"); emitline("(BP)\n");
let sn: *node = newnode(c.a, nkind.N_IDENT, let sn: *node = newnode(nkind.N_IDENT,
"", 0, 0); "", 0, 0);
sn.str = sname; sn.str = sname;
if (prevarg == nil) { n.list = sn; } if (prevarg == nil) { n.list = sn; }

View File

@@ -11,7 +11,6 @@
package wcc; package wcc;
import os; import os;
import mem;
import ast; import ast;
import tok; import tok;
import typ; import typ;

View File

@@ -15,7 +15,6 @@
package wcc; package wcc;
import os; import os;
import mem;
import ast; import ast;
import tok; import tok;
import typ; import typ;
@@ -30,7 +29,7 @@ import strconv;
// (caller side) both advertise their effective type as []ELEM — // (caller side) both advertise their effective type as []ELEM —
// every isslicetype / nodeisslice check then succeeds naturally. // every isslicetype / nodeisslice check then succeeds naturally.
fn slicewrap(c: *cgen, elem: *node) *node = { fn slicewrap(c: *cgen, elem: *node) *node = {
let s: *node = newnode(c.a, nkind.N_TSLICE, "", 0, 0); let s: *node = newnode(nkind.N_TSLICE, "", 0, 0);
s.lhs = elem; s.lhs = elem;
return s; return s;
}; };

View File

@@ -20,11 +20,9 @@
package wcc; package wcc;
import os; import os;
import mem;
import tok; import tok;
type checker = struct { type checker = struct {
a: *arena,
tc: *tctx, tc: *tctx,
top: *scope, top: *scope,
cur: *scope, cur: *scope,
@@ -72,11 +70,11 @@ fn seedprimitives(c: *checker) void = {
// separate alias chain — see collectaliases in cgen.ww for the // separate alias chain — see collectaliases in cgen.ww for the
// companion seed. // companion seed.
let empty: str; let empty: str;
let tnvoid: *node = newnode(c.a, nkind.N_TNAME, empty, 0, 0); let tnvoid: *node = newnode(nkind.N_TNAME, empty, 0, 0);
tnvoid.str = "void"; tnvoid.str = "void";
let bang: *node = newnode(c.a, nkind.N_TBANG, empty, 0, 0); let bang: *node = newnode(nkind.N_TBANG, empty, 0, 0);
bang.lhs = tnvoid; bang.lhs = tnvoid;
let nomemdecl: *node = newnode(c.a, nkind.N_TYPEDECL, empty, 0, 0); let nomemdecl: *node = newnode(nkind.N_TYPEDECL, empty, 0, 0);
nomemdecl.str = "nomem"; nomemdecl.str = "nomem";
nomemdecl.lhs = bang; nomemdecl.lhs = bang;
scopedefine(c.top, "nomem", skind.SK_TYPE, nil, nomemdecl); scopedefine(c.top, "nomem", skind.SK_TYPE, nil, nomemdecl);
@@ -350,7 +348,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
if (k == nkind.N_MCASE) { if (k == nkind.N_MCASE) {
if (n.lhs != nil) { resolvewalk(c, n.lhs); }; if (n.lhs != nil) { resolvewalk(c, n.lhs); };
let outer: *scope = c.cur; let outer: *scope = c.cur;
c.cur = newscope(c.a, outer); c.cur = newscope(outer);
let nm: str = n.str; let nm: str = n.str;
if (nm.len > 0) { if (nm.len > 0) {
checkmoduleshadow(c, nm, "binding"); checkmoduleshadow(c, nm, "binding");
@@ -372,7 +370,7 @@ fn resolvewalk(c: *checker, n: *node) void = {
// Mirrors cstage cstmt N_BLOCK at cmd/wcc/check.c:1559-1566. // Mirrors cstage cstmt N_BLOCK at cmd/wcc/check.c:1559-1566.
if (k == nkind.N_BLOCK) { if (k == nkind.N_BLOCK) {
let outer: *scope = c.cur; let outer: *scope = c.cur;
c.cur = newscope(c.a, outer); c.cur = newscope(outer);
let m: *node = n.list; let m: *node = n.list;
for (m != nil) { for (m != nil) {
resolvewalk(c, m); resolvewalk(c, m);
@@ -651,7 +649,7 @@ fn scruttype(c: *checker, e: *node) *node = {
// exprtype to return primitive type nodes for literal // exprtype to return primitive type nodes for literal
// expressions. The arena keeps them around as long as the checker. // expressions. The arena keeps them around as long as the checker.
fn mktname(c: *checker, nm: str) *node = { fn mktname(c: *checker, nm: str) *node = {
let n: *node = newnode(c.a, nkind.N_TNAME, "", 0, 0); let n: *node = newnode(nkind.N_TNAME, "", 0, 0);
n.str = nm; n.str = nm;
return n; return n;
}; };
@@ -838,7 +836,7 @@ fn astoffset(c: *checker, dot: *node) i64 = {
// wwstage cgen only reads `uval` for N_INTLIT codegen so `str` is // wwstage cgen only reads `uval` for N_INTLIT codegen so `str` is
// just for the AST printer, but set it for parity with the parser's // just for the AST printer, but set it for parity with the parser's
// own literal-emit shape. // own literal-emit shape.
fn arenau64tos(a: *arena, v: u64) str = { fn arenau64tos(v: u64) str = {
let buf: []u8 = alloc([], 24u64)!; let buf: []u8 = alloc([], 24u64)!;
let i: i32 = 23; let i: i32 = 23;
buf[i] = 0u8; buf[i] = 0u8;
@@ -862,7 +860,7 @@ fn arenau64tos(a: *arena, v: u64) str = {
fn foldtointlit(c: *checker, n: *node, v: i64) void = { fn foldtointlit(c: *checker, n: *node, v: i64) void = {
n.kind = nkind.N_INTLIT; n.kind = nkind.N_INTLIT;
n.uval = v: u64; n.uval = v: u64;
n.str = arenau64tos(c.a, v: u64); n.str = arenau64tos(v: u64);
n.lhs = nil; n.lhs = nil;
n.list = nil; n.list = nil;
let empty: str; let empty: str;
@@ -1014,11 +1012,11 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
// site that needs iserror discrimination. // site that needs iserror discrimination.
r = tinfofornode(c, n.lhs); r = tinfofornode(c, n.lhs);
} else { if (k == nkind.N_TPTR) { } else { if (k == nkind.N_TPTR) {
r = typeptr(c.a, tinfofornode(c, n.lhs)); r = typeptr(tinfofornode(c, n.lhs));
} else { if (k == nkind.N_TSLICE) { } else { if (k == nkind.N_TSLICE) {
r = typeslice(c.a, tinfofornode(c, n.lhs)); r = typeslice(tinfofornode(c, n.lhs));
} else { if (k == nkind.N_TCHAN) { } else { if (k == nkind.N_TCHAN) {
r = typechan(c.a, tinfofornode(c, n.lhs)); r = typechan(tinfofornode(c, n.lhs));
} else { if (k == nkind.N_TARRAY) { } else { if (k == nkind.N_TARRAY) {
// Cstage cmd/wcc/check.c:314-326: length must be an integer // Cstage cmd/wcc/check.c:314-326: length must be an integer
// literal (`[_]T` keeps alen=0 as the inferred-length sentinel // literal (`[_]T` keeps alen=0 as the inferred-length sentinel
@@ -1034,14 +1032,14 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
if (n.rhs.kind == nkind.N_INTLIT) { elen = n.rhs.uval; }; if (n.rhs.kind == nkind.N_INTLIT) { elen = n.rhs.uval; };
}; };
let sub: *tinfo = tinfofornode(c, n.lhs); let sub: *tinfo = tinfofornode(c, n.lhs);
r = typearray(c.a, sub, elen); r = typearray(sub, elen);
} else { if (k == nkind.N_TFN) { } else { if (k == nkind.N_TFN) {
// Cstage cmd/wcc/check.c:437-466: function types are 8B / 8B // Cstage cmd/wcc/check.c:437-466: function types are 8B / 8B
// (call-target pointer shape). Pre-bind before recursing into // (call-target pointer shape). Pre-bind before recursing into
// the return type so a recursive `type F = fn() F` self-ref // the return type so a recursive `type F = fn() F` self-ref
// doesn't spin (cycle-break mirror of the TSTRUCT/TTAGGED // doesn't spin (cycle-break mirror of the TSTRUCT/TTAGGED
// pattern below). // pattern below).
r = newtype(c.a, tykind.TY_FN); r = newtype(tykind.TY_FN);
r.size = 8u64; r.size = 8u64;
r.align = 8u64; r.align = 8u64;
r.slotsize = 8u64; r.slotsize = 8u64;
@@ -1052,7 +1050,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
// (default i32 = 4B/4B). Cgen's slotsize-TENUM fallback pads // (default i32 = 4B/4B). Cgen's slotsize-TENUM fallback pads
// to 8B per its stack-slot contract; tinfo.size carries the // to 8B per its stack-slot contract; tinfo.size carries the
// raw storage width so size(EnumT) folds to the correct value. // raw storage width so size(EnumT) folds to the correct value.
r = newtype(c.a, tykind.TY_ENUM); r = newtype(tykind.TY_ENUM);
let storage: *tinfo = nil; let storage: *tinfo = nil;
if (n.lhs != nil) { storage = tinfofornode(c, n.lhs); }; if (n.lhs != nil) { storage = tinfofornode(c, n.lhs); };
if (storage == nil) { storage = c.tc.tyi32; }; if (storage == nil) { storage = c.tc.tyi32; };
@@ -1071,7 +1069,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
// slotsize TTUPLE — narrow scalars pad to 8 (cgen spills each // slotsize TTUPLE — narrow scalars pad to 8 (cgen spills each
// tuple element into its own register / stack-slot eightbyte), // tuple element into its own register / stack-slot eightbyte),
// composites contribute their own ti.slotsize. // composites contribute their own ti.slotsize.
r = newtype(c.a, tykind.TY_TUPLE); r = newtype(tykind.TY_TUPLE);
tinfocachebind(c.tc, n, r); tinfocachebind(c.tc, n, r);
let total: u64 = 0u64; let total: u64 = 0u64;
let slottotal: u64 = 0u64; let slottotal: u64 = 0u64;
@@ -1109,7 +1107,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
// struct; size-derived alignment; final round to 8). That // struct; size-derived alignment; final round to 8). That
// slot total lands in ti.slotsize so the cgen fast-path can // slot total lands in ti.slotsize so the cgen fast-path can
// graduate TY_STRUCT off the AST walker. // graduate TY_STRUCT off the AST walker.
r = newtype(c.a, tykind.TY_STRUCT); r = newtype(tykind.TY_STRUCT);
tinfocachebind(c.tc, n, r); tinfocachebind(c.tc, n, r);
let off: u64 = 0u64; let off: u64 = 0u64;
let maxalign: u64 = 1u64; let maxalign: u64 = 1u64;
@@ -1151,7 +1149,7 @@ fn tinfofornode(c: *checker, n: *node) *tinfo = {
// Cstage cmd/wcc/check.c:347-435: 8B tag + max(variant) // Cstage cmd/wcc/check.c:347-435: 8B tag + max(variant)
// rounded up to 8. Pre-bind for cycle protection (recursive // rounded up to 8. Pre-bind for cycle protection (recursive
// sum-type shapes through NAMED variants). // sum-type shapes through NAMED variants).
r = newtype(c.a, tykind.TY_TAGGED); r = newtype(tykind.TY_TAGGED);
tinfocachebind(c.tc, n, r); tinfocachebind(c.tc, n, r);
// #61 A.3 nullable fold: `(*T | void)` collapses to a single // #61 A.3 nullable fold: `(*T | void)` collapses to a single
// 8B pointer slot, null is the void variant. Mirrors // 8B pointer slot, null is the void variant. Mirrors
@@ -1310,11 +1308,11 @@ fn exprtype(c: *checker, e: *node) *node = {
if (e.list.list == nil) { if (e.list.list == nil) {
if (e.list.next != nil) { if (e.list.next != nil) {
if (e.list.next.next == nil) { if (e.list.next.next == nil) {
let sl: *node = newnode(c.a, nkind.N_TSLICE, "", 0, 0); let sl: *node = newnode(nkind.N_TSLICE, "", 0, 0);
sl.lhs = mktname(c, "u8"); sl.lhs = mktname(c, "u8");
let nome: *node = mktname(c, "nomem"); let nome: *node = mktname(c, "nomem");
sl.next = nome; sl.next = nome;
let tt: *node = newnode(c.a, nkind.N_TTAGGED, "", 0, 0); let tt: *node = newnode(nkind.N_TTAGGED, "", 0, 0);
tt.list = sl; tt.list = sl;
return tt; return tt;
}; };
@@ -1324,11 +1322,11 @@ fn exprtype(c: *checker, e: *node) *node = {
// Value form: `alloc(value)`. // Value form: `alloc(value)`.
if (e.list.next == nil) { if (e.list.next == nil) {
let argt: *node = exprtype(c, e.list); let argt: *node = exprtype(c, e.list);
let ptr: *node = newnode(c.a, nkind.N_TPTR, "", 0, 0); let ptr: *node = newnode(nkind.N_TPTR, "", 0, 0);
ptr.lhs = argt; ptr.lhs = argt;
let nome: *node = mktname(c, "nomem"); let nome: *node = mktname(c, "nomem");
ptr.next = nome; ptr.next = nome;
let tt: *node = newnode(c.a, nkind.N_TTAGGED, "", 0, 0); let tt: *node = newnode(nkind.N_TTAGGED, "", 0, 0);
tt.list = ptr; tt.list = ptr;
return tt; return tt;
}; };
@@ -1845,14 +1843,14 @@ fn checkletassign(c: *checker, n: *node) void = {
}; };
}; };
if (!shadowed) { if (!shadowed) {
let sl: *node = newnode(c.a, nkind.N_TSLICE, "", 0, 0); let sl: *node = newnode(nkind.N_TSLICE, "", 0, 0);
sl.lhs = n.lhs.lhs; sl.lhs = n.lhs.lhs;
if (wrapped) { if (wrapped) {
src = sl; src = sl;
} else { } else {
let nome: *node = mktname(c, "nomem"); let nome: *node = mktname(c, "nomem");
sl.next = nome; sl.next = nome;
let tt: *node = newnode(c.a, nkind.N_TTAGGED, "", 0, 0); let tt: *node = newnode(nkind.N_TTAGGED, "", 0, 0);
tt.list = sl; tt.list = sl;
src = tt; src = tt;
}; };
@@ -2043,7 +2041,7 @@ fn installparams(c: *checker, params: *node) void = {
// per-statement scopes. // per-statement scopes.
fn resolvefnbody(c: *checker, fnnode: *node) void = { fn resolvefnbody(c: *checker, fnnode: *node) void = {
let outer: *scope = c.cur; let outer: *scope = c.cur;
c.cur = newscope(c.a, c.cur); c.cur = newscope(c.cur);
installparams(c, fnnode.list); installparams(c, fnnode.list);
// #61 audit §1.8 — A.2: walk each param's declared type-expr so // #61 audit §1.8 — A.2: walk each param's declared type-expr so
// tinfofornode stamps n.type_ on it. installparams binds the name // tinfofornode stamps n.type_ on it. installparams binds the name
@@ -2065,10 +2063,9 @@ fn resolvefnbody(c: *checker, fnnode: *node) void = {
c.cur = outer; c.cur = outer;
}; };
export fn checkinit(c: *checker, a: *arena, tc: *tctx) void = { export fn checkinit(c: *checker, tc: *tctx) void = {
c.a = a;
c.tc = tc; c.tc = tc;
c.top = newscope(a, nil); c.top = newscope(nil);
c.cur = c.top; c.cur = c.top;
c.nresolved = 0; c.nresolved = 0;
c.nunresolved = 0; c.nunresolved = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,6 @@
package main; package main;
import os; import os;
import mem;
import tok; import tok;
import lex; import lex;
import ast; import ast;
@@ -99,7 +98,6 @@ export fn main(argc: i32, argv: **u8) i32 = {
}; };
}; };
let a: *arena = newarena();
let buf: []u8 = alloc([], sz: u64)!; let buf: []u8 = alloc([], sz: u64)!;
buf.len = sz: i32; buf.len = sz: i32;
let rr: (i64 | os.oserror) = os.readall(fd, buf.ptr, sz: u64); let rr: (i64 | os.oserror) = os.readall(fd, buf.ptr, sz: u64);
@@ -118,7 +116,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
}; };
let l: lex; let l: lex;
lexinit(&l, a, argstr(path), buf.ptr, sz: u64); lexinit(&l, argstr(path), buf.ptr, sz: u64);
if (mode == 116) { // '-t' if (mode == 116) { // '-t'
for (true) { for (true) {
@@ -130,17 +128,17 @@ export fn main(argc: i32, argv: **u8) i32 = {
}; };
} else { if (mode == 97) { // '-a' } else { if (mode == 97) { // '-a'
let ps: parser; let ps: parser;
parserinit(&ps, a, &l); parserinit(&ps, &l);
let f: *node = parsefile(&ps); let f: *node = parsefile(&ps);
astprint(1i32, f); astprint(1i32, f);
} else { if (mode == 114) { // '-r' — name resolve report } else { if (mode == 114) { // '-r' — name resolve report
let ps: parser; let ps: parser;
parserinit(&ps, a, &l); parserinit(&ps, &l);
let f: *node = parsefile(&ps); let f: *node = parsefile(&ps);
let tc: tctx; let tc: tctx;
typesinit(&tc, a); typesinit(&tc);
let ck: checker; let ck: checker;
checkinit(&ck, a, &tc); checkinit(&ck, &tc);
// Quiet by default; flip to 1 when debugging missing names. // Quiet by default; flip to 1 when debugging missing names.
ck.verbose = 0; ck.verbose = 0;
checkfile(&ck, f); checkfile(&ck, f);
@@ -158,7 +156,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
if (ck.nunresolved > 0) { return 1; }; if (ck.nunresolved > 0) { return 1; };
} else { if (mode == 99) { // '-c' — codegen / emit asm } else { if (mode == 99) { // '-c' — codegen / emit asm
let ps: parser; let ps: parser;
parserinit(&ps, a, &l); parserinit(&ps, &l);
let f: *node = parsefile(&ps); let f: *node = parsefile(&ps);
// #50: mirror w6c — run check before cgen so AST mutations // #50: mirror w6c — run check before cgen so AST mutations
// from #42 (size/align/offset fold) and audit §1.8 (node.type_ // from #42 (size/align/offset fold) and audit §1.8 (node.type_
@@ -166,13 +164,13 @@ export fn main(argc: i32, argv: **u8) i32 = {
// (the byte-identity probe for 994) would diverge from w6c_ww // (the byte-identity probe for 994) would diverge from w6c_ww
// on any program that uses the size/align/offset typed builtins. // on any program that uses the size/align/offset typed builtins.
let tc: tctx; let tc: tctx;
typesinit(&tc, a); typesinit(&tc);
let ck: checker; let ck: checker;
checkinit(&ck, a, &tc); checkinit(&ck, &tc);
checkfile(&ck, f); checkfile(&ck, f);
if (ck.errs > 0) { return 1; }; if (ck.errs > 0) { return 1; };
let cg: cgen; let cg: cgen;
cgeninit(&cg, a); cgeninit(&cg);
cgfile(&cg, f); cgfile(&cg, f);
};};};}; };};};};

View File

@@ -1,20 +1,16 @@
// selfhost/test/sym_link.ww — link-and-run probe for the ww-cgen // selfhost/test/sym_link.ww — link-and-run probe for the ww-cgen
// against the sym/typ/ast/mem dep stack. Exercises arena (mem), // against the sym/typ/ast dep stack. Exercises hashtable scope
// hashtable scope (sym), and pulls in typ/ast as type carriers. // (sym), and pulls in typ/ast as type carriers.
// Returns 42 on success; smaller values name the probe that broke. // Returns 42 on success; smaller values name the probe that broke.
package test; package test;
import mem;
import typ; import typ;
import ast; import ast;
import sym; import sym;
export fn main() i32 = { export fn main() i32 = {
let a: *arena = newarena(); let s: *scope = newscope(nil);
if (a == nil) { return 1; };
let s: *scope = newscope(a, nil);
if (s == nil) { return 2; }; if (s == nil) { return 2; };
let n1: str = "foo"; let n1: str = "foo";
@@ -42,6 +38,5 @@ export fn main() i32 = {
let l3: *sym = scopelookup(s, n3); let l3: *sym = scopelookup(s, n3);
if (l3 != nil) { return 10; }; if (l3 != nil) { return 10; };
freearena(a);
return 42; return 42;
}; };