Branch ast-stage-c. Tag v3-lower7-flip.
This session did three things: (1) flipped the emitter so Lower is
the only active emitter, (2) deleted the inline emit from the
statement and declaration productions, and (3) started the value/emit
decoupling so expression emit could go too — in the process it found
and fixed a real latent bug in the VAR-actual note ring.
Everything is verified with compiler/run_tests.sh (204/204) and
bootstrap/fixpoint.sh (FIXPOINT OK) after every step.
857c221)The driver (compiler/src/compiler.frm) now always runs the per-unit
Lower emit: BeginSession/BeginUnit/LowerUnitNow/EndSession.
The grammar's inline emit is still present but runs suppressed
(SetNoEmit) and is discarded. -lower is now test-only — it does not
change what is emitted, only names the image <mod>L.ssa for the
byte-compare harness.
This was a no-op flip because Lower had already been verified
byte-identical to the legacy inline emit on every single-file test and
every session.
FIXPOINT OK, 3,553,701 bytes.
| commit | production group |
|---|---|
e5830b2 |
builtin statements (EXIT, INCL/EXCL, INC/DEC, NEW, DISPOSE) |
ce37247 |
control flow (IF/WHILE/REPEAT/LOOP/FOR/CASE), RETURN, HALT |
acc4e91 |
declarations/lifecycle (DeclVar/DeclConst, module/impl/nested/class BeginInit/EndInit/BeginBody/EndModule, FlushPend, FwdPatch) |
Not mechanical: many QbeGen.* calls are semantic queries or parser
state, not emit (TopLoop/PushLoop/PopLoop, TopWith/PushWith,
IsImm/Fold2/NormInt, LocFull, ConstInt, …) and must stay.
7de78bb)Removing the grammar's QbeGen.DeclVar exposed a latent mis-resolution:
Strings.Replace's src VAR actual became $Strings_nl, so Showcase11
no longer linked.
Root cause: QbeGen.AddrOfVal scans the whole 256-entry nVal/nAddr
VAR-actual note ring, and RestoreSession restored nn but never
cleared the ring. The grammar's suppressed parse-time NoteAddr
entries survived into Lower; their keys are temps that restart per
function, so a stale entry could false-match. Removing DeclVar (fewer
AllocLocal/NewTemp calls) shifted those keys and exposed it.
Fix: RestoreSession clears the ring. Lower re-notes its own VAR
actuals, so an empty ring is correct. The fix is output-neutral on
Showcase11 and corrected some latent resolutions in the compiler's own
image.
| commit | removed |
|---|---|
d730e80 |
LowerSession, LowerUnit, the whole Can* family, SetLower/lowerRequested |
e269828 |
QbeGen's CloseModule, FwdPatch, FwdElemPatch, Remark |
241c2c9 |
SymTab's CurModule/CurUnit/ProcDepth/ParamName/ModDefined/ModImplemented/Qual*/NestArray/NewSub/SetElemCheck/SetFor/UnaryCheck/FwdVarKind, QbeGen.StrLen |
b0ef2bf |
AST.TxtLen, AST.SetKind (AST.AddChild stays: t_ast.mod uses it) |
A scan over src/, tests/, runtime/, stdlib/, tools/ now reports
no unreferenced procs in AST/SymTab/QbeGen/Lower.
Still needed until the inline emit is gone:
SaveSession/RestoreSession/SetNoEmit, and
MaterializeGlobals/MaterializeReplace (live, from LowerOneUnit).
The expression value is also the front-end's constant value (Expr's q
feeds SymTab.SetSymVal/Lower.NoteConstVal and IsImm/ConstInt), so
it cannot simply be dropped. The decoupling marks runtime results with a
non-constant sentinel "@" (IsImm/ConstInt reject it), keeps
constant folding (NegFold/Fold2/StrFold) and every check.
| commit | production |
|---|---|
6001af6 |
SimExpr (unary -, OR, UString/CHAR concat, set binops, arithmetic) |
5fb26e7 |
Term (AND, set intersection, * / DIV MOD) |
4f2afa0 |
Expr relation (=,#,<,<=,>,>=,IN) |
d469c78 |
Fact's always-runtime branches (ResultComp ElemLoad, zero-arg calls, ADR, SHIFT/ROTATE, open-array HIGH/LEN, CHR8 range check) |
Constant-producing builtins (fixed-array HIGH/LEN, SIZE/TSIZE,
MAX/MIN, ORD/CHR/VAL, …) keep their folding paths.
Design → Fact → ArgList → ActParam plus the NoteAddr/
AddrOfVal chain moved as one unit (commit 90d2529): Fact
records no notes, ActParam checks VAR-actual addressability by AST
kind (NkDesignator, or NkStrLit), and ArgList drops
CallBegin/CallEnd. Design/ResultComp (0667290), assignment
(0ebe92e), the remaining runtime value ops (f59b784) and the
ProcHeading output (02f2526) followed.
The inline emit is gone from every production where it could be removed
cleanly: statements, control flow, declarations, SimExpr/Term/
Expr/Fact, Design/ResultComp, ArgList/ActParam, assignment,
the runtime builtins, and ProcHeading's output. A runtime value is the
non-constant sentinel "@".
What intentionally remains in the grammar is the value layer
(CopyOp, IsImm, IntStr, Fold2, NormInt/NormReal/NormLit,
Conv*, CharVal, StrFold/StrEq, CapQ/AbsQ/NotQ, UStrLen)
that computes constants and the q Lower.NoteConstVal consumes, plus
the value/parser-state API the checks depend on: the ProcHeading
lifecycle (BeginFunc resets nPar/opens the scope, FuncParam is a
check, EndFunc/AbortFunc close it), PushWith/PopWith (WITH
field resolution), PushLoop/PopLoop (EXIT validity), and
TopWith/TopLoop/LocFull.
One trap worth remembering: an empty (. .) action in ProcDecl
generated a bare ; empty statement that gm2 accepts but the V3
self-host grammar rejects — the suite passed while the fixpoint
failed.
Then: retire the -lower test flag and the now-degenerate byte-compare
tests (done: -lower/IsLowerParam/lowerTest/EndSession's
testSuffix removed, 23 lower_ok cases dropped, suite now 181), and
delete SaveSession/RestoreSession/SetNoEmit (still used by the
per-unit flow).
| step | bytes |
|---|---|
| flip | 3,553,701 |
| statements + declarations + bug fix | 3,538,557 |
| dead-code sweep | 3,420,733 |
| value/emit decoupling (expr layer) | 3,406,951 |
| decoupling complete (Design/Fact/calls/assignment/ProcHeading) | 3,377,935 |
The functional goal — Lower is the only emitter — is met. The rest
is architecture/cleanliness.