@rcrsr/rill 0.1.0 → 0.2.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/README.md +16 -8
- package/dist/check/config.d.ts +20 -0
- package/dist/check/config.d.ts.map +1 -0
- package/dist/check/config.js +151 -0
- package/dist/check/config.js.map +1 -0
- package/dist/check/fixer.d.ts +39 -0
- package/dist/check/fixer.d.ts.map +1 -0
- package/dist/check/fixer.js +119 -0
- package/dist/check/fixer.js.map +1 -0
- package/dist/check/index.d.ts +10 -0
- package/dist/check/index.d.ts.map +1 -0
- package/dist/check/index.js +21 -0
- package/dist/check/index.js.map +1 -0
- package/dist/check/rules/anti-patterns.d.ts +65 -0
- package/dist/check/rules/anti-patterns.d.ts.map +1 -0
- package/dist/check/rules/anti-patterns.js +427 -0
- package/dist/check/rules/anti-patterns.js.map +1 -0
- package/dist/check/rules/closures.d.ts +66 -0
- package/dist/check/rules/closures.d.ts.map +1 -0
- package/dist/check/rules/closures.js +373 -0
- package/dist/check/rules/closures.js.map +1 -0
- package/dist/check/rules/collections.d.ts +90 -0
- package/dist/check/rules/collections.d.ts.map +1 -0
- package/dist/check/rules/collections.js +373 -0
- package/dist/check/rules/collections.js.map +1 -0
- package/dist/check/rules/conditionals.d.ts +41 -0
- package/dist/check/rules/conditionals.d.ts.map +1 -0
- package/dist/check/rules/conditionals.js +106 -0
- package/dist/check/rules/conditionals.js.map +1 -0
- package/dist/check/rules/flow.d.ts +46 -0
- package/dist/check/rules/flow.d.ts.map +1 -0
- package/dist/check/rules/flow.js +206 -0
- package/dist/check/rules/flow.js.map +1 -0
- package/dist/check/rules/formatting.d.ts +133 -0
- package/dist/check/rules/formatting.d.ts.map +1 -0
- package/dist/check/rules/formatting.js +639 -0
- package/dist/check/rules/formatting.js.map +1 -0
- package/dist/check/rules/helpers.d.ts +26 -0
- package/dist/check/rules/helpers.d.ts.map +1 -0
- package/dist/check/rules/helpers.js +66 -0
- package/dist/check/rules/helpers.js.map +1 -0
- package/dist/check/rules/index.d.ts +21 -0
- package/dist/check/rules/index.d.ts.map +1 -0
- package/dist/check/rules/index.js +78 -0
- package/dist/check/rules/index.js.map +1 -0
- package/dist/check/rules/loops.d.ts +70 -0
- package/dist/check/rules/loops.d.ts.map +1 -0
- package/dist/check/rules/loops.js +227 -0
- package/dist/check/rules/loops.js.map +1 -0
- package/dist/check/rules/naming.d.ts +21 -0
- package/dist/check/rules/naming.d.ts.map +1 -0
- package/dist/check/rules/naming.js +167 -0
- package/dist/check/rules/naming.js.map +1 -0
- package/dist/check/rules/strings.d.ts +28 -0
- package/dist/check/rules/strings.d.ts.map +1 -0
- package/dist/check/rules/strings.js +80 -0
- package/dist/check/rules/strings.js.map +1 -0
- package/dist/check/rules/types.d.ts +41 -0
- package/dist/check/rules/types.d.ts.map +1 -0
- package/dist/check/rules/types.js +162 -0
- package/dist/check/rules/types.js.map +1 -0
- package/dist/check/types.d.ts +106 -0
- package/dist/check/types.d.ts.map +1 -0
- package/dist/check/types.js +6 -0
- package/dist/check/types.js.map +1 -0
- package/dist/check/validator.d.ts +18 -0
- package/dist/check/validator.d.ts.map +1 -0
- package/dist/check/validator.js +88 -0
- package/dist/check/validator.js.map +1 -0
- package/dist/check/visitor.d.ts +33 -0
- package/dist/check/visitor.d.ts.map +1 -0
- package/dist/check/visitor.js +243 -0
- package/dist/check/visitor.js.map +1 -0
- package/dist/cli-check.d.ts +43 -0
- package/dist/cli-check.d.ts.map +1 -0
- package/dist/cli-check.js +356 -0
- package/dist/cli-check.js.map +1 -0
- package/dist/cli-eval.d.ts +15 -0
- package/dist/cli-eval.d.ts.map +1 -0
- package/dist/cli-eval.js +120 -0
- package/dist/cli-eval.js.map +1 -0
- package/dist/cli-exec.d.ts +49 -0
- package/dist/cli-exec.d.ts.map +1 -0
- package/dist/cli-exec.js +191 -0
- package/dist/cli-exec.js.map +1 -0
- package/dist/cli-module-loader.d.ts +19 -0
- package/dist/cli-module-loader.d.ts.map +1 -0
- package/dist/cli-module-loader.js +83 -0
- package/dist/cli-module-loader.js.map +1 -0
- package/dist/cli-shared.d.ts +36 -0
- package/dist/cli-shared.d.ts.map +1 -0
- package/dist/cli-shared.js +101 -0
- package/dist/cli-shared.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -11
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lexer/readers.d.ts +1 -1
- package/dist/lexer/readers.d.ts.map +1 -1
- package/dist/lexer/readers.js +62 -32
- package/dist/lexer/readers.js.map +1 -1
- package/dist/lexer/tokenizer.d.ts.map +1 -1
- package/dist/lexer/tokenizer.js +5 -6
- package/dist/lexer/tokenizer.js.map +1 -1
- package/dist/parser/index.js +1 -1
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/parser-expr.js +23 -5
- package/dist/parser/parser-expr.js.map +1 -1
- package/dist/parser/parser-functions.d.ts +2 -2
- package/dist/parser/parser-functions.d.ts.map +1 -1
- package/dist/parser/parser-functions.js +2 -1
- package/dist/parser/parser-functions.js.map +1 -1
- package/dist/parser/parser-literals.js +2 -2
- package/dist/parser/parser-literals.js.map +1 -1
- package/dist/parser/parser-script.js +9 -7
- package/dist/parser/parser-script.js.map +1 -1
- package/dist/parser/parser-variables.js +4 -3
- package/dist/parser/parser-variables.js.map +1 -1
- package/dist/runtime/core/callable.d.ts +5 -6
- package/dist/runtime/core/callable.d.ts.map +1 -1
- package/dist/runtime/core/callable.js.map +1 -1
- package/dist/runtime/core/context.d.ts.map +1 -1
- package/dist/runtime/core/context.js +19 -32
- package/dist/runtime/core/context.js.map +1 -1
- package/dist/runtime/core/equals.js +1 -1
- package/dist/runtime/core/equals.js.map +1 -1
- package/dist/runtime/core/eval/evaluator.d.ts +78 -0
- package/dist/runtime/core/eval/evaluator.d.ts.map +1 -1
- package/dist/runtime/core/eval/evaluator.js +78 -0
- package/dist/runtime/core/eval/evaluator.js.map +1 -1
- package/dist/runtime/core/eval/mixins/closures.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/closures.js +9 -1
- package/dist/runtime/core/eval/mixins/closures.js.map +1 -1
- package/dist/runtime/core/eval/mixins/variables.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/variables.js +143 -2
- package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
- package/dist/runtime/core/types.d.ts +15 -2
- package/dist/runtime/core/types.d.ts.map +1 -1
- package/dist/runtime/core/types.js.map +1 -1
- package/dist/runtime/ext/extensions.d.ts +51 -0
- package/dist/runtime/ext/extensions.d.ts.map +1 -0
- package/dist/runtime/ext/extensions.js +67 -0
- package/dist/runtime/ext/extensions.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/types.d.ts +8 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -4
- package/dist/types.js.map +1 -1
- package/docs/00_INDEX.md +1 -0
- package/docs/01_guide.md +3 -3
- package/docs/02_types.md +8 -10
- package/docs/03_variables.md +10 -0
- package/docs/04_operators.md +3 -3
- package/docs/05_control-flow.md +21 -0
- package/docs/07_collections.md +2 -0
- package/docs/10_parsing.md +9 -9
- package/docs/11_reference.md +1 -1
- package/docs/12_examples.md +36 -62
- package/docs/14_host-integration.md +116 -111
- package/docs/15_grammar.ebnf +1 -5
- package/docs/16_conventions.md +3 -4
- package/docs/17_cli-tools.md +184 -0
- package/docs/99_llm-reference.txt +46 -5
- package/package.json +13 -4
- package/dist/demo.d.ts +0 -6
- package/dist/demo.d.ts.map +0 -1
- package/dist/demo.js +0 -121
- package/dist/demo.js.map +0 -1
- package/dist/lexer.d.ts +0 -19
- package/dist/lexer.d.ts.map +0 -1
- package/dist/lexer.js +0 -344
- package/dist/lexer.js.map +0 -1
- package/dist/parser/arithmetic.d.ts +0 -16
- package/dist/parser/arithmetic.d.ts.map +0 -1
- package/dist/parser/arithmetic.js +0 -128
- package/dist/parser/arithmetic.js.map +0 -1
- package/dist/parser/boolean.d.ts +0 -15
- package/dist/parser/boolean.d.ts.map +0 -1
- package/dist/parser/boolean.js +0 -20
- package/dist/parser/boolean.js.map +0 -1
- package/dist/parser/control-flow.d.ts +0 -56
- package/dist/parser/control-flow.d.ts.map +0 -1
- package/dist/parser/control-flow.js +0 -167
- package/dist/parser/control-flow.js.map +0 -1
- package/dist/parser/expressions.d.ts +0 -23
- package/dist/parser/expressions.d.ts.map +0 -1
- package/dist/parser/expressions.js +0 -950
- package/dist/parser/expressions.js.map +0 -1
- package/dist/parser/extraction.d.ts +0 -48
- package/dist/parser/extraction.d.ts.map +0 -1
- package/dist/parser/extraction.js +0 -279
- package/dist/parser/extraction.js.map +0 -1
- package/dist/parser/functions.d.ts +0 -20
- package/dist/parser/functions.d.ts.map +0 -1
- package/dist/parser/functions.js +0 -96
- package/dist/parser/functions.js.map +0 -1
- package/dist/parser/literals.d.ts +0 -37
- package/dist/parser/literals.d.ts.map +0 -1
- package/dist/parser/literals.js +0 -373
- package/dist/parser/literals.js.map +0 -1
- package/dist/parser/script.d.ts +0 -14
- package/dist/parser/script.d.ts.map +0 -1
- package/dist/parser/script.js +0 -196
- package/dist/parser/script.js.map +0 -1
- package/dist/parser/variables.d.ts +0 -10
- package/dist/parser/variables.d.ts.map +0 -1
- package/dist/parser/variables.js +0 -215
- package/dist/parser/variables.js.map +0 -1
- package/dist/runtime/ast-equals.d.ts +0 -13
- package/dist/runtime/ast-equals.d.ts.map +0 -1
- package/dist/runtime/ast-equals.js +0 -447
- package/dist/runtime/ast-equals.js.map +0 -1
- package/dist/runtime/builtins.d.ts +0 -13
- package/dist/runtime/builtins.d.ts.map +0 -1
- package/dist/runtime/builtins.js +0 -180
- package/dist/runtime/builtins.js.map +0 -1
- package/dist/runtime/callable.d.ts +0 -88
- package/dist/runtime/callable.d.ts.map +0 -1
- package/dist/runtime/callable.js +0 -98
- package/dist/runtime/callable.js.map +0 -1
- package/dist/runtime/context.d.ts +0 -13
- package/dist/runtime/context.d.ts.map +0 -1
- package/dist/runtime/context.js +0 -73
- package/dist/runtime/context.js.map +0 -1
- package/dist/runtime/core/evaluate.d.ts +0 -42
- package/dist/runtime/core/evaluate.d.ts.map +0 -1
- package/dist/runtime/core/evaluate.debug.js +0 -1251
- package/dist/runtime/core/evaluate.js +0 -1913
- package/dist/runtime/core/evaluate.js.map +0 -1
- package/dist/runtime/evaluate.d.ts +0 -32
- package/dist/runtime/evaluate.d.ts.map +0 -1
- package/dist/runtime/evaluate.js +0 -1111
- package/dist/runtime/evaluate.js.map +0 -1
- package/dist/runtime/execute.d.ts +0 -26
- package/dist/runtime/execute.d.ts.map +0 -1
- package/dist/runtime/execute.js +0 -121
- package/dist/runtime/execute.js.map +0 -1
- package/dist/runtime/signals.d.ts +0 -19
- package/dist/runtime/signals.d.ts.map +0 -1
- package/dist/runtime/signals.js +0 -26
- package/dist/runtime/signals.js.map +0 -1
- package/dist/runtime/types.d.ts +0 -169
- package/dist/runtime/types.d.ts.map +0 -1
- package/dist/runtime/types.js +0 -50
- package/dist/runtime/types.js.map +0 -1
- package/dist/runtime/values.d.ts +0 -50
- package/dist/runtime/values.d.ts.map +0 -1
- package/dist/runtime/values.js +0 -209
- package/dist/runtime/values.js.map +0 -1
- package/dist/runtime.d.ts +0 -254
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js +0 -2014
- package/dist/runtime.js.map +0 -1
|
@@ -15,9 +15,11 @@ const source = `
|
|
|
15
15
|
const ast = parse(source);
|
|
16
16
|
const ctx = createRuntimeContext({
|
|
17
17
|
functions: {
|
|
18
|
-
prompt:
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
prompt: {
|
|
19
|
+
params: [{ name: 'text', type: 'string' }],
|
|
20
|
+
fn: async (args) => {
|
|
21
|
+
return await callYourLLM(args[0]);
|
|
22
|
+
},
|
|
21
23
|
},
|
|
22
24
|
},
|
|
23
25
|
});
|
|
@@ -33,7 +35,7 @@ The `createRuntimeContext()` function accepts these options:
|
|
|
33
35
|
| Option | Type | Description |
|
|
34
36
|
|--------|------|-------------|
|
|
35
37
|
| `variables` | `Record<string, RillValue>` | Initial variables accessible as `$name` |
|
|
36
|
-
| `functions` | `Record<string,
|
|
38
|
+
| `functions` | `Record<string, HostFunctionDefinition>` | Custom functions callable as `name()` |
|
|
37
39
|
| `callbacks` | `Partial<RuntimeCallbacks>` | I/O callbacks (e.g., `onLog`) |
|
|
38
40
|
| `observability` | `ObservabilityCallbacks` | Execution monitoring hooks |
|
|
39
41
|
| `timeout` | `number` | Timeout in ms for async functions |
|
|
@@ -51,18 +53,24 @@ Host functions must follow these rules to ensure correct script behavior:
|
|
|
51
53
|
```typescript
|
|
52
54
|
// WRONG: Mutates input array
|
|
53
55
|
functions: {
|
|
54
|
-
addItem:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
addItem: {
|
|
57
|
+
params: [{ name: 'list', type: 'list' }],
|
|
58
|
+
fn: (args) => {
|
|
59
|
+
const list = args[0] as unknown[];
|
|
60
|
+
list.push('new'); // DON'T DO THIS
|
|
61
|
+
return list;
|
|
62
|
+
},
|
|
58
63
|
},
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
// CORRECT: Return new value
|
|
62
67
|
functions: {
|
|
63
|
-
addItem:
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
addItem: {
|
|
69
|
+
params: [{ name: 'list', type: 'list' }],
|
|
70
|
+
fn: (args) => {
|
|
71
|
+
const list = args[0] as unknown[];
|
|
72
|
+
return [...list, 'new']; // Create new array
|
|
73
|
+
},
|
|
66
74
|
},
|
|
67
75
|
}
|
|
68
76
|
```
|
|
@@ -75,9 +83,12 @@ For maximum safety, consider freezing values passed to host functions:
|
|
|
75
83
|
import { deepFreeze } from './utils'; // Your utility
|
|
76
84
|
|
|
77
85
|
functions: {
|
|
78
|
-
process:
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
process: {
|
|
87
|
+
params: [{ name: 'input', type: 'string' }],
|
|
88
|
+
fn: (args) => {
|
|
89
|
+
const frozen = deepFreeze(args[0]);
|
|
90
|
+
return transform(frozen); // Any mutation throws
|
|
91
|
+
},
|
|
81
92
|
},
|
|
82
93
|
}
|
|
83
94
|
```
|
|
@@ -96,31 +107,40 @@ Functions are called by name: `functionName(arg1, arg2)`.
|
|
|
96
107
|
const ctx = createRuntimeContext({
|
|
97
108
|
functions: {
|
|
98
109
|
// Sync function
|
|
99
|
-
add:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
add: {
|
|
111
|
+
params: [
|
|
112
|
+
{ name: 'a', type: 'number' },
|
|
113
|
+
{ name: 'b', type: 'number' },
|
|
114
|
+
],
|
|
115
|
+
fn: (args) => args[0] + args[1],
|
|
103
116
|
},
|
|
104
117
|
|
|
105
118
|
// Async function
|
|
106
|
-
fetch:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
fetch: {
|
|
120
|
+
params: [{ name: 'url', type: 'string' }],
|
|
121
|
+
fn: async (args, ctx, location) => {
|
|
122
|
+
const response = await fetch(args[0]);
|
|
123
|
+
return await response.text();
|
|
124
|
+
},
|
|
110
125
|
},
|
|
111
126
|
|
|
112
127
|
// Function with context access
|
|
113
|
-
getVar:
|
|
114
|
-
|
|
115
|
-
|
|
128
|
+
getVar: {
|
|
129
|
+
params: [{ name: 'name', type: 'string' }],
|
|
130
|
+
fn: (args, ctx) => {
|
|
131
|
+
return ctx.variables.get(args[0]) ?? null;
|
|
132
|
+
},
|
|
116
133
|
},
|
|
117
134
|
|
|
118
135
|
// Function with location for error reporting
|
|
119
|
-
validate:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
136
|
+
validate: {
|
|
137
|
+
params: [{ name: 'value', type: 'string' }],
|
|
138
|
+
fn: (args, ctx, location) => {
|
|
139
|
+
if (!args[0]) {
|
|
140
|
+
throw new Error(`Validation failed at line ${location?.line}`);
|
|
141
|
+
}
|
|
142
|
+
return args[0];
|
|
143
|
+
},
|
|
124
144
|
},
|
|
125
145
|
},
|
|
126
146
|
});
|
|
@@ -134,14 +154,41 @@ Use `::` to organize functions into namespaces:
|
|
|
134
154
|
const ctx = createRuntimeContext({
|
|
135
155
|
functions: {
|
|
136
156
|
// Namespaced functions use :: separator
|
|
137
|
-
'math::add':
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
157
|
+
'math::add': {
|
|
158
|
+
params: [
|
|
159
|
+
{ name: 'a', type: 'number' },
|
|
160
|
+
{ name: 'b', type: 'number' },
|
|
161
|
+
],
|
|
162
|
+
fn: (args) => args[0] + args[1],
|
|
163
|
+
},
|
|
164
|
+
'math::multiply': {
|
|
165
|
+
params: [
|
|
166
|
+
{ name: 'a', type: 'number' },
|
|
167
|
+
{ name: 'b', type: 'number' },
|
|
168
|
+
],
|
|
169
|
+
fn: (args) => args[0] * args[1],
|
|
170
|
+
},
|
|
171
|
+
'str::upper': {
|
|
172
|
+
params: [{ name: 'text', type: 'string' }],
|
|
173
|
+
fn: (args) => args[0].toUpperCase(),
|
|
174
|
+
},
|
|
175
|
+
'str::lower': {
|
|
176
|
+
params: [{ name: 'text', type: 'string' }],
|
|
177
|
+
fn: (args) => args[0].toLowerCase(),
|
|
178
|
+
},
|
|
141
179
|
|
|
142
180
|
// Multi-level namespaces
|
|
143
|
-
'io::file::read':
|
|
144
|
-
|
|
181
|
+
'io::file::read': {
|
|
182
|
+
params: [{ name: 'path', type: 'string' }],
|
|
183
|
+
fn: async (args) => fs.readFile(args[0], 'utf-8'),
|
|
184
|
+
},
|
|
185
|
+
'io::file::write': {
|
|
186
|
+
params: [
|
|
187
|
+
{ name: 'path', type: 'string' },
|
|
188
|
+
{ name: 'content', type: 'string' },
|
|
189
|
+
],
|
|
190
|
+
fn: async (args) => fs.writeFile(args[0], args[1]),
|
|
191
|
+
},
|
|
145
192
|
},
|
|
146
193
|
});
|
|
147
194
|
```
|
|
@@ -159,6 +206,8 @@ Namespaces help organize host APIs and avoid name collisions without requiring t
|
|
|
159
206
|
|
|
160
207
|
### CallableFn Signature
|
|
161
208
|
|
|
209
|
+
The `fn` property in `HostFunctionDefinition` uses the `CallableFn` type:
|
|
210
|
+
|
|
162
211
|
```typescript
|
|
163
212
|
type CallableFn = (
|
|
164
213
|
args: RillValue[],
|
|
@@ -169,17 +218,17 @@ type CallableFn = (
|
|
|
169
218
|
|
|
170
219
|
| Parameter | Description |
|
|
171
220
|
|-----------|-------------|
|
|
172
|
-
| `args` | Positional arguments passed to the function |
|
|
221
|
+
| `args` | Positional arguments passed to the function (already validated against `params`) |
|
|
173
222
|
| `ctx` | Runtime context with variables, pipeValue, etc. |
|
|
174
223
|
| `location` | Source location of the call site (for error reporting) |
|
|
175
224
|
|
|
176
|
-
##
|
|
225
|
+
## Host Function Type Declarations
|
|
177
226
|
|
|
178
|
-
|
|
227
|
+
All host functions must declare parameter types and optional defaults using the `HostFunctionDefinition` interface. The runtime validates arguments before calling your function, eliminating manual type checking.
|
|
179
228
|
|
|
180
|
-
###
|
|
229
|
+
### Parameter Type Declarations
|
|
181
230
|
|
|
182
|
-
Declare parameter types
|
|
231
|
+
Declare parameter types in the `params` array:
|
|
183
232
|
|
|
184
233
|
```typescript
|
|
185
234
|
const ctx = createRuntimeContext({
|
|
@@ -254,62 +303,6 @@ Error details include:
|
|
|
254
303
|
- Expected type
|
|
255
304
|
- Actual type received
|
|
256
305
|
|
|
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
306
|
### HostFunctionDefinition Interface
|
|
314
307
|
|
|
315
308
|
```typescript
|
|
@@ -439,9 +432,12 @@ const controller = new AbortController();
|
|
|
439
432
|
const ctx = createRuntimeContext({
|
|
440
433
|
signal: controller.signal,
|
|
441
434
|
functions: {
|
|
442
|
-
longTask:
|
|
443
|
-
|
|
444
|
-
|
|
435
|
+
longTask: {
|
|
436
|
+
params: [],
|
|
437
|
+
fn: async () => {
|
|
438
|
+
await new Promise((r) => setTimeout(r, 10000));
|
|
439
|
+
return 'done';
|
|
440
|
+
},
|
|
445
441
|
},
|
|
446
442
|
},
|
|
447
443
|
});
|
|
@@ -620,10 +616,13 @@ Set a timeout for async operations:
|
|
|
620
616
|
const ctx = createRuntimeContext({
|
|
621
617
|
timeout: 30000, // 30 seconds
|
|
622
618
|
functions: {
|
|
623
|
-
slowOperation:
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
619
|
+
slowOperation: {
|
|
620
|
+
params: [],
|
|
621
|
+
fn: async () => {
|
|
622
|
+
// Will throw TimeoutError if exceeds 30s
|
|
623
|
+
await longRunningTask();
|
|
624
|
+
return 'done';
|
|
625
|
+
},
|
|
627
626
|
},
|
|
628
627
|
},
|
|
629
628
|
});
|
|
@@ -640,10 +639,13 @@ const ctx = createRuntimeContext({
|
|
|
640
639
|
'FATAL', // Matches "FATAL" anywhere
|
|
641
640
|
],
|
|
642
641
|
functions: {
|
|
643
|
-
process:
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
642
|
+
process: {
|
|
643
|
+
params: [{ name: 'input', type: 'string' }],
|
|
644
|
+
fn: (args) => {
|
|
645
|
+
// If this returns "error: invalid input",
|
|
646
|
+
// execution halts with AutoExceptionError
|
|
647
|
+
return externalProcess(args[0]);
|
|
648
|
+
},
|
|
647
649
|
},
|
|
648
650
|
},
|
|
649
651
|
});
|
|
@@ -749,9 +751,12 @@ const ctx = createRuntimeContext({
|
|
|
749
751
|
},
|
|
750
752
|
|
|
751
753
|
functions: {
|
|
752
|
-
prompt:
|
|
753
|
-
|
|
754
|
-
|
|
754
|
+
prompt: {
|
|
755
|
+
params: [{ name: 'text', type: 'string' }],
|
|
756
|
+
fn: async (args, ctx, location) => {
|
|
757
|
+
console.log(`[prompt at line ${location?.line}]`);
|
|
758
|
+
return await callLLM(args[0]);
|
|
759
|
+
},
|
|
755
760
|
},
|
|
756
761
|
},
|
|
757
762
|
|
package/docs/15_grammar.ebnf
CHANGED
|
@@ -188,7 +188,7 @@ body = block | grouped-expr | postfix-expr ;
|
|
|
188
188
|
closure = "|" , [ closure-param , { "," , closure-param } ] , "|" , body ;
|
|
189
189
|
|
|
190
190
|
string = '"' , { char | escape | brace-escape | interpolation } , '"'
|
|
191
|
-
| "
|
|
191
|
+
| '"""' , { char | escape | brace-escape | interpolation } , '"""' ;
|
|
192
192
|
|
|
193
193
|
char = letter | digit | " " | "!" | "#" | "$" | "%" | "&" | "'" | "(" | ")"
|
|
194
194
|
| "*" | "+" | "," | "-" | "." | "/" | ":" | ";" | "<" | "=" | ">"
|
|
@@ -196,10 +196,6 @@ char = letter | digit | " " | "!" | "#" | "$" | "%" | "&" | "'" | "(" |
|
|
|
196
196
|
(* excludes " \ { } which have special meaning in strings *)
|
|
197
197
|
escape = "\\" , ( "n" | "r" | "t" | "\\" | '"' ) ;
|
|
198
198
|
brace-escape = "{{" | "}}" ; (* {{ -> literal {, }} -> literal } *)
|
|
199
|
-
delimiter = identifier ;
|
|
200
|
-
heredoc-body = { heredoc-line } ; (* heredocs also support interpolation *)
|
|
201
|
-
heredoc-line = { heredoc-char | interpolation | brace-escape } , newline ;
|
|
202
|
-
heredoc-char = char | '"' | "\\" ; (* excludes { } which have special meaning *)
|
|
203
199
|
|
|
204
200
|
interpolation = "{" , expression , "}" ;
|
|
205
201
|
|
package/docs/16_conventions.md
CHANGED
|
@@ -318,16 +318,15 @@ parseJson($input):dict :> $data
|
|
|
318
318
|
|
|
319
319
|
## String Handling
|
|
320
320
|
|
|
321
|
-
### Use
|
|
321
|
+
### Use triple-quotes for multiline content
|
|
322
322
|
|
|
323
323
|
```text
|
|
324
|
-
|
|
324
|
+
"""
|
|
325
325
|
Analyze this content:
|
|
326
326
|
{$content}
|
|
327
327
|
|
|
328
328
|
Provide a summary.
|
|
329
|
-
|
|
330
|
-
)
|
|
329
|
+
"""
|
|
331
330
|
```
|
|
332
331
|
|
|
333
332
|
### Use .empty for emptiness checks
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# CLI Tools
|
|
2
|
+
|
|
3
|
+
rill ships three command-line tools for running and validating scripts.
|
|
4
|
+
|
|
5
|
+
## rill-exec
|
|
6
|
+
|
|
7
|
+
Execute a rill script file with arguments.
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
rill-exec <script.rill> [args...]
|
|
11
|
+
rill-exec - # Read from stdin
|
|
12
|
+
rill-exec --help
|
|
13
|
+
rill-exec --version
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Arguments
|
|
17
|
+
|
|
18
|
+
Positional arguments pass to the script as a string list in `$` (pipe value).
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
rill-exec greet.rill alice bob
|
|
22
|
+
# Inside script: $ == ["alice", "bob"]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Stdin
|
|
26
|
+
|
|
27
|
+
Use `-` to read a script from standard input:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
echo 'log("hello")' | rill-exec -
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Frontmatter Modules
|
|
34
|
+
|
|
35
|
+
Scripts with `use:` frontmatter load modules before execution:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
---
|
|
39
|
+
use:
|
|
40
|
+
- utils: ./lib/utils.rill
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
$utils.helper("input")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Exit Codes
|
|
47
|
+
|
|
48
|
+
| Return Value | Exit Code |
|
|
49
|
+
|-------------|-----------|
|
|
50
|
+
| `true` or non-empty string | 0 |
|
|
51
|
+
| `false` or empty string | 1 |
|
|
52
|
+
| `[0, "message"]` | 0 (prints message) |
|
|
53
|
+
| `[1, "message"]` | 1 (prints message) |
|
|
54
|
+
|
|
55
|
+
## rill-eval
|
|
56
|
+
|
|
57
|
+
Evaluate a single rill expression. No file context or module loading.
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
rill-eval <expression>
|
|
61
|
+
rill-eval --help
|
|
62
|
+
rill-eval --version
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Examples
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
rill-eval '"hello".len'
|
|
69
|
+
# 5
|
|
70
|
+
|
|
71
|
+
rill-eval '5 + 3'
|
|
72
|
+
# 8
|
|
73
|
+
|
|
74
|
+
rill-eval '[1, 2, 3] -> map |x|($x * 2)'
|
|
75
|
+
# [2, 4, 6]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## rill-check
|
|
79
|
+
|
|
80
|
+
Static analysis tool that validates rill scripts against lint rules.
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
rill-check [options] <file>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Options
|
|
87
|
+
|
|
88
|
+
| Flag | Description |
|
|
89
|
+
|------|-------------|
|
|
90
|
+
| `--fix` | Apply automatic fixes to the source file |
|
|
91
|
+
| `--format text` | Human-readable output (default) |
|
|
92
|
+
| `--format json` | Machine-readable JSON output |
|
|
93
|
+
| `--verbose` | Include rule category in JSON output |
|
|
94
|
+
| `-h`, `--help` | Show help |
|
|
95
|
+
| `-v`, `--version` | Show version |
|
|
96
|
+
|
|
97
|
+
### Exit Codes
|
|
98
|
+
|
|
99
|
+
| Code | Meaning |
|
|
100
|
+
|------|---------|
|
|
101
|
+
| 0 | No issues found |
|
|
102
|
+
| 1 | Diagnostics reported (or argument error) |
|
|
103
|
+
| 2 | File not found or unreadable |
|
|
104
|
+
| 3 | Parse error in source file |
|
|
105
|
+
|
|
106
|
+
### Output Formats
|
|
107
|
+
|
|
108
|
+
**Text** (default): one line per diagnostic.
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
script.rill:5:3: warning: message (RULE_CODE)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**JSON**: structured output with summary.
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"file": "script.rill",
|
|
119
|
+
"errors": [
|
|
120
|
+
{
|
|
121
|
+
"location": { "line": 5, "column": 3, "offset": 42 },
|
|
122
|
+
"severity": "warning",
|
|
123
|
+
"code": "RULE_CODE",
|
|
124
|
+
"message": "description"
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"summary": { "total": 1, "errors": 0, "warnings": 1, "info": 0 }
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Configuration
|
|
132
|
+
|
|
133
|
+
Place a `.rill-check.json` file in the project root to configure rules:
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"rules": {
|
|
138
|
+
"NAMING_SNAKE_CASE": "on",
|
|
139
|
+
"SPACING_OPERATOR": "off",
|
|
140
|
+
"COMPLEX_CONDITION": "warn"
|
|
141
|
+
},
|
|
142
|
+
"severity": {
|
|
143
|
+
"AVOID_REASSIGNMENT": "error"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Rule states: `"on"` (enabled), `"off"` (disabled), `"warn"` (downgrade to warning).
|
|
149
|
+
|
|
150
|
+
### Lint Rules
|
|
151
|
+
|
|
152
|
+
| Code | Category | Default | Description |
|
|
153
|
+
|------|----------|---------|-------------|
|
|
154
|
+
| `NAMING_SNAKE_CASE` | naming | error | Variable names must use snake_case |
|
|
155
|
+
| `AVOID_REASSIGNMENT` | anti-patterns | warning | Avoid reassigning captured variables |
|
|
156
|
+
| `COMPLEX_CONDITION` | anti-patterns | info | Condition expression is complex |
|
|
157
|
+
| `LOOP_OUTER_CAPTURE` | anti-patterns | warning | Loop body captures to outer variable |
|
|
158
|
+
| `USE_EMPTY_METHOD` | strings | warning | Use `.empty` instead of `.len == 0` |
|
|
159
|
+
| `UNNECESSARY_ASSERTION` | types | info | Type assertion on a literal value |
|
|
160
|
+
| `VALIDATE_EXTERNAL` | types | info | External data lacks type validation |
|
|
161
|
+
| `CAPTURE_INLINE_CHAIN` | flow | info | Capture breaks a pipe chain |
|
|
162
|
+
| `CAPTURE_BEFORE_BRANCH` | flow | info | Capture value before branching |
|
|
163
|
+
| `LOOP_ACCUMULATOR` | loops | info | Use accumulator `$@` pattern |
|
|
164
|
+
| `PREFER_DO_WHILE` | loops | info | Consider do-while for init-then-loop |
|
|
165
|
+
| `USE_EACH` | loops | info | Use `each` instead of while loop |
|
|
166
|
+
| `BREAK_IN_PARALLEL` | collections | error | `break` inside `map` or `filter` |
|
|
167
|
+
| `PREFER_MAP` | collections | info | Use `map` when body has no side effects |
|
|
168
|
+
| `FOLD_INTERMEDIATES` | collections | info | `fold` discards intermediate results |
|
|
169
|
+
| `FILTER_NEGATION` | collections | warning | Negated filter condition |
|
|
170
|
+
| `METHOD_SHORTHAND` | collections | info | Use method reference shorthand |
|
|
171
|
+
| `USE_DEFAULT_OPERATOR` | conditionals | info | Use `??` instead of conditional |
|
|
172
|
+
| `CONDITION_TYPE` | conditionals | warning | Condition not boolean |
|
|
173
|
+
| `CLOSURE_BARE_DOLLAR` | closures | warning | Stored closure uses bare `$` |
|
|
174
|
+
| `CLOSURE_BRACES` | closures | info | Multi-statement closure needs braces |
|
|
175
|
+
| `CLOSURE_LATE_BINDING` | closures | warning | Closure captures late-bound variable |
|
|
176
|
+
| `SPACING_OPERATOR` | formatting | info | Operators need surrounding spaces |
|
|
177
|
+
| `SPACING_BRACES` | formatting | info | Braces need inner spacing |
|
|
178
|
+
| `SPACING_BRACKETS` | formatting | info | Brackets need consistent spacing |
|
|
179
|
+
| `SPACING_CLOSURE` | formatting | info | Closure params need spacing |
|
|
180
|
+
| `INDENT_CONTINUATION` | formatting | info | Continuation line indentation |
|
|
181
|
+
| `IMPLICIT_DOLLAR_METHOD` | formatting | info | Prefer implicit `$` for methods |
|
|
182
|
+
| `IMPLICIT_DOLLAR_FUNCTION` | formatting | info | Prefer implicit `$` for functions |
|
|
183
|
+
| `IMPLICIT_DOLLAR_CLOSURE` | formatting | info | Prefer implicit `$` for closures |
|
|
184
|
+
| `THROWAWAY_CAPTURE` | formatting | info | Captured variable never used |
|
|
@@ -67,10 +67,17 @@ CRITICAL DIFFERENCES FROM MAINSTREAM LANGUAGES
|
|
|
67
67
|
"hello" :> $x
|
|
68
68
|
42 :> $x # ERROR: cannot assign number to string variable
|
|
69
69
|
|
|
70
|
-
5. NO VARIABLE SHADOWING
|
|
70
|
+
5. NO VARIABLE SHADOWING (CRITICAL FOR LOOPS)
|
|
71
71
|
Child scopes can READ parent variables but cannot WRITE or redeclare them.
|
|
72
72
|
Variables created inside blocks/loops do NOT leak out.
|
|
73
73
|
|
|
74
|
+
WRONG - this pattern NEVER works:
|
|
75
|
+
0 :> $count
|
|
76
|
+
[1, 2, 3] -> each { $count + 1 :> $count } # creates LOCAL $count
|
|
77
|
+
$count # still 0!
|
|
78
|
+
|
|
79
|
+
RIGHT - use $ or $@ as state carrier (see LOOP STATE PATTERNS below)
|
|
80
|
+
|
|
74
81
|
6. NO EXCEPTIONS
|
|
75
82
|
Errors halt execution. No try/catch. Use conditionals for error handling.
|
|
76
83
|
Script-level exit functions (error, stop) must be host-provided.
|
|
@@ -80,7 +87,7 @@ SYNTAX QUICK REFERENCE
|
|
|
80
87
|
|
|
81
88
|
Variables: $name (always prefixed with $)
|
|
82
89
|
Strings: "hello {$var}" # interpolation with {}
|
|
83
|
-
|
|
90
|
+
"""...""" # multiline (also interpolates)
|
|
84
91
|
Numbers: 42, 3.14, -7
|
|
85
92
|
Booleans: true, false
|
|
86
93
|
Lists: [1, 2, 3]
|
|
@@ -118,10 +125,10 @@ Conditional (if-else):
|
|
|
118
125
|
Piped conditional ($ becomes condition):
|
|
119
126
|
value -> ? then_expr ! else_expr
|
|
120
127
|
|
|
121
|
-
|
|
128
|
+
Condition loop (NO "while" keyword - use @ operator):
|
|
122
129
|
init_value -> ($ < 10) @ { $ + 1 } # $ is accumulator
|
|
123
130
|
|
|
124
|
-
Do-
|
|
131
|
+
Do-condition loop (body runs at least once):
|
|
125
132
|
init_value -> @ { $ + 1 } ? ($ < 10)
|
|
126
133
|
|
|
127
134
|
Break (exits loop, returns collected results before break):
|
|
@@ -131,6 +138,39 @@ Return (exits block or script with value):
|
|
|
131
138
|
{ 5 :> $x; ($x > 3) ? ("big" -> return); "small" } # returns "big"
|
|
132
139
|
"done" -> return # exits script with "done"
|
|
133
140
|
|
|
141
|
+
LOOP STATE PATTERNS (CRITICAL)
|
|
142
|
+
------------------------------
|
|
143
|
+
Rill loops CANNOT modify outer variables. All state must flow through $ or $@.
|
|
144
|
+
|
|
145
|
+
WRONG - outer variable modification (NEVER works):
|
|
146
|
+
0 :> $sum
|
|
147
|
+
[1, 2, 3] -> each { $sum + $ :> $sum } # $sum unchanged!
|
|
148
|
+
|
|
149
|
+
WRONG - "while" keyword does not exist:
|
|
150
|
+
while ($i < 10) { $i + 1 :> $i } # SYNTAX ERROR
|
|
151
|
+
|
|
152
|
+
RIGHT - use fold for reduction:
|
|
153
|
+
[1, 2, 3] -> fold(0) { $@ + $ } # 6 ($@ is accumulator)
|
|
154
|
+
|
|
155
|
+
RIGHT - use each(init) when you need both results AND accumulator:
|
|
156
|
+
[1, 2, 3] -> each(0) { $@ + $ } # [1, 3, 6] (running totals)
|
|
157
|
+
|
|
158
|
+
RIGHT - use (cond) @ { } with $ as state dict for multiple values:
|
|
159
|
+
[iter: 0, max: 3, text: $input, done: false]
|
|
160
|
+
-> (!$.done && $.iter < $.max) @ {
|
|
161
|
+
$.iter + 1 :> $i
|
|
162
|
+
process($.text) :> $result
|
|
163
|
+
$result.finished ? [iter: $i, max: $.max, text: $.text, done: true]
|
|
164
|
+
! [iter: $i, max: $.max, text: $result.text, done: false]
|
|
165
|
+
}
|
|
166
|
+
# Access final state: $.text, $.iter
|
|
167
|
+
|
|
168
|
+
Pattern summary:
|
|
169
|
+
- Single value accumulation -> fold(init) { $@ + $ }
|
|
170
|
+
- Per-item results + running -> each(init) { ... $@ ... }
|
|
171
|
+
- Multiple state values / while -> (cond) @ { } with $ as state dict
|
|
172
|
+
- "while" and "for" keywords -> DO NOT EXIST
|
|
173
|
+
|
|
134
174
|
COLLECTION OPERATORS
|
|
135
175
|
--------------------
|
|
136
176
|
|
|
@@ -286,10 +326,11 @@ COMMON MISTAKES
|
|
|
286
326
|
2. Using || for defaults -> use ?? instead
|
|
287
327
|
3. Assuming truthiness -> explicit boolean checks required
|
|
288
328
|
4. Breaking from map/filter -> only works in each/fold
|
|
289
|
-
5.
|
|
329
|
+
5. Modifying outer vars in loops -> use fold/$@ or $ as state dict (see LOOP STATE PATTERNS)
|
|
290
330
|
6. Expecting variables to leak -> block scope is strict
|
|
291
331
|
7. Forgetting () on methods -> .upper() not .upper (unless property)
|
|
292
332
|
8. Reassigning different type -> variables lock to first type
|
|
333
|
+
9. Using while/for keywords -> use (cond) @ { } or -> each { } instead
|
|
293
334
|
|
|
294
335
|
SCRIPT RETURN VALUES
|
|
295
336
|
--------------------
|