selfhost: graduate N_* defs to nkind enum
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
// cgexpr is a thin dispatcher over n.kind; each non-trivial branch
|
||||
// lives in a per-kind helper (cgstrlit, cgident, cgindex, cgmatch,
|
||||
// cgdot, cgun, cgbin, cgcall, cgassign). Trivial literal loads
|
||||
// (N_INTLIT, N_RUNELIT, N_TRUE/FALSE/NIL, N_CAST) stay inline.
|
||||
// (nkind.N_INTLIT, nkind.N_RUNELIT, nkind.N_TRUE/FALSE/NIL, nkind.N_CAST) stay inline.
|
||||
//
|
||||
// The remainder of cgen lives in cgen.ww (foundation: types, emit
|
||||
// primitives, the collect* tables, FFI/module maps) and cgenstmt.ww
|
||||
@@ -24,7 +24,7 @@ fn cgexpr(c: *cgen, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
let k: i32 = n.kind;
|
||||
|
||||
if (k == N_INTLIT) {
|
||||
if (k == nkind.N_INTLIT) {
|
||||
// Print signed (i64), not unsigned (u64). C cgen uses
|
||||
// `$%lld` so 64-bit constants with bit 63 set show up as
|
||||
// negative — e.g. FNV-1a's offset basis prints as
|
||||
@@ -34,39 +34,39 @@ fn cgexpr(c: *cgen, n: *node) void = {
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
if (k == N_RUNELIT) {
|
||||
if (k == nkind.N_RUNELIT) {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(n.uval: i64);
|
||||
emitline(", AX\n");
|
||||
return;
|
||||
};
|
||||
if (k == N_STRLIT) { cgstrlit(c, n); return; };
|
||||
if (k == N_TRUE) {
|
||||
if (k == nkind.N_STRLIT) { cgstrlit(c, n); return; };
|
||||
if (k == nkind.N_TRUE) {
|
||||
emitline("\tMOVQ\t$1, AX\n");
|
||||
return;
|
||||
};
|
||||
if (k == N_FALSE) {
|
||||
if (k == nkind.N_FALSE) {
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
return;
|
||||
};
|
||||
if (k == N_NIL) {
|
||||
if (k == nkind.N_NIL) {
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
return;
|
||||
};
|
||||
if (k == N_VOIDLIT) {
|
||||
if (k == nkind.N_VOIDLIT) {
|
||||
// void value: zero-size, but the consumer's ABI expects a
|
||||
// deterministic AX. Emit 0 like nil/false do.
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
return;
|
||||
};
|
||||
|
||||
if (k == N_IDENT) { cgident(c, n); return; };
|
||||
if (k == nkind.N_IDENT) { cgident(c, n); return; };
|
||||
|
||||
if (k == N_INDEX) { cgindex(c, n); return; };
|
||||
if (k == nkind.N_INDEX) { cgindex(c, n); return; };
|
||||
|
||||
if (k == N_MATCH) { cgmatch(c, n); return; };
|
||||
if (k == nkind.N_MATCH) { cgmatch(c, n); return; };
|
||||
|
||||
if (k == N_CAST) {
|
||||
if (k == nkind.N_CAST) {
|
||||
// Type casts are mostly no-ops at the asm level for our
|
||||
// integer-shaped operands. Evaluate the source; AX holds
|
||||
// the bits unchanged. (Sign- or zero-extending narrow loads
|
||||
@@ -76,38 +76,38 @@ fn cgexpr(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
|
||||
if (k == N_DOT) { cgdot(c, n); return; };
|
||||
if (k == nkind.N_DOT) { cgdot(c, n); return; };
|
||||
|
||||
if (k == N_UN) { cgun(c, n); return; };
|
||||
if (k == nkind.N_UN) { cgun(c, n); return; };
|
||||
|
||||
if (k == N_BIN) { cgbin(c, n); return; };
|
||||
if (k == nkind.N_BIN) { cgbin(c, n); return; };
|
||||
|
||||
if (k == N_CALL) { cgcall(c, n); return; };
|
||||
if (k == nkind.N_CALL) { cgcall(c, n); return; };
|
||||
|
||||
if (k == N_ASSIGN) { cgassign(c, n); return; };
|
||||
if (k == nkind.N_ASSIGN) { cgassign(c, n); return; };
|
||||
|
||||
if (k == N_TRYPROP) { cgtryprop(c, n); return; };
|
||||
if (k == N_TRYUNW) { cgtryunw(c, n); return; };
|
||||
if (k == N_TYPETEST) { cgtypetest(c, n); return; };
|
||||
if (k == N_TYPEASSERT) { cgtypeassert(c, n); return; };
|
||||
if (k == nkind.N_TRYPROP) { cgtryprop(c, n); return; };
|
||||
if (k == nkind.N_TRYUNW) { cgtryunw(c, n); return; };
|
||||
if (k == nkind.N_TYPETEST) { cgtypetest(c, n); return; };
|
||||
if (k == nkind.N_TYPEASSERT) { cgtypeassert(c, n); return; };
|
||||
};
|
||||
|
||||
// cgtagvariantidx — find the 0-based variant index of `vt` inside the
|
||||
// tagged-union type expression `tagged`. -1 if `tagged` isn't an
|
||||
// N_TTAGGED or no variant matches. Mirrors the lookup that cgmatch
|
||||
// nkind.N_TTAGGED or no variant matches. Mirrors the lookup that cgmatch
|
||||
// does inline; pulled out so `is` / `as` can reuse it.
|
||||
fn cgtagvariantidx(tagged: *node, vt: *node) i32 = {
|
||||
if (tagged == nil) { return -1; };
|
||||
if (vt == nil) { return -1; };
|
||||
if (tagged.kind != N_TTAGGED) { return -1; };
|
||||
if (tagged.kind != nkind.N_TTAGGED) { return -1; };
|
||||
let want: str;
|
||||
want.ptr = nil; want.len = 0;
|
||||
if (vt.kind == N_TNAME) { want = vt.str; };
|
||||
if (vt.kind == nkind.N_TNAME) { want = vt.str; };
|
||||
if (want.len == 0) { return -1; };
|
||||
let v: *node = tagged.list;
|
||||
let idx: i32 = 0;
|
||||
for (v != nil) {
|
||||
if (v.kind == N_TNAME) {
|
||||
if (v.kind == nkind.N_TNAME) {
|
||||
if (streq(v.str, want)) { return idx; };
|
||||
};
|
||||
v = v.next;
|
||||
@@ -136,17 +136,17 @@ fn cgtryprop(c: *cgen, n: *node) void = {
|
||||
// shuffle (DX,CX) → (AX,BX); else move DX → AX.
|
||||
let succisstr: bool = false;
|
||||
if (n.lhs != nil) {
|
||||
if (n.lhs.kind == N_CALL) {
|
||||
if (n.lhs.kind == nkind.N_CALL) {
|
||||
let callee: *node = n.lhs.lhs;
|
||||
if (callee != nil) {
|
||||
let cname: str;
|
||||
cname.ptr = nil; cname.len = 0;
|
||||
if (callee.kind == N_IDENT) { cname = callee.str; };
|
||||
if (callee.kind == N_DOT) { cname = callee.str; };
|
||||
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
|
||||
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
|
||||
if (cname.len > 0) {
|
||||
let rt: *node = fnretlookup(c, cname);
|
||||
if (rt != nil) {
|
||||
if (rt.kind == N_TTAGGED) {
|
||||
if (rt.kind == nkind.N_TTAGGED) {
|
||||
let first: *node = rt.list;
|
||||
if (first != nil) {
|
||||
if (isstrtype(c, first)) {
|
||||
@@ -180,17 +180,17 @@ fn cgtryunw(c: *cgen, n: *node) void = {
|
||||
// Unwrap success value. (Same shuffle pattern as cgtryprop.)
|
||||
let succisstr: bool = false;
|
||||
if (n.lhs != nil) {
|
||||
if (n.lhs.kind == N_CALL) {
|
||||
if (n.lhs.kind == nkind.N_CALL) {
|
||||
let callee: *node = n.lhs.lhs;
|
||||
if (callee != nil) {
|
||||
let cname: str;
|
||||
cname.ptr = nil; cname.len = 0;
|
||||
if (callee.kind == N_IDENT) { cname = callee.str; };
|
||||
if (callee.kind == N_DOT) { cname = callee.str; };
|
||||
if (callee.kind == nkind.N_IDENT) { cname = callee.str; };
|
||||
if (callee.kind == nkind.N_DOT) { cname = callee.str; };
|
||||
if (cname.len > 0) {
|
||||
let rt: *node = fnretlookup(c, cname);
|
||||
if (rt != nil) {
|
||||
if (rt.kind == N_TTAGGED) {
|
||||
if (rt.kind == nkind.N_TTAGGED) {
|
||||
let first: *node = rt.list;
|
||||
if (first != nil) {
|
||||
if (isstrtype(c, first)) {
|
||||
@@ -222,7 +222,7 @@ fn cgtypetest(c: *cgen, n: *node) void = {
|
||||
let scrutoff: i32 = 0;
|
||||
let scrutt: *node = nil;
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_IDENT) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, lhs.str);
|
||||
if (lc != nil) {
|
||||
scrutoff = lc.off;
|
||||
@@ -253,33 +253,33 @@ fn cgtypetest(c: *cgen, n: *node) void = {
|
||||
|
||||
// isenumexpr — does this expression's static type resolve to an enum?
|
||||
// Recognises enum-member access (`Foo.MEMBER`), enum-typed local
|
||||
// idents, and N_BIN whose either operand is enum (so `R | W` flows
|
||||
// idents, and nkind.N_BIN whose either operand is enum (so `R | W` flows
|
||||
// through the cast pass-through too).
|
||||
fn isenumexpr(c: *cgen, e: *node) bool = {
|
||||
if (e == nil) { return false; };
|
||||
let k: i32 = e.kind;
|
||||
if (k == N_DOT) {
|
||||
if (k == nkind.N_DOT) {
|
||||
if (e.lhs != nil) {
|
||||
if (e.lhs.kind == N_IDENT) {
|
||||
if (e.lhs.kind == nkind.N_IDENT) {
|
||||
if (enumlookup(c, e.lhs.str) != nil) { return true; };
|
||||
};
|
||||
};
|
||||
};
|
||||
if (k == N_IDENT) {
|
||||
if (k == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, e.str);
|
||||
if (lc != nil) {
|
||||
if (lc.tnode != nil) {
|
||||
if (lc.tnode.kind == N_TNAME) {
|
||||
if (lc.tnode.kind == nkind.N_TNAME) {
|
||||
if (enumlookup(c, lc.tnode.str) != nil) { return true; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (k == N_BIN) {
|
||||
if (k == nkind.N_BIN) {
|
||||
if (isenumexpr(c, e.lhs)) { return true; };
|
||||
if (isenumexpr(c, e.rhs)) { return true; };
|
||||
};
|
||||
if (k == N_UN) {
|
||||
if (k == nkind.N_UN) {
|
||||
if (isenumexpr(c, e.lhs)) { return true; };
|
||||
};
|
||||
return false;
|
||||
@@ -287,8 +287,8 @@ fn isenumexpr(c: *cgen, e: *node) bool = {
|
||||
|
||||
fn isenumtype(c: *cgen, t: *node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
if (t.kind == N_TENUM) { return true; };
|
||||
if (t.kind == N_TNAME) {
|
||||
if (t.kind == nkind.N_TENUM) { return true; };
|
||||
if (t.kind == nkind.N_TNAME) {
|
||||
if (enumlookup(c, t.str) != nil) { return true; };
|
||||
};
|
||||
return false;
|
||||
@@ -310,7 +310,7 @@ fn cgtypeassert(c: *cgen, n: *node) void = {
|
||||
let scrutoff: i32 = 0;
|
||||
let scrutt: *node = nil;
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_IDENT) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, lhs.str);
|
||||
if (lc != nil) {
|
||||
scrutoff = lc.off;
|
||||
@@ -412,11 +412,11 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
let esz: i32 = 8;
|
||||
let baselocal: *local = nil;
|
||||
if (base != nil) {
|
||||
if (base.kind == N_IDENT) {
|
||||
if (base.kind == nkind.N_IDENT) {
|
||||
let bn: str = base.str;
|
||||
baselocal = localfindnode(c, bn);
|
||||
if (baselocal != nil) { esz = elemsizeof(baselocal.tnode); };
|
||||
} else { if (base.kind == N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
esz = indexbaseesz(c, base);
|
||||
};};
|
||||
};
|
||||
@@ -430,7 +430,7 @@ fn cgindex(c: *cgen, n: *node) void = {
|
||||
if (baselocal != nil) {
|
||||
let tn: *node = baselocal.tnode;
|
||||
let isarray: bool = false;
|
||||
if (tn != nil) { if (tn.kind == N_TARRAY) { isarray = true; }; };
|
||||
if (tn != nil) { if (tn.kind == nkind.N_TARRAY) { isarray = true; }; };
|
||||
if (isarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(baselocal.off: i64);
|
||||
@@ -479,7 +479,7 @@ fn cgmatch(c: *cgen, n: *node) void = {
|
||||
let scrutoff: i32 = 0;
|
||||
let scrutt: *node = nil;
|
||||
if (scrut != nil) {
|
||||
if (scrut.kind == N_IDENT) {
|
||||
if (scrut.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, scrut.str);
|
||||
if (lc != nil) {
|
||||
scrutoff = lc.off;
|
||||
@@ -507,7 +507,7 @@ fn cgmatch(c: *cgen, n: *node) void = {
|
||||
// void arm: skip if ptr != 0.
|
||||
let ptr_tag: i32 = nullableptrtag(scrutt);
|
||||
let cur_tag: i32 = 0;
|
||||
if (pat.kind == N_TPTR) { cur_tag = ptr_tag; }
|
||||
if (pat.kind == nkind.N_TPTR) { cur_tag = ptr_tag; }
|
||||
else { if (ptr_tag == 0) { cur_tag = 1; }; };
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scrutoff: i64);
|
||||
@@ -523,15 +523,15 @@ fn cgmatch(c: *cgen, n: *node) void = {
|
||||
} else {
|
||||
let want: i32 = 0;
|
||||
if (scrutt != nil) {
|
||||
if (scrutt.kind == N_TTAGGED) {
|
||||
if (scrutt.kind == nkind.N_TTAGGED) {
|
||||
let patname: str;
|
||||
patname.ptr = nil; patname.len = 0;
|
||||
if (pat.kind == N_TNAME) { patname = pat.str; };
|
||||
if (pat.kind == nkind.N_TNAME) { patname = pat.str; };
|
||||
let v: *node = scrutt.list;
|
||||
let idx: i32 = 0;
|
||||
let found: bool = false;
|
||||
for (v != nil) {
|
||||
if (v.kind == N_TNAME) {
|
||||
if (v.kind == nkind.N_TNAME) {
|
||||
if (streq(v.str, patname)) {
|
||||
want = idx;
|
||||
found = true;
|
||||
@@ -565,7 +565,7 @@ fn cgmatch(c: *cgen, n: *node) void = {
|
||||
// Bind the pointer (or skip for the
|
||||
// void arm, which has zero-size). The
|
||||
// value IS slot+0.
|
||||
if (pat.kind == N_TPTR) {
|
||||
if (pat.kind == nkind.N_TPTR) {
|
||||
let voff: i32 = localalloc(c, bn, 8, pat);
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(scrutoff: i64);
|
||||
@@ -621,12 +621,12 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
if (lhs != nil) {
|
||||
let etname: str;
|
||||
etname.ptr = nil; etname.len = 0;
|
||||
if (lhs.kind == N_IDENT) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
etname = lhs.str;
|
||||
};
|
||||
if (lhs.kind == N_DOT) {
|
||||
if (lhs.kind == nkind.N_DOT) {
|
||||
if (lhs.lhs != nil) {
|
||||
if (lhs.lhs.kind == N_IDENT) {
|
||||
if (lhs.lhs.kind == nkind.N_IDENT) {
|
||||
etname = lhs.str;
|
||||
};
|
||||
};
|
||||
@@ -645,7 +645,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_IDENT) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
let nm: str = lhs.str;
|
||||
let lc: *local = localfindnode(c, nm);
|
||||
if (lc != nil) {
|
||||
@@ -653,12 +653,12 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
let lkind: i32 = -1;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
// Pointer-to-struct: deref then field load.
|
||||
if (lkind == N_TPTR) {
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (inner != nil) {
|
||||
if (inner.kind == N_TNAME) {
|
||||
if (inner.kind == nkind.N_TNAME) {
|
||||
sname = inner.str;
|
||||
};
|
||||
};
|
||||
@@ -699,7 +699,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
// Direct struct local: field load at off+foff.
|
||||
if (lkind == N_TNAME) {
|
||||
if (lkind == nkind.N_TNAME) {
|
||||
let sname: str = tn.str;
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
@@ -733,7 +733,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// Array pseudo-fields: `.ptr` is the array's
|
||||
// address (LEAQ); `.len` is the static element
|
||||
// count (immediate).
|
||||
if (lkind == N_TARRAY) {
|
||||
if (lkind == nkind.N_TARRAY) {
|
||||
if (streq(fld, "ptr")) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
@@ -744,7 +744,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
let lenn: *node = tn.rhs;
|
||||
let alen: i64 = 0i64;
|
||||
if (lenn != nil) {
|
||||
if (lenn.kind == N_INTLIT) { alen = lenn.uval: i64; };
|
||||
if (lenn.kind == nkind.N_INTLIT) { alen = lenn.uval: i64; };
|
||||
};
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(alen);
|
||||
@@ -758,7 +758,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// the scalar in an 8B slot and the str in 16B). For
|
||||
// a str element, load both halves into (AX, BX) so
|
||||
// chains like `t.1.len` propagate correctly.
|
||||
if (lkind == N_TTUPLE) {
|
||||
if (lkind == nkind.N_TTUPLE) {
|
||||
let idx: i32 = fldnumidx(fld);
|
||||
if (idx >= 0) {
|
||||
let tp: *node = tn.list;
|
||||
@@ -805,15 +805,15 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// Pointer to str/slice (`*[]u8`, `*str`):
|
||||
// deref, then load at delta within the
|
||||
// pointed-to header. C cgen does the same.
|
||||
if (lkind == N_TPTR) {
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let innerkind: i32 = -1;
|
||||
if (inner != nil) { innerkind = inner.kind; };
|
||||
let innerstr: bool = false;
|
||||
if (innerkind == N_TNAME) {
|
||||
if (innerkind == nkind.N_TNAME) {
|
||||
if (streq(inner.str, "str")) { innerstr = true; };
|
||||
};
|
||||
if (innerkind == N_TSLICE) { innerstr = true; };
|
||||
if (innerkind == nkind.N_TSLICE) { innerstr = true; };
|
||||
if (innerstr) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(lc.off: i64);
|
||||
@@ -836,12 +836,12 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// Sdef-backed strs aren't laid out in memory, so falling
|
||||
// through to the SB-load fallback below would mis-emit
|
||||
// `MOVQ <field>(SB), AX` (looking up the field name as a
|
||||
// symbol). Mirrors cmd/w6c/cgen.c N_DOT off==0 / Sdef branch.
|
||||
// symbol). Mirrors cmd/w6c/cgen.c nkind.N_DOT off==0 / Sdef branch.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_IDENT) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
let drhs: *node = deflookuprhs(c, lhs.str);
|
||||
if (drhs != nil) {
|
||||
if (drhs.kind == N_STRLIT) {
|
||||
if (drhs.kind == nkind.N_STRLIT) {
|
||||
let bytes: str = drhs.str;
|
||||
if (streq(fld, "ptr")) {
|
||||
let lab: str = internstrlit(c, bytes);
|
||||
@@ -861,11 +861,11 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
// Module-qualified value reference: `mod.name` where `mod`
|
||||
// is N_IDENT bound as skind.SK_USE and the leaf isn't a local.
|
||||
// is nkind.N_IDENT bound as skind.SK_USE and the leaf isn't a local.
|
||||
// Treat as a SB symbol — `MOVQ leaf(SB), AX`. Same fallback
|
||||
// the C cgen takes when bt is NULL/tyerr.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_IDENT) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitsymname(c, fld);
|
||||
emitline("(SB), AX\n");
|
||||
@@ -892,7 +892,7 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
// itself, so reads silently get the pointer value instead of
|
||||
// the field. (Showed up porting w6l/pass.ww.)
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_DOT) {
|
||||
if (lhs.kind == nkind.N_DOT) {
|
||||
let innert: *node = dotinnerstructptr(c, lhs);
|
||||
if (innert != nil) {
|
||||
let sname: str = innert.str;
|
||||
@@ -941,7 +941,7 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
if (n.op == tkind.TK_AMP) {
|
||||
let opnd: *node = n.lhs;
|
||||
if (opnd != nil) {
|
||||
if (opnd.kind == N_IDENT) {
|
||||
if (opnd.kind == nkind.N_IDENT) {
|
||||
let nm: str = opnd.str;
|
||||
let off: i32 = localfind(c, nm);
|
||||
if (off != 0) {
|
||||
@@ -1047,7 +1047,7 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
let calleename: str;
|
||||
calleename.ptr = nil; calleename.len = 0;
|
||||
// Detect fn-pointer field call: `w.emit(args)` where `w` is
|
||||
// a struct local and `emit` is an N_TFN field. Load the
|
||||
// a struct local and `emit` is an nkind.N_TFN field. Load the
|
||||
// field value into AX and CALL through it. Also detect a
|
||||
// bare `fp(args)` where `fp` is a local holding a function
|
||||
// pointer — mirror C cgen's localfind dispatch (commit
|
||||
@@ -1055,17 +1055,17 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
// the linker rightly fails.
|
||||
let isfnptrcall: bool = false;
|
||||
if (callee != nil) {
|
||||
if (callee.kind == N_IDENT) {
|
||||
if (callee.kind == nkind.N_IDENT) {
|
||||
let cn: str = callee.str;
|
||||
if (localfindnode(c, cn) != nil) {
|
||||
isfnptrcall = true;
|
||||
};
|
||||
};
|
||||
if (callee.kind == N_DOT) {
|
||||
if (callee.kind == nkind.N_DOT) {
|
||||
let base: *node = callee.lhs;
|
||||
let fld: str = callee.str;
|
||||
if (base != nil) {
|
||||
if (base.kind == N_IDENT) {
|
||||
if (base.kind == nkind.N_IDENT) {
|
||||
let bn: str = base.str;
|
||||
let lc: *local = localfindnode(c, bn);
|
||||
if (lc != nil) {
|
||||
@@ -1074,11 +1074,11 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
let lkind: i32 = tn.kind;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (lkind == N_TNAME) { sname = tn.str; };
|
||||
if (lkind == N_TPTR) {
|
||||
if (lkind == nkind.N_TNAME) { sname = tn.str; };
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
if (inner != nil) {
|
||||
if (inner.kind == N_TNAME) { sname = inner.str; };
|
||||
if (inner.kind == nkind.N_TNAME) { sname = inner.str; };
|
||||
};
|
||||
};
|
||||
if (sname.len > 0) {
|
||||
@@ -1090,7 +1090,7 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
if (streq(fn_, fld)) {
|
||||
let ft: *node = fi.tnode;
|
||||
if (ft != nil) {
|
||||
if (ft.kind == N_TFN) {
|
||||
if (ft.kind == nkind.N_TFN) {
|
||||
isfnptrcall = true;
|
||||
};
|
||||
};
|
||||
@@ -1117,10 +1117,10 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
} else {
|
||||
emitline("\tCALL\t");
|
||||
if (callee != nil) {
|
||||
if (callee.kind == N_IDENT) {
|
||||
if (callee.kind == nkind.N_IDENT) {
|
||||
calleename = callee.str;
|
||||
emitsymname(c, calleename);
|
||||
} else { if (callee.kind == N_DOT) {
|
||||
} else { if (callee.kind == nkind.N_DOT) {
|
||||
calleename = callee.str;
|
||||
emitsymname(c, calleename);
|
||||
};};
|
||||
@@ -1141,10 +1141,10 @@ fn cgcall(c: *cgen, n: *node) void = {
|
||||
fn cgassign(c: *cgen, n: *node) void = {
|
||||
let lhs: *node = n.lhs;
|
||||
// Discard lvalue `_ = expr;` — evaluate rhs for side effects,
|
||||
// write nothing. Detected by lhs being an N_IDENT with empty str
|
||||
// write nothing. Detected by lhs being an nkind.N_IDENT with empty str
|
||||
// (planted by parseprimary on the tkind.TK_UNDER token).
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_IDENT) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
if (lhs.str.len == 0) {
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
cgexpr(c, n.rhs);
|
||||
@@ -1159,22 +1159,22 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// We default to MOVQ (8B) since most fixtures use it; for
|
||||
// `*bool` / `*u8` / `*i32` we narrow via the local's tnode.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_UN) {
|
||||
if (lhs.kind == nkind.N_UN) {
|
||||
if (lhs.op == tkind.TK_STAR) {
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
let inner: *node = lhs.lhs;
|
||||
let elemstr: bool = false;
|
||||
let storeop: str = "MOVQ";
|
||||
if (inner != nil) {
|
||||
if (inner.kind == N_IDENT) {
|
||||
if (inner.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, inner.str);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
if (tn != nil) {
|
||||
if (tn.kind == N_TPTR) {
|
||||
if (tn.kind == nkind.N_TPTR) {
|
||||
let pe: *node = tn.lhs;
|
||||
if (pe != nil) {
|
||||
if (pe.kind == N_TNAME) {
|
||||
if (pe.kind == nkind.N_TNAME) {
|
||||
if (streq(pe.str, "str")) { elemstr = true; }
|
||||
else {
|
||||
let ps: i32 = primsize(pe.str);
|
||||
@@ -1218,20 +1218,20 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// Array/slice/ptr index store: `arr[i] = v;`. Element size
|
||||
// from base.tnode picks MOVB vs MOVQ.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_INDEX) {
|
||||
if (lhs.kind == nkind.N_INDEX) {
|
||||
if (n.op == tkind.TK_ASSIGN) {
|
||||
let base: *node = lhs.lhs;
|
||||
let idx: *node = lhs.rhs;
|
||||
let esz: i32 = 8;
|
||||
let baselocal: *local = nil;
|
||||
if (base != nil) {
|
||||
if (base.kind == N_IDENT) {
|
||||
if (base.kind == nkind.N_IDENT) {
|
||||
let bn: str = base.str;
|
||||
baselocal = localfindnode(c, bn);
|
||||
if (baselocal != nil) {
|
||||
esz = elemsizeof(baselocal.tnode);
|
||||
};
|
||||
} else { if (base.kind == N_DOT) {
|
||||
} else { if (base.kind == nkind.N_DOT) {
|
||||
esz = indexbaseesz(c, base);
|
||||
};};
|
||||
};
|
||||
@@ -1249,7 +1249,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (baselocal != nil) {
|
||||
let tn: *node = baselocal.tnode;
|
||||
let isarray: bool = false;
|
||||
if (tn != nil) { if (tn.kind == N_TARRAY) { isarray = true; }; };
|
||||
if (tn != nil) { if (tn.kind == nkind.N_TARRAY) { isarray = true; }; };
|
||||
if (isarray) {
|
||||
emitline("\tLEAQ\t");
|
||||
emitoff(baselocal.off: i64);
|
||||
@@ -1282,11 +1282,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// `p.f = expr;`. Only plain `=` is wired (compound on field
|
||||
// is rare and not yet needed by our fixtures).
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_DOT) {
|
||||
if (lhs.kind == nkind.N_DOT) {
|
||||
let base: *node = lhs.lhs;
|
||||
let fld: str = lhs.str;
|
||||
if (base != nil) {
|
||||
if (base.kind == N_IDENT) {
|
||||
if (base.kind == nkind.N_IDENT) {
|
||||
let bn: str = base.str;
|
||||
let lc: *local = localfindnode(c, bn);
|
||||
if (lc != nil) {
|
||||
@@ -1294,12 +1294,12 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
let lkind: i32 = -1;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
// Pointer-to-struct: deref then store.
|
||||
if (lkind == N_TPTR) {
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (inner != nil) {
|
||||
if (inner.kind == N_TNAME) { sname = inner.str; };
|
||||
if (inner.kind == nkind.N_TNAME) { sname = inner.str; };
|
||||
};
|
||||
if (sname.len > 0) {
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
@@ -1368,7 +1368,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
// Direct struct local: store at off+foff.
|
||||
if (lkind == N_TNAME) {
|
||||
if (lkind == nkind.N_TNAME) {
|
||||
let sname: str = tn.str;
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
@@ -1395,15 +1395,15 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
if (streq(fld, "len")) { delta = 8; };
|
||||
if (streq(fld, "cap")) { delta = 16; };
|
||||
if (delta >= 0) {
|
||||
if (lkind == N_TPTR) {
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
let innerkind: i32 = -1;
|
||||
if (inner != nil) { innerkind = inner.kind; };
|
||||
let innerstr: bool = false;
|
||||
if (innerkind == N_TNAME) {
|
||||
if (innerkind == nkind.N_TNAME) {
|
||||
if (streq(inner.str, "str")) { innerstr = true; };
|
||||
};
|
||||
if (innerkind == N_TSLICE) { innerstr = true; };
|
||||
if (innerkind == nkind.N_TSLICE) { innerstr = true; };
|
||||
if (innerstr) {
|
||||
if (n.op != tkind.TK_ASSIGN) {
|
||||
// Compound on `(*str|*slice).field`: load
|
||||
@@ -1462,11 +1462,11 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// store. Only plain `=` is wired here; chained compound on a
|
||||
// pointer-field hasn't surfaced.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_DOT) {
|
||||
if (lhs.kind == nkind.N_DOT) {
|
||||
let base: *node = lhs.lhs;
|
||||
let fld: str = lhs.str;
|
||||
if (base != nil) {
|
||||
if (base.kind == N_DOT) {
|
||||
if (base.kind == nkind.N_DOT) {
|
||||
let innert: *node = dotinnerstructptr(c, base);
|
||||
if (innert != nil) {
|
||||
let sname: str = innert.str;
|
||||
@@ -1522,7 +1522,7 @@ fn cgassign(c: *cgen, n: *node) void = {
|
||||
// forms (+= -= *= /=); other compounds fall back to
|
||||
// "evaluate rhs, replace". Mirrors C cgen's IDENT-assign path.
|
||||
if (lhs != nil) {
|
||||
if (lhs.kind == N_IDENT) {
|
||||
if (lhs.kind == nkind.N_IDENT) {
|
||||
let nm: str = lhs.str;
|
||||
let off: i32 = localfind(c, nm);
|
||||
if (off == 0) { return; };
|
||||
|
||||
Reference in New Issue
Block a user