@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.
Files changed (62) hide show
  1. package/dist/data.d.ts +5 -6
  2. package/dist/data.js +44 -47
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +1 -0
  5. package/dist/interpreter/errors.d.ts +3 -5
  6. package/dist/interpreter/errors.js +22 -51
  7. package/dist/interpreter/execute.js +3 -5
  8. package/dist/interpreter/globals.js +47 -69
  9. package/dist/interpreter/host.d.ts +41 -0
  10. package/dist/interpreter/host.js +44 -0
  11. package/dist/interpreter/methods.d.ts +4 -0
  12. package/dist/interpreter/methods.js +837 -0
  13. package/dist/interpreter/model.d.ts +36 -13
  14. package/dist/interpreter/model.js +45 -15
  15. package/dist/interpreter/objects.d.ts +13 -106
  16. package/dist/interpreter/objects.js +65 -192
  17. package/dist/interpreter/promises.d.ts +13 -12
  18. package/dist/interpreter/promises.js +54 -59
  19. package/dist/interpreter/references.d.ts +0 -1
  20. package/dist/interpreter/references.js +33 -20
  21. package/dist/interpreter/runner.d.ts +11 -15
  22. package/dist/interpreter/runner.js +21 -21
  23. package/dist/interpreter/runtime.d.ts +3 -3
  24. package/dist/interpreter/runtime.js +327 -165
  25. package/dist/interpreter/scope.js +6 -6
  26. package/dist/stdlib/array.d.ts +2 -4
  27. package/dist/stdlib/array.js +32 -424
  28. package/dist/stdlib/collections.d.ts +7 -3
  29. package/dist/stdlib/collections.js +119 -291
  30. package/dist/stdlib/console.d.ts +2 -3
  31. package/dist/stdlib/console.js +30 -35
  32. package/dist/stdlib/date.d.ts +7 -1
  33. package/dist/stdlib/date.js +188 -93
  34. package/dist/stdlib/json.d.ts +2 -2
  35. package/dist/stdlib/json.js +27 -27
  36. package/dist/stdlib/math.d.ts +2 -2
  37. package/dist/stdlib/math.js +76 -96
  38. package/dist/stdlib/number.d.ts +4 -3
  39. package/dist/stdlib/number.js +60 -95
  40. package/dist/stdlib/object.d.ts +4 -4
  41. package/dist/stdlib/object.js +54 -128
  42. package/dist/stdlib/regexp.d.ts +8 -6
  43. package/dist/stdlib/regexp.js +68 -76
  44. package/dist/stdlib/string.d.ts +2 -2
  45. package/dist/stdlib/string.js +50 -213
  46. package/dist/stdlib/url.d.ts +13 -5
  47. package/dist/stdlib/url.js +102 -202
  48. package/dist/stdlib/value.d.ts +9 -5
  49. package/dist/stdlib/value.js +38 -16
  50. package/dist/stdlib/web.d.ts +4 -4
  51. package/dist/stdlib/web.js +10 -12
  52. package/dist/tool-runtime.d.ts +1 -2
  53. package/dist/tool-runtime.js +2 -2
  54. package/dist/values.d.ts +37 -0
  55. package/dist/values.js +56 -0
  56. package/package.json +1 -1
  57. package/dist/interpreter/generators.d.ts +0 -4
  58. package/dist/interpreter/generators.js +0 -25
  59. package/dist/interpreter/intrinsics.d.ts +0 -13
  60. package/dist/interpreter/intrinsics.js +0 -82
  61. package/dist/interpreter/native.d.ts +0 -19
  62. package/dist/interpreter/native.js +0 -40
@@ -1,30 +1,31 @@
1
1
  import { Effect, Exit, Scope } from "effect";
2
2
  import type { Diagnostic } from "../codemode.js";
3
- import { type AstNode, InterpreterRuntimeError } from "./model.js";
4
- import { ProgramObject, ProgramPromise } from "./objects.js";
3
+ import { type AstNode, InterpreterRuntimeError, PromiseInstanceMethodReference } from "./model.js";
4
+ import { HostFunction } from "./host.js";
5
+ import { Values } from "../values.js";
5
6
  import { type Runner } from "./runner.js";
6
7
  export declare class PromiseRuntime<R> {
7
8
  private readonly scope;
8
- private readonly proto;
9
9
  private readonly active;
10
10
  private readonly ids;
11
11
  private readonly observed;
12
12
  private readonly failures;
13
13
  private nextID;
14
- constructor(scope: Scope.Scope, proto: ProgramObject);
14
+ constructor(scope: Scope.Scope);
15
15
  createWithSelf(body: (self: {
16
- promise?: ProgramPromise;
17
- }) => Effect.Effect<unknown, unknown, R>): Effect.Effect<ProgramPromise, never, R>;
18
- create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<ProgramPromise, never, R>;
19
- markObserved(promise: ProgramPromise): void;
20
- await(promise: ProgramPromise): Effect.Effect<Exit.Exit<unknown, unknown>>;
16
+ promise?: Values.Promise;
17
+ }) => Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
18
+ create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
19
+ markObserved(promise: Values.Promise): void;
20
+ await(promise: Values.Promise): Effect.Effect<Exit.Exit<unknown, unknown>>;
21
21
  fork(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<void, never, R>;
22
22
  diagnostics(): Array<Diagnostic>;
23
23
  interrupt(): Effect.Effect<Array<Diagnostic>>;
24
24
  }
25
25
  export declare const selfResolutionError: (node?: AstNode) => InterpreterRuntimeError;
26
26
  export declare const resolvePromiseValue: <R>(runner: Runner<R>, value: unknown, node: AstNode, own?: {
27
- promise?: ProgramPromise;
27
+ promise?: Values.Promise;
28
28
  }) => Effect.Effect<unknown, unknown, R>;
29
- export declare const resolvePromise: <R>(runner: Runner<R>, promises: PromiseRuntime<R>, value: unknown, node: AstNode) => Effect.Effect<ProgramPromise, never, R>;
30
- export declare const promiseGlobal: <R>(runner: Runner<R>, promises: PromiseRuntime<R>) => import("./objects.js").NativeFunction<R>;
29
+ export declare const resolvePromise: <R>(runner: Runner<R>, promises: PromiseRuntime<R>, value: unknown, node: AstNode) => Effect.Effect<Values.Promise, never, R>;
30
+ export declare const invokePromiseInstanceMethod: <R>(runner: Runner<R>, promises: PromiseRuntime<R>, ref: PromiseInstanceMethodReference, args: Array<unknown>, node: AstNode) => Effect.Effect<Values.Promise, never, R>;
31
+ export declare const promiseGlobal: <R>(runner: Runner<R>, promises: PromiseRuntime<R>) => HostFunction<R>;
@@ -1,27 +1,27 @@
1
1
  import { Cause, Deferred, Effect, Exit, Fiber, Scope } from "effect";
2
- import { InterpreterRuntimeError, ProgramThrow } from "./model.js";
3
- import { Callable, define, get, hidden, ProgramArray, ProgramFunction, ProgramObject, ProgramPromise, record, } from "./objects.js";
4
- import { constructor, fn, methods, native, receiver, requiresNew } from "./native.js";
5
- import { caughtErrorValue, createAggregateErrorValue, normalizeError } from "./errors.js";
2
+ import { InterpreterRuntimeError, ProgramThrow, PromiseInstanceMethodReference } from "./model.js";
3
+ import { get, ProgramArray, ProgramFunction, ProgramObject, record } from "./objects.js";
4
+ import { HostFunction, requiresNew, sync } from "./host.js";
5
+ import { caughtErrorValue, normalizeError } from "./errors.js";
6
6
  import { typeofValue } from "./references.js";
7
+ import { createAggregateErrorValue } from "../stdlib/value.js";
8
+ import { Values } from "../values.js";
7
9
  import { applyCollectionCallback, isSupportedCallback } from "./runner.js";
8
10
  // A `resolve`/`reject` handed to an executor or thenable: calling it settles the capability.
9
- const capability = (runner, name, settle) => fn(runner.prototypes, name, 1, (_, args) => {
11
+ const capability = (name, settle) => sync(name, (args) => {
10
12
  settle(args[0]);
11
13
  return undefined;
12
14
  });
13
15
  // Observation only controls rejection reporting; program completion interrupts all promise work.
14
16
  export class PromiseRuntime {
15
17
  scope;
16
- proto;
17
18
  active = new Set();
18
19
  ids = new WeakMap();
19
20
  observed = new WeakSet();
20
21
  failures = new Map();
21
22
  nextID = 0;
22
- constructor(scope, proto) {
23
+ constructor(scope) {
23
24
  this.scope = scope;
24
- this.proto = proto;
25
25
  }
26
26
  // Resolution bodies need the promise's own identity to reject `resolve(promise)` self-resolution.
27
27
  createWithSelf(body) {
@@ -36,7 +36,7 @@ export class PromiseRuntime {
36
36
  // Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
37
37
  const id = this.nextID++;
38
38
  return Effect.map(Effect.forkIn(effect, this.scope, { startImmediately: true }), (fiber) => {
39
- const promise = new ProgramPromise(this.proto, fiber);
39
+ const promise = new Values.Promise(fiber);
40
40
  this.active.add(promise);
41
41
  this.ids.set(promise, id);
42
42
  fiber.addObserver((exit) => {
@@ -83,11 +83,11 @@ export class PromiseRuntime {
83
83
  });
84
84
  }
85
85
  }
86
- export const selfResolutionError = (node) => new InterpreterRuntimeError("Chaining cycle detected: a promise cannot resolve with itself.", node);
86
+ export const selfResolutionError = (node) => new InterpreterRuntimeError("Chaining cycle detected: a promise cannot resolve with itself.", node).as("TypeError");
87
87
  export const resolvePromiseValue = (runner, value, node, own) => {
88
88
  if (own?.promise !== undefined && value === own.promise)
89
89
  return Effect.fail(selfResolutionError(node));
90
- if (value instanceof ProgramPromise)
90
+ if (value instanceof Values.Promise)
91
91
  return runner.settlePromise(value);
92
92
  if (!(value instanceof ProgramObject))
93
93
  return Effect.succeed(value);
@@ -98,9 +98,9 @@ export const resolvePromiseValue = (runner, value, node, own) => {
98
98
  // Promise resolution invokes a thenable's method in a later job.
99
99
  yield* Effect.yieldNow;
100
100
  const deferred = Deferred.makeUnsafe();
101
- const resolve = capability(runner, "resolve", (result) => Deferred.doneUnsafe(deferred, Exit.succeed(result)));
102
- const reject = capability(runner, "reject", (reason) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(reason))));
103
- const executed = yield* Effect.exit(runner.invokeCallable(then, value, [resolve, reject], node));
101
+ const resolve = capability("resolve", (result) => Deferred.doneUnsafe(deferred, Exit.succeed(result)));
102
+ const reject = capability("reject", (reason) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(reason))));
103
+ const executed = yield* Effect.exit(runner.invokeCallable(then, [resolve, reject], node));
104
104
  if (!Exit.isSuccess(executed)) {
105
105
  if (Cause.hasInterruptsOnly(executed.cause))
106
106
  return yield* Effect.failCause(executed.cause);
@@ -110,7 +110,7 @@ export const resolvePromiseValue = (runner, value, node, own) => {
110
110
  });
111
111
  };
112
112
  export const resolvePromise = (runner, promises, value, node) => {
113
- if (value instanceof ProgramPromise)
113
+ if (value instanceof Values.Promise)
114
114
  return Effect.succeed(value);
115
115
  return promises.createWithSelf((self) => resolvePromiseValue(runner, value, node, self));
116
116
  };
@@ -125,7 +125,7 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
125
125
  return promises.create(Effect.gen(function* () {
126
126
  const cursor = yield* runner.syncIterator(args[0], node);
127
127
  if (cursor === undefined) {
128
- throw new InterpreterRuntimeError(`Promise.${name} expects an array or other synchronous iterable.`, node);
128
+ throw new InterpreterRuntimeError(`Promise.${name} expects an array or other synchronous iterable.`, node).as("TypeError");
129
129
  }
130
130
  const items = [];
131
131
  while (true) {
@@ -137,25 +137,22 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
137
137
  items.push(item);
138
138
  }
139
139
  if (name === "all") {
140
- return new ProgramArray(runner.prototypes.Array, yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" })));
140
+ return new ProgramArray(yield* settleAfterTurn(Effect.all(items.map((item) => Effect.flatten(promises.await(item))), { concurrency: "unbounded" })));
141
141
  }
142
142
  if (name === "allSettled") {
143
143
  const outcomes = [];
144
144
  for (const item of items) {
145
145
  const exit = yield* promises.await(item);
146
146
  if (Exit.isSuccess(exit)) {
147
- outcomes.push(record(runner.prototypes.Object, { status: "fulfilled", value: exit.value }));
147
+ outcomes.push(record({ status: "fulfilled", value: exit.value }));
148
148
  continue;
149
149
  }
150
150
  if (Cause.hasInterruptsOnly(exit.cause))
151
151
  return yield* Effect.failCause(exit.cause);
152
- outcomes.push(record(runner.prototypes.Object, {
153
- status: "rejected",
154
- reason: caughtErrorValue(runner, Cause.squash(exit.cause)),
155
- }));
152
+ outcomes.push(record({ status: "rejected", reason: caughtErrorValue(Cause.squash(exit.cause)) }));
156
153
  }
157
154
  yield* Effect.yieldNow;
158
- return new ProgramArray(runner.prototypes.Array, outcomes);
155
+ return new ProgramArray(outcomes);
159
156
  }
160
157
  if (name === "race") {
161
158
  if (items.length === 0) {
@@ -168,32 +165,31 @@ const invokePromiseMethod = (runner, promises, name, args, node) => {
168
165
  return Effect.fail(new PromiseAnyFulfilled(exit.value));
169
166
  if (Cause.hasInterruptsOnly(exit.cause))
170
167
  return Effect.failCause(exit.cause);
171
- return Effect.succeed(caughtErrorValue(runner, Cause.squash(exit.cause)));
168
+ return Effect.succeed(caughtErrorValue(Cause.squash(exit.cause)));
172
169
  }));
173
- return yield* settleAfterTurn(Effect.all(flipped, { concurrency: "unbounded" }).pipe(Effect.flatMap((reasons) => Effect.fail(new ProgramThrow(createAggregateErrorValue(runner, reasons, "All promises were rejected")))), Effect.catch((error) => error instanceof PromiseAnyFulfilled ? Effect.succeed(error.value) : Effect.fail(error))));
170
+ return yield* settleAfterTurn(Effect.all(flipped, { concurrency: "unbounded" }).pipe(Effect.flatMap((reasons) => Effect.fail(new ProgramThrow(createAggregateErrorValue(reasons, "All promises were rejected")))), Effect.catch((error) => error instanceof PromiseAnyFulfilled ? Effect.succeed(error.value) : Effect.fail(error))));
174
171
  }));
175
172
  };
176
- const instanceMethod = (runner, promises, name, thisValue, args, node) => {
177
- const method = `Promise.prototype.${name}`;
178
- const promise = receiver(ProgramPromise, thisValue, method, node);
179
- promises.markObserved(promise);
180
- if (name === "finally") {
181
- return chainFinally(runner, promises, promise, reactionHandler(args[0], method, node), method, node);
173
+ export const invokePromiseInstanceMethod = (runner, promises, ref, args, node) => {
174
+ const method = `Promise.prototype.${ref.name}`;
175
+ promises.markObserved(ref.promise);
176
+ if (ref.name === "finally") {
177
+ return chainFinally(runner, promises, ref.promise, reactionHandler(args[0], method, node), method, node);
182
178
  }
183
- const onFulfilled = name === "then" ? reactionHandler(args[0], method, node) : undefined;
184
- const onRejected = reactionHandler(name === "then" ? args[1] : args[0], method, node);
185
- return chainReaction(runner, promises, promise, onFulfilled, onRejected, method, node);
179
+ const onFulfilled = ref.name === "then" ? reactionHandler(args[0], method, node) : undefined;
180
+ const onRejected = reactionHandler(ref.name === "then" ? args[1] : args[0], method, node);
181
+ return chainReaction(runner, promises, ref.promise, onFulfilled, onRejected, method, node);
186
182
  };
187
183
  const constructPromise = (runner, promises, executor, node) => {
188
184
  if (!(executor instanceof ProgramFunction)) {
189
- throw new InterpreterRuntimeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).", node);
185
+ throw new InterpreterRuntimeError("new Promise(...) expects an executor function (e.g. new Promise((resolve, reject) => { ... })).", node).as("TypeError");
190
186
  }
191
187
  return Effect.gen(function* () {
192
188
  const deferred = Deferred.makeUnsafe();
193
189
  const promise = yield* promises.createWithSelf((self) => Effect.flatMap(Deferred.await(deferred), (value) => resolvePromiseValue(runner, value, node, self)));
194
- const resolve = capability(runner, "resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
195
- const reject = capability(runner, "reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(value))));
196
- const executed = yield* Effect.exit(runner.invokeCallable(executor, undefined, [resolve, reject], node));
190
+ const resolve = capability("resolve", (value) => Deferred.doneUnsafe(deferred, Exit.succeed(value)));
191
+ const reject = capability("reject", (value) => Deferred.doneUnsafe(deferred, Exit.fail(new ProgramThrow(value))));
192
+ const executed = yield* Effect.exit(runner.invokeFunction(executor, [resolve, reject]));
197
193
  if (!Exit.isSuccess(executed)) {
198
194
  if (Cause.hasInterruptsOnly(executed.cause))
199
195
  return yield* Effect.failCause(executed.cause);
@@ -232,7 +228,7 @@ const chainReaction = (runner, promises, source, onFulfilled, onRejected, method
232
228
  const handler = Exit.isSuccess(exit) ? onFulfilled : onRejected;
233
229
  if (handler === undefined)
234
230
  return yield* exit;
235
- const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(runner, Cause.squash(exit.cause));
231
+ const input = Exit.isSuccess(exit) ? exit.value : caughtErrorValue(Cause.squash(exit.cause));
236
232
  const result = yield* applyCollectionCallback(runner, handler, method, node)([input]);
237
233
  return yield* resolvePromiseValue(runner, result, node, self);
238
234
  }));
@@ -250,27 +246,26 @@ const chainFinally = (runner, promises, source, cleanup, method, node) => promis
250
246
  return yield* exit;
251
247
  }));
252
248
  export const promiseGlobal = (runner, promises) => {
253
- const protos = runner.prototypes;
254
- const proto = protos.Promise;
255
- const promise = constructor(protos, proto, {
249
+ // Combinators are not callbacks: `[p].map(Promise.resolve)` must ask for an arrow function.
250
+ const statics = new Map(promiseStatics.map((name) => [
251
+ name,
252
+ new HostFunction({
253
+ name: `Promise.${name}`,
254
+ call: (args, node) => invokePromiseMethod(runner, promises, name, args, node),
255
+ callback: false,
256
+ }),
257
+ ]));
258
+ return new HostFunction({
256
259
  name: "Promise",
257
- length: 1,
258
260
  call: requiresNew("Promise"),
259
- construct: (args, _, node) => constructPromise(runner, promises, args[0], node),
261
+ construct: (args, node) => constructPromise(runner, promises, args[0], node),
262
+ instanceOf: (value) => value instanceof Values.Promise,
263
+ // Unknown statics fail loudly so a missing await cannot hide behind `undefined`.
264
+ members: (key, node) => {
265
+ const method = typeof key === "string" ? statics.get(key) : undefined;
266
+ if (method !== undefined)
267
+ return method;
268
+ throw new InterpreterRuntimeError(`Promise.${String(key)} is not available. Available: Promise.all, Promise.allSettled, Promise.race, Promise.any, Promise.resolve, and Promise.reject; consume promises with await.`, node);
269
+ },
260
270
  });
261
- // Combinators are not callbacks: `[p].map(Promise.resolve)` must ask for an arrow function.
262
- for (const name of promiseStatics) {
263
- define(promise, name, native(protos, {
264
- name,
265
- length: 1,
266
- call: (_, args, node) => invokePromiseMethod(runner, promises, name, args, node),
267
- callback: false,
268
- }), hidden);
269
- }
270
- methods(protos, proto, [
271
- ["then", 2, (thisValue, args, node) => instanceMethod(runner, promises, "then", thisValue, args, node)],
272
- ["catch", 1, (thisValue, args, node) => instanceMethod(runner, promises, "catch", thisValue, args, node)],
273
- ["finally", 1, (thisValue, args, node) => instanceMethod(runner, promises, "finally", thisValue, args, node)],
274
- ]);
275
- return promise;
276
271
  };
@@ -1,5 +1,4 @@
1
1
  import { type AstNode } from "./model.js";
2
- /** Values that cannot cross the data boundary. */
3
2
  export declare const isRuntimeReference: (value: unknown) => boolean;
4
3
  export declare const containsRuntimeReference: (value: unknown) => boolean;
5
4
  export declare const containsOpaqueReference: (value: unknown) => boolean;
@@ -1,12 +1,18 @@
1
1
  import { ToolReference } from "../tool-runtime.js";
2
- import { InterpreterRuntimeError } from "./model.js";
3
- import { Callable, getOwn, isWrapper, ownKeys, ProgramArray, ProgramDate, ProgramGenerator, ProgramMap, ProgramObject, ProgramPromise, ProgramRegExp, ProgramSet, ProgramURL, ProgramURLSearchParams, } from "./objects.js";
4
- /** Values that cannot cross the data boundary. */
5
- export const isRuntimeReference = (value) => value instanceof Callable ||
6
- value instanceof ProgramGenerator ||
2
+ import { Values } from "../values.js";
3
+ import { HostFunction, HostNamespace } from "./host.js";
4
+ import { CodeModeGenerator, GeneratorMethodReference, InterpreterRuntimeError, IntrinsicReference, PromiseInstanceMethodReference, } from "./model.js";
5
+ import { getOwn, ownKeys, ProgramArray, ProgramFunction, ProgramObject } from "./objects.js";
6
+ export const isRuntimeReference = (value) => value instanceof HostFunction ||
7
+ value instanceof HostNamespace ||
8
+ value instanceof ProgramFunction ||
9
+ value instanceof CodeModeGenerator ||
10
+ value instanceof GeneratorMethodReference ||
7
11
  value instanceof ToolReference ||
8
- value instanceof ProgramPromise ||
9
- isWrapper(value);
12
+ value instanceof IntrinsicReference ||
13
+ value instanceof PromiseInstanceMethodReference ||
14
+ value instanceof Values.Promise ||
15
+ Values.isValue(value);
10
16
  function* childValues(value) {
11
17
  if (!(value instanceof ProgramObject))
12
18
  return;
@@ -34,8 +40,8 @@ const find = (value, match, skip, seen) => {
34
40
  };
35
41
  const never = () => false;
36
42
  export const containsRuntimeReference = (value) => find(value, isRuntimeReference, never, new Set());
37
- // Wrapper values are data here, not opaque interpreter references.
38
- export const containsOpaqueReference = (value) => find(value, (current) => !isWrapper(current) && isRuntimeReference(current), isWrapper, new Set());
43
+ // CodeMode values are data here, not opaque interpreter references.
44
+ export const containsOpaqueReference = (value) => find(value, (current) => !Values.isValue(current) && isRuntimeReference(current), Values.isValue, new Set());
39
45
  // Reject cycles before mutation so later boundary walks remain safe.
40
46
  export const rejectCircularInsertion = (container, value, label, node, seen = new Set()) => {
41
47
  if (find(value, (current) => current === container, isRuntimeReference, seen)) {
@@ -43,27 +49,27 @@ export const rejectCircularInsertion = (container, value, label, node, seen = ne
43
49
  }
44
50
  };
45
51
  export const describeValue = (value) => {
46
- if (value === null || value === undefined)
47
- return String(value);
52
+ if (value === null)
53
+ return "null";
48
54
  if (value instanceof ProgramArray)
49
55
  return "an array";
50
- if (value instanceof ProgramPromise)
56
+ if (value instanceof Values.Promise)
51
57
  return "an un-awaited Promise";
52
58
  if (value instanceof ToolReference)
53
59
  return "a tool reference";
54
- if (value instanceof ProgramDate)
60
+ if (value instanceof Values.Date)
55
61
  return "a Date";
56
- if (value instanceof ProgramRegExp)
62
+ if (value instanceof Values.RegExp)
57
63
  return "a RegExp";
58
- if (value instanceof ProgramMap)
64
+ if (value instanceof Values.Map)
59
65
  return "a Map";
60
- if (value instanceof ProgramSet)
66
+ if (value instanceof Values.Set)
61
67
  return "a Set";
62
- if (value instanceof ProgramURL)
68
+ if (value instanceof Values.URL)
63
69
  return "a URL";
64
- if (value instanceof ProgramURLSearchParams)
70
+ if (value instanceof Values.URLSearchParams)
65
71
  return "a URLSearchParams";
66
- if (value instanceof ProgramGenerator)
72
+ if (value instanceof CodeModeGenerator)
67
73
  return "a generator";
68
74
  if (isRuntimeReference(value))
69
75
  return "a function";
@@ -72,8 +78,15 @@ export const describeValue = (value) => {
72
78
  return `a ${typeof value}`;
73
79
  };
74
80
  export const typeofValue = (value) => {
75
- if (value instanceof Callable)
81
+ if (value instanceof HostFunction ||
82
+ value instanceof ProgramFunction ||
83
+ value instanceof GeneratorMethodReference ||
84
+ value instanceof IntrinsicReference ||
85
+ value instanceof PromiseInstanceMethodReference) {
76
86
  return "function";
87
+ }
88
+ if (value instanceof HostNamespace)
89
+ return "object";
77
90
  if (value instanceof ToolReference)
78
91
  return value.path.length > 0 ? "function" : "object";
79
92
  return typeof value;
@@ -1,7 +1,8 @@
1
1
  import { Effect } from "effect";
2
- import type { Prototypes } from "./intrinsics.js";
3
- import { type AstNode } from "./model.js";
4
- import { Callable, ProgramPromise } from "./objects.js";
2
+ import { Values } from "../values.js";
3
+ import { HostFunction } from "./host.js";
4
+ import { type AstNode, IntrinsicReference } from "./model.js";
5
+ import { ProgramFunction } from "./objects.js";
5
6
  export type IteratorCursor<R> = {
6
7
  readonly next: Effect.Effect<{
7
8
  readonly done: boolean;
@@ -9,20 +10,15 @@ export type IteratorCursor<R> = {
9
10
  }, unknown, R>;
10
11
  readonly close: Effect.Effect<void, unknown, R>;
11
12
  };
12
- /** Everything a native function needs from the realm: calling back into the program and its intrinsic objects. */
13
+ /** Everything a host function needs to call back into the program. */
13
14
  export type Runner<R> = {
14
- readonly invokeCallable: (callable: unknown, thisValue: unknown, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
15
- readonly settlePromise: (promise: ProgramPromise) => Effect.Effect<unknown, unknown, never>;
15
+ readonly invokeFunction: (fn: ProgramFunction, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
16
+ readonly invokeCallable: (callable: unknown, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
17
+ readonly settlePromise: (promise: Values.Promise) => Effect.Effect<unknown, unknown, never>;
16
18
  readonly syncIterator: (value: unknown, node: AstNode) => Effect.Effect<IteratorCursor<R> | undefined, unknown, R>;
17
- readonly prototypes: Prototypes;
18
19
  };
19
20
  export declare const preserveConsumerError: <A, R>(cursor: IteratorCursor<R>, effect: Effect.Effect<A, unknown, R>) => Effect.Effect<A, unknown, R>;
20
- /**
21
- * ToPrimitive: calls `valueOf`/`toString` in hint order and returns the first primitive result. Dates treat the
22
- * default hint as "string", like their `Symbol.toPrimitive`.
23
- */
24
- export declare const toPrimitive: <R>(runner: Runner<R>, value: unknown, hint: "number" | "string" | "default", node: AstNode) => Effect.Effect<unknown, unknown, R>;
25
- export declare const toPrimitiveString: <R>(runner: Runner<R>, value: unknown, node: AstNode) => Effect.Effect<string, unknown, R>;
26
- export declare const toPrimitiveNumber: <R>(runner: Runner<R>, value: unknown, node: AstNode) => Effect.Effect<number, unknown, R>;
27
- export declare const isSupportedCallback: (value: unknown) => value is Callable;
21
+ export declare const toPrimitive: <R>(runner: Runner<R>, value: unknown, hint: "number" | "string", node: AstNode) => Effect.Effect<unknown, unknown, R>;
22
+ export type SupportedCallback = ProgramFunction | HostFunction<unknown> | IntrinsicReference;
23
+ export declare const isSupportedCallback: (value: unknown) => value is SupportedCallback;
28
24
  export declare const applyCollectionCallback: <R>(runner: Runner<R>, callback: unknown, name: string, node: AstNode) => ((args: Array<unknown>) => Effect.Effect<unknown, unknown, R>);
@@ -1,45 +1,45 @@
1
1
  import { Effect, Exit } from "effect";
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";
2
+ import { Values } from "../values.js";
3
+ import { coerceToString } from "../stdlib/value.js";
4
+ import { HostFunction } from "./host.js";
5
+ import { InterpreterRuntimeError, IntrinsicReference } from "./model.js";
6
+ import { get, has, ProgramFunction, ProgramObject } from "./objects.js";
5
7
  import { typeofValue } from "./references.js";
6
8
  export const preserveConsumerError = (cursor, effect) => Effect.flatMap(Effect.exit(effect), (exit) => Exit.isSuccess(exit)
7
9
  ? Effect.succeed(exit.value)
8
10
  : Effect.andThen(Effect.exit(cursor.close), Effect.failCause(exit.cause)));
9
- /**
10
- * ToPrimitive: calls `valueOf`/`toString` in hint order and returns the first primitive result. Dates treat the
11
- * default hint as "string", like their `Symbol.toPrimitive`.
12
- */
13
11
  export const toPrimitive = (runner, value, hint, node) => {
12
+ if (value === null || typeof value !== "object")
13
+ return Effect.succeed(value);
14
+ if (Values.isValue(value)) {
15
+ return Effect.succeed(value instanceof Values.Date && hint === "number" ? value.time : coerceToString(value));
16
+ }
14
17
  if (!(value instanceof ProgramObject))
15
18
  return Effect.succeed(value);
16
- const asString = hint === "string" || (hint === "default" && value instanceof ProgramDate);
17
- const order = asString ? ["toString", "valueOf"] : ["valueOf", "toString"];
19
+ const order = hint === "number" ? ["valueOf", "toString"] : ["toString", "valueOf"];
18
20
  return Effect.gen(function* () {
19
21
  for (const method of order) {
22
+ if (method === "toString" && !has(value, "toString"))
23
+ return coerceToString(value);
20
24
  const callable = get(value, method);
21
- if (!(callable instanceof Callable))
25
+ if (typeofValue(callable) !== "function")
22
26
  continue;
23
- const result = yield* runner.invokeCallable(callable, value, [], node);
27
+ const result = yield* runner.invokeCallable(callable, [], node);
24
28
  if (result === null || (typeof result !== "object" && typeof result !== "function"))
25
29
  return result;
26
30
  }
27
- throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node);
31
+ throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node).as("TypeError");
28
32
  });
29
33
  };
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);
32
- // The single acceptance list for callbacks: collections, sort, string replacers,
33
- // Array.from mappers, and promise reactions all admit exactly these callables.
34
- // Admission means dispatchable, not necessarily invocable: new-requiring
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);
34
+ export const isSupportedCallback = (value) => value instanceof ProgramFunction ||
35
+ (value instanceof HostFunction && value.callback) ||
36
+ value instanceof IntrinsicReference;
37
37
  export const applyCollectionCallback = (runner, callback, name, node) => {
38
38
  if (!isSupportedCallback(callback)) {
39
39
  if (typeofValue(callback) === "function") {
40
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);
41
41
  }
42
- throw new InterpreterRuntimeError(`${name} expects a function callback.`, node);
42
+ throw new InterpreterRuntimeError(`${name} expects a function callback.`, node).as("TypeError");
43
43
  }
44
- return (callbackArgs) => runner.invokeCallable(callback, undefined, callbackArgs, node);
44
+ return (callbackArgs) => runner.invokeCallable(callback, callbackArgs, node);
45
45
  };
@@ -1,6 +1,5 @@
1
1
  import type { Program } from "acorn";
2
2
  import { Effect } from "effect";
3
- import type { Prototypes } from "./intrinsics.js";
4
3
  import { type Host } from "./globals.js";
5
4
  import { type Runner } from "./runner.js";
6
5
  import { PromiseRuntime } from "./promises.js";
@@ -10,10 +9,11 @@ export declare class Runtime<R> {
10
9
  readonly search: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>;
11
10
  readonly toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>;
12
11
  readonly promises: PromiseRuntime<R>;
13
- readonly prototypes: Prototypes;
14
12
  readonly logs: Array<string>;
15
13
  readonly runner: Runner<R>;
14
+ /** Built-in globals by name, unaffected by program shadowing. */
15
+ readonly builtins: ReadonlyMap<string, unknown>;
16
16
  private readonly root;
17
- constructor(executeTool: (path: ReadonlyArray<string>, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, search: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>, promises: PromiseRuntime<R>, prototypes: Prototypes, logs?: Array<string>, extraGlobals?: (host: Host<R>) => ReadonlyArray<readonly [string, unknown]>);
17
+ constructor(executeTool: (path: ReadonlyArray<string>, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, search: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>, promises: PromiseRuntime<R>, logs?: Array<string>, extraGlobals?: (host: Host<R>) => ReadonlyArray<readonly [string, unknown]>);
18
18
  run(program: Program): Effect.Effect<unknown, unknown, R>;
19
19
  }