This answers "where are we after all the refactoring?".
The L7 flip is byte-identical. Running the compiler on its own
sources under -lower now produces exactly the same image as the
legacy inline emit: cmp reports MATCH, both 3,510,051 bytes
(736/736 functions). run_tests.sh is 204/204 and
bootstrap/fixpoint.sh is FIXPOINT OK (3,510,051 bytes).
The remaining work is the mechanical part of the flip: delete the
grammar's inline emit and the -lower flag, then remove the dead
LowerSession/MaterializeGlobals scaffolding.
run_tests.sh is
204/204 and bootstrap/fixpoint.sh is FIXPOINT OK
(3,510,051 bytes, byte-identical stage2/stage3).Lower
reproduces the whole compiler image byte-for-byte from the AST.-lower) and does not affect the
normal build; the final step is to make it the only emitter.There are two ways the compiler can turn Modula-2 into QBE IR:
Lower walks the AST and emits QBE IR. This is
selected with the -lower flag and is the goal of the
refactor ("the flip" = make Lower the only emitter and delete the
inline emit).The refactor is being done in slices:
| phase | what | state |
|---|---|---|
| L0–L2 | scalars, control flow (IF/WHILE/FOR/…) |
done |
| L3 | procedures, calls, the self-host root-cause fix | done |
| L4 | builtins, CASE, WITH |
done |
| L5 | records/arrays/pointers/sets/strings, literals | done |
| L6 | nested modules, classes, qualified names | done |
| L7 | the flip: Lower emits the whole session | in progress |
Everything is committed in small steps; the many commits are
incremental fixes to the new Lower path, not changes to the
working legacy compiler.
The flip is driven per unit: the driver suppresses the grammar's
inline emit (SetNoEmit), snapshots the QbeGen state before each
unit's parse, restores it, and lets Lower re-emit the unit. On the
compiler's own sources:
-lower emits the full image: 736 functions (same as
legacy), ~1.5 s.first diff at byte 2,935,735, line 89,349 of 120,266.line 9 → 327 → 1124 → 3437 → 6961 → 56294 → 70934 → 82194 → 86942 → 89349.The first divergence is now the generic grammar ArgList call, which
has 9 arguments but AST.MaxChild = 8 caps a call at 7, so Lower
drops the tail.
Lower is V3-legal (forward references declared in Lower.def;
V3 has no whole-module pass) and the SymTab.FormalOk open-array
def/impl bug.FindSym/FindProc.HIGH(s) picked the wrong s).AST.MaxChild:
CASE arms, multi-name VAR declarations, CASE bodies.VAL,
LEN/HIGH, qualified calls, qualified proc-typed variables,
const values, 1-char strings passed as ARRAY OF CHAR.MaterializeReplace).ArgList case):
chunk the call actuals and make the argument loops follow the
NkBlock chunks. (A prototype regressed AstCallNode's legacy
emit and was reverted.)-lower flag.cd compiler
./build.sh # rebuild
./run_tests.sh # 204/204
cd ..
bootstrap/fixpoint.sh # FIXPOINT OK