@markw65/monkeyc-optimizer 1.1.12 → 1.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/api.cjs CHANGED
@@ -2758,13 +2758,15 @@ function fixNodeScope(state, lookupNode, nodeStack) {
2758
2758
  /* harmony import */ var _type_flow__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(4859);
2759
2759
  /* harmony import */ var _type_flow_could_be__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(4055);
2760
2760
  /* harmony import */ var _type_flow_interp__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(7161);
2761
- /* harmony import */ var _type_flow_optimize__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(3687);
2762
- /* harmony import */ var _type_flow_sub_type__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(9234);
2763
- /* harmony import */ var _type_flow_types__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(7255);
2764
- /* harmony import */ var _unused_exprs__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(424);
2765
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(6906);
2766
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_16___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_16__);
2767
- /* harmony import */ var _variable_renamer__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(4405);
2761
+ /* harmony import */ var _type_flow_minimize_modules__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(4416);
2762
+ /* harmony import */ var _type_flow_optimize__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(3687);
2763
+ /* harmony import */ var _type_flow_sub_type__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(9234);
2764
+ /* harmony import */ var _type_flow_types__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(7255);
2765
+ /* harmony import */ var _unused_exprs__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(424);
2766
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(6906);
2767
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_17___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_17__);
2768
+ /* harmony import */ var _variable_renamer__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(4405);
2769
+
2768
2770
 
2769
2771
 
2770
2772
 
@@ -3370,32 +3372,30 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3370
3372
  break;
3371
3373
  case "Identifier": {
3372
3374
  const map = topLocals().map;
3373
- if (map) {
3374
- if (hasProperty(map, node.name)) {
3375
- const name = map[node.name];
3376
- if (typeof name === "string") {
3377
- renameIdentifier(node, name);
3378
- }
3379
- const [, results] = state.lookupValue(node);
3380
- if (results) {
3381
- if (results.length !== 1 || results[0].results.length !== 1) {
3382
- throw new Error(`Local ${node.name} had multiple lookup results`);
3383
- }
3384
- const parent = results[0].parent;
3385
- if (!parent) {
3386
- throw new Error(`Local ${node.name} had no parent`);
3387
- }
3388
- const decl = results[0].results[0];
3389
- if (parent.type === "FunctionDeclaration" ||
3390
- decl.type !== "VariableDeclarator") {
3391
- // we can't optimize away function or catch parameters
3392
- return [];
3393
- }
3394
- if (parent.type !== "BlockStatement") {
3395
- throw new Error(`Local ${node.name} was not declared at block scope(??)`);
3396
- }
3397
- decl.used = true;
3375
+ if (hasProperty(map, node.name)) {
3376
+ const name = map[node.name];
3377
+ if (typeof name === "string") {
3378
+ renameIdentifier(node, name);
3379
+ }
3380
+ const [, results] = state.lookupValue(node);
3381
+ if (results) {
3382
+ if (results.length !== 1 || results[0].results.length !== 1) {
3383
+ throw new Error(`Local ${node.name} had multiple lookup results`);
3384
+ }
3385
+ const parent = results[0].parent;
3386
+ if (!parent) {
3387
+ throw new Error(`Local ${node.name} had no parent`);
3388
+ }
3389
+ const decl = results[0].results[0];
3390
+ if (parent.type === "FunctionDeclaration" ||
3391
+ decl.type !== "VariableDeclarator") {
3392
+ // we can't optimize away function or catch parameters
3393
+ return [];
3394
+ }
3395
+ if (parent.type !== "BlockStatement") {
3396
+ throw new Error(`Local ${node.name} was not declared at block scope(??)`);
3398
3397
  }
3398
+ decl.used = true;
3399
3399
  }
3400
3400
  }
3401
3401
  return [];
@@ -3683,6 +3683,11 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3683
3683
  state.nextExposed = {};
3684
3684
  delete state.pre;
3685
3685
  delete state.post;
3686
+ if (state.config?.minimizeModules ?? true) {
3687
+ Object.values(fnMap).forEach((f) => {
3688
+ minimizeModules(f.ast, state);
3689
+ });
3690
+ }
3686
3691
  Object.values(state.allFunctions).forEach((fns) => fns.forEach((fn) => sizeBasedPRE(state, fn)));
3687
3692
  const cleanup = (node) => {
3688
3693
  switch (node.type) {
@@ -4026,7 +4031,7 @@ function pragmaChecker(state, ast, diagnostics) {
4026
4031
  if (kind === "match") {
4027
4032
  const haystack = formatAst(node)
4028
4033
  .replace(/([\r\n]|\s)+/g, " ")
4029
- .replace(/\b\w+\s\/\*>(\w+)<\*\//g, "$1");
4034
+ .replace(/\b\w+\s\/\*>([\w.]+)<\*\//g, "$1");
4030
4035
  if (!matcher(quote, needle, haystack)) {
4031
4036
  matcher(quote, needle, haystack);
4032
4037
  diagnostic(state, comment, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
@@ -4951,8 +4956,8 @@ function buildConflictGraph(state, func) {
4951
4956
  function addEquiv(ts, key, equiv) {
4952
4957
  if (key === equiv)
4953
4958
  return true;
4954
- let keyVal = ts.get(key);
4955
- let equivVal = ts.get(equiv);
4959
+ const keyVal = ts.get(key);
4960
+ const equivVal = ts.get(equiv);
4956
4961
  if (!keyVal || !equivVal)
4957
4962
  return false;
4958
4963
  if (equivVal.equivSet) {
@@ -4964,31 +4969,25 @@ function addEquiv(ts, key, equiv) {
4964
4969
  }
4965
4970
  // equiv is not (or no longer) part of an equivSet
4966
4971
  if (!keyVal.equivSet) {
4967
- keyVal = { ...keyVal };
4968
4972
  keyVal.equivSet = new Set([key, equiv]);
4969
- ts.set(key, keyVal);
4970
4973
  }
4971
4974
  else {
4972
4975
  keyVal.equivSet.add(equiv);
4973
4976
  }
4974
- equivVal = { ...equivVal, equivSet: keyVal.equivSet };
4975
- ts.set(equiv, equivVal);
4977
+ equivVal.equivSet = keyVal.equivSet;
4976
4978
  return false;
4977
4979
  }
4978
4980
  function removeEquiv(ts, equiv) {
4979
- let equivVal = ts.get(equiv);
4981
+ const equivVal = ts.get(equiv);
4980
4982
  if (!equivVal?.equivSet)
4981
4983
  return;
4982
4984
  equivVal.equivSet.delete(equiv);
4983
4985
  if (equivVal.equivSet.size === 1) {
4984
4986
  const other = Array.from(equivVal.equivSet)[0];
4985
- const otherVal = { ...ts.get(other) };
4987
+ const otherVal = ts.get(other);
4986
4988
  delete otherVal.equivSet;
4987
- ts.set(other, otherVal);
4988
4989
  }
4989
- equivVal = { ...equivVal };
4990
4990
  delete equivVal.equivSet;
4991
- ts.set(equiv, equivVal);
4992
4991
  }
4993
4992
  function getEquivSet(ts, k) {
4994
4993
  const keys = ts.get(k)?.equivSet;
@@ -5042,9 +5041,14 @@ function cloneTypeState(blockState) {
5042
5041
  const { map, trackedMemberDecls, liveCopyPropEvents, ...rest } = blockState;
5043
5042
  const clone = { map: new Map(map), ...rest };
5044
5043
  clone.map.forEach((value, key) => {
5045
- if (value.equivSet && key === Array.from(value.equivSet)[0]) {
5046
- const equivSet = new Set(value.equivSet);
5047
- equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
5044
+ if (value.equivSet) {
5045
+ if (key === Array.from(value.equivSet)[0]) {
5046
+ const equivSet = new Set(value.equivSet);
5047
+ equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
5048
+ }
5049
+ }
5050
+ else {
5051
+ clone.map.set(key, { ...value });
5048
5052
  }
5049
5053
  });
5050
5054
  if (trackedMemberDecls) {
@@ -5081,12 +5085,9 @@ function addCopyPropEvent(blockState, item) {
5081
5085
  const liveCopyPropEvents = blockState.liveCopyPropEvents;
5082
5086
  const decl = item.event.decl;
5083
5087
  assert(declIsLocal(decl));
5084
- let tov = blockState.map.get(decl);
5088
+ const tov = blockState.map.get(decl);
5085
5089
  assert(tov);
5086
- if (tov.copyPropItem !== item) {
5087
- tov = { ...tov, copyPropItem: item };
5088
- blockState.map.set(decl, tov);
5089
- }
5090
+ tov.copyPropItem = item;
5090
5091
  item.contained.forEach((value, key) => {
5091
5092
  const decls = liveCopyPropEvents.get(key);
5092
5093
  if (!decls) {
@@ -5119,15 +5120,13 @@ function clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp) {
5119
5120
  blockState.liveCopyPropEvents
5120
5121
  ?.get(decl)
5121
5122
  ?.forEach((cpDecl) => {
5122
- let value = blockState.map.get(cpDecl);
5123
+ const value = blockState.map.get(cpDecl);
5123
5124
  assert(value && value.copyPropItem);
5124
5125
  assert(Array.from(value.copyPropItem.contained).some(([key]) => {
5125
5126
  return decl === key;
5126
5127
  }));
5127
5128
  copyPropFailed(blockState, value.copyPropItem, nodeCopyProp);
5128
- value = { ...value };
5129
5129
  delete value.copyPropItem;
5130
- blockState.map.set(cpDecl, value);
5131
5130
  });
5132
5131
  }
5133
5132
  function validateTypeState(curState) {
@@ -5170,11 +5169,9 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5170
5169
  if (tov.equivSet) {
5171
5170
  if (intersectEquiv(to.map, from.map, k)) {
5172
5171
  changes = true;
5173
- tov = to.map.get(k);
5174
5172
  }
5175
5173
  }
5176
5174
  if (tov.assocPaths) {
5177
- tov = { ...tov };
5178
5175
  if (!fromv.assocPaths) {
5179
5176
  changes = true;
5180
5177
  delete tov.assocPaths;
@@ -5197,7 +5194,6 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5197
5194
  delete tov.assocPaths;
5198
5195
  }
5199
5196
  }
5200
- to.map.set(k, tov);
5201
5197
  }
5202
5198
  // if both from and to have copyPropEvents, we can only
5203
5199
  // keep it if they're the same event.
@@ -5215,10 +5211,8 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5215
5211
  }
5216
5212
  nodeCopyProp.set(fromv.copyPropItem.event.node, false);
5217
5213
  }
5218
- tov = { ...tov };
5219
5214
  delete tov.copyPropItem;
5220
5215
  changes = true;
5221
- to.map.set(k, tov);
5222
5216
  }
5223
5217
  else {
5224
5218
  assert(k === tov.copyPropItem.event.decl);
@@ -5229,7 +5223,7 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5229
5223
  if (subtypeOf(fromv.curType, tov.curType))
5230
5224
  return;
5231
5225
  if (subtypeOf(tov.curType, fromv.curType)) {
5232
- to.map.set(k, { ...tov, curType: fromv.curType });
5226
+ tov.curType = fromv.curType;
5233
5227
  changes = true;
5234
5228
  return;
5235
5229
  }
@@ -5242,7 +5236,7 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
5242
5236
  if (wide)
5243
5237
  result = wide;
5244
5238
  }
5245
- to.map.set(k, { ...tov, curType: result });
5239
+ tov.curType = result;
5246
5240
  changes = true;
5247
5241
  });
5248
5242
  return changes;
@@ -5267,7 +5261,6 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
5267
5261
  let droppedComponents = null;
5268
5262
  const entry = blockState.map.get(key);
5269
5263
  assert(entry && entry.assocPaths);
5270
- let newEntry = entry;
5271
5264
  entry.assocPaths.forEach((path) => {
5272
5265
  if (key === baseDecl && path === assignedPath) {
5273
5266
  return;
@@ -5286,12 +5279,9 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
5286
5279
  });
5287
5280
  if (pathItem === affectedName && couldBeShallow(type, objectType)) {
5288
5281
  const newAssocKey = assocPath.map((av) => av.name ?? "*").join(".");
5289
- if (newEntry === entry) {
5290
- newEntry = { ...entry };
5291
- }
5292
5282
  if (newAssocKey !== path) {
5293
- newEntry.assocPaths = new Set(newEntry.assocPaths);
5294
- newEntry.assocPaths.delete(path);
5283
+ entry.assocPaths = new Set(entry.assocPaths);
5284
+ entry.assocPaths.delete(path);
5295
5285
  // the "extra" path components will also have entries
5296
5286
  // in blockState.trackedMemberDecls. Since they're gone
5297
5287
  // from here, we (may) need to remove them from there
@@ -5303,8 +5293,7 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
5303
5293
  }
5304
5294
  break;
5305
5295
  }
5306
- const baseType = updateByAssocPath(assocPath, assignedType, true);
5307
- newEntry.curType = baseType;
5296
+ entry.curType = updateByAssocPath(assocPath, assignedType, true);
5308
5297
  break;
5309
5298
  }
5310
5299
  if (pathItem === "*") {
@@ -5334,14 +5323,11 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
5334
5323
  }
5335
5324
  }
5336
5325
  });
5337
- if (newEntry !== entry) {
5338
- if (droppedComponents) {
5339
- newEntry.assocPaths.forEach((path) => path
5340
- .split(".")
5341
- .forEach((pathComponent) => droppedComponents.delete(pathComponent)));
5342
- droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
5343
- }
5344
- blockState.map.set(key, newEntry);
5326
+ if (droppedComponents) {
5327
+ entry.assocPaths.forEach((path) => path
5328
+ .split(".")
5329
+ .forEach((pathComponent) => droppedComponents.delete(pathComponent)));
5330
+ droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
5345
5331
  }
5346
5332
  });
5347
5333
  }
@@ -5448,10 +5434,9 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5448
5434
  const assocKey = assocValue.map((av) => av.name ?? "*").join(".");
5449
5435
  const newType = updateByAssocPath(assocValue, next, false);
5450
5436
  setStateEvent(blockState, decl.base, newType, newValue ? 1 /* UpdateKind.Inner */ : 0 /* UpdateKind.None */);
5451
- const tsv = { ...blockState.map.get(decl.base) };
5437
+ const tsv = blockState.map.get(decl.base);
5452
5438
  tsv.assocPaths = new Set(tsv.assocPaths);
5453
5439
  tsv.assocPaths.add(assocKey);
5454
- blockState.map.set(decl.base, tsv);
5455
5440
  addTrackedMemberDecl(blockState, decl.base, assocKey);
5456
5441
  if (newValue) {
5457
5442
  const baseElem = assocValue[decl.path.length - 1];
@@ -5529,34 +5514,39 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5529
5514
  // that foo is side-effect free, and accesses no globals.
5530
5515
  clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp);
5531
5516
  }
5517
+ const v = blockState.map.get(decl);
5518
+ if (!v) {
5519
+ blockState.map.set(decl, { curType: value });
5520
+ return;
5521
+ }
5532
5522
  if (updateKind !== 2 /* UpdateKind.Reassign */) {
5533
5523
  /*
5534
5524
  * If we're not re-assigning, the equivalencies don't
5535
5525
  * change, so this update must be applied to every
5536
5526
  * element of the set
5537
5527
  */
5538
- const v = blockState.map.get(decl);
5539
- if (v?.equivSet) {
5528
+ if (v.equivSet) {
5540
5529
  v.equivSet.forEach((s) => {
5541
5530
  const next = blockState.map.get(s);
5542
5531
  assert(next && next.equivSet?.has(s));
5543
- blockState.map.set(s, { ...next, curType: value });
5532
+ next.curType = value;
5544
5533
  });
5545
5534
  }
5546
5535
  else {
5547
- blockState.map.set(decl, { ...v, curType: value });
5536
+ v.curType = value;
5548
5537
  }
5549
5538
  }
5550
5539
  else {
5551
- const v = blockState.map.get(decl);
5552
5540
  removeEquiv(blockState.map, decl);
5553
- if (v?.assocPaths?.size) {
5541
+ if (v.assocPaths?.size) {
5554
5542
  clearAssocPaths(blockState, decl, v);
5543
+ delete v.assocPaths;
5555
5544
  }
5556
- if (v?.copyPropItem) {
5545
+ if (v.copyPropItem) {
5557
5546
  copyPropFailed(blockState, v.copyPropItem, nodeCopyProp);
5547
+ delete v.copyPropItem;
5558
5548
  }
5559
- blockState.map.set(decl, { curType: value });
5549
+ v.curType = value;
5560
5550
  }
5561
5551
  return;
5562
5552
  }
@@ -5890,7 +5880,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5890
5880
  break;
5891
5881
  }
5892
5882
  case "ref": {
5893
- let curEntry = getStateEntry(curState, event.decl);
5883
+ const curEntry = getStateEntry(curState, event.decl);
5894
5884
  typeMap.set(event.node, curEntry.curType);
5895
5885
  nodeEquivs.delete(event.node);
5896
5886
  if (curEntry.equivSet) {
@@ -5914,9 +5904,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5914
5904
  nodeCopyProp.set(curEntry.copyPropItem.event.node, event.node);
5915
5905
  }
5916
5906
  clearCopyProp(curState, curEntry.copyPropItem);
5917
- curEntry = { ...curEntry };
5918
5907
  delete curEntry.copyPropItem;
5919
- curState.map.set(event.decl, curEntry);
5920
5908
  }
5921
5909
  else if (declIsNonLocal(event.decl)) {
5922
5910
  clearRelatedCopyPropEvents(curState, null, nodeCopyProp);
@@ -5991,10 +5979,9 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
5991
5979
  setUnionComponent(type, 32768 /* TypeTag.Object */, newData);
5992
5980
  if (tsv.assocPaths) {
5993
5981
  clearAssocPaths(curState, decl, tsv);
5994
- tsv = { ...tsv };
5995
5982
  delete tsv.assocPaths;
5996
5983
  }
5997
- curState.map.set(decl, { ...tsv, curType: type });
5984
+ tsv.curType = type;
5998
5985
  }
5999
5986
  }
6000
5987
  clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
@@ -6019,10 +6006,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
6019
6006
  (event.node.type !== "AssignmentExpression" ||
6020
6007
  event.node.operator !== "=")) {
6021
6008
  copyPropFailed(curState, before.copyPropItem, nodeCopyProp);
6022
- const v = { ...before };
6023
- delete v.copyPropItem;
6024
- assert(isTypeStateKey(event.decl));
6025
- curState.map.set(event.decl, v);
6009
+ delete before.copyPropItem;
6026
6010
  }
6027
6011
  }
6028
6012
  const expr = event.node.type === "VariableDeclarator"
@@ -6717,7 +6701,9 @@ function couldBeObj(a, b) {
6717
6701
  /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5101);
6718
6702
  /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8180);
6719
6703
  /* harmony import */ var _inliner__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(333);
6720
- /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1638);
6704
+ /* harmony import */ var _minimize_locals__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(736);
6705
+ /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(1638);
6706
+
6721
6707
 
6722
6708
 
6723
6709
 
@@ -6985,7 +6971,10 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
6985
6971
  console.log(`${formatAst(dead)} (${sourceLocation(dead.loc)})`));
6986
6972
  }
6987
6973
  let changes = false;
6988
- traverseAst(func.node.body, null, (node, parent) => {
6974
+ traverseAst(func.node.body, null, (node) => {
6975
+ const cleaned = variableCleanup(node);
6976
+ if (cleaned !== null)
6977
+ return cleaned;
6989
6978
  if (node.type === "ExpressionStatement" &&
6990
6979
  node.expression.type === "AssignmentExpression" &&
6991
6980
  deadStores.has(node.expression)) {
@@ -7007,40 +6996,17 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
7007
6996
  changes = true;
7008
6997
  return { type: "Literal", value: null, raw: "null" };
7009
6998
  }
7010
- if (node.type === "VariableDeclaration") {
7011
- const result = [];
7012
- for (let i = 0; i < node.declarations.length; i++) {
7013
- const decl = node.declarations[i];
7014
- if (decl.init && deadStores.has(decl)) {
7015
- const body = unused(state, decl.init);
7016
- if (body.length) {
7017
- if (!parent ||
7018
- (parent.type !== "BlockStatement" && parent.type !== "SwitchCase")) {
7019
- // Must be the init in a for statement. Fixing
7020
- // it would be complicated, so just punt for now.
7021
- break;
7022
- }
7023
- const newDeclaration = withLoc({ ...node }, node, decl.id);
7024
- if (i + 1 < node.declarations.length) {
7025
- newDeclaration.declarations = node.declarations.splice(0, i + 1);
7026
- result.push(newDeclaration);
7027
- withLoc(node, node.declarations[0], node);
7028
- i = -1;
7029
- }
7030
- else {
7031
- result.push(node);
7032
- }
7033
- result.push(...body);
7034
- }
7035
- changes = true;
7036
- delete decl.init;
7037
- }
7038
- }
7039
- if (result.length) {
7040
- if (!result.includes(node)) {
7041
- result.push(node);
6999
+ if (node.type === "VariableDeclarator") {
7000
+ const decl = node;
7001
+ if (decl.init && deadStores.has(decl)) {
7002
+ const body = unused(state, decl.init);
7003
+ delete decl.init;
7004
+ changes = true;
7005
+ if (!body.length) {
7006
+ return null;
7042
7007
  }
7043
- return result;
7008
+ body.unshift(decl);
7009
+ return body;
7044
7010
  }
7045
7011
  }
7046
7012
  return null;
@@ -9339,7 +9305,7 @@ function restrictByEquality(a, b) {
9339
9305
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9340
9306
 
9341
9307
  "use strict";
9342
- /* unused harmony export minimizeLocals */
9308
+ /* unused harmony exports minimizeLocals, variableCleanup */
9343
9309
  /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4143);
9344
9310
  /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_assert__WEBPACK_IMPORTED_MODULE_0__);
9345
9311
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6817);
@@ -9513,11 +9479,6 @@ function minimizeLocals(state, func) {
9513
9479
  return null;
9514
9480
  }
9515
9481
  break;
9516
- case "ExpressionStatement":
9517
- if (node.expression.type === "Literal") {
9518
- return false;
9519
- }
9520
- break;
9521
9482
  case "UpdateExpression":
9522
9483
  if (info) {
9523
9484
  assert(node.argument.type === "Identifier");
@@ -9538,7 +9499,7 @@ function minimizeLocals(state, func) {
9538
9499
  }
9539
9500
  // VariableDeclarations aren't allowed to have
9540
9501
  // AssignmentExpressions in them, but we'll fix that
9541
- // below
9502
+ // via variableCleanup
9542
9503
  return withLoc({
9543
9504
  type: "AssignmentExpression",
9544
9505
  operator: "=",
@@ -9551,79 +9512,297 @@ function minimizeLocals(state, func) {
9551
9512
  }, node, node);
9552
9513
  }
9553
9514
  break;
9554
- case "VariableDeclaration":
9555
- if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
9556
- const results = [];
9557
- node.declarations.forEach((decl) => {
9558
- if (isExpression(decl)) {
9559
- results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
9560
- }
9561
- else if (decl.init) {
9562
- results.push(withLoc({
9563
- type: "ExpressionStatement",
9564
- expression: withLoc({
9565
- type: "AssignmentExpression",
9566
- operator: "=",
9567
- left: withLoc({
9568
- type: "Identifier",
9569
- name: variableDeclarationName(decl.id),
9570
- }, decl.id, decl.id),
9571
- right: decl.init,
9572
- }, decl, decl),
9573
- }, decl, decl));
9574
- }
9575
- });
9576
- node.declarations = node.declarations.filter((decl) => {
9577
- if (decl.type === "VariableDeclarator") {
9578
- delete decl.init;
9579
- return true;
9580
- }
9581
- return false;
9582
- });
9583
- if (node.declarations.length) {
9584
- withLocDeep(node, node, false);
9585
- results.unshift(node);
9515
+ }
9516
+ assert(!info);
9517
+ return variableCleanup(node);
9518
+ });
9519
+ return;
9520
+ }
9521
+ function variableCleanup(node) {
9522
+ switch (node.type) {
9523
+ case "ExpressionStatement":
9524
+ if (node.expression.type === "Literal") {
9525
+ return false;
9526
+ }
9527
+ break;
9528
+ case "VariableDeclaration":
9529
+ if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
9530
+ const results = [];
9531
+ node.declarations.forEach((decl) => {
9532
+ if (isStatement(decl)) {
9533
+ results.push(decl);
9534
+ }
9535
+ else if (isExpression(decl)) {
9536
+ results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
9537
+ }
9538
+ else if (decl.init) {
9539
+ results.push(withLoc({
9540
+ type: "ExpressionStatement",
9541
+ expression: withLoc({
9542
+ type: "AssignmentExpression",
9543
+ operator: "=",
9544
+ left: withLoc({
9545
+ type: "Identifier",
9546
+ name: variableDeclarationName(decl.id),
9547
+ }, decl.id, decl.id),
9548
+ right: decl.init,
9549
+ }, decl, decl),
9550
+ }, decl, decl));
9586
9551
  }
9587
- // if this was the init of a ForStatement, this will
9588
- // replace its init with a BlockStatement, so we have to
9589
- // fix that below.
9590
- return results;
9552
+ });
9553
+ node.declarations = node.declarations.filter((decl) => {
9554
+ if (decl.type === "VariableDeclarator") {
9555
+ delete decl.init;
9556
+ return true;
9557
+ }
9558
+ return false;
9559
+ });
9560
+ if (node.declarations.length) {
9561
+ withLocDeep(node, node, false);
9562
+ results.unshift(node);
9591
9563
  }
9592
- break;
9593
- case "ForStatement":
9594
- if (node.init) {
9595
- if (node.init.type === "BlockStatement") {
9596
- const result = node.init;
9597
- delete node.init;
9598
- result.body.push(node);
9599
- if (node.loc && result.loc) {
9600
- // result has the range of the original VariableDeclaration
9601
- // but now we're moving that ahead of the 'for', so to keep
9602
- // things straight, we need to set the for's start to be
9603
- // where result ended, and result's end to be where the for
9604
- // ends (since that block now encloses the for)
9605
- node.start = result.end;
9606
- node.loc.start = result.loc.end;
9607
- result.end = node.end;
9608
- result.loc.end = node.loc.end;
9564
+ // if this was the init of a ForStatement, this will
9565
+ // replace its init with a BlockStatement, so we have to
9566
+ // fix that below.
9567
+ return results;
9568
+ }
9569
+ break;
9570
+ case "ForStatement":
9571
+ if (node.init) {
9572
+ if (node.init.type === "BlockStatement") {
9573
+ const result = node.init;
9574
+ delete node.init;
9575
+ result.body.push(node);
9576
+ if (node.loc && result.loc) {
9577
+ // result has the range of the original VariableDeclaration
9578
+ // but now we're moving that ahead of the 'for', so to keep
9579
+ // things straight, we need to set the for's start to be
9580
+ // where result ended, and result's end to be where the for
9581
+ // ends (since that block now encloses the for)
9582
+ node.start = result.end;
9583
+ node.loc.start = result.loc.end;
9584
+ result.end = node.end;
9585
+ result.loc.end = node.loc.end;
9586
+ }
9587
+ return result;
9588
+ }
9589
+ if (node.init.type === "Literal") {
9590
+ delete node.init;
9591
+ }
9592
+ }
9593
+ break;
9594
+ case "SequenceExpression":
9595
+ if (node.expressions.some((e) => e.type === "Literal")) {
9596
+ node.expressions = node.expressions.filter((e) => e.type !== "Literal");
9597
+ }
9598
+ break;
9599
+ }
9600
+ return null;
9601
+ }
9602
+
9603
+
9604
+ /***/ }),
9605
+
9606
+ /***/ 4416:
9607
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9608
+
9609
+ "use strict";
9610
+ /* unused harmony export minimizeModules */
9611
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4143);
9612
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_assert__WEBPACK_IMPORTED_MODULE_0__);
9613
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
9614
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6817);
9615
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_2__);
9616
+
9617
+
9618
+
9619
+ function minimizeModules(ast, state) {
9620
+ const { pre, post } = state;
9621
+ try {
9622
+ const replacementMap = new Map();
9623
+ const conflictingNames = new Set();
9624
+ state.pre = (node) => {
9625
+ if (state.inType)
9626
+ return null;
9627
+ switch (node.type) {
9628
+ case "ModuleDeclaration":
9629
+ case "ClassDeclaration":
9630
+ case "FunctionDeclaration":
9631
+ return ["body"];
9632
+ case "Using":
9633
+ conflictingNames.add(node.as?.name ??
9634
+ (node.id.type === "Identifier"
9635
+ ? node.id.name
9636
+ : node.id.property.name));
9637
+ return [];
9638
+ case "ImportModule":
9639
+ conflictingNames.add(node.id.type === "Identifier" ? node.id.name : node.id.property.name);
9640
+ return [];
9641
+ case "Identifier":
9642
+ case "MemberExpression": {
9643
+ let current = node;
9644
+ const parts = [];
9645
+ while (current.type === "MemberExpression" && !current.computed) {
9646
+ parts.unshift(current);
9647
+ current = current.object;
9648
+ }
9649
+ if (current.type !== "Identifier" &&
9650
+ current.type !== "ThisExpression") {
9651
+ break;
9652
+ }
9653
+ let toReplace = null;
9654
+ let module = null;
9655
+ let addImport = false;
9656
+ let [, results] = state.lookupValue(current, null);
9657
+ let i = 0;
9658
+ for (; results &&
9659
+ results.length === 1 &&
9660
+ results[0].results.length === 1 &&
9661
+ (results[0].results[0].type === "Program" ||
9662
+ results[0].results[0].type === "ClassDeclaration" ||
9663
+ results[0].results[0].type === "ModuleDeclaration"); i++) {
9664
+ if (current.type === "Identifier" &&
9665
+ results[0].results[0].type === "ModuleDeclaration" &&
9666
+ isImportCandidate(results[0].results[0])) {
9667
+ const directResults = i
9668
+ ? state.lookupValue(current, null)
9669
+ : results;
9670
+ if (directResults &&
9671
+ directResults.length === 1 &&
9672
+ directResults[0].results.length === 1 &&
9673
+ directResults[0].results[0] === results[0].results[0]) {
9674
+ // we would find the same thing if we just looked up
9675
+ // current directly.
9676
+ toReplace = (i ? parts[i - 1] : current);
9677
+ module = results[0].results[0];
9678
+ if (findUsingForNode(state, state.stack, state.stack.length - 1, current) === directResults[0].results[0]) {
9679
+ // we already find it via an import, so we don't need
9680
+ // a new import.
9681
+ addImport = false;
9682
+ }
9683
+ else {
9684
+ addImport = true;
9685
+ }
9686
+ }
9687
+ else {
9688
+ toReplace = parts[i - 1];
9689
+ module = results[0].results[0];
9690
+ addImport = true;
9691
+ }
9609
9692
  }
9610
- return result;
9693
+ if (i === parts.length)
9694
+ break;
9695
+ current = parts[i].property;
9696
+ results = lookupNext(state, results, "decls", current);
9697
+ }
9698
+ if (toReplace) {
9699
+ assert(module);
9700
+ replacementMap.set(toReplace, { module, addImport });
9701
+ }
9702
+ else if (parts.length === 0) {
9703
+ assert(node.type === "Identifier");
9704
+ conflictingNames.add(node.name);
9611
9705
  }
9612
- if (node.init.type === "Literal") {
9613
- delete node.init;
9706
+ else if (parts[0].object.type === "Identifier") {
9707
+ conflictingNames.add(parts[0].object.name);
9614
9708
  }
9709
+ return [];
9615
9710
  }
9616
- break;
9617
- case "SequenceExpression":
9618
- if (node.expressions.some((e) => e.type === "Literal")) {
9619
- node.expressions = node.expressions.filter((e) => e.type !== "Literal");
9711
+ }
9712
+ return null;
9713
+ };
9714
+ collectNamespaces(ast, state);
9715
+ const mappedNames = new Map();
9716
+ replacementMap.forEach((value, key) => {
9717
+ let name;
9718
+ if (value.addImport) {
9719
+ name = mappedNames.get(value.module);
9720
+ if (!name) {
9721
+ name = value.module.name;
9722
+ for (let i = 0; conflictingNames.has(name); i++) {
9723
+ name = `${value.module.name}_${i}`;
9724
+ }
9725
+ mappedNames.set(value.module, name);
9726
+ conflictingNames.add(name);
9620
9727
  }
9621
- break;
9622
- }
9623
- assert(!info);
9624
- return null;
9728
+ }
9729
+ else {
9730
+ name = key.type === "Identifier" ? key.name : key.property.name;
9731
+ }
9732
+ const original = formatAstLongLines(key);
9733
+ const repl = key;
9734
+ repl.type = "Identifier";
9735
+ repl.name = name;
9736
+ if (name !== original) {
9737
+ repl.original = original;
9738
+ }
9739
+ delete repl.property;
9740
+ delete repl.object;
9741
+ delete repl.computed;
9742
+ });
9743
+ mappedNames.forEach((name, module) => {
9744
+ const id = makeScopedName(module.fullName.slice(2));
9745
+ const as = name !== (id.type === "Identifier" ? id : id.property).name &&
9746
+ makeIdentifier(name);
9747
+ const using = withLocDeep(as ? { type: "Using", id, as } : { type: "Using", id }, ast, false, true);
9748
+ ast.body.unshift(using);
9749
+ });
9750
+ }
9751
+ finally {
9752
+ state.pre = pre;
9753
+ state.post = post;
9754
+ }
9755
+ }
9756
+ /**
9757
+ * There's a bug in garmin's runtime (although the compiler could
9758
+ * work around it). See
9759
+ *
9760
+ * https://forums.garmin.com/developer/connect-iq/i/bug-reports/referencing-an-imported-module-doesn-t-run-its-parent-s-init
9761
+ *
9762
+ * What this means is that if a module's parent isn't `globals`
9763
+ * and it needs to be initialized, then we can't risk
9764
+ * importing it, because the parent module might not get initialized
9765
+ * in time.
9766
+ */
9767
+ function isImportCandidate(module) {
9768
+ if (module.fullName.startsWith("$.Toybox."))
9769
+ return true;
9770
+ if (module.fullName.startsWith("$.Rez."))
9771
+ return false;
9772
+ assert(module.stack);
9773
+ if (module.stack.length === 1)
9774
+ return true;
9775
+ return module.stack.every((elem) => {
9776
+ if (!elem.sn.decls)
9777
+ return false;
9778
+ if (elem.sn.type === "Program")
9779
+ return true;
9780
+ if (elem.sn.type !== "ModuleDeclaration")
9781
+ return false;
9782
+ return Object.values(elem.sn.decls).every((decls) => decls.every((decl) => {
9783
+ if (decl.type !== "VariableDeclarator")
9784
+ return true;
9785
+ if (!decl.node.init)
9786
+ return true;
9787
+ if (decl.node.init.type === "UnaryExpression" &&
9788
+ decl.node.init.operator === ":") {
9789
+ return true;
9790
+ }
9791
+ if (decl.node.init.type !== "Literal")
9792
+ return false;
9793
+ switch (typeof decl.node.init.value) {
9794
+ case "boolean":
9795
+ return true;
9796
+ case "bigint":
9797
+ return false;
9798
+ case "number":
9799
+ return !/[dl]$/i.test(decl.node.init.raw);
9800
+ case "object":
9801
+ return decl.node.init.value === null;
9802
+ }
9803
+ return false;
9804
+ }));
9625
9805
  });
9626
- return;
9627
9806
  }
9628
9807
 
9629
9808