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