mlogjs 0.2.1 → 0.2.2
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/build/bin.cjs +69 -0
- package/dist/bin.cjs +69 -0
- package/dist/index.cjs +1817 -0
- package/dist/index.mjs +1813 -0
- package/dist/types/Compiler.d.ts +18 -0
- package/{build → dist/types}/Scope.d.ts +23 -26
- package/dist/types/bin.d.ts +1 -0
- package/dist/types/handlers/BlockStatement.d.ts +2 -0
- package/dist/types/handlers/CallExpression.d.ts +3 -0
- package/dist/types/handlers/ForStatement.d.ts +2 -0
- package/{build → dist/types}/handlers/Function.d.ts +4 -4
- package/{build → dist/types}/handlers/Identifier.d.ts +2 -2
- package/dist/types/handlers/IfStatement.d.ts +2 -0
- package/{build → dist/types}/handlers/Literal.d.ts +2 -2
- package/{build → dist/types}/handlers/Object.d.ts +4 -4
- package/{build → dist/types}/handlers/OperationExpressions.d.ts +7 -7
- package/dist/types/handlers/Program.d.ts +2 -0
- package/dist/types/handlers/Statements.d.ts +5 -0
- package/dist/types/handlers/TemplateExpression.d.ts +2 -0
- package/dist/types/handlers/VariableDeclaration.d.ts +3 -0
- package/dist/types/handlers/WhileStatement.d.ts +2 -0
- package/{build → dist/types}/handlers/index.d.ts +14 -14
- package/dist/types/index.d.ts +1 -0
- package/{build → dist/types}/initScope.d.ts +2 -2
- package/{build → dist/types}/instructions/AddressResolver.d.ts +12 -12
- package/{build → dist/types}/instructions/ControlInstructions.d.ts +11 -11
- package/{build → dist/types}/instructions/EndInstruction.d.ts +4 -4
- package/{build → dist/types}/instructions/InstructionBase.d.ts +10 -10
- package/{build → dist/types}/instructions/JumpInstruction.d.ts +15 -15
- package/{build → dist/types}/instructions/OperationInstruction.d.ts +5 -5
- package/{build → dist/types}/instructions/SetCounterInstruction.d.ts +5 -5
- package/{build → dist/types}/instructions/SetInstruction.d.ts +5 -5
- package/{build → dist/types}/instructions/ZeroSpaceInstruction.d.ts +4 -4
- package/{build → dist/types}/instructions/index.d.ts +9 -9
- package/{build → dist/types}/macros/Building.d.ts +11 -11
- package/dist/types/macros/Function.d.ts +12 -0
- package/{build → dist/types}/macros/Math.d.ts +5 -5
- package/{build → dist/types}/macros/Memory.d.ts +5 -5
- package/{build → dist/types}/macros/Namespace.d.ts +21 -21
- package/{build → dist/types}/macros/Other.d.ts +5 -5
- package/{build → dist/types}/macros/RawValue.d.ts +5 -5
- package/{build → dist/types}/macros/commands/Control.d.ts +5 -5
- package/{build → dist/types}/macros/commands/Draw.d.ts +5 -5
- package/{build → dist/types}/macros/commands/DrawFlush.d.ts +5 -5
- package/{build → dist/types}/macros/commands/GetLink.d.ts +5 -5
- package/{build → dist/types}/macros/commands/Lookup.d.ts +5 -5
- package/{build → dist/types}/macros/commands/Print.d.ts +5 -5
- package/{build → dist/types}/macros/commands/PrintFlush.d.ts +5 -5
- package/{build → dist/types}/macros/commands/Radar.d.ts +7 -7
- package/{build → dist/types}/macros/commands/Sensor.d.ts +5 -5
- package/{build → dist/types}/macros/commands/UnitBind.d.ts +5 -5
- package/dist/types/macros/commands/UnitControl.d.ts +5 -0
- package/{build → dist/types}/macros/commands/UnitLocate.d.ts +5 -5
- package/{build → dist/types}/macros/commands/UnitRadar.d.ts +5 -5
- package/{build → dist/types}/macros/commands/Wait.d.ts +5 -5
- package/{build → dist/types}/macros/commands/index.d.ts +14 -14
- package/{build → dist/types}/macros/index.d.ts +7 -7
- package/{build → dist/types}/operators.d.ts +25 -25
- package/dist/types/types.d.ts +100 -0
- package/{build → dist/types}/utils.d.ts +3 -3
- package/{build → dist/types}/values/BaseValue.d.ts +5 -5
- package/{build → dist/types}/values/FunctionValue.d.ts +34 -34
- package/{build → dist/types}/values/LiteralValue.d.ts +12 -12
- package/dist/types/values/ObjectValue.d.ts +19 -0
- package/{build → dist/types}/values/StoreValue.d.ts +11 -11
- package/{build → dist/types}/values/TempValue.d.ts +12 -12
- package/{build → dist/types}/values/VoidValue.d.ts +13 -11
- package/{build → dist/types}/values/index.d.ts +6 -6
- package/doc/README.md +9 -0
- package/lib/eslib/lib.es5.d.ts +1 -1
- package/lib/traits.d.ts +0 -1
- package/package.json +17 -27
- package/build/Compiler.d.ts +0 -18
- package/build/Compiler.js +0 -100
- package/build/Compiler.js.map +0 -1
- package/build/Scope.js +0 -61
- package/build/Scope.js.map +0 -1
- package/build/bin.d.ts +0 -2
- package/build/bin.js +0 -61
- package/build/bin.js.map +0 -1
- package/build/handlers/BlockStatement.d.ts +0 -2
- package/build/handlers/BlockStatement.js +0 -14
- package/build/handlers/BlockStatement.js.map +0 -1
- package/build/handlers/CallExpression.d.ts +0 -3
- package/build/handlers/CallExpression.js +0 -20
- package/build/handlers/CallExpression.js.map +0 -1
- package/build/handlers/ForStatement.d.ts +0 -2
- package/build/handlers/ForStatement.js +0 -32
- package/build/handlers/ForStatement.js.map +0 -1
- package/build/handlers/Function.js +0 -36
- package/build/handlers/Function.js.map +0 -1
- package/build/handlers/Identifier.js +0 -8
- package/build/handlers/Identifier.js.map +0 -1
- package/build/handlers/IfStatement.d.ts +0 -2
- package/build/handlers/IfStatement.js +0 -25
- package/build/handlers/IfStatement.js.map +0 -1
- package/build/handlers/Literal.js +0 -18
- package/build/handlers/Literal.js.map +0 -1
- package/build/handlers/Object.js +0 -44
- package/build/handlers/Object.js.map +0 -1
- package/build/handlers/OperationExpressions.js +0 -33
- package/build/handlers/OperationExpressions.js.map +0 -1
- package/build/handlers/Program.d.ts +0 -2
- package/build/handlers/Program.js +0 -9
- package/build/handlers/Program.js.map +0 -1
- package/build/handlers/Statements.d.ts +0 -5
- package/build/handlers/Statements.js +0 -30
- package/build/handlers/Statements.js.map +0 -1
- package/build/handlers/TemplateExpression.d.ts +0 -2
- package/build/handlers/TemplateExpression.js +0 -18
- package/build/handlers/TemplateExpression.js.map +0 -1
- package/build/handlers/VariableDeclaration.d.ts +0 -3
- package/build/handlers/VariableDeclaration.js +0 -56
- package/build/handlers/VariableDeclaration.js.map +0 -1
- package/build/handlers/WhileStatement.d.ts +0 -2
- package/build/handlers/WhileStatement.js +0 -23
- package/build/handlers/WhileStatement.js.map +0 -1
- package/build/handlers/index.js +0 -31
- package/build/handlers/index.js.map +0 -1
- package/build/index.d.ts +0 -1
- package/build/index.js +0 -8
- package/build/index.js.map +0 -1
- package/build/initScope.js +0 -40
- package/build/initScope.js.map +0 -1
- package/build/instructions/AddressResolver.js +0 -31
- package/build/instructions/AddressResolver.js.map +0 -1
- package/build/instructions/ControlInstructions.js +0 -23
- package/build/instructions/ControlInstructions.js.map +0 -1
- package/build/instructions/EndInstruction.js +0 -11
- package/build/instructions/EndInstruction.js.map +0 -1
- package/build/instructions/InstructionBase.js +0 -21
- package/build/instructions/InstructionBase.js.map +0 -1
- package/build/instructions/JumpInstruction.js +0 -22
- package/build/instructions/JumpInstruction.js.map +0 -1
- package/build/instructions/OperationInstruction.js +0 -11
- package/build/instructions/OperationInstruction.js.map +0 -1
- package/build/instructions/SetCounterInstruction.js +0 -11
- package/build/instructions/SetCounterInstruction.js.map +0 -1
- package/build/instructions/SetInstruction.js +0 -11
- package/build/instructions/SetInstruction.js.map +0 -1
- package/build/instructions/ZeroSpaceInstruction.js +0 -11
- package/build/instructions/ZeroSpaceInstruction.js.map +0 -1
- package/build/instructions/index.js +0 -26
- package/build/instructions/index.js.map +0 -1
- package/build/macros/Building.js +0 -81
- package/build/macros/Building.js.map +0 -1
- package/build/macros/Function.d.ts +0 -12
- package/build/macros/Function.js +0 -20
- package/build/macros/Function.js.map +0 -1
- package/build/macros/Math.js +0 -57
- package/build/macros/Math.js.map +0 -1
- package/build/macros/Memory.js +0 -61
- package/build/macros/Memory.js.map +0 -1
- package/build/macros/Namespace.js +0 -98
- package/build/macros/Namespace.js.map +0 -1
- package/build/macros/Other.js +0 -20
- package/build/macros/Other.js.map +0 -1
- package/build/macros/RawValue.js +0 -16
- package/build/macros/RawValue.js.map +0 -1
- package/build/macros/commands/Control.js +0 -25
- package/build/macros/commands/Control.js.map +0 -1
- package/build/macros/commands/Draw.js +0 -39
- package/build/macros/commands/Draw.js.map +0 -1
- package/build/macros/commands/DrawFlush.js +0 -17
- package/build/macros/commands/DrawFlush.js.map +0 -1
- package/build/macros/commands/GetLink.js +0 -21
- package/build/macros/commands/GetLink.js.map +0 -1
- package/build/macros/commands/Lookup.js +0 -24
- package/build/macros/commands/Lookup.js.map +0 -1
- package/build/macros/commands/Print.js +0 -14
- package/build/macros/commands/Print.js.map +0 -1
- package/build/macros/commands/PrintFlush.js +0 -17
- package/build/macros/commands/PrintFlush.js.map +0 -1
- package/build/macros/commands/Radar.js +0 -61
- package/build/macros/commands/Radar.js.map +0 -1
- package/build/macros/commands/Sensor.js +0 -20
- package/build/macros/commands/Sensor.js.map +0 -1
- package/build/macros/commands/UnitBind.js +0 -17
- package/build/macros/commands/UnitBind.js.map +0 -1
- package/build/macros/commands/UnitControl.d.ts +0 -5
- package/build/macros/commands/UnitControl.js +0 -68
- package/build/macros/commands/UnitControl.js.map +0 -1
- package/build/macros/commands/UnitLocate.js +0 -55
- package/build/macros/commands/UnitLocate.js.map +0 -1
- package/build/macros/commands/UnitRadar.js +0 -41
- package/build/macros/commands/UnitRadar.js.map +0 -1
- package/build/macros/commands/Wait.js +0 -18
- package/build/macros/commands/Wait.js.map +0 -1
- package/build/macros/commands/index.js +0 -33
- package/build/macros/commands/index.js.map +0 -1
- package/build/macros/index.js +0 -40
- package/build/macros/index.js.map +0 -1
- package/build/operators.js +0 -102
- package/build/operators.js.map +0 -1
- package/build/types.d.ts +0 -49
- package/build/types.js +0 -28
- package/build/types.js.map +0 -1
- package/build/utils.js +0 -13
- package/build/utils.js.map +0 -1
- package/build/values/BaseValue.js +0 -112
- package/build/values/BaseValue.js.map +0 -1
- package/build/values/FunctionValue.js +0 -104
- package/build/values/FunctionValue.js.map +0 -1
- package/build/values/LiteralValue.js +0 -88
- package/build/values/LiteralValue.js.map +0 -1
- package/build/values/ObjectValue.d.ts +0 -17
- package/build/values/ObjectValue.js +0 -50
- package/build/values/ObjectValue.js.map +0 -1
- package/build/values/StoreValue.js +0 -31
- package/build/values/StoreValue.js.map +0 -1
- package/build/values/TempValue.js +0 -67
- package/build/values/TempValue.js.map +0 -1
- package/build/values/VoidValue.js +0 -31
- package/build/values/VoidValue.js.map +0 -1
- package/build/values/index.js +0 -23
- package/build/values/index.js.map +0 -1
- package/dist/mlogjs.es.js +0 -6366
- package/dist/mlogjs.umd.js +0 -8
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1813 @@
|
|
|
1
|
+
import { parse } from 'acorn';
|
|
2
|
+
|
|
3
|
+
const arithmeticBinaryOperators = [
|
|
4
|
+
"*",
|
|
5
|
+
"**",
|
|
6
|
+
"+",
|
|
7
|
+
"-",
|
|
8
|
+
"/",
|
|
9
|
+
"%",
|
|
10
|
+
];
|
|
11
|
+
const comparisonBinaryOperators = [
|
|
12
|
+
"!=",
|
|
13
|
+
"!==",
|
|
14
|
+
"<",
|
|
15
|
+
"<=",
|
|
16
|
+
"==",
|
|
17
|
+
"===",
|
|
18
|
+
">",
|
|
19
|
+
">=",
|
|
20
|
+
];
|
|
21
|
+
const bitwiseBinaryOperators = [
|
|
22
|
+
"&",
|
|
23
|
+
"<<",
|
|
24
|
+
">>",
|
|
25
|
+
">>>",
|
|
26
|
+
"^",
|
|
27
|
+
"|",
|
|
28
|
+
];
|
|
29
|
+
const binaryOperators = [
|
|
30
|
+
...arithmeticBinaryOperators,
|
|
31
|
+
...comparisonBinaryOperators,
|
|
32
|
+
...bitwiseBinaryOperators,
|
|
33
|
+
"instanceof",
|
|
34
|
+
"in",
|
|
35
|
+
];
|
|
36
|
+
const logicalOperators = ["&&", "??", "||"];
|
|
37
|
+
const arithmeticAssignmentOperators = [
|
|
38
|
+
"%=",
|
|
39
|
+
"&=",
|
|
40
|
+
"*=",
|
|
41
|
+
"**=",
|
|
42
|
+
"+=",
|
|
43
|
+
"-=",
|
|
44
|
+
"/=",
|
|
45
|
+
];
|
|
46
|
+
const logicalAssignmentOperators = ["&&=", "||="];
|
|
47
|
+
const bitwiseAssignmentOperators = [
|
|
48
|
+
"<<=",
|
|
49
|
+
">>=",
|
|
50
|
+
">>>=",
|
|
51
|
+
"^=",
|
|
52
|
+
"|=",
|
|
53
|
+
];
|
|
54
|
+
const assignmentOperators = [
|
|
55
|
+
...arithmeticAssignmentOperators,
|
|
56
|
+
...logicalAssignmentOperators,
|
|
57
|
+
...bitwiseAssignmentOperators,
|
|
58
|
+
"=",
|
|
59
|
+
];
|
|
60
|
+
const leftRightOperators = [
|
|
61
|
+
...binaryOperators,
|
|
62
|
+
...logicalOperators,
|
|
63
|
+
...assignmentOperators,
|
|
64
|
+
];
|
|
65
|
+
const unaryOperators = [
|
|
66
|
+
"!",
|
|
67
|
+
"u+",
|
|
68
|
+
"u-",
|
|
69
|
+
"delete",
|
|
70
|
+
"typeof",
|
|
71
|
+
"void",
|
|
72
|
+
"~",
|
|
73
|
+
];
|
|
74
|
+
const updateOperators = ["++", "--"];
|
|
75
|
+
const singleOperators = [...unaryOperators, ...updateOperators];
|
|
76
|
+
const operators = [...leftRightOperators, ...singleOperators];
|
|
77
|
+
const operatorMap$2 = {
|
|
78
|
+
"==": "equal",
|
|
79
|
+
"===": "strictEqual",
|
|
80
|
+
"!=": "notEqual",
|
|
81
|
+
"!==": "notEqual",
|
|
82
|
+
"<": "lessThan",
|
|
83
|
+
">": "greaterThan",
|
|
84
|
+
"<=": "lessThanEq",
|
|
85
|
+
">=": "greaterThanEq",
|
|
86
|
+
"+": "add",
|
|
87
|
+
"-": "sub",
|
|
88
|
+
"*": "mul",
|
|
89
|
+
"/": "div",
|
|
90
|
+
"%": "mod",
|
|
91
|
+
"**": "pow",
|
|
92
|
+
"|": "or",
|
|
93
|
+
"&": "and",
|
|
94
|
+
"^": "xor",
|
|
95
|
+
">>": "shr",
|
|
96
|
+
">>>": "shr",
|
|
97
|
+
"<<": "shl",
|
|
98
|
+
"&&": "land",
|
|
99
|
+
"||": "or",
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
class VoidValue {
|
|
103
|
+
constructor(scope) {
|
|
104
|
+
this.constant = false;
|
|
105
|
+
this.macro = false;
|
|
106
|
+
this.scope = scope;
|
|
107
|
+
}
|
|
108
|
+
eval(scope) {
|
|
109
|
+
throw new Error(`${this} cannot eval.`);
|
|
110
|
+
}
|
|
111
|
+
call(scope, args) {
|
|
112
|
+
throw new Error(`${this} cannot call.`);
|
|
113
|
+
}
|
|
114
|
+
get(scope, name) {
|
|
115
|
+
throw new Error(`${this} cannot get.`);
|
|
116
|
+
}
|
|
117
|
+
toString() {
|
|
118
|
+
return "void";
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
for (const key of operators) {
|
|
122
|
+
VoidValue.prototype[key] = function () {
|
|
123
|
+
console.log(this);
|
|
124
|
+
throw new Error(`${this} cannot '${key}' operation.`);
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
class InstructionBase {
|
|
129
|
+
constructor(...args) {
|
|
130
|
+
this._hidden = false;
|
|
131
|
+
this.args = args;
|
|
132
|
+
}
|
|
133
|
+
get hidden() {
|
|
134
|
+
return this._hidden;
|
|
135
|
+
}
|
|
136
|
+
set hidden(value) {
|
|
137
|
+
this._hidden = value;
|
|
138
|
+
}
|
|
139
|
+
resolve(i) { }
|
|
140
|
+
toString() {
|
|
141
|
+
return this.args.filter(arg => arg).join(" ");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
class OperationInstruction extends InstructionBase {
|
|
146
|
+
constructor(kind, temp, left, right) {
|
|
147
|
+
super("op", kind, temp, left, right);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
class SetInstruction extends InstructionBase {
|
|
152
|
+
constructor(store, value) {
|
|
153
|
+
super("set", store, value);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
class EndInstruction extends InstructionBase {
|
|
158
|
+
constructor() {
|
|
159
|
+
super("end");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
class AddressResolver extends InstructionBase {
|
|
164
|
+
constructor(...bonds) {
|
|
165
|
+
super();
|
|
166
|
+
this.bonds = bonds;
|
|
167
|
+
}
|
|
168
|
+
get hidden() {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
set hidden(value) { }
|
|
172
|
+
resolve(i) {
|
|
173
|
+
for (const literal of this.bonds)
|
|
174
|
+
literal.data = i;
|
|
175
|
+
}
|
|
176
|
+
bind(bond) {
|
|
177
|
+
this.bonds.push(bond);
|
|
178
|
+
}
|
|
179
|
+
bindBreak(scope) {
|
|
180
|
+
scope.break = this;
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
183
|
+
bindContinue(scope) {
|
|
184
|
+
scope.continue = this;
|
|
185
|
+
return this;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
var EJumpKind;
|
|
190
|
+
(function (EJumpKind) {
|
|
191
|
+
EJumpKind["Equal"] = "equal";
|
|
192
|
+
EJumpKind["NotEqual"] = "notEqual";
|
|
193
|
+
EJumpKind["LessThan"] = "lessThan";
|
|
194
|
+
EJumpKind["LessThanEq"] = "lessThanEq";
|
|
195
|
+
EJumpKind["GreaterThan"] = "greaterThan";
|
|
196
|
+
EJumpKind["GreaterThanEq"] = "greaterThanEq";
|
|
197
|
+
EJumpKind["StrictEqual"] = "strictEqual";
|
|
198
|
+
EJumpKind["Always"] = "always";
|
|
199
|
+
})(EJumpKind || (EJumpKind = {}));
|
|
200
|
+
class JumpInstruction extends InstructionBase {
|
|
201
|
+
constructor(address, kind, left = null, right = null) {
|
|
202
|
+
super("jump", address, kind, left, right);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
class SetCounterInstruction extends InstructionBase {
|
|
207
|
+
constructor(value) {
|
|
208
|
+
super("set", "@counter", value);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
class ZeroSpaceInstruction extends InstructionBase {
|
|
213
|
+
toString() {
|
|
214
|
+
return this.args.join("");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
class BreakInstruction extends JumpInstruction {
|
|
219
|
+
constructor(address) {
|
|
220
|
+
super(address, EJumpKind.Always);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
class ContinueInstruction extends JumpInstruction {
|
|
224
|
+
constructor(address) {
|
|
225
|
+
super(address, EJumpKind.Always);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
class ReturnInstruction extends JumpInstruction {
|
|
229
|
+
constructor(address) {
|
|
230
|
+
super(address, EJumpKind.Always);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
class BaseValue extends VoidValue {
|
|
235
|
+
"u-"(scope) {
|
|
236
|
+
const [that, inst] = this.eval(scope);
|
|
237
|
+
const temp = new TempValue(scope);
|
|
238
|
+
return [
|
|
239
|
+
temp,
|
|
240
|
+
[
|
|
241
|
+
...inst,
|
|
242
|
+
new OperationInstruction("sub", temp, new LiteralValue(scope, 0), that),
|
|
243
|
+
],
|
|
244
|
+
];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const operatorMap$1 = {
|
|
248
|
+
"==": "equal",
|
|
249
|
+
"===": "strictEqual",
|
|
250
|
+
"!=": "notEqual",
|
|
251
|
+
"!==": "notEqual",
|
|
252
|
+
"<": "lessThan",
|
|
253
|
+
">": "greaterThan",
|
|
254
|
+
"<=": "lessThanEq",
|
|
255
|
+
">=": "greaterThanEq",
|
|
256
|
+
"+": "add",
|
|
257
|
+
"-": "sub",
|
|
258
|
+
"*": "mul",
|
|
259
|
+
"/": "div",
|
|
260
|
+
"%": "mod",
|
|
261
|
+
"**": "pow",
|
|
262
|
+
"|": "or",
|
|
263
|
+
"&": "and",
|
|
264
|
+
"^": "xor",
|
|
265
|
+
">>": "shr",
|
|
266
|
+
">>>": "shr",
|
|
267
|
+
"<<": "shl",
|
|
268
|
+
"&&": "land",
|
|
269
|
+
"||": "or",
|
|
270
|
+
};
|
|
271
|
+
for (const key in operatorMap$1) {
|
|
272
|
+
const kind = operatorMap$1[key];
|
|
273
|
+
BaseValue.prototype[key] = function (scope, value) {
|
|
274
|
+
const [left, leftInst] = this.eval(scope);
|
|
275
|
+
const [right, rightInst] = value.eval(scope);
|
|
276
|
+
const temp = new TempValue(scope);
|
|
277
|
+
return [
|
|
278
|
+
temp,
|
|
279
|
+
[
|
|
280
|
+
...leftInst,
|
|
281
|
+
...rightInst,
|
|
282
|
+
new OperationInstruction(kind, temp, left, right),
|
|
283
|
+
],
|
|
284
|
+
];
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
const unaryOperatorMap$1 = {
|
|
288
|
+
"!": "not",
|
|
289
|
+
"~": "flip",
|
|
290
|
+
};
|
|
291
|
+
for (const key in unaryOperatorMap$1) {
|
|
292
|
+
const name = unaryOperatorMap$1[key];
|
|
293
|
+
BaseValue.prototype[key] = function (scope) {
|
|
294
|
+
const [that, inst] = this.eval(scope);
|
|
295
|
+
const temp = new TempValue(scope);
|
|
296
|
+
return [temp, [...inst, new OperationInstruction(name, temp, that, null)]];
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
const assignmentToBinary = {
|
|
300
|
+
"+=": "+",
|
|
301
|
+
"-=": "-",
|
|
302
|
+
"*=": "*",
|
|
303
|
+
"/=": "/",
|
|
304
|
+
"%=": "%",
|
|
305
|
+
"**=": "**",
|
|
306
|
+
"|=": "|",
|
|
307
|
+
"&=": "&",
|
|
308
|
+
"^=": "^",
|
|
309
|
+
">>=": ">>",
|
|
310
|
+
">>>=": ">>>",
|
|
311
|
+
"<<=": "<<",
|
|
312
|
+
"&&=": "&&",
|
|
313
|
+
"||=": "||",
|
|
314
|
+
};
|
|
315
|
+
for (const op in assignmentToBinary) {
|
|
316
|
+
BaseValue.prototype[op] = function (scope, value) {
|
|
317
|
+
const [opValue, opInst] = this[assignmentToBinary[op]](scope, value);
|
|
318
|
+
const [retValue, retInst] = this["="](scope, opValue);
|
|
319
|
+
return [retValue, [...opInst, ...retInst]];
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
for (const key of updateOperators) {
|
|
323
|
+
BaseValue.prototype[key] = function (scope, prefix) {
|
|
324
|
+
let [ret, inst] = this.eval(scope);
|
|
325
|
+
if (!prefix) {
|
|
326
|
+
const temp = new TempValue(scope);
|
|
327
|
+
const [tempValue, tempInst] = temp["="](scope, ret);
|
|
328
|
+
ret = tempValue;
|
|
329
|
+
inst.push(...tempInst);
|
|
330
|
+
}
|
|
331
|
+
const kind = key === "++" ? "+=" : "-=";
|
|
332
|
+
return [
|
|
333
|
+
ret,
|
|
334
|
+
[...inst, ...this[kind](scope, new LiteralValue(scope, 1))[1]],
|
|
335
|
+
];
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const literalMethods = {
|
|
340
|
+
length: function (scope) {
|
|
341
|
+
if (typeof this.data !== "string")
|
|
342
|
+
throw new Error("Length method only works on string literal values.");
|
|
343
|
+
return new LiteralValue(scope, this.data.length);
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
class LiteralValue extends BaseValue {
|
|
347
|
+
constructor(scope, data) {
|
|
348
|
+
super(scope);
|
|
349
|
+
this.constant = true;
|
|
350
|
+
this.data = data;
|
|
351
|
+
}
|
|
352
|
+
eval(scope) {
|
|
353
|
+
return [this, []];
|
|
354
|
+
}
|
|
355
|
+
toString() {
|
|
356
|
+
return JSON.stringify(this.data);
|
|
357
|
+
}
|
|
358
|
+
get(scope, name) {
|
|
359
|
+
if (!(name instanceof LiteralValue && typeof name.data === "string"))
|
|
360
|
+
return super.get(scope, name);
|
|
361
|
+
const method = literalMethods[name.data];
|
|
362
|
+
if (!method)
|
|
363
|
+
throw new Error(`Method ${name.data} does not exist on literal values.`);
|
|
364
|
+
return [method.apply(this, [scope]), []];
|
|
365
|
+
}
|
|
366
|
+
get num() {
|
|
367
|
+
if (this.data === null)
|
|
368
|
+
return 0;
|
|
369
|
+
if (typeof this.data === "string")
|
|
370
|
+
return 1;
|
|
371
|
+
return this.data;
|
|
372
|
+
}
|
|
373
|
+
typeof(scope) {
|
|
374
|
+
return [new LiteralValue(scope, "literal"), []];
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const operatorMap = {
|
|
378
|
+
"==": (a, b) => +(a == b),
|
|
379
|
+
"===": (a, b) => +(a === b),
|
|
380
|
+
"!=": (a, b) => +(a != b),
|
|
381
|
+
"!==": (a, b) => +(a !== b),
|
|
382
|
+
"<": (a, b) => +(a < b),
|
|
383
|
+
">": (a, b) => +(a > b),
|
|
384
|
+
"<=": (a, b) => +(a <= b),
|
|
385
|
+
">=": (a, b) => +(a >= b),
|
|
386
|
+
"+": (a, b) => a + b,
|
|
387
|
+
"-": (a, b) => a - b,
|
|
388
|
+
"*": (a, b) => a * b,
|
|
389
|
+
"/": (a, b) => a / b,
|
|
390
|
+
"%": (a, b) => a % b,
|
|
391
|
+
"**": (a, b) => a ** b,
|
|
392
|
+
"|": (a, b) => a | b,
|
|
393
|
+
"&": (a, b) => a & b,
|
|
394
|
+
"^": (a, b) => a ^ b,
|
|
395
|
+
">>": (a, b) => a >> b,
|
|
396
|
+
">>>": (a, b) => a >> b,
|
|
397
|
+
"<<": (a, b) => a << b,
|
|
398
|
+
"&&": (a, b) => +(a && b),
|
|
399
|
+
"||": (a, b) => +(a || b),
|
|
400
|
+
};
|
|
401
|
+
for (const key in operatorMap) {
|
|
402
|
+
const fn = operatorMap[key];
|
|
403
|
+
LiteralValue.prototype[key] = function (scope, value) {
|
|
404
|
+
if (!(value instanceof LiteralValue)) {
|
|
405
|
+
return BaseValue.prototype[key].apply(this, [scope, value]);
|
|
406
|
+
}
|
|
407
|
+
return [new LiteralValue(scope, fn(this.num, value.num)), []];
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
const unaryOperatorMap = {
|
|
411
|
+
"!": v => +!v,
|
|
412
|
+
"~": v => ~v,
|
|
413
|
+
"u-": v => -v,
|
|
414
|
+
};
|
|
415
|
+
for (const key in unaryOperatorMap) {
|
|
416
|
+
LiteralValue.prototype[key] = function (scope) {
|
|
417
|
+
const fn = unaryOperatorMap[key];
|
|
418
|
+
return [new LiteralValue(scope, fn(this.num)), []];
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
class StoreValue extends BaseValue {
|
|
423
|
+
constructor(scope, name) {
|
|
424
|
+
super(scope);
|
|
425
|
+
this.constant = false;
|
|
426
|
+
this.name = name;
|
|
427
|
+
}
|
|
428
|
+
typeof(scope) {
|
|
429
|
+
return [new LiteralValue(scope, "store"), []];
|
|
430
|
+
}
|
|
431
|
+
"="(scope, value) {
|
|
432
|
+
if (this.constant)
|
|
433
|
+
throw new Error(`Cannot assign to unmutable store '${this.name}'.`);
|
|
434
|
+
if (value instanceof TempValue && value.canProxy)
|
|
435
|
+
return value.proxy(this);
|
|
436
|
+
const [evalValue, evalInst] = value.eval(scope);
|
|
437
|
+
return [this, [...evalInst, new SetInstruction(this, evalValue)]];
|
|
438
|
+
}
|
|
439
|
+
eval(scope) {
|
|
440
|
+
return [this, []];
|
|
441
|
+
}
|
|
442
|
+
toString() {
|
|
443
|
+
return this.name;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
class TempValue extends StoreValue {
|
|
448
|
+
constructor(scope, name) {
|
|
449
|
+
super(scope, name ?? "t" + scope.ntemp + (scope.name ? ":" + scope.name : ""));
|
|
450
|
+
this.canProxy = true;
|
|
451
|
+
if (!name)
|
|
452
|
+
scope.ntemp++;
|
|
453
|
+
}
|
|
454
|
+
eval(scope) {
|
|
455
|
+
return super.eval(scope);
|
|
456
|
+
}
|
|
457
|
+
"="(scope, value) {
|
|
458
|
+
if (this.proxied) {
|
|
459
|
+
this.noProxy();
|
|
460
|
+
return [this, [new SetInstruction(this, value)]];
|
|
461
|
+
}
|
|
462
|
+
if (value instanceof LiteralValue && this.canProxy) {
|
|
463
|
+
return this.proxy(value);
|
|
464
|
+
}
|
|
465
|
+
return super["="](scope, value);
|
|
466
|
+
}
|
|
467
|
+
proxy(value) {
|
|
468
|
+
if (!this.canProxy) {
|
|
469
|
+
console.log(this.proxied);
|
|
470
|
+
throw new Error("Cannot proxy (canProxy = false).");
|
|
471
|
+
}
|
|
472
|
+
if (this.proxied)
|
|
473
|
+
throw new Error("Cannot proxy multiple times.");
|
|
474
|
+
this.proxied = value;
|
|
475
|
+
this.canProxy = false;
|
|
476
|
+
for (const key of [
|
|
477
|
+
...operators,
|
|
478
|
+
"eval",
|
|
479
|
+
"get",
|
|
480
|
+
"call",
|
|
481
|
+
"toString",
|
|
482
|
+
"proxy",
|
|
483
|
+
]) {
|
|
484
|
+
if (key !== "=" && key in value)
|
|
485
|
+
this[key] = (...args) => value[key].apply(value, args);
|
|
486
|
+
}
|
|
487
|
+
this.setInst = new SetInstruction(this, value);
|
|
488
|
+
this.setInst.hidden = true;
|
|
489
|
+
return [this, [this.setInst]];
|
|
490
|
+
}
|
|
491
|
+
noProxy() {
|
|
492
|
+
this.setInst.hidden = false;
|
|
493
|
+
for (const key of [
|
|
494
|
+
...operators,
|
|
495
|
+
"eval",
|
|
496
|
+
"get",
|
|
497
|
+
"call",
|
|
498
|
+
"toString",
|
|
499
|
+
"proxy",
|
|
500
|
+
]) {
|
|
501
|
+
this[key] = TempValue.prototype[key];
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
class ObjectValue extends VoidValue {
|
|
507
|
+
constructor(scope, data = {}) {
|
|
508
|
+
super(scope);
|
|
509
|
+
this.constant = true;
|
|
510
|
+
this.macro = true;
|
|
511
|
+
this.data = data;
|
|
512
|
+
}
|
|
513
|
+
typeof(scope) {
|
|
514
|
+
return [new LiteralValue(scope, "object"), []];
|
|
515
|
+
}
|
|
516
|
+
get(scope, key) {
|
|
517
|
+
// avoids naming collisions with keys like
|
|
518
|
+
// constructor or toString
|
|
519
|
+
if (this.data.hasOwnProperty(key.data)) {
|
|
520
|
+
const member = this.data[key.data];
|
|
521
|
+
return [member, []];
|
|
522
|
+
}
|
|
523
|
+
const { $get } = this.data;
|
|
524
|
+
if (!$get)
|
|
525
|
+
throw new Error("Cannot get undefined member.");
|
|
526
|
+
return $get.call(scope, [key]);
|
|
527
|
+
}
|
|
528
|
+
eval(scope) {
|
|
529
|
+
const { $eval } = this.data;
|
|
530
|
+
if (!$eval)
|
|
531
|
+
return [this, []];
|
|
532
|
+
return $eval.call(scope, []);
|
|
533
|
+
}
|
|
534
|
+
call(scope, args) {
|
|
535
|
+
const { $call } = this.data;
|
|
536
|
+
if (!$call)
|
|
537
|
+
return super.call(scope, args);
|
|
538
|
+
return $call.call(scope, args);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
for (const op of operators) {
|
|
542
|
+
ObjectValue.prototype[op] = function (...args) {
|
|
543
|
+
const $ = this.data[`$${op}`];
|
|
544
|
+
if (!$)
|
|
545
|
+
return VoidValue.prototype[op].apply(this, args);
|
|
546
|
+
let [scope, ...fnArgs] = args;
|
|
547
|
+
return $.call(scope, fnArgs);
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
class Scope {
|
|
552
|
+
constructor(values, parent = null, stacked = false, ntemp = 0, name = "", inst = []) {
|
|
553
|
+
this.parent = parent;
|
|
554
|
+
this.stacked = stacked;
|
|
555
|
+
this.ntemp = ntemp;
|
|
556
|
+
this.name = name;
|
|
557
|
+
this.inst = inst;
|
|
558
|
+
this.data = values;
|
|
559
|
+
}
|
|
560
|
+
copy() {
|
|
561
|
+
const scope = new Scope({ ...this.data }, this.parent, this.stacked, this.ntemp, this.name, this.inst);
|
|
562
|
+
scope.break = this.break;
|
|
563
|
+
scope.continue = this.continue;
|
|
564
|
+
scope.function = this.function;
|
|
565
|
+
return scope;
|
|
566
|
+
}
|
|
567
|
+
createScope() {
|
|
568
|
+
const scope = this.copy();
|
|
569
|
+
scope.data = {};
|
|
570
|
+
scope.parent = this;
|
|
571
|
+
return scope;
|
|
572
|
+
}
|
|
573
|
+
createFunction(name, stacked) {
|
|
574
|
+
return new Scope({}, this, stacked ?? this.stacked, 0, name, this.inst);
|
|
575
|
+
}
|
|
576
|
+
has(name) {
|
|
577
|
+
if (name in this.data)
|
|
578
|
+
return true;
|
|
579
|
+
if (this.parent)
|
|
580
|
+
return this.parent.has(name);
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
get(name) {
|
|
584
|
+
const value = this.data[name];
|
|
585
|
+
if (value)
|
|
586
|
+
return value;
|
|
587
|
+
if (this.parent)
|
|
588
|
+
return this.parent.get(name);
|
|
589
|
+
throw Error(`${name} is not declared.`);
|
|
590
|
+
}
|
|
591
|
+
set(name, value) {
|
|
592
|
+
if (name in this.data)
|
|
593
|
+
throw Error(`${name} is already declared.`);
|
|
594
|
+
return this.hardSet(name, value);
|
|
595
|
+
}
|
|
596
|
+
hardSet(name, value) {
|
|
597
|
+
this.data[name] = value;
|
|
598
|
+
return value;
|
|
599
|
+
}
|
|
600
|
+
make(name, storeName) {
|
|
601
|
+
return this.set(name, this.stacked ? null : new StoreValue(this, storeName));
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const Program = (c, scope, node) => {
|
|
606
|
+
return c.handleMany(scope ?? new Scope({}), node.body);
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
function nodeName(node) {
|
|
610
|
+
const { line, column } = node.loc.start;
|
|
611
|
+
return line + ":" + column;
|
|
612
|
+
}
|
|
613
|
+
function camelToDashCase(name) {
|
|
614
|
+
return name.replace(/[A-Z]/g, str => `-${str.toLowerCase()}`);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const VariableDeclaration = (c, scope, node) => {
|
|
618
|
+
return c.handleMany(scope, node.declarations, (scope, child) => VariableDeclarator(c, scope, child, node.kind));
|
|
619
|
+
};
|
|
620
|
+
const VariableDeclarator = (c, scope, node, kind = "let") => {
|
|
621
|
+
let valinst = node.init
|
|
622
|
+
? c.handleEval(scope, node.init)
|
|
623
|
+
: [null, []];
|
|
624
|
+
switch (node.id.type) {
|
|
625
|
+
case "Identifier": {
|
|
626
|
+
const { name } = node.id;
|
|
627
|
+
const [init] = valinst;
|
|
628
|
+
if (kind === "const" && !init)
|
|
629
|
+
throw Error("Cannot create constant with void value.");
|
|
630
|
+
if (kind === "const" && init?.constant) {
|
|
631
|
+
scope.set(name, init);
|
|
632
|
+
return valinst;
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
const value = scope.make(name, nodeName(node));
|
|
636
|
+
if (init) {
|
|
637
|
+
if (init.macro)
|
|
638
|
+
throw new Error("Macro value must be constant.");
|
|
639
|
+
valinst[1].push(...value["="](scope, init)[1]);
|
|
640
|
+
}
|
|
641
|
+
if (kind === "const")
|
|
642
|
+
value.constant = true;
|
|
643
|
+
return valinst;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
case "ArrayPattern": {
|
|
647
|
+
const { elements } = node.id;
|
|
648
|
+
const [init] = valinst;
|
|
649
|
+
if (!init)
|
|
650
|
+
throw new Error("Cannot use array destructuring with constant with void value.");
|
|
651
|
+
if (!init.macro)
|
|
652
|
+
throw new Error("Cannot use array destructuring on non macro values");
|
|
653
|
+
if (!(init instanceof ObjectValue)) {
|
|
654
|
+
throw new Error("Array destructuring target must be an object value");
|
|
655
|
+
}
|
|
656
|
+
for (let i = 0; i < elements.length; i++) {
|
|
657
|
+
const element = elements[i];
|
|
658
|
+
if (!element)
|
|
659
|
+
continue;
|
|
660
|
+
if (element.type !== "Identifier") {
|
|
661
|
+
throw new Error("Array destructuring expression can only have empty items or identifiers");
|
|
662
|
+
}
|
|
663
|
+
const val = init.data[i];
|
|
664
|
+
scope.set(element.name, val);
|
|
665
|
+
}
|
|
666
|
+
return valinst;
|
|
667
|
+
}
|
|
668
|
+
default:
|
|
669
|
+
throw new Error("");
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
const Literal = (c, scope, node) => {
|
|
674
|
+
const { value } = node;
|
|
675
|
+
if (value === null ||
|
|
676
|
+
typeof value === "string" ||
|
|
677
|
+
typeof value === "number") {
|
|
678
|
+
return [new LiteralValue(scope, value), []];
|
|
679
|
+
}
|
|
680
|
+
if (typeof value === "boolean") {
|
|
681
|
+
return [new LiteralValue(scope, +value), []];
|
|
682
|
+
}
|
|
683
|
+
throw Error("Cannot create literal " + typeof value);
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
const LRExpression = (c, scope, node) => {
|
|
687
|
+
const [left, leftInst] = c.handleEval(scope, node.left);
|
|
688
|
+
const [right, rightInst] = c.handleEval(scope, node.right);
|
|
689
|
+
const [op, opInst] = left[node.operator](scope, right);
|
|
690
|
+
return [op, [...leftInst, ...rightInst, ...opInst]];
|
|
691
|
+
};
|
|
692
|
+
const BinaryExpression = LRExpression;
|
|
693
|
+
const LogicalExpression = LRExpression;
|
|
694
|
+
const AssignmentExpression = (c, scope, node) => {
|
|
695
|
+
const [left, leftInst] = c.handle(scope, node.left);
|
|
696
|
+
const [right, rightInst] = c.handleEval(scope, node.right);
|
|
697
|
+
const [op, opInst] = left[node.operator](scope, right);
|
|
698
|
+
return [op, [...leftInst, ...rightInst, ...opInst]];
|
|
699
|
+
};
|
|
700
|
+
const UnaryExpression = (c, scope, { argument, operator }) => {
|
|
701
|
+
const [arg, argInst] = c.handleEval(scope, argument);
|
|
702
|
+
const operatorId = operator == "+" || operator == "-" ? `u${operator}` : operator;
|
|
703
|
+
const [op, opInst] = arg[operatorId](scope);
|
|
704
|
+
return [op, [...argInst, ...opInst]];
|
|
705
|
+
};
|
|
706
|
+
const UpdateExpression = (c, scope, { argument, operator, prefix }) => {
|
|
707
|
+
const [arg, argInst] = c.handle(scope, argument);
|
|
708
|
+
const [op, opInst] = arg[operator](scope, prefix);
|
|
709
|
+
return [op, [...argInst, ...opInst]];
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
const Identifier = (c, scope, node) => {
|
|
713
|
+
return [scope.get(node.name), []];
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
const ExpressionStatement = (c, scope, node) => {
|
|
717
|
+
return c.handle(scope, node.expression);
|
|
718
|
+
};
|
|
719
|
+
const BreakStatement = (_, scope) => {
|
|
720
|
+
const addr = new LiteralValue(scope, null);
|
|
721
|
+
scope.break.bind(addr);
|
|
722
|
+
return [null, [new BreakInstruction(addr)]];
|
|
723
|
+
};
|
|
724
|
+
const ContinueStatement = (_, scope) => {
|
|
725
|
+
const addr = new LiteralValue(scope, null);
|
|
726
|
+
scope.continue.bind(addr);
|
|
727
|
+
return [null, [new ContinueInstruction(addr)]];
|
|
728
|
+
};
|
|
729
|
+
const ReturnStatement = (c, scope, node) => {
|
|
730
|
+
const [arg, argInst] = node.argument
|
|
731
|
+
? c.handle(scope, node.argument)
|
|
732
|
+
: [null, []];
|
|
733
|
+
const [ret, retInst] = scope.function.return(scope, arg);
|
|
734
|
+
return [ret, [...argInst, ...retInst]];
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
const IfStatement = (c, scope, node) => {
|
|
738
|
+
const inst = [];
|
|
739
|
+
const [test, testInst] = c.handleEval(scope, node.test);
|
|
740
|
+
if (test instanceof LiteralValue) {
|
|
741
|
+
if (test.data)
|
|
742
|
+
inst.push(...c.handle(scope, node.consequent)[1]);
|
|
743
|
+
else if (node.alternate)
|
|
744
|
+
inst.push(...c.handle(scope, node.alternate)[1]);
|
|
745
|
+
return [null, inst];
|
|
746
|
+
}
|
|
747
|
+
const endIfAddr = new LiteralValue(scope, null);
|
|
748
|
+
inst.push(...testInst, new JumpInstruction(endIfAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...c.handle(scope, node.consequent)[1], new AddressResolver(endIfAddr));
|
|
749
|
+
const endElseAddr = new LiteralValue(scope, null);
|
|
750
|
+
if (node.alternate)
|
|
751
|
+
inst.push(new JumpInstruction(endElseAddr, EJumpKind.Always), new AddressResolver(endIfAddr), ...c.handle(scope, node.alternate)[1], new AddressResolver(endElseAddr));
|
|
752
|
+
return [null, inst];
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
const WhileStatement = (c, scope, node) => {
|
|
756
|
+
const lines = [];
|
|
757
|
+
const [test, testLines] = c.handleEval(scope, node.test);
|
|
758
|
+
const startLoopAddr = new LiteralValue(scope, null);
|
|
759
|
+
const endLoopAddr = new LiteralValue(scope, null);
|
|
760
|
+
const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
|
|
761
|
+
const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
|
|
762
|
+
if (test instanceof LiteralValue) {
|
|
763
|
+
if (test.data) {
|
|
764
|
+
lines.push(startLoopLine, ...c.handle(scope, node.body)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
|
|
765
|
+
}
|
|
766
|
+
return [null, lines];
|
|
767
|
+
}
|
|
768
|
+
lines.push(startLoopLine, ...testLines, new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)), ...c.handle(scope, node.body)[1], new JumpInstruction(startLoopAddr, EJumpKind.Always), endLoopLine);
|
|
769
|
+
return [null, lines];
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
const ForStatement = (c, scope, node) => {
|
|
773
|
+
scope = scope.createScope();
|
|
774
|
+
const initInst = node.init ? c.handle(scope, node.init)[1] : [];
|
|
775
|
+
const [test, testLines] = node.test
|
|
776
|
+
? c.handleEval(scope, node.test)
|
|
777
|
+
: [new LiteralValue(scope, 1), []];
|
|
778
|
+
const updateLines = node.update ? c.handle(scope, node.update)[1] : [];
|
|
779
|
+
const startLoopAddr = new LiteralValue(scope, null);
|
|
780
|
+
const endLoopAddr = new LiteralValue(scope, null);
|
|
781
|
+
const startLoopLine = new AddressResolver(startLoopAddr).bindContinue(scope);
|
|
782
|
+
const endLoopLine = new AddressResolver(endLoopAddr).bindBreak(scope);
|
|
783
|
+
return [
|
|
784
|
+
null,
|
|
785
|
+
[
|
|
786
|
+
...initInst,
|
|
787
|
+
startLoopLine,
|
|
788
|
+
...testLines,
|
|
789
|
+
new JumpInstruction(endLoopAddr, EJumpKind.Equal, test, new LiteralValue(scope, 0)),
|
|
790
|
+
...c.handle(scope, node.body)[1],
|
|
791
|
+
...updateLines,
|
|
792
|
+
new JumpInstruction(startLoopAddr, EJumpKind.Always),
|
|
793
|
+
endLoopLine,
|
|
794
|
+
],
|
|
795
|
+
];
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
class FunctionValue extends VoidValue {
|
|
799
|
+
constructor(scope, name, paramNames, paramStores, body, c) {
|
|
800
|
+
super(scope);
|
|
801
|
+
this.constant = true;
|
|
802
|
+
this.macro = true;
|
|
803
|
+
this.bundled = false;
|
|
804
|
+
this.name = name;
|
|
805
|
+
this.paramNames = paramNames;
|
|
806
|
+
this.paramStores = paramStores;
|
|
807
|
+
this.body = body;
|
|
808
|
+
this.c = c;
|
|
809
|
+
this.callSize = paramStores.length + 2;
|
|
810
|
+
scope.function = this;
|
|
811
|
+
this.createValues();
|
|
812
|
+
this.createInst();
|
|
813
|
+
}
|
|
814
|
+
createValues() {
|
|
815
|
+
this.addr = new LiteralValue(this.scope, null);
|
|
816
|
+
this.temp = new StoreValue(this.scope, "f" + this.name);
|
|
817
|
+
this.ret = new StoreValue(this.scope, "r" + this.name);
|
|
818
|
+
}
|
|
819
|
+
typeof(scope) {
|
|
820
|
+
return [new LiteralValue(scope, "function"), []];
|
|
821
|
+
}
|
|
822
|
+
createInst() {
|
|
823
|
+
this.inst = [
|
|
824
|
+
new AddressResolver(this.addr),
|
|
825
|
+
...this.c.handle(this.scope, this.body)[1],
|
|
826
|
+
];
|
|
827
|
+
this.inst.push(new SetCounterInstruction(this.ret));
|
|
828
|
+
}
|
|
829
|
+
normalReturn(scope, arg) {
|
|
830
|
+
const argInst = arg ? this.temp["="](scope, arg)[1] : [];
|
|
831
|
+
return [null, [...argInst, new SetCounterInstruction(this.ret)]];
|
|
832
|
+
}
|
|
833
|
+
normalCall(scope, args) {
|
|
834
|
+
if (!this.bundled)
|
|
835
|
+
this.scope.inst.push(...this.inst);
|
|
836
|
+
this.bundled = true;
|
|
837
|
+
const callAddressLiteral = new LiteralValue(scope, null);
|
|
838
|
+
const inst = this.paramStores
|
|
839
|
+
.map((param, i) => param["="](scope, args[i])[1])
|
|
840
|
+
.reduce((s, c) => s.concat(c), [])
|
|
841
|
+
.concat(...this.ret["="](scope, callAddressLiteral)[1], new JumpInstruction(this.addr, EJumpKind.Always), new AddressResolver(callAddressLiteral));
|
|
842
|
+
return [this.temp, inst];
|
|
843
|
+
}
|
|
844
|
+
inlineReturn(scope, arg) {
|
|
845
|
+
const argInst = arg ? this.inlineTemp["="](scope, arg)[1] : [];
|
|
846
|
+
return [null, [...argInst, new ReturnInstruction(this.inlineEnd)]];
|
|
847
|
+
}
|
|
848
|
+
inlineCall(scope, args) {
|
|
849
|
+
// create return value
|
|
850
|
+
this.inlineTemp = new TempValue(scope);
|
|
851
|
+
this.inlineEnd = new LiteralValue(scope, null);
|
|
852
|
+
// make a copy of the function scope
|
|
853
|
+
const fnScope = this.scope.copy();
|
|
854
|
+
// hard set variables within the function scope
|
|
855
|
+
this.paramNames.forEach((name, i) => fnScope.hardSet(name, args[i]));
|
|
856
|
+
this.tryingInline = true;
|
|
857
|
+
let inst = this.c.handle(fnScope, this.body)[1];
|
|
858
|
+
this.tryingInline = false;
|
|
859
|
+
// removing useless instruction
|
|
860
|
+
// get the last instructions
|
|
861
|
+
// const [jump] = inst.slice(-1);
|
|
862
|
+
// if (jump instanceof JumpInstruction) {
|
|
863
|
+
// // remove useless jump
|
|
864
|
+
// if (jump.args[1] === this.inlineEnd) inst.pop();
|
|
865
|
+
// }
|
|
866
|
+
inst.push(new AddressResolver(this.inlineEnd));
|
|
867
|
+
// return the function value
|
|
868
|
+
return [this.inlineTemp, inst];
|
|
869
|
+
}
|
|
870
|
+
call(scope, args) {
|
|
871
|
+
if (args.length !== this.paramStores.length)
|
|
872
|
+
throw new Error("Cannot call: argument count not matching.");
|
|
873
|
+
const inlineCall = this.inlineCall(scope, args);
|
|
874
|
+
const inlineSize = inlineCall[1].filter(i => !i.hidden).length;
|
|
875
|
+
if (this.inline || inlineSize <= this.callSize)
|
|
876
|
+
return inlineCall;
|
|
877
|
+
return this.normalCall(scope, args);
|
|
878
|
+
}
|
|
879
|
+
return(scope, arg) {
|
|
880
|
+
if (arg && arg.macro) {
|
|
881
|
+
this.inline = true;
|
|
882
|
+
return [null, []];
|
|
883
|
+
}
|
|
884
|
+
if (this.inline || this.tryingInline)
|
|
885
|
+
return this.inlineReturn(scope, arg);
|
|
886
|
+
return this.normalReturn(scope, arg);
|
|
887
|
+
}
|
|
888
|
+
eval(scope) {
|
|
889
|
+
return [this, []];
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
const ArrowFunctionExpression = (c, scope, node) => {
|
|
894
|
+
const name = nodeName(node);
|
|
895
|
+
scope = scope.createFunction(name);
|
|
896
|
+
let { params, body } = node;
|
|
897
|
+
if (node.expression) {
|
|
898
|
+
body = {
|
|
899
|
+
type: "BlockStatement",
|
|
900
|
+
body: [{ type: "ReturnStatement", argument: body }],
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
const paramNames = [];
|
|
904
|
+
const paramStores = [];
|
|
905
|
+
for (const id of params) {
|
|
906
|
+
paramNames.push(id.name);
|
|
907
|
+
paramStores.push(scope.make(id.name, nodeName(id)));
|
|
908
|
+
}
|
|
909
|
+
return [
|
|
910
|
+
new FunctionValue(scope, name, paramNames, paramStores, body, c),
|
|
911
|
+
[],
|
|
912
|
+
];
|
|
913
|
+
};
|
|
914
|
+
const FunctionDeclaration = (c, scope, node) => {
|
|
915
|
+
return [
|
|
916
|
+
scope.set(node.id.name, ArrowFunctionExpression(c, scope, node, null)[0]),
|
|
917
|
+
[],
|
|
918
|
+
];
|
|
919
|
+
};
|
|
920
|
+
const FunctionExpression = ArrowFunctionExpression;
|
|
921
|
+
|
|
922
|
+
const CallExpression = (c, scope, node) => {
|
|
923
|
+
const inst = [];
|
|
924
|
+
const args = node.arguments.map(node => {
|
|
925
|
+
// TODO: this might be why t0 did not increment
|
|
926
|
+
const [v, i] = c.handleEval(scope, node);
|
|
927
|
+
inst.push(...i);
|
|
928
|
+
return v;
|
|
929
|
+
});
|
|
930
|
+
const [callee, calleeInst] = c.handleEval(scope, node.callee);
|
|
931
|
+
inst.push(...calleeInst);
|
|
932
|
+
const [callValue, callInst] = callee.call(scope, args);
|
|
933
|
+
inst.push(...callInst);
|
|
934
|
+
return [callValue, inst];
|
|
935
|
+
};
|
|
936
|
+
const NewExpression = CallExpression;
|
|
937
|
+
|
|
938
|
+
const ObjectExpression = (c, scope, node) => {
|
|
939
|
+
const data = {};
|
|
940
|
+
const inst = [];
|
|
941
|
+
for (const prop of node.properties) {
|
|
942
|
+
if (prop.computed)
|
|
943
|
+
throw new Error("Cannot handle computed property.");
|
|
944
|
+
const { key, value } = prop;
|
|
945
|
+
let index;
|
|
946
|
+
if (key.type === "Identifier")
|
|
947
|
+
index = key.name;
|
|
948
|
+
else if (key.type === "Literal")
|
|
949
|
+
index = "" + key.value;
|
|
950
|
+
else {
|
|
951
|
+
throw new Error(`Unsupported object key type: ${key.type}`);
|
|
952
|
+
}
|
|
953
|
+
const [member, memberInst] = c.handleEval(scope, value);
|
|
954
|
+
data[index] = member;
|
|
955
|
+
inst.push(...memberInst);
|
|
956
|
+
}
|
|
957
|
+
return [new ObjectValue(scope, data), inst];
|
|
958
|
+
};
|
|
959
|
+
const ArrayExpression = (c, scope, node) => {
|
|
960
|
+
const data = {};
|
|
961
|
+
const inst = [];
|
|
962
|
+
node.elements.forEach((element, i) => {
|
|
963
|
+
if (!element)
|
|
964
|
+
return;
|
|
965
|
+
const [value, valueInst] = c.handleEval(scope, element);
|
|
966
|
+
data[i] = value;
|
|
967
|
+
inst.push(...valueInst);
|
|
968
|
+
});
|
|
969
|
+
return [new ObjectValue(scope, data), inst];
|
|
970
|
+
};
|
|
971
|
+
const MemberExpression = (c, scope, node) => {
|
|
972
|
+
const [obj, objInst] = c.handleEval(scope, node.object);
|
|
973
|
+
const [prop, propInst] = node.computed
|
|
974
|
+
? c.handleEval(scope, node.property)
|
|
975
|
+
: [new LiteralValue(scope, node.property.name), []];
|
|
976
|
+
const [got, gotInst] = obj.get(scope, prop);
|
|
977
|
+
return [got, [...objInst, ...propInst, ...gotInst]];
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
const TemplateLiteral = (c, scope, node) => {
|
|
981
|
+
const args = [];
|
|
982
|
+
const inst = [];
|
|
983
|
+
node.expressions.forEach((expression, i) => {
|
|
984
|
+
const [v, vi] = c.handleEval(scope, expression);
|
|
985
|
+
inst.push(...vi);
|
|
986
|
+
args.push(node.quasis[i].value.raw, v);
|
|
987
|
+
});
|
|
988
|
+
args.push(node.quasis.slice(-1)[0].value.raw);
|
|
989
|
+
inst.push(new ZeroSpaceInstruction(...args));
|
|
990
|
+
return [null, inst];
|
|
991
|
+
};
|
|
992
|
+
|
|
993
|
+
const BlockStatement = (c, scope, node) => {
|
|
994
|
+
const [value, insts] = c.handleMany(scope.createScope(), node.body);
|
|
995
|
+
// const cleanInst = []
|
|
996
|
+
// for (const inst of insts) {
|
|
997
|
+
// if (inst instanceof BreakInstruction || inst instanceof ContinueInstruction || inst instanceof ReturnInstruction || inst instanceof SetCounterInstruction) break
|
|
998
|
+
// cleanInst.push(inst)
|
|
999
|
+
// }
|
|
1000
|
+
return [value, insts];
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
var handlers = /*#__PURE__*/Object.freeze({
|
|
1004
|
+
__proto__: null,
|
|
1005
|
+
Program: Program,
|
|
1006
|
+
VariableDeclaration: VariableDeclaration,
|
|
1007
|
+
VariableDeclarator: VariableDeclarator,
|
|
1008
|
+
Literal: Literal,
|
|
1009
|
+
LRExpression: LRExpression,
|
|
1010
|
+
BinaryExpression: BinaryExpression,
|
|
1011
|
+
LogicalExpression: LogicalExpression,
|
|
1012
|
+
AssignmentExpression: AssignmentExpression,
|
|
1013
|
+
UnaryExpression: UnaryExpression,
|
|
1014
|
+
UpdateExpression: UpdateExpression,
|
|
1015
|
+
Identifier: Identifier,
|
|
1016
|
+
ExpressionStatement: ExpressionStatement,
|
|
1017
|
+
BreakStatement: BreakStatement,
|
|
1018
|
+
ContinueStatement: ContinueStatement,
|
|
1019
|
+
ReturnStatement: ReturnStatement,
|
|
1020
|
+
IfStatement: IfStatement,
|
|
1021
|
+
WhileStatement: WhileStatement,
|
|
1022
|
+
ForStatement: ForStatement,
|
|
1023
|
+
ArrowFunctionExpression: ArrowFunctionExpression,
|
|
1024
|
+
FunctionDeclaration: FunctionDeclaration,
|
|
1025
|
+
FunctionExpression: FunctionExpression,
|
|
1026
|
+
CallExpression: CallExpression,
|
|
1027
|
+
NewExpression: NewExpression,
|
|
1028
|
+
ObjectExpression: ObjectExpression,
|
|
1029
|
+
ArrayExpression: ArrayExpression,
|
|
1030
|
+
MemberExpression: MemberExpression,
|
|
1031
|
+
TemplateLiteral: TemplateLiteral,
|
|
1032
|
+
BlockStatement: BlockStatement
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
class MacroFunction extends VoidValue {
|
|
1036
|
+
constructor(scope, fn) {
|
|
1037
|
+
super(scope);
|
|
1038
|
+
this.macro = true;
|
|
1039
|
+
this.constant = true;
|
|
1040
|
+
this.fn = fn;
|
|
1041
|
+
}
|
|
1042
|
+
call(scope, args) {
|
|
1043
|
+
return this.fn.apply(this, args);
|
|
1044
|
+
}
|
|
1045
|
+
eval(scope) {
|
|
1046
|
+
return [this, []];
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
const mathOperations = {
|
|
1051
|
+
max: (a, b) => Math.max(a, b),
|
|
1052
|
+
min: (a, b) => Math.min(a, b),
|
|
1053
|
+
angle: (x, y) => {
|
|
1054
|
+
const angle = (Math.atan2(y, x) * 180) / Math.PI;
|
|
1055
|
+
return angle < 0 ? angle + 360 : angle;
|
|
1056
|
+
},
|
|
1057
|
+
len: (a, b) => Math.sqrt(a ** 2 + b ** 2),
|
|
1058
|
+
noise: null,
|
|
1059
|
+
abs: a => Math.abs(a),
|
|
1060
|
+
log: a => Math.log(a),
|
|
1061
|
+
log10: a => Math.log10(a),
|
|
1062
|
+
sin: a => Math.sin(a),
|
|
1063
|
+
cos: a => Math.cos(a),
|
|
1064
|
+
tan: a => Math.tan(a),
|
|
1065
|
+
floor: a => Math.floor(a),
|
|
1066
|
+
ceil: a => Math.ceil(a),
|
|
1067
|
+
sqrt: a => Math.sqrt(a),
|
|
1068
|
+
rand: null,
|
|
1069
|
+
};
|
|
1070
|
+
function createMacroMathOperations(scope) {
|
|
1071
|
+
const macroMathOperations = {};
|
|
1072
|
+
for (const key in mathOperations) {
|
|
1073
|
+
const fn = mathOperations[key];
|
|
1074
|
+
macroMathOperations[key] = new MacroFunction(scope, (a, b) => {
|
|
1075
|
+
if (b) {
|
|
1076
|
+
if (fn && a instanceof LiteralValue && b instanceof LiteralValue) {
|
|
1077
|
+
if (typeof a.data !== "number" || typeof b.data !== "number")
|
|
1078
|
+
throw new Error("Cannot do math operation with non-numerical literals.");
|
|
1079
|
+
return [new LiteralValue(scope, fn(a.num, b.num)), []];
|
|
1080
|
+
}
|
|
1081
|
+
const temp = new TempValue(scope);
|
|
1082
|
+
return [temp, [new OperationInstruction(key, temp, a, b)]];
|
|
1083
|
+
}
|
|
1084
|
+
if (fn && a instanceof LiteralValue) {
|
|
1085
|
+
if (typeof a.data !== "number")
|
|
1086
|
+
throw new Error("Cannot do math operation with non-numerical literal.");
|
|
1087
|
+
return [new LiteralValue(scope, fn(a.num)), []];
|
|
1088
|
+
}
|
|
1089
|
+
const temp = new TempValue(scope);
|
|
1090
|
+
return [temp, [new OperationInstruction(key, temp, a, b)]];
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
return macroMathOperations;
|
|
1094
|
+
}
|
|
1095
|
+
class MlogMath extends ObjectValue {
|
|
1096
|
+
constructor(scope) {
|
|
1097
|
+
super(scope, createMacroMathOperations(scope));
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
// op angle result a b
|
|
1101
|
+
// op len result a b
|
|
1102
|
+
|
|
1103
|
+
class Concat extends MacroFunction {
|
|
1104
|
+
constructor(scope) {
|
|
1105
|
+
super(scope, (...values) => {
|
|
1106
|
+
for (const value of values)
|
|
1107
|
+
if (!(value instanceof LiteralValue))
|
|
1108
|
+
throw new Error("Concat arguments must all be literal values.");
|
|
1109
|
+
return [
|
|
1110
|
+
new LiteralValue(scope, values.map(v => v.data).join("")),
|
|
1111
|
+
[],
|
|
1112
|
+
];
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
class Draw extends MacroFunction {
|
|
1118
|
+
constructor(scope) {
|
|
1119
|
+
super(scope, (kind, ...args) => {
|
|
1120
|
+
if (!(kind instanceof LiteralValue && typeof kind.data === "string"))
|
|
1121
|
+
throw new Error("Draw kind must be literal.");
|
|
1122
|
+
if ([
|
|
1123
|
+
"clear",
|
|
1124
|
+
"color",
|
|
1125
|
+
"stroke",
|
|
1126
|
+
"line",
|
|
1127
|
+
"rect",
|
|
1128
|
+
"lineRect",
|
|
1129
|
+
"poly",
|
|
1130
|
+
"linePoly",
|
|
1131
|
+
"triangle",
|
|
1132
|
+
"image",
|
|
1133
|
+
].indexOf(kind.data) === -1)
|
|
1134
|
+
throw new Error("Draw kind must be valid");
|
|
1135
|
+
return [
|
|
1136
|
+
null,
|
|
1137
|
+
[
|
|
1138
|
+
new InstructionBase("draw", kind.data, ...args.map(v => {
|
|
1139
|
+
if (v instanceof LiteralValue && typeof v.data === "string")
|
|
1140
|
+
return v.data;
|
|
1141
|
+
return v;
|
|
1142
|
+
})),
|
|
1143
|
+
],
|
|
1144
|
+
];
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
class Print extends MacroFunction {
|
|
1150
|
+
constructor(scope) {
|
|
1151
|
+
super(scope, (...values) => {
|
|
1152
|
+
const inst = [];
|
|
1153
|
+
for (const value of values) {
|
|
1154
|
+
inst.push(new InstructionBase("print", value));
|
|
1155
|
+
}
|
|
1156
|
+
return [null, inst];
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
class PrintFlush extends MacroFunction {
|
|
1162
|
+
constructor(scope) {
|
|
1163
|
+
super(scope, (target) => {
|
|
1164
|
+
if (!(target instanceof ObjectValue))
|
|
1165
|
+
throw new Error("The printflush target must be a building");
|
|
1166
|
+
return [null, [new InstructionBase("printflush", target)]];
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
class DrawFlush extends MacroFunction {
|
|
1172
|
+
constructor(scope) {
|
|
1173
|
+
super(scope, (target) => {
|
|
1174
|
+
if (!(target instanceof ObjectValue))
|
|
1175
|
+
throw new Error("The drawflush target must be a building");
|
|
1176
|
+
return [null, [new InstructionBase("drawflush", target)]];
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
const itemNames = [
|
|
1182
|
+
"copper",
|
|
1183
|
+
"lead",
|
|
1184
|
+
"metaglass",
|
|
1185
|
+
"graphite",
|
|
1186
|
+
"sand",
|
|
1187
|
+
"coal",
|
|
1188
|
+
"titanium",
|
|
1189
|
+
"thorium",
|
|
1190
|
+
"scrap",
|
|
1191
|
+
"silicon",
|
|
1192
|
+
"plastanium",
|
|
1193
|
+
"phaseFabric",
|
|
1194
|
+
"surgeAlloy",
|
|
1195
|
+
"sporePod",
|
|
1196
|
+
"blastCompound",
|
|
1197
|
+
"pyratite",
|
|
1198
|
+
];
|
|
1199
|
+
class Building extends ObjectValue {
|
|
1200
|
+
constructor(scope, name) {
|
|
1201
|
+
super(scope, {
|
|
1202
|
+
$get: new MacroFunction(scope, (prop) => {
|
|
1203
|
+
if (prop instanceof LiteralValue && typeof prop.data === "string") {
|
|
1204
|
+
const name = itemNames.includes(prop.data)
|
|
1205
|
+
? camelToDashCase(prop.data)
|
|
1206
|
+
: prop.data;
|
|
1207
|
+
const temp = new TempValue(scope);
|
|
1208
|
+
return [
|
|
1209
|
+
temp,
|
|
1210
|
+
[new InstructionBase("sensor", temp, this, `@${name}`)],
|
|
1211
|
+
];
|
|
1212
|
+
}
|
|
1213
|
+
if (prop instanceof StoreValue) {
|
|
1214
|
+
const temp = new TempValue(scope);
|
|
1215
|
+
return [temp, [new InstructionBase("sensor", temp, this, prop)]];
|
|
1216
|
+
}
|
|
1217
|
+
throw new Error("Building property acessors must be string literals or stores");
|
|
1218
|
+
}),
|
|
1219
|
+
});
|
|
1220
|
+
this.name = name;
|
|
1221
|
+
}
|
|
1222
|
+
toString() {
|
|
1223
|
+
return this.name;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
class BuildingBuilder extends ObjectValue {
|
|
1227
|
+
constructor(scope) {
|
|
1228
|
+
super(scope, {
|
|
1229
|
+
$call: new MacroFunction(scope, (nameLit) => {
|
|
1230
|
+
if (!(nameLit instanceof LiteralValue))
|
|
1231
|
+
throw new Error("Block name must be a literal.");
|
|
1232
|
+
if (typeof nameLit.data !== "string")
|
|
1233
|
+
throw new Error("Block name must be a string.");
|
|
1234
|
+
return [new Building(scope, nameLit.data), []];
|
|
1235
|
+
}),
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
for (const key in operatorMap$2) {
|
|
1240
|
+
const kind = operatorMap$2[key];
|
|
1241
|
+
Building.prototype[key] = function (scope, value) {
|
|
1242
|
+
const left = new StoreValue(scope, this.name);
|
|
1243
|
+
const [right, rightInst] = value.eval(scope);
|
|
1244
|
+
const temp = new TempValue(scope);
|
|
1245
|
+
return [
|
|
1246
|
+
temp,
|
|
1247
|
+
[...rightInst, new OperationInstruction(kind, temp, left, right)],
|
|
1248
|
+
];
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
class GetLink extends MacroFunction {
|
|
1253
|
+
constructor(scope) {
|
|
1254
|
+
super(scope, (index) => {
|
|
1255
|
+
if (!(index instanceof StoreValue) &&
|
|
1256
|
+
(!(index instanceof LiteralValue) || typeof index.data !== "number"))
|
|
1257
|
+
throw new Error("The getlink index must be a number literal or a store");
|
|
1258
|
+
const temp = new TempValue(scope);
|
|
1259
|
+
const outBuild = new Building(scope, temp.name);
|
|
1260
|
+
return [outBuild, [new InstructionBase("getlink", temp, index)]];
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
const validKinds$1 = ["enabled", "shoot", "shootp", "config", "color"];
|
|
1266
|
+
class Control extends MacroFunction {
|
|
1267
|
+
constructor(scope) {
|
|
1268
|
+
super(scope, (kind, building, ...args) => {
|
|
1269
|
+
if (!(kind instanceof LiteralValue) || typeof kind.data !== "string")
|
|
1270
|
+
throw new Error("The control kind must be a string literal");
|
|
1271
|
+
if (!validKinds$1.includes(kind.data))
|
|
1272
|
+
throw new Error("Invalid control kind");
|
|
1273
|
+
if (!(building instanceof ObjectValue))
|
|
1274
|
+
throw new Error("The building must be an object value");
|
|
1275
|
+
return [
|
|
1276
|
+
null,
|
|
1277
|
+
[new InstructionBase("control", kind.data, building, ...args)],
|
|
1278
|
+
];
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
class NamespaceMacro extends ObjectValue {
|
|
1284
|
+
constructor(scope, { changeCasing = false } = {}) {
|
|
1285
|
+
super(scope, {
|
|
1286
|
+
$get: new MacroFunction(scope, prop => {
|
|
1287
|
+
if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
|
|
1288
|
+
throw new Error("Cannot use dynamic properties on object macros");
|
|
1289
|
+
const symbolName = this.changeCasing
|
|
1290
|
+
? camelToDashCase(prop.data)
|
|
1291
|
+
: prop.data;
|
|
1292
|
+
return [new StoreValue(scope, `@${symbolName}`), []];
|
|
1293
|
+
}),
|
|
1294
|
+
});
|
|
1295
|
+
this.changeCasing = changeCasing;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
class VarsNamespace extends NamespaceMacro {
|
|
1299
|
+
constructor(scope) {
|
|
1300
|
+
super(scope);
|
|
1301
|
+
const $get = this.data.$get;
|
|
1302
|
+
this.data.$get = new MacroFunction(scope, prop => {
|
|
1303
|
+
if (prop instanceof LiteralValue) {
|
|
1304
|
+
if (prop.data === "unit")
|
|
1305
|
+
return [new Unit(scope, "@unit"), []];
|
|
1306
|
+
if (prop.data === "this")
|
|
1307
|
+
return [new Building(scope, "@this"), []];
|
|
1308
|
+
}
|
|
1309
|
+
return $get.call(scope, [prop]);
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
class UCommandsNamespace extends NamespaceMacro {
|
|
1314
|
+
constructor(scope) {
|
|
1315
|
+
super(scope);
|
|
1316
|
+
const $get = this.data.$get;
|
|
1317
|
+
this.data.$get = new MacroFunction(scope, prop => {
|
|
1318
|
+
if (!(prop instanceof LiteralValue) || typeof prop.data !== "string")
|
|
1319
|
+
throw new Error("Cannot use dynamic properties on object macros");
|
|
1320
|
+
const symbolName = prop.data[0].toUpperCase() + prop.data.slice(1);
|
|
1321
|
+
return [new StoreValue(scope, `@command${symbolName}`), []];
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
// TODO: repeated logic between UnitMacro and Building
|
|
1326
|
+
class Unit extends ObjectValue {
|
|
1327
|
+
constructor(scope, name) {
|
|
1328
|
+
super(scope, {
|
|
1329
|
+
$get: new MacroFunction(scope, prop => {
|
|
1330
|
+
if (prop instanceof LiteralValue && typeof prop.data === "string") {
|
|
1331
|
+
const name = itemNames.includes(prop.data)
|
|
1332
|
+
? camelToDashCase(prop.data)
|
|
1333
|
+
: prop.data;
|
|
1334
|
+
const temp = new TempValue(scope);
|
|
1335
|
+
// special case, should return another unit or building
|
|
1336
|
+
const result = prop.data === "controller" ? new Unit(scope, temp.name) : temp;
|
|
1337
|
+
return [
|
|
1338
|
+
result,
|
|
1339
|
+
[new InstructionBase("sensor", result, this, `@${name}`)],
|
|
1340
|
+
];
|
|
1341
|
+
}
|
|
1342
|
+
if (prop instanceof StoreValue) {
|
|
1343
|
+
const temp = new TempValue(scope);
|
|
1344
|
+
return [temp, [new InstructionBase("sensor", temp, this, prop)]];
|
|
1345
|
+
}
|
|
1346
|
+
throw new Error("Building property acessors must be string literals or stores");
|
|
1347
|
+
}),
|
|
1348
|
+
});
|
|
1349
|
+
this.name = name;
|
|
1350
|
+
}
|
|
1351
|
+
toString() {
|
|
1352
|
+
return this.name;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
for (const key in operatorMap$2) {
|
|
1356
|
+
const kind = operatorMap$2[key];
|
|
1357
|
+
Unit.prototype[key] = function (scope, value) {
|
|
1358
|
+
const left = new StoreValue(scope, this.name);
|
|
1359
|
+
const [right, rightInst] = value.eval(scope);
|
|
1360
|
+
const temp = new TempValue(scope);
|
|
1361
|
+
return [
|
|
1362
|
+
temp,
|
|
1363
|
+
[...rightInst, new OperationInstruction(kind, temp, left, right)],
|
|
1364
|
+
];
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
const validRadarFilters = [
|
|
1369
|
+
"any",
|
|
1370
|
+
"enemy",
|
|
1371
|
+
"ally",
|
|
1372
|
+
"player",
|
|
1373
|
+
"attacker",
|
|
1374
|
+
"flying",
|
|
1375
|
+
"boss",
|
|
1376
|
+
"ground",
|
|
1377
|
+
];
|
|
1378
|
+
const validRadarSorts = [
|
|
1379
|
+
"distance",
|
|
1380
|
+
"health",
|
|
1381
|
+
"shield",
|
|
1382
|
+
"armor",
|
|
1383
|
+
"maxHealth",
|
|
1384
|
+
];
|
|
1385
|
+
class Radar extends MacroFunction {
|
|
1386
|
+
constructor(scope) {
|
|
1387
|
+
super(scope, (building, filter1, filter2, filter3, order, sort) => {
|
|
1388
|
+
if (!(building instanceof ObjectValue))
|
|
1389
|
+
throw new Error("The building must a store");
|
|
1390
|
+
if (!(filter1 instanceof LiteralValue) ||
|
|
1391
|
+
typeof filter1.data !== "string" ||
|
|
1392
|
+
!(filter2 instanceof LiteralValue) ||
|
|
1393
|
+
typeof filter2.data !== "string" ||
|
|
1394
|
+
!(filter3 instanceof LiteralValue) ||
|
|
1395
|
+
typeof filter3.data !== "string")
|
|
1396
|
+
throw new Error("The filters must be string literals");
|
|
1397
|
+
if (!validRadarFilters.includes(filter1.data))
|
|
1398
|
+
throw new Error("Invalid value for filter1");
|
|
1399
|
+
if (!validRadarFilters.includes(filter2.data))
|
|
1400
|
+
throw new Error("Invalid value for filter2");
|
|
1401
|
+
if (!validRadarFilters.includes(filter3.data))
|
|
1402
|
+
throw new Error("Invalid value for filter3");
|
|
1403
|
+
if (!(order instanceof LiteralValue || order instanceof StoreValue))
|
|
1404
|
+
throw new Error("The radar order must be a literal or a store");
|
|
1405
|
+
if (!(sort instanceof LiteralValue) || typeof sort.data !== "string")
|
|
1406
|
+
throw new Error("The radar sort must be a string literal");
|
|
1407
|
+
if (!validRadarSorts.includes(sort.data))
|
|
1408
|
+
throw new Error("Invalid sort value");
|
|
1409
|
+
const temp = new TempValue(scope);
|
|
1410
|
+
const resultUnit = new Unit(scope, temp.name);
|
|
1411
|
+
return [
|
|
1412
|
+
resultUnit,
|
|
1413
|
+
[
|
|
1414
|
+
new InstructionBase("radar", filter1.data, filter2.data, filter3.data, sort.data, building, order, temp),
|
|
1415
|
+
],
|
|
1416
|
+
];
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
class Sensor extends MacroFunction {
|
|
1422
|
+
constructor(scope) {
|
|
1423
|
+
super(scope, (property, target) => {
|
|
1424
|
+
if (!(property instanceof StoreValue))
|
|
1425
|
+
throw new Error("The sensor property must be a store");
|
|
1426
|
+
if (!(target instanceof ObjectValue))
|
|
1427
|
+
throw new Error("The sensor target must be a store");
|
|
1428
|
+
const temp = new TempValue(scope);
|
|
1429
|
+
return [temp, [new InstructionBase("sensor", temp, property, target)]];
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
class Wait extends MacroFunction {
|
|
1435
|
+
constructor(scope) {
|
|
1436
|
+
super(scope, seconds => {
|
|
1437
|
+
if (!(seconds instanceof StoreValue) &&
|
|
1438
|
+
!(seconds instanceof LiteralValue && typeof seconds.data === "number"))
|
|
1439
|
+
throw new Error("The wait seconds must be either a number literal or a store");
|
|
1440
|
+
return [null, [new InstructionBase("wait", seconds)]];
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
const validKinds = ["block", "unit", "item", "liquid"];
|
|
1446
|
+
class Lookup extends MacroFunction {
|
|
1447
|
+
constructor(scope) {
|
|
1448
|
+
super(scope, (kind, index) => {
|
|
1449
|
+
if (!(kind instanceof LiteralValue && typeof kind.data === "string"))
|
|
1450
|
+
throw new Error("The lookup kind must be a string literal");
|
|
1451
|
+
if (!validKinds.includes(kind.data))
|
|
1452
|
+
throw new Error("Invalid lookup kind");
|
|
1453
|
+
if (!(index instanceof LiteralValue && typeof index.data === "number") &&
|
|
1454
|
+
!(index instanceof StoreValue))
|
|
1455
|
+
throw new Error("The lookup index must be a number literal or a store");
|
|
1456
|
+
const temp = new TempValue(scope);
|
|
1457
|
+
return [temp, [new InstructionBase("lookup", kind.data, temp, index)]];
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
class UnitBind extends MacroFunction {
|
|
1463
|
+
constructor(scope) {
|
|
1464
|
+
super(scope, type => {
|
|
1465
|
+
if (!(type instanceof StoreValue))
|
|
1466
|
+
throw new Error("The unitBind type must be a store");
|
|
1467
|
+
return [null, [new InstructionBase("ubind", type)]];
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
const validModes = [
|
|
1473
|
+
"idle",
|
|
1474
|
+
"stop",
|
|
1475
|
+
"move",
|
|
1476
|
+
"approach",
|
|
1477
|
+
"boost",
|
|
1478
|
+
"pathfind",
|
|
1479
|
+
"target",
|
|
1480
|
+
"targetp",
|
|
1481
|
+
"itemDrop",
|
|
1482
|
+
"itemTake",
|
|
1483
|
+
"payDrop",
|
|
1484
|
+
"payTake",
|
|
1485
|
+
"payEnter",
|
|
1486
|
+
"mine",
|
|
1487
|
+
"flag",
|
|
1488
|
+
"build",
|
|
1489
|
+
"getBlock",
|
|
1490
|
+
"within",
|
|
1491
|
+
];
|
|
1492
|
+
class UnitControl extends MacroFunction {
|
|
1493
|
+
constructor(scope) {
|
|
1494
|
+
super(scope, (mode, ...args) => {
|
|
1495
|
+
if (!(mode instanceof LiteralValue) || typeof mode.data !== "string")
|
|
1496
|
+
throw new Error("The unitControl mode must be a string literal");
|
|
1497
|
+
if (!validModes.includes(mode.data))
|
|
1498
|
+
throw new Error("Invalid unitControl mode");
|
|
1499
|
+
if (args.some(value => !(value instanceof StoreValue ||
|
|
1500
|
+
value instanceof LiteralValue ||
|
|
1501
|
+
value instanceof ObjectValue)))
|
|
1502
|
+
throw new Error("The others arguments of unitControl must be literals or stores");
|
|
1503
|
+
let result = null;
|
|
1504
|
+
let extraArgs = [];
|
|
1505
|
+
switch (mode.data) {
|
|
1506
|
+
case "getBlock": {
|
|
1507
|
+
const outType = new TempValue(scope);
|
|
1508
|
+
const outBuilding = new TempValue(scope);
|
|
1509
|
+
result = new ObjectValue(scope, {
|
|
1510
|
+
0: outType,
|
|
1511
|
+
1: new Building(scope, outBuilding.name),
|
|
1512
|
+
length: new LiteralValue(scope, 2),
|
|
1513
|
+
});
|
|
1514
|
+
extraArgs = [outType, outBuilding, new LiteralValue(scope, 0)];
|
|
1515
|
+
break;
|
|
1516
|
+
}
|
|
1517
|
+
case "within": {
|
|
1518
|
+
const temp = new TempValue(scope);
|
|
1519
|
+
result = temp;
|
|
1520
|
+
extraArgs = [temp, new LiteralValue(scope, 0)];
|
|
1521
|
+
break;
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
return [
|
|
1525
|
+
result,
|
|
1526
|
+
[new InstructionBase("ucontrol", mode.data, ...args, ...extraArgs)],
|
|
1527
|
+
];
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
class UnitRadar extends MacroFunction {
|
|
1533
|
+
constructor(scope) {
|
|
1534
|
+
super(scope, (filter1, filter2, filter3, order, sort) => {
|
|
1535
|
+
if (!(filter1 instanceof LiteralValue) ||
|
|
1536
|
+
typeof filter1.data !== "string" ||
|
|
1537
|
+
!(filter2 instanceof LiteralValue) ||
|
|
1538
|
+
typeof filter2.data !== "string" ||
|
|
1539
|
+
!(filter3 instanceof LiteralValue) ||
|
|
1540
|
+
typeof filter3.data !== "string")
|
|
1541
|
+
throw new Error("The filters must be string literals");
|
|
1542
|
+
if (!validRadarFilters.includes(filter1.data))
|
|
1543
|
+
throw new Error("Invalid value for filter1");
|
|
1544
|
+
if (!validRadarFilters.includes(filter2.data))
|
|
1545
|
+
throw new Error("Invalid value for filter2");
|
|
1546
|
+
if (!validRadarFilters.includes(filter3.data))
|
|
1547
|
+
throw new Error("Invalid value for filter3");
|
|
1548
|
+
if (!(order instanceof LiteralValue || order instanceof StoreValue))
|
|
1549
|
+
throw new Error("The radar order must be a literal or a store");
|
|
1550
|
+
if (!(sort instanceof LiteralValue) || typeof sort.data !== "string")
|
|
1551
|
+
throw new Error("The radar sort must be a string literal");
|
|
1552
|
+
if (!validRadarSorts.includes(sort.data))
|
|
1553
|
+
throw new Error("Invalid sort value");
|
|
1554
|
+
const temp = new TempValue(scope);
|
|
1555
|
+
return [
|
|
1556
|
+
temp,
|
|
1557
|
+
[
|
|
1558
|
+
new InstructionBase("uradar", filter1.data, filter2.data, filter3.data, order, sort.data, temp),
|
|
1559
|
+
],
|
|
1560
|
+
];
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
const validFinds = ["ore", "building", "spawn", "damaged"];
|
|
1566
|
+
const validBuildingGroups = [
|
|
1567
|
+
"core",
|
|
1568
|
+
"storage",
|
|
1569
|
+
"generator",
|
|
1570
|
+
"turret",
|
|
1571
|
+
"factory",
|
|
1572
|
+
"repair",
|
|
1573
|
+
"rally",
|
|
1574
|
+
"battery",
|
|
1575
|
+
"reactor",
|
|
1576
|
+
];
|
|
1577
|
+
class UnitLocate extends MacroFunction {
|
|
1578
|
+
constructor(scope) {
|
|
1579
|
+
super(scope, (find, ...args) => {
|
|
1580
|
+
if (!(find instanceof LiteralValue && typeof find.data === "string"))
|
|
1581
|
+
throw new Error("The unitLocate find must be a string literal");
|
|
1582
|
+
if (!validFinds.includes(find.data))
|
|
1583
|
+
throw new Error("Invalid find value");
|
|
1584
|
+
if (args.some(value => !(value instanceof StoreValue || value instanceof LiteralValue)))
|
|
1585
|
+
throw new Error("The others arguments of unitLocate must be literals or stores");
|
|
1586
|
+
const outFound = new TempValue(scope);
|
|
1587
|
+
const outX = new TempValue(scope);
|
|
1588
|
+
const outY = new TempValue(scope);
|
|
1589
|
+
const outBuilding = new TempValue(scope);
|
|
1590
|
+
const outArgs = [outX, outY, outFound, outBuilding];
|
|
1591
|
+
let inputArgs = [];
|
|
1592
|
+
switch (find.data) {
|
|
1593
|
+
case "ore": {
|
|
1594
|
+
const [ore] = args;
|
|
1595
|
+
inputArgs = [find.data, "core", "true", ore];
|
|
1596
|
+
break;
|
|
1597
|
+
}
|
|
1598
|
+
case "building": {
|
|
1599
|
+
const [group, enemy] = args;
|
|
1600
|
+
if (!(group instanceof LiteralValue && typeof group.data === "string")) {
|
|
1601
|
+
throw new Error("The building group must be a string literal");
|
|
1602
|
+
}
|
|
1603
|
+
if (!validBuildingGroups.includes(group.data))
|
|
1604
|
+
throw new Error("Invalid building group");
|
|
1605
|
+
inputArgs = [find.data, group.data, enemy, "@copper"];
|
|
1606
|
+
break;
|
|
1607
|
+
}
|
|
1608
|
+
case "spawn":
|
|
1609
|
+
case "damaged": {
|
|
1610
|
+
inputArgs = [find.data, "core", "true", "@copper"];
|
|
1611
|
+
break;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
return [
|
|
1615
|
+
new ObjectValue(scope, {
|
|
1616
|
+
0: outFound,
|
|
1617
|
+
1: outX,
|
|
1618
|
+
2: outY,
|
|
1619
|
+
3: new Building(scope, outBuilding.name),
|
|
1620
|
+
length: new LiteralValue(scope, find.data === "ore" ? 3 : 4),
|
|
1621
|
+
}),
|
|
1622
|
+
[new InstructionBase("ulocate", ...inputArgs, ...outArgs)],
|
|
1623
|
+
];
|
|
1624
|
+
});
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
var index = /*#__PURE__*/Object.freeze({
|
|
1629
|
+
__proto__: null,
|
|
1630
|
+
Radar: Radar,
|
|
1631
|
+
Draw: Draw,
|
|
1632
|
+
Print: Print,
|
|
1633
|
+
PrintFlush: PrintFlush,
|
|
1634
|
+
DrawFlush: DrawFlush,
|
|
1635
|
+
GetLink: GetLink,
|
|
1636
|
+
Control: Control,
|
|
1637
|
+
Sensor: Sensor,
|
|
1638
|
+
Wait: Wait,
|
|
1639
|
+
Lookup: Lookup,
|
|
1640
|
+
UnitBind: UnitBind,
|
|
1641
|
+
UnitControl: UnitControl,
|
|
1642
|
+
UnitRadar: UnitRadar,
|
|
1643
|
+
UnitLocate: UnitLocate
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
class MemoryEntry extends ObjectValue {
|
|
1647
|
+
constructor(scope, mem, prop) {
|
|
1648
|
+
super(scope, {
|
|
1649
|
+
$eval: new MacroFunction(scope, () => {
|
|
1650
|
+
const temp = new TempValue(scope);
|
|
1651
|
+
return [temp, [new InstructionBase("read", temp, mem.cell, prop)]];
|
|
1652
|
+
}),
|
|
1653
|
+
"$=": new MacroFunction(scope, value => {
|
|
1654
|
+
return [value, [new InstructionBase("write", value, mem.cell, prop)]];
|
|
1655
|
+
}),
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
for (const operator of operators) {
|
|
1660
|
+
if (operator === "=")
|
|
1661
|
+
continue;
|
|
1662
|
+
MemoryEntry.prototype[operator] = function (...args) {
|
|
1663
|
+
return BaseValue.prototype[operator].apply(this, args);
|
|
1664
|
+
};
|
|
1665
|
+
}
|
|
1666
|
+
class MemoryMacro extends ObjectValue {
|
|
1667
|
+
constructor(scope, cell, size) {
|
|
1668
|
+
super(scope, {
|
|
1669
|
+
$get: new MacroFunction(scope, (prop) => {
|
|
1670
|
+
if (prop instanceof LiteralValue && typeof prop.data !== "number")
|
|
1671
|
+
throw new Error(`Invalid memory object property: "${prop.data}"`);
|
|
1672
|
+
const obj = new MemoryEntry(scope, this, prop);
|
|
1673
|
+
return [obj, []];
|
|
1674
|
+
}),
|
|
1675
|
+
length: size,
|
|
1676
|
+
size,
|
|
1677
|
+
});
|
|
1678
|
+
this.cell = cell;
|
|
1679
|
+
this.name = cell.toString();
|
|
1680
|
+
}
|
|
1681
|
+
toString() {
|
|
1682
|
+
return this.name;
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
class MemoryBuilder extends ObjectValue {
|
|
1686
|
+
constructor(scope) {
|
|
1687
|
+
super(scope, {
|
|
1688
|
+
$call: new MacroFunction(scope, (cell, size = new LiteralValue(scope, 64)) => {
|
|
1689
|
+
if (!(cell instanceof ObjectValue))
|
|
1690
|
+
throw new Error("Memory cell must be a building object.");
|
|
1691
|
+
if (!(size instanceof LiteralValue && typeof size.data === "number"))
|
|
1692
|
+
throw new Error("The memory size must be a number literal.");
|
|
1693
|
+
return [new MemoryMacro(scope, cell, size), []];
|
|
1694
|
+
}),
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
class RawValueMacro extends MacroFunction {
|
|
1700
|
+
constructor(scope) {
|
|
1701
|
+
super(scope, (name) => {
|
|
1702
|
+
if (!(name instanceof LiteralValue) || typeof name.data !== "string")
|
|
1703
|
+
throw new Error("The name of the building must be a string literal.");
|
|
1704
|
+
return [new StoreValue(scope, name.data), []];
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
function initScope(scope) {
|
|
1710
|
+
// namespaces
|
|
1711
|
+
scope.hardSet("ControlKind", new NamespaceMacro(scope));
|
|
1712
|
+
scope.hardSet("Vars", new VarsNamespace(scope));
|
|
1713
|
+
scope.hardSet("Items", new NamespaceMacro(scope, { changeCasing: true }));
|
|
1714
|
+
scope.hardSet("Liquids", new NamespaceMacro(scope));
|
|
1715
|
+
scope.hardSet("Units", new NamespaceMacro(scope));
|
|
1716
|
+
scope.hardSet("LAccess", new NamespaceMacro(scope));
|
|
1717
|
+
scope.hardSet("UnitCommands", new UCommandsNamespace(scope));
|
|
1718
|
+
scope.hardSet("Blocks", new NamespaceMacro(scope, { changeCasing: true }));
|
|
1719
|
+
// helper methods
|
|
1720
|
+
scope.hardSet("getBuilding", new BuildingBuilder(scope));
|
|
1721
|
+
scope.hardSet("getVar", new RawValueMacro(scope));
|
|
1722
|
+
scope.hardSet("concat", new Concat(scope));
|
|
1723
|
+
scope.hardSet("Math", new MlogMath(scope));
|
|
1724
|
+
scope.hardSet("Memory", new MemoryBuilder(scope));
|
|
1725
|
+
// commands
|
|
1726
|
+
scope.hardSet("draw", new Draw(scope));
|
|
1727
|
+
scope.hardSet("print", new Print(scope));
|
|
1728
|
+
scope.hardSet("printFlush", new PrintFlush(scope));
|
|
1729
|
+
scope.hardSet("drawFlush", new DrawFlush(scope));
|
|
1730
|
+
scope.hardSet("getLink", new GetLink(scope));
|
|
1731
|
+
scope.hardSet("control", new Control(scope));
|
|
1732
|
+
scope.hardSet("radar", new Radar(scope));
|
|
1733
|
+
scope.hardSet("sensor", new Sensor(scope));
|
|
1734
|
+
scope.hardSet("wait", new Wait(scope));
|
|
1735
|
+
scope.hardSet("lookup", new Lookup(scope));
|
|
1736
|
+
scope.hardSet("unitBind", new UnitBind(scope));
|
|
1737
|
+
scope.hardSet("unitControl", new UnitControl(scope));
|
|
1738
|
+
scope.hardSet("unitRadar", new UnitRadar(scope));
|
|
1739
|
+
scope.hardSet("unitLocate", new UnitLocate(scope));
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
class Compiler {
|
|
1743
|
+
constructor(stackName) {
|
|
1744
|
+
this.handlers = handlers;
|
|
1745
|
+
this.usingStack = !!stackName;
|
|
1746
|
+
this.stackName = stackName;
|
|
1747
|
+
}
|
|
1748
|
+
compile(script) {
|
|
1749
|
+
let output;
|
|
1750
|
+
try {
|
|
1751
|
+
const program = this.parse(script);
|
|
1752
|
+
const scope = new Scope({});
|
|
1753
|
+
initScope(scope);
|
|
1754
|
+
const valueInst = this.handle(scope, program);
|
|
1755
|
+
valueInst[1].push(new EndInstruction(), ...scope.inst);
|
|
1756
|
+
this.resolve(valueInst);
|
|
1757
|
+
output = this.serialize(valueInst) + "\n";
|
|
1758
|
+
}
|
|
1759
|
+
catch (error) {
|
|
1760
|
+
return [null, error, error?.nodeStack ?? []];
|
|
1761
|
+
}
|
|
1762
|
+
return [output, null, []];
|
|
1763
|
+
}
|
|
1764
|
+
resolve(valueInst) {
|
|
1765
|
+
let i = 0;
|
|
1766
|
+
for (const inst of valueInst[1]) {
|
|
1767
|
+
inst.resolve(i);
|
|
1768
|
+
if (!inst.hidden)
|
|
1769
|
+
i++;
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
serialize(resLines) {
|
|
1773
|
+
const [_, inst] = resLines;
|
|
1774
|
+
return inst.filter(l => !l.hidden).join("\n");
|
|
1775
|
+
}
|
|
1776
|
+
parse(script) {
|
|
1777
|
+
return parse(script, {
|
|
1778
|
+
locations: true,
|
|
1779
|
+
ecmaVersion: "latest",
|
|
1780
|
+
});
|
|
1781
|
+
}
|
|
1782
|
+
handle(scope, node) {
|
|
1783
|
+
try {
|
|
1784
|
+
const handler = this.handlers[node.type];
|
|
1785
|
+
if (!handler)
|
|
1786
|
+
throw Error("Missing handler for " + node.type);
|
|
1787
|
+
return handler(this, scope, node, null);
|
|
1788
|
+
}
|
|
1789
|
+
catch (error) {
|
|
1790
|
+
error.nodeStack ??= [];
|
|
1791
|
+
error.nodeStack.push(node);
|
|
1792
|
+
throw error;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
handleEval(scope, node) {
|
|
1796
|
+
const [res, inst] = this.handle(scope, node);
|
|
1797
|
+
const [evaluated, evaluatedLines] = res.eval(scope);
|
|
1798
|
+
return [evaluated, [...inst, ...evaluatedLines]];
|
|
1799
|
+
}
|
|
1800
|
+
handleMany(scope, nodes, handler = this.handle.bind(this)) {
|
|
1801
|
+
const lines = [];
|
|
1802
|
+
for (const node of nodes) {
|
|
1803
|
+
const [_, nodeLines] = handler(scope, node);
|
|
1804
|
+
lines.push(...nodeLines);
|
|
1805
|
+
}
|
|
1806
|
+
return [null, lines];
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
const compiler = new Compiler();
|
|
1811
|
+
const compile = (script) => compiler.compile(script);
|
|
1812
|
+
|
|
1813
|
+
export { compile };
|