porffor 0.39.1 → 0.39.2
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/__internal_object.ts +1 -1
- package/compiler/builtins/array.ts +37 -3
- package/compiler/builtins/error.js +3 -1
- package/compiler/builtins/reflect.ts +1 -19
- package/compiler/builtins/string.ts +1 -1
- package/compiler/builtins_precompiled.js +144 -84
- package/compiler/codegen.js +71 -40
- package/compiler/precompile.js +1 -1
- package/compiler/prototype.js +1 -1
- package/compiler/types.js +2 -0
- package/compiler/wrap.js +4 -2
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -335,7 +335,7 @@ const internalThrow = (scope, constructor, message, expectsValue = Prefs.alwaysV
|
|
335
335
|
];
|
336
336
|
|
337
337
|
const generateIdent = (scope, decl) => {
|
338
|
-
const lookup = rawName => {
|
338
|
+
const lookup = (rawName, failEarly = false) => {
|
339
339
|
const name = mapName(rawName);
|
340
340
|
let local = scope.locals[rawName];
|
341
341
|
|
@@ -376,11 +376,18 @@ const generateIdent = (scope, decl) => {
|
|
376
376
|
let parent = rawName.slice(2).split('_').slice(0, -1).join('_');
|
377
377
|
if (parent.includes('_')) parent = '__' + parent;
|
378
378
|
|
379
|
-
const parentLookup = lookup(parent);
|
379
|
+
const parentLookup = lookup(parent, true);
|
380
380
|
if (!parentLookup[1]) return number(UNDEFINED);
|
381
381
|
}
|
382
382
|
|
383
|
-
if (local?.idx === undefined)
|
383
|
+
if (local?.idx === undefined) {
|
384
|
+
if (failEarly) return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
385
|
+
|
386
|
+
return [ [ null, () => {
|
387
|
+
// try generating again at the end
|
388
|
+
return lookup(rawName, true);
|
389
|
+
}, 1 ] ];
|
390
|
+
}
|
384
391
|
|
385
392
|
return [
|
386
393
|
[ Opcodes.local_get, local.idx ],
|
@@ -889,12 +896,17 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
889
896
|
// try hacky version for built-ins first
|
890
897
|
const rightName = decl.right.name;
|
891
898
|
if (rightName) {
|
892
|
-
|
899
|
+
let checkType = TYPES[rightName.toLowerCase()];
|
893
900
|
if (checkType != null && rightName === TYPE_NAMES[checkType] && !rightName.endsWith('Error')) {
|
894
901
|
const out = generate(scope, decl.left);
|
895
902
|
disposeLeftover(out);
|
896
903
|
|
897
|
-
|
904
|
+
// switch primitive types to primitive object types
|
905
|
+
if (checkType === TYPES.number) checkType = TYPES.numberobject;
|
906
|
+
if (checkType === TYPES.boolean) checkType = TYPES.booleanobject;
|
907
|
+
|
908
|
+
// currently unsupported types
|
909
|
+
if ([TYPES.string].includes(checkType)) {
|
898
910
|
out.push(...number(0));
|
899
911
|
} else {
|
900
912
|
out.push(
|
@@ -1032,7 +1044,7 @@ const asmFuncToAsm = (scope, func) => {
|
|
1032
1044
|
return [ [ null, () => {
|
1033
1045
|
if (types.some(x => usedTypes.has(x))) return wasm();
|
1034
1046
|
return [];
|
1035
|
-
} ] ];
|
1047
|
+
}, 0 ] ];
|
1036
1048
|
}
|
1037
1049
|
}
|
1038
1050
|
});
|
@@ -1160,7 +1172,11 @@ const isExistingProtoFunc = name => {
|
|
1160
1172
|
return false;
|
1161
1173
|
};
|
1162
1174
|
|
1163
|
-
const getType = (scope, _name) => {
|
1175
|
+
const getType = (scope, _name, failEarly = false) => {
|
1176
|
+
const fallback = failEarly ? number(TYPES.undefined, Valtype.i32) : [ [ null, () => {
|
1177
|
+
return getType(scope, _name, true);
|
1178
|
+
}, 1 ] ];
|
1179
|
+
|
1164
1180
|
const name = mapName(_name);
|
1165
1181
|
|
1166
1182
|
if (Object.hasOwn(builtinVars, name)) return number(builtinVars[name].type ?? TYPES.number, Valtype.i32);
|
@@ -1172,7 +1188,7 @@ const getType = (scope, _name) => {
|
|
1172
1188
|
if (typeLocal) return [ [ Opcodes.local_get, typeLocal.idx ] ];
|
1173
1189
|
|
1174
1190
|
// todo: warn here?
|
1175
|
-
return
|
1191
|
+
return fallback;
|
1176
1192
|
}
|
1177
1193
|
|
1178
1194
|
if (name === 'arguments' && scope.name !== 'main' && !scope.arrow) {
|
@@ -1186,7 +1202,7 @@ const getType = (scope, _name) => {
|
|
1186
1202
|
if (typeLocal) return [ [ Opcodes.global_get, typeLocal.idx ] ];
|
1187
1203
|
|
1188
1204
|
// todo: warn here?
|
1189
|
-
return
|
1205
|
+
return fallback;
|
1190
1206
|
}
|
1191
1207
|
|
1192
1208
|
if (Object.hasOwn(builtinFuncs, name) || Object.hasOwn(importedFuncs, name) ||
|
@@ -1195,7 +1211,7 @@ const getType = (scope, _name) => {
|
|
1195
1211
|
|
1196
1212
|
if (isExistingProtoFunc(name)) return number(TYPES.function, Valtype.i32);
|
1197
1213
|
|
1198
|
-
return
|
1214
|
+
return fallback;
|
1199
1215
|
};
|
1200
1216
|
|
1201
1217
|
const setType = (scope, _name, type) => {
|
@@ -1507,7 +1523,10 @@ const countLeftover = wasm => {
|
|
1507
1523
|
|
1508
1524
|
for (let i = 0; i < wasm.length; i++) {
|
1509
1525
|
const inst = wasm[i];
|
1510
|
-
if (inst[0] == null)
|
1526
|
+
if (depth === 0 && inst[0] == null) {
|
1527
|
+
if (typeof inst[1] === 'function' && typeof inst[2] === 'number') count += inst[2];
|
1528
|
+
continue;
|
1529
|
+
}
|
1511
1530
|
|
1512
1531
|
if (depth === 0 && (inst[0] === Opcodes.if || inst[0] === Opcodes.block || inst[0] === Opcodes.loop)) {
|
1513
1532
|
if (inst[0] === Opcodes.if) count--;
|
@@ -1538,7 +1557,7 @@ const countLeftover = wasm => {
|
|
1538
1557
|
count += 2; // fixed return (value, type)
|
1539
1558
|
} else count--;
|
1540
1559
|
|
1541
|
-
// console.log(count, decompile([ inst ]).slice(0, -1));
|
1560
|
+
// console.log(count, depth, decompile([ inst ]).slice(0, -1));
|
1542
1561
|
}
|
1543
1562
|
|
1544
1563
|
return count;
|
@@ -2861,7 +2880,7 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary, fallthrough = fals
|
|
2861
2880
|
out = [];
|
2862
2881
|
if (types.some(x => usedTypes.has(x))) add();
|
2863
2882
|
return out;
|
2864
|
-
}]);
|
2883
|
+
}, 0 ]);
|
2865
2884
|
}
|
2866
2885
|
}
|
2867
2886
|
}
|
@@ -4542,16 +4561,7 @@ const generateForIn = (scope, decl) => {
|
|
4542
4561
|
};
|
4543
4562
|
|
4544
4563
|
const generateSwitch = (scope, decl) => {
|
4545
|
-
|
4546
|
-
const out = [
|
4547
|
-
...generate(scope, decl.discriminant),
|
4548
|
-
[ Opcodes.local_set, tmp ],
|
4549
|
-
|
4550
|
-
[ Opcodes.block, Blocktype.void ]
|
4551
|
-
];
|
4552
|
-
|
4553
|
-
depth.push('switch');
|
4554
|
-
|
4564
|
+
// special fast path just for `switch (Porffor.rawType(...))`
|
4555
4565
|
if (decl.discriminant.type === 'CallExpression' && decl.discriminant.callee.type === 'Identifier' && decl.discriminant.callee.name === '__Porffor_rawType') {
|
4556
4566
|
const cases = []
|
4557
4567
|
let canTypeCheck = true;
|
@@ -4574,28 +4584,42 @@ const generateSwitch = (scope, decl) => {
|
|
4574
4584
|
}
|
4575
4585
|
|
4576
4586
|
if (canTypeCheck) {
|
4577
|
-
|
4578
|
-
|
4579
|
-
|
4580
|
-
|
4581
|
-
|
4582
|
-
|
4583
|
-
|
4584
|
-
|
4585
|
-
|
4586
|
-
|
4587
|
-
|
4588
|
-
}
|
4587
|
+
depth.push('switch');
|
4588
|
+
|
4589
|
+
const out = typeSwitch(scope, getNodeType(scope, decl.discriminant.arguments[0]), () => {
|
4590
|
+
const bc = [];
|
4591
|
+
let types = [];
|
4592
|
+
for (const [ type, consequent ] of cases) {
|
4593
|
+
types.push(type);
|
4594
|
+
|
4595
|
+
if (consequent.length !== 0) {
|
4596
|
+
bc.push([ types, () => generate(scope, { type: 'BlockStatement', body: consequent }) ]);
|
4597
|
+
types = [];
|
4589
4598
|
}
|
4599
|
+
}
|
4590
4600
|
|
4591
|
-
|
4592
|
-
|
4601
|
+
return bc;
|
4602
|
+
}, Blocktype.void, true);
|
4593
4603
|
|
4594
4604
|
depth.pop();
|
4595
4605
|
return out;
|
4596
4606
|
}
|
4597
4607
|
}
|
4598
4608
|
|
4609
|
+
const tmpName = '#switch' + uniqId();
|
4610
|
+
const tmp = localTmp(scope, tmpName);
|
4611
|
+
localTmp(scope, tmpName + '#type', Valtype.i32);
|
4612
|
+
|
4613
|
+
const out = [
|
4614
|
+
...generate(scope, decl.discriminant),
|
4615
|
+
[ Opcodes.local_set, tmp ],
|
4616
|
+
...setType(scope, tmpName, getNodeType(scope, decl.discriminant)),
|
4617
|
+
|
4618
|
+
[ Opcodes.block, Blocktype.void ]
|
4619
|
+
];
|
4620
|
+
|
4621
|
+
depth.push('switch');
|
4622
|
+
|
4599
4623
|
const cases = decl.cases.slice();
|
4600
4624
|
const defaultCase = cases.findIndex(x => x.test == null);
|
4601
4625
|
if (defaultCase != -1) {
|
@@ -4613,9 +4637,16 @@ const generateSwitch = (scope, decl) => {
|
|
4613
4637
|
if (x.test) {
|
4614
4638
|
// todo: this should use same value zero
|
4615
4639
|
out.push(
|
4616
|
-
|
4617
|
-
|
4618
|
-
|
4640
|
+
...generate(scope, {
|
4641
|
+
type: 'BinaryExpression',
|
4642
|
+
operator: '===',
|
4643
|
+
left: {
|
4644
|
+
type: 'Identifier',
|
4645
|
+
name: tmpName
|
4646
|
+
},
|
4647
|
+
right: x.test
|
4648
|
+
}),
|
4649
|
+
Opcodes.i32_to_u,
|
4619
4650
|
[ Opcodes.br_if, i ]
|
4620
4651
|
);
|
4621
4652
|
} else {
|
package/compiler/precompile.js
CHANGED
@@ -25,7 +25,7 @@ const compile = async (file, _funcs) => {
|
|
25
25
|
first = source.slice(0, source.indexOf('\n'));
|
26
26
|
}
|
27
27
|
|
28
|
-
let args = ['--module', '--todo-time=compile', '--truthy=no_nan_negative', '--no-rm-unused-types', '--scoped-page-names', '--funsafe-no-unlikely-proto-checks', '--fast-length', '--parse-types', '--opt-types', '--no-passive-data', '--active-data', '--exception-mode=lut'];
|
28
|
+
let args = ['--module', '--todo-time=compile', '--truthy=no_nan_negative', '--no-rm-unused-types', '--scoped-page-names', '--funsafe-no-unlikely-proto-checks', '--zero-checks=charCodeAt', '--fast-length', '--parse-types', '--opt-types', '--no-passive-data', '--active-data', '--exception-mode=lut'];
|
29
29
|
if (first.startsWith('// @porf')) {
|
30
30
|
args = first.slice('// @porf '.length).split(' ').concat(args);
|
31
31
|
}
|
package/compiler/prototype.js
CHANGED
@@ -10,7 +10,7 @@ export const PrototypeFuncs = function() {
|
|
10
10
|
const noUnlikelyChecks = Prefs.funsafeNoUnlikelyProtoChecks;
|
11
11
|
|
12
12
|
let zeroChecks;
|
13
|
-
if (Prefs.zeroChecks) zeroChecks = Prefs.zeroChecks.split('
|
13
|
+
if (Prefs.zeroChecks) zeroChecks = Prefs.zeroChecks.split(',').reduce((acc, x) => { acc[x.toLowerCase()] = true; return acc; }, {});
|
14
14
|
else zeroChecks = {};
|
15
15
|
|
16
16
|
this[TYPES.array] = {
|
package/compiler/types.js
CHANGED
@@ -85,6 +85,8 @@ registerInternalType('SyntaxError');
|
|
85
85
|
registerInternalType('RangeError');
|
86
86
|
registerInternalType('EvalError');
|
87
87
|
registerInternalType('URIError');
|
88
|
+
registerInternalType('Test262Error');
|
89
|
+
registerInternalType('__Porffor_TodoError');
|
88
90
|
|
89
91
|
if (Prefs.largestTypes) {
|
90
92
|
const typeKeys = Object.keys(TYPES);
|
package/compiler/wrap.js
CHANGED
@@ -312,9 +312,11 @@ ${flags & 0b0001 ? ` get func idx: ${get}
|
|
312
312
|
case TYPES.syntaxerror:
|
313
313
|
case TYPES.rangeerror:
|
314
314
|
case TYPES.evalerror:
|
315
|
-
case TYPES.urierror:
|
315
|
+
case TYPES.urierror:
|
316
|
+
case TYPES.test262error:
|
317
|
+
case TYPES.__porffor_todoerror: {
|
316
318
|
const obj = porfToJSValue({ memory, funcs, pages }, value, TYPES.object);
|
317
|
-
const constr = globalThis[TYPE_NAMES[type]];
|
319
|
+
const constr = globalThis[TYPE_NAMES[type]] ?? Error;
|
318
320
|
const err = new constr(obj.message);
|
319
321
|
err.name = obj.name;
|
320
322
|
err.stack = `${TYPE_NAMES[type]}: ${obj.message}`;
|
package/package.json
CHANGED