@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,33 +1,33 @@
1
- import { toData, toProgram } from "../data.js";
2
1
  import { methods } from "../interpreter/native.js";
3
- import { entries, get, ProgramArray, ProgramDate, ProgramMap, ProgramObject, ProgramPromise, ProgramRegExp, ProgramSet, ProgramURL, ProgramURLSearchParams, } from "../interpreter/objects.js";
4
- import { containsOpaqueReference, containsRuntimeReference, isRuntimeReference } from "../interpreter/references.js";
2
+ import { entries, get, Arr, Bytes, DateObj, MapObj, Obj, PromiseObj, RegExpObj, SetObj, URLObj, URLSearchParamsObj, } from "../interpreter/objects.js";
3
+ import { containsOpaqueReference, isRuntimeReference } from "../interpreter/references.js";
5
4
  import { coerceToString } from "./value.js";
6
5
  const consoleMethods = ["log", "info", "debug", "warn", "error", "dir", "table"];
7
6
  /** Captured console: every method appends one formatted line to `logs`. */
8
- export const consoleGlobal = (runner, logs) => {
9
- const protos = runner.prototypes;
10
- const console = new ProgramObject(protos.Object);
11
- methods(protos, console, consoleMethods.map((name) => [
7
+ export const consoleGlobal = (ctx) => {
8
+ const builtins = ctx.builtins;
9
+ const console = new Obj(builtins.Object);
10
+ methods(builtins, console, consoleMethods.map((name) => [
12
11
  name,
13
12
  0,
14
13
  (_, args) => {
15
- logs.push(formatConsoleMessage(protos, name, args));
14
+ ctx.logs.push(formatConsoleMessage(name, args));
16
15
  return undefined;
17
16
  },
18
17
  ]));
19
18
  return console;
20
19
  };
21
20
  const MAX_CONSOLE_DEPTH = 32;
22
- const formatConsoleMessage = (protos, name, args) => {
21
+ const formatConsoleMessage = (name, args) => {
23
22
  if (name === "dir")
24
- return args.length === 0 ? "undefined" : formatConsoleArgument(args[0]);
23
+ return args.length === 0 ? "undefined" : formatValue(args[0]);
25
24
  if (name === "table")
26
- return formatConsoleTable(protos, args[0], args[1]);
25
+ return formatConsoleTable(args[0], args[1]);
27
26
  const prefix = name === "warn" ? "[warn] " : name === "error" ? "[error] " : name === "debug" ? "[debug] " : "";
28
- return `${prefix}${args.map((arg) => formatConsoleArgument(arg)).join(" ")}`;
27
+ return `${prefix}${args.map((arg) => formatValue(arg)).join(" ")}`;
29
28
  };
30
- const formatConsoleArgument = (value) => {
29
+ /** One value as `console.log` shows it. */
30
+ export const formatValue = (value) => {
31
31
  if (value === undefined)
32
32
  return "undefined";
33
33
  if (typeof value === "string")
@@ -43,21 +43,23 @@ const formatConsoleValue = (value, seen, depth) => {
43
43
  return String(value);
44
44
  if (typeof value !== "object")
45
45
  return String(value);
46
- if (value instanceof ProgramPromise)
46
+ if (value instanceof PromiseObj)
47
47
  return "[Promise (await it to get its value)]";
48
- if (value instanceof ProgramDate)
48
+ if (value instanceof DateObj)
49
49
  return coerceToString(value);
50
- if (value instanceof ProgramRegExp)
50
+ if (value instanceof RegExpObj)
51
51
  return coerceToString(value);
52
- if (value instanceof ProgramURL)
52
+ if (value instanceof URLObj)
53
53
  return coerceToString(value);
54
- if (value instanceof ProgramURLSearchParams)
54
+ if (value instanceof URLSearchParamsObj)
55
55
  return coerceToString(value);
56
+ if (value instanceof Bytes)
57
+ return `Uint8Array(${value.bytes.length}) [${value.bytes.join(",")}]`;
56
58
  if (depth > MAX_CONSOLE_DEPTH)
57
59
  return "...";
58
60
  if (seen.has(value))
59
61
  return "[Circular]";
60
- if (value instanceof ProgramMap) {
62
+ if (value instanceof MapObj) {
61
63
  seen.add(value);
62
64
  try {
63
65
  const items = Array.from(value.map.entries(), ([key, item]) => `[${formatItems([key, item], seen, depth + 1)}]`);
@@ -67,7 +69,7 @@ const formatConsoleValue = (value, seen, depth) => {
67
69
  seen.delete(value);
68
70
  }
69
71
  }
70
- if (value instanceof ProgramSet) {
72
+ if (value instanceof SetObj) {
71
73
  seen.add(value);
72
74
  try {
73
75
  return `Set(${value.set.size}) [${formatItems([...value.set.values()], seen, depth + 1)}]`;
@@ -80,9 +82,9 @@ const formatConsoleValue = (value, seen, depth) => {
80
82
  return "[opaque reference]";
81
83
  seen.add(value);
82
84
  try {
83
- if (value instanceof ProgramArray)
85
+ if (value instanceof Arr)
84
86
  return `[${formatItems(value.items, seen, depth + 1)}]`;
85
- if (!(value instanceof ProgramObject))
87
+ if (!(value instanceof Obj))
86
88
  return "[object Object]";
87
89
  return `{${entries(value)
88
90
  .map(([key, item]) => `${JSON.stringify(key)}:${formatConsoleValue(item, seen, depth + 1)}`)
@@ -93,14 +95,13 @@ const formatConsoleValue = (value, seen, depth) => {
93
95
  }
94
96
  };
95
97
  const formatItems = (items, seen, depth) => items.map((item) => formatConsoleValue(item, seen, depth)).join(",");
96
- const formatConsoleTable = (protos, value, columnsArgument) => {
98
+ const formatConsoleTable = (value, columnsArgument) => {
97
99
  if (value === undefined)
98
100
  return "undefined";
99
101
  if (containsOpaqueReference(value))
100
102
  return "[opaque reference]";
101
- const data = toProgram(protos, value, "console.table argument");
102
- const columns = consoleTableColumns(columnsArgument);
103
- const rows = consoleTableRows(data, columns);
103
+ const columns = columnsArgument instanceof Arr ? columnsArgument.items.map(String) : undefined;
104
+ const rows = consoleTableRows(value, columns);
104
105
  const keys = columns ?? Array.from(new Set(rows.flatMap((row) => Object.keys(row.values))));
105
106
  const header = ["(index)", ...keys].join("\t");
106
107
  return [
@@ -108,25 +109,17 @@ const formatConsoleTable = (protos, value, columnsArgument) => {
108
109
  ...rows.map((row) => [row.index, ...keys.map((key) => formatConsoleTableCell(row.values[key]))].join("\t")),
109
110
  ].join("\n");
110
111
  };
111
- const consoleTableColumns = (value) => {
112
- if (value === undefined)
113
- return undefined;
114
- if (containsRuntimeReference(value))
115
- return undefined;
116
- const columns = toData(value, "console.table columns", "result");
117
- return Array.isArray(columns) ? columns.map((column) => String(column)) : undefined;
118
- };
119
112
  const consoleTableRows = (data, columns) => {
120
- if (data instanceof ProgramArray) {
113
+ if (data instanceof Arr) {
121
114
  return data.items.map((item, index) => ({ index: String(index), values: consoleTableValues(item, columns) }));
122
115
  }
123
- if (data instanceof ProgramObject) {
116
+ if (data instanceof Obj) {
124
117
  return entries(data).map(([index, item]) => ({ index, values: consoleTableValues(item, columns) }));
125
118
  }
126
119
  return [{ index: "0", values: { Value: data } }];
127
120
  };
128
121
  const consoleTableValues = (value, columns) => {
129
- if (value instanceof ProgramObject && !(value instanceof ProgramArray)) {
122
+ if (value instanceof Obj && !(value instanceof Arr)) {
130
123
  if (columns !== undefined)
131
124
  return Object.fromEntries(columns.map((column) => [column, get(value, column)]));
132
125
  return Object.fromEntries(entries(value));
@@ -1,2 +1,2 @@
1
- import { type Runner } from "../interpreter/runner.js";
2
- export declare const dateGlobal: <R>(runner: Runner<R>) => import("../interpreter/objects.js").NativeFunction<R>;
1
+ import type { Interpreter } from "../interpreter/interpreter.js";
2
+ export declare const dateGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
@@ -1,22 +1,22 @@
1
1
  import { Effect } from "effect";
2
2
  import { constructor, methods, prototypeFrom, receiver } from "../interpreter/native.js";
3
3
  import { rangeError } from "../interpreter/model.js";
4
- import { ProgramDate, ProgramObject } from "../interpreter/objects.js";
5
- import { toPrimitive, toPrimitiveNumber } from "../interpreter/runner.js";
4
+ import { DateObj, Obj } from "../interpreter/objects.js";
5
+ import { toPrimitive, toPrimitiveNumber } from "../interpreter/callback.js";
6
6
  import { coerceToNumber, coerceToString } from "./value.js";
7
- const constructDate = (runner, args, proto, node) => {
7
+ const constructDate = (ctx, args, proto) => {
8
8
  if (args.length === 0)
9
- return Effect.succeed(new ProgramDate(proto, Date.now()));
9
+ return Effect.succeed(new DateObj(proto, Date.now()));
10
10
  if (args.length === 1) {
11
11
  const arg = args[0];
12
- if (arg instanceof ProgramDate)
13
- return Effect.succeed(new ProgramDate(proto, arg.time));
14
- return Effect.map(toPrimitive(runner, arg, "default", node), (value) => typeof value === "string"
15
- ? new ProgramDate(proto, Date.parse(value))
16
- : new ProgramDate(proto, new Date(coerceToNumber(value)).getTime()));
12
+ if (arg instanceof DateObj)
13
+ return Effect.succeed(new DateObj(proto, arg.time));
14
+ return Effect.map(toPrimitive(ctx, arg, "default"), (value) => typeof value === "string"
15
+ ? new DateObj(proto, Date.parse(value))
16
+ : new DateObj(proto, new Date(coerceToNumber(value)).getTime()));
17
17
  }
18
18
  const parts = args.map((arg) => coerceToNumber(arg));
19
- return Effect.succeed(new ProgramDate(proto, new Date(...parts).getTime()));
19
+ return Effect.succeed(new DateObj(proto, new Date(...parts).getTime()));
20
20
  };
21
21
  const getters = [
22
22
  "getFullYear",
@@ -54,53 +54,53 @@ const setters = [
54
54
  ["setFullYear", 3],
55
55
  ["setUTCFullYear", 3],
56
56
  ];
57
- export const dateGlobal = (runner) => {
58
- const protos = runner.prototypes;
59
- const proto = protos.Date;
60
- const date = constructor(protos, proto, {
57
+ export const dateGlobal = (ctx) => {
58
+ const builtins = ctx.builtins;
59
+ const proto = builtins.Date;
60
+ const date = constructor(builtins, proto, {
61
61
  name: "Date",
62
62
  length: 7,
63
63
  // ISO instead of the host's locale string: date strings are deterministic and must not leak the host timezone.
64
64
  call: () => Effect.sync(() => new Date().toISOString()),
65
- construct: (args, newTarget, node) => constructDate(runner, args, prototypeFrom(newTarget, proto), node),
65
+ construct: (args, newTarget) => constructDate(ctx, args, prototypeFrom(newTarget, proto)),
66
66
  });
67
- methods(protos, date, [
67
+ methods(builtins, date, [
68
68
  ["now", 0, () => Date.now()],
69
69
  ["parse", 1, (_, args) => Date.parse(coerceToString(args[0]))],
70
70
  ["UTC", 7, (_, args) => Date.UTC(...args.map((arg) => coerceToNumber(arg)))],
71
71
  ]);
72
- const self = (thisValue, name, node) => receiver(ProgramDate, thisValue, `Date.prototype.${name}`, node);
73
- const iso = (value, node) => {
72
+ const self = (thisValue, name) => receiver(DateObj, thisValue, `Date.prototype.${name}`);
73
+ const iso = (value) => {
74
74
  if (!Number.isFinite(value.time))
75
- throw rangeError("Invalid time value.", node);
75
+ throw rangeError("Invalid time value.");
76
76
  return new Date(value.time).toISOString();
77
77
  };
78
- methods(protos, proto, [
79
- ["getTime", 0, (thisValue, _, node) => self(thisValue, "getTime", node).time],
80
- ["valueOf", 0, (thisValue, _, node) => self(thisValue, "valueOf", node).time],
81
- ["toISOString", 0, (thisValue, _, node) => iso(self(thisValue, "toISOString", node), node)],
78
+ methods(builtins, proto, [
79
+ ["getTime", 0, (thisValue) => self(thisValue, "getTime").time],
80
+ ["valueOf", 0, (thisValue) => self(thisValue, "valueOf").time],
81
+ ["toISOString", 0, (thisValue) => iso(self(thisValue, "toISOString"))],
82
82
  [
83
83
  "toJSON",
84
84
  1,
85
- (thisValue, _, node) => {
86
- const value = self(thisValue, "toJSON", node);
87
- return Number.isFinite(value.time) ? iso(value, node) : null;
85
+ (thisValue) => {
86
+ const value = self(thisValue, "toJSON");
87
+ return Number.isFinite(value.time) ? iso(value) : null;
88
88
  },
89
89
  ],
90
- ["toString", 0, (thisValue, _, node) => coerceToString(self(thisValue, "toString", node))],
91
- ["toDateString", 0, (thisValue, _, node) => new Date(self(thisValue, "toDateString", node).time).toDateString()],
92
- ["toTimeString", 0, (thisValue, _, node) => new Date(self(thisValue, "toTimeString", node).time).toTimeString()],
93
- ["toUTCString", 0, (thisValue, _, node) => new Date(self(thisValue, "toUTCString", node).time).toUTCString()],
94
- ["toGMTString", 0, (thisValue, _, node) => new Date(self(thisValue, "toGMTString", node).time).toUTCString()],
95
- ...getters.map((name) => [name, 0, (thisValue, _, node) => new Date(self(thisValue, name, node).time)[name]()]),
90
+ ["toString", 0, (thisValue) => coerceToString(self(thisValue, "toString"))],
91
+ ["toDateString", 0, (thisValue) => new Date(self(thisValue, "toDateString").time).toDateString()],
92
+ ["toTimeString", 0, (thisValue) => new Date(self(thisValue, "toTimeString").time).toTimeString()],
93
+ ["toUTCString", 0, (thisValue) => new Date(self(thisValue, "toUTCString").time).toUTCString()],
94
+ ["toGMTString", 0, (thisValue) => new Date(self(thisValue, "toGMTString").time).toUTCString()],
95
+ ...getters.map((name) => [name, 0, (thisValue) => new Date(self(thisValue, name).time)[name]()]),
96
96
  ...setters.map(([name, length]) => [
97
97
  name,
98
98
  length,
99
- (thisValue, args, node) => {
100
- const target = self(thisValue, name, node);
99
+ (thisValue, args) => {
100
+ const target = self(thisValue, name);
101
101
  // Native setters read the current time before argument coercion, whose callbacks may mutate the Date.
102
102
  const hosted = new Date(target.time);
103
- return Effect.map(Effect.forEach(args.slice(0, length), (arg) => toPrimitiveNumber(runner, arg, node), {
103
+ return Effect.map(Effect.forEach(args.slice(0, length), (arg) => toPrimitiveNumber(ctx, arg), {
104
104
  concurrency: 1,
105
105
  }), (values) => {
106
106
  target.time = hosted[name](...values);
@@ -1,3 +1,3 @@
1
- import { type Runner } from "../interpreter/runner.js";
2
- import { ProgramObject } from "../interpreter/objects.js";
3
- export declare const jsonGlobal: <R>(runner: Runner<R>) => ProgramObject;
1
+ import type { Interpreter } from "../interpreter/interpreter.js";
2
+ import { Obj } from "../interpreter/objects.js";
3
+ export declare const jsonGlobal: <R>(ctx: Interpreter<R>) => Obj;
@@ -1,36 +1,37 @@
1
1
  import { Effect } from "effect";
2
2
  import { methods } from "../interpreter/native.js";
3
- import { applyCollectionCallback } from "../interpreter/runner.js";
4
- import { InterpreterRuntimeError, syntaxError } from "../interpreter/model.js";
3
+ import { applyCollectionCallback } from "../interpreter/callback.js";
4
+ import { checkStringLength } from "../interpreter/limits.js";
5
+ import { syntaxError, typeError } from "../interpreter/model.js";
5
6
  import { typeofValue } from "../interpreter/references.js";
6
- import { fromData, toData, toProgram } from "../data.js";
7
- import { Callable, get, keys, ProgramArray, ProgramObject, record, remove, set } from "../interpreter/objects.js";
8
- export const jsonGlobal = (runner) => {
9
- const json = new ProgramObject(runner.prototypes.Object);
10
- methods(runner.prototypes, json, [
11
- ["parse", 2, (_, args, node) => parse(runner, args, node)],
12
- ["stringify", 3, (_, args, node) => stringify(runner, args, node)],
7
+ import { fromJson, toJson } from "../data.js";
8
+ import { get, keys, Arr, Obj, record, remove, set } from "../interpreter/objects.js";
9
+ export const jsonGlobal = (ctx) => {
10
+ const json = new Obj(ctx.builtins.Object);
11
+ methods(ctx.builtins, json, [
12
+ ["parse", 2, (_, args) => parse(ctx, args)],
13
+ ["stringify", 3, (_, args) => stringify(ctx, args)],
13
14
  ]);
14
15
  return json;
15
16
  };
16
- const parse = (runner, args, node) => {
17
+ const parse = (ctx, args) => {
17
18
  const text = args[0];
18
19
  if (typeof text !== "string")
19
- throw new InterpreterRuntimeError("JSON.parse expects a string.", node);
20
+ throw typeError("JSON.parse expects a string.");
20
21
  const parsed = (() => {
21
22
  try {
22
- return fromData(runner.prototypes, JSON.parse(text), "JSON.parse result");
23
+ return fromJson(ctx, JSON.parse(text));
23
24
  }
24
25
  catch (error) {
25
- throw syntaxError(`JSON.parse received invalid JSON: ${error instanceof Error ? error.message : String(error)}`, node);
26
+ throw syntaxError(`JSON.parse received invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
26
27
  }
27
28
  })();
28
29
  if (typeofValue(args[1]) !== "function")
29
30
  return Effect.succeed(parsed);
30
- const apply = applyCollectionCallback(runner, args[1], "JSON.parse", node);
31
+ const apply = applyCollectionCallback(ctx, args[1], "JSON.parse");
31
32
  const visit = (holder, key) => Effect.gen(function* () {
32
33
  const value = get(holder, key);
33
- if (value instanceof ProgramObject) {
34
+ if (value instanceof Obj) {
34
35
  for (const name of keys(value)) {
35
36
  const revived = yield* visit(value, name);
36
37
  if (revived === undefined)
@@ -41,61 +42,22 @@ const parse = (runner, args, node) => {
41
42
  }
42
43
  return yield* apply([key, value]);
43
44
  });
44
- return visit(record(runner.prototypes.Object, { "": parsed }), "");
45
+ return visit(record(ctx.builtins.Object, { "": parsed }), "");
45
46
  };
46
- const stringify = (runner, args, node) => {
47
+ const stringify = (ctx, args) => {
47
48
  const space = args[2];
48
49
  const indent = typeof space === "number" || typeof space === "string" ? space : undefined;
49
50
  const replacer = args[1];
50
- if (typeofValue(replacer) !== "function") {
51
- const properties = replacer instanceof ProgramArray
52
- ? replacer.items
53
- .filter((item) => typeof item === "string" || typeof item === "number")
54
- .map(String)
55
- : null;
56
- return Effect.succeed(JSON.stringify(toData(args[0], "JSON.stringify value"), properties, indent));
57
- }
58
- // Validate up front; the replacer walk below reads the original value.
59
- toProgram(runner.prototypes, args[0], "JSON.stringify value");
60
- const apply = applyCollectionCallback(runner, replacer, "JSON.stringify", node);
61
- const stack = new Set();
62
- const visit = (holder, key) => Effect.gen(function* () {
63
- const value = yield* apply([key, yield* toJSONValue(runner, get(holder, key), key, node)]);
64
- if (value === undefined || typeofValue(value) === "function")
65
- return undefined;
66
- toProgram(runner.prototypes, value, "JSON.stringify replacer result");
67
- if (typeof value === "number")
68
- return Number.isFinite(value) ? value : null;
69
- if (value === null || typeof value === "string" || typeof value === "boolean")
70
- return value;
71
- if (!(value instanceof ProgramObject))
72
- return {};
73
- if (stack.has(value))
74
- throw new InterpreterRuntimeError("Converting circular structure to JSON.", node);
75
- stack.add(value);
76
- if (value instanceof ProgramArray) {
77
- const result = [];
78
- for (let index = 0; index < value.items.length; index += 1) {
79
- result.push((yield* visit(value, String(index))) ?? null);
80
- }
81
- stack.delete(value);
82
- return result;
83
- }
84
- const result = Object.create(null);
85
- for (const name of keys(value)) {
86
- const item = yield* visit(value, name);
87
- if (item !== undefined)
88
- result[name] = item;
89
- }
90
- stack.delete(value);
91
- return result;
51
+ const properties = replacer instanceof Arr
52
+ ? replacer.items
53
+ .filter((item) => typeof item === "string" || typeof item === "number")
54
+ .map(String)
55
+ : null;
56
+ const callback = typeofValue(replacer) === "function" ? applyCollectionCallback(ctx, replacer, "JSON.stringify") : undefined;
57
+ return Effect.map(toJson(ctx, args[0], callback), (value) => {
58
+ const text = JSON.stringify(value, properties, indent);
59
+ if (text !== undefined)
60
+ checkStringLength(text.length);
61
+ return text;
92
62
  });
93
- return Effect.map(visit(record(runner.prototypes.Object, { "": args[0] }), ""), (value) => JSON.stringify(value, null, indent));
94
- };
95
- // SerializeJSONProperty step 2: a callable `toJSON` decides the value, as Date and URL define.
96
- const toJSONValue = (runner, value, key, node) => {
97
- if (!(value instanceof ProgramObject))
98
- return Effect.succeed(value);
99
- const toJSON = get(value, "toJSON");
100
- return toJSON instanceof Callable ? runner.invokeCallable(toJSON, value, [key], node) : Effect.succeed(value);
101
63
  };
@@ -1,8 +1,8 @@
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
  declare global {
4
4
  interface Math {
5
5
  sumPrecise(values: Iterable<number>): number;
6
6
  }
7
7
  }
8
- export declare const mathGlobal: <R>(runner: Runner<R>) => ProgramObject;
8
+ export declare const mathGlobal: <R>(ctx: Interpreter<R>) => Obj;
@@ -1,40 +1,36 @@
1
1
  import { Effect } from "effect";
2
2
  import { constants, methods } from "../interpreter/native.js";
3
- import { InterpreterRuntimeError } from "../interpreter/model.js";
4
- import { ProgramObject } from "../interpreter/objects.js";
5
- import { preserveConsumerError } from "../interpreter/runner.js";
3
+ import { typeError } from "../interpreter/model.js";
4
+ import { Obj } from "../interpreter/objects.js";
5
+ import { preserveConsumerError } from "../interpreter/callback.js";
6
6
  // Validate only the arguments a method consumes; like JS, extras are ignored
7
7
  // (so built-ins work as callbacks receiving (element, index, array)).
8
- const number = (name, args, index, node) => {
8
+ const number = (name, args, index) => {
9
9
  if (index >= args.length)
10
10
  return Number.NaN;
11
11
  const arg = args[index];
12
12
  if (typeof arg !== "number")
13
- throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
13
+ throw typeError(`Math.${name} expects number arguments.`);
14
14
  return arg;
15
15
  };
16
- const unary = (name, op) => [
17
- name,
18
- 1,
19
- (_, args, node) => op(number(name, args, 0, node)),
20
- ];
16
+ const unary = (name, op) => [name, 1, (_, args) => op(number(name, args, 0))];
21
17
  const binary = (name, op) => [
22
18
  name,
23
19
  2,
24
- (_, args, node) => op(number(name, args, 0, node), number(name, args, 1, node)),
20
+ (_, args) => op(number(name, args, 0), number(name, args, 1)),
25
21
  ];
26
22
  const variadic = (name, op) => [
27
23
  name,
28
24
  2,
29
- (_, args, node) => op(...args.map((arg) => {
25
+ (_, args) => op(...args.map((arg) => {
30
26
  if (typeof arg !== "number")
31
- throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
27
+ throw typeError(`Math.${name} expects number arguments.`);
32
28
  return arg;
33
29
  })),
34
30
  ];
35
- export const mathGlobal = (runner) => {
36
- const protos = runner.prototypes;
37
- const math = new ProgramObject(protos.Object);
31
+ export const mathGlobal = (ctx) => {
32
+ const builtins = ctx.builtins;
33
+ const math = new Obj(builtins.Object);
38
34
  constants(math, {
39
35
  PI: Math.PI,
40
36
  E: Math.E,
@@ -45,7 +41,7 @@ export const mathGlobal = (runner) => {
45
41
  SQRT2: Math.SQRT2,
46
42
  SQRT1_2: Math.SQRT1_2,
47
43
  });
48
- methods(protos, math, [
44
+ methods(builtins, math, [
49
45
  ["random", 0, () => Math.random()],
50
46
  variadic("max", Math.max),
51
47
  variadic("min", Math.min),
@@ -85,10 +81,10 @@ export const mathGlobal = (runner) => {
85
81
  [
86
82
  "sumPrecise",
87
83
  1,
88
- (_, args, node) => Effect.gen(function* () {
89
- const cursor = yield* runner.syncIterator(args[0], node);
84
+ (_, args) => Effect.gen(function* () {
85
+ const cursor = yield* ctx.iterate(args[0]);
90
86
  if (cursor === undefined) {
91
- throw new InterpreterRuntimeError("Math.sumPrecise expects a synchronous iterable.", node);
87
+ throw typeError("Math.sumPrecise expects a synchronous iterable.");
92
88
  }
93
89
  const numbers = [];
94
90
  while (true) {
@@ -97,7 +93,7 @@ export const mathGlobal = (runner) => {
97
93
  return Math.sumPrecise(numbers);
98
94
  yield* preserveConsumerError(cursor, Effect.sync(() => {
99
95
  if (typeof step.value !== "number") {
100
- throw new InterpreterRuntimeError("Math.sumPrecise expects an iterable of numbers.", node);
96
+ throw typeError("Math.sumPrecise expects an iterable of numbers.");
101
97
  }
102
98
  numbers.push(step.value);
103
99
  }));
@@ -1,3 +1,3 @@
1
- import type { Runner } from "../interpreter/runner.js";
2
- export declare const numberGlobal: <R>(runner: Runner<R>) => import("../interpreter/objects.js").NativeFunction<R>;
3
- export declare const booleanGlobal: <R>(runner: Runner<R>) => import("../interpreter/objects.js").NativeFunction<R>;
1
+ import type { Interpreter } from "../interpreter/interpreter.js";
2
+ export declare const numberGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
3
+ export declare const booleanGlobal: <R>(ctx: Interpreter<R>) => import("../interpreter/objects.js").Native<R>;
@@ -1,12 +1,12 @@
1
1
  import { constructor, constants, methods } from "../interpreter/native.js";
2
- import { InterpreterRuntimeError, rangeError } from "../interpreter/model.js";
2
+ import { rangeError, typeError } from "../interpreter/model.js";
3
3
  import { coercion, coerceToString } from "./value.js";
4
- export const numberGlobal = (runner) => {
5
- const protos = runner.prototypes;
6
- const number = constructor(protos, protos.Number, {
4
+ export const numberGlobal = (ctx) => {
5
+ const builtins = ctx.builtins;
6
+ const number = constructor(builtins, builtins.Number, {
7
7
  name: "Number",
8
8
  length: 1,
9
- call: coercion(runner, "Number").call,
9
+ call: coercion(ctx, "Number").call,
10
10
  });
11
11
  constants(number, {
12
12
  MAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER,
@@ -18,7 +18,7 @@ export const numberGlobal = (runner) => {
18
18
  POSITIVE_INFINITY: Number.POSITIVE_INFINITY,
19
19
  NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
20
20
  });
21
- methods(protos, number, [
21
+ methods(builtins, number, [
22
22
  ["isInteger", 1, (_, args) => Number.isInteger(args[0])],
23
23
  ["isFinite", 1, (_, args) => Number.isFinite(args[0])],
24
24
  ["isNaN", 1, (_, args) => Number.isNaN(args[0])],
@@ -26,79 +26,75 @@ export const numberGlobal = (runner) => {
26
26
  [
27
27
  "parseInt",
28
28
  2,
29
- (_, args, node) => {
29
+ (_, args) => {
30
30
  const radix = args[1];
31
31
  if (radix !== undefined && typeof radix !== "number") {
32
- throw new InterpreterRuntimeError("Number.parseInt expects a numeric radix.", node);
32
+ throw typeError("Number.parseInt expects a numeric radix.");
33
33
  }
34
34
  return parseInt(coerceToString(args[0]), radix);
35
35
  },
36
36
  ],
37
37
  ["parseFloat", 1, (_, args) => parseFloat(coerceToString(args[0]))],
38
38
  ]);
39
- const self = (thisValue, name, node) => {
39
+ const self = (thisValue, name) => {
40
40
  if (typeof thisValue === "number")
41
41
  return thisValue;
42
- throw new InterpreterRuntimeError(`Number.prototype.${name} requires that 'this' be a Number.`, node);
42
+ throw typeError(`Number.prototype.${name} requires that 'this' be a Number.`);
43
43
  };
44
- const optNum = (name, arg, node) => {
44
+ const optNum = (name, arg) => {
45
45
  if (arg === undefined)
46
46
  return undefined;
47
47
  if (typeof arg !== "number")
48
- throw new InterpreterRuntimeError(`Number.${name} expects a number argument.`, node);
48
+ throw typeError(`Number.${name} expects a number argument.`);
49
49
  return arg;
50
50
  };
51
- methods(protos, protos.Number, [
52
- [
53
- "toFixed",
54
- 1,
55
- (thisValue, args, node) => self(thisValue, "toFixed", node).toFixed(optNum("toFixed", args[0], node)),
56
- ],
51
+ methods(builtins, builtins.Number, [
52
+ ["toFixed", 1, (thisValue, args) => self(thisValue, "toFixed").toFixed(optNum("toFixed", args[0]))],
57
53
  [
58
54
  "toExponential",
59
55
  1,
60
- (thisValue, args, node) => self(thisValue, "toExponential", node).toExponential(optNum("toExponential", args[0], node)),
56
+ (thisValue, args) => self(thisValue, "toExponential").toExponential(optNum("toExponential", args[0])),
61
57
  ],
62
58
  [
63
59
  "toPrecision",
64
60
  1,
65
- (thisValue, args, node) => {
66
- const value = self(thisValue, "toPrecision", node);
67
- const digits = optNum("toPrecision", args[0], node);
61
+ (thisValue, args) => {
62
+ const value = self(thisValue, "toPrecision");
63
+ const digits = optNum("toPrecision", args[0]);
68
64
  return digits === undefined ? value.toString() : value.toPrecision(digits);
69
65
  },
70
66
  ],
71
67
  [
72
68
  "toString",
73
69
  1,
74
- (thisValue, args, node) => {
75
- const value = self(thisValue, "toString", node);
76
- const radix = optNum("toString", args[0], node);
70
+ (thisValue, args) => {
71
+ const value = self(thisValue, "toString");
72
+ const radix = optNum("toString", args[0]);
77
73
  if (radix !== undefined && (radix < 2 || radix > 36)) {
78
- throw rangeError("Number.toString radix must be between 2 and 36.", node);
74
+ throw rangeError("Number.toString radix must be between 2 and 36.");
79
75
  }
80
76
  return value.toString(radix);
81
77
  },
82
78
  ],
83
- ["valueOf", 0, (thisValue, _, node) => self(thisValue, "valueOf", node)],
79
+ ["valueOf", 0, (thisValue) => self(thisValue, "valueOf")],
84
80
  ]);
85
81
  return number;
86
82
  };
87
- export const booleanGlobal = (runner) => {
88
- const protos = runner.prototypes;
89
- const boolean = constructor(protos, protos.Boolean, {
83
+ export const booleanGlobal = (ctx) => {
84
+ const builtins = ctx.builtins;
85
+ const boolean = constructor(builtins, builtins.Boolean, {
90
86
  name: "Boolean",
91
87
  length: 1,
92
- call: coercion(runner, "Boolean").call,
88
+ call: coercion(ctx, "Boolean").call,
93
89
  });
94
- const self = (thisValue, name, node) => {
90
+ const self = (thisValue, name) => {
95
91
  if (typeof thisValue === "boolean")
96
92
  return thisValue;
97
- throw new InterpreterRuntimeError(`Boolean.prototype.${name} requires that 'this' be a Boolean.`, node);
93
+ throw typeError(`Boolean.prototype.${name} requires that 'this' be a Boolean.`);
98
94
  };
99
- methods(protos, protos.Boolean, [
100
- ["toString", 0, (thisValue, _, node) => String(self(thisValue, "toString", node))],
101
- ["valueOf", 0, (thisValue, _, node) => self(thisValue, "valueOf", node)],
95
+ methods(builtins, builtins.Boolean, [
96
+ ["toString", 0, (thisValue) => String(self(thisValue, "toString"))],
97
+ ["valueOf", 0, (thisValue) => self(thisValue, "valueOf")],
102
98
  ]);
103
99
  return boolean;
104
100
  };