@rcrsr/rill 0.9.0 → 0.11.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 (169) hide show
  1. package/dist/ast-nodes.d.ts +43 -10
  2. package/dist/ast-nodes.d.ts.map +1 -1
  3. package/dist/ast-unions.d.ts +1 -1
  4. package/dist/ast-unions.d.ts.map +1 -1
  5. package/dist/constants.d.ts +1 -1
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +1 -0
  8. package/dist/constants.js.map +1 -1
  9. package/dist/error-registry.d.ts.map +1 -1
  10. package/dist/error-registry.js +273 -6
  11. package/dist/error-registry.js.map +1 -1
  12. package/dist/ext/crypto/index.d.ts.map +1 -1
  13. package/dist/ext/crypto/index.js +23 -12
  14. package/dist/ext/crypto/index.js.map +1 -1
  15. package/dist/ext/exec/index.d.ts.map +1 -1
  16. package/dist/ext/exec/index.js +10 -11
  17. package/dist/ext/exec/index.js.map +1 -1
  18. package/dist/ext/fetch/index.d.ts.map +1 -1
  19. package/dist/ext/fetch/index.js +15 -15
  20. package/dist/ext/fetch/index.js.map +1 -1
  21. package/dist/ext/fs/index.d.ts.map +1 -1
  22. package/dist/ext/fs/index.js +139 -47
  23. package/dist/ext/fs/index.js.map +1 -1
  24. package/dist/ext/kv/index.d.ts.map +1 -1
  25. package/dist/ext/kv/index.js +130 -31
  26. package/dist/ext/kv/index.js.map +1 -1
  27. package/dist/generated/introspection-data.d.ts +1 -1
  28. package/dist/generated/introspection-data.d.ts.map +1 -1
  29. package/dist/generated/introspection-data.js +109 -8
  30. package/dist/generated/introspection-data.js.map +1 -1
  31. package/dist/generated/version-data.d.ts +1 -1
  32. package/dist/generated/version-data.d.ts.map +1 -1
  33. package/dist/generated/version-data.js +2 -2
  34. package/dist/generated/version-data.js.map +1 -1
  35. package/dist/highlight-map.d.ts.map +1 -1
  36. package/dist/highlight-map.js +1 -0
  37. package/dist/highlight-map.js.map +1 -1
  38. package/dist/index.d.ts +3 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +1 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/lexer/readers.d.ts.map +1 -1
  43. package/dist/lexer/readers.js +1 -0
  44. package/dist/lexer/readers.js.map +1 -1
  45. package/dist/parser/index.d.ts +3 -1
  46. package/dist/parser/index.d.ts.map +1 -1
  47. package/dist/parser/index.js +4 -1
  48. package/dist/parser/index.js.map +1 -1
  49. package/dist/parser/parser-control.d.ts +1 -1
  50. package/dist/parser/parser-control.d.ts.map +1 -1
  51. package/dist/parser/parser-control.js +2 -2
  52. package/dist/parser/parser-control.js.map +1 -1
  53. package/dist/parser/parser-expr.d.ts +2 -1
  54. package/dist/parser/parser-expr.d.ts.map +1 -1
  55. package/dist/parser/parser-expr.js +15 -2
  56. package/dist/parser/parser-expr.js.map +1 -1
  57. package/dist/parser/parser-extract.d.ts.map +1 -1
  58. package/dist/parser/parser-extract.js +10 -9
  59. package/dist/parser/parser-extract.js.map +1 -1
  60. package/dist/parser/parser-functions.js +11 -6
  61. package/dist/parser/parser-functions.js.map +1 -1
  62. package/dist/parser/parser-literals.d.ts +1 -1
  63. package/dist/parser/parser-literals.d.ts.map +1 -1
  64. package/dist/parser/parser-literals.js +61 -7
  65. package/dist/parser/parser-literals.js.map +1 -1
  66. package/dist/parser/parser-types.d.ts +22 -6
  67. package/dist/parser/parser-types.d.ts.map +1 -1
  68. package/dist/parser/parser-types.js +126 -9
  69. package/dist/parser/parser-types.js.map +1 -1
  70. package/dist/parser/parser-use.d.ts +11 -0
  71. package/dist/parser/parser-use.d.ts.map +1 -0
  72. package/dist/parser/parser-use.js +68 -0
  73. package/dist/parser/parser-use.js.map +1 -0
  74. package/dist/parser/parser-variables.d.ts.map +1 -1
  75. package/dist/parser/parser-variables.js +5 -4
  76. package/dist/parser/parser-variables.js.map +1 -1
  77. package/dist/runtime/core/callable.d.ts +59 -70
  78. package/dist/runtime/core/callable.d.ts.map +1 -1
  79. package/dist/runtime/core/callable.js +37 -93
  80. package/dist/runtime/core/callable.js.map +1 -1
  81. package/dist/runtime/core/context.d.ts.map +1 -1
  82. package/dist/runtime/core/context.js +104 -33
  83. package/dist/runtime/core/context.js.map +1 -1
  84. package/dist/runtime/core/equals.d.ts.map +1 -1
  85. package/dist/runtime/core/equals.js +59 -17
  86. package/dist/runtime/core/equals.js.map +1 -1
  87. package/dist/runtime/core/eval/evaluator.d.ts.map +1 -1
  88. package/dist/runtime/core/eval/evaluator.js +2 -1
  89. package/dist/runtime/core/eval/evaluator.js.map +1 -1
  90. package/dist/runtime/core/eval/index.d.ts +2 -2
  91. package/dist/runtime/core/eval/index.d.ts.map +1 -1
  92. package/dist/runtime/core/eval/index.js +5 -0
  93. package/dist/runtime/core/eval/index.js.map +1 -1
  94. package/dist/runtime/core/eval/mixins/closures.d.ts +3 -5
  95. package/dist/runtime/core/eval/mixins/closures.d.ts.map +1 -1
  96. package/dist/runtime/core/eval/mixins/closures.js +76 -40
  97. package/dist/runtime/core/eval/mixins/closures.js.map +1 -1
  98. package/dist/runtime/core/eval/mixins/collections.d.ts.map +1 -1
  99. package/dist/runtime/core/eval/mixins/collections.js +4 -2
  100. package/dist/runtime/core/eval/mixins/collections.js.map +1 -1
  101. package/dist/runtime/core/eval/mixins/conversion.d.ts +9 -9
  102. package/dist/runtime/core/eval/mixins/conversion.d.ts.map +1 -1
  103. package/dist/runtime/core/eval/mixins/conversion.js +51 -21
  104. package/dist/runtime/core/eval/mixins/conversion.js.map +1 -1
  105. package/dist/runtime/core/eval/mixins/core.d.ts.map +1 -1
  106. package/dist/runtime/core/eval/mixins/core.js +8 -2
  107. package/dist/runtime/core/eval/mixins/core.js.map +1 -1
  108. package/dist/runtime/core/eval/mixins/extraction.d.ts.map +1 -1
  109. package/dist/runtime/core/eval/mixins/extraction.js +20 -8
  110. package/dist/runtime/core/eval/mixins/extraction.js.map +1 -1
  111. package/dist/runtime/core/eval/mixins/literals.d.ts.map +1 -1
  112. package/dist/runtime/core/eval/mixins/literals.js +32 -15
  113. package/dist/runtime/core/eval/mixins/literals.js.map +1 -1
  114. package/dist/runtime/core/eval/mixins/types.d.ts.map +1 -1
  115. package/dist/runtime/core/eval/mixins/types.js +166 -21
  116. package/dist/runtime/core/eval/mixins/types.js.map +1 -1
  117. package/dist/runtime/core/eval/mixins/use.d.ts +25 -0
  118. package/dist/runtime/core/eval/mixins/use.d.ts.map +1 -0
  119. package/dist/runtime/core/eval/mixins/use.js +152 -0
  120. package/dist/runtime/core/eval/mixins/use.js.map +1 -0
  121. package/dist/runtime/core/eval/mixins/variables.d.ts.map +1 -1
  122. package/dist/runtime/core/eval/mixins/variables.js +67 -32
  123. package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
  124. package/dist/runtime/core/execute.d.ts.map +1 -1
  125. package/dist/runtime/core/execute.js +11 -1
  126. package/dist/runtime/core/execute.js.map +1 -1
  127. package/dist/runtime/core/field-descriptor.d.ts +6 -6
  128. package/dist/runtime/core/field-descriptor.d.ts.map +1 -1
  129. package/dist/runtime/core/field-descriptor.js +2 -2
  130. package/dist/runtime/core/field-descriptor.js.map +1 -1
  131. package/dist/runtime/core/introspection.d.ts +16 -0
  132. package/dist/runtime/core/introspection.d.ts.map +1 -1
  133. package/dist/runtime/core/introspection.js +102 -7
  134. package/dist/runtime/core/introspection.js.map +1 -1
  135. package/dist/runtime/core/resolvers.d.ts +39 -0
  136. package/dist/runtime/core/resolvers.d.ts.map +1 -0
  137. package/dist/runtime/core/resolvers.js +89 -0
  138. package/dist/runtime/core/resolvers.js.map +1 -0
  139. package/dist/runtime/core/types.d.ts +54 -5
  140. package/dist/runtime/core/types.d.ts.map +1 -1
  141. package/dist/runtime/core/types.js.map +1 -1
  142. package/dist/runtime/core/values.d.ts +43 -29
  143. package/dist/runtime/core/values.d.ts.map +1 -1
  144. package/dist/runtime/core/values.js +153 -68
  145. package/dist/runtime/core/values.js.map +1 -1
  146. package/dist/runtime/ext/builtins.d.ts +3 -4
  147. package/dist/runtime/ext/builtins.d.ts.map +1 -1
  148. package/dist/runtime/ext/builtins.js +621 -444
  149. package/dist/runtime/ext/builtins.js.map +1 -1
  150. package/dist/runtime/ext/extensions.d.ts +43 -43
  151. package/dist/runtime/ext/extensions.d.ts.map +1 -1
  152. package/dist/runtime/ext/extensions.js.map +1 -1
  153. package/dist/runtime/index.d.ts +8 -5
  154. package/dist/runtime/index.d.ts.map +1 -1
  155. package/dist/runtime/index.js +6 -2
  156. package/dist/runtime/index.js.map +1 -1
  157. package/dist/signature-parser.d.ts +43 -0
  158. package/dist/signature-parser.d.ts.map +1 -0
  159. package/dist/signature-parser.js +289 -0
  160. package/dist/signature-parser.js.map +1 -0
  161. package/dist/token-types.d.ts +1 -0
  162. package/dist/token-types.d.ts.map +1 -1
  163. package/dist/token-types.js +1 -0
  164. package/dist/token-types.js.map +1 -1
  165. package/dist/value-types.d.ts +20 -6
  166. package/dist/value-types.d.ts.map +1 -1
  167. package/dist/value-types.js +1 -1
  168. package/dist/value-types.js.map +1 -1
  169. package/package.json +4 -1
@@ -65,101 +65,119 @@ function makeDictIterator(dict, index) {
65
65
  */
66
66
  export const BUILTIN_FUNCTIONS = {
67
67
  /** Identity function - returns its argument */
68
- identity: (args) => args[0] ?? null,
68
+ identity: {
69
+ signature: '|value: any|:any',
70
+ fn: (args) => args[0] ?? null,
71
+ },
69
72
  /** Log a value and return it unchanged (passthrough) */
70
- log: (args, ctx) => {
71
- const value = args[0] ?? null;
72
- const message = formatValue(value);
73
- ctx.callbacks.onLog(message);
74
- return value;
73
+ log: {
74
+ signature: '|message: any|',
75
+ fn: (args, ctx) => {
76
+ const value = args[0] ?? null;
77
+ const message = formatValue(value);
78
+ ctx.callbacks.onLog(message);
79
+ return value;
80
+ },
75
81
  },
76
82
  /** Convert any value to JSON string (throws RuntimeError RILL-R004 on closures, tuples, vectors) */
77
- json: (args, _ctx, location) => {
78
- const value = args[0] ?? null;
79
- try {
80
- const jsonValue = valueToJSON(value);
81
- return JSON.stringify(jsonValue);
82
- }
83
- catch (err) {
84
- if (err instanceof RuntimeError)
83
+ json: {
84
+ signature: '|value: any|:string',
85
+ fn: (args, _ctx, location) => {
86
+ const value = args[0] ?? null;
87
+ try {
88
+ const jsonValue = valueToJSON(value);
89
+ return JSON.stringify(jsonValue);
90
+ }
91
+ catch (err) {
92
+ if (err instanceof RuntimeError)
93
+ throw err;
94
+ if (err instanceof Error) {
95
+ throw new RuntimeError('RILL-R004', err.message, location);
96
+ }
85
97
  throw err;
86
- if (err instanceof Error) {
87
- throw new RuntimeError('RILL-R004', err.message, location);
88
98
  }
89
- throw err;
90
- }
99
+ },
91
100
  },
92
101
  /**
93
102
  * Enumerate a list or dict, returning list of indexed dicts.
94
103
  * List: enumerate([10, 20]) -> [[index: 0, value: 10], [index: 1, value: 20]]
95
104
  * Dict: enumerate([a: 1]) -> [[index: 0, key: "a", value: 1]]
96
105
  */
97
- enumerate: (args) => {
98
- const input = args[0] ?? null;
99
- if (Array.isArray(input)) {
100
- return input.map((value, index) => ({ index, value }));
101
- }
102
- if (isDict(input)) {
103
- const keys = Object.keys(input).sort();
104
- return keys.map((key, index) => ({
105
- index,
106
- key,
107
- value: input[key],
108
- }));
109
- }
110
- return [];
106
+ enumerate: {
107
+ signature: '|items: list | dict | string|:list',
108
+ fn: (args) => {
109
+ const input = args[0] ?? null;
110
+ if (Array.isArray(input)) {
111
+ return input.map((value, index) => ({ index, value }));
112
+ }
113
+ if (isDict(input)) {
114
+ const keys = Object.keys(input).sort();
115
+ return keys.map((key, index) => ({
116
+ index,
117
+ key,
118
+ value: input[key],
119
+ }));
120
+ }
121
+ return [];
122
+ },
111
123
  },
112
124
  /**
113
125
  * Create an iterator that generates a sequence of numbers.
114
126
  * range(start, end, step=1) - generates [start, start+step, ...] up to (but not including) end
115
127
  */
116
- range: (args, _ctx, location) => {
117
- const start = typeof args[0] === 'number' ? args[0] : 0;
118
- const end = typeof args[1] === 'number' ? args[1] : 0;
119
- const step = typeof args[2] === 'number' ? args[2] : 1;
120
- if (step === 0) {
121
- throw new RuntimeError('RILL-R001', 'range step cannot be zero', location);
122
- }
123
- const makeRangeIterator = (current) => {
124
- const done = step > 0 ? current >= end : step < 0 ? current <= end : true;
125
- if (done) {
128
+ range: {
129
+ signature: '|start: number, stop: number, step: number = 1|:iterator',
130
+ fn: (args, _ctx, location) => {
131
+ const start = typeof args[0] === 'number' ? args[0] : 0;
132
+ const end = typeof args[1] === 'number' ? args[1] : 0;
133
+ const step = typeof args[2] === 'number' ? args[2] : 1;
134
+ if (step === 0) {
135
+ throw new RuntimeError('RILL-R001', 'range step cannot be zero', location);
136
+ }
137
+ const makeRangeIterator = (current) => {
138
+ const done = step > 0 ? current >= end : step < 0 ? current <= end : true;
139
+ if (done) {
140
+ return {
141
+ done: true,
142
+ next: callable(() => makeRangeIterator(current)),
143
+ };
144
+ }
126
145
  return {
127
- done: true,
128
- next: callable(() => makeRangeIterator(current)),
146
+ value: current,
147
+ done: false,
148
+ next: callable(() => makeRangeIterator(current + step)),
129
149
  };
130
- }
131
- return {
132
- value: current,
133
- done: false,
134
- next: callable(() => makeRangeIterator(current + step)),
135
150
  };
136
- };
137
- return makeRangeIterator(start);
151
+ return makeRangeIterator(start);
152
+ },
138
153
  },
139
154
  /**
140
155
  * Create an iterator that repeats a value n times.
141
156
  * repeat(value, count) - generates value repeated count times
142
157
  */
143
- repeat: (args, _ctx, location) => {
144
- const value = args[0] ?? '';
145
- const count = typeof args[1] === 'number' ? Math.floor(args[1]) : 0;
146
- if (count < 0) {
147
- throw new RuntimeError('RILL-R001', 'repeat count cannot be negative', location);
148
- }
149
- const makeRepeatIterator = (remaining) => {
150
- if (remaining <= 0) {
158
+ repeat: {
159
+ signature: '|value: any, count: number|:iterator',
160
+ fn: (args, _ctx, location) => {
161
+ const value = args[0] ?? '';
162
+ const count = typeof args[1] === 'number' ? Math.floor(args[1]) : 0;
163
+ if (count < 0) {
164
+ throw new RuntimeError('RILL-R001', 'repeat count cannot be negative', location);
165
+ }
166
+ const makeRepeatIterator = (remaining) => {
167
+ if (remaining <= 0) {
168
+ return {
169
+ done: true,
170
+ next: callable(() => makeRepeatIterator(0)),
171
+ };
172
+ }
151
173
  return {
152
- done: true,
153
- next: callable(() => makeRepeatIterator(0)),
174
+ value,
175
+ done: false,
176
+ next: callable(() => makeRepeatIterator(remaining - 1)),
154
177
  };
155
- }
156
- return {
157
- value,
158
- done: false,
159
- next: callable(() => makeRepeatIterator(remaining - 1)),
160
178
  };
161
- };
162
- return makeRepeatIterator(count);
179
+ return makeRepeatIterator(count);
180
+ },
163
181
  },
164
182
  /**
165
183
  * Pipe a value through one or more closures, left-to-right.
@@ -168,35 +186,38 @@ export const BUILTIN_FUNCTIONS = {
168
186
  * chain(value, []) -> value unchanged
169
187
  * Non-closure/non-list second arg throws RILL-R040 (EC-14).
170
188
  */
171
- chain: async (args, ctx, location) => {
172
- // Pipe position: 5 -> chain($closure) sends args=[$closure] with pipeValue=5.
173
- // Detect this by checking if there is exactly one arg and a pipe value is set.
174
- let value;
175
- let arg;
176
- if (args.length === 1 && ctx.pipeValue !== null) {
177
- value = ctx.pipeValue;
178
- arg = args[0] ?? null;
179
- }
180
- else {
181
- value = args[0] ?? null;
182
- arg = args[1] ?? null;
183
- }
184
- if (Array.isArray(arg)) {
185
- // List of closures: fold left-to-right
186
- let result = value;
187
- for (const item of arg) {
188
- if (!isCallable(item)) {
189
- throw new RuntimeError('RILL-R040', `chain: list element must be a closure, got ${inferType(item)}`, location);
189
+ chain: {
190
+ signature: '|value: any, transform: any|:any',
191
+ fn: async (args, ctx, location) => {
192
+ // Pipe position: 5 -> chain($closure) sends args=[$closure] with pipeValue=5.
193
+ // Detect this by checking if there is exactly one arg and a pipe value is set.
194
+ let value;
195
+ let arg;
196
+ if (args.length === 1 && ctx.pipeValue !== null) {
197
+ value = ctx.pipeValue;
198
+ arg = args[0] ?? null;
199
+ }
200
+ else {
201
+ value = args[0] ?? null;
202
+ arg = args[1] ?? null;
203
+ }
204
+ if (Array.isArray(arg)) {
205
+ // List of closures: fold left-to-right
206
+ let result = value;
207
+ for (const item of arg) {
208
+ if (!isCallable(item)) {
209
+ throw new RuntimeError('RILL-R040', `chain: list element must be a closure, got ${inferType(item)}`, location);
210
+ }
211
+ result = await invokeCallable(item, [result], ctx, location);
190
212
  }
191
- result = await invokeCallable(item, [result], ctx, location);
213
+ return result;
192
214
  }
193
- return result;
194
- }
195
- if (isCallable(arg)) {
196
- // Single closure: invoke with value
197
- return invokeCallable(arg, [value], ctx, location);
198
- }
199
- throw new RuntimeError('RILL-R040', `chain: second argument must be a closure or list of closures, got ${inferType(arg)}`, location);
215
+ if (isCallable(arg)) {
216
+ // Single closure: invoke with value
217
+ return invokeCallable(arg, [value], ctx, location);
218
+ }
219
+ throw new RuntimeError('RILL-R040', `chain: second argument must be a closure or list of closures, got ${inferType(arg)}`, location);
220
+ },
200
221
  },
201
222
  };
202
223
  // ============================================================
@@ -212,452 +233,608 @@ function createComparisonMethod(compare) {
212
233
  return compare(formatValue(receiver), formatValue(arg ?? ''));
213
234
  };
214
235
  }
236
+ // receiverTypes convention:
237
+ // - Declare explicit types (e.g. ['string', 'list']) when dispatch enforcement is sufficient.
238
+ // - Use [] when the method body performs its own type checking (e.g. works across
239
+ // multiple types with distinct branches, or produces a custom error message).
215
240
  export const BUILTIN_METHODS = {
216
- // === Conversion methods ===
217
- /** Convert value to string */
218
- str: (receiver) => formatValue(receiver),
219
- /** Convert value to number */
220
- num: (receiver) => {
221
- if (typeof receiver === 'number')
222
- return receiver;
223
- if (typeof receiver === 'string') {
224
- const n = parseFloat(receiver);
225
- if (!isNaN(n))
226
- return n;
227
- }
228
- if (typeof receiver === 'boolean')
229
- return receiver ? 1 : 0;
230
- return 0;
231
- },
232
241
  /** Get length of string or array */
233
- len: (receiver) => {
234
- if (typeof receiver === 'string')
235
- return receiver.length;
236
- if (Array.isArray(receiver))
237
- return receiver.length;
238
- if (receiver && typeof receiver === 'object') {
239
- return Object.keys(receiver).length;
240
- }
241
- return 0;
242
+ len: {
243
+ signature: '||:number',
244
+ receiverTypes: ['string', 'list', 'dict'],
245
+ method: (receiver) => {
246
+ if (typeof receiver === 'string')
247
+ return receiver.length;
248
+ if (Array.isArray(receiver))
249
+ return receiver.length;
250
+ if (receiver && typeof receiver === 'object') {
251
+ return Object.keys(receiver).length;
252
+ }
253
+ return 0;
254
+ },
242
255
  },
243
256
  /** Trim whitespace from string */
244
- trim: (receiver) => formatValue(receiver).trim(),
257
+ trim: {
258
+ signature: '||:string',
259
+ receiverTypes: ['string'],
260
+ method: (receiver) => formatValue(receiver).trim(),
261
+ },
245
262
  // === Element access methods ===
246
263
  /** Get first element of array or first char of string */
247
- head: (receiver, _args, _ctx, location) => {
248
- if (Array.isArray(receiver)) {
249
- if (receiver.length === 0) {
250
- throw new RuntimeError('RILL-R002', 'Cannot get head of empty list', location);
264
+ head: {
265
+ signature: '||:any',
266
+ receiverTypes: [],
267
+ method: (receiver, _args, _ctx, location) => {
268
+ if (Array.isArray(receiver)) {
269
+ if (receiver.length === 0) {
270
+ throw new RuntimeError('RILL-R002', 'Cannot get head of empty list', location);
271
+ }
272
+ return receiver[0];
251
273
  }
252
- return receiver[0];
253
- }
254
- if (typeof receiver === 'string') {
255
- if (receiver.length === 0) {
256
- throw new RuntimeError('RILL-R002', 'Cannot get head of empty string', location);
274
+ if (typeof receiver === 'string') {
275
+ if (receiver.length === 0) {
276
+ throw new RuntimeError('RILL-R002', 'Cannot get head of empty string', location);
277
+ }
278
+ return receiver[0];
257
279
  }
258
- return receiver[0];
259
- }
260
- throw new RuntimeError('RILL-R003', `head requires list or string, got ${inferType(receiver)}`, location);
280
+ throw new RuntimeError('RILL-R003', `head requires list or string, got ${inferType(receiver)}`, location);
281
+ },
261
282
  },
262
283
  /** Get last element of array or last char of string */
263
- tail: (receiver, _args, _ctx, location) => {
264
- if (Array.isArray(receiver)) {
265
- if (receiver.length === 0) {
266
- throw new RuntimeError('RILL-R002', 'Cannot get tail of empty list', location);
284
+ tail: {
285
+ signature: '||:any',
286
+ receiverTypes: [],
287
+ method: (receiver, _args, _ctx, location) => {
288
+ if (Array.isArray(receiver)) {
289
+ if (receiver.length === 0) {
290
+ throw new RuntimeError('RILL-R002', 'Cannot get tail of empty list', location);
291
+ }
292
+ return receiver[receiver.length - 1];
267
293
  }
268
- return receiver[receiver.length - 1];
269
- }
270
- if (typeof receiver === 'string') {
271
- if (receiver.length === 0) {
272
- throw new RuntimeError('RILL-R002', 'Cannot get tail of empty string', location);
294
+ if (typeof receiver === 'string') {
295
+ if (receiver.length === 0) {
296
+ throw new RuntimeError('RILL-R002', 'Cannot get tail of empty string', location);
297
+ }
298
+ return receiver[receiver.length - 1];
273
299
  }
274
- return receiver[receiver.length - 1];
275
- }
276
- throw new RuntimeError('RILL-R003', `tail requires list or string, got ${inferType(receiver)}`, location);
300
+ throw new RuntimeError('RILL-R003', `tail requires list or string, got ${inferType(receiver)}`, location);
301
+ },
277
302
  },
278
303
  /** Get iterator at first position for any collection */
279
- first: (receiver, _args, _ctx, location) => {
280
- // For iterators, return as-is (identity)
281
- if (isRillIterator(receiver)) {
282
- return receiver;
283
- }
284
- // For lists
285
- if (Array.isArray(receiver)) {
286
- return makeListIterator(receiver, 0);
287
- }
288
- // For strings
289
- if (typeof receiver === 'string') {
290
- return makeStringIterator(receiver, 0);
291
- }
292
- // For dicts
293
- if (isDict(receiver)) {
294
- return makeDictIterator(receiver, 0);
295
- }
296
- throw new RuntimeError('RILL-R003', `first requires list, string, dict, or iterator, got ${inferType(receiver)}`, location);
304
+ first: {
305
+ signature: '||:iterator',
306
+ receiverTypes: [],
307
+ method: (receiver, _args, _ctx, location) => {
308
+ // For iterators, return as-is (identity)
309
+ if (isRillIterator(receiver)) {
310
+ return receiver;
311
+ }
312
+ // For lists
313
+ if (Array.isArray(receiver)) {
314
+ return makeListIterator(receiver, 0);
315
+ }
316
+ // For strings
317
+ if (typeof receiver === 'string') {
318
+ return makeStringIterator(receiver, 0);
319
+ }
320
+ // For dicts
321
+ if (isDict(receiver)) {
322
+ return makeDictIterator(receiver, 0);
323
+ }
324
+ throw new RuntimeError('RILL-R003', `first requires list, string, dict, or iterator, got ${inferType(receiver)}`, location);
325
+ },
297
326
  },
298
327
  /** Get element at index */
299
- at: (receiver, args, _ctx, location) => {
300
- const idx = typeof args[0] === 'number' ? args[0] : 0;
301
- if (Array.isArray(receiver)) {
302
- if (idx < 0 || idx >= receiver.length) {
303
- throw new RuntimeError('RILL-R002', `List index out of bounds: ${idx}`, location);
328
+ at: {
329
+ signature: '|index: number|:any',
330
+ receiverTypes: [],
331
+ method: (receiver, args, _ctx, location) => {
332
+ const idx = typeof args[0] === 'number' ? args[0] : 0;
333
+ if (Array.isArray(receiver)) {
334
+ if (idx < 0 || idx >= receiver.length) {
335
+ throw new RuntimeError('RILL-R002', `List index out of bounds: ${idx}`, location);
336
+ }
337
+ return receiver[idx];
304
338
  }
305
- return receiver[idx];
306
- }
307
- if (typeof receiver === 'string') {
308
- if (idx < 0 || idx >= receiver.length) {
309
- throw new RuntimeError('RILL-R002', `String index out of bounds: ${idx}`, location);
339
+ if (typeof receiver === 'string') {
340
+ if (idx < 0 || idx >= receiver.length) {
341
+ throw new RuntimeError('RILL-R002', `String index out of bounds: ${idx}`, location);
342
+ }
343
+ return receiver[idx];
310
344
  }
311
- return receiver[idx];
312
- }
313
- throw new RuntimeError('RILL-R003', `Cannot call .at() on ${typeof receiver}`, location);
345
+ throw new RuntimeError('RILL-R003', `Cannot call .at() on ${typeof receiver}`, location);
346
+ },
314
347
  },
315
348
  // === String operations ===
316
349
  /** Split string by separator (default: newline) */
317
- split: (receiver, args) => {
318
- const str = formatValue(receiver);
319
- const sep = typeof args[0] === 'string' ? args[0] : '\n';
320
- return str.split(sep);
350
+ split: {
351
+ signature: '|separator: string = "\\n"|:list',
352
+ receiverTypes: ['string'],
353
+ method: (receiver, args) => {
354
+ const str = formatValue(receiver);
355
+ const sep = typeof args[0] === 'string' ? args[0] : '\n';
356
+ return str.split(sep);
357
+ },
321
358
  },
322
359
  /** Join array elements with separator (default: comma) */
323
- join: (receiver, args) => {
324
- const sep = typeof args[0] === 'string' ? args[0] : ',';
325
- if (!Array.isArray(receiver))
326
- return formatValue(receiver);
327
- return receiver.map(formatValue).join(sep);
360
+ join: {
361
+ signature: '|separator: string = ","|:string',
362
+ receiverTypes: ['list'],
363
+ method: (receiver, args) => {
364
+ const sep = typeof args[0] === 'string' ? args[0] : ',';
365
+ if (!Array.isArray(receiver))
366
+ return formatValue(receiver);
367
+ return receiver.map(formatValue).join(sep);
368
+ },
328
369
  },
329
370
  /** Split string into lines (same as .split but newline only) */
330
- lines: (receiver) => {
331
- const str = formatValue(receiver);
332
- return str.split('\n');
371
+ lines: {
372
+ signature: '||:list',
373
+ receiverTypes: ['string'],
374
+ method: (receiver) => {
375
+ const str = formatValue(receiver);
376
+ return str.split('\n');
377
+ },
333
378
  },
334
379
  // === Utility methods ===
335
380
  /** Check if value is empty */
336
- empty: (receiver) => isEmpty(receiver),
381
+ empty: {
382
+ signature: '||:bool',
383
+ receiverTypes: ['string', 'list', 'dict', 'bool', 'number'],
384
+ method: (receiver) => isEmpty(receiver),
385
+ },
337
386
  // === String methods ===
338
387
  /** Check if string starts with prefix */
339
- starts_with: (receiver, args) => {
340
- const str = formatValue(receiver);
341
- const prefix = formatValue(args[0] ?? '');
342
- return str.startsWith(prefix);
388
+ starts_with: {
389
+ signature: '|prefix: string|:bool',
390
+ receiverTypes: ['string'],
391
+ method: (receiver, args) => {
392
+ const str = formatValue(receiver);
393
+ const prefix = formatValue(args[0] ?? '');
394
+ return str.startsWith(prefix);
395
+ },
343
396
  },
344
397
  /** Check if string ends with suffix */
345
- ends_with: (receiver, args) => {
346
- const str = formatValue(receiver);
347
- const suffix = formatValue(args[0] ?? '');
348
- return str.endsWith(suffix);
398
+ ends_with: {
399
+ signature: '|suffix: string|:bool',
400
+ receiverTypes: ['string'],
401
+ method: (receiver, args) => {
402
+ const str = formatValue(receiver);
403
+ const suffix = formatValue(args[0] ?? '');
404
+ return str.endsWith(suffix);
405
+ },
349
406
  },
350
407
  /** Convert string to lowercase */
351
- lower: (receiver) => formatValue(receiver).toLowerCase(),
408
+ lower: {
409
+ signature: '||:string',
410
+ receiverTypes: ['string'],
411
+ method: (receiver) => formatValue(receiver).toLowerCase(),
412
+ },
352
413
  /** Convert string to uppercase */
353
- upper: (receiver) => formatValue(receiver).toUpperCase(),
414
+ upper: {
415
+ signature: '||:string',
416
+ receiverTypes: ['string'],
417
+ method: (receiver) => formatValue(receiver).toUpperCase(),
418
+ },
354
419
  /** Replace first regex match */
355
- replace: (receiver, args) => {
356
- const str = formatValue(receiver);
357
- const pattern = formatValue(args[0] ?? '');
358
- const replacement = formatValue(args[1] ?? '');
359
- try {
360
- return str.replace(new RegExp(pattern), replacement);
361
- }
362
- catch {
363
- return str;
364
- }
420
+ replace: {
421
+ signature: '|pattern: string, replacement: string|:string',
422
+ receiverTypes: ['string'],
423
+ method: (receiver, args) => {
424
+ const str = formatValue(receiver);
425
+ const pattern = formatValue(args[0] ?? '');
426
+ const replacement = formatValue(args[1] ?? '');
427
+ try {
428
+ return str.replace(new RegExp(pattern), replacement);
429
+ }
430
+ catch {
431
+ return str;
432
+ }
433
+ },
365
434
  },
366
435
  /** Replace all regex matches */
367
- replace_all: (receiver, args) => {
368
- const str = formatValue(receiver);
369
- const pattern = formatValue(args[0] ?? '');
370
- const replacement = formatValue(args[1] ?? '');
371
- try {
372
- return str.replace(new RegExp(pattern, 'g'), replacement);
373
- }
374
- catch {
375
- return str;
376
- }
436
+ replace_all: {
437
+ signature: '|pattern: string, replacement: string|:string',
438
+ receiverTypes: ['string'],
439
+ method: (receiver, args) => {
440
+ const str = formatValue(receiver);
441
+ const pattern = formatValue(args[0] ?? '');
442
+ const replacement = formatValue(args[1] ?? '');
443
+ try {
444
+ return str.replace(new RegExp(pattern, 'g'), replacement);
445
+ }
446
+ catch {
447
+ return str;
448
+ }
449
+ },
377
450
  },
378
451
  /** Check if string contains substring */
379
- contains: (receiver, args) => {
380
- const str = formatValue(receiver);
381
- const search = formatValue(args[0] ?? '');
382
- return str.includes(search);
452
+ contains: {
453
+ signature: '|search: string|:bool',
454
+ receiverTypes: ['string'],
455
+ method: (receiver, args) => {
456
+ const str = formatValue(receiver);
457
+ const search = formatValue(args[0] ?? '');
458
+ return str.includes(search);
459
+ },
383
460
  },
384
461
  /**
385
462
  * First regex match info, or empty dict if no match.
386
463
  * Returns: [matched: string, index: number, groups: []]
387
464
  */
388
- match: (receiver, args) => {
389
- const str = formatValue(receiver);
390
- const pattern = formatValue(args[0] ?? '');
391
- try {
392
- const m = new RegExp(pattern).exec(str);
393
- if (!m)
465
+ match: {
466
+ signature: '|pattern: string|:dict',
467
+ receiverTypes: ['string'],
468
+ method: (receiver, args) => {
469
+ const str = formatValue(receiver);
470
+ const pattern = formatValue(args[0] ?? '');
471
+ try {
472
+ const m = new RegExp(pattern).exec(str);
473
+ if (!m)
474
+ return {};
475
+ return {
476
+ matched: m[0],
477
+ index: m.index,
478
+ groups: m.slice(1),
479
+ };
480
+ }
481
+ catch {
394
482
  return {};
395
- return {
396
- matched: m[0],
397
- index: m.index,
398
- groups: m.slice(1),
399
- };
400
- }
401
- catch {
402
- return {};
403
- }
483
+ }
484
+ },
404
485
  },
405
486
  /** True if regex matches anywhere in string */
406
- is_match: (receiver, args) => {
407
- const str = formatValue(receiver);
408
- const pattern = formatValue(args[0] ?? '');
409
- try {
410
- return new RegExp(pattern).test(str);
411
- }
412
- catch {
413
- return false;
414
- }
487
+ is_match: {
488
+ signature: '|pattern: string|:bool',
489
+ receiverTypes: ['string'],
490
+ method: (receiver, args) => {
491
+ const str = formatValue(receiver);
492
+ const pattern = formatValue(args[0] ?? '');
493
+ try {
494
+ return new RegExp(pattern).test(str);
495
+ }
496
+ catch {
497
+ return false;
498
+ }
499
+ },
415
500
  },
416
501
  /** Position of first substring occurrence (-1 if not found) */
417
- index_of: (receiver, args) => {
418
- const str = formatValue(receiver);
419
- const search = formatValue(args[0] ?? '');
420
- return str.indexOf(search);
502
+ index_of: {
503
+ signature: '|search: string|:number',
504
+ receiverTypes: ['string'],
505
+ method: (receiver, args) => {
506
+ const str = formatValue(receiver);
507
+ const search = formatValue(args[0] ?? '');
508
+ return str.indexOf(search);
509
+ },
421
510
  },
422
511
  /** Repeat string n times */
423
- repeat: (receiver, args) => {
424
- const str = formatValue(receiver);
425
- const n = typeof args[0] === 'number' ? Math.max(0, Math.floor(args[0])) : 0;
426
- return str.repeat(n);
512
+ repeat: {
513
+ signature: '|count: number|:string',
514
+ receiverTypes: ['string'],
515
+ method: (receiver, args) => {
516
+ const str = formatValue(receiver);
517
+ const n = typeof args[0] === 'number' ? Math.max(0, Math.floor(args[0])) : 0;
518
+ return str.repeat(n);
519
+ },
427
520
  },
428
521
  /** Pad start to length with fill string */
429
- pad_start: (receiver, args) => {
430
- const str = formatValue(receiver);
431
- const length = typeof args[0] === 'number' ? args[0] : str.length;
432
- const fill = typeof args[1] === 'string' ? args[1] : ' ';
433
- return str.padStart(length, fill);
522
+ pad_start: {
523
+ signature: '|length: number, fill: string = " "|:string',
524
+ receiverTypes: ['string'],
525
+ method: (receiver, args) => {
526
+ const str = formatValue(receiver);
527
+ const length = typeof args[0] === 'number' ? args[0] : str.length;
528
+ const fill = typeof args[1] === 'string' ? args[1] : ' ';
529
+ return str.padStart(length, fill);
530
+ },
434
531
  },
435
532
  /** Pad end to length with fill string */
436
- pad_end: (receiver, args) => {
437
- const str = formatValue(receiver);
438
- const length = typeof args[0] === 'number' ? args[0] : str.length;
439
- const fill = typeof args[1] === 'string' ? args[1] : ' ';
440
- return str.padEnd(length, fill);
533
+ pad_end: {
534
+ signature: '|length: number, fill: string = " "|:string',
535
+ receiverTypes: ['string'],
536
+ method: (receiver, args) => {
537
+ const str = formatValue(receiver);
538
+ const length = typeof args[0] === 'number' ? args[0] : str.length;
539
+ const fill = typeof args[1] === 'string' ? args[1] : ' ';
540
+ return str.padEnd(length, fill);
541
+ },
441
542
  },
442
543
  // === Comparison methods ===
443
544
  /** Equality check (deep structural comparison) */
444
- eq: (receiver, args) => deepEquals(receiver, args[0] ?? null),
545
+ eq: {
546
+ signature: '|other: any|:bool',
547
+ receiverTypes: [],
548
+ method: (receiver, args) => deepEquals(receiver, args[0] ?? null),
549
+ },
445
550
  /** Inequality check (deep structural comparison) */
446
- ne: (receiver, args) => !deepEquals(receiver, args[0] ?? null),
551
+ ne: {
552
+ signature: '|other: any|:bool',
553
+ receiverTypes: [],
554
+ method: (receiver, args) => !deepEquals(receiver, args[0] ?? null),
555
+ },
447
556
  /** Less than */
448
- lt: createComparisonMethod((a, b) => a < b),
557
+ lt: {
558
+ signature: '|other: any|:bool',
559
+ receiverTypes: ['number', 'string'],
560
+ method: createComparisonMethod((a, b) => a < b),
561
+ },
449
562
  /** Greater than */
450
- gt: createComparisonMethod((a, b) => a > b),
563
+ gt: {
564
+ signature: '|other: any|:bool',
565
+ receiverTypes: ['number', 'string'],
566
+ method: createComparisonMethod((a, b) => a > b),
567
+ },
451
568
  /** Less than or equal */
452
- le: createComparisonMethod((a, b) => a <= b),
569
+ le: {
570
+ signature: '|other: any|:bool',
571
+ receiverTypes: ['number', 'string'],
572
+ method: createComparisonMethod((a, b) => a <= b),
573
+ },
453
574
  /** Greater than or equal */
454
- ge: createComparisonMethod((a, b) => a >= b),
575
+ ge: {
576
+ signature: '|other: any|:bool',
577
+ receiverTypes: ['number', 'string'],
578
+ method: createComparisonMethod((a, b) => a >= b),
579
+ },
455
580
  // === Dict methods (reserved) ===
456
581
  /** Get all keys of a dict as a tuple of strings */
457
- keys: (receiver) => {
458
- if (isDict(receiver)) {
459
- return Object.keys(receiver);
460
- }
461
- return [];
582
+ keys: {
583
+ signature: '||:list',
584
+ receiverTypes: [],
585
+ method: (receiver) => {
586
+ if (isDict(receiver)) {
587
+ return Object.keys(receiver);
588
+ }
589
+ return [];
590
+ },
462
591
  },
463
592
  /** Get all values of a dict as a tuple */
464
- values: (receiver) => {
465
- if (isDict(receiver)) {
466
- return Object.values(receiver);
467
- }
468
- return [];
593
+ values: {
594
+ signature: '||:list',
595
+ receiverTypes: [],
596
+ method: (receiver) => {
597
+ if (isDict(receiver)) {
598
+ return Object.values(receiver);
599
+ }
600
+ return [];
601
+ },
469
602
  },
470
603
  /** Get all entries of a dict as a tuple of [key, value] pairs */
471
- entries: (receiver) => {
472
- if (isDict(receiver)) {
473
- return Object.entries(receiver).map(([k, v]) => [k, v]);
474
- }
475
- return [];
604
+ entries: {
605
+ signature: '||:list',
606
+ receiverTypes: [],
607
+ method: (receiver) => {
608
+ if (isDict(receiver)) {
609
+ return Object.entries(receiver).map(([k, v]) => [k, v]);
610
+ }
611
+ return [];
612
+ },
476
613
  },
477
614
  // === List membership methods ===
478
615
  /** Check if list contains value (deep equality) */
479
- has: (receiver, args, _ctx, location) => {
480
- if (!Array.isArray(receiver)) {
481
- throw new RuntimeError('RILL-R003', `has() requires list receiver, got ${inferType(receiver)}`, location);
482
- }
483
- if (args.length !== 1) {
484
- throw new RuntimeError('RILL-R001', `has() expects 1 argument, got ${args.length}`, location);
485
- }
486
- const searchValue = args[0] ?? null;
487
- for (const item of receiver) {
488
- if (deepEquals(item, searchValue)) {
489
- return true;
616
+ has: {
617
+ signature: '|value: any|:bool',
618
+ receiverTypes: [],
619
+ method: (receiver, args, _ctx, location) => {
620
+ if (!Array.isArray(receiver)) {
621
+ throw new RuntimeError('RILL-R003', `has() requires list receiver, got ${inferType(receiver)}`, location);
490
622
  }
491
- }
492
- return false;
493
- },
494
- /** Check if list contains any value from candidates (deep equality) */
495
- has_any: (receiver, args, _ctx, location) => {
496
- if (!Array.isArray(receiver)) {
497
- throw new RuntimeError('RILL-R003', `has_any() requires list receiver, got ${inferType(receiver)}`, location);
498
- }
499
- if (args.length !== 1) {
500
- throw new RuntimeError('RILL-R001', `has_any() expects 1 argument, got ${args.length}`, location);
501
- }
502
- const candidates = args[0] ?? null;
503
- if (!Array.isArray(candidates)) {
504
- throw new RuntimeError('RILL-R001', `has_any() expects list argument, got ${inferType(candidates)}`, location);
505
- }
506
- // Short-circuit on first match
507
- for (const candidate of candidates) {
623
+ if (args.length !== 1) {
624
+ throw new RuntimeError('RILL-R001', `has() expects 1 argument, got ${args.length}`, location);
625
+ }
626
+ const searchValue = args[0] ?? null;
508
627
  for (const item of receiver) {
509
- if (deepEquals(item, candidate)) {
628
+ if (deepEquals(item, searchValue)) {
510
629
  return true;
511
630
  }
512
631
  }
513
- }
514
- return false;
632
+ return false;
633
+ },
515
634
  },
516
- /** Check if list contains all values from candidates (deep equality) */
517
- has_all: (receiver, args, _ctx, location) => {
518
- if (!Array.isArray(receiver)) {
519
- throw new RuntimeError('RILL-R003', `has_all() requires list receiver, got ${inferType(receiver)}`, location);
520
- }
521
- if (args.length !== 1) {
522
- throw new RuntimeError('RILL-R001', `has_all() expects 1 argument, got ${args.length}`, location);
523
- }
524
- const candidates = args[0] ?? null;
525
- if (!Array.isArray(candidates)) {
526
- throw new RuntimeError('RILL-R001', `has_all() expects list argument, got ${inferType(candidates)}`, location);
527
- }
528
- // Short-circuit on first mismatch
529
- for (const candidate of candidates) {
530
- let found = false;
531
- for (const item of receiver) {
532
- if (deepEquals(item, candidate)) {
533
- found = true;
534
- break;
635
+ /** Check if list contains any value from candidates (deep equality) */
636
+ has_any: {
637
+ signature: '|candidates: list|:bool',
638
+ receiverTypes: [],
639
+ method: (receiver, args, _ctx, location) => {
640
+ if (!Array.isArray(receiver)) {
641
+ throw new RuntimeError('RILL-R003', `has_any() requires list receiver, got ${inferType(receiver)}`, location);
642
+ }
643
+ if (args.length !== 1) {
644
+ throw new RuntimeError('RILL-R001', `has_any() expects 1 argument, got ${args.length}`, location);
645
+ }
646
+ const candidates = args[0] ?? null;
647
+ if (!Array.isArray(candidates)) {
648
+ throw new RuntimeError('RILL-R001', `has_any() expects list argument, got ${inferType(candidates)}`, location);
649
+ }
650
+ // Short-circuit on first match
651
+ for (const candidate of candidates) {
652
+ for (const item of receiver) {
653
+ if (deepEquals(item, candidate)) {
654
+ return true;
655
+ }
535
656
  }
536
657
  }
537
- if (!found) {
538
- return false;
658
+ return false;
659
+ },
660
+ },
661
+ /** Check if list contains all values from candidates (deep equality) */
662
+ has_all: {
663
+ signature: '|candidates: list|:bool',
664
+ receiverTypes: [],
665
+ method: (receiver, args, _ctx, location) => {
666
+ if (!Array.isArray(receiver)) {
667
+ throw new RuntimeError('RILL-R003', `has_all() requires list receiver, got ${inferType(receiver)}`, location);
539
668
  }
540
- }
541
- return true;
669
+ if (args.length !== 1) {
670
+ throw new RuntimeError('RILL-R001', `has_all() expects 1 argument, got ${args.length}`, location);
671
+ }
672
+ const candidates = args[0] ?? null;
673
+ if (!Array.isArray(candidates)) {
674
+ throw new RuntimeError('RILL-R001', `has_all() expects list argument, got ${inferType(candidates)}`, location);
675
+ }
676
+ // Short-circuit on first mismatch
677
+ for (const candidate of candidates) {
678
+ let found = false;
679
+ for (const item of receiver) {
680
+ if (deepEquals(item, candidate)) {
681
+ found = true;
682
+ break;
683
+ }
684
+ }
685
+ if (!found) {
686
+ return false;
687
+ }
688
+ }
689
+ return true;
690
+ },
542
691
  },
543
692
  // === Vector methods ===
544
693
  /** Get number of dimensions in vector */
545
- dimensions: (receiver, _args, _ctx, location) => {
546
- if (!isVector(receiver)) {
547
- throw new RuntimeError('RILL-R003', `dimensions requires vector receiver, got ${inferType(receiver)}`, location);
548
- }
549
- return receiver.data.length;
694
+ dimensions: {
695
+ signature: '||:number',
696
+ receiverTypes: [],
697
+ method: (receiver, _args, _ctx, location) => {
698
+ if (!isVector(receiver)) {
699
+ throw new RuntimeError('RILL-R003', `dimensions requires vector receiver, got ${inferType(receiver)}`, location);
700
+ }
701
+ return receiver.data.length;
702
+ },
550
703
  },
551
704
  /** Get model name of vector */
552
- model: (receiver, _args, _ctx, location) => {
553
- if (!isVector(receiver)) {
554
- throw new RuntimeError('RILL-R003', `model requires vector receiver, got ${inferType(receiver)}`, location);
555
- }
556
- return receiver.model;
705
+ model: {
706
+ signature: '||:string',
707
+ receiverTypes: [],
708
+ method: (receiver, _args, _ctx, location) => {
709
+ if (!isVector(receiver)) {
710
+ throw new RuntimeError('RILL-R003', `model requires vector receiver, got ${inferType(receiver)}`, location);
711
+ }
712
+ return receiver.model;
713
+ },
557
714
  },
558
715
  /** Calculate cosine similarity between two vectors (range [-1, 1]) */
559
- similarity: (receiver, args, _ctx, location) => {
560
- if (!isVector(receiver)) {
561
- throw new RuntimeError('RILL-R003', `similarity requires vector receiver, got ${inferType(receiver)}`, location);
562
- }
563
- const other = args[0] ?? null;
564
- if (!isVector(other)) {
565
- throw new RuntimeError('RILL-R003', `expected vector, got ${inferType(other)}`, location);
566
- }
567
- if (receiver.data.length !== other.data.length) {
568
- throw new RuntimeError('RILL-R003', `vector dimension mismatch: ${receiver.data.length} vs ${other.data.length}`, location);
569
- }
570
- // Cosine similarity: dot(a, b) / (norm(a) * norm(b))
571
- let dotProduct = 0;
572
- let normA = 0;
573
- let normB = 0;
574
- for (let i = 0; i < receiver.data.length; i++) {
575
- const a = receiver.data[i];
576
- const b = other.data[i];
577
- dotProduct += a * b;
578
- normA += a * a;
579
- normB += b * b;
580
- }
581
- const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
582
- if (magnitude === 0)
583
- return 0;
584
- return dotProduct / magnitude;
716
+ similarity: {
717
+ signature: '|other: any|:number',
718
+ receiverTypes: [],
719
+ method: (receiver, args, _ctx, location) => {
720
+ if (!isVector(receiver)) {
721
+ throw new RuntimeError('RILL-R003', `similarity requires vector receiver, got ${inferType(receiver)}`, location);
722
+ }
723
+ const other = args[0] ?? null;
724
+ if (!isVector(other)) {
725
+ throw new RuntimeError('RILL-R003', `expected vector, got ${inferType(other)}`, location);
726
+ }
727
+ if (receiver.data.length !== other.data.length) {
728
+ throw new RuntimeError('RILL-R003', `vector dimension mismatch: ${receiver.data.length} vs ${other.data.length}`, location);
729
+ }
730
+ // Cosine similarity: dot(a, b) / (norm(a) * norm(b))
731
+ let dotProduct = 0;
732
+ let normA = 0;
733
+ let normB = 0;
734
+ for (let i = 0; i < receiver.data.length; i++) {
735
+ const a = receiver.data[i];
736
+ const b = other.data[i];
737
+ dotProduct += a * b;
738
+ normA += a * a;
739
+ normB += b * b;
740
+ }
741
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
742
+ if (magnitude === 0)
743
+ return 0;
744
+ return dotProduct / magnitude;
745
+ },
585
746
  },
586
747
  /** Calculate dot product between two vectors */
587
- dot: (receiver, args, _ctx, location) => {
588
- if (!isVector(receiver)) {
589
- throw new RuntimeError('RILL-R003', `dot requires vector receiver, got ${inferType(receiver)}`, location);
590
- }
591
- const other = args[0] ?? null;
592
- if (!isVector(other)) {
593
- throw new RuntimeError('RILL-R003', `expected vector, got ${inferType(other)}`, location);
594
- }
595
- if (receiver.data.length !== other.data.length) {
596
- throw new RuntimeError('RILL-R003', `vector dimension mismatch: ${receiver.data.length} vs ${other.data.length}`, location);
597
- }
598
- let result = 0;
599
- for (let i = 0; i < receiver.data.length; i++) {
600
- result += receiver.data[i] * other.data[i];
601
- }
602
- return result;
748
+ dot: {
749
+ signature: '|other: any|:number',
750
+ receiverTypes: [],
751
+ method: (receiver, args, _ctx, location) => {
752
+ if (!isVector(receiver)) {
753
+ throw new RuntimeError('RILL-R003', `dot requires vector receiver, got ${inferType(receiver)}`, location);
754
+ }
755
+ const other = args[0] ?? null;
756
+ if (!isVector(other)) {
757
+ throw new RuntimeError('RILL-R003', `expected vector, got ${inferType(other)}`, location);
758
+ }
759
+ if (receiver.data.length !== other.data.length) {
760
+ throw new RuntimeError('RILL-R003', `vector dimension mismatch: ${receiver.data.length} vs ${other.data.length}`, location);
761
+ }
762
+ let result = 0;
763
+ for (let i = 0; i < receiver.data.length; i++) {
764
+ result += receiver.data[i] * other.data[i];
765
+ }
766
+ return result;
767
+ },
603
768
  },
604
769
  /** Calculate Euclidean distance between two vectors (>= 0) */
605
- distance: (receiver, args, _ctx, location) => {
606
- if (!isVector(receiver)) {
607
- throw new RuntimeError('RILL-R003', `distance requires vector receiver, got ${inferType(receiver)}`, location);
608
- }
609
- const other = args[0] ?? null;
610
- if (!isVector(other)) {
611
- throw new RuntimeError('RILL-R003', `expected vector, got ${inferType(other)}`, location);
612
- }
613
- if (receiver.data.length !== other.data.length) {
614
- throw new RuntimeError('RILL-R003', `vector dimension mismatch: ${receiver.data.length} vs ${other.data.length}`, location);
615
- }
616
- let sumSquares = 0;
617
- for (let i = 0; i < receiver.data.length; i++) {
618
- const diff = receiver.data[i] - other.data[i];
619
- sumSquares += diff * diff;
620
- }
621
- return Math.sqrt(sumSquares);
770
+ distance: {
771
+ signature: '|other: any|:number',
772
+ receiverTypes: [],
773
+ method: (receiver, args, _ctx, location) => {
774
+ if (!isVector(receiver)) {
775
+ throw new RuntimeError('RILL-R003', `distance requires vector receiver, got ${inferType(receiver)}`, location);
776
+ }
777
+ const other = args[0] ?? null;
778
+ if (!isVector(other)) {
779
+ throw new RuntimeError('RILL-R003', `expected vector, got ${inferType(other)}`, location);
780
+ }
781
+ if (receiver.data.length !== other.data.length) {
782
+ throw new RuntimeError('RILL-R003', `vector dimension mismatch: ${receiver.data.length} vs ${other.data.length}`, location);
783
+ }
784
+ let sumSquares = 0;
785
+ for (let i = 0; i < receiver.data.length; i++) {
786
+ const diff = receiver.data[i] - other.data[i];
787
+ sumSquares += diff * diff;
788
+ }
789
+ return Math.sqrt(sumSquares);
790
+ },
622
791
  },
623
792
  /** Calculate L2 norm (magnitude) of vector */
624
- norm: (receiver, _args, _ctx, location) => {
625
- if (!isVector(receiver)) {
626
- throw new RuntimeError('RILL-R003', `norm requires vector receiver, got ${inferType(receiver)}`, location);
627
- }
628
- let sumSquares = 0;
629
- for (let i = 0; i < receiver.data.length; i++) {
630
- const val = receiver.data[i];
631
- sumSquares += val * val;
632
- }
633
- return Math.sqrt(sumSquares);
793
+ norm: {
794
+ signature: '||:number',
795
+ receiverTypes: [],
796
+ method: (receiver, _args, _ctx, location) => {
797
+ if (!isVector(receiver)) {
798
+ throw new RuntimeError('RILL-R003', `norm requires vector receiver, got ${inferType(receiver)}`, location);
799
+ }
800
+ let sumSquares = 0;
801
+ for (let i = 0; i < receiver.data.length; i++) {
802
+ const val = receiver.data[i];
803
+ sumSquares += val * val;
804
+ }
805
+ return Math.sqrt(sumSquares);
806
+ },
634
807
  },
635
808
  /** Create unit vector (preserves model) */
636
- normalize: (receiver, _args, _ctx, location) => {
637
- if (!isVector(receiver)) {
638
- throw new RuntimeError('RILL-R003', `normalize requires vector receiver, got ${inferType(receiver)}`, location);
639
- }
640
- // Calculate norm
641
- let sumSquares = 0;
642
- for (let i = 0; i < receiver.data.length; i++) {
643
- const val = receiver.data[i];
644
- sumSquares += val * val;
645
- }
646
- const magnitude = Math.sqrt(sumSquares);
647
- // If zero vector, return as-is
648
- if (magnitude === 0) {
649
- return receiver;
650
- }
651
- // Create normalized vector
652
- const normalized = new Float32Array(receiver.data.length);
653
- for (let i = 0; i < receiver.data.length; i++) {
654
- normalized[i] = receiver.data[i] / magnitude;
655
- }
656
- return {
657
- __rill_vector: true,
658
- data: normalized,
659
- model: receiver.model,
660
- };
809
+ normalize: {
810
+ signature: '||:any',
811
+ receiverTypes: [],
812
+ method: (receiver, _args, _ctx, location) => {
813
+ if (!isVector(receiver)) {
814
+ throw new RuntimeError('RILL-R003', `normalize requires vector receiver, got ${inferType(receiver)}`, location);
815
+ }
816
+ // Calculate norm
817
+ let sumSquares = 0;
818
+ for (let i = 0; i < receiver.data.length; i++) {
819
+ const val = receiver.data[i];
820
+ sumSquares += val * val;
821
+ }
822
+ const magnitude = Math.sqrt(sumSquares);
823
+ // If zero vector, return as-is
824
+ if (magnitude === 0) {
825
+ return receiver;
826
+ }
827
+ // Create normalized vector
828
+ const normalized = new Float32Array(receiver.data.length);
829
+ for (let i = 0; i < receiver.data.length; i++) {
830
+ normalized[i] = receiver.data[i] / magnitude;
831
+ }
832
+ return {
833
+ __rill_vector: true,
834
+ data: normalized,
835
+ model: receiver.model,
836
+ };
837
+ },
661
838
  },
662
839
  };
663
840
  //# sourceMappingURL=builtins.js.map