@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,696 @@
|
|
|
1
|
+
# rill Conventions and Idioms
|
|
2
|
+
|
|
3
|
+
*Idiomatic patterns for readable, maintainable rill code*
|
|
4
|
+
|
|
5
|
+
This document collects conventions and best practices. It is a living document that will grow as the language matures.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Naming
|
|
10
|
+
|
|
11
|
+
### Case Style: snake_case
|
|
12
|
+
|
|
13
|
+
Use **snake_case** for all identifiers in rill:
|
|
14
|
+
|
|
15
|
+
```rill
|
|
16
|
+
# variables
|
|
17
|
+
"hello" :> $user_name
|
|
18
|
+
[1, 2, 3] :> $item_list
|
|
19
|
+
true :> $is_valid
|
|
20
|
+
|
|
21
|
+
# closures
|
|
22
|
+
|x|($x * 2) :> $double_value
|
|
23
|
+
|s|($s -> .trim) :> $cleanup_text
|
|
24
|
+
|
|
25
|
+
# dict keys
|
|
26
|
+
[first_name: "Alice", last_name: "Smith", is_active: true] :> $user
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Variables
|
|
30
|
+
|
|
31
|
+
Use descriptive snake_case names with `$` prefix:
|
|
32
|
+
|
|
33
|
+
```rill
|
|
34
|
+
"hello" :> $greeting # good: descriptive
|
|
35
|
+
"hello" :> $g # avoid: too terse
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For loop variables, short names are acceptable when scope is small:
|
|
39
|
+
|
|
40
|
+
```rill
|
|
41
|
+
[1, 2, 3] -> each |x| ($x * 2) # fine: small scope
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Closures
|
|
45
|
+
|
|
46
|
+
Name closures for their action:
|
|
47
|
+
|
|
48
|
+
```rill
|
|
49
|
+
|x|($x * 2) :> $double # verb describing transformation
|
|
50
|
+
|s|($s -> .trim) :> $cleanup # verb describing action
|
|
51
|
+
||{ $.count * $.price } :> $total # noun for computed value
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Capture and Flow
|
|
57
|
+
|
|
58
|
+
### Prefer inline capture when continuing the chain
|
|
59
|
+
|
|
60
|
+
Capture mid-chain with `:>` to store and continue:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
# good: capture and continue
|
|
64
|
+
prompt("Read file") :> $raw -> log -> .contains("ERROR") ? {
|
|
65
|
+
error("Failed: {$raw}")
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# less clear: separate statements
|
|
69
|
+
prompt("Read file") :> $raw
|
|
70
|
+
$raw -> log
|
|
71
|
+
$raw -> .contains("ERROR") ? { error("Failed: {$raw}") }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Use explicit capture before branching
|
|
75
|
+
|
|
76
|
+
Capture values before conditionals when you need them in multiple branches:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
# good: $result available in both branches
|
|
80
|
+
checkStatus() :> $result
|
|
81
|
+
$result -> .contains("OK") ? {
|
|
82
|
+
"Success: {$result}"
|
|
83
|
+
} ! {
|
|
84
|
+
"Failed: {$result}"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Collection Operators
|
|
91
|
+
|
|
92
|
+
### Choose the right operator
|
|
93
|
+
|
|
94
|
+
| Use case | Operator | Why |
|
|
95
|
+
|----------|----------|-----|
|
|
96
|
+
| Transform each element | `map` | Parallel, all results |
|
|
97
|
+
| Transform with side effects | `each` | Sequential order |
|
|
98
|
+
| Keep matching elements | `filter` | Parallel filter |
|
|
99
|
+
| Reduce to single value | `fold` | Final result only |
|
|
100
|
+
| Running totals | `each(init)` | All intermediate results |
|
|
101
|
+
| Find first match | `each` + `break` | Early termination |
|
|
102
|
+
|
|
103
|
+
### Prefer method shorthand in collection operators
|
|
104
|
+
|
|
105
|
+
```rill
|
|
106
|
+
# good: concise
|
|
107
|
+
["hello", "world"] -> map .upper
|
|
108
|
+
|
|
109
|
+
# equivalent but verbose
|
|
110
|
+
["hello", "world"] -> map { $.upper() }
|
|
111
|
+
["hello", "world"] -> map |x| $x.upper()
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Method chains work too:
|
|
115
|
+
|
|
116
|
+
```rill
|
|
117
|
+
[" HELLO ", " WORLD "] -> map .trim.lower
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Use grouped form for negation
|
|
121
|
+
|
|
122
|
+
```rill
|
|
123
|
+
# correct: grouped negation
|
|
124
|
+
["", "a", "b"] -> filter (!.empty)
|
|
125
|
+
|
|
126
|
+
# wrong: .empty returns truthy elements
|
|
127
|
+
["", "a", "b"] -> filter .empty # returns [""]
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Use fold for reduction, each(init) for running totals
|
|
131
|
+
|
|
132
|
+
```rill
|
|
133
|
+
# sum: use fold (returns final value)
|
|
134
|
+
[1, 2, 3] -> fold(0) { $@ + $ } # 6
|
|
135
|
+
|
|
136
|
+
# running sum: use each (returns all intermediates)
|
|
137
|
+
[1, 2, 3] -> each(0) { $@ + $ } # [1, 3, 6]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Break returns partial results in each
|
|
141
|
+
|
|
142
|
+
```rill
|
|
143
|
+
[1, 2, 3, 4, 5] -> each {
|
|
144
|
+
($ == 3) ? break
|
|
145
|
+
$ * 2
|
|
146
|
+
}
|
|
147
|
+
# Result: [2, 4] (elements processed BEFORE break)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Loops
|
|
153
|
+
|
|
154
|
+
### Use $ as accumulator in while/do-while
|
|
155
|
+
|
|
156
|
+
```rill
|
|
157
|
+
# good: $ accumulates naturally
|
|
158
|
+
0 -> ($ < 5) @ { $ + 1 }
|
|
159
|
+
|
|
160
|
+
# avoid: named variables don't persist across iterations
|
|
161
|
+
0 -> ($ < 5) @ {
|
|
162
|
+
$ :> $x # $x exists only in this iteration
|
|
163
|
+
$x + 1
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Prefer do-while for retry patterns
|
|
168
|
+
|
|
169
|
+
Do-while runs body at least once, eliminating duplicate first-attempt code:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
# good: body runs at least once
|
|
173
|
+
@ {
|
|
174
|
+
attemptOperation()
|
|
175
|
+
} ? (.contains("RETRY"))
|
|
176
|
+
|
|
177
|
+
# less clean: separate first attempt
|
|
178
|
+
attemptOperation() :> $result
|
|
179
|
+
$result -> .contains("RETRY") @ {
|
|
180
|
+
attemptOperation()
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Use each for collection iteration, not while
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
# good: each is designed for collections
|
|
188
|
+
$items -> each { process($) }
|
|
189
|
+
|
|
190
|
+
# avoid: manual iteration with while
|
|
191
|
+
$items -> .first() -> (!$.done) @ {
|
|
192
|
+
process($.value)
|
|
193
|
+
$.next()
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Conditionals
|
|
200
|
+
|
|
201
|
+
### Condition must be boolean
|
|
202
|
+
|
|
203
|
+
The condition in `cond ? then ! else` must evaluate to boolean:
|
|
204
|
+
|
|
205
|
+
```rill
|
|
206
|
+
# correct: .contains() returns boolean
|
|
207
|
+
"hello" -> .contains("ell") ? "found" ! "not found"
|
|
208
|
+
|
|
209
|
+
# correct: comparison returns boolean
|
|
210
|
+
5 -> ($ > 3) ? "big" ! "small"
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Use ?? for defaults, not conditionals
|
|
214
|
+
|
|
215
|
+
```text
|
|
216
|
+
# good: concise default
|
|
217
|
+
$dict.field ?? "default"
|
|
218
|
+
|
|
219
|
+
# avoid: verbose conditional
|
|
220
|
+
$dict.?field ? $dict.field ! "default"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Chain conditionals for multi-way branching
|
|
224
|
+
|
|
225
|
+
```text
|
|
226
|
+
($status == "ok") ? {
|
|
227
|
+
"Success"
|
|
228
|
+
} ! ($status == "pending") ? {
|
|
229
|
+
"Waiting"
|
|
230
|
+
} ! {
|
|
231
|
+
"Unknown: {$status}"
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Closures
|
|
238
|
+
|
|
239
|
+
### Use braces for complex bodies
|
|
240
|
+
|
|
241
|
+
```rill
|
|
242
|
+
# simple: parentheses ok
|
|
243
|
+
|x|($x * 2) :> $double
|
|
244
|
+
|
|
245
|
+
# complex: braces required
|
|
246
|
+
|n| {
|
|
247
|
+
($n < 1) ? 1 ! ($n * $factorial($n - 1))
|
|
248
|
+
} :> $factorial
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Capture loop variable explicitly for deferred closures
|
|
252
|
+
|
|
253
|
+
```rill
|
|
254
|
+
# good: explicit capture per iteration
|
|
255
|
+
[1, 2, 3] -> each {
|
|
256
|
+
$ :> $item
|
|
257
|
+
|| { $item }
|
|
258
|
+
} :> $closures
|
|
259
|
+
|
|
260
|
+
# result: closures return [1, 2, 3] when called
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Dict closures for computed properties
|
|
264
|
+
|
|
265
|
+
Zero-arg closures auto-invoke when accessed:
|
|
266
|
+
|
|
267
|
+
```rill
|
|
268
|
+
[
|
|
269
|
+
items: [1, 2, 3],
|
|
270
|
+
count: ||{ $.items -> .len }
|
|
271
|
+
] :> $data
|
|
272
|
+
|
|
273
|
+
$data.count # 3 (auto-invokes)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Parameterized closures work as methods:
|
|
277
|
+
|
|
278
|
+
```rill
|
|
279
|
+
[
|
|
280
|
+
name: "test",
|
|
281
|
+
greet: |x|{ "{$.name}: {$x}" }
|
|
282
|
+
] :> $obj
|
|
283
|
+
|
|
284
|
+
$obj.greet("hello") # "test: hello"
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Type Safety
|
|
290
|
+
|
|
291
|
+
### Annotate closure parameters for clarity
|
|
292
|
+
|
|
293
|
+
```rill
|
|
294
|
+
|name: string, count: number| {
|
|
295
|
+
"{$name}: {$count}"
|
|
296
|
+
} :> $format
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Capture with type annotation for documentation
|
|
300
|
+
|
|
301
|
+
```rill
|
|
302
|
+
"processing" :> $status:string
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Use type assertions sparingly
|
|
306
|
+
|
|
307
|
+
Type assertions (`:type`) are for validation, not conversion:
|
|
308
|
+
|
|
309
|
+
```text
|
|
310
|
+
# good: validate external input
|
|
311
|
+
parseJson($input):dict :> $data
|
|
312
|
+
|
|
313
|
+
# unnecessary: type is already known
|
|
314
|
+
5:number :> $n
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## String Handling
|
|
320
|
+
|
|
321
|
+
### Use heredocs for multiline content
|
|
322
|
+
|
|
323
|
+
```text
|
|
324
|
+
prompt(<<EOF
|
|
325
|
+
Analyze this content:
|
|
326
|
+
{$content}
|
|
327
|
+
|
|
328
|
+
Provide a summary.
|
|
329
|
+
EOF
|
|
330
|
+
)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Use .empty for emptiness checks
|
|
334
|
+
|
|
335
|
+
```rill
|
|
336
|
+
# good
|
|
337
|
+
"" -> .empty ? "empty" ! "not empty"
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Avoid direct string comparison (not allowed):
|
|
341
|
+
|
|
342
|
+
```text
|
|
343
|
+
# this pattern doesn't work in rill
|
|
344
|
+
$str == "" ? "empty"
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Chain string methods naturally
|
|
348
|
+
|
|
349
|
+
```rill
|
|
350
|
+
" HELLO world " -> .trim.lower.split(" ")
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Error Handling
|
|
356
|
+
|
|
357
|
+
### Validate early with conditionals
|
|
358
|
+
|
|
359
|
+
```text
|
|
360
|
+
$input -> .empty ? { error("Input required") }
|
|
361
|
+
|
|
362
|
+
# continue with validated input
|
|
363
|
+
process($input)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Use explicit signals for workflow control
|
|
367
|
+
|
|
368
|
+
```text
|
|
369
|
+
prompt("...") :> $result
|
|
370
|
+
|
|
371
|
+
$result -> .contains(":::ERROR:::") ? {
|
|
372
|
+
error("Operation failed: {$result}")
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
$result -> .contains(":::DONE:::") ? {
|
|
376
|
+
"Complete" -> return
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Parsing LLM Output
|
|
383
|
+
|
|
384
|
+
### Chain parsers for structured extraction
|
|
385
|
+
|
|
386
|
+
```text
|
|
387
|
+
# extract JSON from code fence
|
|
388
|
+
$response -> parseFence("json") -> parseJson :> $data
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Use parseAuto for unknown formats
|
|
392
|
+
|
|
393
|
+
```text
|
|
394
|
+
$response -> parseAuto :> $parsed
|
|
395
|
+
($parsed.type == "json") ? {
|
|
396
|
+
$parsed.data
|
|
397
|
+
} ! {
|
|
398
|
+
error("Expected JSON, got {$parsed.type}")
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Extract XML tags for Claude-style responses
|
|
403
|
+
|
|
404
|
+
```text
|
|
405
|
+
$response -> parseXml("thinking") -> log
|
|
406
|
+
$response -> parseXml("answer") :> $answer
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Anti-Patterns
|
|
412
|
+
|
|
413
|
+
### Avoid reassigning variables
|
|
414
|
+
|
|
415
|
+
Variables lock to their first type. Reassigning suggests misuse:
|
|
416
|
+
|
|
417
|
+
```text
|
|
418
|
+
# avoid: confusing reassignment
|
|
419
|
+
"initial" :> $x
|
|
420
|
+
"updated" :> $x # works but unclear
|
|
421
|
+
|
|
422
|
+
# prefer: new variable or functional style
|
|
423
|
+
"initial" -> transform() :> $result
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Avoid bare $ in stored closures
|
|
427
|
+
|
|
428
|
+
```rill
|
|
429
|
+
# confusing: what is $?
|
|
430
|
+
|| { $ + 1 } :> $fn # $ is undefined when called
|
|
431
|
+
|
|
432
|
+
# clear: explicit parameter
|
|
433
|
+
|x| { $x + 1 } :> $fn
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Avoid break in parallel operators
|
|
437
|
+
|
|
438
|
+
Break is not supported in `map` or `filter` (they run in parallel):
|
|
439
|
+
|
|
440
|
+
```text
|
|
441
|
+
# wrong: break in map
|
|
442
|
+
[1, 2, 3] -> map { ($ > 2) ? break }
|
|
443
|
+
|
|
444
|
+
# correct: use each if you need break
|
|
445
|
+
[1, 2, 3] -> each { ($ > 2) ? break }
|
|
446
|
+
|
|
447
|
+
# or filter first
|
|
448
|
+
[1, 2, 3] -> filter { $ <= 2 } -> map { $ }
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### Avoid complex logic in conditions
|
|
452
|
+
|
|
453
|
+
```text
|
|
454
|
+
# hard to read
|
|
455
|
+
(($x > 5) && (($y < 10) || ($z == 0))) ? { ... }
|
|
456
|
+
|
|
457
|
+
# clearer: extract to named check
|
|
458
|
+
($x > 5) :> $big_enough
|
|
459
|
+
(($y < 10) || ($z == 0)) :> $valid_range
|
|
460
|
+
($big_enough && $valid_range) ? { ... }
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Formatting
|
|
466
|
+
|
|
467
|
+
### Spacing Rules
|
|
468
|
+
|
|
469
|
+
**Operators**: space on both sides
|
|
470
|
+
|
|
471
|
+
```text
|
|
472
|
+
# good
|
|
473
|
+
5 + 3
|
|
474
|
+
$x -> .upper
|
|
475
|
+
"hello" :> $greeting
|
|
476
|
+
($a == $b) ? "yes" ! "no"
|
|
477
|
+
|
|
478
|
+
# avoid
|
|
479
|
+
5+3
|
|
480
|
+
$x->.upper
|
|
481
|
+
"hello":>$greeting
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**Parentheses**: no inner spaces
|
|
485
|
+
|
|
486
|
+
```text
|
|
487
|
+
# good
|
|
488
|
+
($x + 1)
|
|
489
|
+
($ > 3) ? "big"
|
|
490
|
+
[1, 2, 3] -> each |x| ($x * 2)
|
|
491
|
+
|
|
492
|
+
# avoid
|
|
493
|
+
( $x + 1 )
|
|
494
|
+
( $ > 3 ) ? "big"
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
**Braces**: space after `{` and before `}`
|
|
498
|
+
|
|
499
|
+
```text
|
|
500
|
+
# good
|
|
501
|
+
{ $x + 1 }
|
|
502
|
+
[1, 2, 3] -> each { $ * 2 }
|
|
503
|
+
|x| { $x -> .trim }
|
|
504
|
+
|
|
505
|
+
# avoid
|
|
506
|
+
{$x + 1}
|
|
507
|
+
[1, 2, 3] -> each {$ * 2}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**Multiline braces**: opening brace on same line, closing on own line
|
|
511
|
+
|
|
512
|
+
```text
|
|
513
|
+
# good
|
|
514
|
+
[1, 2, 3] -> each {
|
|
515
|
+
$ :> $item
|
|
516
|
+
$item * 2
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
# avoid
|
|
520
|
+
[1, 2, 3] -> each
|
|
521
|
+
{
|
|
522
|
+
$ * 2
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
**Brackets**: no inner spaces for indexing
|
|
527
|
+
|
|
528
|
+
```text
|
|
529
|
+
# good
|
|
530
|
+
$list[0]
|
|
531
|
+
$dict.items[1]
|
|
532
|
+
|
|
533
|
+
# avoid
|
|
534
|
+
$list[ 0 ]
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**List/dict literals**: space after colons and commas
|
|
538
|
+
|
|
539
|
+
```text
|
|
540
|
+
# good
|
|
541
|
+
[1, 2, 3]
|
|
542
|
+
[name: "alice", age: 30]
|
|
543
|
+
|
|
544
|
+
# avoid
|
|
545
|
+
[1,2,3]
|
|
546
|
+
[name:"alice",age:30]
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**Closure parameters**: no space before pipe, space after
|
|
550
|
+
|
|
551
|
+
```text
|
|
552
|
+
# good
|
|
553
|
+
|x| ($x * 2)
|
|
554
|
+
|a, b| { $a + $b }
|
|
555
|
+
|| { $.count }
|
|
556
|
+
|
|
557
|
+
# avoid
|
|
558
|
+
| x | ($x * 2)
|
|
559
|
+
|a,b|{ $a + $b }
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
**Method calls**: no space before dot or parentheses
|
|
563
|
+
|
|
564
|
+
```text
|
|
565
|
+
# good
|
|
566
|
+
$str.upper()
|
|
567
|
+
$list.join(", ")
|
|
568
|
+
"hello" -> .trim.lower
|
|
569
|
+
|
|
570
|
+
# avoid
|
|
571
|
+
$str .upper()
|
|
572
|
+
$list.join (", ")
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
**Pipes**: space on both sides of `->` and `:>`
|
|
576
|
+
|
|
577
|
+
```text
|
|
578
|
+
# good
|
|
579
|
+
"hello" -> .upper -> .len
|
|
580
|
+
"value" :> $x -> log
|
|
581
|
+
|
|
582
|
+
# avoid
|
|
583
|
+
"hello"->.upper->.len
|
|
584
|
+
"value":>$x->log
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
**Implicit `$` shorthand**: prefer sugared forms
|
|
588
|
+
|
|
589
|
+
```text
|
|
590
|
+
# methods: $.foo() -> .foo
|
|
591
|
+
# good
|
|
592
|
+
"hello" -> .upper -> .len
|
|
593
|
+
[1, 2, 3] -> map .str
|
|
594
|
+
|
|
595
|
+
# avoid
|
|
596
|
+
"hello" -> $.upper() -> $.len
|
|
597
|
+
[1, 2, 3] -> map $.str
|
|
598
|
+
|
|
599
|
+
# global functions: foo($) -> foo
|
|
600
|
+
# good
|
|
601
|
+
"hello" -> log -> .upper
|
|
602
|
+
42 -> type
|
|
603
|
+
|
|
604
|
+
# avoid
|
|
605
|
+
"hello" -> log($) -> .upper
|
|
606
|
+
42 -> type($)
|
|
607
|
+
|
|
608
|
+
# closures: $fn($) -> $fn
|
|
609
|
+
# good
|
|
610
|
+
|x| ($x * 2) :> $double
|
|
611
|
+
5 -> $double
|
|
612
|
+
|
|
613
|
+
# avoid
|
|
614
|
+
5 -> $double($)
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
**No throwaway captures**: don't capture just to continue
|
|
618
|
+
|
|
619
|
+
```text
|
|
620
|
+
# avoid: unnecessary intermediate variables
|
|
621
|
+
"hello" :> $x
|
|
622
|
+
$x -> .upper :> $y
|
|
623
|
+
$y -> .len
|
|
624
|
+
|
|
625
|
+
# good: use line continuation instead
|
|
626
|
+
"hello"
|
|
627
|
+
-> .upper
|
|
628
|
+
-> .len
|
|
629
|
+
|
|
630
|
+
# good: capture only when reused later
|
|
631
|
+
"hello" :> $input
|
|
632
|
+
$input -> .upper :> $upper
|
|
633
|
+
"{$input} became {$upper}" # both variables referenced
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
**Chain continuations**: indent continued lines by 2 spaces
|
|
637
|
+
|
|
638
|
+
```text
|
|
639
|
+
# good: align continuation with pipe
|
|
640
|
+
$data
|
|
641
|
+
-> .filter { $.active }
|
|
642
|
+
-> map { $.name }
|
|
643
|
+
-> .join(", ")
|
|
644
|
+
|
|
645
|
+
# good: long method chains
|
|
646
|
+
" hello world "
|
|
647
|
+
-> .trim
|
|
648
|
+
-> .upper
|
|
649
|
+
-> .split(" ")
|
|
650
|
+
-> .join("-")
|
|
651
|
+
|
|
652
|
+
# good: capture mid-chain
|
|
653
|
+
prompt("analyze {$file}")
|
|
654
|
+
:> $result
|
|
655
|
+
-> log
|
|
656
|
+
-> .contains("ERROR") ? { error($result) }
|
|
657
|
+
|
|
658
|
+
# avoid: no indent on continuation
|
|
659
|
+
$data
|
|
660
|
+
-> .filter { $.active }
|
|
661
|
+
-> map { $.name }
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### One statement per line for complex code
|
|
665
|
+
|
|
666
|
+
```text
|
|
667
|
+
# good: clear structure
|
|
668
|
+
$input -> validate() :> $valid
|
|
669
|
+
$valid -> process() :> $result
|
|
670
|
+
$result -> format()
|
|
671
|
+
|
|
672
|
+
# acceptable for simple chains
|
|
673
|
+
$input -> .trim -> .lower -> .split(" ")
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### Indent block contents
|
|
677
|
+
|
|
678
|
+
```rill
|
|
679
|
+
{
|
|
680
|
+
"first" :> $a
|
|
681
|
+
"second" :> $b
|
|
682
|
+
"{$a} {$b}"
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
### Align related captures
|
|
687
|
+
|
|
688
|
+
```text
|
|
689
|
+
prompt("Get name") :> $name
|
|
690
|
+
prompt("Get age") :> $age
|
|
691
|
+
prompt("Get role") :> $role
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
696
|
+
*This document will be extended as conventions emerge from real-world usage.*
|