@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,330 @@
|
|
|
1
|
+
# rill Iterators
|
|
2
|
+
|
|
3
|
+
*Lazy sequence generation with the iterator protocol*
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Iterators provide lazy sequence generation in rill. They produce values on demand rather than materializing entire collections upfront.
|
|
8
|
+
|
|
9
|
+
**Built-in iterators:**
|
|
10
|
+
|
|
11
|
+
| Function | Description |
|
|
12
|
+
|----------|-------------|
|
|
13
|
+
| `range(start, end, step?)` | Generate number sequence |
|
|
14
|
+
| `repeat(value, count)` | Repeat value n times |
|
|
15
|
+
| `.first()` | Get iterator for any collection |
|
|
16
|
+
|
|
17
|
+
**Key characteristics:**
|
|
18
|
+
|
|
19
|
+
- Value-based: `.next()` returns a new iterator, original unchanged
|
|
20
|
+
- Lazy: Elements generated on demand
|
|
21
|
+
- Composable: Work with all collection operators (`each`, `map`, `filter`, `fold`)
|
|
22
|
+
|
|
23
|
+
```rill
|
|
24
|
+
range(0, 5) -> each { $ * 2 } # [0, 2, 4, 6, 8]
|
|
25
|
+
repeat("x", 3) -> each { $ } # ["x", "x", "x"]
|
|
26
|
+
[1, 2, 3] -> .first() -> each { $ } # [1, 2, 3]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Iterator Protocol
|
|
32
|
+
|
|
33
|
+
Iterators are dicts with three fields:
|
|
34
|
+
|
|
35
|
+
| Field | Type | Description |
|
|
36
|
+
|-------|------|-------------|
|
|
37
|
+
| `value` | any | Current element (absent when done) |
|
|
38
|
+
| `done` | bool | True if exhausted |
|
|
39
|
+
| `next` | closure | Returns new iterator at next position |
|
|
40
|
+
|
|
41
|
+
```rill
|
|
42
|
+
# Iterator structure
|
|
43
|
+
[
|
|
44
|
+
value: 0,
|
|
45
|
+
done: false,
|
|
46
|
+
next: || { ... } # returns new iterator
|
|
47
|
+
]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Collection operators automatically recognize and expand iterators:
|
|
51
|
+
|
|
52
|
+
```rill
|
|
53
|
+
range(1, 4) -> map { $ * 10 } # [10, 20, 30]
|
|
54
|
+
range(0, 10) -> filter { $ > 5 } # [6, 7, 8, 9]
|
|
55
|
+
range(1, 6) -> fold(0) { $@ + $ } # 15
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Built-in Iterators
|
|
61
|
+
|
|
62
|
+
### `range(start, end, step?)`
|
|
63
|
+
|
|
64
|
+
Generate a sequence of numbers from `start` (inclusive) to `end` (exclusive).
|
|
65
|
+
|
|
66
|
+
| Parameter | Type | Default | Description |
|
|
67
|
+
|-----------|------|---------|-------------|
|
|
68
|
+
| `start` | number | required | First value |
|
|
69
|
+
| `end` | number | required | Stop value (exclusive) |
|
|
70
|
+
| `step` | number | 1 | Increment (can be negative) |
|
|
71
|
+
|
|
72
|
+
```rill
|
|
73
|
+
range(0, 5) # 0, 1, 2, 3, 4
|
|
74
|
+
range(1, 6) # 1, 2, 3, 4, 5
|
|
75
|
+
range(0, 10, 2) # 0, 2, 4, 6, 8
|
|
76
|
+
range(5, 0, -1) # 5, 4, 3, 2, 1
|
|
77
|
+
range(-3, 2) # -3, -2, -1, 0, 1
|
|
78
|
+
range(0, 1, 0.25) # 0, 0.25, 0.5, 0.75
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Edge cases:**
|
|
82
|
+
|
|
83
|
+
```rill
|
|
84
|
+
range(5, 5) # empty (start == end)
|
|
85
|
+
range(5, 3) # empty (start > end with positive step)
|
|
86
|
+
range(0, 5, -1) # empty (wrong direction)
|
|
87
|
+
range(0, 5, 0) # ERROR: step cannot be zero
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### `repeat(value, count)`
|
|
91
|
+
|
|
92
|
+
Generate a value repeated n times.
|
|
93
|
+
|
|
94
|
+
| Parameter | Type | Description |
|
|
95
|
+
|-----------|------|-------------|
|
|
96
|
+
| `value` | any | Value to repeat |
|
|
97
|
+
| `count` | number | Number of repetitions |
|
|
98
|
+
|
|
99
|
+
```rill
|
|
100
|
+
repeat("x", 3) # "x", "x", "x"
|
|
101
|
+
repeat(0, 5) # 0, 0, 0, 0, 0
|
|
102
|
+
repeat([a: 1], 2) # [a: 1], [a: 1]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Edge cases:**
|
|
106
|
+
|
|
107
|
+
```rill
|
|
108
|
+
repeat("x", 0) # empty
|
|
109
|
+
repeat("x", -1) # ERROR: count cannot be negative
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## The `.first()` Method
|
|
115
|
+
|
|
116
|
+
Returns an iterator for any collection. Provides a consistent interface for manual iteration.
|
|
117
|
+
|
|
118
|
+
| Input Type | `.first()` Returns |
|
|
119
|
+
|------------|-------------------|
|
|
120
|
+
| list | Iterator over elements |
|
|
121
|
+
| string | Iterator over characters |
|
|
122
|
+
| dict | Iterator over `[key: k, value: v]` entries |
|
|
123
|
+
| iterator | Returns itself (identity) |
|
|
124
|
+
|
|
125
|
+
```rill
|
|
126
|
+
[1, 2, 3] -> .first() # iterator at 1
|
|
127
|
+
"abc" -> .first() # iterator at "a"
|
|
128
|
+
[a: 1, b: 2] -> .first() # iterator at [key: "a", value: 1]
|
|
129
|
+
range(0, 5) -> .first() # iterator at 0 (identity)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Empty collections** return a done iterator:
|
|
133
|
+
|
|
134
|
+
```rill
|
|
135
|
+
[] -> .first() # [done: true, next: ...]
|
|
136
|
+
"" -> .first() # [done: true, next: ...]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Using `.first()` with collection operators:**
|
|
140
|
+
|
|
141
|
+
```rill
|
|
142
|
+
[1, 2, 3] -> .first() -> each { $ * 2 } # [2, 4, 6]
|
|
143
|
+
"hello" -> .first() -> each { $ } # ["h", "e", "l", "l", "o"]
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Manual Iteration
|
|
149
|
+
|
|
150
|
+
Traverse an iterator by accessing `.value`, `.done`, and calling `.next()`:
|
|
151
|
+
|
|
152
|
+
```rill
|
|
153
|
+
[1, 2, 3] -> .first() :> $it
|
|
154
|
+
|
|
155
|
+
# Check if done
|
|
156
|
+
$it.done # false
|
|
157
|
+
|
|
158
|
+
# Get current value
|
|
159
|
+
$it.value # 1
|
|
160
|
+
|
|
161
|
+
# Advance to next position
|
|
162
|
+
$it.next() :> $it
|
|
163
|
+
$it.value # 2
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Loop pattern (using $ as accumulator):**
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
"hello" -> .first() -> !$.done @ {
|
|
170
|
+
$.value -> log
|
|
171
|
+
$.next()
|
|
172
|
+
}
|
|
173
|
+
# logs: h, e, l, l, o
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Preferred: use `each` for iteration:**
|
|
177
|
+
|
|
178
|
+
```rill
|
|
179
|
+
"hello" -> each { log($) }
|
|
180
|
+
# logs: h, e, l, l, o
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Check before access:**
|
|
184
|
+
|
|
185
|
+
```rill
|
|
186
|
+
$list -> .first() :> $it
|
|
187
|
+
$it.done ? "empty" ! $it.value
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Custom Iterators
|
|
193
|
+
|
|
194
|
+
Create custom iterators by implementing the protocol:
|
|
195
|
+
|
|
196
|
+
```rill
|
|
197
|
+
# Counter from start to max
|
|
198
|
+
|start, max| [
|
|
199
|
+
value: $start,
|
|
200
|
+
done: ($start > $max),
|
|
201
|
+
next: || { $counter($.value + 1, $max) }
|
|
202
|
+
] :> $counter
|
|
203
|
+
|
|
204
|
+
$counter(1, 5) -> each { $ } # [1, 2, 3, 4, 5]
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Fibonacci sequence:**
|
|
208
|
+
|
|
209
|
+
```text
|
|
210
|
+
|a, b, max| [
|
|
211
|
+
value: $a,
|
|
212
|
+
done: ($a > $max),
|
|
213
|
+
next: || { $fib($.b, $.a + $.b, $max) }
|
|
214
|
+
] :> $fib
|
|
215
|
+
|
|
216
|
+
$fib(0, 1, 50) -> each { $ } # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Infinite iterator (use with limit):**
|
|
220
|
+
|
|
221
|
+
```text
|
|
222
|
+
|n| [
|
|
223
|
+
value: $n,
|
|
224
|
+
done: false,
|
|
225
|
+
next: || { $naturals($.value + 1) }
|
|
226
|
+
] :> $naturals
|
|
227
|
+
|
|
228
|
+
# Take first 5 using fold with compound accumulator
|
|
229
|
+
$naturals(1) -> .first() -> fold([list: [], it: $]) {
|
|
230
|
+
($@.list -> .len >= 5) ? $@ -> break ! [
|
|
231
|
+
list: [...$@.list, $@.it.value],
|
|
232
|
+
it: $@.it.next()
|
|
233
|
+
]
|
|
234
|
+
} -> $.list # [1, 2, 3, 4, 5]
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Element Access: `.head` and `.tail`
|
|
240
|
+
|
|
241
|
+
For direct element access (not iteration), use `.head` and `.tail`:
|
|
242
|
+
|
|
243
|
+
| Method | Description |
|
|
244
|
+
|--------|-------------|
|
|
245
|
+
| `.head` | First element (errors on empty) |
|
|
246
|
+
| `.tail` | Last element (errors on empty) |
|
|
247
|
+
|
|
248
|
+
```rill
|
|
249
|
+
[1, 2, 3] -> .head # 1
|
|
250
|
+
[1, 2, 3] -> .tail # 3
|
|
251
|
+
"hello" -> .head # "h"
|
|
252
|
+
"hello" -> .tail # "o"
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Empty collections error** (no null in rill):
|
|
256
|
+
|
|
257
|
+
```rill
|
|
258
|
+
[] -> .head # ERROR: Cannot get head of empty list
|
|
259
|
+
"" -> .tail # ERROR: Cannot get tail of empty string
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Comparison with `.first()`:**
|
|
263
|
+
|
|
264
|
+
| Method | Returns | On Empty |
|
|
265
|
+
|--------|---------|----------|
|
|
266
|
+
| `.head` | Element directly | Error |
|
|
267
|
+
| `.first()` | Iterator | Done iterator |
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Examples
|
|
272
|
+
|
|
273
|
+
### Sum of squares
|
|
274
|
+
|
|
275
|
+
```rill
|
|
276
|
+
range(1, 11) -> map { $ * $ } -> fold(0) { $@ + $ }
|
|
277
|
+
# 385 (1 + 4 + 9 + ... + 100)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Generate index markers
|
|
281
|
+
|
|
282
|
+
```rill
|
|
283
|
+
range(0, 5) -> each { "Item {$}" }
|
|
284
|
+
# ["Item 0", "Item 1", "Item 2", "Item 3", "Item 4"]
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Retry pattern
|
|
288
|
+
|
|
289
|
+
```text
|
|
290
|
+
repeat(1, 3) -> each {
|
|
291
|
+
attempt() :> $result
|
|
292
|
+
($result.success == true) ? ($result -> break)
|
|
293
|
+
pause("00:00:01")
|
|
294
|
+
$result
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Filter even numbers
|
|
299
|
+
|
|
300
|
+
```rill
|
|
301
|
+
range(0, 20) -> filter { ($ % 2) == 0 }
|
|
302
|
+
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Nested iteration
|
|
306
|
+
|
|
307
|
+
```rill
|
|
308
|
+
range(1, 4) -> each { $ :> $row -> range(1, 4) -> each { $row * $ } }
|
|
309
|
+
# [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Limits
|
|
315
|
+
|
|
316
|
+
Iterators are expanded eagerly when passed to collection operators. A default limit of 10000 elements prevents infinite loops:
|
|
317
|
+
|
|
318
|
+
```rill
|
|
319
|
+
# This would error after 10000 elements
|
|
320
|
+
|n| [value: $n, done: false, next: || { $inf($.value + 1) }] :> $inf
|
|
321
|
+
$inf(0) -> each { $ } # ERROR: Iterator exceeded 10000 elements
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## See Also
|
|
327
|
+
|
|
328
|
+
- [Collections](07_collections.md) — `each`, `map`, `filter`, `fold` operators
|
|
329
|
+
- [Closures](06_closures.md) — Closure semantics for custom iterators
|
|
330
|
+
- [Reference](11_reference.md) — Complete language specification
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# rill String Methods Reference
|
|
2
|
+
|
|
3
|
+
String methods for text manipulation, pattern matching, and formatting.
|
|
4
|
+
|
|
5
|
+
## Case Conversion
|
|
6
|
+
|
|
7
|
+
| Method | Signature | Description |
|
|
8
|
+
|----------|-------------|-----------------------|
|
|
9
|
+
| `.lower` | `() -> string` | Convert to lowercase |
|
|
10
|
+
| `.upper` | `() -> string` | Convert to uppercase |
|
|
11
|
+
|
|
12
|
+
```rill
|
|
13
|
+
"Hello World" -> .lower # "hello world"
|
|
14
|
+
"Hello World" -> .upper # "HELLO WORLD"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Prefix and Suffix
|
|
18
|
+
|
|
19
|
+
| Method | Signature | Description |
|
|
20
|
+
|----------------|------------------------|--------------------------------|
|
|
21
|
+
| `.starts_with` | `(prefix: string) -> bool` | True if string starts with prefix |
|
|
22
|
+
| `.ends_with` | `(suffix: string) -> bool` | True if string ends with suffix |
|
|
23
|
+
|
|
24
|
+
```rill
|
|
25
|
+
"hello" -> .starts_with("he") # true
|
|
26
|
+
"file.txt" -> .ends_with(".txt") # true
|
|
27
|
+
"Hello" -> .starts_with("hello") # false (case sensitive)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Search and Position
|
|
31
|
+
|
|
32
|
+
| Method | Signature | Description |
|
|
33
|
+
|-------------|------------------------|-------------------------------------|
|
|
34
|
+
| `.contains` | `(substr: string) -> bool` | True if string contains substring |
|
|
35
|
+
| `.index_of` | `(substr: string) -> number` | Position of first match (-1 if none) |
|
|
36
|
+
|
|
37
|
+
```rill
|
|
38
|
+
"hello world" -> .contains("world") # true
|
|
39
|
+
"hello world" -> .index_of("o") # 4
|
|
40
|
+
"hello" -> .index_of("x") # -1
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Pattern Matching
|
|
44
|
+
|
|
45
|
+
| Method | Signature | Description |
|
|
46
|
+
|-------------|------------------------|----------------------------------|
|
|
47
|
+
| `.match` | `(pattern: string) -> dict` | First regex match info, or `[:]` if none |
|
|
48
|
+
| `.is_match` | `(pattern: string) -> bool` | True if regex matches anywhere |
|
|
49
|
+
|
|
50
|
+
### `.match` Return Value
|
|
51
|
+
|
|
52
|
+
Returns a dict with three fields:
|
|
53
|
+
- `matched`: The matched text
|
|
54
|
+
- `index`: Position of match in string
|
|
55
|
+
- `groups`: Capture groups as list
|
|
56
|
+
|
|
57
|
+
```rill
|
|
58
|
+
"hello123" -> .match("[0-9]+")
|
|
59
|
+
# [matched: "123", index: 5, groups: []]
|
|
60
|
+
|
|
61
|
+
"v1.2.3" -> .match("v(\\d+)\\.(\\d+)\\.(\\d+)")
|
|
62
|
+
# [matched: "v1.2.3", index: 0, groups: ["1", "2", "3"]]
|
|
63
|
+
|
|
64
|
+
"hello" -> .match("[0-9]+")
|
|
65
|
+
# [:] (empty dict = no match)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `.is_match` for Boolean Checks
|
|
69
|
+
|
|
70
|
+
```rill
|
|
71
|
+
"hello123" -> .is_match("[0-9]+") # true
|
|
72
|
+
"hello" -> .is_match("[0-9]+") # false
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Pattern Matching in Conditionals
|
|
76
|
+
|
|
77
|
+
```rill
|
|
78
|
+
$response -> .is_match("ERROR") ? handle_error()
|
|
79
|
+
|
|
80
|
+
$response -> .match("code: (\\d+)") :> $m
|
|
81
|
+
$m -> !.empty ? process($m.groups[0])
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Replacement
|
|
85
|
+
|
|
86
|
+
| Method | Signature | Description |
|
|
87
|
+
|----------------|-----------------------------------------|--------------------------|
|
|
88
|
+
| `.replace` | `(pattern: string, replacement: string) -> string` | Replace first regex match |
|
|
89
|
+
| `.replace_all` | `(pattern: string, replacement: string) -> string` | Replace all regex matches |
|
|
90
|
+
|
|
91
|
+
```rill
|
|
92
|
+
"a-b-c" -> .replace("-", "_") # "a_b-c"
|
|
93
|
+
"a-b-c" -> .replace_all("-", "_") # "a_b_c"
|
|
94
|
+
|
|
95
|
+
"a1b2c3" -> .replace("[0-9]", "X") # "aXb2c3"
|
|
96
|
+
"a1b2c3" -> .replace_all("[0-9]", "X") # "aXbXcX"
|
|
97
|
+
|
|
98
|
+
"hello" -> .replace_all("l", "") # "heo"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Formatting
|
|
102
|
+
|
|
103
|
+
| Method | Signature | Description |
|
|
104
|
+
|--------------|----------------------------------------|--------------------------------|
|
|
105
|
+
| `.trim` | `() -> string` | Remove leading/trailing whitespace |
|
|
106
|
+
| `.repeat` | `(n: number) -> string` | Repeat string n times |
|
|
107
|
+
| `.pad_start` | `(length: number, fill: string = " ") -> string` | Pad start to length |
|
|
108
|
+
| `.pad_end` | `(length: number, fill: string = " ") -> string` | Pad end to length |
|
|
109
|
+
|
|
110
|
+
```rill
|
|
111
|
+
" hello " -> .trim # "hello"
|
|
112
|
+
|
|
113
|
+
"ab" -> .repeat(3) # "ababab"
|
|
114
|
+
"ab" -> .repeat(0) # ""
|
|
115
|
+
|
|
116
|
+
"42" -> .pad_start(5) # " 42"
|
|
117
|
+
"42" -> .pad_start(5, "0") # "00042"
|
|
118
|
+
|
|
119
|
+
"42" -> .pad_end(5) # "42 "
|
|
120
|
+
"42" -> .pad_end(5, "0") # "42000"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Splitting and Joining
|
|
124
|
+
|
|
125
|
+
| Method | Signature | Description |
|
|
126
|
+
|----------|------------------------------|------------------------------------|
|
|
127
|
+
| `.split` | `(sep: string = "\n") -> list` | Split by separator |
|
|
128
|
+
| `.join` | `(sep: string = ",") -> string` | Join list with separator |
|
|
129
|
+
| `.lines` | `() -> list` | Split on newlines (same as .split) |
|
|
130
|
+
|
|
131
|
+
```rill
|
|
132
|
+
"a,b,c" -> .split(",") # ["a", "b", "c"]
|
|
133
|
+
"a\nb\nc" -> .lines # ["a", "b", "c"]
|
|
134
|
+
|
|
135
|
+
["a", "b", "c"] -> .join("-") # "a-b-c"
|
|
136
|
+
["a", "b", "c"] -> .join("\n") # "a\nb\nc"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Conversion and Length
|
|
140
|
+
|
|
141
|
+
| Method | Signature | Description |
|
|
142
|
+
|--------|----------------|-----------------------------|
|
|
143
|
+
| `.str` | `() -> string` | Convert any value to string |
|
|
144
|
+
| `.num` | `() -> number` | Parse string to number |
|
|
145
|
+
| `.len` | `() -> number` | String length |
|
|
146
|
+
|
|
147
|
+
```rill
|
|
148
|
+
42 -> .str # "42"
|
|
149
|
+
"42" -> .num # 42
|
|
150
|
+
"hello" -> .len # 5
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Element Access
|
|
154
|
+
|
|
155
|
+
| Method | Signature | Description |
|
|
156
|
+
|----------|------------------------|--------------------------|
|
|
157
|
+
| `.head` | `-> string` | First character (errors on empty) |
|
|
158
|
+
| `.tail` | `-> string` | Last character (errors on empty) |
|
|
159
|
+
| `.at` | `(index: number) -> string` | Character at index |
|
|
160
|
+
|
|
161
|
+
```rill
|
|
162
|
+
"hello" -> .head # "h"
|
|
163
|
+
"hello" -> .tail # "o"
|
|
164
|
+
"hello" -> .at(1) # "e"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Common Patterns
|
|
168
|
+
|
|
169
|
+
### Normalize and Compare
|
|
170
|
+
|
|
171
|
+
```rill
|
|
172
|
+
$input -> .trim -> .lower -> .eq("yes")
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Extract and Validate
|
|
176
|
+
|
|
177
|
+
```rill
|
|
178
|
+
$email -> .is_match("^[^@]+@[^@]+$") ? process($email) ! error("Invalid email")
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Format Output
|
|
182
|
+
|
|
183
|
+
```rill
|
|
184
|
+
[[name: "Alice", value: 100], [name: "Bob", value: 42]] :> $items
|
|
185
|
+
$items -> each {
|
|
186
|
+
$.name -> .pad_end(20) :> $name
|
|
187
|
+
$.value -> .str -> .pad_start(10) :> $val
|
|
188
|
+
"{$name}{$val}"
|
|
189
|
+
} -> .join("\n")
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Replace Patterns
|
|
193
|
+
|
|
194
|
+
```rill
|
|
195
|
+
"hello world" :> $text
|
|
196
|
+
$text -> .replace_all("\\s+", " ") -> .trim
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Parse Structured Text
|
|
200
|
+
|
|
201
|
+
```rill
|
|
202
|
+
"key: value" :> $line
|
|
203
|
+
$line -> .match("(\\w+):\\s*(.+)") :> $m
|
|
204
|
+
$m -> !.empty ? [key: $m.groups[0], value: $m.groups[1]]
|
|
205
|
+
```
|