@opencode/codemode 0.0.0-dev-19356 → 0.0.0-dev-19360
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.
|
@@ -6,7 +6,7 @@ import { transpile } from "#transpile";
|
|
|
6
6
|
import { toData } from "../data.js";
|
|
7
7
|
import { ToolRuntime } from "../tool-runtime.js";
|
|
8
8
|
import { normalizeError } from "./errors.js";
|
|
9
|
-
import { InterpreterRuntimeError
|
|
9
|
+
import { InterpreterRuntimeError } from "./model.js";
|
|
10
10
|
import { PromiseRuntime } from "./promises.js";
|
|
11
11
|
import { Interpreter } from "./runtime.js";
|
|
12
12
|
export const executeProgram = (code, prepared, limits, hooks) => {
|
|
@@ -88,17 +88,13 @@ const parseProgram = (code) => {
|
|
|
88
88
|
const bodyStart = transpiled.outputText.indexOf("{") + 1;
|
|
89
89
|
const bodyEnd = transpiled.outputText.lastIndexOf("}");
|
|
90
90
|
const executableCode = transpiled.outputText.slice(bodyStart, bodyEnd);
|
|
91
|
-
|
|
91
|
+
return parse(executableCode, {
|
|
92
92
|
ecmaVersion: "latest",
|
|
93
93
|
sourceType: "script",
|
|
94
94
|
allowReturnOutsideFunction: true,
|
|
95
95
|
allowAwaitOutsideFunction: true,
|
|
96
96
|
locations: true,
|
|
97
97
|
});
|
|
98
|
-
if (!isRecord(parsed) || parsed.type !== "Program" || !Array.isArray(parsed.body)) {
|
|
99
|
-
throw new InterpreterRuntimeError("Failed to parse script as a Program node.");
|
|
100
|
-
}
|
|
101
|
-
return parsed;
|
|
102
98
|
};
|
|
103
99
|
const utf8ByteLength = (value) => new TextEncoder().encode(value).byteLength;
|
|
104
100
|
// Drop a replacement character produced by truncating inside a UTF-8 sequence.
|
|
@@ -1,24 +1,10 @@
|
|
|
1
|
+
import type { BlockStatement, Expression, Node, Pattern } from "acorn";
|
|
1
2
|
import type { Effect } from "effect";
|
|
2
3
|
import type { DiagnosticKind } from "../codemode.js";
|
|
3
4
|
import type { SafeObject } from "../data.js";
|
|
4
5
|
import type { Values } from "../values.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
column: number;
|
|
8
|
-
};
|
|
9
|
-
export type SourceLocation = {
|
|
10
|
-
start: SourcePosition;
|
|
11
|
-
end: SourcePosition;
|
|
12
|
-
};
|
|
13
|
-
export type AstNode = {
|
|
14
|
-
type: string;
|
|
15
|
-
loc?: SourceLocation;
|
|
16
|
-
[key: string]: unknown;
|
|
17
|
-
};
|
|
18
|
-
export type ProgramNode = AstNode & {
|
|
19
|
-
type: "Program";
|
|
20
|
-
body: Array<AstNode>;
|
|
21
|
-
};
|
|
6
|
+
/** Any parsed node; the interpreter narrows on `type` and reads `loc` for diagnostics. */
|
|
7
|
+
export type AstNode = Node;
|
|
22
8
|
export type Binding = {
|
|
23
9
|
mutable: boolean;
|
|
24
10
|
value: unknown;
|
|
@@ -41,12 +27,12 @@ export type MemberReference = {
|
|
|
41
27
|
key: PropertyKey;
|
|
42
28
|
};
|
|
43
29
|
export declare class CodeModeFunction {
|
|
44
|
-
readonly parameters: ReadonlyArray<
|
|
45
|
-
readonly body:
|
|
30
|
+
readonly parameters: ReadonlyArray<Pattern>;
|
|
31
|
+
readonly body: BlockStatement | Expression;
|
|
46
32
|
readonly capturedScopes: ReadonlyArray<Map<string, Binding>>;
|
|
47
33
|
readonly async: boolean;
|
|
48
34
|
readonly generator: boolean;
|
|
49
|
-
constructor(parameters: ReadonlyArray<
|
|
35
|
+
constructor(parameters: ReadonlyArray<Pattern>, body: BlockStatement | Expression, capturedScopes: ReadonlyArray<Map<string, Binding>>, async: boolean, generator: boolean);
|
|
50
36
|
}
|
|
51
37
|
export type GeneratorRequestKind = "next" | "return" | "throw";
|
|
52
38
|
export declare class CodeModeGenerator {
|
|
@@ -138,12 +124,6 @@ export declare class InterpreterRuntimeError extends Error {
|
|
|
138
124
|
}
|
|
139
125
|
export declare const unsupportedSyntax: (kind: string, node: AstNode) => InterpreterRuntimeError;
|
|
140
126
|
export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
|
|
141
|
-
export declare const asNode: (value: unknown, context: string) => AstNode;
|
|
142
|
-
export declare const getArray: (node: AstNode, key: string) => Array<unknown>;
|
|
143
|
-
export declare const getString: (node: AstNode, key: string) => string;
|
|
144
|
-
export declare const getBoolean: (node: AstNode, key: string) => boolean;
|
|
145
|
-
export declare const getOptionalNode: (node: AstNode, key: string) => AstNode | undefined;
|
|
146
|
-
export declare const getNode: (node: AstNode, key: string) => AstNode;
|
|
147
127
|
export declare const sourceLocation: (node: AstNode) => {
|
|
148
128
|
readonly line: number;
|
|
149
129
|
readonly column: number;
|
|
@@ -143,37 +143,6 @@ export class InterpreterRuntimeError extends Error {
|
|
|
143
143
|
}
|
|
144
144
|
export const unsupportedSyntax = (kind, node) => new InterpreterRuntimeError(`Syntax '${kind}' is not supported. ${supportedSyntaxMessage}`, node, "UnsupportedSyntax", [supportedSyntaxMessage]);
|
|
145
145
|
export const isRecord = (value) => typeof value === "object" && value !== null;
|
|
146
|
-
export const asNode = (value, context) => {
|
|
147
|
-
if (!isRecord(value) || typeof value.type !== "string") {
|
|
148
|
-
throw new InterpreterRuntimeError(`Invalid AST node while reading ${context}.`);
|
|
149
|
-
}
|
|
150
|
-
return value;
|
|
151
|
-
};
|
|
152
|
-
export const getArray = (node, key) => {
|
|
153
|
-
const value = node[key];
|
|
154
|
-
if (!Array.isArray(value))
|
|
155
|
-
throw new InterpreterRuntimeError(`Expected '${key}' to be an array.`, node);
|
|
156
|
-
return value;
|
|
157
|
-
};
|
|
158
|
-
export const getString = (node, key) => {
|
|
159
|
-
const value = node[key];
|
|
160
|
-
if (typeof value !== "string")
|
|
161
|
-
throw new InterpreterRuntimeError(`Expected '${key}' to be a string.`, node);
|
|
162
|
-
return value;
|
|
163
|
-
};
|
|
164
|
-
export const getBoolean = (node, key) => {
|
|
165
|
-
const value = node[key];
|
|
166
|
-
if (typeof value !== "boolean")
|
|
167
|
-
throw new InterpreterRuntimeError(`Expected '${key}' to be a boolean.`, node);
|
|
168
|
-
return value;
|
|
169
|
-
};
|
|
170
|
-
export const getOptionalNode = (node, key) => {
|
|
171
|
-
const value = node[key];
|
|
172
|
-
if (value === undefined || value === null)
|
|
173
|
-
return undefined;
|
|
174
|
-
return asNode(value, key);
|
|
175
|
-
};
|
|
176
|
-
export const getNode = (node, key) => asNode(node[key], key);
|
|
177
146
|
export const sourceLocation = (node) => ({
|
|
178
147
|
line: Math.max(1, (node.loc?.start.line ?? 2) - 1),
|
|
179
148
|
column: Math.max(1, (node.loc?.start.column ?? 4) - 3),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { Program } from "acorn";
|
|
1
2
|
import { Effect } from "effect";
|
|
2
|
-
import { type ProgramNode } from "./model.js";
|
|
3
3
|
import { PromiseRuntime } from "./promises.js";
|
|
4
4
|
export declare class Interpreter<R> {
|
|
5
5
|
private scopes;
|
|
@@ -12,7 +12,7 @@ export declare class Interpreter<R> {
|
|
|
12
12
|
private generatorAsync;
|
|
13
13
|
private readonly runner;
|
|
14
14
|
constructor(executeTool: (path: ReadonlyArray<string>, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, invokeSearch: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>, promises: PromiseRuntime<R>, logs?: Array<string>);
|
|
15
|
-
run(program:
|
|
15
|
+
run(program: Program): Effect.Effect<unknown, unknown, R>;
|
|
16
16
|
private createToolCallPromise;
|
|
17
17
|
private createPromise;
|
|
18
18
|
private settlePromise;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Cause, Deferred, Effect, Exit } from "effect";
|
|
2
2
|
import { isBlockedMember, ToolRuntimeError, toProgram } from "../data.js";
|
|
3
3
|
import { ToolReference } from "../tool-runtime.js";
|
|
4
|
-
import { AsyncIteratorSymbol,
|
|
4
|
+
import { AsyncIteratorSymbol, CodeModeFunction, CodeModeGenerator, CoercionFunction, ComputedValue, ErrorConstructorReference, GlobalMethodReference, GlobalNamespace, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, isRecord, IteratorSymbol, IteratorSymbols, JsonMethodReference, OptionalShortCircuit, PromiseCapabilityFunction, PromiseInstanceMethodReference, PromiseMethodReference, PromiseNamespace, ProgramThrow, SearchFunction, SymbolNamespace, unsupportedSyntax, UriFunction, } from "./model.js";
|
|
5
5
|
import { caughtErrorValue, constructAggregateErrorValue, constructErrorValue } from "./errors.js";
|
|
6
6
|
import { arrayStatics, invokeArrayFrom, invokeGlobalMethod, invokeGroupBy, invokeIntrinsic, toPrimitive, } from "./methods.js";
|
|
7
7
|
import { preserveConsumerError } from "./iterator.js";
|
|
@@ -40,18 +40,18 @@ const parseArrayIndex = (key) => {
|
|
|
40
40
|
return index < MAX_ARRAY_LENGTH ? index : undefined;
|
|
41
41
|
};
|
|
42
42
|
const calleeDescription = (callee) => {
|
|
43
|
-
if (callee
|
|
44
|
-
return
|
|
45
|
-
if (callee
|
|
46
|
-
const object =
|
|
47
|
-
const property =
|
|
48
|
-
const key = callee.computed
|
|
49
|
-
?
|
|
43
|
+
if (callee?.type === "Identifier")
|
|
44
|
+
return callee.name;
|
|
45
|
+
if (callee?.type === "MemberExpression") {
|
|
46
|
+
const object = callee.object;
|
|
47
|
+
const property = callee.property;
|
|
48
|
+
const key = !callee.computed && property.type === "Identifier"
|
|
49
|
+
? property.name
|
|
50
50
|
: property.type === "Literal" && typeof property.value === "string"
|
|
51
51
|
? property.value
|
|
52
52
|
: undefined;
|
|
53
53
|
if (object.type === "Identifier" && key !== undefined)
|
|
54
|
-
return `${
|
|
54
|
+
return `${object.name}.${key}`;
|
|
55
55
|
}
|
|
56
56
|
return "The called value";
|
|
57
57
|
};
|
|
@@ -90,24 +90,23 @@ const instanceofValue = (lhs, rhs, node) => {
|
|
|
90
90
|
const collectPatternNames = (pattern, out = []) => {
|
|
91
91
|
switch (pattern.type) {
|
|
92
92
|
case "Identifier":
|
|
93
|
-
out.push(
|
|
93
|
+
out.push(pattern.name);
|
|
94
94
|
break;
|
|
95
95
|
case "AssignmentPattern":
|
|
96
|
-
collectPatternNames(
|
|
96
|
+
collectPatternNames(pattern.left, out);
|
|
97
97
|
break;
|
|
98
98
|
case "RestElement":
|
|
99
|
-
collectPatternNames(
|
|
99
|
+
collectPatternNames(pattern.argument, out);
|
|
100
100
|
break;
|
|
101
101
|
case "ArrayPattern":
|
|
102
|
-
for (const element of
|
|
102
|
+
for (const element of pattern.elements) {
|
|
103
103
|
if (element !== null)
|
|
104
|
-
collectPatternNames(
|
|
104
|
+
collectPatternNames(element, out);
|
|
105
105
|
}
|
|
106
106
|
break;
|
|
107
107
|
case "ObjectPattern":
|
|
108
|
-
for (const
|
|
109
|
-
|
|
110
|
-
collectPatternNames(prop.type === "RestElement" ? getNode(prop, "argument") : getNode(prop, "value"), out);
|
|
108
|
+
for (const prop of pattern.properties) {
|
|
109
|
+
collectPatternNames(prop.type === "RestElement" ? prop.argument : prop.value, out);
|
|
111
110
|
}
|
|
112
111
|
break;
|
|
113
112
|
}
|
|
@@ -116,13 +115,13 @@ const collectPatternNames = (pattern, out = []) => {
|
|
|
116
115
|
const loopDeclaration = (left, statement) => {
|
|
117
116
|
if (left.type !== "VariableDeclaration")
|
|
118
117
|
return undefined;
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
118
|
+
const declaration = left.declarations.length === 1 ? left.declarations[0] : undefined;
|
|
119
|
+
if (declaration === undefined) {
|
|
121
120
|
throw new InterpreterRuntimeError(`${statement} supports one declared binding.`, left);
|
|
122
121
|
}
|
|
123
|
-
const kind =
|
|
122
|
+
const kind = left.kind;
|
|
124
123
|
return {
|
|
125
|
-
pattern:
|
|
124
|
+
pattern: declaration.id,
|
|
126
125
|
mutable: kind !== "const",
|
|
127
126
|
lexical: kind !== "var",
|
|
128
127
|
};
|
|
@@ -140,7 +139,7 @@ const copyIteratorSymbols = (source, target, consumed) => {
|
|
|
140
139
|
Reflect.set(target, symbol, Reflect.get(source, symbol));
|
|
141
140
|
}
|
|
142
141
|
};
|
|
143
|
-
const promiseResolutionNode = { type: "PromiseResolution" };
|
|
142
|
+
const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
|
|
144
143
|
export class Interpreter {
|
|
145
144
|
scopes;
|
|
146
145
|
executeTool;
|
|
@@ -207,7 +206,7 @@ export class Interpreter {
|
|
|
207
206
|
let value = undefined;
|
|
208
207
|
for (const [index, statement] of program.body.entries()) {
|
|
209
208
|
if (index === program.body.length - 1 && statement.type === "ExpressionStatement") {
|
|
210
|
-
value = yield* self.evaluateExpression(
|
|
209
|
+
value = yield* self.evaluateExpression(statement.expression);
|
|
211
210
|
break;
|
|
212
211
|
}
|
|
213
212
|
const result = yield* self.evaluateStatement(statement);
|
|
@@ -242,11 +241,11 @@ export class Interpreter {
|
|
|
242
241
|
evaluateStatement(node) {
|
|
243
242
|
switch (node.type) {
|
|
244
243
|
case "ExpressionStatement":
|
|
245
|
-
return Effect.as(this.evaluateExpression(
|
|
244
|
+
return Effect.as(this.evaluateExpression(node.expression), { kind: "none" });
|
|
246
245
|
case "VariableDeclaration":
|
|
247
246
|
return Effect.map(this.evaluateVariableDeclaration(node), () => ({ kind: "none" }));
|
|
248
247
|
case "ReturnStatement": {
|
|
249
|
-
const argumentNode =
|
|
248
|
+
const argumentNode = node.argument;
|
|
250
249
|
return argumentNode
|
|
251
250
|
? Effect.map(this.evaluateExpression(argumentNode), (value) => ({ kind: "return", value }))
|
|
252
251
|
: Effect.succeed({ kind: "return", value: undefined });
|
|
@@ -289,11 +288,10 @@ export class Interpreter {
|
|
|
289
288
|
this.scopes.push();
|
|
290
289
|
const self = this;
|
|
291
290
|
return Effect.gen(function* () {
|
|
292
|
-
const body =
|
|
291
|
+
const body = node.body;
|
|
293
292
|
self.predeclareLexical(body);
|
|
294
293
|
self.hoistFunctions(body);
|
|
295
|
-
for (const
|
|
296
|
-
const statement = asNode(statementValue, "body");
|
|
294
|
+
for (const statement of body) {
|
|
297
295
|
const result = yield* self.evaluateStatement(statement);
|
|
298
296
|
if (result.kind !== "none") {
|
|
299
297
|
return result;
|
|
@@ -303,27 +301,24 @@ export class Interpreter {
|
|
|
303
301
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
304
302
|
}
|
|
305
303
|
createFunction(node) {
|
|
306
|
-
return new CodeModeFunction(
|
|
304
|
+
return new CodeModeFunction(node.params, node.body, this.scopes.capture(), node.async, node.generator);
|
|
307
305
|
}
|
|
308
306
|
hoistFunctions(statements) {
|
|
309
|
-
for (const
|
|
310
|
-
if (
|
|
307
|
+
for (const node of statements) {
|
|
308
|
+
if (node.type !== "FunctionDeclaration")
|
|
311
309
|
continue;
|
|
312
|
-
|
|
313
|
-
this.scopes.declare(getString(getNode(node, "id"), "name"), this.createFunction(node), true, node);
|
|
310
|
+
this.scopes.declare(node.id.name, this.createFunction(node), true, node);
|
|
314
311
|
}
|
|
315
312
|
}
|
|
316
313
|
predeclareLexical(statements) {
|
|
317
|
-
for (const
|
|
318
|
-
if (
|
|
314
|
+
for (const statement of statements) {
|
|
315
|
+
if (statement.type !== "VariableDeclaration")
|
|
319
316
|
continue;
|
|
320
|
-
const
|
|
321
|
-
const kind = getString(statement, "kind");
|
|
317
|
+
const kind = statement.kind;
|
|
322
318
|
if (kind === "var")
|
|
323
319
|
continue;
|
|
324
|
-
for (const
|
|
325
|
-
const
|
|
326
|
-
for (const name of collectPatternNames(getNode(declaration, "id"))) {
|
|
320
|
+
for (const declaration of statement.declarations) {
|
|
321
|
+
for (const name of collectPatternNames(declaration.id)) {
|
|
327
322
|
this.scopes.reserve(name, kind !== "const", declaration);
|
|
328
323
|
}
|
|
329
324
|
}
|
|
@@ -334,30 +329,27 @@ export class Interpreter {
|
|
|
334
329
|
this.scopes.reserve(name, mutable, node);
|
|
335
330
|
}
|
|
336
331
|
evaluateIfStatement(node) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
? this.evaluateStatement(consequentNode)
|
|
342
|
-
: alternateNode
|
|
343
|
-
? this.evaluateStatement(alternateNode)
|
|
332
|
+
return Effect.flatMap(this.evaluateExpression(node.test), (test) => test
|
|
333
|
+
? this.evaluateStatement(node.consequent)
|
|
334
|
+
: node.alternate
|
|
335
|
+
? this.evaluateStatement(node.alternate)
|
|
344
336
|
: Effect.succeed({ kind: "none" }));
|
|
345
337
|
}
|
|
346
338
|
evaluateSwitchStatement(node) {
|
|
347
339
|
const self = this;
|
|
348
340
|
return Effect.gen(function* () {
|
|
349
|
-
const discriminant = yield* self.evaluateExpression(
|
|
341
|
+
const discriminant = yield* self.evaluateExpression(node.discriminant);
|
|
350
342
|
if (containsOpaqueReference(discriminant)) {
|
|
351
343
|
throw new InterpreterRuntimeError("Switch discriminants must be data values.", node, "InvalidDataValue");
|
|
352
344
|
}
|
|
353
345
|
self.scopes.push();
|
|
354
346
|
return yield* Effect.gen(function* () {
|
|
355
|
-
const cases =
|
|
356
|
-
self.predeclareLexical(cases.flatMap((branch) =>
|
|
347
|
+
const cases = node.cases;
|
|
348
|
+
self.predeclareLexical(cases.flatMap((branch) => branch.consequent));
|
|
357
349
|
let defaultIndex;
|
|
358
350
|
let selected;
|
|
359
351
|
for (const [index, branch] of cases.entries()) {
|
|
360
|
-
const test =
|
|
352
|
+
const test = branch.test;
|
|
361
353
|
if (!test) {
|
|
362
354
|
defaultIndex = index;
|
|
363
355
|
continue;
|
|
@@ -375,8 +367,8 @@ export class Interpreter {
|
|
|
375
367
|
if (start === undefined)
|
|
376
368
|
return { kind: "none" };
|
|
377
369
|
for (let index = start; index < cases.length; index += 1) {
|
|
378
|
-
for (const
|
|
379
|
-
const result = yield* self.evaluateStatement(
|
|
370
|
+
for (const statement of cases[index].consequent) {
|
|
371
|
+
const result = yield* self.evaluateStatement(statement);
|
|
380
372
|
if (result.kind === "break") {
|
|
381
373
|
if (result.label === undefined)
|
|
382
374
|
return { kind: "none" };
|
|
@@ -391,12 +383,10 @@ export class Interpreter {
|
|
|
391
383
|
});
|
|
392
384
|
}
|
|
393
385
|
evaluateWhileStatement(node, labels) {
|
|
394
|
-
const testNode = getNode(node, "test");
|
|
395
|
-
const bodyNode = getNode(node, "body");
|
|
396
386
|
const self = this;
|
|
397
387
|
return Effect.gen(function* () {
|
|
398
|
-
while (yield* self.evaluateExpression(
|
|
399
|
-
const result = yield* self.evaluateStatement(
|
|
388
|
+
while (yield* self.evaluateExpression(node.test)) {
|
|
389
|
+
const result = yield* self.evaluateStatement(node.body);
|
|
400
390
|
if (result.kind === "continue") {
|
|
401
391
|
if (result.label !== undefined && !labels?.has(result.label))
|
|
402
392
|
return result;
|
|
@@ -415,12 +405,10 @@ export class Interpreter {
|
|
|
415
405
|
});
|
|
416
406
|
}
|
|
417
407
|
evaluateDoWhileStatement(node, labels) {
|
|
418
|
-
const bodyNode = getNode(node, "body");
|
|
419
|
-
const testNode = getNode(node, "test");
|
|
420
408
|
const self = this;
|
|
421
409
|
return Effect.gen(function* () {
|
|
422
410
|
do {
|
|
423
|
-
const result = yield* self.evaluateStatement(
|
|
411
|
+
const result = yield* self.evaluateStatement(node.body);
|
|
424
412
|
if (result.kind === "continue") {
|
|
425
413
|
if (result.label !== undefined && !labels?.has(result.label))
|
|
426
414
|
return result;
|
|
@@ -434,7 +422,7 @@ export class Interpreter {
|
|
|
434
422
|
if (result.kind === "return") {
|
|
435
423
|
return result;
|
|
436
424
|
}
|
|
437
|
-
} while (yield* self.evaluateExpression(
|
|
425
|
+
} while (yield* self.evaluateExpression(node.test));
|
|
438
426
|
return { kind: "none" };
|
|
439
427
|
});
|
|
440
428
|
}
|
|
@@ -442,11 +430,10 @@ export class Interpreter {
|
|
|
442
430
|
this.scopes.push();
|
|
443
431
|
const self = this;
|
|
444
432
|
return Effect.gen(function* () {
|
|
445
|
-
const initNode =
|
|
446
|
-
const testNode =
|
|
447
|
-
const updateNode =
|
|
448
|
-
|
|
449
|
-
if (initNode?.type === "VariableDeclaration" && getString(initNode, "kind") !== "var") {
|
|
433
|
+
const initNode = node.init;
|
|
434
|
+
const testNode = node.test;
|
|
435
|
+
const updateNode = node.update;
|
|
436
|
+
if (initNode?.type === "VariableDeclaration" && initNode.kind !== "var") {
|
|
450
437
|
self.predeclareLexical([initNode]);
|
|
451
438
|
}
|
|
452
439
|
if (initNode) {
|
|
@@ -457,7 +444,7 @@ export class Interpreter {
|
|
|
457
444
|
yield* self.evaluateExpression(initNode);
|
|
458
445
|
}
|
|
459
446
|
}
|
|
460
|
-
const perIterationBindings = initNode?.type === "VariableDeclaration" &&
|
|
447
|
+
const perIterationBindings = initNode?.type === "VariableDeclaration" && initNode.kind !== "var"
|
|
461
448
|
? Array.from(self.scopes.current().keys())
|
|
462
449
|
: [];
|
|
463
450
|
const nextIteration = () => {
|
|
@@ -469,7 +456,7 @@ export class Interpreter {
|
|
|
469
456
|
};
|
|
470
457
|
nextIteration();
|
|
471
458
|
while (testNode ? yield* self.evaluateExpression(testNode) : true) {
|
|
472
|
-
const result = yield* self.evaluateStatement(
|
|
459
|
+
const result = yield* self.evaluateStatement(node.body);
|
|
473
460
|
if (result.kind === "return") {
|
|
474
461
|
return result;
|
|
475
462
|
}
|
|
@@ -492,8 +479,8 @@ export class Interpreter {
|
|
|
492
479
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
493
480
|
}
|
|
494
481
|
evaluateForOfStatement(node, labels) {
|
|
495
|
-
const awaiting =
|
|
496
|
-
const left =
|
|
482
|
+
const awaiting = node.await;
|
|
483
|
+
const left = node.left;
|
|
497
484
|
const declared = loopDeclaration(left, "for...of");
|
|
498
485
|
if (declared?.lexical)
|
|
499
486
|
this.scopes.push();
|
|
@@ -501,8 +488,7 @@ export class Interpreter {
|
|
|
501
488
|
return Effect.gen(function* () {
|
|
502
489
|
if (declared?.lexical)
|
|
503
490
|
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
504
|
-
const right = yield* self.evaluateExpression(
|
|
505
|
-
const body = getNode(node, "body");
|
|
491
|
+
const right = yield* self.evaluateExpression(node.right);
|
|
506
492
|
const iterator = yield* self.customIterator(right, node, awaiting);
|
|
507
493
|
const cursor = iterator === undefined ? yield* self.syncIterator(right, node) : undefined;
|
|
508
494
|
if (iterator === undefined && cursor === undefined) {
|
|
@@ -513,17 +499,10 @@ export class Interpreter {
|
|
|
513
499
|
: awaiting
|
|
514
500
|
? Effect.andThen(cursor?.close ?? Effect.void, Effect.yieldNow)
|
|
515
501
|
: (cursor?.close ?? Effect.void);
|
|
516
|
-
|
|
517
|
-
if (left.type !== "VariableDeclaration" &&
|
|
518
|
-
(left.type === "Identifier" ||
|
|
519
|
-
left.type === "MemberExpression" ||
|
|
520
|
-
left.type === "ArrayPattern" ||
|
|
521
|
-
left.type === "ObjectPattern")) {
|
|
522
|
-
assignment = left;
|
|
523
|
-
}
|
|
524
|
-
else if (left.type !== "VariableDeclaration") {
|
|
502
|
+
if (left.type === "RestElement" || left.type === "AssignmentPattern") {
|
|
525
503
|
throw new InterpreterRuntimeError("Unsupported for...of binding.", left);
|
|
526
504
|
}
|
|
505
|
+
const assignment = left.type === "VariableDeclaration" ? undefined : left;
|
|
527
506
|
const evaluateBody = (value) => Effect.gen(function* () {
|
|
528
507
|
if (declared) {
|
|
529
508
|
self.scopes.push();
|
|
@@ -534,7 +513,7 @@ export class Interpreter {
|
|
|
534
513
|
else if (assignment) {
|
|
535
514
|
yield* self.assignPattern(assignment, value, left);
|
|
536
515
|
}
|
|
537
|
-
return yield* self.evaluateStatement(body);
|
|
516
|
+
return yield* self.evaluateStatement(node.body);
|
|
538
517
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
539
518
|
if (declared)
|
|
540
519
|
self.scopes.pop();
|
|
@@ -734,7 +713,7 @@ export class Interpreter {
|
|
|
734
713
|
return undefined;
|
|
735
714
|
}
|
|
736
715
|
evaluateForInStatement(node, labels) {
|
|
737
|
-
const left =
|
|
716
|
+
const left = node.left;
|
|
738
717
|
const declared = loopDeclaration(left, "for...in");
|
|
739
718
|
if (declared?.lexical)
|
|
740
719
|
this.scopes.push();
|
|
@@ -742,19 +721,15 @@ export class Interpreter {
|
|
|
742
721
|
return Effect.gen(function* () {
|
|
743
722
|
if (declared?.lexical)
|
|
744
723
|
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
745
|
-
const right = yield* self.evaluateExpression(
|
|
746
|
-
const body = getNode(node, "body");
|
|
724
|
+
const right = yield* self.evaluateExpression(node.right);
|
|
747
725
|
const keys = self.enumerableKeys(right);
|
|
748
726
|
if (keys === undefined) {
|
|
749
727
|
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);
|
|
750
728
|
}
|
|
751
|
-
|
|
752
|
-
if (left.type === "Identifier") {
|
|
753
|
-
assignmentName = getString(left, "name");
|
|
754
|
-
}
|
|
755
|
-
else if (left.type !== "VariableDeclaration") {
|
|
729
|
+
if (left.type !== "Identifier" && left.type !== "VariableDeclaration") {
|
|
756
730
|
throw new InterpreterRuntimeError("Unsupported for...in binding.", left);
|
|
757
731
|
}
|
|
732
|
+
const assignmentName = left.type === "Identifier" ? left.name : undefined;
|
|
758
733
|
for (const key of keys) {
|
|
759
734
|
const result = yield* Effect.gen(function* () {
|
|
760
735
|
if (declared) {
|
|
@@ -766,7 +741,7 @@ export class Interpreter {
|
|
|
766
741
|
else if (assignmentName) {
|
|
767
742
|
self.scopes.set(assignmentName, key, left);
|
|
768
743
|
}
|
|
769
|
-
return yield* self.evaluateStatement(body);
|
|
744
|
+
return yield* self.evaluateStatement(node.body);
|
|
770
745
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
771
746
|
if (declared)
|
|
772
747
|
self.scopes.pop();
|
|
@@ -792,19 +767,17 @@ export class Interpreter {
|
|
|
792
767
|
})));
|
|
793
768
|
}
|
|
794
769
|
evaluateBreakStatement(node) {
|
|
795
|
-
|
|
796
|
-
return labelNode ? { kind: "break", label: getString(labelNode, "name") } : { kind: "break" };
|
|
770
|
+
return node.label ? { kind: "break", label: node.label.name } : { kind: "break" };
|
|
797
771
|
}
|
|
798
772
|
evaluateContinueStatement(node) {
|
|
799
|
-
|
|
800
|
-
return labelNode ? { kind: "continue", label: getString(labelNode, "name") } : { kind: "continue" };
|
|
773
|
+
return node.label ? { kind: "continue", label: node.label.name } : { kind: "continue" };
|
|
801
774
|
}
|
|
802
775
|
evaluateLabeledStatement(node) {
|
|
803
776
|
const labels = new Set();
|
|
804
777
|
let body = node;
|
|
805
778
|
while (body.type === "LabeledStatement") {
|
|
806
|
-
labels.add(
|
|
807
|
-
body =
|
|
779
|
+
labels.add(body.label.name);
|
|
780
|
+
body = body.body;
|
|
808
781
|
}
|
|
809
782
|
const evaluated = (() => {
|
|
810
783
|
if (body.type === "WhileStatement")
|
|
@@ -824,13 +797,12 @@ export class Interpreter {
|
|
|
824
797
|
: result);
|
|
825
798
|
}
|
|
826
799
|
evaluateThrowStatement(node) {
|
|
827
|
-
|
|
828
|
-
return Effect.flatMap(this.evaluateExpression(argument), (value) => Effect.fail(new ProgramThrow(value)));
|
|
800
|
+
return Effect.flatMap(this.evaluateExpression(node.argument), (value) => Effect.fail(new ProgramThrow(value)));
|
|
829
801
|
}
|
|
830
802
|
evaluateTryStatement(node) {
|
|
831
|
-
const body =
|
|
832
|
-
const handler =
|
|
833
|
-
const finalizer =
|
|
803
|
+
const body = node.block;
|
|
804
|
+
const handler = node.handler;
|
|
805
|
+
const finalizer = node.finalizer;
|
|
834
806
|
const self = this;
|
|
835
807
|
const attempted = Effect.matchCauseEffect(this.evaluateStatement(body), {
|
|
836
808
|
onFailure: (cause) => {
|
|
@@ -838,12 +810,12 @@ export class Interpreter {
|
|
|
838
810
|
return Effect.failCause(cause);
|
|
839
811
|
}
|
|
840
812
|
const caught = caughtErrorValue(Cause.squash(cause));
|
|
841
|
-
const parameter =
|
|
813
|
+
const parameter = handler.param;
|
|
842
814
|
self.scopes.push();
|
|
843
815
|
return Effect.gen(function* () {
|
|
844
816
|
if (parameter)
|
|
845
817
|
yield* self.declarePattern(parameter, caught, true, handler);
|
|
846
|
-
return yield* self.evaluateStatement(
|
|
818
|
+
return yield* self.evaluateStatement(handler.body);
|
|
847
819
|
}).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
|
|
848
820
|
},
|
|
849
821
|
onSuccess: Effect.succeed,
|
|
@@ -859,18 +831,16 @@ export class Interpreter {
|
|
|
859
831
|
});
|
|
860
832
|
}
|
|
861
833
|
evaluateVariableDeclaration(node) {
|
|
862
|
-
const kind =
|
|
863
|
-
const declarations = getArray(node, "declarations");
|
|
834
|
+
const kind = node.kind;
|
|
864
835
|
const self = this;
|
|
865
836
|
return Effect.gen(function* () {
|
|
866
|
-
for (const
|
|
867
|
-
const declaration = asNode(declarationValue, "declarations");
|
|
837
|
+
for (const declaration of node.declarations) {
|
|
868
838
|
if (declaration.type !== "VariableDeclarator") {
|
|
869
839
|
throw new InterpreterRuntimeError("Unsupported variable declaration shape.", declaration);
|
|
870
840
|
}
|
|
871
|
-
const init =
|
|
841
|
+
const init = declaration.init;
|
|
872
842
|
const value = init ? yield* self.evaluateExpression(init) : undefined;
|
|
873
|
-
yield* self.declarePattern(
|
|
843
|
+
yield* self.declarePattern(declaration.id, value, kind !== "const", declaration, kind !== "var");
|
|
874
844
|
}
|
|
875
845
|
});
|
|
876
846
|
}
|
|
@@ -878,7 +848,7 @@ export class Interpreter {
|
|
|
878
848
|
const self = this;
|
|
879
849
|
return Effect.gen(function* () {
|
|
880
850
|
if (pattern.type === "Identifier") {
|
|
881
|
-
const name =
|
|
851
|
+
const name = pattern.name;
|
|
882
852
|
if (initialize)
|
|
883
853
|
self.scopes.initialize(name, value, node);
|
|
884
854
|
else
|
|
@@ -886,8 +856,8 @@ export class Interpreter {
|
|
|
886
856
|
return;
|
|
887
857
|
}
|
|
888
858
|
if (pattern.type === "AssignmentPattern") {
|
|
889
|
-
const resolved = value === undefined ? yield* self.evaluateExpression(
|
|
890
|
-
yield* self.declarePattern(
|
|
859
|
+
const resolved = value === undefined ? yield* self.evaluateExpression(pattern.right) : value;
|
|
860
|
+
yield* self.declarePattern(pattern.left, resolved, mutable, node, initialize);
|
|
891
861
|
return;
|
|
892
862
|
}
|
|
893
863
|
if (pattern.type === "ObjectPattern") {
|
|
@@ -895,8 +865,7 @@ export class Interpreter {
|
|
|
895
865
|
throw new InterpreterRuntimeError("Object destructuring requires a data object or array value.", pattern, "InvalidDataValue");
|
|
896
866
|
}
|
|
897
867
|
const consumed = new Set();
|
|
898
|
-
for (const
|
|
899
|
-
const property = asNode(propertyValue, "properties");
|
|
868
|
+
for (const property of pattern.properties) {
|
|
900
869
|
if (property.type === "RestElement") {
|
|
901
870
|
const rest = Object.create(null);
|
|
902
871
|
for (const [key, item] of Object.entries(value)) {
|
|
@@ -904,7 +873,7 @@ export class Interpreter {
|
|
|
904
873
|
rest[key] = item;
|
|
905
874
|
}
|
|
906
875
|
copyIteratorSymbols(value, rest, consumed);
|
|
907
|
-
yield* self.declarePattern(
|
|
876
|
+
yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
|
|
908
877
|
continue;
|
|
909
878
|
}
|
|
910
879
|
const key = yield* self.destructuringPropertyKey(property);
|
|
@@ -912,7 +881,7 @@ export class Interpreter {
|
|
|
912
881
|
throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, property);
|
|
913
882
|
}
|
|
914
883
|
consumed.add(typeof key === "symbol" ? key : String(key));
|
|
915
|
-
yield* self.declarePattern(
|
|
884
|
+
yield* self.declarePattern(property.value, self.destructuringPropertyValue(value, key), mutable, property, initialize);
|
|
916
885
|
}
|
|
917
886
|
return;
|
|
918
887
|
}
|
|
@@ -926,7 +895,7 @@ export class Interpreter {
|
|
|
926
895
|
const self = this;
|
|
927
896
|
return Effect.gen(function* () {
|
|
928
897
|
if (pattern.type === "Identifier") {
|
|
929
|
-
self.scopes.set(
|
|
898
|
+
self.scopes.set(pattern.name, value, pattern);
|
|
930
899
|
return;
|
|
931
900
|
}
|
|
932
901
|
if (pattern.type === "MemberExpression") {
|
|
@@ -934,8 +903,8 @@ export class Interpreter {
|
|
|
934
903
|
return;
|
|
935
904
|
}
|
|
936
905
|
if (pattern.type === "AssignmentPattern") {
|
|
937
|
-
const resolved = value === undefined ? yield* self.evaluateExpression(
|
|
938
|
-
yield* self.assignPattern(
|
|
906
|
+
const resolved = value === undefined ? yield* self.evaluateExpression(pattern.right) : value;
|
|
907
|
+
yield* self.assignPattern(pattern.left, resolved, node);
|
|
939
908
|
return;
|
|
940
909
|
}
|
|
941
910
|
if (pattern.type === "ObjectPattern") {
|
|
@@ -944,8 +913,7 @@ export class Interpreter {
|
|
|
944
913
|
}
|
|
945
914
|
const source = value;
|
|
946
915
|
const consumed = new Set();
|
|
947
|
-
for (const
|
|
948
|
-
const property = asNode(propertyValue, "properties");
|
|
916
|
+
for (const property of pattern.properties) {
|
|
949
917
|
if (property.type === "RestElement") {
|
|
950
918
|
const rest = Object.create(null);
|
|
951
919
|
for (const [key, item] of Object.entries(source)) {
|
|
@@ -953,7 +921,7 @@ export class Interpreter {
|
|
|
953
921
|
rest[key] = item;
|
|
954
922
|
}
|
|
955
923
|
copyIteratorSymbols(source, rest, consumed);
|
|
956
|
-
yield* self.assignPattern(
|
|
924
|
+
yield* self.assignPattern(property.argument, rest, property);
|
|
957
925
|
continue;
|
|
958
926
|
}
|
|
959
927
|
const key = yield* self.destructuringPropertyKey(property);
|
|
@@ -961,7 +929,7 @@ export class Interpreter {
|
|
|
961
929
|
throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, property);
|
|
962
930
|
}
|
|
963
931
|
consumed.add(typeof key === "symbol" ? key : String(key));
|
|
964
|
-
yield* self.assignPattern(
|
|
932
|
+
yield* self.assignPattern(property.value, self.destructuringPropertyValue(source, key), property);
|
|
965
933
|
}
|
|
966
934
|
return;
|
|
967
935
|
}
|
|
@@ -979,21 +947,19 @@ export class Interpreter {
|
|
|
979
947
|
throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern).as("TypeError");
|
|
980
948
|
}
|
|
981
949
|
let done = false;
|
|
982
|
-
for (const
|
|
950
|
+
for (const element of pattern.elements) {
|
|
983
951
|
if (done) {
|
|
984
|
-
if (
|
|
952
|
+
if (element === null)
|
|
985
953
|
continue;
|
|
986
|
-
|
|
987
|
-
yield* consume(element.type === "RestElement" ? getNode(element, "argument") : element, element.type === "RestElement" ? [] : undefined, element);
|
|
954
|
+
yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? [] : undefined, element);
|
|
988
955
|
if (element.type === "RestElement")
|
|
989
956
|
return;
|
|
990
957
|
continue;
|
|
991
958
|
}
|
|
992
959
|
const step = yield* cursor.next;
|
|
993
960
|
done = step.done;
|
|
994
|
-
if (
|
|
961
|
+
if (element === null)
|
|
995
962
|
continue;
|
|
996
|
-
const element = asNode(item, `elements[${index}]`);
|
|
997
963
|
if (element.type === "RestElement") {
|
|
998
964
|
const rest = [];
|
|
999
965
|
if (!step.done)
|
|
@@ -1004,7 +970,7 @@ export class Interpreter {
|
|
|
1004
970
|
if (!done)
|
|
1005
971
|
rest.push(next.value);
|
|
1006
972
|
}
|
|
1007
|
-
yield* consume(
|
|
973
|
+
yield* consume(element.argument, rest, element);
|
|
1008
974
|
return;
|
|
1009
975
|
}
|
|
1010
976
|
const consumed = consume(element, step.done ? undefined : step.value, pattern);
|
|
@@ -1015,14 +981,18 @@ export class Interpreter {
|
|
|
1015
981
|
});
|
|
1016
982
|
}
|
|
1017
983
|
destructuringPropertyKey(property) {
|
|
1018
|
-
if (property.type !== "Property" ||
|
|
984
|
+
if (property.type !== "Property" || property.kind !== "init") {
|
|
1019
985
|
throw new InterpreterRuntimeError("Unsupported object destructuring property.", property);
|
|
1020
986
|
}
|
|
1021
|
-
const keyNode =
|
|
1022
|
-
if (
|
|
987
|
+
const keyNode = property.key;
|
|
988
|
+
if (property.computed) {
|
|
1023
989
|
return Effect.map(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value, keyNode));
|
|
1024
990
|
}
|
|
1025
|
-
|
|
991
|
+
if (keyNode.type === "Identifier")
|
|
992
|
+
return Effect.succeed(keyNode.name);
|
|
993
|
+
if (keyNode.type === "Literal")
|
|
994
|
+
return Effect.succeed(String(keyNode.value));
|
|
995
|
+
throw unsupportedSyntax(keyNode.type, keyNode);
|
|
1026
996
|
}
|
|
1027
997
|
destructuringPropertyValue(source, key) {
|
|
1028
998
|
if (!Array.isArray(source))
|
|
@@ -1041,13 +1011,12 @@ export class Interpreter {
|
|
|
1041
1011
|
switch (node.type) {
|
|
1042
1012
|
case "Literal": {
|
|
1043
1013
|
const regex = node.regex;
|
|
1044
|
-
if (
|
|
1045
|
-
return Effect.sync(() => this.constructRegExp([regex.pattern,
|
|
1046
|
-
}
|
|
1014
|
+
if (regex)
|
|
1015
|
+
return Effect.sync(() => this.constructRegExp([regex.pattern, regex.flags], node));
|
|
1047
1016
|
return Effect.sync(() => toProgram(node.value, "Literal"));
|
|
1048
1017
|
}
|
|
1049
1018
|
case "Identifier":
|
|
1050
|
-
return Effect.sync(() => this.scopes.get(
|
|
1019
|
+
return Effect.sync(() => this.scopes.get(node.name, node));
|
|
1051
1020
|
case "BinaryExpression":
|
|
1052
1021
|
return this.evaluateBinaryExpression(node);
|
|
1053
1022
|
case "LogicalExpression":
|
|
@@ -1060,8 +1029,8 @@ export class Interpreter {
|
|
|
1060
1029
|
const self = this;
|
|
1061
1030
|
return Effect.gen(function* () {
|
|
1062
1031
|
let result;
|
|
1063
|
-
for (const expression of
|
|
1064
|
-
result = yield* self.evaluateExpression(
|
|
1032
|
+
for (const expression of node.expressions) {
|
|
1033
|
+
result = yield* self.evaluateExpression(expression);
|
|
1065
1034
|
}
|
|
1066
1035
|
return result;
|
|
1067
1036
|
});
|
|
@@ -1074,7 +1043,7 @@ export class Interpreter {
|
|
|
1074
1043
|
case "MemberExpression":
|
|
1075
1044
|
return this.readMember(node);
|
|
1076
1045
|
case "ChainExpression":
|
|
1077
|
-
return Effect.map(this.evaluateExpression(
|
|
1046
|
+
return Effect.map(this.evaluateExpression(node.expression), (value) => value === OptionalShortCircuit ? undefined : value);
|
|
1078
1047
|
case "ObjectExpression":
|
|
1079
1048
|
return this.evaluateObjectExpression(node);
|
|
1080
1049
|
case "ArrayExpression":
|
|
@@ -1087,7 +1056,7 @@ export class Interpreter {
|
|
|
1087
1056
|
return this.evaluateUpdateExpression(node);
|
|
1088
1057
|
case "AwaitExpression": {
|
|
1089
1058
|
// Await always suspends, including for plain values.
|
|
1090
|
-
return Effect.flatMap(this.evaluateExpression(
|
|
1059
|
+
return Effect.flatMap(this.evaluateExpression(node.argument), (value) => this.awaitValue(value, node));
|
|
1091
1060
|
}
|
|
1092
1061
|
case "YieldExpression":
|
|
1093
1062
|
return this.evaluateYieldExpression(node);
|
|
@@ -1098,12 +1067,12 @@ export class Interpreter {
|
|
|
1098
1067
|
}
|
|
1099
1068
|
}
|
|
1100
1069
|
evaluateNewExpression(node) {
|
|
1101
|
-
const callee =
|
|
1070
|
+
const callee = node.callee;
|
|
1102
1071
|
if (callee.type !== "Identifier") {
|
|
1103
1072
|
throw unsupportedSyntax("NewExpression", node);
|
|
1104
1073
|
}
|
|
1105
|
-
const name =
|
|
1106
|
-
const argNodes =
|
|
1074
|
+
const name = callee.name;
|
|
1075
|
+
const argNodes = node.arguments;
|
|
1107
1076
|
const self = this;
|
|
1108
1077
|
if (name === "Promise") {
|
|
1109
1078
|
return Effect.flatMap(this.evaluateCallArguments(argNodes), (args) => constructPromise(self.runner, self.promises, args[0], node));
|
|
@@ -1303,11 +1272,14 @@ export class Interpreter {
|
|
|
1303
1272
|
});
|
|
1304
1273
|
}
|
|
1305
1274
|
evaluateBinaryExpression(node) {
|
|
1306
|
-
const operator =
|
|
1275
|
+
const operator = node.operator;
|
|
1276
|
+
const left = node.left;
|
|
1277
|
+
if (left.type === "PrivateIdentifier")
|
|
1278
|
+
throw unsupportedSyntax(left.type, left);
|
|
1307
1279
|
const self = this;
|
|
1308
1280
|
return Effect.gen(function* () {
|
|
1309
|
-
const lhs = yield* self.evaluateExpression(
|
|
1310
|
-
const rhs = yield* self.evaluateExpression(
|
|
1281
|
+
const lhs = yield* self.evaluateExpression(left);
|
|
1282
|
+
const rhs = yield* self.evaluateExpression(node.right);
|
|
1311
1283
|
if (operator === "instanceof")
|
|
1312
1284
|
return instanceofValue(lhs, rhs, node);
|
|
1313
1285
|
return toProgram(self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
|
|
@@ -1380,26 +1352,24 @@ export class Interpreter {
|
|
|
1380
1352
|
}
|
|
1381
1353
|
}
|
|
1382
1354
|
evaluateLogicalExpression(node) {
|
|
1383
|
-
const operator =
|
|
1384
|
-
return Effect.flatMap(this.evaluateExpression(
|
|
1355
|
+
const operator = node.operator;
|
|
1356
|
+
return Effect.flatMap(this.evaluateExpression(node.left), (left) => {
|
|
1385
1357
|
if (operator === "&&")
|
|
1386
|
-
return left ? this.evaluateExpression(
|
|
1358
|
+
return left ? this.evaluateExpression(node.right) : Effect.succeed(left);
|
|
1387
1359
|
if (operator === "||")
|
|
1388
|
-
return left ? Effect.succeed(left) : this.evaluateExpression(
|
|
1360
|
+
return left ? Effect.succeed(left) : this.evaluateExpression(node.right);
|
|
1389
1361
|
if (operator === "??")
|
|
1390
|
-
return left !== null && left !== undefined
|
|
1391
|
-
? Effect.succeed(left)
|
|
1392
|
-
: this.evaluateExpression(getNode(node, "right"));
|
|
1362
|
+
return left !== null && left !== undefined ? Effect.succeed(left) : this.evaluateExpression(node.right);
|
|
1393
1363
|
throw new InterpreterRuntimeError(`Unsupported logical operator '${operator}'.`, node);
|
|
1394
1364
|
});
|
|
1395
1365
|
}
|
|
1396
1366
|
evaluateUnaryExpression(node) {
|
|
1397
|
-
const operator =
|
|
1398
|
-
const argument =
|
|
1367
|
+
const operator = node.operator;
|
|
1368
|
+
const argument = node.argument;
|
|
1399
1369
|
if (operator === "delete")
|
|
1400
1370
|
return this.evaluateDeleteExpression(argument);
|
|
1401
1371
|
// Undeclared names short-circuit, but declared TDZ bindings must still throw.
|
|
1402
|
-
if (operator === "typeof" && argument.type === "Identifier" && !this.scopes.resolve(
|
|
1372
|
+
if (operator === "typeof" && argument.type === "Identifier" && !this.scopes.resolve(argument.name)) {
|
|
1403
1373
|
return Effect.succeed("undefined");
|
|
1404
1374
|
}
|
|
1405
1375
|
return Effect.map(this.evaluateExpression(argument), (value) => {
|
|
@@ -1435,31 +1405,31 @@ export class Interpreter {
|
|
|
1435
1405
|
});
|
|
1436
1406
|
}
|
|
1437
1407
|
evaluateAssignmentExpression(node) {
|
|
1438
|
-
const left =
|
|
1439
|
-
const operator =
|
|
1408
|
+
const left = node.left;
|
|
1409
|
+
const operator = node.operator;
|
|
1440
1410
|
const self = this;
|
|
1441
1411
|
return Effect.gen(function* () {
|
|
1442
1412
|
if (operator === "??=" || operator === "||=" || operator === "&&=") {
|
|
1443
1413
|
return yield* self.evaluateLogicalAssignment(node, left, operator);
|
|
1444
1414
|
}
|
|
1445
1415
|
if (operator === "=" && (left.type === "ObjectPattern" || left.type === "ArrayPattern")) {
|
|
1446
|
-
const rightValue = yield* self.evaluateExpression(
|
|
1416
|
+
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1447
1417
|
yield* self.assignPattern(left, rightValue, node);
|
|
1448
1418
|
return rightValue;
|
|
1449
1419
|
}
|
|
1450
1420
|
if (left.type === "Identifier") {
|
|
1451
|
-
const name =
|
|
1421
|
+
const name = left.name;
|
|
1452
1422
|
if (operator !== "=") {
|
|
1453
1423
|
const current = self.scopes.get(name, left);
|
|
1454
|
-
const rightValue = yield* self.evaluateExpression(
|
|
1424
|
+
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1455
1425
|
const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
|
|
1456
1426
|
return self.scopes.set(name, next, left);
|
|
1457
1427
|
}
|
|
1458
|
-
const rightValue = yield* self.evaluateExpression(
|
|
1428
|
+
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1459
1429
|
return self.scopes.set(name, rightValue, left);
|
|
1460
1430
|
}
|
|
1461
1431
|
if (left.type === "MemberExpression") {
|
|
1462
|
-
return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(
|
|
1432
|
+
return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(node.right), (rightValue) => {
|
|
1463
1433
|
if (operator === "=")
|
|
1464
1434
|
return { write: true, next: rightValue, result: rightValue };
|
|
1465
1435
|
const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
|
|
@@ -1473,18 +1443,18 @@ export class Interpreter {
|
|
|
1473
1443
|
const self = this;
|
|
1474
1444
|
const shouldAssign = (current) => operator === "??=" ? current === null || current === undefined : operator === "||=" ? !current : Boolean(current);
|
|
1475
1445
|
if (left.type === "Identifier") {
|
|
1476
|
-
const name =
|
|
1446
|
+
const name = left.name;
|
|
1477
1447
|
return Effect.gen(function* () {
|
|
1478
1448
|
const current = self.scopes.get(name, left);
|
|
1479
1449
|
if (!shouldAssign(current))
|
|
1480
1450
|
return current;
|
|
1481
|
-
const rightValue = yield* self.evaluateExpression(
|
|
1451
|
+
const rightValue = yield* self.evaluateExpression(node.right);
|
|
1482
1452
|
return self.scopes.set(name, rightValue, left);
|
|
1483
1453
|
});
|
|
1484
1454
|
}
|
|
1485
1455
|
if (left.type === "MemberExpression") {
|
|
1486
1456
|
return self.modifyMember(left, (current) => shouldAssign(current)
|
|
1487
|
-
? Effect.map(self.evaluateExpression(
|
|
1457
|
+
? Effect.map(self.evaluateExpression(node.right), (rightValue) => ({
|
|
1488
1458
|
write: true,
|
|
1489
1459
|
next: rightValue,
|
|
1490
1460
|
result: rightValue,
|
|
@@ -1494,9 +1464,9 @@ export class Interpreter {
|
|
|
1494
1464
|
throw new InterpreterRuntimeError("Assignment target must be an Identifier or MemberExpression.", left);
|
|
1495
1465
|
}
|
|
1496
1466
|
evaluateUpdateExpression(node) {
|
|
1497
|
-
const operator =
|
|
1498
|
-
const argument =
|
|
1499
|
-
const prefix =
|
|
1467
|
+
const operator = node.operator;
|
|
1468
|
+
const argument = node.argument;
|
|
1469
|
+
const prefix = node.prefix;
|
|
1500
1470
|
const increment = operator === "++" ? 1 : operator === "--" ? -1 : undefined;
|
|
1501
1471
|
if (increment === undefined) {
|
|
1502
1472
|
throw new InterpreterRuntimeError(`Unsupported update operator '${operator}'.`, node);
|
|
@@ -1511,7 +1481,7 @@ export class Interpreter {
|
|
|
1511
1481
|
};
|
|
1512
1482
|
if (argument.type === "Identifier") {
|
|
1513
1483
|
return Effect.sync(() => {
|
|
1514
|
-
const name =
|
|
1484
|
+
const name = argument.name;
|
|
1515
1485
|
const current = operand(this.scopes.get(name, argument));
|
|
1516
1486
|
const next = current + increment;
|
|
1517
1487
|
this.scopes.set(name, next, argument);
|
|
@@ -1528,26 +1498,28 @@ export class Interpreter {
|
|
|
1528
1498
|
throw new InterpreterRuntimeError("Update target must be an Identifier or MemberExpression.", argument);
|
|
1529
1499
|
}
|
|
1530
1500
|
evaluateCallExpression(node) {
|
|
1531
|
-
const callee =
|
|
1532
|
-
const argNodes = getArray(node, "arguments");
|
|
1501
|
+
const callee = node.callee;
|
|
1533
1502
|
const self = this;
|
|
1534
1503
|
return Effect.gen(function* () {
|
|
1504
|
+
if (callee.type === "Super")
|
|
1505
|
+
throw unsupportedSyntax(callee.type, callee);
|
|
1535
1506
|
const callable = yield* self.evaluateExpression(callee);
|
|
1536
1507
|
if (callable === OptionalShortCircuit)
|
|
1537
1508
|
return OptionalShortCircuit;
|
|
1538
|
-
if ((callable === null || callable === undefined) && node.optional
|
|
1509
|
+
if ((callable === null || callable === undefined) && node.optional)
|
|
1539
1510
|
return OptionalShortCircuit;
|
|
1540
|
-
const args = yield* self.evaluateCallArguments(
|
|
1511
|
+
const args = yield* self.evaluateCallArguments(node.arguments);
|
|
1541
1512
|
return yield* self.invokeCallable(callable, args, node, callee);
|
|
1542
1513
|
});
|
|
1543
1514
|
}
|
|
1544
1515
|
// The single dispatch for every invocation: call expressions and callbacks share it.
|
|
1545
|
-
invokeCallable(callable, args, node, callee
|
|
1516
|
+
invokeCallable(callable, args, node, callee) {
|
|
1546
1517
|
const self = this;
|
|
1547
1518
|
return Effect.gen(function* () {
|
|
1548
1519
|
if (callable instanceof ToolReference) {
|
|
1549
|
-
if (callable.path.length === 0)
|
|
1550
|
-
throw new InterpreterRuntimeError("The tools root is not callable.", callee);
|
|
1520
|
+
if (callable.path.length === 0) {
|
|
1521
|
+
throw new InterpreterRuntimeError("The tools root is not callable.", callee ?? node);
|
|
1522
|
+
}
|
|
1551
1523
|
return yield* self.createToolCallPromise(callable.path, args);
|
|
1552
1524
|
}
|
|
1553
1525
|
if (callable instanceof PromiseMethodReference) {
|
|
@@ -1638,9 +1610,9 @@ export class Interpreter {
|
|
|
1638
1610
|
return undefined;
|
|
1639
1611
|
}
|
|
1640
1612
|
if (callable === undefined || callable === null) {
|
|
1641
|
-
throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee).as("TypeError");
|
|
1613
|
+
throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node).as("TypeError");
|
|
1642
1614
|
}
|
|
1643
|
-
throw new InterpreterRuntimeError("Only tools are callable here.", callee);
|
|
1615
|
+
throw new InterpreterRuntimeError("Only tools are callable here.", callee ?? node);
|
|
1644
1616
|
});
|
|
1645
1617
|
}
|
|
1646
1618
|
invokeObjectMethodOnTools(name, ref, node) {
|
|
@@ -1659,10 +1631,9 @@ export class Interpreter {
|
|
|
1659
1631
|
const self = this;
|
|
1660
1632
|
return Effect.gen(function* () {
|
|
1661
1633
|
const args = [];
|
|
1662
|
-
for (const
|
|
1663
|
-
const argNode = asNode(arg, `arguments[${index}]`);
|
|
1634
|
+
for (const argNode of argNodes) {
|
|
1664
1635
|
if (argNode.type === "SpreadElement") {
|
|
1665
|
-
const spread = yield* self.evaluateExpression(
|
|
1636
|
+
const spread = yield* self.evaluateExpression(argNode.argument);
|
|
1666
1637
|
const cursor = yield* self.syncIterator(spread, argNode);
|
|
1667
1638
|
if (cursor === undefined)
|
|
1668
1639
|
throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode).as("TypeError");
|
|
@@ -1693,7 +1664,7 @@ export class Interpreter {
|
|
|
1693
1664
|
}
|
|
1694
1665
|
for (const [index, parameter] of fn.parameters.entries()) {
|
|
1695
1666
|
if (parameter.type === "RestElement") {
|
|
1696
|
-
yield* invocation.declarePattern(
|
|
1667
|
+
yield* invocation.declarePattern(parameter.argument, args.slice(index), true, parameter, true);
|
|
1697
1668
|
break;
|
|
1698
1669
|
}
|
|
1699
1670
|
yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
|
|
@@ -1814,12 +1785,12 @@ export class Interpreter {
|
|
|
1814
1785
|
return request;
|
|
1815
1786
|
}
|
|
1816
1787
|
evaluateYieldExpression(node) {
|
|
1817
|
-
const argument =
|
|
1788
|
+
const argument = node.argument;
|
|
1818
1789
|
const self = this;
|
|
1819
1790
|
return Effect.gen(function* () {
|
|
1820
1791
|
if (!self.generatorState)
|
|
1821
1792
|
throw new InterpreterRuntimeError("yield is only valid inside a generator.", node);
|
|
1822
|
-
if (node.delegate
|
|
1793
|
+
if (node.delegate) {
|
|
1823
1794
|
const value = argument ? yield* self.evaluateExpression(argument) : undefined;
|
|
1824
1795
|
return yield* self.delegateYield(value, node);
|
|
1825
1796
|
}
|
|
@@ -1920,13 +1891,11 @@ export class Interpreter {
|
|
|
1920
1891
|
}
|
|
1921
1892
|
evaluateObjectExpression(node) {
|
|
1922
1893
|
const objectValue = Object.create(null);
|
|
1923
|
-
const properties = getArray(node, "properties");
|
|
1924
1894
|
const self = this;
|
|
1925
1895
|
return Effect.gen(function* () {
|
|
1926
|
-
for (const
|
|
1927
|
-
const property = asNode(propertyValue, "properties");
|
|
1896
|
+
for (const property of node.properties) {
|
|
1928
1897
|
if (property.type === "SpreadElement") {
|
|
1929
|
-
const spread = yield* self.evaluateExpression(
|
|
1898
|
+
const spread = yield* self.evaluateExpression(property.argument);
|
|
1930
1899
|
if (spread === null || spread === undefined || Values.isValue(spread))
|
|
1931
1900
|
continue;
|
|
1932
1901
|
if (typeof spread !== "object" || Array.isArray(spread) || isRuntimeReference(spread)) {
|
|
@@ -1940,21 +1909,16 @@ export class Interpreter {
|
|
|
1940
1909
|
copyIteratorSymbols(spread, objectValue);
|
|
1941
1910
|
continue;
|
|
1942
1911
|
}
|
|
1943
|
-
if (property.
|
|
1944
|
-
throw new InterpreterRuntimeError("Only standard object properties are supported.", property);
|
|
1945
|
-
}
|
|
1946
|
-
if (getString(property, "kind") !== "init") {
|
|
1912
|
+
if (property.kind !== "init") {
|
|
1947
1913
|
throw new InterpreterRuntimeError("Only init object properties are supported.", property);
|
|
1948
1914
|
}
|
|
1949
|
-
const keyNode =
|
|
1950
|
-
const valueNode = getNode(property, "value");
|
|
1951
|
-
const computed = getBoolean(property, "computed");
|
|
1915
|
+
const keyNode = property.key;
|
|
1952
1916
|
let key;
|
|
1953
|
-
if (computed) {
|
|
1917
|
+
if (property.computed) {
|
|
1954
1918
|
key = self.toPropertyKey(yield* self.evaluateExpression(keyNode), keyNode);
|
|
1955
1919
|
}
|
|
1956
1920
|
else if (keyNode.type === "Identifier") {
|
|
1957
|
-
key =
|
|
1921
|
+
key = keyNode.name;
|
|
1958
1922
|
}
|
|
1959
1923
|
else if (keyNode.type === "Literal") {
|
|
1960
1924
|
key = self.toPropertyKey(keyNode.value, keyNode);
|
|
@@ -1965,25 +1929,23 @@ export class Interpreter {
|
|
|
1965
1929
|
if (isBlockedMember(String(key))) {
|
|
1966
1930
|
throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, keyNode);
|
|
1967
1931
|
}
|
|
1968
|
-
Reflect.set(objectValue, key, yield* self.evaluateExpression(
|
|
1932
|
+
Reflect.set(objectValue, key, yield* self.evaluateExpression(property.value));
|
|
1969
1933
|
}
|
|
1970
1934
|
return objectValue;
|
|
1971
1935
|
});
|
|
1972
1936
|
}
|
|
1973
1937
|
evaluateArrayExpression(node) {
|
|
1974
|
-
const elements = getArray(node, "elements");
|
|
1975
1938
|
const values = [];
|
|
1976
1939
|
const self = this;
|
|
1977
1940
|
return Effect.gen(function* () {
|
|
1978
|
-
for (const
|
|
1979
|
-
if (
|
|
1941
|
+
for (const element of node.elements) {
|
|
1942
|
+
if (element === null) {
|
|
1980
1943
|
// A literal elision is a real hole, like JS: extend length without an own index.
|
|
1981
1944
|
values.length += 1;
|
|
1982
1945
|
continue;
|
|
1983
1946
|
}
|
|
1984
|
-
const element = asNode(elementValue, "elements");
|
|
1985
1947
|
if (element.type === "SpreadElement") {
|
|
1986
|
-
const spread = yield* self.evaluateExpression(
|
|
1948
|
+
const spread = yield* self.evaluateExpression(element.argument);
|
|
1987
1949
|
const cursor = yield* self.syncIterator(spread, element);
|
|
1988
1950
|
if (cursor === undefined)
|
|
1989
1951
|
throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element).as("TypeError");
|
|
@@ -2002,20 +1964,20 @@ export class Interpreter {
|
|
|
2002
1964
|
});
|
|
2003
1965
|
}
|
|
2004
1966
|
evaluateTemplateLiteral(node) {
|
|
2005
|
-
const quasis =
|
|
2006
|
-
const expressions =
|
|
1967
|
+
const quasis = node.quasis;
|
|
1968
|
+
const expressions = node.expressions;
|
|
2007
1969
|
let output = "";
|
|
2008
1970
|
const self = this;
|
|
2009
1971
|
return Effect.gen(function* () {
|
|
2010
1972
|
for (let index = 0; index < quasis.length; index += 1) {
|
|
2011
|
-
const quasi =
|
|
2012
|
-
|
|
2013
|
-
if (
|
|
1973
|
+
const quasi = quasis[index];
|
|
1974
|
+
// acorn only omits `cooked` for invalid escapes in tagged templates, which are unsupported.
|
|
1975
|
+
if (typeof quasi.value.cooked !== "string") {
|
|
2014
1976
|
throw new InterpreterRuntimeError("Invalid template literal quasi.", quasi);
|
|
2015
1977
|
}
|
|
2016
|
-
output +=
|
|
1978
|
+
output += quasi.value.cooked;
|
|
2017
1979
|
if (index < expressions.length) {
|
|
2018
|
-
const raw = yield* self.evaluateExpression(
|
|
1980
|
+
const raw = yield* self.evaluateExpression(expressions[index]);
|
|
2019
1981
|
output += coerceToString(toProgram(raw, "Template interpolation"));
|
|
2020
1982
|
}
|
|
2021
1983
|
}
|
|
@@ -2023,7 +1985,7 @@ export class Interpreter {
|
|
|
2023
1985
|
});
|
|
2024
1986
|
}
|
|
2025
1987
|
evaluateConditionalExpression(node) {
|
|
2026
|
-
return Effect.flatMap(this.evaluateExpression(
|
|
1988
|
+
return Effect.flatMap(this.evaluateExpression(node.test), (test) => this.evaluateExpression(test ? node.consequent : node.alternate));
|
|
2027
1989
|
}
|
|
2028
1990
|
applyCompoundAssignment(operator, current, incoming, node) {
|
|
2029
1991
|
if (!compoundOperators.has(operator)) {
|
|
@@ -2032,21 +1994,23 @@ export class Interpreter {
|
|
|
2032
1994
|
return this.applyBinaryOperator(operator.slice(0, -1), current, incoming, node);
|
|
2033
1995
|
}
|
|
2034
1996
|
getMemberReference(node, operation = "read") {
|
|
2035
|
-
const objectNode =
|
|
2036
|
-
const propertyNode =
|
|
2037
|
-
|
|
2038
|
-
|
|
1997
|
+
const objectNode = node.object;
|
|
1998
|
+
const propertyNode = node.property;
|
|
1999
|
+
if (objectNode.type === "Super")
|
|
2000
|
+
throw unsupportedSyntax(objectNode.type, objectNode);
|
|
2001
|
+
if (propertyNode.type === "PrivateIdentifier")
|
|
2002
|
+
throw unsupportedSyntax(propertyNode.type, propertyNode);
|
|
2039
2003
|
const self = this;
|
|
2040
2004
|
return Effect.gen(function* () {
|
|
2041
2005
|
const objectValue = yield* self.evaluateExpression(objectNode);
|
|
2042
2006
|
if (objectValue === OptionalShortCircuit)
|
|
2043
2007
|
return OptionalShortCircuit;
|
|
2044
|
-
if ((objectValue === null || objectValue === undefined) && optional)
|
|
2008
|
+
if ((objectValue === null || objectValue === undefined) && node.optional)
|
|
2045
2009
|
return OptionalShortCircuit;
|
|
2046
|
-
const key = computed
|
|
2010
|
+
const key = node.computed
|
|
2047
2011
|
? self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode)
|
|
2048
2012
|
: propertyNode.type === "Identifier"
|
|
2049
|
-
?
|
|
2013
|
+
? propertyNode.name
|
|
2050
2014
|
: self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode);
|
|
2051
2015
|
if (objectValue instanceof ToolReference) {
|
|
2052
2016
|
if (typeof key !== "string") {
|
|
@@ -2234,7 +2198,7 @@ export class Interpreter {
|
|
|
2234
2198
|
return this.modifyMember(node, () => Effect.succeed({ write: true, next: value, result: value }));
|
|
2235
2199
|
}
|
|
2236
2200
|
evaluateDeleteExpression(argument) {
|
|
2237
|
-
const target = argument.type === "ChainExpression" ?
|
|
2201
|
+
const target = argument.type === "ChainExpression" ? argument.expression : argument;
|
|
2238
2202
|
if (target.type !== "MemberExpression") {
|
|
2239
2203
|
throw new InterpreterRuntimeError("Only data fields may be deleted.", argument);
|
|
2240
2204
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@opencode/codemode",
|
|
4
|
-
"version": "0.0.0-dev-
|
|
4
|
+
"version": "0.0.0-dev-19360",
|
|
5
5
|
"description": "Effect-native confined code execution over schema-described tools",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|