Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
88 changes: 88 additions & 0 deletions docs/guides/how-to-run-a-statement-program.md
Original file line number Diff line number Diff line change
@@ -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).
Loading