From 02845d13b095f875fdc0b24311fbde264ccbf6aa Mon Sep 17 00:00:00 2001 From: JohnnyT Date: Mon, 5 Oct 2026 05:25:41 -0600 Subject: [PATCH] Adds a guide to compiling and evaluating a rule A how-to page under docs/guides: compile a rule's text, keep the instruction list as JSON (or the tagged encoding when it carries a date, a datetime or a float), and evaluate it for one loan, with the result each step shows. The README's Documentation map links it under Do. Refs: pts-3rn1 --- README.md | 1 + .../how-to-compile-and-evaluate-a-rule.md | 96 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 docs/guides/how-to-compile-and-evaluate-a-rule.md diff --git a/README.md b/README.md index 44c09eb..2af0f79 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ failing arm of the result rather than as a throw; `ok` tells the two apart. - [Basic usage](#basic-usage): a rule compiled once and evaluated against two loans. - [Compiling a rule](#compiling-a-rule): a rule compiled, run and refused, with each result checked. - 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. - [Writing a location](#writing-a-location): write an assignment's location into your own data without running a program. diff --git a/docs/guides/how-to-compile-and-evaluate-a-rule.md b/docs/guides/how-to-compile-and-evaluate-a-rule.md new file mode 100644 index 0000000..89fda92 --- /dev/null +++ b/docs/guides/how-to-compile-and-evaluate-a-rule.md @@ -0,0 +1,96 @@ +# How to compile and evaluate a rule + +This guide shows you how to turn a rule a librarian writes into an instruction +list, keep that list, and decide the rule for one loan. + +You start with `@riddler/predicator` installed and the rule as text: here, a +copy counts as lost when its loan is more than thirty days overdue and the copy +is still checked out. + +## Compile the rule + +1. Import `compile` and pass it the rule's text. + + ```ts + import { compile } from "@riddler/predicator"; + + const compiled = compile("loan.days_overdue > 30 AND copy.status == 'checked_out'"); + ``` + + `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", "days_overdue"], ["lit", 30]`. + +3. If the rule does not compile, show the author where it failed. For + `compile("loan.days_overdue > ")`, `compiled.ok` is `false`, + `compiled.error.reason` is `"expected_primary"` and + `compiled.error.position` is `{ line: 1, column: 21 }`, the place the text + ran out. + +## Keep the instruction list + +1. Store or send the list as JSON. + + ```ts + const stored = JSON.stringify(compiled.instructions); + ``` + + `stored` is a JSON array of arrays that starts `[["load","loan"],`. + +2. Read it back where the rule is decided. + + ```ts + const instructions = JSON.parse(stored); + ``` + + `instructions` holds the same list `compile` answered. + +If the rule carries a date, a datetime or a float, plain JSON does not keep it: +store the `text` that `encodeTagged(compiled.instructions)` answers instead, +and read it back with `decodeTagged`, both from `@riddler/predicator/tagged` +([the tagged subpath](https://github.com/riddler/predicator-ts/blob/main/README.md#the-tagged-subpath)). + +## Evaluate the rule for a loan + +1. Import `evaluate` and pass it the instruction list and a context that binds + every name the rule reads. + + ```ts + import { evaluate } from "@riddler/predicator"; + + const decision = evaluate(instructions, { + loan: { days_overdue: 45 }, + copy: { status: "checked_out" }, + }); + ``` + + `decision` is `{ ok: true, value: true }`: this copy counts as lost. + +2. Evaluate it again for a copy that has come back. + + ```ts + const returned = evaluate(instructions, { + loan: { days_overdue: 45 }, + copy: { status: "returned" }, + }); + ``` + + `returned` is `{ ok: true, value: false }`. + +3. Check `ok` before you read `value`. For a context that leaves `loan` out, + `ok` is `false`, `error.type` is `"UndefinedVariableError"` and + `error.reason` is `"unbound_variable"`. + +For what a failed evaluation carries and the options `evaluate` takes, see +[Evaluating a rule](https://github.com/riddler/predicator-ts/blob/main/README.md#evaluating-a-rule) +and +[Evaluation options](https://github.com/riddler/predicator-ts/blob/main/README.md#evaluation-options).