@opencode/codemode 0.0.0-dev-19366 → 0.0.0-dev-19368
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/interpreter/errors.d.ts +4 -6
- package/dist/interpreter/errors.js +20 -4
- package/dist/interpreter/globals.d.ts +13 -0
- package/dist/interpreter/globals.js +59 -0
- package/dist/interpreter/host.d.ts +41 -0
- package/dist/interpreter/host.js +44 -0
- package/dist/interpreter/methods.d.ts +3 -23
- package/dist/interpreter/methods.js +8 -183
- package/dist/interpreter/model.d.ts +0 -41
- package/dist/interpreter/model.js +0 -56
- package/dist/interpreter/promises.d.ts +7 -8
- package/dist/interpreter/promises.js +45 -22
- package/dist/interpreter/references.js +11 -28
- package/dist/interpreter/runner.d.ts +23 -0
- package/dist/interpreter/runner.js +42 -0
- package/dist/interpreter/runtime.d.ts +0 -11
- package/dist/interpreter/runtime.js +33 -423
- package/dist/stdlib/array.d.ts +3 -0
- package/dist/stdlib/array.js +73 -0
- package/dist/stdlib/collections.d.ts +6 -1
- package/dist/stdlib/collections.js +120 -1
- package/dist/stdlib/console.d.ts +3 -2
- package/dist/stdlib/console.js +11 -2
- package/dist/stdlib/date.d.ts +3 -2
- package/dist/stdlib/date.js +27 -11
- package/dist/stdlib/json.d.ts +4 -4
- package/dist/stdlib/json.js +6 -2
- package/dist/stdlib/math.d.ts +3 -7
- package/dist/stdlib/math.js +85 -153
- package/dist/stdlib/number.d.ts +1 -3
- package/dist/stdlib/number.js +28 -36
- package/dist/stdlib/object.d.ts +4 -6
- package/dist/stdlib/object.js +101 -71
- package/dist/stdlib/regexp.d.ts +2 -4
- package/dist/stdlib/regexp.js +32 -9
- package/dist/stdlib/string.d.ts +1 -3
- package/dist/stdlib/string.js +14 -16
- package/dist/stdlib/url.d.ts +8 -4
- package/dist/stdlib/url.js +97 -21
- package/dist/stdlib/value.d.ts +5 -3
- package/dist/stdlib/value.js +21 -19
- package/package.json +1 -1
- package/dist/interpreter/iterator.d.ts +0 -13
- package/dist/interpreter/iterator.js +0 -4
- package/dist/stdlib/promise.d.ts +0 -2
- package/dist/stdlib/promise.js +0 -1
|
@@ -1,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,
|
|
5
|
-
import { caughtErrorValue
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
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,
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
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
|
|
60
|
-
|
|
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) {
|
|
@@ -163,38 +120,9 @@ export class Interpreter {
|
|
|
163
120
|
this.toolKeys = toolKeys;
|
|
164
121
|
this.logs = logs;
|
|
165
122
|
this.promises = promises;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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 });
|
|
123
|
+
const host = { runner: this.runner, promises, search: invokeSearch, toolKeys, logs };
|
|
124
|
+
for (const [name, value] of globals(host))
|
|
125
|
+
globalScope.set(name, { mutable: false, value });
|
|
198
126
|
}
|
|
199
127
|
run(program) {
|
|
200
128
|
const self = this;
|
|
@@ -1012,7 +940,7 @@ export class Interpreter {
|
|
|
1012
940
|
case "Literal": {
|
|
1013
941
|
const regex = node.regex;
|
|
1014
942
|
if (regex)
|
|
1015
|
-
return Effect.sync(() =>
|
|
943
|
+
return Effect.sync(() => constructRegExp([regex.pattern, regex.flags], node));
|
|
1016
944
|
return Effect.sync(() => toProgram(node.value, "Literal"));
|
|
1017
945
|
}
|
|
1018
946
|
case "Identifier":
|
|
@@ -1067,208 +995,15 @@ export class Interpreter {
|
|
|
1067
995
|
}
|
|
1068
996
|
}
|
|
1069
997
|
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
|
-
const self = this;
|
|
1170
|
-
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
998
|
const self = this;
|
|
1193
999
|
return Effect.gen(function* () {
|
|
1194
|
-
const
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
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
|
-
}
|
|
1000
|
+
const callee = yield* self.evaluateExpression(node.callee);
|
|
1001
|
+
// Globals are built with this interpreter's R; `instanceof` cannot recover the type argument.
|
|
1002
|
+
const construct = callee instanceof HostFunction ? callee.construct : undefined;
|
|
1003
|
+
if (construct === undefined)
|
|
1004
|
+
throw unsupportedSyntax("NewExpression", node);
|
|
1005
|
+
const args = yield* self.evaluateCallArguments(node.arguments);
|
|
1006
|
+
return yield* construct(args, node);
|
|
1272
1007
|
});
|
|
1273
1008
|
}
|
|
1274
1009
|
evaluateBinaryExpression(node) {
|
|
@@ -1522,12 +1257,6 @@ export class Interpreter {
|
|
|
1522
1257
|
}
|
|
1523
1258
|
return yield* self.createToolCallPromise(callable.path, args);
|
|
1524
1259
|
}
|
|
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
1260
|
if (callable instanceof CodeModeFunction) {
|
|
1532
1261
|
return yield* self.invokeFunction(callable, args);
|
|
1533
1262
|
}
|
|
@@ -1540,93 +1269,17 @@ export class Interpreter {
|
|
|
1540
1269
|
if (callable instanceof IntrinsicReference) {
|
|
1541
1270
|
return yield* invokeIntrinsic(self.runner, callable, args, node);
|
|
1542
1271
|
}
|
|
1543
|
-
if (callable instanceof
|
|
1544
|
-
|
|
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`);
|
|
1573
|
-
}
|
|
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;
|
|
1272
|
+
if (callable instanceof PromiseInstanceMethodReference) {
|
|
1273
|
+
return yield* invokePromiseInstanceMethod(self.runner, self.promises, callable, args, node);
|
|
1611
1274
|
}
|
|
1275
|
+
if (callable instanceof HostFunction)
|
|
1276
|
+
return yield* callable.call(args, node);
|
|
1612
1277
|
if (callable === undefined || callable === null) {
|
|
1613
1278
|
throw new InterpreterRuntimeError(`${calleeDescription(callee)} is not a function.`, callee ?? node).as("TypeError");
|
|
1614
1279
|
}
|
|
1615
1280
|
throw new InterpreterRuntimeError("Only tools are callable here.", callee ?? node);
|
|
1616
1281
|
});
|
|
1617
1282
|
}
|
|
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
1283
|
evaluateCallArguments(argNodes) {
|
|
1631
1284
|
const self = this;
|
|
1632
1285
|
return Effect.gen(function* () {
|
|
@@ -2018,38 +1671,12 @@ export class Interpreter {
|
|
|
2018
1671
|
}
|
|
2019
1672
|
return new ToolReference([...objectValue.path, key]);
|
|
2020
1673
|
}
|
|
2021
|
-
if (objectValue instanceof
|
|
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) {
|
|
1674
|
+
if (objectValue instanceof HostFunction || objectValue instanceof HostNamespace) {
|
|
2035
1675
|
if (typeof key === "string" && isBlockedMember(key)) {
|
|
2036
1676
|
throw new InterpreterRuntimeError(`${objectValue.name}.${key} is not available.`, propertyNode);
|
|
2037
1677
|
}
|
|
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
1678
|
// Unknown static members read as undefined so feature detection works like native JS.
|
|
2052
|
-
return new ComputedValue(
|
|
1679
|
+
return new ComputedValue(objectValue.member(key, propertyNode));
|
|
2053
1680
|
}
|
|
2054
1681
|
if (typeof objectValue === "string") {
|
|
2055
1682
|
if (key === "length")
|
|
@@ -2066,23 +1693,6 @@ export class Interpreter {
|
|
|
2066
1693
|
return new IntrinsicReference(objectValue, key);
|
|
2067
1694
|
return new ComputedValue(undefined);
|
|
2068
1695
|
}
|
|
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
1696
|
if (objectValue instanceof Values.Date) {
|
|
2087
1697
|
if (typeof key === "string" && dateMethods.has(key))
|
|
2088
1698
|
return new IntrinsicReference(objectValue, key);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { HostFunction, sync, syncCall } from "../interpreter/host.js";
|
|
3
|
+
import { CodeModeGenerator, InterpreterRuntimeError } from "../interpreter/model.js";
|
|
4
|
+
import { applyCollectionCallback, preserveConsumerError } from "../interpreter/runner.js";
|
|
5
|
+
import { Values } from "../values.js";
|
|
6
|
+
const constructArray = (args, node) => {
|
|
7
|
+
if (args.length !== 1)
|
|
8
|
+
return [...args];
|
|
9
|
+
const first = args[0];
|
|
10
|
+
if (typeof first !== "number")
|
|
11
|
+
return [first];
|
|
12
|
+
if (!Number.isInteger(first) || first < 0 || first > 4294967295) {
|
|
13
|
+
throw new InterpreterRuntimeError("Invalid array length.", node).as("RangeError");
|
|
14
|
+
}
|
|
15
|
+
// Sparse like JS: Array(3) has holes, and combinator loops already skip them.
|
|
16
|
+
return new Array(first);
|
|
17
|
+
};
|
|
18
|
+
const arrayLikeSource = (source, node) => {
|
|
19
|
+
if (source instanceof Values.Promise) {
|
|
20
|
+
throw new InterpreterRuntimeError("Array.from received an un-awaited Promise; await it before creating the array.", node, "InvalidDataValue");
|
|
21
|
+
}
|
|
22
|
+
if (source !== null &&
|
|
23
|
+
typeof source === "object" &&
|
|
24
|
+
(Object.getPrototypeOf(source) === Object.prototype || Object.getPrototypeOf(source) === null) &&
|
|
25
|
+
typeof source.length === "number") {
|
|
26
|
+
const length = source.length;
|
|
27
|
+
const normalized = Number.isNaN(length) || length <= 0 ? 0 : Math.trunc(length);
|
|
28
|
+
if (normalized > 4_294_967_295)
|
|
29
|
+
throw new RangeError("Invalid array length");
|
|
30
|
+
return { length: normalized, source };
|
|
31
|
+
}
|
|
32
|
+
throw new InterpreterRuntimeError("Array.from expects an array, string, Map, Set, or array-like value.", node, "InvalidDataValue");
|
|
33
|
+
};
|
|
34
|
+
const arrayFrom = (runner, args, node) => {
|
|
35
|
+
const source = args[0];
|
|
36
|
+
const apply = args.length < 2 || args[1] === undefined ? undefined : applyCollectionCallback(runner, args[1], "Array.from", node);
|
|
37
|
+
return Effect.gen(function* () {
|
|
38
|
+
const cursor = yield* runner.syncIterator(source, node);
|
|
39
|
+
if (cursor === undefined) {
|
|
40
|
+
if (source instanceof CodeModeGenerator) {
|
|
41
|
+
throw new InterpreterRuntimeError("Array.from expects a synchronous iterable or array-like value.", node).as("TypeError");
|
|
42
|
+
}
|
|
43
|
+
const arrayLike = arrayLikeSource(source, node);
|
|
44
|
+
const values = [];
|
|
45
|
+
for (let index = 0; index < arrayLike.length; index += 1) {
|
|
46
|
+
const item = Reflect.get(arrayLike.source, index);
|
|
47
|
+
values.push(apply === undefined ? item : yield* apply([item, index]));
|
|
48
|
+
}
|
|
49
|
+
return values;
|
|
50
|
+
}
|
|
51
|
+
const values = [];
|
|
52
|
+
let index = 0;
|
|
53
|
+
while (true) {
|
|
54
|
+
const step = yield* cursor.next;
|
|
55
|
+
if (step.done)
|
|
56
|
+
return values;
|
|
57
|
+
values.push(apply === undefined ? step.value : yield* preserveConsumerError(cursor, apply([step.value, index])));
|
|
58
|
+
index += 1;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
// Array constructs identically with or without new, like JS.
|
|
63
|
+
export const arrayGlobal = (runner) => new HostFunction({
|
|
64
|
+
name: "Array",
|
|
65
|
+
call: syncCall(constructArray),
|
|
66
|
+
construct: syncCall(constructArray),
|
|
67
|
+
instanceOf: (value) => Array.isArray(value),
|
|
68
|
+
members: {
|
|
69
|
+
isArray: sync("Array.isArray", (args) => Array.isArray(args[0])),
|
|
70
|
+
of: sync("Array.of", (args) => [...args]),
|
|
71
|
+
from: new HostFunction({ name: "Array.from", call: (args, node) => arrayFrom(runner, args, node) }),
|
|
72
|
+
},
|
|
73
|
+
});
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import { HostFunction } from "../interpreter/host.js";
|
|
2
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
1
3
|
export declare const arrayMethods: Set<string>;
|
|
2
4
|
export declare const mapMethods: Set<string>;
|
|
3
|
-
export declare const mapStatics: Set<string>;
|
|
4
5
|
export declare const setMethods: Set<string>;
|
|
6
|
+
/** `Map.groupBy` and `Object.groupBy`: the same iteration, keyed into a Map or a data object. */
|
|
7
|
+
export declare const groupBy: <R>(runner: Runner<R>, namespace: "Map" | "Object") => HostFunction<R>;
|
|
8
|
+
export declare const mapGlobal: <R>(runner: Runner<R>) => HostFunction<R>;
|
|
9
|
+
export declare const setGlobal: <R>(runner: Runner<R>) => HostFunction<R>;
|