Files
ww/rt/ensure.ww
Hojun-Cho 7b9488706b parse: enforce strict-package — reject package-less files (#24a)
Flip the soft-default to a hard "missing package clause" error symmetrically in
both stages (cmd/wcc/parse.c + lib/ww/syntax/parse.ww): the first real decl of a
primary section with empty pathmod/resetmod and no seen clause is now rejected.
Closes the documented soft-default divergence (the 63-wrapper carve-out).

The gate flip can't be split from the migration it breaks, so this is one atomic
commit: ~80 test/wcc wrappers gain `package main;` via a shared wwtestpkg.h
helper, 6 data fixtures plus 17 asm-grep assertions update for the bare->main.<leaf>
root-helper mangle shift, and rt/ declares `package rt;` with @symbol pinning the
bare rt_ensure/rt_malloc linker names.

Root mangling narrows: the executable entry `main` stays bare (existing
carve-out), but root helper symbols become main.X. The #84 cluster is rewritten
to assert main.run distinct from aa.run/test.run; its cgen fix and bare machinery
are retained — still load-bearing for package-less module-reset deps. New
table-driven test 782_strict_package.c (6 rows, both stages).

Retiring //ww:module-reset is deferred to #24b: it is load-bearing (clears the
.wwi pathmod so the body's package clause asserts), not a vestige; fusing its
removal here would be a silent mismatch.

All byte-id gates green; full make test reports "all 335 tests passed".
2026-06-29 03:55:26 +09:00

56 lines
1.9 KiB
Plaintext

// rt/ensure.ww — slice growth helper, archived into libwwrt.a.
//
// Companion to the `append(s, v)` builtin. The compiler lowers
// `append(s, v)` to:
//
// ; push v
// ; s.len += 1
// ; CALL rt_ensure(&s, sizeof(elem))
// ; ; ensure may have realloc'd, so re-read s.ptr
// ; pop v
// ; *(s.ptr + (s.len - 1) * elem_size) = v
//
// One helper handles every element width via the membsz parameter —
// no per-type wrapper functions (appendu8 / appendi64) needed.
//
// User code never `use`s this — the symbol is resolved at link time
// from libwwrt.a, like rt_malloc and rt_streq. rt/ensure.ww is compiled
// standalone via `w6c rt/ensure.ww` (not through the driver). Under
// strict-package (#24a) it declares `package rt;` (matching its
// directory) like every primary section; the link-resolved name is
// pinned bare via @symbol on the export (the clause would otherwise
// mangle it to rt.rt_ensure).
package rt;
@symbol("rt_malloc") fn malloc(n: u64) *void;
// Mirrors ww's []T header layout: 24 bytes with 8-byte slots.
// ww's source uses i32 for len/cap but the compiler stores them in
// 8-byte slots; declaring as i64 here keeps the field offsets right
// for this polymorphic alias.
type slice = struct {
ptr: *u8,
len: i64,
cap: i64,
};
@symbol("rt_ensure") export fn rt_ensure(s: *slice, membsz: u64) void = {
if (s.cap >= s.len) { return; };
let nc: i64 = s.cap * 2i64;
if (nc < 8i64) { nc = 8i64; };
for (nc < s.len) { nc *= 2i64; };
// Task #30 (commit 3) upgrades to nullable *void + null-check.
// For now, rt_malloc returns plain *void; OOM faults on deref.
let np: *u8 = malloc((nc: u64) * membsz): *u8;
let n: u64 = (s.cap: u64) * membsz;
let i: u64 = 0u64;
for (i < n) {
np[i] = s.ptr[i];
i += 1u64;
};
// No free: the bump allocator (rt/malloc.ww) can't reclaim a
// mid-chunk region; the old buffer leaks until process exit. (#8)
s.ptr = np;
s.cap = nc;
};