@rcrsr/rill 0.7.1 → 0.8.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 (73) hide show
  1. package/README.md +1 -1
  2. package/dist/ast-nodes.d.ts +635 -0
  3. package/dist/ast-nodes.d.ts.map +1 -0
  4. package/dist/ast-nodes.js +2 -0
  5. package/dist/ast-nodes.js.map +1 -0
  6. package/dist/ast-unions.d.ts +6 -0
  7. package/dist/ast-unions.d.ts.map +1 -0
  8. package/dist/ast-unions.js +6 -0
  9. package/dist/ast-unions.js.map +1 -0
  10. package/dist/error-classes.d.ts +90 -0
  11. package/dist/error-classes.d.ts.map +1 -0
  12. package/dist/error-classes.js +185 -0
  13. package/dist/error-classes.js.map +1 -0
  14. package/dist/error-registry.d.ts +93 -0
  15. package/dist/error-registry.d.ts.map +1 -0
  16. package/dist/error-registry.js +712 -0
  17. package/dist/error-registry.js.map +1 -0
  18. package/dist/generated/introspection-data.d.ts +1 -1
  19. package/dist/generated/introspection-data.d.ts.map +1 -1
  20. package/dist/generated/introspection-data.js +509 -481
  21. package/dist/generated/introspection-data.js.map +1 -1
  22. package/dist/generated/version-data.d.ts +1 -1
  23. package/dist/generated/version-data.js +3 -3
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +1 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/parser/parser-expr.js +9 -6
  29. package/dist/parser/parser-expr.js.map +1 -1
  30. package/dist/runtime/core/callable.d.ts +5 -5
  31. package/dist/runtime/core/callable.d.ts.map +1 -1
  32. package/dist/runtime/core/callable.js +2 -1
  33. package/dist/runtime/core/callable.js.map +1 -1
  34. package/dist/runtime/core/eval/mixins/collections.d.ts.map +1 -1
  35. package/dist/runtime/core/eval/mixins/collections.js +5 -1
  36. package/dist/runtime/core/eval/mixins/collections.js.map +1 -1
  37. package/dist/runtime/core/eval/mixins/literals.d.ts.map +1 -1
  38. package/dist/runtime/core/eval/mixins/literals.js +5 -1
  39. package/dist/runtime/core/eval/mixins/literals.js.map +1 -1
  40. package/dist/runtime/core/eval/mixins/variables.js +12 -12
  41. package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
  42. package/dist/runtime/core/values.d.ts +31 -3
  43. package/dist/runtime/core/values.d.ts.map +1 -1
  44. package/dist/runtime/core/values.js +47 -1
  45. package/dist/runtime/core/values.js.map +1 -1
  46. package/dist/runtime/ext/builtins.d.ts.map +1 -1
  47. package/dist/runtime/ext/builtins.js +202 -1
  48. package/dist/runtime/ext/builtins.js.map +1 -1
  49. package/dist/runtime/ext/extensions.d.ts +39 -3
  50. package/dist/runtime/ext/extensions.d.ts.map +1 -1
  51. package/dist/runtime/ext/extensions.js +77 -12
  52. package/dist/runtime/ext/extensions.js.map +1 -1
  53. package/dist/runtime/index.d.ts +5 -5
  54. package/dist/runtime/index.d.ts.map +1 -1
  55. package/dist/runtime/index.js +2 -2
  56. package/dist/runtime/index.js.map +1 -1
  57. package/dist/source-location.d.ts +10 -0
  58. package/dist/source-location.d.ts.map +1 -0
  59. package/dist/source-location.js +5 -0
  60. package/dist/source-location.js.map +1 -0
  61. package/dist/token-types.d.ts +68 -0
  62. package/dist/token-types.d.ts.map +1 -0
  63. package/dist/token-types.js +79 -0
  64. package/dist/token-types.js.map +1 -0
  65. package/dist/types.d.ts +9 -882
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/types.js +8 -958
  68. package/dist/types.js.map +1 -1
  69. package/dist/value-types.d.ts +3 -0
  70. package/dist/value-types.d.ts.map +1 -0
  71. package/dist/value-types.js +2 -0
  72. package/dist/value-types.js.map +1 -0
  73. package/package.json +15 -2
@@ -1,538 +1,566 @@
1
1
  // AUTO-GENERATED - DO NOT EDIT
2
2
  // Generated by packages/core/scripts/generate-docs-bundle.ts from docs/ref-llm.txt
3
- export const LANGUAGE_REFERENCE = `RILL LANGUAGE REFERENCE
4
- =======================
5
-
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
3
+ export const LANGUAGE_REFERENCE = `# rill
4
+
5
+ > Scripting language designed for machine-generated code. LLMs generate rill scripts; humans review and debug. Data flows through pipes (\`->\`), not assignment. Variables use \`\$\` prefix. No null, no exceptions, no truthiness.
6
+
7
+ ## Documentation
8
+
9
+ - [Getting Started](https://rill.run/docs/guide/getting-started/): Beginner-friendly introduction to rill
10
+ - [Language Reference](https://rill.run/docs/reference/language/): Core language specification
11
+ - [Examples](https://rill.run/docs/guide/examples/): Workflow patterns and use cases
12
+ - [Cookbook](https://rill.run/docs/guide/cookbook/): Advanced agent scripting patterns
13
+ - [Types](https://rill.run/docs/language/types/): Primitives, tuples, dicts, type assertions
14
+ - [Variables](https://rill.run/docs/language/variables/): Declaration, scope rules, \`\$\` binding
15
+ - [Control Flow](https://rill.run/docs/language/control-flow/): Conditionals, loops, break/return
16
+ - [Operators](https://rill.run/docs/language/operators/): Arithmetic, comparison, spread, extraction
17
+ - [Closures](https://rill.run/docs/language/closures/): Late binding, dict-bound closures
18
+ - [Collections](https://rill.run/docs/data/collections/): \`each\`, \`map\`, \`filter\`, \`fold\` operators
19
+ - [Iterators](https://rill.run/docs/data/iterators/): Lazy sequences with \`range\`, \`repeat\`, \`.first()\`
20
+ - [Strings](https://rill.run/docs/data/strings/): String methods for text manipulation
21
+ - [Host Integration](https://rill.run/docs/integration/host/): Embedding rill in applications
22
+ - [Host API Reference](https://rill.run/docs/reference/host-api/): Complete TypeScript API exports
23
+ - [Developing Extensions](https://rill.run/docs/integration/extensions/): Writing reusable host function packages
24
+ - [Modules](https://rill.run/docs/integration/modules/): Convention for host-provided module systems
25
+ - [CLI Tools](https://rill.run/docs/integration/cli/): \`rill-exec\`, \`rill-eval\`, \`rill-check\` commands
26
+ - [Error Reference](https://rill.run/docs/reference/errors/): Error codes and resolution
27
+
28
+ ## Essentials
29
+
30
+ 1. Variables use \`\$\` prefix ALWAYS: \`5 => \$x\` (no assignment operator \`=\`)
31
+ 2. Pipe with \`->\`, capture with \`=>\`: \`"hello" => \$x -> .upper => \$y\`
13
32
  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
33
+ 4. Variables lock to first type: \`"hi" => \$x; 42 => \$x\` is an ERROR
34
+ 5. Loops cannot modify outer vars: use \`fold\`, \`each(init)\`, or \`\$\` as state dict
35
+
36
+ ## Strengths and Use Cases
16
37
 
17
- STRENGTHS AND USE CASES
18
- -----------------------
19
38
  Strengths:
20
- - Unambiguous syntax: \$ prefix, explicit operators, no implicit coercion
21
- - Single-pass parseable: LLMs generate correct code without symbol tables
22
- - Readable by humans: pipe chains show data flow left-to-right
23
- - Safe defaults: immutable values, type locking, no null/undefined
39
+ - Unambiguous syntax: \`\$\` prefix, explicit operators, no implicit coercion
40
+ - Single-pass parseable: LLMs generate correct code without symbol tables
41
+ - Readable by humans: pipe chains show data flow left-to-right
42
+ - Safe defaults: immutable values, type locking, no null/undefined
24
43
 
25
44
  Use cases:
26
- - Workflow orchestration: chain LLM calls, API requests, transformations
27
- - State machines: (cond) @ { } loops with \$ as state dict
28
- - Data pipelines: each/map/filter/fold process collections declaratively
29
-
30
- State machine pattern (\$ carries state through iterations):
31
- [state: "init", data: \$input]
32
- -> (\$.state != "done") @ {
33
- \$.state -> [
34
- init: { [state: "process", data: transform(\$.data)] },
35
- process: { [state: "done", data: finalize(\$.data)] }
36
- ]
37
- }
38
-
39
- NAMING CONVENTION: snake_case
40
- -----------------------------
45
+ - Workflow orchestration: chain LLM calls, API requests, transformations
46
+ - State machines: \`(cond) @ { }\` loops with \`\$\` as state dict
47
+ - Data pipelines: \`each\`/\`map\`/\`filter\`/\`fold\` process collections declaratively
48
+
49
+ State machine pattern (\`\$\` carries state through iterations):
50
+
51
+ [state: "init", data: \$input]
52
+ -> (\$.state != "done") @ {
53
+ \$.state -> [
54
+ init: { [state: "process", data: transform(\$.data)] },
55
+ process: { [state: "done", data: finalize(\$.data)] }
56
+ ]
57
+ }
58
+
59
+ ## Naming Convention: snake_case
60
+
41
61
  Use snake_case for all identifiers:
42
- \$user_name, \$item_list, \$is_valid # variables
43
- \$double_value, \$cleanup_text # closures
44
- [first_name: "x", last_name: "y"] # dict keys
45
-
46
- WHY VARIABLES USE \$ PREFIX
47
- --------------------------
48
- The \$ prefix enables single-pass parsing without a symbol table:
49
-
50
- name() -> host function call
51
- \$name() -> closure invocation
52
- \$name -> variable reference
53
- name -> dict key literal
54
-
55
- Without \$, "process(data)" is ambiguous: is process a host function or stored
56
- closure? Is data a variable or key? This would require tracking all declarations.
57
-
58
- SPACING RULES
59
- -------------
60
- Operators: space both sides 5 + 3, \$x -> .upper, "a" => \$b
61
- Parentheses: no inner space (\$x + 1), (\$ > 3) ? "yes"
62
- Braces: space inside { \$x + 1 }, each { \$ * 2 }
63
- Brackets: no inner space \$list[0], \$dict.items[1]
64
- Literals: space after , and : [1, 2, 3], [name: "x", age: 30]
65
- Closures: space after params |x| (\$x * 2), |a, b| { \$a + \$b }
66
- Methods: no space before . or ( \$str.upper(), \$list.join(", ")
67
- Pipes: space both sides "x" -> .upper -> .len
68
- Continuations: indent 2 spaces \$data
69
- -> .filter { \$.active }
70
- -> map { \$.name }
71
-
72
- IMPLICIT \$ SHORTHAND (always prefer)
73
- ------------------------------------
74
- \$.method() -> .method "x" -> .upper (not \$.upper())
75
- func(\$) -> func "x" -> log (not log(\$))
76
- \$fn(\$) -> \$fn 5 -> \$double (not \$double(\$))
77
-
78
- Don't capture just to continue - use line continuation instead:
79
- # avoid # good
80
- "x" => \$a "x"
81
- \$a -> .upper => \$b -> .upper
82
- \$b -> .len -> .len
62
+
63
+ \$user_name, \$item_list, \$is_valid # variables
64
+ \$double_value, \$cleanup_text # closures
65
+ [first_name: "x", last_name: "y"] # dict keys
66
+
67
+ ## Why Variables Use \$ Prefix
68
+
69
+ The \`\$\` prefix enables single-pass parsing without a symbol table:
70
+
71
+ name() -> host function call
72
+ \$name() -> closure invocation
73
+ \$name -> variable reference
74
+ name -> dict key literal
75
+
76
+ Without \`\$\`, \`process(data)\` is ambiguous: is \`process\` a host function or stored closure? Is \`data\` a variable or key? This would require tracking all declarations.
77
+
78
+ ## Spacing Rules
79
+
80
+ Operators: space both sides 5 + 3, \$x -> .upper, "a" => \$b
81
+ Parentheses: no inner space (\$x + 1), (\$ > 3) ? "yes"
82
+ Braces: space inside { \$x + 1 }, each { \$ * 2 }
83
+ Brackets: no inner space \$list[0], \$dict.items[1]
84
+ Literals: space after , and : [1, 2, 3], [name: "x", age: 30]
85
+ Closures: space after params |x| (\$x * 2), |a, b| { \$a + \$b }
86
+ Methods: no space before . or ( \$str.upper(), \$list.join(", ")
87
+ Pipes: space both sides "x" -> .upper -> .len
88
+ Continuations: indent 2 spaces \$data
89
+ -> .filter { \$.active }
90
+ -> map { \$.name }
91
+
92
+ ## Implicit \$ Shorthand (Always Prefer)
93
+
94
+ \$.method() -> .method "x" -> .upper (not \$.upper())
95
+ func(\$) -> func "x" -> log (not log(\$))
96
+ \$fn(\$) -> \$fn 5 -> \$double (not \$double(\$))
97
+
98
+ Don't capture just to continue use line continuation instead:
99
+
100
+ # avoid # good
101
+ "x" => \$a "x"
102
+ \$a -> .upper => \$b -> .upper
103
+ \$b -> .len -> .len
83
104
 
84
105
  Only capture when the variable is reused later in the code.
85
106
 
86
- CRITICAL DIFFERENCES FROM MAINSTREAM LANGUAGES
87
- ----------------------------------------------
88
-
89
- 1. NO ASSIGNMENT OPERATOR
90
- Wrong: x = 5 Mainstream: x = value
91
- Right: 5 => \$x rill: value => \$x
92
-
93
- Pipe (->): passes value to next operation
94
- Capture (=>): stores value AND continues chain
95
- Example: "hello" => \$x -> .upper => \$y # \$x="hello", \$y="HELLO"
96
-
97
- 2. NO NULL/UNDEFINED
98
- Empty values ("", [], [:]) exist. "No value" cannot be represented.
99
- Use ?? for defaults: \$dict.field ?? "default"
100
- Use .empty to check: \$str -> .empty ? "was empty"
101
- Mainstream: null/undefined rill: ?? default, .? existence check
102
-
103
- 3. NO TRUTHINESS
104
- Conditions MUST be boolean. No implicit coercion.
105
- Wrong: "" ? "yes" ! "no" Right: "" -> .empty ? "yes" ! "no"
106
- Wrong: 0 ? "yes" ! "no" Right: (0 == 0) ? "yes" ! "no"
107
- Negation (!) also requires boolean:
108
- Right: !true # false
109
- Right: "hello" -> .empty -> (!\$) # true (negates boolean from .empty)
110
- Wrong: !"hello" # ERROR: Negation requires boolean
111
- Mainstream: if "" / if 0 rill: .empty, == 0, :?type
112
-
113
- 4. VARIABLES LOCK TO FIRST TYPE
114
- "hello" => \$x
115
- 42 => \$x # ERROR: cannot assign number to string variable
116
-
117
- 5. NO VARIABLE SHADOWING (CRITICAL FOR LOOPS)
118
- Child scopes can READ parent variables but cannot WRITE or redeclare them.
119
- Variables created inside blocks/loops do NOT leak out.
120
-
121
- WRONG - outer variable modification (NEVER works):
122
- 0 => \$count
123
- [1, 2, 3] -> each { \$count + 1 => \$count } # creates LOCAL \$count
124
- \$count # still 0!
125
-
126
- WRONG - "while" keyword does not exist:
127
- while (\$i < 10) { \$i + 1 => \$i } # SYNTAX ERROR
128
-
129
- RIGHT - use fold for reduction:
130
- [1, 2, 3] -> fold(0) { \$@ + \$ } # 6 (\$@ is accumulator)
131
-
132
- RIGHT - use each(init) for results AND accumulator:
133
- [1, 2, 3] -> each(0) { \$@ + \$ } # [1, 3, 6] (running totals)
134
-
135
- RIGHT - use (cond) @ { } with \$ as state dict for multiple values:
136
- [iter: 0, max: 3, text: \$input, done: false]
137
- -> (!\$.done && \$.iter < \$.max) @ {
138
- \$.iter + 1 => \$i
139
- process(\$.text) => \$result
140
- \$result.finished ? [iter: \$i, max: \$.max, text: \$.text, done: true]
141
- ! [iter: \$i, max: \$.max, text: \$result.text, done: false]
142
- }
143
-
144
- Pattern summary:
145
- Single value accumulation -> fold(init) { \$@ + \$ }
146
- Per-item results + running -> each(init) { ... \$@ ... }
147
- Multiple state values / while -> (cond) @ { } with \$ as state dict
148
- "while" and "for" keywords -> DO NOT EXIST
149
- Mainstream: count += 1 in loop rill: fold(0) { \$@ + 1 } or \$ accumulator
150
-
151
- 6. NO EXCEPTIONS
152
- Errors halt execution. No try/catch. Use conditionals for error handling.
153
- Built-in: assert (validate condition), error (halt with message).
154
- Mainstream: try { } catch { } rill: assert, conditionals, error
155
-
156
- 7. VALUE SEMANTICS (no references)
157
- All copies are deep. All comparisons are by value. No object identity.
158
- [1, 2, 3] == [1, 2, 3] # true (content equality)
159
- [1, 2] => \$a
160
- \$a => \$b # \$b is an independent deep copy
161
- Mainstream: a === b (reference) rill: == always compares by value
162
- Mainstream: a = b (shared ref) rill: => always deep-copies
163
-
164
- SYNTAX QUICK REFERENCE
165
- ----------------------
166
-
167
- Variables: \$name (always prefixed with \$)
168
- Strings: "hello {\$var}" # interpolation with {}
169
- """...""" # multiline (also interpolates)
170
- Numbers: 42, 3.14, -7
171
- Booleans: true, false
172
- Lists: [1, 2, 3]
173
- [...\$list, 4] # spread: inline list elements
174
- Dicts: [name: "alice", age: 30] # identifier keys
175
- [1: "one", 2: "two"] # number keys (incl. negative: [-1: "neg"])
176
- [true: "yes", false: "no"] # boolean keys
177
- [["a", "b"]: 1] # multi-key: [a: 1, b: 1]
178
- [\$keyVar: value] # variable key (must eval to string)
179
- [(\$expr): value] # computed key (must eval to string)
180
- Tuples: *[1, 2, 3] # for argument unpacking
181
- Closures: |x|(\$x + 1) # like lambda/arrow functions
182
- Type annot: "hi" => \$x:string # lock type on capture
183
- Comments: # single line only
184
-
185
- PIPES AND \$ BINDING
186
- -------------------
187
-
188
- \$ is the current piped value. Its meaning depends on context:
189
-
190
- | Context | \$ contains |
191
- |----------------------------|-------------------------|
192
- | -> { body } | piped value |
193
- | -> each { } | current item |
194
- | (cond) @ { } | accumulated value |
195
- | @ { } ? cond | accumulated value |
196
- | cond ? { } ! { } | tested value |
197
- | -> ? { } ! { } | piped value |
198
- | ||{ \$.field } in dict | the containing dict |
199
- | |x|{ } stored closure | N/A - use parameters |
200
-
201
- Implied \$: bare .method() means \$ -> .method()
202
- Example: "hello" -> .upper # same as "hello" -> \$.upper()
203
-
204
- CONTROL FLOW
205
- ------------
107
+ ## Critical Differences from Mainstream Languages
108
+
109
+ ### 1. No Assignment Operator
110
+
111
+ Wrong: x = 5 Mainstream: x = value
112
+ Right: 5 => \$x rill: value => \$x
113
+
114
+ Pipe (\`->\`): passes value to next operation.
115
+ Capture (\`=>\`): stores value AND continues chain.
116
+ Example: \`"hello" => \$x -> .upper => \$y\` — \`\$x="hello"\`, \`\$y="HELLO"\`.
117
+
118
+ ### 2. No Null/Undefined
119
+
120
+ Empty values (\`""\`, \`[]\`, \`[:]\`) exist. "No value" cannot be represented.
121
+ Use \`??\` for defaults: \`\$dict.field ?? "default"\`.
122
+ Use \`.empty\` to check: \`\$str -> .empty ? "was empty"\`.
123
+
124
+ ### 3. No Truthiness
125
+
126
+ Conditions MUST be boolean. No implicit coercion.
127
+
128
+ Wrong: "" ? "yes" ! "no" Right: "" -> .empty ? "yes" ! "no"
129
+ Wrong: 0 ? "yes" ! "no" Right: (0 == 0) ? "yes" ! "no"
130
+
131
+ Negation (\`!\`) also requires boolean:
132
+
133
+ !true # false
134
+ "hello" -> .empty -> (!\$) # true (negates boolean from .empty)
135
+ !"hello" # ERROR: Negation requires boolean
136
+
137
+ ### 4. Variables Lock to First Type
138
+
139
+ "hello" => \$x
140
+ 42 => \$x # ERROR: cannot assign number to string variable
141
+
142
+ ### 5. No Variable Shadowing (Critical for Loops)
143
+
144
+ Child scopes can READ parent variables but cannot WRITE or redeclare them.
145
+ Variables created inside blocks/loops do NOT leak out.
146
+
147
+ WRONG outer variable modification (NEVER works):
148
+
149
+ 0 => \$count
150
+ [1, 2, 3] -> each { \$count + 1 => \$count } # creates LOCAL \$count
151
+ \$count # still 0!
152
+
153
+ RIGHT use \`fold\` for reduction:
154
+
155
+ [1, 2, 3] -> fold(0) { \$@ + \$ } # 6 (\$@ is accumulator)
156
+
157
+ RIGHT use \`each(init)\` for results AND accumulator:
158
+
159
+ [1, 2, 3] -> each(0) { \$@ + \$ } # [1, 3, 6] (running totals)
160
+
161
+ RIGHT use \`(cond) @ { }\` with \`\$\` as state dict for multiple values:
162
+
163
+ [iter: 0, max: 3, text: \$input, done: false]
164
+ -> (!\$.done && \$.iter < \$.max) @ {
165
+ \$.iter + 1 => \$i
166
+ process(\$.text) => \$result
167
+ \$result.finished ? [iter: \$i, max: \$.max, text: \$.text, done: true]
168
+ ! [iter: \$i, max: \$.max, text: \$result.text, done: false]
169
+ }
170
+
171
+ Pattern summary:
172
+
173
+ Single value accumulation -> fold(init) { \$@ + \$ }
174
+ Per-item results + running -> each(init) { ... \$@ ... }
175
+ Multiple state values / while -> (cond) @ { } with \$ as state dict
176
+ "while" and "for" keywords -> DO NOT EXIST
177
+
178
+ ### 6. No Exceptions
179
+
180
+ Errors halt execution. No try/catch. Use conditionals for error handling.
181
+ Built-in: \`assert\` (validate condition), \`error\` (halt with message).
182
+
183
+ ### 7. Value Semantics (No References)
184
+
185
+ All copies are deep. All comparisons are by value. No object identity.
186
+
187
+ [1, 2, 3] == [1, 2, 3] # true (content equality)
188
+ [1, 2] => \$a
189
+ \$a => \$b # \$b is an independent deep copy
190
+
191
+ ## Syntax Quick Reference
192
+
193
+ Variables: \$name (always prefixed with \$)
194
+ Strings: "hello {\$var}" # interpolation with {}
195
+ """...""" # multiline (also interpolates)
196
+ Numbers: 42, 3.14, -7
197
+ Booleans: true, false
198
+ Lists: [1, 2, 3]
199
+ [...\$list, 4] # spread: inline list elements
200
+ Dicts: [name: "alice", age: 30] # identifier keys
201
+ [1: "one", 2: "two"] # number keys (incl. negative: [-1: "neg"])
202
+ [true: "yes", false: "no"] # boolean keys
203
+ [["a", "b"]: 1] # multi-key: [a: 1, b: 1]
204
+ [\$keyVar: value] # variable key (must eval to string)
205
+ [(\$expr): value] # computed key (must eval to string)
206
+ Tuples: *[1, 2, 3] # for argument unpacking
207
+ Closures: |x|(\$x + 1) # like lambda/arrow functions
208
+ Type annot: "hi" => \$x:string # lock type on capture
209
+ Comments: # single line only
210
+
211
+ ## Pipes and \$ Binding
212
+
213
+ \`\$\` is the current piped value. Its meaning depends on context:
214
+
215
+ | Context | \`\$\` contains |
216
+ |---|---|
217
+ | \`-> { body }\` | piped value |
218
+ | \`-> each { }\` | current item |
219
+ | \`(cond) @ { }\` | accumulated value |
220
+ | \`@ { } ? cond\` | accumulated value |
221
+ | \`cond ? { } ! { }\` | tested value |
222
+ | \`-> ? { } ! { }\` | piped value |
223
+ | \`\\|\\|{ \$.field }\` in dict | the containing dict |
224
+ | \`\\|x\\|{ }\` stored closure | N/A — use parameters |
225
+
226
+ Implied \`\$\`: bare \`.method()\` means \`\$ -> .method()\`.
227
+ Example: \`"hello" -> .upper\` is the same as \`"hello" -> \$.upper()\`.
228
+
229
+ ## Control Flow
206
230
 
207
231
  Conditional (if-else):
208
- cond ? then_expr ! else_expr
209
- cond ? then_expr # else returns ""
210
-
211
- Piped conditional (\$ becomes condition):
212
- value -> ? then_expr ! else_expr
213
-
214
- Multi-line conditionals (? and ! work as line continuations):
215
- condition
216
- ? "yes"
217
- ! "no"
218
- value -> is_valid
219
- ? "ok"
220
- ! "error"
221
- \$val -> .eq("A") ? "a"
222
- ! .eq("B") ? "b"
223
- ! "c"
224
-
225
- Condition loop (NO "while" keyword - use @ operator):
226
- init_value -> (\$ < 10) @ { \$ + 1 } # \$ is accumulator
232
+
233
+ cond ? then_expr ! else_expr
234
+ cond ? then_expr # else returns ""
235
+
236
+ Piped conditional (\`\$\` becomes condition):
237
+
238
+ value -> ? then_expr ! else_expr
239
+
240
+ Multi-line conditionals (\`?\` and \`!\` work as line continuations):
241
+
242
+ condition
243
+ ? "yes"
244
+ ! "no"
245
+ value -> is_valid
246
+ ? "ok"
247
+ ! "error"
248
+ \$val -> .eq("A") ? "a"
249
+ ! .eq("B") ? "b"
250
+ ! "c"
251
+
252
+ Condition loop (NO \`while\` keyword — use \`@\` operator):
253
+
254
+ init_value -> (\$ < 10) @ { \$ + 1 } # \$ is accumulator
227
255
 
228
256
  Do-condition loop (body runs at least once):
229
- init_value -> @ { \$ + 1 } ? (\$ < 10)
257
+
258
+ init_value -> @ { \$ + 1 } ? (\$ < 10)
230
259
 
231
260
  Break (exits loop, returns collected results before break):
232
- [1,2,3,4,5] -> each { (\$ == 3) ? break; \$ } # returns [1, 2]
261
+
262
+ [1,2,3,4,5] -> each { (\$ == 3) ? break; \$ } # returns [1, 2]
233
263
 
234
264
  Return (exits block or script with value):
235
- { 5 => \$x; (\$x > 3) ? ("big" -> return); "small" } # returns "big"
236
- "done" -> return # exits script with "done"
265
+
266
+ { 5 => \$x; (\$x > 3) ? ("big" -> return); "small" } # returns "big"
267
+ "done" -> return # exits script with "done"
237
268
 
238
269
  Assert (validate condition, halt if false, pass through if true):
239
- 5 -> assert (\$ > 0) # returns 5
240
- -1 -> assert (\$ > 0) # ERROR: Assertion failed
241
- "" -> assert !.empty "Input required" # ERROR: Input required
242
- \$val -> assert \$:?list "Expected list" # type validation
270
+
271
+ 5 -> assert (\$ > 0) # returns 5
272
+ -1 -> assert (\$ > 0) # ERROR: Assertion failed
273
+ "" -> assert !.empty "Input required" # ERROR: Input required
274
+ \$val -> assert \$:?list "Expected list" # type validation
243
275
 
244
276
  Error (halt execution immediately with message):
245
- error "Something went wrong" # halt with message
246
- "Operation failed" -> error # piped form (must be string)
247
- error "Status: {\$code}" # interpolation works
248
-
249
- Pass (returns \$ unchanged, explicit no-op):
250
- cond ? pass ! "fallback" # preserve \$ when condition true
251
- cond ? "value" ! pass # preserve \$ when condition false
252
- "data" -> { [status: pass] } # include \$ in dict: [status: "data"]
253
- [1, -2, 3] -> map { (\$ > 0) ? pass ! 0 } # [1, 0, 3]
254
- Note: pass requires pipe context. Using pass without \$ throws error.
255
-
256
- COLLECTION OPERATORS
257
- --------------------
258
-
259
- | Operator | Execution | Returns | Break? |
260
- |--------------------|------------|----------------------|--------|
261
- | -> each { } | sequential | all body results | yes |
262
- | -> each(i) { \$@+\$} | sequential | all with accumulator | yes |
263
- | -> map { } | parallel | all body results | NO |
264
- | -> filter { } | parallel | matching elements | NO |
265
- | -> fold(i) { \$@+\$} | sequential | final result only | yes |
266
-
267
- \$@ is the accumulator in each(init) and fold(init).
277
+
278
+ error "Something went wrong" # halt with message
279
+ "Operation failed" -> error # piped form (must be string)
280
+ error "Status: {\$code}" # interpolation works
281
+
282
+ Pass (returns \`\$\` unchanged, explicit no-op):
283
+
284
+ cond ? pass ! "fallback" # preserve \$ when condition true
285
+ cond ? "value" ! pass # preserve \$ when condition false
286
+ "data" -> { [status: pass] } # include \$ in dict: [status: "data"]
287
+ [1, -2, 3] -> map { (\$ > 0) ? pass ! 0 } # [1, 0, 3]
288
+
289
+ Note: \`pass\` requires pipe context. Using \`pass\` without \`\$\` throws error.
290
+
291
+ ## Collection Operators
292
+
293
+ | Operator | Execution | Returns | Break? |
294
+ |---|---|---|---|
295
+ | \`-> each { }\` | sequential | all body results | yes |
296
+ | \`-> each(i) { \$@ + \$ }\` | sequential | all with accumulator | yes |
297
+ | \`-> map { }\` | parallel | all body results | NO |
298
+ | \`-> filter { }\` | parallel | matching elements | NO |
299
+ | \`-> fold(i) { \$@ + \$ }\` | sequential | final result only | yes |
300
+
301
+ \`\$@\` is the accumulator in \`each(init)\` and \`fold(init)\`.
268
302
 
269
303
  Method shorthand in collection operators:
270
- ["a", "b"] -> map .upper # ["A", "B"]
271
- ["", "x"] -> filter (!.empty) # ["x"]
272
- ["a", "b"] -> map .pad_start(3, "0") # ["00a", "00b"] (with args)
273
- [" HI "] -> map .trim.lower # ["hi"] (chained methods)
304
+
305
+ ["a", "b"] -> map .upper # ["A", "B"]
306
+ ["", "x"] -> filter (!.empty) # ["x"]
307
+ ["a", "b"] -> map .pad_start(3, "0") # ["00a", "00b"] (with args)
308
+ [" HI "] -> map .trim.lower # ["hi"] (chained methods)
274
309
 
275
310
  Body forms (all operators accept these):
276
- -> each { \$ * 2 } # block (\$ is current element)
277
- -> each (\$ + 10) # grouped expression
278
- -> each |x| (\$x * 2) # inline closure
279
- -> each \$double # variable closure
280
- -> each .upper # method shorthand
281
- -> each log # host function
282
311
 
283
- Dict iteration (\$ contains key and value fields):
284
- [a: 1, b: 2] -> each { "{\$.key}={\$.value}" } # ["a=1", "b=2"]
285
- [a: 1, b: 5] -> filter { \$.value > 2 } # entries where value > 2
312
+ -> each { \$ * 2 } # block (\$ is current element)
313
+ -> each (\$ + 10) # grouped expression
314
+ -> each |x| (\$x * 2) # inline closure
315
+ -> each \$double # variable closure
316
+ -> each .upper # method shorthand
317
+ -> each log # host function
318
+
319
+ Dict iteration (\`\$\` contains \`key\` and \`value\` fields):
320
+
321
+ [a: 1, b: 2] -> each { "{\$.key}={\$.value}" } # ["a=1", "b=2"]
322
+ [a: 1, b: 5] -> filter { \$.value > 2 } # entries where value > 2
286
323
 
287
324
  String iteration (iterates over characters):
288
- "abc" -> each { "{\$}!" } # ["a!", "b!", "c!"]
289
- "hello" -> filter { \$ != "l" } # ["h", "e", "o"]
290
325
 
291
- CLOSURES
292
- --------
326
+ "abc" -> each { "{\$}!" } # ["a!", "b!", "c!"]
327
+ "hello" -> filter { \$ != "l" } # ["h", "e", "o"]
293
328
 
294
- BLOCK-CLOSURES vs EXPLICIT CLOSURES:
329
+ ## Closures
295
330
 
296
331
  Two ways to create closures:
297
332
 
298
- 1. Block-closures: { body } in expression position
299
- { \$ + 1 } => \$inc # implicit \$ parameter
300
- \$inc(5) # 6
301
- 5 -> \$inc # 6 (pipe invocation)
302
- [x: { \$ * 2 }] # dict value is closure
303
- type({ "hi" }) # "closure"
304
-
305
- 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
310
-
311
- CRITICAL: { } vs ( ) distinction
312
-
313
- | Syntax | Semantics | Example |
314
- |--------------|------------------------|----------------------------|
315
- | { body } | Deferred (closure) | { \$ + 1 } => \$fn # closure |
316
- | ( expr ) | Eager (immediate eval) | ( 5 + 1 ) => \$x # 6 |
317
-
318
- When to use:
319
- { body } => \$fn # store closure for later use
320
- ( expr ) => \$x # store result value immediately
321
-
322
- PIPE TARGET: { } creates closure then immediately invokes it:
323
- 5 -> { \$ + 1 } # 6 (create closure, invoke with 5)
324
- 5 -> (\$ + 1) # 6 (evaluate expression with \$=5)
325
- Same observable result, different mechanism. Error messages differ.
326
-
327
- Block-closure invocation:
328
- { \$ + 1 } => \$inc
329
- \$inc(5) # direct call: 6
330
- 5 -> \$inc # pipe call: 6
331
- [1,2,3] -> map \$inc # in collection op
333
+ **Block-closures:** \`{ body }\` in expression position
334
+
335
+ { \$ + 1 } => \$inc # implicit \$ parameter
336
+ \$inc(5) # 6
337
+ 5 -> \$inc # 6 (pipe invocation)
338
+ [x: { \$ * 2 }] # dict value is closure
339
+ type({ "hi" }) # "closure"
340
+
341
+ **Explicit closures:** \`|params| body\`
342
+
343
+ |x|(\$x + 1) => \$inc # named parameter
344
+ |a, b|(\$a + \$b) => \$add # multiple params
345
+ |x = 0|(\$x + 1) => \$inc_or_one # default value
346
+ |x: number|(\$x + 1) => \$typed # type annotation
347
+
348
+ \`{ body }\` vs \`( expr )\` distinction:
349
+
350
+ | Syntax | Semantics | Example |
351
+ |---|---|---|
352
+ | \`{ body }\` | Deferred (closure) | \`{ \$ + 1 } => \$fn\` |
353
+ | \`( expr )\` | Eager (immediate eval) | \`( 5 + 1 ) => \$x\` gives 6 |
332
354
 
333
355
  LATE BINDING: closures capture scope, not values. Variables resolve at call time.
334
356
 
335
- \$ vs named params:
336
- Use \$ in inline pipes and loops: "hello" -> { .upper }
337
- Use named params in stored closures: |x| (\$x * 2) => \$double
338
- \$ is undefined when a stored closure is called later — always use params.
357
+ \`\$\` vs named params:
358
+ - Use \`\$\` in inline pipes and loops: \`"hello" -> { .upper }\`
359
+ - Use named params in stored closures: \`|x| (\$x * 2) => \$double\`
360
+ - \`\$\` is undefined when a stored closure is called later — always use params.
339
361
 
340
362
  Zero-param dict closures (methods):
341
- [count: 3, double: ||{ \$.count * 2 }] => \$obj
342
- \$obj.double # 6 (\$ is bound to dict)
343
-
344
- PROPERTY ACCESS
345
- ---------------
346
-
347
- \$data.field # dict field
348
- \$data[0], \$data[-1] # list index (negative from end)
349
- \$data.\$key # variable as key
350
- \$data.(\$i + 1) # computed key
351
- \$data.(a || b) # try keys left-to-right
352
- \$data.field ?? "default" # default if missing
353
- \$data.?field # existence check (boolean)
354
- \$data.?\$keyVar # variable existence check
355
- \$data.?(\$expr) # computed existence check
356
- \$data.?field&string # existence AND type check
357
- \$data.?\$key&number # variable existence + type check
358
- \$data.?(\$a -> "{\$}_b")&list # computed existence + type check
359
-
360
- DISPATCH OPERATORS
361
- ------------------
362
-
363
- DICT DISPATCH (single key):
364
- Pipe a value to a dict to match keys and return associated values:
365
- \$val -> [apple: "fruit", carrot: "veg"] # returns "fruit" if \$val is "apple"
366
- \$val -> [apple: "fruit"] ?? "not found" # default if no match
367
- \$method -> [["GET", "HEAD"]: "safe", ["POST", "PUT"]: "unsafe"] # multi-key dispatch
363
+
364
+ [count: 3, double: ||{ \$.count * 2 }] => \$obj
365
+ \$obj.double # 6 (\$ is bound to dict)
366
+
367
+ ## Property Access
368
+
369
+ \$data.field # dict field
370
+ \$data[0], \$data[-1] # list index (negative from end)
371
+ \$data.\$key # variable as key
372
+ \$data.(\$i + 1) # computed key
373
+ \$data.(a || b) # try keys left-to-right
374
+ \$data.field ?? "default" # default if missing
375
+ \$data.?field # existence check (boolean)
376
+ \$data.?\$keyVar # variable existence check
377
+ \$data.?(\$expr) # computed existence check
378
+ \$data.?field&string # existence AND type check
379
+ \$data.?\$key&number # variable existence + type check
380
+ \$data.?(\$a -> "{\$}_b")&list # computed existence + type check
381
+
382
+ ## Dispatch Operators
383
+
384
+ **Dict dispatch** (single key) — pipe a value to a dict to match keys:
385
+
386
+ \$val -> [apple: "fruit", carrot: "veg"] # "fruit" if \$val is "apple"
387
+ \$val -> [apple: "fruit"] ?? "not found" # default if no match
388
+ \$method -> [["GET", "HEAD"]: "safe", ["POST", "PUT"]: "unsafe"] # multi-key
368
389
 
369
390
  Type-aware matching (keys matched by value AND type):
370
- 1 -> [1: "number", "1": "string"] # "number" (number key matches)
371
- "1" -> [1: "number", "1": "string"] # "string" (string key matches)
372
- true -> [true: "bool", "true": "str"] # "bool" (boolean key matches)
373
-
374
- LIST DISPATCH (index):
375
- Pipe a number to a list to get element at index:
376
- 0 -> ["first", "second"] # "first"
377
- -1 -> ["first", "second"] # "second" (last)
378
- 5 -> ["a", "b"] ?? "not found" # default if out of bounds
379
-
380
- HIERARCHICAL DISPATCH (path navigation):
381
- Pipe a list of keys/indexes to navigate nested structures:
382
- ["name", "first"] -> [name: [first: "Alice"]] # "Alice" (dict path)
383
- [0, 1] -> [[1, 2, 3], [4, 5, 6]] # 2 (list path)
384
- ["users", 0, "name"] -> [users: [[name: "Alice"]]] # "Alice" (mixed)
385
- [] -> [a: 1] # [a: 1] (empty path = unchanged)
386
- ["a", "missing"] -> [a: [x: 1]] ?? "default" # "default" (missing key)
387
-
388
- TYPE OPERATIONS
389
- ---------------
390
-
391
- :type - assert type (error if wrong): 42:number passes; "x":number errors
392
- :?type - check type (boolean): 42:?number is true; "x":?number is false
393
-
394
- Types: string, number, boolean, list, dict, tuple, closure
395
-
396
- Comparison methods (for readable conditionals):
397
- .eq(val) == .ne(val) != .lt(val) < .gt(val) > .le(val) <= .ge(val) >=
398
- Example: \$age -> .ge(18) ? "adult" ! "minor"
399
-
400
- OPERATOR PRECEDENCE (highest to lowest)
401
- ---------------------------------------
402
-
403
- 1. Member access: .field, [index]
404
- 2. Type operators: :type, :?type
405
- 3. Unary: -, !
406
- 4. Multiplicative: *, /, %
407
- 5. Additive: +, -
408
- 6. Comparison: ==, !=, <, >, <=, >=
409
- 7. Logical AND: &&
410
- 8. Logical OR: ||
411
- 9. Default: ??
412
- 10. Pipe: ->
413
- 11. Capture: =>
414
-
415
- Use parentheses to override: (2 + 3) * 4
416
-
417
- EXTRACTION OPERATORS
418
- --------------------
419
-
420
- Destructure (*<>):
421
- [1, 2, 3] -> *<\$a, \$b, \$c> # \$a=1, \$b=2, \$c=3
422
- [x: 1, y: 2] -> *<x: \$a, y: \$b> # \$a=1, \$b=2
423
- [1, 2, 3] -> *<\$first, _, \$third> # _ skips element
424
-
425
- Slice (/<start:stop:step>):
426
- [0,1,2,3,4] -> /<1:3> # [1, 2]
427
- [0,1,2,3,4] -> /<-2:> # [3, 4]
428
- [0,1,2,3,4] -> /<::-1> # [4,3,2,1,0] (reverse)
429
- "hello" -> /<1:4> # "ell"
430
-
431
- LIST SPREAD IN LITERALS
432
- -----------------------
433
-
434
- Inline list elements into a new list using ... (spread operator):
435
- [1, 2] => \$a
436
- [...\$a, 3] # [1, 2, 3]
437
- [...\$a, ...\$b] # concatenate lists
438
- [...(\$nums -> map {\$ * 2})] # spread expression result
439
-
440
- MULTI-KEY DICT LITERALS
441
- -----------------------
442
-
443
- Map multiple keys to the same value using list syntax:
444
- [["a", "b"]: 1] # [a: 1, b: 1]
445
- [[1, "1"]: "x"] # [1: "x", "1": "x"] (mixed types)
446
- [a: 0, ["b", "c"]: 1] # [a: 0, b: 1, c: 1] (mixed entries)
447
-
448
- TUPLES FOR ARGUMENT UNPACKING
449
- -----------------------------
450
-
451
- *[1, 2, 3] -> \$fn() # positional: \$fn(1, 2, 3)
452
- *[b: 2, a: 1] -> \$fn() # named: \$fn(a=1, b=2)
453
- *[...\$list, 3] -> \$fn() # spread in tuple: combines elements
454
-
455
- CLOSURE CHAIN (@)
456
- -----------------
391
+
392
+ 1 -> [1: "number", "1": "string"] # "number"
393
+ "1" -> [1: "number", "1": "string"] # "string"
394
+ true -> [true: "bool", "true": "str"] # "bool"
395
+
396
+ **List dispatch** (index) — pipe a number to a list:
397
+
398
+ 0 -> ["first", "second"] # "first"
399
+ -1 -> ["first", "second"] # "second" (last)
400
+ 5 -> ["a", "b"] ?? "not found" # default if out of bounds
401
+
402
+ **Hierarchical dispatch** (path navigation) — pipe a list of keys/indexes:
403
+
404
+ ["name", "first"] -> [name: [first: "Alice"]] # "Alice"
405
+ [0, 1] -> [[1, 2, 3], [4, 5, 6]] # 2
406
+ ["users", 0, "name"] -> [users: [[name: "Alice"]]] # "Alice"
407
+ [] -> [a: 1] # [a: 1] (empty path = unchanged)
408
+ ["a", "missing"] -> [a: [x: 1]] ?? "default" # "default"
409
+
410
+ ## Type Operations
411
+
412
+ \`:type\` assert type (error if wrong): \`42:number\` passes; \`"x":number\` errors.
413
+ \`:?type\` check type (boolean): \`42:?number\` is true; \`"x":?number\` is false.
414
+
415
+ Types: \`string\`, \`number\`, \`boolean\`, \`list\`, \`dict\`, \`tuple\`, \`closure\`.
416
+
417
+ Comparison methods:
418
+
419
+ .eq(val) == .ne(val) != .lt(val) < .gt(val) > .le(val) <= .ge(val) >=
420
+ Example: \$age -> .ge(18) ? "adult" ! "minor"
421
+
422
+ ## Operator Precedence (Highest to Lowest)
423
+
424
+ 1. Member access: \`.field\`, \`[index]\`
425
+ 2. Type operators: \`:type\`, \`:?type\`
426
+ 3. Unary: \`-\`, \`!\`
427
+ 4. Multiplicative: \`*\`, \`/\`, \`%\`
428
+ 5. Additive: \`+\`, \`-\`
429
+ 6. Comparison: \`==\`, \`!=\`, \`<\`, \`>\`, \`<=\`, \`>=\`
430
+ 7. Logical AND: \`&&\`
431
+ 8. Logical OR: \`||\`
432
+ 9. Default: \`??\`
433
+ 10. Pipe: \`->\`
434
+ 11. Capture: \`=>\`
435
+
436
+ Use parentheses to override: \`(2 + 3) * 4\`
437
+
438
+ ## Extraction Operators
439
+
440
+ Destructure (\`*<>\`):
441
+
442
+ [1, 2, 3] -> *<\$a, \$b, \$c> # \$a=1, \$b=2, \$c=3
443
+ [x: 1, y: 2] -> *<x: \$a, y: \$b> # \$a=1, \$b=2
444
+ [1, 2, 3] -> *<\$first, _, \$third> # _ skips element
445
+
446
+ Slice (\`/<start:stop:step>\`):
447
+
448
+ [0,1,2,3,4] -> /<1:3> # [1, 2]
449
+ [0,1,2,3,4] -> /<-2:> # [3, 4]
450
+ [0,1,2,3,4] -> /<::-1> # [4,3,2,1,0] (reverse)
451
+ "hello" -> /<1:4> # "ell"
452
+
453
+ ## List Spread in Literals
454
+
455
+ Inline list elements into a new list using \`...\` (spread operator):
456
+
457
+ [1, 2] => \$a
458
+ [...\$a, 3] # [1, 2, 3]
459
+ [...\$a, ...\$b] # concatenate lists
460
+ [...(\$nums -> map {\$ * 2})] # spread expression result
461
+
462
+ ## Tuples for Argument Unpacking
463
+
464
+ *[1, 2, 3] -> \$fn() # positional: \$fn(1, 2, 3)
465
+ *[b: 2, a: 1] -> \$fn() # named: \$fn(a=1, b=2)
466
+ *[...\$list, 3] -> \$fn() # spread in tuple: combines elements
467
+
468
+ ## Closure Chain (@)
457
469
 
458
470
  Chains closures sequentially (each receives previous result):
459
- 5 -> @[\$inc, \$double, \$add10] # (5+1)*2+10 = 22
460
-
461
- STRING METHODS
462
- --------------
463
-
464
- .len length .empty is empty string
465
- .trim remove whitespace .upper uppercase
466
- .lower lowercase .str convert to string
467
- .num parse to number .head first character
468
- .tail last character .at(i) character at index
469
- .split(sep) split into list (default: newline)
470
- .lines split on newlines .join(sep) join list with separator
471
- .contains(s) substring check .starts_with(s) prefix check
472
- .ends_with(s) suffix check .index_of(s) first match position (-1 if none)
473
- .replace(p,r) replace first regex match
474
- .replace_all(p,r) replace all regex matches
475
- .match(regex) first match info (dict with matched, index, groups)
476
- .is_match(regex) boolean regex check
477
- .repeat(n) repeat n times: "ab" -> .repeat(3) # "ababab"
478
- .pad_start(n,f) pad start: "42" -> .pad_start(5, "0") # "00042"
479
- .pad_end(n,f) pad end: "42" -> .pad_end(5, "0") # "42000"
480
-
481
- LIST/DICT METHODS
482
- -----------------
483
-
484
- .len length .empty is empty
485
- .head first element .tail last element
486
- .at(i) element at index .keys dict keys as list
487
- .values dict values as list .entries dict as list of [k, v] tuples
488
- .has(val) list contains value (deep equality)
489
- .has_any(list) list contains any value from candidates
490
- .has_all(list) list contains all values from candidates
491
-
492
- GLOBAL FUNCTIONS
493
- ----------------
494
-
495
- type(val) returns type name (string, number, boolean, list, dict, closure, tuple)
496
- log(val) print and pass through
497
- json(val) convert to JSON string
498
- identity(val) returns input unchanged
499
- range(start, end, step?) number sequence (iterator)
500
- repeat(val, count) repeat value n times (iterator)
501
- enumerate(coll) lists: [index, value]; dicts: [index, key, value]
502
-
503
- ITERATORS
504
- ---------
471
+
472
+ 5 -> @[\$inc, \$double, \$add10] # (5+1)*2+10 = 22
473
+
474
+ ## String Methods
475
+
476
+ | Method | Description |
477
+ |---|---|
478
+ | \`.len\` | length |
479
+ | \`.empty\` | is empty string |
480
+ | \`.trim\` | remove whitespace |
481
+ | \`.upper\` | uppercase |
482
+ | \`.lower\` | lowercase |
483
+ | \`.str\` | convert to string |
484
+ | \`.num\` | parse to number |
485
+ | \`.head\` | first character |
486
+ | \`.tail\` | last character |
487
+ | \`.at(i)\` | character at index |
488
+ | \`.split(sep)\` | split into list (default: newline) |
489
+ | \`.lines\` | split on newlines |
490
+ | \`.join(sep)\` | join list with separator |
491
+ | \`.contains(s)\` | substring check |
492
+ | \`.starts_with(s)\` | prefix check |
493
+ | \`.ends_with(s)\` | suffix check |
494
+ | \`.index_of(s)\` | first match position (-1 if none) |
495
+ | \`.replace(p, r)\` | replace first regex match |
496
+ | \`.replace_all(p, r)\` | replace all regex matches |
497
+ | \`.match(regex)\` | first match info (dict with matched, index, groups) |
498
+ | \`.is_match(regex)\` | boolean regex check |
499
+ | \`.repeat(n)\` | repeat n times |
500
+ | \`.pad_start(n, f)\` | pad start |
501
+ | \`.pad_end(n, f)\` | pad end |
502
+
503
+ ## List/Dict Methods
504
+
505
+ | Method | Description |
506
+ |---|---|
507
+ | \`.len\` | length |
508
+ | \`.empty\` | is empty |
509
+ | \`.head\` | first element |
510
+ | \`.tail\` | last element |
511
+ | \`.at(i)\` | element at index |
512
+ | \`.keys\` | dict keys as list |
513
+ | \`.values\` | dict values as list |
514
+ | \`.entries\` | dict as list of [k, v] tuples |
515
+ | \`.has(val)\` | list contains value (deep equality) |
516
+ | \`.has_any(list)\` | list contains any value from candidates |
517
+ | \`.has_all(list)\` | list contains all values from candidates |
518
+
519
+ ## Global Functions
520
+
521
+ | Function | Description |
522
+ |---|---|
523
+ | \`type(val)\` | returns type name |
524
+ | \`log(val)\` | print and pass through |
525
+ | \`json(val)\` | convert to JSON string |
526
+ | \`identity(val)\` | returns input unchanged |
527
+ | \`range(start, end, step?)\` | number sequence (iterator) |
528
+ | \`repeat(val, count)\` | repeat value n times (iterator) |
529
+ | \`enumerate(coll)\` | lists: [index, value]; dicts: [index, key, value] |
530
+
531
+ ## Iterators
505
532
 
506
533
  Lazy sequence generation. Collection operators auto-expand iterators.
507
534
 
508
- Built-in iterators:
509
- range(0, 5) -> each { \$ * 2 } # [0, 2, 4, 6, 8]
510
- repeat("x", 3) -> each { \$ } # ["x", "x", "x"]
535
+ range(0, 5) -> each { \$ * 2 } # [0, 2, 4, 6, 8]
536
+ repeat("x", 3) -> each { \$ } # ["x", "x", "x"]
537
+
538
+ \`.first()\` method (returns iterator for any collection):
539
+
540
+ [1, 2, 3] -> .first() # iterator at 1
541
+ "abc" -> .first() # iterator at "a"
511
542
 
512
- .first() method (returns iterator for any collection):
513
- [1, 2, 3] -> .first() # iterator at 1
514
- "abc" -> .first() # iterator at "a"
543
+ Iterator protocol (dict with \`value\`, \`done\`, \`next\`):
515
544
 
516
- Iterator protocol (dict with value, done, next):
517
- \$it.done # bool: is exhausted?
518
- \$it.value # current element
519
- \$it.next() # returns new iterator at next position
545
+ \$it.done # bool: is exhausted?
546
+ \$it.value # current element
547
+ \$it.next() # returns new iterator at next position
520
548
 
521
- ITERATION LIMITS
522
- ----------------
549
+ ## Iteration Limits
523
550
 
524
551
  Default: 10,000 iterations max for loops.
525
- Override: ^(limit: N) statement
552
+ Override: \`^(limit: N)\` statement.
526
553
 
527
- ^(limit: 100) 0 -> (\$ < 50) @ { \$ + 1 }
528
- ^(limit: 3) \$items -> map { slow_process(\$) } # concurrency limit
554
+ ^(limit: 100) 0 -> (\$ < 50) @ { \$ + 1 }
555
+ ^(limit: 3) \$items -> map { slow_process(\$) } # concurrency limit
529
556
 
530
- SCRIPT RETURN VALUES
531
- --------------------
557
+ ## Script Return Values
532
558
 
533
- true / non-empty string -> exit code 0
534
- false / empty string -> exit code 1
535
- [0, "message"] -> exit code 0 with message
536
- [1, "message"] -> exit code 1 with message
559
+ | Return value | Exit code |
560
+ |---|---|
561
+ | \`true\` / non-empty string | 0 |
562
+ | \`false\` / empty string | 1 |
563
+ | \`[0, "message"]\` | 0 with message |
564
+ | \`[1, "message"]\` | 1 with message |
537
565
  `;
538
566
  //# sourceMappingURL=introspection-data.js.map