@rcrsr/rill 0.8.6 → 0.10.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.
- package/dist/ast-nodes.d.ts +189 -49
- package/dist/ast-nodes.d.ts.map +1 -1
- package/dist/ast-unions.d.ts +1 -1
- package/dist/ast-unions.d.ts.map +1 -1
- package/dist/constants.d.ts +14 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +30 -0
- package/dist/constants.js.map +1 -0
- package/dist/error-classes.d.ts +3 -1
- package/dist/error-classes.d.ts.map +1 -1
- package/dist/error-classes.js +11 -5
- package/dist/error-classes.js.map +1 -1
- package/dist/error-registry.d.ts.map +1 -1
- package/dist/error-registry.js +313 -11
- package/dist/error-registry.js.map +1 -1
- package/dist/ext/crypto/index.d.ts +2 -1
- package/dist/ext/crypto/index.d.ts.map +1 -1
- package/dist/ext/crypto/index.js +7 -0
- package/dist/ext/crypto/index.js.map +1 -1
- package/dist/ext/exec/index.d.ts +2 -1
- package/dist/ext/exec/index.d.ts.map +1 -1
- package/dist/ext/exec/index.js +6 -0
- package/dist/ext/exec/index.js.map +1 -1
- package/dist/ext/fetch/index.d.ts +2 -1
- package/dist/ext/fetch/index.d.ts.map +1 -1
- package/dist/ext/fetch/index.js +6 -0
- package/dist/ext/fetch/index.js.map +1 -1
- package/dist/ext/fs/index.d.ts +2 -1
- package/dist/ext/fs/index.d.ts.map +1 -1
- package/dist/ext/fs/index.js +3 -0
- package/dist/ext/fs/index.js.map +1 -1
- package/dist/ext/kv/index.d.ts +2 -1
- package/dist/ext/kv/index.d.ts.map +1 -1
- package/dist/ext/kv/index.js +5 -1
- package/dist/ext/kv/index.js.map +1 -1
- 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 +194 -185
- package/dist/generated/introspection-data.js.map +1 -1
- package/dist/generated/version-data.d.ts +1 -1
- package/dist/generated/version-data.d.ts.map +1 -1
- package/dist/generated/version-data.js +3 -3
- package/dist/generated/version-data.js.map +1 -1
- package/dist/highlight-map.d.ts.map +1 -1
- package/dist/highlight-map.js +8 -2
- package/dist/highlight-map.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lexer/operators.d.ts.map +1 -1
- package/dist/lexer/operators.js +0 -2
- package/dist/lexer/operators.js.map +1 -1
- package/dist/lexer/readers.d.ts +18 -1
- package/dist/lexer/readers.d.ts.map +1 -1
- package/dist/lexer/readers.js +55 -0
- package/dist/lexer/readers.js.map +1 -1
- package/dist/parser/helpers.d.ts +8 -13
- package/dist/parser/helpers.d.ts.map +1 -1
- package/dist/parser/helpers.js +42 -35
- package/dist/parser/helpers.js.map +1 -1
- package/dist/parser/index.d.ts +1 -0
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +1 -0
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/parser-collect.d.ts.map +1 -1
- package/dist/parser/parser-collect.js +34 -5
- package/dist/parser/parser-collect.js.map +1 -1
- package/dist/parser/parser-control.d.ts +1 -1
- package/dist/parser/parser-control.d.ts.map +1 -1
- package/dist/parser/parser-control.js +11 -2
- package/dist/parser/parser-control.js.map +1 -1
- package/dist/parser/parser-expr.d.ts +3 -1
- package/dist/parser/parser-expr.d.ts.map +1 -1
- package/dist/parser/parser-expr.js +377 -100
- package/dist/parser/parser-expr.js.map +1 -1
- package/dist/parser/parser-extract.d.ts +3 -5
- package/dist/parser/parser-extract.d.ts.map +1 -1
- package/dist/parser/parser-extract.js +37 -69
- package/dist/parser/parser-extract.js.map +1 -1
- package/dist/parser/parser-functions.d.ts +2 -2
- package/dist/parser/parser-functions.d.ts.map +1 -1
- package/dist/parser/parser-functions.js +112 -36
- package/dist/parser/parser-functions.js.map +1 -1
- package/dist/parser/parser-literals.d.ts +5 -4
- package/dist/parser/parser-literals.d.ts.map +1 -1
- package/dist/parser/parser-literals.js +316 -47
- package/dist/parser/parser-literals.js.map +1 -1
- package/dist/parser/parser-script.d.ts.map +1 -1
- package/dist/parser/parser-script.js +25 -12
- package/dist/parser/parser-script.js.map +1 -1
- package/dist/parser/parser-shape.d.ts +13 -0
- package/dist/parser/parser-shape.d.ts.map +1 -0
- package/dist/parser/parser-shape.js +72 -0
- package/dist/parser/parser-shape.js.map +1 -0
- package/dist/parser/parser-types.d.ts +31 -0
- package/dist/parser/parser-types.d.ts.map +1 -0
- package/dist/parser/parser-types.js +78 -0
- package/dist/parser/parser-types.js.map +1 -0
- package/dist/parser/parser-variables.d.ts.map +1 -1
- package/dist/parser/parser-variables.js +10 -1
- package/dist/parser/parser-variables.js.map +1 -1
- package/dist/runtime/core/callable.d.ts +27 -22
- package/dist/runtime/core/callable.d.ts.map +1 -1
- package/dist/runtime/core/callable.js +30 -26
- package/dist/runtime/core/callable.js.map +1 -1
- package/dist/runtime/core/context.d.ts.map +1 -1
- package/dist/runtime/core/context.js +8 -8
- package/dist/runtime/core/context.js.map +1 -1
- package/dist/runtime/core/equals.d.ts.map +1 -1
- package/dist/runtime/core/equals.js +179 -30
- package/dist/runtime/core/equals.js.map +1 -1
- package/dist/runtime/core/eval/base.d.ts +2 -2
- package/dist/runtime/core/eval/base.d.ts.map +1 -1
- package/dist/runtime/core/eval/evaluator.d.ts.map +1 -1
- package/dist/runtime/core/eval/evaluator.js +3 -1
- package/dist/runtime/core/eval/evaluator.js.map +1 -1
- package/dist/runtime/core/eval/index.d.ts +18 -3
- package/dist/runtime/core/eval/index.d.ts.map +1 -1
- package/dist/runtime/core/eval/index.js +22 -2
- package/dist/runtime/core/eval/index.js.map +1 -1
- package/dist/runtime/core/eval/mixins/annotations.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/annotations.js +14 -8
- package/dist/runtime/core/eval/mixins/annotations.js.map +1 -1
- package/dist/runtime/core/eval/mixins/closures.d.ts +0 -2
- package/dist/runtime/core/eval/mixins/closures.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/closures.js +341 -105
- package/dist/runtime/core/eval/mixins/closures.js.map +1 -1
- package/dist/runtime/core/eval/mixins/collections.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/collections.js +65 -25
- package/dist/runtime/core/eval/mixins/collections.js.map +1 -1
- package/dist/runtime/core/eval/mixins/control-flow.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/control-flow.js +21 -17
- package/dist/runtime/core/eval/mixins/control-flow.js.map +1 -1
- package/dist/runtime/core/eval/mixins/conversion.d.ts +30 -0
- package/dist/runtime/core/eval/mixins/conversion.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/conversion.js +212 -0
- package/dist/runtime/core/eval/mixins/conversion.js.map +1 -0
- package/dist/runtime/core/eval/mixins/core.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/core.js +101 -32
- package/dist/runtime/core/eval/mixins/core.js.map +1 -1
- package/dist/runtime/core/eval/mixins/extraction.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/extraction.js +136 -30
- package/dist/runtime/core/eval/mixins/extraction.js.map +1 -1
- package/dist/runtime/core/eval/mixins/list-dispatch.d.ts +17 -0
- package/dist/runtime/core/eval/mixins/list-dispatch.d.ts.map +1 -0
- package/dist/runtime/core/eval/mixins/list-dispatch.js +97 -0
- package/dist/runtime/core/eval/mixins/list-dispatch.js.map +1 -0
- package/dist/runtime/core/eval/mixins/literals.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/literals.js +73 -83
- package/dist/runtime/core/eval/mixins/literals.js.map +1 -1
- package/dist/runtime/core/eval/mixins/types.d.ts +4 -0
- package/dist/runtime/core/eval/mixins/types.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/types.js +323 -3
- package/dist/runtime/core/eval/mixins/types.js.map +1 -1
- package/dist/runtime/core/eval/mixins/variables.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/variables.js +45 -7
- package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
- package/dist/runtime/core/execute.d.ts.map +1 -1
- package/dist/runtime/core/execute.js +3 -16
- package/dist/runtime/core/execute.js.map +1 -1
- package/dist/runtime/core/field-descriptor.d.ts +29 -0
- package/dist/runtime/core/field-descriptor.d.ts.map +1 -0
- package/dist/runtime/core/field-descriptor.js +27 -0
- package/dist/runtime/core/field-descriptor.js.map +1 -0
- package/dist/runtime/core/types.d.ts +15 -6
- package/dist/runtime/core/types.d.ts.map +1 -1
- package/dist/runtime/core/types.js.map +1 -1
- package/dist/runtime/core/values.d.ts +114 -9
- package/dist/runtime/core/values.d.ts.map +1 -1
- package/dist/runtime/core/values.js +529 -43
- 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 +47 -107
- package/dist/runtime/ext/builtins.js.map +1 -1
- package/dist/runtime/ext/extensions.d.ts +21 -2
- package/dist/runtime/ext/extensions.d.ts.map +1 -1
- package/dist/runtime/ext/extensions.js.map +1 -1
- package/dist/runtime/index.d.ts +6 -4
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +7 -2
- package/dist/runtime/index.js.map +1 -1
- package/dist/token-types.d.ts +7 -2
- package/dist/token-types.d.ts.map +1 -1
- package/dist/token-types.js +9 -2
- package/dist/token-types.js.map +1 -1
- package/dist/value-types.d.ts +32 -1
- package/dist/value-types.d.ts.map +1 -1
- package/dist/value-types.js +1 -1
- package/dist/value-types.js.map +1 -1
- package/package.json +4 -1
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
* - Invoke operations
|
|
9
9
|
* - Pipe invocations
|
|
10
10
|
* - Property access on piped values
|
|
11
|
-
* - Closure chains
|
|
12
11
|
*
|
|
13
12
|
* Interface requirements (from spec):
|
|
14
13
|
* - invokeCallable(callable, args, location) -> Promise<RillValue>
|
|
@@ -20,7 +19,6 @@
|
|
|
20
19
|
* - evaluatePipeInvoke(node, input) -> Promise<RillValue>
|
|
21
20
|
* - evaluateMethod(node, receiver) -> Promise<RillValue>
|
|
22
21
|
* - evaluateInvoke(node, receiver) -> Promise<RillValue>
|
|
23
|
-
* - evaluateClosureChain(node, input) -> Promise<RillValue>
|
|
24
22
|
*
|
|
25
23
|
* Error Handling:
|
|
26
24
|
* - Undefined functions throw RuntimeError(RUNTIME_UNDEFINED_FUNCTION) [EC-18]
|
|
@@ -46,9 +44,9 @@
|
|
|
46
44
|
* @internal
|
|
47
45
|
*/
|
|
48
46
|
import { RuntimeError } from '../../../../types.js';
|
|
49
|
-
import { isCallable, isScriptCallable, isApplicationCallable, isDict, validateCallableArgs, } from '../../callable.js';
|
|
47
|
+
import { isCallable, isScriptCallable, isApplicationCallable, isDict, validateCallableArgs, paramsToStructuralType, } from '../../callable.js';
|
|
50
48
|
import { getVariable, pushCallFrame, popCallFrame } from '../../context.js';
|
|
51
|
-
import { inferType, isTuple } from '../../values.js';
|
|
49
|
+
import { inferType, isTypeValue, isTuple, isOrdered, createOrdered, inferStructuralType, structuralTypeMatches, formatStructuralType, } from '../../values.js';
|
|
52
50
|
/**
|
|
53
51
|
* ClosuresMixin implementation.
|
|
54
52
|
*
|
|
@@ -70,14 +68,13 @@ import { inferType, isTuple } from '../../values.js';
|
|
|
70
68
|
* - evaluatePipeInvoke(node, input) -> Promise<RillValue>
|
|
71
69
|
* - evaluateMethod(node, receiver) -> Promise<RillValue>
|
|
72
70
|
* - evaluateInvoke(node, receiver) -> Promise<RillValue>
|
|
73
|
-
* - evaluateClosureChain(node, input) -> Promise<RillValue>
|
|
74
71
|
* - evaluateArgs(argExprs) -> Promise<RillValue[]> (helper)
|
|
75
72
|
* - invokeFnCallable(callable, args, location) -> Promise<RillValue> (helper)
|
|
76
73
|
* - invokeScriptCallable(callable, args, location) -> Promise<RillValue> (helper)
|
|
77
|
-
* - invokeScriptCallableWithArgs(callable, tuple, location) -> Promise<RillValue> (helper)
|
|
78
74
|
* - createCallableContext(callable) -> RuntimeContext (helper)
|
|
79
75
|
* - validateParamType(param, value, location) -> void (helper)
|
|
80
76
|
* - inferTypeFromDefault(defaultValue) -> RillTypeName | null (helper)
|
|
77
|
+
* - bindArgsToParams(argNodes, callable, callLocation) -> Promise<BoundArgs> (helper)
|
|
81
78
|
*/
|
|
82
79
|
function createClosuresMixin(Base) {
|
|
83
80
|
return class ClosuresEvaluator extends Base {
|
|
@@ -89,8 +86,9 @@ function createClosuresMixin(Base) {
|
|
|
89
86
|
const savedPipeValue = this.ctx.pipeValue;
|
|
90
87
|
const args = [];
|
|
91
88
|
for (const arg of argExprs) {
|
|
89
|
+
const expr = arg.type === 'SpreadArg' ? arg.expression : arg;
|
|
92
90
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
|
-
args.push(await this.evaluateExpression(
|
|
91
|
+
args.push(await this.evaluateExpression(expr));
|
|
94
92
|
}
|
|
95
93
|
this.ctx.pipeValue = savedPipeValue;
|
|
96
94
|
return args;
|
|
@@ -188,7 +186,29 @@ function createClosuresMixin(Base) {
|
|
|
188
186
|
* Throws RuntimeError on type mismatch.
|
|
189
187
|
*/
|
|
190
188
|
validateParamType(param, value, callLocation) {
|
|
189
|
+
// IR-4: Structural dispatch — use typeStructure when sub-fields present
|
|
190
|
+
if (param.typeStructure !== undefined) {
|
|
191
|
+
const ts = param.typeStructure;
|
|
192
|
+
const hasSubFields = 'element' in ts ||
|
|
193
|
+
'fields' in ts ||
|
|
194
|
+
'elements' in ts ||
|
|
195
|
+
'params' in ts ||
|
|
196
|
+
'ret' in ts;
|
|
197
|
+
if (hasSubFields) {
|
|
198
|
+
if (!structuralTypeMatches(value, ts)) {
|
|
199
|
+
throw new RuntimeError('RILL-R001', `Parameter type mismatch: ${param.name} expects ${formatStructuralType(ts)}, got ${formatStructuralType(inferStructuralType(value))}`, callLocation, {
|
|
200
|
+
paramName: param.name,
|
|
201
|
+
expectedType: formatStructuralType(ts),
|
|
202
|
+
actualType: formatStructuralType(inferStructuralType(value)),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Backward-compatible leaf type check
|
|
191
209
|
const expectedType = param.typeName ?? this.inferTypeFromDefault(param.defaultValue);
|
|
210
|
+
if (expectedType === 'any')
|
|
211
|
+
return;
|
|
192
212
|
if (expectedType !== null) {
|
|
193
213
|
const valueType = inferType(value);
|
|
194
214
|
if (valueType !== expectedType) {
|
|
@@ -201,10 +221,6 @@ function createClosuresMixin(Base) {
|
|
|
201
221
|
* Handles parameter binding, default values, and type checking.
|
|
202
222
|
*/
|
|
203
223
|
async invokeScriptCallable(callable, args, callLocation) {
|
|
204
|
-
const firstArg = args[0];
|
|
205
|
-
if (args.length === 1 && firstArg !== undefined && isTuple(firstArg)) {
|
|
206
|
-
return this.invokeScriptCallableWithArgs(callable, firstArg, callLocation);
|
|
207
|
-
}
|
|
208
224
|
const callableCtx = this.createCallableContext(callable);
|
|
209
225
|
// Validate excess arguments (EC-8)
|
|
210
226
|
if (args.length > callable.params.length) {
|
|
@@ -229,78 +245,24 @@ function createClosuresMixin(Base) {
|
|
|
229
245
|
callableCtx.pipeValue = value;
|
|
230
246
|
}
|
|
231
247
|
}
|
|
248
|
+
// EC-1: Reject empty block bodies before execution (AC-17)
|
|
249
|
+
if (callable.body.type === 'Block' &&
|
|
250
|
+
callable.body.statements.length === 0) {
|
|
251
|
+
throw new RuntimeError('RILL-R043', 'Closure body produced no value', callLocation, { context: 'Closure body' });
|
|
252
|
+
}
|
|
232
253
|
// Switch context to callable context
|
|
233
254
|
const savedCtx = this.ctx;
|
|
234
255
|
this.ctx = callableCtx;
|
|
235
256
|
try {
|
|
236
257
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Invoke script callable with tuple arguments (named or positional).
|
|
245
|
-
* Handles *[...] and *[name: val] argument unpacking.
|
|
246
|
-
*/
|
|
247
|
-
async invokeScriptCallableWithArgs(closure, tupleValue, callLocation) {
|
|
248
|
-
const closureCtx = this.createCallableContext(closure);
|
|
249
|
-
const hasNumericKeys = [...tupleValue.entries.keys()].some((k) => typeof k === 'number');
|
|
250
|
-
const hasStringKeys = [...tupleValue.entries.keys()].some((k) => typeof k === 'string');
|
|
251
|
-
if (hasNumericKeys && hasStringKeys) {
|
|
252
|
-
throw new RuntimeError('RILL-R001', 'Tuple cannot mix positional (numeric) and named (string) keys', callLocation);
|
|
253
|
-
}
|
|
254
|
-
const boundParams = new Set();
|
|
255
|
-
if (hasNumericKeys) {
|
|
256
|
-
for (const [key, value] of tupleValue.entries) {
|
|
257
|
-
const position = key;
|
|
258
|
-
const param = closure.params[position];
|
|
259
|
-
if (param === undefined) {
|
|
260
|
-
throw new RuntimeError('RILL-R001', `Extra argument at position ${position} (closure has ${closure.params.length} params)`, callLocation, { position, paramCount: closure.params.length });
|
|
261
|
-
}
|
|
262
|
-
this.validateParamType(param, value, callLocation);
|
|
263
|
-
closureCtx.variables.set(param.name, value);
|
|
264
|
-
boundParams.add(param.name);
|
|
258
|
+
const result = await this.evaluateBodyExpression(callable.body);
|
|
259
|
+
// IR-4: Assert return value against declared returnShape (AC-14, AC-15, AC-16)
|
|
260
|
+
if (callable.returnShape !== undefined) {
|
|
261
|
+
// EC-4: Type assertion — value must match the declared scalar type
|
|
262
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
263
|
+
this.assertType(result, callable.returnShape.structure, callLocation);
|
|
265
264
|
}
|
|
266
|
-
|
|
267
|
-
else if (hasStringKeys) {
|
|
268
|
-
const paramNames = new Set(closure.params.map((p) => p.name));
|
|
269
|
-
for (const [key, value] of tupleValue.entries) {
|
|
270
|
-
const name = key;
|
|
271
|
-
if (!paramNames.has(name)) {
|
|
272
|
-
throw new RuntimeError('RILL-R001', `Unknown argument '${name}' (valid params: ${[...paramNames].join(', ')})`, callLocation, { argName: name, validParams: [...paramNames] });
|
|
273
|
-
}
|
|
274
|
-
const param = closure.params.find((p) => p.name === name);
|
|
275
|
-
this.validateParamType(param, value, callLocation);
|
|
276
|
-
closureCtx.variables.set(name, value);
|
|
277
|
-
// Block-closures have param named '$': sync with pipeValue for bare $ references
|
|
278
|
-
if (name === '$') {
|
|
279
|
-
closureCtx.pipeValue = value;
|
|
280
|
-
}
|
|
281
|
-
boundParams.add(name);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
for (const param of closure.params) {
|
|
285
|
-
if (!boundParams.has(param.name)) {
|
|
286
|
-
if (param.defaultValue !== null) {
|
|
287
|
-
closureCtx.variables.set(param.name, param.defaultValue);
|
|
288
|
-
// Block-closures have param named '$': sync with pipeValue for bare $ references
|
|
289
|
-
if (param.name === '$') {
|
|
290
|
-
closureCtx.pipeValue = param.defaultValue;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
throw new RuntimeError('RILL-R001', `Missing argument '${param.name}' (no default value)`, callLocation, { paramName: param.name });
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
// Switch context to callable context
|
|
299
|
-
const savedCtx = this.ctx;
|
|
300
|
-
this.ctx = closureCtx;
|
|
301
|
-
try {
|
|
302
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
303
|
-
return await this.evaluateBodyExpression(closure.body);
|
|
265
|
+
return result;
|
|
304
266
|
}
|
|
305
267
|
finally {
|
|
306
268
|
this.ctx = savedCtx;
|
|
@@ -316,6 +278,32 @@ function createClosuresMixin(Base) {
|
|
|
316
278
|
if (!fn) {
|
|
317
279
|
throw new RuntimeError('RILL-R006', `Unknown function: ${node.name}`, this.getNodeLocation(node), { functionName: node.name });
|
|
318
280
|
}
|
|
281
|
+
// EC-10/EC-11: spread-aware path for host calls
|
|
282
|
+
const hasSpread = node.args.some((a) => a.type === 'SpreadArg');
|
|
283
|
+
if (hasSpread) {
|
|
284
|
+
if (typeof fn === 'function') {
|
|
285
|
+
// EC-10: raw built-in (RuntimeCallable) — spread not supported
|
|
286
|
+
throw new RuntimeError('RILL-R001', `Spread not supported for built-in function '${node.name}'`, this.getNodeLocation(node), { functionName: node.name });
|
|
287
|
+
}
|
|
288
|
+
// EC-11: ApplicationCallable — bindArgsToParams handles no-params guard
|
|
289
|
+
const boundArgs = await this.bindArgsToParams(node.args, fn, node.span.start);
|
|
290
|
+
const orderedArgs = fn.params.map((p) => boundArgs.params.get(p.name));
|
|
291
|
+
// Observability: onHostCall before execution
|
|
292
|
+
this.ctx.observability.onHostCall?.({
|
|
293
|
+
name: node.name,
|
|
294
|
+
args: orderedArgs,
|
|
295
|
+
});
|
|
296
|
+
const startTime = performance.now();
|
|
297
|
+
const wrappedPromise = this.withTimeout(this.invokeCallable(fn, orderedArgs, node.span.start, node.name), this.ctx.timeout, node.name, node);
|
|
298
|
+
const result = await wrappedPromise;
|
|
299
|
+
const durationMs = performance.now() - startTime;
|
|
300
|
+
this.ctx.observability.onFunctionReturn?.({
|
|
301
|
+
name: node.name,
|
|
302
|
+
value: result,
|
|
303
|
+
durationMs,
|
|
304
|
+
});
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
319
307
|
const args = await this.evaluateArgs(node.args);
|
|
320
308
|
// Add pipe value to empty args list UNLESS function has typed params with length 0
|
|
321
309
|
// (typed functions with params: [] explicitly declare zero parameters)
|
|
@@ -359,6 +347,50 @@ function createClosuresMixin(Base) {
|
|
|
359
347
|
});
|
|
360
348
|
return result;
|
|
361
349
|
}
|
|
350
|
+
/**
|
|
351
|
+
* Evaluate host function reference: ns::name (no parens, namespaced).
|
|
352
|
+
*
|
|
353
|
+
* When pipeValue is null (value-capture context): returns the
|
|
354
|
+
* ApplicationCallable directly without invoking [IR-4].
|
|
355
|
+
*
|
|
356
|
+
* When pipeValue is set (pipe/branch context): invokes the callable
|
|
357
|
+
* with the pipe value as the implicit argument, consistent with how
|
|
358
|
+
* bare HostRef behaves as a pipe-stage expression [IR-4].
|
|
359
|
+
*
|
|
360
|
+
* Throws RILL-R006 when the function name is not registered [EC-4].
|
|
361
|
+
*/
|
|
362
|
+
async evaluateHostRef(node) {
|
|
363
|
+
this.checkAborted(node);
|
|
364
|
+
const fn = this.ctx.functions.get(node.name);
|
|
365
|
+
if (!fn) {
|
|
366
|
+
throw new RuntimeError('RILL-R006', `Function "${node.name}" not found`, this.getNodeLocation(node), { functionName: node.name });
|
|
367
|
+
}
|
|
368
|
+
// Build ApplicationCallable wrapper for raw CallableFn; pass through
|
|
369
|
+
// ApplicationCallable objects directly.
|
|
370
|
+
let appCallable;
|
|
371
|
+
if (typeof fn === 'function') {
|
|
372
|
+
appCallable = {
|
|
373
|
+
__type: 'callable',
|
|
374
|
+
kind: 'application',
|
|
375
|
+
fn,
|
|
376
|
+
params: undefined,
|
|
377
|
+
isProperty: false,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
appCallable = fn;
|
|
382
|
+
}
|
|
383
|
+
// Value-capture context: no pipe value → return callable without invoking [IR-4]
|
|
384
|
+
if (this.ctx.pipeValue === null) {
|
|
385
|
+
return appCallable;
|
|
386
|
+
}
|
|
387
|
+
// Pipe/branch context: pipe value present → invoke with it as implicit argument
|
|
388
|
+
const fnHasTypedZeroParams = appCallable.params !== undefined && appCallable.params.length === 0;
|
|
389
|
+
const args = fnHasTypedZeroParams
|
|
390
|
+
? []
|
|
391
|
+
: [this.ctx.pipeValue];
|
|
392
|
+
return this.invokeCallable(appCallable, args, this.getNodeLocation(node), node.name);
|
|
393
|
+
}
|
|
362
394
|
/**
|
|
363
395
|
* Evaluate closure call: $fn(args)
|
|
364
396
|
* Delegates to evaluateClosureCallWithPipe using current pipe value.
|
|
@@ -396,6 +428,15 @@ function createClosuresMixin(Base) {
|
|
|
396
428
|
throw new RuntimeError('RILL-R002', `'${fullPath}' is not callable`, this.getNodeLocation(node), { path: fullPath, actualType: inferType(value) });
|
|
397
429
|
}
|
|
398
430
|
const closure = value;
|
|
431
|
+
// Spread-aware path: when args contain a SpreadArgNode use bindArgsToParams
|
|
432
|
+
if (node.args.some((a) => a.type === 'SpreadArg')) {
|
|
433
|
+
if (!isScriptCallable(closure) && !isApplicationCallable(closure)) {
|
|
434
|
+
throw new RuntimeError('RILL-R001', `Spread not supported for built-in callable at '${fullPath}'`, this.getNodeLocation(node));
|
|
435
|
+
}
|
|
436
|
+
const boundArgs = await this.bindArgsToParams(node.args, closure, node.span.start);
|
|
437
|
+
const orderedArgs = closure.params.map((p) => boundArgs.params.get(p.name));
|
|
438
|
+
return this.invokeCallable(closure, orderedArgs, node.span.start, fullPath);
|
|
439
|
+
}
|
|
399
440
|
const args = await this.evaluateArgs(node.args);
|
|
400
441
|
// If no explicit args and has pipe input, add pipe value as first arg
|
|
401
442
|
// UNLESS closure has zero parameters (explicit zero-param signature)
|
|
@@ -464,6 +505,12 @@ function createClosuresMixin(Base) {
|
|
|
464
505
|
if (!isScriptCallable(input)) {
|
|
465
506
|
throw new RuntimeError('RILL-R002', `Cannot invoke non-closure value (got ${typeof input})`, this.getNodeLocation(node));
|
|
466
507
|
}
|
|
508
|
+
// Spread-aware path: when args contain a SpreadArgNode use bindArgsToParams
|
|
509
|
+
if (node.args.some((a) => a.type === 'SpreadArg')) {
|
|
510
|
+
const boundArgs = await this.bindArgsToParams(node.args, input, node.span.start);
|
|
511
|
+
const orderedArgs = input.params.map((p) => boundArgs.params.get(p.name));
|
|
512
|
+
return this.invokeScriptCallable(input, orderedArgs, node.span.start);
|
|
513
|
+
}
|
|
467
514
|
const args = await this.evaluateArgs(node.args);
|
|
468
515
|
return this.invokeScriptCallable(input, args, node.span.start);
|
|
469
516
|
}
|
|
@@ -480,6 +527,16 @@ function createClosuresMixin(Base) {
|
|
|
480
527
|
if (isCallable(receiver)) {
|
|
481
528
|
throw new RuntimeError('RILL-R003', `Method .${node.name} not available on callable (invoke with -> $() first)`, this.getNodeLocation(node), { methodName: node.name, receiverType: 'callable' });
|
|
482
529
|
}
|
|
530
|
+
// IR-3: .name on type values returns the typeName string (method path)
|
|
531
|
+
// IR-4: .signature on type values returns formatStructuralType(structure)
|
|
532
|
+
if (isTypeValue(receiver)) {
|
|
533
|
+
if (node.name === 'name') {
|
|
534
|
+
return receiver.typeName;
|
|
535
|
+
}
|
|
536
|
+
if (node.name === 'signature') {
|
|
537
|
+
return formatStructuralType(receiver.structure);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
483
540
|
const args = await this.evaluateArgs(node.args);
|
|
484
541
|
if (isDict(receiver)) {
|
|
485
542
|
const dictValue = receiver[node.name];
|
|
@@ -493,6 +550,10 @@ function createClosuresMixin(Base) {
|
|
|
493
550
|
if (isDict(receiver) && args.length === 0 && node.name in receiver) {
|
|
494
551
|
return receiver[node.name];
|
|
495
552
|
}
|
|
553
|
+
// EC-5: Unknown dot property on type value raises RILL-R009
|
|
554
|
+
if (isTypeValue(receiver)) {
|
|
555
|
+
throw new RuntimeError('RILL-R009', `Property '${node.name}' not found on type value (available: name, signature)`, this.getNodeLocation(node), { property: node.name, type: 'type value' });
|
|
556
|
+
}
|
|
496
557
|
throw new RuntimeError('RILL-R007', `Unknown method: ${node.name}`, this.getNodeLocation(node), { methodName: node.name });
|
|
497
558
|
}
|
|
498
559
|
const result = method(receiver, args, this.ctx, this.getNodeLocation(node));
|
|
@@ -506,35 +567,17 @@ function createClosuresMixin(Base) {
|
|
|
506
567
|
if (!isCallable(receiver)) {
|
|
507
568
|
throw new RuntimeError('RILL-R002', `Cannot invoke non-callable value (got ${inferType(receiver)})`, this.getNodeLocation(node), { actualType: inferType(receiver) });
|
|
508
569
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
* Evaluate closure chain: >>expr
|
|
514
|
-
* Chains multiple closures for composition.
|
|
515
|
-
*/
|
|
516
|
-
async evaluateClosureChain(node, input) {
|
|
517
|
-
// Evaluate the target expression to get the closure(s)
|
|
518
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
519
|
-
const target = await this.evaluateExpression(node.target);
|
|
520
|
-
if (Array.isArray(target)) {
|
|
521
|
-
// List of closures: chain them left-to-right
|
|
522
|
-
let result = input;
|
|
523
|
-
for (const closure of target) {
|
|
524
|
-
if (!isCallable(closure)) {
|
|
525
|
-
throw new RuntimeError('RILL-R002', `Closure chain element must be callable, got ${inferType(closure)}`, this.getNodeLocation(node));
|
|
526
|
-
}
|
|
527
|
-
result = await this.invokeCallable(closure, [result], this.getNodeLocation(node));
|
|
570
|
+
// Spread-aware path: when args contain a SpreadArgNode use bindArgsToParams
|
|
571
|
+
if (node.args.some((a) => a.type === 'SpreadArg')) {
|
|
572
|
+
if (!isScriptCallable(receiver) && !isApplicationCallable(receiver)) {
|
|
573
|
+
throw new RuntimeError('RILL-R001', `Spread not supported for built-in callable`, this.getNodeLocation(node));
|
|
528
574
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
// Single closure: invoke with input
|
|
533
|
-
return this.invokeCallable(target, [input], this.getNodeLocation(node));
|
|
534
|
-
}
|
|
535
|
-
else {
|
|
536
|
-
throw new RuntimeError('RILL-R002', `Closure chain requires callable or list of callables, got ${inferType(target)}`, this.getNodeLocation(node));
|
|
575
|
+
const boundArgs = await this.bindArgsToParams(node.args, receiver, node.span.start);
|
|
576
|
+
const orderedArgs = receiver.params.map((p) => boundArgs.params.get(p.name));
|
|
577
|
+
return this.invokeCallable(receiver, orderedArgs, node.span.start);
|
|
537
578
|
}
|
|
579
|
+
const args = await this.evaluateArgs(node.args);
|
|
580
|
+
return this.invokeCallable(receiver, args, this.getNodeLocation(node));
|
|
538
581
|
}
|
|
539
582
|
/**
|
|
540
583
|
* Evaluate annotation reflection access: .^key
|
|
@@ -545,9 +588,72 @@ function createClosuresMixin(Base) {
|
|
|
545
588
|
* Throws RUNTIME_UNDEFINED_ANNOTATION for missing annotations.
|
|
546
589
|
*/
|
|
547
590
|
async evaluateAnnotationAccess(value, key, location) {
|
|
591
|
+
// IR-2: .^type returns a RillTypeValue for any rill value
|
|
592
|
+
if (key === 'type') {
|
|
593
|
+
const typeValue = Object.freeze({
|
|
594
|
+
__rill_type: true,
|
|
595
|
+
typeName: inferType(value),
|
|
596
|
+
structure: inferStructuralType(value),
|
|
597
|
+
});
|
|
598
|
+
return typeValue;
|
|
599
|
+
}
|
|
600
|
+
// IR-5: .^name on type values raises RILL-R008 (type values are not annotation containers)
|
|
601
|
+
if (isTypeValue(value) && key === 'name') {
|
|
602
|
+
throw new RuntimeError('RILL-R008', `Annotation access not supported on type values`, location, { annotationKey: key });
|
|
603
|
+
}
|
|
604
|
+
// IR-2/IR-5: .^input returns the input shape for callable values
|
|
605
|
+
// Params are converted from internal tuples to RillOrdered so the
|
|
606
|
+
// value survives rill's homogeneous-list constraint.
|
|
607
|
+
if (key === 'input') {
|
|
608
|
+
if (isScriptCallable(value)) {
|
|
609
|
+
const shape = value.inputShape;
|
|
610
|
+
if (shape.type === 'closure') {
|
|
611
|
+
return {
|
|
612
|
+
type: shape.type,
|
|
613
|
+
params: createOrdered(shape.params),
|
|
614
|
+
ret: value.returnShape !== undefined
|
|
615
|
+
? value.returnShape.structure
|
|
616
|
+
: shape.ret,
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
return shape;
|
|
620
|
+
}
|
|
621
|
+
if (isApplicationCallable(value)) {
|
|
622
|
+
if (value.params === undefined) {
|
|
623
|
+
// IR-5: untyped host function — no shape available
|
|
624
|
+
return false;
|
|
625
|
+
}
|
|
626
|
+
const shape = paramsToStructuralType(value.params);
|
|
627
|
+
if (shape.type === 'closure') {
|
|
628
|
+
return {
|
|
629
|
+
type: shape.type,
|
|
630
|
+
params: createOrdered(shape.params),
|
|
631
|
+
ret: shape.ret,
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
return shape;
|
|
635
|
+
}
|
|
636
|
+
// Non-callable: fall through to existing RILL-R003 guard below
|
|
637
|
+
}
|
|
638
|
+
// IR-3: .^output returns the declared output contract for callable values
|
|
639
|
+
if (key === 'output') {
|
|
640
|
+
if (isScriptCallable(value)) {
|
|
641
|
+
if (value.returnShape !== undefined) {
|
|
642
|
+
return value.returnShape;
|
|
643
|
+
}
|
|
644
|
+
// No :type-target declared — return type value `any` (AC-17, AC-18, AC-19)
|
|
645
|
+
const anyTypeValue = Object.freeze({
|
|
646
|
+
__rill_type: true,
|
|
647
|
+
typeName: 'any',
|
|
648
|
+
structure: { type: 'any' },
|
|
649
|
+
});
|
|
650
|
+
return anyTypeValue;
|
|
651
|
+
}
|
|
652
|
+
// Non-callable: fall through to existing RILL-R003 guard below
|
|
653
|
+
}
|
|
548
654
|
// Only ScriptCallable supports annotation reflection
|
|
549
655
|
if (!isScriptCallable(value)) {
|
|
550
|
-
throw new RuntimeError('RILL-R003', `
|
|
656
|
+
throw new RuntimeError('RILL-R003', `annotation not found: ^${key}`, location, { actualType: inferType(value) });
|
|
551
657
|
}
|
|
552
658
|
// Access annotation from ScriptCallable
|
|
553
659
|
const annotationValue = value.annotations[key];
|
|
@@ -557,6 +663,136 @@ function createClosuresMixin(Base) {
|
|
|
557
663
|
}
|
|
558
664
|
return annotationValue;
|
|
559
665
|
}
|
|
666
|
+
/**
|
|
667
|
+
* Bind argument nodes to callable parameters when a SpreadArgNode is present.
|
|
668
|
+
*
|
|
669
|
+
* Evaluates positional args LTR, evaluates the spread expression, dispatches
|
|
670
|
+
* by value type (Tuple, Ordered, or Dict), validates bindings, and returns
|
|
671
|
+
* a Map of param name → value.
|
|
672
|
+
*
|
|
673
|
+
* EC-3: bare ... with null pipe value → RuntimeError
|
|
674
|
+
* EC-4: spread value is not tuple/dict/ordered → RuntimeError
|
|
675
|
+
* EC-5: dict spread key matches no parameter → RuntimeError
|
|
676
|
+
* EC-6: ordered spread key at position N mismatches param at position N → RuntimeError
|
|
677
|
+
* EC-7: duplicate binding (positional + spread) → RuntimeError
|
|
678
|
+
* EC-8: missing required parameter after all args processed → RuntimeError
|
|
679
|
+
* EC-9: extra tuple values exceed param count → RuntimeError
|
|
680
|
+
* EC-11: ApplicationCallable with no params metadata → RuntimeError
|
|
681
|
+
*/
|
|
682
|
+
async bindArgsToParams(argNodes, callable, callLocation) {
|
|
683
|
+
// EC-11: ApplicationCallable must have params metadata for spread to work
|
|
684
|
+
if (callable.kind === 'application' && callable.params === undefined) {
|
|
685
|
+
const name = callable.fn.name !== '' ? callable.fn.name : '<anonymous>';
|
|
686
|
+
throw new RuntimeError('RILL-R001', `Spread not supported for host function '${name}': parameter metadata required`, callLocation);
|
|
687
|
+
}
|
|
688
|
+
const params = callable.params;
|
|
689
|
+
const bound = new Map();
|
|
690
|
+
// Positional index: next unbound parameter position
|
|
691
|
+
let positionalIndex = 0;
|
|
692
|
+
// Save pipe value so evaluating args does not mutate it permanently
|
|
693
|
+
const savedPipeValue = this.ctx.pipeValue;
|
|
694
|
+
try {
|
|
695
|
+
for (const argNode of argNodes) {
|
|
696
|
+
if (argNode.type !== 'SpreadArg') {
|
|
697
|
+
// Positional argument
|
|
698
|
+
const param = params[positionalIndex];
|
|
699
|
+
if (param === undefined) {
|
|
700
|
+
// Extra positional arg beyond param count — EC-9 reports after spread
|
|
701
|
+
// but for pure positional excess, error here with the positional count
|
|
702
|
+
throw new RuntimeError('RILL-R001', `Extra positional argument at position ${positionalIndex} (function has ${params.length} parameters)`, callLocation);
|
|
703
|
+
}
|
|
704
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
705
|
+
const value = await this.evaluateExpression(argNode);
|
|
706
|
+
bound.set(param.name, value);
|
|
707
|
+
positionalIndex++;
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
// SpreadArg: evaluate the expression
|
|
711
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
712
|
+
const spreadValue = await this.evaluateExpression(argNode.expression);
|
|
713
|
+
// EC-3: bare ... with no pipe value evaluates to null
|
|
714
|
+
if (spreadValue === null) {
|
|
715
|
+
throw new RuntimeError('RILL-R001', 'Spread requires an active pipe value ($)', callLocation);
|
|
716
|
+
}
|
|
717
|
+
// Dispatch by type: isOrdered BEFORE isDict per spec (IC-3 algorithm step 2)
|
|
718
|
+
if (isTuple(spreadValue)) {
|
|
719
|
+
// Tuple: fill remaining params positionally LTR (EC-9)
|
|
720
|
+
const tupleEntries = spreadValue.entries;
|
|
721
|
+
const remaining = params.length - positionalIndex;
|
|
722
|
+
if (tupleEntries.length > remaining) {
|
|
723
|
+
throw new RuntimeError('RILL-R001', `Spread tuple has ${tupleEntries.length} values but only ${remaining} parameter(s) remain`, callLocation);
|
|
724
|
+
}
|
|
725
|
+
for (let i = 0; i < tupleEntries.length; i++) {
|
|
726
|
+
const param = params[positionalIndex + i];
|
|
727
|
+
// EC-7: duplicate binding
|
|
728
|
+
if (bound.has(param.name)) {
|
|
729
|
+
throw new RuntimeError('RILL-R001', `Duplicate binding for parameter '${param.name}': already bound positionally`, callLocation);
|
|
730
|
+
}
|
|
731
|
+
bound.set(param.name, tupleEntries[i]);
|
|
732
|
+
}
|
|
733
|
+
positionalIndex += tupleEntries.length;
|
|
734
|
+
}
|
|
735
|
+
else if (isOrdered(spreadValue)) {
|
|
736
|
+
// Ordered: match key by name AND position
|
|
737
|
+
// Key at position N within ordered value must match param at (spreadStart + N)
|
|
738
|
+
const orderedEntries = spreadValue.entries;
|
|
739
|
+
for (let i = 0; i < orderedEntries.length; i++) {
|
|
740
|
+
const [key, value] = orderedEntries[i];
|
|
741
|
+
const expectedParam = params[positionalIndex + i];
|
|
742
|
+
// EC-6: key-order mismatch
|
|
743
|
+
if (expectedParam === undefined || expectedParam.name !== key) {
|
|
744
|
+
const expectedName = expectedParam?.name ?? '<none>';
|
|
745
|
+
throw new RuntimeError('RILL-R001', `Ordered spread key '${key}' at position ${i} does not match expected parameter '${expectedName}' at position ${positionalIndex + i}`, callLocation);
|
|
746
|
+
}
|
|
747
|
+
// EC-7: duplicate binding
|
|
748
|
+
if (bound.has(key)) {
|
|
749
|
+
throw new RuntimeError('RILL-R001', `Duplicate binding for parameter '${key}': already bound positionally`, callLocation);
|
|
750
|
+
}
|
|
751
|
+
bound.set(key, value);
|
|
752
|
+
}
|
|
753
|
+
positionalIndex += orderedEntries.length;
|
|
754
|
+
}
|
|
755
|
+
else if (isDict(spreadValue)) {
|
|
756
|
+
// Dict: match each key to param by name (order irrelevant)
|
|
757
|
+
const dictValue = spreadValue;
|
|
758
|
+
const paramNames = new Set(params.map((p) => p.name));
|
|
759
|
+
for (const [key, value] of Object.entries(dictValue)) {
|
|
760
|
+
// EC-5: key matches no parameter
|
|
761
|
+
if (!paramNames.has(key)) {
|
|
762
|
+
const validParams = params.map((p) => p.name).join(', ');
|
|
763
|
+
throw new RuntimeError('RILL-R001', `Dict spread key '${key}' does not match any parameter. Valid parameters: ${validParams}`, callLocation);
|
|
764
|
+
}
|
|
765
|
+
// EC-7: duplicate binding
|
|
766
|
+
if (bound.has(key)) {
|
|
767
|
+
throw new RuntimeError('RILL-R001', `Duplicate binding for parameter '${key}': already bound positionally`, callLocation);
|
|
768
|
+
}
|
|
769
|
+
bound.set(key, value);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
// EC-4: spread value is not tuple/dict/ordered
|
|
774
|
+
const actualType = inferType(spreadValue);
|
|
775
|
+
throw new RuntimeError('RILL-R001', `Spread requires a tuple, dict, or ordered value, got ${actualType}`, callLocation);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
finally {
|
|
781
|
+
this.ctx.pipeValue = savedPipeValue;
|
|
782
|
+
}
|
|
783
|
+
// EC-8: check for missing required parameters
|
|
784
|
+
for (const param of params) {
|
|
785
|
+
if (!bound.has(param.name)) {
|
|
786
|
+
if (param.defaultValue !== null) {
|
|
787
|
+
bound.set(param.name, param.defaultValue);
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
throw new RuntimeError('RILL-R001', `Missing required parameter '${param.name}'`, callLocation);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
return { params: bound };
|
|
795
|
+
}
|
|
560
796
|
/**
|
|
561
797
|
* Evaluate .params property access on closures.
|
|
562
798
|
* Builds dict from closure parameter metadata.
|