@opencode/codemode 2.0.3 → 2.0.4

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.
Files changed (71) hide show
  1. package/dist/codemode.d.ts +3 -0
  2. package/dist/codemode.js +12 -1
  3. package/dist/data.d.ts +14 -21
  4. package/dist/data.js +72 -140
  5. package/dist/extension.d.ts +11 -0
  6. package/dist/extension.js +9 -0
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/interpreter/callback.d.ts +20 -0
  10. package/dist/interpreter/{runner.js → callback.js} +14 -14
  11. package/dist/interpreter/errors.d.ts +12 -5
  12. package/dist/interpreter/errors.js +66 -54
  13. package/dist/interpreter/execute.d.ts +2 -2
  14. package/dist/interpreter/execute.js +15 -15
  15. package/dist/interpreter/extensions.d.ts +8 -0
  16. package/dist/interpreter/extensions.js +155 -0
  17. package/dist/interpreter/generators.d.ts +2 -3
  18. package/dist/interpreter/generators.js +10 -10
  19. package/dist/interpreter/globals.d.ts +4 -12
  20. package/dist/interpreter/globals.js +56 -49
  21. package/dist/interpreter/interpreter.d.ts +34 -0
  22. package/dist/interpreter/{runtime.js → interpreter.js} +250 -215
  23. package/dist/interpreter/intrinsics.d.ts +5 -5
  24. package/dist/interpreter/intrinsics.js +16 -10
  25. package/dist/interpreter/limits.d.ts +10 -0
  26. package/dist/interpreter/limits.js +19 -0
  27. package/dist/interpreter/model.d.ts +27 -14
  28. package/dist/interpreter/model.js +22 -14
  29. package/dist/interpreter/native.d.ts +12 -13
  30. package/dist/interpreter/native.js +17 -16
  31. package/dist/interpreter/objects.d.ts +55 -48
  32. package/dist/interpreter/objects.js +64 -44
  33. package/dist/interpreter/promises.d.ts +13 -15
  34. package/dist/interpreter/promises.js +89 -85
  35. package/dist/interpreter/references.d.ts +1 -2
  36. package/dist/interpreter/references.js +18 -16
  37. package/dist/interpreter/scope.js +6 -6
  38. package/dist/openapi/types.d.ts +1 -1
  39. package/dist/stdlib/array.d.ts +3 -4
  40. package/dist/stdlib/array.js +115 -110
  41. package/dist/stdlib/bytes.d.ts +10 -0
  42. package/dist/stdlib/bytes.js +228 -0
  43. package/dist/stdlib/collections.d.ts +4 -4
  44. package/dist/stdlib/collections.js +89 -89
  45. package/dist/stdlib/console.d.ts +5 -3
  46. package/dist/stdlib/console.js +30 -37
  47. package/dist/stdlib/date.d.ts +2 -2
  48. package/dist/stdlib/date.js +35 -35
  49. package/dist/stdlib/json.d.ts +3 -3
  50. package/dist/stdlib/json.js +29 -67
  51. package/dist/stdlib/math.d.ts +3 -3
  52. package/dist/stdlib/math.js +17 -21
  53. package/dist/stdlib/number.d.ts +3 -3
  54. package/dist/stdlib/number.js +32 -36
  55. package/dist/stdlib/object.d.ts +5 -5
  56. package/dist/stdlib/object.js +59 -62
  57. package/dist/stdlib/regexp.d.ts +7 -8
  58. package/dist/stdlib/regexp.js +40 -48
  59. package/dist/stdlib/string.d.ts +2 -2
  60. package/dist/stdlib/string.js +110 -88
  61. package/dist/stdlib/url.d.ts +4 -6
  62. package/dist/stdlib/url.js +86 -90
  63. package/dist/stdlib/value.d.ts +3 -3
  64. package/dist/stdlib/value.js +26 -24
  65. package/dist/stdlib/web.d.ts +4 -4
  66. package/dist/stdlib/web.js +22 -8
  67. package/dist/tool-runtime.d.ts +12 -5
  68. package/dist/tool-runtime.js +25 -11
  69. package/package.json +1 -1
  70. package/dist/interpreter/runner.d.ts +0 -28
  71. package/dist/interpreter/runtime.d.ts +0 -19
@@ -1,4 +1,5 @@
1
1
  import { Effect, Schema } from "effect";
2
+ import type { Extension } from "./extension.js";
2
3
  import { type Services, type ToolDescription, ToolRuntime } from "./tool-runtime.js";
3
4
  import type { Tools } from "./tools.js";
4
5
  /** A tool call admitted during an execution. */
@@ -29,6 +30,8 @@ export type ResolvedExecutionLimits = {
29
30
  export type Options<Provided extends Record<string, unknown> = {}> = ToolRuntime.ToolCallHooks<Services<Provided>> & {
30
31
  /** Explicit tools exposed to the program as `tools`. */
31
32
  tools?: Provided & Tools<Services<Provided>>;
33
+ /** Host functions exposed as globals; see `Extension.make`. */
34
+ extensions?: ReadonlyArray<Extension>;
32
35
  /** Resource limits enforced on each execution. */
33
36
  limits?: ExecutionLimits;
34
37
  };
package/dist/codemode.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { executeProgram } from "./interpreter/execute.js";
3
+ import { extensionGlobals } from "./interpreter/extensions.js";
4
+ import { globalNames } from "./interpreter/globals.js";
3
5
  import { ToolRuntime } from "./tool-runtime.js";
4
6
  /** Signature-construction helpers for host-owned catalog instructions. */
5
7
  export { searchSignature, toolExpression } from "./tool-runtime.js";
@@ -59,8 +61,17 @@ export const execute = (options) => make(options).execute(options.code);
59
61
  export const make = (options = {}) => {
60
62
  const prepared = ToolRuntime.prepare((options.tools ?? {}));
61
63
  const limits = resolveExecutionLimits(options.limits);
64
+ const extensions = options.extensions ?? [];
65
+ const bound = new Set(globalNames);
66
+ for (const extension of extensions) {
67
+ for (const name of Object.keys(extension.globals)) {
68
+ if (bound.has(name))
69
+ throw new TypeError(`Extension "${extension.name}" global "${name}" is already defined.`);
70
+ bound.add(name);
71
+ }
72
+ }
62
73
  return {
63
74
  catalog: prepared.catalog,
64
- execute: (code) => executeProgram(code, prepared, limits, options),
75
+ execute: (code) => executeProgram(code, prepared, limits, options, (ctx) => extensionGlobals(ctx, extensions)),
65
76
  };
66
77
  };
package/dist/data.d.ts CHANGED
@@ -1,26 +1,19 @@
1
1
  export * as Data from "./data.js";
2
- import type { DiagnosticKind } from "./codemode.js";
3
- import type { Prototypes } from "./interpreter/intrinsics.js";
4
- export declare class ToolRuntimeError extends Error {
5
- readonly kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "InvalidDataValue" | "ToolCallLimitExceeded">;
6
- readonly suggestions: ReadonlyArray<string>;
7
- constructor(kind: Extract<DiagnosticKind, "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "InvalidDataValue" | "ToolCallLimitExceeded">, message: string, suggestions?: ReadonlyArray<string>);
8
- }
2
+ import { Effect, type Schema } from "effect";
3
+ import type { Interpreter } from "./interpreter/interpreter.js";
4
+ export type Json = Schema.Json;
5
+ type Replacer<R> = (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
9
6
  /**
10
- * Brings a host-produced value into the program: program values pass through, host Date, RegExp,
11
- * Map, Set, URL, and URLSearchParams become their built-in wrappers, and host objects and arrays
12
- * are copied.
7
+ * What `JSON.stringify` would serialize for a program value, as host JSON: `toJSON` is honored, functions and
8
+ * `undefined` vanish, non-finite numbers become null, and everything else is copied. Two departures from JS
9
+ * so a mistake is not a silent `{}`: an Error serializes as `{ name, message, ...own }`, and a promise throws.
13
10
  */
14
- export declare const toProgram: (protos: Prototypes, value: unknown, label: string) => unknown;
11
+ export declare const toJson: <R>(ctx: Interpreter<R>, value: unknown, replacer?: Replacer<R>) => Effect.Effect<Schema.Json | undefined, unknown, R>;
15
12
  /**
16
- * Brings host data into the program: Date and URL become strings, other host collections become
17
- * empty objects, and objects become program copies. Used for tool results and parsed JSON.
13
+ * The host boundary: `toJson`, plus what a program most likely meant when a value cannot be JSON. A promise is
14
+ * awaited, a Set crosses as an array, a URLSearchParams as its query string, a Uint8Array asks to be encoded as
15
+ * text first, and a `__proto__` key is dropped so host code can never receive one.
18
16
  */
19
- export declare const fromData: (protos: Prototypes, value: unknown, label: string) => unknown;
20
- /**
21
- * Takes a program value out as plain JSON: runtime values serialize like `JSON.stringify` would,
22
- * non-finite numbers become null, and array holes become null. `undefined` object properties are
23
- * dropped ("json") or become null ("result", for program results where the consumer must never see
24
- * undefined); a bare `undefined` follows the same rule.
25
- */
26
- export declare const toData: (value: unknown, label: string, undefinedAs?: "json" | "result") => unknown;
17
+ export declare const toBoundary: <R>(ctx: Interpreter<R>, value: unknown) => Effect.Effect<Schema.Json | undefined, unknown, R>;
18
+ /** Host JSON as program values: objects and arrays are copied, primitives pass through. */
19
+ export declare const fromJson: <R>(ctx: Interpreter<R>, value: unknown) => unknown;
package/dist/data.js CHANGED
@@ -1,156 +1,88 @@
1
1
  export * as Data from "./data.js";
2
- import { Callable, define, entries, get, isWrapper, parseArrayIndex, ProgramArray, ProgramDate, ProgramError, ProgramGenerator, ProgramMap, ProgramObject, ProgramPromise, ProgramRegExp, ProgramSet, ProgramURL, ProgramURLSearchParams, } from "./interpreter/objects.js";
3
- const MAX_VALUE_DEPTH = 32;
4
- export class ToolRuntimeError extends Error {
5
- kind;
6
- suggestions;
7
- constructor(kind, message, suggestions = []) {
8
- super(message);
9
- this.kind = kind;
10
- this.suggestions = suggestions;
11
- this.name = "ToolRuntimeError";
12
- }
13
- }
2
+ import { Effect } from "effect";
3
+ import { MAX_VALUE_DEPTH } from "./interpreter/limits.js";
4
+ import { invalidData, rangeError, typeError } from "./interpreter/model.js";
5
+ import { Arr, Bytes, Callable, define, ErrorObj, get, keys, Obj, PromiseObj, record, SetObj, URLSearchParamsObj, } from "./interpreter/objects.js";
6
+ import { typeofValue } from "./interpreter/references.js";
14
7
  /**
15
- * Brings a host-produced value into the program: program values pass through, host Date, RegExp,
16
- * Map, Set, URL, and URLSearchParams become their built-in wrappers, and host objects and arrays
17
- * are copied.
8
+ * What `JSON.stringify` would serialize for a program value, as host JSON: `toJSON` is honored, functions and
9
+ * `undefined` vanish, non-finite numbers become null, and everything else is copied. Two departures from JS
10
+ * so a mistake is not a silent `{}`: an Error serializes as `{ name, message, ...own }`, and a promise throws.
18
11
  */
19
- export const toProgram = (protos, value, label) => copy(value, label, "program", 0, new Set(), protos);
12
+ export const toJson = (ctx, value, replacer) => walk(ctx, value, replacer, false);
20
13
  /**
21
- * Brings host data into the program: Date and URL become strings, other host collections become
22
- * empty objects, and objects become program copies. Used for tool results and parsed JSON.
14
+ * The host boundary: `toJson`, plus what a program most likely meant when a value cannot be JSON. A promise is
15
+ * awaited, a Set crosses as an array, a URLSearchParams as its query string, a Uint8Array asks to be encoded as
16
+ * text first, and a `__proto__` key is dropped so host code can never receive one.
23
17
  */
24
- export const fromData = (protos, value, label) => copy(value, label, "data", 0, new Set(), protos);
25
- /**
26
- * Takes a program value out as plain JSON: runtime values serialize like `JSON.stringify` would,
27
- * non-finite numbers become null, and array holes become null. `undefined` object properties are
28
- * dropped ("json") or become null ("result", for program results where the consumer must never see
29
- * undefined); a bare `undefined` follows the same rule.
30
- */
31
- export const toData = (value, label, undefinedAs = "json") => copy(value, label, undefinedAs, 0, new Set());
32
- const copy = (value, label, mode, depth, seen, protos) => {
33
- const next = (item) => copy(item, label, mode, depth + 1, seen, protos);
34
- if (depth > MAX_VALUE_DEPTH) {
35
- throw new ToolRuntimeError("InvalidDataValue", `${label} exceeds the maximum value depth of ${MAX_VALUE_DEPTH}.`);
36
- }
37
- if (value === undefined)
38
- return mode === "result" ? null : undefined;
39
- if (typeof value === "number")
40
- return (mode === "json" || mode === "result") && !Number.isFinite(value) ? null : value;
41
- if (value === null || typeof value === "string" || typeof value === "boolean")
42
- return value;
43
- if (typeof value !== "object") {
44
- throw new ToolRuntimeError("InvalidDataValue", `${label} must contain data only.`);
45
- }
46
- if (value instanceof ProgramPromise) {
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
- }
49
- if ((value instanceof Callable || value instanceof ProgramGenerator) && mode !== "program") {
50
- throw new ToolRuntimeError("InvalidDataValue", `${label} must contain data only.`);
51
- }
52
- if (protos !== undefined && mode === "program") {
53
- if (value instanceof ProgramObject)
18
+ export const toBoundary = (ctx, value) => walk(ctx, value, undefined, true);
19
+ const walk = (ctx, value, replacer, boundary) => {
20
+ const stack = new Set();
21
+ const visit = (holder, key, depth) => Effect.gen(function* () {
22
+ if (depth > MAX_VALUE_DEPTH)
23
+ throw rangeError(`Value exceeds the maximum depth of ${MAX_VALUE_DEPTH}.`);
24
+ const raw = get(holder, key);
25
+ if (raw instanceof PromiseObj && !boundary) {
26
+ throw invalidData("JSON.stringify received an un-awaited Promise; await it first - e.g. `const result = await tools.ns.tool(...)`.");
27
+ }
28
+ const settled = raw instanceof PromiseObj ? yield* ctx.await(raw) : raw;
29
+ const toJSON = settled instanceof Obj ? get(settled, "toJSON") : undefined;
30
+ const own = toJSON instanceof Callable ? yield* ctx.call(toJSON, settled, [key]) : settled;
31
+ const value = replacer === undefined ? own : yield* replacer([key, own]);
32
+ if (value === undefined || typeofValue(value) === "function")
33
+ return undefined;
34
+ if (typeof value === "number")
35
+ return Number.isFinite(value) ? value : null;
36
+ if (value === null || typeof value === "string" || typeof value === "boolean")
54
37
  return value;
55
- if (value instanceof Date)
56
- return new ProgramDate(protos.Date, value.getTime());
57
- if (value instanceof RegExp)
58
- return new ProgramRegExp(protos.RegExp, value.source, value.flags);
59
- if (value instanceof Map) {
60
- const wrapped = new ProgramMap(protos.Map);
61
- for (const [key, item] of value.entries())
62
- wrapped.map.set(next(key), next(item));
63
- return wrapped;
38
+ if (!(value instanceof Obj))
39
+ return {};
40
+ if (boundary && value instanceof Bytes) {
41
+ throw invalidData("A Uint8Array cannot cross to the host; pass text instead, e.g. `new TextDecoder().decode(bytes)` or `bytes.toBase64()`.");
64
42
  }
65
- if (value instanceof Set) {
66
- const wrapped = new ProgramSet(protos.Set);
67
- for (const item of value.values())
68
- wrapped.set.add(next(item));
69
- return wrapped;
43
+ if (boundary && value instanceof URLSearchParamsObj)
44
+ return value.params.toString();
45
+ const target = boundary && value instanceof SetObj ? new Arr(ctx.builtins.Array, [...value.set]) : value;
46
+ if (stack.has(target))
47
+ throw typeError("Converting circular structure to JSON.");
48
+ stack.add(target);
49
+ if (target instanceof Arr) {
50
+ const items = [];
51
+ for (let index = 0; index < target.items.length; index += 1) {
52
+ items.push((yield* visit(target, String(index), depth + 1)) ?? null);
53
+ }
54
+ stack.delete(target);
55
+ return items;
70
56
  }
71
- if (value instanceof URL)
72
- return new ProgramURL(protos.URL, protos.URLSearchParams, new URL(value.href));
73
- if (value instanceof URLSearchParams)
74
- return new ProgramURLSearchParams(protos.URLSearchParams, new URLSearchParams(value));
75
- }
76
- if (value instanceof ProgramDate)
77
- return Number.isFinite(value.time) ? new Date(value.time).toISOString() : null;
78
- if (value instanceof Date)
79
- return Number.isFinite(value.getTime()) ? value.toISOString() : null;
80
- if (value instanceof ProgramURL)
81
- return value.url.href;
82
- if (value instanceof URL)
83
- return value.href;
84
- // Remaining wrappers and their host counterparts serialize as empty objects, like JSON.stringify.
85
- if (isWrapper(value) ||
86
- value instanceof RegExp ||
87
- value instanceof Map ||
88
- value instanceof Set ||
89
- value instanceof URLSearchParams) {
90
- return protos !== undefined ? new ProgramObject(protos.Object) : {};
91
- }
92
- if (seen.has(value)) {
93
- throw new ToolRuntimeError("InvalidDataValue", `${label} contains a circular value.`);
94
- }
95
- seen.add(value);
96
- if (value instanceof ProgramArray) {
97
- const copied = Array.from(value.items, (item) => next(item) ?? null);
98
- seen.delete(value);
99
- return copied;
100
- }
101
- if (value instanceof ProgramObject) {
102
57
  const copied = {};
58
+ // Own data property regardless of the key, so "__proto__" never reaches the Object.prototype setter.
59
+ const put = (name, item) => {
60
+ if (item !== undefined)
61
+ Object.defineProperty(copied, name, { value: item, enumerable: true, writable: true, configurable: true });
62
+ };
103
63
  // Errors serialize as { name, message, ...own }: both may be inherited, and neither is enumerable in JS.
104
- if (value instanceof ProgramError) {
105
- defineHost(copied, "name", next(get(value, "name")));
106
- defineHost(copied, "message", next(get(value, "message")));
64
+ if (target instanceof ErrorObj) {
65
+ put("name", yield* visit(target, "name", depth + 1));
66
+ put("message", yield* visit(target, "message", depth + 1));
107
67
  }
108
- for (const [key, item] of entries(value)) {
109
- const copiedItem = next(item);
110
- if (copiedItem === undefined && mode === "json")
68
+ for (const name of keys(target)) {
69
+ if (boundary && name === "__proto__")
111
70
  continue;
112
- defineHost(copied, key, copiedItem);
71
+ put(name, yield* visit(target, name, depth + 1));
113
72
  }
114
- seen.delete(value);
73
+ stack.delete(target);
115
74
  return copied;
116
- }
117
- if (Array.isArray(value)) {
118
- if (protos !== undefined) {
119
- const copied = new ProgramArray(protos.Array, value.map(next));
120
- for (const [key, item] of Object.entries(value)) {
121
- if (parseArrayIndex(key) === undefined)
122
- define(copied, key, next(item));
123
- }
124
- seen.delete(value);
125
- return copied;
126
- }
127
- const copied = Array.from(value, (item) => next(item) ?? null);
128
- seen.delete(value);
129
- return copied;
130
- }
131
- const prototype = Object.getPrototypeOf(value);
132
- if (prototype !== Object.prototype && prototype !== null) {
133
- throw new ToolRuntimeError("InvalidDataValue", `${label} must contain plain objects only.`);
134
- }
135
- if (protos !== undefined) {
136
- const copied = new ProgramObject(protos.Object);
137
- for (const [key, item] of Object.entries(value))
138
- define(copied, key, next(item));
139
- seen.delete(value);
140
- return copied;
141
- }
142
- const copied = {};
143
- for (const [key, item] of Object.entries(value)) {
144
- const copiedItem = next(item);
145
- if (copiedItem === undefined && mode === "json")
146
- continue;
147
- defineHost(copied, key, copiedItem);
148
- }
149
- seen.delete(value);
150
- return copied;
75
+ });
76
+ return visit(record(ctx.builtins.Object, { "": value }), "", 0);
151
77
  };
152
- // Own data property regardless of the target's prototype, so a "__proto__" key on a host object
153
- // never reaches the Object.prototype setter.
154
- const defineHost = (target, key, value) => {
155
- Object.defineProperty(target, key, { value, enumerable: true, writable: true, configurable: true });
78
+ /** Host JSON as program values: objects and arrays are copied, primitives pass through. */
79
+ export const fromJson = (ctx, value) => {
80
+ if (value === null || typeof value !== "object")
81
+ return value;
82
+ if (Array.isArray(value))
83
+ return new Arr(ctx.builtins.Array, value.map((item) => fromJson(ctx, item)));
84
+ const copied = new Obj(ctx.builtins.Object);
85
+ for (const [key, item] of Object.entries(value))
86
+ define(copied, key, fromJson(ctx, item));
87
+ return copied;
156
88
  };
@@ -0,0 +1,11 @@
1
+ export * as Extension from "./extension.js";
2
+ /**
3
+ * Host functions a program calls directly as globals. Values crossing in either direction are converted, never
4
+ * shared: arguments come in as copies, results go out as copies, and a function inside a result is callable the
5
+ * same way. Extension calls are not tool calls.
6
+ */
7
+ export type Extension = {
8
+ readonly name: string;
9
+ readonly globals: Readonly<Record<string, Function>>;
10
+ };
11
+ export declare const make: (options: Extension) => Extension;
@@ -0,0 +1,9 @@
1
+ export * as Extension from "./extension.js";
2
+ export const make = (options) => {
3
+ for (const [name, value] of Object.entries(options.globals)) {
4
+ if (typeof value !== "function") {
5
+ throw new TypeError(`Extension "${options.name}" global "${name}" must be a function.`);
6
+ }
7
+ }
8
+ return { name: options.name, globals: { ...options.globals } };
9
+ };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * as CodeMode from "./codemode.js";
2
+ export * as Extension from "./extension.js";
2
3
  export * as Namespace from "./namespace.js";
3
4
  export * as Tool from "./tool.js";
4
5
  export * as OpenAPI from "./openapi/index.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * as CodeMode from "./codemode.js";
2
+ export * as Extension from "./extension.js";
2
3
  export * as Namespace from "./namespace.js";
3
4
  export * as Tool from "./tool.js";
4
5
  export * as OpenAPI from "./openapi/index.js";
@@ -0,0 +1,20 @@
1
+ import { Effect } from "effect";
2
+ import type { Interpreter } from "./interpreter.js";
3
+ import { Callable } from "./objects.js";
4
+ export type IteratorCursor<R> = {
5
+ readonly next: Effect.Effect<{
6
+ readonly done: boolean;
7
+ readonly value: unknown;
8
+ }, unknown, R>;
9
+ readonly close: Effect.Effect<void, unknown, R>;
10
+ };
11
+ export declare const preserveConsumerError: <A, R>(cursor: IteratorCursor<R>, effect: Effect.Effect<A, unknown, R>) => Effect.Effect<A, unknown, R>;
12
+ /**
13
+ * ToPrimitive: calls `valueOf`/`toString` in hint order and returns the first primitive result. Dates treat the
14
+ * default hint as "string", like their `Symbol.toPrimitive`.
15
+ */
16
+ export declare const toPrimitive: <R>(ctx: Interpreter<R>, value: unknown, hint: "number" | "string" | "default") => Effect.Effect<unknown, unknown, R>;
17
+ export declare const toPrimitiveString: <R>(ctx: Interpreter<R>, value: unknown) => Effect.Effect<string, unknown, R>;
18
+ export declare const toPrimitiveNumber: <R>(ctx: Interpreter<R>, value: unknown) => Effect.Effect<number, unknown, R>;
19
+ export declare const isSupportedCallback: (value: unknown) => value is Callable;
20
+ export declare const applyCollectionCallback: <R>(ctx: Interpreter<R>, callback: unknown, name: string) => ((args: Array<unknown>) => Effect.Effect<unknown, unknown, R>);
@@ -1,7 +1,7 @@
1
1
  import { Effect, Exit } from "effect";
2
2
  import { coerceToNumber, coerceToString } from "../stdlib/value.js";
3
- import { InterpreterRuntimeError } from "./model.js";
4
- import { Callable, get, NativeFunction, ProgramDate, ProgramObject, ProgramPromise } from "./objects.js";
3
+ import { typeError } from "./model.js";
4
+ import { Callable, get, Native, DateObj, Obj } from "./objects.js";
5
5
  import { typeofValue } from "./references.js";
6
6
  export const preserveConsumerError = (cursor, effect) => Effect.flatMap(Effect.exit(effect), (exit) => Exit.isSuccess(exit)
7
7
  ? Effect.succeed(exit.value)
@@ -10,36 +10,36 @@ export const preserveConsumerError = (cursor, effect) => Effect.flatMap(Effect.e
10
10
  * ToPrimitive: calls `valueOf`/`toString` in hint order and returns the first primitive result. Dates treat the
11
11
  * default hint as "string", like their `Symbol.toPrimitive`.
12
12
  */
13
- export const toPrimitive = (runner, value, hint, node) => {
14
- if (!(value instanceof ProgramObject))
13
+ export const toPrimitive = (ctx, value, hint) => {
14
+ if (!(value instanceof Obj))
15
15
  return Effect.succeed(value);
16
- const asString = hint === "string" || (hint === "default" && value instanceof ProgramDate);
16
+ const asString = hint === "string" || (hint === "default" && value instanceof DateObj);
17
17
  const order = asString ? ["toString", "valueOf"] : ["valueOf", "toString"];
18
18
  return Effect.gen(function* () {
19
19
  for (const method of order) {
20
20
  const callable = get(value, method);
21
21
  if (!(callable instanceof Callable))
22
22
  continue;
23
- const result = yield* runner.invokeCallable(callable, value, [], node);
23
+ const result = yield* ctx.call(callable, value, []);
24
24
  if (result === null || (typeof result !== "object" && typeof result !== "function"))
25
25
  return result;
26
26
  }
27
- throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node);
27
+ throw typeError("Cannot convert object to primitive value.");
28
28
  });
29
29
  };
30
- export const toPrimitiveString = (runner, value, node) => Effect.map(toPrimitive(runner, value, "string", node), coerceToString);
31
- export const toPrimitiveNumber = (runner, value, node) => Effect.map(toPrimitive(runner, value, "number", node), coerceToNumber);
30
+ export const toPrimitiveString = (ctx, value) => Effect.map(toPrimitive(ctx, value, "string"), coerceToString);
31
+ export const toPrimitiveNumber = (ctx, value) => Effect.map(toPrimitive(ctx, value, "number"), coerceToNumber);
32
32
  // The single acceptance list for callbacks: collections, sort, string replacers,
33
33
  // Array.from mappers, and promise reactions all admit exactly these callables.
34
34
  // Admission means dispatchable, not necessarily invocable: new-requiring
35
35
  // constructors pass the gate and throw a TypeError on call, like JS.
36
- export const isSupportedCallback = (value) => value instanceof Callable && !(value instanceof NativeFunction && !value.callback);
37
- export const applyCollectionCallback = (runner, callback, name, node) => {
36
+ export const isSupportedCallback = (value) => value instanceof Callable && !(value instanceof Native && !value.callback);
37
+ export const applyCollectionCallback = (ctx, callback, name) => {
38
38
  if (!isSupportedCallback(callback)) {
39
39
  if (typeofValue(callback) === "function") {
40
- throw new InterpreterRuntimeError(`${name} cannot use this callable as a callback; wrap it in an arrow function, e.g. (value) => tools.ns.tool(value).`, node);
40
+ throw typeError(`${name} cannot use this callable as a callback; wrap it in an arrow function, e.g. (value) => tools.ns.tool(value).`);
41
41
  }
42
- throw new InterpreterRuntimeError(`${name} expects a function callback.`, node);
42
+ throw typeError(`${name} expects a function callback.`);
43
43
  }
44
- return (callbackArgs) => runner.invokeCallable(callback, undefined, callbackArgs, node);
44
+ return (callbackArgs) => ctx.call(callback, undefined, callbackArgs);
45
45
  };
@@ -1,9 +1,16 @@
1
1
  import type { Diagnostic } from "../codemode.js";
2
+ import { type AstNode } from "./model.js";
2
3
  import { type ErrorType } from "./intrinsics.js";
3
- import { type NativeFunction, ProgramError, ProgramObject } from "./objects.js";
4
- import { type Runner } from "./runner.js";
4
+ import { type Native, ErrorObj, Obj } from "./objects.js";
5
+ import type { Interpreter } from "./interpreter.js";
5
6
  export declare const normalizeError: (error: unknown) => Diagnostic;
6
- export declare const caughtErrorValue: <R>(runner: Runner<R>, thrown: unknown) => unknown;
7
- export declare const createAggregateErrorValue: <R>(runner: Runner<R>, errors: Array<unknown>, message: string, proto?: ProgramObject) => ProgramError;
7
+ /**
8
+ * Gives a failure the source location of the expression that raised it, keeping the first one attached. Host errors
9
+ * that escape a built-in become the equivalent program error here.
10
+ */
11
+ export declare const locate: (error: unknown, node?: AstNode) => unknown;
12
+ /** The program value a handler receives for a failure; one failure always yields the same value. */
13
+ export declare const materialize: <R>(ctx: Interpreter<R>, thrown: unknown) => unknown;
14
+ export declare const createAggregateErrorValue: <R>(ctx: Interpreter<R>, errors: Array<unknown>, message: string, proto?: Obj) => ErrorObj;
8
15
  /** An error constructor such as `Error` or `TypeError`; callable with or without `new`, like JS. */
9
- export declare const errorGlobal: <R>(type: ErrorType, runner: Runner<R>) => NativeFunction<R>;
16
+ export declare const errorGlobal: <R>(type: ErrorType, ctx: Interpreter<R>) => Native<R>;