w6c+selfhost: cgen N_DOT slice-field through *T root in call args (closes #29)
This commit is contained in:
@@ -413,6 +413,75 @@ fn nodeisslice(c: *cgen, n: *node) bool = {
|
||||
};
|
||||
if (k == nkind.N_SLICE) { return true; };
|
||||
if (k == nkind.N_CAST) { return isslicetype(c, n.rhs); };
|
||||
// N_DOT to a slice field: resolve the field through the struct
|
||||
// (or *struct) the base ident / inner chain lands on, then check
|
||||
// the field tnode. Mirrors nodeisstr's N_DOT branch so call-arg
|
||||
// push/pop counts 3 words for `p.sl` and `p.inner.sl` shapes.
|
||||
// `.ptr` / `.len` / `.cap` are pseudo-fields — they yield ptr
|
||||
// (*u8) and i32, not a slice — so we exclude them up front.
|
||||
if (k == nkind.N_DOT) {
|
||||
let base: *node = n.lhs;
|
||||
let fld: str = n.str;
|
||||
if (streq(fld, "ptr")) { return false; };
|
||||
if (streq(fld, "len")) { return false; };
|
||||
if (streq(fld, "cap")) { return false; };
|
||||
if (base != nil) {
|
||||
let sname: str;
|
||||
sname.ptr = nil; sname.len = 0;
|
||||
if (base.kind == nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, base.str);
|
||||
if (lc != nil) {
|
||||
let tn: *node = lc.tnode;
|
||||
let lkind: nkind = nkind.N_NONE;
|
||||
if (tn != nil) { lkind = tn.kind; };
|
||||
if (lkind == nkind.N_TNAME) { sname = tn.str; };
|
||||
if (lkind == nkind.N_TPTR) {
|
||||
let inner: *node = tn.lhs;
|
||||
if (inner != nil) {
|
||||
if (inner.kind == nkind.N_TNAME) { sname = inner.str; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (base.kind == nkind.N_DOT) {
|
||||
let innert: *node = dotinnerstructptr(c, base);
|
||||
if (innert != nil) {
|
||||
if (innert.kind == nkind.N_TNAME) { sname = innert.str; };
|
||||
};
|
||||
};
|
||||
if (sname.len > 0) {
|
||||
let si: *structinfo = structlookup(c, sname);
|
||||
if (si != nil) {
|
||||
let fi: *fieldinfo = si.fields;
|
||||
for (fi != nil) {
|
||||
if (streq(fi.fname, fld)) {
|
||||
return isslicetype(c, fi.tnode);
|
||||
};
|
||||
fi = fi.finext;
|
||||
};
|
||||
};
|
||||
};
|
||||
// Chained dot through value-struct hops (`o.inner.sl`,
|
||||
// `p.inner.sl`): dotinnerstructptr above only walks
|
||||
// *struct fields, so a value-struct chain falls through.
|
||||
// dotchainresolve handles arbitrary depth through value
|
||||
// struct AND `*T` root, returning the leaf fieldinfo.
|
||||
let rootnm: str = "";
|
||||
let rootoff: i32 = 0;
|
||||
let totaloff: i32 = 0;
|
||||
let lfi: *fieldinfo = nil;
|
||||
let sdelta: i32 = -1;
|
||||
let isglobal: bool = false;
|
||||
let ptrroot: bool = false;
|
||||
let ok: bool = dotchainresolve(c, n,
|
||||
&rootnm, &rootoff, &totaloff,
|
||||
&lfi, &sdelta, &isglobal, &ptrroot);
|
||||
if (ok && sdelta < 0 && lfi != nil) {
|
||||
return isslicetype(c, lfi.tnode);
|
||||
};
|
||||
};
|
||||
return false;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -494,12 +563,10 @@ fn nodeisstr(c: *cgen, n: *node) bool = {
|
||||
};
|
||||
};
|
||||
// Chained dot through value-struct hops (`p.inner.s`):
|
||||
// dotinnerstructptr above only walks *struct fields, so
|
||||
// a value-struct chain falls through and the call-arg
|
||||
// path then pushes only 1 word for the str instead of
|
||||
// 2 (ptr+len), silently dropping the len half.
|
||||
// dotchainresolve handles arbitrary depth through value
|
||||
// struct AND `*T` root, returning the leaf fieldinfo.
|
||||
// dotinnerstructptr above only walks *struct fields;
|
||||
// dotchainresolve handles arbitrary depth through
|
||||
// value struct AND `*T` root. Mirror of the nodeisslice
|
||||
// fallback so chained str-field args also push 2 words.
|
||||
let rootnm: str = "";
|
||||
let rootoff: i32 = 0;
|
||||
let totaloff: i32 = 0;
|
||||
|
||||
Reference in New Issue
Block a user