@opencode-ai/codemode 0.0.0-next-17250

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.
Files changed (68) hide show
  1. package/README.md +168 -0
  2. package/dist/codemode.d.ts +148 -0
  3. package/dist/codemode.js +70 -0
  4. package/dist/index.d.ts +5 -0
  5. package/dist/index.js +5 -0
  6. package/dist/interpreter/errors.d.ts +9 -0
  7. package/dist/interpreter/errors.js +91 -0
  8. package/dist/interpreter/execute.d.ts +4 -0
  9. package/dist/interpreter/execute.js +183 -0
  10. package/dist/interpreter/iterator.d.ts +13 -0
  11. package/dist/interpreter/iterator.js +4 -0
  12. package/dist/interpreter/methods.d.ts +17 -0
  13. package/dist/interpreter/methods.js +1026 -0
  14. package/dist/interpreter/model.d.ts +151 -0
  15. package/dist/interpreter/model.js +186 -0
  16. package/dist/interpreter/promises.d.ts +29 -0
  17. package/dist/interpreter/promises.js +253 -0
  18. package/dist/interpreter/references.d.ts +6 -0
  19. package/dist/interpreter/references.js +114 -0
  20. package/dist/interpreter/runtime.d.ts +98 -0
  21. package/dist/interpreter/runtime.js +2351 -0
  22. package/dist/interpreter/scope.d.ts +15 -0
  23. package/dist/interpreter/scope.js +79 -0
  24. package/dist/openapi/index.d.ts +7 -0
  25. package/dist/openapi/index.js +101 -0
  26. package/dist/openapi/runtime.d.ts +4 -0
  27. package/dist/openapi/runtime.js +283 -0
  28. package/dist/openapi/spec.d.ts +20 -0
  29. package/dist/openapi/spec.js +588 -0
  30. package/dist/openapi/types.d.ts +122 -0
  31. package/dist/openapi/types.js +2 -0
  32. package/dist/stdlib/collections.d.ts +4 -0
  33. package/dist/stdlib/collections.js +57 -0
  34. package/dist/stdlib/console.d.ts +2 -0
  35. package/dist/stdlib/console.js +126 -0
  36. package/dist/stdlib/date.d.ts +7 -0
  37. package/dist/stdlib/date.js +186 -0
  38. package/dist/stdlib/json.d.ts +6 -0
  39. package/dist/stdlib/json.js +124 -0
  40. package/dist/stdlib/math.d.ts +12 -0
  41. package/dist/stdlib/math.js +157 -0
  42. package/dist/stdlib/number.d.ts +6 -0
  43. package/dist/stdlib/number.js +76 -0
  44. package/dist/stdlib/object.d.ts +7 -0
  45. package/dist/stdlib/object.js +100 -0
  46. package/dist/stdlib/promise.d.ts +2 -0
  47. package/dist/stdlib/promise.js +1 -0
  48. package/dist/stdlib/regexp.d.ts +11 -0
  49. package/dist/stdlib/regexp.js +106 -0
  50. package/dist/stdlib/string.d.ts +4 -0
  51. package/dist/stdlib/string.js +48 -0
  52. package/dist/stdlib/url.d.ts +12 -0
  53. package/dist/stdlib/url.js +84 -0
  54. package/dist/stdlib/value.d.ts +12 -0
  55. package/dist/stdlib/value.js +120 -0
  56. package/dist/tool-error.d.ts +11 -0
  57. package/dist/tool-error.js +9 -0
  58. package/dist/tool-runtime.d.ts +68 -0
  59. package/dist/tool-runtime.js +390 -0
  60. package/dist/tool-schema.d.ts +15 -0
  61. package/dist/tool-schema.js +213 -0
  62. package/dist/tool.d.ts +55 -0
  63. package/dist/tool.js +21 -0
  64. package/dist/tools.d.ts +4 -0
  65. package/dist/tools.js +1 -0
  66. package/dist/values.d.ts +31 -0
  67. package/dist/values.js +50 -0
  68. package/package.json +40 -0
@@ -0,0 +1,2351 @@
1
+ import { Cause, Deferred, Effect, Exit } from "effect";
2
+ import { isBlockedMember, ToolReference, ToolRuntimeError } from "../tool-runtime.js";
3
+ import { AsyncIteratorSymbol, asNode, CodeModeFunction, CodeModeGenerator, CoercionFunction, ComputedValue, ErrorConstructorReference, GlobalMethodReference, GlobalNamespace, GeneratorMethodReference, GeneratorReturn, getArray, getBoolean, getNode, getOptionalNode, getString, IntrinsicReference, InterpreterRuntimeError, isRecord, IteratorSymbol, IteratorSymbols, JsonMethodReference, OptionalShortCircuit, PromiseCapabilityFunction, PromiseInstanceMethodReference, PromiseMethodReference, PromiseNamespace, ProgramThrow, SearchFunction, SymbolNamespace, unsupportedSyntax, UriFunction, } from "./model.js";
4
+ import { caughtErrorValue, constructAggregateErrorValue, constructErrorValue } from "./errors.js";
5
+ import { arrayStatics, invokeArrayFrom, invokeGlobalMethod, invokeGroupBy, invokeIntrinsic, } from "./methods.js";
6
+ import { preserveConsumerError } from "./iterator.js";
7
+ import { constructPromise, invokePromiseInstanceMethod, invokePromiseMethod, PromiseRuntime, resolvePromise, resolvePromiseValue, } from "./promises.js";
8
+ import { containsOpaqueReference, isRuntimeReference, rejectCircularInsertion, typeofValue } from "./references.js";
9
+ import { ScopeStack } from "./scope.js";
10
+ import { arrayMethods, mapMethods, mapStatics, setMethods } from "../stdlib/collections.js";
11
+ import { consoleMethods, formatConsoleMessage } from "../stdlib/console.js";
12
+ import { dateMethods, dateStatics } from "../stdlib/date.js";
13
+ import { invokeJsonMethod, jsonStatics } from "../stdlib/json.js";
14
+ import { invokeMathSumPrecise, mathConstants, mathMethods } from "../stdlib/math.js";
15
+ import { numberConstants, numberMethods, numberStatics } from "../stdlib/number.js";
16
+ import { invokeObjectFromEntries, objectMethodsPreservingIdentity, objectStatics } from "../stdlib/object.js";
17
+ import { promiseStatics } from "../stdlib/promise.js";
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
+ };
33
+ const MAX_ARRAY_LENGTH = 4_294_967_295;
34
+ const parseArrayIndex = (key) => {
35
+ const property = String(key);
36
+ if (!/^(0|[1-9]\d*)$/.test(property))
37
+ return undefined;
38
+ const index = Number(property);
39
+ return index < MAX_ARRAY_LENGTH ? index : undefined;
40
+ };
41
+ const calleeDescription = (callee) => {
42
+ if (callee.type === "Identifier")
43
+ return getString(callee, "name");
44
+ if (callee.type === "MemberExpression") {
45
+ const object = getNode(callee, "object");
46
+ const property = getNode(callee, "property");
47
+ const key = callee.computed !== true && property.type === "Identifier"
48
+ ? getString(property, "name")
49
+ : property.type === "Literal" && typeof property.value === "string"
50
+ ? property.value
51
+ : undefined;
52
+ if (object.type === "Identifier" && key !== undefined)
53
+ return `${getString(object, "name")}.${key}`;
54
+ }
55
+ return "The called value";
56
+ };
57
+ const instanceofValue = (lhs, rhs, node) => {
58
+ if (rhs instanceof ErrorConstructorReference) {
59
+ const brand = errorBrandName(lhs);
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
+ }
87
+ 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
+ };
89
+ const collectPatternNames = (pattern, out = []) => {
90
+ switch (pattern.type) {
91
+ case "Identifier":
92
+ out.push(getString(pattern, "name"));
93
+ break;
94
+ case "AssignmentPattern":
95
+ collectPatternNames(getNode(pattern, "left"), out);
96
+ break;
97
+ case "RestElement":
98
+ collectPatternNames(getNode(pattern, "argument"), out);
99
+ break;
100
+ case "ArrayPattern":
101
+ for (const element of getArray(pattern, "elements")) {
102
+ if (element !== null)
103
+ collectPatternNames(asNode(element, "elements"), out);
104
+ }
105
+ break;
106
+ case "ObjectPattern":
107
+ for (const property of getArray(pattern, "properties")) {
108
+ const prop = asNode(property, "properties");
109
+ collectPatternNames(prop.type === "RestElement" ? getNode(prop, "argument") : getNode(prop, "value"), out);
110
+ }
111
+ break;
112
+ }
113
+ return out;
114
+ };
115
+ const loopDeclaration = (left, statement) => {
116
+ if (left.type !== "VariableDeclaration")
117
+ return undefined;
118
+ const declarations = getArray(left, "declarations");
119
+ if (declarations.length !== 1) {
120
+ throw new InterpreterRuntimeError(`${statement} supports one declared binding.`, left);
121
+ }
122
+ const kind = getString(left, "kind");
123
+ return {
124
+ pattern: getNode(asNode(declarations[0], "declarations[0]"), "id"),
125
+ mutable: kind !== "const",
126
+ lexical: kind !== "var",
127
+ };
128
+ };
129
+ const isOpaqueMemberReference = (value) => value instanceof ToolReference ||
130
+ value instanceof PromiseMethodReference ||
131
+ value instanceof PromiseInstanceMethodReference ||
132
+ value instanceof IntrinsicReference ||
133
+ value instanceof GlobalMethodReference ||
134
+ value instanceof JsonMethodReference ||
135
+ value instanceof GeneratorMethodReference;
136
+ const copyIteratorSymbols = (source, target, consumed) => {
137
+ for (const symbol of IteratorSymbols) {
138
+ if (!consumed?.has(symbol) && Object.hasOwn(source, symbol))
139
+ Reflect.set(target, symbol, Reflect.get(source, symbol));
140
+ }
141
+ };
142
+ const promiseResolutionNode = { type: "PromiseResolution" };
143
+ export class Interpreter {
144
+ scopes;
145
+ executeTool;
146
+ invokeSearch;
147
+ toolKeys;
148
+ logs;
149
+ promises;
150
+ generatorState;
151
+ generatorAsync = false;
152
+ runner = {
153
+ invokeFunction: (fn, args) => this.invokeFunction(fn, args),
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]);
161
+ this.executeTool = executeTool;
162
+ this.invokeSearch = invokeSearch;
163
+ this.toolKeys = toolKeys;
164
+ this.logs = logs;
165
+ this.promises = promises;
166
+ globalScope.set("tools", { mutable: false, value: new ToolReference([]) });
167
+ globalScope.set("search", { mutable: false, value: new SearchFunction() });
168
+ globalScope.set("Promise", { mutable: false, value: new PromiseNamespace() });
169
+ globalScope.set("Symbol", { mutable: false, value: new SymbolNamespace() });
170
+ globalScope.set("undefined", { mutable: false, value: undefined });
171
+ globalScope.set("Object", { mutable: false, value: new GlobalNamespace("Object") });
172
+ globalScope.set("Math", { mutable: false, value: new GlobalNamespace("Math") });
173
+ globalScope.set("JSON", { mutable: false, value: new GlobalNamespace("JSON") });
174
+ globalScope.set("Number", { mutable: false, value: new CoercionFunction("Number") });
175
+ globalScope.set("String", { mutable: false, value: new CoercionFunction("String") });
176
+ globalScope.set("Boolean", { mutable: false, value: new CoercionFunction("Boolean") });
177
+ globalScope.set("Array", { mutable: false, value: new GlobalNamespace("Array") });
178
+ globalScope.set("console", { mutable: false, value: new GlobalNamespace("console") });
179
+ globalScope.set("parseInt", { mutable: false, value: new CoercionFunction("parseInt") });
180
+ globalScope.set("parseFloat", { mutable: false, value: new CoercionFunction("parseFloat") });
181
+ globalScope.set("isFinite", { mutable: false, value: new CoercionFunction("isFinite") });
182
+ globalScope.set("isNaN", { mutable: false, value: new CoercionFunction("isNaN") });
183
+ globalScope.set("Date", { mutable: false, value: new GlobalNamespace("Date") });
184
+ globalScope.set("RegExp", { mutable: false, value: new GlobalNamespace("RegExp") });
185
+ globalScope.set("Map", { mutable: false, value: new GlobalNamespace("Map") });
186
+ globalScope.set("Set", { mutable: false, value: new GlobalNamespace("Set") });
187
+ globalScope.set("URL", { mutable: false, value: new GlobalNamespace("URL") });
188
+ globalScope.set("URLSearchParams", { mutable: false, value: new GlobalNamespace("URLSearchParams") });
189
+ globalScope.set("encodeURI", { mutable: false, value: new UriFunction("encodeURI") });
190
+ globalScope.set("encodeURIComponent", { mutable: false, value: new UriFunction("encodeURIComponent") });
191
+ globalScope.set("decodeURI", { mutable: false, value: new UriFunction("decodeURI") });
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 });
198
+ }
199
+ run(program) {
200
+ const self = this;
201
+ // Keep top-level declarations separate so they can shadow builtins.
202
+ this.scopes.push();
203
+ return Effect.gen(function* () {
204
+ self.predeclareLexical(program.body);
205
+ self.hoistFunctions(program.body);
206
+ let value = undefined;
207
+ for (const [index, statement] of program.body.entries()) {
208
+ if (index === program.body.length - 1 && statement.type === "ExpressionStatement") {
209
+ value = yield* self.evaluateExpression(getNode(statement, "expression"));
210
+ break;
211
+ }
212
+ const result = yield* self.evaluateStatement(statement);
213
+ if (result.kind === "return") {
214
+ value = result.value;
215
+ break;
216
+ }
217
+ if (result.kind === "break" || result.kind === "continue") {
218
+ throw new InterpreterRuntimeError(`Unexpected '${result.kind}' outside of a loop.`, statement);
219
+ }
220
+ }
221
+ // The implicit async body adopts returned promises before copy-out.
222
+ value = yield* resolvePromiseValue(self.runner, value, program);
223
+ return value;
224
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
225
+ }
226
+ // Fork at the call site so admission and hooks occur when the call is made.
227
+ createToolCallPromise(path, args) {
228
+ return this.createPromise(Effect.suspend(() => this.executeTool(path, args)));
229
+ }
230
+ createPromise(effect) {
231
+ return this.promises.create(effect);
232
+ }
233
+ // Fiber exits make settlement idempotent; yielding prevents inline continuation.
234
+ settlePromise(promise) {
235
+ const promises = this.promises;
236
+ return Effect.suspend(() => {
237
+ promises.markObserved(promise);
238
+ return Effect.flatMap(promises.await(promise), (exit) => Effect.andThen(Effect.yieldNow, exit));
239
+ });
240
+ }
241
+ evaluateStatement(node) {
242
+ switch (node.type) {
243
+ case "ExpressionStatement":
244
+ return Effect.as(this.evaluateExpression(getNode(node, "expression")), { kind: "none" });
245
+ case "VariableDeclaration":
246
+ return Effect.map(this.evaluateVariableDeclaration(node), () => ({ kind: "none" }));
247
+ case "ReturnStatement": {
248
+ const argumentNode = getOptionalNode(node, "argument");
249
+ return argumentNode
250
+ ? Effect.map(this.evaluateExpression(argumentNode), (value) => ({ kind: "return", value }))
251
+ : Effect.succeed({ kind: "return", value: undefined });
252
+ }
253
+ case "BlockStatement":
254
+ return this.evaluateBlock(node);
255
+ case "IfStatement":
256
+ return this.evaluateIfStatement(node);
257
+ case "SwitchStatement":
258
+ return this.evaluateSwitchStatement(node);
259
+ case "LabeledStatement":
260
+ return this.evaluateLabeledStatement(node);
261
+ case "WhileStatement":
262
+ return this.evaluateWhileStatement(node);
263
+ case "DoWhileStatement":
264
+ return this.evaluateDoWhileStatement(node);
265
+ case "ForStatement":
266
+ return this.evaluateForStatement(node);
267
+ case "ForOfStatement":
268
+ return this.evaluateForOfStatement(node);
269
+ case "ForInStatement":
270
+ return this.evaluateForInStatement(node);
271
+ case "BreakStatement":
272
+ return Effect.succeed(this.evaluateBreakStatement(node));
273
+ case "ContinueStatement":
274
+ return Effect.succeed(this.evaluateContinueStatement(node));
275
+ case "ThrowStatement":
276
+ return this.evaluateThrowStatement(node);
277
+ case "TryStatement":
278
+ return this.evaluateTryStatement(node);
279
+ case "EmptyStatement":
280
+ return Effect.succeed({ kind: "none" });
281
+ case "FunctionDeclaration":
282
+ return Effect.succeed({ kind: "none" });
283
+ default:
284
+ throw unsupportedSyntax(node.type, node);
285
+ }
286
+ }
287
+ evaluateBlock(node) {
288
+ this.scopes.push();
289
+ const self = this;
290
+ return Effect.gen(function* () {
291
+ const body = getArray(node, "body");
292
+ self.predeclareLexical(body);
293
+ self.hoistFunctions(body);
294
+ for (const statementValue of body) {
295
+ const statement = asNode(statementValue, "body");
296
+ const result = yield* self.evaluateStatement(statement);
297
+ if (result.kind !== "none") {
298
+ return result;
299
+ }
300
+ }
301
+ return { kind: "none" };
302
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
303
+ }
304
+ createFunction(node) {
305
+ return new CodeModeFunction(getArray(node, "params").map((parameter, index) => asNode(parameter, `params[${index}]`)), getNode(node, "body"), this.scopes.capture(), node.async === true, node.generator === true);
306
+ }
307
+ hoistFunctions(statements) {
308
+ for (const statementValue of statements) {
309
+ if (!isRecord(statementValue) || statementValue.type !== "FunctionDeclaration")
310
+ continue;
311
+ const node = statementValue;
312
+ this.scopes.declare(getString(getNode(node, "id"), "name"), this.createFunction(node), true, node);
313
+ }
314
+ }
315
+ predeclareLexical(statements) {
316
+ for (const statementValue of statements) {
317
+ if (!isRecord(statementValue) || statementValue.type !== "VariableDeclaration")
318
+ continue;
319
+ const statement = statementValue;
320
+ const kind = getString(statement, "kind");
321
+ if (kind === "var")
322
+ continue;
323
+ for (const declarationValue of getArray(statement, "declarations")) {
324
+ const declaration = asNode(declarationValue, "declarations");
325
+ for (const name of collectPatternNames(getNode(declaration, "id"))) {
326
+ this.scopes.reserve(name, kind !== "const", declaration);
327
+ }
328
+ }
329
+ }
330
+ }
331
+ predeclarePattern(pattern, mutable, node) {
332
+ for (const name of collectPatternNames(pattern))
333
+ this.scopes.reserve(name, mutable, node);
334
+ }
335
+ evaluateIfStatement(node) {
336
+ const testNode = getNode(node, "test");
337
+ const consequentNode = getNode(node, "consequent");
338
+ const alternateNode = getOptionalNode(node, "alternate");
339
+ return Effect.flatMap(this.evaluateExpression(testNode), (test) => test
340
+ ? this.evaluateStatement(consequentNode)
341
+ : alternateNode
342
+ ? this.evaluateStatement(alternateNode)
343
+ : Effect.succeed({ kind: "none" }));
344
+ }
345
+ evaluateSwitchStatement(node) {
346
+ const self = this;
347
+ return Effect.gen(function* () {
348
+ const discriminant = yield* self.evaluateExpression(getNode(node, "discriminant"));
349
+ if (containsOpaqueReference(discriminant)) {
350
+ throw new InterpreterRuntimeError("Switch discriminants must be data values.", node, "InvalidDataValue");
351
+ }
352
+ self.scopes.push();
353
+ return yield* Effect.gen(function* () {
354
+ const cases = getArray(node, "cases").map((value, index) => asNode(value, `cases[${index}]`));
355
+ self.predeclareLexical(cases.flatMap((branch) => getArray(branch, "consequent")));
356
+ let defaultIndex;
357
+ let selected;
358
+ for (const [index, branch] of cases.entries()) {
359
+ const test = getOptionalNode(branch, "test");
360
+ if (!test) {
361
+ defaultIndex = index;
362
+ continue;
363
+ }
364
+ const candidate = yield* self.evaluateExpression(test);
365
+ if (containsOpaqueReference(candidate)) {
366
+ throw new InterpreterRuntimeError("Switch case values must be data values.", test, "InvalidDataValue");
367
+ }
368
+ if (candidate === discriminant) {
369
+ selected = index;
370
+ break;
371
+ }
372
+ }
373
+ const start = selected ?? defaultIndex;
374
+ if (start === undefined)
375
+ return { kind: "none" };
376
+ for (let index = start; index < cases.length; index += 1) {
377
+ for (const statementValue of getArray(cases[index], "consequent")) {
378
+ const result = yield* self.evaluateStatement(asNode(statementValue, "consequent"));
379
+ if (result.kind === "break") {
380
+ if (result.label === undefined)
381
+ return { kind: "none" };
382
+ return result;
383
+ }
384
+ if (result.kind === "return" || result.kind === "continue")
385
+ return result;
386
+ }
387
+ }
388
+ return { kind: "none" };
389
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
390
+ });
391
+ }
392
+ evaluateWhileStatement(node, labels) {
393
+ const testNode = getNode(node, "test");
394
+ const bodyNode = getNode(node, "body");
395
+ const self = this;
396
+ return Effect.gen(function* () {
397
+ while (yield* self.evaluateExpression(testNode)) {
398
+ const result = yield* self.evaluateStatement(bodyNode);
399
+ if (result.kind === "continue") {
400
+ if (result.label !== undefined && !labels?.has(result.label))
401
+ return result;
402
+ continue;
403
+ }
404
+ if (result.kind === "break") {
405
+ if (result.label !== undefined && !labels?.has(result.label))
406
+ return result;
407
+ return { kind: "none" };
408
+ }
409
+ if (result.kind === "return") {
410
+ return result;
411
+ }
412
+ }
413
+ return { kind: "none" };
414
+ });
415
+ }
416
+ evaluateDoWhileStatement(node, labels) {
417
+ const bodyNode = getNode(node, "body");
418
+ const testNode = getNode(node, "test");
419
+ const self = this;
420
+ return Effect.gen(function* () {
421
+ do {
422
+ const result = yield* self.evaluateStatement(bodyNode);
423
+ if (result.kind === "continue") {
424
+ if (result.label !== undefined && !labels?.has(result.label))
425
+ return result;
426
+ continue;
427
+ }
428
+ if (result.kind === "break") {
429
+ if (result.label !== undefined && !labels?.has(result.label))
430
+ return result;
431
+ return { kind: "none" };
432
+ }
433
+ if (result.kind === "return") {
434
+ return result;
435
+ }
436
+ } while (yield* self.evaluateExpression(testNode));
437
+ return { kind: "none" };
438
+ });
439
+ }
440
+ evaluateForStatement(node, labels) {
441
+ this.scopes.push();
442
+ const self = this;
443
+ return Effect.gen(function* () {
444
+ const initNode = getOptionalNode(node, "init");
445
+ const testNode = getOptionalNode(node, "test");
446
+ const updateNode = getOptionalNode(node, "update");
447
+ const bodyNode = getNode(node, "body");
448
+ if (initNode?.type === "VariableDeclaration" && getString(initNode, "kind") !== "var") {
449
+ self.predeclareLexical([initNode]);
450
+ }
451
+ if (initNode) {
452
+ if (initNode.type === "VariableDeclaration") {
453
+ yield* self.evaluateVariableDeclaration(initNode);
454
+ }
455
+ else {
456
+ yield* self.evaluateExpression(initNode);
457
+ }
458
+ }
459
+ const perIterationBindings = initNode?.type === "VariableDeclaration" && getString(initNode, "kind") !== "var"
460
+ ? Array.from(self.scopes.current().keys())
461
+ : [];
462
+ const nextIteration = () => {
463
+ if (perIterationBindings.length === 0)
464
+ return;
465
+ const current = self.scopes.current();
466
+ self.scopes.pop();
467
+ self.scopes.push(new Map(perIterationBindings.map((name) => [name, { ...current.get(name) }])));
468
+ };
469
+ nextIteration();
470
+ while (testNode ? yield* self.evaluateExpression(testNode) : true) {
471
+ const result = yield* self.evaluateStatement(bodyNode);
472
+ if (result.kind === "return") {
473
+ return result;
474
+ }
475
+ if (result.kind === "break") {
476
+ if (result.label !== undefined && !labels?.has(result.label))
477
+ return result;
478
+ return { kind: "none" };
479
+ }
480
+ if (result.kind === "continue" && result.label !== undefined && !labels?.has(result.label))
481
+ return result;
482
+ nextIteration();
483
+ if (updateNode) {
484
+ yield* self.evaluateExpression(updateNode);
485
+ }
486
+ if (result.kind === "continue") {
487
+ continue;
488
+ }
489
+ }
490
+ return { kind: "none" };
491
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
492
+ }
493
+ evaluateForOfStatement(node, labels) {
494
+ const awaiting = getBoolean(node, "await");
495
+ const left = getNode(node, "left");
496
+ const declared = loopDeclaration(left, "for...of");
497
+ if (declared?.lexical)
498
+ this.scopes.push();
499
+ const self = this;
500
+ return Effect.gen(function* () {
501
+ if (declared?.lexical)
502
+ self.predeclarePattern(declared.pattern, declared.mutable, left);
503
+ const right = yield* self.evaluateExpression(getNode(node, "right"));
504
+ const body = getNode(node, "body");
505
+ const iterator = yield* self.customIterator(right, node, awaiting);
506
+ const cursor = iterator === undefined ? yield* self.syncIterator(right, node) : undefined;
507
+ if (iterator === undefined && cursor === undefined) {
508
+ throw new InterpreterRuntimeError(`${awaiting ? "for await...of" : "for...of"} requires an array, string, Map, Set, or URLSearchParams, or custom iterator value.`, node).as("TypeError");
509
+ }
510
+ const close = () => iterator
511
+ ? self.closeIterator(iterator, node, awaiting)
512
+ : awaiting
513
+ ? Effect.andThen(cursor?.close ?? Effect.void, Effect.yieldNow)
514
+ : (cursor?.close ?? Effect.void);
515
+ let assignment;
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") {
524
+ throw new InterpreterRuntimeError("Unsupported for...of binding.", left);
525
+ }
526
+ const evaluateBody = (value) => Effect.gen(function* () {
527
+ if (declared) {
528
+ self.scopes.push();
529
+ if (declared.lexical)
530
+ self.predeclarePattern(declared.pattern, declared.mutable, left);
531
+ yield* self.declarePattern(declared.pattern, value, declared.mutable, left, declared.lexical);
532
+ }
533
+ else if (assignment) {
534
+ yield* self.assignPattern(assignment, value, left);
535
+ }
536
+ return yield* self.evaluateStatement(body);
537
+ }).pipe(Effect.ensuring(Effect.sync(() => {
538
+ if (declared)
539
+ self.scopes.pop();
540
+ })));
541
+ while (true) {
542
+ const current = iterator
543
+ ? yield* self.nextIteratorResult(iterator, node, awaiting)
544
+ : yield* cursor?.next ?? Effect.fail(new InterpreterRuntimeError("Iterator is unavailable.", node));
545
+ const step = cursor && awaiting ? { done: current.done, value: yield* self.awaitValue(current.value) } : current;
546
+ if (step.done)
547
+ return { kind: "none" };
548
+ const bodyExit = yield* Effect.exit(evaluateBody(step.value));
549
+ if (!Exit.isSuccess(bodyExit)) {
550
+ // Process interruption must remain prompt; user cleanup cannot extend a timeout.
551
+ if (!Cause.hasInterruptsOnly(bodyExit.cause)) {
552
+ yield* Effect.exit(close());
553
+ }
554
+ return yield* Effect.failCause(bodyExit.cause);
555
+ }
556
+ const result = bodyExit.value;
557
+ if (result.kind === "return") {
558
+ yield* close();
559
+ return result;
560
+ }
561
+ if (result.kind === "break") {
562
+ yield* close();
563
+ if (result.label !== undefined && !labels?.has(result.label))
564
+ return result;
565
+ return { kind: "none" };
566
+ }
567
+ if (result.kind === "continue" && result.label !== undefined && !labels?.has(result.label)) {
568
+ yield* close();
569
+ return result;
570
+ }
571
+ }
572
+ }).pipe(Effect.ensuring(Effect.sync(() => {
573
+ if (declared?.lexical)
574
+ self.scopes.pop();
575
+ })));
576
+ }
577
+ awaitValue(value, node = promiseResolutionNode) {
578
+ return Effect.flatMap(resolvePromise(this.runner, this.promises, value, node), (promise) => this.settlePromise(promise));
579
+ }
580
+ awaitAsyncFromSyncValue(iterator, value, node, closeOnRejection) {
581
+ const self = this;
582
+ return Effect.gen(function* () {
583
+ const settled = yield* Effect.exit(self.awaitValue(value));
584
+ if (Exit.isSuccess(settled))
585
+ return settled.value;
586
+ if (closeOnRejection && !Cause.hasInterruptsOnly(settled.cause)) {
587
+ yield* Effect.exit(self.closeIterator(iterator, node, false));
588
+ }
589
+ return yield* Effect.failCause(settled.cause);
590
+ });
591
+ }
592
+ syncIterator(value, node) {
593
+ const iterator = Array.isArray(value)
594
+ ? value[Symbol.iterator]()
595
+ : typeof value === "string"
596
+ ? value[Symbol.iterator]()
597
+ : value instanceof CodeModeMap
598
+ ? value.map.entries()
599
+ : value instanceof CodeModeSet
600
+ ? value.set.values()
601
+ : value instanceof CodeModeURLSearchParams
602
+ ? value.params.entries()
603
+ : undefined;
604
+ if (iterator !== undefined) {
605
+ return Effect.succeed({
606
+ next: Effect.sync(() => {
607
+ const step = iterator.next();
608
+ return { done: Boolean(step.done), value: step.value };
609
+ }),
610
+ close: Effect.void,
611
+ });
612
+ }
613
+ const self = this;
614
+ return Effect.map(this.customIterator(value, node, false), (iterator) => iterator === undefined
615
+ ? undefined
616
+ : {
617
+ next: self.nextIteratorResult(iterator, node, false),
618
+ close: Effect.suspend(() => self.closeIterator(iterator, node, false)),
619
+ });
620
+ }
621
+ customIterator(value, node, allowAsync = true) {
622
+ if (value instanceof CodeModeGenerator) {
623
+ if (value.asynchronous && !allowAsync)
624
+ return Effect.succeed(undefined);
625
+ return Effect.succeed({
626
+ iterator: value,
627
+ next: new GeneratorMethodReference(value, "next"),
628
+ asynchronous: value.asynchronous,
629
+ });
630
+ }
631
+ if (!isRecord(value) || isRuntimeReference(value))
632
+ return Effect.succeed(undefined);
633
+ const asyncMethod = allowAsync ? Reflect.get(value, AsyncIteratorSymbol) : undefined;
634
+ const method = asyncMethod ?? Reflect.get(value, IteratorSymbol);
635
+ if (method === undefined || method === null)
636
+ return Effect.succeed(undefined);
637
+ const self = this;
638
+ return Effect.map(this.invokeCallable(this.requireIteratorMethod(method, "Iterator method", node), [], node), (iterator) => {
639
+ const object = self.requireIterator(iterator, node);
640
+ return {
641
+ iterator: object,
642
+ next: object instanceof CodeModeGenerator
643
+ ? new GeneratorMethodReference(object, "next")
644
+ : self.requireIteratorMethod(object.next, "Iterator next", node),
645
+ asynchronous: asyncMethod !== undefined && asyncMethod !== null,
646
+ };
647
+ });
648
+ }
649
+ nextIteratorResult(iterator, node, awaiting) {
650
+ const self = this;
651
+ return Effect.gen(function* () {
652
+ if (iterator.asynchronous) {
653
+ const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(iterator.next, [], node)), "Iterator next() result", node);
654
+ return { done: Boolean(object.done), value: object.value };
655
+ }
656
+ const called = yield* Effect.exit(self.invokeCallable(iterator.next, [], node));
657
+ if (!Exit.isSuccess(called)) {
658
+ if (awaiting)
659
+ yield* Effect.yieldNow;
660
+ return yield* Effect.failCause(called.cause);
661
+ }
662
+ const captured = yield* Effect.exit(Effect.sync(() => {
663
+ const object = self.requireIteratorObject(called.value, "Iterator next() result", node);
664
+ return { done: Boolean(object.done), value: object.value };
665
+ }));
666
+ if (!Exit.isSuccess(captured)) {
667
+ if (awaiting)
668
+ yield* Effect.yieldNow;
669
+ return yield* Effect.failCause(captured.cause);
670
+ }
671
+ return {
672
+ done: captured.value.done,
673
+ value: awaiting
674
+ ? yield* self.awaitAsyncFromSyncValue(iterator, captured.value.value, node, !captured.value.done)
675
+ : captured.value.value,
676
+ };
677
+ });
678
+ }
679
+ closeIterator(iterator, node, awaiting = true) {
680
+ const close = iterator.iterator instanceof CodeModeGenerator
681
+ ? new GeneratorMethodReference(iterator.iterator, "return")
682
+ : iterator.iterator.return;
683
+ if (close === undefined || close === null)
684
+ return iterator.asynchronous || !awaiting ? Effect.void : Effect.yieldNow;
685
+ const self = this;
686
+ return Effect.gen(function* () {
687
+ const method = self.requireIteratorMethod(close, "Iterator return", node);
688
+ if (iterator.asynchronous) {
689
+ self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(method, [], node)), "Iterator return() result", node);
690
+ return;
691
+ }
692
+ const called = yield* Effect.exit(self.invokeCallable(method, [], node));
693
+ if (!Exit.isSuccess(called)) {
694
+ if (awaiting)
695
+ yield* Effect.yieldNow;
696
+ return yield* Effect.failCause(called.cause);
697
+ }
698
+ const captured = yield* Effect.exit(Effect.sync(() => self.requireIteratorObject(called.value, "Iterator return() result", node).value));
699
+ if (!Exit.isSuccess(captured)) {
700
+ if (awaiting)
701
+ yield* Effect.yieldNow;
702
+ return yield* Effect.failCause(captured.cause);
703
+ }
704
+ if (awaiting)
705
+ yield* self.awaitValue(captured.value);
706
+ });
707
+ }
708
+ requireIteratorObject(value, context, node) {
709
+ if (isRecord(value) && !isRuntimeReference(value))
710
+ return value;
711
+ throw new InterpreterRuntimeError(`${context} must be an object.`, node).as("TypeError");
712
+ }
713
+ requireIterator(value, node) {
714
+ return value instanceof CodeModeGenerator
715
+ ? value
716
+ : this.requireIteratorObject(value, "Iterator method result", node);
717
+ }
718
+ requireIteratorMethod(value, context, node) {
719
+ if (typeofValue(value) === "function")
720
+ return value;
721
+ throw new InterpreterRuntimeError(`${context} must be a function.`, node).as("TypeError");
722
+ }
723
+ enumerableKeys(value) {
724
+ if (value instanceof ToolReference) {
725
+ return [...this.toolKeys(value.path)];
726
+ }
727
+ if (Array.isArray(value)) {
728
+ return Object.keys(value);
729
+ }
730
+ if (value !== null && typeof value === "object" && !isRuntimeReference(value)) {
731
+ return Object.keys(value);
732
+ }
733
+ return undefined;
734
+ }
735
+ evaluateForInStatement(node, labels) {
736
+ const left = getNode(node, "left");
737
+ const declared = loopDeclaration(left, "for...in");
738
+ if (declared?.lexical)
739
+ this.scopes.push();
740
+ const self = this;
741
+ return Effect.gen(function* () {
742
+ if (declared?.lexical)
743
+ self.predeclarePattern(declared.pattern, declared.mutable, left);
744
+ const right = yield* self.evaluateExpression(getNode(node, "right"));
745
+ const body = getNode(node, "body");
746
+ const keys = self.enumerableKeys(right);
747
+ if (keys === undefined) {
748
+ 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
+ }
750
+ let assignmentName;
751
+ if (left.type === "Identifier") {
752
+ assignmentName = getString(left, "name");
753
+ }
754
+ else if (left.type !== "VariableDeclaration") {
755
+ throw new InterpreterRuntimeError("Unsupported for...in binding.", left);
756
+ }
757
+ for (const key of keys) {
758
+ const result = yield* Effect.gen(function* () {
759
+ if (declared) {
760
+ self.scopes.push();
761
+ if (declared.lexical)
762
+ self.predeclarePattern(declared.pattern, declared.mutable, left);
763
+ yield* self.declarePattern(declared.pattern, key, declared.mutable, left, declared.lexical);
764
+ }
765
+ else if (assignmentName) {
766
+ self.scopes.set(assignmentName, key, left);
767
+ }
768
+ return yield* self.evaluateStatement(body);
769
+ }).pipe(Effect.ensuring(Effect.sync(() => {
770
+ if (declared)
771
+ self.scopes.pop();
772
+ })));
773
+ if (result.kind === "return") {
774
+ return result;
775
+ }
776
+ if (result.kind === "break") {
777
+ if (result.label !== undefined && !labels?.has(result.label))
778
+ return result;
779
+ return { kind: "none" };
780
+ }
781
+ if (result.kind === "continue") {
782
+ if (result.label !== undefined && !labels?.has(result.label))
783
+ return result;
784
+ continue;
785
+ }
786
+ }
787
+ return { kind: "none" };
788
+ }).pipe(Effect.ensuring(Effect.sync(() => {
789
+ if (declared?.lexical)
790
+ self.scopes.pop();
791
+ })));
792
+ }
793
+ evaluateBreakStatement(node) {
794
+ const labelNode = getOptionalNode(node, "label");
795
+ return labelNode ? { kind: "break", label: getString(labelNode, "name") } : { kind: "break" };
796
+ }
797
+ evaluateContinueStatement(node) {
798
+ const labelNode = getOptionalNode(node, "label");
799
+ return labelNode ? { kind: "continue", label: getString(labelNode, "name") } : { kind: "continue" };
800
+ }
801
+ evaluateLabeledStatement(node) {
802
+ const labels = new Set();
803
+ let body = node;
804
+ while (body.type === "LabeledStatement") {
805
+ labels.add(getString(getNode(body, "label"), "name"));
806
+ body = getNode(body, "body");
807
+ }
808
+ const evaluated = (() => {
809
+ if (body.type === "WhileStatement")
810
+ return this.evaluateWhileStatement(body, labels);
811
+ if (body.type === "DoWhileStatement")
812
+ return this.evaluateDoWhileStatement(body, labels);
813
+ if (body.type === "ForStatement")
814
+ return this.evaluateForStatement(body, labels);
815
+ if (body.type === "ForOfStatement")
816
+ return this.evaluateForOfStatement(body, labels);
817
+ if (body.type === "ForInStatement")
818
+ return this.evaluateForInStatement(body, labels);
819
+ return this.evaluateStatement(body);
820
+ })();
821
+ return Effect.map(evaluated, (result) => result.kind === "break" && result.label !== undefined && labels.has(result.label)
822
+ ? { kind: "none" }
823
+ : result);
824
+ }
825
+ evaluateThrowStatement(node) {
826
+ const argument = getNode(node, "argument");
827
+ return Effect.flatMap(this.evaluateExpression(argument), (value) => Effect.fail(new ProgramThrow(value)));
828
+ }
829
+ evaluateTryStatement(node) {
830
+ const body = getNode(node, "block");
831
+ const handler = getOptionalNode(node, "handler");
832
+ const finalizer = getOptionalNode(node, "finalizer");
833
+ const self = this;
834
+ const attempted = Effect.matchCauseEffect(this.evaluateStatement(body), {
835
+ onFailure: (cause) => {
836
+ if (cause.reasons.some(Cause.isInterruptReason) || Cause.squash(cause) instanceof GeneratorReturn || !handler) {
837
+ return Effect.failCause(cause);
838
+ }
839
+ const caught = caughtErrorValue(Cause.squash(cause));
840
+ const parameter = getOptionalNode(handler, "param");
841
+ self.scopes.push();
842
+ return Effect.gen(function* () {
843
+ if (parameter)
844
+ yield* self.declarePattern(parameter, caught, true, handler);
845
+ return yield* self.evaluateStatement(getNode(handler, "body"));
846
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
847
+ },
848
+ onSuccess: Effect.succeed,
849
+ });
850
+ if (!finalizer)
851
+ return attempted;
852
+ const isAbrupt = (result) => result.kind === "return" || result.kind === "break" || result.kind === "continue";
853
+ return Effect.matchCauseEffect(attempted, {
854
+ onFailure: (cause) => cause.reasons.some(Cause.isInterruptReason)
855
+ ? Effect.failCause(cause)
856
+ : Effect.flatMap(this.evaluateStatement(finalizer), (final) => isAbrupt(final) ? Effect.succeed(final) : Effect.failCause(cause)),
857
+ onSuccess: (result) => Effect.flatMap(this.evaluateStatement(finalizer), (final) => isAbrupt(final) ? Effect.succeed(final) : Effect.succeed(result)),
858
+ });
859
+ }
860
+ evaluateVariableDeclaration(node) {
861
+ const kind = getString(node, "kind");
862
+ const declarations = getArray(node, "declarations");
863
+ const self = this;
864
+ return Effect.gen(function* () {
865
+ for (const declarationValue of declarations) {
866
+ const declaration = asNode(declarationValue, "declarations");
867
+ if (declaration.type !== "VariableDeclarator") {
868
+ throw new InterpreterRuntimeError("Unsupported variable declaration shape.", declaration);
869
+ }
870
+ const init = getOptionalNode(declaration, "init");
871
+ const value = init ? yield* self.evaluateExpression(init) : undefined;
872
+ yield* self.declarePattern(getNode(declaration, "id"), value, kind !== "const", declaration, kind !== "var");
873
+ }
874
+ });
875
+ }
876
+ declarePattern(pattern, value, mutable, node, initialize = false) {
877
+ const self = this;
878
+ return Effect.gen(function* () {
879
+ if (pattern.type === "Identifier") {
880
+ const name = getString(pattern, "name");
881
+ if (initialize)
882
+ self.scopes.initialize(name, value, node);
883
+ else
884
+ self.scopes.declare(name, value, mutable, node);
885
+ return;
886
+ }
887
+ if (pattern.type === "AssignmentPattern") {
888
+ const resolved = value === undefined ? yield* self.evaluateExpression(getNode(pattern, "right")) : value;
889
+ yield* self.declarePattern(getNode(pattern, "left"), resolved, mutable, node, initialize);
890
+ return;
891
+ }
892
+ if (pattern.type === "ObjectPattern") {
893
+ if (value === null || typeof value !== "object" || isRuntimeReference(value)) {
894
+ throw new InterpreterRuntimeError("Object destructuring requires a data object or array value.", pattern, "InvalidDataValue");
895
+ }
896
+ const consumed = new Set();
897
+ for (const propertyValue of getArray(pattern, "properties")) {
898
+ const property = asNode(propertyValue, "properties");
899
+ if (property.type === "RestElement") {
900
+ const rest = Object.create(null);
901
+ for (const [key, item] of Object.entries(value)) {
902
+ if (!consumed.has(key) && !isBlockedMember(key))
903
+ rest[key] = item;
904
+ }
905
+ copyIteratorSymbols(value, rest, consumed);
906
+ yield* self.declarePattern(getNode(property, "argument"), rest, mutable, property, initialize);
907
+ continue;
908
+ }
909
+ const key = yield* self.destructuringPropertyKey(property);
910
+ if (isBlockedMember(String(key))) {
911
+ throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, property);
912
+ }
913
+ consumed.add(typeof key === "symbol" ? key : String(key));
914
+ yield* self.declarePattern(getNode(property, "value"), self.destructuringPropertyValue(value, key), mutable, property, initialize);
915
+ }
916
+ return;
917
+ }
918
+ if (pattern.type === "ArrayPattern") {
919
+ return yield* self.destructureArrayPattern(pattern, value, (target, item, context) => self.declarePattern(target, item, mutable, context, initialize));
920
+ }
921
+ throw new InterpreterRuntimeError(`Unsupported binding pattern '${pattern.type}'.`, pattern);
922
+ });
923
+ }
924
+ assignPattern(pattern, value, node) {
925
+ const self = this;
926
+ return Effect.gen(function* () {
927
+ if (pattern.type === "Identifier") {
928
+ self.scopes.set(getString(pattern, "name"), value, pattern);
929
+ return;
930
+ }
931
+ if (pattern.type === "MemberExpression") {
932
+ yield* self.writeMember(pattern, value);
933
+ return;
934
+ }
935
+ if (pattern.type === "AssignmentPattern") {
936
+ const resolved = value === undefined ? yield* self.evaluateExpression(getNode(pattern, "right")) : value;
937
+ yield* self.assignPattern(getNode(pattern, "left"), resolved, node);
938
+ return;
939
+ }
940
+ if (pattern.type === "ObjectPattern") {
941
+ if (value === null || typeof value !== "object" || isRuntimeReference(value)) {
942
+ throw new InterpreterRuntimeError("Object destructuring requires a data object or array value.", pattern, "InvalidDataValue");
943
+ }
944
+ const source = value;
945
+ const consumed = new Set();
946
+ for (const propertyValue of getArray(pattern, "properties")) {
947
+ const property = asNode(propertyValue, "properties");
948
+ if (property.type === "RestElement") {
949
+ const rest = Object.create(null);
950
+ for (const [key, item] of Object.entries(source)) {
951
+ if (!consumed.has(key) && !isBlockedMember(key))
952
+ rest[key] = item;
953
+ }
954
+ copyIteratorSymbols(source, rest, consumed);
955
+ yield* self.assignPattern(getNode(property, "argument"), rest, property);
956
+ continue;
957
+ }
958
+ const key = yield* self.destructuringPropertyKey(property);
959
+ if (isBlockedMember(String(key))) {
960
+ throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, property);
961
+ }
962
+ consumed.add(typeof key === "symbol" ? key : String(key));
963
+ yield* self.assignPattern(getNode(property, "value"), self.destructuringPropertyValue(source, key), property);
964
+ }
965
+ return;
966
+ }
967
+ if (pattern.type === "ArrayPattern") {
968
+ return yield* self.destructureArrayPattern(pattern, value, (target, item, context) => self.assignPattern(target, item, context));
969
+ }
970
+ throw new InterpreterRuntimeError(`Unsupported assignment pattern '${pattern.type}'.`, node);
971
+ });
972
+ }
973
+ destructureArrayPattern(pattern, value, consume) {
974
+ const self = this;
975
+ return Effect.gen(function* () {
976
+ const cursor = yield* self.syncIterator(value, pattern);
977
+ if (cursor === undefined) {
978
+ throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern).as("TypeError");
979
+ }
980
+ let done = false;
981
+ for (const [index, item] of getArray(pattern, "elements").entries()) {
982
+ if (done) {
983
+ if (item === null)
984
+ continue;
985
+ const element = asNode(item, `elements[${index}]`);
986
+ yield* consume(element.type === "RestElement" ? getNode(element, "argument") : element, element.type === "RestElement" ? [] : undefined, element);
987
+ if (element.type === "RestElement")
988
+ return;
989
+ continue;
990
+ }
991
+ const step = yield* cursor.next;
992
+ done = step.done;
993
+ if (item === null)
994
+ continue;
995
+ const element = asNode(item, `elements[${index}]`);
996
+ if (element.type === "RestElement") {
997
+ const rest = [];
998
+ if (!step.done)
999
+ rest.push(step.value);
1000
+ while (!done) {
1001
+ const next = yield* cursor.next;
1002
+ done = next.done;
1003
+ if (!done)
1004
+ rest.push(next.value);
1005
+ }
1006
+ yield* consume(getNode(element, "argument"), rest, element);
1007
+ return;
1008
+ }
1009
+ const consumed = consume(element, step.done ? undefined : step.value, pattern);
1010
+ yield* step.done ? consumed : preserveConsumerError(cursor, consumed);
1011
+ }
1012
+ if (!done)
1013
+ yield* cursor.close;
1014
+ });
1015
+ }
1016
+ destructuringPropertyKey(property) {
1017
+ if (property.type !== "Property" || getString(property, "kind") !== "init") {
1018
+ throw new InterpreterRuntimeError("Unsupported object destructuring property.", property);
1019
+ }
1020
+ const keyNode = getNode(property, "key");
1021
+ if (getBoolean(property, "computed")) {
1022
+ return Effect.map(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value, keyNode));
1023
+ }
1024
+ return Effect.succeed(keyNode.type === "Identifier" ? getString(keyNode, "name") : String(keyNode.value));
1025
+ }
1026
+ destructuringPropertyValue(source, key) {
1027
+ if (!Array.isArray(source))
1028
+ return Reflect.get(source, key);
1029
+ if (key === "length")
1030
+ return source.length;
1031
+ if (typeof key === "number")
1032
+ return source[key];
1033
+ if (Object.hasOwn(source, key))
1034
+ return Reflect.get(source, key);
1035
+ if (typeof key === "string" && arrayMethods.has(key))
1036
+ return new IntrinsicReference(source, key);
1037
+ return undefined;
1038
+ }
1039
+ evaluateExpression(node) {
1040
+ switch (node.type) {
1041
+ case "Literal": {
1042
+ const regex = node.regex;
1043
+ if (isRecord(regex) && typeof regex.pattern === "string") {
1044
+ return Effect.sync(() => this.constructRegExp([regex.pattern, typeof regex.flags === "string" ? regex.flags : ""], node));
1045
+ }
1046
+ return Effect.sync(() => boundedData(node.value, "Literal"));
1047
+ }
1048
+ case "Identifier":
1049
+ return Effect.sync(() => this.scopes.get(getString(node, "name"), node));
1050
+ case "BinaryExpression":
1051
+ return this.evaluateBinaryExpression(node);
1052
+ case "LogicalExpression":
1053
+ return this.evaluateLogicalExpression(node);
1054
+ case "UnaryExpression":
1055
+ return this.evaluateUnaryExpression(node);
1056
+ case "AssignmentExpression":
1057
+ return this.evaluateAssignmentExpression(node);
1058
+ case "SequenceExpression": {
1059
+ const self = this;
1060
+ return Effect.gen(function* () {
1061
+ let result;
1062
+ for (const expression of getArray(node, "expressions")) {
1063
+ result = yield* self.evaluateExpression(asNode(expression, "expressions"));
1064
+ }
1065
+ return result;
1066
+ });
1067
+ }
1068
+ case "CallExpression":
1069
+ return this.evaluateCallExpression(node);
1070
+ case "ArrowFunctionExpression":
1071
+ case "FunctionExpression":
1072
+ return Effect.sync(() => this.createFunction(node));
1073
+ case "MemberExpression":
1074
+ return this.readMember(node);
1075
+ case "ChainExpression":
1076
+ return Effect.map(this.evaluateExpression(getNode(node, "expression")), (value) => value === OptionalShortCircuit ? undefined : value);
1077
+ case "ObjectExpression":
1078
+ return this.evaluateObjectExpression(node);
1079
+ case "ArrayExpression":
1080
+ return this.evaluateArrayExpression(node);
1081
+ case "TemplateLiteral":
1082
+ return this.evaluateTemplateLiteral(node);
1083
+ case "ConditionalExpression":
1084
+ return this.evaluateConditionalExpression(node);
1085
+ case "UpdateExpression":
1086
+ return this.evaluateUpdateExpression(node);
1087
+ case "AwaitExpression": {
1088
+ // Await always suspends, including for plain values.
1089
+ return Effect.flatMap(this.evaluateExpression(getNode(node, "argument")), (value) => this.awaitValue(value, node));
1090
+ }
1091
+ case "YieldExpression":
1092
+ return this.evaluateYieldExpression(node);
1093
+ case "NewExpression":
1094
+ return this.evaluateNewExpression(node);
1095
+ default:
1096
+ throw unsupportedSyntax(node.type, node);
1097
+ }
1098
+ }
1099
+ 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
+ const self = this;
1244
+ return Effect.gen(function* () {
1245
+ const cursor = yield* self.syncIterator(init, node);
1246
+ if (cursor === undefined) {
1247
+ throw new InterpreterRuntimeError("new Set(...) expects a synchronous iterable or no argument.", node).as("TypeError");
1248
+ }
1249
+ while (true) {
1250
+ const step = yield* cursor.next;
1251
+ if (step.done)
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
+ }
1323
+ });
1324
+ }
1325
+ evaluateBinaryExpression(node) {
1326
+ const operator = getString(node, "operator");
1327
+ const self = this;
1328
+ return Effect.gen(function* () {
1329
+ const lhs = yield* self.evaluateExpression(getNode(node, "left"));
1330
+ const rhs = yield* self.evaluateExpression(getNode(node, "right"));
1331
+ if (operator === "instanceof")
1332
+ return instanceofValue(lhs, rhs, node);
1333
+ return boundedData(self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
1334
+ });
1335
+ }
1336
+ applyBinaryOperator(operator, lhs, rhs, node) {
1337
+ if (operator === "===")
1338
+ return lhs === rhs;
1339
+ if (operator === "!==")
1340
+ return lhs !== rhs;
1341
+ if (containsOpaqueReference(lhs) || containsOpaqueReference(rhs)) {
1342
+ throw new InterpreterRuntimeError("Binary operators require data values.", node, "InvalidDataValue");
1343
+ }
1344
+ // Null-prototype data needs explicit primitive coercion; identity and `in` retain raw objects.
1345
+ // Dates use their default string hint for addition and loose equality, and epoch time elsewhere.
1346
+ const coerceOperand = (operand) => {
1347
+ if (operand instanceof CodeModeDate) {
1348
+ return operator === "+" || operator === "==" || operator === "!=" ? coerceToString(operand) : operand.time;
1349
+ }
1350
+ return operand !== null && typeof operand === "object" ? coerceToString(operand) : operand;
1351
+ };
1352
+ const bothObjects = lhs !== null && typeof lhs === "object" && rhs !== null && typeof rhs === "object";
1353
+ const l = coerceOperand(lhs);
1354
+ const r = coerceOperand(rhs);
1355
+ switch (operator) {
1356
+ case "+":
1357
+ return l + r;
1358
+ case "-":
1359
+ return l - r;
1360
+ case "*":
1361
+ return l * r;
1362
+ case "/":
1363
+ return l / r;
1364
+ case "%":
1365
+ return l % r;
1366
+ case "**":
1367
+ return l ** r;
1368
+ case "==":
1369
+ return bothObjects ? lhs === rhs : l == r;
1370
+ case "!=":
1371
+ return bothObjects ? lhs !== rhs : l != r;
1372
+ case "<":
1373
+ return l < r;
1374
+ case "<=":
1375
+ return l <= r;
1376
+ case ">":
1377
+ return l > r;
1378
+ case ">=":
1379
+ return l >= r;
1380
+ case "&":
1381
+ return l & r;
1382
+ case "|":
1383
+ return l | r;
1384
+ case "^":
1385
+ return l ^ r;
1386
+ case "<<":
1387
+ return l << r;
1388
+ case ">>":
1389
+ return l >> r;
1390
+ case ">>>":
1391
+ return l >>> r;
1392
+ case "in":
1393
+ if (rhs === null || typeof rhs !== "object") {
1394
+ throw new InterpreterRuntimeError("The 'in' operator requires a data object on the right-hand side.", node);
1395
+ }
1396
+ // Never expose properties inherited from host prototypes.
1397
+ return Object.hasOwn(rhs, coerceOperand(lhs));
1398
+ default:
1399
+ throw new InterpreterRuntimeError(`Unsupported binary operator '${operator}'.`, node);
1400
+ }
1401
+ }
1402
+ evaluateLogicalExpression(node) {
1403
+ const operator = getString(node, "operator");
1404
+ return Effect.flatMap(this.evaluateExpression(getNode(node, "left")), (left) => {
1405
+ if (operator === "&&")
1406
+ return left ? this.evaluateExpression(getNode(node, "right")) : Effect.succeed(left);
1407
+ if (operator === "||")
1408
+ return left ? Effect.succeed(left) : this.evaluateExpression(getNode(node, "right"));
1409
+ if (operator === "??")
1410
+ return left !== null && left !== undefined
1411
+ ? Effect.succeed(left)
1412
+ : this.evaluateExpression(getNode(node, "right"));
1413
+ throw new InterpreterRuntimeError(`Unsupported logical operator '${operator}'.`, node);
1414
+ });
1415
+ }
1416
+ evaluateUnaryExpression(node) {
1417
+ const operator = getString(node, "operator");
1418
+ const argument = getNode(node, "argument");
1419
+ if (operator === "delete")
1420
+ return this.evaluateDeleteExpression(argument);
1421
+ // Undeclared names short-circuit, but declared TDZ bindings must still throw.
1422
+ if (operator === "typeof" && argument.type === "Identifier" && !this.scopes.resolve(getString(argument, "name"))) {
1423
+ return Effect.succeed("undefined");
1424
+ }
1425
+ return Effect.map(this.evaluateExpression(argument), (value) => {
1426
+ if (operator === "typeof")
1427
+ return typeofValue(value);
1428
+ if (operator === "!")
1429
+ return !value;
1430
+ if (operator === "void")
1431
+ return undefined;
1432
+ if (containsOpaqueReference(value)) {
1433
+ throw new InterpreterRuntimeError("Unary operators require data values.", node, "InvalidDataValue");
1434
+ }
1435
+ const operand = value instanceof CodeModeDate
1436
+ ? value.time
1437
+ : value !== null && typeof value === "object"
1438
+ ? coerceToString(value)
1439
+ : value;
1440
+ let result;
1441
+ switch (operator) {
1442
+ case "+":
1443
+ result = +operand;
1444
+ break;
1445
+ case "-":
1446
+ result = -operand;
1447
+ break;
1448
+ case "~":
1449
+ result = ~operand;
1450
+ break;
1451
+ default:
1452
+ throw new InterpreterRuntimeError(`Unsupported unary operator '${operator}'.`, node);
1453
+ }
1454
+ return boundedData(result, "Unary expression result");
1455
+ });
1456
+ }
1457
+ evaluateAssignmentExpression(node) {
1458
+ const left = getNode(node, "left");
1459
+ const operator = getString(node, "operator");
1460
+ const self = this;
1461
+ return Effect.gen(function* () {
1462
+ if (operator === "??=" || operator === "||=" || operator === "&&=") {
1463
+ return yield* self.evaluateLogicalAssignment(node, left, operator);
1464
+ }
1465
+ if (operator === "=" && (left.type === "ObjectPattern" || left.type === "ArrayPattern")) {
1466
+ const rightValue = yield* self.evaluateExpression(getNode(node, "right"));
1467
+ yield* self.assignPattern(left, rightValue, node);
1468
+ return rightValue;
1469
+ }
1470
+ if (left.type === "Identifier") {
1471
+ const name = getString(left, "name");
1472
+ if (operator !== "=") {
1473
+ const current = self.scopes.get(name, left);
1474
+ const rightValue = yield* self.evaluateExpression(getNode(node, "right"));
1475
+ const next = boundedData(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1476
+ return self.scopes.set(name, next, left);
1477
+ }
1478
+ const rightValue = yield* self.evaluateExpression(getNode(node, "right"));
1479
+ return self.scopes.set(name, rightValue, left);
1480
+ }
1481
+ if (left.type === "MemberExpression") {
1482
+ return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(getNode(node, "right")), (rightValue) => {
1483
+ if (operator === "=")
1484
+ return { write: true, next: rightValue, result: rightValue };
1485
+ const next = boundedData(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1486
+ return { write: true, next, result: next };
1487
+ }));
1488
+ }
1489
+ throw new InterpreterRuntimeError("Assignment target must be an Identifier or MemberExpression.", left);
1490
+ });
1491
+ }
1492
+ evaluateLogicalAssignment(node, left, operator) {
1493
+ const self = this;
1494
+ const shouldAssign = (current) => operator === "??=" ? current === null || current === undefined : operator === "||=" ? !current : Boolean(current);
1495
+ if (left.type === "Identifier") {
1496
+ const name = getString(left, "name");
1497
+ return Effect.gen(function* () {
1498
+ const current = self.scopes.get(name, left);
1499
+ if (!shouldAssign(current))
1500
+ return current;
1501
+ const rightValue = yield* self.evaluateExpression(getNode(node, "right"));
1502
+ return self.scopes.set(name, rightValue, left);
1503
+ });
1504
+ }
1505
+ if (left.type === "MemberExpression") {
1506
+ return self.modifyMember(left, (current) => shouldAssign(current)
1507
+ ? Effect.map(self.evaluateExpression(getNode(node, "right")), (rightValue) => ({
1508
+ write: true,
1509
+ next: rightValue,
1510
+ result: rightValue,
1511
+ }))
1512
+ : Effect.succeed({ write: false, next: current, result: current }));
1513
+ }
1514
+ throw new InterpreterRuntimeError("Assignment target must be an Identifier or MemberExpression.", left);
1515
+ }
1516
+ evaluateUpdateExpression(node) {
1517
+ const operator = getString(node, "operator");
1518
+ const argument = getNode(node, "argument");
1519
+ const prefix = getBoolean(node, "prefix");
1520
+ const increment = operator === "++" ? 1 : operator === "--" ? -1 : undefined;
1521
+ if (increment === undefined) {
1522
+ throw new InterpreterRuntimeError(`Unsupported update operator '${operator}'.`, node);
1523
+ }
1524
+ // CodeMode numeric coercion, not host Number(): null-prototype data objects would make
1525
+ // the host throw during ToPrimitive, and opaque runtime references must reject clearly.
1526
+ const operand = (current) => {
1527
+ if (containsOpaqueReference(current)) {
1528
+ throw new InterpreterRuntimeError(`'${operator}' requires a data value.`, argument, "InvalidDataValue");
1529
+ }
1530
+ return coerceToNumber(current);
1531
+ };
1532
+ if (argument.type === "Identifier") {
1533
+ return Effect.sync(() => {
1534
+ const name = getString(argument, "name");
1535
+ const current = operand(this.scopes.get(name, argument));
1536
+ const next = current + increment;
1537
+ this.scopes.set(name, next, argument);
1538
+ return prefix ? next : current;
1539
+ });
1540
+ }
1541
+ if (argument.type === "MemberExpression") {
1542
+ return this.modifyMember(argument, (current) => {
1543
+ const value = operand(current);
1544
+ const next = value + increment;
1545
+ return Effect.succeed({ write: true, next, result: prefix ? next : value });
1546
+ });
1547
+ }
1548
+ throw new InterpreterRuntimeError("Update target must be an Identifier or MemberExpression.", argument);
1549
+ }
1550
+ evaluateCallExpression(node) {
1551
+ const callee = getNode(node, "callee");
1552
+ const argNodes = getArray(node, "arguments");
1553
+ const self = this;
1554
+ return Effect.gen(function* () {
1555
+ const callable = yield* self.evaluateExpression(callee);
1556
+ if (callable === OptionalShortCircuit)
1557
+ return OptionalShortCircuit;
1558
+ if ((callable === null || callable === undefined) && node.optional === true)
1559
+ return OptionalShortCircuit;
1560
+ const args = yield* self.evaluateCallArguments(argNodes);
1561
+ return yield* self.invokeCallable(callable, args, node, callee);
1562
+ });
1563
+ }
1564
+ // The single dispatch for every invocation: call expressions and callbacks share it.
1565
+ invokeCallable(callable, args, node, callee = node) {
1566
+ const self = this;
1567
+ return Effect.gen(function* () {
1568
+ if (callable instanceof ToolReference) {
1569
+ if (callable.path.length === 0)
1570
+ throw new InterpreterRuntimeError("The tools root is not callable.", callee);
1571
+ return yield* self.createToolCallPromise(callable.path, args);
1572
+ }
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
+ if (callable instanceof CodeModeFunction) {
1580
+ return yield* self.invokeFunction(callable, args);
1581
+ }
1582
+ if (callable instanceof GeneratorMethodReference) {
1583
+ if (callable.kind === "iterator")
1584
+ return callable.generator;
1585
+ const requested = callable.generator.request(callable.kind, args[0], node);
1586
+ return callable.generator.asynchronous ? yield* self.createPromise(requested) : yield* requested;
1587
+ }
1588
+ 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`);
1615
+ }
1616
+ if (callable instanceof JsonMethodReference) {
1617
+ return yield* invokeJsonMethod(self.runner, callable.name, args, node);
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;
1659
+ }
1660
+ if (callable === undefined || callable === null) {
1661
+ throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee).as("TypeError");
1662
+ }
1663
+ throw new InterpreterRuntimeError("Only tools are callable here.", callee);
1664
+ });
1665
+ }
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
+ evaluateCallArguments(argNodes) {
1679
+ const self = this;
1680
+ return Effect.gen(function* () {
1681
+ const args = [];
1682
+ for (const [index, arg] of argNodes.entries()) {
1683
+ const argNode = asNode(arg, `arguments[${index}]`);
1684
+ if (argNode.type === "SpreadElement") {
1685
+ const spread = yield* self.evaluateExpression(getNode(argNode, "argument"));
1686
+ const cursor = yield* self.syncIterator(spread, argNode);
1687
+ if (cursor === undefined)
1688
+ throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode).as("TypeError");
1689
+ while (true) {
1690
+ const step = yield* cursor.next;
1691
+ if (step.done)
1692
+ break;
1693
+ args.push(step.value);
1694
+ }
1695
+ }
1696
+ else {
1697
+ args.push(yield* self.evaluateExpression(argNode));
1698
+ }
1699
+ }
1700
+ return args;
1701
+ });
1702
+ }
1703
+ invokeFunction(fn, args) {
1704
+ const invocation = new Interpreter(this.executeTool, this.invokeSearch, this.toolKeys, this.promises, this.logs);
1705
+ invocation.scopes = new ScopeStack([...fn.capturedScopes, new Map()]);
1706
+ const run = Effect.gen(function* () {
1707
+ // Seed all parameters first so defaults cannot fall through to same-named outer bindings.
1708
+ const paramScope = invocation.scopes.current();
1709
+ for (const parameter of fn.parameters) {
1710
+ for (const name of collectPatternNames(parameter)) {
1711
+ paramScope.set(name, { mutable: true, value: undefined, initialized: false });
1712
+ }
1713
+ }
1714
+ for (const [index, parameter] of fn.parameters.entries()) {
1715
+ if (parameter.type === "RestElement") {
1716
+ yield* invocation.declarePattern(getNode(parameter, "argument"), args.slice(index), true, parameter, true);
1717
+ break;
1718
+ }
1719
+ yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
1720
+ }
1721
+ if (fn.body.type === "BlockStatement") {
1722
+ const result = yield* invocation.evaluateStatement(fn.body);
1723
+ return result.kind === "return" ? result.value : undefined;
1724
+ }
1725
+ return yield* invocation.evaluateExpression(fn.body);
1726
+ });
1727
+ if (fn.generator)
1728
+ return Effect.succeed(this.createGenerator(invocation, run, fn.async));
1729
+ if (!fn.async)
1730
+ return run;
1731
+ // The initial yield assigns the promise before the body can self-resolve.
1732
+ const box = {};
1733
+ return Effect.map(this.createPromise(Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runner, value, fn.body, box))), (promise) => {
1734
+ box.promise = promise;
1735
+ return promise;
1736
+ });
1737
+ }
1738
+ createGenerator(invocation, run, asynchronous) {
1739
+ const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
1740
+ invocation.generatorState = state;
1741
+ invocation.generatorAsync = asynchronous;
1742
+ const generator = new CodeModeGenerator(asynchronous, (kind, value, node) => {
1743
+ const request = { kind, value, response: Deferred.makeUnsafe() };
1744
+ if (!asynchronous && state.active) {
1745
+ return Effect.fail(new InterpreterRuntimeError("Generator is already running.", node).as("TypeError"));
1746
+ }
1747
+ if (asynchronous && (state.completed || (!state.started && kind !== "next"))) {
1748
+ state.started = true;
1749
+ state.completed = true;
1750
+ state.pending.push(request);
1751
+ if (state.draining)
1752
+ return Deferred.await(request.response);
1753
+ state.draining = true;
1754
+ return Effect.andThen(this.promises.fork(invocation
1755
+ .completeGeneratorRequests(state, true)
1756
+ .pipe(Effect.ensuring(Effect.sync(() => (state.draining = false))))), Deferred.await(request.response));
1757
+ }
1758
+ if (state.completed) {
1759
+ if (kind === "throw")
1760
+ return Effect.fail(new ProgramThrow(value));
1761
+ return Effect.succeed({ value: kind === "return" ? value : undefined, done: true });
1762
+ }
1763
+ if (!state.started && kind !== "next") {
1764
+ state.completed = true;
1765
+ if (kind === "throw")
1766
+ return Effect.fail(new ProgramThrow(value));
1767
+ return Effect.succeed({ value, done: true });
1768
+ }
1769
+ state.pending.push(request);
1770
+ if (state.available) {
1771
+ const available = state.available;
1772
+ state.available = undefined;
1773
+ Deferred.doneUnsafe(available, Exit.succeed(undefined));
1774
+ }
1775
+ if (!state.started) {
1776
+ state.started = true;
1777
+ const body = Effect.gen(function* () {
1778
+ state.active = yield* invocation.takeGeneratorRequest(state);
1779
+ const exit = yield* Effect.exit(run.pipe(Effect.flatMap((result) => (asynchronous ? invocation.awaitValue(result) : Effect.succeed(result))), Effect.catch((error) => error instanceof GeneratorReturn
1780
+ ? asynchronous
1781
+ ? invocation.awaitValue(error.value)
1782
+ : Effect.succeed(error.value)
1783
+ : Effect.fail(error))));
1784
+ const active = state.active;
1785
+ state.active = undefined;
1786
+ if (active) {
1787
+ Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed({ value: exit.value, done: true }) : exit);
1788
+ }
1789
+ yield* invocation.completeGeneratorRequests(state, asynchronous);
1790
+ state.completed = true;
1791
+ });
1792
+ return Effect.andThen(this.promises.fork(body), Deferred.await(request.response));
1793
+ }
1794
+ return Deferred.await(request.response);
1795
+ });
1796
+ return generator;
1797
+ }
1798
+ completeGeneratorRequests(state, asynchronous) {
1799
+ const self = this;
1800
+ return Effect.gen(function* () {
1801
+ while (true) {
1802
+ const pending = self.dequeueGeneratorRequest(state);
1803
+ if (!pending)
1804
+ return;
1805
+ if (pending.kind === "throw") {
1806
+ Deferred.doneUnsafe(pending.response, Exit.fail(new ProgramThrow(pending.value)));
1807
+ continue;
1808
+ }
1809
+ if (asynchronous && pending.kind === "return") {
1810
+ const resolved = yield* Effect.exit(self.awaitValue(pending.value));
1811
+ Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed({ value: resolved.value, done: true }) : resolved);
1812
+ continue;
1813
+ }
1814
+ Deferred.doneUnsafe(pending.response, Exit.succeed({ value: pending.kind === "return" ? pending.value : undefined, done: true }));
1815
+ }
1816
+ });
1817
+ }
1818
+ takeGeneratorRequest(state) {
1819
+ const next = this.dequeueGeneratorRequest(state);
1820
+ if (next)
1821
+ return Effect.succeed(next);
1822
+ state.available = Deferred.makeUnsafe();
1823
+ return Effect.andThen(Deferred.await(state.available), Effect.sync(() => this.dequeueGeneratorRequest(state)));
1824
+ }
1825
+ dequeueGeneratorRequest(state) {
1826
+ const request = state.pending[state.pendingIndex];
1827
+ if (!request)
1828
+ return undefined;
1829
+ state.pendingIndex += 1;
1830
+ if (state.pendingIndex === state.pending.length) {
1831
+ state.pending = [];
1832
+ state.pendingIndex = 0;
1833
+ }
1834
+ return request;
1835
+ }
1836
+ evaluateYieldExpression(node) {
1837
+ const argument = getOptionalNode(node, "argument");
1838
+ const self = this;
1839
+ return Effect.gen(function* () {
1840
+ if (!self.generatorState)
1841
+ throw new InterpreterRuntimeError("yield is only valid inside a generator.", node);
1842
+ if (node.delegate === true) {
1843
+ const value = argument ? yield* self.evaluateExpression(argument) : undefined;
1844
+ return yield* self.delegateYield(value, node);
1845
+ }
1846
+ const value = argument ? yield* self.evaluateExpression(argument) : undefined;
1847
+ const yielded = self.generatorAsync ? yield* self.awaitValue(value) : value;
1848
+ return yield* self.suspendGenerator(yielded, node);
1849
+ });
1850
+ }
1851
+ suspendGenerator(value, node) {
1852
+ const state = this.generatorState;
1853
+ if (!state?.active)
1854
+ throw new InterpreterRuntimeError("Generator has no active request.", node);
1855
+ Deferred.doneUnsafe(state.active.response, Exit.succeed({ value, done: false }));
1856
+ state.active = undefined;
1857
+ return Effect.flatMap(this.takeGeneratorRequest(state), (request) => {
1858
+ state.active = request;
1859
+ if (request.kind === "next")
1860
+ return Effect.succeed(request.value);
1861
+ if (request.kind === "throw")
1862
+ return Effect.fail(new ProgramThrow(request.value));
1863
+ return this.generatorAsync
1864
+ ? Effect.flatMap(this.awaitValue(request.value), (value) => Effect.fail(new GeneratorReturn(value)))
1865
+ : Effect.fail(new GeneratorReturn(request.value));
1866
+ });
1867
+ }
1868
+ delegateYield(value, node) {
1869
+ const self = this;
1870
+ return Effect.gen(function* () {
1871
+ if (Array.isArray(value) ||
1872
+ typeof value === "string" ||
1873
+ value instanceof CodeModeMap ||
1874
+ value instanceof CodeModeSet ||
1875
+ value instanceof CodeModeURLSearchParams) {
1876
+ const cursor = yield* self.syncIterator(value, node);
1877
+ if (!cursor)
1878
+ throw new InterpreterRuntimeError("Built-in iterator is unavailable.", node);
1879
+ while (true) {
1880
+ const step = yield* cursor.next;
1881
+ if (step.done)
1882
+ return undefined;
1883
+ const resumed = yield* Effect.exit(self.suspendGenerator(self.generatorAsync ? yield* self.awaitValue(step.value) : step.value, node));
1884
+ if (Exit.isSuccess(resumed))
1885
+ continue;
1886
+ const error = Cause.squash(resumed.cause);
1887
+ if (error instanceof GeneratorReturn) {
1888
+ yield* cursor.close;
1889
+ return yield* Effect.fail(error);
1890
+ }
1891
+ if (error instanceof ProgramThrow) {
1892
+ yield* cursor.close;
1893
+ throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node).as("TypeError");
1894
+ }
1895
+ return yield* Effect.failCause(resumed.cause);
1896
+ }
1897
+ }
1898
+ const iterator = yield* self.customIterator(value, node, self.generatorAsync);
1899
+ if (!iterator)
1900
+ throw new InterpreterRuntimeError("yield* requires a compatible iterable value.", node).as("TypeError");
1901
+ let kind = "next";
1902
+ let input = undefined;
1903
+ while (true) {
1904
+ const method = kind === "next"
1905
+ ? iterator.next
1906
+ : iterator.iterator instanceof CodeModeGenerator
1907
+ ? new GeneratorMethodReference(iterator.iterator, kind)
1908
+ : iterator.iterator[kind];
1909
+ if (method === undefined || method === null) {
1910
+ if (kind === "return")
1911
+ return yield* Effect.fail(new GeneratorReturn(input));
1912
+ yield* self.closeIterator(iterator, node, self.generatorAsync);
1913
+ throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node).as("TypeError");
1914
+ }
1915
+ const called = yield* self.invokeCallable(self.requireIteratorMethod(method, `Iterator ${kind}`, node), [input], node);
1916
+ const result = self.requireIteratorObject(iterator.asynchronous ? yield* self.awaitValue(called) : called, `Iterator ${kind}() result`, node);
1917
+ const done = Boolean(result.done);
1918
+ const resultValue = self.generatorAsync && !iterator.asynchronous
1919
+ ? yield* self.awaitAsyncFromSyncValue(iterator, result.value, node, kind !== "return" && !done)
1920
+ : result.value;
1921
+ if (done) {
1922
+ if (kind === "return")
1923
+ return yield* Effect.fail(new GeneratorReturn(resultValue));
1924
+ return resultValue;
1925
+ }
1926
+ const resumed = yield* Effect.exit(self.suspendGenerator(resultValue, node));
1927
+ if (Exit.isSuccess(resumed)) {
1928
+ kind = "next";
1929
+ input = resumed.value;
1930
+ continue;
1931
+ }
1932
+ const error = Cause.squash(resumed.cause);
1933
+ if (!(error instanceof GeneratorReturn) && !(error instanceof ProgramThrow)) {
1934
+ return yield* Effect.failCause(resumed.cause);
1935
+ }
1936
+ kind = error instanceof GeneratorReturn ? "return" : "throw";
1937
+ input = error.value;
1938
+ }
1939
+ });
1940
+ }
1941
+ evaluateObjectExpression(node) {
1942
+ const objectValue = Object.create(null);
1943
+ const properties = getArray(node, "properties");
1944
+ const self = this;
1945
+ return Effect.gen(function* () {
1946
+ for (const propertyValue of properties) {
1947
+ const property = asNode(propertyValue, "properties");
1948
+ if (property.type === "SpreadElement") {
1949
+ const spread = yield* self.evaluateExpression(getNode(property, "argument"));
1950
+ if (spread === null || spread === undefined || isCodeModeValue(spread))
1951
+ continue;
1952
+ if (typeof spread !== "object" || Array.isArray(spread) || isRuntimeReference(spread)) {
1953
+ throw new InterpreterRuntimeError("Object spread requires a data object.", property, "InvalidDataValue");
1954
+ }
1955
+ for (const [key, value] of Object.entries(spread)) {
1956
+ if (isBlockedMember(key))
1957
+ throw new InterpreterRuntimeError(`Property '${key}' is not available.`, property);
1958
+ objectValue[key] = value;
1959
+ }
1960
+ copyIteratorSymbols(spread, objectValue);
1961
+ continue;
1962
+ }
1963
+ if (property.type !== "Property") {
1964
+ throw new InterpreterRuntimeError("Only standard object properties are supported.", property);
1965
+ }
1966
+ if (getString(property, "kind") !== "init") {
1967
+ throw new InterpreterRuntimeError("Only init object properties are supported.", property);
1968
+ }
1969
+ const keyNode = getNode(property, "key");
1970
+ const valueNode = getNode(property, "value");
1971
+ const computed = getBoolean(property, "computed");
1972
+ let key;
1973
+ if (computed) {
1974
+ key = self.toPropertyKey(yield* self.evaluateExpression(keyNode), keyNode);
1975
+ }
1976
+ else if (keyNode.type === "Identifier") {
1977
+ key = getString(keyNode, "name");
1978
+ }
1979
+ else if (keyNode.type === "Literal") {
1980
+ key = self.toPropertyKey(keyNode.value, keyNode);
1981
+ }
1982
+ else {
1983
+ throw new InterpreterRuntimeError("Unsupported object property key shape.", keyNode);
1984
+ }
1985
+ if (isBlockedMember(String(key))) {
1986
+ throw new InterpreterRuntimeError(`Property '${String(key)}' is not available.`, keyNode);
1987
+ }
1988
+ Reflect.set(objectValue, key, yield* self.evaluateExpression(valueNode));
1989
+ }
1990
+ return objectValue;
1991
+ });
1992
+ }
1993
+ evaluateArrayExpression(node) {
1994
+ const elements = getArray(node, "elements");
1995
+ const values = [];
1996
+ const self = this;
1997
+ return Effect.gen(function* () {
1998
+ for (const elementValue of elements) {
1999
+ if (elementValue === null) {
2000
+ // A literal elision is a real hole, like JS: extend length without an own index.
2001
+ values.length += 1;
2002
+ continue;
2003
+ }
2004
+ const element = asNode(elementValue, "elements");
2005
+ if (element.type === "SpreadElement") {
2006
+ const spread = yield* self.evaluateExpression(getNode(element, "argument"));
2007
+ const cursor = yield* self.syncIterator(spread, element);
2008
+ if (cursor === undefined)
2009
+ throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element).as("TypeError");
2010
+ while (true) {
2011
+ const step = yield* cursor.next;
2012
+ if (step.done)
2013
+ break;
2014
+ values.push(step.value);
2015
+ }
2016
+ }
2017
+ else {
2018
+ values.push(yield* self.evaluateExpression(element));
2019
+ }
2020
+ }
2021
+ return values;
2022
+ });
2023
+ }
2024
+ evaluateTemplateLiteral(node) {
2025
+ const quasis = getArray(node, "quasis");
2026
+ const expressions = getArray(node, "expressions");
2027
+ let output = "";
2028
+ const self = this;
2029
+ return Effect.gen(function* () {
2030
+ for (let index = 0; index < quasis.length; index += 1) {
2031
+ const quasi = asNode(quasis[index], "quasis");
2032
+ const rawValue = quasi.value;
2033
+ if (!isRecord(rawValue) || typeof rawValue.cooked !== "string") {
2034
+ throw new InterpreterRuntimeError("Invalid template literal quasi.", quasi);
2035
+ }
2036
+ output += rawValue.cooked;
2037
+ if (index < expressions.length) {
2038
+ const raw = yield* self.evaluateExpression(asNode(expressions[index], "expressions"));
2039
+ output += coerceToString(boundedData(raw, "Template interpolation"));
2040
+ }
2041
+ }
2042
+ return output;
2043
+ });
2044
+ }
2045
+ evaluateConditionalExpression(node) {
2046
+ return Effect.flatMap(this.evaluateExpression(getNode(node, "test")), (test) => this.evaluateExpression(getNode(node, test ? "consequent" : "alternate")));
2047
+ }
2048
+ applyCompoundAssignment(operator, current, incoming, node) {
2049
+ if (!compoundOperators.has(operator)) {
2050
+ throw new InterpreterRuntimeError(`Unsupported assignment operator '${operator}'.`, node);
2051
+ }
2052
+ return this.applyBinaryOperator(operator.slice(0, -1), current, incoming, node);
2053
+ }
2054
+ getMemberReference(node, operation = "read") {
2055
+ const objectNode = getNode(node, "object");
2056
+ const propertyNode = getNode(node, "property");
2057
+ const computed = getBoolean(node, "computed");
2058
+ const optional = node.optional === true;
2059
+ const self = this;
2060
+ return Effect.gen(function* () {
2061
+ const objectValue = yield* self.evaluateExpression(objectNode);
2062
+ if (objectValue === OptionalShortCircuit)
2063
+ return OptionalShortCircuit;
2064
+ if ((objectValue === null || objectValue === undefined) && optional)
2065
+ return OptionalShortCircuit;
2066
+ const key = computed
2067
+ ? self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode)
2068
+ : propertyNode.type === "Identifier"
2069
+ ? getString(propertyNode, "name")
2070
+ : self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode);
2071
+ if (objectValue instanceof ToolReference) {
2072
+ if (typeof key !== "string") {
2073
+ throw new InterpreterRuntimeError("Tool paths must use string property names.", propertyNode);
2074
+ }
2075
+ return new ToolReference([...objectValue.path, key]);
2076
+ }
2077
+ if (objectValue instanceof PromiseNamespace) {
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) {
2091
+ if (typeof key === "string" && isBlockedMember(key)) {
2092
+ throw new InterpreterRuntimeError(`${objectValue.name}.${key} is not available.`, propertyNode);
2093
+ }
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
+ // Unknown static members read as undefined so feature detection works like native JS.
2108
+ return new ComputedValue(undefined);
2109
+ }
2110
+ if (typeof objectValue === "string") {
2111
+ if (key === "length")
2112
+ return new ComputedValue(objectValue.length);
2113
+ const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
2114
+ if (index !== undefined)
2115
+ return new ComputedValue(objectValue[index]);
2116
+ if (typeof key === "string" && stringMethods.has(key))
2117
+ return new IntrinsicReference(objectValue, key);
2118
+ return new ComputedValue(undefined);
2119
+ }
2120
+ if (typeof objectValue === "number") {
2121
+ if (typeof key === "string" && numberMethods.has(key))
2122
+ return new IntrinsicReference(objectValue, key);
2123
+ return new ComputedValue(undefined);
2124
+ }
2125
+ if (objectValue instanceof CoercionFunction) {
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) {
2143
+ if (typeof key === "string" && dateMethods.has(key))
2144
+ return new IntrinsicReference(objectValue, key);
2145
+ return new ComputedValue(undefined);
2146
+ }
2147
+ if (objectValue instanceof CodeModeRegExp) {
2148
+ if (key === "lastIndex")
2149
+ return { target: objectValue, key };
2150
+ if (typeof key === "string" && regexpProperties.has(key)) {
2151
+ return new ComputedValue(objectValue.regex[key]);
2152
+ }
2153
+ if (typeof key === "string" && regexpMethods.has(key))
2154
+ return new IntrinsicReference(objectValue, key);
2155
+ return new ComputedValue(undefined);
2156
+ }
2157
+ if (objectValue instanceof CodeModeMap) {
2158
+ if (key === "size")
2159
+ return new ComputedValue(objectValue.map.size);
2160
+ if (typeof key === "string" && mapMethods.has(key))
2161
+ return new IntrinsicReference(objectValue, key);
2162
+ return new ComputedValue(undefined);
2163
+ }
2164
+ if (objectValue instanceof CodeModeSet) {
2165
+ if (key === "size")
2166
+ return new ComputedValue(objectValue.set.size);
2167
+ if (typeof key === "string" && setMethods.has(key))
2168
+ return new IntrinsicReference(objectValue, key);
2169
+ return new ComputedValue(undefined);
2170
+ }
2171
+ if (objectValue instanceof CodeModeURL) {
2172
+ if (key === "searchParams") {
2173
+ return new ComputedValue(objectValue.searchParams);
2174
+ }
2175
+ if (typeof key === "string" && urlMethods.has(key))
2176
+ return new IntrinsicReference(objectValue, key);
2177
+ if (typeof key === "string" && urlProperties.has(key))
2178
+ return { target: objectValue, key };
2179
+ return new ComputedValue(undefined);
2180
+ }
2181
+ if (objectValue instanceof CodeModeURLSearchParams) {
2182
+ if (key === "size")
2183
+ return new ComputedValue(objectValue.params.size);
2184
+ if (typeof key === "string" && urlSearchParamsMethods.has(key)) {
2185
+ return new IntrinsicReference(objectValue, key);
2186
+ }
2187
+ return new ComputedValue(undefined);
2188
+ }
2189
+ // Reject unknown promise properties so a missing await cannot hide.
2190
+ if (objectValue instanceof CodeModePromise) {
2191
+ if (key === "then" || key === "catch" || key === "finally") {
2192
+ return new PromiseInstanceMethodReference(objectValue, key);
2193
+ }
2194
+ throw new InterpreterRuntimeError("This value is an un-awaited Promise; await it first - e.g. `const result = await tools.ns.tool(...)`.", objectNode, "InvalidDataValue");
2195
+ }
2196
+ if (objectValue instanceof CodeModeGenerator) {
2197
+ if (key === "next" || key === "return" || key === "throw") {
2198
+ return new GeneratorMethodReference(objectValue, key);
2199
+ }
2200
+ if ((key === IteratorSymbol && !objectValue.asynchronous) ||
2201
+ (key === AsyncIteratorSymbol && objectValue.asynchronous)) {
2202
+ return new GeneratorMethodReference(objectValue, "iterator");
2203
+ }
2204
+ return new ComputedValue(undefined);
2205
+ }
2206
+ if (isRuntimeReference(objectValue)) {
2207
+ throw new InterpreterRuntimeError("Runtime references are opaque and do not expose properties.", objectNode, "InvalidDataValue");
2208
+ }
2209
+ if (typeof objectValue !== "object" || objectValue === null) {
2210
+ throw new InterpreterRuntimeError("Cannot access a property on a non-object value.", objectNode);
2211
+ }
2212
+ if (typeof key === "string" && isBlockedMember(key)) {
2213
+ throw new InterpreterRuntimeError(`Property '${key}' is not available.`, propertyNode);
2214
+ }
2215
+ if (Array.isArray(objectValue)) {
2216
+ if (operation === "delete")
2217
+ return { target: objectValue, key };
2218
+ const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
2219
+ if (key !== "length" && !(typeof key === "string" && arrayMethods.has(key)) && index === undefined) {
2220
+ if (typeof key === "string" && Object.hasOwn(objectValue, key)) {
2221
+ return new ComputedValue(objectValue[key]);
2222
+ }
2223
+ return new ComputedValue(undefined);
2224
+ }
2225
+ return { target: objectValue, key: index ?? key };
2226
+ }
2227
+ return { target: objectValue, key };
2228
+ });
2229
+ }
2230
+ readMember(node) {
2231
+ return Effect.map(this.getMemberReference(node), (reference) => {
2232
+ if (reference === OptionalShortCircuit)
2233
+ return OptionalShortCircuit;
2234
+ if (reference instanceof ComputedValue)
2235
+ return reference.value;
2236
+ if (reference === undefined || isOpaqueMemberReference(reference))
2237
+ return reference;
2238
+ if (Array.isArray(reference.target)) {
2239
+ if (reference.key === "length")
2240
+ return reference.target.length;
2241
+ if (typeof reference.key === "string")
2242
+ return new IntrinsicReference(reference.target, reference.key);
2243
+ return Reflect.get(reference.target, reference.key);
2244
+ }
2245
+ if (reference.target instanceof CodeModeRegExp)
2246
+ return reference.target.lastIndex;
2247
+ if (reference.target instanceof CodeModeURL) {
2248
+ return Reflect.get(reference.target.url, reference.key);
2249
+ }
2250
+ return Reflect.get(reference.target, reference.key);
2251
+ });
2252
+ }
2253
+ writeMember(node, value) {
2254
+ return this.modifyMember(node, () => Effect.succeed({ write: true, next: value, result: value }));
2255
+ }
2256
+ evaluateDeleteExpression(argument) {
2257
+ const target = argument.type === "ChainExpression" ? getNode(argument, "expression") : argument;
2258
+ if (target.type !== "MemberExpression") {
2259
+ throw new InterpreterRuntimeError("Only data fields may be deleted.", argument);
2260
+ }
2261
+ return Effect.map(this.getMemberReference(target, "delete"), (reference) => {
2262
+ if (reference === OptionalShortCircuit)
2263
+ return true;
2264
+ if (reference instanceof ComputedValue ||
2265
+ reference === undefined ||
2266
+ isOpaqueMemberReference(reference) ||
2267
+ reference.target instanceof CodeModeURL) {
2268
+ throw new InterpreterRuntimeError("Only data fields may be deleted.", target, "InvalidDataValue");
2269
+ }
2270
+ if (reference.target instanceof CodeModeRegExp) {
2271
+ return Reflect.deleteProperty(reference.target.regex, reference.key);
2272
+ }
2273
+ return Reflect.deleteProperty(reference.target, reference.key);
2274
+ });
2275
+ }
2276
+ // Resolve side-effecting object and key expressions exactly once.
2277
+ modifyMember(node, compute) {
2278
+ const self = this;
2279
+ return Effect.gen(function* () {
2280
+ const reference = yield* self.getMemberReference(node);
2281
+ if (reference === OptionalShortCircuit ||
2282
+ reference instanceof ComputedValue ||
2283
+ reference === undefined ||
2284
+ isOpaqueMemberReference(reference)) {
2285
+ throw new InterpreterRuntimeError("Only data fields may be assigned.", node);
2286
+ }
2287
+ if (Array.isArray(reference.target)) {
2288
+ if (reference.key === "length")
2289
+ throw new InterpreterRuntimeError("Array length cannot be assigned.", node);
2290
+ if (typeof reference.key === "string" && arrayMethods.has(reference.key)) {
2291
+ throw new InterpreterRuntimeError("Array methods cannot be assigned.", node);
2292
+ }
2293
+ }
2294
+ const key = reference.key;
2295
+ const { write, next, result } = yield* compute(self.readReferenceValue(reference, key));
2296
+ if (write)
2297
+ self.assignToReference(reference, key, next, node);
2298
+ return result;
2299
+ });
2300
+ }
2301
+ readReferenceValue(reference, key) {
2302
+ if (reference.target instanceof CodeModeURL) {
2303
+ return Reflect.get(reference.target.url, key);
2304
+ }
2305
+ if (reference.target instanceof CodeModeRegExp)
2306
+ return reference.target.lastIndex;
2307
+ return Reflect.get(reference.target, key);
2308
+ }
2309
+ assignToReference(reference, key, next, node) {
2310
+ if (Array.isArray(reference.target)) {
2311
+ const target = reference.target;
2312
+ if (typeof key !== "number" || parseArrayIndex(key) === undefined) {
2313
+ throw new InterpreterRuntimeError("Array assignment index must be a valid array index.", node, "InvalidDataValue");
2314
+ }
2315
+ rejectCircularInsertion(target, next, "Array assignment result", node);
2316
+ target[key] = next;
2317
+ return;
2318
+ }
2319
+ if (reference.target instanceof CodeModeURL) {
2320
+ const property = key;
2321
+ if (!urlWritableProperties.has(property)) {
2322
+ throw new InterpreterRuntimeError(`URL.${property} is read-only.`, node).as("TypeError");
2323
+ }
2324
+ try {
2325
+ const url = reference.target.url;
2326
+ url[property] = uriArgument(next, `URL.${property} value`);
2327
+ return;
2328
+ }
2329
+ catch (error) {
2330
+ if (error instanceof InterpreterRuntimeError || error instanceof ToolRuntimeError)
2331
+ throw error;
2332
+ throw new InterpreterRuntimeError(`URL.${property} received an invalid value.`, node).as("TypeError");
2333
+ }
2334
+ }
2335
+ if (reference.target instanceof CodeModeRegExp) {
2336
+ reference.target.lastIndex = next;
2337
+ return;
2338
+ }
2339
+ const target = reference.target;
2340
+ rejectCircularInsertion(target, next, "Object assignment result", node);
2341
+ Reflect.set(target, key, next);
2342
+ }
2343
+ toPropertyKey(value, node) {
2344
+ if (typeof value === "string" || typeof value === "number") {
2345
+ return value;
2346
+ }
2347
+ if (value === AsyncIteratorSymbol || value === IteratorSymbol)
2348
+ return value;
2349
+ throw new InterpreterRuntimeError("Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.", node);
2350
+ }
2351
+ }