@markw65/monkeyc-optimizer 1.0.28 → 1.0.31
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 +75 -0
- package/build/api.cjs +2901 -342
- package/build/optimizer.cjs +2775 -429
- package/build/src/api.d.ts +6 -4
- package/build/src/ast.d.ts +8 -0
- package/build/src/build.d.ts +1 -0
- package/build/src/control-flow.d.ts +21 -0
- package/build/src/function-info.d.ts +12 -0
- package/build/src/inliner.d.ts +4 -3
- package/build/src/jungles.d.ts +1 -0
- package/build/src/mc-rewrite.d.ts +3 -2
- package/build/src/optimizer-types.d.ts +188 -0
- package/build/src/optimizer.d.ts +4 -173
- package/build/src/pragma-checker.d.ts +2 -1
- package/build/src/pre.d.ts +1 -0
- package/build/src/unused-exprs.d.ts +3 -0
- package/build/src/variable-renamer.d.ts +1 -0
- package/build/src/visitor.d.ts +1 -0
- package/package.json +4 -2
package/build/optimizer.cjs
CHANGED
|
@@ -2172,6 +2172,185 @@ function pendGo(self, fn) {
|
|
|
2172
2172
|
}
|
|
2173
2173
|
|
|
2174
2174
|
|
|
2175
|
+
/***/ }),
|
|
2176
|
+
|
|
2177
|
+
/***/ 2789:
|
|
2178
|
+
/***/ ((module) => {
|
|
2179
|
+
|
|
2180
|
+
/**
|
|
2181
|
+
* Expose `PriorityQueue`.
|
|
2182
|
+
*/
|
|
2183
|
+
module.exports = PriorityQueue;
|
|
2184
|
+
|
|
2185
|
+
/**
|
|
2186
|
+
* Initializes a new empty `PriorityQueue` with the given `comparator(a, b)`
|
|
2187
|
+
* function, uses `.DEFAULT_COMPARATOR()` when no function is provided.
|
|
2188
|
+
*
|
|
2189
|
+
* The comparator function must return a positive number when `a > b`, 0 when
|
|
2190
|
+
* `a == b` and a negative number when `a < b`.
|
|
2191
|
+
*
|
|
2192
|
+
* @param {Function}
|
|
2193
|
+
* @return {PriorityQueue}
|
|
2194
|
+
* @api public
|
|
2195
|
+
*/
|
|
2196
|
+
function PriorityQueue(comparator) {
|
|
2197
|
+
this._comparator = comparator || PriorityQueue.DEFAULT_COMPARATOR;
|
|
2198
|
+
this._elements = [];
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
/**
|
|
2202
|
+
* Compares `a` and `b`, when `a > b` it returns a positive number, when
|
|
2203
|
+
* it returns 0 and when `a < b` it returns a negative number.
|
|
2204
|
+
*
|
|
2205
|
+
* @param {String|Number} a
|
|
2206
|
+
* @param {String|Number} b
|
|
2207
|
+
* @return {Number}
|
|
2208
|
+
* @api public
|
|
2209
|
+
*/
|
|
2210
|
+
PriorityQueue.DEFAULT_COMPARATOR = function(a, b) {
|
|
2211
|
+
if (typeof a === 'number' && typeof b === 'number') {
|
|
2212
|
+
return a - b;
|
|
2213
|
+
} else {
|
|
2214
|
+
a = a.toString();
|
|
2215
|
+
b = b.toString();
|
|
2216
|
+
|
|
2217
|
+
if (a == b) return 0;
|
|
2218
|
+
|
|
2219
|
+
return (a > b) ? 1 : -1;
|
|
2220
|
+
}
|
|
2221
|
+
};
|
|
2222
|
+
|
|
2223
|
+
/**
|
|
2224
|
+
* Returns whether the priority queue is empty or not.
|
|
2225
|
+
*
|
|
2226
|
+
* @return {Boolean}
|
|
2227
|
+
* @api public
|
|
2228
|
+
*/
|
|
2229
|
+
PriorityQueue.prototype.isEmpty = function() {
|
|
2230
|
+
return this.size() === 0;
|
|
2231
|
+
};
|
|
2232
|
+
|
|
2233
|
+
/**
|
|
2234
|
+
* Peeks at the top element of the priority queue.
|
|
2235
|
+
*
|
|
2236
|
+
* @return {Object}
|
|
2237
|
+
* @throws {Error} when the queue is empty.
|
|
2238
|
+
* @api public
|
|
2239
|
+
*/
|
|
2240
|
+
PriorityQueue.prototype.peek = function() {
|
|
2241
|
+
if (this.isEmpty()) throw new Error('PriorityQueue is empty');
|
|
2242
|
+
|
|
2243
|
+
return this._elements[0];
|
|
2244
|
+
};
|
|
2245
|
+
|
|
2246
|
+
/**
|
|
2247
|
+
* Dequeues the top element of the priority queue.
|
|
2248
|
+
*
|
|
2249
|
+
* @return {Object}
|
|
2250
|
+
* @throws {Error} when the queue is empty.
|
|
2251
|
+
* @api public
|
|
2252
|
+
*/
|
|
2253
|
+
PriorityQueue.prototype.deq = function() {
|
|
2254
|
+
var first = this.peek();
|
|
2255
|
+
var last = this._elements.pop();
|
|
2256
|
+
var size = this.size();
|
|
2257
|
+
|
|
2258
|
+
if (size === 0) return first;
|
|
2259
|
+
|
|
2260
|
+
this._elements[0] = last;
|
|
2261
|
+
var current = 0;
|
|
2262
|
+
|
|
2263
|
+
while (current < size) {
|
|
2264
|
+
var largest = current;
|
|
2265
|
+
var left = (2 * current) + 1;
|
|
2266
|
+
var right = (2 * current) + 2;
|
|
2267
|
+
|
|
2268
|
+
if (left < size && this._compare(left, largest) >= 0) {
|
|
2269
|
+
largest = left;
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
if (right < size && this._compare(right, largest) >= 0) {
|
|
2273
|
+
largest = right;
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
if (largest === current) break;
|
|
2277
|
+
|
|
2278
|
+
this._swap(largest, current);
|
|
2279
|
+
current = largest;
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
return first;
|
|
2283
|
+
};
|
|
2284
|
+
|
|
2285
|
+
/**
|
|
2286
|
+
* Enqueues the `element` at the priority queue and returns its new size.
|
|
2287
|
+
*
|
|
2288
|
+
* @param {Object} element
|
|
2289
|
+
* @return {Number}
|
|
2290
|
+
* @api public
|
|
2291
|
+
*/
|
|
2292
|
+
PriorityQueue.prototype.enq = function(element) {
|
|
2293
|
+
var size = this._elements.push(element);
|
|
2294
|
+
var current = size - 1;
|
|
2295
|
+
|
|
2296
|
+
while (current > 0) {
|
|
2297
|
+
var parent = Math.floor((current - 1) / 2);
|
|
2298
|
+
|
|
2299
|
+
if (this._compare(current, parent) <= 0) break;
|
|
2300
|
+
|
|
2301
|
+
this._swap(parent, current);
|
|
2302
|
+
current = parent;
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
return size;
|
|
2306
|
+
};
|
|
2307
|
+
|
|
2308
|
+
/**
|
|
2309
|
+
* Returns the size of the priority queue.
|
|
2310
|
+
*
|
|
2311
|
+
* @return {Number}
|
|
2312
|
+
* @api public
|
|
2313
|
+
*/
|
|
2314
|
+
PriorityQueue.prototype.size = function() {
|
|
2315
|
+
return this._elements.length;
|
|
2316
|
+
};
|
|
2317
|
+
|
|
2318
|
+
/**
|
|
2319
|
+
* Iterates over queue elements
|
|
2320
|
+
*
|
|
2321
|
+
* @param {Function} fn
|
|
2322
|
+
*/
|
|
2323
|
+
PriorityQueue.prototype.forEach = function(fn) {
|
|
2324
|
+
return this._elements.forEach(fn);
|
|
2325
|
+
};
|
|
2326
|
+
|
|
2327
|
+
/**
|
|
2328
|
+
* Compares the values at position `a` and `b` in the priority queue using its
|
|
2329
|
+
* comparator function.
|
|
2330
|
+
*
|
|
2331
|
+
* @param {Number} a
|
|
2332
|
+
* @param {Number} b
|
|
2333
|
+
* @return {Number}
|
|
2334
|
+
* @api private
|
|
2335
|
+
*/
|
|
2336
|
+
PriorityQueue.prototype._compare = function(a, b) {
|
|
2337
|
+
return this._comparator(this._elements[a], this._elements[b]);
|
|
2338
|
+
};
|
|
2339
|
+
|
|
2340
|
+
/**
|
|
2341
|
+
* Swaps the values at position `a` and `b` in the priority queue.
|
|
2342
|
+
*
|
|
2343
|
+
* @param {Number} a
|
|
2344
|
+
* @param {Number} b
|
|
2345
|
+
* @api private
|
|
2346
|
+
*/
|
|
2347
|
+
PriorityQueue.prototype._swap = function(a, b) {
|
|
2348
|
+
var aux = this._elements[a];
|
|
2349
|
+
this._elements[a] = this._elements[b];
|
|
2350
|
+
this._elements[b] = aux;
|
|
2351
|
+
};
|
|
2352
|
+
|
|
2353
|
+
|
|
2175
2354
|
/***/ }),
|
|
2176
2355
|
|
|
2177
2356
|
/***/ 4286:
|
|
@@ -9874,17 +10053,17 @@ async function build_project(product, options, lineCallback) {
|
|
|
9874
10053
|
if (!product) {
|
|
9875
10054
|
extraArgs.push("-e");
|
|
9876
10055
|
}
|
|
9877
|
-
switch (typeCheckLevel) {
|
|
9878
|
-
case "
|
|
10056
|
+
switch (typeCheckLevel?.toLowerCase()) {
|
|
10057
|
+
case "off":
|
|
9879
10058
|
extraArgs.push("-l", "0");
|
|
9880
10059
|
break;
|
|
9881
|
-
case "
|
|
10060
|
+
case "gradual":
|
|
9882
10061
|
extraArgs.push("-l", "1");
|
|
9883
10062
|
break;
|
|
9884
|
-
case "
|
|
10063
|
+
case "informative":
|
|
9885
10064
|
extraArgs.push("-l", "2");
|
|
9886
10065
|
break;
|
|
9887
|
-
case "
|
|
10066
|
+
case "strict":
|
|
9888
10067
|
extraArgs.push("-l", "3");
|
|
9889
10068
|
break;
|
|
9890
10069
|
}
|
|
@@ -10812,62 +10991,68 @@ function _check(x) {
|
|
|
10812
10991
|
x = y;
|
|
10813
10992
|
}
|
|
10814
10993
|
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:
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
|
|
10851
|
-
|
|
10852
|
-
|
|
10853
|
-
|
|
10854
|
-
|
|
10855
|
-
|
|
10856
|
-
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
|
|
10994
|
+
ArrayExpression: { keys: ["elements"], expr: true },
|
|
10995
|
+
AssignmentExpression: { keys: ["left", "right"], expr: true },
|
|
10996
|
+
AttributeList: { keys: ["attributes"] },
|
|
10997
|
+
Attributes: { keys: ["elements"] },
|
|
10998
|
+
BinaryExpression: { keys: ["left", "right"], expr: true },
|
|
10999
|
+
Block: { keys: [] },
|
|
11000
|
+
BlockStatement: { keys: ["body", "innerComments"], stmt: true },
|
|
11001
|
+
BreakStatement: { keys: [], stmt: true },
|
|
11002
|
+
CallExpression: { keys: ["callee", "arguments"], expr: true },
|
|
11003
|
+
CatchClause: { keys: ["param", "body"] },
|
|
11004
|
+
CatchClauses: { keys: ["catches"] },
|
|
11005
|
+
ClassBody: { keys: ["body"] },
|
|
11006
|
+
ClassDeclaration: { keys: ["attrs", "id", "superClass", "body"], stmt: true },
|
|
11007
|
+
ClassElement: { keys: ["item"] },
|
|
11008
|
+
ConditionalExpression: {
|
|
11009
|
+
keys: ["test", "consequent", "alternate"],
|
|
11010
|
+
expr: true,
|
|
11011
|
+
},
|
|
11012
|
+
ContinueStatement: { keys: [], stmt: true },
|
|
11013
|
+
DoWhileStatement: { keys: ["body", "test"], stmt: true },
|
|
11014
|
+
EnumDeclaration: { keys: ["attrs", "id", "body"], stmt: true },
|
|
11015
|
+
EnumStringBody: { keys: ["members"] },
|
|
11016
|
+
EnumStringMember: { keys: ["id", "init"] },
|
|
11017
|
+
ExpressionStatement: { keys: ["expression"], stmt: true },
|
|
11018
|
+
ForStatement: { keys: ["init", "test", "body", "update"], stmt: true },
|
|
11019
|
+
FunctionDeclaration: {
|
|
11020
|
+
keys: ["attrs", "id", "params", "returnType", "body"],
|
|
11021
|
+
stmt: true,
|
|
11022
|
+
},
|
|
11023
|
+
Identifier: { keys: [], expr: true },
|
|
11024
|
+
IfStatement: { keys: ["test", "consequent", "alternate"], stmt: true },
|
|
11025
|
+
ImportModule: { keys: ["id"] },
|
|
11026
|
+
InstanceOfCase: { keys: ["id"] },
|
|
11027
|
+
Line: { keys: [] },
|
|
11028
|
+
Literal: { keys: [], expr: true },
|
|
11029
|
+
LogicalExpression: { keys: ["left", "right"], expr: true },
|
|
11030
|
+
MemberExpression: { keys: ["object", "property"], expr: true },
|
|
11031
|
+
MethodDefinition: { keys: ["params", "returnType"] },
|
|
11032
|
+
ModuleDeclaration: { keys: ["attrs", "id", "body"], stmt: true },
|
|
11033
|
+
MultiLine: { keys: [] },
|
|
11034
|
+
NewExpression: { keys: ["callee", "arguments"], expr: true },
|
|
11035
|
+
ObjectExpression: { keys: ["properties"], expr: true },
|
|
11036
|
+
ParenthesizedExpression: { keys: ["expression"], expr: true },
|
|
11037
|
+
Program: { keys: ["body", "comments"] },
|
|
11038
|
+
Property: { keys: ["key", "value"] },
|
|
11039
|
+
ReturnStatement: { keys: ["argument"], stmt: true },
|
|
11040
|
+
SequenceExpression: { keys: ["expressions"], expr: true },
|
|
11041
|
+
SizedArrayExpression: { keys: ["size", "ts"], expr: true },
|
|
11042
|
+
SwitchCase: { keys: ["test", "consequent"] },
|
|
11043
|
+
SwitchStatement: { keys: ["discriminant", "cases"], stmt: true },
|
|
11044
|
+
ThisExpression: { keys: [], expr: true },
|
|
11045
|
+
ThrowStatement: { keys: ["argument"], stmt: true },
|
|
11046
|
+
TryStatement: { keys: ["block", "handler", "finalizer"], stmt: true },
|
|
11047
|
+
TypedefDeclaration: { keys: ["attrs", "id", "ts"], stmt: true },
|
|
11048
|
+
TypeSpecList: { keys: ["ts"] },
|
|
11049
|
+
TypeSpecPart: { keys: ["name", "body", "callspec", "generics"] },
|
|
11050
|
+
UnaryExpression: { keys: ["argument"], expr: true },
|
|
11051
|
+
UpdateExpression: { keys: ["argument"], expr: true },
|
|
11052
|
+
Using: { keys: ["id", "as"] },
|
|
11053
|
+
VariableDeclaration: { keys: ["attrs", "declarations"], stmt: true },
|
|
11054
|
+
VariableDeclarator: { keys: ["id", "init"] },
|
|
11055
|
+
WhileStatement: { keys: ["test", "body"], stmt: true },
|
|
10871
11056
|
};
|
|
10872
11057
|
function isMCTreeNode(node) {
|
|
10873
11058
|
return node ? typeof node === "object" && "type" in node : false;
|
|
@@ -10892,7 +11077,7 @@ function traverseAst(node, pre, post) {
|
|
|
10892
11077
|
if (!mctreeTypeInfo[node.type]) {
|
|
10893
11078
|
throw new Error("what?");
|
|
10894
11079
|
}
|
|
10895
|
-
for (const key of nodes || mctreeTypeInfo[node.type]) {
|
|
11080
|
+
for (const key of nodes || mctreeTypeInfo[node.type].keys) {
|
|
10896
11081
|
const value = node[key];
|
|
10897
11082
|
if (!value)
|
|
10898
11083
|
continue;
|
|
@@ -10919,13 +11104,21 @@ function traverseAst(node, pre, post) {
|
|
|
10919
11104
|
}
|
|
10920
11105
|
}
|
|
10921
11106
|
else if (isMCTreeNode(value)) {
|
|
10922
|
-
|
|
11107
|
+
let repl = traverseAst(value, pre, post);
|
|
10923
11108
|
if (repl === false) {
|
|
10924
11109
|
delete node[key];
|
|
10925
11110
|
}
|
|
10926
11111
|
else if (repl != null) {
|
|
10927
11112
|
if (Array.isArray(repl)) {
|
|
10928
|
-
|
|
11113
|
+
if (isStatement(value) && repl.every((s) => isStatement(s))) {
|
|
11114
|
+
repl = withLoc({
|
|
11115
|
+
type: "BlockStatement",
|
|
11116
|
+
body: repl,
|
|
11117
|
+
}, repl[0], repl[repl.length - 1]);
|
|
11118
|
+
}
|
|
11119
|
+
else {
|
|
11120
|
+
throw new Error("Array returned by traverseAst in Node context");
|
|
11121
|
+
}
|
|
10929
11122
|
}
|
|
10930
11123
|
node[key] = repl;
|
|
10931
11124
|
}
|
|
@@ -10933,6 +11126,184 @@ function traverseAst(node, pre, post) {
|
|
|
10933
11126
|
}
|
|
10934
11127
|
return post && post(node);
|
|
10935
11128
|
}
|
|
11129
|
+
function isStatement(node) {
|
|
11130
|
+
return hasProperty(mctreeTypeInfo[node.type], "stmt");
|
|
11131
|
+
}
|
|
11132
|
+
function isExpression(node) {
|
|
11133
|
+
return hasProperty(mctreeTypeInfo[node.type], "expr");
|
|
11134
|
+
}
|
|
11135
|
+
function mayThrow(node) {
|
|
11136
|
+
switch (node.type) {
|
|
11137
|
+
case "BinaryExpression":
|
|
11138
|
+
case "CallExpression":
|
|
11139
|
+
case "ConditionalExpression":
|
|
11140
|
+
case "LogicalExpression":
|
|
11141
|
+
case "NewExpression":
|
|
11142
|
+
case "ThrowStatement":
|
|
11143
|
+
case "UnaryExpression":
|
|
11144
|
+
case "UpdateExpression":
|
|
11145
|
+
return true;
|
|
11146
|
+
default:
|
|
11147
|
+
return false;
|
|
11148
|
+
}
|
|
11149
|
+
}
|
|
11150
|
+
function hasProperty(obj, prop) {
|
|
11151
|
+
return obj ? Object.prototype.hasOwnProperty.call(obj, prop) : false;
|
|
11152
|
+
}
|
|
11153
|
+
function withLoc(node, start, end) {
|
|
11154
|
+
if (start && start.loc) {
|
|
11155
|
+
node.start = start.start;
|
|
11156
|
+
if (!node.end)
|
|
11157
|
+
node.end = start.end;
|
|
11158
|
+
node.loc = { ...(node.loc || start.loc), start: start.loc.start };
|
|
11159
|
+
}
|
|
11160
|
+
if (end && end.loc) {
|
|
11161
|
+
node.end = end.end;
|
|
11162
|
+
node.loc = { ...(node.loc || end.loc), end: end.loc.end };
|
|
11163
|
+
}
|
|
11164
|
+
return node;
|
|
11165
|
+
}
|
|
11166
|
+
function withLocDeep(node, start, end, inplace) {
|
|
11167
|
+
node = withLoc(inplace ? node : { ...node }, start, end);
|
|
11168
|
+
for (const key of mctreeTypeInfo[node.type].keys) {
|
|
11169
|
+
const value = node[key];
|
|
11170
|
+
if (!value)
|
|
11171
|
+
continue;
|
|
11172
|
+
const fix = (v) => isMCTreeNode(v) ? withLocDeep(v, start, end, inplace) : v;
|
|
11173
|
+
const repl = Array.isArray(value) ? value.map(fix) : fix(value);
|
|
11174
|
+
inplace || (node[key] = repl);
|
|
11175
|
+
}
|
|
11176
|
+
return node;
|
|
11177
|
+
}
|
|
11178
|
+
function cloneDeep(node) {
|
|
11179
|
+
return withLocDeep(node, null);
|
|
11180
|
+
}
|
|
11181
|
+
|
|
11182
|
+
;// CONCATENATED MODULE: ./src/function-info.ts
|
|
11183
|
+
|
|
11184
|
+
function cloneSet(ae) {
|
|
11185
|
+
return new Set(ae);
|
|
11186
|
+
}
|
|
11187
|
+
function mergeSet(a, b) {
|
|
11188
|
+
b.forEach((event) => a.add(event));
|
|
11189
|
+
}
|
|
11190
|
+
function recordModifiedDecl(func, decl) {
|
|
11191
|
+
if (!func.next_info) {
|
|
11192
|
+
func.next_info = { modifiedDecls: new Set(), calledFuncs: new Set() };
|
|
11193
|
+
}
|
|
11194
|
+
func.next_info.modifiedDecls.add(decl);
|
|
11195
|
+
return null;
|
|
11196
|
+
}
|
|
11197
|
+
function recordModifiedDecls(func, lookupDefs) {
|
|
11198
|
+
lookupDefs.forEach((lookupDef) => lookupDef.results.forEach((result) => {
|
|
11199
|
+
if (result.type == "VariableDeclarator" && result.node.kind === "var") {
|
|
11200
|
+
recordModifiedDecl(func, result);
|
|
11201
|
+
}
|
|
11202
|
+
}));
|
|
11203
|
+
}
|
|
11204
|
+
function recordModifiedName(func, name) {
|
|
11205
|
+
if (!func.next_info) {
|
|
11206
|
+
func.next_info = { modifiedDecls: new Set(), calledFuncs: new Set() };
|
|
11207
|
+
}
|
|
11208
|
+
if (!func.next_info.modifiedNames) {
|
|
11209
|
+
func.next_info.modifiedNames = new Set();
|
|
11210
|
+
}
|
|
11211
|
+
func.next_info.modifiedNames.add(name);
|
|
11212
|
+
}
|
|
11213
|
+
function recordModifiedUnknown(func) {
|
|
11214
|
+
if (!func.next_info) {
|
|
11215
|
+
func.next_info = { modifiedDecls: new Set(), calledFuncs: new Set() };
|
|
11216
|
+
}
|
|
11217
|
+
func.next_info.modifiedUnknown = true;
|
|
11218
|
+
}
|
|
11219
|
+
function recordCalledFunc(func, callee) {
|
|
11220
|
+
if (!func.next_info) {
|
|
11221
|
+
func.next_info = { modifiedDecls: new Set(), calledFuncs: new Set() };
|
|
11222
|
+
}
|
|
11223
|
+
func.next_info.calledFuncs.add(callee);
|
|
11224
|
+
return null;
|
|
11225
|
+
}
|
|
11226
|
+
function recordCalledFuncs(func, callees) {
|
|
11227
|
+
callees.forEach((callee) => {
|
|
11228
|
+
recordCalledFunc(func, callee);
|
|
11229
|
+
});
|
|
11230
|
+
}
|
|
11231
|
+
function functionMayModify(state, func, decl) {
|
|
11232
|
+
const info = func.info;
|
|
11233
|
+
if (!info || info.modifiedUnknown)
|
|
11234
|
+
return true;
|
|
11235
|
+
if (info.resolvedDecls) {
|
|
11236
|
+
return info.resolvedDecls.has(decl);
|
|
11237
|
+
}
|
|
11238
|
+
if (info.modifiedNames?.has(decl.name))
|
|
11239
|
+
return true;
|
|
11240
|
+
if (info.modifiedDecls.has(decl))
|
|
11241
|
+
return true;
|
|
11242
|
+
const visited = new Set();
|
|
11243
|
+
const resolved = new Set();
|
|
11244
|
+
const resolveDecls = (f) => {
|
|
11245
|
+
if (visited.has(f))
|
|
11246
|
+
return true;
|
|
11247
|
+
if (!f.info)
|
|
11248
|
+
return false;
|
|
11249
|
+
if (f.info.modifiedUnknown) {
|
|
11250
|
+
info.modifiedUnknown = true;
|
|
11251
|
+
return false;
|
|
11252
|
+
}
|
|
11253
|
+
if (f.info.modifiedNames) {
|
|
11254
|
+
if (info.modifiedNames) {
|
|
11255
|
+
mergeSet(info.modifiedNames, f.info.modifiedNames);
|
|
11256
|
+
}
|
|
11257
|
+
else {
|
|
11258
|
+
info.modifiedNames = cloneSet(f.info.modifiedNames);
|
|
11259
|
+
}
|
|
11260
|
+
}
|
|
11261
|
+
mergeSet(resolved, f.info.modifiedDecls);
|
|
11262
|
+
visited.add(f);
|
|
11263
|
+
const q = true;
|
|
11264
|
+
if (q &&
|
|
11265
|
+
f.info.callsExposed &&
|
|
11266
|
+
state.exposed &&
|
|
11267
|
+
!Object.keys(state.exposed).every((key) => !state.allFunctions[key] ||
|
|
11268
|
+
state.allFunctions[key].every(resolveDecls))) {
|
|
11269
|
+
return false;
|
|
11270
|
+
}
|
|
11271
|
+
return Array.from(f.info.calledFuncs).every(resolveDecls);
|
|
11272
|
+
};
|
|
11273
|
+
if (resolveDecls(func)) {
|
|
11274
|
+
info.resolvedDecls = resolved;
|
|
11275
|
+
return resolved.has(decl);
|
|
11276
|
+
}
|
|
11277
|
+
return true;
|
|
11278
|
+
}
|
|
11279
|
+
function findCallees(lookupDefs) {
|
|
11280
|
+
const decls = lookupDefs.reduce((decls, r) => (decls ? decls.concat(r.results) : r.results), null);
|
|
11281
|
+
return (decls &&
|
|
11282
|
+
decls.filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
|
|
11283
|
+
}
|
|
11284
|
+
function findCalleesForNew(lookupDefs) {
|
|
11285
|
+
const initializer = (decl) => {
|
|
11286
|
+
if (hasProperty(decl.decls, "initialize")) {
|
|
11287
|
+
return decl.decls["initialize"];
|
|
11288
|
+
}
|
|
11289
|
+
if (decl.superClass && decl.superClass !== true) {
|
|
11290
|
+
return decl.superClass.reduce((cur, cls) => {
|
|
11291
|
+
const init = initializer(cls);
|
|
11292
|
+
if (init) {
|
|
11293
|
+
if (!cur)
|
|
11294
|
+
return init;
|
|
11295
|
+
return cur.concat(init);
|
|
11296
|
+
}
|
|
11297
|
+
return cur;
|
|
11298
|
+
}, null);
|
|
11299
|
+
}
|
|
11300
|
+
return null;
|
|
11301
|
+
};
|
|
11302
|
+
return lookupDefs.flatMap((r) => r.results
|
|
11303
|
+
.filter((decl) => decl.type === "ClassDeclaration")
|
|
11304
|
+
.flatMap(initializer)
|
|
11305
|
+
.filter((decl) => decl ? decl.type === "FunctionDeclaration" : false));
|
|
11306
|
+
}
|
|
10936
11307
|
|
|
10937
11308
|
;// CONCATENATED MODULE: ./src/variable-renamer.ts
|
|
10938
11309
|
|
|
@@ -10994,6 +11365,7 @@ function renameVariable(state, locals, declName) {
|
|
|
10994
11365
|
|
|
10995
11366
|
|
|
10996
11367
|
|
|
11368
|
+
|
|
10997
11369
|
function getArgSafety(state, func, args, requireAll) {
|
|
10998
11370
|
// determine whether decl might be changed by a function call
|
|
10999
11371
|
// or assignment during the evaluation of FunctionStateNode.
|
|
@@ -11026,8 +11398,9 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
11026
11398
|
}
|
|
11027
11399
|
};
|
|
11028
11400
|
const safeArgs = [];
|
|
11401
|
+
const argDecls = [];
|
|
11029
11402
|
let allSafe = true;
|
|
11030
|
-
if (!args.every((arg) => {
|
|
11403
|
+
if (!args.every((arg, i) => {
|
|
11031
11404
|
switch (arg.type) {
|
|
11032
11405
|
case "Literal":
|
|
11033
11406
|
safeArgs.push(true);
|
|
@@ -11041,13 +11414,17 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
11041
11414
|
safeArgs.push(null);
|
|
11042
11415
|
return !requireAll;
|
|
11043
11416
|
}
|
|
11044
|
-
const
|
|
11417
|
+
const decl = results[0].results[0];
|
|
11418
|
+
const safety = getSafety(decl);
|
|
11045
11419
|
safeArgs.push(safety);
|
|
11046
11420
|
if (!safety) {
|
|
11047
11421
|
allSafe = false;
|
|
11048
11422
|
if (safety === null) {
|
|
11049
11423
|
return !requireAll;
|
|
11050
11424
|
}
|
|
11425
|
+
else if (decl.type === "VariableDeclarator") {
|
|
11426
|
+
argDecls[i] = decl;
|
|
11427
|
+
}
|
|
11051
11428
|
}
|
|
11052
11429
|
return true;
|
|
11053
11430
|
}
|
|
@@ -11060,34 +11437,91 @@ function getArgSafety(state, func, args, requireAll) {
|
|
|
11060
11437
|
}
|
|
11061
11438
|
if (allSafe && requireAll)
|
|
11062
11439
|
return true;
|
|
11063
|
-
|
|
11440
|
+
const callsSeen = new Set();
|
|
11441
|
+
const modifiedDecls = new Set();
|
|
11442
|
+
let modifiedUnknown = false;
|
|
11064
11443
|
const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
|
|
11065
11444
|
// look for uses of "unsafe" args that occur after a call.
|
|
11066
11445
|
// use post to do the checking, because arguments are evaluated
|
|
11067
11446
|
// prior to the call, so eg "return f(x.y);" is fine, but
|
|
11068
11447
|
// "return f()+x.y" is not.
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
|
|
11072
|
-
|
|
11073
|
-
|
|
11074
|
-
|
|
11075
|
-
|
|
11448
|
+
const { pre, post, stack } = state;
|
|
11449
|
+
try {
|
|
11450
|
+
delete state.pre;
|
|
11451
|
+
state.post = (node) => {
|
|
11452
|
+
switch (node.type) {
|
|
11453
|
+
case "AssignmentExpression":
|
|
11454
|
+
case "UpdateExpression": {
|
|
11455
|
+
const v = node.type == "UpdateExpression" ? node.argument : node.left;
|
|
11456
|
+
if (v.type === "Identifier" && (0,external_api_cjs_namespaceObject.hasProperty)(params, v.name)) {
|
|
11457
|
+
// If a parameter is modified, we can't just substitute the
|
|
11458
|
+
// argument wherever the parameter is used.
|
|
11459
|
+
safeArgs[params[v.name]] = null;
|
|
11460
|
+
break;
|
|
11461
|
+
}
|
|
11462
|
+
if (modifiedUnknown)
|
|
11463
|
+
break;
|
|
11464
|
+
const [, results] = state.lookup(v);
|
|
11465
|
+
if (results) {
|
|
11466
|
+
results.forEach((r) => r.results.forEach((decl) => decl.type === "VariableDeclarator" && modifiedDecls.add(decl)));
|
|
11467
|
+
}
|
|
11468
|
+
else {
|
|
11469
|
+
modifiedUnknown = true;
|
|
11470
|
+
}
|
|
11471
|
+
break;
|
|
11076
11472
|
}
|
|
11473
|
+
case "CallExpression":
|
|
11474
|
+
case "NewExpression":
|
|
11475
|
+
if (!modifiedUnknown) {
|
|
11476
|
+
const [, results] = state.lookup(node.callee, null,
|
|
11477
|
+
// calls are looked up as non-locals, but new is not
|
|
11478
|
+
node.type === "CallExpression" ? func.stack : state.stack);
|
|
11479
|
+
if (!results) {
|
|
11480
|
+
const callee_name = node.callee.type === "Identifier"
|
|
11481
|
+
? node.callee
|
|
11482
|
+
: node.callee.type === "MemberExpression"
|
|
11483
|
+
? (0,external_api_cjs_namespaceObject.isLookupCandidate)(node.callee)
|
|
11484
|
+
: null;
|
|
11485
|
+
if (callee_name) {
|
|
11486
|
+
const callees = state.allFunctions[callee_name.name];
|
|
11487
|
+
if (callees) {
|
|
11488
|
+
callees.forEach((callee) => callsSeen.add(callee));
|
|
11489
|
+
}
|
|
11490
|
+
}
|
|
11491
|
+
else {
|
|
11492
|
+
modifiedUnknown = true;
|
|
11493
|
+
}
|
|
11494
|
+
}
|
|
11495
|
+
else {
|
|
11496
|
+
const callees = node.type === "CallExpression"
|
|
11497
|
+
? findCallees(results)
|
|
11498
|
+
: findCalleesForNew(results);
|
|
11499
|
+
if (callees) {
|
|
11500
|
+
callees.forEach((callee) => callsSeen.add(callee));
|
|
11501
|
+
}
|
|
11502
|
+
}
|
|
11503
|
+
}
|
|
11504
|
+
break;
|
|
11505
|
+
case "Identifier":
|
|
11506
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(params, node.name) &&
|
|
11507
|
+
!safeArgs[params[node.name]] &&
|
|
11508
|
+
(modifiedUnknown ||
|
|
11509
|
+
!argDecls[params[node.name]] ||
|
|
11510
|
+
modifiedDecls.has(argDecls[params[node.name]]) ||
|
|
11511
|
+
Array.from(callsSeen).some((callee) => functionMayModify(state, callee, argDecls[params[node.name]])))) {
|
|
11512
|
+
safeArgs[params[node.name]] = null;
|
|
11513
|
+
}
|
|
11077
11514
|
}
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
}
|
|
11089
|
-
}
|
|
11090
|
-
});
|
|
11515
|
+
return null;
|
|
11516
|
+
};
|
|
11517
|
+
state.stack = func.stack;
|
|
11518
|
+
state.traverse(func.node.body);
|
|
11519
|
+
}
|
|
11520
|
+
finally {
|
|
11521
|
+
state.pre = pre;
|
|
11522
|
+
state.post = post;
|
|
11523
|
+
state.stack = stack;
|
|
11524
|
+
}
|
|
11091
11525
|
return safeArgs;
|
|
11092
11526
|
}
|
|
11093
11527
|
function canInline(state, func, args) {
|
|
@@ -11192,9 +11626,6 @@ function processInlineBody(state, func, call, root, params) {
|
|
|
11192
11626
|
state.pre = (node) => {
|
|
11193
11627
|
if (failed)
|
|
11194
11628
|
return [];
|
|
11195
|
-
node.start = call.start;
|
|
11196
|
-
node.end = call.end;
|
|
11197
|
-
node.loc = call.loc;
|
|
11198
11629
|
if (replacements.has(node))
|
|
11199
11630
|
return false;
|
|
11200
11631
|
const result = pre(node, state);
|
|
@@ -11209,6 +11640,7 @@ function processInlineBody(state, func, call, root, params) {
|
|
|
11209
11640
|
if (params[paramName] >= 0)
|
|
11210
11641
|
return null;
|
|
11211
11642
|
const name = renameVariable(state, locals, paramName) || paramName;
|
|
11643
|
+
locals.map[name] = true;
|
|
11212
11644
|
return {
|
|
11213
11645
|
type: "VariableDeclarator",
|
|
11214
11646
|
id: { type: "Identifier", name },
|
|
@@ -11227,31 +11659,49 @@ function processInlineBody(state, func, call, root, params) {
|
|
|
11227
11659
|
}
|
|
11228
11660
|
return result;
|
|
11229
11661
|
};
|
|
11662
|
+
const fixId = (node) => {
|
|
11663
|
+
if (state.inType)
|
|
11664
|
+
return null;
|
|
11665
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(params, node.name)) {
|
|
11666
|
+
const ix = params[node.name];
|
|
11667
|
+
if (ix >= 0) {
|
|
11668
|
+
const replacement = { ...call.arguments[ix] };
|
|
11669
|
+
replacements.add(replacement);
|
|
11670
|
+
return replacement;
|
|
11671
|
+
}
|
|
11672
|
+
return null;
|
|
11673
|
+
}
|
|
11674
|
+
const replacement = fixNodeScope(state, node, func.stack);
|
|
11675
|
+
if (!replacement) {
|
|
11676
|
+
failed = true;
|
|
11677
|
+
inlineDiagnostic(state, func, call, `Failed to resolve '${node.name}'`);
|
|
11678
|
+
}
|
|
11679
|
+
return replacement;
|
|
11680
|
+
};
|
|
11230
11681
|
state.post = (node) => {
|
|
11231
11682
|
if (failed)
|
|
11232
11683
|
return post(node, state);
|
|
11233
11684
|
let replacement = null;
|
|
11234
11685
|
switch (node.type) {
|
|
11235
|
-
case "
|
|
11236
|
-
if (
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
if (ix >= 0) {
|
|
11241
|
-
replacement = call.arguments[ix];
|
|
11242
|
-
replacements.add(replacement);
|
|
11243
|
-
return replacement;
|
|
11686
|
+
case "AssignmentExpression":
|
|
11687
|
+
if (node.left.type === "Identifier") {
|
|
11688
|
+
const rep = fixId(node.left);
|
|
11689
|
+
if (rep) {
|
|
11690
|
+
node.left = rep;
|
|
11244
11691
|
}
|
|
11245
|
-
break;
|
|
11246
11692
|
}
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11693
|
+
break;
|
|
11694
|
+
case "UpdateExpression":
|
|
11695
|
+
if (node.argument.type === "Identifier") {
|
|
11696
|
+
const rep = fixId(node.argument);
|
|
11697
|
+
if (rep) {
|
|
11698
|
+
node.argument = rep;
|
|
11699
|
+
}
|
|
11252
11700
|
}
|
|
11253
11701
|
break;
|
|
11254
|
-
|
|
11702
|
+
case "Identifier":
|
|
11703
|
+
replacement = fixId(node);
|
|
11704
|
+
break;
|
|
11255
11705
|
}
|
|
11256
11706
|
const ret = post(replacement || node, state);
|
|
11257
11707
|
return ret === false || ret ? ret : replacement;
|
|
@@ -11277,6 +11727,10 @@ function processInlineBody(state, func, call, root, params) {
|
|
|
11277
11727
|
}
|
|
11278
11728
|
}
|
|
11279
11729
|
function unused(expression, top) {
|
|
11730
|
+
const estmt = (expression) => withLoc({
|
|
11731
|
+
type: "ExpressionStatement",
|
|
11732
|
+
expression,
|
|
11733
|
+
}, expression);
|
|
11280
11734
|
switch (expression.type) {
|
|
11281
11735
|
case "Literal":
|
|
11282
11736
|
return [];
|
|
@@ -11288,9 +11742,50 @@ function unused(expression, top) {
|
|
|
11288
11742
|
if (expression.operator === "as") {
|
|
11289
11743
|
return unused(expression.left);
|
|
11290
11744
|
}
|
|
11291
|
-
// fall through
|
|
11292
|
-
case "LogicalExpression":
|
|
11293
11745
|
return unused(expression.left).concat(unused(expression.right));
|
|
11746
|
+
case "LogicalExpression": {
|
|
11747
|
+
const right = unused(expression.right);
|
|
11748
|
+
if (!right.length)
|
|
11749
|
+
return unused(expression.left);
|
|
11750
|
+
const consequent = withLoc({
|
|
11751
|
+
type: "BlockStatement",
|
|
11752
|
+
body: [estmt(expression.right)],
|
|
11753
|
+
}, expression.right);
|
|
11754
|
+
let alternate;
|
|
11755
|
+
if (expression.operator == "||") {
|
|
11756
|
+
alternate = { ...consequent };
|
|
11757
|
+
consequent.body = [];
|
|
11758
|
+
}
|
|
11759
|
+
return [
|
|
11760
|
+
withLoc({
|
|
11761
|
+
type: "IfStatement",
|
|
11762
|
+
test: expression.left,
|
|
11763
|
+
consequent,
|
|
11764
|
+
alternate,
|
|
11765
|
+
}, expression),
|
|
11766
|
+
];
|
|
11767
|
+
}
|
|
11768
|
+
case "ConditionalExpression": {
|
|
11769
|
+
const consequentExprs = unused(expression.consequent);
|
|
11770
|
+
const alternateExprs = unused(expression.alternate);
|
|
11771
|
+
if (!consequentExprs.length && !alternateExprs.length) {
|
|
11772
|
+
return unused(expression.test);
|
|
11773
|
+
}
|
|
11774
|
+
return [
|
|
11775
|
+
withLoc({
|
|
11776
|
+
type: "IfStatement",
|
|
11777
|
+
test: expression.test,
|
|
11778
|
+
consequent: withLoc({
|
|
11779
|
+
type: "BlockStatement",
|
|
11780
|
+
body: consequentExprs,
|
|
11781
|
+
}, expression.consequent),
|
|
11782
|
+
alternate: withLoc({
|
|
11783
|
+
type: "BlockStatement",
|
|
11784
|
+
body: alternateExprs,
|
|
11785
|
+
}, expression.alternate),
|
|
11786
|
+
}, expression),
|
|
11787
|
+
];
|
|
11788
|
+
}
|
|
11294
11789
|
case "UnaryExpression":
|
|
11295
11790
|
return unused(expression.argument);
|
|
11296
11791
|
case "MemberExpression":
|
|
@@ -11305,17 +11800,7 @@ function unused(expression, top) {
|
|
|
11305
11800
|
.map((p) => unused(p.key).concat(unused(p.value)))
|
|
11306
11801
|
.flat(1);
|
|
11307
11802
|
}
|
|
11308
|
-
return top
|
|
11309
|
-
? null
|
|
11310
|
-
: [
|
|
11311
|
-
{
|
|
11312
|
-
type: "ExpressionStatement",
|
|
11313
|
-
expression,
|
|
11314
|
-
start: expression.start,
|
|
11315
|
-
end: expression.end,
|
|
11316
|
-
loc: expression.loc,
|
|
11317
|
-
},
|
|
11318
|
-
];
|
|
11803
|
+
return top ? null : [estmt(expression)];
|
|
11319
11804
|
}
|
|
11320
11805
|
function diagnostic(state, loc, message, type = "INFO") {
|
|
11321
11806
|
if (!loc || !loc.source)
|
|
@@ -11348,6 +11833,10 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11348
11833
|
if (!func.node || !func.node.body) {
|
|
11349
11834
|
return null;
|
|
11350
11835
|
}
|
|
11836
|
+
const lastStmt = (block) => {
|
|
11837
|
+
const last = block.body.slice(-1)[0];
|
|
11838
|
+
return last.type === "BlockStatement" ? lastStmt(last) : [last, block];
|
|
11839
|
+
};
|
|
11351
11840
|
let retStmtCount = 0;
|
|
11352
11841
|
if (context.type === "ReturnStatement") {
|
|
11353
11842
|
const last = func.node.body.body.slice(-1)[0];
|
|
@@ -11363,21 +11852,25 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11363
11852
|
if (retStmtCount > 1) {
|
|
11364
11853
|
inlineDiagnostic(state, func, call, "Function had more than one return statement");
|
|
11365
11854
|
}
|
|
11366
|
-
else if (context.type === "AssignmentExpression"
|
|
11855
|
+
else if ((context.type === "AssignmentExpression" ||
|
|
11856
|
+
context.type === "VariableDeclarator") &&
|
|
11857
|
+
retStmtCount !== 1) {
|
|
11367
11858
|
inlineDiagnostic(state, func, call, "Function did not have a return statement");
|
|
11368
11859
|
return null;
|
|
11369
11860
|
}
|
|
11370
11861
|
if (retStmtCount === 1) {
|
|
11371
|
-
const last = func.node.body
|
|
11862
|
+
const [last] = lastStmt(func.node.body);
|
|
11372
11863
|
if (!last ||
|
|
11373
11864
|
last.type !== "ReturnStatement" ||
|
|
11374
|
-
(context.type === "AssignmentExpression"
|
|
11865
|
+
((context.type === "AssignmentExpression" ||
|
|
11866
|
+
context.type === "VariableDeclarator") &&
|
|
11867
|
+
!last.argument)) {
|
|
11375
11868
|
inlineDiagnostic(state, func, call, "There was a return statement, but not at the end of the function");
|
|
11376
11869
|
return null;
|
|
11377
11870
|
}
|
|
11378
11871
|
}
|
|
11379
11872
|
}
|
|
11380
|
-
const body =
|
|
11873
|
+
const body = cloneDeep(func.node.body);
|
|
11381
11874
|
const safeArgs = getArgSafety(state, func, call.arguments, false);
|
|
11382
11875
|
const params = Object.fromEntries(func.node.params.map((param, i) => {
|
|
11383
11876
|
const argnum = safeArgs === true || (safeArgs !== false && safeArgs[i] !== null)
|
|
@@ -11391,37 +11884,54 @@ function inlineWithArgs(state, func, call, context) {
|
|
|
11391
11884
|
}
|
|
11392
11885
|
diagnostic(state, call.loc, null);
|
|
11393
11886
|
if (context.type !== "ReturnStatement" && retStmtCount) {
|
|
11394
|
-
const last = body
|
|
11887
|
+
const [last, block] = lastStmt(body);
|
|
11395
11888
|
if (last.type != "ReturnStatement") {
|
|
11396
11889
|
throw new Error("ReturnStatement got lost!");
|
|
11397
11890
|
}
|
|
11398
|
-
if (
|
|
11399
|
-
context.
|
|
11400
|
-
|
|
11401
|
-
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
11891
|
+
if (last.argument) {
|
|
11892
|
+
if (context.type === "AssignmentExpression") {
|
|
11893
|
+
context.right = last.argument;
|
|
11894
|
+
block.body[block.body.length - 1] = {
|
|
11895
|
+
type: "ExpressionStatement",
|
|
11896
|
+
expression: context,
|
|
11897
|
+
};
|
|
11898
|
+
}
|
|
11899
|
+
else if (context.type === "VariableDeclarator") {
|
|
11900
|
+
const { id, init: _init, kind: _kind, ...rest } = context;
|
|
11901
|
+
block.body[block.body.length - 1] = {
|
|
11902
|
+
...rest,
|
|
11903
|
+
type: "ExpressionStatement",
|
|
11904
|
+
expression: {
|
|
11905
|
+
...rest,
|
|
11906
|
+
type: "AssignmentExpression",
|
|
11907
|
+
operator: "=",
|
|
11908
|
+
left: id.type === "Identifier" ? id : id.left,
|
|
11909
|
+
right: last.argument,
|
|
11910
|
+
},
|
|
11911
|
+
};
|
|
11912
|
+
}
|
|
11913
|
+
else {
|
|
11914
|
+
const side_exprs = unused(last.argument);
|
|
11915
|
+
block.body.splice(block.body.length - 1, 1, ...side_exprs);
|
|
11916
|
+
}
|
|
11408
11917
|
}
|
|
11409
11918
|
else {
|
|
11410
|
-
--
|
|
11919
|
+
--block.body.length;
|
|
11411
11920
|
}
|
|
11412
11921
|
}
|
|
11922
|
+
withLocDeep(body, context, context, true);
|
|
11413
11923
|
return body;
|
|
11414
11924
|
}
|
|
11415
11925
|
function inlineFunction(state, func, call, context) {
|
|
11416
11926
|
if (context) {
|
|
11417
11927
|
return inlineWithArgs(state, func, call, context);
|
|
11418
11928
|
}
|
|
11419
|
-
const retArg =
|
|
11929
|
+
const retArg = cloneDeep(func.node.body.body[0].argument);
|
|
11420
11930
|
const params = Object.fromEntries(func.node.params.map((param, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(param), i]));
|
|
11421
11931
|
const map = fixupLocalsMap(state);
|
|
11422
11932
|
const ret = processInlineBody(state, func, call, retArg, params);
|
|
11423
11933
|
state.localsStack[state.localsStack.length - 1].map = map;
|
|
11424
|
-
return ret;
|
|
11934
|
+
return ret && withLocDeep(ret, call, call, true);
|
|
11425
11935
|
}
|
|
11426
11936
|
function applyTypeIfNeeded(node) {
|
|
11427
11937
|
if ("enumType" in node && node.enumType) {
|
|
@@ -11526,25 +12036,1674 @@ function fixNodeScope(state, lookupNode, nodeStack) {
|
|
|
11526
12036
|
return null;
|
|
11527
12037
|
}
|
|
11528
12038
|
|
|
11529
|
-
;// CONCATENATED MODULE: ./src/
|
|
12039
|
+
;// CONCATENATED MODULE: ./src/pragma-checker.ts
|
|
11530
12040
|
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
12041
|
+
|
|
12042
|
+
|
|
12043
|
+
function pragmaChecker(state, ast, diagnostics) {
|
|
12044
|
+
const comments = ast.comments;
|
|
12045
|
+
if (!comments)
|
|
12046
|
+
return;
|
|
12047
|
+
diagnostics = diagnostics
|
|
12048
|
+
?.slice()
|
|
12049
|
+
.sort((d1, d2) => d1.loc.start < d2.loc.start ? -1 : d1.loc.start == d2.loc.start ? 0 : 1);
|
|
12050
|
+
let diagIndex = 0;
|
|
12051
|
+
let index = -1;
|
|
12052
|
+
let comment;
|
|
12053
|
+
let matchers;
|
|
12054
|
+
const next = () => {
|
|
12055
|
+
while (++index < comments.length) {
|
|
12056
|
+
comment = comments[index];
|
|
12057
|
+
let match = comment.value.match(/^\s*@(match|expect)\s+(.+)/);
|
|
12058
|
+
if (!match)
|
|
12059
|
+
continue;
|
|
12060
|
+
const kind = match[1];
|
|
12061
|
+
let str = match[2];
|
|
12062
|
+
matchers = [];
|
|
12063
|
+
while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
|
|
12064
|
+
matchers.push({ kind, quote: match[1], needle: match[2] });
|
|
12065
|
+
str = str.substring(match[0].length);
|
|
12066
|
+
if (!str.length)
|
|
12067
|
+
break;
|
|
12068
|
+
}
|
|
12069
|
+
if (!str.length)
|
|
12070
|
+
break;
|
|
12071
|
+
if (!matchers.length) {
|
|
12072
|
+
match = str.match(/^(\S+)\s+$/);
|
|
12073
|
+
if (match) {
|
|
12074
|
+
matchers.push({ kind, quote: '"', needle: match[1] });
|
|
12075
|
+
break;
|
|
12076
|
+
}
|
|
12077
|
+
}
|
|
12078
|
+
diagnostic(state, comment.loc, `Build pragma '${comment.value}' is invalid`, "ERROR");
|
|
12079
|
+
}
|
|
12080
|
+
};
|
|
12081
|
+
const matcher = (quote, needle, haystack) => {
|
|
12082
|
+
if (quote == '"') {
|
|
12083
|
+
return haystack.includes(needle);
|
|
12084
|
+
}
|
|
12085
|
+
const re = new RegExp(needle.replace(/@(\d+)/g, "(pre_)?$1(_\\d+)?"));
|
|
12086
|
+
return re.test(haystack);
|
|
12087
|
+
};
|
|
12088
|
+
next();
|
|
12089
|
+
traverseAst(ast, (node) => {
|
|
12090
|
+
if (index >= comments.length)
|
|
12091
|
+
return false;
|
|
12092
|
+
if (node.start && node.start >= (comment.end || Infinity)) {
|
|
12093
|
+
const { kind, quote, needle } = matchers.shift();
|
|
12094
|
+
if (kind === "match") {
|
|
12095
|
+
const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/([\r\n]|\s)+/g, " ");
|
|
12096
|
+
if (!matcher(quote, needle, haystack)) {
|
|
12097
|
+
matcher(quote, needle, haystack);
|
|
12098
|
+
diagnostic(state, comment.loc, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
|
|
12099
|
+
}
|
|
12100
|
+
}
|
|
12101
|
+
else if (kind === "expect") {
|
|
12102
|
+
const locCmp = (a, b) => {
|
|
12103
|
+
if (!b)
|
|
12104
|
+
return -1;
|
|
12105
|
+
if (a.start.line < b.start.line)
|
|
12106
|
+
return -1;
|
|
12107
|
+
if (a.start.line === b.start.line &&
|
|
12108
|
+
a.start.column < b.start.column) {
|
|
12109
|
+
return -1;
|
|
12110
|
+
}
|
|
12111
|
+
if (a.end.line > b.end.line)
|
|
12112
|
+
return 1;
|
|
12113
|
+
if (a.end.line === b.end.line && a.end.column >= b.end.column) {
|
|
12114
|
+
return 1;
|
|
12115
|
+
}
|
|
12116
|
+
return 0;
|
|
12117
|
+
};
|
|
12118
|
+
let found = false;
|
|
12119
|
+
if (diagnostics) {
|
|
12120
|
+
while (true) {
|
|
12121
|
+
if (diagIndex >= diagnostics.length) {
|
|
12122
|
+
diagnostics = null;
|
|
12123
|
+
break;
|
|
12124
|
+
}
|
|
12125
|
+
const diag = diagnostics[diagIndex];
|
|
12126
|
+
const cmp = locCmp(diag.loc, node.loc);
|
|
12127
|
+
if (cmp > 0) {
|
|
12128
|
+
break;
|
|
12129
|
+
}
|
|
12130
|
+
diagIndex++;
|
|
12131
|
+
if (cmp < 0)
|
|
12132
|
+
continue;
|
|
12133
|
+
if (matcher(quote, needle, diag.message)) {
|
|
12134
|
+
found = true;
|
|
12135
|
+
diag.type = "INFO";
|
|
12136
|
+
}
|
|
12137
|
+
}
|
|
12138
|
+
}
|
|
12139
|
+
if (!found) {
|
|
12140
|
+
diagnostic(state, comment.loc, `Missing error message '${needle}`, "ERROR");
|
|
12141
|
+
}
|
|
12142
|
+
}
|
|
12143
|
+
if (matchers.length) {
|
|
12144
|
+
// if we're checking a series of nodes, we need
|
|
12145
|
+
// to skip over this one.
|
|
12146
|
+
return false;
|
|
12147
|
+
}
|
|
12148
|
+
next();
|
|
12149
|
+
}
|
|
12150
|
+
return null;
|
|
12151
|
+
});
|
|
12152
|
+
}
|
|
12153
|
+
|
|
12154
|
+
;// CONCATENATED MODULE: ./src/control-flow.ts
|
|
12155
|
+
|
|
12156
|
+
|
|
12157
|
+
const Terminals = {
|
|
12158
|
+
BreakStatement: "break",
|
|
12159
|
+
ContinueStatement: "continue",
|
|
12160
|
+
ReturnStatement: null,
|
|
12161
|
+
ThrowStatement: "throw",
|
|
12162
|
+
};
|
|
12163
|
+
class LocalState {
|
|
12164
|
+
constructor(func) {
|
|
12165
|
+
this.stack = [];
|
|
12166
|
+
this.info = new Map();
|
|
12167
|
+
this.curBlock = {};
|
|
12168
|
+
this.unreachable = false;
|
|
12169
|
+
this.push(func);
|
|
12170
|
+
}
|
|
12171
|
+
push(node) {
|
|
12172
|
+
const top = { node };
|
|
12173
|
+
this.stack.push(top);
|
|
12174
|
+
return top;
|
|
12175
|
+
}
|
|
12176
|
+
pop() {
|
|
12177
|
+
return this.stack.pop();
|
|
12178
|
+
}
|
|
12179
|
+
top(depth) {
|
|
12180
|
+
return this.stack[this.stack.length - (depth || 1)];
|
|
12181
|
+
}
|
|
12182
|
+
addEdge(from, to) {
|
|
12183
|
+
if (!from.succs) {
|
|
12184
|
+
from.succs = [to];
|
|
12185
|
+
}
|
|
12186
|
+
else {
|
|
12187
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(from.succs, to);
|
|
12188
|
+
}
|
|
12189
|
+
if (!to.preds) {
|
|
12190
|
+
to.preds = [from];
|
|
12191
|
+
}
|
|
12192
|
+
else {
|
|
12193
|
+
(0,external_util_cjs_namespaceObject.pushUnique)(to.preds, from);
|
|
12194
|
+
}
|
|
12195
|
+
}
|
|
12196
|
+
newBlock(block) {
|
|
12197
|
+
if (!block)
|
|
12198
|
+
block = {};
|
|
12199
|
+
if (!this.unreachable) {
|
|
12200
|
+
this.addEdge(this.curBlock, block);
|
|
12201
|
+
}
|
|
12202
|
+
this.unreachable = false;
|
|
12203
|
+
for (let i = this.stack.length; i--;) {
|
|
12204
|
+
const si = this.stack[i];
|
|
12205
|
+
if (si.throw) {
|
|
12206
|
+
block.exsucc = si.throw;
|
|
12207
|
+
if (!si.throw.expreds) {
|
|
12208
|
+
si.throw.expreds = [block];
|
|
12209
|
+
}
|
|
12210
|
+
else {
|
|
12211
|
+
si.throw.expreds.push(block);
|
|
12212
|
+
}
|
|
12213
|
+
break;
|
|
12214
|
+
}
|
|
12215
|
+
}
|
|
12216
|
+
return (this.curBlock = block);
|
|
12217
|
+
}
|
|
12218
|
+
terminal(type) {
|
|
12219
|
+
const re = Terminals[type];
|
|
12220
|
+
if (re) {
|
|
12221
|
+
for (let i = this.stack.length; i--;) {
|
|
12222
|
+
const target = this.stack[i][re];
|
|
12223
|
+
if (target) {
|
|
12224
|
+
this.addEdge(this.curBlock, target);
|
|
12225
|
+
break;
|
|
12226
|
+
}
|
|
12227
|
+
}
|
|
12228
|
+
}
|
|
12229
|
+
this.unreachable = true;
|
|
12230
|
+
}
|
|
12231
|
+
}
|
|
12232
|
+
function buildReducedGraph(state, func, notice) {
|
|
12233
|
+
const { stack, pre, post } = state;
|
|
12234
|
+
try {
|
|
12235
|
+
const localState = new LocalState(func.node);
|
|
12236
|
+
const ret = localState.curBlock;
|
|
12237
|
+
state.stack = func.stack;
|
|
12238
|
+
const stmtStack = [func.node];
|
|
12239
|
+
let tryActive = 0;
|
|
12240
|
+
state.pre = (node) => {
|
|
12241
|
+
if (state.inType || localState.unreachable) {
|
|
12242
|
+
return [];
|
|
12243
|
+
}
|
|
12244
|
+
if (!localState.curBlock.node &&
|
|
12245
|
+
(isStatement(node) || isExpression(node))) {
|
|
12246
|
+
localState.curBlock.node = node;
|
|
12247
|
+
}
|
|
12248
|
+
if (isStatement(node)) {
|
|
12249
|
+
stmtStack.push(node);
|
|
12250
|
+
}
|
|
12251
|
+
switch (node.type) {
|
|
12252
|
+
case "AttributeList":
|
|
12253
|
+
return [];
|
|
12254
|
+
case "SwitchStatement": {
|
|
12255
|
+
const top = localState.push(node);
|
|
12256
|
+
top.break = {};
|
|
12257
|
+
state.traverse(node.discriminant);
|
|
12258
|
+
const testBlocks = [];
|
|
12259
|
+
let defaultSeen = false;
|
|
12260
|
+
node.cases.forEach((sc, i) => {
|
|
12261
|
+
if (sc.test) {
|
|
12262
|
+
state.traverse(sc.test);
|
|
12263
|
+
testBlocks[i] = localState.curBlock;
|
|
12264
|
+
localState.newBlock();
|
|
12265
|
+
}
|
|
12266
|
+
else {
|
|
12267
|
+
defaultSeen = true;
|
|
12268
|
+
}
|
|
12269
|
+
});
|
|
12270
|
+
const endOfTests = localState.curBlock;
|
|
12271
|
+
if (!defaultSeen) {
|
|
12272
|
+
localState.addEdge(endOfTests, top.break);
|
|
12273
|
+
}
|
|
12274
|
+
localState.unreachable = true;
|
|
12275
|
+
node.cases.forEach((sc, i) => {
|
|
12276
|
+
localState.newBlock();
|
|
12277
|
+
localState.addEdge(testBlocks[i] || endOfTests, localState.curBlock);
|
|
12278
|
+
sc.consequent.every((s) => {
|
|
12279
|
+
state.traverse(s);
|
|
12280
|
+
return !localState.unreachable;
|
|
12281
|
+
});
|
|
12282
|
+
});
|
|
12283
|
+
localState.newBlock(top.break);
|
|
12284
|
+
localState.unreachable = !top.break.preds;
|
|
12285
|
+
return [];
|
|
12286
|
+
}
|
|
12287
|
+
case "DoWhileStatement":
|
|
12288
|
+
case "WhileStatement": {
|
|
12289
|
+
localState.push(node);
|
|
12290
|
+
const top = localState.top();
|
|
12291
|
+
top.break = {};
|
|
12292
|
+
top.continue = {};
|
|
12293
|
+
let head;
|
|
12294
|
+
if (node.type === "WhileStatement") {
|
|
12295
|
+
head = localState.newBlock(top.continue);
|
|
12296
|
+
state.traverse(node.test);
|
|
12297
|
+
localState.addEdge(localState.curBlock, top.break);
|
|
12298
|
+
localState.newBlock();
|
|
12299
|
+
}
|
|
12300
|
+
else {
|
|
12301
|
+
head = localState.newBlock();
|
|
12302
|
+
}
|
|
12303
|
+
state.traverse(node.body);
|
|
12304
|
+
if (node.type === "DoWhileStatement") {
|
|
12305
|
+
localState.newBlock(top.continue);
|
|
12306
|
+
state.traverse(node.test);
|
|
12307
|
+
localState.addEdge(localState.curBlock, top.break);
|
|
12308
|
+
}
|
|
12309
|
+
localState.addEdge(localState.curBlock, head);
|
|
12310
|
+
localState.curBlock = top.break;
|
|
12311
|
+
return [];
|
|
12312
|
+
}
|
|
12313
|
+
case "TryStatement": {
|
|
12314
|
+
const top = localState.push(node);
|
|
12315
|
+
const catches = (top.throw = {});
|
|
12316
|
+
// This edge shouldn't exist, but we can trigger
|
|
12317
|
+
// (incorrect) "variable may not be initialized" errors
|
|
12318
|
+
// in the monkey c compiler without it.
|
|
12319
|
+
// https://forums.garmin.com/developer/connect-iq/i/bug-reports/incorrect-maybe-uninitialized-error
|
|
12320
|
+
localState.addEdge(localState.curBlock, top.throw);
|
|
12321
|
+
localState.newBlock();
|
|
12322
|
+
tryActive++;
|
|
12323
|
+
state.traverse(node.block);
|
|
12324
|
+
tryActive--;
|
|
12325
|
+
delete top.throw;
|
|
12326
|
+
top.posttry = {};
|
|
12327
|
+
const tryFallsThrough = !localState.unreachable;
|
|
12328
|
+
if (node.finalizer) {
|
|
12329
|
+
tryActive++;
|
|
12330
|
+
top.throw = top.finally = {};
|
|
12331
|
+
// curBlock branches to finally, no matter how it exits.
|
|
12332
|
+
localState.addEdge(localState.curBlock, top.finally);
|
|
12333
|
+
}
|
|
12334
|
+
else {
|
|
12335
|
+
if (!localState.unreachable) {
|
|
12336
|
+
localState.addEdge(localState.curBlock, top.posttry);
|
|
12337
|
+
}
|
|
12338
|
+
}
|
|
12339
|
+
localState.unreachable = true;
|
|
12340
|
+
localState.newBlock(catches);
|
|
12341
|
+
if (node.handler) {
|
|
12342
|
+
state.traverse(node.handler);
|
|
12343
|
+
if (top.throw) {
|
|
12344
|
+
tryActive--;
|
|
12345
|
+
delete top.throw;
|
|
12346
|
+
}
|
|
12347
|
+
// Each "catch (ex instanceof Foo)" chains to the next,
|
|
12348
|
+
// but "catch (ex)" terminates the list. If the end
|
|
12349
|
+
// of the chain has a predecessor, its possible that
|
|
12350
|
+
// none of the conditions matched, so the exception
|
|
12351
|
+
// will propagate from there.
|
|
12352
|
+
if (localState.curBlock.preds) {
|
|
12353
|
+
localState.terminal("ThrowStatement");
|
|
12354
|
+
}
|
|
12355
|
+
}
|
|
12356
|
+
if (top.throw) {
|
|
12357
|
+
tryActive--;
|
|
12358
|
+
delete top.throw;
|
|
12359
|
+
}
|
|
12360
|
+
if (node.finalizer) {
|
|
12361
|
+
localState.unreachable = true;
|
|
12362
|
+
localState.newBlock(top.finally);
|
|
12363
|
+
delete top.finally;
|
|
12364
|
+
state.traverse(node.finalizer);
|
|
12365
|
+
if (tryFallsThrough && !localState.unreachable) {
|
|
12366
|
+
localState.addEdge(localState.curBlock, top.posttry);
|
|
12367
|
+
}
|
|
12368
|
+
localState.terminal("ThrowStatement");
|
|
12369
|
+
}
|
|
12370
|
+
localState.unreachable = true;
|
|
12371
|
+
localState.newBlock(top.posttry);
|
|
12372
|
+
return [];
|
|
12373
|
+
}
|
|
12374
|
+
case "CatchClause": {
|
|
12375
|
+
const top = localState.top();
|
|
12376
|
+
if (!localState.curBlock.preds && !localState.curBlock.expreds) {
|
|
12377
|
+
return [];
|
|
12378
|
+
}
|
|
12379
|
+
const next = {};
|
|
12380
|
+
if (node.param && node.param.type === "BinaryExpression") {
|
|
12381
|
+
state.traverse(node.param);
|
|
12382
|
+
localState.addEdge(localState.curBlock, next);
|
|
12383
|
+
localState.newBlock();
|
|
12384
|
+
}
|
|
12385
|
+
state.traverse(node.body);
|
|
12386
|
+
if (top.finally) {
|
|
12387
|
+
// this edge exists even if this point is unreachable
|
|
12388
|
+
localState.addEdge(localState.curBlock, top.finally);
|
|
12389
|
+
}
|
|
12390
|
+
if (!localState.unreachable) {
|
|
12391
|
+
if (!top.posttry)
|
|
12392
|
+
top.posttry = {};
|
|
12393
|
+
localState.addEdge(localState.curBlock, top.posttry);
|
|
12394
|
+
}
|
|
12395
|
+
localState.unreachable = true;
|
|
12396
|
+
localState.newBlock(next);
|
|
12397
|
+
return [];
|
|
12398
|
+
}
|
|
12399
|
+
case "ForStatement": {
|
|
12400
|
+
const top = localState.push(node);
|
|
12401
|
+
if (node.init)
|
|
12402
|
+
state.traverse(node.init);
|
|
12403
|
+
const head = localState.newBlock();
|
|
12404
|
+
top.break = {};
|
|
12405
|
+
top.continue = {};
|
|
12406
|
+
if (node.test) {
|
|
12407
|
+
state.traverse(node.test);
|
|
12408
|
+
localState.addEdge(localState.curBlock, top.break);
|
|
12409
|
+
localState.newBlock();
|
|
12410
|
+
}
|
|
12411
|
+
state.traverse(node.body);
|
|
12412
|
+
localState.newBlock(top.continue);
|
|
12413
|
+
if (node.update) {
|
|
12414
|
+
state.traverse(node.update);
|
|
12415
|
+
}
|
|
12416
|
+
if (!localState.unreachable) {
|
|
12417
|
+
localState.addEdge(localState.curBlock, head);
|
|
12418
|
+
}
|
|
12419
|
+
// there is no fall through from the end of the loop
|
|
12420
|
+
// to the next block. The only way there is via break
|
|
12421
|
+
// or the test failing.
|
|
12422
|
+
localState.unreachable = true;
|
|
12423
|
+
localState.newBlock(top.break);
|
|
12424
|
+
if (!top.break.preds) {
|
|
12425
|
+
localState.unreachable = true;
|
|
12426
|
+
}
|
|
12427
|
+
return [];
|
|
12428
|
+
}
|
|
12429
|
+
case "IfStatement":
|
|
12430
|
+
case "ConditionalExpression": {
|
|
12431
|
+
state.traverse(node.test);
|
|
12432
|
+
const alternate = {};
|
|
12433
|
+
localState.addEdge(localState.curBlock, alternate);
|
|
12434
|
+
localState.newBlock();
|
|
12435
|
+
state.traverse(node.consequent);
|
|
12436
|
+
const consequent = localState.unreachable
|
|
12437
|
+
? null
|
|
12438
|
+
: localState.curBlock;
|
|
12439
|
+
localState.unreachable = true;
|
|
12440
|
+
localState.newBlock(alternate);
|
|
12441
|
+
if (node.alternate) {
|
|
12442
|
+
state.traverse(node.alternate);
|
|
12443
|
+
if (!localState.unreachable) {
|
|
12444
|
+
localState.newBlock();
|
|
12445
|
+
}
|
|
12446
|
+
}
|
|
12447
|
+
if (consequent) {
|
|
12448
|
+
if (localState.unreachable) {
|
|
12449
|
+
localState.newBlock();
|
|
12450
|
+
}
|
|
12451
|
+
localState.addEdge(consequent, localState.curBlock);
|
|
12452
|
+
}
|
|
12453
|
+
return [];
|
|
12454
|
+
}
|
|
12455
|
+
case "LogicalExpression": {
|
|
12456
|
+
state.traverse(node.left);
|
|
12457
|
+
if (localState.unreachable)
|
|
12458
|
+
break;
|
|
12459
|
+
const mid = localState.curBlock;
|
|
12460
|
+
localState.newBlock();
|
|
12461
|
+
state.traverse(node.right);
|
|
12462
|
+
localState.newBlock();
|
|
12463
|
+
localState.addEdge(mid, localState.curBlock);
|
|
12464
|
+
return [];
|
|
12465
|
+
}
|
|
12466
|
+
case "VariableDeclarator":
|
|
12467
|
+
return ["init"];
|
|
12468
|
+
case "MemberExpression":
|
|
12469
|
+
if (!node.computed) {
|
|
12470
|
+
return ["object"];
|
|
12471
|
+
}
|
|
12472
|
+
break;
|
|
12473
|
+
case "UnaryExpression":
|
|
12474
|
+
if (node.operator === ":") {
|
|
12475
|
+
return [];
|
|
12476
|
+
}
|
|
12477
|
+
break;
|
|
12478
|
+
case "UpdateExpression":
|
|
12479
|
+
// We don't want to traverse the argument, since then it would
|
|
12480
|
+
// look like a ref, rather than a def. But if its a
|
|
12481
|
+
// MemberExpression, we *do* want to traverse the subexpressions
|
|
12482
|
+
// as potential refs.
|
|
12483
|
+
if (node.argument.type === "MemberExpression") {
|
|
12484
|
+
state.traverse(node.argument.object);
|
|
12485
|
+
if (node.argument.computed) {
|
|
12486
|
+
state.traverse(node.argument.property);
|
|
12487
|
+
}
|
|
12488
|
+
}
|
|
12489
|
+
return [];
|
|
12490
|
+
case "AssignmentExpression":
|
|
12491
|
+
if (node.left.type === "MemberExpression") {
|
|
12492
|
+
state.traverse(node.left.object);
|
|
12493
|
+
if (node.left.computed) {
|
|
12494
|
+
state.traverse(node.left.property);
|
|
12495
|
+
}
|
|
12496
|
+
}
|
|
12497
|
+
return ["right"];
|
|
12498
|
+
case "ThrowStatement":
|
|
12499
|
+
case "ReturnStatement":
|
|
12500
|
+
if (node.argument) {
|
|
12501
|
+
state.traverse(node.argument);
|
|
12502
|
+
}
|
|
12503
|
+
// fall through
|
|
12504
|
+
case "BreakStatement":
|
|
12505
|
+
case "ContinueStatement":
|
|
12506
|
+
localState.terminal(node.type);
|
|
12507
|
+
return [];
|
|
12508
|
+
}
|
|
12509
|
+
return null;
|
|
12510
|
+
};
|
|
12511
|
+
const addEvent = (block, event) => {
|
|
12512
|
+
if (!block.events) {
|
|
12513
|
+
block.events = [event];
|
|
12514
|
+
}
|
|
12515
|
+
else {
|
|
12516
|
+
block.events.push(event);
|
|
12517
|
+
}
|
|
12518
|
+
};
|
|
12519
|
+
state.post = (node) => {
|
|
12520
|
+
const curStmt = stmtStack[stmtStack.length - 1];
|
|
12521
|
+
if (!state.inType) {
|
|
12522
|
+
const throws = tryActive > 0 && mayThrow(node);
|
|
12523
|
+
const event = notice(node, curStmt, throws);
|
|
12524
|
+
if (throws) {
|
|
12525
|
+
if (!event) {
|
|
12526
|
+
throw new Error("mayThrow expression in try/catch must generate an event");
|
|
12527
|
+
}
|
|
12528
|
+
}
|
|
12529
|
+
else if (event) {
|
|
12530
|
+
event.mayThrow = false;
|
|
12531
|
+
}
|
|
12532
|
+
if (event) {
|
|
12533
|
+
if (event.mayThrow) {
|
|
12534
|
+
for (let i = localState.stack.length; i--;) {
|
|
12535
|
+
const target = localState.stack[i].throw;
|
|
12536
|
+
if (target) {
|
|
12537
|
+
if (localState.curBlock.exsucc) {
|
|
12538
|
+
if (localState.curBlock.exsucc !== target) {
|
|
12539
|
+
throw new Error(`Block has multiple throw targets`);
|
|
12540
|
+
}
|
|
12541
|
+
}
|
|
12542
|
+
else {
|
|
12543
|
+
localState.curBlock.exsucc = target;
|
|
12544
|
+
if (!target.expreds) {
|
|
12545
|
+
target.expreds = [localState.curBlock];
|
|
12546
|
+
}
|
|
12547
|
+
else {
|
|
12548
|
+
target.expreds.push(localState.curBlock);
|
|
12549
|
+
}
|
|
12550
|
+
}
|
|
12551
|
+
break;
|
|
12552
|
+
}
|
|
12553
|
+
}
|
|
12554
|
+
}
|
|
12555
|
+
addEvent(localState.curBlock, event);
|
|
12556
|
+
}
|
|
12557
|
+
}
|
|
12558
|
+
if (curStmt === node) {
|
|
12559
|
+
stmtStack.pop();
|
|
12560
|
+
}
|
|
12561
|
+
if (localState.top().node === node) {
|
|
12562
|
+
localState.pop();
|
|
12563
|
+
}
|
|
12564
|
+
return null;
|
|
12565
|
+
};
|
|
12566
|
+
state.traverse(func.node);
|
|
12567
|
+
return cleanCfg(ret);
|
|
12568
|
+
}
|
|
12569
|
+
finally {
|
|
12570
|
+
state.pre = pre;
|
|
12571
|
+
state.post = post;
|
|
12572
|
+
state.stack = stack;
|
|
12573
|
+
}
|
|
12574
|
+
}
|
|
12575
|
+
function cleanCfg(head) {
|
|
12576
|
+
preOrderTraverse(head, (cur) => {
|
|
12577
|
+
if (cur.succs && cur.succs.length === 1) {
|
|
12578
|
+
const succ = cur.succs[0];
|
|
12579
|
+
if (succ !== head &&
|
|
12580
|
+
succ.preds.length === 1 &&
|
|
12581
|
+
(!cur.exsucc || cur.exsucc === succ.exsucc) &&
|
|
12582
|
+
(!succ.succs ||
|
|
12583
|
+
succ.succs.length === 1 ||
|
|
12584
|
+
(cur.preds && cur.preds.length === 1))) {
|
|
12585
|
+
if (cur.events) {
|
|
12586
|
+
if (succ.events) {
|
|
12587
|
+
cur.events.push(...succ.events);
|
|
12588
|
+
}
|
|
12589
|
+
}
|
|
12590
|
+
else if (succ.events) {
|
|
12591
|
+
cur.events = succ.events;
|
|
12592
|
+
}
|
|
12593
|
+
if (succ.exsucc) {
|
|
12594
|
+
const preds = succ.exsucc.expreds;
|
|
12595
|
+
for (let i = preds.length; i--;) {
|
|
12596
|
+
if (preds[i] === succ) {
|
|
12597
|
+
// If cur has an exsucc, we already
|
|
12598
|
+
// checked that its the same as succ's,
|
|
12599
|
+
// so we can just delete the edge.
|
|
12600
|
+
// Otherwise, we need to point it at cur.
|
|
12601
|
+
if (cur.exsucc) {
|
|
12602
|
+
preds.splice(i, 1);
|
|
12603
|
+
}
|
|
12604
|
+
else {
|
|
12605
|
+
preds[i] = cur;
|
|
12606
|
+
}
|
|
12607
|
+
}
|
|
12608
|
+
}
|
|
12609
|
+
}
|
|
12610
|
+
cur.exsucc = succ.exsucc;
|
|
12611
|
+
cur.succs = succ.succs;
|
|
12612
|
+
if (cur.succs) {
|
|
12613
|
+
cur.succs.forEach((s) => s.preds.forEach((p, i, arr) => {
|
|
12614
|
+
if (p === succ) {
|
|
12615
|
+
arr[i] = cur;
|
|
12616
|
+
}
|
|
12617
|
+
}));
|
|
12618
|
+
}
|
|
12619
|
+
if (!cur.node)
|
|
12620
|
+
cur.node = succ.node;
|
|
12621
|
+
}
|
|
12622
|
+
}
|
|
12623
|
+
});
|
|
12624
|
+
return head;
|
|
12625
|
+
}
|
|
12626
|
+
function postOrderTraverse(head, visitor) {
|
|
12627
|
+
const visited = new Set();
|
|
12628
|
+
const helper = (cur) => {
|
|
12629
|
+
if (visited.has(cur))
|
|
12630
|
+
return;
|
|
12631
|
+
visited.add(cur);
|
|
12632
|
+
if (cur.succs) {
|
|
12633
|
+
cur.succs.forEach((block) => helper(block));
|
|
12634
|
+
}
|
|
12635
|
+
if (cur.exsucc)
|
|
12636
|
+
helper(cur.exsucc);
|
|
12637
|
+
visitor(cur);
|
|
12638
|
+
};
|
|
12639
|
+
helper(head);
|
|
12640
|
+
}
|
|
12641
|
+
function preOrderTraverse(head, visitor) {
|
|
12642
|
+
const visited = new Set();
|
|
12643
|
+
const helper = (cur) => {
|
|
12644
|
+
if (visited.has(cur))
|
|
12645
|
+
return;
|
|
12646
|
+
visited.add(cur);
|
|
12647
|
+
visitor(cur);
|
|
12648
|
+
if (cur.succs) {
|
|
12649
|
+
cur.succs.forEach((block) => helper(block));
|
|
12650
|
+
}
|
|
12651
|
+
if (cur.exsucc)
|
|
12652
|
+
helper(cur.exsucc);
|
|
12653
|
+
};
|
|
12654
|
+
helper(head);
|
|
12655
|
+
}
|
|
12656
|
+
function getPostOrder(head) {
|
|
12657
|
+
const blocks = [];
|
|
12658
|
+
postOrderTraverse(head, (block) => blocks.push(block));
|
|
12659
|
+
return blocks;
|
|
12660
|
+
}
|
|
12661
|
+
function getPreOrder(head) {
|
|
12662
|
+
const blocks = [];
|
|
12663
|
+
postOrderTraverse(head, (block) => blocks.push(block));
|
|
12664
|
+
return blocks;
|
|
12665
|
+
}
|
|
12666
|
+
|
|
12667
|
+
// EXTERNAL MODULE: ./node_modules/priorityqueuejs/index.js
|
|
12668
|
+
var priorityqueuejs = __webpack_require__(2789);
|
|
12669
|
+
;// CONCATENATED MODULE: ./src/pre.ts
|
|
12670
|
+
|
|
12671
|
+
|
|
12672
|
+
|
|
12673
|
+
|
|
12674
|
+
|
|
12675
|
+
/**
|
|
12676
|
+
* This implements a pseudo Partial Redundancy Elimination
|
|
12677
|
+
* pass. It isn't quite like traditional PRE because we're
|
|
12678
|
+
* aiming to minimize size, not dynamic instructions. So
|
|
12679
|
+
* for us, its worthwhile to take something like:
|
|
12680
|
+
*
|
|
12681
|
+
* switch (x) {
|
|
12682
|
+
* case 1: foo(A.B); break;
|
|
12683
|
+
* case 2: foo(C); break;
|
|
12684
|
+
* case 3: bar(A.B); break;
|
|
12685
|
+
* }
|
|
12686
|
+
*
|
|
12687
|
+
* and rewrite it as
|
|
12688
|
+
*
|
|
12689
|
+
* var tmp = A.B;
|
|
12690
|
+
* switch (x) {
|
|
12691
|
+
* case 1: foo(tmp); break;
|
|
12692
|
+
* case 2: foo(C); break;
|
|
12693
|
+
* case 3: bar(tmp); break;
|
|
12694
|
+
* }
|
|
12695
|
+
*
|
|
12696
|
+
* because even though A.B wasn't used on all paths where we
|
|
12697
|
+
* inserted the temporary, we still reduced the code size.
|
|
12698
|
+
*/
|
|
12699
|
+
const logging = false;
|
|
12700
|
+
function declFullName(decl) {
|
|
12701
|
+
switch (decl.type) {
|
|
12702
|
+
case "Literal":
|
|
12703
|
+
return decl.raw || decl.value?.toString() || "null";
|
|
12704
|
+
case "VariableDeclarator":
|
|
12705
|
+
return decl.fullName;
|
|
12706
|
+
default:
|
|
12707
|
+
throw new Error(`Unexpected EventDecl type: ${decl.type}`);
|
|
12708
|
+
}
|
|
12709
|
+
}
|
|
12710
|
+
function declName(decl) {
|
|
12711
|
+
switch (decl.type) {
|
|
12712
|
+
case "Literal":
|
|
12713
|
+
return (decl.raw || decl.value?.toString() || "null").replace(/[^\w]/g, "_");
|
|
12714
|
+
case "VariableDeclarator":
|
|
12715
|
+
return decl.name;
|
|
12716
|
+
default:
|
|
12717
|
+
throw new Error(`Unexpected EventDecl type: ${decl.type}`);
|
|
12718
|
+
}
|
|
12719
|
+
}
|
|
12720
|
+
function logAntState(s, decl) {
|
|
12721
|
+
const defs = Array.from(s.ant).reduce((defs, event) => {
|
|
12722
|
+
if (event.type === "def" || event.type === "mod")
|
|
12723
|
+
defs++;
|
|
12724
|
+
return defs;
|
|
12725
|
+
}, 0);
|
|
12726
|
+
console.log(` - ${declFullName(decl)}: ${candidateCost(s)} bytes, ${s.ant.size - defs} refs, ${defs} defs, ${s.live ? "" : "!"}live, ${s.isIsolated ? "" : "!"}isolated`);
|
|
12727
|
+
console.log(` - members: ${Array.from(s.members)
|
|
12728
|
+
.map(([block, live]) => block.order + (live ? "t" : "f"))
|
|
12729
|
+
.join(", ")}`);
|
|
12730
|
+
}
|
|
12731
|
+
function logAntDecls(antDecls) {
|
|
12732
|
+
antDecls.forEach(logAntState);
|
|
12733
|
+
}
|
|
12734
|
+
function sizeBasedPRE(state, func) {
|
|
12735
|
+
if (!func.node.body)
|
|
12736
|
+
return;
|
|
12737
|
+
if (!state.config ||
|
|
12738
|
+
!state.config.sizeBasedPRE ||
|
|
12739
|
+
(typeof state.config.sizeBasedPRE === "string" &&
|
|
12740
|
+
state.config.sizeBasedPRE !== func.fullName)) {
|
|
12741
|
+
return;
|
|
12742
|
+
}
|
|
12743
|
+
const { graph: head, identifiers } = buildPREGraph(state, func);
|
|
12744
|
+
const candidates = computeAttributes(state, head);
|
|
12745
|
+
if (candidates) {
|
|
12746
|
+
if (logging) {
|
|
12747
|
+
console.log(`Found ${candidates.size} candidates in ${func.fullName}`);
|
|
12748
|
+
logAntDecls(candidates);
|
|
12749
|
+
}
|
|
12750
|
+
const nodeMap = new Map();
|
|
12751
|
+
const declMap = new Map();
|
|
12752
|
+
const variableDecl = withLoc({
|
|
12753
|
+
type: "VariableDeclaration",
|
|
12754
|
+
declarations: [],
|
|
12755
|
+
kind: "var",
|
|
12756
|
+
}, func.node.body);
|
|
12757
|
+
variableDecl.end = variableDecl.start;
|
|
12758
|
+
variableDecl.loc.end = variableDecl.loc.start;
|
|
12759
|
+
candidates.forEach((s, decl) => {
|
|
12760
|
+
let name;
|
|
12761
|
+
let i = 0;
|
|
12762
|
+
do {
|
|
12763
|
+
name = `pre_${declName(decl)}${i ? "_" + i : ""}`;
|
|
12764
|
+
if (!identifiers.has(name)) {
|
|
12765
|
+
identifiers.add(name);
|
|
12766
|
+
break;
|
|
12767
|
+
}
|
|
12768
|
+
i++;
|
|
12769
|
+
} while (true);
|
|
12770
|
+
declMap.set(decl, name);
|
|
12771
|
+
variableDecl.declarations.push(withLoc({
|
|
12772
|
+
type: "VariableDeclarator",
|
|
12773
|
+
id: withLoc({ type: "Identifier", name }, variableDecl),
|
|
12774
|
+
kind: "var",
|
|
12775
|
+
}, variableDecl));
|
|
12776
|
+
s.ant.forEach((event) => {
|
|
12777
|
+
const events = nodeMap.get(event.node);
|
|
12778
|
+
if (!events) {
|
|
12779
|
+
nodeMap.set(event.node, [event]);
|
|
12780
|
+
}
|
|
12781
|
+
else {
|
|
12782
|
+
events.push(event);
|
|
12783
|
+
}
|
|
12784
|
+
});
|
|
12785
|
+
});
|
|
12786
|
+
applyReplacements(func.node, nodeMap, declMap);
|
|
12787
|
+
func.node.body.body.unshift(variableDecl);
|
|
12788
|
+
}
|
|
12789
|
+
}
|
|
12790
|
+
function unhandledExpression(node) {
|
|
12791
|
+
throw new Error(`Unhandled expression type: ${node.type}`);
|
|
12792
|
+
}
|
|
12793
|
+
function buildPREGraph(state, func) {
|
|
12794
|
+
const findDecl = (node) => {
|
|
12795
|
+
if (node.type === "Identifier" ||
|
|
12796
|
+
(node.type === "MemberExpression" && !node.computed)) {
|
|
12797
|
+
const [, results] = state.lookup(node);
|
|
12798
|
+
if (results &&
|
|
12799
|
+
results.length === 1 &&
|
|
12800
|
+
results[0].parent?.type != "BlockStatement" &&
|
|
12801
|
+
results[0].results.length === 1 &&
|
|
12802
|
+
results[0].results[0].type === "VariableDeclarator") {
|
|
12803
|
+
return results[0].results[0];
|
|
12804
|
+
}
|
|
12805
|
+
}
|
|
12806
|
+
return null;
|
|
12807
|
+
};
|
|
12808
|
+
const literals = new Map();
|
|
12809
|
+
const identifiers = new Set();
|
|
12810
|
+
const liveDefs = new Map();
|
|
12811
|
+
const liveStmts = new Map();
|
|
12812
|
+
const liveDef = (def, stmt) => {
|
|
12813
|
+
let curNodes = liveDefs.get(def);
|
|
12814
|
+
if (!curNodes) {
|
|
12815
|
+
liveDefs.set(def, (curNodes = new Set()));
|
|
12816
|
+
}
|
|
12817
|
+
curNodes.add(stmt);
|
|
12818
|
+
let defs = liveStmts.get(stmt);
|
|
12819
|
+
if (!defs) {
|
|
12820
|
+
liveStmts.set(stmt, (defs = new Map()));
|
|
12821
|
+
}
|
|
12822
|
+
defs.set(def, (defs.get(def) || 0) + 1);
|
|
12823
|
+
};
|
|
12824
|
+
return {
|
|
12825
|
+
identifiers,
|
|
12826
|
+
graph: buildReducedGraph(state, func, (node, stmt, mayThrow) => {
|
|
12827
|
+
const defs = liveStmts.get(node);
|
|
12828
|
+
if (defs) {
|
|
12829
|
+
liveStmts.delete(node);
|
|
12830
|
+
defs.forEach((count, def) => {
|
|
12831
|
+
if (count > 1) {
|
|
12832
|
+
defs.set(def, count--);
|
|
12833
|
+
return;
|
|
12834
|
+
}
|
|
12835
|
+
const v = liveDefs.get(def);
|
|
12836
|
+
if (!v || !v.has(node)) {
|
|
12837
|
+
throw new Error(`No stmt in liveDef for ${def ? declFullName(def) : "null"}`);
|
|
12838
|
+
}
|
|
12839
|
+
v.delete(node);
|
|
12840
|
+
if (!v.size) {
|
|
12841
|
+
liveDefs.delete(def);
|
|
12842
|
+
}
|
|
12843
|
+
});
|
|
12844
|
+
}
|
|
12845
|
+
switch (node.type) {
|
|
12846
|
+
case "BinaryExpression":
|
|
12847
|
+
case "UnaryExpression":
|
|
12848
|
+
case "SizedArrayExpression":
|
|
12849
|
+
case "ArrayExpression":
|
|
12850
|
+
case "ObjectExpression":
|
|
12851
|
+
case "ThisExpression":
|
|
12852
|
+
case "LogicalExpression":
|
|
12853
|
+
case "ConditionalExpression":
|
|
12854
|
+
case "SequenceExpression":
|
|
12855
|
+
case "ParenthesizedExpression":
|
|
12856
|
+
break;
|
|
12857
|
+
case "Literal":
|
|
12858
|
+
if (refCost(node) > LocalRefCost) {
|
|
12859
|
+
let decl = literals.get(node.value);
|
|
12860
|
+
if (!decl) {
|
|
12861
|
+
decl = node;
|
|
12862
|
+
literals.set(node.value, decl);
|
|
12863
|
+
}
|
|
12864
|
+
return {
|
|
12865
|
+
type: "ref",
|
|
12866
|
+
node,
|
|
12867
|
+
decl: decl,
|
|
12868
|
+
mayThrow,
|
|
12869
|
+
};
|
|
12870
|
+
}
|
|
12871
|
+
break;
|
|
12872
|
+
case "Identifier":
|
|
12873
|
+
identifiers.add(node.name);
|
|
12874
|
+
// fall through
|
|
12875
|
+
case "MemberExpression":
|
|
12876
|
+
{
|
|
12877
|
+
const decl = findDecl(node);
|
|
12878
|
+
if (decl && decl.type === "VariableDeclarator") {
|
|
12879
|
+
const defStmts = (decl.node.kind === "var" && liveDefs.get(null)) ||
|
|
12880
|
+
liveDefs.get(decl);
|
|
12881
|
+
if (defStmts) {
|
|
12882
|
+
break;
|
|
12883
|
+
/*
|
|
12884
|
+
// hold off on this for now. we need to communicate
|
|
12885
|
+
// which defs need to be fixed, which involves yet-another
|
|
12886
|
+
// table.
|
|
12887
|
+
|
|
12888
|
+
if (defStmts.size !== 1) break;
|
|
12889
|
+
const fixable = isFixableStmt([...defStmts][0]);
|
|
12890
|
+
if (fixable === false) break;
|
|
12891
|
+
cost += fixable;
|
|
12892
|
+
*/
|
|
12893
|
+
}
|
|
12894
|
+
return {
|
|
12895
|
+
type: "ref",
|
|
12896
|
+
node,
|
|
12897
|
+
decl,
|
|
12898
|
+
mayThrow,
|
|
12899
|
+
};
|
|
12900
|
+
}
|
|
12901
|
+
}
|
|
12902
|
+
break;
|
|
12903
|
+
case "VariableDeclarator": {
|
|
12904
|
+
const decl = findDecl(node.id.type === "BinaryExpression" ? node.id.left : node.id);
|
|
12905
|
+
if (decl) {
|
|
12906
|
+
liveDef(decl, stmt);
|
|
12907
|
+
return {
|
|
12908
|
+
type: "def",
|
|
12909
|
+
node,
|
|
12910
|
+
decl,
|
|
12911
|
+
mayThrow,
|
|
12912
|
+
};
|
|
12913
|
+
}
|
|
12914
|
+
break;
|
|
12915
|
+
}
|
|
12916
|
+
case "AssignmentExpression": {
|
|
12917
|
+
const decl = findDecl(node.left);
|
|
12918
|
+
if (decl) {
|
|
12919
|
+
liveDef(decl, stmt);
|
|
12920
|
+
return {
|
|
12921
|
+
type: "def",
|
|
12922
|
+
node,
|
|
12923
|
+
decl,
|
|
12924
|
+
mayThrow,
|
|
12925
|
+
};
|
|
12926
|
+
}
|
|
12927
|
+
break;
|
|
12928
|
+
}
|
|
12929
|
+
case "UpdateExpression": {
|
|
12930
|
+
const decl = findDecl(node.argument);
|
|
12931
|
+
if (decl) {
|
|
12932
|
+
liveDef(decl, stmt);
|
|
12933
|
+
return {
|
|
12934
|
+
type: "def",
|
|
12935
|
+
node,
|
|
12936
|
+
decl,
|
|
12937
|
+
mayThrow,
|
|
12938
|
+
};
|
|
12939
|
+
}
|
|
12940
|
+
break;
|
|
12941
|
+
}
|
|
12942
|
+
case "NewExpression": {
|
|
12943
|
+
const [, results] = state.lookup(node.callee);
|
|
12944
|
+
const callees = results ? findCalleesForNew(results) : null;
|
|
12945
|
+
liveDef(null, stmt);
|
|
12946
|
+
return { type: "mod", node, mayThrow, callees };
|
|
12947
|
+
}
|
|
12948
|
+
case "CallExpression": {
|
|
12949
|
+
liveDef(null, stmt);
|
|
12950
|
+
const [, results] = state.lookup(node.callee);
|
|
12951
|
+
const callees = results ? findCallees(results) : null;
|
|
12952
|
+
return { type: "mod", node, mayThrow, callees };
|
|
12953
|
+
}
|
|
12954
|
+
default:
|
|
12955
|
+
if (!isExpression(node))
|
|
12956
|
+
break;
|
|
12957
|
+
unhandledExpression(node);
|
|
12958
|
+
}
|
|
12959
|
+
if (mayThrow) {
|
|
12960
|
+
return { type: "exn", node, mayThrow };
|
|
12961
|
+
}
|
|
12962
|
+
return null;
|
|
12963
|
+
}),
|
|
12964
|
+
};
|
|
12965
|
+
}
|
|
12966
|
+
function anticipatedDecls() {
|
|
12967
|
+
return new Map();
|
|
12968
|
+
}
|
|
12969
|
+
function equalSet(a, b) {
|
|
12970
|
+
if (a.size != b.size)
|
|
12971
|
+
return false;
|
|
12972
|
+
for (const item of a) {
|
|
12973
|
+
if (!b.has(item))
|
|
12974
|
+
return false;
|
|
12975
|
+
}
|
|
12976
|
+
return true;
|
|
12977
|
+
}
|
|
12978
|
+
function equalMap(a, b) {
|
|
12979
|
+
if (a.size != b.size)
|
|
12980
|
+
return false;
|
|
12981
|
+
for (const [item, value] of a) {
|
|
12982
|
+
if (b.get(item) !== value)
|
|
12983
|
+
return false;
|
|
12984
|
+
}
|
|
12985
|
+
return true;
|
|
12986
|
+
}
|
|
12987
|
+
function anticipatedState(node, events) {
|
|
12988
|
+
return { ant: events || new Set(), live: true, node, members: new Map() };
|
|
12989
|
+
}
|
|
12990
|
+
function cloneAnticipatedState(as) {
|
|
12991
|
+
return {
|
|
12992
|
+
ant: cloneSet(as.ant),
|
|
12993
|
+
live: as.live,
|
|
12994
|
+
node: as.node,
|
|
12995
|
+
members: new Map(as.members),
|
|
12996
|
+
};
|
|
12997
|
+
}
|
|
12998
|
+
function mergeAnticipatedState(ae, be) {
|
|
12999
|
+
mergeSet(ae.ant, be.ant);
|
|
13000
|
+
be.members.forEach((live, block) => ae.members.set(block, live));
|
|
13001
|
+
if (be.live)
|
|
13002
|
+
ae.live = true;
|
|
13003
|
+
}
|
|
13004
|
+
function cloneAnticipatedDecls(ad) {
|
|
13005
|
+
const copy = anticipatedDecls();
|
|
13006
|
+
for (const [k, v] of ad) {
|
|
13007
|
+
if (!v.isIsolated) {
|
|
13008
|
+
copy.set(k, cloneAnticipatedState(v));
|
|
13009
|
+
}
|
|
13010
|
+
}
|
|
13011
|
+
return copy;
|
|
13012
|
+
}
|
|
13013
|
+
function mergeAnticipatedDecls(a, b) {
|
|
13014
|
+
for (const [k, v] of b) {
|
|
13015
|
+
if (v.isIsolated)
|
|
13016
|
+
continue;
|
|
13017
|
+
const ae = a.get(k);
|
|
13018
|
+
if (ae) {
|
|
13019
|
+
mergeAnticipatedState(ae, v);
|
|
13020
|
+
}
|
|
13021
|
+
else {
|
|
13022
|
+
a.set(k, cloneAnticipatedState(v));
|
|
13023
|
+
}
|
|
13024
|
+
}
|
|
13025
|
+
}
|
|
13026
|
+
function equalStates(a, b) {
|
|
13027
|
+
if (a.size !== b.size)
|
|
13028
|
+
return false;
|
|
13029
|
+
for (const [k, ae] of a) {
|
|
13030
|
+
const be = b.get(k);
|
|
13031
|
+
if (!be ||
|
|
13032
|
+
be.live != ae.live ||
|
|
13033
|
+
be.isIsolated != ae.isIsolated ||
|
|
13034
|
+
!equalSet(ae.ant, be.ant) ||
|
|
13035
|
+
!equalMap(ae.members, be.members)) {
|
|
13036
|
+
return false;
|
|
13037
|
+
}
|
|
13038
|
+
}
|
|
13039
|
+
return true;
|
|
13040
|
+
}
|
|
13041
|
+
const LocalRefCost = 2;
|
|
13042
|
+
function refCost(node) {
|
|
13043
|
+
if (node.type === "Literal") {
|
|
13044
|
+
switch (typeof node.value) {
|
|
13045
|
+
case "string":
|
|
13046
|
+
return 5;
|
|
13047
|
+
case "bigint":
|
|
13048
|
+
case "number":
|
|
13049
|
+
return 5;
|
|
13050
|
+
case "boolean":
|
|
13051
|
+
return 2;
|
|
13052
|
+
default:
|
|
13053
|
+
if (node.value === null) {
|
|
13054
|
+
return 2;
|
|
13055
|
+
}
|
|
13056
|
+
return 0;
|
|
13057
|
+
}
|
|
13058
|
+
}
|
|
13059
|
+
// A read from a non-local identifier takes 8 bytes
|
|
13060
|
+
let cost = 8;
|
|
13061
|
+
if (node.type === "Identifier")
|
|
13062
|
+
return cost;
|
|
13063
|
+
while (true) {
|
|
13064
|
+
const next = node.object;
|
|
13065
|
+
if (next.type != "MemberExpression") {
|
|
13066
|
+
if (next.type != "ThisExpression") {
|
|
13067
|
+
cost += next.type === "Identifier" && next.name === "$" ? 4 : 6;
|
|
13068
|
+
}
|
|
13069
|
+
return cost;
|
|
13070
|
+
}
|
|
13071
|
+
node = next;
|
|
13072
|
+
cost += 6;
|
|
13073
|
+
}
|
|
13074
|
+
}
|
|
13075
|
+
function defCost(node) {
|
|
13076
|
+
return refCost(node) + 2;
|
|
13077
|
+
}
|
|
13078
|
+
function candidateBoundary(candState) {
|
|
13079
|
+
const boundary = new Set();
|
|
13080
|
+
candState.members.forEach((live, block) => {
|
|
13081
|
+
if (live && block !== candState.head) {
|
|
13082
|
+
if (block.preds) {
|
|
13083
|
+
block.preds.forEach((pred) => candState.members.has(pred) || boundary.add(pred));
|
|
13084
|
+
}
|
|
13085
|
+
}
|
|
13086
|
+
});
|
|
13087
|
+
if (candState.live) {
|
|
13088
|
+
if (!candState.head) {
|
|
13089
|
+
throw new Error(`Missing head`);
|
|
13090
|
+
}
|
|
13091
|
+
boundary.add(candState.head);
|
|
13092
|
+
}
|
|
13093
|
+
return boundary;
|
|
13094
|
+
}
|
|
13095
|
+
function candidateCost(candState) {
|
|
13096
|
+
let cost = 0;
|
|
13097
|
+
candState.ant.forEach((event) => {
|
|
13098
|
+
if (event.type === "ref") {
|
|
13099
|
+
cost -= refCost(candState.node) - LocalRefCost;
|
|
13100
|
+
}
|
|
13101
|
+
else {
|
|
13102
|
+
cost += defCost(candState.node);
|
|
13103
|
+
}
|
|
13104
|
+
});
|
|
13105
|
+
const boundarySize = candidateBoundary(candState).size;
|
|
13106
|
+
cost += defCost(candState.node) * boundarySize;
|
|
13107
|
+
return cost;
|
|
13108
|
+
}
|
|
13109
|
+
function computeAttributes(state, head) {
|
|
13110
|
+
const order = getPostOrder(head);
|
|
13111
|
+
order.forEach((block, i) => {
|
|
13112
|
+
block.order = i;
|
|
13113
|
+
});
|
|
13114
|
+
if (logging) {
|
|
13115
|
+
order.forEach((block) => {
|
|
13116
|
+
console.log(block.order, `(${block.node ? block.node.loc?.start.line : "??"})`, `Preds: ${(block.preds || [])
|
|
13117
|
+
.map((block) => block.order)
|
|
13118
|
+
.join(", ")}`);
|
|
13119
|
+
if (block.events) {
|
|
13120
|
+
block.events.forEach((event) => event.type !== "exn" &&
|
|
13121
|
+
console.log(` ${event.type}: ${event.decl ? declFullName(event.decl) : "??"}`));
|
|
13122
|
+
}
|
|
13123
|
+
console.log(`Succs: ${(block.succs || [])
|
|
13124
|
+
.map((block) => block.order)
|
|
13125
|
+
.join(", ")} ExSucc: ${block.exsucc ? block.exsucc.order : ""}`);
|
|
13126
|
+
});
|
|
13127
|
+
}
|
|
13128
|
+
const enqueued = new Set();
|
|
13129
|
+
const queue = new priorityqueuejs((b, a) => (a.order || 0) - (b.order || 0));
|
|
13130
|
+
const enqueue = (block) => {
|
|
13131
|
+
if (!enqueued.has(block)) {
|
|
13132
|
+
enqueued.add(block);
|
|
13133
|
+
queue.enq(block);
|
|
13134
|
+
}
|
|
13135
|
+
};
|
|
13136
|
+
const dequeue = () => {
|
|
13137
|
+
const block = queue.deq();
|
|
13138
|
+
enqueued.delete(block);
|
|
13139
|
+
return block;
|
|
13140
|
+
};
|
|
13141
|
+
const blockStates = [];
|
|
13142
|
+
/*
|
|
13143
|
+
Algorithm
|
|
13144
|
+
=========
|
|
13145
|
+
|
|
13146
|
+
Process blocks in post-order, and the events in reverse
|
|
13147
|
+
order to collect the AnticipatedState at the start of each
|
|
13148
|
+
Block.
|
|
13149
|
+
|
|
13150
|
+
Then for each EventDecl find the best starting block.
|
|
13151
|
+
*/
|
|
13152
|
+
const modMap = new Map();
|
|
13153
|
+
const getMod = (event, decl, id) => {
|
|
13154
|
+
if (id.type !== "Identifier" && id.type !== "MemberExpression") {
|
|
13155
|
+
throw new Error("Trying to modify a non-variable");
|
|
13156
|
+
}
|
|
13157
|
+
let eventMap = modMap.get(event);
|
|
13158
|
+
if (!eventMap) {
|
|
13159
|
+
modMap.set(event, (eventMap = new Map()));
|
|
13160
|
+
}
|
|
13161
|
+
let result = eventMap.get(decl);
|
|
13162
|
+
if (!result) {
|
|
13163
|
+
result = {
|
|
13164
|
+
type: "mod",
|
|
13165
|
+
node: event.node,
|
|
13166
|
+
decl,
|
|
13167
|
+
id,
|
|
13168
|
+
mayThrow: event.mayThrow,
|
|
13169
|
+
};
|
|
13170
|
+
eventMap.set(decl, result);
|
|
13171
|
+
}
|
|
13172
|
+
return result;
|
|
13173
|
+
};
|
|
13174
|
+
order.forEach((block) => enqueue(block));
|
|
13175
|
+
while (queue.size()) {
|
|
13176
|
+
const top = dequeue();
|
|
13177
|
+
if (top.order === undefined) {
|
|
13178
|
+
throw new Error(`Unreachable block was visited!`);
|
|
13179
|
+
}
|
|
13180
|
+
const curState = (top.succs &&
|
|
13181
|
+
top.succs.reduce((blockState, succ) => {
|
|
13182
|
+
const succState = blockStates[succ.order];
|
|
13183
|
+
if (succState) {
|
|
13184
|
+
if (!blockState) {
|
|
13185
|
+
blockState = cloneAnticipatedDecls(succState);
|
|
13186
|
+
}
|
|
13187
|
+
else {
|
|
13188
|
+
mergeAnticipatedDecls(blockState, succState);
|
|
13189
|
+
}
|
|
13190
|
+
}
|
|
13191
|
+
return blockState;
|
|
13192
|
+
}, null)) ||
|
|
13193
|
+
anticipatedDecls();
|
|
13194
|
+
if (top.events) {
|
|
13195
|
+
for (let i = top.events.length; i--;) {
|
|
13196
|
+
const event = top.events[i];
|
|
13197
|
+
if (event.mayThrow && top.exsucc) {
|
|
13198
|
+
const succState = blockStates[top.exsucc.order];
|
|
13199
|
+
if (succState) {
|
|
13200
|
+
mergeAnticipatedDecls(curState, succState);
|
|
13201
|
+
}
|
|
13202
|
+
}
|
|
13203
|
+
switch (event.type) {
|
|
13204
|
+
case "ref": {
|
|
13205
|
+
let candidates = curState.get(event.decl);
|
|
13206
|
+
if (!candidates) {
|
|
13207
|
+
candidates = anticipatedState(event.node);
|
|
13208
|
+
curState.set(event.decl, candidates);
|
|
13209
|
+
}
|
|
13210
|
+
candidates.ant.add(event);
|
|
13211
|
+
candidates.live = true;
|
|
13212
|
+
break;
|
|
13213
|
+
}
|
|
13214
|
+
case "mod": {
|
|
13215
|
+
curState.forEach((candidates, decl) => {
|
|
13216
|
+
if (decl.type === "VariableDeclarator" &&
|
|
13217
|
+
decl.node.kind === "var" &&
|
|
13218
|
+
candidates.live &&
|
|
13219
|
+
(!event.callees ||
|
|
13220
|
+
event.callees.some((callee) => functionMayModify(state, callee, decl)))) {
|
|
13221
|
+
candidates.ant.add(getMod(event, decl, candidates.node));
|
|
13222
|
+
candidates.live = false;
|
|
13223
|
+
}
|
|
13224
|
+
});
|
|
13225
|
+
break;
|
|
13226
|
+
}
|
|
13227
|
+
case "def": {
|
|
13228
|
+
let candidates = curState.get(event.decl);
|
|
13229
|
+
const isUpdate = event.node.type === "UpdateExpression" ||
|
|
13230
|
+
(event.node.type === "AssignmentExpression" &&
|
|
13231
|
+
event.node.operator !== "=");
|
|
13232
|
+
if (!candidates) {
|
|
13233
|
+
const target = event.node.type === "AssignmentExpression"
|
|
13234
|
+
? event.node.left
|
|
13235
|
+
: event.node.type === "UpdateExpression"
|
|
13236
|
+
? event.node.argument
|
|
13237
|
+
: event.node.id.type === "BinaryExpression"
|
|
13238
|
+
? event.node.id.left
|
|
13239
|
+
: event.node.id;
|
|
13240
|
+
candidates = anticipatedState(target);
|
|
13241
|
+
curState.set(event.decl, candidates);
|
|
13242
|
+
}
|
|
13243
|
+
if (isUpdate || candidates.live) {
|
|
13244
|
+
candidates.ant.add(event);
|
|
13245
|
+
}
|
|
13246
|
+
candidates.live = isUpdate;
|
|
13247
|
+
break;
|
|
13248
|
+
}
|
|
13249
|
+
}
|
|
13250
|
+
}
|
|
13251
|
+
}
|
|
13252
|
+
curState.forEach((antState) => {
|
|
13253
|
+
antState.head = top;
|
|
13254
|
+
antState.members.set(top, antState.live);
|
|
13255
|
+
if (!antState.live && candidateBoundary(antState).size === 0) {
|
|
13256
|
+
// we found a group that's isolated from the rest
|
|
13257
|
+
// of the function. Don't merge it with earlier
|
|
13258
|
+
// refs and defs, because we can take it or leave
|
|
13259
|
+
// it based on its own cost.
|
|
13260
|
+
antState.isIsolated = true;
|
|
13261
|
+
}
|
|
13262
|
+
});
|
|
13263
|
+
const oldState = blockStates[top.order];
|
|
13264
|
+
if (oldState && equalStates(oldState, curState)) {
|
|
13265
|
+
continue;
|
|
13266
|
+
}
|
|
13267
|
+
blockStates[top.order] = curState;
|
|
13268
|
+
if (logging) {
|
|
13269
|
+
console.log(`Updated block ${top.order}`);
|
|
13270
|
+
logAntDecls(curState);
|
|
13271
|
+
}
|
|
13272
|
+
if (top.preds) {
|
|
13273
|
+
top.preds.forEach((pred) => enqueue(pred));
|
|
13274
|
+
}
|
|
13275
|
+
}
|
|
13276
|
+
const candidateDecls = anticipatedDecls();
|
|
13277
|
+
blockStates.forEach((blockState, i) => {
|
|
13278
|
+
blockState &&
|
|
13279
|
+
blockState.forEach((events, decl) => {
|
|
13280
|
+
const cost = candidateCost(events);
|
|
13281
|
+
if (cost >= 0)
|
|
13282
|
+
return;
|
|
13283
|
+
const existing = candidateDecls.get(decl);
|
|
13284
|
+
if (!existing ||
|
|
13285
|
+
existing.isIsolated ||
|
|
13286
|
+
candidateCost(existing) > cost) {
|
|
13287
|
+
const boundary = candidateBoundary(events);
|
|
13288
|
+
if (!Array.from(boundary).every((block) => {
|
|
13289
|
+
if (block !== events.head && block.events) {
|
|
13290
|
+
if (events.node.type === "Literal") {
|
|
13291
|
+
return false;
|
|
13292
|
+
}
|
|
13293
|
+
let i = block.events.length;
|
|
13294
|
+
while (i--) {
|
|
13295
|
+
const event = block.events[i];
|
|
13296
|
+
if (event.type === "def" || event.type === "mod") {
|
|
13297
|
+
events.ant.add({
|
|
13298
|
+
type: "mod",
|
|
13299
|
+
node: event.node,
|
|
13300
|
+
decl,
|
|
13301
|
+
id: events.node,
|
|
13302
|
+
mayThrow: false,
|
|
13303
|
+
});
|
|
13304
|
+
events.members.set(block, false);
|
|
13305
|
+
return true;
|
|
13306
|
+
}
|
|
13307
|
+
}
|
|
13308
|
+
}
|
|
13309
|
+
const node = block.node;
|
|
13310
|
+
if (!node)
|
|
13311
|
+
return false;
|
|
13312
|
+
events.ant.add({
|
|
13313
|
+
type: "mod",
|
|
13314
|
+
node: node.type === "FunctionDeclaration" ? node.body : node,
|
|
13315
|
+
before: true,
|
|
13316
|
+
decl,
|
|
13317
|
+
id: events.node,
|
|
13318
|
+
mayThrow: false,
|
|
13319
|
+
});
|
|
13320
|
+
events.members.set(block, false);
|
|
13321
|
+
return true;
|
|
13322
|
+
})) {
|
|
13323
|
+
return;
|
|
13324
|
+
}
|
|
13325
|
+
events.live = false;
|
|
13326
|
+
if (existing && existing.isIsolated) {
|
|
13327
|
+
delete existing.isIsolated;
|
|
13328
|
+
mergeAnticipatedState(events, existing);
|
|
13329
|
+
}
|
|
13330
|
+
else if (candidateCost(events) != cost) {
|
|
13331
|
+
throw new Error(`cost of block ${i} changed`);
|
|
13332
|
+
}
|
|
13333
|
+
candidateDecls.set(decl, events);
|
|
13334
|
+
}
|
|
13335
|
+
});
|
|
13336
|
+
});
|
|
13337
|
+
if (candidateDecls.size) {
|
|
13338
|
+
return candidateDecls;
|
|
13339
|
+
}
|
|
13340
|
+
return null;
|
|
13341
|
+
}
|
|
13342
|
+
/*
|
|
13343
|
+
* Determine the cost of fixing a def under a statement.
|
|
13344
|
+
*
|
|
13345
|
+
* eg:
|
|
13346
|
+
*
|
|
13347
|
+
* if (foo()) {
|
|
13348
|
+
* bar(X.y);
|
|
13349
|
+
* } else {
|
|
13350
|
+
* baz(X.y);
|
|
13351
|
+
* }
|
|
13352
|
+
*
|
|
13353
|
+
* Here, we could pull out X.y as a local, but if foo might modify
|
|
13354
|
+
* X.y, we have nowhere to insert the temporary. But we can rewrite
|
|
13355
|
+
* it as:
|
|
13356
|
+
*
|
|
13357
|
+
* var tmp = foo();
|
|
13358
|
+
* if (tmp) {
|
|
13359
|
+
* bar(X.y);
|
|
13360
|
+
* } else {
|
|
13361
|
+
* baz(X.y);
|
|
13362
|
+
* }
|
|
13363
|
+
*
|
|
13364
|
+
* and now we can insert a temporary before the if, but it costs
|
|
13365
|
+
* 4 bytes to do so.
|
|
13366
|
+
*
|
|
13367
|
+
* We can do the same for switch statements unless (ugh!)
|
|
13368
|
+
* the cases might modify the decl too.
|
|
13369
|
+
*
|
|
13370
|
+
* eg
|
|
13371
|
+
*
|
|
13372
|
+
* switch (foo()) {
|
|
13373
|
+
* case bar(): ...
|
|
13374
|
+
* }
|
|
13375
|
+
*
|
|
13376
|
+
*/
|
|
13377
|
+
function _isFixableStmt(node) {
|
|
13378
|
+
switch (node.type) {
|
|
13379
|
+
case "IfStatement":
|
|
13380
|
+
return 4;
|
|
13381
|
+
case "SwitchStatement":
|
|
13382
|
+
if (node.cases.every((c) => !c.test ||
|
|
13383
|
+
c.test.type === "Literal" ||
|
|
13384
|
+
c.test.type === "Identifier" ||
|
|
13385
|
+
c.test.type === "InstanceOfCase" ||
|
|
13386
|
+
(c.test.type === "UnaryExpression" && c.test.operator === ":"))) {
|
|
13387
|
+
return 4;
|
|
13388
|
+
}
|
|
13389
|
+
break;
|
|
13390
|
+
}
|
|
13391
|
+
return false;
|
|
13392
|
+
}
|
|
13393
|
+
function applyReplacements(func, nodeMap, declMap) {
|
|
13394
|
+
const ident = (name, node) => {
|
|
13395
|
+
return withLoc({ type: "Identifier", name }, node);
|
|
13396
|
+
};
|
|
13397
|
+
const pendingMap = new Map();
|
|
13398
|
+
const stmtStack = [func];
|
|
13399
|
+
traverseAst(func, (node) => {
|
|
13400
|
+
if (isStatement(node)) {
|
|
13401
|
+
stmtStack.push(node);
|
|
13402
|
+
}
|
|
13403
|
+
}, (node) => {
|
|
13404
|
+
const stmt = stmtStack[stmtStack.length - 1];
|
|
13405
|
+
if (stmt === node)
|
|
13406
|
+
stmtStack.pop();
|
|
13407
|
+
const events = nodeMap.get(node);
|
|
13408
|
+
if (events) {
|
|
13409
|
+
const ret = events.reduce((ret, event) => {
|
|
13410
|
+
if (event.type === "ref") {
|
|
13411
|
+
if (ret) {
|
|
13412
|
+
throw new Error(`ref found when there was already a replacement for this node`);
|
|
13413
|
+
}
|
|
13414
|
+
if (node.type !== "Identifier" &&
|
|
13415
|
+
node.type !== "MemberExpression" &&
|
|
13416
|
+
node.type !== "Literal") {
|
|
13417
|
+
throw new Error(`Ref found, but wrong type of node: ${node.type}`);
|
|
13418
|
+
}
|
|
13419
|
+
const name = declMap.get(event.decl);
|
|
13420
|
+
if (!name) {
|
|
13421
|
+
throw new Error(`No replacement found for "${(0,external_api_cjs_namespaceObject.formatAst)(node)}"`);
|
|
13422
|
+
}
|
|
13423
|
+
return ident(name, node);
|
|
13424
|
+
}
|
|
13425
|
+
if (event.type === "def") {
|
|
13426
|
+
if (ret) {
|
|
13427
|
+
throw new Error(`def found when there was already a replacement for this node`);
|
|
13428
|
+
}
|
|
13429
|
+
if (node.type !== "AssignmentExpression" &&
|
|
13430
|
+
node.type !== "UpdateExpression") {
|
|
13431
|
+
throw new Error(`Def found, but wrong type of node: ${node.type}`);
|
|
13432
|
+
}
|
|
13433
|
+
const target = node.type === "AssignmentExpression"
|
|
13434
|
+
? node.left
|
|
13435
|
+
: node.argument;
|
|
13436
|
+
const name = declMap.get(event.decl);
|
|
13437
|
+
if (!name) {
|
|
13438
|
+
throw new Error(`No replacement found for "${(0,external_api_cjs_namespaceObject.formatAst)(target)}"`);
|
|
13439
|
+
}
|
|
13440
|
+
const id = ident(name, target);
|
|
13441
|
+
const assign = withLoc({
|
|
13442
|
+
type: "AssignmentExpression",
|
|
13443
|
+
left: target,
|
|
13444
|
+
right: { ...id },
|
|
13445
|
+
operator: "=",
|
|
13446
|
+
}, node);
|
|
13447
|
+
if (node.type === "AssignmentExpression") {
|
|
13448
|
+
node.left = id;
|
|
13449
|
+
}
|
|
13450
|
+
else {
|
|
13451
|
+
node.argument = id;
|
|
13452
|
+
}
|
|
13453
|
+
return withLoc({ type: "SequenceExpression", expressions: [node, assign] }, node);
|
|
13454
|
+
}
|
|
13455
|
+
if (event.type === "mod") {
|
|
13456
|
+
if (!event.decl) {
|
|
13457
|
+
throw new Error(`Unexpected null decl on mod event`);
|
|
13458
|
+
}
|
|
13459
|
+
let pending = pendingMap.get(stmt);
|
|
13460
|
+
if (!pending) {
|
|
13461
|
+
pendingMap.set(stmt, (pending = new Set()));
|
|
13462
|
+
}
|
|
13463
|
+
pending.add(event);
|
|
13464
|
+
}
|
|
13465
|
+
else {
|
|
13466
|
+
throw new Error(`Unexpected ${event.type} found`);
|
|
13467
|
+
}
|
|
13468
|
+
return ret;
|
|
13469
|
+
}, null);
|
|
13470
|
+
if (ret) {
|
|
13471
|
+
return ret;
|
|
13472
|
+
}
|
|
13473
|
+
}
|
|
13474
|
+
const pending = pendingMap.get(node);
|
|
13475
|
+
if (node.type === "SequenceExpression") {
|
|
13476
|
+
if (pending) {
|
|
13477
|
+
throw new Error(`Unexpected pending list at SequenceExpression`);
|
|
13478
|
+
}
|
|
13479
|
+
for (let i = node.expressions.length; i--;) {
|
|
13480
|
+
const ni = node.expressions[i];
|
|
13481
|
+
if (ni.type === "SequenceExpression") {
|
|
13482
|
+
node.expressions.splice(i, 1, ...ni.expressions);
|
|
13483
|
+
}
|
|
13484
|
+
}
|
|
13485
|
+
}
|
|
13486
|
+
const applyPending = (results, locNode) => {
|
|
13487
|
+
const target = results.length === 1 && results[0].type === "BlockStatement"
|
|
13488
|
+
? results[0]
|
|
13489
|
+
: null;
|
|
13490
|
+
pendingMap.delete(node);
|
|
13491
|
+
pending.forEach((event) => {
|
|
13492
|
+
const decl = event.decl;
|
|
13493
|
+
const name = declMap.get(decl);
|
|
13494
|
+
if (!name) {
|
|
13495
|
+
throw new Error(`No replacement found for "${declFullName(decl)}"`);
|
|
13496
|
+
}
|
|
13497
|
+
if (!event.id) {
|
|
13498
|
+
throw new Error(`Missing id for mod event for "${declFullName(decl)}"`);
|
|
13499
|
+
}
|
|
13500
|
+
const rhs = withLocDeep(event.id, locNode, locNode);
|
|
13501
|
+
rhs.end = rhs.start;
|
|
13502
|
+
if (rhs.loc) {
|
|
13503
|
+
rhs.loc.end = rhs.loc.start;
|
|
13504
|
+
}
|
|
13505
|
+
const insertion = withLoc({
|
|
13506
|
+
type: "ExpressionStatement",
|
|
13507
|
+
expression: withLoc({
|
|
13508
|
+
type: "AssignmentExpression",
|
|
13509
|
+
left: ident(name, rhs),
|
|
13510
|
+
right: rhs,
|
|
13511
|
+
operator: "=",
|
|
13512
|
+
}, rhs),
|
|
13513
|
+
}, rhs);
|
|
13514
|
+
if (event.type === "mod" && event.before) {
|
|
13515
|
+
if (target) {
|
|
13516
|
+
target.body.unshift(insertion);
|
|
13517
|
+
}
|
|
13518
|
+
else {
|
|
13519
|
+
results.unshift(insertion);
|
|
13520
|
+
}
|
|
13521
|
+
}
|
|
13522
|
+
else {
|
|
13523
|
+
results.push(insertion);
|
|
13524
|
+
}
|
|
13525
|
+
});
|
|
13526
|
+
return results.length === 1 ? null : results;
|
|
13527
|
+
};
|
|
13528
|
+
if (node.type === "ExpressionStatement" &&
|
|
13529
|
+
node.expression.type === "SequenceExpression") {
|
|
13530
|
+
const results = [];
|
|
13531
|
+
node.expression.expressions.forEach((expression) => {
|
|
13532
|
+
results.push({ ...node, expression });
|
|
13533
|
+
});
|
|
13534
|
+
if (!pending) {
|
|
13535
|
+
return results;
|
|
13536
|
+
}
|
|
13537
|
+
return applyPending(results, node);
|
|
13538
|
+
}
|
|
13539
|
+
if (pending) {
|
|
13540
|
+
return applyPending([node], node);
|
|
13541
|
+
}
|
|
13542
|
+
return null;
|
|
13543
|
+
});
|
|
13544
|
+
}
|
|
13545
|
+
|
|
13546
|
+
;// CONCATENATED MODULE: ./src/unused-exprs.ts
|
|
13547
|
+
|
|
13548
|
+
|
|
13549
|
+
|
|
13550
|
+
function cleanupUnusedVars(state, node) {
|
|
13551
|
+
const [parent] = state.stack.slice(-1);
|
|
13552
|
+
if (parent.node !== node) {
|
|
13553
|
+
return;
|
|
13554
|
+
}
|
|
13555
|
+
if (parent.type != "BlockStatement") {
|
|
13556
|
+
throw new Error(`Unexpected parent type '${parent.type}' for local declaration`);
|
|
13557
|
+
}
|
|
13558
|
+
if (parent.decls) {
|
|
13559
|
+
let toRemove = null;
|
|
13560
|
+
Object.values(parent.decls).forEach((decls) => {
|
|
13561
|
+
if (decls.length === 1 &&
|
|
13562
|
+
decls[0].type === "VariableDeclarator" &&
|
|
13563
|
+
!decls[0].used) {
|
|
13564
|
+
if (!toRemove)
|
|
13565
|
+
toRemove = {};
|
|
13566
|
+
toRemove[decls[0].name] = decls[0];
|
|
13567
|
+
}
|
|
13568
|
+
});
|
|
13569
|
+
if (toRemove) {
|
|
13570
|
+
const varDeclarations = new Map();
|
|
13571
|
+
traverseAst(node, null, (node) => {
|
|
13572
|
+
switch (node.type) {
|
|
13573
|
+
case "VariableDeclaration": {
|
|
13574
|
+
node.declarations.forEach((decl, i) => {
|
|
13575
|
+
const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id);
|
|
13576
|
+
if (hasProperty(toRemove, name)) {
|
|
13577
|
+
const indices = varDeclarations.get(node);
|
|
13578
|
+
if (indices) {
|
|
13579
|
+
indices.push(i);
|
|
13580
|
+
}
|
|
13581
|
+
else {
|
|
13582
|
+
varDeclarations.set(node, [i]);
|
|
13583
|
+
}
|
|
13584
|
+
}
|
|
13585
|
+
});
|
|
13586
|
+
break;
|
|
13587
|
+
}
|
|
13588
|
+
case "ExpressionStatement":
|
|
13589
|
+
if (node.expression.type === "AssignmentExpression") {
|
|
13590
|
+
if (node.expression.left.type === "Identifier" &&
|
|
13591
|
+
hasProperty(toRemove, node.expression.left.name)) {
|
|
13592
|
+
return unused(node.expression.right);
|
|
13593
|
+
}
|
|
13594
|
+
}
|
|
13595
|
+
else if (node.expression.type === "UpdateExpression" &&
|
|
13596
|
+
node.expression.argument.type === "Identifier" &&
|
|
13597
|
+
hasProperty(toRemove, node.expression.argument.name)) {
|
|
13598
|
+
return false;
|
|
13599
|
+
}
|
|
13600
|
+
break;
|
|
13601
|
+
case "SequenceExpression": {
|
|
13602
|
+
for (let i = node.expressions.length; i--;) {
|
|
13603
|
+
const expr = node.expressions[i];
|
|
13604
|
+
if (expr.type === "AssignmentExpression") {
|
|
13605
|
+
if (expr.left.type === "Identifier" &&
|
|
13606
|
+
hasProperty(toRemove, expr.left.name)) {
|
|
13607
|
+
const rep = unused(expr.right);
|
|
13608
|
+
if (!rep.length) {
|
|
13609
|
+
node.expressions.splice(i, 1);
|
|
13610
|
+
}
|
|
13611
|
+
else {
|
|
13612
|
+
// Sequence expressions can only be assignments
|
|
13613
|
+
// or update expressions. Even calls aren't allowed
|
|
13614
|
+
toRemove[expr.left.name] = null;
|
|
13615
|
+
expr.operator = "=";
|
|
13616
|
+
}
|
|
13617
|
+
}
|
|
13618
|
+
}
|
|
13619
|
+
else if (expr.type === "UpdateExpression" &&
|
|
13620
|
+
expr.argument.type === "Identifier" &&
|
|
13621
|
+
hasProperty(toRemove, expr.argument.name)) {
|
|
13622
|
+
node.expressions.splice(i, 1);
|
|
13623
|
+
}
|
|
13624
|
+
}
|
|
13625
|
+
break;
|
|
13626
|
+
}
|
|
13627
|
+
}
|
|
13628
|
+
return null;
|
|
13629
|
+
});
|
|
13630
|
+
varDeclarations.forEach((indices, decl) => {
|
|
13631
|
+
let index = -1;
|
|
13632
|
+
for (let ii = indices.length, j = decl.declarations.length; ii--;) {
|
|
13633
|
+
const i = indices[ii];
|
|
13634
|
+
const vdecl = decl.declarations[i];
|
|
13635
|
+
const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(vdecl.id);
|
|
13636
|
+
if (hasProperty(toRemove, name)) {
|
|
13637
|
+
const rep = vdecl.init ? unused(vdecl.init) : [];
|
|
13638
|
+
if (rep.length) {
|
|
13639
|
+
if (parent.node.type === "ForStatement") {
|
|
13640
|
+
// declarations whose inits have side effects
|
|
13641
|
+
// can't be deleted from for statements.
|
|
13642
|
+
continue;
|
|
13643
|
+
}
|
|
13644
|
+
if (index < 0) {
|
|
13645
|
+
index = parent.node.body.findIndex((s) => s === decl);
|
|
13646
|
+
if (index < 0) {
|
|
13647
|
+
throw new Error(`Failed to find variable declaration for ${(0,external_api_cjs_namespaceObject.variableDeclarationName)(vdecl.id)}`);
|
|
13648
|
+
}
|
|
13649
|
+
}
|
|
13650
|
+
if (j > i + 1) {
|
|
13651
|
+
const tail = {
|
|
13652
|
+
...decl,
|
|
13653
|
+
declarations: decl.declarations.slice(i + 1, j),
|
|
13654
|
+
};
|
|
13655
|
+
if (decl.loc && vdecl.loc) {
|
|
13656
|
+
tail.loc = { ...decl.loc, start: vdecl.loc.end };
|
|
13657
|
+
tail.start = vdecl.end;
|
|
13658
|
+
}
|
|
13659
|
+
rep.push(tail);
|
|
13660
|
+
}
|
|
13661
|
+
if (decl.loc && vdecl.loc) {
|
|
13662
|
+
decl.loc = { ...decl.loc, end: vdecl.loc.start };
|
|
13663
|
+
decl.end = vdecl.start;
|
|
13664
|
+
}
|
|
13665
|
+
decl.declarations.splice(i);
|
|
13666
|
+
parent.node.body.splice(index + 1, 0, ...rep);
|
|
13667
|
+
j = i;
|
|
13668
|
+
continue;
|
|
13669
|
+
}
|
|
13670
|
+
if (toRemove[name]) {
|
|
13671
|
+
j--;
|
|
13672
|
+
decl.declarations.splice(i, 1);
|
|
13673
|
+
if (i === j && decl.loc && vdecl.loc) {
|
|
13674
|
+
decl.loc = { ...decl.loc, end: vdecl.loc.start };
|
|
13675
|
+
decl.end = vdecl.start;
|
|
13676
|
+
}
|
|
13677
|
+
}
|
|
13678
|
+
else {
|
|
13679
|
+
delete vdecl.init;
|
|
13680
|
+
}
|
|
13681
|
+
}
|
|
13682
|
+
}
|
|
13683
|
+
});
|
|
13684
|
+
}
|
|
13685
|
+
}
|
|
13686
|
+
}
|
|
13687
|
+
|
|
13688
|
+
;// CONCATENATED MODULE: ./src/visitor.ts
|
|
13689
|
+
|
|
13690
|
+
function visitReferences(state, ast, name, defn, callback) {
|
|
13691
|
+
const checkResults = ([name, results], node) => {
|
|
13692
|
+
if (name && results) {
|
|
13693
|
+
if (!defn || (0,external_api_cjs_namespaceObject.sameLookupResult)(results, defn)) {
|
|
13694
|
+
if (callback(node, results, false) === false) {
|
|
13695
|
+
return [];
|
|
13696
|
+
}
|
|
13697
|
+
}
|
|
13698
|
+
}
|
|
13699
|
+
else if (defn === false) {
|
|
13700
|
+
if (callback(node, [], results === null) === false) {
|
|
13701
|
+
return [];
|
|
13702
|
+
}
|
|
13703
|
+
}
|
|
13704
|
+
return null;
|
|
13705
|
+
};
|
|
13706
|
+
state.pre = (node) => {
|
|
11548
13707
|
switch (node.type) {
|
|
11549
13708
|
case "AttributeList":
|
|
11550
13709
|
return [];
|
|
@@ -11590,14 +13749,16 @@ function visitReferences(state, ast, name, defn, callback) {
|
|
|
11590
13749
|
return checkResults(state.lookup(node), node);
|
|
11591
13750
|
}
|
|
11592
13751
|
break;
|
|
11593
|
-
case "MemberExpression":
|
|
11594
|
-
|
|
11595
|
-
|
|
13752
|
+
case "MemberExpression": {
|
|
13753
|
+
const property = (0,external_api_cjs_namespaceObject.isLookupCandidate)(node);
|
|
13754
|
+
if (property) {
|
|
13755
|
+
if (!name || property.name === name) {
|
|
11596
13756
|
return checkResults(state.lookup(node), node) || ["object"];
|
|
11597
13757
|
}
|
|
11598
13758
|
return ["object"];
|
|
11599
13759
|
}
|
|
11600
13760
|
break;
|
|
13761
|
+
}
|
|
11601
13762
|
case "MethodDefinition": {
|
|
11602
13763
|
if (!state.inType) {
|
|
11603
13764
|
throw new Error("Method definition outside of type!");
|
|
@@ -11606,7 +13767,6 @@ function visitReferences(state, ast, name, defn, callback) {
|
|
|
11606
13767
|
node.params.forEach((param) => {
|
|
11607
13768
|
if (param.type == "BinaryExpression") {
|
|
11608
13769
|
state.traverse(param.right);
|
|
11609
|
-
state.inType = true;
|
|
11610
13770
|
}
|
|
11611
13771
|
});
|
|
11612
13772
|
}
|
|
@@ -11628,6 +13788,10 @@ function visitReferences(state, ast, name, defn, callback) {
|
|
|
11628
13788
|
|
|
11629
13789
|
|
|
11630
13790
|
|
|
13791
|
+
|
|
13792
|
+
|
|
13793
|
+
|
|
13794
|
+
|
|
11631
13795
|
function collectClassInfo(state) {
|
|
11632
13796
|
const toybox = state.stack[0].decls["Toybox"][0];
|
|
11633
13797
|
const lang = toybox.decls["Lang"][0];
|
|
@@ -11687,8 +13851,7 @@ function collectClassInfo(state) {
|
|
|
11687
13851
|
c.decls &&
|
|
11688
13852
|
Object.values(c.decls).forEach((funcs) => {
|
|
11689
13853
|
funcs.forEach((f) => {
|
|
11690
|
-
if (
|
|
11691
|
-
f.type === "FunctionDeclaration" &&
|
|
13854
|
+
if (f.type === "FunctionDeclaration" &&
|
|
11692
13855
|
(0,external_api_cjs_namespaceObject.hasProperty)(cls.decls, f.name)) {
|
|
11693
13856
|
f.node.hasOverride = true;
|
|
11694
13857
|
}
|
|
@@ -11701,6 +13864,15 @@ function collectClassInfo(state) {
|
|
|
11701
13864
|
state.allClasses.forEach((elm) => {
|
|
11702
13865
|
if (elm.superClass)
|
|
11703
13866
|
markOverrides(elm, elm.superClass);
|
|
13867
|
+
if (elm.hasInvoke && elm.decls) {
|
|
13868
|
+
Object.values(elm.decls).forEach((funcs) => {
|
|
13869
|
+
funcs.forEach((f) => {
|
|
13870
|
+
if (f.type === "FunctionDeclaration" && !f.isStatic) {
|
|
13871
|
+
(0,external_api_cjs_namespaceObject.markInvokeClassMethod)(f);
|
|
13872
|
+
}
|
|
13873
|
+
});
|
|
13874
|
+
});
|
|
13875
|
+
}
|
|
11704
13876
|
});
|
|
11705
13877
|
}
|
|
11706
13878
|
function getFileSources(fnMap) {
|
|
@@ -11739,7 +13911,7 @@ async function analyze(fnMap, barrelList, config) {
|
|
|
11739
13911
|
const preState = {
|
|
11740
13912
|
fnMap,
|
|
11741
13913
|
config,
|
|
11742
|
-
allFunctions:
|
|
13914
|
+
allFunctions: {},
|
|
11743
13915
|
allClasses: [],
|
|
11744
13916
|
shouldExclude(node) {
|
|
11745
13917
|
if ("attrs" in node &&
|
|
@@ -11769,11 +13941,6 @@ async function analyze(fnMap, barrelList, config) {
|
|
|
11769
13941
|
pre(node, state) {
|
|
11770
13942
|
switch (node.type) {
|
|
11771
13943
|
case "FunctionDeclaration":
|
|
11772
|
-
if (markApi) {
|
|
11773
|
-
node.body = null;
|
|
11774
|
-
break;
|
|
11775
|
-
}
|
|
11776
|
-
// falls through
|
|
11777
13944
|
case "ModuleDeclaration":
|
|
11778
13945
|
case "ClassDeclaration": {
|
|
11779
13946
|
const [scope] = state.stack.slice(-1);
|
|
@@ -11784,7 +13951,18 @@ async function analyze(fnMap, barrelList, config) {
|
|
|
11784
13951
|
(scope.node.attrs &&
|
|
11785
13952
|
scope.node.attrs.access &&
|
|
11786
13953
|
scope.node.attrs.access.includes("static"));
|
|
11787
|
-
|
|
13954
|
+
if (markApi) {
|
|
13955
|
+
node.body = null;
|
|
13956
|
+
scope.info = (0,external_api_cjs_namespaceObject.getApiFunctionInfo)(scope);
|
|
13957
|
+
delete scope.stack;
|
|
13958
|
+
}
|
|
13959
|
+
const allFuncs = state.allFunctions;
|
|
13960
|
+
if (!(0,external_api_cjs_namespaceObject.hasProperty)(allFuncs, scope.name)) {
|
|
13961
|
+
allFuncs[scope.name] = [scope];
|
|
13962
|
+
}
|
|
13963
|
+
else {
|
|
13964
|
+
allFuncs[scope.name].push(scope);
|
|
13965
|
+
}
|
|
11788
13966
|
}
|
|
11789
13967
|
else if (scope.type === "ClassDeclaration") {
|
|
11790
13968
|
state.allClasses.push(scope);
|
|
@@ -11809,7 +13987,7 @@ async function analyze(fnMap, barrelList, config) {
|
|
|
11809
13987
|
value.hasTests = hasTests;
|
|
11810
13988
|
});
|
|
11811
13989
|
delete state.shouldExclude;
|
|
11812
|
-
delete state.
|
|
13990
|
+
delete state.pre;
|
|
11813
13991
|
collectClassInfo(state);
|
|
11814
13992
|
const diagnosticType = config?.checkInvalidSymbols !== "OFF"
|
|
11815
13993
|
? config?.checkInvalidSymbols || "WARNING"
|
|
@@ -11832,6 +14010,8 @@ async function analyze(fnMap, barrelList, config) {
|
|
|
11832
14010
|
});
|
|
11833
14011
|
});
|
|
11834
14012
|
}
|
|
14013
|
+
state.exposed = state.nextExposed;
|
|
14014
|
+
state.nextExposed = {};
|
|
11835
14015
|
return state;
|
|
11836
14016
|
}
|
|
11837
14017
|
function compareLiteralLike(a, b) {
|
|
@@ -11877,15 +14057,12 @@ function getLiteralNode(node) {
|
|
|
11877
14057
|
if (node.argument.type != "Literal")
|
|
11878
14058
|
return null;
|
|
11879
14059
|
switch (node.operator) {
|
|
11880
|
-
case "-":
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
value: -node.argument.value,
|
|
11885
|
-
raw: "-" + node.argument.value,
|
|
11886
|
-
enumType: node.enumType,
|
|
11887
|
-
};
|
|
14060
|
+
case "-": {
|
|
14061
|
+
const [arg, type] = getNodeValue(node.argument);
|
|
14062
|
+
if (type === "Number" || type === "Long") {
|
|
14063
|
+
return replacementLiteral(arg, -arg.value, type);
|
|
11888
14064
|
}
|
|
14065
|
+
}
|
|
11889
14066
|
}
|
|
11890
14067
|
}
|
|
11891
14068
|
return null;
|
|
@@ -11904,31 +14081,114 @@ function getNodeValue(node) {
|
|
|
11904
14081
|
if (node.type != "Literal") {
|
|
11905
14082
|
return [null, null];
|
|
11906
14083
|
}
|
|
11907
|
-
|
|
14084
|
+
if (node.value === null) {
|
|
14085
|
+
return [node, "Null"];
|
|
14086
|
+
}
|
|
14087
|
+
const type = typeof node.value;
|
|
11908
14088
|
if (type === "number") {
|
|
11909
|
-
const match =
|
|
14089
|
+
const match = prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.exec(node.raw);
|
|
11910
14090
|
if (match) {
|
|
11911
|
-
|
|
14091
|
+
return match[2] === "l" || match[2] === "L"
|
|
14092
|
+
? [node, "Long"]
|
|
14093
|
+
: [node, "Number"];
|
|
11912
14094
|
}
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
14095
|
+
return [node, node.raw.endsWith("d") ? "Double" : "Float"];
|
|
14096
|
+
}
|
|
14097
|
+
if (type === "bigint") {
|
|
14098
|
+
return [node, "Long"];
|
|
14099
|
+
}
|
|
14100
|
+
if (type === "string") {
|
|
14101
|
+
return [node, "String"];
|
|
14102
|
+
}
|
|
14103
|
+
if (type === "boolean") {
|
|
14104
|
+
return [node, "Boolean"];
|
|
14105
|
+
}
|
|
14106
|
+
throw new Error(`Literal has unknown type '${type}'`);
|
|
14107
|
+
}
|
|
14108
|
+
function fullTypeName(state, tsp) {
|
|
14109
|
+
if (typeof tsp.name === "string") {
|
|
14110
|
+
return tsp.name;
|
|
14111
|
+
}
|
|
14112
|
+
const [, results] = state.lookupType(tsp.name);
|
|
14113
|
+
if (results && results.length === 1 && results[0].results.length === 1) {
|
|
14114
|
+
const result = results[0].results[0];
|
|
14115
|
+
if ((0,external_api_cjs_namespaceObject.isStateNode)(result)) {
|
|
14116
|
+
return result.fullName;
|
|
11918
14117
|
}
|
|
11919
14118
|
}
|
|
11920
|
-
|
|
11921
|
-
|
|
14119
|
+
return null;
|
|
14120
|
+
}
|
|
14121
|
+
function isBooleanExpression(state, node) {
|
|
14122
|
+
switch (node.type) {
|
|
14123
|
+
case "Literal":
|
|
14124
|
+
return typeof node.value === "boolean";
|
|
14125
|
+
case "BinaryExpression":
|
|
14126
|
+
switch (node.operator) {
|
|
14127
|
+
case "==":
|
|
14128
|
+
case "!=":
|
|
14129
|
+
case "<=":
|
|
14130
|
+
case ">=":
|
|
14131
|
+
case "<":
|
|
14132
|
+
case ">":
|
|
14133
|
+
return true;
|
|
14134
|
+
case "as":
|
|
14135
|
+
return node.right.ts.length === 1 &&
|
|
14136
|
+
node.right.ts[0].type === "TypeSpecPart" &&
|
|
14137
|
+
node.right.ts[0].name &&
|
|
14138
|
+
fullTypeName(state, node.right.ts[0]) === "$.Toybox.Lang.Boolean"
|
|
14139
|
+
? true
|
|
14140
|
+
: false;
|
|
14141
|
+
}
|
|
14142
|
+
return false;
|
|
14143
|
+
case "LogicalExpression":
|
|
14144
|
+
return (isBooleanExpression(state, node.left) &&
|
|
14145
|
+
isBooleanExpression(state, node.right));
|
|
14146
|
+
case "UnaryExpression":
|
|
14147
|
+
return node.operator === "!" && isBooleanExpression(state, node.argument);
|
|
11922
14148
|
}
|
|
11923
|
-
|
|
14149
|
+
return false;
|
|
14150
|
+
}
|
|
14151
|
+
function replacementLiteral(arg, value, type) {
|
|
14152
|
+
if (typeof value === "boolean") {
|
|
11924
14153
|
type = "Boolean";
|
|
11925
14154
|
}
|
|
11926
|
-
else {
|
|
11927
|
-
|
|
14155
|
+
else if (type === "Number") {
|
|
14156
|
+
value = Number(BigInt.asIntN(32, BigInt(value)));
|
|
11928
14157
|
}
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
14158
|
+
else if (type === "Long") {
|
|
14159
|
+
value = BigInt.asIntN(64, BigInt(value));
|
|
14160
|
+
}
|
|
14161
|
+
return {
|
|
14162
|
+
...arg,
|
|
14163
|
+
value,
|
|
14164
|
+
raw: value.toString() + (type === "Long" ? "l" : ""),
|
|
14165
|
+
};
|
|
14166
|
+
}
|
|
14167
|
+
const operators = {
|
|
14168
|
+
"+": (left, right) => left + right,
|
|
14169
|
+
"-": (left, right) => left - right,
|
|
14170
|
+
"*": (left, right) => left * right,
|
|
14171
|
+
"/": (left, right) => left / right,
|
|
14172
|
+
"%": (left, right) => left % right,
|
|
14173
|
+
"&": (left, right) => left & right,
|
|
14174
|
+
"|": (left, right) => left | right,
|
|
14175
|
+
"^": (left, right) => left ^ right,
|
|
14176
|
+
"<<": (left, right) => left << (right & 127n),
|
|
14177
|
+
">>": (left, right) => left >> (right & 127n),
|
|
14178
|
+
"==": (left, right) =>
|
|
14179
|
+
// two string literals will compare unequal, becuase string
|
|
14180
|
+
// equality is object equality.
|
|
14181
|
+
typeof left === "string" ? false : left === right,
|
|
14182
|
+
"!=": (left, right) => typeof left === "string" ? true : left !== right,
|
|
14183
|
+
"<=": (left, right) => left <= right,
|
|
14184
|
+
">=": (left, right) => left >= right,
|
|
14185
|
+
"<": (left, right) => left < right,
|
|
14186
|
+
">": (left, right) => left > right,
|
|
14187
|
+
as: null,
|
|
14188
|
+
instanceof: null,
|
|
14189
|
+
has: null,
|
|
14190
|
+
};
|
|
14191
|
+
function optimizeNode(state, node) {
|
|
11932
14192
|
switch (node.type) {
|
|
11933
14193
|
case "UnaryExpression": {
|
|
11934
14194
|
const [arg, type] = getNodeValue(node.argument);
|
|
@@ -11942,29 +14202,17 @@ function optimizeNode(node) {
|
|
|
11942
14202
|
break;
|
|
11943
14203
|
case "-":
|
|
11944
14204
|
if (type === "Number" || type === "Long") {
|
|
11945
|
-
return
|
|
11946
|
-
...arg,
|
|
11947
|
-
value: -arg.value,
|
|
11948
|
-
raw: (-arg.value).toString() + (type === "Long" ? "l" : ""),
|
|
11949
|
-
};
|
|
14205
|
+
return replacementLiteral(arg, -arg.value, type);
|
|
11950
14206
|
}
|
|
11951
14207
|
break;
|
|
11952
14208
|
case "!":
|
|
11953
14209
|
case "~":
|
|
11954
14210
|
{
|
|
11955
|
-
let value;
|
|
11956
14211
|
if (type === "Number" || type === "Long") {
|
|
11957
|
-
|
|
14212
|
+
return replacementLiteral(arg, ~BigInt(arg.value), type);
|
|
11958
14213
|
}
|
|
11959
|
-
|
|
11960
|
-
|
|
11961
|
-
}
|
|
11962
|
-
if (value !== undefined) {
|
|
11963
|
-
return {
|
|
11964
|
-
...arg,
|
|
11965
|
-
value,
|
|
11966
|
-
raw: value.toString() + (type === "Long" ? "l" : ""),
|
|
11967
|
-
};
|
|
14214
|
+
if (type === "Boolean" && node.operator == "!") {
|
|
14215
|
+
return replacementLiteral(arg, !arg.value, type);
|
|
11968
14216
|
}
|
|
11969
14217
|
}
|
|
11970
14218
|
break;
|
|
@@ -11972,56 +14220,81 @@ function optimizeNode(node) {
|
|
|
11972
14220
|
break;
|
|
11973
14221
|
}
|
|
11974
14222
|
case "BinaryExpression": {
|
|
11975
|
-
const operators = {
|
|
11976
|
-
"+": (left, right) => left + right,
|
|
11977
|
-
"-": (left, right) => left - right,
|
|
11978
|
-
"*": (left, right) => left * right,
|
|
11979
|
-
"/": (left, right) => Math.trunc(left / right),
|
|
11980
|
-
"%": (left, right) => left % right,
|
|
11981
|
-
"&": (left, right, type) => type === "Number" ? left & right : null,
|
|
11982
|
-
"|": (left, right, type) => type === "Number" ? left | right : null,
|
|
11983
|
-
"<<": (left, right, type) => type === "Number" ? left << right : null,
|
|
11984
|
-
">>": (left, right, type) => type === "Number" ? left >> right : null,
|
|
11985
|
-
};
|
|
11986
14223
|
const op = operators[node.operator];
|
|
11987
14224
|
if (op) {
|
|
11988
14225
|
const [left, left_type] = getNodeValue(node.left);
|
|
11989
14226
|
const [right, right_type] = getNodeValue(node.right);
|
|
11990
14227
|
if (!left || !right)
|
|
11991
14228
|
break;
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
14229
|
+
let value = null;
|
|
14230
|
+
let type;
|
|
14231
|
+
if ((left_type != "Number" && left_type != "Long") ||
|
|
14232
|
+
left_type != right_type) {
|
|
14233
|
+
if (node.operator !== "==" && node.operator !== "!=") {
|
|
14234
|
+
break;
|
|
14235
|
+
}
|
|
14236
|
+
value = operators[node.operator](left.value, right.value);
|
|
14237
|
+
type = "Boolean";
|
|
14238
|
+
}
|
|
14239
|
+
else {
|
|
14240
|
+
type = left_type;
|
|
14241
|
+
value = op(BigInt(left.value), BigInt(right.value));
|
|
11995
14242
|
}
|
|
11996
|
-
const value = op(left.value, right.value, left_type);
|
|
11997
14243
|
if (value === null)
|
|
11998
14244
|
break;
|
|
11999
|
-
return
|
|
12000
|
-
|
|
12001
|
-
|
|
12002
|
-
|
|
12003
|
-
|
|
14245
|
+
return replacementLiteral(left, value, type);
|
|
14246
|
+
}
|
|
14247
|
+
break;
|
|
14248
|
+
}
|
|
14249
|
+
case "LogicalExpression": {
|
|
14250
|
+
const [left, left_type] = getNodeValue(node.left);
|
|
14251
|
+
if (!left)
|
|
14252
|
+
break;
|
|
14253
|
+
const falsy = left.value === false ||
|
|
14254
|
+
left.value === null ||
|
|
14255
|
+
((left_type === "Number" || left_type === "Long") &&
|
|
14256
|
+
(left.value === 0 || left.value === 0n));
|
|
14257
|
+
if (falsy === (node.operator === "&&")) {
|
|
14258
|
+
return left;
|
|
14259
|
+
}
|
|
14260
|
+
if (left_type !== "Boolean" &&
|
|
14261
|
+
left_type !== "Number" &&
|
|
14262
|
+
left_type !== "Long") {
|
|
14263
|
+
break;
|
|
14264
|
+
}
|
|
14265
|
+
const [right, right_type] = getNodeValue(node.right);
|
|
14266
|
+
if (right && right_type === left_type) {
|
|
14267
|
+
if (left_type === "Boolean" || node.operator === "||") {
|
|
14268
|
+
return right;
|
|
14269
|
+
}
|
|
14270
|
+
if (node.operator !== "&&") {
|
|
14271
|
+
throw new Error(`Unexpected operator "${node.operator}"`);
|
|
14272
|
+
}
|
|
14273
|
+
return { ...node, type: "BinaryExpression", operator: "&" };
|
|
14274
|
+
}
|
|
14275
|
+
if (left_type === "Boolean") {
|
|
14276
|
+
if (isBooleanExpression(state, node.right)) {
|
|
14277
|
+
return node.right;
|
|
14278
|
+
}
|
|
12004
14279
|
}
|
|
12005
14280
|
break;
|
|
12006
14281
|
}
|
|
12007
14282
|
case "FunctionDeclaration":
|
|
12008
|
-
if (node.body && evaluateFunction(node, null) !== false) {
|
|
14283
|
+
if (node.body && evaluateFunction(state, node, null) !== false) {
|
|
12009
14284
|
node.optimizable = true;
|
|
12010
14285
|
}
|
|
12011
14286
|
break;
|
|
12012
14287
|
}
|
|
12013
14288
|
return null;
|
|
12014
14289
|
}
|
|
12015
|
-
function evaluateFunction(func, args) {
|
|
14290
|
+
function evaluateFunction(state, func, args) {
|
|
12016
14291
|
if (!func.body || (args && args.length != func.params.length)) {
|
|
12017
14292
|
return false;
|
|
12018
14293
|
}
|
|
12019
14294
|
const paramValues = args &&
|
|
12020
14295
|
Object.fromEntries(func.params.map((p, i) => [(0,external_api_cjs_namespaceObject.variableDeclarationName)(p), args[i]]));
|
|
12021
14296
|
let ret = null;
|
|
12022
|
-
const body = args
|
|
12023
|
-
? JSON.parse(JSON.stringify(func.body))
|
|
12024
|
-
: func.body;
|
|
14297
|
+
const body = args ? cloneDeep(func.body) : func.body;
|
|
12025
14298
|
try {
|
|
12026
14299
|
traverseAst(body, (node) => {
|
|
12027
14300
|
switch (node.type) {
|
|
@@ -12051,7 +14324,7 @@ function evaluateFunction(func, args) {
|
|
|
12051
14324
|
}
|
|
12052
14325
|
// fall through;
|
|
12053
14326
|
default: {
|
|
12054
|
-
const repl = optimizeNode(node);
|
|
14327
|
+
const repl = optimizeNode(state, node);
|
|
12055
14328
|
if (repl && repl.type === "Literal")
|
|
12056
14329
|
return repl;
|
|
12057
14330
|
throw new Error("Didn't optimize");
|
|
@@ -12072,12 +14345,10 @@ function markFunctionCalled(state, func) {
|
|
|
12072
14345
|
(0,external_util_cjs_namespaceObject.pushUnique)(state.calledFunctions[func.id.name], func);
|
|
12073
14346
|
}
|
|
12074
14347
|
async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
12075
|
-
const state =
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
calledFunctions: {},
|
|
12080
|
-
};
|
|
14348
|
+
const state = (await analyze(fnMap, barrelList, config));
|
|
14349
|
+
state.localsStack = [{}];
|
|
14350
|
+
state.calledFunctions = {};
|
|
14351
|
+
state.usedByName = {};
|
|
12081
14352
|
const replace = (node, old) => {
|
|
12082
14353
|
if (node === false || node === null)
|
|
12083
14354
|
return node;
|
|
@@ -12111,10 +14382,19 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12111
14382
|
if (!objects) {
|
|
12112
14383
|
return false;
|
|
12113
14384
|
}
|
|
12114
|
-
|
|
14385
|
+
let obj = getLiteralFromDecls(objects);
|
|
12115
14386
|
if (!obj) {
|
|
12116
14387
|
return false;
|
|
12117
14388
|
}
|
|
14389
|
+
while (obj.type === "BinaryExpression") {
|
|
14390
|
+
if (obj.left.type === "BinaryExpression" && obj.left.operator === "as") {
|
|
14391
|
+
obj = { ...obj, left: obj.left.left };
|
|
14392
|
+
}
|
|
14393
|
+
else {
|
|
14394
|
+
obj = { ...obj, left: { ...obj.left } };
|
|
14395
|
+
break;
|
|
14396
|
+
}
|
|
14397
|
+
}
|
|
12118
14398
|
inPlaceReplacement(node, obj);
|
|
12119
14399
|
return true;
|
|
12120
14400
|
};
|
|
@@ -12157,6 +14437,58 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12157
14437
|
f.type == "FunctionDeclaration" &&
|
|
12158
14438
|
maybeCalled(f.node))) ||
|
|
12159
14439
|
(sc.superClass && checkInherited(sc, name))));
|
|
14440
|
+
const renamer = (idnode) => {
|
|
14441
|
+
const ident = idnode.type === "Identifier" ? idnode : idnode.left;
|
|
14442
|
+
const locals = topLocals();
|
|
14443
|
+
const { map } = locals;
|
|
14444
|
+
if (map) {
|
|
14445
|
+
const declName = ident.name;
|
|
14446
|
+
const name = renameVariable(state, locals, declName);
|
|
14447
|
+
if (name) {
|
|
14448
|
+
const [, results] = state.lookupValue(ident);
|
|
14449
|
+
if (!results) {
|
|
14450
|
+
throw new Error(`Didn't find local ${declName} which needed renaming`);
|
|
14451
|
+
}
|
|
14452
|
+
if (results.length !== 1) {
|
|
14453
|
+
throw new Error(`Lookup of local ${declName} found more than one result`);
|
|
14454
|
+
}
|
|
14455
|
+
const parent = results[0].parent;
|
|
14456
|
+
if (!parent) {
|
|
14457
|
+
throw new Error(`No parent in lookup of local ${declName}`);
|
|
14458
|
+
}
|
|
14459
|
+
const decls = parent.decls;
|
|
14460
|
+
if (!decls || !(0,external_api_cjs_namespaceObject.hasProperty)(decls, declName)) {
|
|
14461
|
+
throw new Error(`Missing decls in lookup of local ${declName}`);
|
|
14462
|
+
}
|
|
14463
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(decls, name)) {
|
|
14464
|
+
throw new Error(`While renaming ${declName} to ${name}, there was already a variable ${name}`);
|
|
14465
|
+
}
|
|
14466
|
+
if (decls[declName].length === 1) {
|
|
14467
|
+
decls[name] = decls[declName];
|
|
14468
|
+
delete decls[declName];
|
|
14469
|
+
}
|
|
14470
|
+
else {
|
|
14471
|
+
let i = decls[declName].length;
|
|
14472
|
+
while (i--) {
|
|
14473
|
+
const decl = decls[declName][i];
|
|
14474
|
+
if (decl === idnode ||
|
|
14475
|
+
(decl.type === "VariableDeclarator" && decl.node.id === idnode)) {
|
|
14476
|
+
decls[declName].splice(i, 1);
|
|
14477
|
+
decls[name] = [decl];
|
|
14478
|
+
break;
|
|
14479
|
+
}
|
|
14480
|
+
}
|
|
14481
|
+
if (i < 0) {
|
|
14482
|
+
throw new Error(`While renaming ${declName} to ${name}: Didn't find original declaration`);
|
|
14483
|
+
}
|
|
14484
|
+
}
|
|
14485
|
+
ident.name = name;
|
|
14486
|
+
}
|
|
14487
|
+
else {
|
|
14488
|
+
map[declName] = true;
|
|
14489
|
+
}
|
|
14490
|
+
}
|
|
14491
|
+
};
|
|
12160
14492
|
state.pre = (node) => {
|
|
12161
14493
|
switch (node.type) {
|
|
12162
14494
|
case "ConditionalExpression":
|
|
@@ -12177,7 +14509,11 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12177
14509
|
result = !!value.value;
|
|
12178
14510
|
}
|
|
12179
14511
|
if (result !== null) {
|
|
12180
|
-
node.test = {
|
|
14512
|
+
node.test = {
|
|
14513
|
+
type: "Literal",
|
|
14514
|
+
value: result,
|
|
14515
|
+
raw: result.toString(),
|
|
14516
|
+
};
|
|
12181
14517
|
if (node.type === "IfStatement" ||
|
|
12182
14518
|
node.type === "ConditionalExpression") {
|
|
12183
14519
|
return [result ? "consequent" : "alternate"];
|
|
@@ -12196,7 +14532,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12196
14532
|
return null;
|
|
12197
14533
|
}
|
|
12198
14534
|
case "EnumDeclaration":
|
|
12199
|
-
return
|
|
14535
|
+
return [];
|
|
12200
14536
|
case "ForStatement": {
|
|
12201
14537
|
const map = topLocals().map;
|
|
12202
14538
|
if (map) {
|
|
@@ -12205,43 +14541,13 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12205
14541
|
break;
|
|
12206
14542
|
}
|
|
12207
14543
|
case "VariableDeclarator": {
|
|
12208
|
-
|
|
12209
|
-
const { map } = locals;
|
|
12210
|
-
if (map) {
|
|
12211
|
-
const declName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(node.id);
|
|
12212
|
-
const name = renameVariable(state, locals, declName);
|
|
12213
|
-
if (name) {
|
|
12214
|
-
if (node.id.type === "Identifier") {
|
|
12215
|
-
node.id.name = name;
|
|
12216
|
-
}
|
|
12217
|
-
else {
|
|
12218
|
-
node.id.left.name = name;
|
|
12219
|
-
}
|
|
12220
|
-
}
|
|
12221
|
-
else {
|
|
12222
|
-
map[declName] = true;
|
|
12223
|
-
}
|
|
12224
|
-
}
|
|
14544
|
+
renamer(node.id);
|
|
12225
14545
|
return ["init"];
|
|
12226
14546
|
}
|
|
12227
14547
|
case "CatchClause":
|
|
12228
14548
|
if (node.param) {
|
|
12229
14549
|
state.localsStack.push({ node, map: { ...(topLocals().map || {}) } });
|
|
12230
|
-
|
|
12231
|
-
const map = locals.map;
|
|
12232
|
-
const declName = (0,external_api_cjs_namespaceObject.variableDeclarationName)(node.param);
|
|
12233
|
-
const name = renameVariable(state, locals, declName);
|
|
12234
|
-
if (name) {
|
|
12235
|
-
if (node.param.type === "Identifier") {
|
|
12236
|
-
node.param.name = name;
|
|
12237
|
-
}
|
|
12238
|
-
else {
|
|
12239
|
-
node.param.left.name = name;
|
|
12240
|
-
}
|
|
12241
|
-
}
|
|
12242
|
-
else {
|
|
12243
|
-
map[declName] = true;
|
|
12244
|
-
}
|
|
14550
|
+
renamer(node.param);
|
|
12245
14551
|
return ["body"];
|
|
12246
14552
|
}
|
|
12247
14553
|
break;
|
|
@@ -12257,14 +14563,8 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12257
14563
|
break;
|
|
12258
14564
|
case "UnaryExpression":
|
|
12259
14565
|
if (node.operator == ":") {
|
|
12260
|
-
//
|
|
12261
|
-
//
|
|
12262
|
-
// indirectly, so we can't remove any enums or
|
|
12263
|
-
// constants with that name (we can still replace
|
|
12264
|
-
// uses of those constants though).
|
|
12265
|
-
state.exposed[node.argument.name] = true;
|
|
12266
|
-
// In any case, we can't replace *this* use of the
|
|
12267
|
-
// symbol with its value...
|
|
14566
|
+
// node.argument is not a normal identifier.
|
|
14567
|
+
// don't visit it.
|
|
12268
14568
|
return [];
|
|
12269
14569
|
}
|
|
12270
14570
|
break;
|
|
@@ -12276,29 +14576,73 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12276
14576
|
if (typeof name === "string") {
|
|
12277
14577
|
node.name = name;
|
|
12278
14578
|
}
|
|
14579
|
+
const [, results] = state.lookupValue(node);
|
|
14580
|
+
if (results) {
|
|
14581
|
+
if (results.length !== 1 || results[0].results.length !== 1) {
|
|
14582
|
+
throw new Error(`Local ${node.name} had multiple lookup results`);
|
|
14583
|
+
}
|
|
14584
|
+
const parent = results[0].parent;
|
|
14585
|
+
if (!parent) {
|
|
14586
|
+
throw new Error(`Local ${node.name} had no parent`);
|
|
14587
|
+
}
|
|
14588
|
+
const decl = results[0].results[0];
|
|
14589
|
+
if (parent.type === "FunctionDeclaration" ||
|
|
14590
|
+
decl.type !== "VariableDeclarator") {
|
|
14591
|
+
// we can't optimize away function or catch parameters
|
|
14592
|
+
return [];
|
|
14593
|
+
}
|
|
14594
|
+
if (parent.type !== "BlockStatement") {
|
|
14595
|
+
throw new Error(`Local ${node.name} was not declared at block scope(??)`);
|
|
14596
|
+
}
|
|
14597
|
+
decl.used = true;
|
|
14598
|
+
}
|
|
12279
14599
|
}
|
|
12280
14600
|
}
|
|
12281
14601
|
if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, node.name)) {
|
|
12282
14602
|
if (!lookupAndReplace(node)) {
|
|
12283
|
-
state.
|
|
14603
|
+
state.usedByName[node.name] = true;
|
|
12284
14604
|
}
|
|
12285
14605
|
}
|
|
12286
14606
|
return [];
|
|
12287
14607
|
}
|
|
12288
|
-
case "MemberExpression":
|
|
12289
|
-
|
|
12290
|
-
|
|
14608
|
+
case "MemberExpression": {
|
|
14609
|
+
const property = (0,external_api_cjs_namespaceObject.isLookupCandidate)(node);
|
|
14610
|
+
if (property) {
|
|
14611
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, property.name)) {
|
|
12291
14612
|
if (lookupAndReplace(node)) {
|
|
12292
14613
|
return false;
|
|
12293
14614
|
}
|
|
12294
14615
|
else {
|
|
12295
|
-
state.
|
|
14616
|
+
state.usedByName[property.name] = true;
|
|
12296
14617
|
}
|
|
12297
14618
|
}
|
|
12298
14619
|
// Don't optimize the property.
|
|
12299
14620
|
return ["object"];
|
|
12300
14621
|
}
|
|
12301
14622
|
break;
|
|
14623
|
+
}
|
|
14624
|
+
case "AssignmentExpression":
|
|
14625
|
+
case "UpdateExpression": {
|
|
14626
|
+
const lhs = node.type === "AssignmentExpression" ? node.left : node.argument;
|
|
14627
|
+
if (lhs.type === "Identifier") {
|
|
14628
|
+
const map = topLocals().map;
|
|
14629
|
+
if (map) {
|
|
14630
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(map, lhs.name)) {
|
|
14631
|
+
const name = map[lhs.name];
|
|
14632
|
+
if (typeof name === "string") {
|
|
14633
|
+
lhs.name = name;
|
|
14634
|
+
}
|
|
14635
|
+
}
|
|
14636
|
+
}
|
|
14637
|
+
}
|
|
14638
|
+
else if (lhs.type === "MemberExpression") {
|
|
14639
|
+
state.traverse(lhs.object);
|
|
14640
|
+
if (lhs.computed) {
|
|
14641
|
+
state.traverse(lhs.property);
|
|
14642
|
+
}
|
|
14643
|
+
}
|
|
14644
|
+
return node.type === "AssignmentExpression" ? ["right"] : [];
|
|
14645
|
+
}
|
|
12302
14646
|
case "BlockStatement": {
|
|
12303
14647
|
const map = topLocals().map;
|
|
12304
14648
|
if (map) {
|
|
@@ -12314,7 +14658,11 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12314
14658
|
node.params &&
|
|
12315
14659
|
node.params.forEach((p) => (map[(0,external_api_cjs_namespaceObject.variableDeclarationName)(p)] = true));
|
|
12316
14660
|
state.localsStack.push({ node, map });
|
|
12317
|
-
const [parent] = state.stack.slice(-2);
|
|
14661
|
+
const [parent, self] = state.stack.slice(-2);
|
|
14662
|
+
if (state.currentFunction) {
|
|
14663
|
+
throw new Error(`Nested functions: ${self.fullName} was activated during processing of ${state.currentFunction.fullName}`);
|
|
14664
|
+
}
|
|
14665
|
+
state.currentFunction = self;
|
|
12318
14666
|
if (parent.type == "ClassDeclaration" && !maybeCalled(node)) {
|
|
12319
14667
|
let used = false;
|
|
12320
14668
|
if (node.id.name == "initialize") {
|
|
@@ -12332,14 +14680,33 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12332
14680
|
return null;
|
|
12333
14681
|
};
|
|
12334
14682
|
state.post = (node) => {
|
|
12335
|
-
|
|
14683
|
+
const locals = topLocals();
|
|
14684
|
+
if (locals.node === node) {
|
|
12336
14685
|
state.localsStack.pop();
|
|
12337
14686
|
}
|
|
12338
|
-
const opt = optimizeNode(node);
|
|
14687
|
+
const opt = optimizeNode(state, node);
|
|
12339
14688
|
if (opt) {
|
|
12340
14689
|
return replace(opt, node);
|
|
12341
14690
|
}
|
|
12342
14691
|
switch (node.type) {
|
|
14692
|
+
case "FunctionDeclaration":
|
|
14693
|
+
if (!state.currentFunction) {
|
|
14694
|
+
throw new Error(`Finished function ${state.stack.slice(-1)[0].fullName}, but it was not marked current`);
|
|
14695
|
+
}
|
|
14696
|
+
state.currentFunction.info = state.currentFunction.next_info;
|
|
14697
|
+
delete state.currentFunction.next_info;
|
|
14698
|
+
delete state.currentFunction;
|
|
14699
|
+
break;
|
|
14700
|
+
case "BlockStatement":
|
|
14701
|
+
if (node.body.length === 1 && node.body[0].type === "BlockStatement") {
|
|
14702
|
+
node.body.splice(0, 1, ...node.body[0].body);
|
|
14703
|
+
}
|
|
14704
|
+
// fall through
|
|
14705
|
+
case "ForStatement":
|
|
14706
|
+
if (locals.map) {
|
|
14707
|
+
cleanupUnusedVars(state, node);
|
|
14708
|
+
}
|
|
14709
|
+
break;
|
|
12343
14710
|
case "ConditionalExpression":
|
|
12344
14711
|
case "IfStatement":
|
|
12345
14712
|
if (node.test.type === "Literal" &&
|
|
@@ -12349,6 +14716,12 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12349
14716
|
return false;
|
|
12350
14717
|
return replace(rep, rep);
|
|
12351
14718
|
}
|
|
14719
|
+
else if (node.type === "IfStatement" &&
|
|
14720
|
+
node.alternate &&
|
|
14721
|
+
node.alternate.type === "BlockStatement" &&
|
|
14722
|
+
!node.alternate.body.length) {
|
|
14723
|
+
delete node.alternate;
|
|
14724
|
+
}
|
|
12352
14725
|
break;
|
|
12353
14726
|
case "WhileStatement":
|
|
12354
14727
|
if (node.test.type === "Literal" && node.test.value === false) {
|
|
@@ -12365,17 +14738,62 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12365
14738
|
return replace(optimizeCall(state, node.argument, node), node.argument);
|
|
12366
14739
|
}
|
|
12367
14740
|
break;
|
|
14741
|
+
case "NewExpression":
|
|
14742
|
+
if (state.currentFunction) {
|
|
14743
|
+
const [, results] = state.lookup(node.callee);
|
|
14744
|
+
if (results) {
|
|
14745
|
+
recordCalledFuncs(state.currentFunction, findCalleesForNew(results));
|
|
14746
|
+
}
|
|
14747
|
+
else {
|
|
14748
|
+
recordModifiedUnknown(state.currentFunction);
|
|
14749
|
+
}
|
|
14750
|
+
}
|
|
14751
|
+
break;
|
|
12368
14752
|
case "CallExpression": {
|
|
12369
14753
|
return replace(optimizeCall(state, node, null), node);
|
|
12370
14754
|
}
|
|
12371
|
-
case "
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
node
|
|
12375
|
-
node.
|
|
12376
|
-
|
|
14755
|
+
case "VariableDeclaration": {
|
|
14756
|
+
const locals = topLocals();
|
|
14757
|
+
if (locals.map &&
|
|
14758
|
+
locals.node &&
|
|
14759
|
+
locals.node.type === "BlockStatement") {
|
|
14760
|
+
let results;
|
|
14761
|
+
const declarations = node.declarations;
|
|
14762
|
+
let i = 0;
|
|
14763
|
+
let j = 0;
|
|
14764
|
+
while (i < node.declarations.length) {
|
|
14765
|
+
const decl = declarations[i++];
|
|
14766
|
+
if (decl.init && decl.init.type === "CallExpression") {
|
|
14767
|
+
const inlined = replace(optimizeCall(state, decl.init, decl), decl.init);
|
|
14768
|
+
if (!inlined)
|
|
14769
|
+
continue;
|
|
14770
|
+
if (Array.isArray(inlined) || inlined.type != "BlockStatement") {
|
|
14771
|
+
throw new Error("Unexpected inlined result");
|
|
14772
|
+
}
|
|
14773
|
+
if (!results) {
|
|
14774
|
+
results = [];
|
|
14775
|
+
}
|
|
14776
|
+
delete decl.init;
|
|
14777
|
+
results.push(withLoc({
|
|
14778
|
+
...node,
|
|
14779
|
+
declarations: declarations.slice(j, i),
|
|
14780
|
+
}, j ? declarations[j] : null, decl.id));
|
|
14781
|
+
results.push(inlined);
|
|
14782
|
+
j = i;
|
|
14783
|
+
}
|
|
14784
|
+
}
|
|
14785
|
+
if (results) {
|
|
14786
|
+
if (j < i) {
|
|
14787
|
+
results.push({
|
|
14788
|
+
...node,
|
|
14789
|
+
declarations: declarations.slice(j, i),
|
|
14790
|
+
});
|
|
14791
|
+
}
|
|
14792
|
+
return results;
|
|
14793
|
+
}
|
|
12377
14794
|
}
|
|
12378
14795
|
break;
|
|
14796
|
+
}
|
|
12379
14797
|
case "ExpressionStatement":
|
|
12380
14798
|
if (node.expression.type === "CallExpression") {
|
|
12381
14799
|
return replace(optimizeCall(state, node.expression, node), node.expression);
|
|
@@ -12407,6 +14825,32 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12407
14825
|
}
|
|
12408
14826
|
}
|
|
12409
14827
|
break;
|
|
14828
|
+
case "AssignmentExpression":
|
|
14829
|
+
if (node.operator === "=" &&
|
|
14830
|
+
node.left.type === "Identifier" &&
|
|
14831
|
+
node.right.type === "Identifier" &&
|
|
14832
|
+
node.left.name === node.right.name) {
|
|
14833
|
+
return { type: "Literal", value: null, raw: "null" };
|
|
14834
|
+
}
|
|
14835
|
+
// fall through;
|
|
14836
|
+
case "UpdateExpression":
|
|
14837
|
+
if (state.currentFunction) {
|
|
14838
|
+
const lhs = node.type === "AssignmentExpression" ? node.left : node.argument;
|
|
14839
|
+
const [, results] = state.lookup(lhs);
|
|
14840
|
+
if (results) {
|
|
14841
|
+
recordModifiedDecls(state.currentFunction, results);
|
|
14842
|
+
}
|
|
14843
|
+
else {
|
|
14844
|
+
const id = lhs.type === "Identifier" ? lhs : (0,external_api_cjs_namespaceObject.isLookupCandidate)(lhs);
|
|
14845
|
+
if (id) {
|
|
14846
|
+
recordModifiedName(state.currentFunction, id.name);
|
|
14847
|
+
}
|
|
14848
|
+
else {
|
|
14849
|
+
recordModifiedUnknown(state.currentFunction);
|
|
14850
|
+
}
|
|
14851
|
+
}
|
|
14852
|
+
}
|
|
14853
|
+
break;
|
|
12410
14854
|
}
|
|
12411
14855
|
return null;
|
|
12412
14856
|
};
|
|
@@ -12414,12 +14858,16 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12414
14858
|
(0,external_api_cjs_namespaceObject.collectNamespaces)(f.ast, state);
|
|
12415
14859
|
});
|
|
12416
14860
|
state.calledFunctions = {};
|
|
12417
|
-
state.exposed =
|
|
14861
|
+
state.exposed = state.nextExposed;
|
|
14862
|
+
state.nextExposed = {};
|
|
12418
14863
|
Object.values(fnMap).forEach((f) => {
|
|
12419
14864
|
(0,external_api_cjs_namespaceObject.collectNamespaces)(f.ast, state);
|
|
12420
14865
|
});
|
|
14866
|
+
state.exposed = state.nextExposed;
|
|
14867
|
+
state.nextExposed = {};
|
|
12421
14868
|
delete state.pre;
|
|
12422
14869
|
delete state.post;
|
|
14870
|
+
Object.values(state.allFunctions).forEach((fns) => fns.forEach((fn) => sizeBasedPRE(state, fn)));
|
|
12423
14871
|
const cleanup = (node) => {
|
|
12424
14872
|
switch (node.type) {
|
|
12425
14873
|
case "ThisExpression":
|
|
@@ -12429,7 +14877,8 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12429
14877
|
if (node.members.every((m) => {
|
|
12430
14878
|
const name = "name" in m ? m.name : m.id.name;
|
|
12431
14879
|
return ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, name) &&
|
|
12432
|
-
!(0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, name)
|
|
14880
|
+
!(0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, name) &&
|
|
14881
|
+
!(0,external_api_cjs_namespaceObject.hasProperty)(state.usedByName, name));
|
|
12433
14882
|
})) {
|
|
12434
14883
|
node.enumType = [
|
|
12435
14884
|
...new Set(node.members.map((m) => {
|
|
@@ -12472,7 +14921,9 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12472
14921
|
case "VariableDeclaration": {
|
|
12473
14922
|
node.declarations = node.declarations.filter((d) => {
|
|
12474
14923
|
const name = (0,external_api_cjs_namespaceObject.variableDeclarationName)(d.id);
|
|
12475
|
-
return (!(0,external_api_cjs_namespaceObject.hasProperty)(state.index, name) ||
|
|
14924
|
+
return (!(0,external_api_cjs_namespaceObject.hasProperty)(state.index, name) ||
|
|
14925
|
+
(0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, name) ||
|
|
14926
|
+
(0,external_api_cjs_namespaceObject.hasProperty)(state.usedByName, name));
|
|
12476
14927
|
});
|
|
12477
14928
|
if (!node.declarations.length) {
|
|
12478
14929
|
return false;
|
|
@@ -12505,7 +14956,7 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12505
14956
|
}
|
|
12506
14957
|
return null;
|
|
12507
14958
|
};
|
|
12508
|
-
Object.
|
|
14959
|
+
Object.entries(fnMap).forEach(([name, f]) => {
|
|
12509
14960
|
traverseAst(f.ast, undefined, (node) => {
|
|
12510
14961
|
const ret = cleanup(node);
|
|
12511
14962
|
if (ret === false) {
|
|
@@ -12513,16 +14964,15 @@ async function optimizeMonkeyC(fnMap, barrelList, config) {
|
|
|
12513
14964
|
}
|
|
12514
14965
|
return ret;
|
|
12515
14966
|
});
|
|
14967
|
+
if (state.config && state.config.checkBuildPragmas) {
|
|
14968
|
+
pragmaChecker(state, f.ast, state.diagnostics?.[name]);
|
|
14969
|
+
}
|
|
12516
14970
|
});
|
|
12517
14971
|
return state.diagnostics;
|
|
12518
14972
|
}
|
|
12519
14973
|
function optimizeCall(state, node, context) {
|
|
12520
14974
|
const [name, results] = state.lookupNonlocal(node.callee);
|
|
12521
|
-
const callees = results
|
|
12522
|
-
results
|
|
12523
|
-
.map((r) => r.results)
|
|
12524
|
-
.flat()
|
|
12525
|
-
.filter((c) => c.type === "FunctionDeclaration");
|
|
14975
|
+
const callees = results ? findCallees(results) : null;
|
|
12526
14976
|
if (!callees || !callees.length) {
|
|
12527
14977
|
const n = name ||
|
|
12528
14978
|
("name" in node.callee && node.callee.name) ||
|
|
@@ -12531,21 +14981,31 @@ function optimizeCall(state, node, context) {
|
|
|
12531
14981
|
"name" in node.callee.property &&
|
|
12532
14982
|
node.callee.property.name);
|
|
12533
14983
|
if (n) {
|
|
12534
|
-
state.
|
|
14984
|
+
if ((0,external_api_cjs_namespaceObject.hasProperty)(state.allFunctions, n)) {
|
|
14985
|
+
if (state.currentFunction) {
|
|
14986
|
+
recordCalledFuncs(state.currentFunction, state.allFunctions[n]);
|
|
14987
|
+
}
|
|
14988
|
+
state.allFunctions[n].forEach((fn) => markFunctionCalled(state, fn.node));
|
|
14989
|
+
}
|
|
12535
14990
|
}
|
|
12536
|
-
else {
|
|
12537
|
-
//
|
|
12538
|
-
//
|
|
14991
|
+
else if (state.currentFunction) {
|
|
14992
|
+
// I don't think this can happen: foo[x](args)
|
|
14993
|
+
// doesn't parse, so you can't even do things like
|
|
14994
|
+
// $.Toybox.Lang[:format]("fmt", [])
|
|
14995
|
+
recordModifiedUnknown(state.currentFunction);
|
|
12539
14996
|
}
|
|
12540
14997
|
return null;
|
|
12541
14998
|
}
|
|
14999
|
+
if (state.currentFunction) {
|
|
15000
|
+
recordCalledFuncs(state.currentFunction, callees);
|
|
15001
|
+
}
|
|
12542
15002
|
if (callees.length == 1 && callees[0].type === "FunctionDeclaration") {
|
|
12543
15003
|
const callee = callees[0].node;
|
|
12544
15004
|
if (!context &&
|
|
12545
15005
|
callee.optimizable &&
|
|
12546
15006
|
!callee.hasOverride &&
|
|
12547
15007
|
node.arguments.every((n) => getNodeValue(n)[0] !== null)) {
|
|
12548
|
-
const ret = evaluateFunction(callee, node.arguments);
|
|
15008
|
+
const ret = evaluateFunction(state, callee, node.arguments);
|
|
12549
15009
|
if (ret) {
|
|
12550
15010
|
return ret;
|
|
12551
15011
|
}
|
|
@@ -12561,118 +15021,6 @@ function optimizeCall(state, node, context) {
|
|
|
12561
15021
|
return null;
|
|
12562
15022
|
}
|
|
12563
15023
|
|
|
12564
|
-
;// CONCATENATED MODULE: ./src/pragma-checker.ts
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
function pragmaChecker(ast, diagnostics) {
|
|
12568
|
-
const comments = ast.comments;
|
|
12569
|
-
if (!comments)
|
|
12570
|
-
return;
|
|
12571
|
-
diagnostics = diagnostics
|
|
12572
|
-
?.slice()
|
|
12573
|
-
.sort((d1, d2) => d1.loc.start < d2.loc.start ? -1 : d1.loc.start == d2.loc.start ? 0 : 1);
|
|
12574
|
-
let diagIndex = 0;
|
|
12575
|
-
let index = -1;
|
|
12576
|
-
let comment;
|
|
12577
|
-
let matchers;
|
|
12578
|
-
const next = () => {
|
|
12579
|
-
while (++index < comments.length) {
|
|
12580
|
-
comment = comments[index];
|
|
12581
|
-
let match = comment.value.match(/^\s*@(match|expect)\s+(.+)/);
|
|
12582
|
-
if (!match)
|
|
12583
|
-
continue;
|
|
12584
|
-
const kind = match[1];
|
|
12585
|
-
let str = match[2];
|
|
12586
|
-
matchers = [];
|
|
12587
|
-
while ((match = str.match(/^([/%&#@"])(.+?(?<!\\)(?:\\{2})*)\1(\s+|$)/))) {
|
|
12588
|
-
matchers.push({ kind, quote: match[1], needle: match[2] });
|
|
12589
|
-
str = str.substring(match[0].length);
|
|
12590
|
-
if (!str.length)
|
|
12591
|
-
break;
|
|
12592
|
-
}
|
|
12593
|
-
if (!str.length)
|
|
12594
|
-
break;
|
|
12595
|
-
if (!matchers.length) {
|
|
12596
|
-
match = str.match(/^(\S+)\s+$/);
|
|
12597
|
-
if (match) {
|
|
12598
|
-
matchers.push({ kind, quote: '"', needle: match[1] });
|
|
12599
|
-
break;
|
|
12600
|
-
}
|
|
12601
|
-
}
|
|
12602
|
-
throw new Error(`Build pragma '${comment.value}' is invalid. In ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12603
|
-
}
|
|
12604
|
-
};
|
|
12605
|
-
const matcher = (quote, needle, haystack) => {
|
|
12606
|
-
if (quote == '"') {
|
|
12607
|
-
return haystack.includes(needle);
|
|
12608
|
-
}
|
|
12609
|
-
const re = new RegExp(needle);
|
|
12610
|
-
return re.test(haystack);
|
|
12611
|
-
};
|
|
12612
|
-
next();
|
|
12613
|
-
traverseAst(ast, (node) => {
|
|
12614
|
-
if (index >= comments.length)
|
|
12615
|
-
return false;
|
|
12616
|
-
if (node.start && node.start >= (comment.end || Infinity)) {
|
|
12617
|
-
const { kind, quote, needle } = matchers.shift();
|
|
12618
|
-
if (kind === "match") {
|
|
12619
|
-
if (!matcher(quote, needle, (0,external_api_cjs_namespaceObject.formatAst)(node).replace(/([\r\n]|\s)+/g, " "))) {
|
|
12620
|
-
throw new Error(`Didn't find '${needle}' at ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12621
|
-
}
|
|
12622
|
-
}
|
|
12623
|
-
else if (kind === "expect") {
|
|
12624
|
-
const locCmp = (a, b) => {
|
|
12625
|
-
if (!b)
|
|
12626
|
-
return -1;
|
|
12627
|
-
if (a.start.line < b.start.line)
|
|
12628
|
-
return -1;
|
|
12629
|
-
if (a.start.line === b.start.line &&
|
|
12630
|
-
a.start.column < b.start.column) {
|
|
12631
|
-
return -1;
|
|
12632
|
-
}
|
|
12633
|
-
if (a.end.line > b.end.line)
|
|
12634
|
-
return 1;
|
|
12635
|
-
if (a.end.line === b.end.line && a.end.column >= b.end.column) {
|
|
12636
|
-
return 1;
|
|
12637
|
-
}
|
|
12638
|
-
return 0;
|
|
12639
|
-
};
|
|
12640
|
-
let found = false;
|
|
12641
|
-
if (diagnostics) {
|
|
12642
|
-
while (true) {
|
|
12643
|
-
if (diagIndex >= diagnostics.length) {
|
|
12644
|
-
diagnostics = null;
|
|
12645
|
-
break;
|
|
12646
|
-
}
|
|
12647
|
-
const diag = diagnostics[diagIndex];
|
|
12648
|
-
const cmp = locCmp(diag.loc, node.loc);
|
|
12649
|
-
if (cmp > 0) {
|
|
12650
|
-
break;
|
|
12651
|
-
}
|
|
12652
|
-
diagIndex++;
|
|
12653
|
-
if (cmp < 0)
|
|
12654
|
-
continue;
|
|
12655
|
-
if (matcher(quote, needle, diag.message)) {
|
|
12656
|
-
found = true;
|
|
12657
|
-
diag.type = "INFO";
|
|
12658
|
-
}
|
|
12659
|
-
}
|
|
12660
|
-
}
|
|
12661
|
-
if (!found) {
|
|
12662
|
-
throw new Error(`Missing error message '${needle} at ${comment.loc.source}:${comment.loc.start.line}`);
|
|
12663
|
-
}
|
|
12664
|
-
}
|
|
12665
|
-
if (matchers.length) {
|
|
12666
|
-
// if we're checking a series of nodes, we need
|
|
12667
|
-
// to skip over this one.
|
|
12668
|
-
return false;
|
|
12669
|
-
}
|
|
12670
|
-
next();
|
|
12671
|
-
}
|
|
12672
|
-
return null;
|
|
12673
|
-
});
|
|
12674
|
-
}
|
|
12675
|
-
|
|
12676
15024
|
;// CONCATENATED MODULE: ./src/optimizer.ts
|
|
12677
15025
|
|
|
12678
15026
|
|
|
@@ -13058,6 +15406,7 @@ const configOptionsToCheck = [
|
|
|
13058
15406
|
"ignoredAnnotations",
|
|
13059
15407
|
"ignoredSourcePaths",
|
|
13060
15408
|
"checkInvalidSymbols",
|
|
15409
|
+
"sizeBasedPRE",
|
|
13061
15410
|
];
|
|
13062
15411
|
/**
|
|
13063
15412
|
* @param {BuildConfig} config
|
|
@@ -13109,22 +15458,19 @@ async function generateOneConfig(buildConfig, dependencyFiles, config) {
|
|
|
13109
15458
|
// the oldest optimized file, we don't need to regenerate
|
|
13110
15459
|
const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
|
|
13111
15460
|
const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
|
|
13112
|
-
if (source_time < opt_time &&
|
|
15461
|
+
if (source_time < opt_time && 1657670997056 < opt_time) {
|
|
13113
15462
|
return { hasTests, diagnostics: prevDiagnostics };
|
|
13114
15463
|
}
|
|
13115
15464
|
}
|
|
13116
15465
|
await promises_namespaceObject.rm(output, { recursive: true, force: true });
|
|
13117
15466
|
await promises_namespaceObject.mkdir(output, { recursive: true });
|
|
13118
15467
|
const diagnostics = await optimizeMonkeyC(fnMap, Object.keys(buildConfig.barrelMap || {}), config);
|
|
13119
|
-
return Promise.all(Object.
|
|
15468
|
+
return Promise.all(Object.values(fnMap).map(async (info) => {
|
|
13120
15469
|
const name = info.output;
|
|
13121
15470
|
const dir = external_path_.dirname(name);
|
|
13122
15471
|
await promises_namespaceObject.mkdir(dir, { recursive: true });
|
|
13123
15472
|
const opt_source = (0,external_api_cjs_namespaceObject.formatAst)(info.ast, info.monkeyCSource);
|
|
13124
15473
|
await promises_namespaceObject.writeFile(name, opt_source);
|
|
13125
|
-
if (config.checkBuildPragmas) {
|
|
13126
|
-
pragmaChecker(info.ast, diagnostics?.[inFile]);
|
|
13127
|
-
}
|
|
13128
15474
|
return info.hasTests;
|
|
13129
15475
|
})).then((results) => {
|
|
13130
15476
|
const hasTests = results.some((v) => v);
|