From e4ad1d4ef6a371c91721bb33b5ea90a34379c7f6 Mon Sep 17 00:00:00 2001 From: JohnnyT Date: Mon, 5 Oct 2026 05:40:14 -0600 Subject: [PATCH] Adds a guide to running a statement program A how-to page under docs/guides: compile a renewal script, execute it for a loan and read back the loan it leaves, ask executeValue for the last expression's value, and handle a script that fails, with the result each step shows. The README's Documentation map links it under Do in place of the Statement programs line, which moves to Look up, where its reference text belongs. Refs: pts-1tr8 --- README.md | 3 +- docs/guides/how-to-run-a-statement-program.md | 88 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 docs/guides/how-to-run-a-statement-program.md diff --git a/README.md b/README.md index 3d837d8..12a2453 100644 --- a/README.md +++ b/README.md @@ -76,12 +76,13 @@ failing arm of the result rather than as a throw; `ok` tells the two apart. - Do - [How to compile and evaluate a rule](https://github.com/riddler/predicator-ts/blob/main/docs/guides/how-to-compile-and-evaluate-a-rule.md): compile a rule's text, keep the instruction list, and decide the rule for one loan. - [Rendering a rule back](#rendering-a-rule-back): show an authored rule back to its author in a normalized form. - - [Statement programs](#statement-programs): run a short script that assigns into its context. + - [How to run a statement program](https://github.com/riddler/predicator-ts/blob/main/docs/guides/how-to-run-a-statement-program.md): execute a short script that changes a loan's fields, read back the loan it leaves, and handle a script that fails. - [Writing a location](#writing-a-location): write an assignment's location into your own data without running a program. - [How to add host functions](https://github.com/riddler/predicator-ts/blob/main/docs/guides/how-to-add-host-functions.md): let a rule call a function your application supplies, and handle a call that fails. - Look up - The API reference: every exported function and type, built into `docs/api/` by `mise exec -- pnpm run docs` in a clone of this repository. - [The entry points](#the-entry-points): the two import paths and what each one exports. + - [Statement programs](#statement-programs): what a program's statements can be, what `execute` and `executeValue` answer, and what a failing execution hands back. - [The value domain](#the-value-domain): each value type and its shape in TypeScript. - [Evaluation options](#evaluation-options): the options an evaluation takes, and their defaults. - [Host functions](#host-functions): how a host function's arguments and answer cross into the language's values, and how its name shadows a builtin. diff --git a/docs/guides/how-to-run-a-statement-program.md b/docs/guides/how-to-run-a-statement-program.md new file mode 100644 index 0000000..d1fa8b3 --- /dev/null +++ b/docs/guides/how-to-run-a-statement-program.md @@ -0,0 +1,88 @@ +# How to run a statement program + +This guide shows you how to execute a short script that changes a loan's +fields, and read back the loan it leaves. + +You start with `@riddler/predicator` installed and a renewal script as text: a +loan renewed fewer than twice gets one more renewal and fourteen more days, +and any other loan is marked refused. + +## Compile the script + +1. Import `compileProgram` and pass it the script's text. + + ```ts + import { compileProgram } from "@riddler/predicator"; + + const compiled = compileProgram( + "if loan.renewals < 2 { loan.renewals = loan.renewals + 1; loan.days_left = loan.days_left + 14 } else { loan.status = 'refused' }", + ); + ``` + + `compiled.ok` is `true`. + +2. Check `ok` before you use the result. + + ```ts + if (!compiled.ok) { + throw new Error(compiled.error.message); + } + ``` + + After the check, `compiled.instructions` is the instruction list, starting + `["load", "loan"], ["access", "renewals"], ["lit", 2]`. + +3. If the script does not compile, show the author where it failed. For + `compileProgram("loan.renewals + 1 = 2")`, `compiled.ok` is `false`, + `compiled.error.reason` is `"unassignable_location"` and + `compiled.error.position` is `{ line: 1, column: 19 }`, the `=` whose left + side cannot be written. + +## Execute the script for a loan + +1. Import `execute` and pass it the instruction list and a context holding the + loan. + + ```ts + import { execute } from "@riddler/predicator"; + + const loan = { renewals: 1, days_left: 3 }; + + const renewed = execute(compiled.instructions, { loan }); + ``` + + `renewed` is `{ ok: true, context: { loan: { renewals: 2, days_left: 17 } } }`: + the loan has one more renewal and fourteen more days. + +2. Read the changed loan from `renewed.context`. The `loan` you passed in is + unchanged: `loan.renewals` is still `1`. + +3. Execute it again for a loan already renewed twice. + + ```ts + const refused = execute(compiled.instructions, { + loan: { renewals: 2, days_left: 3 }, + }); + ``` + + `refused` is + `{ ok: true, context: { loan: { renewals: 2, days_left: 3, status: "refused" } } }`. + +4. If you also want a value back, end the script with that expression and call + `executeValue` instead. For the same script followed by `; loan.days_left`, + and the loan from step 1, the result's `value` is `17`. + +## Handle a script that fails + +1. Check `ok` before you read `context`. For a loan with no `days_left`, such + as `{ renewals: 1 }`, `ok` is `false`, `error.type` is + `"TypeMismatchError"` and `error.reason` is `"add"`. + +2. Decide what to keep. The failing result's `context` is + `{ loan: { renewals: 2 } }`, the writes made before the statement that + failed; to keep none of them, keep the loan you passed in. + +For what a program's statements can be, and the options `execute` takes, see +[Statement programs](https://github.com/riddler/predicator-ts/blob/main/README.md#statement-programs) +and +[Evaluation options](https://github.com/riddler/predicator-ts/blob/main/README.md#evaluation-options).