@rcrsr/rill 0.7.2 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -1
- package/dist/ast-nodes.d.ts +635 -0
- package/dist/ast-nodes.d.ts.map +1 -0
- package/dist/ast-nodes.js +2 -0
- package/dist/ast-nodes.js.map +1 -0
- package/dist/ast-unions.d.ts +6 -0
- package/dist/ast-unions.d.ts.map +1 -0
- package/dist/ast-unions.js +6 -0
- package/dist/ast-unions.js.map +1 -0
- package/dist/error-classes.d.ts +90 -0
- package/dist/error-classes.d.ts.map +1 -0
- package/dist/error-classes.js +185 -0
- package/dist/error-classes.js.map +1 -0
- package/dist/error-registry.d.ts +93 -0
- package/dist/error-registry.d.ts.map +1 -0
- package/dist/error-registry.js +876 -0
- package/dist/error-registry.js.map +1 -0
- package/dist/ext/crypto/index.d.ts +32 -0
- package/dist/ext/crypto/index.d.ts.map +1 -0
- package/dist/ext/crypto/index.js +143 -0
- package/dist/ext/crypto/index.js.map +1 -0
- package/dist/ext/exec/index.d.ts +45 -0
- package/dist/ext/exec/index.d.ts.map +1 -0
- package/dist/ext/exec/index.js +168 -0
- package/dist/ext/exec/index.js.map +1 -0
- package/dist/ext/exec/runner.d.ts +62 -0
- package/dist/ext/exec/runner.d.ts.map +1 -0
- package/dist/ext/exec/runner.js +168 -0
- package/dist/ext/exec/runner.js.map +1 -0
- package/dist/ext/fetch/index.d.ts +68 -0
- package/dist/ext/fetch/index.d.ts.map +1 -0
- package/dist/ext/fetch/index.js +259 -0
- package/dist/ext/fetch/index.js.map +1 -0
- package/dist/ext/fetch/request.d.ts +90 -0
- package/dist/ext/fetch/request.d.ts.map +1 -0
- package/dist/ext/fetch/request.js +413 -0
- package/dist/ext/fetch/request.js.map +1 -0
- package/dist/ext/fs/index.d.ts +39 -0
- package/dist/ext/fs/index.d.ts.map +1 -0
- package/dist/ext/fs/index.js +560 -0
- package/dist/ext/fs/index.js.map +1 -0
- package/dist/ext/fs/sandbox.d.ts +78 -0
- package/dist/ext/fs/sandbox.d.ts.map +1 -0
- package/dist/ext/fs/sandbox.js +208 -0
- package/dist/ext/fs/sandbox.js.map +1 -0
- package/dist/ext/kv/index.d.ts +46 -0
- package/dist/ext/kv/index.d.ts.map +1 -0
- package/dist/ext/kv/index.js +215 -0
- package/dist/ext/kv/index.js.map +1 -0
- package/dist/ext/kv/store.d.ts +46 -0
- package/dist/ext/kv/store.d.ts.map +1 -0
- package/dist/ext/kv/store.js +256 -0
- package/dist/ext/kv/store.js.map +1 -0
- package/dist/generated/introspection-data.d.ts +1 -1
- package/dist/generated/introspection-data.d.ts.map +1 -1
- package/dist/generated/introspection-data.js +509 -481
- package/dist/generated/introspection-data.js.map +1 -1
- package/dist/generated/version-data.d.ts +1 -1
- package/dist/generated/version-data.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/core/callable.d.ts +5 -5
- package/dist/runtime/core/callable.d.ts.map +1 -1
- package/dist/runtime/core/callable.js +2 -1
- package/dist/runtime/core/callable.js.map +1 -1
- package/dist/runtime/core/eval/mixins/collections.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/collections.js +5 -1
- package/dist/runtime/core/eval/mixins/collections.js.map +1 -1
- package/dist/runtime/core/eval/mixins/literals.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/literals.js +5 -1
- package/dist/runtime/core/eval/mixins/literals.js.map +1 -1
- package/dist/runtime/core/eval/mixins/variables.js +12 -12
- package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
- package/dist/runtime/core/values.d.ts +31 -3
- package/dist/runtime/core/values.d.ts.map +1 -1
- package/dist/runtime/core/values.js +47 -1
- package/dist/runtime/core/values.js.map +1 -1
- package/dist/runtime/ext/builtins.d.ts.map +1 -1
- package/dist/runtime/ext/builtins.js +202 -1
- package/dist/runtime/ext/builtins.js.map +1 -1
- package/dist/runtime/ext/extensions.d.ts +39 -3
- package/dist/runtime/ext/extensions.d.ts.map +1 -1
- package/dist/runtime/ext/extensions.js +77 -12
- package/dist/runtime/ext/extensions.js.map +1 -1
- package/dist/runtime/index.d.ts +5 -5
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/index.js.map +1 -1
- package/dist/source-location.d.ts +10 -0
- package/dist/source-location.d.ts.map +1 -0
- package/dist/source-location.js +5 -0
- package/dist/source-location.js.map +1 -0
- package/dist/token-types.d.ts +68 -0
- package/dist/token-types.d.ts.map +1 -0
- package/dist/token-types.js +79 -0
- package/dist/token-types.js.map +1 -0
- package/dist/types.d.ts +9 -882
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -958
- package/dist/types.js.map +1 -1
- package/dist/value-types.d.ts +3 -0
- package/dist/value-types.d.ts.map +1 -0
- package/dist/value-types.js +2 -0
- package/dist/value-types.js.map +1 -0
- package/package.json +50 -11
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KV Store Implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides JSON-based key-value persistence with schema validation.
|
|
5
|
+
* Lifecycle: Load (read store file) -> Execute (in-memory operations) -> Flush (atomic write on dispose)
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs/promises';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { RuntimeError } from '../../error-classes.js';
|
|
10
|
+
// ============================================================
|
|
11
|
+
// STORE IMPLEMENTATION
|
|
12
|
+
// ============================================================
|
|
13
|
+
/**
|
|
14
|
+
* Create KV store with JSON persistence.
|
|
15
|
+
*
|
|
16
|
+
* @param config - Store configuration
|
|
17
|
+
* @returns Store operations object
|
|
18
|
+
* @throws RuntimeError if store file is corrupt (EC-25)
|
|
19
|
+
*/
|
|
20
|
+
export async function createStore(config) {
|
|
21
|
+
// Apply defaults
|
|
22
|
+
const maxEntries = config.maxEntries ?? 10000;
|
|
23
|
+
const maxValueSize = config.maxValueSize ?? 102400; // 100KB
|
|
24
|
+
const maxStoreSize = config.maxStoreSize ?? 10485760; // 10MB
|
|
25
|
+
const writePolicy = config.writePolicy ?? 'dispose';
|
|
26
|
+
const schema = config.schema;
|
|
27
|
+
// Resolve store path
|
|
28
|
+
const storePath = path.resolve(config.store);
|
|
29
|
+
const storeDir = path.dirname(storePath);
|
|
30
|
+
// Ensure store directory exists
|
|
31
|
+
await fs.mkdir(storeDir, { recursive: true });
|
|
32
|
+
// In-memory data store
|
|
33
|
+
const data = new Map();
|
|
34
|
+
// ============================================================
|
|
35
|
+
// LOAD PHASE
|
|
36
|
+
// ============================================================
|
|
37
|
+
// Load existing store file or initialize with schema defaults
|
|
38
|
+
try {
|
|
39
|
+
const fileContent = await fs.readFile(storePath, 'utf-8');
|
|
40
|
+
const parsed = JSON.parse(fileContent);
|
|
41
|
+
// Validate and load entries
|
|
42
|
+
if (typeof parsed !== 'object' ||
|
|
43
|
+
parsed === null ||
|
|
44
|
+
Array.isArray(parsed)) {
|
|
45
|
+
// EC-25: Store file corrupt
|
|
46
|
+
throw new RuntimeError('RILL-R004', 'state file corrupt — reset or delete to recover', undefined, { path: storePath });
|
|
47
|
+
}
|
|
48
|
+
// Apply schema validation if in declared mode
|
|
49
|
+
if (schema) {
|
|
50
|
+
// Load declared keys with defaults, validate existing values
|
|
51
|
+
for (const [key, schemaEntry] of Object.entries(schema)) {
|
|
52
|
+
if (key in parsed) {
|
|
53
|
+
const value = parsed[key];
|
|
54
|
+
validateType(key, value, schemaEntry.type, storePath);
|
|
55
|
+
data.set(key, value);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Missing key - use default from schema
|
|
59
|
+
data.set(key, schemaEntry.default);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Extra keys in file are dropped (not in schema)
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// Open mode - load all keys
|
|
66
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
67
|
+
data.set(key, value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error instanceof RuntimeError) {
|
|
73
|
+
throw error; // Re-throw our error
|
|
74
|
+
}
|
|
75
|
+
// Check if file doesn't exist (first run)
|
|
76
|
+
if (error &&
|
|
77
|
+
typeof error === 'object' &&
|
|
78
|
+
'code' in error &&
|
|
79
|
+
error.code === 'ENOENT') {
|
|
80
|
+
// First run - initialize with schema defaults if declared mode
|
|
81
|
+
if (schema) {
|
|
82
|
+
for (const [key, schemaEntry] of Object.entries(schema)) {
|
|
83
|
+
data.set(key, schemaEntry.default);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// If open mode and file doesn't exist, data remains empty
|
|
87
|
+
}
|
|
88
|
+
else if (error instanceof SyntaxError) {
|
|
89
|
+
// JSON parse error
|
|
90
|
+
throw new RuntimeError('RILL-R004', 'state file corrupt — reset or delete to recover', undefined, { path: storePath });
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Other filesystem error
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// ============================================================
|
|
98
|
+
// HELPERS
|
|
99
|
+
// ============================================================
|
|
100
|
+
/** Calculate size of a value in bytes */
|
|
101
|
+
function calculateValueSize(value) {
|
|
102
|
+
return Buffer.byteLength(JSON.stringify(value), 'utf-8');
|
|
103
|
+
}
|
|
104
|
+
/** Calculate total store size in bytes */
|
|
105
|
+
function calculateStoreSize() {
|
|
106
|
+
const entries = {};
|
|
107
|
+
for (const [key, value] of data.entries()) {
|
|
108
|
+
entries[key] = value;
|
|
109
|
+
}
|
|
110
|
+
return Buffer.byteLength(JSON.stringify(entries), 'utf-8');
|
|
111
|
+
}
|
|
112
|
+
/** Validate value type against schema */
|
|
113
|
+
function validateType(key, value, expectedType, location) {
|
|
114
|
+
let actualType;
|
|
115
|
+
if (typeof value === 'string') {
|
|
116
|
+
actualType = 'string';
|
|
117
|
+
}
|
|
118
|
+
else if (typeof value === 'number') {
|
|
119
|
+
actualType = 'number';
|
|
120
|
+
}
|
|
121
|
+
else if (typeof value === 'boolean') {
|
|
122
|
+
actualType = 'bool';
|
|
123
|
+
}
|
|
124
|
+
else if (Array.isArray(value)) {
|
|
125
|
+
actualType = 'list';
|
|
126
|
+
}
|
|
127
|
+
else if (typeof value === 'object' && value !== null) {
|
|
128
|
+
actualType = 'dict';
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
actualType = typeof value;
|
|
132
|
+
}
|
|
133
|
+
// EC-21: Type mismatch
|
|
134
|
+
if (actualType !== expectedType) {
|
|
135
|
+
throw new RuntimeError('RILL-R004', `key "${key}" expects ${expectedType}, got ${actualType}`, undefined, { key, expectedType, actualType, location });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// ============================================================
|
|
139
|
+
// OPERATIONS
|
|
140
|
+
// ============================================================
|
|
141
|
+
/** Get value or schema default */
|
|
142
|
+
function get(key) {
|
|
143
|
+
// EC-20: Key not in schema (declared mode)
|
|
144
|
+
if (schema && !(key in schema)) {
|
|
145
|
+
throw new RuntimeError('RILL-R004', `key "${key}" not declared in schema`, undefined, { key });
|
|
146
|
+
}
|
|
147
|
+
return data.get(key);
|
|
148
|
+
}
|
|
149
|
+
/** Set value with validation */
|
|
150
|
+
async function set(key, value) {
|
|
151
|
+
// EC-20: Key not in schema (declared mode)
|
|
152
|
+
if (schema && !(key in schema)) {
|
|
153
|
+
throw new RuntimeError('RILL-R004', `key "${key}" not declared in schema`, undefined, { key });
|
|
154
|
+
}
|
|
155
|
+
// Validate type if in declared mode
|
|
156
|
+
if (schema && key in schema) {
|
|
157
|
+
validateType(key, value, schema[key].type, storePath);
|
|
158
|
+
}
|
|
159
|
+
// EC-22: Value exceeds maxValueSize
|
|
160
|
+
const valueSize = calculateValueSize(value);
|
|
161
|
+
if (valueSize > maxValueSize) {
|
|
162
|
+
throw new RuntimeError('RILL-R004', `value for "${key}" exceeds size limit`, undefined, { key, size: valueSize, max: maxValueSize });
|
|
163
|
+
}
|
|
164
|
+
// EC-24: Max entries exceeded (when adding new key)
|
|
165
|
+
if (!data.has(key) && data.size >= maxEntries) {
|
|
166
|
+
throw new RuntimeError('RILL-R004', `store exceeds entry limit (${data.size + 1} > ${maxEntries})`, undefined, { count: data.size + 1, max: maxEntries });
|
|
167
|
+
}
|
|
168
|
+
// Save old value for rollback (if key exists)
|
|
169
|
+
const oldValue = data.get(key);
|
|
170
|
+
const hadKey = data.has(key);
|
|
171
|
+
// Set value
|
|
172
|
+
data.set(key, value);
|
|
173
|
+
// EC-23: Store exceeds maxStoreSize
|
|
174
|
+
const storeSize = calculateStoreSize();
|
|
175
|
+
if (storeSize > maxStoreSize) {
|
|
176
|
+
// Rollback the set operation
|
|
177
|
+
if (hadKey) {
|
|
178
|
+
data.set(key, oldValue);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
data.delete(key);
|
|
182
|
+
}
|
|
183
|
+
throw new RuntimeError('RILL-R004', `store exceeds size limit (${storeSize} > ${maxStoreSize})`, undefined, { size: storeSize, max: maxStoreSize });
|
|
184
|
+
}
|
|
185
|
+
// Immediate write if policy is 'immediate'
|
|
186
|
+
if (writePolicy === 'immediate') {
|
|
187
|
+
await flush();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** Delete key */
|
|
191
|
+
function deleteKey(key) {
|
|
192
|
+
return data.delete(key);
|
|
193
|
+
}
|
|
194
|
+
/** Get all keys */
|
|
195
|
+
function keys() {
|
|
196
|
+
return Array.from(data.keys());
|
|
197
|
+
}
|
|
198
|
+
/** Check key existence */
|
|
199
|
+
function has(key) {
|
|
200
|
+
return data.has(key);
|
|
201
|
+
}
|
|
202
|
+
/** Clear all keys */
|
|
203
|
+
function clear() {
|
|
204
|
+
data.clear();
|
|
205
|
+
// If in declared mode, restore schema defaults
|
|
206
|
+
if (schema) {
|
|
207
|
+
for (const [key, schemaEntry] of Object.entries(schema)) {
|
|
208
|
+
data.set(key, schemaEntry.default);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** Get all entries as dict */
|
|
213
|
+
function getAll() {
|
|
214
|
+
const result = {};
|
|
215
|
+
for (const [key, value] of data.entries()) {
|
|
216
|
+
result[key] = value;
|
|
217
|
+
}
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
/** Flush data to disk (atomic write) */
|
|
221
|
+
async function flush() {
|
|
222
|
+
const entries = getAll();
|
|
223
|
+
const content = JSON.stringify(entries, null, 2);
|
|
224
|
+
// Atomic write: write to .tmp file, then rename
|
|
225
|
+
const tmpPath = `${storePath}.tmp`;
|
|
226
|
+
try {
|
|
227
|
+
await fs.writeFile(tmpPath, content, 'utf-8');
|
|
228
|
+
await fs.rename(tmpPath, storePath);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
// Flush failure - log warning, don't throw (per spec)
|
|
232
|
+
console.warn(`[KV Store] Failed to flush state to ${storePath}:`, error);
|
|
233
|
+
// Clean up tmp file if it exists
|
|
234
|
+
try {
|
|
235
|
+
await fs.unlink(tmpPath);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
// Ignore cleanup errors
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// ============================================================
|
|
243
|
+
// RETURN STORE OPERATIONS
|
|
244
|
+
// ============================================================
|
|
245
|
+
return {
|
|
246
|
+
get,
|
|
247
|
+
set,
|
|
248
|
+
delete: deleteKey,
|
|
249
|
+
keys,
|
|
250
|
+
has,
|
|
251
|
+
clear,
|
|
252
|
+
getAll,
|
|
253
|
+
flush,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/ext/kv/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -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\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\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\nMulti-line conditionals (? and ! work as line continuations):\n condition\n ? \"yes\"\n ! \"no\"\n value -> is_valid\n ? \"ok\"\n ! \"error\"\n $val -> .eq(\"A\") ? \"a\"\n ! .eq(\"B\") ? \"b\"\n ! \"c\"\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\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";
|
|
1
|
+
export declare const LANGUAGE_REFERENCE = "# rill\n\n> 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.\n\n## Documentation\n\n- [Getting Started](https://rill.run/docs/guide/getting-started/): Beginner-friendly introduction to rill\n- [Language Reference](https://rill.run/docs/reference/language/): Core language specification\n- [Examples](https://rill.run/docs/guide/examples/): Workflow patterns and use cases\n- [Cookbook](https://rill.run/docs/guide/cookbook/): Advanced agent scripting patterns\n- [Types](https://rill.run/docs/language/types/): Primitives, tuples, dicts, type assertions\n- [Variables](https://rill.run/docs/language/variables/): Declaration, scope rules, `$` binding\n- [Control Flow](https://rill.run/docs/language/control-flow/): Conditionals, loops, break/return\n- [Operators](https://rill.run/docs/language/operators/): Arithmetic, comparison, spread, extraction\n- [Closures](https://rill.run/docs/language/closures/): Late binding, dict-bound closures\n- [Collections](https://rill.run/docs/data/collections/): `each`, `map`, `filter`, `fold` operators\n- [Iterators](https://rill.run/docs/data/iterators/): Lazy sequences with `range`, `repeat`, `.first()`\n- [Strings](https://rill.run/docs/data/strings/): String methods for text manipulation\n- [Host Integration](https://rill.run/docs/integration/host/): Embedding rill in applications\n- [Host API Reference](https://rill.run/docs/reference/host-api/): Complete TypeScript API exports\n- [Developing Extensions](https://rill.run/docs/integration/extensions/): Writing reusable host function packages\n- [Modules](https://rill.run/docs/integration/modules/): Convention for host-provided module systems\n- [CLI Tools](https://rill.run/docs/integration/cli/): `rill-exec`, `rill-eval`, `rill-check` commands\n- [Error Reference](https://rill.run/docs/reference/errors/): Error codes and resolution\n\n## Essentials\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` is an ERROR\n5. Loops cannot modify outer vars: use `fold`, `each(init)`, or `$` as state dict\n\n## Strengths 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\nState machine pattern (`$` carries state through iterations):\n\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\n## Naming Convention: snake_case\n\nUse snake_case for all identifiers:\n\n $user_name, $item_list, $is_valid # variables\n $double_value, $cleanup_text # closures\n [first_name: \"x\", last_name: \"y\"] # dict keys\n\n## Why 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 closure? Is `data` a variable or key? This would require tracking all declarations.\n\n## Spacing Rules\n\n Operators: space both sides 5 + 3, $x -> .upper, \"a\" => $b\n Parentheses: no inner space ($x + 1), ($ > 3) ? \"yes\"\n Braces: space inside { $x + 1 }, each { $ * 2 }\n Brackets: no inner space $list[0], $dict.items[1]\n Literals: space after , and : [1, 2, 3], [name: \"x\", age: 30]\n Closures: space after params |x| ($x * 2), |a, b| { $a + $b }\n Methods: no space before . or ( $str.upper(), $list.join(\", \")\n Pipes: space both sides \"x\" -> .upper -> .len\n Continuations: indent 2 spaces $data\n -> .filter { $.active }\n -> map { $.name }\n\n## Implicit $ Shorthand (Always Prefer)\n\n $.method() -> .method \"x\" -> .upper (not $.upper())\n func($) -> func \"x\" -> log (not log($))\n $fn($) -> $fn 5 -> $double (not $double($))\n\nDon't capture just to continue \u2014 use line continuation instead:\n\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\n## Critical Differences from Mainstream Languages\n\n### 1. No Assignment Operator\n\n Wrong: x = 5 Mainstream: x = value\n Right: 5 => $x rill: value => $x\n\nPipe (`->`): passes value to next operation.\nCapture (`=>`): stores value AND continues chain.\nExample: `\"hello\" => $x -> .upper => $y` \u2014 `$x=\"hello\"`, `$y=\"HELLO\"`.\n\n### 2. No Null/Undefined\n\nEmpty values (`\"\"`, `[]`, `[:]`) exist. \"No value\" cannot be represented.\nUse `??` for defaults: `$dict.field ?? \"default\"`.\nUse `.empty` to check: `$str -> .empty ? \"was empty\"`.\n\n### 3. No Truthiness\n\nConditions MUST be boolean. No implicit coercion.\n\n Wrong: \"\" ? \"yes\" ! \"no\" Right: \"\" -> .empty ? \"yes\" ! \"no\"\n Wrong: 0 ? \"yes\" ! \"no\" Right: (0 == 0) ? \"yes\" ! \"no\"\n\nNegation (`!`) also requires boolean:\n\n !true # false\n \"hello\" -> .empty -> (!$) # true (negates boolean from .empty)\n !\"hello\" # ERROR: Negation requires boolean\n\n### 4. Variables Lock to First Type\n\n \"hello\" => $x\n 42 => $x # ERROR: cannot assign number to string variable\n\n### 5. No Variable Shadowing (Critical for Loops)\n\nChild scopes can READ parent variables but cannot WRITE or redeclare them.\nVariables created inside blocks/loops do NOT leak out.\n\nWRONG \u2014 outer variable modification (NEVER works):\n\n 0 => $count\n [1, 2, 3] -> each { $count + 1 => $count } # creates LOCAL $count\n $count # still 0!\n\nRIGHT \u2014 use `fold` for reduction:\n\n [1, 2, 3] -> fold(0) { $@ + $ } # 6 ($@ is accumulator)\n\nRIGHT \u2014 use `each(init)` for results AND accumulator:\n\n [1, 2, 3] -> each(0) { $@ + $ } # [1, 3, 6] (running totals)\n\nRIGHT \u2014 use `(cond) @ { }` with `$` as state dict for multiple values:\n\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\nPattern summary:\n\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\n### 6. No Exceptions\n\nErrors halt execution. No try/catch. Use conditionals for error handling.\nBuilt-in: `assert` (validate condition), `error` (halt with message).\n\n### 7. Value Semantics (No References)\n\nAll copies are deep. All comparisons are by value. No object identity.\n\n [1, 2, 3] == [1, 2, 3] # true (content equality)\n [1, 2] => $a\n $a => $b # $b is an independent deep copy\n\n## Syntax Quick Reference\n\n Variables: $name (always prefixed with $)\n Strings: \"hello {$var}\" # interpolation with {}\n \"\"\"...\"\"\" # multiline (also interpolates)\n Numbers: 42, 3.14, -7\n Booleans: true, false\n Lists: [1, 2, 3]\n [...$list, 4] # spread: inline list elements\n Dicts: [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)\n Tuples: *[1, 2, 3] # for argument unpacking\n Closures: |x|($x + 1) # like lambda/arrow functions\n Type annot: \"hi\" => $x:string # lock type on capture\n Comments: # single line only\n\n## Pipes and $ Binding\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 \u2014 use parameters |\n\nImplied `$`: bare `.method()` means `$ -> .method()`.\nExample: `\"hello\" -> .upper` is the same as `\"hello\" -> $.upper()`.\n\n## Control Flow\n\nConditional (if-else):\n\n cond ? then_expr ! else_expr\n cond ? then_expr # else returns \"\"\n\nPiped conditional (`$` becomes condition):\n\n value -> ? then_expr ! else_expr\n\nMulti-line conditionals (`?` and `!` work as line continuations):\n\n condition\n ? \"yes\"\n ! \"no\"\n value -> is_valid\n ? \"ok\"\n ! \"error\"\n $val -> .eq(\"A\") ? \"a\"\n ! .eq(\"B\") ? \"b\"\n ! \"c\"\n\nCondition loop (NO `while` keyword \u2014 use `@` operator):\n\n init_value -> ($ < 10) @ { $ + 1 } # $ is accumulator\n\nDo-condition loop (body runs at least once):\n\n init_value -> @ { $ + 1 } ? ($ < 10)\n\nBreak (exits loop, returns collected results before break):\n\n [1,2,3,4,5] -> each { ($ == 3) ? break; $ } # returns [1, 2]\n\nReturn (exits block or script with value):\n\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\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\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\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\nNote: `pass` requires pipe context. Using `pass` without `$` throws error.\n\n## Collection Operators\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\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\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\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\n \"abc\" -> each { \"{$}!\" } # [\"a!\", \"b!\", \"c!\"]\n \"hello\" -> filter { $ != \"l\" } # [\"h\", \"e\", \"o\"]\n\n## Closures\n\nTwo ways to create closures:\n\n**Block-closures:** `{ body }` in expression position\n\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\n**Explicit closures:** `|params| body`\n\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\n`{ body }` vs `( expr )` distinction:\n\n| Syntax | Semantics | Example |\n|---|---|---|\n| `{ body }` | Deferred (closure) | `{ $ + 1 } => $fn` |\n| `( expr )` | Eager (immediate eval) | `( 5 + 1 ) => $x` gives 6 |\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\n [count: 3, double: ||{ $.count * 2 }] => $obj\n $obj.double # 6 ($ is bound to dict)\n\n## Property Access\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\n## Dispatch Operators\n\n**Dict dispatch** (single key) \u2014 pipe a value to a dict to match keys:\n\n $val -> [apple: \"fruit\", carrot: \"veg\"] # \"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\n\nType-aware matching (keys matched by value AND type):\n\n 1 -> [1: \"number\", \"1\": \"string\"] # \"number\"\n \"1\" -> [1: \"number\", \"1\": \"string\"] # \"string\"\n true -> [true: \"bool\", \"true\": \"str\"] # \"bool\"\n\n**List dispatch** (index) \u2014 pipe a number to a list:\n\n 0 -> [\"first\", \"second\"] # \"first\"\n -1 -> [\"first\", \"second\"] # \"second\" (last)\n 5 -> [\"a\", \"b\"] ?? \"not found\" # default if out of bounds\n\n**Hierarchical dispatch** (path navigation) \u2014 pipe a list of keys/indexes:\n\n [\"name\", \"first\"] -> [name: [first: \"Alice\"]] # \"Alice\"\n [0, 1] -> [[1, 2, 3], [4, 5, 6]] # 2\n [\"users\", 0, \"name\"] -> [users: [[name: \"Alice\"]]] # \"Alice\"\n [] -> [a: 1] # [a: 1] (empty path = unchanged)\n [\"a\", \"missing\"] -> [a: [x: 1]] ?? \"default\" # \"default\"\n\n## Type Operations\n\n`:type` \u2014 assert type (error if wrong): `42:number` passes; `\"x\":number` errors.\n`:?type` \u2014 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 .eq(val) == .ne(val) != .lt(val) < .gt(val) > .le(val) <= .ge(val) >=\n Example: $age -> .ge(18) ? \"adult\" ! \"minor\"\n\n## Operator Precedence (Highest to Lowest)\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\n## Extraction Operators\n\nDestructure (`*<>`):\n\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\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\n## List Spread in Literals\n\nInline list elements into a new list using `...` (spread operator):\n\n [1, 2] => $a\n [...$a, 3] # [1, 2, 3]\n [...$a, ...$b] # concatenate lists\n [...($nums -> map {$ * 2})] # spread expression result\n\n## Tuples for Argument Unpacking\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\n## Closure Chain (@)\n\nChains closures sequentially (each receives previous result):\n\n 5 -> @[$inc, $double, $add10] # (5+1)*2+10 = 22\n\n## String Methods\n\n| Method | Description |\n|---|---|\n| `.len` | length |\n| `.empty` | is empty string |\n| `.trim` | remove whitespace |\n| `.upper` | uppercase |\n| `.lower` | lowercase |\n| `.str` | convert to string |\n| `.num` | parse to number |\n| `.head` | first character |\n| `.tail` | last character |\n| `.at(i)` | character at index |\n| `.split(sep)` | split into list (default: newline) |\n| `.lines` | split on newlines |\n| `.join(sep)` | join list with separator |\n| `.contains(s)` | substring check |\n| `.starts_with(s)` | prefix check |\n| `.ends_with(s)` | suffix check |\n| `.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 |\n| `.pad_start(n, f)` | pad start |\n| `.pad_end(n, f)` | pad end |\n\n## List/Dict Methods\n\n| Method | Description |\n|---|---|\n| `.len` | length |\n| `.empty` | is empty |\n| `.head` | first element |\n| `.tail` | last element |\n| `.at(i)` | element at index |\n| `.keys` | dict keys as list |\n| `.values` | dict values as list |\n| `.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\n## Global Functions\n\n| Function | Description |\n|---|---|\n| `type(val)` | returns type name |\n| `log(val)` | print and pass through |\n| `json(val)` | convert to JSON string |\n| `identity(val)` | returns input unchanged |\n| `range(start, end, step?)` | number sequence (iterator) |\n| `repeat(val, count)` | repeat value n times (iterator) |\n| `enumerate(coll)` | lists: [index, value]; dicts: [index, key, value] |\n\n## Iterators\n\nLazy sequence generation. Collection operators auto-expand iterators.\n\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\n [1, 2, 3] -> .first() # iterator at 1\n \"abc\" -> .first() # iterator at \"a\"\n\nIterator protocol (dict with `value`, `done`, `next`):\n\n $it.done # bool: is exhausted?\n $it.value # current element\n $it.next() # returns new iterator at next position\n\n## Iteration Limits\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\n## Script Return Values\n\n| Return value | Exit code |\n|---|---|\n| `true` / non-empty string | 0 |\n| `false` / empty string | 1 |\n| `[0, \"message\"]` | 0 with message |\n| `[1, \"message\"]` | 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,
|
|
1
|
+
{"version":3,"file":"introspection-data.d.ts","sourceRoot":"","sources":["../../src/generated/introspection-data.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,kBAAkB,y0rBAkjB9B,CAAC"}
|