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.mjs CHANGED
@@ -2,12 +2,58 @@ import { parse } from '@babel/parser';
2
2
  import * as es from '@babel/types';
3
3
 
4
4
  class CompilerError extends Error {
5
- constructor(message, nodeStack = []) {
5
+ constructor(message, source) {
6
6
  super(message);
7
- this.nodeStack = nodeStack;
7
+ this.loc = source;
8
+ }
9
+ get loc() {
10
+ return this._loc;
11
+ }
12
+ set loc(value) {
13
+ if (!value)
14
+ return;
15
+ if ("type" in value) {
16
+ this._loc = value.loc;
17
+ }
18
+ else if ("start" in value) {
19
+ this._loc = value;
20
+ }
21
+ else {
22
+ this._loc = {
23
+ start: value,
24
+ end: value,
25
+ };
26
+ }
27
+ }
28
+ static from(error, source) {
29
+ let message;
30
+ if (error && typeof error === "object" && "loc" in error) {
31
+ const err = error;
32
+ message = err.toString();
33
+ source ??= err.loc;
34
+ }
35
+ else if (error instanceof Error) {
36
+ message = error.message;
37
+ }
38
+ else if (typeof error === "string") {
39
+ message = error;
40
+ }
41
+ else {
42
+ message = `Unknown error: ${error}`;
43
+ }
44
+ const result = new CompilerError(message, source);
45
+ result.inner = error;
46
+ return result;
8
47
  }
9
48
  }
10
49
 
50
+ var EInstIntent;
51
+ (function (EInstIntent) {
52
+ EInstIntent[EInstIntent["none"] = 0] = "none";
53
+ EInstIntent[EInstIntent["break"] = 1] = "break";
54
+ EInstIntent[EInstIntent["continue"] = 2] = "continue";
55
+ EInstIntent[EInstIntent["return"] = 3] = "return";
56
+ })(EInstIntent || (EInstIntent = {}));
11
57
  /** Defines the possible types of mutability of a value */
12
58
  var EMutability;
13
59
  (function (EMutability) {
@@ -101,11 +147,10 @@ const singleOperators = [...unaryOperators, ...updateOperators];
101
147
  const operators = [...leftRightOperators, ...singleOperators];
102
148
 
103
149
  class VoidValue {
104
- constructor(scope) {
150
+ constructor() {
105
151
  this.owner = null;
106
152
  this.mutability = EMutability.mutable;
107
153
  this.macro = false;
108
- this.scope = scope;
109
154
  }
110
155
  eval(_scope) {
111
156
  throw new CompilerError(`${this} cannot eval.`);
@@ -135,6 +180,8 @@ for (const key of operators) {
135
180
 
136
181
  class InstructionBase {
137
182
  constructor(...args) {
183
+ this.intent = EInstIntent.none;
184
+ this.alwaysRuns = true;
138
185
  this._hidden = false;
139
186
  this.args = args;
140
187
  }
@@ -211,6 +258,7 @@ var EJumpKind;
211
258
  class JumpInstruction extends InstructionBase {
212
259
  constructor(address, kind, left = null, right = null) {
213
260
  super("jump", address, kind, left, right);
261
+ this.address = address;
214
262
  }
215
263
  }
216
264
 
@@ -229,43 +277,13 @@ class ZeroSpaceInstruction extends InstructionBase {
229
277
  class BreakInstruction extends JumpInstruction {
230
278
  constructor(address) {
231
279
  super(address, EJumpKind.Always);
280
+ this.intent = EInstIntent.break;
232
281
  }
233
282
  }
234
283
  class ContinueInstruction extends JumpInstruction {
235
284
  constructor(address) {
236
285
  super(address, EJumpKind.Always);
237
- }
238
- }
239
-
240
- class ValueOwner {
241
- /**
242
- * Creates a new `ValueOwner`, if `value` is already owned,
243
- * `this` will be aliased to `value`, else `this` will own `value`
244
- */
245
- constructor({ scope, constant = false, value, identifier, name, }) {
246
- this.scope = scope;
247
- this.constant = constant;
248
- this.value = value;
249
- this.identifier = identifier;
250
- this.name = name ?? scope.makeTempName();
251
- this.persistent = !!name;
252
- this.owned = new Set();
253
- if (!value.owner?.persistent)
254
- this.own(value);
255
- }
256
- own(target) {
257
- target.owner = this;
258
- this.owned.add(target);
259
- }
260
- replace(target) {
261
- this.value.owner = null;
262
- this.owned.delete(this.value);
263
- this.value = target;
264
- this.own(target);
265
- }
266
- moveInto(owner) {
267
- this.owned.forEach(value => owner.own(value));
268
- this.owned.clear();
286
+ this.intent = EInstIntent.continue;
269
287
  }
270
288
  }
271
289
 
@@ -277,7 +295,7 @@ class BaseValue extends VoidValue {
277
295
  temp,
278
296
  [
279
297
  ...inst,
280
- new OperationInstruction("sub", temp, new LiteralValue(scope, 0), that),
298
+ new OperationInstruction("sub", temp, new LiteralValue(0), that),
281
299
  ],
282
300
  ];
283
301
  }
@@ -285,8 +303,19 @@ class BaseValue extends VoidValue {
285
303
  // TODO: should it return 0 + this ?
286
304
  return this.eval(scope);
287
305
  }
288
- ensureOwned() {
289
- this.owner ??= new ValueOwner({ scope: this.scope, value: this });
306
+ "!"(scope) {
307
+ const [that, inst] = this.consume(scope);
308
+ const temp = new StoreValue(scope);
309
+ const falseLiteral = new LiteralValue(0);
310
+ return [
311
+ temp,
312
+ [...inst, new OperationInstruction("equal", temp, that, falseLiteral)],
313
+ ];
314
+ }
315
+ "~"(scope) {
316
+ const [that, inst] = this.consume(scope);
317
+ const temp = new StoreValue(scope);
318
+ return [temp, [...inst, new OperationInstruction("not", temp, that, null)]];
290
319
  }
291
320
  }
292
321
  const operatorMap$1 = {
@@ -329,18 +358,6 @@ for (const key in operatorMap$1) {
329
358
  ];
330
359
  };
331
360
  }
332
- const unaryOperatorMap$1 = {
333
- "!": "not",
334
- "~": "flip",
335
- };
336
- for (const key in unaryOperatorMap$1) {
337
- const name = unaryOperatorMap$1[key];
338
- BaseValue.prototype[key] = function (scope) {
339
- const [that, inst] = this.consume(scope);
340
- const temp = new StoreValue(scope);
341
- return [temp, [...inst, new OperationInstruction(name, temp, that, null)]];
342
- };
343
- }
344
361
  const assignmentToBinary = {
345
362
  "+=": "+",
346
363
  "-=": "-",
@@ -375,23 +392,20 @@ for (const key of updateOperators) {
375
392
  inst.push(...tempInst);
376
393
  }
377
394
  const kind = key === "++" ? "+=" : "-=";
378
- return [
379
- ret,
380
- [...inst, ...this[kind](scope, new LiteralValue(scope, 1))[1]],
381
- ];
395
+ return [ret, [...inst, ...this[kind](scope, new LiteralValue(1))[1]]];
382
396
  };
383
397
  }
384
398
 
385
399
  const literalMethods = {
386
- length: function (scope) {
400
+ length: function () {
387
401
  if (typeof this.data !== "string")
388
402
  throw new CompilerError("Length method only works on string literal values.");
389
- return new LiteralValue(scope, this.data.length);
403
+ return new LiteralValue(this.data.length);
390
404
  },
391
405
  };
392
406
  class LiteralValue extends BaseValue {
393
- constructor(scope, data) {
394
- super(scope);
407
+ constructor(data) {
408
+ super();
395
409
  this.mutability = EMutability.constant;
396
410
  this.data = data;
397
411
  }
@@ -419,9 +433,10 @@ class LiteralValue extends BaseValue {
419
433
  return 1;
420
434
  return this.data;
421
435
  }
422
- typeof(scope) {
423
- return [new LiteralValue(scope, "literal"), []];
436
+ typeof() {
437
+ return [new LiteralValue("literal"), []];
424
438
  }
439
+ ensureOwned() { }
425
440
  }
426
441
  const operatorMap = {
427
442
  "==": (a, b) => +(a == b),
@@ -453,18 +468,19 @@ for (const key in operatorMap) {
453
468
  if (!(value instanceof LiteralValue)) {
454
469
  return BaseValue.prototype[key].apply(this, [scope, value]);
455
470
  }
456
- return [new LiteralValue(scope, fn(this.num, value.num)), []];
471
+ return [new LiteralValue(fn(this.data, value.data)), []];
457
472
  };
458
473
  }
459
474
  const unaryOperatorMap = {
460
475
  "!": v => +!v,
461
476
  "~": v => ~v,
462
477
  "u-": v => -v,
478
+ "u+": v => +v,
463
479
  };
464
480
  for (const key in unaryOperatorMap) {
465
- LiteralValue.prototype[key] = function (scope) {
481
+ LiteralValue.prototype[key] = function () {
466
482
  const fn = unaryOperatorMap[key];
467
- return [new LiteralValue(scope, fn(this.num)), []];
483
+ return [new LiteralValue(fn(this.data)), []];
468
484
  };
469
485
  }
470
486
 
@@ -519,8 +535,60 @@ const itemNames = [
519
535
  /**
520
536
  * A more type safe version of `Object.assign`
521
537
  */
538
+ // eslint-disable-next-line @typescript-eslint/ban-types
522
539
  function assign(obj, props) {
523
540
  return Object.assign(obj, props);
541
+ }
542
+ function appendSourceLocations(valueInst, node) {
543
+ for (const inst of valueInst[1]) {
544
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
545
+ inst.source ??= node.loc;
546
+ }
547
+ return valueInst;
548
+ }
549
+ function withAlwaysRuns(valueInst, value) {
550
+ valueInst[1].forEach(inst => (inst.alwaysRuns = value));
551
+ return valueInst;
552
+ }
553
+ function isTemplateObjectArray(value) {
554
+ return (value instanceof ObjectValue &&
555
+ value.data.length instanceof LiteralValue &&
556
+ typeof value.data.length.data === "number" &&
557
+ value.data.raw instanceof ObjectValue &&
558
+ value.data.raw.data.length instanceof LiteralValue &&
559
+ typeof value.data.raw.data.length.data === "number");
560
+ }
561
+
562
+ class ValueOwner {
563
+ /**
564
+ * Creates a new `ValueOwner`, if `value` is already owned,
565
+ * `this` will be aliased to `value`, else `this` will own `value`
566
+ */
567
+ constructor({ scope, constant = false, value, identifier, name, }) {
568
+ this.scope = scope;
569
+ this.constant = constant;
570
+ this.value = value;
571
+ this.identifier = identifier;
572
+ this.name = name ?? scope.makeTempName();
573
+ this.persistent = !!name;
574
+ this.owned = new Set();
575
+ if (!value.owner?.persistent)
576
+ this.own(value);
577
+ }
578
+ own(target) {
579
+ target.owner = this;
580
+ this.owned.add(target);
581
+ }
582
+ replace(target) {
583
+ this.value.owner = null;
584
+ this.owned.delete(this.value);
585
+ this.value = target;
586
+ this.own(target);
587
+ }
588
+ moveInto(owner) {
589
+ this.owned.forEach(value => owner.own(value));
590
+ this.owned.clear();
591
+ }
524
592
  }
525
593
 
526
594
  /**
@@ -529,11 +597,12 @@ function assign(obj, props) {
529
597
  */
530
598
  class StoreValue extends BaseValue {
531
599
  constructor(scope) {
532
- super(scope);
600
+ super();
601
+ this.scope = scope;
533
602
  this.mutability = EMutability.mutable;
534
603
  }
535
- typeof(scope) {
536
- return [new LiteralValue(scope, "store"), []];
604
+ typeof() {
605
+ return [new LiteralValue("store"), []];
537
606
  }
538
607
  "="(scope, value) {
539
608
  if (this.mutability !== EMutability.mutable)
@@ -560,30 +629,34 @@ class StoreValue extends BaseValue {
560
629
  this.ensureOwned();
561
630
  return [this, []];
562
631
  }
632
+ ensureOwned() {
633
+ this.owner ??= new ValueOwner({ scope: this.scope, value: this });
634
+ }
563
635
  toString() {
564
636
  return this.owner?.name ?? discardedName;
565
637
  }
566
638
  }
567
639
 
568
640
  class ObjectValue extends VoidValue {
569
- constructor(scope, data = {}) {
570
- super(scope);
641
+ constructor(data = {}) {
642
+ super();
571
643
  this.mutability = EMutability.constant;
572
644
  this.macro = true;
573
645
  this.data = data;
574
646
  }
575
- static fromArray(scope, items) {
647
+ static fromArray(items, intialData) {
576
648
  const data = {
577
- length: new LiteralValue(scope, items.length),
649
+ ...intialData,
650
+ length: new LiteralValue(items.length),
578
651
  };
579
652
  items.forEach((item, i) => {
580
653
  if (item)
581
654
  data[i] = item;
582
655
  });
583
- return new ObjectValue(scope, data);
656
+ return new ObjectValue(data);
584
657
  }
585
- typeof(scope) {
586
- return [new LiteralValue(scope, "object"), []];
658
+ typeof() {
659
+ return [new LiteralValue("object"), []];
587
660
  }
588
661
  get(scope, key) {
589
662
  // avoids naming collisions with keys like
@@ -620,9 +693,7 @@ class ObjectValue extends VoidValue {
620
693
  return super.call(scope, args);
621
694
  return $call.call(scope, args);
622
695
  }
623
- ensureOwned() {
624
- this.owner ??= new ValueOwner({ scope: this.scope, value: this });
625
- }
696
+ ensureOwned() { }
626
697
  }
627
698
  for (const op of operators) {
628
699
  ObjectValue.prototype[op] = function (...args) {
@@ -674,7 +745,9 @@ class SenseableValue extends StoreValue {
674
745
  ];
675
746
  }
676
747
  if (prop instanceof StoreValue) {
677
- const temp = new StoreValue(scope);
748
+ const temp = assign(new SenseableValue(scope), {
749
+ mutability: EMutability.readonly,
750
+ });
678
751
  return [temp, [new InstructionBase("sensor", temp, this, prop)]];
679
752
  }
680
753
  throw new CompilerError(`Cannot sense "${prop}" property`);
@@ -689,8 +762,8 @@ class SenseableValue extends StoreValue {
689
762
  * each of them to their counterparts on the right hand value.
690
763
  */
691
764
  class DestructuringValue extends VoidValue {
692
- constructor(scope, members) {
693
- super(scope);
765
+ constructor(members) {
766
+ super();
694
767
  this.members = members;
695
768
  this.macro = true;
696
769
  }
@@ -799,7 +872,7 @@ const Program = (c, scope, node) => {
799
872
  };
800
873
 
801
874
  const VariableDeclaration = (c, scope, node) => {
802
- return c.handleMany(scope, node.declarations, (scope, child) => VariableDeclarator(c, scope, child, node.kind));
875
+ return c.handleMany(scope, node.declarations, child => VariableDeclarator(c, scope, child, node.kind));
803
876
  };
804
877
  const VariableDeclarator = (c, scope, node, kind = "let") => {
805
878
  const [init, inst] = node.init
@@ -809,24 +882,24 @@ const VariableDeclarator = (c, scope, node, kind = "let") => {
809
882
  return [null, inst];
810
883
  };
811
884
  const Declare = (c, scope, node, kind, init) => {
812
- switch (node.type) {
813
- case "Identifier":
814
- return DeclareIdentifier(c, scope, node, kind, init);
815
- case "ArrayPattern":
816
- return DeclareArrayPattern(c, scope, node, kind, init);
817
- case "ObjectPattern":
818
- return DeclareObjectPattern(c, scope, node, kind, init);
819
- default:
820
- throw new CompilerError(`Unsupported declaration type: ${node.type}`, [
821
- node,
822
- ]);
823
- }
885
+ return c.handle(scope, node, () => {
886
+ switch (node.type) {
887
+ case "Identifier":
888
+ return DeclareIdentifier(c, scope, node, kind, init);
889
+ case "ArrayPattern":
890
+ return DeclareArrayPattern(c, scope, node, kind, init);
891
+ case "ObjectPattern":
892
+ return DeclareObjectPattern(c, scope, node, kind, init);
893
+ default:
894
+ throw new CompilerError(`Unsupported declaration type: ${node.type}`, node);
895
+ }
896
+ });
824
897
  };
825
898
  const DeclareIdentifier = (c, scope, node, kind, init) => {
826
899
  const { name: identifier } = node;
827
900
  const name = nodeName(node, !c.compactNames && identifier);
828
901
  if (kind === "const" && !init)
829
- throw new CompilerError("Constants must be initialized.", [node]);
902
+ throw new CompilerError("Constants must be initialized.", node);
830
903
  if (kind === "const" && init?.mutability === EMutability.constant) {
831
904
  const owner = new ValueOwner({
832
905
  scope,
@@ -843,9 +916,7 @@ const DeclareIdentifier = (c, scope, node, kind, init) => {
843
916
  const inst = [];
844
917
  if (init) {
845
918
  if (init.macro)
846
- throw new CompilerError("Macro values must be held by constants", [
847
- node,
848
- ]);
919
+ throw new CompilerError("Macro values must be held by constants", node);
849
920
  inst.push(...value["="](scope, init)[1]);
850
921
  }
851
922
  if (kind === "const")
@@ -864,39 +935,38 @@ const DeclareArrayPattern = (c, scope, node, kind, init) => {
864
935
  continue;
865
936
  const val = init.data[i];
866
937
  if (!val)
867
- throw new CompilerError(`The target object does not have a value at index ${i}`, [element]);
938
+ throw new CompilerError(`The target object does not have a value at index ${i}`, element);
868
939
  inst.push(...Declare(c, scope, element, kind, val)[1]);
869
940
  }
870
941
  return [null, inst];
871
942
  };
872
943
  const DeclareObjectPattern = (c, scope, node, kind, base) => {
873
944
  if (!base)
874
- throw new CompilerError("Cannot use object destructuring without an initializer", [node]);
945
+ throw new CompilerError("Cannot use object destructuring without an initializer", node);
875
946
  const { properties } = node;
876
947
  const [init, inst] = base.consume(scope);
877
- for (const prop of properties) {
948
+ const propertiesInst = c.handleMany(scope, properties, prop => {
878
949
  if (prop.type === "RestElement")
879
- throw new CompilerError("The rest operator is not supported", [prop]);
950
+ throw new CompilerError("The rest operator is not supported", prop);
880
951
  const { key, value } = prop;
881
- const child = key.type === "Identifier" && !prop.computed
882
- ? [new LiteralValue(scope, key.name), []]
952
+ const keyInst = key.type === "Identifier" && !prop.computed
953
+ ? [new LiteralValue(key.name), []]
883
954
  : c.handleConsume(scope, prop.key);
884
- inst.push(...child[1]);
885
- const propInit = init.get(scope, child[0]);
886
- inst.push(...propInit[1]);
887
- inst.push(...Declare(c, scope, value, kind, propInit[0])[1]);
888
- }
889
- return [null, inst];
955
+ const propInit = init.get(scope, keyInst[0]);
956
+ const declarationInst = Declare(c, scope, value, kind, propInit[0]);
957
+ return [null, [...keyInst[1], ...propInit[1], ...declarationInst[1]]];
958
+ });
959
+ return [null, [...inst, ...propertiesInst[1]]];
890
960
  };
891
961
 
892
- const Literal = (_c, scope, node) => [new LiteralValue(scope, node.value), []];
962
+ const Literal = (_c, scope, node) => [new LiteralValue(node.value), []];
893
963
  const NumericLiteral = Literal;
894
964
  const StringLiteral = Literal;
895
- const NullLiteral = (_c, scope) => [
896
- new LiteralValue(scope, null),
965
+ const NullLiteral = () => [
966
+ new LiteralValue(null),
897
967
  [],
898
968
  ];
899
- const BooleanLiteral = (_c, scope, node) => [new LiteralValue(scope, +node.value), []];
969
+ const BooleanLiteral = (_c, scope, node) => [new LiteralValue(+node.value), []];
900
970
 
901
971
  const LRExpression = (c, scope, node) => {
902
972
  const [left, leftInst] = c.handleConsume(scope, node.left);
@@ -905,7 +975,34 @@ const LRExpression = (c, scope, node) => {
905
975
  return [op, [...leftInst, ...rightInst, ...opInst]];
906
976
  };
907
977
  const BinaryExpression = LRExpression;
908
- const LogicalExpression = LRExpression;
978
+ const LogicalExpression = (c, scope, node) => {
979
+ if (node.operator !== "??")
980
+ return LRExpression(c, scope, node);
981
+ const nullLiteral = new LiteralValue(null);
982
+ const endAdress = new LiteralValue(null);
983
+ const [left, leftInst] = c.handleEval(scope, node.left);
984
+ const [nullTest] = left["=="](scope, nullLiteral);
985
+ if (nullTest instanceof LiteralValue) {
986
+ if (nullTest.data)
987
+ return c.handleEval(scope, node.right);
988
+ else
989
+ return [left, leftInst];
990
+ }
991
+ const [right, rightInst] = c.handleEval(scope, node.right);
992
+ const result = new StoreValue(scope);
993
+ result.ensureOwned();
994
+ return [
995
+ result,
996
+ [
997
+ ...leftInst,
998
+ ...result["="](scope, left)[1],
999
+ new JumpInstruction(endAdress, EJumpKind.NotEqual, result, nullLiteral),
1000
+ ...rightInst,
1001
+ ...result["="](scope, right)[1],
1002
+ new AddressResolver(endAdress),
1003
+ ],
1004
+ ];
1005
+ };
909
1006
  const AssignmentExpression = (c, scope, node) => {
910
1007
  const [left, leftInst] = c.handle(scope, node.left);
911
1008
  // doesn't need to consume because the operators already do that
@@ -941,13 +1038,13 @@ const ConditionalExpression = (c, scope, node) => {
941
1038
  result.ensureOwned();
942
1039
  const consequent = c.handleEval(scope, node.consequent);
943
1040
  const alternate = c.handleEval(scope, node.alternate);
944
- const alternateStartAdress = new LiteralValue(scope, null);
945
- const endExpressionAdress = new LiteralValue(scope, null);
1041
+ const alternateStartAdress = new LiteralValue(null);
1042
+ const endExpressionAdress = new LiteralValue(null);
946
1043
  return [
947
1044
  result,
948
1045
  [
949
1046
  ...testInst,
950
- new JumpInstruction(alternateStartAdress, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
1047
+ new JumpInstruction(alternateStartAdress, EJumpKind.Equal, test, new LiteralValue(0)),
951
1048
  ...consequent[1],
952
1049
  ...result["="](scope, consequent[0])[1],
953
1050
  new JumpInstruction(endExpressionAdress, EJumpKind.Always),
@@ -967,12 +1064,12 @@ const ExpressionStatement = (c, scope, node) => {
967
1064
  return c.handle(scope, node.expression);
968
1065
  };
969
1066
  const BreakStatement = (_, scope) => {
970
- const addr = new LiteralValue(scope, null);
1067
+ const addr = new LiteralValue(null);
971
1068
  scope.break.bind(addr);
972
1069
  return [null, [new BreakInstruction(addr)]];
973
1070
  };
974
1071
  const ContinueStatement = (_, scope) => {
975
- const addr = new LiteralValue(scope, null);
1072
+ const addr = new LiteralValue(null);
976
1073
  scope.continue.bind(addr);
977
1074
  return [null, [new ContinueInstruction(addr)]];
978
1075
  };
@@ -994,19 +1091,81 @@ const IfStatement = (c, scope, node) => {
994
1091
  inst.push(...c.handle(scope, node.alternate)[1]);
995
1092
  return [null, inst];
996
1093
  }
997
- const endIfAddr = new LiteralValue(scope, null);
998
- inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...c.handle(scope, node.consequent)[1], new AddressResolver(endIfAddr));
999
- const endElseAddr = new LiteralValue(scope, null);
1000
- if (node.alternate)
1001
- inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...c.handle(scope, node.alternate)[1], new AddressResolver(endElseAddr));
1094
+ const endIfAddr = new LiteralValue(null);
1095
+ inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(0)), ...withAlwaysRuns(c.handle(scope, node.consequent), false)[1], new AddressResolver(endIfAddr));
1096
+ const endElseAddr = new LiteralValue(null);
1097
+ if (node.alternate) {
1098
+ inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...withAlwaysRuns(c.handle(scope, node.alternate), false)[1], new AddressResolver(endElseAddr));
1099
+ }
1002
1100
  return [null, inst];
1003
1101
  };
1004
1102
 
1103
+ const SwitchStatement = (c, scope, node) => {
1104
+ const innerScope = scope.createScope();
1105
+ const [ref, refInst] = c.handleConsume(scope, node.discriminant);
1106
+ const inst = [];
1107
+ const endAdress = new LiteralValue(null);
1108
+ const endLine = new AddressResolver(endAdress).bindBreak(innerScope);
1109
+ const caseJumps = [];
1110
+ let defaultJump;
1111
+ for (const scase of node.cases) {
1112
+ const [, bodyInst] = c.handleMany(innerScope, scase.consequent);
1113
+ const bodyAdress = new LiteralValue(null);
1114
+ const bodyLine = new AddressResolver(bodyAdress);
1115
+ if (!scase.test) {
1116
+ [defaultJump] = c.handle(innerScope, scase, () => [
1117
+ null,
1118
+ [new JumpInstruction(bodyAdress, EJumpKind.Always)],
1119
+ ])[1];
1120
+ inst.push(bodyLine, ...bodyInst);
1121
+ continue;
1122
+ }
1123
+ const [test, testInst] = c.handleConsume(innerScope, scase.test);
1124
+ // check if it can be evaluated at compile time
1125
+ const [comp] = ref["=="](innerScope, test);
1126
+ // if the constant expression resolves to false
1127
+ // the whole case gets omitted
1128
+ // otherwise it returns the instructions for
1129
+ // the body of this case
1130
+ if (comp instanceof LiteralValue) {
1131
+ if (comp.data)
1132
+ return [null, bodyInst];
1133
+ else
1134
+ continue;
1135
+ }
1136
+ // makes sourcemapping for the jump more specific
1137
+ const [, jump] = c.handle(innerScope, scase, () => [
1138
+ null,
1139
+ [new JumpInstruction(bodyAdress, EJumpKind.StrictEqual, ref, test)],
1140
+ ]);
1141
+ caseJumps.push(...testInst, ...jump);
1142
+ inst.push(bodyLine, ...bodyInst);
1143
+ }
1144
+ // ensures that the processor exits
1145
+ // the switch if no cases match
1146
+ defaultJump ??= new JumpInstruction(endAdress, EJumpKind.Always);
1147
+ if (caseJumps.length > 0) {
1148
+ withAlwaysRuns([null, inst], false);
1149
+ withAlwaysRuns([null, [...caseJumps.slice(1), defaultJump]], false);
1150
+ withAlwaysRuns([null, inst], false);
1151
+ }
1152
+ return [
1153
+ null,
1154
+ [
1155
+ ...refInst,
1156
+ ...caseJumps,
1157
+ ...(caseJumps.length > 0 ? [defaultJump] : []),
1158
+ ...inst,
1159
+ endLine,
1160
+ ],
1161
+ ];
1162
+ };
1163
+
1005
1164
  const WhileStatement = (c, scope, node) => {
1006
1165
  const lines = [];
1007
1166
  const [test, testLines] = c.handleConsume(scope, node.test);
1008
- const startLoopAddr = new LiteralValue(scope, null);
1009
- const endLoopAddr = new LiteralValue(scope, null);
1167
+ const startLoopAddr = new LiteralValue(null);
1168
+ const endLoopAddr = new LiteralValue(null);
1010
1169
  const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1011
1170
  const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1012
1171
  if (test instanceof LiteralValue) {
@@ -1015,13 +1174,13 @@ const WhileStatement = (c, scope, node) => {
1015
1174
  }
1016
1175
  return [null, lines];
1017
1176
  }
1018
- 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);
1177
+ 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);
1019
1178
  return [null, lines];
1020
1179
  };
1021
1180
  const DoWhileStatement = (c, scope, node) => {
1022
1181
  const lines = [];
1023
1182
  const [test, testLines] = c.handleConsume(scope, node.test);
1024
- const startLoopAddr = new LiteralValue(scope, null);
1183
+ const startLoopAddr = new LiteralValue(null);
1025
1184
  const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1026
1185
  const [, bodyLines] = c.handle(scope, node.body);
1027
1186
  if (test instanceof LiteralValue) {
@@ -1037,7 +1196,7 @@ const DoWhileStatement = (c, scope, node) => {
1037
1196
  ],
1038
1197
  ];
1039
1198
  }
1040
- lines.push(startLoopLine, ...bodyLines, ...testLines, new JumpInstruction(startLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 1)));
1199
+ lines.push(startLoopLine, ...bodyLines, ...testLines, new JumpInstruction(startLoopAddr, EJumpKind.Equal, test, new LiteralValue(1)));
1041
1200
  return [null, lines];
1042
1201
  };
1043
1202
 
@@ -1046,10 +1205,10 @@ const ForStatement = (c, scope, node) => {
1046
1205
  const initInst = node.init ? c.handle(scope, node.init)[1] : [];
1047
1206
  const [test, testLines] = node.test
1048
1207
  ? c.handleConsume(scope, node.test)
1049
- : [new LiteralValue(scope, 1), []];
1208
+ : [new LiteralValue(1), []];
1050
1209
  const updateLines = node.update ? c.handle(scope, node.update)[1] : [];
1051
- const startLoopAddr = new LiteralValue(scope, null);
1052
- const endLoopAddr = new LiteralValue(scope, null);
1210
+ const startLoopAddr = new LiteralValue(null);
1211
+ const endLoopAddr = new LiteralValue(null);
1053
1212
  const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
1054
1213
  const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
1055
1214
  return [
@@ -1058,8 +1217,8 @@ const ForStatement = (c, scope, node) => {
1058
1217
  ...initInst,
1059
1218
  startLoopLine,
1060
1219
  ...testLines,
1061
- new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
1062
- ...c.handle(scope, node.body)[1],
1220
+ new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(0)),
1221
+ ...withAlwaysRuns(c.handle(scope, node.body), false)[1],
1063
1222
  ...updateLines,
1064
1223
  new JumpInstruction(startLoopAddr, EJumpKind.Always),
1065
1224
  endLoopLine,
@@ -1068,20 +1227,20 @@ const ForStatement = (c, scope, node) => {
1068
1227
  };
1069
1228
 
1070
1229
  class FunctionValue extends VoidValue {
1071
- constructor({ scope, params, body, c, node, }) {
1072
- super(scope);
1230
+ constructor({ scope, params, body, c, }) {
1231
+ super();
1073
1232
  this.mutability = EMutability.constant;
1074
1233
  this.macro = true;
1075
1234
  this.paramOwners = [];
1076
1235
  this.bundled = false;
1077
1236
  this.initialized = false;
1237
+ this.scope = scope;
1078
1238
  this.body = body;
1079
1239
  this.c = c;
1080
- this.node = node;
1081
1240
  this.params = params;
1082
1241
  }
1083
- typeof(scope) {
1084
- return [new LiteralValue(scope, "function"), []];
1242
+ typeof() {
1243
+ return [new LiteralValue("function"), []];
1085
1244
  }
1086
1245
  initScope(name) {
1087
1246
  this.childScope = this.scope.createFunction(name);
@@ -1090,7 +1249,9 @@ class FunctionValue extends VoidValue {
1090
1249
  const name = nodeName(id, !this.c.compactNames && id.name);
1091
1250
  const owner = new ValueOwner({
1092
1251
  scope: this.childScope,
1093
- value: new StoreValue(this.childScope),
1252
+ value: assign(new SenseableValue(this.childScope), {
1253
+ mutability: EMutability.mutable,
1254
+ }),
1094
1255
  identifier: id.name,
1095
1256
  name,
1096
1257
  });
@@ -1107,7 +1268,7 @@ class FunctionValue extends VoidValue {
1107
1268
  this.initialized = true;
1108
1269
  const { name } = this.owner;
1109
1270
  this.initScope(name);
1110
- this.addr = new LiteralValue(this.childScope, null);
1271
+ this.addr = new LiteralValue(null);
1111
1272
  this.temp = new ValueOwner({
1112
1273
  scope: this.childScope,
1113
1274
  name: `${internalPrefix}f${name}`,
@@ -1125,18 +1286,23 @@ class FunctionValue extends VoidValue {
1125
1286
  ...this.c.handle(this.childScope, this.body)[1],
1126
1287
  ];
1127
1288
  if (!endsWithReturn(this.inst)) {
1128
- this.inst.push(new SetCounterInstruction(this.ret.value));
1289
+ this.inst.push(assign(new SetCounterInstruction(this.ret.value), {
1290
+ intent: EInstIntent.return,
1291
+ }));
1129
1292
  }
1130
1293
  }
1131
1294
  normalReturn(scope, arg) {
1132
1295
  const argInst = arg ? this.temp.value["="](scope, arg)[1] : [];
1133
- return [null, [...argInst, new SetCounterInstruction(this.ret.value)]];
1296
+ const returnInst = assign(new SetCounterInstruction(this.ret.value), {
1297
+ intent: EInstIntent.return,
1298
+ });
1299
+ return [null, [...argInst, returnInst]];
1134
1300
  }
1135
1301
  normalCall(scope, args) {
1136
1302
  if (!this.bundled)
1137
1303
  this.childScope.inst.push(...this.inst);
1138
1304
  this.bundled = true;
1139
- const callAddressLiteral = new LiteralValue(scope, null);
1305
+ const callAddressLiteral = new LiteralValue(null);
1140
1306
  const inst = this.paramOwners
1141
1307
  .map(({ value: param }, i) => param["="](scope, args[i])[1])
1142
1308
  .reduce((s, c) => s.concat(c), [])
@@ -1145,7 +1311,12 @@ class FunctionValue extends VoidValue {
1145
1311
  }
1146
1312
  inlineReturn(scope, arg) {
1147
1313
  const argInst = arg ? this.inlineTemp.value["="](scope, arg)[1] : [];
1148
- return [null, argInst];
1314
+ if (!this.inlineEnd)
1315
+ throw new CompilerError("Error during inline attempt: missing inline end adress");
1316
+ const jump = assign(new JumpInstruction(this.inlineEnd, EJumpKind.Always), {
1317
+ intent: EInstIntent.return,
1318
+ });
1319
+ return [null, [...argInst, jump]];
1149
1320
  }
1150
1321
  inlineCall(scope, args) {
1151
1322
  // create return value
@@ -1155,7 +1326,6 @@ class FunctionValue extends VoidValue {
1155
1326
  mutability: EMutability.mutable,
1156
1327
  }),
1157
1328
  });
1158
- this.inlineEnd = new LiteralValue(scope, null);
1159
1329
  // make a copy of the function scope
1160
1330
  const fnScope = this.childScope.copy();
1161
1331
  // hard set variables within the function scope
@@ -1170,16 +1340,13 @@ class FunctionValue extends VoidValue {
1170
1340
  name: owner.name,
1171
1341
  }));
1172
1342
  });
1343
+ this.inlineEnd = new LiteralValue(null);
1173
1344
  this.tryingInline = true;
1174
- const inst = this.c.handle(fnScope, this.body)[1];
1345
+ let inst = this.c.handle(fnScope, this.body)[1];
1175
1346
  this.tryingInline = false;
1176
- // removing useless instruction
1177
- // get the last instructions
1178
- // const [jump] = inst.slice(-1);
1179
- // if (jump instanceof JumpInstruction) {
1180
- // // remove useless jump
1181
- // if (jump.args[1] === this.inlineEnd) inst.pop();
1182
- // }
1347
+ const returnIndex = inst.findIndex(i => i.alwaysRuns && i.intent === EInstIntent.return);
1348
+ if (returnIndex !== -1)
1349
+ inst = inst.slice(0, returnIndex + 1);
1183
1350
  inst.push(new AddressResolver(this.inlineEnd));
1184
1351
  // return the function value
1185
1352
  return [this.inlineTemp.value, inst];
@@ -1224,11 +1391,14 @@ function endsWithReturn(inst) {
1224
1391
  function handleFunctionNode(c, scope, node) {
1225
1392
  let { params, body } = node;
1226
1393
  if (es.isExpression(body)) {
1227
- body = es.blockStatement([es.returnStatement(body)]);
1394
+ const { loc } = body;
1395
+ const statement = es.returnStatement(body);
1396
+ statement.loc = loc;
1397
+ body = es.blockStatement([statement]);
1398
+ body.loc = loc;
1228
1399
  }
1229
1400
  return [
1230
1401
  new FunctionValue({
1231
- node,
1232
1402
  scope,
1233
1403
  params: params,
1234
1404
  body,
@@ -1270,16 +1440,32 @@ const CallExpression = (c, scope, node) => {
1270
1440
  inst.push(...callInst);
1271
1441
  return [callValue, inst];
1272
1442
  };
1273
- const NewExpression = CallExpression;
1443
+ const NewExpression = CallExpression;
1444
+ const TaggedTemplateExpression = (c, scope, node) => {
1445
+ const [tag, tagInst] = c.handleConsume(scope, node.tag);
1446
+ const template = node.quasi;
1447
+ const stringsObject = ObjectValue.fromArray(template.quasis.map(quasi => new LiteralValue(quasi.value.cooked ?? "")), {
1448
+ raw: ObjectValue.fromArray(template.quasis.map(quasi => new LiteralValue(quasi.value.raw))),
1449
+ });
1450
+ const expressions = [];
1451
+ const expressionInsts = [];
1452
+ template.expressions.forEach(expression => {
1453
+ const [value, inst] = c.handleConsume(scope, expression);
1454
+ expressions.push(value);
1455
+ expressionInsts.push(...inst);
1456
+ });
1457
+ const [result, resultInst] = tag.call(scope, [stringsObject, ...expressions]);
1458
+ return [result, [...expressionInsts, ...tagInst, ...resultInst]];
1459
+ };
1274
1460
 
1275
1461
  const ObjectExpression = (c, scope, node) => {
1276
1462
  const data = {};
1277
1463
  const inst = [];
1278
1464
  for (const prop of node.properties) {
1279
1465
  if (prop.type === "SpreadElement")
1280
- throw new CompilerError("Cannot handle spread element", [prop]);
1466
+ throw new CompilerError("Cannot handle spread element", prop);
1281
1467
  if (prop.computed)
1282
- throw new CompilerError("Cannot handle computed property.", [prop]);
1468
+ throw new CompilerError("Cannot handle computed property.", prop);
1283
1469
  const { key } = prop;
1284
1470
  const value = prop.type === "ObjectProperty" ? prop.value : prop;
1285
1471
  let index;
@@ -1290,20 +1476,21 @@ const ObjectExpression = (c, scope, node) => {
1290
1476
  index = `${key.value}`;
1291
1477
  }
1292
1478
  else {
1293
- throw new CompilerError(`Unsupported object key type: ${key.type}`, [
1294
- key,
1295
- ]);
1479
+ throw new CompilerError(`Unsupported object key type: ${key.type}`, key);
1296
1480
  }
1297
1481
  const [member, memberInst] = c.handleEval(scope, value);
1298
- const owner = new ValueOwner({
1299
- scope,
1300
- constant: true,
1301
- value: member,
1302
- });
1303
- data[index] = owner.value;
1482
+ // TODO: use an approach that can be defined by each type
1483
+ if (!member.owner && !(member instanceof LiteralValue)) {
1484
+ new ValueOwner({
1485
+ scope,
1486
+ constant: true,
1487
+ value: member,
1488
+ });
1489
+ }
1490
+ data[index] = member;
1304
1491
  inst.push(...memberInst);
1305
1492
  }
1306
- return [new ObjectValue(scope, data), inst];
1493
+ return [new ObjectValue(data), inst];
1307
1494
  };
1308
1495
  const ArrayExpression = (c, scope, node) => {
1309
1496
  const items = [];
@@ -1315,13 +1502,13 @@ const ArrayExpression = (c, scope, node) => {
1315
1502
  items.push(value);
1316
1503
  inst.push(...valueInst);
1317
1504
  });
1318
- return [ObjectValue.fromArray(scope, items), inst];
1505
+ return [ObjectValue.fromArray(items), inst];
1319
1506
  };
1320
1507
  const MemberExpression = (c, scope, node) => {
1321
1508
  const [obj, objInst] = c.handleConsume(scope, node.object);
1322
1509
  const [prop, propInst] = node.computed
1323
1510
  ? c.handleConsume(scope, node.property)
1324
- : [new LiteralValue(scope, node.property.name), []];
1511
+ : [new LiteralValue(node.property.name), []];
1325
1512
  const [got, gotInst] = obj.get(scope, prop);
1326
1513
  return [got, [...objInst, ...propInst, ...gotInst]];
1327
1514
  };
@@ -1334,13 +1521,11 @@ const ArrayPattern = (c, scope, node) => {
1334
1521
  continue;
1335
1522
  const valueInst = c.handle(scope, element);
1336
1523
  if (!valueInst[0])
1337
- throw new CompilerError("Destructuring element must resolve to a value", [
1338
- element,
1339
- ]);
1524
+ throw new CompilerError("Destructuring element must resolve to a value", element);
1340
1525
  inst.push(...valueInst[1]);
1341
- members.set(new LiteralValue(scope, i), valueInst[0]);
1526
+ members.set(new LiteralValue(i), valueInst[0]);
1342
1527
  }
1343
- return [new DestructuringValue(scope, members), inst];
1528
+ return [new DestructuringValue(members), inst];
1344
1529
  };
1345
1530
  const ObjectPattern = (c, scope, node) => {
1346
1531
  const inst = [];
@@ -1352,31 +1537,20 @@ const ObjectPattern = (c, scope, node) => {
1352
1537
  continue;
1353
1538
  const { key } = prop;
1354
1539
  const keyInst = !prop.computed && key.type === "Identifier"
1355
- ? [new LiteralValue(scope, key.name), []]
1540
+ ? [new LiteralValue(key.name), []]
1356
1541
  : c.handleConsume(scope, prop.key);
1357
1542
  inst.push(...keyInst[1]);
1358
1543
  const valueInst = c.handle(scope, prop.value);
1359
1544
  if (!valueInst[0])
1360
- throw new CompilerError("Destructuring member must resolve to a value", [
1361
- prop.value,
1362
- ]);
1545
+ throw new CompilerError("Destructuring member must resolve to a value", prop.value);
1363
1546
  inst.push(...valueInst[1]);
1364
1547
  members.set(keyInst[0], valueInst[0]);
1365
1548
  }
1366
- return [new DestructuringValue(scope, members), inst];
1549
+ return [new DestructuringValue(members), inst];
1367
1550
  };
1368
1551
 
1369
- const TemplateLiteral = (c, scope, node) => {
1370
- const args = [];
1371
- const inst = [];
1372
- node.expressions.forEach((expression, i) => {
1373
- const [v, vi] = c.handleConsume(scope, expression);
1374
- inst.push(...vi);
1375
- args.push(node.quasis[i].value.raw, v);
1376
- });
1377
- args.push(node.quasis.slice(-1)[0].value.raw);
1378
- inst.push(new ZeroSpaceInstruction(...args));
1379
- return [null, inst];
1552
+ const TemplateLiteral = () => {
1553
+ throw new CompilerError("Template strings are currently unavailable. To inline mlog code use the asm function.");
1380
1554
  };
1381
1555
 
1382
1556
  const BlockStatement = (c, scope, node) => {
@@ -1409,14 +1583,12 @@ const TSEnumDeclaration = (c, scope, node) => {
1409
1583
  const data = {};
1410
1584
  for (const member of node.members) {
1411
1585
  if (lastType === "string" && !member.initializer)
1412
- throw new CompilerError("This enum member must be initialized", [member]);
1586
+ throw new CompilerError("This enum member must be initialized", member);
1413
1587
  const [value] = member.initializer
1414
1588
  ? c.handleEval(scope, member.initializer)
1415
- : [new LiteralValue(scope, counter)];
1589
+ : [new LiteralValue(counter)];
1416
1590
  if (!(value instanceof LiteralValue))
1417
- throw new CompilerError("Enum members must contain literal values", [
1418
- member,
1419
- ]);
1591
+ throw new CompilerError("Enum members must contain literal values", member);
1420
1592
  if (typeof value.data === "number") {
1421
1593
  lastType = "number";
1422
1594
  counter = value.data + 1;
@@ -1429,7 +1601,7 @@ const TSEnumDeclaration = (c, scope, node) => {
1429
1601
  }
1430
1602
  scope.set(new ValueOwner({
1431
1603
  scope,
1432
- value: new ObjectValue(scope, data),
1604
+ value: new ObjectValue(data),
1433
1605
  constant: true,
1434
1606
  identifier: node.id.name,
1435
1607
  name: nodeName(node, !c.compactNames && node.id.name),
@@ -1462,6 +1634,7 @@ var handlers = /*#__PURE__*/Object.freeze({
1462
1634
  ContinueStatement: ContinueStatement,
1463
1635
  ReturnStatement: ReturnStatement,
1464
1636
  IfStatement: IfStatement,
1637
+ SwitchStatement: SwitchStatement,
1465
1638
  WhileStatement: WhileStatement,
1466
1639
  DoWhileStatement: DoWhileStatement,
1467
1640
  ForStatement: ForStatement,
@@ -1471,6 +1644,7 @@ var handlers = /*#__PURE__*/Object.freeze({
1471
1644
  ObjectMethod: ObjectMethod,
1472
1645
  CallExpression: CallExpression,
1473
1646
  NewExpression: NewExpression,
1647
+ TaggedTemplateExpression: TaggedTemplateExpression,
1474
1648
  ObjectExpression: ObjectExpression,
1475
1649
  ArrayExpression: ArrayExpression,
1476
1650
  MemberExpression: MemberExpression,
@@ -1488,14 +1662,14 @@ var handlers = /*#__PURE__*/Object.freeze({
1488
1662
  });
1489
1663
 
1490
1664
  class MacroFunction extends VoidValue {
1491
- constructor(scope, fn) {
1492
- super(scope);
1665
+ constructor(fn) {
1666
+ super();
1493
1667
  this.macro = true;
1494
1668
  this.constant = true;
1495
1669
  this.fn = fn;
1496
1670
  }
1497
1671
  call(scope, args) {
1498
- return this.fn.apply(this, args);
1672
+ return this.fn.apply(this, [scope, ...args]);
1499
1673
  }
1500
1674
  eval(_scope) {
1501
1675
  return [this, []];
@@ -1526,16 +1700,16 @@ const mathOperations = {
1526
1700
  sqrt: a => Math.sqrt(a),
1527
1701
  rand: null,
1528
1702
  };
1529
- function createMacroMathOperations(scope) {
1703
+ function createMacroMathOperations() {
1530
1704
  const macroMathOperations = {};
1531
1705
  for (const key in mathOperations) {
1532
1706
  const fn = mathOperations[key];
1533
- macroMathOperations[key] = new MacroFunction(scope, (a, b) => {
1707
+ macroMathOperations[key] = new MacroFunction((scope, a, b) => {
1534
1708
  if (b) {
1535
1709
  if (fn && a instanceof LiteralValue && b instanceof LiteralValue) {
1536
1710
  if (typeof a.data !== "number" || typeof b.data !== "number")
1537
1711
  throw new CompilerError("Cannot do math operation with non-numerical literals.");
1538
- return [new LiteralValue(scope, fn(a.num, b.num)), []];
1712
+ return [new LiteralValue(fn(a.num, b.num)), []];
1539
1713
  }
1540
1714
  const temp = new StoreValue(scope);
1541
1715
  return [temp, [new OperationInstruction(key, temp, a, b)]];
@@ -1543,7 +1717,7 @@ function createMacroMathOperations(scope) {
1543
1717
  if (fn && a instanceof LiteralValue) {
1544
1718
  if (typeof a.data !== "number")
1545
1719
  throw new CompilerError("Cannot do math operation with non-numerical literal.");
1546
- return [new LiteralValue(scope, fn(a.num)), []];
1720
+ return [new LiteralValue(fn(a.num)), []];
1547
1721
  }
1548
1722
  const temp = new StoreValue(scope);
1549
1723
  return [temp, [new OperationInstruction(key, temp, a, b)]];
@@ -1552,74 +1726,190 @@ function createMacroMathOperations(scope) {
1552
1726
  return macroMathOperations;
1553
1727
  }
1554
1728
  class MlogMath extends ObjectValue {
1555
- constructor(scope) {
1556
- super(scope, createMacroMathOperations(scope));
1729
+ constructor() {
1730
+ super(createMacroMathOperations());
1557
1731
  }
1558
1732
  }
1559
1733
  // op angle result a b
1560
1734
  // op len result a b
1561
1735
 
1562
1736
  class Concat extends MacroFunction {
1563
- constructor(scope) {
1564
- super(scope, (...values) => {
1737
+ constructor() {
1738
+ super((scope, ...values) => {
1565
1739
  for (const value of values)
1566
1740
  if (!(value instanceof LiteralValue))
1567
1741
  throw new CompilerError("Concat arguments must all be literal values.");
1568
1742
  return [
1569
- new LiteralValue(scope, values.map(v => v.data).join("")),
1743
+ new LiteralValue(values.map(v => v.data).join("")),
1570
1744
  [],
1571
1745
  ];
1572
1746
  });
1573
1747
  }
1574
1748
  }
1575
1749
 
1576
- class Draw extends MacroFunction {
1577
- constructor(scope) {
1578
- super(scope, (kind, ...args) => {
1579
- if (!(kind instanceof LiteralValue && typeof kind.data === "string"))
1580
- throw new CompilerError("Draw kind must be a string literal.");
1581
- if ([
1582
- "clear",
1583
- "color",
1584
- "stroke",
1585
- "line",
1586
- "rect",
1587
- "lineRect",
1588
- "poly",
1589
- "linePoly",
1590
- "triangle",
1591
- "image",
1592
- ].indexOf(kind.data) === -1)
1593
- throw new CompilerError("Invalid draw kind");
1594
- return [
1595
- null,
1596
- [
1597
- new InstructionBase("draw", kind.data, ...args.map(v => {
1598
- if (v instanceof LiteralValue && typeof v.data === "string")
1599
- return v.data;
1600
- return v;
1601
- })),
1602
- ],
1603
- ];
1750
+ /** Asserts that `value` is a `LiteralValue` that contains a string */
1751
+ function assertStringLiteral(value, name) {
1752
+ if (!(value instanceof LiteralValue) || typeof value.data !== "string")
1753
+ throw new CompilerError(`${name} must be a string literal`);
1754
+ }
1755
+ /** Asserts that `value` is a string literal that is part of a given set of `members`*/
1756
+ function assertLiteralOneOf(value, members, name) {
1757
+ assertStringLiteral(value, name);
1758
+ if (!members.includes(value.data))
1759
+ throw new CompilerError(`${name} must be one of: ${members
1760
+ .slice(0, -1)
1761
+ .map(member => `"${member}"`)
1762
+ .join(", ")} or "${members[members.length - 1]}"`);
1763
+ }
1764
+ /** Asserts that `value` is either a store or a literal */
1765
+ function assertIsRuntimeValue(value, name) {
1766
+ if (!(value instanceof LiteralValue) && !(value instanceof StoreValue))
1767
+ throw new CompilerError(`${name} must be a valid runtime value`);
1768
+ }
1769
+ /** Asserts that `value` is an `ObjectValue` */
1770
+ function assertIsObjectMacro(value, name) {
1771
+ if (!(value instanceof ObjectValue))
1772
+ throw new CompilerError(`${name} must be an object macro`);
1773
+ }
1774
+ /** Asserts that `value` is an `ObjectValue` that has a length property */
1775
+ function assertIsArrayMacro(value, name) {
1776
+ if (!(value instanceof ObjectValue) || !value.data.length)
1777
+ throw new CompilerError(`${name} must be an array macro`);
1778
+ }
1779
+ /** Asserts that all of the fields described are present on `value`*/
1780
+ function assertObjectFields(value, fields) {
1781
+ const result = [];
1782
+ for (const field of fields) {
1783
+ const param = typeof field === "object" ? field : { key: field };
1784
+ const item = value.data[param.key];
1785
+ if (item) {
1786
+ param.validate?.(item);
1787
+ result.push(item);
1788
+ continue;
1789
+ }
1790
+ if (param.default == undefined)
1791
+ throw new CompilerError(`The field "${param.name ?? param.key}" must be present`);
1792
+ result.push(param.default);
1793
+ }
1794
+ return result;
1795
+ }
1796
+
1797
+ /** Used to create namespaces that contain multiple methods that map into instructions */
1798
+ function createOverloadNamespace({ overloads, handler, }) {
1799
+ const result = {};
1800
+ for (const key in overloads) {
1801
+ const { named, args } = overloads[key];
1802
+ if (named) {
1803
+ result[key] = new MacroFunction((scope, options) => {
1804
+ assertIsObjectMacro(options, named);
1805
+ return handler(scope, key, ...assertObjectFields(options, args));
1806
+ });
1807
+ continue;
1808
+ }
1809
+ result[key] = new MacroFunction((scope, ...params) => {
1810
+ const handlerParams = [];
1811
+ // validate the paramters
1812
+ for (let i = 0; i < args.length; i++) {
1813
+ let arg = args[i];
1814
+ if (typeof arg === "string")
1815
+ arg = { key: arg };
1816
+ const param = params[i];
1817
+ if (!param) {
1818
+ if (arg.default == undefined)
1819
+ throw new CompilerError(`Missing argument: ${arg.name ?? arg.key}`);
1820
+ handlerParams.push(arg.default);
1821
+ continue;
1822
+ }
1823
+ arg.validate?.(param);
1824
+ handlerParams.push(param);
1825
+ }
1826
+ return handler(scope, key, ...handlerParams);
1604
1827
  });
1605
1828
  }
1829
+ return result;
1830
+ }
1831
+
1832
+ class Draw extends ObjectValue {
1833
+ constructor() {
1834
+ const data = createOverloadNamespace({
1835
+ overloads: {
1836
+ clear: {
1837
+ args: ["r", "g", "b"],
1838
+ },
1839
+ color: {
1840
+ args: ["r", "g", "b", { key: "a", default: "" }],
1841
+ },
1842
+ stroke: {
1843
+ args: ["width"],
1844
+ },
1845
+ line: {
1846
+ named: "options",
1847
+ args: ["x", "y", "x2", "y2"],
1848
+ },
1849
+ rect: {
1850
+ named: "options",
1851
+ args: ["x", "y", "width", "height"],
1852
+ },
1853
+ lineRect: { named: "options", args: ["x", "y", "width", "height"] },
1854
+ linePoly: {
1855
+ named: "options",
1856
+ args: ["x", "y", "sides", "radius", "rotation"],
1857
+ },
1858
+ poly: {
1859
+ named: "options",
1860
+ args: ["x", "y", "sides", "radius", "rotation"],
1861
+ },
1862
+ triangle: {
1863
+ named: "options",
1864
+ args: ["x", "y", "x2", "y2", "x3", "y3"],
1865
+ },
1866
+ image: {
1867
+ named: "options",
1868
+ args: ["x", "y", "image", "size", "rotation"],
1869
+ },
1870
+ },
1871
+ handler(scope, overload, ...args) {
1872
+ return [null, [new InstructionBase("draw", overload, ...args)]];
1873
+ },
1874
+ });
1875
+ super(data);
1876
+ }
1606
1877
  }
1607
1878
 
1608
1879
  class Print extends MacroFunction {
1609
- constructor(scope) {
1610
- super(scope, (...values) => {
1880
+ constructor() {
1881
+ super((scope, ...values) => {
1882
+ const [first] = values;
1611
1883
  const inst = [];
1612
- for (const value of values) {
1613
- inst.push(new InstructionBase("print", value));
1884
+ if (!isTemplateObjectArray(first)) {
1885
+ for (const value of values) {
1886
+ inst.push(new InstructionBase("print", value));
1887
+ }
1888
+ return [null, inst];
1614
1889
  }
1890
+ // `first` is likely a template strings array
1891
+ // maybe this should be checked in another way?
1892
+ const { length } = first.data;
1893
+ for (let i = 1; i < values.length; i++) {
1894
+ const [string] = first.get(scope, new LiteralValue(i - 1));
1895
+ if (string.data)
1896
+ inst.push(new InstructionBase("print", string));
1897
+ inst.push(new InstructionBase("print", values[i]));
1898
+ }
1899
+ const [tail] = first.get(scope, new LiteralValue(length.data - 1));
1900
+ if (tail.data)
1901
+ inst.push(new InstructionBase("print", tail));
1615
1902
  return [null, inst];
1616
1903
  });
1617
1904
  }
1618
1905
  }
1619
1906
 
1907
+ const defaultTargetName$1 = "message1";
1620
1908
  class PrintFlush extends MacroFunction {
1621
- constructor(scope) {
1622
- super(scope, (target) => {
1909
+ constructor() {
1910
+ super((scope, target) => {
1911
+ if (!target)
1912
+ return [null, [new InstructionBase("printflush", defaultTargetName$1)]];
1623
1913
  if (!(target instanceof SenseableValue))
1624
1914
  throw new CompilerError("The printflush target must be a senseable value");
1625
1915
  return [null, [new InstructionBase("printflush", target)]];
@@ -1627,9 +1917,12 @@ class PrintFlush extends MacroFunction {
1627
1917
  }
1628
1918
  }
1629
1919
 
1920
+ const defaultTargetName = "display1";
1630
1921
  class DrawFlush extends MacroFunction {
1631
- constructor(scope) {
1632
- super(scope, (target) => {
1922
+ constructor() {
1923
+ super((scope, target) => {
1924
+ if (!target)
1925
+ return [null, [new InstructionBase("drawflush", defaultTargetName)]];
1633
1926
  if (!(target instanceof SenseableValue))
1634
1927
  throw new CompilerError("The drawflush target must be a senseable value");
1635
1928
  return [null, [new InstructionBase("drawflush", target)]];
@@ -1637,9 +1930,32 @@ class DrawFlush extends MacroFunction {
1637
1930
  }
1638
1931
  }
1639
1932
 
1933
+ class GetBlock extends ObjectValue {
1934
+ constructor() {
1935
+ const data = createOverloadNamespace({
1936
+ overloads: {
1937
+ floor: { args: ["x", "y"] },
1938
+ ore: { args: ["x", "y"] },
1939
+ block: { args: ["x", "y"] },
1940
+ building: { args: ["x", "y"] },
1941
+ },
1942
+ handler(scope, overload, x, y) {
1943
+ const output = overload === "building"
1944
+ ? new SenseableValue(scope)
1945
+ : new StoreValue(scope);
1946
+ return [
1947
+ output,
1948
+ [new InstructionBase("getblock", overload, output, x, y)],
1949
+ ];
1950
+ },
1951
+ });
1952
+ super(data);
1953
+ }
1954
+ }
1955
+
1640
1956
  class GetLink extends MacroFunction {
1641
- constructor(scope) {
1642
- super(scope, (index) => {
1957
+ constructor() {
1958
+ super((scope, index) => {
1643
1959
  if (!(index instanceof StoreValue) &&
1644
1960
  (!(index instanceof LiteralValue) || typeof index.data !== "number"))
1645
1961
  throw new CompilerError("The getlink index must be a number literal or a store");
@@ -1649,21 +1965,26 @@ class GetLink extends MacroFunction {
1649
1965
  }
1650
1966
  }
1651
1967
 
1652
- const validKinds$1 = ["enabled", "shoot", "shootp", "config", "color"];
1653
- class Control extends MacroFunction {
1654
- constructor(scope) {
1655
- super(scope, (kind, building, ...args) => {
1656
- if (!(kind instanceof LiteralValue) || typeof kind.data !== "string")
1657
- throw new CompilerError("The control kind must be a string literal");
1658
- if (!validKinds$1.includes(kind.data))
1659
- throw new CompilerError("Invalid control kind");
1660
- if (!(building instanceof SenseableValue))
1661
- throw new CompilerError("The building must be a senseable value");
1662
- return [
1663
- null,
1664
- [new InstructionBase("control", kind.data, building, ...args)],
1665
- ];
1666
- });
1968
+ class Control extends ObjectValue {
1969
+ constructor() {
1970
+ super(createOverloadNamespace({
1971
+ overloads: {
1972
+ enabled: { args: ["building", "value"] },
1973
+ shoot: {
1974
+ named: "options",
1975
+ args: ["building", "x", "y", "shoot"],
1976
+ },
1977
+ shootp: {
1978
+ named: "options",
1979
+ args: ["building", "unit", "shoot"],
1980
+ },
1981
+ config: { args: ["building", "value"] },
1982
+ color: { args: ["building", "r", "g", "b"] },
1983
+ },
1984
+ handler(scope, overload, ...args) {
1985
+ return [null, [new InstructionBase("control", overload, ...args)]];
1986
+ },
1987
+ }));
1667
1988
  }
1668
1989
  }
1669
1990
 
@@ -1685,29 +2006,26 @@ const validRadarSorts = [
1685
2006
  "maxHealth",
1686
2007
  ];
1687
2008
  class Radar extends MacroFunction {
1688
- constructor(scope) {
1689
- super(scope, (building, filter1, filter2, filter3, order, sort) => {
2009
+ constructor() {
2010
+ super((scope, options) => {
2011
+ assertIsObjectMacro(options, "The radar options");
2012
+ const { building, filters, order, sort } = options.data;
1690
2013
  if (!(building instanceof SenseableValue))
1691
2014
  throw new CompilerError("The building must a senseable value");
1692
- if (!(filter1 instanceof LiteralValue) ||
1693
- typeof filter1.data !== "string" ||
1694
- !(filter2 instanceof LiteralValue) ||
1695
- typeof filter2.data !== "string" ||
1696
- !(filter3 instanceof LiteralValue) ||
1697
- typeof filter3.data !== "string")
1698
- throw new CompilerError("The filters must be string literals");
1699
- if (!validRadarFilters.includes(filter1.data))
1700
- throw new CompilerError("Invalid value for filter1");
1701
- if (!validRadarFilters.includes(filter2.data))
1702
- throw new CompilerError("Invalid value for filter2");
1703
- if (!validRadarFilters.includes(filter3.data))
1704
- throw new CompilerError("Invalid value for filter3");
2015
+ assertIsArrayMacro(filters, "filters");
2016
+ const { length } = filters.data;
2017
+ if (!(length instanceof LiteralValue) || typeof length.data !== "number")
2018
+ throw new CompilerError("The length of an array macro must be");
2019
+ if (length.data !== 3)
2020
+ throw new CompilerError("The filters array must have 3 items");
2021
+ // data is not an array
2022
+ const { 0: filter1, 1: filter2, 2: filter3 } = filters.data;
2023
+ assertLiteralOneOf(filter1, validRadarFilters, "The first filter");
2024
+ assertLiteralOneOf(filter2, validRadarFilters, "The second filter");
2025
+ assertLiteralOneOf(filter3, validRadarFilters, "The third filter");
1705
2026
  if (!(order instanceof LiteralValue || order instanceof StoreValue))
1706
2027
  throw new CompilerError("The radar order must be a literal or a store");
1707
- if (!(sort instanceof LiteralValue) || typeof sort.data !== "string")
1708
- throw new CompilerError("The radar sort must be a string literal");
1709
- if (!validRadarSorts.includes(sort.data))
1710
- throw new CompilerError("Invalid sort value");
2028
+ assertLiteralOneOf(sort, validRadarSorts, "The radar sort");
1711
2029
  const outUnit = new SenseableValue(scope);
1712
2030
  return [
1713
2031
  outUnit,
@@ -1720,21 +2038,23 @@ class Radar extends MacroFunction {
1720
2038
  }
1721
2039
 
1722
2040
  class Sensor extends MacroFunction {
1723
- constructor(scope) {
1724
- super(scope, (property, target) => {
2041
+ constructor() {
2042
+ super((scope, property, target) => {
1725
2043
  if (!(property instanceof StoreValue))
1726
2044
  throw new CompilerError("The sensor property must be a store");
1727
2045
  if (!(target instanceof SenseableValue))
1728
2046
  throw new CompilerError("The sensor target must be a senseable value");
1729
- const temp = new StoreValue(scope);
2047
+ const temp = assign(new SenseableValue(scope), {
2048
+ mutability: EMutability.readonly,
2049
+ });
1730
2050
  return [temp, [new InstructionBase("sensor", temp, target, property)]];
1731
2051
  });
1732
2052
  }
1733
2053
  }
1734
2054
 
1735
2055
  class Wait extends MacroFunction {
1736
- constructor(scope) {
1737
- super(scope, seconds => {
2056
+ constructor() {
2057
+ super((scope, seconds) => {
1738
2058
  if (!(seconds instanceof StoreValue) &&
1739
2059
  !(seconds instanceof LiteralValue && typeof seconds.data === "number"))
1740
2060
  throw new CompilerError("The wait seconds must be either a number literal or a store");
@@ -1743,32 +2063,102 @@ class Wait extends MacroFunction {
1743
2063
  }
1744
2064
  }
1745
2065
 
1746
- const validKinds = ["block", "unit", "item", "liquid"];
1747
- class Lookup extends MacroFunction {
1748
- constructor(scope) {
1749
- super(scope, (kind, index) => {
1750
- if (!(kind instanceof LiteralValue && typeof kind.data === "string"))
1751
- throw new CompilerError("The lookup kind must be a string literal");
1752
- if (!validKinds.includes(kind.data))
1753
- throw new CompilerError("Invalid lookup kind");
1754
- if (!(index instanceof LiteralValue && typeof index.data === "number") &&
1755
- !(index instanceof StoreValue))
1756
- throw new CompilerError("The lookup index must be a number literal or a store");
1757
- const temp = new StoreValue(scope);
1758
- return [temp, [new InstructionBase("lookup", kind.data, temp, index)]];
2066
+ class Lookup extends ObjectValue {
2067
+ constructor() {
2068
+ const data = createOverloadNamespace({
2069
+ overloads: {
2070
+ block: { args: ["index"] },
2071
+ unit: { args: ["index"] },
2072
+ item: { args: ["index"] },
2073
+ liquid: { args: ["index"] },
2074
+ },
2075
+ handler(scope, overload, index) {
2076
+ const output = new StoreValue(scope);
2077
+ return [
2078
+ output,
2079
+ [new InstructionBase("lookup", overload, output, index)],
2080
+ ];
2081
+ },
2082
+ });
2083
+ super(data);
2084
+ }
2085
+ }
2086
+
2087
+ class PackColor extends MacroFunction {
2088
+ constructor() {
2089
+ super((scope, ...args) => {
2090
+ if (args.length !== 4) {
2091
+ throw new CompilerError(`Expected 4 arguments, received ${args.length}`);
2092
+ }
2093
+ if (!args.every((value) => value instanceof StoreValue ||
2094
+ (value instanceof LiteralValue && typeof value.data === "number"))) {
2095
+ throw new CompilerError("packColor arguments must be either stores or number literals");
2096
+ }
2097
+ const output = new StoreValue(scope);
2098
+ return [output, [new InstructionBase("packcolor", output, ...args)]];
1759
2099
  });
1760
2100
  }
1761
2101
  }
1762
2102
 
1763
2103
  class End extends MacroFunction {
1764
- constructor(scope) {
1765
- super(scope, () => [null, [new EndInstruction()]]);
2104
+ constructor() {
2105
+ super(() => [null, [new EndInstruction()]]);
2106
+ }
2107
+ }
2108
+
2109
+ class SetBlock extends ObjectValue {
2110
+ constructor() {
2111
+ const data = createOverloadNamespace({
2112
+ overloads: {
2113
+ floor: { args: ["x", "y", "to"] },
2114
+ ore: { args: ["x", "y", "to"] },
2115
+ block: {
2116
+ named: "options",
2117
+ args: ["x", "y", "to", "team", { key: "rotation", default: "0" }],
2118
+ },
2119
+ },
2120
+ handler(scope, overload, x, y, to, team, rotation) {
2121
+ return [
2122
+ null,
2123
+ [
2124
+ new InstructionBase("setblock", overload, to, x, y, team ?? "@delerict", rotation ?? "0"),
2125
+ ],
2126
+ ];
2127
+ },
2128
+ });
2129
+ super(data);
2130
+ }
2131
+ }
2132
+
2133
+ class SpawnUnit extends MacroFunction {
2134
+ constructor() {
2135
+ super((scope, options) => {
2136
+ assertIsObjectMacro(options, "The options");
2137
+ const { type, x, y, team, rotation } = options.data;
2138
+ assertIsRuntimeValue(type, "type");
2139
+ assertIsRuntimeValue(x, "x");
2140
+ assertIsRuntimeValue(y, "y");
2141
+ assertIsRuntimeValue(team, "team");
2142
+ const output = new SenseableValue(scope);
2143
+ return [
2144
+ output,
2145
+ [
2146
+ new InstructionBase("spawn", type, x, y, rotation ?? "0", team, output),
2147
+ ],
2148
+ ];
2149
+ });
2150
+ }
2151
+ }
2152
+
2153
+ class Stop extends MacroFunction {
2154
+ constructor() {
2155
+ super(() => [null, [new InstructionBase("stop")]]);
1766
2156
  }
1767
2157
  }
1768
2158
 
1769
2159
  class UnitBind extends MacroFunction {
1770
- constructor(scope) {
1771
- super(scope, type => {
2160
+ constructor() {
2161
+ super((scope, type) => {
1772
2162
  if (!(type instanceof StoreValue))
1773
2163
  throw new CompilerError("The unitBind type must be a store");
1774
2164
  return [null, [new InstructionBase("ubind", type)]];
@@ -1776,82 +2166,84 @@ class UnitBind extends MacroFunction {
1776
2166
  }
1777
2167
  }
1778
2168
 
1779
- const validModes = [
1780
- "idle",
1781
- "stop",
1782
- "move",
1783
- "approach",
1784
- "boost",
1785
- "pathfind",
1786
- "target",
1787
- "targetp",
1788
- "itemDrop",
1789
- "itemTake",
1790
- "payDrop",
1791
- "payTake",
1792
- "payEnter",
1793
- "mine",
1794
- "flag",
1795
- "build",
1796
- "getBlock",
1797
- "within",
1798
- ];
1799
- class UnitControl extends MacroFunction {
1800
- constructor(scope) {
1801
- super(scope, (mode, ...args) => {
1802
- if (!(mode instanceof LiteralValue) || typeof mode.data !== "string")
1803
- throw new CompilerError("The unitControl mode must be a string literal");
1804
- if (!validModes.includes(mode.data))
1805
- throw new CompilerError("Invalid unitControl mode");
1806
- if (args.some(value => !(value instanceof StoreValue || value instanceof LiteralValue)))
1807
- throw new CompilerError("The others arguments of unitControl must be literals or stores");
1808
- let result = null;
1809
- let extraArgs = [];
1810
- switch (mode.data) {
1811
- case "getBlock": {
1812
- const outType = new StoreValue(scope);
1813
- const outBuilding = new SenseableValue(scope);
1814
- result = ObjectValue.fromArray(scope, [outType, outBuilding]);
1815
- extraArgs = [outType, outBuilding, new LiteralValue(scope, 0)];
1816
- break;
1817
- }
1818
- case "within": {
1819
- const temp = new StoreValue(scope);
1820
- result = temp;
1821
- extraArgs = [temp, new LiteralValue(scope, 0)];
1822
- break;
2169
+ class UnitControl extends ObjectValue {
2170
+ constructor() {
2171
+ const data = createOverloadNamespace({
2172
+ overloads: {
2173
+ idle: { args: [] },
2174
+ stop: { args: [] },
2175
+ move: { args: ["x", "y"] },
2176
+ approach: { named: "options", args: ["x", "y", "radius"] },
2177
+ boost: { args: ["enable"] },
2178
+ pathfind: { args: [] },
2179
+ target: { named: "options", args: ["x", "y", "shoot"] },
2180
+ targetp: { named: "options", args: ["unit", "shoot"] },
2181
+ itemDrop: { args: ["target", "amount"] },
2182
+ itemTake: { args: ["target", "item", "amount"] },
2183
+ payDrop: { args: [] },
2184
+ payTake: { named: "options", args: ["takeUnits"] },
2185
+ payEnter: { args: [] },
2186
+ mine: { args: ["x", "y"] },
2187
+ flag: { args: ["value"] },
2188
+ build: {
2189
+ named: "options",
2190
+ args: ["x", "y", "block", "rotation", { key: "config", default: "" }],
2191
+ },
2192
+ getBlock: {
2193
+ args: ["x", "y"],
2194
+ },
2195
+ within: {
2196
+ named: "options",
2197
+ args: ["x", "y", "radius"],
2198
+ },
2199
+ },
2200
+ handler(scope, overload, ...args) {
2201
+ let result = null;
2202
+ let extraArgs = [];
2203
+ switch (overload) {
2204
+ case "getBlock": {
2205
+ const outType = new StoreValue(scope);
2206
+ const outBuilding = new SenseableValue(scope);
2207
+ result = ObjectValue.fromArray([outType, outBuilding]);
2208
+ extraArgs = [outType, outBuilding, new LiteralValue(0)];
2209
+ break;
2210
+ }
2211
+ case "within": {
2212
+ const temp = new StoreValue(scope);
2213
+ result = temp;
2214
+ extraArgs = [temp, new LiteralValue(0)];
2215
+ break;
2216
+ }
1823
2217
  }
1824
- }
1825
- return [
1826
- result,
1827
- [new InstructionBase("ucontrol", mode.data, ...args, ...extraArgs)],
1828
- ];
2218
+ return [
2219
+ result,
2220
+ [new InstructionBase("ucontrol", overload, ...args, ...extraArgs)],
2221
+ ];
2222
+ },
1829
2223
  });
2224
+ super(data);
1830
2225
  }
1831
2226
  }
1832
2227
 
1833
2228
  class UnitRadar extends MacroFunction {
1834
- constructor(scope) {
1835
- super(scope, (filter1, filter2, filter3, order, sort) => {
1836
- if (!(filter1 instanceof LiteralValue) ||
1837
- typeof filter1.data !== "string" ||
1838
- !(filter2 instanceof LiteralValue) ||
1839
- typeof filter2.data !== "string" ||
1840
- !(filter3 instanceof LiteralValue) ||
1841
- typeof filter3.data !== "string")
1842
- throw new CompilerError("The filters must be string literals");
1843
- if (!validRadarFilters.includes(filter1.data))
1844
- throw new CompilerError("Invalid value for filter1");
1845
- if (!validRadarFilters.includes(filter2.data))
1846
- throw new CompilerError("Invalid value for filter2");
1847
- if (!validRadarFilters.includes(filter3.data))
1848
- throw new CompilerError("Invalid value for filter3");
2229
+ constructor() {
2230
+ super((scope, options) => {
2231
+ assertIsObjectMacro(options, "The radar options");
2232
+ const { filters, order, sort } = options.data;
2233
+ assertIsArrayMacro(filters, "filters");
2234
+ const { length } = filters.data;
2235
+ if (!(length instanceof LiteralValue) || typeof length.data !== "number")
2236
+ throw new CompilerError("The length of an array macro must be");
2237
+ if (length.data !== 3)
2238
+ throw new CompilerError("The filters array must have 3 items");
2239
+ // data is not an array
2240
+ const { 0: filter1, 1: filter2, 2: filter3 } = filters.data;
2241
+ assertLiteralOneOf(filter1, validRadarFilters, "The first filter");
2242
+ assertLiteralOneOf(filter2, validRadarFilters, "The second filter");
2243
+ assertLiteralOneOf(filter3, validRadarFilters, "The third filter");
1849
2244
  if (!(order instanceof LiteralValue || order instanceof StoreValue))
1850
2245
  throw new CompilerError("The radar order must be a literal or a store");
1851
- if (!(sort instanceof LiteralValue) || typeof sort.data !== "string")
1852
- throw new CompilerError("The radar sort must be a string literal");
1853
- if (!validRadarSorts.includes(sort.data))
1854
- throw new CompilerError("Invalid sort value");
2246
+ assertLiteralOneOf(sort, validRadarSorts, "The radar sort");
1855
2247
  const outUnit = new SenseableValue(scope);
1856
2248
  return [
1857
2249
  outUnit,
@@ -1864,7 +2256,6 @@ class UnitRadar extends MacroFunction {
1864
2256
  }
1865
2257
  }
1866
2258
 
1867
- const validFinds = ["ore", "building", "spawn", "damaged"];
1868
2259
  const validBuildingGroups = [
1869
2260
  "core",
1870
2261
  "storage",
@@ -1876,86 +2267,333 @@ const validBuildingGroups = [
1876
2267
  "battery",
1877
2268
  "reactor",
1878
2269
  ];
1879
- class UnitLocate extends MacroFunction {
1880
- constructor(scope) {
1881
- super(scope, (find, ...args) => {
1882
- if (!(find instanceof LiteralValue && typeof find.data === "string"))
1883
- throw new CompilerError("The unitLocate find must be a string literal");
1884
- if (!validFinds.includes(find.data))
1885
- throw new CompilerError("Invalid find value");
1886
- if (args.some(value => !(value instanceof StoreValue || value instanceof LiteralValue)))
1887
- throw new CompilerError("The others arguments of unitLocate must be literals or stores");
1888
- const outFound = new StoreValue(scope);
1889
- const outX = new StoreValue(scope);
1890
- const outY = new StoreValue(scope);
1891
- const outBuilding = new SenseableValue(scope);
1892
- const outArgs = [outX, outY, outFound, outBuilding];
1893
- let inputArgs = [];
1894
- switch (find.data) {
1895
- case "ore": {
1896
- const [ore] = args;
1897
- inputArgs = [find.data, "core", "true", ore];
1898
- break;
1899
- }
1900
- case "building": {
1901
- const [group, enemy] = args;
1902
- if (!(group instanceof LiteralValue && typeof group.data === "string")) {
1903
- throw new CompilerError("The building group must be a string literal");
2270
+ class UnitLocate extends ObjectValue {
2271
+ constructor() {
2272
+ const data = createOverloadNamespace({
2273
+ overloads: {
2274
+ ore: {
2275
+ args: ["ore"],
2276
+ },
2277
+ building: { named: "options", args: ["group", "enemy"] },
2278
+ spawn: {
2279
+ args: [],
2280
+ },
2281
+ damaged: {
2282
+ args: [],
2283
+ },
2284
+ },
2285
+ handler(scope, overload, ...args) {
2286
+ const outFound = new StoreValue(scope);
2287
+ const outX = new StoreValue(scope);
2288
+ const outY = new StoreValue(scope);
2289
+ const outBuilding = new SenseableValue(scope);
2290
+ const outArgs = [outX, outY, outFound, outBuilding];
2291
+ let inputArgs = [];
2292
+ switch (overload) {
2293
+ case "ore": {
2294
+ const [ore] = args;
2295
+ inputArgs = [overload, "core", "true", ore];
2296
+ break;
2297
+ }
2298
+ case "building": {
2299
+ const [group, enemy] = args;
2300
+ if (!(group instanceof LiteralValue))
2301
+ throw new CompilerError("The building group must be a string literal");
2302
+ assertLiteralOneOf(group, validBuildingGroups, "The building group");
2303
+ inputArgs = [overload, group.data, enemy, "@copper"];
2304
+ break;
2305
+ }
2306
+ case "spawn":
2307
+ case "damaged": {
2308
+ inputArgs = [overload, "core", "true", "@copper"];
2309
+ break;
1904
2310
  }
1905
- if (!validBuildingGroups.includes(group.data))
1906
- throw new CompilerError("Invalid building group");
1907
- inputArgs = [find.data, group.data, enemy, "@copper"];
1908
- break;
1909
- }
1910
- case "spawn":
1911
- case "damaged": {
1912
- inputArgs = [find.data, "core", "true", "@copper"];
1913
- break;
1914
2311
  }
1915
- }
1916
- return [
1917
- ObjectValue.fromArray(scope, [
1918
- outFound,
1919
- outX,
1920
- outY,
1921
- ...(find.data !== "ore" ? [outBuilding] : []),
1922
- ]),
1923
- [new InstructionBase("ulocate", ...inputArgs, ...outArgs)],
1924
- ];
2312
+ return [
2313
+ ObjectValue.fromArray([
2314
+ outFound,
2315
+ outX,
2316
+ outY,
2317
+ ...(overload !== "ore" ? [outBuilding] : []),
2318
+ ]),
2319
+ [new InstructionBase("ulocate", ...inputArgs, ...outArgs)],
2320
+ ];
2321
+ },
1925
2322
  });
2323
+ super(data);
1926
2324
  }
1927
2325
  }
1928
2326
 
1929
- class MemoryEntry extends ObjectValue {
1930
- constructor(scope, mem, prop) {
1931
- super(scope, {
1932
- $eval: new MacroFunction(scope, () => {
1933
- if (this.store)
1934
- return [this.store, []];
1935
- const temp = new StoreValue(scope);
1936
- return [temp, [new InstructionBase("read", temp, mem.cell, prop)]];
1937
- }),
1938
- $consume: new MacroFunction(scope, () => {
1939
- if (this.store)
1940
- return [this.store, []];
1941
- this.ensureOwned();
1942
- this.store = new StoreValue(scope);
1943
- this.owner.own(this.store);
2327
+ const validEffects = [
2328
+ "burning",
2329
+ "freezing",
2330
+ "unmoving",
2331
+ "wet",
2332
+ "melting",
2333
+ "sapped",
2334
+ "electrified",
2335
+ "spore-slowed",
2336
+ "tarred",
2337
+ "overdrive",
2338
+ "overclock",
2339
+ "boss",
2340
+ "shocked",
2341
+ "blasted",
2342
+ ];
2343
+ class ApplyStatus extends ObjectValue {
2344
+ constructor() {
2345
+ const data = createOverloadNamespace({
2346
+ overloads: {
2347
+ apply: {
2348
+ args: ["status", "unit", { key: "duration", default: "10" }],
2349
+ },
2350
+ clear: { args: ["status", "unit"] },
2351
+ },
2352
+ handler(scope, overload, effect, unit, duration) {
2353
+ if (!(effect instanceof LiteralValue))
2354
+ throw new CompilerError("The status effect must be a string literal");
2355
+ assertLiteralOneOf(effect, validEffects, "The status effect");
1944
2356
  return [
1945
- this.store,
1946
- [new InstructionBase("read", this.store, mem.cell, prop)],
2357
+ null,
2358
+ [
2359
+ new InstructionBase("status", String(overload !== "apply"), effect.data, unit, duration),
2360
+ ],
1947
2361
  ];
1948
- }),
1949
- "$=": new MacroFunction(scope, value => {
1950
- const [data, dataInst] = value.consume(scope);
2362
+ },
2363
+ });
2364
+ super(data);
2365
+ }
2366
+ }
2367
+
2368
+ class SpawnWave extends MacroFunction {
2369
+ constructor() {
2370
+ super((scope, natural, x, y) => {
2371
+ if (!(natural instanceof LiteralValue) ||
2372
+ (natural.data !== 1 && natural.data !== 0))
2373
+ throw new CompilerError("The 'natural' argument must be a boolean literal");
2374
+ return [
2375
+ null,
2376
+ [
2377
+ new InstructionBase("spawnwave", x ?? "10", y ?? "10", String(!!natural.data)),
2378
+ ],
2379
+ ];
2380
+ });
2381
+ }
2382
+ }
2383
+
2384
+ class SetRule extends ObjectValue {
2385
+ constructor() {
2386
+ const data = createOverloadNamespace({
2387
+ overloads: {
2388
+ currentWaveTime: { args: ["seconds"] },
2389
+ waveTimer: { args: ["enabled"] },
2390
+ waves: { args: ["enabled"] },
2391
+ wave: { args: ["number"] },
2392
+ waveSpacing: { args: ["seconds"] },
2393
+ waveSending: { args: ["enabled"] },
2394
+ attackMode: { args: ["enabled"] },
2395
+ enemyCoreBuildRadius: { args: ["radius"] },
2396
+ dropZoneRadius: { args: ["radius"] },
2397
+ unitCap: { args: ["cap"] },
2398
+ mapArea: { named: "options", args: ["x", "y", "width", "height"] },
2399
+ lighting: { args: ["enabled"] },
2400
+ ambientLight: { args: ["rgbaData"] },
2401
+ solarMultiplier: { args: ["multiplier"] },
2402
+ buildSpeed: { args: ["team", "multiplier"] },
2403
+ unitBuildSpeed: { args: ["team", "multiplier"] },
2404
+ unitDamage: { args: ["team", "multiplier"] },
2405
+ blockHealth: { args: ["team", "multiplier"] },
2406
+ blockDamage: { args: ["team", "multiplier"] },
2407
+ rtsMinWeight: { args: ["team", "value"] },
2408
+ rtsMinSquad: { args: ["team", "value"] },
2409
+ },
2410
+ handler(scope, overload, ...args) {
2411
+ const params = ["10", "0", "0", "100", "100"];
2412
+ switch (overload) {
2413
+ case "mapArea": {
2414
+ const [x, y, width, height] = args;
2415
+ params[1] = x;
2416
+ params[2] = y;
2417
+ params[3] = width;
2418
+ params[4] = height;
2419
+ break;
2420
+ }
2421
+ case "buildSpeed":
2422
+ case "unitBuildSpeed":
2423
+ case "unitDamage":
2424
+ case "blockHealth":
2425
+ case "blockDamage":
2426
+ case "rtsMinWeight":
2427
+ case "rtsMinSquad": {
2428
+ const [team, value] = args;
2429
+ params[1] = team;
2430
+ params[2] = value;
2431
+ break;
2432
+ }
2433
+ default:
2434
+ params[0] = args[0]; // the general value
2435
+ }
2436
+ return [null, [new InstructionBase("setrule", overload, ...params)]];
2437
+ },
2438
+ });
2439
+ super(data);
2440
+ }
2441
+ }
2442
+
2443
+ class FlushMessage extends ObjectValue {
2444
+ constructor() {
2445
+ const data = createOverloadNamespace({
2446
+ overloads: {
2447
+ notify: { args: [] },
2448
+ mission: { args: [] },
2449
+ announce: { args: ["duration"] },
2450
+ toast: { args: ["duration"] },
2451
+ },
2452
+ handler(scope, overload, duration) {
2453
+ return [null, [new InstructionBase("message", overload, duration)]];
2454
+ },
2455
+ });
2456
+ super(data);
2457
+ }
2458
+ }
2459
+
2460
+ class Cutscene extends ObjectValue {
2461
+ constructor() {
2462
+ const data = createOverloadNamespace({
2463
+ overloads: {
2464
+ pan: { named: "options", args: ["x", "y", "speed"] },
2465
+ zoom: { args: ["level"] },
2466
+ stop: { args: [] },
2467
+ },
2468
+ handler(scope, overload, ...args) {
2469
+ const params = Object.assign(["100", "100", "0.06", "0"], args);
2470
+ return [null, [new InstructionBase("cutscene", overload, ...params)]];
2471
+ },
2472
+ });
2473
+ super(data);
2474
+ }
2475
+ }
2476
+
2477
+ class Explosion extends MacroFunction {
2478
+ constructor() {
2479
+ super((scope, options) => {
2480
+ assertIsObjectMacro(options, "The options");
2481
+ const params = assertObjectFields(options, [
2482
+ "team",
2483
+ "x",
2484
+ "y",
2485
+ "radius",
2486
+ "damage",
2487
+ "air",
2488
+ "ground",
2489
+ "pierce",
2490
+ ]);
2491
+ return [null, [new InstructionBase("explosion", ...params)]];
2492
+ });
2493
+ }
2494
+ }
2495
+
2496
+ class SetRate extends MacroFunction {
2497
+ constructor() {
2498
+ super((scope, ipt) => [null, [new InstructionBase("setrate", ipt)]]);
2499
+ }
2500
+ }
2501
+
2502
+ class Fetch extends ObjectValue {
2503
+ constructor() {
2504
+ const data = createOverloadNamespace({
2505
+ overloads: {
2506
+ unit: { args: ["team", "index"] },
2507
+ unitCount: { args: ["team"] },
2508
+ player: { args: ["team", "index"] },
2509
+ playerCount: { args: ["team"] },
2510
+ core: { args: ["team", "index"] },
2511
+ coreCount: { args: ["team"] },
2512
+ build: { args: ["team", "index", "block"] },
2513
+ buildCount: { args: ["team", "block"] },
2514
+ },
2515
+ handler(scope, overload, team, ...rest) {
2516
+ const output = new SenseableValue(scope);
2517
+ const params = ["0", "@conveyor"];
2518
+ if (overload === "buildCount") {
2519
+ params[1] = rest[0];
2520
+ }
2521
+ else {
2522
+ Object.assign(params, rest);
2523
+ }
1951
2524
  return [
1952
- data,
1953
- [...dataInst, new InstructionBase("write", data, mem.cell, prop)],
2525
+ output,
2526
+ [new InstructionBase("fetch", overload, output, team, ...params)],
1954
2527
  ];
1955
- }),
2528
+ },
1956
2529
  });
2530
+ super(data);
2531
+ }
2532
+ }
2533
+
2534
+ class GetFlag extends MacroFunction {
2535
+ constructor() {
2536
+ super((scope, flag) => {
2537
+ const result = new StoreValue(scope);
2538
+ return [result, [new InstructionBase("getflag", result, flag)]];
2539
+ });
2540
+ }
2541
+ }
2542
+
2543
+ class SetFlag extends MacroFunction {
2544
+ constructor() {
2545
+ super((scope, flag, value) => {
2546
+ if (!flag)
2547
+ throw new CompilerError("Missing flag argument");
2548
+ if (!value)
2549
+ throw new CompilerError("Missing flag value");
2550
+ return [null, [new InstructionBase("setflag", flag, value)]];
2551
+ });
2552
+ }
2553
+ }
2554
+
2555
+ class MemoryEntry extends BaseValue {
2556
+ constructor(scope, mem, prop) {
2557
+ super();
2558
+ this.scope = scope;
2559
+ this.mem = mem;
2560
+ this.prop = prop;
2561
+ this.macro = true;
1957
2562
  this.store = null;
1958
2563
  }
2564
+ eval(scope) {
2565
+ if (this.store)
2566
+ return [this.store, []];
2567
+ const temp = new StoreValue(scope);
2568
+ return [
2569
+ temp,
2570
+ [new InstructionBase("read", temp, this.mem.cell, this.prop)],
2571
+ ];
2572
+ }
2573
+ consume(scope) {
2574
+ if (this.store)
2575
+ return [this.store, []];
2576
+ this.ensureOwned();
2577
+ this.store = new StoreValue(scope);
2578
+ this.owner.own(this.store);
2579
+ return [
2580
+ this.store,
2581
+ [new InstructionBase("read", this.store, this.mem.cell, this.prop)],
2582
+ ];
2583
+ }
2584
+ "="(scope, value) {
2585
+ const [data, dataInst] = value.consume(scope);
2586
+ return [
2587
+ data,
2588
+ [
2589
+ ...dataInst,
2590
+ new InstructionBase("write", data, this.mem.cell, this.prop),
2591
+ ],
2592
+ ];
2593
+ }
2594
+ ensureOwned() {
2595
+ this.owner ??= new ValueOwner({ scope: this.scope, value: this });
2596
+ }
1959
2597
  }
1960
2598
  for (const operator of operators) {
1961
2599
  if (operator === "=")
@@ -1966,9 +2604,9 @@ for (const operator of operators) {
1966
2604
  };
1967
2605
  }
1968
2606
  class MemoryMacro extends ObjectValue {
1969
- constructor(scope, cell, size) {
1970
- super(scope, {
1971
- $get: new MacroFunction(scope, (prop) => {
2607
+ constructor(cell, size) {
2608
+ super({
2609
+ $get: new MacroFunction((scope, prop) => {
1972
2610
  if (prop instanceof LiteralValue && typeof prop.data !== "number")
1973
2611
  throw new CompilerError(`Invalid memory object property: "${prop.data}"`);
1974
2612
  const obj = new MemoryEntry(scope, this, prop);
@@ -1978,21 +2616,20 @@ class MemoryMacro extends ObjectValue {
1978
2616
  size,
1979
2617
  });
1980
2618
  this.cell = cell;
1981
- this.name = cell.toString();
1982
2619
  }
1983
2620
  toString() {
1984
- return this.name;
2621
+ return this.cell.toString();
1985
2622
  }
1986
2623
  }
1987
2624
  class MemoryBuilder extends ObjectValue {
1988
- constructor(scope) {
1989
- super(scope, {
1990
- $call: new MacroFunction(scope, (cell, size = new LiteralValue(scope, 64)) => {
2625
+ constructor() {
2626
+ super({
2627
+ $call: new MacroFunction((scope, cell, size = new LiteralValue(64)) => {
1991
2628
  if (!(cell instanceof SenseableValue))
1992
2629
  throw new CompilerError("Memory cell must be a senseable value.");
1993
2630
  if (!(size instanceof LiteralValue && typeof size.data === "number"))
1994
2631
  throw new CompilerError("The memory size must be a number literal.");
1995
- return [new MemoryMacro(scope, cell, size), []];
2632
+ return [new MemoryMacro(cell, size), []];
1996
2633
  }),
1997
2634
  });
1998
2635
  }
@@ -2000,9 +2637,9 @@ class MemoryBuilder extends ObjectValue {
2000
2637
 
2001
2638
  const dynamicVars = ["time", "tick"];
2002
2639
  class NamespaceMacro extends ObjectValue {
2003
- constructor(scope, { changeCasing = false } = {}) {
2004
- super(scope, {
2005
- $get: new MacroFunction(scope, prop => {
2640
+ constructor({ changeCasing = false } = {}) {
2641
+ super({
2642
+ $get: new MacroFunction((scope, prop) => {
2006
2643
  if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
2007
2644
  throw new CompilerError("Cannot use dynamic properties on namespace macros");
2008
2645
  const symbolName = this.changeCasing
@@ -2026,7 +2663,7 @@ class NamespaceMacro extends ObjectValue {
2026
2663
  }
2027
2664
  class VarsNamespace extends NamespaceMacro {
2028
2665
  constructor(scope) {
2029
- super(scope);
2666
+ super();
2030
2667
  Object.assign(this.data, {
2031
2668
  unit: new ValueOwner({
2032
2669
  scope,
@@ -2040,29 +2677,11 @@ class VarsNamespace extends NamespaceMacro {
2040
2677
  }).value,
2041
2678
  });
2042
2679
  }
2043
- }
2044
- class UCommandsNamespace extends NamespaceMacro {
2045
- constructor(scope) {
2046
- super(scope);
2047
- this.data.$get = new MacroFunction(scope, prop => {
2048
- if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
2049
- throw new CompilerError("Cannot use dynamic properties on namespace macros");
2050
- const symbolName = prop.data[0].toUpperCase() + prop.data.slice(1);
2051
- const owner = new ValueOwner({
2052
- scope,
2053
- name: `@command${symbolName}`,
2054
- value: assign(new StoreValue(scope), {
2055
- mutability: EMutability.constant,
2056
- }),
2057
- });
2058
- return [owner.value, []];
2059
- });
2060
- }
2061
2680
  }
2062
2681
 
2063
2682
  class GetGlobal extends MacroFunction {
2064
- constructor(scope, mutability) {
2065
- super(scope, (name) => {
2683
+ constructor(mutability) {
2684
+ super((scope, name) => {
2066
2685
  if (!(name instanceof LiteralValue) || typeof name.data !== "string")
2067
2686
  throw new CompilerError("The name parameter must be a string literal.");
2068
2687
  const owner = new ValueOwner({
@@ -2077,66 +2696,163 @@ class GetGlobal extends MacroFunction {
2077
2696
  }
2078
2697
  }
2079
2698
 
2699
+ class Asm extends MacroFunction {
2700
+ constructor() {
2701
+ super((scope, stringsArray, ...values) => {
2702
+ if (!isTemplateObjectArray(stringsArray))
2703
+ throw new CompilerError("Expected to receive a template strings array");
2704
+ const args = [];
2705
+ for (let i = 0; i < values.length; i++) {
2706
+ const [item] = stringsArray.get(scope, new LiteralValue(i));
2707
+ args.push(item.data);
2708
+ args.push(values[i]);
2709
+ }
2710
+ const { length } = stringsArray.data;
2711
+ const [tail] = stringsArray.get(scope, new LiteralValue(length.data - 1));
2712
+ args.push(tail.data);
2713
+ return [null, formatInstructions(args)];
2714
+ });
2715
+ }
2716
+ }
2717
+ /** Splits multiline asm calls and formats each line. */
2718
+ function formatInstructions(args) {
2719
+ const instructions = [];
2720
+ let buffer = [];
2721
+ for (let i = 0; i < args.length; i++) {
2722
+ const arg = args[i];
2723
+ if (typeof arg !== "string" || !arg.includes("\n")) {
2724
+ buffer.push(arg);
2725
+ continue;
2726
+ }
2727
+ const segments = arg.split("\n");
2728
+ const params = [...buffer, segments[0]];
2729
+ if (validateInstructionArgs(params)) {
2730
+ instructions.push(new ZeroSpaceInstruction(...params));
2731
+ buffer = [];
2732
+ }
2733
+ // iterates over all segments except the first and last
2734
+ // the first segment was already processed above
2735
+ // the last segment will be added to the buffer because there might
2736
+ // be an interpolation after it
2737
+ // and putting it in the buffer makes sure it has a proper output format
2738
+ for (let i = 1; i < segments.length - 1; i++) {
2739
+ const trimmed = segments[i].trim();
2740
+ if (trimmed.length == 0)
2741
+ continue;
2742
+ instructions.push(new ZeroSpaceInstruction(trimmed));
2743
+ }
2744
+ if (segments.length > 1) {
2745
+ buffer.push(segments[segments.length - 1]);
2746
+ }
2747
+ }
2748
+ if (buffer.length > 0 && validateInstructionArgs(buffer)) {
2749
+ instructions.push(new ZeroSpaceInstruction(...buffer));
2750
+ }
2751
+ return instructions;
2752
+ }
2753
+ /** Determines if an asm line should be generated and trims it at the start and end */
2754
+ function validateInstructionArgs(args) {
2755
+ if (args.length === 0)
2756
+ return false;
2757
+ if (args.length === 1) {
2758
+ const item = args[0];
2759
+ if (typeof item !== "string")
2760
+ return true;
2761
+ args[0] = item.trim();
2762
+ return args[0].length !== 0;
2763
+ }
2764
+ const first = args[0];
2765
+ const last = args[args.length - 1];
2766
+ if (typeof first === "string")
2767
+ args[0] = first.trimStart();
2768
+ if (typeof last === "string")
2769
+ args[args.length - 1] = last.trimEnd();
2770
+ return true;
2771
+ }
2772
+
2080
2773
  /**
2081
2774
  * Adds all the compiler globals to `scope`
2082
2775
  */
2083
2776
  function initScope(scope) {
2084
2777
  // namespaces
2085
- scope.hardSet("ControlKind", new NamespaceMacro(scope));
2778
+ scope.hardSet("ControlKind", new NamespaceMacro());
2086
2779
  scope.hardSet("Vars", new VarsNamespace(scope));
2087
- scope.hardSet("Items", new NamespaceMacro(scope, { changeCasing: true }));
2088
- scope.hardSet("Liquids", new NamespaceMacro(scope));
2089
- scope.hardSet("Units", new NamespaceMacro(scope));
2090
- scope.hardSet("LAccess", new NamespaceMacro(scope));
2091
- scope.hardSet("UnitCommands", new UCommandsNamespace(scope));
2092
- scope.hardSet("Blocks", new NamespaceMacro(scope, { changeCasing: true }));
2780
+ scope.hardSet("Teams", new NamespaceMacro());
2781
+ scope.hardSet("Items", new NamespaceMacro({ changeCasing: true }));
2782
+ scope.hardSet("Liquids", new NamespaceMacro());
2783
+ scope.hardSet("Units", new NamespaceMacro({ changeCasing: true }));
2784
+ scope.hardSet("LAccess", new NamespaceMacro());
2785
+ scope.hardSet("Blocks", new NamespaceMacro({ changeCasing: true }));
2093
2786
  // helper methods
2094
- scope.hardSet("getBuilding", new GetGlobal(scope, EMutability.constant));
2095
- scope.hardSet("getVar", new GetGlobal(scope, EMutability.mutable));
2096
- scope.hardSet("concat", new Concat(scope));
2097
- scope.hardSet("Math", new MlogMath(scope));
2098
- scope.hardSet("Memory", new MemoryBuilder(scope));
2787
+ scope.hardSet("getBuilding", new GetGlobal(EMutability.constant));
2788
+ scope.hardSet("getVar", new GetGlobal(EMutability.mutable));
2789
+ scope.hardSet("concat", new Concat());
2790
+ scope.hardSet("asm", new Asm());
2791
+ scope.hardSet("Math", new MlogMath());
2792
+ scope.hardSet("Memory", new MemoryBuilder());
2099
2793
  // commands
2100
- scope.hardSet("draw", new Draw(scope));
2101
- scope.hardSet("print", new Print(scope));
2102
- scope.hardSet("printFlush", new PrintFlush(scope));
2103
- scope.hardSet("drawFlush", new DrawFlush(scope));
2104
- scope.hardSet("getLink", new GetLink(scope));
2105
- scope.hardSet("control", new Control(scope));
2106
- scope.hardSet("radar", new Radar(scope));
2107
- scope.hardSet("sensor", new Sensor(scope));
2108
- scope.hardSet("wait", new Wait(scope));
2109
- scope.hardSet("lookup", new Lookup(scope));
2110
- scope.hardSet("endScript", new End(scope));
2111
- scope.hardSet("unitBind", new UnitBind(scope));
2112
- scope.hardSet("unitControl", new UnitControl(scope));
2113
- scope.hardSet("unitRadar", new UnitRadar(scope));
2114
- scope.hardSet("unitLocate", new UnitLocate(scope));
2794
+ scope.hardSet("draw", new Draw());
2795
+ scope.hardSet("print", new Print());
2796
+ scope.hardSet("printFlush", new PrintFlush());
2797
+ scope.hardSet("drawFlush", new DrawFlush());
2798
+ scope.hardSet("getLink", new GetLink());
2799
+ scope.hardSet("control", new Control());
2800
+ scope.hardSet("radar", new Radar());
2801
+ scope.hardSet("sensor", new Sensor());
2802
+ scope.hardSet("wait", new Wait());
2803
+ scope.hardSet("lookup", new Lookup());
2804
+ scope.hardSet("packColor", new PackColor());
2805
+ scope.hardSet("endScript", new End());
2806
+ scope.hardSet("stopScript", new Stop());
2807
+ scope.hardSet("unitBind", new UnitBind());
2808
+ scope.hardSet("unitControl", new UnitControl());
2809
+ scope.hardSet("unitRadar", new UnitRadar());
2810
+ scope.hardSet("unitLocate", new UnitLocate());
2811
+ // world processor commands
2812
+ scope.hardSet("getBlock", new GetBlock());
2813
+ scope.hardSet("setBlock", new SetBlock());
2814
+ scope.hardSet("spawnUnit", new SpawnUnit());
2815
+ scope.hardSet("applyStatus", new ApplyStatus());
2816
+ scope.hardSet("spawnWave", new SpawnWave());
2817
+ scope.hardSet("setRule", new SetRule());
2818
+ scope.hardSet("flushMessage", new FlushMessage());
2819
+ scope.hardSet("cutscene", new Cutscene());
2820
+ scope.hardSet("explosion", new Explosion());
2821
+ scope.hardSet("setRate", new SetRate());
2822
+ scope.hardSet("fetch", new Fetch());
2823
+ scope.hardSet("getFlag", new GetFlag());
2824
+ scope.hardSet("setFlag", new SetFlag());
2115
2825
  }
2116
2826
 
2117
2827
  class Compiler {
2118
- constructor({ stackName, compactNames = false } = {}) {
2828
+ constructor({ stackName, compactNames = false, sourcemap = false, } = {}) {
2119
2829
  this.handlers = handlers;
2120
2830
  this.usingStack = !!stackName;
2121
2831
  this.stackName = stackName;
2122
2832
  this.compactNames = compactNames;
2833
+ this.sourcemap = sourcemap;
2123
2834
  }
2124
2835
  compile(script) {
2125
2836
  let output;
2837
+ let sourcemaps;
2126
2838
  try {
2127
2839
  const program = this.parse(script);
2128
2840
  const scope = new Scope({});
2129
2841
  initScope(scope);
2130
2842
  const valueInst = this.handle(scope, program);
2131
2843
  valueInst[1].push(new EndInstruction(), ...scope.inst);
2844
+ hideRedundantJumps(valueInst[1]);
2132
2845
  this.resolve(valueInst);
2133
2846
  output = this.serialize(valueInst) + "\n";
2847
+ if (this.sourcemap) {
2848
+ sourcemaps = this.mapSources(valueInst);
2849
+ }
2134
2850
  }
2135
2851
  catch (error) {
2136
- const nodeStack = error instanceof CompilerError ? error.nodeStack : [];
2137
- return [null, error, nodeStack];
2852
+ const err = error instanceof CompilerError ? error : CompilerError.from(error);
2853
+ return [null, err];
2138
2854
  }
2139
- return [output, null, []];
2855
+ return [output, null, sourcemaps];
2140
2856
  }
2141
2857
  resolve(valueInst) {
2142
2858
  let i = 0;
@@ -2156,40 +2872,92 @@ class Compiler {
2156
2872
  plugins: ["typescript"],
2157
2873
  });
2158
2874
  }
2159
- handle(scope, node) {
2875
+ mapSources(valueInst) {
2876
+ const result = [];
2877
+ for (const inst of valueInst[1]) {
2878
+ if (!inst.hidden)
2879
+ result.push(inst.source);
2880
+ }
2881
+ return result;
2882
+ }
2883
+ handle(scope, node, handler = this.handlers[node.type]) {
2160
2884
  try {
2161
- const handler = this.handlers[node.type];
2162
2885
  if (!handler)
2163
2886
  throw new CompilerError("Missing handler for " + node.type);
2164
- return handler(this, scope, node, null);
2887
+ const result = handler(this, scope, node, null);
2888
+ if (this.sourcemap)
2889
+ return appendSourceLocations(result, node);
2890
+ return result;
2165
2891
  }
2166
2892
  catch (error) {
2167
2893
  if (error instanceof CompilerError) {
2168
- error.nodeStack.push(node);
2894
+ error.loc ??= node.loc;
2169
2895
  }
2170
2896
  throw error;
2171
2897
  }
2172
2898
  }
2173
2899
  handleEval(scope, node) {
2174
2900
  const [res, inst] = this.handle(scope, node);
2175
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2901
+ if (!res)
2902
+ throw new CompilerError("Cannot eval null", node);
2176
2903
  const [evaluated, evaluatedInst] = res.eval(scope);
2177
- return [evaluated, [...inst, ...evaluatedInst]];
2904
+ const result = [evaluated, [...inst, ...evaluatedInst]];
2905
+ if (this.sourcemap)
2906
+ return appendSourceLocations(result, node);
2907
+ return result;
2178
2908
  }
2179
2909
  handleConsume(scope, node) {
2180
2910
  const [res, inst] = this.handle(scope, node);
2181
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2911
+ if (!res)
2912
+ throw new CompilerError("Cannot consume null", node);
2182
2913
  const [evaluated, evaluatedInst] = res.consume(scope);
2183
- return [evaluated, [...inst, ...evaluatedInst]];
2914
+ const result = [evaluated, [...inst, ...evaluatedInst]];
2915
+ if (this.sourcemap)
2916
+ return appendSourceLocations(result, node);
2917
+ return result;
2184
2918
  }
2185
- handleMany(scope, nodes, handler = this.handle.bind(this)) {
2919
+ /**
2920
+ * Handles many nodes in order.
2921
+ *
2922
+ * The usage of this method over a regular loop over an array of nodes
2923
+ * is only required if the code inside the loop generates
2924
+ * instructions that are not tracked by the compiler
2925
+ * handler methods ({@link handle}, {@link handleEval}, {@link handleConsume}
2926
+ * and {@link handleMany})
2927
+ *
2928
+ */
2929
+ handleMany(scope, nodes, handler) {
2186
2930
  const lines = [];
2187
2931
  for (const node of nodes) {
2188
- const [, nodeLines] = handler(scope, node);
2932
+ const [, nodeLines] = this.handle(scope, node, handler && (() => handler(node)));
2189
2933
  lines.push(...nodeLines);
2190
2934
  }
2191
2935
  return [null, lines];
2192
2936
  }
2937
+ }
2938
+ /** Removes jump instructions that point right to the next line */
2939
+ function hideRedundantJumps(inst) {
2940
+ for (let i = 0; i < inst.length; i++) {
2941
+ const instruction = inst[i];
2942
+ if (!(instruction instanceof JumpInstruction))
2943
+ continue;
2944
+ const { address } = instruction;
2945
+ let searchIndex = i + 1;
2946
+ let current = inst[searchIndex];
2947
+ while (current.hidden) {
2948
+ if (current instanceof AddressResolver &&
2949
+ current.bonds.includes(address)) {
2950
+ // only gets assigned if `current` is an adress resolver
2951
+ // that resolves the jump adress
2952
+ // and that is also right next to the jump,
2953
+ // without any actual instructions in between
2954
+ instruction.hidden = true;
2955
+ break;
2956
+ }
2957
+ searchIndex++;
2958
+ current = inst[searchIndex];
2959
+ }
2960
+ }
2193
2961
  }
2194
2962
 
2195
2963
  export { Compiler, CompilerError };