@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,24 +1,36 @@
1
1
  import { Effect } from "effect";
2
- import { constructor, methods, prototypeFrom, receiver } from "../interpreter/native.js";
3
- import { rangeError } from "../interpreter/model.js";
4
- import { ProgramDate, ProgramObject } from "../interpreter/objects.js";
5
- import { toPrimitive, toPrimitiveNumber } from "../interpreter/runner.js";
2
+ import { HostFunction, sync } from "../interpreter/host.js";
3
+ import { InterpreterRuntimeError } from "../interpreter/model.js";
4
+ import { toPrimitive } from "../interpreter/runner.js";
5
+ import { Values } from "../values.js";
6
6
  import { coerceToNumber, coerceToString } from "./value.js";
7
- const constructDate = (runner, args, proto, node) => {
8
- if (args.length === 0)
9
- return Effect.succeed(new ProgramDate(proto, Date.now()));
10
- if (args.length === 1) {
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()));
17
- }
18
- const parts = args.map((arg) => coerceToNumber(arg));
19
- return Effect.succeed(new ProgramDate(proto, new Date(...parts).getTime()));
20
- };
21
- const getters = [
7
+ const dateSetterArguments = new Map([
8
+ ["setTime", 1],
9
+ ["setMilliseconds", 1],
10
+ ["setUTCMilliseconds", 1],
11
+ ["setSeconds", 2],
12
+ ["setUTCSeconds", 2],
13
+ ["setMinutes", 3],
14
+ ["setUTCMinutes", 3],
15
+ ["setHours", 4],
16
+ ["setUTCHours", 4],
17
+ ["setDate", 1],
18
+ ["setUTCDate", 1],
19
+ ["setMonth", 2],
20
+ ["setUTCMonth", 2],
21
+ ["setFullYear", 3],
22
+ ["setUTCFullYear", 3],
23
+ ]);
24
+ export const dateMethods = new Set([
25
+ "getTime",
26
+ "valueOf",
27
+ "toISOString",
28
+ "toJSON",
29
+ "toString",
30
+ "toDateString",
31
+ "toTimeString",
32
+ "toUTCString",
33
+ "toGMTString",
22
34
  "getFullYear",
23
35
  "getMonth",
24
36
  "getDate",
@@ -36,78 +48,161 @@ const getters = [
36
48
  "getUTCSeconds",
37
49
  "getUTCMilliseconds",
38
50
  "getTimezoneOffset",
39
- ];
40
- const setters = [
41
- ["setTime", 1],
42
- ["setMilliseconds", 1],
43
- ["setUTCMilliseconds", 1],
44
- ["setSeconds", 2],
45
- ["setUTCSeconds", 2],
46
- ["setMinutes", 3],
47
- ["setUTCMinutes", 3],
48
- ["setHours", 4],
49
- ["setUTCHours", 4],
50
- ["setDate", 1],
51
- ["setUTCDate", 1],
52
- ["setMonth", 2],
53
- ["setUTCMonth", 2],
54
- ["setFullYear", 3],
55
- ["setUTCFullYear", 3],
56
- ];
57
- export const dateGlobal = (runner) => {
58
- const protos = runner.prototypes;
59
- const proto = protos.Date;
60
- const date = constructor(protos, proto, {
61
- name: "Date",
62
- length: 7,
63
- // ISO instead of the host's locale string: date strings are deterministic and must not leak the host timezone.
64
- call: () => Effect.sync(() => new Date().toISOString()),
65
- construct: (args, newTarget, node) => constructDate(runner, args, prototypeFrom(newTarget, proto), node),
66
- });
67
- methods(protos, date, [
68
- ["now", 0, () => Date.now()],
69
- ["parse", 1, (_, args) => Date.parse(coerceToString(args[0]))],
70
- ["UTC", 7, (_, args) => Date.UTC(...args.map((arg) => coerceToNumber(arg)))],
71
- ]);
72
- const self = (thisValue, name, node) => receiver(ProgramDate, thisValue, `Date.prototype.${name}`, node);
73
- const iso = (value, node) => {
74
- if (!Number.isFinite(value.time))
75
- throw rangeError("Invalid time value.", node);
76
- return new Date(value.time).toISOString();
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)],
82
- [
83
- "toJSON",
84
- 1,
85
- (thisValue, _, node) => {
86
- const value = self(thisValue, "toJSON", node);
87
- return Number.isFinite(value.time) ? iso(value, node) : null;
88
- },
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]()]),
96
- ...setters.map(([name, length]) => [
97
- name,
98
- length,
99
- (thisValue, args, node) => {
100
- const target = self(thisValue, name, node);
101
- // Native setters read the current time before argument coercion, whose callbacks may mutate the Date.
102
- const hosted = new Date(target.time);
103
- return Effect.map(Effect.forEach(args.slice(0, length), (arg) => toPrimitiveNumber(runner, arg, node), {
104
- concurrency: 1,
105
- }), (values) => {
106
- target.time = hosted[name](...values);
107
- return target.time;
108
- });
109
- },
110
- ]),
111
- ]);
112
- return date;
51
+ ...dateSetterArguments.keys(),
52
+ ]);
53
+ const constructDate = (runner, args, node) => {
54
+ if (args.length === 0)
55
+ return Effect.succeed(new Values.Date(Date.now()));
56
+ if (args.length === 1) {
57
+ const arg = args[0];
58
+ if (arg instanceof Values.Date)
59
+ return Effect.succeed(new Values.Date(arg.time));
60
+ return Effect.map(toPrimitive(runner, arg, "number", node), (value) => typeof value === "string"
61
+ ? new Values.Date(Date.parse(value))
62
+ : new Values.Date(new Date(coerceToNumber(value)).getTime()));
63
+ }
64
+ const parts = args.map((arg) => coerceToNumber(arg));
65
+ return Effect.succeed(new Values.Date(new Date(...parts).getTime()));
66
+ };
67
+ export const dateGlobal = (runner) => new HostFunction({
68
+ name: "Date",
69
+ // ISO instead of the host's locale string: date strings are deterministic and must not leak the host timezone.
70
+ call: () => Effect.sync(() => new Date().toISOString()),
71
+ construct: (args, node) => constructDate(runner, args, node),
72
+ instanceOf: (value) => value instanceof Values.Date,
73
+ members: {
74
+ now: sync("Date.now", () => Date.now()),
75
+ parse: sync("Date.parse", (args) => Date.parse(coerceToString(args[0]))),
76
+ UTC: sync("Date.UTC", (args) => Date.UTC(...args.map((arg) => coerceToNumber(arg)))),
77
+ },
78
+ });
79
+ export const dateSetterArgumentCount = (name) => dateSetterArguments.get(name);
80
+ export const invokeDateMethod = (value, name, args, node, initialTime = value.time) => {
81
+ const hosted = new Date(initialTime);
82
+ switch (name) {
83
+ case "getTime":
84
+ case "valueOf":
85
+ return value.time;
86
+ case "toISOString":
87
+ if (!Number.isFinite(value.time))
88
+ throw new InterpreterRuntimeError("Invalid time value.", node).as("RangeError");
89
+ return hosted.toISOString();
90
+ case "toJSON":
91
+ return Number.isFinite(value.time) ? hosted.toISOString() : null;
92
+ case "toString":
93
+ return coerceToString(value);
94
+ case "toDateString":
95
+ return hosted.toDateString();
96
+ case "toTimeString":
97
+ return hosted.toTimeString();
98
+ case "toUTCString":
99
+ case "toGMTString":
100
+ return hosted.toUTCString();
101
+ case "getFullYear":
102
+ return hosted.getFullYear();
103
+ case "getMonth":
104
+ return hosted.getMonth();
105
+ case "getDate":
106
+ return hosted.getDate();
107
+ case "getDay":
108
+ return hosted.getDay();
109
+ case "getHours":
110
+ return hosted.getHours();
111
+ case "getMinutes":
112
+ return hosted.getMinutes();
113
+ case "getSeconds":
114
+ return hosted.getSeconds();
115
+ case "getMilliseconds":
116
+ return hosted.getMilliseconds();
117
+ case "getUTCFullYear":
118
+ return hosted.getUTCFullYear();
119
+ case "getUTCMonth":
120
+ return hosted.getUTCMonth();
121
+ case "getUTCDate":
122
+ return hosted.getUTCDate();
123
+ case "getUTCDay":
124
+ return hosted.getUTCDay();
125
+ case "getUTCHours":
126
+ return hosted.getUTCHours();
127
+ case "getUTCMinutes":
128
+ return hosted.getUTCMinutes();
129
+ case "getUTCSeconds":
130
+ return hosted.getUTCSeconds();
131
+ case "getUTCMilliseconds":
132
+ return hosted.getUTCMilliseconds();
133
+ case "getTimezoneOffset":
134
+ return hosted.getTimezoneOffset();
135
+ case "setTime":
136
+ return updateDate(value, hosted.setTime(args[0]));
137
+ case "setMilliseconds":
138
+ return updateDate(value, hosted.setMilliseconds(args[0]));
139
+ case "setUTCMilliseconds":
140
+ return updateDate(value, hosted.setUTCMilliseconds(args[0]));
141
+ case "setSeconds":
142
+ if (args.length < 2)
143
+ return updateDate(value, hosted.setSeconds(args[0]));
144
+ return updateDate(value, hosted.setSeconds(args[0], args[1]));
145
+ case "setUTCSeconds":
146
+ if (args.length < 2)
147
+ return updateDate(value, hosted.setUTCSeconds(args[0]));
148
+ return updateDate(value, hosted.setUTCSeconds(args[0], args[1]));
149
+ case "setMinutes":
150
+ if (args.length < 2)
151
+ return updateDate(value, hosted.setMinutes(args[0]));
152
+ if (args.length < 3)
153
+ return updateDate(value, hosted.setMinutes(args[0], args[1]));
154
+ return updateDate(value, hosted.setMinutes(args[0], args[1], args[2]));
155
+ case "setUTCMinutes":
156
+ if (args.length < 2)
157
+ return updateDate(value, hosted.setUTCMinutes(args[0]));
158
+ if (args.length < 3)
159
+ return updateDate(value, hosted.setUTCMinutes(args[0], args[1]));
160
+ return updateDate(value, hosted.setUTCMinutes(args[0], args[1], args[2]));
161
+ case "setHours":
162
+ if (args.length < 2)
163
+ return updateDate(value, hosted.setHours(args[0]));
164
+ if (args.length < 3)
165
+ return updateDate(value, hosted.setHours(args[0], args[1]));
166
+ if (args.length < 4)
167
+ return updateDate(value, hosted.setHours(args[0], args[1], args[2]));
168
+ return updateDate(value, hosted.setHours(args[0], args[1], args[2], args[3]));
169
+ case "setUTCHours":
170
+ if (args.length < 2)
171
+ return updateDate(value, hosted.setUTCHours(args[0]));
172
+ if (args.length < 3)
173
+ return updateDate(value, hosted.setUTCHours(args[0], args[1]));
174
+ if (args.length < 4)
175
+ return updateDate(value, hosted.setUTCHours(args[0], args[1], args[2]));
176
+ return updateDate(value, hosted.setUTCHours(args[0], args[1], args[2], args[3]));
177
+ case "setDate":
178
+ return updateDate(value, hosted.setDate(args[0]));
179
+ case "setUTCDate":
180
+ return updateDate(value, hosted.setUTCDate(args[0]));
181
+ case "setMonth":
182
+ if (args.length < 2)
183
+ return updateDate(value, hosted.setMonth(args[0]));
184
+ return updateDate(value, hosted.setMonth(args[0], args[1]));
185
+ case "setUTCMonth":
186
+ if (args.length < 2)
187
+ return updateDate(value, hosted.setUTCMonth(args[0]));
188
+ return updateDate(value, hosted.setUTCMonth(args[0], args[1]));
189
+ case "setFullYear":
190
+ if (args.length < 2)
191
+ return updateDate(value, hosted.setFullYear(args[0]));
192
+ if (args.length < 3)
193
+ return updateDate(value, hosted.setFullYear(args[0], args[1]));
194
+ return updateDate(value, hosted.setFullYear(args[0], args[1], args[2]));
195
+ case "setUTCFullYear":
196
+ if (args.length < 2)
197
+ return updateDate(value, hosted.setUTCFullYear(args[0]));
198
+ if (args.length < 3)
199
+ return updateDate(value, hosted.setUTCFullYear(args[0], args[1]));
200
+ return updateDate(value, hosted.setUTCFullYear(args[0], args[1], args[2]));
201
+ default:
202
+ throw new InterpreterRuntimeError(`Date method '${name}' is not available.`, node);
203
+ }
204
+ };
205
+ const updateDate = (value, time) => {
206
+ value.time = time;
207
+ return time;
113
208
  };
@@ -1,3 +1,3 @@
1
+ import { HostNamespace } from "../interpreter/host.js";
1
2
  import { type Runner } from "../interpreter/runner.js";
2
- import { ProgramObject } from "../interpreter/objects.js";
3
- export declare const jsonGlobal: <R>(runner: Runner<R>) => ProgramObject;
3
+ export declare const jsonGlobal: <R>(runner: Runner<R>) => HostNamespace;
@@ -1,28 +1,25 @@
1
1
  import { Effect } from "effect";
2
- import { methods } from "../interpreter/native.js";
2
+ import { HostFunction, HostNamespace } from "../interpreter/host.js";
3
3
  import { applyCollectionCallback } from "../interpreter/runner.js";
4
- import { InterpreterRuntimeError, syntaxError } from "../interpreter/model.js";
4
+ import { InterpreterRuntimeError } from "../interpreter/model.js";
5
5
  import { typeofValue } from "../interpreter/references.js";
6
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)],
13
- ]);
14
- return json;
15
- };
7
+ import { get, ownKeys, ProgramArray, ProgramObject, record, remove, set } from "../interpreter/objects.js";
8
+ import { Values } from "../values.js";
9
+ export const jsonGlobal = (runner) => new HostNamespace("JSON", {
10
+ parse: new HostFunction({ name: "JSON.parse", call: (args, node) => parse(runner, args, node) }),
11
+ stringify: new HostFunction({ name: "JSON.stringify", call: (args, node) => stringify(runner, args, node) }),
12
+ });
16
13
  const parse = (runner, args, node) => {
17
14
  const text = args[0];
18
15
  if (typeof text !== "string")
19
16
  throw new InterpreterRuntimeError("JSON.parse expects a string.", node);
20
17
  const parsed = (() => {
21
18
  try {
22
- return fromData(runner.prototypes, JSON.parse(text), "JSON.parse result");
19
+ return fromData(JSON.parse(text), "JSON.parse result");
23
20
  }
24
21
  catch (error) {
25
- throw syntaxError(`JSON.parse received invalid JSON: ${error instanceof Error ? error.message : String(error)}`, node);
22
+ throw new InterpreterRuntimeError(`JSON.parse received invalid JSON: ${error instanceof Error ? error.message : String(error)}`, node).as("SyntaxError");
26
23
  }
27
24
  })();
28
25
  if (typeofValue(args[1]) !== "function")
@@ -31,7 +28,7 @@ const parse = (runner, args, node) => {
31
28
  const visit = (holder, key) => Effect.gen(function* () {
32
29
  const value = get(holder, key);
33
30
  if (value instanceof ProgramObject) {
34
- for (const name of keys(value)) {
31
+ for (const name of ownKeys(value)) {
35
32
  const revived = yield* visit(value, name);
36
33
  if (revived === undefined)
37
34
  remove(value, name);
@@ -41,7 +38,7 @@ const parse = (runner, args, node) => {
41
38
  }
42
39
  return yield* apply([key, value]);
43
40
  });
44
- return visit(record(runner.prototypes.Object, { "": parsed }), "");
41
+ return visit(record({ "": parsed }), "");
45
42
  };
46
43
  const stringify = (runner, args, node) => {
47
44
  const space = args[2];
@@ -56,14 +53,14 @@ const stringify = (runner, args, node) => {
56
53
  return Effect.succeed(JSON.stringify(toData(args[0], "JSON.stringify value"), properties, indent));
57
54
  }
58
55
  // Validate up front; the replacer walk below reads the original value.
59
- toProgram(runner.prototypes, args[0], "JSON.stringify value");
56
+ toProgram(args[0], "JSON.stringify value");
60
57
  const apply = applyCollectionCallback(runner, replacer, "JSON.stringify", node);
61
58
  const stack = new Set();
62
59
  const visit = (holder, key) => Effect.gen(function* () {
63
- const value = yield* apply([key, yield* toJSONValue(runner, get(holder, key), key, node)]);
60
+ const value = yield* apply([key, toJSONValue(get(holder, key))]);
64
61
  if (value === undefined || typeofValue(value) === "function")
65
62
  return undefined;
66
- toProgram(runner.prototypes, value, "JSON.stringify replacer result");
63
+ toProgram(value, "JSON.stringify replacer result");
67
64
  if (typeof value === "number")
68
65
  return Number.isFinite(value) ? value : null;
69
66
  if (value === null || typeof value === "string" || typeof value === "boolean")
@@ -71,7 +68,7 @@ const stringify = (runner, args, node) => {
71
68
  if (!(value instanceof ProgramObject))
72
69
  return {};
73
70
  if (stack.has(value))
74
- throw new InterpreterRuntimeError("Converting circular structure to JSON.", node);
71
+ throw new InterpreterRuntimeError("Converting circular structure to JSON.", node).as("TypeError");
75
72
  stack.add(value);
76
73
  if (value instanceof ProgramArray) {
77
74
  const result = [];
@@ -82,7 +79,9 @@ const stringify = (runner, args, node) => {
82
79
  return result;
83
80
  }
84
81
  const result = Object.create(null);
85
- for (const name of keys(value)) {
82
+ for (const name of ownKeys(value)) {
83
+ if (typeof name !== "string")
84
+ continue;
86
85
  const item = yield* visit(value, name);
87
86
  if (item !== undefined)
88
87
  result[name] = item;
@@ -90,12 +89,13 @@ const stringify = (runner, args, node) => {
90
89
  stack.delete(value);
91
90
  return result;
92
91
  });
93
- return Effect.map(visit(record(runner.prototypes.Object, { "": args[0] }), ""), (value) => JSON.stringify(value, null, indent));
92
+ return Effect.map(visit(record({ "": args[0] }), ""), (value) => JSON.stringify(value, null, indent));
94
93
  };
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);
94
+ const toJSONValue = (value) => {
95
+ if (value instanceof Values.Date) {
96
+ return Number.isFinite(value.time) ? new Date(value.time).toISOString() : null;
97
+ }
98
+ if (value instanceof Values.URL)
99
+ return value.url.href;
100
+ return value;
101
101
  };
@@ -1,8 +1,8 @@
1
- import { ProgramObject } from "../interpreter/objects.js";
1
+ import { HostNamespace } from "../interpreter/host.js";
2
2
  import { type Runner } from "../interpreter/runner.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>(runner: Runner<R>) => HostNamespace;
@@ -1,8 +1,7 @@
1
1
  import { Effect } from "effect";
2
- import { constants, methods } from "../interpreter/native.js";
3
- import { InterpreterRuntimeError } from "../interpreter/model.js";
4
- import { ProgramObject } from "../interpreter/objects.js";
2
+ import { HostFunction, HostNamespace, sync } from "../interpreter/host.js";
5
3
  import { preserveConsumerError } from "../interpreter/runner.js";
4
+ import { InterpreterRuntimeError } from "../interpreter/model.js";
6
5
  // Validate only the arguments a method consumes; like JS, extras are ignored
7
6
  // (so built-ins work as callbacks receiving (element, index, array)).
8
7
  const number = (name, args, index, node) => {
@@ -13,97 +12,78 @@ const number = (name, args, index, node) => {
13
12
  throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
14
13
  return arg;
15
14
  };
16
- const unary = (name, op) => [
17
- name,
18
- 1,
19
- (_, args, node) => op(number(name, args, 0, node)),
20
- ];
21
- const binary = (name, op) => [
22
- name,
23
- 2,
24
- (_, args, node) => op(number(name, args, 0, node), number(name, args, 1, node)),
25
- ];
26
- const variadic = (name, op) => [
27
- name,
28
- 2,
29
- (_, args, node) => op(...args.map((arg) => {
30
- if (typeof arg !== "number")
31
- throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
32
- return arg;
33
- })),
34
- ];
35
- export const mathGlobal = (runner) => {
36
- const protos = runner.prototypes;
37
- const math = new ProgramObject(protos.Object);
38
- constants(math, {
39
- PI: Math.PI,
40
- E: Math.E,
41
- LN2: Math.LN2,
42
- LN10: Math.LN10,
43
- LOG2E: Math.LOG2E,
44
- LOG10E: Math.LOG10E,
45
- SQRT2: Math.SQRT2,
46
- SQRT1_2: Math.SQRT1_2,
47
- });
48
- methods(protos, math, [
49
- ["random", 0, () => Math.random()],
50
- variadic("max", Math.max),
51
- variadic("min", Math.min),
52
- variadic("hypot", Math.hypot),
53
- unary("abs", Math.abs),
54
- unary("acos", Math.acos),
55
- unary("acosh", Math.acosh),
56
- unary("asin", Math.asin),
57
- unary("asinh", Math.asinh),
58
- unary("atan", Math.atan),
59
- binary("atan2", Math.atan2),
60
- unary("atanh", Math.atanh),
61
- unary("floor", Math.floor),
62
- unary("ceil", Math.ceil),
63
- unary("round", Math.round),
64
- unary("trunc", Math.trunc),
65
- unary("sign", Math.sign),
66
- unary("sqrt", Math.sqrt),
67
- unary("cbrt", Math.cbrt),
68
- binary("pow", Math.pow),
69
- unary("cos", Math.cos),
70
- unary("cosh", Math.cosh),
71
- unary("sin", Math.sin),
72
- unary("sinh", Math.sinh),
73
- unary("tan", Math.tan),
74
- unary("tanh", Math.tanh),
75
- unary("log", Math.log),
76
- unary("log2", Math.log2),
77
- unary("log10", Math.log10),
78
- unary("log1p", Math.log1p),
79
- unary("exp", Math.exp),
80
- unary("expm1", Math.expm1),
81
- unary("f16round", Math.f16round),
82
- unary("fround", Math.fround),
83
- unary("clz32", Math.clz32),
84
- binary("imul", Math.imul),
85
- [
86
- "sumPrecise",
87
- 1,
88
- (_, args, node) => Effect.gen(function* () {
89
- const cursor = yield* runner.syncIterator(args[0], node);
90
- if (cursor === undefined) {
91
- throw new InterpreterRuntimeError("Math.sumPrecise expects a synchronous iterable.", node);
92
- }
93
- const numbers = [];
94
- while (true) {
95
- const step = yield* cursor.next;
96
- if (step.done)
97
- return Math.sumPrecise(numbers);
98
- yield* preserveConsumerError(cursor, Effect.sync(() => {
99
- if (typeof step.value !== "number") {
100
- throw new InterpreterRuntimeError("Math.sumPrecise expects an iterable of numbers.", node);
101
- }
102
- numbers.push(step.value);
103
- }));
15
+ const unary = (name, op) => sync(`Math.${name}`, (args, node) => op(number(name, args, 0, node)));
16
+ const binary = (name, op) => sync(`Math.${name}`, (args, node) => op(number(name, args, 0, node), number(name, args, 1, node)));
17
+ const variadic = (name, op) => sync(`Math.${name}`, (args, node) => op(...args.map((arg) => {
18
+ if (typeof arg !== "number")
19
+ throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
20
+ return arg;
21
+ })));
22
+ const sumPrecise = (runner) => new HostFunction({
23
+ name: "Math.sumPrecise",
24
+ call: (args, node) => Effect.gen(function* () {
25
+ const cursor = yield* runner.syncIterator(args[0], node);
26
+ if (cursor === undefined) {
27
+ throw new InterpreterRuntimeError("Math.sumPrecise expects a synchronous iterable.", node).as("TypeError");
28
+ }
29
+ const numbers = [];
30
+ while (true) {
31
+ const step = yield* cursor.next;
32
+ if (step.done)
33
+ return Math.sumPrecise(numbers);
34
+ yield* preserveConsumerError(cursor, Effect.sync(() => {
35
+ if (typeof step.value !== "number") {
36
+ throw new InterpreterRuntimeError("Math.sumPrecise expects an iterable of numbers.", node).as("TypeError");
104
37
  }
105
- }),
106
- ],
107
- ]);
108
- return math;
109
- };
38
+ numbers.push(step.value);
39
+ }));
40
+ }
41
+ }),
42
+ });
43
+ export const mathGlobal = (runner) => new HostNamespace("Math", {
44
+ PI: Math.PI,
45
+ E: Math.E,
46
+ LN2: Math.LN2,
47
+ LN10: Math.LN10,
48
+ LOG2E: Math.LOG2E,
49
+ LOG10E: Math.LOG10E,
50
+ SQRT2: Math.SQRT2,
51
+ SQRT1_2: Math.SQRT1_2,
52
+ random: sync("Math.random", () => Math.random()),
53
+ max: variadic("max", Math.max),
54
+ min: variadic("min", Math.min),
55
+ hypot: variadic("hypot", Math.hypot),
56
+ abs: unary("abs", Math.abs),
57
+ acos: unary("acos", Math.acos),
58
+ acosh: unary("acosh", Math.acosh),
59
+ asin: unary("asin", Math.asin),
60
+ asinh: unary("asinh", Math.asinh),
61
+ atan: unary("atan", Math.atan),
62
+ atan2: binary("atan2", Math.atan2),
63
+ atanh: unary("atanh", Math.atanh),
64
+ floor: unary("floor", Math.floor),
65
+ ceil: unary("ceil", Math.ceil),
66
+ round: unary("round", Math.round),
67
+ trunc: unary("trunc", Math.trunc),
68
+ sign: unary("sign", Math.sign),
69
+ sqrt: unary("sqrt", Math.sqrt),
70
+ cbrt: unary("cbrt", Math.cbrt),
71
+ pow: binary("pow", Math.pow),
72
+ cos: unary("cos", Math.cos),
73
+ cosh: unary("cosh", Math.cosh),
74
+ sin: unary("sin", Math.sin),
75
+ sinh: unary("sinh", Math.sinh),
76
+ tan: unary("tan", Math.tan),
77
+ tanh: unary("tanh", Math.tanh),
78
+ log: unary("log", Math.log),
79
+ log2: unary("log2", Math.log2),
80
+ log10: unary("log10", Math.log10),
81
+ log1p: unary("log1p", Math.log1p),
82
+ exp: unary("exp", Math.exp),
83
+ expm1: unary("expm1", Math.expm1),
84
+ f16round: unary("f16round", Math.f16round),
85
+ fround: unary("fround", Math.fround),
86
+ clz32: unary("clz32", Math.clz32),
87
+ imul: binary("imul", Math.imul),
88
+ sumPrecise: sumPrecise(runner),
89
+ });
@@ -1,3 +1,4 @@
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 AstNode } from "../interpreter/model.js";
2
+ export declare const numberMethods: Set<string>;
3
+ export declare const invokeNumberMethod: (value: number, name: string, args: Array<unknown>, node: AstNode) => unknown;
4
+ export declare const numberGlobal: import("../interpreter/host.js").HostFunction<never>;