@rcrsr/rill 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +69 -0
- package/dist/cli.js.map +1 -0
- package/dist/demo.d.ts +6 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/demo.js +121 -0
- package/dist/demo.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/lexer/errors.d.ts +9 -0
- package/dist/lexer/errors.d.ts.map +1 -0
- package/dist/lexer/errors.js +12 -0
- package/dist/lexer/errors.js.map +1 -0
- package/dist/lexer/helpers.d.ts +14 -0
- package/dist/lexer/helpers.d.ts.map +1 -0
- package/dist/lexer/helpers.js +30 -0
- package/dist/lexer/helpers.js.map +1 -0
- package/dist/lexer/index.d.ts +8 -0
- package/dist/lexer/index.d.ts.map +1 -0
- package/dist/lexer/index.js +8 -0
- package/dist/lexer/index.js.map +1 -0
- package/dist/lexer/operators.d.ts +11 -0
- package/dist/lexer/operators.d.ts.map +1 -0
- package/dist/lexer/operators.js +58 -0
- package/dist/lexer/operators.js.map +1 -0
- package/dist/lexer/readers.d.ts +12 -0
- package/dist/lexer/readers.d.ts.map +1 -0
- package/dist/lexer/readers.js +144 -0
- package/dist/lexer/readers.js.map +1 -0
- package/dist/lexer/state.d.ts +18 -0
- package/dist/lexer/state.d.ts.map +1 -0
- package/dist/lexer/state.js +37 -0
- package/dist/lexer/state.js.map +1 -0
- package/dist/lexer/tokenizer.d.ts +9 -0
- package/dist/lexer/tokenizer.d.ts.map +1 -0
- package/dist/lexer/tokenizer.js +100 -0
- package/dist/lexer/tokenizer.js.map +1 -0
- package/dist/lexer.d.ts +19 -0
- package/dist/lexer.d.ts.map +1 -0
- package/dist/lexer.js +344 -0
- package/dist/lexer.js.map +1 -0
- package/dist/parser/arithmetic.d.ts +16 -0
- package/dist/parser/arithmetic.d.ts.map +1 -0
- package/dist/parser/arithmetic.js +128 -0
- package/dist/parser/arithmetic.js.map +1 -0
- package/dist/parser/boolean.d.ts +15 -0
- package/dist/parser/boolean.d.ts.map +1 -0
- package/dist/parser/boolean.js +20 -0
- package/dist/parser/boolean.js.map +1 -0
- package/dist/parser/control-flow.d.ts +56 -0
- package/dist/parser/control-flow.d.ts.map +1 -0
- package/dist/parser/control-flow.js +167 -0
- package/dist/parser/control-flow.js.map +1 -0
- package/dist/parser/expressions.d.ts +23 -0
- package/dist/parser/expressions.d.ts.map +1 -0
- package/dist/parser/expressions.js +950 -0
- package/dist/parser/expressions.js.map +1 -0
- package/dist/parser/extraction.d.ts +48 -0
- package/dist/parser/extraction.d.ts.map +1 -0
- package/dist/parser/extraction.js +279 -0
- package/dist/parser/extraction.js.map +1 -0
- package/dist/parser/functions.d.ts +20 -0
- package/dist/parser/functions.d.ts.map +1 -0
- package/dist/parser/functions.js +96 -0
- package/dist/parser/functions.js.map +1 -0
- package/dist/parser/helpers.d.ts +94 -0
- package/dist/parser/helpers.d.ts.map +1 -0
- package/dist/parser/helpers.js +225 -0
- package/dist/parser/helpers.js.map +1 -0
- package/dist/parser/index.d.ts +49 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +73 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/literals.d.ts +37 -0
- package/dist/parser/literals.d.ts.map +1 -0
- package/dist/parser/literals.js +373 -0
- package/dist/parser/literals.js.map +1 -0
- package/dist/parser/parser-collect.d.ts +16 -0
- package/dist/parser/parser-collect.d.ts.map +1 -0
- package/dist/parser/parser-collect.js +125 -0
- package/dist/parser/parser-collect.js.map +1 -0
- package/dist/parser/parser-control.d.ts +20 -0
- package/dist/parser/parser-control.d.ts.map +1 -0
- package/dist/parser/parser-control.js +120 -0
- package/dist/parser/parser-control.js.map +1 -0
- package/dist/parser/parser-expr.d.ts +37 -0
- package/dist/parser/parser-expr.d.ts.map +1 -0
- package/dist/parser/parser-expr.js +639 -0
- package/dist/parser/parser-expr.js.map +1 -0
- package/dist/parser/parser-extract.d.ts +17 -0
- package/dist/parser/parser-extract.d.ts.map +1 -0
- package/dist/parser/parser-extract.js +222 -0
- package/dist/parser/parser-extract.js.map +1 -0
- package/dist/parser/parser-functions.d.ts +21 -0
- package/dist/parser/parser-functions.d.ts.map +1 -0
- package/dist/parser/parser-functions.js +155 -0
- package/dist/parser/parser-functions.js.map +1 -0
- package/dist/parser/parser-literals.d.ts +22 -0
- package/dist/parser/parser-literals.d.ts.map +1 -0
- package/dist/parser/parser-literals.js +288 -0
- package/dist/parser/parser-literals.js.map +1 -0
- package/dist/parser/parser-script.d.ts +21 -0
- package/dist/parser/parser-script.d.ts.map +1 -0
- package/dist/parser/parser-script.js +174 -0
- package/dist/parser/parser-script.js.map +1 -0
- package/dist/parser/parser-variables.d.ts +20 -0
- package/dist/parser/parser-variables.d.ts.map +1 -0
- package/dist/parser/parser-variables.js +146 -0
- package/dist/parser/parser-variables.js.map +1 -0
- package/dist/parser/parser.d.ts +49 -0
- package/dist/parser/parser.d.ts.map +1 -0
- package/dist/parser/parser.js +54 -0
- package/dist/parser/parser.js.map +1 -0
- package/dist/parser/script.d.ts +14 -0
- package/dist/parser/script.d.ts.map +1 -0
- package/dist/parser/script.js +196 -0
- package/dist/parser/script.js.map +1 -0
- package/dist/parser/state.d.ts +40 -0
- package/dist/parser/state.d.ts.map +1 -0
- package/dist/parser/state.js +129 -0
- package/dist/parser/state.js.map +1 -0
- package/dist/parser/variables.d.ts +10 -0
- package/dist/parser/variables.d.ts.map +1 -0
- package/dist/parser/variables.js +215 -0
- package/dist/parser/variables.js.map +1 -0
- package/dist/runtime/ast-equals.d.ts +13 -0
- package/dist/runtime/ast-equals.d.ts.map +1 -0
- package/dist/runtime/ast-equals.js +447 -0
- package/dist/runtime/ast-equals.js.map +1 -0
- package/dist/runtime/builtins.d.ts +13 -0
- package/dist/runtime/builtins.d.ts.map +1 -0
- package/dist/runtime/builtins.js +180 -0
- package/dist/runtime/builtins.js.map +1 -0
- package/dist/runtime/callable.d.ts +88 -0
- package/dist/runtime/callable.d.ts.map +1 -0
- package/dist/runtime/callable.js +98 -0
- package/dist/runtime/callable.js.map +1 -0
- package/dist/runtime/context.d.ts +13 -0
- package/dist/runtime/context.d.ts.map +1 -0
- package/dist/runtime/context.js +73 -0
- package/dist/runtime/context.js.map +1 -0
- package/dist/runtime/core/callable.d.ts +171 -0
- package/dist/runtime/core/callable.d.ts.map +1 -0
- package/dist/runtime/core/callable.js +246 -0
- package/dist/runtime/core/callable.js.map +1 -0
- package/dist/runtime/core/context.d.ts +29 -0
- package/dist/runtime/core/context.d.ts.map +1 -0
- package/dist/runtime/core/context.js +154 -0
- package/dist/runtime/core/context.js.map +1 -0
- package/dist/runtime/core/equals.d.ts +9 -0
- package/dist/runtime/core/equals.d.ts.map +1 -0
- package/dist/runtime/core/equals.js +381 -0
- package/dist/runtime/core/equals.js.map +1 -0
- package/dist/runtime/core/eval/base.d.ts +65 -0
- package/dist/runtime/core/eval/base.d.ts.map +1 -0
- package/dist/runtime/core/eval/base.js +112 -0
- package/dist/runtime/core/eval/base.js.map +1 -0
- package/dist/runtime/core/eval/evaluator.d.ts +47 -0
- package/dist/runtime/core/eval/evaluator.d.ts.map +1 -0
- package/dist/runtime/core/eval/evaluator.js +73 -0
- package/dist/runtime/core/eval/evaluator.js.map +1 -0
- package/dist/runtime/core/eval/index.d.ts +57 -0
- package/dist/runtime/core/eval/index.d.ts.map +1 -0
- package/dist/runtime/core/eval/index.js +95 -0
- package/dist/runtime/core/eval/index.js.map +1 -0
- package/dist/runtime/core/eval/mixins/annotations.d.ts +19 -0
- package/dist/runtime/core/eval/mixins/annotations.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/annotations.js +146 -0
- package/dist/runtime/core/eval/mixins/annotations.js.map +1 -0
- package/dist/runtime/core/eval/mixins/closures.d.ts +49 -0
- package/dist/runtime/core/eval/mixins/closures.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/closures.js +479 -0
- package/dist/runtime/core/eval/mixins/closures.js.map +1 -0
- package/dist/runtime/core/eval/mixins/collections.d.ts +24 -0
- package/dist/runtime/core/eval/mixins/collections.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/collections.js +466 -0
- package/dist/runtime/core/eval/mixins/collections.js.map +1 -0
- package/dist/runtime/core/eval/mixins/control-flow.d.ts +27 -0
- package/dist/runtime/core/eval/mixins/control-flow.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/control-flow.js +369 -0
- package/dist/runtime/core/eval/mixins/control-flow.js.map +1 -0
- package/dist/runtime/core/eval/mixins/core.d.ts +24 -0
- package/dist/runtime/core/eval/mixins/core.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/core.js +335 -0
- package/dist/runtime/core/eval/mixins/core.js.map +1 -0
- package/dist/runtime/core/eval/mixins/expressions.d.ts +19 -0
- package/dist/runtime/core/eval/mixins/expressions.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/expressions.js +202 -0
- package/dist/runtime/core/eval/mixins/expressions.js.map +1 -0
- package/dist/runtime/core/eval/mixins/extraction.d.ts +10 -0
- package/dist/runtime/core/eval/mixins/extraction.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/extraction.js +250 -0
- package/dist/runtime/core/eval/mixins/extraction.js.map +1 -0
- package/dist/runtime/core/eval/mixins/literals.d.ts +23 -0
- package/dist/runtime/core/eval/mixins/literals.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/literals.js +180 -0
- package/dist/runtime/core/eval/mixins/literals.js.map +1 -0
- package/dist/runtime/core/eval/mixins/types.d.ts +20 -0
- package/dist/runtime/core/eval/mixins/types.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/types.js +109 -0
- package/dist/runtime/core/eval/mixins/types.js.map +1 -0
- package/dist/runtime/core/eval/mixins/variables.d.ts +34 -0
- package/dist/runtime/core/eval/mixins/variables.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/variables.js +247 -0
- package/dist/runtime/core/eval/mixins/variables.js.map +1 -0
- package/dist/runtime/core/eval/types.d.ts +41 -0
- package/dist/runtime/core/eval/types.d.ts.map +1 -0
- package/dist/runtime/core/eval/types.js +10 -0
- package/dist/runtime/core/eval/types.js.map +1 -0
- package/dist/runtime/core/evaluate.d.ts +42 -0
- package/dist/runtime/core/evaluate.d.ts.map +1 -0
- package/dist/runtime/core/evaluate.debug.js +1251 -0
- package/dist/runtime/core/evaluate.js +1913 -0
- package/dist/runtime/core/evaluate.js.map +1 -0
- package/dist/runtime/core/execute.d.ts +26 -0
- package/dist/runtime/core/execute.d.ts.map +1 -0
- package/dist/runtime/core/execute.js +177 -0
- package/dist/runtime/core/execute.js.map +1 -0
- package/dist/runtime/core/signals.d.ts +19 -0
- package/dist/runtime/core/signals.d.ts.map +1 -0
- package/dist/runtime/core/signals.js +26 -0
- package/dist/runtime/core/signals.js.map +1 -0
- package/dist/runtime/core/types.d.ts +177 -0
- package/dist/runtime/core/types.d.ts.map +1 -0
- package/dist/runtime/core/types.js +50 -0
- package/dist/runtime/core/types.js.map +1 -0
- package/dist/runtime/core/values.d.ts +66 -0
- package/dist/runtime/core/values.d.ts.map +1 -0
- package/dist/runtime/core/values.js +240 -0
- package/dist/runtime/core/values.js.map +1 -0
- package/dist/runtime/evaluate.d.ts +32 -0
- package/dist/runtime/evaluate.d.ts.map +1 -0
- package/dist/runtime/evaluate.js +1111 -0
- package/dist/runtime/evaluate.js.map +1 -0
- package/dist/runtime/execute.d.ts +26 -0
- package/dist/runtime/execute.d.ts.map +1 -0
- package/dist/runtime/execute.js +121 -0
- package/dist/runtime/execute.js.map +1 -0
- package/dist/runtime/ext/builtins.d.ts +16 -0
- package/dist/runtime/ext/builtins.d.ts.map +1 -0
- package/dist/runtime/ext/builtins.js +528 -0
- package/dist/runtime/ext/builtins.js.map +1 -0
- package/dist/runtime/ext/content-parser.d.ts +83 -0
- package/dist/runtime/ext/content-parser.d.ts.map +1 -0
- package/dist/runtime/ext/content-parser.js +536 -0
- package/dist/runtime/ext/content-parser.js.map +1 -0
- package/dist/runtime/index.d.ts +28 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +34 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/signals.d.ts +19 -0
- package/dist/runtime/signals.d.ts.map +1 -0
- package/dist/runtime/signals.js +26 -0
- package/dist/runtime/signals.js.map +1 -0
- package/dist/runtime/types.d.ts +169 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +50 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/values.d.ts +50 -0
- package/dist/runtime/values.d.ts.map +1 -0
- package/dist/runtime/values.js +209 -0
- package/dist/runtime/values.js.map +1 -0
- package/dist/runtime.d.ts +254 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +2014 -0
- package/dist/runtime.js.map +1 -0
- package/dist/types.d.ts +752 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +189 -0
- package/dist/types.js.map +1 -0
- package/docs/00_INDEX.md +65 -0
- package/docs/01_guide.md +390 -0
- package/docs/02_types.md +399 -0
- package/docs/03_variables.md +314 -0
- package/docs/04_operators.md +551 -0
- package/docs/05_control-flow.md +350 -0
- package/docs/06_closures.md +353 -0
- package/docs/07_collections.md +686 -0
- package/docs/08_iterators.md +330 -0
- package/docs/09_strings.md +205 -0
- package/docs/10_parsing.md +366 -0
- package/docs/11_reference.md +350 -0
- package/docs/12_examples.md +771 -0
- package/docs/13_modules.md +519 -0
- package/docs/14_host-integration.md +826 -0
- package/docs/15_grammar.ebnf +693 -0
- package/docs/16_conventions.md +696 -0
- package/docs/99_llm-reference.txt +300 -0
- package/docs/assets/logo.png +0 -0
- package/package.json +70 -0
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
# Host Integration Guide
|
|
2
|
+
|
|
3
|
+
This guide covers embedding Rill in host applications. Rill is a vanilla language—all domain-specific functionality must be provided by the host.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { parse, execute, createRuntimeContext } from '@rcrsr/rill';
|
|
9
|
+
|
|
10
|
+
const source = `
|
|
11
|
+
"Hello, World!" -> prompt() :> $response
|
|
12
|
+
$response
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
const ast = parse(source);
|
|
16
|
+
const ctx = createRuntimeContext({
|
|
17
|
+
functions: {
|
|
18
|
+
prompt: async (args) => {
|
|
19
|
+
const text = String(args[0]);
|
|
20
|
+
return await callYourLLM(text);
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const result = await execute(ast, ctx);
|
|
26
|
+
console.log(result.value);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## RuntimeOptions
|
|
30
|
+
|
|
31
|
+
The `createRuntimeContext()` function accepts these options:
|
|
32
|
+
|
|
33
|
+
| Option | Type | Description |
|
|
34
|
+
|--------|------|-------------|
|
|
35
|
+
| `variables` | `Record<string, RillValue>` | Initial variables accessible as `$name` |
|
|
36
|
+
| `functions` | `Record<string, CallableFn \| HostFunctionDefinition>` | Custom functions callable as `name()` |
|
|
37
|
+
| `callbacks` | `Partial<RuntimeCallbacks>` | I/O callbacks (e.g., `onLog`) |
|
|
38
|
+
| `observability` | `ObservabilityCallbacks` | Execution monitoring hooks |
|
|
39
|
+
| `timeout` | `number` | Timeout in ms for async functions |
|
|
40
|
+
| `autoExceptions` | `string[]` | Regex patterns that halt execution |
|
|
41
|
+
| `signal` | `AbortSignal` | Cancellation signal |
|
|
42
|
+
|
|
43
|
+
## Host Function Contract
|
|
44
|
+
|
|
45
|
+
Host functions must follow these rules to ensure correct script behavior:
|
|
46
|
+
|
|
47
|
+
### Immutability
|
|
48
|
+
|
|
49
|
+
**Host functions must not mutate input arguments.** rill values are immutable by design—modifying arguments breaks value semantics and causes unpredictable behavior.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// WRONG: Mutates input array
|
|
53
|
+
functions: {
|
|
54
|
+
addItem: (args) => {
|
|
55
|
+
const list = args[0] as unknown[];
|
|
56
|
+
list.push('new'); // DON'T DO THIS
|
|
57
|
+
return list;
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// CORRECT: Return new value
|
|
62
|
+
functions: {
|
|
63
|
+
addItem: (args) => {
|
|
64
|
+
const list = args[0] as unknown[];
|
|
65
|
+
return [...list, 'new']; // Create new array
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Defensive Copies
|
|
71
|
+
|
|
72
|
+
For maximum safety, consider freezing values passed to host functions:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { deepFreeze } from './utils'; // Your utility
|
|
76
|
+
|
|
77
|
+
functions: {
|
|
78
|
+
process: (args) => {
|
|
79
|
+
const frozen = deepFreeze(args[0]);
|
|
80
|
+
return transform(frozen); // Any mutation throws
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Return Values
|
|
86
|
+
|
|
87
|
+
- Return new values instead of modifying inputs
|
|
88
|
+
- Return `RillValue` types (string, number, boolean, array, object, or `RillCallable`)
|
|
89
|
+
- Avoid returning `null` or `undefined`—use empty string `''` or empty array `[]` instead
|
|
90
|
+
|
|
91
|
+
## Custom Functions
|
|
92
|
+
|
|
93
|
+
Functions are called by name: `functionName(arg1, arg2)`.
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
const ctx = createRuntimeContext({
|
|
97
|
+
functions: {
|
|
98
|
+
// Sync function
|
|
99
|
+
add: (args) => {
|
|
100
|
+
const a = typeof args[0] === 'number' ? args[0] : 0;
|
|
101
|
+
const b = typeof args[1] === 'number' ? args[1] : 0;
|
|
102
|
+
return a + b;
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
// Async function
|
|
106
|
+
fetch: async (args, ctx, location) => {
|
|
107
|
+
const url = String(args[0]);
|
|
108
|
+
const response = await fetch(url);
|
|
109
|
+
return await response.text();
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
// Function with context access
|
|
113
|
+
getVar: (args, ctx) => {
|
|
114
|
+
const name = String(args[0]);
|
|
115
|
+
return ctx.variables.get(name) ?? null;
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Function with location for error reporting
|
|
119
|
+
validate: (args, ctx, location) => {
|
|
120
|
+
if (!args[0]) {
|
|
121
|
+
throw new Error(`Validation failed at line ${location?.line}`);
|
|
122
|
+
}
|
|
123
|
+
return args[0];
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Namespaced Functions
|
|
130
|
+
|
|
131
|
+
Use `::` to organize functions into namespaces:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const ctx = createRuntimeContext({
|
|
135
|
+
functions: {
|
|
136
|
+
// Namespaced functions use :: separator
|
|
137
|
+
'math::add': (args) => (args[0] as number) + (args[1] as number),
|
|
138
|
+
'math::multiply': (args) => (args[0] as number) * (args[1] as number),
|
|
139
|
+
'str::upper': (args) => String(args[0]).toUpperCase(),
|
|
140
|
+
'str::lower': (args) => String(args[0]).toLowerCase(),
|
|
141
|
+
|
|
142
|
+
// Multi-level namespaces
|
|
143
|
+
'io::file::read': async (args) => fs.readFile(String(args[0]), 'utf-8'),
|
|
144
|
+
'io::file::write': async (args) => fs.writeFile(String(args[0]), String(args[1])),
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Scripts call namespaced functions with the same syntax:
|
|
150
|
+
|
|
151
|
+
```rill
|
|
152
|
+
math::add(1, 2) # 3
|
|
153
|
+
"hello" -> str::upper # "HELLO"
|
|
154
|
+
io::file::read("config.json") -> parse_json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Namespaces help organize host APIs and avoid name collisions without requiring the `$` variable prefix.
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### CallableFn Signature
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
type CallableFn = (
|
|
164
|
+
args: RillValue[],
|
|
165
|
+
ctx: RuntimeContext,
|
|
166
|
+
location?: SourceLocation
|
|
167
|
+
) => RillValue | Promise<RillValue>;
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
| Parameter | Description |
|
|
171
|
+
|-----------|-------------|
|
|
172
|
+
| `args` | Positional arguments passed to the function |
|
|
173
|
+
| `ctx` | Runtime context with variables, pipeValue, etc. |
|
|
174
|
+
| `location` | Source location of the call site (for error reporting) |
|
|
175
|
+
|
|
176
|
+
## Typed Host Functions
|
|
177
|
+
|
|
178
|
+
Host functions can declare parameter types and defaults. The runtime validates arguments before calling your function, eliminating manual type checking.
|
|
179
|
+
|
|
180
|
+
### Basic Type Declarations
|
|
181
|
+
|
|
182
|
+
Declare parameter types using the `HostFunctionDefinition` interface:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const ctx = createRuntimeContext({
|
|
186
|
+
functions: {
|
|
187
|
+
repeat: {
|
|
188
|
+
params: [
|
|
189
|
+
{ name: 'str', type: 'string' },
|
|
190
|
+
{ name: 'count', type: 'number', defaultValue: 1 },
|
|
191
|
+
],
|
|
192
|
+
fn: (args) => {
|
|
193
|
+
// args[0] guaranteed to be string
|
|
194
|
+
// args[1] guaranteed to be number (or default)
|
|
195
|
+
return args[0].repeat(args[1]);
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Scripts call typed functions the same way:
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
repeat("hello", 3) # "hellohellohello"
|
|
206
|
+
repeat("hi") # "hi" (uses default count)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Supported Types
|
|
210
|
+
|
|
211
|
+
| Type | Rill Value | Validation |
|
|
212
|
+
|------|------------|------------|
|
|
213
|
+
| `'string'` | String | `typeof value === 'string'` |
|
|
214
|
+
| `'number'` | Number | `typeof value === 'number'` |
|
|
215
|
+
| `'bool'` | Boolean | `typeof value === 'boolean'` |
|
|
216
|
+
| `'list'` | List | `Array.isArray(value)` |
|
|
217
|
+
| `'dict'` | Dict | `isDict(value)` |
|
|
218
|
+
|
|
219
|
+
### Default Values
|
|
220
|
+
|
|
221
|
+
Parameters with default values are optional. The default applies when the argument is missing:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
functions: {
|
|
225
|
+
greet: {
|
|
226
|
+
params: [
|
|
227
|
+
{ name: 'name', type: 'string' },
|
|
228
|
+
{ name: 'greeting', type: 'string', defaultValue: 'Hello' },
|
|
229
|
+
],
|
|
230
|
+
fn: (args) => `${args[1]}, ${args[0]}!`,
|
|
231
|
+
},
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
greet("Alice") # "Hello, Alice!"
|
|
237
|
+
greet("Bob", "Hi") # "Hi, Bob!"
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Type Mismatch Errors
|
|
241
|
+
|
|
242
|
+
When argument types don't match, the runtime throws `RuntimeError` with code `RUNTIME_TYPE_ERROR`:
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
// Script: repeat(42, 3)
|
|
246
|
+
// Error: Function 'repeat' expects parameter 'str' (position 0) to be string, got number
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Error details include:
|
|
250
|
+
|
|
251
|
+
- Function name
|
|
252
|
+
- Parameter name
|
|
253
|
+
- Parameter position
|
|
254
|
+
- Expected type
|
|
255
|
+
- Actual type received
|
|
256
|
+
|
|
257
|
+
### Migration from Untyped Functions
|
|
258
|
+
|
|
259
|
+
Typed function declarations are optional. Existing untyped functions continue working without changes.
|
|
260
|
+
|
|
261
|
+
**Before (manual validation):**
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
functions: {
|
|
265
|
+
repeat: (args) => {
|
|
266
|
+
const str = typeof args[0] === 'string' ? args[0] : '';
|
|
267
|
+
const count = typeof args[1] === 'number' ? args[1] : 1;
|
|
268
|
+
return str.repeat(count);
|
|
269
|
+
},
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**After (declarative validation):**
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
functions: {
|
|
277
|
+
repeat: {
|
|
278
|
+
params: [
|
|
279
|
+
{ name: 'str', type: 'string' },
|
|
280
|
+
{ name: 'count', type: 'number', defaultValue: 1 },
|
|
281
|
+
],
|
|
282
|
+
fn: (args) => args[0].repeat(args[1]), // Types guaranteed
|
|
283
|
+
},
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Benefits of migration:
|
|
288
|
+
|
|
289
|
+
- Eliminates manual type checking code
|
|
290
|
+
- Provides clear error messages to script authors
|
|
291
|
+
- Documents expected types in function signature
|
|
292
|
+
- Reduces bugs from incorrect type coercion
|
|
293
|
+
|
|
294
|
+
### Mixed Function Definitions
|
|
295
|
+
|
|
296
|
+
You can mix typed and untyped functions in the same context:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
const ctx = createRuntimeContext({
|
|
300
|
+
functions: {
|
|
301
|
+
// Untyped (legacy)
|
|
302
|
+
'legacy::func': (args) => args[0],
|
|
303
|
+
|
|
304
|
+
// Typed (new)
|
|
305
|
+
'typed::func': {
|
|
306
|
+
params: [{ name: 'x', type: 'string' }],
|
|
307
|
+
fn: (args) => args[0],
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### HostFunctionDefinition Interface
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
interface HostFunctionDefinition {
|
|
317
|
+
params: HostFunctionParam[];
|
|
318
|
+
fn: CallableFn;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
interface HostFunctionParam {
|
|
322
|
+
name: string;
|
|
323
|
+
type: 'string' | 'number' | 'bool' | 'list' | 'dict';
|
|
324
|
+
defaultValue?: RillValue;
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Application Callables
|
|
329
|
+
|
|
330
|
+
Hosts can create first-class callable values that scripts can store, pass, and invoke.
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
import { callable, isCallable, isApplicationCallable } from '@rcrsr/rill';
|
|
334
|
+
|
|
335
|
+
// Create a callable
|
|
336
|
+
const greet = callable((args) => `Hello, ${args[0]}!`);
|
|
337
|
+
|
|
338
|
+
// Use in variables
|
|
339
|
+
const ctx = createRuntimeContext({
|
|
340
|
+
variables: {
|
|
341
|
+
greet: greet,
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// Script can invoke: $greet("World") -> "Hello, World!"
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### callable() Function
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
function callable(fn: CallableFn, isProperty?: boolean): ApplicationCallable;
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
| Parameter | Description |
|
|
355
|
+
|-----------|-------------|
|
|
356
|
+
| `fn` | The function to wrap |
|
|
357
|
+
| `isProperty` | If `true`, auto-invokes when accessed from dict |
|
|
358
|
+
|
|
359
|
+
### Property-Style Callables
|
|
360
|
+
|
|
361
|
+
Property-style callables auto-invoke when accessed from a dict, enabling computed properties:
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
const ctx = createRuntimeContext({
|
|
365
|
+
variables: {
|
|
366
|
+
user: {
|
|
367
|
+
firstName: 'John',
|
|
368
|
+
lastName: 'Doe',
|
|
369
|
+
// Auto-invokes on access, receives bound dict
|
|
370
|
+
fullName: callable((args) => {
|
|
371
|
+
const dict = args[0] as Record<string, RillValue>;
|
|
372
|
+
return `${dict.firstName} ${dict.lastName}`;
|
|
373
|
+
}, true),
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// Script: $user.fullName -> "John Doe"
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Dict Callables
|
|
382
|
+
|
|
383
|
+
Callables stored in dicts can be invoked using method syntax:
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
const ctx = createRuntimeContext({
|
|
387
|
+
variables: {
|
|
388
|
+
math: {
|
|
389
|
+
add: callable((args) => {
|
|
390
|
+
const a = typeof args[0] === 'number' ? args[0] : 0;
|
|
391
|
+
const b = typeof args[1] === 'number' ? args[1] : 0;
|
|
392
|
+
return a + b;
|
|
393
|
+
}),
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// Script: $math.add(1, 2) -> 3
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Callable Kinds
|
|
402
|
+
|
|
403
|
+
| Kind | Type | Description |
|
|
404
|
+
|------|------|-------------|
|
|
405
|
+
| `script` | `ScriptCallable` | Closures from Rill source code |
|
|
406
|
+
| `runtime` | `RuntimeCallable` | Rill's built-in functions |
|
|
407
|
+
| `application` | `ApplicationCallable` | Host-provided callables |
|
|
408
|
+
|
|
409
|
+
### Type Guards
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
import {
|
|
413
|
+
isCallable,
|
|
414
|
+
isScriptCallable,
|
|
415
|
+
isRuntimeCallable,
|
|
416
|
+
isApplicationCallable,
|
|
417
|
+
} from '@rcrsr/rill';
|
|
418
|
+
|
|
419
|
+
if (isCallable(value)) {
|
|
420
|
+
// value is RillCallable (any callable)
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (isApplicationCallable(value)) {
|
|
424
|
+
// value is ApplicationCallable (host-provided)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (isScriptCallable(value)) {
|
|
428
|
+
// value is ScriptCallable (from Rill source)
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Cancellation
|
|
433
|
+
|
|
434
|
+
Use `AbortSignal` to cancel long-running scripts:
|
|
435
|
+
|
|
436
|
+
```typescript
|
|
437
|
+
const controller = new AbortController();
|
|
438
|
+
|
|
439
|
+
const ctx = createRuntimeContext({
|
|
440
|
+
signal: controller.signal,
|
|
441
|
+
functions: {
|
|
442
|
+
longTask: async () => {
|
|
443
|
+
await new Promise((r) => setTimeout(r, 10000));
|
|
444
|
+
return 'done';
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// Cancel after 1 second
|
|
450
|
+
setTimeout(() => controller.abort(), 1000);
|
|
451
|
+
|
|
452
|
+
try {
|
|
453
|
+
await execute(ast, ctx);
|
|
454
|
+
} catch (err) {
|
|
455
|
+
if (err instanceof AbortError) {
|
|
456
|
+
console.log('Execution cancelled');
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### AbortError
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
import { AbortError } from '@rcrsr/rill';
|
|
465
|
+
|
|
466
|
+
try {
|
|
467
|
+
await execute(ast, ctx);
|
|
468
|
+
} catch (err) {
|
|
469
|
+
if (err instanceof AbortError) {
|
|
470
|
+
console.log(err.code); // 'RUNTIME_ABORTED'
|
|
471
|
+
console.log(err.message); // 'Execution aborted'
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
Abort is checked at:
|
|
477
|
+
- Before each statement
|
|
478
|
+
- Before each function call
|
|
479
|
+
- Before each loop iteration
|
|
480
|
+
- In the stepper's `step()` method
|
|
481
|
+
|
|
482
|
+
## Observability
|
|
483
|
+
|
|
484
|
+
Monitor execution with observability callbacks:
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
const ctx = createRuntimeContext({
|
|
488
|
+
observability: {
|
|
489
|
+
onStepStart: (event) => {
|
|
490
|
+
console.log(`Step ${event.index + 1}/${event.total}`);
|
|
491
|
+
},
|
|
492
|
+
onStepEnd: (event) => {
|
|
493
|
+
console.log(`Completed in ${event.durationMs}ms`);
|
|
494
|
+
},
|
|
495
|
+
onFunctionCall: (event) => {
|
|
496
|
+
console.log(`Calling ${event.name}(${event.args.join(', ')})`);
|
|
497
|
+
},
|
|
498
|
+
onFunctionReturn: (event) => {
|
|
499
|
+
console.log(`${event.name} returned: ${event.value}`);
|
|
500
|
+
},
|
|
501
|
+
onCapture: (event) => {
|
|
502
|
+
console.log(`Captured $${event.name} = ${event.value}`);
|
|
503
|
+
},
|
|
504
|
+
onError: (event) => {
|
|
505
|
+
console.error(`Error at step ${event.index}:`, event.error);
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
});
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### Event Types
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
interface StepStartEvent {
|
|
515
|
+
index: number; // Statement index (0-based)
|
|
516
|
+
total: number; // Total statements
|
|
517
|
+
pipeValue: RillValue;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
interface StepEndEvent {
|
|
521
|
+
index: number;
|
|
522
|
+
total: number;
|
|
523
|
+
value: RillValue;
|
|
524
|
+
durationMs: number;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
interface FunctionCallEvent {
|
|
528
|
+
name: string;
|
|
529
|
+
args: RillValue[];
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
interface FunctionReturnEvent {
|
|
533
|
+
name: string;
|
|
534
|
+
value: RillValue;
|
|
535
|
+
durationMs: number;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
interface CaptureEvent {
|
|
539
|
+
name: string;
|
|
540
|
+
value: RillValue;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
interface ErrorEvent {
|
|
544
|
+
error: Error;
|
|
545
|
+
index?: number;
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
## Step-by-Step Execution
|
|
550
|
+
|
|
551
|
+
Use the stepper API for controlled execution:
|
|
552
|
+
|
|
553
|
+
```typescript
|
|
554
|
+
import { parse, createRuntimeContext, createStepper } from '@rcrsr/rill';
|
|
555
|
+
|
|
556
|
+
const ast = parse(source);
|
|
557
|
+
const ctx = createRuntimeContext({ ... });
|
|
558
|
+
const stepper = createStepper(ast, ctx);
|
|
559
|
+
|
|
560
|
+
while (!stepper.done) {
|
|
561
|
+
const result = await stepper.step();
|
|
562
|
+
console.log(`Step ${result.index + 1}: ${result.value}`);
|
|
563
|
+
|
|
564
|
+
if (result.captured) {
|
|
565
|
+
console.log(`Captured: $${result.captured.name}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const final = stepper.getResult();
|
|
570
|
+
console.log('Final value:', final.value);
|
|
571
|
+
console.log('Variables:', final.variables);
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
### ExecutionStepper Interface
|
|
575
|
+
|
|
576
|
+
```typescript
|
|
577
|
+
interface ExecutionStepper {
|
|
578
|
+
readonly done: boolean;
|
|
579
|
+
readonly index: number;
|
|
580
|
+
readonly total: number;
|
|
581
|
+
readonly context: RuntimeContext;
|
|
582
|
+
step(): Promise<StepResult>;
|
|
583
|
+
getResult(): ExecutionResult;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
interface StepResult {
|
|
587
|
+
value: RillValue;
|
|
588
|
+
done: boolean;
|
|
589
|
+
index: number;
|
|
590
|
+
total: number;
|
|
591
|
+
captured?: { name: string; value: RillValue };
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
interface ExecutionResult {
|
|
595
|
+
value: RillValue;
|
|
596
|
+
variables: Record<string, RillValue>;
|
|
597
|
+
}
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
## I/O Callbacks
|
|
601
|
+
|
|
602
|
+
Handle script I/O through callbacks:
|
|
603
|
+
|
|
604
|
+
```typescript
|
|
605
|
+
const ctx = createRuntimeContext({
|
|
606
|
+
callbacks: {
|
|
607
|
+
onLog: (value) => {
|
|
608
|
+
// Called when script uses .log method
|
|
609
|
+
console.log('[Rill]', value);
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
});
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
## Timeouts
|
|
616
|
+
|
|
617
|
+
Set a timeout for async operations:
|
|
618
|
+
|
|
619
|
+
```typescript
|
|
620
|
+
const ctx = createRuntimeContext({
|
|
621
|
+
timeout: 30000, // 30 seconds
|
|
622
|
+
functions: {
|
|
623
|
+
slowOperation: async () => {
|
|
624
|
+
// Will throw TimeoutError if exceeds 30s
|
|
625
|
+
await longRunningTask();
|
|
626
|
+
return 'done';
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
});
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
## Auto-Exceptions
|
|
633
|
+
|
|
634
|
+
Halt execution when output matches patterns:
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
const ctx = createRuntimeContext({
|
|
638
|
+
autoExceptions: [
|
|
639
|
+
'error:.*', // Matches "error: something"
|
|
640
|
+
'FATAL', // Matches "FATAL" anywhere
|
|
641
|
+
],
|
|
642
|
+
functions: {
|
|
643
|
+
process: (args) => {
|
|
644
|
+
// If this returns "error: invalid input",
|
|
645
|
+
// execution halts with AutoExceptionError
|
|
646
|
+
return externalProcess(args[0]);
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
});
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
## Initial Variables
|
|
653
|
+
|
|
654
|
+
Provide variables accessible in scripts:
|
|
655
|
+
|
|
656
|
+
```typescript
|
|
657
|
+
const ctx = createRuntimeContext({
|
|
658
|
+
variables: {
|
|
659
|
+
config: {
|
|
660
|
+
apiUrl: 'https://api.example.com',
|
|
661
|
+
maxRetries: 3,
|
|
662
|
+
},
|
|
663
|
+
userId: 'user-123',
|
|
664
|
+
items: [1, 2, 3],
|
|
665
|
+
},
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
// Script can access: $config.apiUrl, $userId, $items
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
## Error Handling
|
|
672
|
+
|
|
673
|
+
All Rill errors extend `RillError` with structured information:
|
|
674
|
+
|
|
675
|
+
```typescript
|
|
676
|
+
import { RuntimeError, ParseError, AbortError, TimeoutError } from '@rcrsr/rill';
|
|
677
|
+
|
|
678
|
+
try {
|
|
679
|
+
const ast = parse(source);
|
|
680
|
+
const result = await execute(ast, ctx);
|
|
681
|
+
} catch (err) {
|
|
682
|
+
if (err instanceof ParseError) {
|
|
683
|
+
console.log('Parse error:', err.message);
|
|
684
|
+
console.log('Location:', err.location);
|
|
685
|
+
} else if (err instanceof RuntimeError) {
|
|
686
|
+
console.log('Runtime error:', err.code);
|
|
687
|
+
console.log('Message:', err.message);
|
|
688
|
+
console.log('Location:', err.location);
|
|
689
|
+
console.log('Context:', err.context);
|
|
690
|
+
} else if (err instanceof AbortError) {
|
|
691
|
+
console.log('Execution cancelled');
|
|
692
|
+
} else if (err instanceof TimeoutError) {
|
|
693
|
+
console.log('Operation timed out');
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### Error Codes
|
|
699
|
+
|
|
700
|
+
| Code | Description |
|
|
701
|
+
|------|-------------|
|
|
702
|
+
| `PARSE_UNEXPECTED_TOKEN` | Unexpected token in source |
|
|
703
|
+
| `PARSE_INVALID_SYNTAX` | Invalid syntax |
|
|
704
|
+
| `PARSE_INVALID_TYPE` | Invalid type annotation |
|
|
705
|
+
| `RUNTIME_UNDEFINED_VARIABLE` | Variable not defined |
|
|
706
|
+
| `RUNTIME_UNDEFINED_FUNCTION` | Function not defined |
|
|
707
|
+
| `RUNTIME_UNDEFINED_METHOD` | Method not defined (built-in only) |
|
|
708
|
+
| `RUNTIME_TYPE_ERROR` | Type mismatch (includes host function parameter validation) |
|
|
709
|
+
| `RUNTIME_TIMEOUT` | Operation timed out |
|
|
710
|
+
| `RUNTIME_ABORTED` | Execution cancelled |
|
|
711
|
+
| `RUNTIME_INVALID_PATTERN` | Invalid regex pattern |
|
|
712
|
+
| `RUNTIME_AUTO_EXCEPTION` | Auto-exception triggered |
|
|
713
|
+
|
|
714
|
+
## Complete Example
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
import {
|
|
718
|
+
parse,
|
|
719
|
+
execute,
|
|
720
|
+
createRuntimeContext,
|
|
721
|
+
callable,
|
|
722
|
+
AbortError,
|
|
723
|
+
type RillValue,
|
|
724
|
+
} from '@rcrsr/rill';
|
|
725
|
+
|
|
726
|
+
const script = `
|
|
727
|
+
$config.greeting -> prompt() :> $response
|
|
728
|
+
$response
|
|
729
|
+
`;
|
|
730
|
+
|
|
731
|
+
const controller = new AbortController();
|
|
732
|
+
|
|
733
|
+
const ctx = createRuntimeContext({
|
|
734
|
+
variables: {
|
|
735
|
+
config: {
|
|
736
|
+
greeting: 'Say hello in French',
|
|
737
|
+
},
|
|
738
|
+
utils: {
|
|
739
|
+
// Property-style callable (computed property)
|
|
740
|
+
timestamp: callable(() => Date.now(), true),
|
|
741
|
+
// Regular callable
|
|
742
|
+
format: callable((args) => {
|
|
743
|
+
const [template, ...values] = args;
|
|
744
|
+
return String(template).replace(/\{\}/g, () =>
|
|
745
|
+
String(values.shift() ?? '')
|
|
746
|
+
);
|
|
747
|
+
}),
|
|
748
|
+
},
|
|
749
|
+
},
|
|
750
|
+
|
|
751
|
+
functions: {
|
|
752
|
+
prompt: async (args, ctx, location) => {
|
|
753
|
+
console.log(`[prompt at line ${location?.line}]`);
|
|
754
|
+
return await callLLM(String(args[0]));
|
|
755
|
+
},
|
|
756
|
+
},
|
|
757
|
+
|
|
758
|
+
callbacks: {
|
|
759
|
+
onLog: (value) => console.log('[log]', value),
|
|
760
|
+
},
|
|
761
|
+
|
|
762
|
+
observability: {
|
|
763
|
+
onStepStart: (e) => console.log(`Step ${e.index + 1}...`),
|
|
764
|
+
onStepEnd: (e) => console.log(`Done (${e.durationMs}ms)`),
|
|
765
|
+
},
|
|
766
|
+
|
|
767
|
+
timeout: 30000,
|
|
768
|
+
signal: controller.signal,
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
try {
|
|
772
|
+
const ast = parse(script);
|
|
773
|
+
const result = await execute(ast, ctx);
|
|
774
|
+
console.log('Result:', result.value);
|
|
775
|
+
console.log('Variables:', result.variables);
|
|
776
|
+
} catch (err) {
|
|
777
|
+
if (err instanceof AbortError) {
|
|
778
|
+
console.log('Cancelled');
|
|
779
|
+
} else {
|
|
780
|
+
throw err;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
## API Reference
|
|
786
|
+
|
|
787
|
+
### Exports
|
|
788
|
+
|
|
789
|
+
```typescript
|
|
790
|
+
// Parsing
|
|
791
|
+
export { parse, ParseError, tokenize, LexerError };
|
|
792
|
+
|
|
793
|
+
// Execution
|
|
794
|
+
export { execute, createRuntimeContext, createStepper };
|
|
795
|
+
export type { RuntimeContext, RuntimeOptions, ExecutionResult };
|
|
796
|
+
export type { ExecutionStepper, StepResult };
|
|
797
|
+
|
|
798
|
+
// Callable types
|
|
799
|
+
export { callable, isCallable, isScriptCallable, isRuntimeCallable, isApplicationCallable };
|
|
800
|
+
export type { RillCallable, ScriptCallable, RuntimeCallable, ApplicationCallable, CallableFn };
|
|
801
|
+
|
|
802
|
+
// Host function types
|
|
803
|
+
export type { HostFunctionDefinition, HostFunctionParam };
|
|
804
|
+
export { validateHostFunctionArgs };
|
|
805
|
+
|
|
806
|
+
// Value types
|
|
807
|
+
export type { RillValue, RillArgs };
|
|
808
|
+
|
|
809
|
+
// Callbacks
|
|
810
|
+
export type { RuntimeCallbacks, ObservabilityCallbacks };
|
|
811
|
+
export type { StepStartEvent, StepEndEvent, FunctionCallEvent, FunctionReturnEvent };
|
|
812
|
+
export type { CaptureEvent, ErrorEvent };
|
|
813
|
+
|
|
814
|
+
// Errors
|
|
815
|
+
export { RillError, RuntimeError, ParseError, AbortError, TimeoutError, AutoExceptionError };
|
|
816
|
+
export { RILL_ERROR_CODES };
|
|
817
|
+
export type { RillErrorCode };
|
|
818
|
+
|
|
819
|
+
// Utilities
|
|
820
|
+
export { isArgs, isDict, isReservedMethod, RESERVED_DICT_METHODS };
|
|
821
|
+
export type { SourceLocation, SourceSpan };
|
|
822
|
+
|
|
823
|
+
// Control flow (for advanced use)
|
|
824
|
+
export { BreakSignal, ReturnSignal };
|
|
825
|
+
```
|
|
826
|
+
|