This answers "where are we now?".
compiler/run_tests.sh).tools/v3-corpus/corpus.sh over the gm2 testsuite); the rest are
genuine language gaps, gm2 leniencies V3 deliberately rejects, or
unresolved imports.master; tree clean.per unit:
Parse -> AST + declarations; each procedure body is skipped and
re-parsed at unit end, so forward references bind normally
Lower -> walk the AST, emit QBE (the only emitter)
Emit -> buffered image, EndModule
-notwophase restores the legacy inline parse for
debugging.Check module was deleted once it was
proven vestigial (gutting it left the emitted .ssa byte-identical):
binding is late by construction.Lower is the only emitter; the AST is the interface.Program modules; CONST/VAR/TYPE (scalars, subranges, enums,
arrays, records incl. variants, sets, pointers); WITH/IN; whole
array/record copy; NEW/DISPOSE; full expressions and control flow;
GOTO/labels; procedures (value/VAR params, functions, recursion,
FORWARD, nested procedures, procedure values); Clarion-form CLASS
(methods, single inheritance, virtual dispatch); PIM coroutines;
Unicode (UCHAR/UString, UTF-8 edges); ISO type conversions T(x);
separate compilation (FROM/IMPORT, qualified L.x, opaque types);
generics (ISO 10514-2 refinement): type/value/procedure
parameters, constraints, nested generics, generic classes.
Lower (L0–L7) — Lower emits the whole session from the AST.Check deleted.T(x) (incl. CONST folding), the builtins
ODD/TRUNC/FLOAT, and BOOLEAN/ENUM array bounds + indices:
corpus 365 → 381.CharSet{"0".."9"},
a union of set constants) is folded to a mask at parse and re-emitted
as a pooled data $setN descriptor. Builtin CONST folding
(CAP/ABS/ODD over immediates), BOOLEAN CONSTs,
representation-changing CONST conversions (VAL(REAL, int),
VAL(LONGINT, int), …), procedure values (ADR(proc),
VAL↔PROC conversions, p := foo into a PROC), SYSTEM sized
reals (REAL32/REAL64), FROM SYSTEM IMPORT SHIFT/ROTATE/CAST/…
(a builtin import is accepted), and ISO foreign modules
(DEFINITION/IMPLEMENTATION MODULE FOR "C", EXPORT UNQUALIFIED),
and ISO CONVERT(T, x) (a VAL sibling), set↔word VAL/CAST
(BITSET), and enumeration literals with their type (export/import/
qualified; imp*) and ORDL de-reserved (a gm2/FileIO helper, not
a built-in; fileio/baseimport): corpus 382 → 405. Fixed a
SHIFT-by-a-negative fault and the qualified-const value
(LoadDesignator)..defs); this more accurate harness is the method from
2026-10-18.M2 exit codes (0 ok / 1 errors / 2 usage-IO).PopPos wiping repass diagnostics; global record data
size (w 0 → l 0 for pointer/LONGINT/proc fields); template
arithmetic over a type formal; proc-typed formals in DEF/IMPL;
imported procedures used as values.showcase23 (generic doubly linked list).V3 follows Modula-2 (PIM/ISO), not gm2's degradations. In
particular the language requires declaration before use (the only
forward reference is a POINTER's base type), so the use-before-
declaration programs that gm2 accepts are rejected by design. The
corpus is gcc's gm2 testsuite, so its number mixes conforming programs
with gm2 leniencies; each known case is catalogued (with a reproducer)
in docs/gaps/.
Known non-conforming behaviour still retained (pre-existing, not yet removed): forward procedure calls from a body (the two-phase parse defers procedure bodies, and the generated parser's mutually recursive productions rely on it). Everything else is strict:
VAR references,
forward types inside a TYPE block, and forward SET OF <type> are
rejected (Track A, 2026-10-18);SymTab declaration sequence +
Lookup). FORWARD remains the way to call a later procedure.
Corpus 427 → 421 (the drop is 6 gm2-leniency files now correctly
rejected, e.g. block, blockindirect, nestedfor).Module-level forward procedure references and FORWARD
declarations still work (t_fwdproc, t_fwdok).
not supported yet,
undeclared identifier, invalid call); separate them from gm2
leniencies (docs/gaps/) and missing stdlib imports (LIB). See
docs/analysis_gaps.md.docs/summary_l3_selfhost_fix.md). It was never
size-sensitive: the fixpoint gate matched the literal string
"Parsed correctly" that the ASTDUMP debug dump printed
unconditionally, so the gate passed while the compiler session was
actually reporting Incorrect source (Lower's forward procedure
references → invalid call). Removing ASTDUMP merely removed the
masking line, which looked like a size effect. Fixed by a3ef897
(remove ASTDUMP; gate on Parsed correctly; declare Lower's walkers
in Lower.def). The gate now fails on errors (verified with
t_fwdvar), and self-hosting stays byte-identical.docs/wip/).docs/INDEX.md is the entry point; the
unreferenced historical records are under docs/archive/ (2026-10-19).
resolve-check was merged to master.cd compiler
./build.sh # M2.atg -> scanner/parser/driver -> ./M2
./run_tests.sh # 246/246
cd ..
./bootstrap/fixpoint.sh # FIXPOINT OK (byte-identical stage2/stage3)