lib/log: add Option C parallel vstream API (#94 fold-e5)

Last per-caller migration before fold-eFinal (#50). Adds the 10 _v
variants of OLD log.ww's surface (new_v / lprintln_v / println_v /
lprintfln_v / printfln_v / lfatal_v / fatal_v / lfatalf_v / fatalf_v /
setlogger_v) alongside a vlogger vtable + vstdlogger over io.vstream.
Default sink is a module-static stderrsink_ctx_g with vt FIRST field for
the intrusive vstream cast and fd=2 — only scalars/ptrs beyond vt per
ken's mandate, no nested aggregates that would bite #18, no f32 per
#165b. Zero-init at link time per #129 A.2/A.3 SSoT; ensureinit_v wires
vt.reader / vt.writer / fd lazily on first dispatch (mirror of OLD
ensureinit at log.ww:122 + lib/temp's rnginit pattern).

OLD lib/log/log.ww UNCHANGED. fold-eFinal (#50) atomically retires the
OLD logger / stdlogger / globals + the pre-vtable stderrsink and drops
the `_v` suffix wholesale to match Hare's bare names.

Two `export` bumps on lib/fmt/vstream.ww (vfprint, vfprintf) so log's
stdprintln_v / stdprintfln_v dispatch through the existing vstream-side
formatters; additive exposure, eFinal collapses fprint over the unified
surface.

Bootstrap-embed check: log is NOT in any selfhost/cmd/*/main.combined.ww
(grep `package log\|import log` returns empty pre-impl). The fmt
vstream.ww changes are also non-embedded. 990-997 byte-id gates stay
green by virtue of log being test-only and the touched fmt symbols not
being embedded.

Probe wcc/779_log_vstream_run pins the additive surface across 4 rows
(println_v_default_stderr / printfln_v_default_stderr /
lprintln_v_custom_sink / branched_lprintln_v) cstage-only per #209
(wwstage formattable match-arm bail; bites OLD log.println identically).
Byte-id graduates when #209 lands.

Cite refs: ref/hare/log/{logger,funcs,global,silent}.ha; drew acks on
module-static stderrsink_ctx + intrusive vt + 10-fn _v parity; ken
mandates on bootstrap byte-id mechanical + simple-ctx + #129 static-init.

Sibling tasks parked (filed, NOT fixed): eFinal #50; #206 (2 cast sites
at ensureinit_v); #173 (stderrwrite_v constructs nomem + widens to
io.error); #209 (cstage-only).
This commit is contained in:
2026-05-29 11:01:39 +09:00
parent c62e8e5560
commit d87ee01cdf
4 changed files with 698 additions and 4 deletions

View File

@@ -170,8 +170,10 @@ fn vformatfield(vs: io.vstream, f: field) (size | io.error) = {
// vfprint — vstream-side fprint. Mirror of fmt.fprint (fmt.ww:177).
// Per-arg loop with a space separator; returns total bytes written
// or the first io.error.
fn vfprint(vs: io.vstream, args: formattable...) (size | io.error) = {
// or the first io.error. Exported so lib/log's V API (fold-e5) can
// dispatch through it; eFinal (#50) collapses fprint over the unified
// surface.
export fn vfprint(vs: io.vstream, args: formattable...) (size | io.error) = {
let total: size = 0;
let i: i32 = 0;
for (i < args.len) {
@@ -196,8 +198,9 @@ fn vfprint(vs: io.vstream, args: formattable...) (size | io.error) = {
// {n}-placeholder parser routed through vformatfield + vputbytes
// instead of fmt.formatfield + fmt.putbytes; the placeholder language
// (incl. `{N:mods}` modifier subset) is identical — scandigits /
// scanmods / modsinit reused directly from fmt.ww.
fn vfprintf(vs: io.vstream, fmt: str, args: field...) (size | io.error) = {
// scanmods / modsinit reused directly from fmt.ww. Exported (same
// rationale as vfprint above) so lib/log's V API dispatches through it.
export fn vfprintf(vs: io.vstream, fmt: str, args: field...) (size | io.error) = {
let total: size = 0;
let i: i32 = 0;
let nextimpl: i32 = 0;