# Two-phase refactor — slice 3 (designators → AST) Branch `ast-stage-c`. Suite **178/178**; self-hosting fixpoint **OK** (**2,970,007 bytes**; slice 2 was 2,966,245). ## What landed `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 ```modula2 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. ## Verified (temporary `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: 1. `AST.AddChild` returns `BOOLEAN`; GNU Modula-2 refuses to discard a function result. Switched to `AST.SetChild(n, AST.NChild(n), …)`. 2. The field name was first stored as a raw `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. ## Deliberately deferred 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. ## Next 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.