diff --git a/.github/workflows/emit-bitexact-gate.yml b/.github/workflows/emit-bitexact-gate.yml index 8f620b29a..98d8250e6 100644 --- a/.github/workflows/emit-bitexact-gate.yml +++ b/.github/workflows/emit-bitexact-gate.yml @@ -20,6 +20,7 @@ on: # rewrites the C emitter merges with the cross-target proof never running. - "bootstrap/**" - "cli/**" + - "tools/check_specs_parse.py" - "tools/gft_backprop_microcode.py" - "tools/verify_emit_bitexact.py" - "tools/verify_multitarget.py" @@ -54,6 +55,15 @@ jobs: - name: Build t27c run: cargo build --release -p t27c + # Precondition for everything below. A spec that does not parse produces no + # backend output at all, and the downstream scripts report that as "the C + # backend failed to build" -- which sent four days of readers to the wrong + # subsystem. Ask the parser first, and print its own message. + - name: Required specs parse (negative control) + run: python3 tools/check_specs_parse.py --self-check + - name: Required specs parse + run: python3 tools/check_specs_parse.py + - name: Prove generated RTL == GF-T model (bit-exact) + synthesizes run: python3 tools/verify_emit_bitexact.py diff --git a/docs/NOW.md b/docs/NOW.md index 552d43126..db529269a 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -1,3 +1,17 @@ +# NOW -- one missing brace, and three layers that named the wrong subsystem (2026-08-18) + +Last updated: 2026-08-18 + +## specs: close 27 unterminated test blocks; the cross-target proof was never running (Closes #2185) + +- **`emit-bitexact` was red since 2026-08-14 because of one character.** A bulk edit appended `test _w339_batch_depth_invariant_2 {` to 27 spec files and omitted the closing `}` in every one, so the parser hits the next `test` keyword while still inside the block +- **Three layers each reported something else, and only the innermost was true.** The CI gate said `IGLA RACE CROSS-TARGET MISMATCH`; `verify_igla_race.py` said `FAIL: C backend failed to build/run`; `t27c` said `parse error in fn 'ternary_mac_w339_batch_depth_invariant_2' near line 1815: unexpected token after expression statement: KwTest` -- file, function, line and token, exactly right. The script runs its builds with `capture_output=True` and inspects only `returncode`, so that message was collected and thrown away +- **A diagnostic that names the wrong subsystem costs more than none.** "The C and Rust backends diverge" is a far more alarming claim than "a spec has a typo", and it is where four days of reading went +- **There was no cross-target divergence.** With the braces closed, `verify_igla_race.py` exits 0: C and Rust each match the reference bit-exact over 800 vectors, for both `ternary_mul/mac` and `systolic_ternary_pe` with its i16 accumulator. #2184 is corrected accordingly -- the `i16 + i8` no-cast gap in `gen_rust` is real, is documented in the script, and is worked around there; it was never what made the gate red +- **Gate:** `tools/check_specs_parse.py` asks the question the three layers did not -- does `t27c` accept the file -- and prints the compiler's own message. Negative control plants an unclosed block and proves the gate rejects it. Wired in ahead of every other step, because it is their precondition +- **Reported, not fixed:** closing the braces reveals 15 of 27 igla specs still failing on unrelated parser features (`unknown cast target type f32`, `Unexpected top-level token: KwModule`), overlapping #2174. Different class, left alone +- The `paths:` edit silently failed on an indentation mismatch for the second time today. Caught by a negative control over the filter, not by reading it + # NOW -- the bit-exactness gate could not see the compiler (2026-08-18) Last updated: 2026-08-18 diff --git a/specs/igla/coder/arch.t27 b/specs/igla/coder/arch.t27 index 1b5ad9ca0..367a43f75 100644 --- a/specs/igla/coder/arch.t27 +++ b/specs/igla/coder/arch.t27 @@ -2329,7 +2329,7 @@ test arch_w339_batch_depth_invariant_1 { test arch_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (72→73) test arch_w340_batch_depth_invariant_1 { /* verify baseline */ } test arch_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/coder/bench_proxy.t27 b/specs/igla/coder/bench_proxy.t27 index ef8bbb15f..71d5d96dc 100644 --- a/specs/igla/coder/bench_proxy.t27 +++ b/specs/igla/coder/bench_proxy.t27 @@ -1231,7 +1231,7 @@ test bench_proxy_w339_batch_depth_invariant_1 { test bench_proxy_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (72→73) test bench_proxy_w340_batch_depth_invariant_1 { /* verify baseline */ } test bench_proxy_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/coder/benchmark.t27 b/specs/igla/coder/benchmark.t27 index 5ec007f87..5bb026046 100644 --- a/specs/igla/coder/benchmark.t27 +++ b/specs/igla/coder/benchmark.t27 @@ -4617,7 +4617,7 @@ test benchmark_w339_batch_depth_invariant_1 { test benchmark_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (73→74) test benchmark_w340_batch_depth_invariant_1 { /* verify baseline */ } test benchmark_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/coder/dataset.t27 b/specs/igla/coder/dataset.t27 index efd1672dc..64d1bcc73 100644 --- a/specs/igla/coder/dataset.t27 +++ b/specs/igla/coder/dataset.t27 @@ -2450,7 +2450,7 @@ test dataset_w339_batch_depth_invariant_1 { test dataset_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (72→73) test dataset_w340_batch_depth_invariant_1 { /* verify baseline */ } test dataset_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/coder/eval.t27 b/specs/igla/coder/eval.t27 index 8e6bc20ac..fe6dfb98c 100644 --- a/specs/igla/coder/eval.t27 +++ b/specs/igla/coder/eval.t27 @@ -3631,7 +3631,7 @@ test eval_w339_batch_depth_invariant_1 { test eval_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (74→75) test eval_w340_batch_depth_invariant_1 { /* verify baseline */ } test eval_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/coder/pipeline.t27 b/specs/igla/coder/pipeline.t27 index 42a3bac3d..7c3a995b9 100644 --- a/specs/igla/coder/pipeline.t27 +++ b/specs/igla/coder/pipeline.t27 @@ -2253,7 +2253,7 @@ test pipeline_w339_batch_depth_invariant_1 { test pipeline_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (73→74) test pipeline_w340_batch_depth_invariant_1 { /* verify baseline */ } test pipeline_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/coder/prm.t27 b/specs/igla/coder/prm.t27 index 4b9c4f09c..8cbbc3f9c 100644 --- a/specs/igla/coder/prm.t27 +++ b/specs/igla/coder/prm.t27 @@ -1559,7 +1559,7 @@ test prm_w339_batch_depth_invariant_1 { test prm_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (73→74) test prm_w340_batch_depth_invariant_1 { /* verify baseline */ } test prm_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/coder/tokenizer.t27 b/specs/igla/coder/tokenizer.t27 index 03eeabea6..9c7935f2a 100644 --- a/specs/igla/coder/tokenizer.t27 +++ b/specs/igla/coder/tokenizer.t27 @@ -1381,7 +1381,7 @@ test tokenizer_w339_batch_depth_invariant_1 { test tokenizer_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (73→74) test tokenizer_w340_batch_depth_invariant_1 { /* verify baseline */ } test tokenizer_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/coder/training.t27 b/specs/igla/coder/training.t27 index b72e4fea6..af04667c5 100644 --- a/specs/igla/coder/training.t27 +++ b/specs/igla/coder/training.t27 @@ -1587,7 +1587,7 @@ test training_w339_batch_depth_invariant_1 { test training_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (73→74) test training_w340_batch_depth_invariant_1 { /* verify baseline */ } test training_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/coder/weights.t27 b/specs/igla/coder/weights.t27 index 81c4c48dd..ddc60118e 100644 --- a/specs/igla/coder/weights.t27 +++ b/specs/igla/coder/weights.t27 @@ -1460,7 +1460,7 @@ test weights_w339_batch_depth_invariant_1 { test weights_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — CODER depth +1 (73→74) test weights_w340_batch_depth_invariant_1 { /* verify baseline */ } test weights_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/adder_tree.t27 b/specs/igla/race/adder_tree.t27 index 0ccd84a7d..c29c04697 100644 --- a/specs/igla/race/adder_tree.t27 +++ b/specs/igla/race/adder_tree.t27 @@ -1594,7 +1594,7 @@ test adder_tree_w339_batch_depth_invariant_1 { test adder_tree_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (82→83) test adder_tree_w340_batch_depth_invariant_1 { /* verify baseline */ } test adder_tree_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/backend.t27 b/specs/igla/race/backend.t27 index 0c3dd5711..a9be9fbe1 100644 --- a/specs/igla/race/backend.t27 +++ b/specs/igla/race/backend.t27 @@ -1934,7 +1934,7 @@ test backend_w339_batch_depth_invariant_1 { test backend_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (85→86) test backend_w340_batch_depth_invariant_1 { /* verify baseline */ } test backend_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/bram_weights.t27 b/specs/igla/race/bram_weights.t27 index ba7db7044..327acff1d 100644 --- a/specs/igla/race/bram_weights.t27 +++ b/specs/igla/race/bram_weights.t27 @@ -1588,7 +1588,7 @@ test bram_weights_w339_batch_depth_invariant_1 { test bram_weights_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (83→84) test bram_weights_w340_batch_depth_invariant_1 { /* verify baseline */ } test bram_weights_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/cordic.t27 b/specs/igla/race/cordic.t27 index 4572c01f6..761e940fc 100644 --- a/specs/igla/race/cordic.t27 +++ b/specs/igla/race/cordic.t27 @@ -1601,7 +1601,7 @@ test cordic_w339_batch_depth_invariant_1 { test cordic_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (83→84) test cordic_w340_batch_depth_invariant_1 { /* verify baseline */ } test cordic_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/cordic_fixed.t27 b/specs/igla/race/cordic_fixed.t27 index d234ccd10..dc00568f2 100644 --- a/specs/igla/race/cordic_fixed.t27 +++ b/specs/igla/race/cordic_fixed.t27 @@ -1615,7 +1615,7 @@ test cordic_fixed_w339_batch_depth_invariant_1 { test cordic_fixed_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (84→85) test cordic_fixed_w340_batch_depth_invariant_1 { /* verify baseline */ } test cordic_fixed_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/cordic_top.t27 b/specs/igla/race/cordic_top.t27 index 65b4fad40..4cf284ed8 100644 --- a/specs/igla/race/cordic_top.t27 +++ b/specs/igla/race/cordic_top.t27 @@ -1640,7 +1640,7 @@ test cordic_top_w339_batch_depth_invariant_1 { test cordic_top_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (84→85) test cordic_top_w340_batch_depth_invariant_1 { /* verify baseline */ } test cordic_top_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/eda.t27 b/specs/igla/race/eda.t27 index 6dc4ea1e2..8e4fd5df8 100644 --- a/specs/igla/race/eda.t27 +++ b/specs/igla/race/eda.t27 @@ -1829,7 +1829,7 @@ test eda_w339_batch_depth_invariant_1 { test eda_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (83→84) test eda_w340_batch_depth_invariant_1 { /* verify baseline */ } test eda_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/formal.t27 b/specs/igla/race/formal.t27 index 67ddaa93d..c6cfb629c 100644 --- a/specs/igla/race/formal.t27 +++ b/specs/igla/race/formal.t27 @@ -1750,7 +1750,7 @@ test formal_w339_batch_depth_invariant_1 { test formal_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (83→84) test formal_w340_batch_depth_invariant_1 { /* verify baseline */ } test formal_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/gemm.t27 b/specs/igla/race/gemm.t27 index 186870366..f8d35cffb 100644 --- a/specs/igla/race/gemm.t27 +++ b/specs/igla/race/gemm.t27 @@ -1642,7 +1642,7 @@ test gemm_w339_batch_depth_invariant_1 { test gemm_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (83→84) test gemm_w340_batch_depth_invariant_1 { /* verify baseline */ } test gemm_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/opcodes.t27 b/specs/igla/race/opcodes.t27 index 81c44b1c9..f486688ee 100644 --- a/specs/igla/race/opcodes.t27 +++ b/specs/igla/race/opcodes.t27 @@ -1456,7 +1456,7 @@ test opcodes_w339_batch_depth_invariant_1 { test opcodes_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (83→84) test opcodes_w340_batch_depth_invariant_1 { /* verify baseline */ } test opcodes_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/rtl.t27 b/specs/igla/race/rtl.t27 index be1f732e9..173c959f1 100644 --- a/specs/igla/race/rtl.t27 +++ b/specs/igla/race/rtl.t27 @@ -1776,7 +1776,7 @@ test rtl_w339_batch_depth_invariant_1 { test rtl_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (83→84) test rtl_w340_batch_depth_invariant_1 { /* verify baseline */ } test rtl_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/systolic_array.t27 b/specs/igla/race/systolic_array.t27 index f28984256..56b2c2d78 100644 --- a/specs/igla/race/systolic_array.t27 +++ b/specs/igla/race/systolic_array.t27 @@ -1755,7 +1755,7 @@ test systolic_array_w339_batch_depth_invariant_1 { test systolic_array_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (86→87) test systolic_array_w340_batch_depth_invariant_1 { /* verify baseline */ } test systolic_array_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/systolic_ternary.t27 b/specs/igla/race/systolic_ternary.t27 index 71ac7522f..cf25acfc4 100644 --- a/specs/igla/race/systolic_ternary.t27 +++ b/specs/igla/race/systolic_ternary.t27 @@ -2004,7 +2004,7 @@ test systolic_ternary_w339_batch_depth_invariant_1 { test systolic_ternary_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool B depth +1 (99→100) test systolic_ternary_w340_batch_depth_invariant_1 { /* verify baseline */ } test systolic_ternary_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/ternary_gemm.t27 b/specs/igla/race/ternary_gemm.t27 index 50c7d123b..b152b76be 100644 --- a/specs/igla/race/ternary_gemm.t27 +++ b/specs/igla/race/ternary_gemm.t27 @@ -1755,7 +1755,7 @@ test ternary_gemm_w339_batch_depth_invariant_1 { test ternary_gemm_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (82→83) test ternary_gemm_w340_batch_depth_invariant_1 { /* verify baseline */ } test ternary_gemm_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/ternary_inference.t27 b/specs/igla/race/ternary_inference.t27 index 5ae878522..32269dbb1 100644 --- a/specs/igla/race/ternary_inference.t27 +++ b/specs/igla/race/ternary_inference.t27 @@ -1130,7 +1130,7 @@ test ternary_inference_w339_batch_depth_invariant_1 { test ternary_inference_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Integration depth +1 (82→83) test ternary_inference_w340_batch_depth_invariant_1 { /* verify baseline */ } test ternary_inference_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/ternary_mac.t27 b/specs/igla/race/ternary_mac.t27 index ac3d6c9e3..0ddb5a5a3 100644 --- a/specs/igla/race/ternary_mac.t27 +++ b/specs/igla/race/ternary_mac.t27 @@ -1810,7 +1810,7 @@ test ternary_mac_w339_batch_depth_invariant_1 { test ternary_mac_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (82→83) test ternary_mac_w340_batch_depth_invariant_1 { /* verify baseline */ } test ternary_mac_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/specs/igla/race/yosys.t27 b/specs/igla/race/yosys.t27 index 9930a4aec..24dada8fa 100644 --- a/specs/igla/race/yosys.t27 +++ b/specs/igla/race/yosys.t27 @@ -1785,7 +1785,7 @@ test yosys_w339_batch_depth_invariant_1 { test yosys_w339_batch_depth_invariant_2 { // Verify baseline properties for 15-variable accumulation assert(true) - +} // Wave Loop 340 — Pool A depth +1 (84→85) test yosys_w340_batch_depth_invariant_1 { /* verify baseline */ } test yosys_w340_batch_depth_invariant_2 { /* verify baseline */ } diff --git a/tools/check_specs_parse.py b/tools/check_specs_parse.py new file mode 100755 index 000000000..11a21036a --- /dev/null +++ b/tools/check_specs_parse.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +"""Does every spec the cross-target gate depends on still parse? + +Written after a bulk edit dropped one closing brace in 27 files and nobody +noticed for four days. + +`test X_w339_batch_depth_invariant_2 {` was appended to 27 specs with its `}` +omitted, so the parser hit the next `test` keyword while still inside the block: + + parse error in fn 'ternary_mac_w339_batch_depth_invariant_2' near line 1815: + unexpected token after expression statement: KwTest + +The message was exact. Nothing surfaced it, because three layers reported +something else: + + the CI gate said IGLA RACE CROSS-TARGET MISMATCH + the script said FAIL: C backend failed to build/run + the truth was the spec does not parse, so no backend ever ran + +The script's own build helpers pass capture_output=True and inspect only +returncode, so the compiler's message -- which named the file, the function and +the line -- was collected and thrown away. A diagnostic that names the wrong +subsystem costs more than no diagnostic: it sends the reader to the backend. + +This gate asks the one question those three layers did not: does `t27c` accept +the file at all. It reports the compiler's own error verbatim. + +Usage: + tools/check_specs_parse.py gate over the required set + tools/check_specs_parse.py --all every spec under specs/, reporting + tools/check_specs_parse.py --self-check negative control + +Exits non-zero if a required spec does not parse. +""" +import glob +import os +import pathlib +import subprocess +import sys + +ROOT = pathlib.Path(__file__).resolve().parent.parent + +# Specs the cross-target bit-exactness proof consumes. These must parse; a PR +# that breaks one is breaking the proof, not merely a file. +REQUIRED = [ + "specs/igla/race/ternary_mac.t27", + "specs/igla/race/systolic_ternary.t27", + "specs/ternary/gft_smul.t27", + "specs/ternary/gft_sadd.t27", +] + + +def find_t27c(): + for p in ("target/release/t27c", "target/debug/t27c"): + c = ROOT / p + if c.exists(): + return str(c) + return None + + +def parses(t27c, spec): + """(ok, first line of the compiler's own error).""" + r = subprocess.run([t27c, "gen-c", spec], capture_output=True, text=True, cwd=ROOT) + if r.returncode == 0: + return True, "" + err = (r.stderr or r.stdout or "").strip().split("\n") + return False, err[0] if err else f"exit {r.returncode}, no message" + + +def self_check(t27c): + """Plant an unclosed test block and prove the gate reports it.""" + import tempfile, shutil + src = ROOT / REQUIRED[0] + with tempfile.TemporaryDirectory() as td: + bad = os.path.join(td, "bad.t27") + text = src.read_text(encoding="utf-8") + # remove the first closing brace of a test block -> the exact fault we hit + i = text.find("\n}\n", text.find("test ")) + shutil.copy(src, bad) + pathlib.Path(bad).write_text(text[:i] + "\n" + text[i + 3:], encoding="utf-8") + ok_bad, msg = parses(t27c, bad) + ok_good, _ = parses(t27c, str(src)) + print(f" self-check: planted spec rejected = {not ok_bad}, real spec accepted = {ok_good}") + if not ok_bad: + print(f" reported: {msg[:100]}") + return 0 if (not ok_bad and ok_good) else 1 + + +def main(): + t27c = find_t27c() + if not t27c: + print("FAIL: t27c not built. Run: cargo build --release -p t27c") + return 1 + if "--self-check" in sys.argv: + return self_check(t27c) + + targets = (sorted(glob.glob(str(ROOT / "specs/**/*.t27"), recursive=True)) + if "--all" in sys.argv else [str(ROOT / p) for p in REQUIRED]) + bad = [] + for spec in targets: + rel = os.path.relpath(spec, ROOT) + ok, msg = parses(t27c, spec) + if not ok: + bad.append((rel, msg)) + elif "--all" not in sys.argv: + print(f" ok {rel}") + + if "--all" in sys.argv: + print(f"\n {len(targets) - len(bad)} of {len(targets)} specs parse") + for rel, msg in bad: + print(f" {rel}\n {msg[:120]}") + print("\n --all is a report, not a gate: many specs fail on parser features") + print(" that are tracked separately. Only the REQUIRED set gates CI.") + return 0 + + if not bad: + print(f"\nOK: all {len(targets)} required specs parse") + return 0 + print(f"\nFAIL: {len(bad)} required spec(s) do not parse\n") + for rel, msg in bad: + print(f" {rel}") + print(f" {msg}") + print("\n This is the compiler's own message. It names the file, the function") + print(" and the line -- read it before looking at any backend.") + return 1 + + +if __name__ == "__main__": + sys.exit(main())