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