@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/data.d.ts
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
export * as Data from "./data.js";
|
|
2
2
|
import type { DiagnosticKind } from "./codemode.js";
|
|
3
|
-
import type { Prototypes } from "./interpreter/intrinsics.js";
|
|
4
3
|
export declare class ToolRuntimeError extends Error {
|
|
5
4
|
readonly kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "InvalidDataValue" | "ToolCallLimitExceeded">;
|
|
6
5
|
readonly suggestions: ReadonlyArray<string>;
|
|
7
6
|
constructor(kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "InvalidDataValue" | "ToolCallLimitExceeded">, message: string, suggestions?: ReadonlyArray<string>);
|
|
8
7
|
}
|
|
9
8
|
/**
|
|
10
|
-
* Brings a host-produced value into the program: program values pass through,
|
|
11
|
-
* Map, Set, URL,
|
|
12
|
-
* are copied.
|
|
9
|
+
* Brings a host-produced value into the program: program and runtime values pass through, their
|
|
10
|
+
* host counterparts (Date, RegExp, Map, Set, URL, URLSearchParams) are wrapped, and host objects
|
|
11
|
+
* and arrays are copied.
|
|
13
12
|
*/
|
|
14
|
-
export declare const toProgram: (
|
|
13
|
+
export declare const toProgram: (value: unknown, label: string) => unknown;
|
|
15
14
|
/**
|
|
16
15
|
* Brings host data into the program: Date and URL become strings, other host collections become
|
|
17
16
|
* empty objects, and objects become program copies. Used for tool results and parsed JSON.
|
|
18
17
|
*/
|
|
19
|
-
export declare const fromData: (
|
|
18
|
+
export declare const fromData: (value: unknown, label: string) => unknown;
|
|
20
19
|
/**
|
|
21
20
|
* Takes a program value out as plain JSON: runtime values serialize like `JSON.stringify` would,
|
|
22
21
|
* non-finite numbers become null, and array holes become null. `undefined` object properties are
|
package/dist/data.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * as Data from "./data.js";
|
|
2
|
-
import {
|
|
2
|
+
import { ownEntries, parseArrayIndex, ProgramArray, ProgramFunction, ProgramObject, set, } from "./interpreter/objects.js";
|
|
3
|
+
import { Values } from "./values.js";
|
|
3
4
|
const MAX_VALUE_DEPTH = 32;
|
|
4
5
|
export class ToolRuntimeError extends Error {
|
|
5
6
|
kind;
|
|
@@ -12,16 +13,16 @@ export class ToolRuntimeError extends Error {
|
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
|
-
* Brings a host-produced value into the program: program values pass through,
|
|
16
|
-
* Map, Set, URL,
|
|
17
|
-
* are copied.
|
|
16
|
+
* Brings a host-produced value into the program: program and runtime values pass through, their
|
|
17
|
+
* host counterparts (Date, RegExp, Map, Set, URL, URLSearchParams) are wrapped, and host objects
|
|
18
|
+
* and arrays are copied.
|
|
18
19
|
*/
|
|
19
|
-
export const toProgram = (
|
|
20
|
+
export const toProgram = (value, label) => copy(value, label, "program", 0, new Set());
|
|
20
21
|
/**
|
|
21
22
|
* Brings host data into the program: Date and URL become strings, other host collections become
|
|
22
23
|
* empty objects, and objects become program copies. Used for tool results and parsed JSON.
|
|
23
24
|
*/
|
|
24
|
-
export const fromData = (
|
|
25
|
+
export const fromData = (value, label) => copy(value, label, "data", 0, new Set());
|
|
25
26
|
/**
|
|
26
27
|
* Takes a program value out as plain JSON: runtime values serialize like `JSON.stringify` would,
|
|
27
28
|
* non-finite numbers become null, and array holes become null. `undefined` object properties are
|
|
@@ -29,8 +30,7 @@ export const fromData = (protos, value, label) => copy(value, label, "data", 0,
|
|
|
29
30
|
* undefined); a bare `undefined` follows the same rule.
|
|
30
31
|
*/
|
|
31
32
|
export const toData = (value, label, undefinedAs = "json") => copy(value, label, undefinedAs, 0, new Set());
|
|
32
|
-
const copy = (value, label, mode, depth, seen
|
|
33
|
-
const next = (item) => copy(item, label, mode, depth + 1, seen, protos);
|
|
33
|
+
const copy = (value, label, mode, depth, seen) => {
|
|
34
34
|
if (depth > MAX_VALUE_DEPTH) {
|
|
35
35
|
throw new ToolRuntimeError("InvalidDataValue", `${label} exceeds the maximum value depth of ${MAX_VALUE_DEPTH}.`);
|
|
36
36
|
}
|
|
@@ -43,88 +43,85 @@ const copy = (value, label, mode, depth, seen, protos) => {
|
|
|
43
43
|
if (typeof value !== "object") {
|
|
44
44
|
throw new ToolRuntimeError("InvalidDataValue", `${label} must contain data only.`);
|
|
45
45
|
}
|
|
46
|
-
if (value instanceof
|
|
46
|
+
if (value instanceof Values.Promise) {
|
|
47
47
|
throw new ToolRuntimeError("InvalidDataValue", `${label} contains an un-awaited Promise; await tool calls (e.g. \`const result = await tools.ns.tool(...)\`) before using their results.`);
|
|
48
48
|
}
|
|
49
|
-
if (
|
|
49
|
+
if (value instanceof ProgramFunction && mode !== "program") {
|
|
50
50
|
throw new ToolRuntimeError("InvalidDataValue", `${label} must contain data only.`);
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
const plain = mode === "program" || mode === "data";
|
|
53
|
+
if (mode === "program") {
|
|
54
|
+
if (value instanceof ProgramObject || Values.isValue(value))
|
|
54
55
|
return value;
|
|
55
56
|
if (value instanceof Date)
|
|
56
|
-
return new
|
|
57
|
+
return new Values.Date(value.getTime());
|
|
57
58
|
if (value instanceof RegExp)
|
|
58
|
-
return new
|
|
59
|
+
return new Values.RegExp(value.source, value.flags);
|
|
59
60
|
if (value instanceof Map) {
|
|
60
|
-
const wrapped = new
|
|
61
|
-
for (const [key, item] of value.entries())
|
|
62
|
-
wrapped.map.set(
|
|
61
|
+
const wrapped = new Values.Map();
|
|
62
|
+
for (const [key, item] of value.entries()) {
|
|
63
|
+
wrapped.map.set(copy(key, label, mode, depth + 1, seen), copy(item, label, mode, depth + 1, seen));
|
|
64
|
+
}
|
|
63
65
|
return wrapped;
|
|
64
66
|
}
|
|
65
67
|
if (value instanceof Set) {
|
|
66
|
-
const wrapped = new
|
|
68
|
+
const wrapped = new Values.Set();
|
|
67
69
|
for (const item of value.values())
|
|
68
|
-
wrapped.set.add(
|
|
70
|
+
wrapped.set.add(copy(item, label, mode, depth + 1, seen));
|
|
69
71
|
return wrapped;
|
|
70
72
|
}
|
|
71
73
|
if (value instanceof URL)
|
|
72
|
-
return new
|
|
74
|
+
return new Values.URL(new URL(value.href));
|
|
73
75
|
if (value instanceof URLSearchParams)
|
|
74
|
-
return new
|
|
76
|
+
return new Values.URLSearchParams(new URLSearchParams(value));
|
|
75
77
|
}
|
|
76
|
-
if (value instanceof
|
|
78
|
+
if (value instanceof Values.Date)
|
|
77
79
|
return Number.isFinite(value.time) ? new Date(value.time).toISOString() : null;
|
|
78
80
|
if (value instanceof Date)
|
|
79
81
|
return Number.isFinite(value.getTime()) ? value.toISOString() : null;
|
|
80
|
-
if (value instanceof
|
|
82
|
+
if (value instanceof Values.URL)
|
|
81
83
|
return value.url.href;
|
|
82
84
|
if (value instanceof URL)
|
|
83
85
|
return value.href;
|
|
84
|
-
// Remaining
|
|
85
|
-
if (
|
|
86
|
+
// Remaining runtime values and their host counterparts serialize as empty objects, like JSON.stringify.
|
|
87
|
+
if (Values.isValue(value) ||
|
|
86
88
|
value instanceof RegExp ||
|
|
87
89
|
value instanceof Map ||
|
|
88
90
|
value instanceof Set ||
|
|
89
91
|
value instanceof URLSearchParams) {
|
|
90
|
-
return
|
|
92
|
+
return plain ? new ProgramObject() : {};
|
|
91
93
|
}
|
|
92
94
|
if (seen.has(value)) {
|
|
93
95
|
throw new ToolRuntimeError("InvalidDataValue", `${label} contains a circular value.`);
|
|
94
96
|
}
|
|
95
97
|
seen.add(value);
|
|
96
98
|
if (value instanceof ProgramArray) {
|
|
97
|
-
const copied = Array.from(value.items, (item) =>
|
|
99
|
+
const copied = Array.from(value.items, (item) => copy(item, label, mode, depth + 1, seen) ?? null);
|
|
98
100
|
seen.delete(value);
|
|
99
101
|
return copied;
|
|
100
102
|
}
|
|
101
103
|
if (value instanceof ProgramObject) {
|
|
102
104
|
const copied = {};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
defineHost(copied, "message", next(get(value, "message")));
|
|
107
|
-
}
|
|
108
|
-
for (const [key, item] of entries(value)) {
|
|
109
|
-
const copiedItem = next(item);
|
|
110
|
-
if (copiedItem === undefined && mode === "json")
|
|
105
|
+
for (const [key, item] of ownEntries(value)) {
|
|
106
|
+
const next = copy(item, label, mode, depth + 1, seen);
|
|
107
|
+
if (next === undefined && mode === "json")
|
|
111
108
|
continue;
|
|
112
|
-
|
|
109
|
+
define(copied, key, next);
|
|
113
110
|
}
|
|
114
111
|
seen.delete(value);
|
|
115
112
|
return copied;
|
|
116
113
|
}
|
|
117
114
|
if (Array.isArray(value)) {
|
|
118
|
-
if (
|
|
119
|
-
const copied = new ProgramArray(
|
|
115
|
+
if (plain) {
|
|
116
|
+
const copied = new ProgramArray(value.map((item) => copy(item, label, mode, depth + 1, seen)));
|
|
120
117
|
for (const [key, item] of Object.entries(value)) {
|
|
121
118
|
if (parseArrayIndex(key) === undefined)
|
|
122
|
-
|
|
119
|
+
set(copied, key, copy(item, label, mode, depth + 1, seen));
|
|
123
120
|
}
|
|
124
121
|
seen.delete(value);
|
|
125
122
|
return copied;
|
|
126
123
|
}
|
|
127
|
-
const copied = Array.from(value, (item) =>
|
|
124
|
+
const copied = Array.from(value, (item) => copy(item, label, mode, depth + 1, seen) ?? null);
|
|
128
125
|
seen.delete(value);
|
|
129
126
|
return copied;
|
|
130
127
|
}
|
|
@@ -132,25 +129,25 @@ const copy = (value, label, mode, depth, seen, protos) => {
|
|
|
132
129
|
if (prototype !== Object.prototype && prototype !== null) {
|
|
133
130
|
throw new ToolRuntimeError("InvalidDataValue", `${label} must contain plain objects only.`);
|
|
134
131
|
}
|
|
135
|
-
if (
|
|
136
|
-
const copied = new ProgramObject(
|
|
132
|
+
if (plain) {
|
|
133
|
+
const copied = new ProgramObject();
|
|
137
134
|
for (const [key, item] of Object.entries(value))
|
|
138
|
-
|
|
135
|
+
set(copied, key, copy(item, label, mode, depth + 1, seen));
|
|
139
136
|
seen.delete(value);
|
|
140
137
|
return copied;
|
|
141
138
|
}
|
|
142
139
|
const copied = {};
|
|
143
140
|
for (const [key, item] of Object.entries(value)) {
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
141
|
+
const next = copy(item, label, mode, depth + 1, seen);
|
|
142
|
+
if (next === undefined && mode === "json")
|
|
146
143
|
continue;
|
|
147
|
-
|
|
144
|
+
define(copied, key, next);
|
|
148
145
|
}
|
|
149
146
|
seen.delete(value);
|
|
150
147
|
return copied;
|
|
151
148
|
};
|
|
152
149
|
// Own data property regardless of the target's prototype, so a "__proto__" key on a host object
|
|
153
150
|
// never reaches the Object.prototype setter.
|
|
154
|
-
const
|
|
151
|
+
const define = (target, key, value) => {
|
|
155
152
|
Object.defineProperty(target, key, { value, enumerable: true, writable: true, configurable: true });
|
|
156
153
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export * as CodeMode from "./codemode.js";
|
|
|
2
2
|
export * as Namespace from "./namespace.js";
|
|
3
3
|
export * as Tool from "./tool.js";
|
|
4
4
|
export * as OpenAPI from "./openapi/index.js";
|
|
5
|
+
export { Values } from "./values.js";
|
|
5
6
|
export { searchSignature, toolExpression } from "./codemode.js";
|
|
6
7
|
export { ToolError, toolError } from "./tool-error.js";
|
package/dist/index.js
CHANGED
|
@@ -2,5 +2,6 @@ export * as CodeMode from "./codemode.js";
|
|
|
2
2
|
export * as Namespace from "./namespace.js";
|
|
3
3
|
export * as Tool from "./tool.js";
|
|
4
4
|
export * as OpenAPI from "./openapi/index.js";
|
|
5
|
+
export { Values } from "./values.js";
|
|
5
6
|
export { searchSignature, toolExpression } from "./codemode.js";
|
|
6
7
|
export { ToolError, toolError } from "./tool-error.js";
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { Diagnostic } from "../codemode.js";
|
|
2
|
-
import {
|
|
3
|
-
import { type NativeFunction, ProgramError, ProgramObject } from "./objects.js";
|
|
2
|
+
import { HostFunction } from "./host.js";
|
|
4
3
|
import { type Runner } from "./runner.js";
|
|
5
4
|
export declare const normalizeError: (error: unknown) => Diagnostic;
|
|
6
|
-
export declare const caughtErrorValue:
|
|
7
|
-
export declare const createAggregateErrorValue: <R>(runner: Runner<R>, errors: Array<unknown>, message: string, proto?: ProgramObject) => ProgramError;
|
|
5
|
+
export declare const caughtErrorValue: (thrown: unknown) => unknown;
|
|
8
6
|
/** An error constructor such as `Error` or `TypeError`; callable with or without `new`, like JS. */
|
|
9
|
-
export declare const errorGlobal: <R>(
|
|
7
|
+
export declare const errorGlobal: <R>(name: string, runner: Runner<R>) => HostFunction<R>;
|
|
@@ -3,11 +3,10 @@ import { ToolError } from "../tool-error.js";
|
|
|
3
3
|
import { toData, ToolRuntimeError } from "../data.js";
|
|
4
4
|
import { formatLocation, InterpreterRuntimeError, ProgramThrow, sourceLocation } from "./model.js";
|
|
5
5
|
import { containsRuntimeReference } from "./references.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { define, get, hidden, ProgramArray, ProgramError, ProgramObject, } from "./objects.js";
|
|
6
|
+
import { HostFunction } from "./host.js";
|
|
7
|
+
import { get, ProgramError, ProgramObject } from "./objects.js";
|
|
9
8
|
import {} from "./runner.js";
|
|
10
|
-
import { coerceToString } from "../stdlib/value.js";
|
|
9
|
+
import { coerceToString, createAggregateErrorValue, createErrorValue, errorBrandName, errorConstructors, } from "../stdlib/value.js";
|
|
11
10
|
export const normalizeError = (error) => {
|
|
12
11
|
if (error instanceof InterpreterRuntimeError) {
|
|
13
12
|
return {
|
|
@@ -67,69 +66,41 @@ export const normalizeError = (error) => {
|
|
|
67
66
|
message: String(error),
|
|
68
67
|
};
|
|
69
68
|
};
|
|
70
|
-
export const caughtErrorValue = (
|
|
69
|
+
export const caughtErrorValue = (thrown) => {
|
|
71
70
|
if (thrown instanceof ProgramThrow)
|
|
72
71
|
return thrown.value;
|
|
73
|
-
const prototypes = runner.prototypes;
|
|
74
72
|
if (thrown instanceof InterpreterRuntimeError)
|
|
75
|
-
return createErrorValue(
|
|
76
|
-
const
|
|
77
|
-
return createErrorValue(
|
|
73
|
+
return createErrorValue(thrown.errorName, thrown.message);
|
|
74
|
+
const name = thrown instanceof Error && errorConstructors.has(thrown.name) ? thrown.name : "Error";
|
|
75
|
+
return createErrorValue(name, normalizeError(thrown).message);
|
|
78
76
|
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
define(value, "errors", new ProgramArray(runner.prototypes.Array, errors), { ...hidden });
|
|
82
|
-
return value;
|
|
83
|
-
};
|
|
84
|
-
const constructAggregateErrorValue = (runner, args, proto, node) => Effect.gen(function* () {
|
|
77
|
+
const constructErrorValue = (name, args) => createErrorValue(name, args[0] === undefined ? "" : coerceToString(args[0]));
|
|
78
|
+
const constructAggregateErrorValue = (runner, args, node) => Effect.gen(function* () {
|
|
85
79
|
const cursor = yield* runner.syncIterator(args[0], node);
|
|
86
80
|
if (cursor === undefined) {
|
|
87
|
-
throw new InterpreterRuntimeError("new AggregateError(...) expects a synchronous iterable of errors.", node);
|
|
81
|
+
throw new InterpreterRuntimeError("new AggregateError(...) expects a synchronous iterable of errors.", node).as("TypeError");
|
|
88
82
|
}
|
|
89
83
|
const errors = [];
|
|
90
84
|
while (true) {
|
|
91
85
|
const step = yield* cursor.next;
|
|
92
86
|
if (step.done) {
|
|
93
|
-
return createAggregateErrorValue(
|
|
87
|
+
return createAggregateErrorValue(errors, args[1] === undefined ? "" : coerceToString(args[1]));
|
|
94
88
|
}
|
|
95
89
|
errors.push(step.value);
|
|
96
90
|
}
|
|
97
91
|
});
|
|
98
92
|
/** An error constructor such as `Error` or `TypeError`; callable with or without `new`, like JS. */
|
|
99
|
-
export const errorGlobal = (
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
: Effect.sync(() => createErrorValue(proto, args[0] === undefined ? undefined : coerceToString(args[0])));
|
|
107
|
-
};
|
|
108
|
-
const ctor = constructor(protos, prototype, {
|
|
109
|
-
name: type,
|
|
110
|
-
length: type === "AggregateError" ? 2 : 1,
|
|
111
|
-
call: (_, args, node) => construct(args, ctor, node),
|
|
93
|
+
export const errorGlobal = (name, runner) => {
|
|
94
|
+
const construct = (args, node) => name === "AggregateError"
|
|
95
|
+
? constructAggregateErrorValue(runner, args, node)
|
|
96
|
+
: Effect.sync(() => constructErrorValue(name, args));
|
|
97
|
+
return new HostFunction({
|
|
98
|
+
name,
|
|
99
|
+
call: construct,
|
|
112
100
|
construct,
|
|
101
|
+
instanceOf: (value) => {
|
|
102
|
+
const brand = errorBrandName(value);
|
|
103
|
+
return brand !== undefined && (name === "Error" || brand === name);
|
|
104
|
+
},
|
|
113
105
|
});
|
|
114
|
-
if (type === "Error") {
|
|
115
|
-
methods(protos, prototype, [
|
|
116
|
-
[
|
|
117
|
-
"toString",
|
|
118
|
-
0,
|
|
119
|
-
(thisValue, _, node) => {
|
|
120
|
-
const self = receiver(ProgramObject, thisValue, "Error.prototype.toString", node);
|
|
121
|
-
const name = get(self, "name");
|
|
122
|
-
const message = get(self, "message");
|
|
123
|
-
const shownName = name === undefined ? "Error" : coerceToString(name);
|
|
124
|
-
const shownMessage = message === undefined ? "" : coerceToString(message);
|
|
125
|
-
if (shownMessage === "")
|
|
126
|
-
return shownName;
|
|
127
|
-
if (shownName === "")
|
|
128
|
-
return shownMessage;
|
|
129
|
-
return `${shownName}: ${shownMessage}`;
|
|
130
|
-
},
|
|
131
|
-
],
|
|
132
|
-
]);
|
|
133
|
-
}
|
|
134
|
-
return ctor;
|
|
135
106
|
};
|
|
@@ -6,7 +6,6 @@ import { transpile } from "#transpile";
|
|
|
6
6
|
import { toData } from "../data.js";
|
|
7
7
|
import { ToolRuntime } from "../tool-runtime.js";
|
|
8
8
|
import { normalizeError } from "./errors.js";
|
|
9
|
-
import { createPrototypes } from "./intrinsics.js";
|
|
10
9
|
import { InterpreterRuntimeError } from "./model.js";
|
|
11
10
|
import { PromiseRuntime } from "./promises.js";
|
|
12
11
|
import { Runtime } from "./runtime.js";
|
|
@@ -20,16 +19,15 @@ export const executeProgram = (code, prepared, limits, hooks, extraGlobals) => {
|
|
|
20
19
|
}
|
|
21
20
|
// Allocate execution state inside suspension so reused Effects never share it.
|
|
22
21
|
return Effect.suspend(() => {
|
|
23
|
-
const
|
|
24
|
-
const tools = ToolRuntime.make(prepared, prototypes, limits.maxToolCalls, hooks);
|
|
22
|
+
const tools = ToolRuntime.make(prepared, limits.maxToolCalls, hooks);
|
|
25
23
|
const logs = [];
|
|
26
24
|
const logged = () => (logs.length > 0 ? { logs: [...logs] } : {});
|
|
27
25
|
// Set only after copy-out so timeouts cannot report invalid values as completed.
|
|
28
26
|
let returned;
|
|
29
27
|
const base = Effect.acquireUseRelease(Scope.make("parallel"), (scope) => Effect.gen(function* () {
|
|
30
28
|
const program = parseProgram(code);
|
|
31
|
-
const promises = new PromiseRuntime(scope
|
|
32
|
-
const value = yield* new Runtime(tools.execute, tools.search, tools.keys, promises,
|
|
29
|
+
const promises = new PromiseRuntime(scope);
|
|
30
|
+
const value = yield* new Runtime(tools.execute, tools.search, tools.keys, promises, logs, extraGlobals).run(program);
|
|
33
31
|
const result = toData(value, "Execution result", "result");
|
|
34
32
|
returned = { value: result, promises };
|
|
35
33
|
const warnings = yield* promises.interrupt();
|
|
@@ -5,81 +5,59 @@ import { consoleGlobal } from "../stdlib/console.js";
|
|
|
5
5
|
import { dateGlobal } from "../stdlib/date.js";
|
|
6
6
|
import { jsonGlobal } from "../stdlib/json.js";
|
|
7
7
|
import { mathGlobal } from "../stdlib/math.js";
|
|
8
|
-
import {
|
|
8
|
+
import { numberGlobal } from "../stdlib/number.js";
|
|
9
9
|
import { objectGlobal } from "../stdlib/object.js";
|
|
10
10
|
import { regexpGlobal } from "../stdlib/regexp.js";
|
|
11
11
|
import { stringGlobal } from "../stdlib/string.js";
|
|
12
12
|
import { uriGlobal, urlGlobal, urlSearchParamsGlobal } from "../stdlib/url.js";
|
|
13
|
-
import { coercion } from "../stdlib/value.js";
|
|
14
|
-
import {
|
|
13
|
+
import { coercion, errorConstructors } from "../stdlib/value.js";
|
|
14
|
+
import { atobGlobal, btoaGlobal, cryptoGlobal } from "../stdlib/web.js";
|
|
15
15
|
import { ToolReference } from "../tool-runtime.js";
|
|
16
16
|
import { errorGlobal } from "./errors.js";
|
|
17
|
-
import {
|
|
18
|
-
import { constants, constructor, native } from "./native.js";
|
|
17
|
+
import { HostFunction } from "./host.js";
|
|
19
18
|
import { AsyncIteratorSymbol, InterpreterRuntimeError, IteratorSymbol } from "./model.js";
|
|
20
|
-
import { generatorGlobals } from "./generators.js";
|
|
21
19
|
import { promiseGlobal } from "./promises.js";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
throw new InterpreterRuntimeError("
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
call: reject,
|
|
31
|
-
construct: (args, _, node) => reject(undefined, args, node),
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
|
-
const symbolGlobal = (runner) => {
|
|
35
|
-
const symbol = native(runner.prototypes, {
|
|
36
|
-
name: "Symbol",
|
|
37
|
-
call: (_, __, node) => Effect.sync(() => {
|
|
38
|
-
throw new InterpreterRuntimeError("Symbol is not callable; only Symbol.asyncIterator and Symbol.iterator are available.", node);
|
|
39
|
-
}),
|
|
40
|
-
callback: false,
|
|
41
|
-
});
|
|
42
|
-
constants(symbol, { asyncIterator: AsyncIteratorSymbol, iterator: IteratorSymbol });
|
|
43
|
-
return symbol;
|
|
44
|
-
};
|
|
20
|
+
const symbolGlobal = new HostFunction({
|
|
21
|
+
name: "Symbol",
|
|
22
|
+
call: (_, node) => Effect.sync(() => {
|
|
23
|
+
throw new InterpreterRuntimeError("Symbol is not callable; only Symbol.asyncIterator and Symbol.iterator are available.", node).as("TypeError");
|
|
24
|
+
}),
|
|
25
|
+
callback: false,
|
|
26
|
+
members: { asyncIterator: AsyncIteratorSymbol, iterator: IteratorSymbol },
|
|
27
|
+
});
|
|
45
28
|
/** The immutable global bindings of every program, in declaration order. */
|
|
46
|
-
export const globals = (host) =>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
["btoa", base64Global(runner, "btoa")],
|
|
82
|
-
["crypto", cryptoGlobal(runner)],
|
|
83
|
-
...errorTypes.map((type) => [type, errorGlobal(type, runner)]),
|
|
84
|
-
];
|
|
85
|
-
};
|
|
29
|
+
export const globals = (host) => [
|
|
30
|
+
["tools", new ToolReference([])],
|
|
31
|
+
["search", new HostFunction({ name: "search", call: (args) => host.search(args), callback: false })],
|
|
32
|
+
["undefined", undefined],
|
|
33
|
+
["NaN", NaN],
|
|
34
|
+
["Infinity", Infinity],
|
|
35
|
+
["Object", objectGlobal(host.runner, host.toolKeys)],
|
|
36
|
+
["Array", arrayGlobal(host.runner)],
|
|
37
|
+
["Math", mathGlobal(host.runner)],
|
|
38
|
+
["JSON", jsonGlobal(host.runner)],
|
|
39
|
+
["console", consoleGlobal(host.logs)],
|
|
40
|
+
["Promise", promiseGlobal(host.runner, host.promises)],
|
|
41
|
+
["Symbol", symbolGlobal],
|
|
42
|
+
["Number", numberGlobal],
|
|
43
|
+
["String", stringGlobal],
|
|
44
|
+
["Boolean", coercion("Boolean", { instanceOf: () => false })],
|
|
45
|
+
["parseInt", coercion("parseInt")],
|
|
46
|
+
["parseFloat", coercion("parseFloat")],
|
|
47
|
+
["isFinite", coercion("isFinite")],
|
|
48
|
+
["isNaN", coercion("isNaN")],
|
|
49
|
+
["Date", dateGlobal(host.runner)],
|
|
50
|
+
["RegExp", regexpGlobal],
|
|
51
|
+
["Map", mapGlobal(host.runner)],
|
|
52
|
+
["Set", setGlobal(host.runner)],
|
|
53
|
+
["URL", urlGlobal],
|
|
54
|
+
["URLSearchParams", urlSearchParamsGlobal(host.runner)],
|
|
55
|
+
["encodeURI", uriGlobal("encodeURI")],
|
|
56
|
+
["encodeURIComponent", uriGlobal("encodeURIComponent")],
|
|
57
|
+
["decodeURI", uriGlobal("decodeURI")],
|
|
58
|
+
["decodeURIComponent", uriGlobal("decodeURIComponent")],
|
|
59
|
+
["atob", atobGlobal],
|
|
60
|
+
["btoa", btoaGlobal],
|
|
61
|
+
["crypto", cryptoGlobal],
|
|
62
|
+
...[...errorConstructors].map((name) => [name, errorGlobal(name, host.runner)]),
|
|
63
|
+
];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { type AstNode } from "./model.js";
|
|
3
|
+
export type HostCall<R> = (args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
4
|
+
type HostMember = (key: PropertyKey, node: AstNode) => unknown;
|
|
5
|
+
type HostFunctionOptions<R> = {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly call: HostCall<R>;
|
|
8
|
+
/** `new name(...)`; without it `new` is unsupported syntax. */
|
|
9
|
+
readonly construct?: HostCall<R>;
|
|
10
|
+
/** Static members read through `name.key`; unknown keys read as `undefined` unless the function decides otherwise. */
|
|
11
|
+
readonly members?: Record<string, unknown> | HostMember;
|
|
12
|
+
/** `value instanceof name`; without it the operator rejects this right-hand side. */
|
|
13
|
+
readonly instanceOf?: (value: unknown) => boolean;
|
|
14
|
+
/** Whether callback sites (array methods, replacers, promise reactions) admit this function. Defaults to true. */
|
|
15
|
+
readonly callback?: boolean;
|
|
16
|
+
};
|
|
17
|
+
/** A host-implemented function value. `typeof` is "function". */
|
|
18
|
+
export declare class HostFunction<R = never> {
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly call: HostCall<R>;
|
|
21
|
+
readonly construct: HostCall<R> | undefined;
|
|
22
|
+
readonly member: HostMember;
|
|
23
|
+
readonly instanceOf: ((value: unknown) => boolean) | undefined;
|
|
24
|
+
readonly callback: boolean;
|
|
25
|
+
constructor(options: HostFunctionOptions<R>);
|
|
26
|
+
}
|
|
27
|
+
/** A host-implemented object of static members. `typeof` is "object" and it is not callable. */
|
|
28
|
+
export declare class HostNamespace {
|
|
29
|
+
readonly name: string;
|
|
30
|
+
readonly member: HostMember;
|
|
31
|
+
constructor(name: string, members: Record<string, unknown> | HostMember);
|
|
32
|
+
}
|
|
33
|
+
export type SyncOptions = Omit<HostFunctionOptions<never>, "name" | "call">;
|
|
34
|
+
type SyncImpl = (args: Array<unknown>, node: AstNode) => unknown;
|
|
35
|
+
/** Lifts a synchronous implementation, which may throw `InterpreterRuntimeError`, into a host call. */
|
|
36
|
+
export declare const syncCall: (impl: SyncImpl) => HostCall<never>;
|
|
37
|
+
/** A synchronous host function. */
|
|
38
|
+
export declare const sync: (name: string, impl: SyncImpl, options?: SyncOptions) => HostFunction<never>;
|
|
39
|
+
/** The `call` of a constructor that JS requires to be invoked with `new`. */
|
|
40
|
+
export declare const requiresNew: (name: string) => HostCall<never>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { InterpreterRuntimeError } from "./model.js";
|
|
3
|
+
/** A host-implemented function value. `typeof` is "function". */
|
|
4
|
+
export class HostFunction {
|
|
5
|
+
name;
|
|
6
|
+
call;
|
|
7
|
+
construct;
|
|
8
|
+
member;
|
|
9
|
+
instanceOf;
|
|
10
|
+
callback;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.name = options.name;
|
|
13
|
+
this.call = options.call;
|
|
14
|
+
this.construct = options.construct;
|
|
15
|
+
this.member = memberLookup(options.members);
|
|
16
|
+
this.instanceOf = options.instanceOf;
|
|
17
|
+
this.callback = options.callback ?? true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** A host-implemented object of static members. `typeof` is "object" and it is not callable. */
|
|
21
|
+
export class HostNamespace {
|
|
22
|
+
name;
|
|
23
|
+
member;
|
|
24
|
+
constructor(name, members) {
|
|
25
|
+
this.name = name;
|
|
26
|
+
this.member = memberLookup(members);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const memberLookup = (members) => {
|
|
30
|
+
if (members === undefined)
|
|
31
|
+
return () => undefined;
|
|
32
|
+
if (typeof members === "function")
|
|
33
|
+
return members;
|
|
34
|
+
const table = new Map(Object.entries(members));
|
|
35
|
+
return (key) => (typeof key === "string" ? table.get(key) : undefined);
|
|
36
|
+
};
|
|
37
|
+
/** Lifts a synchronous implementation, which may throw `InterpreterRuntimeError`, into a host call. */
|
|
38
|
+
export const syncCall = (impl) => (args, node) => Effect.sync(() => impl(args, node));
|
|
39
|
+
/** A synchronous host function. */
|
|
40
|
+
export const sync = (name, impl, options = {}) => new HostFunction({ name, call: syncCall(impl), ...options });
|
|
41
|
+
/** The `call` of a constructor that JS requires to be invoked with `new`. */
|
|
42
|
+
export const requiresNew = (name) => (_, node) => Effect.sync(() => {
|
|
43
|
+
throw new InterpreterRuntimeError(`Constructor ${name} requires 'new'.`, node).as("TypeError");
|
|
44
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { type AstNode, IntrinsicReference } from "./model.js";
|
|
3
|
+
import { type Runner } from "./runner.js";
|
|
4
|
+
export declare const invokeIntrinsic: <R>(runner: Runner<R>, ref: IntrinsicReference, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|