writeonce/compiler/README.md
shoney.arickathil 2de724df11 feat(compiler): MVS ownership pass + woc driver; drop Money/SKU/Float, reject abstract
Completes plan 2 Tasks 7-8. owner.ml: mutable-value-semantics flow analysis
producing the four plan-3 emitter tables (moves, drops incl. LIVE-MASK for trap
unwinding, rc with elision, residual borrow sites) plus WO-E301-304 two-site
diagnostics. Alias questions run over canonicalized places, so a double-mut
reached through let-bound aliases lands in the residual table like the direct
form; dump.ml's contract notes the emitter must coalesce guards per operand.
main.ml: directory discovery, cross-file programs (symbols merge before bodies
check), diagnostics ordered by (file,line,col), new WO-E214 for a name declared
in two files. New docs/plan/oop-vm/01-error-catalog.md (14 emitted + 10 reserved
codes), un-ignored so both plan tracks can cite it; justfile regains woc-*.

builtin_scalars is now the five that work: Int, Bool, Text, Timestamp, Id.
Money/SKU/Float and the abstract_types allowlist are gone — `abstract` never
lexed, and Float had no literal syntax and no wob kind, so no value could exist.
Fixtures and samples retype Money->Int, SKU->Text. The abstract newtype feature
is rejected outright (verdict row adopt->reject); haxe-parity Task 7 keeps `is`.

nullable-types-implementation.md corrected: ?T is plumbed but UNENFORCED
(E211-213 declared, never emitted; probe exits 0), handed to haxe-parity Task 6
as next work item. Records all 10 dead codes incl. E205 — interface satisfaction
is unchecked. crates/rt keeps its Money/SKU fixtures (opaque strings, Stage 2).

Gate: build warning-clean, 14 + 264 checks 0 failures, pricing golden exit 0,
docs/examples histograms unchanged (13/70, zero WO-E225).
2026-08-10 21:24:50 +02:00

3.8 KiB
Raw Blame History

compiler/ — the OCaml woc compiler

Lexer → parser → typechecker → ownership pass, for .wo. OCaml stdlib only (no Menhir, no ppx); dune is the build runner. Sibling of the C wovm bytecode VM (runtime/) — the two halves of the OOP track's spec (docs/superpowers/specs/2026-08-01-oop-compiler-vm-design.md) meet at plan 3 (.wob emission; not built yet).

Stage: plan 2 (docs/plan/compiler/2026-08-01-woc-compiler-front.md) complete, Tasks 1–8. Diagnostics, lexer, parser (declarations + statements/expressions), typechecker (symbols, field kinds, structural interfaces, ?T nullable), and the MVS ownership pass are all implemented and wired into the woc executable. Bytecode emission and .wob output are plan 3 — not started.

Requirements

OCaml 4.14.1, dune 3.14.0 — Ubuntu 24.04 apt packages (sudo apt install ocaml dune), the version floor. Confirm with ocaml -version / dune --version. No opam packages, no Menhir, no ppx — stdlib only.

Build, test

cd compiler && dune build     # -> _build/default/bin/woc
cd compiler && dune runtest   # test_diag unit checks + runner golden/CLI-smoke suite

just woc-build   # same, from the repo root
just woc-test    # same, from the repo root

WOC_BLESS=1 dune runtest (from compiler/) rewrites golden .expected files to match current output — use it once, by hand, to seed or intentionally update a fixture.

Running woc

woc <path>                  # compile (lex, parse, typecheck, ownership-check); nothing prints on success
woc --dump-tokens <path>    # stdout: one line per lexed token
woc --dump-ast <path>       # stdout: the declaration + body AST, indented
woc --dump-owner <path>     # stdout: the ownership pass's four tables (moves, drops, rc, residual)

<path> is a single .wo file or a directory. A directory is discovered recursively for every .wo file under it — same contract as wo run (crates/rt/src/lib.rs::discover): dot-prefixed entries and target/data/node_modules are skipped, results are sorted by path. Every discovered file compiles as one program (declarations in one file resolve for bodies in another, regardless of discovery order); diagnostics from every file and every stage print sorted by (file, line, col). For multi-file --dump-* output, each file's dump is preceded by a === path === header line (compiler/src/dump.ml's file_header) — a single-file run never prints one.

Diagnostics render as file:line:col: severity CODE: message plus a source excerpt with a caret; every shipped code is cataloged in docs/plan/oop-vm/01-error-catalog.md. Exit codes: 0 clean compile, 1 diagnostics reported, 2 usage/IO failure.

Layout

  • src/ — one module per stage: diag (diagnostics, collector, exit-code decision), token/lexer, ast/parser, types (typechecker), owner (MVS ownership pass), dump (stable text dumps for all of the above)
  • bin/ — the woc executable: CLI parsing, file discovery, the multi-file/cross-file driver
  • test/ — runner.ml (golden runner + CLI smoke) and test_diag.ml (diag.ml unit checks); test/golden/<stage>/ holds one-file-per-fixture goldens (tokens, ast, owner, owner-err); test/fixtures/driver/ holds the multi-file CLI-smoke fixtures (directory discovery, cross-file symbols, diagnostic ordering) that don't fit the one-.wo-file-per-fixture golden shape

Governing docs (all under docs/, not here — this file stays an orientation README): spec docs/superpowers/specs/2026-08-01-oop-compiler-vm-design.md; plan docs/plan/compiler/2026-08-01-woc-compiler-front.md (+ architecture.md, nullable-types-implementation.md, 2026-08-01-haxe-parity-language.md, 2026-08-01-wob-emit-e2e-single-binary.md in the same directory). Format contract: docs/plan/oop-vm/00-wob-format.md. Error catalog: docs/plan/oop-vm/01-error-catalog.md.