# Step: TopSpeed V3 corpus validation Tag `v3-topspeed-corpus`. V3 suite **151/151**, fixpoint OK (unchanged — this touches only the sidecar). ## Why After self-hosting, the next "normal" step was to exercise the front-end on a **real corpus**. The historical TopSpeed/JPI V3 corpus is the natural target: `$HOME/bin/Dos/M2/TS-V3` — **662 files** (352 `.DEF` + 310 `.MOD`). V3's own `M2.atg` is the classic/Redux subset and would not take this dialect (pragmas `(*#...)`, conditional compilation `(*%...)`, `H`/`C`/ `B` literals, `::=`, address constructors `[seg:ofs]^`, `CLASS`/`IS`, manifest constants, ...). The project already carries a **sidecar** grammar for it, `compiler/src/TopSpeed-V3-M2.atg`, whose deliverable is *parsing* the dialect (unlowered constructs end in the standard `230`, parse-now / lower-later). That sidecar had never been compiled and run over the full corpus. ## What was done 1. **Built the sidecar** (`tools/topspeed-grammar/build.sh`) — copies the grammar + the V3 frames + `SymTab`/`QbeGen`/`FileIO`, runs `CR -m -C`, `gm2 -fiso`, links `build/TSM2`. 2. **Fixed API drift** vs the current `SymTab`/`QbeGen` (the sidecar predated several changes): - `SymTab.NewArray(e)` → `SymTab.NewOpenArray(e)`; - `SymTab.FixPending(t)` / `SetProcRes(t)` now return `BOOLEAN`; - `QbeGen.EndModule` now takes the module name. 3. **Three real grammar gaps** the corpus exposed: - **tagless variant** `CASE : T OF` (anonymous selector) — TopSpeed accepted, the sidecar required a named tag; - **manifest constants without `CONST`** (`NAME = value;` at declaration level); - **trailing `|`** in a variant list (`TRUE: …; | FALSE: …; |`). 4. **Corpus harness** (`tools/topspeed-grammar/corpus.sh`) — runs `TSM2` over every `.DEF`/`.MOD` in a scratch tree (so listings never touch the corpus) and classifies each file as *parse-OK* (only the deliberate `230`/semantic markers) or *syntax-bad* (a real Coco/R error). ## Result | | files | | --- | --- | | corpus | **662** (352 `.DEF` + 310 `.MOD`) | | **parse-OK** (230/semantic only) | **631** | | syntax-bad | **31** | Coverage rose **590 → 627 → 631** as the fixes landed. ### Remaining 31 syntax-bad - **17 use `(*%…*)` conditional compilation** — a lexer feature the sidecar does not implement; text inside a disabled block is parsed as code. (Pragmas `(*#…)` are already fine — they lex as ordinary `(* … *)` comments.) - **14 assorted**, e.g. a typed set constructor in an argument list (`GetMenu("…", CharSet{'N','P','T'}, ch)`), address constructors, and a few files with malformed/commented-out regions (`END (*QMLB` …). Full list in the harness output. ## Reproduce ```sh cd tools/topspeed-grammar ./build.sh # -> build/TSM2 ./corpus.sh # -> 631 parse-OK / 31 syntax-bad ``` ## Notes - V3's own compiler (`M2.atg`) and the self-hosting path are untouched; the sidecar is a separate grammar built on demand. - The sidecar now tracks the V3 `SymTab`/`QbeGen` API; if those drift again, `build.sh` is where the small patch belongs. ## Files `compiler/src/TopSpeed-V3-M2.atg` (three grammar fixes), `tools/topspeed-grammar/{build.sh,corpus.sh,README.md}`, `.gitignore` (build dir), this doc.