@rcrsr/rill 0.5.0 → 0.6.1
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 +88 -162
- package/dist/generated/introspection-data.d.ts +1 -1
- package/dist/generated/introspection-data.d.ts.map +1 -1
- package/dist/generated/introspection-data.js +107 -186
- package/dist/generated/introspection-data.js.map +1 -1
- package/dist/generated/version-data.d.ts +1 -1
- package/dist/generated/version-data.js +4 -4
- package/dist/generated/version-data.js.map +1 -1
- package/dist/highlight-map.d.ts +4 -0
- package/dist/highlight-map.d.ts.map +1 -0
- package/dist/highlight-map.js +71 -0
- package/dist/highlight-map.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lexer/errors.d.ts.map +1 -1
- package/dist/lexer/errors.js +9 -3
- package/dist/lexer/errors.js.map +1 -1
- package/dist/lexer/operators.js +1 -1
- package/dist/lexer/tokenizer.d.ts.map +1 -1
- package/dist/lexer/tokenizer.js +0 -14
- package/dist/lexer/tokenizer.js.map +1 -1
- package/dist/parser/helpers.d.ts +8 -0
- package/dist/parser/helpers.d.ts.map +1 -1
- package/dist/parser/helpers.js +4 -4
- package/dist/parser/helpers.js.map +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +1 -1
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/parser-collect.js +1 -1
- package/dist/parser/parser-collect.js.map +1 -1
- package/dist/parser/parser-control.js +4 -4
- package/dist/parser/parser-control.js.map +1 -1
- package/dist/parser/parser-expr.js +32 -10
- package/dist/parser/parser-expr.js.map +1 -1
- package/dist/parser/parser-extract.js +7 -3
- package/dist/parser/parser-extract.js.map +1 -1
- package/dist/parser/parser-functions.d.ts.map +1 -1
- package/dist/parser/parser-functions.js +7 -18
- package/dist/parser/parser-functions.js.map +1 -1
- package/dist/parser/parser-literals.js +15 -15
- package/dist/parser/parser-literals.js.map +1 -1
- package/dist/parser/parser-script.js +3 -3
- package/dist/parser/parser-script.js.map +1 -1
- package/dist/parser/parser-variables.js +4 -4
- package/dist/parser/parser-variables.js.map +1 -1
- package/dist/parser/state.d.ts +1 -1
- package/dist/parser/state.d.ts.map +1 -1
- package/dist/parser/state.js +2 -2
- package/dist/parser/state.js.map +1 -1
- package/dist/runtime/core/callable.d.ts +20 -0
- package/dist/runtime/core/callable.d.ts.map +1 -1
- package/dist/runtime/core/callable.js +30 -7
- package/dist/runtime/core/callable.js.map +1 -1
- package/dist/runtime/core/context.d.ts +21 -0
- package/dist/runtime/core/context.d.ts.map +1 -1
- package/dist/runtime/core/context.js +75 -4
- package/dist/runtime/core/context.js.map +1 -1
- package/dist/runtime/core/eval/base.d.ts.map +1 -1
- package/dist/runtime/core/eval/base.js +3 -3
- package/dist/runtime/core/eval/base.js.map +1 -1
- package/dist/runtime/core/eval/index.d.ts.map +1 -1
- package/dist/runtime/core/eval/index.js +2 -0
- package/dist/runtime/core/eval/index.js.map +1 -1
- package/dist/runtime/core/eval/mixins/annotations.js +3 -3
- package/dist/runtime/core/eval/mixins/annotations.js.map +1 -1
- package/dist/runtime/core/eval/mixins/closures.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/closures.js +69 -40
- package/dist/runtime/core/eval/mixins/closures.js.map +1 -1
- package/dist/runtime/core/eval/mixins/collections.js +15 -15
- package/dist/runtime/core/eval/mixins/collections.js.map +1 -1
- package/dist/runtime/core/eval/mixins/control-flow.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/control-flow.js +12 -12
- package/dist/runtime/core/eval/mixins/control-flow.js.map +1 -1
- package/dist/runtime/core/eval/mixins/core.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/core.js +12 -13
- package/dist/runtime/core/eval/mixins/core.js.map +1 -1
- package/dist/runtime/core/eval/mixins/expressions.js +9 -9
- package/dist/runtime/core/eval/mixins/expressions.js.map +1 -1
- package/dist/runtime/core/eval/mixins/extraction.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/extraction.js +15 -15
- package/dist/runtime/core/eval/mixins/extraction.js.map +1 -1
- package/dist/runtime/core/eval/mixins/literals.js +22 -22
- package/dist/runtime/core/eval/mixins/literals.js.map +1 -1
- package/dist/runtime/core/eval/mixins/types.js +4 -4
- package/dist/runtime/core/eval/mixins/types.js.map +1 -1
- package/dist/runtime/core/eval/mixins/variables.js +34 -34
- package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
- package/dist/runtime/core/execute.js +3 -3
- package/dist/runtime/core/execute.js.map +1 -1
- package/dist/runtime/core/introspection.d.ts +30 -1
- package/dist/runtime/core/introspection.d.ts.map +1 -1
- package/dist/runtime/core/introspection.js +47 -1
- package/dist/runtime/core/introspection.js.map +1 -1
- package/dist/runtime/core/types.d.ts +11 -0
- package/dist/runtime/core/types.d.ts.map +1 -1
- package/dist/runtime/core/types.js.map +1 -1
- package/dist/runtime/ext/builtins.js +22 -22
- package/dist/runtime/ext/builtins.js.map +1 -1
- package/dist/runtime/ext/extensions.d.ts +1 -1
- package/dist/runtime/ext/extensions.d.ts.map +1 -1
- package/dist/runtime/ext/extensions.js +4 -5
- package/dist/runtime/ext/extensions.js.map +1 -1
- package/dist/runtime/index.d.ts +6 -4
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +3 -2
- package/dist/runtime/index.js.map +1 -1
- package/dist/types.d.ts +36 -37
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +440 -120
- package/dist/types.js.map +1 -1
- package/package.json +7 -66
- package/dist/check/config.d.ts +0 -20
- package/dist/check/config.d.ts.map +0 -1
- package/dist/check/config.js +0 -151
- package/dist/check/config.js.map +0 -1
- package/dist/check/fixer.d.ts +0 -39
- package/dist/check/fixer.d.ts.map +0 -1
- package/dist/check/fixer.js +0 -119
- package/dist/check/fixer.js.map +0 -1
- package/dist/check/index.d.ts +0 -10
- package/dist/check/index.d.ts.map +0 -1
- package/dist/check/index.js +0 -21
- package/dist/check/index.js.map +0 -1
- package/dist/check/rules/anti-patterns.d.ts +0 -65
- package/dist/check/rules/anti-patterns.d.ts.map +0 -1
- package/dist/check/rules/anti-patterns.js +0 -481
- package/dist/check/rules/anti-patterns.js.map +0 -1
- package/dist/check/rules/closures.d.ts +0 -66
- package/dist/check/rules/closures.d.ts.map +0 -1
- package/dist/check/rules/closures.js +0 -370
- package/dist/check/rules/closures.js.map +0 -1
- package/dist/check/rules/collections.d.ts +0 -90
- package/dist/check/rules/collections.d.ts.map +0 -1
- package/dist/check/rules/collections.js +0 -373
- package/dist/check/rules/collections.js.map +0 -1
- package/dist/check/rules/conditionals.d.ts +0 -41
- package/dist/check/rules/conditionals.d.ts.map +0 -1
- package/dist/check/rules/conditionals.js +0 -134
- package/dist/check/rules/conditionals.js.map +0 -1
- package/dist/check/rules/flow.d.ts +0 -46
- package/dist/check/rules/flow.d.ts.map +0 -1
- package/dist/check/rules/flow.js +0 -206
- package/dist/check/rules/flow.js.map +0 -1
- package/dist/check/rules/formatting.d.ts +0 -133
- package/dist/check/rules/formatting.d.ts.map +0 -1
- package/dist/check/rules/formatting.js +0 -648
- package/dist/check/rules/formatting.js.map +0 -1
- package/dist/check/rules/helpers.d.ts +0 -26
- package/dist/check/rules/helpers.d.ts.map +0 -1
- package/dist/check/rules/helpers.js +0 -66
- package/dist/check/rules/helpers.js.map +0 -1
- package/dist/check/rules/index.d.ts +0 -21
- package/dist/check/rules/index.d.ts.map +0 -1
- package/dist/check/rules/index.js +0 -78
- package/dist/check/rules/index.js.map +0 -1
- package/dist/check/rules/loops.d.ts +0 -77
- package/dist/check/rules/loops.d.ts.map +0 -1
- package/dist/check/rules/loops.js +0 -310
- package/dist/check/rules/loops.js.map +0 -1
- package/dist/check/rules/naming.d.ts +0 -21
- package/dist/check/rules/naming.d.ts.map +0 -1
- package/dist/check/rules/naming.js +0 -174
- package/dist/check/rules/naming.js.map +0 -1
- package/dist/check/rules/strings.d.ts +0 -28
- package/dist/check/rules/strings.d.ts.map +0 -1
- package/dist/check/rules/strings.js +0 -79
- package/dist/check/rules/strings.js.map +0 -1
- package/dist/check/rules/types.d.ts +0 -41
- package/dist/check/rules/types.d.ts.map +0 -1
- package/dist/check/rules/types.js +0 -167
- package/dist/check/rules/types.js.map +0 -1
- package/dist/check/types.d.ts +0 -112
- package/dist/check/types.d.ts.map +0 -1
- package/dist/check/types.js +0 -6
- package/dist/check/types.js.map +0 -1
- package/dist/check/validator.d.ts +0 -18
- package/dist/check/validator.d.ts.map +0 -1
- package/dist/check/validator.js +0 -110
- package/dist/check/validator.js.map +0 -1
- package/dist/check/visitor.d.ts +0 -33
- package/dist/check/visitor.d.ts.map +0 -1
- package/dist/check/visitor.js +0 -259
- package/dist/check/visitor.js.map +0 -1
- package/dist/cli-check.d.ts +0 -43
- package/dist/cli-check.d.ts.map +0 -1
- package/dist/cli-check.js +0 -368
- package/dist/cli-check.js.map +0 -1
- package/dist/cli-eval.d.ts +0 -15
- package/dist/cli-eval.d.ts.map +0 -1
- package/dist/cli-eval.js +0 -116
- package/dist/cli-eval.js.map +0 -1
- package/dist/cli-exec.d.ts +0 -49
- package/dist/cli-exec.d.ts.map +0 -1
- package/dist/cli-exec.js +0 -183
- package/dist/cli-exec.js.map +0 -1
- package/dist/cli-module-loader.d.ts +0 -19
- package/dist/cli-module-loader.d.ts.map +0 -1
- package/dist/cli-module-loader.js +0 -83
- package/dist/cli-module-loader.js.map +0 -1
- package/dist/cli-shared.d.ts +0 -44
- package/dist/cli-shared.d.ts.map +0 -1
- package/dist/cli-shared.js +0 -108
- package/dist/cli-shared.js.map +0 -1
- package/dist/cli.d.ts +0 -13
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -62
- package/dist/cli.js.map +0 -1
- package/dist/runtime/core/introspection-data.d.ts +0 -2
- package/dist/runtime/core/introspection-data.d.ts.map +0 -1
- package/dist/runtime/core/introspection-data.js +0 -618
- package/dist/runtime/core/introspection-data.js.map +0 -1
- package/dist/runtime/core/version-data.d.ts +0 -18
- package/dist/runtime/core/version-data.d.ts.map +0 -1
- package/dist/runtime/core/version-data.js +0 -16
- package/dist/runtime/core/version-data.js.map +0 -1
- package/docs/00_INDEX.md +0 -67
- package/docs/01_guide.md +0 -390
- package/docs/02_types.md +0 -504
- package/docs/03_variables.md +0 -324
- package/docs/04_operators.md +0 -629
- package/docs/05_control-flow.md +0 -692
- package/docs/06_closures.md +0 -787
- package/docs/07_collections.md +0 -688
- package/docs/08_iterators.md +0 -330
- package/docs/09_strings.md +0 -205
- package/docs/10_parsing.md +0 -366
- package/docs/11_reference.md +0 -600
- package/docs/12_examples.md +0 -748
- package/docs/13_modules.md +0 -519
- package/docs/14_host-integration.md +0 -985
- package/docs/15_grammar.ebnf +0 -773
- package/docs/16_conventions.md +0 -695
- package/docs/17_cli-tools.md +0 -184
- package/docs/18_design-principles.md +0 -247
- package/docs/19_cookbook.md +0 -628
- package/docs/88_errors.md +0 -902
- package/docs/99_llm-reference.txt +0 -614
- package/docs/assets/logo.png +0 -0
package/docs/05_control-flow.md
DELETED
|
@@ -1,692 +0,0 @@
|
|
|
1
|
-
# rill Control Flow
|
|
2
|
-
|
|
3
|
-
*Conditionals, loops, break, and return*
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
rill provides singular control flow—no exceptions, no try/catch. Errors halt execution. Recovery requires explicit conditionals.
|
|
8
|
-
|
|
9
|
-
| Syntax | Description |
|
|
10
|
-
|--------|-------------|
|
|
11
|
-
| `cond ? then ! else` | Conditional (if-else) |
|
|
12
|
-
| `$val -> ? then ! else` | Piped conditional (uses $ as cond) |
|
|
13
|
-
| `(cond) @ body` | While loop (cond is bool) |
|
|
14
|
-
| `@ body ? cond` | Do-while (body first) |
|
|
15
|
-
| `break` / `$val -> break` | Exit loop |
|
|
16
|
-
| `return` / `$val -> return` | Exit block |
|
|
17
|
-
| `assert cond` / `assert cond "msg"` | Validate condition, halt on failure |
|
|
18
|
-
| `error "msg"` / `$val -> error` | Halt execution with error message |
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Conditionals
|
|
23
|
-
|
|
24
|
-
`?` is the conditional operator. The condition precedes `?`, and `!` introduces the else clause.
|
|
25
|
-
|
|
26
|
-
### Syntax Forms
|
|
27
|
-
|
|
28
|
-
```text
|
|
29
|
-
condition ? then-body
|
|
30
|
-
condition ? then-body ! else-body
|
|
31
|
-
$val -> ? then-body ! else-body # piped form: $ is the condition
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Standalone Form
|
|
35
|
-
|
|
36
|
-
Condition precedes `?`:
|
|
37
|
-
|
|
38
|
-
```rill
|
|
39
|
-
true ? "yes" ! "no" # "yes"
|
|
40
|
-
false ? "yes" ! "no" # "no"
|
|
41
|
-
(5 > 3) ? "big" ! "small" # grouped comparison as condition
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Piped Form
|
|
45
|
-
|
|
46
|
-
Use `$` as condition:
|
|
47
|
-
|
|
48
|
-
```rill
|
|
49
|
-
true -> ? "yes" ! "no" # "yes" (pipe value must be bool)
|
|
50
|
-
5 -> ($ > 3) ? "big" ! "small" # "big"
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Method Conditions
|
|
54
|
-
|
|
55
|
-
Methods that return booleans work directly as conditions:
|
|
56
|
-
|
|
57
|
-
```rill
|
|
58
|
-
"hello" -> .contains("ell") ? "found" ! "missing" # "found"
|
|
59
|
-
"abc" -> !.empty ? "has content" ! "empty" # "has content"
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Condition Forms
|
|
63
|
-
|
|
64
|
-
```rill
|
|
65
|
-
"test" -> ($ == "test") ? "match" ! "no" # grouped comparison
|
|
66
|
-
"test" -> .eq("test") ? "match" ! "no" # comparison method
|
|
67
|
-
"xyz" -> .contains("x") ? "found" ! "no" # method as condition
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Optional Else
|
|
71
|
-
|
|
72
|
-
The else branch (`! ...`) is optional:
|
|
73
|
-
|
|
74
|
-
```rill
|
|
75
|
-
true ? "executed" # only runs if true
|
|
76
|
-
false ? "skipped" # returns empty string
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Else-If Chains
|
|
80
|
-
|
|
81
|
-
```rill
|
|
82
|
-
"B" :> $val
|
|
83
|
-
$val -> .eq("A") ? "a" ! .eq("B") ? "b" ! "other" # "b"
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Return Value
|
|
87
|
-
|
|
88
|
-
Conditionals return the last expression of the executed branch:
|
|
89
|
-
|
|
90
|
-
```rill
|
|
91
|
-
true -> ? "yes" ! "no" :> $result # "yes"
|
|
92
|
-
false -> ? "yes" ! "no" :> $result # "no"
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Block Bodies
|
|
96
|
-
|
|
97
|
-
Use braces for multi-statement branches:
|
|
98
|
-
|
|
99
|
-
```rill
|
|
100
|
-
true -> ? {
|
|
101
|
-
"step 1" -> log
|
|
102
|
-
"step 2" -> log
|
|
103
|
-
"done"
|
|
104
|
-
} ! {
|
|
105
|
-
"skipped"
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## While Loop
|
|
112
|
-
|
|
113
|
-
Pre-condition loop. Condition is evaluated before each iteration. The body result becomes the next iteration's `$`.
|
|
114
|
-
|
|
115
|
-
> **Note:** There is no `while` keyword. Use `(condition) @ { body }` syntax. Loop bodies cannot modify outer-scope variables—use `$` to carry all state. For multiple values, pack them in a dict.
|
|
116
|
-
|
|
117
|
-
### Syntax
|
|
118
|
-
|
|
119
|
-
```text
|
|
120
|
-
initial -> (condition) @ { body }
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### Basic Usage
|
|
124
|
-
|
|
125
|
-
```rill
|
|
126
|
-
# Count to 5
|
|
127
|
-
0 -> ($ < 5) @ { $ + 1 } # Result: 5
|
|
128
|
-
|
|
129
|
-
# String accumulation
|
|
130
|
-
"" -> (.len < 5) @ { "{$}x" } # Result: "xxxxx"
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Condition Forms
|
|
134
|
-
|
|
135
|
-
```rill
|
|
136
|
-
0 -> ($ < 10) @ { $ + 1 } # comparison condition
|
|
137
|
-
"" -> (.len < 5) @ { "{$}x" } # method call condition
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### Infinite Loop with Break
|
|
141
|
-
|
|
142
|
-
```rill
|
|
143
|
-
0 -> (true) @ {
|
|
144
|
-
$ + 1 -> ($ > 5) ? break ! $
|
|
145
|
-
} # Result: 6
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Loop Limits
|
|
149
|
-
|
|
150
|
-
Use `^(limit: N)` annotation to set maximum iterations (default: 10,000):
|
|
151
|
-
|
|
152
|
-
```rill
|
|
153
|
-
^(limit: 100) 0 -> ($ < 10) @ { $ + 1 } # Runs 10 iterations, returns 10
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
Exceeding the limit throws `RuntimeError` with code `RUNTIME_LIMIT_EXCEEDED`.
|
|
157
|
-
|
|
158
|
-
### Multiple State Values
|
|
159
|
-
|
|
160
|
-
When you need to track multiple values across iterations, use `$` as a state dict:
|
|
161
|
-
|
|
162
|
-
```text
|
|
163
|
-
# Track iteration count, text, and done flag
|
|
164
|
-
[iter: 0, text: $input, done: false]
|
|
165
|
-
-> (!$.done && $.iter < 3) @ {
|
|
166
|
-
$.iter + 1 :> $i
|
|
167
|
-
app::process($.text) :> $result
|
|
168
|
-
$result.finished
|
|
169
|
-
? [iter: $i, text: $.text, done: true]
|
|
170
|
-
! [iter: $i, text: $result.text, done: false]
|
|
171
|
-
}
|
|
172
|
-
# Access final state: $.text, $.iter
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
This pattern replaces the common (but invalid) approach of trying to modify outer variables from inside the loop.
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
## Do-While Loop
|
|
180
|
-
|
|
181
|
-
Post-condition loop. Body executes first, then condition is checked. Use when you want at least one execution.
|
|
182
|
-
|
|
183
|
-
### Syntax
|
|
184
|
-
|
|
185
|
-
```text
|
|
186
|
-
initial -> @ { body } ? (condition)
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Basic Usage
|
|
190
|
-
|
|
191
|
-
```rill
|
|
192
|
-
# Execute at least once, continue while condition holds
|
|
193
|
-
0 -> @ { $ + 1 } ? ($ < 5) # Returns 5
|
|
194
|
-
|
|
195
|
-
# String accumulation
|
|
196
|
-
"" -> @ { "{$}x" } ? (.len < 3) # Returns "xxx"
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### When to Use
|
|
200
|
-
|
|
201
|
-
- **While** `(condition) @ { body }`: condition checked BEFORE body (may execute 0 times)
|
|
202
|
-
- **Do-while** `@ { body } ? (condition)`: condition checked AFTER body (executes at least once)
|
|
203
|
-
|
|
204
|
-
### Retry Pattern
|
|
205
|
-
|
|
206
|
-
Do-while is ideal for retry patterns:
|
|
207
|
-
|
|
208
|
-
```text
|
|
209
|
-
^(limit: 5) @ {
|
|
210
|
-
app::prompt("Perform operation")
|
|
211
|
-
} ? (.contains("RETRY"))
|
|
212
|
-
# Loop exits when result doesn't contain RETRY
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### Loop Limit
|
|
216
|
-
|
|
217
|
-
```rill
|
|
218
|
-
^(limit: 100) 0 -> @ { $ + 1 } ? ($ < 10) # Returns 10
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
## Break
|
|
224
|
-
|
|
225
|
-
Exit a loop early. Returns the value piped to `break`, or current `$` if bare.
|
|
226
|
-
|
|
227
|
-
### Syntax
|
|
228
|
-
|
|
229
|
-
```text
|
|
230
|
-
break # exit with current $
|
|
231
|
-
$value -> break # exit with value
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### In Each Loop
|
|
235
|
-
|
|
236
|
-
```rill
|
|
237
|
-
[1, 2, 3, 4, 5] -> each {
|
|
238
|
-
($ > 3) ? ("found {$}" -> break)
|
|
239
|
-
$
|
|
240
|
-
}
|
|
241
|
-
# Returns "found 4"
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### In While Loop
|
|
245
|
-
|
|
246
|
-
```rill
|
|
247
|
-
0 -> (true) @ {
|
|
248
|
-
($ + 1) -> ($ > 3) ? break ! $
|
|
249
|
-
}
|
|
250
|
-
# Returns 4
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### Break Value
|
|
254
|
-
|
|
255
|
-
In `each`, break returns partial results collected before the break:
|
|
256
|
-
|
|
257
|
-
```rill
|
|
258
|
-
["a", "b", "STOP", "c"] -> each {
|
|
259
|
-
($ == "STOP") ? break
|
|
260
|
-
$
|
|
261
|
-
}
|
|
262
|
-
# Returns ["a", "b"] (partial results before break)
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
### Break Not Allowed
|
|
266
|
-
|
|
267
|
-
`break` is not supported in `map`, `filter`, or `fold` (parallel operations):
|
|
268
|
-
|
|
269
|
-
```text
|
|
270
|
-
[1, 2, 3] -> map { break } # ERROR: break not supported in map
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
## Return
|
|
276
|
-
|
|
277
|
-
Exit a block early. Returns the value piped to `return`, or current `$` if bare.
|
|
278
|
-
|
|
279
|
-
### Syntax
|
|
280
|
-
|
|
281
|
-
```text
|
|
282
|
-
return # exit with current $
|
|
283
|
-
$value -> return # exit with value
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
### In Blocks
|
|
287
|
-
|
|
288
|
-
```rill
|
|
289
|
-
{
|
|
290
|
-
5 :> $x
|
|
291
|
-
($x > 3) ? ("big" -> return)
|
|
292
|
-
"small"
|
|
293
|
-
}
|
|
294
|
-
# Returns "big"
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### Multi-Phase Pipeline
|
|
298
|
-
|
|
299
|
-
```text
|
|
300
|
-
{
|
|
301
|
-
"content" :> $data
|
|
302
|
-
$data -> .contains("ERROR") ? ("Read failed" -> return)
|
|
303
|
-
"processed: {$data}"
|
|
304
|
-
}
|
|
305
|
-
# Returns "processed: content" or "Read failed"
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
---
|
|
309
|
-
|
|
310
|
-
## Assert
|
|
311
|
-
|
|
312
|
-
Validate conditions during execution. Halts the script with a clear error if the assertion fails.
|
|
313
|
-
|
|
314
|
-
### Syntax
|
|
315
|
-
|
|
316
|
-
```text
|
|
317
|
-
assert condition
|
|
318
|
-
assert condition "error message"
|
|
319
|
-
$value -> assert condition
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### Basic Usage
|
|
323
|
-
|
|
324
|
-
Assert halts execution when the condition evaluates to `false`. If the condition is `true`, the piped value passes through unchanged.
|
|
325
|
-
|
|
326
|
-
```rill
|
|
327
|
-
5 -> assert ($ > 0) # Returns 5 (condition true)
|
|
328
|
-
-1 -> assert ($ > 0) # Error: Assertion failed
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
### Custom Error Messages
|
|
332
|
-
|
|
333
|
-
Provide a descriptive message as the second argument:
|
|
334
|
-
|
|
335
|
-
```rill
|
|
336
|
-
"" -> assert !.empty "Empty input not allowed"
|
|
337
|
-
# Error: Empty input not allowed
|
|
338
|
-
|
|
339
|
-
[1, 2, 3] -> assert (.len > 0) "List cannot be empty"
|
|
340
|
-
# Returns [1, 2, 3] (assertion passes)
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
### Type Assertions
|
|
344
|
-
|
|
345
|
-
Combine with type checks to validate input:
|
|
346
|
-
|
|
347
|
-
```rill
|
|
348
|
-
"hello" -> assert $:?string # Returns "hello" (type check passes)
|
|
349
|
-
42 -> assert $:?string # Error: Assertion failed
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
### In Loops
|
|
353
|
-
|
|
354
|
-
Assert validates each iteration. The loop halts on the first failing assertion:
|
|
355
|
-
|
|
356
|
-
```rill
|
|
357
|
-
[1, 2, 3] -> each {
|
|
358
|
-
assert ($ > 0) "Must be positive"
|
|
359
|
-
}
|
|
360
|
-
# Returns [1, 2, 3] (all elements valid)
|
|
361
|
-
|
|
362
|
-
[1, 0, 3] -> each {
|
|
363
|
-
assert ($ > 0) "Must be positive"
|
|
364
|
-
}
|
|
365
|
-
# Error: Must be positive
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
### Pipe Passthrough
|
|
369
|
-
|
|
370
|
-
When the assertion passes, the piped value flows through unchanged:
|
|
371
|
-
|
|
372
|
-
```rill
|
|
373
|
-
"data" :> $input
|
|
374
|
-
$input
|
|
375
|
-
-> assert !.empty "Input required"
|
|
376
|
-
-> .upper
|
|
377
|
-
-> assert (.len > 0) "Processed value required"
|
|
378
|
-
# Returns "DATA"
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
### Error Behavior
|
|
382
|
-
|
|
383
|
-
Assert throws `RuntimeError` when:
|
|
384
|
-
|
|
385
|
-
| Condition | Error Code | Message |
|
|
386
|
-
|-----------|-----------|---------|
|
|
387
|
-
| Condition is `false` | `RUNTIME_ASSERTION_FAILED` | Custom message or "Assertion failed" |
|
|
388
|
-
| Condition is not boolean | `RUNTIME_TYPE_ERROR` | "assert requires boolean condition, got {type}" |
|
|
389
|
-
|
|
390
|
-
```rill
|
|
391
|
-
# Non-boolean condition
|
|
392
|
-
"test" -> assert $ # Error: assert requires boolean condition, got string
|
|
393
|
-
|
|
394
|
-
# Failed assertion with location
|
|
395
|
-
-1 -> assert ($ > 0) # Error: Assertion failed
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
### Validation Patterns
|
|
399
|
-
|
|
400
|
-
Guard clauses at function start:
|
|
401
|
-
|
|
402
|
-
```text
|
|
403
|
-
|data| {
|
|
404
|
-
assert $data:?list "Expected list"
|
|
405
|
-
assert !$data.empty "List cannot be empty"
|
|
406
|
-
$data -> each { $ * 2 }
|
|
407
|
-
} :> $process
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
Multi-step validation:
|
|
411
|
-
|
|
412
|
-
```text
|
|
413
|
-
$input
|
|
414
|
-
-> assert $:?string "Input must be string"
|
|
415
|
-
-> .trim
|
|
416
|
-
-> assert !.empty "Trimmed input cannot be empty"
|
|
417
|
-
-> assert (.len >= 5) "Input too short (min 5 chars)"
|
|
418
|
-
-> app::process()
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
---
|
|
422
|
-
|
|
423
|
-
## Error
|
|
424
|
-
|
|
425
|
-
Halt execution immediately with a custom error message. Unlike `assert`, which validates a condition, `error` always halts.
|
|
426
|
-
|
|
427
|
-
### Syntax
|
|
428
|
-
|
|
429
|
-
```text
|
|
430
|
-
error "message" # Direct form
|
|
431
|
-
$value -> error # Piped form
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
### Basic Usage
|
|
435
|
-
|
|
436
|
-
Use `error` with a string literal to halt with a message:
|
|
437
|
-
|
|
438
|
-
```text
|
|
439
|
-
error "Something went wrong"
|
|
440
|
-
# Halts execution with: Something went wrong
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
The message argument accepts string literals or piped string values (see Piped Form below).
|
|
444
|
-
|
|
445
|
-
### Piped Form
|
|
446
|
-
|
|
447
|
-
Pipe a string value to `error` to use dynamic error messages:
|
|
448
|
-
|
|
449
|
-
```text
|
|
450
|
-
"Operation failed" -> error
|
|
451
|
-
# Halts with: Operation failed
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
The piped value must be a string:
|
|
455
|
-
|
|
456
|
-
```text
|
|
457
|
-
"Error occurred" :> $msg
|
|
458
|
-
$msg -> error
|
|
459
|
-
# Halts with: Error occurred
|
|
460
|
-
|
|
461
|
-
"Status: " :> $prefix
|
|
462
|
-
404 :> $code
|
|
463
|
-
"{$prefix}{$code}" -> error
|
|
464
|
-
# Halts with: Status: 404
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
Piping non-string values throws a type error:
|
|
468
|
-
|
|
469
|
-
```text
|
|
470
|
-
42 -> error # Error: error requires string, got number
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
### String Interpolation
|
|
474
|
-
|
|
475
|
-
Use interpolation for dynamic error messages:
|
|
476
|
-
|
|
477
|
-
```text
|
|
478
|
-
404 :> $code
|
|
479
|
-
error "Unexpected status: {$code}"
|
|
480
|
-
# Halts with: Unexpected status: 404
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
```text
|
|
484
|
-
3 :> $step
|
|
485
|
-
"timeout" :> $reason
|
|
486
|
-
error "Failed at step {$step}: {$reason}"
|
|
487
|
-
# Halts with: Failed at step 3: timeout
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
### Conditional Usage
|
|
491
|
-
|
|
492
|
-
Combine `error` with conditionals for guard clauses:
|
|
493
|
-
|
|
494
|
-
```rill
|
|
495
|
-
5 :> $x
|
|
496
|
-
($x < 0) ? { error "Number must be non-negative" } ! $x
|
|
497
|
-
# Returns 5 (condition false, proceeds with else branch)
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
```text
|
|
501
|
-
$data -> .empty ? { error "Data cannot be empty" } ! $data
|
|
502
|
-
# Proceeds with $data if not empty
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
### In Blocks
|
|
506
|
-
|
|
507
|
-
Use `error` in blocks for multi-step validation:
|
|
508
|
-
|
|
509
|
-
```text
|
|
510
|
-
|age| {
|
|
511
|
-
($age < 0) ? { error "Age cannot be negative: {$age}" }
|
|
512
|
-
($age > 150) ? { error "Age out of range: {$age}" }
|
|
513
|
-
"Valid age: {$age}"
|
|
514
|
-
} :> $validate_age
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
### Error Behavior
|
|
518
|
-
|
|
519
|
-
Error throws `RuntimeError` with code `RUNTIME_ERROR_RAISED`:
|
|
520
|
-
|
|
521
|
-
| Pattern | Halts With | Message Source |
|
|
522
|
-
|---------|-----------|----------------|
|
|
523
|
-
| `error "msg"` | RUNTIME_ERROR_RAISED | String literal |
|
|
524
|
-
| `$val -> error` | RUNTIME_ERROR_RAISED | Piped value (must be string) |
|
|
525
|
-
| `error ""` | RUNTIME_ERROR_RAISED | Empty message |
|
|
526
|
-
| `error 123` | Parse error | PARSE_INVALID_SYNTAX |
|
|
527
|
-
|
|
528
|
-
All error responses include the source location from the error statement.
|
|
529
|
-
|
|
530
|
-
### Multiline Messages
|
|
531
|
-
|
|
532
|
-
Use triple-quoted strings for formatted error messages:
|
|
533
|
-
|
|
534
|
-
```text
|
|
535
|
-
error """
|
|
536
|
-
Error occurred:
|
|
537
|
-
- Line 1
|
|
538
|
-
- Line 2
|
|
539
|
-
"""
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
### Comparison with Assert
|
|
543
|
-
|
|
544
|
-
| Statement | Condition | Behavior |
|
|
545
|
-
|-----------|-----------|----------|
|
|
546
|
-
| `assert cond "msg"` | Validates condition | Halts if condition is false, passes through if true |
|
|
547
|
-
| `error "msg"` | None | Always halts with message |
|
|
548
|
-
|
|
549
|
-
Use `assert` when you need to validate a condition. Use `error` when you've already determined that execution cannot continue.
|
|
550
|
-
|
|
551
|
-
### In Loops
|
|
552
|
-
|
|
553
|
-
Error halts the loop immediately:
|
|
554
|
-
|
|
555
|
-
```text
|
|
556
|
-
[1, 2, 3] -> each {
|
|
557
|
-
($ == 2) ? { error "Halted at 2" }
|
|
558
|
-
$ * 2
|
|
559
|
-
}
|
|
560
|
-
# Halts on second iteration with: Halted at 2
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
---
|
|
564
|
-
|
|
565
|
-
## Pass
|
|
566
|
-
|
|
567
|
-
The `pass` keyword returns the current pipe value (`$`) unchanged. Use it for explicit identity pass-through in conditional branches and dict values.
|
|
568
|
-
|
|
569
|
-
### In Conditionals
|
|
570
|
-
|
|
571
|
-
Use `pass` when one branch should preserve the piped value:
|
|
572
|
-
|
|
573
|
-
```rill
|
|
574
|
-
"input" -> .contains("in") ? pass ! "fallback"
|
|
575
|
-
# Returns "input" (condition true, pass preserves $)
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
```rill
|
|
579
|
-
"data" -> .empty ? { error "Empty input" } ! pass
|
|
580
|
-
# Returns "data" (condition false, pass preserves $)
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
### In Dict Values
|
|
584
|
-
|
|
585
|
-
Use `pass` to include the piped value in dict construction:
|
|
586
|
-
|
|
587
|
-
```rill
|
|
588
|
-
"success" -> { [status: pass, code: 0] }
|
|
589
|
-
# Returns [status: "success", code: 0]
|
|
590
|
-
```
|
|
591
|
-
|
|
592
|
-
### In Collection Operators
|
|
593
|
-
|
|
594
|
-
Preserve elements conditionally:
|
|
595
|
-
|
|
596
|
-
```rill
|
|
597
|
-
[1, -2, 3, -4] -> map { ($ > 0) ? pass ! 0 }
|
|
598
|
-
# Returns [1, 0, 3, 0]
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
### Why Use Pass?
|
|
602
|
-
|
|
603
|
-
The `pass` keyword provides clearer intent than bare `$`:
|
|
604
|
-
|
|
605
|
-
```text
|
|
606
|
-
# Less clear - what does $ mean here?
|
|
607
|
-
$cond ? do_something() ! $
|
|
608
|
-
|
|
609
|
-
# More explicit - reader knows this is intentional no-op
|
|
610
|
-
$cond ? do_something() ! pass
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
### Pass Behavior
|
|
614
|
-
|
|
615
|
-
| Pattern | Returns | Context |
|
|
616
|
-
|---------|---------|---------|
|
|
617
|
-
| `cond ? pass ! alt` | `$` if true, `alt` if false | Conditional branch |
|
|
618
|
-
| `cond ? alt ! pass` | `alt` if true, `$` if false | Conditional branch |
|
|
619
|
-
| `[key: pass]` | Dict with `$` as value | Dict construction |
|
|
620
|
-
| `-> { pass }` | `$` | Block body |
|
|
621
|
-
|
|
622
|
-
**Note:** `pass` requires pipe context. Using `pass` without `$` bound throws an error.
|
|
623
|
-
|
|
624
|
-
---
|
|
625
|
-
|
|
626
|
-
## Control Flow Summary
|
|
627
|
-
|
|
628
|
-
| Statement | Scope | Effect |
|
|
629
|
-
|-----------|-------|--------|
|
|
630
|
-
| `break` | Loop | Exit loop with current `$` |
|
|
631
|
-
| `$val -> break` | Loop | Exit loop with value |
|
|
632
|
-
| `return` | Block/Script | Exit block or script with current `$` |
|
|
633
|
-
| `$val -> return` | Block/Script | Exit block or script with value |
|
|
634
|
-
| `pass` | Any | Returns current `$` unchanged |
|
|
635
|
-
| `assert cond` | Any | Halt if condition false, pass through on success |
|
|
636
|
-
| `assert cond "msg"` | Any | Halt with custom message if condition false |
|
|
637
|
-
| `error "msg"` | Any | Always halt with error message |
|
|
638
|
-
| `$val -> error` | Any | Always halt with piped error message (must be string) |
|
|
639
|
-
|
|
640
|
-
---
|
|
641
|
-
|
|
642
|
-
## Patterns
|
|
643
|
-
|
|
644
|
-
### Guard Clauses
|
|
645
|
-
|
|
646
|
-
Exit early on invalid conditions (assumes host provides `error()`):
|
|
647
|
-
|
|
648
|
-
```text
|
|
649
|
-
|data| {
|
|
650
|
-
$data -> .empty ? app::error("Empty input")
|
|
651
|
-
$data -> :?list ? $ ! app::error("Expected list")
|
|
652
|
-
$data -> each { $ * 2 }
|
|
653
|
-
} :> $process
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
### Retry with Limit
|
|
657
|
-
|
|
658
|
-
```text
|
|
659
|
-
^(limit: 3) @ {
|
|
660
|
-
app::prompt("Try operation")
|
|
661
|
-
} ? (.contains("RETRY"))
|
|
662
|
-
|
|
663
|
-
.contains("SUCCESS") ? [0, "Done"] ! [1, "Failed"]
|
|
664
|
-
```
|
|
665
|
-
|
|
666
|
-
### State Machine
|
|
667
|
-
|
|
668
|
-
```rill
|
|
669
|
-
"start" -> ($ != "done") @ {
|
|
670
|
-
($ == "start") ? "processing" ! ($ == "processing") ? "validating" ! ($ == "validating") ? "done" ! $
|
|
671
|
-
}
|
|
672
|
-
# Walks through states: start -> processing -> validating -> done
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
### Find First Match
|
|
676
|
-
|
|
677
|
-
```rill
|
|
678
|
-
[1, 2, 3, 4, 5] -> each {
|
|
679
|
-
($ > 3) ? ($ -> break)
|
|
680
|
-
$
|
|
681
|
-
}
|
|
682
|
-
# Returns 4 (first element > 3)
|
|
683
|
-
```
|
|
684
|
-
|
|
685
|
-
---
|
|
686
|
-
|
|
687
|
-
## See Also
|
|
688
|
-
|
|
689
|
-
- [Variables](03_variables.md) — Scope rules and `$` binding
|
|
690
|
-
- [Collections](07_collections.md) — `each`, `map`, `filter`, `fold` iteration
|
|
691
|
-
- [Operators](04_operators.md) — Comparison and logical operators
|
|
692
|
-
- [Reference](11_reference.md) — Quick reference tables
|