@markw65/monkeyc-optimizer 1.0.1 → 1.0.4
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 +21 -0
- package/build/api.cjs +501 -0
- package/build/optimizer.cjs +418 -4296
- package/build/util.cjs +4159 -0
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -8,4 +8,25 @@ This module is a set of utilities for optimizing Garmin Monkey-C code. Its the e
|
|
|
8
8
|
|
|
9
9
|
Initial release
|
|
10
10
|
|
|
11
|
+
#### 1.0.1
|
|
12
|
+
|
|
13
|
+
- Make a better attempt to fix all the negative constants in api.mir
|
|
14
|
+
- Make export explicitly do a release build by default.
|
|
15
|
+
|
|
16
|
+
#### 1.0.2
|
|
17
|
+
|
|
18
|
+
- Better error reporting when something goes wrong internally
|
|
19
|
+
- Fix an order dependency when processing imports. Previously, if the import statement was seen before the module being imported, we would fail to properly handle the import.
|
|
20
|
+
|
|
21
|
+
### 1.0.3
|
|
22
|
+
|
|
23
|
+
- Split the build into release and debug, so we can exclude code based on (:release) and (:debug)
|
|
24
|
+
- Optimize away `if (constant)`, `while (false)` and `constant ? E1 : E2`. Convert `do BODY while(false)` to `BODY`
|
|
25
|
+
|
|
26
|
+
### 1.0.4
|
|
27
|
+
|
|
28
|
+
- Fix a bug resulting in a failure to fully optimize constants initialized by constant conditional expressions
|
|
29
|
+
- Make the generated .cjs files work better with es modules (vscode doesn't work with es modules, so prettier-extension-monkeyc doesn't care - but for other projects importing this package it improves the behavior)
|
|
30
|
+
- Generate separate debug/release jungle files.
|
|
31
|
+
|
|
11
32
|
---
|
package/build/api.cjs
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
0 && (module.exports = {LiteralIntegerRe,getApiMapping,hasProperty,collectNamespaces,traverseAst,formatAst});
|
|
2
|
+
/******/ (() => { // webpackBootstrap
|
|
3
|
+
/******/ "use strict";
|
|
4
|
+
/******/ // The require scope
|
|
5
|
+
/******/ var __webpack_require__ = {};
|
|
6
|
+
/******/
|
|
7
|
+
/************************************************************************/
|
|
8
|
+
/******/ /* webpack/runtime/define property getters */
|
|
9
|
+
/******/ (() => {
|
|
10
|
+
/******/ // define getter functions for harmony exports
|
|
11
|
+
/******/ __webpack_require__.d = (exports, definition) => {
|
|
12
|
+
/******/ for(var key in definition) {
|
|
13
|
+
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
14
|
+
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
15
|
+
/******/ }
|
|
16
|
+
/******/ }
|
|
17
|
+
/******/ };
|
|
18
|
+
/******/ })();
|
|
19
|
+
/******/
|
|
20
|
+
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
21
|
+
/******/ (() => {
|
|
22
|
+
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
|
23
|
+
/******/ })();
|
|
24
|
+
/******/
|
|
25
|
+
/******/ /* webpack/runtime/make namespace object */
|
|
26
|
+
/******/ (() => {
|
|
27
|
+
/******/ // define __esModule on exports
|
|
28
|
+
/******/ __webpack_require__.r = (exports) => {
|
|
29
|
+
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
30
|
+
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
31
|
+
/******/ }
|
|
32
|
+
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
33
|
+
/******/ };
|
|
34
|
+
/******/ })();
|
|
35
|
+
/******/
|
|
36
|
+
/************************************************************************/
|
|
37
|
+
var __webpack_exports__ = {};
|
|
38
|
+
// ESM COMPAT FLAG
|
|
39
|
+
__webpack_require__.r(__webpack_exports__);
|
|
40
|
+
|
|
41
|
+
// EXPORTS
|
|
42
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
43
|
+
"LiteralIntegerRe": () => (/* binding */ LiteralIntegerRe),
|
|
44
|
+
"collectNamespaces": () => (/* binding */ collectNamespaces),
|
|
45
|
+
"formatAst": () => (/* binding */ formatAst),
|
|
46
|
+
"getApiMapping": () => (/* binding */ getApiMapping),
|
|
47
|
+
"hasProperty": () => (/* binding */ hasProperty),
|
|
48
|
+
"traverseAst": () => (/* binding */ traverseAst)
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
;// CONCATENATED MODULE: external "@markw65/prettier-plugin-monkeyc"
|
|
52
|
+
const prettier_plugin_monkeyc_namespaceObject = require("@markw65/prettier-plugin-monkeyc");
|
|
53
|
+
;// CONCATENATED MODULE: external "fs/promises"
|
|
54
|
+
const promises_namespaceObject = require("fs/promises");
|
|
55
|
+
;// CONCATENATED MODULE: external "prettier/standalone.js"
|
|
56
|
+
const standalone_js_namespaceObject = require("prettier/standalone.js");
|
|
57
|
+
;// CONCATENATED MODULE: external "./util.cjs"
|
|
58
|
+
const external_util_cjs_namespaceObject = require("./util.cjs");
|
|
59
|
+
;// CONCATENATED MODULE: ./src/negative-fixups.js
|
|
60
|
+
/*
|
|
61
|
+
* This is strange. It pretty much has to be a bug in the sdk,
|
|
62
|
+
* but its the same in every sdk.
|
|
63
|
+
*
|
|
64
|
+
* ${sdk}/bin/api.mir describes the Toybox api down to every module,
|
|
65
|
+
* class, function, enum and constant, together with the enum
|
|
66
|
+
* and constant values.
|
|
67
|
+
*
|
|
68
|
+
* The problem is that every enum or constant with a negative
|
|
69
|
+
* value, appears with the corresponding positive value in api.mir.
|
|
70
|
+
* So eg Graphics.COLOR_TRANSPARENT should be -1, but instead, it has
|
|
71
|
+
* the value 1.
|
|
72
|
+
*
|
|
73
|
+
* This is a (currently somewhat ad-hoc) list of the negative constants
|
|
74
|
+
* so we can fix them after reading api.mir.
|
|
75
|
+
*/
|
|
76
|
+
const negativeFixups = [
|
|
77
|
+
"Toybox.Communications.BLE_CONNECTION_UNAVAILABLE",
|
|
78
|
+
"Toybox.Communications.INVALID_HTTP_BODY_IN_REQUEST",
|
|
79
|
+
"Toybox.Communications.REQUEST_CANCELLED",
|
|
80
|
+
"Toybox.Communications.UNSUPPORTED_CONTENT_TYPE_IN_RESPONSE",
|
|
81
|
+
"Toybox.Communications.UNABLE_TO_PROCESS_IMAGE",
|
|
82
|
+
"Toybox.Communications.NETWORK_RESPONSE_OUT_OF_MEMORY",
|
|
83
|
+
"Toybox.Communications.BLE_REQUEST_CANCELLED",
|
|
84
|
+
"Toybox.Communications.INVALID_HTTP_METHOD_IN_REQUEST",
|
|
85
|
+
"Toybox.Communications.BLE_NO_DATA",
|
|
86
|
+
"Toybox.Communications.INVALID_HTTP_HEADER_FIELDS_IN_REQUEST",
|
|
87
|
+
"Toybox.Communications.BLE_ERROR",
|
|
88
|
+
"Toybox.Communications.NETWORK_RESPONSE_TOO_LARGE",
|
|
89
|
+
"Toybox.Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE",
|
|
90
|
+
"Toybox.Communications.BLE_REQUEST_TOO_LARGE",
|
|
91
|
+
"Toybox.Communications.UNABLE_TO_PROCESS_MEDIA",
|
|
92
|
+
"Toybox.Communications.REQUEST_CONNECTION_DROPPED",
|
|
93
|
+
"Toybox.Communications.BLE_UNKNOWN_SEND_ERROR",
|
|
94
|
+
"Toybox.Communications.BLE_QUEUE_FULL",
|
|
95
|
+
"Toybox.Communications.STORAGE_FULL",
|
|
96
|
+
"Toybox.Communications.BLE_SERVER_TIMEOUT",
|
|
97
|
+
"Toybox.Communications.INVALID_HTTP_HEADER_FIELDS_IN_NETWORK_RESPONSE",
|
|
98
|
+
"Toybox.Communications.SECURE_CONNECTION_REQUIRED",
|
|
99
|
+
"Toybox.Communications.NETWORK_REQUEST_TIMED_OUT",
|
|
100
|
+
"Toybox.Communications.BLE_HOST_TIMEOUT",
|
|
101
|
+
"Toybox.Communications.UNABLE_TO_PROCESS_HLS",
|
|
102
|
+
"Toybox.Graphics.COLOR_TRANSPARENT",
|
|
103
|
+
"Toybox.AntPlus.INVALID_SPEED",
|
|
104
|
+
"Toybox.AntPlus.INVALID_CADENCE",
|
|
105
|
+
"Toybox.WatchUi.LAYOUT_VALIGN_START",
|
|
106
|
+
"Toybox.WatchUi.LAYOUT_VALIGN_TOP",
|
|
107
|
+
"Toybox.WatchUi.LAYOUT_VALIGN_BOTTOM",
|
|
108
|
+
"Toybox.WatchUi.LAYOUT_VALIGN_CENTER",
|
|
109
|
+
"Toybox.WatchUi.LAYOUT_HALIGN_RIGHT",
|
|
110
|
+
"Toybox.WatchUi.LAYOUT_HALIGN_CENTER",
|
|
111
|
+
"Toybox.WatchUi.LAYOUT_HALIGN_START",
|
|
112
|
+
"Toybox.WatchUi.LAYOUT_HALIGN_LEFT",
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
;// CONCATENATED MODULE: ./src/api.js
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
const LiteralIntegerRe = /^(0x[0-9a-f]+|\d+)(l)?$/;
|
|
123
|
+
/*
|
|
124
|
+
* This is an unfortunate hack. I want to be able to extract things
|
|
125
|
+
* like the types of all of a Class's variables (in particular the type
|
|
126
|
+
* of each member of Activity.Info), and also map things like enum names
|
|
127
|
+
* to their values (eg to take font names, and color names to their values).
|
|
128
|
+
* The only place I can find this information is in api.mir, which is totally
|
|
129
|
+
* undocumented. The same could be said of compiler.json and simulator.json,
|
|
130
|
+
* but those are at least in a standard format.
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
// Extract all enum values from api.mir
|
|
134
|
+
async function getApiMapping(state) {
|
|
135
|
+
// get the path to the currently active sdk
|
|
136
|
+
const parser = prettier_plugin_monkeyc_namespaceObject.parsers.monkeyc;
|
|
137
|
+
|
|
138
|
+
const sdk = await (0,external_util_cjs_namespaceObject.getSdkPath)();
|
|
139
|
+
|
|
140
|
+
const api = (await promises_namespaceObject.readFile(`${sdk}bin/api.mir`))
|
|
141
|
+
.toString()
|
|
142
|
+
.replace(/\r\n/g, "\n")
|
|
143
|
+
.replace(/^\s*\[.*?\]\s*$/gm, "")
|
|
144
|
+
//.replace(/(COLOR_TRANSPARENT|LAYOUT_[HV]ALIGN_\w+) = (\d+)/gm, "$1 = -$2")
|
|
145
|
+
.replace(/^(\s*type)\s/gm, "$1def ");
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const result = collectNamespaces(parser.parse(api, {}), state);
|
|
149
|
+
negativeFixups.forEach((fixup) => {
|
|
150
|
+
const value = fixup.split(".").reduce((state, part) => {
|
|
151
|
+
const decls = state.decls[part];
|
|
152
|
+
if (!Array.isArray(decls) || decls.length != 1 || !decls[0]) {
|
|
153
|
+
throw `Failed to find and fix negative constant ${fixup}`;
|
|
154
|
+
}
|
|
155
|
+
return decls[0];
|
|
156
|
+
}, result);
|
|
157
|
+
if (value.type != "Literal") {
|
|
158
|
+
throw `Negative constant ${fixup} was not a Literal`;
|
|
159
|
+
}
|
|
160
|
+
if (value.value > 0) {
|
|
161
|
+
value.value = -value.value;
|
|
162
|
+
value.raw = "-" + value.raw;
|
|
163
|
+
} else {
|
|
164
|
+
console.log(`Negative fixup ${fixup} was already negative!`);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
return result;
|
|
168
|
+
} catch (e) {
|
|
169
|
+
console.error(e.toString());
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function hasProperty(obj, prop) {
|
|
174
|
+
return obj && Object.prototype.hasOwnProperty.call(obj, prop);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function collectNamespaces(ast, state) {
|
|
178
|
+
state = state || {};
|
|
179
|
+
if (!state.index) state.index = {};
|
|
180
|
+
if (!state.stack) {
|
|
181
|
+
state.stack = [{ type: "Program", name: "$", fullName: "$" }];
|
|
182
|
+
}
|
|
183
|
+
const checkOne = (ns, name) => {
|
|
184
|
+
if (hasProperty(ns.decls, name)) {
|
|
185
|
+
return ns.decls[name];
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
};
|
|
189
|
+
state.lookup = (node, name, stack) => {
|
|
190
|
+
stack || (stack = state.stack);
|
|
191
|
+
switch (node.type) {
|
|
192
|
+
case "MemberExpression": {
|
|
193
|
+
if (node.property.type != "Identifier" || node.computed) break;
|
|
194
|
+
const [, module] = state.lookup(node.object, name, stack);
|
|
195
|
+
if (module && module.length === 1) {
|
|
196
|
+
const result = checkOne(module[0], node.property.name);
|
|
197
|
+
if (result) {
|
|
198
|
+
return [name || node.property.name, result];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
case "ThisExpression":
|
|
204
|
+
return [name, stack.slice(-1)];
|
|
205
|
+
case "Identifier": {
|
|
206
|
+
if (node.name == "$") {
|
|
207
|
+
return [name || node.name, [stack[0]]];
|
|
208
|
+
}
|
|
209
|
+
for (let i = stack.length; i--; ) {
|
|
210
|
+
const result = checkOne(stack[i], node.name);
|
|
211
|
+
if (result) {
|
|
212
|
+
return [name || node.name, result];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return [null, null];
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
state.traverse = (root) =>
|
|
222
|
+
traverseAst(
|
|
223
|
+
root,
|
|
224
|
+
(node) => {
|
|
225
|
+
try {
|
|
226
|
+
if (state.shouldExclude && state.shouldExclude(node)) {
|
|
227
|
+
// don't visit any children, but do call post
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
switch (node.type) {
|
|
231
|
+
case "Program":
|
|
232
|
+
if (state.stack.length != 1) {
|
|
233
|
+
throw new Error("Unexpected stack length for Program node");
|
|
234
|
+
}
|
|
235
|
+
if (node.source) {
|
|
236
|
+
state.stack[0].source = node.source;
|
|
237
|
+
}
|
|
238
|
+
break;
|
|
239
|
+
case "BlockStatement": {
|
|
240
|
+
const [parent] = state.stack.slice(-1);
|
|
241
|
+
if (
|
|
242
|
+
parent.type != "FunctionDeclaration" &&
|
|
243
|
+
parent.type != "BlockStatement"
|
|
244
|
+
) {
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
// fall through
|
|
248
|
+
}
|
|
249
|
+
case "ClassDeclaration":
|
|
250
|
+
case "FunctionDeclaration":
|
|
251
|
+
case "ModuleDeclaration":
|
|
252
|
+
if (node.id || node.type == "BlockStatement") {
|
|
253
|
+
const [parent] = state.stack.slice(-1);
|
|
254
|
+
const elm = {
|
|
255
|
+
type: node.type,
|
|
256
|
+
name: node.id && node.id.name,
|
|
257
|
+
node,
|
|
258
|
+
};
|
|
259
|
+
state.stack.push(elm);
|
|
260
|
+
elm.fullName = state.stack
|
|
261
|
+
.map((e) => e.name)
|
|
262
|
+
.filter((e) => e != null)
|
|
263
|
+
.join(".");
|
|
264
|
+
if (elm.name) {
|
|
265
|
+
if (!parent.decls) parent.decls = {};
|
|
266
|
+
if (hasProperty(parent.decls, elm.name)) {
|
|
267
|
+
const what =
|
|
268
|
+
node.type == "ModuleDeclaration" ? "type" : "node";
|
|
269
|
+
const e = parent.decls[elm.name].find(
|
|
270
|
+
(d) => d[what] == elm[what]
|
|
271
|
+
);
|
|
272
|
+
if (e != null) {
|
|
273
|
+
e.node = node;
|
|
274
|
+
state.stack.splice(-1, 1, e);
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
parent.decls[elm.name] = [];
|
|
279
|
+
}
|
|
280
|
+
parent.decls[elm.name].push(elm);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break;
|
|
284
|
+
// an EnumDeclaration doesn't create a scope, but
|
|
285
|
+
// it does create a type (if it has a name)
|
|
286
|
+
case "EnumDeclaration": {
|
|
287
|
+
if (!node.id) break;
|
|
288
|
+
const [parent] = state.stack.slice(-1);
|
|
289
|
+
const name = (parent.fullName + "." + node.id.name).replace(
|
|
290
|
+
/^\$\./,
|
|
291
|
+
""
|
|
292
|
+
);
|
|
293
|
+
node.body.members.forEach((m) => ((m.init || m).enumType = name));
|
|
294
|
+
}
|
|
295
|
+
// fall through
|
|
296
|
+
case "TypedefDeclaration": {
|
|
297
|
+
const [parent] = state.stack.slice(-1);
|
|
298
|
+
if (!parent.decls) parent.decls = {};
|
|
299
|
+
if (!hasProperty(parent.decls, node.id.name)) {
|
|
300
|
+
parent.decls[node.id.name] = [];
|
|
301
|
+
}
|
|
302
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(
|
|
303
|
+
parent.decls[node.id.name],
|
|
304
|
+
node.ts ? formatAst(node.ts.argument) : node.id.name
|
|
305
|
+
);
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
case "VariableDeclaration": {
|
|
309
|
+
const [parent] = state.stack.slice(-1);
|
|
310
|
+
if (!parent.decls) parent.decls = {};
|
|
311
|
+
node.declarations.forEach((decl) => {
|
|
312
|
+
if (!hasProperty(parent.decls, decl.id.name)) {
|
|
313
|
+
parent.decls[decl.id.name] = [];
|
|
314
|
+
}
|
|
315
|
+
if (node.kind == "const") {
|
|
316
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(parent.decls[decl.id.name], decl.init);
|
|
317
|
+
if (!hasProperty(state.index, decl.id.name)) {
|
|
318
|
+
state.index[decl.id.name] = [];
|
|
319
|
+
}
|
|
320
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[decl.id.name], parent);
|
|
321
|
+
} else if (decl.id.ts) {
|
|
322
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(
|
|
323
|
+
parent.decls[decl.id.name],
|
|
324
|
+
formatAst(decl.id.ts.argument)
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
case "EnumStringBody": {
|
|
331
|
+
const [parent] = state.stack.slice(-1);
|
|
332
|
+
const values = parent.decls || (parent.decls = {});
|
|
333
|
+
let prev = -1;
|
|
334
|
+
node.members.forEach((m) => {
|
|
335
|
+
let name, init;
|
|
336
|
+
if (m.type == "EnumStringMember") {
|
|
337
|
+
name = m.id.name;
|
|
338
|
+
init = m.init;
|
|
339
|
+
if (
|
|
340
|
+
init.type == "Literal" &&
|
|
341
|
+
LiteralIntegerRe.test(init.raw)
|
|
342
|
+
) {
|
|
343
|
+
prev = init.value;
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
name = m.name;
|
|
347
|
+
prev += 1;
|
|
348
|
+
if (!state.constants) {
|
|
349
|
+
state.constants = {};
|
|
350
|
+
}
|
|
351
|
+
const key = m.enumType ? `${m.enumType}:${prev}` : prev;
|
|
352
|
+
init = state.constants[key];
|
|
353
|
+
if (!init) {
|
|
354
|
+
init = state.constants[key] = {
|
|
355
|
+
type: "Literal",
|
|
356
|
+
value: prev,
|
|
357
|
+
raw: prev.toString(),
|
|
358
|
+
enumType: m.enumType,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (!hasProperty(values, name)) {
|
|
363
|
+
values[name] = [];
|
|
364
|
+
}
|
|
365
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(values[name], init);
|
|
366
|
+
if (!hasProperty(state.index, name)) {
|
|
367
|
+
state.index[name] = [];
|
|
368
|
+
}
|
|
369
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
|
|
370
|
+
});
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (state.pre) return state.pre(node);
|
|
375
|
+
} catch (e) {
|
|
376
|
+
handleException(state, node, e);
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
(node) => {
|
|
380
|
+
try {
|
|
381
|
+
let ret;
|
|
382
|
+
if (state.shouldExclude && state.shouldExclude(node)) {
|
|
383
|
+
// delete the node.
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
if (state.post) ret = state.post(node);
|
|
387
|
+
if (state.stack.slice(-1).pop().node === node) {
|
|
388
|
+
state.stack.pop();
|
|
389
|
+
}
|
|
390
|
+
return ret;
|
|
391
|
+
} catch (e) {
|
|
392
|
+
handleException(state, node, e);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
);
|
|
396
|
+
state.traverse(ast);
|
|
397
|
+
if (state.stack.length != 1) {
|
|
398
|
+
throw new Error("Invalid AST!");
|
|
399
|
+
}
|
|
400
|
+
return state.stack[0];
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/*
|
|
404
|
+
* Traverse the ast rooted at node, calling pre before
|
|
405
|
+
* visiting each node, and post after.
|
|
406
|
+
*
|
|
407
|
+
* - if pre returns false, the node is not traversed, and
|
|
408
|
+
* post is not called;
|
|
409
|
+
* - if pre returns a list of child nodes, only those will
|
|
410
|
+
* be traversed
|
|
411
|
+
* - otherwise all child nodes are traversed
|
|
412
|
+
*
|
|
413
|
+
* - if post returns false, the node it was called on is
|
|
414
|
+
* removed.
|
|
415
|
+
*/
|
|
416
|
+
function traverseAst(node, pre, post) {
|
|
417
|
+
const nodes = pre && pre(node);
|
|
418
|
+
if (nodes === false) return;
|
|
419
|
+
for (const key of nodes || Object.keys(node)) {
|
|
420
|
+
const value = node[key];
|
|
421
|
+
if (!value) continue;
|
|
422
|
+
if (Array.isArray(value)) {
|
|
423
|
+
const deletions = value.reduce((state, obj, i) => {
|
|
424
|
+
const repl = traverseAst(obj, pre, post);
|
|
425
|
+
if (repl === false) {
|
|
426
|
+
if (!state) state = {};
|
|
427
|
+
state[i] = true;
|
|
428
|
+
} else if (repl != null) {
|
|
429
|
+
value[i] = repl;
|
|
430
|
+
}
|
|
431
|
+
return state;
|
|
432
|
+
}, null);
|
|
433
|
+
if (deletions) {
|
|
434
|
+
value.splice(
|
|
435
|
+
0,
|
|
436
|
+
value.length,
|
|
437
|
+
...value.filter((obj, i) => deletions[i] !== true)
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
} else if (typeof value == "object" && value.type) {
|
|
441
|
+
const repl = traverseAst(value, pre, post);
|
|
442
|
+
if (repl === false) {
|
|
443
|
+
delete node[key];
|
|
444
|
+
} else if (repl != null) {
|
|
445
|
+
node[key] = repl;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return post && post(node);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function formatAst(node, options) {
|
|
453
|
+
if (!node.monkeyCSource && node.comments) {
|
|
454
|
+
// Prettier inserts comments by using the source location to
|
|
455
|
+
// find the original comment, rather than using the contents
|
|
456
|
+
// of the comment as reported by the comment nodes themselves.
|
|
457
|
+
// If all we've got is the ast, rather than the actual
|
|
458
|
+
// source code, this goes horribly wrong, so just drop all
|
|
459
|
+
// the comments.
|
|
460
|
+
delete node.comments;
|
|
461
|
+
}
|
|
462
|
+
// If we *do* have the original source, pass that in ahead of the
|
|
463
|
+
// json. The parser knows to just treat the last line of the input
|
|
464
|
+
// as the ast itself, and the printers will find what they're
|
|
465
|
+
// looking for in the source.
|
|
466
|
+
const source =
|
|
467
|
+
(node.monkeyCSource ? node.monkeyCSource + "\n" : "") +
|
|
468
|
+
JSON.stringify(node);
|
|
469
|
+
return standalone_js_namespaceObject.format(source, {
|
|
470
|
+
...(options || {}),
|
|
471
|
+
parser: "monkeyc-json",
|
|
472
|
+
plugins: [prettier_plugin_monkeyc_namespaceObject],
|
|
473
|
+
endOfLine: "lf",
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function handleException(state, node, exception) {
|
|
478
|
+
let message;
|
|
479
|
+
try {
|
|
480
|
+
const fullName = state.stack
|
|
481
|
+
.map((e) => e.name)
|
|
482
|
+
.concat(node.name)
|
|
483
|
+
.filter((e) => e != null)
|
|
484
|
+
.join(".");
|
|
485
|
+
const location = state.stack[0].source
|
|
486
|
+
? `${state.stack[0].source}:${node.start || 0}:${node.end || 0}`
|
|
487
|
+
: "<unknown>";
|
|
488
|
+
message = `Got exception \`${exception.toString()}' while processing node ${fullName}:${
|
|
489
|
+
node.type
|
|
490
|
+
} from ${location}`;
|
|
491
|
+
} catch {
|
|
492
|
+
throw exception;
|
|
493
|
+
}
|
|
494
|
+
throw new Error(message);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
var __webpack_export_target__ = exports;
|
|
498
|
+
for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i];
|
|
499
|
+
if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true });
|
|
500
|
+
/******/ })()
|
|
501
|
+
;
|