@opencode/codemode 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/codemode.d.ts +7 -2
- package/dist/codemode.js +15 -2
- package/dist/data.d.ts +14 -21
- package/dist/data.js +72 -140
- package/dist/extension.d.ts +11 -0
- package/dist/extension.js +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/callback.d.ts +20 -0
- package/dist/interpreter/{runner.js → callback.js} +14 -14
- package/dist/interpreter/errors.d.ts +12 -5
- package/dist/interpreter/errors.js +66 -54
- package/dist/interpreter/execute.d.ts +2 -2
- package/dist/interpreter/execute.js +15 -15
- package/dist/interpreter/extensions.d.ts +8 -0
- package/dist/interpreter/extensions.js +160 -0
- package/dist/interpreter/generators.d.ts +2 -3
- package/dist/interpreter/generators.js +10 -10
- package/dist/interpreter/globals.d.ts +4 -12
- package/dist/interpreter/globals.js +56 -49
- package/dist/interpreter/interpreter.d.ts +34 -0
- package/dist/interpreter/{runtime.js → interpreter.js} +250 -215
- package/dist/interpreter/intrinsics.d.ts +5 -5
- package/dist/interpreter/intrinsics.js +16 -10
- package/dist/interpreter/limits.d.ts +10 -0
- package/dist/interpreter/limits.js +19 -0
- package/dist/interpreter/model.d.ts +27 -14
- package/dist/interpreter/model.js +22 -14
- package/dist/interpreter/native.d.ts +12 -13
- package/dist/interpreter/native.js +17 -16
- package/dist/interpreter/objects.d.ts +55 -48
- package/dist/interpreter/objects.js +64 -44
- package/dist/interpreter/promises.d.ts +13 -15
- package/dist/interpreter/promises.js +89 -85
- package/dist/interpreter/references.d.ts +1 -2
- package/dist/interpreter/references.js +18 -16
- package/dist/interpreter/scope.js +6 -6
- package/dist/openapi/types.d.ts +1 -1
- package/dist/stdlib/array.d.ts +3 -4
- package/dist/stdlib/array.js +115 -110
- package/dist/stdlib/bytes.d.ts +10 -0
- package/dist/stdlib/bytes.js +228 -0
- package/dist/stdlib/collections.d.ts +4 -4
- package/dist/stdlib/collections.js +89 -89
- package/dist/stdlib/console.d.ts +5 -3
- package/dist/stdlib/console.js +30 -37
- package/dist/stdlib/date.d.ts +2 -2
- package/dist/stdlib/date.js +35 -35
- package/dist/stdlib/json.d.ts +3 -3
- package/dist/stdlib/json.js +29 -67
- package/dist/stdlib/math.d.ts +3 -3
- package/dist/stdlib/math.js +17 -21
- package/dist/stdlib/number.d.ts +3 -3
- package/dist/stdlib/number.js +32 -36
- package/dist/stdlib/object.d.ts +5 -5
- package/dist/stdlib/object.js +59 -62
- package/dist/stdlib/regexp.d.ts +7 -8
- package/dist/stdlib/regexp.js +40 -48
- package/dist/stdlib/string.d.ts +2 -2
- package/dist/stdlib/string.js +110 -88
- package/dist/stdlib/url.d.ts +4 -6
- package/dist/stdlib/url.js +86 -90
- package/dist/stdlib/value.d.ts +3 -3
- package/dist/stdlib/value.js +26 -24
- package/dist/stdlib/web.d.ts +4 -4
- package/dist/stdlib/web.js +22 -8
- package/dist/tool-runtime.d.ts +38 -19
- package/dist/tool-runtime.js +70 -48
- package/package.json +1 -1
- package/dist/interpreter/runner.d.ts +0 -28
- package/dist/interpreter/runtime.d.ts +0 -19
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit } from "effect";
|
|
2
|
-
import {
|
|
2
|
+
import { fromJson, toBoundary } from "../data.js";
|
|
3
3
|
import { ToolReference } from "../tool-runtime.js";
|
|
4
|
-
import { AsyncIteratorSymbol,
|
|
5
|
-
import {
|
|
4
|
+
import { AsyncIteratorSymbol, CallSite, GeneratorReturn, IteratorSymbol, OptionalShortCircuit, invalidData, Throw, rangeError, typeError, unsupportedSyntax, } from "./model.js";
|
|
5
|
+
import { checkStringLength } from "./limits.js";
|
|
6
|
+
import { locate, materialize } from "./errors.js";
|
|
6
7
|
import { globals } from "./globals.js";
|
|
7
|
-
import { assign, Callable, define, get, has, hasPrototype, keys,
|
|
8
|
-
import { preserveConsumerError } from "./
|
|
9
|
-
import {
|
|
8
|
+
import { assign, Callable, define, get, has, hasPrototype, keys, Native, parseArrayIndex, Arr, Bytes, DateObj, Fn, GeneratorObj, MapObj, Obj, PromiseObj, SetObj, URLSearchParamsObj, record, remove, set, } from "./objects.js";
|
|
9
|
+
import { preserveConsumerError } from "./callback.js";
|
|
10
|
+
import { Pending, resolvePromise, resolvePromiseValue } from "./promises.js";
|
|
10
11
|
import { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue } from "./references.js";
|
|
11
12
|
import { ScopeStack } from "./scope.js";
|
|
12
13
|
import { constructRegExp } from "../stdlib/regexp.js";
|
|
@@ -45,11 +46,11 @@ const calleeDescription = (callee) => {
|
|
|
45
46
|
// OrdinaryHasInstance: walk the left operand's chain looking for the constructor's `prototype`.
|
|
46
47
|
const instanceofValue = (lhs, rhs, node) => {
|
|
47
48
|
if (!(rhs instanceof Callable)) {
|
|
48
|
-
throw
|
|
49
|
+
throw typeError("The right-hand side of 'instanceof' is not callable.", node);
|
|
49
50
|
}
|
|
50
51
|
const prototype = get(rhs, "prototype");
|
|
51
|
-
if (!(prototype instanceof
|
|
52
|
-
throw
|
|
52
|
+
if (!(prototype instanceof Obj)) {
|
|
53
|
+
throw typeError("The right-hand side of 'instanceof' has no 'prototype' object.", node);
|
|
53
54
|
}
|
|
54
55
|
return hasPrototype(lhs, prototype);
|
|
55
56
|
};
|
|
@@ -132,7 +133,7 @@ const loopDeclaration = (left, statement) => {
|
|
|
132
133
|
return undefined;
|
|
133
134
|
const declaration = left.declarations.length === 1 ? left.declarations[0] : undefined;
|
|
134
135
|
if (declaration === undefined) {
|
|
135
|
-
throw
|
|
136
|
+
throw typeError(`${statement} supports one declared binding.`, left);
|
|
136
137
|
}
|
|
137
138
|
const kind = left.kind;
|
|
138
139
|
return {
|
|
@@ -141,50 +142,60 @@ const loopDeclaration = (left, statement) => {
|
|
|
141
142
|
lexical: kind !== "var",
|
|
142
143
|
};
|
|
143
144
|
};
|
|
144
|
-
const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
|
|
145
145
|
/** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
|
|
146
|
-
export class
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
promises;
|
|
151
|
-
prototypes;
|
|
146
|
+
export class Interpreter {
|
|
147
|
+
tools;
|
|
148
|
+
pending;
|
|
149
|
+
builtins;
|
|
152
150
|
logs;
|
|
153
|
-
runner;
|
|
154
151
|
root;
|
|
155
|
-
constructor(
|
|
156
|
-
this.
|
|
157
|
-
this.
|
|
158
|
-
this.
|
|
159
|
-
this.
|
|
160
|
-
this.prototypes = prototypes;
|
|
161
|
-
this.logs = logs;
|
|
152
|
+
constructor(options) {
|
|
153
|
+
this.tools = options.tools;
|
|
154
|
+
this.pending = options.pending;
|
|
155
|
+
this.builtins = options.builtins;
|
|
156
|
+
this.logs = options.logs ?? [];
|
|
162
157
|
const globalScope = new Map();
|
|
163
158
|
// Calling back into the program never reads frame state, so any frame serves; the root is always alive.
|
|
164
159
|
this.root = new Frame(this, new ScopeStack([globalScope]));
|
|
165
|
-
this.
|
|
166
|
-
invokeCallable: (callable, thisValue, args, node) => this.root.invokeCallable(callable, thisValue, args, node),
|
|
167
|
-
settlePromise: (promise) => this.root.settlePromise(promise),
|
|
168
|
-
syncIterator: (value, node) => this.root.syncIterator(value, node),
|
|
169
|
-
prototypes,
|
|
170
|
-
};
|
|
171
|
-
for (const [name, value] of [...globals(this), ...extraGlobals(this)]) {
|
|
160
|
+
for (const [name, value] of [...globals(this), ...(options.globals?.(this) ?? [])]) {
|
|
172
161
|
globalScope.set(name, { mutable: false, value });
|
|
173
162
|
}
|
|
174
163
|
}
|
|
175
164
|
run(program) {
|
|
176
165
|
return this.root.run(program);
|
|
177
166
|
}
|
|
167
|
+
call(callable, thisValue, args) {
|
|
168
|
+
return this.root.call(callable, thisValue, args);
|
|
169
|
+
}
|
|
170
|
+
await(promise) {
|
|
171
|
+
return this.root.await(promise);
|
|
172
|
+
}
|
|
173
|
+
iterate(value) {
|
|
174
|
+
return this.root.iterate(value);
|
|
175
|
+
}
|
|
176
|
+
/** Runs one host tool: arguments cross as JSON and the result comes back as program values. */
|
|
177
|
+
tool(run, args) {
|
|
178
|
+
const ctx = this;
|
|
179
|
+
return Effect.gen(function* () {
|
|
180
|
+
const json = yield* Effect.forEach(args, (arg) => toBoundary(ctx, arg));
|
|
181
|
+
return fromJson(ctx, yield* run(json));
|
|
182
|
+
});
|
|
183
|
+
}
|
|
178
184
|
}
|
|
185
|
+
const MAX_CALL_DEPTH = 10_000;
|
|
179
186
|
/** One activation: the top-level program or a single function call, evaluating against its own scope chain. */
|
|
180
187
|
class Frame {
|
|
181
|
-
|
|
188
|
+
ctx;
|
|
182
189
|
scopes;
|
|
190
|
+
depth;
|
|
183
191
|
generatorState;
|
|
184
192
|
generatorAsync = false;
|
|
185
|
-
constructor(
|
|
186
|
-
|
|
193
|
+
constructor(ctx, scopes,
|
|
194
|
+
/** Nested call depth; resets when an await resumes, since the continuation runs from the job queue. */
|
|
195
|
+
depth = 0) {
|
|
196
|
+
this.ctx = ctx;
|
|
187
197
|
this.scopes = scopes;
|
|
198
|
+
this.depth = depth;
|
|
188
199
|
}
|
|
189
200
|
run(program) {
|
|
190
201
|
const self = this;
|
|
@@ -206,24 +217,24 @@ class Frame {
|
|
|
206
217
|
break;
|
|
207
218
|
}
|
|
208
219
|
if (result.kind === "break" || result.kind === "continue") {
|
|
209
|
-
throw
|
|
220
|
+
throw typeError(`Unexpected '${result.kind}' outside of a loop.`, statement);
|
|
210
221
|
}
|
|
211
222
|
}
|
|
212
223
|
// The implicit async body adopts returned promises before copy-out.
|
|
213
|
-
value = yield* resolvePromiseValue(self.
|
|
224
|
+
value = yield* resolvePromiseValue(self.ctx, value);
|
|
214
225
|
return value;
|
|
215
226
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
216
227
|
}
|
|
217
228
|
// Fork at the call site so admission and hooks occur when the call is made.
|
|
218
229
|
createToolCallPromise(path, args) {
|
|
219
|
-
return this.
|
|
230
|
+
return this.ctx.pending.create(this.ctx.tool((json) => this.ctx.tools.execute(path, json), args));
|
|
220
231
|
}
|
|
221
232
|
// Fiber exits make settlement idempotent; yielding prevents inline continuation.
|
|
222
|
-
|
|
223
|
-
const
|
|
233
|
+
await(promise) {
|
|
234
|
+
const pending = this.ctx.pending;
|
|
224
235
|
return Effect.suspend(() => {
|
|
225
|
-
|
|
226
|
-
return Effect.flatMap(
|
|
236
|
+
pending.markObserved(promise);
|
|
237
|
+
return Effect.flatMap(pending.await(promise), (exit) => Effect.andThen(Effect.yieldNow, exit));
|
|
227
238
|
});
|
|
228
239
|
}
|
|
229
240
|
evaluateStatement(node) {
|
|
@@ -289,7 +300,7 @@ class Frame {
|
|
|
289
300
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
290
301
|
}
|
|
291
302
|
createFunction(node, name = node.type === "ArrowFunctionExpression" ? "" : (node.id?.name ?? "")) {
|
|
292
|
-
return new
|
|
303
|
+
return new Fn(this.ctx.builtins.Function, name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
|
|
293
304
|
}
|
|
294
305
|
// NamedEvaluation: an anonymous function definition takes the name of what it is assigned to.
|
|
295
306
|
evaluateNamed(node, name) {
|
|
@@ -348,7 +359,7 @@ class Frame {
|
|
|
348
359
|
return Effect.gen(function* () {
|
|
349
360
|
const discriminant = yield* self.evaluateExpression(node.discriminant);
|
|
350
361
|
if (containsOpaqueReference(discriminant)) {
|
|
351
|
-
throw
|
|
362
|
+
throw invalidData("Switch discriminants must be data values.", node);
|
|
352
363
|
}
|
|
353
364
|
self.scopes.push();
|
|
354
365
|
return yield* Effect.gen(function* () {
|
|
@@ -366,7 +377,7 @@ class Frame {
|
|
|
366
377
|
}
|
|
367
378
|
const candidate = yield* self.evaluateExpression(test);
|
|
368
379
|
if (containsOpaqueReference(candidate)) {
|
|
369
|
-
throw
|
|
380
|
+
throw invalidData("Switch case values must be data values.", test);
|
|
370
381
|
}
|
|
371
382
|
if (candidate === discriminant) {
|
|
372
383
|
selected = index;
|
|
@@ -467,9 +478,9 @@ class Frame {
|
|
|
467
478
|
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
468
479
|
const right = yield* self.evaluateExpression(node.right);
|
|
469
480
|
const iterator = yield* self.customIterator(right, node, awaiting);
|
|
470
|
-
const cursor = iterator === undefined ? yield* self.
|
|
481
|
+
const cursor = iterator === undefined ? yield* self.iterate(right, node) : undefined;
|
|
471
482
|
if (iterator === undefined && cursor === undefined) {
|
|
472
|
-
throw
|
|
483
|
+
throw invalidData(`${awaiting ? "for await...of" : "for...of"} requires an array, string, Map, Set, or URLSearchParams, or custom iterator value.`, node);
|
|
473
484
|
}
|
|
474
485
|
const close = () => iterator
|
|
475
486
|
? self.closeIterator(iterator, node, awaiting)
|
|
@@ -477,7 +488,7 @@ class Frame {
|
|
|
477
488
|
? Effect.andThen(cursor?.close ?? Effect.void, Effect.yieldNow)
|
|
478
489
|
: (cursor?.close ?? Effect.void);
|
|
479
490
|
if (left.type === "RestElement" || left.type === "AssignmentPattern") {
|
|
480
|
-
throw
|
|
491
|
+
throw typeError("Unsupported for...of binding.", left);
|
|
481
492
|
}
|
|
482
493
|
const assignment = left.type === "VariableDeclaration" ? undefined : left;
|
|
483
494
|
const evaluateBody = (value) => Effect.gen(function* () {
|
|
@@ -500,7 +511,7 @@ class Frame {
|
|
|
500
511
|
while (true) {
|
|
501
512
|
const current = iterator
|
|
502
513
|
? yield* self.nextIteratorResult(iterator, node, awaiting)
|
|
503
|
-
: yield* cursor?.next ?? Effect.
|
|
514
|
+
: yield* cursor?.next ?? Effect.die(typeError("Iterator is unavailable.", node));
|
|
504
515
|
const step = cursor && awaiting ? { done: current.done, value: yield* self.awaitValue(current.value) } : current;
|
|
505
516
|
if (step.done)
|
|
506
517
|
return { kind: "none" };
|
|
@@ -523,8 +534,8 @@ class Frame {
|
|
|
523
534
|
self.scopes.pop();
|
|
524
535
|
})));
|
|
525
536
|
}
|
|
526
|
-
awaitValue(value
|
|
527
|
-
return Effect.flatMap(resolvePromise(this.
|
|
537
|
+
awaitValue(value) {
|
|
538
|
+
return Effect.flatMap(resolvePromise(this.ctx, value), (promise) => Effect.ensuring(this.await(promise), Effect.sync(() => (this.depth = 0))));
|
|
528
539
|
}
|
|
529
540
|
awaitAsyncFromSyncValue(iterator, value, node, closeOnRejection) {
|
|
530
541
|
const self = this;
|
|
@@ -538,26 +549,28 @@ class Frame {
|
|
|
538
549
|
return yield* Effect.failCause(settled.cause);
|
|
539
550
|
});
|
|
540
551
|
}
|
|
541
|
-
|
|
542
|
-
const iterator = value instanceof
|
|
552
|
+
iterate(value, node) {
|
|
553
|
+
const iterator = value instanceof Arr
|
|
543
554
|
? value.items[Symbol.iterator]()
|
|
544
555
|
: typeof value === "string"
|
|
545
556
|
? value[Symbol.iterator]()
|
|
546
|
-
: value instanceof
|
|
557
|
+
: value instanceof MapObj
|
|
547
558
|
? value.map.entries()
|
|
548
|
-
: value instanceof
|
|
559
|
+
: value instanceof SetObj
|
|
549
560
|
? value.set.values()
|
|
550
|
-
: value instanceof
|
|
561
|
+
: value instanceof URLSearchParamsObj
|
|
551
562
|
? value.params.entries()
|
|
552
|
-
:
|
|
563
|
+
: value instanceof Bytes
|
|
564
|
+
? value.bytes.values()
|
|
565
|
+
: undefined;
|
|
553
566
|
if (iterator !== undefined) {
|
|
554
|
-
const proto = this.
|
|
567
|
+
const proto = this.ctx.builtins.Array;
|
|
555
568
|
return Effect.succeed({
|
|
556
569
|
next: Effect.sync(() => {
|
|
557
570
|
const step = iterator.next();
|
|
558
571
|
return {
|
|
559
572
|
done: Boolean(step.done),
|
|
560
|
-
value: Array.isArray(step.value) ? new
|
|
573
|
+
value: Array.isArray(step.value) ? new Arr(proto, step.value) : step.value,
|
|
561
574
|
};
|
|
562
575
|
}),
|
|
563
576
|
close: Effect.void,
|
|
@@ -572,14 +585,14 @@ class Frame {
|
|
|
572
585
|
});
|
|
573
586
|
}
|
|
574
587
|
customIterator(value, node, allowAsync = true) {
|
|
575
|
-
if (!(value instanceof
|
|
588
|
+
if (!(value instanceof Obj))
|
|
576
589
|
return Effect.undefined;
|
|
577
590
|
const asyncMethod = allowAsync ? get(value, AsyncIteratorSymbol) : undefined;
|
|
578
591
|
const method = asyncMethod ?? get(value, IteratorSymbol);
|
|
579
592
|
if (method === undefined || method === null)
|
|
580
593
|
return Effect.undefined;
|
|
581
594
|
const self = this;
|
|
582
|
-
return Effect.map(this.
|
|
595
|
+
return Effect.map(this.call(this.requireIteratorMethod(method, "Iterator method", node), value, [], node), (iterator) => {
|
|
583
596
|
const object = self.requireIteratorObject(iterator, "Iterator method result", node);
|
|
584
597
|
return {
|
|
585
598
|
iterator: object,
|
|
@@ -592,10 +605,10 @@ class Frame {
|
|
|
592
605
|
const self = this;
|
|
593
606
|
return Effect.gen(function* () {
|
|
594
607
|
if (iterator.asynchronous) {
|
|
595
|
-
const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.
|
|
608
|
+
const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.call(iterator.next, iterator.iterator, [], node)), "Iterator next() result", node);
|
|
596
609
|
return { done: Boolean(get(object, "done")), value: get(object, "value") };
|
|
597
610
|
}
|
|
598
|
-
const called = yield* Effect.exit(self.
|
|
611
|
+
const called = yield* Effect.exit(self.call(iterator.next, iterator.iterator, [], node));
|
|
599
612
|
if (!Exit.isSuccess(called)) {
|
|
600
613
|
if (awaiting)
|
|
601
614
|
yield* Effect.yieldNow;
|
|
@@ -626,10 +639,10 @@ class Frame {
|
|
|
626
639
|
return Effect.gen(function* () {
|
|
627
640
|
const method = self.requireIteratorMethod(close, "Iterator return", node);
|
|
628
641
|
if (iterator.asynchronous) {
|
|
629
|
-
self.requireIteratorObject(yield* self.awaitValue(yield* self.
|
|
642
|
+
self.requireIteratorObject(yield* self.awaitValue(yield* self.call(method, iterator.iterator, [], node)), "Iterator return() result", node);
|
|
630
643
|
return;
|
|
631
644
|
}
|
|
632
|
-
const called = yield* Effect.exit(self.
|
|
645
|
+
const called = yield* Effect.exit(self.call(method, iterator.iterator, [], node));
|
|
633
646
|
if (!Exit.isSuccess(called)) {
|
|
634
647
|
if (awaiting)
|
|
635
648
|
yield* Effect.yieldNow;
|
|
@@ -646,22 +659,22 @@ class Frame {
|
|
|
646
659
|
});
|
|
647
660
|
}
|
|
648
661
|
requireIteratorObject(value, context, node) {
|
|
649
|
-
if (value instanceof
|
|
662
|
+
if (value instanceof Obj)
|
|
650
663
|
return value;
|
|
651
|
-
throw
|
|
664
|
+
throw typeError(`${context} must be an object.`, node);
|
|
652
665
|
}
|
|
653
666
|
requireIteratorMethod(value, context, node) {
|
|
654
667
|
if (typeofValue(value) === "function")
|
|
655
668
|
return value;
|
|
656
|
-
throw
|
|
669
|
+
throw typeError(`${context} must be a function.`, node);
|
|
657
670
|
}
|
|
658
671
|
// for...in over null/undefined iterates nothing, like JS.
|
|
659
672
|
enumerableKeys(value, node) {
|
|
660
673
|
if (value instanceof ToolReference)
|
|
661
|
-
return [...this.
|
|
674
|
+
return [...this.ctx.tools.keys(value.path)];
|
|
662
675
|
if (value === null || value === undefined)
|
|
663
676
|
return [];
|
|
664
|
-
return keys(enumerableSource(this.
|
|
677
|
+
return keys(enumerableSource(this.ctx, "for...in", value, node));
|
|
665
678
|
}
|
|
666
679
|
evaluateForInStatement(node, labels) {
|
|
667
680
|
const left = node.left;
|
|
@@ -675,7 +688,7 @@ class Frame {
|
|
|
675
688
|
const right = yield* self.evaluateExpression(node.right);
|
|
676
689
|
const keys = self.enumerableKeys(right, node.right);
|
|
677
690
|
if (left.type !== "Identifier" && left.type !== "VariableDeclaration") {
|
|
678
|
-
throw
|
|
691
|
+
throw typeError("Unsupported for...in binding.", left);
|
|
679
692
|
}
|
|
680
693
|
const assignmentName = left.type === "Identifier" ? left.name : undefined;
|
|
681
694
|
for (const key of keys) {
|
|
@@ -737,7 +750,7 @@ class Frame {
|
|
|
737
750
|
: result);
|
|
738
751
|
}
|
|
739
752
|
evaluateThrowStatement(node) {
|
|
740
|
-
return Effect.flatMap(this.evaluateExpression(node.argument), (value) => Effect.fail(new
|
|
753
|
+
return Effect.flatMap(this.evaluateExpression(node.argument), (value) => Effect.fail(new Throw(value)));
|
|
741
754
|
}
|
|
742
755
|
evaluateTryStatement(node) {
|
|
743
756
|
const body = node.block;
|
|
@@ -749,7 +762,7 @@ class Frame {
|
|
|
749
762
|
if (cause.reasons.some(Cause.isInterruptReason) || Cause.squash(cause) instanceof GeneratorReturn || !handler) {
|
|
750
763
|
return Effect.failCause(cause);
|
|
751
764
|
}
|
|
752
|
-
const caught =
|
|
765
|
+
const caught = materialize(self.ctx, Cause.squash(cause));
|
|
753
766
|
const parameter = handler.param;
|
|
754
767
|
self.scopes.push();
|
|
755
768
|
return Effect.gen(function* () {
|
|
@@ -776,7 +789,7 @@ class Frame {
|
|
|
776
789
|
return Effect.gen(function* () {
|
|
777
790
|
for (const declaration of node.declarations) {
|
|
778
791
|
if (declaration.type !== "VariableDeclarator") {
|
|
779
|
-
throw
|
|
792
|
+
throw typeError("Unsupported variable declaration shape.", declaration);
|
|
780
793
|
}
|
|
781
794
|
const init = declaration.init;
|
|
782
795
|
// `var x` alone is a no-op: the binding was hoisted on function entry.
|
|
@@ -809,27 +822,27 @@ class Frame {
|
|
|
809
822
|
return;
|
|
810
823
|
}
|
|
811
824
|
if (pattern.type === "ObjectPattern") {
|
|
812
|
-
if (!(value instanceof
|
|
813
|
-
throw
|
|
825
|
+
if (!(value instanceof Obj)) {
|
|
826
|
+
throw typeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern);
|
|
814
827
|
}
|
|
815
828
|
const consumed = new Set();
|
|
816
829
|
for (const property of pattern.properties) {
|
|
817
830
|
if (property.type === "RestElement") {
|
|
818
|
-
const rest = new
|
|
831
|
+
const rest = new Obj(self.ctx.builtins.Object);
|
|
819
832
|
assign(rest, value, consumed);
|
|
820
833
|
yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
|
|
821
834
|
continue;
|
|
822
835
|
}
|
|
823
836
|
const key = yield* self.destructuringPropertyKey(property);
|
|
824
837
|
consumed.add(typeof key === "symbol" ? key : String(key));
|
|
825
|
-
yield* self.declarePattern(property.value,
|
|
838
|
+
yield* self.declarePattern(property.value, self.readProperty(value, key, property), mutable, property, initialize);
|
|
826
839
|
}
|
|
827
840
|
return;
|
|
828
841
|
}
|
|
829
842
|
if (pattern.type === "ArrayPattern") {
|
|
830
843
|
return yield* self.destructureArrayPattern(pattern, value, (target, item, context) => self.declarePattern(target, item, mutable, context, initialize));
|
|
831
844
|
}
|
|
832
|
-
throw
|
|
845
|
+
throw typeError(`Unsupported binding pattern '${pattern.type}'.`, pattern);
|
|
833
846
|
});
|
|
834
847
|
}
|
|
835
848
|
assignPattern(pattern, value, node) {
|
|
@@ -849,27 +862,27 @@ class Frame {
|
|
|
849
862
|
return;
|
|
850
863
|
}
|
|
851
864
|
if (pattern.type === "ObjectPattern") {
|
|
852
|
-
if (!(value instanceof
|
|
853
|
-
throw
|
|
865
|
+
if (!(value instanceof Obj)) {
|
|
866
|
+
throw invalidData(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern);
|
|
854
867
|
}
|
|
855
868
|
const consumed = new Set();
|
|
856
869
|
for (const property of pattern.properties) {
|
|
857
870
|
if (property.type === "RestElement") {
|
|
858
|
-
const rest = new
|
|
871
|
+
const rest = new Obj(self.ctx.builtins.Object);
|
|
859
872
|
assign(rest, value, consumed);
|
|
860
873
|
yield* self.assignPattern(property.argument, rest, property);
|
|
861
874
|
continue;
|
|
862
875
|
}
|
|
863
876
|
const key = yield* self.destructuringPropertyKey(property);
|
|
864
877
|
consumed.add(typeof key === "symbol" ? key : String(key));
|
|
865
|
-
yield* self.assignPattern(property.value,
|
|
878
|
+
yield* self.assignPattern(property.value, self.readProperty(value, key, property), property);
|
|
866
879
|
}
|
|
867
880
|
return;
|
|
868
881
|
}
|
|
869
882
|
if (pattern.type === "ArrayPattern") {
|
|
870
883
|
return yield* self.destructureArrayPattern(pattern, value, (target, item, context) => self.assignPattern(target, item, context));
|
|
871
884
|
}
|
|
872
|
-
throw
|
|
885
|
+
throw typeError(`Unsupported assignment pattern '${pattern.type}'.`, node);
|
|
873
886
|
});
|
|
874
887
|
}
|
|
875
888
|
evaluateDefault(pattern) {
|
|
@@ -880,16 +893,16 @@ class Frame {
|
|
|
880
893
|
destructureArrayPattern(pattern, value, consume) {
|
|
881
894
|
const self = this;
|
|
882
895
|
return Effect.gen(function* () {
|
|
883
|
-
const cursor = yield* self.
|
|
896
|
+
const cursor = yield* self.iterate(value, pattern);
|
|
884
897
|
if (cursor === undefined) {
|
|
885
|
-
throw
|
|
898
|
+
throw typeError("Array destructuring requires a supported iterable value.", pattern);
|
|
886
899
|
}
|
|
887
900
|
let done = false;
|
|
888
901
|
for (const element of pattern.elements) {
|
|
889
902
|
if (done) {
|
|
890
903
|
if (element === null)
|
|
891
904
|
continue;
|
|
892
|
-
yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new
|
|
905
|
+
yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new Arr(self.ctx.builtins.Array) : undefined, element);
|
|
893
906
|
if (element.type === "RestElement")
|
|
894
907
|
return;
|
|
895
908
|
continue;
|
|
@@ -908,7 +921,7 @@ class Frame {
|
|
|
908
921
|
if (!done)
|
|
909
922
|
rest.push(next.value);
|
|
910
923
|
}
|
|
911
|
-
yield* consume(element.argument, new
|
|
924
|
+
yield* consume(element.argument, new Arr(self.ctx.builtins.Array, rest), element);
|
|
912
925
|
return;
|
|
913
926
|
}
|
|
914
927
|
const consumed = consume(element, step.done ? undefined : step.value, pattern);
|
|
@@ -920,7 +933,7 @@ class Frame {
|
|
|
920
933
|
}
|
|
921
934
|
destructuringPropertyKey(property) {
|
|
922
935
|
if (property.type !== "Property" || property.kind !== "init") {
|
|
923
|
-
throw
|
|
936
|
+
throw typeError("Unsupported object destructuring property.", property);
|
|
924
937
|
}
|
|
925
938
|
const keyNode = property.key;
|
|
926
939
|
if (property.computed) {
|
|
@@ -937,8 +950,10 @@ class Frame {
|
|
|
937
950
|
case "Literal": {
|
|
938
951
|
const regex = node.regex;
|
|
939
952
|
if (regex)
|
|
940
|
-
return Effect.sync(() => constructRegExp(this.
|
|
941
|
-
|
|
953
|
+
return Effect.sync(() => constructRegExp(this.ctx.builtins, [regex.pattern, regex.flags]));
|
|
954
|
+
if (typeof node.value === "bigint")
|
|
955
|
+
throw typeError("BigInt literals are not supported.", node);
|
|
956
|
+
return Effect.succeed(node.value);
|
|
942
957
|
}
|
|
943
958
|
case "Identifier":
|
|
944
959
|
return Effect.sync(() => this.scopes.get(node.name, node));
|
|
@@ -981,7 +996,7 @@ class Frame {
|
|
|
981
996
|
return this.evaluateUpdateExpression(node);
|
|
982
997
|
case "AwaitExpression": {
|
|
983
998
|
// Await always suspends, including for plain values.
|
|
984
|
-
return Effect.flatMap(this.evaluateExpression(node.argument), (value) => this.awaitValue(value
|
|
999
|
+
return Effect.flatMap(this.evaluateExpression(node.argument), (value) => this.awaitValue(value));
|
|
985
1000
|
}
|
|
986
1001
|
case "YieldExpression":
|
|
987
1002
|
return this.evaluateYieldExpression(node);
|
|
@@ -996,21 +1011,21 @@ class Frame {
|
|
|
996
1011
|
return Effect.gen(function* () {
|
|
997
1012
|
const callee = yield* self.evaluateExpression(node.callee);
|
|
998
1013
|
// Globals are built with this interpreter's R; `instanceof` cannot recover the type argument.
|
|
999
|
-
const construct = callee instanceof
|
|
1014
|
+
const construct = callee instanceof Native ? callee.construct : undefined;
|
|
1000
1015
|
if (construct === undefined) {
|
|
1001
1016
|
// `new` itself is supported, so a non-constructible callee is a TypeError like JS rather than
|
|
1002
1017
|
// unsupported syntax. Built-ins like Number are real constructors in JS, so do not claim
|
|
1003
1018
|
// otherwise; say `new` is unsupported for them and point at the plain call.
|
|
1004
1019
|
const name = calleeDescription(node.callee);
|
|
1005
|
-
const message = callee instanceof
|
|
1020
|
+
const message = callee instanceof Fn
|
|
1006
1021
|
? `${name} cannot be constructed: user-defined constructors and classes are not supported. Call it as a function that returns a plain object instead.`
|
|
1007
|
-
: callee instanceof
|
|
1022
|
+
: callee instanceof Native
|
|
1008
1023
|
? `new ${name}(...) is not supported; call ${name}(...) without new instead.`
|
|
1009
1024
|
: `${name} is not a constructor.`;
|
|
1010
|
-
throw
|
|
1025
|
+
throw typeError(message, node);
|
|
1011
1026
|
}
|
|
1012
1027
|
const args = yield* self.evaluateCallArguments(node.arguments);
|
|
1013
|
-
return yield* construct(args, callee, node);
|
|
1028
|
+
return yield* self.native(() => construct(args, callee), node);
|
|
1014
1029
|
});
|
|
1015
1030
|
}
|
|
1016
1031
|
evaluateBinaryExpression(node) {
|
|
@@ -1024,7 +1039,7 @@ class Frame {
|
|
|
1024
1039
|
const rhs = yield* self.evaluateExpression(node.right);
|
|
1025
1040
|
if (operator === "instanceof")
|
|
1026
1041
|
return instanceofValue(lhs, rhs, node);
|
|
1027
|
-
return
|
|
1042
|
+
return self.applyBinaryOperator(operator, lhs, rhs, node);
|
|
1028
1043
|
});
|
|
1029
1044
|
}
|
|
1030
1045
|
applyBinaryOperator(operator, lhs, rhs, node) {
|
|
@@ -1032,16 +1047,16 @@ class Frame {
|
|
|
1032
1047
|
return lhs === rhs;
|
|
1033
1048
|
if (operator === "!==")
|
|
1034
1049
|
return lhs !== rhs;
|
|
1035
|
-
if (operator === "in" && rhs instanceof
|
|
1050
|
+
if (operator === "in" && rhs instanceof Obj && !containsOpaqueReference(lhs)) {
|
|
1036
1051
|
return has(rhs, lhs !== null && typeof lhs === "object" ? coerceToString(lhs) : lhs);
|
|
1037
1052
|
}
|
|
1038
1053
|
if (containsOpaqueReference(lhs) || containsOpaqueReference(rhs)) {
|
|
1039
|
-
throw
|
|
1054
|
+
throw invalidData("Binary operators require data values.", node);
|
|
1040
1055
|
}
|
|
1041
1056
|
// Null-prototype data needs explicit primitive coercion; identity and `in` retain raw objects.
|
|
1042
1057
|
// Dates use their default string hint for addition and loose equality, and epoch time elsewhere.
|
|
1043
1058
|
const coerceOperand = (operand) => {
|
|
1044
|
-
if (operand instanceof
|
|
1059
|
+
if (operand instanceof DateObj) {
|
|
1045
1060
|
return operator === "+" || operator === "==" || operator === "!=" ? coerceToString(operand) : operand.time;
|
|
1046
1061
|
}
|
|
1047
1062
|
return operand !== null && typeof operand === "object" ? coerceToString(operand) : operand;
|
|
@@ -1050,8 +1065,12 @@ class Frame {
|
|
|
1050
1065
|
const l = coerceOperand(lhs);
|
|
1051
1066
|
const r = coerceOperand(rhs);
|
|
1052
1067
|
switch (operator) {
|
|
1053
|
-
case "+":
|
|
1054
|
-
|
|
1068
|
+
case "+": {
|
|
1069
|
+
const sum = l + r;
|
|
1070
|
+
if (typeof sum === "string")
|
|
1071
|
+
checkStringLength(sum.length);
|
|
1072
|
+
return sum;
|
|
1073
|
+
}
|
|
1055
1074
|
case "-":
|
|
1056
1075
|
return l - r;
|
|
1057
1076
|
case "*":
|
|
@@ -1087,12 +1106,12 @@ class Frame {
|
|
|
1087
1106
|
case ">>>":
|
|
1088
1107
|
return l >>> r;
|
|
1089
1108
|
case "in":
|
|
1090
|
-
if (!(rhs instanceof
|
|
1091
|
-
throw
|
|
1109
|
+
if (!(rhs instanceof Obj)) {
|
|
1110
|
+
throw typeError("The 'in' operator requires a data object on the right-hand side.", node);
|
|
1092
1111
|
}
|
|
1093
1112
|
return has(rhs, coerceOperand(lhs));
|
|
1094
1113
|
default:
|
|
1095
|
-
throw
|
|
1114
|
+
throw typeError(`Unsupported binary operator '${operator}'.`, node);
|
|
1096
1115
|
}
|
|
1097
1116
|
}
|
|
1098
1117
|
evaluateLogicalExpression(node) {
|
|
@@ -1104,7 +1123,7 @@ class Frame {
|
|
|
1104
1123
|
return left ? Effect.succeed(left) : this.evaluateExpression(node.right);
|
|
1105
1124
|
if (operator === "??")
|
|
1106
1125
|
return left !== null && left !== undefined ? Effect.succeed(left) : this.evaluateExpression(node.right);
|
|
1107
|
-
throw
|
|
1126
|
+
throw typeError(`Unsupported logical operator '${operator}'.`, node);
|
|
1108
1127
|
});
|
|
1109
1128
|
}
|
|
1110
1129
|
evaluateUnaryExpression(node) {
|
|
@@ -1124,9 +1143,9 @@ class Frame {
|
|
|
1124
1143
|
if (operator === "void")
|
|
1125
1144
|
return undefined;
|
|
1126
1145
|
if (containsOpaqueReference(value)) {
|
|
1127
|
-
throw
|
|
1146
|
+
throw invalidData("Unary operators require data values.", node);
|
|
1128
1147
|
}
|
|
1129
|
-
const operand = value instanceof
|
|
1148
|
+
const operand = value instanceof DateObj
|
|
1130
1149
|
? value.time
|
|
1131
1150
|
: value !== null && typeof value === "object"
|
|
1132
1151
|
? coerceToString(value)
|
|
@@ -1143,9 +1162,9 @@ class Frame {
|
|
|
1143
1162
|
result = ~operand;
|
|
1144
1163
|
break;
|
|
1145
1164
|
default:
|
|
1146
|
-
throw
|
|
1165
|
+
throw typeError(`Unsupported unary operator '${operator}'.`, node);
|
|
1147
1166
|
}
|
|
1148
|
-
return
|
|
1167
|
+
return result;
|
|
1149
1168
|
});
|
|
1150
1169
|
}
|
|
1151
1170
|
evaluateAssignmentExpression(node) {
|
|
@@ -1166,8 +1185,7 @@ class Frame {
|
|
|
1166
1185
|
if (operator !== "=") {
|
|
1167
1186
|
const current = self.scopes.get(name, left);
|
|
1168
1187
|
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1169
|
-
|
|
1170
|
-
return self.scopes.set(name, next, left);
|
|
1188
|
+
return self.scopes.set(name, self.applyCompoundAssignment(operator, current, rightValue, node), left);
|
|
1171
1189
|
}
|
|
1172
1190
|
const rightValue = yield* self.evaluateNamed(node.right, name);
|
|
1173
1191
|
return self.scopes.set(name, rightValue, left);
|
|
@@ -1176,11 +1194,11 @@ class Frame {
|
|
|
1176
1194
|
return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(node.right), (rightValue) => {
|
|
1177
1195
|
if (operator === "=")
|
|
1178
1196
|
return { write: true, next: rightValue, result: rightValue };
|
|
1179
|
-
const next =
|
|
1197
|
+
const next = self.applyCompoundAssignment(operator, current, rightValue, node);
|
|
1180
1198
|
return { write: true, next, result: next };
|
|
1181
1199
|
}));
|
|
1182
1200
|
}
|
|
1183
|
-
throw
|
|
1201
|
+
throw typeError("Assignment target must be an Identifier or MemberExpression.", left);
|
|
1184
1202
|
});
|
|
1185
1203
|
}
|
|
1186
1204
|
evaluateLogicalAssignment(node, left, operator) {
|
|
@@ -1205,7 +1223,7 @@ class Frame {
|
|
|
1205
1223
|
}))
|
|
1206
1224
|
: Effect.succeed({ write: false, next: current, result: current }));
|
|
1207
1225
|
}
|
|
1208
|
-
throw
|
|
1226
|
+
throw typeError("Assignment target must be an Identifier or MemberExpression.", left);
|
|
1209
1227
|
}
|
|
1210
1228
|
evaluateUpdateExpression(node) {
|
|
1211
1229
|
const operator = node.operator;
|
|
@@ -1213,13 +1231,13 @@ class Frame {
|
|
|
1213
1231
|
const prefix = node.prefix;
|
|
1214
1232
|
const increment = operator === "++" ? 1 : operator === "--" ? -1 : undefined;
|
|
1215
1233
|
if (increment === undefined) {
|
|
1216
|
-
throw
|
|
1234
|
+
throw typeError(`Unsupported update operator '${operator}'.`, node);
|
|
1217
1235
|
}
|
|
1218
1236
|
// CodeMode numeric coercion, not host Number(): null-prototype data objects would make
|
|
1219
1237
|
// the host throw during ToPrimitive, and opaque runtime references must reject clearly.
|
|
1220
1238
|
const operand = (current) => {
|
|
1221
1239
|
if (containsOpaqueReference(current)) {
|
|
1222
|
-
throw
|
|
1240
|
+
throw invalidData(`'${operator}' requires a data value.`, argument);
|
|
1223
1241
|
}
|
|
1224
1242
|
return coerceToNumber(current);
|
|
1225
1243
|
};
|
|
@@ -1239,7 +1257,7 @@ class Frame {
|
|
|
1239
1257
|
return Effect.succeed({ write: true, next, result: prefix ? next : value });
|
|
1240
1258
|
});
|
|
1241
1259
|
}
|
|
1242
|
-
throw
|
|
1260
|
+
throw typeError("Update target must be an Identifier or MemberExpression.", argument);
|
|
1243
1261
|
}
|
|
1244
1262
|
// EvaluateCall: a member callee supplies its base object as `this`; anything else calls with undefined.
|
|
1245
1263
|
evaluateCallExpression(node) {
|
|
@@ -1256,7 +1274,7 @@ class Frame {
|
|
|
1256
1274
|
if ((callable === null || callable === undefined) && node.optional)
|
|
1257
1275
|
return OptionalShortCircuit;
|
|
1258
1276
|
const args = yield* self.evaluateCallArguments(node.arguments);
|
|
1259
|
-
return yield* self.
|
|
1277
|
+
return yield* self.call(callable, thisValue, args, node, callee);
|
|
1260
1278
|
});
|
|
1261
1279
|
}
|
|
1262
1280
|
readMethod(node) {
|
|
@@ -1271,22 +1289,27 @@ class Frame {
|
|
|
1271
1289
|
});
|
|
1272
1290
|
}
|
|
1273
1291
|
// The single dispatch for every invocation: call expressions and callbacks share it.
|
|
1274
|
-
|
|
1292
|
+
call(callable, thisValue, args, node, callee) {
|
|
1275
1293
|
const self = this;
|
|
1276
1294
|
return Effect.gen(function* () {
|
|
1277
1295
|
if (callable instanceof ToolReference) {
|
|
1278
1296
|
if (callable.path.length === 0) {
|
|
1279
|
-
throw
|
|
1297
|
+
throw typeError("The tools root is not callable.", callee ?? node);
|
|
1280
1298
|
}
|
|
1281
1299
|
return yield* self.createToolCallPromise(callable.path, args);
|
|
1282
1300
|
}
|
|
1283
|
-
if (callable instanceof
|
|
1284
|
-
return yield* self.invokeFunction(callable, args);
|
|
1285
|
-
if (callable instanceof
|
|
1286
|
-
return yield* callable.call(thisValue, args, node);
|
|
1287
|
-
|
|
1301
|
+
if (callable instanceof Fn)
|
|
1302
|
+
return yield* self.invokeFunction(callable, args, node);
|
|
1303
|
+
if (callable instanceof Native) {
|
|
1304
|
+
return yield* self.native(() => callable.call(thisValue, args), node);
|
|
1305
|
+
}
|
|
1306
|
+
throw typeError(`${calleeDescription(callee)} is not a function.`, callee ?? node);
|
|
1288
1307
|
});
|
|
1289
1308
|
}
|
|
1309
|
+
// Built-ins throw without a location, synchronously or inside their Effect; the call site supplies it.
|
|
1310
|
+
native(body, node) {
|
|
1311
|
+
return Effect.provideService(Effect.catchDefect(Effect.suspend(body), (defect) => Effect.die(locate(defect, node))), CallSite, { node, depth: this.depth });
|
|
1312
|
+
}
|
|
1290
1313
|
evaluateCallArguments(argNodes) {
|
|
1291
1314
|
const self = this;
|
|
1292
1315
|
return Effect.gen(function* () {
|
|
@@ -1294,9 +1317,9 @@ class Frame {
|
|
|
1294
1317
|
for (const argNode of argNodes) {
|
|
1295
1318
|
if (argNode.type === "SpreadElement") {
|
|
1296
1319
|
const spread = yield* self.evaluateExpression(argNode.argument);
|
|
1297
|
-
const cursor = yield* self.
|
|
1320
|
+
const cursor = yield* self.iterate(spread, argNode);
|
|
1298
1321
|
if (cursor === undefined)
|
|
1299
|
-
throw
|
|
1322
|
+
throw typeError("Spread arguments require a synchronous iterable.", argNode);
|
|
1300
1323
|
while (true) {
|
|
1301
1324
|
const step = yield* cursor.next;
|
|
1302
1325
|
if (step.done)
|
|
@@ -1311,49 +1334,54 @@ class Frame {
|
|
|
1311
1334
|
return args;
|
|
1312
1335
|
});
|
|
1313
1336
|
}
|
|
1314
|
-
|
|
1337
|
+
// A callback invoked by a built-in runs below the call that invoked the built-in, so the deeper of the two counts.
|
|
1338
|
+
invokeFunction(fn, args, node) {
|
|
1315
1339
|
const self = this;
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1340
|
+
return Effect.flatMap(CallSite, (site) => {
|
|
1341
|
+
const depth = Math.max(self.depth, site.depth) + 1;
|
|
1342
|
+
if (depth > MAX_CALL_DEPTH)
|
|
1343
|
+
throw rangeError("Maximum call stack size exceeded", node);
|
|
1344
|
+
const invocation = new Frame(this.ctx, new ScopeStack([...fn.capturedScopes, new Map()]), depth);
|
|
1345
|
+
const run = Effect.gen(function* () {
|
|
1346
|
+
// Seed all parameters first so defaults cannot fall through to same-named outer bindings.
|
|
1347
|
+
const paramScope = invocation.scopes.current();
|
|
1348
|
+
for (const parameter of fn.parameters) {
|
|
1349
|
+
for (const name of collectPatternNames(parameter)) {
|
|
1350
|
+
paramScope.set(name, { mutable: true, value: undefined, initialized: false });
|
|
1351
|
+
}
|
|
1323
1352
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1353
|
+
for (const [index, parameter] of fn.parameters.entries()) {
|
|
1354
|
+
if (parameter.type === "RestElement") {
|
|
1355
|
+
yield* invocation.declarePattern(parameter.argument, new Arr(self.ctx.builtins.Array, args.slice(index)), true, parameter, true);
|
|
1356
|
+
break;
|
|
1357
|
+
}
|
|
1358
|
+
yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
|
|
1329
1359
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
return
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1360
|
+
if (fn.body.type === "BlockStatement") {
|
|
1361
|
+
invocation.scopes.push();
|
|
1362
|
+
invocation.hoistVars(fn.body.body, paramScope);
|
|
1363
|
+
const result = yield* invocation.evaluateStatement(fn.body);
|
|
1364
|
+
return result.kind === "return" ? result.value : undefined;
|
|
1365
|
+
}
|
|
1366
|
+
return yield* invocation.evaluateExpression(fn.body);
|
|
1367
|
+
});
|
|
1368
|
+
if (fn.generator)
|
|
1369
|
+
return Effect.succeed(this.createGenerator(invocation, run, fn.async));
|
|
1370
|
+
if (!fn.async)
|
|
1371
|
+
return run;
|
|
1372
|
+
return this.ctx.pending.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.ctx, value, self)));
|
|
1339
1373
|
});
|
|
1340
|
-
if (fn.generator)
|
|
1341
|
-
return Effect.succeed(this.createGenerator(invocation, run, fn.async));
|
|
1342
|
-
if (!fn.async)
|
|
1343
|
-
return run;
|
|
1344
|
-
return this.runtime.promises.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, fn.body, self)));
|
|
1345
1374
|
}
|
|
1346
1375
|
createGenerator(invocation, run, asynchronous) {
|
|
1347
1376
|
const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
|
|
1348
1377
|
invocation.generatorState = state;
|
|
1349
1378
|
invocation.generatorAsync = asynchronous;
|
|
1350
|
-
const
|
|
1351
|
-
const result = (value, done) => record(
|
|
1352
|
-
const request = (kind, value
|
|
1379
|
+
const builtins = this.ctx.builtins;
|
|
1380
|
+
const result = (value, done) => record(builtins.Object, { value, done });
|
|
1381
|
+
const request = (kind, value) => {
|
|
1353
1382
|
const request = { kind, value, response: Deferred.makeUnsafe() };
|
|
1354
|
-
if (!asynchronous && state.active)
|
|
1355
|
-
return Effect.
|
|
1356
|
-
}
|
|
1383
|
+
if (!asynchronous && state.active)
|
|
1384
|
+
return Effect.die(typeError("Generator is already running."));
|
|
1357
1385
|
if (asynchronous && (state.completed || (!state.started && kind !== "next"))) {
|
|
1358
1386
|
state.started = true;
|
|
1359
1387
|
state.completed = true;
|
|
@@ -1361,19 +1389,19 @@ class Frame {
|
|
|
1361
1389
|
if (state.draining)
|
|
1362
1390
|
return Deferred.await(request.response);
|
|
1363
1391
|
state.draining = true;
|
|
1364
|
-
return Effect.andThen(this.
|
|
1392
|
+
return Effect.andThen(this.ctx.pending.fork(invocation
|
|
1365
1393
|
.completeGeneratorRequests(state, true)
|
|
1366
1394
|
.pipe(Effect.ensuring(Effect.sync(() => (state.draining = false))))), Deferred.await(request.response));
|
|
1367
1395
|
}
|
|
1368
1396
|
if (state.completed) {
|
|
1369
1397
|
if (kind === "throw")
|
|
1370
|
-
return Effect.fail(new
|
|
1398
|
+
return Effect.fail(new Throw(value));
|
|
1371
1399
|
return Effect.succeed(result(kind === "return" ? value : undefined, true));
|
|
1372
1400
|
}
|
|
1373
1401
|
if (!state.started && kind !== "next") {
|
|
1374
1402
|
state.completed = true;
|
|
1375
1403
|
if (kind === "throw")
|
|
1376
|
-
return Effect.fail(new
|
|
1404
|
+
return Effect.fail(new Throw(value));
|
|
1377
1405
|
return Effect.succeed(result(value, true));
|
|
1378
1406
|
}
|
|
1379
1407
|
state.pending.push(request);
|
|
@@ -1399,23 +1427,23 @@ class Frame {
|
|
|
1399
1427
|
yield* invocation.completeGeneratorRequests(state, asynchronous);
|
|
1400
1428
|
state.completed = true;
|
|
1401
1429
|
});
|
|
1402
|
-
return Effect.andThen(this.
|
|
1430
|
+
return Effect.andThen(this.ctx.pending.fork(body), Deferred.await(request.response));
|
|
1403
1431
|
}
|
|
1404
1432
|
return Deferred.await(request.response);
|
|
1405
1433
|
};
|
|
1406
|
-
const generator = new
|
|
1434
|
+
const generator = new GeneratorObj(asynchronous ? builtins.AsyncGenerator : builtins.Generator, asynchronous, request);
|
|
1407
1435
|
return generator;
|
|
1408
1436
|
}
|
|
1409
1437
|
completeGeneratorRequests(state, asynchronous) {
|
|
1410
1438
|
const self = this;
|
|
1411
|
-
const result = (value, done) => record(self.
|
|
1439
|
+
const result = (value, done) => record(self.ctx.builtins.Object, { value, done });
|
|
1412
1440
|
return Effect.gen(function* () {
|
|
1413
1441
|
while (true) {
|
|
1414
1442
|
const pending = self.dequeueGeneratorRequest(state);
|
|
1415
1443
|
if (!pending)
|
|
1416
1444
|
return;
|
|
1417
1445
|
if (pending.kind === "throw") {
|
|
1418
|
-
Deferred.doneUnsafe(pending.response, Exit.fail(new
|
|
1446
|
+
Deferred.doneUnsafe(pending.response, Exit.fail(new Throw(pending.value)));
|
|
1419
1447
|
continue;
|
|
1420
1448
|
}
|
|
1421
1449
|
if (asynchronous && pending.kind === "return") {
|
|
@@ -1450,7 +1478,7 @@ class Frame {
|
|
|
1450
1478
|
const self = this;
|
|
1451
1479
|
return Effect.gen(function* () {
|
|
1452
1480
|
if (!self.generatorState)
|
|
1453
|
-
throw
|
|
1481
|
+
throw typeError("yield is only valid inside a generator.", node);
|
|
1454
1482
|
if (node.delegate) {
|
|
1455
1483
|
const value = argument ? yield* self.evaluateExpression(argument) : undefined;
|
|
1456
1484
|
return yield* self.delegateYield(value, node);
|
|
@@ -1463,15 +1491,15 @@ class Frame {
|
|
|
1463
1491
|
suspendGenerator(value, node) {
|
|
1464
1492
|
const state = this.generatorState;
|
|
1465
1493
|
if (!state?.active)
|
|
1466
|
-
throw
|
|
1467
|
-
Deferred.doneUnsafe(state.active.response, Exit.succeed(record(this.
|
|
1494
|
+
throw typeError("Generator has no active request.", node);
|
|
1495
|
+
Deferred.doneUnsafe(state.active.response, Exit.succeed(record(this.ctx.builtins.Object, { value, done: false })));
|
|
1468
1496
|
state.active = undefined;
|
|
1469
1497
|
return Effect.flatMap(this.takeGeneratorRequest(state), (request) => {
|
|
1470
1498
|
state.active = request;
|
|
1471
1499
|
if (request.kind === "next")
|
|
1472
1500
|
return Effect.succeed(request.value);
|
|
1473
1501
|
if (request.kind === "throw")
|
|
1474
|
-
return Effect.fail(new
|
|
1502
|
+
return Effect.fail(new Throw(request.value));
|
|
1475
1503
|
return this.generatorAsync
|
|
1476
1504
|
? Effect.flatMap(this.awaitValue(request.value), (value) => Effect.fail(new GeneratorReturn(value)))
|
|
1477
1505
|
: Effect.fail(new GeneratorReturn(request.value));
|
|
@@ -1480,14 +1508,15 @@ class Frame {
|
|
|
1480
1508
|
delegateYield(value, node) {
|
|
1481
1509
|
const self = this;
|
|
1482
1510
|
return Effect.gen(function* () {
|
|
1483
|
-
if (value instanceof
|
|
1511
|
+
if (value instanceof Arr ||
|
|
1484
1512
|
typeof value === "string" ||
|
|
1485
|
-
value instanceof
|
|
1486
|
-
value instanceof
|
|
1487
|
-
value instanceof
|
|
1488
|
-
|
|
1513
|
+
value instanceof MapObj ||
|
|
1514
|
+
value instanceof SetObj ||
|
|
1515
|
+
value instanceof URLSearchParamsObj ||
|
|
1516
|
+
value instanceof Bytes) {
|
|
1517
|
+
const cursor = yield* self.iterate(value, node);
|
|
1489
1518
|
if (!cursor)
|
|
1490
|
-
throw
|
|
1519
|
+
throw typeError("Built-in iterator is unavailable.", node);
|
|
1491
1520
|
while (true) {
|
|
1492
1521
|
const step = yield* cursor.next;
|
|
1493
1522
|
if (step.done)
|
|
@@ -1500,16 +1529,16 @@ class Frame {
|
|
|
1500
1529
|
yield* cursor.close;
|
|
1501
1530
|
return yield* Effect.fail(error);
|
|
1502
1531
|
}
|
|
1503
|
-
if (error instanceof
|
|
1532
|
+
if (error instanceof Throw) {
|
|
1504
1533
|
yield* cursor.close;
|
|
1505
|
-
throw
|
|
1534
|
+
throw typeError("The delegated iterator does not provide a throw() method.", node);
|
|
1506
1535
|
}
|
|
1507
1536
|
return yield* Effect.failCause(resumed.cause);
|
|
1508
1537
|
}
|
|
1509
1538
|
}
|
|
1510
1539
|
const iterator = yield* self.customIterator(value, node, self.generatorAsync);
|
|
1511
1540
|
if (!iterator)
|
|
1512
|
-
throw
|
|
1541
|
+
throw typeError("yield* requires a compatible iterable value.", node);
|
|
1513
1542
|
let kind = "next";
|
|
1514
1543
|
let input = undefined;
|
|
1515
1544
|
while (true) {
|
|
@@ -1518,9 +1547,9 @@ class Frame {
|
|
|
1518
1547
|
if (kind === "return")
|
|
1519
1548
|
return yield* Effect.fail(new GeneratorReturn(input));
|
|
1520
1549
|
yield* self.closeIterator(iterator, node, self.generatorAsync);
|
|
1521
|
-
throw
|
|
1550
|
+
throw typeError("The delegated iterator does not provide a throw() method.", node);
|
|
1522
1551
|
}
|
|
1523
|
-
const called = yield* self.
|
|
1552
|
+
const called = yield* self.call(self.requireIteratorMethod(method, `Iterator ${kind}`, node), iterator.iterator, [input], node);
|
|
1524
1553
|
const result = self.requireIteratorObject(iterator.asynchronous ? yield* self.awaitValue(called) : called, `Iterator ${kind}() result`, node);
|
|
1525
1554
|
const done = Boolean(get(result, "done"));
|
|
1526
1555
|
const resultValue = self.generatorAsync && !iterator.asynchronous
|
|
@@ -1538,7 +1567,7 @@ class Frame {
|
|
|
1538
1567
|
continue;
|
|
1539
1568
|
}
|
|
1540
1569
|
const error = Cause.squash(resumed.cause);
|
|
1541
|
-
if (!(error instanceof GeneratorReturn) && !(error instanceof
|
|
1570
|
+
if (!(error instanceof GeneratorReturn) && !(error instanceof Throw)) {
|
|
1542
1571
|
return yield* Effect.failCause(resumed.cause);
|
|
1543
1572
|
}
|
|
1544
1573
|
kind = error instanceof GeneratorReturn ? "return" : "throw";
|
|
@@ -1547,7 +1576,7 @@ class Frame {
|
|
|
1547
1576
|
});
|
|
1548
1577
|
}
|
|
1549
1578
|
evaluateObjectExpression(node) {
|
|
1550
|
-
const objectValue = new
|
|
1579
|
+
const objectValue = new Obj(this.ctx.builtins.Object);
|
|
1551
1580
|
const self = this;
|
|
1552
1581
|
return Effect.gen(function* () {
|
|
1553
1582
|
for (const property of node.properties) {
|
|
@@ -1555,11 +1584,11 @@ class Frame {
|
|
|
1555
1584
|
const spread = yield* self.evaluateExpression(property.argument);
|
|
1556
1585
|
if (spread === null || spread === undefined)
|
|
1557
1586
|
continue;
|
|
1558
|
-
assign(objectValue, enumerableSource(self.
|
|
1587
|
+
assign(objectValue, enumerableSource(self.ctx, "Object spread", spread, property));
|
|
1559
1588
|
continue;
|
|
1560
1589
|
}
|
|
1561
1590
|
if (property.kind !== "init") {
|
|
1562
|
-
throw
|
|
1591
|
+
throw typeError("Only init object properties are supported.", property);
|
|
1563
1592
|
}
|
|
1564
1593
|
const keyNode = property.key;
|
|
1565
1594
|
let key;
|
|
@@ -1573,7 +1602,7 @@ class Frame {
|
|
|
1573
1602
|
key = self.toPropertyKey(keyNode.value, keyNode);
|
|
1574
1603
|
}
|
|
1575
1604
|
else {
|
|
1576
|
-
throw
|
|
1605
|
+
throw typeError("Unsupported object property key shape.", keyNode);
|
|
1577
1606
|
}
|
|
1578
1607
|
const name = key === IteratorSymbol
|
|
1579
1608
|
? "[Symbol.iterator]"
|
|
@@ -1597,9 +1626,9 @@ class Frame {
|
|
|
1597
1626
|
}
|
|
1598
1627
|
if (element.type === "SpreadElement") {
|
|
1599
1628
|
const spread = yield* self.evaluateExpression(element.argument);
|
|
1600
|
-
const cursor = yield* self.
|
|
1629
|
+
const cursor = yield* self.iterate(spread, element);
|
|
1601
1630
|
if (cursor === undefined)
|
|
1602
|
-
throw
|
|
1631
|
+
throw typeError("Array spread requires a synchronous iterable.", element);
|
|
1603
1632
|
while (true) {
|
|
1604
1633
|
const step = yield* cursor.next;
|
|
1605
1634
|
if (step.done)
|
|
@@ -1611,7 +1640,7 @@ class Frame {
|
|
|
1611
1640
|
values.push(yield* self.evaluateExpression(element));
|
|
1612
1641
|
}
|
|
1613
1642
|
}
|
|
1614
|
-
return new
|
|
1643
|
+
return new Arr(self.ctx.builtins.Array, values);
|
|
1615
1644
|
});
|
|
1616
1645
|
}
|
|
1617
1646
|
evaluateTemplateLiteral(node) {
|
|
@@ -1624,12 +1653,14 @@ class Frame {
|
|
|
1624
1653
|
const quasi = quasis[index];
|
|
1625
1654
|
// acorn only omits `cooked` for invalid escapes in tagged templates, which are unsupported.
|
|
1626
1655
|
if (typeof quasi.value.cooked !== "string") {
|
|
1627
|
-
throw
|
|
1656
|
+
throw typeError("Invalid template literal quasi.", quasi);
|
|
1628
1657
|
}
|
|
1629
1658
|
output += quasi.value.cooked;
|
|
1659
|
+
checkStringLength(output.length);
|
|
1630
1660
|
if (index < expressions.length) {
|
|
1631
1661
|
const raw = yield* self.evaluateExpression(expressions[index]);
|
|
1632
|
-
output += coerceToString(
|
|
1662
|
+
output += coerceToString(raw);
|
|
1663
|
+
checkStringLength(output.length);
|
|
1633
1664
|
}
|
|
1634
1665
|
}
|
|
1635
1666
|
return output;
|
|
@@ -1640,7 +1671,7 @@ class Frame {
|
|
|
1640
1671
|
}
|
|
1641
1672
|
applyCompoundAssignment(operator, current, incoming, node) {
|
|
1642
1673
|
if (!compoundOperators.has(operator)) {
|
|
1643
|
-
throw
|
|
1674
|
+
throw typeError(`Unsupported assignment operator '${operator}'.`, node);
|
|
1644
1675
|
}
|
|
1645
1676
|
return this.applyBinaryOperator(operator.slice(0, -1), current, incoming, node);
|
|
1646
1677
|
}
|
|
@@ -1665,39 +1696,43 @@ class Frame {
|
|
|
1665
1696
|
: self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode);
|
|
1666
1697
|
if (objectValue instanceof ToolReference) {
|
|
1667
1698
|
if (typeof key !== "string") {
|
|
1668
|
-
throw
|
|
1699
|
+
throw typeError("Tool paths must use string property names.", propertyNode);
|
|
1669
1700
|
}
|
|
1670
1701
|
return new ToolReference([...objectValue.path, key]);
|
|
1671
1702
|
}
|
|
1672
|
-
if (objectValue instanceof
|
|
1703
|
+
if (objectValue instanceof Obj)
|
|
1673
1704
|
return { target: objectValue, key, receiver: objectValue };
|
|
1674
1705
|
// Primitives read through their wrapper prototype without being boxed; strings own length and indexes.
|
|
1675
|
-
const
|
|
1706
|
+
const builtins = self.ctx.builtins;
|
|
1676
1707
|
if (typeof objectValue === "string") {
|
|
1677
1708
|
if (key === "length")
|
|
1678
1709
|
return { value: objectValue.length };
|
|
1679
1710
|
const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
|
|
1680
1711
|
if (index !== undefined)
|
|
1681
1712
|
return { value: objectValue[index] };
|
|
1682
|
-
return { target:
|
|
1713
|
+
return { target: builtins.String, key, receiver: objectValue };
|
|
1683
1714
|
}
|
|
1684
1715
|
if (typeof objectValue === "number")
|
|
1685
|
-
return { target:
|
|
1716
|
+
return { target: builtins.Number, key, receiver: objectValue };
|
|
1686
1717
|
if (typeof objectValue === "boolean")
|
|
1687
|
-
return { target:
|
|
1718
|
+
return { target: builtins.Boolean, key, receiver: objectValue };
|
|
1688
1719
|
if (objectValue === null || objectValue === undefined) {
|
|
1689
|
-
throw
|
|
1720
|
+
throw typeError(`Cannot read properties of ${objectValue} (reading '${String(key)}').`, objectNode);
|
|
1690
1721
|
}
|
|
1691
|
-
throw
|
|
1722
|
+
throw typeError("Cannot access a property on a non-object value.", objectNode);
|
|
1692
1723
|
});
|
|
1693
1724
|
}
|
|
1694
1725
|
readReference(reference, node) {
|
|
1695
1726
|
// Reject unknown promise properties so a missing await cannot hide.
|
|
1696
|
-
if (reference.target instanceof
|
|
1697
|
-
throw
|
|
1727
|
+
if (reference.target instanceof PromiseObj && !has(reference.target, reference.key)) {
|
|
1728
|
+
throw invalidData("This value is an un-awaited Promise; await it first - e.g. `const result = await tools.ns.tool(...)`.", node.object);
|
|
1698
1729
|
}
|
|
1730
|
+
return this.readProperty(reference.target, reference.key, node, reference.receiver);
|
|
1731
|
+
}
|
|
1732
|
+
// Accessors throw without a location; the member or pattern that read them supplies it.
|
|
1733
|
+
readProperty(target, key, node, receiver = target) {
|
|
1699
1734
|
try {
|
|
1700
|
-
return get(
|
|
1735
|
+
return get(target, key, receiver);
|
|
1701
1736
|
}
|
|
1702
1737
|
catch (error) {
|
|
1703
1738
|
throw locate(error, node);
|
|
@@ -1720,17 +1755,17 @@ class Frame {
|
|
|
1720
1755
|
evaluateDeleteExpression(argument) {
|
|
1721
1756
|
const target = argument.type === "ChainExpression" ? argument.expression : argument;
|
|
1722
1757
|
if (target.type !== "MemberExpression") {
|
|
1723
|
-
throw
|
|
1758
|
+
throw typeError("Only data fields may be deleted.", argument);
|
|
1724
1759
|
}
|
|
1725
1760
|
return Effect.map(this.getMemberReference(target), (reference) => {
|
|
1726
1761
|
if (reference === OptionalShortCircuit)
|
|
1727
1762
|
return true;
|
|
1728
1763
|
if (reference instanceof ToolReference || "value" in reference || reference.receiver !== reference.target) {
|
|
1729
|
-
throw
|
|
1764
|
+
throw invalidData("Only data fields may be deleted.", target);
|
|
1730
1765
|
}
|
|
1731
1766
|
if (remove(reference.target, reference.key))
|
|
1732
1767
|
return true;
|
|
1733
|
-
throw
|
|
1768
|
+
throw typeError(`Cannot delete property '${String(reference.key)}'.`, target);
|
|
1734
1769
|
});
|
|
1735
1770
|
}
|
|
1736
1771
|
// Resolve side-effecting object and key expressions exactly once.
|
|
@@ -1739,10 +1774,10 @@ class Frame {
|
|
|
1739
1774
|
return Effect.gen(function* () {
|
|
1740
1775
|
const reference = yield* self.getMemberReference(node);
|
|
1741
1776
|
if (reference === OptionalShortCircuit || reference instanceof ToolReference || "value" in reference) {
|
|
1742
|
-
throw
|
|
1777
|
+
throw typeError("Only data fields may be assigned.", node);
|
|
1743
1778
|
}
|
|
1744
1779
|
if (reference.receiver !== reference.target) {
|
|
1745
|
-
throw
|
|
1780
|
+
throw typeError(`Cannot create property '${String(reference.key)}' on ${typeof reference.receiver} '${String(reference.receiver)}'.`, node);
|
|
1746
1781
|
}
|
|
1747
1782
|
const key = reference.key;
|
|
1748
1783
|
const { write, next, result } = yield* compute(self.readReference(reference, node));
|
|
@@ -1752,9 +1787,9 @@ class Frame {
|
|
|
1752
1787
|
});
|
|
1753
1788
|
}
|
|
1754
1789
|
assignToReference(target, key, next, node) {
|
|
1755
|
-
rejectCircularInsertion(target, next, target instanceof ProgramArray ? "Array assignment result" : "Object assignment result", node);
|
|
1756
1790
|
const written = (() => {
|
|
1757
1791
|
try {
|
|
1792
|
+
rejectCircularInsertion(target, next, target instanceof Arr ? "Array assignment result" : "Object assignment result");
|
|
1758
1793
|
return set(target, key, next);
|
|
1759
1794
|
}
|
|
1760
1795
|
catch (error) {
|
|
@@ -1763,9 +1798,9 @@ class Frame {
|
|
|
1763
1798
|
})();
|
|
1764
1799
|
if (written)
|
|
1765
1800
|
return;
|
|
1766
|
-
if (target instanceof
|
|
1801
|
+
if (target instanceof Arr && key === "length")
|
|
1767
1802
|
throw rangeError("Invalid array length", node);
|
|
1768
|
-
throw
|
|
1803
|
+
throw typeError(`Cannot assign to read only property '${String(key)}'.`, node);
|
|
1769
1804
|
}
|
|
1770
1805
|
toPropertyKey(value, node) {
|
|
1771
1806
|
if (typeof value === "string" || typeof value === "number") {
|
|
@@ -1773,6 +1808,6 @@ class Frame {
|
|
|
1773
1808
|
}
|
|
1774
1809
|
if (value === AsyncIteratorSymbol || value === IteratorSymbol)
|
|
1775
1810
|
return value;
|
|
1776
|
-
throw
|
|
1811
|
+
throw typeError("Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.", node);
|
|
1777
1812
|
}
|
|
1778
1813
|
}
|