lib: port errors.errno + os errno/strerror sys-layer (#6)

Hare-faithful port of errors::errno (ref/hare/errors/{rt,common,opaque}.ha): the 13 named common error conditions, opaque_data/opaque_ (the type-erased tail whose strerror fn-ptr defers to os.strerror), and errno(os.errno) error mapping the ~12 mapped errnos to named conditions and wrapping the unmapped tail in opaque_. The raw errno type (!i32, kernel-int width, distinct from oserror's !i64 negative raw return), the E* constants, and the strerror message table live in lib/os: ww folds Hare's sys role into os, so os is the import floor that lib/io and lib/errors build on -- documented in lib/CLAUDE.md (os never imports io or errors). errors.error is explicitly enumerated, matching Hare; the ...errors::error spread is only io.error's (blocked by #199b). Prereq for post-eFinal #5's faithful io error mapping; retires the nomem-collapse interim. Adds errnotest (mapping / opaque-tail / strerror) + test/wcc/902_errno_run. Landing required two wwstage cgen fixes (#9 struct-variant-large-union return, #11 deref-store alias narrow). Divergences cited at-site: bare-type-name return -> let+return; switch fall-through vs Hare's exhaustiveness-only default; opaque_ const dropped.
This commit is contained in:
2026-05-30 05:58:06 +09:00
parent 0eb3465919
commit fc9b486fb4
13 changed files with 905 additions and 39 deletions

View File

@@ -13,7 +13,6 @@ static const char *modules[] = {
"lib/types/types.ww",
"lib/ascii/ascii.ww",
"lib/io/io.ww",
"lib/errors/errors.ww",
"lib/strconv/strconv.ww",
"lib/sort/sort.ww",
"lib/path/path.ww",
@@ -30,19 +29,21 @@ static const char *modules[] = {
"lib/math/random/random.ww",
"lib/time/time.ww",
"lib/c/libc/libc.ww",
/* lib/bufio/bufio.ww, lib/bytes/bytes.ww, lib/fmt/fmt.ww,
* lib/os/os.ww, and lib/strings/strings.ww moved off this list:
* each has cross-module type refs that only resolve once the
* driver concatenates `use`d modules. bufio / fmt graduated to
* io.stream-based sinks (io.stream = *io.vtable, io.eof, io.error); lib/os
* carries time.instant in filestat post-Commit B;
* lib/strings.iterator + lib/strings.next reference utf8.decoder
* / utf8.done; lib/bytes.tokenize references os.assert +
* types.I64_MAX/MIN per ref/hare/bytes/tokenize.ha:23-24,42-43.
* Coverage lives at lib/bufio/bufiotest.ww + lib/bytes/bytestest.ww
* + lib/fmt/fmttest.ww + lib/os/stattest.ww +
* lib/strings/stringstest.ww (wired at 998_bufio_run.c,
* 967_bytes_run.c, 970_fmt_run.c, 976_stat_run.c,
/* lib/bufio/bufio.ww, lib/bytes/bytes.ww, lib/errors/errors.ww,
* lib/fmt/fmt.ww, lib/os/os.ww, and lib/strings/strings.ww moved
* off this list: each has cross-module type refs that only resolve
* once the driver concatenates `use`d modules. bufio / fmt
* graduated to io.stream-based sinks (io.stream = *io.vtable,
* io.eof, io.error); lib/os carries time.instant in filestat
* post-Commit B; lib/errors.errno references os.errno / os.E* /
* os.strerror (ww folds Hare's sys role into os); lib/strings.iterator
* + lib/strings.next reference utf8.decoder / utf8.done;
* lib/bytes.tokenize references os.assert + types.I64_MAX/MIN per
* ref/hare/bytes/tokenize.ha:23-24,42-43. Coverage lives at
* lib/bufio/bufiotest.ww + lib/bytes/bytestest.ww +
* lib/errors/errnotest.ww + lib/fmt/fmttest.ww + lib/os/stattest.ww
* + lib/strings/stringstest.ww (wired at 998_bufio_run.c,
* 967_bytes_run.c, 902_errno_run.c, 970_fmt_run.c, 976_stat_run.c,
* 966_strings_run.c), plus the bufio.scanline / fmt.println e2e
* rows in test/wcc/700_e2e.c. */
"lib/net/net.ww",

51
test/wcc/902_errno_run.c Normal file
View File

@@ -0,0 +1,51 @@
/*
* 902_errno_run — execute the lib/errors errno @test fixture under the
* C-side `ww run` driver and assert exit 0.
*
* Sibling to 982_getopt_run / 980_memio_run. errnotest.ww carries its
* own `export fn main()` that drives the @test fns and signals which
* case failed via the exit code, so this file is a thin wrapper — no
* @test scanning, no synthetic main generation.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
static int
runwait(const char *cmd)
{
int rc = system(cmd);
if (rc == -1) return -1;
if (WIFEXITED(rc)) return WEXITSTATUS(rc);
return 1;
}
int
main(void)
{
const char *bin = getenv("BIN");
if (!bin) bin = "out/bin";
char absbin[1024];
if (bin[0] != '/') {
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin);
bin = absbin;
}
char cwd[1024];
if (getcwd(cwd, sizeof cwd) == NULL) return 1;
const char *src = "lib/errors/errnotest.ww";
char path[1024], cmd[2048];
snprintf(path, sizeof path, "%s/%s", cwd, src);
snprintf(cmd, sizeof cmd, "%s/ww run %s", bin, path);
(void)cwd;
int rc = runwait(cmd);
if (rc != 0) {
fprintf(stderr, "errno_run FAIL: %s exited %d\n", src, rc);
return 1;
}
printf("errno_run: %s ok\n", src);
return 0;
}