mlogjs 0.3.0 → 0.4.0
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/Compiler.d.ts +39 -0
- package/dist/CompilerError.d.ts +33 -0
- package/dist/Scope.d.ts +24 -0
- package/dist/assertions.d.ts +28 -0
- package/dist/bin.cjs +7 -14
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.d.ts +1 -0
- package/dist/handlers/BlockStatement.d.ts +2 -0
- package/dist/handlers/CallExpression.d.ts +4 -0
- package/dist/handlers/File.d.ts +2 -0
- package/dist/handlers/ForStatement.d.ts +2 -0
- package/dist/handlers/Function.d.ts +5 -0
- package/dist/handlers/Identifier.d.ts +2 -0
- package/dist/handlers/IfStatement.d.ts +2 -0
- package/dist/handlers/Literal.d.ts +5 -0
- package/dist/handlers/Object.d.ts +6 -0
- package/dist/handlers/OperationExpressions.d.ts +8 -0
- package/dist/handlers/Program.d.ts +2 -0
- package/dist/handlers/Statements.d.ts +5 -0
- package/dist/handlers/SwitchStatement.d.ts +2 -0
- package/dist/handlers/TemplateExpression.d.ts +2 -0
- package/dist/handlers/Typescript.d.ts +7 -0
- package/dist/handlers/VariableDeclaration.d.ts +3 -0
- package/dist/handlers/WhileStatement.d.ts +3 -0
- package/dist/handlers/index.d.ts +17 -0
- package/dist/index.cjs +1037 -315
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +1037 -315
- package/dist/index.mjs.map +1 -1
- package/dist/initScope.d.ts +5 -0
- package/dist/instructions/AddressResolver.d.ts +12 -0
- package/dist/instructions/ControlInstructions.d.ts +10 -0
- package/dist/instructions/EndInstruction.d.ts +4 -0
- package/dist/instructions/InstructionBase.d.ts +14 -0
- package/dist/instructions/JumpInstruction.d.ts +16 -0
- package/dist/instructions/OperationInstruction.d.ts +5 -0
- package/dist/instructions/SetCounterInstruction.d.ts +5 -0
- package/dist/instructions/SetInstruction.d.ts +6 -0
- package/dist/instructions/ZeroSpaceInstruction.d.ts +4 -0
- package/dist/instructions/index.d.ts +9 -0
- package/dist/{types/macros/RawValue.d.ts → macros/Asm.d.ts} +1 -1
- package/dist/macros/Function.d.ts +13 -0
- package/dist/macros/GetGlobal.d.ts +5 -0
- package/dist/macros/Math.d.ts +5 -0
- package/dist/macros/Memory.d.ts +5 -0
- package/dist/macros/Namespace.d.ts +13 -0
- package/dist/macros/Other.d.ts +5 -0
- package/dist/macros/commands/ApplyStatus.d.ts +5 -0
- package/dist/macros/commands/Control.d.ts +5 -0
- package/dist/macros/commands/Cutscene.d.ts +5 -0
- package/dist/macros/commands/Draw.d.ts +5 -0
- package/dist/macros/commands/DrawFlush.d.ts +5 -0
- package/dist/macros/commands/End.d.ts +5 -0
- package/dist/macros/commands/Explosion.d.ts +5 -0
- package/dist/macros/commands/Fetch.d.ts +5 -0
- package/dist/macros/commands/FlushMessage.d.ts +5 -0
- package/dist/macros/commands/GetBlock.d.ts +5 -0
- package/dist/macros/commands/GetFlag.d.ts +5 -0
- package/dist/macros/commands/GetLink.d.ts +5 -0
- package/dist/macros/commands/Lookup.d.ts +5 -0
- package/dist/macros/commands/PackColor.d.ts +5 -0
- package/dist/macros/commands/Print.d.ts +5 -0
- package/dist/macros/commands/PrintFlush.d.ts +5 -0
- package/dist/macros/commands/Radar.d.ts +7 -0
- package/dist/macros/commands/Sensor.d.ts +5 -0
- package/dist/macros/commands/SetBlock.d.ts +5 -0
- package/dist/macros/commands/SetFlag.d.ts +5 -0
- package/dist/macros/commands/SetRate.d.ts +5 -0
- package/dist/macros/commands/SetRule.d.ts +5 -0
- package/dist/macros/commands/SpawnUnit.d.ts +5 -0
- package/dist/macros/commands/SpawnWave.d.ts +5 -0
- package/dist/macros/commands/Stop.d.ts +5 -0
- package/dist/macros/commands/UnitBind.d.ts +5 -0
- package/dist/macros/commands/UnitControl.d.ts +5 -0
- package/dist/macros/commands/UnitLocate.d.ts +5 -0
- package/dist/macros/commands/UnitRadar.d.ts +5 -0
- package/dist/macros/commands/Wait.d.ts +5 -0
- package/dist/macros/commands/index.d.ts +30 -0
- package/dist/macros/index.d.ts +6 -0
- package/dist/macros/util.d.ts +18 -0
- package/dist/operators.d.ts +25 -0
- package/dist/types/Compiler.d.ts +17 -4
- package/dist/types/CompilerError.d.ts +28 -4
- package/dist/types/assertions.d.ts +28 -0
- package/dist/types/handlers/CallExpression.d.ts +1 -0
- package/dist/types/handlers/SwitchStatement.d.ts +2 -0
- package/dist/types/handlers/index.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/instructions/ControlInstructions.d.ts +3 -1
- package/dist/types/instructions/InstructionBase.d.ts +5 -1
- package/dist/types/instructions/JumpInstruction.d.ts +1 -0
- package/dist/types/macros/Asm.d.ts +5 -0
- package/dist/types/macros/Namespace.d.ts +0 -3
- package/dist/types/macros/commands/ApplyStatus.d.ts +5 -0
- package/dist/types/macros/commands/Control.d.ts +2 -2
- package/dist/types/macros/commands/Cutscene.d.ts +5 -0
- package/dist/types/macros/commands/Draw.d.ts +2 -2
- package/dist/types/macros/commands/Explosion.d.ts +5 -0
- package/dist/types/macros/commands/Fetch.d.ts +5 -0
- package/dist/types/macros/commands/FlushMessage.d.ts +5 -0
- package/dist/types/macros/commands/GetBlock.d.ts +5 -0
- package/dist/types/macros/commands/GetFlag.d.ts +5 -0
- package/dist/types/macros/commands/Lookup.d.ts +2 -2
- package/dist/types/macros/commands/PackColor.d.ts +5 -0
- package/dist/types/macros/commands/Radar.d.ts +2 -2
- package/dist/types/macros/commands/SetBlock.d.ts +5 -0
- package/dist/types/macros/commands/SetFlag.d.ts +5 -0
- package/dist/types/macros/commands/SetRate.d.ts +5 -0
- package/dist/types/macros/commands/SetRule.d.ts +5 -0
- package/dist/types/macros/commands/SpawnUnit.d.ts +5 -0
- package/dist/types/macros/commands/SpawnWave.d.ts +5 -0
- package/dist/types/macros/commands/Stop.d.ts +5 -0
- package/dist/types/macros/commands/UnitControl.d.ts +3 -3
- package/dist/types/macros/commands/UnitLocate.d.ts +2 -2
- package/dist/types/macros/commands/index.d.ts +15 -0
- package/dist/types/macros/util.d.ts +18 -0
- package/dist/types/types.d.ts +14 -0
- package/dist/types/utils.d.ts +19 -2
- package/dist/types/values/BaseValue.d.ts +2 -0
- package/dist/types/values/FunctionValue.d.ts +1 -1
- package/dist/types/values/ObjectValue.d.ts +1 -1
- package/dist/types.d.ts +238 -0
- package/dist/utils.d.ts +47 -0
- package/dist/values/BaseValue.d.ts +9 -0
- package/dist/values/DestructuringValue.d.ts +17 -0
- package/dist/values/FunctionValue.d.ts +47 -0
- package/dist/values/LiteralValue.d.ts +13 -0
- package/dist/values/ObjectValue.d.ts +23 -0
- package/dist/values/SenseableValue.d.ts +23 -0
- package/dist/{types/values/StackValue.d.ts → values/StoreValue.d.ts} +5 -6
- package/dist/values/ValueOwner.d.ts +27 -0
- package/dist/values/VoidValue.d.ts +16 -0
- package/dist/values/index.d.ts +7 -0
- package/lib/commands.d.ts +849 -418
- 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 +15 -16
- 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/types/macros/Building.d.ts +0 -10
- package/dist/types/macros/Entities.d.ts +0 -11
- package/dist/types/values/TempValue.d.ts +0 -19
package/dist/index.mjs
CHANGED
|
@@ -2,12 +2,58 @@ import { parse } from '@babel/parser';
|
|
|
2
2
|
import * as es from '@babel/types';
|
|
3
3
|
|
|
4
4
|
class CompilerError extends Error {
|
|
5
|
-
constructor(message,
|
|
5
|
+
constructor(message, source) {
|
|
6
6
|
super(message);
|
|
7
|
-
this.
|
|
7
|
+
this.loc = source;
|
|
8
|
+
}
|
|
9
|
+
get loc() {
|
|
10
|
+
return this._loc;
|
|
11
|
+
}
|
|
12
|
+
set loc(value) {
|
|
13
|
+
if (!value)
|
|
14
|
+
return;
|
|
15
|
+
if ("type" in value) {
|
|
16
|
+
this._loc = value.loc;
|
|
17
|
+
}
|
|
18
|
+
else if ("start" in value) {
|
|
19
|
+
this._loc = value;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
this._loc = {
|
|
23
|
+
start: value,
|
|
24
|
+
end: value,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
static from(error, source) {
|
|
29
|
+
let message;
|
|
30
|
+
if (error && typeof error === "object" && "loc" in error) {
|
|
31
|
+
const err = error;
|
|
32
|
+
message = err.toString();
|
|
33
|
+
source ??= err.loc;
|
|
34
|
+
}
|
|
35
|
+
else if (error instanceof Error) {
|
|
36
|
+
message = error.message;
|
|
37
|
+
}
|
|
38
|
+
else if (typeof error === "string") {
|
|
39
|
+
message = error;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
message = `Unknown error: ${error}`;
|
|
43
|
+
}
|
|
44
|
+
const result = new CompilerError(message, source);
|
|
45
|
+
result.inner = error;
|
|
46
|
+
return result;
|
|
8
47
|
}
|
|
9
48
|
}
|
|
10
49
|
|
|
50
|
+
var EInstIntent;
|
|
51
|
+
(function (EInstIntent) {
|
|
52
|
+
EInstIntent[EInstIntent["none"] = 0] = "none";
|
|
53
|
+
EInstIntent[EInstIntent["break"] = 1] = "break";
|
|
54
|
+
EInstIntent[EInstIntent["continue"] = 2] = "continue";
|
|
55
|
+
EInstIntent[EInstIntent["return"] = 3] = "return";
|
|
56
|
+
})(EInstIntent || (EInstIntent = {}));
|
|
11
57
|
/** Defines the possible types of mutability of a value */
|
|
12
58
|
var EMutability;
|
|
13
59
|
(function (EMutability) {
|
|
@@ -135,6 +181,8 @@ for (const key of operators) {
|
|
|
135
181
|
|
|
136
182
|
class InstructionBase {
|
|
137
183
|
constructor(...args) {
|
|
184
|
+
this.intent = EInstIntent.none;
|
|
185
|
+
this.alwaysRuns = true;
|
|
138
186
|
this._hidden = false;
|
|
139
187
|
this.args = args;
|
|
140
188
|
}
|
|
@@ -211,6 +259,7 @@ var EJumpKind;
|
|
|
211
259
|
class JumpInstruction extends InstructionBase {
|
|
212
260
|
constructor(address, kind, left = null, right = null) {
|
|
213
261
|
super("jump", address, kind, left, right);
|
|
262
|
+
this.address = address;
|
|
214
263
|
}
|
|
215
264
|
}
|
|
216
265
|
|
|
@@ -229,11 +278,13 @@ class ZeroSpaceInstruction extends InstructionBase {
|
|
|
229
278
|
class BreakInstruction extends JumpInstruction {
|
|
230
279
|
constructor(address) {
|
|
231
280
|
super(address, EJumpKind.Always);
|
|
281
|
+
this.intent = EInstIntent.break;
|
|
232
282
|
}
|
|
233
283
|
}
|
|
234
284
|
class ContinueInstruction extends JumpInstruction {
|
|
235
285
|
constructor(address) {
|
|
236
286
|
super(address, EJumpKind.Always);
|
|
287
|
+
this.intent = EInstIntent.continue;
|
|
237
288
|
}
|
|
238
289
|
}
|
|
239
290
|
|
|
@@ -285,6 +336,20 @@ class BaseValue extends VoidValue {
|
|
|
285
336
|
// TODO: should it return 0 + this ?
|
|
286
337
|
return this.eval(scope);
|
|
287
338
|
}
|
|
339
|
+
"!"(scope) {
|
|
340
|
+
const [that, inst] = this.consume(scope);
|
|
341
|
+
const temp = new StoreValue(scope);
|
|
342
|
+
const falseLiteral = new LiteralValue(scope, 0);
|
|
343
|
+
return [
|
|
344
|
+
temp,
|
|
345
|
+
[...inst, new OperationInstruction("equal", temp, that, falseLiteral)],
|
|
346
|
+
];
|
|
347
|
+
}
|
|
348
|
+
"~"(scope) {
|
|
349
|
+
const [that, inst] = this.consume(scope);
|
|
350
|
+
const temp = new StoreValue(scope);
|
|
351
|
+
return [temp, [...inst, new OperationInstruction("not", temp, that, null)]];
|
|
352
|
+
}
|
|
288
353
|
ensureOwned() {
|
|
289
354
|
this.owner ??= new ValueOwner({ scope: this.scope, value: this });
|
|
290
355
|
}
|
|
@@ -329,18 +394,6 @@ for (const key in operatorMap$1) {
|
|
|
329
394
|
];
|
|
330
395
|
};
|
|
331
396
|
}
|
|
332
|
-
const unaryOperatorMap$1 = {
|
|
333
|
-
"!": "not",
|
|
334
|
-
"~": "flip",
|
|
335
|
-
};
|
|
336
|
-
for (const key in unaryOperatorMap$1) {
|
|
337
|
-
const name = unaryOperatorMap$1[key];
|
|
338
|
-
BaseValue.prototype[key] = function (scope) {
|
|
339
|
-
const [that, inst] = this.consume(scope);
|
|
340
|
-
const temp = new StoreValue(scope);
|
|
341
|
-
return [temp, [...inst, new OperationInstruction(name, temp, that, null)]];
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
397
|
const assignmentToBinary = {
|
|
345
398
|
"+=": "+",
|
|
346
399
|
"-=": "-",
|
|
@@ -453,18 +506,22 @@ for (const key in operatorMap) {
|
|
|
453
506
|
if (!(value instanceof LiteralValue)) {
|
|
454
507
|
return BaseValue.prototype[key].apply(this, [scope, value]);
|
|
455
508
|
}
|
|
456
|
-
return [
|
|
509
|
+
return [
|
|
510
|
+
new LiteralValue(scope, fn(this.data, value.data)),
|
|
511
|
+
[],
|
|
512
|
+
];
|
|
457
513
|
};
|
|
458
514
|
}
|
|
459
515
|
const unaryOperatorMap = {
|
|
460
516
|
"!": v => +!v,
|
|
461
517
|
"~": v => ~v,
|
|
462
518
|
"u-": v => -v,
|
|
519
|
+
"u+": v => +v,
|
|
463
520
|
};
|
|
464
521
|
for (const key in unaryOperatorMap) {
|
|
465
522
|
LiteralValue.prototype[key] = function (scope) {
|
|
466
523
|
const fn = unaryOperatorMap[key];
|
|
467
|
-
return [new LiteralValue(scope, fn(this.
|
|
524
|
+
return [new LiteralValue(scope, fn(this.data)), []];
|
|
468
525
|
};
|
|
469
526
|
}
|
|
470
527
|
|
|
@@ -519,8 +576,28 @@ const itemNames = [
|
|
|
519
576
|
/**
|
|
520
577
|
* A more type safe version of `Object.assign`
|
|
521
578
|
*/
|
|
579
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
522
580
|
function assign(obj, props) {
|
|
523
581
|
return Object.assign(obj, props);
|
|
582
|
+
}
|
|
583
|
+
function appendSourceLocations(valueInst, node) {
|
|
584
|
+
for (const inst of valueInst[1]) {
|
|
585
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
586
|
+
inst.source ??= node.loc;
|
|
587
|
+
}
|
|
588
|
+
return valueInst;
|
|
589
|
+
}
|
|
590
|
+
function withAlwaysRuns(valueInst, value) {
|
|
591
|
+
valueInst[1].forEach(inst => (inst.alwaysRuns = value));
|
|
592
|
+
return valueInst;
|
|
593
|
+
}
|
|
594
|
+
function isTemplateObjectArray(value) {
|
|
595
|
+
return (value instanceof ObjectValue &&
|
|
596
|
+
value.data.length instanceof LiteralValue &&
|
|
597
|
+
typeof value.data.length.data === "number" &&
|
|
598
|
+
value.data.raw instanceof ObjectValue &&
|
|
599
|
+
value.data.raw.data.length instanceof LiteralValue &&
|
|
600
|
+
typeof value.data.raw.data.length.data === "number");
|
|
524
601
|
}
|
|
525
602
|
|
|
526
603
|
/**
|
|
@@ -572,8 +649,9 @@ class ObjectValue extends VoidValue {
|
|
|
572
649
|
this.macro = true;
|
|
573
650
|
this.data = data;
|
|
574
651
|
}
|
|
575
|
-
static fromArray(scope, items) {
|
|
652
|
+
static fromArray(scope, items, intialData) {
|
|
576
653
|
const data = {
|
|
654
|
+
...intialData,
|
|
577
655
|
length: new LiteralValue(scope, items.length),
|
|
578
656
|
};
|
|
579
657
|
items.forEach((item, i) => {
|
|
@@ -674,7 +752,9 @@ class SenseableValue extends StoreValue {
|
|
|
674
752
|
];
|
|
675
753
|
}
|
|
676
754
|
if (prop instanceof StoreValue) {
|
|
677
|
-
const temp = new
|
|
755
|
+
const temp = assign(new SenseableValue(scope), {
|
|
756
|
+
mutability: EMutability.readonly,
|
|
757
|
+
});
|
|
678
758
|
return [temp, [new InstructionBase("sensor", temp, this, prop)]];
|
|
679
759
|
}
|
|
680
760
|
throw new CompilerError(`Cannot sense "${prop}" property`);
|
|
@@ -799,7 +879,7 @@ const Program = (c, scope, node) => {
|
|
|
799
879
|
};
|
|
800
880
|
|
|
801
881
|
const VariableDeclaration = (c, scope, node) => {
|
|
802
|
-
return c.handleMany(scope, node.declarations,
|
|
882
|
+
return c.handleMany(scope, node.declarations, child => VariableDeclarator(c, scope, child, node.kind));
|
|
803
883
|
};
|
|
804
884
|
const VariableDeclarator = (c, scope, node, kind = "let") => {
|
|
805
885
|
const [init, inst] = node.init
|
|
@@ -809,24 +889,24 @@ const VariableDeclarator = (c, scope, node, kind = "let") => {
|
|
|
809
889
|
return [null, inst];
|
|
810
890
|
};
|
|
811
891
|
const Declare = (c, scope, node, kind, init) => {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
node
|
|
822
|
-
|
|
823
|
-
}
|
|
892
|
+
return c.handle(scope, node, () => {
|
|
893
|
+
switch (node.type) {
|
|
894
|
+
case "Identifier":
|
|
895
|
+
return DeclareIdentifier(c, scope, node, kind, init);
|
|
896
|
+
case "ArrayPattern":
|
|
897
|
+
return DeclareArrayPattern(c, scope, node, kind, init);
|
|
898
|
+
case "ObjectPattern":
|
|
899
|
+
return DeclareObjectPattern(c, scope, node, kind, init);
|
|
900
|
+
default:
|
|
901
|
+
throw new CompilerError(`Unsupported declaration type: ${node.type}`, node);
|
|
902
|
+
}
|
|
903
|
+
});
|
|
824
904
|
};
|
|
825
905
|
const DeclareIdentifier = (c, scope, node, kind, init) => {
|
|
826
906
|
const { name: identifier } = node;
|
|
827
907
|
const name = nodeName(node, !c.compactNames && identifier);
|
|
828
908
|
if (kind === "const" && !init)
|
|
829
|
-
throw new CompilerError("Constants must be initialized.",
|
|
909
|
+
throw new CompilerError("Constants must be initialized.", node);
|
|
830
910
|
if (kind === "const" && init?.mutability === EMutability.constant) {
|
|
831
911
|
const owner = new ValueOwner({
|
|
832
912
|
scope,
|
|
@@ -843,9 +923,7 @@ const DeclareIdentifier = (c, scope, node, kind, init) => {
|
|
|
843
923
|
const inst = [];
|
|
844
924
|
if (init) {
|
|
845
925
|
if (init.macro)
|
|
846
|
-
throw new CompilerError("Macro values must be held by constants",
|
|
847
|
-
node,
|
|
848
|
-
]);
|
|
926
|
+
throw new CompilerError("Macro values must be held by constants", node);
|
|
849
927
|
inst.push(...value["="](scope, init)[1]);
|
|
850
928
|
}
|
|
851
929
|
if (kind === "const")
|
|
@@ -864,29 +942,28 @@ const DeclareArrayPattern = (c, scope, node, kind, init) => {
|
|
|
864
942
|
continue;
|
|
865
943
|
const val = init.data[i];
|
|
866
944
|
if (!val)
|
|
867
|
-
throw new CompilerError(`The target object does not have a value at index ${i}`,
|
|
945
|
+
throw new CompilerError(`The target object does not have a value at index ${i}`, element);
|
|
868
946
|
inst.push(...Declare(c, scope, element, kind, val)[1]);
|
|
869
947
|
}
|
|
870
948
|
return [null, inst];
|
|
871
949
|
};
|
|
872
950
|
const DeclareObjectPattern = (c, scope, node, kind, base) => {
|
|
873
951
|
if (!base)
|
|
874
|
-
throw new CompilerError("Cannot use object destructuring without an initializer",
|
|
952
|
+
throw new CompilerError("Cannot use object destructuring without an initializer", node);
|
|
875
953
|
const { properties } = node;
|
|
876
954
|
const [init, inst] = base.consume(scope);
|
|
877
|
-
|
|
955
|
+
const propertiesInst = c.handleMany(scope, properties, prop => {
|
|
878
956
|
if (prop.type === "RestElement")
|
|
879
|
-
throw new CompilerError("The rest operator is not supported",
|
|
957
|
+
throw new CompilerError("The rest operator is not supported", prop);
|
|
880
958
|
const { key, value } = prop;
|
|
881
|
-
const
|
|
959
|
+
const keyInst = key.type === "Identifier" && !prop.computed
|
|
882
960
|
? [new LiteralValue(scope, key.name), []]
|
|
883
961
|
: c.handleConsume(scope, prop.key);
|
|
884
|
-
|
|
885
|
-
const
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
return [null, inst];
|
|
962
|
+
const propInit = init.get(scope, keyInst[0]);
|
|
963
|
+
const declarationInst = Declare(c, scope, value, kind, propInit[0]);
|
|
964
|
+
return [null, [...keyInst[1], ...propInit[1], ...declarationInst[1]]];
|
|
965
|
+
});
|
|
966
|
+
return [null, [...inst, ...propertiesInst[1]]];
|
|
890
967
|
};
|
|
891
968
|
|
|
892
969
|
const Literal = (_c, scope, node) => [new LiteralValue(scope, node.value), []];
|
|
@@ -905,7 +982,34 @@ const LRExpression = (c, scope, node) => {
|
|
|
905
982
|
return [op, [...leftInst, ...rightInst, ...opInst]];
|
|
906
983
|
};
|
|
907
984
|
const BinaryExpression = LRExpression;
|
|
908
|
-
const LogicalExpression =
|
|
985
|
+
const LogicalExpression = (c, scope, node) => {
|
|
986
|
+
if (node.operator !== "??")
|
|
987
|
+
return LRExpression(c, scope, node);
|
|
988
|
+
const nullLiteral = new LiteralValue(scope, null);
|
|
989
|
+
const endAdress = new LiteralValue(scope, null);
|
|
990
|
+
const [left, leftInst] = c.handleEval(scope, node.left);
|
|
991
|
+
const [nullTest] = left["=="](scope, nullLiteral);
|
|
992
|
+
if (nullTest instanceof LiteralValue) {
|
|
993
|
+
if (nullTest.data)
|
|
994
|
+
return c.handleEval(scope, node.right);
|
|
995
|
+
else
|
|
996
|
+
return [left, leftInst];
|
|
997
|
+
}
|
|
998
|
+
const [right, rightInst] = c.handleEval(scope, node.right);
|
|
999
|
+
const result = new StoreValue(scope);
|
|
1000
|
+
result.ensureOwned();
|
|
1001
|
+
return [
|
|
1002
|
+
result,
|
|
1003
|
+
[
|
|
1004
|
+
...leftInst,
|
|
1005
|
+
...result["="](scope, left)[1],
|
|
1006
|
+
new JumpInstruction(endAdress, EJumpKind.NotEqual, result, nullLiteral),
|
|
1007
|
+
...rightInst,
|
|
1008
|
+
...result["="](scope, right)[1],
|
|
1009
|
+
new AddressResolver(endAdress),
|
|
1010
|
+
],
|
|
1011
|
+
];
|
|
1012
|
+
};
|
|
909
1013
|
const AssignmentExpression = (c, scope, node) => {
|
|
910
1014
|
const [left, leftInst] = c.handle(scope, node.left);
|
|
911
1015
|
// doesn't need to consume because the operators already do that
|
|
@@ -995,13 +1099,75 @@ const IfStatement = (c, scope, node) => {
|
|
|
995
1099
|
return [null, inst];
|
|
996
1100
|
}
|
|
997
1101
|
const endIfAddr = new LiteralValue(scope, null);
|
|
998
|
-
inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...c.handle(scope, node.consequent)[1], new AddressResolver(endIfAddr));
|
|
1102
|
+
inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...withAlwaysRuns(c.handle(scope, node.consequent), false)[1], new AddressResolver(endIfAddr));
|
|
999
1103
|
const endElseAddr = new LiteralValue(scope, null);
|
|
1000
|
-
if (node.alternate)
|
|
1001
|
-
inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...c.handle(scope, node.alternate)[1], new AddressResolver(endElseAddr));
|
|
1104
|
+
if (node.alternate) {
|
|
1105
|
+
inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...withAlwaysRuns(c.handle(scope, node.alternate), false)[1], new AddressResolver(endElseAddr));
|
|
1106
|
+
}
|
|
1002
1107
|
return [null, inst];
|
|
1003
1108
|
};
|
|
1004
1109
|
|
|
1110
|
+
const SwitchStatement = (c, scope, node) => {
|
|
1111
|
+
const innerScope = scope.createScope();
|
|
1112
|
+
const [ref, refInst] = c.handleConsume(scope, node.discriminant);
|
|
1113
|
+
const inst = [];
|
|
1114
|
+
const endAdress = new LiteralValue(innerScope, null);
|
|
1115
|
+
const endLine = new AddressResolver(endAdress).bindBreak(innerScope);
|
|
1116
|
+
const caseJumps = [];
|
|
1117
|
+
let defaultJump;
|
|
1118
|
+
for (const scase of node.cases) {
|
|
1119
|
+
const [, bodyInst] = c.handleMany(innerScope, scase.consequent);
|
|
1120
|
+
const bodyAdress = new LiteralValue(innerScope, null);
|
|
1121
|
+
const bodyLine = new AddressResolver(bodyAdress);
|
|
1122
|
+
if (!scase.test) {
|
|
1123
|
+
[defaultJump] = c.handle(innerScope, scase, () => [
|
|
1124
|
+
null,
|
|
1125
|
+
[new JumpInstruction(bodyAdress, EJumpKind.Always)],
|
|
1126
|
+
])[1];
|
|
1127
|
+
inst.push(bodyLine, ...bodyInst);
|
|
1128
|
+
continue;
|
|
1129
|
+
}
|
|
1130
|
+
const [test, testInst] = c.handleConsume(innerScope, scase.test);
|
|
1131
|
+
// check if it can be evaluated at compile time
|
|
1132
|
+
const [comp] = ref["=="](innerScope, test);
|
|
1133
|
+
// if the constant expression resolves to false
|
|
1134
|
+
// the whole case gets omitted
|
|
1135
|
+
// otherwise it returns the instructions for
|
|
1136
|
+
// the body of this case
|
|
1137
|
+
if (comp instanceof LiteralValue) {
|
|
1138
|
+
if (comp.data)
|
|
1139
|
+
return [null, bodyInst];
|
|
1140
|
+
else
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
// makes sourcemapping for the jump more specific
|
|
1144
|
+
const [, jump] = c.handle(innerScope, scase, () => [
|
|
1145
|
+
null,
|
|
1146
|
+
[new JumpInstruction(bodyAdress, EJumpKind.StrictEqual, ref, test)],
|
|
1147
|
+
]);
|
|
1148
|
+
caseJumps.push(...testInst, ...jump);
|
|
1149
|
+
inst.push(bodyLine, ...bodyInst);
|
|
1150
|
+
}
|
|
1151
|
+
// ensures that the processor exits
|
|
1152
|
+
// the switch if no cases match
|
|
1153
|
+
defaultJump ??= new JumpInstruction(endAdress, EJumpKind.Always);
|
|
1154
|
+
if (caseJumps.length > 0) {
|
|
1155
|
+
withAlwaysRuns([null, inst], false);
|
|
1156
|
+
withAlwaysRuns([null, [...caseJumps.slice(1), defaultJump]], false);
|
|
1157
|
+
withAlwaysRuns([null, inst], false);
|
|
1158
|
+
}
|
|
1159
|
+
return [
|
|
1160
|
+
null,
|
|
1161
|
+
[
|
|
1162
|
+
...refInst,
|
|
1163
|
+
...caseJumps,
|
|
1164
|
+
...(caseJumps.length > 0 ? [defaultJump] : []),
|
|
1165
|
+
...inst,
|
|
1166
|
+
endLine,
|
|
1167
|
+
],
|
|
1168
|
+
];
|
|
1169
|
+
};
|
|
1170
|
+
|
|
1005
1171
|
const WhileStatement = (c, scope, node) => {
|
|
1006
1172
|
const lines = [];
|
|
1007
1173
|
const [test, testLines] = c.handleConsume(scope, node.test);
|
|
@@ -1015,7 +1181,7 @@ const WhileStatement = (c, scope, node) => {
|
|
|
1015
1181
|
}
|
|
1016
1182
|
return [null, lines];
|
|
1017
1183
|
}
|
|
1018
|
-
lines.push(startLoopLine, ...testLines, new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...c.handle(scope, node.body)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
|
|
1184
|
+
lines.push(startLoopLine, ...testLines, new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...withAlwaysRuns(c.handle(scope, node.body), false)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
|
|
1019
1185
|
return [null, lines];
|
|
1020
1186
|
};
|
|
1021
1187
|
const DoWhileStatement = (c, scope, node) => {
|
|
@@ -1059,7 +1225,7 @@ const ForStatement = (c, scope, node) => {
|
|
|
1059
1225
|
startLoopLine,
|
|
1060
1226
|
...testLines,
|
|
1061
1227
|
new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
|
|
1062
|
-
...c.handle(scope, node.body)[1],
|
|
1228
|
+
...withAlwaysRuns(c.handle(scope, node.body), false)[1],
|
|
1063
1229
|
...updateLines,
|
|
1064
1230
|
new JumpInstruction(startLoopAddr, EJumpKind.Always),
|
|
1065
1231
|
endLoopLine,
|
|
@@ -1090,7 +1256,9 @@ class FunctionValue extends VoidValue {
|
|
|
1090
1256
|
const name = nodeName(id, !this.c.compactNames && id.name);
|
|
1091
1257
|
const owner = new ValueOwner({
|
|
1092
1258
|
scope: this.childScope,
|
|
1093
|
-
value: new
|
|
1259
|
+
value: assign(new SenseableValue(this.childScope), {
|
|
1260
|
+
mutability: EMutability.mutable,
|
|
1261
|
+
}),
|
|
1094
1262
|
identifier: id.name,
|
|
1095
1263
|
name,
|
|
1096
1264
|
});
|
|
@@ -1125,12 +1293,17 @@ class FunctionValue extends VoidValue {
|
|
|
1125
1293
|
...this.c.handle(this.childScope, this.body)[1],
|
|
1126
1294
|
];
|
|
1127
1295
|
if (!endsWithReturn(this.inst)) {
|
|
1128
|
-
this.inst.push(new SetCounterInstruction(this.ret.value)
|
|
1296
|
+
this.inst.push(assign(new SetCounterInstruction(this.ret.value), {
|
|
1297
|
+
intent: EInstIntent.return,
|
|
1298
|
+
}));
|
|
1129
1299
|
}
|
|
1130
1300
|
}
|
|
1131
1301
|
normalReturn(scope, arg) {
|
|
1132
1302
|
const argInst = arg ? this.temp.value["="](scope, arg)[1] : [];
|
|
1133
|
-
|
|
1303
|
+
const returnInst = assign(new SetCounterInstruction(this.ret.value), {
|
|
1304
|
+
intent: EInstIntent.return,
|
|
1305
|
+
});
|
|
1306
|
+
return [null, [...argInst, returnInst]];
|
|
1134
1307
|
}
|
|
1135
1308
|
normalCall(scope, args) {
|
|
1136
1309
|
if (!this.bundled)
|
|
@@ -1145,7 +1318,12 @@ class FunctionValue extends VoidValue {
|
|
|
1145
1318
|
}
|
|
1146
1319
|
inlineReturn(scope, arg) {
|
|
1147
1320
|
const argInst = arg ? this.inlineTemp.value["="](scope, arg)[1] : [];
|
|
1148
|
-
|
|
1321
|
+
if (!this.inlineEnd)
|
|
1322
|
+
throw new CompilerError("Error during inline attempt: missing inline end adress");
|
|
1323
|
+
const jump = assign(new JumpInstruction(this.inlineEnd, EJumpKind.Always), {
|
|
1324
|
+
intent: EInstIntent.return,
|
|
1325
|
+
});
|
|
1326
|
+
return [null, [...argInst, jump]];
|
|
1149
1327
|
}
|
|
1150
1328
|
inlineCall(scope, args) {
|
|
1151
1329
|
// create return value
|
|
@@ -1155,7 +1333,6 @@ class FunctionValue extends VoidValue {
|
|
|
1155
1333
|
mutability: EMutability.mutable,
|
|
1156
1334
|
}),
|
|
1157
1335
|
});
|
|
1158
|
-
this.inlineEnd = new LiteralValue(scope, null);
|
|
1159
1336
|
// make a copy of the function scope
|
|
1160
1337
|
const fnScope = this.childScope.copy();
|
|
1161
1338
|
// hard set variables within the function scope
|
|
@@ -1170,16 +1347,13 @@ class FunctionValue extends VoidValue {
|
|
|
1170
1347
|
name: owner.name,
|
|
1171
1348
|
}));
|
|
1172
1349
|
});
|
|
1350
|
+
this.inlineEnd = new LiteralValue(scope, null);
|
|
1173
1351
|
this.tryingInline = true;
|
|
1174
|
-
|
|
1352
|
+
let inst = this.c.handle(fnScope, this.body)[1];
|
|
1175
1353
|
this.tryingInline = false;
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
// if (jump instanceof JumpInstruction) {
|
|
1180
|
-
// // remove useless jump
|
|
1181
|
-
// if (jump.args[1] === this.inlineEnd) inst.pop();
|
|
1182
|
-
// }
|
|
1354
|
+
const returnIndex = inst.findIndex(i => i.alwaysRuns && i.intent === EInstIntent.return);
|
|
1355
|
+
if (returnIndex !== -1)
|
|
1356
|
+
inst = inst.slice(0, returnIndex + 1);
|
|
1183
1357
|
inst.push(new AddressResolver(this.inlineEnd));
|
|
1184
1358
|
// return the function value
|
|
1185
1359
|
return [this.inlineTemp.value, inst];
|
|
@@ -1224,7 +1398,11 @@ function endsWithReturn(inst) {
|
|
|
1224
1398
|
function handleFunctionNode(c, scope, node) {
|
|
1225
1399
|
let { params, body } = node;
|
|
1226
1400
|
if (es.isExpression(body)) {
|
|
1227
|
-
|
|
1401
|
+
const { loc } = body;
|
|
1402
|
+
const statement = es.returnStatement(body);
|
|
1403
|
+
statement.loc = loc;
|
|
1404
|
+
body = es.blockStatement([statement]);
|
|
1405
|
+
body.loc = loc;
|
|
1228
1406
|
}
|
|
1229
1407
|
return [
|
|
1230
1408
|
new FunctionValue({
|
|
@@ -1270,16 +1448,32 @@ const CallExpression = (c, scope, node) => {
|
|
|
1270
1448
|
inst.push(...callInst);
|
|
1271
1449
|
return [callValue, inst];
|
|
1272
1450
|
};
|
|
1273
|
-
const NewExpression = CallExpression;
|
|
1451
|
+
const NewExpression = CallExpression;
|
|
1452
|
+
const TaggedTemplateExpression = (c, scope, node) => {
|
|
1453
|
+
const [tag, tagInst] = c.handleConsume(scope, node.tag);
|
|
1454
|
+
const template = node.quasi;
|
|
1455
|
+
const stringsObject = ObjectValue.fromArray(scope, template.quasis.map(quasi => new LiteralValue(scope, quasi.value.cooked ?? "")), {
|
|
1456
|
+
raw: ObjectValue.fromArray(scope, template.quasis.map(quasi => new LiteralValue(scope, quasi.value.raw))),
|
|
1457
|
+
});
|
|
1458
|
+
const expressions = [];
|
|
1459
|
+
const expressionInsts = [];
|
|
1460
|
+
template.expressions.forEach(expression => {
|
|
1461
|
+
const [value, inst] = c.handleConsume(scope, expression);
|
|
1462
|
+
expressions.push(value);
|
|
1463
|
+
expressionInsts.push(...inst);
|
|
1464
|
+
});
|
|
1465
|
+
const [result, resultInst] = tag.call(scope, [stringsObject, ...expressions]);
|
|
1466
|
+
return [result, [...expressionInsts, ...tagInst, ...resultInst]];
|
|
1467
|
+
};
|
|
1274
1468
|
|
|
1275
1469
|
const ObjectExpression = (c, scope, node) => {
|
|
1276
1470
|
const data = {};
|
|
1277
1471
|
const inst = [];
|
|
1278
1472
|
for (const prop of node.properties) {
|
|
1279
1473
|
if (prop.type === "SpreadElement")
|
|
1280
|
-
throw new CompilerError("Cannot handle spread element",
|
|
1474
|
+
throw new CompilerError("Cannot handle spread element", prop);
|
|
1281
1475
|
if (prop.computed)
|
|
1282
|
-
throw new CompilerError("Cannot handle computed property.",
|
|
1476
|
+
throw new CompilerError("Cannot handle computed property.", prop);
|
|
1283
1477
|
const { key } = prop;
|
|
1284
1478
|
const value = prop.type === "ObjectProperty" ? prop.value : prop;
|
|
1285
1479
|
let index;
|
|
@@ -1290,17 +1484,18 @@ const ObjectExpression = (c, scope, node) => {
|
|
|
1290
1484
|
index = `${key.value}`;
|
|
1291
1485
|
}
|
|
1292
1486
|
else {
|
|
1293
|
-
throw new CompilerError(`Unsupported object key type: ${key.type}`,
|
|
1294
|
-
key,
|
|
1295
|
-
]);
|
|
1487
|
+
throw new CompilerError(`Unsupported object key type: ${key.type}`, key);
|
|
1296
1488
|
}
|
|
1297
1489
|
const [member, memberInst] = c.handleEval(scope, value);
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1490
|
+
// TODO: use an approach that can be defined by each type
|
|
1491
|
+
if (!member.owner && !(member instanceof LiteralValue)) {
|
|
1492
|
+
new ValueOwner({
|
|
1493
|
+
scope,
|
|
1494
|
+
constant: true,
|
|
1495
|
+
value: member,
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
data[index] = member;
|
|
1304
1499
|
inst.push(...memberInst);
|
|
1305
1500
|
}
|
|
1306
1501
|
return [new ObjectValue(scope, data), inst];
|
|
@@ -1334,9 +1529,7 @@ const ArrayPattern = (c, scope, node) => {
|
|
|
1334
1529
|
continue;
|
|
1335
1530
|
const valueInst = c.handle(scope, element);
|
|
1336
1531
|
if (!valueInst[0])
|
|
1337
|
-
throw new CompilerError("Destructuring element must resolve to a value",
|
|
1338
|
-
element,
|
|
1339
|
-
]);
|
|
1532
|
+
throw new CompilerError("Destructuring element must resolve to a value", element);
|
|
1340
1533
|
inst.push(...valueInst[1]);
|
|
1341
1534
|
members.set(new LiteralValue(scope, i), valueInst[0]);
|
|
1342
1535
|
}
|
|
@@ -1357,26 +1550,15 @@ const ObjectPattern = (c, scope, node) => {
|
|
|
1357
1550
|
inst.push(...keyInst[1]);
|
|
1358
1551
|
const valueInst = c.handle(scope, prop.value);
|
|
1359
1552
|
if (!valueInst[0])
|
|
1360
|
-
throw new CompilerError("Destructuring member must resolve to a value",
|
|
1361
|
-
prop.value,
|
|
1362
|
-
]);
|
|
1553
|
+
throw new CompilerError("Destructuring member must resolve to a value", prop.value);
|
|
1363
1554
|
inst.push(...valueInst[1]);
|
|
1364
1555
|
members.set(keyInst[0], valueInst[0]);
|
|
1365
1556
|
}
|
|
1366
1557
|
return [new DestructuringValue(scope, members), inst];
|
|
1367
1558
|
};
|
|
1368
1559
|
|
|
1369
|
-
const TemplateLiteral = (
|
|
1370
|
-
|
|
1371
|
-
const inst = [];
|
|
1372
|
-
node.expressions.forEach((expression, i) => {
|
|
1373
|
-
const [v, vi] = c.handleConsume(scope, expression);
|
|
1374
|
-
inst.push(...vi);
|
|
1375
|
-
args.push(node.quasis[i].value.raw, v);
|
|
1376
|
-
});
|
|
1377
|
-
args.push(node.quasis.slice(-1)[0].value.raw);
|
|
1378
|
-
inst.push(new ZeroSpaceInstruction(...args));
|
|
1379
|
-
return [null, inst];
|
|
1560
|
+
const TemplateLiteral = () => {
|
|
1561
|
+
throw new CompilerError("Template strings are currently unavailable. To inline mlog code use the asm function.");
|
|
1380
1562
|
};
|
|
1381
1563
|
|
|
1382
1564
|
const BlockStatement = (c, scope, node) => {
|
|
@@ -1409,14 +1591,12 @@ const TSEnumDeclaration = (c, scope, node) => {
|
|
|
1409
1591
|
const data = {};
|
|
1410
1592
|
for (const member of node.members) {
|
|
1411
1593
|
if (lastType === "string" && !member.initializer)
|
|
1412
|
-
throw new CompilerError("This enum member must be initialized",
|
|
1594
|
+
throw new CompilerError("This enum member must be initialized", member);
|
|
1413
1595
|
const [value] = member.initializer
|
|
1414
1596
|
? c.handleEval(scope, member.initializer)
|
|
1415
1597
|
: [new LiteralValue(scope, counter)];
|
|
1416
1598
|
if (!(value instanceof LiteralValue))
|
|
1417
|
-
throw new CompilerError("Enum members must contain literal values",
|
|
1418
|
-
member,
|
|
1419
|
-
]);
|
|
1599
|
+
throw new CompilerError("Enum members must contain literal values", member);
|
|
1420
1600
|
if (typeof value.data === "number") {
|
|
1421
1601
|
lastType = "number";
|
|
1422
1602
|
counter = value.data + 1;
|
|
@@ -1462,6 +1642,7 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1462
1642
|
ContinueStatement: ContinueStatement,
|
|
1463
1643
|
ReturnStatement: ReturnStatement,
|
|
1464
1644
|
IfStatement: IfStatement,
|
|
1645
|
+
SwitchStatement: SwitchStatement,
|
|
1465
1646
|
WhileStatement: WhileStatement,
|
|
1466
1647
|
DoWhileStatement: DoWhileStatement,
|
|
1467
1648
|
ForStatement: ForStatement,
|
|
@@ -1471,6 +1652,7 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1471
1652
|
ObjectMethod: ObjectMethod,
|
|
1472
1653
|
CallExpression: CallExpression,
|
|
1473
1654
|
NewExpression: NewExpression,
|
|
1655
|
+
TaggedTemplateExpression: TaggedTemplateExpression,
|
|
1474
1656
|
ObjectExpression: ObjectExpression,
|
|
1475
1657
|
ArrayExpression: ArrayExpression,
|
|
1476
1658
|
MemberExpression: MemberExpression,
|
|
@@ -1573,53 +1755,170 @@ class Concat extends MacroFunction {
|
|
|
1573
1755
|
}
|
|
1574
1756
|
}
|
|
1575
1757
|
|
|
1576
|
-
|
|
1758
|
+
/** Asserts that `value` is a `LiteralValue` that contains a string */
|
|
1759
|
+
function assertStringLiteral(value, name) {
|
|
1760
|
+
if (!(value instanceof LiteralValue) || typeof value.data !== "string")
|
|
1761
|
+
throw new CompilerError(`${name} must be a string literal`);
|
|
1762
|
+
}
|
|
1763
|
+
/** Asserts that `value` is a string literal that is part of a given set of `members`*/
|
|
1764
|
+
function assertLiteralOneOf(value, members, name) {
|
|
1765
|
+
assertStringLiteral(value, name);
|
|
1766
|
+
if (!members.includes(value.data))
|
|
1767
|
+
throw new CompilerError(`${name} must be one of: ${members
|
|
1768
|
+
.slice(0, -1)
|
|
1769
|
+
.map(member => `"${member}"`)
|
|
1770
|
+
.join(", ")} or "${members[members.length - 1]}"`);
|
|
1771
|
+
}
|
|
1772
|
+
/** Asserts that `value` is either a store or a literal */
|
|
1773
|
+
function assertIsRuntimeValue(value, name) {
|
|
1774
|
+
if (!(value instanceof LiteralValue) && !(value instanceof StoreValue))
|
|
1775
|
+
throw new CompilerError(`${name} must be a valid runtime value`);
|
|
1776
|
+
}
|
|
1777
|
+
/** Asserts that `value` is an `ObjectValue` */
|
|
1778
|
+
function assertIsObjectMacro(value, name) {
|
|
1779
|
+
if (!(value instanceof ObjectValue))
|
|
1780
|
+
throw new CompilerError(`${name} must be an object macro`);
|
|
1781
|
+
}
|
|
1782
|
+
/** Asserts that `value` is an `ObjectValue` that has a length property */
|
|
1783
|
+
function assertIsArrayMacro(value, name) {
|
|
1784
|
+
if (!(value instanceof ObjectValue) || !value.data.length)
|
|
1785
|
+
throw new CompilerError(`${name} must be an array macro`);
|
|
1786
|
+
}
|
|
1787
|
+
/** Asserts that all of the fields described are present on `value`*/
|
|
1788
|
+
function assertObjectFields(value, fields) {
|
|
1789
|
+
const result = [];
|
|
1790
|
+
for (const field of fields) {
|
|
1791
|
+
const param = typeof field === "object" ? field : { key: field };
|
|
1792
|
+
const item = value.data[param.key];
|
|
1793
|
+
if (item) {
|
|
1794
|
+
param.validate?.(item);
|
|
1795
|
+
result.push(item);
|
|
1796
|
+
continue;
|
|
1797
|
+
}
|
|
1798
|
+
if (param.default == undefined)
|
|
1799
|
+
throw new CompilerError(`The field "${param.name ?? param.key}" must be present`);
|
|
1800
|
+
result.push(param.default);
|
|
1801
|
+
}
|
|
1802
|
+
return result;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
/** Used to create namespaces that contain multiple methods that map into instructions */
|
|
1806
|
+
function createOverloadNamespace({ scope, overloads, handler, }) {
|
|
1807
|
+
const result = {};
|
|
1808
|
+
for (const key in overloads) {
|
|
1809
|
+
const { named, args } = overloads[key];
|
|
1810
|
+
if (named) {
|
|
1811
|
+
result[key] = new MacroFunction(scope, options => {
|
|
1812
|
+
assertIsObjectMacro(options, named);
|
|
1813
|
+
return handler(key, ...assertObjectFields(options, args));
|
|
1814
|
+
});
|
|
1815
|
+
continue;
|
|
1816
|
+
}
|
|
1817
|
+
result[key] = new MacroFunction(scope, (...params) => {
|
|
1818
|
+
const handlerParams = [];
|
|
1819
|
+
// validate the paramters
|
|
1820
|
+
for (let i = 0; i < args.length; i++) {
|
|
1821
|
+
let arg = args[i];
|
|
1822
|
+
if (typeof arg === "string")
|
|
1823
|
+
arg = { key: arg };
|
|
1824
|
+
const param = params[i];
|
|
1825
|
+
if (!param) {
|
|
1826
|
+
if (arg.default == undefined)
|
|
1827
|
+
throw new CompilerError(`Missing argument: ${arg.name ?? arg.key}`);
|
|
1828
|
+
handlerParams.push(arg.default);
|
|
1829
|
+
continue;
|
|
1830
|
+
}
|
|
1831
|
+
arg.validate?.(param);
|
|
1832
|
+
handlerParams.push(param);
|
|
1833
|
+
}
|
|
1834
|
+
return handler(key, ...handlerParams);
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
return result;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
class Draw extends ObjectValue {
|
|
1577
1841
|
constructor(scope) {
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1842
|
+
const data = createOverloadNamespace({
|
|
1843
|
+
scope,
|
|
1844
|
+
overloads: {
|
|
1845
|
+
clear: {
|
|
1846
|
+
args: ["r", "g", "b"],
|
|
1847
|
+
},
|
|
1848
|
+
color: {
|
|
1849
|
+
args: ["r", "g", "b", { key: "a", default: "" }],
|
|
1850
|
+
},
|
|
1851
|
+
stroke: {
|
|
1852
|
+
args: ["width"],
|
|
1853
|
+
},
|
|
1854
|
+
line: {
|
|
1855
|
+
named: "options",
|
|
1856
|
+
args: ["x", "y", "x2", "y2"],
|
|
1857
|
+
},
|
|
1858
|
+
rect: {
|
|
1859
|
+
named: "options",
|
|
1860
|
+
args: ["x", "y", "width", "height"],
|
|
1861
|
+
},
|
|
1862
|
+
lineRect: { named: "options", args: ["x", "y", "width", "height"] },
|
|
1863
|
+
linePoly: {
|
|
1864
|
+
named: "options",
|
|
1865
|
+
args: ["x", "y", "sides", "radius", "rotation"],
|
|
1866
|
+
},
|
|
1867
|
+
poly: {
|
|
1868
|
+
named: "options",
|
|
1869
|
+
args: ["x", "y", "sides", "radius", "rotation"],
|
|
1870
|
+
},
|
|
1871
|
+
triangle: {
|
|
1872
|
+
named: "options",
|
|
1873
|
+
args: ["x", "y", "x2", "y2", "x3", "y3"],
|
|
1874
|
+
},
|
|
1875
|
+
image: {
|
|
1876
|
+
named: "options",
|
|
1877
|
+
args: ["x", "y", "image", "size", "rotation"],
|
|
1878
|
+
},
|
|
1879
|
+
},
|
|
1880
|
+
handler(overload, ...args) {
|
|
1881
|
+
return [null, [new InstructionBase("draw", overload, ...args)]];
|
|
1882
|
+
},
|
|
1604
1883
|
});
|
|
1884
|
+
super(scope, data);
|
|
1605
1885
|
}
|
|
1606
1886
|
}
|
|
1607
1887
|
|
|
1608
1888
|
class Print extends MacroFunction {
|
|
1609
1889
|
constructor(scope) {
|
|
1610
1890
|
super(scope, (...values) => {
|
|
1891
|
+
const [first] = values;
|
|
1611
1892
|
const inst = [];
|
|
1612
|
-
|
|
1613
|
-
|
|
1893
|
+
if (!isTemplateObjectArray(first)) {
|
|
1894
|
+
for (const value of values) {
|
|
1895
|
+
inst.push(new InstructionBase("print", value));
|
|
1896
|
+
}
|
|
1897
|
+
return [null, inst];
|
|
1614
1898
|
}
|
|
1899
|
+
// `first` is likely a template strings array
|
|
1900
|
+
// maybe this should be checked in another way?
|
|
1901
|
+
const { length } = first.data;
|
|
1902
|
+
for (let i = 1; i < values.length; i++) {
|
|
1903
|
+
const [string] = first.get(scope, new LiteralValue(scope, i - 1));
|
|
1904
|
+
if (string.data)
|
|
1905
|
+
inst.push(new InstructionBase("print", string));
|
|
1906
|
+
inst.push(new InstructionBase("print", values[i]));
|
|
1907
|
+
}
|
|
1908
|
+
const [tail] = first.get(scope, new LiteralValue(scope, length.data - 1));
|
|
1909
|
+
if (tail.data)
|
|
1910
|
+
inst.push(new InstructionBase("print", tail));
|
|
1615
1911
|
return [null, inst];
|
|
1616
1912
|
});
|
|
1617
1913
|
}
|
|
1618
1914
|
}
|
|
1619
1915
|
|
|
1916
|
+
const defaultTargetName$1 = "message1";
|
|
1620
1917
|
class PrintFlush extends MacroFunction {
|
|
1621
1918
|
constructor(scope) {
|
|
1622
1919
|
super(scope, (target) => {
|
|
1920
|
+
if (!target)
|
|
1921
|
+
return [null, [new InstructionBase("printflush", defaultTargetName$1)]];
|
|
1623
1922
|
if (!(target instanceof SenseableValue))
|
|
1624
1923
|
throw new CompilerError("The printflush target must be a senseable value");
|
|
1625
1924
|
return [null, [new InstructionBase("printflush", target)]];
|
|
@@ -1627,9 +1926,12 @@ class PrintFlush extends MacroFunction {
|
|
|
1627
1926
|
}
|
|
1628
1927
|
}
|
|
1629
1928
|
|
|
1929
|
+
const defaultTargetName = "display1";
|
|
1630
1930
|
class DrawFlush extends MacroFunction {
|
|
1631
1931
|
constructor(scope) {
|
|
1632
1932
|
super(scope, (target) => {
|
|
1933
|
+
if (!target)
|
|
1934
|
+
return [null, [new InstructionBase("drawflush", defaultTargetName)]];
|
|
1633
1935
|
if (!(target instanceof SenseableValue))
|
|
1634
1936
|
throw new CompilerError("The drawflush target must be a senseable value");
|
|
1635
1937
|
return [null, [new InstructionBase("drawflush", target)]];
|
|
@@ -1637,6 +1939,30 @@ class DrawFlush extends MacroFunction {
|
|
|
1637
1939
|
}
|
|
1638
1940
|
}
|
|
1639
1941
|
|
|
1942
|
+
class GetBlock extends ObjectValue {
|
|
1943
|
+
constructor(scope) {
|
|
1944
|
+
const data = createOverloadNamespace({
|
|
1945
|
+
scope,
|
|
1946
|
+
overloads: {
|
|
1947
|
+
floor: { args: ["x", "y"] },
|
|
1948
|
+
ore: { args: ["x", "y"] },
|
|
1949
|
+
block: { args: ["x", "y"] },
|
|
1950
|
+
building: { args: ["x", "y"] },
|
|
1951
|
+
},
|
|
1952
|
+
handler(overload, x, y) {
|
|
1953
|
+
const output = overload === "building"
|
|
1954
|
+
? new SenseableValue(scope)
|
|
1955
|
+
: new StoreValue(scope);
|
|
1956
|
+
return [
|
|
1957
|
+
output,
|
|
1958
|
+
[new InstructionBase("getblock", overload, output, x, y)],
|
|
1959
|
+
];
|
|
1960
|
+
},
|
|
1961
|
+
});
|
|
1962
|
+
super(scope, data);
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1640
1966
|
class GetLink extends MacroFunction {
|
|
1641
1967
|
constructor(scope) {
|
|
1642
1968
|
super(scope, (index) => {
|
|
@@ -1649,21 +1975,27 @@ class GetLink extends MacroFunction {
|
|
|
1649
1975
|
}
|
|
1650
1976
|
}
|
|
1651
1977
|
|
|
1652
|
-
|
|
1653
|
-
class Control extends MacroFunction {
|
|
1978
|
+
class Control extends ObjectValue {
|
|
1654
1979
|
constructor(scope) {
|
|
1655
|
-
super(scope, (
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1980
|
+
super(scope, createOverloadNamespace({
|
|
1981
|
+
scope,
|
|
1982
|
+
overloads: {
|
|
1983
|
+
enabled: { args: ["building", "value"] },
|
|
1984
|
+
shoot: {
|
|
1985
|
+
named: "options",
|
|
1986
|
+
args: ["building", "x", "y", "shoot"],
|
|
1987
|
+
},
|
|
1988
|
+
shootp: {
|
|
1989
|
+
named: "options",
|
|
1990
|
+
args: ["building", "unit", "shoot"],
|
|
1991
|
+
},
|
|
1992
|
+
config: { args: ["building", "value"] },
|
|
1993
|
+
color: { args: ["building", "r", "g", "b"] },
|
|
1994
|
+
},
|
|
1995
|
+
handler(overload, ...args) {
|
|
1996
|
+
return [null, [new InstructionBase("control", overload, ...args)]];
|
|
1997
|
+
},
|
|
1998
|
+
}));
|
|
1667
1999
|
}
|
|
1668
2000
|
}
|
|
1669
2001
|
|
|
@@ -1686,28 +2018,25 @@ const validRadarSorts = [
|
|
|
1686
2018
|
];
|
|
1687
2019
|
class Radar extends MacroFunction {
|
|
1688
2020
|
constructor(scope) {
|
|
1689
|
-
super(scope,
|
|
2021
|
+
super(scope, options => {
|
|
2022
|
+
assertIsObjectMacro(options, "The radar options");
|
|
2023
|
+
const { building, filters, order, sort } = options.data;
|
|
1690
2024
|
if (!(building instanceof SenseableValue))
|
|
1691
2025
|
throw new CompilerError("The building must a senseable value");
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
if (!validRadarFilters.includes(filter3.data))
|
|
1704
|
-
throw new CompilerError("Invalid value for filter3");
|
|
2026
|
+
assertIsArrayMacro(filters, "filters");
|
|
2027
|
+
const { length } = filters.data;
|
|
2028
|
+
if (!(length instanceof LiteralValue) || typeof length.data !== "number")
|
|
2029
|
+
throw new CompilerError("The length of an array macro must be");
|
|
2030
|
+
if (length.data !== 3)
|
|
2031
|
+
throw new CompilerError("The filters array must have 3 items");
|
|
2032
|
+
// data is not an array
|
|
2033
|
+
const { 0: filter1, 1: filter2, 2: filter3 } = filters.data;
|
|
2034
|
+
assertLiteralOneOf(filter1, validRadarFilters, "The first filter");
|
|
2035
|
+
assertLiteralOneOf(filter2, validRadarFilters, "The second filter");
|
|
2036
|
+
assertLiteralOneOf(filter3, validRadarFilters, "The third filter");
|
|
1705
2037
|
if (!(order instanceof LiteralValue || order instanceof StoreValue))
|
|
1706
2038
|
throw new CompilerError("The radar order must be a literal or a store");
|
|
1707
|
-
|
|
1708
|
-
throw new CompilerError("The radar sort must be a string literal");
|
|
1709
|
-
if (!validRadarSorts.includes(sort.data))
|
|
1710
|
-
throw new CompilerError("Invalid sort value");
|
|
2039
|
+
assertLiteralOneOf(sort, validRadarSorts, "The radar sort");
|
|
1711
2040
|
const outUnit = new SenseableValue(scope);
|
|
1712
2041
|
return [
|
|
1713
2042
|
outUnit,
|
|
@@ -1726,7 +2055,9 @@ class Sensor extends MacroFunction {
|
|
|
1726
2055
|
throw new CompilerError("The sensor property must be a store");
|
|
1727
2056
|
if (!(target instanceof SenseableValue))
|
|
1728
2057
|
throw new CompilerError("The sensor target must be a senseable value");
|
|
1729
|
-
const temp = new
|
|
2058
|
+
const temp = assign(new SenseableValue(scope), {
|
|
2059
|
+
mutability: EMutability.readonly,
|
|
2060
|
+
});
|
|
1730
2061
|
return [temp, [new InstructionBase("sensor", temp, target, property)]];
|
|
1731
2062
|
});
|
|
1732
2063
|
}
|
|
@@ -1743,19 +2074,40 @@ class Wait extends MacroFunction {
|
|
|
1743
2074
|
}
|
|
1744
2075
|
}
|
|
1745
2076
|
|
|
1746
|
-
|
|
1747
|
-
class Lookup extends MacroFunction {
|
|
2077
|
+
class Lookup extends ObjectValue {
|
|
1748
2078
|
constructor(scope) {
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
2079
|
+
const data = createOverloadNamespace({
|
|
2080
|
+
scope,
|
|
2081
|
+
overloads: {
|
|
2082
|
+
block: { args: ["index"] },
|
|
2083
|
+
unit: { args: ["index"] },
|
|
2084
|
+
item: { args: ["index"] },
|
|
2085
|
+
liquid: { args: ["index"] },
|
|
2086
|
+
},
|
|
2087
|
+
handler(overload, index) {
|
|
2088
|
+
const output = new StoreValue(scope);
|
|
2089
|
+
return [
|
|
2090
|
+
output,
|
|
2091
|
+
[new InstructionBase("lookup", overload, output, index)],
|
|
2092
|
+
];
|
|
2093
|
+
},
|
|
2094
|
+
});
|
|
2095
|
+
super(scope, data);
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
class PackColor extends MacroFunction {
|
|
2100
|
+
constructor(scope) {
|
|
2101
|
+
super(scope, (...args) => {
|
|
2102
|
+
if (args.length !== 4) {
|
|
2103
|
+
throw new CompilerError(`Expected 4 arguments, received ${args.length}`);
|
|
2104
|
+
}
|
|
2105
|
+
if (!args.every((value) => value instanceof StoreValue ||
|
|
2106
|
+
(value instanceof LiteralValue && typeof value.data === "number"))) {
|
|
2107
|
+
throw new CompilerError("packColor arguments must be either stores or number literals");
|
|
2108
|
+
}
|
|
2109
|
+
const output = new StoreValue(scope);
|
|
2110
|
+
return [output, [new InstructionBase("packcolor", output, ...args)]];
|
|
1759
2111
|
});
|
|
1760
2112
|
}
|
|
1761
2113
|
}
|
|
@@ -1766,6 +2118,57 @@ class End extends MacroFunction {
|
|
|
1766
2118
|
}
|
|
1767
2119
|
}
|
|
1768
2120
|
|
|
2121
|
+
class SetBlock extends ObjectValue {
|
|
2122
|
+
constructor(scope) {
|
|
2123
|
+
const data = createOverloadNamespace({
|
|
2124
|
+
scope,
|
|
2125
|
+
overloads: {
|
|
2126
|
+
floor: { args: ["x", "y", "to"] },
|
|
2127
|
+
ore: { args: ["x", "y", "to"] },
|
|
2128
|
+
block: {
|
|
2129
|
+
named: "options",
|
|
2130
|
+
args: ["x", "y", "to", "team", { key: "rotation", default: "0" }],
|
|
2131
|
+
},
|
|
2132
|
+
},
|
|
2133
|
+
handler(overload, x, y, to, team, rotation) {
|
|
2134
|
+
return [
|
|
2135
|
+
null,
|
|
2136
|
+
[
|
|
2137
|
+
new InstructionBase("setblock", overload, to, x, y, team ?? "@delerict", rotation ?? "0"),
|
|
2138
|
+
],
|
|
2139
|
+
];
|
|
2140
|
+
},
|
|
2141
|
+
});
|
|
2142
|
+
super(scope, data);
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
class SpawnUnit extends MacroFunction {
|
|
2147
|
+
constructor(scope) {
|
|
2148
|
+
super(scope, options => {
|
|
2149
|
+
assertIsObjectMacro(options, "The options");
|
|
2150
|
+
const { type, x, y, team, rotation } = options.data;
|
|
2151
|
+
assertIsRuntimeValue(type, "type");
|
|
2152
|
+
assertIsRuntimeValue(x, "x");
|
|
2153
|
+
assertIsRuntimeValue(y, "y");
|
|
2154
|
+
assertIsRuntimeValue(team, "team");
|
|
2155
|
+
const output = new SenseableValue(scope);
|
|
2156
|
+
return [
|
|
2157
|
+
output,
|
|
2158
|
+
[
|
|
2159
|
+
new InstructionBase("spawn", type, x, y, rotation ?? "0", team, output),
|
|
2160
|
+
],
|
|
2161
|
+
];
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
class Stop extends MacroFunction {
|
|
2167
|
+
constructor(scope) {
|
|
2168
|
+
super(scope, () => [null, [new InstructionBase("stop")]]);
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
|
|
1769
2172
|
class UnitBind extends MacroFunction {
|
|
1770
2173
|
constructor(scope) {
|
|
1771
2174
|
super(scope, type => {
|
|
@@ -1776,82 +2179,85 @@ class UnitBind extends MacroFunction {
|
|
|
1776
2179
|
}
|
|
1777
2180
|
}
|
|
1778
2181
|
|
|
1779
|
-
|
|
1780
|
-
"idle",
|
|
1781
|
-
"stop",
|
|
1782
|
-
"move",
|
|
1783
|
-
"approach",
|
|
1784
|
-
"boost",
|
|
1785
|
-
"pathfind",
|
|
1786
|
-
"target",
|
|
1787
|
-
"targetp",
|
|
1788
|
-
"itemDrop",
|
|
1789
|
-
"itemTake",
|
|
1790
|
-
"payDrop",
|
|
1791
|
-
"payTake",
|
|
1792
|
-
"payEnter",
|
|
1793
|
-
"mine",
|
|
1794
|
-
"flag",
|
|
1795
|
-
"build",
|
|
1796
|
-
"getBlock",
|
|
1797
|
-
"within",
|
|
1798
|
-
];
|
|
1799
|
-
class UnitControl extends MacroFunction {
|
|
2182
|
+
class UnitControl extends ObjectValue {
|
|
1800
2183
|
constructor(scope) {
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
2184
|
+
const data = createOverloadNamespace({
|
|
2185
|
+
scope,
|
|
2186
|
+
overloads: {
|
|
2187
|
+
idle: { args: [] },
|
|
2188
|
+
stop: { args: [] },
|
|
2189
|
+
move: { args: ["x", "y"] },
|
|
2190
|
+
approach: { named: "options", args: ["x", "y", "radius"] },
|
|
2191
|
+
boost: { args: ["enable"] },
|
|
2192
|
+
pathfind: { args: [] },
|
|
2193
|
+
target: { named: "options", args: ["x", "y", "shoot"] },
|
|
2194
|
+
targetp: { named: "options", args: ["unit", "shoot"] },
|
|
2195
|
+
itemDrop: { args: ["target", "amount"] },
|
|
2196
|
+
itemTake: { args: ["target", "item", "amount"] },
|
|
2197
|
+
payDrop: { args: [] },
|
|
2198
|
+
payTake: { named: "options", args: ["takeUnits"] },
|
|
2199
|
+
payEnter: { args: [] },
|
|
2200
|
+
mine: { args: ["x", "y"] },
|
|
2201
|
+
flag: { args: ["value"] },
|
|
2202
|
+
build: {
|
|
2203
|
+
named: "options",
|
|
2204
|
+
args: ["x", "y", "block", "rotation", { key: "config", default: "" }],
|
|
2205
|
+
},
|
|
2206
|
+
getBlock: {
|
|
2207
|
+
args: ["x", "y"],
|
|
2208
|
+
},
|
|
2209
|
+
within: {
|
|
2210
|
+
named: "options",
|
|
2211
|
+
args: ["x", "y", "radius"],
|
|
2212
|
+
},
|
|
2213
|
+
},
|
|
2214
|
+
handler(overload, ...args) {
|
|
2215
|
+
let result = null;
|
|
2216
|
+
let extraArgs = [];
|
|
2217
|
+
switch (overload) {
|
|
2218
|
+
case "getBlock": {
|
|
2219
|
+
const outType = new StoreValue(scope);
|
|
2220
|
+
const outBuilding = new SenseableValue(scope);
|
|
2221
|
+
result = ObjectValue.fromArray(scope, [outType, outBuilding]);
|
|
2222
|
+
extraArgs = [outType, outBuilding, new LiteralValue(scope, 0)];
|
|
2223
|
+
break;
|
|
2224
|
+
}
|
|
2225
|
+
case "within": {
|
|
2226
|
+
const temp = new StoreValue(scope);
|
|
2227
|
+
result = temp;
|
|
2228
|
+
extraArgs = [temp, new LiteralValue(scope, 0)];
|
|
2229
|
+
break;
|
|
2230
|
+
}
|
|
1823
2231
|
}
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
2232
|
+
return [
|
|
2233
|
+
result,
|
|
2234
|
+
[new InstructionBase("ucontrol", overload, ...args, ...extraArgs)],
|
|
2235
|
+
];
|
|
2236
|
+
},
|
|
1829
2237
|
});
|
|
2238
|
+
super(scope, data);
|
|
1830
2239
|
}
|
|
1831
2240
|
}
|
|
1832
2241
|
|
|
1833
2242
|
class UnitRadar extends MacroFunction {
|
|
1834
2243
|
constructor(scope) {
|
|
1835
|
-
super(scope,
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
2244
|
+
super(scope, options => {
|
|
2245
|
+
assertIsObjectMacro(options, "The radar options");
|
|
2246
|
+
const { filters, order, sort } = options.data;
|
|
2247
|
+
assertIsArrayMacro(filters, "filters");
|
|
2248
|
+
const { length } = filters.data;
|
|
2249
|
+
if (!(length instanceof LiteralValue) || typeof length.data !== "number")
|
|
2250
|
+
throw new CompilerError("The length of an array macro must be");
|
|
2251
|
+
if (length.data !== 3)
|
|
2252
|
+
throw new CompilerError("The filters array must have 3 items");
|
|
2253
|
+
// data is not an array
|
|
2254
|
+
const { 0: filter1, 1: filter2, 2: filter3 } = filters.data;
|
|
2255
|
+
assertLiteralOneOf(filter1, validRadarFilters, "The first filter");
|
|
2256
|
+
assertLiteralOneOf(filter2, validRadarFilters, "The second filter");
|
|
2257
|
+
assertLiteralOneOf(filter3, validRadarFilters, "The third filter");
|
|
1849
2258
|
if (!(order instanceof LiteralValue || order instanceof StoreValue))
|
|
1850
2259
|
throw new CompilerError("The radar order must be a literal or a store");
|
|
1851
|
-
|
|
1852
|
-
throw new CompilerError("The radar sort must be a string literal");
|
|
1853
|
-
if (!validRadarSorts.includes(sort.data))
|
|
1854
|
-
throw new CompilerError("Invalid sort value");
|
|
2260
|
+
assertLiteralOneOf(sort, validRadarSorts, "The radar sort");
|
|
1855
2261
|
const outUnit = new SenseableValue(scope);
|
|
1856
2262
|
return [
|
|
1857
2263
|
outUnit,
|
|
@@ -1864,7 +2270,6 @@ class UnitRadar extends MacroFunction {
|
|
|
1864
2270
|
}
|
|
1865
2271
|
}
|
|
1866
2272
|
|
|
1867
|
-
const validFinds = ["ore", "building", "spawn", "damaged"];
|
|
1868
2273
|
const validBuildingGroups = [
|
|
1869
2274
|
"core",
|
|
1870
2275
|
"storage",
|
|
@@ -1876,56 +2281,297 @@ const validBuildingGroups = [
|
|
|
1876
2281
|
"battery",
|
|
1877
2282
|
"reactor",
|
|
1878
2283
|
];
|
|
1879
|
-
class UnitLocate extends
|
|
2284
|
+
class UnitLocate extends ObjectValue {
|
|
1880
2285
|
constructor(scope) {
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
2286
|
+
const data = createOverloadNamespace({
|
|
2287
|
+
scope,
|
|
2288
|
+
overloads: {
|
|
2289
|
+
ore: {
|
|
2290
|
+
args: ["ore"],
|
|
2291
|
+
},
|
|
2292
|
+
building: { named: "options", args: ["group", "enemy"] },
|
|
2293
|
+
spawn: {
|
|
2294
|
+
args: [],
|
|
2295
|
+
},
|
|
2296
|
+
damaged: {
|
|
2297
|
+
args: [],
|
|
2298
|
+
},
|
|
2299
|
+
},
|
|
2300
|
+
handler(overload, ...args) {
|
|
2301
|
+
const outFound = new StoreValue(scope);
|
|
2302
|
+
const outX = new StoreValue(scope);
|
|
2303
|
+
const outY = new StoreValue(scope);
|
|
2304
|
+
const outBuilding = new SenseableValue(scope);
|
|
2305
|
+
const outArgs = [outX, outY, outFound, outBuilding];
|
|
2306
|
+
let inputArgs = [];
|
|
2307
|
+
switch (overload) {
|
|
2308
|
+
case "ore": {
|
|
2309
|
+
const [ore] = args;
|
|
2310
|
+
inputArgs = [overload, "core", "true", ore];
|
|
2311
|
+
break;
|
|
2312
|
+
}
|
|
2313
|
+
case "building": {
|
|
2314
|
+
const [group, enemy] = args;
|
|
2315
|
+
if (!(group instanceof LiteralValue))
|
|
2316
|
+
throw new CompilerError("The building group must be a string literal");
|
|
2317
|
+
assertLiteralOneOf(group, validBuildingGroups, "The building group");
|
|
2318
|
+
inputArgs = [overload, group.data, enemy, "@copper"];
|
|
2319
|
+
break;
|
|
2320
|
+
}
|
|
2321
|
+
case "spawn":
|
|
2322
|
+
case "damaged": {
|
|
2323
|
+
inputArgs = [overload, "core", "true", "@copper"];
|
|
2324
|
+
break;
|
|
1904
2325
|
}
|
|
1905
|
-
if (!validBuildingGroups.includes(group.data))
|
|
1906
|
-
throw new CompilerError("Invalid building group");
|
|
1907
|
-
inputArgs = [find.data, group.data, enemy, "@copper"];
|
|
1908
|
-
break;
|
|
1909
|
-
}
|
|
1910
|
-
case "spawn":
|
|
1911
|
-
case "damaged": {
|
|
1912
|
-
inputArgs = [find.data, "core", "true", "@copper"];
|
|
1913
|
-
break;
|
|
1914
2326
|
}
|
|
1915
|
-
|
|
2327
|
+
return [
|
|
2328
|
+
ObjectValue.fromArray(scope, [
|
|
2329
|
+
outFound,
|
|
2330
|
+
outX,
|
|
2331
|
+
outY,
|
|
2332
|
+
...(overload !== "ore" ? [outBuilding] : []),
|
|
2333
|
+
]),
|
|
2334
|
+
[new InstructionBase("ulocate", ...inputArgs, ...outArgs)],
|
|
2335
|
+
];
|
|
2336
|
+
},
|
|
2337
|
+
});
|
|
2338
|
+
super(scope, data);
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
const validEffects = [
|
|
2343
|
+
"burning",
|
|
2344
|
+
"freezing",
|
|
2345
|
+
"unmoving",
|
|
2346
|
+
"wet",
|
|
2347
|
+
"melting",
|
|
2348
|
+
"sapped",
|
|
2349
|
+
"electrified",
|
|
2350
|
+
"spore-slowed",
|
|
2351
|
+
"tarred",
|
|
2352
|
+
"overdrive",
|
|
2353
|
+
"overclock",
|
|
2354
|
+
"boss",
|
|
2355
|
+
"shocked",
|
|
2356
|
+
"blasted",
|
|
2357
|
+
];
|
|
2358
|
+
class ApplyStatus extends ObjectValue {
|
|
2359
|
+
constructor(scope) {
|
|
2360
|
+
const data = createOverloadNamespace({
|
|
2361
|
+
scope,
|
|
2362
|
+
overloads: {
|
|
2363
|
+
apply: {
|
|
2364
|
+
args: ["status", "unit", { key: "duration", default: "10" }],
|
|
2365
|
+
},
|
|
2366
|
+
clear: { args: ["status", "unit"] },
|
|
2367
|
+
},
|
|
2368
|
+
handler(overload, effect, unit, duration) {
|
|
2369
|
+
if (!(effect instanceof LiteralValue))
|
|
2370
|
+
throw new CompilerError("The status effect must be a string literal");
|
|
2371
|
+
assertLiteralOneOf(effect, validEffects, "The status effect");
|
|
2372
|
+
return [
|
|
2373
|
+
null,
|
|
2374
|
+
[
|
|
2375
|
+
new InstructionBase("status", String(overload !== "apply"), effect.data, unit, duration),
|
|
2376
|
+
],
|
|
2377
|
+
];
|
|
2378
|
+
},
|
|
2379
|
+
});
|
|
2380
|
+
super(scope, data);
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
class SpawnWave extends MacroFunction {
|
|
2385
|
+
constructor(scope) {
|
|
2386
|
+
super(scope, (natural, x, y) => {
|
|
2387
|
+
if (!(natural instanceof LiteralValue) ||
|
|
2388
|
+
(natural.data !== 1 && natural.data !== 0))
|
|
2389
|
+
throw new CompilerError("The 'natural' argument must be a boolean literal");
|
|
1916
2390
|
return [
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
...(find.data !== "ore" ? [outBuilding] : []),
|
|
1922
|
-
]),
|
|
1923
|
-
[new InstructionBase("ulocate", ...inputArgs, ...outArgs)],
|
|
2391
|
+
null,
|
|
2392
|
+
[
|
|
2393
|
+
new InstructionBase("spawnwave", x ?? "10", y ?? "10", String(!!natural.data)),
|
|
2394
|
+
],
|
|
1924
2395
|
];
|
|
1925
2396
|
});
|
|
1926
2397
|
}
|
|
1927
2398
|
}
|
|
1928
2399
|
|
|
2400
|
+
class SetRule extends ObjectValue {
|
|
2401
|
+
constructor(scope) {
|
|
2402
|
+
const data = createOverloadNamespace({
|
|
2403
|
+
scope,
|
|
2404
|
+
overloads: {
|
|
2405
|
+
currentWaveTime: { args: ["seconds"] },
|
|
2406
|
+
waveTimer: { args: ["enabled"] },
|
|
2407
|
+
waves: { args: ["enabled"] },
|
|
2408
|
+
wave: { args: ["number"] },
|
|
2409
|
+
waveSpacing: { args: ["seconds"] },
|
|
2410
|
+
waveSending: { args: ["enabled"] },
|
|
2411
|
+
attackMode: { args: ["enabled"] },
|
|
2412
|
+
enemyCoreBuildRadius: { args: ["radius"] },
|
|
2413
|
+
dropZoneRadius: { args: ["radius"] },
|
|
2414
|
+
unitCap: { args: ["cap"] },
|
|
2415
|
+
mapArea: { named: "options", args: ["x", "y", "width", "height"] },
|
|
2416
|
+
lighting: { args: ["enabled"] },
|
|
2417
|
+
ambientLight: { args: ["rgbaData"] },
|
|
2418
|
+
solarMultiplier: { args: ["multiplier"] },
|
|
2419
|
+
buildSpeed: { args: ["team", "multiplier"] },
|
|
2420
|
+
unitBuildSpeed: { args: ["team", "multiplier"] },
|
|
2421
|
+
unitDamage: { args: ["team", "multiplier"] },
|
|
2422
|
+
blockHealth: { args: ["team", "multiplier"] },
|
|
2423
|
+
blockDamage: { args: ["team", "multiplier"] },
|
|
2424
|
+
rtsMinWeight: { args: ["team", "value"] },
|
|
2425
|
+
rtsMinSquad: { args: ["team", "value"] },
|
|
2426
|
+
},
|
|
2427
|
+
handler(overload, ...args) {
|
|
2428
|
+
const params = ["10", "0", "0", "100", "100"];
|
|
2429
|
+
switch (overload) {
|
|
2430
|
+
case "mapArea": {
|
|
2431
|
+
const [x, y, width, height] = args;
|
|
2432
|
+
params[1] = x;
|
|
2433
|
+
params[2] = y;
|
|
2434
|
+
params[3] = width;
|
|
2435
|
+
params[4] = height;
|
|
2436
|
+
break;
|
|
2437
|
+
}
|
|
2438
|
+
case "buildSpeed":
|
|
2439
|
+
case "unitBuildSpeed":
|
|
2440
|
+
case "unitDamage":
|
|
2441
|
+
case "blockHealth":
|
|
2442
|
+
case "blockDamage":
|
|
2443
|
+
case "rtsMinWeight":
|
|
2444
|
+
case "rtsMinSquad": {
|
|
2445
|
+
const [team, value] = args;
|
|
2446
|
+
params[1] = team;
|
|
2447
|
+
params[2] = value;
|
|
2448
|
+
break;
|
|
2449
|
+
}
|
|
2450
|
+
default:
|
|
2451
|
+
params[0] = args[0]; // the general value
|
|
2452
|
+
}
|
|
2453
|
+
return [null, [new InstructionBase("setrule", overload, ...params)]];
|
|
2454
|
+
},
|
|
2455
|
+
});
|
|
2456
|
+
super(scope, data);
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
class FlushMessage extends ObjectValue {
|
|
2461
|
+
constructor(scope) {
|
|
2462
|
+
const data = createOverloadNamespace({
|
|
2463
|
+
scope,
|
|
2464
|
+
overloads: {
|
|
2465
|
+
notify: { args: [] },
|
|
2466
|
+
mission: { args: [] },
|
|
2467
|
+
announce: { args: ["duration"] },
|
|
2468
|
+
toast: { args: ["duration"] },
|
|
2469
|
+
},
|
|
2470
|
+
handler(overload, duration) {
|
|
2471
|
+
return [null, [new InstructionBase("message", overload, duration)]];
|
|
2472
|
+
},
|
|
2473
|
+
});
|
|
2474
|
+
super(scope, data);
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
class Cutscene extends ObjectValue {
|
|
2479
|
+
constructor(scope) {
|
|
2480
|
+
const data = createOverloadNamespace({
|
|
2481
|
+
scope,
|
|
2482
|
+
overloads: {
|
|
2483
|
+
pan: { named: "options", args: ["x", "y", "speed"] },
|
|
2484
|
+
zoom: { args: ["level"] },
|
|
2485
|
+
stop: { args: [] },
|
|
2486
|
+
},
|
|
2487
|
+
handler(overload, ...args) {
|
|
2488
|
+
const params = Object.assign(["100", "100", "0.06", "0"], args);
|
|
2489
|
+
return [null, [new InstructionBase("cutscene", overload, ...params)]];
|
|
2490
|
+
},
|
|
2491
|
+
});
|
|
2492
|
+
super(scope, data);
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
class Explosion extends MacroFunction {
|
|
2497
|
+
constructor(scope) {
|
|
2498
|
+
super(scope, options => {
|
|
2499
|
+
assertIsObjectMacro(options, "The options");
|
|
2500
|
+
const params = assertObjectFields(options, [
|
|
2501
|
+
"team",
|
|
2502
|
+
"x",
|
|
2503
|
+
"y",
|
|
2504
|
+
"radius",
|
|
2505
|
+
"damage",
|
|
2506
|
+
"air",
|
|
2507
|
+
"ground",
|
|
2508
|
+
"pierce",
|
|
2509
|
+
]);
|
|
2510
|
+
return [null, [new InstructionBase("explosion", ...params)]];
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
class SetRate extends MacroFunction {
|
|
2516
|
+
constructor(scope) {
|
|
2517
|
+
super(scope, ipt => [null, [new InstructionBase("setrate", ipt)]]);
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
class Fetch extends ObjectValue {
|
|
2522
|
+
constructor(scope) {
|
|
2523
|
+
const data = createOverloadNamespace({
|
|
2524
|
+
scope,
|
|
2525
|
+
overloads: {
|
|
2526
|
+
unit: { args: ["team", "index"] },
|
|
2527
|
+
unitCount: { args: ["team"] },
|
|
2528
|
+
player: { args: ["team", "index"] },
|
|
2529
|
+
playerCount: { args: ["team"] },
|
|
2530
|
+
core: { args: ["team", "index"] },
|
|
2531
|
+
coreCount: { args: ["team"] },
|
|
2532
|
+
build: { args: ["team", "index", "block"] },
|
|
2533
|
+
buildCount: { args: ["team", "block"] },
|
|
2534
|
+
},
|
|
2535
|
+
handler(overload, team, ...rest) {
|
|
2536
|
+
const output = new SenseableValue(scope);
|
|
2537
|
+
const params = ["0", "@conveyor"];
|
|
2538
|
+
if (overload === "buildCount") {
|
|
2539
|
+
params[1] = rest[0];
|
|
2540
|
+
}
|
|
2541
|
+
else {
|
|
2542
|
+
Object.assign(params, rest);
|
|
2543
|
+
}
|
|
2544
|
+
return [
|
|
2545
|
+
output,
|
|
2546
|
+
[new InstructionBase("fetch", overload, output, team, ...params)],
|
|
2547
|
+
];
|
|
2548
|
+
},
|
|
2549
|
+
});
|
|
2550
|
+
super(scope, data);
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
class GetFlag extends MacroFunction {
|
|
2555
|
+
constructor(scope) {
|
|
2556
|
+
super(scope, flag => {
|
|
2557
|
+
const result = new StoreValue(scope);
|
|
2558
|
+
return [result, [new InstructionBase("getflag", result, flag)]];
|
|
2559
|
+
});
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
class SetFlag extends MacroFunction {
|
|
2564
|
+
constructor(scope) {
|
|
2565
|
+
super(scope, (flag, value) => {
|
|
2566
|
+
if (!flag)
|
|
2567
|
+
throw new CompilerError("Missing flag argument");
|
|
2568
|
+
if (!value)
|
|
2569
|
+
throw new CompilerError("Missing flag value");
|
|
2570
|
+
return [null, [new InstructionBase("setflag", flag, value)]];
|
|
2571
|
+
});
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
|
|
1929
2575
|
class MemoryEntry extends ObjectValue {
|
|
1930
2576
|
constructor(scope, mem, prop) {
|
|
1931
2577
|
super(scope, {
|
|
@@ -2040,24 +2686,6 @@ class VarsNamespace extends NamespaceMacro {
|
|
|
2040
2686
|
}).value,
|
|
2041
2687
|
});
|
|
2042
2688
|
}
|
|
2043
|
-
}
|
|
2044
|
-
class UCommandsNamespace extends NamespaceMacro {
|
|
2045
|
-
constructor(scope) {
|
|
2046
|
-
super(scope);
|
|
2047
|
-
this.data.$get = new MacroFunction(scope, prop => {
|
|
2048
|
-
if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
|
|
2049
|
-
throw new CompilerError("Cannot use dynamic properties on namespace macros");
|
|
2050
|
-
const symbolName = prop.data[0].toUpperCase() + prop.data.slice(1);
|
|
2051
|
-
const owner = new ValueOwner({
|
|
2052
|
-
scope,
|
|
2053
|
-
name: `@command${symbolName}`,
|
|
2054
|
-
value: assign(new StoreValue(scope), {
|
|
2055
|
-
mutability: EMutability.constant,
|
|
2056
|
-
}),
|
|
2057
|
-
});
|
|
2058
|
-
return [owner.value, []];
|
|
2059
|
-
});
|
|
2060
|
-
}
|
|
2061
2689
|
}
|
|
2062
2690
|
|
|
2063
2691
|
class GetGlobal extends MacroFunction {
|
|
@@ -2077,6 +2705,25 @@ class GetGlobal extends MacroFunction {
|
|
|
2077
2705
|
}
|
|
2078
2706
|
}
|
|
2079
2707
|
|
|
2708
|
+
class Asm extends MacroFunction {
|
|
2709
|
+
constructor(scope) {
|
|
2710
|
+
super(scope, (stringsArray, ...values) => {
|
|
2711
|
+
if (!isTemplateObjectArray(stringsArray))
|
|
2712
|
+
throw new CompilerError("Expected to receive a template strings array");
|
|
2713
|
+
const args = [];
|
|
2714
|
+
for (let i = 0; i < values.length; i++) {
|
|
2715
|
+
const [item] = stringsArray.get(scope, new LiteralValue(scope, i));
|
|
2716
|
+
args.push(item.data);
|
|
2717
|
+
args.push(values[i]);
|
|
2718
|
+
}
|
|
2719
|
+
const { length } = stringsArray.data;
|
|
2720
|
+
const [tail] = stringsArray.get(scope, new LiteralValue(scope, length.data - 1));
|
|
2721
|
+
args.push(tail.data);
|
|
2722
|
+
return [null, [new ZeroSpaceInstruction(...args)]];
|
|
2723
|
+
});
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2080
2727
|
/**
|
|
2081
2728
|
* Adds all the compiler globals to `scope`
|
|
2082
2729
|
*/
|
|
@@ -2084,16 +2731,17 @@ function initScope(scope) {
|
|
|
2084
2731
|
// namespaces
|
|
2085
2732
|
scope.hardSet("ControlKind", new NamespaceMacro(scope));
|
|
2086
2733
|
scope.hardSet("Vars", new VarsNamespace(scope));
|
|
2734
|
+
scope.hardSet("Teams", new NamespaceMacro(scope));
|
|
2087
2735
|
scope.hardSet("Items", new NamespaceMacro(scope, { changeCasing: true }));
|
|
2088
2736
|
scope.hardSet("Liquids", new NamespaceMacro(scope));
|
|
2089
|
-
scope.hardSet("Units", new NamespaceMacro(scope));
|
|
2737
|
+
scope.hardSet("Units", new NamespaceMacro(scope, { changeCasing: true }));
|
|
2090
2738
|
scope.hardSet("LAccess", new NamespaceMacro(scope));
|
|
2091
|
-
scope.hardSet("UnitCommands", new UCommandsNamespace(scope));
|
|
2092
2739
|
scope.hardSet("Blocks", new NamespaceMacro(scope, { changeCasing: true }));
|
|
2093
2740
|
// helper methods
|
|
2094
2741
|
scope.hardSet("getBuilding", new GetGlobal(scope, EMutability.constant));
|
|
2095
2742
|
scope.hardSet("getVar", new GetGlobal(scope, EMutability.mutable));
|
|
2096
2743
|
scope.hardSet("concat", new Concat(scope));
|
|
2744
|
+
scope.hardSet("asm", new Asm(scope));
|
|
2097
2745
|
scope.hardSet("Math", new MlogMath(scope));
|
|
2098
2746
|
scope.hardSet("Memory", new MemoryBuilder(scope));
|
|
2099
2747
|
// commands
|
|
@@ -2107,36 +2755,58 @@ function initScope(scope) {
|
|
|
2107
2755
|
scope.hardSet("sensor", new Sensor(scope));
|
|
2108
2756
|
scope.hardSet("wait", new Wait(scope));
|
|
2109
2757
|
scope.hardSet("lookup", new Lookup(scope));
|
|
2758
|
+
scope.hardSet("packColor", new PackColor(scope));
|
|
2110
2759
|
scope.hardSet("endScript", new End(scope));
|
|
2760
|
+
scope.hardSet("stopScript", new Stop(scope));
|
|
2111
2761
|
scope.hardSet("unitBind", new UnitBind(scope));
|
|
2112
2762
|
scope.hardSet("unitControl", new UnitControl(scope));
|
|
2113
2763
|
scope.hardSet("unitRadar", new UnitRadar(scope));
|
|
2114
2764
|
scope.hardSet("unitLocate", new UnitLocate(scope));
|
|
2765
|
+
// world processor commands
|
|
2766
|
+
scope.hardSet("getBlock", new GetBlock(scope));
|
|
2767
|
+
scope.hardSet("setBlock", new SetBlock(scope));
|
|
2768
|
+
scope.hardSet("spawnUnit", new SpawnUnit(scope));
|
|
2769
|
+
scope.hardSet("applyStatus", new ApplyStatus(scope));
|
|
2770
|
+
scope.hardSet("spawnWave", new SpawnWave(scope));
|
|
2771
|
+
scope.hardSet("setRule", new SetRule(scope));
|
|
2772
|
+
scope.hardSet("flushMessage", new FlushMessage(scope));
|
|
2773
|
+
scope.hardSet("cutscene", new Cutscene(scope));
|
|
2774
|
+
scope.hardSet("explosion", new Explosion(scope));
|
|
2775
|
+
scope.hardSet("setRate", new SetRate(scope));
|
|
2776
|
+
scope.hardSet("fetch", new Fetch(scope));
|
|
2777
|
+
scope.hardSet("getFlag", new GetFlag(scope));
|
|
2778
|
+
scope.hardSet("setFlag", new SetFlag(scope));
|
|
2115
2779
|
}
|
|
2116
2780
|
|
|
2117
2781
|
class Compiler {
|
|
2118
|
-
constructor({ stackName, compactNames = false } = {}) {
|
|
2782
|
+
constructor({ stackName, compactNames = false, sourcemap = false, } = {}) {
|
|
2119
2783
|
this.handlers = handlers;
|
|
2120
2784
|
this.usingStack = !!stackName;
|
|
2121
2785
|
this.stackName = stackName;
|
|
2122
2786
|
this.compactNames = compactNames;
|
|
2787
|
+
this.sourcemap = sourcemap;
|
|
2123
2788
|
}
|
|
2124
2789
|
compile(script) {
|
|
2125
2790
|
let output;
|
|
2791
|
+
let sourcemaps;
|
|
2126
2792
|
try {
|
|
2127
2793
|
const program = this.parse(script);
|
|
2128
2794
|
const scope = new Scope({});
|
|
2129
2795
|
initScope(scope);
|
|
2130
2796
|
const valueInst = this.handle(scope, program);
|
|
2131
2797
|
valueInst[1].push(new EndInstruction(), ...scope.inst);
|
|
2798
|
+
hideRedundantJumps(valueInst[1]);
|
|
2132
2799
|
this.resolve(valueInst);
|
|
2133
2800
|
output = this.serialize(valueInst) + "\n";
|
|
2801
|
+
if (this.sourcemap) {
|
|
2802
|
+
sourcemaps = this.mapSources(valueInst);
|
|
2803
|
+
}
|
|
2134
2804
|
}
|
|
2135
2805
|
catch (error) {
|
|
2136
|
-
const
|
|
2137
|
-
return [null,
|
|
2806
|
+
const err = error instanceof CompilerError ? error : CompilerError.from(error);
|
|
2807
|
+
return [null, err];
|
|
2138
2808
|
}
|
|
2139
|
-
return [output, null,
|
|
2809
|
+
return [output, null, sourcemaps];
|
|
2140
2810
|
}
|
|
2141
2811
|
resolve(valueInst) {
|
|
2142
2812
|
let i = 0;
|
|
@@ -2156,40 +2826,92 @@ class Compiler {
|
|
|
2156
2826
|
plugins: ["typescript"],
|
|
2157
2827
|
});
|
|
2158
2828
|
}
|
|
2159
|
-
|
|
2829
|
+
mapSources(valueInst) {
|
|
2830
|
+
const result = [];
|
|
2831
|
+
for (const inst of valueInst[1]) {
|
|
2832
|
+
if (!inst.hidden)
|
|
2833
|
+
result.push(inst.source);
|
|
2834
|
+
}
|
|
2835
|
+
return result;
|
|
2836
|
+
}
|
|
2837
|
+
handle(scope, node, handler = this.handlers[node.type]) {
|
|
2160
2838
|
try {
|
|
2161
|
-
const handler = this.handlers[node.type];
|
|
2162
2839
|
if (!handler)
|
|
2163
2840
|
throw new CompilerError("Missing handler for " + node.type);
|
|
2164
|
-
|
|
2841
|
+
const result = handler(this, scope, node, null);
|
|
2842
|
+
if (this.sourcemap)
|
|
2843
|
+
return appendSourceLocations(result, node);
|
|
2844
|
+
return result;
|
|
2165
2845
|
}
|
|
2166
2846
|
catch (error) {
|
|
2167
2847
|
if (error instanceof CompilerError) {
|
|
2168
|
-
error.
|
|
2848
|
+
error.loc ??= node.loc;
|
|
2169
2849
|
}
|
|
2170
2850
|
throw error;
|
|
2171
2851
|
}
|
|
2172
2852
|
}
|
|
2173
2853
|
handleEval(scope, node) {
|
|
2174
2854
|
const [res, inst] = this.handle(scope, node);
|
|
2175
|
-
|
|
2855
|
+
if (!res)
|
|
2856
|
+
throw new CompilerError("Cannot eval null", node);
|
|
2176
2857
|
const [evaluated, evaluatedInst] = res.eval(scope);
|
|
2177
|
-
|
|
2858
|
+
const result = [evaluated, [...inst, ...evaluatedInst]];
|
|
2859
|
+
if (this.sourcemap)
|
|
2860
|
+
return appendSourceLocations(result, node);
|
|
2861
|
+
return result;
|
|
2178
2862
|
}
|
|
2179
2863
|
handleConsume(scope, node) {
|
|
2180
2864
|
const [res, inst] = this.handle(scope, node);
|
|
2181
|
-
|
|
2865
|
+
if (!res)
|
|
2866
|
+
throw new CompilerError("Cannot consume null", node);
|
|
2182
2867
|
const [evaluated, evaluatedInst] = res.consume(scope);
|
|
2183
|
-
|
|
2868
|
+
const result = [evaluated, [...inst, ...evaluatedInst]];
|
|
2869
|
+
if (this.sourcemap)
|
|
2870
|
+
return appendSourceLocations(result, node);
|
|
2871
|
+
return result;
|
|
2184
2872
|
}
|
|
2185
|
-
|
|
2873
|
+
/**
|
|
2874
|
+
* Handles many nodes in order.
|
|
2875
|
+
*
|
|
2876
|
+
* The usage of this method over a regular loop over an array of nodes
|
|
2877
|
+
* is only required if the code inside the loop generates
|
|
2878
|
+
* instructions that are not tracked by the compiler
|
|
2879
|
+
* handler methods ({@link handle}, {@link handleEval}, {@link handleConsume}
|
|
2880
|
+
* and {@link handleMany})
|
|
2881
|
+
*
|
|
2882
|
+
*/
|
|
2883
|
+
handleMany(scope, nodes, handler) {
|
|
2186
2884
|
const lines = [];
|
|
2187
2885
|
for (const node of nodes) {
|
|
2188
|
-
const [, nodeLines] =
|
|
2886
|
+
const [, nodeLines] = this.handle(scope, node, handler && (() => handler(node)));
|
|
2189
2887
|
lines.push(...nodeLines);
|
|
2190
2888
|
}
|
|
2191
2889
|
return [null, lines];
|
|
2192
2890
|
}
|
|
2891
|
+
}
|
|
2892
|
+
/** Removes jump instructions that point right to the next line */
|
|
2893
|
+
function hideRedundantJumps(inst) {
|
|
2894
|
+
for (let i = 0; i < inst.length; i++) {
|
|
2895
|
+
const instruction = inst[i];
|
|
2896
|
+
if (!(instruction instanceof JumpInstruction))
|
|
2897
|
+
continue;
|
|
2898
|
+
const { address } = instruction;
|
|
2899
|
+
let searchIndex = i + 1;
|
|
2900
|
+
let current = inst[searchIndex];
|
|
2901
|
+
while (current.hidden) {
|
|
2902
|
+
if (current instanceof AddressResolver &&
|
|
2903
|
+
current.bonds.includes(address)) {
|
|
2904
|
+
// only gets assigned if `current` is an adress resolver
|
|
2905
|
+
// that resolves the jump adress
|
|
2906
|
+
// and that is also right next to the jump,
|
|
2907
|
+
// without any actual instructions in between
|
|
2908
|
+
instruction.hidden = true;
|
|
2909
|
+
break;
|
|
2910
|
+
}
|
|
2911
|
+
searchIndex++;
|
|
2912
|
+
current = inst[searchIndex];
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2193
2915
|
}
|
|
2194
2916
|
|
|
2195
2917
|
export { Compiler, CompilerError };
|