@opencode/codemode 0.0.0-dev-19530 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data.d.ts +5 -6
- package/dist/data.js +44 -47
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/errors.d.ts +3 -5
- package/dist/interpreter/errors.js +22 -51
- package/dist/interpreter/execute.js +3 -5
- package/dist/interpreter/globals.js +47 -69
- package/dist/interpreter/host.d.ts +41 -0
- package/dist/interpreter/host.js +44 -0
- package/dist/interpreter/methods.d.ts +4 -0
- package/dist/interpreter/methods.js +837 -0
- package/dist/interpreter/model.d.ts +36 -13
- package/dist/interpreter/model.js +45 -15
- package/dist/interpreter/objects.d.ts +13 -106
- package/dist/interpreter/objects.js +65 -192
- package/dist/interpreter/promises.d.ts +13 -12
- package/dist/interpreter/promises.js +54 -59
- package/dist/interpreter/references.d.ts +0 -1
- package/dist/interpreter/references.js +33 -20
- package/dist/interpreter/runner.d.ts +11 -15
- package/dist/interpreter/runner.js +21 -21
- package/dist/interpreter/runtime.d.ts +3 -3
- package/dist/interpreter/runtime.js +327 -165
- package/dist/interpreter/scope.js +6 -6
- package/dist/stdlib/array.d.ts +2 -4
- package/dist/stdlib/array.js +32 -424
- package/dist/stdlib/collections.d.ts +7 -3
- package/dist/stdlib/collections.js +119 -291
- package/dist/stdlib/console.d.ts +2 -3
- package/dist/stdlib/console.js +30 -35
- package/dist/stdlib/date.d.ts +7 -1
- package/dist/stdlib/date.js +188 -93
- package/dist/stdlib/json.d.ts +2 -2
- package/dist/stdlib/json.js +27 -27
- package/dist/stdlib/math.d.ts +2 -2
- package/dist/stdlib/math.js +76 -96
- package/dist/stdlib/number.d.ts +4 -3
- package/dist/stdlib/number.js +60 -95
- package/dist/stdlib/object.d.ts +4 -4
- package/dist/stdlib/object.js +54 -128
- package/dist/stdlib/regexp.d.ts +8 -6
- package/dist/stdlib/regexp.js +68 -76
- package/dist/stdlib/string.d.ts +2 -2
- package/dist/stdlib/string.js +50 -213
- package/dist/stdlib/url.d.ts +13 -5
- package/dist/stdlib/url.js +102 -202
- package/dist/stdlib/value.d.ts +9 -5
- package/dist/stdlib/value.js +38 -16
- package/dist/stdlib/web.d.ts +4 -4
- package/dist/stdlib/web.js +10 -12
- package/dist/tool-runtime.d.ts +1 -2
- package/dist/tool-runtime.js +2 -2
- package/dist/values.d.ts +37 -0
- package/dist/values.js +56 -0
- package/package.json +1 -1
- package/dist/interpreter/generators.d.ts +0 -4
- package/dist/interpreter/generators.js +0 -25
- package/dist/interpreter/intrinsics.d.ts +0 -13
- package/dist/interpreter/intrinsics.js +0 -82
- package/dist/interpreter/native.d.ts +0 -19
- package/dist/interpreter/native.js +0 -40
package/dist/stdlib/number.js
CHANGED
|
@@ -1,14 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { toProgram } from "../data.js";
|
|
2
|
+
import { sync } from "../interpreter/host.js";
|
|
3
|
+
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
3
4
|
import { coercion, coerceToString } from "./value.js";
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
export const numberMethods = new Set(["toFixed", "toPrecision", "toExponential", "toString", "valueOf"]);
|
|
6
|
+
export const invokeNumberMethod = (value, name, args, node) => {
|
|
7
|
+
const optNum = (index) => {
|
|
8
|
+
const arg = args[index];
|
|
9
|
+
if (arg === undefined)
|
|
10
|
+
return undefined;
|
|
11
|
+
if (typeof arg !== "number")
|
|
12
|
+
throw new InterpreterRuntimeError(`Number.${name} expects a number argument.`, node);
|
|
13
|
+
return arg;
|
|
14
|
+
};
|
|
15
|
+
let result;
|
|
16
|
+
switch (name) {
|
|
17
|
+
case "toFixed":
|
|
18
|
+
result = value.toFixed(optNum(0));
|
|
19
|
+
break;
|
|
20
|
+
case "toExponential":
|
|
21
|
+
result = value.toExponential(optNum(0));
|
|
22
|
+
break;
|
|
23
|
+
case "toPrecision": {
|
|
24
|
+
const digits = optNum(0);
|
|
25
|
+
result = digits === undefined ? value.toString() : value.toPrecision(digits);
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
case "toString": {
|
|
29
|
+
const radix = optNum(0);
|
|
30
|
+
if (radix !== undefined && (radix < 2 || radix > 36)) {
|
|
31
|
+
throw new InterpreterRuntimeError("Number.toString radix must be between 2 and 36.", node);
|
|
32
|
+
}
|
|
33
|
+
result = value.toString(radix);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
case "valueOf":
|
|
37
|
+
result = value;
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
throw new InterpreterRuntimeError(`Number method '${name}' is not available.`, node);
|
|
41
|
+
}
|
|
42
|
+
return toProgram(result, `Number.${name} result`);
|
|
43
|
+
};
|
|
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);
|
|
48
|
+
}
|
|
49
|
+
return parseInt(coerceToString(args[0]), radix);
|
|
50
|
+
});
|
|
51
|
+
export const numberGlobal = coercion("Number", {
|
|
52
|
+
instanceOf: () => false,
|
|
53
|
+
members: {
|
|
12
54
|
MAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER,
|
|
13
55
|
MIN_SAFE_INTEGER: Number.MIN_SAFE_INTEGER,
|
|
14
56
|
MAX_VALUE: Number.MAX_VALUE,
|
|
@@ -17,88 +59,11 @@ export const numberGlobal = (runner) => {
|
|
|
17
59
|
NaN: Number.NaN,
|
|
18
60
|
POSITIVE_INFINITY: Number.POSITIVE_INFINITY,
|
|
19
61
|
NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
2,
|
|
29
|
-
(_, args, node) => {
|
|
30
|
-
const radix = args[1];
|
|
31
|
-
if (radix !== undefined && typeof radix !== "number") {
|
|
32
|
-
throw new InterpreterRuntimeError("Number.parseInt expects a numeric radix.", node);
|
|
33
|
-
}
|
|
34
|
-
return parseInt(coerceToString(args[0]), radix);
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
["parseFloat", 1, (_, args) => parseFloat(coerceToString(args[0]))],
|
|
38
|
-
]);
|
|
39
|
-
const self = (thisValue, name, node) => {
|
|
40
|
-
if (typeof thisValue === "number")
|
|
41
|
-
return thisValue;
|
|
42
|
-
throw new InterpreterRuntimeError(`Number.prototype.${name} requires that 'this' be a Number.`, node);
|
|
43
|
-
};
|
|
44
|
-
const optNum = (name, arg, node) => {
|
|
45
|
-
if (arg === undefined)
|
|
46
|
-
return undefined;
|
|
47
|
-
if (typeof arg !== "number")
|
|
48
|
-
throw new InterpreterRuntimeError(`Number.${name} expects a number argument.`, node);
|
|
49
|
-
return arg;
|
|
50
|
-
};
|
|
51
|
-
methods(protos, protos.Number, [
|
|
52
|
-
[
|
|
53
|
-
"toFixed",
|
|
54
|
-
1,
|
|
55
|
-
(thisValue, args, node) => self(thisValue, "toFixed", node).toFixed(optNum("toFixed", args[0], node)),
|
|
56
|
-
],
|
|
57
|
-
[
|
|
58
|
-
"toExponential",
|
|
59
|
-
1,
|
|
60
|
-
(thisValue, args, node) => self(thisValue, "toExponential", node).toExponential(optNum("toExponential", args[0], node)),
|
|
61
|
-
],
|
|
62
|
-
[
|
|
63
|
-
"toPrecision",
|
|
64
|
-
1,
|
|
65
|
-
(thisValue, args, node) => {
|
|
66
|
-
const value = self(thisValue, "toPrecision", node);
|
|
67
|
-
const digits = optNum("toPrecision", args[0], node);
|
|
68
|
-
return digits === undefined ? value.toString() : value.toPrecision(digits);
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
[
|
|
72
|
-
"toString",
|
|
73
|
-
1,
|
|
74
|
-
(thisValue, args, node) => {
|
|
75
|
-
const value = self(thisValue, "toString", node);
|
|
76
|
-
const radix = optNum("toString", args[0], node);
|
|
77
|
-
if (radix !== undefined && (radix < 2 || radix > 36)) {
|
|
78
|
-
throw rangeError("Number.toString radix must be between 2 and 36.", node);
|
|
79
|
-
}
|
|
80
|
-
return value.toString(radix);
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
["valueOf", 0, (thisValue, _, node) => self(thisValue, "valueOf", node)],
|
|
84
|
-
]);
|
|
85
|
-
return number;
|
|
86
|
-
};
|
|
87
|
-
export const booleanGlobal = (runner) => {
|
|
88
|
-
const protos = runner.prototypes;
|
|
89
|
-
const boolean = constructor(protos, protos.Boolean, {
|
|
90
|
-
name: "Boolean",
|
|
91
|
-
length: 1,
|
|
92
|
-
call: coercion(runner, "Boolean").call,
|
|
93
|
-
});
|
|
94
|
-
const self = (thisValue, name, node) => {
|
|
95
|
-
if (typeof thisValue === "boolean")
|
|
96
|
-
return thisValue;
|
|
97
|
-
throw new InterpreterRuntimeError(`Boolean.prototype.${name} requires that 'this' be a Boolean.`, node);
|
|
98
|
-
};
|
|
99
|
-
methods(protos, protos.Boolean, [
|
|
100
|
-
["toString", 0, (thisValue, _, node) => String(self(thisValue, "toString", node))],
|
|
101
|
-
["valueOf", 0, (thisValue, _, node) => self(thisValue, "valueOf", node)],
|
|
102
|
-
]);
|
|
103
|
-
return boolean;
|
|
104
|
-
};
|
|
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,7 @@
|
|
|
1
|
+
import { HostFunction } from "../interpreter/host.js";
|
|
1
2
|
import { type AstNode } from "../interpreter/model.js";
|
|
2
3
|
import { ProgramObject } from "../interpreter/objects.js";
|
|
3
4
|
import { type Runner } from "../interpreter/runner.js";
|
|
4
|
-
export declare const enumerableSource:
|
|
5
|
-
export declare const objectAssign:
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const objectGlobal: <R>(runner: Runner<R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>) => import("../interpreter/objects.js").NativeFunction<R>;
|
|
5
|
+
export declare const enumerableSource: (label: string, value: unknown, node: AstNode) => ProgramObject;
|
|
6
|
+
export declare const objectAssign: (args: Array<unknown>, node: AstNode) => unknown;
|
|
7
|
+
export declare const objectGlobal: <R>(runner: Runner<R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>) => HostFunction<R>;
|
package/dist/stdlib/object.js
CHANGED
|
@@ -1,58 +1,59 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { toProgram } from "../data.js";
|
|
3
|
-
import {
|
|
4
|
-
import { AsyncIteratorSymbol, InterpreterRuntimeError, IteratorSymbol
|
|
5
|
-
import {
|
|
6
|
-
import { containsOpaqueReference, describeValue, rejectCircularInsertion } from "../interpreter/references.js";
|
|
3
|
+
import { HostFunction, sync, syncCall } from "../interpreter/host.js";
|
|
4
|
+
import { AsyncIteratorSymbol, InterpreterRuntimeError, IteratorSymbol } from "../interpreter/model.js";
|
|
5
|
+
import { getOwn, hasOwn, ownEntries, ownKeys, ProgramArray, ProgramObject, set } from "../interpreter/objects.js";
|
|
6
|
+
import { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue, } from "../interpreter/references.js";
|
|
7
7
|
import { preserveConsumerError } from "../interpreter/runner.js";
|
|
8
8
|
import { ToolReference } from "../tool-runtime.js";
|
|
9
|
+
import { Values } from "../values.js";
|
|
9
10
|
import { groupBy } from "./collections.js";
|
|
10
11
|
import { coerceToString } from "./value.js";
|
|
11
12
|
// ToObject for enumeration.
|
|
12
|
-
export const enumerableSource = (
|
|
13
|
+
export const enumerableSource = (label, value, node) => {
|
|
13
14
|
if (value === null || value === undefined) {
|
|
14
|
-
throw new InterpreterRuntimeError(`${label} cannot convert ${describeValue(value)} to an object.`, node);
|
|
15
|
+
throw new InterpreterRuntimeError(`${label} cannot convert ${describeValue(value)} to an object.`, node).as("TypeError");
|
|
15
16
|
}
|
|
16
|
-
if (value instanceof
|
|
17
|
+
if (value instanceof Values.Promise) {
|
|
17
18
|
throw new InterpreterRuntimeError(`${label} received an un-awaited Promise; await it before inspecting the result.`, node, "InvalidDataValue");
|
|
18
19
|
}
|
|
19
20
|
if (value instanceof ToolReference) {
|
|
20
21
|
throw new InterpreterRuntimeError(`${label} cannot read tool references: they are not plain data. Use Object.keys(tools) for names, or search({ query }) for signatures.`, node, "InvalidDataValue");
|
|
21
22
|
}
|
|
22
23
|
if (typeof value === "string")
|
|
23
|
-
return new ProgramArray(
|
|
24
|
+
return new ProgramArray([...value]);
|
|
24
25
|
if (value instanceof ProgramObject)
|
|
25
26
|
return value;
|
|
26
|
-
return new ProgramObject(
|
|
27
|
+
return new ProgramObject();
|
|
27
28
|
};
|
|
28
|
-
export const objectAssign = (
|
|
29
|
+
export const objectAssign = (args, node) => {
|
|
29
30
|
const target = args[0];
|
|
30
31
|
// JS would box a primitive target; wrappers and primitives cannot hold fields here.
|
|
31
32
|
if (!(target instanceof ProgramObject)) {
|
|
32
|
-
throw new InterpreterRuntimeError(`Object.assign expects a data object or array target, received ${describeValue(target)}.`, node);
|
|
33
|
+
throw new InterpreterRuntimeError(`Object.assign expects a data object or array target, received ${describeValue(target)}.`, node).as("TypeError");
|
|
33
34
|
}
|
|
34
35
|
const seen = new Set();
|
|
35
36
|
for (const source of args.slice(1)) {
|
|
36
37
|
if (source === null || source === undefined)
|
|
37
38
|
continue;
|
|
38
|
-
const from = enumerableSource(
|
|
39
|
-
for (const key of
|
|
39
|
+
const from = enumerableSource("Object.assign(...)", source, node);
|
|
40
|
+
for (const key of ownKeys(from)) {
|
|
41
|
+
if (typeof key === "symbol" && key !== AsyncIteratorSymbol && key !== IteratorSymbol)
|
|
42
|
+
continue;
|
|
40
43
|
rejectCircularInsertion(target, getOwn(from, key), "Object.assign result", node, seen);
|
|
41
44
|
if (!set(target, key, getOwn(from, key))) {
|
|
42
|
-
|
|
43
|
-
throw rangeError("Invalid array length", node);
|
|
44
|
-
throw new InterpreterRuntimeError(`Cannot assign to read only property '${String(key)}'.`, node);
|
|
45
|
+
throw new InterpreterRuntimeError("Invalid array length", node).as("RangeError");
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
return target;
|
|
49
50
|
};
|
|
50
51
|
const objectFromEntries = (runner, source, node) => {
|
|
51
|
-
const out = new ProgramObject(
|
|
52
|
+
const out = new ProgramObject();
|
|
52
53
|
return Effect.gen(function* () {
|
|
53
54
|
const cursor = yield* runner.syncIterator(source, node);
|
|
54
55
|
if (cursor === undefined) {
|
|
55
|
-
throw new InterpreterRuntimeError("Object.fromEntries expects a synchronous iterable of entries.", node);
|
|
56
|
+
throw new InterpreterRuntimeError("Object.fromEntries expects a synchronous iterable of entries.", node).as("TypeError");
|
|
56
57
|
}
|
|
57
58
|
while (true) {
|
|
58
59
|
const step = yield* cursor.next;
|
|
@@ -60,121 +61,46 @@ const objectFromEntries = (runner, source, node) => {
|
|
|
60
61
|
return out;
|
|
61
62
|
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
62
63
|
if (!(step.value instanceof ProgramObject) || containsOpaqueReference(step.value)) {
|
|
63
|
-
throw new InterpreterRuntimeError("Object.fromEntries expects [key, value] entry objects.", node);
|
|
64
|
+
throw new InterpreterRuntimeError("Object.fromEntries expects [key, value] entry objects.", node).as("TypeError");
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
+
set(out, coerceToString(getOwn(step.value, 0)), getOwn(step.value, 1));
|
|
66
67
|
}));
|
|
67
68
|
}
|
|
68
69
|
});
|
|
69
70
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (value instanceof Callable)
|
|
78
|
-
return "Function";
|
|
79
|
-
if (value instanceof ProgramError)
|
|
80
|
-
return "Error";
|
|
81
|
-
if (value instanceof ProgramDate)
|
|
82
|
-
return "Date";
|
|
83
|
-
if (value instanceof ProgramRegExp)
|
|
84
|
-
return "RegExp";
|
|
85
|
-
if (typeof value === "string")
|
|
86
|
-
return "String";
|
|
87
|
-
if (typeof value === "number")
|
|
88
|
-
return "Number";
|
|
89
|
-
if (typeof value === "boolean")
|
|
90
|
-
return "Boolean";
|
|
91
|
-
return "Object";
|
|
71
|
+
const constructObject = (args, node) => {
|
|
72
|
+
const first = args[0];
|
|
73
|
+
if (first === null || first === undefined)
|
|
74
|
+
return new ProgramObject();
|
|
75
|
+
if (typeof first === "object")
|
|
76
|
+
return first;
|
|
77
|
+
throw new InterpreterRuntimeError(`Object(${typeof first}) wrapper objects are not supported; use the primitive value directly.`, node);
|
|
92
78
|
};
|
|
93
|
-
const propertyKey = (value) => value === AsyncIteratorSymbol || value === IteratorSymbol ? value : coerceToString(value);
|
|
94
79
|
// Object constructs identically with or without new, like JS. Only `keys` copies its result into the
|
|
95
80
|
// program; `values`, `entries`, `assign`, and `fromEntries` hand back the program's own values.
|
|
96
|
-
export const objectGlobal = (runner, toolKeys) => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
1,
|
|
123
|
-
(_, args, node) => new ProgramArray(protos.Array, entries(enumerableSource(runner, "Object.values(...)", args[0], node)).map((entry) => entry[1])),
|
|
124
|
-
],
|
|
125
|
-
[
|
|
126
|
-
"entries",
|
|
127
|
-
1,
|
|
128
|
-
(_, args, node) => new ProgramArray(protos.Array, entries(enumerableSource(runner, "Object.entries(...)", args[0], node)).map((entry) => new ProgramArray(protos.Array, entry))),
|
|
129
|
-
],
|
|
130
|
-
[
|
|
131
|
-
"hasOwn",
|
|
132
|
-
2,
|
|
133
|
-
(_, args, node) => hasOwn(enumerableSource(runner, "Object.hasOwn(...)", args[0], node), propertyKey(args[1])),
|
|
134
|
-
],
|
|
135
|
-
[
|
|
136
|
-
"is",
|
|
137
|
-
2,
|
|
138
|
-
(_, args, node) => {
|
|
139
|
-
if (containsOpaqueReference(args[0]) || containsOpaqueReference(args[1])) {
|
|
140
|
-
throw new InterpreterRuntimeError("Object.is requires data values.", node, "InvalidDataValue");
|
|
141
|
-
}
|
|
142
|
-
return Object.is(args[0], args[1]);
|
|
143
|
-
},
|
|
144
|
-
],
|
|
145
|
-
["assign", 2, (_, args, node) => objectAssign(runner, args, node)],
|
|
146
|
-
["fromEntries", 1, (_, args, node) => objectFromEntries(runner, args[0], node)],
|
|
147
|
-
]);
|
|
148
|
-
define(object, "groupBy", groupBy(runner, "Object"), hidden);
|
|
149
|
-
methods(protos, protos.Object, [
|
|
150
|
-
[
|
|
151
|
-
"hasOwnProperty",
|
|
152
|
-
1,
|
|
153
|
-
(thisValue, args, node) => hasOwn(receiver(ProgramObject, thisValue, "Object.prototype.hasOwnProperty", node), propertyKey(args[0])),
|
|
154
|
-
],
|
|
155
|
-
[
|
|
156
|
-
"isPrototypeOf",
|
|
157
|
-
1,
|
|
158
|
-
(thisValue, args, node) => hasPrototype(args[0], receiver(ProgramObject, thisValue, "Object.prototype.isPrototypeOf", node)),
|
|
159
|
-
],
|
|
160
|
-
[
|
|
161
|
-
"propertyIsEnumerable",
|
|
162
|
-
1,
|
|
163
|
-
(thisValue, args, node) => own(receiver(ProgramObject, thisValue, "Object.prototype.propertyIsEnumerable", node), propertyKey(args[0]))
|
|
164
|
-
?.enumerable === true,
|
|
165
|
-
],
|
|
166
|
-
["toString", 0, (thisValue) => `[object ${classTag(thisValue)}]`],
|
|
167
|
-
["toLocaleString", 0, (thisValue) => `[object ${classTag(thisValue)}]`],
|
|
168
|
-
[
|
|
169
|
-
"valueOf",
|
|
170
|
-
0,
|
|
171
|
-
(thisValue, _, node) => {
|
|
172
|
-
if (thisValue === null || thisValue === undefined) {
|
|
173
|
-
throw new InterpreterRuntimeError("Object.prototype.valueOf called on null or undefined.", node);
|
|
174
|
-
}
|
|
175
|
-
return thisValue;
|
|
176
|
-
},
|
|
177
|
-
],
|
|
178
|
-
]);
|
|
179
|
-
return object;
|
|
180
|
-
};
|
|
81
|
+
export const objectGlobal = (runner, toolKeys) => new HostFunction({
|
|
82
|
+
name: "Object",
|
|
83
|
+
call: syncCall(constructObject),
|
|
84
|
+
construct: syncCall(constructObject),
|
|
85
|
+
instanceOf: (value) => value !== null && (typeof value === "object" || typeofValue(value) === "function"),
|
|
86
|
+
members: {
|
|
87
|
+
keys: sync("Object.keys", (args, node) => toProgram(args[0] instanceof ToolReference
|
|
88
|
+
? [...toolKeys(args[0].path)]
|
|
89
|
+
: ownKeys(enumerableSource("Object.keys(...)", args[0], node)).filter((key) => typeof key === "string"), "Object.keys result")),
|
|
90
|
+
values: sync("Object.values", (args, node) => new ProgramArray(ownEntries(enumerableSource("Object.values(...)", args[0], node)).map((entry) => entry[1]))),
|
|
91
|
+
entries: sync("Object.entries", (args, node) => new ProgramArray(ownEntries(enumerableSource("Object.entries(...)", args[0], node)).map((entry) => new ProgramArray(entry)))),
|
|
92
|
+
hasOwn: sync("Object.hasOwn", (args, node) => hasOwn(enumerableSource("Object.hasOwn(...)", args[0], node), args[1] === AsyncIteratorSymbol || args[1] === IteratorSymbol ? args[1] : String(args[1]))),
|
|
93
|
+
is: sync("Object.is", (args, node) => {
|
|
94
|
+
if (containsOpaqueReference(args[0]) || containsOpaqueReference(args[1])) {
|
|
95
|
+
throw new InterpreterRuntimeError("Object.is requires data values.", node, "InvalidDataValue");
|
|
96
|
+
}
|
|
97
|
+
return Object.is(args[0], args[1]);
|
|
98
|
+
}),
|
|
99
|
+
assign: sync("Object.assign", objectAssign),
|
|
100
|
+
fromEntries: new HostFunction({
|
|
101
|
+
name: "Object.fromEntries",
|
|
102
|
+
call: (args, node) => Effect.suspend(() => objectFromEntries(runner, args[0], node)),
|
|
103
|
+
}),
|
|
104
|
+
groupBy: groupBy(runner, "Object"),
|
|
105
|
+
},
|
|
106
|
+
});
|
package/dist/stdlib/regexp.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { Prototypes } from "../interpreter/intrinsics.js";
|
|
2
1
|
import { type AstNode } from "../interpreter/model.js";
|
|
3
|
-
import { ProgramArray
|
|
4
|
-
import
|
|
2
|
+
import { ProgramArray } from "../interpreter/objects.js";
|
|
3
|
+
import { Values } from "../values.js";
|
|
4
|
+
export declare const regexpMethods: Set<string>;
|
|
5
|
+
export declare const regexpProperties: Set<string>;
|
|
5
6
|
export declare const toHostRegex: (arg: unknown, method: string, node: AstNode, extraFlags?: string) => RegExp;
|
|
6
|
-
export declare const matchToValue: (
|
|
7
|
-
export declare const constructRegExp: (
|
|
8
|
-
export declare const regexpGlobal:
|
|
7
|
+
export declare const matchToValue: (match: RegExpMatchArray) => ProgramArray;
|
|
8
|
+
export declare const constructRegExp: (args: Array<unknown>, node: AstNode) => Values.RegExp;
|
|
9
|
+
export declare const regexpGlobal: import("../interpreter/host.js").HostFunction<never>;
|
|
10
|
+
export declare const invokeRegExpMethod: (value: Values.RegExp, name: string, args: Array<unknown>, node: AstNode) => unknown;
|
package/dist/stdlib/regexp.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { sync, syncCall } from "../interpreter/host.js";
|
|
2
|
+
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
3
|
+
import { ProgramArray, record, set } from "../interpreter/objects.js";
|
|
4
|
+
import { Values } from "../values.js";
|
|
5
5
|
import { coerceToNumber, coerceToString } from "./value.js";
|
|
6
|
-
const
|
|
6
|
+
export const regexpMethods = new Set(["test", "exec", "toString"]);
|
|
7
|
+
export const regexpProperties = new Set([
|
|
8
|
+
"source",
|
|
9
|
+
"flags",
|
|
10
|
+
"lastIndex",
|
|
7
11
|
"hasIndices",
|
|
8
12
|
"global",
|
|
9
13
|
"ignoreCase",
|
|
@@ -12,53 +16,91 @@ const flagProperties = [
|
|
|
12
16
|
"unicode",
|
|
13
17
|
"unicodeSets",
|
|
14
18
|
"dotAll",
|
|
15
|
-
];
|
|
19
|
+
]);
|
|
16
20
|
const regexFailureReason = (error) => (error instanceof Error ? error.message : String(error)).replace(/^Invalid regular expression:\s*/i, "");
|
|
17
21
|
const escapeRegexHint = 'To match special characters like ( ) [ ] { } + * ? . literally, escape them with a backslash (e.g. "\\\\(") or test for them with String.includes instead.';
|
|
18
22
|
export const toHostRegex = (arg, method, node, extraFlags = "") => {
|
|
19
23
|
// Native parity: an undefined pattern behaves as an empty pattern.
|
|
20
24
|
if (arg === undefined)
|
|
21
25
|
return new RegExp("", extraFlags);
|
|
22
|
-
if (arg instanceof
|
|
26
|
+
if (arg instanceof Values.RegExp)
|
|
23
27
|
return arg.regex;
|
|
24
28
|
if (typeof arg === "string") {
|
|
25
29
|
try {
|
|
26
30
|
return new RegExp(arg, extraFlags);
|
|
27
31
|
}
|
|
28
32
|
catch (error) {
|
|
29
|
-
throw
|
|
33
|
+
throw new InterpreterRuntimeError(`String.${method} received the string ${JSON.stringify(arg)}, which is not a valid regular expression pattern (${regexFailureReason(error)}). ${escapeRegexHint}`, node).as("SyntaxError");
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
36
|
throw new InterpreterRuntimeError(`String.${method} expects a regular expression (a /pattern/flags literal or new RegExp(...)) or a string pattern, not ${arg === null ? "null" : typeof arg}.`, node);
|
|
33
37
|
};
|
|
34
|
-
export const matchToValue = (
|
|
35
|
-
const result = new ProgramArray(
|
|
38
|
+
export const matchToValue = (match) => {
|
|
39
|
+
const result = new ProgramArray(Array.from(match, (group) => group));
|
|
36
40
|
if (match.index !== undefined)
|
|
37
|
-
|
|
41
|
+
set(result, "index", match.index);
|
|
38
42
|
if (match.input !== undefined)
|
|
39
|
-
|
|
43
|
+
set(result, "input", match.input);
|
|
40
44
|
if (match.groups)
|
|
41
|
-
|
|
45
|
+
set(result, "groups", record(match.groups));
|
|
42
46
|
if (match.indices)
|
|
43
|
-
|
|
47
|
+
set(result, "indices", indicesToValue(match.indices));
|
|
44
48
|
return result;
|
|
45
49
|
};
|
|
46
|
-
export const constructRegExp = (
|
|
50
|
+
export const constructRegExp = (args, node) => {
|
|
47
51
|
const first = args[0];
|
|
48
|
-
const pattern = first instanceof
|
|
52
|
+
const pattern = first instanceof Values.RegExp ? first.regex.source : first === undefined ? "" : coerceToString(first);
|
|
49
53
|
const flagsArg = args[1];
|
|
50
54
|
if (flagsArg !== undefined && typeof flagsArg !== "string") {
|
|
51
|
-
throw
|
|
55
|
+
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");
|
|
52
56
|
}
|
|
53
|
-
const flags = flagsArg ?? (first instanceof
|
|
57
|
+
const flags = flagsArg ?? (first instanceof Values.RegExp ? first.regex.flags : "");
|
|
54
58
|
try {
|
|
55
|
-
return new
|
|
59
|
+
return new Values.RegExp(pattern, flags);
|
|
56
60
|
}
|
|
57
61
|
catch (error) {
|
|
58
62
|
const reason = regexFailureReason(error);
|
|
59
|
-
throw
|
|
63
|
+
throw new InterpreterRuntimeError(/flag/i.test(reason)
|
|
60
64
|
? `new RegExp(...) received invalid flags ${JSON.stringify(flags)} (${reason}). Valid flags are d, g, i, m, s, u, v, and y.`
|
|
61
|
-
: `new RegExp(...) received ${JSON.stringify(pattern)}, which is not a valid regular expression pattern (${reason}). ${escapeRegexHint}`, node);
|
|
65
|
+
: `new RegExp(...) received ${JSON.stringify(pattern)}, which is not a valid regular expression pattern (${reason}). ${escapeRegexHint}`, node).as("SyntaxError");
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
// RegExp constructs identically with or without new, like JS.
|
|
69
|
+
export const regexpGlobal = sync("RegExp", constructRegExp, {
|
|
70
|
+
construct: syncCall(constructRegExp),
|
|
71
|
+
instanceOf: (value) => value instanceof Values.RegExp,
|
|
72
|
+
members: {
|
|
73
|
+
escape: sync("RegExp.escape", (args, node) => {
|
|
74
|
+
if (typeof args[0] !== "string") {
|
|
75
|
+
throw new InterpreterRuntimeError("RegExp.escape expects a string.", node).as("TypeError");
|
|
76
|
+
}
|
|
77
|
+
return RegExp.escape(args[0]);
|
|
78
|
+
}),
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
export const invokeRegExpMethod = (value, name, args, node) => {
|
|
82
|
+
switch (name) {
|
|
83
|
+
case "test":
|
|
84
|
+
case "exec": {
|
|
85
|
+
const input = coerceToString(args[0]);
|
|
86
|
+
const lastIndex = value.lastIndex;
|
|
87
|
+
const stateful = value.regex.global || value.regex.sticky;
|
|
88
|
+
value.regex.lastIndex = toLength(lastIndex);
|
|
89
|
+
if (name === "test") {
|
|
90
|
+
const matched = value.regex.test(input);
|
|
91
|
+
if (!stateful)
|
|
92
|
+
value.lastIndex = lastIndex;
|
|
93
|
+
return matched;
|
|
94
|
+
}
|
|
95
|
+
const matched = value.regex.exec(input);
|
|
96
|
+
if (!stateful)
|
|
97
|
+
value.lastIndex = lastIndex;
|
|
98
|
+
return matched === null ? null : matchToValue(matched);
|
|
99
|
+
}
|
|
100
|
+
case "toString":
|
|
101
|
+
return coerceToString(value);
|
|
102
|
+
default:
|
|
103
|
+
throw new InterpreterRuntimeError(`RegExp method '${name}' is not available.`, node);
|
|
62
104
|
}
|
|
63
105
|
};
|
|
64
106
|
const toLength = (value) => {
|
|
@@ -67,62 +109,12 @@ const toLength = (value) => {
|
|
|
67
109
|
return 0;
|
|
68
110
|
return Math.min(Math.floor(number), Number.MAX_SAFE_INTEGER);
|
|
69
111
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
const proto = protos.RegExp;
|
|
74
|
-
const regexp = constructor(protos, proto, {
|
|
75
|
-
name: "RegExp",
|
|
76
|
-
length: 2,
|
|
77
|
-
call: (_, args, node) => Effect.sync(() => constructRegExp(protos, args, node)),
|
|
78
|
-
construct: (args, newTarget, node) => Effect.sync(() => constructRegExp(protos, args, node, prototypeFrom(newTarget, proto))),
|
|
79
|
-
});
|
|
80
|
-
methods(protos, regexp, [
|
|
81
|
-
[
|
|
82
|
-
"escape",
|
|
83
|
-
1,
|
|
84
|
-
(_, args, node) => {
|
|
85
|
-
if (typeof args[0] !== "string")
|
|
86
|
-
throw new InterpreterRuntimeError("RegExp.escape expects a string.", node);
|
|
87
|
-
return RegExp.escape(args[0]);
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
]);
|
|
91
|
-
const self = (thisValue, name, node) => receiver(ProgramRegExp, thisValue, `RegExp.prototype.${name}`, node);
|
|
92
|
-
defineAccessor(proto, "source", (thisValue) => self(thisValue, "source").regex.source);
|
|
93
|
-
defineAccessor(proto, "flags", (thisValue) => self(thisValue, "flags").regex.flags);
|
|
94
|
-
for (const name of flagProperties)
|
|
95
|
-
defineAccessor(proto, name, (thisValue) => self(thisValue, name).regex[name]);
|
|
96
|
-
// exec/test run the host regex from the program-visible lastIndex and write it back only when g or y is set.
|
|
97
|
-
const run = (name) => [
|
|
98
|
-
name,
|
|
99
|
-
1,
|
|
100
|
-
(thisValue, args, node) => {
|
|
101
|
-
const value = self(thisValue, name, node);
|
|
102
|
-
const input = coerceToString(args[0]);
|
|
103
|
-
const stateful = value.regex.global || value.regex.sticky;
|
|
104
|
-
value.regex.lastIndex = toLength(getOwn(value, "lastIndex"));
|
|
105
|
-
const matched = value.regex.exec(input);
|
|
106
|
-
if (stateful)
|
|
107
|
-
set(value, "lastIndex", value.regex.lastIndex);
|
|
108
|
-
if (name === "test")
|
|
109
|
-
return matched !== null;
|
|
110
|
-
return matched === null ? null : matchToValue(protos, matched);
|
|
111
|
-
},
|
|
112
|
-
];
|
|
113
|
-
methods(protos, proto, [
|
|
114
|
-
run("exec"),
|
|
115
|
-
run("test"),
|
|
116
|
-
["toString", 0, (thisValue, _, node) => coerceToString(self(thisValue, "toString", node))],
|
|
117
|
-
]);
|
|
118
|
-
return regexp;
|
|
119
|
-
};
|
|
120
|
-
const indicesToValue = (protos, indices) => {
|
|
121
|
-
const range = (pair) => pair === undefined ? undefined : new ProgramArray(protos.Array, [...pair]);
|
|
122
|
-
const result = new ProgramArray(protos.Array, Array.from(indices, range));
|
|
112
|
+
const indicesToValue = (indices) => {
|
|
113
|
+
const range = (pair) => (pair === undefined ? undefined : new ProgramArray([...pair]));
|
|
114
|
+
const result = new ProgramArray(Array.from(indices, range));
|
|
123
115
|
const groups = indices.groups;
|
|
124
|
-
|
|
116
|
+
set(result, "groups", groups === undefined
|
|
125
117
|
? undefined
|
|
126
|
-
: record(
|
|
118
|
+
: record(Object.fromEntries(Object.entries(groups).map(([key, pair]) => [key, range(pair)]))));
|
|
127
119
|
return result;
|
|
128
120
|
};
|
package/dist/stdlib/string.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const stringGlobal:
|
|
1
|
+
export declare const stringMethods: Set<string>;
|
|
2
|
+
export declare const stringGlobal: import("../interpreter/host.js").HostFunction<never>;
|