mlogjs 0.4.0 → 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.
Files changed (148) hide show
  1. package/dist/Scope.d.ts +1 -0
  2. package/dist/handlers/Statements.d.ts +1 -0
  3. package/dist/index.cjs +500 -350
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.mjs +500 -350
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/instructions/SetInstruction.d.ts +2 -0
  8. package/dist/macros/Asm.d.ts +1 -2
  9. package/dist/macros/Function.d.ts +4 -4
  10. package/dist/macros/GetGlobal.d.ts +2 -2
  11. package/dist/macros/Memory.d.ts +1 -2
  12. package/dist/macros/Namespace.d.ts +1 -1
  13. package/dist/macros/Other.d.ts +1 -2
  14. package/dist/macros/commands/ApplyStatus.d.ts +1 -2
  15. package/dist/macros/commands/Control.d.ts +1 -2
  16. package/dist/macros/commands/Cutscene.d.ts +1 -2
  17. package/dist/macros/commands/Draw.d.ts +1 -2
  18. package/dist/macros/commands/DrawFlush.d.ts +1 -2
  19. package/dist/macros/commands/End.d.ts +1 -2
  20. package/dist/macros/commands/Explosion.d.ts +1 -2
  21. package/dist/macros/commands/Fetch.d.ts +1 -2
  22. package/dist/macros/commands/FlushMessage.d.ts +1 -2
  23. package/dist/macros/commands/GetBlock.d.ts +1 -2
  24. package/dist/macros/commands/GetFlag.d.ts +1 -2
  25. package/dist/macros/commands/GetLink.d.ts +1 -2
  26. package/dist/macros/commands/Lookup.d.ts +1 -2
  27. package/dist/macros/commands/PackColor.d.ts +1 -2
  28. package/dist/macros/commands/Print.d.ts +1 -2
  29. package/dist/macros/commands/PrintFlush.d.ts +1 -2
  30. package/dist/macros/commands/Radar.d.ts +1 -2
  31. package/dist/macros/commands/Sensor.d.ts +1 -2
  32. package/dist/macros/commands/SetBlock.d.ts +1 -2
  33. package/dist/macros/commands/SetFlag.d.ts +1 -2
  34. package/dist/macros/commands/SetRate.d.ts +1 -2
  35. package/dist/macros/commands/SetRule.d.ts +1 -2
  36. package/dist/macros/commands/SpawnUnit.d.ts +1 -2
  37. package/dist/macros/commands/SpawnWave.d.ts +1 -2
  38. package/dist/macros/commands/Stop.d.ts +1 -2
  39. package/dist/macros/commands/UnitBind.d.ts +1 -2
  40. package/dist/macros/commands/UnitControl.d.ts +1 -2
  41. package/dist/macros/commands/UnitLocate.d.ts +1 -2
  42. package/dist/macros/commands/UnitRadar.d.ts +1 -2
  43. package/dist/macros/commands/Wait.d.ts +1 -2
  44. package/dist/macros/util.d.ts +2 -3
  45. package/dist/operators.d.ts +4 -4
  46. package/dist/types.d.ts +3 -1
  47. package/dist/values/BaseValue.d.ts +2 -2
  48. package/dist/values/DestructuringValue.d.ts +1 -1
  49. package/dist/values/FunctionValue.d.ts +3 -4
  50. package/dist/values/LiteralValue.d.ts +3 -2
  51. package/dist/values/ObjectValue.d.ts +3 -3
  52. package/dist/values/StoreValue.d.ts +4 -2
  53. package/dist/values/VoidValue.d.ts +0 -2
  54. package/lib/commands.d.ts +306 -40
  55. package/lib/eslib/lib.es5.d.ts +23 -0
  56. package/lib/globals.d.ts +2 -3
  57. package/lib/helpers.d.ts +2 -1
  58. package/lib/kinds.d.ts +5 -2
  59. package/lib/traits.d.ts +10 -6
  60. package/package.json +2 -7
  61. package/dist/types/Compiler.d.ts +0 -39
  62. package/dist/types/CompilerError.d.ts +0 -33
  63. package/dist/types/Scope.d.ts +0 -24
  64. package/dist/types/assertions.d.ts +0 -28
  65. package/dist/types/bin.d.ts +0 -1
  66. package/dist/types/handlers/BlockStatement.d.ts +0 -2
  67. package/dist/types/handlers/CallExpression.d.ts +0 -4
  68. package/dist/types/handlers/File.d.ts +0 -2
  69. package/dist/types/handlers/ForStatement.d.ts +0 -2
  70. package/dist/types/handlers/Function.d.ts +0 -5
  71. package/dist/types/handlers/Identifier.d.ts +0 -2
  72. package/dist/types/handlers/IfStatement.d.ts +0 -2
  73. package/dist/types/handlers/Literal.d.ts +0 -5
  74. package/dist/types/handlers/Object.d.ts +0 -6
  75. package/dist/types/handlers/OperationExpressions.d.ts +0 -8
  76. package/dist/types/handlers/Program.d.ts +0 -2
  77. package/dist/types/handlers/Statements.d.ts +0 -5
  78. package/dist/types/handlers/SwitchStatement.d.ts +0 -2
  79. package/dist/types/handlers/TemplateExpression.d.ts +0 -2
  80. package/dist/types/handlers/Typescript.d.ts +0 -7
  81. package/dist/types/handlers/VariableDeclaration.d.ts +0 -3
  82. package/dist/types/handlers/WhileStatement.d.ts +0 -3
  83. package/dist/types/handlers/index.d.ts +0 -17
  84. package/dist/types/index.d.ts +0 -3
  85. package/dist/types/initScope.d.ts +0 -5
  86. package/dist/types/instructions/AddressResolver.d.ts +0 -12
  87. package/dist/types/instructions/ControlInstructions.d.ts +0 -10
  88. package/dist/types/instructions/EndInstruction.d.ts +0 -4
  89. package/dist/types/instructions/InstructionBase.d.ts +0 -14
  90. package/dist/types/instructions/JumpInstruction.d.ts +0 -16
  91. package/dist/types/instructions/OperationInstruction.d.ts +0 -5
  92. package/dist/types/instructions/SetCounterInstruction.d.ts +0 -5
  93. package/dist/types/instructions/SetInstruction.d.ts +0 -6
  94. package/dist/types/instructions/ZeroSpaceInstruction.d.ts +0 -4
  95. package/dist/types/instructions/index.d.ts +0 -9
  96. package/dist/types/macros/Asm.d.ts +0 -5
  97. package/dist/types/macros/Function.d.ts +0 -13
  98. package/dist/types/macros/GetGlobal.d.ts +0 -5
  99. package/dist/types/macros/Math.d.ts +0 -5
  100. package/dist/types/macros/Memory.d.ts +0 -5
  101. package/dist/types/macros/Namespace.d.ts +0 -13
  102. package/dist/types/macros/Other.d.ts +0 -5
  103. package/dist/types/macros/commands/ApplyStatus.d.ts +0 -5
  104. package/dist/types/macros/commands/Control.d.ts +0 -5
  105. package/dist/types/macros/commands/Cutscene.d.ts +0 -5
  106. package/dist/types/macros/commands/Draw.d.ts +0 -5
  107. package/dist/types/macros/commands/DrawFlush.d.ts +0 -5
  108. package/dist/types/macros/commands/End.d.ts +0 -5
  109. package/dist/types/macros/commands/Explosion.d.ts +0 -5
  110. package/dist/types/macros/commands/Fetch.d.ts +0 -5
  111. package/dist/types/macros/commands/FlushMessage.d.ts +0 -5
  112. package/dist/types/macros/commands/GetBlock.d.ts +0 -5
  113. package/dist/types/macros/commands/GetFlag.d.ts +0 -5
  114. package/dist/types/macros/commands/GetLink.d.ts +0 -5
  115. package/dist/types/macros/commands/Lookup.d.ts +0 -5
  116. package/dist/types/macros/commands/PackColor.d.ts +0 -5
  117. package/dist/types/macros/commands/Print.d.ts +0 -5
  118. package/dist/types/macros/commands/PrintFlush.d.ts +0 -5
  119. package/dist/types/macros/commands/Radar.d.ts +0 -7
  120. package/dist/types/macros/commands/Sensor.d.ts +0 -5
  121. package/dist/types/macros/commands/SetBlock.d.ts +0 -5
  122. package/dist/types/macros/commands/SetFlag.d.ts +0 -5
  123. package/dist/types/macros/commands/SetRate.d.ts +0 -5
  124. package/dist/types/macros/commands/SetRule.d.ts +0 -5
  125. package/dist/types/macros/commands/SpawnUnit.d.ts +0 -5
  126. package/dist/types/macros/commands/SpawnWave.d.ts +0 -5
  127. package/dist/types/macros/commands/Stop.d.ts +0 -5
  128. package/dist/types/macros/commands/UnitBind.d.ts +0 -5
  129. package/dist/types/macros/commands/UnitControl.d.ts +0 -5
  130. package/dist/types/macros/commands/UnitLocate.d.ts +0 -5
  131. package/dist/types/macros/commands/UnitRadar.d.ts +0 -5
  132. package/dist/types/macros/commands/Wait.d.ts +0 -5
  133. package/dist/types/macros/commands/index.d.ts +0 -30
  134. package/dist/types/macros/index.d.ts +0 -6
  135. package/dist/types/macros/util.d.ts +0 -18
  136. package/dist/types/operators.d.ts +0 -25
  137. package/dist/types/types.d.ts +0 -238
  138. package/dist/types/utils.d.ts +0 -47
  139. package/dist/types/values/BaseValue.d.ts +0 -9
  140. package/dist/types/values/DestructuringValue.d.ts +0 -17
  141. package/dist/types/values/FunctionValue.d.ts +0 -47
  142. package/dist/types/values/LiteralValue.d.ts +0 -13
  143. package/dist/types/values/ObjectValue.d.ts +0 -23
  144. package/dist/types/values/SenseableValue.d.ts +0 -23
  145. package/dist/types/values/StoreValue.d.ts +0 -15
  146. package/dist/types/values/ValueOwner.d.ts +0 -27
  147. package/dist/types/values/VoidValue.d.ts +0 -16
  148. package/dist/types/values/index.d.ts +0 -7
package/dist/index.mjs CHANGED
@@ -114,7 +114,7 @@ const arithmeticAssignmentOperators = [
114
114
  "-=",
115
115
  "/=",
116
116
  ];
117
- const logicalAssignmentOperators = ["&&=", "||="];
117
+ const logicalAssignmentOperators = ["&&=", "||=", "??="];
118
118
  const bitwiseAssignmentOperators = [
119
119
  "<<=",
120
120
  ">>=",
@@ -147,11 +147,10 @@ const singleOperators = [...unaryOperators, ...updateOperators];
147
147
  const operators = [...leftRightOperators, ...singleOperators];
148
148
 
149
149
  class VoidValue {
150
- constructor(scope) {
150
+ constructor() {
151
151
  this.owner = null;
152
152
  this.mutability = EMutability.mutable;
153
153
  this.macro = false;
154
- this.scope = scope;
155
154
  }
156
155
  eval(_scope) {
157
156
  throw new CompilerError(`${this} cannot eval.`);
@@ -208,8 +207,22 @@ class SetInstruction extends InstructionBase {
208
207
  constructor(store, value) {
209
208
  super("set", store, value);
210
209
  }
210
+ get store() {
211
+ return this.args[1];
212
+ }
213
+ get value() {
214
+ return this.args[2];
215
+ }
211
216
  get hidden() {
212
- return this._hidden || !this.args[1].owner;
217
+ const { store, value } = this;
218
+ return (this._hidden ||
219
+ // assignment to discarded value
220
+ !store.owner ||
221
+ // self assignment of a store
222
+ (!!store.owner &&
223
+ store instanceof StoreValue &&
224
+ value instanceof StoreValue &&
225
+ store.owner === value.owner));
213
226
  }
214
227
  }
215
228
 
@@ -288,38 +301,6 @@ class ContinueInstruction extends JumpInstruction {
288
301
  }
289
302
  }
290
303
 
291
- class ValueOwner {
292
- /**
293
- * Creates a new `ValueOwner`, if `value` is already owned,
294
- * `this` will be aliased to `value`, else `this` will own `value`
295
- */
296
- constructor({ scope, constant = false, value, identifier, name, }) {
297
- this.scope = scope;
298
- this.constant = constant;
299
- this.value = value;
300
- this.identifier = identifier;
301
- this.name = name ?? scope.makeTempName();
302
- this.persistent = !!name;
303
- this.owned = new Set();
304
- if (!value.owner?.persistent)
305
- this.own(value);
306
- }
307
- own(target) {
308
- target.owner = this;
309
- this.owned.add(target);
310
- }
311
- replace(target) {
312
- this.value.owner = null;
313
- this.owned.delete(this.value);
314
- this.value = target;
315
- this.own(target);
316
- }
317
- moveInto(owner) {
318
- this.owned.forEach(value => owner.own(value));
319
- this.owned.clear();
320
- }
321
- }
322
-
323
304
  class BaseValue extends VoidValue {
324
305
  "u-"(scope) {
325
306
  const [that, inst] = this.consume(scope);
@@ -328,7 +309,7 @@ class BaseValue extends VoidValue {
328
309
  temp,
329
310
  [
330
311
  ...inst,
331
- new OperationInstruction("sub", temp, new LiteralValue(scope, 0), that),
312
+ new OperationInstruction("sub", temp, new LiteralValue(0), that),
332
313
  ],
333
314
  ];
334
315
  }
@@ -339,7 +320,7 @@ class BaseValue extends VoidValue {
339
320
  "!"(scope) {
340
321
  const [that, inst] = this.consume(scope);
341
322
  const temp = new StoreValue(scope);
342
- const falseLiteral = new LiteralValue(scope, 0);
323
+ const falseLiteral = new LiteralValue(0);
343
324
  return [
344
325
  temp,
345
326
  [...inst, new OperationInstruction("equal", temp, that, falseLiteral)],
@@ -350,8 +331,33 @@ class BaseValue extends VoidValue {
350
331
  const temp = new StoreValue(scope);
351
332
  return [temp, [...inst, new OperationInstruction("not", temp, that, null)]];
352
333
  }
353
- ensureOwned() {
354
- this.owner ??= new ValueOwner({ scope: this.scope, value: this });
334
+ // requires special handling
335
+ // the handler should give an object value to allow the lazy evaluation
336
+ "??"(scope, other) {
337
+ const [left, leftInst] = this.eval(scope);
338
+ const nullLiteral = new LiteralValue(null);
339
+ const endAdress = new LiteralValue(null);
340
+ const [nullTest] = left["=="](scope, nullLiteral);
341
+ if (nullTest instanceof LiteralValue) {
342
+ if (nullTest.data)
343
+ return other.eval(scope);
344
+ else
345
+ return [left, leftInst];
346
+ }
347
+ const [right, rightInst] = other.eval(scope);
348
+ const result = new StoreValue(scope);
349
+ result.ensureOwned();
350
+ return [
351
+ result,
352
+ [
353
+ ...leftInst,
354
+ ...result["="](scope, left)[1],
355
+ new JumpInstruction(endAdress, EJumpKind.NotEqual, result, nullLiteral),
356
+ ...rightInst,
357
+ ...result["="](scope, right)[1],
358
+ new AddressResolver(endAdress),
359
+ ],
360
+ ];
355
361
  }
356
362
  }
357
363
  const operatorMap$1 = {
@@ -409,6 +415,7 @@ const assignmentToBinary = {
409
415
  "<<=": "<<",
410
416
  "&&=": "&&",
411
417
  "||=": "||",
418
+ "??=": "??",
412
419
  };
413
420
  for (const op in assignmentToBinary) {
414
421
  BaseValue.prototype[op] = function (scope, value) {
@@ -428,23 +435,20 @@ for (const key of updateOperators) {
428
435
  inst.push(...tempInst);
429
436
  }
430
437
  const kind = key === "++" ? "+=" : "-=";
431
- return [
432
- ret,
433
- [...inst, ...this[kind](scope, new LiteralValue(scope, 1))[1]],
434
- ];
438
+ return [ret, [...inst, ...this[kind](scope, new LiteralValue(1))[1]]];
435
439
  };
436
440
  }
437
441
 
438
442
  const literalMethods = {
439
- length: function (scope) {
443
+ length: function () {
440
444
  if (typeof this.data !== "string")
441
445
  throw new CompilerError("Length method only works on string literal values.");
442
- return new LiteralValue(scope, this.data.length);
446
+ return new LiteralValue(this.data.length);
443
447
  },
444
448
  };
445
449
  class LiteralValue extends BaseValue {
446
- constructor(scope, data) {
447
- super(scope);
450
+ constructor(data) {
451
+ super();
448
452
  this.mutability = EMutability.constant;
449
453
  this.data = data;
450
454
  }
@@ -472,9 +476,10 @@ class LiteralValue extends BaseValue {
472
476
  return 1;
473
477
  return this.data;
474
478
  }
475
- typeof(scope) {
476
- return [new LiteralValue(scope, "literal"), []];
479
+ typeof() {
480
+ return [new LiteralValue("literal"), []];
477
481
  }
482
+ ensureOwned() { }
478
483
  }
479
484
  const operatorMap = {
480
485
  "==": (a, b) => +(a == b),
@@ -506,10 +511,7 @@ for (const key in operatorMap) {
506
511
  if (!(value instanceof LiteralValue)) {
507
512
  return BaseValue.prototype[key].apply(this, [scope, value]);
508
513
  }
509
- return [
510
- new LiteralValue(scope, fn(this.data, value.data)),
511
- [],
512
- ];
514
+ return [new LiteralValue(fn(this.data, value.data)), []];
513
515
  };
514
516
  }
515
517
  const unaryOperatorMap = {
@@ -519,9 +521,9 @@ const unaryOperatorMap = {
519
521
  "u+": v => +v,
520
522
  };
521
523
  for (const key in unaryOperatorMap) {
522
- LiteralValue.prototype[key] = function (scope) {
524
+ LiteralValue.prototype[key] = function () {
523
525
  const fn = unaryOperatorMap[key];
524
- return [new LiteralValue(scope, fn(this.data)), []];
526
+ return [new LiteralValue(fn(this.data)), []];
525
527
  };
526
528
  }
527
529
 
@@ -600,17 +602,50 @@ function isTemplateObjectArray(value) {
600
602
  typeof value.data.raw.data.length.data === "number");
601
603
  }
602
604
 
605
+ class ValueOwner {
606
+ /**
607
+ * Creates a new `ValueOwner`, if `value` is already owned,
608
+ * `this` will be aliased to `value`, else `this` will own `value`
609
+ */
610
+ constructor({ scope, constant = false, value, identifier, name, }) {
611
+ this.scope = scope;
612
+ this.constant = constant;
613
+ this.value = value;
614
+ this.identifier = identifier;
615
+ this.name = name ?? scope.makeTempName();
616
+ this.persistent = !!name;
617
+ this.owned = new Set();
618
+ if (!value.owner?.persistent)
619
+ this.own(value);
620
+ }
621
+ own(target) {
622
+ target.owner = this;
623
+ this.owned.add(target);
624
+ }
625
+ replace(target) {
626
+ this.value.owner = null;
627
+ this.owned.delete(this.value);
628
+ this.value = target;
629
+ this.own(target);
630
+ }
631
+ moveInto(owner) {
632
+ this.owned.forEach(value => owner.own(value));
633
+ this.owned.clear();
634
+ }
635
+ }
636
+
603
637
  /**
604
638
  * `StoreValue` represents values unknown at compile time,
605
639
  * mostly used with mutable variables and temporary values
606
640
  */
607
641
  class StoreValue extends BaseValue {
608
642
  constructor(scope) {
609
- super(scope);
643
+ super();
644
+ this.scope = scope;
610
645
  this.mutability = EMutability.mutable;
611
646
  }
612
- typeof(scope) {
613
- return [new LiteralValue(scope, "store"), []];
647
+ typeof() {
648
+ return [new LiteralValue("store"), []];
614
649
  }
615
650
  "="(scope, value) {
616
651
  if (this.mutability !== EMutability.mutable)
@@ -637,31 +672,34 @@ class StoreValue extends BaseValue {
637
672
  this.ensureOwned();
638
673
  return [this, []];
639
674
  }
675
+ ensureOwned() {
676
+ this.owner ??= new ValueOwner({ scope: this.scope, value: this });
677
+ }
640
678
  toString() {
641
679
  return this.owner?.name ?? discardedName;
642
680
  }
643
681
  }
644
682
 
645
683
  class ObjectValue extends VoidValue {
646
- constructor(scope, data = {}) {
647
- super(scope);
684
+ constructor(data = {}) {
685
+ super();
648
686
  this.mutability = EMutability.constant;
649
687
  this.macro = true;
650
688
  this.data = data;
651
689
  }
652
- static fromArray(scope, items, intialData) {
690
+ static fromArray(items, intialData) {
653
691
  const data = {
654
692
  ...intialData,
655
- length: new LiteralValue(scope, items.length),
693
+ length: new LiteralValue(items.length),
656
694
  };
657
695
  items.forEach((item, i) => {
658
696
  if (item)
659
697
  data[i] = item;
660
698
  });
661
- return new ObjectValue(scope, data);
699
+ return new ObjectValue(data);
662
700
  }
663
- typeof(scope) {
664
- return [new LiteralValue(scope, "object"), []];
701
+ typeof() {
702
+ return [new LiteralValue("object"), []];
665
703
  }
666
704
  get(scope, key) {
667
705
  // avoids naming collisions with keys like
@@ -698,9 +736,7 @@ class ObjectValue extends VoidValue {
698
736
  return super.call(scope, args);
699
737
  return $call.call(scope, args);
700
738
  }
701
- ensureOwned() {
702
- this.owner ??= new ValueOwner({ scope: this.scope, value: this });
703
- }
739
+ ensureOwned() { }
704
740
  }
705
741
  for (const op of operators) {
706
742
  ObjectValue.prototype[op] = function (...args) {
@@ -769,8 +805,8 @@ class SenseableValue extends StoreValue {
769
805
  * each of them to their counterparts on the right hand value.
770
806
  */
771
807
  class DestructuringValue extends VoidValue {
772
- constructor(scope, members) {
773
- super(scope);
808
+ constructor(members) {
809
+ super();
774
810
  this.members = members;
775
811
  this.macro = true;
776
812
  }
@@ -957,7 +993,7 @@ const DeclareObjectPattern = (c, scope, node, kind, base) => {
957
993
  throw new CompilerError("The rest operator is not supported", prop);
958
994
  const { key, value } = prop;
959
995
  const keyInst = key.type === "Identifier" && !prop.computed
960
- ? [new LiteralValue(scope, key.name), []]
996
+ ? [new LiteralValue(key.name), []]
961
997
  : c.handleConsume(scope, prop.key);
962
998
  const propInit = init.get(scope, keyInst[0]);
963
999
  const declarationInst = Declare(c, scope, value, kind, propInit[0]);
@@ -966,14 +1002,14 @@ const DeclareObjectPattern = (c, scope, node, kind, base) => {
966
1002
  return [null, [...inst, ...propertiesInst[1]]];
967
1003
  };
968
1004
 
969
- const Literal = (_c, scope, node) => [new LiteralValue(scope, node.value), []];
1005
+ const Literal = (_c, scope, node) => [new LiteralValue(node.value), []];
970
1006
  const NumericLiteral = Literal;
971
1007
  const StringLiteral = Literal;
972
- const NullLiteral = (_c, scope) => [
973
- new LiteralValue(scope, null),
1008
+ const NullLiteral = () => [
1009
+ new LiteralValue(null),
974
1010
  [],
975
1011
  ];
976
- const BooleanLiteral = (_c, scope, node) => [new LiteralValue(scope, +node.value), []];
1012
+ const BooleanLiteral = (_c, scope, node) => [new LiteralValue(+node.value), []];
977
1013
 
978
1014
  const LRExpression = (c, scope, node) => {
979
1015
  const [left, leftInst] = c.handleConsume(scope, node.left);
@@ -985,35 +1021,26 @@ const BinaryExpression = LRExpression;
985
1021
  const LogicalExpression = (c, scope, node) => {
986
1022
  if (node.operator !== "??")
987
1023
  return LRExpression(c, scope, node);
988
- const nullLiteral = new LiteralValue(scope, null);
989
- const endAdress = new LiteralValue(scope, null);
1024
+ const other = lazyValue({
1025
+ eval: scope => c.handleEval(scope, node.right),
1026
+ consume: scope => c.handleConsume(scope, node.right),
1027
+ });
990
1028
  const [left, leftInst] = c.handleEval(scope, node.left);
991
- const [nullTest] = left["=="](scope, nullLiteral);
992
- if (nullTest instanceof LiteralValue) {
993
- if (nullTest.data)
994
- return c.handleEval(scope, node.right);
995
- else
996
- return [left, leftInst];
997
- }
998
- const [right, rightInst] = c.handleEval(scope, node.right);
999
- const result = new StoreValue(scope);
1000
- result.ensureOwned();
1001
- return [
1002
- result,
1003
- [
1004
- ...leftInst,
1005
- ...result["="](scope, left)[1],
1006
- new JumpInstruction(endAdress, EJumpKind.NotEqual, result, nullLiteral),
1007
- ...rightInst,
1008
- ...result["="](scope, right)[1],
1009
- new AddressResolver(endAdress),
1010
- ],
1011
- ];
1029
+ const [result, resultInst] = left["??"](scope, other);
1030
+ return [result, [...leftInst, ...resultInst]];
1012
1031
  };
1013
1032
  const AssignmentExpression = (c, scope, node) => {
1014
1033
  const [left, leftInst] = c.handle(scope, node.left);
1015
1034
  // doesn't need to consume because the operators already do that
1016
- const [right, rightInst] = c.handleEval(scope, node.right);
1035
+ const [right, rightInst] = node.operator !== "??="
1036
+ ? c.handleEval(scope, node.right)
1037
+ : [
1038
+ lazyValue({
1039
+ eval: scope => c.handleEval(scope, node.right),
1040
+ consume: scope => c.handleConsume(scope, node.right),
1041
+ }),
1042
+ [],
1043
+ ];
1017
1044
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1018
1045
  const [op, opInst] = left[node.operator](scope, right);
1019
1046
  return [op, [...leftInst, ...rightInst, ...opInst]];
@@ -1045,13 +1072,13 @@ const ConditionalExpression = (c, scope, node) => {
1045
1072
  result.ensureOwned();
1046
1073
  const consequent = c.handleEval(scope, node.consequent);
1047
1074
  const alternate = c.handleEval(scope, node.alternate);
1048
- const alternateStartAdress = new LiteralValue(scope, null);
1049
- const endExpressionAdress = new LiteralValue(scope, null);
1075
+ const alternateStartAdress = new LiteralValue(null);
1076
+ const endExpressionAdress = new LiteralValue(null);
1050
1077
  return [
1051
1078
  result,
1052
1079
  [
1053
1080
  ...testInst,
1054
- new JumpInstruction(alternateStartAdress, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
1081
+ new JumpInstruction(alternateStartAdress, EJumpKind.Equal, test, new LiteralValue(0)),
1055
1082
  ...consequent[1],
1056
1083
  ...result["="](scope, consequent[0])[1],
1057
1084
  new JumpInstruction(endExpressionAdress, EJumpKind.Always),
@@ -1061,7 +1088,13 @@ const ConditionalExpression = (c, scope, node) => {
1061
1088
  new AddressResolver(endExpressionAdress),
1062
1089
  ],
1063
1090
  ];
1064
- };
1091
+ };
1092
+ function lazyValue(options) {
1093
+ const value = new VoidValue();
1094
+ value.eval = options.eval;
1095
+ value.consume = options.consume;
1096
+ return value;
1097
+ }
1065
1098
 
1066
1099
  const Identifier = (c, scope, node) => {
1067
1100
  return [scope.get(node.name), []];
@@ -1070,14 +1103,18 @@ const Identifier = (c, scope, node) => {
1070
1103
  const ExpressionStatement = (c, scope, node) => {
1071
1104
  return c.handle(scope, node.expression);
1072
1105
  };
1073
- const BreakStatement = (_, scope) => {
1074
- const addr = new LiteralValue(scope, null);
1075
- scope.break.bind(addr);
1106
+ const BreakStatement = (_, scope, node) => {
1107
+ const label = node.label?.name;
1108
+ const target = label ? findScopeLabel(scope, label) : scope;
1109
+ const addr = new LiteralValue(null);
1110
+ target.break.bind(addr);
1076
1111
  return [null, [new BreakInstruction(addr)]];
1077
1112
  };
1078
- const ContinueStatement = (_, scope) => {
1079
- const addr = new LiteralValue(scope, null);
1080
- scope.continue.bind(addr);
1113
+ const ContinueStatement = (_, scope, node) => {
1114
+ const addr = new LiteralValue(null);
1115
+ const label = node.label?.name;
1116
+ const target = label ? findScopeLabel(scope, label) : scope;
1117
+ target.continue.bind(addr);
1081
1118
  return [null, [new ContinueInstruction(addr)]];
1082
1119
  };
1083
1120
  const ReturnStatement = (c, scope, node) => {
@@ -1086,7 +1123,24 @@ const ReturnStatement = (c, scope, node) => {
1086
1123
  : [null, []];
1087
1124
  const [ret, retInst] = scope.function.return(scope, arg);
1088
1125
  return [ret, [...argInst, ...retInst]];
1089
- };
1126
+ };
1127
+ const LabeledStatement = (c, scope, node) => {
1128
+ const inner = scope.createScope();
1129
+ inner.label = node.label.name;
1130
+ const end = new LiteralValue(null);
1131
+ const endAdress = new AddressResolver(end).bindBreak(inner);
1132
+ const [, bodyInst] = c.handle(inner, node.body);
1133
+ return [null, [...bodyInst, endAdress]];
1134
+ };
1135
+ function findScopeLabel(scope, label) {
1136
+ let current = scope;
1137
+ while (current !== null) {
1138
+ if (current.label === label)
1139
+ return current;
1140
+ current = current.parent;
1141
+ }
1142
+ throw new CompilerError(`Could not find label "${label}"`);
1143
+ }
1090
1144
 
1091
1145
  const IfStatement = (c, scope, node) => {
1092
1146
  const inst = [];
@@ -1098,9 +1152,9 @@ const IfStatement = (c, scope, node) => {
1098
1152
  inst.push(...c.handle(scope, node.alternate)[1]);
1099
1153
  return [null, inst];
1100
1154
  }
1101
- const endIfAddr = new LiteralValue(scope, null);
1102
- inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...withAlwaysRuns(c.handle(scope, node.consequent), false)[1], new AddressResolver(endIfAddr));
1103
- const endElseAddr = new LiteralValue(scope, null);
1155
+ const endIfAddr = new LiteralValue(null);
1156
+ inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(0)), ...withAlwaysRuns(c.handle(scope, node.consequent), false)[1], new AddressResolver(endIfAddr));
1157
+ const endElseAddr = new LiteralValue(null);
1104
1158
  if (node.alternate) {
1105
1159
  inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...withAlwaysRuns(c.handle(scope, node.alternate), false)[1], new AddressResolver(endElseAddr));
1106
1160
  }
@@ -1111,13 +1165,13 @@ const SwitchStatement = (c, scope, node) => {
1111
1165
  const innerScope = scope.createScope();
1112
1166
  const [ref, refInst] = c.handleConsume(scope, node.discriminant);
1113
1167
  const inst = [];
1114
- const endAdress = new LiteralValue(innerScope, null);
1168
+ const endAdress = new LiteralValue(null);
1115
1169
  const endLine = new AddressResolver(endAdress).bindBreak(innerScope);
1116
1170
  const caseJumps = [];
1117
1171
  let defaultJump;
1118
1172
  for (const scase of node.cases) {
1119
1173
  const [, bodyInst] = c.handleMany(innerScope, scase.consequent);
1120
- const bodyAdress = new LiteralValue(innerScope, null);
1174
+ const bodyAdress = new LiteralValue(null);
1121
1175
  const bodyLine = new AddressResolver(bodyAdress);
1122
1176
  if (!scase.test) {
1123
1177
  [defaultJump] = c.handle(innerScope, scase, () => [
@@ -1171,25 +1225,33 @@ const SwitchStatement = (c, scope, node) => {
1171
1225
  const WhileStatement = (c, scope, node) => {
1172
1226
  const lines = [];
1173
1227
  const [test, testLines] = c.handleConsume(scope, node.test);
1174
- const startLoopAddr = new LiteralValue(scope, null);
1175
- const endLoopAddr = new LiteralValue(scope, null);
1176
- const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1177
- const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1228
+ const childScope = scope.createScope();
1229
+ const startLoopAddr = new LiteralValue(null);
1230
+ const endLoopAddr = new LiteralValue(null);
1231
+ const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(childScope);
1232
+ const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(childScope);
1233
+ if (scope.label) {
1234
+ startLoopLine.bindContinue(scope);
1235
+ }
1178
1236
  if (test instanceof LiteralValue) {
1179
1237
  if (test.data) {
1180
- lines.push(startLoopLine, ...c.handle(scope, node.body)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
1238
+ lines.push(startLoopLine, ...c.handle(childScope, node.body)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
1181
1239
  }
1182
1240
  return [null, lines];
1183
1241
  }
1184
- lines.push(startLoopLine, ...testLines, new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...withAlwaysRuns(c.handle(scope, node.body), false)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
1242
+ 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);
1185
1243
  return [null, lines];
1186
1244
  };
1187
1245
  const DoWhileStatement = (c, scope, node) => {
1188
1246
  const lines = [];
1189
1247
  const [test, testLines] = c.handleConsume(scope, node.test);
1190
- const startLoopAddr = new LiteralValue(scope, null);
1191
- const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1192
- const [, bodyLines] = c.handle(scope, node.body);
1248
+ const childScope = scope.createScope();
1249
+ const startLoopAddr = new LiteralValue(null);
1250
+ const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(childScope);
1251
+ if (scope.label) {
1252
+ startLoopLine.bindContinue(scope);
1253
+ }
1254
+ const [, bodyLines] = c.handle(childScope, node.body);
1193
1255
  if (test instanceof LiteralValue) {
1194
1256
  if (!test.data)
1195
1257
  return [null, [...lines, ...bodyLines]];
@@ -1203,28 +1265,31 @@ const DoWhileStatement = (c, scope, node) => {
1203
1265
  ],
1204
1266
  ];
1205
1267
  }
1206
- lines.push(startLoopLine, ...bodyLines, ...testLines, new JumpInstruction(startLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 1)));
1268
+ lines.push(startLoopLine, ...bodyLines, ...testLines, new JumpInstruction(startLoopAddr, EJumpKind.Equal, test, new LiteralValue(1)));
1207
1269
  return [null, lines];
1208
1270
  };
1209
1271
 
1210
- const ForStatement = (c, scope, node) => {
1211
- scope = scope.createScope();
1272
+ const ForStatement = (c, parentScope, node) => {
1273
+ const scope = parentScope.createScope();
1212
1274
  const initInst = node.init ? c.handle(scope, node.init)[1] : [];
1213
1275
  const [test, testLines] = node.test
1214
1276
  ? c.handleConsume(scope, node.test)
1215
- : [new LiteralValue(scope, 1), []];
1277
+ : [new LiteralValue(1), []];
1216
1278
  const updateLines = node.update ? c.handle(scope, node.update)[1] : [];
1217
- const startLoopAddr = new LiteralValue(scope, null);
1218
- const endLoopAddr = new LiteralValue(scope, null);
1279
+ const startLoopAddr = new LiteralValue(null);
1280
+ const endLoopAddr = new LiteralValue(null);
1219
1281
  const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1220
1282
  const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1283
+ if (parentScope.label) {
1284
+ startLoopLine.bindContinue(parentScope);
1285
+ }
1221
1286
  return [
1222
1287
  null,
1223
1288
  [
1224
1289
  ...initInst,
1225
1290
  startLoopLine,
1226
1291
  ...testLines,
1227
- new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
1292
+ new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(0)),
1228
1293
  ...withAlwaysRuns(c.handle(scope, node.body), false)[1],
1229
1294
  ...updateLines,
1230
1295
  new JumpInstruction(startLoopAddr, EJumpKind.Always),
@@ -1234,20 +1299,20 @@ const ForStatement = (c, scope, node) => {
1234
1299
  };
1235
1300
 
1236
1301
  class FunctionValue extends VoidValue {
1237
- constructor({ scope, params, body, c, node, }) {
1238
- super(scope);
1302
+ constructor({ scope, params, body, c, }) {
1303
+ super();
1239
1304
  this.mutability = EMutability.constant;
1240
1305
  this.macro = true;
1241
1306
  this.paramOwners = [];
1242
1307
  this.bundled = false;
1243
1308
  this.initialized = false;
1309
+ this.scope = scope;
1244
1310
  this.body = body;
1245
1311
  this.c = c;
1246
- this.node = node;
1247
1312
  this.params = params;
1248
1313
  }
1249
- typeof(scope) {
1250
- return [new LiteralValue(scope, "function"), []];
1314
+ typeof() {
1315
+ return [new LiteralValue("function"), []];
1251
1316
  }
1252
1317
  initScope(name) {
1253
1318
  this.childScope = this.scope.createFunction(name);
@@ -1275,7 +1340,7 @@ class FunctionValue extends VoidValue {
1275
1340
  this.initialized = true;
1276
1341
  const { name } = this.owner;
1277
1342
  this.initScope(name);
1278
- this.addr = new LiteralValue(this.childScope, null);
1343
+ this.addr = new LiteralValue(null);
1279
1344
  this.temp = new ValueOwner({
1280
1345
  scope: this.childScope,
1281
1346
  name: `${internalPrefix}f${name}`,
@@ -1309,7 +1374,7 @@ class FunctionValue extends VoidValue {
1309
1374
  if (!this.bundled)
1310
1375
  this.childScope.inst.push(...this.inst);
1311
1376
  this.bundled = true;
1312
- const callAddressLiteral = new LiteralValue(scope, null);
1377
+ const callAddressLiteral = new LiteralValue(null);
1313
1378
  const inst = this.paramOwners
1314
1379
  .map(({ value: param }, i) => param["="](scope, args[i])[1])
1315
1380
  .reduce((s, c) => s.concat(c), [])
@@ -1347,7 +1412,7 @@ class FunctionValue extends VoidValue {
1347
1412
  name: owner.name,
1348
1413
  }));
1349
1414
  });
1350
- this.inlineEnd = new LiteralValue(scope, null);
1415
+ this.inlineEnd = new LiteralValue(null);
1351
1416
  this.tryingInline = true;
1352
1417
  let inst = this.c.handle(fnScope, this.body)[1];
1353
1418
  this.tryingInline = false;
@@ -1406,7 +1471,6 @@ function handleFunctionNode(c, scope, node) {
1406
1471
  }
1407
1472
  return [
1408
1473
  new FunctionValue({
1409
- node,
1410
1474
  scope,
1411
1475
  params: params,
1412
1476
  body,
@@ -1452,8 +1516,8 @@ const NewExpression = CallExpression;
1452
1516
  const TaggedTemplateExpression = (c, scope, node) => {
1453
1517
  const [tag, tagInst] = c.handleConsume(scope, node.tag);
1454
1518
  const template = node.quasi;
1455
- const stringsObject = ObjectValue.fromArray(scope, template.quasis.map(quasi => new LiteralValue(scope, quasi.value.cooked ?? "")), {
1456
- raw: ObjectValue.fromArray(scope, template.quasis.map(quasi => new LiteralValue(scope, quasi.value.raw))),
1519
+ const stringsObject = ObjectValue.fromArray(template.quasis.map(quasi => new LiteralValue(quasi.value.cooked ?? "")), {
1520
+ raw: ObjectValue.fromArray(template.quasis.map(quasi => new LiteralValue(quasi.value.raw))),
1457
1521
  });
1458
1522
  const expressions = [];
1459
1523
  const expressionInsts = [];
@@ -1498,7 +1562,7 @@ const ObjectExpression = (c, scope, node) => {
1498
1562
  data[index] = member;
1499
1563
  inst.push(...memberInst);
1500
1564
  }
1501
- return [new ObjectValue(scope, data), inst];
1565
+ return [new ObjectValue(data), inst];
1502
1566
  };
1503
1567
  const ArrayExpression = (c, scope, node) => {
1504
1568
  const items = [];
@@ -1510,13 +1574,13 @@ const ArrayExpression = (c, scope, node) => {
1510
1574
  items.push(value);
1511
1575
  inst.push(...valueInst);
1512
1576
  });
1513
- return [ObjectValue.fromArray(scope, items), inst];
1577
+ return [ObjectValue.fromArray(items), inst];
1514
1578
  };
1515
1579
  const MemberExpression = (c, scope, node) => {
1516
1580
  const [obj, objInst] = c.handleConsume(scope, node.object);
1517
1581
  const [prop, propInst] = node.computed
1518
1582
  ? c.handleConsume(scope, node.property)
1519
- : [new LiteralValue(scope, node.property.name), []];
1583
+ : [new LiteralValue(node.property.name), []];
1520
1584
  const [got, gotInst] = obj.get(scope, prop);
1521
1585
  return [got, [...objInst, ...propInst, ...gotInst]];
1522
1586
  };
@@ -1531,9 +1595,9 @@ const ArrayPattern = (c, scope, node) => {
1531
1595
  if (!valueInst[0])
1532
1596
  throw new CompilerError("Destructuring element must resolve to a value", element);
1533
1597
  inst.push(...valueInst[1]);
1534
- members.set(new LiteralValue(scope, i), valueInst[0]);
1598
+ members.set(new LiteralValue(i), valueInst[0]);
1535
1599
  }
1536
- return [new DestructuringValue(scope, members), inst];
1600
+ return [new DestructuringValue(members), inst];
1537
1601
  };
1538
1602
  const ObjectPattern = (c, scope, node) => {
1539
1603
  const inst = [];
@@ -1545,7 +1609,7 @@ const ObjectPattern = (c, scope, node) => {
1545
1609
  continue;
1546
1610
  const { key } = prop;
1547
1611
  const keyInst = !prop.computed && key.type === "Identifier"
1548
- ? [new LiteralValue(scope, key.name), []]
1612
+ ? [new LiteralValue(key.name), []]
1549
1613
  : c.handleConsume(scope, prop.key);
1550
1614
  inst.push(...keyInst[1]);
1551
1615
  const valueInst = c.handle(scope, prop.value);
@@ -1554,7 +1618,7 @@ const ObjectPattern = (c, scope, node) => {
1554
1618
  inst.push(...valueInst[1]);
1555
1619
  members.set(keyInst[0], valueInst[0]);
1556
1620
  }
1557
- return [new DestructuringValue(scope, members), inst];
1621
+ return [new DestructuringValue(members), inst];
1558
1622
  };
1559
1623
 
1560
1624
  const TemplateLiteral = () => {
@@ -1594,7 +1658,7 @@ const TSEnumDeclaration = (c, scope, node) => {
1594
1658
  throw new CompilerError("This enum member must be initialized", member);
1595
1659
  const [value] = member.initializer
1596
1660
  ? c.handleEval(scope, member.initializer)
1597
- : [new LiteralValue(scope, counter)];
1661
+ : [new LiteralValue(counter)];
1598
1662
  if (!(value instanceof LiteralValue))
1599
1663
  throw new CompilerError("Enum members must contain literal values", member);
1600
1664
  if (typeof value.data === "number") {
@@ -1609,7 +1673,7 @@ const TSEnumDeclaration = (c, scope, node) => {
1609
1673
  }
1610
1674
  scope.set(new ValueOwner({
1611
1675
  scope,
1612
- value: new ObjectValue(scope, data),
1676
+ value: new ObjectValue(data),
1613
1677
  constant: true,
1614
1678
  identifier: node.id.name,
1615
1679
  name: nodeName(node, !c.compactNames && node.id.name),
@@ -1641,6 +1705,7 @@ var handlers = /*#__PURE__*/Object.freeze({
1641
1705
  BreakStatement: BreakStatement,
1642
1706
  ContinueStatement: ContinueStatement,
1643
1707
  ReturnStatement: ReturnStatement,
1708
+ LabeledStatement: LabeledStatement,
1644
1709
  IfStatement: IfStatement,
1645
1710
  SwitchStatement: SwitchStatement,
1646
1711
  WhileStatement: WhileStatement,
@@ -1670,14 +1735,14 @@ var handlers = /*#__PURE__*/Object.freeze({
1670
1735
  });
1671
1736
 
1672
1737
  class MacroFunction extends VoidValue {
1673
- constructor(scope, fn) {
1674
- super(scope);
1738
+ constructor(fn) {
1739
+ super();
1675
1740
  this.macro = true;
1676
- this.constant = true;
1741
+ this.mutability = EMutability.constant;
1677
1742
  this.fn = fn;
1678
1743
  }
1679
1744
  call(scope, args) {
1680
- return this.fn.apply(this, args);
1745
+ return this.fn.apply(this, [scope, ...args]);
1681
1746
  }
1682
1747
  eval(_scope) {
1683
1748
  return [this, []];
@@ -1708,16 +1773,31 @@ const mathOperations = {
1708
1773
  sqrt: a => Math.sqrt(a),
1709
1774
  rand: null,
1710
1775
  };
1776
+ function mathConstant(scope, name) {
1777
+ return new ValueOwner({
1778
+ scope,
1779
+ constant: true,
1780
+ name,
1781
+ value: assign(new StoreValue(scope), {
1782
+ mutability: EMutability.constant,
1783
+ }),
1784
+ }).value;
1785
+ }
1711
1786
  function createMacroMathOperations(scope) {
1712
- const macroMathOperations = {};
1787
+ const macroMathOperations = {
1788
+ PI: mathConstant(scope, "@pi"),
1789
+ E: mathConstant(scope, "@e"),
1790
+ degToRad: mathConstant(scope, "@degToRad"),
1791
+ radToDeg: mathConstant(scope, "@radToDeg"),
1792
+ };
1713
1793
  for (const key in mathOperations) {
1714
1794
  const fn = mathOperations[key];
1715
- macroMathOperations[key] = new MacroFunction(scope, (a, b) => {
1795
+ macroMathOperations[key] = new MacroFunction((scope, a, b) => {
1716
1796
  if (b) {
1717
1797
  if (fn && a instanceof LiteralValue && b instanceof LiteralValue) {
1718
1798
  if (typeof a.data !== "number" || typeof b.data !== "number")
1719
1799
  throw new CompilerError("Cannot do math operation with non-numerical literals.");
1720
- return [new LiteralValue(scope, fn(a.num, b.num)), []];
1800
+ return [new LiteralValue(fn(a.num, b.num)), []];
1721
1801
  }
1722
1802
  const temp = new StoreValue(scope);
1723
1803
  return [temp, [new OperationInstruction(key, temp, a, b)]];
@@ -1725,7 +1805,7 @@ function createMacroMathOperations(scope) {
1725
1805
  if (fn && a instanceof LiteralValue) {
1726
1806
  if (typeof a.data !== "number")
1727
1807
  throw new CompilerError("Cannot do math operation with non-numerical literal.");
1728
- return [new LiteralValue(scope, fn(a.num)), []];
1808
+ return [new LiteralValue(fn(a.num)), []];
1729
1809
  }
1730
1810
  const temp = new StoreValue(scope);
1731
1811
  return [temp, [new OperationInstruction(key, temp, a, b)]];
@@ -1735,20 +1815,20 @@ function createMacroMathOperations(scope) {
1735
1815
  }
1736
1816
  class MlogMath extends ObjectValue {
1737
1817
  constructor(scope) {
1738
- super(scope, createMacroMathOperations(scope));
1818
+ super(createMacroMathOperations(scope));
1739
1819
  }
1740
1820
  }
1741
1821
  // op angle result a b
1742
1822
  // op len result a b
1743
1823
 
1744
1824
  class Concat extends MacroFunction {
1745
- constructor(scope) {
1746
- super(scope, (...values) => {
1825
+ constructor() {
1826
+ super((scope, ...values) => {
1747
1827
  for (const value of values)
1748
1828
  if (!(value instanceof LiteralValue))
1749
1829
  throw new CompilerError("Concat arguments must all be literal values.");
1750
1830
  return [
1751
- new LiteralValue(scope, values.map(v => v.data).join("")),
1831
+ new LiteralValue(values.map(v => v.data).join("")),
1752
1832
  [],
1753
1833
  ];
1754
1834
  });
@@ -1803,18 +1883,18 @@ function assertObjectFields(value, fields) {
1803
1883
  }
1804
1884
 
1805
1885
  /** Used to create namespaces that contain multiple methods that map into instructions */
1806
- function createOverloadNamespace({ scope, overloads, handler, }) {
1886
+ function createOverloadNamespace({ overloads, handler, }) {
1807
1887
  const result = {};
1808
1888
  for (const key in overloads) {
1809
1889
  const { named, args } = overloads[key];
1810
1890
  if (named) {
1811
- result[key] = new MacroFunction(scope, options => {
1891
+ result[key] = new MacroFunction((scope, options) => {
1812
1892
  assertIsObjectMacro(options, named);
1813
- return handler(key, ...assertObjectFields(options, args));
1893
+ return handler(scope, key, ...assertObjectFields(options, args));
1814
1894
  });
1815
1895
  continue;
1816
1896
  }
1817
- result[key] = new MacroFunction(scope, (...params) => {
1897
+ result[key] = new MacroFunction((scope, ...params) => {
1818
1898
  const handlerParams = [];
1819
1899
  // validate the paramters
1820
1900
  for (let i = 0; i < args.length; i++) {
@@ -1831,16 +1911,15 @@ function createOverloadNamespace({ scope, overloads, handler, }) {
1831
1911
  arg.validate?.(param);
1832
1912
  handlerParams.push(param);
1833
1913
  }
1834
- return handler(key, ...handlerParams);
1914
+ return handler(scope, key, ...handlerParams);
1835
1915
  });
1836
1916
  }
1837
1917
  return result;
1838
1918
  }
1839
1919
 
1840
1920
  class Draw extends ObjectValue {
1841
- constructor(scope) {
1921
+ constructor() {
1842
1922
  const data = createOverloadNamespace({
1843
- scope,
1844
1923
  overloads: {
1845
1924
  clear: {
1846
1925
  args: ["r", "g", "b"],
@@ -1877,17 +1956,17 @@ class Draw extends ObjectValue {
1877
1956
  args: ["x", "y", "image", "size", "rotation"],
1878
1957
  },
1879
1958
  },
1880
- handler(overload, ...args) {
1959
+ handler(scope, overload, ...args) {
1881
1960
  return [null, [new InstructionBase("draw", overload, ...args)]];
1882
1961
  },
1883
1962
  });
1884
- super(scope, data);
1963
+ super(data);
1885
1964
  }
1886
1965
  }
1887
1966
 
1888
1967
  class Print extends MacroFunction {
1889
- constructor(scope) {
1890
- super(scope, (...values) => {
1968
+ constructor() {
1969
+ super((scope, ...values) => {
1891
1970
  const [first] = values;
1892
1971
  const inst = [];
1893
1972
  if (!isTemplateObjectArray(first)) {
@@ -1900,12 +1979,12 @@ class Print extends MacroFunction {
1900
1979
  // maybe this should be checked in another way?
1901
1980
  const { length } = first.data;
1902
1981
  for (let i = 1; i < values.length; i++) {
1903
- const [string] = first.get(scope, new LiteralValue(scope, i - 1));
1982
+ const [string] = first.get(scope, new LiteralValue(i - 1));
1904
1983
  if (string.data)
1905
1984
  inst.push(new InstructionBase("print", string));
1906
1985
  inst.push(new InstructionBase("print", values[i]));
1907
1986
  }
1908
- const [tail] = first.get(scope, new LiteralValue(scope, length.data - 1));
1987
+ const [tail] = first.get(scope, new LiteralValue(length.data - 1));
1909
1988
  if (tail.data)
1910
1989
  inst.push(new InstructionBase("print", tail));
1911
1990
  return [null, inst];
@@ -1915,8 +1994,8 @@ class Print extends MacroFunction {
1915
1994
 
1916
1995
  const defaultTargetName$1 = "message1";
1917
1996
  class PrintFlush extends MacroFunction {
1918
- constructor(scope) {
1919
- super(scope, (target) => {
1997
+ constructor() {
1998
+ super((scope, target) => {
1920
1999
  if (!target)
1921
2000
  return [null, [new InstructionBase("printflush", defaultTargetName$1)]];
1922
2001
  if (!(target instanceof SenseableValue))
@@ -1928,8 +2007,8 @@ class PrintFlush extends MacroFunction {
1928
2007
 
1929
2008
  const defaultTargetName = "display1";
1930
2009
  class DrawFlush extends MacroFunction {
1931
- constructor(scope) {
1932
- super(scope, (target) => {
2010
+ constructor() {
2011
+ super((scope, target) => {
1933
2012
  if (!target)
1934
2013
  return [null, [new InstructionBase("drawflush", defaultTargetName)]];
1935
2014
  if (!(target instanceof SenseableValue))
@@ -1940,16 +2019,15 @@ class DrawFlush extends MacroFunction {
1940
2019
  }
1941
2020
 
1942
2021
  class GetBlock extends ObjectValue {
1943
- constructor(scope) {
2022
+ constructor() {
1944
2023
  const data = createOverloadNamespace({
1945
- scope,
1946
2024
  overloads: {
1947
2025
  floor: { args: ["x", "y"] },
1948
2026
  ore: { args: ["x", "y"] },
1949
2027
  block: { args: ["x", "y"] },
1950
2028
  building: { args: ["x", "y"] },
1951
2029
  },
1952
- handler(overload, x, y) {
2030
+ handler(scope, overload, x, y) {
1953
2031
  const output = overload === "building"
1954
2032
  ? new SenseableValue(scope)
1955
2033
  : new StoreValue(scope);
@@ -1959,13 +2037,13 @@ class GetBlock extends ObjectValue {
1959
2037
  ];
1960
2038
  },
1961
2039
  });
1962
- super(scope, data);
2040
+ super(data);
1963
2041
  }
1964
2042
  }
1965
2043
 
1966
2044
  class GetLink extends MacroFunction {
1967
- constructor(scope) {
1968
- super(scope, (index) => {
2045
+ constructor() {
2046
+ super((scope, index) => {
1969
2047
  if (!(index instanceof StoreValue) &&
1970
2048
  (!(index instanceof LiteralValue) || typeof index.data !== "number"))
1971
2049
  throw new CompilerError("The getlink index must be a number literal or a store");
@@ -1976,9 +2054,8 @@ class GetLink extends MacroFunction {
1976
2054
  }
1977
2055
 
1978
2056
  class Control extends ObjectValue {
1979
- constructor(scope) {
1980
- super(scope, createOverloadNamespace({
1981
- scope,
2057
+ constructor() {
2058
+ super(createOverloadNamespace({
1982
2059
  overloads: {
1983
2060
  enabled: { args: ["building", "value"] },
1984
2061
  shoot: {
@@ -1992,7 +2069,7 @@ class Control extends ObjectValue {
1992
2069
  config: { args: ["building", "value"] },
1993
2070
  color: { args: ["building", "r", "g", "b"] },
1994
2071
  },
1995
- handler(overload, ...args) {
2072
+ handler(scope, overload, ...args) {
1996
2073
  return [null, [new InstructionBase("control", overload, ...args)]];
1997
2074
  },
1998
2075
  }));
@@ -2017,8 +2094,8 @@ const validRadarSorts = [
2017
2094
  "maxHealth",
2018
2095
  ];
2019
2096
  class Radar extends MacroFunction {
2020
- constructor(scope) {
2021
- super(scope, options => {
2097
+ constructor() {
2098
+ super((scope, options) => {
2022
2099
  assertIsObjectMacro(options, "The radar options");
2023
2100
  const { building, filters, order, sort } = options.data;
2024
2101
  if (!(building instanceof SenseableValue))
@@ -2049,8 +2126,8 @@ class Radar extends MacroFunction {
2049
2126
  }
2050
2127
 
2051
2128
  class Sensor extends MacroFunction {
2052
- constructor(scope) {
2053
- super(scope, (property, target) => {
2129
+ constructor() {
2130
+ super((scope, property, target) => {
2054
2131
  if (!(property instanceof StoreValue))
2055
2132
  throw new CompilerError("The sensor property must be a store");
2056
2133
  if (!(target instanceof SenseableValue))
@@ -2064,8 +2141,8 @@ class Sensor extends MacroFunction {
2064
2141
  }
2065
2142
 
2066
2143
  class Wait extends MacroFunction {
2067
- constructor(scope) {
2068
- super(scope, seconds => {
2144
+ constructor() {
2145
+ super((scope, seconds) => {
2069
2146
  if (!(seconds instanceof StoreValue) &&
2070
2147
  !(seconds instanceof LiteralValue && typeof seconds.data === "number"))
2071
2148
  throw new CompilerError("The wait seconds must be either a number literal or a store");
@@ -2075,16 +2152,15 @@ class Wait extends MacroFunction {
2075
2152
  }
2076
2153
 
2077
2154
  class Lookup extends ObjectValue {
2078
- constructor(scope) {
2155
+ constructor() {
2079
2156
  const data = createOverloadNamespace({
2080
- scope,
2081
2157
  overloads: {
2082
2158
  block: { args: ["index"] },
2083
2159
  unit: { args: ["index"] },
2084
2160
  item: { args: ["index"] },
2085
2161
  liquid: { args: ["index"] },
2086
2162
  },
2087
- handler(overload, index) {
2163
+ handler(scope, overload, index) {
2088
2164
  const output = new StoreValue(scope);
2089
2165
  return [
2090
2166
  output,
@@ -2092,13 +2168,13 @@ class Lookup extends ObjectValue {
2092
2168
  ];
2093
2169
  },
2094
2170
  });
2095
- super(scope, data);
2171
+ super(data);
2096
2172
  }
2097
2173
  }
2098
2174
 
2099
2175
  class PackColor extends MacroFunction {
2100
- constructor(scope) {
2101
- super(scope, (...args) => {
2176
+ constructor() {
2177
+ super((scope, ...args) => {
2102
2178
  if (args.length !== 4) {
2103
2179
  throw new CompilerError(`Expected 4 arguments, received ${args.length}`);
2104
2180
  }
@@ -2113,15 +2189,14 @@ class PackColor extends MacroFunction {
2113
2189
  }
2114
2190
 
2115
2191
  class End extends MacroFunction {
2116
- constructor(scope) {
2117
- super(scope, () => [null, [new EndInstruction()]]);
2192
+ constructor() {
2193
+ super(() => [null, [new EndInstruction()]]);
2118
2194
  }
2119
2195
  }
2120
2196
 
2121
2197
  class SetBlock extends ObjectValue {
2122
- constructor(scope) {
2198
+ constructor() {
2123
2199
  const data = createOverloadNamespace({
2124
- scope,
2125
2200
  overloads: {
2126
2201
  floor: { args: ["x", "y", "to"] },
2127
2202
  ore: { args: ["x", "y", "to"] },
@@ -2130,7 +2205,7 @@ class SetBlock extends ObjectValue {
2130
2205
  args: ["x", "y", "to", "team", { key: "rotation", default: "0" }],
2131
2206
  },
2132
2207
  },
2133
- handler(overload, x, y, to, team, rotation) {
2208
+ handler(scope, overload, x, y, to, team, rotation) {
2134
2209
  return [
2135
2210
  null,
2136
2211
  [
@@ -2139,13 +2214,13 @@ class SetBlock extends ObjectValue {
2139
2214
  ];
2140
2215
  },
2141
2216
  });
2142
- super(scope, data);
2217
+ super(data);
2143
2218
  }
2144
2219
  }
2145
2220
 
2146
2221
  class SpawnUnit extends MacroFunction {
2147
- constructor(scope) {
2148
- super(scope, options => {
2222
+ constructor() {
2223
+ super((scope, options) => {
2149
2224
  assertIsObjectMacro(options, "The options");
2150
2225
  const { type, x, y, team, rotation } = options.data;
2151
2226
  assertIsRuntimeValue(type, "type");
@@ -2164,14 +2239,14 @@ class SpawnUnit extends MacroFunction {
2164
2239
  }
2165
2240
 
2166
2241
  class Stop extends MacroFunction {
2167
- constructor(scope) {
2168
- super(scope, () => [null, [new InstructionBase("stop")]]);
2242
+ constructor() {
2243
+ super(() => [null, [new InstructionBase("stop")]]);
2169
2244
  }
2170
2245
  }
2171
2246
 
2172
2247
  class UnitBind extends MacroFunction {
2173
- constructor(scope) {
2174
- super(scope, type => {
2248
+ constructor() {
2249
+ super((scope, type) => {
2175
2250
  if (!(type instanceof StoreValue))
2176
2251
  throw new CompilerError("The unitBind type must be a store");
2177
2252
  return [null, [new InstructionBase("ubind", type)]];
@@ -2180,9 +2255,8 @@ class UnitBind extends MacroFunction {
2180
2255
  }
2181
2256
 
2182
2257
  class UnitControl extends ObjectValue {
2183
- constructor(scope) {
2258
+ constructor() {
2184
2259
  const data = createOverloadNamespace({
2185
- scope,
2186
2260
  overloads: {
2187
2261
  idle: { args: [] },
2188
2262
  stop: { args: [] },
@@ -2211,21 +2285,21 @@ class UnitControl extends ObjectValue {
2211
2285
  args: ["x", "y", "radius"],
2212
2286
  },
2213
2287
  },
2214
- handler(overload, ...args) {
2288
+ handler(scope, overload, ...args) {
2215
2289
  let result = null;
2216
2290
  let extraArgs = [];
2217
2291
  switch (overload) {
2218
2292
  case "getBlock": {
2219
2293
  const outType = new StoreValue(scope);
2220
2294
  const outBuilding = new SenseableValue(scope);
2221
- result = ObjectValue.fromArray(scope, [outType, outBuilding]);
2222
- extraArgs = [outType, outBuilding, new LiteralValue(scope, 0)];
2295
+ result = ObjectValue.fromArray([outType, outBuilding]);
2296
+ extraArgs = [outType, outBuilding, new LiteralValue(0)];
2223
2297
  break;
2224
2298
  }
2225
2299
  case "within": {
2226
2300
  const temp = new StoreValue(scope);
2227
2301
  result = temp;
2228
- extraArgs = [temp, new LiteralValue(scope, 0)];
2302
+ extraArgs = [temp, new LiteralValue(0)];
2229
2303
  break;
2230
2304
  }
2231
2305
  }
@@ -2235,13 +2309,13 @@ class UnitControl extends ObjectValue {
2235
2309
  ];
2236
2310
  },
2237
2311
  });
2238
- super(scope, data);
2312
+ super(data);
2239
2313
  }
2240
2314
  }
2241
2315
 
2242
2316
  class UnitRadar extends MacroFunction {
2243
- constructor(scope) {
2244
- super(scope, options => {
2317
+ constructor() {
2318
+ super((scope, options) => {
2245
2319
  assertIsObjectMacro(options, "The radar options");
2246
2320
  const { filters, order, sort } = options.data;
2247
2321
  assertIsArrayMacro(filters, "filters");
@@ -2282,9 +2356,8 @@ const validBuildingGroups = [
2282
2356
  "reactor",
2283
2357
  ];
2284
2358
  class UnitLocate extends ObjectValue {
2285
- constructor(scope) {
2359
+ constructor() {
2286
2360
  const data = createOverloadNamespace({
2287
- scope,
2288
2361
  overloads: {
2289
2362
  ore: {
2290
2363
  args: ["ore"],
@@ -2297,7 +2370,7 @@ class UnitLocate extends ObjectValue {
2297
2370
  args: [],
2298
2371
  },
2299
2372
  },
2300
- handler(overload, ...args) {
2373
+ handler(scope, overload, ...args) {
2301
2374
  const outFound = new StoreValue(scope);
2302
2375
  const outX = new StoreValue(scope);
2303
2376
  const outY = new StoreValue(scope);
@@ -2325,7 +2398,7 @@ class UnitLocate extends ObjectValue {
2325
2398
  }
2326
2399
  }
2327
2400
  return [
2328
- ObjectValue.fromArray(scope, [
2401
+ ObjectValue.fromArray([
2329
2402
  outFound,
2330
2403
  outX,
2331
2404
  outY,
@@ -2335,7 +2408,7 @@ class UnitLocate extends ObjectValue {
2335
2408
  ];
2336
2409
  },
2337
2410
  });
2338
- super(scope, data);
2411
+ super(data);
2339
2412
  }
2340
2413
  }
2341
2414
 
@@ -2356,16 +2429,15 @@ const validEffects = [
2356
2429
  "blasted",
2357
2430
  ];
2358
2431
  class ApplyStatus extends ObjectValue {
2359
- constructor(scope) {
2432
+ constructor() {
2360
2433
  const data = createOverloadNamespace({
2361
- scope,
2362
2434
  overloads: {
2363
2435
  apply: {
2364
2436
  args: ["status", "unit", { key: "duration", default: "10" }],
2365
2437
  },
2366
2438
  clear: { args: ["status", "unit"] },
2367
2439
  },
2368
- handler(overload, effect, unit, duration) {
2440
+ handler(scope, overload, effect, unit, duration) {
2369
2441
  if (!(effect instanceof LiteralValue))
2370
2442
  throw new CompilerError("The status effect must be a string literal");
2371
2443
  assertLiteralOneOf(effect, validEffects, "The status effect");
@@ -2377,13 +2449,13 @@ class ApplyStatus extends ObjectValue {
2377
2449
  ];
2378
2450
  },
2379
2451
  });
2380
- super(scope, data);
2452
+ super(data);
2381
2453
  }
2382
2454
  }
2383
2455
 
2384
2456
  class SpawnWave extends MacroFunction {
2385
- constructor(scope) {
2386
- super(scope, (natural, x, y) => {
2457
+ constructor() {
2458
+ super((scope, natural, x, y) => {
2387
2459
  if (!(natural instanceof LiteralValue) ||
2388
2460
  (natural.data !== 1 && natural.data !== 0))
2389
2461
  throw new CompilerError("The 'natural' argument must be a boolean literal");
@@ -2398,9 +2470,8 @@ class SpawnWave extends MacroFunction {
2398
2470
  }
2399
2471
 
2400
2472
  class SetRule extends ObjectValue {
2401
- constructor(scope) {
2473
+ constructor() {
2402
2474
  const data = createOverloadNamespace({
2403
- scope,
2404
2475
  overloads: {
2405
2476
  currentWaveTime: { args: ["seconds"] },
2406
2477
  waveTimer: { args: ["enabled"] },
@@ -2418,13 +2489,14 @@ class SetRule extends ObjectValue {
2418
2489
  solarMultiplier: { args: ["multiplier"] },
2419
2490
  buildSpeed: { args: ["team", "multiplier"] },
2420
2491
  unitBuildSpeed: { args: ["team", "multiplier"] },
2492
+ unitCost: { args: ["team", "multiplier"] },
2421
2493
  unitDamage: { args: ["team", "multiplier"] },
2422
2494
  blockHealth: { args: ["team", "multiplier"] },
2423
2495
  blockDamage: { args: ["team", "multiplier"] },
2424
2496
  rtsMinWeight: { args: ["team", "value"] },
2425
2497
  rtsMinSquad: { args: ["team", "value"] },
2426
2498
  },
2427
- handler(overload, ...args) {
2499
+ handler(scope, overload, ...args) {
2428
2500
  const params = ["10", "0", "0", "100", "100"];
2429
2501
  switch (overload) {
2430
2502
  case "mapArea": {
@@ -2437,6 +2509,7 @@ class SetRule extends ObjectValue {
2437
2509
  }
2438
2510
  case "buildSpeed":
2439
2511
  case "unitBuildSpeed":
2512
+ case "unitCost":
2440
2513
  case "unitDamage":
2441
2514
  case "blockHealth":
2442
2515
  case "blockDamage":
@@ -2444,7 +2517,7 @@ class SetRule extends ObjectValue {
2444
2517
  case "rtsMinSquad": {
2445
2518
  const [team, value] = args;
2446
2519
  params[1] = team;
2447
- params[2] = value;
2520
+ params[0] = value;
2448
2521
  break;
2449
2522
  }
2450
2523
  default:
@@ -2453,49 +2526,47 @@ class SetRule extends ObjectValue {
2453
2526
  return [null, [new InstructionBase("setrule", overload, ...params)]];
2454
2527
  },
2455
2528
  });
2456
- super(scope, data);
2529
+ super(data);
2457
2530
  }
2458
2531
  }
2459
2532
 
2460
2533
  class FlushMessage extends ObjectValue {
2461
- constructor(scope) {
2534
+ constructor() {
2462
2535
  const data = createOverloadNamespace({
2463
- scope,
2464
2536
  overloads: {
2465
2537
  notify: { args: [] },
2466
2538
  mission: { args: [] },
2467
2539
  announce: { args: ["duration"] },
2468
2540
  toast: { args: ["duration"] },
2469
2541
  },
2470
- handler(overload, duration) {
2542
+ handler(scope, overload, duration) {
2471
2543
  return [null, [new InstructionBase("message", overload, duration)]];
2472
2544
  },
2473
2545
  });
2474
- super(scope, data);
2546
+ super(data);
2475
2547
  }
2476
2548
  }
2477
2549
 
2478
2550
  class Cutscene extends ObjectValue {
2479
- constructor(scope) {
2551
+ constructor() {
2480
2552
  const data = createOverloadNamespace({
2481
- scope,
2482
2553
  overloads: {
2483
2554
  pan: { named: "options", args: ["x", "y", "speed"] },
2484
2555
  zoom: { args: ["level"] },
2485
2556
  stop: { args: [] },
2486
2557
  },
2487
- handler(overload, ...args) {
2558
+ handler(scope, overload, ...args) {
2488
2559
  const params = Object.assign(["100", "100", "0.06", "0"], args);
2489
2560
  return [null, [new InstructionBase("cutscene", overload, ...params)]];
2490
2561
  },
2491
2562
  });
2492
- super(scope, data);
2563
+ super(data);
2493
2564
  }
2494
2565
  }
2495
2566
 
2496
2567
  class Explosion extends MacroFunction {
2497
- constructor(scope) {
2498
- super(scope, options => {
2568
+ constructor() {
2569
+ super((scope, options) => {
2499
2570
  assertIsObjectMacro(options, "The options");
2500
2571
  const params = assertObjectFields(options, [
2501
2572
  "team",
@@ -2513,15 +2584,14 @@ class Explosion extends MacroFunction {
2513
2584
  }
2514
2585
 
2515
2586
  class SetRate extends MacroFunction {
2516
- constructor(scope) {
2517
- super(scope, ipt => [null, [new InstructionBase("setrate", ipt)]]);
2587
+ constructor() {
2588
+ super((scope, ipt) => [null, [new InstructionBase("setrate", ipt)]]);
2518
2589
  }
2519
2590
  }
2520
2591
 
2521
2592
  class Fetch extends ObjectValue {
2522
- constructor(scope) {
2593
+ constructor() {
2523
2594
  const data = createOverloadNamespace({
2524
- scope,
2525
2595
  overloads: {
2526
2596
  unit: { args: ["team", "index"] },
2527
2597
  unitCount: { args: ["team"] },
@@ -2532,7 +2602,7 @@ class Fetch extends ObjectValue {
2532
2602
  build: { args: ["team", "index", "block"] },
2533
2603
  buildCount: { args: ["team", "block"] },
2534
2604
  },
2535
- handler(overload, team, ...rest) {
2605
+ handler(scope, overload, team, ...rest) {
2536
2606
  const output = new SenseableValue(scope);
2537
2607
  const params = ["0", "@conveyor"];
2538
2608
  if (overload === "buildCount") {
@@ -2547,13 +2617,13 @@ class Fetch extends ObjectValue {
2547
2617
  ];
2548
2618
  },
2549
2619
  });
2550
- super(scope, data);
2620
+ super(data);
2551
2621
  }
2552
2622
  }
2553
2623
 
2554
2624
  class GetFlag extends MacroFunction {
2555
- constructor(scope) {
2556
- super(scope, flag => {
2625
+ constructor() {
2626
+ super((scope, flag) => {
2557
2627
  const result = new StoreValue(scope);
2558
2628
  return [result, [new InstructionBase("getflag", result, flag)]];
2559
2629
  });
@@ -2561,8 +2631,8 @@ class GetFlag extends MacroFunction {
2561
2631
  }
2562
2632
 
2563
2633
  class SetFlag extends MacroFunction {
2564
- constructor(scope) {
2565
- super(scope, (flag, value) => {
2634
+ constructor() {
2635
+ super((scope, flag, value) => {
2566
2636
  if (!flag)
2567
2637
  throw new CompilerError("Missing flag argument");
2568
2638
  if (!value)
@@ -2572,36 +2642,48 @@ class SetFlag extends MacroFunction {
2572
2642
  }
2573
2643
  }
2574
2644
 
2575
- class MemoryEntry extends ObjectValue {
2645
+ class MemoryEntry extends BaseValue {
2576
2646
  constructor(scope, mem, prop) {
2577
- super(scope, {
2578
- $eval: new MacroFunction(scope, () => {
2579
- if (this.store)
2580
- return [this.store, []];
2581
- const temp = new StoreValue(scope);
2582
- return [temp, [new InstructionBase("read", temp, mem.cell, prop)]];
2583
- }),
2584
- $consume: new MacroFunction(scope, () => {
2585
- if (this.store)
2586
- return [this.store, []];
2587
- this.ensureOwned();
2588
- this.store = new StoreValue(scope);
2589
- this.owner.own(this.store);
2590
- return [
2591
- this.store,
2592
- [new InstructionBase("read", this.store, mem.cell, prop)],
2593
- ];
2594
- }),
2595
- "$=": new MacroFunction(scope, value => {
2596
- const [data, dataInst] = value.consume(scope);
2597
- return [
2598
- data,
2599
- [...dataInst, new InstructionBase("write", data, mem.cell, prop)],
2600
- ];
2601
- }),
2602
- });
2647
+ super();
2648
+ this.scope = scope;
2649
+ this.mem = mem;
2650
+ this.prop = prop;
2651
+ this.macro = true;
2603
2652
  this.store = null;
2604
2653
  }
2654
+ eval(scope) {
2655
+ if (this.store)
2656
+ return [this.store, []];
2657
+ const temp = new StoreValue(scope);
2658
+ return [
2659
+ temp,
2660
+ [new InstructionBase("read", temp, this.mem.cell, this.prop)],
2661
+ ];
2662
+ }
2663
+ consume(scope) {
2664
+ if (this.store)
2665
+ return [this.store, []];
2666
+ this.ensureOwned();
2667
+ this.store = new StoreValue(scope);
2668
+ this.owner.own(this.store);
2669
+ return [
2670
+ this.store,
2671
+ [new InstructionBase("read", this.store, this.mem.cell, this.prop)],
2672
+ ];
2673
+ }
2674
+ "="(scope, value) {
2675
+ const [data, dataInst] = value.consume(scope);
2676
+ return [
2677
+ data,
2678
+ [
2679
+ ...dataInst,
2680
+ new InstructionBase("write", data, this.mem.cell, this.prop),
2681
+ ],
2682
+ ];
2683
+ }
2684
+ ensureOwned() {
2685
+ this.owner ??= new ValueOwner({ scope: this.scope, value: this });
2686
+ }
2605
2687
  }
2606
2688
  for (const operator of operators) {
2607
2689
  if (operator === "=")
@@ -2612,9 +2694,9 @@ for (const operator of operators) {
2612
2694
  };
2613
2695
  }
2614
2696
  class MemoryMacro extends ObjectValue {
2615
- constructor(scope, cell, size) {
2616
- super(scope, {
2617
- $get: new MacroFunction(scope, (prop) => {
2697
+ constructor(cell, size) {
2698
+ super({
2699
+ $get: new MacroFunction((scope, prop) => {
2618
2700
  if (prop instanceof LiteralValue && typeof prop.data !== "number")
2619
2701
  throw new CompilerError(`Invalid memory object property: "${prop.data}"`);
2620
2702
  const obj = new MemoryEntry(scope, this, prop);
@@ -2624,21 +2706,20 @@ class MemoryMacro extends ObjectValue {
2624
2706
  size,
2625
2707
  });
2626
2708
  this.cell = cell;
2627
- this.name = cell.toString();
2628
2709
  }
2629
2710
  toString() {
2630
- return this.name;
2711
+ return this.cell.toString();
2631
2712
  }
2632
2713
  }
2633
2714
  class MemoryBuilder extends ObjectValue {
2634
- constructor(scope) {
2635
- super(scope, {
2636
- $call: new MacroFunction(scope, (cell, size = new LiteralValue(scope, 64)) => {
2715
+ constructor() {
2716
+ super({
2717
+ $call: new MacroFunction((scope, cell, size = new LiteralValue(64)) => {
2637
2718
  if (!(cell instanceof SenseableValue))
2638
2719
  throw new CompilerError("Memory cell must be a senseable value.");
2639
2720
  if (!(size instanceof LiteralValue && typeof size.data === "number"))
2640
2721
  throw new CompilerError("The memory size must be a number literal.");
2641
- return [new MemoryMacro(scope, cell, size), []];
2722
+ return [new MemoryMacro(cell, size), []];
2642
2723
  }),
2643
2724
  });
2644
2725
  }
@@ -2646,9 +2727,9 @@ class MemoryBuilder extends ObjectValue {
2646
2727
 
2647
2728
  const dynamicVars = ["time", "tick"];
2648
2729
  class NamespaceMacro extends ObjectValue {
2649
- constructor(scope, { changeCasing = false } = {}) {
2650
- super(scope, {
2651
- $get: new MacroFunction(scope, prop => {
2730
+ constructor({ changeCasing = false } = {}) {
2731
+ super({
2732
+ $get: new MacroFunction((scope, prop) => {
2652
2733
  if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
2653
2734
  throw new CompilerError("Cannot use dynamic properties on namespace macros");
2654
2735
  const symbolName = this.changeCasing
@@ -2672,7 +2753,7 @@ class NamespaceMacro extends ObjectValue {
2672
2753
  }
2673
2754
  class VarsNamespace extends NamespaceMacro {
2674
2755
  constructor(scope) {
2675
- super(scope);
2756
+ super();
2676
2757
  Object.assign(this.data, {
2677
2758
  unit: new ValueOwner({
2678
2759
  scope,
@@ -2689,8 +2770,8 @@ class VarsNamespace extends NamespaceMacro {
2689
2770
  }
2690
2771
 
2691
2772
  class GetGlobal extends MacroFunction {
2692
- constructor(scope, mutability) {
2693
- super(scope, (name) => {
2773
+ constructor(mutability) {
2774
+ super((scope, name) => {
2694
2775
  if (!(name instanceof LiteralValue) || typeof name.data !== "string")
2695
2776
  throw new CompilerError("The name parameter must be a string literal.");
2696
2777
  const owner = new ValueOwner({
@@ -2706,22 +2787,77 @@ class GetGlobal extends MacroFunction {
2706
2787
  }
2707
2788
 
2708
2789
  class Asm extends MacroFunction {
2709
- constructor(scope) {
2710
- super(scope, (stringsArray, ...values) => {
2790
+ constructor() {
2791
+ super((scope, stringsArray, ...values) => {
2711
2792
  if (!isTemplateObjectArray(stringsArray))
2712
2793
  throw new CompilerError("Expected to receive a template strings array");
2713
2794
  const args = [];
2714
2795
  for (let i = 0; i < values.length; i++) {
2715
- const [item] = stringsArray.get(scope, new LiteralValue(scope, i));
2796
+ const [item] = stringsArray.get(scope, new LiteralValue(i));
2716
2797
  args.push(item.data);
2717
2798
  args.push(values[i]);
2718
2799
  }
2719
2800
  const { length } = stringsArray.data;
2720
- const [tail] = stringsArray.get(scope, new LiteralValue(scope, length.data - 1));
2801
+ const [tail] = stringsArray.get(scope, new LiteralValue(length.data - 1));
2721
2802
  args.push(tail.data);
2722
- return [null, [new ZeroSpaceInstruction(...args)]];
2803
+ return [null, formatInstructions(args)];
2723
2804
  });
2724
2805
  }
2806
+ }
2807
+ /** Splits multiline asm calls and formats each line. */
2808
+ function formatInstructions(args) {
2809
+ const instructions = [];
2810
+ let buffer = [];
2811
+ for (let i = 0; i < args.length; i++) {
2812
+ const arg = args[i];
2813
+ if (typeof arg !== "string" || !arg.includes("\n")) {
2814
+ buffer.push(arg);
2815
+ continue;
2816
+ }
2817
+ const segments = arg.split("\n");
2818
+ const params = [...buffer, segments[0]];
2819
+ if (validateInstructionArgs(params)) {
2820
+ instructions.push(new ZeroSpaceInstruction(...params));
2821
+ buffer = [];
2822
+ }
2823
+ // iterates over all segments except the first and last
2824
+ // the first segment was already processed above
2825
+ // the last segment will be added to the buffer because there might
2826
+ // be an interpolation after it
2827
+ // and putting it in the buffer makes sure it has a proper output format
2828
+ for (let i = 1; i < segments.length - 1; i++) {
2829
+ const trimmed = segments[i].trim();
2830
+ if (trimmed.length == 0)
2831
+ continue;
2832
+ instructions.push(new ZeroSpaceInstruction(trimmed));
2833
+ }
2834
+ if (segments.length > 1) {
2835
+ buffer.push(segments[segments.length - 1]);
2836
+ }
2837
+ }
2838
+ if (buffer.length > 0 && validateInstructionArgs(buffer)) {
2839
+ instructions.push(new ZeroSpaceInstruction(...buffer));
2840
+ }
2841
+ return instructions;
2842
+ }
2843
+ /** Determines if an asm line should be generated and trims it at the start and end */
2844
+ function validateInstructionArgs(args) {
2845
+ if (args.length === 0)
2846
+ return false;
2847
+ if (args.length === 1) {
2848
+ const item = args[0];
2849
+ if (typeof item !== "string")
2850
+ return true;
2851
+ args[0] = item.trim();
2852
+ return args[0].length !== 0;
2853
+ }
2854
+ const first = args[0];
2855
+ const last = args[args.length - 1];
2856
+ if (typeof first === "string")
2857
+ args[0] = first.trimStart();
2858
+ if (typeof last === "string")
2859
+ args[args.length - 1] = last.trimEnd();
2860
+ return true;
2725
2861
  }
2726
2862
 
2727
2863
  /**
@@ -2729,53 +2865,53 @@ class Asm extends MacroFunction {
2729
2865
  */
2730
2866
  function initScope(scope) {
2731
2867
  // namespaces
2732
- scope.hardSet("ControlKind", new NamespaceMacro(scope));
2868
+ scope.hardSet("ControlKind", new NamespaceMacro());
2733
2869
  scope.hardSet("Vars", new VarsNamespace(scope));
2734
- scope.hardSet("Teams", new NamespaceMacro(scope));
2735
- scope.hardSet("Items", new NamespaceMacro(scope, { changeCasing: true }));
2736
- scope.hardSet("Liquids", new NamespaceMacro(scope));
2737
- scope.hardSet("Units", new NamespaceMacro(scope, { changeCasing: true }));
2738
- scope.hardSet("LAccess", new NamespaceMacro(scope));
2739
- scope.hardSet("Blocks", new NamespaceMacro(scope, { changeCasing: true }));
2870
+ scope.hardSet("Teams", new NamespaceMacro());
2871
+ scope.hardSet("Items", new NamespaceMacro({ changeCasing: true }));
2872
+ scope.hardSet("Liquids", new NamespaceMacro());
2873
+ scope.hardSet("Units", new NamespaceMacro({ changeCasing: true }));
2874
+ scope.hardSet("LAccess", new NamespaceMacro());
2875
+ scope.hardSet("Blocks", new NamespaceMacro({ changeCasing: true }));
2740
2876
  // helper methods
2741
- scope.hardSet("getBuilding", new GetGlobal(scope, EMutability.constant));
2742
- scope.hardSet("getVar", new GetGlobal(scope, EMutability.mutable));
2743
- scope.hardSet("concat", new Concat(scope));
2744
- scope.hardSet("asm", new Asm(scope));
2877
+ scope.hardSet("getBuilding", new GetGlobal(EMutability.constant));
2878
+ scope.hardSet("getVar", new GetGlobal(EMutability.mutable));
2879
+ scope.hardSet("concat", new Concat());
2880
+ scope.hardSet("asm", new Asm());
2745
2881
  scope.hardSet("Math", new MlogMath(scope));
2746
- scope.hardSet("Memory", new MemoryBuilder(scope));
2882
+ scope.hardSet("Memory", new MemoryBuilder());
2747
2883
  // commands
2748
- scope.hardSet("draw", new Draw(scope));
2749
- scope.hardSet("print", new Print(scope));
2750
- scope.hardSet("printFlush", new PrintFlush(scope));
2751
- scope.hardSet("drawFlush", new DrawFlush(scope));
2752
- scope.hardSet("getLink", new GetLink(scope));
2753
- scope.hardSet("control", new Control(scope));
2754
- scope.hardSet("radar", new Radar(scope));
2755
- scope.hardSet("sensor", new Sensor(scope));
2756
- scope.hardSet("wait", new Wait(scope));
2757
- scope.hardSet("lookup", new Lookup(scope));
2758
- scope.hardSet("packColor", new PackColor(scope));
2759
- scope.hardSet("endScript", new End(scope));
2760
- scope.hardSet("stopScript", new Stop(scope));
2761
- scope.hardSet("unitBind", new UnitBind(scope));
2762
- scope.hardSet("unitControl", new UnitControl(scope));
2763
- scope.hardSet("unitRadar", new UnitRadar(scope));
2764
- scope.hardSet("unitLocate", new UnitLocate(scope));
2884
+ scope.hardSet("draw", new Draw());
2885
+ scope.hardSet("print", new Print());
2886
+ scope.hardSet("printFlush", new PrintFlush());
2887
+ scope.hardSet("drawFlush", new DrawFlush());
2888
+ scope.hardSet("getLink", new GetLink());
2889
+ scope.hardSet("control", new Control());
2890
+ scope.hardSet("radar", new Radar());
2891
+ scope.hardSet("sensor", new Sensor());
2892
+ scope.hardSet("wait", new Wait());
2893
+ scope.hardSet("lookup", new Lookup());
2894
+ scope.hardSet("packColor", new PackColor());
2895
+ scope.hardSet("endScript", new End());
2896
+ scope.hardSet("stopScript", new Stop());
2897
+ scope.hardSet("unitBind", new UnitBind());
2898
+ scope.hardSet("unitControl", new UnitControl());
2899
+ scope.hardSet("unitRadar", new UnitRadar());
2900
+ scope.hardSet("unitLocate", new UnitLocate());
2765
2901
  // world processor commands
2766
- scope.hardSet("getBlock", new GetBlock(scope));
2767
- scope.hardSet("setBlock", new SetBlock(scope));
2768
- scope.hardSet("spawnUnit", new SpawnUnit(scope));
2769
- scope.hardSet("applyStatus", new ApplyStatus(scope));
2770
- scope.hardSet("spawnWave", new SpawnWave(scope));
2771
- scope.hardSet("setRule", new SetRule(scope));
2772
- scope.hardSet("flushMessage", new FlushMessage(scope));
2773
- scope.hardSet("cutscene", new Cutscene(scope));
2774
- scope.hardSet("explosion", new Explosion(scope));
2775
- scope.hardSet("setRate", new SetRate(scope));
2776
- scope.hardSet("fetch", new Fetch(scope));
2777
- scope.hardSet("getFlag", new GetFlag(scope));
2778
- scope.hardSet("setFlag", new SetFlag(scope));
2902
+ scope.hardSet("getBlock", new GetBlock());
2903
+ scope.hardSet("setBlock", new SetBlock());
2904
+ scope.hardSet("spawnUnit", new SpawnUnit());
2905
+ scope.hardSet("applyStatus", new ApplyStatus());
2906
+ scope.hardSet("spawnWave", new SpawnWave());
2907
+ scope.hardSet("setRule", new SetRule());
2908
+ scope.hardSet("flushMessage", new FlushMessage());
2909
+ scope.hardSet("cutscene", new Cutscene());
2910
+ scope.hardSet("explosion", new Explosion());
2911
+ scope.hardSet("setRate", new SetRate());
2912
+ scope.hardSet("fetch", new Fetch());
2913
+ scope.hardSet("getFlag", new GetFlag());
2914
+ scope.hardSet("setFlag", new SetFlag());
2779
2915
  }
2780
2916
 
2781
2917
  class Compiler {
@@ -2882,7 +3018,7 @@ class Compiler {
2882
3018
  */
2883
3019
  handleMany(scope, nodes, handler) {
2884
3020
  const lines = [];
2885
- for (const node of nodes) {
3021
+ for (const node of hoistedFunctionNodes(nodes)) {
2886
3022
  const [, nodeLines] = this.handle(scope, node, handler && (() => handler(node)));
2887
3023
  lines.push(...nodeLines);
2888
3024
  }
@@ -2912,6 +3048,20 @@ function hideRedundantJumps(inst) {
2912
3048
  current = inst[searchIndex];
2913
3049
  }
2914
3050
  }
3051
+ }
3052
+ function* hoistedFunctionNodes(nodes) {
3053
+ // sorting is O(n long n) while this is just O(n)
3054
+ // besides, it's better not to modify the node array
3055
+ for (const node of nodes) {
3056
+ if (node.type === "FunctionDeclaration") {
3057
+ yield node;
3058
+ }
3059
+ }
3060
+ for (const node of nodes) {
3061
+ if (node.type !== "FunctionDeclaration") {
3062
+ yield node;
3063
+ }
3064
+ }
2915
3065
  }
2916
3066
 
2917
3067
  export { Compiler, CompilerError };