Files
ww/selfhost/CLAUDE.md

1.7 KiB

selfhost — ww reimplementation of the toolchain (wcc, w6c, w6a, w6l, ww, wwdump). Compiled by the C bootstrap (../cmd/); the goal is to eventually compile itself.

Identifiers: Plan 9 style. lowercase, words run together (newbuf, tcpsock, parsefile). No snake_case.

Syntax and idioms: Hare-shaped. Trailing ;, = after fn/type signatures, export for visibility, match/?/! for tagged-union errors. Consult ref/hare/ for canonical signatures and error-handling patterns before inventing your own.

The C bootstrap's cgen ("wwstage") has four known silent-miscompilation traps. They produce wrong runtime behavior, not compile errors. When porting C → ww here, default to the workarounds:

  1. Two-level field write through pointer field doesn't stick. r.sym.isdyn = 1 where r.sym: *T drops the write. Bind the inner pointer to a local first:

    let sym: *lsym = r.sym;
    sym.isdyn = 1;
    
  2. Tuple return (scalar, str) corrupts the str half. Both ptr and len come back garbage. Split into two functions — one returns the scalar, another returns the str. Plain str returns are fine.

  3. def NAME: str = "..."; is broken. The .len picks up an unrelated accumulator. Wrap the literal in a nullary fn instead:

    fn namestr() str = { return "..."; };
    
  4. amalloc(n) with n < struct size silently corrupts neighbours. No error — the bump arena hands out n bytes and field writes overflow into the next record. When introducing or growing a struct, audit every amalloc(_, n) call site and over-size (we routinely pass 48 for a 40-byte struct). Symptom: linked-list prepends lose all but the most recent entry.

If a port "should work" but the binary is wrong, suspect these first.