summary_2026-10-02.md 3.6 KB

Session summary — 2026-10-02 (b): Stage A + the Stage B/C finding

Suite 178/178; self-hosting fixpoint OK (2,900,782 bytes). Tags v3-ast-stageA (AST module + bug fix). This session also established that the two-phase refactor is a single job (see §3).

Steps, tags and commits

Step Tag Commit What
AST module v3-ast-stageA 53943fa AST.def/.mod, self-test
Docs v3-ast-stageA c91695c docs/summary_ast-stageA.md
Finding — 7cec94a Stage B folds into Stage C (handoff)

1. Stage A — the AST module

compiler/src/AST.def + AST.mod: an arena-backed node store, referenced by integer index (Node) like SymTab.TypeIndex — no pointers in the interface, no GC, bounded memory.

  • One flat NodeRec (kind, op, ty, nch, child[0..7]); every construct is a kind + up to 8 children.
  • Kinds for units, declarations, type constructors, statements and expressions; operator/selector codes in op.
  • Interned text pool (AddTxt/Txt/TxtLen).
  • MakeNode/MakeLeaf/MakeBin/MakeUn; Kind/Op/Ty/NChild/ Child/AddChild/SetChild; debug Dump.

Additive: nothing in the grammar calls it yet. tests/t_ast.mod builds a := b + 2, an unary node and a block, then walks it (exit 42); added to run_tests.sh.

2. Bug fixed — array-of-record element stride

QbeGen.ElemSize derived an element's stride from its class, and ClRecord/ClClass/ClSet fell through to 4. So

TYPE R = RECORD kind, op : INTEGER; child : ARRAY [0..7] OF INTEGER END;
VAR a : ARRAY [0..3] OF R;

strided by 4 instead of 48: consecutive elements overlapped and a[i].op / a[i].child[0] read neighbouring elements' fields. A single record and a 2-element array happened to work; 4 elements did not (rc=1). Fix: record/class/set elements use SymTab.TypeSize. Repro rec3.mod now exits 42.

This blocked the AST self-test (its NodeRec holds child : ARRAY [0..7] OF Node) and is a real user-facing bug.

3. Finding — Stage B is not separable from Stage C

Starting the two-phase-declarations step (option 2) showed it is not an independent stepping stone:

  • Bodies are lowered during ProcDecl, interleaved with parsing.
  • To complete the symbol table before lowering a body, the body must not be lowered while parsed — so it must be stored.
  • A stored body is statements + expressions, i.e. Stage C's AST.
  • A "declarations-only" AST does not help: the bodies need deferring.

Options 1 and 2 are the same job. The refactor must be done as one long branch: convert Block/Stat/Expr to AST nodes, move the QbeGen body calls into a lowering walk, then declarations; delete the forward-variable text-patching (FwdPatchAll/FixLoadClass/ FixStoreClass). Keep the old path behind a flag until the new walk passes the suite; expect a red fixpoint between increments.

4. False alarm (recorded so it is not re-chased)

“Nested calls mis-order arguments” — not a bug. rc is the exit status modulo 256, so an encoding of 1234 observed 210 and 1274 observed 250. An equality check (P(1,2,3,4) → rc=42) confirmed the call and codegen are correct.

Resume

cd .../m2compiler-V3
./bootstrap/fixpoint.sh                       # FIXPOINT OK
cd compiler && ./build.sh && ./run_tests.sh   # 178/178

Files

compiler/src/AST.def, compiler/src/AST.mod, compiler/src/QbeGen.mod (ElemSize), compiler/tests/t_ast.mod, compiler/run_tests.sh, docs/summary_ast-stageA.md, docs/session-handoff-2026-10-01.md (revised plan), this doc.