Commit Graph

14 Commits

Author SHA1 Message Date
077d0f95ed selfhost: graduate SK_* defs to skind enum 2026-05-12 04:52:42 +09:00
408ea2a322 ww+wcc: graduate selfhost TK_* defs to tkind enum
`type tkind = enum i32 { TK_NONE = 0, TK_EOF = 1, ... TK_LAST = 86 }`
replaces the 87-line `def TK_*: i32 = N` cluster in lib/ww/lex/tok.ww.
Numeric values explicit so 990_selfhost's byte-diff against the C-side
`Tkind` enum still passes.

All ~270 reference sites in lib/ww and selfhost/cmd/{wcc,wwdump}
sed-renamed `TK_X` → `tkind.TK_X`. Struct fields (`tok.kind`,
`parser.curkind`) intentionally kept as `i32` — making them `tkind`
shifted some byte-positions in the cgen output and broke 990/993/995
byte-identity probes without an obvious win.

To make the rename non-cascading on every signature, type_assignable
and unify_arith in cmd/wcc/check+type relax to allow enum ↔ int
mixing when storage matches (a `tkind` value flows into an `i32`
slot and vice versa, no explicit cast). This deviates from Hare's
strict enum semantics; doc'd as an explicit pragmatic relaxation
for the compiler's internal enum-shaped kinds. External user code
can still get the type-safety benefit if they declare their
parameters with the enum type.

combined.ww files regenerated by ww build.
2026-05-12 04:50:36 +09:00
5149d10618 wcc+selfhost: pkg-qualified enum access (os.whence.CUR)
Driver-side concatenation flattens module names, but enum member
lookup keyed off the exact lhs ident — so `whence.CUR` worked while
`os.whence.CUR` fell through to w6l with `undefined main.whence`.

C side: fold TY_ENUM members in the post-cexpr cascade too, not
just the early SK_TYPE shortcut. The recursive cexpr lands the
inner N_DOT(os, whence) on the named enum type; the outer access
then folds normally.

Selfhost: cgdot now treats `N_IDENT.MEMBER` and `N_DOT.MEMBER` the
same way, keying off the leaf name. enumlookup strips a trailing
`.`-prefix from the lookup key.

Adds e2e test 700: `use os; os.whence.CUR as i32 == 1`.
2026-05-12 04:30:20 +09:00
f597ce67f6 selfhost: cgen for enum (member fold + as pass-through)
w6c_ww now compiles enum end-to-end and emits byte-identical
asm to the C w6c on the new 994 corpus case (`type mode = enum u8
{ R, W, RW = R | W }; main() { return (mode.RW): i32 }`). Mechanism
mirrors the C side:

- collectenums walks every `type X = enum {...}` at file scope and
  pre-resolves each member's u64 value (auto-increment from prior,
  sibling-ref folding for `RDWR = READ | WRITE`).
- cgdot recognises `EnumName.MEMBER` before the local lookup and
  emits MOVQ $value, AX directly.
- cgtypeassert short-circuits when either side is enum: cgexpr on
  the LHS lands the value in AX with the right integer width; no
  tag/unwrap.

main.combined.ww (wwdump/ + w6c/) regenerated by ww build.
2026-05-12 04:25:28 +09:00
f267f99a2b wcc: match-as-expression with yield
`match (e) { ... }` can now sit in expression position, with each
arm using `yield expr;` to produce the match's value:

    let v = match (r) {
    case let n: i32 => yield n + 1;
    case let s: str => yield s.len: i32 + 100;
    };

TK_YIELD keyword + N_YIELD AST node, both appended at the tail of
their enums to keep prior numeric values byte-stable for the
wwdump-diff gates.

Checker: cexpr for N_MATCH walks each arm's body looking for the
first N_YIELD; the match's type is the unified yield type (or
ty_void if no yield, preserving the statement-form semantics).
Mismatched arm yields are flagged.

Cgen: a yield-target stack (separate from the loop break stack)
holds each enclosing match's end label. N_YIELD evaluates its
expression into AX (and BX for str) and JMPs to the topmost entry.
cgmatch pushes its end label on entry and pops on exit.

Selfhost mirror: lib/ww/lex/tok.ww kwtab+name, lib/ww/ast.ww
N_YIELD def+print, lib/ww/parse/stmt.ww yield-stmt; selfhost cgen
adds a yieldbuf to the cgen struct and a cgyield helper. Verified
end-to-end: a yield-using program compiled via the wwstage cgen
matches the C-cgen build's exit code.
2026-05-12 03:08:00 +09:00
67e27589fd selfhost: mirror nullable pointer folding for (*T | void)
C-cgen-side nullable folding landed in f4efaac. This commit catches
the selfhost cgen up so a wwstage-compiled binary produces the same
ABI for `(*T | void)`.

- cgenutil: isnullabletype(), nullableptrtag() helpers shaped to
  the selfhost cgen's AST-only world view (it doesn't carry a Type
  with a .nullable flag — it walks N_TTAGGED node lists). slotsize
  returns 8 for nullable.
- cgenexpr cgmatch: nullable arm uses pointer-vs-null discriminator
  and binds only the *T case (void has size 0).
- cgenstmt cglet: nullable target spills only AX (no tag word, no
  value-word DX/CX).
- cgenstmt cgreturn: nullable return passes AX through with no
  shuffle; bare `return;` emits AX = 0 (void encoding).

Verified end-to-end: a fn returning `(*i32 | void)` compiled by the
wwstage cgen produces the same exit code as the C-cgen build. The
995 fixed-point gate stays green — no selfhost source uses nullable
yet, so the existing tagged paths are still byte-identical.
2026-05-12 02:57:47 +09:00
dc8405429e selfhost: ?/! postfix in parser + cgen; use ! in lex.ww escape path
Selfhost parser (lib/ww/parse/expr.ww) recognises postfix `?` and
`!` at the same level as `as`/`is`/`:`. Selfhost cgen
(selfhost/cmd/wcc/cgenexpr.ww) emits matching code: cmp AX against
the success tag (0 in legacy mode), branch over the propagate /
abort path, then unwrap (DX → AX, CX → BX for str). Mirrors the C
cgen but without the tag-remap loop — none of the selfhost code
that uses `?` today needs cross-shape remapping.

lib/ww/lex/lex.ww \\x escape handling switched from 5-line match
blocks to one-liners: ascii.digitval(c: rune)!. Both digits are
already validated by isxdigit above; the void variant is
unreachable, so `!` collapses correctly. 995 fixed-point gate
verifies the selfhost cgen produces the same `!` codegen as C cgen.
2026-05-12 02:45:27 +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
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
7cefedb634 wcc/cgen: handle def-str field access (.ptr/.len) on Sdef ident 2026-05-11 22:35:05 +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
6219a47c6f ww: hare-feature batch (_, const, [_]T, ..., size/offset, assert, for-else) 2026-05-11 19:38:12 +09:00
97ca76d2bb selfhost: drop snake_case locals in dyn/dynout/obj + w6a + cgen + ww driver 2026-05-11 16:33:02 +09:00
1e7be36577 wcc/cgen: drop underscore from cgen_*.ww filenames 2026-05-11 16:19:46 +09:00