mlogjs 0.4.7 → 0.4.9
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/handlers/Object.d.ts +2 -1
- package/dist/handlers/OperationExpressions.d.ts +1 -0
- package/dist/handlers/Statements.d.ts +1 -0
- package/dist/index.cjs +128 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +128 -23
- package/dist/index.mjs.map +1 -1
- package/dist/utils/general.d.ts +2 -0
- package/dist/values/BaseValue.d.ts +1 -0
- package/dist/values/StoreValue.d.ts +4 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -262,6 +262,11 @@ function camelToDashCase(name) {
|
|
|
262
262
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
263
263
|
function assign(obj, props) {
|
|
264
264
|
return Object.assign(obj, props);
|
|
265
|
+
}
|
|
266
|
+
/** Lazily computes and caches an expression */
|
|
267
|
+
function lazy(fn) {
|
|
268
|
+
let value;
|
|
269
|
+
return () => (value ??= fn());
|
|
265
270
|
}
|
|
266
271
|
|
|
267
272
|
function appendSourceLocations(valueInst, node) {
|
|
@@ -524,12 +529,16 @@ class BaseValue extends VoidValue {
|
|
|
524
529
|
],
|
|
525
530
|
];
|
|
526
531
|
}
|
|
532
|
+
"!=="(scope, other, out) {
|
|
533
|
+
const [equal, equalInst] = this["==="](scope, other);
|
|
534
|
+
const [result, resultInst] = equal["!"](scope, out);
|
|
535
|
+
return [result, [...equalInst, ...resultInst]];
|
|
536
|
+
}
|
|
527
537
|
}
|
|
528
538
|
const operatorMap$1 = {
|
|
529
539
|
"==": "equal",
|
|
530
540
|
"===": "strictEqual",
|
|
531
541
|
"!=": "notEqual",
|
|
532
|
-
"!==": "notEqual",
|
|
533
542
|
"<": "lessThan",
|
|
534
543
|
">": "greaterThan",
|
|
535
544
|
"<=": "lessThanEq",
|
|
@@ -739,12 +748,40 @@ class StoreValue extends BaseValue {
|
|
|
739
748
|
const [evalValue, evalInst] = value.eval(scope, this);
|
|
740
749
|
return [this, [...evalInst, new SetInstruction(this, evalValue)]];
|
|
741
750
|
}
|
|
751
|
+
"=="(scope, value, out) {
|
|
752
|
+
if (compareStores(this, value))
|
|
753
|
+
return [new LiteralValue(1), []];
|
|
754
|
+
return super["=="](scope, value, out);
|
|
755
|
+
}
|
|
756
|
+
"==="(scope, value, out) {
|
|
757
|
+
if (compareStores(this, value))
|
|
758
|
+
return [new LiteralValue(1), []];
|
|
759
|
+
return super["==="](scope, value, out);
|
|
760
|
+
}
|
|
761
|
+
"!="(scope, value, out) {
|
|
762
|
+
if (compareStores(this, value))
|
|
763
|
+
return [new LiteralValue(0), []];
|
|
764
|
+
return super["!="](scope, value, out);
|
|
765
|
+
}
|
|
766
|
+
"!=="(scope, value, out) {
|
|
767
|
+
if (compareStores(this, value))
|
|
768
|
+
return [new LiteralValue(0), []];
|
|
769
|
+
return super["!=="](scope, value, out);
|
|
770
|
+
}
|
|
742
771
|
eval(_scope) {
|
|
743
772
|
return [this, []];
|
|
744
773
|
}
|
|
745
774
|
toString() {
|
|
746
775
|
return this.name;
|
|
747
776
|
}
|
|
777
|
+
}
|
|
778
|
+
function compareStores(left, right) {
|
|
779
|
+
return (left === right ||
|
|
780
|
+
// prevents a store from being equal to a senseable value
|
|
781
|
+
(right instanceof left.constructor &&
|
|
782
|
+
right.mutability === EMutability.constant &&
|
|
783
|
+
left.mutability === EMutability.constant &&
|
|
784
|
+
right.name === left.name));
|
|
748
785
|
}
|
|
749
786
|
|
|
750
787
|
class ObjectValue extends VoidValue {
|
|
@@ -1228,6 +1265,17 @@ const ConditionalExpression = (c, scope, node, out) => {
|
|
|
1228
1265
|
new AddressResolver(endExpressionAdress),
|
|
1229
1266
|
],
|
|
1230
1267
|
];
|
|
1268
|
+
};
|
|
1269
|
+
const SequenceExpression = (c, scope, node, out) => {
|
|
1270
|
+
const { expressions } = node;
|
|
1271
|
+
const inst = [];
|
|
1272
|
+
// compute every expression except the last one
|
|
1273
|
+
for (let i = 0; i < expressions.length - 1; i++) {
|
|
1274
|
+
const [, exprInst] = c.handleEval(scope, expressions[i], discardedName);
|
|
1275
|
+
inst.push(...exprInst);
|
|
1276
|
+
}
|
|
1277
|
+
const [value, valueInst] = c.handleEval(scope, expressions[expressions.length - 1], out);
|
|
1278
|
+
return [value, [...inst, ...valueInst]];
|
|
1231
1279
|
};
|
|
1232
1280
|
|
|
1233
1281
|
const Identifier = (c, scope, node) => {
|
|
@@ -1259,6 +1307,7 @@ const ReturnStatement = (c, scope, node, out) => {
|
|
|
1259
1307
|
const [ret, retInst] = scope.function.return(scope, arg, out);
|
|
1260
1308
|
return [ret, [...argInst, ...retInst]];
|
|
1261
1309
|
};
|
|
1310
|
+
const EmptyStatement = () => [null, []];
|
|
1262
1311
|
const LabeledStatement = (c, scope, node) => {
|
|
1263
1312
|
const inner = scope.createScope();
|
|
1264
1313
|
inner.label = node.label.name;
|
|
@@ -1304,38 +1353,67 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1304
1353
|
const endLine = new AddressResolver(endAdress).bindBreak(innerScope);
|
|
1305
1354
|
const caseJumps = [];
|
|
1306
1355
|
let defaultJump;
|
|
1356
|
+
// if there is a case that is guaranteed to run
|
|
1357
|
+
let constantCase = false;
|
|
1358
|
+
let onlyConstantTests = true;
|
|
1307
1359
|
for (const scase of node.cases) {
|
|
1308
|
-
const
|
|
1360
|
+
const bodyInst = lazy(() => c.handleMany(innerScope, scase.consequent)[1]);
|
|
1309
1361
|
const bodyAdress = new LiteralValue(null);
|
|
1310
1362
|
const bodyLine = new AddressResolver(bodyAdress);
|
|
1363
|
+
const canFallInto = !endsWithoutFalltrough(inst, endLine);
|
|
1364
|
+
let includeJump = !constantCase;
|
|
1365
|
+
const includeBody = !constantCase || canFallInto;
|
|
1311
1366
|
if (!scase.test) {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1367
|
+
if (includeJump) {
|
|
1368
|
+
[defaultJump] = c.handle(innerScope, scase, () => [
|
|
1369
|
+
null,
|
|
1370
|
+
[new JumpInstruction(bodyAdress, EJumpKind.Always)],
|
|
1371
|
+
])[1];
|
|
1372
|
+
}
|
|
1373
|
+
if (includeBody)
|
|
1374
|
+
inst.push(bodyLine, ...bodyInst());
|
|
1317
1375
|
continue;
|
|
1318
1376
|
}
|
|
1319
1377
|
const [test, testInst] = c.handleEval(innerScope, scase.test);
|
|
1378
|
+
if (onlyConstantTests)
|
|
1379
|
+
onlyConstantTests = test.mutability === EMutability.constant;
|
|
1380
|
+
let jump;
|
|
1320
1381
|
// 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
|
|
1382
|
+
// the scope copy prevents unecessary increases in the temp counter
|
|
1383
|
+
const [comp] = ref["=="](innerScope.copy(), test);
|
|
1326
1384
|
if (comp instanceof LiteralValue) {
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1385
|
+
// whether other cases can falltrough and reach this one
|
|
1386
|
+
const noFallInto = !canFallInto;
|
|
1387
|
+
if (!comp.data) {
|
|
1388
|
+
// this case is not accessible in any way
|
|
1389
|
+
if (noFallInto)
|
|
1390
|
+
continue;
|
|
1391
|
+
includeJump = false;
|
|
1392
|
+
}
|
|
1393
|
+
else {
|
|
1394
|
+
// this case is only accessible via the comparison jump
|
|
1395
|
+
// and all the other cases will never run
|
|
1396
|
+
if (noFallInto &&
|
|
1397
|
+
onlyConstantTests &&
|
|
1398
|
+
endsWithoutFalltrough(bodyInst(), endLine)) {
|
|
1399
|
+
return [null, [...bodyInst(), endLine]];
|
|
1400
|
+
}
|
|
1401
|
+
jump = c.handle(innerScope, scase, () => [
|
|
1402
|
+
null,
|
|
1403
|
+
[new JumpInstruction(bodyAdress, EJumpKind.Always)],
|
|
1404
|
+
])[1];
|
|
1405
|
+
constantCase = true;
|
|
1406
|
+
}
|
|
1331
1407
|
}
|
|
1332
1408
|
// makes sourcemapping for the jump more specific
|
|
1333
|
-
|
|
1409
|
+
jump ??= c.handle(innerScope, scase, () => [
|
|
1334
1410
|
null,
|
|
1335
1411
|
[new JumpInstruction(bodyAdress, EJumpKind.StrictEqual, ref, test)],
|
|
1336
|
-
]);
|
|
1337
|
-
|
|
1338
|
-
|
|
1412
|
+
])[1];
|
|
1413
|
+
if (includeJump)
|
|
1414
|
+
caseJumps.push(...testInst, ...jump);
|
|
1415
|
+
if (includeBody)
|
|
1416
|
+
inst.push(bodyLine, ...bodyInst());
|
|
1339
1417
|
}
|
|
1340
1418
|
// ensures that the processor exits
|
|
1341
1419
|
// the switch if no cases match
|
|
@@ -1350,12 +1428,34 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1350
1428
|
[
|
|
1351
1429
|
...refInst,
|
|
1352
1430
|
...caseJumps,
|
|
1353
|
-
...(caseJumps.length > 0 ? [defaultJump] : []),
|
|
1431
|
+
...(caseJumps.length > 0 && !constantCase ? [defaultJump] : []),
|
|
1354
1432
|
...inst,
|
|
1355
1433
|
endLine,
|
|
1356
1434
|
],
|
|
1357
1435
|
];
|
|
1358
|
-
};
|
|
1436
|
+
};
|
|
1437
|
+
function endsWithoutFalltrough(inst, endLine) {
|
|
1438
|
+
if (inst.length === 0)
|
|
1439
|
+
return true;
|
|
1440
|
+
for (let i = inst.length - 1; i >= 0; i--) {
|
|
1441
|
+
const instruction = inst[i];
|
|
1442
|
+
// this means that there is an instruction trying to reference
|
|
1443
|
+
// the final function `set @counter` instruction
|
|
1444
|
+
// of course this generates an unecessary
|
|
1445
|
+
// `set @counter` in cases where a control flow
|
|
1446
|
+
// structure contains a fallback return statement
|
|
1447
|
+
// TODO: fix this with static analysis
|
|
1448
|
+
if (instruction instanceof AddressResolver)
|
|
1449
|
+
return false;
|
|
1450
|
+
if (instruction.hidden)
|
|
1451
|
+
continue;
|
|
1452
|
+
return (instruction instanceof SetCounterInstruction ||
|
|
1453
|
+
instruction.intent === EInstIntent.return ||
|
|
1454
|
+
(instruction instanceof BreakInstruction &&
|
|
1455
|
+
endLine.bonds.includes(instruction.address)));
|
|
1456
|
+
}
|
|
1457
|
+
return false;
|
|
1458
|
+
}
|
|
1359
1459
|
|
|
1360
1460
|
const WhileStatement = (c, scope, node) => {
|
|
1361
1461
|
const lines = [];
|
|
@@ -1791,7 +1891,9 @@ const ObjectPattern = (c, scope, node) => {
|
|
|
1791
1891
|
});
|
|
1792
1892
|
}
|
|
1793
1893
|
return [new DestructuringValue(members), inst];
|
|
1794
|
-
};
|
|
1894
|
+
};
|
|
1895
|
+
// the mlog runtime already does this check for us
|
|
1896
|
+
const OptionalMemberExpression = MemberExpression;
|
|
1795
1897
|
|
|
1796
1898
|
const TemplateLiteral = () => {
|
|
1797
1899
|
throw new CompilerError("Template strings are currently unavailable. To inline mlog code use the asm function.");
|
|
@@ -1868,11 +1970,13 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1868
1970
|
UnaryExpression: UnaryExpression,
|
|
1869
1971
|
UpdateExpression: UpdateExpression,
|
|
1870
1972
|
ConditionalExpression: ConditionalExpression,
|
|
1973
|
+
SequenceExpression: SequenceExpression,
|
|
1871
1974
|
Identifier: Identifier,
|
|
1872
1975
|
ExpressionStatement: ExpressionStatement,
|
|
1873
1976
|
BreakStatement: BreakStatement,
|
|
1874
1977
|
ContinueStatement: ContinueStatement,
|
|
1875
1978
|
ReturnStatement: ReturnStatement,
|
|
1979
|
+
EmptyStatement: EmptyStatement,
|
|
1876
1980
|
LabeledStatement: LabeledStatement,
|
|
1877
1981
|
IfStatement: IfStatement,
|
|
1878
1982
|
SwitchStatement: SwitchStatement,
|
|
@@ -1891,6 +1995,7 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1891
1995
|
MemberExpression: MemberExpression,
|
|
1892
1996
|
ArrayPattern: ArrayPattern,
|
|
1893
1997
|
ObjectPattern: ObjectPattern,
|
|
1998
|
+
OptionalMemberExpression: OptionalMemberExpression,
|
|
1894
1999
|
TemplateLiteral: TemplateLiteral,
|
|
1895
2000
|
BlockStatement: BlockStatement,
|
|
1896
2001
|
File: File,
|