Commit Graph

22 Commits

Author SHA1 Message Date
fd45aedf6c os: graduate filesize/readall/writeall to (i64 | oserror)
`type oserror = i64` carries -errno (Hare's errors::errno-shaped
named-i64). The three convenience wrappers move off the i64 = -1
sentinel and onto the tagged-union surface.

Callers updated across the selfhost (wwdump, w6c, w6a, w6l, ww
driver). The slurp paths in w6c/w6a/w6l/wwdump now match on the
filesize and readall results; the ELF-emitting writeall sites in
w6a/obj.ww are wrapped through two small local helpers (`wrn` for
"wrote N bytes ok?", `wrdrop` for fire-and-forget) so the existing
11-callsite write loop stays readable.

selfhost/test/smoke.ww kept using raw os.read instead of
os.readall: the 990 cgen-match probe compiles smoke.ww standalone
(no `use` expansion), and cross-module type references like
`os.oserror` can't be resolved in that mode.

Two selfhost-side gaps surfaced and got plugged:
- lib/ww/parse/parse.ww parsetype now collapses dotted type names
  (`pkg.Type` → single N_TNAME with the joined string), mirroring C
  parsetype's dotted-path loop. Local `joindotted` helper because
  there's no arena-based string-concat in the selfhost lib yet.
- selfhost/cmd/wcc/check.ww name-resolver applies the dotted-prefix
  rule from cmd/wcc/check.c's resolve_typename: split at the last
  dot, look up the head as a `use` import, then the leaf as a type.
2026-05-12 02:25:40 +09:00
5c20c40724 io: graduate stream to tagged-union returns
read → (i32 | eof | closed), write → (i32 | closed),
close → (void | closed). `type eof = void` and `type closed = void`
are exported as named-void variants — distinct nominal tags despite
identical (zero-byte) payloads.

No existing callers exercised the eof/closed sentinels (the smoke
test mimics the stream pattern with its own local types), so the
graduation is purely API shape — no callsite churn.
2026-05-12 02:14:09 +09:00
e9c3f75fd1 lib: graduate utf8.runesz and bufio.readbyte to (i32 | void)
Both used the -1 sentinel return; both had no external callers, so
the graduation is purely the API-shape change. utf8.runesz uses void
for "rune outside legal range"; bufio.readbyte uses void for EOF
(empty buffer). The full Hare shapes ((size | invalid) and
(u8 | EOF | io::error)) are still richer than this — those richer
returns arrive when utf8 grows an explicit invalid type and bufio
wires through io::stream's error path.
2026-05-12 02:12:33 +09:00
2f385cec00 ascii: graduate digitval to (i32 | void); selfhost tagged ABI follow-on
ascii.digitval returns (i32 | void) instead of an i32 -1 sentinel.
Two callers updated to match-on the result (lib/ww/lex/lex.ww escape
parse, selfhost/test/smoke.ww probe 6).

`!` would have been more idiomatic at both call sites — both have
verified isxdigit beforehand — but the selfhost parser doesn't yet
recognize postfix `!`/`?`, so using them in bootstrap-bound code
breaks the 993/995 byte-identity gates. Match is fine for now.

Selfhost cgen follow-on for the 8-byte-rounded tagged-union ABI
(landed in 1e2f55a for the C side):
- cgenutil.slotsize: tagged size = 8 (tag) + max(payload), padded to
  8-byte multiple. Was hardcoded 24.
- cgendecl prologue: spill size/8 arg registers, not always 3.
- cgenstmt cglet tagged-call path: spill the CX value-word only when
  the slot is >16 bytes.

All three were emitting 3-register patterns appropriate to (T | str)
sized unions and overflowing the new 16-byte (i32 | void) slots.
2026-05-12 02:10:10 +09:00
4085742853 strconv: graduate to (T | invalid | overflow); add void expression
`type invalid = i32` (payload: byte index of first bad rune; mirrors
Hare's strconv::invalid = !size) and `type overflow = void` (Hare's
overflow = !void). stoi64/stou64 now return these instead of the
str-error placeholder. atoi64 dropped — lib/CLAUDE.md says graduate
in one go, don't keep both shapes around.

To produce the void variant payload, `void` is now a real
expression literal (TK_VOID kw, N_VOIDLIT). It evaluates to ty_void;
codegen emits MOVQ $0, AX. Both kinds are appended at the tail of
their enums to keep prior numeric values byte-stable for the
wwdump-diff fixtures.

check_file reorder: USE declarations are now installed in pass 1
alongside the type-decl placeholders so dotted type references
(`strconv.invalid` from a typedecl body) resolve. DEF/FN/LET silently
overwrite a USE-occupied slot — matches the old behavior where USE
silently no-op'd when a same-name fn/def existed (the conflict
manifested in selfhost main.combined.ww at `use parse;` colliding
with `export fn parse(a)`).

selfhost mirror: lib/ww/lex/tok.ww kwtab+name; lib/ww/ast.ww
N_VOIDLIT def+print; lib/ww/parse/{expr,parse}.ww TK_VOID handling;
selfhost/cmd/wcc/cgenexpr.ww N_VOIDLIT codegen.
2026-05-12 02:02:08 +09:00
1e2f55aed8 lib: graduate bytes/strings find-funcs to (i32 | void)
Replaces the -1 sentinel return on indexbyte/byteindex/rbyteindex/
index with Hare's optional-shaped tagged union. Callers `match` on
the result and bind the index from the i32 variant.

Two cgen fixes were needed first:

1. resolve_type for N_TTAGGED rounded value payload up to an 8-byte
   multiple. (i32 | void) was sized 12 — tag (8) + payload (4) —
   which made the reg-passing ABI compute size/8 = 1 word and drop
   the value word.

2. The call-arg push path special-cased struct and slice args but
   not tagged-return calls. A nested `f(g())` where g returns a
   tagged union pushed only AX (tag); the matching pop loaded a
   stale DX/SI for the value. Now pushes AX/DX[/CX] in order so
   the pop side drains tag → arg-reg[0], value(s) → arg-reg[1..].

strings.contains rewritten to match on the new tagged result. No
other callers existed in lib/ — bufio/io still use their own
shapes.
2026-05-12 01:49:00 +09:00
fa070b6d07 wcc: tagged-union foundations (never, void, flatten, exhaust)
- `never` bottom type: TY_NEVER, assignable to anything; size 0.
- Type-set normalization for N_TTAGGED in resolve_type:
  - flatten nested anonymous (A|B)|C → (A|B|C); named aliases stay
    nominal (not flattened through)
  - dedup duplicates (NAMED pointer-id; others structural)
  - drop `never` variants
  - collapse single-element set: (T|never) → T, (T|T) → T
- Match exhaustiveness: error when a variant is unhandled and no
  default arm covers it. Multi-pattern `case T1 | T2 =>` counts
  each alt.
- (T | void) optionals: bare `return;` from a tagged-union-returning
  fn emits the void variant's tag (payload undefined; void size 0).

selfhost mirrored: TY_NEVER constant + tynever in tctx + seedprim
entry; voidvariantindex helper; cgreturn bare-return handling.
2026-05-12 01:31:35 +09:00
1ac1d985f6 lib: rename stdlib surface to Hare names; add endian/math
Sweeping rename so the lib/ surface mirrors Hare's stdlib spellings.
- ascii: rune-taking predicates; ishex -> isxdigit
- bufio: rinit -> init; take1/takeline -> readbyte/readline
- bytes: indexsub -> index
- encoding/utf8: runelen -> runesz
- errors: eEOF/eShortRead/... -> eof/underread/...
- fmt: errln -> errorln; println/fprintln return i64
- os: readfull/writefull -> readall/writeall; unlink -> remove
- path: isabs -> abs; drop lastindex (now strings.rbyteindex)
- strconv: u64toa/i64toa -> u64tos/i64tos; parse64/parseu64 -> stoi64/stou64
- strings: drop len/isempty; equal -> compare; indexbyte -> byteindex; +rbyteindex
- types: drop numeric helpers (moved to math)
- new lib/endian (htonu16/ntohu16), lib/math (absi32/absi64)
- net: drop htons (use endian.htonu16)

Callers in selfhost/, lib/ww/, cmd/w6c/cgen.c, and test/wcc/700_e2e.c
updated to match.
2026-05-12 00:45:18 +09:00
dd188ca460 ww: add Hare-style is/as postfix ops on tagged unions
`e is T` returns bool (variant tag == T's index); `e as T` unwraps
to T or exit(1) on mismatch. Postfix, same precedence as `:` cast.
TK_IS / N_TYPETEST / N_TYPEASSERT appended at the tail of their
enums so every prior numeric value stays unchanged — the
990_selfhost wwdump-diff stays byte-clean.

Cgen mirrors the match-case slot-based load (tag at +0, value at
+8/+16), so an N_IDENT tagged-union local works just like a
match scrutinee. Selfhost cgen inlines the slot resolution
because the wwstage cgen drops sign bits on `*i32` output
parameters in this position.

Renames `errors.is` -> `errors.equal` (the only naming collision;
the existing comment already noted it shared shape with
strings.equal/bytes.equal).
2026-05-11 23:21:08 +09:00
c5f30f2fce ww: cgen trap batch (def-str field, chained-ptr write, scalar+str tuple ABI) 2026-05-11 20:49:21 +09:00
2ac15e4e99 lib: CLAUDE.md documents bootstrap-minimalism subset stance 2026-05-11 19:50:37 +09:00
07f4e93b2b ww: rename streq_local -> streqlocal 2026-05-11 19:50:32 +09:00
6219a47c6f ww: hare-feature batch (_, const, [_]T, ..., size/offset, assert, for-else) 2026-05-11 19:38:12 +09:00
5408160d49 rt: move slice append helpers from lib/slices/ into libwwrt.a 2026-05-11 16:56:46 +09:00
8ffe6dbee6 ww: split parse.ww into parse/{parse,expr,stmt,decl}.ww submodule 2026-05-11 16:48:58 +09:00
72dfb6ac8d ww: group lex.ww + tok.ww into lib/ww/lex/ submodule 2026-05-11 16:42:13 +09:00
97ca76d2bb selfhost: drop snake_case locals in dyn/dynout/obj + w6a + cgen + ww driver 2026-05-11 16:33:02 +09:00
177862fb29 ww: lift introspection files to lib/ww/ (ast, lex, tok, parse, typ, sym) 2026-05-11 16:17:23 +09:00
2918013c1a lib: drop snake_case from io/types/bufio/net/os exports 2026-05-11 14:15:53 +09:00
2c33228b7e ww: rename toolchain to w-prefix + hare-style build/run/test driver
Plan 9-style w-prefix on the per-arch tools, disambiguating from the
real Plan 9 6c/6a/6l in ref/plan9front/:

    cmd/wwc/      → cmd/wcc/        libwwc.a → libwcc.a
    cmd/6{c,a,l}  → cmd/w6{c,a,l}   binary names too
    test/wwc/     → test/wcc/       6 test files w/ w6 prefix
    selfhost/cmd  mirror in lockstep
    bootstrap/amd64/{w6c,w6a,w6l}   snapshot binaries (gitignored)
    WW_6{C,A,L}   → WW_W6{C,A,L}    env-var overrides

Plan 9 source-tree refs ("Plan 9 6c shape", ref/plan9front/, etc.)
preserved. Hare-style driver, both C and ww sides:

    ww test [path]   discover *_test.ww in a directory module, run
                     each; single-file mode for `ww test foo.ww`
    Module-by-name   `ww build foo` resolves to foo.ww or foo/foo.ww
                     via search path (cwd : -I dirs : $WW_LIB)
    Default-to-cwd   `ww build` / `ww test` build the cwd module
    Run pass-through `ww run path arg1 arg2` reaches the program

lib/os: getcwd (79) and getdents64 (217) syscalls power `.` resolution
and directory enumeration on the ww side.

Makefile: wwstage tool deps now include lib/os/os.ww (+ lib/strconv
for wwdump_ww) so lib/* edits force their rebuild instead of leaving
stale binaries — surfaced when test 995 first failed against a stale
w6c_ww built before the lib/os additions.

Test 993 byte-identical parity gate (C-side ww vs ww-side ww_ww on a
build corpus) stays green; all 19 tests pass.
2026-05-11 13:49:27 +09:00
218d8469ff 6c: ww-side compiler binary, dup2 syscall, test 994
selfhost/cmd/6c/main.ww is a thin packaging of the wwc cgen — slurp
a .ww file, run lex+parse+cgen, write Plan 9 amd64 asm to the path
given by -o. The cgen routines in selfhost/cmd/wwc/cgen.ww write
directly to fd 1, so we use dup2 to redirect stdout into the
output file rather than thread an fd through every emit helper.
Adds the SYS_DUP2=33 wrapper in lib/os.

Makefile wires $(BIN)/6c_ww alongside the other wwstage tools and
adds $(BIN)/test_6c_ww to the TESTS list.

test/wwc/994_6c_ww.c diffs 6c_ww byte-for-byte against
`wwdump_ww -c` on five in-source programs plus the four selfhost
main.combined.ww files: same cgen reached through two binaries, so
any divergence is a packaging bug in selfhost/cmd/6c.

We deliberately don't diff against C-side 6c here — 990 probe 5
already covers that on the subset the ww cgen handles today.
2026-05-11 11:20:06 +09:00
1657bdeda3 ww: import toolchain — C bootstrap + ww-side self-host (phases 0-10)
C bootstrap (phases 0-9):
  cmd/wwc, cmd/6c, cmd/6a, cmd/6l, cmd/ww, rt, lib/*.

ww-side self-host (phase 10):
  selfhost/cmd/wwc — ww-cgen frontend; bootstrap fixed point.
  selfhost/cmd/6a  — assembler; byte-identical to C 6a (test 991).
  selfhost/cmd/6l  — linker w/ archive (.a) support; byte-identical
                     to C 6l (test 992).
  selfhost/cmd/ww  — driver (build/run/version); byte-identical to
                     C ww (test 993).

make test: 15/15. make bootstrap: ww2.s == ww3.s, ww2.o == ww3.o,
ww2 == ww3 byte-identical, with the full ww-tooled chain.
2026-05-11 02:17:47 +09:00