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
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { THandler } from "../types";
|
|
1
|
+
import { IValue, THandler } from "../types";
|
|
2
2
|
export declare const ObjectExpression: THandler;
|
|
3
3
|
export declare const ArrayExpression: THandler;
|
|
4
4
|
export declare const MemberExpression: THandler;
|
|
5
5
|
export declare const ArrayPattern: THandler;
|
|
6
6
|
export declare const ObjectPattern: THandler;
|
|
7
|
+
export declare const OptionalMemberExpression: THandler<IValue>;
|
|
@@ -3,4 +3,5 @@ export declare const ExpressionStatement: THandler<IValue | null>;
|
|
|
3
3
|
export declare const BreakStatement: THandler<null>;
|
|
4
4
|
export declare const ContinueStatement: THandler<null>;
|
|
5
5
|
export declare const ReturnStatement: THandler<IValue | null>;
|
|
6
|
+
export declare const EmptyStatement: THandler<null>;
|
|
6
7
|
export declare const LabeledStatement: THandler<null>;
|
package/dist/index.cjs
CHANGED
|
@@ -283,6 +283,11 @@ function camelToDashCase(name) {
|
|
|
283
283
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
284
284
|
function assign(obj, props) {
|
|
285
285
|
return Object.assign(obj, props);
|
|
286
|
+
}
|
|
287
|
+
/** Lazily computes and caches an expression */
|
|
288
|
+
function lazy(fn) {
|
|
289
|
+
let value;
|
|
290
|
+
return () => (value ??= fn());
|
|
286
291
|
}
|
|
287
292
|
|
|
288
293
|
function appendSourceLocations(valueInst, node) {
|
|
@@ -545,12 +550,16 @@ class BaseValue extends VoidValue {
|
|
|
545
550
|
],
|
|
546
551
|
];
|
|
547
552
|
}
|
|
553
|
+
"!=="(scope, other, out) {
|
|
554
|
+
const [equal, equalInst] = this["==="](scope, other);
|
|
555
|
+
const [result, resultInst] = equal["!"](scope, out);
|
|
556
|
+
return [result, [...equalInst, ...resultInst]];
|
|
557
|
+
}
|
|
548
558
|
}
|
|
549
559
|
const operatorMap$1 = {
|
|
550
560
|
"==": "equal",
|
|
551
561
|
"===": "strictEqual",
|
|
552
562
|
"!=": "notEqual",
|
|
553
|
-
"!==": "notEqual",
|
|
554
563
|
"<": "lessThan",
|
|
555
564
|
">": "greaterThan",
|
|
556
565
|
"<=": "lessThanEq",
|
|
@@ -760,12 +769,40 @@ class StoreValue extends BaseValue {
|
|
|
760
769
|
const [evalValue, evalInst] = value.eval(scope, this);
|
|
761
770
|
return [this, [...evalInst, new SetInstruction(this, evalValue)]];
|
|
762
771
|
}
|
|
772
|
+
"=="(scope, value, out) {
|
|
773
|
+
if (compareStores(this, value))
|
|
774
|
+
return [new LiteralValue(1), []];
|
|
775
|
+
return super["=="](scope, value, out);
|
|
776
|
+
}
|
|
777
|
+
"==="(scope, value, out) {
|
|
778
|
+
if (compareStores(this, value))
|
|
779
|
+
return [new LiteralValue(1), []];
|
|
780
|
+
return super["==="](scope, value, out);
|
|
781
|
+
}
|
|
782
|
+
"!="(scope, value, out) {
|
|
783
|
+
if (compareStores(this, value))
|
|
784
|
+
return [new LiteralValue(0), []];
|
|
785
|
+
return super["!="](scope, value, out);
|
|
786
|
+
}
|
|
787
|
+
"!=="(scope, value, out) {
|
|
788
|
+
if (compareStores(this, value))
|
|
789
|
+
return [new LiteralValue(0), []];
|
|
790
|
+
return super["!=="](scope, value, out);
|
|
791
|
+
}
|
|
763
792
|
eval(_scope) {
|
|
764
793
|
return [this, []];
|
|
765
794
|
}
|
|
766
795
|
toString() {
|
|
767
796
|
return this.name;
|
|
768
797
|
}
|
|
798
|
+
}
|
|
799
|
+
function compareStores(left, right) {
|
|
800
|
+
return (left === right ||
|
|
801
|
+
// prevents a store from being equal to a senseable value
|
|
802
|
+
(right instanceof left.constructor &&
|
|
803
|
+
right.mutability === EMutability.constant &&
|
|
804
|
+
left.mutability === EMutability.constant &&
|
|
805
|
+
right.name === left.name));
|
|
769
806
|
}
|
|
770
807
|
|
|
771
808
|
class ObjectValue extends VoidValue {
|
|
@@ -1249,6 +1286,17 @@ const ConditionalExpression = (c, scope, node, out) => {
|
|
|
1249
1286
|
new AddressResolver(endExpressionAdress),
|
|
1250
1287
|
],
|
|
1251
1288
|
];
|
|
1289
|
+
};
|
|
1290
|
+
const SequenceExpression = (c, scope, node, out) => {
|
|
1291
|
+
const { expressions } = node;
|
|
1292
|
+
const inst = [];
|
|
1293
|
+
// compute every expression except the last one
|
|
1294
|
+
for (let i = 0; i < expressions.length - 1; i++) {
|
|
1295
|
+
const [, exprInst] = c.handleEval(scope, expressions[i], discardedName);
|
|
1296
|
+
inst.push(...exprInst);
|
|
1297
|
+
}
|
|
1298
|
+
const [value, valueInst] = c.handleEval(scope, expressions[expressions.length - 1], out);
|
|
1299
|
+
return [value, [...inst, ...valueInst]];
|
|
1252
1300
|
};
|
|
1253
1301
|
|
|
1254
1302
|
const Identifier = (c, scope, node) => {
|
|
@@ -1280,6 +1328,7 @@ const ReturnStatement = (c, scope, node, out) => {
|
|
|
1280
1328
|
const [ret, retInst] = scope.function.return(scope, arg, out);
|
|
1281
1329
|
return [ret, [...argInst, ...retInst]];
|
|
1282
1330
|
};
|
|
1331
|
+
const EmptyStatement = () => [null, []];
|
|
1283
1332
|
const LabeledStatement = (c, scope, node) => {
|
|
1284
1333
|
const inner = scope.createScope();
|
|
1285
1334
|
inner.label = node.label.name;
|
|
@@ -1325,38 +1374,67 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1325
1374
|
const endLine = new AddressResolver(endAdress).bindBreak(innerScope);
|
|
1326
1375
|
const caseJumps = [];
|
|
1327
1376
|
let defaultJump;
|
|
1377
|
+
// if there is a case that is guaranteed to run
|
|
1378
|
+
let constantCase = false;
|
|
1379
|
+
let onlyConstantTests = true;
|
|
1328
1380
|
for (const scase of node.cases) {
|
|
1329
|
-
const
|
|
1381
|
+
const bodyInst = lazy(() => c.handleMany(innerScope, scase.consequent)[1]);
|
|
1330
1382
|
const bodyAdress = new LiteralValue(null);
|
|
1331
1383
|
const bodyLine = new AddressResolver(bodyAdress);
|
|
1384
|
+
const canFallInto = !endsWithoutFalltrough(inst, endLine);
|
|
1385
|
+
let includeJump = !constantCase;
|
|
1386
|
+
const includeBody = !constantCase || canFallInto;
|
|
1332
1387
|
if (!scase.test) {
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1388
|
+
if (includeJump) {
|
|
1389
|
+
[defaultJump] = c.handle(innerScope, scase, () => [
|
|
1390
|
+
null,
|
|
1391
|
+
[new JumpInstruction(bodyAdress, EJumpKind.Always)],
|
|
1392
|
+
])[1];
|
|
1393
|
+
}
|
|
1394
|
+
if (includeBody)
|
|
1395
|
+
inst.push(bodyLine, ...bodyInst());
|
|
1338
1396
|
continue;
|
|
1339
1397
|
}
|
|
1340
1398
|
const [test, testInst] = c.handleEval(innerScope, scase.test);
|
|
1399
|
+
if (onlyConstantTests)
|
|
1400
|
+
onlyConstantTests = test.mutability === EMutability.constant;
|
|
1401
|
+
let jump;
|
|
1341
1402
|
// 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
|
|
1403
|
+
// the scope copy prevents unecessary increases in the temp counter
|
|
1404
|
+
const [comp] = ref["=="](innerScope.copy(), test);
|
|
1347
1405
|
if (comp instanceof LiteralValue) {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1406
|
+
// whether other cases can falltrough and reach this one
|
|
1407
|
+
const noFallInto = !canFallInto;
|
|
1408
|
+
if (!comp.data) {
|
|
1409
|
+
// this case is not accessible in any way
|
|
1410
|
+
if (noFallInto)
|
|
1411
|
+
continue;
|
|
1412
|
+
includeJump = false;
|
|
1413
|
+
}
|
|
1414
|
+
else {
|
|
1415
|
+
// this case is only accessible via the comparison jump
|
|
1416
|
+
// and all the other cases will never run
|
|
1417
|
+
if (noFallInto &&
|
|
1418
|
+
onlyConstantTests &&
|
|
1419
|
+
endsWithoutFalltrough(bodyInst(), endLine)) {
|
|
1420
|
+
return [null, [...bodyInst(), endLine]];
|
|
1421
|
+
}
|
|
1422
|
+
jump = c.handle(innerScope, scase, () => [
|
|
1423
|
+
null,
|
|
1424
|
+
[new JumpInstruction(bodyAdress, EJumpKind.Always)],
|
|
1425
|
+
])[1];
|
|
1426
|
+
constantCase = true;
|
|
1427
|
+
}
|
|
1352
1428
|
}
|
|
1353
1429
|
// makes sourcemapping for the jump more specific
|
|
1354
|
-
|
|
1430
|
+
jump ??= c.handle(innerScope, scase, () => [
|
|
1355
1431
|
null,
|
|
1356
1432
|
[new JumpInstruction(bodyAdress, EJumpKind.StrictEqual, ref, test)],
|
|
1357
|
-
]);
|
|
1358
|
-
|
|
1359
|
-
|
|
1433
|
+
])[1];
|
|
1434
|
+
if (includeJump)
|
|
1435
|
+
caseJumps.push(...testInst, ...jump);
|
|
1436
|
+
if (includeBody)
|
|
1437
|
+
inst.push(bodyLine, ...bodyInst());
|
|
1360
1438
|
}
|
|
1361
1439
|
// ensures that the processor exits
|
|
1362
1440
|
// the switch if no cases match
|
|
@@ -1371,12 +1449,34 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1371
1449
|
[
|
|
1372
1450
|
...refInst,
|
|
1373
1451
|
...caseJumps,
|
|
1374
|
-
...(caseJumps.length > 0 ? [defaultJump] : []),
|
|
1452
|
+
...(caseJumps.length > 0 && !constantCase ? [defaultJump] : []),
|
|
1375
1453
|
...inst,
|
|
1376
1454
|
endLine,
|
|
1377
1455
|
],
|
|
1378
1456
|
];
|
|
1379
|
-
};
|
|
1457
|
+
};
|
|
1458
|
+
function endsWithoutFalltrough(inst, endLine) {
|
|
1459
|
+
if (inst.length === 0)
|
|
1460
|
+
return true;
|
|
1461
|
+
for (let i = inst.length - 1; i >= 0; i--) {
|
|
1462
|
+
const instruction = inst[i];
|
|
1463
|
+
// this means that there is an instruction trying to reference
|
|
1464
|
+
// the final function `set @counter` instruction
|
|
1465
|
+
// of course this generates an unecessary
|
|
1466
|
+
// `set @counter` in cases where a control flow
|
|
1467
|
+
// structure contains a fallback return statement
|
|
1468
|
+
// TODO: fix this with static analysis
|
|
1469
|
+
if (instruction instanceof AddressResolver)
|
|
1470
|
+
return false;
|
|
1471
|
+
if (instruction.hidden)
|
|
1472
|
+
continue;
|
|
1473
|
+
return (instruction instanceof SetCounterInstruction ||
|
|
1474
|
+
instruction.intent === EInstIntent.return ||
|
|
1475
|
+
(instruction instanceof BreakInstruction &&
|
|
1476
|
+
endLine.bonds.includes(instruction.address)));
|
|
1477
|
+
}
|
|
1478
|
+
return false;
|
|
1479
|
+
}
|
|
1380
1480
|
|
|
1381
1481
|
const WhileStatement = (c, scope, node) => {
|
|
1382
1482
|
const lines = [];
|
|
@@ -1812,7 +1912,9 @@ const ObjectPattern = (c, scope, node) => {
|
|
|
1812
1912
|
});
|
|
1813
1913
|
}
|
|
1814
1914
|
return [new DestructuringValue(members), inst];
|
|
1815
|
-
};
|
|
1915
|
+
};
|
|
1916
|
+
// the mlog runtime already does this check for us
|
|
1917
|
+
const OptionalMemberExpression = MemberExpression;
|
|
1816
1918
|
|
|
1817
1919
|
const TemplateLiteral = () => {
|
|
1818
1920
|
throw new CompilerError("Template strings are currently unavailable. To inline mlog code use the asm function.");
|
|
@@ -1889,11 +1991,13 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1889
1991
|
UnaryExpression: UnaryExpression,
|
|
1890
1992
|
UpdateExpression: UpdateExpression,
|
|
1891
1993
|
ConditionalExpression: ConditionalExpression,
|
|
1994
|
+
SequenceExpression: SequenceExpression,
|
|
1892
1995
|
Identifier: Identifier,
|
|
1893
1996
|
ExpressionStatement: ExpressionStatement,
|
|
1894
1997
|
BreakStatement: BreakStatement,
|
|
1895
1998
|
ContinueStatement: ContinueStatement,
|
|
1896
1999
|
ReturnStatement: ReturnStatement,
|
|
2000
|
+
EmptyStatement: EmptyStatement,
|
|
1897
2001
|
LabeledStatement: LabeledStatement,
|
|
1898
2002
|
IfStatement: IfStatement,
|
|
1899
2003
|
SwitchStatement: SwitchStatement,
|
|
@@ -1912,6 +2016,7 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1912
2016
|
MemberExpression: MemberExpression,
|
|
1913
2017
|
ArrayPattern: ArrayPattern,
|
|
1914
2018
|
ObjectPattern: ObjectPattern,
|
|
2019
|
+
OptionalMemberExpression: OptionalMemberExpression,
|
|
1915
2020
|
TemplateLiteral: TemplateLiteral,
|
|
1916
2021
|
BlockStatement: BlockStatement,
|
|
1917
2022
|
File: File,
|