@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.
Files changed (295) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +187 -0
  3. package/dist/cli.d.ts +11 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +69 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/demo.d.ts +6 -0
  8. package/dist/demo.d.ts.map +1 -0
  9. package/dist/demo.js +121 -0
  10. package/dist/demo.js.map +1 -0
  11. package/dist/index.d.ts +10 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +9 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/lexer/errors.d.ts +9 -0
  16. package/dist/lexer/errors.d.ts.map +1 -0
  17. package/dist/lexer/errors.js +12 -0
  18. package/dist/lexer/errors.js.map +1 -0
  19. package/dist/lexer/helpers.d.ts +14 -0
  20. package/dist/lexer/helpers.d.ts.map +1 -0
  21. package/dist/lexer/helpers.js +30 -0
  22. package/dist/lexer/helpers.js.map +1 -0
  23. package/dist/lexer/index.d.ts +8 -0
  24. package/dist/lexer/index.d.ts.map +1 -0
  25. package/dist/lexer/index.js +8 -0
  26. package/dist/lexer/index.js.map +1 -0
  27. package/dist/lexer/operators.d.ts +11 -0
  28. package/dist/lexer/operators.d.ts.map +1 -0
  29. package/dist/lexer/operators.js +58 -0
  30. package/dist/lexer/operators.js.map +1 -0
  31. package/dist/lexer/readers.d.ts +12 -0
  32. package/dist/lexer/readers.d.ts.map +1 -0
  33. package/dist/lexer/readers.js +144 -0
  34. package/dist/lexer/readers.js.map +1 -0
  35. package/dist/lexer/state.d.ts +18 -0
  36. package/dist/lexer/state.d.ts.map +1 -0
  37. package/dist/lexer/state.js +37 -0
  38. package/dist/lexer/state.js.map +1 -0
  39. package/dist/lexer/tokenizer.d.ts +9 -0
  40. package/dist/lexer/tokenizer.d.ts.map +1 -0
  41. package/dist/lexer/tokenizer.js +100 -0
  42. package/dist/lexer/tokenizer.js.map +1 -0
  43. package/dist/lexer.d.ts +19 -0
  44. package/dist/lexer.d.ts.map +1 -0
  45. package/dist/lexer.js +344 -0
  46. package/dist/lexer.js.map +1 -0
  47. package/dist/parser/arithmetic.d.ts +16 -0
  48. package/dist/parser/arithmetic.d.ts.map +1 -0
  49. package/dist/parser/arithmetic.js +128 -0
  50. package/dist/parser/arithmetic.js.map +1 -0
  51. package/dist/parser/boolean.d.ts +15 -0
  52. package/dist/parser/boolean.d.ts.map +1 -0
  53. package/dist/parser/boolean.js +20 -0
  54. package/dist/parser/boolean.js.map +1 -0
  55. package/dist/parser/control-flow.d.ts +56 -0
  56. package/dist/parser/control-flow.d.ts.map +1 -0
  57. package/dist/parser/control-flow.js +167 -0
  58. package/dist/parser/control-flow.js.map +1 -0
  59. package/dist/parser/expressions.d.ts +23 -0
  60. package/dist/parser/expressions.d.ts.map +1 -0
  61. package/dist/parser/expressions.js +950 -0
  62. package/dist/parser/expressions.js.map +1 -0
  63. package/dist/parser/extraction.d.ts +48 -0
  64. package/dist/parser/extraction.d.ts.map +1 -0
  65. package/dist/parser/extraction.js +279 -0
  66. package/dist/parser/extraction.js.map +1 -0
  67. package/dist/parser/functions.d.ts +20 -0
  68. package/dist/parser/functions.d.ts.map +1 -0
  69. package/dist/parser/functions.js +96 -0
  70. package/dist/parser/functions.js.map +1 -0
  71. package/dist/parser/helpers.d.ts +94 -0
  72. package/dist/parser/helpers.d.ts.map +1 -0
  73. package/dist/parser/helpers.js +225 -0
  74. package/dist/parser/helpers.js.map +1 -0
  75. package/dist/parser/index.d.ts +49 -0
  76. package/dist/parser/index.d.ts.map +1 -0
  77. package/dist/parser/index.js +73 -0
  78. package/dist/parser/index.js.map +1 -0
  79. package/dist/parser/literals.d.ts +37 -0
  80. package/dist/parser/literals.d.ts.map +1 -0
  81. package/dist/parser/literals.js +373 -0
  82. package/dist/parser/literals.js.map +1 -0
  83. package/dist/parser/parser-collect.d.ts +16 -0
  84. package/dist/parser/parser-collect.d.ts.map +1 -0
  85. package/dist/parser/parser-collect.js +125 -0
  86. package/dist/parser/parser-collect.js.map +1 -0
  87. package/dist/parser/parser-control.d.ts +20 -0
  88. package/dist/parser/parser-control.d.ts.map +1 -0
  89. package/dist/parser/parser-control.js +120 -0
  90. package/dist/parser/parser-control.js.map +1 -0
  91. package/dist/parser/parser-expr.d.ts +37 -0
  92. package/dist/parser/parser-expr.d.ts.map +1 -0
  93. package/dist/parser/parser-expr.js +639 -0
  94. package/dist/parser/parser-expr.js.map +1 -0
  95. package/dist/parser/parser-extract.d.ts +17 -0
  96. package/dist/parser/parser-extract.d.ts.map +1 -0
  97. package/dist/parser/parser-extract.js +222 -0
  98. package/dist/parser/parser-extract.js.map +1 -0
  99. package/dist/parser/parser-functions.d.ts +21 -0
  100. package/dist/parser/parser-functions.d.ts.map +1 -0
  101. package/dist/parser/parser-functions.js +155 -0
  102. package/dist/parser/parser-functions.js.map +1 -0
  103. package/dist/parser/parser-literals.d.ts +22 -0
  104. package/dist/parser/parser-literals.d.ts.map +1 -0
  105. package/dist/parser/parser-literals.js +288 -0
  106. package/dist/parser/parser-literals.js.map +1 -0
  107. package/dist/parser/parser-script.d.ts +21 -0
  108. package/dist/parser/parser-script.d.ts.map +1 -0
  109. package/dist/parser/parser-script.js +174 -0
  110. package/dist/parser/parser-script.js.map +1 -0
  111. package/dist/parser/parser-variables.d.ts +20 -0
  112. package/dist/parser/parser-variables.d.ts.map +1 -0
  113. package/dist/parser/parser-variables.js +146 -0
  114. package/dist/parser/parser-variables.js.map +1 -0
  115. package/dist/parser/parser.d.ts +49 -0
  116. package/dist/parser/parser.d.ts.map +1 -0
  117. package/dist/parser/parser.js +54 -0
  118. package/dist/parser/parser.js.map +1 -0
  119. package/dist/parser/script.d.ts +14 -0
  120. package/dist/parser/script.d.ts.map +1 -0
  121. package/dist/parser/script.js +196 -0
  122. package/dist/parser/script.js.map +1 -0
  123. package/dist/parser/state.d.ts +40 -0
  124. package/dist/parser/state.d.ts.map +1 -0
  125. package/dist/parser/state.js +129 -0
  126. package/dist/parser/state.js.map +1 -0
  127. package/dist/parser/variables.d.ts +10 -0
  128. package/dist/parser/variables.d.ts.map +1 -0
  129. package/dist/parser/variables.js +215 -0
  130. package/dist/parser/variables.js.map +1 -0
  131. package/dist/runtime/ast-equals.d.ts +13 -0
  132. package/dist/runtime/ast-equals.d.ts.map +1 -0
  133. package/dist/runtime/ast-equals.js +447 -0
  134. package/dist/runtime/ast-equals.js.map +1 -0
  135. package/dist/runtime/builtins.d.ts +13 -0
  136. package/dist/runtime/builtins.d.ts.map +1 -0
  137. package/dist/runtime/builtins.js +180 -0
  138. package/dist/runtime/builtins.js.map +1 -0
  139. package/dist/runtime/callable.d.ts +88 -0
  140. package/dist/runtime/callable.d.ts.map +1 -0
  141. package/dist/runtime/callable.js +98 -0
  142. package/dist/runtime/callable.js.map +1 -0
  143. package/dist/runtime/context.d.ts +13 -0
  144. package/dist/runtime/context.d.ts.map +1 -0
  145. package/dist/runtime/context.js +73 -0
  146. package/dist/runtime/context.js.map +1 -0
  147. package/dist/runtime/core/callable.d.ts +171 -0
  148. package/dist/runtime/core/callable.d.ts.map +1 -0
  149. package/dist/runtime/core/callable.js +246 -0
  150. package/dist/runtime/core/callable.js.map +1 -0
  151. package/dist/runtime/core/context.d.ts +29 -0
  152. package/dist/runtime/core/context.d.ts.map +1 -0
  153. package/dist/runtime/core/context.js +154 -0
  154. package/dist/runtime/core/context.js.map +1 -0
  155. package/dist/runtime/core/equals.d.ts +9 -0
  156. package/dist/runtime/core/equals.d.ts.map +1 -0
  157. package/dist/runtime/core/equals.js +381 -0
  158. package/dist/runtime/core/equals.js.map +1 -0
  159. package/dist/runtime/core/eval/base.d.ts +65 -0
  160. package/dist/runtime/core/eval/base.d.ts.map +1 -0
  161. package/dist/runtime/core/eval/base.js +112 -0
  162. package/dist/runtime/core/eval/base.js.map +1 -0
  163. package/dist/runtime/core/eval/evaluator.d.ts +47 -0
  164. package/dist/runtime/core/eval/evaluator.d.ts.map +1 -0
  165. package/dist/runtime/core/eval/evaluator.js +73 -0
  166. package/dist/runtime/core/eval/evaluator.js.map +1 -0
  167. package/dist/runtime/core/eval/index.d.ts +57 -0
  168. package/dist/runtime/core/eval/index.d.ts.map +1 -0
  169. package/dist/runtime/core/eval/index.js +95 -0
  170. package/dist/runtime/core/eval/index.js.map +1 -0
  171. package/dist/runtime/core/eval/mixins/annotations.d.ts +19 -0
  172. package/dist/runtime/core/eval/mixins/annotations.d.ts.map +1 -0
  173. package/dist/runtime/core/eval/mixins/annotations.js +146 -0
  174. package/dist/runtime/core/eval/mixins/annotations.js.map +1 -0
  175. package/dist/runtime/core/eval/mixins/closures.d.ts +49 -0
  176. package/dist/runtime/core/eval/mixins/closures.d.ts.map +1 -0
  177. package/dist/runtime/core/eval/mixins/closures.js +479 -0
  178. package/dist/runtime/core/eval/mixins/closures.js.map +1 -0
  179. package/dist/runtime/core/eval/mixins/collections.d.ts +24 -0
  180. package/dist/runtime/core/eval/mixins/collections.d.ts.map +1 -0
  181. package/dist/runtime/core/eval/mixins/collections.js +466 -0
  182. package/dist/runtime/core/eval/mixins/collections.js.map +1 -0
  183. package/dist/runtime/core/eval/mixins/control-flow.d.ts +27 -0
  184. package/dist/runtime/core/eval/mixins/control-flow.d.ts.map +1 -0
  185. package/dist/runtime/core/eval/mixins/control-flow.js +369 -0
  186. package/dist/runtime/core/eval/mixins/control-flow.js.map +1 -0
  187. package/dist/runtime/core/eval/mixins/core.d.ts +24 -0
  188. package/dist/runtime/core/eval/mixins/core.d.ts.map +1 -0
  189. package/dist/runtime/core/eval/mixins/core.js +335 -0
  190. package/dist/runtime/core/eval/mixins/core.js.map +1 -0
  191. package/dist/runtime/core/eval/mixins/expressions.d.ts +19 -0
  192. package/dist/runtime/core/eval/mixins/expressions.d.ts.map +1 -0
  193. package/dist/runtime/core/eval/mixins/expressions.js +202 -0
  194. package/dist/runtime/core/eval/mixins/expressions.js.map +1 -0
  195. package/dist/runtime/core/eval/mixins/extraction.d.ts +10 -0
  196. package/dist/runtime/core/eval/mixins/extraction.d.ts.map +1 -0
  197. package/dist/runtime/core/eval/mixins/extraction.js +250 -0
  198. package/dist/runtime/core/eval/mixins/extraction.js.map +1 -0
  199. package/dist/runtime/core/eval/mixins/literals.d.ts +23 -0
  200. package/dist/runtime/core/eval/mixins/literals.d.ts.map +1 -0
  201. package/dist/runtime/core/eval/mixins/literals.js +180 -0
  202. package/dist/runtime/core/eval/mixins/literals.js.map +1 -0
  203. package/dist/runtime/core/eval/mixins/types.d.ts +20 -0
  204. package/dist/runtime/core/eval/mixins/types.d.ts.map +1 -0
  205. package/dist/runtime/core/eval/mixins/types.js +109 -0
  206. package/dist/runtime/core/eval/mixins/types.js.map +1 -0
  207. package/dist/runtime/core/eval/mixins/variables.d.ts +34 -0
  208. package/dist/runtime/core/eval/mixins/variables.d.ts.map +1 -0
  209. package/dist/runtime/core/eval/mixins/variables.js +247 -0
  210. package/dist/runtime/core/eval/mixins/variables.js.map +1 -0
  211. package/dist/runtime/core/eval/types.d.ts +41 -0
  212. package/dist/runtime/core/eval/types.d.ts.map +1 -0
  213. package/dist/runtime/core/eval/types.js +10 -0
  214. package/dist/runtime/core/eval/types.js.map +1 -0
  215. package/dist/runtime/core/evaluate.d.ts +42 -0
  216. package/dist/runtime/core/evaluate.d.ts.map +1 -0
  217. package/dist/runtime/core/evaluate.debug.js +1251 -0
  218. package/dist/runtime/core/evaluate.js +1913 -0
  219. package/dist/runtime/core/evaluate.js.map +1 -0
  220. package/dist/runtime/core/execute.d.ts +26 -0
  221. package/dist/runtime/core/execute.d.ts.map +1 -0
  222. package/dist/runtime/core/execute.js +177 -0
  223. package/dist/runtime/core/execute.js.map +1 -0
  224. package/dist/runtime/core/signals.d.ts +19 -0
  225. package/dist/runtime/core/signals.d.ts.map +1 -0
  226. package/dist/runtime/core/signals.js +26 -0
  227. package/dist/runtime/core/signals.js.map +1 -0
  228. package/dist/runtime/core/types.d.ts +177 -0
  229. package/dist/runtime/core/types.d.ts.map +1 -0
  230. package/dist/runtime/core/types.js +50 -0
  231. package/dist/runtime/core/types.js.map +1 -0
  232. package/dist/runtime/core/values.d.ts +66 -0
  233. package/dist/runtime/core/values.d.ts.map +1 -0
  234. package/dist/runtime/core/values.js +240 -0
  235. package/dist/runtime/core/values.js.map +1 -0
  236. package/dist/runtime/evaluate.d.ts +32 -0
  237. package/dist/runtime/evaluate.d.ts.map +1 -0
  238. package/dist/runtime/evaluate.js +1111 -0
  239. package/dist/runtime/evaluate.js.map +1 -0
  240. package/dist/runtime/execute.d.ts +26 -0
  241. package/dist/runtime/execute.d.ts.map +1 -0
  242. package/dist/runtime/execute.js +121 -0
  243. package/dist/runtime/execute.js.map +1 -0
  244. package/dist/runtime/ext/builtins.d.ts +16 -0
  245. package/dist/runtime/ext/builtins.d.ts.map +1 -0
  246. package/dist/runtime/ext/builtins.js +528 -0
  247. package/dist/runtime/ext/builtins.js.map +1 -0
  248. package/dist/runtime/ext/content-parser.d.ts +83 -0
  249. package/dist/runtime/ext/content-parser.d.ts.map +1 -0
  250. package/dist/runtime/ext/content-parser.js +536 -0
  251. package/dist/runtime/ext/content-parser.js.map +1 -0
  252. package/dist/runtime/index.d.ts +28 -0
  253. package/dist/runtime/index.d.ts.map +1 -0
  254. package/dist/runtime/index.js +34 -0
  255. package/dist/runtime/index.js.map +1 -0
  256. package/dist/runtime/signals.d.ts +19 -0
  257. package/dist/runtime/signals.d.ts.map +1 -0
  258. package/dist/runtime/signals.js +26 -0
  259. package/dist/runtime/signals.js.map +1 -0
  260. package/dist/runtime/types.d.ts +169 -0
  261. package/dist/runtime/types.d.ts.map +1 -0
  262. package/dist/runtime/types.js +50 -0
  263. package/dist/runtime/types.js.map +1 -0
  264. package/dist/runtime/values.d.ts +50 -0
  265. package/dist/runtime/values.d.ts.map +1 -0
  266. package/dist/runtime/values.js +209 -0
  267. package/dist/runtime/values.js.map +1 -0
  268. package/dist/runtime.d.ts +254 -0
  269. package/dist/runtime.d.ts.map +1 -0
  270. package/dist/runtime.js +2014 -0
  271. package/dist/runtime.js.map +1 -0
  272. package/dist/types.d.ts +752 -0
  273. package/dist/types.d.ts.map +1 -0
  274. package/dist/types.js +189 -0
  275. package/dist/types.js.map +1 -0
  276. package/docs/00_INDEX.md +65 -0
  277. package/docs/01_guide.md +390 -0
  278. package/docs/02_types.md +399 -0
  279. package/docs/03_variables.md +314 -0
  280. package/docs/04_operators.md +551 -0
  281. package/docs/05_control-flow.md +350 -0
  282. package/docs/06_closures.md +353 -0
  283. package/docs/07_collections.md +686 -0
  284. package/docs/08_iterators.md +330 -0
  285. package/docs/09_strings.md +205 -0
  286. package/docs/10_parsing.md +366 -0
  287. package/docs/11_reference.md +350 -0
  288. package/docs/12_examples.md +771 -0
  289. package/docs/13_modules.md +519 -0
  290. package/docs/14_host-integration.md +826 -0
  291. package/docs/15_grammar.ebnf +693 -0
  292. package/docs/16_conventions.md +696 -0
  293. package/docs/99_llm-reference.txt +300 -0
  294. package/docs/assets/logo.png +0 -0
  295. 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.*