STATUS.md 6.9 KB

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

This answers "where are we now?".

Numbers

  • Suite 246/246 (compiler/run_tests.sh).
  • Self-hosting FIXPOINT OK — stage2 and stage3 images are byte-identical (3,872,467 bytes).
  • Corpus 427 / 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 master; 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. The re-parse is order-aware: a body sees only module-level variables, constants and types declared before its procedure (forward procedure calls remain allowed). -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*) 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).
  • 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 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:

  • the declaration part: module-level forward type/VAR references, forward types inside a TYPE block, and forward SET OF <type> are rejected (Track A, 2026-10-18);
  • inside a deferred procedure body, a reference to a module-level variable, constant or type declared after the enclosing procedure is rejected as undeclared (Track P3, 2026-10-19) — the body re-parse is order-aware (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).

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 — root-caused and fixed (2026-10-19; see 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.
  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 — docs/INDEX.md is the entry point; the unreferenced historical records are under docs/archive/ (2026-10-19). resolve-check was merged to master.

How to check for yourself

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)