selfhost: graduate N_* defs to nkind enum
This commit is contained in:
@@ -5,17 +5,17 @@
|
||||
// then by assembling + linking + running the result.
|
||||
//
|
||||
// Current coverage:
|
||||
// - decls: N_FILE, N_FNDECL (params, frame for locals, prologue
|
||||
// - decls: nkind.N_FILE, nkind.N_FNDECL (params, frame for locals, prologue
|
||||
// + dual-epilogue suppression; FFI body-less fn skipped)
|
||||
// - stmts: N_BLOCK, N_RETURN, N_EXPRSTMT, N_LET (no init),
|
||||
// N_LET (int-literal / ident / call / N_BIN init),
|
||||
// N_IF (with optional else), N_FOR (cond-only and full
|
||||
// init/cond/post), N_BREAK, N_CONTINUE
|
||||
// - exprs: N_INTLIT, N_IDENT (local/param), N_BIN with full op
|
||||
// - stmts: nkind.N_BLOCK, nkind.N_RETURN, nkind.N_EXPRSTMT, nkind.N_LET (no init),
|
||||
// nkind.N_LET (int-literal / ident / call / nkind.N_BIN init),
|
||||
// nkind.N_IF (with optional else), nkind.N_FOR (cond-only and full
|
||||
// init/cond/post), nkind.N_BREAK, nkind.N_CONTINUE
|
||||
// - exprs: nkind.N_INTLIT, nkind.N_IDENT (local/param), nkind.N_BIN with full op
|
||||
// coverage (+/-/*/// %, &/|/^, <</>>, comparisons with
|
||||
// signed-vs-unsigned dispatch, &&/||), N_UN (- ! ~ & *),
|
||||
// N_CALL (recursive R-to-L push, pop into argregs L-to-R),
|
||||
// N_ASSIGN to local idents (plain and compound +=/-=)
|
||||
// signed-vs-unsigned dispatch, &&/||), nkind.N_UN (- ! ~ & *),
|
||||
// nkind.N_CALL (recursive R-to-L push, pop into argregs L-to-R),
|
||||
// nkind.N_ASSIGN to local idents (plain and compound +=/-=)
|
||||
//
|
||||
// Type info is shallow — frame slots are 8 bytes per local, all loads
|
||||
// /stores are MOVQ. Programs that mix i8/i32/i64 locals work but spill
|
||||
@@ -41,7 +41,7 @@ use cgendecl;
|
||||
//
|
||||
// `type error = str;` makes `error` a struct-shape alias. We track
|
||||
// alias→target so isstrtype / isslicetype / structlookup can
|
||||
// resolve through the chain. Only direct N_TNAME aliases are mapped;
|
||||
// resolve through the chain. Only direct nkind.N_TNAME aliases are mapped;
|
||||
// `type p = struct {...}` is handled by collectstructs.
|
||||
|
||||
type aliasent = struct {
|
||||
@@ -54,10 +54,10 @@ fn collectaliases(c: *cgen, file: *node) void = {
|
||||
c.aliases = nil;
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == N_TYPEDECL) {
|
||||
if (d.kind == nkind.N_TYPEDECL) {
|
||||
let body: *node = d.lhs;
|
||||
if (body != nil) {
|
||||
if (body.kind != N_TSTRUCT) {
|
||||
if (body.kind != nkind.N_TSTRUCT) {
|
||||
let a: *aliasent = amalloc(c.a, 32u64): *aliasent;
|
||||
a.aname = d.str;
|
||||
a.target = body;
|
||||
@@ -90,11 +90,11 @@ fn aliaslookup(c: *cgen, name: str) *node = {
|
||||
fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
|
||||
if (e == nil) { return false; };
|
||||
let k: i32 = e.kind;
|
||||
if (k == N_INTLIT) { *out = e.uval; return true; };
|
||||
if (k == N_RUNELIT) { *out = e.uval; return true; };
|
||||
if (k == N_TRUE) { *out = 1u64; return true; };
|
||||
if (k == N_FALSE) { *out = 0u64; return true; };
|
||||
if (k == N_IDENT) {
|
||||
if (k == nkind.N_INTLIT) { *out = e.uval; return true; };
|
||||
if (k == nkind.N_RUNELIT) { *out = e.uval; return true; };
|
||||
if (k == nkind.N_TRUE) { *out = 1u64; return true; };
|
||||
if (k == nkind.N_FALSE) { *out = 0u64; return true; };
|
||||
if (k == nkind.N_IDENT) {
|
||||
let m: *enummember = prev;
|
||||
for (m != nil) {
|
||||
if (streq(m.mname, e.str)) {
|
||||
@@ -105,7 +105,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
|
||||
};
|
||||
return false;
|
||||
};
|
||||
if (k == N_BIN) {
|
||||
if (k == nkind.N_BIN) {
|
||||
let a: u64;
|
||||
let b: u64;
|
||||
if (!enumevalmember(prev, e.lhs, &a)) { return false; };
|
||||
@@ -129,7 +129,7 @@ fn enumevalmember(prev: *enummember, e: *node, out: *u64) bool = {
|
||||
if (op == tkind.TK_RSHIFT) { *out = a >> b; return true; };
|
||||
return false;
|
||||
};
|
||||
if (k == N_UN) {
|
||||
if (k == nkind.N_UN) {
|
||||
let v: u64;
|
||||
if (!enumevalmember(prev, e.lhs, &v)) { return false; };
|
||||
let op: i32 = e.op;
|
||||
@@ -145,10 +145,10 @@ fn collectenums(c: *cgen, file: *node) void = {
|
||||
c.enums = nil;
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == N_TYPEDECL) {
|
||||
if (d.kind == nkind.N_TYPEDECL) {
|
||||
let body: *node = d.lhs;
|
||||
if (body != nil) {
|
||||
if (body.kind == N_TENUM) {
|
||||
if (body.kind == nkind.N_TENUM) {
|
||||
let et: *enumtype = amalloc(c.a, 48u64): *enumtype;
|
||||
et.ename = d.str;
|
||||
et.storage = body.lhs;
|
||||
@@ -226,7 +226,7 @@ fn resolvetype(c: *cgen, t: *node) *node = {
|
||||
let depth: i32 = 0;
|
||||
for (depth < 16) {
|
||||
if (cur == nil) { return nil; };
|
||||
if (cur.kind != N_TNAME) { return cur; };
|
||||
if (cur.kind != nkind.N_TNAME) { return cur; };
|
||||
let nm: str = cur.str;
|
||||
let next: *node = aliaslookup(c, nm);
|
||||
if (next == nil) { return cur; };
|
||||
@@ -239,8 +239,8 @@ fn resolvetype(c: *cgen, t: *node) *node = {
|
||||
// ---- struct registry ------------------------------------------------
|
||||
//
|
||||
// Per-file map from struct name → list of fields with computed offsets
|
||||
// and sizes. Built when cgfile walks N_TYPEDECL with N_TSTRUCT lhs.
|
||||
// N_DOT and N_ASSIGN consult this to resolve `s.field` for struct or
|
||||
// and sizes. Built when cgfile walks nkind.N_TYPEDECL with nkind.N_TSTRUCT lhs.
|
||||
// nkind.N_DOT and nkind.N_ASSIGN consult this to resolve `s.field` for struct or
|
||||
// *struct bases.
|
||||
|
||||
type fieldinfo = struct {
|
||||
@@ -263,12 +263,12 @@ type structinfo = struct {
|
||||
type local = struct {
|
||||
name: str,
|
||||
off: i32,
|
||||
tnode: *node, // declared type expr (N_TNAME / N_TPTR / ...) or nil
|
||||
tnode: *node, // declared type expr (nkind.N_TNAME / nkind.N_TPTR / ...) or nil
|
||||
lnext: *local,
|
||||
};
|
||||
|
||||
// strlit — interned string literal record. Emitted as a DATA directive
|
||||
// after all functions; cgexpr N_STRLIT loads (LEAQ ptr, MOVQ len).
|
||||
// after all functions; cgexpr nkind.N_STRLIT loads (LEAQ ptr, MOVQ len).
|
||||
type strlit = struct {
|
||||
label: str, // "_S_<seq>"
|
||||
bytes: str,
|
||||
@@ -352,7 +352,7 @@ fn cgeninit(c: *cgen, a: *arena) void = {
|
||||
// match-arm bindings, which C cgen allocates via cgexpr's by-value
|
||||
// `locals` list — so two separate matches each get fresh slots even
|
||||
// when their bind names collide. scanlocals follows the same rule
|
||||
// for N_MCASE.
|
||||
// for nkind.N_MCASE.
|
||||
fn localalloc(c: *cgen, name: str, sz: i32, tnode: *node) i32 = {
|
||||
let asz: i32 = sz;
|
||||
if (asz < 8) { asz = 8; };
|
||||
@@ -380,7 +380,7 @@ fn localadd(c: *cgen, name: str, sz: i32, tnode: *node) i32 = {
|
||||
//
|
||||
// On a dedup hit we also overwrite the stored tnode to match
|
||||
// the new declaration's type. C reads `n->lhs->type` (filled
|
||||
// by the checker) at every N_DOT/N_CAST site; we read
|
||||
// by the checker) at every nkind.N_DOT/nkind.N_CAST site; we read
|
||||
// `lc.tnode`, so it must follow source order. Without this,
|
||||
// a later `let m: *node` inside a branch keeps an earlier
|
||||
// `let m: i32`'s tnode and `m.next` falls into the SB fallback.
|
||||
@@ -552,16 +552,16 @@ fn internstrlit(c: *cgen, bytes: str) str = {
|
||||
fn emitdefconstants(c: *cgen, file: *node) void = {
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == N_DEF) {
|
||||
if (d.kind == nkind.N_DEF) {
|
||||
let r: *node = d.rhs;
|
||||
let v: u64 = 0u64;
|
||||
let ok: bool = false;
|
||||
if (r != nil) {
|
||||
if (r.kind == N_INTLIT) { v = r.uval; ok = true; };
|
||||
if (r.kind == N_RUNELIT) { v = r.uval; ok = true; };
|
||||
if (r.kind == N_TRUE) { v = 1u64; ok = true; };
|
||||
if (r.kind == N_FALSE) { v = 0u64; ok = true; };
|
||||
if (r.kind == N_NIL) { v = 0u64; ok = true; };
|
||||
if (r.kind == nkind.N_INTLIT) { v = r.uval; ok = true; };
|
||||
if (r.kind == nkind.N_RUNELIT) { v = r.uval; ok = true; };
|
||||
if (r.kind == nkind.N_TRUE) { v = 1u64; ok = true; };
|
||||
if (r.kind == nkind.N_FALSE) { v = 0u64; ok = true; };
|
||||
if (r.kind == nkind.N_NIL) { v = 0u64; ok = true; };
|
||||
};
|
||||
if (ok) {
|
||||
emitline("DATA ");
|
||||
@@ -691,7 +691,7 @@ fn collectfnrets(c: *cgen, file: *node) void = {
|
||||
c.fnrets = nil;
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == N_FNDECL) {
|
||||
if (d.kind == nkind.N_FNDECL) {
|
||||
let f: *fnret = amalloc(c.a, 32u64): *fnret;
|
||||
f.fname = d.str;
|
||||
f.rtype = d.lhs;
|
||||
@@ -716,7 +716,7 @@ fn fnretlookup(c: *cgen, name: str) *node = {
|
||||
//
|
||||
// `def NAME: T = LIT;` becomes a DATA symbol the C-side w6c emits; an
|
||||
// ident reference loads it via `MOVQ NAME(SB), AX`. We collect them at
|
||||
// file load and consult on N_IDENT lookup.
|
||||
// file load and consult on nkind.N_IDENT lookup.
|
||||
|
||||
type defent = struct {
|
||||
dname: str,
|
||||
@@ -728,7 +728,7 @@ fn collectdefs(c: *cgen, file: *node) void = {
|
||||
c.defs = nil;
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == N_DEF) {
|
||||
if (d.kind == nkind.N_DEF) {
|
||||
let e: *defent = amalloc(c.a, 32u64): *defent;
|
||||
e.dname = d.str;
|
||||
e.drhs = d.rhs;
|
||||
@@ -784,7 +784,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
||||
// Mirror collectfnrets' shape exactly (plain prepend in one
|
||||
// branch). Earlier nested-if/early-return variants tickled a
|
||||
// wwstage cgen bug that dropped most prepends.
|
||||
if (d.kind == N_FNDECL) {
|
||||
if (d.kind == nkind.N_FNDECL) {
|
||||
if (d.exported == 0) {
|
||||
if (d.module.len > 0) {
|
||||
if (!streq(d.str, "main")) {
|
||||
@@ -797,7 +797,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (d.kind == N_DEF) {
|
||||
if (d.kind == nkind.N_DEF) {
|
||||
if (d.exported == 0) {
|
||||
if (d.module.len > 0) {
|
||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||
@@ -808,7 +808,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (d.kind == N_TYPEDECL) {
|
||||
if (d.kind == nkind.N_TYPEDECL) {
|
||||
if (d.exported == 0) {
|
||||
if (d.module.len > 0) {
|
||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||
@@ -819,7 +819,7 @@ fn collectmods(c: *cgen, file: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
if (d.kind == N_LET) {
|
||||
if (d.kind == nkind.N_LET) {
|
||||
if (d.exported == 0) {
|
||||
if (d.module.len > 0) {
|
||||
let m: *modent = amalloc(c.a, 48u64): *modent;
|
||||
@@ -872,15 +872,15 @@ fn fficollect(c: *cgen, file: *node) void = {
|
||||
if (file == nil) { return; };
|
||||
let d: *node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == N_FNDECL) {
|
||||
if (d.kind == nkind.N_FNDECL) {
|
||||
let a: *node = d.attr;
|
||||
for (a != nil) {
|
||||
if (a.kind == N_ATTR) {
|
||||
if (a.kind == nkind.N_ATTR) {
|
||||
let aname: str = a.str;
|
||||
if (streq(aname, "symbol")) {
|
||||
let symnode: *node = a.list;
|
||||
if (symnode != nil) {
|
||||
if (symnode.kind == N_STRLIT) {
|
||||
if (symnode.kind == nkind.N_STRLIT) {
|
||||
let f: *ffi = amalloc(c.a, 48u64): *ffi;
|
||||
f.ident = d.str;
|
||||
f.symbol = symnode.str;
|
||||
|
||||
Reference in New Issue
Block a user