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.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
  ">>=",
@@ -171,11 +171,10 @@ const singleOperators = [...unaryOperators, ...updateOperators];
171
171
  const operators = [...leftRightOperators, ...singleOperators];
172
172
 
173
173
  class VoidValue {
174
- constructor(scope) {
174
+ constructor() {
175
175
  this.owner = null;
176
176
  this.mutability = EMutability.mutable;
177
177
  this.macro = false;
178
- this.scope = scope;
179
178
  }
180
179
  eval(_scope) {
181
180
  throw new CompilerError(`${this} cannot eval.`);
@@ -232,8 +231,22 @@ class SetInstruction extends InstructionBase {
232
231
  constructor(store, value) {
233
232
  super("set", store, value);
234
233
  }
234
+ get store() {
235
+ return this.args[1];
236
+ }
237
+ get value() {
238
+ return this.args[2];
239
+ }
235
240
  get hidden() {
236
- 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));
237
250
  }
238
251
  }
239
252
 
@@ -312,38 +325,6 @@ class ContinueInstruction extends JumpInstruction {
312
325
  }
313
326
  }
314
327
 
315
- class ValueOwner {
316
- /**
317
- * Creates a new `ValueOwner`, if `value` is already owned,
318
- * `this` will be aliased to `value`, else `this` will own `value`
319
- */
320
- constructor({ scope, constant = false, value, identifier, name, }) {
321
- this.scope = scope;
322
- this.constant = constant;
323
- this.value = value;
324
- this.identifier = identifier;
325
- this.name = name ?? scope.makeTempName();
326
- this.persistent = !!name;
327
- this.owned = new Set();
328
- if (!value.owner?.persistent)
329
- this.own(value);
330
- }
331
- own(target) {
332
- target.owner = this;
333
- this.owned.add(target);
334
- }
335
- replace(target) {
336
- this.value.owner = null;
337
- this.owned.delete(this.value);
338
- this.value = target;
339
- this.own(target);
340
- }
341
- moveInto(owner) {
342
- this.owned.forEach(value => owner.own(value));
343
- this.owned.clear();
344
- }
345
- }
346
-
347
328
  class BaseValue extends VoidValue {
348
329
  "u-"(scope) {
349
330
  const [that, inst] = this.consume(scope);
@@ -352,7 +333,7 @@ class BaseValue extends VoidValue {
352
333
  temp,
353
334
  [
354
335
  ...inst,
355
- new OperationInstruction("sub", temp, new LiteralValue(scope, 0), that),
336
+ new OperationInstruction("sub", temp, new LiteralValue(0), that),
356
337
  ],
357
338
  ];
358
339
  }
@@ -363,7 +344,7 @@ class BaseValue extends VoidValue {
363
344
  "!"(scope) {
364
345
  const [that, inst] = this.consume(scope);
365
346
  const temp = new StoreValue(scope);
366
- const falseLiteral = new LiteralValue(scope, 0);
347
+ const falseLiteral = new LiteralValue(0);
367
348
  return [
368
349
  temp,
369
350
  [...inst, new OperationInstruction("equal", temp, that, falseLiteral)],
@@ -374,8 +355,33 @@ class BaseValue extends VoidValue {
374
355
  const temp = new StoreValue(scope);
375
356
  return [temp, [...inst, new OperationInstruction("not", temp, that, null)]];
376
357
  }
377
- ensureOwned() {
378
- this.owner ??= new ValueOwner({ scope: this.scope, value: this });
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
+ ];
379
385
  }
380
386
  }
381
387
  const operatorMap$1 = {
@@ -433,6 +439,7 @@ const assignmentToBinary = {
433
439
  "<<=": "<<",
434
440
  "&&=": "&&",
435
441
  "||=": "||",
442
+ "??=": "??",
436
443
  };
437
444
  for (const op in assignmentToBinary) {
438
445
  BaseValue.prototype[op] = function (scope, value) {
@@ -452,23 +459,20 @@ for (const key of updateOperators) {
452
459
  inst.push(...tempInst);
453
460
  }
454
461
  const kind = key === "++" ? "+=" : "-=";
455
- return [
456
- ret,
457
- [...inst, ...this[kind](scope, new LiteralValue(scope, 1))[1]],
458
- ];
462
+ return [ret, [...inst, ...this[kind](scope, new LiteralValue(1))[1]]];
459
463
  };
460
464
  }
461
465
 
462
466
  const literalMethods = {
463
- length: function (scope) {
467
+ length: function () {
464
468
  if (typeof this.data !== "string")
465
469
  throw new CompilerError("Length method only works on string literal values.");
466
- return new LiteralValue(scope, this.data.length);
470
+ return new LiteralValue(this.data.length);
467
471
  },
468
472
  };
469
473
  class LiteralValue extends BaseValue {
470
- constructor(scope, data) {
471
- super(scope);
474
+ constructor(data) {
475
+ super();
472
476
  this.mutability = EMutability.constant;
473
477
  this.data = data;
474
478
  }
@@ -496,9 +500,10 @@ class LiteralValue extends BaseValue {
496
500
  return 1;
497
501
  return this.data;
498
502
  }
499
- typeof(scope) {
500
- return [new LiteralValue(scope, "literal"), []];
503
+ typeof() {
504
+ return [new LiteralValue("literal"), []];
501
505
  }
506
+ ensureOwned() { }
502
507
  }
503
508
  const operatorMap = {
504
509
  "==": (a, b) => +(a == b),
@@ -530,10 +535,7 @@ for (const key in operatorMap) {
530
535
  if (!(value instanceof LiteralValue)) {
531
536
  return BaseValue.prototype[key].apply(this, [scope, value]);
532
537
  }
533
- return [
534
- new LiteralValue(scope, fn(this.data, value.data)),
535
- [],
536
- ];
538
+ return [new LiteralValue(fn(this.data, value.data)), []];
537
539
  };
538
540
  }
539
541
  const unaryOperatorMap = {
@@ -543,9 +545,9 @@ const unaryOperatorMap = {
543
545
  "u+": v => +v,
544
546
  };
545
547
  for (const key in unaryOperatorMap) {
546
- LiteralValue.prototype[key] = function (scope) {
548
+ LiteralValue.prototype[key] = function () {
547
549
  const fn = unaryOperatorMap[key];
548
- return [new LiteralValue(scope, fn(this.data)), []];
550
+ return [new LiteralValue(fn(this.data)), []];
549
551
  };
550
552
  }
551
553
 
@@ -624,17 +626,50 @@ function isTemplateObjectArray(value) {
624
626
  typeof value.data.raw.data.length.data === "number");
625
627
  }
626
628
 
629
+ class ValueOwner {
630
+ /**
631
+ * Creates a new `ValueOwner`, if `value` is already owned,
632
+ * `this` will be aliased to `value`, else `this` will own `value`
633
+ */
634
+ constructor({ scope, constant = false, value, identifier, name, }) {
635
+ this.scope = scope;
636
+ this.constant = constant;
637
+ this.value = value;
638
+ this.identifier = identifier;
639
+ this.name = name ?? scope.makeTempName();
640
+ this.persistent = !!name;
641
+ this.owned = new Set();
642
+ if (!value.owner?.persistent)
643
+ this.own(value);
644
+ }
645
+ own(target) {
646
+ target.owner = this;
647
+ this.owned.add(target);
648
+ }
649
+ replace(target) {
650
+ this.value.owner = null;
651
+ this.owned.delete(this.value);
652
+ this.value = target;
653
+ this.own(target);
654
+ }
655
+ moveInto(owner) {
656
+ this.owned.forEach(value => owner.own(value));
657
+ this.owned.clear();
658
+ }
659
+ }
660
+
627
661
  /**
628
662
  * `StoreValue` represents values unknown at compile time,
629
663
  * mostly used with mutable variables and temporary values
630
664
  */
631
665
  class StoreValue extends BaseValue {
632
666
  constructor(scope) {
633
- super(scope);
667
+ super();
668
+ this.scope = scope;
634
669
  this.mutability = EMutability.mutable;
635
670
  }
636
- typeof(scope) {
637
- return [new LiteralValue(scope, "store"), []];
671
+ typeof() {
672
+ return [new LiteralValue("store"), []];
638
673
  }
639
674
  "="(scope, value) {
640
675
  if (this.mutability !== EMutability.mutable)
@@ -661,31 +696,34 @@ class StoreValue extends BaseValue {
661
696
  this.ensureOwned();
662
697
  return [this, []];
663
698
  }
699
+ ensureOwned() {
700
+ this.owner ??= new ValueOwner({ scope: this.scope, value: this });
701
+ }
664
702
  toString() {
665
703
  return this.owner?.name ?? discardedName;
666
704
  }
667
705
  }
668
706
 
669
707
  class ObjectValue extends VoidValue {
670
- constructor(scope, data = {}) {
671
- super(scope);
708
+ constructor(data = {}) {
709
+ super();
672
710
  this.mutability = EMutability.constant;
673
711
  this.macro = true;
674
712
  this.data = data;
675
713
  }
676
- static fromArray(scope, items, intialData) {
714
+ static fromArray(items, intialData) {
677
715
  const data = {
678
716
  ...intialData,
679
- length: new LiteralValue(scope, items.length),
717
+ length: new LiteralValue(items.length),
680
718
  };
681
719
  items.forEach((item, i) => {
682
720
  if (item)
683
721
  data[i] = item;
684
722
  });
685
- return new ObjectValue(scope, data);
723
+ return new ObjectValue(data);
686
724
  }
687
- typeof(scope) {
688
- return [new LiteralValue(scope, "object"), []];
725
+ typeof() {
726
+ return [new LiteralValue("object"), []];
689
727
  }
690
728
  get(scope, key) {
691
729
  // avoids naming collisions with keys like
@@ -722,9 +760,7 @@ class ObjectValue extends VoidValue {
722
760
  return super.call(scope, args);
723
761
  return $call.call(scope, args);
724
762
  }
725
- ensureOwned() {
726
- this.owner ??= new ValueOwner({ scope: this.scope, value: this });
727
- }
763
+ ensureOwned() { }
728
764
  }
729
765
  for (const op of operators) {
730
766
  ObjectValue.prototype[op] = function (...args) {
@@ -793,8 +829,8 @@ class SenseableValue extends StoreValue {
793
829
  * each of them to their counterparts on the right hand value.
794
830
  */
795
831
  class DestructuringValue extends VoidValue {
796
- constructor(scope, members) {
797
- super(scope);
832
+ constructor(members) {
833
+ super();
798
834
  this.members = members;
799
835
  this.macro = true;
800
836
  }
@@ -981,7 +1017,7 @@ const DeclareObjectPattern = (c, scope, node, kind, base) => {
981
1017
  throw new CompilerError("The rest operator is not supported", prop);
982
1018
  const { key, value } = prop;
983
1019
  const keyInst = key.type === "Identifier" && !prop.computed
984
- ? [new LiteralValue(scope, key.name), []]
1020
+ ? [new LiteralValue(key.name), []]
985
1021
  : c.handleConsume(scope, prop.key);
986
1022
  const propInit = init.get(scope, keyInst[0]);
987
1023
  const declarationInst = Declare(c, scope, value, kind, propInit[0]);
@@ -990,14 +1026,14 @@ const DeclareObjectPattern = (c, scope, node, kind, base) => {
990
1026
  return [null, [...inst, ...propertiesInst[1]]];
991
1027
  };
992
1028
 
993
- const Literal = (_c, scope, node) => [new LiteralValue(scope, node.value), []];
1029
+ const Literal = (_c, scope, node) => [new LiteralValue(node.value), []];
994
1030
  const NumericLiteral = Literal;
995
1031
  const StringLiteral = Literal;
996
- const NullLiteral = (_c, scope) => [
997
- new LiteralValue(scope, null),
1032
+ const NullLiteral = () => [
1033
+ new LiteralValue(null),
998
1034
  [],
999
1035
  ];
1000
- const BooleanLiteral = (_c, scope, node) => [new LiteralValue(scope, +node.value), []];
1036
+ const BooleanLiteral = (_c, scope, node) => [new LiteralValue(+node.value), []];
1001
1037
 
1002
1038
  const LRExpression = (c, scope, node) => {
1003
1039
  const [left, leftInst] = c.handleConsume(scope, node.left);
@@ -1009,35 +1045,26 @@ const BinaryExpression = LRExpression;
1009
1045
  const LogicalExpression = (c, scope, node) => {
1010
1046
  if (node.operator !== "??")
1011
1047
  return LRExpression(c, scope, node);
1012
- const nullLiteral = new LiteralValue(scope, null);
1013
- const endAdress = new LiteralValue(scope, null);
1048
+ const other = lazyValue({
1049
+ eval: scope => c.handleEval(scope, node.right),
1050
+ consume: scope => c.handleConsume(scope, node.right),
1051
+ });
1014
1052
  const [left, leftInst] = c.handleEval(scope, node.left);
1015
- const [nullTest] = left["=="](scope, nullLiteral);
1016
- if (nullTest instanceof LiteralValue) {
1017
- if (nullTest.data)
1018
- return c.handleEval(scope, node.right);
1019
- else
1020
- return [left, leftInst];
1021
- }
1022
- const [right, rightInst] = c.handleEval(scope, node.right);
1023
- const result = new StoreValue(scope);
1024
- result.ensureOwned();
1025
- return [
1026
- result,
1027
- [
1028
- ...leftInst,
1029
- ...result["="](scope, left)[1],
1030
- new JumpInstruction(endAdress, EJumpKind.NotEqual, result, nullLiteral),
1031
- ...rightInst,
1032
- ...result["="](scope, right)[1],
1033
- new AddressResolver(endAdress),
1034
- ],
1035
- ];
1053
+ const [result, resultInst] = left["??"](scope, other);
1054
+ return [result, [...leftInst, ...resultInst]];
1036
1055
  };
1037
1056
  const AssignmentExpression = (c, scope, node) => {
1038
1057
  const [left, leftInst] = c.handle(scope, node.left);
1039
1058
  // doesn't need to consume because the operators already do that
1040
- 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
+ ];
1041
1068
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1042
1069
  const [op, opInst] = left[node.operator](scope, right);
1043
1070
  return [op, [...leftInst, ...rightInst, ...opInst]];
@@ -1069,13 +1096,13 @@ const ConditionalExpression = (c, scope, node) => {
1069
1096
  result.ensureOwned();
1070
1097
  const consequent = c.handleEval(scope, node.consequent);
1071
1098
  const alternate = c.handleEval(scope, node.alternate);
1072
- const alternateStartAdress = new LiteralValue(scope, null);
1073
- const endExpressionAdress = new LiteralValue(scope, null);
1099
+ const alternateStartAdress = new LiteralValue(null);
1100
+ const endExpressionAdress = new LiteralValue(null);
1074
1101
  return [
1075
1102
  result,
1076
1103
  [
1077
1104
  ...testInst,
1078
- new JumpInstruction(alternateStartAdress, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
1105
+ new JumpInstruction(alternateStartAdress, EJumpKind.Equal, test, new LiteralValue(0)),
1079
1106
  ...consequent[1],
1080
1107
  ...result["="](scope, consequent[0])[1],
1081
1108
  new JumpInstruction(endExpressionAdress, EJumpKind.Always),
@@ -1085,7 +1112,13 @@ const ConditionalExpression = (c, scope, node) => {
1085
1112
  new AddressResolver(endExpressionAdress),
1086
1113
  ],
1087
1114
  ];
1088
- };
1115
+ };
1116
+ function lazyValue(options) {
1117
+ const value = new VoidValue();
1118
+ value.eval = options.eval;
1119
+ value.consume = options.consume;
1120
+ return value;
1121
+ }
1089
1122
 
1090
1123
  const Identifier = (c, scope, node) => {
1091
1124
  return [scope.get(node.name), []];
@@ -1094,14 +1127,18 @@ const Identifier = (c, scope, node) => {
1094
1127
  const ExpressionStatement = (c, scope, node) => {
1095
1128
  return c.handle(scope, node.expression);
1096
1129
  };
1097
- const BreakStatement = (_, scope) => {
1098
- const addr = new LiteralValue(scope, null);
1099
- scope.break.bind(addr);
1130
+ const BreakStatement = (_, scope, node) => {
1131
+ const label = node.label?.name;
1132
+ const target = label ? findScopeLabel(scope, label) : scope;
1133
+ const addr = new LiteralValue(null);
1134
+ target.break.bind(addr);
1100
1135
  return [null, [new BreakInstruction(addr)]];
1101
1136
  };
1102
- const ContinueStatement = (_, scope) => {
1103
- const addr = new LiteralValue(scope, null);
1104
- scope.continue.bind(addr);
1137
+ const ContinueStatement = (_, scope, node) => {
1138
+ const addr = new LiteralValue(null);
1139
+ const label = node.label?.name;
1140
+ const target = label ? findScopeLabel(scope, label) : scope;
1141
+ target.continue.bind(addr);
1105
1142
  return [null, [new ContinueInstruction(addr)]];
1106
1143
  };
1107
1144
  const ReturnStatement = (c, scope, node) => {
@@ -1110,7 +1147,24 @@ const ReturnStatement = (c, scope, node) => {
1110
1147
  : [null, []];
1111
1148
  const [ret, retInst] = scope.function.return(scope, arg);
1112
1149
  return [ret, [...argInst, ...retInst]];
1113
- };
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
+ }
1114
1168
 
1115
1169
  const IfStatement = (c, scope, node) => {
1116
1170
  const inst = [];
@@ -1122,9 +1176,9 @@ const IfStatement = (c, scope, node) => {
1122
1176
  inst.push(...c.handle(scope, node.alternate)[1]);
1123
1177
  return [null, inst];
1124
1178
  }
1125
- const endIfAddr = new LiteralValue(scope, null);
1126
- inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...withAlwaysRuns(c.handle(scope, node.consequent), false)[1], new AddressResolver(endIfAddr));
1127
- const endElseAddr = new LiteralValue(scope, null);
1179
+ const endIfAddr = new LiteralValue(null);
1180
+ inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(0)), ...withAlwaysRuns(c.handle(scope, node.consequent), false)[1], new AddressResolver(endIfAddr));
1181
+ const endElseAddr = new LiteralValue(null);
1128
1182
  if (node.alternate) {
1129
1183
  inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...withAlwaysRuns(c.handle(scope, node.alternate), false)[1], new AddressResolver(endElseAddr));
1130
1184
  }
@@ -1135,13 +1189,13 @@ const SwitchStatement = (c, scope, node) => {
1135
1189
  const innerScope = scope.createScope();
1136
1190
  const [ref, refInst] = c.handleConsume(scope, node.discriminant);
1137
1191
  const inst = [];
1138
- const endAdress = new LiteralValue(innerScope, null);
1192
+ const endAdress = new LiteralValue(null);
1139
1193
  const endLine = new AddressResolver(endAdress).bindBreak(innerScope);
1140
1194
  const caseJumps = [];
1141
1195
  let defaultJump;
1142
1196
  for (const scase of node.cases) {
1143
1197
  const [, bodyInst] = c.handleMany(innerScope, scase.consequent);
1144
- const bodyAdress = new LiteralValue(innerScope, null);
1198
+ const bodyAdress = new LiteralValue(null);
1145
1199
  const bodyLine = new AddressResolver(bodyAdress);
1146
1200
  if (!scase.test) {
1147
1201
  [defaultJump] = c.handle(innerScope, scase, () => [
@@ -1195,25 +1249,33 @@ const SwitchStatement = (c, scope, node) => {
1195
1249
  const WhileStatement = (c, scope, node) => {
1196
1250
  const lines = [];
1197
1251
  const [test, testLines] = c.handleConsume(scope, node.test);
1198
- const startLoopAddr = new LiteralValue(scope, null);
1199
- const endLoopAddr = new LiteralValue(scope, null);
1200
- const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1201
- const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1252
+ const childScope = scope.createScope();
1253
+ const startLoopAddr = new LiteralValue(null);
1254
+ const endLoopAddr = new LiteralValue(null);
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
+ }
1202
1260
  if (test instanceof LiteralValue) {
1203
1261
  if (test.data) {
1204
- 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);
1205
1263
  }
1206
1264
  return [null, lines];
1207
1265
  }
1208
- 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);
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);
1209
1267
  return [null, lines];
1210
1268
  };
1211
1269
  const DoWhileStatement = (c, scope, node) => {
1212
1270
  const lines = [];
1213
1271
  const [test, testLines] = c.handleConsume(scope, node.test);
1214
- const startLoopAddr = new LiteralValue(scope, null);
1215
- const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1216
- const [, bodyLines] = c.handle(scope, node.body);
1272
+ const childScope = scope.createScope();
1273
+ const startLoopAddr = new LiteralValue(null);
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);
1217
1279
  if (test instanceof LiteralValue) {
1218
1280
  if (!test.data)
1219
1281
  return [null, [...lines, ...bodyLines]];
@@ -1227,28 +1289,31 @@ const DoWhileStatement = (c, scope, node) => {
1227
1289
  ],
1228
1290
  ];
1229
1291
  }
1230
- lines.push(startLoopLine, ...bodyLines, ...testLines, new JumpInstruction(startLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 1)));
1292
+ lines.push(startLoopLine, ...bodyLines, ...testLines, new JumpInstruction(startLoopAddr, EJumpKind.Equal, test, new LiteralValue(1)));
1231
1293
  return [null, lines];
1232
1294
  };
1233
1295
 
1234
- const ForStatement = (c, scope, node) => {
1235
- scope = scope.createScope();
1296
+ const ForStatement = (c, parentScope, node) => {
1297
+ const scope = parentScope.createScope();
1236
1298
  const initInst = node.init ? c.handle(scope, node.init)[1] : [];
1237
1299
  const [test, testLines] = node.test
1238
1300
  ? c.handleConsume(scope, node.test)
1239
- : [new LiteralValue(scope, 1), []];
1301
+ : [new LiteralValue(1), []];
1240
1302
  const updateLines = node.update ? c.handle(scope, node.update)[1] : [];
1241
- const startLoopAddr = new LiteralValue(scope, null);
1242
- const endLoopAddr = new LiteralValue(scope, null);
1303
+ const startLoopAddr = new LiteralValue(null);
1304
+ const endLoopAddr = new LiteralValue(null);
1243
1305
  const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1244
1306
  const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1307
+ if (parentScope.label) {
1308
+ startLoopLine.bindContinue(parentScope);
1309
+ }
1245
1310
  return [
1246
1311
  null,
1247
1312
  [
1248
1313
  ...initInst,
1249
1314
  startLoopLine,
1250
1315
  ...testLines,
1251
- new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
1316
+ new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(0)),
1252
1317
  ...withAlwaysRuns(c.handle(scope, node.body), false)[1],
1253
1318
  ...updateLines,
1254
1319
  new JumpInstruction(startLoopAddr, EJumpKind.Always),
@@ -1258,20 +1323,20 @@ const ForStatement = (c, scope, node) => {
1258
1323
  };
1259
1324
 
1260
1325
  class FunctionValue extends VoidValue {
1261
- constructor({ scope, params, body, c, node, }) {
1262
- super(scope);
1326
+ constructor({ scope, params, body, c, }) {
1327
+ super();
1263
1328
  this.mutability = EMutability.constant;
1264
1329
  this.macro = true;
1265
1330
  this.paramOwners = [];
1266
1331
  this.bundled = false;
1267
1332
  this.initialized = false;
1333
+ this.scope = scope;
1268
1334
  this.body = body;
1269
1335
  this.c = c;
1270
- this.node = node;
1271
1336
  this.params = params;
1272
1337
  }
1273
- typeof(scope) {
1274
- return [new LiteralValue(scope, "function"), []];
1338
+ typeof() {
1339
+ return [new LiteralValue("function"), []];
1275
1340
  }
1276
1341
  initScope(name) {
1277
1342
  this.childScope = this.scope.createFunction(name);
@@ -1299,7 +1364,7 @@ class FunctionValue extends VoidValue {
1299
1364
  this.initialized = true;
1300
1365
  const { name } = this.owner;
1301
1366
  this.initScope(name);
1302
- this.addr = new LiteralValue(this.childScope, null);
1367
+ this.addr = new LiteralValue(null);
1303
1368
  this.temp = new ValueOwner({
1304
1369
  scope: this.childScope,
1305
1370
  name: `${internalPrefix}f${name}`,
@@ -1333,7 +1398,7 @@ class FunctionValue extends VoidValue {
1333
1398
  if (!this.bundled)
1334
1399
  this.childScope.inst.push(...this.inst);
1335
1400
  this.bundled = true;
1336
- const callAddressLiteral = new LiteralValue(scope, null);
1401
+ const callAddressLiteral = new LiteralValue(null);
1337
1402
  const inst = this.paramOwners
1338
1403
  .map(({ value: param }, i) => param["="](scope, args[i])[1])
1339
1404
  .reduce((s, c) => s.concat(c), [])
@@ -1371,7 +1436,7 @@ class FunctionValue extends VoidValue {
1371
1436
  name: owner.name,
1372
1437
  }));
1373
1438
  });
1374
- this.inlineEnd = new LiteralValue(scope, null);
1439
+ this.inlineEnd = new LiteralValue(null);
1375
1440
  this.tryingInline = true;
1376
1441
  let inst = this.c.handle(fnScope, this.body)[1];
1377
1442
  this.tryingInline = false;
@@ -1430,7 +1495,6 @@ function handleFunctionNode(c, scope, node) {
1430
1495
  }
1431
1496
  return [
1432
1497
  new FunctionValue({
1433
- node,
1434
1498
  scope,
1435
1499
  params: params,
1436
1500
  body,
@@ -1476,8 +1540,8 @@ const NewExpression = CallExpression;
1476
1540
  const TaggedTemplateExpression = (c, scope, node) => {
1477
1541
  const [tag, tagInst] = c.handleConsume(scope, node.tag);
1478
1542
  const template = node.quasi;
1479
- const stringsObject = ObjectValue.fromArray(scope, template.quasis.map(quasi => new LiteralValue(scope, quasi.value.cooked ?? "")), {
1480
- raw: ObjectValue.fromArray(scope, template.quasis.map(quasi => new LiteralValue(scope, quasi.value.raw))),
1543
+ const stringsObject = ObjectValue.fromArray(template.quasis.map(quasi => new LiteralValue(quasi.value.cooked ?? "")), {
1544
+ raw: ObjectValue.fromArray(template.quasis.map(quasi => new LiteralValue(quasi.value.raw))),
1481
1545
  });
1482
1546
  const expressions = [];
1483
1547
  const expressionInsts = [];
@@ -1522,7 +1586,7 @@ const ObjectExpression = (c, scope, node) => {
1522
1586
  data[index] = member;
1523
1587
  inst.push(...memberInst);
1524
1588
  }
1525
- return [new ObjectValue(scope, data), inst];
1589
+ return [new ObjectValue(data), inst];
1526
1590
  };
1527
1591
  const ArrayExpression = (c, scope, node) => {
1528
1592
  const items = [];
@@ -1534,13 +1598,13 @@ const ArrayExpression = (c, scope, node) => {
1534
1598
  items.push(value);
1535
1599
  inst.push(...valueInst);
1536
1600
  });
1537
- return [ObjectValue.fromArray(scope, items), inst];
1601
+ return [ObjectValue.fromArray(items), inst];
1538
1602
  };
1539
1603
  const MemberExpression = (c, scope, node) => {
1540
1604
  const [obj, objInst] = c.handleConsume(scope, node.object);
1541
1605
  const [prop, propInst] = node.computed
1542
1606
  ? c.handleConsume(scope, node.property)
1543
- : [new LiteralValue(scope, node.property.name), []];
1607
+ : [new LiteralValue(node.property.name), []];
1544
1608
  const [got, gotInst] = obj.get(scope, prop);
1545
1609
  return [got, [...objInst, ...propInst, ...gotInst]];
1546
1610
  };
@@ -1555,9 +1619,9 @@ const ArrayPattern = (c, scope, node) => {
1555
1619
  if (!valueInst[0])
1556
1620
  throw new CompilerError("Destructuring element must resolve to a value", element);
1557
1621
  inst.push(...valueInst[1]);
1558
- members.set(new LiteralValue(scope, i), valueInst[0]);
1622
+ members.set(new LiteralValue(i), valueInst[0]);
1559
1623
  }
1560
- return [new DestructuringValue(scope, members), inst];
1624
+ return [new DestructuringValue(members), inst];
1561
1625
  };
1562
1626
  const ObjectPattern = (c, scope, node) => {
1563
1627
  const inst = [];
@@ -1569,7 +1633,7 @@ const ObjectPattern = (c, scope, node) => {
1569
1633
  continue;
1570
1634
  const { key } = prop;
1571
1635
  const keyInst = !prop.computed && key.type === "Identifier"
1572
- ? [new LiteralValue(scope, key.name), []]
1636
+ ? [new LiteralValue(key.name), []]
1573
1637
  : c.handleConsume(scope, prop.key);
1574
1638
  inst.push(...keyInst[1]);
1575
1639
  const valueInst = c.handle(scope, prop.value);
@@ -1578,7 +1642,7 @@ const ObjectPattern = (c, scope, node) => {
1578
1642
  inst.push(...valueInst[1]);
1579
1643
  members.set(keyInst[0], valueInst[0]);
1580
1644
  }
1581
- return [new DestructuringValue(scope, members), inst];
1645
+ return [new DestructuringValue(members), inst];
1582
1646
  };
1583
1647
 
1584
1648
  const TemplateLiteral = () => {
@@ -1618,7 +1682,7 @@ const TSEnumDeclaration = (c, scope, node) => {
1618
1682
  throw new CompilerError("This enum member must be initialized", member);
1619
1683
  const [value] = member.initializer
1620
1684
  ? c.handleEval(scope, member.initializer)
1621
- : [new LiteralValue(scope, counter)];
1685
+ : [new LiteralValue(counter)];
1622
1686
  if (!(value instanceof LiteralValue))
1623
1687
  throw new CompilerError("Enum members must contain literal values", member);
1624
1688
  if (typeof value.data === "number") {
@@ -1633,7 +1697,7 @@ const TSEnumDeclaration = (c, scope, node) => {
1633
1697
  }
1634
1698
  scope.set(new ValueOwner({
1635
1699
  scope,
1636
- value: new ObjectValue(scope, data),
1700
+ value: new ObjectValue(data),
1637
1701
  constant: true,
1638
1702
  identifier: node.id.name,
1639
1703
  name: nodeName(node, !c.compactNames && node.id.name),
@@ -1665,6 +1729,7 @@ var handlers = /*#__PURE__*/Object.freeze({
1665
1729
  BreakStatement: BreakStatement,
1666
1730
  ContinueStatement: ContinueStatement,
1667
1731
  ReturnStatement: ReturnStatement,
1732
+ LabeledStatement: LabeledStatement,
1668
1733
  IfStatement: IfStatement,
1669
1734
  SwitchStatement: SwitchStatement,
1670
1735
  WhileStatement: WhileStatement,
@@ -1694,14 +1759,14 @@ var handlers = /*#__PURE__*/Object.freeze({
1694
1759
  });
1695
1760
 
1696
1761
  class MacroFunction extends VoidValue {
1697
- constructor(scope, fn) {
1698
- super(scope);
1762
+ constructor(fn) {
1763
+ super();
1699
1764
  this.macro = true;
1700
- this.constant = true;
1765
+ this.mutability = EMutability.constant;
1701
1766
  this.fn = fn;
1702
1767
  }
1703
1768
  call(scope, args) {
1704
- return this.fn.apply(this, args);
1769
+ return this.fn.apply(this, [scope, ...args]);
1705
1770
  }
1706
1771
  eval(_scope) {
1707
1772
  return [this, []];
@@ -1732,16 +1797,31 @@ const mathOperations = {
1732
1797
  sqrt: a => Math.sqrt(a),
1733
1798
  rand: null,
1734
1799
  };
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
+ }
1735
1810
  function createMacroMathOperations(scope) {
1736
- const macroMathOperations = {};
1811
+ const macroMathOperations = {
1812
+ PI: mathConstant(scope, "@pi"),
1813
+ E: mathConstant(scope, "@e"),
1814
+ degToRad: mathConstant(scope, "@degToRad"),
1815
+ radToDeg: mathConstant(scope, "@radToDeg"),
1816
+ };
1737
1817
  for (const key in mathOperations) {
1738
1818
  const fn = mathOperations[key];
1739
- macroMathOperations[key] = new MacroFunction(scope, (a, b) => {
1819
+ macroMathOperations[key] = new MacroFunction((scope, a, b) => {
1740
1820
  if (b) {
1741
1821
  if (fn && a instanceof LiteralValue && b instanceof LiteralValue) {
1742
1822
  if (typeof a.data !== "number" || typeof b.data !== "number")
1743
1823
  throw new CompilerError("Cannot do math operation with non-numerical literals.");
1744
- return [new LiteralValue(scope, fn(a.num, b.num)), []];
1824
+ return [new LiteralValue(fn(a.num, b.num)), []];
1745
1825
  }
1746
1826
  const temp = new StoreValue(scope);
1747
1827
  return [temp, [new OperationInstruction(key, temp, a, b)]];
@@ -1749,7 +1829,7 @@ function createMacroMathOperations(scope) {
1749
1829
  if (fn && a instanceof LiteralValue) {
1750
1830
  if (typeof a.data !== "number")
1751
1831
  throw new CompilerError("Cannot do math operation with non-numerical literal.");
1752
- return [new LiteralValue(scope, fn(a.num)), []];
1832
+ return [new LiteralValue(fn(a.num)), []];
1753
1833
  }
1754
1834
  const temp = new StoreValue(scope);
1755
1835
  return [temp, [new OperationInstruction(key, temp, a, b)]];
@@ -1759,20 +1839,20 @@ function createMacroMathOperations(scope) {
1759
1839
  }
1760
1840
  class MlogMath extends ObjectValue {
1761
1841
  constructor(scope) {
1762
- super(scope, createMacroMathOperations(scope));
1842
+ super(createMacroMathOperations(scope));
1763
1843
  }
1764
1844
  }
1765
1845
  // op angle result a b
1766
1846
  // op len result a b
1767
1847
 
1768
1848
  class Concat extends MacroFunction {
1769
- constructor(scope) {
1770
- super(scope, (...values) => {
1849
+ constructor() {
1850
+ super((scope, ...values) => {
1771
1851
  for (const value of values)
1772
1852
  if (!(value instanceof LiteralValue))
1773
1853
  throw new CompilerError("Concat arguments must all be literal values.");
1774
1854
  return [
1775
- new LiteralValue(scope, values.map(v => v.data).join("")),
1855
+ new LiteralValue(values.map(v => v.data).join("")),
1776
1856
  [],
1777
1857
  ];
1778
1858
  });
@@ -1827,18 +1907,18 @@ function assertObjectFields(value, fields) {
1827
1907
  }
1828
1908
 
1829
1909
  /** Used to create namespaces that contain multiple methods that map into instructions */
1830
- function createOverloadNamespace({ scope, overloads, handler, }) {
1910
+ function createOverloadNamespace({ overloads, handler, }) {
1831
1911
  const result = {};
1832
1912
  for (const key in overloads) {
1833
1913
  const { named, args } = overloads[key];
1834
1914
  if (named) {
1835
- result[key] = new MacroFunction(scope, options => {
1915
+ result[key] = new MacroFunction((scope, options) => {
1836
1916
  assertIsObjectMacro(options, named);
1837
- return handler(key, ...assertObjectFields(options, args));
1917
+ return handler(scope, key, ...assertObjectFields(options, args));
1838
1918
  });
1839
1919
  continue;
1840
1920
  }
1841
- result[key] = new MacroFunction(scope, (...params) => {
1921
+ result[key] = new MacroFunction((scope, ...params) => {
1842
1922
  const handlerParams = [];
1843
1923
  // validate the paramters
1844
1924
  for (let i = 0; i < args.length; i++) {
@@ -1855,16 +1935,15 @@ function createOverloadNamespace({ scope, overloads, handler, }) {
1855
1935
  arg.validate?.(param);
1856
1936
  handlerParams.push(param);
1857
1937
  }
1858
- return handler(key, ...handlerParams);
1938
+ return handler(scope, key, ...handlerParams);
1859
1939
  });
1860
1940
  }
1861
1941
  return result;
1862
1942
  }
1863
1943
 
1864
1944
  class Draw extends ObjectValue {
1865
- constructor(scope) {
1945
+ constructor() {
1866
1946
  const data = createOverloadNamespace({
1867
- scope,
1868
1947
  overloads: {
1869
1948
  clear: {
1870
1949
  args: ["r", "g", "b"],
@@ -1901,17 +1980,17 @@ class Draw extends ObjectValue {
1901
1980
  args: ["x", "y", "image", "size", "rotation"],
1902
1981
  },
1903
1982
  },
1904
- handler(overload, ...args) {
1983
+ handler(scope, overload, ...args) {
1905
1984
  return [null, [new InstructionBase("draw", overload, ...args)]];
1906
1985
  },
1907
1986
  });
1908
- super(scope, data);
1987
+ super(data);
1909
1988
  }
1910
1989
  }
1911
1990
 
1912
1991
  class Print extends MacroFunction {
1913
- constructor(scope) {
1914
- super(scope, (...values) => {
1992
+ constructor() {
1993
+ super((scope, ...values) => {
1915
1994
  const [first] = values;
1916
1995
  const inst = [];
1917
1996
  if (!isTemplateObjectArray(first)) {
@@ -1924,12 +2003,12 @@ class Print extends MacroFunction {
1924
2003
  // maybe this should be checked in another way?
1925
2004
  const { length } = first.data;
1926
2005
  for (let i = 1; i < values.length; i++) {
1927
- const [string] = first.get(scope, new LiteralValue(scope, i - 1));
2006
+ const [string] = first.get(scope, new LiteralValue(i - 1));
1928
2007
  if (string.data)
1929
2008
  inst.push(new InstructionBase("print", string));
1930
2009
  inst.push(new InstructionBase("print", values[i]));
1931
2010
  }
1932
- const [tail] = first.get(scope, new LiteralValue(scope, length.data - 1));
2011
+ const [tail] = first.get(scope, new LiteralValue(length.data - 1));
1933
2012
  if (tail.data)
1934
2013
  inst.push(new InstructionBase("print", tail));
1935
2014
  return [null, inst];
@@ -1939,8 +2018,8 @@ class Print extends MacroFunction {
1939
2018
 
1940
2019
  const defaultTargetName$1 = "message1";
1941
2020
  class PrintFlush extends MacroFunction {
1942
- constructor(scope) {
1943
- super(scope, (target) => {
2021
+ constructor() {
2022
+ super((scope, target) => {
1944
2023
  if (!target)
1945
2024
  return [null, [new InstructionBase("printflush", defaultTargetName$1)]];
1946
2025
  if (!(target instanceof SenseableValue))
@@ -1952,8 +2031,8 @@ class PrintFlush extends MacroFunction {
1952
2031
 
1953
2032
  const defaultTargetName = "display1";
1954
2033
  class DrawFlush extends MacroFunction {
1955
- constructor(scope) {
1956
- super(scope, (target) => {
2034
+ constructor() {
2035
+ super((scope, target) => {
1957
2036
  if (!target)
1958
2037
  return [null, [new InstructionBase("drawflush", defaultTargetName)]];
1959
2038
  if (!(target instanceof SenseableValue))
@@ -1964,16 +2043,15 @@ class DrawFlush extends MacroFunction {
1964
2043
  }
1965
2044
 
1966
2045
  class GetBlock extends ObjectValue {
1967
- constructor(scope) {
2046
+ constructor() {
1968
2047
  const data = createOverloadNamespace({
1969
- scope,
1970
2048
  overloads: {
1971
2049
  floor: { args: ["x", "y"] },
1972
2050
  ore: { args: ["x", "y"] },
1973
2051
  block: { args: ["x", "y"] },
1974
2052
  building: { args: ["x", "y"] },
1975
2053
  },
1976
- handler(overload, x, y) {
2054
+ handler(scope, overload, x, y) {
1977
2055
  const output = overload === "building"
1978
2056
  ? new SenseableValue(scope)
1979
2057
  : new StoreValue(scope);
@@ -1983,13 +2061,13 @@ class GetBlock extends ObjectValue {
1983
2061
  ];
1984
2062
  },
1985
2063
  });
1986
- super(scope, data);
2064
+ super(data);
1987
2065
  }
1988
2066
  }
1989
2067
 
1990
2068
  class GetLink extends MacroFunction {
1991
- constructor(scope) {
1992
- super(scope, (index) => {
2069
+ constructor() {
2070
+ super((scope, index) => {
1993
2071
  if (!(index instanceof StoreValue) &&
1994
2072
  (!(index instanceof LiteralValue) || typeof index.data !== "number"))
1995
2073
  throw new CompilerError("The getlink index must be a number literal or a store");
@@ -2000,9 +2078,8 @@ class GetLink extends MacroFunction {
2000
2078
  }
2001
2079
 
2002
2080
  class Control extends ObjectValue {
2003
- constructor(scope) {
2004
- super(scope, createOverloadNamespace({
2005
- scope,
2081
+ constructor() {
2082
+ super(createOverloadNamespace({
2006
2083
  overloads: {
2007
2084
  enabled: { args: ["building", "value"] },
2008
2085
  shoot: {
@@ -2016,7 +2093,7 @@ class Control extends ObjectValue {
2016
2093
  config: { args: ["building", "value"] },
2017
2094
  color: { args: ["building", "r", "g", "b"] },
2018
2095
  },
2019
- handler(overload, ...args) {
2096
+ handler(scope, overload, ...args) {
2020
2097
  return [null, [new InstructionBase("control", overload, ...args)]];
2021
2098
  },
2022
2099
  }));
@@ -2041,8 +2118,8 @@ const validRadarSorts = [
2041
2118
  "maxHealth",
2042
2119
  ];
2043
2120
  class Radar extends MacroFunction {
2044
- constructor(scope) {
2045
- super(scope, options => {
2121
+ constructor() {
2122
+ super((scope, options) => {
2046
2123
  assertIsObjectMacro(options, "The radar options");
2047
2124
  const { building, filters, order, sort } = options.data;
2048
2125
  if (!(building instanceof SenseableValue))
@@ -2073,8 +2150,8 @@ class Radar extends MacroFunction {
2073
2150
  }
2074
2151
 
2075
2152
  class Sensor extends MacroFunction {
2076
- constructor(scope) {
2077
- super(scope, (property, target) => {
2153
+ constructor() {
2154
+ super((scope, property, target) => {
2078
2155
  if (!(property instanceof StoreValue))
2079
2156
  throw new CompilerError("The sensor property must be a store");
2080
2157
  if (!(target instanceof SenseableValue))
@@ -2088,8 +2165,8 @@ class Sensor extends MacroFunction {
2088
2165
  }
2089
2166
 
2090
2167
  class Wait extends MacroFunction {
2091
- constructor(scope) {
2092
- super(scope, seconds => {
2168
+ constructor() {
2169
+ super((scope, seconds) => {
2093
2170
  if (!(seconds instanceof StoreValue) &&
2094
2171
  !(seconds instanceof LiteralValue && typeof seconds.data === "number"))
2095
2172
  throw new CompilerError("The wait seconds must be either a number literal or a store");
@@ -2099,16 +2176,15 @@ class Wait extends MacroFunction {
2099
2176
  }
2100
2177
 
2101
2178
  class Lookup extends ObjectValue {
2102
- constructor(scope) {
2179
+ constructor() {
2103
2180
  const data = createOverloadNamespace({
2104
- scope,
2105
2181
  overloads: {
2106
2182
  block: { args: ["index"] },
2107
2183
  unit: { args: ["index"] },
2108
2184
  item: { args: ["index"] },
2109
2185
  liquid: { args: ["index"] },
2110
2186
  },
2111
- handler(overload, index) {
2187
+ handler(scope, overload, index) {
2112
2188
  const output = new StoreValue(scope);
2113
2189
  return [
2114
2190
  output,
@@ -2116,13 +2192,13 @@ class Lookup extends ObjectValue {
2116
2192
  ];
2117
2193
  },
2118
2194
  });
2119
- super(scope, data);
2195
+ super(data);
2120
2196
  }
2121
2197
  }
2122
2198
 
2123
2199
  class PackColor extends MacroFunction {
2124
- constructor(scope) {
2125
- super(scope, (...args) => {
2200
+ constructor() {
2201
+ super((scope, ...args) => {
2126
2202
  if (args.length !== 4) {
2127
2203
  throw new CompilerError(`Expected 4 arguments, received ${args.length}`);
2128
2204
  }
@@ -2137,15 +2213,14 @@ class PackColor extends MacroFunction {
2137
2213
  }
2138
2214
 
2139
2215
  class End extends MacroFunction {
2140
- constructor(scope) {
2141
- super(scope, () => [null, [new EndInstruction()]]);
2216
+ constructor() {
2217
+ super(() => [null, [new EndInstruction()]]);
2142
2218
  }
2143
2219
  }
2144
2220
 
2145
2221
  class SetBlock extends ObjectValue {
2146
- constructor(scope) {
2222
+ constructor() {
2147
2223
  const data = createOverloadNamespace({
2148
- scope,
2149
2224
  overloads: {
2150
2225
  floor: { args: ["x", "y", "to"] },
2151
2226
  ore: { args: ["x", "y", "to"] },
@@ -2154,7 +2229,7 @@ class SetBlock extends ObjectValue {
2154
2229
  args: ["x", "y", "to", "team", { key: "rotation", default: "0" }],
2155
2230
  },
2156
2231
  },
2157
- handler(overload, x, y, to, team, rotation) {
2232
+ handler(scope, overload, x, y, to, team, rotation) {
2158
2233
  return [
2159
2234
  null,
2160
2235
  [
@@ -2163,13 +2238,13 @@ class SetBlock extends ObjectValue {
2163
2238
  ];
2164
2239
  },
2165
2240
  });
2166
- super(scope, data);
2241
+ super(data);
2167
2242
  }
2168
2243
  }
2169
2244
 
2170
2245
  class SpawnUnit extends MacroFunction {
2171
- constructor(scope) {
2172
- super(scope, options => {
2246
+ constructor() {
2247
+ super((scope, options) => {
2173
2248
  assertIsObjectMacro(options, "The options");
2174
2249
  const { type, x, y, team, rotation } = options.data;
2175
2250
  assertIsRuntimeValue(type, "type");
@@ -2188,14 +2263,14 @@ class SpawnUnit extends MacroFunction {
2188
2263
  }
2189
2264
 
2190
2265
  class Stop extends MacroFunction {
2191
- constructor(scope) {
2192
- super(scope, () => [null, [new InstructionBase("stop")]]);
2266
+ constructor() {
2267
+ super(() => [null, [new InstructionBase("stop")]]);
2193
2268
  }
2194
2269
  }
2195
2270
 
2196
2271
  class UnitBind extends MacroFunction {
2197
- constructor(scope) {
2198
- super(scope, type => {
2272
+ constructor() {
2273
+ super((scope, type) => {
2199
2274
  if (!(type instanceof StoreValue))
2200
2275
  throw new CompilerError("The unitBind type must be a store");
2201
2276
  return [null, [new InstructionBase("ubind", type)]];
@@ -2204,9 +2279,8 @@ class UnitBind extends MacroFunction {
2204
2279
  }
2205
2280
 
2206
2281
  class UnitControl extends ObjectValue {
2207
- constructor(scope) {
2282
+ constructor() {
2208
2283
  const data = createOverloadNamespace({
2209
- scope,
2210
2284
  overloads: {
2211
2285
  idle: { args: [] },
2212
2286
  stop: { args: [] },
@@ -2235,21 +2309,21 @@ class UnitControl extends ObjectValue {
2235
2309
  args: ["x", "y", "radius"],
2236
2310
  },
2237
2311
  },
2238
- handler(overload, ...args) {
2312
+ handler(scope, overload, ...args) {
2239
2313
  let result = null;
2240
2314
  let extraArgs = [];
2241
2315
  switch (overload) {
2242
2316
  case "getBlock": {
2243
2317
  const outType = new StoreValue(scope);
2244
2318
  const outBuilding = new SenseableValue(scope);
2245
- result = ObjectValue.fromArray(scope, [outType, outBuilding]);
2246
- extraArgs = [outType, outBuilding, new LiteralValue(scope, 0)];
2319
+ result = ObjectValue.fromArray([outType, outBuilding]);
2320
+ extraArgs = [outType, outBuilding, new LiteralValue(0)];
2247
2321
  break;
2248
2322
  }
2249
2323
  case "within": {
2250
2324
  const temp = new StoreValue(scope);
2251
2325
  result = temp;
2252
- extraArgs = [temp, new LiteralValue(scope, 0)];
2326
+ extraArgs = [temp, new LiteralValue(0)];
2253
2327
  break;
2254
2328
  }
2255
2329
  }
@@ -2259,13 +2333,13 @@ class UnitControl extends ObjectValue {
2259
2333
  ];
2260
2334
  },
2261
2335
  });
2262
- super(scope, data);
2336
+ super(data);
2263
2337
  }
2264
2338
  }
2265
2339
 
2266
2340
  class UnitRadar extends MacroFunction {
2267
- constructor(scope) {
2268
- super(scope, options => {
2341
+ constructor() {
2342
+ super((scope, options) => {
2269
2343
  assertIsObjectMacro(options, "The radar options");
2270
2344
  const { filters, order, sort } = options.data;
2271
2345
  assertIsArrayMacro(filters, "filters");
@@ -2306,9 +2380,8 @@ const validBuildingGroups = [
2306
2380
  "reactor",
2307
2381
  ];
2308
2382
  class UnitLocate extends ObjectValue {
2309
- constructor(scope) {
2383
+ constructor() {
2310
2384
  const data = createOverloadNamespace({
2311
- scope,
2312
2385
  overloads: {
2313
2386
  ore: {
2314
2387
  args: ["ore"],
@@ -2321,7 +2394,7 @@ class UnitLocate extends ObjectValue {
2321
2394
  args: [],
2322
2395
  },
2323
2396
  },
2324
- handler(overload, ...args) {
2397
+ handler(scope, overload, ...args) {
2325
2398
  const outFound = new StoreValue(scope);
2326
2399
  const outX = new StoreValue(scope);
2327
2400
  const outY = new StoreValue(scope);
@@ -2349,7 +2422,7 @@ class UnitLocate extends ObjectValue {
2349
2422
  }
2350
2423
  }
2351
2424
  return [
2352
- ObjectValue.fromArray(scope, [
2425
+ ObjectValue.fromArray([
2353
2426
  outFound,
2354
2427
  outX,
2355
2428
  outY,
@@ -2359,7 +2432,7 @@ class UnitLocate extends ObjectValue {
2359
2432
  ];
2360
2433
  },
2361
2434
  });
2362
- super(scope, data);
2435
+ super(data);
2363
2436
  }
2364
2437
  }
2365
2438
 
@@ -2380,16 +2453,15 @@ const validEffects = [
2380
2453
  "blasted",
2381
2454
  ];
2382
2455
  class ApplyStatus extends ObjectValue {
2383
- constructor(scope) {
2456
+ constructor() {
2384
2457
  const data = createOverloadNamespace({
2385
- scope,
2386
2458
  overloads: {
2387
2459
  apply: {
2388
2460
  args: ["status", "unit", { key: "duration", default: "10" }],
2389
2461
  },
2390
2462
  clear: { args: ["status", "unit"] },
2391
2463
  },
2392
- handler(overload, effect, unit, duration) {
2464
+ handler(scope, overload, effect, unit, duration) {
2393
2465
  if (!(effect instanceof LiteralValue))
2394
2466
  throw new CompilerError("The status effect must be a string literal");
2395
2467
  assertLiteralOneOf(effect, validEffects, "The status effect");
@@ -2401,13 +2473,13 @@ class ApplyStatus extends ObjectValue {
2401
2473
  ];
2402
2474
  },
2403
2475
  });
2404
- super(scope, data);
2476
+ super(data);
2405
2477
  }
2406
2478
  }
2407
2479
 
2408
2480
  class SpawnWave extends MacroFunction {
2409
- constructor(scope) {
2410
- super(scope, (natural, x, y) => {
2481
+ constructor() {
2482
+ super((scope, natural, x, y) => {
2411
2483
  if (!(natural instanceof LiteralValue) ||
2412
2484
  (natural.data !== 1 && natural.data !== 0))
2413
2485
  throw new CompilerError("The 'natural' argument must be a boolean literal");
@@ -2422,9 +2494,8 @@ class SpawnWave extends MacroFunction {
2422
2494
  }
2423
2495
 
2424
2496
  class SetRule extends ObjectValue {
2425
- constructor(scope) {
2497
+ constructor() {
2426
2498
  const data = createOverloadNamespace({
2427
- scope,
2428
2499
  overloads: {
2429
2500
  currentWaveTime: { args: ["seconds"] },
2430
2501
  waveTimer: { args: ["enabled"] },
@@ -2442,13 +2513,14 @@ class SetRule extends ObjectValue {
2442
2513
  solarMultiplier: { args: ["multiplier"] },
2443
2514
  buildSpeed: { args: ["team", "multiplier"] },
2444
2515
  unitBuildSpeed: { args: ["team", "multiplier"] },
2516
+ unitCost: { args: ["team", "multiplier"] },
2445
2517
  unitDamage: { args: ["team", "multiplier"] },
2446
2518
  blockHealth: { args: ["team", "multiplier"] },
2447
2519
  blockDamage: { args: ["team", "multiplier"] },
2448
2520
  rtsMinWeight: { args: ["team", "value"] },
2449
2521
  rtsMinSquad: { args: ["team", "value"] },
2450
2522
  },
2451
- handler(overload, ...args) {
2523
+ handler(scope, overload, ...args) {
2452
2524
  const params = ["10", "0", "0", "100", "100"];
2453
2525
  switch (overload) {
2454
2526
  case "mapArea": {
@@ -2461,6 +2533,7 @@ class SetRule extends ObjectValue {
2461
2533
  }
2462
2534
  case "buildSpeed":
2463
2535
  case "unitBuildSpeed":
2536
+ case "unitCost":
2464
2537
  case "unitDamage":
2465
2538
  case "blockHealth":
2466
2539
  case "blockDamage":
@@ -2468,7 +2541,7 @@ class SetRule extends ObjectValue {
2468
2541
  case "rtsMinSquad": {
2469
2542
  const [team, value] = args;
2470
2543
  params[1] = team;
2471
- params[2] = value;
2544
+ params[0] = value;
2472
2545
  break;
2473
2546
  }
2474
2547
  default:
@@ -2477,49 +2550,47 @@ class SetRule extends ObjectValue {
2477
2550
  return [null, [new InstructionBase("setrule", overload, ...params)]];
2478
2551
  },
2479
2552
  });
2480
- super(scope, data);
2553
+ super(data);
2481
2554
  }
2482
2555
  }
2483
2556
 
2484
2557
  class FlushMessage extends ObjectValue {
2485
- constructor(scope) {
2558
+ constructor() {
2486
2559
  const data = createOverloadNamespace({
2487
- scope,
2488
2560
  overloads: {
2489
2561
  notify: { args: [] },
2490
2562
  mission: { args: [] },
2491
2563
  announce: { args: ["duration"] },
2492
2564
  toast: { args: ["duration"] },
2493
2565
  },
2494
- handler(overload, duration) {
2566
+ handler(scope, overload, duration) {
2495
2567
  return [null, [new InstructionBase("message", overload, duration)]];
2496
2568
  },
2497
2569
  });
2498
- super(scope, data);
2570
+ super(data);
2499
2571
  }
2500
2572
  }
2501
2573
 
2502
2574
  class Cutscene extends ObjectValue {
2503
- constructor(scope) {
2575
+ constructor() {
2504
2576
  const data = createOverloadNamespace({
2505
- scope,
2506
2577
  overloads: {
2507
2578
  pan: { named: "options", args: ["x", "y", "speed"] },
2508
2579
  zoom: { args: ["level"] },
2509
2580
  stop: { args: [] },
2510
2581
  },
2511
- handler(overload, ...args) {
2582
+ handler(scope, overload, ...args) {
2512
2583
  const params = Object.assign(["100", "100", "0.06", "0"], args);
2513
2584
  return [null, [new InstructionBase("cutscene", overload, ...params)]];
2514
2585
  },
2515
2586
  });
2516
- super(scope, data);
2587
+ super(data);
2517
2588
  }
2518
2589
  }
2519
2590
 
2520
2591
  class Explosion extends MacroFunction {
2521
- constructor(scope) {
2522
- super(scope, options => {
2592
+ constructor() {
2593
+ super((scope, options) => {
2523
2594
  assertIsObjectMacro(options, "The options");
2524
2595
  const params = assertObjectFields(options, [
2525
2596
  "team",
@@ -2537,15 +2608,14 @@ class Explosion extends MacroFunction {
2537
2608
  }
2538
2609
 
2539
2610
  class SetRate extends MacroFunction {
2540
- constructor(scope) {
2541
- super(scope, ipt => [null, [new InstructionBase("setrate", ipt)]]);
2611
+ constructor() {
2612
+ super((scope, ipt) => [null, [new InstructionBase("setrate", ipt)]]);
2542
2613
  }
2543
2614
  }
2544
2615
 
2545
2616
  class Fetch extends ObjectValue {
2546
- constructor(scope) {
2617
+ constructor() {
2547
2618
  const data = createOverloadNamespace({
2548
- scope,
2549
2619
  overloads: {
2550
2620
  unit: { args: ["team", "index"] },
2551
2621
  unitCount: { args: ["team"] },
@@ -2556,7 +2626,7 @@ class Fetch extends ObjectValue {
2556
2626
  build: { args: ["team", "index", "block"] },
2557
2627
  buildCount: { args: ["team", "block"] },
2558
2628
  },
2559
- handler(overload, team, ...rest) {
2629
+ handler(scope, overload, team, ...rest) {
2560
2630
  const output = new SenseableValue(scope);
2561
2631
  const params = ["0", "@conveyor"];
2562
2632
  if (overload === "buildCount") {
@@ -2571,13 +2641,13 @@ class Fetch extends ObjectValue {
2571
2641
  ];
2572
2642
  },
2573
2643
  });
2574
- super(scope, data);
2644
+ super(data);
2575
2645
  }
2576
2646
  }
2577
2647
 
2578
2648
  class GetFlag extends MacroFunction {
2579
- constructor(scope) {
2580
- super(scope, flag => {
2649
+ constructor() {
2650
+ super((scope, flag) => {
2581
2651
  const result = new StoreValue(scope);
2582
2652
  return [result, [new InstructionBase("getflag", result, flag)]];
2583
2653
  });
@@ -2585,8 +2655,8 @@ class GetFlag extends MacroFunction {
2585
2655
  }
2586
2656
 
2587
2657
  class SetFlag extends MacroFunction {
2588
- constructor(scope) {
2589
- super(scope, (flag, value) => {
2658
+ constructor() {
2659
+ super((scope, flag, value) => {
2590
2660
  if (!flag)
2591
2661
  throw new CompilerError("Missing flag argument");
2592
2662
  if (!value)
@@ -2596,36 +2666,48 @@ class SetFlag extends MacroFunction {
2596
2666
  }
2597
2667
  }
2598
2668
 
2599
- class MemoryEntry extends ObjectValue {
2669
+ class MemoryEntry extends BaseValue {
2600
2670
  constructor(scope, mem, prop) {
2601
- super(scope, {
2602
- $eval: new MacroFunction(scope, () => {
2603
- if (this.store)
2604
- return [this.store, []];
2605
- const temp = new StoreValue(scope);
2606
- return [temp, [new InstructionBase("read", temp, mem.cell, prop)]];
2607
- }),
2608
- $consume: new MacroFunction(scope, () => {
2609
- if (this.store)
2610
- return [this.store, []];
2611
- this.ensureOwned();
2612
- this.store = new StoreValue(scope);
2613
- this.owner.own(this.store);
2614
- return [
2615
- this.store,
2616
- [new InstructionBase("read", this.store, mem.cell, prop)],
2617
- ];
2618
- }),
2619
- "$=": new MacroFunction(scope, value => {
2620
- const [data, dataInst] = value.consume(scope);
2621
- return [
2622
- data,
2623
- [...dataInst, new InstructionBase("write", data, mem.cell, prop)],
2624
- ];
2625
- }),
2626
- });
2671
+ super();
2672
+ this.scope = scope;
2673
+ this.mem = mem;
2674
+ this.prop = prop;
2675
+ this.macro = true;
2627
2676
  this.store = null;
2628
2677
  }
2678
+ eval(scope) {
2679
+ if (this.store)
2680
+ return [this.store, []];
2681
+ const temp = new StoreValue(scope);
2682
+ return [
2683
+ temp,
2684
+ [new InstructionBase("read", temp, this.mem.cell, this.prop)],
2685
+ ];
2686
+ }
2687
+ consume(scope) {
2688
+ if (this.store)
2689
+ return [this.store, []];
2690
+ this.ensureOwned();
2691
+ this.store = new StoreValue(scope);
2692
+ this.owner.own(this.store);
2693
+ return [
2694
+ this.store,
2695
+ [new InstructionBase("read", this.store, this.mem.cell, this.prop)],
2696
+ ];
2697
+ }
2698
+ "="(scope, value) {
2699
+ const [data, dataInst] = value.consume(scope);
2700
+ return [
2701
+ data,
2702
+ [
2703
+ ...dataInst,
2704
+ new InstructionBase("write", data, this.mem.cell, this.prop),
2705
+ ],
2706
+ ];
2707
+ }
2708
+ ensureOwned() {
2709
+ this.owner ??= new ValueOwner({ scope: this.scope, value: this });
2710
+ }
2629
2711
  }
2630
2712
  for (const operator of operators) {
2631
2713
  if (operator === "=")
@@ -2636,9 +2718,9 @@ for (const operator of operators) {
2636
2718
  };
2637
2719
  }
2638
2720
  class MemoryMacro extends ObjectValue {
2639
- constructor(scope, cell, size) {
2640
- super(scope, {
2641
- $get: new MacroFunction(scope, (prop) => {
2721
+ constructor(cell, size) {
2722
+ super({
2723
+ $get: new MacroFunction((scope, prop) => {
2642
2724
  if (prop instanceof LiteralValue && typeof prop.data !== "number")
2643
2725
  throw new CompilerError(`Invalid memory object property: "${prop.data}"`);
2644
2726
  const obj = new MemoryEntry(scope, this, prop);
@@ -2648,21 +2730,20 @@ class MemoryMacro extends ObjectValue {
2648
2730
  size,
2649
2731
  });
2650
2732
  this.cell = cell;
2651
- this.name = cell.toString();
2652
2733
  }
2653
2734
  toString() {
2654
- return this.name;
2735
+ return this.cell.toString();
2655
2736
  }
2656
2737
  }
2657
2738
  class MemoryBuilder extends ObjectValue {
2658
- constructor(scope) {
2659
- super(scope, {
2660
- $call: new MacroFunction(scope, (cell, size = new LiteralValue(scope, 64)) => {
2739
+ constructor() {
2740
+ super({
2741
+ $call: new MacroFunction((scope, cell, size = new LiteralValue(64)) => {
2661
2742
  if (!(cell instanceof SenseableValue))
2662
2743
  throw new CompilerError("Memory cell must be a senseable value.");
2663
2744
  if (!(size instanceof LiteralValue && typeof size.data === "number"))
2664
2745
  throw new CompilerError("The memory size must be a number literal.");
2665
- return [new MemoryMacro(scope, cell, size), []];
2746
+ return [new MemoryMacro(cell, size), []];
2666
2747
  }),
2667
2748
  });
2668
2749
  }
@@ -2670,9 +2751,9 @@ class MemoryBuilder extends ObjectValue {
2670
2751
 
2671
2752
  const dynamicVars = ["time", "tick"];
2672
2753
  class NamespaceMacro extends ObjectValue {
2673
- constructor(scope, { changeCasing = false } = {}) {
2674
- super(scope, {
2675
- $get: new MacroFunction(scope, prop => {
2754
+ constructor({ changeCasing = false } = {}) {
2755
+ super({
2756
+ $get: new MacroFunction((scope, prop) => {
2676
2757
  if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
2677
2758
  throw new CompilerError("Cannot use dynamic properties on namespace macros");
2678
2759
  const symbolName = this.changeCasing
@@ -2696,7 +2777,7 @@ class NamespaceMacro extends ObjectValue {
2696
2777
  }
2697
2778
  class VarsNamespace extends NamespaceMacro {
2698
2779
  constructor(scope) {
2699
- super(scope);
2780
+ super();
2700
2781
  Object.assign(this.data, {
2701
2782
  unit: new ValueOwner({
2702
2783
  scope,
@@ -2713,8 +2794,8 @@ class VarsNamespace extends NamespaceMacro {
2713
2794
  }
2714
2795
 
2715
2796
  class GetGlobal extends MacroFunction {
2716
- constructor(scope, mutability) {
2717
- super(scope, (name) => {
2797
+ constructor(mutability) {
2798
+ super((scope, name) => {
2718
2799
  if (!(name instanceof LiteralValue) || typeof name.data !== "string")
2719
2800
  throw new CompilerError("The name parameter must be a string literal.");
2720
2801
  const owner = new ValueOwner({
@@ -2730,22 +2811,77 @@ class GetGlobal extends MacroFunction {
2730
2811
  }
2731
2812
 
2732
2813
  class Asm extends MacroFunction {
2733
- constructor(scope) {
2734
- super(scope, (stringsArray, ...values) => {
2814
+ constructor() {
2815
+ super((scope, stringsArray, ...values) => {
2735
2816
  if (!isTemplateObjectArray(stringsArray))
2736
2817
  throw new CompilerError("Expected to receive a template strings array");
2737
2818
  const args = [];
2738
2819
  for (let i = 0; i < values.length; i++) {
2739
- const [item] = stringsArray.get(scope, new LiteralValue(scope, i));
2820
+ const [item] = stringsArray.get(scope, new LiteralValue(i));
2740
2821
  args.push(item.data);
2741
2822
  args.push(values[i]);
2742
2823
  }
2743
2824
  const { length } = stringsArray.data;
2744
- const [tail] = stringsArray.get(scope, new LiteralValue(scope, length.data - 1));
2825
+ const [tail] = stringsArray.get(scope, new LiteralValue(length.data - 1));
2745
2826
  args.push(tail.data);
2746
- return [null, [new ZeroSpaceInstruction(...args)]];
2827
+ return [null, formatInstructions(args)];
2747
2828
  });
2748
2829
  }
2830
+ }
2831
+ /** Splits multiline asm calls and formats each line. */
2832
+ function formatInstructions(args) {
2833
+ const instructions = [];
2834
+ let buffer = [];
2835
+ for (let i = 0; i < args.length; i++) {
2836
+ const arg = args[i];
2837
+ if (typeof arg !== "string" || !arg.includes("\n")) {
2838
+ buffer.push(arg);
2839
+ continue;
2840
+ }
2841
+ const segments = arg.split("\n");
2842
+ const params = [...buffer, segments[0]];
2843
+ if (validateInstructionArgs(params)) {
2844
+ instructions.push(new ZeroSpaceInstruction(...params));
2845
+ buffer = [];
2846
+ }
2847
+ // iterates over all segments except the first and last
2848
+ // the first segment was already processed above
2849
+ // the last segment will be added to the buffer because there might
2850
+ // be an interpolation after it
2851
+ // and putting it in the buffer makes sure it has a proper output format
2852
+ for (let i = 1; i < segments.length - 1; i++) {
2853
+ const trimmed = segments[i].trim();
2854
+ if (trimmed.length == 0)
2855
+ continue;
2856
+ instructions.push(new ZeroSpaceInstruction(trimmed));
2857
+ }
2858
+ if (segments.length > 1) {
2859
+ buffer.push(segments[segments.length - 1]);
2860
+ }
2861
+ }
2862
+ if (buffer.length > 0 && validateInstructionArgs(buffer)) {
2863
+ instructions.push(new ZeroSpaceInstruction(...buffer));
2864
+ }
2865
+ return instructions;
2866
+ }
2867
+ /** Determines if an asm line should be generated and trims it at the start and end */
2868
+ function validateInstructionArgs(args) {
2869
+ if (args.length === 0)
2870
+ return false;
2871
+ if (args.length === 1) {
2872
+ const item = args[0];
2873
+ if (typeof item !== "string")
2874
+ return true;
2875
+ args[0] = item.trim();
2876
+ return args[0].length !== 0;
2877
+ }
2878
+ const first = args[0];
2879
+ const last = args[args.length - 1];
2880
+ if (typeof first === "string")
2881
+ args[0] = first.trimStart();
2882
+ if (typeof last === "string")
2883
+ args[args.length - 1] = last.trimEnd();
2884
+ return true;
2749
2885
  }
2750
2886
 
2751
2887
  /**
@@ -2753,53 +2889,53 @@ class Asm extends MacroFunction {
2753
2889
  */
2754
2890
  function initScope(scope) {
2755
2891
  // namespaces
2756
- scope.hardSet("ControlKind", new NamespaceMacro(scope));
2892
+ scope.hardSet("ControlKind", new NamespaceMacro());
2757
2893
  scope.hardSet("Vars", new VarsNamespace(scope));
2758
- scope.hardSet("Teams", new NamespaceMacro(scope));
2759
- scope.hardSet("Items", new NamespaceMacro(scope, { changeCasing: true }));
2760
- scope.hardSet("Liquids", new NamespaceMacro(scope));
2761
- scope.hardSet("Units", new NamespaceMacro(scope, { changeCasing: true }));
2762
- scope.hardSet("LAccess", new NamespaceMacro(scope));
2763
- scope.hardSet("Blocks", new NamespaceMacro(scope, { changeCasing: true }));
2894
+ scope.hardSet("Teams", new NamespaceMacro());
2895
+ scope.hardSet("Items", new NamespaceMacro({ changeCasing: true }));
2896
+ scope.hardSet("Liquids", new NamespaceMacro());
2897
+ scope.hardSet("Units", new NamespaceMacro({ changeCasing: true }));
2898
+ scope.hardSet("LAccess", new NamespaceMacro());
2899
+ scope.hardSet("Blocks", new NamespaceMacro({ changeCasing: true }));
2764
2900
  // helper methods
2765
- scope.hardSet("getBuilding", new GetGlobal(scope, EMutability.constant));
2766
- scope.hardSet("getVar", new GetGlobal(scope, EMutability.mutable));
2767
- scope.hardSet("concat", new Concat(scope));
2768
- scope.hardSet("asm", new Asm(scope));
2901
+ scope.hardSet("getBuilding", new GetGlobal(EMutability.constant));
2902
+ scope.hardSet("getVar", new GetGlobal(EMutability.mutable));
2903
+ scope.hardSet("concat", new Concat());
2904
+ scope.hardSet("asm", new Asm());
2769
2905
  scope.hardSet("Math", new MlogMath(scope));
2770
- scope.hardSet("Memory", new MemoryBuilder(scope));
2906
+ scope.hardSet("Memory", new MemoryBuilder());
2771
2907
  // commands
2772
- scope.hardSet("draw", new Draw(scope));
2773
- scope.hardSet("print", new Print(scope));
2774
- scope.hardSet("printFlush", new PrintFlush(scope));
2775
- scope.hardSet("drawFlush", new DrawFlush(scope));
2776
- scope.hardSet("getLink", new GetLink(scope));
2777
- scope.hardSet("control", new Control(scope));
2778
- scope.hardSet("radar", new Radar(scope));
2779
- scope.hardSet("sensor", new Sensor(scope));
2780
- scope.hardSet("wait", new Wait(scope));
2781
- scope.hardSet("lookup", new Lookup(scope));
2782
- scope.hardSet("packColor", new PackColor(scope));
2783
- scope.hardSet("endScript", new End(scope));
2784
- scope.hardSet("stopScript", new Stop(scope));
2785
- scope.hardSet("unitBind", new UnitBind(scope));
2786
- scope.hardSet("unitControl", new UnitControl(scope));
2787
- scope.hardSet("unitRadar", new UnitRadar(scope));
2788
- scope.hardSet("unitLocate", new UnitLocate(scope));
2908
+ scope.hardSet("draw", new Draw());
2909
+ scope.hardSet("print", new Print());
2910
+ scope.hardSet("printFlush", new PrintFlush());
2911
+ scope.hardSet("drawFlush", new DrawFlush());
2912
+ scope.hardSet("getLink", new GetLink());
2913
+ scope.hardSet("control", new Control());
2914
+ scope.hardSet("radar", new Radar());
2915
+ scope.hardSet("sensor", new Sensor());
2916
+ scope.hardSet("wait", new Wait());
2917
+ scope.hardSet("lookup", new Lookup());
2918
+ scope.hardSet("packColor", new PackColor());
2919
+ scope.hardSet("endScript", new End());
2920
+ scope.hardSet("stopScript", new Stop());
2921
+ scope.hardSet("unitBind", new UnitBind());
2922
+ scope.hardSet("unitControl", new UnitControl());
2923
+ scope.hardSet("unitRadar", new UnitRadar());
2924
+ scope.hardSet("unitLocate", new UnitLocate());
2789
2925
  // world processor commands
2790
- scope.hardSet("getBlock", new GetBlock(scope));
2791
- scope.hardSet("setBlock", new SetBlock(scope));
2792
- scope.hardSet("spawnUnit", new SpawnUnit(scope));
2793
- scope.hardSet("applyStatus", new ApplyStatus(scope));
2794
- scope.hardSet("spawnWave", new SpawnWave(scope));
2795
- scope.hardSet("setRule", new SetRule(scope));
2796
- scope.hardSet("flushMessage", new FlushMessage(scope));
2797
- scope.hardSet("cutscene", new Cutscene(scope));
2798
- scope.hardSet("explosion", new Explosion(scope));
2799
- scope.hardSet("setRate", new SetRate(scope));
2800
- scope.hardSet("fetch", new Fetch(scope));
2801
- scope.hardSet("getFlag", new GetFlag(scope));
2802
- scope.hardSet("setFlag", new SetFlag(scope));
2926
+ scope.hardSet("getBlock", new GetBlock());
2927
+ scope.hardSet("setBlock", new SetBlock());
2928
+ scope.hardSet("spawnUnit", new SpawnUnit());
2929
+ scope.hardSet("applyStatus", new ApplyStatus());
2930
+ scope.hardSet("spawnWave", new SpawnWave());
2931
+ scope.hardSet("setRule", new SetRule());
2932
+ scope.hardSet("flushMessage", new FlushMessage());
2933
+ scope.hardSet("cutscene", new Cutscene());
2934
+ scope.hardSet("explosion", new Explosion());
2935
+ scope.hardSet("setRate", new SetRate());
2936
+ scope.hardSet("fetch", new Fetch());
2937
+ scope.hardSet("getFlag", new GetFlag());
2938
+ scope.hardSet("setFlag", new SetFlag());
2803
2939
  }
2804
2940
 
2805
2941
  class Compiler {
@@ -2906,7 +3042,7 @@ class Compiler {
2906
3042
  */
2907
3043
  handleMany(scope, nodes, handler) {
2908
3044
  const lines = [];
2909
- for (const node of nodes) {
3045
+ for (const node of hoistedFunctionNodes(nodes)) {
2910
3046
  const [, nodeLines] = this.handle(scope, node, handler && (() => handler(node)));
2911
3047
  lines.push(...nodeLines);
2912
3048
  }
@@ -2936,6 +3072,20 @@ function hideRedundantJumps(inst) {
2936
3072
  current = inst[searchIndex];
2937
3073
  }
2938
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
+ }
2939
3089
  }
2940
3090
 
2941
3091
  exports.Compiler = Compiler;