porffor 0.61.2 → 0.61.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.
package/compiler/2c.js CHANGED
@@ -2,7 +2,6 @@ import { read_unsignedLEB128 } from './encoding.js';
2
2
  import { Blocktype, Opcodes, Valtype, PageSize } from './wasmSpec.js';
3
3
  import { operatorOpcode } from './expression.js';
4
4
  import { log } from './log.js';
5
- import './prefs.js';
6
5
 
7
6
  const CValtype = {
8
7
  i8: 'u8',
@@ -209,7 +208,7 @@ export default ({ funcs, globals, data, pages }) => {
209
208
 
210
209
  includes.set('stdint.h', true);
211
210
 
212
- globalThis.out = ``;
211
+ let out = '';
213
212
 
214
213
  for (const x in globals) {
215
214
  const g = globals[x];
@@ -281,6 +280,7 @@ export default ({ funcs, globals, data, pages }) => {
281
280
  if (cified.has(f.name)) return '';
282
281
  cified.add(f.name);
283
282
 
283
+ let topOfOut = '';
284
284
  let out = '';
285
285
 
286
286
  let depth = 1;
@@ -358,8 +358,7 @@ export default ({ funcs, globals, data, pages }) => {
358
358
 
359
359
  if (f.name === '__Porffor_promise_runJobs') {
360
360
  out += '}';
361
- globalThis.out = globalThis.out + out;
362
- return;
361
+ return topOfOut + out;
363
362
  }
364
363
 
365
364
  if (f.name === '#main') {
@@ -661,66 +660,6 @@ f64 _time_out${id} = (f64)_ts${id}.tv_sec * 1000.0 + (f64)_ts${id}.tv_nsec / 1.0
661
660
  break;
662
661
  }
663
662
 
664
- case '__Porffor_readArgv': {
665
- prepend.set('__Porffor_readArgv',
666
- `i32 __Porffor_readArgv(u32 index, u32 outPtr) {
667
- if (index >= _argc) {
668
- return -1;
669
- }
670
-
671
- char* arg = _argv[index];
672
-
673
- u32 read = 0;
674
- char* out = _memory + outPtr + 4;
675
- char ch;
676
- while ((ch = *(arg++)) != 0) {
677
- out[read++] = ch;
678
- }
679
-
680
- *((i32*)(_memory + outPtr)) = (i32)read;
681
- return read;
682
- }`);
683
-
684
- const outPtr = vals.pop();
685
- const index = vals.pop();
686
- vals.push(`(f64)__Porffor_readArgv((u32)(${index}), (u32)(${outPtr}))`);
687
- break;
688
- }
689
-
690
- case '__Porffor_readFile': {
691
- includes.set('stdio.h', true);
692
-
693
- prepend.set('__Porffor_readFile',
694
- `i32 __Porffor_readFile(u32 pathPtr, u32 outPtr) {
695
- FILE* fp;
696
- if (pathPtr == 0) {
697
- fp = stdin;
698
- } else {
699
- char* path = _memory + pathPtr + 4;
700
- fp = fopen(path, "r");
701
- if (fp == NULL) {
702
- return -1;
703
- }
704
- }
705
-
706
- u32 read = 0;
707
- char* out = _memory + outPtr + 4;
708
- char ch;
709
- while ((ch = fgetc(fp)) != EOF) {
710
- out[read++] = ch;
711
- }
712
-
713
- fclose(fp);
714
-
715
- *((i32*)(_memory + outPtr)) = (i32)read;
716
- return read;
717
- }`);
718
- const outPtr = vals.pop();
719
- const pathPtr = vals.pop();
720
- vals.push(`(f64)__Porffor_readFile((u32)(${pathPtr}), (u32)(${outPtr}))`);
721
- break;
722
- }
723
-
724
663
  default:
725
664
  log.warning('2c', `unimplemented import: ${importFunc.name}`);
726
665
  break;
@@ -730,7 +669,7 @@ f64 _time_out${id} = (f64)_ts${id}.tv_sec * 1000.0 + (f64)_ts${id}.tv_nsec / 1.0
730
669
  }
731
670
 
732
671
  if (!cified.has(func.name) && !ffiFuncs[func.name]) {
733
- cify(func);
672
+ topOfOut += cify(func);
734
673
  }
735
674
 
736
675
  let args = [];
@@ -951,12 +890,11 @@ f64 _time_out${id} = (f64)_ts${id}.tv_sec * 1000.0 + (f64)_ts${id}.tv_nsec / 1.0
951
890
  }
952
891
 
953
892
  out += '}\n\n';
954
-
955
- globalThis.out = globalThis.out + out;
893
+ return topOfOut + out;
956
894
  };
957
895
 
958
896
  for (const x of funcs) {
959
- if (x.export || x.name === '#main') cify(x);
897
+ if (x.export || x.name === '#main') out += cify(x);
960
898
  }
961
899
 
962
900
  const rawParams = f => {
@@ -25,14 +25,12 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
25
25
  if (f.usesImports) for (let j = 0; j < f.wasm.length; j++) {
26
26
  const x = f.wasm[j];
27
27
  if (x[0] === Opcodes.call && x[1] < importedFuncs.length) {
28
- const idx = x[1];
29
- const func = importedFuncs[idx];
30
-
28
+ const func = importedFuncs[x[1]];
31
29
  if (!remap.has(func)) {
32
30
  remap.set(func, importFuncs.length);
33
31
  importFuncs.push(func);
34
32
  }
35
- x[1] = remap.get(func);
33
+ f.wasm[j] = [ x[0], remap.get(func) ];
36
34
  }
37
35
  }
38
36
  }
@@ -22,7 +22,7 @@ export const __ByteString_prototype_${a0} = (_this: bytestring) =>
22
22
  export const __String_prototype_${name} = (_this: string, arg: any) => {
23
23
  arg = ecma262.ToString(arg);
24
24
  const len: i32 = arg.length;
25
- const escaped: bytestring = Porffor.malloc(4 + len * 6); // overallocate in case of &quot;s
25
+ const escaped: bytestring = Porffor.malloc(6 + len * 6); // overallocate in case of &quot;s
26
26
  for (let i: i32 = 0; i < len; i++) {
27
27
  const c: i32 = arg.charCodeAt(i);
28
28
  if (c != 34) {
@@ -371,6 +371,8 @@ export const __Array_prototype_fill = (_this: any[], value: any, _start: any, _e
371
371
  // @porf-typed-array
372
372
  export const __Array_prototype_indexOf = (_this: any[], searchElement: any, _position: any) => {
373
373
  const len: i32 = _this.length;
374
+ if (len == 0) return -1;
375
+
374
376
  let position: i32 = ecma262.ToIntegerOrInfinity(_position);
375
377
  if (position >= 0) {
376
378
  if (position > len) position = len;
@@ -389,6 +391,8 @@ export const __Array_prototype_indexOf = (_this: any[], searchElement: any, _pos
389
391
  // @porf-typed-array
390
392
  export const __Array_prototype_lastIndexOf = (_this: any[], searchElement: any, _position: any) => {
391
393
  const len: i32 = _this.length;
394
+ if (len == 0) return -1;
395
+
392
396
  let position: i32 = _position == null ? len - 1 : ecma262.ToIntegerOrInfinity(_position);
393
397
  if (position >= 0) {
394
398
  if (position > len - 1) position = len - 1;
@@ -406,6 +410,8 @@ export const __Array_prototype_lastIndexOf = (_this: any[], searchElement: any,
406
410
  // @porf-typed-array
407
411
  export const __Array_prototype_includes = (_this: any[], searchElement: any, _position: any) => {
408
412
  const len: i32 = _this.length;
413
+ if (len == 0) return false;
414
+
409
415
  let position: i32 = ecma262.ToIntegerOrInfinity(_position);
410
416
  if (position >= 0) {
411
417
  if (position > len) position = len;
@@ -415,7 +421,7 @@ export const __Array_prototype_includes = (_this: any[], searchElement: any, _po
415
421
  }
416
422
 
417
423
  for (let i: i32 = position; i < len; i++) {
418
- if (_this[i] === searchElement) return true;
424
+ if (__ecma262_SameValueZero(_this[i], searchElement)) return true;
419
425
  }
420
426
 
421
427
  return false;
@@ -612,6 +618,7 @@ export const __Array_prototype_findIndex = (_this: any[], callbackFn: any, thisA
612
618
  if (!!callbackFn.call(thisArg, _this[i], i, _this)) return i;
613
619
  i++;
614
620
  }
621
+ return -1;
615
622
  };
616
623
 
617
624
  // @porf-typed-array
@@ -621,6 +628,7 @@ export const __Array_prototype_findLastIndex = (_this: any[], callbackFn: any, t
621
628
  while (i > 0) {
622
629
  if (!!callbackFn.call(thisArg, _this[--i], i, _this)) return i;
623
630
  }
631
+ return -1;
624
632
  };
625
633
 
626
634
  // @porf-typed-array
@@ -59,6 +59,7 @@ export const __Porffor_print = (arg: any, colors: boolean = true, depth: number
59
59
  return;
60
60
 
61
61
  case Porffor.TYPES.boolean:
62
+ case Porffor.TYPES.booleanobject:
62
63
  if (colors) Porffor.printStatic('\x1b[33m'); // yellow
63
64
  if (arg) {
64
65
  Porffor.printStatic('true');
@@ -21,8 +21,7 @@ export const __Function_prototype_toString = (_this: Function) => {
21
21
  export const __Function_prototype_toLocaleString = (_this: Function) => __Function_prototype_toString(_this);
22
22
 
23
23
  export const __Function_prototype_apply = (_this: Function, thisArg: any, argsArray: any) => {
24
- argsArray = Array.from(argsArray ?? []);
25
- return Porffor.call(_this, argsArray, thisArg, null);
24
+ return Porffor.call(_this, Array.from(argsArray ?? []) as any[], thisArg, null);
26
25
  };
27
26
 
28
27
  export const __Function_prototype_bind = (_this: Function, thisArg: any, argsArray: any) => {
@@ -39,6 +39,7 @@ export const __Porffor_json_canSerialize = (value: any): boolean => {
39
39
  Porffor.type(value) == Porffor.TYPES.stringobject,
40
40
  Porffor.type(value) == Porffor.TYPES.number,
41
41
  Porffor.type(value) == Porffor.TYPES.numberobject,
42
+ Porffor.type(value) == Porffor.TYPES.booleanobject,
42
43
  Porffor.type(value) == Porffor.TYPES.array,
43
44
  Porffor.type(value) > Porffor.TYPES.function
44
45
  )) return true;
@@ -57,6 +58,12 @@ export const __Porffor_json_serialize = (_buffer: i32, value: any, depth: i32, s
57
58
  if (value === true) return __Porffor_bytestring_bufferStr(buffer, 'true');
58
59
  if (value === false) return __Porffor_bytestring_bufferStr(buffer, 'false');
59
60
 
61
+ // Handle Boolean objects by extracting [[BooleanData]]
62
+ if (Porffor.type(value) == Porffor.TYPES.booleanobject) {
63
+ if (value.valueOf()) return __Porffor_bytestring_bufferStr(buffer, 'true');
64
+ return __Porffor_bytestring_bufferStr(buffer, 'false');
65
+ }
66
+
60
67
  if (Porffor.fastOr(
61
68
  (Porffor.type(value) | 0b10000000) == Porffor.TYPES.bytestring,
62
69
  Porffor.type(value) == Porffor.TYPES.stringobject
@@ -240,7 +247,7 @@ export const __JSON_stringify = (value: any, replacer: any, space: any) => {
240
247
  if (space < 1) {
241
248
  space = undefined;
242
249
  } else {
243
- const spaceStr: bytestring = Porffor.malloc(4 + space);
250
+ const spaceStr: bytestring = Porffor.malloc(6 + space);
244
251
  for (let i: i32 = 0; i < space; i++) Porffor.bytestring.appendChar(spaceStr, 32);
245
252
 
246
253
  space = spaceStr;
@@ -72,7 +72,9 @@ export const __Map_prototype_clear = (_this: Map) => {
72
72
  vals.length = 0;
73
73
  };
74
74
 
75
- export const __Map_prototype_forEach = (_this: Map, callbackFn: any) => {
75
+ export const __Map_prototype_forEach = (_this: Map, callbackFn: any, thisArg: any = undefined) => {
76
+ if (Porffor.type(callbackFn) != Porffor.TYPES.function) throw new TypeError('callbackFn is not a function');
77
+
76
78
  const keys: any[] = Porffor.wasm.i32.load(_this, 0, 0);
77
79
  const vals: any[] = Porffor.wasm.i32.load(_this, 0, 4);
78
80
 
@@ -80,7 +82,7 @@ export const __Map_prototype_forEach = (_this: Map, callbackFn: any) => {
80
82
 
81
83
  let i: i32 = 0;
82
84
  while (i < size) {
83
- callbackFn(vals[i], keys[i++], _this);
85
+ callbackFn.call(thisArg, vals[i], keys[i++], _this);
84
86
  }
85
87
  };
86
88
 
@@ -154,7 +154,7 @@ export const __Math_pow = (base: number, exponent: number): number => {
154
154
  }
155
155
 
156
156
  // 5. If base is -∞𝔽, then
157
- const isOdd = exponent % 2 == 1;
157
+ const isOdd = Math.abs(exponent) % 2 == 1;
158
158
 
159
159
  // a. If exponent > +0𝔽, then
160
160
  if (exponent > 0) {
@@ -178,7 +178,7 @@ export const __Math_pow = (base: number, exponent: number): number => {
178
178
  }
179
179
 
180
180
  // 7. If base is -0𝔽, then
181
- const isOdd = exponent % 2 == 1;
181
+ const isOdd = Math.abs(exponent) % 2 == 1;
182
182
 
183
183
  // a. If exponent > +0𝔽, then
184
184
  if (exponent > 0) {
@@ -246,7 +246,7 @@ export const __Math_pow = (base: number, exponent: number): number => {
246
246
  }
247
247
 
248
248
  currentBase *= currentBase;
249
- currentExponent >>= 1;
249
+ currentExponent = Math.trunc(currentExponent / 2);
250
250
  } else {
251
251
  // Handle fractional part
252
252
  result *= Math.exp(currentExponent * Math.log(Math.abs(currentBase)));
@@ -282,7 +282,10 @@ export const __Math_expm1 = (x: number): number => {
282
282
  };
283
283
 
284
284
  export const __Math_log1p = (x: number): number => {
285
+ // log1p(0) = 0 (preserve sign)
286
+ if (x == 0) return x;
285
287
  if (x == -1) return -Infinity; // log(0) = -inf
288
+ if (x < -1) return NaN; // log of negative is NaN
286
289
  if (!Number.isFinite(x)) return x;
287
290
 
288
291
  // opt: use exp(x) - 1 for large x
@@ -305,7 +308,7 @@ export const __Math_log1p = (x: number): number => {
305
308
 
306
309
  export const __Math_sqrt = (y: number): number => {
307
310
  if (y <= 0) {
308
- if (y == 0) return 0;
311
+ if (y == 0) return y; // sqrt(0) = 0 (preserve sign)
309
312
  return NaN;
310
313
  }
311
314
  if (!Number.isFinite(y)) return y;
@@ -323,7 +326,7 @@ export const __Math_sqrt = (y: number): number => {
323
326
  };
324
327
 
325
328
  export const __Math_cbrt = (y: number): number => {
326
- if (y == 0) return 0; // cbrt(0) = 0
329
+ if (y == 0) return y; // cbrt(0) = 0 (preserves sign)
327
330
  if (!Number.isFinite(y)) return y;
328
331
 
329
332
  // Babylonian method
@@ -341,9 +344,16 @@ export const __Math_cbrt = (y: number): number => {
341
344
 
342
345
 
343
346
  // todo: varargs
344
- export const __Math_hypot = (x: number, y: number): number => Math.sqrt(x * x + y * y);
347
+ export const __Math_hypot = (x: number, y: number): number => {
348
+ // If any argument is ±Infinity, return +Infinity (even if other args are NaN)
349
+ if (x == Infinity || x == -Infinity || y == Infinity || y == -Infinity) return Infinity;
350
+ return Math.sqrt(x * x + y * y);
351
+ };
345
352
 
346
353
  export const __Math_sin = (x: number): number => {
354
+ // sin(0) = 0 (preserve sign)
355
+ if (x == 0) return x;
356
+
347
357
  // -inf <= x <= inf -> 0 <= x <= 2pi
348
358
  const piX2: number = Math.PI * 2;
349
359
  x %= piX2;
@@ -381,21 +391,47 @@ export const __Math_sin = (x: number): number => {
381
391
  // );
382
392
  };
383
393
 
384
- export const __Math_cos = (x: number): number => Math.sin(x - Math.PI / 2);
385
- export const __Math_tan = (x: number): number => Math.sin(x) / Math.cos(x);
394
+ export const __Math_cos = (x: number): number => {
395
+ if (x == 0) return 1;
396
+ return Math.sin(x + Math.PI / 2);
397
+ };
398
+ export const __Math_tan = (x: number): number => {
399
+ // tan(0) = 0 (preserve sign)
400
+ if (x == 0) return x;
401
+ return Math.sin(x) / Math.cos(x);
402
+ };
386
403
 
387
- export const __Math_sinh = (x: number): number => (Math.exp(x) - Math.exp(-x)) / 2;
404
+ export const __Math_sinh = (x: number): number => {
405
+ // sinh(0) = 0 (preserve sign)
406
+ if (x == 0) return x;
407
+ return (Math.exp(x) - Math.exp(-x)) / 2;
408
+ };
388
409
  export const __Math_cosh = (x: number): number => (Math.exp(x) + Math.exp(-x)) / 2;
389
- export const __Math_tanh = (x: number): number => Math.sinh(x) / Math.cosh(x);
410
+ export const __Math_tanh = (x: number): number => {
411
+ // tanh(0) = 0 (preserve sign)
412
+ if (x == 0) return x;
413
+ if (x == Infinity) return 1;
414
+ if (x == -Infinity) return -1;
415
+ return Math.sinh(x) / Math.cosh(x);
416
+ };
390
417
 
391
418
 
392
- export const __Math_asinh = (x: number): number => Math.log(x + Math.sqrt(x * x + 1));
419
+ export const __Math_asinh = (x: number): number => {
420
+ // asinh(0) = 0 (preserve sign)
421
+ if (x == 0) return x;
422
+ if (!Number.isFinite(x)) return x;
423
+ return Math.log(x + Math.sqrt(x * x + 1));
424
+ };
393
425
  export const __Math_acosh = (x: number): number => {
394
426
  if (x < 1) return NaN;
395
427
  return Math.log(x + Math.sqrt(x * x - 1));
396
428
  };
397
429
  export const __Math_atanh = (x: number): number => {
398
- if (Math.abs(x) >= 1) return NaN;
430
+ // atanh(0) = 0 (preserve sign)
431
+ if (x == 0) return x;
432
+ if (x == 1) return Infinity;
433
+ if (x == -1) return -Infinity;
434
+ if (Math.abs(x) > 1) return NaN;
399
435
  return 0.5 * Math.log((1 + x) / (1 - x));
400
436
  };
401
437
 
@@ -424,7 +460,7 @@ export const __Math_asin = (x: number): number => {
424
460
  return sum;
425
461
  };
426
462
 
427
- export const __Math_acos = (x: number): number => Math.asin(x) - Math.PI / 2;
463
+ export const __Math_acos = (x: number): number => Math.PI / 2 - Math.asin(x);
428
464
 
429
465
  export const __Math_atan = (x: number): number => {
430
466
  if (x == Infinity) return Math.PI / 2;
@@ -40,7 +40,7 @@ export const __Number_prototype_toString = (_this: number, radix: number|any) =>
40
40
  radix = 10;
41
41
  }
42
42
 
43
- radix |= 0;
43
+ radix = Math.trunc(radix);
44
44
  if (radix < 2 || radix > 36) {
45
45
  throw new RangeError('toString() radix argument must be between 2 and 36');
46
46
  }
@@ -268,7 +268,7 @@ export const __Number_prototype_toString = (_this: number, radix: number|any) =>
268
268
  };
269
269
 
270
270
  export const __Number_prototype_toFixed = (_this: number, fractionDigits: number) => {
271
- fractionDigits |= 0;
271
+ fractionDigits = Math.trunc(fractionDigits);
272
272
  if (fractionDigits < 0 || fractionDigits > 100) {
273
273
  throw new RangeError('toFixed() fractionDigits argument must be between 0 and 100');
274
274
  }
@@ -367,7 +367,7 @@ export const __Number_prototype_toExponential = (_this: number, fractionDigits:
367
367
  // todo: string to number
368
368
  fractionDigits = undefined;
369
369
  } else {
370
- fractionDigits |= 0;
370
+ fractionDigits = Math.trunc(fractionDigits);
371
371
  if (fractionDigits < 0 || fractionDigits > 100) {
372
372
  throw new RangeError('toExponential() fractionDigits argument must be between 0 and 100');
373
373
  }
@@ -695,6 +695,10 @@ export const parseFloat = (input: any): f64 => {
695
695
  let negative: boolean = false;
696
696
 
697
697
  let i: i32 = 0;
698
+ const len: i32 = input.length;
699
+
700
+ if (len == 0) return NaN;
701
+
698
702
  const start: i32 = input.charCodeAt(0);
699
703
 
700
704
  // +, ignore
@@ -708,7 +712,22 @@ export const parseFloat = (input: any): f64 => {
708
712
  negative = true;
709
713
  }
710
714
 
711
- const len: i32 = input.length;
715
+ // Check for "Infinity"
716
+ if (len - i >= 8) {
717
+ // Check if remaining string starts with "Infinity"
718
+ if (input.charCodeAt(i) == 73 && // I
719
+ input.charCodeAt(i + 1) == 110 && // n
720
+ input.charCodeAt(i + 2) == 102 && // f
721
+ input.charCodeAt(i + 3) == 105 && // i
722
+ input.charCodeAt(i + 4) == 110 && // n
723
+ input.charCodeAt(i + 5) == 105 && // i
724
+ input.charCodeAt(i + 6) == 116 && // t
725
+ input.charCodeAt(i + 7) == 121) { // y
726
+ if (negative) return -Infinity;
727
+ return Infinity;
728
+ }
729
+ }
730
+
712
731
  while (i < len) {
713
732
  const chr: i32 = input.charCodeAt(i++);
714
733
 
@@ -643,7 +643,11 @@ export const __Object_setPrototypeOf = (obj: any, proto: any): any => {
643
643
  if (obj == null) throw new TypeError('Object is nullish, expected object');
644
644
  if (!Porffor.object.isObjectOrNull(proto)) throw new TypeError('Prototype should be an object or null');
645
645
 
646
- // todo: if inextensible, throw if proto != current prototype
646
+ // If object is inextensible, throw if new proto is different from current
647
+ if (Porffor.object.isObject(obj) && Porffor.object.isInextensible(obj)) {
648
+ const currentProto: any = Porffor.object.getPrototypeWithHidden(obj, Porffor.type(obj));
649
+ if (proto !== currentProto) throw new TypeError('Cannot set prototype of non-extensible object');
650
+ }
647
651
 
648
652
  Porffor.object.setPrototype(obj, proto);
649
653
  return obj;
@@ -96,6 +96,7 @@ type PorfforGlobal = {
96
96
  }
97
97
 
98
98
  print(x: any): i32;
99
+ printStatic(str: string): void;
99
100
 
100
101
  randomByte(): i32;
101
102
 
@@ -127,10 +128,6 @@ type PorfforGlobal = {
127
128
 
128
129
  s(...args: any): string;
129
130
  bs(...args: any): bytestring;
130
-
131
- printStatic(str: string): void;
132
- readArgv(index: i32, out: bytestring): i32;
133
- readFile(path: bytestring, out: bytestring): i32;
134
131
  };
135
132
 
136
133
  declare global {