Browse Source

docs: handoff for finishing L3 via option 2 (zero SymTab surface)

Records that option 2's architecture is proven (Lower-owned syms/procs
tables + inert grammar hooks; prologue/locals/params byte-aligned) and
does not break self-hosting, the single remaining bug (the procedure
body node is not dispatched by LowerDecls), the exact first diagnostic to
run next, the two already-identified bugs to re-apply (NkProcDecl op=0,
CalleeName), and the do-nots (no SymTab edits, no concurrent emit, no
committed ASTDUMP).

Gates at this point: suite 182/182; fixpoint OK (3147849 bytes).
Eric Streit 1 week ago
parent
commit
90b1d7601a
1 changed files with 109 additions and 0 deletions
  1. 109 0
      docs/handoff-l3-option2.md

+ 109 - 0
docs/handoff-l3-option2.md

@@ -0,0 +1,109 @@
+# Handoff — finishing L3 via option 2 (next session)
+
+Branch **`ast-stage-c`**, HEAD **`e276345`**.  Suite **182/182**;
+fixpoint **OK** (**3,147,849 bytes**).  Tree clean except `toto.mod`.
+
+## Goal
+
+Finish **L3 (procedures)** for the Lower phase
+(`docs/plan-lower.md`, `docs/summary_two-phase-lower3-finding.md`) using
+**option 2 with zero `SymTab` surface**: a `Lower`-owned symbol/signature
+table filled by the grammar while scopes are open, so the end-of-unit
+walk can resolve locals/params after `SymTab` has popped their scopes —
+**without** touching `SymTab` (which broke self-hosting when tried).
+
+## What is already proven (rebuilt transiently, then reverted)
+
+Option 2's architecture **works** and does not break self-hosting:
+
+- `Lower` owned tables worked: `syms[]` (name/kind/ty) with a scope
+  save-stack (`ScopeEnter`/`ScopeLeave`), and `procs[]` (uid/res/depth/
+  ext/params) via `NoteProc`/`NoteParam`/`SetProcRes`.  Resolution via
+  `FindSym`/`FindProc` (`Resolve`, `ProcInfo`, `ParamInfo`).
+- Grammar hooks (all inert — they only fill tables, never emit):
+  - root `M2`: `Lower.Reset`
+  - `VarDecl`: `Lower.NoteVar(nm, KindVar, t)` per pend name
+  - `ConstDecl`: `Lower.NoteVar(n, KindConst, t)`
+  - `ProcHeading`: `Lower.ScopeEnter`, `Lower.NoteProc(pn, uid, Invalid,
+    depth, FALSE)` after `EnterProc`; `Lower.SetProcRes(t)` at the result
+  - `ParamSection`: `Lower.NoteParam(nm, t, isV)` +
+    `Lower.NoteVar(nm, KindParam, t)` per name
+  - `ProcDecl`: `Lower.ScopeLeave` in all three arms (FORWARD / EXTERNAL /
+    body)
+- With the bypass of `CanLower`, the procedure **prologue emitted
+  correctly and byte-aligned** with the legacy image: `BeginFunc`,
+  `FuncParam` for each formal, `EndFuncHeader`, and the **locals did
+  emit** (`%t8 =l alloc4 4 ...` for a local `s`).
+
+## The one remaining bug
+
+The procedure **body** did not emit: `LowerDecls`'s `NkProcDecl` branch
+does
+
+```modula2
+LowerDecls(AST.Child(c, 2));   (* locals  -- emitted OK *)
+LowerStmt(AST.Child(c, 1));    (* body    -- emitted NOTHING *)
+QbeGen.EndFunc(res)
+```
+
+and the output jumped straight from the locals to `EndFunc`'s default
+`ret 0`, i.e. `LowerStmt(AST.Child(c, 1))` dispatched to nothing.
+
+**First step next session:** dump ONE `NkProcDecl`'s children to pin the
+body index.  Add a one-off `AST.Dump(astUnit, 0)` in the root (and
+**remove it before committing** — an `ASTDUMP` was accidentally committed
+once and cost real time), compile e.g.:
+
+```modula2
+MODULE Proc1;
+VAR ExitCode : INTEGER;
+PROCEDURE Add(a, b : INTEGER) : INTEGER;
+VAR s : INTEGER;
+BEGIN s := a + b; RETURN s END Add;
+BEGIN ExitCode := Add(4, 10) END Proc1.
+```
+
+Expect `NkProcDecl` = `[0]=NkIdent Add, [1]=NkBlock[assign, return],
+[2]=locals`.  If the body is elsewhere (e.g. child 1 is the locals and
+the block is nested), fix the dispatch in `LowerDecls`.  The earlier
+slice-5 dump showed child 1 = the body block; the locals (child 2) now
+emit, so verify whether setting child 2 shifted the body.
+
+Likely fix: the body is `AST.Child(c, 1)` and `LowerStmt` handles
+`NkBlock` — check `LowerStmt`'s `NkBlock` branch and the assign/return
+cases reach it.  A `QbeGen.Remark` at the top of `LowerStmt` (removed
+after) will show whether it is entered for the body.
+
+## Then
+
+- Enable procs in `CanLower` (it already routes `NkDecl → CanProc`; the
+  earlier session found `NkProcDecl` `op` defaulted to `-1` and `CanProc`
+  requires `0` for a normal body — **set `AST.SetOp(astNode, 0)` at node
+  creation** in `ProcDecl`; this was one of the two real bugs).
+- Add `lower_ok t_lower3.mod` to `run_tests.sh`.
+- Gate: `build.sh` + `run_tests.sh` (expect 183/183) + `fixpoint.sh`
+  (**must stay OK** — the whole point of option 2).
+
+## Two bugs already identified (re-apply with the option-2 work)
+
+1. `NkProcDecl` op defaults to `-1`; normal body must be `0`
+   (`CanProc` rejects otherwise).  Set it at creation.
+2. `NkCall` child 0 is an `NkDesignator`, not a bare `NkIdent` — calls
+   mangled as `$_0`.  `Lower.CalleeName` unwraps the designator (already
+   in the committed `v3-lower3-wip` `Lower.mod`; re-add for option 2).
+
+## Do NOT
+
+- Do not modify `SymTab` (that broke self-hosting).
+- Do not run the legacy and `L` emitters concurrently (shared
+  `QbeGen` buffer + counters).
+- Do not leave an `ASTDUMP` in `M2.atg`.
+
+## Resume
+
+```sh
+cd ~/Projets/Projets-Modula2/MyWork/m2compiler-V3
+git checkout ast-stage-c
+cd compiler && ./build.sh && ./run_tests.sh   # 182/182
+cd .. && ./bootstrap/fixpoint.sh              # FIXPOINT OK
+```