Skip to content

Runs a source string as a program at execute - #161

Merged
johnnyt merged 2 commits into
mainfrom
pts-0zns-execute-program-mode
Oct 1, 2026
Merged

johnnyt merged 2 commits into
mainfrom
pts-0zns-execute-program-mode

Conversation

@johnnyt

@johnnyt johnnyt commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

execute and executeValue now compile a source string as a statement program, as the reference's execute/3 and execute_value/3 do at v9.4.2; evaluate still compiles an expression, as evaluate/3 does. Ruled by the operator, 2026-10-01: switch to match the reference, a named host-visible change.

Bead: pts-0zns.

What changes

  • src/index.ts: programOf takes the compiler as an argument; evaluate passes compile, execute and executeValue pass compileProgram. The three doc comments say so.
  • src/compile.ts: the compileProgram doc comment names execute and executeValue as the entry points that run a program (it said evaluate).
  • docs/adr/0004-the-compiler-surface.md: a dated Amendment at the foot, at proposed, add-only. It supersedes, for execute and executeValue only, the section "The three entry points take a source string" on compiling an expression, and is the "later change with its own record" the statement-grammar Amendment names.
  • changelog.d/pts-0zns.md: a ### Changed fragment.
  • README.md: the source-string paragraph and its example (see Provenance).
  • test/index.test.ts: the tests below.

Host-visible effects

Each row was run through this package after the change and, for the after column, through Predicator.execute_value/3 in an export of the reference at v9.4.2, which answered the same:

at source before after
execute, executeValue x = 1 assignment_in_expression runs, binding x
execute, executeValue score 3 trailing_token, "... after expression" trailing_token, "... after statement"
execute, executeValue if statement_keyword expected_primary at the end of input
executeValue score > 1, score bound to 5 value absent value true

The first row is a source the expression grammar refused that now runs; the second and third are a refusal that is now the program grammar's. The fourth follows from the same switch: an expression's source compiles to the expression's list followed by ["pop"], so executeValue answers its value. All three effects stand, each as the reference answers it (ruled by the operator, 2026-10-01), and the fragment names all three.

Tests changed, with old and new answers

  • "answers the compiler's own refusal on the failing arm, at all three" is now "answers the expression compiler's own refusal at evaluate": execute("x = 1") and executeValue("x = 1") answered assignment_in_expression; they now run (pinned in the new block).
  • "carries no context where the source did not compile" used execute("x = 1"), which now runs; it uses 3 = renewals at both entry points, refused by the program grammar.
  • "answers the absence at executeValue, whatever the expression evaluates to" is now "answers an expression source's value at executeValue": executeValue("score > 1", { score: 5 }) answered value undefined; the test now pins executeValue("loan.renewals > 1", { loan: { renewals: 2 } }) at value true, and execute on the same source still answers the context it was given.

New: a source the expression grammar refused runs at both; evaluate keeps refusing an assignment; four program_refusal rows of the compile transcript (stray-else/leading, not-a-location/literal, missing-block/if-token, after-statement/missing-separator) are answered verbatim at both entry points with their reasons; and for every corpus case with a source both grammars compile, the program is the expression's list plus ["pop"], execute's answer and executeValue's context or failing arm match the expression's list, and evaluate is unchanged.

Sabotage, each run and restored byte-equal, each caught on an assertion: execute back to compile; executeValue back to compile; evaluate to compileProgram; the refusal's message rewritten in programOf; a context handed back beside a refused source; executeValue answering the absence for a source.

Provenance

  • README.md was outside the brief's "leave it" scope only where it had to move: its executed example asserted execute("x = 1") is refused, which is now false and would fail the README test. The paragraph and that example now say evaluate compiles an expression and execute/executeValue a program; the parse/compile sentences elsewhere are untouched.
  • Not decided here, and stated in the Amendment: a refused source carries no context on the failing arm (the reference answers its normalized input context there), and an evaluation error's position stays the failing instruction's index rather than a source location (the reference runs a source with its positions tables).
  • Main moved under the branch three times. The first move was a foot Note on the same record; the branch was rebased before the Amendment was written, so the Amendment sits after that Note. The second was a change to the duration and parser sources (02d4a21); the branch was rebased onto it with no conflict. The third brought the export of DecompileResult, with its own ADR-0004 Amendment at the foot, and executeTagged on ./tagged, with a sentence in execute's doc comment pointing at it. The rebase onto 5afceb8 conflicted at the foot of ADR-0004 only; it was resolved keep-both, with this branch's Amendment after the DecompileResult Amendment and zero removed lines. Both sides changed execute's doc comment in different paragraphs: git merged them, and the comment keeps both the program-mode wording and the executeTagged pointer, which is true of both, since executeTagged also compiles a source string as a statement program. The full gate ran on the combined tree.

Cure 1

The review asked that the fixtures this branch added use the library world. The new tests now use loan.overdue, fines, patron.holds, 3 = renewals, status = 'late' at evaluate, and loan.renewals > 1. Fixtures that were already on main are untouched. The six sabotage checks above were re-run on the cured tests: each was caught on an assertion and restored byte-equal.

Record check

The Amendment adds 120 lines and removes none (git diff origin/main -- docs/adr/). Each claim was checked on this branch: the code split at programOf and the three entry points in src/index.ts; EvaluationError.position in src/errors.ts; the four rows in conformance/transcript/compile.json; the reference anchors evaluate/3 (Parser.parse), execute_value/3 (Parser.parse_program) and execute_value_ast in lib/predicator.ex at v9.4.2.

Gate

Full mise exec -- pnpm run gate green on the head after the rebase onto 5afceb8 (the combined tree): typecheck, lint, neutrality, 35 test files with 2837 tests passed, coverage, corpus:check, build, identity, resolution. The whole output is on the bead.

@johnnyt
johnnyt force-pushed the pts-0zns-execute-program-mode branch from 79e53d2 to d2be57b Compare October 1, 2026 12:49
execute and executeValue compile a source string with the statement
program compiler, as the reference's execute/3 and execute_value/3
do; evaluate still compiles an expression, as evaluate/3 does. An
expression's source runs as a one-statement program, so execute's
answer for it is unchanged, and executeValue now answers its value.

Tests pin the switch, the program grammar's refusals at both entry
points against their compile transcript rows, and the unchanged
answers over every corpus case with a source both grammars compile.
A dated Amendment to ADR-0004 records the decision (ruled by the
operator, 2026-10-01), and a Changed fragment names the host-visible
effects. The README example that showed execute refusing an
assignment now shows evaluate refusing it and execute running it.
The fixtures this branch added for execute, executeValue and evaluate
now use the library's loans, patrons and fines.
@johnnyt
johnnyt force-pushed the pts-0zns-execute-program-mode branch from d2be57b to 980187b Compare October 1, 2026 14:23
@johnnyt
johnnyt merged commit 8e20280 into main Oct 1, 2026
1 check passed
@johnnyt
johnnyt deleted the pts-0zns-execute-program-mode branch October 1, 2026 14:26
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