porffor 0.50.17 → 0.50.19
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/codegen.js +227 -234
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -219,7 +219,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
219
219
|
return cacheAst(decl, generateFunc(scope, decl)[1]);
|
220
220
|
|
221
221
|
case 'BlockStatement':
|
222
|
-
return cacheAst(decl,
|
222
|
+
return cacheAst(decl, generateBlock(scope, decl));
|
223
223
|
|
224
224
|
case 'ReturnStatement':
|
225
225
|
return cacheAst(decl, generateReturn(scope, decl));
|
@@ -304,7 +304,10 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
304
304
|
return cacheAst(decl, generateTry(scope, decl));
|
305
305
|
|
306
306
|
case 'DebuggerStatement':
|
307
|
-
return cacheAst(decl, [
|
307
|
+
return cacheAst(decl, [
|
308
|
+
[ Opcodes.call, importedFuncs.debugger ],
|
309
|
+
number(UNDEFINED)
|
310
|
+
]);
|
308
311
|
|
309
312
|
case 'ArrayExpression':
|
310
313
|
return cacheAst(decl, generateArray(scope, decl, global, name, globalThis.precompile));
|
@@ -332,7 +335,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
332
335
|
return cacheAst(decl, generateTaggedTemplate(scope, decl, global, name));
|
333
336
|
|
334
337
|
case 'ExportNamedDeclaration':
|
335
|
-
if (!decl.declaration) return todo(scope, 'unsupported export declaration');
|
338
|
+
if (!decl.declaration) return todo(scope, 'unsupported export declaration', true);
|
336
339
|
|
337
340
|
const funcsBefore = funcs.map(x => x.name);
|
338
341
|
generate(scope, decl.declaration);
|
@@ -349,16 +352,16 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
349
352
|
}
|
350
353
|
}
|
351
354
|
|
352
|
-
return cacheAst(decl, []);
|
355
|
+
return cacheAst(decl, [ number(UNDEFINED) ]);
|
353
356
|
|
354
357
|
default:
|
355
358
|
// ignore typescript nodes
|
356
359
|
if (decl.type.startsWith('TS') ||
|
357
360
|
decl.type === 'ImportDeclaration' && decl.importKind === 'type') {
|
358
|
-
return cacheAst(decl, []);
|
361
|
+
return cacheAst(decl, [ number(UNDEFINED) ]);
|
359
362
|
}
|
360
363
|
|
361
|
-
return cacheAst(decl, todo(scope, `no generation for ${decl.type}!`,
|
364
|
+
return cacheAst(decl, todo(scope, `no generation for ${decl.type}!`, true));
|
362
365
|
}
|
363
366
|
};
|
364
367
|
|
@@ -1110,7 +1113,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
1110
1113
|
let checkType = TYPES[rightName.toLowerCase()];
|
1111
1114
|
if (checkType != null && rightName === TYPE_NAMES[checkType] && !rightName.endsWith('Error')) {
|
1112
1115
|
const out = generate(scope, decl.left);
|
1113
|
-
|
1116
|
+
out.push([ Opcodes.drop ]);
|
1114
1117
|
|
1115
1118
|
// switch primitive types to primitive object types
|
1116
1119
|
if (checkType === TYPES.number) checkType = TYPES.numberobject;
|
@@ -1532,6 +1535,7 @@ const getNodeType = (scope, node) => {
|
|
1532
1535
|
}
|
1533
1536
|
|
1534
1537
|
if (isFuncType(node.type)) {
|
1538
|
+
if (node.type.endsWith('Declaration')) return TYPES.undefined;
|
1535
1539
|
return TYPES.function;
|
1536
1540
|
}
|
1537
1541
|
|
@@ -1711,6 +1715,18 @@ const getNodeType = (scope, node) => {
|
|
1711
1715
|
return getNodeType(scope, node.expression);
|
1712
1716
|
}
|
1713
1717
|
|
1718
|
+
if (node.type === 'BlockStatement') {
|
1719
|
+
return getNodeType(scope, getLastNode(node.body));
|
1720
|
+
}
|
1721
|
+
|
1722
|
+
if (node.type === 'LabeledStatement') {
|
1723
|
+
return getNodeType(scope, node.body);
|
1724
|
+
}
|
1725
|
+
|
1726
|
+
if (node.type.endsWith('Statement') || node.type.endsWith('Declaration')) {
|
1727
|
+
return TYPES.undefined;
|
1728
|
+
}
|
1729
|
+
|
1714
1730
|
return getLastType(scope);
|
1715
1731
|
})();
|
1716
1732
|
|
@@ -1745,68 +1761,13 @@ const generateLiteral = (scope, decl, global, name) => {
|
|
1745
1761
|
}
|
1746
1762
|
};
|
1747
1763
|
|
1748
|
-
const countLeftover = wasm => {
|
1749
|
-
let count = 0, depth = 0;
|
1750
|
-
|
1751
|
-
for (let i = 0; i < wasm.length; i++) {
|
1752
|
-
const inst = wasm[i];
|
1753
|
-
if (depth === 0 && inst[0] == null) {
|
1754
|
-
if (typeof inst[1] === 'function' && typeof inst[2] === 'number') count += inst[2];
|
1755
|
-
continue;
|
1756
|
-
}
|
1757
|
-
|
1758
|
-
if (depth === 0 && (inst[0] === Opcodes.if || inst[0] === Opcodes.block || inst[0] === Opcodes.loop)) {
|
1759
|
-
if (inst[0] === Opcodes.if) count--;
|
1760
|
-
if (inst[1] !== Blocktype.void) count++;
|
1761
|
-
}
|
1762
|
-
if ([Opcodes.if, Opcodes.try, Opcodes.loop, Opcodes.block].includes(inst[0])) depth++;
|
1763
|
-
if (inst[0] === Opcodes.end) depth--;
|
1764
|
-
|
1765
|
-
if (depth === 0)
|
1766
|
-
if ([Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1767
|
-
else if ([Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_abs, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.f32_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x04)) {}
|
1768
|
-
else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const, Opcodes.memory_size].includes(inst[0])) count++;
|
1769
|
-
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.f32_store, Opcodes.i32_store16, Opcodes.i32_store8, Opcodes.select].includes(inst[0])) count -= 2;
|
1770
|
-
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1771
|
-
else if (inst[0] === Opcodes.return) count = 0;
|
1772
|
-
else if (inst[0] === Opcodes.catch) count += 2;
|
1773
|
-
else if (inst[0] === Opcodes.throw) {
|
1774
|
-
count--;
|
1775
|
-
if ((Prefs.exceptionMode ?? 'stack') === 'stack' || (globalThis.precompile && inst[1] === 1)) count--;
|
1776
|
-
} else if (inst[0] === Opcodes.call) {
|
1777
|
-
if (inst[1] < importedFuncs.length) {
|
1778
|
-
const func = importedFuncs[inst[1]];
|
1779
|
-
count = count - func.params + func.returns;
|
1780
|
-
} else {
|
1781
|
-
const func = funcByIndex(inst[1]);
|
1782
|
-
count = count - func.params.length + func.returns.length;
|
1783
|
-
}
|
1784
|
-
} else if (inst[0] === Opcodes.call_indirect) {
|
1785
|
-
count--; // funcidx
|
1786
|
-
count -= inst[1] * 2; // params * 2 (typed)
|
1787
|
-
count += 2; // fixed return (value, type)
|
1788
|
-
} else count--;
|
1789
|
-
|
1790
|
-
// console.log(count, depth, decompile([ inst ], undefined, undefined, undefined, undefined, undefined, funcs).slice(0, -1));
|
1791
|
-
}
|
1792
|
-
|
1793
|
-
return count;
|
1794
|
-
};
|
1795
|
-
|
1796
|
-
const disposeLeftover = wasm => {
|
1797
|
-
const leftover = countLeftover(wasm);
|
1798
|
-
for (let i = 0; i < leftover; i++) wasm.push([ Opcodes.drop ]);
|
1799
|
-
};
|
1800
|
-
|
1801
1764
|
const generateExp = (scope, decl) => {
|
1802
1765
|
if (decl.directive === 'use strict') {
|
1803
1766
|
scope.strict = true;
|
1767
|
+
return [ number(UNDEFINED) ];
|
1804
1768
|
}
|
1805
1769
|
|
1806
|
-
|
1807
|
-
disposeLeftover(out);
|
1808
|
-
|
1809
|
-
return out;
|
1770
|
+
return generate(scope, decl.expression, undefined, undefined, !scope.inEval);
|
1810
1771
|
};
|
1811
1772
|
|
1812
1773
|
const generateSequence = (scope, decl) => {
|
@@ -1814,8 +1775,8 @@ const generateSequence = (scope, decl) => {
|
|
1814
1775
|
|
1815
1776
|
const exprs = decl.expressions;
|
1816
1777
|
for (let i = 0; i < exprs.length; i++) {
|
1817
|
-
if (i > 0) disposeLeftover(out);
|
1818
1778
|
out.push(...generate(scope, exprs[i]));
|
1779
|
+
if (i !== exprs.length - 1) out.push([ Opcodes.drop ]);
|
1819
1780
|
}
|
1820
1781
|
|
1821
1782
|
return out;
|
@@ -1932,19 +1893,16 @@ const setObjProp = (obj, prop, value) => {
|
|
1932
1893
|
};
|
1933
1894
|
|
1934
1895
|
return objectHack({
|
1935
|
-
type: '
|
1936
|
-
|
1937
|
-
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
|
1944
|
-
|
1945
|
-
},
|
1946
|
-
right: value
|
1947
|
-
}
|
1896
|
+
type: 'AssignmentExpression',
|
1897
|
+
operator: '=',
|
1898
|
+
left: {
|
1899
|
+
type: 'MemberExpression',
|
1900
|
+
object: obj,
|
1901
|
+
property: prop,
|
1902
|
+
computed: false,
|
1903
|
+
optional: false
|
1904
|
+
},
|
1905
|
+
right: value
|
1948
1906
|
});
|
1949
1907
|
};
|
1950
1908
|
|
@@ -2058,6 +2016,14 @@ const createThisArg = (scope, decl) => {
|
|
2058
2016
|
}
|
2059
2017
|
};
|
2060
2018
|
|
2019
|
+
const isEmptyNode = x => x && (x.type === 'EmptyStatement' || (x.type === 'BlockStatement' && x.body.length === 0));
|
2020
|
+
const getLastNode = body => {
|
2021
|
+
let offset = 1, node = body[body.length - offset];
|
2022
|
+
while (isEmptyNode(node)) node = body[body.length - ++offset];
|
2023
|
+
|
2024
|
+
return node ?? { type: 'EmptyStatement' };
|
2025
|
+
};
|
2026
|
+
|
2061
2027
|
const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
2062
2028
|
if (decl.type === 'NewExpression') decl._new = true;
|
2063
2029
|
|
@@ -2095,17 +2061,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2095
2061
|
});
|
2096
2062
|
scope.inEval = false;
|
2097
2063
|
|
2098
|
-
|
2099
|
-
if (lastInst && lastInst[0] === Opcodes.drop) {
|
2100
|
-
out.splice(out.length - 1, 1);
|
2101
|
-
|
2102
|
-
const finalStatement = parsed.body[parsed.body.length - 1];
|
2103
|
-
out.push(...setLastType(scope, getNodeType(scope, finalStatement)));
|
2104
|
-
} else if (countLeftover(out) === 0) {
|
2105
|
-
out.push(number(UNDEFINED));
|
2106
|
-
out.push(...setLastType(scope, TYPES.undefined));
|
2107
|
-
}
|
2108
|
-
|
2064
|
+
out.push(...setLastType(scope, getNodeType(scope, getLastNode(parsed.body))));
|
2109
2065
|
return out;
|
2110
2066
|
}
|
2111
2067
|
}
|
@@ -2406,6 +2362,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2406
2362
|
// TODO: error better
|
2407
2363
|
default: internalThrow(scope, 'TypeError', `'${protoName}' proto func tried to be called on a type without an impl`, !unusedValue)
|
2408
2364
|
}, unusedValue ? Blocktype.void : valtypeBinary),
|
2365
|
+
...(unusedValue ? [ number(UNDEFINED) ] : [])
|
2409
2366
|
];
|
2410
2367
|
}
|
2411
2368
|
|
@@ -3060,6 +3017,7 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary, fallthrough = fals
|
|
3060
3017
|
|
3061
3018
|
out.push([ Opcodes.end ]);
|
3062
3019
|
|
3020
|
+
// todo: sometimes gets stuck?
|
3063
3021
|
if (depth.at(-1) === 'typeswitch') {
|
3064
3022
|
depth.pop();
|
3065
3023
|
}
|
@@ -3524,6 +3482,7 @@ const generateVar = (scope, decl) => {
|
|
3524
3482
|
out = out.concat(generateVarDstr(scope, decl.kind, x.id, x.init, undefined, global));
|
3525
3483
|
}
|
3526
3484
|
|
3485
|
+
out.push(number(UNDEFINED));
|
3527
3486
|
return out;
|
3528
3487
|
};
|
3529
3488
|
|
@@ -3704,7 +3663,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3704
3663
|
...decl,
|
3705
3664
|
_internalAssign: true
|
3706
3665
|
});
|
3707
|
-
if (valueUnused)
|
3666
|
+
if (valueUnused) slow.push([ Opcodes.drop ]);
|
3708
3667
|
|
3709
3668
|
return [
|
3710
3669
|
...out,
|
@@ -4053,7 +4012,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
4053
4012
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
4054
4013
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
4055
4014
|
], getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
|
4056
|
-
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
4057
4015
|
|
4058
4016
|
...setType(scope, name, getLastType(scope), true)
|
4059
4017
|
];
|
@@ -4148,7 +4106,7 @@ const generateUnary = (scope, decl) => {
|
|
4148
4106
|
case 'void': {
|
4149
4107
|
// drop current expression value after running, give undefined
|
4150
4108
|
const out = generate(scope, decl.argument);
|
4151
|
-
|
4109
|
+
out.push([ Opcodes.drop ]);
|
4152
4110
|
|
4153
4111
|
out.push(number(UNDEFINED));
|
4154
4112
|
return out;
|
@@ -4215,7 +4173,7 @@ const generateUnary = (scope, decl) => {
|
|
4215
4173
|
}
|
4216
4174
|
|
4217
4175
|
const out = toGenerate ? generate(scope, decl.argument) : [];
|
4218
|
-
|
4176
|
+
if (toGenerate) out.push([ Opcodes.drop ]);
|
4219
4177
|
|
4220
4178
|
out.push(number(toReturn ? 1 : 0));
|
4221
4179
|
return out;
|
@@ -4229,7 +4187,7 @@ const generateUnary = (scope, decl) => {
|
|
4229
4187
|
}
|
4230
4188
|
|
4231
4189
|
const out = toGenerate ? generate(scope, decl.argument) : [];
|
4232
|
-
|
4190
|
+
if (toGenerate) out.push([ Opcodes.drop ]);
|
4233
4191
|
|
4234
4192
|
out.push(...typeSwitch(scope, overrideType ?? getNodeType(scope, decl.argument), [
|
4235
4193
|
[ TYPES.number, () => makeString(scope, 'number') ],
|
@@ -4308,8 +4266,7 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
|
|
4308
4266
|
right: { type: 'Literal', value: 1 }
|
4309
4267
|
}
|
4310
4268
|
}, _global, _name, valueUnused),
|
4311
|
-
...(decl.prefix || valueUnused ? [] : [ [ Opcodes.drop ] ])
|
4312
|
-
...optional([ number(UNDEFINED) ], valueUnused)
|
4269
|
+
...(decl.prefix || valueUnused ? [] : [ [ Opcodes.drop ] ])
|
4313
4270
|
];
|
4314
4271
|
};
|
4315
4272
|
|
@@ -4351,22 +4308,26 @@ const generateIf = (scope, decl) => {
|
|
4351
4308
|
depth.push('if');
|
4352
4309
|
inferBranchStart(scope, decl.consequent);
|
4353
4310
|
|
4354
|
-
|
4355
|
-
|
4356
|
-
|
4311
|
+
out.push(
|
4312
|
+
...generate(scope, decl.consequent),
|
4313
|
+
[ Opcodes.drop ]
|
4314
|
+
);
|
4357
4315
|
|
4358
4316
|
inferBranchEnd(scope);
|
4359
4317
|
if (decl.alternate) {
|
4360
|
-
out.push([ Opcodes.else ]);
|
4361
4318
|
inferBranchStart(scope, decl.alternate);
|
4362
|
-
|
4363
|
-
|
4364
|
-
|
4365
|
-
|
4319
|
+
out.push(
|
4320
|
+
[ Opcodes.else ],
|
4321
|
+
...generate(scope, decl.alternate),
|
4322
|
+
[ Opcodes.drop ]
|
4323
|
+
);
|
4366
4324
|
inferBranchEnd(scope);
|
4367
4325
|
}
|
4368
4326
|
|
4369
|
-
out.push(
|
4327
|
+
out.push(
|
4328
|
+
[ Opcodes.end ],
|
4329
|
+
number(UNDEFINED)
|
4330
|
+
);
|
4370
4331
|
depth.pop();
|
4371
4332
|
|
4372
4333
|
return out;
|
@@ -4402,10 +4363,10 @@ let depth = [];
|
|
4402
4363
|
const generateFor = (scope, decl) => {
|
4403
4364
|
const out = [];
|
4404
4365
|
|
4405
|
-
if (decl.init)
|
4406
|
-
|
4407
|
-
|
4408
|
-
|
4366
|
+
if (decl.init) out.push(
|
4367
|
+
...generate(scope, decl.init, false, undefined, true),
|
4368
|
+
[ Opcodes.drop ]
|
4369
|
+
);
|
4409
4370
|
|
4410
4371
|
inferLoopStart(scope, decl);
|
4411
4372
|
out.push([ Opcodes.loop, Blocktype.void ]);
|
@@ -4414,19 +4375,31 @@ const generateFor = (scope, decl) => {
|
|
4414
4375
|
if (decl.test) out.push(...generate(scope, decl.test), Opcodes.i32_to);
|
4415
4376
|
else out.push(number(1, Valtype.i32));
|
4416
4377
|
|
4417
|
-
out.push(
|
4418
|
-
|
4378
|
+
out.push(
|
4379
|
+
[ Opcodes.if, Blocktype.void ],
|
4380
|
+
[ Opcodes.block, Blocktype.void ]
|
4381
|
+
);
|
4382
|
+
depth.push('if', 'block');
|
4419
4383
|
|
4420
|
-
out.push(
|
4421
|
-
|
4422
|
-
|
4423
|
-
|
4384
|
+
out.push(
|
4385
|
+
...generate(scope, decl.body),
|
4386
|
+
[ Opcodes.drop ],
|
4387
|
+
[ Opcodes.end ]
|
4388
|
+
);
|
4389
|
+
depth.pop();
|
4424
4390
|
|
4425
|
-
if (decl.update) out.push(
|
4391
|
+
if (decl.update) out.push(
|
4392
|
+
...generate(scope, decl.update, false, undefined, true),
|
4393
|
+
[ Opcodes.drop ]
|
4394
|
+
);
|
4426
4395
|
|
4427
|
-
out.push(
|
4428
|
-
|
4429
|
-
|
4396
|
+
out.push(
|
4397
|
+
[ Opcodes.br, 1 ],
|
4398
|
+
[ Opcodes.end ],
|
4399
|
+
[ Opcodes.end ],
|
4400
|
+
number(UNDEFINED)
|
4401
|
+
);
|
4402
|
+
depth.pop(); depth.pop();
|
4430
4403
|
|
4431
4404
|
inferLoopEnd(scope);
|
4432
4405
|
return out;
|
@@ -4439,14 +4412,21 @@ const generateWhile = (scope, decl) => {
|
|
4439
4412
|
out.push([ Opcodes.loop, Blocktype.void ]);
|
4440
4413
|
depth.push('while');
|
4441
4414
|
|
4442
|
-
out.push(
|
4443
|
-
|
4415
|
+
out.push(
|
4416
|
+
...generate(scope, decl.test),
|
4417
|
+
Opcodes.i32_to,
|
4418
|
+
[ Opcodes.if, Blocktype.void ]
|
4419
|
+
);
|
4444
4420
|
depth.push('if');
|
4445
4421
|
|
4446
|
-
out.push(
|
4447
|
-
|
4448
|
-
|
4449
|
-
|
4422
|
+
out.push(
|
4423
|
+
...generate(scope, decl.body),
|
4424
|
+
[ Opcodes.drop ],
|
4425
|
+
[ Opcodes.br, 1 ],
|
4426
|
+
[ Opcodes.end ],
|
4427
|
+
[ Opcodes.end ],
|
4428
|
+
number(UNDEFINED)
|
4429
|
+
);
|
4450
4430
|
depth.pop(); depth.pop();
|
4451
4431
|
|
4452
4432
|
inferLoopEnd(scope);
|
@@ -4458,27 +4438,31 @@ const generateDoWhile = (scope, decl) => {
|
|
4458
4438
|
inferLoopStart(scope, decl);
|
4459
4439
|
|
4460
4440
|
out.push([ Opcodes.loop, Blocktype.void ]);
|
4461
|
-
depth.push('dowhile');
|
4462
4441
|
|
4463
4442
|
// block for break (includes all)
|
4464
4443
|
out.push([ Opcodes.block, Blocktype.void ]);
|
4465
|
-
depth.push('block');
|
4466
4444
|
|
4467
4445
|
// block for continue
|
4468
4446
|
// includes body but not test+loop so we can exit body at anytime
|
4469
4447
|
// and still test+loop after
|
4470
4448
|
out.push([ Opcodes.block, Blocktype.void ]);
|
4471
|
-
depth.push('block');
|
4449
|
+
depth.push('dowhile', 'block', 'block');
|
4472
4450
|
|
4473
|
-
out.push(
|
4474
|
-
|
4475
|
-
|
4451
|
+
out.push(
|
4452
|
+
...generate(scope, decl.body),
|
4453
|
+
[ Opcodes.drop ],
|
4454
|
+
[ Opcodes.end ]
|
4455
|
+
);
|
4476
4456
|
depth.pop();
|
4477
4457
|
|
4478
|
-
out.push(
|
4479
|
-
|
4480
|
-
|
4481
|
-
|
4458
|
+
out.push(
|
4459
|
+
...generate(scope, decl.test),
|
4460
|
+
Opcodes.i32_to,
|
4461
|
+
[ Opcodes.br_if, 1 ],
|
4462
|
+
[ Opcodes.end ],
|
4463
|
+
[ Opcodes.end ],
|
4464
|
+
number(UNDEFINED)
|
4465
|
+
);
|
4482
4466
|
depth.pop(); depth.pop();
|
4483
4467
|
|
4484
4468
|
inferLoopEnd(scope);
|
@@ -4811,17 +4795,17 @@ const generateForOf = (scope, decl) => {
|
|
4811
4795
|
}
|
4812
4796
|
|
4813
4797
|
// next and set local
|
4814
|
-
out.push(
|
4815
|
-
|
4816
|
-
|
4817
|
-
|
4818
|
-
|
4819
|
-
|
4820
|
-
|
4821
|
-
|
4798
|
+
out.push(
|
4799
|
+
...setVar,
|
4800
|
+
...generate(scope, decl.body),
|
4801
|
+
[ Opcodes.drop ],
|
4802
|
+
[ Opcodes.br, 1 ], // continue
|
4803
|
+
[ Opcodes.end ], // end block
|
4804
|
+
[ Opcodes.end ], // end loop
|
4805
|
+
number(UNDEFINED)
|
4806
|
+
);
|
4822
4807
|
|
4823
|
-
depth.pop();
|
4824
|
-
depth.pop();
|
4808
|
+
depth.pop(); depth.pop();
|
4825
4809
|
|
4826
4810
|
inferLoopEnd(scope);
|
4827
4811
|
return out;
|
@@ -4921,6 +4905,7 @@ const generateForIn = (scope, decl) => {
|
|
4921
4905
|
[ Opcodes.i32_and ],
|
4922
4906
|
[ Opcodes.if, Blocktype.void ],
|
4923
4907
|
...generate(scope, decl.body),
|
4908
|
+
[ Opcodes.drop ],
|
4924
4909
|
[ Opcodes.end ],
|
4925
4910
|
|
4926
4911
|
// increment pointer by 14
|
@@ -4953,33 +4938,41 @@ const generateForIn = (scope, decl) => {
|
|
4953
4938
|
|
4954
4939
|
inferLoopEnd(scope);
|
4955
4940
|
|
4956
|
-
|
4941
|
+
const final = typeSwitch(scope, getNodeType(scope, decl.right), {
|
4957
4942
|
// fast path for objects
|
4958
4943
|
[TYPES.object]: out,
|
4959
4944
|
|
4960
4945
|
// wrap for of object.keys
|
4961
|
-
default: () =>
|
4962
|
-
|
4963
|
-
|
4964
|
-
|
4965
|
-
|
4966
|
-
|
4967
|
-
|
4968
|
-
|
4969
|
-
|
4970
|
-
|
4971
|
-
|
4972
|
-
|
4973
|
-
|
4974
|
-
|
4975
|
-
|
4976
|
-
|
4977
|
-
|
4978
|
-
|
4979
|
-
|
4980
|
-
|
4981
|
-
|
4946
|
+
default: () => {
|
4947
|
+
const out = generate(scope, {
|
4948
|
+
type: 'ForOfStatement',
|
4949
|
+
left: decl.left,
|
4950
|
+
body: decl.body,
|
4951
|
+
right: {
|
4952
|
+
type: 'CallExpression',
|
4953
|
+
callee: {
|
4954
|
+
type: 'Identifier',
|
4955
|
+
name: '__Object_keys'
|
4956
|
+
},
|
4957
|
+
arguments: [ {
|
4958
|
+
type: 'LogicalExpression',
|
4959
|
+
left: decl.right,
|
4960
|
+
operator: '??',
|
4961
|
+
right: {
|
4962
|
+
type: 'Literal',
|
4963
|
+
value: 0
|
4964
|
+
}
|
4965
|
+
} ]
|
4966
|
+
}
|
4967
|
+
});
|
4968
|
+
|
4969
|
+
out.push([ Opcodes.drop ]);
|
4970
|
+
return out;
|
4971
|
+
}
|
4982
4972
|
}, Blocktype.void);
|
4973
|
+
|
4974
|
+
final.push(number(UNDEFINED));
|
4975
|
+
return final;
|
4983
4976
|
};
|
4984
4977
|
|
4985
4978
|
const generateSwitch = (scope, decl) => {
|
@@ -5024,6 +5017,7 @@ const generateSwitch = (scope, decl) => {
|
|
5024
5017
|
}, Blocktype.void, true);
|
5025
5018
|
|
5026
5019
|
depth.pop();
|
5020
|
+
out.push(number(UNDEFINED));
|
5027
5021
|
return out;
|
5028
5022
|
}
|
5029
5023
|
}
|
@@ -5082,13 +5076,15 @@ const generateSwitch = (scope, decl) => {
|
|
5082
5076
|
depth.pop();
|
5083
5077
|
out.push(
|
5084
5078
|
[ Opcodes.end ],
|
5085
|
-
...generate(scope, { type: 'BlockStatement', body: cases[i].consequent })
|
5079
|
+
...generate(scope, { type: 'BlockStatement', body: cases[i].consequent }),
|
5080
|
+
[ Opcodes.drop ]
|
5086
5081
|
);
|
5087
5082
|
}
|
5088
5083
|
|
5089
5084
|
out.push([ Opcodes.end ]);
|
5090
5085
|
depth.pop();
|
5091
5086
|
|
5087
|
+
out.push(number(UNDEFINED));
|
5092
5088
|
return out;
|
5093
5089
|
};
|
5094
5090
|
|
@@ -5193,11 +5189,16 @@ const generateThrow = (scope, decl) => {
|
|
5193
5189
|
];
|
5194
5190
|
}
|
5195
5191
|
|
5196
|
-
|
5197
|
-
|
5198
|
-
|
5199
|
-
|
5200
|
-
|
5192
|
+
const out = generate(scope, decl.argument);
|
5193
|
+
const lastOp = out.at(-1);
|
5194
|
+
if (lastOp[0] === Opcodes.local_set && lastOp[1] === scope.locals['#last_type']?.idx) {
|
5195
|
+
out.pop();
|
5196
|
+
} else {
|
5197
|
+
out.push(...getNodeType(scope, decl.argument));
|
5198
|
+
}
|
5199
|
+
|
5200
|
+
out.push([ Opcodes.throw, globalThis.precompile ? 1 : 0 ]);
|
5201
|
+
return out;
|
5201
5202
|
};
|
5202
5203
|
|
5203
5204
|
const generateTry = (scope, decl) => {
|
@@ -5206,13 +5207,19 @@ const generateTry = (scope, decl) => {
|
|
5206
5207
|
|
5207
5208
|
const out = [];
|
5208
5209
|
|
5209
|
-
const finalizer = decl.finalizer ?
|
5210
|
+
const finalizer = decl.finalizer ? [
|
5211
|
+
...generate(scope, decl.finalizer),
|
5212
|
+
[ Opcodes.drop ]
|
5213
|
+
]: [];
|
5210
5214
|
|
5211
5215
|
out.push([ Opcodes.try, Blocktype.void ]);
|
5212
5216
|
depth.push('try');
|
5213
5217
|
|
5214
|
-
out.push(
|
5215
|
-
|
5218
|
+
out.push(
|
5219
|
+
...generate(scope, decl.block),
|
5220
|
+
[ Opcodes.drop ],
|
5221
|
+
...finalizer
|
5222
|
+
);
|
5216
5223
|
|
5217
5224
|
if (decl.handler) {
|
5218
5225
|
depth.pop();
|
@@ -5247,6 +5254,7 @@ const generateTry = (scope, decl) => {
|
|
5247
5254
|
|
5248
5255
|
out.push(
|
5249
5256
|
...generate(scope, decl.handler.body),
|
5257
|
+
[ Opcodes.drop ],
|
5250
5258
|
...finalizer
|
5251
5259
|
);
|
5252
5260
|
}
|
@@ -5254,11 +5262,12 @@ const generateTry = (scope, decl) => {
|
|
5254
5262
|
out.push([ Opcodes.end ]);
|
5255
5263
|
depth.pop();
|
5256
5264
|
|
5265
|
+
out.push(number(UNDEFINED));
|
5257
5266
|
return out;
|
5258
5267
|
};
|
5259
5268
|
|
5260
5269
|
const generateEmpty = (scope, decl) => {
|
5261
|
-
return [];
|
5270
|
+
return [ number(UNDEFINED) ];
|
5262
5271
|
};
|
5263
5272
|
|
5264
5273
|
const generateMeta = (scope, decl) => {
|
@@ -6138,13 +6147,15 @@ const generateClass = (scope, decl) => {
|
|
6138
6147
|
// Bar.__proto__ = Foo
|
6139
6148
|
// Bar.prototype.__proto__ = Foo.prototype
|
6140
6149
|
...generate(scope, setObjProp(root, '__proto__', decl.superClass)),
|
6141
|
-
|
6150
|
+
[ Opcodes.drop ],
|
6151
|
+
...generate(scope, setObjProp(proto, '__proto__', getObjProp(decl.superClass, 'prototype'))),
|
6152
|
+
[ Opcodes.drop ]
|
6142
6153
|
);
|
6143
6154
|
}
|
6144
6155
|
|
6145
6156
|
for (const x of body) {
|
6146
6157
|
let { type, key, value, kind, static: _static, computed } = x;
|
6147
|
-
if (type !== 'MethodDefinition' && type !== 'PropertyDefinition') return todo(scope, `class body type ${type} is not supported yet`,
|
6158
|
+
if (type !== 'MethodDefinition' && type !== 'PropertyDefinition') return todo(scope, `class body type ${type} is not supported yet`, true);
|
6148
6159
|
|
6149
6160
|
if (kind === 'constructor') continue;
|
6150
6161
|
|
@@ -6579,6 +6590,30 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6579
6590
|
wasm = generate(func, body);
|
6580
6591
|
wasm.unshift(...preface);
|
6581
6592
|
|
6593
|
+
if (name === '#main') {
|
6594
|
+
func.gotLastType = true;
|
6595
|
+
func.export = true;
|
6596
|
+
|
6597
|
+
wasm.push(...getNodeType(func, getLastNode(decl.body.body)));
|
6598
|
+
|
6599
|
+
// inject promise job runner func at the end of main if promises are made
|
6600
|
+
if (Object.hasOwn(funcIndex, 'Promise') || Object.hasOwn(funcIndex, '__Promise_resolve') || Object.hasOwn(funcIndex, '__Promise_reject')) {
|
6601
|
+
wasm.push(
|
6602
|
+
[ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ],
|
6603
|
+
[ Opcodes.drop ],
|
6604
|
+
[ Opcodes.drop ]
|
6605
|
+
);
|
6606
|
+
}
|
6607
|
+
} else {
|
6608
|
+
// add end empty return if not found
|
6609
|
+
if (wasm[wasm.length - 1]?.[0] !== Opcodes.return) {
|
6610
|
+
wasm.push(
|
6611
|
+
[ Opcodes.drop ],
|
6612
|
+
...generateReturn(func, {})
|
6613
|
+
);
|
6614
|
+
}
|
6615
|
+
}
|
6616
|
+
|
6582
6617
|
if (func.generator) {
|
6583
6618
|
// make generator at the start
|
6584
6619
|
wasm.unshift(
|
@@ -6623,57 +6658,6 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6623
6658
|
ensureTag();
|
6624
6659
|
}
|
6625
6660
|
|
6626
|
-
if (name === '#main') {
|
6627
|
-
func.gotLastType = true;
|
6628
|
-
func.export = true;
|
6629
|
-
|
6630
|
-
let finalStatement = decl.body.body[decl.body.body.length - 1];
|
6631
|
-
if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
|
6632
|
-
|
6633
|
-
const lastInst = getLastInst(wasm) ?? [ Opcodes.end ];
|
6634
|
-
if (lastInst[0] === Opcodes.drop || lastInst[0] === Opcodes.f64_const) {
|
6635
|
-
if (finalStatement.type.endsWith('Declaration')) {
|
6636
|
-
// final statement is decl, force undefined
|
6637
|
-
disposeLeftover(wasm);
|
6638
|
-
wasm.push(
|
6639
|
-
number(UNDEFINED),
|
6640
|
-
number(TYPES.undefined, Valtype.i32)
|
6641
|
-
);
|
6642
|
-
} else {
|
6643
|
-
wasm.splice(wasm.length - 1, 1);
|
6644
|
-
wasm.push(...getNodeType(func, finalStatement));
|
6645
|
-
}
|
6646
|
-
}
|
6647
|
-
|
6648
|
-
if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
|
6649
|
-
if (lastInst[0] === Opcodes.local_set && lastInst[1] === func.locals['#last_type'].idx) {
|
6650
|
-
wasm.splice(wasm.length - 1, 1);
|
6651
|
-
} else {
|
6652
|
-
func.returns = [];
|
6653
|
-
}
|
6654
|
-
}
|
6655
|
-
|
6656
|
-
if (lastInst[0] === Opcodes.call) {
|
6657
|
-
const callee = funcByIndex(lastInst[1]);
|
6658
|
-
if (callee) func.returns = callee.returns.slice();
|
6659
|
-
else func.returns = [];
|
6660
|
-
}
|
6661
|
-
|
6662
|
-
// inject promise job runner func at the end of main if promises are made
|
6663
|
-
if (Object.hasOwn(funcIndex, 'Promise') || Object.hasOwn(funcIndex, '__Promise_resolve') || Object.hasOwn(funcIndex, '__Promise_reject')) {
|
6664
|
-
wasm.push(
|
6665
|
-
[ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ],
|
6666
|
-
[ Opcodes.drop ],
|
6667
|
-
[ Opcodes.drop ]
|
6668
|
-
);
|
6669
|
-
}
|
6670
|
-
} else {
|
6671
|
-
// add end return if not found
|
6672
|
-
if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) < func.returns.length) {
|
6673
|
-
wasm.push(...generateReturn(func, {}));
|
6674
|
-
}
|
6675
|
-
}
|
6676
|
-
|
6677
6661
|
return func.wasm = wasm;
|
6678
6662
|
}
|
6679
6663
|
};
|
@@ -6742,24 +6726,31 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6742
6726
|
if (globalThis.precompile) func.generate();
|
6743
6727
|
|
6744
6728
|
if (decl._doNotMarkFuncRef) doNotMarkFuncRef = true;
|
6745
|
-
const out = decl.type.endsWith('Expression') && !forceNoExpr ? funcRef(func) : [];
|
6729
|
+
const out = decl.type.endsWith('Expression') && !forceNoExpr ? funcRef(func) : [ number(UNDEFINED) ];
|
6746
6730
|
doNotMarkFuncRef = false;
|
6747
6731
|
|
6748
6732
|
astCache.set(decl, out);
|
6749
6733
|
return [ func, out ];
|
6750
6734
|
};
|
6751
6735
|
|
6752
|
-
const
|
6736
|
+
const generateBlock = (scope, decl) => {
|
6753
6737
|
let out = [];
|
6754
6738
|
|
6755
6739
|
scope.inferTree ??= [];
|
6756
6740
|
scope.inferTree.push(decl);
|
6757
6741
|
|
6758
|
-
|
6742
|
+
let j = 0;
|
6743
|
+
for (let i = 0; i < decl.body.length; i++) {
|
6744
|
+
const x = decl.body[i];
|
6745
|
+
if (isEmptyNode(x)) continue;
|
6746
|
+
|
6747
|
+
if (j++ > 0) out.push([ Opcodes.drop ]);
|
6759
6748
|
out = out.concat(generate(scope, x));
|
6760
6749
|
}
|
6761
6750
|
|
6762
6751
|
scope.inferTree.pop();
|
6752
|
+
|
6753
|
+
if (out.length === 0) out.push(number(UNDEFINED));
|
6763
6754
|
return out;
|
6764
6755
|
};
|
6765
6756
|
|
@@ -6862,7 +6853,9 @@ const internalConstrs = {
|
|
6862
6853
|
scope.usesImports = true;
|
6863
6854
|
|
6864
6855
|
const str = decl.arguments[0].value;
|
6865
|
-
|
6856
|
+
const out = printStaticStr(str);
|
6857
|
+
out.push(number(UNDEFINED));
|
6858
|
+
return out;
|
6866
6859
|
},
|
6867
6860
|
type: TYPES.undefined,
|
6868
6861
|
notConstr: true,
|
package/package.json
CHANGED