Branch ast-stage-c. Suite 178/178; self-hosting fixpoint OK
(2,970,007 bytes; slice 2 was 2,966,245).
Design now builds a designator node in addition to emitting, so real
expressions (identifiers, indexing, fields, derefs, qualified names)
have a meaningful AST, not just literals.
| Part | AST |
|---|---|
| base identifier | NkDesignator with child 0 = NkIdent(name) |
[ expr ] / , expr |
one NkSelector (SelIndex) per index, child 0 = the index expression |
. field |
NkSelector (SelField), child 0 = NkIdent(field) |
^ |
NkSelector (SelDeref), no child |
Design keeps a per-invocation astDes local; each selector is appended
with AST.SetChild(astDes, AST.NChild(astDes), …), and the production
ends with astCur := astDes. Fact's designator alternative captures
that node right after Design returns (astD := astCur) and, at the end
of the alternative, does
IF astCall THEN astCur := AST.NoNode ELSE astCur := astD END;
astIsLit := TRUE
so a bare designator survives the Fact reset, while a brace literal or
a call (both marked astCall := TRUE) still yields NoNode for now.
AST.Dump, then removed)a[1] → NkDesignator(Ident a, SelIndex(1))r.f → NkDesignator(Ident r, SelField(Ident f))p^ → NkDesignator(Ident p, SelDeref)r.f + a[2] → Add(NkDesignator(r, SelField f), NkDesignator(a, SelIndex 2))Two bugs were caught this way:
AST.AddChild returns BOOLEAN; GNU Modula-2 refuses to discard a
function result. Switched to AST.SetChild(n, AST.NChild(n), …).TxtIndex in
NkSelector.child[0]. Any tree walk (e.g. AST.Dump) then reads
that integer as a node index and can recurse forever — r.f hung
the dump. Fixed by storing a real NkIdent node as the child.Still NoNode in Fact: calls (ArgList), brace/set literals,
ResultComp suffixes, builds CHR/ORD/ABS/HIGH/LEN/…, NOT.
Lower + .ssa byte-compare still not started.
Slice 4: statements (Block/Stat) build NkAssign/NkIf/NkWhile/…,
then calls/braces; or first finish Fact (calls, builtins). Statements
are the missing piece before a body can be lowered from the AST.