Branch ast-stage-c. Suite 178/178; self-hosting fixpoint OK
(2,966,245 bytes; slice 1 was 2,957,466, +8,779 for the builder).
The scalar expression hierarchy now builds an AST alongside the
legacy emit path. The nodes are still inert (nothing lowers them), so
the generated .ssa is unchanged (fixpoint byte-identical).
| Production | Now builds |
|---|---|
Expr |
NkBinExpr for a relation (= # < <= > >= IN) |
SimExpr |
NkUnary (-, OpSub) for a leading minus; NkBinExpr for + - OR |
Term |
NkBinExpr for * / DIV MOD AND |
Fact |
NkIntLit / NkCharLit / NkRealLit / NkStrLit; ( Expr ) passes the inner node through |
The productions keep their existing t/q attributes (no signature
changes, so no call sites change). A single module-level
astCur : AST.Node carries the result of the most recently completed
Expr/SimExpr/Term/Fact; the combination productions save it into
locals before parsing the next operand.
The one hazard is Fact: alternatives such as CHR(x) or a[i] call
Expr internally (and Design calls Expr for indices), which would
leave an inner node in astCur. The fix is a per-invocation
astIsLit : BOOLEAN local in Fact: it is set only by the literal
alternatives, and a trailing action does
IF NOT astIsLit THEN astCur := AST.NoNode END
Because astIsLit is a local (stack) variable, a nested Fact has its
own copy and cannot make an outer non-literal Fact look literal.
( Expr ) is the single pure-grouping alternative and explicitly sets
astIsLit := TRUE so the inner node survives.
AST.Dump, then removed)AST.Dump(astCur, 0) was wired into the M2 root for one build and
three shapes checked; the dump was then removed (the committed grammar
has no debug output):
2 + 3 * 4 - 5 → Sub(Add(2, Mul(3,4)), 5) — precedence + left assoc.-2 + 3 → Add(Unary(Sub, 2), 3).-(2 + 3) * 4 → Unary(Sub, Mul(Add(2,3), 4)) — unary binds to the
whole Term, as the grammar specifies.2 * (3 + 4) → Mul(2, Add(3,4)); 2 < 3 → BinExpr(op=OpLt)(2,3).Two builder bugs were caught this way and fixed (unary minus not fed back into the left accumulator; parentheses discarding the inner node).
Still astCur := NoNode (to be converted in later slices):
Design (identifiers, qualified names, selectors .f [i] ^)
— the largest piece; NkIdent/NkDesignator/NkSelector.ArgList, result suffixes) and NkBraceLit / NkSetLit.CHR/ORD/ABS/HIGH/LEN/… and NOT.Lower + .ssa byte-compare (plan §3 phase 2) — not started; the
inert builder is validated by the fixpoint and the manual dump above.Slice 3: convert Design and the Fact designator/call alternatives,
which turns the spine into a useful AST for real expressions.