porffor 0.37.24 → 0.37.25
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/builtins/boolean.ts +10 -4
- package/compiler/builtins/number.ts +3 -3
- package/compiler/builtins/object.ts +10 -3
- package/compiler/builtins/porffor.d.ts +6 -0
- package/compiler/builtins_precompiled.js +95 -93
- package/compiler/codegen.js +102 -41
- package/compiler/types.js +3 -0
- package/compiler/wrap.js +5 -0
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -357,6 +357,13 @@ const generateIdent = (scope, decl) => {
|
|
357
357
|
}
|
358
358
|
|
359
359
|
if (local?.idx === undefined) {
|
360
|
+
if (name === 'arguments' && scope.name !== 'main' && !scope.arrow) {
|
361
|
+
// todo: stub arguments as [] for now :)
|
362
|
+
return generateArray(scope, {
|
363
|
+
elements: []
|
364
|
+
}, false, '#arguments');
|
365
|
+
}
|
366
|
+
|
360
367
|
// no local var with name
|
361
368
|
if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
|
362
369
|
|
@@ -559,7 +566,8 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
|
|
559
566
|
const useTmp = knownType(scope, type) == null;
|
560
567
|
const tmp = useTmp && localTmp(scope, `#logicinner_tmp${intIn ? '_int' : ''}`, intIn ? Valtype.i32 : valtypeBinary);
|
561
568
|
|
562
|
-
const
|
569
|
+
const truthyMode = forceTruthyMode ?? Prefs.truthy ?? 'full';
|
570
|
+
const def = (() => {
|
563
571
|
if (truthyMode === 'full') return [
|
564
572
|
// if value != 0 or NaN
|
565
573
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
@@ -584,7 +592,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
|
|
584
592
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
585
593
|
...(!intOut || (intIn && intOut) ? [] : [ Opcodes.i32_to_u ])
|
586
594
|
];
|
587
|
-
})(
|
595
|
+
})();
|
588
596
|
|
589
597
|
return [
|
590
598
|
...wasm,
|
@@ -603,6 +611,17 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
|
|
603
611
|
[ Opcodes.i32_eqz ], */
|
604
612
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
605
613
|
] ],
|
614
|
+
// [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
|
615
|
+
// [ 'default', [
|
616
|
+
// // other types are always truthy
|
617
|
+
// ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
618
|
+
// ...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
619
|
+
// ] ]
|
620
|
+
...(truthyMode === 'full' ? [ [ [ TYPES.booleanobject, TYPES.numberobject ], [
|
621
|
+
// always truthy :))
|
622
|
+
...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
623
|
+
...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
624
|
+
] ] ] : []),
|
606
625
|
[ 'default', def ]
|
607
626
|
], intOut ? Valtype.i32 : valtypeBinary)
|
608
627
|
];
|
@@ -612,7 +631,8 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode
|
|
612
631
|
const useTmp = knownType(scope, type) == null;
|
613
632
|
const tmp = useTmp && localTmp(scope, `#logicinner_tmp${intIn ? '_int' : ''}`, intIn ? Valtype.i32 : valtypeBinary);
|
614
633
|
|
615
|
-
const
|
634
|
+
const truthyMode = forceTruthyMode ?? Prefs.truthy ?? 'full';
|
635
|
+
const def = (() => {
|
616
636
|
if (truthyMode === 'full') return [
|
617
637
|
// if value == 0 or NaN
|
618
638
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
@@ -638,7 +658,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode
|
|
638
658
|
...(intIn ? [ [ Opcodes.i32_eqz ] ] : [ ...Opcodes.eqz ]),
|
639
659
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
640
660
|
];
|
641
|
-
})(
|
661
|
+
})();
|
642
662
|
|
643
663
|
return [
|
644
664
|
...wasm,
|
@@ -656,6 +676,17 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode
|
|
656
676
|
[ Opcodes.i32_eqz ],
|
657
677
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
658
678
|
] ],
|
679
|
+
// [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
|
680
|
+
// [ 'default', [
|
681
|
+
// // other types are always truthy
|
682
|
+
// ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
683
|
+
// ...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
684
|
+
// ] ]
|
685
|
+
...(truthyMode === 'full' ? [ [ [ TYPES.booleanobject, TYPES.numberobject ], [
|
686
|
+
// always truthy :))
|
687
|
+
...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
688
|
+
...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
689
|
+
] ] ] : []),
|
659
690
|
[ 'default', def ]
|
660
691
|
], intOut ? Valtype.i32 : valtypeBinary)
|
661
692
|
];
|
@@ -1680,6 +1711,20 @@ const setObjProp = (obj, prop, value) => {
|
|
1680
1711
|
});
|
1681
1712
|
};
|
1682
1713
|
|
1714
|
+
const aliasPrimObjsBC = bc => {
|
1715
|
+
const add = (x, y) => {
|
1716
|
+
if (bc[x] == null) return;
|
1717
|
+
|
1718
|
+
// bc[`${x},${y}`] = original;
|
1719
|
+
|
1720
|
+
// intentionally duplicate to avoid extra bc for prim objs as rarely used
|
1721
|
+
bc[y] = bc[x];
|
1722
|
+
};
|
1723
|
+
|
1724
|
+
add(TYPES.boolean, TYPES.booleanobject);
|
1725
|
+
add(TYPES.number, TYPES.numberobject);
|
1726
|
+
};
|
1727
|
+
|
1683
1728
|
const createThisArg = (scope, decl) => {
|
1684
1729
|
const name = mapName(decl.callee?.name);
|
1685
1730
|
if (decl._new) {
|
@@ -2075,6 +2120,9 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2075
2120
|
// fallback to object prototype impl as a basic prototype chain hack
|
2076
2121
|
if (protoBC[TYPES.object]) def = protoBC[TYPES.object];
|
2077
2122
|
|
2123
|
+
// alias primitive prototype with primitive object types
|
2124
|
+
aliasPrimObjsBC(protoBC);
|
2125
|
+
|
2078
2126
|
return [
|
2079
2127
|
...out,
|
2080
2128
|
|
@@ -2718,27 +2766,40 @@ const typeUsed = (scope, x) => {
|
|
2718
2766
|
scope.usedTypes ??= new Set();
|
2719
2767
|
scope.usedTypes.add(x);
|
2720
2768
|
};
|
2769
|
+
|
2721
2770
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary, fallthrough = false) => {
|
2771
|
+
if (typeof bc === 'function') bc = bc();
|
2772
|
+
|
2773
|
+
let def;
|
2774
|
+
if (!Array.isArray(bc)) {
|
2775
|
+
def = bc.default;
|
2776
|
+
bc = Object.entries(bc);
|
2777
|
+
|
2778
|
+
// turn keys back into numbers from keys
|
2779
|
+
for (const x of bc) {
|
2780
|
+
const k = x[0];
|
2781
|
+
if (k === 'default') continue;
|
2782
|
+
|
2783
|
+
// uncomment if needed/used again
|
2784
|
+
// x[0] = k.split(',').map(x => +x);
|
2785
|
+
x[0] = +k;
|
2786
|
+
}
|
2787
|
+
}
|
2788
|
+
|
2722
2789
|
const known = knownType(scope, type);
|
2723
2790
|
if (known != null) {
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
2728
|
-
def = wasm;
|
2729
|
-
continue;
|
2730
|
-
}
|
2731
|
-
|
2732
|
-
if (Array.isArray(type)) {
|
2733
|
-
if (type.includes(known)) return typeof wasm === 'function' ? wasm() : wasm;
|
2734
|
-
} else if (type === known) return typeof wasm === 'function' ? wasm() : wasm;
|
2791
|
+
for (const [ type, wasm ] of bc) {
|
2792
|
+
if (type === 'default') {
|
2793
|
+
def = wasm;
|
2794
|
+
continue;
|
2735
2795
|
}
|
2736
2796
|
|
2737
|
-
|
2738
|
-
|
2739
|
-
|
2740
|
-
return typeof wasm === 'function' ? wasm() : wasm;
|
2797
|
+
if (type === known || (Array.isArray(type) && type.includes(known))) {
|
2798
|
+
return typeof wasm === 'function' ? wasm() : wasm;
|
2799
|
+
}
|
2741
2800
|
}
|
2801
|
+
|
2802
|
+
return typeof def === 'function' ? def() : def;
|
2742
2803
|
}
|
2743
2804
|
|
2744
2805
|
if (Prefs.typeswitchBrtable) {
|
@@ -2753,19 +2814,6 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary, fallthrough = fals
|
|
2753
2814
|
[ Opcodes.block, returns ]
|
2754
2815
|
];
|
2755
2816
|
|
2756
|
-
if (typeof bc === 'function') bc = bc();
|
2757
|
-
|
2758
|
-
let def;
|
2759
|
-
if (!Array.isArray(bc)) {
|
2760
|
-
def = bc.default;
|
2761
|
-
bc = Object.entries(bc);
|
2762
|
-
|
2763
|
-
// turn keys back into numbers from keys
|
2764
|
-
for (const x of bc) {
|
2765
|
-
if (x[0] !== 'default') x[0] = +x[0];
|
2766
|
-
}
|
2767
|
-
}
|
2768
|
-
|
2769
2817
|
for (let i = 0; i < bc.length; i++) {
|
2770
2818
|
let [ types, wasm ] = bc[i];
|
2771
2819
|
if (types === 'default') {
|
@@ -2837,6 +2885,17 @@ const typeIsOneOf = (type, types, valtype = Valtype.i32) => {
|
|
2837
2885
|
return out;
|
2838
2886
|
};
|
2839
2887
|
|
2888
|
+
const typeIsNotOneOf = (type, types, valtype = Valtype.i32) => {
|
2889
|
+
const out = [];
|
2890
|
+
|
2891
|
+
for (let i = 0; i < types.length; i++) {
|
2892
|
+
out.push(...type, ...number(types[i], valtype), valtype === Valtype.f64 ? [ Opcodes.f64_ne ] : [ Opcodes.i32_ne ]);
|
2893
|
+
if (i !== 0) out.push([ Opcodes.i32_and ]);
|
2894
|
+
}
|
2895
|
+
|
2896
|
+
return out;
|
2897
|
+
};
|
2898
|
+
|
2840
2899
|
const allocVar = (scope, name, global = false, type = true) => {
|
2841
2900
|
const target = global ? globals : scope.locals;
|
2842
2901
|
|
@@ -5411,7 +5470,10 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5411
5470
|
if (type === known) return bc[type]();
|
5412
5471
|
}
|
5413
5472
|
|
5414
|
-
if (known == null)
|
5473
|
+
if (known == null) {
|
5474
|
+
aliasPrimObjsBC(bc);
|
5475
|
+
extraBC = bc;
|
5476
|
+
}
|
5415
5477
|
}
|
5416
5478
|
|
5417
5479
|
// todo/perf: use i32 object (and prop?) locals
|
@@ -5892,6 +5954,7 @@ const generateFunc = (scope, decl) => {
|
|
5892
5954
|
const params = decl.params ?? [];
|
5893
5955
|
|
5894
5956
|
// TODO: share scope/locals between !!!
|
5957
|
+
const arrow = decl.type === 'ArrowFunctionExpression' || decl.type === 'Program';
|
5895
5958
|
const func = {
|
5896
5959
|
locals: {},
|
5897
5960
|
localInd: 0,
|
@@ -5899,11 +5962,8 @@ const generateFunc = (scope, decl) => {
|
|
5899
5962
|
returns: [ valtypeBinary, Valtype.i32 ],
|
5900
5963
|
name,
|
5901
5964
|
index: currentFuncIndex++,
|
5902
|
-
|
5903
|
-
|
5904
|
-
(decl.type && decl.type !== 'ArrowFunctionExpression' && decl.type !== 'Program') &&
|
5905
|
-
// not async or generator
|
5906
|
-
!decl.async && !decl.generator,
|
5965
|
+
arrow,
|
5966
|
+
constr: !arrow && !decl.generator && !decl.async,
|
5907
5967
|
_onlyConstr: decl._onlyConstr, _onlyThisMethod: decl._onlyThisMethod,
|
5908
5968
|
strict: scope.strict || decl.strict,
|
5909
5969
|
|
@@ -6097,10 +6157,11 @@ const generateFunc = (scope, decl) => {
|
|
6097
6157
|
TYPES.weakref, TYPES.weakset, TYPES.weakmap,
|
6098
6158
|
TYPES.arraybuffer, TYPES.sharedarraybuffer, TYPES.dataview
|
6099
6159
|
].includes(typeAnno.type)) {
|
6160
|
+
let types = [ typeAnno.type ];
|
6161
|
+
if (typeAnno.type === TYPES.number) types.push(TYPES.numberobject);
|
6162
|
+
|
6100
6163
|
prelude.push(
|
6101
|
-
[ Opcodes.local_get, func.locals[name].idx + 1 ],
|
6102
|
-
...number(typeAnno.type, Valtype.i32),
|
6103
|
-
[ Opcodes.i32_ne ],
|
6164
|
+
...typeIsNotOneOf([ [ Opcodes.local_get, func.locals[name].idx + 1 ] ], types),
|
6104
6165
|
[ Opcodes.if, Blocktype.void ],
|
6105
6166
|
...internalThrow(func, 'TypeError', `${unhackName(func.name)} expects 'this' to be a ${TYPE_NAMES[typeAnno.type]}`),
|
6106
6167
|
[ Opcodes.end ]
|
package/compiler/types.js
CHANGED
@@ -74,6 +74,9 @@ registerInternalType('WeakMap');
|
|
74
74
|
|
75
75
|
registerInternalType('Promise');
|
76
76
|
|
77
|
+
registerInternalType('BooleanObject');
|
78
|
+
registerInternalType('NumberObject');
|
79
|
+
|
77
80
|
if (Prefs.largestTypes) {
|
78
81
|
const typeKeys = Object.keys(TYPES);
|
79
82
|
const typeVals = Object.values(TYPES);
|
package/compiler/wrap.js
CHANGED
@@ -41,7 +41,12 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type, override = undefin
|
|
41
41
|
case TYPES.undefined:
|
42
42
|
return undefined;
|
43
43
|
|
44
|
+
case TYPES.number: return value;
|
45
|
+
case TYPES.numberobject: return new Number(value);
|
46
|
+
|
44
47
|
case TYPES.boolean: return Boolean(value);
|
48
|
+
case TYPES.booleanobject: return new Boolean(value);
|
49
|
+
|
45
50
|
case TYPES.object: {
|
46
51
|
if (value === 0 || checkOOB(memory, value)) return null;
|
47
52
|
|
package/package.json
CHANGED