Commit Graph

2 Commits

Author SHA1 Message Date
df287846c5 lib/fmt: port V-side fprintln/fprintfln/bsprintf/asprintf (#94 fold-e7)
V had vfprint / vfprintf but no compositions over them, so callers
needing the newline / printf-newline / bounded-buffer / heap-grow
shapes still routed through the OLD io.stream-shaped fprintln /
fprintfln / bsprintf / asprintf. Port the four compositions into
vstream.ww as the v* twins: vfprintln + vfprintfln chain a
"\n" vputbytes after the underlying primitive; vbsprintf threads a
caller buffer through memio.fixed_vstream and returns the prefix view;
vasprintf grows through memio.dynamic_vstream and shrink-copies to a
tight allocation before io.st_close.

Bundles the two memio enablers (fixed_string / dynamic_string in
lib/memio/vstream.ww) that vbsprintf / vasprintf depend on directly,
per drew-approved exception to one-class-one-commit
(feedback_refactor_routing_same_class_drops applies — helpers are
direct prereqs, not unrelated churn; the bus-routing site lives in
v* fmt code, not in memio). They mirror OLD memio.string (memio.ww:
102) over the per-flavour *fixed_ctx / *dynamic_ctx intrusive cast,
same shape as the read/write callback split at memio/vstream.ww:144.

Mirror sites:
  vfprintln    fmt.ww:240 fprintln          ref/hare/fmt/wrappers.ha:48
  vfprintfln   fmt.ww:740 fprintfln         ref/hare/fmt/wrappers.ha:69
  vbsprintf    fmt.ww:839 bsprintf          ref/hare/fmt/wrappers.ha:42
  vasprintf    fmt.ww:873 asprintf          ref/hare/fmt/wrappers.ha:29

Divergence vs Hare on vbsprintf: Hare returns `(const str | nomem)`;
ww collapses to `(str | io.error)` so the underlying vfprintf io.error
arm stays uniform. The fixed_vstream nomem widens into io.error
explicitly (no `memio.fixed_vstream(buf)?`) because #173 (TRY-on-
tagged-return both-stages broken) is still open — same shape memio/
vstream.ww adopted at line 87-99 for fixed_vstream itself. vasprintf
keeps OLD's bare `str` return (no nomem variant on public surface).

ken cs==ww mechanical: additive only, both stages compile identically.
fmt is NOT embedded in any selfhost main.combined.ww (grep verified
pre-impl: zero `^package fmt;` hits in selfhost/cmd/*/main.combined.
ww). memio.vstream.ww IS embedded in w6c + wwdump combined.ww (lib/
ww/cgen.ww uses memio.dynamic for buffer growth); the two memio
helpers regen-and-commit via ww build per #110 SSoT.

test/wcc/781_fmt_vstream_compositions_run.c (cstage-only per #209): 4
rows pin all four V wrappers — fdprintln_v_run_basic (newline shape),
fdprintfln_v_run_fmt ({n}-placeholder + newline), bsprintf_v_basic
(fixed buffer + returned view + caller bytes), asprintf_v_basic
(owned heap str + os.free roundtrip). Mirror of 777/780 cstage carve-
out (#209 wwstage formattable match-arm bail). Byte-id graduates with
#209 close. 214 total tests green (was 213).
2026-05-29 12:28:12 +09:00
b842f9337b lib/memio: add Option C parallel vstream API (#94 fold-e2)
Adds lib/memio/vstream.ww with three new constructors —
fixed_vstream / dynamic_vstream / dynamicfrom_vstream — that return
io.vstream (= *io.vtable, from lib/io/stream.ww) alongside the
pre-vtable memio.fixed / dynamic / dynamicfrom shape in memio.ww.

Hare's memio::fixed/dynamic return a `stream` whose first field IS
io::stream (= *vtable); ww mirrors that intrusively with fixed_ctx
+ dynamic_ctx structs whose first field is `vt: io.vtable`. A
heap-alloc'd *fixed_ctx is castable to vstream via `&c.vt`, and
callbacks recover the outer ctx via `s: *fixed_ctx` (same pattern
as lib/bufio.stream over io.stream and lib/log.stdlogger over
logger). ptr/len/cap kept flat (memio.ww:39 SOP) to dodge the
chained-dot-through-pointer-into-slice-subfield miscompile family.

Constructor flow: alloc with vt zero-initialised via a local, then
chained `c.vt.X = …` field-assigns through the *ctx pointer.
Struct-lit init via `vt = local_vt` (with local pre-set) silently
drops tagged-union slots past the first — sibling task filed,
workaround is the alloc-then-assign route (proven byte-id between
both stages). *ctx is a plain pointer-to-struct, not an aliased
pointer, so the chained-store path doesn't hit #195.

Cast workaround per #206 at each vtable-fn-ptr-slot init (8 sites
across the 3 constructors): bare `&fn_name` does not type-check as
`(*<alias> | void)`. Same `(&fn): *io.<role>` shape that
test/wcc/775_io_vtable_run.c uses. Drops out when #206 closes.

OLD memio surface is UNCHANGED. fold-eFinal (task #50) atomically
flips the package shape: deletes OLD constructors + callbacks and
renames `_vstream` suffix off.

Probe test/wcc/776_memio_vstream_run.c: 4 rows
(fixed_read_5 / dynamic_write_grow / dynamicfrom_alt_rw /
branched_fixed) exercise both vtable flavours through the
io.st_read / st_write / st_close dispatchers. Each row drives
cs runtime + ww runtime + cs.s == ww.s byte-id — 12 fixtures
total, all green.

Pre-existing wwstage gap surfaced + documented inline: ww_ww's
combined.ww concat order trips the wwstage checker on os.tryread
/ trywrite / tryopen's bare `return r;` over `(int | oserror)`
when os is checked after rt/io. Each probe row places `import os;`
FIRST to match the ordering selfhost uses (time → os → rt → …)
where the checker resolves cleanly. Sibling task; resolves the
ordering-sensitivity in the wwstage checker drops the workaround.
2026-05-29 08:42:36 +09:00