session-handoff-2026-10-01.md 5.6 KB

Session handoff — 2026-10-01 (end of day)

State: master at tag v3-wrap-modules (bdcefbb). Suite 177/177, fixpoint OK (2,899,706 bytes). Working tree clean except the user's compiler/toto.mod.

>>> NEXT SESSION: architectural work — FINDING (2026-10-02) <<<

Plan of record: docs/plan-two-phase.md. No restart — it is a middle-of-the-compiler refactor reusing SymTab, QbeGen, the runtime and the harnesses; only the grammar actions change (build nodes instead of emit). Branch ast-stage-c off v3-session-2026-10-02; work §4 slice by slice with the fixpoint as the hard gate.

Stage A is DONE (tag v3-ast-stageA, commit c91695c): the AST node module compiler/src/AST.def/.mod exists and is tested (tests/t_ast.mod), and a real bug was fixed along the way (array-of- record element stride in QbeGen.ElemSize). Suite 178/178, fixpoint OK. See docs/summary_ast-stageA.md.

KEY FINDING — Stage B is not separable from Stage C.

While starting Stage B (two-phase declarations) it became clear that option 2 is not an independent stepping stone:

  • Bodies are lowered during ProcDecl, interleaved with parsing.
  • To finish the symbol table before lowering a body you must not lower the body while parsing it.
  • If you don't lower it then, you must have stored it — and a body is statements + expressions, i.e. Stage C's AST.
  • A "declarations-only" AST does not help: the bodies are what needs deferring.

There is no intermediate. Either bodies are lowered inline (today) or they are built into a tree (Stage C). Options 1 and 2 are the same job.

Revised plan

Do the two-phase refactor as one long, single-purpose branch:

  1. Convert Block / StatSeq / Stat and the expression hierarchy to build AST nodes instead of lowering.
  2. Move the current QbeGen calls for bodies into a tree walk (Lower(n)), run after the unit's declarations are complete in SymTab.
  3. Then declarations (ConstBlock/TypeBlock/VarBlock/ProcDecl) likewise; delete FwdPatchAll / FixLoadClass / FixStoreClass and the Design forward-variable placeholder path.

Expect the fixpoint to be red between increments; keep the old path behind a flag until the new walk passes run_tests.sh, then flip.

What landed today

Tag Commit What
(prev) 678f20e showcase21: expression result suffixes, coroutines, core library
v3-fwdvars-resultsfx a613e7b forward module-level variables, expression result suffixes, LongIO/LongWholeIO/DynamicStrings/SysStorage
v3-wrap-modules 05d9bd0 StdChans, TimeString, wrapclock, wraptime, wrapc
v3-wrap-modules bdcefbb showcase22 + docs/summary_wrap-modules.md

Docs: docs/language-report.md (feature set + gaps), docs/summary_fwdvars-resultsfx.md, docs/summary_wrap-modules.md.

The one blocked feature

ChanConsts and StreamFile are written and parked in docs/wip/ (not compiled into the tree). They are blocked by a single missing language feature:

Aggregate (set) values in CONST declarations. read = FlagSet{readFlag} — and even CONST b = BITSET{0} — is rejected with not supported yet.

Important precision: this is not a "typed set constructor" problem. T{…} constructors already work in expression/assignment position, including a := FSet{r} over an enum base. The gap is specifically that ConstDecl (compiler/src/M2.atg) accepts only ClArray/ClRecord/ClClass/ClStr/ClUStr as aggregate constants and has no set case; a set value has no single immediate operand.

Why it was not attempted

It touches the riskiest area of the frontend (M2.atg) across ConstDecl, TypedBraceLit/BraceElem and Design, plus new SymTab set-word storage and QbeGen set-constant materialisation — a multi-step change, each step needing the full build → suite → fixpoint loop. Today's session showed that grammar edits here can silently break self-hosting; doing it unreliably would risk the green state.

Suggested plan for next time (branch-first)

Work on a branch off bdcefbb; after every increment run ./bootstrap/fixpoint.sh and cd compiler && ./build.sh && ./run_tests.sh. Revert the increment (git checkout -- compiler/src) if either fails. Commit only when both are green.

Increments:

  1. SymTab: store a set constant's bit words per symbol (SetSymSet/GetSymSet), reusing SymNode.val or a small array.
  2. QbeGen: SetConstBegin/SetConstBit/SetConstEnd accumulating words, and SetConstLoad(name) materialising NewSetTemp + Zero + word stores at a use site.
  3. Grammar: a constCtx flag set in ConstDecl; in TypedBraceLit (set branch) accumulate words when constCtx; ConstDecl stores them; Design's KindConst + ClSet calls SetConstLoad.
  4. Activate docs/wip/chanconsts.* and docs/wip/streamfile.* (move back to stdlib/), add them to run_tests.sh, and add a wrapflags.mod test.

Other open items (see docs/language-report.md §9)

  • GOTO/labels.
  • Generics.
  • Statement-context result suffixes (F()[i] := x).
  • Multiple inheritance (deliberate).
  • Full forward variables: module scope only (done); forward procedure references rely on the DEFINITION being present.
  • BITSET is not accepted as a function-result type (hence wrapc.ReadOnly/WriteOnly return CARDINAL).

Resume

cd ~/Projets/Projets-Modula2/MyWork/m2compiler-V3
./bootstrap/fixpoint.sh                       # FIXPOINT OK
cd compiler && ./build.sh && ./run_tests.sh   # 177/177