summary_two-phase-slice6.md 2.3 KB

Two-phase refactor — slice 6 (declarations → AST)

Branch ast-stage-c. Suite 178/178; self-hosting fixpoint OK (3,007,851 bytes; slice 5 was 3,000,988).

What landed

Declarations now build AST nodes. A module-level astDecl carries each declaration's node; DeclSeq folds them into an NkDeclSeq.

Declaration AST
DeclSeq NkDeclSeq of the contained declarations
CONST … NkDeclSeq of NkConstDecl(name=Ident, value=expr), ty = const type
TYPE T = … NkTypeDecl(name=Ident), ty = the resolved SymTab.TypeIndex
VAR x, y : T NkVarDecl(names = Ident… ), ty = the type index
PROCEDURE P … NkProcDecl(name=Ident, body), op = 0 normal / 1 forward / 2 external

Each block (CONST/VAR) that holds several declarations builds its own NkDeclSeq; DeclSeq adds one node per block. A leading astDecl := NoNode in DeclSeq/statement loops prevents stale results.

Design note — types by index, not by tree

Declaration nodes do not build structural type-constructor trees (NkRecord, NkArray, …). They record the resolved SymTab.TypeIndex in the node's ty field, which is exactly what AST.def intends (ty : a SymTab.TypeIndex set by the checker). This keeps declarations cheap and avoids duplicating the type table; a future Lower can read ty directly.

Block now resets astStmt := NoNode after its DeclSeq, so a procedure body with no BEGIN yields NoNode instead of a stale node from a nested declaration.

Verified (temporary AST.Dump, then removed)

CONST c = 5;
TYPE R = RECORD f : INTEGER END;
VAR x : INTEGER;
PROCEDURE P(a : INTEGER); BEGIN x := a END P;

produced an NkDeclSeq:

  • NkDeclSeq[ NkConstDecl(Ident c, 5) ty=INTEGER ]
  • NkTypeDecl(Ident R) ty=<record>
  • NkDeclSeq[ NkVarDecl(Ident x) ty=INTEGER ]
  • NkProcDecl(Ident P, NkBlock[ NkAssign(x, a) ])

Deliberately deferred

  • Unit roots (NkUnit), imports (NkImport), CLASS items and nested modules.
  • Remaining statements (CASE/WITH, builtins) and expressions (brace/set literals, ResultComp).
  • Lower + .ssa byte-compare.

Next

A unit/NkUnit root and imports, then the remaining statements, then the Lower walk (where declaration ty/body nodes finally replace the inline emit).