@markw65/monkeyc-optimizer 1.0.22 → 1.0.23
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 +12 -1
- package/build/api.cjs +183 -92
- package/build/optimizer.cjs +191 -37
- package/build/src/api.d.ts +2 -1
- package/build/src/ast.d.ts +2 -0
- package/build/src/optimizer.d.ts +3 -3
- package/build/util.cjs +5 -3
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -263,4 +263,15 @@ More fixes found via open source projects.
|
|
|
263
263
|
- Recognize the the variable in a catch clause is a declaration
|
|
264
264
|
|
|
265
265
|
- Breaking change
|
|
266
|
-
- By popular demand, reversed the sense of
|
|
266
|
+
- By popular demand, reversed the sense of `inline*foo`, so now it inlines when foo is _not_ declared as an excludeAnnotation
|
|
267
|
+
|
|
268
|
+
### 1.0.23
|
|
269
|
+
|
|
270
|
+
- Bug Fixes
|
|
271
|
+
|
|
272
|
+
- Don't treat parameters to Method types as undeclared variables
|
|
273
|
+
- eg `var x as (Method(a as Number, b as Number) as Void)` should not report that `a` and `b` are undeclared
|
|
274
|
+
|
|
275
|
+
- Tests
|
|
276
|
+
- Various new tests for module/class/local resolution of symbols
|
|
277
|
+
- Make tests fail by default if the optimizer reports any undefined symbols, and add `@expects` or `checkInvalidSymbols=WARNING` as needed to prevent test failures.
|
package/build/api.cjs
CHANGED
|
@@ -59,7 +59,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
59
59
|
"hasProperty": () => (/* binding */ api_hasProperty),
|
|
60
60
|
"isStateNode": () => (/* binding */ api_isStateNode),
|
|
61
61
|
"sameLookupResult": () => (/* binding */ api_sameLookupResult),
|
|
62
|
-
"traverseAst": () => (/*
|
|
62
|
+
"traverseAst": () => (/* reexport */ ast_traverseAst),
|
|
63
63
|
"variableDeclarationName": () => (/* binding */ api_variableDeclarationName),
|
|
64
64
|
"visitReferences": () => (/* reexport */ visitor_visitReferences)
|
|
65
65
|
});
|
|
@@ -71,10 +71,148 @@ var prettier_plugin_monkeyc_default = /*#__PURE__*/__webpack_require__.n(prettie
|
|
|
71
71
|
const promises_namespaceObject = require("fs/promises");
|
|
72
72
|
;// CONCATENATED MODULE: external "prettier"
|
|
73
73
|
const external_prettier_namespaceObject = require("prettier");
|
|
74
|
+
;// CONCATENATED MODULE: ./src/ast.ts
|
|
75
|
+
/*
|
|
76
|
+
* This ensures that mctreeTypeInfo has every key of MCTreeTypeInfo,
|
|
77
|
+
* and that the corresponding arrays contain every element of the
|
|
78
|
+
* corresponding type.
|
|
79
|
+
*
|
|
80
|
+
* ie, any time mctree.Node changes, we'll get errors here if
|
|
81
|
+
* mctreeTypeInfo needs updating.
|
|
82
|
+
*
|
|
83
|
+
*/
|
|
84
|
+
function _check(x) {
|
|
85
|
+
const y = x;
|
|
86
|
+
x = y;
|
|
87
|
+
}
|
|
88
|
+
const mctreeTypeInfo = {
|
|
89
|
+
ArrayExpression: ["elements"],
|
|
90
|
+
AssignmentExpression: ["left", "right"],
|
|
91
|
+
AttributeList: ["attributes"],
|
|
92
|
+
Attributes: ["elements"],
|
|
93
|
+
BinaryExpression: ["left", "right"],
|
|
94
|
+
Block: [],
|
|
95
|
+
BlockStatement: ["body", "innerComments"],
|
|
96
|
+
BreakStatement: [],
|
|
97
|
+
CallExpression: ["callee", "arguments"],
|
|
98
|
+
CatchClause: ["param", "body"],
|
|
99
|
+
CatchClauses: ["catches"],
|
|
100
|
+
ClassBody: ["body"],
|
|
101
|
+
ClassDeclaration: ["attrs", "id", "superClass", "body"],
|
|
102
|
+
ClassElement: ["item"],
|
|
103
|
+
ConditionalExpression: ["test", "consequent", "alternate"],
|
|
104
|
+
ContinueStatement: [],
|
|
105
|
+
DoWhileStatement: ["body", "test"],
|
|
106
|
+
EnumDeclaration: ["attrs", "id", "body"],
|
|
107
|
+
EnumStringBody: ["members"],
|
|
108
|
+
EnumStringMember: ["id", "init"],
|
|
109
|
+
ExpressionStatement: ["expression"],
|
|
110
|
+
ForStatement: ["init", "test", "body", "update"],
|
|
111
|
+
FunctionDeclaration: ["attrs", "id", "params", "body"],
|
|
112
|
+
Identifier: [],
|
|
113
|
+
IfStatement: ["test", "consequent", "alternate"],
|
|
114
|
+
ImportModule: ["id"],
|
|
115
|
+
InstanceOfCase: ["id"],
|
|
116
|
+
Line: [],
|
|
117
|
+
Literal: [],
|
|
118
|
+
LogicalExpression: ["left", "right"],
|
|
119
|
+
MemberExpression: ["object", "property"],
|
|
120
|
+
MethodDefinition: ["params", "returnType"],
|
|
121
|
+
ModuleDeclaration: ["attrs", "id", "body"],
|
|
122
|
+
MultiLine: [],
|
|
123
|
+
NewExpression: ["callee", "arguments"],
|
|
124
|
+
ObjectExpression: ["properties"],
|
|
125
|
+
ParenthesizedExpression: ["expression"],
|
|
126
|
+
Program: ["body", "comments"],
|
|
127
|
+
Property: ["key", "value"],
|
|
128
|
+
ReturnStatement: ["argument"],
|
|
129
|
+
SequenceExpression: ["expressions"],
|
|
130
|
+
SizedArrayExpression: ["size", "ts"],
|
|
131
|
+
SwitchCase: ["test", "consequent"],
|
|
132
|
+
SwitchStatement: ["discriminant", "cases"],
|
|
133
|
+
ThisExpression: [],
|
|
134
|
+
ThrowStatement: ["argument"],
|
|
135
|
+
TryStatement: ["block", "handler", "finalizer"],
|
|
136
|
+
TypedefDeclaration: ["attrs", "id", "ts"],
|
|
137
|
+
TypeSpecList: ["ts"],
|
|
138
|
+
TypeSpecPart: ["body", "callspec", "generics"],
|
|
139
|
+
UnaryExpression: ["argument"],
|
|
140
|
+
UpdateExpression: ["argument"],
|
|
141
|
+
Using: ["id", "as"],
|
|
142
|
+
VariableDeclaration: ["attrs", "declarations"],
|
|
143
|
+
VariableDeclarator: ["id", "init"],
|
|
144
|
+
WhileStatement: ["test", "body"],
|
|
145
|
+
};
|
|
146
|
+
function isMCTreeNode(node) {
|
|
147
|
+
return node ? typeof node === "object" && "type" in node : false;
|
|
148
|
+
}
|
|
149
|
+
/*
|
|
150
|
+
* Traverse the ast rooted at node, calling pre before
|
|
151
|
+
* visiting each node, and post after.
|
|
152
|
+
*
|
|
153
|
+
* - if pre returns false, the node is not traversed, and
|
|
154
|
+
* post is not called;
|
|
155
|
+
* - if pre returns a list of child nodes, only those will
|
|
156
|
+
* be traversed
|
|
157
|
+
* - otherwise all child nodes are traversed
|
|
158
|
+
*
|
|
159
|
+
* - if post returns false, the node it was called on is
|
|
160
|
+
* removed.
|
|
161
|
+
*/
|
|
162
|
+
function ast_traverseAst(node, pre, post) {
|
|
163
|
+
const nodes = pre && pre(node);
|
|
164
|
+
if (nodes === false)
|
|
165
|
+
return;
|
|
166
|
+
if (!mctreeTypeInfo[node.type]) {
|
|
167
|
+
throw new Error("what?");
|
|
168
|
+
}
|
|
169
|
+
for (const key of nodes || mctreeTypeInfo[node.type]) {
|
|
170
|
+
const value = node[key];
|
|
171
|
+
if (!value)
|
|
172
|
+
continue;
|
|
173
|
+
if (Array.isArray(value)) {
|
|
174
|
+
const values = value;
|
|
175
|
+
const deletions = values.reduce((state, obj, i) => {
|
|
176
|
+
if (isMCTreeNode(obj)) {
|
|
177
|
+
const repl = ast_traverseAst(obj, pre, post);
|
|
178
|
+
if (repl === false) {
|
|
179
|
+
if (!state)
|
|
180
|
+
state = {};
|
|
181
|
+
state[i] = true;
|
|
182
|
+
}
|
|
183
|
+
else if (repl != null) {
|
|
184
|
+
if (!state)
|
|
185
|
+
state = {};
|
|
186
|
+
values[i] = repl;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return state;
|
|
190
|
+
}, null);
|
|
191
|
+
if (deletions) {
|
|
192
|
+
values.splice(0, values.length, ...values.filter((obj, i) => deletions[i] !== true).flat(1));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else if (isMCTreeNode(value)) {
|
|
196
|
+
const repl = ast_traverseAst(value, pre, post);
|
|
197
|
+
if (repl === false) {
|
|
198
|
+
delete node[key];
|
|
199
|
+
}
|
|
200
|
+
else if (repl != null) {
|
|
201
|
+
if (Array.isArray(repl)) {
|
|
202
|
+
throw new Error("Array returned by traverseAst in Node context");
|
|
203
|
+
}
|
|
204
|
+
node[key] = repl;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return post && post(node);
|
|
209
|
+
}
|
|
210
|
+
|
|
74
211
|
;// CONCATENATED MODULE: external "./api.cjs"
|
|
75
212
|
const external_api_cjs_namespaceObject = require("./api.cjs");
|
|
76
213
|
;// CONCATENATED MODULE: ./src/variable-renamer.ts
|
|
77
214
|
|
|
215
|
+
|
|
78
216
|
function variable_renamer_renameVariable(state, locals, declName) {
|
|
79
217
|
const map = locals.map;
|
|
80
218
|
if (!hasProperty(map, declName))
|
|
@@ -131,6 +269,7 @@ function variable_renamer_renameVariable(state, locals, declName) {
|
|
|
131
269
|
;// CONCATENATED MODULE: ./src/inliner.ts
|
|
132
270
|
|
|
133
271
|
|
|
272
|
+
|
|
134
273
|
function getArgSafety(state, func, args, requireAll) {
|
|
135
274
|
// determine whether decl might be changed by a function call
|
|
136
275
|
// or assignment during the evaluation of FunctionStateNode.
|
|
@@ -198,25 +337,12 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
198
337
|
if (allSafe && requireAll)
|
|
199
338
|
return true;
|
|
200
339
|
let callSeen = false;
|
|
201
|
-
let ok = true;
|
|
202
340
|
const params = Object.fromEntries(func.node.params.map((param, i) => [variableDeclarationName(param), i]));
|
|
203
|
-
const getLoc = (node) => (Array.isArray(node) ? node[0].start : node.start) || 0;
|
|
204
341
|
// look for uses of "unsafe" args that occur after a call.
|
|
205
342
|
// use post to do the checking, because arguments are evaluated
|
|
206
343
|
// prior to the call, so eg "return f(x.y);" is fine, but
|
|
207
344
|
// "return f()+x.y" is not.
|
|
208
|
-
|
|
209
|
-
// We also have to use a "pre" to ensure that child nodes are
|
|
210
|
-
// visited in source order (otherwise we could visit x.y before f()
|
|
211
|
-
// in the above example)
|
|
212
|
-
traverseAst(func.node.body, (node) => {
|
|
213
|
-
return Object.entries(node)
|
|
214
|
-
.filter((kv) => Array.isArray(kv[1])
|
|
215
|
-
? kv[1].length !== 0 && hasProperty(kv[1][0], "type")
|
|
216
|
-
: hasProperty(kv[1], "type"))
|
|
217
|
-
.sort(([, a], [, b]) => getLoc(a) - getLoc(b))
|
|
218
|
-
.map(([key]) => key);
|
|
219
|
-
}, (node) => {
|
|
345
|
+
traverseAst(func.node.body, null, (node) => {
|
|
220
346
|
switch (node.type) {
|
|
221
347
|
case "AssignmentExpression":
|
|
222
348
|
case "UpdateExpression": {
|
|
@@ -726,6 +852,20 @@ function visitor_visitReferences(state, ast, name, defn, callback) {
|
|
|
726
852
|
return ["object"];
|
|
727
853
|
}
|
|
728
854
|
break;
|
|
855
|
+
case "MethodDefinition": {
|
|
856
|
+
if (!state.inType) {
|
|
857
|
+
throw new Error("Method definition outside of type!");
|
|
858
|
+
}
|
|
859
|
+
if (node.params) {
|
|
860
|
+
node.params.forEach((param) => {
|
|
861
|
+
if (param.type == "BinaryExpression") {
|
|
862
|
+
state.traverse(param.right);
|
|
863
|
+
state.inType = true;
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
return ["returnType"];
|
|
868
|
+
}
|
|
729
869
|
}
|
|
730
870
|
return null;
|
|
731
871
|
};
|
|
@@ -741,6 +881,7 @@ function visitor_visitReferences(state, ast, name, defn, callback) {
|
|
|
741
881
|
|
|
742
882
|
|
|
743
883
|
|
|
884
|
+
|
|
744
885
|
function collectClassInfo(state) {
|
|
745
886
|
const toybox = state.stack[0].decls["Toybox"][0];
|
|
746
887
|
const lang = toybox.decls["Lang"][0];
|
|
@@ -822,7 +963,9 @@ function getFileSources(fnMap) {
|
|
|
822
963
|
fs
|
|
823
964
|
.readFile(name)
|
|
824
965
|
.then((data) => (value.monkeyCSource = data.toString().replace(/\r\n/g, "\n"))));
|
|
825
|
-
})).then(() => {
|
|
966
|
+
})).then(() => {
|
|
967
|
+
return;
|
|
968
|
+
});
|
|
826
969
|
}
|
|
827
970
|
function getFileASTs(fnMap) {
|
|
828
971
|
return getFileSources(fnMap).then(() => Object.entries(fnMap).reduce((ok, [name, value]) => {
|
|
@@ -885,6 +1028,7 @@ async function analyze(fnMap, barrelList, config) {
|
|
|
885
1028
|
node.body = null;
|
|
886
1029
|
break;
|
|
887
1030
|
}
|
|
1031
|
+
// falls through
|
|
888
1032
|
case "ModuleDeclaration":
|
|
889
1033
|
case "ClassDeclaration": {
|
|
890
1034
|
const [scope] = state.stack.slice(-1);
|
|
@@ -928,7 +1072,7 @@ async function analyze(fnMap, barrelList, config) {
|
|
|
928
1072
|
if (diagnosticType &&
|
|
929
1073
|
!config?.compilerOptions?.includes("--Eno-invalid-symbol")) {
|
|
930
1074
|
const checkTypes = config?.typeCheckLevel && config.typeCheckLevel !== "Off";
|
|
931
|
-
Object.entries(fnMap).forEach(([
|
|
1075
|
+
Object.entries(fnMap).forEach(([, v]) => {
|
|
932
1076
|
visitReferences(state, v.ast, null, false, (node, results, error) => {
|
|
933
1077
|
if (!error)
|
|
934
1078
|
return undefined;
|
|
@@ -1273,7 +1417,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
1273
1417
|
case "ConditionalExpression":
|
|
1274
1418
|
case "IfStatement":
|
|
1275
1419
|
case "DoWhileStatement":
|
|
1276
|
-
case "WhileStatement":
|
|
1420
|
+
case "WhileStatement": {
|
|
1277
1421
|
const test = (state.traverse(node.test) ||
|
|
1278
1422
|
node.test);
|
|
1279
1423
|
const [value, type] = getNodeValue(test);
|
|
@@ -1305,6 +1449,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
1305
1449
|
}
|
|
1306
1450
|
}
|
|
1307
1451
|
return null;
|
|
1452
|
+
}
|
|
1308
1453
|
case "EnumDeclaration":
|
|
1309
1454
|
return false;
|
|
1310
1455
|
case "ForStatement": {
|
|
@@ -1739,6 +1884,8 @@ const external_sdk_util_cjs_namespaceObject = require("./sdk-util.cjs");
|
|
|
1739
1884
|
|
|
1740
1885
|
|
|
1741
1886
|
|
|
1887
|
+
|
|
1888
|
+
|
|
1742
1889
|
/*
|
|
1743
1890
|
* This is an unfortunate hack. I want to be able to extract things
|
|
1744
1891
|
* like the types of all of a Class's variables (in particular the type
|
|
@@ -1786,8 +1933,9 @@ async function api_getApiMapping(state, barrelList) {
|
|
|
1786
1933
|
return decls[0];
|
|
1787
1934
|
}, result);
|
|
1788
1935
|
const value = api_isStateNode(vs) ? vs.node : vs;
|
|
1789
|
-
if (value
|
|
1790
|
-
(value.type !== "
|
|
1936
|
+
if (!value ||
|
|
1937
|
+
(value.type !== "EnumStringMember" &&
|
|
1938
|
+
(value.type !== "VariableDeclarator" || value.kind != "const"))) {
|
|
1791
1939
|
throw `Negative constant ${fixup} did not refer to a constant`;
|
|
1792
1940
|
}
|
|
1793
1941
|
const init = getLiteralNode(value.init);
|
|
@@ -1835,8 +1983,9 @@ function checkOne(state, ns, decls, node, isStatic) {
|
|
|
1835
1983
|
return null;
|
|
1836
1984
|
}
|
|
1837
1985
|
return cls.superClass.reduce((result, sup) => {
|
|
1838
|
-
const
|
|
1839
|
-
|
|
1986
|
+
const sdecls = sup[decls];
|
|
1987
|
+
const next = api_hasProperty(sdecls, node.name)
|
|
1988
|
+
? sdecls[node.name]
|
|
1840
1989
|
: superChain(sup);
|
|
1841
1990
|
return next ? (result ? result.concat(next) : next) : result;
|
|
1842
1991
|
}, null);
|
|
@@ -1859,8 +2008,9 @@ function checkOne(state, ns, decls, node, isStatic) {
|
|
|
1859
2008
|
}, null);
|
|
1860
2009
|
};
|
|
1861
2010
|
if (api_isStateNode(ns)) {
|
|
1862
|
-
|
|
1863
|
-
|
|
2011
|
+
const ndecls = ns[decls];
|
|
2012
|
+
if (api_hasProperty(ndecls, node.name)) {
|
|
2013
|
+
return ndecls[node.name];
|
|
1864
2014
|
}
|
|
1865
2015
|
switch (ns.type) {
|
|
1866
2016
|
case "ClassDeclaration":
|
|
@@ -2025,14 +2175,15 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
2025
2175
|
let low = 0, high = ast.comments.length;
|
|
2026
2176
|
while (high > low) {
|
|
2027
2177
|
const mid = (low + high) >> 1;
|
|
2028
|
-
if (ast.comments[mid].start < node.start) {
|
|
2178
|
+
if ((ast.comments[mid].start || 0) < node.start) {
|
|
2029
2179
|
low = mid + 1;
|
|
2030
2180
|
}
|
|
2031
2181
|
else {
|
|
2032
2182
|
high = mid;
|
|
2033
2183
|
}
|
|
2034
2184
|
}
|
|
2035
|
-
while (high < ast.comments.length &&
|
|
2185
|
+
while (high < ast.comments.length &&
|
|
2186
|
+
(ast.comments[high].end || 0) < node.end) {
|
|
2036
2187
|
high++;
|
|
2037
2188
|
}
|
|
2038
2189
|
if (high > low) {
|
|
@@ -2048,7 +2199,7 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
2048
2199
|
? { ...elm }
|
|
2049
2200
|
: elm);
|
|
2050
2201
|
state.inType = false;
|
|
2051
|
-
state.traverse = (root) =>
|
|
2202
|
+
state.traverse = (root) => ast_traverseAst(root, (node) => {
|
|
2052
2203
|
try {
|
|
2053
2204
|
if (state.shouldExclude && state.shouldExclude(node)) {
|
|
2054
2205
|
// don't visit any children, but do call post
|
|
@@ -2340,67 +2491,6 @@ function api_collectNamespaces(ast, stateIn) {
|
|
|
2340
2491
|
}
|
|
2341
2492
|
return state.stack[0];
|
|
2342
2493
|
}
|
|
2343
|
-
function isMCTreeNode(node) {
|
|
2344
|
-
return node ? typeof node === "object" && "type" in node : false;
|
|
2345
|
-
}
|
|
2346
|
-
/*
|
|
2347
|
-
* Traverse the ast rooted at node, calling pre before
|
|
2348
|
-
* visiting each node, and post after.
|
|
2349
|
-
*
|
|
2350
|
-
* - if pre returns false, the node is not traversed, and
|
|
2351
|
-
* post is not called;
|
|
2352
|
-
* - if pre returns a list of child nodes, only those will
|
|
2353
|
-
* be traversed
|
|
2354
|
-
* - otherwise all child nodes are traversed
|
|
2355
|
-
*
|
|
2356
|
-
* - if post returns false, the node it was called on is
|
|
2357
|
-
* removed.
|
|
2358
|
-
*/
|
|
2359
|
-
function api_traverseAst(node, pre, post) {
|
|
2360
|
-
const nodes = pre && pre(node);
|
|
2361
|
-
if (nodes === false)
|
|
2362
|
-
return;
|
|
2363
|
-
for (const key of nodes || Object.keys(node)) {
|
|
2364
|
-
const value = node[key];
|
|
2365
|
-
if (!value)
|
|
2366
|
-
continue;
|
|
2367
|
-
if (Array.isArray(value)) {
|
|
2368
|
-
const values = value;
|
|
2369
|
-
const deletions = values.reduce((state, obj, i) => {
|
|
2370
|
-
if (isMCTreeNode(obj)) {
|
|
2371
|
-
const repl = api_traverseAst(obj, pre, post);
|
|
2372
|
-
if (repl === false) {
|
|
2373
|
-
if (!state)
|
|
2374
|
-
state = {};
|
|
2375
|
-
state[i] = true;
|
|
2376
|
-
}
|
|
2377
|
-
else if (repl != null) {
|
|
2378
|
-
if (!state)
|
|
2379
|
-
state = {};
|
|
2380
|
-
values[i] = repl;
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
return state;
|
|
2384
|
-
}, null);
|
|
2385
|
-
if (deletions) {
|
|
2386
|
-
values.splice(0, values.length, ...values.filter((obj, i) => deletions[i] !== true).flat(1));
|
|
2387
|
-
}
|
|
2388
|
-
}
|
|
2389
|
-
else if (isMCTreeNode(value)) {
|
|
2390
|
-
const repl = api_traverseAst(value, pre, post);
|
|
2391
|
-
if (repl === false) {
|
|
2392
|
-
delete node[key];
|
|
2393
|
-
}
|
|
2394
|
-
else if (repl != null) {
|
|
2395
|
-
if (Array.isArray(repl)) {
|
|
2396
|
-
throw new Error("Array returned by traverseAst in Node context");
|
|
2397
|
-
}
|
|
2398
|
-
node[key] = repl;
|
|
2399
|
-
}
|
|
2400
|
-
}
|
|
2401
|
-
}
|
|
2402
|
-
return post && post(node);
|
|
2403
|
-
}
|
|
2404
2494
|
function api_formatAst(node, monkeyCSource = null) {
|
|
2405
2495
|
/*
|
|
2406
2496
|
* The estree printer sometimes looks at the parent node without
|
|
@@ -2454,9 +2544,10 @@ function handleException(state, node, exception) {
|
|
|
2454
2544
|
exception = new Error(message);
|
|
2455
2545
|
}
|
|
2456
2546
|
}
|
|
2457
|
-
|
|
2547
|
+
catch (ex) {
|
|
2458
2548
|
throw exception;
|
|
2459
2549
|
}
|
|
2550
|
+
throw exception;
|
|
2460
2551
|
}
|
|
2461
2552
|
function findUsing(state, stack, using) {
|
|
2462
2553
|
if (using.module)
|
|
@@ -2503,9 +2594,9 @@ function findUsingForNode(state, stack, i, node, isType) {
|
|
|
2503
2594
|
for (let j = si.imports.length; j--;) {
|
|
2504
2595
|
const using = si.imports[j];
|
|
2505
2596
|
const module = findUsing(state, stack, using);
|
|
2506
|
-
if (
|
|
2507
|
-
if (api_hasProperty(
|
|
2508
|
-
return
|
|
2597
|
+
if (module) {
|
|
2598
|
+
if (api_hasProperty(module.type_decls, node.name)) {
|
|
2599
|
+
return module.type_decls[node.name];
|
|
2509
2600
|
}
|
|
2510
2601
|
}
|
|
2511
2602
|
}
|
package/build/optimizer.cjs
CHANGED
|
@@ -9858,7 +9858,7 @@ const external_util_cjs_namespaceObject = require("./util.cjs");
|
|
|
9858
9858
|
async function build_project(product, options, lineCallback) {
|
|
9859
9859
|
const { workspace, program, jungleFiles, developerKeyPath, simulatorBuild, releaseBuild, testBuild, compilerOptions, compilerWarnings, typeCheckLevel, returnCommand, } = options;
|
|
9860
9860
|
const sdk = await (0,external_sdk_util_cjs_namespaceObject.getSdkPath)();
|
|
9861
|
-
|
|
9861
|
+
const extraArgs = [];
|
|
9862
9862
|
if (compilerOptions) {
|
|
9863
9863
|
extraArgs.push(...compilerOptions.split(/\s+/));
|
|
9864
9864
|
}
|
|
@@ -9894,6 +9894,9 @@ async function build_project(product, options, lineCallback) {
|
|
|
9894
9894
|
else if (testBuild) {
|
|
9895
9895
|
throw new Error("Building for tests requires a device to build for!");
|
|
9896
9896
|
}
|
|
9897
|
+
if (!program || !jungleFiles || !developerKeyPath || !workspace) {
|
|
9898
|
+
throw new Error("Required arguments were missing!");
|
|
9899
|
+
}
|
|
9897
9900
|
const exe = external_path_.resolve(sdk, "bin", external_sdk_util_cjs_namespaceObject.isWin ? "monkeyc.bat" : "monkeyc");
|
|
9898
9901
|
const args = [
|
|
9899
9902
|
["-o", program],
|
|
@@ -9928,9 +9931,8 @@ async function readManifest(manifest) {
|
|
|
9928
9931
|
return (0,xml2js.parseStringPromise)(data.toString(), { trim: true });
|
|
9929
9932
|
}
|
|
9930
9933
|
async function writeManifest(filename, xml) {
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
return promises_namespaceObject.writeFile(filename, text);
|
|
9934
|
+
const builder = new xml2js.Builder();
|
|
9935
|
+
return promises_namespaceObject.writeFile(filename, builder.buildObject(xml));
|
|
9934
9936
|
}
|
|
9935
9937
|
function manifestProducts(manifest) {
|
|
9936
9938
|
const app = manifest["iq:manifest"]["iq:application"] ||
|
|
@@ -10228,7 +10230,7 @@ function resolve_node_by_path(state, path) {
|
|
|
10228
10230
|
}
|
|
10229
10231
|
if (!s[n] && s["."]) {
|
|
10230
10232
|
const sdot = s["."];
|
|
10231
|
-
|
|
10233
|
+
const resolved = resolve_node_list(state, sdot);
|
|
10232
10234
|
if (!resolved.length)
|
|
10233
10235
|
return undefined;
|
|
10234
10236
|
const r = resolved[0][n];
|
|
@@ -10317,11 +10319,11 @@ async function resolve_literals(qualifier, default_source, deviceInfo) {
|
|
|
10317
10319
|
return resolve_file_list(v.values);
|
|
10318
10320
|
}
|
|
10319
10321
|
let resolved = resolve_filename(v, default_source);
|
|
10320
|
-
if (/[
|
|
10322
|
+
if (/[*?[\]{}]/.test(resolved)) {
|
|
10321
10323
|
// Jungle files can contain "./**.mc" which is supposed to match
|
|
10322
10324
|
// any mc file under "./". The standard way to express that
|
|
10323
10325
|
// is "./**/*.mc", which is what glob expects, so translate.
|
|
10324
|
-
resolved = resolved.replace(/[
|
|
10326
|
+
resolved = resolved.replace(/[\\/]\*\*([^\\/])/g, "/**/*$1");
|
|
10325
10327
|
const match = await (0,external_util_cjs_namespaceObject.globa)(resolved);
|
|
10326
10328
|
return match.length ? resolved : null;
|
|
10327
10329
|
}
|
|
@@ -10595,7 +10597,7 @@ function resolve_barrel(barrel, barrelDir, products, options) {
|
|
|
10595
10597
|
const sha1 = external_crypto_namespaceObject.createHash("sha1")
|
|
10596
10598
|
.update(barrel, "binary")
|
|
10597
10599
|
.digest("base64")
|
|
10598
|
-
.replace(/[
|
|
10600
|
+
.replace(/[/=+]/g, "");
|
|
10599
10601
|
const localPath = external_path_.resolve(barrelDir, `${external_path_.basename(barrel, ".barrel")}-${sha1}`);
|
|
10600
10602
|
rawBarrel = external_path_.resolve(localPath, "barrel.jungle");
|
|
10601
10603
|
promise = promise.then(() => promises_namespaceObject.stat(localPath)
|
|
@@ -10745,7 +10747,9 @@ async function get_jungle_and_barrels(jungleFiles, defaultProducts, options) {
|
|
|
10745
10747
|
targets.push({ product, qualifier, shape });
|
|
10746
10748
|
return resolve_barrels(product, qualifier, barrels, products, options);
|
|
10747
10749
|
})
|
|
10748
|
-
.then(() => {
|
|
10750
|
+
.then(() => {
|
|
10751
|
+
return;
|
|
10752
|
+
});
|
|
10749
10753
|
};
|
|
10750
10754
|
products.forEach((product) => {
|
|
10751
10755
|
if ((0,external_api_cjs_namespaceObject.hasProperty)(state, product)) {
|
|
@@ -10788,11 +10792,151 @@ function simulateProgram(prg, device, test = false, logger) {
|
|
|
10788
10792
|
const args = [prg, device];
|
|
10789
10793
|
if (test)
|
|
10790
10794
|
args.push("-t");
|
|
10791
|
-
return (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => (0,external_util_cjs_namespaceObject.spawnByLine)(external_path_.resolve(sdk, "bin", "monkeydo"), args, logger || ((line) => console.log(line))).then(() => {
|
|
10795
|
+
return (0,external_sdk_util_cjs_namespaceObject.getSdkPath)().then((sdk) => (0,external_util_cjs_namespaceObject.spawnByLine)(external_path_.resolve(sdk, "bin", "monkeydo"), args, logger || ((line) => console.log(line))).then(() => {
|
|
10796
|
+
return;
|
|
10797
|
+
}));
|
|
10798
|
+
}
|
|
10799
|
+
|
|
10800
|
+
;// CONCATENATED MODULE: ./src/ast.ts
|
|
10801
|
+
/*
|
|
10802
|
+
* This ensures that mctreeTypeInfo has every key of MCTreeTypeInfo,
|
|
10803
|
+
* and that the corresponding arrays contain every element of the
|
|
10804
|
+
* corresponding type.
|
|
10805
|
+
*
|
|
10806
|
+
* ie, any time mctree.Node changes, we'll get errors here if
|
|
10807
|
+
* mctreeTypeInfo needs updating.
|
|
10808
|
+
*
|
|
10809
|
+
*/
|
|
10810
|
+
function _check(x) {
|
|
10811
|
+
const y = x;
|
|
10812
|
+
x = y;
|
|
10813
|
+
}
|
|
10814
|
+
const mctreeTypeInfo = {
|
|
10815
|
+
ArrayExpression: ["elements"],
|
|
10816
|
+
AssignmentExpression: ["left", "right"],
|
|
10817
|
+
AttributeList: ["attributes"],
|
|
10818
|
+
Attributes: ["elements"],
|
|
10819
|
+
BinaryExpression: ["left", "right"],
|
|
10820
|
+
Block: [],
|
|
10821
|
+
BlockStatement: ["body", "innerComments"],
|
|
10822
|
+
BreakStatement: [],
|
|
10823
|
+
CallExpression: ["callee", "arguments"],
|
|
10824
|
+
CatchClause: ["param", "body"],
|
|
10825
|
+
CatchClauses: ["catches"],
|
|
10826
|
+
ClassBody: ["body"],
|
|
10827
|
+
ClassDeclaration: ["attrs", "id", "superClass", "body"],
|
|
10828
|
+
ClassElement: ["item"],
|
|
10829
|
+
ConditionalExpression: ["test", "consequent", "alternate"],
|
|
10830
|
+
ContinueStatement: [],
|
|
10831
|
+
DoWhileStatement: ["body", "test"],
|
|
10832
|
+
EnumDeclaration: ["attrs", "id", "body"],
|
|
10833
|
+
EnumStringBody: ["members"],
|
|
10834
|
+
EnumStringMember: ["id", "init"],
|
|
10835
|
+
ExpressionStatement: ["expression"],
|
|
10836
|
+
ForStatement: ["init", "test", "body", "update"],
|
|
10837
|
+
FunctionDeclaration: ["attrs", "id", "params", "body"],
|
|
10838
|
+
Identifier: [],
|
|
10839
|
+
IfStatement: ["test", "consequent", "alternate"],
|
|
10840
|
+
ImportModule: ["id"],
|
|
10841
|
+
InstanceOfCase: ["id"],
|
|
10842
|
+
Line: [],
|
|
10843
|
+
Literal: [],
|
|
10844
|
+
LogicalExpression: ["left", "right"],
|
|
10845
|
+
MemberExpression: ["object", "property"],
|
|
10846
|
+
MethodDefinition: ["params", "returnType"],
|
|
10847
|
+
ModuleDeclaration: ["attrs", "id", "body"],
|
|
10848
|
+
MultiLine: [],
|
|
10849
|
+
NewExpression: ["callee", "arguments"],
|
|
10850
|
+
ObjectExpression: ["properties"],
|
|
10851
|
+
ParenthesizedExpression: ["expression"],
|
|
10852
|
+
Program: ["body", "comments"],
|
|
10853
|
+
Property: ["key", "value"],
|
|
10854
|
+
ReturnStatement: ["argument"],
|
|
10855
|
+
SequenceExpression: ["expressions"],
|
|
10856
|
+
SizedArrayExpression: ["size", "ts"],
|
|
10857
|
+
SwitchCase: ["test", "consequent"],
|
|
10858
|
+
SwitchStatement: ["discriminant", "cases"],
|
|
10859
|
+
ThisExpression: [],
|
|
10860
|
+
ThrowStatement: ["argument"],
|
|
10861
|
+
TryStatement: ["block", "handler", "finalizer"],
|
|
10862
|
+
TypedefDeclaration: ["attrs", "id", "ts"],
|
|
10863
|
+
TypeSpecList: ["ts"],
|
|
10864
|
+
TypeSpecPart: ["body", "callspec", "generics"],
|
|
10865
|
+
UnaryExpression: ["argument"],
|
|
10866
|
+
UpdateExpression: ["argument"],
|
|
10867
|
+
Using: ["id", "as"],
|
|
10868
|
+
VariableDeclaration: ["attrs", "declarations"],
|
|
10869
|
+
VariableDeclarator: ["id", "init"],
|
|
10870
|
+
WhileStatement: ["test", "body"],
|
|
10871
|
+
};
|
|
10872
|
+
function isMCTreeNode(node) {
|
|
10873
|
+
return node ? typeof node === "object" && "type" in node : false;
|
|
10874
|
+
}
|
|
10875
|
+
/*
|
|
10876
|
+
* Traverse the ast rooted at node, calling pre before
|
|
10877
|
+
* visiting each node, and post after.
|
|
10878
|
+
*
|
|
10879
|
+
* - if pre returns false, the node is not traversed, and
|
|
10880
|
+
* post is not called;
|
|
10881
|
+
* - if pre returns a list of child nodes, only those will
|
|
10882
|
+
* be traversed
|
|
10883
|
+
* - otherwise all child nodes are traversed
|
|
10884
|
+
*
|
|
10885
|
+
* - if post returns false, the node it was called on is
|
|
10886
|
+
* removed.
|
|
10887
|
+
*/
|
|
10888
|
+
function traverseAst(node, pre, post) {
|
|
10889
|
+
const nodes = pre && pre(node);
|
|
10890
|
+
if (nodes === false)
|
|
10891
|
+
return;
|
|
10892
|
+
if (!mctreeTypeInfo[node.type]) {
|
|
10893
|
+
throw new Error("what?");
|
|
10894
|
+
}
|
|
10895
|
+
for (const key of nodes || mctreeTypeInfo[node.type]) {
|
|
10896
|
+
const value = node[key];
|
|
10897
|
+
if (!value)
|
|
10898
|
+
continue;
|
|
10899
|
+
if (Array.isArray(value)) {
|
|
10900
|
+
const values = value;
|
|
10901
|
+
const deletions = values.reduce((state, obj, i) => {
|
|
10902
|
+
if (isMCTreeNode(obj)) {
|
|
10903
|
+
const repl = traverseAst(obj, pre, post);
|
|
10904
|
+
if (repl === false) {
|
|
10905
|
+
if (!state)
|
|
10906
|
+
state = {};
|
|
10907
|
+
state[i] = true;
|
|
10908
|
+
}
|
|
10909
|
+
else if (repl != null) {
|
|
10910
|
+
if (!state)
|
|
10911
|
+
state = {};
|
|
10912
|
+
values[i] = repl;
|
|
10913
|
+
}
|
|
10914
|
+
}
|
|
10915
|
+
return state;
|
|
10916
|
+
}, null);
|
|
10917
|
+
if (deletions) {
|
|
10918
|
+
values.splice(0, values.length, ...values.filter((obj, i) => deletions[i] !== true).flat(1));
|
|
10919
|
+
}
|
|
10920
|
+
}
|
|
10921
|
+
else if (isMCTreeNode(value)) {
|
|
10922
|
+
const repl = traverseAst(value, pre, post);
|
|
10923
|
+
if (repl === false) {
|
|
10924
|
+
delete node[key];
|
|
10925
|
+
}
|
|
10926
|
+
else if (repl != null) {
|
|
10927
|
+
if (Array.isArray(repl)) {
|
|
10928
|
+
throw new Error("Array returned by traverseAst in Node context");
|
|
10929
|
+
}
|
|
10930
|
+
node[key] = repl;
|
|
10931
|
+
}
|
|
10932
|
+
}
|
|
10933
|
+
}
|
|
10934
|
+
return post && post(node);
|
|
10792
10935
|
}
|
|
10793
10936
|
|
|
10794
10937
|
;// CONCATENATED MODULE: ./src/variable-renamer.ts
|
|
10795
10938
|
|
|
10939
|
+
|
|
10796
10940
|
function renameVariable(state, locals, declName) {
|
|
10797
10941
|
const map = locals.map;
|
|
10798
10942
|
if (!(0,external_api_cjs_namespaceObject.hasProperty)(map, declName))
|
|
@@ -10809,7 +10953,7 @@ function renameVariable(state, locals, declName) {
|
|
|
10809
10953
|
// more conflicts
|
|
10810
10954
|
locals.inners = {};
|
|
10811
10955
|
const inners = locals.inners;
|
|
10812
|
-
|
|
10956
|
+
traverseAst(locals.node, (node) => {
|
|
10813
10957
|
if (node.type === "VariableDeclarator") {
|
|
10814
10958
|
inners[(0,external_api_cjs_namespaceObject.variableDeclarationName)(node.id)] = true;
|
|
10815
10959
|
}
|
|
@@ -10849,6 +10993,7 @@ function renameVariable(state, locals, declName) {
|
|
|
10849
10993
|
;// CONCATENATED MODULE: ./src/inliner.ts
|
|
10850
10994
|
|
|
10851
10995
|
|
|
10996
|
+
|
|
10852
10997
|
function getArgSafety(state, func, args, requireAll) {
|
|
10853
10998
|
// determine whether decl might be changed by a function call
|
|
10854
10999
|
// or assignment during the evaluation of FunctionStateNode.
|
|
@@ -10916,25 +11061,12 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
10916
11061
|
if (allSafe && requireAll)
|
|
10917
11062
|
return true;
|
|
10918
11063
|
let callSeen = false;
|
|
10919
|
-
let ok = true;
|
|
10920
11064
|
const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
|
|
10921
|
-
const getLoc = (node) => (Array.isArray(node) ? node[0].start : node.start) || 0;
|
|
10922
11065
|
// look for uses of "unsafe" args that occur after a call.
|
|
10923
11066
|
// use post to do the checking, because arguments are evaluated
|
|
10924
11067
|
// prior to the call, so eg "return f(x.y);" is fine, but
|
|
10925
11068
|
// "return f()+x.y" is not.
|
|
10926
|
-
|
|
10927
|
-
// We also have to use a "pre" to ensure that child nodes are
|
|
10928
|
-
// visited in source order (otherwise we could visit x.y before f()
|
|
10929
|
-
// in the above example)
|
|
10930
|
-
(0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, (node) => {
|
|
10931
|
-
return Object.entries(node)
|
|
10932
|
-
.filter((kv) => Array.isArray(kv[1])
|
|
10933
|
-
? kv[1].length !== 0 && (0,external_api_cjs_namespaceObject.hasProperty)(kv[1][0], "type")
|
|
10934
|
-
: (0,external_api_cjs_namespaceObject.hasProperty)(kv[1], "type"))
|
|
10935
|
-
.sort(([, a], [, b]) => getLoc(a) - getLoc(b))
|
|
10936
|
-
.map(([key]) => key);
|
|
10937
|
-
}, (node) => {
|
|
11069
|
+
traverseAst(func.node.body, null, (node) => {
|
|
10938
11070
|
switch (node.type) {
|
|
10939
11071
|
case "AssignmentExpression":
|
|
10940
11072
|
case "UpdateExpression": {
|
|
@@ -11207,7 +11339,7 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11207
11339
|
}
|
|
11208
11340
|
}
|
|
11209
11341
|
else {
|
|
11210
|
-
|
|
11342
|
+
traverseAst(func.node.body, (node) => {
|
|
11211
11343
|
node.type === "ReturnStatement" && retStmtCount++;
|
|
11212
11344
|
});
|
|
11213
11345
|
if (retStmtCount > 1) {
|
|
@@ -11442,6 +11574,20 @@ function visitReferences(state, ast, name, defn, callback) {
|
|
|
11442
11574
|
return ["object"];
|
|
11443
11575
|
}
|
|
11444
11576
|
break;
|
|
11577
|
+
case "MethodDefinition": {
|
|
11578
|
+
if (!state.inType) {
|
|
11579
|
+
throw new Error("Method definition outside of type!");
|
|
11580
|
+
}
|
|
11581
|
+
if (node.params) {
|
|
11582
|
+
node.params.forEach((param) => {
|
|
11583
|
+
if (param.type == "BinaryExpression") {
|
|
11584
|
+
state.traverse(param.right);
|
|
11585
|
+
state.inType = true;
|
|
11586
|
+
}
|
|
11587
|
+
});
|
|
11588
|
+
}
|
|
11589
|
+
return ["returnType"];
|
|
11590
|
+
}
|
|
11445
11591
|
}
|
|
11446
11592
|
return null;
|
|
11447
11593
|
};
|
|
@@ -11457,6 +11603,7 @@ function visitReferences(state, ast, name, defn, callback) {
|
|
|
11457
11603
|
|
|
11458
11604
|
|
|
11459
11605
|
|
|
11606
|
+
|
|
11460
11607
|
function collectClassInfo(state) {
|
|
11461
11608
|
const toybox = state.stack[0].decls["Toybox"][0];
|
|
11462
11609
|
const lang = toybox.decls["Lang"][0];
|
|
@@ -11537,7 +11684,9 @@ function getFileSources(fnMap) {
|
|
|
11537
11684
|
return (value.monkeyCSource ||
|
|
11538
11685
|
promises_namespaceObject.readFile(name)
|
|
11539
11686
|
.then((data) => (value.monkeyCSource = data.toString().replace(/\r\n/g, "\n"))));
|
|
11540
|
-
})).then(() => {
|
|
11687
|
+
})).then(() => {
|
|
11688
|
+
return;
|
|
11689
|
+
});
|
|
11541
11690
|
}
|
|
11542
11691
|
function getFileASTs(fnMap) {
|
|
11543
11692
|
return getFileSources(fnMap).then(() => Object.entries(fnMap).reduce((ok, [name, value]) => {
|
|
@@ -11600,6 +11749,7 @@ async function analyze(fnMap, barrelList, config) {
|
|
|
11600
11749
|
node.body = null;
|
|
11601
11750
|
break;
|
|
11602
11751
|
}
|
|
11752
|
+
// falls through
|
|
11603
11753
|
case "ModuleDeclaration":
|
|
11604
11754
|
case "ClassDeclaration": {
|
|
11605
11755
|
const [scope] = state.stack.slice(-1);
|
|
@@ -11643,7 +11793,7 @@ async function analyze(fnMap, barrelList, config) {
|
|
|
11643
11793
|
if (diagnosticType &&
|
|
11644
11794
|
!config?.compilerOptions?.includes("--Eno-invalid-symbol")) {
|
|
11645
11795
|
const checkTypes = config?.typeCheckLevel && config.typeCheckLevel !== "Off";
|
|
11646
|
-
Object.entries(fnMap).forEach(([
|
|
11796
|
+
Object.entries(fnMap).forEach(([, v]) => {
|
|
11647
11797
|
visitReferences(state, v.ast, null, false, (node, results, error) => {
|
|
11648
11798
|
if (!error)
|
|
11649
11799
|
return undefined;
|
|
@@ -11849,7 +11999,7 @@ function evaluateFunction(func, args) {
|
|
|
11849
11999
|
? JSON.parse(JSON.stringify(func.body))
|
|
11850
12000
|
: func.body;
|
|
11851
12001
|
try {
|
|
11852
|
-
|
|
12002
|
+
traverseAst(body, (node) => {
|
|
11853
12003
|
switch (node.type) {
|
|
11854
12004
|
case "BlockStatement":
|
|
11855
12005
|
case "ReturnStatement":
|
|
@@ -11988,7 +12138,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
11988
12138
|
case "ConditionalExpression":
|
|
11989
12139
|
case "IfStatement":
|
|
11990
12140
|
case "DoWhileStatement":
|
|
11991
|
-
case "WhileStatement":
|
|
12141
|
+
case "WhileStatement": {
|
|
11992
12142
|
const test = (state.traverse(node.test) ||
|
|
11993
12143
|
node.test);
|
|
11994
12144
|
const [value, type] = getNodeValue(test);
|
|
@@ -12020,6 +12170,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12020
12170
|
}
|
|
12021
12171
|
}
|
|
12022
12172
|
return null;
|
|
12173
|
+
}
|
|
12023
12174
|
case "EnumDeclaration":
|
|
12024
12175
|
return false;
|
|
12025
12176
|
case "ForStatement": {
|
|
@@ -12331,7 +12482,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12331
12482
|
return null;
|
|
12332
12483
|
};
|
|
12333
12484
|
Object.values(fnMap).forEach((f) => {
|
|
12334
|
-
|
|
12485
|
+
traverseAst(f.ast, undefined, (node) => {
|
|
12335
12486
|
const ret = cleanup(node);
|
|
12336
12487
|
if (ret === false) {
|
|
12337
12488
|
state.removeNodeComments(node, f.ast);
|
|
@@ -12388,6 +12539,7 @@ function optimizeCall(state, node, context) {
|
|
|
12388
12539
|
|
|
12389
12540
|
;// CONCATENATED MODULE: ./src/pragma-checker.ts
|
|
12390
12541
|
|
|
12542
|
+
|
|
12391
12543
|
function pragmaChecker(ast, diagnostics) {
|
|
12392
12544
|
const comments = ast.comments;
|
|
12393
12545
|
if (!comments)
|
|
@@ -12434,7 +12586,7 @@ function pragmaChecker(ast, diagnostics) {
|
|
|
12434
12586
|
return re.test(haystack);
|
|
12435
12587
|
};
|
|
12436
12588
|
next();
|
|
12437
|
-
|
|
12589
|
+
traverseAst(ast, (node) => {
|
|
12438
12590
|
if (index >= comments.length)
|
|
12439
12591
|
return false;
|
|
12440
12592
|
if (node.start && node.start >= (comment.end || Infinity)) {
|
|
@@ -12513,7 +12665,7 @@ function pragmaChecker(ast, diagnostics) {
|
|
|
12513
12665
|
|
|
12514
12666
|
|
|
12515
12667
|
function relative_path_no_dotdot(relative) {
|
|
12516
|
-
return relative.replace(/^(\.\.[
|
|
12668
|
+
return relative.replace(/^(\.\.[\\/])+/, (str) => `__${"dot".repeat(str.length / 3)}__${str.slice(-1)}`);
|
|
12517
12669
|
}
|
|
12518
12670
|
async function getVSCodeSettings(path) {
|
|
12519
12671
|
try {
|
|
@@ -12645,7 +12797,7 @@ async function createLocalBarrels(targets, options) {
|
|
|
12645
12797
|
const sha1 = external_crypto_namespaceObject.createHash("sha1")
|
|
12646
12798
|
.update(rawBarrelDir, "binary")
|
|
12647
12799
|
.digest("base64")
|
|
12648
|
-
.replace(/[
|
|
12800
|
+
.replace(/[/=+]/g, "");
|
|
12649
12801
|
const optBarrelDir = external_path_.resolve(barrelDir, `${barrel}-${sha1}`);
|
|
12650
12802
|
if (!(0,external_api_cjs_namespaceObject.hasProperty)(optBarrels, barrel)) {
|
|
12651
12803
|
optBarrels[barrel] = {
|
|
@@ -12693,7 +12845,9 @@ async function generateOptimizedProject(options) {
|
|
|
12693
12845
|
}
|
|
12694
12846
|
return {
|
|
12695
12847
|
jungleFiles: config.jungleFiles,
|
|
12848
|
+
xml,
|
|
12696
12849
|
program: external_path_.basename(external_path_.dirname(manifest)),
|
|
12850
|
+
hasTests: !!config.testBuild,
|
|
12697
12851
|
};
|
|
12698
12852
|
}
|
|
12699
12853
|
let dropBarrels = false;
|
|
@@ -12794,7 +12948,7 @@ async function generateOptimizedProject(options) {
|
|
|
12794
12948
|
}
|
|
12795
12949
|
const prefix = `${product}.`;
|
|
12796
12950
|
process_field(prefix, qualifier, "sourcePath", (s) => external_path_.join(group.dir, "source", relative_path_no_dotdot(external_path_.relative(workspace, s)))
|
|
12797
|
-
.replace(/([
|
|
12951
|
+
.replace(/([\\/]\*\*)[\\/]\*/g, "$1"));
|
|
12798
12952
|
if (group.optimizerConfig.optBarrels) {
|
|
12799
12953
|
parts.push(`${prefix}barrelPath = ${Object.values(group.optimizerConfig.optBarrels)
|
|
12800
12954
|
.map((value) => `[${value.jungleFiles
|
|
@@ -12808,7 +12962,7 @@ async function generateOptimizedProject(options) {
|
|
|
12808
12962
|
.map(([barrel, resolvedBarrel]) => {
|
|
12809
12963
|
const root = external_path_.dirname(resolvedBarrel.jungles[0]);
|
|
12810
12964
|
return (resolvedBarrel.qualifier.sourcePath || []).map((s) => external_path_.join(group.dir, "barrels", barrel, external_path_.relative(root, s))
|
|
12811
|
-
.replace(/([
|
|
12965
|
+
.replace(/([\\/]\*\*)[\\/]\*/g, "$1"));
|
|
12812
12966
|
})
|
|
12813
12967
|
.flat()
|
|
12814
12968
|
.sort()
|
|
@@ -12931,7 +13085,7 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
12931
13085
|
// the oldest optimized file, we don't need to regenerate
|
|
12932
13086
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
12933
13087
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
12934
|
-
if (source_time < opt_time &&
|
|
13088
|
+
if (source_time < opt_time && 1655677006664 < opt_time) {
|
|
12935
13089
|
return { hasTests, diagnostics: prevDiagnostics };
|
|
12936
13090
|
}
|
|
12937
13091
|
}
|
package/build/src/api.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { mctree } from "@markw65/prettier-plugin-monkeyc";
|
|
2
|
+
import { traverseAst } from "./ast";
|
|
2
3
|
export { visitReferences } from "./visitor";
|
|
4
|
+
export { traverseAst };
|
|
3
5
|
export declare function getApiMapping(state?: ProgramState, barrelList?: string[]): Promise<ProgramStateNode | null>;
|
|
4
6
|
export declare function hasProperty<T extends null extends T ? unknown : undefined extends T ? unknown : never>(obj: T, prop: string): obj is NonNullable<T>;
|
|
5
7
|
export declare function hasProperty<T>(obj: T, prop: string): boolean;
|
|
@@ -7,6 +9,5 @@ export declare function isStateNode(node: StateNodeDecl): node is StateNode;
|
|
|
7
9
|
export declare function variableDeclarationName(node: mctree.TypedIdentifier | mctree.InstanceofIdentifier): string;
|
|
8
10
|
export declare function sameLookupResult(a: LookupDefinition[], b: LookupDefinition[]): boolean;
|
|
9
11
|
export declare function collectNamespaces(ast: mctree.Program, stateIn?: ProgramState): ProgramStateNode;
|
|
10
|
-
export declare function traverseAst(node: mctree.Node, pre?: null | ((node: mctree.Node) => void | null | false | (keyof mctree.NodeAll)[]), post?: (node: mctree.Node) => void | null | false | mctree.Node | mctree.Node[]): false | void | null | mctree.Node | mctree.Node[];
|
|
11
12
|
export declare function formatAst(node: mctree.Node, monkeyCSource?: string | null): string;
|
|
12
13
|
export declare function findUsingForNode(state: ProgramStateLive, stack: ProgramStateStack, i: number, node: mctree.Identifier, isType: boolean): StateNodeDecl[] | null;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { mctree } from "@markw65/prettier-plugin-monkeyc";
|
|
2
|
+
export declare function traverseAst(node: mctree.Node, pre?: null | ((node: mctree.Node) => void | null | false | (keyof mctree.NodeAll)[]), post?: (node: mctree.Node) => void | null | false | mctree.Node | mctree.Node[]): false | void | null | mctree.Node | mctree.Node[];
|
package/build/src/optimizer.d.ts
CHANGED
|
@@ -197,7 +197,7 @@ export declare function buildOptimizedProject(product: string | null, options: B
|
|
|
197
197
|
args: string[];
|
|
198
198
|
program: string;
|
|
199
199
|
product: string | null;
|
|
200
|
-
hasTests: boolean
|
|
200
|
+
hasTests: boolean;
|
|
201
201
|
diagnostics: Record<string, {
|
|
202
202
|
type: DiagnosticType;
|
|
203
203
|
loc: {
|
|
@@ -209,9 +209,9 @@ export declare function buildOptimizedProject(product: string | null, options: B
|
|
|
209
209
|
}>;
|
|
210
210
|
export declare function generateOptimizedProject(options: BuildConfig): Promise<{
|
|
211
211
|
jungleFiles: string | undefined;
|
|
212
|
+
xml: import("./manifest").ManifestXML;
|
|
212
213
|
program: string;
|
|
213
|
-
|
|
214
|
-
hasTests?: undefined;
|
|
214
|
+
hasTests: boolean;
|
|
215
215
|
diagnostics?: undefined;
|
|
216
216
|
} | {
|
|
217
217
|
jungleFiles: string;
|
package/build/util.cjs
CHANGED
|
@@ -4145,10 +4145,12 @@ async function copyRecursiveAsNeeded(source, target, filter) {
|
|
|
4145
4145
|
}
|
|
4146
4146
|
const files = await promises_namespaceObject.readdir(source);
|
|
4147
4147
|
return Promise.all(files.map((file) => {
|
|
4148
|
-
|
|
4149
|
-
|
|
4148
|
+
const src = external_path_.join(source, file);
|
|
4149
|
+
const tgt = external_path_.join(target, file);
|
|
4150
4150
|
return copyRecursiveAsNeeded(src, tgt, filter);
|
|
4151
|
-
})).then(() => {
|
|
4151
|
+
})).then(() => {
|
|
4152
|
+
return;
|
|
4153
|
+
});
|
|
4152
4154
|
}
|
|
4153
4155
|
else {
|
|
4154
4156
|
if (filter && !filter(source, target)) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markw65/monkeyc-optimizer",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.23",
|
|
5
5
|
"description": "Source to source optimizer for Garmin Monkey C code",
|
|
6
6
|
"main": "build/optimizer.cjs",
|
|
7
7
|
"types": "build/src/optimizer.d.ts",
|
|
@@ -20,9 +20,12 @@
|
|
|
20
20
|
"build-debug": "webpack --mode development",
|
|
21
21
|
"build-release": "webpack --mode production",
|
|
22
22
|
"prepack": "webpack --mode production",
|
|
23
|
-
"test": "npm run test-
|
|
23
|
+
"test": "npm run test-optimized && npm run test-remote",
|
|
24
24
|
"test-remote": "node ./test/test.js --product=pick-one --github",
|
|
25
|
-
"test-
|
|
25
|
+
"test-optimized": "node test/test.js --run-tests --product=fenix5 --product=fr235 --jungle $(pwd)/test/OptimizerTests/monkey.jungle",
|
|
26
|
+
"test-unopt": "node test/test.js --skipOptimization --run-tests --product=fenix5 --product=fr235 --jungle $(pwd)/test/OptimizerTests/monkey.jungle",
|
|
27
|
+
"test-garmin-opt": "node test/test.js --skipOptimization --garminOptLevel=2 --run-tests --product=fenix5 --product=fr235 --jungle $(pwd)/test/OptimizerTests/monkey.jungle",
|
|
28
|
+
"eslint": "npx eslint ."
|
|
26
29
|
},
|
|
27
30
|
"files": [
|
|
28
31
|
"build/optimizer.cjs",
|
|
@@ -34,12 +37,14 @@
|
|
|
34
37
|
"author": "markw65",
|
|
35
38
|
"license": "MIT",
|
|
36
39
|
"dependencies": {
|
|
37
|
-
"@markw65/prettier-plugin-monkeyc": "^1.0.
|
|
40
|
+
"@markw65/prettier-plugin-monkeyc": "^1.0.27"
|
|
38
41
|
},
|
|
39
42
|
"devDependencies": {
|
|
40
43
|
"@types/glob": "^7.2.0",
|
|
41
44
|
"@types/prettier": "^2.6.1",
|
|
42
45
|
"@types/xml2js": "^0.4.11",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
|
47
|
+
"@typescript-eslint/parser": "^5.28.0",
|
|
43
48
|
"eslint": "^8.12.0",
|
|
44
49
|
"extract-zip": "^2.0.1",
|
|
45
50
|
"glob": "^7.2.0",
|