@opencode/codemode 0.0.0-beta-19365 → 0.0.0-beta-19378

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/interpreter/errors.d.ts +4 -6
  2. package/dist/interpreter/errors.js +20 -4
  3. package/dist/interpreter/execute.js +2 -3
  4. package/dist/interpreter/globals.d.ts +13 -0
  5. package/dist/interpreter/globals.js +59 -0
  6. package/dist/interpreter/host.d.ts +41 -0
  7. package/dist/interpreter/host.js +44 -0
  8. package/dist/interpreter/methods.d.ts +3 -23
  9. package/dist/interpreter/methods.js +8 -183
  10. package/dist/interpreter/model.d.ts +0 -41
  11. package/dist/interpreter/model.js +0 -56
  12. package/dist/interpreter/promises.d.ts +7 -8
  13. package/dist/interpreter/promises.js +45 -22
  14. package/dist/interpreter/references.js +11 -28
  15. package/dist/interpreter/runner.d.ts +23 -0
  16. package/dist/interpreter/runner.js +42 -0
  17. package/dist/interpreter/runtime.d.ts +11 -92
  18. package/dist/interpreter/runtime.js +75 -452
  19. package/dist/stdlib/array.d.ts +3 -0
  20. package/dist/stdlib/array.js +73 -0
  21. package/dist/stdlib/collections.d.ts +6 -1
  22. package/dist/stdlib/collections.js +120 -1
  23. package/dist/stdlib/console.d.ts +3 -2
  24. package/dist/stdlib/console.js +11 -2
  25. package/dist/stdlib/date.d.ts +3 -2
  26. package/dist/stdlib/date.js +27 -11
  27. package/dist/stdlib/json.d.ts +4 -4
  28. package/dist/stdlib/json.js +6 -2
  29. package/dist/stdlib/math.d.ts +3 -7
  30. package/dist/stdlib/math.js +85 -153
  31. package/dist/stdlib/number.d.ts +1 -3
  32. package/dist/stdlib/number.js +28 -36
  33. package/dist/stdlib/object.d.ts +4 -6
  34. package/dist/stdlib/object.js +101 -71
  35. package/dist/stdlib/regexp.d.ts +2 -4
  36. package/dist/stdlib/regexp.js +32 -9
  37. package/dist/stdlib/string.d.ts +1 -3
  38. package/dist/stdlib/string.js +14 -16
  39. package/dist/stdlib/url.d.ts +8 -4
  40. package/dist/stdlib/url.js +97 -21
  41. package/dist/stdlib/value.d.ts +5 -3
  42. package/dist/stdlib/value.js +21 -19
  43. package/package.json +1 -1
  44. package/dist/interpreter/iterator.d.ts +0 -13
  45. package/dist/interpreter/iterator.js +0 -4
  46. package/dist/stdlib/promise.d.ts +0 -2
  47. package/dist/stdlib/promise.js +0 -1
@@ -1,36 +1,23 @@
1
1
  import { Cause, Deferred, Effect, Exit } from "effect";
2
2
  import { isBlockedMember, ToolRuntimeError, toProgram } from "../data.js";
3
3
  import { ToolReference } from "../tool-runtime.js";
4
- import { AsyncIteratorSymbol, CodeModeFunction, CodeModeGenerator, CoercionFunction, ComputedValue, ErrorConstructorReference, GlobalMethodReference, GlobalNamespace, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, isRecord, IteratorSymbol, IteratorSymbols, JsonMethodReference, OptionalShortCircuit, PromiseCapabilityFunction, PromiseInstanceMethodReference, PromiseMethodReference, PromiseNamespace, ProgramThrow, SearchFunction, SymbolNamespace, unsupportedSyntax, UriFunction, } from "./model.js";
5
- import { caughtErrorValue, constructAggregateErrorValue, constructErrorValue } from "./errors.js";
6
- import { arrayStatics, invokeArrayFrom, invokeGlobalMethod, invokeGroupBy, invokeIntrinsic, toPrimitive, } from "./methods.js";
7
- import { preserveConsumerError } from "./iterator.js";
8
- import { constructPromise, invokePromiseInstanceMethod, invokePromiseMethod, PromiseRuntime, resolvePromise, resolvePromiseValue, } from "./promises.js";
4
+ import { AsyncIteratorSymbol, CodeModeFunction, CodeModeGenerator, ComputedValue, GeneratorMethodReference, GeneratorReturn, IntrinsicReference, InterpreterRuntimeError, isRecord, IteratorSymbol, IteratorSymbols, OptionalShortCircuit, PromiseInstanceMethodReference, ProgramThrow, unsupportedSyntax, } from "./model.js";
5
+ import { caughtErrorValue } from "./errors.js";
6
+ import { globals } from "./globals.js";
7
+ import { HostFunction, HostNamespace } from "./host.js";
8
+ import { invokeIntrinsic } from "./methods.js";
9
+ import { preserveConsumerError } from "./runner.js";
10
+ import { invokePromiseInstanceMethod, PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
9
11
  import { containsOpaqueReference, isRuntimeReference, rejectCircularInsertion, typeofValue } from "./references.js";
10
12
  import { ScopeStack } from "./scope.js";
11
- import { arrayMethods, mapMethods, mapStatics, setMethods } from "../stdlib/collections.js";
12
- import { consoleMethods, formatConsoleMessage } from "../stdlib/console.js";
13
- import { dateMethods, dateStatics } from "../stdlib/date.js";
14
- import { invokeJsonMethod, jsonStatics } from "../stdlib/json.js";
15
- import { invokeMathSumPrecise, mathConstants, mathMethods } from "../stdlib/math.js";
16
- import { numberConstants, numberMethods, numberStatics } from "../stdlib/number.js";
17
- import { invokeObjectFromEntries, objectMethodsPreservingIdentity, objectStatics } from "../stdlib/object.js";
18
- import { promiseStatics } from "../stdlib/promise.js";
19
- import { escapeRegexHint, regexpMethods, regexpProperties, regexpStatics, regexFailureReason, } from "../stdlib/regexp.js";
20
- import { stringMethods, stringStatics } from "../stdlib/string.js";
21
- import { urlMethods, urlProperties, urlSearchParamsMethods, urlStatics, urlWritableProperties, invokeUriFunction, uriArgument, urlArgument, } from "../stdlib/url.js";
22
- import { coerceToNumber, coerceToString, compoundOperators, errorBrandName, errorConstructors, invokeCoercion, valueConstructors, } from "../stdlib/value.js";
13
+ import { arrayMethods, mapMethods, setMethods } from "../stdlib/collections.js";
14
+ import { dateMethods } from "../stdlib/date.js";
15
+ import { numberMethods } from "../stdlib/number.js";
16
+ import { constructRegExp, regexpMethods, regexpProperties } from "../stdlib/regexp.js";
17
+ import { stringMethods } from "../stdlib/string.js";
18
+ import { uriArgument, urlMethods, urlProperties, urlSearchParamsMethods, urlWritableProperties } from "../stdlib/url.js";
19
+ import { coerceToNumber, coerceToString, compoundOperators } from "../stdlib/value.js";
23
20
  import { Values } from "../values.js";
24
- const globalStaticMembers = {
25
- Object: objectStatics,
26
- Math: mathMethods,
27
- Array: arrayStatics,
28
- console: consoleMethods,
29
- Date: dateStatics,
30
- RegExp: regexpStatics,
31
- Map: mapStatics,
32
- URL: urlStatics,
33
- };
34
21
  const MAX_ARRAY_LENGTH = 4_294_967_295;
35
22
  const parseArrayIndex = (key) => {
36
23
  const property = String(key);
@@ -56,35 +43,8 @@ const calleeDescription = (callee) => {
56
43
  return "The called value";
57
44
  };
58
45
  const instanceofValue = (lhs, rhs, node) => {
59
- if (rhs instanceof ErrorConstructorReference) {
60
- const brand = errorBrandName(lhs);
61
- return brand !== undefined && (rhs.name === "Error" || brand === rhs.name);
62
- }
63
- if (rhs instanceof GlobalNamespace) {
64
- switch (rhs.name) {
65
- case "Date":
66
- return lhs instanceof Values.Date;
67
- case "RegExp":
68
- return lhs instanceof Values.RegExp;
69
- case "Map":
70
- return lhs instanceof Values.Map;
71
- case "Set":
72
- return lhs instanceof Values.Set;
73
- case "URL":
74
- return lhs instanceof Values.URL;
75
- case "URLSearchParams":
76
- return lhs instanceof Values.URLSearchParams;
77
- case "Array":
78
- return Array.isArray(lhs);
79
- case "Object":
80
- return lhs !== null && (typeof lhs === "object" || typeofValue(lhs) === "function");
81
- }
82
- }
83
- if (rhs instanceof PromiseNamespace)
84
- return lhs instanceof Values.Promise;
85
- if (rhs instanceof CoercionFunction && (rhs.name === "Number" || rhs.name === "String" || rhs.name === "Boolean")) {
86
- return false;
87
- }
46
+ if (rhs instanceof HostFunction && rhs.instanceOf !== undefined)
47
+ return rhs.instanceOf(lhs);
88
48
  throw new InterpreterRuntimeError("The right-hand side of 'instanceof' must be a supported constructor: Error (or a specific error type like TypeError), Date, RegExp, Map, Set, URL, URLSearchParams, Array, Object, or Promise.", node);
89
49
  };
90
50
  const collectPatternNames = (pattern, out = []) => {
@@ -127,11 +87,8 @@ const loopDeclaration = (left, statement) => {
127
87
  };
128
88
  };
129
89
  const isOpaqueMemberReference = (value) => value instanceof ToolReference ||
130
- value instanceof PromiseMethodReference ||
131
90
  value instanceof PromiseInstanceMethodReference ||
132
91
  value instanceof IntrinsicReference ||
133
- value instanceof GlobalMethodReference ||
134
- value instanceof JsonMethodReference ||
135
92
  value instanceof GeneratorMethodReference;
136
93
  const copyIteratorSymbols = (source, target, consumed) => {
137
94
  for (const symbol of IteratorSymbols) {
@@ -140,61 +97,46 @@ const copyIteratorSymbols = (source, target, consumed) => {
140
97
  }
141
98
  };
142
99
  const promiseResolutionNode = { type: "PromiseResolution", start: 0, end: 0 };
143
- export class Interpreter {
144
- scopes;
100
+ /** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
101
+ export class Runtime {
145
102
  executeTool;
146
- invokeSearch;
103
+ search;
147
104
  toolKeys;
148
- logs;
149
105
  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]);
106
+ logs;
107
+ runner;
108
+ root;
109
+ constructor(executeTool, search, toolKeys, promises, logs = []) {
161
110
  this.executeTool = executeTool;
162
- this.invokeSearch = invokeSearch;
111
+ this.search = search;
163
112
  this.toolKeys = toolKeys;
164
- this.logs = logs;
165
113
  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 });
114
+ this.logs = logs;
115
+ const globalScope = new Map();
116
+ // Calling back into the program never reads frame state, so any frame serves; the root is always alive.
117
+ this.root = new Frame(this, new ScopeStack([globalScope]));
118
+ this.runner = {
119
+ invokeFunction: (fn, args) => this.root.invokeFunction(fn, args),
120
+ invokeCallable: (callable, args, node) => this.root.invokeCallable(callable, args, node),
121
+ settlePromise: (promise) => this.root.settlePromise(promise),
122
+ syncIterator: (value, node) => this.root.syncIterator(value, node),
123
+ };
124
+ for (const [name, value] of globals(this))
125
+ globalScope.set(name, { mutable: false, value });
126
+ }
127
+ run(program) {
128
+ return this.root.run(program);
129
+ }
130
+ }
131
+ /** One activation: the top-level program or a single function call, evaluating against its own scope chain. */
132
+ class Frame {
133
+ runtime;
134
+ scopes;
135
+ generatorState;
136
+ generatorAsync = false;
137
+ constructor(runtime, scopes) {
138
+ this.runtime = runtime;
139
+ this.scopes = scopes;
198
140
  }
199
141
  run(program) {
200
142
  const self = this;
@@ -219,20 +161,20 @@ export class Interpreter {
219
161
  }
220
162
  }
221
163
  // The implicit async body adopts returned promises before copy-out.
222
- value = yield* resolvePromiseValue(self.runner, value, program);
164
+ value = yield* resolvePromiseValue(self.runtime.runner, value, program);
223
165
  return value;
224
166
  }).pipe(Effect.ensuring(Effect.sync(() => self.scopes.pop())));
225
167
  }
226
168
  // Fork at the call site so admission and hooks occur when the call is made.
227
169
  createToolCallPromise(path, args) {
228
- return this.createPromise(Effect.suspend(() => this.executeTool(path, args)));
170
+ return this.createPromise(Effect.suspend(() => this.runtime.executeTool(path, args)));
229
171
  }
230
172
  createPromise(effect) {
231
- return this.promises.create(effect);
173
+ return this.runtime.promises.create(effect);
232
174
  }
233
175
  // Fiber exits make settlement idempotent; yielding prevents inline continuation.
234
176
  settlePromise(promise) {
235
- const promises = this.promises;
177
+ const promises = this.runtime.promises;
236
178
  return Effect.suspend(() => {
237
179
  promises.markObserved(promise);
238
180
  return Effect.flatMap(promises.await(promise), (exit) => Effect.andThen(Effect.yieldNow, exit));
@@ -555,7 +497,7 @@ export class Interpreter {
555
497
  })));
556
498
  }
557
499
  awaitValue(value, node = promiseResolutionNode) {
558
- return Effect.flatMap(resolvePromise(this.runner, this.promises, value, node), (promise) => this.settlePromise(promise));
500
+ return Effect.flatMap(resolvePromise(this.runtime.runner, this.runtime.promises, value, node), (promise) => this.settlePromise(promise));
559
501
  }
560
502
  awaitAsyncFromSyncValue(iterator, value, node, closeOnRejection) {
561
503
  const self = this;
@@ -702,7 +644,7 @@ export class Interpreter {
702
644
  }
703
645
  enumerableKeys(value) {
704
646
  if (value instanceof ToolReference) {
705
- return [...this.toolKeys(value.path)];
647
+ return [...this.runtime.toolKeys(value.path)];
706
648
  }
707
649
  if (Array.isArray(value)) {
708
650
  return Object.keys(value);
@@ -1012,7 +954,7 @@ export class Interpreter {
1012
954
  case "Literal": {
1013
955
  const regex = node.regex;
1014
956
  if (regex)
1015
- return Effect.sync(() => this.constructRegExp([regex.pattern, regex.flags], node));
957
+ return Effect.sync(() => constructRegExp([regex.pattern, regex.flags], node));
1016
958
  return Effect.sync(() => toProgram(node.value, "Literal"));
1017
959
  }
1018
960
  case "Identifier":
@@ -1067,208 +1009,15 @@ export class Interpreter {
1067
1009
  }
1068
1010
  }
1069
1011
  evaluateNewExpression(node) {
1070
- const callee = node.callee;
1071
- if (callee.type !== "Identifier") {
1072
- throw unsupportedSyntax("NewExpression", node);
1073
- }
1074
- const name = callee.name;
1075
- const argNodes = node.arguments;
1076
- const self = this;
1077
- if (name === "Promise") {
1078
- return Effect.flatMap(this.evaluateCallArguments(argNodes), (args) => constructPromise(self.runner, self.promises, args[0], node));
1079
- }
1080
- if (errorConstructors.has(name)) {
1081
- return Effect.flatMap(this.evaluateCallArguments(argNodes), (args) => name === "AggregateError"
1082
- ? constructAggregateErrorValue(self.runner, args, node)
1083
- : Effect.succeed(constructErrorValue(name, args)));
1084
- }
1085
- // Array and Object construct identically with or without new, like JS.
1086
- if (name === "Array") {
1087
- return Effect.map(this.evaluateCallArguments(argNodes), (args) => self.constructArray(args, node));
1088
- }
1089
- if (name === "Object") {
1090
- return Effect.map(this.evaluateCallArguments(argNodes), (args) => self.constructObject(args, node));
1091
- }
1092
- if (valueConstructors.has(name)) {
1093
- return Effect.gen(function* () {
1094
- const args = yield* self.evaluateCallArguments(argNodes);
1095
- switch (name) {
1096
- case "Date":
1097
- return yield* self.constructDate(args, node);
1098
- case "RegExp":
1099
- return self.constructRegExp(args, node);
1100
- case "Map":
1101
- return yield* self.constructMap(args[0], node);
1102
- case "Set":
1103
- return yield* self.constructSet(args[0], node);
1104
- case "URL":
1105
- return self.constructURL(args, node);
1106
- default:
1107
- return yield* self.constructURLSearchParams(args[0], node);
1108
- }
1109
- });
1110
- }
1111
- throw unsupportedSyntax("NewExpression", node);
1112
- }
1113
- constructArray(args, node) {
1114
- if (args.length !== 1)
1115
- return [...args];
1116
- const first = args[0];
1117
- if (typeof first !== "number")
1118
- return [first];
1119
- if (!Number.isInteger(first) || first < 0 || first > 4294967295) {
1120
- throw new InterpreterRuntimeError("Invalid array length.", node).as("RangeError");
1121
- }
1122
- // Sparse like JS: Array(3) has holes, and combinator loops already skip them.
1123
- return new Array(first);
1124
- }
1125
- constructObject(args, node) {
1126
- const first = args[0];
1127
- if (first === null || first === undefined)
1128
- return {};
1129
- if (typeof first === "object")
1130
- return first;
1131
- throw new InterpreterRuntimeError(`Object(${typeof first}) wrapper objects are not supported; use the primitive value directly.`, node);
1132
- }
1133
- constructDate(args, node) {
1134
- if (args.length === 0)
1135
- return Effect.succeed(new Values.Date(Date.now()));
1136
- if (args.length === 1) {
1137
- const arg = args[0];
1138
- if (arg instanceof Values.Date)
1139
- return Effect.succeed(new Values.Date(arg.time));
1140
- return Effect.map(toPrimitive(this.runner, arg, "number", node), (value) => typeof value === "string"
1141
- ? new Values.Date(Date.parse(value))
1142
- : new Values.Date(new Date(coerceToNumber(value)).getTime()));
1143
- }
1144
- const parts = args.map((arg) => coerceToNumber(arg));
1145
- return Effect.succeed(new Values.Date(new Date(...parts).getTime()));
1146
- }
1147
- constructRegExp(args, node) {
1148
- const first = args[0];
1149
- const pattern = first instanceof Values.RegExp ? first.regex.source : first === undefined ? "" : coerceToString(first);
1150
- const flagsArg = args[1];
1151
- if (flagsArg !== undefined && typeof flagsArg !== "string") {
1152
- 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");
1153
- }
1154
- const flags = flagsArg ?? (first instanceof Values.RegExp ? first.regex.flags : "");
1155
- try {
1156
- return new Values.RegExp(pattern, flags);
1157
- }
1158
- catch (error) {
1159
- const reason = regexFailureReason(error);
1160
- throw new InterpreterRuntimeError(/flag/i.test(reason)
1161
- ? `new RegExp(...) received invalid flags ${JSON.stringify(flags)} (${reason}). Valid flags are d, g, i, m, s, u, v, and y.`
1162
- : `new RegExp(...) received ${JSON.stringify(pattern)}, which is not a valid regular expression pattern (${reason}). ${escapeRegexHint}`, node).as("SyntaxError");
1163
- }
1164
- }
1165
- constructMap(init, node) {
1166
- const target = new Values.Map();
1167
- if (init === undefined || init === null)
1168
- return Effect.succeed(target);
1169
1012
  const self = this;
1170
1013
  return Effect.gen(function* () {
1171
- const cursor = yield* self.syncIterator(init, node);
1172
- if (cursor === undefined) {
1173
- throw new InterpreterRuntimeError("new Map(...) expects an iterable of [key, value] pairs or no argument.", node).as("TypeError");
1174
- }
1175
- while (true) {
1176
- const step = yield* cursor.next;
1177
- if (step.done)
1178
- return target;
1179
- yield* preserveConsumerError(cursor, Effect.sync(() => {
1180
- if (!isRecord(step.value) || isRuntimeReference(step.value)) {
1181
- throw new InterpreterRuntimeError("new Map(...) expects [key, value] pairs as entry objects.", node).as("TypeError");
1182
- }
1183
- target.map.set(step.value[0], step.value[1]);
1184
- }));
1185
- }
1186
- });
1187
- }
1188
- constructSet(init, node) {
1189
- const target = new Values.Set();
1190
- if (init === undefined || init === null)
1191
- return Effect.succeed(target);
1192
- const self = this;
1193
- return Effect.gen(function* () {
1194
- const cursor = yield* self.syncIterator(init, node);
1195
- if (cursor === undefined) {
1196
- throw new InterpreterRuntimeError("new Set(...) expects a synchronous iterable or no argument.", node).as("TypeError");
1197
- }
1198
- while (true) {
1199
- const step = yield* cursor.next;
1200
- if (step.done)
1201
- return target;
1202
- target.set.add(step.value);
1203
- }
1204
- });
1205
- }
1206
- constructURL(args, node) {
1207
- if (args.length === 0) {
1208
- throw new InterpreterRuntimeError("new URL(...) requires a URL string and an optional base URL.", node).as("TypeError");
1209
- }
1210
- const input = urlArgument(args[0], "new URL input");
1211
- const base = args[1] === undefined ? undefined : urlArgument(args[1], "new URL base");
1212
- try {
1213
- return new Values.URL(new URL(input, base));
1214
- }
1215
- catch {
1216
- throw new InterpreterRuntimeError(`new URL(...) received an invalid URL${base === undefined ? "" : " or base URL"}.`, node).as("TypeError");
1217
- }
1218
- }
1219
- constructURLSearchParams(init, node) {
1220
- if (init === undefined)
1221
- return Effect.succeed(new Values.URLSearchParams(new URLSearchParams()));
1222
- if (init instanceof Values.URLSearchParams) {
1223
- return Effect.succeed(new Values.URLSearchParams(new URLSearchParams(init.params)));
1224
- }
1225
- if (typeof init === "string")
1226
- return Effect.succeed(new Values.URLSearchParams(new URLSearchParams(init)));
1227
- if (init === null || typeof init === "number" || typeof init === "boolean") {
1228
- return Effect.succeed(new Values.URLSearchParams(new URLSearchParams(coerceToString(init))));
1229
- }
1230
- const self = this;
1231
- return Effect.gen(function* () {
1232
- const cursor = yield* self.syncIterator(init, node);
1233
- if (cursor !== undefined) {
1234
- const entries = [];
1235
- while (true) {
1236
- const step = yield* cursor.next;
1237
- if (step.done) {
1238
- if (entries.some((entry) => entry.length !== 2)) {
1239
- throw new InterpreterRuntimeError("new URLSearchParams(...) expects iterable [name, value] pairs.", node).as("TypeError");
1240
- }
1241
- return new Values.URLSearchParams(new URLSearchParams(entries.map((entry) => [entry[0] ?? "", entry[1] ?? ""])));
1242
- }
1243
- entries.push(yield* preserveConsumerError(cursor, self.readURLSearchParamsPair(step.value, node)));
1244
- }
1245
- }
1246
- if (isRuntimeReference(init)) {
1247
- throw new InterpreterRuntimeError("new URLSearchParams(...) expects a query string, data object, or synchronous iterable pairs.", node).as("TypeError");
1248
- }
1249
- if (Values.isValue(init))
1250
- return new Values.URLSearchParams(new URLSearchParams());
1251
- const data = toProgram(init, "new URLSearchParams input");
1252
- if (data === null || typeof data !== "object") {
1253
- throw new InterpreterRuntimeError("new URLSearchParams(...) expects a query string, data object, iterable pairs, or URLSearchParams.", node).as("TypeError");
1254
- }
1255
- return new Values.URLSearchParams(new URLSearchParams(Object.fromEntries(Object.entries(data).map(([key, value]) => [key, coerceToString(value)]))));
1256
- });
1257
- }
1258
- readURLSearchParamsPair(value, node) {
1259
- const self = this;
1260
- return Effect.gen(function* () {
1261
- const cursor = yield* self.syncIterator(value, node);
1262
- if (cursor === undefined) {
1263
- throw new InterpreterRuntimeError("new URLSearchParams(...) expects iterable [name, value] pairs.", node).as("TypeError");
1264
- }
1265
- const items = [];
1266
- while (true) {
1267
- const step = yield* cursor.next;
1268
- if (step.done)
1269
- return items;
1270
- items.push(yield* preserveConsumerError(cursor, Effect.sync(() => uriArgument(step.value, "URLSearchParams pair value"))));
1271
- }
1014
+ const callee = yield* self.evaluateExpression(node.callee);
1015
+ // Globals are built with this interpreter's R; `instanceof` cannot recover the type argument.
1016
+ const construct = callee instanceof HostFunction ? callee.construct : undefined;
1017
+ if (construct === undefined)
1018
+ throw unsupportedSyntax("NewExpression", node);
1019
+ const args = yield* self.evaluateCallArguments(node.arguments);
1020
+ return yield* construct(args, node);
1272
1021
  });
1273
1022
  }
1274
1023
  evaluateBinaryExpression(node) {
@@ -1522,12 +1271,6 @@ export class Interpreter {
1522
1271
  }
1523
1272
  return yield* self.createToolCallPromise(callable.path, args);
1524
1273
  }
1525
- if (callable instanceof PromiseMethodReference) {
1526
- return yield* invokePromiseMethod(self.runner, self.promises, callable, args, node);
1527
- }
1528
- if (callable instanceof PromiseInstanceMethodReference) {
1529
- return yield* invokePromiseInstanceMethod(self.runner, self.promises, callable, args, node);
1530
- }
1531
1274
  if (callable instanceof CodeModeFunction) {
1532
1275
  return yield* self.invokeFunction(callable, args);
1533
1276
  }
@@ -1538,95 +1281,19 @@ export class Interpreter {
1538
1281
  return callable.generator.asynchronous ? yield* self.createPromise(requested) : yield* requested;
1539
1282
  }
1540
1283
  if (callable instanceof IntrinsicReference) {
1541
- return yield* invokeIntrinsic(self.runner, callable, args, node);
1542
- }
1543
- if (callable instanceof GlobalMethodReference) {
1544
- if (callable.namespace === "console")
1545
- return self.invokeConsole(callable.name, args, node);
1546
- if (callable.namespace === "Object" && args[0] instanceof ToolReference) {
1547
- return self.invokeObjectMethodOnTools(callable.name, args[0], node);
1548
- }
1549
- if (callable.namespace === "Object" && objectMethodsPreservingIdentity.has(callable.name)) {
1550
- if (callable.name === "fromEntries")
1551
- return yield* invokeObjectFromEntries(self.runner, args[0], node);
1552
- return invokeGlobalMethod(callable, args, node);
1553
- }
1554
- if (callable.namespace === "Array" && callable.name === "from") {
1555
- return yield* invokeArrayFrom(self.runner, args, node);
1556
- }
1557
- if ((callable.namespace === "Object" || callable.namespace === "Map") && callable.name === "groupBy") {
1558
- return yield* invokeGroupBy(self.runner, callable.namespace, args, node);
1559
- }
1560
- if (callable.namespace === "Math" && callable.name === "sumPrecise") {
1561
- return yield* invokeMathSumPrecise(self.runner, args[0], node);
1562
- }
1563
- if (callable.namespace === "Array" && callable.name === "of") {
1564
- return invokeGlobalMethod(callable, args, node);
1565
- }
1566
- return toProgram(invokeGlobalMethod(callable, args, node), `${callable.namespace}.${callable.name} result`);
1567
- }
1568
- if (callable instanceof JsonMethodReference) {
1569
- return yield* invokeJsonMethod(self.runner, callable.name, args, node);
1570
- }
1571
- if (callable instanceof CoercionFunction) {
1572
- return toProgram(invokeCoercion(callable, args, node), `${callable.name} result`);
1284
+ return yield* invokeIntrinsic(self.runtime.runner, callable, args, node);
1573
1285
  }
1574
- if (callable instanceof UriFunction) {
1575
- return invokeUriFunction(callable, args, node);
1576
- }
1577
- if (callable instanceof SearchFunction) {
1578
- return yield* self.invokeSearch(args);
1579
- }
1580
- if (callable instanceof ErrorConstructorReference) {
1581
- if (callable.name === "AggregateError")
1582
- return yield* constructAggregateErrorValue(self.runner, args, node);
1583
- return constructErrorValue(callable.name, args);
1584
- }
1585
- if (callable instanceof GlobalNamespace) {
1586
- // Real JS permits calling Array, Object, Date, and RegExp without new.
1587
- if (callable.name === "Array")
1588
- return self.constructArray(args, node);
1589
- if (callable.name === "Object")
1590
- return self.constructObject(args, node);
1591
- // ISO instead of the host's locale string: CodeMode date strings are
1592
- // deterministic and must not leak the host timezone.
1593
- if (callable.name === "Date")
1594
- return new Date().toISOString();
1595
- if (callable.name === "RegExp")
1596
- return self.constructRegExp(args, node);
1597
- if (typeofValue(callable) === "function") {
1598
- throw new InterpreterRuntimeError(`Constructor ${callable.name} requires 'new'.`, node).as("TypeError");
1599
- }
1600
- throw new InterpreterRuntimeError(`${callable.name} is not a function.`, node).as("TypeError");
1601
- }
1602
- if (callable instanceof PromiseNamespace) {
1603
- throw new InterpreterRuntimeError("Constructor Promise requires 'new'.", node).as("TypeError");
1604
- }
1605
- if (callable instanceof SymbolNamespace) {
1606
- throw new InterpreterRuntimeError("Symbol is not callable; only Symbol.asyncIterator and Symbol.iterator are available.", node).as("TypeError");
1607
- }
1608
- if (callable instanceof PromiseCapabilityFunction) {
1609
- callable.settle(args[0]);
1610
- return undefined;
1286
+ if (callable instanceof PromiseInstanceMethodReference) {
1287
+ return yield* invokePromiseInstanceMethod(self.runtime.runner, self.runtime.promises, callable, args, node);
1611
1288
  }
1289
+ if (callable instanceof HostFunction)
1290
+ return yield* callable.call(args, node);
1612
1291
  if (callable === undefined || callable === null) {
1613
1292
  throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node).as("TypeError");
1614
1293
  }
1615
1294
  throw new InterpreterRuntimeError("Only tools are callable here.", callee ?? node);
1616
1295
  });
1617
1296
  }
1618
- invokeObjectMethodOnTools(name, ref, node) {
1619
- if (name === "keys") {
1620
- return toProgram(this.enumerableKeys(ref), "Object.keys result");
1621
- }
1622
- 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");
1623
- }
1624
- invokeConsole(name, args, node) {
1625
- if (!consoleMethods.has(name))
1626
- throw new InterpreterRuntimeError(`console.${name} is not available.`, node);
1627
- this.logs.push(formatConsoleMessage(name, args));
1628
- return undefined;
1629
- }
1630
1297
  evaluateCallArguments(argNodes) {
1631
1298
  const self = this;
1632
1299
  return Effect.gen(function* () {
@@ -1652,8 +1319,7 @@ export class Interpreter {
1652
1319
  });
1653
1320
  }
1654
1321
  invokeFunction(fn, args) {
1655
- const invocation = new Interpreter(this.executeTool, this.invokeSearch, this.toolKeys, this.promises, this.logs);
1656
- invocation.scopes = new ScopeStack([...fn.capturedScopes, new Map()]);
1322
+ const invocation = new Frame(this.runtime, new ScopeStack([...fn.capturedScopes, new Map()]));
1657
1323
  const run = Effect.gen(function* () {
1658
1324
  // Seed all parameters first so defaults cannot fall through to same-named outer bindings.
1659
1325
  const paramScope = invocation.scopes.current();
@@ -1681,7 +1347,7 @@ export class Interpreter {
1681
1347
  return run;
1682
1348
  // The initial yield assigns the promise before the body can self-resolve.
1683
1349
  const box = {};
1684
- return Effect.map(this.createPromise(Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runner, value, fn.body, box))), (promise) => {
1350
+ return Effect.map(this.createPromise(Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, fn.body, box))), (promise) => {
1685
1351
  box.promise = promise;
1686
1352
  return promise;
1687
1353
  });
@@ -1702,7 +1368,7 @@ export class Interpreter {
1702
1368
  if (state.draining)
1703
1369
  return Deferred.await(request.response);
1704
1370
  state.draining = true;
1705
- return Effect.andThen(this.promises.fork(invocation
1371
+ return Effect.andThen(this.runtime.promises.fork(invocation
1706
1372
  .completeGeneratorRequests(state, true)
1707
1373
  .pipe(Effect.ensuring(Effect.sync(() => (state.draining = false))))), Deferred.await(request.response));
1708
1374
  }
@@ -1740,7 +1406,7 @@ export class Interpreter {
1740
1406
  yield* invocation.completeGeneratorRequests(state, asynchronous);
1741
1407
  state.completed = true;
1742
1408
  });
1743
- return Effect.andThen(this.promises.fork(body), Deferred.await(request.response));
1409
+ return Effect.andThen(this.runtime.promises.fork(body), Deferred.await(request.response));
1744
1410
  }
1745
1411
  return Deferred.await(request.response);
1746
1412
  });
@@ -2018,38 +1684,12 @@ export class Interpreter {
2018
1684
  }
2019
1685
  return new ToolReference([...objectValue.path, key]);
2020
1686
  }
2021
- if (objectValue instanceof PromiseNamespace) {
2022
- if (typeof key === "string" && promiseStatics.has(key)) {
2023
- return new PromiseMethodReference(key);
2024
- }
2025
- 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);
2026
- }
2027
- if (objectValue instanceof SymbolNamespace) {
2028
- if (key === "asyncIterator")
2029
- return new ComputedValue(AsyncIteratorSymbol);
2030
- if (key === "iterator")
2031
- return new ComputedValue(IteratorSymbol);
2032
- return new ComputedValue(undefined);
2033
- }
2034
- if (objectValue instanceof GlobalNamespace) {
1687
+ if (objectValue instanceof HostFunction || objectValue instanceof HostNamespace) {
2035
1688
  if (typeof key === "string" && isBlockedMember(key)) {
2036
1689
  throw new InterpreterRuntimeError(`${objectValue.name}.${key} is not available.`, propertyNode);
2037
1690
  }
2038
- if (typeof key !== "string")
2039
- return new ComputedValue(undefined);
2040
- if (objectValue.name === "Math" && mathConstants.has(key)) {
2041
- return new ComputedValue(Math[key]);
2042
- }
2043
- if (objectValue.name === "JSON") {
2044
- if (jsonStatics.has(key))
2045
- return new JsonMethodReference(key);
2046
- return new ComputedValue(undefined);
2047
- }
2048
- if (globalStaticMembers[objectValue.name]?.has(key)) {
2049
- return new GlobalMethodReference(objectValue.name, key);
2050
- }
2051
1691
  // Unknown static members read as undefined so feature detection works like native JS.
2052
- return new ComputedValue(undefined);
1692
+ return new ComputedValue(objectValue.member(key, propertyNode));
2053
1693
  }
2054
1694
  if (typeof objectValue === "string") {
2055
1695
  if (key === "length")
@@ -2066,23 +1706,6 @@ export class Interpreter {
2066
1706
  return new IntrinsicReference(objectValue, key);
2067
1707
  return new ComputedValue(undefined);
2068
1708
  }
2069
- if (objectValue instanceof CoercionFunction) {
2070
- if (typeof key === "string" && isBlockedMember(key)) {
2071
- throw new InterpreterRuntimeError(`${objectValue.name}.${key} is not available.`, propertyNode);
2072
- }
2073
- if (typeof key !== "string")
2074
- return new ComputedValue(undefined);
2075
- if (objectValue.name === "Number" && numberConstants.has(key)) {
2076
- return new ComputedValue(Number[key]);
2077
- }
2078
- if (objectValue.name === "Number" && numberStatics.has(key)) {
2079
- return new GlobalMethodReference("Number", key);
2080
- }
2081
- if (objectValue.name === "String" && stringStatics.has(key)) {
2082
- return new GlobalMethodReference("String", key);
2083
- }
2084
- return new ComputedValue(undefined);
2085
- }
2086
1709
  if (objectValue instanceof Values.Date) {
2087
1710
  if (typeof key === "string" && dateMethods.has(key))
2088
1711
  return new IntrinsicReference(objectValue, key);