porffor 0.14.0-eca486960 → 0.16.0-594397507

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.
@@ -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,3 +1,5 @@
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 = '';
@@ -1,3 +1,5 @@
1
+ import type {} from './porffor.d.ts';
2
+
1
3
  export const __Object_prototype_toString = (_this: object) => {
2
4
  let out: bytestring = '[object Object]';
3
5
  return out;
@@ -22,6 +22,14 @@ 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
+ print(x: any): i32;
32
+
25
33
  randomByte(): i32;
26
34
 
27
35
  type(x: any): bytestring;
@@ -1,3 +1,5 @@
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
5
  Porffor.wasm`i32.const 1
@@ -183,4 +185,16 @@ export const Set$constructor = (iterable: any): Set => {
183
185
  }
184
186
 
185
187
  return out;
186
- };
188
+ };
189
+
190
+ export const __Set_prototype_union = (_this: Set, other: any) => {
191
+ if (Porffor.rawType(other) != Porffor.TYPES.set) {
192
+ throw new TypeError("Set.prototype.union\'s \'other\' argument must be a Set");
193
+ }
194
+
195
+ const out: Set = Set$constructor(_this);
196
+ for (const x of other) {
197
+ out.add(x);
198
+ }
199
+ return out;
200
+ };
@@ -1,4 +1,5 @@
1
1
  // @porf --valtype=i32
2
+ import type {} from './porffor.d.ts';
2
3
 
3
4
  export const __String_fromCharCode = (code: i32) => {
4
5
  // todo: support >1 arg
@@ -1,3 +1,5 @@
1
+ import type {} from './porffor.d.ts';
2
+
1
3
  export const __Porffor_symbol_descStore = (op: boolean, value: any): any => {
2
4
  const ptr: bytestring = '';
3
5
 
@@ -6,10 +8,10 @@ export const __Porffor_symbol_descStore = (op: boolean, value: any): any => {
6
8
  Porffor.wasm.i32.store(ptr, size + 1, 0, 0)
7
9
 
8
10
  // reuse set internals to store description
9
- __Porffor_set_write(ptr, size, value);
11
+ Porffor.set.write(ptr, size, value);
10
12
  return size;
11
13
  } else { // read
12
- return __Porffor_set_read(ptr, value);
14
+ return Porffor.set.read(ptr, value);
13
15
  }
14
16
  };
15
17
 
@@ -18,10 +20,9 @@ export const Symbol = (description: any): Symbol => {
18
20
  return __Porffor_symbol_descStore(true, description) + 1;
19
21
  };
20
22
 
21
- // todo: this should be a getter somehow not a method
22
23
  export const __Symbol_prototype_description$get = (_this: Symbol) => {
23
- const description: bytestring = __Porffor_symbol_descStore(false,
24
- Porffor.wasm`local.get ${_this}` - 1);
24
+ const description: bytestring =
25
+ __Porffor_symbol_descStore(false, Porffor.wasm`local.get ${_this}` - 1);
25
26
  return description;
26
27
  };
27
28
 
@@ -37,8 +38,8 @@ export const __Symbol_prototype_toString = (_this: Symbol) => {
37
38
  Porffor.wasm.i32.store8(out, 108, 0, 9);
38
39
  Porffor.wasm.i32.store8(out, 40, 0, 10);
39
40
 
40
- const description: bytestring = __Porffor_symbol_descStore(false,
41
- Porffor.wasm`local.get ${_this}` - 1);
41
+ const description: bytestring =
42
+ __Porffor_symbol_descStore(false, Porffor.wasm`local.get ${_this}` - 1);
42
43
 
43
44
  const descLen: i32 = description.length;
44
45
  let outPtr: i32 = Porffor.wasm`local.get ${out}` + 7;
@@ -40,6 +40,18 @@ export const importedFuncs = [
40
40
  import: 'z',
41
41
  params: 1,
42
42
  returns: 0
43
+ },
44
+ {
45
+ name: '__Porffor_readArgv',
46
+ import: 'w',
47
+ params: 2,
48
+ returns: 0
49
+ },
50
+ {
51
+ name: '__Porffor_readFile',
52
+ import: 'q',
53
+ params: 2,
54
+ returns: 0
43
55
  }
44
56
  ];
45
57
 
@@ -138,7 +150,7 @@ export const BuiltinVars = function() {
138
150
  this.Math = number(1);
139
151
 
140
152
  // wintercg(tm)
141
- this.__navigator_userAgent = (scope, { makeString }) => makeString(scope, `Porffor/0.14.0`, false, '__navigator_userAgent');
153
+ this.__navigator_userAgent = (scope, { makeString }) => makeString(scope, `Porffor/0.16.0`, false, '__navigator_userAgent');
142
154
  this.__navigator_userAgent.type = Prefs.bytestring ? TYPES.bytestring : TYPES.string;
143
155
 
144
156
  for (const x in TYPES) {
@@ -221,7 +233,7 @@ export const BuiltinFuncs = function() {
221
233
  typedParams: true,
222
234
  locals: [ Valtype.i32, Valtype.i32 ],
223
235
  returns: [],
224
- wasm: (scope, { typeSwitch }) => [
236
+ wasm: (scope, { typeSwitch, builtin }) => [
225
237
  ...typeSwitch(scope, [ [ Opcodes.local_get, 1 ] ], {
226
238
  [TYPES.number]: [
227
239
  [ Opcodes.local_get, 0 ],
@@ -317,7 +329,7 @@ export const BuiltinFuncs = function() {
317
329
 
318
330
  // make end pointer
319
331
  [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
320
- ...number(ValtypeSize[valtype], Valtype.i32),
332
+ ...number(ValtypeSize[valtype] + 1, Valtype.i32),
321
333
  [ Opcodes.i32_mul ],
322
334
 
323
335
  [ Opcodes.local_get, 2 ],
@@ -326,14 +338,18 @@ export const BuiltinFuncs = function() {
326
338
 
327
339
  [ Opcodes.loop, Blocktype.void ],
328
340
 
329
- // print current char
341
+ // print current array element
330
342
  [ Opcodes.local_get, 2 ],
331
- [ Opcodes.load, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
332
- [ Opcodes.call, importedFuncs.print ],
343
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
344
+
345
+ [ Opcodes.local_get, 2 ],
346
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
347
+
348
+ [ Opcodes.call, builtin('__Porffor_print') ],
333
349
 
334
350
  // increment pointer by sizeof valtype
335
351
  [ Opcodes.local_get, 2 ],
336
- ...number(ValtypeSize[valtype], Valtype.i32),
352
+ ...number(ValtypeSize[valtype] + 1, Valtype.i32),
337
353
  [ Opcodes.i32_add ],
338
354
  [ Opcodes.local_tee, 2 ],
339
355