porffor 0.42.5 → 0.42.7
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/math.ts +1 -1
- package/compiler/builtins_precompiled.js +2 -2
- package/compiler/codegen.js +102 -75
- package/compiler/wrap.js +1 -1
- package/package.json +1 -1
- package/r.js +4 -0
- package/runner/index.js +1 -1
- package/runner/repl.js +8 -1
@@ -1780,9 +1780,9 @@ params:[124,127],typedParams:1,returns:[124,127],typedReturns:1,
|
|
1780
1780
|
locals:[124,124],localNames:["y","y#type","x","prev"],
|
1781
1781
|
}
|
1782
1782
|
this.__Math_cbrt = {
|
1783
|
-
wasm:(_,{builtin})=>[[32,0],[68,0],[97],[4,64],[68,0],[65,1],[15],[11],[32,0],[16,builtin('__Number_isFinite')],[68,0],[97],[4,64],[32,0],[65,1],[15],[11],[32,0],[16,builtin('__Math_abs')],[33,2],[
|
1783
|
+
wasm:(_,{builtin})=>[[32,0],[68,0],[97],[4,64],[68,0],[65,1],[15],[11],[32,0],[16,builtin('__Number_isFinite')],[68,0],[97],[4,64],[32,0],[65,1],[15],[11],[32,0],[16,builtin('__Math_abs')],[33,2],[3,64],[2,64],[32,2],[33,3],[68,2],[32,2],[162],[32,0],[32,2],[32,2],[162],[163],[160],[68,3],[163],[33,2],[32,3],[32,2],[161],[16,builtin('__Math_abs')],[68,1e-15],[100],[13,1],[11],[11],[32,0],[68,0],[99],[4,124],[32,2],[154],[65,1],[33,4],[5],[32,2],[65,1],[33,4],[11],[32,4],[15]],
|
1784
1784
|
params:[124,127],typedParams:1,returns:[124,127],typedReturns:1,
|
1785
|
-
locals:[124,
|
1785
|
+
locals:[124,124,127],localNames:["y","y#type","x","prev","#last_type"],
|
1786
1786
|
}
|
1787
1787
|
this.__Math_hypot = {
|
1788
1788
|
wasm:(_,{builtin})=>[[32,0],[32,0],[162],[32,2],[32,2],[162],[160],[65,1],[16,builtin('__Math_sqrt')],[34,4],[15]],
|
package/compiler/codegen.js
CHANGED
@@ -1340,8 +1340,12 @@ const setType = (scope, name, type) => {
|
|
1340
1340
|
};
|
1341
1341
|
|
1342
1342
|
const getLastType = scope => {
|
1343
|
+
if (!scope.locals['#last_type']) return number(TYPES.number, Valtype.i32);
|
1344
|
+
|
1343
1345
|
scope.gotLastType = true;
|
1344
|
-
return [
|
1346
|
+
return [
|
1347
|
+
[ Opcodes.local_get, localTmp(scope, '#last_type', Valtype.i32) ]
|
1348
|
+
];
|
1345
1349
|
};
|
1346
1350
|
|
1347
1351
|
const setLastType = (scope, type = []) => {
|
@@ -1388,11 +1392,7 @@ const getNodeType = (scope, node) => {
|
|
1388
1392
|
|
1389
1393
|
if (name == null) {
|
1390
1394
|
// iife
|
1391
|
-
|
1392
|
-
|
1393
|
-
// presume
|
1394
|
-
if (Prefs.warnAssumedType) console.warn(`Indirect call assumed to be number`);
|
1395
|
-
return TYPES.number;
|
1395
|
+
return getLastType(scope);
|
1396
1396
|
}
|
1397
1397
|
|
1398
1398
|
const func = funcByName(name);
|
@@ -1426,38 +1426,7 @@ const getNodeType = (scope, node) => {
|
|
1426
1426
|
return TYPES.number;
|
1427
1427
|
}
|
1428
1428
|
|
1429
|
-
|
1430
|
-
|
1431
|
-
// presume
|
1432
|
-
if (Prefs.warnAssumedType) console.warn(`Call to ${name} assumed to be number`);
|
1433
|
-
return TYPES.number;
|
1434
|
-
|
1435
|
-
// let protoFunc;
|
1436
|
-
// // ident.func()
|
1437
|
-
// if (name && name.startsWith('__')) {
|
1438
|
-
// const spl = name.slice(2).split('_');
|
1439
|
-
|
1440
|
-
// const baseName = spl.slice(0, -1).join('_');
|
1441
|
-
// const baseType = getType(scope, baseName);
|
1442
|
-
|
1443
|
-
// const func = spl[spl.length - 1];
|
1444
|
-
// protoFunc = prototypeFuncs[baseType]?.[func];
|
1445
|
-
// }
|
1446
|
-
|
1447
|
-
// // literal.func()
|
1448
|
-
// if (!name && node.callee.type === 'MemberExpression') {
|
1449
|
-
// if (node.callee.object.regex) {
|
1450
|
-
// const funcName = node.callee.property.name;
|
1451
|
-
// return Rhemyn[funcName] ? TYPES.boolean : TYPES.undefined;
|
1452
|
-
// }
|
1453
|
-
|
1454
|
-
// const baseType = getNodeType(scope, node.callee.object);
|
1455
|
-
|
1456
|
-
// const func = node.callee.property.name;
|
1457
|
-
// protoFunc = prototypeFuncs[baseType]?.[func];
|
1458
|
-
// }
|
1459
|
-
|
1460
|
-
// if (protoFunc) return protoFunc.returnType;
|
1429
|
+
return getLastType(scope);
|
1461
1430
|
}
|
1462
1431
|
|
1463
1432
|
if (node.type === 'ExpressionStatement') {
|
@@ -1505,10 +1474,7 @@ const getNodeType = (scope, node) => {
|
|
1505
1474
|
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
|
1506
1475
|
guess = TYPES.bytestring;
|
1507
1476
|
|
1508
|
-
|
1509
|
-
|
1510
|
-
// presume
|
1511
|
-
return TYPES.number;
|
1477
|
+
return getLastType(scope);
|
1512
1478
|
}
|
1513
1479
|
|
1514
1480
|
if (node.type === 'UnaryExpression') {
|
@@ -1542,11 +1508,7 @@ const getNodeType = (scope, node) => {
|
|
1542
1508
|
}
|
1543
1509
|
}
|
1544
1510
|
|
1545
|
-
|
1546
|
-
|
1547
|
-
// presume
|
1548
|
-
if (Prefs.warnAssumedType) console.warn(`Member access to field .${name} assumed to be number`);
|
1549
|
-
return TYPES.number;
|
1511
|
+
return getLastType(scope);
|
1550
1512
|
}
|
1551
1513
|
|
1552
1514
|
if (node.type === 'TemplateLiteral') {
|
@@ -1579,11 +1541,7 @@ const getNodeType = (scope, node) => {
|
|
1579
1541
|
}
|
1580
1542
|
}
|
1581
1543
|
|
1582
|
-
|
1583
|
-
|
1584
|
-
// presume
|
1585
|
-
if (Prefs.warnAssumedType) console.warn(`AST node ${node.type} assumed to be number`);
|
1586
|
-
return TYPES.number;
|
1544
|
+
return getLastType(scope);
|
1587
1545
|
})();
|
1588
1546
|
|
1589
1547
|
const out = typeof ret === 'number' ? number(ret, Valtype.i32) : ret;
|
@@ -2447,6 +2405,31 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2447
2405
|
paramOffset += 4;
|
2448
2406
|
}
|
2449
2407
|
|
2408
|
+
if (args.at(-1)?.type === 'SpreadElement') {
|
2409
|
+
// hack: support spread element if last by doing essentially:
|
2410
|
+
// const foo = (a, b, c, d) => ...
|
2411
|
+
// foo(a, b, ...c) -> _ = c; foo(a, b, _[0], _[1])
|
2412
|
+
const arg = args.at(-1).argument;
|
2413
|
+
out.push(
|
2414
|
+
...generate(scope, arg),
|
2415
|
+
[ Opcodes.local_set, localTmp(scope, '#spread') ],
|
2416
|
+
...getNodeType(scope, arg),
|
2417
|
+
[ Opcodes.local_set, localTmp(scope, '#spread#type', Valtype.i32) ]
|
2418
|
+
);
|
2419
|
+
|
2420
|
+
args.pop();
|
2421
|
+
const leftover = paramCount - args.length;
|
2422
|
+
for (let i = 0; i < leftover; i++) {
|
2423
|
+
args.push({
|
2424
|
+
type: 'MemberExpression',
|
2425
|
+
object: { type: 'Identifier', name: '#spread' },
|
2426
|
+
property: { type: 'Literal', value: i },
|
2427
|
+
computed: true,
|
2428
|
+
optional: false
|
2429
|
+
});
|
2430
|
+
}
|
2431
|
+
}
|
2432
|
+
|
2450
2433
|
if (func && args.length < paramCount) {
|
2451
2434
|
// too little args, push undefineds
|
2452
2435
|
args = args.concat(new Array(paramCount - (func.hasRestArgument ? 1 : 0) - args.length).fill(DEFAULT_VALUE()));
|
@@ -3689,6 +3672,11 @@ const ifIdentifierErrors = (scope, decl) => {
|
|
3689
3672
|
const generateUnary = (scope, decl) => {
|
3690
3673
|
switch (decl.operator) {
|
3691
3674
|
case '+':
|
3675
|
+
// opt: skip ToNumber if already known as number type
|
3676
|
+
generate(scope, decl.argument); // hack: fix last type not being defined for getNodeType before generation
|
3677
|
+
const known = knownType(scope, getNodeType(scope, decl.argument));
|
3678
|
+
if (known === TYPES.number) return generate(scope, decl.argument);
|
3679
|
+
|
3692
3680
|
// 13.5.4 Unary + Operator, 13.5.4.1 Runtime Semantics: Evaluation
|
3693
3681
|
// https://tc39.es/ecma262/#sec-unary-plus-operator-runtime-semantics-evaluation
|
3694
3682
|
// 1. Let expr be ? Evaluation of UnaryExpression.
|
@@ -3705,7 +3693,7 @@ const generateUnary = (scope, decl) => {
|
|
3705
3693
|
});
|
3706
3694
|
|
3707
3695
|
case '-':
|
3708
|
-
// * -1
|
3696
|
+
// +x * -1
|
3709
3697
|
|
3710
3698
|
if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
|
3711
3699
|
// if -n, just return that as a const
|
@@ -3713,7 +3701,12 @@ const generateUnary = (scope, decl) => {
|
|
3713
3701
|
}
|
3714
3702
|
|
3715
3703
|
return [
|
3716
|
-
...generate(scope,
|
3704
|
+
...generate(scope, {
|
3705
|
+
type: 'UnaryExpression',
|
3706
|
+
operator: '+',
|
3707
|
+
prefix: true,
|
3708
|
+
argument: decl.argument
|
3709
|
+
}),
|
3717
3710
|
...(valtype === 'f64' ? [ [ Opcodes.f64_neg ] ] : [ ...number(-1), [ Opcodes.mul ] ])
|
3718
3711
|
];
|
3719
3712
|
|
@@ -3729,7 +3722,12 @@ const generateUnary = (scope, decl) => {
|
|
3729
3722
|
|
3730
3723
|
case '~':
|
3731
3724
|
return [
|
3732
|
-
...generate(scope,
|
3725
|
+
...generate(scope, {
|
3726
|
+
type: 'UnaryExpression',
|
3727
|
+
operator: '+',
|
3728
|
+
prefix: true,
|
3729
|
+
argument: decl.argument
|
3730
|
+
}),
|
3733
3731
|
Opcodes.i32_to,
|
3734
3732
|
[ Opcodes.i32_const, ...signedLEB128(-1) ],
|
3735
3733
|
[ Opcodes.i32_xor ],
|
@@ -3821,33 +3819,62 @@ const generateUnary = (scope, decl) => {
|
|
3821
3819
|
|
3822
3820
|
const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
|
3823
3821
|
const { name } = decl.argument;
|
3824
|
-
|
3825
3822
|
const [ local, isGlobal ] = lookupName(scope, name);
|
3823
|
+
if (local != null) {
|
3824
|
+
// fast path: just a local
|
3825
|
+
// todo: not as compliant as slow path (non numbers)
|
3826
|
+
const idx = local.idx;
|
3827
|
+
const out = [];
|
3828
|
+
|
3829
|
+
out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
|
3830
|
+
if (!decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
|
3831
|
+
|
3832
|
+
switch (decl.operator) {
|
3833
|
+
case '++':
|
3834
|
+
out.push(...number(1), [ Opcodes.add ]);
|
3835
|
+
break;
|
3826
3836
|
|
3827
|
-
|
3828
|
-
|
3829
|
-
|
3830
|
-
|
3831
|
-
const idx = local.idx;
|
3832
|
-
const out = [];
|
3833
|
-
|
3834
|
-
out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
|
3835
|
-
if (!decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
|
3837
|
+
case '--':
|
3838
|
+
out.push(...number(1), [ Opcodes.sub ]);
|
3839
|
+
break;
|
3840
|
+
}
|
3836
3841
|
|
3837
|
-
|
3838
|
-
|
3839
|
-
out.push(...number(1), [ Opcodes.add ]);
|
3840
|
-
break;
|
3842
|
+
out.push([ isGlobal ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
3843
|
+
if (decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
|
3841
3844
|
|
3842
|
-
|
3843
|
-
out.push(...number(1), [ Opcodes.sub ]);
|
3844
|
-
break;
|
3845
|
+
return out;
|
3845
3846
|
}
|
3846
3847
|
|
3847
|
-
|
3848
|
-
|
3848
|
+
// ++x: tmp = +x; x = tmp + 1
|
3849
|
+
// x++: tmp = +x; x = tmp + 1; tmp
|
3850
|
+
const tmp = localTmp(scope, '#updatetmp');
|
3851
|
+
addVarMetadata(scope, '#updatetmp', false, { type: TYPES.number });
|
3849
3852
|
|
3850
|
-
return
|
3853
|
+
return [
|
3854
|
+
// tmp = +x
|
3855
|
+
// if postfix, tee to keep on stack as return value
|
3856
|
+
...generate(scope, {
|
3857
|
+
type: 'UnaryExpression',
|
3858
|
+
operator: '+',
|
3859
|
+
prefix: true,
|
3860
|
+
argument: decl.argument
|
3861
|
+
}),
|
3862
|
+
[ decl.prefix ? Opcodes.local_set : Opcodes.local_tee, tmp ],
|
3863
|
+
|
3864
|
+
// x = tmp + 1
|
3865
|
+
...generate(scope, {
|
3866
|
+
type: 'AssignmentExpression',
|
3867
|
+
operator: '=',
|
3868
|
+
left: decl.argument,
|
3869
|
+
right: {
|
3870
|
+
type: 'BinaryExpression',
|
3871
|
+
operator: decl.operator[0],
|
3872
|
+
left: { type: 'Identifier', name: '#updatetmp' },
|
3873
|
+
right: { type: 'Literal', value: 1 }
|
3874
|
+
}
|
3875
|
+
}),
|
3876
|
+
...(decl.prefix ? [] : [ [ Opcodes.drop ] ])
|
3877
|
+
];
|
3851
3878
|
};
|
3852
3879
|
|
3853
3880
|
const generateIf = (scope, decl) => {
|
package/compiler/wrap.js
CHANGED
@@ -320,7 +320,7 @@ ${flags & 0b0001 ? ` get func idx: ${get}
|
|
320
320
|
const err = new (globalThis[TYPE_NAMES[type]] ?? Error)(obj.message);
|
321
321
|
|
322
322
|
err.name = obj.name;
|
323
|
-
err.stack = `${
|
323
|
+
err.stack = `${obj.name}: ${obj.message}`;
|
324
324
|
return err;
|
325
325
|
}
|
326
326
|
|
package/package.json
CHANGED
package/r.js
ADDED
package/runner/index.js
CHANGED
package/runner/repl.js
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import { TYPE_NAMES } from '../compiler/types.js';
|
2
2
|
import compile from '../compiler/wrap.js';
|
3
|
+
import parse from '../compiler/parse.js';
|
3
4
|
|
4
5
|
import util from 'node:util';
|
5
6
|
|
@@ -83,7 +84,13 @@ const run = (source, _context, _filename, callback, run = true) => {
|
|
83
84
|
// hack: print "secret" before latest code ran to only enable printing for new code
|
84
85
|
|
85
86
|
source = source.trim();
|
86
|
-
if (source.startsWith('{') && source.endsWith('}'))
|
87
|
+
if (source.startsWith('{') && source.endsWith('}')) {
|
88
|
+
const wrapped = '(' + source + ')';
|
89
|
+
try {
|
90
|
+
parse(wrapped);
|
91
|
+
source = wrapped;
|
92
|
+
} catch {}
|
93
|
+
}
|
87
94
|
|
88
95
|
let toRun = (prev ? (prev + `;\nprint(-0x1337);\n`) : '') + source;
|
89
96
|
|