Skip to content

Adds the statement program compiler - #157

Merged
johnnyt merged 2 commits into
mainfrom
pts-xmz6-compile-program-statement-grammar
Oct 1, 2026
Merged

johnnyt merged 2 commits into
mainfrom
pts-xmz6-compile-program-statement-grammar

Conversation

@johnnyt

@johnnyt johnnyt commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Why

The package compiled the expression grammar only. A statechart's script element holds a statement program, and the reference compiles one through compile_program/1, compile_program_with_positions/1 and compile_program_with_spans/1. The lexer already tokenized the separator and the three statement keywords and the evaluator already ran store, pop and the jumps; the grammar and the emission were missing. The scope is the reference's full statement grammar, and its evidence is the program rows of the compile transcript taken from the reference at v9.4.2 (both ruled by the operator, 2026-10-01).

What

  • compileProgram, compileProgramWithPositions and compileProgramWithSpans, exported from the main entry and pinned in test/export-surface.json. Each answers its expression counterpart's result union; the two located variants carry one more member on the succeeding arm, segmentPositions or segmentSpans, keyed by each store's index with one annotation per location segment (the reference's segment_positions). A refusal is a ParseError value, never a throw.
  • parseProgram in src/parser.ts: statement sequences with an optional trailing separator, assignment to an identifier, a property access or a bracket access (probed as an additive expression, refused at the = otherwise), if / else / else if, while, bare expressions, and no separator needed after a statement ending in }.
  • emitProgram in src/emitter.ts: the reference's instructions visitor for statements - location segments root first, store n, pop after a bare expression, the relative jumps of if, if/else and while - with the positions, spans and segment tables built in one walk. A store is positioned at the location's root and spanned over the whole assignment, as the reference annotates it.
  • ParseReason gains unexpected_else, unassignable_location and expected_open_brace. The program grammar's other two wordings map to members already in the union: Unexpected token X after statement to trailing_token, and Expected '}' to close the block but found X to expected_close_brace.
  • The depth bound applies to programs: nested blocks and else if links count against the declared source limit in both walks; a statement sequence's length costs no depth.
  • ADR-0004 carries a dated Amendment at proposed, appended (zero removed lines). README gains a compileProgram example (executed by the README suite) and drops the sentence saying statement compilation was not implemented. Changelog fragment changelog.d/pts-xmz6.md (Added).
  • Unchanged: compile, compileWithPositions, compileWithSpans, parse, evaluate, execute, executeValue and decompile answer as before; conformance/registry.json, the vendored corpus and the transcript are untouched.

Evidence

  • test/reference-compile.test.ts reads every program row through the stamped reader and holds compileProgramWithSpans to it exactly: the instruction list compared as values, the spans table and the segment table entry by entry. Every program_refusal row is held to compileProgram's message (verbatim), position and span, with the reason a member of the closed union.
  • The rows carry the reference's span tables only, so the point tables were checked by running Predicator.compile_program_with_positions/1 in a detached export of predicator-ex at v9.4.2 over every program the rows hold; every table agreed. test/compile-program.test.ts pins a selection of them, each quoted as the run printed it, plus one source per refusal family pinned to its reason, the depth bound, and the unchanged expression entry points.
  • Sabotage, each check run singly, the file restored from a copy and proven byte-equal: dropping the jump ending a then block, the pop after a bare expression, or the while back edge each turned the program-row suite red on an assertion; so did a store spanned from the =, a bracket segment annotated with its access node, a store positioned at the =, a property segment annotated with its root, rewording the stray-else or the unassignable-location message, refusing a trailing separator inside a block, and giving the stray else or the unterminated block another reason. Removing the parser's block-level depth count alone survived, because the emitter still refuses; removing it together with the emitter's level per if turned the depth test red, and the same held for the else if chain.

Provenance

Engineering choices made in this change, each recorded in the Amendment:

  • The segment table is a separate member named for its annotation kind (segmentPositions / segmentSpans) rather than a reshaped positions, so each located result is a subtype of its expression counterpart. No name is exported for the two result types; no new type name joins the entry.
  • Two statement-grammar wordings join existing reason members under the union's existing rule (one template up to the token and the construct it names is one family); three families the union lacked get new members.
  • An else if chain counts a level per link, since the tree nests it; the Amendment declares this as the one flat construct of the program grammar whose length is bounded.
  • The rebases onto main crossed two merged requests, the one that declares the duration divergences and the one that refuses a duration component past the safe range; neither rebase conflicted, and the full gate ran green on the rebased head each time.

Notes

  • Gate: the full pnpm run gate is green on the rebased head (typecheck, lint, engine neutrality, the suite with coverage, corpus check, build, cross-entry identity, legacy resolution). The whole output is on the bead rather than here, because it prints local paths.
  • Review tier: this is a contract-surface change; the cold pass is the conductor's.
  • Review: the first direction pass found one blocking line, the Amendment naming the commit this branch was cut from, which the rebase had made false. That clause is removed (the line is this change's own text, so the record still shows zero removed lines against main).

Closes pts-xmz6

Adds compileProgram, compileProgramWithPositions and
compileProgramWithSpans: the reference's statement grammar at v9.4.2
(assignment to an identifier, a property or an index, the separator,
if/else and else if, while, bare expressions) parsed by parseProgram
and emitted by the emitter's program walk. Each answers the result
union of its expression counterpart; the located variants add a
segment table per store.

Every program row of the compile transcript is reproduced exactly,
read through the stamped reader. ParseReason gains unexpected_else,
unassignable_location and expected_open_brace. The compiler-surface
record carries a proposed Amendment; the expression entry points and
the conformance registry are unchanged.

Refs: pts-xmz6
The Amendment's first paragraph named the commit the branch was cut
from, which a rebase made false. The clause is removed; the
transcript citation at its stated commit stands.

Refs: pts-xmz6
@johnnyt
johnnyt force-pushed the pts-xmz6-compile-program-statement-grammar branch from 24e3b66 to 8aeb63f Compare October 1, 2026 12:27
@johnnyt
johnnyt merged commit ea1d274 into main Oct 1, 2026
1 check passed
@johnnyt
johnnyt deleted the pts-xmz6-compile-program-statement-grammar branch October 1, 2026 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant