mlogjs 0.4.7 → 0.4.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/dist/index.cjs +71 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +71 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1304,38 +1304,67 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1304
1304
|
const endLine = new AddressResolver(endAdress).bindBreak(innerScope);
|
|
1305
1305
|
const caseJumps = [];
|
|
1306
1306
|
let defaultJump;
|
|
1307
|
+
// if there is a case that is guaranteed to run
|
|
1308
|
+
let constantCase = false;
|
|
1309
|
+
let onlyConstantTests = true;
|
|
1307
1310
|
for (const scase of node.cases) {
|
|
1308
1311
|
const [, bodyInst] = c.handleMany(innerScope, scase.consequent);
|
|
1309
1312
|
const bodyAdress = new LiteralValue(null);
|
|
1310
1313
|
const bodyLine = new AddressResolver(bodyAdress);
|
|
1314
|
+
const canFallInto = !endsWithoutFalltrough(inst, endLine);
|
|
1315
|
+
let includeJump = !constantCase;
|
|
1316
|
+
const includeBody = !constantCase || canFallInto;
|
|
1311
1317
|
if (!scase.test) {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1318
|
+
if (includeJump) {
|
|
1319
|
+
[defaultJump] = c.handle(innerScope, scase, () => [
|
|
1320
|
+
null,
|
|
1321
|
+
[new JumpInstruction(bodyAdress, EJumpKind.Always)],
|
|
1322
|
+
])[1];
|
|
1323
|
+
}
|
|
1324
|
+
if (includeBody)
|
|
1325
|
+
inst.push(bodyLine, ...bodyInst);
|
|
1317
1326
|
continue;
|
|
1318
1327
|
}
|
|
1319
1328
|
const [test, testInst] = c.handleEval(innerScope, scase.test);
|
|
1329
|
+
if (onlyConstantTests)
|
|
1330
|
+
onlyConstantTests = test.mutability === EMutability.constant;
|
|
1331
|
+
let jump;
|
|
1320
1332
|
// check if it can be evaluated at compile time
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
// the whole case gets omitted
|
|
1324
|
-
// otherwise it returns the instructions for
|
|
1325
|
-
// the body of this case
|
|
1333
|
+
// the scope copy prevents unecessary increases in the temp counter
|
|
1334
|
+
const [comp] = ref["=="](innerScope.copy(), test);
|
|
1326
1335
|
if (comp instanceof LiteralValue) {
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1336
|
+
// whether other cases can falltrough and reach this one
|
|
1337
|
+
const noFallInto = !canFallInto;
|
|
1338
|
+
if (!comp.data) {
|
|
1339
|
+
// this case is not accessible in any way
|
|
1340
|
+
if (noFallInto)
|
|
1341
|
+
continue;
|
|
1342
|
+
includeJump = false;
|
|
1343
|
+
}
|
|
1344
|
+
else {
|
|
1345
|
+
// this case is only accessible via the comparison jump
|
|
1346
|
+
// and all the other cases will never run
|
|
1347
|
+
if (noFallInto &&
|
|
1348
|
+
onlyConstantTests &&
|
|
1349
|
+
endsWithoutFalltrough(bodyInst, endLine)) {
|
|
1350
|
+
return [null, [...bodyInst, endLine]];
|
|
1351
|
+
}
|
|
1352
|
+
jump = c.handle(innerScope, scase, () => [
|
|
1353
|
+
null,
|
|
1354
|
+
[new JumpInstruction(bodyAdress, EJumpKind.Always)],
|
|
1355
|
+
])[1];
|
|
1356
|
+
constantCase = true;
|
|
1357
|
+
}
|
|
1331
1358
|
}
|
|
1332
1359
|
// makes sourcemapping for the jump more specific
|
|
1333
|
-
|
|
1360
|
+
jump ??= c.handle(innerScope, scase, () => [
|
|
1334
1361
|
null,
|
|
1335
1362
|
[new JumpInstruction(bodyAdress, EJumpKind.StrictEqual, ref, test)],
|
|
1336
|
-
]);
|
|
1337
|
-
|
|
1338
|
-
|
|
1363
|
+
])[1];
|
|
1364
|
+
if (includeJump)
|
|
1365
|
+
caseJumps.push(...testInst, ...jump);
|
|
1366
|
+
if (includeBody)
|
|
1367
|
+
inst.push(bodyLine, ...bodyInst);
|
|
1339
1368
|
}
|
|
1340
1369
|
// ensures that the processor exits
|
|
1341
1370
|
// the switch if no cases match
|
|
@@ -1350,12 +1379,34 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1350
1379
|
[
|
|
1351
1380
|
...refInst,
|
|
1352
1381
|
...caseJumps,
|
|
1353
|
-
...(caseJumps.length > 0 ? [defaultJump] : []),
|
|
1382
|
+
...(caseJumps.length > 0 && !constantCase ? [defaultJump] : []),
|
|
1354
1383
|
...inst,
|
|
1355
1384
|
endLine,
|
|
1356
1385
|
],
|
|
1357
1386
|
];
|
|
1358
|
-
};
|
|
1387
|
+
};
|
|
1388
|
+
function endsWithoutFalltrough(inst, endLine) {
|
|
1389
|
+
if (inst.length === 0)
|
|
1390
|
+
return true;
|
|
1391
|
+
for (let i = inst.length - 1; i >= 0; i--) {
|
|
1392
|
+
const instruction = inst[i];
|
|
1393
|
+
// this means that there is an instruction trying to reference
|
|
1394
|
+
// the final function `set @counter` instruction
|
|
1395
|
+
// of course this generates an unecessary
|
|
1396
|
+
// `set @counter` in cases where a control flow
|
|
1397
|
+
// structure contains a fallback return statement
|
|
1398
|
+
// TODO: fix this with static analysis
|
|
1399
|
+
if (instruction instanceof AddressResolver)
|
|
1400
|
+
return false;
|
|
1401
|
+
if (instruction.hidden)
|
|
1402
|
+
continue;
|
|
1403
|
+
return (instruction instanceof SetCounterInstruction ||
|
|
1404
|
+
instruction.intent === EInstIntent.return ||
|
|
1405
|
+
(instruction instanceof BreakInstruction &&
|
|
1406
|
+
endLine.bonds.includes(instruction.address)));
|
|
1407
|
+
}
|
|
1408
|
+
return false;
|
|
1409
|
+
}
|
|
1359
1410
|
|
|
1360
1411
|
const WhileStatement = (c, scope, node) => {
|
|
1361
1412
|
const lines = [];
|