@opencode/codemode 0.0.0-dev-19366 → 0.0.0-dev-19367
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,3 +1,11 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { isBlockedMember } from "../data.js";
|
|
3
|
+
import { HostFunction, requiresNew } from "../interpreter/host.js";
|
|
4
|
+
import { InterpreterRuntimeError, isRecord } from "../interpreter/model.js";
|
|
5
|
+
import { isRuntimeReference } from "../interpreter/references.js";
|
|
6
|
+
import { applyCollectionCallback, preserveConsumerError, toPrimitive } from "../interpreter/runner.js";
|
|
7
|
+
import { Values } from "../values.js";
|
|
8
|
+
import { coerceToString } from "./value.js";
|
|
1
9
|
export const arrayMethods = new Set([
|
|
2
10
|
"map",
|
|
3
11
|
"filter",
|
|
@@ -37,7 +45,6 @@ export const arrayMethods = new Set([
|
|
|
37
45
|
"entries",
|
|
38
46
|
]);
|
|
39
47
|
export const mapMethods = new Set(["get", "set", "has", "delete", "clear", "forEach", "keys", "values", "entries"]);
|
|
40
|
-
export const mapStatics = new Set(["groupBy"]);
|
|
41
48
|
export const setMethods = new Set([
|
|
42
49
|
"add",
|
|
43
50
|
"has",
|
|
@@ -55,3 +62,115 @@ export const setMethods = new Set([
|
|
|
55
62
|
"isSupersetOf",
|
|
56
63
|
"isDisjointFrom",
|
|
57
64
|
]);
|
|
65
|
+
const coerceGroupByPropertyKey = (runner, value, node) => {
|
|
66
|
+
if (value instanceof Values.Promise)
|
|
67
|
+
return Effect.succeed("[object Promise]");
|
|
68
|
+
if (!Values.isValue(value) && isRuntimeReference(value)) {
|
|
69
|
+
throw new InterpreterRuntimeError("Object.groupBy callback must return a data value.", node, "InvalidDataValue");
|
|
70
|
+
}
|
|
71
|
+
return Effect.map(toPrimitive(runner, value, "string", node), coerceToString);
|
|
72
|
+
};
|
|
73
|
+
/** `Map.groupBy` and `Object.groupBy`: the same iteration, keyed into a Map or a data object. */
|
|
74
|
+
export const groupBy = (runner, namespace) => new HostFunction({
|
|
75
|
+
name: `${namespace}.groupBy`,
|
|
76
|
+
call: (args, node) => {
|
|
77
|
+
const source = args[0];
|
|
78
|
+
if (source === null || source === undefined) {
|
|
79
|
+
throw new InterpreterRuntimeError(`${namespace}.groupBy expects an iterable collection.`, node).as("TypeError");
|
|
80
|
+
}
|
|
81
|
+
const apply = applyCollectionCallback(runner, args[1], `${namespace}.groupBy`, node);
|
|
82
|
+
return Effect.gen(function* () {
|
|
83
|
+
const cursor = yield* runner.syncIterator(source, node);
|
|
84
|
+
if (cursor === undefined) {
|
|
85
|
+
throw new InterpreterRuntimeError(`${namespace}.groupBy expects an iterable collection.`, node).as("TypeError");
|
|
86
|
+
}
|
|
87
|
+
if (namespace === "Map") {
|
|
88
|
+
const result = new Values.Map();
|
|
89
|
+
let index = 0;
|
|
90
|
+
while (true) {
|
|
91
|
+
const step = yield* cursor.next;
|
|
92
|
+
if (step.done)
|
|
93
|
+
return result;
|
|
94
|
+
const item = step.value;
|
|
95
|
+
const key = yield* preserveConsumerError(cursor, apply([item, index]));
|
|
96
|
+
const group = result.map.get(key);
|
|
97
|
+
if (group === undefined)
|
|
98
|
+
result.map.set(key, [item]);
|
|
99
|
+
else
|
|
100
|
+
group.push(item);
|
|
101
|
+
index += 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const result = Object.create(null);
|
|
105
|
+
let index = 0;
|
|
106
|
+
while (true) {
|
|
107
|
+
const step = yield* cursor.next;
|
|
108
|
+
if (step.done)
|
|
109
|
+
return result;
|
|
110
|
+
const item = step.value;
|
|
111
|
+
const key = yield* preserveConsumerError(cursor, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(runner, value, node)));
|
|
112
|
+
if (isBlockedMember(key)) {
|
|
113
|
+
return yield* preserveConsumerError(cursor, Effect.fail(new InterpreterRuntimeError(`Property '${key}' is not available.`, node)));
|
|
114
|
+
}
|
|
115
|
+
const group = result[key];
|
|
116
|
+
if (group === undefined)
|
|
117
|
+
result[key] = [item];
|
|
118
|
+
else
|
|
119
|
+
group.push(item);
|
|
120
|
+
index += 1;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
const constructMap = (runner, init, node) => {
|
|
126
|
+
const target = new Values.Map();
|
|
127
|
+
if (init === undefined || init === null)
|
|
128
|
+
return Effect.succeed(target);
|
|
129
|
+
return Effect.gen(function* () {
|
|
130
|
+
const cursor = yield* runner.syncIterator(init, node);
|
|
131
|
+
if (cursor === undefined) {
|
|
132
|
+
throw new InterpreterRuntimeError("new Map(...) expects an iterable of [key, value] pairs or no argument.", node).as("TypeError");
|
|
133
|
+
}
|
|
134
|
+
while (true) {
|
|
135
|
+
const step = yield* cursor.next;
|
|
136
|
+
if (step.done)
|
|
137
|
+
return target;
|
|
138
|
+
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
139
|
+
if (!isRecord(step.value) || isRuntimeReference(step.value)) {
|
|
140
|
+
throw new InterpreterRuntimeError("new Map(...) expects [key, value] pairs as entry objects.", node).as("TypeError");
|
|
141
|
+
}
|
|
142
|
+
target.map.set(step.value[0], step.value[1]);
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
const constructSet = (runner, init, node) => {
|
|
148
|
+
const target = new Values.Set();
|
|
149
|
+
if (init === undefined || init === null)
|
|
150
|
+
return Effect.succeed(target);
|
|
151
|
+
return Effect.gen(function* () {
|
|
152
|
+
const cursor = yield* runner.syncIterator(init, node);
|
|
153
|
+
if (cursor === undefined) {
|
|
154
|
+
throw new InterpreterRuntimeError("new Set(...) expects a synchronous iterable or no argument.", node).as("TypeError");
|
|
155
|
+
}
|
|
156
|
+
while (true) {
|
|
157
|
+
const step = yield* cursor.next;
|
|
158
|
+
if (step.done)
|
|
159
|
+
return target;
|
|
160
|
+
target.set.add(step.value);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
export const mapGlobal = (runner) => new HostFunction({
|
|
165
|
+
name: "Map",
|
|
166
|
+
call: requiresNew("Map"),
|
|
167
|
+
construct: (args, node) => constructMap(runner, args[0], node),
|
|
168
|
+
instanceOf: (value) => value instanceof Values.Map,
|
|
169
|
+
members: { groupBy: groupBy(runner, "Map") },
|
|
170
|
+
});
|
|
171
|
+
export const setGlobal = (runner) => new HostFunction({
|
|
172
|
+
name: "Set",
|
|
173
|
+
call: requiresNew("Set"),
|
|
174
|
+
construct: (args, node) => constructSet(runner, args[0], node),
|
|
175
|
+
instanceOf: (value) => value instanceof Values.Set,
|
|
176
|
+
});
|
package/dist/stdlib/console.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { HostNamespace } from "../interpreter/host.js";
|
|
2
|
+
/** Captured console: every method appends one formatted line to `logs`. */
|
|
3
|
+
export declare const consoleGlobal: (logs: Array<string>) => HostNamespace;
|
package/dist/stdlib/console.js
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import { toData, toProgram } from "../data.js";
|
|
2
|
+
import { HostNamespace, sync } from "../interpreter/host.js";
|
|
2
3
|
import { containsOpaqueReference, containsRuntimeReference, isRuntimeReference } from "../interpreter/references.js";
|
|
3
4
|
import { Values } from "../values.js";
|
|
4
5
|
import { coerceToString } from "./value.js";
|
|
5
|
-
|
|
6
|
+
const consoleMethods = ["log", "info", "debug", "warn", "error", "dir", "table"];
|
|
7
|
+
/** Captured console: every method appends one formatted line to `logs`. */
|
|
8
|
+
export const consoleGlobal = (logs) => new HostNamespace("console", Object.fromEntries(consoleMethods.map((name) => [
|
|
9
|
+
name,
|
|
10
|
+
sync(`console.${name}`, (args) => {
|
|
11
|
+
logs.push(formatConsoleMessage(name, args));
|
|
12
|
+
return undefined;
|
|
13
|
+
}),
|
|
14
|
+
])));
|
|
6
15
|
const MAX_CONSOLE_DEPTH = 32;
|
|
7
|
-
|
|
16
|
+
const formatConsoleMessage = (name, args) => {
|
|
8
17
|
if (name === "dir")
|
|
9
18
|
return args.length === 0 ? "undefined" : formatConsoleArgument(args[0]);
|
|
10
19
|
if (name === "table")
|
package/dist/stdlib/date.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { HostFunction } from "../interpreter/host.js";
|
|
1
2
|
import { type AstNode } from "../interpreter/model.js";
|
|
3
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
2
4
|
import { Values } from "../values.js";
|
|
3
5
|
export declare const dateMethods: Set<string>;
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const invokeDateStatic: (name: string, args: Array<unknown>, node: AstNode) => number;
|
|
6
|
+
export declare const dateGlobal: <R>(runner: Runner<R>) => HostFunction<R>;
|
|
6
7
|
export declare const dateSetterArgumentCount: (name: string) => number | undefined;
|
|
7
8
|
export declare const invokeDateMethod: (value: Values.Date, name: string, args: Array<number>, node: AstNode, initialTime?: number) => unknown;
|
package/dist/stdlib/date.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { HostFunction, sync } from "../interpreter/host.js";
|
|
1
3
|
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
4
|
+
import { toPrimitive } from "../interpreter/runner.js";
|
|
2
5
|
import { Values } from "../values.js";
|
|
3
6
|
import { coerceToNumber, coerceToString } from "./value.js";
|
|
4
7
|
const dateSetterArguments = new Map([
|
|
@@ -45,19 +48,32 @@ export const dateMethods = new Set([
|
|
|
45
48
|
"getTimezoneOffset",
|
|
46
49
|
...dateSetterArguments.keys(),
|
|
47
50
|
]);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
throw new InterpreterRuntimeError(`Date.${name} is not available.`, node);
|
|
51
|
+
const constructDate = (runner, args, node) => {
|
|
52
|
+
if (args.length === 0)
|
|
53
|
+
return Effect.succeed(new Values.Date(Date.now()));
|
|
54
|
+
if (args.length === 1) {
|
|
55
|
+
const arg = args[0];
|
|
56
|
+
if (arg instanceof Values.Date)
|
|
57
|
+
return Effect.succeed(new Values.Date(arg.time));
|
|
58
|
+
return Effect.map(toPrimitive(runner, arg, "number", node), (value) => typeof value === "string"
|
|
59
|
+
? new Values.Date(Date.parse(value))
|
|
60
|
+
: new Values.Date(new Date(coerceToNumber(value)).getTime()));
|
|
59
61
|
}
|
|
62
|
+
const parts = args.map((arg) => coerceToNumber(arg));
|
|
63
|
+
return Effect.succeed(new Values.Date(new Date(...parts).getTime()));
|
|
60
64
|
};
|
|
65
|
+
export const dateGlobal = (runner) => new HostFunction({
|
|
66
|
+
name: "Date",
|
|
67
|
+
// ISO instead of the host's locale string: date strings are deterministic and must not leak the host timezone.
|
|
68
|
+
call: () => Effect.sync(() => new Date().toISOString()),
|
|
69
|
+
construct: (args, node) => constructDate(runner, args, node),
|
|
70
|
+
instanceOf: (value) => value instanceof Values.Date,
|
|
71
|
+
members: {
|
|
72
|
+
now: sync("Date.now", () => Date.now()),
|
|
73
|
+
parse: sync("Date.parse", (args) => Date.parse(coerceToString(args[0]))),
|
|
74
|
+
UTC: sync("Date.UTC", (args) => Date.UTC(...args.map((arg) => coerceToNumber(arg)))),
|
|
75
|
+
},
|
|
76
|
+
});
|
|
61
77
|
export const dateSetterArgumentCount = (name) => dateSetterArguments.get(name);
|
|
62
78
|
export const invokeDateMethod = (value, name, args, node, initialTime = value.time) => {
|
|
63
79
|
const hosted = new Date(initialTime);
|
package/dist/stdlib/json.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import
|
|
2
|
+
import { HostNamespace } from "../interpreter/host.js";
|
|
3
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
3
4
|
import { type AstNode } from "../interpreter/model.js";
|
|
4
|
-
export declare const
|
|
5
|
-
export
|
|
6
|
-
export declare const invokeJsonMethod: <R>(runner: CallbackRunner<R>, name: JsonMethodName, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
5
|
+
export declare const invokeJsonMethod: <R>(runner: Runner<R>, name: "parse" | "stringify", args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
6
|
+
export declare const jsonGlobal: <R>(runner: Runner<R>) => HostNamespace;
|
package/dist/stdlib/json.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import {
|
|
2
|
+
import { HostFunction, HostNamespace } from "../interpreter/host.js";
|
|
3
|
+
import { applyCollectionCallback } from "../interpreter/runner.js";
|
|
3
4
|
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
4
5
|
import { typeofValue } from "../interpreter/references.js";
|
|
5
6
|
import { fromData, toData, toProgram } from "../data.js";
|
|
6
7
|
import { Values } from "../values.js";
|
|
7
|
-
export const jsonStatics = new Set(["parse", "stringify"]);
|
|
8
8
|
export const invokeJsonMethod = (runner, name, args, node) => {
|
|
9
9
|
return name === "parse" ? parse(runner, args, node) : stringify(runner, args, node);
|
|
10
10
|
};
|
|
11
|
+
export const jsonGlobal = (runner) => new HostNamespace("JSON", {
|
|
12
|
+
parse: new HostFunction({ name: "JSON.parse", call: (args, node) => parse(runner, args, node) }),
|
|
13
|
+
stringify: new HostFunction({ name: "JSON.stringify", call: (args, node) => stringify(runner, args, node) }),
|
|
14
|
+
});
|
|
11
15
|
const parse = (runner, args, node) => {
|
|
12
16
|
const text = args[0];
|
|
13
17
|
if (typeof text !== "string")
|
package/dist/stdlib/math.d.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type
|
|
3
|
-
import { type AstNode } from "../interpreter/model.js";
|
|
1
|
+
import { HostNamespace } from "../interpreter/host.js";
|
|
2
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
4
3
|
declare global {
|
|
5
4
|
interface Math {
|
|
6
5
|
sumPrecise(values: Iterable<number>): number;
|
|
7
6
|
}
|
|
8
7
|
}
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const mathMethods: Set<string>;
|
|
11
|
-
export declare const invokeMathMethod: (name: string, args: Array<unknown>, node: AstNode) => number;
|
|
12
|
-
export declare const invokeMathSumPrecise: <R>(runner: SyncIteratorRunner<R>, source: unknown, node: AstNode) => Effect.Effect<number, unknown, R>;
|
|
8
|
+
export declare const mathGlobal: <R>(runner: Runner<R>) => HostNamespace;
|
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
1
|
import { type AstNode } from "../interpreter/model.js";
|
|
2
2
|
export declare const numberMethods: Set<string>;
|
|
3
|
-
export declare const numberConstants: Set<string>;
|
|
4
|
-
export declare const numberStatics: Set<string>;
|
|
5
3
|
export declare const invokeNumberMethod: (value: number, name: string, args: Array<unknown>, node: AstNode) => unknown;
|
|
6
|
-
export declare const
|
|
4
|
+
export declare const numberGlobal: import("../interpreter/host.js").HostFunction<never>;
|
package/dist/stdlib/number.js
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
2
1
|
import { toProgram } from "../data.js";
|
|
3
|
-
import {
|
|
2
|
+
import { sync } from "../interpreter/host.js";
|
|
3
|
+
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
4
|
+
import { coercion, coerceToString } from "./value.js";
|
|
4
5
|
export const numberMethods = new Set(["toFixed", "toPrecision", "toExponential", "toString", "valueOf"]);
|
|
5
|
-
export const numberConstants = new Set([
|
|
6
|
-
"MAX_SAFE_INTEGER",
|
|
7
|
-
"MIN_SAFE_INTEGER",
|
|
8
|
-
"MAX_VALUE",
|
|
9
|
-
"MIN_VALUE",
|
|
10
|
-
"EPSILON",
|
|
11
|
-
"NaN",
|
|
12
|
-
"POSITIVE_INFINITY",
|
|
13
|
-
"NEGATIVE_INFINITY",
|
|
14
|
-
]);
|
|
15
|
-
export const numberStatics = new Set(["isInteger", "isFinite", "isNaN", "isSafeInteger", "parseInt", "parseFloat"]);
|
|
16
6
|
export const invokeNumberMethod = (value, name, args, node) => {
|
|
17
7
|
const optNum = (index) => {
|
|
18
8
|
const arg = args[index];
|
|
@@ -51,27 +41,29 @@ export const invokeNumberMethod = (value, name, args, node) => {
|
|
|
51
41
|
}
|
|
52
42
|
return toProgram(result, `Number.${name} result`);
|
|
53
43
|
};
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return Number.isInteger(value);
|
|
59
|
-
case "isFinite":
|
|
60
|
-
return Number.isFinite(value);
|
|
61
|
-
case "isNaN":
|
|
62
|
-
return Number.isNaN(value);
|
|
63
|
-
case "isSafeInteger":
|
|
64
|
-
return Number.isSafeInteger(value);
|
|
65
|
-
case "parseInt": {
|
|
66
|
-
const radix = args[1];
|
|
67
|
-
if (radix !== undefined && typeof radix !== "number") {
|
|
68
|
-
throw new InterpreterRuntimeError("Number.parseInt expects a numeric radix.", node);
|
|
69
|
-
}
|
|
70
|
-
return parseInt(coerceToString(value), radix);
|
|
71
|
-
}
|
|
72
|
-
case "parseFloat":
|
|
73
|
-
return parseFloat(coerceToString(value));
|
|
74
|
-
default:
|
|
75
|
-
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);
|
|
76
48
|
}
|
|
77
|
-
|
|
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>;
|