mlogjs 0.3.0 → 0.4.1

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 (250) hide show
  1. package/dist/{types/Compiler.d.ts → Compiler.d.ts} +17 -4
  2. package/dist/CompilerError.d.ts +33 -0
  3. package/dist/{types/Scope.d.ts → Scope.d.ts} +0 -0
  4. package/dist/assertions.d.ts +28 -0
  5. package/dist/bin.cjs +7 -14
  6. package/dist/{types/bin.d.ts → bin.d.ts} +0 -0
  7. package/dist/{types/handlers → handlers}/BlockStatement.d.ts +0 -0
  8. package/dist/{types/handlers → handlers}/CallExpression.d.ts +1 -0
  9. package/dist/{types/handlers → handlers}/File.d.ts +0 -0
  10. package/dist/{types/handlers → handlers}/ForStatement.d.ts +0 -0
  11. package/dist/{types/handlers → handlers}/Function.d.ts +0 -0
  12. package/dist/{types/handlers → handlers}/Identifier.d.ts +0 -0
  13. package/dist/{types/handlers → handlers}/IfStatement.d.ts +0 -0
  14. package/dist/{types/handlers → handlers}/Literal.d.ts +0 -0
  15. package/dist/{types/handlers → handlers}/Object.d.ts +0 -0
  16. package/dist/{types/handlers → handlers}/OperationExpressions.d.ts +0 -0
  17. package/dist/{types/handlers → handlers}/Program.d.ts +0 -0
  18. package/dist/{types/handlers → handlers}/Statements.d.ts +0 -0
  19. package/dist/handlers/SwitchStatement.d.ts +2 -0
  20. package/dist/{types/handlers → handlers}/TemplateExpression.d.ts +0 -0
  21. package/dist/{types/handlers → handlers}/Typescript.d.ts +0 -0
  22. package/dist/{types/handlers → handlers}/VariableDeclaration.d.ts +0 -0
  23. package/dist/{types/handlers → handlers}/WhileStatement.d.ts +0 -0
  24. package/dist/{types/handlers → handlers}/index.d.ts +1 -0
  25. package/dist/index.cjs +1282 -514
  26. package/dist/{types/index.d.ts → index.d.ts} +1 -0
  27. package/dist/index.mjs +1282 -514
  28. package/dist/{types/initScope.d.ts → initScope.d.ts} +0 -0
  29. package/dist/{types/instructions → instructions}/AddressResolver.d.ts +0 -0
  30. package/dist/{types/instructions → instructions}/ControlInstructions.d.ts +3 -1
  31. package/dist/{types/instructions → instructions}/EndInstruction.d.ts +0 -0
  32. package/dist/{types/instructions → instructions}/InstructionBase.d.ts +5 -1
  33. package/dist/{types/instructions → instructions}/JumpInstruction.d.ts +1 -0
  34. package/dist/{types/instructions → instructions}/OperationInstruction.d.ts +0 -0
  35. package/dist/{types/instructions → instructions}/SetCounterInstruction.d.ts +0 -0
  36. package/dist/{types/instructions → instructions}/SetInstruction.d.ts +0 -0
  37. package/dist/{types/instructions → instructions}/ZeroSpaceInstruction.d.ts +0 -0
  38. package/dist/{types/instructions → instructions}/index.d.ts +0 -0
  39. package/dist/macros/Asm.d.ts +4 -0
  40. package/dist/{types/macros → macros}/Function.d.ts +2 -2
  41. package/dist/macros/GetGlobal.d.ts +5 -0
  42. package/dist/{types/macros → macros}/Math.d.ts +1 -2
  43. package/dist/{types/macros → macros}/Memory.d.ts +1 -2
  44. package/dist/{types/macros → macros}/Namespace.d.ts +1 -4
  45. package/dist/{types/macros → macros}/Other.d.ts +1 -2
  46. package/dist/macros/commands/ApplyStatus.d.ts +4 -0
  47. package/dist/macros/commands/Control.d.ts +4 -0
  48. package/dist/macros/commands/Cutscene.d.ts +4 -0
  49. package/dist/macros/commands/Draw.d.ts +4 -0
  50. package/dist/{types/macros → macros}/commands/DrawFlush.d.ts +1 -2
  51. package/dist/{types/macros → macros}/commands/End.d.ts +1 -2
  52. package/dist/macros/commands/Explosion.d.ts +4 -0
  53. package/dist/macros/commands/Fetch.d.ts +4 -0
  54. package/dist/macros/commands/FlushMessage.d.ts +4 -0
  55. package/dist/macros/commands/GetBlock.d.ts +4 -0
  56. package/dist/macros/commands/GetFlag.d.ts +4 -0
  57. package/dist/{types/macros → macros}/commands/GetLink.d.ts +1 -2
  58. package/dist/macros/commands/Lookup.d.ts +4 -0
  59. package/dist/macros/commands/PackColor.d.ts +4 -0
  60. package/dist/{types/macros → macros}/commands/Print.d.ts +1 -2
  61. package/dist/{types/macros → macros}/commands/PrintFlush.d.ts +1 -2
  62. package/dist/macros/commands/Radar.d.ts +6 -0
  63. package/dist/{types/macros → macros}/commands/Sensor.d.ts +1 -2
  64. package/dist/macros/commands/SetBlock.d.ts +4 -0
  65. package/dist/macros/commands/SetFlag.d.ts +4 -0
  66. package/dist/macros/commands/SetRate.d.ts +4 -0
  67. package/dist/macros/commands/SetRule.d.ts +4 -0
  68. package/dist/macros/commands/SpawnUnit.d.ts +4 -0
  69. package/dist/macros/commands/SpawnWave.d.ts +4 -0
  70. package/dist/macros/commands/Stop.d.ts +4 -0
  71. package/dist/{types/macros → macros}/commands/UnitBind.d.ts +1 -2
  72. package/dist/macros/commands/UnitControl.d.ts +4 -0
  73. package/dist/macros/commands/UnitLocate.d.ts +4 -0
  74. package/dist/{types/macros → macros}/commands/UnitRadar.d.ts +1 -2
  75. package/dist/{types/macros → macros}/commands/Wait.d.ts +1 -2
  76. package/dist/macros/commands/index.d.ts +30 -0
  77. package/dist/{types/macros → macros}/index.d.ts +0 -0
  78. package/dist/macros/util.d.ts +17 -0
  79. package/dist/{types/operators.d.ts → operators.d.ts} +0 -0
  80. package/dist/{types/types.d.ts → types.d.ts} +14 -1
  81. package/dist/utils.d.ts +47 -0
  82. package/dist/{types/values → values}/BaseValue.d.ts +3 -2
  83. package/dist/{types/values → values}/DestructuringValue.d.ts +1 -1
  84. package/dist/{types/values → values}/FunctionValue.d.ts +4 -5
  85. package/dist/{types/values → values}/LiteralValue.d.ts +3 -2
  86. package/dist/{types/values → values}/ObjectValue.d.ts +3 -3
  87. package/dist/{types/values → values}/SenseableValue.d.ts +0 -0
  88. package/dist/{types/values → values}/StoreValue.d.ts +4 -2
  89. package/dist/{types/values → values}/ValueOwner.d.ts +0 -0
  90. package/dist/{types/values → values}/VoidValue.d.ts +0 -2
  91. package/dist/{types/values → values}/index.d.ts +0 -0
  92. package/lib/commands.d.ts +847 -420
  93. package/lib/eslib/lib.es2015.core.d.ts +3 -0
  94. package/lib/globals.d.ts +331 -19
  95. package/lib/helpers.d.ts +14 -0
  96. package/lib/kinds.d.ts +3 -2
  97. package/lib/memory.d.ts +1 -1
  98. package/lib/traits.d.ts +6 -0
  99. package/lib/util.d.ts +16 -0
  100. package/package.json +16 -17
  101. package/build/Compiler.js +0 -105
  102. package/build/Compiler.js.map +0 -1
  103. package/build/CompilerError.js +0 -11
  104. package/build/CompilerError.js.map +0 -1
  105. package/build/Scope.js +0 -71
  106. package/build/Scope.js.map +0 -1
  107. package/build/bin.js +0 -75
  108. package/build/bin.js.map +0 -1
  109. package/build/handlers/BlockStatement.js +0 -14
  110. package/build/handlers/BlockStatement.js.map +0 -1
  111. package/build/handlers/CallExpression.js +0 -20
  112. package/build/handlers/CallExpression.js.map +0 -1
  113. package/build/handlers/File.js +0 -9
  114. package/build/handlers/File.js.map +0 -1
  115. package/build/handlers/ForStatement.js +0 -32
  116. package/build/handlers/ForStatement.js.map +0 -1
  117. package/build/handlers/Function.js +0 -47
  118. package/build/handlers/Function.js.map +0 -1
  119. package/build/handlers/Identifier.js +0 -8
  120. package/build/handlers/Identifier.js.map +0 -1
  121. package/build/handlers/IfStatement.js +0 -25
  122. package/build/handlers/IfStatement.js.map +0 -1
  123. package/build/handlers/Literal.js +0 -15
  124. package/build/handlers/Literal.js.map +0 -1
  125. package/build/handlers/Object.js +0 -55
  126. package/build/handlers/Object.js.map +0 -1
  127. package/build/handlers/OperationExpressions.js +0 -38
  128. package/build/handlers/OperationExpressions.js.map +0 -1
  129. package/build/handlers/Program.js +0 -9
  130. package/build/handlers/Program.js.map +0 -1
  131. package/build/handlers/Statements.js +0 -30
  132. package/build/handlers/Statements.js.map +0 -1
  133. package/build/handlers/TemplateExpression.js +0 -18
  134. package/build/handlers/TemplateExpression.js.map +0 -1
  135. package/build/handlers/VariableDeclaration.js +0 -72
  136. package/build/handlers/VariableDeclaration.js.map +0 -1
  137. package/build/handlers/WhileStatement.js +0 -23
  138. package/build/handlers/WhileStatement.js.map +0 -1
  139. package/build/handlers/index.js +0 -32
  140. package/build/handlers/index.js.map +0 -1
  141. package/build/index.js +0 -8
  142. package/build/index.js.map +0 -1
  143. package/build/initScope.js +0 -40
  144. package/build/initScope.js.map +0 -1
  145. package/build/instructions/AddressResolver.js +0 -31
  146. package/build/instructions/AddressResolver.js.map +0 -1
  147. package/build/instructions/ControlInstructions.js +0 -23
  148. package/build/instructions/ControlInstructions.js.map +0 -1
  149. package/build/instructions/EndInstruction.js +0 -11
  150. package/build/instructions/EndInstruction.js.map +0 -1
  151. package/build/instructions/InstructionBase.js +0 -21
  152. package/build/instructions/InstructionBase.js.map +0 -1
  153. package/build/instructions/JumpInstruction.js +0 -22
  154. package/build/instructions/JumpInstruction.js.map +0 -1
  155. package/build/instructions/OperationInstruction.js +0 -11
  156. package/build/instructions/OperationInstruction.js.map +0 -1
  157. package/build/instructions/SetCounterInstruction.js +0 -11
  158. package/build/instructions/SetCounterInstruction.js.map +0 -1
  159. package/build/instructions/SetInstruction.js +0 -11
  160. package/build/instructions/SetInstruction.js.map +0 -1
  161. package/build/instructions/ZeroSpaceInstruction.js +0 -11
  162. package/build/instructions/ZeroSpaceInstruction.js.map +0 -1
  163. package/build/instructions/index.js +0 -26
  164. package/build/instructions/index.js.map +0 -1
  165. package/build/macros/Building.js +0 -89
  166. package/build/macros/Building.js.map +0 -1
  167. package/build/macros/Function.js +0 -20
  168. package/build/macros/Function.js.map +0 -1
  169. package/build/macros/Math.js +0 -62
  170. package/build/macros/Math.js.map +0 -1
  171. package/build/macros/Memory.js +0 -63
  172. package/build/macros/Memory.js.map +0 -1
  173. package/build/macros/Namespace.js +0 -111
  174. package/build/macros/Namespace.js.map +0 -1
  175. package/build/macros/Other.js +0 -21
  176. package/build/macros/Other.js.map +0 -1
  177. package/build/macros/RawValue.js +0 -17
  178. package/build/macros/RawValue.js.map +0 -1
  179. package/build/macros/commands/Control.js +0 -26
  180. package/build/macros/commands/Control.js.map +0 -1
  181. package/build/macros/commands/Draw.js +0 -40
  182. package/build/macros/commands/Draw.js.map +0 -1
  183. package/build/macros/commands/DrawFlush.js +0 -18
  184. package/build/macros/commands/DrawFlush.js.map +0 -1
  185. package/build/macros/commands/GetLink.js +0 -25
  186. package/build/macros/commands/GetLink.js.map +0 -1
  187. package/build/macros/commands/Lookup.js +0 -25
  188. package/build/macros/commands/Lookup.js.map +0 -1
  189. package/build/macros/commands/Print.js +0 -18
  190. package/build/macros/commands/Print.js.map +0 -1
  191. package/build/macros/commands/PrintFlush.js +0 -18
  192. package/build/macros/commands/PrintFlush.js.map +0 -1
  193. package/build/macros/commands/Radar.js +0 -65
  194. package/build/macros/commands/Radar.js.map +0 -1
  195. package/build/macros/commands/Sensor.js +0 -21
  196. package/build/macros/commands/Sensor.js.map +0 -1
  197. package/build/macros/commands/UnitBind.js +0 -18
  198. package/build/macros/commands/UnitBind.js.map +0 -1
  199. package/build/macros/commands/UnitControl.js +0 -73
  200. package/build/macros/commands/UnitControl.js.map +0 -1
  201. package/build/macros/commands/UnitLocate.js +0 -76
  202. package/build/macros/commands/UnitLocate.js.map +0 -1
  203. package/build/macros/commands/UnitRadar.js +0 -48
  204. package/build/macros/commands/UnitRadar.js.map +0 -1
  205. package/build/macros/commands/Wait.js +0 -19
  206. package/build/macros/commands/Wait.js.map +0 -1
  207. package/build/macros/commands/index.js +0 -33
  208. package/build/macros/commands/index.js.map +0 -1
  209. package/build/macros/index.js +0 -40
  210. package/build/macros/index.js.map +0 -1
  211. package/build/operators.js +0 -102
  212. package/build/operators.js.map +0 -1
  213. package/build/types.js +0 -28
  214. package/build/types.js.map +0 -1
  215. package/build/utils.js +0 -18
  216. package/build/utils.js.map +0 -1
  217. package/build/values/BaseValue.js +0 -112
  218. package/build/values/BaseValue.js.map +0 -1
  219. package/build/values/FunctionValue.js +0 -116
  220. package/build/values/FunctionValue.js.map +0 -1
  221. package/build/values/LiteralValue.js +0 -89
  222. package/build/values/LiteralValue.js.map +0 -1
  223. package/build/values/ObjectValue.js +0 -55
  224. package/build/values/ObjectValue.js.map +0 -1
  225. package/build/values/StoreValue.js +0 -32
  226. package/build/values/StoreValue.js.map +0 -1
  227. package/build/values/TempValue.js +0 -78
  228. package/build/values/TempValue.js.map +0 -1
  229. package/build/values/VoidValue.js +0 -32
  230. package/build/values/VoidValue.js.map +0 -1
  231. package/build/values/index.js +0 -23
  232. package/build/values/index.js.map +0 -1
  233. package/dist/bin.cjs.map +0 -1
  234. package/dist/index.cjs.map +0 -1
  235. package/dist/index.mjs.map +0 -1
  236. package/dist/types/CompilerError.d.ts +0 -9
  237. package/dist/types/macros/Building.d.ts +0 -10
  238. package/dist/types/macros/Entities.d.ts +0 -11
  239. package/dist/types/macros/GetGlobal.d.ts +0 -5
  240. package/dist/types/macros/RawValue.d.ts +0 -5
  241. package/dist/types/macros/commands/Control.d.ts +0 -5
  242. package/dist/types/macros/commands/Draw.d.ts +0 -5
  243. package/dist/types/macros/commands/Lookup.d.ts +0 -5
  244. package/dist/types/macros/commands/Radar.d.ts +0 -7
  245. package/dist/types/macros/commands/UnitControl.d.ts +0 -5
  246. package/dist/types/macros/commands/UnitLocate.d.ts +0 -5
  247. package/dist/types/macros/commands/index.d.ts +0 -15
  248. package/dist/types/utils.d.ts +0 -30
  249. package/dist/types/values/StackValue.d.ts +0 -16
  250. package/dist/types/values/TempValue.d.ts +0 -19
package/dist/index.cjs CHANGED
@@ -26,12 +26,58 @@ function _interopNamespace(e) {
26
26
  var es__namespace = /*#__PURE__*/_interopNamespace(es);
27
27
 
28
28
  class CompilerError extends Error {
29
- constructor(message, nodeStack = []) {
29
+ constructor(message, source) {
30
30
  super(message);
31
- this.nodeStack = nodeStack;
31
+ this.loc = source;
32
+ }
33
+ get loc() {
34
+ return this._loc;
35
+ }
36
+ set loc(value) {
37
+ if (!value)
38
+ return;
39
+ if ("type" in value) {
40
+ this._loc = value.loc;
41
+ }
42
+ else if ("start" in value) {
43
+ this._loc = value;
44
+ }
45
+ else {
46
+ this._loc = {
47
+ start: value,
48
+ end: value,
49
+ };
50
+ }
51
+ }
52
+ static from(error, source) {
53
+ let message;
54
+ if (error && typeof error === "object" && "loc" in error) {
55
+ const err = error;
56
+ message = err.toString();
57
+ source ??= err.loc;
58
+ }
59
+ else if (error instanceof Error) {
60
+ message = error.message;
61
+ }
62
+ else if (typeof error === "string") {
63
+ message = error;
64
+ }
65
+ else {
66
+ message = `Unknown error: ${error}`;
67
+ }
68
+ const result = new CompilerError(message, source);
69
+ result.inner = error;
70
+ return result;
32
71
  }
33
72
  }
34
73
 
74
+ var EInstIntent;
75
+ (function (EInstIntent) {
76
+ EInstIntent[EInstIntent["none"] = 0] = "none";
77
+ EInstIntent[EInstIntent["break"] = 1] = "break";
78
+ EInstIntent[EInstIntent["continue"] = 2] = "continue";
79
+ EInstIntent[EInstIntent["return"] = 3] = "return";
80
+ })(EInstIntent || (EInstIntent = {}));
35
81
  /** Defines the possible types of mutability of a value */
36
82
  var EMutability;
37
83
  (function (EMutability) {
@@ -125,11 +171,10 @@ const singleOperators = [...unaryOperators, ...updateOperators];
125
171
  const operators = [...leftRightOperators, ...singleOperators];
126
172
 
127
173
  class VoidValue {
128
- constructor(scope) {
174
+ constructor() {
129
175
  this.owner = null;
130
176
  this.mutability = EMutability.mutable;
131
177
  this.macro = false;
132
- this.scope = scope;
133
178
  }
134
179
  eval(_scope) {
135
180
  throw new CompilerError(`${this} cannot eval.`);
@@ -159,6 +204,8 @@ for (const key of operators) {
159
204
 
160
205
  class InstructionBase {
161
206
  constructor(...args) {
207
+ this.intent = EInstIntent.none;
208
+ this.alwaysRuns = true;
162
209
  this._hidden = false;
163
210
  this.args = args;
164
211
  }
@@ -235,6 +282,7 @@ var EJumpKind;
235
282
  class JumpInstruction extends InstructionBase {
236
283
  constructor(address, kind, left = null, right = null) {
237
284
  super("jump", address, kind, left, right);
285
+ this.address = address;
238
286
  }
239
287
  }
240
288
 
@@ -253,43 +301,13 @@ class ZeroSpaceInstruction extends InstructionBase {
253
301
  class BreakInstruction extends JumpInstruction {
254
302
  constructor(address) {
255
303
  super(address, EJumpKind.Always);
304
+ this.intent = EInstIntent.break;
256
305
  }
257
306
  }
258
307
  class ContinueInstruction extends JumpInstruction {
259
308
  constructor(address) {
260
309
  super(address, EJumpKind.Always);
261
- }
262
- }
263
-
264
- class ValueOwner {
265
- /**
266
- * Creates a new `ValueOwner`, if `value` is already owned,
267
- * `this` will be aliased to `value`, else `this` will own `value`
268
- */
269
- constructor({ scope, constant = false, value, identifier, name, }) {
270
- this.scope = scope;
271
- this.constant = constant;
272
- this.value = value;
273
- this.identifier = identifier;
274
- this.name = name ?? scope.makeTempName();
275
- this.persistent = !!name;
276
- this.owned = new Set();
277
- if (!value.owner?.persistent)
278
- this.own(value);
279
- }
280
- own(target) {
281
- target.owner = this;
282
- this.owned.add(target);
283
- }
284
- replace(target) {
285
- this.value.owner = null;
286
- this.owned.delete(this.value);
287
- this.value = target;
288
- this.own(target);
289
- }
290
- moveInto(owner) {
291
- this.owned.forEach(value => owner.own(value));
292
- this.owned.clear();
310
+ this.intent = EInstIntent.continue;
293
311
  }
294
312
  }
295
313
 
@@ -301,7 +319,7 @@ class BaseValue extends VoidValue {
301
319
  temp,
302
320
  [
303
321
  ...inst,
304
- new OperationInstruction("sub", temp, new LiteralValue(scope, 0), that),
322
+ new OperationInstruction("sub", temp, new LiteralValue(0), that),
305
323
  ],
306
324
  ];
307
325
  }
@@ -309,8 +327,19 @@ class BaseValue extends VoidValue {
309
327
  // TODO: should it return 0 + this ?
310
328
  return this.eval(scope);
311
329
  }
312
- ensureOwned() {
313
- this.owner ??= new ValueOwner({ scope: this.scope, value: this });
330
+ "!"(scope) {
331
+ const [that, inst] = this.consume(scope);
332
+ const temp = new StoreValue(scope);
333
+ const falseLiteral = new LiteralValue(0);
334
+ return [
335
+ temp,
336
+ [...inst, new OperationInstruction("equal", temp, that, falseLiteral)],
337
+ ];
338
+ }
339
+ "~"(scope) {
340
+ const [that, inst] = this.consume(scope);
341
+ const temp = new StoreValue(scope);
342
+ return [temp, [...inst, new OperationInstruction("not", temp, that, null)]];
314
343
  }
315
344
  }
316
345
  const operatorMap$1 = {
@@ -353,18 +382,6 @@ for (const key in operatorMap$1) {
353
382
  ];
354
383
  };
355
384
  }
356
- const unaryOperatorMap$1 = {
357
- "!": "not",
358
- "~": "flip",
359
- };
360
- for (const key in unaryOperatorMap$1) {
361
- const name = unaryOperatorMap$1[key];
362
- BaseValue.prototype[key] = function (scope) {
363
- const [that, inst] = this.consume(scope);
364
- const temp = new StoreValue(scope);
365
- return [temp, [...inst, new OperationInstruction(name, temp, that, null)]];
366
- };
367
- }
368
385
  const assignmentToBinary = {
369
386
  "+=": "+",
370
387
  "-=": "-",
@@ -399,23 +416,20 @@ for (const key of updateOperators) {
399
416
  inst.push(...tempInst);
400
417
  }
401
418
  const kind = key === "++" ? "+=" : "-=";
402
- return [
403
- ret,
404
- [...inst, ...this[kind](scope, new LiteralValue(scope, 1))[1]],
405
- ];
419
+ return [ret, [...inst, ...this[kind](scope, new LiteralValue(1))[1]]];
406
420
  };
407
421
  }
408
422
 
409
423
  const literalMethods = {
410
- length: function (scope) {
424
+ length: function () {
411
425
  if (typeof this.data !== "string")
412
426
  throw new CompilerError("Length method only works on string literal values.");
413
- return new LiteralValue(scope, this.data.length);
427
+ return new LiteralValue(this.data.length);
414
428
  },
415
429
  };
416
430
  class LiteralValue extends BaseValue {
417
- constructor(scope, data) {
418
- super(scope);
431
+ constructor(data) {
432
+ super();
419
433
  this.mutability = EMutability.constant;
420
434
  this.data = data;
421
435
  }
@@ -443,9 +457,10 @@ class LiteralValue extends BaseValue {
443
457
  return 1;
444
458
  return this.data;
445
459
  }
446
- typeof(scope) {
447
- return [new LiteralValue(scope, "literal"), []];
460
+ typeof() {
461
+ return [new LiteralValue("literal"), []];
448
462
  }
463
+ ensureOwned() { }
449
464
  }
450
465
  const operatorMap = {
451
466
  "==": (a, b) => +(a == b),
@@ -477,18 +492,19 @@ for (const key in operatorMap) {
477
492
  if (!(value instanceof LiteralValue)) {
478
493
  return BaseValue.prototype[key].apply(this, [scope, value]);
479
494
  }
480
- return [new LiteralValue(scope, fn(this.num, value.num)), []];
495
+ return [new LiteralValue(fn(this.data, value.data)), []];
481
496
  };
482
497
  }
483
498
  const unaryOperatorMap = {
484
499
  "!": v => +!v,
485
500
  "~": v => ~v,
486
501
  "u-": v => -v,
502
+ "u+": v => +v,
487
503
  };
488
504
  for (const key in unaryOperatorMap) {
489
- LiteralValue.prototype[key] = function (scope) {
505
+ LiteralValue.prototype[key] = function () {
490
506
  const fn = unaryOperatorMap[key];
491
- return [new LiteralValue(scope, fn(this.num)), []];
507
+ return [new LiteralValue(fn(this.data)), []];
492
508
  };
493
509
  }
494
510
 
@@ -543,8 +559,60 @@ const itemNames = [
543
559
  /**
544
560
  * A more type safe version of `Object.assign`
545
561
  */
562
+ // eslint-disable-next-line @typescript-eslint/ban-types
546
563
  function assign(obj, props) {
547
564
  return Object.assign(obj, props);
565
+ }
566
+ function appendSourceLocations(valueInst, node) {
567
+ for (const inst of valueInst[1]) {
568
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
569
+ inst.source ??= node.loc;
570
+ }
571
+ return valueInst;
572
+ }
573
+ function withAlwaysRuns(valueInst, value) {
574
+ valueInst[1].forEach(inst => (inst.alwaysRuns = value));
575
+ return valueInst;
576
+ }
577
+ function isTemplateObjectArray(value) {
578
+ return (value instanceof ObjectValue &&
579
+ value.data.length instanceof LiteralValue &&
580
+ typeof value.data.length.data === "number" &&
581
+ value.data.raw instanceof ObjectValue &&
582
+ value.data.raw.data.length instanceof LiteralValue &&
583
+ typeof value.data.raw.data.length.data === "number");
584
+ }
585
+
586
+ class ValueOwner {
587
+ /**
588
+ * Creates a new `ValueOwner`, if `value` is already owned,
589
+ * `this` will be aliased to `value`, else `this` will own `value`
590
+ */
591
+ constructor({ scope, constant = false, value, identifier, name, }) {
592
+ this.scope = scope;
593
+ this.constant = constant;
594
+ this.value = value;
595
+ this.identifier = identifier;
596
+ this.name = name ?? scope.makeTempName();
597
+ this.persistent = !!name;
598
+ this.owned = new Set();
599
+ if (!value.owner?.persistent)
600
+ this.own(value);
601
+ }
602
+ own(target) {
603
+ target.owner = this;
604
+ this.owned.add(target);
605
+ }
606
+ replace(target) {
607
+ this.value.owner = null;
608
+ this.owned.delete(this.value);
609
+ this.value = target;
610
+ this.own(target);
611
+ }
612
+ moveInto(owner) {
613
+ this.owned.forEach(value => owner.own(value));
614
+ this.owned.clear();
615
+ }
548
616
  }
549
617
 
550
618
  /**
@@ -553,11 +621,12 @@ function assign(obj, props) {
553
621
  */
554
622
  class StoreValue extends BaseValue {
555
623
  constructor(scope) {
556
- super(scope);
624
+ super();
625
+ this.scope = scope;
557
626
  this.mutability = EMutability.mutable;
558
627
  }
559
- typeof(scope) {
560
- return [new LiteralValue(scope, "store"), []];
628
+ typeof() {
629
+ return [new LiteralValue("store"), []];
561
630
  }
562
631
  "="(scope, value) {
563
632
  if (this.mutability !== EMutability.mutable)
@@ -584,30 +653,34 @@ class StoreValue extends BaseValue {
584
653
  this.ensureOwned();
585
654
  return [this, []];
586
655
  }
656
+ ensureOwned() {
657
+ this.owner ??= new ValueOwner({ scope: this.scope, value: this });
658
+ }
587
659
  toString() {
588
660
  return this.owner?.name ?? discardedName;
589
661
  }
590
662
  }
591
663
 
592
664
  class ObjectValue extends VoidValue {
593
- constructor(scope, data = {}) {
594
- super(scope);
665
+ constructor(data = {}) {
666
+ super();
595
667
  this.mutability = EMutability.constant;
596
668
  this.macro = true;
597
669
  this.data = data;
598
670
  }
599
- static fromArray(scope, items) {
671
+ static fromArray(items, intialData) {
600
672
  const data = {
601
- length: new LiteralValue(scope, items.length),
673
+ ...intialData,
674
+ length: new LiteralValue(items.length),
602
675
  };
603
676
  items.forEach((item, i) => {
604
677
  if (item)
605
678
  data[i] = item;
606
679
  });
607
- return new ObjectValue(scope, data);
680
+ return new ObjectValue(data);
608
681
  }
609
- typeof(scope) {
610
- return [new LiteralValue(scope, "object"), []];
682
+ typeof() {
683
+ return [new LiteralValue("object"), []];
611
684
  }
612
685
  get(scope, key) {
613
686
  // avoids naming collisions with keys like
@@ -644,9 +717,7 @@ class ObjectValue extends VoidValue {
644
717
  return super.call(scope, args);
645
718
  return $call.call(scope, args);
646
719
  }
647
- ensureOwned() {
648
- this.owner ??= new ValueOwner({ scope: this.scope, value: this });
649
- }
720
+ ensureOwned() { }
650
721
  }
651
722
  for (const op of operators) {
652
723
  ObjectValue.prototype[op] = function (...args) {
@@ -698,7 +769,9 @@ class SenseableValue extends StoreValue {
698
769
  ];
699
770
  }
700
771
  if (prop instanceof StoreValue) {
701
- const temp = new StoreValue(scope);
772
+ const temp = assign(new SenseableValue(scope), {
773
+ mutability: EMutability.readonly,
774
+ });
702
775
  return [temp, [new InstructionBase("sensor", temp, this, prop)]];
703
776
  }
704
777
  throw new CompilerError(`Cannot sense "${prop}" property`);
@@ -713,8 +786,8 @@ class SenseableValue extends StoreValue {
713
786
  * each of them to their counterparts on the right hand value.
714
787
  */
715
788
  class DestructuringValue extends VoidValue {
716
- constructor(scope, members) {
717
- super(scope);
789
+ constructor(members) {
790
+ super();
718
791
  this.members = members;
719
792
  this.macro = true;
720
793
  }
@@ -823,7 +896,7 @@ const Program = (c, scope, node) => {
823
896
  };
824
897
 
825
898
  const VariableDeclaration = (c, scope, node) => {
826
- return c.handleMany(scope, node.declarations, (scope, child) => VariableDeclarator(c, scope, child, node.kind));
899
+ return c.handleMany(scope, node.declarations, child => VariableDeclarator(c, scope, child, node.kind));
827
900
  };
828
901
  const VariableDeclarator = (c, scope, node, kind = "let") => {
829
902
  const [init, inst] = node.init
@@ -833,24 +906,24 @@ const VariableDeclarator = (c, scope, node, kind = "let") => {
833
906
  return [null, inst];
834
907
  };
835
908
  const Declare = (c, scope, node, kind, init) => {
836
- switch (node.type) {
837
- case "Identifier":
838
- return DeclareIdentifier(c, scope, node, kind, init);
839
- case "ArrayPattern":
840
- return DeclareArrayPattern(c, scope, node, kind, init);
841
- case "ObjectPattern":
842
- return DeclareObjectPattern(c, scope, node, kind, init);
843
- default:
844
- throw new CompilerError(`Unsupported declaration type: ${node.type}`, [
845
- node,
846
- ]);
847
- }
909
+ return c.handle(scope, node, () => {
910
+ switch (node.type) {
911
+ case "Identifier":
912
+ return DeclareIdentifier(c, scope, node, kind, init);
913
+ case "ArrayPattern":
914
+ return DeclareArrayPattern(c, scope, node, kind, init);
915
+ case "ObjectPattern":
916
+ return DeclareObjectPattern(c, scope, node, kind, init);
917
+ default:
918
+ throw new CompilerError(`Unsupported declaration type: ${node.type}`, node);
919
+ }
920
+ });
848
921
  };
849
922
  const DeclareIdentifier = (c, scope, node, kind, init) => {
850
923
  const { name: identifier } = node;
851
924
  const name = nodeName(node, !c.compactNames && identifier);
852
925
  if (kind === "const" && !init)
853
- throw new CompilerError("Constants must be initialized.", [node]);
926
+ throw new CompilerError("Constants must be initialized.", node);
854
927
  if (kind === "const" && init?.mutability === EMutability.constant) {
855
928
  const owner = new ValueOwner({
856
929
  scope,
@@ -867,9 +940,7 @@ const DeclareIdentifier = (c, scope, node, kind, init) => {
867
940
  const inst = [];
868
941
  if (init) {
869
942
  if (init.macro)
870
- throw new CompilerError("Macro values must be held by constants", [
871
- node,
872
- ]);
943
+ throw new CompilerError("Macro values must be held by constants", node);
873
944
  inst.push(...value["="](scope, init)[1]);
874
945
  }
875
946
  if (kind === "const")
@@ -888,39 +959,38 @@ const DeclareArrayPattern = (c, scope, node, kind, init) => {
888
959
  continue;
889
960
  const val = init.data[i];
890
961
  if (!val)
891
- throw new CompilerError(`The target object does not have a value at index ${i}`, [element]);
962
+ throw new CompilerError(`The target object does not have a value at index ${i}`, element);
892
963
  inst.push(...Declare(c, scope, element, kind, val)[1]);
893
964
  }
894
965
  return [null, inst];
895
966
  };
896
967
  const DeclareObjectPattern = (c, scope, node, kind, base) => {
897
968
  if (!base)
898
- throw new CompilerError("Cannot use object destructuring without an initializer", [node]);
969
+ throw new CompilerError("Cannot use object destructuring without an initializer", node);
899
970
  const { properties } = node;
900
971
  const [init, inst] = base.consume(scope);
901
- for (const prop of properties) {
972
+ const propertiesInst = c.handleMany(scope, properties, prop => {
902
973
  if (prop.type === "RestElement")
903
- throw new CompilerError("The rest operator is not supported", [prop]);
974
+ throw new CompilerError("The rest operator is not supported", prop);
904
975
  const { key, value } = prop;
905
- const child = key.type === "Identifier" && !prop.computed
906
- ? [new LiteralValue(scope, key.name), []]
976
+ const keyInst = key.type === "Identifier" && !prop.computed
977
+ ? [new LiteralValue(key.name), []]
907
978
  : c.handleConsume(scope, prop.key);
908
- inst.push(...child[1]);
909
- const propInit = init.get(scope, child[0]);
910
- inst.push(...propInit[1]);
911
- inst.push(...Declare(c, scope, value, kind, propInit[0])[1]);
912
- }
913
- return [null, inst];
979
+ const propInit = init.get(scope, keyInst[0]);
980
+ const declarationInst = Declare(c, scope, value, kind, propInit[0]);
981
+ return [null, [...keyInst[1], ...propInit[1], ...declarationInst[1]]];
982
+ });
983
+ return [null, [...inst, ...propertiesInst[1]]];
914
984
  };
915
985
 
916
- const Literal = (_c, scope, node) => [new LiteralValue(scope, node.value), []];
986
+ const Literal = (_c, scope, node) => [new LiteralValue(node.value), []];
917
987
  const NumericLiteral = Literal;
918
988
  const StringLiteral = Literal;
919
- const NullLiteral = (_c, scope) => [
920
- new LiteralValue(scope, null),
989
+ const NullLiteral = () => [
990
+ new LiteralValue(null),
921
991
  [],
922
992
  ];
923
- const BooleanLiteral = (_c, scope, node) => [new LiteralValue(scope, +node.value), []];
993
+ const BooleanLiteral = (_c, scope, node) => [new LiteralValue(+node.value), []];
924
994
 
925
995
  const LRExpression = (c, scope, node) => {
926
996
  const [left, leftInst] = c.handleConsume(scope, node.left);
@@ -929,7 +999,34 @@ const LRExpression = (c, scope, node) => {
929
999
  return [op, [...leftInst, ...rightInst, ...opInst]];
930
1000
  };
931
1001
  const BinaryExpression = LRExpression;
932
- const LogicalExpression = LRExpression;
1002
+ const LogicalExpression = (c, scope, node) => {
1003
+ if (node.operator !== "??")
1004
+ return LRExpression(c, scope, node);
1005
+ const nullLiteral = new LiteralValue(null);
1006
+ const endAdress = new LiteralValue(null);
1007
+ const [left, leftInst] = c.handleEval(scope, node.left);
1008
+ const [nullTest] = left["=="](scope, nullLiteral);
1009
+ if (nullTest instanceof LiteralValue) {
1010
+ if (nullTest.data)
1011
+ return c.handleEval(scope, node.right);
1012
+ else
1013
+ return [left, leftInst];
1014
+ }
1015
+ const [right, rightInst] = c.handleEval(scope, node.right);
1016
+ const result = new StoreValue(scope);
1017
+ result.ensureOwned();
1018
+ return [
1019
+ result,
1020
+ [
1021
+ ...leftInst,
1022
+ ...result["="](scope, left)[1],
1023
+ new JumpInstruction(endAdress, EJumpKind.NotEqual, result, nullLiteral),
1024
+ ...rightInst,
1025
+ ...result["="](scope, right)[1],
1026
+ new AddressResolver(endAdress),
1027
+ ],
1028
+ ];
1029
+ };
933
1030
  const AssignmentExpression = (c, scope, node) => {
934
1031
  const [left, leftInst] = c.handle(scope, node.left);
935
1032
  // doesn't need to consume because the operators already do that
@@ -965,13 +1062,13 @@ const ConditionalExpression = (c, scope, node) => {
965
1062
  result.ensureOwned();
966
1063
  const consequent = c.handleEval(scope, node.consequent);
967
1064
  const alternate = c.handleEval(scope, node.alternate);
968
- const alternateStartAdress = new LiteralValue(scope, null);
969
- const endExpressionAdress = new LiteralValue(scope, null);
1065
+ const alternateStartAdress = new LiteralValue(null);
1066
+ const endExpressionAdress = new LiteralValue(null);
970
1067
  return [
971
1068
  result,
972
1069
  [
973
1070
  ...testInst,
974
- new JumpInstruction(alternateStartAdress, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
1071
+ new JumpInstruction(alternateStartAdress, EJumpKind.Equal, test, new LiteralValue(0)),
975
1072
  ...consequent[1],
976
1073
  ...result["="](scope, consequent[0])[1],
977
1074
  new JumpInstruction(endExpressionAdress, EJumpKind.Always),
@@ -991,12 +1088,12 @@ const ExpressionStatement = (c, scope, node) => {
991
1088
  return c.handle(scope, node.expression);
992
1089
  };
993
1090
  const BreakStatement = (_, scope) => {
994
- const addr = new LiteralValue(scope, null);
1091
+ const addr = new LiteralValue(null);
995
1092
  scope.break.bind(addr);
996
1093
  return [null, [new BreakInstruction(addr)]];
997
1094
  };
998
1095
  const ContinueStatement = (_, scope) => {
999
- const addr = new LiteralValue(scope, null);
1096
+ const addr = new LiteralValue(null);
1000
1097
  scope.continue.bind(addr);
1001
1098
  return [null, [new ContinueInstruction(addr)]];
1002
1099
  };
@@ -1018,19 +1115,81 @@ const IfStatement = (c, scope, node) => {
1018
1115
  inst.push(...c.handle(scope, node.alternate)[1]);
1019
1116
  return [null, inst];
1020
1117
  }
1021
- const endIfAddr = new LiteralValue(scope, null);
1022
- inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...c.handle(scope, node.consequent)[1], new AddressResolver(endIfAddr));
1023
- const endElseAddr = new LiteralValue(scope, null);
1024
- if (node.alternate)
1025
- inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...c.handle(scope, node.alternate)[1], new AddressResolver(endElseAddr));
1118
+ const endIfAddr = new LiteralValue(null);
1119
+ inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(0)), ...withAlwaysRuns(c.handle(scope, node.consequent), false)[1], new AddressResolver(endIfAddr));
1120
+ const endElseAddr = new LiteralValue(null);
1121
+ if (node.alternate) {
1122
+ inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...withAlwaysRuns(c.handle(scope, node.alternate), false)[1], new AddressResolver(endElseAddr));
1123
+ }
1026
1124
  return [null, inst];
1027
1125
  };
1028
1126
 
1127
+ const SwitchStatement = (c, scope, node) => {
1128
+ const innerScope = scope.createScope();
1129
+ const [ref, refInst] = c.handleConsume(scope, node.discriminant);
1130
+ const inst = [];
1131
+ const endAdress = new LiteralValue(null);
1132
+ const endLine = new AddressResolver(endAdress).bindBreak(innerScope);
1133
+ const caseJumps = [];
1134
+ let defaultJump;
1135
+ for (const scase of node.cases) {
1136
+ const [, bodyInst] = c.handleMany(innerScope, scase.consequent);
1137
+ const bodyAdress = new LiteralValue(null);
1138
+ const bodyLine = new AddressResolver(bodyAdress);
1139
+ if (!scase.test) {
1140
+ [defaultJump] = c.handle(innerScope, scase, () => [
1141
+ null,
1142
+ [new JumpInstruction(bodyAdress, EJumpKind.Always)],
1143
+ ])[1];
1144
+ inst.push(bodyLine, ...bodyInst);
1145
+ continue;
1146
+ }
1147
+ const [test, testInst] = c.handleConsume(innerScope, scase.test);
1148
+ // check if it can be evaluated at compile time
1149
+ const [comp] = ref["=="](innerScope, test);
1150
+ // if the constant expression resolves to false
1151
+ // the whole case gets omitted
1152
+ // otherwise it returns the instructions for
1153
+ // the body of this case
1154
+ if (comp instanceof LiteralValue) {
1155
+ if (comp.data)
1156
+ return [null, bodyInst];
1157
+ else
1158
+ continue;
1159
+ }
1160
+ // makes sourcemapping for the jump more specific
1161
+ const [, jump] = c.handle(innerScope, scase, () => [
1162
+ null,
1163
+ [new JumpInstruction(bodyAdress, EJumpKind.StrictEqual, ref, test)],
1164
+ ]);
1165
+ caseJumps.push(...testInst, ...jump);
1166
+ inst.push(bodyLine, ...bodyInst);
1167
+ }
1168
+ // ensures that the processor exits
1169
+ // the switch if no cases match
1170
+ defaultJump ??= new JumpInstruction(endAdress, EJumpKind.Always);
1171
+ if (caseJumps.length > 0) {
1172
+ withAlwaysRuns([null, inst], false);
1173
+ withAlwaysRuns([null, [...caseJumps.slice(1), defaultJump]], false);
1174
+ withAlwaysRuns([null, inst], false);
1175
+ }
1176
+ return [
1177
+ null,
1178
+ [
1179
+ ...refInst,
1180
+ ...caseJumps,
1181
+ ...(caseJumps.length > 0 ? [defaultJump] : []),
1182
+ ...inst,
1183
+ endLine,
1184
+ ],
1185
+ ];
1186
+ };
1187
+
1029
1188
  const WhileStatement = (c, scope, node) => {
1030
1189
  const lines = [];
1031
1190
  const [test, testLines] = c.handleConsume(scope, node.test);
1032
- const startLoopAddr = new LiteralValue(scope, null);
1033
- const endLoopAddr = new LiteralValue(scope, null);
1191
+ const startLoopAddr = new LiteralValue(null);
1192
+ const endLoopAddr = new LiteralValue(null);
1034
1193
  const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1035
1194
  const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1036
1195
  if (test instanceof LiteralValue) {
@@ -1039,13 +1198,13 @@ const WhileStatement = (c, scope, node) => {
1039
1198
  }
1040
1199
  return [null, lines];
1041
1200
  }
1042
- lines.push(startLoopLine, ...testLines, new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...c.handle(scope, node.body)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
1201
+ lines.push(startLoopLine, ...testLines, new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(0)), ...withAlwaysRuns(c.handle(scope, node.body), false)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
1043
1202
  return [null, lines];
1044
1203
  };
1045
1204
  const DoWhileStatement = (c, scope, node) => {
1046
1205
  const lines = [];
1047
1206
  const [test, testLines] = c.handleConsume(scope, node.test);
1048
- const startLoopAddr = new LiteralValue(scope, null);
1207
+ const startLoopAddr = new LiteralValue(null);
1049
1208
  const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1050
1209
  const [, bodyLines] = c.handle(scope, node.body);
1051
1210
  if (test instanceof LiteralValue) {
@@ -1061,7 +1220,7 @@ const DoWhileStatement = (c, scope, node) => {
1061
1220
  ],
1062
1221
  ];
1063
1222
  }
1064
- lines.push(startLoopLine, ...bodyLines, ...testLines, new JumpInstruction(startLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 1)));
1223
+ lines.push(startLoopLine, ...bodyLines, ...testLines, new JumpInstruction(startLoopAddr, EJumpKind.Equal, test, new LiteralValue(1)));
1065
1224
  return [null, lines];
1066
1225
  };
1067
1226
 
@@ -1070,10 +1229,10 @@ const ForStatement = (c, scope, node) => {
1070
1229
  const initInst = node.init ? c.handle(scope, node.init)[1] : [];
1071
1230
  const [test, testLines] = node.test
1072
1231
  ? c.handleConsume(scope, node.test)
1073
- : [new LiteralValue(scope, 1), []];
1232
+ : [new LiteralValue(1), []];
1074
1233
  const updateLines = node.update ? c.handle(scope, node.update)[1] : [];
1075
- const startLoopAddr = new LiteralValue(scope, null);
1076
- const endLoopAddr = new LiteralValue(scope, null);
1234
+ const startLoopAddr = new LiteralValue(null);
1235
+ const endLoopAddr = new LiteralValue(null);
1077
1236
  const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1078
1237
  const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1079
1238
  return [
@@ -1082,8 +1241,8 @@ const ForStatement = (c, scope, node) => {
1082
1241
  ...initInst,
1083
1242
  startLoopLine,
1084
1243
  ...testLines,
1085
- new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
1086
- ...c.handle(scope, node.body)[1],
1244
+ new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(0)),
1245
+ ...withAlwaysRuns(c.handle(scope, node.body), false)[1],
1087
1246
  ...updateLines,
1088
1247
  new JumpInstruction(startLoopAddr, EJumpKind.Always),
1089
1248
  endLoopLine,
@@ -1092,20 +1251,20 @@ const ForStatement = (c, scope, node) => {
1092
1251
  };
1093
1252
 
1094
1253
  class FunctionValue extends VoidValue {
1095
- constructor({ scope, params, body, c, node, }) {
1096
- super(scope);
1254
+ constructor({ scope, params, body, c, }) {
1255
+ super();
1097
1256
  this.mutability = EMutability.constant;
1098
1257
  this.macro = true;
1099
1258
  this.paramOwners = [];
1100
1259
  this.bundled = false;
1101
1260
  this.initialized = false;
1261
+ this.scope = scope;
1102
1262
  this.body = body;
1103
1263
  this.c = c;
1104
- this.node = node;
1105
1264
  this.params = params;
1106
1265
  }
1107
- typeof(scope) {
1108
- return [new LiteralValue(scope, "function"), []];
1266
+ typeof() {
1267
+ return [new LiteralValue("function"), []];
1109
1268
  }
1110
1269
  initScope(name) {
1111
1270
  this.childScope = this.scope.createFunction(name);
@@ -1114,7 +1273,9 @@ class FunctionValue extends VoidValue {
1114
1273
  const name = nodeName(id, !this.c.compactNames && id.name);
1115
1274
  const owner = new ValueOwner({
1116
1275
  scope: this.childScope,
1117
- value: new StoreValue(this.childScope),
1276
+ value: assign(new SenseableValue(this.childScope), {
1277
+ mutability: EMutability.mutable,
1278
+ }),
1118
1279
  identifier: id.name,
1119
1280
  name,
1120
1281
  });
@@ -1131,7 +1292,7 @@ class FunctionValue extends VoidValue {
1131
1292
  this.initialized = true;
1132
1293
  const { name } = this.owner;
1133
1294
  this.initScope(name);
1134
- this.addr = new LiteralValue(this.childScope, null);
1295
+ this.addr = new LiteralValue(null);
1135
1296
  this.temp = new ValueOwner({
1136
1297
  scope: this.childScope,
1137
1298
  name: `${internalPrefix}f${name}`,
@@ -1149,18 +1310,23 @@ class FunctionValue extends VoidValue {
1149
1310
  ...this.c.handle(this.childScope, this.body)[1],
1150
1311
  ];
1151
1312
  if (!endsWithReturn(this.inst)) {
1152
- this.inst.push(new SetCounterInstruction(this.ret.value));
1313
+ this.inst.push(assign(new SetCounterInstruction(this.ret.value), {
1314
+ intent: EInstIntent.return,
1315
+ }));
1153
1316
  }
1154
1317
  }
1155
1318
  normalReturn(scope, arg) {
1156
1319
  const argInst = arg ? this.temp.value["="](scope, arg)[1] : [];
1157
- return [null, [...argInst, new SetCounterInstruction(this.ret.value)]];
1320
+ const returnInst = assign(new SetCounterInstruction(this.ret.value), {
1321
+ intent: EInstIntent.return,
1322
+ });
1323
+ return [null, [...argInst, returnInst]];
1158
1324
  }
1159
1325
  normalCall(scope, args) {
1160
1326
  if (!this.bundled)
1161
1327
  this.childScope.inst.push(...this.inst);
1162
1328
  this.bundled = true;
1163
- const callAddressLiteral = new LiteralValue(scope, null);
1329
+ const callAddressLiteral = new LiteralValue(null);
1164
1330
  const inst = this.paramOwners
1165
1331
  .map(({ value: param }, i) => param["="](scope, args[i])[1])
1166
1332
  .reduce((s, c) => s.concat(c), [])
@@ -1169,7 +1335,12 @@ class FunctionValue extends VoidValue {
1169
1335
  }
1170
1336
  inlineReturn(scope, arg) {
1171
1337
  const argInst = arg ? this.inlineTemp.value["="](scope, arg)[1] : [];
1172
- return [null, argInst];
1338
+ if (!this.inlineEnd)
1339
+ throw new CompilerError("Error during inline attempt: missing inline end adress");
1340
+ const jump = assign(new JumpInstruction(this.inlineEnd, EJumpKind.Always), {
1341
+ intent: EInstIntent.return,
1342
+ });
1343
+ return [null, [...argInst, jump]];
1173
1344
  }
1174
1345
  inlineCall(scope, args) {
1175
1346
  // create return value
@@ -1179,7 +1350,6 @@ class FunctionValue extends VoidValue {
1179
1350
  mutability: EMutability.mutable,
1180
1351
  }),
1181
1352
  });
1182
- this.inlineEnd = new LiteralValue(scope, null);
1183
1353
  // make a copy of the function scope
1184
1354
  const fnScope = this.childScope.copy();
1185
1355
  // hard set variables within the function scope
@@ -1194,16 +1364,13 @@ class FunctionValue extends VoidValue {
1194
1364
  name: owner.name,
1195
1365
  }));
1196
1366
  });
1367
+ this.inlineEnd = new LiteralValue(null);
1197
1368
  this.tryingInline = true;
1198
- const inst = this.c.handle(fnScope, this.body)[1];
1369
+ let inst = this.c.handle(fnScope, this.body)[1];
1199
1370
  this.tryingInline = false;
1200
- // removing useless instruction
1201
- // get the last instructions
1202
- // const [jump] = inst.slice(-1);
1203
- // if (jump instanceof JumpInstruction) {
1204
- // // remove useless jump
1205
- // if (jump.args[1] === this.inlineEnd) inst.pop();
1206
- // }
1371
+ const returnIndex = inst.findIndex(i => i.alwaysRuns && i.intent === EInstIntent.return);
1372
+ if (returnIndex !== -1)
1373
+ inst = inst.slice(0, returnIndex + 1);
1207
1374
  inst.push(new AddressResolver(this.inlineEnd));
1208
1375
  // return the function value
1209
1376
  return [this.inlineTemp.value, inst];
@@ -1248,11 +1415,14 @@ function endsWithReturn(inst) {
1248
1415
  function handleFunctionNode(c, scope, node) {
1249
1416
  let { params, body } = node;
1250
1417
  if (es__namespace.isExpression(body)) {
1251
- body = es__namespace.blockStatement([es__namespace.returnStatement(body)]);
1418
+ const { loc } = body;
1419
+ const statement = es__namespace.returnStatement(body);
1420
+ statement.loc = loc;
1421
+ body = es__namespace.blockStatement([statement]);
1422
+ body.loc = loc;
1252
1423
  }
1253
1424
  return [
1254
1425
  new FunctionValue({
1255
- node,
1256
1426
  scope,
1257
1427
  params: params,
1258
1428
  body,
@@ -1294,16 +1464,32 @@ const CallExpression = (c, scope, node) => {
1294
1464
  inst.push(...callInst);
1295
1465
  return [callValue, inst];
1296
1466
  };
1297
- const NewExpression = CallExpression;
1467
+ const NewExpression = CallExpression;
1468
+ const TaggedTemplateExpression = (c, scope, node) => {
1469
+ const [tag, tagInst] = c.handleConsume(scope, node.tag);
1470
+ const template = node.quasi;
1471
+ const stringsObject = ObjectValue.fromArray(template.quasis.map(quasi => new LiteralValue(quasi.value.cooked ?? "")), {
1472
+ raw: ObjectValue.fromArray(template.quasis.map(quasi => new LiteralValue(quasi.value.raw))),
1473
+ });
1474
+ const expressions = [];
1475
+ const expressionInsts = [];
1476
+ template.expressions.forEach(expression => {
1477
+ const [value, inst] = c.handleConsume(scope, expression);
1478
+ expressions.push(value);
1479
+ expressionInsts.push(...inst);
1480
+ });
1481
+ const [result, resultInst] = tag.call(scope, [stringsObject, ...expressions]);
1482
+ return [result, [...expressionInsts, ...tagInst, ...resultInst]];
1483
+ };
1298
1484
 
1299
1485
  const ObjectExpression = (c, scope, node) => {
1300
1486
  const data = {};
1301
1487
  const inst = [];
1302
1488
  for (const prop of node.properties) {
1303
1489
  if (prop.type === "SpreadElement")
1304
- throw new CompilerError("Cannot handle spread element", [prop]);
1490
+ throw new CompilerError("Cannot handle spread element", prop);
1305
1491
  if (prop.computed)
1306
- throw new CompilerError("Cannot handle computed property.", [prop]);
1492
+ throw new CompilerError("Cannot handle computed property.", prop);
1307
1493
  const { key } = prop;
1308
1494
  const value = prop.type === "ObjectProperty" ? prop.value : prop;
1309
1495
  let index;
@@ -1314,20 +1500,21 @@ const ObjectExpression = (c, scope, node) => {
1314
1500
  index = `${key.value}`;
1315
1501
  }
1316
1502
  else {
1317
- throw new CompilerError(`Unsupported object key type: ${key.type}`, [
1318
- key,
1319
- ]);
1503
+ throw new CompilerError(`Unsupported object key type: ${key.type}`, key);
1320
1504
  }
1321
1505
  const [member, memberInst] = c.handleEval(scope, value);
1322
- const owner = new ValueOwner({
1323
- scope,
1324
- constant: true,
1325
- value: member,
1326
- });
1327
- data[index] = owner.value;
1506
+ // TODO: use an approach that can be defined by each type
1507
+ if (!member.owner && !(member instanceof LiteralValue)) {
1508
+ new ValueOwner({
1509
+ scope,
1510
+ constant: true,
1511
+ value: member,
1512
+ });
1513
+ }
1514
+ data[index] = member;
1328
1515
  inst.push(...memberInst);
1329
1516
  }
1330
- return [new ObjectValue(scope, data), inst];
1517
+ return [new ObjectValue(data), inst];
1331
1518
  };
1332
1519
  const ArrayExpression = (c, scope, node) => {
1333
1520
  const items = [];
@@ -1339,13 +1526,13 @@ const ArrayExpression = (c, scope, node) => {
1339
1526
  items.push(value);
1340
1527
  inst.push(...valueInst);
1341
1528
  });
1342
- return [ObjectValue.fromArray(scope, items), inst];
1529
+ return [ObjectValue.fromArray(items), inst];
1343
1530
  };
1344
1531
  const MemberExpression = (c, scope, node) => {
1345
1532
  const [obj, objInst] = c.handleConsume(scope, node.object);
1346
1533
  const [prop, propInst] = node.computed
1347
1534
  ? c.handleConsume(scope, node.property)
1348
- : [new LiteralValue(scope, node.property.name), []];
1535
+ : [new LiteralValue(node.property.name), []];
1349
1536
  const [got, gotInst] = obj.get(scope, prop);
1350
1537
  return [got, [...objInst, ...propInst, ...gotInst]];
1351
1538
  };
@@ -1358,13 +1545,11 @@ const ArrayPattern = (c, scope, node) => {
1358
1545
  continue;
1359
1546
  const valueInst = c.handle(scope, element);
1360
1547
  if (!valueInst[0])
1361
- throw new CompilerError("Destructuring element must resolve to a value", [
1362
- element,
1363
- ]);
1548
+ throw new CompilerError("Destructuring element must resolve to a value", element);
1364
1549
  inst.push(...valueInst[1]);
1365
- members.set(new LiteralValue(scope, i), valueInst[0]);
1550
+ members.set(new LiteralValue(i), valueInst[0]);
1366
1551
  }
1367
- return [new DestructuringValue(scope, members), inst];
1552
+ return [new DestructuringValue(members), inst];
1368
1553
  };
1369
1554
  const ObjectPattern = (c, scope, node) => {
1370
1555
  const inst = [];
@@ -1376,31 +1561,20 @@ const ObjectPattern = (c, scope, node) => {
1376
1561
  continue;
1377
1562
  const { key } = prop;
1378
1563
  const keyInst = !prop.computed && key.type === "Identifier"
1379
- ? [new LiteralValue(scope, key.name), []]
1564
+ ? [new LiteralValue(key.name), []]
1380
1565
  : c.handleConsume(scope, prop.key);
1381
1566
  inst.push(...keyInst[1]);
1382
1567
  const valueInst = c.handle(scope, prop.value);
1383
1568
  if (!valueInst[0])
1384
- throw new CompilerError("Destructuring member must resolve to a value", [
1385
- prop.value,
1386
- ]);
1569
+ throw new CompilerError("Destructuring member must resolve to a value", prop.value);
1387
1570
  inst.push(...valueInst[1]);
1388
1571
  members.set(keyInst[0], valueInst[0]);
1389
1572
  }
1390
- return [new DestructuringValue(scope, members), inst];
1573
+ return [new DestructuringValue(members), inst];
1391
1574
  };
1392
1575
 
1393
- const TemplateLiteral = (c, scope, node) => {
1394
- const args = [];
1395
- const inst = [];
1396
- node.expressions.forEach((expression, i) => {
1397
- const [v, vi] = c.handleConsume(scope, expression);
1398
- inst.push(...vi);
1399
- args.push(node.quasis[i].value.raw, v);
1400
- });
1401
- args.push(node.quasis.slice(-1)[0].value.raw);
1402
- inst.push(new ZeroSpaceInstruction(...args));
1403
- return [null, inst];
1576
+ const TemplateLiteral = () => {
1577
+ throw new CompilerError("Template strings are currently unavailable. To inline mlog code use the asm function.");
1404
1578
  };
1405
1579
 
1406
1580
  const BlockStatement = (c, scope, node) => {
@@ -1433,14 +1607,12 @@ const TSEnumDeclaration = (c, scope, node) => {
1433
1607
  const data = {};
1434
1608
  for (const member of node.members) {
1435
1609
  if (lastType === "string" && !member.initializer)
1436
- throw new CompilerError("This enum member must be initialized", [member]);
1610
+ throw new CompilerError("This enum member must be initialized", member);
1437
1611
  const [value] = member.initializer
1438
1612
  ? c.handleEval(scope, member.initializer)
1439
- : [new LiteralValue(scope, counter)];
1613
+ : [new LiteralValue(counter)];
1440
1614
  if (!(value instanceof LiteralValue))
1441
- throw new CompilerError("Enum members must contain literal values", [
1442
- member,
1443
- ]);
1615
+ throw new CompilerError("Enum members must contain literal values", member);
1444
1616
  if (typeof value.data === "number") {
1445
1617
  lastType = "number";
1446
1618
  counter = value.data + 1;
@@ -1453,7 +1625,7 @@ const TSEnumDeclaration = (c, scope, node) => {
1453
1625
  }
1454
1626
  scope.set(new ValueOwner({
1455
1627
  scope,
1456
- value: new ObjectValue(scope, data),
1628
+ value: new ObjectValue(data),
1457
1629
  constant: true,
1458
1630
  identifier: node.id.name,
1459
1631
  name: nodeName(node, !c.compactNames && node.id.name),
@@ -1486,6 +1658,7 @@ var handlers = /*#__PURE__*/Object.freeze({
1486
1658
  ContinueStatement: ContinueStatement,
1487
1659
  ReturnStatement: ReturnStatement,
1488
1660
  IfStatement: IfStatement,
1661
+ SwitchStatement: SwitchStatement,
1489
1662
  WhileStatement: WhileStatement,
1490
1663
  DoWhileStatement: DoWhileStatement,
1491
1664
  ForStatement: ForStatement,
@@ -1495,6 +1668,7 @@ var handlers = /*#__PURE__*/Object.freeze({
1495
1668
  ObjectMethod: ObjectMethod,
1496
1669
  CallExpression: CallExpression,
1497
1670
  NewExpression: NewExpression,
1671
+ TaggedTemplateExpression: TaggedTemplateExpression,
1498
1672
  ObjectExpression: ObjectExpression,
1499
1673
  ArrayExpression: ArrayExpression,
1500
1674
  MemberExpression: MemberExpression,
@@ -1512,14 +1686,14 @@ var handlers = /*#__PURE__*/Object.freeze({
1512
1686
  });
1513
1687
 
1514
1688
  class MacroFunction extends VoidValue {
1515
- constructor(scope, fn) {
1516
- super(scope);
1689
+ constructor(fn) {
1690
+ super();
1517
1691
  this.macro = true;
1518
1692
  this.constant = true;
1519
1693
  this.fn = fn;
1520
1694
  }
1521
1695
  call(scope, args) {
1522
- return this.fn.apply(this, args);
1696
+ return this.fn.apply(this, [scope, ...args]);
1523
1697
  }
1524
1698
  eval(_scope) {
1525
1699
  return [this, []];
@@ -1550,16 +1724,16 @@ const mathOperations = {
1550
1724
  sqrt: a => Math.sqrt(a),
1551
1725
  rand: null,
1552
1726
  };
1553
- function createMacroMathOperations(scope) {
1727
+ function createMacroMathOperations() {
1554
1728
  const macroMathOperations = {};
1555
1729
  for (const key in mathOperations) {
1556
1730
  const fn = mathOperations[key];
1557
- macroMathOperations[key] = new MacroFunction(scope, (a, b) => {
1731
+ macroMathOperations[key] = new MacroFunction((scope, a, b) => {
1558
1732
  if (b) {
1559
1733
  if (fn && a instanceof LiteralValue && b instanceof LiteralValue) {
1560
1734
  if (typeof a.data !== "number" || typeof b.data !== "number")
1561
1735
  throw new CompilerError("Cannot do math operation with non-numerical literals.");
1562
- return [new LiteralValue(scope, fn(a.num, b.num)), []];
1736
+ return [new LiteralValue(fn(a.num, b.num)), []];
1563
1737
  }
1564
1738
  const temp = new StoreValue(scope);
1565
1739
  return [temp, [new OperationInstruction(key, temp, a, b)]];
@@ -1567,7 +1741,7 @@ function createMacroMathOperations(scope) {
1567
1741
  if (fn && a instanceof LiteralValue) {
1568
1742
  if (typeof a.data !== "number")
1569
1743
  throw new CompilerError("Cannot do math operation with non-numerical literal.");
1570
- return [new LiteralValue(scope, fn(a.num)), []];
1744
+ return [new LiteralValue(fn(a.num)), []];
1571
1745
  }
1572
1746
  const temp = new StoreValue(scope);
1573
1747
  return [temp, [new OperationInstruction(key, temp, a, b)]];
@@ -1576,74 +1750,190 @@ function createMacroMathOperations(scope) {
1576
1750
  return macroMathOperations;
1577
1751
  }
1578
1752
  class MlogMath extends ObjectValue {
1579
- constructor(scope) {
1580
- super(scope, createMacroMathOperations(scope));
1753
+ constructor() {
1754
+ super(createMacroMathOperations());
1581
1755
  }
1582
1756
  }
1583
1757
  // op angle result a b
1584
1758
  // op len result a b
1585
1759
 
1586
1760
  class Concat extends MacroFunction {
1587
- constructor(scope) {
1588
- super(scope, (...values) => {
1761
+ constructor() {
1762
+ super((scope, ...values) => {
1589
1763
  for (const value of values)
1590
1764
  if (!(value instanceof LiteralValue))
1591
1765
  throw new CompilerError("Concat arguments must all be literal values.");
1592
1766
  return [
1593
- new LiteralValue(scope, values.map(v => v.data).join("")),
1767
+ new LiteralValue(values.map(v => v.data).join("")),
1594
1768
  [],
1595
1769
  ];
1596
1770
  });
1597
1771
  }
1598
1772
  }
1599
1773
 
1600
- class Draw extends MacroFunction {
1601
- constructor(scope) {
1602
- super(scope, (kind, ...args) => {
1603
- if (!(kind instanceof LiteralValue && typeof kind.data === "string"))
1604
- throw new CompilerError("Draw kind must be a string literal.");
1605
- if ([
1606
- "clear",
1607
- "color",
1608
- "stroke",
1609
- "line",
1610
- "rect",
1611
- "lineRect",
1612
- "poly",
1613
- "linePoly",
1614
- "triangle",
1615
- "image",
1616
- ].indexOf(kind.data) === -1)
1617
- throw new CompilerError("Invalid draw kind");
1618
- return [
1619
- null,
1620
- [
1621
- new InstructionBase("draw", kind.data, ...args.map(v => {
1622
- if (v instanceof LiteralValue && typeof v.data === "string")
1623
- return v.data;
1624
- return v;
1625
- })),
1626
- ],
1627
- ];
1774
+ /** Asserts that `value` is a `LiteralValue` that contains a string */
1775
+ function assertStringLiteral(value, name) {
1776
+ if (!(value instanceof LiteralValue) || typeof value.data !== "string")
1777
+ throw new CompilerError(`${name} must be a string literal`);
1778
+ }
1779
+ /** Asserts that `value` is a string literal that is part of a given set of `members`*/
1780
+ function assertLiteralOneOf(value, members, name) {
1781
+ assertStringLiteral(value, name);
1782
+ if (!members.includes(value.data))
1783
+ throw new CompilerError(`${name} must be one of: ${members
1784
+ .slice(0, -1)
1785
+ .map(member => `"${member}"`)
1786
+ .join(", ")} or "${members[members.length - 1]}"`);
1787
+ }
1788
+ /** Asserts that `value` is either a store or a literal */
1789
+ function assertIsRuntimeValue(value, name) {
1790
+ if (!(value instanceof LiteralValue) && !(value instanceof StoreValue))
1791
+ throw new CompilerError(`${name} must be a valid runtime value`);
1792
+ }
1793
+ /** Asserts that `value` is an `ObjectValue` */
1794
+ function assertIsObjectMacro(value, name) {
1795
+ if (!(value instanceof ObjectValue))
1796
+ throw new CompilerError(`${name} must be an object macro`);
1797
+ }
1798
+ /** Asserts that `value` is an `ObjectValue` that has a length property */
1799
+ function assertIsArrayMacro(value, name) {
1800
+ if (!(value instanceof ObjectValue) || !value.data.length)
1801
+ throw new CompilerError(`${name} must be an array macro`);
1802
+ }
1803
+ /** Asserts that all of the fields described are present on `value`*/
1804
+ function assertObjectFields(value, fields) {
1805
+ const result = [];
1806
+ for (const field of fields) {
1807
+ const param = typeof field === "object" ? field : { key: field };
1808
+ const item = value.data[param.key];
1809
+ if (item) {
1810
+ param.validate?.(item);
1811
+ result.push(item);
1812
+ continue;
1813
+ }
1814
+ if (param.default == undefined)
1815
+ throw new CompilerError(`The field "${param.name ?? param.key}" must be present`);
1816
+ result.push(param.default);
1817
+ }
1818
+ return result;
1819
+ }
1820
+
1821
+ /** Used to create namespaces that contain multiple methods that map into instructions */
1822
+ function createOverloadNamespace({ overloads, handler, }) {
1823
+ const result = {};
1824
+ for (const key in overloads) {
1825
+ const { named, args } = overloads[key];
1826
+ if (named) {
1827
+ result[key] = new MacroFunction((scope, options) => {
1828
+ assertIsObjectMacro(options, named);
1829
+ return handler(scope, key, ...assertObjectFields(options, args));
1830
+ });
1831
+ continue;
1832
+ }
1833
+ result[key] = new MacroFunction((scope, ...params) => {
1834
+ const handlerParams = [];
1835
+ // validate the paramters
1836
+ for (let i = 0; i < args.length; i++) {
1837
+ let arg = args[i];
1838
+ if (typeof arg === "string")
1839
+ arg = { key: arg };
1840
+ const param = params[i];
1841
+ if (!param) {
1842
+ if (arg.default == undefined)
1843
+ throw new CompilerError(`Missing argument: ${arg.name ?? arg.key}`);
1844
+ handlerParams.push(arg.default);
1845
+ continue;
1846
+ }
1847
+ arg.validate?.(param);
1848
+ handlerParams.push(param);
1849
+ }
1850
+ return handler(scope, key, ...handlerParams);
1628
1851
  });
1629
1852
  }
1853
+ return result;
1854
+ }
1855
+
1856
+ class Draw extends ObjectValue {
1857
+ constructor() {
1858
+ const data = createOverloadNamespace({
1859
+ overloads: {
1860
+ clear: {
1861
+ args: ["r", "g", "b"],
1862
+ },
1863
+ color: {
1864
+ args: ["r", "g", "b", { key: "a", default: "" }],
1865
+ },
1866
+ stroke: {
1867
+ args: ["width"],
1868
+ },
1869
+ line: {
1870
+ named: "options",
1871
+ args: ["x", "y", "x2", "y2"],
1872
+ },
1873
+ rect: {
1874
+ named: "options",
1875
+ args: ["x", "y", "width", "height"],
1876
+ },
1877
+ lineRect: { named: "options", args: ["x", "y", "width", "height"] },
1878
+ linePoly: {
1879
+ named: "options",
1880
+ args: ["x", "y", "sides", "radius", "rotation"],
1881
+ },
1882
+ poly: {
1883
+ named: "options",
1884
+ args: ["x", "y", "sides", "radius", "rotation"],
1885
+ },
1886
+ triangle: {
1887
+ named: "options",
1888
+ args: ["x", "y", "x2", "y2", "x3", "y3"],
1889
+ },
1890
+ image: {
1891
+ named: "options",
1892
+ args: ["x", "y", "image", "size", "rotation"],
1893
+ },
1894
+ },
1895
+ handler(scope, overload, ...args) {
1896
+ return [null, [new InstructionBase("draw", overload, ...args)]];
1897
+ },
1898
+ });
1899
+ super(data);
1900
+ }
1630
1901
  }
1631
1902
 
1632
1903
  class Print extends MacroFunction {
1633
- constructor(scope) {
1634
- super(scope, (...values) => {
1904
+ constructor() {
1905
+ super((scope, ...values) => {
1906
+ const [first] = values;
1635
1907
  const inst = [];
1636
- for (const value of values) {
1637
- inst.push(new InstructionBase("print", value));
1908
+ if (!isTemplateObjectArray(first)) {
1909
+ for (const value of values) {
1910
+ inst.push(new InstructionBase("print", value));
1911
+ }
1912
+ return [null, inst];
1638
1913
  }
1914
+ // `first` is likely a template strings array
1915
+ // maybe this should be checked in another way?
1916
+ const { length } = first.data;
1917
+ for (let i = 1; i < values.length; i++) {
1918
+ const [string] = first.get(scope, new LiteralValue(i - 1));
1919
+ if (string.data)
1920
+ inst.push(new InstructionBase("print", string));
1921
+ inst.push(new InstructionBase("print", values[i]));
1922
+ }
1923
+ const [tail] = first.get(scope, new LiteralValue(length.data - 1));
1924
+ if (tail.data)
1925
+ inst.push(new InstructionBase("print", tail));
1639
1926
  return [null, inst];
1640
1927
  });
1641
1928
  }
1642
1929
  }
1643
1930
 
1931
+ const defaultTargetName$1 = "message1";
1644
1932
  class PrintFlush extends MacroFunction {
1645
- constructor(scope) {
1646
- super(scope, (target) => {
1933
+ constructor() {
1934
+ super((scope, target) => {
1935
+ if (!target)
1936
+ return [null, [new InstructionBase("printflush", defaultTargetName$1)]];
1647
1937
  if (!(target instanceof SenseableValue))
1648
1938
  throw new CompilerError("The printflush target must be a senseable value");
1649
1939
  return [null, [new InstructionBase("printflush", target)]];
@@ -1651,9 +1941,12 @@ class PrintFlush extends MacroFunction {
1651
1941
  }
1652
1942
  }
1653
1943
 
1944
+ const defaultTargetName = "display1";
1654
1945
  class DrawFlush extends MacroFunction {
1655
- constructor(scope) {
1656
- super(scope, (target) => {
1946
+ constructor() {
1947
+ super((scope, target) => {
1948
+ if (!target)
1949
+ return [null, [new InstructionBase("drawflush", defaultTargetName)]];
1657
1950
  if (!(target instanceof SenseableValue))
1658
1951
  throw new CompilerError("The drawflush target must be a senseable value");
1659
1952
  return [null, [new InstructionBase("drawflush", target)]];
@@ -1661,9 +1954,32 @@ class DrawFlush extends MacroFunction {
1661
1954
  }
1662
1955
  }
1663
1956
 
1957
+ class GetBlock extends ObjectValue {
1958
+ constructor() {
1959
+ const data = createOverloadNamespace({
1960
+ overloads: {
1961
+ floor: { args: ["x", "y"] },
1962
+ ore: { args: ["x", "y"] },
1963
+ block: { args: ["x", "y"] },
1964
+ building: { args: ["x", "y"] },
1965
+ },
1966
+ handler(scope, overload, x, y) {
1967
+ const output = overload === "building"
1968
+ ? new SenseableValue(scope)
1969
+ : new StoreValue(scope);
1970
+ return [
1971
+ output,
1972
+ [new InstructionBase("getblock", overload, output, x, y)],
1973
+ ];
1974
+ },
1975
+ });
1976
+ super(data);
1977
+ }
1978
+ }
1979
+
1664
1980
  class GetLink extends MacroFunction {
1665
- constructor(scope) {
1666
- super(scope, (index) => {
1981
+ constructor() {
1982
+ super((scope, index) => {
1667
1983
  if (!(index instanceof StoreValue) &&
1668
1984
  (!(index instanceof LiteralValue) || typeof index.data !== "number"))
1669
1985
  throw new CompilerError("The getlink index must be a number literal or a store");
@@ -1673,21 +1989,26 @@ class GetLink extends MacroFunction {
1673
1989
  }
1674
1990
  }
1675
1991
 
1676
- const validKinds$1 = ["enabled", "shoot", "shootp", "config", "color"];
1677
- class Control extends MacroFunction {
1678
- constructor(scope) {
1679
- super(scope, (kind, building, ...args) => {
1680
- if (!(kind instanceof LiteralValue) || typeof kind.data !== "string")
1681
- throw new CompilerError("The control kind must be a string literal");
1682
- if (!validKinds$1.includes(kind.data))
1683
- throw new CompilerError("Invalid control kind");
1684
- if (!(building instanceof SenseableValue))
1685
- throw new CompilerError("The building must be a senseable value");
1686
- return [
1687
- null,
1688
- [new InstructionBase("control", kind.data, building, ...args)],
1689
- ];
1690
- });
1992
+ class Control extends ObjectValue {
1993
+ constructor() {
1994
+ super(createOverloadNamespace({
1995
+ overloads: {
1996
+ enabled: { args: ["building", "value"] },
1997
+ shoot: {
1998
+ named: "options",
1999
+ args: ["building", "x", "y", "shoot"],
2000
+ },
2001
+ shootp: {
2002
+ named: "options",
2003
+ args: ["building", "unit", "shoot"],
2004
+ },
2005
+ config: { args: ["building", "value"] },
2006
+ color: { args: ["building", "r", "g", "b"] },
2007
+ },
2008
+ handler(scope, overload, ...args) {
2009
+ return [null, [new InstructionBase("control", overload, ...args)]];
2010
+ },
2011
+ }));
1691
2012
  }
1692
2013
  }
1693
2014
 
@@ -1709,29 +2030,26 @@ const validRadarSorts = [
1709
2030
  "maxHealth",
1710
2031
  ];
1711
2032
  class Radar extends MacroFunction {
1712
- constructor(scope) {
1713
- super(scope, (building, filter1, filter2, filter3, order, sort) => {
2033
+ constructor() {
2034
+ super((scope, options) => {
2035
+ assertIsObjectMacro(options, "The radar options");
2036
+ const { building, filters, order, sort } = options.data;
1714
2037
  if (!(building instanceof SenseableValue))
1715
2038
  throw new CompilerError("The building must a senseable value");
1716
- if (!(filter1 instanceof LiteralValue) ||
1717
- typeof filter1.data !== "string" ||
1718
- !(filter2 instanceof LiteralValue) ||
1719
- typeof filter2.data !== "string" ||
1720
- !(filter3 instanceof LiteralValue) ||
1721
- typeof filter3.data !== "string")
1722
- throw new CompilerError("The filters must be string literals");
1723
- if (!validRadarFilters.includes(filter1.data))
1724
- throw new CompilerError("Invalid value for filter1");
1725
- if (!validRadarFilters.includes(filter2.data))
1726
- throw new CompilerError("Invalid value for filter2");
1727
- if (!validRadarFilters.includes(filter3.data))
1728
- throw new CompilerError("Invalid value for filter3");
2039
+ assertIsArrayMacro(filters, "filters");
2040
+ const { length } = filters.data;
2041
+ if (!(length instanceof LiteralValue) || typeof length.data !== "number")
2042
+ throw new CompilerError("The length of an array macro must be");
2043
+ if (length.data !== 3)
2044
+ throw new CompilerError("The filters array must have 3 items");
2045
+ // data is not an array
2046
+ const { 0: filter1, 1: filter2, 2: filter3 } = filters.data;
2047
+ assertLiteralOneOf(filter1, validRadarFilters, "The first filter");
2048
+ assertLiteralOneOf(filter2, validRadarFilters, "The second filter");
2049
+ assertLiteralOneOf(filter3, validRadarFilters, "The third filter");
1729
2050
  if (!(order instanceof LiteralValue || order instanceof StoreValue))
1730
2051
  throw new CompilerError("The radar order must be a literal or a store");
1731
- if (!(sort instanceof LiteralValue) || typeof sort.data !== "string")
1732
- throw new CompilerError("The radar sort must be a string literal");
1733
- if (!validRadarSorts.includes(sort.data))
1734
- throw new CompilerError("Invalid sort value");
2052
+ assertLiteralOneOf(sort, validRadarSorts, "The radar sort");
1735
2053
  const outUnit = new SenseableValue(scope);
1736
2054
  return [
1737
2055
  outUnit,
@@ -1744,21 +2062,23 @@ class Radar extends MacroFunction {
1744
2062
  }
1745
2063
 
1746
2064
  class Sensor extends MacroFunction {
1747
- constructor(scope) {
1748
- super(scope, (property, target) => {
2065
+ constructor() {
2066
+ super((scope, property, target) => {
1749
2067
  if (!(property instanceof StoreValue))
1750
2068
  throw new CompilerError("The sensor property must be a store");
1751
2069
  if (!(target instanceof SenseableValue))
1752
2070
  throw new CompilerError("The sensor target must be a senseable value");
1753
- const temp = new StoreValue(scope);
2071
+ const temp = assign(new SenseableValue(scope), {
2072
+ mutability: EMutability.readonly,
2073
+ });
1754
2074
  return [temp, [new InstructionBase("sensor", temp, target, property)]];
1755
2075
  });
1756
2076
  }
1757
2077
  }
1758
2078
 
1759
2079
  class Wait extends MacroFunction {
1760
- constructor(scope) {
1761
- super(scope, seconds => {
2080
+ constructor() {
2081
+ super((scope, seconds) => {
1762
2082
  if (!(seconds instanceof StoreValue) &&
1763
2083
  !(seconds instanceof LiteralValue && typeof seconds.data === "number"))
1764
2084
  throw new CompilerError("The wait seconds must be either a number literal or a store");
@@ -1767,32 +2087,102 @@ class Wait extends MacroFunction {
1767
2087
  }
1768
2088
  }
1769
2089
 
1770
- const validKinds = ["block", "unit", "item", "liquid"];
1771
- class Lookup extends MacroFunction {
1772
- constructor(scope) {
1773
- super(scope, (kind, index) => {
1774
- if (!(kind instanceof LiteralValue && typeof kind.data === "string"))
1775
- throw new CompilerError("The lookup kind must be a string literal");
1776
- if (!validKinds.includes(kind.data))
1777
- throw new CompilerError("Invalid lookup kind");
1778
- if (!(index instanceof LiteralValue && typeof index.data === "number") &&
1779
- !(index instanceof StoreValue))
1780
- throw new CompilerError("The lookup index must be a number literal or a store");
1781
- const temp = new StoreValue(scope);
1782
- return [temp, [new InstructionBase("lookup", kind.data, temp, index)]];
2090
+ class Lookup extends ObjectValue {
2091
+ constructor() {
2092
+ const data = createOverloadNamespace({
2093
+ overloads: {
2094
+ block: { args: ["index"] },
2095
+ unit: { args: ["index"] },
2096
+ item: { args: ["index"] },
2097
+ liquid: { args: ["index"] },
2098
+ },
2099
+ handler(scope, overload, index) {
2100
+ const output = new StoreValue(scope);
2101
+ return [
2102
+ output,
2103
+ [new InstructionBase("lookup", overload, output, index)],
2104
+ ];
2105
+ },
2106
+ });
2107
+ super(data);
2108
+ }
2109
+ }
2110
+
2111
+ class PackColor extends MacroFunction {
2112
+ constructor() {
2113
+ super((scope, ...args) => {
2114
+ if (args.length !== 4) {
2115
+ throw new CompilerError(`Expected 4 arguments, received ${args.length}`);
2116
+ }
2117
+ if (!args.every((value) => value instanceof StoreValue ||
2118
+ (value instanceof LiteralValue && typeof value.data === "number"))) {
2119
+ throw new CompilerError("packColor arguments must be either stores or number literals");
2120
+ }
2121
+ const output = new StoreValue(scope);
2122
+ return [output, [new InstructionBase("packcolor", output, ...args)]];
1783
2123
  });
1784
2124
  }
1785
2125
  }
1786
2126
 
1787
2127
  class End extends MacroFunction {
1788
- constructor(scope) {
1789
- super(scope, () => [null, [new EndInstruction()]]);
2128
+ constructor() {
2129
+ super(() => [null, [new EndInstruction()]]);
2130
+ }
2131
+ }
2132
+
2133
+ class SetBlock extends ObjectValue {
2134
+ constructor() {
2135
+ const data = createOverloadNamespace({
2136
+ overloads: {
2137
+ floor: { args: ["x", "y", "to"] },
2138
+ ore: { args: ["x", "y", "to"] },
2139
+ block: {
2140
+ named: "options",
2141
+ args: ["x", "y", "to", "team", { key: "rotation", default: "0" }],
2142
+ },
2143
+ },
2144
+ handler(scope, overload, x, y, to, team, rotation) {
2145
+ return [
2146
+ null,
2147
+ [
2148
+ new InstructionBase("setblock", overload, to, x, y, team ?? "@delerict", rotation ?? "0"),
2149
+ ],
2150
+ ];
2151
+ },
2152
+ });
2153
+ super(data);
2154
+ }
2155
+ }
2156
+
2157
+ class SpawnUnit extends MacroFunction {
2158
+ constructor() {
2159
+ super((scope, options) => {
2160
+ assertIsObjectMacro(options, "The options");
2161
+ const { type, x, y, team, rotation } = options.data;
2162
+ assertIsRuntimeValue(type, "type");
2163
+ assertIsRuntimeValue(x, "x");
2164
+ assertIsRuntimeValue(y, "y");
2165
+ assertIsRuntimeValue(team, "team");
2166
+ const output = new SenseableValue(scope);
2167
+ return [
2168
+ output,
2169
+ [
2170
+ new InstructionBase("spawn", type, x, y, rotation ?? "0", team, output),
2171
+ ],
2172
+ ];
2173
+ });
2174
+ }
2175
+ }
2176
+
2177
+ class Stop extends MacroFunction {
2178
+ constructor() {
2179
+ super(() => [null, [new InstructionBase("stop")]]);
1790
2180
  }
1791
2181
  }
1792
2182
 
1793
2183
  class UnitBind extends MacroFunction {
1794
- constructor(scope) {
1795
- super(scope, type => {
2184
+ constructor() {
2185
+ super((scope, type) => {
1796
2186
  if (!(type instanceof StoreValue))
1797
2187
  throw new CompilerError("The unitBind type must be a store");
1798
2188
  return [null, [new InstructionBase("ubind", type)]];
@@ -1800,82 +2190,84 @@ class UnitBind extends MacroFunction {
1800
2190
  }
1801
2191
  }
1802
2192
 
1803
- const validModes = [
1804
- "idle",
1805
- "stop",
1806
- "move",
1807
- "approach",
1808
- "boost",
1809
- "pathfind",
1810
- "target",
1811
- "targetp",
1812
- "itemDrop",
1813
- "itemTake",
1814
- "payDrop",
1815
- "payTake",
1816
- "payEnter",
1817
- "mine",
1818
- "flag",
1819
- "build",
1820
- "getBlock",
1821
- "within",
1822
- ];
1823
- class UnitControl extends MacroFunction {
1824
- constructor(scope) {
1825
- super(scope, (mode, ...args) => {
1826
- if (!(mode instanceof LiteralValue) || typeof mode.data !== "string")
1827
- throw new CompilerError("The unitControl mode must be a string literal");
1828
- if (!validModes.includes(mode.data))
1829
- throw new CompilerError("Invalid unitControl mode");
1830
- if (args.some(value => !(value instanceof StoreValue || value instanceof LiteralValue)))
1831
- throw new CompilerError("The others arguments of unitControl must be literals or stores");
1832
- let result = null;
1833
- let extraArgs = [];
1834
- switch (mode.data) {
1835
- case "getBlock": {
1836
- const outType = new StoreValue(scope);
1837
- const outBuilding = new SenseableValue(scope);
1838
- result = ObjectValue.fromArray(scope, [outType, outBuilding]);
1839
- extraArgs = [outType, outBuilding, new LiteralValue(scope, 0)];
1840
- break;
1841
- }
1842
- case "within": {
1843
- const temp = new StoreValue(scope);
1844
- result = temp;
1845
- extraArgs = [temp, new LiteralValue(scope, 0)];
1846
- break;
2193
+ class UnitControl extends ObjectValue {
2194
+ constructor() {
2195
+ const data = createOverloadNamespace({
2196
+ overloads: {
2197
+ idle: { args: [] },
2198
+ stop: { args: [] },
2199
+ move: { args: ["x", "y"] },
2200
+ approach: { named: "options", args: ["x", "y", "radius"] },
2201
+ boost: { args: ["enable"] },
2202
+ pathfind: { args: [] },
2203
+ target: { named: "options", args: ["x", "y", "shoot"] },
2204
+ targetp: { named: "options", args: ["unit", "shoot"] },
2205
+ itemDrop: { args: ["target", "amount"] },
2206
+ itemTake: { args: ["target", "item", "amount"] },
2207
+ payDrop: { args: [] },
2208
+ payTake: { named: "options", args: ["takeUnits"] },
2209
+ payEnter: { args: [] },
2210
+ mine: { args: ["x", "y"] },
2211
+ flag: { args: ["value"] },
2212
+ build: {
2213
+ named: "options",
2214
+ args: ["x", "y", "block", "rotation", { key: "config", default: "" }],
2215
+ },
2216
+ getBlock: {
2217
+ args: ["x", "y"],
2218
+ },
2219
+ within: {
2220
+ named: "options",
2221
+ args: ["x", "y", "radius"],
2222
+ },
2223
+ },
2224
+ handler(scope, overload, ...args) {
2225
+ let result = null;
2226
+ let extraArgs = [];
2227
+ switch (overload) {
2228
+ case "getBlock": {
2229
+ const outType = new StoreValue(scope);
2230
+ const outBuilding = new SenseableValue(scope);
2231
+ result = ObjectValue.fromArray([outType, outBuilding]);
2232
+ extraArgs = [outType, outBuilding, new LiteralValue(0)];
2233
+ break;
2234
+ }
2235
+ case "within": {
2236
+ const temp = new StoreValue(scope);
2237
+ result = temp;
2238
+ extraArgs = [temp, new LiteralValue(0)];
2239
+ break;
2240
+ }
1847
2241
  }
1848
- }
1849
- return [
1850
- result,
1851
- [new InstructionBase("ucontrol", mode.data, ...args, ...extraArgs)],
1852
- ];
2242
+ return [
2243
+ result,
2244
+ [new InstructionBase("ucontrol", overload, ...args, ...extraArgs)],
2245
+ ];
2246
+ },
1853
2247
  });
2248
+ super(data);
1854
2249
  }
1855
2250
  }
1856
2251
 
1857
2252
  class UnitRadar extends MacroFunction {
1858
- constructor(scope) {
1859
- super(scope, (filter1, filter2, filter3, order, sort) => {
1860
- if (!(filter1 instanceof LiteralValue) ||
1861
- typeof filter1.data !== "string" ||
1862
- !(filter2 instanceof LiteralValue) ||
1863
- typeof filter2.data !== "string" ||
1864
- !(filter3 instanceof LiteralValue) ||
1865
- typeof filter3.data !== "string")
1866
- throw new CompilerError("The filters must be string literals");
1867
- if (!validRadarFilters.includes(filter1.data))
1868
- throw new CompilerError("Invalid value for filter1");
1869
- if (!validRadarFilters.includes(filter2.data))
1870
- throw new CompilerError("Invalid value for filter2");
1871
- if (!validRadarFilters.includes(filter3.data))
1872
- throw new CompilerError("Invalid value for filter3");
2253
+ constructor() {
2254
+ super((scope, options) => {
2255
+ assertIsObjectMacro(options, "The radar options");
2256
+ const { filters, order, sort } = options.data;
2257
+ assertIsArrayMacro(filters, "filters");
2258
+ const { length } = filters.data;
2259
+ if (!(length instanceof LiteralValue) || typeof length.data !== "number")
2260
+ throw new CompilerError("The length of an array macro must be");
2261
+ if (length.data !== 3)
2262
+ throw new CompilerError("The filters array must have 3 items");
2263
+ // data is not an array
2264
+ const { 0: filter1, 1: filter2, 2: filter3 } = filters.data;
2265
+ assertLiteralOneOf(filter1, validRadarFilters, "The first filter");
2266
+ assertLiteralOneOf(filter2, validRadarFilters, "The second filter");
2267
+ assertLiteralOneOf(filter3, validRadarFilters, "The third filter");
1873
2268
  if (!(order instanceof LiteralValue || order instanceof StoreValue))
1874
2269
  throw new CompilerError("The radar order must be a literal or a store");
1875
- if (!(sort instanceof LiteralValue) || typeof sort.data !== "string")
1876
- throw new CompilerError("The radar sort must be a string literal");
1877
- if (!validRadarSorts.includes(sort.data))
1878
- throw new CompilerError("Invalid sort value");
2270
+ assertLiteralOneOf(sort, validRadarSorts, "The radar sort");
1879
2271
  const outUnit = new SenseableValue(scope);
1880
2272
  return [
1881
2273
  outUnit,
@@ -1888,7 +2280,6 @@ class UnitRadar extends MacroFunction {
1888
2280
  }
1889
2281
  }
1890
2282
 
1891
- const validFinds = ["ore", "building", "spawn", "damaged"];
1892
2283
  const validBuildingGroups = [
1893
2284
  "core",
1894
2285
  "storage",
@@ -1900,86 +2291,333 @@ const validBuildingGroups = [
1900
2291
  "battery",
1901
2292
  "reactor",
1902
2293
  ];
1903
- class UnitLocate extends MacroFunction {
1904
- constructor(scope) {
1905
- super(scope, (find, ...args) => {
1906
- if (!(find instanceof LiteralValue && typeof find.data === "string"))
1907
- throw new CompilerError("The unitLocate find must be a string literal");
1908
- if (!validFinds.includes(find.data))
1909
- throw new CompilerError("Invalid find value");
1910
- if (args.some(value => !(value instanceof StoreValue || value instanceof LiteralValue)))
1911
- throw new CompilerError("The others arguments of unitLocate must be literals or stores");
1912
- const outFound = new StoreValue(scope);
1913
- const outX = new StoreValue(scope);
1914
- const outY = new StoreValue(scope);
1915
- const outBuilding = new SenseableValue(scope);
1916
- const outArgs = [outX, outY, outFound, outBuilding];
1917
- let inputArgs = [];
1918
- switch (find.data) {
1919
- case "ore": {
1920
- const [ore] = args;
1921
- inputArgs = [find.data, "core", "true", ore];
1922
- break;
1923
- }
1924
- case "building": {
1925
- const [group, enemy] = args;
1926
- if (!(group instanceof LiteralValue && typeof group.data === "string")) {
1927
- throw new CompilerError("The building group must be a string literal");
2294
+ class UnitLocate extends ObjectValue {
2295
+ constructor() {
2296
+ const data = createOverloadNamespace({
2297
+ overloads: {
2298
+ ore: {
2299
+ args: ["ore"],
2300
+ },
2301
+ building: { named: "options", args: ["group", "enemy"] },
2302
+ spawn: {
2303
+ args: [],
2304
+ },
2305
+ damaged: {
2306
+ args: [],
2307
+ },
2308
+ },
2309
+ handler(scope, overload, ...args) {
2310
+ const outFound = new StoreValue(scope);
2311
+ const outX = new StoreValue(scope);
2312
+ const outY = new StoreValue(scope);
2313
+ const outBuilding = new SenseableValue(scope);
2314
+ const outArgs = [outX, outY, outFound, outBuilding];
2315
+ let inputArgs = [];
2316
+ switch (overload) {
2317
+ case "ore": {
2318
+ const [ore] = args;
2319
+ inputArgs = [overload, "core", "true", ore];
2320
+ break;
2321
+ }
2322
+ case "building": {
2323
+ const [group, enemy] = args;
2324
+ if (!(group instanceof LiteralValue))
2325
+ throw new CompilerError("The building group must be a string literal");
2326
+ assertLiteralOneOf(group, validBuildingGroups, "The building group");
2327
+ inputArgs = [overload, group.data, enemy, "@copper"];
2328
+ break;
2329
+ }
2330
+ case "spawn":
2331
+ case "damaged": {
2332
+ inputArgs = [overload, "core", "true", "@copper"];
2333
+ break;
1928
2334
  }
1929
- if (!validBuildingGroups.includes(group.data))
1930
- throw new CompilerError("Invalid building group");
1931
- inputArgs = [find.data, group.data, enemy, "@copper"];
1932
- break;
1933
- }
1934
- case "spawn":
1935
- case "damaged": {
1936
- inputArgs = [find.data, "core", "true", "@copper"];
1937
- break;
1938
2335
  }
1939
- }
1940
- return [
1941
- ObjectValue.fromArray(scope, [
1942
- outFound,
1943
- outX,
1944
- outY,
1945
- ...(find.data !== "ore" ? [outBuilding] : []),
1946
- ]),
1947
- [new InstructionBase("ulocate", ...inputArgs, ...outArgs)],
1948
- ];
2336
+ return [
2337
+ ObjectValue.fromArray([
2338
+ outFound,
2339
+ outX,
2340
+ outY,
2341
+ ...(overload !== "ore" ? [outBuilding] : []),
2342
+ ]),
2343
+ [new InstructionBase("ulocate", ...inputArgs, ...outArgs)],
2344
+ ];
2345
+ },
1949
2346
  });
2347
+ super(data);
1950
2348
  }
1951
2349
  }
1952
2350
 
1953
- class MemoryEntry extends ObjectValue {
1954
- constructor(scope, mem, prop) {
1955
- super(scope, {
1956
- $eval: new MacroFunction(scope, () => {
1957
- if (this.store)
1958
- return [this.store, []];
1959
- const temp = new StoreValue(scope);
1960
- return [temp, [new InstructionBase("read", temp, mem.cell, prop)]];
1961
- }),
1962
- $consume: new MacroFunction(scope, () => {
1963
- if (this.store)
1964
- return [this.store, []];
1965
- this.ensureOwned();
1966
- this.store = new StoreValue(scope);
1967
- this.owner.own(this.store);
2351
+ const validEffects = [
2352
+ "burning",
2353
+ "freezing",
2354
+ "unmoving",
2355
+ "wet",
2356
+ "melting",
2357
+ "sapped",
2358
+ "electrified",
2359
+ "spore-slowed",
2360
+ "tarred",
2361
+ "overdrive",
2362
+ "overclock",
2363
+ "boss",
2364
+ "shocked",
2365
+ "blasted",
2366
+ ];
2367
+ class ApplyStatus extends ObjectValue {
2368
+ constructor() {
2369
+ const data = createOverloadNamespace({
2370
+ overloads: {
2371
+ apply: {
2372
+ args: ["status", "unit", { key: "duration", default: "10" }],
2373
+ },
2374
+ clear: { args: ["status", "unit"] },
2375
+ },
2376
+ handler(scope, overload, effect, unit, duration) {
2377
+ if (!(effect instanceof LiteralValue))
2378
+ throw new CompilerError("The status effect must be a string literal");
2379
+ assertLiteralOneOf(effect, validEffects, "The status effect");
1968
2380
  return [
1969
- this.store,
1970
- [new InstructionBase("read", this.store, mem.cell, prop)],
2381
+ null,
2382
+ [
2383
+ new InstructionBase("status", String(overload !== "apply"), effect.data, unit, duration),
2384
+ ],
1971
2385
  ];
1972
- }),
1973
- "$=": new MacroFunction(scope, value => {
1974
- const [data, dataInst] = value.consume(scope);
2386
+ },
2387
+ });
2388
+ super(data);
2389
+ }
2390
+ }
2391
+
2392
+ class SpawnWave extends MacroFunction {
2393
+ constructor() {
2394
+ super((scope, natural, x, y) => {
2395
+ if (!(natural instanceof LiteralValue) ||
2396
+ (natural.data !== 1 && natural.data !== 0))
2397
+ throw new CompilerError("The 'natural' argument must be a boolean literal");
2398
+ return [
2399
+ null,
2400
+ [
2401
+ new InstructionBase("spawnwave", x ?? "10", y ?? "10", String(!!natural.data)),
2402
+ ],
2403
+ ];
2404
+ });
2405
+ }
2406
+ }
2407
+
2408
+ class SetRule extends ObjectValue {
2409
+ constructor() {
2410
+ const data = createOverloadNamespace({
2411
+ overloads: {
2412
+ currentWaveTime: { args: ["seconds"] },
2413
+ waveTimer: { args: ["enabled"] },
2414
+ waves: { args: ["enabled"] },
2415
+ wave: { args: ["number"] },
2416
+ waveSpacing: { args: ["seconds"] },
2417
+ waveSending: { args: ["enabled"] },
2418
+ attackMode: { args: ["enabled"] },
2419
+ enemyCoreBuildRadius: { args: ["radius"] },
2420
+ dropZoneRadius: { args: ["radius"] },
2421
+ unitCap: { args: ["cap"] },
2422
+ mapArea: { named: "options", args: ["x", "y", "width", "height"] },
2423
+ lighting: { args: ["enabled"] },
2424
+ ambientLight: { args: ["rgbaData"] },
2425
+ solarMultiplier: { args: ["multiplier"] },
2426
+ buildSpeed: { args: ["team", "multiplier"] },
2427
+ unitBuildSpeed: { args: ["team", "multiplier"] },
2428
+ unitDamage: { args: ["team", "multiplier"] },
2429
+ blockHealth: { args: ["team", "multiplier"] },
2430
+ blockDamage: { args: ["team", "multiplier"] },
2431
+ rtsMinWeight: { args: ["team", "value"] },
2432
+ rtsMinSquad: { args: ["team", "value"] },
2433
+ },
2434
+ handler(scope, overload, ...args) {
2435
+ const params = ["10", "0", "0", "100", "100"];
2436
+ switch (overload) {
2437
+ case "mapArea": {
2438
+ const [x, y, width, height] = args;
2439
+ params[1] = x;
2440
+ params[2] = y;
2441
+ params[3] = width;
2442
+ params[4] = height;
2443
+ break;
2444
+ }
2445
+ case "buildSpeed":
2446
+ case "unitBuildSpeed":
2447
+ case "unitDamage":
2448
+ case "blockHealth":
2449
+ case "blockDamage":
2450
+ case "rtsMinWeight":
2451
+ case "rtsMinSquad": {
2452
+ const [team, value] = args;
2453
+ params[1] = team;
2454
+ params[2] = value;
2455
+ break;
2456
+ }
2457
+ default:
2458
+ params[0] = args[0]; // the general value
2459
+ }
2460
+ return [null, [new InstructionBase("setrule", overload, ...params)]];
2461
+ },
2462
+ });
2463
+ super(data);
2464
+ }
2465
+ }
2466
+
2467
+ class FlushMessage extends ObjectValue {
2468
+ constructor() {
2469
+ const data = createOverloadNamespace({
2470
+ overloads: {
2471
+ notify: { args: [] },
2472
+ mission: { args: [] },
2473
+ announce: { args: ["duration"] },
2474
+ toast: { args: ["duration"] },
2475
+ },
2476
+ handler(scope, overload, duration) {
2477
+ return [null, [new InstructionBase("message", overload, duration)]];
2478
+ },
2479
+ });
2480
+ super(data);
2481
+ }
2482
+ }
2483
+
2484
+ class Cutscene extends ObjectValue {
2485
+ constructor() {
2486
+ const data = createOverloadNamespace({
2487
+ overloads: {
2488
+ pan: { named: "options", args: ["x", "y", "speed"] },
2489
+ zoom: { args: ["level"] },
2490
+ stop: { args: [] },
2491
+ },
2492
+ handler(scope, overload, ...args) {
2493
+ const params = Object.assign(["100", "100", "0.06", "0"], args);
2494
+ return [null, [new InstructionBase("cutscene", overload, ...params)]];
2495
+ },
2496
+ });
2497
+ super(data);
2498
+ }
2499
+ }
2500
+
2501
+ class Explosion extends MacroFunction {
2502
+ constructor() {
2503
+ super((scope, options) => {
2504
+ assertIsObjectMacro(options, "The options");
2505
+ const params = assertObjectFields(options, [
2506
+ "team",
2507
+ "x",
2508
+ "y",
2509
+ "radius",
2510
+ "damage",
2511
+ "air",
2512
+ "ground",
2513
+ "pierce",
2514
+ ]);
2515
+ return [null, [new InstructionBase("explosion", ...params)]];
2516
+ });
2517
+ }
2518
+ }
2519
+
2520
+ class SetRate extends MacroFunction {
2521
+ constructor() {
2522
+ super((scope, ipt) => [null, [new InstructionBase("setrate", ipt)]]);
2523
+ }
2524
+ }
2525
+
2526
+ class Fetch extends ObjectValue {
2527
+ constructor() {
2528
+ const data = createOverloadNamespace({
2529
+ overloads: {
2530
+ unit: { args: ["team", "index"] },
2531
+ unitCount: { args: ["team"] },
2532
+ player: { args: ["team", "index"] },
2533
+ playerCount: { args: ["team"] },
2534
+ core: { args: ["team", "index"] },
2535
+ coreCount: { args: ["team"] },
2536
+ build: { args: ["team", "index", "block"] },
2537
+ buildCount: { args: ["team", "block"] },
2538
+ },
2539
+ handler(scope, overload, team, ...rest) {
2540
+ const output = new SenseableValue(scope);
2541
+ const params = ["0", "@conveyor"];
2542
+ if (overload === "buildCount") {
2543
+ params[1] = rest[0];
2544
+ }
2545
+ else {
2546
+ Object.assign(params, rest);
2547
+ }
1975
2548
  return [
1976
- data,
1977
- [...dataInst, new InstructionBase("write", data, mem.cell, prop)],
2549
+ output,
2550
+ [new InstructionBase("fetch", overload, output, team, ...params)],
1978
2551
  ];
1979
- }),
2552
+ },
1980
2553
  });
2554
+ super(data);
2555
+ }
2556
+ }
2557
+
2558
+ class GetFlag extends MacroFunction {
2559
+ constructor() {
2560
+ super((scope, flag) => {
2561
+ const result = new StoreValue(scope);
2562
+ return [result, [new InstructionBase("getflag", result, flag)]];
2563
+ });
2564
+ }
2565
+ }
2566
+
2567
+ class SetFlag extends MacroFunction {
2568
+ constructor() {
2569
+ super((scope, flag, value) => {
2570
+ if (!flag)
2571
+ throw new CompilerError("Missing flag argument");
2572
+ if (!value)
2573
+ throw new CompilerError("Missing flag value");
2574
+ return [null, [new InstructionBase("setflag", flag, value)]];
2575
+ });
2576
+ }
2577
+ }
2578
+
2579
+ class MemoryEntry extends BaseValue {
2580
+ constructor(scope, mem, prop) {
2581
+ super();
2582
+ this.scope = scope;
2583
+ this.mem = mem;
2584
+ this.prop = prop;
2585
+ this.macro = true;
1981
2586
  this.store = null;
1982
2587
  }
2588
+ eval(scope) {
2589
+ if (this.store)
2590
+ return [this.store, []];
2591
+ const temp = new StoreValue(scope);
2592
+ return [
2593
+ temp,
2594
+ [new InstructionBase("read", temp, this.mem.cell, this.prop)],
2595
+ ];
2596
+ }
2597
+ consume(scope) {
2598
+ if (this.store)
2599
+ return [this.store, []];
2600
+ this.ensureOwned();
2601
+ this.store = new StoreValue(scope);
2602
+ this.owner.own(this.store);
2603
+ return [
2604
+ this.store,
2605
+ [new InstructionBase("read", this.store, this.mem.cell, this.prop)],
2606
+ ];
2607
+ }
2608
+ "="(scope, value) {
2609
+ const [data, dataInst] = value.consume(scope);
2610
+ return [
2611
+ data,
2612
+ [
2613
+ ...dataInst,
2614
+ new InstructionBase("write", data, this.mem.cell, this.prop),
2615
+ ],
2616
+ ];
2617
+ }
2618
+ ensureOwned() {
2619
+ this.owner ??= new ValueOwner({ scope: this.scope, value: this });
2620
+ }
1983
2621
  }
1984
2622
  for (const operator of operators) {
1985
2623
  if (operator === "=")
@@ -1990,9 +2628,9 @@ for (const operator of operators) {
1990
2628
  };
1991
2629
  }
1992
2630
  class MemoryMacro extends ObjectValue {
1993
- constructor(scope, cell, size) {
1994
- super(scope, {
1995
- $get: new MacroFunction(scope, (prop) => {
2631
+ constructor(cell, size) {
2632
+ super({
2633
+ $get: new MacroFunction((scope, prop) => {
1996
2634
  if (prop instanceof LiteralValue && typeof prop.data !== "number")
1997
2635
  throw new CompilerError(`Invalid memory object property: "${prop.data}"`);
1998
2636
  const obj = new MemoryEntry(scope, this, prop);
@@ -2002,21 +2640,20 @@ class MemoryMacro extends ObjectValue {
2002
2640
  size,
2003
2641
  });
2004
2642
  this.cell = cell;
2005
- this.name = cell.toString();
2006
2643
  }
2007
2644
  toString() {
2008
- return this.name;
2645
+ return this.cell.toString();
2009
2646
  }
2010
2647
  }
2011
2648
  class MemoryBuilder extends ObjectValue {
2012
- constructor(scope) {
2013
- super(scope, {
2014
- $call: new MacroFunction(scope, (cell, size = new LiteralValue(scope, 64)) => {
2649
+ constructor() {
2650
+ super({
2651
+ $call: new MacroFunction((scope, cell, size = new LiteralValue(64)) => {
2015
2652
  if (!(cell instanceof SenseableValue))
2016
2653
  throw new CompilerError("Memory cell must be a senseable value.");
2017
2654
  if (!(size instanceof LiteralValue && typeof size.data === "number"))
2018
2655
  throw new CompilerError("The memory size must be a number literal.");
2019
- return [new MemoryMacro(scope, cell, size), []];
2656
+ return [new MemoryMacro(cell, size), []];
2020
2657
  }),
2021
2658
  });
2022
2659
  }
@@ -2024,9 +2661,9 @@ class MemoryBuilder extends ObjectValue {
2024
2661
 
2025
2662
  const dynamicVars = ["time", "tick"];
2026
2663
  class NamespaceMacro extends ObjectValue {
2027
- constructor(scope, { changeCasing = false } = {}) {
2028
- super(scope, {
2029
- $get: new MacroFunction(scope, prop => {
2664
+ constructor({ changeCasing = false } = {}) {
2665
+ super({
2666
+ $get: new MacroFunction((scope, prop) => {
2030
2667
  if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
2031
2668
  throw new CompilerError("Cannot use dynamic properties on namespace macros");
2032
2669
  const symbolName = this.changeCasing
@@ -2050,7 +2687,7 @@ class NamespaceMacro extends ObjectValue {
2050
2687
  }
2051
2688
  class VarsNamespace extends NamespaceMacro {
2052
2689
  constructor(scope) {
2053
- super(scope);
2690
+ super();
2054
2691
  Object.assign(this.data, {
2055
2692
  unit: new ValueOwner({
2056
2693
  scope,
@@ -2064,29 +2701,11 @@ class VarsNamespace extends NamespaceMacro {
2064
2701
  }).value,
2065
2702
  });
2066
2703
  }
2067
- }
2068
- class UCommandsNamespace extends NamespaceMacro {
2069
- constructor(scope) {
2070
- super(scope);
2071
- this.data.$get = new MacroFunction(scope, prop => {
2072
- if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
2073
- throw new CompilerError("Cannot use dynamic properties on namespace macros");
2074
- const symbolName = prop.data[0].toUpperCase() + prop.data.slice(1);
2075
- const owner = new ValueOwner({
2076
- scope,
2077
- name: `@command${symbolName}`,
2078
- value: assign(new StoreValue(scope), {
2079
- mutability: EMutability.constant,
2080
- }),
2081
- });
2082
- return [owner.value, []];
2083
- });
2084
- }
2085
2704
  }
2086
2705
 
2087
2706
  class GetGlobal extends MacroFunction {
2088
- constructor(scope, mutability) {
2089
- super(scope, (name) => {
2707
+ constructor(mutability) {
2708
+ super((scope, name) => {
2090
2709
  if (!(name instanceof LiteralValue) || typeof name.data !== "string")
2091
2710
  throw new CompilerError("The name parameter must be a string literal.");
2092
2711
  const owner = new ValueOwner({
@@ -2101,66 +2720,163 @@ class GetGlobal extends MacroFunction {
2101
2720
  }
2102
2721
  }
2103
2722
 
2723
+ class Asm extends MacroFunction {
2724
+ constructor() {
2725
+ super((scope, stringsArray, ...values) => {
2726
+ if (!isTemplateObjectArray(stringsArray))
2727
+ throw new CompilerError("Expected to receive a template strings array");
2728
+ const args = [];
2729
+ for (let i = 0; i < values.length; i++) {
2730
+ const [item] = stringsArray.get(scope, new LiteralValue(i));
2731
+ args.push(item.data);
2732
+ args.push(values[i]);
2733
+ }
2734
+ const { length } = stringsArray.data;
2735
+ const [tail] = stringsArray.get(scope, new LiteralValue(length.data - 1));
2736
+ args.push(tail.data);
2737
+ return [null, formatInstructions(args)];
2738
+ });
2739
+ }
2740
+ }
2741
+ /** Splits multiline asm calls and formats each line. */
2742
+ function formatInstructions(args) {
2743
+ const instructions = [];
2744
+ let buffer = [];
2745
+ for (let i = 0; i < args.length; i++) {
2746
+ const arg = args[i];
2747
+ if (typeof arg !== "string" || !arg.includes("\n")) {
2748
+ buffer.push(arg);
2749
+ continue;
2750
+ }
2751
+ const segments = arg.split("\n");
2752
+ const params = [...buffer, segments[0]];
2753
+ if (validateInstructionArgs(params)) {
2754
+ instructions.push(new ZeroSpaceInstruction(...params));
2755
+ buffer = [];
2756
+ }
2757
+ // iterates over all segments except the first and last
2758
+ // the first segment was already processed above
2759
+ // the last segment will be added to the buffer because there might
2760
+ // be an interpolation after it
2761
+ // and putting it in the buffer makes sure it has a proper output format
2762
+ for (let i = 1; i < segments.length - 1; i++) {
2763
+ const trimmed = segments[i].trim();
2764
+ if (trimmed.length == 0)
2765
+ continue;
2766
+ instructions.push(new ZeroSpaceInstruction(trimmed));
2767
+ }
2768
+ if (segments.length > 1) {
2769
+ buffer.push(segments[segments.length - 1]);
2770
+ }
2771
+ }
2772
+ if (buffer.length > 0 && validateInstructionArgs(buffer)) {
2773
+ instructions.push(new ZeroSpaceInstruction(...buffer));
2774
+ }
2775
+ return instructions;
2776
+ }
2777
+ /** Determines if an asm line should be generated and trims it at the start and end */
2778
+ function validateInstructionArgs(args) {
2779
+ if (args.length === 0)
2780
+ return false;
2781
+ if (args.length === 1) {
2782
+ const item = args[0];
2783
+ if (typeof item !== "string")
2784
+ return true;
2785
+ args[0] = item.trim();
2786
+ return args[0].length !== 0;
2787
+ }
2788
+ const first = args[0];
2789
+ const last = args[args.length - 1];
2790
+ if (typeof first === "string")
2791
+ args[0] = first.trimStart();
2792
+ if (typeof last === "string")
2793
+ args[args.length - 1] = last.trimEnd();
2794
+ return true;
2795
+ }
2796
+
2104
2797
  /**
2105
2798
  * Adds all the compiler globals to `scope`
2106
2799
  */
2107
2800
  function initScope(scope) {
2108
2801
  // namespaces
2109
- scope.hardSet("ControlKind", new NamespaceMacro(scope));
2802
+ scope.hardSet("ControlKind", new NamespaceMacro());
2110
2803
  scope.hardSet("Vars", new VarsNamespace(scope));
2111
- scope.hardSet("Items", new NamespaceMacro(scope, { changeCasing: true }));
2112
- scope.hardSet("Liquids", new NamespaceMacro(scope));
2113
- scope.hardSet("Units", new NamespaceMacro(scope));
2114
- scope.hardSet("LAccess", new NamespaceMacro(scope));
2115
- scope.hardSet("UnitCommands", new UCommandsNamespace(scope));
2116
- scope.hardSet("Blocks", new NamespaceMacro(scope, { changeCasing: true }));
2804
+ scope.hardSet("Teams", new NamespaceMacro());
2805
+ scope.hardSet("Items", new NamespaceMacro({ changeCasing: true }));
2806
+ scope.hardSet("Liquids", new NamespaceMacro());
2807
+ scope.hardSet("Units", new NamespaceMacro({ changeCasing: true }));
2808
+ scope.hardSet("LAccess", new NamespaceMacro());
2809
+ scope.hardSet("Blocks", new NamespaceMacro({ changeCasing: true }));
2117
2810
  // helper methods
2118
- scope.hardSet("getBuilding", new GetGlobal(scope, EMutability.constant));
2119
- scope.hardSet("getVar", new GetGlobal(scope, EMutability.mutable));
2120
- scope.hardSet("concat", new Concat(scope));
2121
- scope.hardSet("Math", new MlogMath(scope));
2122
- scope.hardSet("Memory", new MemoryBuilder(scope));
2811
+ scope.hardSet("getBuilding", new GetGlobal(EMutability.constant));
2812
+ scope.hardSet("getVar", new GetGlobal(EMutability.mutable));
2813
+ scope.hardSet("concat", new Concat());
2814
+ scope.hardSet("asm", new Asm());
2815
+ scope.hardSet("Math", new MlogMath());
2816
+ scope.hardSet("Memory", new MemoryBuilder());
2123
2817
  // commands
2124
- scope.hardSet("draw", new Draw(scope));
2125
- scope.hardSet("print", new Print(scope));
2126
- scope.hardSet("printFlush", new PrintFlush(scope));
2127
- scope.hardSet("drawFlush", new DrawFlush(scope));
2128
- scope.hardSet("getLink", new GetLink(scope));
2129
- scope.hardSet("control", new Control(scope));
2130
- scope.hardSet("radar", new Radar(scope));
2131
- scope.hardSet("sensor", new Sensor(scope));
2132
- scope.hardSet("wait", new Wait(scope));
2133
- scope.hardSet("lookup", new Lookup(scope));
2134
- scope.hardSet("endScript", new End(scope));
2135
- scope.hardSet("unitBind", new UnitBind(scope));
2136
- scope.hardSet("unitControl", new UnitControl(scope));
2137
- scope.hardSet("unitRadar", new UnitRadar(scope));
2138
- scope.hardSet("unitLocate", new UnitLocate(scope));
2818
+ scope.hardSet("draw", new Draw());
2819
+ scope.hardSet("print", new Print());
2820
+ scope.hardSet("printFlush", new PrintFlush());
2821
+ scope.hardSet("drawFlush", new DrawFlush());
2822
+ scope.hardSet("getLink", new GetLink());
2823
+ scope.hardSet("control", new Control());
2824
+ scope.hardSet("radar", new Radar());
2825
+ scope.hardSet("sensor", new Sensor());
2826
+ scope.hardSet("wait", new Wait());
2827
+ scope.hardSet("lookup", new Lookup());
2828
+ scope.hardSet("packColor", new PackColor());
2829
+ scope.hardSet("endScript", new End());
2830
+ scope.hardSet("stopScript", new Stop());
2831
+ scope.hardSet("unitBind", new UnitBind());
2832
+ scope.hardSet("unitControl", new UnitControl());
2833
+ scope.hardSet("unitRadar", new UnitRadar());
2834
+ scope.hardSet("unitLocate", new UnitLocate());
2835
+ // world processor commands
2836
+ scope.hardSet("getBlock", new GetBlock());
2837
+ scope.hardSet("setBlock", new SetBlock());
2838
+ scope.hardSet("spawnUnit", new SpawnUnit());
2839
+ scope.hardSet("applyStatus", new ApplyStatus());
2840
+ scope.hardSet("spawnWave", new SpawnWave());
2841
+ scope.hardSet("setRule", new SetRule());
2842
+ scope.hardSet("flushMessage", new FlushMessage());
2843
+ scope.hardSet("cutscene", new Cutscene());
2844
+ scope.hardSet("explosion", new Explosion());
2845
+ scope.hardSet("setRate", new SetRate());
2846
+ scope.hardSet("fetch", new Fetch());
2847
+ scope.hardSet("getFlag", new GetFlag());
2848
+ scope.hardSet("setFlag", new SetFlag());
2139
2849
  }
2140
2850
 
2141
2851
  class Compiler {
2142
- constructor({ stackName, compactNames = false } = {}) {
2852
+ constructor({ stackName, compactNames = false, sourcemap = false, } = {}) {
2143
2853
  this.handlers = handlers;
2144
2854
  this.usingStack = !!stackName;
2145
2855
  this.stackName = stackName;
2146
2856
  this.compactNames = compactNames;
2857
+ this.sourcemap = sourcemap;
2147
2858
  }
2148
2859
  compile(script) {
2149
2860
  let output;
2861
+ let sourcemaps;
2150
2862
  try {
2151
2863
  const program = this.parse(script);
2152
2864
  const scope = new Scope({});
2153
2865
  initScope(scope);
2154
2866
  const valueInst = this.handle(scope, program);
2155
2867
  valueInst[1].push(new EndInstruction(), ...scope.inst);
2868
+ hideRedundantJumps(valueInst[1]);
2156
2869
  this.resolve(valueInst);
2157
2870
  output = this.serialize(valueInst) + "\n";
2871
+ if (this.sourcemap) {
2872
+ sourcemaps = this.mapSources(valueInst);
2873
+ }
2158
2874
  }
2159
2875
  catch (error) {
2160
- const nodeStack = error instanceof CompilerError ? error.nodeStack : [];
2161
- return [null, error, nodeStack];
2876
+ const err = error instanceof CompilerError ? error : CompilerError.from(error);
2877
+ return [null, err];
2162
2878
  }
2163
- return [output, null, []];
2879
+ return [output, null, sourcemaps];
2164
2880
  }
2165
2881
  resolve(valueInst) {
2166
2882
  let i = 0;
@@ -2180,40 +2896,92 @@ class Compiler {
2180
2896
  plugins: ["typescript"],
2181
2897
  });
2182
2898
  }
2183
- handle(scope, node) {
2899
+ mapSources(valueInst) {
2900
+ const result = [];
2901
+ for (const inst of valueInst[1]) {
2902
+ if (!inst.hidden)
2903
+ result.push(inst.source);
2904
+ }
2905
+ return result;
2906
+ }
2907
+ handle(scope, node, handler = this.handlers[node.type]) {
2184
2908
  try {
2185
- const handler = this.handlers[node.type];
2186
2909
  if (!handler)
2187
2910
  throw new CompilerError("Missing handler for " + node.type);
2188
- return handler(this, scope, node, null);
2911
+ const result = handler(this, scope, node, null);
2912
+ if (this.sourcemap)
2913
+ return appendSourceLocations(result, node);
2914
+ return result;
2189
2915
  }
2190
2916
  catch (error) {
2191
2917
  if (error instanceof CompilerError) {
2192
- error.nodeStack.push(node);
2918
+ error.loc ??= node.loc;
2193
2919
  }
2194
2920
  throw error;
2195
2921
  }
2196
2922
  }
2197
2923
  handleEval(scope, node) {
2198
2924
  const [res, inst] = this.handle(scope, node);
2199
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2925
+ if (!res)
2926
+ throw new CompilerError("Cannot eval null", node);
2200
2927
  const [evaluated, evaluatedInst] = res.eval(scope);
2201
- return [evaluated, [...inst, ...evaluatedInst]];
2928
+ const result = [evaluated, [...inst, ...evaluatedInst]];
2929
+ if (this.sourcemap)
2930
+ return appendSourceLocations(result, node);
2931
+ return result;
2202
2932
  }
2203
2933
  handleConsume(scope, node) {
2204
2934
  const [res, inst] = this.handle(scope, node);
2205
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2935
+ if (!res)
2936
+ throw new CompilerError("Cannot consume null", node);
2206
2937
  const [evaluated, evaluatedInst] = res.consume(scope);
2207
- return [evaluated, [...inst, ...evaluatedInst]];
2938
+ const result = [evaluated, [...inst, ...evaluatedInst]];
2939
+ if (this.sourcemap)
2940
+ return appendSourceLocations(result, node);
2941
+ return result;
2208
2942
  }
2209
- handleMany(scope, nodes, handler = this.handle.bind(this)) {
2943
+ /**
2944
+ * Handles many nodes in order.
2945
+ *
2946
+ * The usage of this method over a regular loop over an array of nodes
2947
+ * is only required if the code inside the loop generates
2948
+ * instructions that are not tracked by the compiler
2949
+ * handler methods ({@link handle}, {@link handleEval}, {@link handleConsume}
2950
+ * and {@link handleMany})
2951
+ *
2952
+ */
2953
+ handleMany(scope, nodes, handler) {
2210
2954
  const lines = [];
2211
2955
  for (const node of nodes) {
2212
- const [, nodeLines] = handler(scope, node);
2956
+ const [, nodeLines] = this.handle(scope, node, handler && (() => handler(node)));
2213
2957
  lines.push(...nodeLines);
2214
2958
  }
2215
2959
  return [null, lines];
2216
2960
  }
2961
+ }
2962
+ /** Removes jump instructions that point right to the next line */
2963
+ function hideRedundantJumps(inst) {
2964
+ for (let i = 0; i < inst.length; i++) {
2965
+ const instruction = inst[i];
2966
+ if (!(instruction instanceof JumpInstruction))
2967
+ continue;
2968
+ const { address } = instruction;
2969
+ let searchIndex = i + 1;
2970
+ let current = inst[searchIndex];
2971
+ while (current.hidden) {
2972
+ if (current instanceof AddressResolver &&
2973
+ current.bonds.includes(address)) {
2974
+ // only gets assigned if `current` is an adress resolver
2975
+ // that resolves the jump adress
2976
+ // and that is also right next to the jump,
2977
+ // without any actual instructions in between
2978
+ instruction.hidden = true;
2979
+ break;
2980
+ }
2981
+ searchIndex++;
2982
+ current = inst[searchIndex];
2983
+ }
2984
+ }
2217
2985
  }
2218
2986
 
2219
2987
  exports.Compiler = Compiler;