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.cjs
CHANGED
|
@@ -1325,38 +1325,67 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1325
1325
|
const endLine = new AddressResolver(endAdress).bindBreak(innerScope);
|
|
1326
1326
|
const caseJumps = [];
|
|
1327
1327
|
let defaultJump;
|
|
1328
|
+
// if there is a case that is guaranteed to run
|
|
1329
|
+
let constantCase = false;
|
|
1330
|
+
let onlyConstantTests = true;
|
|
1328
1331
|
for (const scase of node.cases) {
|
|
1329
1332
|
const [, bodyInst] = c.handleMany(innerScope, scase.consequent);
|
|
1330
1333
|
const bodyAdress = new LiteralValue(null);
|
|
1331
1334
|
const bodyLine = new AddressResolver(bodyAdress);
|
|
1335
|
+
const canFallInto = !endsWithoutFalltrough(inst, endLine);
|
|
1336
|
+
let includeJump = !constantCase;
|
|
1337
|
+
const includeBody = !constantCase || canFallInto;
|
|
1332
1338
|
if (!scase.test) {
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1339
|
+
if (includeJump) {
|
|
1340
|
+
[defaultJump] = c.handle(innerScope, scase, () => [
|
|
1341
|
+
null,
|
|
1342
|
+
[new JumpInstruction(bodyAdress, EJumpKind.Always)],
|
|
1343
|
+
])[1];
|
|
1344
|
+
}
|
|
1345
|
+
if (includeBody)
|
|
1346
|
+
inst.push(bodyLine, ...bodyInst);
|
|
1338
1347
|
continue;
|
|
1339
1348
|
}
|
|
1340
1349
|
const [test, testInst] = c.handleEval(innerScope, scase.test);
|
|
1350
|
+
if (onlyConstantTests)
|
|
1351
|
+
onlyConstantTests = test.mutability === EMutability.constant;
|
|
1352
|
+
let jump;
|
|
1341
1353
|
// check if it can be evaluated at compile time
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
// the whole case gets omitted
|
|
1345
|
-
// otherwise it returns the instructions for
|
|
1346
|
-
// the body of this case
|
|
1354
|
+
// the scope copy prevents unecessary increases in the temp counter
|
|
1355
|
+
const [comp] = ref["=="](innerScope.copy(), test);
|
|
1347
1356
|
if (comp instanceof LiteralValue) {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1357
|
+
// whether other cases can falltrough and reach this one
|
|
1358
|
+
const noFallInto = !canFallInto;
|
|
1359
|
+
if (!comp.data) {
|
|
1360
|
+
// this case is not accessible in any way
|
|
1361
|
+
if (noFallInto)
|
|
1362
|
+
continue;
|
|
1363
|
+
includeJump = false;
|
|
1364
|
+
}
|
|
1365
|
+
else {
|
|
1366
|
+
// this case is only accessible via the comparison jump
|
|
1367
|
+
// and all the other cases will never run
|
|
1368
|
+
if (noFallInto &&
|
|
1369
|
+
onlyConstantTests &&
|
|
1370
|
+
endsWithoutFalltrough(bodyInst, endLine)) {
|
|
1371
|
+
return [null, [...bodyInst, endLine]];
|
|
1372
|
+
}
|
|
1373
|
+
jump = c.handle(innerScope, scase, () => [
|
|
1374
|
+
null,
|
|
1375
|
+
[new JumpInstruction(bodyAdress, EJumpKind.Always)],
|
|
1376
|
+
])[1];
|
|
1377
|
+
constantCase = true;
|
|
1378
|
+
}
|
|
1352
1379
|
}
|
|
1353
1380
|
// makes sourcemapping for the jump more specific
|
|
1354
|
-
|
|
1381
|
+
jump ??= c.handle(innerScope, scase, () => [
|
|
1355
1382
|
null,
|
|
1356
1383
|
[new JumpInstruction(bodyAdress, EJumpKind.StrictEqual, ref, test)],
|
|
1357
|
-
]);
|
|
1358
|
-
|
|
1359
|
-
|
|
1384
|
+
])[1];
|
|
1385
|
+
if (includeJump)
|
|
1386
|
+
caseJumps.push(...testInst, ...jump);
|
|
1387
|
+
if (includeBody)
|
|
1388
|
+
inst.push(bodyLine, ...bodyInst);
|
|
1360
1389
|
}
|
|
1361
1390
|
// ensures that the processor exits
|
|
1362
1391
|
// the switch if no cases match
|
|
@@ -1371,12 +1400,34 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1371
1400
|
[
|
|
1372
1401
|
...refInst,
|
|
1373
1402
|
...caseJumps,
|
|
1374
|
-
...(caseJumps.length > 0 ? [defaultJump] : []),
|
|
1403
|
+
...(caseJumps.length > 0 && !constantCase ? [defaultJump] : []),
|
|
1375
1404
|
...inst,
|
|
1376
1405
|
endLine,
|
|
1377
1406
|
],
|
|
1378
1407
|
];
|
|
1379
|
-
};
|
|
1408
|
+
};
|
|
1409
|
+
function endsWithoutFalltrough(inst, endLine) {
|
|
1410
|
+
if (inst.length === 0)
|
|
1411
|
+
return true;
|
|
1412
|
+
for (let i = inst.length - 1; i >= 0; i--) {
|
|
1413
|
+
const instruction = inst[i];
|
|
1414
|
+
// this means that there is an instruction trying to reference
|
|
1415
|
+
// the final function `set @counter` instruction
|
|
1416
|
+
// of course this generates an unecessary
|
|
1417
|
+
// `set @counter` in cases where a control flow
|
|
1418
|
+
// structure contains a fallback return statement
|
|
1419
|
+
// TODO: fix this with static analysis
|
|
1420
|
+
if (instruction instanceof AddressResolver)
|
|
1421
|
+
return false;
|
|
1422
|
+
if (instruction.hidden)
|
|
1423
|
+
continue;
|
|
1424
|
+
return (instruction instanceof SetCounterInstruction ||
|
|
1425
|
+
instruction.intent === EInstIntent.return ||
|
|
1426
|
+
(instruction instanceof BreakInstruction &&
|
|
1427
|
+
endLine.bonds.includes(instruction.address)));
|
|
1428
|
+
}
|
|
1429
|
+
return false;
|
|
1430
|
+
}
|
|
1380
1431
|
|
|
1381
1432
|
const WhileStatement = (c, scope, node) => {
|
|
1382
1433
|
const lines = [];
|