porffor 0.50.18 → 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 +217 -229
- 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
|
|
@@ -5211,13 +5207,19 @@ const generateTry = (scope, decl) => {
|
|
5211
5207
|
|
5212
5208
|
const out = [];
|
5213
5209
|
|
5214
|
-
const finalizer = decl.finalizer ?
|
5210
|
+
const finalizer = decl.finalizer ? [
|
5211
|
+
...generate(scope, decl.finalizer),
|
5212
|
+
[ Opcodes.drop ]
|
5213
|
+
]: [];
|
5215
5214
|
|
5216
5215
|
out.push([ Opcodes.try, Blocktype.void ]);
|
5217
5216
|
depth.push('try');
|
5218
5217
|
|
5219
|
-
out.push(
|
5220
|
-
|
5218
|
+
out.push(
|
5219
|
+
...generate(scope, decl.block),
|
5220
|
+
[ Opcodes.drop ],
|
5221
|
+
...finalizer
|
5222
|
+
);
|
5221
5223
|
|
5222
5224
|
if (decl.handler) {
|
5223
5225
|
depth.pop();
|
@@ -5252,6 +5254,7 @@ const generateTry = (scope, decl) => {
|
|
5252
5254
|
|
5253
5255
|
out.push(
|
5254
5256
|
...generate(scope, decl.handler.body),
|
5257
|
+
[ Opcodes.drop ],
|
5255
5258
|
...finalizer
|
5256
5259
|
);
|
5257
5260
|
}
|
@@ -5259,11 +5262,12 @@ const generateTry = (scope, decl) => {
|
|
5259
5262
|
out.push([ Opcodes.end ]);
|
5260
5263
|
depth.pop();
|
5261
5264
|
|
5265
|
+
out.push(number(UNDEFINED));
|
5262
5266
|
return out;
|
5263
5267
|
};
|
5264
5268
|
|
5265
5269
|
const generateEmpty = (scope, decl) => {
|
5266
|
-
return [];
|
5270
|
+
return [ number(UNDEFINED) ];
|
5267
5271
|
};
|
5268
5272
|
|
5269
5273
|
const generateMeta = (scope, decl) => {
|
@@ -6143,13 +6147,15 @@ const generateClass = (scope, decl) => {
|
|
6143
6147
|
// Bar.__proto__ = Foo
|
6144
6148
|
// Bar.prototype.__proto__ = Foo.prototype
|
6145
6149
|
...generate(scope, setObjProp(root, '__proto__', decl.superClass)),
|
6146
|
-
|
6150
|
+
[ Opcodes.drop ],
|
6151
|
+
...generate(scope, setObjProp(proto, '__proto__', getObjProp(decl.superClass, 'prototype'))),
|
6152
|
+
[ Opcodes.drop ]
|
6147
6153
|
);
|
6148
6154
|
}
|
6149
6155
|
|
6150
6156
|
for (const x of body) {
|
6151
6157
|
let { type, key, value, kind, static: _static, computed } = x;
|
6152
|
-
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);
|
6153
6159
|
|
6154
6160
|
if (kind === 'constructor') continue;
|
6155
6161
|
|
@@ -6584,6 +6590,30 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6584
6590
|
wasm = generate(func, body);
|
6585
6591
|
wasm.unshift(...preface);
|
6586
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
|
+
|
6587
6617
|
if (func.generator) {
|
6588
6618
|
// make generator at the start
|
6589
6619
|
wasm.unshift(
|
@@ -6628,57 +6658,6 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6628
6658
|
ensureTag();
|
6629
6659
|
}
|
6630
6660
|
|
6631
|
-
if (name === '#main') {
|
6632
|
-
func.gotLastType = true;
|
6633
|
-
func.export = true;
|
6634
|
-
|
6635
|
-
let finalStatement = decl.body.body[decl.body.body.length - 1];
|
6636
|
-
if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
|
6637
|
-
|
6638
|
-
const lastInst = getLastInst(wasm) ?? [ Opcodes.end ];
|
6639
|
-
if (lastInst[0] === Opcodes.drop || lastInst[0] === Opcodes.f64_const) {
|
6640
|
-
if (finalStatement.type.endsWith('Declaration')) {
|
6641
|
-
// final statement is decl, force undefined
|
6642
|
-
disposeLeftover(wasm);
|
6643
|
-
wasm.push(
|
6644
|
-
number(UNDEFINED),
|
6645
|
-
number(TYPES.undefined, Valtype.i32)
|
6646
|
-
);
|
6647
|
-
} else {
|
6648
|
-
wasm.splice(wasm.length - 1, 1);
|
6649
|
-
wasm.push(...getNodeType(func, finalStatement));
|
6650
|
-
}
|
6651
|
-
}
|
6652
|
-
|
6653
|
-
if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
|
6654
|
-
if (lastInst[0] === Opcodes.local_set && lastInst[1] === func.locals['#last_type'].idx) {
|
6655
|
-
wasm.splice(wasm.length - 1, 1);
|
6656
|
-
} else {
|
6657
|
-
func.returns = [];
|
6658
|
-
}
|
6659
|
-
}
|
6660
|
-
|
6661
|
-
if (lastInst[0] === Opcodes.call) {
|
6662
|
-
const callee = funcByIndex(lastInst[1]);
|
6663
|
-
if (callee) func.returns = callee.returns.slice();
|
6664
|
-
else func.returns = [];
|
6665
|
-
}
|
6666
|
-
|
6667
|
-
// inject promise job runner func at the end of main if promises are made
|
6668
|
-
if (Object.hasOwn(funcIndex, 'Promise') || Object.hasOwn(funcIndex, '__Promise_resolve') || Object.hasOwn(funcIndex, '__Promise_reject')) {
|
6669
|
-
wasm.push(
|
6670
|
-
[ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ],
|
6671
|
-
[ Opcodes.drop ],
|
6672
|
-
[ Opcodes.drop ]
|
6673
|
-
);
|
6674
|
-
}
|
6675
|
-
} else {
|
6676
|
-
// add end return if not found
|
6677
|
-
if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) < func.returns.length) {
|
6678
|
-
wasm.push(...generateReturn(func, {}));
|
6679
|
-
}
|
6680
|
-
}
|
6681
|
-
|
6682
6661
|
return func.wasm = wasm;
|
6683
6662
|
}
|
6684
6663
|
};
|
@@ -6747,24 +6726,31 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6747
6726
|
if (globalThis.precompile) func.generate();
|
6748
6727
|
|
6749
6728
|
if (decl._doNotMarkFuncRef) doNotMarkFuncRef = true;
|
6750
|
-
const out = decl.type.endsWith('Expression') && !forceNoExpr ? funcRef(func) : [];
|
6729
|
+
const out = decl.type.endsWith('Expression') && !forceNoExpr ? funcRef(func) : [ number(UNDEFINED) ];
|
6751
6730
|
doNotMarkFuncRef = false;
|
6752
6731
|
|
6753
6732
|
astCache.set(decl, out);
|
6754
6733
|
return [ func, out ];
|
6755
6734
|
};
|
6756
6735
|
|
6757
|
-
const
|
6736
|
+
const generateBlock = (scope, decl) => {
|
6758
6737
|
let out = [];
|
6759
6738
|
|
6760
6739
|
scope.inferTree ??= [];
|
6761
6740
|
scope.inferTree.push(decl);
|
6762
6741
|
|
6763
|
-
|
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 ]);
|
6764
6748
|
out = out.concat(generate(scope, x));
|
6765
6749
|
}
|
6766
6750
|
|
6767
6751
|
scope.inferTree.pop();
|
6752
|
+
|
6753
|
+
if (out.length === 0) out.push(number(UNDEFINED));
|
6768
6754
|
return out;
|
6769
6755
|
};
|
6770
6756
|
|
@@ -6867,7 +6853,9 @@ const internalConstrs = {
|
|
6867
6853
|
scope.usesImports = true;
|
6868
6854
|
|
6869
6855
|
const str = decl.arguments[0].value;
|
6870
|
-
|
6856
|
+
const out = printStaticStr(str);
|
6857
|
+
out.push(number(UNDEFINED));
|
6858
|
+
return out;
|
6871
6859
|
},
|
6872
6860
|
type: TYPES.undefined,
|
6873
6861
|
notConstr: true,
|
package/package.json
CHANGED