@opencode/codemode 0.0.0-beta-19296 → 0.0.0-beta-19378
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/codemode.d.ts +8 -11
- package/dist/codemode.js +4 -8
- package/dist/data.d.ts +28 -0
- package/dist/data.js +130 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/errors.d.ts +4 -6
- package/dist/interpreter/errors.js +22 -6
- package/dist/interpreter/execute.d.ts +3 -3
- package/dist/interpreter/execute.js +11 -18
- package/dist/interpreter/globals.d.ts +13 -0
- package/dist/interpreter/globals.js +59 -0
- package/dist/interpreter/host.d.ts +41 -0
- package/dist/interpreter/host.js +44 -0
- package/dist/interpreter/methods.d.ts +3 -16
- package/dist/interpreter/methods.js +42 -239
- package/dist/interpreter/model.d.ts +12 -73
- package/dist/interpreter/model.js +0 -87
- package/dist/interpreter/promises.d.ts +12 -13
- package/dist/interpreter/promises.js +49 -26
- package/dist/interpreter/references.js +23 -70
- package/dist/interpreter/runner.d.ts +23 -0
- package/dist/interpreter/runner.js +42 -0
- package/dist/interpreter/runtime.d.ts +13 -95
- package/dist/interpreter/runtime.js +290 -723
- package/dist/openapi/spec.js +1 -1
- package/dist/stdlib/array.d.ts +3 -0
- package/dist/stdlib/array.js +73 -0
- package/dist/stdlib/collections.d.ts +6 -1
- package/dist/stdlib/collections.js +120 -1
- package/dist/stdlib/console.d.ts +3 -2
- package/dist/stdlib/console.js +25 -16
- package/dist/stdlib/date.d.ts +5 -4
- package/dist/stdlib/date.js +28 -12
- package/dist/stdlib/json.d.ts +4 -4
- package/dist/stdlib/json.js +23 -28
- package/dist/stdlib/math.d.ts +3 -7
- package/dist/stdlib/math.js +85 -153
- package/dist/stdlib/number.d.ts +2 -4
- package/dist/stdlib/number.js +30 -37
- package/dist/stdlib/object.d.ts +4 -6
- package/dist/stdlib/object.js +106 -75
- package/dist/stdlib/regexp.d.ts +4 -6
- package/dist/stdlib/regexp.js +35 -12
- package/dist/stdlib/string.d.ts +1 -3
- package/dist/stdlib/string.js +15 -17
- package/dist/stdlib/url.d.ts +10 -6
- package/dist/stdlib/url.js +102 -25
- package/dist/stdlib/value.d.ts +6 -5
- package/dist/stdlib/value.js +33 -32
- package/dist/tool-runtime.d.ts +16 -15
- package/dist/tool-runtime.js +13 -150
- package/dist/values.d.ts +22 -16
- package/dist/values.js +23 -17
- package/package.json +1 -1
- package/dist/interpreter/iterator.d.ts +0 -13
- package/dist/interpreter/iterator.js +0 -4
- package/dist/stdlib/promise.d.ts +0 -2
- package/dist/stdlib/promise.js +0 -1
|
@@ -1,35 +1,23 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit } from "effect";
|
|
2
|
-
import { isBlockedMember,
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { isBlockedMember, ToolRuntimeError, toProgram } from "../data.js";
|
|
3
|
+
import { ToolReference } from "../tool-runtime.js";
|
|
4
|
+
import { AsyncIteratorSymbol, CodeModeFunction, CodeModeGenerator, ComputedValue, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, isRecord, IteratorSymbol, IteratorSymbols, OptionalShortCircuit, PromiseInstanceMethodReference, ProgramThrow, unsupportedSyntax, } from "./model.js";
|
|
5
|
+
import { caughtErrorValue } from "./errors.js";
|
|
6
|
+
import { globals } from "./globals.js";
|
|
7
|
+
import { HostFunction, HostNamespace } from "./host.js";
|
|
8
|
+
import { invokeIntrinsic } from "./methods.js";
|
|
9
|
+
import { preserveConsumerError } from "./runner.js";
|
|
10
|
+
import { invokePromiseInstanceMethod, PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
|
|
8
11
|
import { containsOpaqueReference, isRuntimeReference, rejectCircularInsertion, typeofValue } from "./references.js";
|
|
9
12
|
import { ScopeStack } from "./scope.js";
|
|
10
|
-
import { arrayMethods, mapMethods,
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { escapeRegexHint, regexpMethods, regexpProperties, regexpStatics, regexFailureReason, } from "../stdlib/regexp.js";
|
|
19
|
-
import { stringMethods, stringStatics } from "../stdlib/string.js";
|
|
20
|
-
import { urlMethods, urlProperties, urlSearchParamsMethods, urlStatics, urlWritableProperties, invokeUriFunction, uriArgument, urlArgument, } from "../stdlib/url.js";
|
|
21
|
-
import { boundedData, coerceToNumber, coerceToString, compoundOperators, errorBrandName, errorConstructors, invokeCoercion, valueConstructors, } from "../stdlib/value.js";
|
|
22
|
-
import { isCodeModeValue, CodeModeDate, CodeModeMap, CodeModePromise, CodeModeRegExp, CodeModeSet, CodeModeURL, CodeModeURLSearchParams, } from "../values.js";
|
|
23
|
-
const globalStaticMembers = {
|
|
24
|
-
Object: objectStatics,
|
|
25
|
-
Math: mathMethods,
|
|
26
|
-
Array: arrayStatics,
|
|
27
|
-
console: consoleMethods,
|
|
28
|
-
Date: dateStatics,
|
|
29
|
-
RegExp: regexpStatics,
|
|
30
|
-
Map: mapStatics,
|
|
31
|
-
URL: urlStatics,
|
|
32
|
-
};
|
|
13
|
+
import { arrayMethods, mapMethods, setMethods } from "../stdlib/collections.js";
|
|
14
|
+
import { dateMethods } from "../stdlib/date.js";
|
|
15
|
+
import { numberMethods } from "../stdlib/number.js";
|
|
16
|
+
import { constructRegExp, regexpMethods, regexpProperties } from "../stdlib/regexp.js";
|
|
17
|
+
import { stringMethods } from "../stdlib/string.js";
|
|
18
|
+
import { uriArgument, urlMethods, urlProperties, urlSearchParamsMethods, urlWritableProperties } from "../stdlib/url.js";
|
|
19
|
+
import { coerceToNumber, coerceToString, compoundOperators } from "../stdlib/value.js";
|
|
20
|
+
import { Values } from "../values.js";
|
|
33
21
|
const MAX_ARRAY_LENGTH = 4_294_967_295;
|
|
34
22
|
const parseArrayIndex = (key) => {
|
|
35
23
|
const property = String(key);
|
|
@@ -39,74 +27,46 @@ const parseArrayIndex = (key) => {
|
|
|
39
27
|
return index < MAX_ARRAY_LENGTH ? index : undefined;
|
|
40
28
|
};
|
|
41
29
|
const calleeDescription = (callee) => {
|
|
42
|
-
if (callee
|
|
43
|
-
return
|
|
44
|
-
if (callee
|
|
45
|
-
const object =
|
|
46
|
-
const property =
|
|
47
|
-
const key = callee.computed
|
|
48
|
-
?
|
|
30
|
+
if (callee?.type === "Identifier")
|
|
31
|
+
return callee.name;
|
|
32
|
+
if (callee?.type === "MemberExpression") {
|
|
33
|
+
const object = callee.object;
|
|
34
|
+
const property = callee.property;
|
|
35
|
+
const key = !callee.computed && property.type === "Identifier"
|
|
36
|
+
? property.name
|
|
49
37
|
: property.type === "Literal" && typeof property.value === "string"
|
|
50
38
|
? property.value
|
|
51
39
|
: undefined;
|
|
52
40
|
if (object.type === "Identifier" && key !== undefined)
|
|
53
|
-
return `${
|
|
41
|
+
return `${object.name}.${key}`;
|
|
54
42
|
}
|
|
55
43
|
return "The called value";
|
|
56
44
|
};
|
|
57
45
|
const instanceofValue = (lhs, rhs, node) => {
|
|
58
|
-
if (rhs instanceof
|
|
59
|
-
|
|
60
|
-
return brand !== undefined && (rhs.name === "Error" || brand === rhs.name);
|
|
61
|
-
}
|
|
62
|
-
if (rhs instanceof GlobalNamespace) {
|
|
63
|
-
switch (rhs.name) {
|
|
64
|
-
case "Date":
|
|
65
|
-
return lhs instanceof CodeModeDate;
|
|
66
|
-
case "RegExp":
|
|
67
|
-
return lhs instanceof CodeModeRegExp;
|
|
68
|
-
case "Map":
|
|
69
|
-
return lhs instanceof CodeModeMap;
|
|
70
|
-
case "Set":
|
|
71
|
-
return lhs instanceof CodeModeSet;
|
|
72
|
-
case "URL":
|
|
73
|
-
return lhs instanceof CodeModeURL;
|
|
74
|
-
case "URLSearchParams":
|
|
75
|
-
return lhs instanceof CodeModeURLSearchParams;
|
|
76
|
-
case "Array":
|
|
77
|
-
return Array.isArray(lhs);
|
|
78
|
-
case "Object":
|
|
79
|
-
return lhs !== null && (typeof lhs === "object" || typeofValue(lhs) === "function");
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
if (rhs instanceof PromiseNamespace)
|
|
83
|
-
return lhs instanceof CodeModePromise;
|
|
84
|
-
if (rhs instanceof CoercionFunction && (rhs.name === "Number" || rhs.name === "String" || rhs.name === "Boolean")) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
46
|
+
if (rhs instanceof HostFunction && rhs.instanceOf !== undefined)
|
|
47
|
+
return rhs.instanceOf(lhs);
|
|
87
48
|
throw new InterpreterRuntimeError("The right-hand side of 'instanceof' must be a supported constructor: Error (or a specific error type like TypeError), Date, RegExp, Map, Set, URL, URLSearchParams, Array, Object, or Promise.", node);
|
|
88
49
|
};
|
|
89
50
|
const collectPatternNames = (pattern, out = []) => {
|
|
90
51
|
switch (pattern.type) {
|
|
91
52
|
case "Identifier":
|
|
92
|
-
out.push(
|
|
53
|
+
out.push(pattern.name);
|
|
93
54
|
break;
|
|
94
55
|
case "AssignmentPattern":
|
|
95
|
-
collectPatternNames(
|
|
56
|
+
collectPatternNames(pattern.left, out);
|
|
96
57
|
break;
|
|
97
58
|
case "RestElement":
|
|
98
|
-
collectPatternNames(
|
|
59
|
+
collectPatternNames(pattern.argument, out);
|
|
99
60
|
break;
|
|
100
61
|
case "ArrayPattern":
|
|
101
|
-
for (const element of
|
|
62
|
+
for (const element of pattern.elements) {
|
|
102
63
|
if (element !== null)
|
|
103
|
-
collectPatternNames(
|
|
64
|
+
collectPatternNames(element, out);
|
|
104
65
|
}
|
|
105
66
|
break;
|
|
106
67
|
case "ObjectPattern":
|
|
107
|
-
for (const
|
|
108
|
-
|
|
109
|
-
collectPatternNames(prop.type === "RestElement" ? getNode(prop, "argument") : getNode(prop, "value"), out);
|
|
68
|
+
for (const prop of pattern.properties) {
|
|
69
|
+
collectPatternNames(prop.type === "RestElement" ? prop.argument : prop.value, out);
|
|
110
70
|
}
|
|
111
71
|
break;
|
|
112
72
|
}
|
|
@@ -115,23 +75,20 @@ const collectPatternNames = (pattern, out = []) => {
|
|
|
115
75
|
const loopDeclaration = (left, statement) => {
|
|
116
76
|
if (left.type !== "VariableDeclaration")
|
|
117
77
|
return undefined;
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
78
|
+
const declaration = left.declarations.length === 1 ? left.declarations[0] : undefined;
|
|
79
|
+
if (declaration === undefined) {
|
|
120
80
|
throw new InterpreterRuntimeError(`${statement} supports one declared binding.`, left);
|
|
121
81
|
}
|
|
122
|
-
const kind =
|
|
82
|
+
const kind = left.kind;
|
|
123
83
|
return {
|
|
124
|
-
pattern:
|
|
84
|
+
pattern: declaration.id,
|
|
125
85
|
mutable: kind !== "const",
|
|
126
86
|
lexical: kind !== "var",
|
|
127
87
|
};
|
|
128
88
|
};
|
|
129
89
|
const isOpaqueMemberReference = (value) => value instanceof ToolReference ||
|
|
130
|
-
value instanceof PromiseMethodReference ||
|
|
131
90
|
value instanceof PromiseInstanceMethodReference ||
|
|
132
91
|
value instanceof IntrinsicReference ||
|
|
133
|
-
value instanceof GlobalMethodReference ||
|
|
134
|
-
value instanceof JsonMethodReference ||
|
|
135
92
|
value instanceof GeneratorMethodReference;
|
|
136
93
|
const copyIteratorSymbols = (source, target, consumed) => {
|
|
137
94
|
for (const symbol of IteratorSymbols) {
|
|
@@ -139,62 +96,47 @@ const copyIteratorSymbols = (source, target, consumed) => {
|
|
|
139
96
|
Reflect.set(target, symbol, Reflect.get(source, symbol));
|
|
140
97
|
}
|
|
141
98
|
};
|
|
142
|
-
const promiseResolutionNode = { type: "PromiseResolution" };
|
|
143
|
-
|
|
144
|
-
|
|
99
|
+
const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
|
|
100
|
+
/** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
|
|
101
|
+
export class Runtime {
|
|
145
102
|
executeTool;
|
|
146
|
-
|
|
103
|
+
search;
|
|
147
104
|
toolKeys;
|
|
148
|
-
logs;
|
|
149
105
|
promises;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
invokeCallable: (callable, args, node) => this.invokeCallable(callable, args, node),
|
|
155
|
-
settlePromise: (promise) => this.settlePromise(promise),
|
|
156
|
-
syncIterator: (value, node) => this.syncIterator(value, node),
|
|
157
|
-
};
|
|
158
|
-
constructor(executeTool, invokeSearch, toolKeys, promises, logs = []) {
|
|
159
|
-
const globalScope = new Map();
|
|
160
|
-
this.scopes = new ScopeStack([globalScope]);
|
|
106
|
+
logs;
|
|
107
|
+
runner;
|
|
108
|
+
root;
|
|
109
|
+
constructor(executeTool, search, toolKeys, promises, logs = []) {
|
|
161
110
|
this.executeTool = executeTool;
|
|
162
|
-
this.
|
|
111
|
+
this.search = search;
|
|
163
112
|
this.toolKeys = toolKeys;
|
|
164
|
-
this.logs = logs;
|
|
165
113
|
this.promises = promises;
|
|
166
|
-
|
|
167
|
-
globalScope
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
globalScope.set("decodeURIComponent", { mutable: false, value: new UriFunction("decodeURIComponent") });
|
|
193
|
-
for (const name of errorConstructors) {
|
|
194
|
-
globalScope.set(name, { mutable: false, value: new ErrorConstructorReference(name) });
|
|
195
|
-
}
|
|
196
|
-
globalScope.set("NaN", { mutable: false, value: NaN });
|
|
197
|
-
globalScope.set("Infinity", { mutable: false, value: Infinity });
|
|
114
|
+
this.logs = logs;
|
|
115
|
+
const globalScope = new Map();
|
|
116
|
+
// Calling back into the program never reads frame state, so any frame serves; the root is always alive.
|
|
117
|
+
this.root = new Frame(this, new ScopeStack([globalScope]));
|
|
118
|
+
this.runner = {
|
|
119
|
+
invokeFunction: (fn, args) => this.root.invokeFunction(fn, args),
|
|
120
|
+
invokeCallable: (callable, args, node) => this.root.invokeCallable(callable, args, node),
|
|
121
|
+
settlePromise: (promise) => this.root.settlePromise(promise),
|
|
122
|
+
syncIterator: (value, node) => this.root.syncIterator(value, node),
|
|
123
|
+
};
|
|
124
|
+
for (const [name, value] of globals(this))
|
|
125
|
+
globalScope.set(name, { mutable: false, value });
|
|
126
|
+
}
|
|
127
|
+
run(program) {
|
|
128
|
+
return this.root.run(program);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** One activation: the top-level program or a single function call, evaluating against its own scope chain. */
|
|
132
|
+
class Frame {
|
|
133
|
+
runtime;
|
|
134
|
+
scopes;
|
|
135
|
+
generatorState;
|
|
136
|
+
generatorAsync = false;
|
|
137
|
+
constructor(runtime, scopes) {
|
|
138
|
+
this.runtime = runtime;
|
|
139
|
+
this.scopes = scopes;
|
|
198
140
|
}
|
|
199
141
|
run(program) {
|
|
200
142
|
const self = this;
|
|
@@ -206,7 +148,7 @@ export class Interpreter {
|
|
|
206
148
|
let value = undefined;
|
|
207
149
|
for (const [index, statement] of program.body.entries()) {
|
|
208
150
|
if (index === program.body.length - 1 && statement.type === "ExpressionStatement") {
|
|
209
|
-
value = yield* self.evaluateExpression(
|
|
151
|
+
value = yield* self.evaluateExpression(statement.expression);
|
|
210
152
|
break;
|
|
211
153
|
}
|
|
212
154
|
const result = yield* self.evaluateStatement(statement);
|
|
@@ -219,20 +161,20 @@ export class Interpreter {
|
|
|
219
161
|
}
|
|
220
162
|
}
|
|
221
163
|
// The implicit async body adopts returned promises before copy-out.
|
|
222
|
-
value = yield* resolvePromiseValue(self.runner, value, program);
|
|
164
|
+
value = yield* resolvePromiseValue(self.runtime.runner, value, program);
|
|
223
165
|
return value;
|
|
224
166
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
225
167
|
}
|
|
226
168
|
// Fork at the call site so admission and hooks occur when the call is made.
|
|
227
169
|
createToolCallPromise(path, args) {
|
|
228
|
-
return this.createPromise(Effect.suspend(() => this.executeTool(path, args)));
|
|
170
|
+
return this.createPromise(Effect.suspend(() => this.runtime.executeTool(path, args)));
|
|
229
171
|
}
|
|
230
172
|
createPromise(effect) {
|
|
231
|
-
return this.promises.create(effect);
|
|
173
|
+
return this.runtime.promises.create(effect);
|
|
232
174
|
}
|
|
233
175
|
// Fiber exits make settlement idempotent; yielding prevents inline continuation.
|
|
234
176
|
settlePromise(promise) {
|
|
235
|
-
const promises = this.promises;
|
|
177
|
+
const promises = this.runtime.promises;
|
|
236
178
|
return Effect.suspend(() => {
|
|
237
179
|
promises.markObserved(promise);
|
|
238
180
|
return Effect.flatMap(promises.await(promise), (exit) => Effect.andThen(Effect.yieldNow, exit));
|
|
@@ -241,11 +183,11 @@ export class Interpreter {
|
|
|
241
183
|
evaluateStatement(node) {
|
|
242
184
|
switch (node.type) {
|
|
243
185
|
case "ExpressionStatement":
|
|
244
|
-
return Effect.as(this.evaluateExpression(
|
|
186
|
+
return Effect.as(this.evaluateExpression(node.expression), { kind: "none" });
|
|
245
187
|
case "VariableDeclaration":
|
|
246
188
|
return Effect.map(this.evaluateVariableDeclaration(node), () => ({ kind: "none" }));
|
|
247
189
|
case "ReturnStatement": {
|
|
248
|
-
const argumentNode =
|
|
190
|
+
const argumentNode = node.argument;
|
|
249
191
|
return argumentNode
|
|
250
192
|
? Effect.map(this.evaluateExpression(argumentNode), (value) => ({ kind: "return", value }))
|
|
251
193
|
: Effect.succeed({ kind: "return", value: undefined });
|
|
@@ -288,11 +230,10 @@ export class Interpreter {
|
|
|
288
230
|
this.scopes.push();
|
|
289
231
|
const self = this;
|
|
290
232
|
return Effect.gen(function* () {
|
|
291
|
-
const body =
|
|
233
|
+
const body = node.body;
|
|
292
234
|
self.predeclareLexical(body);
|
|
293
235
|
self.hoistFunctions(body);
|
|
294
|
-
for (const
|
|
295
|
-
const statement = asNode(statementValue, "body");
|
|
236
|
+
for (const statement of body) {
|
|
296
237
|
const result = yield* self.evaluateStatement(statement);
|
|
297
238
|
if (result.kind !== "none") {
|
|
298
239
|
return result;
|
|
@@ -302,27 +243,24 @@ export class Interpreter {
|
|
|
302
243
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
303
244
|
}
|
|
304
245
|
createFunction(node) {
|
|
305
|
-
return new CodeModeFunction(
|
|
246
|
+
return new CodeModeFunction(node.params, node.body, this.scopes.capture(), node.async, node.generator);
|
|
306
247
|
}
|
|
307
248
|
hoistFunctions(statements) {
|
|
308
|
-
for (const
|
|
309
|
-
if (
|
|
249
|
+
for (const node of statements) {
|
|
250
|
+
if (node.type !== "FunctionDeclaration")
|
|
310
251
|
continue;
|
|
311
|
-
|
|
312
|
-
this.scopes.declare(getString(getNode(node, "id"), "name"), this.createFunction(node), true, node);
|
|
252
|
+
this.scopes.declare(node.id.name, this.createFunction(node), true, node);
|
|
313
253
|
}
|
|
314
254
|
}
|
|
315
255
|
predeclareLexical(statements) {
|
|
316
|
-
for (const
|
|
317
|
-
if (
|
|
256
|
+
for (const statement of statements) {
|
|
257
|
+
if (statement.type !== "VariableDeclaration")
|
|
318
258
|
continue;
|
|
319
|
-
const
|
|
320
|
-
const kind = getString(statement, "kind");
|
|
259
|
+
const kind = statement.kind;
|
|
321
260
|
if (kind === "var")
|
|
322
261
|
continue;
|
|
323
|
-
for (const
|
|
324
|
-
const
|
|
325
|
-
for (const name of collectPatternNames(getNode(declaration, "id"))) {
|
|
262
|
+
for (const declaration of statement.declarations) {
|
|
263
|
+
for (const name of collectPatternNames(declaration.id)) {
|
|
326
264
|
this.scopes.reserve(name, kind !== "const", declaration);
|
|
327
265
|
}
|
|
328
266
|
}
|
|
@@ -333,30 +271,27 @@ export class Interpreter {
|
|
|
333
271
|
this.scopes.reserve(name, mutable, node);
|
|
334
272
|
}
|
|
335
273
|
evaluateIfStatement(node) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
? this.evaluateStatement(consequentNode)
|
|
341
|
-
: alternateNode
|
|
342
|
-
? this.evaluateStatement(alternateNode)
|
|
274
|
+
return Effect.flatMap(this.evaluateExpression(node.test), (test) => test
|
|
275
|
+
? this.evaluateStatement(node.consequent)
|
|
276
|
+
: node.alternate
|
|
277
|
+
? this.evaluateStatement(node.alternate)
|
|
343
278
|
: Effect.succeed({ kind: "none" }));
|
|
344
279
|
}
|
|
345
280
|
evaluateSwitchStatement(node) {
|
|
346
281
|
const self = this;
|
|
347
282
|
return Effect.gen(function* () {
|
|
348
|
-
const discriminant = yield* self.evaluateExpression(
|
|
283
|
+
const discriminant = yield* self.evaluateExpression(node.discriminant);
|
|
349
284
|
if (containsOpaqueReference(discriminant)) {
|
|
350
285
|
throw new InterpreterRuntimeError("Switch discriminants must be data values.", node, "InvalidDataValue");
|
|
351
286
|
}
|
|
352
287
|
self.scopes.push();
|
|
353
288
|
return yield* Effect.gen(function* () {
|
|
354
|
-
const cases =
|
|
355
|
-
self.predeclareLexical(cases.flatMap((branch) =>
|
|
289
|
+
const cases = node.cases;
|
|
290
|
+
self.predeclareLexical(cases.flatMap((branch) => branch.consequent));
|
|
356
291
|
let defaultIndex;
|
|
357
292
|
let selected;
|
|
358
293
|
for (const [index, branch] of cases.entries()) {
|
|
359
|
-
const test =
|
|
294
|
+
const test = branch.test;
|
|
360
295
|
if (!test) {
|
|
361
296
|
defaultIndex = index;
|
|
362
297
|
continue;
|
|
@@ -374,8 +309,8 @@ export class Interpreter {
|
|
|
374
309
|
if (start === undefined)
|
|
375
310
|
return { kind: "none" };
|
|
376
311
|
for (let index = start; index < cases.length; index += 1) {
|
|
377
|
-
for (const
|
|
378
|
-
const result = yield* self.evaluateStatement(
|
|
312
|
+
for (const statement of cases[index].consequent) {
|
|
313
|
+
const result = yield* self.evaluateStatement(statement);
|
|
379
314
|
if (result.kind === "break") {
|
|
380
315
|
if (result.label === undefined)
|
|
381
316
|
return { kind: "none" };
|
|
@@ -390,12 +325,10 @@ export class Interpreter {
|
|
|
390
325
|
});
|
|
391
326
|
}
|
|
392
327
|
evaluateWhileStatement(node, labels) {
|
|
393
|
-
const testNode = getNode(node, "test");
|
|
394
|
-
const bodyNode = getNode(node, "body");
|
|
395
328
|
const self = this;
|
|
396
329
|
return Effect.gen(function* () {
|
|
397
|
-
while (yield* self.evaluateExpression(
|
|
398
|
-
const result = yield* self.evaluateStatement(
|
|
330
|
+
while (yield* self.evaluateExpression(node.test)) {
|
|
331
|
+
const result = yield* self.evaluateStatement(node.body);
|
|
399
332
|
if (result.kind === "continue") {
|
|
400
333
|
if (result.label !== undefined && !labels?.has(result.label))
|
|
401
334
|
return result;
|
|
@@ -414,12 +347,10 @@ export class Interpreter {
|
|
|
414
347
|
});
|
|
415
348
|
}
|
|
416
349
|
evaluateDoWhileStatement(node, labels) {
|
|
417
|
-
const bodyNode = getNode(node, "body");
|
|
418
|
-
const testNode = getNode(node, "test");
|
|
419
350
|
const self = this;
|
|
420
351
|
return Effect.gen(function* () {
|
|
421
352
|
do {
|
|
422
|
-
const result = yield* self.evaluateStatement(
|
|
353
|
+
const result = yield* self.evaluateStatement(node.body);
|
|
423
354
|
if (result.kind === "continue") {
|
|
424
355
|
if (result.label !== undefined && !labels?.has(result.label))
|
|
425
356
|
return result;
|
|
@@ -433,7 +364,7 @@ export class Interpreter {
|
|
|
433
364
|
if (result.kind === "return") {
|
|
434
365
|
return result;
|
|
435
366
|
}
|
|
436
|
-
} while (yield* self.evaluateExpression(
|
|
367
|
+
} while (yield* self.evaluateExpression(node.test));
|
|
437
368
|
return { kind: "none" };
|
|
438
369
|
});
|
|
439
370
|
}
|
|
@@ -441,11 +372,10 @@ export class Interpreter {
|
|
|
441
372
|
this.scopes.push();
|
|
442
373
|
const self = this;
|
|
443
374
|
return Effect.gen(function* () {
|
|
444
|
-
const initNode =
|
|
445
|
-
const testNode =
|
|
446
|
-
const updateNode =
|
|
447
|
-
|
|
448
|
-
if (initNode?.type === "VariableDeclaration" && getString(initNode, "kind") !== "var") {
|
|
375
|
+
const initNode = node.init;
|
|
376
|
+
const testNode = node.test;
|
|
377
|
+
const updateNode = node.update;
|
|
378
|
+
if (initNode?.type === "VariableDeclaration" && initNode.kind !== "var") {
|
|
449
379
|
self.predeclareLexical([initNode]);
|
|
450
380
|
}
|
|
451
381
|
if (initNode) {
|
|
@@ -456,7 +386,7 @@ export class Interpreter {
|
|
|
456
386
|
yield* self.evaluateExpression(initNode);
|
|
457
387
|
}
|
|
458
388
|
}
|
|
459
|
-
const perIterationBindings = initNode?.type === "VariableDeclaration" &&
|
|
389
|
+
const perIterationBindings = initNode?.type === "VariableDeclaration" && initNode.kind !== "var"
|
|
460
390
|
? Array.from(self.scopes.current().keys())
|
|
461
391
|
: [];
|
|
462
392
|
const nextIteration = () => {
|
|
@@ -468,7 +398,7 @@ export class Interpreter {
|
|
|
468
398
|
};
|
|
469
399
|
nextIteration();
|
|
470
400
|
while (testNode ? yield* self.evaluateExpression(testNode) : true) {
|
|
471
|
-
const result = yield* self.evaluateStatement(
|
|
401
|
+
const result = yield* self.evaluateStatement(node.body);
|
|
472
402
|
if (result.kind === "return") {
|
|
473
403
|
return result;
|
|
474
404
|
}
|
|
@@ -491,8 +421,8 @@ export class Interpreter {
|
|
|
491
421
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
492
422
|
}
|
|
493
423
|
evaluateForOfStatement(node, labels) {
|
|
494
|
-
const awaiting =
|
|
495
|
-
const left =
|
|
424
|
+
const awaiting = node.await;
|
|
425
|
+
const left = node.left;
|
|
496
426
|
const declared = loopDeclaration(left, "for...of");
|
|
497
427
|
if (declared?.lexical)
|
|
498
428
|
this.scopes.push();
|
|
@@ -500,8 +430,7 @@ export class Interpreter {
|
|
|
500
430
|
return Effect.gen(function* () {
|
|
501
431
|
if (declared?.lexical)
|
|
502
432
|
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
503
|
-
const right = yield* self.evaluateExpression(
|
|
504
|
-
const body = getNode(node, "body");
|
|
433
|
+
const right = yield* self.evaluateExpression(node.right);
|
|
505
434
|
const iterator = yield* self.customIterator(right, node, awaiting);
|
|
506
435
|
const cursor = iterator === undefined ? yield* self.syncIterator(right, node) : undefined;
|
|
507
436
|
if (iterator === undefined && cursor === undefined) {
|
|
@@ -512,17 +441,10 @@ export class Interpreter {
|
|
|
512
441
|
: awaiting
|
|
513
442
|
? Effect.andThen(cursor?.close ?? Effect.void, Effect.yieldNow)
|
|
514
443
|
: (cursor?.close ?? Effect.void);
|
|
515
|
-
|
|
516
|
-
if (left.type !== "VariableDeclaration" &&
|
|
517
|
-
(left.type === "Identifier" ||
|
|
518
|
-
left.type === "MemberExpression" ||
|
|
519
|
-
left.type === "ArrayPattern" ||
|
|
520
|
-
left.type === "ObjectPattern")) {
|
|
521
|
-
assignment = left;
|
|
522
|
-
}
|
|
523
|
-
else if (left.type !== "VariableDeclaration") {
|
|
444
|
+
if (left.type === "RestElement" || left.type === "AssignmentPattern") {
|
|
524
445
|
throw new InterpreterRuntimeError("Unsupported for...of binding.", left);
|
|
525
446
|
}
|
|
447
|
+
const assignment = left.type === "VariableDeclaration" ? undefined : left;
|
|
526
448
|
const evaluateBody = (value) => Effect.gen(function* () {
|
|
527
449
|
if (declared) {
|
|
528
450
|
self.scopes.push();
|
|
@@ -533,7 +455,7 @@ export class Interpreter {
|
|
|
533
455
|
else if (assignment) {
|
|
534
456
|
yield* self.assignPattern(assignment, value, left);
|
|
535
457
|
}
|
|
536
|
-
return yield* self.evaluateStatement(body);
|
|
458
|
+
return yield* self.evaluateStatement(node.body);
|
|
537
459
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
538
460
|
if (declared)
|
|
539
461
|
self.scopes.pop();
|
|
@@ -575,7 +497,7 @@ export class Interpreter {
|
|
|
575
497
|
})));
|
|
576
498
|
}
|
|
577
499
|
awaitValue(value, node = promiseResolutionNode) {
|
|
578
|
-
return Effect.flatMap(resolvePromise(this.runner, this.promises, value, node), (promise) => this.settlePromise(promise));
|
|
500
|
+
return Effect.flatMap(resolvePromise(this.runtime.runner, this.runtime.promises, value, node), (promise) => this.settlePromise(promise));
|
|
579
501
|
}
|
|
580
502
|
awaitAsyncFromSyncValue(iterator, value, node, closeOnRejection) {
|
|
581
503
|
const self = this;
|
|
@@ -594,11 +516,11 @@ export class Interpreter {
|
|
|
594
516
|
? value[Symbol.iterator]()
|
|
595
517
|
: typeof value === "string"
|
|
596
518
|
? value[Symbol.iterator]()
|
|
597
|
-
: value instanceof
|
|
519
|
+
: value instanceof Values.Map
|
|
598
520
|
? value.map.entries()
|
|
599
|
-
: value instanceof
|
|
521
|
+
: value instanceof Values.Set
|
|
600
522
|
? value.set.values()
|
|
601
|
-
: value instanceof
|
|
523
|
+
: value instanceof Values.URLSearchParams
|
|
602
524
|
? value.params.entries()
|
|
603
525
|
: undefined;
|
|
604
526
|
if (iterator !== undefined) {
|
|
@@ -722,7 +644,7 @@ export class Interpreter {
|
|
|
722
644
|
}
|
|
723
645
|
enumerableKeys(value) {
|
|
724
646
|
if (value instanceof ToolReference) {
|
|
725
|
-
return [...this.toolKeys(value.path)];
|
|
647
|
+
return [...this.runtime.toolKeys(value.path)];
|
|
726
648
|
}
|
|
727
649
|
if (Array.isArray(value)) {
|
|
728
650
|
return Object.keys(value);
|
|
@@ -733,7 +655,7 @@ export class Interpreter {
|
|
|
733
655
|
return undefined;
|
|
734
656
|
}
|
|
735
657
|
evaluateForInStatement(node, labels) {
|
|
736
|
-
const left =
|
|
658
|
+
const left = node.left;
|
|
737
659
|
const declared = loopDeclaration(left, "for...in");
|
|
738
660
|
if (declared?.lexical)
|
|
739
661
|
this.scopes.push();
|
|
@@ -741,19 +663,15 @@ export class Interpreter {
|
|
|
741
663
|
return Effect.gen(function* () {
|
|
742
664
|
if (declared?.lexical)
|
|
743
665
|
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
744
|
-
const right = yield* self.evaluateExpression(
|
|
745
|
-
const body = getNode(node, "body");
|
|
666
|
+
const right = yield* self.evaluateExpression(node.right);
|
|
746
667
|
const keys = self.enumerableKeys(right);
|
|
747
668
|
if (keys === undefined) {
|
|
748
669
|
throw new InterpreterRuntimeError("for...in requires a plain object, array, or tools reference. Use for...of for arrays/strings/Maps/Sets, or Object.keys(value) for a key list.", node);
|
|
749
670
|
}
|
|
750
|
-
|
|
751
|
-
if (left.type === "Identifier") {
|
|
752
|
-
assignmentName = getString(left, "name");
|
|
753
|
-
}
|
|
754
|
-
else if (left.type !== "VariableDeclaration") {
|
|
671
|
+
if (left.type !== "Identifier" && left.type !== "VariableDeclaration") {
|
|
755
672
|
throw new InterpreterRuntimeError("Unsupported for...in binding.", left);
|
|
756
673
|
}
|
|
674
|
+
const assignmentName = left.type === "Identifier" ? left.name : undefined;
|
|
757
675
|
for (const key of keys) {
|
|
758
676
|
const result = yield* Effect.gen(function* () {
|
|
759
677
|
if (declared) {
|
|
@@ -765,7 +683,7 @@ export class Interpreter {
|
|
|
765
683
|
else if (assignmentName) {
|
|
766
684
|
self.scopes.set(assignmentName, key, left);
|
|
767
685
|
}
|
|
768
|
-
return yield* self.evaluateStatement(body);
|
|
686
|
+
return yield* self.evaluateStatement(node.body);
|
|
769
687
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
770
688
|
if (declared)
|
|
771
689
|
self.scopes.pop();
|
|
@@ -791,19 +709,17 @@ export class Interpreter {
|
|
|
791
709
|
})));
|
|
792
710
|
}
|
|
793
711
|
evaluateBreakStatement(node) {
|
|
794
|
-
|
|
795
|
-
return labelNode ? { kind: "break", label: getString(labelNode, "name") } : { kind: "break" };
|
|
712
|
+
return node.label ? { kind: "break", label: node.label.name } : { kind: "break" };
|
|
796
713
|
}
|
|
797
714
|
evaluateContinueStatement(node) {
|
|
798
|
-
|
|
799
|
-
return labelNode ? { kind: "continue", label: getString(labelNode, "name") } : { kind: "continue" };
|
|
715
|
+
return node.label ? { kind: "continue", label: node.label.name } : { kind: "continue" };
|
|
800
716
|
}
|
|
801
717
|
evaluateLabeledStatement(node) {
|
|
802
718
|
const labels = new Set();
|
|
803
719
|
let body = node;
|
|
804
720
|
while (body.type === "LabeledStatement") {
|
|
805
|
-
labels.add(
|
|
806
|
-
body =
|
|
721
|
+
labels.add(body.label.name);
|
|
722
|
+
body = body.body;
|
|
807
723
|
}
|
|
808
724
|
const evaluated = (() => {
|
|
809
725
|
if (body.type === "WhileStatement")
|
|
@@ -823,13 +739,12 @@ export class Interpreter {
|
|
|
823
739
|
: result);
|
|
824
740
|
}
|
|
825
741
|
evaluateThrowStatement(node) {
|
|
826
|
-
|
|
827
|
-
return Effect.flatMap(this.evaluateExpression(argument), (value) => Effect.fail(new ProgramThrow(value)));
|
|
742
|
+
return Effect.flatMap(this.evaluateExpression(node.argument), (value) => Effect.fail(new ProgramThrow(value)));
|
|
828
743
|
}
|
|
829
744
|
evaluateTryStatement(node) {
|
|
830
|
-
const body =
|
|
831
|
-
const handler =
|
|
832
|
-
const finalizer =
|
|
745
|
+
const body = node.block;
|
|
746
|
+
const handler = node.handler;
|
|
747
|
+
const finalizer = node.finalizer;
|
|
833
748
|
const self = this;
|
|
834
749
|
const attempted = Effect.matchCauseEffect(this.evaluateStatement(body), {
|
|
835
750
|
onFailure: (cause) => {
|
|
@@ -837,12 +752,12 @@ export class Interpreter {
|
|
|
837
752
|
return Effect.failCause(cause);
|
|
838
753
|
}
|
|
839
754
|
const caught = caughtErrorValue(Cause.squash(cause));
|
|
840
|
-
const parameter =
|
|
755
|
+
const parameter = handler.param;
|
|
841
756
|
self.scopes.push();
|
|
842
757
|
return Effect.gen(function* () {
|
|
843
758
|
if (parameter)
|
|
844
759
|
yield* self.declarePattern(parameter, caught, true, handler);
|
|
845
|
-
return yield* self.evaluateStatement(
|
|
760
|
+
return yield* self.evaluateStatement(handler.body);
|
|
846
761
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
847
762
|
},
|
|
848
763
|
onSuccess: Effect.succeed,
|
|
@@ -858,18 +773,16 @@ export class Interpreter {
|
|
|
858
773
|
});
|
|
859
774
|
}
|
|
860
775
|
evaluateVariableDeclaration(node) {
|
|
861
|
-
const kind =
|
|
862
|
-
const declarations = getArray(node, "declarations");
|
|
776
|
+
const kind = node.kind;
|
|
863
777
|
const self = this;
|
|
864
778
|
return Effect.gen(function* () {
|
|
865
|
-
for (const
|
|
866
|
-
const declaration = asNode(declarationValue, "declarations");
|
|
779
|
+
for (const declaration of node.declarations) {
|
|
867
780
|
if (declaration.type !== "VariableDeclarator") {
|
|
868
781
|
throw new InterpreterRuntimeError("Unsupported variable declaration shape.", declaration);
|
|
869
782
|
}
|
|
870
|
-
const init =
|
|
783
|
+
const init = declaration.init;
|
|
871
784
|
const value = init ? yield* self.evaluateExpression(init) : undefined;
|
|
872
|
-
yield* self.declarePattern(
|
|
785
|
+
yield* self.declarePattern(declaration.id, value, kind !== "const", declaration, kind !== "var");
|
|
873
786
|
}
|
|
874
787
|
});
|
|
875
788
|
}
|
|
@@ -877,7 +790,7 @@ export class Interpreter {
|
|
|
877
790
|
const self = this;
|
|
878
791
|
return Effect.gen(function* () {
|
|
879
792
|
if (pattern.type === "Identifier") {
|
|
880
|
-
const name =
|
|
793
|
+
const name = pattern.name;
|
|
881
794
|
if (initialize)
|
|
882
795
|
self.scopes.initialize(name, value, node);
|
|
883
796
|
else
|
|
@@ -885,8 +798,8 @@ export class Interpreter {
|
|
|
885
798
|
return;
|
|
886
799
|
}
|
|
887
800
|
if (pattern.type === "AssignmentPattern") {
|
|
888
|
-
const resolved = value === undefined ? yield* self.evaluateExpression(
|
|
889
|
-
yield* self.declarePattern(
|
|
801
|
+
const resolved = value === undefined ? yield* self.evaluateExpression(pattern.right) : value;
|
|
802
|
+
yield* self.declarePattern(pattern.left, resolved, mutable, node, initialize);
|
|
890
803
|
return;
|
|
891
804
|
}
|
|
892
805
|
if (pattern.type === "ObjectPattern") {
|
|
@@ -894,8 +807,7 @@ export class Interpreter {
|
|
|
894
807
|
throw new InterpreterRuntimeError("Object destructuring requires a data object or array value.", pattern, "InvalidDataValue");
|
|
895
808
|
}
|
|
896
809
|
const consumed = new Set();
|
|
897
|
-
for (const
|
|
898
|
-
const property = asNode(propertyValue, "properties");
|
|
810
|
+
for (const property of pattern.properties) {
|
|
899
811
|
if (property.type === "RestElement") {
|
|
900
812
|
const rest = Object.create(null);
|
|
901
813
|
for (const [key, item] of Object.entries(value)) {
|
|
@@ -903,7 +815,7 @@ export class Interpreter {
|
|
|
903
815
|
rest[key] = item;
|
|
904
816
|
}
|
|
905
817
|
copyIteratorSymbols(value, rest, consumed);
|
|
906
|
-
yield* self.declarePattern(
|
|
818
|
+
yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
|
|
907
819
|
continue;
|
|
908
820
|
}
|
|
909
821
|
const key = yield* self.destructuringPropertyKey(property);
|
|
@@ -911,7 +823,7 @@ export class Interpreter {
|
|
|
911
823
|
throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, property);
|
|
912
824
|
}
|
|
913
825
|
consumed.add(typeof key === "symbol" ? key : String(key));
|
|
914
|
-
yield* self.declarePattern(
|
|
826
|
+
yield* self.declarePattern(property.value, self.destructuringPropertyValue(value, key), mutable, property, initialize);
|
|
915
827
|
}
|
|
916
828
|
return;
|
|
917
829
|
}
|
|
@@ -925,7 +837,7 @@ export class Interpreter {
|
|
|
925
837
|
const self = this;
|
|
926
838
|
return Effect.gen(function* () {
|
|
927
839
|
if (pattern.type === "Identifier") {
|
|
928
|
-
self.scopes.set(
|
|
840
|
+
self.scopes.set(pattern.name, value, pattern);
|
|
929
841
|
return;
|
|
930
842
|
}
|
|
931
843
|
if (pattern.type === "MemberExpression") {
|
|
@@ -933,8 +845,8 @@ export class Interpreter {
|
|
|
933
845
|
return;
|
|
934
846
|
}
|
|
935
847
|
if (pattern.type === "AssignmentPattern") {
|
|
936
|
-
const resolved = value === undefined ? yield* self.evaluateExpression(
|
|
937
|
-
yield* self.assignPattern(
|
|
848
|
+
const resolved = value === undefined ? yield* self.evaluateExpression(pattern.right) : value;
|
|
849
|
+
yield* self.assignPattern(pattern.left, resolved, node);
|
|
938
850
|
return;
|
|
939
851
|
}
|
|
940
852
|
if (pattern.type === "ObjectPattern") {
|
|
@@ -943,8 +855,7 @@ export class Interpreter {
|
|
|
943
855
|
}
|
|
944
856
|
const source = value;
|
|
945
857
|
const consumed = new Set();
|
|
946
|
-
for (const
|
|
947
|
-
const property = asNode(propertyValue, "properties");
|
|
858
|
+
for (const property of pattern.properties) {
|
|
948
859
|
if (property.type === "RestElement") {
|
|
949
860
|
const rest = Object.create(null);
|
|
950
861
|
for (const [key, item] of Object.entries(source)) {
|
|
@@ -952,7 +863,7 @@ export class Interpreter {
|
|
|
952
863
|
rest[key] = item;
|
|
953
864
|
}
|
|
954
865
|
copyIteratorSymbols(source, rest, consumed);
|
|
955
|
-
yield* self.assignPattern(
|
|
866
|
+
yield* self.assignPattern(property.argument, rest, property);
|
|
956
867
|
continue;
|
|
957
868
|
}
|
|
958
869
|
const key = yield* self.destructuringPropertyKey(property);
|
|
@@ -960,7 +871,7 @@ export class Interpreter {
|
|
|
960
871
|
throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, property);
|
|
961
872
|
}
|
|
962
873
|
consumed.add(typeof key === "symbol" ? key : String(key));
|
|
963
|
-
yield* self.assignPattern(
|
|
874
|
+
yield* self.assignPattern(property.value, self.destructuringPropertyValue(source, key), property);
|
|
964
875
|
}
|
|
965
876
|
return;
|
|
966
877
|
}
|
|
@@ -978,21 +889,19 @@ export class Interpreter {
|
|
|
978
889
|
throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern).as("TypeError");
|
|
979
890
|
}
|
|
980
891
|
let done = false;
|
|
981
|
-
for (const
|
|
892
|
+
for (const element of pattern.elements) {
|
|
982
893
|
if (done) {
|
|
983
|
-
if (
|
|
894
|
+
if (element === null)
|
|
984
895
|
continue;
|
|
985
|
-
|
|
986
|
-
yield* consume(element.type === "RestElement" ? getNode(element, "argument") : element, element.type === "RestElement" ? [] : undefined, element);
|
|
896
|
+
yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? [] : undefined, element);
|
|
987
897
|
if (element.type === "RestElement")
|
|
988
898
|
return;
|
|
989
899
|
continue;
|
|
990
900
|
}
|
|
991
901
|
const step = yield* cursor.next;
|
|
992
902
|
done = step.done;
|
|
993
|
-
if (
|
|
903
|
+
if (element === null)
|
|
994
904
|
continue;
|
|
995
|
-
const element = asNode(item, `elements[${index}]`);
|
|
996
905
|
if (element.type === "RestElement") {
|
|
997
906
|
const rest = [];
|
|
998
907
|
if (!step.done)
|
|
@@ -1003,7 +912,7 @@ export class Interpreter {
|
|
|
1003
912
|
if (!done)
|
|
1004
913
|
rest.push(next.value);
|
|
1005
914
|
}
|
|
1006
|
-
yield* consume(
|
|
915
|
+
yield* consume(element.argument, rest, element);
|
|
1007
916
|
return;
|
|
1008
917
|
}
|
|
1009
918
|
const consumed = consume(element, step.done ? undefined : step.value, pattern);
|
|
@@ -1014,14 +923,18 @@ export class Interpreter {
|
|
|
1014
923
|
});
|
|
1015
924
|
}
|
|
1016
925
|
destructuringPropertyKey(property) {
|
|
1017
|
-
if (property.type !== "Property" ||
|
|
926
|
+
if (property.type !== "Property" || property.kind !== "init") {
|
|
1018
927
|
throw new InterpreterRuntimeError("Unsupported object destructuring property.", property);
|
|
1019
928
|
}
|
|
1020
|
-
const keyNode =
|
|
1021
|
-
if (
|
|
929
|
+
const keyNode = property.key;
|
|
930
|
+
if (property.computed) {
|
|
1022
931
|
return Effect.map(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value, keyNode));
|
|
1023
932
|
}
|
|
1024
|
-
|
|
933
|
+
if (keyNode.type === "Identifier")
|
|
934
|
+
return Effect.succeed(keyNode.name);
|
|
935
|
+
if (keyNode.type === "Literal")
|
|
936
|
+
return Effect.succeed(String(keyNode.value));
|
|
937
|
+
throw unsupportedSyntax(keyNode.type, keyNode);
|
|
1025
938
|
}
|
|
1026
939
|
destructuringPropertyValue(source, key) {
|
|
1027
940
|
if (!Array.isArray(source))
|
|
@@ -1040,13 +953,12 @@ export class Interpreter {
|
|
|
1040
953
|
switch (node.type) {
|
|
1041
954
|
case "Literal": {
|
|
1042
955
|
const regex = node.regex;
|
|
1043
|
-
if (
|
|
1044
|
-
return Effect.sync(() =>
|
|
1045
|
-
|
|
1046
|
-
return Effect.sync(() => boundedData(node.value, "Literal"));
|
|
956
|
+
if (regex)
|
|
957
|
+
return Effect.sync(() => constructRegExp([regex.pattern, regex.flags], node));
|
|
958
|
+
return Effect.sync(() => toProgram(node.value, "Literal"));
|
|
1047
959
|
}
|
|
1048
960
|
case "Identifier":
|
|
1049
|
-
return Effect.sync(() => this.scopes.get(
|
|
961
|
+
return Effect.sync(() => this.scopes.get(node.name, node));
|
|
1050
962
|
case "BinaryExpression":
|
|
1051
963
|
return this.evaluateBinaryExpression(node);
|
|
1052
964
|
case "LogicalExpression":
|
|
@@ -1059,8 +971,8 @@ export class Interpreter {
|
|
|
1059
971
|
const self = this;
|
|
1060
972
|
return Effect.gen(function* () {
|
|
1061
973
|
let result;
|
|
1062
|
-
for (const expression of
|
|
1063
|
-
result = yield* self.evaluateExpression(
|
|
974
|
+
for (const expression of node.expressions) {
|
|
975
|
+
result = yield* self.evaluateExpression(expression);
|
|
1064
976
|
}
|
|
1065
977
|
return result;
|
|
1066
978
|
});
|
|
@@ -1073,7 +985,7 @@ export class Interpreter {
|
|
|
1073
985
|
case "MemberExpression":
|
|
1074
986
|
return this.readMember(node);
|
|
1075
987
|
case "ChainExpression":
|
|
1076
|
-
return Effect.map(this.evaluateExpression(
|
|
988
|
+
return Effect.map(this.evaluateExpression(node.expression), (value) => value === OptionalShortCircuit ? undefined : value);
|
|
1077
989
|
case "ObjectExpression":
|
|
1078
990
|
return this.evaluateObjectExpression(node);
|
|
1079
991
|
case "ArrayExpression":
|
|
@@ -1086,7 +998,7 @@ export class Interpreter {
|
|
|
1086
998
|
return this.evaluateUpdateExpression(node);
|
|
1087
999
|
case "AwaitExpression": {
|
|
1088
1000
|
// Await always suspends, including for plain values.
|
|
1089
|
-
return Effect.flatMap(this.evaluateExpression(
|
|
1001
|
+
return Effect.flatMap(this.evaluateExpression(node.argument), (value) => this.awaitValue(value, node));
|
|
1090
1002
|
}
|
|
1091
1003
|
case "YieldExpression":
|
|
1092
1004
|
return this.evaluateYieldExpression(node);
|
|
@@ -1097,240 +1009,29 @@ export class Interpreter {
|
|
|
1097
1009
|
}
|
|
1098
1010
|
}
|
|
1099
1011
|
evaluateNewExpression(node) {
|
|
1100
|
-
const callee = getNode(node, "callee");
|
|
1101
|
-
if (callee.type !== "Identifier") {
|
|
1102
|
-
throw unsupportedSyntax("NewExpression", node);
|
|
1103
|
-
}
|
|
1104
|
-
const name = getString(callee, "name");
|
|
1105
|
-
const argNodes = getArray(node, "arguments");
|
|
1106
|
-
const self = this;
|
|
1107
|
-
if (name === "Promise") {
|
|
1108
|
-
return Effect.flatMap(this.evaluateCallArguments(argNodes), (args) => constructPromise(self.runner, self.promises, args[0], node));
|
|
1109
|
-
}
|
|
1110
|
-
if (errorConstructors.has(name)) {
|
|
1111
|
-
return Effect.flatMap(this.evaluateCallArguments(argNodes), (args) => name === "AggregateError"
|
|
1112
|
-
? constructAggregateErrorValue(self.runner, args, node)
|
|
1113
|
-
: Effect.succeed(constructErrorValue(name, args)));
|
|
1114
|
-
}
|
|
1115
|
-
// Array and Object construct identically with or without new, like JS.
|
|
1116
|
-
if (name === "Array") {
|
|
1117
|
-
return Effect.map(this.evaluateCallArguments(argNodes), (args) => self.constructArray(args, node));
|
|
1118
|
-
}
|
|
1119
|
-
if (name === "Object") {
|
|
1120
|
-
return Effect.map(this.evaluateCallArguments(argNodes), (args) => self.constructObject(args, node));
|
|
1121
|
-
}
|
|
1122
|
-
if (valueConstructors.has(name)) {
|
|
1123
|
-
return Effect.gen(function* () {
|
|
1124
|
-
const args = yield* self.evaluateCallArguments(argNodes);
|
|
1125
|
-
switch (name) {
|
|
1126
|
-
case "Date":
|
|
1127
|
-
return yield* self.constructDate(args, node);
|
|
1128
|
-
case "RegExp":
|
|
1129
|
-
return self.constructRegExp(args, node);
|
|
1130
|
-
case "Map":
|
|
1131
|
-
return yield* self.constructMap(args[0], node);
|
|
1132
|
-
case "Set":
|
|
1133
|
-
return yield* self.constructSet(args[0], node);
|
|
1134
|
-
case "URL":
|
|
1135
|
-
return self.constructURL(args, node);
|
|
1136
|
-
default:
|
|
1137
|
-
return yield* self.constructURLSearchParams(args[0], node);
|
|
1138
|
-
}
|
|
1139
|
-
});
|
|
1140
|
-
}
|
|
1141
|
-
throw unsupportedSyntax("NewExpression", node);
|
|
1142
|
-
}
|
|
1143
|
-
constructArray(args, node) {
|
|
1144
|
-
if (args.length !== 1)
|
|
1145
|
-
return [...args];
|
|
1146
|
-
const first = args[0];
|
|
1147
|
-
if (typeof first !== "number")
|
|
1148
|
-
return [first];
|
|
1149
|
-
if (!Number.isInteger(first) || first < 0 || first > 4294967295) {
|
|
1150
|
-
throw new InterpreterRuntimeError("Invalid array length.", node).as("RangeError");
|
|
1151
|
-
}
|
|
1152
|
-
// Sparse like JS: Array(3) has holes, and combinator loops already skip them.
|
|
1153
|
-
return new Array(first);
|
|
1154
|
-
}
|
|
1155
|
-
constructObject(args, node) {
|
|
1156
|
-
const first = args[0];
|
|
1157
|
-
if (first === null || first === undefined)
|
|
1158
|
-
return {};
|
|
1159
|
-
if (typeof first === "object")
|
|
1160
|
-
return first;
|
|
1161
|
-
throw new InterpreterRuntimeError(`Object(${typeof first}) wrapper objects are not supported; use the primitive value directly.`, node);
|
|
1162
|
-
}
|
|
1163
|
-
constructDate(args, node) {
|
|
1164
|
-
if (args.length === 0)
|
|
1165
|
-
return Effect.succeed(new CodeModeDate(Date.now()));
|
|
1166
|
-
if (args.length === 1) {
|
|
1167
|
-
const arg = args[0];
|
|
1168
|
-
if (arg instanceof CodeModeDate)
|
|
1169
|
-
return Effect.succeed(new CodeModeDate(arg.time));
|
|
1170
|
-
return Effect.map(this.toDatePrimitive(arg, node), (value) => typeof value === "string"
|
|
1171
|
-
? new CodeModeDate(Date.parse(value))
|
|
1172
|
-
: new CodeModeDate(new Date(coerceToNumber(value)).getTime()));
|
|
1173
|
-
}
|
|
1174
|
-
const parts = args.map((arg) => coerceToNumber(arg));
|
|
1175
|
-
return Effect.succeed(new CodeModeDate(new Date(...parts).getTime()));
|
|
1176
|
-
}
|
|
1177
|
-
toDatePrimitive(value, node) {
|
|
1178
|
-
if (value === null || (typeof value !== "object" && typeof value !== "function"))
|
|
1179
|
-
return Effect.succeed(value);
|
|
1180
|
-
const object = value;
|
|
1181
|
-
const self = this;
|
|
1182
|
-
return Effect.gen(function* () {
|
|
1183
|
-
if (Object.hasOwn(object, "valueOf") && typeofValue(object.valueOf) === "function") {
|
|
1184
|
-
const result = yield* self.runner.invokeCallable(object.valueOf, [], node);
|
|
1185
|
-
if (result === null || (typeof result !== "object" && typeof result !== "function"))
|
|
1186
|
-
return result;
|
|
1187
|
-
}
|
|
1188
|
-
if (!Object.hasOwn(object, "toString"))
|
|
1189
|
-
return coerceToString(value);
|
|
1190
|
-
if (typeofValue(object.toString) === "function") {
|
|
1191
|
-
const result = yield* self.runner.invokeCallable(object.toString, [], node);
|
|
1192
|
-
if (result === null || (typeof result !== "object" && typeof result !== "function"))
|
|
1193
|
-
return result;
|
|
1194
|
-
}
|
|
1195
|
-
throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node).as("TypeError");
|
|
1196
|
-
});
|
|
1197
|
-
}
|
|
1198
|
-
constructRegExp(args, node) {
|
|
1199
|
-
const first = args[0];
|
|
1200
|
-
const pattern = first instanceof CodeModeRegExp ? first.regex.source : first === undefined ? "" : coerceToString(first);
|
|
1201
|
-
const flagsArg = args[1];
|
|
1202
|
-
if (flagsArg !== undefined && typeof flagsArg !== "string") {
|
|
1203
|
-
throw new InterpreterRuntimeError(`RegExp flags must be a string of flag characters (e.g. "g", "gi"), not ${flagsArg === null ? "null" : typeof flagsArg}.`, node).as("SyntaxError");
|
|
1204
|
-
}
|
|
1205
|
-
const flags = flagsArg ?? (first instanceof CodeModeRegExp ? first.regex.flags : "");
|
|
1206
|
-
try {
|
|
1207
|
-
return new CodeModeRegExp(pattern, flags);
|
|
1208
|
-
}
|
|
1209
|
-
catch (error) {
|
|
1210
|
-
const reason = regexFailureReason(error);
|
|
1211
|
-
throw new InterpreterRuntimeError(/flag/i.test(reason)
|
|
1212
|
-
? `new RegExp(...) received invalid flags ${JSON.stringify(flags)} (${reason}). Valid flags are d, g, i, m, s, u, v, and y.`
|
|
1213
|
-
: `new RegExp(...) received ${JSON.stringify(pattern)}, which is not a valid regular expression pattern (${reason}). ${escapeRegexHint}`, node).as("SyntaxError");
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
constructMap(init, node) {
|
|
1217
|
-
const target = new CodeModeMap();
|
|
1218
|
-
if (init === undefined || init === null)
|
|
1219
|
-
return Effect.succeed(target);
|
|
1220
|
-
const self = this;
|
|
1221
|
-
return Effect.gen(function* () {
|
|
1222
|
-
const cursor = yield* self.syncIterator(init, node);
|
|
1223
|
-
if (cursor === undefined) {
|
|
1224
|
-
throw new InterpreterRuntimeError("new Map(...) expects an iterable of [key, value] pairs or no argument.", node).as("TypeError");
|
|
1225
|
-
}
|
|
1226
|
-
while (true) {
|
|
1227
|
-
const step = yield* cursor.next;
|
|
1228
|
-
if (step.done)
|
|
1229
|
-
return target;
|
|
1230
|
-
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
1231
|
-
if (!isRecord(step.value) || isRuntimeReference(step.value)) {
|
|
1232
|
-
throw new InterpreterRuntimeError("new Map(...) expects [key, value] pairs as entry objects.", node).as("TypeError");
|
|
1233
|
-
}
|
|
1234
|
-
target.map.set(step.value[0], step.value[1]);
|
|
1235
|
-
}));
|
|
1236
|
-
}
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1239
|
-
constructSet(init, node) {
|
|
1240
|
-
const target = new CodeModeSet();
|
|
1241
|
-
if (init === undefined || init === null)
|
|
1242
|
-
return Effect.succeed(target);
|
|
1243
1012
|
const self = this;
|
|
1244
1013
|
return Effect.gen(function* () {
|
|
1245
|
-
const
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
return target;
|
|
1253
|
-
target.set.add(step.value);
|
|
1254
|
-
}
|
|
1255
|
-
});
|
|
1256
|
-
}
|
|
1257
|
-
constructURL(args, node) {
|
|
1258
|
-
if (args.length === 0) {
|
|
1259
|
-
throw new InterpreterRuntimeError("new URL(...) requires a URL string and an optional base URL.", node).as("TypeError");
|
|
1260
|
-
}
|
|
1261
|
-
const input = urlArgument(args[0], "new URL input");
|
|
1262
|
-
const base = args[1] === undefined ? undefined : urlArgument(args[1], "new URL base");
|
|
1263
|
-
try {
|
|
1264
|
-
return new CodeModeURL(new URL(input, base));
|
|
1265
|
-
}
|
|
1266
|
-
catch {
|
|
1267
|
-
throw new InterpreterRuntimeError(`new URL(...) received an invalid URL${base === undefined ? "" : " or base URL"}.`, node).as("TypeError");
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
constructURLSearchParams(init, node) {
|
|
1271
|
-
if (init === undefined)
|
|
1272
|
-
return Effect.succeed(new CodeModeURLSearchParams(new URLSearchParams()));
|
|
1273
|
-
if (init instanceof CodeModeURLSearchParams) {
|
|
1274
|
-
return Effect.succeed(new CodeModeURLSearchParams(new URLSearchParams(init.params)));
|
|
1275
|
-
}
|
|
1276
|
-
if (typeof init === "string")
|
|
1277
|
-
return Effect.succeed(new CodeModeURLSearchParams(new URLSearchParams(init)));
|
|
1278
|
-
if (init === null || typeof init === "number" || typeof init === "boolean") {
|
|
1279
|
-
return Effect.succeed(new CodeModeURLSearchParams(new URLSearchParams(coerceToString(init))));
|
|
1280
|
-
}
|
|
1281
|
-
const self = this;
|
|
1282
|
-
return Effect.gen(function* () {
|
|
1283
|
-
const cursor = yield* self.syncIterator(init, node);
|
|
1284
|
-
if (cursor !== undefined) {
|
|
1285
|
-
const entries = [];
|
|
1286
|
-
while (true) {
|
|
1287
|
-
const step = yield* cursor.next;
|
|
1288
|
-
if (step.done) {
|
|
1289
|
-
if (entries.some((entry) => entry.length !== 2)) {
|
|
1290
|
-
throw new InterpreterRuntimeError("new URLSearchParams(...) expects iterable [name, value] pairs.", node).as("TypeError");
|
|
1291
|
-
}
|
|
1292
|
-
return new CodeModeURLSearchParams(new URLSearchParams(entries.map((entry) => [entry[0] ?? "", entry[1] ?? ""])));
|
|
1293
|
-
}
|
|
1294
|
-
entries.push(yield* preserveConsumerError(cursor, self.readURLSearchParamsPair(step.value, node)));
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
if (isRuntimeReference(init)) {
|
|
1298
|
-
throw new InterpreterRuntimeError("new URLSearchParams(...) expects a query string, data object, or synchronous iterable pairs.", node).as("TypeError");
|
|
1299
|
-
}
|
|
1300
|
-
if (isCodeModeValue(init))
|
|
1301
|
-
return new CodeModeURLSearchParams(new URLSearchParams());
|
|
1302
|
-
const data = boundedData(init, "new URLSearchParams input");
|
|
1303
|
-
if (data === null || typeof data !== "object") {
|
|
1304
|
-
throw new InterpreterRuntimeError("new URLSearchParams(...) expects a query string, data object, iterable pairs, or URLSearchParams.", node).as("TypeError");
|
|
1305
|
-
}
|
|
1306
|
-
return new CodeModeURLSearchParams(new URLSearchParams(Object.fromEntries(Object.entries(data).map(([key, value]) => [key, coerceToString(value)]))));
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
|
-
readURLSearchParamsPair(value, node) {
|
|
1310
|
-
const self = this;
|
|
1311
|
-
return Effect.gen(function* () {
|
|
1312
|
-
const cursor = yield* self.syncIterator(value, node);
|
|
1313
|
-
if (cursor === undefined) {
|
|
1314
|
-
throw new InterpreterRuntimeError("new URLSearchParams(...) expects iterable [name, value] pairs.", node).as("TypeError");
|
|
1315
|
-
}
|
|
1316
|
-
const items = [];
|
|
1317
|
-
while (true) {
|
|
1318
|
-
const step = yield* cursor.next;
|
|
1319
|
-
if (step.done)
|
|
1320
|
-
return items;
|
|
1321
|
-
items.push(yield* preserveConsumerError(cursor, Effect.sync(() => uriArgument(step.value, "URLSearchParams pair value"))));
|
|
1322
|
-
}
|
|
1014
|
+
const callee = yield* self.evaluateExpression(node.callee);
|
|
1015
|
+
// Globals are built with this interpreter's R; `instanceof` cannot recover the type argument.
|
|
1016
|
+
const construct = callee instanceof HostFunction ? callee.construct : undefined;
|
|
1017
|
+
if (construct === undefined)
|
|
1018
|
+
throw unsupportedSyntax("NewExpression", node);
|
|
1019
|
+
const args = yield* self.evaluateCallArguments(node.arguments);
|
|
1020
|
+
return yield* construct(args, node);
|
|
1323
1021
|
});
|
|
1324
1022
|
}
|
|
1325
1023
|
evaluateBinaryExpression(node) {
|
|
1326
|
-
const operator =
|
|
1024
|
+
const operator = node.operator;
|
|
1025
|
+
const left = node.left;
|
|
1026
|
+
if (left.type === "PrivateIdentifier")
|
|
1027
|
+
throw unsupportedSyntax(left.type, left);
|
|
1327
1028
|
const self = this;
|
|
1328
1029
|
return Effect.gen(function* () {
|
|
1329
|
-
const lhs = yield* self.evaluateExpression(
|
|
1330
|
-
const rhs = yield* self.evaluateExpression(
|
|
1030
|
+
const lhs = yield* self.evaluateExpression(left);
|
|
1031
|
+
const rhs = yield* self.evaluateExpression(node.right);
|
|
1331
1032
|
if (operator === "instanceof")
|
|
1332
1033
|
return instanceofValue(lhs, rhs, node);
|
|
1333
|
-
return
|
|
1034
|
+
return toProgram(self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
|
|
1334
1035
|
});
|
|
1335
1036
|
}
|
|
1336
1037
|
applyBinaryOperator(operator, lhs, rhs, node) {
|
|
@@ -1344,7 +1045,7 @@ export class Interpreter {
|
|
|
1344
1045
|
// Null-prototype data needs explicit primitive coercion; identity and `in` retain raw objects.
|
|
1345
1046
|
// Dates use their default string hint for addition and loose equality, and epoch time elsewhere.
|
|
1346
1047
|
const coerceOperand = (operand) => {
|
|
1347
|
-
if (operand instanceof
|
|
1048
|
+
if (operand instanceof Values.Date) {
|
|
1348
1049
|
return operator === "+" || operator === "==" || operator === "!=" ? coerceToString(operand) : operand.time;
|
|
1349
1050
|
}
|
|
1350
1051
|
return operand !== null && typeof operand === "object" ? coerceToString(operand) : operand;
|
|
@@ -1400,26 +1101,24 @@ export class Interpreter {
|
|
|
1400
1101
|
}
|
|
1401
1102
|
}
|
|
1402
1103
|
evaluateLogicalExpression(node) {
|
|
1403
|
-
const operator =
|
|
1404
|
-
return Effect.flatMap(this.evaluateExpression(
|
|
1104
|
+
const operator = node.operator;
|
|
1105
|
+
return Effect.flatMap(this.evaluateExpression(node.left), (left) => {
|
|
1405
1106
|
if (operator === "&&")
|
|
1406
|
-
return left ? this.evaluateExpression(
|
|
1107
|
+
return left ? this.evaluateExpression(node.right) : Effect.succeed(left);
|
|
1407
1108
|
if (operator === "||")
|
|
1408
|
-
return left ? Effect.succeed(left) : this.evaluateExpression(
|
|
1109
|
+
return left ? Effect.succeed(left) : this.evaluateExpression(node.right);
|
|
1409
1110
|
if (operator === "??")
|
|
1410
|
-
return left !== null && left !== undefined
|
|
1411
|
-
? Effect.succeed(left)
|
|
1412
|
-
: this.evaluateExpression(getNode(node, "right"));
|
|
1111
|
+
return left !== null && left !== undefined ? Effect.succeed(left) : this.evaluateExpression(node.right);
|
|
1413
1112
|
throw new InterpreterRuntimeError(`Unsupported logical operator '${operator}'.`, node);
|
|
1414
1113
|
});
|
|
1415
1114
|
}
|
|
1416
1115
|
evaluateUnaryExpression(node) {
|
|
1417
|
-
const operator =
|
|
1418
|
-
const argument =
|
|
1116
|
+
const operator = node.operator;
|
|
1117
|
+
const argument = node.argument;
|
|
1419
1118
|
if (operator === "delete")
|
|
1420
1119
|
return this.evaluateDeleteExpression(argument);
|
|
1421
1120
|
// Undeclared names short-circuit, but declared TDZ bindings must still throw.
|
|
1422
|
-
if (operator === "typeof" && argument.type === "Identifier" && !this.scopes.resolve(
|
|
1121
|
+
if (operator === "typeof" && argument.type === "Identifier" && !this.scopes.resolve(argument.name)) {
|
|
1423
1122
|
return Effect.succeed("undefined");
|
|
1424
1123
|
}
|
|
1425
1124
|
return Effect.map(this.evaluateExpression(argument), (value) => {
|
|
@@ -1432,7 +1131,7 @@ export class Interpreter {
|
|
|
1432
1131
|
if (containsOpaqueReference(value)) {
|
|
1433
1132
|
throw new InterpreterRuntimeError("Unary operators require data values.", node, "InvalidDataValue");
|
|
1434
1133
|
}
|
|
1435
|
-
const operand = value instanceof
|
|
1134
|
+
const operand = value instanceof Values.Date
|
|
1436
1135
|
? value.time
|
|
1437
1136
|
: value !== null && typeof value === "object"
|
|
1438
1137
|
? coerceToString(value)
|
|
@@ -1451,38 +1150,38 @@ export class Interpreter {
|
|
|
1451
1150
|
default:
|
|
1452
1151
|
throw new InterpreterRuntimeError(`Unsupported unary operator '${operator}'.`, node);
|
|
1453
1152
|
}
|
|
1454
|
-
return
|
|
1153
|
+
return toProgram(result, "Unary expression result");
|
|
1455
1154
|
});
|
|
1456
1155
|
}
|
|
1457
1156
|
evaluateAssignmentExpression(node) {
|
|
1458
|
-
const left =
|
|
1459
|
-
const operator =
|
|
1157
|
+
const left = node.left;
|
|
1158
|
+
const operator = node.operator;
|
|
1460
1159
|
const self = this;
|
|
1461
1160
|
return Effect.gen(function* () {
|
|
1462
1161
|
if (operator === "??=" || operator === "||=" || operator === "&&=") {
|
|
1463
1162
|
return yield* self.evaluateLogicalAssignment(node, left, operator);
|
|
1464
1163
|
}
|
|
1465
1164
|
if (operator === "=" && (left.type === "ObjectPattern" || left.type === "ArrayPattern")) {
|
|
1466
|
-
const rightValue = yield* self.evaluateExpression(
|
|
1165
|
+
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1467
1166
|
yield* self.assignPattern(left, rightValue, node);
|
|
1468
1167
|
return rightValue;
|
|
1469
1168
|
}
|
|
1470
1169
|
if (left.type === "Identifier") {
|
|
1471
|
-
const name =
|
|
1170
|
+
const name = left.name;
|
|
1472
1171
|
if (operator !== "=") {
|
|
1473
1172
|
const current = self.scopes.get(name, left);
|
|
1474
|
-
const rightValue = yield* self.evaluateExpression(
|
|
1475
|
-
const next =
|
|
1173
|
+
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1174
|
+
const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
|
|
1476
1175
|
return self.scopes.set(name, next, left);
|
|
1477
1176
|
}
|
|
1478
|
-
const rightValue = yield* self.evaluateExpression(
|
|
1177
|
+
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1479
1178
|
return self.scopes.set(name, rightValue, left);
|
|
1480
1179
|
}
|
|
1481
1180
|
if (left.type === "MemberExpression") {
|
|
1482
|
-
return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(
|
|
1181
|
+
return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(node.right), (rightValue) => {
|
|
1483
1182
|
if (operator === "=")
|
|
1484
1183
|
return { write: true, next: rightValue, result: rightValue };
|
|
1485
|
-
const next =
|
|
1184
|
+
const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
|
|
1486
1185
|
return { write: true, next, result: next };
|
|
1487
1186
|
}));
|
|
1488
1187
|
}
|
|
@@ -1493,18 +1192,18 @@ export class Interpreter {
|
|
|
1493
1192
|
const self = this;
|
|
1494
1193
|
const shouldAssign = (current) => operator === "??=" ? current === null || current === undefined : operator === "||=" ? !current : Boolean(current);
|
|
1495
1194
|
if (left.type === "Identifier") {
|
|
1496
|
-
const name =
|
|
1195
|
+
const name = left.name;
|
|
1497
1196
|
return Effect.gen(function* () {
|
|
1498
1197
|
const current = self.scopes.get(name, left);
|
|
1499
1198
|
if (!shouldAssign(current))
|
|
1500
1199
|
return current;
|
|
1501
|
-
const rightValue = yield* self.evaluateExpression(
|
|
1200
|
+
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1502
1201
|
return self.scopes.set(name, rightValue, left);
|
|
1503
1202
|
});
|
|
1504
1203
|
}
|
|
1505
1204
|
if (left.type === "MemberExpression") {
|
|
1506
1205
|
return self.modifyMember(left, (current) => shouldAssign(current)
|
|
1507
|
-
? Effect.map(self.evaluateExpression(
|
|
1206
|
+
? Effect.map(self.evaluateExpression(node.right), (rightValue) => ({
|
|
1508
1207
|
write: true,
|
|
1509
1208
|
next: rightValue,
|
|
1510
1209
|
result: rightValue,
|
|
@@ -1514,9 +1213,9 @@ export class Interpreter {
|
|
|
1514
1213
|
throw new InterpreterRuntimeError("Assignment target must be an Identifier or MemberExpression.", left);
|
|
1515
1214
|
}
|
|
1516
1215
|
evaluateUpdateExpression(node) {
|
|
1517
|
-
const operator =
|
|
1518
|
-
const argument =
|
|
1519
|
-
const prefix =
|
|
1216
|
+
const operator = node.operator;
|
|
1217
|
+
const argument = node.argument;
|
|
1218
|
+
const prefix = node.prefix;
|
|
1520
1219
|
const increment = operator === "++" ? 1 : operator === "--" ? -1 : undefined;
|
|
1521
1220
|
if (increment === undefined) {
|
|
1522
1221
|
throw new InterpreterRuntimeError(`Unsupported update operator '${operator}'.`, node);
|
|
@@ -1531,7 +1230,7 @@ export class Interpreter {
|
|
|
1531
1230
|
};
|
|
1532
1231
|
if (argument.type === "Identifier") {
|
|
1533
1232
|
return Effect.sync(() => {
|
|
1534
|
-
const name =
|
|
1233
|
+
const name = argument.name;
|
|
1535
1234
|
const current = operand(this.scopes.get(name, argument));
|
|
1536
1235
|
const next = current + increment;
|
|
1537
1236
|
this.scopes.set(name, next, argument);
|
|
@@ -1548,34 +1247,30 @@ export class Interpreter {
|
|
|
1548
1247
|
throw new InterpreterRuntimeError("Update target must be an Identifier or MemberExpression.", argument);
|
|
1549
1248
|
}
|
|
1550
1249
|
evaluateCallExpression(node) {
|
|
1551
|
-
const callee =
|
|
1552
|
-
const argNodes = getArray(node, "arguments");
|
|
1250
|
+
const callee = node.callee;
|
|
1553
1251
|
const self = this;
|
|
1554
1252
|
return Effect.gen(function* () {
|
|
1253
|
+
if (callee.type === "Super")
|
|
1254
|
+
throw unsupportedSyntax(callee.type, callee);
|
|
1555
1255
|
const callable = yield* self.evaluateExpression(callee);
|
|
1556
1256
|
if (callable === OptionalShortCircuit)
|
|
1557
1257
|
return OptionalShortCircuit;
|
|
1558
|
-
if ((callable === null || callable === undefined) && node.optional
|
|
1258
|
+
if ((callable === null || callable === undefined) && node.optional)
|
|
1559
1259
|
return OptionalShortCircuit;
|
|
1560
|
-
const args = yield* self.evaluateCallArguments(
|
|
1260
|
+
const args = yield* self.evaluateCallArguments(node.arguments);
|
|
1561
1261
|
return yield* self.invokeCallable(callable, args, node, callee);
|
|
1562
1262
|
});
|
|
1563
1263
|
}
|
|
1564
1264
|
// The single dispatch for every invocation: call expressions and callbacks share it.
|
|
1565
|
-
invokeCallable(callable, args, node, callee
|
|
1265
|
+
invokeCallable(callable, args, node, callee) {
|
|
1566
1266
|
const self = this;
|
|
1567
1267
|
return Effect.gen(function* () {
|
|
1568
1268
|
if (callable instanceof ToolReference) {
|
|
1569
|
-
if (callable.path.length === 0)
|
|
1570
|
-
throw new InterpreterRuntimeError("The tools root is not callable.", callee);
|
|
1269
|
+
if (callable.path.length === 0) {
|
|
1270
|
+
throw new InterpreterRuntimeError("The tools root is not callable.", callee ?? node);
|
|
1271
|
+
}
|
|
1571
1272
|
return yield* self.createToolCallPromise(callable.path, args);
|
|
1572
1273
|
}
|
|
1573
|
-
if (callable instanceof PromiseMethodReference) {
|
|
1574
|
-
return yield* invokePromiseMethod(self.runner, self.promises, callable, args, node);
|
|
1575
|
-
}
|
|
1576
|
-
if (callable instanceof PromiseInstanceMethodReference) {
|
|
1577
|
-
return yield* invokePromiseInstanceMethod(self.runner, self.promises, callable, args, node);
|
|
1578
|
-
}
|
|
1579
1274
|
if (callable instanceof CodeModeFunction) {
|
|
1580
1275
|
return yield* self.invokeFunction(callable, args);
|
|
1581
1276
|
}
|
|
@@ -1586,103 +1281,26 @@ export class Interpreter {
|
|
|
1586
1281
|
return callable.generator.asynchronous ? yield* self.createPromise(requested) : yield* requested;
|
|
1587
1282
|
}
|
|
1588
1283
|
if (callable instanceof IntrinsicReference) {
|
|
1589
|
-
return yield* invokeIntrinsic(self.runner, callable, args, node);
|
|
1590
|
-
}
|
|
1591
|
-
if (callable instanceof GlobalMethodReference) {
|
|
1592
|
-
if (callable.namespace === "console")
|
|
1593
|
-
return self.invokeConsole(callable.name, args, node);
|
|
1594
|
-
if (callable.namespace === "Object" && args[0] instanceof ToolReference) {
|
|
1595
|
-
return self.invokeObjectMethodOnTools(callable.name, args[0], node);
|
|
1596
|
-
}
|
|
1597
|
-
if (callable.namespace === "Object" && objectMethodsPreservingIdentity.has(callable.name)) {
|
|
1598
|
-
if (callable.name === "fromEntries")
|
|
1599
|
-
return yield* invokeObjectFromEntries(self.runner, args[0], node);
|
|
1600
|
-
return invokeGlobalMethod(callable, args, node);
|
|
1601
|
-
}
|
|
1602
|
-
if (callable.namespace === "Array" && callable.name === "from") {
|
|
1603
|
-
return yield* invokeArrayFrom(self.runner, args, node);
|
|
1604
|
-
}
|
|
1605
|
-
if ((callable.namespace === "Object" || callable.namespace === "Map") && callable.name === "groupBy") {
|
|
1606
|
-
return yield* invokeGroupBy(self.runner, callable.namespace, args, node);
|
|
1607
|
-
}
|
|
1608
|
-
if (callable.namespace === "Math" && callable.name === "sumPrecise") {
|
|
1609
|
-
return yield* invokeMathSumPrecise(self.runner, args[0], node);
|
|
1610
|
-
}
|
|
1611
|
-
if (callable.namespace === "Array" && callable.name === "of") {
|
|
1612
|
-
return invokeGlobalMethod(callable, args, node);
|
|
1613
|
-
}
|
|
1614
|
-
return boundedData(invokeGlobalMethod(callable, args, node), `${callable.namespace}.${callable.name} result`);
|
|
1284
|
+
return yield* invokeIntrinsic(self.runtime.runner, callable, args, node);
|
|
1615
1285
|
}
|
|
1616
|
-
if (callable instanceof
|
|
1617
|
-
return yield*
|
|
1618
|
-
}
|
|
1619
|
-
if (callable instanceof CoercionFunction) {
|
|
1620
|
-
return boundedData(invokeCoercion(callable, args, node), `${callable.name} result`);
|
|
1621
|
-
}
|
|
1622
|
-
if (callable instanceof UriFunction) {
|
|
1623
|
-
return invokeUriFunction(callable, args, node);
|
|
1624
|
-
}
|
|
1625
|
-
if (callable instanceof SearchFunction) {
|
|
1626
|
-
return yield* self.invokeSearch(args);
|
|
1627
|
-
}
|
|
1628
|
-
if (callable instanceof ErrorConstructorReference) {
|
|
1629
|
-
if (callable.name === "AggregateError")
|
|
1630
|
-
return yield* constructAggregateErrorValue(self.runner, args, node);
|
|
1631
|
-
return constructErrorValue(callable.name, args);
|
|
1632
|
-
}
|
|
1633
|
-
if (callable instanceof GlobalNamespace) {
|
|
1634
|
-
// Real JS permits calling Array, Object, Date, and RegExp without new.
|
|
1635
|
-
if (callable.name === "Array")
|
|
1636
|
-
return self.constructArray(args, node);
|
|
1637
|
-
if (callable.name === "Object")
|
|
1638
|
-
return self.constructObject(args, node);
|
|
1639
|
-
// ISO instead of the host's locale string: CodeMode date strings are
|
|
1640
|
-
// deterministic and must not leak the host timezone.
|
|
1641
|
-
if (callable.name === "Date")
|
|
1642
|
-
return new Date().toISOString();
|
|
1643
|
-
if (callable.name === "RegExp")
|
|
1644
|
-
return self.constructRegExp(args, node);
|
|
1645
|
-
if (typeofValue(callable) === "function") {
|
|
1646
|
-
throw new InterpreterRuntimeError(`Constructor ${callable.name} requires 'new'.`, node).as("TypeError");
|
|
1647
|
-
}
|
|
1648
|
-
throw new InterpreterRuntimeError(`${callable.name} is not a function.`, node).as("TypeError");
|
|
1649
|
-
}
|
|
1650
|
-
if (callable instanceof PromiseNamespace) {
|
|
1651
|
-
throw new InterpreterRuntimeError("Constructor Promise requires 'new'.", node).as("TypeError");
|
|
1652
|
-
}
|
|
1653
|
-
if (callable instanceof SymbolNamespace) {
|
|
1654
|
-
throw new InterpreterRuntimeError("Symbol is not callable; only Symbol.asyncIterator and Symbol.iterator are available.", node).as("TypeError");
|
|
1655
|
-
}
|
|
1656
|
-
if (callable instanceof PromiseCapabilityFunction) {
|
|
1657
|
-
callable.settle(args[0]);
|
|
1658
|
-
return undefined;
|
|
1286
|
+
if (callable instanceof PromiseInstanceMethodReference) {
|
|
1287
|
+
return yield* invokePromiseInstanceMethod(self.runtime.runner, self.runtime.promises, callable, args, node);
|
|
1659
1288
|
}
|
|
1289
|
+
if (callable instanceof HostFunction)
|
|
1290
|
+
return yield* callable.call(args, node);
|
|
1660
1291
|
if (callable === undefined || callable === null) {
|
|
1661
|
-
throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee).as("TypeError");
|
|
1292
|
+
throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node).as("TypeError");
|
|
1662
1293
|
}
|
|
1663
|
-
throw new InterpreterRuntimeError("Only tools are callable here.", callee);
|
|
1294
|
+
throw new InterpreterRuntimeError("Only tools are callable here.", callee ?? node);
|
|
1664
1295
|
});
|
|
1665
1296
|
}
|
|
1666
|
-
invokeObjectMethodOnTools(name, ref, node) {
|
|
1667
|
-
if (name === "keys") {
|
|
1668
|
-
return boundedData(this.enumerableKeys(ref), "Object.keys result");
|
|
1669
|
-
}
|
|
1670
|
-
throw new InterpreterRuntimeError(`Object.${name}(...) cannot read tool references: they are not plain data. Use Object.keys(tools) for names, or search({ query }) for signatures.`, node, "InvalidDataValue");
|
|
1671
|
-
}
|
|
1672
|
-
invokeConsole(name, args, node) {
|
|
1673
|
-
if (!consoleMethods.has(name))
|
|
1674
|
-
throw new InterpreterRuntimeError(`console.${name} is not available.`, node);
|
|
1675
|
-
this.logs.push(formatConsoleMessage(name, args));
|
|
1676
|
-
return undefined;
|
|
1677
|
-
}
|
|
1678
1297
|
evaluateCallArguments(argNodes) {
|
|
1679
1298
|
const self = this;
|
|
1680
1299
|
return Effect.gen(function* () {
|
|
1681
1300
|
const args = [];
|
|
1682
|
-
for (const
|
|
1683
|
-
const argNode = asNode(arg, `arguments[${index}]`);
|
|
1301
|
+
for (const argNode of argNodes) {
|
|
1684
1302
|
if (argNode.type === "SpreadElement") {
|
|
1685
|
-
const spread = yield* self.evaluateExpression(
|
|
1303
|
+
const spread = yield* self.evaluateExpression(argNode.argument);
|
|
1686
1304
|
const cursor = yield* self.syncIterator(spread, argNode);
|
|
1687
1305
|
if (cursor === undefined)
|
|
1688
1306
|
throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode).as("TypeError");
|
|
@@ -1701,8 +1319,7 @@ export class Interpreter {
|
|
|
1701
1319
|
});
|
|
1702
1320
|
}
|
|
1703
1321
|
invokeFunction(fn, args) {
|
|
1704
|
-
const invocation = new
|
|
1705
|
-
invocation.scopes = new ScopeStack([...fn.capturedScopes, new Map()]);
|
|
1322
|
+
const invocation = new Frame(this.runtime, new ScopeStack([...fn.capturedScopes, new Map()]));
|
|
1706
1323
|
const run = Effect.gen(function* () {
|
|
1707
1324
|
// Seed all parameters first so defaults cannot fall through to same-named outer bindings.
|
|
1708
1325
|
const paramScope = invocation.scopes.current();
|
|
@@ -1713,7 +1330,7 @@ export class Interpreter {
|
|
|
1713
1330
|
}
|
|
1714
1331
|
for (const [index, parameter] of fn.parameters.entries()) {
|
|
1715
1332
|
if (parameter.type === "RestElement") {
|
|
1716
|
-
yield* invocation.declarePattern(
|
|
1333
|
+
yield* invocation.declarePattern(parameter.argument, args.slice(index), true, parameter, true);
|
|
1717
1334
|
break;
|
|
1718
1335
|
}
|
|
1719
1336
|
yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
|
|
@@ -1730,7 +1347,7 @@ export class Interpreter {
|
|
|
1730
1347
|
return run;
|
|
1731
1348
|
// The initial yield assigns the promise before the body can self-resolve.
|
|
1732
1349
|
const box = {};
|
|
1733
|
-
return Effect.map(this.createPromise(Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runner, value, fn.body, box))), (promise) => {
|
|
1350
|
+
return Effect.map(this.createPromise(Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, fn.body, box))), (promise) => {
|
|
1734
1351
|
box.promise = promise;
|
|
1735
1352
|
return promise;
|
|
1736
1353
|
});
|
|
@@ -1751,7 +1368,7 @@ export class Interpreter {
|
|
|
1751
1368
|
if (state.draining)
|
|
1752
1369
|
return Deferred.await(request.response);
|
|
1753
1370
|
state.draining = true;
|
|
1754
|
-
return Effect.andThen(this.promises.fork(invocation
|
|
1371
|
+
return Effect.andThen(this.runtime.promises.fork(invocation
|
|
1755
1372
|
.completeGeneratorRequests(state, true)
|
|
1756
1373
|
.pipe(Effect.ensuring(Effect.sync(() => (state.draining = false))))), Deferred.await(request.response));
|
|
1757
1374
|
}
|
|
@@ -1789,7 +1406,7 @@ export class Interpreter {
|
|
|
1789
1406
|
yield* invocation.completeGeneratorRequests(state, asynchronous);
|
|
1790
1407
|
state.completed = true;
|
|
1791
1408
|
});
|
|
1792
|
-
return Effect.andThen(this.promises.fork(body), Deferred.await(request.response));
|
|
1409
|
+
return Effect.andThen(this.runtime.promises.fork(body), Deferred.await(request.response));
|
|
1793
1410
|
}
|
|
1794
1411
|
return Deferred.await(request.response);
|
|
1795
1412
|
});
|
|
@@ -1834,12 +1451,12 @@ export class Interpreter {
|
|
|
1834
1451
|
return request;
|
|
1835
1452
|
}
|
|
1836
1453
|
evaluateYieldExpression(node) {
|
|
1837
|
-
const argument =
|
|
1454
|
+
const argument = node.argument;
|
|
1838
1455
|
const self = this;
|
|
1839
1456
|
return Effect.gen(function* () {
|
|
1840
1457
|
if (!self.generatorState)
|
|
1841
1458
|
throw new InterpreterRuntimeError("yield is only valid inside a generator.", node);
|
|
1842
|
-
if (node.delegate
|
|
1459
|
+
if (node.delegate) {
|
|
1843
1460
|
const value = argument ? yield* self.evaluateExpression(argument) : undefined;
|
|
1844
1461
|
return yield* self.delegateYield(value, node);
|
|
1845
1462
|
}
|
|
@@ -1870,9 +1487,9 @@ export class Interpreter {
|
|
|
1870
1487
|
return Effect.gen(function* () {
|
|
1871
1488
|
if (Array.isArray(value) ||
|
|
1872
1489
|
typeof value === "string" ||
|
|
1873
|
-
value instanceof
|
|
1874
|
-
value instanceof
|
|
1875
|
-
value instanceof
|
|
1490
|
+
value instanceof Values.Map ||
|
|
1491
|
+
value instanceof Values.Set ||
|
|
1492
|
+
value instanceof Values.URLSearchParams) {
|
|
1876
1493
|
const cursor = yield* self.syncIterator(value, node);
|
|
1877
1494
|
if (!cursor)
|
|
1878
1495
|
throw new InterpreterRuntimeError("Built-in iterator is unavailable.", node);
|
|
@@ -1940,14 +1557,12 @@ export class Interpreter {
|
|
|
1940
1557
|
}
|
|
1941
1558
|
evaluateObjectExpression(node) {
|
|
1942
1559
|
const objectValue = Object.create(null);
|
|
1943
|
-
const properties = getArray(node, "properties");
|
|
1944
1560
|
const self = this;
|
|
1945
1561
|
return Effect.gen(function* () {
|
|
1946
|
-
for (const
|
|
1947
|
-
const property = asNode(propertyValue, "properties");
|
|
1562
|
+
for (const property of node.properties) {
|
|
1948
1563
|
if (property.type === "SpreadElement") {
|
|
1949
|
-
const spread = yield* self.evaluateExpression(
|
|
1950
|
-
if (spread === null || spread === undefined ||
|
|
1564
|
+
const spread = yield* self.evaluateExpression(property.argument);
|
|
1565
|
+
if (spread === null || spread === undefined || Values.isValue(spread))
|
|
1951
1566
|
continue;
|
|
1952
1567
|
if (typeof spread !== "object" || Array.isArray(spread) || isRuntimeReference(spread)) {
|
|
1953
1568
|
throw new InterpreterRuntimeError("Object spread requires a data object.", property, "InvalidDataValue");
|
|
@@ -1960,21 +1575,16 @@ export class Interpreter {
|
|
|
1960
1575
|
copyIteratorSymbols(spread, objectValue);
|
|
1961
1576
|
continue;
|
|
1962
1577
|
}
|
|
1963
|
-
if (property.
|
|
1964
|
-
throw new InterpreterRuntimeError("Only standard object properties are supported.", property);
|
|
1965
|
-
}
|
|
1966
|
-
if (getString(property, "kind") !== "init") {
|
|
1578
|
+
if (property.kind !== "init") {
|
|
1967
1579
|
throw new InterpreterRuntimeError("Only init object properties are supported.", property);
|
|
1968
1580
|
}
|
|
1969
|
-
const keyNode =
|
|
1970
|
-
const valueNode = getNode(property, "value");
|
|
1971
|
-
const computed = getBoolean(property, "computed");
|
|
1581
|
+
const keyNode = property.key;
|
|
1972
1582
|
let key;
|
|
1973
|
-
if (computed) {
|
|
1583
|
+
if (property.computed) {
|
|
1974
1584
|
key = self.toPropertyKey(yield* self.evaluateExpression(keyNode), keyNode);
|
|
1975
1585
|
}
|
|
1976
1586
|
else if (keyNode.type === "Identifier") {
|
|
1977
|
-
key =
|
|
1587
|
+
key = keyNode.name;
|
|
1978
1588
|
}
|
|
1979
1589
|
else if (keyNode.type === "Literal") {
|
|
1980
1590
|
key = self.toPropertyKey(keyNode.value, keyNode);
|
|
@@ -1985,25 +1595,23 @@ export class Interpreter {
|
|
|
1985
1595
|
if (isBlockedMember(String(key))) {
|
|
1986
1596
|
throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, keyNode);
|
|
1987
1597
|
}
|
|
1988
|
-
Reflect.set(objectValue, key, yield* self.evaluateExpression(
|
|
1598
|
+
Reflect.set(objectValue, key, yield* self.evaluateExpression(property.value));
|
|
1989
1599
|
}
|
|
1990
1600
|
return objectValue;
|
|
1991
1601
|
});
|
|
1992
1602
|
}
|
|
1993
1603
|
evaluateArrayExpression(node) {
|
|
1994
|
-
const elements = getArray(node, "elements");
|
|
1995
1604
|
const values = [];
|
|
1996
1605
|
const self = this;
|
|
1997
1606
|
return Effect.gen(function* () {
|
|
1998
|
-
for (const
|
|
1999
|
-
if (
|
|
1607
|
+
for (const element of node.elements) {
|
|
1608
|
+
if (element === null) {
|
|
2000
1609
|
// A literal elision is a real hole, like JS: extend length without an own index.
|
|
2001
1610
|
values.length += 1;
|
|
2002
1611
|
continue;
|
|
2003
1612
|
}
|
|
2004
|
-
const element = asNode(elementValue, "elements");
|
|
2005
1613
|
if (element.type === "SpreadElement") {
|
|
2006
|
-
const spread = yield* self.evaluateExpression(
|
|
1614
|
+
const spread = yield* self.evaluateExpression(element.argument);
|
|
2007
1615
|
const cursor = yield* self.syncIterator(spread, element);
|
|
2008
1616
|
if (cursor === undefined)
|
|
2009
1617
|
throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element).as("TypeError");
|
|
@@ -2022,28 +1630,28 @@ export class Interpreter {
|
|
|
2022
1630
|
});
|
|
2023
1631
|
}
|
|
2024
1632
|
evaluateTemplateLiteral(node) {
|
|
2025
|
-
const quasis =
|
|
2026
|
-
const expressions =
|
|
1633
|
+
const quasis = node.quasis;
|
|
1634
|
+
const expressions = node.expressions;
|
|
2027
1635
|
let output = "";
|
|
2028
1636
|
const self = this;
|
|
2029
1637
|
return Effect.gen(function* () {
|
|
2030
1638
|
for (let index = 0; index < quasis.length; index += 1) {
|
|
2031
|
-
const quasi =
|
|
2032
|
-
|
|
2033
|
-
if (
|
|
1639
|
+
const quasi = quasis[index];
|
|
1640
|
+
// acorn only omits `cooked` for invalid escapes in tagged templates, which are unsupported.
|
|
1641
|
+
if (typeof quasi.value.cooked !== "string") {
|
|
2034
1642
|
throw new InterpreterRuntimeError("Invalid template literal quasi.", quasi);
|
|
2035
1643
|
}
|
|
2036
|
-
output +=
|
|
1644
|
+
output += quasi.value.cooked;
|
|
2037
1645
|
if (index < expressions.length) {
|
|
2038
|
-
const raw = yield* self.evaluateExpression(
|
|
2039
|
-
output += coerceToString(
|
|
1646
|
+
const raw = yield* self.evaluateExpression(expressions[index]);
|
|
1647
|
+
output += coerceToString(toProgram(raw, "Template interpolation"));
|
|
2040
1648
|
}
|
|
2041
1649
|
}
|
|
2042
1650
|
return output;
|
|
2043
1651
|
});
|
|
2044
1652
|
}
|
|
2045
1653
|
evaluateConditionalExpression(node) {
|
|
2046
|
-
return Effect.flatMap(this.evaluateExpression(
|
|
1654
|
+
return Effect.flatMap(this.evaluateExpression(node.test), (test) => this.evaluateExpression(test ? node.consequent : node.alternate));
|
|
2047
1655
|
}
|
|
2048
1656
|
applyCompoundAssignment(operator, current, incoming, node) {
|
|
2049
1657
|
if (!compoundOperators.has(operator)) {
|
|
@@ -2052,21 +1660,23 @@ export class Interpreter {
|
|
|
2052
1660
|
return this.applyBinaryOperator(operator.slice(0, -1), current, incoming, node);
|
|
2053
1661
|
}
|
|
2054
1662
|
getMemberReference(node, operation = "read") {
|
|
2055
|
-
const objectNode =
|
|
2056
|
-
const propertyNode =
|
|
2057
|
-
|
|
2058
|
-
|
|
1663
|
+
const objectNode = node.object;
|
|
1664
|
+
const propertyNode = node.property;
|
|
1665
|
+
if (objectNode.type === "Super")
|
|
1666
|
+
throw unsupportedSyntax(objectNode.type, objectNode);
|
|
1667
|
+
if (propertyNode.type === "PrivateIdentifier")
|
|
1668
|
+
throw unsupportedSyntax(propertyNode.type, propertyNode);
|
|
2059
1669
|
const self = this;
|
|
2060
1670
|
return Effect.gen(function* () {
|
|
2061
1671
|
const objectValue = yield* self.evaluateExpression(objectNode);
|
|
2062
1672
|
if (objectValue === OptionalShortCircuit)
|
|
2063
1673
|
return OptionalShortCircuit;
|
|
2064
|
-
if ((objectValue === null || objectValue === undefined) && optional)
|
|
1674
|
+
if ((objectValue === null || objectValue === undefined) && node.optional)
|
|
2065
1675
|
return OptionalShortCircuit;
|
|
2066
|
-
const key = computed
|
|
1676
|
+
const key = node.computed
|
|
2067
1677
|
? self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode)
|
|
2068
1678
|
: propertyNode.type === "Identifier"
|
|
2069
|
-
?
|
|
1679
|
+
? propertyNode.name
|
|
2070
1680
|
: self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode);
|
|
2071
1681
|
if (objectValue instanceof ToolReference) {
|
|
2072
1682
|
if (typeof key !== "string") {
|
|
@@ -2074,38 +1684,12 @@ export class Interpreter {
|
|
|
2074
1684
|
}
|
|
2075
1685
|
return new ToolReference([...objectValue.path, key]);
|
|
2076
1686
|
}
|
|
2077
|
-
if (objectValue instanceof
|
|
2078
|
-
if (typeof key === "string" && promiseStatics.has(key)) {
|
|
2079
|
-
return new PromiseMethodReference(key);
|
|
2080
|
-
}
|
|
2081
|
-
throw new InterpreterRuntimeError(`Promise.${String(key)} is not available. Available: Promise.all, Promise.allSettled, Promise.race, Promise.any, Promise.resolve, and Promise.reject; consume promises with await.`, propertyNode);
|
|
2082
|
-
}
|
|
2083
|
-
if (objectValue instanceof SymbolNamespace) {
|
|
2084
|
-
if (key === "asyncIterator")
|
|
2085
|
-
return new ComputedValue(AsyncIteratorSymbol);
|
|
2086
|
-
if (key === "iterator")
|
|
2087
|
-
return new ComputedValue(IteratorSymbol);
|
|
2088
|
-
return new ComputedValue(undefined);
|
|
2089
|
-
}
|
|
2090
|
-
if (objectValue instanceof GlobalNamespace) {
|
|
1687
|
+
if (objectValue instanceof HostFunction || objectValue instanceof HostNamespace) {
|
|
2091
1688
|
if (typeof key === "string" && isBlockedMember(key)) {
|
|
2092
1689
|
throw new InterpreterRuntimeError(`${objectValue.name}.${key} is not available.`, propertyNode);
|
|
2093
1690
|
}
|
|
2094
|
-
if (typeof key !== "string")
|
|
2095
|
-
return new ComputedValue(undefined);
|
|
2096
|
-
if (objectValue.name === "Math" && mathConstants.has(key)) {
|
|
2097
|
-
return new ComputedValue(Math[key]);
|
|
2098
|
-
}
|
|
2099
|
-
if (objectValue.name === "JSON") {
|
|
2100
|
-
if (jsonStatics.has(key))
|
|
2101
|
-
return new JsonMethodReference(key);
|
|
2102
|
-
return new ComputedValue(undefined);
|
|
2103
|
-
}
|
|
2104
|
-
if (globalStaticMembers[objectValue.name]?.has(key)) {
|
|
2105
|
-
return new GlobalMethodReference(objectValue.name, key);
|
|
2106
|
-
}
|
|
2107
1691
|
// Unknown static members read as undefined so feature detection works like native JS.
|
|
2108
|
-
return new ComputedValue(
|
|
1692
|
+
return new ComputedValue(objectValue.member(key, propertyNode));
|
|
2109
1693
|
}
|
|
2110
1694
|
if (typeof objectValue === "string") {
|
|
2111
1695
|
if (key === "length")
|
|
@@ -2122,29 +1706,12 @@ export class Interpreter {
|
|
|
2122
1706
|
return new IntrinsicReference(objectValue, key);
|
|
2123
1707
|
return new ComputedValue(undefined);
|
|
2124
1708
|
}
|
|
2125
|
-
if (objectValue instanceof
|
|
2126
|
-
if (typeof key === "string" && isBlockedMember(key)) {
|
|
2127
|
-
throw new InterpreterRuntimeError(`${objectValue.name}.${key} is not available.`, propertyNode);
|
|
2128
|
-
}
|
|
2129
|
-
if (typeof key !== "string")
|
|
2130
|
-
return new ComputedValue(undefined);
|
|
2131
|
-
if (objectValue.name === "Number" && numberConstants.has(key)) {
|
|
2132
|
-
return new ComputedValue(Number[key]);
|
|
2133
|
-
}
|
|
2134
|
-
if (objectValue.name === "Number" && numberStatics.has(key)) {
|
|
2135
|
-
return new GlobalMethodReference("Number", key);
|
|
2136
|
-
}
|
|
2137
|
-
if (objectValue.name === "String" && stringStatics.has(key)) {
|
|
2138
|
-
return new GlobalMethodReference("String", key);
|
|
2139
|
-
}
|
|
2140
|
-
return new ComputedValue(undefined);
|
|
2141
|
-
}
|
|
2142
|
-
if (objectValue instanceof CodeModeDate) {
|
|
1709
|
+
if (objectValue instanceof Values.Date) {
|
|
2143
1710
|
if (typeof key === "string" && dateMethods.has(key))
|
|
2144
1711
|
return new IntrinsicReference(objectValue, key);
|
|
2145
1712
|
return new ComputedValue(undefined);
|
|
2146
1713
|
}
|
|
2147
|
-
if (objectValue instanceof
|
|
1714
|
+
if (objectValue instanceof Values.RegExp) {
|
|
2148
1715
|
if (key === "lastIndex")
|
|
2149
1716
|
return { target: objectValue, key };
|
|
2150
1717
|
if (typeof key === "string" && regexpProperties.has(key)) {
|
|
@@ -2154,21 +1721,21 @@ export class Interpreter {
|
|
|
2154
1721
|
return new IntrinsicReference(objectValue, key);
|
|
2155
1722
|
return new ComputedValue(undefined);
|
|
2156
1723
|
}
|
|
2157
|
-
if (objectValue instanceof
|
|
1724
|
+
if (objectValue instanceof Values.Map) {
|
|
2158
1725
|
if (key === "size")
|
|
2159
1726
|
return new ComputedValue(objectValue.map.size);
|
|
2160
1727
|
if (typeof key === "string" && mapMethods.has(key))
|
|
2161
1728
|
return new IntrinsicReference(objectValue, key);
|
|
2162
1729
|
return new ComputedValue(undefined);
|
|
2163
1730
|
}
|
|
2164
|
-
if (objectValue instanceof
|
|
1731
|
+
if (objectValue instanceof Values.Set) {
|
|
2165
1732
|
if (key === "size")
|
|
2166
1733
|
return new ComputedValue(objectValue.set.size);
|
|
2167
1734
|
if (typeof key === "string" && setMethods.has(key))
|
|
2168
1735
|
return new IntrinsicReference(objectValue, key);
|
|
2169
1736
|
return new ComputedValue(undefined);
|
|
2170
1737
|
}
|
|
2171
|
-
if (objectValue instanceof
|
|
1738
|
+
if (objectValue instanceof Values.URL) {
|
|
2172
1739
|
if (key === "searchParams") {
|
|
2173
1740
|
return new ComputedValue(objectValue.searchParams);
|
|
2174
1741
|
}
|
|
@@ -2178,7 +1745,7 @@ export class Interpreter {
|
|
|
2178
1745
|
return { target: objectValue, key };
|
|
2179
1746
|
return new ComputedValue(undefined);
|
|
2180
1747
|
}
|
|
2181
|
-
if (objectValue instanceof
|
|
1748
|
+
if (objectValue instanceof Values.URLSearchParams) {
|
|
2182
1749
|
if (key === "size")
|
|
2183
1750
|
return new ComputedValue(objectValue.params.size);
|
|
2184
1751
|
if (typeof key === "string" && urlSearchParamsMethods.has(key)) {
|
|
@@ -2187,7 +1754,7 @@ export class Interpreter {
|
|
|
2187
1754
|
return new ComputedValue(undefined);
|
|
2188
1755
|
}
|
|
2189
1756
|
// Reject unknown promise properties so a missing await cannot hide.
|
|
2190
|
-
if (objectValue instanceof
|
|
1757
|
+
if (objectValue instanceof Values.Promise) {
|
|
2191
1758
|
if (key === "then" || key === "catch" || key === "finally") {
|
|
2192
1759
|
return new PromiseInstanceMethodReference(objectValue, key);
|
|
2193
1760
|
}
|
|
@@ -2242,9 +1809,9 @@ export class Interpreter {
|
|
|
2242
1809
|
return new IntrinsicReference(reference.target, reference.key);
|
|
2243
1810
|
return Reflect.get(reference.target, reference.key);
|
|
2244
1811
|
}
|
|
2245
|
-
if (reference.target instanceof
|
|
1812
|
+
if (reference.target instanceof Values.RegExp)
|
|
2246
1813
|
return reference.target.lastIndex;
|
|
2247
|
-
if (reference.target instanceof
|
|
1814
|
+
if (reference.target instanceof Values.URL) {
|
|
2248
1815
|
return Reflect.get(reference.target.url, reference.key);
|
|
2249
1816
|
}
|
|
2250
1817
|
return Reflect.get(reference.target, reference.key);
|
|
@@ -2254,7 +1821,7 @@ export class Interpreter {
|
|
|
2254
1821
|
return this.modifyMember(node, () => Effect.succeed({ write: true, next: value, result: value }));
|
|
2255
1822
|
}
|
|
2256
1823
|
evaluateDeleteExpression(argument) {
|
|
2257
|
-
const target = argument.type === "ChainExpression" ?
|
|
1824
|
+
const target = argument.type === "ChainExpression" ? argument.expression : argument;
|
|
2258
1825
|
if (target.type !== "MemberExpression") {
|
|
2259
1826
|
throw new InterpreterRuntimeError("Only data fields may be deleted.", argument);
|
|
2260
1827
|
}
|
|
@@ -2264,10 +1831,10 @@ export class Interpreter {
|
|
|
2264
1831
|
if (reference instanceof ComputedValue ||
|
|
2265
1832
|
reference === undefined ||
|
|
2266
1833
|
isOpaqueMemberReference(reference) ||
|
|
2267
|
-
reference.target instanceof
|
|
1834
|
+
reference.target instanceof Values.URL) {
|
|
2268
1835
|
throw new InterpreterRuntimeError("Only data fields may be deleted.", target, "InvalidDataValue");
|
|
2269
1836
|
}
|
|
2270
|
-
if (reference.target instanceof
|
|
1837
|
+
if (reference.target instanceof Values.RegExp) {
|
|
2271
1838
|
return Reflect.deleteProperty(reference.target.regex, reference.key);
|
|
2272
1839
|
}
|
|
2273
1840
|
return Reflect.deleteProperty(reference.target, reference.key);
|
|
@@ -2299,10 +1866,10 @@ export class Interpreter {
|
|
|
2299
1866
|
});
|
|
2300
1867
|
}
|
|
2301
1868
|
readReferenceValue(reference, key) {
|
|
2302
|
-
if (reference.target instanceof
|
|
1869
|
+
if (reference.target instanceof Values.URL) {
|
|
2303
1870
|
return Reflect.get(reference.target.url, key);
|
|
2304
1871
|
}
|
|
2305
|
-
if (reference.target instanceof
|
|
1872
|
+
if (reference.target instanceof Values.RegExp)
|
|
2306
1873
|
return reference.target.lastIndex;
|
|
2307
1874
|
return Reflect.get(reference.target, key);
|
|
2308
1875
|
}
|
|
@@ -2316,7 +1883,7 @@ export class Interpreter {
|
|
|
2316
1883
|
target[key] = next;
|
|
2317
1884
|
return;
|
|
2318
1885
|
}
|
|
2319
|
-
if (reference.target instanceof
|
|
1886
|
+
if (reference.target instanceof Values.URL) {
|
|
2320
1887
|
const property = key;
|
|
2321
1888
|
if (!urlWritableProperties.has(property)) {
|
|
2322
1889
|
throw new InterpreterRuntimeError(`URL.${property} is read-only.`, node).as("TypeError");
|
|
@@ -2332,7 +1899,7 @@ export class Interpreter {
|
|
|
2332
1899
|
throw new InterpreterRuntimeError(`URL.${property} received an invalid value.`, node).as("TypeError");
|
|
2333
1900
|
}
|
|
2334
1901
|
}
|
|
2335
|
-
if (reference.target instanceof
|
|
1902
|
+
if (reference.target instanceof Values.RegExp) {
|
|
2336
1903
|
reference.target.lastIndex = next;
|
|
2337
1904
|
return;
|
|
2338
1905
|
}
|