wwstage: port struct embedding; graduate #59.13
The last frontend-gap pin: wwstage had no Hare struct embedding
(struct { hash.hash, ... }), rejecting lib/crypto/sha256 at parse.
- parse.ww: the three member forms (named / anonymous struct / bare
dotted-ident embed), consume-then-branch since this parser has no
peek; embeds carry f.str == "" and the type in f.lhs.
- check.ww N_TSTRUCT flatten: promote the inner struct's flattened
fields at base+src.offset (check.c:961-990); the embed is one
nested-struct unit in the slot ladder; the resolved inner AST is
planted on the TFIELD rhs for cgen.
- check.ww walkers: astoffset / exprtype N_DOT / #251 struct-lit
field lookups descend embeds through shared helpers; the collision
and non-struct-embed rejects live in validatestructfields (the
once-per-decl diagnostic site).
- cgenutil.ww registerstruct: regfieldrun walks the AST against the
flattened tfield cursor, descending embeds via the planted inner
AST so promoted fieldinfo entries keep the inner field's own name
and type node.
- wwi printers unchanged (both stages already emit nameless fields).
sha256_test compiles byte-identically end to end and its 6 tests
pass; 989_lib_byteid is now 44 id / 0 divergent / 0 wwreject.
Fixtures r5913_* (promoted rw, offset shift, anonymous embed,
two-level embed + promoted fn-ptr callee, three rejects); corpus pin
1485/2970.
This commit is contained in:
@@ -2990,6 +2990,53 @@ fn fieldsize(c: *cgen, tnode: *syntax.node) i32 = {
|
||||
// non-TFIELD identically), so they advance in exact step. si.totsize keeps
|
||||
// the slot-padded total (stack-slot allocator's number) from ti.slotsize,
|
||||
// already 8-rounded at check.ww:2259-2261.
|
||||
// regfieldwalk — cursor state threaded through regfieldrun's embed-
|
||||
// descending AST/tfield lock-step walk.
|
||||
type regfieldwalk = struct {
|
||||
tf: *syntax.tfield,
|
||||
head: *fieldinfo,
|
||||
tail: *fieldinfo,
|
||||
};
|
||||
|
||||
// regfieldrun — walk an AST TFIELD list against the flattened
|
||||
// tinfo.fields cursor. A named field consumes one tfield; an embed
|
||||
// (#59.13, f.str == "") descends into the resolved inner struct AST
|
||||
// the checker planted on f.rhs (check.ww N_TSTRUCT flatten) — its
|
||||
// fields were promoted into THIS struct's tinfo run in the same
|
||||
// order, so the one cursor stays in exact step and each promoted
|
||||
// fieldinfo carries the inner field's own name and type node.
|
||||
fn regfieldrun(c: *cgen, flist: *syntax.node, w: *regfieldwalk) void = {
|
||||
let f: *syntax.node = flist;
|
||||
for (f != nil) {
|
||||
if (f.kind == syntax.nkind.N_TFIELD) {
|
||||
if (f.str.len == 0) {
|
||||
if (f.rhs == nil) {
|
||||
let msg: str = "#59.13: registerstruct: embed field has no checker-planted inner struct AST\n";
|
||||
os.write(2, msg.ptr, msg.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
regfieldrun(c, f.rhs.list, w);
|
||||
} else {
|
||||
if (w.tf == nil) {
|
||||
let msg: str = "#44/#55: registerstruct: AST/tfield walk desync (more TFIELDs than tinfo.fields)\n";
|
||||
os.write(2, msg.ptr, msg.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let fi: *fieldinfo = alloc(fieldinfo{
|
||||
fname = f.str,
|
||||
foff = w.tf.offset: i32,
|
||||
fsz = w.tf.type_.size: i32,
|
||||
tnode = f.lhs,
|
||||
})!;
|
||||
if (w.head == nil) { w.head = fi; w.tail = fi; }
|
||||
else { w.tail.finext = fi; w.tail = fi; };
|
||||
w.tf = w.tf.tnext;
|
||||
};
|
||||
};
|
||||
f = f.next;
|
||||
};
|
||||
};
|
||||
|
||||
fn registerstruct(c: *cgen, name: str, srcmod: str, tstruct: *syntax.node) void = {
|
||||
let si: *structinfo = alloc(structinfo{
|
||||
sname = name,
|
||||
@@ -3006,30 +3053,12 @@ fn registerstruct(c: *cgen, name: str, srcmod: str, tstruct: *syntax.node) void
|
||||
os.write(2, msg.ptr, msg.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let head: *fieldinfo = nil;
|
||||
let tail: *fieldinfo = nil;
|
||||
let f: *syntax.node = tstruct.list;
|
||||
let tf: *syntax.tfield = ti.fields;
|
||||
for (f != nil) {
|
||||
if (f.kind == syntax.nkind.N_TFIELD) {
|
||||
if (tf == nil) {
|
||||
let msg: str = "#44/#55: registerstruct: AST/tfield walk desync (more TFIELDs than tinfo.fields)\n";
|
||||
os.write(2, msg.ptr, msg.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
let fi: *fieldinfo = alloc(fieldinfo{
|
||||
fname = f.str,
|
||||
foff = tf.offset: i32,
|
||||
fsz = tf.type_.size: i32,
|
||||
tnode = f.lhs,
|
||||
})!;
|
||||
if (head == nil) { head = fi; tail = fi; }
|
||||
else { tail.finext = fi; tail = fi; };
|
||||
tf = tf.tnext;
|
||||
};
|
||||
f = f.next;
|
||||
};
|
||||
si.fields = head;
|
||||
let w: regfieldwalk;
|
||||
w.tf = ti.fields;
|
||||
w.head = nil;
|
||||
w.tail = nil;
|
||||
regfieldrun(c, tstruct.list, &w);
|
||||
si.fields = w.head;
|
||||
si.totsize = ti.slotsize: i32;
|
||||
si.sinext = c.structs;
|
||||
c.structs = si;
|
||||
|
||||
Reference in New Issue
Block a user