porffor 0.49.7 → 0.49.8
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 +7 -4
- package/compiler/builtins/console.ts +8 -8
- package/compiler/builtins/date.ts +1 -1
- package/compiler/builtins/math.ts +7 -2
- package/compiler/builtins/string.ts +8 -8
- package/compiler/builtins_precompiled.js +58 -58
- package/compiler/codegen.js +168 -60
- package/compiler/cyclone.js +6 -2
- package/compiler/index.js +2 -0
- package/compiler/parse.js +1 -1
- package/compiler/precompile.js +4 -4
- package/package.json +1 -1
- package/runner/debug.js +0 -1
- package/runner/flamegraph.js +205 -0
- package/runner/hotlines.js +0 -1
- package/runner/index.js +7 -2
- package/richards.js +0 -913
package/compiler/codegen.js
CHANGED
@@ -1334,6 +1334,40 @@ const isExistingProtoFunc = name => {
|
|
1334
1334
|
return false;
|
1335
1335
|
};
|
1336
1336
|
|
1337
|
+
let globalInfer;
|
1338
|
+
const getInferred = (scope, name, global = false) => {
|
1339
|
+
if (global) {
|
1340
|
+
if (globalInfer.has(name)) return globalInfer.get(name);
|
1341
|
+
} else if (scope.inferTree) {
|
1342
|
+
for (let i = scope.inferTree.length - 1; i >= 0; i--) {
|
1343
|
+
const x = scope.inferTree[i];
|
1344
|
+
if (x._infer?.has(name)) return x._infer.get(name);
|
1345
|
+
}
|
1346
|
+
}
|
1347
|
+
|
1348
|
+
return null;
|
1349
|
+
};
|
1350
|
+
|
1351
|
+
const setInferred = (scope, name, type, global = false) => {
|
1352
|
+
scope.inferTree ??= [];
|
1353
|
+
|
1354
|
+
if (global) {
|
1355
|
+
// set inferred type in global if not already and not in a loop, else make it null
|
1356
|
+
globalInfer.set(name, globalInfer.has(name) || inferLoopPrev.length > 0 ? null : type);
|
1357
|
+
} else {
|
1358
|
+
// set inferred type in top
|
1359
|
+
const top = scope.inferTree.at(-1);
|
1360
|
+
top._infer ??= new Map();
|
1361
|
+
top._infer.set(name, type);
|
1362
|
+
|
1363
|
+
// invalidate inferred type above if mismatched
|
1364
|
+
for (let i = scope.inferTree.length - 2; i >= 0; i--) {
|
1365
|
+
const x = scope.inferTree[i];
|
1366
|
+
if (x._infer && x._infer.get(name) !== type) x._infer.set(name, null);
|
1367
|
+
}
|
1368
|
+
}
|
1369
|
+
};
|
1370
|
+
|
1337
1371
|
const getType = (scope, name, failEarly = false) => {
|
1338
1372
|
const fallback = failEarly ? number(TYPES.undefined, Valtype.i32) : [ [ null, () => {
|
1339
1373
|
return getType(scope, name, true);
|
@@ -1341,71 +1375,73 @@ const getType = (scope, name, failEarly = false) => {
|
|
1341
1375
|
|
1342
1376
|
if (Object.hasOwn(builtinVars, name)) return number(builtinVars[name].type ?? TYPES.number, Valtype.i32);
|
1343
1377
|
|
1378
|
+
let metadata, typeLocal, global = null;
|
1344
1379
|
if (Object.hasOwn(scope.locals, name)) {
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1380
|
+
metadata = scope.locals[name].metadata;
|
1381
|
+
typeLocal = scope.locals[name + '#type'];
|
1382
|
+
global = false;
|
1383
|
+
} else if (Object.hasOwn(globals, name)) {
|
1384
|
+
metadata = globals[name].metadata;
|
1385
|
+
typeLocal = globals[name + '#type'];
|
1386
|
+
global = true;
|
1352
1387
|
}
|
1353
1388
|
|
1354
|
-
if (name === 'arguments' && scope.name !== '#main' && !scope.arrow) {
|
1389
|
+
if (global !== false && name === 'arguments' && scope.name !== '#main' && !scope.arrow) {
|
1355
1390
|
return number(TYPES.array, Valtype.i32);
|
1356
1391
|
}
|
1357
1392
|
|
1358
|
-
if (
|
1359
|
-
|
1393
|
+
if (metadata?.type != null) {
|
1394
|
+
return number(metadata.type, Valtype.i32);
|
1395
|
+
}
|
1360
1396
|
|
1361
|
-
|
1362
|
-
|
1397
|
+
const inferred = getInferred(scope, name, global);
|
1398
|
+
if (metadata?.type === undefined && inferred != null) return number(inferred, Valtype.i32);
|
1363
1399
|
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1400
|
+
if (typeLocal) return [
|
1401
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, typeLocal.idx ]
|
1402
|
+
];
|
1367
1403
|
|
1368
|
-
if (
|
1369
|
-
|
1370
|
-
|
1404
|
+
if (hasFuncWithName(name)) {
|
1405
|
+
return number(TYPES.function, Valtype.i32);
|
1406
|
+
}
|
1371
1407
|
|
1372
1408
|
if (isExistingProtoFunc(name)) return number(TYPES.function, Valtype.i32);
|
1373
1409
|
|
1374
1410
|
return fallback;
|
1375
1411
|
};
|
1376
1412
|
|
1377
|
-
const setType = (scope, name, type) => {
|
1413
|
+
const setType = (scope, name, type, noInfer = false) => {
|
1378
1414
|
typeUsed(scope, knownType(scope, type));
|
1379
1415
|
|
1380
1416
|
const out = typeof type === 'number' ? number(type, Valtype.i32) : type;
|
1381
1417
|
|
1418
|
+
let metadata, typeLocal, global = false;
|
1382
1419
|
if (Object.hasOwn(scope.locals, name)) {
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1420
|
+
metadata = scope.locals[name].metadata;
|
1421
|
+
typeLocal = scope.locals[name + '#type'];
|
1422
|
+
} else if (Object.hasOwn(globals, name)) {
|
1423
|
+
metadata = globals[name].metadata;
|
1424
|
+
typeLocal = globals[name + '#type'];
|
1425
|
+
global = true;
|
1426
|
+
}
|
1390
1427
|
|
1391
|
-
|
1428
|
+
if (metadata?.type != null) {
|
1392
1429
|
return [];
|
1393
1430
|
}
|
1394
1431
|
|
1395
|
-
if (
|
1396
|
-
|
1397
|
-
|
1398
|
-
const typeLocal = globals[name + '#type'];
|
1399
|
-
if (typeLocal) return [
|
1400
|
-
...out,
|
1401
|
-
[ Opcodes.global_set, typeLocal.idx ]
|
1402
|
-
];
|
1432
|
+
if (!noInfer) {
|
1433
|
+
const newInferred = knownType(scope, type);
|
1434
|
+
setInferred(scope, name, newInferred, global);
|
1403
1435
|
|
1404
|
-
// todo:
|
1405
|
-
return [];
|
1436
|
+
// todo/opt: skip setting if already matches previous
|
1406
1437
|
}
|
1407
1438
|
|
1408
|
-
|
1439
|
+
if (typeLocal) return [
|
1440
|
+
...out,
|
1441
|
+
[ global ? Opcodes.global_set : Opcodes.local_set, typeLocal.idx ]
|
1442
|
+
];
|
1443
|
+
|
1444
|
+
// todo: warn or error here
|
1409
1445
|
return [];
|
1410
1446
|
};
|
1411
1447
|
|
@@ -1506,7 +1542,6 @@ const getNodeType = (scope, node) => {
|
|
1506
1542
|
if (node.type === 'AssignmentExpression') {
|
1507
1543
|
const op = node.operator.slice(0, -1) || '=';
|
1508
1544
|
if (op === '=') return getNodeType(scope, node.right);
|
1509
|
-
// if (op === '=') return getNodeType(scope, node.left);
|
1510
1545
|
|
1511
1546
|
return getNodeType(scope, {
|
1512
1547
|
type: ['||', '&&', '??'].includes(op) ? 'LogicalExpression' : 'BinaryExpression',
|
@@ -1615,6 +1650,10 @@ const getNodeType = (scope, node) => {
|
|
1615
1650
|
return getNodeType(scope, node.expressions.at(-1));
|
1616
1651
|
}
|
1617
1652
|
|
1653
|
+
if (node.type === 'ChainExpression') {
|
1654
|
+
return getNodeType(scope, node.expression);
|
1655
|
+
}
|
1656
|
+
|
1618
1657
|
return getLastType(scope);
|
1619
1658
|
})();
|
1620
1659
|
|
@@ -1763,6 +1802,14 @@ const ArrayUtil = {
|
|
1763
1802
|
]
|
1764
1803
|
};
|
1765
1804
|
|
1805
|
+
const getLastInst = wasm => {
|
1806
|
+
for (let i = wasm.length - 1; i >= 0; i--) {
|
1807
|
+
if (wasm[i]?.[0] != null) return wasm[i];
|
1808
|
+
}
|
1809
|
+
|
1810
|
+
return null;
|
1811
|
+
};
|
1812
|
+
|
1766
1813
|
const createNewTarget = (scope, decl, idx = 0, force = false) => {
|
1767
1814
|
if (decl._new || force) {
|
1768
1815
|
return [
|
@@ -1993,7 +2040,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1993
2040
|
});
|
1994
2041
|
scope.inEval = false;
|
1995
2042
|
|
1996
|
-
const lastInst = out
|
2043
|
+
const lastInst = getLastInst(out);
|
1997
2044
|
if (lastInst && lastInst[0] === Opcodes.drop) {
|
1998
2045
|
out.splice(out.length - 1, 1);
|
1999
2046
|
|
@@ -2671,10 +2718,7 @@ const knownType = (scope, type) => {
|
|
2671
2718
|
|
2672
2719
|
// type idx = var idx + 1
|
2673
2720
|
const name = Object.values(scope.locals).find(x => x.idx === idx)?.name;
|
2674
|
-
if (name)
|
2675
|
-
const local = scope.locals[name];
|
2676
|
-
if (local.metadata?.type != null) return v.metadata.type;
|
2677
|
-
}
|
2721
|
+
if (scope.locals[name]?.metadata?.type != null) return scope.locals[name].metadata.type;
|
2678
2722
|
}
|
2679
2723
|
|
2680
2724
|
return null;
|
@@ -2775,8 +2819,6 @@ const typeUsed = (scope, x) => {
|
|
2775
2819
|
if (x == null) return;
|
2776
2820
|
usedTypes.add(x);
|
2777
2821
|
|
2778
|
-
// console.log(scope.name, TYPE_NAMES[x]);
|
2779
|
-
|
2780
2822
|
scope.usedTypes ??= new Set();
|
2781
2823
|
scope.usedTypes.add(x);
|
2782
2824
|
};
|
@@ -2932,6 +2974,11 @@ const allocVar = (scope, name, global = false, type = true) => {
|
|
2932
2974
|
return idx;
|
2933
2975
|
};
|
2934
2976
|
|
2977
|
+
const setVarMetadata = (scope, name, global = false, metadata = {}) => {
|
2978
|
+
const target = global ? globals : scope.locals;
|
2979
|
+
target[name].metadata = metadata;
|
2980
|
+
};
|
2981
|
+
|
2935
2982
|
const addVarMetadata = (scope, name, global = false, metadata = {}) => {
|
2936
2983
|
const target = global ? globals : scope.locals;
|
2937
2984
|
|
@@ -3111,13 +3158,12 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
|
3111
3158
|
// let generated;
|
3112
3159
|
// if (init) generated = generate(scope, init, global, name);
|
3113
3160
|
|
3114
|
-
const typed = typedInput && pattern.typeAnnotation;
|
3115
|
-
let idx = allocVar(scope, name, global, !(typed &&
|
3116
|
-
addVarMetadata(scope, name, global, { kind });
|
3161
|
+
const typed = typedInput && pattern.typeAnnotation && extractTypeAnnotation(pattern);
|
3162
|
+
let idx = allocVar(scope, name, global, !(typed && typed.type != null));
|
3117
3163
|
|
3118
|
-
|
3119
|
-
|
3120
|
-
|
3164
|
+
const metadata = { kind };
|
3165
|
+
setVarMetadata(scope, name, global, metadata);
|
3166
|
+
if (typed) Object.assign(metadata, typed);
|
3121
3167
|
|
3122
3168
|
if (init) {
|
3123
3169
|
const alreadyArray = scope.arrays?.get(name) != null;
|
@@ -3143,7 +3189,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
|
3143
3189
|
[ Opcodes.if, Blocktype.void ],
|
3144
3190
|
...generate(scope, defaultValue, global, name),
|
3145
3191
|
[ global ? Opcodes.global_set : Opcodes.local_set, idx ],
|
3146
|
-
...setType(scope, name, getNodeType(scope, defaultValue)),
|
3192
|
+
...setType(scope, name, getNodeType(scope, defaultValue), true),
|
3147
3193
|
[ Opcodes.end ],
|
3148
3194
|
);
|
3149
3195
|
}
|
@@ -3152,6 +3198,8 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
|
3152
3198
|
scope.globalInits ??= {};
|
3153
3199
|
scope.globalInits[name] = newOut;
|
3154
3200
|
}
|
3201
|
+
} else {
|
3202
|
+
setInferred(scope, name, null, global);
|
3155
3203
|
}
|
3156
3204
|
|
3157
3205
|
return out;
|
@@ -3714,7 +3762,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3714
3762
|
// only allow = for this, or if in strict mode always throw
|
3715
3763
|
if (!isIdentAssignable(scope, name, op)) return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
3716
3764
|
|
3717
|
-
if (type
|
3765
|
+
if (type !== 'Identifier') {
|
3718
3766
|
const tmpName = '#rhs' + uniqId();
|
3719
3767
|
return [
|
3720
3768
|
...generateVarDstr(scope, 'const', tmpName, decl.right, undefined, true),
|
@@ -3755,6 +3803,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3755
3803
|
// instead, left @ (left = right)
|
3756
3804
|
// eg, x &&= y ~= x && (x = y)
|
3757
3805
|
|
3806
|
+
setInferred(scope, name, knownType(scope, getNodeType(scope, decl)), isGlobal);
|
3807
|
+
|
3758
3808
|
return [
|
3759
3809
|
...performOp(scope, op, [
|
3760
3810
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
@@ -3765,7 +3815,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3765
3815
|
], getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
|
3766
3816
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3767
3817
|
|
3768
|
-
...setType(scope, name, getLastType(scope))
|
3818
|
+
...setType(scope, name, getLastType(scope), true)
|
3769
3819
|
];
|
3770
3820
|
}
|
3771
3821
|
|
@@ -3776,6 +3826,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3776
3826
|
getNodeType(scope, decl)
|
3777
3827
|
);
|
3778
3828
|
|
3829
|
+
setInferred(scope, name, knownType(scope, getNodeType(scope, decl)), isGlobal);
|
3830
|
+
|
3779
3831
|
if (valueUnused) out.push(...number(UNDEFINED));
|
3780
3832
|
return out;
|
3781
3833
|
};
|
@@ -3999,6 +4051,33 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3999
4051
|
];
|
4000
4052
|
};
|
4001
4053
|
|
4054
|
+
const inferBranchStart = (scope, decl) => {
|
4055
|
+
scope.inferTree ??= [];
|
4056
|
+
scope.inferTree.push(decl);
|
4057
|
+
};
|
4058
|
+
|
4059
|
+
const inferBranchEnd = scope => {
|
4060
|
+
scope.inferTree.pop();
|
4061
|
+
};
|
4062
|
+
|
4063
|
+
const inferBranchElse = (scope, decl) => {
|
4064
|
+
inferBranchEnd(scope);
|
4065
|
+
inferBranchStart(scope, decl);
|
4066
|
+
};
|
4067
|
+
|
4068
|
+
const inferLoopPrev = [];
|
4069
|
+
const inferLoopStart = (scope, decl) => {
|
4070
|
+
scope.inferTree ??= [];
|
4071
|
+
|
4072
|
+
// todo/opt: do not just wipe the infer tree for loops
|
4073
|
+
inferLoopPrev.push(scope.inferTree);
|
4074
|
+
scope.inferTree = [ decl ];
|
4075
|
+
};
|
4076
|
+
|
4077
|
+
const inferLoopEnd = scope => {
|
4078
|
+
scope.inferTree = inferLoopPrev.pop();
|
4079
|
+
};
|
4080
|
+
|
4002
4081
|
const generateIf = (scope, decl) => {
|
4003
4082
|
if (globalThis.precompile && decl.test?.tag?.name === '__Porffor_comptime_flag') {
|
4004
4083
|
const flag = decl.test.quasi.quasis[0].value.raw;
|
@@ -4006,20 +4085,23 @@ const generateIf = (scope, decl) => {
|
|
4006
4085
|
}
|
4007
4086
|
|
4008
4087
|
const out = truthy(scope, generate(scope, decl.test), getNodeType(scope, decl.test), false, true);
|
4009
|
-
|
4010
4088
|
out.push([ Opcodes.if, Blocktype.void ]);
|
4011
4089
|
depth.push('if');
|
4090
|
+
inferBranchStart(scope, decl.consequent);
|
4012
4091
|
|
4013
4092
|
const consOut = generate(scope, decl.consequent);
|
4014
4093
|
disposeLeftover(consOut);
|
4015
4094
|
out.push(...consOut);
|
4016
4095
|
|
4096
|
+
inferBranchEnd(scope);
|
4017
4097
|
if (decl.alternate) {
|
4018
4098
|
out.push([ Opcodes.else ]);
|
4099
|
+
inferBranchStart(scope, decl.alternate);
|
4019
4100
|
|
4020
4101
|
const altOut = generate(scope, decl.alternate);
|
4021
4102
|
disposeLeftover(altOut);
|
4022
4103
|
out.push(...altOut);
|
4104
|
+
inferBranchEnd(scope);
|
4023
4105
|
}
|
4024
4106
|
|
4025
4107
|
out.push([ Opcodes.end ]);
|
@@ -4033,6 +4115,7 @@ const generateConditional = (scope, decl) => {
|
|
4033
4115
|
|
4034
4116
|
out.push([ Opcodes.if, valtypeBinary ]);
|
4035
4117
|
depth.push('if');
|
4118
|
+
inferBranchStart(scope, decl.consequent);
|
4036
4119
|
|
4037
4120
|
out.push(
|
4038
4121
|
...generate(scope, decl.consequent),
|
@@ -4040,6 +4123,7 @@ const generateConditional = (scope, decl) => {
|
|
4040
4123
|
);
|
4041
4124
|
|
4042
4125
|
out.push([ Opcodes.else ]);
|
4126
|
+
inferBranchElse(scope, decl.alternate);
|
4043
4127
|
|
4044
4128
|
out.push(
|
4045
4129
|
...generate(scope, decl.alternate),
|
@@ -4047,7 +4131,7 @@ const generateConditional = (scope, decl) => {
|
|
4047
4131
|
);
|
4048
4132
|
|
4049
4133
|
out.push([ Opcodes.end ]);
|
4050
|
-
|
4134
|
+
inferBranchEnd(scope);
|
4051
4135
|
|
4052
4136
|
return out;
|
4053
4137
|
};
|
@@ -4061,6 +4145,7 @@ const generateFor = (scope, decl) => {
|
|
4061
4145
|
disposeLeftover(out);
|
4062
4146
|
}
|
4063
4147
|
|
4148
|
+
inferLoopStart(scope, decl);
|
4064
4149
|
out.push([ Opcodes.loop, Blocktype.void ]);
|
4065
4150
|
depth.push('for');
|
4066
4151
|
|
@@ -4081,11 +4166,13 @@ const generateFor = (scope, decl) => {
|
|
4081
4166
|
out.push([ Opcodes.end ], [ Opcodes.end ]);
|
4082
4167
|
depth.pop(); depth.pop(); depth.pop();
|
4083
4168
|
|
4169
|
+
inferLoopEnd(scope);
|
4084
4170
|
return out;
|
4085
4171
|
};
|
4086
4172
|
|
4087
4173
|
const generateWhile = (scope, decl) => {
|
4088
4174
|
const out = [];
|
4175
|
+
inferLoopStart(scope, decl);
|
4089
4176
|
|
4090
4177
|
out.push([ Opcodes.loop, Blocktype.void ]);
|
4091
4178
|
depth.push('while');
|
@@ -4100,11 +4187,13 @@ const generateWhile = (scope, decl) => {
|
|
4100
4187
|
out.push([ Opcodes.end ], [ Opcodes.end ]);
|
4101
4188
|
depth.pop(); depth.pop();
|
4102
4189
|
|
4190
|
+
inferLoopEnd(scope);
|
4103
4191
|
return out;
|
4104
4192
|
};
|
4105
4193
|
|
4106
4194
|
const generateDoWhile = (scope, decl) => {
|
4107
4195
|
const out = [];
|
4196
|
+
inferLoopStart(scope, decl);
|
4108
4197
|
|
4109
4198
|
out.push([ Opcodes.loop, Blocktype.void ]);
|
4110
4199
|
depth.push('dowhile');
|
@@ -4130,6 +4219,7 @@ const generateDoWhile = (scope, decl) => {
|
|
4130
4219
|
out.push([ Opcodes.end ], [ Opcodes.end ]);
|
4131
4220
|
depth.pop(); depth.pop();
|
4132
4221
|
|
4222
|
+
inferLoopEnd(scope);
|
4133
4223
|
return out;
|
4134
4224
|
};
|
4135
4225
|
|
@@ -4174,6 +4264,7 @@ const generateForOf = (scope, decl) => {
|
|
4174
4264
|
[ Opcodes.if, Blocktype.void ]
|
4175
4265
|
);
|
4176
4266
|
|
4267
|
+
inferLoopStart(scope, decl);
|
4177
4268
|
depth.push('if');
|
4178
4269
|
depth.push('forof');
|
4179
4270
|
depth.push('block');
|
@@ -4504,6 +4595,7 @@ const generateForOf = (scope, decl) => {
|
|
4504
4595
|
depth.pop();
|
4505
4596
|
depth.pop();
|
4506
4597
|
|
4598
|
+
inferLoopEnd(scope);
|
4507
4599
|
return out;
|
4508
4600
|
};
|
4509
4601
|
|
@@ -4537,6 +4629,7 @@ const generateForIn = (scope, decl) => {
|
|
4537
4629
|
[ Opcodes.if, Blocktype.void ]
|
4538
4630
|
);
|
4539
4631
|
|
4632
|
+
inferLoopStart(scope, decl);
|
4540
4633
|
depth.push('if');
|
4541
4634
|
depth.push('forin');
|
4542
4635
|
depth.push('block');
|
@@ -4630,6 +4723,8 @@ const generateForIn = (scope, decl) => {
|
|
4630
4723
|
depth.pop();
|
4631
4724
|
depth.pop();
|
4632
4725
|
|
4726
|
+
inferLoopEnd(scope);
|
4727
|
+
|
4633
4728
|
return typeSwitch(scope, getNodeType(scope, decl.right), {
|
4634
4729
|
// fast path for objects
|
4635
4730
|
[TYPES.object]: out,
|
@@ -5872,7 +5967,6 @@ const generateClass = (scope, decl) => {
|
|
5872
5967
|
export const generateTemplate = (scope, decl) => {
|
5873
5968
|
let current = null;
|
5874
5969
|
const append = val => {
|
5875
|
-
// console.log(val);
|
5876
5970
|
if (!current) {
|
5877
5971
|
current = val;
|
5878
5972
|
return;
|
@@ -6065,6 +6159,8 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6065
6159
|
return [ func, out ];
|
6066
6160
|
}
|
6067
6161
|
|
6162
|
+
if (name === '#main') globalInfer = new Map();
|
6163
|
+
|
6068
6164
|
globalThis.progress?.(null, ' ' + name);
|
6069
6165
|
|
6070
6166
|
const params = decl.params ?? [];
|
@@ -6083,6 +6179,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6083
6179
|
async: decl.async,
|
6084
6180
|
subclass: decl._subclass, _onlyConstr: decl._onlyConstr, _onlyThisMethod: decl._onlyThisMethod,
|
6085
6181
|
strict: scope.strict || decl.strict,
|
6182
|
+
inferTree: [ decl ],
|
6086
6183
|
|
6087
6184
|
generate() {
|
6088
6185
|
if (func.wasm) return func.wasm;
|
@@ -6163,7 +6260,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6163
6260
|
...generate(func, def, false, name),
|
6164
6261
|
[ Opcodes.local_set, func.locals[name].idx ],
|
6165
6262
|
|
6166
|
-
...setType(func, name, getNodeType(func, def)),
|
6263
|
+
...setType(func, name, getNodeType(func, def), true),
|
6167
6264
|
[ Opcodes.end ]
|
6168
6265
|
);
|
6169
6266
|
|
@@ -6257,7 +6354,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6257
6354
|
let finalStatement = decl.body.body[decl.body.body.length - 1];
|
6258
6355
|
if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
|
6259
6356
|
|
6260
|
-
const lastInst = wasm
|
6357
|
+
const lastInst = getLastInst(wasm) ?? [ Opcodes.end ];
|
6261
6358
|
if (lastInst[0] === Opcodes.drop || lastInst[0] === Opcodes.f64_const) {
|
6262
6359
|
if (finalStatement.type.endsWith('Declaration')) {
|
6263
6360
|
// final statement is decl, force undefined
|
@@ -6376,10 +6473,14 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6376
6473
|
const generateCode = (scope, decl) => {
|
6377
6474
|
let out = [];
|
6378
6475
|
|
6476
|
+
scope.inferTree ??= [];
|
6477
|
+
scope.inferTree.push(decl);
|
6478
|
+
|
6379
6479
|
for (const x of decl.body) {
|
6380
6480
|
out = out.concat(generate(scope, x));
|
6381
6481
|
}
|
6382
6482
|
|
6483
|
+
scope.inferTree.pop();
|
6383
6484
|
return out;
|
6384
6485
|
};
|
6385
6486
|
|
@@ -6497,6 +6598,13 @@ const internalConstrs = {
|
|
6497
6598
|
type: TYPES.number,
|
6498
6599
|
notConstr: true,
|
6499
6600
|
length: 1
|
6601
|
+
},
|
6602
|
+
|
6603
|
+
__Porffor_compileType: {
|
6604
|
+
generate: (scope, decl) => makeString(scope, TYPE_NAMES[knownType(scope, getNodeType(scope, decl.arguments[0]))] ?? 'unknown'),
|
6605
|
+
type: TYPES.bytestring,
|
6606
|
+
notConstr: true,
|
6607
|
+
length: 1
|
6500
6608
|
}
|
6501
6609
|
};
|
6502
6610
|
|
package/compiler/cyclone.js
CHANGED
@@ -3,7 +3,6 @@ import { signedLEB128, ieee754_binary64, read_ieee754_binary64, read_signedLEB12
|
|
3
3
|
import { Opcodes, Valtype } from './wasmSpec.js';
|
4
4
|
import { number } from './embedding.js';
|
5
5
|
|
6
|
-
|
7
6
|
const f64ToI32Op = {
|
8
7
|
[Opcodes.f64_eq]: Opcodes.i32_eq,
|
9
8
|
[Opcodes.f64_ne]: Opcodes.i32_ne,
|
@@ -23,7 +22,6 @@ export default wasm => {
|
|
23
22
|
let op = wasm[i];
|
24
23
|
if (!op) continue;
|
25
24
|
|
26
|
-
// op = [ ...op.filter(x => x != null && x <= 0xff) ];
|
27
25
|
op = [ ...op ];
|
28
26
|
wasm[i] = op;
|
29
27
|
|
@@ -479,6 +477,12 @@ export default wasm => {
|
|
479
477
|
break;
|
480
478
|
}
|
481
479
|
|
480
|
+
// case Opcodes.local_tee: {
|
481
|
+
// if (stack.length < 1) { empty(); break; }
|
482
|
+
// push(pop());
|
483
|
+
// break;
|
484
|
+
// }
|
485
|
+
|
482
486
|
default: {
|
483
487
|
empty();
|
484
488
|
break;
|
package/compiler/index.js
CHANGED
@@ -96,6 +96,8 @@ export default (code, module = undefined) => {
|
|
96
96
|
if (logProgress) progressStart('generating wasm...');
|
97
97
|
const t1 = performance.now();
|
98
98
|
const { funcs, globals, tags, exceptions, pages, data } = codegen(program);
|
99
|
+
if (globalThis.compileCallback) globalThis.compileCallback({ funcs, globals, tags, exceptions, pages, data });
|
100
|
+
|
99
101
|
if (logProgress) progressDone('generated wasm', t1);
|
100
102
|
|
101
103
|
if (Prefs.funcs) logFuncs(funcs, globals, exceptions);
|
package/compiler/parse.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import { log } from './log.js';
|
2
2
|
import './prefs.js';
|
3
3
|
|
4
|
-
const file =
|
4
|
+
const file = globalThis.file;
|
5
5
|
|
6
6
|
// should we try to support types (while parsing)
|
7
7
|
const types = Prefs.parseTypes || Prefs.t || file?.endsWith('.ts');
|
package/compiler/precompile.js
CHANGED
@@ -45,7 +45,7 @@ const compile = async (file, _funcs) => {
|
|
45
45
|
first = source.slice(0, source.indexOf('\n'));
|
46
46
|
}
|
47
47
|
|
48
|
-
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'];
|
48
|
+
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', '--no-treeshake-wasm-imports'];
|
49
49
|
if (first.startsWith('// @porf')) {
|
50
50
|
args = first.slice('// @porf '.length).split(' ').concat(args);
|
51
51
|
}
|
@@ -190,15 +190,15 @@ const precompile = async () => {
|
|
190
190
|
try {
|
191
191
|
await compile(join(dir, file), funcs);
|
192
192
|
} catch (e) {
|
193
|
-
console.log(`\r${' '.repeat(
|
193
|
+
console.log(`\r${' '.repeat(80)}\r${' '.repeat(12)}${file}`);
|
194
194
|
throw e;
|
195
195
|
}
|
196
196
|
|
197
|
-
process.stdout.write(`\r${' '.repeat(
|
197
|
+
process.stdout.write(`\r${' '.repeat(80)}\r\u001b[90m${`[${(performance.now() - t).toFixed(2)}ms]`.padEnd(12, ' ')}\u001b[0m\u001b[92m${file}\u001b[0m`);
|
198
198
|
}
|
199
199
|
|
200
200
|
const total = performance.now() - t;
|
201
|
-
console.log(`\r${' '.repeat(
|
201
|
+
console.log(`\r${' '.repeat(80)}\r\u001b[90m${`[${total.toFixed(2)}ms]`.padEnd(12, ' ')}\u001b[0m\u001b[92mcompiled ${fileCount} files (${funcs.length} funcs)\u001b[0m \u001b[90m(${['parse', 'codegen', 'opt'].map(x => `${x}: ${((timing[x] / total) * 100).toFixed(0)}%`).join(', ')})\u001b[0m`);
|
202
202
|
|
203
203
|
const comptimeFlagChecks = {
|
204
204
|
hasFunc: x => `hasFunc('${x}')`
|
package/package.json
CHANGED