summary_two-phase-slice5.md 2.8 KB

Two-phase refactor — slice 5 (statements → AST)

Branch ast-stage-c. Suite 178/178; self-hosting fixpoint OK (3,000,988 bytes; slice 4 was 2,987,484).

What landed

Statements now build AST nodes. A module-level astStmt carries each statement's node; StatSeq folds them into an NkBlock.

Statement AST
StatSeq NkBlock of the contained statements
x := e NkAssign (child 0 = designator, 1 = value)
P(…) / P statement NkCall (shared AstCallNode helper)
IF … THEN … ELSIF … ELSE … END NkIf chain: each ELSIF becomes the else child of the previous NkIf
WHILE c DO … END NkWhile(cond, body)
REPEAT … UNTIL c NkRepeat(body, cond)
LOOP … END NkLoop(body)
EXIT NkExit
FOR v := lo TO hi [BY s] DO … END NkFor(var, lo, hi, by, body)
RETURN [e] NkReturn([e])
HALT [(e)] NkHalt([e])

The IF/ELSIF chain is built incrementally (one NkIf per clause, linked through the else child) rather than with a local array — see the finding below.

Finding — local arrays are miscompiled (pre-existing)

While self-hosting this slice, the IfStat VAR … ARRAY [0..7] OF AST.Node locals exposed a pre-existing V3 codegen bug: a local ARRAY inside a PROCEDURE is miscompiled.

PROCEDURE P;
  VAR a : ARRAY [0..3] OF INTEGER; i : INTEGER;
BEGIN
  i := 0;
  WHILE i < 4 DO a[i] := i * 10; INC(i) END;
  ExitCode := a[0] + a[1] + a[2] + a[3]   (* want 60, got 1 *)
END P;

Module-level arrays are fine; local ones are not. Repro parked in docs/wip/local-array-bug.mod. It is not caused by this refactor (the code is inert and does not touch local-array lowering); it was merely triggered by using local arrays in the grammar. The grammar now uses scalars/globals. This should be a dedicated fix (like the array-of-record stride bug from Stage A).

Verified (temporary AST.Dump of the body, then removed)

A program with assignment, IF/ELSE, WHILE, FOR (no BY) and a statement call produced the expected NkBlock:

  • NkAssign(NkDesignator x, 1)
  • NkIf(Lt(x,2), Block[Assign(x,3)], Block[Assign(x,4)])
  • NkWhile(Lt(x,5), Block[Assign(x, x+1)])
  • NkFor(Ident i, 1, 3, nil, Block[Assign(x, x+i)])
  • NkCall(NkDesignator P, NkDesignator x)

Deliberately deferred

  • CASE and WITH statements: explicit astStmt := NoNode.
  • Builtin statements INCL/EXCL/INC/DEC/NEW/DISPOSE: they do not set astStmt (the Statement leading reset leaves NoNode).
  • Brace/set literals and ResultComp call suffixes (from slice 4).
  • Lower + .ssa byte-compare (not started).

Next

Declarations (CONST/TYPE/VAR/PROC bodies → AST), then CASE/ WITH/builtin statements and brace/set literals, then the Lower walk.