lib: fmt fprint family over io.handle; remove the fdsink workaround (#5)

Graduates the fmt fprint family (fprint/fprintf/fprintln/fprintfln + internal putbytes/writeone/format*) from io.stream to io.handle, so a file (fd) prints directly through io.write's file-arm (commit-1). Removes the fdsink placeholder -- the fake-stream-vtable-over-os.write shim that stood in for the missing handle. The 8 stdio wrappers route over os.STD{OUT,ERR}_FILENO (new i32 filenos in lib/os; os is the import floor, so it can't hold an io.file-typed handle like Hare's os::stdout_file -- consumers cast i32 to io.file). Migrates the fd-shim sentinel tests 777/780/781 to fprint-over-handle as their headers designed, cstage-only per the pre-existing #209 (fmt is wwstage-uncompilable). Regenerates the 6 os-embedding combined.ww.
This commit is contained in:
2026-05-31 18:51:12 +09:00
parent 06c00e0e1b
commit 497f1fa0d3
15 changed files with 348 additions and 384 deletions

View File

@@ -41,10 +41,12 @@
// an imported module name; `use fmt; fn x(fmt: T)` is structurally
// ambiguous under ww's `.`-for-both rule.
//
// Sink today is an [[io.stream]] only — lib/io has no fd-backed handle
// yet (Hare's `io::handle = file | int`, io fold-2 #5). The default
// logger writes to stderr via a private fd_ctx whose write callback
// forwards to [[os.write]] on fd 2.
// Sink today is an [[io.stream]] only. io fold-2 (#5) landed
// [[io.handle]] = (io.file | io.stream) and graduated lib/fmt onto it,
// but lib/log's sink graduation is a separate follow-up; until then the
// default logger writes to stderr via a private fd-backed stream shim
// ([[stderrsink_ctx]]) whose write callback forwards to [[os.write]] on
// os.STDERR_FILENO.
//
// Cast workaround per #206-payoff (ken: KEEP the explicit casts; they
// are cgen-neutral and sidestep the #214 over-acceptance surface). The
@@ -85,7 +87,8 @@ export type stdlogger = struct {
// stderrsink_ctx — module-static state for the default logger's stderr
// sink. vt FIRST field for the intrusive io.stream→*stderrsink_ctx cast
// in stderrwrite. Mirrors fmt.fd_ctx; only scalars/ptrs beyond vt.
// in stderrwrite (the same vtable-first-field shape lib/fmt used before
// #5 graduated it onto io.handle); only scalars/ptrs beyond vt.
type stderrsink_ctx = struct {
vt: io.vtable,
fd: i32,
@@ -113,7 +116,7 @@ let initdone: i32 = 0;
fn ensureinit() void = {
if (initdone != 0) { return; };
stderrsink_ctx_g.fd = 2;
stderrsink_ctx_g.fd = os.STDERR_FILENO;
stderrsink_ctx_g.vt.reader = (&stderrread): *io.reader;
stderrsink_ctx_g.vt.writer = (&stderrwrite): *io.writer;