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