mlogjs 0.4.8 → 0.4.10
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/Compiler.d.ts +1 -1
- package/dist/CompilerError.d.ts +1 -1
- package/dist/Scope.d.ts +6 -1
- 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 +177 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +177 -24
- package/dist/index.mjs.map +1 -1
- package/dist/macros/Function.d.ts +1 -1
- package/dist/macros/Unchecked.d.ts +7 -0
- package/dist/operators.d.ts +9 -8
- package/dist/types.d.ts +22 -5
- package/dist/utils/general.d.ts +2 -0
- package/dist/utils/value.d.ts +1 -1
- package/dist/values/BaseValue.d.ts +1 -0
- package/dist/values/DestructuringValue.d.ts +1 -1
- package/dist/values/FunctionValue.d.ts +1 -1
- package/dist/values/StoreValue.d.ts +4 -0
- package/package.json +1 -1
package/dist/Compiler.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CompilerError } from "./CompilerError";
|
|
2
2
|
import { es, IScope, IValue, TEOutput, THandler, TValueInstructions } from "./types";
|
|
3
|
-
|
|
3
|
+
type THandlerMap = {
|
|
4
4
|
[k in es.Node["type"]]?: THandler<IValue | null>;
|
|
5
5
|
};
|
|
6
6
|
export interface CompilerOptions {
|
package/dist/CompilerError.d.ts
CHANGED
package/dist/Scope.d.ts
CHANGED
|
@@ -7,12 +7,14 @@ export declare class Scope implements IScope {
|
|
|
7
7
|
ntemp: number;
|
|
8
8
|
name: string;
|
|
9
9
|
inst: IInstruction[];
|
|
10
|
+
operationCache: Record<string, IValue>;
|
|
11
|
+
cacheDependencies: Record<string, string[]>;
|
|
10
12
|
data: Record<string, IValue | null>;
|
|
11
13
|
break: AddressResolver;
|
|
12
14
|
continue: AddressResolver;
|
|
13
15
|
function: IFunctionValue;
|
|
14
16
|
label?: string;
|
|
15
|
-
constructor(values: Record<string, IValue | null>, parent?: IScope | null, stacked?: boolean, ntemp?: number, name?: string, inst?: IInstruction[]);
|
|
17
|
+
constructor(values: Record<string, IValue | null>, parent?: IScope | null, stacked?: boolean, ntemp?: number, name?: string, inst?: IInstruction[], operationCache?: Record<string, IValue>, cacheDependencies?: Record<string, string[]>);
|
|
16
18
|
copy(): IScope;
|
|
17
19
|
createScope(): IScope;
|
|
18
20
|
createFunction(name: string, stacked?: boolean): IScope;
|
|
@@ -22,4 +24,7 @@ export declare class Scope implements IScope {
|
|
|
22
24
|
hardSet<T extends IValue>(name: string, value: T): T;
|
|
23
25
|
make(identifier: string, name: string): SenseableValue;
|
|
24
26
|
makeTempName(): string;
|
|
27
|
+
addCachedOperation(op: string, result: IValue, left: IValue, right?: IValue | undefined): void;
|
|
28
|
+
getCachedOperation(op: string, left: IValue, right?: IValue | undefined): IValue | undefined;
|
|
29
|
+
clearDependentCache(value: IValue): void;
|
|
25
30
|
}
|
|
@@ -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
|
@@ -167,7 +167,19 @@ const unaryOperators = [
|
|
|
167
167
|
];
|
|
168
168
|
const updateOperators = ["++", "--"];
|
|
169
169
|
const singleOperators = [...unaryOperators, ...updateOperators];
|
|
170
|
-
const operators = [...leftRightOperators, ...singleOperators];
|
|
170
|
+
const operators = [...leftRightOperators, ...singleOperators];
|
|
171
|
+
const orderIndependentOperators = [
|
|
172
|
+
"!=",
|
|
173
|
+
"!==",
|
|
174
|
+
"&&",
|
|
175
|
+
"&",
|
|
176
|
+
"*",
|
|
177
|
+
"+",
|
|
178
|
+
"==",
|
|
179
|
+
"===",
|
|
180
|
+
"|",
|
|
181
|
+
"||",
|
|
182
|
+
];
|
|
171
183
|
|
|
172
184
|
class VoidValue {
|
|
173
185
|
constructor() {
|
|
@@ -198,18 +210,18 @@ for (const key of operators) {
|
|
|
198
210
|
}
|
|
199
211
|
|
|
200
212
|
class InstructionBase {
|
|
201
|
-
constructor(...args) {
|
|
202
|
-
this.intent = EInstIntent.none;
|
|
203
|
-
this.alwaysRuns = true;
|
|
204
|
-
this._hidden = false;
|
|
205
|
-
this.args = args;
|
|
206
|
-
}
|
|
207
213
|
get hidden() {
|
|
208
214
|
return this._hidden;
|
|
209
215
|
}
|
|
210
216
|
set hidden(value) {
|
|
211
217
|
this._hidden = value;
|
|
212
218
|
}
|
|
219
|
+
constructor(...args) {
|
|
220
|
+
this.intent = EInstIntent.none;
|
|
221
|
+
this.alwaysRuns = true;
|
|
222
|
+
this._hidden = false;
|
|
223
|
+
this.args = args;
|
|
224
|
+
}
|
|
213
225
|
resolve(_i) { }
|
|
214
226
|
toString() {
|
|
215
227
|
return this.args.filter(arg => arg).join(" ");
|
|
@@ -283,6 +295,11 @@ function camelToDashCase(name) {
|
|
|
283
295
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
284
296
|
function assign(obj, props) {
|
|
285
297
|
return Object.assign(obj, props);
|
|
298
|
+
}
|
|
299
|
+
/** Lazily computes and caches an expression */
|
|
300
|
+
function lazy(fn) {
|
|
301
|
+
let value;
|
|
302
|
+
return () => (value ??= fn());
|
|
286
303
|
}
|
|
287
304
|
|
|
288
305
|
function appendSourceLocations(valueInst, node) {
|
|
@@ -422,14 +439,14 @@ class EndInstruction extends InstructionBase {
|
|
|
422
439
|
}
|
|
423
440
|
|
|
424
441
|
class AddressResolver extends InstructionBase {
|
|
425
|
-
constructor(...bonds) {
|
|
426
|
-
super();
|
|
427
|
-
this.bonds = bonds;
|
|
428
|
-
}
|
|
429
442
|
get hidden() {
|
|
430
443
|
return true;
|
|
431
444
|
}
|
|
432
445
|
set hidden(value) { }
|
|
446
|
+
constructor(...bonds) {
|
|
447
|
+
super();
|
|
448
|
+
this.bonds = bonds;
|
|
449
|
+
}
|
|
433
450
|
resolve(i) {
|
|
434
451
|
for (const literal of this.bonds)
|
|
435
452
|
literal.data = i;
|
|
@@ -545,12 +562,16 @@ class BaseValue extends VoidValue {
|
|
|
545
562
|
],
|
|
546
563
|
];
|
|
547
564
|
}
|
|
565
|
+
"!=="(scope, other, out) {
|
|
566
|
+
const [equal, equalInst] = this["==="](scope, other);
|
|
567
|
+
const [result, resultInst] = equal["!"](scope, out);
|
|
568
|
+
return [result, [...equalInst, ...resultInst]];
|
|
569
|
+
}
|
|
548
570
|
}
|
|
549
571
|
const operatorMap$1 = {
|
|
550
572
|
"==": "equal",
|
|
551
573
|
"===": "strictEqual",
|
|
552
574
|
"!=": "notEqual",
|
|
553
|
-
"!==": "notEqual",
|
|
554
575
|
"<": "lessThan",
|
|
555
576
|
">": "greaterThan",
|
|
556
577
|
"<=": "lessThanEq",
|
|
@@ -637,6 +658,7 @@ class LiteralValue extends BaseValue {
|
|
|
637
658
|
super();
|
|
638
659
|
this.mutability = EMutability.constant;
|
|
639
660
|
this.data = data;
|
|
661
|
+
this.name = this.toString();
|
|
640
662
|
}
|
|
641
663
|
eval(_scope) {
|
|
642
664
|
return [this, []];
|
|
@@ -760,12 +782,40 @@ class StoreValue extends BaseValue {
|
|
|
760
782
|
const [evalValue, evalInst] = value.eval(scope, this);
|
|
761
783
|
return [this, [...evalInst, new SetInstruction(this, evalValue)]];
|
|
762
784
|
}
|
|
785
|
+
"=="(scope, value, out) {
|
|
786
|
+
if (compareStores(this, value))
|
|
787
|
+
return [new LiteralValue(1), []];
|
|
788
|
+
return super["=="](scope, value, out);
|
|
789
|
+
}
|
|
790
|
+
"==="(scope, value, out) {
|
|
791
|
+
if (compareStores(this, value))
|
|
792
|
+
return [new LiteralValue(1), []];
|
|
793
|
+
return super["==="](scope, value, out);
|
|
794
|
+
}
|
|
795
|
+
"!="(scope, value, out) {
|
|
796
|
+
if (compareStores(this, value))
|
|
797
|
+
return [new LiteralValue(0), []];
|
|
798
|
+
return super["!="](scope, value, out);
|
|
799
|
+
}
|
|
800
|
+
"!=="(scope, value, out) {
|
|
801
|
+
if (compareStores(this, value))
|
|
802
|
+
return [new LiteralValue(0), []];
|
|
803
|
+
return super["!=="](scope, value, out);
|
|
804
|
+
}
|
|
763
805
|
eval(_scope) {
|
|
764
806
|
return [this, []];
|
|
765
807
|
}
|
|
766
808
|
toString() {
|
|
767
809
|
return this.name;
|
|
768
810
|
}
|
|
811
|
+
}
|
|
812
|
+
function compareStores(left, right) {
|
|
813
|
+
return (left === right ||
|
|
814
|
+
// prevents a store from being equal to a senseable value
|
|
815
|
+
(right instanceof left.constructor &&
|
|
816
|
+
right.mutability === EMutability.constant &&
|
|
817
|
+
left.mutability === EMutability.constant &&
|
|
818
|
+
right.name === left.name));
|
|
769
819
|
}
|
|
770
820
|
|
|
771
821
|
class ObjectValue extends VoidValue {
|
|
@@ -947,16 +997,18 @@ class LazyValue extends VoidValue {
|
|
|
947
997
|
}
|
|
948
998
|
|
|
949
999
|
class Scope {
|
|
950
|
-
constructor(values, parent = null, stacked = false, ntemp = 0, name = "", inst = []) {
|
|
1000
|
+
constructor(values, parent = null, stacked = false, ntemp = 0, name = "", inst = [], operationCache = {}, cacheDependencies = {}) {
|
|
951
1001
|
this.parent = parent;
|
|
952
1002
|
this.stacked = stacked;
|
|
953
1003
|
this.ntemp = ntemp;
|
|
954
1004
|
this.name = name;
|
|
955
1005
|
this.inst = inst;
|
|
1006
|
+
this.operationCache = operationCache;
|
|
1007
|
+
this.cacheDependencies = cacheDependencies;
|
|
956
1008
|
this.data = values;
|
|
957
1009
|
}
|
|
958
1010
|
copy() {
|
|
959
|
-
const scope = new Scope({ ...this.data }, this.parent, this.stacked, this.ntemp, this.name, this.inst);
|
|
1011
|
+
const scope = new Scope({ ...this.data }, this.parent, this.stacked, this.ntemp, this.name, this.inst, { ...this.operationCache }, { ...this.cacheDependencies });
|
|
960
1012
|
scope.break = this.break;
|
|
961
1013
|
scope.continue = this.continue;
|
|
962
1014
|
scope.function = this.function;
|
|
@@ -965,6 +1017,8 @@ class Scope {
|
|
|
965
1017
|
createScope() {
|
|
966
1018
|
const scope = this.copy();
|
|
967
1019
|
scope.data = {};
|
|
1020
|
+
scope.operationCache = {};
|
|
1021
|
+
scope.cacheDependencies = {};
|
|
968
1022
|
scope.parent = this;
|
|
969
1023
|
return scope;
|
|
970
1024
|
}
|
|
@@ -1010,6 +1064,46 @@ class Scope {
|
|
|
1010
1064
|
this.ntemp++;
|
|
1011
1065
|
return result;
|
|
1012
1066
|
}
|
|
1067
|
+
addCachedOperation(op, result, left, right) {
|
|
1068
|
+
if (!left.name || !result.name || (right && !right.name))
|
|
1069
|
+
return;
|
|
1070
|
+
const id = formatCacheId(op, left, right);
|
|
1071
|
+
this.operationCache[id] = result;
|
|
1072
|
+
this.clearDependentCache(result);
|
|
1073
|
+
addCacheDependency(this, left.name, id);
|
|
1074
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1075
|
+
if (right)
|
|
1076
|
+
addCacheDependency(this, right.name, id);
|
|
1077
|
+
addCacheDependency(this, result.name, id);
|
|
1078
|
+
}
|
|
1079
|
+
getCachedOperation(op, left, right) {
|
|
1080
|
+
const id = formatCacheId(op, left, right);
|
|
1081
|
+
const result = this.operationCache[id];
|
|
1082
|
+
if (result)
|
|
1083
|
+
return result;
|
|
1084
|
+
if (this.parent)
|
|
1085
|
+
return this.parent.getCachedOperation(op, left, right);
|
|
1086
|
+
}
|
|
1087
|
+
clearDependentCache(value) {
|
|
1088
|
+
if (!value.name)
|
|
1089
|
+
return;
|
|
1090
|
+
const dependents = this.cacheDependencies[value.name];
|
|
1091
|
+
if (dependents) {
|
|
1092
|
+
for (const id of dependents) {
|
|
1093
|
+
delete this.operationCache[id];
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
if (this.parent)
|
|
1097
|
+
this.parent.clearDependentCache(value);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
function formatCacheId(op, left, right) {
|
|
1101
|
+
if (right)
|
|
1102
|
+
return `{${op}}{${left.name}}{${right.name}}`;
|
|
1103
|
+
return `{${op}}{${left.name}}`;
|
|
1104
|
+
}
|
|
1105
|
+
function addCacheDependency(scope, name, id) {
|
|
1106
|
+
(scope.cacheDependencies[name] ??= []).push(id);
|
|
1013
1107
|
}
|
|
1014
1108
|
|
|
1015
1109
|
const Program = (c, scope, node) => {
|
|
@@ -1185,7 +1279,21 @@ const BooleanLiteral = (_c, scope, node) => [new LiteralValue(+node.value), []];
|
|
|
1185
1279
|
const LRExpression = (c, scope, node, out) => {
|
|
1186
1280
|
const [left, leftInst] = c.handleEval(scope, node.left);
|
|
1187
1281
|
const [right, rightInst] = c.handleEval(scope, node.right);
|
|
1282
|
+
if (!(left instanceof LiteralValue) || !(right instanceof LiteralValue)) {
|
|
1283
|
+
const cachedResult = scope.getCachedOperation(node.operator, left, right);
|
|
1284
|
+
if (cachedResult)
|
|
1285
|
+
return [cachedResult, [...leftInst, ...rightInst]];
|
|
1286
|
+
// because a * b is the same as b * a
|
|
1287
|
+
if (orderIndependentOperators.includes(node.operator)) {
|
|
1288
|
+
const cachedResult = scope.getCachedOperation(node.operator, right, left);
|
|
1289
|
+
if (cachedResult)
|
|
1290
|
+
return [cachedResult, [...leftInst, ...rightInst]];
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1188
1293
|
const [op, opInst] = left[node.operator](scope, right, out);
|
|
1294
|
+
if (!(op instanceof LiteralValue)) {
|
|
1295
|
+
scope.addCachedOperation(node.operator, op, left, right);
|
|
1296
|
+
}
|
|
1189
1297
|
return [op, [...leftInst, ...rightInst, ...opInst]];
|
|
1190
1298
|
};
|
|
1191
1299
|
const BinaryExpression = LRExpression;
|
|
@@ -1207,18 +1315,26 @@ const AssignmentExpression = (c, scope, node) => {
|
|
|
1207
1315
|
];
|
|
1208
1316
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1209
1317
|
const [op, opInst] = left[node.operator](scope, right);
|
|
1318
|
+
if (left)
|
|
1319
|
+
scope.clearDependentCache(left);
|
|
1210
1320
|
return [op, [...leftInst, ...rightInst, ...opInst]];
|
|
1211
1321
|
};
|
|
1212
1322
|
const UnaryExpression = (c, scope, { argument, operator }, out) => {
|
|
1213
1323
|
const [arg, argInst] = c.handleEval(scope, argument);
|
|
1324
|
+
const cachedResult = scope.getCachedOperation(operator, arg);
|
|
1325
|
+
if (cachedResult)
|
|
1326
|
+
return [cachedResult, argInst];
|
|
1214
1327
|
const operatorId = operator == "+" || operator == "-" ? `u${operator}` : operator;
|
|
1215
1328
|
if (operatorId === "throw")
|
|
1216
1329
|
throw new CompilerError("throw operator is not supported");
|
|
1217
1330
|
const [op, opInst] = arg[operatorId](scope, out);
|
|
1331
|
+
scope.addCachedOperation(operator, op, arg);
|
|
1218
1332
|
return [op, [...argInst, ...opInst]];
|
|
1219
1333
|
};
|
|
1220
1334
|
const UpdateExpression = (c, scope, { argument, operator, prefix }, out) => {
|
|
1221
1335
|
const [arg, argInst] = c.handle(scope, argument);
|
|
1336
|
+
if (arg)
|
|
1337
|
+
scope.clearDependentCache(arg);
|
|
1222
1338
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1223
1339
|
const [op, opInst] = arg[operator](scope, prefix, out);
|
|
1224
1340
|
return [op, [...argInst, ...opInst]];
|
|
@@ -1249,6 +1365,17 @@ const ConditionalExpression = (c, scope, node, out) => {
|
|
|
1249
1365
|
new AddressResolver(endExpressionAdress),
|
|
1250
1366
|
],
|
|
1251
1367
|
];
|
|
1368
|
+
};
|
|
1369
|
+
const SequenceExpression = (c, scope, node, out) => {
|
|
1370
|
+
const { expressions } = node;
|
|
1371
|
+
const inst = [];
|
|
1372
|
+
// compute every expression except the last one
|
|
1373
|
+
for (let i = 0; i < expressions.length - 1; i++) {
|
|
1374
|
+
const [, exprInst] = c.handleEval(scope, expressions[i], discardedName);
|
|
1375
|
+
inst.push(...exprInst);
|
|
1376
|
+
}
|
|
1377
|
+
const [value, valueInst] = c.handleEval(scope, expressions[expressions.length - 1], out);
|
|
1378
|
+
return [value, [...inst, ...valueInst]];
|
|
1252
1379
|
};
|
|
1253
1380
|
|
|
1254
1381
|
const Identifier = (c, scope, node) => {
|
|
@@ -1280,6 +1407,7 @@ const ReturnStatement = (c, scope, node, out) => {
|
|
|
1280
1407
|
const [ret, retInst] = scope.function.return(scope, arg, out);
|
|
1281
1408
|
return [ret, [...argInst, ...retInst]];
|
|
1282
1409
|
};
|
|
1410
|
+
const EmptyStatement = () => [null, []];
|
|
1283
1411
|
const LabeledStatement = (c, scope, node) => {
|
|
1284
1412
|
const inner = scope.createScope();
|
|
1285
1413
|
inner.label = node.label.name;
|
|
@@ -1309,9 +1437,12 @@ const IfStatement = (c, scope, node) => {
|
|
|
1309
1437
|
return [null, inst];
|
|
1310
1438
|
}
|
|
1311
1439
|
const endIfAddr = new LiteralValue(null);
|
|
1312
|
-
inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(0)), ...withAlwaysRuns(c.handle(scope, node.consequent), false)[1]
|
|
1313
|
-
|
|
1314
|
-
|
|
1440
|
+
inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(0)), ...withAlwaysRuns(c.handle(scope, node.consequent), false)[1]);
|
|
1441
|
+
if (!node.alternate) {
|
|
1442
|
+
inst.push(new AddressResolver(endIfAddr));
|
|
1443
|
+
}
|
|
1444
|
+
else {
|
|
1445
|
+
const endElseAddr = new LiteralValue(null);
|
|
1315
1446
|
inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...withAlwaysRuns(c.handle(scope, node.alternate), false)[1], new AddressResolver(endElseAddr));
|
|
1316
1447
|
}
|
|
1317
1448
|
return [null, inst];
|
|
@@ -1329,7 +1460,7 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1329
1460
|
let constantCase = false;
|
|
1330
1461
|
let onlyConstantTests = true;
|
|
1331
1462
|
for (const scase of node.cases) {
|
|
1332
|
-
const
|
|
1463
|
+
const bodyInst = lazy(() => c.handleMany(innerScope, scase.consequent)[1]);
|
|
1333
1464
|
const bodyAdress = new LiteralValue(null);
|
|
1334
1465
|
const bodyLine = new AddressResolver(bodyAdress);
|
|
1335
1466
|
const canFallInto = !endsWithoutFalltrough(inst, endLine);
|
|
@@ -1343,7 +1474,7 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1343
1474
|
])[1];
|
|
1344
1475
|
}
|
|
1345
1476
|
if (includeBody)
|
|
1346
|
-
inst.push(bodyLine, ...bodyInst);
|
|
1477
|
+
inst.push(bodyLine, ...bodyInst());
|
|
1347
1478
|
continue;
|
|
1348
1479
|
}
|
|
1349
1480
|
const [test, testInst] = c.handleEval(innerScope, scase.test);
|
|
@@ -1367,8 +1498,8 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1367
1498
|
// and all the other cases will never run
|
|
1368
1499
|
if (noFallInto &&
|
|
1369
1500
|
onlyConstantTests &&
|
|
1370
|
-
endsWithoutFalltrough(bodyInst, endLine)) {
|
|
1371
|
-
return [null, [...bodyInst, endLine]];
|
|
1501
|
+
endsWithoutFalltrough(bodyInst(), endLine)) {
|
|
1502
|
+
return [null, [...bodyInst(), endLine]];
|
|
1372
1503
|
}
|
|
1373
1504
|
jump = c.handle(innerScope, scase, () => [
|
|
1374
1505
|
null,
|
|
@@ -1385,7 +1516,7 @@ const SwitchStatement = (c, scope, node) => {
|
|
|
1385
1516
|
if (includeJump)
|
|
1386
1517
|
caseJumps.push(...testInst, ...jump);
|
|
1387
1518
|
if (includeBody)
|
|
1388
|
-
inst.push(bodyLine, ...bodyInst);
|
|
1519
|
+
inst.push(bodyLine, ...bodyInst());
|
|
1389
1520
|
}
|
|
1390
1521
|
// ensures that the processor exits
|
|
1391
1522
|
// the switch if no cases match
|
|
@@ -1863,7 +1994,9 @@ const ObjectPattern = (c, scope, node) => {
|
|
|
1863
1994
|
});
|
|
1864
1995
|
}
|
|
1865
1996
|
return [new DestructuringValue(members), inst];
|
|
1866
|
-
};
|
|
1997
|
+
};
|
|
1998
|
+
// the mlog runtime already does this check for us
|
|
1999
|
+
const OptionalMemberExpression = MemberExpression;
|
|
1867
2000
|
|
|
1868
2001
|
const TemplateLiteral = () => {
|
|
1869
2002
|
throw new CompilerError("Template strings are currently unavailable. To inline mlog code use the asm function.");
|
|
@@ -1940,11 +2073,13 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1940
2073
|
UnaryExpression: UnaryExpression,
|
|
1941
2074
|
UpdateExpression: UpdateExpression,
|
|
1942
2075
|
ConditionalExpression: ConditionalExpression,
|
|
2076
|
+
SequenceExpression: SequenceExpression,
|
|
1943
2077
|
Identifier: Identifier,
|
|
1944
2078
|
ExpressionStatement: ExpressionStatement,
|
|
1945
2079
|
BreakStatement: BreakStatement,
|
|
1946
2080
|
ContinueStatement: ContinueStatement,
|
|
1947
2081
|
ReturnStatement: ReturnStatement,
|
|
2082
|
+
EmptyStatement: EmptyStatement,
|
|
1948
2083
|
LabeledStatement: LabeledStatement,
|
|
1949
2084
|
IfStatement: IfStatement,
|
|
1950
2085
|
SwitchStatement: SwitchStatement,
|
|
@@ -1963,6 +2098,7 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1963
2098
|
MemberExpression: MemberExpression,
|
|
1964
2099
|
ArrayPattern: ArrayPattern,
|
|
1965
2100
|
ObjectPattern: ObjectPattern,
|
|
2101
|
+
OptionalMemberExpression: OptionalMemberExpression,
|
|
1966
2102
|
TemplateLiteral: TemplateLiteral,
|
|
1967
2103
|
BlockStatement: BlockStatement,
|
|
1968
2104
|
File: File,
|
|
@@ -2010,6 +2146,7 @@ const mathOperations = {
|
|
|
2010
2146
|
sqrt: a => Math.sqrt(a),
|
|
2011
2147
|
rand: null,
|
|
2012
2148
|
};
|
|
2149
|
+
const orderIndependentOperations = ["max", "min", "len"];
|
|
2013
2150
|
function createMacroMathOperations() {
|
|
2014
2151
|
const macroMathOperations = {
|
|
2015
2152
|
PI: new StoreValue("@pi", EMutability.constant),
|
|
@@ -2026,7 +2163,17 @@ function createMacroMathOperations() {
|
|
|
2026
2163
|
throw new CompilerError("Cannot do math operation with non-numerical literals.");
|
|
2027
2164
|
return [new LiteralValue(fn(a.num, b.num)), []];
|
|
2028
2165
|
}
|
|
2166
|
+
const cachedResult = scope.getCachedOperation(key, a, b);
|
|
2167
|
+
if (cachedResult)
|
|
2168
|
+
return [cachedResult, []];
|
|
2169
|
+
// max, min and len do not change if the arguments change in order
|
|
2170
|
+
if (orderIndependentOperations.includes(key)) {
|
|
2171
|
+
const cachedResult = scope.getCachedOperation(key, b, a);
|
|
2172
|
+
if (cachedResult)
|
|
2173
|
+
return [cachedResult, []];
|
|
2174
|
+
}
|
|
2029
2175
|
const temp = StoreValue.from(scope, out);
|
|
2176
|
+
scope.addCachedOperation(key, temp, a, b);
|
|
2030
2177
|
return [temp, [new OperationInstruction(key, temp, a, b)]];
|
|
2031
2178
|
}
|
|
2032
2179
|
if (fn && a instanceof LiteralValue) {
|
|
@@ -2034,8 +2181,14 @@ function createMacroMathOperations() {
|
|
|
2034
2181
|
throw new CompilerError("Cannot do math operation with non-numerical literal.");
|
|
2035
2182
|
return [new LiteralValue(fn(a.num)), []];
|
|
2036
2183
|
}
|
|
2184
|
+
const cachedResult = scope.getCachedOperation(key, a);
|
|
2185
|
+
if (cachedResult)
|
|
2186
|
+
return [cachedResult, []];
|
|
2037
2187
|
const temp = StoreValue.from(scope, out);
|
|
2038
|
-
|
|
2188
|
+
// ensures that operations like `rand` are not cached
|
|
2189
|
+
if (mathOperations[key])
|
|
2190
|
+
scope.addCachedOperation(key, temp, a);
|
|
2191
|
+
return [temp, [new OperationInstruction(key, temp, a, null)]];
|
|
2039
2192
|
});
|
|
2040
2193
|
}
|
|
2041
2194
|
return macroMathOperations;
|