Branch ast-stage-c. L7 = "flip: lower from the AST instead of
inline; delete the inline emit + Fwd* machinery".
The flip makes Lower the sole emitter. The obstacle is that QbeGen
holds one session state, used by the inline emit during parse; a
per-unit Lower emit would be clobbered by the next unit's inline emit.
So the flip is a big-bang: either remove/suppress the grammar's 533
QbeGen.* call sites, or give QbeGen two states — neither is a
byte-verifiable step.
The pragmatic path is therefore a session re-emit: collect every
unit's AST and re-emit the whole session with Lower after parsing.
That is byte-comparable against the legacy session image and becomes the
flip once the inline emit is removed.
d30abfd, tag v3-lower7-scaffold)Lower.LowerSession/LowerOneUnit/MaterializeGlobals.compiler.frm) collects GetUnit() per file and calls
Lower.LowerSession under -lower.SymTab.Materialize makes a unit's own VAR/CONST visible in
globScope, so GlobalRef resolves "<unit>_<name>" at session end
(the unit scopes are closed by then).Lower.Reset from the M2 root so the owned tables persist
across a session.Still scaffolding (inline emit untouched); suite 200/200, FIXPOINT OK (3,401,129 bytes).
DefUnit builds no AST. Its ConstBlock/TypeBlock/VarBlock/
ProcHeading loop never AstAppends, so a definition module's AST has
no decls; its proc headings (which consume backend temps) cannot be
replayed. Fix: append to astDecl in DefUnit.MaxProc=64 / MaxSym=512 are sized for one
unit; a full-session re-emit needs every module's procs/vars. Growing
them grows the compiler image (watch the 4 MiB sessBuf).QualNode(outer, name) does not see a
nested scope's non-exported globals; ReenterGlobals re-enters them
but with curMod = -1 (empty mod), so GlobalRef falls back to
$name instead of $<outer>_<name>.BeginFunc/FuncParam/AbortFunc), like LowerMethodHeadings.Lower.LowerSession's image against the legacy session image
for the compiler's own sources (the real test).Lower per unit; the fixpoint
becomes the gate.