Sfoglia il codice sorgente

two-phase slice 13: CLASS declaration and implementation AST

CLASS T ... END T builds NkClassDecl(name, parents, fields, methods);
CLASS IMPLEMENTATION builds an op=1 NkClassDecl with method bodies and
an optional init body.  Fields are NkVarDecl/NkConstDecl, methods
NkProcDecl (op: normal/virtual/forward).  Module-level accumulators hold
the class being parsed.

Also fixes a latent slice-6 bug: TypeBlock never collected its items, so
only the last TYPE/CLASS declaration survived to DeclSeq; it now builds
an NkDeclSeq.  And ClassImplRest now sets child[1] before child[2]/[3]
(SetChild cannot skip an unset child) and resets astStmt before the
optional BEGIN.

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

See docs/summary_two-phase-slice13.md.
Eric Streit 1 settimana fa
parent
commit
f0b47014e0
4 ha cambiato i file con 3819 aggiunte e 3634 eliminazioni
  1. 85 16
      compiler/src/M2.atg
  2. 3681 3612
      compiler/src/M2.lst
  3. 8 6
      docs/plan-two-phase.md
  4. 45 0
      docs/summary_two-phase-slice13.md

+ 85 - 16
compiler/src/M2.atg

@@ -88,6 +88,12 @@ VAR
      nodes here; each unit stores them as NkUnit child[3]. *)
   astImp, astImpTail: AST.Node;
 
+  (* Class-AST accumulators (slice 13): the class node currently being
+     parsed and its parent/field/method lists.  Classes are not nested
+     inside one another, so module-level state is safe. *)
+  astCls, astClsP, astClsPTail, astClsF, astClsFTail,
+  astClsM, astClsMTail, astMethod: 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. *)
@@ -465,10 +471,16 @@ PRODUCTIONS
   (* Scalar-phase TYPEs: named types, integer subranges, enumerations.
      Opaque "TYPE T;" needs isDef (definition units); elsewhere 231.
      Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *)
-  TypeBlock<isDef: BOOLEAN>
-    = "TYPE"                            (. SymTab.BeginTypeBlock; .)
-      { TypeItem<isDef> ";" | ClassItem ";" }
-                                        (. SymTab.EndTypeBlock; .) .
+  TypeBlock<isDef: BOOLEAN>             (. VAR astSeq, astTail: AST.Node; .)
+    = "TYPE"                            (. SymTab.BeginTypeBlock;
+                                           astSeq := AST.NoNode;
+                                           astTail := AST.NoNode; .)
+      { (. astDecl := AST.NoNode; .)
+        ( TypeItem<isDef> ";" | ClassItem ";" )
+                                        (. AstAppend(AST.NkDeclSeq,
+                                             astSeq, astTail, astDecl); .) }
+                                        (. SymTab.EndTypeBlock;
+                                           astDecl := astSeq; .) .
   TypeItem<isDef: BOOLEAN>              (. VAR n: SymTab.Name;
                                              t, op: SymTab.TypeIndex;
                                              astNode: AST.Node; .)
@@ -805,7 +817,16 @@ PRODUCTIONS
                                              SemError(200) END;
                                            ct := SymTab.NewClass();
                                            SymTab.SetSymType(cn, ct);
-                                           SymTab.PushClassScope(ct); .)
+                                           SymTab.PushClassScope(ct);
+                                           astCls := AST.MakeNode(AST.NkClassDecl);
+                                           AST.SetChild(astCls, 0,
+                                             AST.MakeLeaf(AST.NkIdent, cn));
+                                           astClsP := AST.NoNode;
+                                           astClsPTail := AST.NoNode;
+                                           astClsF := AST.NoNode;
+                                           astClsFTail := AST.NoNode;
+                                           astClsM := AST.NoNode;
+                                           astClsMTail := AST.NoNode; .)
       [ Parents<ct> ]
       ";"
       { ClassField<ct> ";" }
@@ -816,7 +837,11 @@ PRODUCTIONS
       GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
                                              SemError(202) END;
                                            SymTab.LayoutClass(ct);
-                                           SymTab.PopScope; .) .
+                                           SymTab.PopScope;
+                                           AST.SetChild(astCls, 1, astClsP);
+                                           AST.SetChild(astCls, 2, astClsF);
+                                           AST.SetChild(astCls, 3, astClsM);
+                                           astDecl := astCls; .) .
   Parents<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name; .)
     = "(" Parent1<ct>
       { "," GetIdent<p>                 (. SemError(230); .) }
@@ -831,30 +856,59 @@ PRODUCTIONS
                                                SemError(230)
                                              ELSE SymTab.SetParent(ct, pt)
                                              END
-                                           END; .) .
+                                           END;
+                                           AstAppend(AST.NkFieldDecl,
+                                             astClsP, astClsPTail,
+                                             AST.MakeLeaf(AST.NkIdent, p)); .) .
   ClassField<ct: SymTab.TypeIndex>      (. VAR n, rhs: SymTab.Name;
-                                             t: SymTab.TypeIndex; .)
+                                             t: SymTab.TypeIndex;
+                                             astNode: AST.Node; .)
     = GetIdent<n>
       ( "=" GetIdent<rhs>               (. IF NOT SymTab.Enter(n,
                                              SymTab.KindConst) THEN
                                              SemError(200) END;
+                                           astNode := AST.MakeNode(AST.NkConstDecl);
+                                           AST.SetChild(astNode, 0,
+                                             AST.MakeLeaf(AST.NkIdent, n));
+                                           AST.SetChild(astNode, 1,
+                                             AST.MakeLeaf(AST.NkIdent, rhs));
+                                           AstAppend(AST.NkFieldDecl,
+                                             astClsF, astClsFTail, astNode);
                                            IF SymTab.Lookup(rhs) THEN
                                              SymTab.SetSymType(n,
                                                SymTab.SymType(rhs))
                                            END; .)
       |                                 (. IF NOT SymTab.FieldPending(ct,
                                              n) THEN
-                                             SemError(200) END; .)
+                                             SemError(200) END;
+                                           astNode := AST.MakeNode(AST.NkVarDecl);
+                                           AST.SetChild(astNode, 0,
+                                             AST.MakeLeaf(AST.NkIdent, n)); .)
         { "," GetIdent<n>               (. IF NOT SymTab.FieldPending(ct,
                                              n) THEN
-                                             SemError(200) END; .) }
-        ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t); .) ) .
+                                             SemError(200) END;
+                                           AST.SetChild(astNode,
+                                             AST.NChild(astNode),
+                                             AST.MakeLeaf(AST.NkIdent, n)); .) }
+        ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t);
+                                           AST.SetTy(astNode, t);
+                                           AstAppend(AST.NkFieldDecl,
+                                             astClsF, astClsFTail, astNode); .) ) .
   MethodHeading<VAR pn: SymTab.Name; ct: SymTab.TypeIndex>
                                         (. VAR wantVirt: BOOLEAN; .)
     =                                   (. wantVirt := FALSE; .)
       [ "VIRTUAL"                       (. wantVirt := TRUE; .) ]
       ProcHeading<pn, ct>               (. IF wantVirt THEN
-                                             SymTab.MarkVirtual END; .) .
+                                             SymTab.MarkVirtual END;
+                                           astMethod := AST.MakeNode(AST.NkProcDecl);
+                                           AST.SetChild(astMethod, 0,
+                                             AST.MakeLeaf(AST.NkIdent, pn));
+                                           IF wantVirt THEN
+                                             AST.SetOp(astMethod, 3)
+                                           ELSE AST.SetOp(astMethod, 0)
+                                           END;
+                                           AstAppend(AST.NkFieldDecl,
+                                             astClsM, astClsMTail, astMethod); .) .
   ClassImplRest                         (. VAR cn, m2: SymTab.Name;
                                              ct: SymTab.TypeIndex; .)
     = GetIdent<cn>                      (. IF NOT SymTab.Lookup(cn) THEN
@@ -867,6 +921,13 @@ PRODUCTIONS
                                                ct := SymTab.InvalidType
                                              END
                                            END;
+                                           astCls := AST.MakeNode(AST.NkClassDecl);
+                                           AST.SetOp(astCls, 1);
+                                           AST.SetChild(astCls, 0,
+                                             AST.MakeLeaf(AST.NkIdent, cn));
+                                           astClsM := AST.NoNode;
+                                           astClsMTail := AST.NoNode;
+                                           astStmt := AST.NoNode;
                                            IF ct #
                                               SymTab.InvalidType THEN
                                              IF NOT SymTab.PushClassMembers(
@@ -875,13 +936,19 @@ PRODUCTIONS
                                              SymTab.PushImplClass(ct)
                                            END; .)
       ";" { MethodImpl<ct> ";" }
-      [ "BEGIN"                         (. QbeGen.BeginInit(cn); .)
+                                        (. astStmt := AST.NoNode; .)
+      [ "BEGIN"                         (. astStmt := AST.NoNode;
+                                           QbeGen.BeginInit(cn); .)
         [ StatSeq ]                     (. QbeGen.EndInit; .) ]
       "END"
       GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
                                              SemError(202) END;
                                            SymTab.PopImplClass;
-                                           SymTab.PopScope; .) .
+                                           SymTab.PopScope;
+                                           AST.SetChild(astCls, 1, AST.NoNode);
+                                           AST.SetChild(astCls, 2, astStmt);
+                                           AST.SetChild(astCls, 3, astClsM);
+                                           astDecl := astCls; .) .
   MethodImpl<ct: SymTab.TypeIndex>      (. VAR pn: SymTab.Name;
                                              thisQ: QbeGen.QVal;
                                              methRes: SymTab.TypeIndex; .)
@@ -891,7 +958,8 @@ PRODUCTIONS
  AND NOT SymTab.MethodExists(ct,
                                                   pn) THEN
                                              SemError(201) END; .)
-      ( "FORWARD"                       (. SymTab.MarkFwd;
+      ( "FORWARD"                       (. AST.SetOp(astMethod, 1);
+                                           SymTab.MarkFwd;
                                            QbeGen.AbortFunc;
                                            SymTab.CloseProc; .)
       |                                 (. QbeGen.EndFuncHeader;
@@ -900,7 +968,8 @@ PRODUCTIONS
                                               against THIS *)
                                            QbeGen.ThisBase(thisQ);
                                            QbeGen.PushWith(thisQ); .)
-        Block<pn>                       (. QbeGen.PopWith;
+        Block<pn>                       (. AST.SetChild(astMethod, 1, astStmt);
+                                           QbeGen.PopWith;
                                            methRes := SymTab.CurRes();
                                            SymTab.CloseProc;
                                            QbeGen.EndFunc(methRes); .) ) .

File diff suppressed because it is too large
+ 3681 - 3612
compiler/src/M2.lst


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

@@ -92,12 +92,14 @@ Suggested slices, each ending in `build.sh` + `run_tests.sh` +
    `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: `CLASS` items (no class declarations in the compiler's own
-   sources); `Lower`.  Also `docs/summary_two-phase-slice8.md`
-   (`CASE`/`WITH`), `docs/summary_two-phase-slice9.md` (brace/set
-   literals), `docs/summary_two-phase-slice10.md` (`ResultComp` +
-   unbounded `NkBlock`/`NkDeclSeq`), `docs/summary_two-phase-slice11.md`
-   (imports) and `docs/summary_two-phase-slice12.md` (nested modules).
+   Done.  `docs/summary_two-phase-slice8.md` (`CASE`/`WITH`),
+   `docs/summary_two-phase-slice9.md` (brace/set literals),
+   `docs/summary_two-phase-slice10.md` (`ResultComp` + unbounded
+   `NkBlock`/`NkDeclSeq`), `docs/summary_two-phase-slice11.md` (imports),
+   `docs/summary_two-phase-slice12.md` (nested modules) and
+   `docs/summary_two-phase-slice13.md` (`CLASS`, + a `TypeBlock`
+   collection bug fix).  Remaining: `Lower` + byte-compare, and the
+   `MaxChild` cap on `CASE` arms / `WITH` designators / call actuals.
 5. **Flip**: bodies lower from the AST; delete `FwdPatchAll` /
    `FixLoadClass` / `FixStoreClass`, the `Design` forward-variable
    placeholder, and `pendVar*` if superseded.

+ 45 - 0
docs/summary_two-phase-slice13.md

@@ -0,0 +1,45 @@
+# Two-phase refactor — slice 13 (CLASS)
+
+Branch `ast-stage-c`.  Suite **178/178**; self-hosting fixpoint **OK**
+(**3,042,040 bytes**; slice 12 was 3,034,200).
+
+## What landed
+
+| Construct | AST |
+| --- | --- |
+| `CLASS T; … END T;` | `NkClassDecl(name, parents, fields, methods)`, `op = 0` |
+| `CLASS IMPLEMENTATION T; … END T;` | `NkClassDecl(…, initBody, methodsWithBodies)`, `op = 1` |
+| class field/const | `NkVarDecl` (`ty`) / `NkConstDecl` |
+| method heading | `NkProcDecl`, `op = 0` normal / `3` virtual / `1` forward |
+| method implementation | `NkProcDecl` with the body as child 1 |
+
+Module-level accumulators (`astCls`, `astClsP/F/M` + tails, `astMethod`)
+carry the class being parsed; classes are not nested inside one another,
+so this is safe.  `ClassRest` and `ClassImplRest` attach
+`child[1] = parents`, `child[2] = fields`/init body, `child[3] =
+methods`, and set `astDecl` so `DeclSeq`/`TypeBlock` record the class.
+
+## Two bugs found while verifying (both fixed here)
+
+1. **`TypeBlock` never collected its items.**  It ran `TypeItem`/`ClassItem`
+   in a loop but only the *last* one's `astDecl` survived to `DeclSeq` — a
+   latent slice-6 bug (my earlier test had a single type).  `TypeBlock` now
+   builds an `NkDeclSeq` like `ConstBlock`/`VarBlock`, so all `TYPE` and
+   class declarations are recorded.
+2. **`AST.SetChild` cannot skip an unset child.**  The implementation
+   class set `child[2]`/`child[3]` while `child[1]` was unset, so the
+   methods and init body were silently dropped; `child[1]` is now set to
+   `NoNode` first.  Also reset `astStmt` before the optional class-`BEGIN`
+   so a body-less implementation does not inherit the last method's body.
+
+## Verified (temporary `AST.Dump`, then removed)
+
+`tests/t_classmethod.mod` produced an `NkClassDecl` (op 0) with
+`NkFieldDecl[x, y]` and methods `Set`/`Sum`/`CopyX`, plus the
+implementation `NkClassDecl` (op 1) whose methods carry their bodies.
+
+## Next
+
+Step 2 (imports, `CLASS`, nested modules) is now complete.  Remaining:
+the `Lower` walk + `.ssa` byte-compare, and the `MaxChild` cap on
+`CASE` arms / `WITH` designators / call actuals.

Some files were not shown because too many files changed in this diff