porffor 0.14.0-b481bfc5f → 0.14.0-bb0b06c17

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.
@@ -116,6 +116,20 @@ export default (funcs, globals, tags, pages, data, flags) => {
116
116
  ] ])
117
117
  );
118
118
 
119
+ if (pages.has('func argc lut')) {
120
+ // generate func argc lut data
121
+ const bytes = [];
122
+ for (let i = 0; i < funcs.length; i++) {
123
+ const argc = Math.floor(funcs[i].params.length / 2);
124
+ bytes.push(argc % 256, (argc / 256 | 0) % 256);
125
+ }
126
+
127
+ data.push({
128
+ offset: pages.get('func argc lut').ind * pageSize,
129
+ bytes
130
+ });
131
+ }
132
+
119
133
  // const t0 = performance.now();
120
134
 
121
135
  // specially optimized assembly for globals as this version is much (>5x) faster than traditional createSection()
@@ -144,4 +144,80 @@ export const __Array_prototype_toReversed = (_this: any[]) => {
144
144
 
145
145
  export const __Array_prototype_valueOf = (_this: any[]) => {
146
146
  return _this;
147
+ };
148
+
149
+
150
+ export const __Array_prototype_forEach = (_this: any[], callbackFn: any) => {
151
+ const len: i32 = _this.length;
152
+ let i: i32 = 0;
153
+ while (i < len) {
154
+ callbackFn(_this[i], i++, _this);
155
+ }
156
+ };
157
+
158
+ export const __Array_prototype_filter = (_this: any[], callbackFn: any) => {
159
+ const out: any[] = [];
160
+
161
+ const len: i32 = _this.length;
162
+ let i: i32 = 0;
163
+ while (i < len) {
164
+ const el: any = _this[i];
165
+ if (callbackFn(el, i++, _this)) out.push(el);
166
+ }
167
+
168
+ return out;
169
+ };
170
+
171
+ export const __Array_prototype_map = (_this: any[], callbackFn: any) => {
172
+ const out: any[] = [];
173
+
174
+ const len: i32 = _this.length;
175
+ let i: i32 = 0;
176
+ while (i < len) {
177
+ out.push(callbackFn(_this[i], i++, _this));
178
+ }
179
+
180
+ return out;
181
+ };
182
+
183
+ export const __Array_prototype_find = (_this: any[], callbackFn: any) => {
184
+ const len: i32 = _this.length;
185
+ let i: i32 = 0;
186
+ while (i < len) {
187
+ const el: any = _this[i];
188
+ if (callbackFn(el, i++, _this)) return el;
189
+ }
190
+ };
191
+
192
+ export const __Array_prototype_findLast = (_this: any[], callbackFn: any) => {
193
+ let i: i32 = _this.length;
194
+ while (i > 0) {
195
+ const el: any = _this[--i];
196
+ if (callbackFn(el, i, _this)) return el;
197
+ }
198
+ };
199
+
200
+ export const __Array_prototype_findIndex = (_this: any[], callbackFn: any) => {
201
+ const len: i32 = _this.length;
202
+ let i: i32 = 0;
203
+ while (i < len) {
204
+ if (callbackFn(_this[i], i++, _this)) return i;
205
+ }
206
+ };
207
+
208
+ export const __Array_prototype_findLastIndex = (_this: any[], callbackFn: any) => {
209
+ let i: i32 = _this.length;
210
+ while (i > 0) {
211
+ if (callbackFn(_this[--i], i, _this)) return i;
212
+ }
213
+ };
214
+
215
+ export const __Array_prototype_every = (_this: any[], callbackFn: any) => {
216
+ const len: i32 = _this.length;
217
+ let i: i32 = 0;
218
+ while (i < len) {
219
+ if (!callbackFn(_this[i], i++, _this)) return false;
220
+ }
221
+
222
+ return true;
147
223
  };
@@ -0,0 +1,408 @@
1
+ // todo: use any and Number(x) in all these later
2
+ // todo: specify the rest of this file later
3
+ // todo/perf: make i32 variants later
4
+ // todo/perf: add a compiler pref for accuracy vs perf (epsilion?)
5
+
6
+ export const __Math_exp = (x: number): number => {
7
+ if (!Number.isFinite(x)) {
8
+ if (x == -Infinity) return 0;
9
+ return x;
10
+ }
11
+
12
+ if (x < 0) {
13
+ // exp(-x) = 1 / exp(+x)
14
+ return 1 / Math.exp(-x);
15
+ }
16
+
17
+ const k: number = Math.floor(x / Math.LN2);
18
+ const r: number = x - k * Math.LN2;
19
+
20
+ // Horner's method
21
+ let term: number = r;
22
+ let sum: number = 1 + r;
23
+ let i: number = 2;
24
+
25
+ while (Math.abs(term) > 1e-15) {
26
+ term *= r / i;
27
+ sum += term;
28
+ i++;
29
+ }
30
+
31
+ return sum * (1 << k);
32
+ };
33
+
34
+ export const __Math_log2 = (y: number): number => {
35
+ if (y <= 0) return NaN;
36
+ if (!Number.isFinite(y)) return y;
37
+
38
+ // approx using log knowledge
39
+ let x: number = y;
40
+ let exponent: number = 0;
41
+
42
+ while (x >= 2) {
43
+ x /= 2;
44
+ exponent++;
45
+ }
46
+
47
+ while (x < 1) {
48
+ x *= 2;
49
+ exponent--;
50
+ }
51
+
52
+ // 1 <= x < 2 -> 0 <= x < 1
53
+ x -= 1;
54
+
55
+ // refine with Newton-Raphson method
56
+ let delta: number;
57
+ do {
58
+ const e_x: number = Math.exp(x * Math.LN2);
59
+ delta = (e_x - y) / (e_x * Math.LN2);
60
+ x -= delta;
61
+ } while (Math.abs(delta) > 1e-15);
62
+
63
+ return x + exponent;
64
+ };
65
+
66
+ export const __Math_log = (y: number): number => {
67
+ if (y <= 0) {
68
+ if (y == 0) return -Infinity;
69
+ return NaN;
70
+ }
71
+ if (!Number.isFinite(y)) return y;
72
+
73
+ // guess using log knowledge
74
+ let x: number = y > 1 ? Math.log2(y) : 0;
75
+
76
+ // refine with Newton-Raphson method
77
+ let delta: number;
78
+ do {
79
+ const e_x: number = Math.exp(x);
80
+ delta = (e_x - y) / e_x;
81
+ x -= delta;
82
+ } while (Math.abs(delta) > 1e-15);
83
+
84
+ return x;
85
+ };
86
+
87
+ export const __Math_log10 = (x: number): number => {
88
+ if (x <= 0) {
89
+ if (x == 0) return -Infinity;
90
+ return NaN;
91
+ }
92
+ if (!Number.isFinite(x)) return x;
93
+
94
+ return Math.log(x) / Math.LN10;
95
+ };
96
+
97
+ // 21.3.2.26 Math.pow (base, exponent)
98
+ // https://tc39.es/ecma262/#sec-math.pow
99
+ export const __Math_pow = (base: number, exponent: number): number => {
100
+ // 1. Set base to ? ToNumber(base).
101
+ // 2. Set exponent to ? ToNumber(exponent).
102
+ // todo
103
+
104
+ // 3. Return Number::exponentiate(base, exponent).
105
+
106
+ // Number::exponentiate (base, exponent)
107
+ // https://tc39.es/ecma262/#sec-numeric-types-number-exponentiate
108
+ // 1. If exponent is NaN, return NaN.
109
+ if (Number.isNaN(exponent)) return NaN;
110
+
111
+ // 2. If exponent is either +0𝔽 or -0𝔽, return 1𝔽.
112
+ if (exponent == 0) return 1;
113
+
114
+ if (!Number.isFinite(base)) {
115
+ // 3. If base is NaN, return NaN.
116
+ if (Number.isNaN(base)) return base;
117
+
118
+ // 4. If base is +∞𝔽, then
119
+ if (base == Infinity) {
120
+ // a. If exponent > +0𝔽, return +∞𝔽. Otherwise, return +0𝔽.
121
+ if (exponent > 0) return base;
122
+ return 0;
123
+ }
124
+
125
+ // 5. If base is -∞𝔽, then
126
+ const isOdd = exponent % 2 == 1;
127
+
128
+ // a. If exponent > +0𝔽, then
129
+ if (exponent > 0) {
130
+ // i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
131
+ if (isOdd) return -Infinity;
132
+ return Infinity;
133
+ }
134
+
135
+ // b. Else,
136
+ // i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
137
+ if (isOdd) return -0;
138
+ return 0;
139
+ }
140
+
141
+ if (base == 0) {
142
+ // 6. If base is +0𝔽, then
143
+ if (1 / base == Infinity) {
144
+ // a. If exponent > +0𝔽, return +0𝔽. Otherwise, return +∞𝔽.
145
+ if (exponent > 0) return 0;
146
+ return Infinity;
147
+ }
148
+
149
+ // 7. If base is -0𝔽, then
150
+ const isOdd = exponent % 2 == 1;
151
+
152
+ // a. If exponent > +0𝔽, then
153
+ if (exponent > 0) {
154
+ // i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
155
+ if (isOdd) return -0;
156
+ return 0;
157
+ }
158
+
159
+ // b. Else,
160
+ // i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
161
+ if (isOdd) return -Infinity;
162
+ return Infinity;
163
+ }
164
+
165
+ // 8. Assert: base is finite and is neither +0𝔽 nor -0𝔽.
166
+ // todo
167
+
168
+ // 9. If exponent is +∞𝔽, then
169
+ if (exponent == Infinity) {
170
+ const abs = Math.abs(base);
171
+
172
+ // a. If abs(ℝ(base)) > 1, return +∞𝔽.
173
+ if (abs > 1) return Infinity;
174
+
175
+ // b. If abs(ℝ(base)) = 1, return NaN.
176
+ if (abs == 1) return NaN;
177
+
178
+ // c. If abs(ℝ(base)) < 1, return +0𝔽.
179
+ return 0;
180
+ }
181
+
182
+ // 10. If exponent is -∞𝔽, then
183
+ if (exponent == -Infinity) {
184
+ const abs = Math.abs(base);
185
+
186
+ // a. If abs(ℝ(base)) > 1, return +0𝔽.
187
+ if (abs > 1) return 0;
188
+
189
+ // b. If abs(ℝ(base)) = 1, return NaN.
190
+ if (abs == 1) return NaN;
191
+
192
+ // c. If abs(ℝ(base)) < 1, return +∞𝔽.
193
+ return Infinity;
194
+ }
195
+
196
+ // 11. Assert: exponent is finite and is neither +0𝔽 nor -0𝔽.
197
+ // todo
198
+
199
+ // 12. If base < -0𝔽 and exponent is not an integral Number, return NaN.
200
+ if (base < 0) if (!Number.isInteger(exponent)) return NaN;
201
+
202
+ // 13. Return an implementation-approximated Number value representing the result of raising ℝ(base) to the ℝ(exponent) power.
203
+ return Math.exp(exponent * Math.log(base));
204
+ };
205
+
206
+
207
+ export const __Math_expm1 = (x: number): number => {
208
+ if (!Number.isFinite(x)) {
209
+ if (x == -Infinity) return -1;
210
+ return x;
211
+ }
212
+
213
+ // use exp(x) - 1 for large x (perf)
214
+ if (Math.abs(x) > 1e-5) return Math.exp(x) - 1;
215
+
216
+ // Taylor series
217
+ let sum: number = x;
218
+ let term: number = x;
219
+ let i: number = 2;
220
+
221
+ while (Math.abs(term) > 1e-15) {
222
+ term *= x / i;
223
+ sum += term;
224
+ i++;
225
+ }
226
+
227
+ return sum;
228
+ };
229
+
230
+ export const __Math_log1p = (x: number): number => {
231
+ if (x == -1) return -Infinity; // log(0) = -inf
232
+ if (!Number.isFinite(x)) return x;
233
+
234
+ // use exp(x) - 1 for large x (perf)
235
+ if (Math.abs(x) > 1e-5) return Math.log(1 + x);
236
+
237
+ // Taylor series
238
+ let sum: number = 0;
239
+ let term: number = x;
240
+ let i: number = 2;
241
+
242
+ while (Math.abs(term) > 1e-15) {
243
+ term *= -x / i;
244
+ sum += term;
245
+ i++;
246
+ }
247
+
248
+ return sum;
249
+ };
250
+
251
+
252
+ export const __Math_sqrt = (y: number): number => {
253
+ if (y <= 0) {
254
+ if (y == 0) return 0;
255
+ return NaN;
256
+ }
257
+ if (!Number.isFinite(y)) return y;
258
+
259
+ // Babylonian method
260
+ let x: number = y;
261
+ let prev: number;
262
+
263
+ do {
264
+ prev = x;
265
+ x = 0.5 * (x + y / x);
266
+ } while (Math.abs(prev - x) > 1e-15);
267
+
268
+ return x;
269
+ };
270
+
271
+ export const __Math_cbrt = (y: number): number => {
272
+ if (y == 0) return 0; // cbrt(0) = 0
273
+ if (!Number.isFinite(y)) return y;
274
+
275
+ // Babylonian method
276
+ let x = Math.abs(y);
277
+
278
+ let prev: number;
279
+
280
+ do {
281
+ prev = x;
282
+ x = (2 * x + y / (x * x)) / 3;
283
+ } while (Math.abs(prev - x) > 1e-15);
284
+
285
+ return y < 0 ? -x : x;
286
+ };
287
+
288
+
289
+ // todo: varargs
290
+ export const __Math_hypot = (x: number, y: number): number => Math.sqrt(x * x + y * y);
291
+
292
+ export const __Math_sin = (x: number): number => {
293
+ // -inf <= x <= inf -> 0 <= x <= 2pi
294
+ const piX2: number = Math.PI * 2;
295
+ x %= piX2;
296
+ if (x < 0) x += piX2;
297
+
298
+ const x2: number = x * x;
299
+
300
+ return x * (
301
+ 1 + x2 * (
302
+ -1.66666666666666307295e-1 + x2 * (
303
+ 8.33333333332211858878e-3 + x2 * (
304
+ -1.98412698295895385996e-4 + x2 * (
305
+ 2.75573136213857245213e-6 + x2 * (
306
+ -2.50507477628578072866e-8 + x2 * (
307
+ 1.58962301576546568060e-10
308
+ )
309
+ )
310
+ )
311
+ )
312
+ )
313
+ )
314
+ );
315
+
316
+ // todo: investigate which is better (consider perf and accuracy)
317
+ // const x2 = x * x;
318
+ // const x4 = x2 * x2;
319
+ // const x6 = x4 * x2;
320
+ // const x8 = x4 * x4;
321
+ // const x10 = x6 * x4;
322
+ // const x12 = x6 * x6;
323
+ // const x14 = x12 * x2;
324
+
325
+ // return x * (
326
+ // 1 - x2 / 6 + x4 / 120 - x6 / 5040 + x8 / 362880 - x10 / 39916800 + x12 / 6227020800 - x14 / 1307674368000
327
+ // );
328
+ };
329
+
330
+ export const __Math_cos = (x: number): number => Math.sin(x - Math.PI / 2);
331
+ export const __Math_tan = (x: number): number => Math.sin(x) / Math.cos(x);
332
+
333
+ export const __Math_sinh = (x: number): number => (Math.exp(x) - Math.exp(-x)) / 2;
334
+ export const __Math_cosh = (x: number): number => (Math.exp(x) + Math.exp(-x)) / 2;
335
+ export const __Math_tanh = (x: number): number => Math.sinh(x) / Math.cosh(x);
336
+
337
+
338
+ export const __Math_asinh = (x: number): number => Math.log(x + Math.sqrt(x * x + 1));
339
+ export const __Math_acosh = (x: number): number => {
340
+ if (x < 1) return NaN;
341
+ return Math.log(x + Math.sqrt(x * x - 1));
342
+ };
343
+ export const __Math_atanh = (x: number): number => {
344
+ if (Math.abs(x) >= 1) return NaN;
345
+ return 0.5 * Math.log((1 + x) / (1 - x));
346
+ };
347
+
348
+
349
+ export const __Math_asin = (x: number): number => {
350
+ if (x <= -1) {
351
+ if (x == -1) return -Math.PI / 2;
352
+ return NaN;
353
+ }
354
+ if (x >= 1) {
355
+ if (x == 1) return Math.PI / 2;
356
+ return NaN;
357
+ }
358
+
359
+ // Taylor series
360
+ let sum: number = x;
361
+ let term: number = x;
362
+ let n: number = 1;
363
+
364
+ while (Math.abs(term) > 1e-15) {
365
+ term *= x * x * (2 * n - 1) * (2 * n - 1) / ((2 * n) * (2 * n + 1));
366
+ sum += term / (2 * n + 1);
367
+ n++;
368
+ }
369
+
370
+ return sum;
371
+ };
372
+
373
+ export const __Math_acos = (x: number): number => Math.asin(x) - Math.PI / 2;
374
+
375
+ export const __Math_atan = (x: number): number => {
376
+ if (x == Infinity) return Math.PI / 2
377
+ if (x == -Infinity) return -Math.PI / 2;
378
+
379
+ // Taylor series
380
+ let sum: number = x;
381
+ let term: number = x;
382
+ let n: number = 1;
383
+
384
+ while (Math.abs(term) > 1e-15) {
385
+ term *= -x * x * (2 * n - 1) / ((2 * n) * (2 * n + 1));
386
+ sum += term;
387
+ n++;
388
+ }
389
+
390
+ return sum;
391
+ };
392
+
393
+ export const __Math_atan2 = (y: number, x: number): number => {
394
+ if (x == 0) {
395
+ if (y > 0) return Math.PI / 2;
396
+ if (y < 0) return -Math.PI / 2;
397
+
398
+ return NaN;
399
+ }
400
+
401
+ const ratio = y / x;
402
+ if (x > 0) {
403
+ return Math.atan(ratio);
404
+ }
405
+
406
+ if (y >= 0) return Math.atan(ratio) + Math.PI;
407
+ return Math.atan(ratio) - Math.PI;
408
+ };
@@ -221,8 +221,7 @@ export const BuiltinFuncs = function() {
221
221
  typedParams: true,
222
222
  locals: [ Valtype.i32, Valtype.i32 ],
223
223
  returns: [],
224
- callsSelf: true,
225
- wasm: (scope, { typeSwitch }) => [
224
+ wasm: (scope, { typeSwitch, builtin }) => [
226
225
  ...typeSwitch(scope, [ [ Opcodes.local_get, 1 ] ], {
227
226
  [TYPES.number]: [
228
227
  [ Opcodes.local_get, 0 ],
@@ -327,14 +326,14 @@ export const BuiltinFuncs = function() {
327
326
 
328
327
  [ Opcodes.loop, Blocktype.void ],
329
328
 
330
- // print current char
329
+ // print current array element
331
330
  [ Opcodes.local_get, 2 ],
332
331
  [ Opcodes.load, 0, ValtypeSize.i32 ],
333
332
 
334
333
  [ Opcodes.local_get, 2 ],
335
334
  [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
336
335
 
337
- [ Opcodes.call, -1 ],
336
+ [ Opcodes.call, builtin('__Porffor_print') ],
338
337
 
339
338
  // increment pointer by sizeof valtype
340
339
  [ Opcodes.local_get, 2 ],