Repository navigation
t27o: a Zig front end (zig_convert.t27) -- 36,495 Zig fns on the roadmap repos, 10-38 % in a first subset, tests as the oracle (stage 5) #10597
Description
Goal
A third t27o front end, specs/tools/t27o/zig_convert.t27 beside rust_convert.t27 and spice_convert.t27, run as tri t27o <file.zig>: hand-written Zig on the roadmap becomes .t27 specs, judged by vectors recorded from the file's own test blocks. Proposed by the front-end census of #10522 (see the census section of docs/nona-03-manifest/T27O-COMPETITORS-AND-DOGFOOD.md); roadmap stage 5 (#4547) says "hand-written Zig becomes generated Zig".
Why this matters (census 2026-10-19, coarse: regex and brace matching, no type check)
| Language on the five roadmap repos | Distinct fns | In a strict first subset |
|---|---|---|
| Zig | 36,495 | 3,797 (10.4 %); 7,767 (21.3 %) with same-file named types; 13,900 (38.1 %) with *T self |
| Rust (today's front end) | 16,775 | 1,667 converted after #10593 |
Python (stdlib ast) |
6,468 | 237 (3.7 %) |
| TypeScript (compiler API, syntactic) | 9,746 | 243 (2.5 %); 26 % of fns are async |
Zig is the largest pool, its grammar is closest to t27's (both derive from the same expression and statement forms), and 1,947 of 2,644 Zig files already hold test blocks (19,594 expectEqual) that can serve as the oracle. First refusals of the coarse subset: error union 41.8 %, pointer 29.9 %, named type 16.8 %, std/allocator 6.9 %.
Deliverable (three steps, each its own PR with tests and a negative control)
- Scalar and slice leaf fns: every fn the strict subset admits converts, or is refused with a named kind; equivalence on vectors recorded from the file's
testblocks. - Same-file
struct/enumand*Tself methods become t27 structs and free fns; a method that writes throughselfis refused, with a negative control. Re-measure the pool with a real parse first (the census is regex-grade). - Error unions:
!T,try,catch,error.Xconvert to the form the rest of the corpus uses, and the error-union refusals (41.8 % of first refusals) drop.
Done when
Step 1 lands with the before/after count on trinity src and trios crates at named commits; tri t27o-sweep (#10543) counts .zig files beside .rs.
Boundary
- May touch: new
specs/tools/t27o/zig_convert.t27, its gen file and seal, the extension dispatch incmd_t27o(glue only; the requiredown-languagecheck needs every added hand line paid for by a deleted one). - Must not touch:
rust_convert.t27,spice_convert.t27(analog M2a: SPICE front end for t27o -- parse, flatten and inventory an ngspice netlist, or refuse with the line #10509).
Risks
The census was coarse; the real parse (comment below) moves the pool down by about 41 % for step 1. Generated Zig (402 parsed files carry a generator marker in their first 20 lines; most Generated from lines name .tri specs, only 12 name .vibee -- an earlier version of this issue said "341 files naming .vibee", which the real parse refuted) must be excluded or traced to its source spec, never converted twice; the rule keys on the generator marker, not on .vibee.
Links
#10522, #4547, #8995 (Python, ranked third), #10543.
User Scenarios
- Given a Zig file in the roadmap repos containing only scalar and slice leaf functions with
testblocks, whentri t27o <file.zig>runs, then the tool emits a.t27spec that passes equivalence on vectors recorded from the file's owntestblocks. - Given a Zig file containing same-file
struct/enumdefinitions and*Tself methods, whentri t27o <file.zig>runs, then the tool emits a.t27spec with t27 structs and free functions, and refuses any method that writes throughselfwith a named refusal kind. - Given a Zig file containing error unions (
!T,try,catch,error.X), whentri t27o <file.zig>runs, then the tool converts them to the form used by the rest of the corpus and the error-union refusal rate drops from the census baseline.
Requirements
FR-001: The tool specs/tools/t27o/zig_convert.t27 MUST exist beside rust_convert.t27 and spice_convert.t27 and be invokable as tri t27o <file.zig>.
FR-002: For every function admitted by the strict subset (scalar and slice leaf fns), the converter MUST either produce a .t27 spec or refuse with a named refusal kind, and equivalence MUST hold on vectors recorded from the file's test blocks.
FR-003: Same-file struct/enum and *T self methods MUST become t27 structs and free functions; a method that writes through self MUST be refused with a named kind and a negative control test.
FR-004: Error unions (!T, try, catch, error.X) MUST convert to the form used by the rest of the corpus, reducing the error-union refusal rate from the census baseline of 41.8%.
FR-005: Generated Zig files (identified by .vibee spec headers) MUST be excluded or traced to their source spec and never converted twice.
FR-006: The extension dispatch in cmd_t27o MUST be updated for Zig with glue only; any added hand-written line MUST be paid for by a deleted one per the own-language check.
FR-007: rust_convert.t27 and spice_convert.t27 MUST NOT be modified.
Activity
gHashTag commentedon Oct 18, 2026
Real-parse census (std.zig.Ast, Zig 0.16.0; throw-away code, not committed) -- 2026-10-19
Same five repositories and commits as the coarse census. Bodies deduplicated by sha256; "hand" = at least one copy outside a file whose first 20 lines carry a generator marker.
*Tselfspecs/igla/coder/training.zig), unverified against the 0.15.2 the repos pin.@importaliases, nested fns), duplication across trinity / trinity-fpga, and generated copies over-represented in tier 1..trispecs; 12 name.vibee). The earlier "341 files naming.vibee" in this issue was wrong and is corrected above.testblock in the same file; 187 sit insideexpectEqual*/expectApproxEq*(value assertions, the strongest).Honest target for the first PR: about 1,052 tier-1 hand-written distinct fns that call only builtins and
std.math/std.ascii/std.mem.eqland have an unambiguous same-file test call (874 of them in trinity); 842 with no calls at all. Step 1 must carry file-level scalarconstdeclarations (627 need them) and allowstd.math. Baselines: trinitysrc/1,590 tier-1 hand-written (978 with a test call), trioscrates/546 (206).Uncertain: test runnability under 0.15.2 (under 0.16.0, 19 of 40 sampled test files type-check; most failures are std API drift); many assertions are properties (
expect(x > 0)), not values; write-through-self detection sees assignments only.gHashTag commentedon Oct 19, 2026
Owner decision 2026-10-19 (translated): "continue autonomously, options A and B" -- this proposal (option B of #10522) is approved; the
roadmaplabel is on. Generated Zig, the open question above: the default taken is that a file with a generator marker in its first 20 lines is refused as a whole ("generated; convert its source spec instead") and never converted twice; tracing it to its.tri/.vibeespec is a later step. Step 1 is #10765 (in progress).t27o: zig_convert.t27 -- the Zig front end, first cut: items, express…
t27o: zig_convert.t27 -- the Zig front end, first cut: items, express…
t27o: Zig front end, step 1 -- zig_convert.t27 converts tier-1 fns an…