mlogjs 0.3.0-beta.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 +1096 -341
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +1096 -341
- 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/GetGlobal.d.ts +2 -2
- 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 +30 -1
- package/dist/types/utils.d.ts +24 -1
- package/dist/types/values/BaseValue.d.ts +2 -0
- package/dist/types/values/FunctionValue.d.ts +3 -3
- package/dist/types/values/LiteralValue.d.ts +2 -2
- package/dist/types/values/ObjectValue.d.ts +3 -3
- package/dist/types/values/SenseableValue.d.ts +5 -5
- package/dist/types/values/StoreValue.d.ts +2 -2
- package/dist/types/values/VoidValue.d.ts +2 -2
- 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,75 @@ 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 = {}));
|
|
57
|
+
/** Defines the possible types of mutability of a value */
|
|
58
|
+
var EMutability;
|
|
59
|
+
(function (EMutability) {
|
|
60
|
+
/**
|
|
61
|
+
* The value can be changed by the user's code,
|
|
62
|
+
* by the mlog runtime, or us
|
|
63
|
+
*/
|
|
64
|
+
EMutability[EMutability["mutable"] = 0] = "mutable";
|
|
65
|
+
/**
|
|
66
|
+
* The value cannot be directly assigned,
|
|
67
|
+
* but it's still not safe from mutations coming from the runtime.
|
|
68
|
+
*/
|
|
69
|
+
EMutability[EMutability["readonly"] = 1] = "readonly";
|
|
70
|
+
/** Constant values, won't change during execution */
|
|
71
|
+
EMutability[EMutability["constant"] = 2] = "constant";
|
|
72
|
+
})(EMutability || (EMutability = {}));
|
|
73
|
+
|
|
11
74
|
const arithmeticBinaryOperators = [
|
|
12
75
|
"*",
|
|
13
76
|
"**",
|
|
@@ -86,7 +149,7 @@ const operators = [...leftRightOperators, ...singleOperators];
|
|
|
86
149
|
class VoidValue {
|
|
87
150
|
constructor(scope) {
|
|
88
151
|
this.owner = null;
|
|
89
|
-
this.
|
|
152
|
+
this.mutability = EMutability.mutable;
|
|
90
153
|
this.macro = false;
|
|
91
154
|
this.scope = scope;
|
|
92
155
|
}
|
|
@@ -118,6 +181,8 @@ for (const key of operators) {
|
|
|
118
181
|
|
|
119
182
|
class InstructionBase {
|
|
120
183
|
constructor(...args) {
|
|
184
|
+
this.intent = EInstIntent.none;
|
|
185
|
+
this.alwaysRuns = true;
|
|
121
186
|
this._hidden = false;
|
|
122
187
|
this.args = args;
|
|
123
188
|
}
|
|
@@ -194,6 +259,7 @@ var EJumpKind;
|
|
|
194
259
|
class JumpInstruction extends InstructionBase {
|
|
195
260
|
constructor(address, kind, left = null, right = null) {
|
|
196
261
|
super("jump", address, kind, left, right);
|
|
262
|
+
this.address = address;
|
|
197
263
|
}
|
|
198
264
|
}
|
|
199
265
|
|
|
@@ -212,11 +278,13 @@ class ZeroSpaceInstruction extends InstructionBase {
|
|
|
212
278
|
class BreakInstruction extends JumpInstruction {
|
|
213
279
|
constructor(address) {
|
|
214
280
|
super(address, EJumpKind.Always);
|
|
281
|
+
this.intent = EInstIntent.break;
|
|
215
282
|
}
|
|
216
283
|
}
|
|
217
284
|
class ContinueInstruction extends JumpInstruction {
|
|
218
285
|
constructor(address) {
|
|
219
286
|
super(address, EJumpKind.Always);
|
|
287
|
+
this.intent = EInstIntent.continue;
|
|
220
288
|
}
|
|
221
289
|
}
|
|
222
290
|
|
|
@@ -268,6 +336,20 @@ class BaseValue extends VoidValue {
|
|
|
268
336
|
// TODO: should it return 0 + this ?
|
|
269
337
|
return this.eval(scope);
|
|
270
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
|
+
}
|
|
271
353
|
ensureOwned() {
|
|
272
354
|
this.owner ??= new ValueOwner({ scope: this.scope, value: this });
|
|
273
355
|
}
|
|
@@ -312,18 +394,6 @@ for (const key in operatorMap$1) {
|
|
|
312
394
|
];
|
|
313
395
|
};
|
|
314
396
|
}
|
|
315
|
-
const unaryOperatorMap$1 = {
|
|
316
|
-
"!": "not",
|
|
317
|
-
"~": "flip",
|
|
318
|
-
};
|
|
319
|
-
for (const key in unaryOperatorMap$1) {
|
|
320
|
-
const name = unaryOperatorMap$1[key];
|
|
321
|
-
BaseValue.prototype[key] = function (scope) {
|
|
322
|
-
const [that, inst] = this.consume(scope);
|
|
323
|
-
const temp = new StoreValue(scope);
|
|
324
|
-
return [temp, [...inst, new OperationInstruction(name, temp, that, null)]];
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
397
|
const assignmentToBinary = {
|
|
328
398
|
"+=": "+",
|
|
329
399
|
"-=": "-",
|
|
@@ -375,7 +445,7 @@ const literalMethods = {
|
|
|
375
445
|
class LiteralValue extends BaseValue {
|
|
376
446
|
constructor(scope, data) {
|
|
377
447
|
super(scope);
|
|
378
|
-
this.
|
|
448
|
+
this.mutability = EMutability.constant;
|
|
379
449
|
this.data = data;
|
|
380
450
|
}
|
|
381
451
|
eval(_scope) {
|
|
@@ -436,18 +506,22 @@ for (const key in operatorMap) {
|
|
|
436
506
|
if (!(value instanceof LiteralValue)) {
|
|
437
507
|
return BaseValue.prototype[key].apply(this, [scope, value]);
|
|
438
508
|
}
|
|
439
|
-
return [
|
|
509
|
+
return [
|
|
510
|
+
new LiteralValue(scope, fn(this.data, value.data)),
|
|
511
|
+
[],
|
|
512
|
+
];
|
|
440
513
|
};
|
|
441
514
|
}
|
|
442
515
|
const unaryOperatorMap = {
|
|
443
516
|
"!": v => +!v,
|
|
444
517
|
"~": v => ~v,
|
|
445
518
|
"u-": v => -v,
|
|
519
|
+
"u+": v => +v,
|
|
446
520
|
};
|
|
447
521
|
for (const key in unaryOperatorMap) {
|
|
448
522
|
LiteralValue.prototype[key] = function (scope) {
|
|
449
523
|
const fn = unaryOperatorMap[key];
|
|
450
|
-
return [new LiteralValue(scope, fn(this.
|
|
524
|
+
return [new LiteralValue(scope, fn(this.data)), []];
|
|
451
525
|
};
|
|
452
526
|
}
|
|
453
527
|
|
|
@@ -498,7 +572,33 @@ const itemNames = [
|
|
|
498
572
|
"sporePod",
|
|
499
573
|
"blastCompound",
|
|
500
574
|
"pyratite",
|
|
501
|
-
];
|
|
575
|
+
];
|
|
576
|
+
/**
|
|
577
|
+
* A more type safe version of `Object.assign`
|
|
578
|
+
*/
|
|
579
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
580
|
+
function assign(obj, props) {
|
|
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");
|
|
601
|
+
}
|
|
502
602
|
|
|
503
603
|
/**
|
|
504
604
|
* `StoreValue` represents values unknown at compile time,
|
|
@@ -507,13 +607,13 @@ const itemNames = [
|
|
|
507
607
|
class StoreValue extends BaseValue {
|
|
508
608
|
constructor(scope) {
|
|
509
609
|
super(scope);
|
|
510
|
-
this.
|
|
610
|
+
this.mutability = EMutability.mutable;
|
|
511
611
|
}
|
|
512
612
|
typeof(scope) {
|
|
513
613
|
return [new LiteralValue(scope, "store"), []];
|
|
514
614
|
}
|
|
515
615
|
"="(scope, value) {
|
|
516
|
-
if (this.
|
|
616
|
+
if (this.mutability !== EMutability.mutable)
|
|
517
617
|
throw new CompilerError(`Cannot assign to immutable store '${this}'.`);
|
|
518
618
|
if (this.owner) {
|
|
519
619
|
if (this.owner === value.owner && value instanceof StoreValue)
|
|
@@ -545,12 +645,13 @@ class StoreValue extends BaseValue {
|
|
|
545
645
|
class ObjectValue extends VoidValue {
|
|
546
646
|
constructor(scope, data = {}) {
|
|
547
647
|
super(scope);
|
|
548
|
-
this.
|
|
648
|
+
this.mutability = EMutability.constant;
|
|
549
649
|
this.macro = true;
|
|
550
650
|
this.data = data;
|
|
551
651
|
}
|
|
552
|
-
static fromArray(scope, items) {
|
|
652
|
+
static fromArray(scope, items, intialData) {
|
|
553
653
|
const data = {
|
|
654
|
+
...intialData,
|
|
554
655
|
length: new LiteralValue(scope, items.length),
|
|
555
656
|
};
|
|
556
657
|
items.forEach((item, i) => {
|
|
@@ -627,14 +728,15 @@ const senseableProps = ["controller"];
|
|
|
627
728
|
* Note that these values are constant by default, so make sure
|
|
628
729
|
* to set that field to `false` if you want them to be assignable. Example:
|
|
629
730
|
* ```
|
|
630
|
-
* const value = new SenseableValue(scope)
|
|
631
|
-
*
|
|
731
|
+
* const value = assign(new SenseableValue(scope), {
|
|
732
|
+
* mutability: EMutability.mutable
|
|
733
|
+
* })
|
|
632
734
|
* ```
|
|
633
735
|
*/
|
|
634
736
|
class SenseableValue extends StoreValue {
|
|
635
737
|
constructor(scope) {
|
|
636
738
|
super(scope);
|
|
637
|
-
this.
|
|
739
|
+
this.mutability = EMutability.constant;
|
|
638
740
|
}
|
|
639
741
|
get(scope, prop) {
|
|
640
742
|
if (prop instanceof LiteralValue && typeof prop.data === "string") {
|
|
@@ -650,14 +752,13 @@ class SenseableValue extends StoreValue {
|
|
|
650
752
|
];
|
|
651
753
|
}
|
|
652
754
|
if (prop instanceof StoreValue) {
|
|
653
|
-
const temp = new
|
|
755
|
+
const temp = assign(new SenseableValue(scope), {
|
|
756
|
+
mutability: EMutability.readonly,
|
|
757
|
+
});
|
|
654
758
|
return [temp, [new InstructionBase("sensor", temp, this, prop)]];
|
|
655
759
|
}
|
|
656
760
|
throw new CompilerError(`Cannot sense "${prop}" property`);
|
|
657
761
|
}
|
|
658
|
-
typeof(scope) {
|
|
659
|
-
return [new LiteralValue(scope, "senseable"), []];
|
|
660
|
-
}
|
|
661
762
|
}
|
|
662
763
|
|
|
663
764
|
/**
|
|
@@ -754,11 +855,11 @@ class Scope {
|
|
|
754
855
|
return owner.value;
|
|
755
856
|
}
|
|
756
857
|
make(identifier, name) {
|
|
757
|
-
const value = new SenseableValue(this);
|
|
758
|
-
value.constant = false;
|
|
759
858
|
const owner = new ValueOwner({
|
|
760
859
|
scope: this,
|
|
761
|
-
value,
|
|
860
|
+
value: assign(new SenseableValue(this), {
|
|
861
|
+
mutability: EMutability.mutable,
|
|
862
|
+
}),
|
|
762
863
|
identifier,
|
|
763
864
|
name,
|
|
764
865
|
});
|
|
@@ -778,7 +879,7 @@ const Program = (c, scope, node) => {
|
|
|
778
879
|
};
|
|
779
880
|
|
|
780
881
|
const VariableDeclaration = (c, scope, node) => {
|
|
781
|
-
return c.handleMany(scope, node.declarations,
|
|
882
|
+
return c.handleMany(scope, node.declarations, child => VariableDeclarator(c, scope, child, node.kind));
|
|
782
883
|
};
|
|
783
884
|
const VariableDeclarator = (c, scope, node, kind = "let") => {
|
|
784
885
|
const [init, inst] = node.init
|
|
@@ -788,25 +889,25 @@ const VariableDeclarator = (c, scope, node, kind = "let") => {
|
|
|
788
889
|
return [null, inst];
|
|
789
890
|
};
|
|
790
891
|
const Declare = (c, scope, node, kind, init) => {
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
node
|
|
801
|
-
|
|
802
|
-
}
|
|
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
|
+
});
|
|
803
904
|
};
|
|
804
905
|
const DeclareIdentifier = (c, scope, node, kind, init) => {
|
|
805
906
|
const { name: identifier } = node;
|
|
806
907
|
const name = nodeName(node, !c.compactNames && identifier);
|
|
807
908
|
if (kind === "const" && !init)
|
|
808
|
-
throw new CompilerError("Constants must be initialized.",
|
|
809
|
-
if (kind === "const" && init?.constant) {
|
|
909
|
+
throw new CompilerError("Constants must be initialized.", node);
|
|
910
|
+
if (kind === "const" && init?.mutability === EMutability.constant) {
|
|
810
911
|
const owner = new ValueOwner({
|
|
811
912
|
scope,
|
|
812
913
|
identifier,
|
|
@@ -822,13 +923,11 @@ const DeclareIdentifier = (c, scope, node, kind, init) => {
|
|
|
822
923
|
const inst = [];
|
|
823
924
|
if (init) {
|
|
824
925
|
if (init.macro)
|
|
825
|
-
throw new CompilerError("Macro values must be held by constants",
|
|
826
|
-
node,
|
|
827
|
-
]);
|
|
926
|
+
throw new CompilerError("Macro values must be held by constants", node);
|
|
828
927
|
inst.push(...value["="](scope, init)[1]);
|
|
829
928
|
}
|
|
830
929
|
if (kind === "const")
|
|
831
|
-
value.
|
|
930
|
+
value.mutability = EMutability.constant;
|
|
832
931
|
return [null, inst];
|
|
833
932
|
}
|
|
834
933
|
};
|
|
@@ -843,29 +942,28 @@ const DeclareArrayPattern = (c, scope, node, kind, init) => {
|
|
|
843
942
|
continue;
|
|
844
943
|
const val = init.data[i];
|
|
845
944
|
if (!val)
|
|
846
|
-
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);
|
|
847
946
|
inst.push(...Declare(c, scope, element, kind, val)[1]);
|
|
848
947
|
}
|
|
849
948
|
return [null, inst];
|
|
850
949
|
};
|
|
851
950
|
const DeclareObjectPattern = (c, scope, node, kind, base) => {
|
|
852
951
|
if (!base)
|
|
853
|
-
throw new CompilerError("Cannot use object destructuring without an initializer",
|
|
952
|
+
throw new CompilerError("Cannot use object destructuring without an initializer", node);
|
|
854
953
|
const { properties } = node;
|
|
855
954
|
const [init, inst] = base.consume(scope);
|
|
856
|
-
|
|
955
|
+
const propertiesInst = c.handleMany(scope, properties, prop => {
|
|
857
956
|
if (prop.type === "RestElement")
|
|
858
|
-
throw new CompilerError("The rest operator is not supported",
|
|
957
|
+
throw new CompilerError("The rest operator is not supported", prop);
|
|
859
958
|
const { key, value } = prop;
|
|
860
|
-
const
|
|
959
|
+
const keyInst = key.type === "Identifier" && !prop.computed
|
|
861
960
|
? [new LiteralValue(scope, key.name), []]
|
|
862
961
|
: c.handleConsume(scope, prop.key);
|
|
863
|
-
|
|
864
|
-
const
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
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]]];
|
|
869
967
|
};
|
|
870
968
|
|
|
871
969
|
const Literal = (_c, scope, node) => [new LiteralValue(scope, node.value), []];
|
|
@@ -884,7 +982,34 @@ const LRExpression = (c, scope, node) => {
|
|
|
884
982
|
return [op, [...leftInst, ...rightInst, ...opInst]];
|
|
885
983
|
};
|
|
886
984
|
const BinaryExpression = LRExpression;
|
|
887
|
-
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
|
+
};
|
|
888
1013
|
const AssignmentExpression = (c, scope, node) => {
|
|
889
1014
|
const [left, leftInst] = c.handle(scope, node.left);
|
|
890
1015
|
// doesn't need to consume because the operators already do that
|
|
@@ -974,13 +1099,75 @@ const IfStatement = (c, scope, node) => {
|
|
|
974
1099
|
return [null, inst];
|
|
975
1100
|
}
|
|
976
1101
|
const endIfAddr = new LiteralValue(scope, null);
|
|
977
|
-
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));
|
|
978
1103
|
const endElseAddr = new LiteralValue(scope, null);
|
|
979
|
-
if (node.alternate)
|
|
980
|
-
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
|
+
}
|
|
981
1107
|
return [null, inst];
|
|
982
1108
|
};
|
|
983
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
|
+
|
|
984
1171
|
const WhileStatement = (c, scope, node) => {
|
|
985
1172
|
const lines = [];
|
|
986
1173
|
const [test, testLines] = c.handleConsume(scope, node.test);
|
|
@@ -994,7 +1181,7 @@ const WhileStatement = (c, scope, node) => {
|
|
|
994
1181
|
}
|
|
995
1182
|
return [null, lines];
|
|
996
1183
|
}
|
|
997
|
-
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);
|
|
998
1185
|
return [null, lines];
|
|
999
1186
|
};
|
|
1000
1187
|
const DoWhileStatement = (c, scope, node) => {
|
|
@@ -1038,7 +1225,7 @@ const ForStatement = (c, scope, node) => {
|
|
|
1038
1225
|
startLoopLine,
|
|
1039
1226
|
...testLines,
|
|
1040
1227
|
new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
|
|
1041
|
-
...c.handle(scope, node.body)[1],
|
|
1228
|
+
...withAlwaysRuns(c.handle(scope, node.body), false)[1],
|
|
1042
1229
|
...updateLines,
|
|
1043
1230
|
new JumpInstruction(startLoopAddr, EJumpKind.Always),
|
|
1044
1231
|
endLoopLine,
|
|
@@ -1049,7 +1236,7 @@ const ForStatement = (c, scope, node) => {
|
|
|
1049
1236
|
class FunctionValue extends VoidValue {
|
|
1050
1237
|
constructor({ scope, params, body, c, node, }) {
|
|
1051
1238
|
super(scope);
|
|
1052
|
-
this.
|
|
1239
|
+
this.mutability = EMutability.constant;
|
|
1053
1240
|
this.macro = true;
|
|
1054
1241
|
this.paramOwners = [];
|
|
1055
1242
|
this.bundled = false;
|
|
@@ -1069,7 +1256,9 @@ class FunctionValue extends VoidValue {
|
|
|
1069
1256
|
const name = nodeName(id, !this.c.compactNames && id.name);
|
|
1070
1257
|
const owner = new ValueOwner({
|
|
1071
1258
|
scope: this.childScope,
|
|
1072
|
-
value: new
|
|
1259
|
+
value: assign(new SenseableValue(this.childScope), {
|
|
1260
|
+
mutability: EMutability.mutable,
|
|
1261
|
+
}),
|
|
1073
1262
|
identifier: id.name,
|
|
1074
1263
|
name,
|
|
1075
1264
|
});
|
|
@@ -1084,15 +1273,16 @@ class FunctionValue extends VoidValue {
|
|
|
1084
1273
|
if (this.initialized)
|
|
1085
1274
|
return;
|
|
1086
1275
|
this.initialized = true;
|
|
1087
|
-
const name =
|
|
1276
|
+
const { name } = this.owner;
|
|
1088
1277
|
this.initScope(name);
|
|
1089
1278
|
this.addr = new LiteralValue(this.childScope, null);
|
|
1090
1279
|
this.temp = new ValueOwner({
|
|
1091
1280
|
scope: this.childScope,
|
|
1092
1281
|
name: `${internalPrefix}f${name}`,
|
|
1093
|
-
value: new SenseableValue(this.childScope),
|
|
1282
|
+
value: assign(new SenseableValue(this.childScope), {
|
|
1283
|
+
mutability: EMutability.mutable,
|
|
1284
|
+
}),
|
|
1094
1285
|
});
|
|
1095
|
-
this.temp.value.constant = false;
|
|
1096
1286
|
this.ret = new ValueOwner({
|
|
1097
1287
|
scope: this.childScope,
|
|
1098
1288
|
name: `${internalPrefix}r${name}`,
|
|
@@ -1103,12 +1293,17 @@ class FunctionValue extends VoidValue {
|
|
|
1103
1293
|
...this.c.handle(this.childScope, this.body)[1],
|
|
1104
1294
|
];
|
|
1105
1295
|
if (!endsWithReturn(this.inst)) {
|
|
1106
|
-
this.inst.push(new SetCounterInstruction(this.ret.value)
|
|
1296
|
+
this.inst.push(assign(new SetCounterInstruction(this.ret.value), {
|
|
1297
|
+
intent: EInstIntent.return,
|
|
1298
|
+
}));
|
|
1107
1299
|
}
|
|
1108
1300
|
}
|
|
1109
1301
|
normalReturn(scope, arg) {
|
|
1110
1302
|
const argInst = arg ? this.temp.value["="](scope, arg)[1] : [];
|
|
1111
|
-
|
|
1303
|
+
const returnInst = assign(new SetCounterInstruction(this.ret.value), {
|
|
1304
|
+
intent: EInstIntent.return,
|
|
1305
|
+
});
|
|
1306
|
+
return [null, [...argInst, returnInst]];
|
|
1112
1307
|
}
|
|
1113
1308
|
normalCall(scope, args) {
|
|
1114
1309
|
if (!this.bundled)
|
|
@@ -1123,16 +1318,21 @@ class FunctionValue extends VoidValue {
|
|
|
1123
1318
|
}
|
|
1124
1319
|
inlineReturn(scope, arg) {
|
|
1125
1320
|
const argInst = arg ? this.inlineTemp.value["="](scope, arg)[1] : [];
|
|
1126
|
-
|
|
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]];
|
|
1127
1327
|
}
|
|
1128
1328
|
inlineCall(scope, args) {
|
|
1129
1329
|
// create return value
|
|
1130
1330
|
this.inlineTemp = new ValueOwner({
|
|
1131
1331
|
scope: this.childScope,
|
|
1132
|
-
value: new SenseableValue(scope),
|
|
1332
|
+
value: assign(new SenseableValue(scope), {
|
|
1333
|
+
mutability: EMutability.mutable,
|
|
1334
|
+
}),
|
|
1133
1335
|
});
|
|
1134
|
-
this.inlineTemp.value.constant = false;
|
|
1135
|
-
this.inlineEnd = new LiteralValue(scope, null);
|
|
1136
1336
|
// make a copy of the function scope
|
|
1137
1337
|
const fnScope = this.childScope.copy();
|
|
1138
1338
|
// hard set variables within the function scope
|
|
@@ -1147,16 +1347,13 @@ class FunctionValue extends VoidValue {
|
|
|
1147
1347
|
name: owner.name,
|
|
1148
1348
|
}));
|
|
1149
1349
|
});
|
|
1350
|
+
this.inlineEnd = new LiteralValue(scope, null);
|
|
1150
1351
|
this.tryingInline = true;
|
|
1151
|
-
|
|
1352
|
+
let inst = this.c.handle(fnScope, this.body)[1];
|
|
1152
1353
|
this.tryingInline = false;
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
// if (jump instanceof JumpInstruction) {
|
|
1157
|
-
// // remove useless jump
|
|
1158
|
-
// if (jump.args[1] === this.inlineEnd) inst.pop();
|
|
1159
|
-
// }
|
|
1354
|
+
const returnIndex = inst.findIndex(i => i.alwaysRuns && i.intent === EInstIntent.return);
|
|
1355
|
+
if (returnIndex !== -1)
|
|
1356
|
+
inst = inst.slice(0, returnIndex + 1);
|
|
1160
1357
|
inst.push(new AddressResolver(this.inlineEnd));
|
|
1161
1358
|
// return the function value
|
|
1162
1359
|
return [this.inlineTemp.value, inst];
|
|
@@ -1201,7 +1398,11 @@ function endsWithReturn(inst) {
|
|
|
1201
1398
|
function handleFunctionNode(c, scope, node) {
|
|
1202
1399
|
let { params, body } = node;
|
|
1203
1400
|
if (es.isExpression(body)) {
|
|
1204
|
-
|
|
1401
|
+
const { loc } = body;
|
|
1402
|
+
const statement = es.returnStatement(body);
|
|
1403
|
+
statement.loc = loc;
|
|
1404
|
+
body = es.blockStatement([statement]);
|
|
1405
|
+
body.loc = loc;
|
|
1205
1406
|
}
|
|
1206
1407
|
return [
|
|
1207
1408
|
new FunctionValue({
|
|
@@ -1247,16 +1448,32 @@ const CallExpression = (c, scope, node) => {
|
|
|
1247
1448
|
inst.push(...callInst);
|
|
1248
1449
|
return [callValue, inst];
|
|
1249
1450
|
};
|
|
1250
|
-
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
|
+
};
|
|
1251
1468
|
|
|
1252
1469
|
const ObjectExpression = (c, scope, node) => {
|
|
1253
1470
|
const data = {};
|
|
1254
1471
|
const inst = [];
|
|
1255
1472
|
for (const prop of node.properties) {
|
|
1256
1473
|
if (prop.type === "SpreadElement")
|
|
1257
|
-
throw new CompilerError("Cannot handle spread element",
|
|
1474
|
+
throw new CompilerError("Cannot handle spread element", prop);
|
|
1258
1475
|
if (prop.computed)
|
|
1259
|
-
throw new CompilerError("Cannot handle computed property.",
|
|
1476
|
+
throw new CompilerError("Cannot handle computed property.", prop);
|
|
1260
1477
|
const { key } = prop;
|
|
1261
1478
|
const value = prop.type === "ObjectProperty" ? prop.value : prop;
|
|
1262
1479
|
let index;
|
|
@@ -1267,17 +1484,18 @@ const ObjectExpression = (c, scope, node) => {
|
|
|
1267
1484
|
index = `${key.value}`;
|
|
1268
1485
|
}
|
|
1269
1486
|
else {
|
|
1270
|
-
throw new CompilerError(`Unsupported object key type: ${key.type}`,
|
|
1271
|
-
key,
|
|
1272
|
-
]);
|
|
1487
|
+
throw new CompilerError(`Unsupported object key type: ${key.type}`, key);
|
|
1273
1488
|
}
|
|
1274
1489
|
const [member, memberInst] = c.handleEval(scope, value);
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
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;
|
|
1281
1499
|
inst.push(...memberInst);
|
|
1282
1500
|
}
|
|
1283
1501
|
return [new ObjectValue(scope, data), inst];
|
|
@@ -1311,9 +1529,7 @@ const ArrayPattern = (c, scope, node) => {
|
|
|
1311
1529
|
continue;
|
|
1312
1530
|
const valueInst = c.handle(scope, element);
|
|
1313
1531
|
if (!valueInst[0])
|
|
1314
|
-
throw new CompilerError("Destructuring element must resolve to a value",
|
|
1315
|
-
element,
|
|
1316
|
-
]);
|
|
1532
|
+
throw new CompilerError("Destructuring element must resolve to a value", element);
|
|
1317
1533
|
inst.push(...valueInst[1]);
|
|
1318
1534
|
members.set(new LiteralValue(scope, i), valueInst[0]);
|
|
1319
1535
|
}
|
|
@@ -1334,26 +1550,15 @@ const ObjectPattern = (c, scope, node) => {
|
|
|
1334
1550
|
inst.push(...keyInst[1]);
|
|
1335
1551
|
const valueInst = c.handle(scope, prop.value);
|
|
1336
1552
|
if (!valueInst[0])
|
|
1337
|
-
throw new CompilerError("Destructuring member must resolve to a value",
|
|
1338
|
-
prop.value,
|
|
1339
|
-
]);
|
|
1553
|
+
throw new CompilerError("Destructuring member must resolve to a value", prop.value);
|
|
1340
1554
|
inst.push(...valueInst[1]);
|
|
1341
1555
|
members.set(keyInst[0], valueInst[0]);
|
|
1342
1556
|
}
|
|
1343
1557
|
return [new DestructuringValue(scope, members), inst];
|
|
1344
1558
|
};
|
|
1345
1559
|
|
|
1346
|
-
const TemplateLiteral = (
|
|
1347
|
-
|
|
1348
|
-
const inst = [];
|
|
1349
|
-
node.expressions.forEach((expression, i) => {
|
|
1350
|
-
const [v, vi] = c.handleConsume(scope, expression);
|
|
1351
|
-
inst.push(...vi);
|
|
1352
|
-
args.push(node.quasis[i].value.raw, v);
|
|
1353
|
-
});
|
|
1354
|
-
args.push(node.quasis.slice(-1)[0].value.raw);
|
|
1355
|
-
inst.push(new ZeroSpaceInstruction(...args));
|
|
1356
|
-
return [null, inst];
|
|
1560
|
+
const TemplateLiteral = () => {
|
|
1561
|
+
throw new CompilerError("Template strings are currently unavailable. To inline mlog code use the asm function.");
|
|
1357
1562
|
};
|
|
1358
1563
|
|
|
1359
1564
|
const BlockStatement = (c, scope, node) => {
|
|
@@ -1386,14 +1591,12 @@ const TSEnumDeclaration = (c, scope, node) => {
|
|
|
1386
1591
|
const data = {};
|
|
1387
1592
|
for (const member of node.members) {
|
|
1388
1593
|
if (lastType === "string" && !member.initializer)
|
|
1389
|
-
throw new CompilerError("This enum member must be initialized",
|
|
1594
|
+
throw new CompilerError("This enum member must be initialized", member);
|
|
1390
1595
|
const [value] = member.initializer
|
|
1391
1596
|
? c.handleEval(scope, member.initializer)
|
|
1392
1597
|
: [new LiteralValue(scope, counter)];
|
|
1393
1598
|
if (!(value instanceof LiteralValue))
|
|
1394
|
-
throw new CompilerError("Enum members must contain literal values",
|
|
1395
|
-
member,
|
|
1396
|
-
]);
|
|
1599
|
+
throw new CompilerError("Enum members must contain literal values", member);
|
|
1397
1600
|
if (typeof value.data === "number") {
|
|
1398
1601
|
lastType = "number";
|
|
1399
1602
|
counter = value.data + 1;
|
|
@@ -1439,6 +1642,7 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1439
1642
|
ContinueStatement: ContinueStatement,
|
|
1440
1643
|
ReturnStatement: ReturnStatement,
|
|
1441
1644
|
IfStatement: IfStatement,
|
|
1645
|
+
SwitchStatement: SwitchStatement,
|
|
1442
1646
|
WhileStatement: WhileStatement,
|
|
1443
1647
|
DoWhileStatement: DoWhileStatement,
|
|
1444
1648
|
ForStatement: ForStatement,
|
|
@@ -1448,6 +1652,7 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1448
1652
|
ObjectMethod: ObjectMethod,
|
|
1449
1653
|
CallExpression: CallExpression,
|
|
1450
1654
|
NewExpression: NewExpression,
|
|
1655
|
+
TaggedTemplateExpression: TaggedTemplateExpression,
|
|
1451
1656
|
ObjectExpression: ObjectExpression,
|
|
1452
1657
|
ArrayExpression: ArrayExpression,
|
|
1453
1658
|
MemberExpression: MemberExpression,
|
|
@@ -1550,53 +1755,170 @@ class Concat extends MacroFunction {
|
|
|
1550
1755
|
}
|
|
1551
1756
|
}
|
|
1552
1757
|
|
|
1553
|
-
|
|
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 {
|
|
1554
1841
|
constructor(scope) {
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
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
|
+
},
|
|
1581
1883
|
});
|
|
1884
|
+
super(scope, data);
|
|
1582
1885
|
}
|
|
1583
1886
|
}
|
|
1584
1887
|
|
|
1585
1888
|
class Print extends MacroFunction {
|
|
1586
1889
|
constructor(scope) {
|
|
1587
1890
|
super(scope, (...values) => {
|
|
1891
|
+
const [first] = values;
|
|
1588
1892
|
const inst = [];
|
|
1589
|
-
|
|
1590
|
-
|
|
1893
|
+
if (!isTemplateObjectArray(first)) {
|
|
1894
|
+
for (const value of values) {
|
|
1895
|
+
inst.push(new InstructionBase("print", value));
|
|
1896
|
+
}
|
|
1897
|
+
return [null, inst];
|
|
1591
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));
|
|
1592
1911
|
return [null, inst];
|
|
1593
1912
|
});
|
|
1594
1913
|
}
|
|
1595
1914
|
}
|
|
1596
1915
|
|
|
1916
|
+
const defaultTargetName$1 = "message1";
|
|
1597
1917
|
class PrintFlush extends MacroFunction {
|
|
1598
1918
|
constructor(scope) {
|
|
1599
1919
|
super(scope, (target) => {
|
|
1920
|
+
if (!target)
|
|
1921
|
+
return [null, [new InstructionBase("printflush", defaultTargetName$1)]];
|
|
1600
1922
|
if (!(target instanceof SenseableValue))
|
|
1601
1923
|
throw new CompilerError("The printflush target must be a senseable value");
|
|
1602
1924
|
return [null, [new InstructionBase("printflush", target)]];
|
|
@@ -1604,9 +1926,12 @@ class PrintFlush extends MacroFunction {
|
|
|
1604
1926
|
}
|
|
1605
1927
|
}
|
|
1606
1928
|
|
|
1929
|
+
const defaultTargetName = "display1";
|
|
1607
1930
|
class DrawFlush extends MacroFunction {
|
|
1608
1931
|
constructor(scope) {
|
|
1609
1932
|
super(scope, (target) => {
|
|
1933
|
+
if (!target)
|
|
1934
|
+
return [null, [new InstructionBase("drawflush", defaultTargetName)]];
|
|
1610
1935
|
if (!(target instanceof SenseableValue))
|
|
1611
1936
|
throw new CompilerError("The drawflush target must be a senseable value");
|
|
1612
1937
|
return [null, [new InstructionBase("drawflush", target)]];
|
|
@@ -1614,6 +1939,30 @@ class DrawFlush extends MacroFunction {
|
|
|
1614
1939
|
}
|
|
1615
1940
|
}
|
|
1616
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
|
+
|
|
1617
1966
|
class GetLink extends MacroFunction {
|
|
1618
1967
|
constructor(scope) {
|
|
1619
1968
|
super(scope, (index) => {
|
|
@@ -1626,21 +1975,27 @@ class GetLink extends MacroFunction {
|
|
|
1626
1975
|
}
|
|
1627
1976
|
}
|
|
1628
1977
|
|
|
1629
|
-
|
|
1630
|
-
class Control extends MacroFunction {
|
|
1978
|
+
class Control extends ObjectValue {
|
|
1631
1979
|
constructor(scope) {
|
|
1632
|
-
super(scope, (
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
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
|
+
}));
|
|
1644
1999
|
}
|
|
1645
2000
|
}
|
|
1646
2001
|
|
|
@@ -1663,28 +2018,25 @@ const validRadarSorts = [
|
|
|
1663
2018
|
];
|
|
1664
2019
|
class Radar extends MacroFunction {
|
|
1665
2020
|
constructor(scope) {
|
|
1666
|
-
super(scope,
|
|
2021
|
+
super(scope, options => {
|
|
2022
|
+
assertIsObjectMacro(options, "The radar options");
|
|
2023
|
+
const { building, filters, order, sort } = options.data;
|
|
1667
2024
|
if (!(building instanceof SenseableValue))
|
|
1668
2025
|
throw new CompilerError("The building must a senseable value");
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
if (!validRadarFilters.includes(filter3.data))
|
|
1681
|
-
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");
|
|
1682
2037
|
if (!(order instanceof LiteralValue || order instanceof StoreValue))
|
|
1683
2038
|
throw new CompilerError("The radar order must be a literal or a store");
|
|
1684
|
-
|
|
1685
|
-
throw new CompilerError("The radar sort must be a string literal");
|
|
1686
|
-
if (!validRadarSorts.includes(sort.data))
|
|
1687
|
-
throw new CompilerError("Invalid sort value");
|
|
2039
|
+
assertLiteralOneOf(sort, validRadarSorts, "The radar sort");
|
|
1688
2040
|
const outUnit = new SenseableValue(scope);
|
|
1689
2041
|
return [
|
|
1690
2042
|
outUnit,
|
|
@@ -1703,7 +2055,9 @@ class Sensor extends MacroFunction {
|
|
|
1703
2055
|
throw new CompilerError("The sensor property must be a store");
|
|
1704
2056
|
if (!(target instanceof SenseableValue))
|
|
1705
2057
|
throw new CompilerError("The sensor target must be a senseable value");
|
|
1706
|
-
const temp = new
|
|
2058
|
+
const temp = assign(new SenseableValue(scope), {
|
|
2059
|
+
mutability: EMutability.readonly,
|
|
2060
|
+
});
|
|
1707
2061
|
return [temp, [new InstructionBase("sensor", temp, target, property)]];
|
|
1708
2062
|
});
|
|
1709
2063
|
}
|
|
@@ -1720,19 +2074,40 @@ class Wait extends MacroFunction {
|
|
|
1720
2074
|
}
|
|
1721
2075
|
}
|
|
1722
2076
|
|
|
1723
|
-
|
|
1724
|
-
class Lookup extends MacroFunction {
|
|
2077
|
+
class Lookup extends ObjectValue {
|
|
1725
2078
|
constructor(scope) {
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
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)]];
|
|
1736
2111
|
});
|
|
1737
2112
|
}
|
|
1738
2113
|
}
|
|
@@ -1743,6 +2118,57 @@ class End extends MacroFunction {
|
|
|
1743
2118
|
}
|
|
1744
2119
|
}
|
|
1745
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
|
+
|
|
1746
2172
|
class UnitBind extends MacroFunction {
|
|
1747
2173
|
constructor(scope) {
|
|
1748
2174
|
super(scope, type => {
|
|
@@ -1753,82 +2179,85 @@ class UnitBind extends MacroFunction {
|
|
|
1753
2179
|
}
|
|
1754
2180
|
}
|
|
1755
2181
|
|
|
1756
|
-
|
|
1757
|
-
"idle",
|
|
1758
|
-
"stop",
|
|
1759
|
-
"move",
|
|
1760
|
-
"approach",
|
|
1761
|
-
"boost",
|
|
1762
|
-
"pathfind",
|
|
1763
|
-
"target",
|
|
1764
|
-
"targetp",
|
|
1765
|
-
"itemDrop",
|
|
1766
|
-
"itemTake",
|
|
1767
|
-
"payDrop",
|
|
1768
|
-
"payTake",
|
|
1769
|
-
"payEnter",
|
|
1770
|
-
"mine",
|
|
1771
|
-
"flag",
|
|
1772
|
-
"build",
|
|
1773
|
-
"getBlock",
|
|
1774
|
-
"within",
|
|
1775
|
-
];
|
|
1776
|
-
class UnitControl extends MacroFunction {
|
|
2182
|
+
class UnitControl extends ObjectValue {
|
|
1777
2183
|
constructor(scope) {
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
}
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
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
|
+
}
|
|
1800
2231
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
2232
|
+
return [
|
|
2233
|
+
result,
|
|
2234
|
+
[new InstructionBase("ucontrol", overload, ...args, ...extraArgs)],
|
|
2235
|
+
];
|
|
2236
|
+
},
|
|
1806
2237
|
});
|
|
2238
|
+
super(scope, data);
|
|
1807
2239
|
}
|
|
1808
2240
|
}
|
|
1809
2241
|
|
|
1810
2242
|
class UnitRadar extends MacroFunction {
|
|
1811
2243
|
constructor(scope) {
|
|
1812
|
-
super(scope,
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
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");
|
|
1826
2258
|
if (!(order instanceof LiteralValue || order instanceof StoreValue))
|
|
1827
2259
|
throw new CompilerError("The radar order must be a literal or a store");
|
|
1828
|
-
|
|
1829
|
-
throw new CompilerError("The radar sort must be a string literal");
|
|
1830
|
-
if (!validRadarSorts.includes(sort.data))
|
|
1831
|
-
throw new CompilerError("Invalid sort value");
|
|
2260
|
+
assertLiteralOneOf(sort, validRadarSorts, "The radar sort");
|
|
1832
2261
|
const outUnit = new SenseableValue(scope);
|
|
1833
2262
|
return [
|
|
1834
2263
|
outUnit,
|
|
@@ -1841,7 +2270,6 @@ class UnitRadar extends MacroFunction {
|
|
|
1841
2270
|
}
|
|
1842
2271
|
}
|
|
1843
2272
|
|
|
1844
|
-
const validFinds = ["ore", "building", "spawn", "damaged"];
|
|
1845
2273
|
const validBuildingGroups = [
|
|
1846
2274
|
"core",
|
|
1847
2275
|
"storage",
|
|
@@ -1853,56 +2281,297 @@ const validBuildingGroups = [
|
|
|
1853
2281
|
"battery",
|
|
1854
2282
|
"reactor",
|
|
1855
2283
|
];
|
|
1856
|
-
class UnitLocate extends
|
|
2284
|
+
class UnitLocate extends ObjectValue {
|
|
1857
2285
|
constructor(scope) {
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
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;
|
|
1881
2325
|
}
|
|
1882
|
-
if (!validBuildingGroups.includes(group.data))
|
|
1883
|
-
throw new CompilerError("Invalid building group");
|
|
1884
|
-
inputArgs = [find.data, group.data, enemy, "@copper"];
|
|
1885
|
-
break;
|
|
1886
|
-
}
|
|
1887
|
-
case "spawn":
|
|
1888
|
-
case "damaged": {
|
|
1889
|
-
inputArgs = [find.data, "core", "true", "@copper"];
|
|
1890
|
-
break;
|
|
1891
2326
|
}
|
|
1892
|
-
|
|
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");
|
|
1893
2390
|
return [
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
...(find.data !== "ore" ? [outBuilding] : []),
|
|
1899
|
-
]),
|
|
1900
|
-
[new InstructionBase("ulocate", ...inputArgs, ...outArgs)],
|
|
2391
|
+
null,
|
|
2392
|
+
[
|
|
2393
|
+
new InstructionBase("spawnwave", x ?? "10", y ?? "10", String(!!natural.data)),
|
|
2394
|
+
],
|
|
1901
2395
|
];
|
|
1902
2396
|
});
|
|
1903
2397
|
}
|
|
1904
2398
|
}
|
|
1905
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
|
+
|
|
1906
2575
|
class MemoryEntry extends ObjectValue {
|
|
1907
2576
|
constructor(scope, mem, prop) {
|
|
1908
2577
|
super(scope, {
|
|
@@ -1975,6 +2644,7 @@ class MemoryBuilder extends ObjectValue {
|
|
|
1975
2644
|
}
|
|
1976
2645
|
}
|
|
1977
2646
|
|
|
2647
|
+
const dynamicVars = ["time", "tick"];
|
|
1978
2648
|
class NamespaceMacro extends ObjectValue {
|
|
1979
2649
|
constructor(scope, { changeCasing = false } = {}) {
|
|
1980
2650
|
super(scope, {
|
|
@@ -1984,9 +2654,14 @@ class NamespaceMacro extends ObjectValue {
|
|
|
1984
2654
|
const symbolName = this.changeCasing
|
|
1985
2655
|
? camelToDashCase(prop.data)
|
|
1986
2656
|
: prop.data;
|
|
2657
|
+
const mutability = dynamicVars.includes(symbolName)
|
|
2658
|
+
? EMutability.readonly
|
|
2659
|
+
: EMutability.constant;
|
|
1987
2660
|
const owner = new ValueOwner({
|
|
1988
2661
|
scope,
|
|
1989
|
-
value: new StoreValue(scope),
|
|
2662
|
+
value: assign(new StoreValue(scope), {
|
|
2663
|
+
mutability,
|
|
2664
|
+
}),
|
|
1990
2665
|
name: `@${symbolName}`,
|
|
1991
2666
|
});
|
|
1992
2667
|
return [owner.value, []];
|
|
@@ -2011,39 +2686,44 @@ class VarsNamespace extends NamespaceMacro {
|
|
|
2011
2686
|
}).value,
|
|
2012
2687
|
});
|
|
2013
2688
|
}
|
|
2014
|
-
}
|
|
2015
|
-
class UCommandsNamespace extends NamespaceMacro {
|
|
2016
|
-
constructor(scope) {
|
|
2017
|
-
super(scope);
|
|
2018
|
-
this.data.$get = new MacroFunction(scope, prop => {
|
|
2019
|
-
if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
|
|
2020
|
-
throw new CompilerError("Cannot use dynamic properties on namespace macros");
|
|
2021
|
-
const symbolName = prop.data[0].toUpperCase() + prop.data.slice(1);
|
|
2022
|
-
const owner = new ValueOwner({
|
|
2023
|
-
scope,
|
|
2024
|
-
name: `@command${symbolName}`,
|
|
2025
|
-
value: new StoreValue(scope),
|
|
2026
|
-
});
|
|
2027
|
-
return [owner.value, []];
|
|
2028
|
-
});
|
|
2029
|
-
}
|
|
2030
2689
|
}
|
|
2031
2690
|
|
|
2032
2691
|
class GetGlobal extends MacroFunction {
|
|
2033
|
-
constructor(scope) {
|
|
2692
|
+
constructor(scope, mutability) {
|
|
2034
2693
|
super(scope, (name) => {
|
|
2035
2694
|
if (!(name instanceof LiteralValue) || typeof name.data !== "string")
|
|
2036
2695
|
throw new CompilerError("The name parameter must be a string literal.");
|
|
2037
2696
|
const owner = new ValueOwner({
|
|
2038
2697
|
scope,
|
|
2039
2698
|
name: name.data,
|
|
2040
|
-
value: new SenseableValue(scope),
|
|
2699
|
+
value: assign(new SenseableValue(scope), {
|
|
2700
|
+
mutability,
|
|
2701
|
+
}),
|
|
2041
2702
|
});
|
|
2042
2703
|
return [owner.value, []];
|
|
2043
2704
|
});
|
|
2044
2705
|
}
|
|
2045
2706
|
}
|
|
2046
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
|
+
|
|
2047
2727
|
/**
|
|
2048
2728
|
* Adds all the compiler globals to `scope`
|
|
2049
2729
|
*/
|
|
@@ -2051,16 +2731,17 @@ function initScope(scope) {
|
|
|
2051
2731
|
// namespaces
|
|
2052
2732
|
scope.hardSet("ControlKind", new NamespaceMacro(scope));
|
|
2053
2733
|
scope.hardSet("Vars", new VarsNamespace(scope));
|
|
2734
|
+
scope.hardSet("Teams", new NamespaceMacro(scope));
|
|
2054
2735
|
scope.hardSet("Items", new NamespaceMacro(scope, { changeCasing: true }));
|
|
2055
2736
|
scope.hardSet("Liquids", new NamespaceMacro(scope));
|
|
2056
|
-
scope.hardSet("Units", new NamespaceMacro(scope));
|
|
2737
|
+
scope.hardSet("Units", new NamespaceMacro(scope, { changeCasing: true }));
|
|
2057
2738
|
scope.hardSet("LAccess", new NamespaceMacro(scope));
|
|
2058
|
-
scope.hardSet("UnitCommands", new UCommandsNamespace(scope));
|
|
2059
2739
|
scope.hardSet("Blocks", new NamespaceMacro(scope, { changeCasing: true }));
|
|
2060
2740
|
// helper methods
|
|
2061
|
-
scope.hardSet("getBuilding", new GetGlobal(scope));
|
|
2062
|
-
scope.hardSet("getVar", new GetGlobal(scope));
|
|
2741
|
+
scope.hardSet("getBuilding", new GetGlobal(scope, EMutability.constant));
|
|
2742
|
+
scope.hardSet("getVar", new GetGlobal(scope, EMutability.mutable));
|
|
2063
2743
|
scope.hardSet("concat", new Concat(scope));
|
|
2744
|
+
scope.hardSet("asm", new Asm(scope));
|
|
2064
2745
|
scope.hardSet("Math", new MlogMath(scope));
|
|
2065
2746
|
scope.hardSet("Memory", new MemoryBuilder(scope));
|
|
2066
2747
|
// commands
|
|
@@ -2074,36 +2755,58 @@ function initScope(scope) {
|
|
|
2074
2755
|
scope.hardSet("sensor", new Sensor(scope));
|
|
2075
2756
|
scope.hardSet("wait", new Wait(scope));
|
|
2076
2757
|
scope.hardSet("lookup", new Lookup(scope));
|
|
2758
|
+
scope.hardSet("packColor", new PackColor(scope));
|
|
2077
2759
|
scope.hardSet("endScript", new End(scope));
|
|
2760
|
+
scope.hardSet("stopScript", new Stop(scope));
|
|
2078
2761
|
scope.hardSet("unitBind", new UnitBind(scope));
|
|
2079
2762
|
scope.hardSet("unitControl", new UnitControl(scope));
|
|
2080
2763
|
scope.hardSet("unitRadar", new UnitRadar(scope));
|
|
2081
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));
|
|
2082
2779
|
}
|
|
2083
2780
|
|
|
2084
2781
|
class Compiler {
|
|
2085
|
-
constructor({ stackName, compactNames = false } = {}) {
|
|
2782
|
+
constructor({ stackName, compactNames = false, sourcemap = false, } = {}) {
|
|
2086
2783
|
this.handlers = handlers;
|
|
2087
2784
|
this.usingStack = !!stackName;
|
|
2088
2785
|
this.stackName = stackName;
|
|
2089
2786
|
this.compactNames = compactNames;
|
|
2787
|
+
this.sourcemap = sourcemap;
|
|
2090
2788
|
}
|
|
2091
2789
|
compile(script) {
|
|
2092
2790
|
let output;
|
|
2791
|
+
let sourcemaps;
|
|
2093
2792
|
try {
|
|
2094
2793
|
const program = this.parse(script);
|
|
2095
2794
|
const scope = new Scope({});
|
|
2096
2795
|
initScope(scope);
|
|
2097
2796
|
const valueInst = this.handle(scope, program);
|
|
2098
2797
|
valueInst[1].push(new EndInstruction(), ...scope.inst);
|
|
2798
|
+
hideRedundantJumps(valueInst[1]);
|
|
2099
2799
|
this.resolve(valueInst);
|
|
2100
2800
|
output = this.serialize(valueInst) + "\n";
|
|
2801
|
+
if (this.sourcemap) {
|
|
2802
|
+
sourcemaps = this.mapSources(valueInst);
|
|
2803
|
+
}
|
|
2101
2804
|
}
|
|
2102
2805
|
catch (error) {
|
|
2103
|
-
const
|
|
2104
|
-
return [null,
|
|
2806
|
+
const err = error instanceof CompilerError ? error : CompilerError.from(error);
|
|
2807
|
+
return [null, err];
|
|
2105
2808
|
}
|
|
2106
|
-
return [output, null,
|
|
2809
|
+
return [output, null, sourcemaps];
|
|
2107
2810
|
}
|
|
2108
2811
|
resolve(valueInst) {
|
|
2109
2812
|
let i = 0;
|
|
@@ -2123,40 +2826,92 @@ class Compiler {
|
|
|
2123
2826
|
plugins: ["typescript"],
|
|
2124
2827
|
});
|
|
2125
2828
|
}
|
|
2126
|
-
|
|
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]) {
|
|
2127
2838
|
try {
|
|
2128
|
-
const handler = this.handlers[node.type];
|
|
2129
2839
|
if (!handler)
|
|
2130
2840
|
throw new CompilerError("Missing handler for " + node.type);
|
|
2131
|
-
|
|
2841
|
+
const result = handler(this, scope, node, null);
|
|
2842
|
+
if (this.sourcemap)
|
|
2843
|
+
return appendSourceLocations(result, node);
|
|
2844
|
+
return result;
|
|
2132
2845
|
}
|
|
2133
2846
|
catch (error) {
|
|
2134
2847
|
if (error instanceof CompilerError) {
|
|
2135
|
-
error.
|
|
2848
|
+
error.loc ??= node.loc;
|
|
2136
2849
|
}
|
|
2137
2850
|
throw error;
|
|
2138
2851
|
}
|
|
2139
2852
|
}
|
|
2140
2853
|
handleEval(scope, node) {
|
|
2141
2854
|
const [res, inst] = this.handle(scope, node);
|
|
2142
|
-
|
|
2855
|
+
if (!res)
|
|
2856
|
+
throw new CompilerError("Cannot eval null", node);
|
|
2143
2857
|
const [evaluated, evaluatedInst] = res.eval(scope);
|
|
2144
|
-
|
|
2858
|
+
const result = [evaluated, [...inst, ...evaluatedInst]];
|
|
2859
|
+
if (this.sourcemap)
|
|
2860
|
+
return appendSourceLocations(result, node);
|
|
2861
|
+
return result;
|
|
2145
2862
|
}
|
|
2146
2863
|
handleConsume(scope, node) {
|
|
2147
2864
|
const [res, inst] = this.handle(scope, node);
|
|
2148
|
-
|
|
2865
|
+
if (!res)
|
|
2866
|
+
throw new CompilerError("Cannot consume null", node);
|
|
2149
2867
|
const [evaluated, evaluatedInst] = res.consume(scope);
|
|
2150
|
-
|
|
2868
|
+
const result = [evaluated, [...inst, ...evaluatedInst]];
|
|
2869
|
+
if (this.sourcemap)
|
|
2870
|
+
return appendSourceLocations(result, node);
|
|
2871
|
+
return result;
|
|
2151
2872
|
}
|
|
2152
|
-
|
|
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) {
|
|
2153
2884
|
const lines = [];
|
|
2154
2885
|
for (const node of nodes) {
|
|
2155
|
-
const [, nodeLines] =
|
|
2886
|
+
const [, nodeLines] = this.handle(scope, node, handler && (() => handler(node)));
|
|
2156
2887
|
lines.push(...nodeLines);
|
|
2157
2888
|
}
|
|
2158
2889
|
return [null, lines];
|
|
2159
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
|
+
}
|
|
2160
2915
|
}
|
|
2161
2916
|
|
|
2162
2917
|
export { Compiler, CompilerError };
|