lib: split io empty stream into empty.ww per ref/hare/io/empty.ha

Pure file-boundary move of lib/io/stream.ww's single 'empty stream'
banner section (_empty_read, _empty_write, _empty_vt, empty) into
lib/io/empty.ww, mirroring ref/hare/io/empty.ha. No code, name,
signature, or behavior change. Comment-only adjustments: the banner
line is deleted (the file name carries it); the moved block's
'Lives in stream.ww' self-reference now says empty.ww; stream.ww's
head drops its empty bullet (content duplicated by empty.ww's own
comments); io.ww's ownership map gains the empty.ww line; types.ww's
'three files' count becomes four. empty.ww needs no imports (package
io types only).

Makefile: lib/io/empty.ww added beside every lib/io/stream.ww
occurrence (WWFIXTURE_SRC line 75; w6c_ww/wwdump_ww bootstrap prereq
lists at lines 184/204). lib/io has no _test.ww, so no LIBRARY_TESTS
or byteid-roster change; byteid coverage rides the bootstrap gates.

Validation: out/bin/w6c lib/io/io.ww (standalone contract) exit 0;
importer tests green: bufio 26, memio 11, log 11, getopt 12 (calls
io.empty), fmt 49.
This commit is contained in:
2026-08-08 16:46:48 +09:00
parent 34101508be
commit e5379848de
5 changed files with 41 additions and 44 deletions

View File

@@ -72,7 +72,7 @@ WWFIXTURE_SRC = cmd/wwfixture/wwfixture.ww \
lib/encoding/hex/hex.ww lib/encoding/utf8/utf8.ww \ lib/encoding/hex/hex.ww lib/encoding/utf8/utf8.ww \
lib/endian/endian.ww lib/errors/errors.ww lib/fmt/fmt.ww \ lib/endian/endian.ww lib/errors/errors.ww lib/fmt/fmt.ww \
lib/fnmatch/fnmatch.ww lib/hash/hash.ww \ lib/fnmatch/fnmatch.ww lib/hash/hash.ww \
lib/io/io.ww lib/io/stream.ww lib/io/types.ww \ lib/io/empty.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww \
lib/math/floats.ww lib/math/math.ww lib/memio/memio.ww \ lib/math/floats.ww lib/math/math.ww lib/memio/memio.ww \
lib/os/os.ww lib/rt/malloc.ww \ lib/os/os.ww lib/rt/malloc.ww \
lib/strconv/decimal.ww lib/strconv/ftos.ww \ lib/strconv/decimal.ww lib/strconv/ftos.ww \
@@ -181,7 +181,7 @@ $(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \ selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \ selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
selfhost/cmd/wcc/cgendecl.ww \ selfhost/cmd/wcc/cgendecl.ww \
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strconv/stof.ww lib/strconv/ftos_data.ww lib/strconv/ftos.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/errors/errors.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww lib/math/floats.ww lib/math/math.ww lib/memio/memio.ww lib/types/types.ww \ lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strconv/stof.ww lib/strconv/ftos_data.ww lib/strconv/ftos.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/errors/errors.ww lib/io/empty.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww lib/math/floats.ww lib/math/math.ww lib/memio/memio.ww lib/types/types.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN) $(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(WWBUILD)/wwdump_ww @mkdir -p $(WWBUILD)/wwdump_ww
@@ -201,7 +201,7 @@ $(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \ selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgenexpr.ww \
selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \ selfhost/cmd/wcc/cgenstmt.ww selfhost/cmd/wcc/cgenutil.ww \
selfhost/cmd/wcc/cgendecl.ww \ selfhost/cmd/wcc/cgendecl.ww \
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strconv/stof.ww lib/strconv/ftos_data.ww lib/strconv/ftos.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/errors/errors.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww lib/math/floats.ww lib/math/math.ww lib/memio/memio.ww lib/types/types.ww \ lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strconv/stof.ww lib/strconv/ftos_data.ww lib/strconv/ftos.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/errors/errors.ww lib/io/empty.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww lib/math/floats.ww lib/math/math.ww lib/memio/memio.ww lib/types/types.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN) $(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(WWBUILD)/w6c_ww @mkdir -p $(WWBUILD)/w6c_ww

33
lib/io/empty.ww Normal file
View File

@@ -0,0 +1,33 @@
// ref/hare/io/empty.ha:4-17.
//
// Hare uses `const _empty_vt: vtable = { ... }` + `const empty: *stream`.
// ww can't const-init a vtable struct with fn-ptr fields (#118), so the
// vtable is a module-level `let` and [[empty]] is a function that wires
// the fn-ptr slots on every call and returns the stream pointer.
// Single-assignment on the same words: idempotent under re-entry.
// Lives in empty.ww (not io.ww) so io.ww stays standalone without
// referencing the cross-file vtable/reader/writer types.
package io;
fn _empty_read(s: stream, buf: []u8) (size | eof | error) = {
let e: eof;
return e;
};
fn _empty_write(s: stream, buf: []u8) (size | error) = {
return buf.len: size;
};
let _empty_vt: vtable;
// empty — a stream that discards all writes (returning their size) and
// returns EOF on every read. Mirrors ref/hare/io/empty.ha:13.
// #118: const vtable init with fn-ptr fields is unwired (emit_struct_data
// needs a two-pass reloc extension, node_fnptr_sym reusable). Using a
// mutable let + per-call wiring until #118 lands.
export fn empty() stream = {
_empty_vt.reader = (&_empty_read): *reader;
_empty_vt.writer = (&_empty_write): *writer;
return &_empty_vt;
};

View File

@@ -6,9 +6,10 @@
// tagged unions instead of errno-style integer sentinels. // tagged unions instead of errno-style integer sentinels.
// //
// This file owns the eof / underread variant tags; lib/io/stream.ww // This file owns the eof / underread variant tags; lib/io/stream.ww
// owns the `vtable` + `stream` + read/write/close dispatchers and the // owns the `vtable` + `stream` + read/write/close dispatchers,
// [[empty]] singleton, and lib/io/types.ww owns the error union, // lib/io/empty.ww owns the [[empty]] singleton, and lib/io/types.ww
// mode/whence enums, and the reader/writer/closer fn-type aliases. // owns the error union, mode/whence enums, and the reader/writer/
// closer fn-type aliases.
// #94 fold-eFinal collapsed the pre-vtable `stream` struct + `closed` // #94 fold-eFinal collapsed the pre-vtable `stream` struct + `closed`
// tag into the single vtable surface; the dispatchers are read/write/ // tag into the single vtable surface; the dispatchers are read/write/
// close (over `stream`), final over `handle` at io fold-2 (#5). // close (over `stream`), final over `handle` at io fold-2 (#5).

View File

@@ -21,9 +21,6 @@
// public `read`/`write`/`close`; ww has no `handle` yet // public `read`/`write`/`close`; ww has no `handle` yet
// (io fold-2, #5), so the dispatchers ARE the public // (io fold-2, #5), so the dispatchers ARE the public
// surface and grow the `handle` match when #5 lands. // surface and grow the `handle` match when #5 lands.
// empty the discard+EOF stream (ref/hare/io/empty.ha:13). Lives
// here rather than io.ww so io.ww remains a standalone
// frontend input with no cross-file type references.
// //
// Deferrals (drew-signed): `seeker` lands with io fold-2 (#5) once `off` // Deferrals (drew-signed): `seeker` lands with io fold-2 (#5) once `off`
// + `whence` plug into the signature. Hare's `?`-propagating `close` // + `whence` plug into the signature. Hare's `?`-propagating `close`
@@ -186,37 +183,3 @@ export fn seek(h: handle, off: off, w: whence) (off | error) = {
export fn tell(h: handle) (off | error) = { export fn tell(h: handle) (off | error) = {
return seek(h, 0, whence.CUR); return seek(h, 0, whence.CUR);
}; };
// ---- empty stream -------------------------------------------------------
//
// ref/hare/io/empty.ha:4-17.
//
// Hare uses `const _empty_vt: vtable = { ... }` + `const empty: *stream`.
// ww can't const-init a vtable struct with fn-ptr fields (#118), so the
// vtable is a module-level `let` and [[empty]] is a function that wires
// the fn-ptr slots on every call and returns the stream pointer.
// Single-assignment on the same words: idempotent under re-entry.
// Lives in stream.ww (not io.ww) so io.ww stays standalone without
// referencing the cross-file vtable/reader/writer types.
fn _empty_read(s: stream, buf: []u8) (size | eof | error) = {
let e: eof;
return e;
};
fn _empty_write(s: stream, buf: []u8) (size | error) = {
return buf.len: size;
};
let _empty_vt: vtable;
// empty — a stream that discards all writes (returning their size) and
// returns EOF on every read. Mirrors ref/hare/io/empty.ha:13.
// #118: const vtable init with fn-ptr fields is unwired (emit_struct_data
// needs a two-pass reloc extension, node_fnptr_sym reusable). Using a
// mutable let + per-call wiring until #118 lands.
export fn empty() stream = {
_empty_vt.reader = (&_empty_read): *reader;
_empty_vt.writer = (&_empty_write): *writer;
return &_empty_vt;
};

View File

@@ -6,7 +6,7 @@
// the same: lib/io/io.ww owns the `eof` and `underread` tags; // the same: lib/io/io.ww owns the `eof` and `underread` tags;
// lib/io/stream.ww owns the vtable surface (`vtable`, `stream`, // lib/io/stream.ww owns the vtable surface (`vtable`, `stream`,
// `read`/`write`/`close` dispatch); this file owns the surrounding // `read`/`write`/`close` dispatch); this file owns the surrounding
// port. The three files share `package io;` so cross-file refs // port. The four files share `package io;` so cross-file refs
// resolve via the dir-enum concat order (io.ww < stream.ww < types.ww // resolve via the dir-enum concat order (io.ww < stream.ww < types.ww
// — `stream` lands before the reader/writer/closer aliases below). // — `stream` lands before the reader/writer/closer aliases below).
// //