lib/io: port ref/hare/io/stream.ha vtable surface (#94 fold-e1)
Additive: keeps lib/io/io.ww's pre-vtable `stream` struct + `read`/`write`/`close` wrappers (fold-e2-eN migrates the legacy surface to vtable-backed implementations and retires it). lib/io/stream.ww — vtable struct (reader/writer/closer slots, spelled `(*T | void)` per #192 — ww parser rejects `nullable *T`), vstream = *vtable, and the st_read/st_write/st_close dispatchers per ref/hare/io/stream.ha:33-68. Void-arm `return e;` chains two direct widens: concrete `errors.unsupported` → `error` (#199 α) then `error` → (size|eof|error) (#205 NAMED-variant nominal at tagged→tagged subset). Hare's `?`-propagating st_close collapses to a direct `return (*c)(s);` because #173 is still open; the surface stays Hare-shaped. lib/io/types.ww — retarget reader/writer/closer fn-aliases from *stream to vstream. Extend `error` union to include `errors.unsupported` explicitly (no spread — per ken's #204-block the wrapper-vs-flatten layout asymmetry would mis-widen; the deferred fix is filed as #199b layout-extension). test/wcc/775_io_vtable_run.c — 7-row sentinel: reader/writer/ closer × {set, void} happy paths + branched-callee runtime. Rows verify the call runs + the constant exit; the void-arm rows do NOT inspect the resulting variant tag (deferred #199b wrapped-slot tag-remap mis-routes to dst tag 0). Cstage and wwstage emit byte-identical asm on every row. test/wcc/768_io_types_run.c — track the alias retarget; rows now build a vtable, pass `&vt` (= vstream), and call through the fn-VALUE param shape. Combined.ww regen for w6c + wwdump per #110: lib/errors lands transitively via the new `import errors;` in types.ww. Sibling filed inline (NOT fixed): the checker rejects bare `&fn_name` / `let p: *alias = &fn` assignment to a `(*alias | void)` field — the structural `*fn(...)` value isn't accepted as the `*alias` NAMED variant. Both stages reject. Probes route around via explicit `(&fn): *io.reader` cast at each vtable-field assignment.
This commit is contained in:
95
lib/io/stream.ww
Normal file
95
lib/io/stream.ww
Normal file
@@ -0,0 +1,95 @@
|
||||
// stream — Hare-shaped vtable port. Project #94 fold-e1.
|
||||
//
|
||||
// Adds the additive vtable surface alongside lib/io/io.ww's pre-vtable
|
||||
// stream struct + read/write/close wrappers (which fold-e2-eN migrate
|
||||
// to vtable-backed implementations and then retire). Three exports:
|
||||
//
|
||||
// vtable a struct of optional fn-pointer slots — reader/writer/
|
||||
// closer per ref/hare/io/stream.ha:36-42. Hare spells the
|
||||
// nullable as `nullable *T`; ww parser rejects that
|
||||
// spelling (#192), so each slot is a `(*T | void)` tagged
|
||||
// union (Plan-9-lean per the Nullable kept ruling; opt-in
|
||||
// at optionality boundaries only).
|
||||
// vstream `*vtable` alias matching Hare's `stream = *vtable`
|
||||
// (ref/hare/io/stream.ha:33). Named `vstream` rather than
|
||||
// `stream` because lib/io/io.ww still owns the legacy
|
||||
// `stream` struct name until fold-eN collapses both.
|
||||
// st_read /
|
||||
// st_write /
|
||||
// st_close the three dispatchers per ref/hare/io/stream.ha:44-68.
|
||||
// Each `match`es the matching vtable slot, returns
|
||||
// `errors.unsupported` (widened twice) when the slot is
|
||||
// void, otherwise calls through the fn pointer.
|
||||
//
|
||||
// Fold-e1 cgen/checker dependencies (all closed at HEAD): #191
|
||||
// (N_DOT on aliased-ptr receiver — `s.reader` resolves through the
|
||||
// `vstream = *vtable` alias), #198 (`is` on cross-module variant
|
||||
// tag), #199 α (concrete→tagged widen via NAMED-variant nominal
|
||||
// match, used by `let e: error = u;`), #200 (`as` payload-extract),
|
||||
// #201 (return-of-tagged-call forwards instead of rewinds), #205
|
||||
// (tagged→tagged subset accepts NAMED-variant nominal match, used
|
||||
// by `return e;` where ret type contains `error` as a direct
|
||||
// variant). Two direct widens compose for the void-arm `return`:
|
||||
// concrete `errors.unsupported` → tagged `error` via #199 α, then
|
||||
// tagged `error` → tagged `(size | eof | error)` via #205.
|
||||
//
|
||||
// Deferrals (drew-signed): `seeker` lands with fold-e2 once `off`
|
||||
// + `whence` plug into the signature; Hare's `?`-propagating
|
||||
// `st_close` body (`c(s)?;`) collapses to a direct `return (*c)(s);`
|
||||
// here because #173 (TRY-on-tagged-return both-stages broken) is
|
||||
// still open — the dispatcher's surface stays Hare-shaped, only the
|
||||
// internal try-prop is omitted.
|
||||
|
||||
package io;
|
||||
|
||||
// ref/hare/io/stream.ha:36-42. Nullable spelling per #192 (ww parser
|
||||
// rejects `nullable *T`); each slot is `(*T | void)`.
|
||||
export type vtable = struct {
|
||||
reader: (*reader | void),
|
||||
writer: (*writer | void),
|
||||
closer: (*closer | void),
|
||||
};
|
||||
|
||||
// ref/hare/io/stream.ha:33. `vstream` not `stream` while io.ww still
|
||||
// owns the legacy `stream` struct name.
|
||||
export type vstream = *vtable;
|
||||
|
||||
// ref/hare/io/stream.ha:44-50. The void-arm `return e;` chains two
|
||||
// direct widens: `errors.unsupported → error` via #199 α, then
|
||||
// `error → (size | eof | error)` via #205. The call-arm spells the
|
||||
// fn-ptr call explicitly per #193 (ww requires `(*r)(args)` rather
|
||||
// than implicit `r(args)`).
|
||||
export fn st_read(s: vstream, buf: []u8) (size | eof | error) = {
|
||||
match (s.reader) {
|
||||
case void => {
|
||||
let u: errors.unsupported;
|
||||
let e: error = u;
|
||||
return e;
|
||||
};
|
||||
case let r: *reader => return (*r)(s, buf);
|
||||
};
|
||||
};
|
||||
|
||||
// ref/hare/io/stream.ha:53-59.
|
||||
export fn st_write(s: vstream, buf: []u8) (size | error) = {
|
||||
match (s.writer) {
|
||||
case void => {
|
||||
let u: errors.unsupported;
|
||||
let e: error = u;
|
||||
return e;
|
||||
};
|
||||
case let w: *writer => return (*w)(s, buf);
|
||||
};
|
||||
};
|
||||
|
||||
// ref/hare/io/stream.ha:62-68. Hare propagates the close error via
|
||||
// `c(s)?;` then falls through to the void arm; ww collapses to a
|
||||
// direct return because #173 (TRY-on-tagged-return) is still open.
|
||||
// The surface (void | error) matches; only the internal try-prop
|
||||
// is omitted.
|
||||
export fn st_close(s: vstream) (void | error) = {
|
||||
match (s.closer) {
|
||||
case void => return void;
|
||||
case let c: *closer => return (*c)(s);
|
||||
};
|
||||
};
|
||||
@@ -1,18 +1,25 @@
|
||||
// types — error union, mode/whence enums, reader/writer/closer
|
||||
// fn-type aliases. Project #94 fold-1 step (d) (drew Fold D).
|
||||
// fn-type aliases. Project #94 fold-1 step (d) (drew Fold D); the
|
||||
// fn-aliases re-targeted from *stream → vstream as part of fold-e1
|
||||
// (vtable port in stream.ww).
|
||||
//
|
||||
// Hare splits the io module across stream.ha + types.ha and ww does
|
||||
// the same: lib/io/io.ww owns the (pre-vtable) `stream`, `eof`, and
|
||||
// `underread` shapes; this file owns the surrounding port. Both
|
||||
// files share `package io;` so forward refs (e.g. reader → stream)
|
||||
// resolve via the dir-enum concat order.
|
||||
// `underread` shapes; lib/io/stream.ww owns the Hare vtable port
|
||||
// (`vtable`, `vstream`, `st_read`/`st_write`/`st_close` dispatch);
|
||||
// this file owns the surrounding port. The three files share
|
||||
// `package io;` so cross-file refs resolve via the dir-enum concat
|
||||
// order (io.ww < stream.ww < types.ww — `vstream` lands before the
|
||||
// reader/writer/closer aliases below).
|
||||
//
|
||||
// Deferrals (drew-signed): `handle`, `seeker`, `copier`, `strerror`
|
||||
// land with fold-e (need the `handle` sum). Hare's `EOF = done`
|
||||
// land with fold-e2+ (need the `handle` sum). Hare's `EOF = done`
|
||||
// stays as `io.eof` until the `done` singleton ships (#93).
|
||||
|
||||
package io;
|
||||
|
||||
import errors;
|
||||
|
||||
// ref/hare/io/types.ha:29-34. RDWR is spelled `3` rather than Hare's
|
||||
// `READ | WRITE` because the ww parser doesn't fold expressions in
|
||||
// enum value positions; the value SSoT stays the same bitfield.
|
||||
@@ -24,7 +31,7 @@ export type mode = enum u8 {
|
||||
};
|
||||
|
||||
// ref/hare/io/types.ha:37-41. Hare leaves the underlying implicit;
|
||||
// ww requires one. i32 matches the off type that fold-e will plug
|
||||
// ww requires one. i32 matches the off type that fold-e2 will plug
|
||||
// into the seeker signature.
|
||||
export type whence = enum i32 {
|
||||
SET = 0,
|
||||
@@ -32,20 +39,24 @@ export type whence = enum i32 {
|
||||
END = 2,
|
||||
};
|
||||
|
||||
// ref/hare/io/types.ha:11 spreads `errors::error` into the union;
|
||||
// lib/errors isn't ported yet, so the union carries only the tags
|
||||
// observable in this fold — `underread` (from io.ww) and the
|
||||
// predeclared `nomem` (#29, type.c:72 / check.ww:78).
|
||||
export type error = !(underread | nomem);
|
||||
// ref/hare/io/types.ha:11 spreads `...errors::error` into the union;
|
||||
// ww enumerates the tags explicitly (ken's #204-block — spread of an
|
||||
// errors-side tagged into this union triggers a wrapper-vs-flatten
|
||||
// layout mismatch; #199b layout-extension is the deferred fix). The
|
||||
// st_read/st_write dispatchers in stream.ww return
|
||||
// `errors.unsupported` when the matching vtable slot is unset, so the
|
||||
// variant lands here directly.
|
||||
export type error = !(errors.unsupported | underread | nomem);
|
||||
|
||||
// ref/hare/io/types.ha:46. `eof` (not Hare's `done`) per the io.ww:8
|
||||
// rationale; lifts to `done` with #93. `*stream` forward-refs the
|
||||
// pre-vtable struct in io.ww — same cross-file pattern Hare uses.
|
||||
export type reader = fn(s: *stream, buf: []u8) (size | eof | error);
|
||||
// rationale; lifts to `done` with #93. `vstream` forward-refs the
|
||||
// `*vtable` alias in stream.ww — the dispatcher receives the vtable
|
||||
// pointer directly (Hare's stream.ha:33 + types.ha:46 collapse).
|
||||
export type reader = fn(s: vstream, buf: []u8) (size | eof | error);
|
||||
|
||||
// ref/hare/io/types.ha:51. No `const` qualifier — ww has none, and
|
||||
// lib/io/io.ww:30 + lib/sort/sort.ww:18 drop it the same way.
|
||||
export type writer = fn(s: *stream, buf: []u8) (size | error);
|
||||
export type writer = fn(s: vstream, buf: []u8) (size | error);
|
||||
|
||||
// ref/hare/io/types.ha:55.
|
||||
export type closer = fn(s: *stream) (void | error);
|
||||
export type closer = fn(s: vstream) (void | error);
|
||||
|
||||
Reference in New Issue
Block a user