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