wcc: cgen N_CALL "len" TY_ARRAY/TY_SLICE/TY_STR intercept (#131)

wwstage cgenexpr cgcall now intercepts the N_IDENT-callee `len` like
cstage cgen.c:4283-4297 — TY_ARRAY folds to MOVQ $alen,AX at compile
time, TY_SLICE/TY_STR + N_IDENT loads the .len slot from local header,
fallback to cgexpr. Rule-9 Hare-fidelity (Hare/Rust/Go compile-time-fold
len(fixedarray)) + rule-10 align wwstage UP to cstage. Byte-id-neutral
at master (bootstrap has no current len(fixedarray) call-form uses);
prereq for fold-3 decimal.ha port (`len(d.digits)` at decimal.ha:66/
77/86/124).
This commit is contained in:
2026-05-26 20:39:03 +09:00
parent bb6f8406c7
commit 4acab6e0bb
3 changed files with 138 additions and 0 deletions

View File

@@ -3404,6 +3404,52 @@ fn cgcall(c: *cgen, n: *node) void = {
};
};
};
// `len(x)` Hare builtin — mirror cmd/w6c/cgen.c:4283-4297.
// Required for byte-id when compiler-imported lib code uses
// len(fixedarray) (e.g. lib/strconv/decimal.ha's `len(d.digits)`
// over the [800]u8 field). Without this intercept wwstage falls
// through to a regular CALL len(SB) while cstage folds to
// `MOVQ $alen, AX` — rule-10 byte-id break (#131).
//
// Argument-type-driven branches:
// TY_SLICE / TY_STR (+ N_IDENT operand) → load .len at BP+off+8.
// TY_ARRAY → fold `MOVQ $alen, AX`.
// else → evaluate operand (cstage's pseudo-.len fallback —
// unlikely to fire on Hare-shaped sources).
if (streq(callee.str, "len")) {
if (n.list != nil) {
let a: *node = n.list;
let at: *tinfo = a.type_: *tinfo;
let u: *tinfo = at;
for (u != nil && u.kind == tykind.TY_NAMED) {
u = u.under;
};
if (u != nil) {
if ((u.kind == tykind.TY_SLICE
|| u.kind == tykind.TY_STR)
&& a.kind == nkind.N_IDENT) {
let lc: *local = localfindnode(c, a.str);
if (lc != nil) {
emitline("\tMOVQ\t");
emitoff((lc.off + 8): i64);
emitline("(BP), AX\n");
return;
};
};
if (u.kind == tykind.TY_ARRAY) {
emitline("\tMOVQ\t$");
emitint(u.alen: i64);
emitline(", AX\n");
return;
};
};
// Fallback: evaluate the argument and let AX carry
// whatever the value-load shape yields. Mirrors
// cstage's `cgexpr(c, a, locals)` fallthrough.
cgexpr(c, a);
return;
};
};
};
};