# 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 ```sh cd ~/Projets/Projets-Modula2/MyWork/m2compiler-V3 ./bootstrap/fixpoint.sh # FIXPOINT OK cd compiler && ./build.sh && ./run_tests.sh # 177/177 ```