@rcrsr/rill 0.4.5 → 0.6.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.
Files changed (246) hide show
  1. package/dist/generated/introspection-data.d.ts +2 -0
  2. package/dist/generated/introspection-data.d.ts.map +1 -0
  3. package/dist/generated/introspection-data.js +539 -0
  4. package/dist/generated/introspection-data.js.map +1 -0
  5. package/dist/generated/version-data.d.ts +18 -0
  6. package/dist/generated/version-data.d.ts.map +1 -0
  7. package/dist/generated/version-data.js +16 -0
  8. package/dist/generated/version-data.js.map +1 -0
  9. package/dist/highlight-map.d.ts +4 -0
  10. package/dist/highlight-map.d.ts.map +1 -0
  11. package/dist/highlight-map.js +71 -0
  12. package/dist/highlight-map.js.map +1 -0
  13. package/dist/index.d.ts +3 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +9 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/lexer/errors.d.ts +3 -2
  18. package/dist/lexer/errors.d.ts.map +1 -1
  19. package/dist/lexer/errors.js +25 -4
  20. package/dist/lexer/errors.js.map +1 -1
  21. package/dist/lexer/operators.d.ts.map +1 -1
  22. package/dist/lexer/operators.js +2 -1
  23. package/dist/lexer/operators.js.map +1 -1
  24. package/dist/lexer/readers.d.ts.map +1 -1
  25. package/dist/lexer/readers.js +4 -4
  26. package/dist/lexer/readers.js.map +1 -1
  27. package/dist/lexer/tokenizer.d.ts.map +1 -1
  28. package/dist/lexer/tokenizer.js +1 -15
  29. package/dist/lexer/tokenizer.js.map +1 -1
  30. package/dist/parser/helpers.d.ts +8 -0
  31. package/dist/parser/helpers.d.ts.map +1 -1
  32. package/dist/parser/helpers.js +7 -5
  33. package/dist/parser/helpers.js.map +1 -1
  34. package/dist/parser/index.d.ts.map +1 -1
  35. package/dist/parser/index.js +1 -1
  36. package/dist/parser/index.js.map +1 -1
  37. package/dist/parser/parser-collect.js +1 -1
  38. package/dist/parser/parser-collect.js.map +1 -1
  39. package/dist/parser/parser-control.js +6 -4
  40. package/dist/parser/parser-control.js.map +1 -1
  41. package/dist/parser/parser-expr.d.ts.map +1 -1
  42. package/dist/parser/parser-expr.js +52 -10
  43. package/dist/parser/parser-expr.js.map +1 -1
  44. package/dist/parser/parser-extract.js +7 -3
  45. package/dist/parser/parser-extract.js.map +1 -1
  46. package/dist/parser/parser-functions.d.ts.map +1 -1
  47. package/dist/parser/parser-functions.js +8 -18
  48. package/dist/parser/parser-functions.js.map +1 -1
  49. package/dist/parser/parser-literals.js +15 -15
  50. package/dist/parser/parser-literals.js.map +1 -1
  51. package/dist/parser/parser-script.js +5 -3
  52. package/dist/parser/parser-script.js.map +1 -1
  53. package/dist/parser/parser-variables.js +10 -6
  54. package/dist/parser/parser-variables.js.map +1 -1
  55. package/dist/parser/state.d.ts +1 -1
  56. package/dist/parser/state.d.ts.map +1 -1
  57. package/dist/parser/state.js +2 -2
  58. package/dist/parser/state.js.map +1 -1
  59. package/dist/runtime/core/callable.d.ts +28 -0
  60. package/dist/runtime/core/callable.d.ts.map +1 -1
  61. package/dist/runtime/core/callable.js +30 -7
  62. package/dist/runtime/core/callable.js.map +1 -1
  63. package/dist/runtime/core/context.d.ts +21 -0
  64. package/dist/runtime/core/context.d.ts.map +1 -1
  65. package/dist/runtime/core/context.js +90 -10
  66. package/dist/runtime/core/context.js.map +1 -1
  67. package/dist/runtime/core/equals.d.ts.map +1 -1
  68. package/dist/runtime/core/equals.js +2 -1
  69. package/dist/runtime/core/equals.js.map +1 -1
  70. package/dist/runtime/core/eval/base.d.ts.map +1 -1
  71. package/dist/runtime/core/eval/base.js +3 -3
  72. package/dist/runtime/core/eval/base.js.map +1 -1
  73. package/dist/runtime/core/eval/index.d.ts.map +1 -1
  74. package/dist/runtime/core/eval/index.js +2 -0
  75. package/dist/runtime/core/eval/index.js.map +1 -1
  76. package/dist/runtime/core/eval/mixins/annotations.js +3 -3
  77. package/dist/runtime/core/eval/mixins/annotations.js.map +1 -1
  78. package/dist/runtime/core/eval/mixins/closures.d.ts.map +1 -1
  79. package/dist/runtime/core/eval/mixins/closures.js +75 -40
  80. package/dist/runtime/core/eval/mixins/closures.js.map +1 -1
  81. package/dist/runtime/core/eval/mixins/collections.js +15 -15
  82. package/dist/runtime/core/eval/mixins/collections.js.map +1 -1
  83. package/dist/runtime/core/eval/mixins/control-flow.d.ts.map +1 -1
  84. package/dist/runtime/core/eval/mixins/control-flow.js +12 -12
  85. package/dist/runtime/core/eval/mixins/control-flow.js.map +1 -1
  86. package/dist/runtime/core/eval/mixins/core.d.ts.map +1 -1
  87. package/dist/runtime/core/eval/mixins/core.js +39 -17
  88. package/dist/runtime/core/eval/mixins/core.js.map +1 -1
  89. package/dist/runtime/core/eval/mixins/expressions.d.ts +2 -0
  90. package/dist/runtime/core/eval/mixins/expressions.d.ts.map +1 -1
  91. package/dist/runtime/core/eval/mixins/expressions.js +81 -28
  92. package/dist/runtime/core/eval/mixins/expressions.js.map +1 -1
  93. package/dist/runtime/core/eval/mixins/extraction.d.ts.map +1 -1
  94. package/dist/runtime/core/eval/mixins/extraction.js +15 -15
  95. package/dist/runtime/core/eval/mixins/extraction.js.map +1 -1
  96. package/dist/runtime/core/eval/mixins/literals.d.ts +4 -1
  97. package/dist/runtime/core/eval/mixins/literals.d.ts.map +1 -1
  98. package/dist/runtime/core/eval/mixins/literals.js +45 -25
  99. package/dist/runtime/core/eval/mixins/literals.js.map +1 -1
  100. package/dist/runtime/core/eval/mixins/types.js +4 -4
  101. package/dist/runtime/core/eval/mixins/types.js.map +1 -1
  102. package/dist/runtime/core/eval/mixins/variables.js +34 -34
  103. package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
  104. package/dist/runtime/core/execute.js +3 -3
  105. package/dist/runtime/core/execute.js.map +1 -1
  106. package/dist/runtime/core/introspection.d.ts +88 -0
  107. package/dist/runtime/core/introspection.d.ts.map +1 -0
  108. package/dist/runtime/core/introspection.js +166 -0
  109. package/dist/runtime/core/introspection.js.map +1 -0
  110. package/dist/runtime/core/types.d.ts +11 -0
  111. package/dist/runtime/core/types.d.ts.map +1 -1
  112. package/dist/runtime/core/types.js.map +1 -1
  113. package/dist/runtime/ext/builtins.js +22 -22
  114. package/dist/runtime/ext/builtins.js.map +1 -1
  115. package/dist/runtime/ext/extensions.d.ts +1 -1
  116. package/dist/runtime/ext/extensions.d.ts.map +1 -1
  117. package/dist/runtime/ext/extensions.js +4 -5
  118. package/dist/runtime/ext/extensions.js.map +1 -1
  119. package/dist/runtime/index.d.ts +8 -2
  120. package/dist/runtime/index.d.ts.map +1 -1
  121. package/dist/runtime/index.js +4 -1
  122. package/dist/runtime/index.js.map +1 -1
  123. package/dist/types.d.ts +141 -32
  124. package/dist/types.d.ts.map +1 -1
  125. package/dist/types.js +806 -40
  126. package/dist/types.js.map +1 -1
  127. package/package.json +7 -64
  128. package/README.md +0 -223
  129. package/dist/check/config.d.ts +0 -20
  130. package/dist/check/config.d.ts.map +0 -1
  131. package/dist/check/config.js +0 -151
  132. package/dist/check/config.js.map +0 -1
  133. package/dist/check/fixer.d.ts +0 -39
  134. package/dist/check/fixer.d.ts.map +0 -1
  135. package/dist/check/fixer.js +0 -119
  136. package/dist/check/fixer.js.map +0 -1
  137. package/dist/check/index.d.ts +0 -10
  138. package/dist/check/index.d.ts.map +0 -1
  139. package/dist/check/index.js +0 -21
  140. package/dist/check/index.js.map +0 -1
  141. package/dist/check/rules/anti-patterns.d.ts +0 -65
  142. package/dist/check/rules/anti-patterns.d.ts.map +0 -1
  143. package/dist/check/rules/anti-patterns.js +0 -481
  144. package/dist/check/rules/anti-patterns.js.map +0 -1
  145. package/dist/check/rules/closures.d.ts +0 -66
  146. package/dist/check/rules/closures.d.ts.map +0 -1
  147. package/dist/check/rules/closures.js +0 -370
  148. package/dist/check/rules/closures.js.map +0 -1
  149. package/dist/check/rules/collections.d.ts +0 -90
  150. package/dist/check/rules/collections.d.ts.map +0 -1
  151. package/dist/check/rules/collections.js +0 -373
  152. package/dist/check/rules/collections.js.map +0 -1
  153. package/dist/check/rules/conditionals.d.ts +0 -41
  154. package/dist/check/rules/conditionals.d.ts.map +0 -1
  155. package/dist/check/rules/conditionals.js +0 -134
  156. package/dist/check/rules/conditionals.js.map +0 -1
  157. package/dist/check/rules/flow.d.ts +0 -46
  158. package/dist/check/rules/flow.d.ts.map +0 -1
  159. package/dist/check/rules/flow.js +0 -206
  160. package/dist/check/rules/flow.js.map +0 -1
  161. package/dist/check/rules/formatting.d.ts +0 -133
  162. package/dist/check/rules/formatting.d.ts.map +0 -1
  163. package/dist/check/rules/formatting.js +0 -648
  164. package/dist/check/rules/formatting.js.map +0 -1
  165. package/dist/check/rules/helpers.d.ts +0 -26
  166. package/dist/check/rules/helpers.d.ts.map +0 -1
  167. package/dist/check/rules/helpers.js +0 -66
  168. package/dist/check/rules/helpers.js.map +0 -1
  169. package/dist/check/rules/index.d.ts +0 -21
  170. package/dist/check/rules/index.d.ts.map +0 -1
  171. package/dist/check/rules/index.js +0 -78
  172. package/dist/check/rules/index.js.map +0 -1
  173. package/dist/check/rules/loops.d.ts +0 -77
  174. package/dist/check/rules/loops.d.ts.map +0 -1
  175. package/dist/check/rules/loops.js +0 -310
  176. package/dist/check/rules/loops.js.map +0 -1
  177. package/dist/check/rules/naming.d.ts +0 -21
  178. package/dist/check/rules/naming.d.ts.map +0 -1
  179. package/dist/check/rules/naming.js +0 -174
  180. package/dist/check/rules/naming.js.map +0 -1
  181. package/dist/check/rules/strings.d.ts +0 -28
  182. package/dist/check/rules/strings.d.ts.map +0 -1
  183. package/dist/check/rules/strings.js +0 -79
  184. package/dist/check/rules/strings.js.map +0 -1
  185. package/dist/check/rules/types.d.ts +0 -41
  186. package/dist/check/rules/types.d.ts.map +0 -1
  187. package/dist/check/rules/types.js +0 -167
  188. package/dist/check/rules/types.js.map +0 -1
  189. package/dist/check/types.d.ts +0 -112
  190. package/dist/check/types.d.ts.map +0 -1
  191. package/dist/check/types.js +0 -6
  192. package/dist/check/types.js.map +0 -1
  193. package/dist/check/validator.d.ts +0 -18
  194. package/dist/check/validator.d.ts.map +0 -1
  195. package/dist/check/validator.js +0 -110
  196. package/dist/check/validator.js.map +0 -1
  197. package/dist/check/visitor.d.ts +0 -33
  198. package/dist/check/visitor.d.ts.map +0 -1
  199. package/dist/check/visitor.js +0 -258
  200. package/dist/check/visitor.js.map +0 -1
  201. package/dist/cli-check.d.ts +0 -43
  202. package/dist/cli-check.d.ts.map +0 -1
  203. package/dist/cli-check.js +0 -369
  204. package/dist/cli-check.js.map +0 -1
  205. package/dist/cli-eval.d.ts +0 -15
  206. package/dist/cli-eval.d.ts.map +0 -1
  207. package/dist/cli-eval.js +0 -117
  208. package/dist/cli-eval.js.map +0 -1
  209. package/dist/cli-exec.d.ts +0 -49
  210. package/dist/cli-exec.d.ts.map +0 -1
  211. package/dist/cli-exec.js +0 -184
  212. package/dist/cli-exec.js.map +0 -1
  213. package/dist/cli-module-loader.d.ts +0 -19
  214. package/dist/cli-module-loader.d.ts.map +0 -1
  215. package/dist/cli-module-loader.js +0 -83
  216. package/dist/cli-module-loader.js.map +0 -1
  217. package/dist/cli-shared.d.ts +0 -42
  218. package/dist/cli-shared.d.ts.map +0 -1
  219. package/dist/cli-shared.js +0 -112
  220. package/dist/cli-shared.js.map +0 -1
  221. package/dist/cli.d.ts +0 -13
  222. package/dist/cli.d.ts.map +0 -1
  223. package/dist/cli.js +0 -62
  224. package/dist/cli.js.map +0 -1
  225. package/docs/00_INDEX.md +0 -67
  226. package/docs/01_guide.md +0 -390
  227. package/docs/02_types.md +0 -482
  228. package/docs/03_variables.md +0 -324
  229. package/docs/04_operators.md +0 -608
  230. package/docs/05_control-flow.md +0 -630
  231. package/docs/06_closures.md +0 -787
  232. package/docs/07_collections.md +0 -688
  233. package/docs/08_iterators.md +0 -330
  234. package/docs/09_strings.md +0 -205
  235. package/docs/10_parsing.md +0 -366
  236. package/docs/11_reference.md +0 -599
  237. package/docs/12_examples.md +0 -748
  238. package/docs/13_modules.md +0 -519
  239. package/docs/14_host-integration.md +0 -833
  240. package/docs/15_grammar.ebnf +0 -755
  241. package/docs/16_conventions.md +0 -695
  242. package/docs/17_cli-tools.md +0 -184
  243. package/docs/18_design-principles.md +0 -247
  244. package/docs/19_cookbook.md +0 -628
  245. package/docs/99_llm-reference.txt +0 -601
  246. package/docs/assets/logo.png +0 -0
@@ -1,601 +0,0 @@
1
- RILL LANGUAGE REFERENCE
2
- =======================
3
-
4
- Rill is designed to be generated by LLMs and understood by humans. The focus is on auditable LLM output, not ergonomic human authoring. It combines the flexibility of imperative languages with the strictness of declaritive specifications.
5
-
6
- STRENGTHS AND USE CASES
7
- -----------------------
8
- Strengths:
9
- - Unambiguous syntax: $ prefix, explicit operators, no implicit coercion
10
- - Single-pass parseable: LLMs generate correct code without symbol tables
11
- - Readable by humans: pipe chains show data flow left-to-right
12
- - Safe defaults: immutable values, type locking, no null/undefined
13
-
14
- Use cases:
15
- - Workflow orchestration: chain LLM calls, API requests, transformations
16
- - State machines: (cond) @ { } loops with $ as state dict handle multi-state logic
17
- - Data pipelines: each/map/filter/fold process collections declaratively
18
- - Prompt engineering: parse LLM output with parse_json, parse_xml, parse_fence
19
-
20
- State machine pattern ($ carries state through iterations):
21
- [state: "init", data: $input]
22
- -> ($.state != "done") @ {
23
- $.state -> [
24
- init: { [state: "process", data: transform($.data)] },
25
- process: { [state: "done", data: finalize($.data)] }
26
- ]
27
- }
28
-
29
- NAMING CONVENTION: snake_case
30
- -----------------------------
31
- Use snake_case for all identifiers:
32
- $user_name, $item_list, $is_valid # variables
33
- $double_value, $cleanup_text # closures
34
- [first_name: "x", last_name: "y"] # dict keys
35
-
36
- WHY VARIABLES USE $ PREFIX
37
- --------------------------
38
- The $ prefix enables single-pass parsing without a symbol table:
39
-
40
- name() -> host function call
41
- $name() -> closure invocation
42
- $name -> variable reference
43
- name -> dict key literal
44
-
45
- Without $, "process(data)" is ambiguous: is process a host function or stored
46
- closure? Is data a variable or key? This would require tracking all declarations.
47
-
48
- Additional disambiguation:
49
- - Capture: :> $x requires $ for lookahead (avoids conflict with slice /<1:>)
50
- - Destructure: *<$a, $b> marks variables vs skip patterns
51
- - Dynamic access: $data.$key distinguishes variable-key from literal field
52
- - Visual clarity: $total is always a variable, no context needed
53
-
54
- This follows rill's "no magic" principle: syntax communicates intent explicitly.
55
-
56
- SPACING RULES
57
- -------------
58
- Operators: space both sides 5 + 3, $x -> .upper, "a" :> $b
59
- Parentheses: no inner space ($x + 1), ($ > 3) ? "yes"
60
- Braces: space inside { $x + 1 }, each { $ * 2 }
61
- Brackets: no inner space $list[0], $dict.items[1]
62
- Literals: space after , and : [1, 2, 3], [name: "x", age: 30]
63
- Closures: space after params |x| ($x * 2), |a, b| { $a + $b }
64
- Methods: no space before . or ( $str.upper(), $list.join(", ")
65
- Pipes: space both sides "x" -> .upper -> .len
66
- Continuations: indent 2 spaces $data
67
- -> .filter { $.active }
68
- -> map { $.name }
69
-
70
- IMPLICIT $ SHORTHAND (always prefer)
71
- ------------------------------------
72
- $.method() -> .method "x" -> .upper (not $.upper())
73
- func($) -> func "x" -> log (not log($))
74
- $fn($) -> $fn 5 -> $double (not $double($))
75
-
76
- NO THROWAWAY CAPTURES
77
- ---------------------
78
- Don't capture just to continue - use line continuation instead:
79
- # avoid # good
80
- "x" :> $a "x"
81
- $a -> .upper :> $b -> .upper
82
- $b -> .len -> .len
83
-
84
- Only capture when the variable is reused later in the code.
85
-
86
- CRITICAL DIFFERENCES FROM MAINSTREAM LANGUAGES
87
- ----------------------------------------------
88
-
89
- 1. NO ASSIGNMENT OPERATOR
90
- Wrong: x = 5
91
- Right: 5 :> $x
92
-
93
- Pipe (->): passes value to next operation
94
- Capture (:>): stores value AND continues chain
95
- Example: "hello" :> $x -> .upper :> $y # $x="hello", $y="HELLO"
96
-
97
- 2. NO NULL/UNDEFINED
98
- Empty values ("", [], [:]) exist. "No value" cannot be represented.
99
- Use ?? for defaults: $dict.field ?? "default"
100
- Use .empty to check: $str -> .empty ? "was empty"
101
-
102
- 3. NO TRUTHINESS
103
- Conditions MUST be boolean. No implicit coercion.
104
- Wrong: "" ? "yes" ! "no"
105
- Right: "" -> .empty ? "yes" ! "no"
106
- Wrong: 0 ? "yes" ! "no"
107
- Right: (0 == 0) ? "yes" ! "no"
108
-
109
- 4. VARIABLES LOCK TO FIRST TYPE
110
- "hello" :> $x
111
- 42 :> $x # ERROR: cannot assign number to string variable
112
-
113
- 5. NO VARIABLE SHADOWING (CRITICAL FOR LOOPS)
114
- Child scopes can READ parent variables but cannot WRITE or redeclare them.
115
- Variables created inside blocks/loops do NOT leak out.
116
-
117
- WRONG - this pattern NEVER works:
118
- 0 :> $count
119
- [1, 2, 3] -> each { $count + 1 :> $count } # creates LOCAL $count
120
- $count # still 0!
121
-
122
- RIGHT - use $ or $@ as state carrier (see LOOP STATE PATTERNS below)
123
-
124
- 6. NO EXCEPTIONS
125
- Errors halt execution. No try/catch. Use conditionals for error handling.
126
- Built-in: assert (validate condition), error (halt with message).
127
-
128
- 7. VALUE SEMANTICS (no references)
129
- All copies are deep. All comparisons are by value. No object identity.
130
- [1, 2, 3] == [1, 2, 3] # true (content equality)
131
- [1, 2] :> $a
132
- $a :> $b # $b is an independent deep copy
133
- Mainstream habit to avoid: expecting two variables to share the same object.
134
-
135
- SYNTAX QUICK REFERENCE
136
- ----------------------
137
-
138
- Variables: $name (always prefixed with $)
139
- Strings: "hello {$var}" # interpolation with {}
140
- """...""" # multiline (also interpolates)
141
- Numbers: 42, 3.14, -7
142
- Booleans: true, false
143
- Lists: [1, 2, 3]
144
- [...$list, 4] # spread: inline list elements
145
- Dicts: [name: "alice", age: 30] # identifier keys
146
- [1: "one", 2: "two"] # number keys (incl. negative: [-1: "neg"])
147
- [true: "yes", false: "no"] # boolean keys
148
- [["a", "b"]: 1] # multi-key: [a: 1, b: 1]
149
- [$keyVar: value] # variable key (must eval to string)
150
- [($expr): value] # computed key (must eval to string)
151
- Tuples: *[1, 2, 3] # for argument unpacking
152
- Closures: |x|($x + 1) # like lambda/arrow functions
153
- Type annot: "hi" :> $x:string # lock type on capture
154
- Comments: # single line only
155
-
156
- PIPES AND $ BINDING
157
- -------------------
158
-
159
- $ is the current piped value. Its meaning depends on context:
160
-
161
- | Context | $ contains |
162
- |----------------------------|-------------------------|
163
- | -> { body } | piped value |
164
- | -> each { } | current item |
165
- | (cond) @ { } | accumulated value |
166
- | @ { } ? cond | accumulated value |
167
- | cond ? { } ! { } | tested value |
168
- | -> ? { } ! { } | piped value |
169
- | ||{ $.field } in dict | the containing dict |
170
- | |x|{ } stored closure | N/A - use parameters |
171
-
172
- Implied $: bare .method() means $ -> .method()
173
- Example: "hello" -> .upper # same as "hello" -> $.upper()
174
-
175
- CONTROL FLOW
176
- ------------
177
-
178
- Conditional (if-else):
179
- cond ? then_expr ! else_expr
180
- cond ? then_expr # else returns ""
181
-
182
- Piped conditional ($ becomes condition):
183
- value -> ? then_expr ! else_expr
184
-
185
- Condition loop (NO "while" keyword - use @ operator):
186
- init_value -> ($ < 10) @ { $ + 1 } # $ is accumulator
187
-
188
- Do-condition loop (body runs at least once):
189
- init_value -> @ { $ + 1 } ? ($ < 10)
190
-
191
- Break (exits loop, returns collected results before break):
192
- [1,2,3,4,5] -> each { ($ == 3) ? break; $ } # returns [1, 2]
193
-
194
- Return (exits block or script with value):
195
- { 5 :> $x; ($x > 3) ? ("big" -> return); "small" } # returns "big"
196
- "done" -> return # exits script with "done"
197
-
198
- Assert (validate condition, halt if false, pass through if true):
199
- 5 -> assert ($ > 0) # returns 5
200
- -1 -> assert ($ > 0) # ERROR: Assertion failed
201
- "" -> assert !.empty "Input required" # ERROR: Input required
202
- $val -> assert $:?list "Expected list" # type validation
203
-
204
- Error (halt execution immediately with message):
205
- error "Something went wrong" # halt with message
206
- "Operation failed" -> error # piped form (must be string)
207
- error "Status: {$code}" # interpolation works
208
-
209
- LOOP STATE PATTERNS (CRITICAL)
210
- ------------------------------
211
- Rill loops CANNOT modify outer variables. All state must flow through $ or $@.
212
-
213
- WRONG - outer variable modification (NEVER works):
214
- 0 :> $sum
215
- [1, 2, 3] -> each { $sum + $ :> $sum } # $sum unchanged!
216
-
217
- WRONG - "while" keyword does not exist:
218
- while ($i < 10) { $i + 1 :> $i } # SYNTAX ERROR
219
-
220
- RIGHT - use fold for reduction:
221
- [1, 2, 3] -> fold(0) { $@ + $ } # 6 ($@ is accumulator)
222
-
223
- RIGHT - use each(init) when you need both results AND accumulator:
224
- [1, 2, 3] -> each(0) { $@ + $ } # [1, 3, 6] (running totals)
225
-
226
- RIGHT - use (cond) @ { } with $ as state dict for multiple values:
227
- [iter: 0, max: 3, text: $input, done: false]
228
- -> (!$.done && $.iter < $.max) @ {
229
- $.iter + 1 :> $i
230
- process($.text) :> $result
231
- $result.finished ? [iter: $i, max: $.max, text: $.text, done: true]
232
- ! [iter: $i, max: $.max, text: $result.text, done: false]
233
- }
234
- # Access final state: $.text, $.iter
235
-
236
- Pattern summary:
237
- - Single value accumulation -> fold(init) { $@ + $ }
238
- - Per-item results + running -> each(init) { ... $@ ... }
239
- - Multiple state values / while -> (cond) @ { } with $ as state dict
240
- - "while" and "for" keywords -> DO NOT EXIST
241
-
242
- COLLECTION OPERATORS
243
- --------------------
244
-
245
- | Operator | Execution | Returns | Break? |
246
- |--------------------|------------|----------------------|--------|
247
- | -> each { } | sequential | all body results | yes |
248
- | -> each(i) { $@+$} | sequential | all with accumulator | yes |
249
- | -> map { } | parallel | all body results | NO |
250
- | -> filter { } | parallel | matching elements | NO |
251
- | -> fold(i) { $@+$} | sequential | final result only | yes |
252
-
253
- $@ is the accumulator in each(init) and fold(init).
254
-
255
- Method shorthand in collection operators:
256
- ["a", "b"] -> map .upper # ["A", "B"]
257
- ["", "x"] -> filter (!.empty) # ["x"]
258
- ["a", "b"] -> map .pad_start(3, "0") # ["00a", "00b"] (with args)
259
- [" HI "] -> map .trim.lower # ["hi"] (chained methods)
260
-
261
- Body forms (all operators accept these):
262
- -> each { $ * 2 } # block ($ is current element)
263
- -> each ($ + 10) # grouped expression
264
- -> each |x| ($x * 2) # inline closure
265
- -> each $double # variable closure
266
- -> each .upper # method shorthand
267
-
268
- Dict iteration ($ contains key and value fields):
269
- [a: 1, b: 2] -> each { "{$.key}={$.value}" } # ["a=1", "b=2"]
270
- [a: 1, b: 5] -> filter { $.value > 2 } # entries where value > 2
271
-
272
- String iteration (iterates over characters):
273
- "abc" -> each { "{$}!" } # ["a!", "b!", "c!"]
274
- "hello" -> filter { $ != "l" } # ["h", "e", "o"]
275
-
276
- CLOSURES
277
- --------
278
-
279
- BLOCK-CLOSURES vs EXPLICIT CLOSURES:
280
-
281
- Two ways to create closures:
282
-
283
- 1. Block-closures: { body } in expression position
284
- { $ + 1 } :> $inc # implicit $ parameter
285
- $inc(5) # 6
286
- 5 -> $inc # 6 (pipe invocation)
287
- [x: { $ * 2 }] # dict value is closure
288
- type({ "hi" }) # "closure"
289
-
290
- 2. Explicit closures: |params| body
291
- |x|($x + 1) :> $inc # named parameter
292
- |a, b|($a + $b) :> $add # multiple params
293
- |x = 0|($x + 1) :> $inc_or_one # default value
294
- |x: number|($x + 1) :> $typed # type annotation
295
-
296
- CRITICAL: { } vs ( ) distinction
297
-
298
- | Syntax | Semantics | Example |
299
- |--------------|------------------------|----------------------------|
300
- | { body } | Deferred (closure) | { $ + 1 } :> $fn # closure |
301
- | ( expr ) | Eager (immediate eval) | ( 5 + 1 ) :> $x # 6 |
302
-
303
- When to use:
304
- { body } :> $fn # store closure for later use
305
- ( expr ) :> $x # store result value immediately
306
-
307
- PIPE TARGET: { } creates closure then immediately invokes it:
308
- 5 -> { $ + 1 } # 6 (create closure, invoke with 5)
309
- 5 -> ($ + 1) # 6 (evaluate expression with $=5)
310
- Same observable result, different mechanism. Error messages differ.
311
-
312
- Block-closure invocation:
313
- { $ + 1 } :> $inc
314
- $inc(5) # direct call: 6
315
- 5 -> $inc # pipe call: 6
316
- [1,2,3] -> map $inc # in collection op
317
-
318
- LATE BINDING: closures capture scope, not values. Variables resolve at call time.
319
-
320
- $ vs named params:
321
- Use $ in inline pipes and loops: "hello" -> { .upper }
322
- Use named params in stored closures: |x| ($x * 2) :> $double
323
- $ is undefined when a stored closure is called later — always use params.
324
-
325
- Zero-param dict closures (methods):
326
- [count: 3, double: ||{ $.count * 2 }] :> $obj
327
- $obj.double # 6 ($ is bound to dict)
328
-
329
- PROPERTY ACCESS
330
- ---------------
331
-
332
- $data.field # dict field
333
- $data[0], $data[-1] # list index (negative from end)
334
- $data.$key # variable as key
335
- $data.($i + 1) # computed key
336
- $data.(a || b) # try keys left-to-right
337
- $data.field ?? "default" # default if missing
338
- $data.?field # existence check (boolean)
339
- $data.?$keyVar # variable existence check
340
- $data.?($expr) # computed existence check
341
- $data.?field&string # existence AND type check
342
- $data.?$key&number # variable existence + type check
343
- $data.?($a -> "{$}_b")&list # computed existence + type check
344
-
345
- DISPATCH OPERATORS
346
- ------------------
347
-
348
- DICT DISPATCH (single key):
349
- Pipe a value to a dict to match keys and return associated values:
350
- $val -> [apple: "fruit", carrot: "veg"] # returns "fruit" if $val is "apple"
351
- $val -> [apple: "fruit"] ?? "not found" # default if no match
352
- $method -> [["GET", "HEAD"]: "safe", ["POST", "PUT"]: "unsafe"] # multi-key dispatch
353
-
354
- Multi-key dispatch uses the same syntax as multi-key dict literals:
355
- [["GET", "HEAD"]: "safe"] # dict with keys "GET" and "HEAD" both = "safe"
356
- "GET" -> [["GET", "HEAD"]: "safe"] # "safe" (matches "GET" key)
357
-
358
- Type-aware matching (keys matched by value AND type):
359
- 1 -> [1: "number", "1": "string"] # "number" (number key matches)
360
- "1" -> [1: "number", "1": "string"] # "string" (string key matches)
361
- true -> [true: "bool", "true": "str"] # "bool" (boolean key matches)
362
-
363
- LIST DISPATCH (index):
364
- Pipe a number to a list to get element at index:
365
- 0 -> ["first", "second"] # "first"
366
- -1 -> ["first", "second"] # "second" (last)
367
- 5 -> ["a", "b"] ?? "not found" # default if out of bounds
368
-
369
- HIERARCHICAL DISPATCH (path navigation):
370
- Pipe a list of keys/indexes to navigate nested structures:
371
- ["name", "first"] -> [name: [first: "Alice"]] # "Alice" (dict path)
372
- [0, 1] -> [[1, 2, 3], [4, 5, 6]] # 2 (list path)
373
- ["users", 0, "name"] -> [users: [[name: "Alice"]]] # "Alice" (mixed)
374
- [] -> [a: 1] # [a: 1] (empty path = unchanged)
375
- ["a", "missing"] -> [a: [x: 1]] ?? "default" # "default" (missing key)
376
-
377
- Path elements: strings for dict keys, numbers for list indexes (negative supported).
378
- Terminal closures receive $ bound to final path key:
379
- ["req", "draft"] -> [req: [draft: { "key={$}" }]] # "key=draft"
380
-
381
- TYPE OPERATIONS
382
- ---------------
383
-
384
- :type - assert type (error if wrong): 42:number passes; "x":number errors
385
- :?type - check type (boolean): 42:?number is true; "x":?number is false
386
-
387
- Types: string, number, boolean, list, dict, tuple, closure
388
-
389
- COMPARISON METHODS
390
- ------------------
391
-
392
- Methods for readable comparisons in conditionals:
393
- .eq(val) == $v -> .eq("A") ? "match"
394
- .ne(val) != $v -> .ne("") ? "has value"
395
- .lt(val) < $v -> .lt(10) ? "small"
396
- .gt(val) > 5 -> .gt(3) ? "big"
397
- .le(val) <= 10 -> .le(10) ? "ok"
398
- .ge(val) >= $age -> .ge(18) ? "adult"
399
-
400
- OPERATOR PRECEDENCE (highest to lowest)
401
- ---------------------------------------
402
-
403
- 1. Member access: .field, [index]
404
- 2. Type operators: :type, :?type
405
- 3. Unary: -, !
406
- 4. Multiplicative: *, /, %
407
- 5. Additive: +, -
408
- 6. Comparison: ==, !=, <, >, <=, >=
409
- 7. Logical AND: &&
410
- 8. Logical OR: ||
411
- 9. Default: ??
412
- 10. Pipe: ->
413
- 11. Capture: :>
414
-
415
- Use parentheses to override: (2 + 3) * 4
416
-
417
- EXTRACTION OPERATORS
418
- --------------------
419
-
420
- Destructure (*<>):
421
- [1, 2, 3] -> *<$a, $b, $c> # $a=1, $b=2, $c=3
422
- [x: 1, y: 2] -> *<x: $a, y: $b> # $a=1, $b=2
423
- [1, 2, 3] -> *<$first, _, $third> # _ skips element
424
-
425
- Slice (/<start:stop:step>):
426
- [0,1,2,3,4] -> /<1:3> # [1, 2]
427
- [0,1,2,3,4] -> /<-2:> # [3, 4]
428
- [0,1,2,3,4] -> /<::-1> # [4,3,2,1,0] (reverse)
429
- "hello" -> /<1:4> # "ell"
430
-
431
- LIST SPREAD IN LITERALS
432
- -----------------------
433
-
434
- Inline list elements into a new list using ... (spread operator):
435
- [1, 2] :> $a
436
- [...$a, 3] # [1, 2, 3]
437
- [...$a, ...$b] # concatenate lists
438
- [...[], 1] # [1] (empty spread contributes nothing)
439
- [...($nums -> map {$ * 2})] # spread expression result
440
- [...$nested[0]] # spread from nested access
441
-
442
- Error: spreading non-list throws RUNTIME_TYPE_ERROR
443
- "hello" :> $s
444
- [...$s] # ERROR: Spread requires list, got string
445
-
446
- MULTI-KEY DICT LITERALS
447
- -----------------------
448
-
449
- Map multiple keys to the same value using list syntax:
450
- [["a", "b"]: 1] # [a: 1, b: 1]
451
- [[1, "1"]: "x"] # [1: "x", "1": "x"] (mixed types)
452
- [a: 0, ["b", "c"]: 1] # [a: 0, b: 1, c: 1] (mixed entries)
453
- [a: 0, ["a", "b"]: 1] # [a: 1, b: 1] (last-write-wins)
454
-
455
- Error cases:
456
- [[]: 1] # ERROR: empty key list
457
- [[[1, 2], "a"]: 1] # ERROR: non-primitive key element
458
-
459
- TUPLES FOR ARGUMENT UNPACKING
460
- -----------------------------
461
-
462
- *[1, 2, 3] -> $fn() # positional: $fn(1, 2, 3)
463
- *[b: 2, a: 1] -> $fn() # named: $fn(a=1, b=2)
464
- *[...$list, 3] -> $fn() # spread in tuple: combines elements
465
-
466
- SPREAD OPERATOR (@)
467
- -------------------
468
-
469
- Chains closures sequentially:
470
- 5 -> @[$inc, $double, $add10] # (5+1)*2+10 = 22
471
-
472
- STRING METHODS
473
- --------------
474
-
475
- .len length
476
- .empty is empty string
477
- .trim remove whitespace
478
- .upper uppercase
479
- .lower lowercase
480
- .split(sep) split into list
481
- .lines split on newlines
482
- .join(sep) join list with separator (on list)
483
- .contains(s) substring check
484
- .starts_with(s) prefix check
485
- .ends_with(s) suffix check
486
- .replace(p,r) replace first match
487
- .replace_all(p,r) replace all matches
488
- .match(regex) first match info (dict with matched, index, groups)
489
- .is_match(regex) boolean regex check
490
- .head first character
491
- .tail last character
492
- .at(i) character at index
493
- .index_of(s) position of first match (-1 if none)
494
- .repeat(n) repeat string n times: "ab" -> .repeat(3) # "ababab"
495
- .pad_start(n,f) pad start to length: "42" -> .pad_start(5, "0") # "00042"
496
- .pad_end(n,f) pad end to length: "42" -> .pad_end(5, "0") # "42000"
497
- .str convert any value to string: 42 -> .str # "42"
498
- .num parse string to number: "42" -> .num # 42
499
-
500
- LIST/DICT METHODS
501
- -----------------
502
-
503
- .len length
504
- .empty is empty
505
- .head first element
506
- .tail last element
507
- .at(i) element at index
508
- .has(val) check if list contains value (deep equality)
509
- .has_any(list) check if list contains any value from candidates
510
- .has_all(list) check if list contains all values from candidates
511
- .keys dict keys as list
512
- .values dict values as list
513
- .entries dict as list of [key: k, value: v]
514
-
515
- PARSING FUNCTIONS (for LLM output)
516
- ----------------------------------
517
-
518
- parse_auto(str) auto-detect format
519
- parse_json(str) parse JSON (repairs common errors)
520
- parse_xml(str, tag?) extract XML tag content
521
- parse_fence(str, lang?) extract fenced code block
522
- parse_fences(str) all fenced blocks as list
523
- parse_frontmatter(str) parse --- delimited YAML + body
524
- parse_checklist(str) parse markdown task lists
525
-
526
- GLOBAL FUNCTIONS
527
- ----------------
528
-
529
- type(val) returns type name
530
- log(val) print and pass through
531
- json(val) convert to JSON string
532
- identity(val) returns input unchanged
533
- range(start, end, step?) number sequence
534
- repeat(val, count) repeat value n times
535
- enumerate(coll) add index to elements
536
-
537
- ITERATORS
538
- ---------
539
-
540
- Lazy sequence generation. Collection operators auto-expand iterators.
541
-
542
- Built-in iterators:
543
- range(0, 5) -> each { $ * 2 } # [0, 2, 4, 6, 8]
544
- repeat("x", 3) -> each { $ } # ["x", "x", "x"]
545
-
546
- .first() method (returns iterator for any collection):
547
- [1, 2, 3] -> .first() # iterator at 1
548
- "abc" -> .first() # iterator at "a"
549
- [] -> .first() # [done: true, ...]
550
-
551
- Iterator protocol (dict with value, done, next):
552
- $it.done # bool: is exhausted?
553
- $it.value # current element
554
- $it.next() # returns new iterator at next position
555
-
556
- ITERATION LIMITS
557
- ----------------
558
-
559
- Default: 10,000 iterations max for loops.
560
- Override: ^(limit: N) statement
561
-
562
- Example:
563
- ^(limit: 100) 0 -> ($ < 50) @ { $ + 1 }
564
-
565
- Concurrency limit for map (controls parallel concurrency):
566
- ^(limit: 3) $items -> map { slow_process($) }
567
-
568
- COMMON MISTAKES
569
- ---------------
570
-
571
- 1. Using = for assignment -> use :> instead
572
- 2. Using || for defaults -> use ?? instead
573
- 3. Assuming truthiness -> explicit boolean checks required
574
- 4. Breaking from map/filter -> only works in each/fold
575
- 5. Modifying outer vars in loops -> use fold/$@ or $ as state dict (see LOOP STATE PATTERNS)
576
- 6. Expecting variables to leak -> block scope is strict
577
- 7. Forgetting () on methods -> .upper() not .upper (unless property)
578
- 8. Reassigning different type -> variables lock to first type
579
- 9. Using while/for keywords -> use (cond) @ { } or -> each { } instead
580
-
581
- SCRIPT RETURN VALUES
582
- --------------------
583
-
584
- true / non-empty string -> exit code 0
585
- false / empty string -> exit code 1
586
- [0, "message"] -> exit code 0 with message
587
- [1, "message"] -> exit code 1 with message
588
-
589
- MAINSTREAM TO RILL TRANSLATION
590
- ------------------------------
591
-
592
- | Mainstream | Rill |
593
- |--------------------------|----------------------------------------- |
594
- | x = value | value :> $x |
595
- | null / undefined | ?? default, .? existence check |
596
- | if "" (truthiness) | .empty, == 0, :?type |
597
- | try { } catch { } | assert, conditionals, error |
598
- | for (i = 0; ...) | each, map, filter, fold |
599
- | count += 1 in loop | fold(0) { $@ + 1 } or $ accumulator |
600
- | a === b (reference) | == always compares by value |
601
- | a = b (shared ref) | :> always deep-copies |
Binary file