Browse Source

corpus: run the V3 compiler over the gm2 testsuite (219/612 compile-OK)

- tools/v3-corpus/{corpus.sh,README.md}: compile each PIM/ISO
  testsuite file with compiler/M2 alone; split failures into CRASH
  (M2 died), LIB (imports a gm2 library V3 lacks) and LANG (real gap).
- Baseline on 612 files: 219 compile-OK, 7 CRASH, 182 LIB, 204 LANG.
- LANG gaps: 7 set-related segfaults; array constructors (230);
  SYSTEM facilities (BYTE); anchored subranges T[lo..hi]; unnamed
  proc-type parameters.
- docs/summary_v3-corpus.md.  V3 compiler/fixpoint untouched.
Eric Streit 1 week ago
parent
commit
faddb4ddb2
3 changed files with 161 additions and 0 deletions
  1. 71 0
      docs/summary_v3-corpus.md
  2. 26 0
      tools/v3-corpus/README.md
  3. 64 0
      tools/v3-corpus/corpus.sh

+ 71 - 0
docs/summary_v3-corpus.md

@@ -0,0 +1,71 @@
+# Step: V3 compiler corpus run (gm2 testsuite)
+
+Tag `v3-corpus-run`. V3 suite **151/151**, fixpoint OK (unchanged —
+this only adds a harness and a doc).
+
+## Why
+
+The TopSpeed corpus validated the *sidecar grammar*, not V3 the
+compiler (the sidecar is a separate `TSM2` binary built from
+`TopSpeed-V3-M2.atg`; it reuses V3's `SymTab`/`QbeGen`/`FileIO` sources
+but never runs `compiler/M2`).  So this step runs **V3 itself** over a
+real standard-Modula-2 corpus: the gm2 testsuite
+`testsuite/gm2/pim/pass` and `testsuite/gm2/iso/run/pass`.
+
+Harness: `tools/v3-corpus/corpus.sh` (copies each file to a scratch
+tree, compiles alone, splits failures into CRASH / LIB / LANG — see its
+README).
+
+## Baseline
+
+| | files |
+| --- | --- |
+| total | **612** |
+| **compile-OK** (0 errors) | **219** |
+| CRASH (M2 died, rc ≥ 128) | **7** |
+| LIB (imports a gm2 library V3 lacks) | **182** |
+| LANG (real V3 gap) | **204** |
+
+So ~182 of the 393 failures are simply **missing gm2 libraries**
+(`StrIO`, `NumberIO`, `STextIO`, `SWholeIO`, `FpuIO`, `WholeStr`,
+`StdIO`, `M2RTS`, `DynamicStrings`, `Processes`, …) — expected, not
+language gaps.  The signal is the **204 LANG** files.
+
+## Top LANG gaps (from the corpus)
+
+- **7 crashes** — all set-related: `largeset`, `program2`, `set9`,
+  `sets3`, `smallset4/5/6`.  Real bugs (segfaults), highest priority.
+- **48 `not supported yet`** — deliberate V3 `230`s; the corpus shows
+  which constructs matter, e.g. **array constructors**
+  (`array {'h','e','l','l','o'}` in `arrayconst1`).
+- **79 `undeclared identifier`** — mostly **`SYSTEM` facilities** V3
+  does not expose (`FROM SYSTEM IMPORT BYTE;` → `BYTE`), plus small
+  library holes.
+- **Anchored subranges** `INTEGER [-1 .. 24]` (`array2`, `array3`) —
+  PIM form V3's `Subrange` does not parse (`';' expected` at `[`).
+- **Unnamed parameters in procedure types**
+  (`PROCEDURE (VAR ARRAY OF REAL)` in `another.mod`) — PIM allows
+  them; V3 requires a name (`ident expected`).
+- Assorted: `incompatible assignment`/`comparison` on char arrays,
+  `invalid ArrayType`, `invalid call`, `FOR … BY`, etc.
+
+## Reproduce
+
+```sh
+cd tools/v3-corpus
+./corpus.sh            # -> 219 compile-OK / 7 CRASH / 182 LIB / 204 LANG
+```
+
+## Suggested next steps
+
+1. **Fix the 7 set crashes** (a correctness bug — a compiler must not
+   segfault on valid input).
+2. **`SYSTEM` facilities**: expose at least `BYTE` / `WORD` /
+   `SHORTADDR` etc. so `FROM SYSTEM IMPORT …` works.
+3. **Anchored subranges** `T[lo..hi]` (small grammar addition).
+4. **Unnamed proc-type parameters** (small grammar addition).
+5. **Array constructors** `array{…}` (bigger: codegen).
+
+## Files
+
+`tools/v3-corpus/{corpus.sh,README.md}`, this doc.

+ 26 - 0
tools/v3-corpus/README.md

@@ -0,0 +1,26 @@
+# v3-corpus
+
+Runs the **V3 compiler** (`compiler/M2`) over a corpus of standard
+Modula-2 sources and reports compile coverage — unlike
+`tools/topspeed-grammar`, which runs the *sidecar* grammar.
+
+```sh
+./corpus.sh [corpus-dir ...]
+# default: gm2 testsuite pim/pass + iso/run/pass
+```
+
+Each source is copied into a scratch tree (so its `.LST` listing never
+touches the corpus) and compiled on its own.  A file with **0 errors**
+is a pass.  Failures are split into:
+
+- **CRASH** — `M2` died (rc ≥ 128): a real compiler bug;
+- **LIB** — the file imports a module outside V3's known stdlib set
+  (gm2's `StrIO`/`NumberIO`/`STextIO`/…), so the `undeclared
+  identifier`s are expected, not a language gap;
+- **LANG** — otherwise: a genuine parse/semantic gap in V3.
+
+A "pass" is syntactic+semantic cleanup, not a linkable image (many
+testsuite files are DEFINITION/IMPLEMENTATION modules with no program;
+V3 reports those as `Incorrect source` but with 0 errors).
+
+Current baseline: `docs/summary_v3-corpus.md`.

+ 64 - 0
tools/v3-corpus/corpus.sh

@@ -0,0 +1,64 @@
+#!/bin/sh
+# Runs the V3 compiler (compiler/M2) over a corpus of standard Modula-2
+# sources and reports how many compile cleanly.
+#
+# Each source is copied into a scratch tree (so its .LST listing never
+# touches the corpus) and compiled alone.  A file with 0 errors is a
+# pass.  Failures are split into:
+#   CRASH  -- M2 died (rc >= 128): a real compiler bug
+#   LIB    -- the file imports a module outside V3's known stdlib set
+#             (gm2's StrIO/NumberIO/STextIO/...), so "undeclared" is
+#             expected and not a language gap
+#   LANG   -- otherwise: a genuine parse/semantic gap in V3
+#
+# Usage: ./corpus.sh [corpus-dir ...]
+cd "$(dirname "$0")"
+ROOT="$(cd ../.. && pwd)"
+M2="$ROOT/compiler/M2"
+WORK=/tmp/opencode/v3corpus
+KNOWN="SYSTEM SysIO TextIO Strings Math Conversions RealIO ProgramArgs IOChan Files Storage WholeIO CharClass SysClock"
+[ -x "$M2" ] || { echo "compiler/M2 missing -- run compiler/build.sh"; exit 1; }
+[ "$#" -gt 0 ] || set -- \
+  "$HOME/Projets/Projets-Modula2/MyWork/gcc-git/gcc/testsuite/gm2/pim/pass" \
+  "$HOME/Projets/Projets-Modula2/MyWork/gcc-git/gcc/testsuite/gm2/iso/run/pass"
+
+known() { for k in $KNOWN; do [ "$1" = "$k" ] && return 0; done; return 1; }
+
+rm -rf "$WORK"; mkdir -p "$WORK"; : > "$WORK/results.txt"
+n=0
+for dir in "$@"; do
+  find "$dir" -maxdepth 1 \( -iname '*.mod' -o -iname '*.def' \) 2>/dev/null | sort |
+  while read -r f; do
+    n=$((n+1))
+    w="$WORK/f$n"; mkdir -p "$w"; base=$(basename "$f")
+    cp "$f" "$w/$base"
+    "$M2" "$w/$base" >/dev/null 2>&1
+    rc=$?
+    lst="$w/$(echo "$base" | sed 's/\.[^.]*$//').LST"
+    if [ "$rc" -ge 128 ]; then echo "CRASH||$f" >> "$WORK/results.txt"; continue; fi
+    if [ ! -f "$lst" ]; then echo "LANG|no listing|$f" >> "$WORK/results.txt"; continue; fi
+    e=$(grep -oE '[0-9]+ errors?' "$lst" | head -1 | grep -oE '[0-9]+')
+    [ -z "$e" ] && e=-1
+    if [ "$e" = 0 ]; then echo "OK||$f" >> "$WORK/results.txt"; continue; fi
+    # classify: does it import a module outside the known set?
+    names=$( { sed -nE 's/^[[:space:]]*FROM[[:space:]]+([A-Za-z][A-Za-z0-9_]*).*/\1/p' "$w/$base"
+               sed -nE 's/^[[:space:]]*IMPORT[[:space:]]+(.*)/\1/p' "$w/$base" | sed 's/;.*//' | tr ',' '\n'
+             } | sed -E 's/[[:space:]]//g' | grep -E '^[A-Za-z][A-Za-z0-9_]*$' )
+    lib=0
+    for m in $names; do known "$m" || lib=1; done
+    m=$(grep -E '^\*\*\*\*\*' "$lst" | head -1 | sed -E 's/^\*\*\*\*\* *\^? *//; s/^\*\*\*\*\*//')
+    if [ "$lib" = 1 ]; then echo "LIB|$m|$f" >> "$WORK/results.txt"
+    else echo "LANG|$m|$f" >> "$WORK/results.txt"; fi
+  done
+done
+total=$(wc -l < "$WORK/results.txt")
+cnt() { grep -c "^$1" "$WORK/results.txt" 2>/dev/null || true; }
+echo "total      : $total"
+echo "compile-OK : $(cnt OK)"
+echo "CRASH      : $(cnt CRASH)"
+echo "LIB (needs a gm2 library): $(cnt LIB)"
+echo "LANG (V3 gap)            : $(cnt LANG)"
+echo "=== LANG error kinds (top) ==="
+grep '^LANG' "$WORK/results.txt" | cut -d'|' -f2 | sed -E 's/[0-9]+/N/g' | sort | uniq -c | sort -rn | head -15
+echo "=== LANG files (first 40) ==="
+grep '^LANG' "$WORK/results.txt" | head -40 | sed -E 's/^LANG\|([^|]*)\|/  [\1] /'