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