@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.
@@ -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 "Off":
10056
+ switch (typeCheckLevel?.toLowerCase()) {
10057
+ case "off":
9879
10058
  extraArgs.push("-l", "0");
9880
10059
  break;
9881
- case "Gradual":
10060
+ case "gradual":
9882
10061
  extraArgs.push("-l", "1");
9883
10062
  break;
9884
- case "Informative":
10063
+ case "informative":
9885
10064
  extraArgs.push("-l", "2");
9886
10065
  break;
9887
- case "Strict":
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: ["test", "consequent", "alternate"],
10830
- ContinueStatement: [],
10831
- DoWhileStatement: ["body", "test"],
10832
- EnumDeclaration: ["attrs", "id", "body"],
10833
- EnumStringBody: ["members"],
10834
- EnumStringMember: ["id", "init"],
10835
- ExpressionStatement: ["expression"],
10836
- ForStatement: ["init", "test", "body", "update"],
10837
- FunctionDeclaration: ["attrs", "id", "params", "returnType", "body"],
10838
- Identifier: [],
10839
- IfStatement: ["test", "consequent", "alternate"],
10840
- ImportModule: ["id"],
10841
- InstanceOfCase: ["id"],
10842
- Line: [],
10843
- Literal: [],
10844
- LogicalExpression: ["left", "right"],
10845
- MemberExpression: ["object", "property"],
10846
- MethodDefinition: ["params", "returnType"],
10847
- ModuleDeclaration: ["attrs", "id", "body"],
10848
- MultiLine: [],
10849
- NewExpression: ["callee", "arguments"],
10850
- ObjectExpression: ["properties"],
10851
- ParenthesizedExpression: ["expression"],
10852
- Program: ["body", "comments"],
10853
- Property: ["key", "value"],
10854
- ReturnStatement: ["argument"],
10855
- SequenceExpression: ["expressions"],
10856
- SizedArrayExpression: ["size", "ts"],
10857
- SwitchCase: ["test", "consequent"],
10858
- SwitchStatement: ["discriminant", "cases"],
10859
- ThisExpression: [],
10860
- ThrowStatement: ["argument"],
10861
- TryStatement: ["block", "handler", "finalizer"],
10862
- TypedefDeclaration: ["attrs", "id", "ts"],
10863
- TypeSpecList: ["ts"],
10864
- TypeSpecPart: ["name", "body", "callspec", "generics"],
10865
- UnaryExpression: ["argument"],
10866
- UpdateExpression: ["argument"],
10867
- Using: ["id", "as"],
10868
- VariableDeclaration: ["attrs", "declarations"],
10869
- VariableDeclarator: ["id", "init"],
10870
- WhileStatement: ["test", "body"],
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
- const repl = traverseAst(value, pre, post);
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
- throw new Error("Array returned by traverseAst in Node context");
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 safety = getSafety(results[0].results[0]);
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
- let callSeen = false;
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
- traverseAst(func.node.body, null, (node) => {
11070
- switch (node.type) {
11071
- case "AssignmentExpression":
11072
- case "UpdateExpression": {
11073
- const v = node.type == "UpdateExpression" ? node.argument : node.left;
11074
- if (v.type === "Identifier" && (0,external_api_cjs_namespaceObject.hasProperty)(params, v.name)) {
11075
- safeArgs[params[v.name]] = null;
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
- // fall through
11079
- case "CallExpression":
11080
- case "NewExpression":
11081
- callSeen = true;
11082
- break;
11083
- case "Identifier":
11084
- if (callSeen &&
11085
- (0,external_api_cjs_namespaceObject.hasProperty)(params, node.name) &&
11086
- !safeArgs[params[node.name]]) {
11087
- safeArgs[params[node.name]] = null;
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 "Identifier": {
11236
- if (state.inType)
11237
- break;
11238
- if ((0,external_api_cjs_namespaceObject.hasProperty)(params, node.name)) {
11239
- const ix = params[node.name];
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
- replacement = fixNodeScope(state, node, func.stack);
11248
- if (!replacement) {
11249
- failed = true;
11250
- inlineDiagnostic(state, func, call, `Failed to resolve '${node.name}'`);
11251
- return post(node, state);
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" && retStmtCount !== 1) {
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.body.slice(-1)[0];
11862
+ const [last] = lastStmt(func.node.body);
11372
11863
  if (!last ||
11373
11864
  last.type !== "ReturnStatement" ||
11374
- (context.type === "AssignmentExpression" && !last.argument)) {
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 = JSON.parse(JSON.stringify(func.node.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.body[body.body.length - 1];
11887
+ const [last, block] = lastStmt(body);
11395
11888
  if (last.type != "ReturnStatement") {
11396
11889
  throw new Error("ReturnStatement got lost!");
11397
11890
  }
11398
- if (context.type === "AssignmentExpression") {
11399
- context.right = last.argument;
11400
- body.body[body.body.length - 1] = {
11401
- type: "ExpressionStatement",
11402
- expression: context,
11403
- };
11404
- }
11405
- else if (last.argument) {
11406
- const side_exprs = unused(last.argument);
11407
- body.body.splice(body.body.length - 1, 1, ...side_exprs);
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
- --body.body.length;
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 = JSON.parse(JSON.stringify(func.node.body.body[0].argument));
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/visitor.ts
12039
+ ;// CONCATENATED MODULE: ./src/pragma-checker.ts
11530
12040
 
11531
- function visitReferences(state, ast, name, defn, callback) {
11532
- const checkResults = ([name, results], node) => {
11533
- if (name && results) {
11534
- if (!defn || (0,external_api_cjs_namespaceObject.sameLookupResult)(results, defn)) {
11535
- if (callback(node, results, false) === false) {
11536
- return [];
11537
- }
11538
- }
11539
- }
11540
- else if (defn === false) {
11541
- if (callback(node, [], results === null) === false) {
11542
- return [];
11543
- }
11544
- }
11545
- return null;
11546
- };
11547
- state.pre = (node) => {
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
- if (!node.computed && node.property.type === "Identifier") {
11595
- if (!name || node.property.name === name) {
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 ((0,external_api_cjs_namespaceObject.isStateNode)(f) &&
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
- state.allFunctions.push(scope);
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.post;
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
- if (typeof node.argument.value == "number") {
11882
- return {
11883
- ...node.argument,
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
- let type = node.value === null ? "Null" : typeof node.value;
14084
+ if (node.value === null) {
14085
+ return [node, "Null"];
14086
+ }
14087
+ const type = typeof node.value;
11908
14088
  if (type === "number") {
11909
- const match = node.raw && prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.exec(node.raw);
14089
+ const match = prettier_plugin_monkeyc_namespaceObject.LiteralIntegerRe.exec(node.raw);
11910
14090
  if (match) {
11911
- type = match[2] == "l" ? "Long" : "Number";
14091
+ return match[2] === "l" || match[2] === "L"
14092
+ ? [node, "Long"]
14093
+ : [node, "Number"];
11912
14094
  }
11913
- else if (node.raw && node.raw.endsWith("d")) {
11914
- type = "Double";
11915
- }
11916
- else {
11917
- type = "Float";
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
- else if (type === "string") {
11921
- type = "String";
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
- else if (type === "boolean") {
14149
+ return false;
14150
+ }
14151
+ function replacementLiteral(arg, value, type) {
14152
+ if (typeof value === "boolean") {
11924
14153
  type = "Boolean";
11925
14154
  }
11926
- else {
11927
- type = "Unknown";
14155
+ else if (type === "Number") {
14156
+ value = Number(BigInt.asIntN(32, BigInt(value)));
11928
14157
  }
11929
- return [node, type];
11930
- }
11931
- function optimizeNode(node) {
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
- value = -arg.value - 1;
14212
+ return replacementLiteral(arg, ~BigInt(arg.value), type);
11958
14213
  }
11959
- else if (type === "Boolean" && node.operator == "!") {
11960
- value = !arg.value;
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
- if (left_type != right_type ||
11993
- (left_type != "Number" && left_type != "Long")) {
11994
- break;
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
- ...left,
12001
- value,
12002
- raw: value.toString() + (left_type === "Long" ? "l" : ""),
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
- ...(await analyze(fnMap, barrelList, config)),
12077
- localsStack: [{}],
12078
- exposed: {},
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
- const obj = getLiteralFromDecls(objects);
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 = { type: "Literal", value: result };
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 false;
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
- const locals = topLocals();
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
- const locals = topLocals();
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
- // If we produce a Symbol, for a given name,
12261
- // its possible that someone uses that symbol
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.exposed[node.name] = true;
14603
+ state.usedByName[node.name] = true;
12284
14604
  }
12285
14605
  }
12286
14606
  return [];
12287
14607
  }
12288
- case "MemberExpression":
12289
- if (node.property.type === "Identifier" && !node.computed) {
12290
- if ((0,external_api_cjs_namespaceObject.hasProperty)(state.index, node.property.name)) {
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.exposed[node.property.name] = true;
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
- if (topLocals().node === node) {
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 "AssignmentExpression":
12372
- if (node.operator === "=" &&
12373
- node.left.type === "Identifier" &&
12374
- node.right.type === "Identifier" &&
12375
- node.left.name === node.right.name) {
12376
- return { type: "Literal", value: null, raw: "null" };
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) || (0,external_api_cjs_namespaceObject.hasProperty)(state.exposed, 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.values(fnMap).forEach((f) => {
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.exposed[n] = true;
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
- // There are unnamed CallExpressions, such as new [size]
12538
- // So there's nothing to do here.
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 && 1655916886685 < 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.entries(fnMap).map(async ([inFile, info]) => {
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);