mlogjs 0.2.2 → 0.3.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/build/Compiler.js +105 -0
- package/build/Compiler.js.map +1 -0
- package/build/CompilerError.js +11 -0
- package/build/CompilerError.js.map +1 -0
- package/build/Scope.js +71 -0
- package/build/Scope.js.map +1 -0
- package/build/bin.js +75 -0
- package/build/bin.js.map +1 -0
- package/build/handlers/BlockStatement.js +14 -0
- package/build/handlers/BlockStatement.js.map +1 -0
- package/build/handlers/CallExpression.js +20 -0
- package/build/handlers/CallExpression.js.map +1 -0
- package/build/handlers/File.js +9 -0
- package/build/handlers/File.js.map +1 -0
- package/build/handlers/ForStatement.js +32 -0
- package/build/handlers/ForStatement.js.map +1 -0
- package/build/handlers/Function.js +47 -0
- package/build/handlers/Function.js.map +1 -0
- package/build/handlers/Identifier.js +8 -0
- package/build/handlers/Identifier.js.map +1 -0
- package/build/handlers/IfStatement.js +25 -0
- package/build/handlers/IfStatement.js.map +1 -0
- package/build/handlers/Literal.js +15 -0
- package/build/handlers/Literal.js.map +1 -0
- package/build/handlers/Object.js +55 -0
- package/build/handlers/Object.js.map +1 -0
- package/build/handlers/OperationExpressions.js +38 -0
- package/build/handlers/OperationExpressions.js.map +1 -0
- package/build/handlers/Program.js +9 -0
- package/build/handlers/Program.js.map +1 -0
- package/build/handlers/Statements.js +30 -0
- package/build/handlers/Statements.js.map +1 -0
- package/build/handlers/TemplateExpression.js +18 -0
- package/build/handlers/TemplateExpression.js.map +1 -0
- package/build/handlers/VariableDeclaration.js +72 -0
- package/build/handlers/VariableDeclaration.js.map +1 -0
- package/build/handlers/WhileStatement.js +23 -0
- package/build/handlers/WhileStatement.js.map +1 -0
- package/build/handlers/index.js +32 -0
- package/build/handlers/index.js.map +1 -0
- package/build/index.js +8 -0
- package/build/index.js.map +1 -0
- package/build/initScope.js +40 -0
- package/build/initScope.js.map +1 -0
- package/build/instructions/AddressResolver.js +31 -0
- package/build/instructions/AddressResolver.js.map +1 -0
- package/build/instructions/ControlInstructions.js +23 -0
- package/build/instructions/ControlInstructions.js.map +1 -0
- package/build/instructions/EndInstruction.js +11 -0
- package/build/instructions/EndInstruction.js.map +1 -0
- package/build/instructions/InstructionBase.js +21 -0
- package/build/instructions/InstructionBase.js.map +1 -0
- package/build/instructions/JumpInstruction.js +22 -0
- package/build/instructions/JumpInstruction.js.map +1 -0
- package/build/instructions/OperationInstruction.js +11 -0
- package/build/instructions/OperationInstruction.js.map +1 -0
- package/build/instructions/SetCounterInstruction.js +11 -0
- package/build/instructions/SetCounterInstruction.js.map +1 -0
- package/build/instructions/SetInstruction.js +11 -0
- package/build/instructions/SetInstruction.js.map +1 -0
- package/build/instructions/ZeroSpaceInstruction.js +11 -0
- package/build/instructions/ZeroSpaceInstruction.js.map +1 -0
- package/build/instructions/index.js +26 -0
- package/build/instructions/index.js.map +1 -0
- package/build/macros/Building.js +89 -0
- package/build/macros/Building.js.map +1 -0
- package/build/macros/Function.js +20 -0
- package/build/macros/Function.js.map +1 -0
- package/build/macros/Math.js +62 -0
- package/build/macros/Math.js.map +1 -0
- package/build/macros/Memory.js +63 -0
- package/build/macros/Memory.js.map +1 -0
- package/build/macros/Namespace.js +111 -0
- package/build/macros/Namespace.js.map +1 -0
- package/build/macros/Other.js +21 -0
- package/build/macros/Other.js.map +1 -0
- package/build/macros/RawValue.js +17 -0
- package/build/macros/RawValue.js.map +1 -0
- package/build/macros/commands/Control.js +26 -0
- package/build/macros/commands/Control.js.map +1 -0
- package/build/macros/commands/Draw.js +40 -0
- package/build/macros/commands/Draw.js.map +1 -0
- package/build/macros/commands/DrawFlush.js +18 -0
- package/build/macros/commands/DrawFlush.js.map +1 -0
- package/build/macros/commands/GetLink.js +25 -0
- package/build/macros/commands/GetLink.js.map +1 -0
- package/build/macros/commands/Lookup.js +25 -0
- package/build/macros/commands/Lookup.js.map +1 -0
- package/build/macros/commands/Print.js +18 -0
- package/build/macros/commands/Print.js.map +1 -0
- package/build/macros/commands/PrintFlush.js +18 -0
- package/build/macros/commands/PrintFlush.js.map +1 -0
- package/build/macros/commands/Radar.js +65 -0
- package/build/macros/commands/Radar.js.map +1 -0
- package/build/macros/commands/Sensor.js +21 -0
- package/build/macros/commands/Sensor.js.map +1 -0
- package/build/macros/commands/UnitBind.js +18 -0
- package/build/macros/commands/UnitBind.js.map +1 -0
- package/build/macros/commands/UnitControl.js +73 -0
- package/build/macros/commands/UnitControl.js.map +1 -0
- package/build/macros/commands/UnitLocate.js +76 -0
- package/build/macros/commands/UnitLocate.js.map +1 -0
- package/build/macros/commands/UnitRadar.js +48 -0
- package/build/macros/commands/UnitRadar.js.map +1 -0
- package/build/macros/commands/Wait.js +19 -0
- package/build/macros/commands/Wait.js.map +1 -0
- package/build/macros/commands/index.js +33 -0
- package/build/macros/commands/index.js.map +1 -0
- package/build/macros/index.js +40 -0
- package/build/macros/index.js.map +1 -0
- package/build/operators.js +102 -0
- package/build/operators.js.map +1 -0
- package/build/types.js +28 -0
- package/build/types.js.map +1 -0
- package/build/utils.js +18 -0
- package/build/utils.js.map +1 -0
- package/build/values/BaseValue.js +112 -0
- package/build/values/BaseValue.js.map +1 -0
- package/build/values/FunctionValue.js +116 -0
- package/build/values/FunctionValue.js.map +1 -0
- package/build/values/LiteralValue.js +89 -0
- package/build/values/LiteralValue.js.map +1 -0
- package/build/values/ObjectValue.js +55 -0
- package/build/values/ObjectValue.js.map +1 -0
- package/build/values/StoreValue.js +32 -0
- package/build/values/StoreValue.js.map +1 -0
- package/build/values/TempValue.js +78 -0
- package/build/values/TempValue.js.map +1 -0
- package/build/values/VoidValue.js +32 -0
- package/build/values/VoidValue.js.map +1 -0
- package/build/values/index.js +23 -0
- package/build/values/index.js.map +1 -0
- package/dist/bin.cjs +17 -4
- package/dist/bin.cjs.map +1 -0
- package/dist/index.cjs +940 -570
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +918 -569
- package/dist/index.mjs.map +1 -0
- package/dist/types/Compiler.d.ts +11 -3
- package/dist/types/CompilerError.d.ts +9 -0
- package/dist/types/Scope.d.ts +10 -9
- package/dist/types/handlers/File.d.ts +2 -0
- package/dist/types/handlers/Function.d.ts +1 -0
- package/dist/types/handlers/Literal.d.ts +4 -1
- package/dist/types/handlers/Object.d.ts +2 -0
- package/dist/types/handlers/OperationExpressions.d.ts +1 -0
- package/dist/types/handlers/Typescript.d.ts +7 -0
- package/dist/types/handlers/VariableDeclaration.d.ts +2 -2
- package/dist/types/handlers/WhileStatement.d.ts +1 -0
- package/dist/types/handlers/index.d.ts +2 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/initScope.d.ts +3 -0
- package/dist/types/instructions/ControlInstructions.d.ts +0 -3
- package/dist/types/instructions/InstructionBase.d.ts +2 -2
- package/dist/types/instructions/SetInstruction.d.ts +1 -0
- package/dist/types/macros/Building.d.ts +1 -2
- package/dist/types/macros/Entities.d.ts +11 -0
- package/dist/types/macros/Function.d.ts +2 -1
- package/dist/types/macros/GetGlobal.d.ts +5 -0
- package/dist/types/macros/Namespace.d.ts +0 -5
- package/dist/types/macros/commands/End.d.ts +5 -0
- package/dist/types/macros/commands/index.d.ts +1 -0
- package/dist/types/macros/index.d.ts +0 -1
- package/dist/types/operators.d.ts +1 -1
- package/dist/types/types.d.ts +121 -12
- package/dist/types/utils.d.ts +22 -1
- package/dist/types/values/BaseValue.d.ts +3 -1
- package/dist/types/values/DestructuringValue.d.ts +17 -0
- package/dist/types/values/FunctionValue.d.ts +21 -8
- package/dist/types/values/LiteralValue.d.ts +2 -1
- package/dist/types/values/ObjectValue.d.ts +5 -1
- package/dist/types/values/SenseableValue.d.ts +23 -0
- package/dist/types/values/StackValue.d.ts +16 -0
- package/dist/types/values/StoreValue.d.ts +7 -3
- package/dist/types/values/TempValue.d.ts +9 -2
- package/dist/types/values/ValueOwner.d.ts +27 -0
- package/dist/types/values/VoidValue.d.ts +8 -5
- package/dist/types/values/index.d.ts +2 -1
- package/lib/commands.d.ts +242 -36
- package/lib/globals.d.ts +172 -159
- package/lib/helpers.d.ts +2 -2
- package/lib/memory.d.ts +1 -1
- package/lib/traits.d.ts +130 -109
- package/package.json +23 -18
- package/build/bin.cjs +0 -69
- package/doc/README.md +0 -9
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import { parse } from '
|
|
1
|
+
import { parse } from '@babel/parser';
|
|
2
|
+
import * as es from '@babel/types';
|
|
3
|
+
|
|
4
|
+
class CompilerError extends Error {
|
|
5
|
+
constructor(message, nodeStack = []) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.nodeStack = nodeStack;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
2
10
|
|
|
3
11
|
const arithmeticBinaryOperators = [
|
|
4
12
|
"*",
|
|
@@ -73,46 +81,29 @@ const unaryOperators = [
|
|
|
73
81
|
];
|
|
74
82
|
const updateOperators = ["++", "--"];
|
|
75
83
|
const singleOperators = [...unaryOperators, ...updateOperators];
|
|
76
|
-
const operators = [...leftRightOperators, ...singleOperators];
|
|
77
|
-
const operatorMap$2 = {
|
|
78
|
-
"==": "equal",
|
|
79
|
-
"===": "strictEqual",
|
|
80
|
-
"!=": "notEqual",
|
|
81
|
-
"!==": "notEqual",
|
|
82
|
-
"<": "lessThan",
|
|
83
|
-
">": "greaterThan",
|
|
84
|
-
"<=": "lessThanEq",
|
|
85
|
-
">=": "greaterThanEq",
|
|
86
|
-
"+": "add",
|
|
87
|
-
"-": "sub",
|
|
88
|
-
"*": "mul",
|
|
89
|
-
"/": "div",
|
|
90
|
-
"%": "mod",
|
|
91
|
-
"**": "pow",
|
|
92
|
-
"|": "or",
|
|
93
|
-
"&": "and",
|
|
94
|
-
"^": "xor",
|
|
95
|
-
">>": "shr",
|
|
96
|
-
">>>": "shr",
|
|
97
|
-
"<<": "shl",
|
|
98
|
-
"&&": "land",
|
|
99
|
-
"||": "or",
|
|
100
|
-
};
|
|
84
|
+
const operators = [...leftRightOperators, ...singleOperators];
|
|
101
85
|
|
|
102
86
|
class VoidValue {
|
|
103
87
|
constructor(scope) {
|
|
88
|
+
this.owner = null;
|
|
104
89
|
this.constant = false;
|
|
105
90
|
this.macro = false;
|
|
106
91
|
this.scope = scope;
|
|
107
92
|
}
|
|
108
|
-
eval(
|
|
109
|
-
throw new
|
|
93
|
+
eval(_scope) {
|
|
94
|
+
throw new CompilerError(`${this} cannot eval.`);
|
|
110
95
|
}
|
|
111
|
-
|
|
112
|
-
throw new
|
|
96
|
+
consume(_scope) {
|
|
97
|
+
throw new CompilerError(`${this} cannot be consumed.`);
|
|
113
98
|
}
|
|
114
|
-
|
|
115
|
-
throw new
|
|
99
|
+
call(_scope, _args) {
|
|
100
|
+
throw new CompilerError(`${this} cannot call.`);
|
|
101
|
+
}
|
|
102
|
+
get(_scope, _name) {
|
|
103
|
+
throw new CompilerError(`${this} cannot get.`);
|
|
104
|
+
}
|
|
105
|
+
ensureOwned() {
|
|
106
|
+
throw new CompilerError(`${this} cannot be owned`);
|
|
116
107
|
}
|
|
117
108
|
toString() {
|
|
118
109
|
return "void";
|
|
@@ -121,7 +112,7 @@ class VoidValue {
|
|
|
121
112
|
for (const key of operators) {
|
|
122
113
|
VoidValue.prototype[key] = function () {
|
|
123
114
|
console.log(this);
|
|
124
|
-
throw new
|
|
115
|
+
throw new CompilerError(`${this} cannot '${key}' operation.`);
|
|
125
116
|
};
|
|
126
117
|
}
|
|
127
118
|
|
|
@@ -136,7 +127,7 @@ class InstructionBase {
|
|
|
136
127
|
set hidden(value) {
|
|
137
128
|
this._hidden = value;
|
|
138
129
|
}
|
|
139
|
-
resolve(
|
|
130
|
+
resolve(_i) { }
|
|
140
131
|
toString() {
|
|
141
132
|
return this.args.filter(arg => arg).join(" ");
|
|
142
133
|
}
|
|
@@ -152,6 +143,9 @@ class SetInstruction extends InstructionBase {
|
|
|
152
143
|
constructor(store, value) {
|
|
153
144
|
super("set", store, value);
|
|
154
145
|
}
|
|
146
|
+
get hidden() {
|
|
147
|
+
return this._hidden || !this.args[1].owner;
|
|
148
|
+
}
|
|
155
149
|
}
|
|
156
150
|
|
|
157
151
|
class EndInstruction extends InstructionBase {
|
|
@@ -224,17 +218,44 @@ class ContinueInstruction extends JumpInstruction {
|
|
|
224
218
|
constructor(address) {
|
|
225
219
|
super(address, EJumpKind.Always);
|
|
226
220
|
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
class ValueOwner {
|
|
224
|
+
/**
|
|
225
|
+
* Creates a new `ValueOwner`, if `value` is already owned,
|
|
226
|
+
* `this` will be aliased to `value`, else `this` will own `value`
|
|
227
|
+
*/
|
|
228
|
+
constructor({ scope, constant = false, value, identifier, name, }) {
|
|
229
|
+
this.scope = scope;
|
|
230
|
+
this.constant = constant;
|
|
231
|
+
this.value = value;
|
|
232
|
+
this.identifier = identifier;
|
|
233
|
+
this.name = name ?? scope.makeTempName();
|
|
234
|
+
this.persistent = !!name;
|
|
235
|
+
this.owned = new Set();
|
|
236
|
+
if (!value.owner?.persistent)
|
|
237
|
+
this.own(value);
|
|
238
|
+
}
|
|
239
|
+
own(target) {
|
|
240
|
+
target.owner = this;
|
|
241
|
+
this.owned.add(target);
|
|
242
|
+
}
|
|
243
|
+
replace(target) {
|
|
244
|
+
this.value.owner = null;
|
|
245
|
+
this.owned.delete(this.value);
|
|
246
|
+
this.value = target;
|
|
247
|
+
this.own(target);
|
|
248
|
+
}
|
|
249
|
+
moveInto(owner) {
|
|
250
|
+
this.owned.forEach(value => owner.own(value));
|
|
251
|
+
this.owned.clear();
|
|
231
252
|
}
|
|
232
253
|
}
|
|
233
254
|
|
|
234
255
|
class BaseValue extends VoidValue {
|
|
235
256
|
"u-"(scope) {
|
|
236
|
-
const [that, inst] = this.
|
|
237
|
-
const temp = new
|
|
257
|
+
const [that, inst] = this.consume(scope);
|
|
258
|
+
const temp = new StoreValue(scope);
|
|
238
259
|
return [
|
|
239
260
|
temp,
|
|
240
261
|
[
|
|
@@ -243,6 +264,13 @@ class BaseValue extends VoidValue {
|
|
|
243
264
|
],
|
|
244
265
|
];
|
|
245
266
|
}
|
|
267
|
+
"u+"(scope) {
|
|
268
|
+
// TODO: should it return 0 + this ?
|
|
269
|
+
return this.eval(scope);
|
|
270
|
+
}
|
|
271
|
+
ensureOwned() {
|
|
272
|
+
this.owner ??= new ValueOwner({ scope: this.scope, value: this });
|
|
273
|
+
}
|
|
246
274
|
}
|
|
247
275
|
const operatorMap$1 = {
|
|
248
276
|
"==": "equal",
|
|
@@ -271,9 +299,9 @@ const operatorMap$1 = {
|
|
|
271
299
|
for (const key in operatorMap$1) {
|
|
272
300
|
const kind = operatorMap$1[key];
|
|
273
301
|
BaseValue.prototype[key] = function (scope, value) {
|
|
274
|
-
const [left, leftInst] = this.
|
|
275
|
-
const [right, rightInst] = value.
|
|
276
|
-
const temp = new
|
|
302
|
+
const [left, leftInst] = this.consume(scope);
|
|
303
|
+
const [right, rightInst] = value.consume(scope);
|
|
304
|
+
const temp = new StoreValue(scope);
|
|
277
305
|
return [
|
|
278
306
|
temp,
|
|
279
307
|
[
|
|
@@ -291,8 +319,8 @@ const unaryOperatorMap$1 = {
|
|
|
291
319
|
for (const key in unaryOperatorMap$1) {
|
|
292
320
|
const name = unaryOperatorMap$1[key];
|
|
293
321
|
BaseValue.prototype[key] = function (scope) {
|
|
294
|
-
const [that, inst] = this.
|
|
295
|
-
const temp = new
|
|
322
|
+
const [that, inst] = this.consume(scope);
|
|
323
|
+
const temp = new StoreValue(scope);
|
|
296
324
|
return [temp, [...inst, new OperationInstruction(name, temp, that, null)]];
|
|
297
325
|
};
|
|
298
326
|
}
|
|
@@ -314,6 +342,7 @@ const assignmentToBinary = {
|
|
|
314
342
|
};
|
|
315
343
|
for (const op in assignmentToBinary) {
|
|
316
344
|
BaseValue.prototype[op] = function (scope, value) {
|
|
345
|
+
this.ensureOwned();
|
|
317
346
|
const [opValue, opInst] = this[assignmentToBinary[op]](scope, value);
|
|
318
347
|
const [retValue, retInst] = this["="](scope, opValue);
|
|
319
348
|
return [retValue, [...opInst, ...retInst]];
|
|
@@ -321,9 +350,9 @@ for (const op in assignmentToBinary) {
|
|
|
321
350
|
}
|
|
322
351
|
for (const key of updateOperators) {
|
|
323
352
|
BaseValue.prototype[key] = function (scope, prefix) {
|
|
324
|
-
let [ret, inst] = this.
|
|
353
|
+
let [ret, inst] = this.consume(scope);
|
|
325
354
|
if (!prefix) {
|
|
326
|
-
const temp = new
|
|
355
|
+
const temp = new StoreValue(scope);
|
|
327
356
|
const [tempValue, tempInst] = temp["="](scope, ret);
|
|
328
357
|
ret = tempValue;
|
|
329
358
|
inst.push(...tempInst);
|
|
@@ -339,7 +368,7 @@ for (const key of updateOperators) {
|
|
|
339
368
|
const literalMethods = {
|
|
340
369
|
length: function (scope) {
|
|
341
370
|
if (typeof this.data !== "string")
|
|
342
|
-
throw new
|
|
371
|
+
throw new CompilerError("Length method only works on string literal values.");
|
|
343
372
|
return new LiteralValue(scope, this.data.length);
|
|
344
373
|
},
|
|
345
374
|
};
|
|
@@ -349,7 +378,10 @@ class LiteralValue extends BaseValue {
|
|
|
349
378
|
this.constant = true;
|
|
350
379
|
this.data = data;
|
|
351
380
|
}
|
|
352
|
-
eval(
|
|
381
|
+
eval(_scope) {
|
|
382
|
+
return [this, []];
|
|
383
|
+
}
|
|
384
|
+
consume(_scope) {
|
|
353
385
|
return [this, []];
|
|
354
386
|
}
|
|
355
387
|
toString() {
|
|
@@ -360,7 +392,7 @@ class LiteralValue extends BaseValue {
|
|
|
360
392
|
return super.get(scope, name);
|
|
361
393
|
const method = literalMethods[name.data];
|
|
362
394
|
if (!method)
|
|
363
|
-
throw new
|
|
395
|
+
throw new CompilerError(`Method ${name.data} does not exist on literal values.`);
|
|
364
396
|
return [method.apply(this, [scope]), []];
|
|
365
397
|
}
|
|
366
398
|
get num() {
|
|
@@ -419,87 +451,94 @@ for (const key in unaryOperatorMap) {
|
|
|
419
451
|
};
|
|
420
452
|
}
|
|
421
453
|
|
|
454
|
+
/**
|
|
455
|
+
* The prefix for internal variables inside the compiler output
|
|
456
|
+
*/
|
|
457
|
+
const internalPrefix = "&";
|
|
458
|
+
const discardedName = `${internalPrefix}_`;
|
|
459
|
+
/**
|
|
460
|
+
* Returns a string that has the format: [line]:[column].
|
|
461
|
+
*
|
|
462
|
+
* If `name` is provided, and it is a string, the resulting string will
|
|
463
|
+
* have the format: [name]:[line]:[column].
|
|
464
|
+
*/
|
|
465
|
+
function nodeName(node, name) {
|
|
466
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
467
|
+
const { line, column } = node.loc.start;
|
|
468
|
+
if (typeof name === "string")
|
|
469
|
+
return `${name}:${line}:${column}`;
|
|
470
|
+
return `${line}:${column}`;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Converts a camel case string into a dash case one.
|
|
474
|
+
*
|
|
475
|
+
* As an example `camelCase` becomes `camel-case`
|
|
476
|
+
* @example
|
|
477
|
+
* ```
|
|
478
|
+
* camelToDashCase("camelCase") // returns "camel-case"
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
function camelToDashCase(name) {
|
|
482
|
+
return name.replace(/[A-Z]/g, str => `-${str.toLowerCase()}`);
|
|
483
|
+
}
|
|
484
|
+
const itemNames = [
|
|
485
|
+
"copper",
|
|
486
|
+
"lead",
|
|
487
|
+
"metaglass",
|
|
488
|
+
"graphite",
|
|
489
|
+
"sand",
|
|
490
|
+
"coal",
|
|
491
|
+
"titanium",
|
|
492
|
+
"thorium",
|
|
493
|
+
"scrap",
|
|
494
|
+
"silicon",
|
|
495
|
+
"plastanium",
|
|
496
|
+
"phaseFabric",
|
|
497
|
+
"surgeAlloy",
|
|
498
|
+
"sporePod",
|
|
499
|
+
"blastCompound",
|
|
500
|
+
"pyratite",
|
|
501
|
+
];
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* `StoreValue` represents values unknown at compile time,
|
|
505
|
+
* mostly used with mutable variables and temporary values
|
|
506
|
+
*/
|
|
422
507
|
class StoreValue extends BaseValue {
|
|
423
|
-
constructor(scope
|
|
508
|
+
constructor(scope) {
|
|
424
509
|
super(scope);
|
|
425
510
|
this.constant = false;
|
|
426
|
-
this.name = name;
|
|
427
511
|
}
|
|
428
512
|
typeof(scope) {
|
|
429
513
|
return [new LiteralValue(scope, "store"), []];
|
|
430
514
|
}
|
|
431
515
|
"="(scope, value) {
|
|
432
516
|
if (this.constant)
|
|
433
|
-
throw new
|
|
434
|
-
if (
|
|
435
|
-
|
|
436
|
-
|
|
517
|
+
throw new CompilerError(`Cannot assign to immutable store '${this}'.`);
|
|
518
|
+
if (this.owner) {
|
|
519
|
+
if (this.owner === value.owner && value instanceof StoreValue)
|
|
520
|
+
return [this, []];
|
|
521
|
+
if (!value.owner?.persistent) {
|
|
522
|
+
if (!value.owner)
|
|
523
|
+
this.owner.own(value);
|
|
524
|
+
else
|
|
525
|
+
value.owner.moveInto(this.owner);
|
|
526
|
+
if (value instanceof StoreValue)
|
|
527
|
+
return [this, []];
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
const [evalValue, evalInst] = value.consume(scope);
|
|
437
531
|
return [this, [...evalInst, new SetInstruction(this, evalValue)]];
|
|
438
532
|
}
|
|
439
|
-
eval(
|
|
533
|
+
eval(_scope) {
|
|
440
534
|
return [this, []];
|
|
441
535
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
class TempValue extends StoreValue {
|
|
448
|
-
constructor(scope, name) {
|
|
449
|
-
super(scope, name ?? "t" + scope.ntemp + (scope.name ? ":" + scope.name : ""));
|
|
450
|
-
this.canProxy = true;
|
|
451
|
-
if (!name)
|
|
452
|
-
scope.ntemp++;
|
|
453
|
-
}
|
|
454
|
-
eval(scope) {
|
|
455
|
-
return super.eval(scope);
|
|
456
|
-
}
|
|
457
|
-
"="(scope, value) {
|
|
458
|
-
if (this.proxied) {
|
|
459
|
-
this.noProxy();
|
|
460
|
-
return [this, [new SetInstruction(this, value)]];
|
|
461
|
-
}
|
|
462
|
-
if (value instanceof LiteralValue && this.canProxy) {
|
|
463
|
-
return this.proxy(value);
|
|
464
|
-
}
|
|
465
|
-
return super["="](scope, value);
|
|
536
|
+
consume(_scope) {
|
|
537
|
+
this.ensureOwned();
|
|
538
|
+
return [this, []];
|
|
466
539
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
console.log(this.proxied);
|
|
470
|
-
throw new Error("Cannot proxy (canProxy = false).");
|
|
471
|
-
}
|
|
472
|
-
if (this.proxied)
|
|
473
|
-
throw new Error("Cannot proxy multiple times.");
|
|
474
|
-
this.proxied = value;
|
|
475
|
-
this.canProxy = false;
|
|
476
|
-
for (const key of [
|
|
477
|
-
...operators,
|
|
478
|
-
"eval",
|
|
479
|
-
"get",
|
|
480
|
-
"call",
|
|
481
|
-
"toString",
|
|
482
|
-
"proxy",
|
|
483
|
-
]) {
|
|
484
|
-
if (key !== "=" && key in value)
|
|
485
|
-
this[key] = (...args) => value[key].apply(value, args);
|
|
486
|
-
}
|
|
487
|
-
this.setInst = new SetInstruction(this, value);
|
|
488
|
-
this.setInst.hidden = true;
|
|
489
|
-
return [this, [this.setInst]];
|
|
490
|
-
}
|
|
491
|
-
noProxy() {
|
|
492
|
-
this.setInst.hidden = false;
|
|
493
|
-
for (const key of [
|
|
494
|
-
...operators,
|
|
495
|
-
"eval",
|
|
496
|
-
"get",
|
|
497
|
-
"call",
|
|
498
|
-
"toString",
|
|
499
|
-
"proxy",
|
|
500
|
-
]) {
|
|
501
|
-
this[key] = TempValue.prototype[key];
|
|
502
|
-
}
|
|
540
|
+
toString() {
|
|
541
|
+
return this.owner?.name ?? discardedName;
|
|
503
542
|
}
|
|
504
543
|
}
|
|
505
544
|
|
|
@@ -510,19 +549,30 @@ class ObjectValue extends VoidValue {
|
|
|
510
549
|
this.macro = true;
|
|
511
550
|
this.data = data;
|
|
512
551
|
}
|
|
552
|
+
static fromArray(scope, items) {
|
|
553
|
+
const data = {
|
|
554
|
+
length: new LiteralValue(scope, items.length),
|
|
555
|
+
};
|
|
556
|
+
items.forEach((item, i) => {
|
|
557
|
+
if (item)
|
|
558
|
+
data[i] = item;
|
|
559
|
+
});
|
|
560
|
+
return new ObjectValue(scope, data);
|
|
561
|
+
}
|
|
513
562
|
typeof(scope) {
|
|
514
563
|
return [new LiteralValue(scope, "object"), []];
|
|
515
564
|
}
|
|
516
565
|
get(scope, key) {
|
|
517
566
|
// avoids naming collisions with keys like
|
|
518
567
|
// constructor or toString
|
|
519
|
-
if (
|
|
568
|
+
if (Object.prototype.hasOwnProperty.call(this.data, key.data)) {
|
|
569
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
520
570
|
const member = this.data[key.data];
|
|
521
571
|
return [member, []];
|
|
522
572
|
}
|
|
523
573
|
const { $get } = this.data;
|
|
524
574
|
if (!$get)
|
|
525
|
-
throw new
|
|
575
|
+
throw new CompilerError("Cannot get undefined member.");
|
|
526
576
|
return $get.call(scope, [key]);
|
|
527
577
|
}
|
|
528
578
|
eval(scope) {
|
|
@@ -531,23 +581,115 @@ class ObjectValue extends VoidValue {
|
|
|
531
581
|
return [this, []];
|
|
532
582
|
return $eval.call(scope, []);
|
|
533
583
|
}
|
|
584
|
+
consume(scope) {
|
|
585
|
+
const { $consume } = this.data;
|
|
586
|
+
if ($consume)
|
|
587
|
+
return $consume.call(scope, []);
|
|
588
|
+
const result = this.eval(scope);
|
|
589
|
+
// required by typescript
|
|
590
|
+
const res = result[0];
|
|
591
|
+
res.ensureOwned();
|
|
592
|
+
return result;
|
|
593
|
+
}
|
|
534
594
|
call(scope, args) {
|
|
535
595
|
const { $call } = this.data;
|
|
536
596
|
if (!$call)
|
|
537
597
|
return super.call(scope, args);
|
|
538
598
|
return $call.call(scope, args);
|
|
539
599
|
}
|
|
600
|
+
ensureOwned() {
|
|
601
|
+
this.owner ??= new ValueOwner({ scope: this.scope, value: this });
|
|
602
|
+
}
|
|
540
603
|
}
|
|
541
604
|
for (const op of operators) {
|
|
542
605
|
ObjectValue.prototype[op] = function (...args) {
|
|
543
606
|
const $ = this.data[`$${op}`];
|
|
607
|
+
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-unsafe-return
|
|
544
608
|
if (!$)
|
|
545
609
|
return VoidValue.prototype[op].apply(this, args);
|
|
546
|
-
|
|
610
|
+
const [scope, ...fnArgs] = args;
|
|
547
611
|
return $.call(scope, fnArgs);
|
|
548
612
|
};
|
|
549
613
|
}
|
|
550
614
|
|
|
615
|
+
/**
|
|
616
|
+
* Properties that should return a new `SenseableValue`
|
|
617
|
+
*/
|
|
618
|
+
const senseableProps = ["controller"];
|
|
619
|
+
/**
|
|
620
|
+
* Senseable values are "objects" in the mlog runtime that
|
|
621
|
+
* have special properties that can be accessed
|
|
622
|
+
* via the `sense` instruction.
|
|
623
|
+
*
|
|
624
|
+
* This class extends `StoreValue` to allow dynamic behavior
|
|
625
|
+
* that is not possible with object macros.
|
|
626
|
+
*
|
|
627
|
+
* Note that these values are constant by default, so make sure
|
|
628
|
+
* to set that field to `false` if you want them to be assignable. Example:
|
|
629
|
+
* ```
|
|
630
|
+
* const value = new SenseableValue(scope)
|
|
631
|
+
* value.constant = false
|
|
632
|
+
* ```
|
|
633
|
+
*/
|
|
634
|
+
class SenseableValue extends StoreValue {
|
|
635
|
+
constructor(scope) {
|
|
636
|
+
super(scope);
|
|
637
|
+
this.constant = true;
|
|
638
|
+
}
|
|
639
|
+
get(scope, prop) {
|
|
640
|
+
if (prop instanceof LiteralValue && typeof prop.data === "string") {
|
|
641
|
+
const name = itemNames.includes(prop.data)
|
|
642
|
+
? camelToDashCase(prop.data)
|
|
643
|
+
: prop.data;
|
|
644
|
+
const result = senseableProps.includes(prop.data)
|
|
645
|
+
? new SenseableValue(scope)
|
|
646
|
+
: new StoreValue(scope);
|
|
647
|
+
return [
|
|
648
|
+
result,
|
|
649
|
+
[new InstructionBase("sensor", result, this, `@${name}`)],
|
|
650
|
+
];
|
|
651
|
+
}
|
|
652
|
+
if (prop instanceof StoreValue) {
|
|
653
|
+
const temp = new StoreValue(scope);
|
|
654
|
+
return [temp, [new InstructionBase("sensor", temp, this, prop)]];
|
|
655
|
+
}
|
|
656
|
+
throw new CompilerError(`Cannot sense "${prop}" property`);
|
|
657
|
+
}
|
|
658
|
+
typeof(scope) {
|
|
659
|
+
return [new LiteralValue(scope, "senseable"), []];
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Specific case class, required on the ArrayPattern and ObjectPattern handlers
|
|
665
|
+
* in order to keep the separation of concerns and make the code more modular.
|
|
666
|
+
*
|
|
667
|
+
* When it is assign a value, it will get it's own properties and recursively assign
|
|
668
|
+
* each of them to their counterparts on the right hand value.
|
|
669
|
+
*/
|
|
670
|
+
class DestructuringValue extends VoidValue {
|
|
671
|
+
constructor(scope, members) {
|
|
672
|
+
super(scope);
|
|
673
|
+
this.members = members;
|
|
674
|
+
this.macro = true;
|
|
675
|
+
}
|
|
676
|
+
"="(scope, right) {
|
|
677
|
+
const inst = [];
|
|
678
|
+
for (const [key, value] of this.members) {
|
|
679
|
+
const [item, itemInst] = right.get(scope, key);
|
|
680
|
+
inst.push(...itemInst);
|
|
681
|
+
inst.push(...value["="](scope, item)[1]);
|
|
682
|
+
}
|
|
683
|
+
return [right, inst];
|
|
684
|
+
}
|
|
685
|
+
eval(_scope) {
|
|
686
|
+
return [this, []];
|
|
687
|
+
}
|
|
688
|
+
consume(_scope) {
|
|
689
|
+
return [this, []];
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
551
693
|
class Scope {
|
|
552
694
|
constructor(values, parent = null, stacked = false, ntemp = 0, name = "", inst = []) {
|
|
553
695
|
this.parent = parent;
|
|
@@ -570,35 +712,64 @@ class Scope {
|
|
|
570
712
|
scope.parent = this;
|
|
571
713
|
return scope;
|
|
572
714
|
}
|
|
573
|
-
createFunction(name, stacked) {
|
|
574
|
-
return new Scope({}, this, stacked
|
|
715
|
+
createFunction(name, stacked = this.stacked) {
|
|
716
|
+
return new Scope({}, this, stacked, 0, name, this.inst);
|
|
575
717
|
}
|
|
576
|
-
has(
|
|
577
|
-
if (
|
|
718
|
+
has(identifier) {
|
|
719
|
+
if (identifier in this.data)
|
|
578
720
|
return true;
|
|
579
721
|
if (this.parent)
|
|
580
|
-
return this.parent.has(
|
|
722
|
+
return this.parent.has(identifier);
|
|
581
723
|
return false;
|
|
582
724
|
}
|
|
583
|
-
get(
|
|
584
|
-
const
|
|
585
|
-
if (
|
|
586
|
-
return value;
|
|
725
|
+
get(identifier) {
|
|
726
|
+
const owner = this.data[identifier];
|
|
727
|
+
if (owner)
|
|
728
|
+
return owner.value;
|
|
587
729
|
if (this.parent)
|
|
588
|
-
return this.parent.get(
|
|
589
|
-
throw
|
|
730
|
+
return this.parent.get(identifier);
|
|
731
|
+
throw new CompilerError(`${identifier} is not declared.`);
|
|
590
732
|
}
|
|
591
|
-
set(
|
|
733
|
+
set(...args) {
|
|
734
|
+
const name = args.length === 1 ? args[0].identifier : args[0];
|
|
735
|
+
if (!name)
|
|
736
|
+
throw new CompilerError("Values in a scope must have an identifier");
|
|
592
737
|
if (name in this.data)
|
|
593
|
-
throw
|
|
594
|
-
return this.hardSet(
|
|
595
|
-
}
|
|
596
|
-
hardSet(
|
|
597
|
-
|
|
598
|
-
|
|
738
|
+
throw new CompilerError(`${name} is already declared.`);
|
|
739
|
+
return this.hardSet(...args);
|
|
740
|
+
}
|
|
741
|
+
hardSet(...args) {
|
|
742
|
+
const owner = args.length === 1
|
|
743
|
+
? args[0]
|
|
744
|
+
: new ValueOwner({
|
|
745
|
+
scope: this,
|
|
746
|
+
identifier: args[0],
|
|
747
|
+
name: args[0],
|
|
748
|
+
value: args[1],
|
|
749
|
+
});
|
|
750
|
+
const { identifier } = owner;
|
|
751
|
+
if (!identifier)
|
|
752
|
+
throw new CompilerError("Values in a scope must have an identifier");
|
|
753
|
+
this.data[identifier] = owner;
|
|
754
|
+
return owner.value;
|
|
755
|
+
}
|
|
756
|
+
make(identifier, name) {
|
|
757
|
+
const value = new SenseableValue(this);
|
|
758
|
+
value.constant = false;
|
|
759
|
+
const owner = new ValueOwner({
|
|
760
|
+
scope: this,
|
|
761
|
+
value,
|
|
762
|
+
identifier,
|
|
763
|
+
name,
|
|
764
|
+
});
|
|
765
|
+
return this.set(owner);
|
|
599
766
|
}
|
|
600
|
-
|
|
601
|
-
|
|
767
|
+
makeTempName() {
|
|
768
|
+
let result = `${internalPrefix}t${this.ntemp}`;
|
|
769
|
+
if (this.name)
|
|
770
|
+
result += `:${this.name}`;
|
|
771
|
+
this.ntemp++;
|
|
772
|
+
return result;
|
|
602
773
|
}
|
|
603
774
|
}
|
|
604
775
|
|
|
@@ -606,86 +777,109 @@ const Program = (c, scope, node) => {
|
|
|
606
777
|
return c.handleMany(scope ?? new Scope({}), node.body);
|
|
607
778
|
};
|
|
608
779
|
|
|
609
|
-
function nodeName(node) {
|
|
610
|
-
const { line, column } = node.loc.start;
|
|
611
|
-
return line + ":" + column;
|
|
612
|
-
}
|
|
613
|
-
function camelToDashCase(name) {
|
|
614
|
-
return name.replace(/[A-Z]/g, str => `-${str.toLowerCase()}`);
|
|
615
|
-
}
|
|
616
|
-
|
|
617
780
|
const VariableDeclaration = (c, scope, node) => {
|
|
618
781
|
return c.handleMany(scope, node.declarations, (scope, child) => VariableDeclarator(c, scope, child, node.kind));
|
|
619
782
|
};
|
|
620
783
|
const VariableDeclarator = (c, scope, node, kind = "let") => {
|
|
621
|
-
|
|
784
|
+
const [init, inst] = node.init
|
|
622
785
|
? c.handleEval(scope, node.init)
|
|
623
786
|
: [null, []];
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
const value = scope.make(name, nodeName(node));
|
|
636
|
-
if (init) {
|
|
637
|
-
if (init.macro)
|
|
638
|
-
throw new Error("Macro value must be constant.");
|
|
639
|
-
valinst[1].push(...value["="](scope, init)[1]);
|
|
640
|
-
}
|
|
641
|
-
if (kind === "const")
|
|
642
|
-
value.constant = true;
|
|
643
|
-
return valinst;
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
case "ArrayPattern": {
|
|
647
|
-
const { elements } = node.id;
|
|
648
|
-
const [init] = valinst;
|
|
649
|
-
if (!init)
|
|
650
|
-
throw new Error("Cannot use array destructuring with constant with void value.");
|
|
651
|
-
if (!init.macro)
|
|
652
|
-
throw new Error("Cannot use array destructuring on non macro values");
|
|
653
|
-
if (!(init instanceof ObjectValue)) {
|
|
654
|
-
throw new Error("Array destructuring target must be an object value");
|
|
655
|
-
}
|
|
656
|
-
for (let i = 0; i < elements.length; i++) {
|
|
657
|
-
const element = elements[i];
|
|
658
|
-
if (!element)
|
|
659
|
-
continue;
|
|
660
|
-
if (element.type !== "Identifier") {
|
|
661
|
-
throw new Error("Array destructuring expression can only have empty items or identifiers");
|
|
662
|
-
}
|
|
663
|
-
const val = init.data[i];
|
|
664
|
-
scope.set(element.name, val);
|
|
665
|
-
}
|
|
666
|
-
return valinst;
|
|
667
|
-
}
|
|
787
|
+
inst.push(...Declare(c, scope, node.id, kind, init)[1]);
|
|
788
|
+
return [null, inst];
|
|
789
|
+
};
|
|
790
|
+
const Declare = (c, scope, node, kind, init) => {
|
|
791
|
+
switch (node.type) {
|
|
792
|
+
case "Identifier":
|
|
793
|
+
return DeclareIdentifier(c, scope, node, kind, init);
|
|
794
|
+
case "ArrayPattern":
|
|
795
|
+
return DeclareArrayPattern(c, scope, node, kind, init);
|
|
796
|
+
case "ObjectPattern":
|
|
797
|
+
return DeclareObjectPattern(c, scope, node, kind, init);
|
|
668
798
|
default:
|
|
669
|
-
throw new
|
|
799
|
+
throw new CompilerError(`Unsupported declaration type: ${node.type}`, [
|
|
800
|
+
node,
|
|
801
|
+
]);
|
|
670
802
|
}
|
|
671
|
-
};
|
|
672
|
-
|
|
673
|
-
const
|
|
674
|
-
const
|
|
675
|
-
if (
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
803
|
+
};
|
|
804
|
+
const DeclareIdentifier = (c, scope, node, kind, init) => {
|
|
805
|
+
const { name: identifier } = node;
|
|
806
|
+
const name = nodeName(node, !c.compactNames && identifier);
|
|
807
|
+
if (kind === "const" && !init)
|
|
808
|
+
throw new CompilerError("Constants must be initialized.", [node]);
|
|
809
|
+
if (kind === "const" && init?.constant) {
|
|
810
|
+
const owner = new ValueOwner({
|
|
811
|
+
scope,
|
|
812
|
+
identifier,
|
|
813
|
+
name,
|
|
814
|
+
value: init,
|
|
815
|
+
constant: true,
|
|
816
|
+
});
|
|
817
|
+
scope.set(owner);
|
|
818
|
+
return [null, []];
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
const value = scope.make(identifier, name);
|
|
822
|
+
const inst = [];
|
|
823
|
+
if (init) {
|
|
824
|
+
if (init.macro)
|
|
825
|
+
throw new CompilerError("Macro values must be held by constants", [
|
|
826
|
+
node,
|
|
827
|
+
]);
|
|
828
|
+
inst.push(...value["="](scope, init)[1]);
|
|
829
|
+
}
|
|
830
|
+
if (kind === "const")
|
|
831
|
+
value.constant = true;
|
|
832
|
+
return [null, inst];
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
const DeclareArrayPattern = (c, scope, node, kind, init) => {
|
|
836
|
+
const { elements } = node;
|
|
837
|
+
if (!(init instanceof ObjectValue))
|
|
838
|
+
throw new CompilerError("The value being destructured must be an object value");
|
|
839
|
+
const inst = [];
|
|
840
|
+
for (let i = 0; i < elements.length; i++) {
|
|
841
|
+
const element = elements[i];
|
|
842
|
+
if (!element)
|
|
843
|
+
continue;
|
|
844
|
+
const val = init.data[i];
|
|
845
|
+
if (!val)
|
|
846
|
+
throw new CompilerError(`The target object does not have a value at index ${i}`, [element]);
|
|
847
|
+
inst.push(...Declare(c, scope, element, kind, val)[1]);
|
|
679
848
|
}
|
|
680
|
-
|
|
681
|
-
|
|
849
|
+
return [null, inst];
|
|
850
|
+
};
|
|
851
|
+
const DeclareObjectPattern = (c, scope, node, kind, base) => {
|
|
852
|
+
if (!base)
|
|
853
|
+
throw new CompilerError("Cannot use object destructuring without an initializer", [node]);
|
|
854
|
+
const { properties } = node;
|
|
855
|
+
const [init, inst] = base.consume(scope);
|
|
856
|
+
for (const prop of properties) {
|
|
857
|
+
if (prop.type === "RestElement")
|
|
858
|
+
throw new CompilerError("The rest operator is not supported", [prop]);
|
|
859
|
+
const { key, value } = prop;
|
|
860
|
+
const child = key.type === "Identifier" && !prop.computed
|
|
861
|
+
? [new LiteralValue(scope, key.name), []]
|
|
862
|
+
: c.handleConsume(scope, prop.key);
|
|
863
|
+
inst.push(...child[1]);
|
|
864
|
+
const propInit = init.get(scope, child[0]);
|
|
865
|
+
inst.push(...propInit[1]);
|
|
866
|
+
inst.push(...Declare(c, scope, value, kind, propInit[0])[1]);
|
|
682
867
|
}
|
|
683
|
-
|
|
868
|
+
return [null, inst];
|
|
684
869
|
};
|
|
685
870
|
|
|
871
|
+
const Literal = (_c, scope, node) => [new LiteralValue(scope, node.value), []];
|
|
872
|
+
const NumericLiteral = Literal;
|
|
873
|
+
const StringLiteral = Literal;
|
|
874
|
+
const NullLiteral = (_c, scope) => [
|
|
875
|
+
new LiteralValue(scope, null),
|
|
876
|
+
[],
|
|
877
|
+
];
|
|
878
|
+
const BooleanLiteral = (_c, scope, node) => [new LiteralValue(scope, +node.value), []];
|
|
879
|
+
|
|
686
880
|
const LRExpression = (c, scope, node) => {
|
|
687
|
-
const [left, leftInst] = c.
|
|
688
|
-
const [right, rightInst] = c.
|
|
881
|
+
const [left, leftInst] = c.handleConsume(scope, node.left);
|
|
882
|
+
const [right, rightInst] = c.handleConsume(scope, node.right);
|
|
689
883
|
const [op, opInst] = left[node.operator](scope, right);
|
|
690
884
|
return [op, [...leftInst, ...rightInst, ...opInst]];
|
|
691
885
|
};
|
|
@@ -693,20 +887,55 @@ const BinaryExpression = LRExpression;
|
|
|
693
887
|
const LogicalExpression = LRExpression;
|
|
694
888
|
const AssignmentExpression = (c, scope, node) => {
|
|
695
889
|
const [left, leftInst] = c.handle(scope, node.left);
|
|
890
|
+
// doesn't need to consume because the operators already do that
|
|
696
891
|
const [right, rightInst] = c.handleEval(scope, node.right);
|
|
892
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
697
893
|
const [op, opInst] = left[node.operator](scope, right);
|
|
698
894
|
return [op, [...leftInst, ...rightInst, ...opInst]];
|
|
699
895
|
};
|
|
700
896
|
const UnaryExpression = (c, scope, { argument, operator }) => {
|
|
701
|
-
const [arg, argInst] = c.
|
|
897
|
+
const [arg, argInst] = c.handleConsume(scope, argument);
|
|
702
898
|
const operatorId = operator == "+" || operator == "-" ? `u${operator}` : operator;
|
|
899
|
+
if (operatorId === "throw")
|
|
900
|
+
throw new CompilerError("throw operator is not supported");
|
|
703
901
|
const [op, opInst] = arg[operatorId](scope);
|
|
704
902
|
return [op, [...argInst, ...opInst]];
|
|
705
903
|
};
|
|
706
904
|
const UpdateExpression = (c, scope, { argument, operator, prefix }) => {
|
|
707
905
|
const [arg, argInst] = c.handle(scope, argument);
|
|
906
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
708
907
|
const [op, opInst] = arg[operator](scope, prefix);
|
|
709
908
|
return [op, [...argInst, ...opInst]];
|
|
909
|
+
};
|
|
910
|
+
const ConditionalExpression = (c, scope, node) => {
|
|
911
|
+
const [test, testInst] = c.handleConsume(scope, node.test);
|
|
912
|
+
if (test instanceof LiteralValue) {
|
|
913
|
+
if (test.data)
|
|
914
|
+
return c.handleEval(scope, node.consequent);
|
|
915
|
+
return c.handleEval(scope, node.alternate);
|
|
916
|
+
}
|
|
917
|
+
// TODO: this creates those annoying jumps on the
|
|
918
|
+
// temp counter, specially if you nest ternary operators
|
|
919
|
+
const result = new StoreValue(scope);
|
|
920
|
+
result.ensureOwned();
|
|
921
|
+
const consequent = c.handleEval(scope, node.consequent);
|
|
922
|
+
const alternate = c.handleEval(scope, node.alternate);
|
|
923
|
+
const alternateStartAdress = new LiteralValue(scope, null);
|
|
924
|
+
const endExpressionAdress = new LiteralValue(scope, null);
|
|
925
|
+
return [
|
|
926
|
+
result,
|
|
927
|
+
[
|
|
928
|
+
...testInst,
|
|
929
|
+
new JumpInstruction(alternateStartAdress, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
|
|
930
|
+
...consequent[1],
|
|
931
|
+
...result["="](scope, consequent[0])[1],
|
|
932
|
+
new JumpInstruction(endExpressionAdress, EJumpKind.Always),
|
|
933
|
+
new AddressResolver(alternateStartAdress),
|
|
934
|
+
...alternate[1],
|
|
935
|
+
...result["="](scope, alternate[0])[1],
|
|
936
|
+
new AddressResolver(endExpressionAdress),
|
|
937
|
+
],
|
|
938
|
+
];
|
|
710
939
|
};
|
|
711
940
|
|
|
712
941
|
const Identifier = (c, scope, node) => {
|
|
@@ -736,7 +965,7 @@ const ReturnStatement = (c, scope, node) => {
|
|
|
736
965
|
|
|
737
966
|
const IfStatement = (c, scope, node) => {
|
|
738
967
|
const inst = [];
|
|
739
|
-
const [test, testInst] = c.
|
|
968
|
+
const [test, testInst] = c.handleConsume(scope, node.test);
|
|
740
969
|
if (test instanceof LiteralValue) {
|
|
741
970
|
if (test.data)
|
|
742
971
|
inst.push(...c.handle(scope, node.consequent)[1]);
|
|
@@ -754,7 +983,7 @@ const IfStatement = (c, scope, node) => {
|
|
|
754
983
|
|
|
755
984
|
const WhileStatement = (c, scope, node) => {
|
|
756
985
|
const lines = [];
|
|
757
|
-
const [test, testLines] = c.
|
|
986
|
+
const [test, testLines] = c.handleConsume(scope, node.test);
|
|
758
987
|
const startLoopAddr = new LiteralValue(scope, null);
|
|
759
988
|
const endLoopAddr = new LiteralValue(scope, null);
|
|
760
989
|
const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
|
|
@@ -767,13 +996,35 @@ const WhileStatement = (c, scope, node) => {
|
|
|
767
996
|
}
|
|
768
997
|
lines.push(startLoopLine, ...testLines, new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...c.handle(scope, node.body)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
|
|
769
998
|
return [null, lines];
|
|
999
|
+
};
|
|
1000
|
+
const DoWhileStatement = (c, scope, node) => {
|
|
1001
|
+
const lines = [];
|
|
1002
|
+
const [test, testLines] = c.handleConsume(scope, node.test);
|
|
1003
|
+
const startLoopAddr = new LiteralValue(scope, null);
|
|
1004
|
+
const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
|
|
1005
|
+
const [, bodyLines] = c.handle(scope, node.body);
|
|
1006
|
+
if (test instanceof LiteralValue) {
|
|
1007
|
+
if (!test.data)
|
|
1008
|
+
return [null, [...lines, ...bodyLines]];
|
|
1009
|
+
return [
|
|
1010
|
+
null,
|
|
1011
|
+
[
|
|
1012
|
+
...lines,
|
|
1013
|
+
startLoopLine,
|
|
1014
|
+
...bodyLines,
|
|
1015
|
+
new JumpInstruction(startLoopAddr, EJumpKind.Always),
|
|
1016
|
+
],
|
|
1017
|
+
];
|
|
1018
|
+
}
|
|
1019
|
+
lines.push(startLoopLine, ...bodyLines, ...testLines, new JumpInstruction(startLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 1)));
|
|
1020
|
+
return [null, lines];
|
|
770
1021
|
};
|
|
771
1022
|
|
|
772
1023
|
const ForStatement = (c, scope, node) => {
|
|
773
1024
|
scope = scope.createScope();
|
|
774
1025
|
const initInst = node.init ? c.handle(scope, node.init)[1] : [];
|
|
775
1026
|
const [test, testLines] = node.test
|
|
776
|
-
? c.
|
|
1027
|
+
? c.handleConsume(scope, node.test)
|
|
777
1028
|
: [new LiteralValue(scope, 1), []];
|
|
778
1029
|
const updateLines = node.update ? c.handle(scope, node.update)[1] : [];
|
|
779
1030
|
const startLoopAddr = new LiteralValue(scope, null);
|
|
@@ -796,65 +1047,108 @@ const ForStatement = (c, scope, node) => {
|
|
|
796
1047
|
};
|
|
797
1048
|
|
|
798
1049
|
class FunctionValue extends VoidValue {
|
|
799
|
-
constructor(scope,
|
|
1050
|
+
constructor({ scope, params, body, c, node, }) {
|
|
800
1051
|
super(scope);
|
|
801
1052
|
this.constant = true;
|
|
802
1053
|
this.macro = true;
|
|
1054
|
+
this.paramOwners = [];
|
|
803
1055
|
this.bundled = false;
|
|
804
|
-
this.
|
|
805
|
-
this.paramNames = paramNames;
|
|
806
|
-
this.paramStores = paramStores;
|
|
1056
|
+
this.initialized = false;
|
|
807
1057
|
this.body = body;
|
|
808
1058
|
this.c = c;
|
|
809
|
-
this.
|
|
810
|
-
|
|
811
|
-
this.createValues();
|
|
812
|
-
this.createInst();
|
|
813
|
-
}
|
|
814
|
-
createValues() {
|
|
815
|
-
this.addr = new LiteralValue(this.scope, null);
|
|
816
|
-
this.temp = new StoreValue(this.scope, "f" + this.name);
|
|
817
|
-
this.ret = new StoreValue(this.scope, "r" + this.name);
|
|
1059
|
+
this.node = node;
|
|
1060
|
+
this.params = params;
|
|
818
1061
|
}
|
|
819
1062
|
typeof(scope) {
|
|
820
1063
|
return [new LiteralValue(scope, "function"), []];
|
|
821
1064
|
}
|
|
822
|
-
|
|
1065
|
+
initScope(name) {
|
|
1066
|
+
this.childScope = this.scope.createFunction(name);
|
|
1067
|
+
this.childScope.function = this;
|
|
1068
|
+
for (const id of this.params) {
|
|
1069
|
+
const name = nodeName(id, !this.c.compactNames && id.name);
|
|
1070
|
+
const owner = new ValueOwner({
|
|
1071
|
+
scope: this.childScope,
|
|
1072
|
+
value: new StoreValue(this.childScope),
|
|
1073
|
+
identifier: id.name,
|
|
1074
|
+
name,
|
|
1075
|
+
});
|
|
1076
|
+
this.childScope.set(owner);
|
|
1077
|
+
this.paramOwners.push(owner);
|
|
1078
|
+
}
|
|
1079
|
+
this.callSize = this.paramOwners.length + 2;
|
|
1080
|
+
}
|
|
1081
|
+
ensureInit() {
|
|
1082
|
+
if (!this.owner)
|
|
1083
|
+
throw new CompilerError(`Functions must be owned by a variable`);
|
|
1084
|
+
if (this.initialized)
|
|
1085
|
+
return;
|
|
1086
|
+
this.initialized = true;
|
|
1087
|
+
const name = nodeName(this.node, !this.c.compactNames && this.owner.name);
|
|
1088
|
+
this.initScope(name);
|
|
1089
|
+
this.addr = new LiteralValue(this.childScope, null);
|
|
1090
|
+
this.temp = new ValueOwner({
|
|
1091
|
+
scope: this.childScope,
|
|
1092
|
+
name: `${internalPrefix}f${name}`,
|
|
1093
|
+
value: new SenseableValue(this.childScope),
|
|
1094
|
+
});
|
|
1095
|
+
this.temp.value.constant = false;
|
|
1096
|
+
this.ret = new ValueOwner({
|
|
1097
|
+
scope: this.childScope,
|
|
1098
|
+
name: `${internalPrefix}r${name}`,
|
|
1099
|
+
value: new StoreValue(this.childScope),
|
|
1100
|
+
});
|
|
823
1101
|
this.inst = [
|
|
824
1102
|
new AddressResolver(this.addr),
|
|
825
|
-
...this.c.handle(this.
|
|
1103
|
+
...this.c.handle(this.childScope, this.body)[1],
|
|
826
1104
|
];
|
|
827
|
-
|
|
1105
|
+
if (!endsWithReturn(this.inst)) {
|
|
1106
|
+
this.inst.push(new SetCounterInstruction(this.ret.value));
|
|
1107
|
+
}
|
|
828
1108
|
}
|
|
829
1109
|
normalReturn(scope, arg) {
|
|
830
|
-
const argInst = arg ? this.temp["="](scope, arg)[1] : [];
|
|
831
|
-
return [null, [...argInst, new SetCounterInstruction(this.ret)]];
|
|
1110
|
+
const argInst = arg ? this.temp.value["="](scope, arg)[1] : [];
|
|
1111
|
+
return [null, [...argInst, new SetCounterInstruction(this.ret.value)]];
|
|
832
1112
|
}
|
|
833
1113
|
normalCall(scope, args) {
|
|
834
1114
|
if (!this.bundled)
|
|
835
|
-
this.
|
|
1115
|
+
this.childScope.inst.push(...this.inst);
|
|
836
1116
|
this.bundled = true;
|
|
837
1117
|
const callAddressLiteral = new LiteralValue(scope, null);
|
|
838
|
-
const inst = this.
|
|
839
|
-
.map((param, i) => param["="](scope, args[i])[1])
|
|
1118
|
+
const inst = this.paramOwners
|
|
1119
|
+
.map(({ value: param }, i) => param["="](scope, args[i])[1])
|
|
840
1120
|
.reduce((s, c) => s.concat(c), [])
|
|
841
|
-
.concat(...this.ret["="](scope, callAddressLiteral)[1], new JumpInstruction(this.addr, EJumpKind.Always), new AddressResolver(callAddressLiteral));
|
|
842
|
-
return [this.temp, inst];
|
|
1121
|
+
.concat(...this.ret.value["="](scope, callAddressLiteral)[1], new JumpInstruction(this.addr, EJumpKind.Always), new AddressResolver(callAddressLiteral));
|
|
1122
|
+
return [this.temp.value, inst];
|
|
843
1123
|
}
|
|
844
1124
|
inlineReturn(scope, arg) {
|
|
845
|
-
const argInst = arg ? this.inlineTemp["="](scope, arg)[1] : [];
|
|
846
|
-
return [null,
|
|
1125
|
+
const argInst = arg ? this.inlineTemp.value["="](scope, arg)[1] : [];
|
|
1126
|
+
return [null, argInst];
|
|
847
1127
|
}
|
|
848
1128
|
inlineCall(scope, args) {
|
|
849
1129
|
// create return value
|
|
850
|
-
this.inlineTemp = new
|
|
1130
|
+
this.inlineTemp = new ValueOwner({
|
|
1131
|
+
scope: this.childScope,
|
|
1132
|
+
value: new SenseableValue(scope),
|
|
1133
|
+
});
|
|
1134
|
+
this.inlineTemp.value.constant = false;
|
|
851
1135
|
this.inlineEnd = new LiteralValue(scope, null);
|
|
852
1136
|
// make a copy of the function scope
|
|
853
|
-
const fnScope = this.
|
|
1137
|
+
const fnScope = this.childScope.copy();
|
|
854
1138
|
// hard set variables within the function scope
|
|
855
|
-
this.
|
|
1139
|
+
this.paramOwners.forEach((owner, i) => {
|
|
1140
|
+
const value = args[i];
|
|
1141
|
+
if (!value.owner?.persistent)
|
|
1142
|
+
owner.own(value);
|
|
1143
|
+
fnScope.hardSet(new ValueOwner({
|
|
1144
|
+
scope: fnScope,
|
|
1145
|
+
value,
|
|
1146
|
+
identifier: owner.identifier,
|
|
1147
|
+
name: owner.name,
|
|
1148
|
+
}));
|
|
1149
|
+
});
|
|
856
1150
|
this.tryingInline = true;
|
|
857
|
-
|
|
1151
|
+
const inst = this.c.handle(fnScope, this.body)[1];
|
|
858
1152
|
this.tryingInline = false;
|
|
859
1153
|
// removing useless instruction
|
|
860
1154
|
// get the last instructions
|
|
@@ -865,11 +1159,12 @@ class FunctionValue extends VoidValue {
|
|
|
865
1159
|
// }
|
|
866
1160
|
inst.push(new AddressResolver(this.inlineEnd));
|
|
867
1161
|
// return the function value
|
|
868
|
-
return [this.inlineTemp, inst];
|
|
1162
|
+
return [this.inlineTemp.value, inst];
|
|
869
1163
|
}
|
|
870
1164
|
call(scope, args) {
|
|
871
|
-
|
|
872
|
-
|
|
1165
|
+
this.ensureInit();
|
|
1166
|
+
if (args.length !== this.paramOwners.length)
|
|
1167
|
+
throw new CompilerError("Cannot call: argument count not matching.");
|
|
873
1168
|
const inlineCall = this.inlineCall(scope, args);
|
|
874
1169
|
const inlineSize = inlineCall[1].filter(i => !i.hidden).length;
|
|
875
1170
|
if (this.inline || inlineSize <= this.callSize)
|
|
@@ -877,6 +1172,7 @@ class FunctionValue extends VoidValue {
|
|
|
877
1172
|
return this.normalCall(scope, args);
|
|
878
1173
|
}
|
|
879
1174
|
return(scope, arg) {
|
|
1175
|
+
this.ensureInit();
|
|
880
1176
|
if (arg && arg.macro) {
|
|
881
1177
|
this.inline = true;
|
|
882
1178
|
return [null, []];
|
|
@@ -885,49 +1181,67 @@ class FunctionValue extends VoidValue {
|
|
|
885
1181
|
return this.inlineReturn(scope, arg);
|
|
886
1182
|
return this.normalReturn(scope, arg);
|
|
887
1183
|
}
|
|
888
|
-
eval(
|
|
1184
|
+
eval(_scope) {
|
|
889
1185
|
return [this, []];
|
|
890
1186
|
}
|
|
1187
|
+
consume(_scope) {
|
|
1188
|
+
return [this, []];
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
function endsWithReturn(inst) {
|
|
1192
|
+
for (let i = inst.length - 1; i >= 0; i--) {
|
|
1193
|
+
const instruction = inst[i];
|
|
1194
|
+
if (instruction.hidden)
|
|
1195
|
+
continue;
|
|
1196
|
+
return instruction instanceof SetCounterInstruction;
|
|
1197
|
+
}
|
|
1198
|
+
return false;
|
|
891
1199
|
}
|
|
892
1200
|
|
|
893
|
-
|
|
894
|
-
const name = nodeName(node);
|
|
895
|
-
scope = scope.createFunction(name);
|
|
1201
|
+
function handleFunctionNode(c, scope, node) {
|
|
896
1202
|
let { params, body } = node;
|
|
897
|
-
if (
|
|
898
|
-
body =
|
|
899
|
-
type: "BlockStatement",
|
|
900
|
-
body: [{ type: "ReturnStatement", argument: body }],
|
|
901
|
-
};
|
|
902
|
-
}
|
|
903
|
-
const paramNames = [];
|
|
904
|
-
const paramStores = [];
|
|
905
|
-
for (const id of params) {
|
|
906
|
-
paramNames.push(id.name);
|
|
907
|
-
paramStores.push(scope.make(id.name, nodeName(id)));
|
|
1203
|
+
if (es.isExpression(body)) {
|
|
1204
|
+
body = es.blockStatement([es.returnStatement(body)]);
|
|
908
1205
|
}
|
|
909
1206
|
return [
|
|
910
|
-
new FunctionValue(
|
|
1207
|
+
new FunctionValue({
|
|
1208
|
+
node,
|
|
1209
|
+
scope,
|
|
1210
|
+
params: params,
|
|
1211
|
+
body,
|
|
1212
|
+
c,
|
|
1213
|
+
}),
|
|
911
1214
|
[],
|
|
912
1215
|
];
|
|
1216
|
+
}
|
|
1217
|
+
const ArrowFunctionExpression = (c, scope, node) => {
|
|
1218
|
+
return handleFunctionNode(c, scope, node);
|
|
913
1219
|
};
|
|
914
1220
|
const FunctionDeclaration = (c, scope, node) => {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1221
|
+
const identifier = node.id.name;
|
|
1222
|
+
const name = nodeName(node, !c.compactNames && identifier);
|
|
1223
|
+
const functionIns = handleFunctionNode(c, scope, node);
|
|
1224
|
+
const owner = new ValueOwner({
|
|
1225
|
+
scope,
|
|
1226
|
+
value: functionIns[0],
|
|
1227
|
+
identifier,
|
|
1228
|
+
name,
|
|
1229
|
+
});
|
|
1230
|
+
return [scope.set(owner), []];
|
|
919
1231
|
};
|
|
920
|
-
const FunctionExpression = ArrowFunctionExpression;
|
|
1232
|
+
const FunctionExpression = ArrowFunctionExpression;
|
|
1233
|
+
const ObjectMethod = ArrowFunctionExpression;
|
|
921
1234
|
|
|
922
1235
|
const CallExpression = (c, scope, node) => {
|
|
923
1236
|
const inst = [];
|
|
924
1237
|
const args = node.arguments.map(node => {
|
|
925
1238
|
// TODO: this might be why t0 did not increment
|
|
926
|
-
|
|
1239
|
+
// TODO: figure out if the previous todo is still relevant
|
|
1240
|
+
const [v, i] = c.handleConsume(scope, node);
|
|
927
1241
|
inst.push(...i);
|
|
928
1242
|
return v;
|
|
929
1243
|
});
|
|
930
|
-
const [callee, calleeInst] = c.
|
|
1244
|
+
const [callee, calleeInst] = c.handleConsume(scope, node.callee);
|
|
931
1245
|
inst.push(...calleeInst);
|
|
932
1246
|
const [callValue, callInst] = callee.call(scope, args);
|
|
933
1247
|
inst.push(...callInst);
|
|
@@ -939,49 +1253,101 @@ const ObjectExpression = (c, scope, node) => {
|
|
|
939
1253
|
const data = {};
|
|
940
1254
|
const inst = [];
|
|
941
1255
|
for (const prop of node.properties) {
|
|
1256
|
+
if (prop.type === "SpreadElement")
|
|
1257
|
+
throw new CompilerError("Cannot handle spread element", [prop]);
|
|
942
1258
|
if (prop.computed)
|
|
943
|
-
throw new
|
|
944
|
-
const { key
|
|
1259
|
+
throw new CompilerError("Cannot handle computed property.", [prop]);
|
|
1260
|
+
const { key } = prop;
|
|
1261
|
+
const value = prop.type === "ObjectProperty" ? prop.value : prop;
|
|
945
1262
|
let index;
|
|
946
|
-
if (key.type === "Identifier")
|
|
1263
|
+
if (key.type === "Identifier") {
|
|
947
1264
|
index = key.name;
|
|
948
|
-
|
|
949
|
-
|
|
1265
|
+
}
|
|
1266
|
+
else if (key.type === "StringLiteral" || key.type === "NumericLiteral") {
|
|
1267
|
+
index = `${key.value}`;
|
|
1268
|
+
}
|
|
950
1269
|
else {
|
|
951
|
-
throw new
|
|
1270
|
+
throw new CompilerError(`Unsupported object key type: ${key.type}`, [
|
|
1271
|
+
key,
|
|
1272
|
+
]);
|
|
952
1273
|
}
|
|
953
1274
|
const [member, memberInst] = c.handleEval(scope, value);
|
|
954
|
-
|
|
1275
|
+
const owner = new ValueOwner({
|
|
1276
|
+
scope,
|
|
1277
|
+
constant: true,
|
|
1278
|
+
value: member,
|
|
1279
|
+
});
|
|
1280
|
+
data[index] = owner.value;
|
|
955
1281
|
inst.push(...memberInst);
|
|
956
1282
|
}
|
|
957
1283
|
return [new ObjectValue(scope, data), inst];
|
|
958
1284
|
};
|
|
959
1285
|
const ArrayExpression = (c, scope, node) => {
|
|
960
|
-
const
|
|
1286
|
+
const items = [];
|
|
961
1287
|
const inst = [];
|
|
962
|
-
node.elements.forEach(
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1288
|
+
node.elements.forEach(element => {
|
|
1289
|
+
const [value, valueInst] = element
|
|
1290
|
+
? c.handleEval(scope, element)
|
|
1291
|
+
: [undefined, []];
|
|
1292
|
+
items.push(value);
|
|
967
1293
|
inst.push(...valueInst);
|
|
968
1294
|
});
|
|
969
|
-
return [
|
|
1295
|
+
return [ObjectValue.fromArray(scope, items), inst];
|
|
970
1296
|
};
|
|
971
1297
|
const MemberExpression = (c, scope, node) => {
|
|
972
|
-
const [obj, objInst] = c.
|
|
1298
|
+
const [obj, objInst] = c.handleConsume(scope, node.object);
|
|
973
1299
|
const [prop, propInst] = node.computed
|
|
974
|
-
? c.
|
|
1300
|
+
? c.handleConsume(scope, node.property)
|
|
975
1301
|
: [new LiteralValue(scope, node.property.name), []];
|
|
976
1302
|
const [got, gotInst] = obj.get(scope, prop);
|
|
977
1303
|
return [got, [...objInst, ...propInst, ...gotInst]];
|
|
1304
|
+
};
|
|
1305
|
+
const ArrayPattern = (c, scope, node) => {
|
|
1306
|
+
const inst = [];
|
|
1307
|
+
const members = new Map();
|
|
1308
|
+
for (let i = 0; i < node.elements.length; i++) {
|
|
1309
|
+
const element = node.elements[i];
|
|
1310
|
+
if (!element)
|
|
1311
|
+
continue;
|
|
1312
|
+
const valueInst = c.handle(scope, element);
|
|
1313
|
+
if (!valueInst[0])
|
|
1314
|
+
throw new CompilerError("Destructuring element must resolve to a value", [
|
|
1315
|
+
element,
|
|
1316
|
+
]);
|
|
1317
|
+
inst.push(...valueInst[1]);
|
|
1318
|
+
members.set(new LiteralValue(scope, i), valueInst[0]);
|
|
1319
|
+
}
|
|
1320
|
+
return [new DestructuringValue(scope, members), inst];
|
|
1321
|
+
};
|
|
1322
|
+
const ObjectPattern = (c, scope, node) => {
|
|
1323
|
+
const inst = [];
|
|
1324
|
+
const members = new Map();
|
|
1325
|
+
for (const prop of node.properties) {
|
|
1326
|
+
if (prop.type === "RestElement")
|
|
1327
|
+
throw new CompilerError("The rest operator is not supported");
|
|
1328
|
+
if (!prop)
|
|
1329
|
+
continue;
|
|
1330
|
+
const { key } = prop;
|
|
1331
|
+
const keyInst = !prop.computed && key.type === "Identifier"
|
|
1332
|
+
? [new LiteralValue(scope, key.name), []]
|
|
1333
|
+
: c.handleConsume(scope, prop.key);
|
|
1334
|
+
inst.push(...keyInst[1]);
|
|
1335
|
+
const valueInst = c.handle(scope, prop.value);
|
|
1336
|
+
if (!valueInst[0])
|
|
1337
|
+
throw new CompilerError("Destructuring member must resolve to a value", [
|
|
1338
|
+
prop.value,
|
|
1339
|
+
]);
|
|
1340
|
+
inst.push(...valueInst[1]);
|
|
1341
|
+
members.set(keyInst[0], valueInst[0]);
|
|
1342
|
+
}
|
|
1343
|
+
return [new DestructuringValue(scope, members), inst];
|
|
978
1344
|
};
|
|
979
1345
|
|
|
980
1346
|
const TemplateLiteral = (c, scope, node) => {
|
|
981
1347
|
const args = [];
|
|
982
1348
|
const inst = [];
|
|
983
1349
|
node.expressions.forEach((expression, i) => {
|
|
984
|
-
const [v, vi] = c.
|
|
1350
|
+
const [v, vi] = c.handleConsume(scope, expression);
|
|
985
1351
|
inst.push(...vi);
|
|
986
1352
|
args.push(node.quasis[i].value.raw, v);
|
|
987
1353
|
});
|
|
@@ -1000,18 +1366,73 @@ const BlockStatement = (c, scope, node) => {
|
|
|
1000
1366
|
return [value, insts];
|
|
1001
1367
|
};
|
|
1002
1368
|
|
|
1369
|
+
const File = (c, scope, node) => {
|
|
1370
|
+
return c.handle(scope ?? new Scope({}), node.program);
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1373
|
+
const TypeCastExpression = (c, scope, node) => {
|
|
1374
|
+
return c.handle(scope, node.expression);
|
|
1375
|
+
};
|
|
1376
|
+
const TSAsExpression = TypeCastExpression;
|
|
1377
|
+
const TSTypeAssertion = TypeCastExpression;
|
|
1378
|
+
const IgnoredHandler = () => [null, []];
|
|
1379
|
+
const TSInterfaceDeclaration = IgnoredHandler;
|
|
1380
|
+
const TSTypeAliasDeclaration = IgnoredHandler;
|
|
1381
|
+
const TSEnumDeclaration = (c, scope, node) => {
|
|
1382
|
+
if (!node.const)
|
|
1383
|
+
throw new CompilerError("All enums must be declared with the const keyword before enum");
|
|
1384
|
+
let counter = 0;
|
|
1385
|
+
let lastType = "number";
|
|
1386
|
+
const data = {};
|
|
1387
|
+
for (const member of node.members) {
|
|
1388
|
+
if (lastType === "string" && !member.initializer)
|
|
1389
|
+
throw new CompilerError("This enum member must be initialized", [member]);
|
|
1390
|
+
const [value] = member.initializer
|
|
1391
|
+
? c.handleEval(scope, member.initializer)
|
|
1392
|
+
: [new LiteralValue(scope, counter)];
|
|
1393
|
+
if (!(value instanceof LiteralValue))
|
|
1394
|
+
throw new CompilerError("Enum members must contain literal values", [
|
|
1395
|
+
member,
|
|
1396
|
+
]);
|
|
1397
|
+
if (typeof value.data === "number") {
|
|
1398
|
+
lastType = "number";
|
|
1399
|
+
counter = value.data + 1;
|
|
1400
|
+
}
|
|
1401
|
+
else {
|
|
1402
|
+
lastType = "string";
|
|
1403
|
+
}
|
|
1404
|
+
const name = member.id.type === "Identifier" ? member.id.name : member.id.value;
|
|
1405
|
+
data[name] = value;
|
|
1406
|
+
}
|
|
1407
|
+
scope.set(new ValueOwner({
|
|
1408
|
+
scope,
|
|
1409
|
+
value: new ObjectValue(scope, data),
|
|
1410
|
+
constant: true,
|
|
1411
|
+
identifier: node.id.name,
|
|
1412
|
+
name: nodeName(node, !c.compactNames && node.id.name),
|
|
1413
|
+
}));
|
|
1414
|
+
return [null, []];
|
|
1415
|
+
};
|
|
1416
|
+
const TSNonNullExpression = (c, scope, node) => {
|
|
1417
|
+
return c.handle(scope, node.expression);
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1003
1420
|
var handlers = /*#__PURE__*/Object.freeze({
|
|
1004
1421
|
__proto__: null,
|
|
1005
1422
|
Program: Program,
|
|
1006
1423
|
VariableDeclaration: VariableDeclaration,
|
|
1007
1424
|
VariableDeclarator: VariableDeclarator,
|
|
1008
|
-
|
|
1425
|
+
NumericLiteral: NumericLiteral,
|
|
1426
|
+
StringLiteral: StringLiteral,
|
|
1427
|
+
NullLiteral: NullLiteral,
|
|
1428
|
+
BooleanLiteral: BooleanLiteral,
|
|
1009
1429
|
LRExpression: LRExpression,
|
|
1010
1430
|
BinaryExpression: BinaryExpression,
|
|
1011
1431
|
LogicalExpression: LogicalExpression,
|
|
1012
1432
|
AssignmentExpression: AssignmentExpression,
|
|
1013
1433
|
UnaryExpression: UnaryExpression,
|
|
1014
1434
|
UpdateExpression: UpdateExpression,
|
|
1435
|
+
ConditionalExpression: ConditionalExpression,
|
|
1015
1436
|
Identifier: Identifier,
|
|
1016
1437
|
ExpressionStatement: ExpressionStatement,
|
|
1017
1438
|
BreakStatement: BreakStatement,
|
|
@@ -1019,17 +1440,28 @@ var handlers = /*#__PURE__*/Object.freeze({
|
|
|
1019
1440
|
ReturnStatement: ReturnStatement,
|
|
1020
1441
|
IfStatement: IfStatement,
|
|
1021
1442
|
WhileStatement: WhileStatement,
|
|
1443
|
+
DoWhileStatement: DoWhileStatement,
|
|
1022
1444
|
ForStatement: ForStatement,
|
|
1023
1445
|
ArrowFunctionExpression: ArrowFunctionExpression,
|
|
1024
1446
|
FunctionDeclaration: FunctionDeclaration,
|
|
1025
1447
|
FunctionExpression: FunctionExpression,
|
|
1448
|
+
ObjectMethod: ObjectMethod,
|
|
1026
1449
|
CallExpression: CallExpression,
|
|
1027
1450
|
NewExpression: NewExpression,
|
|
1028
1451
|
ObjectExpression: ObjectExpression,
|
|
1029
1452
|
ArrayExpression: ArrayExpression,
|
|
1030
1453
|
MemberExpression: MemberExpression,
|
|
1454
|
+
ArrayPattern: ArrayPattern,
|
|
1455
|
+
ObjectPattern: ObjectPattern,
|
|
1031
1456
|
TemplateLiteral: TemplateLiteral,
|
|
1032
|
-
BlockStatement: BlockStatement
|
|
1457
|
+
BlockStatement: BlockStatement,
|
|
1458
|
+
File: File,
|
|
1459
|
+
TSAsExpression: TSAsExpression,
|
|
1460
|
+
TSTypeAssertion: TSTypeAssertion,
|
|
1461
|
+
TSInterfaceDeclaration: TSInterfaceDeclaration,
|
|
1462
|
+
TSTypeAliasDeclaration: TSTypeAliasDeclaration,
|
|
1463
|
+
TSEnumDeclaration: TSEnumDeclaration,
|
|
1464
|
+
TSNonNullExpression: TSNonNullExpression
|
|
1033
1465
|
});
|
|
1034
1466
|
|
|
1035
1467
|
class MacroFunction extends VoidValue {
|
|
@@ -1042,11 +1474,15 @@ class MacroFunction extends VoidValue {
|
|
|
1042
1474
|
call(scope, args) {
|
|
1043
1475
|
return this.fn.apply(this, args);
|
|
1044
1476
|
}
|
|
1045
|
-
eval(
|
|
1477
|
+
eval(_scope) {
|
|
1478
|
+
return [this, []];
|
|
1479
|
+
}
|
|
1480
|
+
consume(_scope) {
|
|
1046
1481
|
return [this, []];
|
|
1047
1482
|
}
|
|
1048
1483
|
}
|
|
1049
1484
|
|
|
1485
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
1050
1486
|
const mathOperations = {
|
|
1051
1487
|
max: (a, b) => Math.max(a, b),
|
|
1052
1488
|
min: (a, b) => Math.min(a, b),
|
|
@@ -1075,18 +1511,18 @@ function createMacroMathOperations(scope) {
|
|
|
1075
1511
|
if (b) {
|
|
1076
1512
|
if (fn && a instanceof LiteralValue && b instanceof LiteralValue) {
|
|
1077
1513
|
if (typeof a.data !== "number" || typeof b.data !== "number")
|
|
1078
|
-
throw new
|
|
1514
|
+
throw new CompilerError("Cannot do math operation with non-numerical literals.");
|
|
1079
1515
|
return [new LiteralValue(scope, fn(a.num, b.num)), []];
|
|
1080
1516
|
}
|
|
1081
|
-
const temp = new
|
|
1517
|
+
const temp = new StoreValue(scope);
|
|
1082
1518
|
return [temp, [new OperationInstruction(key, temp, a, b)]];
|
|
1083
1519
|
}
|
|
1084
1520
|
if (fn && a instanceof LiteralValue) {
|
|
1085
1521
|
if (typeof a.data !== "number")
|
|
1086
|
-
throw new
|
|
1522
|
+
throw new CompilerError("Cannot do math operation with non-numerical literal.");
|
|
1087
1523
|
return [new LiteralValue(scope, fn(a.num)), []];
|
|
1088
1524
|
}
|
|
1089
|
-
const temp = new
|
|
1525
|
+
const temp = new StoreValue(scope);
|
|
1090
1526
|
return [temp, [new OperationInstruction(key, temp, a, b)]];
|
|
1091
1527
|
});
|
|
1092
1528
|
}
|
|
@@ -1105,7 +1541,7 @@ class Concat extends MacroFunction {
|
|
|
1105
1541
|
super(scope, (...values) => {
|
|
1106
1542
|
for (const value of values)
|
|
1107
1543
|
if (!(value instanceof LiteralValue))
|
|
1108
|
-
throw new
|
|
1544
|
+
throw new CompilerError("Concat arguments must all be literal values.");
|
|
1109
1545
|
return [
|
|
1110
1546
|
new LiteralValue(scope, values.map(v => v.data).join("")),
|
|
1111
1547
|
[],
|
|
@@ -1118,7 +1554,7 @@ class Draw extends MacroFunction {
|
|
|
1118
1554
|
constructor(scope) {
|
|
1119
1555
|
super(scope, (kind, ...args) => {
|
|
1120
1556
|
if (!(kind instanceof LiteralValue && typeof kind.data === "string"))
|
|
1121
|
-
throw new
|
|
1557
|
+
throw new CompilerError("Draw kind must be a string literal.");
|
|
1122
1558
|
if ([
|
|
1123
1559
|
"clear",
|
|
1124
1560
|
"color",
|
|
@@ -1131,7 +1567,7 @@ class Draw extends MacroFunction {
|
|
|
1131
1567
|
"triangle",
|
|
1132
1568
|
"image",
|
|
1133
1569
|
].indexOf(kind.data) === -1)
|
|
1134
|
-
throw new
|
|
1570
|
+
throw new CompilerError("Invalid draw kind");
|
|
1135
1571
|
return [
|
|
1136
1572
|
null,
|
|
1137
1573
|
[
|
|
@@ -1161,8 +1597,8 @@ class Print extends MacroFunction {
|
|
|
1161
1597
|
class PrintFlush extends MacroFunction {
|
|
1162
1598
|
constructor(scope) {
|
|
1163
1599
|
super(scope, (target) => {
|
|
1164
|
-
if (!(target instanceof
|
|
1165
|
-
throw new
|
|
1600
|
+
if (!(target instanceof SenseableValue))
|
|
1601
|
+
throw new CompilerError("The printflush target must be a senseable value");
|
|
1166
1602
|
return [null, [new InstructionBase("printflush", target)]];
|
|
1167
1603
|
});
|
|
1168
1604
|
}
|
|
@@ -1171,93 +1607,21 @@ class PrintFlush extends MacroFunction {
|
|
|
1171
1607
|
class DrawFlush extends MacroFunction {
|
|
1172
1608
|
constructor(scope) {
|
|
1173
1609
|
super(scope, (target) => {
|
|
1174
|
-
if (!(target instanceof
|
|
1175
|
-
throw new
|
|
1610
|
+
if (!(target instanceof SenseableValue))
|
|
1611
|
+
throw new CompilerError("The drawflush target must be a senseable value");
|
|
1176
1612
|
return [null, [new InstructionBase("drawflush", target)]];
|
|
1177
1613
|
});
|
|
1178
1614
|
}
|
|
1179
1615
|
}
|
|
1180
1616
|
|
|
1181
|
-
const itemNames = [
|
|
1182
|
-
"copper",
|
|
1183
|
-
"lead",
|
|
1184
|
-
"metaglass",
|
|
1185
|
-
"graphite",
|
|
1186
|
-
"sand",
|
|
1187
|
-
"coal",
|
|
1188
|
-
"titanium",
|
|
1189
|
-
"thorium",
|
|
1190
|
-
"scrap",
|
|
1191
|
-
"silicon",
|
|
1192
|
-
"plastanium",
|
|
1193
|
-
"phaseFabric",
|
|
1194
|
-
"surgeAlloy",
|
|
1195
|
-
"sporePod",
|
|
1196
|
-
"blastCompound",
|
|
1197
|
-
"pyratite",
|
|
1198
|
-
];
|
|
1199
|
-
class Building extends ObjectValue {
|
|
1200
|
-
constructor(scope, name) {
|
|
1201
|
-
super(scope, {
|
|
1202
|
-
$get: new MacroFunction(scope, (prop) => {
|
|
1203
|
-
if (prop instanceof LiteralValue && typeof prop.data === "string") {
|
|
1204
|
-
const name = itemNames.includes(prop.data)
|
|
1205
|
-
? camelToDashCase(prop.data)
|
|
1206
|
-
: prop.data;
|
|
1207
|
-
const temp = new TempValue(scope);
|
|
1208
|
-
return [
|
|
1209
|
-
temp,
|
|
1210
|
-
[new InstructionBase("sensor", temp, this, `@${name}`)],
|
|
1211
|
-
];
|
|
1212
|
-
}
|
|
1213
|
-
if (prop instanceof StoreValue) {
|
|
1214
|
-
const temp = new TempValue(scope);
|
|
1215
|
-
return [temp, [new InstructionBase("sensor", temp, this, prop)]];
|
|
1216
|
-
}
|
|
1217
|
-
throw new Error("Building property acessors must be string literals or stores");
|
|
1218
|
-
}),
|
|
1219
|
-
});
|
|
1220
|
-
this.name = name;
|
|
1221
|
-
}
|
|
1222
|
-
toString() {
|
|
1223
|
-
return this.name;
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
class BuildingBuilder extends ObjectValue {
|
|
1227
|
-
constructor(scope) {
|
|
1228
|
-
super(scope, {
|
|
1229
|
-
$call: new MacroFunction(scope, (nameLit) => {
|
|
1230
|
-
if (!(nameLit instanceof LiteralValue))
|
|
1231
|
-
throw new Error("Block name must be a literal.");
|
|
1232
|
-
if (typeof nameLit.data !== "string")
|
|
1233
|
-
throw new Error("Block name must be a string.");
|
|
1234
|
-
return [new Building(scope, nameLit.data), []];
|
|
1235
|
-
}),
|
|
1236
|
-
});
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
for (const key in operatorMap$2) {
|
|
1240
|
-
const kind = operatorMap$2[key];
|
|
1241
|
-
Building.prototype[key] = function (scope, value) {
|
|
1242
|
-
const left = new StoreValue(scope, this.name);
|
|
1243
|
-
const [right, rightInst] = value.eval(scope);
|
|
1244
|
-
const temp = new TempValue(scope);
|
|
1245
|
-
return [
|
|
1246
|
-
temp,
|
|
1247
|
-
[...rightInst, new OperationInstruction(kind, temp, left, right)],
|
|
1248
|
-
];
|
|
1249
|
-
};
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
1617
|
class GetLink extends MacroFunction {
|
|
1253
1618
|
constructor(scope) {
|
|
1254
1619
|
super(scope, (index) => {
|
|
1255
1620
|
if (!(index instanceof StoreValue) &&
|
|
1256
1621
|
(!(index instanceof LiteralValue) || typeof index.data !== "number"))
|
|
1257
|
-
throw new
|
|
1258
|
-
const
|
|
1259
|
-
|
|
1260
|
-
return [outBuild, [new InstructionBase("getlink", temp, index)]];
|
|
1622
|
+
throw new CompilerError("The getlink index must be a number literal or a store");
|
|
1623
|
+
const outBuild = new SenseableValue(scope);
|
|
1624
|
+
return [outBuild, [new InstructionBase("getlink", outBuild, index)]];
|
|
1261
1625
|
});
|
|
1262
1626
|
}
|
|
1263
1627
|
}
|
|
@@ -1267,11 +1631,11 @@ class Control extends MacroFunction {
|
|
|
1267
1631
|
constructor(scope) {
|
|
1268
1632
|
super(scope, (kind, building, ...args) => {
|
|
1269
1633
|
if (!(kind instanceof LiteralValue) || typeof kind.data !== "string")
|
|
1270
|
-
throw new
|
|
1634
|
+
throw new CompilerError("The control kind must be a string literal");
|
|
1271
1635
|
if (!validKinds$1.includes(kind.data))
|
|
1272
|
-
throw new
|
|
1273
|
-
if (!(building instanceof
|
|
1274
|
-
throw new
|
|
1636
|
+
throw new CompilerError("Invalid control kind");
|
|
1637
|
+
if (!(building instanceof SenseableValue))
|
|
1638
|
+
throw new CompilerError("The building must be a senseable value");
|
|
1275
1639
|
return [
|
|
1276
1640
|
null,
|
|
1277
1641
|
[new InstructionBase("control", kind.data, building, ...args)],
|
|
@@ -1280,91 +1644,6 @@ class Control extends MacroFunction {
|
|
|
1280
1644
|
}
|
|
1281
1645
|
}
|
|
1282
1646
|
|
|
1283
|
-
class NamespaceMacro extends ObjectValue {
|
|
1284
|
-
constructor(scope, { changeCasing = false } = {}) {
|
|
1285
|
-
super(scope, {
|
|
1286
|
-
$get: new MacroFunction(scope, prop => {
|
|
1287
|
-
if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
|
|
1288
|
-
throw new Error("Cannot use dynamic properties on object macros");
|
|
1289
|
-
const symbolName = this.changeCasing
|
|
1290
|
-
? camelToDashCase(prop.data)
|
|
1291
|
-
: prop.data;
|
|
1292
|
-
return [new StoreValue(scope, `@${symbolName}`), []];
|
|
1293
|
-
}),
|
|
1294
|
-
});
|
|
1295
|
-
this.changeCasing = changeCasing;
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
class VarsNamespace extends NamespaceMacro {
|
|
1299
|
-
constructor(scope) {
|
|
1300
|
-
super(scope);
|
|
1301
|
-
const $get = this.data.$get;
|
|
1302
|
-
this.data.$get = new MacroFunction(scope, prop => {
|
|
1303
|
-
if (prop instanceof LiteralValue) {
|
|
1304
|
-
if (prop.data === "unit")
|
|
1305
|
-
return [new Unit(scope, "@unit"), []];
|
|
1306
|
-
if (prop.data === "this")
|
|
1307
|
-
return [new Building(scope, "@this"), []];
|
|
1308
|
-
}
|
|
1309
|
-
return $get.call(scope, [prop]);
|
|
1310
|
-
});
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
class UCommandsNamespace extends NamespaceMacro {
|
|
1314
|
-
constructor(scope) {
|
|
1315
|
-
super(scope);
|
|
1316
|
-
const $get = this.data.$get;
|
|
1317
|
-
this.data.$get = new MacroFunction(scope, prop => {
|
|
1318
|
-
if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
|
|
1319
|
-
throw new Error("Cannot use dynamic properties on object macros");
|
|
1320
|
-
const symbolName = prop.data[0].toUpperCase() + prop.data.slice(1);
|
|
1321
|
-
return [new StoreValue(scope, `@command${symbolName}`), []];
|
|
1322
|
-
});
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
// TODO: repeated logic between UnitMacro and Building
|
|
1326
|
-
class Unit extends ObjectValue {
|
|
1327
|
-
constructor(scope, name) {
|
|
1328
|
-
super(scope, {
|
|
1329
|
-
$get: new MacroFunction(scope, prop => {
|
|
1330
|
-
if (prop instanceof LiteralValue && typeof prop.data === "string") {
|
|
1331
|
-
const name = itemNames.includes(prop.data)
|
|
1332
|
-
? camelToDashCase(prop.data)
|
|
1333
|
-
: prop.data;
|
|
1334
|
-
const temp = new TempValue(scope);
|
|
1335
|
-
// special case, should return another unit or building
|
|
1336
|
-
const result = prop.data === "controller" ? new Unit(scope, temp.name) : temp;
|
|
1337
|
-
return [
|
|
1338
|
-
result,
|
|
1339
|
-
[new InstructionBase("sensor", result, this, `@${name}`)],
|
|
1340
|
-
];
|
|
1341
|
-
}
|
|
1342
|
-
if (prop instanceof StoreValue) {
|
|
1343
|
-
const temp = new TempValue(scope);
|
|
1344
|
-
return [temp, [new InstructionBase("sensor", temp, this, prop)]];
|
|
1345
|
-
}
|
|
1346
|
-
throw new Error("Building property acessors must be string literals or stores");
|
|
1347
|
-
}),
|
|
1348
|
-
});
|
|
1349
|
-
this.name = name;
|
|
1350
|
-
}
|
|
1351
|
-
toString() {
|
|
1352
|
-
return this.name;
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
for (const key in operatorMap$2) {
|
|
1356
|
-
const kind = operatorMap$2[key];
|
|
1357
|
-
Unit.prototype[key] = function (scope, value) {
|
|
1358
|
-
const left = new StoreValue(scope, this.name);
|
|
1359
|
-
const [right, rightInst] = value.eval(scope);
|
|
1360
|
-
const temp = new TempValue(scope);
|
|
1361
|
-
return [
|
|
1362
|
-
temp,
|
|
1363
|
-
[...rightInst, new OperationInstruction(kind, temp, left, right)],
|
|
1364
|
-
];
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
1647
|
const validRadarFilters = [
|
|
1369
1648
|
"any",
|
|
1370
1649
|
"enemy",
|
|
@@ -1385,33 +1664,32 @@ const validRadarSorts = [
|
|
|
1385
1664
|
class Radar extends MacroFunction {
|
|
1386
1665
|
constructor(scope) {
|
|
1387
1666
|
super(scope, (building, filter1, filter2, filter3, order, sort) => {
|
|
1388
|
-
if (!(building instanceof
|
|
1389
|
-
throw new
|
|
1667
|
+
if (!(building instanceof SenseableValue))
|
|
1668
|
+
throw new CompilerError("The building must a senseable value");
|
|
1390
1669
|
if (!(filter1 instanceof LiteralValue) ||
|
|
1391
1670
|
typeof filter1.data !== "string" ||
|
|
1392
1671
|
!(filter2 instanceof LiteralValue) ||
|
|
1393
1672
|
typeof filter2.data !== "string" ||
|
|
1394
1673
|
!(filter3 instanceof LiteralValue) ||
|
|
1395
1674
|
typeof filter3.data !== "string")
|
|
1396
|
-
throw new
|
|
1675
|
+
throw new CompilerError("The filters must be string literals");
|
|
1397
1676
|
if (!validRadarFilters.includes(filter1.data))
|
|
1398
|
-
throw new
|
|
1677
|
+
throw new CompilerError("Invalid value for filter1");
|
|
1399
1678
|
if (!validRadarFilters.includes(filter2.data))
|
|
1400
|
-
throw new
|
|
1679
|
+
throw new CompilerError("Invalid value for filter2");
|
|
1401
1680
|
if (!validRadarFilters.includes(filter3.data))
|
|
1402
|
-
throw new
|
|
1681
|
+
throw new CompilerError("Invalid value for filter3");
|
|
1403
1682
|
if (!(order instanceof LiteralValue || order instanceof StoreValue))
|
|
1404
|
-
throw new
|
|
1683
|
+
throw new CompilerError("The radar order must be a literal or a store");
|
|
1405
1684
|
if (!(sort instanceof LiteralValue) || typeof sort.data !== "string")
|
|
1406
|
-
throw new
|
|
1685
|
+
throw new CompilerError("The radar sort must be a string literal");
|
|
1407
1686
|
if (!validRadarSorts.includes(sort.data))
|
|
1408
|
-
throw new
|
|
1409
|
-
const
|
|
1410
|
-
const resultUnit = new Unit(scope, temp.name);
|
|
1687
|
+
throw new CompilerError("Invalid sort value");
|
|
1688
|
+
const outUnit = new SenseableValue(scope);
|
|
1411
1689
|
return [
|
|
1412
|
-
|
|
1690
|
+
outUnit,
|
|
1413
1691
|
[
|
|
1414
|
-
new InstructionBase("radar", filter1.data, filter2.data, filter3.data, sort.data, building, order,
|
|
1692
|
+
new InstructionBase("radar", filter1.data, filter2.data, filter3.data, sort.data, building, order, outUnit),
|
|
1415
1693
|
],
|
|
1416
1694
|
];
|
|
1417
1695
|
});
|
|
@@ -1422,11 +1700,11 @@ class Sensor extends MacroFunction {
|
|
|
1422
1700
|
constructor(scope) {
|
|
1423
1701
|
super(scope, (property, target) => {
|
|
1424
1702
|
if (!(property instanceof StoreValue))
|
|
1425
|
-
throw new
|
|
1426
|
-
if (!(target instanceof
|
|
1427
|
-
throw new
|
|
1428
|
-
const temp = new
|
|
1429
|
-
return [temp, [new InstructionBase("sensor", temp,
|
|
1703
|
+
throw new CompilerError("The sensor property must be a store");
|
|
1704
|
+
if (!(target instanceof SenseableValue))
|
|
1705
|
+
throw new CompilerError("The sensor target must be a senseable value");
|
|
1706
|
+
const temp = new StoreValue(scope);
|
|
1707
|
+
return [temp, [new InstructionBase("sensor", temp, target, property)]];
|
|
1430
1708
|
});
|
|
1431
1709
|
}
|
|
1432
1710
|
}
|
|
@@ -1436,7 +1714,7 @@ class Wait extends MacroFunction {
|
|
|
1436
1714
|
super(scope, seconds => {
|
|
1437
1715
|
if (!(seconds instanceof StoreValue) &&
|
|
1438
1716
|
!(seconds instanceof LiteralValue && typeof seconds.data === "number"))
|
|
1439
|
-
throw new
|
|
1717
|
+
throw new CompilerError("The wait seconds must be either a number literal or a store");
|
|
1440
1718
|
return [null, [new InstructionBase("wait", seconds)]];
|
|
1441
1719
|
});
|
|
1442
1720
|
}
|
|
@@ -1447,23 +1725,29 @@ class Lookup extends MacroFunction {
|
|
|
1447
1725
|
constructor(scope) {
|
|
1448
1726
|
super(scope, (kind, index) => {
|
|
1449
1727
|
if (!(kind instanceof LiteralValue && typeof kind.data === "string"))
|
|
1450
|
-
throw new
|
|
1728
|
+
throw new CompilerError("The lookup kind must be a string literal");
|
|
1451
1729
|
if (!validKinds.includes(kind.data))
|
|
1452
|
-
throw new
|
|
1730
|
+
throw new CompilerError("Invalid lookup kind");
|
|
1453
1731
|
if (!(index instanceof LiteralValue && typeof index.data === "number") &&
|
|
1454
1732
|
!(index instanceof StoreValue))
|
|
1455
|
-
throw new
|
|
1456
|
-
const temp = new
|
|
1733
|
+
throw new CompilerError("The lookup index must be a number literal or a store");
|
|
1734
|
+
const temp = new StoreValue(scope);
|
|
1457
1735
|
return [temp, [new InstructionBase("lookup", kind.data, temp, index)]];
|
|
1458
1736
|
});
|
|
1459
1737
|
}
|
|
1460
1738
|
}
|
|
1461
1739
|
|
|
1740
|
+
class End extends MacroFunction {
|
|
1741
|
+
constructor(scope) {
|
|
1742
|
+
super(scope, () => [null, [new EndInstruction()]]);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1462
1746
|
class UnitBind extends MacroFunction {
|
|
1463
1747
|
constructor(scope) {
|
|
1464
1748
|
super(scope, type => {
|
|
1465
1749
|
if (!(type instanceof StoreValue))
|
|
1466
|
-
throw new
|
|
1750
|
+
throw new CompilerError("The unitBind type must be a store");
|
|
1467
1751
|
return [null, [new InstructionBase("ubind", type)]];
|
|
1468
1752
|
});
|
|
1469
1753
|
}
|
|
@@ -1493,29 +1777,23 @@ class UnitControl extends MacroFunction {
|
|
|
1493
1777
|
constructor(scope) {
|
|
1494
1778
|
super(scope, (mode, ...args) => {
|
|
1495
1779
|
if (!(mode instanceof LiteralValue) || typeof mode.data !== "string")
|
|
1496
|
-
throw new
|
|
1780
|
+
throw new CompilerError("The unitControl mode must be a string literal");
|
|
1497
1781
|
if (!validModes.includes(mode.data))
|
|
1498
|
-
throw new
|
|
1499
|
-
if (args.some(value => !(value instanceof StoreValue ||
|
|
1500
|
-
|
|
1501
|
-
value instanceof ObjectValue)))
|
|
1502
|
-
throw new Error("The others arguments of unitControl must be literals or stores");
|
|
1782
|
+
throw new CompilerError("Invalid unitControl mode");
|
|
1783
|
+
if (args.some(value => !(value instanceof StoreValue || value instanceof LiteralValue)))
|
|
1784
|
+
throw new CompilerError("The others arguments of unitControl must be literals or stores");
|
|
1503
1785
|
let result = null;
|
|
1504
1786
|
let extraArgs = [];
|
|
1505
1787
|
switch (mode.data) {
|
|
1506
1788
|
case "getBlock": {
|
|
1507
|
-
const outType = new
|
|
1508
|
-
const outBuilding = new
|
|
1509
|
-
result =
|
|
1510
|
-
0: outType,
|
|
1511
|
-
1: new Building(scope, outBuilding.name),
|
|
1512
|
-
length: new LiteralValue(scope, 2),
|
|
1513
|
-
});
|
|
1789
|
+
const outType = new StoreValue(scope);
|
|
1790
|
+
const outBuilding = new SenseableValue(scope);
|
|
1791
|
+
result = ObjectValue.fromArray(scope, [outType, outBuilding]);
|
|
1514
1792
|
extraArgs = [outType, outBuilding, new LiteralValue(scope, 0)];
|
|
1515
1793
|
break;
|
|
1516
1794
|
}
|
|
1517
1795
|
case "within": {
|
|
1518
|
-
const temp = new
|
|
1796
|
+
const temp = new StoreValue(scope);
|
|
1519
1797
|
result = temp;
|
|
1520
1798
|
extraArgs = [temp, new LiteralValue(scope, 0)];
|
|
1521
1799
|
break;
|
|
@@ -1538,24 +1816,25 @@ class UnitRadar extends MacroFunction {
|
|
|
1538
1816
|
typeof filter2.data !== "string" ||
|
|
1539
1817
|
!(filter3 instanceof LiteralValue) ||
|
|
1540
1818
|
typeof filter3.data !== "string")
|
|
1541
|
-
throw new
|
|
1819
|
+
throw new CompilerError("The filters must be string literals");
|
|
1542
1820
|
if (!validRadarFilters.includes(filter1.data))
|
|
1543
|
-
throw new
|
|
1821
|
+
throw new CompilerError("Invalid value for filter1");
|
|
1544
1822
|
if (!validRadarFilters.includes(filter2.data))
|
|
1545
|
-
throw new
|
|
1823
|
+
throw new CompilerError("Invalid value for filter2");
|
|
1546
1824
|
if (!validRadarFilters.includes(filter3.data))
|
|
1547
|
-
throw new
|
|
1825
|
+
throw new CompilerError("Invalid value for filter3");
|
|
1548
1826
|
if (!(order instanceof LiteralValue || order instanceof StoreValue))
|
|
1549
|
-
throw new
|
|
1827
|
+
throw new CompilerError("The radar order must be a literal or a store");
|
|
1550
1828
|
if (!(sort instanceof LiteralValue) || typeof sort.data !== "string")
|
|
1551
|
-
throw new
|
|
1829
|
+
throw new CompilerError("The radar sort must be a string literal");
|
|
1552
1830
|
if (!validRadarSorts.includes(sort.data))
|
|
1553
|
-
throw new
|
|
1554
|
-
const
|
|
1831
|
+
throw new CompilerError("Invalid sort value");
|
|
1832
|
+
const outUnit = new SenseableValue(scope);
|
|
1555
1833
|
return [
|
|
1556
|
-
|
|
1834
|
+
outUnit,
|
|
1557
1835
|
[
|
|
1558
|
-
new InstructionBase("uradar", filter1.data, filter2.data, filter3.data,
|
|
1836
|
+
new InstructionBase("uradar", filter1.data, filter2.data, filter3.data, sort.data, "0", // I don't know why, but mindustry requires this extra parameter
|
|
1837
|
+
order, outUnit),
|
|
1559
1838
|
],
|
|
1560
1839
|
];
|
|
1561
1840
|
});
|
|
@@ -1578,15 +1857,15 @@ class UnitLocate extends MacroFunction {
|
|
|
1578
1857
|
constructor(scope) {
|
|
1579
1858
|
super(scope, (find, ...args) => {
|
|
1580
1859
|
if (!(find instanceof LiteralValue && typeof find.data === "string"))
|
|
1581
|
-
throw new
|
|
1860
|
+
throw new CompilerError("The unitLocate find must be a string literal");
|
|
1582
1861
|
if (!validFinds.includes(find.data))
|
|
1583
|
-
throw new
|
|
1862
|
+
throw new CompilerError("Invalid find value");
|
|
1584
1863
|
if (args.some(value => !(value instanceof StoreValue || value instanceof LiteralValue)))
|
|
1585
|
-
throw new
|
|
1586
|
-
const outFound = new
|
|
1587
|
-
const outX = new
|
|
1588
|
-
const outY = new
|
|
1589
|
-
const outBuilding = new
|
|
1864
|
+
throw new CompilerError("The others arguments of unitLocate must be literals or stores");
|
|
1865
|
+
const outFound = new StoreValue(scope);
|
|
1866
|
+
const outX = new StoreValue(scope);
|
|
1867
|
+
const outY = new StoreValue(scope);
|
|
1868
|
+
const outBuilding = new SenseableValue(scope);
|
|
1590
1869
|
const outArgs = [outX, outY, outFound, outBuilding];
|
|
1591
1870
|
let inputArgs = [];
|
|
1592
1871
|
switch (find.data) {
|
|
@@ -1598,10 +1877,10 @@ class UnitLocate extends MacroFunction {
|
|
|
1598
1877
|
case "building": {
|
|
1599
1878
|
const [group, enemy] = args;
|
|
1600
1879
|
if (!(group instanceof LiteralValue && typeof group.data === "string")) {
|
|
1601
|
-
throw new
|
|
1880
|
+
throw new CompilerError("The building group must be a string literal");
|
|
1602
1881
|
}
|
|
1603
1882
|
if (!validBuildingGroups.includes(group.data))
|
|
1604
|
-
throw new
|
|
1883
|
+
throw new CompilerError("Invalid building group");
|
|
1605
1884
|
inputArgs = [find.data, group.data, enemy, "@copper"];
|
|
1606
1885
|
break;
|
|
1607
1886
|
}
|
|
@@ -1612,54 +1891,54 @@ class UnitLocate extends MacroFunction {
|
|
|
1612
1891
|
}
|
|
1613
1892
|
}
|
|
1614
1893
|
return [
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
}),
|
|
1894
|
+
ObjectValue.fromArray(scope, [
|
|
1895
|
+
outFound,
|
|
1896
|
+
outX,
|
|
1897
|
+
outY,
|
|
1898
|
+
...(find.data !== "ore" ? [outBuilding] : []),
|
|
1899
|
+
]),
|
|
1622
1900
|
[new InstructionBase("ulocate", ...inputArgs, ...outArgs)],
|
|
1623
1901
|
];
|
|
1624
1902
|
});
|
|
1625
1903
|
}
|
|
1626
1904
|
}
|
|
1627
1905
|
|
|
1628
|
-
var index = /*#__PURE__*/Object.freeze({
|
|
1629
|
-
__proto__: null,
|
|
1630
|
-
Radar: Radar,
|
|
1631
|
-
Draw: Draw,
|
|
1632
|
-
Print: Print,
|
|
1633
|
-
PrintFlush: PrintFlush,
|
|
1634
|
-
DrawFlush: DrawFlush,
|
|
1635
|
-
GetLink: GetLink,
|
|
1636
|
-
Control: Control,
|
|
1637
|
-
Sensor: Sensor,
|
|
1638
|
-
Wait: Wait,
|
|
1639
|
-
Lookup: Lookup,
|
|
1640
|
-
UnitBind: UnitBind,
|
|
1641
|
-
UnitControl: UnitControl,
|
|
1642
|
-
UnitRadar: UnitRadar,
|
|
1643
|
-
UnitLocate: UnitLocate
|
|
1644
|
-
});
|
|
1645
|
-
|
|
1646
1906
|
class MemoryEntry extends ObjectValue {
|
|
1647
1907
|
constructor(scope, mem, prop) {
|
|
1648
1908
|
super(scope, {
|
|
1649
1909
|
$eval: new MacroFunction(scope, () => {
|
|
1650
|
-
|
|
1910
|
+
if (this.store)
|
|
1911
|
+
return [this.store, []];
|
|
1912
|
+
const temp = new StoreValue(scope);
|
|
1651
1913
|
return [temp, [new InstructionBase("read", temp, mem.cell, prop)]];
|
|
1652
1914
|
}),
|
|
1915
|
+
$consume: new MacroFunction(scope, () => {
|
|
1916
|
+
if (this.store)
|
|
1917
|
+
return [this.store, []];
|
|
1918
|
+
this.ensureOwned();
|
|
1919
|
+
this.store = new StoreValue(scope);
|
|
1920
|
+
this.owner.own(this.store);
|
|
1921
|
+
return [
|
|
1922
|
+
this.store,
|
|
1923
|
+
[new InstructionBase("read", this.store, mem.cell, prop)],
|
|
1924
|
+
];
|
|
1925
|
+
}),
|
|
1653
1926
|
"$=": new MacroFunction(scope, value => {
|
|
1654
|
-
|
|
1927
|
+
const [data, dataInst] = value.consume(scope);
|
|
1928
|
+
return [
|
|
1929
|
+
data,
|
|
1930
|
+
[...dataInst, new InstructionBase("write", data, mem.cell, prop)],
|
|
1931
|
+
];
|
|
1655
1932
|
}),
|
|
1656
1933
|
});
|
|
1934
|
+
this.store = null;
|
|
1657
1935
|
}
|
|
1658
1936
|
}
|
|
1659
1937
|
for (const operator of operators) {
|
|
1660
1938
|
if (operator === "=")
|
|
1661
1939
|
continue;
|
|
1662
1940
|
MemoryEntry.prototype[operator] = function (...args) {
|
|
1941
|
+
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-unsafe-return
|
|
1663
1942
|
return BaseValue.prototype[operator].apply(this, args);
|
|
1664
1943
|
};
|
|
1665
1944
|
}
|
|
@@ -1668,7 +1947,7 @@ class MemoryMacro extends ObjectValue {
|
|
|
1668
1947
|
super(scope, {
|
|
1669
1948
|
$get: new MacroFunction(scope, (prop) => {
|
|
1670
1949
|
if (prop instanceof LiteralValue && typeof prop.data !== "number")
|
|
1671
|
-
throw new
|
|
1950
|
+
throw new CompilerError(`Invalid memory object property: "${prop.data}"`);
|
|
1672
1951
|
const obj = new MemoryEntry(scope, this, prop);
|
|
1673
1952
|
return [obj, []];
|
|
1674
1953
|
}),
|
|
@@ -1686,26 +1965,88 @@ class MemoryBuilder extends ObjectValue {
|
|
|
1686
1965
|
constructor(scope) {
|
|
1687
1966
|
super(scope, {
|
|
1688
1967
|
$call: new MacroFunction(scope, (cell, size = new LiteralValue(scope, 64)) => {
|
|
1689
|
-
if (!(cell instanceof
|
|
1690
|
-
throw new
|
|
1968
|
+
if (!(cell instanceof SenseableValue))
|
|
1969
|
+
throw new CompilerError("Memory cell must be a senseable value.");
|
|
1691
1970
|
if (!(size instanceof LiteralValue && typeof size.data === "number"))
|
|
1692
|
-
throw new
|
|
1971
|
+
throw new CompilerError("The memory size must be a number literal.");
|
|
1693
1972
|
return [new MemoryMacro(scope, cell, size), []];
|
|
1694
1973
|
}),
|
|
1695
1974
|
});
|
|
1696
1975
|
}
|
|
1697
1976
|
}
|
|
1698
1977
|
|
|
1699
|
-
class
|
|
1978
|
+
class NamespaceMacro extends ObjectValue {
|
|
1979
|
+
constructor(scope, { changeCasing = false } = {}) {
|
|
1980
|
+
super(scope, {
|
|
1981
|
+
$get: new MacroFunction(scope, prop => {
|
|
1982
|
+
if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
|
|
1983
|
+
throw new CompilerError("Cannot use dynamic properties on namespace macros");
|
|
1984
|
+
const symbolName = this.changeCasing
|
|
1985
|
+
? camelToDashCase(prop.data)
|
|
1986
|
+
: prop.data;
|
|
1987
|
+
const owner = new ValueOwner({
|
|
1988
|
+
scope,
|
|
1989
|
+
value: new StoreValue(scope),
|
|
1990
|
+
name: `@${symbolName}`,
|
|
1991
|
+
});
|
|
1992
|
+
return [owner.value, []];
|
|
1993
|
+
}),
|
|
1994
|
+
});
|
|
1995
|
+
this.changeCasing = changeCasing;
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
class VarsNamespace extends NamespaceMacro {
|
|
1999
|
+
constructor(scope) {
|
|
2000
|
+
super(scope);
|
|
2001
|
+
Object.assign(this.data, {
|
|
2002
|
+
unit: new ValueOwner({
|
|
2003
|
+
scope,
|
|
2004
|
+
name: "@unit",
|
|
2005
|
+
value: new SenseableValue(scope),
|
|
2006
|
+
}).value,
|
|
2007
|
+
this: new ValueOwner({
|
|
2008
|
+
scope,
|
|
2009
|
+
name: "@this",
|
|
2010
|
+
value: new SenseableValue(scope),
|
|
2011
|
+
}).value,
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
class UCommandsNamespace extends NamespaceMacro {
|
|
2016
|
+
constructor(scope) {
|
|
2017
|
+
super(scope);
|
|
2018
|
+
this.data.$get = new MacroFunction(scope, prop => {
|
|
2019
|
+
if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
|
|
2020
|
+
throw new CompilerError("Cannot use dynamic properties on namespace macros");
|
|
2021
|
+
const symbolName = prop.data[0].toUpperCase() + prop.data.slice(1);
|
|
2022
|
+
const owner = new ValueOwner({
|
|
2023
|
+
scope,
|
|
2024
|
+
name: `@command${symbolName}`,
|
|
2025
|
+
value: new StoreValue(scope),
|
|
2026
|
+
});
|
|
2027
|
+
return [owner.value, []];
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
class GetGlobal extends MacroFunction {
|
|
1700
2033
|
constructor(scope) {
|
|
1701
2034
|
super(scope, (name) => {
|
|
1702
2035
|
if (!(name instanceof LiteralValue) || typeof name.data !== "string")
|
|
1703
|
-
throw new
|
|
1704
|
-
|
|
2036
|
+
throw new CompilerError("The name parameter must be a string literal.");
|
|
2037
|
+
const owner = new ValueOwner({
|
|
2038
|
+
scope,
|
|
2039
|
+
name: name.data,
|
|
2040
|
+
value: new SenseableValue(scope),
|
|
2041
|
+
});
|
|
2042
|
+
return [owner.value, []];
|
|
1705
2043
|
});
|
|
1706
2044
|
}
|
|
1707
2045
|
}
|
|
1708
2046
|
|
|
2047
|
+
/**
|
|
2048
|
+
* Adds all the compiler globals to `scope`
|
|
2049
|
+
*/
|
|
1709
2050
|
function initScope(scope) {
|
|
1710
2051
|
// namespaces
|
|
1711
2052
|
scope.hardSet("ControlKind", new NamespaceMacro(scope));
|
|
@@ -1717,8 +2058,8 @@ function initScope(scope) {
|
|
|
1717
2058
|
scope.hardSet("UnitCommands", new UCommandsNamespace(scope));
|
|
1718
2059
|
scope.hardSet("Blocks", new NamespaceMacro(scope, { changeCasing: true }));
|
|
1719
2060
|
// helper methods
|
|
1720
|
-
scope.hardSet("getBuilding", new
|
|
1721
|
-
scope.hardSet("getVar", new
|
|
2061
|
+
scope.hardSet("getBuilding", new GetGlobal(scope));
|
|
2062
|
+
scope.hardSet("getVar", new GetGlobal(scope));
|
|
1722
2063
|
scope.hardSet("concat", new Concat(scope));
|
|
1723
2064
|
scope.hardSet("Math", new MlogMath(scope));
|
|
1724
2065
|
scope.hardSet("Memory", new MemoryBuilder(scope));
|
|
@@ -1733,6 +2074,7 @@ function initScope(scope) {
|
|
|
1733
2074
|
scope.hardSet("sensor", new Sensor(scope));
|
|
1734
2075
|
scope.hardSet("wait", new Wait(scope));
|
|
1735
2076
|
scope.hardSet("lookup", new Lookup(scope));
|
|
2077
|
+
scope.hardSet("endScript", new End(scope));
|
|
1736
2078
|
scope.hardSet("unitBind", new UnitBind(scope));
|
|
1737
2079
|
scope.hardSet("unitControl", new UnitControl(scope));
|
|
1738
2080
|
scope.hardSet("unitRadar", new UnitRadar(scope));
|
|
@@ -1740,10 +2082,11 @@ function initScope(scope) {
|
|
|
1740
2082
|
}
|
|
1741
2083
|
|
|
1742
2084
|
class Compiler {
|
|
1743
|
-
constructor(stackName) {
|
|
2085
|
+
constructor({ stackName, compactNames = false } = {}) {
|
|
1744
2086
|
this.handlers = handlers;
|
|
1745
2087
|
this.usingStack = !!stackName;
|
|
1746
2088
|
this.stackName = stackName;
|
|
2089
|
+
this.compactNames = compactNames;
|
|
1747
2090
|
}
|
|
1748
2091
|
compile(script) {
|
|
1749
2092
|
let output;
|
|
@@ -1757,7 +2100,8 @@ class Compiler {
|
|
|
1757
2100
|
output = this.serialize(valueInst) + "\n";
|
|
1758
2101
|
}
|
|
1759
2102
|
catch (error) {
|
|
1760
|
-
|
|
2103
|
+
const nodeStack = error instanceof CompilerError ? error.nodeStack : [];
|
|
2104
|
+
return [null, error, nodeStack];
|
|
1761
2105
|
}
|
|
1762
2106
|
return [output, null, []];
|
|
1763
2107
|
}
|
|
@@ -1770,44 +2114,49 @@ class Compiler {
|
|
|
1770
2114
|
}
|
|
1771
2115
|
}
|
|
1772
2116
|
serialize(resLines) {
|
|
1773
|
-
const [
|
|
2117
|
+
const [, inst] = resLines;
|
|
1774
2118
|
return inst.filter(l => !l.hidden).join("\n");
|
|
1775
2119
|
}
|
|
1776
2120
|
parse(script) {
|
|
1777
2121
|
return parse(script, {
|
|
1778
|
-
|
|
1779
|
-
|
|
2122
|
+
ranges: true,
|
|
2123
|
+
plugins: ["typescript"],
|
|
1780
2124
|
});
|
|
1781
2125
|
}
|
|
1782
2126
|
handle(scope, node) {
|
|
1783
2127
|
try {
|
|
1784
2128
|
const handler = this.handlers[node.type];
|
|
1785
2129
|
if (!handler)
|
|
1786
|
-
throw
|
|
2130
|
+
throw new CompilerError("Missing handler for " + node.type);
|
|
1787
2131
|
return handler(this, scope, node, null);
|
|
1788
2132
|
}
|
|
1789
2133
|
catch (error) {
|
|
1790
|
-
error
|
|
1791
|
-
|
|
2134
|
+
if (error instanceof CompilerError) {
|
|
2135
|
+
error.nodeStack.push(node);
|
|
2136
|
+
}
|
|
1792
2137
|
throw error;
|
|
1793
2138
|
}
|
|
1794
2139
|
}
|
|
1795
2140
|
handleEval(scope, node) {
|
|
1796
2141
|
const [res, inst] = this.handle(scope, node);
|
|
1797
|
-
|
|
1798
|
-
|
|
2142
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
2143
|
+
const [evaluated, evaluatedInst] = res.eval(scope);
|
|
2144
|
+
return [evaluated, [...inst, ...evaluatedInst]];
|
|
2145
|
+
}
|
|
2146
|
+
handleConsume(scope, node) {
|
|
2147
|
+
const [res, inst] = this.handle(scope, node);
|
|
2148
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
2149
|
+
const [evaluated, evaluatedInst] = res.consume(scope);
|
|
2150
|
+
return [evaluated, [...inst, ...evaluatedInst]];
|
|
1799
2151
|
}
|
|
1800
2152
|
handleMany(scope, nodes, handler = this.handle.bind(this)) {
|
|
1801
2153
|
const lines = [];
|
|
1802
2154
|
for (const node of nodes) {
|
|
1803
|
-
const [
|
|
2155
|
+
const [, nodeLines] = handler(scope, node);
|
|
1804
2156
|
lines.push(...nodeLines);
|
|
1805
2157
|
}
|
|
1806
2158
|
return [null, lines];
|
|
1807
2159
|
}
|
|
1808
2160
|
}
|
|
1809
2161
|
|
|
1810
|
-
|
|
1811
|
-
const compile = (script) => compiler.compile(script);
|
|
1812
|
-
|
|
1813
|
-
export { compile };
|
|
2162
|
+
export { Compiler, CompilerError };
|