STATUS.md 5.8 KB

m2compiler-V3 — status (2026-10-18)

This answers "where are we now?".

Numbers

  • Suite 237/237 (compiler/run_tests.sh).
  • Self-hosting FIXPOINT OK — stage2 and stage3 images are byte-identical (3,823,257 bytes).
  • Corpus 402 / 612 sources compile with 0 errors, 0 crashes (tools/v3-corpus/corpus.sh over the gm2 testsuite); the rest are genuine language gaps, gm2 leniencies V3 deliberately rejects, or unresolved imports.
  • Branch resolve-check; tree clean.

Architecture (current)

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
  • Two-phase parse. Procedure bodies are deferred (module level) and re-parsed after the unit's declarations, which removed the entire forward-reference mechanism (FwdVar*, Design's forward branch). A module body may now call a procedure declared later; a nested-local forward is a plain 201. -notwophase restores the legacy inline parse for debugging.
  • No resolve/check pass. The 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.

Language coverage

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.

Landed recently (this thread)

  • AST + Lower (L0–L7) — Lower emits the whole session from the AST.
  • Two-phase parse; forward machinery deleted; Check deleted.
  • Generics increment 3: value/procedure parameters, constraint model, nested generics, generic classes via generic modules.
  • ISO type conversions T(x) (incl. CONST folding), the builtins ODD/TRUNC/FLOAT, and BOOLEAN/ENUM array bounds + indices: corpus 365 → 381.
  • SET CONST (static masks): a set constant (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*): corpus 382 → 402. Fixed a SHIFT-by-a-negative fault and the qualified-const value (LoadDesignator).
  • The corpus harness now resolves transitive imports (it used to under-provide .defs); this more accurate harness is the method from 2026-10-18.
  • Clean M2 exit codes (0 ok / 1 errors / 2 usage-IO).
  • Bug fixes: 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.
  • Showcase showcase23 (generic doubly linked list).

Conformance policy

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 references to module-level variables and forward procedure calls from a body (both are the two-phase parse deferring procedure bodies — separate from the declaration part). The declaration part itself is now strict: module-level forward type/VAR references, forward types inside a TYPE block, and forward SET OF <type> are all rejected (Track A, first cut, 2026-10-18). Corpus 398 → 388 (the drop is the 10 gm2-leniency files now correctly rejected).

What remains

  1. Corpus — genuine gaps remain (not supported yet, undeclared identifier, invalid call); separate them from gm2 leniencies (docs/gaps/) and missing stdlib imports (LIB). See docs/analysis_gaps.md.
  2. The size-sensitive V3 miscompile — the long-standing "removing ASTDUMP from M2.atg breaks the fixpoint" has never been root-caused. A real correctness landmine.
  3. Robustness — fixed table limits resolve silently when exceeded; weak error recovery; error-message polish.
  4. Library holes — channel/device framework (docs/wip/).
  5. Housekeeping — consolidate docs/summary_*.md (see docs/INDEX.md); decide on merging/pushing resolve-check.

How to check for yourself

cd compiler
./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
./run_tests.sh      # 237/237
cd ..
./bootstrap/fixpoint.sh   # FIXPOINT OK (byte-identical stage2/stage3)