@opencode/codemode 2.0.0 → 2.0.2
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/data.d.ts +6 -5
- package/dist/data.js +47 -44
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/interpreter/errors.d.ts +5 -3
- package/dist/interpreter/errors.js +51 -22
- package/dist/interpreter/execute.js +5 -3
- package/dist/interpreter/generators.d.ts +4 -0
- package/dist/interpreter/generators.js +25 -0
- package/dist/interpreter/globals.js +69 -47
- package/dist/interpreter/intrinsics.d.ts +13 -0
- package/dist/interpreter/intrinsics.js +82 -0
- package/dist/interpreter/model.d.ts +13 -36
- package/dist/interpreter/model.js +15 -45
- package/dist/interpreter/native.d.ts +19 -0
- package/dist/interpreter/native.js +40 -0
- package/dist/interpreter/objects.d.ts +106 -13
- package/dist/interpreter/objects.js +192 -65
- package/dist/interpreter/promises.d.ts +12 -13
- package/dist/interpreter/promises.js +59 -54
- package/dist/interpreter/references.d.ts +1 -0
- package/dist/interpreter/references.js +20 -33
- package/dist/interpreter/runner.d.ts +15 -11
- package/dist/interpreter/runner.js +21 -21
- package/dist/interpreter/runtime.d.ts +3 -3
- package/dist/interpreter/runtime.js +165 -327
- package/dist/interpreter/scope.js +6 -6
- package/dist/stdlib/array.d.ts +4 -2
- package/dist/stdlib/array.js +424 -32
- package/dist/stdlib/collections.d.ts +3 -7
- package/dist/stdlib/collections.js +291 -119
- package/dist/stdlib/console.d.ts +3 -2
- package/dist/stdlib/console.js +35 -30
- package/dist/stdlib/date.d.ts +1 -7
- package/dist/stdlib/date.js +93 -188
- package/dist/stdlib/json.d.ts +2 -2
- package/dist/stdlib/json.js +27 -27
- package/dist/stdlib/math.d.ts +2 -2
- package/dist/stdlib/math.js +96 -76
- package/dist/stdlib/number.d.ts +3 -4
- package/dist/stdlib/number.js +95 -60
- package/dist/stdlib/object.d.ts +4 -4
- package/dist/stdlib/object.js +128 -54
- package/dist/stdlib/regexp.d.ts +6 -8
- package/dist/stdlib/regexp.js +76 -68
- package/dist/stdlib/string.d.ts +2 -2
- package/dist/stdlib/string.js +213 -50
- package/dist/stdlib/url.d.ts +5 -13
- package/dist/stdlib/url.js +202 -102
- package/dist/stdlib/value.d.ts +5 -9
- package/dist/stdlib/value.js +16 -38
- package/dist/stdlib/web.d.ts +4 -4
- package/dist/stdlib/web.js +12 -10
- package/dist/tool-runtime.d.ts +2 -1
- package/dist/tool-runtime.js +2 -2
- package/package.json +1 -1
- package/dist/interpreter/host.d.ts +0 -41
- package/dist/interpreter/host.js +0 -44
- package/dist/interpreter/methods.d.ts +0 -4
- package/dist/interpreter/methods.js +0 -837
- package/dist/values.d.ts +0 -37
- package/dist/values.js +0 -56
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit } from "effect";
|
|
2
|
-
import {
|
|
2
|
+
import { toProgram } from "../data.js";
|
|
3
3
|
import { ToolReference } from "../tool-runtime.js";
|
|
4
|
-
import { AsyncIteratorSymbol,
|
|
4
|
+
import { AsyncIteratorSymbol, GeneratorReturn, InterpreterRuntimeError, IteratorSymbol, locate, OptionalShortCircuit, ProgramThrow, rangeError, unsupportedSyntax, } from "./model.js";
|
|
5
5
|
import { caughtErrorValue } from "./errors.js";
|
|
6
6
|
import { globals } from "./globals.js";
|
|
7
|
-
import {
|
|
8
|
-
import { invokeIntrinsic } from "./methods.js";
|
|
9
|
-
import { assign, get, has, ownKeys, parseArrayIndex, ProgramArray, ProgramFunction, ProgramObject, record, remove, set, } from "./objects.js";
|
|
7
|
+
import { assign, Callable, define, get, has, hasPrototype, keys, NativeFunction, parseArrayIndex, ProgramArray, ProgramDate, ProgramFunction, ProgramGenerator, ProgramMap, ProgramObject, ProgramPromise, ProgramSet, ProgramURLSearchParams, record, remove, set, } from "./objects.js";
|
|
10
8
|
import { preserveConsumerError } from "./runner.js";
|
|
11
|
-
import {
|
|
12
|
-
import { containsOpaqueReference, describeValue,
|
|
9
|
+
import { PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
|
|
10
|
+
import { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue } from "./references.js";
|
|
13
11
|
import { ScopeStack } from "./scope.js";
|
|
14
|
-
import {
|
|
15
|
-
import { dateMethods } from "../stdlib/date.js";
|
|
16
|
-
import { numberMethods } from "../stdlib/number.js";
|
|
17
|
-
import { constructRegExp, regexpMethods, regexpProperties } from "../stdlib/regexp.js";
|
|
18
|
-
import { stringMethods } from "../stdlib/string.js";
|
|
19
|
-
import { uriArgument, urlMethods, urlProperties, urlSearchParamsMethods, urlWritableProperties } from "../stdlib/url.js";
|
|
12
|
+
import { constructRegExp } from "../stdlib/regexp.js";
|
|
20
13
|
import { enumerableSource } from "../stdlib/object.js";
|
|
21
|
-
import { coerceToNumber, coerceToString, compoundOperators
|
|
22
|
-
import { Values } from "../values.js";
|
|
14
|
+
import { coerceToNumber, coerceToString, compoundOperators } from "../stdlib/value.js";
|
|
23
15
|
// What a loop does with its body's result: exit with a StatementResult, or undefined to keep iterating.
|
|
24
16
|
// Unlabelled break ends this loop; a label the loop does not carry propagates outward.
|
|
25
17
|
const loopExit = (result, labels) => {
|
|
@@ -50,37 +42,16 @@ const calleeDescription = (callee) => {
|
|
|
50
42
|
}
|
|
51
43
|
return "The called value";
|
|
52
44
|
};
|
|
53
|
-
|
|
54
|
-
if (typeof value === "string")
|
|
55
|
-
return "String";
|
|
56
|
-
if (typeof value === "number")
|
|
57
|
-
return "Number";
|
|
58
|
-
if (typeof value === "boolean")
|
|
59
|
-
return "Boolean";
|
|
60
|
-
if (value instanceof ProgramArray)
|
|
61
|
-
return "Array";
|
|
62
|
-
if (value instanceof Values.Date)
|
|
63
|
-
return "Date";
|
|
64
|
-
if (value instanceof Values.RegExp)
|
|
65
|
-
return "RegExp";
|
|
66
|
-
if (value instanceof Values.Map)
|
|
67
|
-
return "Map";
|
|
68
|
-
if (value instanceof Values.Set)
|
|
69
|
-
return "Set";
|
|
70
|
-
if (value instanceof Values.URL)
|
|
71
|
-
return "URL";
|
|
72
|
-
if (value instanceof Values.URLSearchParams)
|
|
73
|
-
return "URLSearchParams";
|
|
74
|
-
if (value instanceof Values.Promise)
|
|
75
|
-
return "Promise";
|
|
76
|
-
if (!(value instanceof ProgramObject) || value instanceof ProgramFunction)
|
|
77
|
-
return undefined;
|
|
78
|
-
return errorBrandName(value) ?? "Object";
|
|
79
|
-
};
|
|
45
|
+
// OrdinaryHasInstance: walk the left operand's chain looking for the constructor's `prototype`.
|
|
80
46
|
const instanceofValue = (lhs, rhs, node) => {
|
|
81
|
-
if (rhs instanceof
|
|
82
|
-
|
|
83
|
-
|
|
47
|
+
if (!(rhs instanceof Callable)) {
|
|
48
|
+
throw new InterpreterRuntimeError("The right-hand side of 'instanceof' is not callable.", node);
|
|
49
|
+
}
|
|
50
|
+
const prototype = get(rhs, "prototype");
|
|
51
|
+
if (!(prototype instanceof ProgramObject)) {
|
|
52
|
+
throw new InterpreterRuntimeError("The right-hand side of 'instanceof' has no 'prototype' object.", node);
|
|
53
|
+
}
|
|
54
|
+
return hasPrototype(lhs, prototype);
|
|
84
55
|
};
|
|
85
56
|
const collectPatternNames = (pattern, out = []) => {
|
|
86
57
|
switch (pattern.type) {
|
|
@@ -170,10 +141,6 @@ const loopDeclaration = (left, statement) => {
|
|
|
170
141
|
lexical: kind !== "var",
|
|
171
142
|
};
|
|
172
143
|
};
|
|
173
|
-
const isOpaqueMemberReference = (value) => value instanceof ToolReference ||
|
|
174
|
-
value instanceof PromiseInstanceMethodReference ||
|
|
175
|
-
value instanceof IntrinsicReference ||
|
|
176
|
-
value instanceof GeneratorMethodReference;
|
|
177
144
|
const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
|
|
178
145
|
/** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
|
|
179
146
|
export class Runtime {
|
|
@@ -181,29 +148,29 @@ export class Runtime {
|
|
|
181
148
|
search;
|
|
182
149
|
toolKeys;
|
|
183
150
|
promises;
|
|
151
|
+
prototypes;
|
|
184
152
|
logs;
|
|
185
153
|
runner;
|
|
186
|
-
/** Built-in globals by name, unaffected by program shadowing. */
|
|
187
|
-
builtins;
|
|
188
154
|
root;
|
|
189
|
-
constructor(executeTool, search, toolKeys, promises, logs = [], extraGlobals = () => []) {
|
|
155
|
+
constructor(executeTool, search, toolKeys, promises, prototypes, logs = [], extraGlobals = () => []) {
|
|
190
156
|
this.executeTool = executeTool;
|
|
191
157
|
this.search = search;
|
|
192
158
|
this.toolKeys = toolKeys;
|
|
193
159
|
this.promises = promises;
|
|
160
|
+
this.prototypes = prototypes;
|
|
194
161
|
this.logs = logs;
|
|
195
162
|
const globalScope = new Map();
|
|
196
163
|
// Calling back into the program never reads frame state, so any frame serves; the root is always alive.
|
|
197
164
|
this.root = new Frame(this, new ScopeStack([globalScope]));
|
|
198
165
|
this.runner = {
|
|
199
|
-
|
|
200
|
-
invokeCallable: (callable, args, node) => this.root.invokeCallable(callable, args, node),
|
|
166
|
+
invokeCallable: (callable, thisValue, args, node) => this.root.invokeCallable(callable, thisValue, args, node),
|
|
201
167
|
settlePromise: (promise) => this.root.settlePromise(promise),
|
|
202
168
|
syncIterator: (value, node) => this.root.syncIterator(value, node),
|
|
169
|
+
prototypes,
|
|
203
170
|
};
|
|
204
|
-
|
|
205
|
-
for (const [name, value] of this.builtins)
|
|
171
|
+
for (const [name, value] of [...globals(this), ...extraGlobals(this)]) {
|
|
206
172
|
globalScope.set(name, { mutable: false, value });
|
|
173
|
+
}
|
|
207
174
|
}
|
|
208
175
|
run(program) {
|
|
209
176
|
return this.root.run(program);
|
|
@@ -249,10 +216,7 @@ class Frame {
|
|
|
249
216
|
}
|
|
250
217
|
// Fork at the call site so admission and hooks occur when the call is made.
|
|
251
218
|
createToolCallPromise(path, args) {
|
|
252
|
-
return this.
|
|
253
|
-
}
|
|
254
|
-
createPromise(effect) {
|
|
255
|
-
return this.runtime.promises.create(effect);
|
|
219
|
+
return this.runtime.promises.create(Effect.suspend(() => this.runtime.executeTool(path, args)));
|
|
256
220
|
}
|
|
257
221
|
// Fiber exits make settlement idempotent; yielding prevents inline continuation.
|
|
258
222
|
settlePromise(promise) {
|
|
@@ -325,7 +289,7 @@ class Frame {
|
|
|
325
289
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
326
290
|
}
|
|
327
291
|
createFunction(node, name = node.type === "ArrowFunctionExpression" ? "" : (node.id?.name ?? "")) {
|
|
328
|
-
return new ProgramFunction(name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
|
|
292
|
+
return new ProgramFunction(this.runtime.prototypes.Function, name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
|
|
329
293
|
}
|
|
330
294
|
// NamedEvaluation: an anonymous function definition takes the name of what it is assigned to.
|
|
331
295
|
evaluateNamed(node, name) {
|
|
@@ -505,7 +469,7 @@ class Frame {
|
|
|
505
469
|
const iterator = yield* self.customIterator(right, node, awaiting);
|
|
506
470
|
const cursor = iterator === undefined ? yield* self.syncIterator(right, node) : undefined;
|
|
507
471
|
if (iterator === undefined && cursor === undefined) {
|
|
508
|
-
throw new InterpreterRuntimeError(`${awaiting ? "for await...of" : "for...of"} requires an array, string, Map, Set, or URLSearchParams, or custom iterator value.`, node)
|
|
472
|
+
throw new InterpreterRuntimeError(`${awaiting ? "for await...of" : "for...of"} requires an array, string, Map, Set, or URLSearchParams, or custom iterator value.`, node);
|
|
509
473
|
}
|
|
510
474
|
const close = () => iterator
|
|
511
475
|
? self.closeIterator(iterator, node, awaiting)
|
|
@@ -579,20 +543,21 @@ class Frame {
|
|
|
579
543
|
? value.items[Symbol.iterator]()
|
|
580
544
|
: typeof value === "string"
|
|
581
545
|
? value[Symbol.iterator]()
|
|
582
|
-
: value instanceof
|
|
546
|
+
: value instanceof ProgramMap
|
|
583
547
|
? value.map.entries()
|
|
584
|
-
: value instanceof
|
|
548
|
+
: value instanceof ProgramSet
|
|
585
549
|
? value.set.values()
|
|
586
|
-
: value instanceof
|
|
550
|
+
: value instanceof ProgramURLSearchParams
|
|
587
551
|
? value.params.entries()
|
|
588
552
|
: undefined;
|
|
589
553
|
if (iterator !== undefined) {
|
|
554
|
+
const proto = this.runtime.prototypes.Array;
|
|
590
555
|
return Effect.succeed({
|
|
591
556
|
next: Effect.sync(() => {
|
|
592
557
|
const step = iterator.next();
|
|
593
558
|
return {
|
|
594
559
|
done: Boolean(step.done),
|
|
595
|
-
value: Array.isArray(step.value) ? new ProgramArray(step.value) : step.value,
|
|
560
|
+
value: Array.isArray(step.value) ? new ProgramArray(proto, step.value) : step.value,
|
|
596
561
|
};
|
|
597
562
|
}),
|
|
598
563
|
close: Effect.void,
|
|
@@ -607,15 +572,6 @@ class Frame {
|
|
|
607
572
|
});
|
|
608
573
|
}
|
|
609
574
|
customIterator(value, node, allowAsync = true) {
|
|
610
|
-
if (value instanceof CodeModeGenerator) {
|
|
611
|
-
if (value.asynchronous && !allowAsync)
|
|
612
|
-
return Effect.undefined;
|
|
613
|
-
return Effect.succeed({
|
|
614
|
-
iterator: value,
|
|
615
|
-
next: new GeneratorMethodReference(value, "next"),
|
|
616
|
-
asynchronous: value.asynchronous,
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
575
|
if (!(value instanceof ProgramObject))
|
|
620
576
|
return Effect.undefined;
|
|
621
577
|
const asyncMethod = allowAsync ? get(value, AsyncIteratorSymbol) : undefined;
|
|
@@ -623,13 +579,11 @@ class Frame {
|
|
|
623
579
|
if (method === undefined || method === null)
|
|
624
580
|
return Effect.undefined;
|
|
625
581
|
const self = this;
|
|
626
|
-
return Effect.map(this.invokeCallable(this.requireIteratorMethod(method, "Iterator method", node), [], node), (iterator) => {
|
|
627
|
-
const object = self.
|
|
582
|
+
return Effect.map(this.invokeCallable(this.requireIteratorMethod(method, "Iterator method", node), value, [], node), (iterator) => {
|
|
583
|
+
const object = self.requireIteratorObject(iterator, "Iterator method result", node);
|
|
628
584
|
return {
|
|
629
585
|
iterator: object,
|
|
630
|
-
next: object
|
|
631
|
-
? new GeneratorMethodReference(object, "next")
|
|
632
|
-
: self.requireIteratorMethod(get(object, "next"), "Iterator next", node),
|
|
586
|
+
next: self.requireIteratorMethod(get(object, "next"), "Iterator next", node),
|
|
633
587
|
asynchronous: asyncMethod !== undefined && asyncMethod !== null,
|
|
634
588
|
};
|
|
635
589
|
});
|
|
@@ -638,10 +592,10 @@ class Frame {
|
|
|
638
592
|
const self = this;
|
|
639
593
|
return Effect.gen(function* () {
|
|
640
594
|
if (iterator.asynchronous) {
|
|
641
|
-
const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(iterator.next, [], node)), "Iterator next() result", node);
|
|
595
|
+
const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(iterator.next, iterator.iterator, [], node)), "Iterator next() result", node);
|
|
642
596
|
return { done: Boolean(get(object, "done")), value: get(object, "value") };
|
|
643
597
|
}
|
|
644
|
-
const called = yield* Effect.exit(self.invokeCallable(iterator.next, [], node));
|
|
598
|
+
const called = yield* Effect.exit(self.invokeCallable(iterator.next, iterator.iterator, [], node));
|
|
645
599
|
if (!Exit.isSuccess(called)) {
|
|
646
600
|
if (awaiting)
|
|
647
601
|
yield* Effect.yieldNow;
|
|
@@ -665,19 +619,17 @@ class Frame {
|
|
|
665
619
|
});
|
|
666
620
|
}
|
|
667
621
|
closeIterator(iterator, node, awaiting = true) {
|
|
668
|
-
const close = iterator.iterator
|
|
669
|
-
? new GeneratorMethodReference(iterator.iterator, "return")
|
|
670
|
-
: get(iterator.iterator, "return");
|
|
622
|
+
const close = get(iterator.iterator, "return");
|
|
671
623
|
if (close === undefined || close === null)
|
|
672
624
|
return iterator.asynchronous || !awaiting ? Effect.void : Effect.yieldNow;
|
|
673
625
|
const self = this;
|
|
674
626
|
return Effect.gen(function* () {
|
|
675
627
|
const method = self.requireIteratorMethod(close, "Iterator return", node);
|
|
676
628
|
if (iterator.asynchronous) {
|
|
677
|
-
self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(method, [], node)), "Iterator return() result", node);
|
|
629
|
+
self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(method, iterator.iterator, [], node)), "Iterator return() result", node);
|
|
678
630
|
return;
|
|
679
631
|
}
|
|
680
|
-
const called = yield* Effect.exit(self.invokeCallable(method, [], node));
|
|
632
|
+
const called = yield* Effect.exit(self.invokeCallable(method, iterator.iterator, [], node));
|
|
681
633
|
if (!Exit.isSuccess(called)) {
|
|
682
634
|
if (awaiting)
|
|
683
635
|
yield* Effect.yieldNow;
|
|
@@ -696,17 +648,12 @@ class Frame {
|
|
|
696
648
|
requireIteratorObject(value, context, node) {
|
|
697
649
|
if (value instanceof ProgramObject)
|
|
698
650
|
return value;
|
|
699
|
-
throw new InterpreterRuntimeError(`${context} must be an object.`, node)
|
|
700
|
-
}
|
|
701
|
-
requireIterator(value, node) {
|
|
702
|
-
return value instanceof CodeModeGenerator
|
|
703
|
-
? value
|
|
704
|
-
: this.requireIteratorObject(value, "Iterator method result", node);
|
|
651
|
+
throw new InterpreterRuntimeError(`${context} must be an object.`, node);
|
|
705
652
|
}
|
|
706
653
|
requireIteratorMethod(value, context, node) {
|
|
707
654
|
if (typeofValue(value) === "function")
|
|
708
655
|
return value;
|
|
709
|
-
throw new InterpreterRuntimeError(`${context} must be a function.`, node)
|
|
656
|
+
throw new InterpreterRuntimeError(`${context} must be a function.`, node);
|
|
710
657
|
}
|
|
711
658
|
// for...in over null/undefined iterates nothing, like JS.
|
|
712
659
|
enumerableKeys(value, node) {
|
|
@@ -714,7 +661,7 @@ class Frame {
|
|
|
714
661
|
return [...this.runtime.toolKeys(value.path)];
|
|
715
662
|
if (value === null || value === undefined)
|
|
716
663
|
return [];
|
|
717
|
-
return
|
|
664
|
+
return keys(enumerableSource(this.runtime.runner, "for...in", value, node));
|
|
718
665
|
}
|
|
719
666
|
evaluateForInStatement(node, labels) {
|
|
720
667
|
const left = node.left;
|
|
@@ -802,7 +749,7 @@ class Frame {
|
|
|
802
749
|
if (cause.reasons.some(Cause.isInterruptReason) || Cause.squash(cause) instanceof GeneratorReturn || !handler) {
|
|
803
750
|
return Effect.failCause(cause);
|
|
804
751
|
}
|
|
805
|
-
const caught = caughtErrorValue(Cause.squash(cause));
|
|
752
|
+
const caught = caughtErrorValue(self.runtime.runner, Cause.squash(cause));
|
|
806
753
|
const parameter = handler.param;
|
|
807
754
|
self.scopes.push();
|
|
808
755
|
return Effect.gen(function* () {
|
|
@@ -868,14 +815,14 @@ class Frame {
|
|
|
868
815
|
const consumed = new Set();
|
|
869
816
|
for (const property of pattern.properties) {
|
|
870
817
|
if (property.type === "RestElement") {
|
|
871
|
-
const rest = new ProgramObject();
|
|
818
|
+
const rest = new ProgramObject(self.runtime.prototypes.Object);
|
|
872
819
|
assign(rest, value, consumed);
|
|
873
820
|
yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
|
|
874
821
|
continue;
|
|
875
822
|
}
|
|
876
823
|
const key = yield* self.destructuringPropertyKey(property);
|
|
877
824
|
consumed.add(typeof key === "symbol" ? key : String(key));
|
|
878
|
-
yield* self.declarePattern(property.value,
|
|
825
|
+
yield* self.declarePattern(property.value, get(value, key), mutable, property, initialize);
|
|
879
826
|
}
|
|
880
827
|
return;
|
|
881
828
|
}
|
|
@@ -908,14 +855,14 @@ class Frame {
|
|
|
908
855
|
const consumed = new Set();
|
|
909
856
|
for (const property of pattern.properties) {
|
|
910
857
|
if (property.type === "RestElement") {
|
|
911
|
-
const rest = new ProgramObject();
|
|
858
|
+
const rest = new ProgramObject(self.runtime.prototypes.Object);
|
|
912
859
|
assign(rest, value, consumed);
|
|
913
860
|
yield* self.assignPattern(property.argument, rest, property);
|
|
914
861
|
continue;
|
|
915
862
|
}
|
|
916
863
|
const key = yield* self.destructuringPropertyKey(property);
|
|
917
864
|
consumed.add(typeof key === "symbol" ? key : String(key));
|
|
918
|
-
yield* self.assignPattern(property.value,
|
|
865
|
+
yield* self.assignPattern(property.value, get(value, key), property);
|
|
919
866
|
}
|
|
920
867
|
return;
|
|
921
868
|
}
|
|
@@ -935,14 +882,14 @@ class Frame {
|
|
|
935
882
|
return Effect.gen(function* () {
|
|
936
883
|
const cursor = yield* self.syncIterator(value, pattern);
|
|
937
884
|
if (cursor === undefined) {
|
|
938
|
-
throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern)
|
|
885
|
+
throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern);
|
|
939
886
|
}
|
|
940
887
|
let done = false;
|
|
941
888
|
for (const element of pattern.elements) {
|
|
942
889
|
if (done) {
|
|
943
890
|
if (element === null)
|
|
944
891
|
continue;
|
|
945
|
-
yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new ProgramArray() : undefined, element);
|
|
892
|
+
yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new ProgramArray(self.runtime.prototypes.Array) : undefined, element);
|
|
946
893
|
if (element.type === "RestElement")
|
|
947
894
|
return;
|
|
948
895
|
continue;
|
|
@@ -961,7 +908,7 @@ class Frame {
|
|
|
961
908
|
if (!done)
|
|
962
909
|
rest.push(next.value);
|
|
963
910
|
}
|
|
964
|
-
yield* consume(element.argument, new ProgramArray(rest), element);
|
|
911
|
+
yield* consume(element.argument, new ProgramArray(self.runtime.prototypes.Array, rest), element);
|
|
965
912
|
return;
|
|
966
913
|
}
|
|
967
914
|
const consumed = consume(element, step.done ? undefined : step.value, pattern);
|
|
@@ -985,22 +932,13 @@ class Frame {
|
|
|
985
932
|
return Effect.succeed(String(keyNode.value));
|
|
986
933
|
throw unsupportedSyntax(keyNode.type, keyNode);
|
|
987
934
|
}
|
|
988
|
-
destructuringPropertyValue(source, key) {
|
|
989
|
-
if (!(source instanceof ProgramArray))
|
|
990
|
-
return get(source, key);
|
|
991
|
-
if (has(source, key))
|
|
992
|
-
return get(source, key);
|
|
993
|
-
if (typeof key === "string" && arrayMethods.has(key))
|
|
994
|
-
return new IntrinsicReference(source, key);
|
|
995
|
-
return undefined;
|
|
996
|
-
}
|
|
997
935
|
evaluateExpression(node) {
|
|
998
936
|
switch (node.type) {
|
|
999
937
|
case "Literal": {
|
|
1000
938
|
const regex = node.regex;
|
|
1001
939
|
if (regex)
|
|
1002
|
-
return Effect.sync(() => constructRegExp([regex.pattern, regex.flags], node));
|
|
1003
|
-
return Effect.sync(() => toProgram(node.value, "Literal"));
|
|
940
|
+
return Effect.sync(() => constructRegExp(this.runtime.prototypes, [regex.pattern, regex.flags], node));
|
|
941
|
+
return Effect.sync(() => toProgram(this.runtime.prototypes, node.value, "Literal"));
|
|
1004
942
|
}
|
|
1005
943
|
case "Identifier":
|
|
1006
944
|
return Effect.sync(() => this.scopes.get(node.name, node));
|
|
@@ -1058,7 +996,7 @@ class Frame {
|
|
|
1058
996
|
return Effect.gen(function* () {
|
|
1059
997
|
const callee = yield* self.evaluateExpression(node.callee);
|
|
1060
998
|
// Globals are built with this interpreter's R; `instanceof` cannot recover the type argument.
|
|
1061
|
-
const construct = callee instanceof
|
|
999
|
+
const construct = callee instanceof NativeFunction ? callee.construct : undefined;
|
|
1062
1000
|
if (construct === undefined) {
|
|
1063
1001
|
// `new` itself is supported, so a non-constructible callee is a TypeError like JS rather than
|
|
1064
1002
|
// unsupported syntax. Built-ins like Number are real constructors in JS, so do not claim
|
|
@@ -1066,13 +1004,13 @@ class Frame {
|
|
|
1066
1004
|
const name = calleeDescription(node.callee);
|
|
1067
1005
|
const message = callee instanceof ProgramFunction
|
|
1068
1006
|
? `${name} cannot be constructed: user-defined constructors and classes are not supported. Call it as a function that returns a plain object instead.`
|
|
1069
|
-
: callee instanceof
|
|
1007
|
+
: callee instanceof NativeFunction
|
|
1070
1008
|
? `new ${name}(...) is not supported; call ${name}(...) without new instead.`
|
|
1071
1009
|
: `${name} is not a constructor.`;
|
|
1072
|
-
throw new InterpreterRuntimeError(message, node)
|
|
1010
|
+
throw new InterpreterRuntimeError(message, node);
|
|
1073
1011
|
}
|
|
1074
1012
|
const args = yield* self.evaluateCallArguments(node.arguments);
|
|
1075
|
-
return yield* construct(args, node);
|
|
1013
|
+
return yield* construct(args, callee, node);
|
|
1076
1014
|
});
|
|
1077
1015
|
}
|
|
1078
1016
|
evaluateBinaryExpression(node) {
|
|
@@ -1086,7 +1024,7 @@ class Frame {
|
|
|
1086
1024
|
const rhs = yield* self.evaluateExpression(node.right);
|
|
1087
1025
|
if (operator === "instanceof")
|
|
1088
1026
|
return instanceofValue(lhs, rhs, node);
|
|
1089
|
-
return toProgram(self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
|
|
1027
|
+
return toProgram(self.runtime.prototypes, self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
|
|
1090
1028
|
});
|
|
1091
1029
|
}
|
|
1092
1030
|
applyBinaryOperator(operator, lhs, rhs, node) {
|
|
@@ -1103,7 +1041,7 @@ class Frame {
|
|
|
1103
1041
|
// Null-prototype data needs explicit primitive coercion; identity and `in` retain raw objects.
|
|
1104
1042
|
// Dates use their default string hint for addition and loose equality, and epoch time elsewhere.
|
|
1105
1043
|
const coerceOperand = (operand) => {
|
|
1106
|
-
if (operand instanceof
|
|
1044
|
+
if (operand instanceof ProgramDate) {
|
|
1107
1045
|
return operator === "+" || operator === "==" || operator === "!=" ? coerceToString(operand) : operand.time;
|
|
1108
1046
|
}
|
|
1109
1047
|
return operand !== null && typeof operand === "object" ? coerceToString(operand) : operand;
|
|
@@ -1188,7 +1126,7 @@ class Frame {
|
|
|
1188
1126
|
if (containsOpaqueReference(value)) {
|
|
1189
1127
|
throw new InterpreterRuntimeError("Unary operators require data values.", node, "InvalidDataValue");
|
|
1190
1128
|
}
|
|
1191
|
-
const operand = value instanceof
|
|
1129
|
+
const operand = value instanceof ProgramDate
|
|
1192
1130
|
? value.time
|
|
1193
1131
|
: value !== null && typeof value === "object"
|
|
1194
1132
|
? coerceToString(value)
|
|
@@ -1207,7 +1145,7 @@ class Frame {
|
|
|
1207
1145
|
default:
|
|
1208
1146
|
throw new InterpreterRuntimeError(`Unsupported unary operator '${operator}'.`, node);
|
|
1209
1147
|
}
|
|
1210
|
-
return toProgram(result, "Unary expression result");
|
|
1148
|
+
return toProgram(this.runtime.prototypes, result, "Unary expression result");
|
|
1211
1149
|
});
|
|
1212
1150
|
}
|
|
1213
1151
|
evaluateAssignmentExpression(node) {
|
|
@@ -1228,7 +1166,7 @@ class Frame {
|
|
|
1228
1166
|
if (operator !== "=") {
|
|
1229
1167
|
const current = self.scopes.get(name, left);
|
|
1230
1168
|
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1231
|
-
const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
|
|
1169
|
+
const next = toProgram(self.runtime.prototypes, self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
|
|
1232
1170
|
return self.scopes.set(name, next, left);
|
|
1233
1171
|
}
|
|
1234
1172
|
const rightValue = yield* self.evaluateNamed(node.right, name);
|
|
@@ -1238,7 +1176,7 @@ class Frame {
|
|
|
1238
1176
|
return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(node.right), (rightValue) => {
|
|
1239
1177
|
if (operator === "=")
|
|
1240
1178
|
return { write: true, next: rightValue, result: rightValue };
|
|
1241
|
-
const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
|
|
1179
|
+
const next = toProgram(self.runtime.prototypes, self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
|
|
1242
1180
|
return { write: true, next, result: next };
|
|
1243
1181
|
}));
|
|
1244
1182
|
}
|
|
@@ -1303,23 +1241,37 @@ class Frame {
|
|
|
1303
1241
|
}
|
|
1304
1242
|
throw new InterpreterRuntimeError("Update target must be an Identifier or MemberExpression.", argument);
|
|
1305
1243
|
}
|
|
1244
|
+
// EvaluateCall: a member callee supplies its base object as `this`; anything else calls with undefined.
|
|
1306
1245
|
evaluateCallExpression(node) {
|
|
1307
1246
|
const callee = node.callee;
|
|
1308
1247
|
const self = this;
|
|
1309
1248
|
return Effect.gen(function* () {
|
|
1310
1249
|
if (callee.type === "Super")
|
|
1311
1250
|
throw unsupportedSyntax(callee.type, callee);
|
|
1312
|
-
const callable =
|
|
1251
|
+
const { callable, thisValue } = callee.type === "MemberExpression"
|
|
1252
|
+
? yield* self.readMethod(callee)
|
|
1253
|
+
: { callable: yield* self.evaluateExpression(callee), thisValue: undefined };
|
|
1313
1254
|
if (callable === OptionalShortCircuit)
|
|
1314
1255
|
return OptionalShortCircuit;
|
|
1315
1256
|
if ((callable === null || callable === undefined) && node.optional)
|
|
1316
1257
|
return OptionalShortCircuit;
|
|
1317
1258
|
const args = yield* self.evaluateCallArguments(node.arguments);
|
|
1318
|
-
return yield* self.invokeCallable(callable, args, node, callee);
|
|
1259
|
+
return yield* self.invokeCallable(callable, thisValue, args, node, callee);
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
readMethod(node) {
|
|
1263
|
+
return Effect.map(this.getMemberReference(node), (reference) => {
|
|
1264
|
+
if (reference === OptionalShortCircuit)
|
|
1265
|
+
return { callable: OptionalShortCircuit, thisValue: undefined };
|
|
1266
|
+
if (reference instanceof ToolReference)
|
|
1267
|
+
return { callable: reference, thisValue: undefined };
|
|
1268
|
+
if ("value" in reference)
|
|
1269
|
+
return { callable: reference.value, thisValue: undefined };
|
|
1270
|
+
return { callable: this.readReference(reference, node), thisValue: reference.receiver };
|
|
1319
1271
|
});
|
|
1320
1272
|
}
|
|
1321
1273
|
// The single dispatch for every invocation: call expressions and callbacks share it.
|
|
1322
|
-
invokeCallable(callable, args, node, callee) {
|
|
1274
|
+
invokeCallable(callable, thisValue, args, node, callee) {
|
|
1323
1275
|
const self = this;
|
|
1324
1276
|
return Effect.gen(function* () {
|
|
1325
1277
|
if (callable instanceof ToolReference) {
|
|
@@ -1328,27 +1280,11 @@ class Frame {
|
|
|
1328
1280
|
}
|
|
1329
1281
|
return yield* self.createToolCallPromise(callable.path, args);
|
|
1330
1282
|
}
|
|
1331
|
-
if (callable instanceof ProgramFunction)
|
|
1283
|
+
if (callable instanceof ProgramFunction)
|
|
1332
1284
|
return yield* self.invokeFunction(callable, args);
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
return callable.generator;
|
|
1337
|
-
const requested = callable.generator.request(callable.kind, args[0], node);
|
|
1338
|
-
return callable.generator.asynchronous ? yield* self.createPromise(requested) : yield* requested;
|
|
1339
|
-
}
|
|
1340
|
-
if (callable instanceof IntrinsicReference) {
|
|
1341
|
-
return yield* invokeIntrinsic(self.runtime.runner, callable, args, node);
|
|
1342
|
-
}
|
|
1343
|
-
if (callable instanceof PromiseInstanceMethodReference) {
|
|
1344
|
-
return yield* invokePromiseInstanceMethod(self.runtime.runner, self.runtime.promises, callable, args, node);
|
|
1345
|
-
}
|
|
1346
|
-
if (callable instanceof HostFunction)
|
|
1347
|
-
return yield* callable.call(args, node);
|
|
1348
|
-
if (callable === undefined || callable === null) {
|
|
1349
|
-
throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node).as("TypeError");
|
|
1350
|
-
}
|
|
1351
|
-
throw new InterpreterRuntimeError("Only tools are callable here.", callee ?? node);
|
|
1285
|
+
if (callable instanceof NativeFunction)
|
|
1286
|
+
return yield* callable.call(thisValue, args, node);
|
|
1287
|
+
throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node);
|
|
1352
1288
|
});
|
|
1353
1289
|
}
|
|
1354
1290
|
evaluateCallArguments(argNodes) {
|
|
@@ -1360,7 +1296,7 @@ class Frame {
|
|
|
1360
1296
|
const spread = yield* self.evaluateExpression(argNode.argument);
|
|
1361
1297
|
const cursor = yield* self.syncIterator(spread, argNode);
|
|
1362
1298
|
if (cursor === undefined)
|
|
1363
|
-
throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode)
|
|
1299
|
+
throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode);
|
|
1364
1300
|
while (true) {
|
|
1365
1301
|
const step = yield* cursor.next;
|
|
1366
1302
|
if (step.done)
|
|
@@ -1376,6 +1312,7 @@ class Frame {
|
|
|
1376
1312
|
});
|
|
1377
1313
|
}
|
|
1378
1314
|
invokeFunction(fn, args) {
|
|
1315
|
+
const self = this;
|
|
1379
1316
|
const invocation = new Frame(this.runtime, new ScopeStack([...fn.capturedScopes, new Map()]));
|
|
1380
1317
|
const run = Effect.gen(function* () {
|
|
1381
1318
|
// Seed all parameters first so defaults cannot fall through to same-named outer bindings.
|
|
@@ -1387,7 +1324,7 @@ class Frame {
|
|
|
1387
1324
|
}
|
|
1388
1325
|
for (const [index, parameter] of fn.parameters.entries()) {
|
|
1389
1326
|
if (parameter.type === "RestElement") {
|
|
1390
|
-
yield* invocation.declarePattern(parameter.argument, new ProgramArray(args.slice(index)), true, parameter, true);
|
|
1327
|
+
yield* invocation.declarePattern(parameter.argument, new ProgramArray(self.runtime.prototypes.Array, args.slice(index)), true, parameter, true);
|
|
1391
1328
|
break;
|
|
1392
1329
|
}
|
|
1393
1330
|
yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
|
|
@@ -1410,10 +1347,12 @@ class Frame {
|
|
|
1410
1347
|
const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
|
|
1411
1348
|
invocation.generatorState = state;
|
|
1412
1349
|
invocation.generatorAsync = asynchronous;
|
|
1413
|
-
const
|
|
1350
|
+
const protos = this.runtime.prototypes;
|
|
1351
|
+
const result = (value, done) => record(protos.Object, { value, done });
|
|
1352
|
+
const request = (kind, value, node) => {
|
|
1414
1353
|
const request = { kind, value, response: Deferred.makeUnsafe() };
|
|
1415
1354
|
if (!asynchronous && state.active) {
|
|
1416
|
-
return Effect.fail(new InterpreterRuntimeError("Generator is already running.", node)
|
|
1355
|
+
return Effect.fail(new InterpreterRuntimeError("Generator is already running.", node));
|
|
1417
1356
|
}
|
|
1418
1357
|
if (asynchronous && (state.completed || (!state.started && kind !== "next"))) {
|
|
1419
1358
|
state.started = true;
|
|
@@ -1429,13 +1368,13 @@ class Frame {
|
|
|
1429
1368
|
if (state.completed) {
|
|
1430
1369
|
if (kind === "throw")
|
|
1431
1370
|
return Effect.fail(new ProgramThrow(value));
|
|
1432
|
-
return Effect.succeed(
|
|
1371
|
+
return Effect.succeed(result(kind === "return" ? value : undefined, true));
|
|
1433
1372
|
}
|
|
1434
1373
|
if (!state.started && kind !== "next") {
|
|
1435
1374
|
state.completed = true;
|
|
1436
1375
|
if (kind === "throw")
|
|
1437
1376
|
return Effect.fail(new ProgramThrow(value));
|
|
1438
|
-
return Effect.succeed(
|
|
1377
|
+
return Effect.succeed(result(value, true));
|
|
1439
1378
|
}
|
|
1440
1379
|
state.pending.push(request);
|
|
1441
1380
|
if (state.available) {
|
|
@@ -1455,7 +1394,7 @@ class Frame {
|
|
|
1455
1394
|
const active = state.active;
|
|
1456
1395
|
state.active = undefined;
|
|
1457
1396
|
if (active) {
|
|
1458
|
-
Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed(
|
|
1397
|
+
Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed(result(exit.value, true)) : exit);
|
|
1459
1398
|
}
|
|
1460
1399
|
yield* invocation.completeGeneratorRequests(state, asynchronous);
|
|
1461
1400
|
state.completed = true;
|
|
@@ -1463,11 +1402,13 @@ class Frame {
|
|
|
1463
1402
|
return Effect.andThen(this.runtime.promises.fork(body), Deferred.await(request.response));
|
|
1464
1403
|
}
|
|
1465
1404
|
return Deferred.await(request.response);
|
|
1466
|
-
}
|
|
1405
|
+
};
|
|
1406
|
+
const generator = new ProgramGenerator(asynchronous ? protos.AsyncGenerator : protos.Generator, asynchronous, request);
|
|
1467
1407
|
return generator;
|
|
1468
1408
|
}
|
|
1469
1409
|
completeGeneratorRequests(state, asynchronous) {
|
|
1470
1410
|
const self = this;
|
|
1411
|
+
const result = (value, done) => record(self.runtime.prototypes.Object, { value, done });
|
|
1471
1412
|
return Effect.gen(function* () {
|
|
1472
1413
|
while (true) {
|
|
1473
1414
|
const pending = self.dequeueGeneratorRequest(state);
|
|
@@ -1479,10 +1420,10 @@ class Frame {
|
|
|
1479
1420
|
}
|
|
1480
1421
|
if (asynchronous && pending.kind === "return") {
|
|
1481
1422
|
const resolved = yield* Effect.exit(self.awaitValue(pending.value));
|
|
1482
|
-
Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed(
|
|
1423
|
+
Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed(result(resolved.value, true)) : resolved);
|
|
1483
1424
|
continue;
|
|
1484
1425
|
}
|
|
1485
|
-
Deferred.doneUnsafe(pending.response, Exit.succeed(
|
|
1426
|
+
Deferred.doneUnsafe(pending.response, Exit.succeed(result(pending.kind === "return" ? pending.value : undefined, true)));
|
|
1486
1427
|
}
|
|
1487
1428
|
});
|
|
1488
1429
|
}
|
|
@@ -1523,7 +1464,7 @@ class Frame {
|
|
|
1523
1464
|
const state = this.generatorState;
|
|
1524
1465
|
if (!state?.active)
|
|
1525
1466
|
throw new InterpreterRuntimeError("Generator has no active request.", node);
|
|
1526
|
-
Deferred.doneUnsafe(state.active.response, Exit.succeed(record({ value, done: false })));
|
|
1467
|
+
Deferred.doneUnsafe(state.active.response, Exit.succeed(record(this.runtime.prototypes.Object, { value, done: false })));
|
|
1527
1468
|
state.active = undefined;
|
|
1528
1469
|
return Effect.flatMap(this.takeGeneratorRequest(state), (request) => {
|
|
1529
1470
|
state.active = request;
|
|
@@ -1541,9 +1482,9 @@ class Frame {
|
|
|
1541
1482
|
return Effect.gen(function* () {
|
|
1542
1483
|
if (value instanceof ProgramArray ||
|
|
1543
1484
|
typeof value === "string" ||
|
|
1544
|
-
value instanceof
|
|
1545
|
-
value instanceof
|
|
1546
|
-
value instanceof
|
|
1485
|
+
value instanceof ProgramMap ||
|
|
1486
|
+
value instanceof ProgramSet ||
|
|
1487
|
+
value instanceof ProgramURLSearchParams) {
|
|
1547
1488
|
const cursor = yield* self.syncIterator(value, node);
|
|
1548
1489
|
if (!cursor)
|
|
1549
1490
|
throw new InterpreterRuntimeError("Built-in iterator is unavailable.", node);
|
|
@@ -1561,29 +1502,25 @@ class Frame {
|
|
|
1561
1502
|
}
|
|
1562
1503
|
if (error instanceof ProgramThrow) {
|
|
1563
1504
|
yield* cursor.close;
|
|
1564
|
-
throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node)
|
|
1505
|
+
throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node);
|
|
1565
1506
|
}
|
|
1566
1507
|
return yield* Effect.failCause(resumed.cause);
|
|
1567
1508
|
}
|
|
1568
1509
|
}
|
|
1569
1510
|
const iterator = yield* self.customIterator(value, node, self.generatorAsync);
|
|
1570
1511
|
if (!iterator)
|
|
1571
|
-
throw new InterpreterRuntimeError("yield* requires a compatible iterable value.", node)
|
|
1512
|
+
throw new InterpreterRuntimeError("yield* requires a compatible iterable value.", node);
|
|
1572
1513
|
let kind = "next";
|
|
1573
1514
|
let input = undefined;
|
|
1574
1515
|
while (true) {
|
|
1575
|
-
const method = kind === "next"
|
|
1576
|
-
? iterator.next
|
|
1577
|
-
: iterator.iterator instanceof CodeModeGenerator
|
|
1578
|
-
? new GeneratorMethodReference(iterator.iterator, kind)
|
|
1579
|
-
: get(iterator.iterator, kind);
|
|
1516
|
+
const method = kind === "next" ? iterator.next : get(iterator.iterator, kind);
|
|
1580
1517
|
if (method === undefined || method === null) {
|
|
1581
1518
|
if (kind === "return")
|
|
1582
1519
|
return yield* Effect.fail(new GeneratorReturn(input));
|
|
1583
1520
|
yield* self.closeIterator(iterator, node, self.generatorAsync);
|
|
1584
|
-
throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node)
|
|
1521
|
+
throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node);
|
|
1585
1522
|
}
|
|
1586
|
-
const called = yield* self.invokeCallable(self.requireIteratorMethod(method, `Iterator ${kind}`, node), [input], node);
|
|
1523
|
+
const called = yield* self.invokeCallable(self.requireIteratorMethod(method, `Iterator ${kind}`, node), iterator.iterator, [input], node);
|
|
1587
1524
|
const result = self.requireIteratorObject(iterator.asynchronous ? yield* self.awaitValue(called) : called, `Iterator ${kind}() result`, node);
|
|
1588
1525
|
const done = Boolean(get(result, "done"));
|
|
1589
1526
|
const resultValue = self.generatorAsync && !iterator.asynchronous
|
|
@@ -1610,7 +1547,7 @@ class Frame {
|
|
|
1610
1547
|
});
|
|
1611
1548
|
}
|
|
1612
1549
|
evaluateObjectExpression(node) {
|
|
1613
|
-
const objectValue = new ProgramObject();
|
|
1550
|
+
const objectValue = new ProgramObject(this.runtime.prototypes.Object);
|
|
1614
1551
|
const self = this;
|
|
1615
1552
|
return Effect.gen(function* () {
|
|
1616
1553
|
for (const property of node.properties) {
|
|
@@ -1618,7 +1555,7 @@ class Frame {
|
|
|
1618
1555
|
const spread = yield* self.evaluateExpression(property.argument);
|
|
1619
1556
|
if (spread === null || spread === undefined)
|
|
1620
1557
|
continue;
|
|
1621
|
-
assign(objectValue, enumerableSource("Object spread", spread, property));
|
|
1558
|
+
assign(objectValue, enumerableSource(self.runtime.runner, "Object spread", spread, property));
|
|
1622
1559
|
continue;
|
|
1623
1560
|
}
|
|
1624
1561
|
if (property.kind !== "init") {
|
|
@@ -1643,7 +1580,7 @@ class Frame {
|
|
|
1643
1580
|
: key === AsyncIteratorSymbol
|
|
1644
1581
|
? "[Symbol.asyncIterator]"
|
|
1645
1582
|
: String(key);
|
|
1646
|
-
|
|
1583
|
+
define(objectValue, key, yield* self.evaluateNamed(property.value, name));
|
|
1647
1584
|
}
|
|
1648
1585
|
return objectValue;
|
|
1649
1586
|
});
|
|
@@ -1662,7 +1599,7 @@ class Frame {
|
|
|
1662
1599
|
const spread = yield* self.evaluateExpression(element.argument);
|
|
1663
1600
|
const cursor = yield* self.syncIterator(spread, element);
|
|
1664
1601
|
if (cursor === undefined)
|
|
1665
|
-
throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element)
|
|
1602
|
+
throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element);
|
|
1666
1603
|
while (true) {
|
|
1667
1604
|
const step = yield* cursor.next;
|
|
1668
1605
|
if (step.done)
|
|
@@ -1674,7 +1611,7 @@ class Frame {
|
|
|
1674
1611
|
values.push(yield* self.evaluateExpression(element));
|
|
1675
1612
|
}
|
|
1676
1613
|
}
|
|
1677
|
-
return new ProgramArray(values);
|
|
1614
|
+
return new ProgramArray(self.runtime.prototypes.Array, values);
|
|
1678
1615
|
});
|
|
1679
1616
|
}
|
|
1680
1617
|
evaluateTemplateLiteral(node) {
|
|
@@ -1692,7 +1629,7 @@ class Frame {
|
|
|
1692
1629
|
output += quasi.value.cooked;
|
|
1693
1630
|
if (index < expressions.length) {
|
|
1694
1631
|
const raw = yield* self.evaluateExpression(expressions[index]);
|
|
1695
|
-
output += coerceToString(toProgram(raw, "Template interpolation"));
|
|
1632
|
+
output += coerceToString(toProgram(self.runtime.prototypes, raw, "Template interpolation"));
|
|
1696
1633
|
}
|
|
1697
1634
|
}
|
|
1698
1635
|
return output;
|
|
@@ -1707,7 +1644,7 @@ class Frame {
|
|
|
1707
1644
|
}
|
|
1708
1645
|
return this.applyBinaryOperator(operator.slice(0, -1), current, incoming, node);
|
|
1709
1646
|
}
|
|
1710
|
-
getMemberReference(node
|
|
1647
|
+
getMemberReference(node) {
|
|
1711
1648
|
const objectNode = node.object;
|
|
1712
1649
|
const propertyNode = node.property;
|
|
1713
1650
|
if (objectNode.type === "Super")
|
|
@@ -1732,123 +1669,49 @@ class Frame {
|
|
|
1732
1669
|
}
|
|
1733
1670
|
return new ToolReference([...objectValue.path, key]);
|
|
1734
1671
|
}
|
|
1735
|
-
if (objectValue instanceof
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
// Values have no prototype chain, so `.constructor` resolves to the owning built-in directly.
|
|
1740
|
-
if (operation === "read" &&
|
|
1741
|
-
key === "constructor" &&
|
|
1742
|
-
!(objectValue instanceof ProgramObject && has(objectValue, key))) {
|
|
1743
|
-
const name = constructorName(objectValue);
|
|
1744
|
-
if (name !== undefined)
|
|
1745
|
-
return new ComputedValue(self.runtime.builtins.get(name));
|
|
1746
|
-
}
|
|
1672
|
+
if (objectValue instanceof ProgramObject)
|
|
1673
|
+
return { target: objectValue, key, receiver: objectValue };
|
|
1674
|
+
// Primitives read through their wrapper prototype without being boxed; strings own length and indexes.
|
|
1675
|
+
const protos = self.runtime.prototypes;
|
|
1747
1676
|
if (typeof objectValue === "string") {
|
|
1748
1677
|
if (key === "length")
|
|
1749
|
-
return
|
|
1678
|
+
return { value: objectValue.length };
|
|
1750
1679
|
const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
|
|
1751
1680
|
if (index !== undefined)
|
|
1752
|
-
return
|
|
1753
|
-
|
|
1754
|
-
return new IntrinsicReference(objectValue, key);
|
|
1755
|
-
return new ComputedValue(undefined);
|
|
1756
|
-
}
|
|
1757
|
-
if (typeof objectValue === "number") {
|
|
1758
|
-
if (typeof key === "string" && numberMethods.has(key))
|
|
1759
|
-
return new IntrinsicReference(objectValue, key);
|
|
1760
|
-
return new ComputedValue(undefined);
|
|
1761
|
-
}
|
|
1762
|
-
if (objectValue instanceof Values.Date) {
|
|
1763
|
-
if (typeof key === "string" && dateMethods.has(key))
|
|
1764
|
-
return new IntrinsicReference(objectValue, key);
|
|
1765
|
-
return new ComputedValue(undefined);
|
|
1766
|
-
}
|
|
1767
|
-
if (objectValue instanceof Values.RegExp) {
|
|
1768
|
-
if (key === "lastIndex")
|
|
1769
|
-
return { target: objectValue, key };
|
|
1770
|
-
if (typeof key === "string" && regexpProperties.has(key)) {
|
|
1771
|
-
return new ComputedValue(objectValue.regex[key]);
|
|
1772
|
-
}
|
|
1773
|
-
if (typeof key === "string" && regexpMethods.has(key))
|
|
1774
|
-
return new IntrinsicReference(objectValue, key);
|
|
1775
|
-
return new ComputedValue(undefined);
|
|
1776
|
-
}
|
|
1777
|
-
if (objectValue instanceof Values.Map) {
|
|
1778
|
-
if (key === "size")
|
|
1779
|
-
return new ComputedValue(objectValue.map.size);
|
|
1780
|
-
if (typeof key === "string" && mapMethods.has(key))
|
|
1781
|
-
return new IntrinsicReference(objectValue, key);
|
|
1782
|
-
return new ComputedValue(undefined);
|
|
1783
|
-
}
|
|
1784
|
-
if (objectValue instanceof Values.Set) {
|
|
1785
|
-
if (key === "size")
|
|
1786
|
-
return new ComputedValue(objectValue.set.size);
|
|
1787
|
-
if (typeof key === "string" && setMethods.has(key))
|
|
1788
|
-
return new IntrinsicReference(objectValue, key);
|
|
1789
|
-
return new ComputedValue(undefined);
|
|
1790
|
-
}
|
|
1791
|
-
if (objectValue instanceof Values.URL) {
|
|
1792
|
-
if (key === "searchParams") {
|
|
1793
|
-
return new ComputedValue(objectValue.searchParams);
|
|
1794
|
-
}
|
|
1795
|
-
if (typeof key === "string" && urlMethods.has(key))
|
|
1796
|
-
return new IntrinsicReference(objectValue, key);
|
|
1797
|
-
if (typeof key === "string" && urlProperties.has(key))
|
|
1798
|
-
return { target: objectValue, key };
|
|
1799
|
-
return new ComputedValue(undefined);
|
|
1800
|
-
}
|
|
1801
|
-
if (objectValue instanceof Values.URLSearchParams) {
|
|
1802
|
-
if (key === "size")
|
|
1803
|
-
return new ComputedValue(objectValue.params.size);
|
|
1804
|
-
if (typeof key === "string" && urlSearchParamsMethods.has(key)) {
|
|
1805
|
-
return new IntrinsicReference(objectValue, key);
|
|
1806
|
-
}
|
|
1807
|
-
return new ComputedValue(undefined);
|
|
1808
|
-
}
|
|
1809
|
-
// Reject unknown promise properties so a missing await cannot hide.
|
|
1810
|
-
if (objectValue instanceof Values.Promise) {
|
|
1811
|
-
if (key === "then" || key === "catch" || key === "finally") {
|
|
1812
|
-
return new PromiseInstanceMethodReference(objectValue, key);
|
|
1813
|
-
}
|
|
1814
|
-
throw new InterpreterRuntimeError("This value is an un-awaited Promise; await it first - e.g. `const result = await tools.ns.tool(...)`.", objectNode, "InvalidDataValue");
|
|
1815
|
-
}
|
|
1816
|
-
if (objectValue instanceof CodeModeGenerator) {
|
|
1817
|
-
if (key === "next" || key === "return" || key === "throw") {
|
|
1818
|
-
return new GeneratorMethodReference(objectValue, key);
|
|
1819
|
-
}
|
|
1820
|
-
if ((key === IteratorSymbol && !objectValue.asynchronous) ||
|
|
1821
|
-
(key === AsyncIteratorSymbol && objectValue.asynchronous)) {
|
|
1822
|
-
return new GeneratorMethodReference(objectValue, "iterator");
|
|
1823
|
-
}
|
|
1824
|
-
return new ComputedValue(undefined);
|
|
1681
|
+
return { value: objectValue[index] };
|
|
1682
|
+
return { target: protos.String, key, receiver: objectValue };
|
|
1825
1683
|
}
|
|
1826
|
-
if (objectValue
|
|
1827
|
-
return { target:
|
|
1828
|
-
if (
|
|
1829
|
-
|
|
1684
|
+
if (typeof objectValue === "number")
|
|
1685
|
+
return { target: protos.Number, key, receiver: objectValue };
|
|
1686
|
+
if (typeof objectValue === "boolean")
|
|
1687
|
+
return { target: protos.Boolean, key, receiver: objectValue };
|
|
1688
|
+
if (objectValue === null || objectValue === undefined) {
|
|
1689
|
+
throw new InterpreterRuntimeError(`Cannot read properties of ${objectValue} (reading '${String(key)}').`, objectNode);
|
|
1830
1690
|
}
|
|
1831
1691
|
throw new InterpreterRuntimeError("Cannot access a property on a non-object value.", objectNode);
|
|
1832
1692
|
});
|
|
1833
1693
|
}
|
|
1694
|
+
readReference(reference, node) {
|
|
1695
|
+
// Reject unknown promise properties so a missing await cannot hide.
|
|
1696
|
+
if (reference.target instanceof ProgramPromise && !has(reference.target, reference.key)) {
|
|
1697
|
+
throw new InterpreterRuntimeError("This value is an un-awaited Promise; await it first - e.g. `const result = await tools.ns.tool(...)`.", node.object, "InvalidDataValue");
|
|
1698
|
+
}
|
|
1699
|
+
try {
|
|
1700
|
+
return get(reference.target, reference.key, reference.receiver);
|
|
1701
|
+
}
|
|
1702
|
+
catch (error) {
|
|
1703
|
+
throw locate(error, node);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1834
1706
|
readMember(node) {
|
|
1835
|
-
const self = this;
|
|
1836
1707
|
return Effect.map(this.getMemberReference(node), (reference) => {
|
|
1837
1708
|
if (reference === OptionalShortCircuit)
|
|
1838
1709
|
return OptionalShortCircuit;
|
|
1839
|
-
if (reference instanceof
|
|
1840
|
-
return reference.value;
|
|
1841
|
-
if (reference === undefined || isOpaqueMemberReference(reference))
|
|
1710
|
+
if (reference instanceof ToolReference)
|
|
1842
1711
|
return reference;
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
typeof reference.key === "string" &&
|
|
1847
|
-
arrayMethods.has(reference.key) &&
|
|
1848
|
-
!has(reference.target, reference.key)) {
|
|
1849
|
-
return new IntrinsicReference(reference.target, reference.key);
|
|
1850
|
-
}
|
|
1851
|
-
return value;
|
|
1712
|
+
if ("value" in reference)
|
|
1713
|
+
return reference.value;
|
|
1714
|
+
return this.readReference(reference, node);
|
|
1852
1715
|
});
|
|
1853
1716
|
}
|
|
1854
1717
|
writeMember(node, value) {
|
|
@@ -1859,75 +1722,50 @@ class Frame {
|
|
|
1859
1722
|
if (target.type !== "MemberExpression") {
|
|
1860
1723
|
throw new InterpreterRuntimeError("Only data fields may be deleted.", argument);
|
|
1861
1724
|
}
|
|
1862
|
-
return Effect.map(this.getMemberReference(target
|
|
1725
|
+
return Effect.map(this.getMemberReference(target), (reference) => {
|
|
1863
1726
|
if (reference === OptionalShortCircuit)
|
|
1864
1727
|
return true;
|
|
1865
|
-
if (reference instanceof
|
|
1866
|
-
reference === undefined ||
|
|
1867
|
-
isOpaqueMemberReference(reference) ||
|
|
1868
|
-
reference.target instanceof Values.URL) {
|
|
1728
|
+
if (reference instanceof ToolReference || "value" in reference || reference.receiver !== reference.target) {
|
|
1869
1729
|
throw new InterpreterRuntimeError("Only data fields may be deleted.", target, "InvalidDataValue");
|
|
1870
1730
|
}
|
|
1871
|
-
if (reference.target
|
|
1872
|
-
return
|
|
1873
|
-
}
|
|
1874
|
-
return remove(reference.target, reference.key);
|
|
1731
|
+
if (remove(reference.target, reference.key))
|
|
1732
|
+
return true;
|
|
1733
|
+
throw new InterpreterRuntimeError(`Cannot delete property '${String(reference.key)}'.`, target);
|
|
1875
1734
|
});
|
|
1876
1735
|
}
|
|
1877
1736
|
// Resolve side-effecting object and key expressions exactly once.
|
|
1878
1737
|
modifyMember(node, compute) {
|
|
1879
1738
|
const self = this;
|
|
1880
1739
|
return Effect.gen(function* () {
|
|
1881
|
-
const reference = yield* self.getMemberReference(node
|
|
1882
|
-
if (reference === OptionalShortCircuit ||
|
|
1883
|
-
reference instanceof ComputedValue ||
|
|
1884
|
-
reference === undefined ||
|
|
1885
|
-
isOpaqueMemberReference(reference)) {
|
|
1740
|
+
const reference = yield* self.getMemberReference(node);
|
|
1741
|
+
if (reference === OptionalShortCircuit || reference instanceof ToolReference || "value" in reference) {
|
|
1886
1742
|
throw new InterpreterRuntimeError("Only data fields may be assigned.", node);
|
|
1887
1743
|
}
|
|
1744
|
+
if (reference.receiver !== reference.target) {
|
|
1745
|
+
throw new InterpreterRuntimeError(`Cannot create property '${String(reference.key)}' on ${typeof reference.receiver} '${String(reference.receiver)}'.`, node);
|
|
1746
|
+
}
|
|
1888
1747
|
const key = reference.key;
|
|
1889
|
-
const { write, next, result } = yield* compute(self.
|
|
1748
|
+
const { write, next, result } = yield* compute(self.readReference(reference, node));
|
|
1890
1749
|
if (write)
|
|
1891
|
-
self.assignToReference(reference, key, next, node);
|
|
1750
|
+
self.assignToReference(reference.target, key, next, node);
|
|
1892
1751
|
return result;
|
|
1893
1752
|
});
|
|
1894
1753
|
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
}
|
|
1899
|
-
if (reference.target instanceof Values.RegExp)
|
|
1900
|
-
return reference.target.lastIndex;
|
|
1901
|
-
return get(reference.target, key);
|
|
1902
|
-
}
|
|
1903
|
-
assignToReference(reference, key, next, node) {
|
|
1904
|
-
if (reference.target instanceof Values.URL) {
|
|
1905
|
-
const property = key;
|
|
1906
|
-
if (!urlWritableProperties.has(property)) {
|
|
1907
|
-
throw new InterpreterRuntimeError(`URL.${property} is read-only.`, node).as("TypeError");
|
|
1908
|
-
}
|
|
1754
|
+
assignToReference(target, key, next, node) {
|
|
1755
|
+
rejectCircularInsertion(target, next, target instanceof ProgramArray ? "Array assignment result" : "Object assignment result", node);
|
|
1756
|
+
const written = (() => {
|
|
1909
1757
|
try {
|
|
1910
|
-
|
|
1911
|
-
url[property] = uriArgument(next, `URL.${property} value`);
|
|
1912
|
-
return;
|
|
1758
|
+
return set(target, key, next);
|
|
1913
1759
|
}
|
|
1914
1760
|
catch (error) {
|
|
1915
|
-
|
|
1916
|
-
throw error;
|
|
1917
|
-
throw new InterpreterRuntimeError(`URL.${property} received an invalid value.`, node).as("TypeError");
|
|
1761
|
+
throw locate(error, node);
|
|
1918
1762
|
}
|
|
1919
|
-
}
|
|
1920
|
-
if (
|
|
1921
|
-
reference.target.lastIndex = next;
|
|
1922
|
-
return;
|
|
1923
|
-
}
|
|
1924
|
-
const target = reference.target;
|
|
1925
|
-
rejectCircularInsertion(target, next, target instanceof ProgramArray ? "Array assignment result" : "Object assignment result", node);
|
|
1926
|
-
if (set(target, key, next))
|
|
1763
|
+
})();
|
|
1764
|
+
if (written)
|
|
1927
1765
|
return;
|
|
1928
|
-
if (target instanceof ProgramArray)
|
|
1929
|
-
throw
|
|
1930
|
-
throw new InterpreterRuntimeError(`Cannot assign to read only property '${String(key)}'.`, node)
|
|
1766
|
+
if (target instanceof ProgramArray && key === "length")
|
|
1767
|
+
throw rangeError("Invalid array length", node);
|
|
1768
|
+
throw new InterpreterRuntimeError(`Cannot assign to read only property '${String(key)}'.`, node);
|
|
1931
1769
|
}
|
|
1932
1770
|
toPropertyKey(value, node) {
|
|
1933
1771
|
if (typeof value === "string" || typeof value === "number") {
|