@markw65/monkeyc-optimizer 1.0.9 → 1.0.12
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/README.md +31 -0
- package/build/api.cjs +1149 -1061
- package/build/optimizer.cjs +4890 -1863
- package/build/sdk-util.cjs +36 -37
- package/build/src/api.d.ts +8 -0
- package/build/src/build.d.ts +6 -0
- package/build/src/estree-types.d.ts +324 -0
- package/build/src/jungles.d.ts +51 -0
- package/build/src/launch.d.ts +2 -0
- package/build/src/manifest.d.ts +71 -0
- package/build/src/mc-rewrite.d.ts +7 -0
- package/build/src/negative-fixups.d.ts +1 -0
- package/build/src/optimizer.d.ts +177 -0
- package/build/src/sdk-util.d.ts +14 -0
- package/build/src/util.d.ts +14 -0
- package/build/util.cjs +121 -109
- package/package.json +11 -3
package/build/api.cjs
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
0 && (module.exports = {
|
|
1
|
+
0 && (module.exports = {getApiMapping,hasProperty,isStateNode,variableDeclarationName,collectNamespaces,traverseAst,formatAst});
|
|
2
2
|
/******/ (() => { // webpackBootstrap
|
|
3
3
|
/******/ "use strict";
|
|
4
4
|
/******/ // The require scope
|
|
5
5
|
/******/ var __webpack_require__ = {};
|
|
6
6
|
/******/
|
|
7
7
|
/************************************************************************/
|
|
8
|
+
/******/ /* webpack/runtime/compat get default export */
|
|
9
|
+
/******/ (() => {
|
|
10
|
+
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
11
|
+
/******/ __webpack_require__.n = (module) => {
|
|
12
|
+
/******/ var getter = module && module.__esModule ?
|
|
13
|
+
/******/ () => (module['default']) :
|
|
14
|
+
/******/ () => (module);
|
|
15
|
+
/******/ __webpack_require__.d(getter, { a: getter });
|
|
16
|
+
/******/ return getter;
|
|
17
|
+
/******/ };
|
|
18
|
+
/******/ })();
|
|
19
|
+
/******/
|
|
8
20
|
/******/ /* webpack/runtime/define property getters */
|
|
9
21
|
/******/ (() => {
|
|
10
22
|
/******/ // define getter functions for harmony exports
|
|
@@ -40,772 +52,827 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
40
52
|
|
|
41
53
|
// EXPORTS
|
|
42
54
|
__webpack_require__.d(__webpack_exports__, {
|
|
43
|
-
"LiteralIntegerRe": () => (/* binding */ api_LiteralIntegerRe),
|
|
44
55
|
"collectNamespaces": () => (/* binding */ api_collectNamespaces),
|
|
45
56
|
"formatAst": () => (/* binding */ formatAst),
|
|
46
57
|
"getApiMapping": () => (/* binding */ api_getApiMapping),
|
|
47
58
|
"hasProperty": () => (/* binding */ api_hasProperty),
|
|
48
|
-
"
|
|
59
|
+
"isStateNode": () => (/* binding */ api_isStateNode),
|
|
60
|
+
"traverseAst": () => (/* binding */ api_traverseAst),
|
|
61
|
+
"variableDeclarationName": () => (/* binding */ api_variableDeclarationName)
|
|
49
62
|
});
|
|
50
63
|
|
|
51
64
|
;// CONCATENATED MODULE: external "@markw65/prettier-plugin-monkeyc"
|
|
52
65
|
const prettier_plugin_monkeyc_namespaceObject = require("@markw65/prettier-plugin-monkeyc");
|
|
66
|
+
var prettier_plugin_monkeyc_default = /*#__PURE__*/__webpack_require__.n(prettier_plugin_monkeyc_namespaceObject);
|
|
53
67
|
;// CONCATENATED MODULE: external "fs/promises"
|
|
54
68
|
const promises_namespaceObject = require("fs/promises");
|
|
55
69
|
;// CONCATENATED MODULE: external "prettier/standalone.js"
|
|
56
70
|
const standalone_js_namespaceObject = require("prettier/standalone.js");
|
|
71
|
+
var standalone_js_default = /*#__PURE__*/__webpack_require__.n(standalone_js_namespaceObject);
|
|
57
72
|
;// CONCATENATED MODULE: external "./api.cjs"
|
|
58
73
|
const external_api_cjs_namespaceObject = require("./api.cjs");
|
|
59
74
|
;// CONCATENATED MODULE: external "./util.cjs"
|
|
60
75
|
const external_util_cjs_namespaceObject = require("./util.cjs");
|
|
61
|
-
;// CONCATENATED MODULE: ./src/mc-rewrite.
|
|
62
|
-
|
|
76
|
+
;// CONCATENATED MODULE: ./src/mc-rewrite.ts
|
|
63
77
|
|
|
64
78
|
|
|
65
79
|
|
|
66
80
|
|
|
67
81
|
function processImports(allImports, lookup) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
allImports.forEach(({ node, stack }) => {
|
|
83
|
+
const [name, module] = lookup(node.id, "as" in node && node.as && node.as.name, stack);
|
|
84
|
+
if (name && module) {
|
|
85
|
+
const [parent] = stack.slice(-1);
|
|
86
|
+
if (!parent.decls)
|
|
87
|
+
parent.decls = {};
|
|
88
|
+
if (!hasProperty(parent.decls, name))
|
|
89
|
+
parent.decls[name] = [];
|
|
90
|
+
module.forEach((m) => {
|
|
91
|
+
if (isStateNode(m) && m.type == "ModuleDeclaration") {
|
|
92
|
+
pushUnique(parent.decls[name], m);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
77
95
|
}
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
});
|
|
96
|
+
});
|
|
81
97
|
}
|
|
82
|
-
|
|
83
98
|
function collectClassInfo(state) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
state.allClasses.forEach((elm) => {
|
|
100
|
+
if (elm.node.superClass) {
|
|
101
|
+
const [, classes] = state.lookup(elm.node.superClass, null, elm.stack);
|
|
102
|
+
const superClass = classes &&
|
|
103
|
+
classes.filter((c) => isStateNode(c) && c.type === "ClassDeclaration");
|
|
104
|
+
// set it "true" if there is a superClass, but we can't find it.
|
|
105
|
+
elm.superClass = superClass && superClass.length ? superClass : true;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
const markOverrides = (cls, scls) => {
|
|
109
|
+
if (scls === true)
|
|
110
|
+
return;
|
|
111
|
+
scls.forEach((c) => {
|
|
112
|
+
c.decls &&
|
|
113
|
+
Object.values(c.decls).forEach((funcs) => {
|
|
114
|
+
funcs.forEach((f) => {
|
|
115
|
+
if (isStateNode(f) &&
|
|
116
|
+
f.type === "FunctionDeclaration" &&
|
|
117
|
+
hasProperty(cls.decls, f.name)) {
|
|
118
|
+
f.node.hasOverride = true;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
if (c.superClass)
|
|
123
|
+
markOverrides(cls, c.superClass);
|
|
105
124
|
});
|
|
106
|
-
|
|
125
|
+
};
|
|
126
|
+
state.allClasses.forEach((elm) => {
|
|
127
|
+
if (elm.superClass)
|
|
128
|
+
markOverrides(elm, elm.superClass);
|
|
107
129
|
});
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
state.allClasses.forEach((elm) => {
|
|
111
|
-
if (elm.superClass) markOverrides(elm, elm.superClass);
|
|
112
|
-
});
|
|
113
130
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
switch (node.type) {
|
|
140
|
-
case "FunctionDeclaration":
|
|
141
|
-
case "ClassDeclaration": {
|
|
142
|
-
const [scope] = state.stack.slice(-1);
|
|
143
|
-
const stack = state.stack.slice(0, -1);
|
|
144
|
-
scope.stack = stack;
|
|
145
|
-
(node.type == "FunctionDeclaration"
|
|
146
|
-
? state.allFunctions
|
|
147
|
-
: state.allClasses
|
|
148
|
-
).push(scope);
|
|
149
|
-
return;
|
|
131
|
+
function getFileSources(fnMap) {
|
|
132
|
+
return Promise.all(Object.entries(fnMap).map(([name, value]) => {
|
|
133
|
+
return (value.monkeyCSource ||
|
|
134
|
+
fs
|
|
135
|
+
.readFile(name)
|
|
136
|
+
.then((data) => (value.monkeyCSource = data.toString().replace(/\r\n/g, "\n"))));
|
|
137
|
+
})).then(() => { });
|
|
138
|
+
}
|
|
139
|
+
function getFileASTs(fnMap) {
|
|
140
|
+
return getFileSources(fnMap).then(() => Object.entries(fnMap).reduce((ok, [name, value]) => {
|
|
141
|
+
if (!value.ast) {
|
|
142
|
+
try {
|
|
143
|
+
value.ast = MonkeyC.parsers.monkeyc.parse(value.monkeyCSource, null, {
|
|
144
|
+
filepath: name,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
ok = false;
|
|
149
|
+
if (e instanceof Error) {
|
|
150
|
+
value.parserError = e;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
value.parserError = new Error("An unknown parser error occurred");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
150
156
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
allImports.push({ node, stack: state.stack.slice() });
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
await getApiMapping(state);
|
|
160
|
-
|
|
161
|
-
// Mark all functions from api.mir as "special" by
|
|
162
|
-
// setting their bodies to null. In api.mir, they're
|
|
163
|
-
// all empty, which makes it look like they're
|
|
164
|
-
// do-nothing functions.
|
|
165
|
-
const markApi = (node) => {
|
|
166
|
-
if (node.type == "FunctionDeclaration") {
|
|
167
|
-
node.node.body = null;
|
|
168
|
-
}
|
|
169
|
-
if (node.decls) {
|
|
170
|
-
Object.values(node.decls).forEach(markApi);
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
markApi(state.stack[0]);
|
|
174
|
-
|
|
175
|
-
const files = await Promise.all(
|
|
176
|
-
fileNames.map(async (name) => ({
|
|
177
|
-
name,
|
|
178
|
-
monkeyCSource: (await fs.readFile(name))
|
|
179
|
-
.toString()
|
|
180
|
-
.replace(/\r\n/g, "\n"),
|
|
181
|
-
}))
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
files.forEach((f) => {
|
|
185
|
-
f.ast = MonkeyC.parsers.monkeyc.parse(f.monkeyCSource, {
|
|
186
|
-
grammarSource: f.name,
|
|
187
|
-
});
|
|
188
|
-
f.ast.source = f.name;
|
|
189
|
-
f.ast.monkeyCSource = f.monkeyCSource;
|
|
190
|
-
delete f.monkeyCSource;
|
|
191
|
-
collectNamespaces(f.ast, state);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
delete state.shouldExclude;
|
|
195
|
-
delete state.post;
|
|
196
|
-
|
|
197
|
-
processImports(allImports, state.lookup);
|
|
198
|
-
collectClassInfo(state);
|
|
199
|
-
|
|
200
|
-
return { files, state };
|
|
157
|
+
return ok;
|
|
158
|
+
}, true));
|
|
201
159
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
160
|
+
async function analyze(fnMap) {
|
|
161
|
+
let excludeAnnotations;
|
|
162
|
+
let hasTests = false;
|
|
163
|
+
const allImports = [];
|
|
164
|
+
const state = {
|
|
165
|
+
allFunctions: [],
|
|
166
|
+
allClasses: [],
|
|
167
|
+
shouldExclude(node) {
|
|
168
|
+
if ("attrs" in node &&
|
|
169
|
+
node.attrs &&
|
|
170
|
+
"attrs" in node.attrs &&
|
|
171
|
+
node.attrs.attrs) {
|
|
172
|
+
return node.attrs.attrs.reduce((drop, attr) => {
|
|
173
|
+
if (attr.type != "UnaryExpression")
|
|
174
|
+
return drop;
|
|
175
|
+
if (attr.argument.type != "Identifier")
|
|
176
|
+
return drop;
|
|
177
|
+
if (hasProperty(excludeAnnotations, attr.argument.name)) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
if (attr.argument.name == "test") {
|
|
181
|
+
hasTests = true;
|
|
182
|
+
}
|
|
183
|
+
return drop;
|
|
184
|
+
}, false);
|
|
185
|
+
}
|
|
186
|
+
return null;
|
|
187
|
+
},
|
|
188
|
+
post(node) {
|
|
189
|
+
switch (node.type) {
|
|
190
|
+
case "FunctionDeclaration":
|
|
191
|
+
case "ClassDeclaration": {
|
|
192
|
+
const [scope] = state.stack.slice(-1);
|
|
193
|
+
const stack = state.stack.slice(0, -1);
|
|
194
|
+
scope.stack = stack;
|
|
195
|
+
if (scope.type == "FunctionDeclaration") {
|
|
196
|
+
state.allFunctions.push(scope);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
state.allClasses.push(scope);
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
case "Using":
|
|
204
|
+
case "ImportModule":
|
|
205
|
+
allImports.push({ node, stack: state.stack.slice() });
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
await getApiMapping(state);
|
|
211
|
+
// Mark all functions from api.mir as "special" by
|
|
212
|
+
// setting their bodies to null. In api.mir, they're
|
|
213
|
+
// all empty, which makes it look like they're
|
|
214
|
+
// do-nothing functions.
|
|
215
|
+
const markApi = (node) => {
|
|
216
|
+
if (node.type == "FunctionDeclaration") {
|
|
217
|
+
node.node.body = null;
|
|
216
218
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
) {
|
|
220
|
-
return result;
|
|
221
|
-
}
|
|
222
|
-
return null;
|
|
223
|
-
}
|
|
224
|
-
if (node.type == "Literal") return node;
|
|
225
|
-
if (node.type == "BinaryExpression" && node.operator == "as") {
|
|
226
|
-
return getLiteralNode(node.left) && node;
|
|
227
|
-
}
|
|
228
|
-
if (node.type == "UnaryExpression") {
|
|
229
|
-
if (node.argument.type != "Literal") return null;
|
|
230
|
-
switch (node.operator) {
|
|
231
|
-
case "-":
|
|
232
|
-
if (typeof node.argument.value == "number") {
|
|
233
|
-
return {
|
|
234
|
-
...node.argument,
|
|
235
|
-
value: -node.argument.value,
|
|
236
|
-
raw: "-" + node.argument.value,
|
|
237
|
-
enumType: node.enumType,
|
|
238
|
-
};
|
|
219
|
+
if ("decls" in node) {
|
|
220
|
+
Object.values(node.decls).forEach((v) => v.forEach(markApi));
|
|
239
221
|
}
|
|
240
|
-
}
|
|
241
|
-
|
|
222
|
+
};
|
|
223
|
+
markApi(state.stack[0]);
|
|
224
|
+
await getFileASTs(fnMap);
|
|
225
|
+
Object.entries(fnMap).forEach(([name, value]) => {
|
|
226
|
+
const { ast, parserError } = value;
|
|
227
|
+
if (!ast) {
|
|
228
|
+
throw parserError || new Error(`Failed to parse ${name}`);
|
|
229
|
+
}
|
|
230
|
+
excludeAnnotations = value.excludeAnnotations;
|
|
231
|
+
hasTests = false;
|
|
232
|
+
collectNamespaces(ast, state);
|
|
233
|
+
value.hasTests = hasTests;
|
|
234
|
+
});
|
|
235
|
+
delete state.shouldExclude;
|
|
236
|
+
delete state.post;
|
|
237
|
+
processImports(allImports, state.lookup);
|
|
238
|
+
collectClassInfo(state);
|
|
239
|
+
return state;
|
|
242
240
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
node.right.ts.length == 1 &&
|
|
250
|
-
typeof node.right.ts[0] == "string"
|
|
251
|
-
) {
|
|
252
|
-
// this is a cast we inserted to retain the type of an enum
|
|
253
|
-
// any arithmetic on it will revert to "Number", or "Long",
|
|
254
|
-
// so just ignore it.
|
|
255
|
-
return getNodeValue(node.left);
|
|
256
|
-
}
|
|
257
|
-
if (node.type != "Literal") {
|
|
258
|
-
return [null, null];
|
|
259
|
-
}
|
|
260
|
-
let type = node.value === null ? "Null" : typeof node.value;
|
|
261
|
-
if (type === "number") {
|
|
262
|
-
const match = LiteralIntegerRe.exec(node.raw);
|
|
263
|
-
if (match) {
|
|
264
|
-
type = match[2] == "l" ? "Long" : "Number";
|
|
265
|
-
} else if (node.raw.endsWith("d")) {
|
|
266
|
-
type = "Double";
|
|
267
|
-
} else {
|
|
268
|
-
type = "Float";
|
|
269
|
-
}
|
|
270
|
-
} else if (type === "string") {
|
|
271
|
-
type = "String";
|
|
272
|
-
} else if (type === "boolean") {
|
|
273
|
-
type = "Boolean";
|
|
274
|
-
} else {
|
|
275
|
-
type = "Unknown";
|
|
276
|
-
}
|
|
277
|
-
return [node, type];
|
|
241
|
+
function compareLiteralLike(a, b) {
|
|
242
|
+
while (a.type === "BinaryExpression")
|
|
243
|
+
a = a.left;
|
|
244
|
+
while (b.type === "BinaryExpression")
|
|
245
|
+
b = b.left;
|
|
246
|
+
return a.type === "Literal" && b.type === "Literal" && a.value === b.value;
|
|
278
247
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if (type === "Number" || type === "Long") {
|
|
293
|
-
return {
|
|
294
|
-
...arg,
|
|
295
|
-
value: -arg.value,
|
|
296
|
-
raw: (-arg.value).toString() + (type === "Long" ? "l" : ""),
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
break;
|
|
300
|
-
case "!":
|
|
301
|
-
case "~":
|
|
302
|
-
{
|
|
303
|
-
let value;
|
|
304
|
-
if (type === "Number" || type === "Long") {
|
|
305
|
-
value = -arg.value - 1;
|
|
306
|
-
} else if (type === "Boolean" && node.operator == "!") {
|
|
307
|
-
value = !arg.value;
|
|
248
|
+
function getLiteralFromDecls(decls) {
|
|
249
|
+
if (!decls.length)
|
|
250
|
+
return null;
|
|
251
|
+
let result = null;
|
|
252
|
+
if (decls.every((d) => {
|
|
253
|
+
if (d.type === "EnumStringMember" ||
|
|
254
|
+
(d.type === "VariableDeclarator" && d.kind === "const")) {
|
|
255
|
+
const init = getLiteralNode(d.init);
|
|
256
|
+
if (!init)
|
|
257
|
+
return false;
|
|
258
|
+
if (!result) {
|
|
259
|
+
result = init;
|
|
260
|
+
return true;
|
|
308
261
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
...arg,
|
|
312
|
-
value,
|
|
313
|
-
raw: value.toString() + (type === "Long" ? "l" : ""),
|
|
314
|
-
};
|
|
262
|
+
else {
|
|
263
|
+
return compareLiteralLike(init, result);
|
|
315
264
|
}
|
|
316
|
-
}
|
|
317
|
-
break;
|
|
318
|
-
}
|
|
319
|
-
break;
|
|
320
|
-
}
|
|
321
|
-
case "BinaryExpression": {
|
|
322
|
-
const operators = {
|
|
323
|
-
"+": (left, right) => left + right,
|
|
324
|
-
"-": (left, right) => left - right,
|
|
325
|
-
"*": (left, right) => left * right,
|
|
326
|
-
"/": (left, right) => Math.trunc(left / right),
|
|
327
|
-
"%": (left, right) => left % right,
|
|
328
|
-
"&": (left, right, type) => (type === "Number" ? left & right : null),
|
|
329
|
-
"|": (left, right, type) => (type === "Number" ? left | right : null),
|
|
330
|
-
"<<": (left, right, type) => (type === "Number" ? left << right : null),
|
|
331
|
-
">>": (left, right, type) => (type === "Number" ? left >> right : null),
|
|
332
|
-
};
|
|
333
|
-
const op = operators[node.operator];
|
|
334
|
-
if (op) {
|
|
335
|
-
const [left, left_type] = getNodeValue(node.left);
|
|
336
|
-
const [right, right_type] = getNodeValue(node.right);
|
|
337
|
-
if (!left || !right) break;
|
|
338
|
-
if (
|
|
339
|
-
left_type != right_type ||
|
|
340
|
-
(left_type != "Number" && left_type != "Long")
|
|
341
|
-
) {
|
|
342
|
-
break;
|
|
343
265
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
return
|
|
347
|
-
...left,
|
|
348
|
-
value,
|
|
349
|
-
raw: value.toString() + (left_type === "Long" ? "l" : ""),
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
break;
|
|
266
|
+
return false;
|
|
267
|
+
})) {
|
|
268
|
+
return result;
|
|
353
269
|
}
|
|
354
|
-
|
|
355
|
-
if (node.body && evaluateFunction(node, null) !== false) {
|
|
356
|
-
node.optimizable = true;
|
|
357
|
-
}
|
|
358
|
-
break;
|
|
359
|
-
}
|
|
270
|
+
return null;
|
|
360
271
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
case "Identifier":
|
|
381
|
-
return;
|
|
382
|
-
default:
|
|
383
|
-
throw new Error("Bad node type");
|
|
272
|
+
function getLiteralNode(node) {
|
|
273
|
+
if (node.type == "Literal")
|
|
274
|
+
return node;
|
|
275
|
+
if (node.type == "BinaryExpression" && node.operator == "as") {
|
|
276
|
+
return getLiteralNode(node.left) && node;
|
|
277
|
+
}
|
|
278
|
+
if (node.type == "UnaryExpression") {
|
|
279
|
+
if (node.argument.type != "Literal")
|
|
280
|
+
return null;
|
|
281
|
+
switch (node.operator) {
|
|
282
|
+
case "-":
|
|
283
|
+
if (typeof node.argument.value == "number") {
|
|
284
|
+
return {
|
|
285
|
+
...node.argument,
|
|
286
|
+
value: -node.argument.value,
|
|
287
|
+
raw: "-" + node.argument.value,
|
|
288
|
+
enumType: node.enumType,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
384
291
|
}
|
|
385
|
-
},
|
|
386
|
-
args &&
|
|
387
|
-
((node) => {
|
|
388
|
-
switch (node.type) {
|
|
389
|
-
case "ReturnStatement":
|
|
390
|
-
ret = node.argument;
|
|
391
|
-
return;
|
|
392
|
-
case "BlockStatement":
|
|
393
|
-
case "Literal":
|
|
394
|
-
return;
|
|
395
|
-
case "Identifier":
|
|
396
|
-
if (hasProperty(paramValues, node.name)) {
|
|
397
|
-
return paramValues[node.name];
|
|
398
|
-
}
|
|
399
|
-
// fall through;
|
|
400
|
-
default: {
|
|
401
|
-
const repl = optimizeNode(node);
|
|
402
|
-
if (repl && repl.type === "Literal") return repl;
|
|
403
|
-
throw new Error("Didn't optimize");
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
})
|
|
407
|
-
);
|
|
408
|
-
return ret;
|
|
409
|
-
} catch (e) {
|
|
410
|
-
return false;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
async function optimizeMonkeyC(fileNames, buildConfig) {
|
|
415
|
-
const { files, state } = await analyze(fileNames, buildConfig);
|
|
416
|
-
const replace = (node, obj) => {
|
|
417
|
-
for (const k of Object.keys(node)) {
|
|
418
|
-
delete node[k];
|
|
419
292
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
right
|
|
426
|
-
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
function getNodeValue(node) {
|
|
296
|
+
if (node.type == "BinaryExpression" &&
|
|
297
|
+
node.operator == "as" &&
|
|
298
|
+
node.right.type == "TypeSpecList" &&
|
|
299
|
+
node.right.ts.length == 1 &&
|
|
300
|
+
typeof node.right.ts[0] == "string") {
|
|
301
|
+
// this is a cast we inserted to retain the type of an enum
|
|
302
|
+
// any arithmetic on it will revert to "Number", or "Long",
|
|
303
|
+
// so just ignore it.
|
|
304
|
+
return getNodeValue(node.left);
|
|
427
305
|
}
|
|
428
|
-
|
|
429
|
-
|
|
306
|
+
if (node.type != "Literal") {
|
|
307
|
+
return [null, null];
|
|
430
308
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
309
|
+
let type = node.value === null ? "Null" : typeof node.value;
|
|
310
|
+
if (type === "number") {
|
|
311
|
+
const match = LiteralIntegerRe.exec(node.raw);
|
|
312
|
+
if (match) {
|
|
313
|
+
type = match[2] == "l" ? "Long" : "Number";
|
|
314
|
+
}
|
|
315
|
+
else if (node.raw.endsWith("d")) {
|
|
316
|
+
type = "Double";
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
type = "Float";
|
|
320
|
+
}
|
|
436
321
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
return false;
|
|
322
|
+
else if (type === "string") {
|
|
323
|
+
type = "String";
|
|
440
324
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
};
|
|
444
|
-
|
|
445
|
-
/*
|
|
446
|
-
* Might this function be called from somewhere, including
|
|
447
|
-
* callbacks from the api (eg getSettingsView, etc).
|
|
448
|
-
*/
|
|
449
|
-
const maybeCalled = (func) => {
|
|
450
|
-
if (!func.body) {
|
|
451
|
-
// this is an api.mir function. It can be called
|
|
452
|
-
return true;
|
|
325
|
+
else if (type === "boolean") {
|
|
326
|
+
type = "Boolean";
|
|
453
327
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
return (
|
|
457
|
-
state.calledFunctions[func.id.name].find((f) => f === func) !== null
|
|
458
|
-
);
|
|
328
|
+
else {
|
|
329
|
+
type = "Unknown";
|
|
459
330
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
* anywhere in its superClass chain.
|
|
464
|
-
*/
|
|
465
|
-
const checkInherited = (elm, name) =>
|
|
466
|
-
elm.superClass === true ||
|
|
467
|
-
elm.superClass.some(
|
|
468
|
-
(sc) =>
|
|
469
|
-
(hasProperty(sc.decls, name) &&
|
|
470
|
-
sc.decls[name].some(
|
|
471
|
-
(f) => f.type == "FunctionDeclaration" && maybeCalled(f)
|
|
472
|
-
)) ||
|
|
473
|
-
(sc.superClass && checkInherited(sc, name))
|
|
474
|
-
);
|
|
475
|
-
|
|
476
|
-
state.localsStack = [{}];
|
|
477
|
-
state.exposed = {};
|
|
478
|
-
state.calledFunctions = {};
|
|
479
|
-
state.pre = (node) => {
|
|
331
|
+
return [node, type];
|
|
332
|
+
}
|
|
333
|
+
function optimizeNode(node) {
|
|
480
334
|
switch (node.type) {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
335
|
+
case "UnaryExpression": {
|
|
336
|
+
const [arg, type] = getNodeValue(node.argument);
|
|
337
|
+
if (arg === null)
|
|
338
|
+
break;
|
|
339
|
+
switch (node.operator) {
|
|
340
|
+
case "+":
|
|
341
|
+
if (type === "Number" || type === "Long") {
|
|
342
|
+
return arg;
|
|
343
|
+
}
|
|
344
|
+
break;
|
|
345
|
+
case "-":
|
|
346
|
+
if (type === "Number" || type === "Long") {
|
|
347
|
+
return {
|
|
348
|
+
...arg,
|
|
349
|
+
value: -arg.value,
|
|
350
|
+
raw: (-arg.value).toString() + (type === "Long" ? "l" : ""),
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
break;
|
|
354
|
+
case "!":
|
|
355
|
+
case "~":
|
|
356
|
+
{
|
|
357
|
+
let value;
|
|
358
|
+
if (type === "Number" || type === "Long") {
|
|
359
|
+
value = -arg.value - 1;
|
|
360
|
+
}
|
|
361
|
+
else if (type === "Boolean" && node.operator == "!") {
|
|
362
|
+
value = !arg.value;
|
|
363
|
+
}
|
|
364
|
+
if (value !== undefined) {
|
|
365
|
+
return {
|
|
366
|
+
...arg,
|
|
367
|
+
value,
|
|
368
|
+
raw: value.toString() + (type === "Long" ? "l" : ""),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
break;
|
|
519
373
|
}
|
|
520
|
-
|
|
374
|
+
break;
|
|
521
375
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
376
|
+
case "BinaryExpression": {
|
|
377
|
+
const operators = {
|
|
378
|
+
"+": (left, right) => left + right,
|
|
379
|
+
"-": (left, right) => left - right,
|
|
380
|
+
"*": (left, right) => left * right,
|
|
381
|
+
"/": (left, right) => Math.trunc(left / right),
|
|
382
|
+
"%": (left, right) => left % right,
|
|
383
|
+
"&": (left, right, type) => type === "Number" ? left & right : null,
|
|
384
|
+
"|": (left, right, type) => type === "Number" ? left | right : null,
|
|
385
|
+
"<<": (left, right, type) => type === "Number" ? left << right : null,
|
|
386
|
+
">>": (left, right, type) => type === "Number" ? left >> right : null,
|
|
387
|
+
};
|
|
388
|
+
const op = operators[node.operator];
|
|
389
|
+
if (op) {
|
|
390
|
+
const [left, left_type] = getNodeValue(node.left);
|
|
391
|
+
const [right, right_type] = getNodeValue(node.right);
|
|
392
|
+
if (!left || !right)
|
|
393
|
+
break;
|
|
394
|
+
if (left_type != right_type ||
|
|
395
|
+
(left_type != "Number" && left_type != "Long")) {
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
const value = op(left.value, right.value, left_type);
|
|
399
|
+
if (value === null)
|
|
400
|
+
break;
|
|
401
|
+
return {
|
|
402
|
+
...left,
|
|
403
|
+
value,
|
|
404
|
+
raw: value.toString() + (left_type === "Long" ? "l" : ""),
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
break;
|
|
530
408
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
const locals = state.localsStack.slice(-1).pop();
|
|
535
|
-
const { map } = locals;
|
|
536
|
-
if (map) {
|
|
537
|
-
if (hasProperty(map, node.id.name)) {
|
|
538
|
-
// We already have a variable with this name in scope
|
|
539
|
-
// Recent monkeyc compilers complain, so rename it
|
|
540
|
-
let suffix = 0;
|
|
541
|
-
let node_name = node.id.name;
|
|
542
|
-
const match = node_name.match(/^pmcr_(.*)_(\d+)$/);
|
|
543
|
-
if (match) {
|
|
544
|
-
node_name = match[1];
|
|
545
|
-
suffix = parseInt(match[2], 10) + 1;
|
|
409
|
+
case "FunctionDeclaration":
|
|
410
|
+
if (node.body && evaluateFunction(node, null) !== false) {
|
|
411
|
+
node.optimizable = true;
|
|
546
412
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
function evaluateFunction(func, args) {
|
|
418
|
+
if (args && args.length != func.params.length) {
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
const paramValues = args &&
|
|
422
|
+
Object.fromEntries(func.params.map((p, i) => [variableDeclarationName(p), args[i]]));
|
|
423
|
+
let ret = null;
|
|
424
|
+
const body = args ? JSON.parse(JSON.stringify(func.body)) : func.body;
|
|
425
|
+
try {
|
|
426
|
+
traverseAst(body, (node) => {
|
|
427
|
+
switch (node.type) {
|
|
428
|
+
case "BlockStatement":
|
|
429
|
+
case "ReturnStatement":
|
|
430
|
+
case "UnaryExpression":
|
|
431
|
+
case "BinaryExpression":
|
|
432
|
+
case "Literal":
|
|
433
|
+
case "Identifier":
|
|
434
|
+
return;
|
|
435
|
+
default:
|
|
436
|
+
throw new Error("Bad node type");
|
|
556
437
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
438
|
+
}, args &&
|
|
439
|
+
((node) => {
|
|
440
|
+
switch (node.type) {
|
|
441
|
+
case "ReturnStatement":
|
|
442
|
+
ret = node.argument;
|
|
443
|
+
return null;
|
|
444
|
+
case "BlockStatement":
|
|
445
|
+
case "Literal":
|
|
446
|
+
return null;
|
|
447
|
+
case "Identifier":
|
|
448
|
+
if (hasProperty(paramValues, node.name)) {
|
|
449
|
+
return paramValues[node.name];
|
|
450
|
+
}
|
|
451
|
+
// fall through;
|
|
452
|
+
default: {
|
|
453
|
+
const repl = optimizeNode(node);
|
|
454
|
+
if (repl && repl.type === "Literal")
|
|
455
|
+
return repl;
|
|
456
|
+
throw new Error("Didn't optimize");
|
|
574
457
|
}
|
|
575
|
-
} else if (elm.node.type === "FunctionDeclaration") {
|
|
576
|
-
ok = true;
|
|
577
|
-
}
|
|
578
458
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
}
|
|
592
|
-
return ["init"];
|
|
593
|
-
}
|
|
594
|
-
case "UnaryExpression":
|
|
595
|
-
if (node.operator == ":") {
|
|
596
|
-
// If we produce a Symbol, for a given name,
|
|
597
|
-
// its possible that someone uses that symbol
|
|
598
|
-
// indirectly, so we can't remove any enums or
|
|
599
|
-
// constants with that name (we can still replace
|
|
600
|
-
// uses of those constants though).
|
|
601
|
-
state.exposed[node.argument.name] = true;
|
|
602
|
-
// In any case, we can't replace *this* use of the
|
|
603
|
-
// symbol with its value...
|
|
604
|
-
return false;
|
|
459
|
+
}));
|
|
460
|
+
return ret;
|
|
461
|
+
}
|
|
462
|
+
catch (e) {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
async function optimizeMonkeyC(fnMap) {
|
|
467
|
+
const state = await analyze(fnMap);
|
|
468
|
+
const replace = (node, obj) => {
|
|
469
|
+
for (const k of Object.keys(node)) {
|
|
470
|
+
delete node[k];
|
|
605
471
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
node.name = name;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
472
|
+
if (obj.enumType) {
|
|
473
|
+
obj = {
|
|
474
|
+
type: "BinaryExpression",
|
|
475
|
+
operator: "as",
|
|
476
|
+
left: obj,
|
|
477
|
+
right: { type: "TypeSpecList", ts: [obj.enumType] },
|
|
478
|
+
};
|
|
616
479
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
state.exposed[node.name] = true;
|
|
620
|
-
}
|
|
480
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
481
|
+
node[k] = v;
|
|
621
482
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
if (
|
|
626
|
-
|
|
627
|
-
if (lookupAndReplace(node)) {
|
|
628
|
-
return false;
|
|
629
|
-
} else {
|
|
630
|
-
state.exposed[node.property.name] = true;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
// Don't optimize the property.
|
|
634
|
-
return ["object"];
|
|
483
|
+
};
|
|
484
|
+
const lookupAndReplace = (node) => {
|
|
485
|
+
const [, objects] = state.lookup(node);
|
|
486
|
+
if (!objects) {
|
|
487
|
+
return false;
|
|
635
488
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
if (map) {
|
|
640
|
-
state.localsStack.push({
|
|
641
|
-
node,
|
|
642
|
-
map: { ...map },
|
|
643
|
-
});
|
|
489
|
+
const obj = getLiteralFromDecls(objects);
|
|
490
|
+
if (!obj) {
|
|
491
|
+
return false;
|
|
644
492
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
} else if (parent.superClass) {
|
|
657
|
-
used = checkInherited(parent, node.id.name);
|
|
658
|
-
}
|
|
659
|
-
if (used) {
|
|
660
|
-
if (!hasProperty(state.calledFunctions, node.id.name)) {
|
|
661
|
-
state.calledFunctions[node.id.name] = [];
|
|
662
|
-
}
|
|
663
|
-
state.calledFunctions[node.id.name].push(node);
|
|
664
|
-
}
|
|
493
|
+
replace(node, obj);
|
|
494
|
+
return true;
|
|
495
|
+
};
|
|
496
|
+
/*
|
|
497
|
+
* Might this function be called from somewhere, including
|
|
498
|
+
* callbacks from the api (eg getSettingsView, etc).
|
|
499
|
+
*/
|
|
500
|
+
const maybeCalled = (func) => {
|
|
501
|
+
if (!func.body) {
|
|
502
|
+
// this is an api.mir function. It can be called
|
|
503
|
+
return true;
|
|
665
504
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
switch (node.type) {
|
|
679
|
-
case "ConditionalExpression":
|
|
680
|
-
case "IfStatement":
|
|
681
|
-
if (typeof node.test === "boolean") {
|
|
682
|
-
const rep = node.test ? node.consequent : node.alternate;
|
|
683
|
-
if (!rep) return false;
|
|
684
|
-
replace(node, rep);
|
|
505
|
+
if (hasProperty(state.exposed, func.id.name))
|
|
506
|
+
return true;
|
|
507
|
+
if (func.attrs &&
|
|
508
|
+
func.attrs.attrs &&
|
|
509
|
+
func.attrs.attrs.some((attr) => {
|
|
510
|
+
if (attr.type != "UnaryExpression")
|
|
511
|
+
return false;
|
|
512
|
+
if (attr.argument.type != "Identifier")
|
|
513
|
+
return false;
|
|
514
|
+
return attr.argument.name == "test";
|
|
515
|
+
})) {
|
|
516
|
+
return true;
|
|
685
517
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (!node.body) return false;
|
|
689
|
-
break;
|
|
690
|
-
case "DoWhileStatement":
|
|
691
|
-
if (!node.test) return node.body;
|
|
692
|
-
break;
|
|
693
|
-
|
|
694
|
-
case "CallExpression": {
|
|
695
|
-
const [name, callees] = state.lookup(node.callee);
|
|
696
|
-
if (!callees || !callees.length) {
|
|
697
|
-
const n =
|
|
698
|
-
name ||
|
|
699
|
-
node.callee.name ||
|
|
700
|
-
(node.callee.property && node.callee.property.name);
|
|
701
|
-
if (n) {
|
|
702
|
-
state.exposed[n] = true;
|
|
703
|
-
} else {
|
|
704
|
-
// There are unnamed CallExpressions, such as new [size]
|
|
705
|
-
// So there's nothing to do here.
|
|
706
|
-
}
|
|
707
|
-
return;
|
|
518
|
+
if (hasProperty(state.calledFunctions, func.id.name)) {
|
|
519
|
+
return (state.calledFunctions[func.id.name].find((f) => f === func) !== null);
|
|
708
520
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
521
|
+
return false;
|
|
522
|
+
};
|
|
523
|
+
/*
|
|
524
|
+
* Does elm (a class) have a maybeCalled function called name,
|
|
525
|
+
* anywhere in its superClass chain.
|
|
526
|
+
*/
|
|
527
|
+
const checkInherited = (elm, name) => elm.superClass === true ||
|
|
528
|
+
elm.superClass.some((sc) => (hasProperty(sc.decls, name) &&
|
|
529
|
+
sc.decls[name].some((f) => isStateNode(f) &&
|
|
530
|
+
f.type == "FunctionDeclaration" &&
|
|
531
|
+
maybeCalled(f.node))) ||
|
|
532
|
+
(sc.superClass && checkInherited(sc, name)));
|
|
533
|
+
state.localsStack = [{}];
|
|
534
|
+
state.exposed = {};
|
|
535
|
+
state.calledFunctions = {};
|
|
536
|
+
state.pre = (node) => {
|
|
537
|
+
switch (node.type) {
|
|
538
|
+
case "ConditionalExpression":
|
|
539
|
+
case "IfStatement":
|
|
540
|
+
case "DoWhileStatement":
|
|
541
|
+
case "WhileStatement":
|
|
542
|
+
state.traverse(node.test);
|
|
543
|
+
const [value, type] = getNodeValue(node.test);
|
|
544
|
+
if (value) {
|
|
545
|
+
let result = null;
|
|
546
|
+
if (type === "Null") {
|
|
547
|
+
result = false;
|
|
548
|
+
}
|
|
549
|
+
else if (type === "Boolean" ||
|
|
550
|
+
type === "Number" ||
|
|
551
|
+
type === "Long") {
|
|
552
|
+
result = !!value.value;
|
|
553
|
+
}
|
|
554
|
+
if (result !== null) {
|
|
555
|
+
if (node.type === "IfStatement" ||
|
|
556
|
+
node.type === "ConditionalExpression") {
|
|
557
|
+
if (result === false) {
|
|
558
|
+
node.consequent = null;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
node.alternate = null;
|
|
562
|
+
}
|
|
563
|
+
node.test = null;
|
|
564
|
+
}
|
|
565
|
+
else if (node.type === "WhileStatement") {
|
|
566
|
+
if (result === false) {
|
|
567
|
+
node.body = null;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
else if (node.type === "DoWhileStatement") {
|
|
571
|
+
if (result === false) {
|
|
572
|
+
node.test = null;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
throw new Error("Unexpected Node type");
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return null;
|
|
581
|
+
case "EnumDeclaration":
|
|
582
|
+
return false;
|
|
583
|
+
case "ForStatement": {
|
|
584
|
+
const map = state.localsStack.slice(-1).pop().map;
|
|
585
|
+
if (map) {
|
|
586
|
+
state.localsStack.push({ node, map: { ...map } });
|
|
587
|
+
}
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
case "VariableDeclarator": {
|
|
591
|
+
const locals = state.localsStack.slice(-1).pop();
|
|
592
|
+
const { map } = locals;
|
|
593
|
+
if (map) {
|
|
594
|
+
const declName = variableDeclarationName(node.id);
|
|
595
|
+
if (hasProperty(map, declName)) {
|
|
596
|
+
// We already have a variable with this name in scope
|
|
597
|
+
// Recent monkeyc compilers complain, so rename it
|
|
598
|
+
let suffix = 0;
|
|
599
|
+
let node_name = declName;
|
|
600
|
+
const match = node_name.match(/^pmcr_(.*)_(\d+)$/);
|
|
601
|
+
if (match) {
|
|
602
|
+
node_name = match[1];
|
|
603
|
+
suffix = parseInt(match[2], 10) + 1;
|
|
604
|
+
}
|
|
605
|
+
if (!locals.inners) {
|
|
606
|
+
// find all the names declared in this scope, to avoid
|
|
607
|
+
// more conflicts
|
|
608
|
+
locals.inners = {};
|
|
609
|
+
traverseAst(locals.node, (node) => {
|
|
610
|
+
if (node.type === "VariableDeclarator") {
|
|
611
|
+
locals.inners[variableDeclarationName(node.id)] = true;
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
let name;
|
|
616
|
+
while (true) {
|
|
617
|
+
name = `pmcr_${node_name}_${suffix}`;
|
|
618
|
+
if (!hasProperty(map, name) &&
|
|
619
|
+
!hasProperty(locals.inners, name)) {
|
|
620
|
+
// we also need to ensure that we don't hide the name of
|
|
621
|
+
// an outer module, class, function, enum or variable,
|
|
622
|
+
// since someone might want to access it from this scope.
|
|
623
|
+
let ok = false;
|
|
624
|
+
let i;
|
|
625
|
+
for (i = state.stack.length; i--;) {
|
|
626
|
+
const elm = state.stack[i];
|
|
627
|
+
if (ok) {
|
|
628
|
+
if (hasProperty(elm.decls, name)) {
|
|
629
|
+
break;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
else if (elm.node.type === "FunctionDeclaration") {
|
|
633
|
+
ok = true;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
if (i < 0) {
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
suffix++;
|
|
641
|
+
}
|
|
642
|
+
map[declName] = name;
|
|
643
|
+
map[name] = true;
|
|
644
|
+
if (node.id.type === "Identifier") {
|
|
645
|
+
node.id.name = name;
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
node.id.left.name = name;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
map[declName] = true;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return ["init"];
|
|
656
|
+
}
|
|
657
|
+
case "UnaryExpression":
|
|
658
|
+
if (node.operator == ":") {
|
|
659
|
+
// If we produce a Symbol, for a given name,
|
|
660
|
+
// its possible that someone uses that symbol
|
|
661
|
+
// indirectly, so we can't remove any enums or
|
|
662
|
+
// constants with that name (we can still replace
|
|
663
|
+
// uses of those constants though).
|
|
664
|
+
state.exposed[node.argument.name] = true;
|
|
665
|
+
// In any case, we can't replace *this* use of the
|
|
666
|
+
// symbol with its value...
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
break;
|
|
670
|
+
case "Identifier": {
|
|
671
|
+
const map = state.localsStack.slice(-1).pop().map;
|
|
672
|
+
if (map) {
|
|
673
|
+
if (hasProperty(map, node.name)) {
|
|
674
|
+
const name = map[node.name];
|
|
675
|
+
if (name !== true) {
|
|
676
|
+
node.name = name;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
if (hasProperty(state.index, node.name)) {
|
|
681
|
+
if (!lookupAndReplace(node)) {
|
|
682
|
+
state.exposed[node.name] = true;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
case "MemberExpression":
|
|
688
|
+
if (node.property.type === "Identifier" && !node.computed) {
|
|
689
|
+
if (hasProperty(state.index, node.property.name)) {
|
|
690
|
+
if (lookupAndReplace(node)) {
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
state.exposed[node.property.name] = true;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
// Don't optimize the property.
|
|
698
|
+
return ["object"];
|
|
699
|
+
}
|
|
700
|
+
break;
|
|
701
|
+
case "BlockStatement": {
|
|
702
|
+
const map = state.localsStack.slice(-1).pop().map;
|
|
703
|
+
if (map) {
|
|
704
|
+
state.localsStack.push({
|
|
705
|
+
node,
|
|
706
|
+
map: { ...map },
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
case "FunctionDeclaration": {
|
|
712
|
+
const map = {};
|
|
713
|
+
node.params &&
|
|
714
|
+
node.params.forEach((p) => (map[variableDeclarationName(p)] = true));
|
|
715
|
+
state.localsStack.push({ node, map });
|
|
716
|
+
const [parent] = state.stack.slice(-2);
|
|
717
|
+
if (parent.type == "ClassDeclaration" && !maybeCalled(node)) {
|
|
718
|
+
let used = false;
|
|
719
|
+
if (node.id.name == "initialize") {
|
|
720
|
+
used = true;
|
|
721
|
+
}
|
|
722
|
+
else if (parent.superClass) {
|
|
723
|
+
used = checkInherited(parent, node.id.name);
|
|
724
|
+
}
|
|
725
|
+
if (used) {
|
|
726
|
+
if (!hasProperty(state.calledFunctions, node.id.name)) {
|
|
727
|
+
state.calledFunctions[node.id.name] = [];
|
|
728
|
+
}
|
|
729
|
+
state.calledFunctions[node.id.name].push(node);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
720
732
|
}
|
|
721
|
-
}
|
|
722
733
|
}
|
|
723
|
-
|
|
724
|
-
|
|
734
|
+
return null;
|
|
735
|
+
};
|
|
736
|
+
state.post = (node) => {
|
|
737
|
+
if (state.localsStack.slice(-1).pop().node === node) {
|
|
738
|
+
state.localsStack.pop();
|
|
725
739
|
}
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
740
|
+
const opt = optimizeNode(node);
|
|
741
|
+
if (opt) {
|
|
742
|
+
replace(node, opt);
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
745
|
+
switch (node.type) {
|
|
746
|
+
case "ConditionalExpression":
|
|
747
|
+
case "IfStatement":
|
|
748
|
+
if (node.test === null) {
|
|
749
|
+
const rep = node.consequent || node.alternate;
|
|
750
|
+
if (!rep)
|
|
751
|
+
return false;
|
|
752
|
+
replace(node, rep);
|
|
753
|
+
}
|
|
754
|
+
break;
|
|
755
|
+
case "WhileStatement":
|
|
756
|
+
if (!node.body)
|
|
757
|
+
return false;
|
|
758
|
+
break;
|
|
759
|
+
case "DoWhileStatement":
|
|
760
|
+
if (!node.test)
|
|
761
|
+
return node.body;
|
|
762
|
+
break;
|
|
763
|
+
case "CallExpression": {
|
|
764
|
+
const [name, callees] = state.lookup(node.callee);
|
|
765
|
+
if (!callees || !callees.length) {
|
|
766
|
+
const n = name ||
|
|
767
|
+
("name" in node.callee && node.callee.name) ||
|
|
768
|
+
("property" in node.callee &&
|
|
769
|
+
node.callee.property &&
|
|
770
|
+
"name" in node.callee.property &&
|
|
771
|
+
node.callee.property.name);
|
|
772
|
+
if (n) {
|
|
773
|
+
state.exposed[n] = true;
|
|
774
|
+
}
|
|
775
|
+
else {
|
|
776
|
+
// There are unnamed CallExpressions, such as new [size]
|
|
777
|
+
// So there's nothing to do here.
|
|
778
|
+
}
|
|
779
|
+
return null;
|
|
780
|
+
}
|
|
781
|
+
if (callees.length == 1) {
|
|
782
|
+
const callee = isStateNode(callees[0]) && callees[0].node;
|
|
783
|
+
if (callee.type == "FunctionDeclaration" &&
|
|
784
|
+
callee.optimizable &&
|
|
785
|
+
!callee.hasOverride &&
|
|
786
|
+
node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
|
|
787
|
+
const ret = evaluateFunction(callee, node.arguments);
|
|
788
|
+
if (ret) {
|
|
789
|
+
replace(node, ret);
|
|
790
|
+
return null;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
if (!hasProperty(state.calledFunctions, name)) {
|
|
795
|
+
state.calledFunctions[name] = [];
|
|
796
|
+
}
|
|
797
|
+
callees.forEach((c) => isStateNode(c) && state.calledFunctions[name].push(c.node));
|
|
798
|
+
break;
|
|
767
799
|
}
|
|
768
|
-
replace(node, {
|
|
769
|
-
type: "TypedefDeclaration",
|
|
770
|
-
id: node.id,
|
|
771
|
-
ts: {
|
|
772
|
-
type: "UnaryExpression",
|
|
773
|
-
argument: { type: "TypeSpecList", ts: [node.body.enumType] },
|
|
774
|
-
prefix: true,
|
|
775
|
-
operator: " as",
|
|
776
|
-
},
|
|
777
|
-
});
|
|
778
|
-
}
|
|
779
|
-
break;
|
|
780
|
-
case "VariableDeclaration": {
|
|
781
|
-
node.declarations = node.declarations.filter(
|
|
782
|
-
(d) =>
|
|
783
|
-
!hasProperty(state.index, d.id.name) ||
|
|
784
|
-
hasProperty(state.exposed, d.id.name)
|
|
785
|
-
);
|
|
786
|
-
if (!node.declarations.length) {
|
|
787
|
-
return false;
|
|
788
|
-
}
|
|
789
|
-
break;
|
|
790
800
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
801
|
+
return null;
|
|
802
|
+
};
|
|
803
|
+
Object.values(fnMap).forEach((f) => {
|
|
804
|
+
collectNamespaces(f.ast, state);
|
|
805
|
+
});
|
|
806
|
+
Object.values(fnMap).forEach((f) => {
|
|
807
|
+
traverseAst(f.ast, null, (node) => {
|
|
808
|
+
switch (node.type) {
|
|
809
|
+
case "EnumStringBody":
|
|
810
|
+
if (node.members.every((m) => {
|
|
811
|
+
const name = "name" in m ? m.name : m.id.name;
|
|
812
|
+
return (hasProperty(state.index, name) &&
|
|
813
|
+
!hasProperty(state.exposed, name));
|
|
814
|
+
})) {
|
|
815
|
+
node.enumType = [
|
|
816
|
+
...new Set(node.members.map((m) => {
|
|
817
|
+
if (!("init" in m))
|
|
818
|
+
return "Number";
|
|
819
|
+
const [node, type] = getNodeValue(m.init);
|
|
820
|
+
if (!node) {
|
|
821
|
+
throw new Error("Failed to get type for eliminated enum");
|
|
822
|
+
}
|
|
823
|
+
return type;
|
|
824
|
+
})),
|
|
825
|
+
].join(" or ");
|
|
826
|
+
node.members.splice(0);
|
|
827
|
+
}
|
|
828
|
+
break;
|
|
829
|
+
case "EnumDeclaration":
|
|
830
|
+
if (!node.body.members.length) {
|
|
831
|
+
if (!node.id)
|
|
832
|
+
return false;
|
|
833
|
+
if (!node.body["enumType"]) {
|
|
834
|
+
throw new Error("Missing enumType on optimized enum");
|
|
835
|
+
}
|
|
836
|
+
replace(node, {
|
|
837
|
+
type: "TypedefDeclaration",
|
|
838
|
+
id: node.id,
|
|
839
|
+
ts: {
|
|
840
|
+
type: "UnaryExpression",
|
|
841
|
+
argument: { type: "TypeSpecList", ts: [node.body.enumType] },
|
|
842
|
+
prefix: true,
|
|
843
|
+
operator: " as",
|
|
844
|
+
},
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
break;
|
|
848
|
+
case "VariableDeclaration": {
|
|
849
|
+
node.declarations = node.declarations.filter((d) => {
|
|
850
|
+
const name = variableDeclarationName(d.id);
|
|
851
|
+
return (!hasProperty(state.index, name) ||
|
|
852
|
+
hasProperty(state.exposed, name));
|
|
853
|
+
});
|
|
854
|
+
if (!node.declarations.length) {
|
|
855
|
+
return false;
|
|
856
|
+
}
|
|
857
|
+
break;
|
|
858
|
+
}
|
|
859
|
+
case "ClassElement":
|
|
860
|
+
if (!node.item) {
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
break;
|
|
864
|
+
case "FunctionDeclaration":
|
|
865
|
+
if (!maybeCalled(node)) {
|
|
866
|
+
return false;
|
|
867
|
+
}
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
return null;
|
|
871
|
+
});
|
|
802
872
|
});
|
|
803
|
-
});
|
|
804
|
-
|
|
805
|
-
return files;
|
|
806
873
|
}
|
|
807
874
|
|
|
808
|
-
;// CONCATENATED MODULE: ./src/negative-fixups.
|
|
875
|
+
;// CONCATENATED MODULE: ./src/negative-fixups.ts
|
|
809
876
|
/*
|
|
810
877
|
* This is strange. It pretty much has to be a bug in the sdk,
|
|
811
878
|
* but its the same in every sdk.
|
|
@@ -823,48 +890,47 @@ async function optimizeMonkeyC(fileNames, buildConfig) {
|
|
|
823
890
|
* so we can fix them after reading api.mir.
|
|
824
891
|
*/
|
|
825
892
|
const negativeFixups = [
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
893
|
+
"Toybox.Communications.BLE_CONNECTION_UNAVAILABLE",
|
|
894
|
+
"Toybox.Communications.INVALID_HTTP_BODY_IN_REQUEST",
|
|
895
|
+
"Toybox.Communications.REQUEST_CANCELLED",
|
|
896
|
+
"Toybox.Communications.UNSUPPORTED_CONTENT_TYPE_IN_RESPONSE",
|
|
897
|
+
"Toybox.Communications.UNABLE_TO_PROCESS_IMAGE",
|
|
898
|
+
"Toybox.Communications.NETWORK_RESPONSE_OUT_OF_MEMORY",
|
|
899
|
+
"Toybox.Communications.BLE_REQUEST_CANCELLED",
|
|
900
|
+
"Toybox.Communications.INVALID_HTTP_METHOD_IN_REQUEST",
|
|
901
|
+
"Toybox.Communications.BLE_NO_DATA",
|
|
902
|
+
"Toybox.Communications.INVALID_HTTP_HEADER_FIELDS_IN_REQUEST",
|
|
903
|
+
"Toybox.Communications.BLE_ERROR",
|
|
904
|
+
"Toybox.Communications.NETWORK_RESPONSE_TOO_LARGE",
|
|
905
|
+
"Toybox.Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE",
|
|
906
|
+
"Toybox.Communications.BLE_REQUEST_TOO_LARGE",
|
|
907
|
+
"Toybox.Communications.UNABLE_TO_PROCESS_MEDIA",
|
|
908
|
+
"Toybox.Communications.REQUEST_CONNECTION_DROPPED",
|
|
909
|
+
"Toybox.Communications.BLE_UNKNOWN_SEND_ERROR",
|
|
910
|
+
"Toybox.Communications.BLE_QUEUE_FULL",
|
|
911
|
+
"Toybox.Communications.STORAGE_FULL",
|
|
912
|
+
"Toybox.Communications.BLE_SERVER_TIMEOUT",
|
|
913
|
+
"Toybox.Communications.INVALID_HTTP_HEADER_FIELDS_IN_NETWORK_RESPONSE",
|
|
914
|
+
"Toybox.Communications.SECURE_CONNECTION_REQUIRED",
|
|
915
|
+
"Toybox.Communications.NETWORK_REQUEST_TIMED_OUT",
|
|
916
|
+
"Toybox.Communications.BLE_HOST_TIMEOUT",
|
|
917
|
+
"Toybox.Communications.UNABLE_TO_PROCESS_HLS",
|
|
918
|
+
"Toybox.Graphics.COLOR_TRANSPARENT",
|
|
919
|
+
"Toybox.AntPlus.INVALID_SPEED",
|
|
920
|
+
"Toybox.AntPlus.INVALID_CADENCE",
|
|
921
|
+
"Toybox.WatchUi.LAYOUT_VALIGN_START",
|
|
922
|
+
"Toybox.WatchUi.LAYOUT_VALIGN_TOP",
|
|
923
|
+
"Toybox.WatchUi.LAYOUT_VALIGN_BOTTOM",
|
|
924
|
+
"Toybox.WatchUi.LAYOUT_VALIGN_CENTER",
|
|
925
|
+
"Toybox.WatchUi.LAYOUT_HALIGN_RIGHT",
|
|
926
|
+
"Toybox.WatchUi.LAYOUT_HALIGN_CENTER",
|
|
927
|
+
"Toybox.WatchUi.LAYOUT_HALIGN_START",
|
|
928
|
+
"Toybox.WatchUi.LAYOUT_HALIGN_LEFT",
|
|
862
929
|
];
|
|
863
930
|
|
|
864
931
|
;// CONCATENATED MODULE: external "./sdk-util.cjs"
|
|
865
932
|
const external_sdk_util_cjs_namespaceObject = require("./sdk-util.cjs");
|
|
866
|
-
;// CONCATENATED MODULE: ./src/api.
|
|
867
|
-
|
|
933
|
+
;// CONCATENATED MODULE: ./src/api.ts
|
|
868
934
|
|
|
869
935
|
|
|
870
936
|
|
|
@@ -872,7 +938,6 @@ const external_sdk_util_cjs_namespaceObject = require("./sdk-util.cjs");
|
|
|
872
938
|
|
|
873
939
|
|
|
874
940
|
|
|
875
|
-
const api_LiteralIntegerRe = /^(0x[0-9a-f]+|\d+)(l)?$/i;
|
|
876
941
|
/*
|
|
877
942
|
* This is an unfortunate hack. I want to be able to extract things
|
|
878
943
|
* like the types of all of a Class's variables (in particular the type
|
|
@@ -882,283 +947,307 @@ const api_LiteralIntegerRe = /^(0x[0-9a-f]+|\d+)(l)?$/i;
|
|
|
882
947
|
* undocumented. The same could be said of compiler.json and simulator.json,
|
|
883
948
|
* but those are at least in a standard format.
|
|
884
949
|
*/
|
|
885
|
-
|
|
886
950
|
// Extract all enum values from api.mir
|
|
887
951
|
async function api_getApiMapping(state) {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
952
|
+
// get the path to the currently active sdk
|
|
953
|
+
const parser = (prettier_plugin_monkeyc_default()).parsers.monkeyc;
|
|
954
|
+
const sdk = await (0,external_sdk_util_cjs_namespaceObject.getSdkPath)();
|
|
955
|
+
const api = (await promises_namespaceObject.readFile(`${sdk}bin/api.mir`))
|
|
956
|
+
.toString()
|
|
957
|
+
.replace(/\r\n/g, "\n")
|
|
958
|
+
.replace(/^\s*\[.*?\]\s*$/gm, "")
|
|
959
|
+
//.replace(/(COLOR_TRANSPARENT|LAYOUT_[HV]ALIGN_\w+) = (\d+)/gm, "$1 = -$2")
|
|
960
|
+
.replace(/^(\s*type)\s/gm, "$1def ");
|
|
961
|
+
try {
|
|
962
|
+
const result = api_collectNamespaces(parser.parse(api, null, {
|
|
963
|
+
filepath: "api.mir",
|
|
964
|
+
}), state);
|
|
965
|
+
negativeFixups.forEach((fixup) => {
|
|
966
|
+
const value = fixup.split(".").reduce((state, part) => {
|
|
967
|
+
const decls = state.decls[part];
|
|
968
|
+
if (!Array.isArray(decls) || decls.length != 1 || !decls[0]) {
|
|
969
|
+
throw `Failed to find and fix negative constant ${fixup}`;
|
|
970
|
+
}
|
|
971
|
+
return decls[0];
|
|
972
|
+
}, result);
|
|
973
|
+
if (value.type !== "EnumStringMember" &&
|
|
974
|
+
(value.type !== "VariableDeclarator" || value.kind != "const")) {
|
|
975
|
+
throw `Negative constant ${fixup} did not refer to a constant`;
|
|
976
|
+
}
|
|
977
|
+
const init = value.init;
|
|
978
|
+
if (init.type !== "Literal") {
|
|
979
|
+
throw `Negative constant ${fixup} was not a Literal`;
|
|
980
|
+
}
|
|
981
|
+
if (init.value > 0) {
|
|
982
|
+
init.value = -init.value;
|
|
983
|
+
init.raw = "-" + init.raw;
|
|
984
|
+
}
|
|
985
|
+
else {
|
|
986
|
+
console.log(`Negative fixup ${fixup} was already negative!`);
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
return result;
|
|
990
|
+
}
|
|
991
|
+
catch (e) {
|
|
992
|
+
console.error(e.toString());
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
924
995
|
}
|
|
925
|
-
|
|
926
996
|
function api_hasProperty(obj, prop) {
|
|
927
|
-
|
|
997
|
+
return obj && Object.prototype.hasOwnProperty.call(obj, prop);
|
|
998
|
+
}
|
|
999
|
+
function api_isStateNode(node) {
|
|
1000
|
+
return api_hasProperty(node, "node");
|
|
1001
|
+
}
|
|
1002
|
+
function api_variableDeclarationName(node) {
|
|
1003
|
+
return ("left" in node ? node.left : node).name;
|
|
928
1004
|
}
|
|
929
|
-
|
|
930
1005
|
function api_collectNamespaces(ast, state) {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
state.stack
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
return ns.decls[name];
|
|
1006
|
+
state = state || {};
|
|
1007
|
+
if (!state.index)
|
|
1008
|
+
state.index = {};
|
|
1009
|
+
if (!state.stack) {
|
|
1010
|
+
state.stack = [
|
|
1011
|
+
{ type: "Program", name: "$", fullName: "$", node: undefined },
|
|
1012
|
+
];
|
|
939
1013
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
stack || (stack = state.stack);
|
|
944
|
-
switch (node.type) {
|
|
945
|
-
case "MemberExpression": {
|
|
946
|
-
if (node.property.type != "Identifier" || node.computed) break;
|
|
947
|
-
const [, module] = state.lookup(node.object, name, stack);
|
|
948
|
-
if (module && module.length === 1) {
|
|
949
|
-
const result = checkOne(module[0], node.property.name);
|
|
950
|
-
if (result) {
|
|
951
|
-
return [name || node.property.name, result];
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
break;
|
|
955
|
-
}
|
|
956
|
-
case "ThisExpression":
|
|
957
|
-
return [name, stack.slice(-1)];
|
|
958
|
-
case "Identifier": {
|
|
959
|
-
if (node.name == "$") {
|
|
960
|
-
return [name || node.name, [stack[0]]];
|
|
961
|
-
}
|
|
962
|
-
for (let i = stack.length; i--; ) {
|
|
963
|
-
const result = checkOne(stack[i], node.name);
|
|
964
|
-
if (result) {
|
|
965
|
-
return [name || node.name, result];
|
|
966
|
-
}
|
|
1014
|
+
const checkOne = (ns, name) => {
|
|
1015
|
+
if (api_isStateNode(ns) && api_hasProperty(ns.decls, name)) {
|
|
1016
|
+
return ns.decls[name];
|
|
967
1017
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
}
|
|
988
|
-
if (node.source) {
|
|
989
|
-
state.stack[0].source = node.source;
|
|
990
|
-
}
|
|
991
|
-
break;
|
|
992
|
-
case "BlockStatement": {
|
|
993
|
-
const [parent] = state.stack.slice(-1);
|
|
994
|
-
if (
|
|
995
|
-
parent.type != "FunctionDeclaration" &&
|
|
996
|
-
parent.type != "BlockStatement"
|
|
997
|
-
) {
|
|
1018
|
+
return null;
|
|
1019
|
+
};
|
|
1020
|
+
state.lookup = (node, name, stack) => {
|
|
1021
|
+
stack || (stack = state.stack);
|
|
1022
|
+
switch (node.type) {
|
|
1023
|
+
case "MemberExpression": {
|
|
1024
|
+
if (node.property.type != "Identifier" || node.computed)
|
|
1025
|
+
break;
|
|
1026
|
+
const [, module, where] = state.lookup(node.object, name, stack);
|
|
1027
|
+
if (module && module.length === 1) {
|
|
1028
|
+
const result = checkOne(module[0], node.property.name);
|
|
1029
|
+
if (result) {
|
|
1030
|
+
return [
|
|
1031
|
+
name || node.property.name,
|
|
1032
|
+
result,
|
|
1033
|
+
where.concat(module[0]),
|
|
1034
|
+
];
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
998
1037
|
break;
|
|
999
|
-
}
|
|
1000
|
-
// fall through
|
|
1001
1038
|
}
|
|
1002
|
-
case "
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
name: node.id && node.id.name,
|
|
1010
|
-
node,
|
|
1011
|
-
};
|
|
1012
|
-
state.stack.push(elm);
|
|
1013
|
-
elm.fullName = state.stack
|
|
1014
|
-
.map((e) => e.name)
|
|
1015
|
-
.filter((e) => e != null)
|
|
1016
|
-
.join(".");
|
|
1017
|
-
if (elm.name) {
|
|
1018
|
-
if (!parent.decls) parent.decls = {};
|
|
1019
|
-
if (api_hasProperty(parent.decls, elm.name)) {
|
|
1020
|
-
const what =
|
|
1021
|
-
node.type == "ModuleDeclaration" ? "type" : "node";
|
|
1022
|
-
const e = parent.decls[elm.name].find(
|
|
1023
|
-
(d) => d[what] == elm[what]
|
|
1024
|
-
);
|
|
1025
|
-
if (e != null) {
|
|
1026
|
-
e.node = node;
|
|
1027
|
-
state.stack.splice(-1, 1, e);
|
|
1028
|
-
break;
|
|
1039
|
+
case "ThisExpression": {
|
|
1040
|
+
for (let i = stack.length; i--;) {
|
|
1041
|
+
const si = stack[i];
|
|
1042
|
+
if (si.type == "ModuleDeclaration" ||
|
|
1043
|
+
si.type == "ClassDeclaration" ||
|
|
1044
|
+
!i) {
|
|
1045
|
+
return [name || si.name, [si], stack.slice(0, i)];
|
|
1029
1046
|
}
|
|
1030
|
-
} else {
|
|
1031
|
-
parent.decls[elm.name] = [];
|
|
1032
|
-
}
|
|
1033
|
-
parent.decls[elm.name].push(elm);
|
|
1034
1047
|
}
|
|
1035
|
-
|
|
1036
|
-
break;
|
|
1037
|
-
// an EnumDeclaration doesn't create a scope, but
|
|
1038
|
-
// it does create a type (if it has a name)
|
|
1039
|
-
case "EnumDeclaration": {
|
|
1040
|
-
if (!node.id) break;
|
|
1041
|
-
const [parent] = state.stack.slice(-1);
|
|
1042
|
-
const name = (parent.fullName + "." + node.id.name).replace(
|
|
1043
|
-
/^\$\./,
|
|
1044
|
-
""
|
|
1045
|
-
);
|
|
1046
|
-
node.body.members.forEach((m) => ((m.init || m).enumType = name));
|
|
1047
|
-
}
|
|
1048
|
-
// fall through
|
|
1049
|
-
case "TypedefDeclaration": {
|
|
1050
|
-
const [parent] = state.stack.slice(-1);
|
|
1051
|
-
if (!parent.decls) parent.decls = {};
|
|
1052
|
-
if (!api_hasProperty(parent.decls, node.id.name)) {
|
|
1053
|
-
parent.decls[node.id.name] = [];
|
|
1054
|
-
}
|
|
1055
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(
|
|
1056
|
-
parent.decls[node.id.name],
|
|
1057
|
-
node.ts ? formatAst(node.ts.argument) : node.id.name
|
|
1058
|
-
);
|
|
1059
|
-
break;
|
|
1048
|
+
break;
|
|
1060
1049
|
}
|
|
1061
|
-
case "
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
node.declarations.forEach((decl) => {
|
|
1065
|
-
if (!api_hasProperty(parent.decls, decl.id.name)) {
|
|
1066
|
-
parent.decls[decl.id.name] = [];
|
|
1050
|
+
case "Identifier": {
|
|
1051
|
+
if (node.name == "$") {
|
|
1052
|
+
return [name || node.name, [stack[0]], []];
|
|
1067
1053
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[decl.id.name], parent);
|
|
1074
|
-
} else if (decl.id.ts) {
|
|
1075
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(
|
|
1076
|
-
parent.decls[decl.id.name],
|
|
1077
|
-
formatAst(decl.id.ts.argument)
|
|
1078
|
-
);
|
|
1054
|
+
for (let i = stack.length; i--;) {
|
|
1055
|
+
const result = checkOne(stack[i], node.name);
|
|
1056
|
+
if (result) {
|
|
1057
|
+
return [name || node.name, result, stack.slice(0, i + 1)];
|
|
1058
|
+
}
|
|
1079
1059
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1060
|
+
break;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
return [null, null, null];
|
|
1064
|
+
};
|
|
1065
|
+
state.traverse = (root) => api_traverseAst(root, (node) => {
|
|
1066
|
+
try {
|
|
1067
|
+
if (state.shouldExclude && state.shouldExclude(node)) {
|
|
1068
|
+
// don't visit any children, but do call post
|
|
1069
|
+
return [];
|
|
1082
1070
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
if (!init) {
|
|
1113
|
-
init = state.constants[key] = {
|
|
1114
|
-
type: "Literal",
|
|
1115
|
-
value: prev,
|
|
1116
|
-
raw: prev.toString(),
|
|
1117
|
-
enumType: m.enumType,
|
|
1071
|
+
switch (node.type) {
|
|
1072
|
+
case "Program":
|
|
1073
|
+
if (state.stack.length != 1) {
|
|
1074
|
+
throw new Error("Unexpected stack length for Program node");
|
|
1075
|
+
}
|
|
1076
|
+
break;
|
|
1077
|
+
case "BlockStatement": {
|
|
1078
|
+
const [parent] = state.stack.slice(-1);
|
|
1079
|
+
if (parent.type != "FunctionDeclaration" &&
|
|
1080
|
+
parent.type != "BlockStatement") {
|
|
1081
|
+
break;
|
|
1082
|
+
}
|
|
1083
|
+
// fall through
|
|
1084
|
+
}
|
|
1085
|
+
case "ClassDeclaration":
|
|
1086
|
+
case "FunctionDeclaration":
|
|
1087
|
+
case "ModuleDeclaration": {
|
|
1088
|
+
const [parent] = state.stack.slice(-1);
|
|
1089
|
+
const name = "id" in node ? node.id && node.id.name : null;
|
|
1090
|
+
const fullName = state.stack
|
|
1091
|
+
.map((e) => e.name)
|
|
1092
|
+
.concat(name)
|
|
1093
|
+
.filter((e) => e != null)
|
|
1094
|
+
.join(".");
|
|
1095
|
+
const elm = {
|
|
1096
|
+
type: node.type,
|
|
1097
|
+
name,
|
|
1098
|
+
fullName,
|
|
1099
|
+
node,
|
|
1118
1100
|
};
|
|
1119
|
-
|
|
1101
|
+
state.stack.push(elm);
|
|
1102
|
+
if (name) {
|
|
1103
|
+
if (!parent.decls)
|
|
1104
|
+
parent.decls = {};
|
|
1105
|
+
if (api_hasProperty(parent.decls, elm.name)) {
|
|
1106
|
+
const what = node.type == "ModuleDeclaration" ? "type" : "node";
|
|
1107
|
+
const e = parent.decls[name].find((d) => api_isStateNode(d) && d[what] == elm[what]);
|
|
1108
|
+
if (e != null) {
|
|
1109
|
+
e.node = node;
|
|
1110
|
+
state.stack.splice(-1, 1, e);
|
|
1111
|
+
break;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
else {
|
|
1115
|
+
parent.decls[elm.name] = [];
|
|
1116
|
+
}
|
|
1117
|
+
if (node.type === "FunctionDeclaration" &&
|
|
1118
|
+
node.params &&
|
|
1119
|
+
node.params.length) {
|
|
1120
|
+
elm.decls = {};
|
|
1121
|
+
node.params.forEach((p) => (elm.decls[api_variableDeclarationName(p)] = [p]));
|
|
1122
|
+
}
|
|
1123
|
+
parent.decls[elm.name].push(elm);
|
|
1124
|
+
}
|
|
1125
|
+
break;
|
|
1120
1126
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1127
|
+
// an EnumDeclaration doesn't create a scope, but
|
|
1128
|
+
// it does create a type (if it has a name)
|
|
1129
|
+
case "EnumDeclaration": {
|
|
1130
|
+
if (!node.id)
|
|
1131
|
+
break;
|
|
1132
|
+
const [parent] = state.stack.slice(-1);
|
|
1133
|
+
const name = (parent.fullName + "." + node.id.name).replace(/^\$\./, "");
|
|
1134
|
+
node.body.members.forEach((m) => (("init" in m ? m.init : m).enumType = name));
|
|
1123
1135
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1136
|
+
// fall through
|
|
1137
|
+
case "TypedefDeclaration": {
|
|
1138
|
+
const [parent] = state.stack.slice(-1);
|
|
1139
|
+
if (!parent.decls)
|
|
1140
|
+
parent.decls = {};
|
|
1141
|
+
if (!api_hasProperty(parent.decls, node.id.name)) {
|
|
1142
|
+
parent.decls[node.id.name] = [];
|
|
1143
|
+
}
|
|
1144
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(parent.decls[node.id.name], node);
|
|
1145
|
+
break;
|
|
1146
|
+
}
|
|
1147
|
+
case "VariableDeclaration": {
|
|
1148
|
+
const [parent] = state.stack.slice(-1);
|
|
1149
|
+
if (!parent.decls)
|
|
1150
|
+
parent.decls = {};
|
|
1151
|
+
node.declarations.forEach((decl) => {
|
|
1152
|
+
const name = api_variableDeclarationName(decl.id);
|
|
1153
|
+
if (!api_hasProperty(parent.decls, name)) {
|
|
1154
|
+
parent.decls[name] = [];
|
|
1155
|
+
}
|
|
1156
|
+
decl.kind = node.kind;
|
|
1157
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(parent.decls[name], decl);
|
|
1158
|
+
if (node.kind == "const") {
|
|
1159
|
+
if (!api_hasProperty(state.index, name)) {
|
|
1160
|
+
state.index[name] = [];
|
|
1161
|
+
}
|
|
1162
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
1165
|
+
break;
|
|
1166
|
+
}
|
|
1167
|
+
case "EnumStringBody": {
|
|
1168
|
+
const [parent] = state.stack.slice(-1);
|
|
1169
|
+
const values = parent.decls || (parent.decls = {});
|
|
1170
|
+
let prev = -1;
|
|
1171
|
+
node.members.forEach((m, i) => {
|
|
1172
|
+
if (m.type == "Identifier") {
|
|
1173
|
+
prev += 1;
|
|
1174
|
+
m = node.members[i] = {
|
|
1175
|
+
type: "EnumStringMember",
|
|
1176
|
+
loc: m.loc,
|
|
1177
|
+
start: m.start,
|
|
1178
|
+
end: m.end,
|
|
1179
|
+
id: m,
|
|
1180
|
+
init: {
|
|
1181
|
+
type: "Literal",
|
|
1182
|
+
value: prev,
|
|
1183
|
+
raw: prev.toString(),
|
|
1184
|
+
enumType: m.enumType,
|
|
1185
|
+
loc: m.loc,
|
|
1186
|
+
start: m.start,
|
|
1187
|
+
end: m.end,
|
|
1188
|
+
},
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
const name = m.id.name;
|
|
1192
|
+
const init = getLiteralNode(m.init);
|
|
1193
|
+
if (!init) {
|
|
1194
|
+
throw new Error("Unexpected enum initializer");
|
|
1195
|
+
}
|
|
1196
|
+
if (init != m.init) {
|
|
1197
|
+
m.init = init;
|
|
1198
|
+
}
|
|
1199
|
+
if (init.type == "Literal" && prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.test(init.raw)) {
|
|
1200
|
+
prev = init.value;
|
|
1201
|
+
}
|
|
1202
|
+
if (!api_hasProperty(values, name)) {
|
|
1203
|
+
values[name] = [];
|
|
1204
|
+
}
|
|
1205
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(values[name], m);
|
|
1206
|
+
if (!api_hasProperty(state.index, name)) {
|
|
1207
|
+
state.index[name] = [];
|
|
1208
|
+
}
|
|
1209
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
|
|
1210
|
+
});
|
|
1211
|
+
break;
|
|
1127
1212
|
}
|
|
1128
|
-
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
|
|
1129
|
-
});
|
|
1130
|
-
break;
|
|
1131
1213
|
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1214
|
+
if (state.pre)
|
|
1215
|
+
return state.pre(node);
|
|
1216
|
+
}
|
|
1217
|
+
catch (e) {
|
|
1218
|
+
handleException(state, node, e);
|
|
1136
1219
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1220
|
+
return null;
|
|
1221
|
+
}, (node) => {
|
|
1139
1222
|
try {
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
state.stack.pop()
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1223
|
+
let ret;
|
|
1224
|
+
if (state.shouldExclude && state.shouldExclude(node)) {
|
|
1225
|
+
// delete the node.
|
|
1226
|
+
return false;
|
|
1227
|
+
}
|
|
1228
|
+
if (state.post)
|
|
1229
|
+
ret = state.post(node);
|
|
1230
|
+
if (state.stack.slice(-1).pop().node === node) {
|
|
1231
|
+
state.stack.pop();
|
|
1232
|
+
}
|
|
1233
|
+
return ret;
|
|
1234
|
+
}
|
|
1235
|
+
catch (e) {
|
|
1236
|
+
handleException(state, node, e);
|
|
1152
1237
|
}
|
|
1153
|
-
|
|
1154
|
-
);
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1238
|
+
});
|
|
1239
|
+
state.traverse(ast);
|
|
1240
|
+
if (state.stack.length != 1) {
|
|
1241
|
+
throw new Error("Invalid AST!");
|
|
1242
|
+
}
|
|
1243
|
+
if (state.stack[0].type != "Program") {
|
|
1244
|
+
throw new Error("Bottom of stack was not a Program!");
|
|
1245
|
+
}
|
|
1246
|
+
return state.stack[0];
|
|
1247
|
+
}
|
|
1248
|
+
function isMCTreeNode(node) {
|
|
1249
|
+
return node && typeof node === "object" && "type" in node;
|
|
1160
1250
|
}
|
|
1161
|
-
|
|
1162
1251
|
/*
|
|
1163
1252
|
* Traverse the ast rooted at node, calling pre before
|
|
1164
1253
|
* visiting each node, and post after.
|
|
@@ -1173,84 +1262,83 @@ function api_collectNamespaces(ast, state) {
|
|
|
1173
1262
|
* removed.
|
|
1174
1263
|
*/
|
|
1175
1264
|
function api_traverseAst(node, pre, post) {
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
const
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1265
|
+
const nodes = pre && pre(node);
|
|
1266
|
+
if (nodes === false)
|
|
1267
|
+
return;
|
|
1268
|
+
for (const key of nodes || Object.keys(node)) {
|
|
1269
|
+
const value = node[key];
|
|
1270
|
+
if (!value)
|
|
1271
|
+
continue;
|
|
1272
|
+
if (Array.isArray(value)) {
|
|
1273
|
+
const values = value;
|
|
1274
|
+
const deletions = values.reduce((state, obj, i) => {
|
|
1275
|
+
if (isMCTreeNode(obj)) {
|
|
1276
|
+
const repl = api_traverseAst(obj, pre, post);
|
|
1277
|
+
if (repl === false) {
|
|
1278
|
+
if (!state)
|
|
1279
|
+
state = {};
|
|
1280
|
+
state[i] = true;
|
|
1281
|
+
}
|
|
1282
|
+
else if (repl != null) {
|
|
1283
|
+
values[i] = repl;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
return state;
|
|
1287
|
+
}, null);
|
|
1288
|
+
if (deletions) {
|
|
1289
|
+
values.splice(0, values.length, ...values.filter((obj, i) => deletions[i] !== true));
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
else if (isMCTreeNode(value)) {
|
|
1293
|
+
const repl = api_traverseAst(value, pre, post);
|
|
1294
|
+
if (repl === false) {
|
|
1295
|
+
delete node[key];
|
|
1296
|
+
}
|
|
1297
|
+
else if (repl != null) {
|
|
1298
|
+
node[key] = repl;
|
|
1299
|
+
}
|
|
1189
1300
|
}
|
|
1190
|
-
return state;
|
|
1191
|
-
}, null);
|
|
1192
|
-
if (deletions) {
|
|
1193
|
-
value.splice(
|
|
1194
|
-
0,
|
|
1195
|
-
value.length,
|
|
1196
|
-
...value.filter((obj, i) => deletions[i] !== true)
|
|
1197
|
-
);
|
|
1198
|
-
}
|
|
1199
|
-
} else if (typeof value == "object" && value.type) {
|
|
1200
|
-
const repl = api_traverseAst(value, pre, post);
|
|
1201
|
-
if (repl === false) {
|
|
1202
|
-
delete node[key];
|
|
1203
|
-
} else if (repl != null) {
|
|
1204
|
-
node[key] = repl;
|
|
1205
|
-
}
|
|
1206
1301
|
}
|
|
1207
|
-
|
|
1208
|
-
return post && post(node);
|
|
1302
|
+
return post && post(node);
|
|
1209
1303
|
}
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
parser: "monkeyc-json",
|
|
1231
|
-
plugins: [prettier_plugin_monkeyc_namespaceObject],
|
|
1232
|
-
endOfLine: "lf",
|
|
1233
|
-
});
|
|
1304
|
+
function formatAst(node, monkeyCSource = null) {
|
|
1305
|
+
if ("comments" in node && !monkeyCSource) {
|
|
1306
|
+
// Prettier inserts comments by using the source location to
|
|
1307
|
+
// find the original comment, rather than using the contents
|
|
1308
|
+
// of the comment as reported by the comment nodes themselves.
|
|
1309
|
+
// If all we've got is the ast, rather than the actual
|
|
1310
|
+
// source code, this goes horribly wrong, so just drop all
|
|
1311
|
+
// the comments.
|
|
1312
|
+
delete node.comments;
|
|
1313
|
+
}
|
|
1314
|
+
// If we *do* have the original source, pass that in ahead of the
|
|
1315
|
+
// json. The parser knows to just treat the last line of the input
|
|
1316
|
+
// as the ast itself, and the printers will find what they're
|
|
1317
|
+
// looking for in the source.
|
|
1318
|
+
const source = (monkeyCSource || "") + "\n" + JSON.stringify(node);
|
|
1319
|
+
return standalone_js_default().format(source, {
|
|
1320
|
+
parser: "monkeyc-json",
|
|
1321
|
+
plugins: [(prettier_plugin_monkeyc_default())],
|
|
1322
|
+
endOfLine: "lf",
|
|
1323
|
+
});
|
|
1234
1324
|
}
|
|
1235
|
-
|
|
1236
1325
|
function handleException(state, node, exception) {
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
throw new Error(message);
|
|
1326
|
+
let message;
|
|
1327
|
+
try {
|
|
1328
|
+
const fullName = state.stack
|
|
1329
|
+
.map((e) => e.name)
|
|
1330
|
+
.concat("name" in node && typeof node.name === "string" ? node.name : null)
|
|
1331
|
+
.filter((e) => e != null)
|
|
1332
|
+
.join(".");
|
|
1333
|
+
const location = node.loc && node.loc.source
|
|
1334
|
+
? `${node.loc.source}:${node.start || 0}:${node.end || 0}`
|
|
1335
|
+
: "<unknown>";
|
|
1336
|
+
message = `Got exception \`${exception.toString()}' while processing node ${fullName}:${node.type} from ${location}`;
|
|
1337
|
+
}
|
|
1338
|
+
catch {
|
|
1339
|
+
throw exception;
|
|
1340
|
+
}
|
|
1341
|
+
throw new Error(message);
|
|
1254
1342
|
}
|
|
1255
1343
|
|
|
1256
1344
|
var __webpack_export_target__ = exports;
|