Explorar o código

two-phase slice 3: build designator AST nodes

Design now builds NkDesignator/NkIdent/NkSelector nodes for identifiers,
[i] indexing, .field, ^ deref and qualified names, via a per-invocation
astDes local.  Fact's designator alternative captures the node and marks
it astIsLit so it survives the Fact reset, while brace literals and calls
remain NoNode.  Nodes are inert; emitted output unchanged.

Two bugs caught with a temporary AST.Dump: AddChild's BOOLEAN result was
being discarded (gm2 rejects it -> SetChild/NChild), and the field name
was stored as a raw TxtIndex that a walk misread as a node index (r.f
looped forever -> store an NkIdent child).

Gates: suite 178/178; fixpoint OK (stage2 == stage3, 2970007 bytes).

See docs/summary_two-phase-slice3.md.
Eric Streit hai 1 semana
pai
achega
d63700d204
Modificáronse 4 ficheiros con 1577 adicións e 1490 borrados
  1. 25 11
      compiler/src/M2.atg
  2. 1486 1472
      compiler/src/M2.lst
  3. 7 7
      docs/plan-two-phase.md
  4. 59 0
      docs/summary_two-phase-slice3.md

+ 25 - 11
compiler/src/M2.atg

@@ -1764,7 +1764,8 @@ PRODUCTIONS
                                              isOpen: BOOLEAN;
                                              isOpen: BOOLEAN;
                                              qb, cv: QbeGen.QVal;
                                              qb, cv: QbeGen.QVal;
                                              fid, fref, slot: INTEGER;
                                              fid, fref, slot: INTEGER;
-                                             r: BOOLEAN; .)
+                                             r: BOOLEAN;
+                                              astDes, astSel: AST.Node; .)
     = GetIdent<n>                       (. methCls := SymTab.InvalidType;
     = GetIdent<n>                       (. methCls := SymTab.InvalidType;
                                            QbeGen.CopyOp(n, qn);
                                            QbeGen.CopyOp(n, qn);
                                            sfx := FALSE;
                                            sfx := FALSE;
@@ -1933,8 +1934,11 @@ PRODUCTIONS
                                                END
                                                END
                                              END
                                              END
                                            END; .)
                                            END; .)
+      (. astDes := AST.MakeNode(AST.NkDesignator);
+         AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .)
       { "[" Expr<it, iq>
       { "[" Expr<it, iq>
-                                        (. IF t = SymTab.InvalidType THEN
+                                        (. AST.SetChild(astDes, AST.NChild(astDes),
+             AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
                                            ELSIF SymTab.ClassOf(t) #
                                            ELSIF SymTab.ClassOf(t) #
                                                  SymTab.ClArray THEN
                                                  SymTab.ClArray THEN
                                              SemError(217);
                                              SemError(217);
@@ -1980,7 +1984,8 @@ PRODUCTIONS
                                              t := eT; sfx := TRUE
                                              t := eT; sfx := TRUE
                                            END; .)
                                            END; .)
         { "," Expr<it, iq>
         { "," Expr<it, iq>
-                                        (. IF t = SymTab.InvalidType THEN
+                                        (. AST.SetChild(astDes, AST.NChild(astDes),
+             AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
                                            ELSIF SymTab.ClassOf(t) #
                                            ELSIF SymTab.ClassOf(t) #
                                                  SymTab.ClArray THEN
                                                  SymTab.ClArray THEN
                                              SemError(217);
                                              SemError(217);
@@ -2027,7 +2032,10 @@ PRODUCTIONS
                                            END; .) }
                                            END; .) }
         "]"
         "]"
       | "." GetIdent<fn>
       | "." GetIdent<fn>
-                                        (. IF k = SymTab.KindModule THEN
+                                        (. astSel := AST.MakeNode(AST.NkSelector);
+             AST.SetOp(astSel, AST.SelField);
+             AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn));
+             AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN
                                              (* qualified L.x: materialize
                                              (* qualified L.x: materialize
                                                 the export, then load it *)
                                                 the export, then load it *)
                                              IF NOT SymTab.MaterializeAlias(n,
                                              IF NOT SymTab.MaterializeAlias(n,
@@ -2087,7 +2095,9 @@ PRODUCTIONS
                                              sfx := TRUE
                                              sfx := TRUE
                                            END; .)
                                            END; .)
       | "^"
       | "^"
-                                        (. IF t = SymTab.InvalidType THEN
+                                        (. astSel := AST.MakeNode(AST.NkSelector);
+             AST.SetOp(astSel, AST.SelDeref);
+             AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN
                                            ELSIF SymTab.ClassOf(t) #
                                            ELSIF SymTab.ClassOf(t) #
                                                  SymTab.ClPtr THEN
                                                  SymTab.ClPtr THEN
                                              SemError(219);
                                              SemError(219);
@@ -2110,7 +2120,7 @@ PRODUCTIONS
                                                   note is q itself. *)
                                                   note is q itself. *)
                                                sfx := TRUE
                                                sfx := TRUE
                                              END
                                              END
-                                           END; .) } .
+                                           END; .) } (. astCur := astDes; .) .
   (* Result suffix (ISO component after a function call): `F()^`,
   (* Result suffix (ISO component after a function call): `F()^`,
      `F()[i]`, `F().field`.  The call result is in t/q with sfx FALSE
      `F()[i]`, `F().field`.  The call result is in t/q with sfx FALSE
      (a value, or a descriptor address for aggregates); each component
      (a value, or a descriptor address for aggregates); each component
@@ -2598,7 +2608,9 @@ PRODUCTIONS
                                              isMax: BOOLEAN;
                                              isMax: BOOLEAN;
                                              called, isHigh, sfx, isCh,
                                              called, isHigh, sfx, isCh,
                                              isU, uok, isStr: BOOLEAN;
                                              isU, uok, isStr: BOOLEAN;
-                                             ucp: INTEGER; astIsLit: BOOLEAN; .)
+                                             ucp: INTEGER; astIsLit: BOOLEAN;
+                                              astD: AST.Node;
+                                              astCall: BOOLEAN; .)
     = (. astIsLit := FALSE; .)
     = (. astIsLit := FALSE; .)
     ( integer                           (. LexString(s);
     ( integer                           (. LexString(s);
                                            QbeGen.NormInt(s, q); IF twoPhase THEN astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s) END;
                                            QbeGen.NormInt(s, q); IF twoPhase THEN astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s) END;
@@ -2653,7 +2665,7 @@ PRODUCTIONS
                                              t := SymTab.NewUStr();
                                              t := SymTab.NewUStr();
                                              QbeGen.NoteAddr(q, q)
                                              QbeGen.NoteAddr(q, q)
                                            END; .)
                                            END; .)
-    | Design<dt, dk, qd, qn, sfx>       (. called := FALSE;
+    | Design<dt, dk, qd, qn, sfx>       (. astD := astCur; astCall := FALSE; called := FALSE;
                                            t := dt;
                                            t := dt;
                                            IF sfx THEN
                                            IF sfx THEN
                                              IF dt =
                                              IF dt =
@@ -2694,9 +2706,9 @@ PRODUCTIONS
                                                      SymTab.ClRecord)) THEN
                                                      SymTab.ClRecord)) THEN
                                              QbeGen.NoteAddr(qd, qd)
                                              QbeGen.NoteAddr(qd, qd)
                                            END; .)
                                            END; .)
-      [ TypedBraceLit<dt, q>            (. t := dt; .) ]
+      [ TypedBraceLit<dt, q>            (. t := dt; astCall := TRUE; .) ]
       [ ArgList<qn, dt, qd, TRUE, FALSE, methCls, ct2, q2, called>
       [ ArgList<qn, dt, qd, TRUE, FALSE, methCls, ct2, q2, called>
-                                        (. t := ct2;
+                                        (. astCall := TRUE; t := ct2;
                                            QbeGen.CopyOp(q2, q);
                                            QbeGen.CopyOp(q2, q);
                                            sfx := FALSE; .)
                                            sfx := FALSE; .)
         { ResultComp<t, q, sfx> }
         { ResultComp<t, q, sfx> }
@@ -2712,7 +2724,9 @@ PRODUCTIONS
                                                QbeGen.CopyOp(q2, q)
                                                QbeGen.CopyOp(q2, q)
                                              END
                                              END
                                            END; .) ]
                                            END; .) ]
-                                        (. IF NOT called
+                                        (. IF astCall THEN astCur := AST.NoNode ELSE astCur := astD END;
+                                            astIsLit := TRUE;
+                                            IF NOT called
  AND (dk = SymTab.KindProc) THEN
  AND (dk = SymTab.KindProc) THEN
                                              (* bare zero-arg function
                                              (* bare zero-arg function
                                                 call (parentheses may be
                                                 call (parentheses may be

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1486 - 1472
compiler/src/M2.lst


+ 7 - 7
docs/plan-two-phase.md

@@ -69,13 +69,13 @@ Suggested slices, each ending in `build.sh` + `run_tests.sh` +
    `docs/summary_two-phase-slice1.md`): `twoPhase` flag; `AST` linked
    `docs/summary_two-phase-slice1.md`): `twoPhase` flag; `AST` linked
    into the compiler build; the `integer` leaf also builds `NkIntLit`.
    into the compiler build; the `integer` leaf also builds `NkIntLit`.
    Nothing consumes it.  Green (178/178, fixpoint OK).
    Nothing consumes it.  Green (178/178, fixpoint OK).
-2. **Expressions → AST** — PARTIAL (branch `ast-stage-c`,
-   `docs/summary_two-phase-slice2.md`): the scalar spine (`Expr` /
-   `SimExpr` / `Term` / literals / parens / unary minus) builds nodes
-   via a module-level `astCur` result slot and a per-invocation
-   `astIsLit` flag in `Fact` (no signature changes).  `Design`,
-   selectors, calls, braces, sets and builtins still leave `NoNode`;
-   `Lower` + `.ssa` compare not started.  Green (178/178, fixpoint OK).
+2. **Expressions → AST** — PARTIAL (branch `ast-stage-c`):
+   `docs/summary_two-phase-slice2.md` (spine, literals, parens, unary
+   minus via `astCur` + per-invocation `astIsLit`) and
+   `docs/summary_two-phase-slice3.md` (`Design`: identifiers,
+   `[i]`/`.f`/`^` selectors, qualified names).  Still `NoNode`: calls,
+   brace/set literals, `ResultComp`, builtins, `NOT`; `Lower` + `.ssa`
+   compare not started.  Green (178/178, fixpoint OK).
 3. **Statements → AST**: `Block`/`Stat` build `NkAssign`/`NkIf`/`NkWhile`/
 3. **Statements → AST**: `Block`/`Stat` build `NkAssign`/`NkIf`/`NkWhile`/
    …; `Lower` them.
    …; `Lower` them.
 4. **Declarations → AST**: `ConstBlock`/`TypeBlock`/`VarBlock`/
 4. **Declarations → AST**: `ConstBlock`/`TypeBlock`/`VarBlock`/

+ 59 - 0
docs/summary_two-phase-slice3.md

@@ -0,0 +1,59 @@
+# 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.

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio