handoff-l3-option2.md 4.4 KB

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

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.:

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

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