mlogjs 0.4.1 → 0.4.2

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/Scope.d.ts CHANGED
@@ -11,6 +11,7 @@ export declare class Scope implements IScope {
11
11
  break: AddressResolver;
12
12
  continue: AddressResolver;
13
13
  function: IFunctionValue;
14
+ label?: string;
14
15
  constructor(values: Record<string, IValueOwner | null>, parent?: IScope | null, stacked?: boolean, ntemp?: number, name?: string, inst?: IInstruction[]);
15
16
  copy(): IScope;
16
17
  createScope(): IScope;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.cjs","sources":["../src/bin.ts"],"sourcesContent":[null],"names":["yargs","hideBin","path","existsSync","Compiler","readFileSync","chalk","resolve","highlight","writeFileSync","parse","join"],"mappings":"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"}
@@ -3,3 +3,4 @@ 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 LabeledStatement: THandler<null>;
package/dist/index.cjs CHANGED
@@ -138,7 +138,7 @@ const arithmeticAssignmentOperators = [
138
138
  "-=",
139
139
  "/=",
140
140
  ];
141
- const logicalAssignmentOperators = ["&&=", "||="];
141
+ const logicalAssignmentOperators = ["&&=", "||=", "??="];
142
142
  const bitwiseAssignmentOperators = [
143
143
  "<<=",
144
144
  ">>=",
@@ -231,8 +231,22 @@ class SetInstruction extends InstructionBase {
231
231
  constructor(store, value) {
232
232
  super("set", store, value);
233
233
  }
234
+ get store() {
235
+ return this.args[1];
236
+ }
237
+ get value() {
238
+ return this.args[2];
239
+ }
234
240
  get hidden() {
235
- return this._hidden || !this.args[1].owner;
241
+ const { store, value } = this;
242
+ return (this._hidden ||
243
+ // assignment to discarded value
244
+ !store.owner ||
245
+ // self assignment of a store
246
+ (!!store.owner &&
247
+ store instanceof StoreValue &&
248
+ value instanceof StoreValue &&
249
+ store.owner === value.owner));
236
250
  }
237
251
  }
238
252
 
@@ -341,6 +355,34 @@ class BaseValue extends VoidValue {
341
355
  const temp = new StoreValue(scope);
342
356
  return [temp, [...inst, new OperationInstruction("not", temp, that, null)]];
343
357
  }
358
+ // requires special handling
359
+ // the handler should give an object value to allow the lazy evaluation
360
+ "??"(scope, other) {
361
+ const [left, leftInst] = this.eval(scope);
362
+ const nullLiteral = new LiteralValue(null);
363
+ const endAdress = new LiteralValue(null);
364
+ const [nullTest] = left["=="](scope, nullLiteral);
365
+ if (nullTest instanceof LiteralValue) {
366
+ if (nullTest.data)
367
+ return other.eval(scope);
368
+ else
369
+ return [left, leftInst];
370
+ }
371
+ const [right, rightInst] = other.eval(scope);
372
+ const result = new StoreValue(scope);
373
+ result.ensureOwned();
374
+ return [
375
+ result,
376
+ [
377
+ ...leftInst,
378
+ ...result["="](scope, left)[1],
379
+ new JumpInstruction(endAdress, EJumpKind.NotEqual, result, nullLiteral),
380
+ ...rightInst,
381
+ ...result["="](scope, right)[1],
382
+ new AddressResolver(endAdress),
383
+ ],
384
+ ];
385
+ }
344
386
  }
345
387
  const operatorMap$1 = {
346
388
  "==": "equal",
@@ -397,6 +439,7 @@ const assignmentToBinary = {
397
439
  "<<=": "<<",
398
440
  "&&=": "&&",
399
441
  "||=": "||",
442
+ "??=": "??",
400
443
  };
401
444
  for (const op in assignmentToBinary) {
402
445
  BaseValue.prototype[op] = function (scope, value) {
@@ -1002,35 +1045,26 @@ const BinaryExpression = LRExpression;
1002
1045
  const LogicalExpression = (c, scope, node) => {
1003
1046
  if (node.operator !== "??")
1004
1047
  return LRExpression(c, scope, node);
1005
- const nullLiteral = new LiteralValue(null);
1006
- const endAdress = new LiteralValue(null);
1048
+ const other = lazyValue({
1049
+ eval: scope => c.handleEval(scope, node.right),
1050
+ consume: scope => c.handleConsume(scope, node.right),
1051
+ });
1007
1052
  const [left, leftInst] = c.handleEval(scope, node.left);
1008
- const [nullTest] = left["=="](scope, nullLiteral);
1009
- if (nullTest instanceof LiteralValue) {
1010
- if (nullTest.data)
1011
- return c.handleEval(scope, node.right);
1012
- else
1013
- return [left, leftInst];
1014
- }
1015
- const [right, rightInst] = c.handleEval(scope, node.right);
1016
- const result = new StoreValue(scope);
1017
- result.ensureOwned();
1018
- return [
1019
- result,
1020
- [
1021
- ...leftInst,
1022
- ...result["="](scope, left)[1],
1023
- new JumpInstruction(endAdress, EJumpKind.NotEqual, result, nullLiteral),
1024
- ...rightInst,
1025
- ...result["="](scope, right)[1],
1026
- new AddressResolver(endAdress),
1027
- ],
1028
- ];
1053
+ const [result, resultInst] = left["??"](scope, other);
1054
+ return [result, [...leftInst, ...resultInst]];
1029
1055
  };
1030
1056
  const AssignmentExpression = (c, scope, node) => {
1031
1057
  const [left, leftInst] = c.handle(scope, node.left);
1032
1058
  // doesn't need to consume because the operators already do that
1033
- const [right, rightInst] = c.handleEval(scope, node.right);
1059
+ const [right, rightInst] = node.operator !== "??="
1060
+ ? c.handleEval(scope, node.right)
1061
+ : [
1062
+ lazyValue({
1063
+ eval: scope => c.handleEval(scope, node.right),
1064
+ consume: scope => c.handleConsume(scope, node.right),
1065
+ }),
1066
+ [],
1067
+ ];
1034
1068
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1035
1069
  const [op, opInst] = left[node.operator](scope, right);
1036
1070
  return [op, [...leftInst, ...rightInst, ...opInst]];
@@ -1078,7 +1112,13 @@ const ConditionalExpression = (c, scope, node) => {
1078
1112
  new AddressResolver(endExpressionAdress),
1079
1113
  ],
1080
1114
  ];
1081
- };
1115
+ };
1116
+ function lazyValue(options) {
1117
+ const value = new VoidValue();
1118
+ value.eval = options.eval;
1119
+ value.consume = options.consume;
1120
+ return value;
1121
+ }
1082
1122
 
1083
1123
  const Identifier = (c, scope, node) => {
1084
1124
  return [scope.get(node.name), []];
@@ -1087,14 +1127,18 @@ const Identifier = (c, scope, node) => {
1087
1127
  const ExpressionStatement = (c, scope, node) => {
1088
1128
  return c.handle(scope, node.expression);
1089
1129
  };
1090
- const BreakStatement = (_, scope) => {
1130
+ const BreakStatement = (_, scope, node) => {
1131
+ const label = node.label?.name;
1132
+ const target = label ? findScopeLabel(scope, label) : scope;
1091
1133
  const addr = new LiteralValue(null);
1092
- scope.break.bind(addr);
1134
+ target.break.bind(addr);
1093
1135
  return [null, [new BreakInstruction(addr)]];
1094
1136
  };
1095
- const ContinueStatement = (_, scope) => {
1137
+ const ContinueStatement = (_, scope, node) => {
1096
1138
  const addr = new LiteralValue(null);
1097
- scope.continue.bind(addr);
1139
+ const label = node.label?.name;
1140
+ const target = label ? findScopeLabel(scope, label) : scope;
1141
+ target.continue.bind(addr);
1098
1142
  return [null, [new ContinueInstruction(addr)]];
1099
1143
  };
1100
1144
  const ReturnStatement = (c, scope, node) => {
@@ -1103,7 +1147,24 @@ const ReturnStatement = (c, scope, node) => {
1103
1147
  : [null, []];
1104
1148
  const [ret, retInst] = scope.function.return(scope, arg);
1105
1149
  return [ret, [...argInst, ...retInst]];
1106
- };
1150
+ };
1151
+ const LabeledStatement = (c, scope, node) => {
1152
+ const inner = scope.createScope();
1153
+ inner.label = node.label.name;
1154
+ const end = new LiteralValue(null);
1155
+ const endAdress = new AddressResolver(end).bindBreak(inner);
1156
+ const [, bodyInst] = c.handle(inner, node.body);
1157
+ return [null, [...bodyInst, endAdress]];
1158
+ };
1159
+ function findScopeLabel(scope, label) {
1160
+ let current = scope;
1161
+ while (current !== null) {
1162
+ if (current.label === label)
1163
+ return current;
1164
+ current = current.parent;
1165
+ }
1166
+ throw new CompilerError(`Could not find label "${label}"`);
1167
+ }
1107
1168
 
1108
1169
  const IfStatement = (c, scope, node) => {
1109
1170
  const inst = [];
@@ -1188,25 +1249,33 @@ const SwitchStatement = (c, scope, node) => {
1188
1249
  const WhileStatement = (c, scope, node) => {
1189
1250
  const lines = [];
1190
1251
  const [test, testLines] = c.handleConsume(scope, node.test);
1252
+ const childScope = scope.createScope();
1191
1253
  const startLoopAddr = new LiteralValue(null);
1192
1254
  const endLoopAddr = new LiteralValue(null);
1193
- const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1194
- const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1255
+ const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(childScope);
1256
+ const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(childScope);
1257
+ if (scope.label) {
1258
+ startLoopLine.bindContinue(scope);
1259
+ }
1195
1260
  if (test instanceof LiteralValue) {
1196
1261
  if (test.data) {
1197
- lines.push(startLoopLine, ...c.handle(scope, node.body)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
1262
+ lines.push(startLoopLine, ...c.handle(childScope, node.body)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
1198
1263
  }
1199
1264
  return [null, lines];
1200
1265
  }
1201
- lines.push(startLoopLine, ...testLines, new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(0)), ...withAlwaysRuns(c.handle(scope, node.body), false)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
1266
+ lines.push(startLoopLine, ...testLines, new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(0)), ...withAlwaysRuns(c.handle(childScope, node.body), false)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
1202
1267
  return [null, lines];
1203
1268
  };
1204
1269
  const DoWhileStatement = (c, scope, node) => {
1205
1270
  const lines = [];
1206
1271
  const [test, testLines] = c.handleConsume(scope, node.test);
1272
+ const childScope = scope.createScope();
1207
1273
  const startLoopAddr = new LiteralValue(null);
1208
- const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1209
- const [, bodyLines] = c.handle(scope, node.body);
1274
+ const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(childScope);
1275
+ if (scope.label) {
1276
+ startLoopLine.bindContinue(scope);
1277
+ }
1278
+ const [, bodyLines] = c.handle(childScope, node.body);
1210
1279
  if (test instanceof LiteralValue) {
1211
1280
  if (!test.data)
1212
1281
  return [null, [...lines, ...bodyLines]];
@@ -1224,8 +1293,8 @@ const DoWhileStatement = (c, scope, node) => {
1224
1293
  return [null, lines];
1225
1294
  };
1226
1295
 
1227
- const ForStatement = (c, scope, node) => {
1228
- scope = scope.createScope();
1296
+ const ForStatement = (c, parentScope, node) => {
1297
+ const scope = parentScope.createScope();
1229
1298
  const initInst = node.init ? c.handle(scope, node.init)[1] : [];
1230
1299
  const [test, testLines] = node.test
1231
1300
  ? c.handleConsume(scope, node.test)
@@ -1235,6 +1304,9 @@ const ForStatement = (c, scope, node) => {
1235
1304
  const endLoopAddr = new LiteralValue(null);
1236
1305
  const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1237
1306
  const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1307
+ if (parentScope.label) {
1308
+ startLoopLine.bindContinue(parentScope);
1309
+ }
1238
1310
  return [
1239
1311
  null,
1240
1312
  [
@@ -1657,6 +1729,7 @@ var handlers = /*#__PURE__*/Object.freeze({
1657
1729
  BreakStatement: BreakStatement,
1658
1730
  ContinueStatement: ContinueStatement,
1659
1731
  ReturnStatement: ReturnStatement,
1732
+ LabeledStatement: LabeledStatement,
1660
1733
  IfStatement: IfStatement,
1661
1734
  SwitchStatement: SwitchStatement,
1662
1735
  WhileStatement: WhileStatement,
@@ -1689,7 +1762,7 @@ class MacroFunction extends VoidValue {
1689
1762
  constructor(fn) {
1690
1763
  super();
1691
1764
  this.macro = true;
1692
- this.constant = true;
1765
+ this.mutability = EMutability.constant;
1693
1766
  this.fn = fn;
1694
1767
  }
1695
1768
  call(scope, args) {
@@ -1724,8 +1797,23 @@ const mathOperations = {
1724
1797
  sqrt: a => Math.sqrt(a),
1725
1798
  rand: null,
1726
1799
  };
1727
- function createMacroMathOperations() {
1728
- const macroMathOperations = {};
1800
+ function mathConstant(scope, name) {
1801
+ return new ValueOwner({
1802
+ scope,
1803
+ constant: true,
1804
+ name,
1805
+ value: assign(new StoreValue(scope), {
1806
+ mutability: EMutability.constant,
1807
+ }),
1808
+ }).value;
1809
+ }
1810
+ function createMacroMathOperations(scope) {
1811
+ const macroMathOperations = {
1812
+ PI: mathConstant(scope, "@pi"),
1813
+ E: mathConstant(scope, "@e"),
1814
+ degToRad: mathConstant(scope, "@degToRad"),
1815
+ radToDeg: mathConstant(scope, "@radToDeg"),
1816
+ };
1729
1817
  for (const key in mathOperations) {
1730
1818
  const fn = mathOperations[key];
1731
1819
  macroMathOperations[key] = new MacroFunction((scope, a, b) => {
@@ -1750,8 +1838,8 @@ function createMacroMathOperations() {
1750
1838
  return macroMathOperations;
1751
1839
  }
1752
1840
  class MlogMath extends ObjectValue {
1753
- constructor() {
1754
- super(createMacroMathOperations());
1841
+ constructor(scope) {
1842
+ super(createMacroMathOperations(scope));
1755
1843
  }
1756
1844
  }
1757
1845
  // op angle result a b
@@ -2425,6 +2513,7 @@ class SetRule extends ObjectValue {
2425
2513
  solarMultiplier: { args: ["multiplier"] },
2426
2514
  buildSpeed: { args: ["team", "multiplier"] },
2427
2515
  unitBuildSpeed: { args: ["team", "multiplier"] },
2516
+ unitCost: { args: ["team", "multiplier"] },
2428
2517
  unitDamage: { args: ["team", "multiplier"] },
2429
2518
  blockHealth: { args: ["team", "multiplier"] },
2430
2519
  blockDamage: { args: ["team", "multiplier"] },
@@ -2444,6 +2533,7 @@ class SetRule extends ObjectValue {
2444
2533
  }
2445
2534
  case "buildSpeed":
2446
2535
  case "unitBuildSpeed":
2536
+ case "unitCost":
2447
2537
  case "unitDamage":
2448
2538
  case "blockHealth":
2449
2539
  case "blockDamage":
@@ -2451,7 +2541,7 @@ class SetRule extends ObjectValue {
2451
2541
  case "rtsMinSquad": {
2452
2542
  const [team, value] = args;
2453
2543
  params[1] = team;
2454
- params[2] = value;
2544
+ params[0] = value;
2455
2545
  break;
2456
2546
  }
2457
2547
  default:
@@ -2812,7 +2902,7 @@ function initScope(scope) {
2812
2902
  scope.hardSet("getVar", new GetGlobal(EMutability.mutable));
2813
2903
  scope.hardSet("concat", new Concat());
2814
2904
  scope.hardSet("asm", new Asm());
2815
- scope.hardSet("Math", new MlogMath());
2905
+ scope.hardSet("Math", new MlogMath(scope));
2816
2906
  scope.hardSet("Memory", new MemoryBuilder());
2817
2907
  // commands
2818
2908
  scope.hardSet("draw", new Draw());
@@ -2952,7 +3042,7 @@ class Compiler {
2952
3042
  */
2953
3043
  handleMany(scope, nodes, handler) {
2954
3044
  const lines = [];
2955
- for (const node of nodes) {
3045
+ for (const node of hoistedFunctionNodes(nodes)) {
2956
3046
  const [, nodeLines] = this.handle(scope, node, handler && (() => handler(node)));
2957
3047
  lines.push(...nodeLines);
2958
3048
  }
@@ -2982,6 +3072,20 @@ function hideRedundantJumps(inst) {
2982
3072
  current = inst[searchIndex];
2983
3073
  }
2984
3074
  }
3075
+ }
3076
+ function* hoistedFunctionNodes(nodes) {
3077
+ // sorting is O(n long n) while this is just O(n)
3078
+ // besides, it's better not to modify the node array
3079
+ for (const node of nodes) {
3080
+ if (node.type === "FunctionDeclaration") {
3081
+ yield node;
3082
+ }
3083
+ }
3084
+ for (const node of nodes) {
3085
+ if (node.type !== "FunctionDeclaration") {
3086
+ yield node;
3087
+ }
3088
+ }
2985
3089
  }
2986
3090
 
2987
3091
  exports.Compiler = Compiler;