@opencode/codemode 0.0.0-beta-19296 → 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.
- package/README.md +6 -0
- package/dist/codemode.d.ts +8 -11
- package/dist/codemode.js +4 -8
- package/dist/data.d.ts +28 -0
- package/dist/data.js +130 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/errors.d.ts +4 -6
- package/dist/interpreter/errors.js +22 -6
- package/dist/interpreter/execute.d.ts +3 -3
- package/dist/interpreter/execute.js +11 -18
- 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 -16
- package/dist/interpreter/methods.js +42 -239
- package/dist/interpreter/model.d.ts +12 -73
- package/dist/interpreter/model.js +0 -87
- package/dist/interpreter/promises.d.ts +12 -13
- package/dist/interpreter/promises.js +49 -26
- package/dist/interpreter/references.js +23 -70
- package/dist/interpreter/runner.d.ts +23 -0
- package/dist/interpreter/runner.js +42 -0
- package/dist/interpreter/runtime.d.ts +13 -95
- package/dist/interpreter/runtime.js +290 -723
- package/dist/openapi/spec.js +1 -1
- 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 +25 -16
- package/dist/stdlib/date.d.ts +5 -4
- package/dist/stdlib/date.js +28 -12
- package/dist/stdlib/json.d.ts +4 -4
- package/dist/stdlib/json.js +23 -28
- package/dist/stdlib/math.d.ts +3 -7
- package/dist/stdlib/math.js +85 -153
- package/dist/stdlib/number.d.ts +2 -4
- package/dist/stdlib/number.js +30 -37
- package/dist/stdlib/object.d.ts +4 -6
- package/dist/stdlib/object.js +106 -75
- package/dist/stdlib/regexp.d.ts +4 -6
- package/dist/stdlib/regexp.js +35 -12
- package/dist/stdlib/string.d.ts +1 -3
- package/dist/stdlib/string.js +15 -17
- package/dist/stdlib/url.d.ts +10 -6
- package/dist/stdlib/url.js +102 -25
- package/dist/stdlib/value.d.ts +6 -5
- package/dist/stdlib/value.js +33 -32
- package/dist/tool-runtime.d.ts +16 -15
- package/dist/tool-runtime.js +13 -150
- package/dist/values.d.ts +22 -16
- package/dist/values.js +23 -17
- 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
package/dist/stdlib/math.js
CHANGED
|
@@ -1,157 +1,89 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import {
|
|
2
|
+
import { HostFunction, HostNamespace, sync } from "../interpreter/host.js";
|
|
3
|
+
import { preserveConsumerError } from "../interpreter/runner.js";
|
|
3
4
|
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"asinh",
|
|
14
|
-
"atan",
|
|
15
|
-
"atan2",
|
|
16
|
-
"atanh",
|
|
17
|
-
"floor",
|
|
18
|
-
"ceil",
|
|
19
|
-
"round",
|
|
20
|
-
"trunc",
|
|
21
|
-
"sign",
|
|
22
|
-
"sqrt",
|
|
23
|
-
"cbrt",
|
|
24
|
-
"pow",
|
|
25
|
-
"hypot",
|
|
26
|
-
"cos",
|
|
27
|
-
"cosh",
|
|
28
|
-
"sin",
|
|
29
|
-
"sinh",
|
|
30
|
-
"tan",
|
|
31
|
-
"tanh",
|
|
32
|
-
"log",
|
|
33
|
-
"log2",
|
|
34
|
-
"log10",
|
|
35
|
-
"log1p",
|
|
36
|
-
"exp",
|
|
37
|
-
"expm1",
|
|
38
|
-
"f16round",
|
|
39
|
-
"fround",
|
|
40
|
-
"clz32",
|
|
41
|
-
"imul",
|
|
42
|
-
"sumPrecise",
|
|
43
|
-
]);
|
|
44
|
-
export const invokeMathMethod = (name, args, node) => {
|
|
45
|
-
if (!mathMethods.has(name))
|
|
46
|
-
throw new InterpreterRuntimeError(`Math.${name} is not available.`, node);
|
|
47
|
-
if (name === "random")
|
|
48
|
-
return Math.random();
|
|
49
|
-
// Validate only the arguments the method consumes; like JS, extras are ignored
|
|
50
|
-
// (so built-ins work as callbacks receiving (element, index, array)).
|
|
51
|
-
const num = (index) => {
|
|
52
|
-
if (index >= args.length)
|
|
53
|
-
return Number.NaN;
|
|
54
|
-
const arg = args[index];
|
|
55
|
-
if (typeof arg !== "number")
|
|
56
|
-
throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
|
|
57
|
-
return arg;
|
|
58
|
-
};
|
|
59
|
-
const nums = () => args.map((arg) => {
|
|
60
|
-
if (typeof arg !== "number")
|
|
61
|
-
throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
|
|
62
|
-
return arg;
|
|
63
|
-
});
|
|
64
|
-
const a = num(0);
|
|
65
|
-
const b = () => num(1);
|
|
66
|
-
switch (name) {
|
|
67
|
-
case "max":
|
|
68
|
-
return Math.max(...nums());
|
|
69
|
-
case "min":
|
|
70
|
-
return Math.min(...nums());
|
|
71
|
-
case "abs":
|
|
72
|
-
return Math.abs(a);
|
|
73
|
-
case "acos":
|
|
74
|
-
return Math.acos(a);
|
|
75
|
-
case "acosh":
|
|
76
|
-
return Math.acosh(a);
|
|
77
|
-
case "asin":
|
|
78
|
-
return Math.asin(a);
|
|
79
|
-
case "asinh":
|
|
80
|
-
return Math.asinh(a);
|
|
81
|
-
case "atan":
|
|
82
|
-
return Math.atan(a);
|
|
83
|
-
case "atan2":
|
|
84
|
-
return Math.atan2(a, b());
|
|
85
|
-
case "atanh":
|
|
86
|
-
return Math.atanh(a);
|
|
87
|
-
case "floor":
|
|
88
|
-
return Math.floor(a);
|
|
89
|
-
case "ceil":
|
|
90
|
-
return Math.ceil(a);
|
|
91
|
-
case "round":
|
|
92
|
-
return Math.round(a);
|
|
93
|
-
case "trunc":
|
|
94
|
-
return Math.trunc(a);
|
|
95
|
-
case "sign":
|
|
96
|
-
return Math.sign(a);
|
|
97
|
-
case "sqrt":
|
|
98
|
-
return Math.sqrt(a);
|
|
99
|
-
case "cbrt":
|
|
100
|
-
return Math.cbrt(a);
|
|
101
|
-
case "pow":
|
|
102
|
-
return Math.pow(a, b());
|
|
103
|
-
case "hypot":
|
|
104
|
-
return Math.hypot(...nums());
|
|
105
|
-
case "cos":
|
|
106
|
-
return Math.cos(a);
|
|
107
|
-
case "cosh":
|
|
108
|
-
return Math.cosh(a);
|
|
109
|
-
case "sin":
|
|
110
|
-
return Math.sin(a);
|
|
111
|
-
case "sinh":
|
|
112
|
-
return Math.sinh(a);
|
|
113
|
-
case "tan":
|
|
114
|
-
return Math.tan(a);
|
|
115
|
-
case "tanh":
|
|
116
|
-
return Math.tanh(a);
|
|
117
|
-
case "log":
|
|
118
|
-
return Math.log(a);
|
|
119
|
-
case "log2":
|
|
120
|
-
return Math.log2(a);
|
|
121
|
-
case "log10":
|
|
122
|
-
return Math.log10(a);
|
|
123
|
-
case "log1p":
|
|
124
|
-
return Math.log1p(a);
|
|
125
|
-
case "exp":
|
|
126
|
-
return Math.exp(a);
|
|
127
|
-
case "expm1":
|
|
128
|
-
return Math.expm1(a);
|
|
129
|
-
case "f16round":
|
|
130
|
-
return Math.f16round(a);
|
|
131
|
-
case "fround":
|
|
132
|
-
return Math.fround(a);
|
|
133
|
-
case "clz32":
|
|
134
|
-
return Math.clz32(a);
|
|
135
|
-
case "imul":
|
|
136
|
-
return Math.imul(a, b());
|
|
137
|
-
}
|
|
138
|
-
throw new InterpreterRuntimeError(`Math.${name} is not available.`, node);
|
|
5
|
+
// Validate only the arguments a method consumes; like JS, extras are ignored
|
|
6
|
+
// (so built-ins work as callbacks receiving (element, index, array)).
|
|
7
|
+
const number = (name, args, index, node) => {
|
|
8
|
+
if (index >= args.length)
|
|
9
|
+
return Number.NaN;
|
|
10
|
+
const arg = args[index];
|
|
11
|
+
if (typeof arg !== "number")
|
|
12
|
+
throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
|
|
13
|
+
return arg;
|
|
139
14
|
};
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
yield*
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
15
|
+
const unary = (name, op) => sync(`Math.${name}`, (args, node) => op(number(name, args, 0, node)));
|
|
16
|
+
const binary = (name, op) => sync(`Math.${name}`, (args, node) => op(number(name, args, 0, node), number(name, args, 1, node)));
|
|
17
|
+
const variadic = (name, op) => sync(`Math.${name}`, (args, node) => op(...args.map((arg) => {
|
|
18
|
+
if (typeof arg !== "number")
|
|
19
|
+
throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
|
|
20
|
+
return arg;
|
|
21
|
+
})));
|
|
22
|
+
const sumPrecise = (runner) => new HostFunction({
|
|
23
|
+
name: "Math.sumPrecise",
|
|
24
|
+
call: (args, node) => Effect.gen(function* () {
|
|
25
|
+
const cursor = yield* runner.syncIterator(args[0], node);
|
|
26
|
+
if (cursor === undefined) {
|
|
27
|
+
throw new InterpreterRuntimeError("Math.sumPrecise expects a synchronous iterable.", node).as("TypeError");
|
|
28
|
+
}
|
|
29
|
+
const numbers = [];
|
|
30
|
+
while (true) {
|
|
31
|
+
const step = yield* cursor.next;
|
|
32
|
+
if (step.done)
|
|
33
|
+
return Math.sumPrecise(numbers);
|
|
34
|
+
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
35
|
+
if (typeof step.value !== "number") {
|
|
36
|
+
throw new InterpreterRuntimeError("Math.sumPrecise expects an iterable of numbers.", node).as("TypeError");
|
|
37
|
+
}
|
|
38
|
+
numbers.push(step.value);
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
}),
|
|
42
|
+
});
|
|
43
|
+
export const mathGlobal = (runner) => new HostNamespace("Math", {
|
|
44
|
+
PI: Math.PI,
|
|
45
|
+
E: Math.E,
|
|
46
|
+
LN2: Math.LN2,
|
|
47
|
+
LN10: Math.LN10,
|
|
48
|
+
LOG2E: Math.LOG2E,
|
|
49
|
+
LOG10E: Math.LOG10E,
|
|
50
|
+
SQRT2: Math.SQRT2,
|
|
51
|
+
SQRT1_2: Math.SQRT1_2,
|
|
52
|
+
random: sync("Math.random", () => Math.random()),
|
|
53
|
+
max: variadic("max", Math.max),
|
|
54
|
+
min: variadic("min", Math.min),
|
|
55
|
+
hypot: variadic("hypot", Math.hypot),
|
|
56
|
+
abs: unary("abs", Math.abs),
|
|
57
|
+
acos: unary("acos", Math.acos),
|
|
58
|
+
acosh: unary("acosh", Math.acosh),
|
|
59
|
+
asin: unary("asin", Math.asin),
|
|
60
|
+
asinh: unary("asinh", Math.asinh),
|
|
61
|
+
atan: unary("atan", Math.atan),
|
|
62
|
+
atan2: binary("atan2", Math.atan2),
|
|
63
|
+
atanh: unary("atanh", Math.atanh),
|
|
64
|
+
floor: unary("floor", Math.floor),
|
|
65
|
+
ceil: unary("ceil", Math.ceil),
|
|
66
|
+
round: unary("round", Math.round),
|
|
67
|
+
trunc: unary("trunc", Math.trunc),
|
|
68
|
+
sign: unary("sign", Math.sign),
|
|
69
|
+
sqrt: unary("sqrt", Math.sqrt),
|
|
70
|
+
cbrt: unary("cbrt", Math.cbrt),
|
|
71
|
+
pow: binary("pow", Math.pow),
|
|
72
|
+
cos: unary("cos", Math.cos),
|
|
73
|
+
cosh: unary("cosh", Math.cosh),
|
|
74
|
+
sin: unary("sin", Math.sin),
|
|
75
|
+
sinh: unary("sinh", Math.sinh),
|
|
76
|
+
tan: unary("tan", Math.tan),
|
|
77
|
+
tanh: unary("tanh", Math.tanh),
|
|
78
|
+
log: unary("log", Math.log),
|
|
79
|
+
log2: unary("log2", Math.log2),
|
|
80
|
+
log10: unary("log10", Math.log10),
|
|
81
|
+
log1p: unary("log1p", Math.log1p),
|
|
82
|
+
exp: unary("exp", Math.exp),
|
|
83
|
+
expm1: unary("expm1", Math.expm1),
|
|
84
|
+
f16round: unary("f16round", Math.f16round),
|
|
85
|
+
fround: unary("fround", Math.fround),
|
|
86
|
+
clz32: unary("clz32", Math.clz32),
|
|
87
|
+
imul: binary("imul", Math.imul),
|
|
88
|
+
sumPrecise: sumPrecise(runner),
|
|
157
89
|
});
|
package/dist/stdlib/number.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
+
import { type AstNode } from "../interpreter/model.js";
|
|
1
2
|
export declare const numberMethods: Set<string>;
|
|
2
|
-
export declare const numberConstants: Set<string>;
|
|
3
|
-
export declare const numberStatics: Set<string>;
|
|
4
3
|
export declare const invokeNumberMethod: (value: number, name: string, args: Array<unknown>, node: AstNode) => unknown;
|
|
5
|
-
export declare const
|
|
6
|
-
import { type AstNode } from "../interpreter/model.js";
|
|
4
|
+
export declare const numberGlobal: import("../interpreter/host.js").HostFunction<never>;
|
package/dist/stdlib/number.js
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
+
import { toProgram } from "../data.js";
|
|
2
|
+
import { sync } from "../interpreter/host.js";
|
|
3
|
+
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
4
|
+
import { coercion, coerceToString } from "./value.js";
|
|
1
5
|
export const numberMethods = new Set(["toFixed", "toPrecision", "toExponential", "toString", "valueOf"]);
|
|
2
|
-
export const numberConstants = new Set([
|
|
3
|
-
"MAX_SAFE_INTEGER",
|
|
4
|
-
"MIN_SAFE_INTEGER",
|
|
5
|
-
"MAX_VALUE",
|
|
6
|
-
"MIN_VALUE",
|
|
7
|
-
"EPSILON",
|
|
8
|
-
"NaN",
|
|
9
|
-
"POSITIVE_INFINITY",
|
|
10
|
-
"NEGATIVE_INFINITY",
|
|
11
|
-
]);
|
|
12
|
-
export const numberStatics = new Set(["isInteger", "isFinite", "isNaN", "isSafeInteger", "parseInt", "parseFloat"]);
|
|
13
6
|
export const invokeNumberMethod = (value, name, args, node) => {
|
|
14
7
|
const optNum = (index) => {
|
|
15
8
|
const arg = args[index];
|
|
@@ -46,31 +39,31 @@ export const invokeNumberMethod = (value, name, args, node) => {
|
|
|
46
39
|
default:
|
|
47
40
|
throw new InterpreterRuntimeError(`Number method '${name}' is not available.`, node);
|
|
48
41
|
}
|
|
49
|
-
return
|
|
42
|
+
return toProgram(result, `Number.${name} result`);
|
|
50
43
|
};
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return Number.isInteger(value);
|
|
56
|
-
case "isFinite":
|
|
57
|
-
return Number.isFinite(value);
|
|
58
|
-
case "isNaN":
|
|
59
|
-
return Number.isNaN(value);
|
|
60
|
-
case "isSafeInteger":
|
|
61
|
-
return Number.isSafeInteger(value);
|
|
62
|
-
case "parseInt": {
|
|
63
|
-
const radix = args[1];
|
|
64
|
-
if (radix !== undefined && typeof radix !== "number") {
|
|
65
|
-
throw new InterpreterRuntimeError("Number.parseInt expects a numeric radix.", node);
|
|
66
|
-
}
|
|
67
|
-
return parseInt(coerceToString(value), radix);
|
|
68
|
-
}
|
|
69
|
-
case "parseFloat":
|
|
70
|
-
return parseFloat(coerceToString(value));
|
|
71
|
-
default:
|
|
72
|
-
throw new InterpreterRuntimeError(`Number.${name} is not available.`, node);
|
|
44
|
+
const parseIntStatic = sync("Number.parseInt", (args, node) => {
|
|
45
|
+
const radix = args[1];
|
|
46
|
+
if (radix !== undefined && typeof radix !== "number") {
|
|
47
|
+
throw new InterpreterRuntimeError("Number.parseInt expects a numeric radix.", node);
|
|
73
48
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
49
|
+
return parseInt(coerceToString(args[0]), radix);
|
|
50
|
+
});
|
|
51
|
+
export const numberGlobal = coercion("Number", {
|
|
52
|
+
instanceOf: () => false,
|
|
53
|
+
members: {
|
|
54
|
+
MAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER,
|
|
55
|
+
MIN_SAFE_INTEGER: Number.MIN_SAFE_INTEGER,
|
|
56
|
+
MAX_VALUE: Number.MAX_VALUE,
|
|
57
|
+
MIN_VALUE: Number.MIN_VALUE,
|
|
58
|
+
EPSILON: Number.EPSILON,
|
|
59
|
+
NaN: Number.NaN,
|
|
60
|
+
POSITIVE_INFINITY: Number.POSITIVE_INFINITY,
|
|
61
|
+
NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
|
|
62
|
+
isInteger: sync("Number.isInteger", (args) => Number.isInteger(args[0])),
|
|
63
|
+
isFinite: sync("Number.isFinite", (args) => Number.isFinite(args[0])),
|
|
64
|
+
isNaN: sync("Number.isNaN", (args) => Number.isNaN(args[0])),
|
|
65
|
+
isSafeInteger: sync("Number.isSafeInteger", (args) => Number.isSafeInteger(args[0])),
|
|
66
|
+
parseInt: parseIntStatic,
|
|
67
|
+
parseFloat: sync("Number.parseFloat", (args) => parseFloat(coerceToString(args[0]))),
|
|
68
|
+
},
|
|
69
|
+
});
|
package/dist/stdlib/object.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HostFunction } from "../interpreter/host.js";
|
|
2
2
|
import { type AstNode } from "../interpreter/model.js";
|
|
3
|
-
import { type
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const invokeObjectMethod: (name: string, args: Array<unknown>, node: AstNode) => unknown;
|
|
7
|
-
export declare const invokeObjectFromEntries: <R>(runner: SyncIteratorRunner<R>, source: unknown, node: AstNode) => Effect.Effect<Record<string, unknown>, unknown, R>;
|
|
3
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
4
|
+
export declare const objectAssign: (args: Array<unknown>, node: AstNode) => unknown;
|
|
5
|
+
export declare const objectGlobal: <R>(runner: Runner<R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>) => HostFunction<R>;
|
package/dist/stdlib/object.js
CHANGED
|
@@ -1,84 +1,66 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
+
import { isBlockedMember, toProgram } from "../data.js";
|
|
3
|
+
import { HostFunction, sync, syncCall } from "../interpreter/host.js";
|
|
2
4
|
import { AsyncIteratorSymbol, InterpreterRuntimeError, IteratorSymbol } from "../interpreter/model.js";
|
|
3
|
-
import { containsOpaqueReference, rejectCircularInsertion } from "../interpreter/references.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const requireObject = () => {
|
|
12
|
-
const input = args[0];
|
|
13
|
-
if (Array.isArray(input))
|
|
14
|
-
return input;
|
|
15
|
-
if (isCodeModeValue(input))
|
|
16
|
-
return {};
|
|
17
|
-
if (input instanceof CodeModePromise) {
|
|
18
|
-
throw new InterpreterRuntimeError(`Object.${name} received an un-awaited Promise; await it before inspecting the result.`, node, "InvalidDataValue");
|
|
19
|
-
}
|
|
20
|
-
if (input === null || typeof input !== "object") {
|
|
21
|
-
throw new InterpreterRuntimeError(`Object.${name} expects a data object or array.`, node, "InvalidDataValue");
|
|
22
|
-
}
|
|
23
|
-
const prototype = Object.getPrototypeOf(input);
|
|
24
|
-
if (prototype !== null && prototype !== Object.prototype) {
|
|
25
|
-
throw new InterpreterRuntimeError(`Object.${name} expects a data object or array.`, node, "InvalidDataValue");
|
|
26
|
-
}
|
|
5
|
+
import { containsOpaqueReference, rejectCircularInsertion, typeofValue } from "../interpreter/references.js";
|
|
6
|
+
import { preserveConsumerError } from "../interpreter/runner.js";
|
|
7
|
+
import { ToolReference } from "../tool-runtime.js";
|
|
8
|
+
import { Values } from "../values.js";
|
|
9
|
+
import { groupBy } from "./collections.js";
|
|
10
|
+
import { coerceToString } from "./value.js";
|
|
11
|
+
const requireObject = (name, input, node) => {
|
|
12
|
+
if (Array.isArray(input))
|
|
27
13
|
return input;
|
|
14
|
+
if (Values.isValue(input))
|
|
15
|
+
return {};
|
|
16
|
+
if (input instanceof Values.Promise) {
|
|
17
|
+
throw new InterpreterRuntimeError(`Object.${name} received an un-awaited Promise; await it before inspecting the result.`, node, "InvalidDataValue");
|
|
18
|
+
}
|
|
19
|
+
if (input === null || typeof input !== "object") {
|
|
20
|
+
throw new InterpreterRuntimeError(`Object.${name} expects a data object or array.`, node, "InvalidDataValue");
|
|
21
|
+
}
|
|
22
|
+
const prototype = Object.getPrototypeOf(input);
|
|
23
|
+
if (prototype !== null && prototype !== Object.prototype) {
|
|
24
|
+
throw new InterpreterRuntimeError(`Object.${name} expects a data object or array.`, node, "InvalidDataValue");
|
|
25
|
+
}
|
|
26
|
+
return input;
|
|
27
|
+
};
|
|
28
|
+
export const objectAssign = (args, node) => {
|
|
29
|
+
const target = args[0];
|
|
30
|
+
if (target === null || typeof target !== "object" || Array.isArray(target) || Values.isValue(target)) {
|
|
31
|
+
throw new InterpreterRuntimeError("Object.assign expects a data object target.", node);
|
|
32
|
+
}
|
|
33
|
+
const out = target;
|
|
34
|
+
const seen = new Set();
|
|
35
|
+
const guardedSet = (key, item) => {
|
|
36
|
+
if (typeof key === "string" && isBlockedMember(key))
|
|
37
|
+
throw new InterpreterRuntimeError(`Property '${key}' is not available.`, node);
|
|
38
|
+
rejectCircularInsertion(out, item, "Object.assign result", node, seen);
|
|
39
|
+
if (!Reflect.set(out, key, item))
|
|
40
|
+
throw new InterpreterRuntimeError(`Object.assign could not assign property '${String(key)}'.`, node).as("TypeError");
|
|
28
41
|
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
case "is":
|
|
39
|
-
if (containsOpaqueReference(args[0]) || containsOpaqueReference(args[1])) {
|
|
40
|
-
throw new InterpreterRuntimeError("Object.is requires data values.", node, "InvalidDataValue");
|
|
41
|
-
}
|
|
42
|
-
return Object.is(args[0], args[1]);
|
|
43
|
-
case "assign": {
|
|
44
|
-
const target = args[0];
|
|
45
|
-
if (target === null || typeof target !== "object" || Array.isArray(target) || isCodeModeValue(target)) {
|
|
46
|
-
throw new InterpreterRuntimeError("Object.assign expects a data object target.", node);
|
|
47
|
-
}
|
|
48
|
-
const out = target;
|
|
49
|
-
const seen = new Set();
|
|
50
|
-
const guardedSet = (key, item) => {
|
|
51
|
-
if (typeof key === "string" && isBlockedMember(key))
|
|
52
|
-
throw new InterpreterRuntimeError(`Property '${key}' is not available.`, node);
|
|
53
|
-
rejectCircularInsertion(out, item, "Object.assign result", node, seen);
|
|
54
|
-
if (!Reflect.set(out, key, item))
|
|
55
|
-
throw new InterpreterRuntimeError(`Object.assign could not assign property '${String(key)}'.`, node).as("TypeError");
|
|
56
|
-
};
|
|
57
|
-
for (const source of args.slice(1)) {
|
|
58
|
-
if (source === null || source === undefined || isCodeModeValue(source))
|
|
59
|
-
continue;
|
|
60
|
-
if (typeof source !== "object" || Array.isArray(source)) {
|
|
61
|
-
throw new InterpreterRuntimeError("Object.assign expects data objects.", node);
|
|
62
|
-
}
|
|
63
|
-
for (const key of Reflect.ownKeys(source)) {
|
|
64
|
-
if (typeof key === "string") {
|
|
65
|
-
if (Object.prototype.propertyIsEnumerable.call(source, key))
|
|
66
|
-
guardedSet(key, Reflect.get(source, key));
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (key !== AsyncIteratorSymbol && key !== IteratorSymbol)
|
|
70
|
-
continue;
|
|
71
|
-
if (!Object.prototype.propertyIsEnumerable.call(source, key))
|
|
72
|
-
continue;
|
|
42
|
+
for (const source of args.slice(1)) {
|
|
43
|
+
if (source === null || source === undefined || Values.isValue(source))
|
|
44
|
+
continue;
|
|
45
|
+
if (typeof source !== "object" || Array.isArray(source)) {
|
|
46
|
+
throw new InterpreterRuntimeError("Object.assign expects data objects.", node);
|
|
47
|
+
}
|
|
48
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
49
|
+
if (typeof key === "string") {
|
|
50
|
+
if (Object.prototype.propertyIsEnumerable.call(source, key))
|
|
73
51
|
guardedSet(key, Reflect.get(source, key));
|
|
74
|
-
|
|
52
|
+
continue;
|
|
75
53
|
}
|
|
76
|
-
|
|
54
|
+
if (key !== AsyncIteratorSymbol && key !== IteratorSymbol)
|
|
55
|
+
continue;
|
|
56
|
+
if (!Object.prototype.propertyIsEnumerable.call(source, key))
|
|
57
|
+
continue;
|
|
58
|
+
guardedSet(key, Reflect.get(source, key));
|
|
77
59
|
}
|
|
78
60
|
}
|
|
79
|
-
|
|
61
|
+
return out;
|
|
80
62
|
};
|
|
81
|
-
|
|
63
|
+
const objectFromEntries = (runner, source, node) => {
|
|
82
64
|
const out = Object.create(null);
|
|
83
65
|
return Effect.gen(function* () {
|
|
84
66
|
const cursor = yield* runner.syncIterator(source, node);
|
|
@@ -92,13 +74,13 @@ export const invokeObjectFromEntries = (runner, source, node) => {
|
|
|
92
74
|
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
93
75
|
if (step.value === null ||
|
|
94
76
|
typeof step.value !== "object" ||
|
|
95
|
-
|
|
77
|
+
Values.isValue(step.value) ||
|
|
96
78
|
containsOpaqueReference(step.value)) {
|
|
97
79
|
throw new InterpreterRuntimeError("Object.fromEntries expects [key, value] entry objects.", node).as("TypeError");
|
|
98
80
|
}
|
|
99
81
|
const entry = step.value;
|
|
100
|
-
|
|
101
|
-
|
|
82
|
+
toProgram(entry[0], "Object.fromEntries key");
|
|
83
|
+
toProgram(entry[1], "Object.fromEntries value");
|
|
102
84
|
const key = coerceToString(entry[0]);
|
|
103
85
|
if (isBlockedMember(key))
|
|
104
86
|
throw new InterpreterRuntimeError(`Property '${key}' is not available.`, node);
|
|
@@ -107,3 +89,52 @@ export const invokeObjectFromEntries = (runner, source, node) => {
|
|
|
107
89
|
}
|
|
108
90
|
});
|
|
109
91
|
};
|
|
92
|
+
const constructObject = (args, node) => {
|
|
93
|
+
const first = args[0];
|
|
94
|
+
if (first === null || first === undefined)
|
|
95
|
+
return {};
|
|
96
|
+
if (typeof first === "object")
|
|
97
|
+
return first;
|
|
98
|
+
throw new InterpreterRuntimeError(`Object(${typeof first}) wrapper objects are not supported; use the primitive value directly.`, node);
|
|
99
|
+
};
|
|
100
|
+
// Tool references are not data; only Object.keys(tools) reads them, for tool names.
|
|
101
|
+
const rejectTools = (name, args, node) => {
|
|
102
|
+
if (!(args[0] instanceof ToolReference))
|
|
103
|
+
return;
|
|
104
|
+
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");
|
|
105
|
+
};
|
|
106
|
+
const objectStatic = (name, impl) => sync(`Object.${name}`, (args, node) => {
|
|
107
|
+
rejectTools(name, args, node);
|
|
108
|
+
return impl(args, node);
|
|
109
|
+
});
|
|
110
|
+
// Object constructs identically with or without new, like JS. Only `keys` copies its result into the
|
|
111
|
+
// program; `values`, `entries`, `assign`, and `fromEntries` hand back the program's own values.
|
|
112
|
+
export const objectGlobal = (runner, toolKeys) => new HostFunction({
|
|
113
|
+
name: "Object",
|
|
114
|
+
call: syncCall(constructObject),
|
|
115
|
+
construct: syncCall(constructObject),
|
|
116
|
+
instanceOf: (value) => value !== null && (typeof value === "object" || typeofValue(value) === "function"),
|
|
117
|
+
members: {
|
|
118
|
+
keys: sync("Object.keys", (args, node) => toProgram(args[0] instanceof ToolReference
|
|
119
|
+
? [...toolKeys(args[0].path)]
|
|
120
|
+
: Object.keys(requireObject("keys", args[0], node)), "Object.keys result")),
|
|
121
|
+
values: objectStatic("values", (args, node) => Object.values(requireObject("values", args[0], node))),
|
|
122
|
+
entries: objectStatic("entries", (args, node) => Object.entries(requireObject("entries", args[0], node)).map(([key, item]) => [key, item])),
|
|
123
|
+
hasOwn: objectStatic("hasOwn", (args, node) => Object.hasOwn(requireObject("hasOwn", args[0], node), args[1] === AsyncIteratorSymbol || args[1] === IteratorSymbol ? args[1] : String(args[1]))),
|
|
124
|
+
is: objectStatic("is", (args, node) => {
|
|
125
|
+
if (containsOpaqueReference(args[0]) || containsOpaqueReference(args[1])) {
|
|
126
|
+
throw new InterpreterRuntimeError("Object.is requires data values.", node, "InvalidDataValue");
|
|
127
|
+
}
|
|
128
|
+
return Object.is(args[0], args[1]);
|
|
129
|
+
}),
|
|
130
|
+
assign: objectStatic("assign", objectAssign),
|
|
131
|
+
fromEntries: new HostFunction({
|
|
132
|
+
name: "Object.fromEntries",
|
|
133
|
+
call: (args, node) => Effect.suspend(() => {
|
|
134
|
+
rejectTools("fromEntries", args, node);
|
|
135
|
+
return objectFromEntries(runner, args[0], node);
|
|
136
|
+
}),
|
|
137
|
+
}),
|
|
138
|
+
groupBy: groupBy(runner, "Object"),
|
|
139
|
+
},
|
|
140
|
+
});
|
package/dist/stdlib/regexp.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { type AstNode } from "../interpreter/model.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Values } from "../values.js";
|
|
3
3
|
export declare const regexpMethods: Set<string>;
|
|
4
|
-
export declare const regexpStatics: Set<string>;
|
|
5
4
|
export declare const regexpProperties: Set<string>;
|
|
6
|
-
export declare const regexFailureReason: (error: unknown) => string;
|
|
7
|
-
export declare const escapeRegexHint = "To match special characters like ( ) [ ] { } + * ? . literally, escape them with a backslash (e.g. \"\\\\(\") or test for them with String.includes instead.";
|
|
8
5
|
export declare const toHostRegex: (arg: unknown, method: string, node: AstNode, extraFlags?: string) => RegExp;
|
|
9
6
|
export declare const matchToValue: (match: RegExpMatchArray) => Array<unknown>;
|
|
10
|
-
export declare const
|
|
11
|
-
export declare const
|
|
7
|
+
export declare const constructRegExp: (args: Array<unknown>, node: AstNode) => Values.RegExp;
|
|
8
|
+
export declare const regexpGlobal: import("../interpreter/host.js").HostFunction<never>;
|
|
9
|
+
export declare const invokeRegExpMethod: (value: Values.RegExp, name: string, args: Array<unknown>, node: AstNode) => unknown;
|
package/dist/stdlib/regexp.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { sync, syncCall } from "../interpreter/host.js";
|
|
1
2
|
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
2
|
-
import { isBlockedMember } from "../
|
|
3
|
-
import {
|
|
3
|
+
import { isBlockedMember } from "../data.js";
|
|
4
|
+
import { Values } from "../values.js";
|
|
4
5
|
import { coerceToNumber, coerceToString } from "./value.js";
|
|
5
6
|
export const regexpMethods = new Set(["test", "exec", "toString"]);
|
|
6
|
-
export const regexpStatics = new Set(["escape"]);
|
|
7
7
|
export const regexpProperties = new Set([
|
|
8
8
|
"source",
|
|
9
9
|
"flags",
|
|
@@ -17,13 +17,13 @@ export const regexpProperties = new Set([
|
|
|
17
17
|
"unicodeSets",
|
|
18
18
|
"dotAll",
|
|
19
19
|
]);
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const regexFailureReason = (error) => (error instanceof Error ? error.message : String(error)).replace(/^Invalid regular expression:\s*/i, "");
|
|
21
|
+
const escapeRegexHint = 'To match special characters like ( ) [ ] { } + * ? . literally, escape them with a backslash (e.g. "\\\\(") or test for them with String.includes instead.';
|
|
22
22
|
export const toHostRegex = (arg, method, node, extraFlags = "") => {
|
|
23
23
|
// Native parity: an undefined pattern behaves as an empty pattern.
|
|
24
24
|
if (arg === undefined)
|
|
25
25
|
return new RegExp("", extraFlags);
|
|
26
|
-
if (arg instanceof
|
|
26
|
+
if (arg instanceof Values.RegExp)
|
|
27
27
|
return arg.regex;
|
|
28
28
|
if (typeof arg === "string") {
|
|
29
29
|
try {
|
|
@@ -51,14 +51,37 @@ export const matchToValue = (match) => {
|
|
|
51
51
|
result.indices = indicesToValue(match.indices);
|
|
52
52
|
return result;
|
|
53
53
|
};
|
|
54
|
-
export const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
export const constructRegExp = (args, node) => {
|
|
55
|
+
const first = args[0];
|
|
56
|
+
const pattern = first instanceof Values.RegExp ? first.regex.source : first === undefined ? "" : coerceToString(first);
|
|
57
|
+
const flagsArg = args[1];
|
|
58
|
+
if (flagsArg !== undefined && typeof flagsArg !== "string") {
|
|
59
|
+
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");
|
|
60
|
+
}
|
|
61
|
+
const flags = flagsArg ?? (first instanceof Values.RegExp ? first.regex.flags : "");
|
|
62
|
+
try {
|
|
63
|
+
return new Values.RegExp(pattern, flags);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const reason = regexFailureReason(error);
|
|
67
|
+
throw new InterpreterRuntimeError(/flag/i.test(reason)
|
|
68
|
+
? `new RegExp(...) received invalid flags ${JSON.stringify(flags)} (${reason}). Valid flags are d, g, i, m, s, u, v, and y.`
|
|
69
|
+
: `new RegExp(...) received ${JSON.stringify(pattern)}, which is not a valid regular expression pattern (${reason}). ${escapeRegexHint}`, node).as("SyntaxError");
|
|
59
70
|
}
|
|
60
|
-
return RegExp.escape(args[0]);
|
|
61
71
|
};
|
|
72
|
+
// RegExp constructs identically with or without new, like JS.
|
|
73
|
+
export const regexpGlobal = sync("RegExp", constructRegExp, {
|
|
74
|
+
construct: syncCall(constructRegExp),
|
|
75
|
+
instanceOf: (value) => value instanceof Values.RegExp,
|
|
76
|
+
members: {
|
|
77
|
+
escape: sync("RegExp.escape", (args, node) => {
|
|
78
|
+
if (typeof args[0] !== "string") {
|
|
79
|
+
throw new InterpreterRuntimeError("RegExp.escape expects a string.", node).as("TypeError");
|
|
80
|
+
}
|
|
81
|
+
return RegExp.escape(args[0]);
|
|
82
|
+
}),
|
|
83
|
+
},
|
|
84
|
+
});
|
|
62
85
|
export const invokeRegExpMethod = (value, name, args, node) => {
|
|
63
86
|
switch (name) {
|
|
64
87
|
case "test":
|
package/dist/stdlib/string.d.ts
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
1
|
export declare const stringMethods: Set<string>;
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const invokeStringStatic: (name: string, args: Array<unknown>, node: AstNode) => unknown;
|
|
4
|
-
import { type AstNode } from "../interpreter/model.js";
|
|
2
|
+
export declare const stringGlobal: import("../interpreter/host.js").HostFunction<never>;
|