porffor 0.14.0-f67c123a1 → 0.16.0-08983b6b1
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.
- package/CONTRIBUTING.md +16 -10
- package/README.md +14 -30
- package/asur/index.js +1 -1
- package/compiler/2c.js +172 -59
- package/compiler/allocators.js +128 -0
- package/compiler/assemble.js +37 -5
- package/compiler/builtins/annexb_string.ts +1 -0
- package/compiler/builtins/array.ts +154 -7
- package/compiler/builtins/base64.ts +1 -0
- package/compiler/builtins/boolean.ts +3 -1
- package/compiler/builtins/console.ts +6 -0
- package/compiler/builtins/crypto.ts +1 -0
- package/compiler/builtins/date.ts +5 -30
- package/compiler/builtins/error.js +22 -0
- package/compiler/builtins/escape.ts +1 -2
- package/compiler/builtins/function.ts +2 -0
- package/compiler/builtins/int.ts +2 -0
- package/compiler/builtins/math.ts +410 -0
- package/compiler/builtins/number.ts +12 -21
- package/compiler/builtins/object.ts +2 -0
- package/compiler/builtins/porffor.d.ts +18 -0
- package/compiler/builtins/set.ts +22 -12
- package/compiler/builtins/string.ts +1 -0
- package/compiler/builtins/string_f64.ts +10 -0
- package/compiler/builtins/symbol.ts +62 -0
- package/compiler/builtins/z_ecma262.ts +62 -0
- package/compiler/builtins.js +50 -12
- package/compiler/codegen.js +826 -552
- package/compiler/cyclone.js +535 -0
- package/compiler/decompile.js +7 -1
- package/compiler/generated_builtins.js +635 -84
- package/compiler/havoc.js +93 -0
- package/compiler/index.js +108 -15
- package/compiler/opt.js +10 -44
- package/compiler/parse.js +3 -9
- package/compiler/pgo.js +212 -0
- package/compiler/precompile.js +17 -11
- package/compiler/prefs.js +13 -5
- package/compiler/prototype.js +200 -186
- package/compiler/wasmSpec.js +2 -2
- package/compiler/wrap.js +128 -44
- package/package.json +3 -5
- package/runner/index.js +31 -15
- package/runner/repl.js +18 -2
- /package/runner/{profiler.js → profile.js} +0 -0
@@ -0,0 +1,410 @@
|
|
1
|
+
import type {} from './porffor.d.ts';
|
2
|
+
|
3
|
+
// todo: use any and Number(x) in all these later
|
4
|
+
// todo: specify the rest of this file later
|
5
|
+
// todo/perf: make i32 variants later
|
6
|
+
// todo/perf: add a compiler pref for accuracy vs perf (epsilion?)
|
7
|
+
|
8
|
+
export const __Math_exp = (x: number): number => {
|
9
|
+
if (!Number.isFinite(x)) {
|
10
|
+
if (x == -Infinity) return 0;
|
11
|
+
return x;
|
12
|
+
}
|
13
|
+
|
14
|
+
if (x < 0) {
|
15
|
+
// exp(-x) = 1 / exp(+x)
|
16
|
+
return 1 / Math.exp(-x);
|
17
|
+
}
|
18
|
+
|
19
|
+
const k: number = Math.floor(x / Math.LN2);
|
20
|
+
const r: number = x - k * Math.LN2;
|
21
|
+
|
22
|
+
// Taylor series via Horner's method
|
23
|
+
let term: number = r;
|
24
|
+
let sum: number = 1 + r;
|
25
|
+
let i: number = 2;
|
26
|
+
|
27
|
+
while (Math.abs(term) > 1e-15) {
|
28
|
+
term *= r / i;
|
29
|
+
sum += term;
|
30
|
+
i++;
|
31
|
+
}
|
32
|
+
|
33
|
+
return sum * (1 << k);
|
34
|
+
};
|
35
|
+
|
36
|
+
export const __Math_log2 = (y: number): number => {
|
37
|
+
if (y <= 0) return NaN;
|
38
|
+
if (!Number.isFinite(y)) return y;
|
39
|
+
|
40
|
+
// approx using log knowledge
|
41
|
+
let x: number = y;
|
42
|
+
let exponent: number = 0;
|
43
|
+
|
44
|
+
while (x >= 2) {
|
45
|
+
x /= 2;
|
46
|
+
exponent++;
|
47
|
+
}
|
48
|
+
|
49
|
+
while (x < 1) {
|
50
|
+
x *= 2;
|
51
|
+
exponent--;
|
52
|
+
}
|
53
|
+
|
54
|
+
// 1 <= x < 2 -> 0 <= x < 1
|
55
|
+
x -= 1;
|
56
|
+
|
57
|
+
// refine with Newton-Raphson method
|
58
|
+
let delta: number;
|
59
|
+
do {
|
60
|
+
const e_x: number = Math.exp(x * Math.LN2);
|
61
|
+
delta = (e_x - y) / (e_x * Math.LN2);
|
62
|
+
x -= delta;
|
63
|
+
} while (Math.abs(delta) > 1e-15);
|
64
|
+
|
65
|
+
return x + exponent;
|
66
|
+
};
|
67
|
+
|
68
|
+
export const __Math_log = (y: number): number => {
|
69
|
+
if (y <= 0) {
|
70
|
+
if (y == 0) return -Infinity;
|
71
|
+
return NaN;
|
72
|
+
}
|
73
|
+
if (!Number.isFinite(y)) return y;
|
74
|
+
|
75
|
+
// guess using log knowledge
|
76
|
+
let x: number = y > 1 ? Math.log2(y) : 0;
|
77
|
+
|
78
|
+
// refine with Newton-Raphson method
|
79
|
+
let delta: number;
|
80
|
+
do {
|
81
|
+
const e_x: number = Math.exp(x);
|
82
|
+
delta = (e_x - y) / e_x;
|
83
|
+
x -= delta;
|
84
|
+
} while (Math.abs(delta) > 1e-15);
|
85
|
+
|
86
|
+
return x;
|
87
|
+
};
|
88
|
+
|
89
|
+
export const __Math_log10 = (x: number): number => {
|
90
|
+
if (x <= 0) {
|
91
|
+
if (x == 0) return -Infinity;
|
92
|
+
return NaN;
|
93
|
+
}
|
94
|
+
if (!Number.isFinite(x)) return x;
|
95
|
+
|
96
|
+
return Math.log(x) / Math.LN10;
|
97
|
+
};
|
98
|
+
|
99
|
+
// 21.3.2.26 Math.pow (base, exponent)
|
100
|
+
// https://tc39.es/ecma262/#sec-math.pow
|
101
|
+
export const __Math_pow = (base: number, exponent: number): number => {
|
102
|
+
// 1. Set base to ? ToNumber(base).
|
103
|
+
// 2. Set exponent to ? ToNumber(exponent).
|
104
|
+
// todo
|
105
|
+
|
106
|
+
// 3. Return Number::exponentiate(base, exponent).
|
107
|
+
|
108
|
+
// Number::exponentiate (base, exponent)
|
109
|
+
// https://tc39.es/ecma262/#sec-numeric-types-number-exponentiate
|
110
|
+
// 1. If exponent is NaN, return NaN.
|
111
|
+
if (Number.isNaN(exponent)) return NaN;
|
112
|
+
|
113
|
+
// 2. If exponent is either +0𝔽 or -0𝔽, return 1𝔽.
|
114
|
+
if (exponent == 0) return 1;
|
115
|
+
|
116
|
+
if (!Number.isFinite(base)) {
|
117
|
+
// 3. If base is NaN, return NaN.
|
118
|
+
if (Number.isNaN(base)) return base;
|
119
|
+
|
120
|
+
// 4. If base is +∞𝔽, then
|
121
|
+
if (base == Infinity) {
|
122
|
+
// a. If exponent > +0𝔽, return +∞𝔽. Otherwise, return +0𝔽.
|
123
|
+
if (exponent > 0) return base;
|
124
|
+
return 0;
|
125
|
+
}
|
126
|
+
|
127
|
+
// 5. If base is -∞𝔽, then
|
128
|
+
const isOdd = exponent % 2 == 1;
|
129
|
+
|
130
|
+
// a. If exponent > +0𝔽, then
|
131
|
+
if (exponent > 0) {
|
132
|
+
// i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
|
133
|
+
if (isOdd) return -Infinity;
|
134
|
+
return Infinity;
|
135
|
+
}
|
136
|
+
|
137
|
+
// b. Else,
|
138
|
+
// i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
|
139
|
+
if (isOdd) return -0;
|
140
|
+
return 0;
|
141
|
+
}
|
142
|
+
|
143
|
+
if (base == 0) {
|
144
|
+
// 6. If base is +0𝔽, then
|
145
|
+
if (1 / base == Infinity) {
|
146
|
+
// a. If exponent > +0𝔽, return +0𝔽. Otherwise, return +∞𝔽.
|
147
|
+
if (exponent > 0) return 0;
|
148
|
+
return Infinity;
|
149
|
+
}
|
150
|
+
|
151
|
+
// 7. If base is -0𝔽, then
|
152
|
+
const isOdd = exponent % 2 == 1;
|
153
|
+
|
154
|
+
// a. If exponent > +0𝔽, then
|
155
|
+
if (exponent > 0) {
|
156
|
+
// i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
|
157
|
+
if (isOdd) return -0;
|
158
|
+
return 0;
|
159
|
+
}
|
160
|
+
|
161
|
+
// b. Else,
|
162
|
+
// i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
|
163
|
+
if (isOdd) return -Infinity;
|
164
|
+
return Infinity;
|
165
|
+
}
|
166
|
+
|
167
|
+
// 8. Assert: base is finite and is neither +0𝔽 nor -0𝔽.
|
168
|
+
// todo
|
169
|
+
|
170
|
+
// 9. If exponent is +∞𝔽, then
|
171
|
+
if (exponent == Infinity) {
|
172
|
+
const abs = Math.abs(base);
|
173
|
+
|
174
|
+
// a. If abs(ℝ(base)) > 1, return +∞𝔽.
|
175
|
+
if (abs > 1) return Infinity;
|
176
|
+
|
177
|
+
// b. If abs(ℝ(base)) = 1, return NaN.
|
178
|
+
if (abs == 1) return NaN;
|
179
|
+
|
180
|
+
// c. If abs(ℝ(base)) < 1, return +0𝔽.
|
181
|
+
return 0;
|
182
|
+
}
|
183
|
+
|
184
|
+
// 10. If exponent is -∞𝔽, then
|
185
|
+
if (exponent == -Infinity) {
|
186
|
+
const abs = Math.abs(base);
|
187
|
+
|
188
|
+
// a. If abs(ℝ(base)) > 1, return +0𝔽.
|
189
|
+
if (abs > 1) return 0;
|
190
|
+
|
191
|
+
// b. If abs(ℝ(base)) = 1, return NaN.
|
192
|
+
if (abs == 1) return NaN;
|
193
|
+
|
194
|
+
// c. If abs(ℝ(base)) < 1, return +∞𝔽.
|
195
|
+
return Infinity;
|
196
|
+
}
|
197
|
+
|
198
|
+
// 11. Assert: exponent is finite and is neither +0𝔽 nor -0𝔽.
|
199
|
+
// todo
|
200
|
+
|
201
|
+
// 12. If base < -0𝔽 and exponent is not an integral Number, return NaN.
|
202
|
+
if (base < 0) if (!Number.isInteger(exponent)) return NaN;
|
203
|
+
|
204
|
+
// 13. Return an implementation-approximated Number value representing the result of raising ℝ(base) to the ℝ(exponent) power.
|
205
|
+
return Math.exp(exponent * Math.log(base));
|
206
|
+
};
|
207
|
+
|
208
|
+
|
209
|
+
export const __Math_expm1 = (x: number): number => {
|
210
|
+
if (!Number.isFinite(x)) {
|
211
|
+
if (x == -Infinity) return -1;
|
212
|
+
return x;
|
213
|
+
}
|
214
|
+
|
215
|
+
// use exp(x) - 1 for large x (perf)
|
216
|
+
if (Math.abs(x) > 1e-5) return Math.exp(x) - 1;
|
217
|
+
|
218
|
+
// Taylor series
|
219
|
+
let sum: number = x;
|
220
|
+
let term: number = x;
|
221
|
+
let i: number = 2;
|
222
|
+
|
223
|
+
while (Math.abs(term) > 1e-15) {
|
224
|
+
term *= x / i;
|
225
|
+
sum += term;
|
226
|
+
i++;
|
227
|
+
}
|
228
|
+
|
229
|
+
return sum;
|
230
|
+
};
|
231
|
+
|
232
|
+
export const __Math_log1p = (x: number): number => {
|
233
|
+
if (x == -1) return -Infinity; // log(0) = -inf
|
234
|
+
if (!Number.isFinite(x)) return x;
|
235
|
+
|
236
|
+
// use exp(x) - 1 for large x (perf)
|
237
|
+
if (Math.abs(x) > 1e-5) return Math.log(1 + x);
|
238
|
+
|
239
|
+
// Taylor series
|
240
|
+
let sum: number = 0;
|
241
|
+
let term: number = x;
|
242
|
+
let i: number = 2;
|
243
|
+
|
244
|
+
while (Math.abs(term) > 1e-15) {
|
245
|
+
term *= -x / i;
|
246
|
+
sum += term;
|
247
|
+
i++;
|
248
|
+
}
|
249
|
+
|
250
|
+
return sum;
|
251
|
+
};
|
252
|
+
|
253
|
+
|
254
|
+
export const __Math_sqrt = (y: number): number => {
|
255
|
+
if (y <= 0) {
|
256
|
+
if (y == 0) return 0;
|
257
|
+
return NaN;
|
258
|
+
}
|
259
|
+
if (!Number.isFinite(y)) return y;
|
260
|
+
|
261
|
+
// Babylonian method
|
262
|
+
let x: number = y;
|
263
|
+
let prev: number;
|
264
|
+
|
265
|
+
do {
|
266
|
+
prev = x;
|
267
|
+
x = 0.5 * (x + y / x);
|
268
|
+
} while (Math.abs(prev - x) > 1e-15);
|
269
|
+
|
270
|
+
return x;
|
271
|
+
};
|
272
|
+
|
273
|
+
export const __Math_cbrt = (y: number): number => {
|
274
|
+
if (y == 0) return 0; // cbrt(0) = 0
|
275
|
+
if (!Number.isFinite(y)) return y;
|
276
|
+
|
277
|
+
// Babylonian method
|
278
|
+
let x = Math.abs(y);
|
279
|
+
|
280
|
+
let prev: number;
|
281
|
+
|
282
|
+
do {
|
283
|
+
prev = x;
|
284
|
+
x = (2 * x + y / (x * x)) / 3;
|
285
|
+
} while (Math.abs(prev - x) > 1e-15);
|
286
|
+
|
287
|
+
return y < 0 ? -x : x;
|
288
|
+
};
|
289
|
+
|
290
|
+
|
291
|
+
// todo: varargs
|
292
|
+
export const __Math_hypot = (x: number, y: number): number => Math.sqrt(x * x + y * y);
|
293
|
+
|
294
|
+
export const __Math_sin = (x: number): number => {
|
295
|
+
// -inf <= x <= inf -> 0 <= x <= 2pi
|
296
|
+
const piX2: number = Math.PI * 2;
|
297
|
+
x %= piX2;
|
298
|
+
if (x < 0) x += piX2;
|
299
|
+
|
300
|
+
const x2: number = x * x;
|
301
|
+
|
302
|
+
return x * (
|
303
|
+
1 + x2 * (
|
304
|
+
-1.66666666666666307295e-1 + x2 * (
|
305
|
+
8.33333333332211858878e-3 + x2 * (
|
306
|
+
-1.98412698295895385996e-4 + x2 * (
|
307
|
+
2.75573136213857245213e-6 + x2 * (
|
308
|
+
-2.50507477628578072866e-8 + x2 * (
|
309
|
+
1.58962301576546568060e-10
|
310
|
+
)
|
311
|
+
)
|
312
|
+
)
|
313
|
+
)
|
314
|
+
)
|
315
|
+
)
|
316
|
+
);
|
317
|
+
|
318
|
+
// todo: investigate which is better (consider perf and accuracy)
|
319
|
+
// const x2 = x * x;
|
320
|
+
// const x4 = x2 * x2;
|
321
|
+
// const x6 = x4 * x2;
|
322
|
+
// const x8 = x4 * x4;
|
323
|
+
// const x10 = x6 * x4;
|
324
|
+
// const x12 = x6 * x6;
|
325
|
+
// const x14 = x12 * x2;
|
326
|
+
|
327
|
+
// return x * (
|
328
|
+
// 1 - x2 / 6 + x4 / 120 - x6 / 5040 + x8 / 362880 - x10 / 39916800 + x12 / 6227020800 - x14 / 1307674368000
|
329
|
+
// );
|
330
|
+
};
|
331
|
+
|
332
|
+
export const __Math_cos = (x: number): number => Math.sin(x - Math.PI / 2);
|
333
|
+
export const __Math_tan = (x: number): number => Math.sin(x) / Math.cos(x);
|
334
|
+
|
335
|
+
export const __Math_sinh = (x: number): number => (Math.exp(x) - Math.exp(-x)) / 2;
|
336
|
+
export const __Math_cosh = (x: number): number => (Math.exp(x) + Math.exp(-x)) / 2;
|
337
|
+
export const __Math_tanh = (x: number): number => Math.sinh(x) / Math.cosh(x);
|
338
|
+
|
339
|
+
|
340
|
+
export const __Math_asinh = (x: number): number => Math.log(x + Math.sqrt(x * x + 1));
|
341
|
+
export const __Math_acosh = (x: number): number => {
|
342
|
+
if (x < 1) return NaN;
|
343
|
+
return Math.log(x + Math.sqrt(x * x - 1));
|
344
|
+
};
|
345
|
+
export const __Math_atanh = (x: number): number => {
|
346
|
+
if (Math.abs(x) >= 1) return NaN;
|
347
|
+
return 0.5 * Math.log((1 + x) / (1 - x));
|
348
|
+
};
|
349
|
+
|
350
|
+
|
351
|
+
export const __Math_asin = (x: number): number => {
|
352
|
+
if (x <= -1) {
|
353
|
+
if (x == -1) return -Math.PI / 2;
|
354
|
+
return NaN;
|
355
|
+
}
|
356
|
+
if (x >= 1) {
|
357
|
+
if (x == 1) return Math.PI / 2;
|
358
|
+
return NaN;
|
359
|
+
}
|
360
|
+
|
361
|
+
// Taylor series
|
362
|
+
let sum: number = x;
|
363
|
+
let term: number = x;
|
364
|
+
let n: number = 1;
|
365
|
+
|
366
|
+
while (Math.abs(term) > 1e-15) {
|
367
|
+
term *= x * x * (2 * n - 1) * (2 * n - 1) / ((2 * n) * (2 * n + 1));
|
368
|
+
sum += term / (2 * n + 1);
|
369
|
+
n++;
|
370
|
+
}
|
371
|
+
|
372
|
+
return sum;
|
373
|
+
};
|
374
|
+
|
375
|
+
export const __Math_acos = (x: number): number => Math.asin(x) - Math.PI / 2;
|
376
|
+
|
377
|
+
export const __Math_atan = (x: number): number => {
|
378
|
+
if (x == Infinity) return Math.PI / 2
|
379
|
+
if (x == -Infinity) return -Math.PI / 2;
|
380
|
+
|
381
|
+
// Taylor series
|
382
|
+
let sum: number = x;
|
383
|
+
let term: number = x;
|
384
|
+
let n: number = 1;
|
385
|
+
|
386
|
+
while (Math.abs(term) > 1e-15) {
|
387
|
+
term *= -x * x * (2 * n - 1) / ((2 * n) * (2 * n + 1));
|
388
|
+
sum += term;
|
389
|
+
n++;
|
390
|
+
}
|
391
|
+
|
392
|
+
return sum;
|
393
|
+
};
|
394
|
+
|
395
|
+
export const __Math_atan2 = (y: number, x: number): number => {
|
396
|
+
if (x == 0) {
|
397
|
+
if (y > 0) return Math.PI / 2;
|
398
|
+
if (y < 0) return -Math.PI / 2;
|
399
|
+
|
400
|
+
return NaN;
|
401
|
+
}
|
402
|
+
|
403
|
+
const ratio = y / x;
|
404
|
+
if (x > 0) {
|
405
|
+
return Math.atan(ratio);
|
406
|
+
}
|
407
|
+
|
408
|
+
if (y >= 0) return Math.atan(ratio) + Math.PI;
|
409
|
+
return Math.atan(ratio) - Math.PI;
|
410
|
+
};
|
@@ -1,14 +1,14 @@
|
|
1
|
+
import type {} from './porffor.d.ts';
|
2
|
+
|
1
3
|
// radix: number|any for rawType check
|
2
4
|
export const __Number_prototype_toString = (_this: number, radix: number|any) => {
|
3
5
|
let out: bytestring = '';
|
4
6
|
let outPtr: i32 = Porffor.wasm`local.get ${out}`;
|
5
7
|
|
6
8
|
if (!Number.isFinite(_this)) {
|
7
|
-
if (Number.isNaN(_this)) out = 'NaN';
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
return out;
|
9
|
+
if (Number.isNaN(_this)) return out = 'NaN';
|
10
|
+
if (_this == Infinity) return out = 'Infinity';
|
11
|
+
return out = '-Infinity';
|
12
12
|
}
|
13
13
|
|
14
14
|
if (Porffor.rawType(radix) != Porffor.TYPES.number) {
|
@@ -22,8 +22,7 @@ export const __Number_prototype_toString = (_this: number, radix: number|any) =>
|
|
22
22
|
}
|
23
23
|
|
24
24
|
if (_this == 0) {
|
25
|
-
out = '0';
|
26
|
-
return out;
|
25
|
+
return out = '0';
|
27
26
|
}
|
28
27
|
|
29
28
|
// if negative value
|
@@ -97,7 +96,6 @@ export const __Number_prototype_toString = (_this: number, radix: number|any) =>
|
|
97
96
|
}
|
98
97
|
|
99
98
|
out.length = outPtr - Porffor.wasm`local.get ${out}`;
|
100
|
-
|
101
99
|
return out;
|
102
100
|
}
|
103
101
|
|
@@ -233,7 +231,6 @@ export const __Number_prototype_toString = (_this: number, radix: number|any) =>
|
|
233
231
|
}
|
234
232
|
|
235
233
|
out.length = outPtr - Porffor.wasm`local.get ${out}`;
|
236
|
-
|
237
234
|
return out;
|
238
235
|
};
|
239
236
|
|
@@ -242,11 +239,9 @@ export const __Number_prototype_toFixed = (_this: number, fractionDigits: number
|
|
242
239
|
let outPtr: i32 = Porffor.wasm`local.get ${out}`;
|
243
240
|
|
244
241
|
if (!Number.isFinite(_this)) {
|
245
|
-
if (Number.isNaN(_this)) out = 'NaN';
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
return out;
|
242
|
+
if (Number.isNaN(_this)) return out = 'NaN';
|
243
|
+
if (_this == Infinity) return out = 'Infinity';
|
244
|
+
return out = '-Infinity';
|
250
245
|
}
|
251
246
|
|
252
247
|
fractionDigits |= 0;
|
@@ -322,7 +317,6 @@ export const __Number_prototype_toFixed = (_this: number, fractionDigits: number
|
|
322
317
|
}
|
323
318
|
|
324
319
|
out.length = outPtr - Porffor.wasm`local.get ${out}`;
|
325
|
-
|
326
320
|
return out;
|
327
321
|
};
|
328
322
|
|
@@ -332,11 +326,9 @@ export const __Number_prototype_toExponential = (_this: number, fractionDigits:
|
|
332
326
|
let outPtr: i32 = Porffor.wasm`local.get ${out}`;
|
333
327
|
|
334
328
|
if (!Number.isFinite(_this)) {
|
335
|
-
if (Number.isNaN(_this)) out = 'NaN';
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
return out;
|
329
|
+
if (Number.isNaN(_this)) return out = 'NaN';
|
330
|
+
if (_this == Infinity) return out = 'Infinity';
|
331
|
+
return out = '-Infinity';
|
340
332
|
}
|
341
333
|
|
342
334
|
if (Porffor.rawType(fractionDigits) != Porffor.TYPES.number) {
|
@@ -517,7 +509,6 @@ export const __Number_prototype_toExponential = (_this: number, fractionDigits:
|
|
517
509
|
}
|
518
510
|
|
519
511
|
out.length = outPtr - Porffor.wasm`local.get ${out}`;
|
520
|
-
|
521
512
|
return out;
|
522
513
|
};
|
523
514
|
|
@@ -22,6 +22,21 @@ type PorfforGlobal = {
|
|
22
22
|
}
|
23
23
|
}
|
24
24
|
|
25
|
+
allocate(): any;
|
26
|
+
set: {
|
27
|
+
read(_this: any, index: number): i32;
|
28
|
+
write(_this: any, index: number, value: any): boolean;
|
29
|
+
}
|
30
|
+
|
31
|
+
bytestring: {
|
32
|
+
// defined in date.ts
|
33
|
+
appendStr(str: bytestring, appendage: bytestring): i32;
|
34
|
+
appendChar(str: bytestring, char: i32): i32;
|
35
|
+
appendPadNum(str: bytestring, num: number, len: number): i32;
|
36
|
+
}
|
37
|
+
|
38
|
+
print(x: any): i32;
|
39
|
+
|
25
40
|
randomByte(): i32;
|
26
41
|
|
27
42
|
type(x: any): bytestring;
|
@@ -48,6 +63,9 @@ type PorfforGlobal = {
|
|
48
63
|
|
49
64
|
s(...args: any): string;
|
50
65
|
bs(...args: any): bytestring;
|
66
|
+
|
67
|
+
readArgv(index: i32, out: bytestring): i32;
|
68
|
+
readFile(path: bytestring, out: bytestring): i32;
|
51
69
|
};
|
52
70
|
|
53
71
|
declare global {
|
package/compiler/builtins/set.ts
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
+
import type {} from './porffor.d.ts';
|
2
|
+
|
1
3
|
// dark wasm magic for dealing with memory, sorry.
|
2
4
|
export const __Porffor_allocate = (): number => {
|
3
|
-
Porffor.wasm`
|
4
|
-
memory.grow 0
|
5
|
-
drop
|
6
|
-
memory.size 0
|
5
|
+
Porffor.wasm`
|
7
6
|
i32.const 1
|
8
|
-
|
7
|
+
memory.grow 0
|
9
8
|
i32.const 65536
|
10
9
|
i32.mul
|
11
10
|
i32.from_u
|
@@ -56,14 +55,13 @@ i32.store8 0 12`;
|
|
56
55
|
};
|
57
56
|
|
58
57
|
|
59
|
-
|
60
|
-
export const __Set_prototype_size = (_this: Set) => {
|
58
|
+
export const __Set_prototype_size$get = (_this: Set) => {
|
61
59
|
return Porffor.wasm.i32.load(_this, 0, 0);
|
62
60
|
};
|
63
61
|
|
64
62
|
export const __Set_prototype_values = (_this: Set) => {
|
65
63
|
// todo: this should return an iterator not array
|
66
|
-
const size: number =
|
64
|
+
const size: number = Porffor.wasm.i32.load(_this, 0, 0);
|
67
65
|
|
68
66
|
const out: any[] = __Porffor_allocate();
|
69
67
|
for (let i: number = 0; i < size; i++) {
|
@@ -79,7 +77,7 @@ export const __Set_prototype_keys = (_this: Set) => {
|
|
79
77
|
};
|
80
78
|
|
81
79
|
export const __Set_prototype_has = (_this: Set, value: any) => {
|
82
|
-
const size: number =
|
80
|
+
const size: number = Porffor.wasm.i32.load(_this, 0, 0);
|
83
81
|
|
84
82
|
for (let i: number = 0; i < size; i++) {
|
85
83
|
if (__Porffor_set_read(_this, i) === value) return true;
|
@@ -89,7 +87,7 @@ export const __Set_prototype_has = (_this: Set, value: any) => {
|
|
89
87
|
};
|
90
88
|
|
91
89
|
export const __Set_prototype_add = (_this: Set, value: any) => {
|
92
|
-
const size: number =
|
90
|
+
const size: number = Porffor.wasm.i32.load(_this, 0, 0);
|
93
91
|
|
94
92
|
// check if already in set
|
95
93
|
for (let i: number = 0; i < size; i++) {
|
@@ -107,7 +105,7 @@ export const __Set_prototype_add = (_this: Set, value: any) => {
|
|
107
105
|
};
|
108
106
|
|
109
107
|
export const __Set_prototype_delete = (_this: Set, value: any) => {
|
110
|
-
const size: number =
|
108
|
+
const size: number = Porffor.wasm.i32.load(_this, 0, 0);
|
111
109
|
|
112
110
|
// check if already in set
|
113
111
|
for (let i: number = 0; i < size; i++) {
|
@@ -184,4 +182,16 @@ export const Set$constructor = (iterable: any): Set => {
|
|
184
182
|
}
|
185
183
|
|
186
184
|
return out;
|
187
|
-
};
|
185
|
+
};
|
186
|
+
|
187
|
+
export const __Set_prototype_union = (_this: Set, other: any) => {
|
188
|
+
if (Porffor.rawType(other) != Porffor.TYPES.set) {
|
189
|
+
throw new TypeError("Set.prototype.union\'s \'other\' argument must be a Set");
|
190
|
+
}
|
191
|
+
|
192
|
+
const out: Set = Set$constructor(_this);
|
193
|
+
for (const x of other) {
|
194
|
+
out.add(x);
|
195
|
+
}
|
196
|
+
return out;
|
197
|
+
};
|
@@ -0,0 +1,10 @@
|
|
1
|
+
// todo: support non-bytestring properly
|
2
|
+
export const String = (value: any): bytestring => {
|
3
|
+
if (Porffor.rawType(value) == Porffor.TYPES.symbol) return __Symbol_prototype_toString(value);
|
4
|
+
return __ecma262_ToString(value);
|
5
|
+
};
|
6
|
+
|
7
|
+
// todo: support constructor/string objects properly
|
8
|
+
export const String$constructor = (value: any): bytestring => {
|
9
|
+
return __ecma262_ToString(value);
|
10
|
+
};
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import type {} from './porffor.d.ts';
|
2
|
+
|
3
|
+
export const __Porffor_symbol_descStore = (op: boolean, value: any): any => {
|
4
|
+
const ptr: bytestring = '';
|
5
|
+
|
6
|
+
if (op) { // write
|
7
|
+
const size: number = Porffor.wasm.i32.load(ptr, 0, 0);
|
8
|
+
Porffor.wasm.i32.store(ptr, size + 1, 0, 0)
|
9
|
+
|
10
|
+
// reuse set internals to store description
|
11
|
+
Porffor.set.write(ptr, size, value);
|
12
|
+
return size;
|
13
|
+
} else { // read
|
14
|
+
return Porffor.set.read(ptr, value);
|
15
|
+
}
|
16
|
+
};
|
17
|
+
|
18
|
+
export const Symbol = (description: any): Symbol => {
|
19
|
+
// 1-based so always truthy as numeric value
|
20
|
+
return __Porffor_symbol_descStore(true, description) + 1;
|
21
|
+
};
|
22
|
+
|
23
|
+
export const __Symbol_prototype_description$get = (_this: Symbol) => {
|
24
|
+
const description: bytestring =
|
25
|
+
__Porffor_symbol_descStore(false, Porffor.wasm`local.get ${_this}` - 1);
|
26
|
+
return description;
|
27
|
+
};
|
28
|
+
|
29
|
+
export const __Symbol_prototype_toString = (_this: Symbol) => {
|
30
|
+
let out: bytestring = '';
|
31
|
+
|
32
|
+
// Symbol(
|
33
|
+
Porffor.wasm.i32.store8(out, 83, 0, 4);
|
34
|
+
Porffor.wasm.i32.store8(out, 121, 0, 5);
|
35
|
+
Porffor.wasm.i32.store8(out, 109, 0, 6);
|
36
|
+
Porffor.wasm.i32.store8(out, 98, 0, 7);
|
37
|
+
Porffor.wasm.i32.store8(out, 111, 0, 8);
|
38
|
+
Porffor.wasm.i32.store8(out, 108, 0, 9);
|
39
|
+
Porffor.wasm.i32.store8(out, 40, 0, 10);
|
40
|
+
|
41
|
+
const description: bytestring =
|
42
|
+
__Porffor_symbol_descStore(false, Porffor.wasm`local.get ${_this}` - 1);
|
43
|
+
|
44
|
+
const descLen: i32 = description.length;
|
45
|
+
let outPtr: i32 = Porffor.wasm`local.get ${out}` + 7;
|
46
|
+
let descPtr: i32 = Porffor.wasm`local.get ${description}`;
|
47
|
+
const descPtrEnd: i32 = descPtr + descLen;
|
48
|
+
while (descPtr < descPtrEnd) {
|
49
|
+
Porffor.wasm.i32.store8(outPtr++, Porffor.wasm.i32.load8_u(descPtr++, 0, 4), 0, 4);
|
50
|
+
}
|
51
|
+
|
52
|
+
// )
|
53
|
+
Porffor.wasm.i32.store8(Porffor.wasm`local.get ${out}` + descLen, 41, 0, 11);
|
54
|
+
|
55
|
+
out.length = 8 + descLen;
|
56
|
+
|
57
|
+
return out;
|
58
|
+
};
|
59
|
+
|
60
|
+
export const __Symbol_prototype_valueOf = (_this: Symbol) => {
|
61
|
+
return _this;
|
62
|
+
};
|