@opencode/codemode 2.0.2 → 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
@@ -0,0 +1,228 @@
1
+ import { Effect } from "effect";
2
+ import { checkArrayLength, checkStringLength } from "../interpreter/limits.js";
3
+ import { constructor, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
4
+ import { rangeError, syntaxError, typeError } from "../interpreter/model.js";
5
+ import { defineAccessor, get, Arr, Bytes, Obj } from "../interpreter/objects.js";
6
+ import { describeValue } from "../interpreter/references.js";
7
+ import { coerceToNumber, coerceToString } from "./value.js";
8
+ /** The bytes a Uint8Array, array, or other iterable of numbers describes; the host array clamps each value. */
9
+ const collectBytes = (ctx, source, name) => {
10
+ if (source instanceof Bytes)
11
+ return Effect.succeed(new Uint8Array(source.bytes));
12
+ return Effect.gen(function* () {
13
+ const cursor = yield* ctx.iterate(source);
14
+ if (cursor === undefined) {
15
+ throw typeError(`${name} expects a Uint8Array, an array, or an iterable of numbers, received ${describeValue(source)}.`);
16
+ }
17
+ const values = [];
18
+ while (true) {
19
+ const step = yield* cursor.next;
20
+ if (step.done)
21
+ return Uint8Array.from(values);
22
+ values.push(coerceToNumber(step.value));
23
+ checkArrayLength(values.length);
24
+ }
25
+ });
26
+ };
27
+ const constructBytes = (ctx, args, proto) => {
28
+ const source = args[0];
29
+ if (source !== null && typeof source === "object") {
30
+ return Effect.map(collectBytes(ctx, source, "new Uint8Array(...)"), (bytes) => new Bytes(proto, bytes));
31
+ }
32
+ const length = source === undefined ? 0 : coerceToNumber(source);
33
+ if (!Number.isInteger(length) || length < 0)
34
+ throw rangeError(`Invalid typed array length: ${coerceToString(source)}`);
35
+ checkArrayLength(length);
36
+ return Effect.succeed(new Bytes(proto, new Uint8Array(length)));
37
+ };
38
+ export const uint8ArrayGlobal = (ctx) => {
39
+ const builtins = ctx.builtins;
40
+ const proto = builtins.Uint8Array;
41
+ const wrap = (bytes) => new Bytes(proto, bytes);
42
+ const uint8Array = constructor(builtins, proto, {
43
+ name: "Uint8Array",
44
+ length: 3,
45
+ call: requiresNew("Uint8Array"),
46
+ construct: (args, newTarget) => constructBytes(ctx, args, prototypeFrom(newTarget, proto)),
47
+ });
48
+ const decode = (name, args, from) => {
49
+ if (typeof args[0] !== "string")
50
+ throw typeError(`Uint8Array.${name} expects a string.`);
51
+ try {
52
+ return wrap(from(args[0]));
53
+ }
54
+ catch {
55
+ throw syntaxError(`Uint8Array.${name}: the string is not valid ${name === "fromHex" ? "hex" : "base64"}.`);
56
+ }
57
+ };
58
+ methods(builtins, uint8Array, [
59
+ ["from", 1, (_, args) => Effect.map(collectBytes(ctx, args[0], "Uint8Array.from"), wrap)],
60
+ ["of", 0, (_, args) => wrap(Uint8Array.from(args, coerceToNumber))],
61
+ ["fromBase64", 1, (_, args) => decode("fromBase64", args, (text) => Uint8Array.fromBase64(text))],
62
+ ["fromHex", 1, (_, args) => decode("fromHex", args, (text) => Uint8Array.fromHex(text))],
63
+ ]);
64
+ const self = (thisValue, name) => receiver(Bytes, thisValue, `Uint8Array.prototype.${name}`);
65
+ const optNumber = (name, value, label) => {
66
+ if (value === undefined)
67
+ return undefined;
68
+ if (typeof value !== "number")
69
+ throw typeError(`Uint8Array.${name} expects ${label} to be a number.`);
70
+ return value;
71
+ };
72
+ const wrapAll = (items) => new Arr(builtins.Array, items);
73
+ defineAccessor(proto, "length", (thisValue) => self(thisValue, "length").bytes.length);
74
+ methods(builtins, proto, [
75
+ ["at", 1, (thisValue, args) => self(thisValue, "at").bytes.at(optNumber("at", args[0], "index") ?? 0)],
76
+ [
77
+ "slice",
78
+ 2,
79
+ (thisValue, args) => wrap(self(thisValue, "slice").bytes.slice(optNumber("slice", args[0], "start"), optNumber("slice", args[1], "end"))),
80
+ ],
81
+ // A view on the same bytes, as in JS: writes through one are visible through the other.
82
+ [
83
+ "subarray",
84
+ 2,
85
+ (thisValue, args) => wrap(self(thisValue, "subarray").bytes.subarray(optNumber("subarray", args[0], "start"), optNumber("subarray", args[1], "end"))),
86
+ ],
87
+ [
88
+ "set",
89
+ 1,
90
+ (thisValue, args) => {
91
+ const target = self(thisValue, "set");
92
+ const offset = optNumber("set", args[1], "offset") ?? 0;
93
+ return Effect.map(collectBytes(ctx, args[0], "Uint8Array.set"), (source) => {
94
+ if (!Number.isInteger(offset) || offset < 0 || source.length + offset > target.bytes.length) {
95
+ throw rangeError("Uint8Array.set: the source does not fit at that offset.");
96
+ }
97
+ target.bytes.set(source, offset);
98
+ return undefined;
99
+ });
100
+ },
101
+ ],
102
+ [
103
+ "fill",
104
+ 1,
105
+ (thisValue, args) => {
106
+ const target = self(thisValue, "fill");
107
+ target.bytes.fill(coerceToNumber(args[0]), optNumber("fill", args[1], "start"), optNumber("fill", args[2], "end"));
108
+ return target;
109
+ },
110
+ ],
111
+ [
112
+ "reverse",
113
+ 0,
114
+ (thisValue) => {
115
+ const target = self(thisValue, "reverse");
116
+ target.bytes.reverse();
117
+ return target;
118
+ },
119
+ ],
120
+ [
121
+ "indexOf",
122
+ 1,
123
+ (thisValue, args) => self(thisValue, "indexOf").bytes.indexOf(coerceToNumber(args[0]), optNumber("indexOf", args[1], "start index")),
124
+ ],
125
+ [
126
+ "lastIndexOf",
127
+ 1,
128
+ (thisValue, args) => {
129
+ const target = self(thisValue, "lastIndexOf").bytes;
130
+ return args[1] === undefined
131
+ ? target.lastIndexOf(coerceToNumber(args[0]))
132
+ : target.lastIndexOf(coerceToNumber(args[0]), optNumber("lastIndexOf", args[1], "start index"));
133
+ },
134
+ ],
135
+ [
136
+ "includes",
137
+ 1,
138
+ (thisValue, args) => self(thisValue, "includes").bytes.includes(coerceToNumber(args[0]), optNumber("includes", args[1], "start index")),
139
+ ],
140
+ [
141
+ "join",
142
+ 1,
143
+ (thisValue, args) => {
144
+ if (args.length > 1 || (args.length === 1 && typeof args[0] !== "string")) {
145
+ throw typeError("Uint8Array.join expects zero arguments or one string separator.");
146
+ }
147
+ const joined = self(thisValue, "join").bytes.join(args.length === 0 ? "," : args[0]);
148
+ checkStringLength(joined.length);
149
+ return joined;
150
+ },
151
+ ],
152
+ ["toString", 0, (thisValue) => self(thisValue, "toString").bytes.join(",")],
153
+ ["toBase64", 0, (thisValue) => self(thisValue, "toBase64").bytes.toBase64()],
154
+ ["toHex", 0, (thisValue) => self(thisValue, "toHex").bytes.toHex()],
155
+ ["keys", 0, (thisValue) => wrapAll(Array.from(self(thisValue, "keys").bytes.keys()))],
156
+ ["values", 0, (thisValue) => wrapAll(Array.from(self(thisValue, "values").bytes.values()))],
157
+ [
158
+ "entries",
159
+ 0,
160
+ (thisValue) => wrapAll(Array.from(self(thisValue, "entries").bytes.entries(), ([index, byte]) => wrapAll([index, byte]))),
161
+ ],
162
+ ]);
163
+ return uint8Array;
164
+ };
165
+ export const textEncoderGlobal = (ctx) => {
166
+ const builtins = ctx.builtins;
167
+ const proto = builtins.TextEncoder;
168
+ const encoder = new TextEncoder();
169
+ defineAccessor(proto, "encoding", () => "utf-8");
170
+ methods(builtins, proto, [
171
+ ["encode", 0, (_, args) => new Bytes(builtins.Uint8Array, encoder.encode(coerceToString(args[0] ?? "")))],
172
+ ]);
173
+ return constructor(builtins, proto, {
174
+ name: "TextEncoder",
175
+ call: requiresNew("TextEncoder"),
176
+ construct: (_, newTarget) => Effect.succeed(new Obj(prototypeFrom(newTarget, proto))),
177
+ });
178
+ };
179
+ /** A `TextDecoder` holding the host decoder its label and options configured. */
180
+ export class TextDecoderObj extends Obj {
181
+ decoder;
182
+ constructor(proto, decoder) {
183
+ super(proto);
184
+ this.decoder = decoder;
185
+ }
186
+ }
187
+ // The WHATWG labels for UTF-8, the only encoding CodeMode decodes.
188
+ const utf8Labels = new Set(["unicode-1-1-utf-8", "unicode11utf8", "unicode20utf8", "utf-8", "utf8", "x-unicode20utf8"]);
189
+ export const textDecoderGlobal = (ctx) => {
190
+ const builtins = ctx.builtins;
191
+ const proto = builtins.TextDecoder;
192
+ const self = (thisValue, name) => receiver(TextDecoderObj, thisValue, `TextDecoder.prototype.${name}`);
193
+ defineAccessor(proto, "encoding", (thisValue) => self(thisValue, "encoding").decoder.encoding);
194
+ defineAccessor(proto, "fatal", (thisValue) => self(thisValue, "fatal").decoder.fatal);
195
+ defineAccessor(proto, "ignoreBOM", (thisValue) => self(thisValue, "ignoreBOM").decoder.ignoreBOM);
196
+ methods(builtins, proto, [
197
+ [
198
+ "decode",
199
+ 0,
200
+ (thisValue, args) => {
201
+ const decoder = self(thisValue, "decode").decoder;
202
+ if (args[0] === undefined)
203
+ return "";
204
+ if (!(args[0] instanceof Bytes)) {
205
+ throw typeError(`TextDecoder.decode expects a Uint8Array, received ${describeValue(args[0])}.`);
206
+ }
207
+ try {
208
+ return decoder.decode(args[0].bytes);
209
+ }
210
+ catch {
211
+ throw typeError(`TextDecoder.decode: the input is not valid ${decoder.encoding}.`);
212
+ }
213
+ },
214
+ ],
215
+ ]);
216
+ return constructor(builtins, proto, {
217
+ name: "TextDecoder",
218
+ call: requiresNew("TextDecoder"),
219
+ construct: (args, newTarget) => Effect.sync(() => {
220
+ const label = args[0] === undefined ? "utf-8" : coerceToString(args[0]).trim().toLowerCase();
221
+ if (!utf8Labels.has(label))
222
+ throw rangeError(`The "${label}" encoding is not supported; only UTF-8 is.`);
223
+ const options = args[1] instanceof Obj ? args[1] : undefined;
224
+ const flag = (name) => options !== undefined && Boolean(get(options, name));
225
+ return new TextDecoderObj(prototypeFrom(newTarget, proto), new TextDecoder("utf-8", { fatal: flag("fatal"), ignoreBOM: flag("ignoreBOM") }));
226
+ }),
227
+ });
228
+ };
@@ -1,5 +1,5 @@
1
- import { type Runner } from "../interpreter/runner.js";
1
+ import type { Interpreter } from "../interpreter/interpreter.js";
2
2
  /** `Map.groupBy` and `Object.groupBy`: the same iteration, keyed into a Map or a data object. */
3
- export declare const groupBy: <R>(runner: Runner<R>, namespace: "Map" | "Object") => import("../interpreter/objects.js").NativeFunction<R>;
4
- export declare const mapGlobal: <R>(runner: Runner<R>) => import("../interpreter/objects.js").NativeFunction<R>;
5
- export declare const setGlobal: <R>(runner: Runner<R>) => import("../interpreter/objects.js").NativeFunction<R>;
3
+ export declare const groupBy: <R>(ctx: Interpreter<R>, namespace: "Map" | "Object") => import("../interpreter/objects.js").Native<R>;
4
+ export declare const mapGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
5
+ export declare const setGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
@@ -1,32 +1,32 @@
1
1
  import { Effect } from "effect";
2
2
  import { constructor, fn, methods, prototypeFrom, receiver, requiresNew } from "../interpreter/native.js";
3
- import { InterpreterRuntimeError } from "../interpreter/model.js";
4
- import { define, defineAccessor, get, getOwn, hidden, isWrapper, ProgramArray, ProgramMap, ProgramObject, ProgramPromise, ProgramSet, } from "../interpreter/objects.js";
3
+ import { invalidData, typeError } from "../interpreter/model.js";
4
+ import { define, defineAccessor, get, getOwn, hidden, isWrapper, Arr, MapObj, Obj, PromiseObj, SetObj, } from "../interpreter/objects.js";
5
5
  import { describeValue, isRuntimeReference } from "../interpreter/references.js";
6
- import { applyCollectionCallback, isSupportedCallback, preserveConsumerError, toPrimitiveNumber, toPrimitiveString, } from "../interpreter/runner.js";
7
- const coerceGroupByPropertyKey = (runner, value, node) => {
8
- if (value instanceof ProgramPromise)
6
+ import { applyCollectionCallback, isSupportedCallback, preserveConsumerError, toPrimitiveNumber, toPrimitiveString, } from "../interpreter/callback.js";
7
+ const coerceGroupByPropertyKey = (ctx, value) => {
8
+ if (value instanceof PromiseObj)
9
9
  return Effect.succeed("[object Promise]");
10
10
  if (!isWrapper(value) && isRuntimeReference(value)) {
11
- throw new InterpreterRuntimeError(`Object.groupBy callback must return a data value, received ${describeValue(value)}.`, node, "InvalidDataValue");
11
+ throw invalidData(`Object.groupBy callback must return a data value, received ${describeValue(value)}.`);
12
12
  }
13
- return toPrimitiveString(runner, value, node);
13
+ return toPrimitiveString(ctx, value);
14
14
  };
15
15
  /** `Map.groupBy` and `Object.groupBy`: the same iteration, keyed into a Map or a data object. */
16
- export const groupBy = (runner, namespace) => fn(runner.prototypes, "groupBy", 2, (_, args, node) => {
17
- const protos = runner.prototypes;
16
+ export const groupBy = (ctx, namespace) => fn(ctx.builtins, "groupBy", 2, (_, args) => {
17
+ const builtins = ctx.builtins;
18
18
  const source = args[0];
19
19
  if (source === null || source === undefined) {
20
- throw new InterpreterRuntimeError(`${namespace}.groupBy expects an iterable collection.`, node);
20
+ throw typeError(`${namespace}.groupBy expects an iterable collection.`);
21
21
  }
22
- const apply = applyCollectionCallback(runner, args[1], `${namespace}.groupBy`, node);
22
+ const apply = applyCollectionCallback(ctx, args[1], `${namespace}.groupBy`);
23
23
  return Effect.gen(function* () {
24
- const cursor = yield* runner.syncIterator(source, node);
24
+ const cursor = yield* ctx.iterate(source);
25
25
  if (cursor === undefined) {
26
- throw new InterpreterRuntimeError(`${namespace}.groupBy expects an iterable collection.`, node);
26
+ throw typeError(`${namespace}.groupBy expects an iterable collection.`);
27
27
  }
28
28
  if (namespace === "Map") {
29
- const result = new ProgramMap(protos.Map);
29
+ const result = new MapObj(builtins.Map);
30
30
  let index = 0;
31
31
  while (true) {
32
32
  const step = yield* cursor.next;
@@ -36,60 +36,60 @@ export const groupBy = (runner, namespace) => fn(runner.prototypes, "groupBy", 2
36
36
  const key = yield* preserveConsumerError(cursor, apply([item, index]));
37
37
  const group = result.map.get(key);
38
38
  if (group === undefined)
39
- result.map.set(key, new ProgramArray(protos.Array, [item]));
39
+ result.map.set(key, new Arr(builtins.Array, [item]));
40
40
  else
41
41
  group.items.push(item);
42
42
  index += 1;
43
43
  }
44
44
  }
45
45
  // Object.groupBy returns a null-prototype object, so group names never collide with inherited methods.
46
- const result = new ProgramObject(null);
46
+ const result = new Obj(null);
47
47
  let index = 0;
48
48
  while (true) {
49
49
  const step = yield* cursor.next;
50
50
  if (step.done)
51
51
  return result;
52
52
  const item = step.value;
53
- const key = yield* preserveConsumerError(cursor, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(runner, value, node)));
53
+ const key = yield* preserveConsumerError(cursor, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(ctx, value)));
54
54
  const group = getOwn(result, key);
55
55
  if (group === undefined)
56
- define(result, key, new ProgramArray(protos.Array, [item]));
56
+ define(result, key, new Arr(builtins.Array, [item]));
57
57
  else
58
58
  group.items.push(item);
59
59
  index += 1;
60
60
  }
61
61
  });
62
62
  });
63
- const constructMap = (runner, init, proto, node) => {
64
- const target = new ProgramMap(proto);
63
+ const constructMap = (ctx, init, proto) => {
64
+ const target = new MapObj(proto);
65
65
  if (init === undefined || init === null)
66
66
  return Effect.succeed(target);
67
67
  return Effect.gen(function* () {
68
- const cursor = yield* runner.syncIterator(init, node);
68
+ const cursor = yield* ctx.iterate(init);
69
69
  if (cursor === undefined) {
70
- throw new InterpreterRuntimeError("new Map(...) expects an iterable of [key, value] pairs or no argument.", node);
70
+ throw typeError("new Map(...) expects an iterable of [key, value] pairs or no argument.");
71
71
  }
72
72
  while (true) {
73
73
  const step = yield* cursor.next;
74
74
  if (step.done)
75
75
  return target;
76
76
  yield* preserveConsumerError(cursor, Effect.sync(() => {
77
- if (!(step.value instanceof ProgramObject)) {
78
- throw new InterpreterRuntimeError("new Map(...) expects [key, value] pairs as entry objects.", node);
77
+ if (!(step.value instanceof Obj)) {
78
+ throw typeError("new Map(...) expects [key, value] pairs as entry objects.");
79
79
  }
80
80
  target.map.set(getOwn(step.value, 0), getOwn(step.value, 1));
81
81
  }));
82
82
  }
83
83
  });
84
84
  };
85
- const constructSet = (runner, init, proto, node) => {
86
- const target = new ProgramSet(proto);
85
+ const constructSet = (ctx, init, proto) => {
86
+ const target = new SetObj(proto);
87
87
  if (init === undefined || init === null)
88
88
  return Effect.succeed(target);
89
89
  return Effect.gen(function* () {
90
- const cursor = yield* runner.syncIterator(init, node);
90
+ const cursor = yield* ctx.iterate(init);
91
91
  if (cursor === undefined) {
92
- throw new InterpreterRuntimeError("new Set(...) expects a synchronous iterable or no argument.", node);
92
+ throw typeError("new Set(...) expects a synchronous iterable or no argument.");
93
93
  }
94
94
  while (true) {
95
95
  const step = yield* cursor.next;
@@ -99,52 +99,52 @@ const constructSet = (runner, init, proto, node) => {
99
99
  }
100
100
  });
101
101
  };
102
- export const mapGlobal = (runner) => {
103
- const protos = runner.prototypes;
104
- const proto = protos.Map;
105
- const map = constructor(protos, proto, {
102
+ export const mapGlobal = (ctx) => {
103
+ const builtins = ctx.builtins;
104
+ const proto = builtins.Map;
105
+ const map = constructor(builtins, proto, {
106
106
  name: "Map",
107
107
  call: requiresNew("Map"),
108
- construct: (args, newTarget, node) => constructMap(runner, args[0], prototypeFrom(newTarget, proto), node),
108
+ construct: (args, newTarget) => constructMap(ctx, args[0], prototypeFrom(newTarget, proto)),
109
109
  });
110
- define(map, "groupBy", groupBy(runner, "Map"), hidden);
111
- const self = (thisValue, name, node) => receiver(ProgramMap, thisValue, `Map.prototype.${name}`, node);
112
- const wrap = (items) => new ProgramArray(protos.Array, items);
113
- defineAccessor(proto, "size", (thisValue) => receiver(ProgramMap, thisValue, "Map.prototype.size").map.size);
114
- methods(protos, proto, [
115
- ["get", 1, (thisValue, args, node) => self(thisValue, "get", node).map.get(args[0])],
116
- ["has", 1, (thisValue, args, node) => self(thisValue, "has", node).map.has(args[0])],
110
+ define(map, "groupBy", groupBy(ctx, "Map"), hidden);
111
+ const self = (thisValue, name) => receiver(MapObj, thisValue, `Map.prototype.${name}`);
112
+ const wrap = (items) => new Arr(builtins.Array, items);
113
+ defineAccessor(proto, "size", (thisValue) => receiver(MapObj, thisValue, "Map.prototype.size").map.size);
114
+ methods(builtins, proto, [
115
+ ["get", 1, (thisValue, args) => self(thisValue, "get").map.get(args[0])],
116
+ ["has", 1, (thisValue, args) => self(thisValue, "has").map.has(args[0])],
117
117
  [
118
118
  "set",
119
119
  2,
120
- (thisValue, args, node) => {
121
- const target = self(thisValue, "set", node);
120
+ (thisValue, args) => {
121
+ const target = self(thisValue, "set");
122
122
  target.map.set(args[0], args[1]);
123
123
  return target;
124
124
  },
125
125
  ],
126
- ["delete", 1, (thisValue, args, node) => self(thisValue, "delete", node).map.delete(args[0])],
126
+ ["delete", 1, (thisValue, args) => self(thisValue, "delete").map.delete(args[0])],
127
127
  [
128
128
  "clear",
129
129
  0,
130
- (thisValue, _, node) => {
131
- self(thisValue, "clear", node).map.clear();
130
+ (thisValue) => {
131
+ self(thisValue, "clear").map.clear();
132
132
  return undefined;
133
133
  },
134
134
  ],
135
- ["keys", 0, (thisValue, _, node) => wrap(Array.from(self(thisValue, "keys", node).map.keys()))],
136
- ["values", 0, (thisValue, _, node) => wrap(Array.from(self(thisValue, "values", node).map.values()))],
135
+ ["keys", 0, (thisValue) => wrap(Array.from(self(thisValue, "keys").map.keys()))],
136
+ ["values", 0, (thisValue) => wrap(Array.from(self(thisValue, "values").map.values()))],
137
137
  [
138
138
  "entries",
139
139
  0,
140
- (thisValue, _, node) => wrap(Array.from(self(thisValue, "entries", node).map.entries(), ([key, item]) => wrap([key, item]))),
140
+ (thisValue) => wrap(Array.from(self(thisValue, "entries").map.entries(), ([key, item]) => wrap([key, item]))),
141
141
  ],
142
142
  [
143
143
  "forEach",
144
144
  1,
145
- (thisValue, args, node) => {
146
- const target = self(thisValue, "forEach", node);
147
- const apply = applyCollectionCallback(runner, args[0], "Map.forEach", node);
145
+ (thisValue, args) => {
146
+ const target = self(thisValue, "forEach");
147
+ const apply = applyCollectionCallback(ctx, args[0], "Map.forEach");
148
148
  return Effect.gen(function* () {
149
149
  for (const [key, item] of Array.from(target.map.entries()))
150
150
  yield* apply([item, key, target]);
@@ -155,49 +155,49 @@ export const mapGlobal = (runner) => {
155
155
  ]);
156
156
  return map;
157
157
  };
158
- const loadSetRecord = (runner, source, name, node) => {
159
- if (source instanceof ProgramSet) {
158
+ const loadSetRecord = (ctx, source, name) => {
159
+ if (source instanceof SetObj) {
160
160
  return Effect.succeed({
161
161
  size: source.set.size,
162
162
  has: (item) => Effect.succeed(source.set.has(item)),
163
163
  keys: () => Effect.succeed(source.set.values()),
164
164
  });
165
165
  }
166
- if (source instanceof ProgramMap) {
166
+ if (source instanceof MapObj) {
167
167
  return Effect.succeed({
168
168
  size: source.map.size,
169
169
  has: (item) => Effect.succeed(source.map.has(item)),
170
170
  keys: () => Effect.succeed(source.map.keys()),
171
171
  });
172
172
  }
173
- if (!(source instanceof ProgramObject)) {
174
- throw new InterpreterRuntimeError(`Set.${name} expects a Set-like object.`, node);
173
+ if (!(source instanceof Obj)) {
174
+ throw typeError(`Set.${name} expects a Set-like object.`);
175
175
  }
176
176
  return Effect.gen(function* () {
177
- const size = yield* toPrimitiveNumber(runner, get(source, "size"), node);
177
+ const size = yield* toPrimitiveNumber(ctx, get(source, "size"));
178
178
  if (Number.isNaN(size)) {
179
- throw new InterpreterRuntimeError(`Set.${name} received a Set-like object with an invalid size.`, node);
179
+ throw typeError(`Set.${name} received a Set-like object with an invalid size.`);
180
180
  }
181
181
  const has = get(source, "has");
182
182
  const keys = get(source, "keys");
183
183
  if (!isSupportedCallback(has) || !isSupportedCallback(keys)) {
184
- throw new InterpreterRuntimeError(`Set.${name} expects callable 'has' and 'keys' methods.`, node);
184
+ throw typeError(`Set.${name} expects callable 'has' and 'keys' methods.`);
185
185
  }
186
186
  return {
187
187
  size: Math.max(Math.trunc(size), 0),
188
- has: (item) => Effect.map(runner.invokeCallable(has, source, [item], node), Boolean),
189
- keys: () => Effect.flatMap(runner.invokeCallable(keys, source, [], node), (result) => {
190
- if (result instanceof ProgramArray)
188
+ has: (item) => Effect.map(ctx.call(has, source, [item]), Boolean),
189
+ keys: () => Effect.flatMap(ctx.call(keys, source, []), (result) => {
190
+ if (result instanceof Arr)
191
191
  return Effect.succeed(result.items);
192
- throw new InterpreterRuntimeError(`Set.${name} expected 'keys' to return an iterator.`, node);
192
+ throw typeError(`Set.${name} expected 'keys' to return an iterator.`);
193
193
  }),
194
194
  };
195
195
  });
196
196
  };
197
- const setOperation = (runner, target, name, source, node) => Effect.gen(function* () {
198
- const other = yield* loadSetRecord(runner, source, name, node);
197
+ const setOperation = (ctx, target, name, source) => Effect.gen(function* () {
198
+ const other = yield* loadSetRecord(ctx, source, name);
199
199
  const copy = () => {
200
- const result = new ProgramSet(runner.prototypes.Set);
200
+ const result = new SetObj(ctx.builtins.Set);
201
201
  for (const item of target.set.values())
202
202
  result.set.add(item);
203
203
  return result;
@@ -209,7 +209,7 @@ const setOperation = (runner, target, name, source, node) => Effect.gen(function
209
209
  return result;
210
210
  }
211
211
  if (name === "intersection") {
212
- const result = new ProgramSet(runner.prototypes.Set);
212
+ const result = new SetObj(ctx.builtins.Set);
213
213
  if (target.set.size <= other.size) {
214
214
  for (const item of target.set.values()) {
215
215
  if (yield* other.has(item))
@@ -277,55 +277,55 @@ const setOperation = (runner, target, name, source, node) => Effect.gen(function
277
277
  }
278
278
  return true;
279
279
  });
280
- export const setGlobal = (runner) => {
281
- const protos = runner.prototypes;
282
- const proto = protos.Set;
283
- const set = constructor(protos, proto, {
280
+ export const setGlobal = (ctx) => {
281
+ const builtins = ctx.builtins;
282
+ const proto = builtins.Set;
283
+ const set = constructor(builtins, proto, {
284
284
  name: "Set",
285
285
  call: requiresNew("Set"),
286
- construct: (args, newTarget, node) => constructSet(runner, args[0], prototypeFrom(newTarget, proto), node),
286
+ construct: (args, newTarget) => constructSet(ctx, args[0], prototypeFrom(newTarget, proto)),
287
287
  });
288
- const self = (thisValue, name, node) => receiver(ProgramSet, thisValue, `Set.prototype.${name}`, node);
289
- const wrap = (items) => new ProgramArray(protos.Array, items);
288
+ const self = (thisValue, name) => receiver(SetObj, thisValue, `Set.prototype.${name}`);
289
+ const wrap = (items) => new Arr(builtins.Array, items);
290
290
  const operation = (name) => [
291
291
  name,
292
292
  1,
293
- (thisValue, args, node) => setOperation(runner, self(thisValue, name, node), name, args[0], node),
293
+ (thisValue, args) => setOperation(ctx, self(thisValue, name), name, args[0]),
294
294
  ];
295
- defineAccessor(proto, "size", (thisValue) => receiver(ProgramSet, thisValue, "Set.prototype.size").set.size);
296
- methods(protos, proto, [
297
- ["has", 1, (thisValue, args, node) => self(thisValue, "has", node).set.has(args[0])],
295
+ defineAccessor(proto, "size", (thisValue) => receiver(SetObj, thisValue, "Set.prototype.size").set.size);
296
+ methods(builtins, proto, [
297
+ ["has", 1, (thisValue, args) => self(thisValue, "has").set.has(args[0])],
298
298
  [
299
299
  "add",
300
300
  1,
301
- (thisValue, args, node) => {
302
- const target = self(thisValue, "add", node);
301
+ (thisValue, args) => {
302
+ const target = self(thisValue, "add");
303
303
  target.set.add(args[0]);
304
304
  return target;
305
305
  },
306
306
  ],
307
- ["delete", 1, (thisValue, args, node) => self(thisValue, "delete", node).set.delete(args[0])],
307
+ ["delete", 1, (thisValue, args) => self(thisValue, "delete").set.delete(args[0])],
308
308
  [
309
309
  "clear",
310
310
  0,
311
- (thisValue, _, node) => {
312
- self(thisValue, "clear", node).set.clear();
311
+ (thisValue) => {
312
+ self(thisValue, "clear").set.clear();
313
313
  return undefined;
314
314
  },
315
315
  ],
316
- ["keys", 0, (thisValue, _, node) => wrap(Array.from(self(thisValue, "keys", node).set.values()))],
317
- ["values", 0, (thisValue, _, node) => wrap(Array.from(self(thisValue, "values", node).set.values()))],
316
+ ["keys", 0, (thisValue) => wrap(Array.from(self(thisValue, "keys").set.values()))],
317
+ ["values", 0, (thisValue) => wrap(Array.from(self(thisValue, "values").set.values()))],
318
318
  [
319
319
  "entries",
320
320
  0,
321
- (thisValue, _, node) => wrap(Array.from(self(thisValue, "entries", node).set.values(), (item) => wrap([item, item]))),
321
+ (thisValue) => wrap(Array.from(self(thisValue, "entries").set.values(), (item) => wrap([item, item]))),
322
322
  ],
323
323
  [
324
324
  "forEach",
325
325
  1,
326
- (thisValue, args, node) => {
327
- const target = self(thisValue, "forEach", node);
328
- const apply = applyCollectionCallback(runner, args[0], "Set.forEach", node);
326
+ (thisValue, args) => {
327
+ const target = self(thisValue, "forEach");
328
+ const apply = applyCollectionCallback(ctx, args[0], "Set.forEach");
329
329
  return Effect.gen(function* () {
330
330
  for (const item of Array.from(target.set.values()))
331
331
  yield* apply([item, item, target]);
@@ -1,4 +1,6 @@
1
- import { ProgramObject } from "../interpreter/objects.js";
2
- import type { Runner } from "../interpreter/runner.js";
1
+ import { Obj } from "../interpreter/objects.js";
2
+ import type { Interpreter } from "../interpreter/interpreter.js";
3
3
  /** Captured console: every method appends one formatted line to `logs`. */
4
- export declare const consoleGlobal: <R>(runner: Runner<R>, logs: Array<string>) => ProgramObject;
4
+ export declare const consoleGlobal: <R>(ctx: Interpreter<R>) => Obj;
5
+ /** One value as `console.log` shows it. */
6
+ export declare const formatValue: (value: unknown) => string;