@opencode/codemode 0.0.0-reserved → 2.0.0

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 (84) hide show
  1. package/README.md +184 -2
  2. package/dist/codemode.d.ts +145 -0
  3. package/dist/codemode.js +66 -0
  4. package/dist/data.d.ts +25 -0
  5. package/dist/data.js +153 -0
  6. package/dist/index.d.ts +7 -0
  7. package/dist/index.js +7 -0
  8. package/dist/interpreter/errors.d.ts +7 -0
  9. package/dist/interpreter/errors.js +106 -0
  10. package/dist/interpreter/execute.d.ts +5 -0
  11. package/dist/interpreter/execute.js +171 -0
  12. package/dist/interpreter/globals.d.ts +13 -0
  13. package/dist/interpreter/globals.js +63 -0
  14. package/dist/interpreter/host.d.ts +41 -0
  15. package/dist/interpreter/host.js +44 -0
  16. package/dist/interpreter/methods.d.ts +4 -0
  17. package/dist/interpreter/methods.js +837 -0
  18. package/dist/interpreter/model.d.ts +82 -0
  19. package/dist/interpreter/model.js +86 -0
  20. package/dist/interpreter/objects.d.ts +37 -0
  21. package/dist/interpreter/objects.js +151 -0
  22. package/dist/interpreter/promises.d.ts +31 -0
  23. package/dist/interpreter/promises.js +271 -0
  24. package/dist/interpreter/references.d.ts +7 -0
  25. package/dist/interpreter/references.js +93 -0
  26. package/dist/interpreter/runner.d.ts +24 -0
  27. package/dist/interpreter/runner.js +45 -0
  28. package/dist/interpreter/runtime.d.ts +19 -0
  29. package/dist/interpreter/runtime.js +1940 -0
  30. package/dist/interpreter/scope.d.ts +15 -0
  31. package/dist/interpreter/scope.js +79 -0
  32. package/dist/interpreter/transpile.node.d.ts +5 -0
  33. package/dist/interpreter/transpile.node.js +19 -0
  34. package/dist/interpreter/transpile.workerd.d.ts +5 -0
  35. package/dist/interpreter/transpile.workerd.js +6 -0
  36. package/dist/namespace.d.ts +15 -0
  37. package/dist/namespace.js +7 -0
  38. package/dist/openapi/index.d.ts +7 -0
  39. package/dist/openapi/index.js +101 -0
  40. package/dist/openapi/runtime.d.ts +4 -0
  41. package/dist/openapi/runtime.js +283 -0
  42. package/dist/openapi/spec.d.ts +20 -0
  43. package/dist/openapi/spec.js +583 -0
  44. package/dist/openapi/types.d.ts +122 -0
  45. package/dist/openapi/types.js +2 -0
  46. package/dist/stdlib/array.d.ts +3 -0
  47. package/dist/stdlib/array.js +68 -0
  48. package/dist/stdlib/collections.d.ts +9 -0
  49. package/dist/stdlib/collections.js +173 -0
  50. package/dist/stdlib/console.d.ts +3 -0
  51. package/dist/stdlib/console.js +137 -0
  52. package/dist/stdlib/date.d.ts +8 -0
  53. package/dist/stdlib/date.js +208 -0
  54. package/dist/stdlib/json.d.ts +3 -0
  55. package/dist/stdlib/json.js +101 -0
  56. package/dist/stdlib/math.d.ts +8 -0
  57. package/dist/stdlib/math.js +89 -0
  58. package/dist/stdlib/number.d.ts +4 -0
  59. package/dist/stdlib/number.js +69 -0
  60. package/dist/stdlib/object.d.ts +7 -0
  61. package/dist/stdlib/object.js +106 -0
  62. package/dist/stdlib/regexp.d.ts +10 -0
  63. package/dist/stdlib/regexp.js +120 -0
  64. package/dist/stdlib/string.d.ts +2 -0
  65. package/dist/stdlib/string.js +51 -0
  66. package/dist/stdlib/url.d.ts +16 -0
  67. package/dist/stdlib/url.js +161 -0
  68. package/dist/stdlib/value.d.ts +13 -0
  69. package/dist/stdlib/value.js +120 -0
  70. package/dist/stdlib/web.d.ts +4 -0
  71. package/dist/stdlib/web.js +20 -0
  72. package/dist/tool-error.d.ts +11 -0
  73. package/dist/tool-error.js +9 -0
  74. package/dist/tool-runtime.d.ts +69 -0
  75. package/dist/tool-runtime.js +254 -0
  76. package/dist/tool-schema.d.ts +16 -0
  77. package/dist/tool-schema.js +263 -0
  78. package/dist/tool.d.ts +66 -0
  79. package/dist/tool.js +16 -0
  80. package/dist/tools.d.ts +5 -0
  81. package/dist/tools.js +1 -0
  82. package/dist/values.d.ts +37 -0
  83. package/dist/values.js +56 -0
  84. package/package.json +37 -6
@@ -0,0 +1,1940 @@
1
+ import { Cause, Deferred, Effect, Exit } from "effect";
2
+ import { ToolRuntimeError, toProgram } from "../data.js";
3
+ import { ToolReference } from "../tool-runtime.js";
4
+ import { AsyncIteratorSymbol, CodeModeGenerator, ComputedValue, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, IteratorSymbol, OptionalShortCircuit, PromiseInstanceMethodReference, ProgramThrow, unsupportedSyntax, } from "./model.js";
5
+ import { caughtErrorValue } from "./errors.js";
6
+ import { globals } from "./globals.js";
7
+ import { HostFunction, HostNamespace } from "./host.js";
8
+ import { invokeIntrinsic } from "./methods.js";
9
+ import { assign, get, has, ownKeys, parseArrayIndex, ProgramArray, ProgramFunction, ProgramObject, record, remove, set, } from "./objects.js";
10
+ import { preserveConsumerError } from "./runner.js";
11
+ import { invokePromiseInstanceMethod, PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
12
+ import { containsOpaqueReference, describeValue, isRuntimeReference, rejectCircularInsertion, typeofValue, } from "./references.js";
13
+ import { ScopeStack } from "./scope.js";
14
+ import { arrayMethods, mapMethods, setMethods } from "../stdlib/collections.js";
15
+ import { dateMethods } from "../stdlib/date.js";
16
+ import { numberMethods } from "../stdlib/number.js";
17
+ import { constructRegExp, regexpMethods, regexpProperties } from "../stdlib/regexp.js";
18
+ import { stringMethods } from "../stdlib/string.js";
19
+ import { uriArgument, urlMethods, urlProperties, urlSearchParamsMethods, urlWritableProperties } from "../stdlib/url.js";
20
+ import { enumerableSource } from "../stdlib/object.js";
21
+ import { coerceToNumber, coerceToString, compoundOperators, errorBrandName } from "../stdlib/value.js";
22
+ import { Values } from "../values.js";
23
+ // What a loop does with its body's result: exit with a StatementResult, or undefined to keep iterating.
24
+ // Unlabelled break ends this loop; a label the loop does not carry propagates outward.
25
+ const loopExit = (result, labels) => {
26
+ if (result.kind === "return")
27
+ return result;
28
+ if (result.kind === "break") {
29
+ if (result.label !== undefined && !labels?.has(result.label))
30
+ return result;
31
+ return { kind: "none" };
32
+ }
33
+ if (result.kind === "continue" && result.label !== undefined && !labels?.has(result.label))
34
+ return result;
35
+ return undefined;
36
+ };
37
+ const calleeDescription = (callee) => {
38
+ if (callee?.type === "Identifier")
39
+ return callee.name;
40
+ if (callee?.type === "MemberExpression") {
41
+ const object = callee.object;
42
+ const property = callee.property;
43
+ const key = !callee.computed && property.type === "Identifier"
44
+ ? property.name
45
+ : property.type === "Literal" && typeof property.value === "string"
46
+ ? property.value
47
+ : undefined;
48
+ if (object.type === "Identifier" && key !== undefined)
49
+ return `${object.name}.${key}`;
50
+ }
51
+ return "The called value";
52
+ };
53
+ const constructorName = (value) => {
54
+ if (typeof value === "string")
55
+ return "String";
56
+ if (typeof value === "number")
57
+ return "Number";
58
+ if (typeof value === "boolean")
59
+ return "Boolean";
60
+ if (value instanceof ProgramArray)
61
+ return "Array";
62
+ if (value instanceof Values.Date)
63
+ return "Date";
64
+ if (value instanceof Values.RegExp)
65
+ return "RegExp";
66
+ if (value instanceof Values.Map)
67
+ return "Map";
68
+ if (value instanceof Values.Set)
69
+ return "Set";
70
+ if (value instanceof Values.URL)
71
+ return "URL";
72
+ if (value instanceof Values.URLSearchParams)
73
+ return "URLSearchParams";
74
+ if (value instanceof Values.Promise)
75
+ return "Promise";
76
+ if (!(value instanceof ProgramObject) || value instanceof ProgramFunction)
77
+ return undefined;
78
+ return errorBrandName(value) ?? "Object";
79
+ };
80
+ const instanceofValue = (lhs, rhs, node) => {
81
+ if (rhs instanceof HostFunction && rhs.instanceOf !== undefined)
82
+ return rhs.instanceOf(lhs);
83
+ 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);
84
+ };
85
+ const collectPatternNames = (pattern, out = []) => {
86
+ switch (pattern.type) {
87
+ case "Identifier":
88
+ out.push(pattern.name);
89
+ break;
90
+ case "AssignmentPattern":
91
+ collectPatternNames(pattern.left, out);
92
+ break;
93
+ case "RestElement":
94
+ collectPatternNames(pattern.argument, out);
95
+ break;
96
+ case "ArrayPattern":
97
+ for (const element of pattern.elements) {
98
+ if (element !== null)
99
+ collectPatternNames(element, out);
100
+ }
101
+ break;
102
+ case "ObjectPattern":
103
+ for (const prop of pattern.properties) {
104
+ collectPatternNames(prop.type === "RestElement" ? prop.argument : prop.value, out);
105
+ }
106
+ break;
107
+ }
108
+ return out;
109
+ };
110
+ // `var` names declared anywhere in a function body except inside nested functions, which own theirs.
111
+ // Memoized per body: a function's var names never change, and hoisting runs on every call.
112
+ const varNames = new WeakMap();
113
+ const collectVarNames = (node, out = []) => {
114
+ if (!node)
115
+ return out;
116
+ switch (node.type) {
117
+ case "VariableDeclaration":
118
+ if (node.kind === "var")
119
+ for (const declaration of node.declarations)
120
+ collectPatternNames(declaration.id, out);
121
+ break;
122
+ case "BlockStatement":
123
+ for (const statement of node.body)
124
+ collectVarNames(statement, out);
125
+ break;
126
+ case "IfStatement":
127
+ collectVarNames(node.consequent, out);
128
+ collectVarNames(node.alternate, out);
129
+ break;
130
+ case "ForStatement":
131
+ if (node.init?.type === "VariableDeclaration")
132
+ collectVarNames(node.init, out);
133
+ collectVarNames(node.body, out);
134
+ break;
135
+ case "ForInStatement":
136
+ case "ForOfStatement":
137
+ if (node.left.type === "VariableDeclaration")
138
+ collectVarNames(node.left, out);
139
+ collectVarNames(node.body, out);
140
+ break;
141
+ case "WhileStatement":
142
+ case "DoWhileStatement":
143
+ case "LabeledStatement":
144
+ collectVarNames(node.body, out);
145
+ break;
146
+ case "SwitchStatement":
147
+ for (const item of node.cases)
148
+ for (const statement of item.consequent)
149
+ collectVarNames(statement, out);
150
+ break;
151
+ case "TryStatement":
152
+ collectVarNames(node.block, out);
153
+ collectVarNames(node.handler?.body, out);
154
+ collectVarNames(node.finalizer, out);
155
+ break;
156
+ }
157
+ return out;
158
+ };
159
+ const loopDeclaration = (left, statement) => {
160
+ if (left.type !== "VariableDeclaration")
161
+ return undefined;
162
+ const declaration = left.declarations.length === 1 ? left.declarations[0] : undefined;
163
+ if (declaration === undefined) {
164
+ throw new InterpreterRuntimeError(`${statement} supports one declared binding.`, left);
165
+ }
166
+ const kind = left.kind;
167
+ return {
168
+ pattern: declaration.id,
169
+ mutable: kind !== "const",
170
+ lexical: kind !== "var",
171
+ };
172
+ };
173
+ const isOpaqueMemberReference = (value) => value instanceof ToolReference ||
174
+ value instanceof PromiseInstanceMethodReference ||
175
+ value instanceof IntrinsicReference ||
176
+ value instanceof GeneratorMethodReference;
177
+ const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
178
+ /** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
179
+ export class Runtime {
180
+ executeTool;
181
+ search;
182
+ toolKeys;
183
+ promises;
184
+ logs;
185
+ runner;
186
+ /** Built-in globals by name, unaffected by program shadowing. */
187
+ builtins;
188
+ root;
189
+ constructor(executeTool, search, toolKeys, promises, logs = [], extraGlobals = () => []) {
190
+ this.executeTool = executeTool;
191
+ this.search = search;
192
+ this.toolKeys = toolKeys;
193
+ this.promises = promises;
194
+ this.logs = logs;
195
+ const globalScope = new Map();
196
+ // Calling back into the program never reads frame state, so any frame serves; the root is always alive.
197
+ this.root = new Frame(this, new ScopeStack([globalScope]));
198
+ this.runner = {
199
+ invokeFunction: (fn, args) => this.root.invokeFunction(fn, args),
200
+ invokeCallable: (callable, args, node) => this.root.invokeCallable(callable, args, node),
201
+ settlePromise: (promise) => this.root.settlePromise(promise),
202
+ syncIterator: (value, node) => this.root.syncIterator(value, node),
203
+ };
204
+ this.builtins = new Map([...globals(this), ...extraGlobals(this)]);
205
+ for (const [name, value] of this.builtins)
206
+ globalScope.set(name, { mutable: false, value });
207
+ }
208
+ run(program) {
209
+ return this.root.run(program);
210
+ }
211
+ }
212
+ /** One activation: the top-level program or a single function call, evaluating against its own scope chain. */
213
+ class Frame {
214
+ runtime;
215
+ scopes;
216
+ generatorState;
217
+ generatorAsync = false;
218
+ constructor(runtime, scopes) {
219
+ this.runtime = runtime;
220
+ this.scopes = scopes;
221
+ }
222
+ run(program) {
223
+ const self = this;
224
+ // Keep top-level declarations separate so they can shadow builtins.
225
+ this.scopes.push();
226
+ return Effect.gen(function* () {
227
+ self.predeclareLexical(program.body);
228
+ self.hoistFunctions(program.body);
229
+ self.hoistVars(program.body);
230
+ let value = undefined;
231
+ for (const [index, statement] of program.body.entries()) {
232
+ if (index === program.body.length - 1 && statement.type === "ExpressionStatement") {
233
+ value = yield* self.evaluateExpression(statement.expression);
234
+ break;
235
+ }
236
+ const result = yield* self.evaluateStatement(statement);
237
+ if (result.kind === "return") {
238
+ value = result.value;
239
+ break;
240
+ }
241
+ if (result.kind === "break" || result.kind === "continue") {
242
+ throw new InterpreterRuntimeError(`Unexpected '${result.kind}' outside of a loop.`, statement);
243
+ }
244
+ }
245
+ // The implicit async body adopts returned promises before copy-out.
246
+ value = yield* resolvePromiseValue(self.runtime.runner, value, program);
247
+ return value;
248
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
249
+ }
250
+ // Fork at the call site so admission and hooks occur when the call is made.
251
+ createToolCallPromise(path, args) {
252
+ return this.createPromise(Effect.suspend(() => this.runtime.executeTool(path, args)));
253
+ }
254
+ createPromise(effect) {
255
+ return this.runtime.promises.create(effect);
256
+ }
257
+ // Fiber exits make settlement idempotent; yielding prevents inline continuation.
258
+ settlePromise(promise) {
259
+ const promises = this.runtime.promises;
260
+ return Effect.suspend(() => {
261
+ promises.markObserved(promise);
262
+ return Effect.flatMap(promises.await(promise), (exit) => Effect.andThen(Effect.yieldNow, exit));
263
+ });
264
+ }
265
+ evaluateStatement(node) {
266
+ switch (node.type) {
267
+ case "ExpressionStatement":
268
+ return Effect.as(this.evaluateExpression(node.expression), { kind: "none" });
269
+ case "VariableDeclaration":
270
+ return Effect.map(this.evaluateVariableDeclaration(node), () => ({ kind: "none" }));
271
+ case "ReturnStatement": {
272
+ const argumentNode = node.argument;
273
+ return argumentNode
274
+ ? Effect.map(this.evaluateExpression(argumentNode), (value) => ({ kind: "return", value }))
275
+ : Effect.succeed({ kind: "return", value: undefined });
276
+ }
277
+ case "BlockStatement":
278
+ return this.evaluateBlock(node);
279
+ case "IfStatement":
280
+ return this.evaluateIfStatement(node);
281
+ case "SwitchStatement":
282
+ return this.evaluateSwitchStatement(node);
283
+ case "LabeledStatement":
284
+ return this.evaluateLabeledStatement(node);
285
+ case "WhileStatement":
286
+ return this.evaluateWhileStatement(node);
287
+ case "DoWhileStatement":
288
+ return this.evaluateDoWhileStatement(node);
289
+ case "ForStatement":
290
+ return this.evaluateForStatement(node);
291
+ case "ForOfStatement":
292
+ return this.evaluateForOfStatement(node);
293
+ case "ForInStatement":
294
+ return this.evaluateForInStatement(node);
295
+ case "BreakStatement":
296
+ return Effect.succeed(this.evaluateBreakStatement(node));
297
+ case "ContinueStatement":
298
+ return Effect.succeed(this.evaluateContinueStatement(node));
299
+ case "ThrowStatement":
300
+ return this.evaluateThrowStatement(node);
301
+ case "TryStatement":
302
+ return this.evaluateTryStatement(node);
303
+ case "EmptyStatement":
304
+ return Effect.succeed({ kind: "none" });
305
+ case "FunctionDeclaration":
306
+ return Effect.succeed({ kind: "none" });
307
+ default:
308
+ throw unsupportedSyntax(node.type, node);
309
+ }
310
+ }
311
+ evaluateBlock(node) {
312
+ this.scopes.push();
313
+ const self = this;
314
+ return Effect.gen(function* () {
315
+ const body = node.body;
316
+ self.predeclareLexical(body);
317
+ self.hoistFunctions(body);
318
+ for (const statement of body) {
319
+ const result = yield* self.evaluateStatement(statement);
320
+ if (result.kind !== "none") {
321
+ return result;
322
+ }
323
+ }
324
+ return { kind: "none" };
325
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
326
+ }
327
+ createFunction(node, name = node.type === "ArrowFunctionExpression" ? "" : (node.id?.name ?? "")) {
328
+ return new ProgramFunction(name, node.params, node.body, this.scopes.capture(), node.async, node.generator);
329
+ }
330
+ // NamedEvaluation: an anonymous function definition takes the name of what it is assigned to.
331
+ evaluateNamed(node, name) {
332
+ if (node.type === "ArrowFunctionExpression" || (node.type === "FunctionExpression" && !node.id)) {
333
+ return Effect.sync(() => this.createFunction(node, name));
334
+ }
335
+ return this.evaluateExpression(node);
336
+ }
337
+ hoistFunctions(statements) {
338
+ for (const node of statements) {
339
+ if (node.type !== "FunctionDeclaration")
340
+ continue;
341
+ this.scopes.declare(node.id.name, this.createFunction(node), true, node);
342
+ }
343
+ }
344
+ // Hoisted `var` bindings start undefined, or copy a same-named parameter. Function bodies hoist
345
+ // into their own scope above the parameters so closures in parameter defaults keep seeing outer names.
346
+ hoistVars(statements, parameters) {
347
+ const names = varNames.get(statements) ??
348
+ statements.reduce((out, statement) => collectVarNames(statement, out), []);
349
+ varNames.set(statements, names);
350
+ const scope = this.scopes.current();
351
+ for (const name of names) {
352
+ if (scope.has(name))
353
+ continue;
354
+ scope.set(name, { mutable: true, value: parameters?.get(name)?.value, initialized: true });
355
+ }
356
+ }
357
+ predeclareLexical(statements) {
358
+ for (const statement of statements) {
359
+ if (statement.type !== "VariableDeclaration")
360
+ continue;
361
+ const kind = statement.kind;
362
+ if (kind === "var")
363
+ continue;
364
+ for (const declaration of statement.declarations) {
365
+ for (const name of collectPatternNames(declaration.id)) {
366
+ this.scopes.reserve(name, kind !== "const", declaration);
367
+ }
368
+ }
369
+ }
370
+ }
371
+ predeclarePattern(pattern, mutable, node) {
372
+ for (const name of collectPatternNames(pattern))
373
+ this.scopes.reserve(name, mutable, node);
374
+ }
375
+ evaluateIfStatement(node) {
376
+ return Effect.flatMap(this.evaluateExpression(node.test), (test) => test
377
+ ? this.evaluateStatement(node.consequent)
378
+ : node.alternate
379
+ ? this.evaluateStatement(node.alternate)
380
+ : Effect.succeed({ kind: "none" }));
381
+ }
382
+ evaluateSwitchStatement(node) {
383
+ const self = this;
384
+ return Effect.gen(function* () {
385
+ const discriminant = yield* self.evaluateExpression(node.discriminant);
386
+ if (containsOpaqueReference(discriminant)) {
387
+ throw new InterpreterRuntimeError("Switch discriminants must be data values.", node, "InvalidDataValue");
388
+ }
389
+ self.scopes.push();
390
+ return yield* Effect.gen(function* () {
391
+ const cases = node.cases;
392
+ const statements = cases.flatMap((branch) => branch.consequent);
393
+ self.predeclareLexical(statements);
394
+ self.hoistFunctions(statements);
395
+ let defaultIndex;
396
+ let selected;
397
+ for (const [index, branch] of cases.entries()) {
398
+ const test = branch.test;
399
+ if (!test) {
400
+ defaultIndex = index;
401
+ continue;
402
+ }
403
+ const candidate = yield* self.evaluateExpression(test);
404
+ if (containsOpaqueReference(candidate)) {
405
+ throw new InterpreterRuntimeError("Switch case values must be data values.", test, "InvalidDataValue");
406
+ }
407
+ if (candidate === discriminant) {
408
+ selected = index;
409
+ break;
410
+ }
411
+ }
412
+ const start = selected ?? defaultIndex;
413
+ if (start === undefined)
414
+ return { kind: "none" };
415
+ for (let index = start; index < cases.length; index += 1) {
416
+ for (const statement of cases[index].consequent) {
417
+ const result = yield* self.evaluateStatement(statement);
418
+ if (result.kind === "break") {
419
+ if (result.label === undefined)
420
+ return { kind: "none" };
421
+ return result;
422
+ }
423
+ if (result.kind === "return" || result.kind === "continue")
424
+ return result;
425
+ }
426
+ }
427
+ return { kind: "none" };
428
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
429
+ });
430
+ }
431
+ evaluateWhileStatement(node, labels) {
432
+ const self = this;
433
+ return Effect.gen(function* () {
434
+ while (yield* self.evaluateExpression(node.test)) {
435
+ const exit = loopExit(yield* self.evaluateStatement(node.body), labels);
436
+ if (exit !== undefined)
437
+ return exit;
438
+ }
439
+ return { kind: "none" };
440
+ });
441
+ }
442
+ evaluateDoWhileStatement(node, labels) {
443
+ const self = this;
444
+ return Effect.gen(function* () {
445
+ do {
446
+ const exit = loopExit(yield* self.evaluateStatement(node.body), labels);
447
+ if (exit !== undefined)
448
+ return exit;
449
+ } while (yield* self.evaluateExpression(node.test));
450
+ return { kind: "none" };
451
+ });
452
+ }
453
+ evaluateForStatement(node, labels) {
454
+ this.scopes.push();
455
+ const self = this;
456
+ return Effect.gen(function* () {
457
+ const initNode = node.init;
458
+ const testNode = node.test;
459
+ const updateNode = node.update;
460
+ if (initNode?.type === "VariableDeclaration" && initNode.kind !== "var") {
461
+ self.predeclareLexical([initNode]);
462
+ }
463
+ if (initNode) {
464
+ if (initNode.type === "VariableDeclaration") {
465
+ yield* self.evaluateVariableDeclaration(initNode);
466
+ }
467
+ else {
468
+ yield* self.evaluateExpression(initNode);
469
+ }
470
+ }
471
+ const perIterationBindings = initNode?.type === "VariableDeclaration" && initNode.kind !== "var"
472
+ ? Array.from(self.scopes.current().keys())
473
+ : [];
474
+ const nextIteration = () => {
475
+ if (perIterationBindings.length === 0)
476
+ return;
477
+ const current = self.scopes.current();
478
+ self.scopes.pop();
479
+ self.scopes.push(new Map(perIterationBindings.map((name) => [name, { ...current.get(name) }])));
480
+ };
481
+ nextIteration();
482
+ while (testNode ? yield* self.evaluateExpression(testNode) : true) {
483
+ const exit = loopExit(yield* self.evaluateStatement(node.body), labels);
484
+ if (exit !== undefined)
485
+ return exit;
486
+ nextIteration();
487
+ if (updateNode) {
488
+ yield* self.evaluateExpression(updateNode);
489
+ }
490
+ }
491
+ return { kind: "none" };
492
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
493
+ }
494
+ evaluateForOfStatement(node, labels) {
495
+ const awaiting = node.await;
496
+ const left = node.left;
497
+ const declared = loopDeclaration(left, "for...of");
498
+ if (declared?.lexical)
499
+ this.scopes.push();
500
+ const self = this;
501
+ return Effect.gen(function* () {
502
+ if (declared?.lexical)
503
+ self.predeclarePattern(declared.pattern, declared.mutable, left);
504
+ const right = yield* self.evaluateExpression(node.right);
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
+ if (left.type === "RestElement" || left.type === "AssignmentPattern") {
516
+ throw new InterpreterRuntimeError("Unsupported for...of binding.", left);
517
+ }
518
+ const assignment = left.type === "VariableDeclaration" ? undefined : left;
519
+ const evaluateBody = (value) => Effect.gen(function* () {
520
+ if (declared?.lexical) {
521
+ self.scopes.push();
522
+ self.predeclarePattern(declared.pattern, declared.mutable, left);
523
+ yield* self.declarePattern(declared.pattern, value, declared.mutable, left, true);
524
+ }
525
+ else if (declared) {
526
+ yield* self.assignPattern(declared.pattern, value, left);
527
+ }
528
+ else if (assignment) {
529
+ yield* self.assignPattern(assignment, value, left);
530
+ }
531
+ return yield* self.evaluateStatement(node.body);
532
+ }).pipe(Effect.ensuring(Effect.sync(() => {
533
+ if (declared?.lexical)
534
+ self.scopes.pop();
535
+ })));
536
+ while (true) {
537
+ const current = iterator
538
+ ? yield* self.nextIteratorResult(iterator, node, awaiting)
539
+ : yield* cursor?.next ?? Effect.fail(new InterpreterRuntimeError("Iterator is unavailable.", node));
540
+ const step = cursor && awaiting ? { done: current.done, value: yield* self.awaitValue(current.value) } : current;
541
+ if (step.done)
542
+ return { kind: "none" };
543
+ const bodyExit = yield* Effect.exit(evaluateBody(step.value));
544
+ if (!Exit.isSuccess(bodyExit)) {
545
+ // Process interruption must remain prompt; user cleanup cannot extend a timeout.
546
+ if (!Cause.hasInterruptsOnly(bodyExit.cause)) {
547
+ yield* Effect.exit(close());
548
+ }
549
+ return yield* Effect.failCause(bodyExit.cause);
550
+ }
551
+ const exit = loopExit(bodyExit.value, labels);
552
+ if (exit !== undefined) {
553
+ yield* close();
554
+ return exit;
555
+ }
556
+ }
557
+ }).pipe(Effect.ensuring(Effect.sync(() => {
558
+ if (declared?.lexical)
559
+ self.scopes.pop();
560
+ })));
561
+ }
562
+ awaitValue(value, node = promiseResolutionNode) {
563
+ return Effect.flatMap(resolvePromise(this.runtime.runner, this.runtime.promises, value, node), (promise) => this.settlePromise(promise));
564
+ }
565
+ awaitAsyncFromSyncValue(iterator, value, node, closeOnRejection) {
566
+ const self = this;
567
+ return Effect.gen(function* () {
568
+ const settled = yield* Effect.exit(self.awaitValue(value));
569
+ if (Exit.isSuccess(settled))
570
+ return settled.value;
571
+ if (closeOnRejection && !Cause.hasInterruptsOnly(settled.cause)) {
572
+ yield* Effect.exit(self.closeIterator(iterator, node, false));
573
+ }
574
+ return yield* Effect.failCause(settled.cause);
575
+ });
576
+ }
577
+ syncIterator(value, node) {
578
+ const iterator = value instanceof ProgramArray
579
+ ? value.items[Symbol.iterator]()
580
+ : typeof value === "string"
581
+ ? value[Symbol.iterator]()
582
+ : value instanceof Values.Map
583
+ ? value.map.entries()
584
+ : value instanceof Values.Set
585
+ ? value.set.values()
586
+ : value instanceof Values.URLSearchParams
587
+ ? value.params.entries()
588
+ : undefined;
589
+ if (iterator !== undefined) {
590
+ return Effect.succeed({
591
+ next: Effect.sync(() => {
592
+ const step = iterator.next();
593
+ return {
594
+ done: Boolean(step.done),
595
+ value: Array.isArray(step.value) ? new ProgramArray(step.value) : step.value,
596
+ };
597
+ }),
598
+ close: Effect.void,
599
+ });
600
+ }
601
+ const self = this;
602
+ return Effect.map(this.customIterator(value, node, false), (iterator) => iterator === undefined
603
+ ? undefined
604
+ : {
605
+ next: self.nextIteratorResult(iterator, node, false),
606
+ close: Effect.suspend(() => self.closeIterator(iterator, node, false)),
607
+ });
608
+ }
609
+ customIterator(value, node, allowAsync = true) {
610
+ if (value instanceof CodeModeGenerator) {
611
+ if (value.asynchronous && !allowAsync)
612
+ return Effect.undefined;
613
+ return Effect.succeed({
614
+ iterator: value,
615
+ next: new GeneratorMethodReference(value, "next"),
616
+ asynchronous: value.asynchronous,
617
+ });
618
+ }
619
+ if (!(value instanceof ProgramObject))
620
+ return Effect.undefined;
621
+ const asyncMethod = allowAsync ? get(value, AsyncIteratorSymbol) : undefined;
622
+ const method = asyncMethod ?? get(value, IteratorSymbol);
623
+ if (method === undefined || method === null)
624
+ return Effect.undefined;
625
+ const self = this;
626
+ return Effect.map(this.invokeCallable(this.requireIteratorMethod(method, "Iterator method", node), [], node), (iterator) => {
627
+ const object = self.requireIterator(iterator, node);
628
+ return {
629
+ iterator: object,
630
+ next: object instanceof CodeModeGenerator
631
+ ? new GeneratorMethodReference(object, "next")
632
+ : self.requireIteratorMethod(get(object, "next"), "Iterator next", node),
633
+ asynchronous: asyncMethod !== undefined && asyncMethod !== null,
634
+ };
635
+ });
636
+ }
637
+ nextIteratorResult(iterator, node, awaiting) {
638
+ const self = this;
639
+ return Effect.gen(function* () {
640
+ if (iterator.asynchronous) {
641
+ const object = self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(iterator.next, [], node)), "Iterator next() result", node);
642
+ return { done: Boolean(get(object, "done")), value: get(object, "value") };
643
+ }
644
+ const called = yield* Effect.exit(self.invokeCallable(iterator.next, [], node));
645
+ if (!Exit.isSuccess(called)) {
646
+ if (awaiting)
647
+ yield* Effect.yieldNow;
648
+ return yield* Effect.failCause(called.cause);
649
+ }
650
+ const captured = yield* Effect.exit(Effect.sync(() => {
651
+ const object = self.requireIteratorObject(called.value, "Iterator next() result", node);
652
+ return { done: Boolean(get(object, "done")), value: get(object, "value") };
653
+ }));
654
+ if (!Exit.isSuccess(captured)) {
655
+ if (awaiting)
656
+ yield* Effect.yieldNow;
657
+ return yield* Effect.failCause(captured.cause);
658
+ }
659
+ return {
660
+ done: captured.value.done,
661
+ value: awaiting
662
+ ? yield* self.awaitAsyncFromSyncValue(iterator, captured.value.value, node, !captured.value.done)
663
+ : captured.value.value,
664
+ };
665
+ });
666
+ }
667
+ closeIterator(iterator, node, awaiting = true) {
668
+ const close = iterator.iterator instanceof CodeModeGenerator
669
+ ? new GeneratorMethodReference(iterator.iterator, "return")
670
+ : get(iterator.iterator, "return");
671
+ if (close === undefined || close === null)
672
+ return iterator.asynchronous || !awaiting ? Effect.void : Effect.yieldNow;
673
+ const self = this;
674
+ return Effect.gen(function* () {
675
+ const method = self.requireIteratorMethod(close, "Iterator return", node);
676
+ if (iterator.asynchronous) {
677
+ self.requireIteratorObject(yield* self.awaitValue(yield* self.invokeCallable(method, [], node)), "Iterator return() result", node);
678
+ return;
679
+ }
680
+ const called = yield* Effect.exit(self.invokeCallable(method, [], node));
681
+ if (!Exit.isSuccess(called)) {
682
+ if (awaiting)
683
+ yield* Effect.yieldNow;
684
+ return yield* Effect.failCause(called.cause);
685
+ }
686
+ const captured = yield* Effect.exit(Effect.sync(() => get(self.requireIteratorObject(called.value, "Iterator return() result", node), "value")));
687
+ if (!Exit.isSuccess(captured)) {
688
+ if (awaiting)
689
+ yield* Effect.yieldNow;
690
+ return yield* Effect.failCause(captured.cause);
691
+ }
692
+ if (awaiting)
693
+ yield* self.awaitValue(captured.value);
694
+ });
695
+ }
696
+ requireIteratorObject(value, context, node) {
697
+ if (value instanceof ProgramObject)
698
+ return value;
699
+ throw new InterpreterRuntimeError(`${context} must be an object.`, node).as("TypeError");
700
+ }
701
+ requireIterator(value, node) {
702
+ return value instanceof CodeModeGenerator
703
+ ? value
704
+ : this.requireIteratorObject(value, "Iterator method result", node);
705
+ }
706
+ requireIteratorMethod(value, context, node) {
707
+ if (typeofValue(value) === "function")
708
+ return value;
709
+ throw new InterpreterRuntimeError(`${context} must be a function.`, node).as("TypeError");
710
+ }
711
+ // for...in over null/undefined iterates nothing, like JS.
712
+ enumerableKeys(value, node) {
713
+ if (value instanceof ToolReference)
714
+ return [...this.runtime.toolKeys(value.path)];
715
+ if (value === null || value === undefined)
716
+ return [];
717
+ return ownKeys(enumerableSource("for...in", value, node)).filter((key) => typeof key === "string");
718
+ }
719
+ evaluateForInStatement(node, labels) {
720
+ const left = node.left;
721
+ const declared = loopDeclaration(left, "for...in");
722
+ if (declared?.lexical)
723
+ this.scopes.push();
724
+ const self = this;
725
+ return Effect.gen(function* () {
726
+ if (declared?.lexical)
727
+ self.predeclarePattern(declared.pattern, declared.mutable, left);
728
+ const right = yield* self.evaluateExpression(node.right);
729
+ const keys = self.enumerableKeys(right, node.right);
730
+ if (left.type !== "Identifier" && left.type !== "VariableDeclaration") {
731
+ throw new InterpreterRuntimeError("Unsupported for...in binding.", left);
732
+ }
733
+ const assignmentName = left.type === "Identifier" ? left.name : undefined;
734
+ for (const key of keys) {
735
+ const result = yield* Effect.gen(function* () {
736
+ if (declared?.lexical) {
737
+ self.scopes.push();
738
+ self.predeclarePattern(declared.pattern, declared.mutable, left);
739
+ yield* self.declarePattern(declared.pattern, key, declared.mutable, left, true);
740
+ }
741
+ else if (declared) {
742
+ yield* self.assignPattern(declared.pattern, key, left);
743
+ }
744
+ else if (assignmentName) {
745
+ self.scopes.set(assignmentName, key, left);
746
+ }
747
+ return yield* self.evaluateStatement(node.body);
748
+ }).pipe(Effect.ensuring(Effect.sync(() => {
749
+ if (declared?.lexical)
750
+ self.scopes.pop();
751
+ })));
752
+ const exit = loopExit(result, labels);
753
+ if (exit !== undefined)
754
+ return exit;
755
+ }
756
+ return { kind: "none" };
757
+ }).pipe(Effect.ensuring(Effect.sync(() => {
758
+ if (declared?.lexical)
759
+ self.scopes.pop();
760
+ })));
761
+ }
762
+ evaluateBreakStatement(node) {
763
+ return node.label ? { kind: "break", label: node.label.name } : { kind: "break" };
764
+ }
765
+ evaluateContinueStatement(node) {
766
+ return node.label ? { kind: "continue", label: node.label.name } : { kind: "continue" };
767
+ }
768
+ evaluateLabeledStatement(node) {
769
+ const labels = new Set();
770
+ let body = node;
771
+ while (body.type === "LabeledStatement") {
772
+ labels.add(body.label.name);
773
+ body = body.body;
774
+ }
775
+ const evaluated = (() => {
776
+ if (body.type === "WhileStatement")
777
+ return this.evaluateWhileStatement(body, labels);
778
+ if (body.type === "DoWhileStatement")
779
+ return this.evaluateDoWhileStatement(body, labels);
780
+ if (body.type === "ForStatement")
781
+ return this.evaluateForStatement(body, labels);
782
+ if (body.type === "ForOfStatement")
783
+ return this.evaluateForOfStatement(body, labels);
784
+ if (body.type === "ForInStatement")
785
+ return this.evaluateForInStatement(body, labels);
786
+ return this.evaluateStatement(body);
787
+ })();
788
+ return Effect.map(evaluated, (result) => result.kind === "break" && result.label !== undefined && labels.has(result.label)
789
+ ? { kind: "none" }
790
+ : result);
791
+ }
792
+ evaluateThrowStatement(node) {
793
+ return Effect.flatMap(this.evaluateExpression(node.argument), (value) => Effect.fail(new ProgramThrow(value)));
794
+ }
795
+ evaluateTryStatement(node) {
796
+ const body = node.block;
797
+ const handler = node.handler;
798
+ const finalizer = node.finalizer;
799
+ const self = this;
800
+ const attempted = Effect.matchCauseEffect(this.evaluateStatement(body), {
801
+ onFailure: (cause) => {
802
+ if (cause.reasons.some(Cause.isInterruptReason) || Cause.squash(cause) instanceof GeneratorReturn || !handler) {
803
+ return Effect.failCause(cause);
804
+ }
805
+ const caught = caughtErrorValue(Cause.squash(cause));
806
+ const parameter = handler.param;
807
+ self.scopes.push();
808
+ return Effect.gen(function* () {
809
+ if (parameter)
810
+ yield* self.declarePattern(parameter, caught, true, handler);
811
+ return yield* self.evaluateStatement(handler.body);
812
+ }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
813
+ },
814
+ onSuccess: Effect.succeed,
815
+ });
816
+ if (!finalizer)
817
+ return attempted;
818
+ const isAbrupt = (result) => result.kind === "return" || result.kind === "break" || result.kind === "continue";
819
+ return Effect.matchCauseEffect(attempted, {
820
+ onFailure: (cause) => cause.reasons.some(Cause.isInterruptReason)
821
+ ? Effect.failCause(cause)
822
+ : Effect.flatMap(this.evaluateStatement(finalizer), (final) => isAbrupt(final) ? Effect.succeed(final) : Effect.failCause(cause)),
823
+ onSuccess: (result) => Effect.flatMap(this.evaluateStatement(finalizer), (final) => isAbrupt(final) ? Effect.succeed(final) : Effect.succeed(result)),
824
+ });
825
+ }
826
+ evaluateVariableDeclaration(node) {
827
+ const kind = node.kind;
828
+ const self = this;
829
+ return Effect.gen(function* () {
830
+ for (const declaration of node.declarations) {
831
+ if (declaration.type !== "VariableDeclarator") {
832
+ throw new InterpreterRuntimeError("Unsupported variable declaration shape.", declaration);
833
+ }
834
+ const init = declaration.init;
835
+ // `var x` alone is a no-op: the binding was hoisted on function entry.
836
+ const id = declaration.id;
837
+ const evaluate = (init) => id.type === "Identifier" ? self.evaluateNamed(init, id.name) : self.evaluateExpression(init);
838
+ if (kind === "var") {
839
+ if (init)
840
+ yield* self.assignPattern(id, yield* evaluate(init), declaration);
841
+ continue;
842
+ }
843
+ const value = init ? yield* evaluate(init) : undefined;
844
+ yield* self.declarePattern(declaration.id, value, kind !== "const", declaration, true);
845
+ }
846
+ });
847
+ }
848
+ declarePattern(pattern, value, mutable, node, initialize = false) {
849
+ const self = this;
850
+ return Effect.gen(function* () {
851
+ if (pattern.type === "Identifier") {
852
+ const name = pattern.name;
853
+ if (initialize)
854
+ self.scopes.initialize(name, value, node);
855
+ else
856
+ self.scopes.declare(name, value, mutable, node);
857
+ return;
858
+ }
859
+ if (pattern.type === "AssignmentPattern") {
860
+ const resolved = value === undefined ? yield* self.evaluateDefault(pattern) : value;
861
+ yield* self.declarePattern(pattern.left, resolved, mutable, node, initialize);
862
+ return;
863
+ }
864
+ if (pattern.type === "ObjectPattern") {
865
+ if (!(value instanceof ProgramObject)) {
866
+ throw new InterpreterRuntimeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern, "InvalidDataValue");
867
+ }
868
+ const consumed = new Set();
869
+ for (const property of pattern.properties) {
870
+ if (property.type === "RestElement") {
871
+ const rest = new ProgramObject();
872
+ assign(rest, value, consumed);
873
+ yield* self.declarePattern(property.argument, rest, mutable, property, initialize);
874
+ continue;
875
+ }
876
+ const key = yield* self.destructuringPropertyKey(property);
877
+ consumed.add(typeof key === "symbol" ? key : String(key));
878
+ yield* self.declarePattern(property.value, self.destructuringPropertyValue(value, key), mutable, property, initialize);
879
+ }
880
+ return;
881
+ }
882
+ if (pattern.type === "ArrayPattern") {
883
+ return yield* self.destructureArrayPattern(pattern, value, (target, item, context) => self.declarePattern(target, item, mutable, context, initialize));
884
+ }
885
+ throw new InterpreterRuntimeError(`Unsupported binding pattern '${pattern.type}'.`, pattern);
886
+ });
887
+ }
888
+ assignPattern(pattern, value, node) {
889
+ const self = this;
890
+ return Effect.gen(function* () {
891
+ if (pattern.type === "Identifier") {
892
+ self.scopes.set(pattern.name, value, pattern);
893
+ return;
894
+ }
895
+ if (pattern.type === "MemberExpression") {
896
+ yield* self.writeMember(pattern, value);
897
+ return;
898
+ }
899
+ if (pattern.type === "AssignmentPattern") {
900
+ const resolved = value === undefined ? yield* self.evaluateDefault(pattern) : value;
901
+ yield* self.assignPattern(pattern.left, resolved, node);
902
+ return;
903
+ }
904
+ if (pattern.type === "ObjectPattern") {
905
+ if (!(value instanceof ProgramObject)) {
906
+ throw new InterpreterRuntimeError(`Object destructuring requires a data object or array value, received ${describeValue(value)}.`, pattern, "InvalidDataValue");
907
+ }
908
+ const consumed = new Set();
909
+ for (const property of pattern.properties) {
910
+ if (property.type === "RestElement") {
911
+ const rest = new ProgramObject();
912
+ assign(rest, value, consumed);
913
+ yield* self.assignPattern(property.argument, rest, property);
914
+ continue;
915
+ }
916
+ const key = yield* self.destructuringPropertyKey(property);
917
+ consumed.add(typeof key === "symbol" ? key : String(key));
918
+ yield* self.assignPattern(property.value, self.destructuringPropertyValue(value, key), property);
919
+ }
920
+ return;
921
+ }
922
+ if (pattern.type === "ArrayPattern") {
923
+ return yield* self.destructureArrayPattern(pattern, value, (target, item, context) => self.assignPattern(target, item, context));
924
+ }
925
+ throw new InterpreterRuntimeError(`Unsupported assignment pattern '${pattern.type}'.`, node);
926
+ });
927
+ }
928
+ evaluateDefault(pattern) {
929
+ return pattern.left.type === "Identifier"
930
+ ? this.evaluateNamed(pattern.right, pattern.left.name)
931
+ : this.evaluateExpression(pattern.right);
932
+ }
933
+ destructureArrayPattern(pattern, value, consume) {
934
+ const self = this;
935
+ return Effect.gen(function* () {
936
+ const cursor = yield* self.syncIterator(value, pattern);
937
+ if (cursor === undefined) {
938
+ throw new InterpreterRuntimeError("Array destructuring requires a supported iterable value.", pattern).as("TypeError");
939
+ }
940
+ let done = false;
941
+ for (const element of pattern.elements) {
942
+ if (done) {
943
+ if (element === null)
944
+ continue;
945
+ yield* consume(element.type === "RestElement" ? element.argument : element, element.type === "RestElement" ? new ProgramArray() : undefined, element);
946
+ if (element.type === "RestElement")
947
+ return;
948
+ continue;
949
+ }
950
+ const step = yield* cursor.next;
951
+ done = step.done;
952
+ if (element === null)
953
+ continue;
954
+ if (element.type === "RestElement") {
955
+ const rest = [];
956
+ if (!step.done)
957
+ rest.push(step.value);
958
+ while (!done) {
959
+ const next = yield* cursor.next;
960
+ done = next.done;
961
+ if (!done)
962
+ rest.push(next.value);
963
+ }
964
+ yield* consume(element.argument, new ProgramArray(rest), element);
965
+ return;
966
+ }
967
+ const consumed = consume(element, step.done ? undefined : step.value, pattern);
968
+ yield* step.done ? consumed : preserveConsumerError(cursor, consumed);
969
+ }
970
+ if (!done)
971
+ yield* cursor.close;
972
+ });
973
+ }
974
+ destructuringPropertyKey(property) {
975
+ if (property.type !== "Property" || property.kind !== "init") {
976
+ throw new InterpreterRuntimeError("Unsupported object destructuring property.", property);
977
+ }
978
+ const keyNode = property.key;
979
+ if (property.computed) {
980
+ return Effect.map(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value, keyNode));
981
+ }
982
+ if (keyNode.type === "Identifier")
983
+ return Effect.succeed(keyNode.name);
984
+ if (keyNode.type === "Literal")
985
+ return Effect.succeed(String(keyNode.value));
986
+ throw unsupportedSyntax(keyNode.type, keyNode);
987
+ }
988
+ destructuringPropertyValue(source, key) {
989
+ if (!(source instanceof ProgramArray))
990
+ return get(source, key);
991
+ if (has(source, key))
992
+ return get(source, key);
993
+ if (typeof key === "string" && arrayMethods.has(key))
994
+ return new IntrinsicReference(source, key);
995
+ return undefined;
996
+ }
997
+ evaluateExpression(node) {
998
+ switch (node.type) {
999
+ case "Literal": {
1000
+ const regex = node.regex;
1001
+ if (regex)
1002
+ return Effect.sync(() => constructRegExp([regex.pattern, regex.flags], node));
1003
+ return Effect.sync(() => toProgram(node.value, "Literal"));
1004
+ }
1005
+ case "Identifier":
1006
+ return Effect.sync(() => this.scopes.get(node.name, node));
1007
+ case "BinaryExpression":
1008
+ return this.evaluateBinaryExpression(node);
1009
+ case "LogicalExpression":
1010
+ return this.evaluateLogicalExpression(node);
1011
+ case "UnaryExpression":
1012
+ return this.evaluateUnaryExpression(node);
1013
+ case "AssignmentExpression":
1014
+ return this.evaluateAssignmentExpression(node);
1015
+ case "SequenceExpression": {
1016
+ const self = this;
1017
+ return Effect.gen(function* () {
1018
+ let result;
1019
+ for (const expression of node.expressions) {
1020
+ result = yield* self.evaluateExpression(expression);
1021
+ }
1022
+ return result;
1023
+ });
1024
+ }
1025
+ case "CallExpression":
1026
+ return this.evaluateCallExpression(node);
1027
+ case "ArrowFunctionExpression":
1028
+ case "FunctionExpression":
1029
+ return Effect.sync(() => this.createFunction(node));
1030
+ case "MemberExpression":
1031
+ return this.readMember(node);
1032
+ case "ChainExpression":
1033
+ return Effect.map(this.evaluateExpression(node.expression), (value) => value === OptionalShortCircuit ? undefined : value);
1034
+ case "ObjectExpression":
1035
+ return this.evaluateObjectExpression(node);
1036
+ case "ArrayExpression":
1037
+ return this.evaluateArrayExpression(node);
1038
+ case "TemplateLiteral":
1039
+ return this.evaluateTemplateLiteral(node);
1040
+ case "ConditionalExpression":
1041
+ return this.evaluateConditionalExpression(node);
1042
+ case "UpdateExpression":
1043
+ return this.evaluateUpdateExpression(node);
1044
+ case "AwaitExpression": {
1045
+ // Await always suspends, including for plain values.
1046
+ return Effect.flatMap(this.evaluateExpression(node.argument), (value) => this.awaitValue(value, node));
1047
+ }
1048
+ case "YieldExpression":
1049
+ return this.evaluateYieldExpression(node);
1050
+ case "NewExpression":
1051
+ return this.evaluateNewExpression(node);
1052
+ default:
1053
+ throw unsupportedSyntax(node.type, node);
1054
+ }
1055
+ }
1056
+ evaluateNewExpression(node) {
1057
+ const self = this;
1058
+ return Effect.gen(function* () {
1059
+ const callee = yield* self.evaluateExpression(node.callee);
1060
+ // Globals are built with this interpreter's R; `instanceof` cannot recover the type argument.
1061
+ const construct = callee instanceof HostFunction ? callee.construct : undefined;
1062
+ if (construct === undefined) {
1063
+ // `new` itself is supported, so a non-constructible callee is a TypeError like JS rather than
1064
+ // unsupported syntax. Built-ins like Number are real constructors in JS, so do not claim
1065
+ // otherwise; say `new` is unsupported for them and point at the plain call.
1066
+ const name = calleeDescription(node.callee);
1067
+ const message = callee instanceof ProgramFunction
1068
+ ? `${name} cannot be constructed: user-defined constructors and classes are not supported. Call it as a function that returns a plain object instead.`
1069
+ : callee instanceof HostFunction
1070
+ ? `new ${name}(...) is not supported; call ${name}(...) without new instead.`
1071
+ : `${name} is not a constructor.`;
1072
+ throw new InterpreterRuntimeError(message, node).as("TypeError");
1073
+ }
1074
+ const args = yield* self.evaluateCallArguments(node.arguments);
1075
+ return yield* construct(args, node);
1076
+ });
1077
+ }
1078
+ evaluateBinaryExpression(node) {
1079
+ const operator = node.operator;
1080
+ const left = node.left;
1081
+ if (left.type === "PrivateIdentifier")
1082
+ throw unsupportedSyntax(left.type, left);
1083
+ const self = this;
1084
+ return Effect.gen(function* () {
1085
+ const lhs = yield* self.evaluateExpression(left);
1086
+ const rhs = yield* self.evaluateExpression(node.right);
1087
+ if (operator === "instanceof")
1088
+ return instanceofValue(lhs, rhs, node);
1089
+ return toProgram(self.applyBinaryOperator(operator, lhs, rhs, node), "Binary expression result");
1090
+ });
1091
+ }
1092
+ applyBinaryOperator(operator, lhs, rhs, node) {
1093
+ if (operator === "===")
1094
+ return lhs === rhs;
1095
+ if (operator === "!==")
1096
+ return lhs !== rhs;
1097
+ if (operator === "in" && rhs instanceof ProgramObject && !containsOpaqueReference(lhs)) {
1098
+ return has(rhs, lhs !== null && typeof lhs === "object" ? coerceToString(lhs) : lhs);
1099
+ }
1100
+ if (containsOpaqueReference(lhs) || containsOpaqueReference(rhs)) {
1101
+ throw new InterpreterRuntimeError("Binary operators require data values.", node, "InvalidDataValue");
1102
+ }
1103
+ // Null-prototype data needs explicit primitive coercion; identity and `in` retain raw objects.
1104
+ // Dates use their default string hint for addition and loose equality, and epoch time elsewhere.
1105
+ const coerceOperand = (operand) => {
1106
+ if (operand instanceof Values.Date) {
1107
+ return operator === "+" || operator === "==" || operator === "!=" ? coerceToString(operand) : operand.time;
1108
+ }
1109
+ return operand !== null && typeof operand === "object" ? coerceToString(operand) : operand;
1110
+ };
1111
+ const bothObjects = lhs !== null && typeof lhs === "object" && rhs !== null && typeof rhs === "object";
1112
+ const l = coerceOperand(lhs);
1113
+ const r = coerceOperand(rhs);
1114
+ switch (operator) {
1115
+ case "+":
1116
+ return l + r;
1117
+ case "-":
1118
+ return l - r;
1119
+ case "*":
1120
+ return l * r;
1121
+ case "/":
1122
+ return l / r;
1123
+ case "%":
1124
+ return l % r;
1125
+ case "**":
1126
+ return l ** r;
1127
+ case "==":
1128
+ return bothObjects ? lhs === rhs : l == r;
1129
+ case "!=":
1130
+ return bothObjects ? lhs !== rhs : l != r;
1131
+ case "<":
1132
+ return l < r;
1133
+ case "<=":
1134
+ return l <= r;
1135
+ case ">":
1136
+ return l > r;
1137
+ case ">=":
1138
+ return l >= r;
1139
+ case "&":
1140
+ return l & r;
1141
+ case "|":
1142
+ return l | r;
1143
+ case "^":
1144
+ return l ^ r;
1145
+ case "<<":
1146
+ return l << r;
1147
+ case ">>":
1148
+ return l >> r;
1149
+ case ">>>":
1150
+ return l >>> r;
1151
+ case "in":
1152
+ if (!(rhs instanceof ProgramObject)) {
1153
+ throw new InterpreterRuntimeError("The 'in' operator requires a data object on the right-hand side.", node);
1154
+ }
1155
+ return has(rhs, coerceOperand(lhs));
1156
+ default:
1157
+ throw new InterpreterRuntimeError(`Unsupported binary operator '${operator}'.`, node);
1158
+ }
1159
+ }
1160
+ evaluateLogicalExpression(node) {
1161
+ const operator = node.operator;
1162
+ return Effect.flatMap(this.evaluateExpression(node.left), (left) => {
1163
+ if (operator === "&&")
1164
+ return left ? this.evaluateExpression(node.right) : Effect.succeed(left);
1165
+ if (operator === "||")
1166
+ return left ? Effect.succeed(left) : this.evaluateExpression(node.right);
1167
+ if (operator === "??")
1168
+ return left !== null && left !== undefined ? Effect.succeed(left) : this.evaluateExpression(node.right);
1169
+ throw new InterpreterRuntimeError(`Unsupported logical operator '${operator}'.`, node);
1170
+ });
1171
+ }
1172
+ evaluateUnaryExpression(node) {
1173
+ const operator = node.operator;
1174
+ const argument = node.argument;
1175
+ if (operator === "delete")
1176
+ return this.evaluateDeleteExpression(argument);
1177
+ // Undeclared names short-circuit, but declared TDZ bindings must still throw.
1178
+ if (operator === "typeof" && argument.type === "Identifier" && !this.scopes.resolve(argument.name)) {
1179
+ return Effect.succeed("undefined");
1180
+ }
1181
+ return Effect.map(this.evaluateExpression(argument), (value) => {
1182
+ if (operator === "typeof")
1183
+ return typeofValue(value);
1184
+ if (operator === "!")
1185
+ return !value;
1186
+ if (operator === "void")
1187
+ return undefined;
1188
+ if (containsOpaqueReference(value)) {
1189
+ throw new InterpreterRuntimeError("Unary operators require data values.", node, "InvalidDataValue");
1190
+ }
1191
+ const operand = value instanceof Values.Date
1192
+ ? value.time
1193
+ : value !== null && typeof value === "object"
1194
+ ? coerceToString(value)
1195
+ : value;
1196
+ let result;
1197
+ switch (operator) {
1198
+ case "+":
1199
+ result = +operand;
1200
+ break;
1201
+ case "-":
1202
+ result = -operand;
1203
+ break;
1204
+ case "~":
1205
+ result = ~operand;
1206
+ break;
1207
+ default:
1208
+ throw new InterpreterRuntimeError(`Unsupported unary operator '${operator}'.`, node);
1209
+ }
1210
+ return toProgram(result, "Unary expression result");
1211
+ });
1212
+ }
1213
+ evaluateAssignmentExpression(node) {
1214
+ const left = node.left;
1215
+ const operator = node.operator;
1216
+ const self = this;
1217
+ return Effect.gen(function* () {
1218
+ if (operator === "??=" || operator === "||=" || operator === "&&=") {
1219
+ return yield* self.evaluateLogicalAssignment(node, left, operator);
1220
+ }
1221
+ if (operator === "=" && (left.type === "ObjectPattern" || left.type === "ArrayPattern")) {
1222
+ const rightValue = yield* self.evaluateExpression(node.right);
1223
+ yield* self.assignPattern(left, rightValue, node);
1224
+ return rightValue;
1225
+ }
1226
+ if (left.type === "Identifier") {
1227
+ const name = left.name;
1228
+ if (operator !== "=") {
1229
+ const current = self.scopes.get(name, left);
1230
+ const rightValue = yield* self.evaluateExpression(node.right);
1231
+ const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1232
+ return self.scopes.set(name, next, left);
1233
+ }
1234
+ const rightValue = yield* self.evaluateNamed(node.right, name);
1235
+ return self.scopes.set(name, rightValue, left);
1236
+ }
1237
+ if (left.type === "MemberExpression") {
1238
+ return yield* self.modifyMember(left, (current) => Effect.map(self.evaluateExpression(node.right), (rightValue) => {
1239
+ if (operator === "=")
1240
+ return { write: true, next: rightValue, result: rightValue };
1241
+ const next = toProgram(self.applyCompoundAssignment(operator, current, rightValue, node), "Assignment result");
1242
+ return { write: true, next, result: next };
1243
+ }));
1244
+ }
1245
+ throw new InterpreterRuntimeError("Assignment target must be an Identifier or MemberExpression.", left);
1246
+ });
1247
+ }
1248
+ evaluateLogicalAssignment(node, left, operator) {
1249
+ const self = this;
1250
+ const shouldAssign = (current) => operator === "??=" ? current === null || current === undefined : operator === "||=" ? !current : Boolean(current);
1251
+ if (left.type === "Identifier") {
1252
+ const name = left.name;
1253
+ return Effect.gen(function* () {
1254
+ const current = self.scopes.get(name, left);
1255
+ if (!shouldAssign(current))
1256
+ return current;
1257
+ const rightValue = yield* self.evaluateNamed(node.right, name);
1258
+ return self.scopes.set(name, rightValue, left);
1259
+ });
1260
+ }
1261
+ if (left.type === "MemberExpression") {
1262
+ return self.modifyMember(left, (current) => shouldAssign(current)
1263
+ ? Effect.map(self.evaluateExpression(node.right), (rightValue) => ({
1264
+ write: true,
1265
+ next: rightValue,
1266
+ result: rightValue,
1267
+ }))
1268
+ : Effect.succeed({ write: false, next: current, result: current }));
1269
+ }
1270
+ throw new InterpreterRuntimeError("Assignment target must be an Identifier or MemberExpression.", left);
1271
+ }
1272
+ evaluateUpdateExpression(node) {
1273
+ const operator = node.operator;
1274
+ const argument = node.argument;
1275
+ const prefix = node.prefix;
1276
+ const increment = operator === "++" ? 1 : operator === "--" ? -1 : undefined;
1277
+ if (increment === undefined) {
1278
+ throw new InterpreterRuntimeError(`Unsupported update operator '${operator}'.`, node);
1279
+ }
1280
+ // CodeMode numeric coercion, not host Number(): null-prototype data objects would make
1281
+ // the host throw during ToPrimitive, and opaque runtime references must reject clearly.
1282
+ const operand = (current) => {
1283
+ if (containsOpaqueReference(current)) {
1284
+ throw new InterpreterRuntimeError(`'${operator}' requires a data value.`, argument, "InvalidDataValue");
1285
+ }
1286
+ return coerceToNumber(current);
1287
+ };
1288
+ if (argument.type === "Identifier") {
1289
+ return Effect.sync(() => {
1290
+ const name = argument.name;
1291
+ const current = operand(this.scopes.get(name, argument));
1292
+ const next = current + increment;
1293
+ this.scopes.set(name, next, argument);
1294
+ return prefix ? next : current;
1295
+ });
1296
+ }
1297
+ if (argument.type === "MemberExpression") {
1298
+ return this.modifyMember(argument, (current) => {
1299
+ const value = operand(current);
1300
+ const next = value + increment;
1301
+ return Effect.succeed({ write: true, next, result: prefix ? next : value });
1302
+ });
1303
+ }
1304
+ throw new InterpreterRuntimeError("Update target must be an Identifier or MemberExpression.", argument);
1305
+ }
1306
+ evaluateCallExpression(node) {
1307
+ const callee = node.callee;
1308
+ const self = this;
1309
+ return Effect.gen(function* () {
1310
+ if (callee.type === "Super")
1311
+ throw unsupportedSyntax(callee.type, callee);
1312
+ const callable = yield* self.evaluateExpression(callee);
1313
+ if (callable === OptionalShortCircuit)
1314
+ return OptionalShortCircuit;
1315
+ if ((callable === null || callable === undefined) && node.optional)
1316
+ return OptionalShortCircuit;
1317
+ const args = yield* self.evaluateCallArguments(node.arguments);
1318
+ return yield* self.invokeCallable(callable, args, node, callee);
1319
+ });
1320
+ }
1321
+ // The single dispatch for every invocation: call expressions and callbacks share it.
1322
+ invokeCallable(callable, args, node, callee) {
1323
+ const self = this;
1324
+ return Effect.gen(function* () {
1325
+ if (callable instanceof ToolReference) {
1326
+ if (callable.path.length === 0) {
1327
+ throw new InterpreterRuntimeError("The tools root is not callable.", callee ?? node);
1328
+ }
1329
+ return yield* self.createToolCallPromise(callable.path, args);
1330
+ }
1331
+ if (callable instanceof ProgramFunction) {
1332
+ return yield* self.invokeFunction(callable, args);
1333
+ }
1334
+ if (callable instanceof GeneratorMethodReference) {
1335
+ if (callable.kind === "iterator")
1336
+ return callable.generator;
1337
+ const requested = callable.generator.request(callable.kind, args[0], node);
1338
+ return callable.generator.asynchronous ? yield* self.createPromise(requested) : yield* requested;
1339
+ }
1340
+ if (callable instanceof IntrinsicReference) {
1341
+ return yield* invokeIntrinsic(self.runtime.runner, callable, args, node);
1342
+ }
1343
+ if (callable instanceof PromiseInstanceMethodReference) {
1344
+ return yield* invokePromiseInstanceMethod(self.runtime.runner, self.runtime.promises, callable, args, node);
1345
+ }
1346
+ if (callable instanceof HostFunction)
1347
+ return yield* callable.call(args, node);
1348
+ if (callable === undefined || callable === null) {
1349
+ throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node).as("TypeError");
1350
+ }
1351
+ throw new InterpreterRuntimeError("Only tools are callable here.", callee ?? node);
1352
+ });
1353
+ }
1354
+ evaluateCallArguments(argNodes) {
1355
+ const self = this;
1356
+ return Effect.gen(function* () {
1357
+ const args = [];
1358
+ for (const argNode of argNodes) {
1359
+ if (argNode.type === "SpreadElement") {
1360
+ const spread = yield* self.evaluateExpression(argNode.argument);
1361
+ const cursor = yield* self.syncIterator(spread, argNode);
1362
+ if (cursor === undefined)
1363
+ throw new InterpreterRuntimeError("Spread arguments require a synchronous iterable.", argNode).as("TypeError");
1364
+ while (true) {
1365
+ const step = yield* cursor.next;
1366
+ if (step.done)
1367
+ break;
1368
+ args.push(step.value);
1369
+ }
1370
+ }
1371
+ else {
1372
+ args.push(yield* self.evaluateExpression(argNode));
1373
+ }
1374
+ }
1375
+ return args;
1376
+ });
1377
+ }
1378
+ invokeFunction(fn, args) {
1379
+ const invocation = new Frame(this.runtime, new ScopeStack([...fn.capturedScopes, new Map()]));
1380
+ const run = Effect.gen(function* () {
1381
+ // Seed all parameters first so defaults cannot fall through to same-named outer bindings.
1382
+ const paramScope = invocation.scopes.current();
1383
+ for (const parameter of fn.parameters) {
1384
+ for (const name of collectPatternNames(parameter)) {
1385
+ paramScope.set(name, { mutable: true, value: undefined, initialized: false });
1386
+ }
1387
+ }
1388
+ for (const [index, parameter] of fn.parameters.entries()) {
1389
+ if (parameter.type === "RestElement") {
1390
+ yield* invocation.declarePattern(parameter.argument, new ProgramArray(args.slice(index)), true, parameter, true);
1391
+ break;
1392
+ }
1393
+ yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
1394
+ }
1395
+ if (fn.body.type === "BlockStatement") {
1396
+ invocation.scopes.push();
1397
+ invocation.hoistVars(fn.body.body, paramScope);
1398
+ const result = yield* invocation.evaluateStatement(fn.body);
1399
+ return result.kind === "return" ? result.value : undefined;
1400
+ }
1401
+ return yield* invocation.evaluateExpression(fn.body);
1402
+ });
1403
+ if (fn.generator)
1404
+ return Effect.succeed(this.createGenerator(invocation, run, fn.async));
1405
+ if (!fn.async)
1406
+ return run;
1407
+ return this.runtime.promises.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, fn.body, self)));
1408
+ }
1409
+ createGenerator(invocation, run, asynchronous) {
1410
+ const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
1411
+ invocation.generatorState = state;
1412
+ invocation.generatorAsync = asynchronous;
1413
+ const generator = new CodeModeGenerator(asynchronous, (kind, value, node) => {
1414
+ const request = { kind, value, response: Deferred.makeUnsafe() };
1415
+ if (!asynchronous && state.active) {
1416
+ return Effect.fail(new InterpreterRuntimeError("Generator is already running.", node).as("TypeError"));
1417
+ }
1418
+ if (asynchronous && (state.completed || (!state.started && kind !== "next"))) {
1419
+ state.started = true;
1420
+ state.completed = true;
1421
+ state.pending.push(request);
1422
+ if (state.draining)
1423
+ return Deferred.await(request.response);
1424
+ state.draining = true;
1425
+ return Effect.andThen(this.runtime.promises.fork(invocation
1426
+ .completeGeneratorRequests(state, true)
1427
+ .pipe(Effect.ensuring(Effect.sync(() => (state.draining = false))))), Deferred.await(request.response));
1428
+ }
1429
+ if (state.completed) {
1430
+ if (kind === "throw")
1431
+ return Effect.fail(new ProgramThrow(value));
1432
+ return Effect.succeed(record({ value: kind === "return" ? value : undefined, done: true }));
1433
+ }
1434
+ if (!state.started && kind !== "next") {
1435
+ state.completed = true;
1436
+ if (kind === "throw")
1437
+ return Effect.fail(new ProgramThrow(value));
1438
+ return Effect.succeed(record({ value, done: true }));
1439
+ }
1440
+ state.pending.push(request);
1441
+ if (state.available) {
1442
+ const available = state.available;
1443
+ state.available = undefined;
1444
+ Deferred.doneUnsafe(available, Exit.succeed(undefined));
1445
+ }
1446
+ if (!state.started) {
1447
+ state.started = true;
1448
+ const body = Effect.gen(function* () {
1449
+ state.active = yield* invocation.takeGeneratorRequest(state);
1450
+ const exit = yield* Effect.exit(run.pipe(Effect.flatMap((result) => (asynchronous ? invocation.awaitValue(result) : Effect.succeed(result))), Effect.catch((error) => error instanceof GeneratorReturn
1451
+ ? asynchronous
1452
+ ? invocation.awaitValue(error.value)
1453
+ : Effect.succeed(error.value)
1454
+ : Effect.fail(error))));
1455
+ const active = state.active;
1456
+ state.active = undefined;
1457
+ if (active) {
1458
+ Deferred.doneUnsafe(active.response, Exit.isSuccess(exit) ? Exit.succeed(record({ value: exit.value, done: true })) : exit);
1459
+ }
1460
+ yield* invocation.completeGeneratorRequests(state, asynchronous);
1461
+ state.completed = true;
1462
+ });
1463
+ return Effect.andThen(this.runtime.promises.fork(body), Deferred.await(request.response));
1464
+ }
1465
+ return Deferred.await(request.response);
1466
+ });
1467
+ return generator;
1468
+ }
1469
+ completeGeneratorRequests(state, asynchronous) {
1470
+ const self = this;
1471
+ return Effect.gen(function* () {
1472
+ while (true) {
1473
+ const pending = self.dequeueGeneratorRequest(state);
1474
+ if (!pending)
1475
+ return;
1476
+ if (pending.kind === "throw") {
1477
+ Deferred.doneUnsafe(pending.response, Exit.fail(new ProgramThrow(pending.value)));
1478
+ continue;
1479
+ }
1480
+ if (asynchronous && pending.kind === "return") {
1481
+ const resolved = yield* Effect.exit(self.awaitValue(pending.value));
1482
+ Deferred.doneUnsafe(pending.response, Exit.isSuccess(resolved) ? Exit.succeed(record({ value: resolved.value, done: true })) : resolved);
1483
+ continue;
1484
+ }
1485
+ Deferred.doneUnsafe(pending.response, Exit.succeed(record({ value: pending.kind === "return" ? pending.value : undefined, done: true })));
1486
+ }
1487
+ });
1488
+ }
1489
+ takeGeneratorRequest(state) {
1490
+ const next = this.dequeueGeneratorRequest(state);
1491
+ if (next)
1492
+ return Effect.succeed(next);
1493
+ state.available = Deferred.makeUnsafe();
1494
+ return Effect.andThen(Deferred.await(state.available), Effect.sync(() => this.dequeueGeneratorRequest(state)));
1495
+ }
1496
+ dequeueGeneratorRequest(state) {
1497
+ const request = state.pending[state.pendingIndex];
1498
+ if (!request)
1499
+ return undefined;
1500
+ state.pendingIndex += 1;
1501
+ if (state.pendingIndex === state.pending.length) {
1502
+ state.pending = [];
1503
+ state.pendingIndex = 0;
1504
+ }
1505
+ return request;
1506
+ }
1507
+ evaluateYieldExpression(node) {
1508
+ const argument = node.argument;
1509
+ const self = this;
1510
+ return Effect.gen(function* () {
1511
+ if (!self.generatorState)
1512
+ throw new InterpreterRuntimeError("yield is only valid inside a generator.", node);
1513
+ if (node.delegate) {
1514
+ const value = argument ? yield* self.evaluateExpression(argument) : undefined;
1515
+ return yield* self.delegateYield(value, node);
1516
+ }
1517
+ const value = argument ? yield* self.evaluateExpression(argument) : undefined;
1518
+ const yielded = self.generatorAsync ? yield* self.awaitValue(value) : value;
1519
+ return yield* self.suspendGenerator(yielded, node);
1520
+ });
1521
+ }
1522
+ suspendGenerator(value, node) {
1523
+ const state = this.generatorState;
1524
+ if (!state?.active)
1525
+ throw new InterpreterRuntimeError("Generator has no active request.", node);
1526
+ Deferred.doneUnsafe(state.active.response, Exit.succeed(record({ value, done: false })));
1527
+ state.active = undefined;
1528
+ return Effect.flatMap(this.takeGeneratorRequest(state), (request) => {
1529
+ state.active = request;
1530
+ if (request.kind === "next")
1531
+ return Effect.succeed(request.value);
1532
+ if (request.kind === "throw")
1533
+ return Effect.fail(new ProgramThrow(request.value));
1534
+ return this.generatorAsync
1535
+ ? Effect.flatMap(this.awaitValue(request.value), (value) => Effect.fail(new GeneratorReturn(value)))
1536
+ : Effect.fail(new GeneratorReturn(request.value));
1537
+ });
1538
+ }
1539
+ delegateYield(value, node) {
1540
+ const self = this;
1541
+ return Effect.gen(function* () {
1542
+ if (value instanceof ProgramArray ||
1543
+ typeof value === "string" ||
1544
+ value instanceof Values.Map ||
1545
+ value instanceof Values.Set ||
1546
+ value instanceof Values.URLSearchParams) {
1547
+ const cursor = yield* self.syncIterator(value, node);
1548
+ if (!cursor)
1549
+ throw new InterpreterRuntimeError("Built-in iterator is unavailable.", node);
1550
+ while (true) {
1551
+ const step = yield* cursor.next;
1552
+ if (step.done)
1553
+ return undefined;
1554
+ const resumed = yield* Effect.exit(self.suspendGenerator(self.generatorAsync ? yield* self.awaitValue(step.value) : step.value, node));
1555
+ if (Exit.isSuccess(resumed))
1556
+ continue;
1557
+ const error = Cause.squash(resumed.cause);
1558
+ if (error instanceof GeneratorReturn) {
1559
+ yield* cursor.close;
1560
+ return yield* Effect.fail(error);
1561
+ }
1562
+ if (error instanceof ProgramThrow) {
1563
+ yield* cursor.close;
1564
+ throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node).as("TypeError");
1565
+ }
1566
+ return yield* Effect.failCause(resumed.cause);
1567
+ }
1568
+ }
1569
+ const iterator = yield* self.customIterator(value, node, self.generatorAsync);
1570
+ if (!iterator)
1571
+ throw new InterpreterRuntimeError("yield* requires a compatible iterable value.", node).as("TypeError");
1572
+ let kind = "next";
1573
+ let input = undefined;
1574
+ while (true) {
1575
+ const method = kind === "next"
1576
+ ? iterator.next
1577
+ : iterator.iterator instanceof CodeModeGenerator
1578
+ ? new GeneratorMethodReference(iterator.iterator, kind)
1579
+ : get(iterator.iterator, kind);
1580
+ if (method === undefined || method === null) {
1581
+ if (kind === "return")
1582
+ return yield* Effect.fail(new GeneratorReturn(input));
1583
+ yield* self.closeIterator(iterator, node, self.generatorAsync);
1584
+ throw new InterpreterRuntimeError("The delegated iterator does not provide a throw() method.", node).as("TypeError");
1585
+ }
1586
+ const called = yield* self.invokeCallable(self.requireIteratorMethod(method, `Iterator ${kind}`, node), [input], node);
1587
+ const result = self.requireIteratorObject(iterator.asynchronous ? yield* self.awaitValue(called) : called, `Iterator ${kind}() result`, node);
1588
+ const done = Boolean(get(result, "done"));
1589
+ const resultValue = self.generatorAsync && !iterator.asynchronous
1590
+ ? yield* self.awaitAsyncFromSyncValue(iterator, get(result, "value"), node, kind !== "return" && !done)
1591
+ : get(result, "value");
1592
+ if (done) {
1593
+ if (kind === "return")
1594
+ return yield* Effect.fail(new GeneratorReturn(resultValue));
1595
+ return resultValue;
1596
+ }
1597
+ const resumed = yield* Effect.exit(self.suspendGenerator(resultValue, node));
1598
+ if (Exit.isSuccess(resumed)) {
1599
+ kind = "next";
1600
+ input = resumed.value;
1601
+ continue;
1602
+ }
1603
+ const error = Cause.squash(resumed.cause);
1604
+ if (!(error instanceof GeneratorReturn) && !(error instanceof ProgramThrow)) {
1605
+ return yield* Effect.failCause(resumed.cause);
1606
+ }
1607
+ kind = error instanceof GeneratorReturn ? "return" : "throw";
1608
+ input = error.value;
1609
+ }
1610
+ });
1611
+ }
1612
+ evaluateObjectExpression(node) {
1613
+ const objectValue = new ProgramObject();
1614
+ const self = this;
1615
+ return Effect.gen(function* () {
1616
+ for (const property of node.properties) {
1617
+ if (property.type === "SpreadElement") {
1618
+ const spread = yield* self.evaluateExpression(property.argument);
1619
+ if (spread === null || spread === undefined)
1620
+ continue;
1621
+ assign(objectValue, enumerableSource("Object spread", spread, property));
1622
+ continue;
1623
+ }
1624
+ if (property.kind !== "init") {
1625
+ throw new InterpreterRuntimeError("Only init object properties are supported.", property);
1626
+ }
1627
+ const keyNode = property.key;
1628
+ let key;
1629
+ if (property.computed) {
1630
+ key = self.toPropertyKey(yield* self.evaluateExpression(keyNode), keyNode);
1631
+ }
1632
+ else if (keyNode.type === "Identifier") {
1633
+ key = keyNode.name;
1634
+ }
1635
+ else if (keyNode.type === "Literal") {
1636
+ key = self.toPropertyKey(keyNode.value, keyNode);
1637
+ }
1638
+ else {
1639
+ throw new InterpreterRuntimeError("Unsupported object property key shape.", keyNode);
1640
+ }
1641
+ const name = key === IteratorSymbol
1642
+ ? "[Symbol.iterator]"
1643
+ : key === AsyncIteratorSymbol
1644
+ ? "[Symbol.asyncIterator]"
1645
+ : String(key);
1646
+ set(objectValue, key, yield* self.evaluateNamed(property.value, name));
1647
+ }
1648
+ return objectValue;
1649
+ });
1650
+ }
1651
+ evaluateArrayExpression(node) {
1652
+ const values = [];
1653
+ const self = this;
1654
+ return Effect.gen(function* () {
1655
+ for (const element of node.elements) {
1656
+ if (element === null) {
1657
+ // A literal elision is a real hole, like JS: extend length without an own index.
1658
+ values.length += 1;
1659
+ continue;
1660
+ }
1661
+ if (element.type === "SpreadElement") {
1662
+ const spread = yield* self.evaluateExpression(element.argument);
1663
+ const cursor = yield* self.syncIterator(spread, element);
1664
+ if (cursor === undefined)
1665
+ throw new InterpreterRuntimeError("Array spread requires a synchronous iterable.", element).as("TypeError");
1666
+ while (true) {
1667
+ const step = yield* cursor.next;
1668
+ if (step.done)
1669
+ break;
1670
+ values.push(step.value);
1671
+ }
1672
+ }
1673
+ else {
1674
+ values.push(yield* self.evaluateExpression(element));
1675
+ }
1676
+ }
1677
+ return new ProgramArray(values);
1678
+ });
1679
+ }
1680
+ evaluateTemplateLiteral(node) {
1681
+ const quasis = node.quasis;
1682
+ const expressions = node.expressions;
1683
+ let output = "";
1684
+ const self = this;
1685
+ return Effect.gen(function* () {
1686
+ for (let index = 0; index < quasis.length; index += 1) {
1687
+ const quasi = quasis[index];
1688
+ // acorn only omits `cooked` for invalid escapes in tagged templates, which are unsupported.
1689
+ if (typeof quasi.value.cooked !== "string") {
1690
+ throw new InterpreterRuntimeError("Invalid template literal quasi.", quasi);
1691
+ }
1692
+ output += quasi.value.cooked;
1693
+ if (index < expressions.length) {
1694
+ const raw = yield* self.evaluateExpression(expressions[index]);
1695
+ output += coerceToString(toProgram(raw, "Template interpolation"));
1696
+ }
1697
+ }
1698
+ return output;
1699
+ });
1700
+ }
1701
+ evaluateConditionalExpression(node) {
1702
+ return Effect.flatMap(this.evaluateExpression(node.test), (test) => this.evaluateExpression(test ? node.consequent : node.alternate));
1703
+ }
1704
+ applyCompoundAssignment(operator, current, incoming, node) {
1705
+ if (!compoundOperators.has(operator)) {
1706
+ throw new InterpreterRuntimeError(`Unsupported assignment operator '${operator}'.`, node);
1707
+ }
1708
+ return this.applyBinaryOperator(operator.slice(0, -1), current, incoming, node);
1709
+ }
1710
+ getMemberReference(node, operation = "read") {
1711
+ const objectNode = node.object;
1712
+ const propertyNode = node.property;
1713
+ if (objectNode.type === "Super")
1714
+ throw unsupportedSyntax(objectNode.type, objectNode);
1715
+ if (propertyNode.type === "PrivateIdentifier")
1716
+ throw unsupportedSyntax(propertyNode.type, propertyNode);
1717
+ const self = this;
1718
+ return Effect.gen(function* () {
1719
+ const objectValue = yield* self.evaluateExpression(objectNode);
1720
+ if (objectValue === OptionalShortCircuit)
1721
+ return OptionalShortCircuit;
1722
+ if ((objectValue === null || objectValue === undefined) && node.optional)
1723
+ return OptionalShortCircuit;
1724
+ const key = node.computed
1725
+ ? self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode)
1726
+ : propertyNode.type === "Identifier"
1727
+ ? propertyNode.name
1728
+ : self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode);
1729
+ if (objectValue instanceof ToolReference) {
1730
+ if (typeof key !== "string") {
1731
+ throw new InterpreterRuntimeError("Tool paths must use string property names.", propertyNode);
1732
+ }
1733
+ return new ToolReference([...objectValue.path, key]);
1734
+ }
1735
+ if (objectValue instanceof HostFunction || objectValue instanceof HostNamespace) {
1736
+ // Unknown static members read as undefined so feature detection works like native JS.
1737
+ return new ComputedValue(objectValue.member(key, propertyNode));
1738
+ }
1739
+ // Values have no prototype chain, so `.constructor` resolves to the owning built-in directly.
1740
+ if (operation === "read" &&
1741
+ key === "constructor" &&
1742
+ !(objectValue instanceof ProgramObject && has(objectValue, key))) {
1743
+ const name = constructorName(objectValue);
1744
+ if (name !== undefined)
1745
+ return new ComputedValue(self.runtime.builtins.get(name));
1746
+ }
1747
+ if (typeof objectValue === "string") {
1748
+ if (key === "length")
1749
+ return new ComputedValue(objectValue.length);
1750
+ const index = typeof key === "symbol" ? undefined : parseArrayIndex(key);
1751
+ if (index !== undefined)
1752
+ return new ComputedValue(objectValue[index]);
1753
+ if (typeof key === "string" && stringMethods.has(key))
1754
+ return new IntrinsicReference(objectValue, key);
1755
+ return new ComputedValue(undefined);
1756
+ }
1757
+ if (typeof objectValue === "number") {
1758
+ if (typeof key === "string" && numberMethods.has(key))
1759
+ return new IntrinsicReference(objectValue, key);
1760
+ return new ComputedValue(undefined);
1761
+ }
1762
+ if (objectValue instanceof Values.Date) {
1763
+ if (typeof key === "string" && dateMethods.has(key))
1764
+ return new IntrinsicReference(objectValue, key);
1765
+ return new ComputedValue(undefined);
1766
+ }
1767
+ if (objectValue instanceof Values.RegExp) {
1768
+ if (key === "lastIndex")
1769
+ return { target: objectValue, key };
1770
+ if (typeof key === "string" && regexpProperties.has(key)) {
1771
+ return new ComputedValue(objectValue.regex[key]);
1772
+ }
1773
+ if (typeof key === "string" && regexpMethods.has(key))
1774
+ return new IntrinsicReference(objectValue, key);
1775
+ return new ComputedValue(undefined);
1776
+ }
1777
+ if (objectValue instanceof Values.Map) {
1778
+ if (key === "size")
1779
+ return new ComputedValue(objectValue.map.size);
1780
+ if (typeof key === "string" && mapMethods.has(key))
1781
+ return new IntrinsicReference(objectValue, key);
1782
+ return new ComputedValue(undefined);
1783
+ }
1784
+ if (objectValue instanceof Values.Set) {
1785
+ if (key === "size")
1786
+ return new ComputedValue(objectValue.set.size);
1787
+ if (typeof key === "string" && setMethods.has(key))
1788
+ return new IntrinsicReference(objectValue, key);
1789
+ return new ComputedValue(undefined);
1790
+ }
1791
+ if (objectValue instanceof Values.URL) {
1792
+ if (key === "searchParams") {
1793
+ return new ComputedValue(objectValue.searchParams);
1794
+ }
1795
+ if (typeof key === "string" && urlMethods.has(key))
1796
+ return new IntrinsicReference(objectValue, key);
1797
+ if (typeof key === "string" && urlProperties.has(key))
1798
+ return { target: objectValue, key };
1799
+ return new ComputedValue(undefined);
1800
+ }
1801
+ if (objectValue instanceof Values.URLSearchParams) {
1802
+ if (key === "size")
1803
+ return new ComputedValue(objectValue.params.size);
1804
+ if (typeof key === "string" && urlSearchParamsMethods.has(key)) {
1805
+ return new IntrinsicReference(objectValue, key);
1806
+ }
1807
+ return new ComputedValue(undefined);
1808
+ }
1809
+ // Reject unknown promise properties so a missing await cannot hide.
1810
+ if (objectValue instanceof Values.Promise) {
1811
+ if (key === "then" || key === "catch" || key === "finally") {
1812
+ return new PromiseInstanceMethodReference(objectValue, key);
1813
+ }
1814
+ throw new InterpreterRuntimeError("This value is an un-awaited Promise; await it first - e.g. `const result = await tools.ns.tool(...)`.", objectNode, "InvalidDataValue");
1815
+ }
1816
+ if (objectValue instanceof CodeModeGenerator) {
1817
+ if (key === "next" || key === "return" || key === "throw") {
1818
+ return new GeneratorMethodReference(objectValue, key);
1819
+ }
1820
+ if ((key === IteratorSymbol && !objectValue.asynchronous) ||
1821
+ (key === AsyncIteratorSymbol && objectValue.asynchronous)) {
1822
+ return new GeneratorMethodReference(objectValue, "iterator");
1823
+ }
1824
+ return new ComputedValue(undefined);
1825
+ }
1826
+ if (objectValue instanceof ProgramObject)
1827
+ return { target: objectValue, key };
1828
+ if (isRuntimeReference(objectValue)) {
1829
+ throw new InterpreterRuntimeError(`Cannot read properties of ${describeValue(objectValue)}; only data values expose properties.`, objectNode, "InvalidDataValue");
1830
+ }
1831
+ throw new InterpreterRuntimeError("Cannot access a property on a non-object value.", objectNode);
1832
+ });
1833
+ }
1834
+ readMember(node) {
1835
+ const self = this;
1836
+ return Effect.map(this.getMemberReference(node), (reference) => {
1837
+ if (reference === OptionalShortCircuit)
1838
+ return OptionalShortCircuit;
1839
+ if (reference instanceof ComputedValue)
1840
+ return reference.value;
1841
+ if (reference === undefined || isOpaqueMemberReference(reference))
1842
+ return reference;
1843
+ const value = self.readReferenceValue(reference, reference.key);
1844
+ if (value === undefined &&
1845
+ reference.target instanceof ProgramArray &&
1846
+ typeof reference.key === "string" &&
1847
+ arrayMethods.has(reference.key) &&
1848
+ !has(reference.target, reference.key)) {
1849
+ return new IntrinsicReference(reference.target, reference.key);
1850
+ }
1851
+ return value;
1852
+ });
1853
+ }
1854
+ writeMember(node, value) {
1855
+ return this.modifyMember(node, () => Effect.succeed({ write: true, next: value, result: value }));
1856
+ }
1857
+ evaluateDeleteExpression(argument) {
1858
+ const target = argument.type === "ChainExpression" ? argument.expression : argument;
1859
+ if (target.type !== "MemberExpression") {
1860
+ throw new InterpreterRuntimeError("Only data fields may be deleted.", argument);
1861
+ }
1862
+ return Effect.map(this.getMemberReference(target, "delete"), (reference) => {
1863
+ if (reference === OptionalShortCircuit)
1864
+ return true;
1865
+ if (reference instanceof ComputedValue ||
1866
+ reference === undefined ||
1867
+ isOpaqueMemberReference(reference) ||
1868
+ reference.target instanceof Values.URL) {
1869
+ throw new InterpreterRuntimeError("Only data fields may be deleted.", target, "InvalidDataValue");
1870
+ }
1871
+ if (reference.target instanceof Values.RegExp) {
1872
+ return Reflect.deleteProperty(reference.target.regex, reference.key);
1873
+ }
1874
+ return remove(reference.target, reference.key);
1875
+ });
1876
+ }
1877
+ // Resolve side-effecting object and key expressions exactly once.
1878
+ modifyMember(node, compute) {
1879
+ const self = this;
1880
+ return Effect.gen(function* () {
1881
+ const reference = yield* self.getMemberReference(node, "write");
1882
+ if (reference === OptionalShortCircuit ||
1883
+ reference instanceof ComputedValue ||
1884
+ reference === undefined ||
1885
+ isOpaqueMemberReference(reference)) {
1886
+ throw new InterpreterRuntimeError("Only data fields may be assigned.", node);
1887
+ }
1888
+ const key = reference.key;
1889
+ const { write, next, result } = yield* compute(self.readReferenceValue(reference, key));
1890
+ if (write)
1891
+ self.assignToReference(reference, key, next, node);
1892
+ return result;
1893
+ });
1894
+ }
1895
+ readReferenceValue(reference, key) {
1896
+ if (reference.target instanceof Values.URL) {
1897
+ return Reflect.get(reference.target.url, key);
1898
+ }
1899
+ if (reference.target instanceof Values.RegExp)
1900
+ return reference.target.lastIndex;
1901
+ return get(reference.target, key);
1902
+ }
1903
+ assignToReference(reference, key, next, node) {
1904
+ if (reference.target instanceof Values.URL) {
1905
+ const property = key;
1906
+ if (!urlWritableProperties.has(property)) {
1907
+ throw new InterpreterRuntimeError(`URL.${property} is read-only.`, node).as("TypeError");
1908
+ }
1909
+ try {
1910
+ const url = reference.target.url;
1911
+ url[property] = uriArgument(next, `URL.${property} value`);
1912
+ return;
1913
+ }
1914
+ catch (error) {
1915
+ if (error instanceof InterpreterRuntimeError || error instanceof ToolRuntimeError)
1916
+ throw error;
1917
+ throw new InterpreterRuntimeError(`URL.${property} received an invalid value.`, node).as("TypeError");
1918
+ }
1919
+ }
1920
+ if (reference.target instanceof Values.RegExp) {
1921
+ reference.target.lastIndex = next;
1922
+ return;
1923
+ }
1924
+ const target = reference.target;
1925
+ rejectCircularInsertion(target, next, target instanceof ProgramArray ? "Array assignment result" : "Object assignment result", node);
1926
+ if (set(target, key, next))
1927
+ return;
1928
+ if (target instanceof ProgramArray)
1929
+ throw new InterpreterRuntimeError("Invalid array length", node).as("RangeError");
1930
+ throw new InterpreterRuntimeError(`Cannot assign to read only property '${String(key)}'.`, node).as("TypeError");
1931
+ }
1932
+ toPropertyKey(value, node) {
1933
+ if (typeof value === "string" || typeof value === "number") {
1934
+ return value;
1935
+ }
1936
+ if (value === AsyncIteratorSymbol || value === IteratorSymbol)
1937
+ return value;
1938
+ throw new InterpreterRuntimeError("Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.", node);
1939
+ }
1940
+ }