Просмотр исходного кода

two-phase slice 7: unit root and builtin statements

astUnit now holds NkUnit(name, decls, body) for definition,
implementation and program modules.  INCL/EXCL, INC/DEC, NEW and
DISPOSE statements build NkCall nodes with an NkIdent callee and the
designator/step children.  Nodes are inert; emit unchanged.

Deferred: imports/CLASS/nested modules, CASE/WITH, brace/set literals,
ResultComp, Lower.

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

See docs/summary_two-phase-slice7.md.
Eric Streit 1 неделя назад
Родитель
Сommit
b91629741f
5 измененных файлов с 3627 добавлено и 3442 удалено
  1. 81 15
      compiler/src/M2.atg
  2. 3485 3419
      compiler/src/M2.lst
  3. 6 4
      docs/plan-two-phase.md
  4. 6 4
      docs/session-handoff-2026-10-03.md
  5. 49 0
      docs/summary_two-phase-slice7.md

+ 81 - 15
compiler/src/M2.atg

@@ -81,6 +81,9 @@ VAR
      declaration; DeclSeq folds these into an NkDeclSeq. *)
   astDecl: AST.Node;
 
+  (* Unit-AST root (slice 7): NkUnit(name, decls, body). *)
+  astUnit: AST.Node;
+
   (* Class of the method named by the last `obj.Method` designator
      (InvalidType when the callee is an ordinary procedure). Set by
      Design, consumed by the following ArgList. *)
@@ -218,6 +221,11 @@ PRODUCTIONS
       | ProcHeading<pn, SymTab.InvalidType> ";"
                                         (. SymTab.CloseProc;
                                              QbeGen.AbortFunc; .) }
+                                        (. astUnit := AST.MakeNode(AST.NkUnit);
+                                           AST.SetChild(astUnit, 0,
+                                             AST.MakeLeaf(AST.NkIdent, m1));
+                                           astDecl := AST.NoNode;
+                                           astStmt := AST.NoNode; .)
       "END"
       GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
                                              SemError(202) END;
@@ -225,10 +233,13 @@ PRODUCTIONS
   ImplUnit                              (. VAR m1, m2: SymTab.Name;
                                              k: CARDINAL;
                                              fname: SymTab.Name;
-                                             unres: BOOLEAN; .)
+                                             unres: BOOLEAN;
+                                             astNode: AST.Node; .)
     = "IMPLEMENTATION" "MODULE"
-      GetIdent<m1>                      (. IF NOT SymTab.BeginImpl(m1) THEN
+      GetIdent<m1> (. IF NOT SymTab.BeginImpl(m1) THEN
                                              SemError(201) END;
+                                           astStmt := AST.NoNode;
+                                           astDecl := AST.NoNode;
                                            nPendVar := 0;
                                            QbeGen.SetModule(m1); .)
       ";"
@@ -255,16 +266,25 @@ PRODUCTIONS
                                            END;
                                            SymTab.FwdClear;
                                            FwdVarFlush;
+                                           astNode := AST.MakeNode(AST.NkUnit);
+                                           AST.SetChild(astNode, 0,
+                                             AST.MakeLeaf(AST.NkIdent, m1));
+                                           AST.SetChild(astNode, 1, astDecl);
+                                           AST.SetChild(astNode, 2, astStmt);
+                                           astUnit := astNode;
                                            IF NOT SymTab.Equal(m1, m2) THEN
                                              SemError(202) END;
                                            SymTab.EndUnit; .) .
   ProgModule                            (. VAR m1, m2: SymTab.Name;
                                              k: CARDINAL;
                                              fname: SymTab.Name;
-                                             unres: BOOLEAN; .)
+                                             unres: BOOLEAN;
+                                             astNode: AST.Node; .)
     = "MODULE"
-      GetIdent<m1>                      (. IF NOT SymTab.BeginProg(m1) THEN
+      GetIdent<m1> (. IF NOT SymTab.BeginProg(m1) THEN
                                              SemError(200) END;
+                                           astStmt := AST.NoNode;
+                                           astDecl := AST.NoNode;
                                            nPendVar := 0;
                                            QbeGen.SetModule(m1); .)
       [ Priority ]
@@ -294,6 +314,12 @@ PRODUCTIONS
                                            FwdVarFlush;
                                            IF NOT SymTab.Equal(m1, m2) THEN
                                              SemError(202) END;
+                                           astNode := AST.MakeNode(AST.NkUnit);
+                                           AST.SetChild(astNode, 0,
+                                             AST.MakeLeaf(AST.NkIdent, m1));
+                                           AST.SetChild(astNode, 1, astDecl);
+                                           AST.SetChild(astNode, 2, astStmt);
+                                           astUnit := astNode;
                                            QbeGen.EndModule(m1);
                                            SymTab.EndUnit; .) .
   DeclSeq                               (. VAR astSeq: AST.Node; .)
@@ -1096,11 +1122,24 @@ PRODUCTIONS
                                              dk: INTEGER;
                                              qd, qe: QbeGen.QVal;
                                              qn: SymTab.Name;
-                                             sfx, isInc: BOOLEAN; .)
+                                             sfx, isInc: BOOLEAN;
+                                             astNode, astD: AST.Node; .)
     = ( "INCL"                          (. isInc := TRUE; .)
       | "EXCL"                          (. isInc := FALSE; .) )
-      "(" Design<at, dk, qd, qn, sfx> ","
+      "(" Design<at, dk, qd, qn, sfx> (. astD := astCur; .) ","
       Expr<et2, qe> ")"
+                                        (. astNode := AST.MakeNode(AST.NkCall);
+                                           IF isInc THEN
+                                             AST.SetChild(astNode, 0,
+                                               AST.MakeLeaf(AST.NkIdent, "INCL"))
+                                           ELSE AST.SetChild(astNode, 0,
+                                               AST.MakeLeaf(AST.NkIdent, "EXCL"))
+                                           END;
+                                           IF astD # AST.NoNode THEN
+                                             AST.SetChild(astNode, 1, astD) END;
+                                           IF astCur # AST.NoNode THEN
+                                             AST.SetChild(astNode, 2, astCur) END;
+                                           astStmt := astNode; .)
                                         (. IF at = SymTab.InvalidType THEN
                                            ELSIF SymTab.ClassOf(at) #
                                                  SymTab.ClSet THEN
@@ -1123,14 +1162,27 @@ PRODUCTIONS
                                              qd, qv, qn2, qstep:
                                                QbeGen.QVal;
                                              qn: SymTab.Name;
-                                             sfx, isInc: BOOLEAN; .)
+                                             sfx, isInc: BOOLEAN;
+                                             astNode, astD, astStep:
+                                               AST.Node; .)
     =                                   (. isInc := TRUE; .)
       ( "INC"                           (. isInc := TRUE; .)
       | "DEC"                           (. isInc := FALSE; .) )
-      "("                               (. QbeGen.CopyOp("1", qstep); .)
-      Design<dt, dk, qd, qn, sfx>
-      [ "," Expr<et2, qstep> ]
-      ")"                               (. IF dt = SymTab.InvalidType THEN
+      "("                               (. QbeGen.CopyOp("1", qstep); astStep := AST.NoNode; .)
+      Design<dt, dk, qd, qn, sfx> (. astD := astCur; .)
+      [ "," Expr<et2, qstep> (. astStep := astCur; .) ]
+      ")"                               (. astNode := AST.MakeNode(AST.NkCall);
+                                           IF isInc THEN
+                                             AST.SetChild(astNode, 0,
+                                               AST.MakeLeaf(AST.NkIdent, "INC"))
+                                           ELSE AST.SetChild(astNode, 0,
+                                               AST.MakeLeaf(AST.NkIdent, "DEC"))
+                                           END;
+                                           IF astD # AST.NoNode THEN
+                                             AST.SetChild(astNode, 1, astD) END;
+                                           IF astStep # AST.NoNode THEN
+                                             AST.SetChild(astNode, 2, astStep) END;
+                                           astStmt := astNode; .)                               (. IF dt = SymTab.InvalidType THEN
                                            ELSIF (dk # SymTab.KindVar)
  AND (dk # SymTab.KindParam)
  AND (dk # SymTab.KindField) THEN
@@ -1167,8 +1219,15 @@ PRODUCTIONS
                                              qd, qm: QbeGen.QVal;
                                              qn: SymTab.Name;
                                              sfx: BOOLEAN;
-                                             bt: SymTab.TypeIndex; .)
-    = "NEW" "(" Design<dt, dk, qd, qn, sfx> ")"
+                                             bt: SymTab.TypeIndex;
+                                             astNode, astD: AST.Node; .)
+    = "NEW" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
+                                        (. astNode := AST.MakeNode(AST.NkCall);
+                                           AST.SetChild(astNode, 0,
+                                             AST.MakeLeaf(AST.NkIdent, "NEW"));
+                                           IF astD # AST.NoNode THEN
+                                             AST.SetChild(astNode, 1, astD) END;
+                                           astStmt := astNode; .)
                                         (. IF dt = SymTab.InvalidType THEN
                                            ELSIF (dk # SymTab.KindVar)
  AND (dk # SymTab.KindParam)
@@ -1196,8 +1255,15 @@ PRODUCTIONS
                                              dk: INTEGER;
                                              qd, qv: QbeGen.QVal;
                                              qn: SymTab.Name;
-                                             sfx: BOOLEAN; .)
-    = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> ")"
+                                             sfx: BOOLEAN;
+                                             astNode, astD: AST.Node; .)
+    = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
+                                        (. astNode := AST.MakeNode(AST.NkCall);
+                                           AST.SetChild(astNode, 0,
+                                             AST.MakeLeaf(AST.NkIdent, "DISPOSE"));
+                                           IF astD # AST.NoNode THEN
+                                             AST.SetChild(astNode, 1, astD) END;
+                                           astStmt := astNode; .)
                                         (. IF dt = SymTab.InvalidType THEN
                                            ELSIF (dk # SymTab.KindVar)
  AND (dk # SymTab.KindParam)

Разница между файлами не показана из-за своего большого размера
+ 3485 - 3419
compiler/src/M2.lst


+ 6 - 4
docs/plan-two-phase.md

@@ -87,10 +87,12 @@ Suggested slices, each ending in `build.sh` + `run_tests.sh` +
    Finding: **local arrays in a PROCEDURE are miscompiled**
    (`docs/wip/local-array-bug.mod`) — pre-existing, worked around here.
 4. **Declarations → AST** — PARTIAL (branch `ast-stage-c`,
-   `docs/summary_two-phase-slice6.md`): `DeclSeq` builds `NkDeclSeq`;
-   `CONST`/`TYPE`/`VAR`/`PROC` build `NkConstDecl`/`NkTypeDecl`/
-   `NkVarDecl`/`NkProcDecl` (types referenced by the node `ty` index).
-   Deferred: unit/`NkUnit` root, imports, `CLASS`, nested modules.
+   `docs/summary_two-phase-slice6.md`, `docs/summary_two-phase-slice7.md`):
+   `DeclSeq` builds `NkDeclSeq`; `CONST`/`TYPE`/`VAR`/`PROC` build
+   `NkConstDecl`/`NkTypeDecl`/`NkVarDecl`/`NkProcDecl` (types referenced
+   by the node `ty` index); `astUnit` holds `NkUnit(name, decls, body)`
+   for all three unit kinds; builtin statements build `NkCall`s.
+   Deferred: imports, `CLASS`, nested modules in the unit AST.
 5. **Flip**: bodies lower from the AST; delete `FwdPatchAll` /
    `FixLoadClass` / `FixStoreClass`, the `Design` forward-variable
    placeholder, and `pendVar*` if superseded.

+ 6 - 4
docs/session-handoff-2026-10-03.md

@@ -1,7 +1,7 @@
 # Session handoff — 2026-10-03 (two-phase frontend, slices 1–5)
 
 State: branch **`ast-stage-c`** (off `1c93f19`, not merged to `master`).
-Suite **178/178**; self-hosting fixpoint **OK** (**3,007,851 bytes**).
+Suite **178/178**; self-hosting fixpoint **OK** (**3,016,802 bytes**).
 Working tree clean except the user's `compiler/toto.mod`.
 
 Plan of record: `docs/plan-two-phase.md`.  Start: §4 slice 3
@@ -17,6 +17,7 @@ Plan of record: `docs/plan-two-phase.md`.  Start: §4 slice 3
 | `v3-ast-slice4` | `summary_two-phase-slice4.md` | calls/`NkCall` with actuals, `NOT`, builtins as named `NkCall`s |
 | `v3-ast-slice5` | `summary_two-phase-slice5.md` | statements: `NkBlock`, assign, `IF`/`WHILE`/`REPEAT`/`LOOP`/`EXIT`/`FOR`/`RETURN`/`HALT`, calls |
 | `v3-ast-slice6` | `summary_two-phase-slice6.md` | declarations: `NkDeclSeq`, `NkConstDecl`, `NkTypeDecl`, `NkVarDecl`, `NkProcDecl` (types by `ty` index) |
+| `v3-ast-slice7` | `summary_two-phase-slice7.md` | unit root `NkUnit(name, decls, body)`; builtin statements `INCL`/`INC`/`NEW`/… as `NkCall`s |
 
 The AST is **built alongside** the existing lowering; nothing consumes it
 yet.  Each slice was gated by `build.sh` + `run_tests.sh` + `fixpoint.sh`,
@@ -25,10 +26,11 @@ production (removed before each commit).
 
 ## Not converted yet (still `NoNode`)
 
-- Statements: `CASE`, `WITH`, `INCL`/`EXCL`/`INC`/`DEC`/`NEW`/`DISPOSE`.
+- Statements: `CASE`, `WITH`.
 - Expressions: brace/set literals, `ResultComp` call suffixes.
-- Declarations: unit/`NkUnit` root, imports, `CLASS`, nested modules
-  (`CONST`/`TYPE`/`VAR`/`PROC` are done as of slice 6).
+- Declarations: imports, `CLASS`, nested modules in the unit AST
+  (`CONST`/`TYPE`/`VAR`/`PROC`, the `NkUnit` root and builtin statements
+  are done as of slices 6–7).
 - **`Lower` + `.ssa` byte-compare** (the point where the old emit path
   gets deleted) — not started.
 

+ 49 - 0
docs/summary_two-phase-slice7.md

@@ -0,0 +1,49 @@
+# Two-phase refactor — slice 7 (unit root + builtin statements)
+
+Branch `ast-stage-c`.  Suite **178/178**; self-hosting fixpoint **OK**
+(**3,016,802 bytes**; slice 6 was 3,007,851).
+
+## What landed
+
+### Unit root
+
+A module-level `astUnit` now holds `NkUnit(name, decls, body)` for
+DEFINITION, IMPLEMENTATION and program modules.  `decls` is the unit's
+`NkDeclSeq` (from `DeclSeq`) and `body` is the program/init `NkBlock`
+(or `NoNode`).  `ProgModule` and `ImplUnit` also reset `astStmt`/
+`astDecl` at entry, so the root never picks up a stale node.
+
+### Builtin statements
+
+`INCL`/`EXCL`, `INC`/`DEC`, `NEW` and `DISPOSE` now build `NkCall`s
+whose callee is an `NkIdent` naming the builtin, with the designator
+(and step/element expression) as children.  Node-building is inserted as
+extra actions around the existing emit actions, which are unchanged.
+
+## Verified (temporary `AST.Dump` of `astUnit`, then removed)
+
+```modula2
+VAR x : INTEGER; s : BITSET; p : POINTER TO INTEGER;
+BEGIN
+  INC(x); INCL(s, 1); NEW(p); DISPOSE(p)
+END
+```
+
+produced
+
+`NkUnit(Ident unitdump, NkDeclSeq[NkVarDecl x/s/p], NkBlock[
+  NkCall(INC, x), NkCall(INCL, s, 1), NkCall(NEW, p), NkCall(DISPOSE, p) ])`
+
+with each `NkVarDecl` carrying its `ty` index.
+
+## Deliberately deferred
+
+- Imports (`NkImport`), `CLASS` items, nested modules in the unit AST.
+- `CASE` and `WITH` statements.
+- Brace/set literals and `ResultComp` call suffixes.
+- `Lower` + `.ssa` byte-compare.
+
+## Next
+
+`CASE`/`WITH`; imports/`CLASS`; brace/set literals; then the `Lower`
+walk.

Некоторые файлы не были показаны из-за большого количества измененных файлов