@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.
@@ -6029,7 +6029,7 @@ function pragmaChecker(state, ast, diagnostics) {
6029
6029
  if (kind === "match") {
6030
6030
  const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node)
6031
6031
  .replace(/([\r\n]|\s)+/g, " ")
6032
- .replace(/\b\w+\s\/\*>(\w+)<\*\//g, "$1");
6032
+ .replace(/\b\w+\s\/\*>([\w.]+)<\*\//g, "$1");
6033
6033
  if (!matcher(quote, needle, haystack)) {
6034
6034
  matcher(quote, needle, haystack);
6035
6035
  (0,external_api_cjs_namespaceObject.diagnostic)(state, comment, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
@@ -11183,6 +11183,7 @@ const external_node_assert_namespaceObject = require("node:assert");
11183
11183
 
11184
11184
 
11185
11185
 
11186
+
11186
11187
  function cloneAnt(antMap) {
11187
11188
  return new Map(antMap);
11188
11189
  }
@@ -11443,7 +11444,10 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
11443
11444
  console.log(`${(0,external_api_cjs_namespaceObject.formatAst)(dead)} (${sourceLocation(dead.loc)})`));
11444
11445
  }
11445
11446
  let changes = false;
11446
- (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, null, (node, parent) => {
11447
+ (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, null, (node) => {
11448
+ const cleaned = variableCleanup(node);
11449
+ if (cleaned !== null)
11450
+ return cleaned;
11447
11451
  if (node.type === "ExpressionStatement" &&
11448
11452
  node.expression.type === "AssignmentExpression" &&
11449
11453
  deadStores.has(node.expression)) {
@@ -11465,40 +11469,17 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
11465
11469
  changes = true;
11466
11470
  return { type: "Literal", value: null, raw: "null" };
11467
11471
  }
11468
- if (node.type === "VariableDeclaration") {
11469
- const result = [];
11470
- for (let i = 0; i < node.declarations.length; i++) {
11471
- const decl = node.declarations[i];
11472
- if (decl.init && deadStores.has(decl)) {
11473
- const body = unused(state, decl.init);
11474
- if (body.length) {
11475
- if (!parent ||
11476
- (parent.type !== "BlockStatement" && parent.type !== "SwitchCase")) {
11477
- // Must be the init in a for statement. Fixing
11478
- // it would be complicated, so just punt for now.
11479
- break;
11480
- }
11481
- const newDeclaration = withLoc({ ...node }, node, decl.id);
11482
- if (i + 1 < node.declarations.length) {
11483
- newDeclaration.declarations = node.declarations.splice(0, i + 1);
11484
- result.push(newDeclaration);
11485
- withLoc(node, node.declarations[0], node);
11486
- i = -1;
11487
- }
11488
- else {
11489
- result.push(node);
11490
- }
11491
- result.push(...body);
11492
- }
11493
- changes = true;
11494
- delete decl.init;
11495
- }
11496
- }
11497
- if (result.length) {
11498
- if (!result.includes(node)) {
11499
- result.push(node);
11472
+ if (node.type === "VariableDeclarator") {
11473
+ const decl = node;
11474
+ if (decl.init && deadStores.has(decl)) {
11475
+ const body = unused(state, decl.init);
11476
+ delete decl.init;
11477
+ changes = true;
11478
+ if (!body.length) {
11479
+ return null;
11500
11480
  }
11501
- return result;
11481
+ body.unshift(decl);
11482
+ return body;
11502
11483
  }
11503
11484
  }
11504
11485
  return null;
@@ -11578,8 +11559,8 @@ function buildConflictGraph(state, func) {
11578
11559
  function addEquiv(ts, key, equiv) {
11579
11560
  if (key === equiv)
11580
11561
  return true;
11581
- let keyVal = ts.get(key);
11582
- let equivVal = ts.get(equiv);
11562
+ const keyVal = ts.get(key);
11563
+ const equivVal = ts.get(equiv);
11583
11564
  if (!keyVal || !equivVal)
11584
11565
  return false;
11585
11566
  if (equivVal.equivSet) {
@@ -11591,31 +11572,25 @@ function addEquiv(ts, key, equiv) {
11591
11572
  }
11592
11573
  // equiv is not (or no longer) part of an equivSet
11593
11574
  if (!keyVal.equivSet) {
11594
- keyVal = { ...keyVal };
11595
11575
  keyVal.equivSet = new Set([key, equiv]);
11596
- ts.set(key, keyVal);
11597
11576
  }
11598
11577
  else {
11599
11578
  keyVal.equivSet.add(equiv);
11600
11579
  }
11601
- equivVal = { ...equivVal, equivSet: keyVal.equivSet };
11602
- ts.set(equiv, equivVal);
11580
+ equivVal.equivSet = keyVal.equivSet;
11603
11581
  return false;
11604
11582
  }
11605
11583
  function removeEquiv(ts, equiv) {
11606
- let equivVal = ts.get(equiv);
11584
+ const equivVal = ts.get(equiv);
11607
11585
  if (!equivVal?.equivSet)
11608
11586
  return;
11609
11587
  equivVal.equivSet.delete(equiv);
11610
11588
  if (equivVal.equivSet.size === 1) {
11611
11589
  const other = Array.from(equivVal.equivSet)[0];
11612
- const otherVal = { ...ts.get(other) };
11590
+ const otherVal = ts.get(other);
11613
11591
  delete otherVal.equivSet;
11614
- ts.set(other, otherVal);
11615
11592
  }
11616
- equivVal = { ...equivVal };
11617
11593
  delete equivVal.equivSet;
11618
- ts.set(equiv, equivVal);
11619
11594
  }
11620
11595
  function getEquivSet(ts, k) {
11621
11596
  const keys = ts.get(k)?.equivSet;
@@ -11669,9 +11644,14 @@ function cloneTypeState(blockState) {
11669
11644
  const { map, trackedMemberDecls, liveCopyPropEvents, ...rest } = blockState;
11670
11645
  const clone = { map: new Map(map), ...rest };
11671
11646
  clone.map.forEach((value, key) => {
11672
- if (value.equivSet && key === Array.from(value.equivSet)[0]) {
11673
- const equivSet = new Set(value.equivSet);
11674
- equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
11647
+ if (value.equivSet) {
11648
+ if (key === Array.from(value.equivSet)[0]) {
11649
+ const equivSet = new Set(value.equivSet);
11650
+ equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
11651
+ }
11652
+ }
11653
+ else {
11654
+ clone.map.set(key, { ...value });
11675
11655
  }
11676
11656
  });
11677
11657
  if (trackedMemberDecls) {
@@ -11708,12 +11688,9 @@ function addCopyPropEvent(blockState, item) {
11708
11688
  const liveCopyPropEvents = blockState.liveCopyPropEvents;
11709
11689
  const decl = item.event.decl;
11710
11690
  external_node_assert_namespaceObject(declIsLocal(decl));
11711
- let tov = blockState.map.get(decl);
11691
+ const tov = blockState.map.get(decl);
11712
11692
  external_node_assert_namespaceObject(tov);
11713
- if (tov.copyPropItem !== item) {
11714
- tov = { ...tov, copyPropItem: item };
11715
- blockState.map.set(decl, tov);
11716
- }
11693
+ tov.copyPropItem = item;
11717
11694
  item.contained.forEach((value, key) => {
11718
11695
  const decls = liveCopyPropEvents.get(key);
11719
11696
  if (!decls) {
@@ -11746,15 +11723,13 @@ function clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp) {
11746
11723
  blockState.liveCopyPropEvents
11747
11724
  ?.get(decl)
11748
11725
  ?.forEach((cpDecl) => {
11749
- let value = blockState.map.get(cpDecl);
11726
+ const value = blockState.map.get(cpDecl);
11750
11727
  external_node_assert_namespaceObject(value && value.copyPropItem);
11751
11728
  external_node_assert_namespaceObject(Array.from(value.copyPropItem.contained).some(([key]) => {
11752
11729
  return decl === key;
11753
11730
  }));
11754
11731
  copyPropFailed(blockState, value.copyPropItem, nodeCopyProp);
11755
- value = { ...value };
11756
11732
  delete value.copyPropItem;
11757
- blockState.map.set(cpDecl, value);
11758
11733
  });
11759
11734
  }
11760
11735
  function validateTypeState(curState) {
@@ -11797,11 +11772,9 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11797
11772
  if (tov.equivSet) {
11798
11773
  if (intersectEquiv(to.map, from.map, k)) {
11799
11774
  changes = true;
11800
- tov = to.map.get(k);
11801
11775
  }
11802
11776
  }
11803
11777
  if (tov.assocPaths) {
11804
- tov = { ...tov };
11805
11778
  if (!fromv.assocPaths) {
11806
11779
  changes = true;
11807
11780
  delete tov.assocPaths;
@@ -11824,7 +11797,6 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11824
11797
  delete tov.assocPaths;
11825
11798
  }
11826
11799
  }
11827
- to.map.set(k, tov);
11828
11800
  }
11829
11801
  // if both from and to have copyPropEvents, we can only
11830
11802
  // keep it if they're the same event.
@@ -11842,10 +11814,8 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11842
11814
  }
11843
11815
  nodeCopyProp.set(fromv.copyPropItem.event.node, false);
11844
11816
  }
11845
- tov = { ...tov };
11846
11817
  delete tov.copyPropItem;
11847
11818
  changes = true;
11848
- to.map.set(k, tov);
11849
11819
  }
11850
11820
  else {
11851
11821
  external_node_assert_namespaceObject(k === tov.copyPropItem.event.decl);
@@ -11856,7 +11826,7 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11856
11826
  if (subtypeOf(fromv.curType, tov.curType))
11857
11827
  return;
11858
11828
  if (subtypeOf(tov.curType, fromv.curType)) {
11859
- to.map.set(k, { ...tov, curType: fromv.curType });
11829
+ tov.curType = fromv.curType;
11860
11830
  changes = true;
11861
11831
  return;
11862
11832
  }
@@ -11869,7 +11839,7 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11869
11839
  if (wide)
11870
11840
  result = wide;
11871
11841
  }
11872
- to.map.set(k, { ...tov, curType: result });
11842
+ tov.curType = result;
11873
11843
  changes = true;
11874
11844
  });
11875
11845
  return changes;
@@ -11894,7 +11864,6 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11894
11864
  let droppedComponents = null;
11895
11865
  const entry = blockState.map.get(key);
11896
11866
  external_node_assert_namespaceObject(entry && entry.assocPaths);
11897
- let newEntry = entry;
11898
11867
  entry.assocPaths.forEach((path) => {
11899
11868
  if (key === baseDecl && path === assignedPath) {
11900
11869
  return;
@@ -11913,12 +11882,9 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11913
11882
  });
11914
11883
  if (pathItem === affectedName && couldBeShallow(type, objectType)) {
11915
11884
  const newAssocKey = assocPath.map((av) => av.name ?? "*").join(".");
11916
- if (newEntry === entry) {
11917
- newEntry = { ...entry };
11918
- }
11919
11885
  if (newAssocKey !== path) {
11920
- newEntry.assocPaths = new Set(newEntry.assocPaths);
11921
- newEntry.assocPaths.delete(path);
11886
+ entry.assocPaths = new Set(entry.assocPaths);
11887
+ entry.assocPaths.delete(path);
11922
11888
  // the "extra" path components will also have entries
11923
11889
  // in blockState.trackedMemberDecls. Since they're gone
11924
11890
  // from here, we (may) need to remove them from there
@@ -11930,8 +11896,7 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11930
11896
  }
11931
11897
  break;
11932
11898
  }
11933
- const baseType = updateByAssocPath(assocPath, assignedType, true);
11934
- newEntry.curType = baseType;
11899
+ entry.curType = updateByAssocPath(assocPath, assignedType, true);
11935
11900
  break;
11936
11901
  }
11937
11902
  if (pathItem === "*") {
@@ -11961,14 +11926,11 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11961
11926
  }
11962
11927
  }
11963
11928
  });
11964
- if (newEntry !== entry) {
11965
- if (droppedComponents) {
11966
- newEntry.assocPaths.forEach((path) => path
11967
- .split(".")
11968
- .forEach((pathComponent) => droppedComponents.delete(pathComponent)));
11969
- droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
11970
- }
11971
- blockState.map.set(key, newEntry);
11929
+ if (droppedComponents) {
11930
+ entry.assocPaths.forEach((path) => path
11931
+ .split(".")
11932
+ .forEach((pathComponent) => droppedComponents.delete(pathComponent)));
11933
+ droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
11972
11934
  }
11973
11935
  });
11974
11936
  }
@@ -12075,10 +12037,9 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12075
12037
  const assocKey = assocValue.map((av) => av.name ?? "*").join(".");
12076
12038
  const newType = updateByAssocPath(assocValue, next, false);
12077
12039
  setStateEvent(blockState, decl.base, newType, newValue ? 1 /* UpdateKind.Inner */ : 0 /* UpdateKind.None */);
12078
- const tsv = { ...blockState.map.get(decl.base) };
12040
+ const tsv = blockState.map.get(decl.base);
12079
12041
  tsv.assocPaths = new Set(tsv.assocPaths);
12080
12042
  tsv.assocPaths.add(assocKey);
12081
- blockState.map.set(decl.base, tsv);
12082
12043
  addTrackedMemberDecl(blockState, decl.base, assocKey);
12083
12044
  if (newValue) {
12084
12045
  const baseElem = assocValue[decl.path.length - 1];
@@ -12156,34 +12117,39 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12156
12117
  // that foo is side-effect free, and accesses no globals.
12157
12118
  clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp);
12158
12119
  }
12120
+ const v = blockState.map.get(decl);
12121
+ if (!v) {
12122
+ blockState.map.set(decl, { curType: value });
12123
+ return;
12124
+ }
12159
12125
  if (updateKind !== 2 /* UpdateKind.Reassign */) {
12160
12126
  /*
12161
12127
  * If we're not re-assigning, the equivalencies don't
12162
12128
  * change, so this update must be applied to every
12163
12129
  * element of the set
12164
12130
  */
12165
- const v = blockState.map.get(decl);
12166
- if (v?.equivSet) {
12131
+ if (v.equivSet) {
12167
12132
  v.equivSet.forEach((s) => {
12168
12133
  const next = blockState.map.get(s);
12169
12134
  external_node_assert_namespaceObject(next && next.equivSet?.has(s));
12170
- blockState.map.set(s, { ...next, curType: value });
12135
+ next.curType = value;
12171
12136
  });
12172
12137
  }
12173
12138
  else {
12174
- blockState.map.set(decl, { ...v, curType: value });
12139
+ v.curType = value;
12175
12140
  }
12176
12141
  }
12177
12142
  else {
12178
- const v = blockState.map.get(decl);
12179
12143
  removeEquiv(blockState.map, decl);
12180
- if (v?.assocPaths?.size) {
12144
+ if (v.assocPaths?.size) {
12181
12145
  clearAssocPaths(blockState, decl, v);
12146
+ delete v.assocPaths;
12182
12147
  }
12183
- if (v?.copyPropItem) {
12148
+ if (v.copyPropItem) {
12184
12149
  copyPropFailed(blockState, v.copyPropItem, nodeCopyProp);
12150
+ delete v.copyPropItem;
12185
12151
  }
12186
- blockState.map.set(decl, { curType: value });
12152
+ v.curType = value;
12187
12153
  }
12188
12154
  return;
12189
12155
  }
@@ -12517,7 +12483,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12517
12483
  break;
12518
12484
  }
12519
12485
  case "ref": {
12520
- let curEntry = getStateEntry(curState, event.decl);
12486
+ const curEntry = getStateEntry(curState, event.decl);
12521
12487
  typeMap.set(event.node, curEntry.curType);
12522
12488
  nodeEquivs.delete(event.node);
12523
12489
  if (curEntry.equivSet) {
@@ -12541,9 +12507,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12541
12507
  nodeCopyProp.set(curEntry.copyPropItem.event.node, event.node);
12542
12508
  }
12543
12509
  clearCopyProp(curState, curEntry.copyPropItem);
12544
- curEntry = { ...curEntry };
12545
12510
  delete curEntry.copyPropItem;
12546
- curState.map.set(event.decl, curEntry);
12547
12511
  }
12548
12512
  else if (declIsNonLocal(event.decl)) {
12549
12513
  clearRelatedCopyPropEvents(curState, null, nodeCopyProp);
@@ -12618,10 +12582,9 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12618
12582
  setUnionComponent(type, 32768 /* TypeTag.Object */, newData);
12619
12583
  if (tsv.assocPaths) {
12620
12584
  clearAssocPaths(curState, decl, tsv);
12621
- tsv = { ...tsv };
12622
12585
  delete tsv.assocPaths;
12623
12586
  }
12624
- curState.map.set(decl, { ...tsv, curType: type });
12587
+ tsv.curType = type;
12625
12588
  }
12626
12589
  }
12627
12590
  clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
@@ -12646,10 +12609,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12646
12609
  (event.node.type !== "AssignmentExpression" ||
12647
12610
  event.node.operator !== "=")) {
12648
12611
  copyPropFailed(curState, before.copyPropItem, nodeCopyProp);
12649
- const v = { ...before };
12650
- delete v.copyPropItem;
12651
- external_node_assert_namespaceObject(isTypeStateKey(event.decl));
12652
- curState.map.set(event.decl, v);
12612
+ delete before.copyPropItem;
12653
12613
  }
12654
12614
  }
12655
12615
  const expr = event.node.type === "VariableDeclarator"
@@ -13318,11 +13278,6 @@ function minimizeLocals(state, func) {
13318
13278
  return null;
13319
13279
  }
13320
13280
  break;
13321
- case "ExpressionStatement":
13322
- if (node.expression.type === "Literal") {
13323
- return false;
13324
- }
13325
- break;
13326
13281
  case "UpdateExpression":
13327
13282
  if (info) {
13328
13283
  external_node_assert_namespaceObject(node.argument.type === "Identifier");
@@ -13343,7 +13298,7 @@ function minimizeLocals(state, func) {
13343
13298
  }
13344
13299
  // VariableDeclarations aren't allowed to have
13345
13300
  // AssignmentExpressions in them, but we'll fix that
13346
- // below
13301
+ // via variableCleanup
13347
13302
  return withLoc({
13348
13303
  type: "AssignmentExpression",
13349
13304
  operator: "=",
@@ -13356,79 +13311,92 @@ function minimizeLocals(state, func) {
13356
13311
  }, node, node);
13357
13312
  }
13358
13313
  break;
13359
- case "VariableDeclaration":
13360
- if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
13361
- const results = [];
13362
- node.declarations.forEach((decl) => {
13363
- if (isExpression(decl)) {
13364
- results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
13365
- }
13366
- else if (decl.init) {
13367
- results.push(withLoc({
13368
- type: "ExpressionStatement",
13369
- expression: withLoc({
13370
- type: "AssignmentExpression",
13371
- operator: "=",
13372
- left: withLoc({
13373
- type: "Identifier",
13374
- name: (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id),
13375
- }, decl.id, decl.id),
13376
- right: decl.init,
13377
- }, decl, decl),
13378
- }, decl, decl));
13379
- }
13380
- });
13381
- node.declarations = node.declarations.filter((decl) => {
13382
- if (decl.type === "VariableDeclarator") {
13383
- delete decl.init;
13384
- return true;
13385
- }
13386
- return false;
13387
- });
13388
- if (node.declarations.length) {
13389
- withLocDeep(node, node, false);
13390
- results.unshift(node);
13314
+ }
13315
+ external_node_assert_namespaceObject(!info);
13316
+ return variableCleanup(node);
13317
+ });
13318
+ return;
13319
+ }
13320
+ function variableCleanup(node) {
13321
+ switch (node.type) {
13322
+ case "ExpressionStatement":
13323
+ if (node.expression.type === "Literal") {
13324
+ return false;
13325
+ }
13326
+ break;
13327
+ case "VariableDeclaration":
13328
+ if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
13329
+ const results = [];
13330
+ node.declarations.forEach((decl) => {
13331
+ if (isStatement(decl)) {
13332
+ results.push(decl);
13391
13333
  }
13392
- // if this was the init of a ForStatement, this will
13393
- // replace its init with a BlockStatement, so we have to
13394
- // fix that below.
13395
- return results;
13396
- }
13397
- break;
13398
- case "ForStatement":
13399
- if (node.init) {
13400
- if (node.init.type === "BlockStatement") {
13401
- const result = node.init;
13402
- delete node.init;
13403
- result.body.push(node);
13404
- if (node.loc && result.loc) {
13405
- // result has the range of the original VariableDeclaration
13406
- // but now we're moving that ahead of the 'for', so to keep
13407
- // things straight, we need to set the for's start to be
13408
- // where result ended, and result's end to be where the for
13409
- // ends (since that block now encloses the for)
13410
- node.start = result.end;
13411
- node.loc.start = result.loc.end;
13412
- result.end = node.end;
13413
- result.loc.end = node.loc.end;
13414
- }
13415
- return result;
13334
+ else if (isExpression(decl)) {
13335
+ results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
13416
13336
  }
13417
- if (node.init.type === "Literal") {
13418
- delete node.init;
13337
+ else if (decl.init) {
13338
+ results.push(withLoc({
13339
+ type: "ExpressionStatement",
13340
+ expression: withLoc({
13341
+ type: "AssignmentExpression",
13342
+ operator: "=",
13343
+ left: withLoc({
13344
+ type: "Identifier",
13345
+ name: (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id),
13346
+ }, decl.id, decl.id),
13347
+ right: decl.init,
13348
+ }, decl, decl),
13349
+ }, decl, decl));
13419
13350
  }
13351
+ });
13352
+ node.declarations = node.declarations.filter((decl) => {
13353
+ if (decl.type === "VariableDeclarator") {
13354
+ delete decl.init;
13355
+ return true;
13356
+ }
13357
+ return false;
13358
+ });
13359
+ if (node.declarations.length) {
13360
+ withLocDeep(node, node, false);
13361
+ results.unshift(node);
13420
13362
  }
13421
- break;
13422
- case "SequenceExpression":
13423
- if (node.expressions.some((e) => e.type === "Literal")) {
13424
- node.expressions = node.expressions.filter((e) => e.type !== "Literal");
13363
+ // if this was the init of a ForStatement, this will
13364
+ // replace its init with a BlockStatement, so we have to
13365
+ // fix that below.
13366
+ return results;
13367
+ }
13368
+ break;
13369
+ case "ForStatement":
13370
+ if (node.init) {
13371
+ if (node.init.type === "BlockStatement") {
13372
+ const result = node.init;
13373
+ delete node.init;
13374
+ result.body.push(node);
13375
+ if (node.loc && result.loc) {
13376
+ // result has the range of the original VariableDeclaration
13377
+ // but now we're moving that ahead of the 'for', so to keep
13378
+ // things straight, we need to set the for's start to be
13379
+ // where result ended, and result's end to be where the for
13380
+ // ends (since that block now encloses the for)
13381
+ node.start = result.end;
13382
+ node.loc.start = result.loc.end;
13383
+ result.end = node.end;
13384
+ result.loc.end = node.loc.end;
13385
+ }
13386
+ return result;
13425
13387
  }
13426
- break;
13427
- }
13428
- external_node_assert_namespaceObject(!info);
13429
- return null;
13430
- });
13431
- return;
13388
+ if (node.init.type === "Literal") {
13389
+ delete node.init;
13390
+ }
13391
+ }
13392
+ break;
13393
+ case "SequenceExpression":
13394
+ if (node.expressions.some((e) => e.type === "Literal")) {
13395
+ node.expressions = node.expressions.filter((e) => e.type !== "Literal");
13396
+ }
13397
+ break;
13398
+ }
13399
+ return null;
13432
13400
  }
13433
13401
 
13434
13402
  ;// CONCATENATED MODULE: ./src/pre.ts
@@ -14181,6 +14149,199 @@ function applyReplacements(func, nodeMap, declMap) {
14181
14149
  });
14182
14150
  }
14183
14151
 
14152
+ ;// CONCATENATED MODULE: ./src/type-flow/minimize-modules.ts
14153
+
14154
+
14155
+
14156
+ function minimizeModules(ast, state) {
14157
+ const { pre, post } = state;
14158
+ try {
14159
+ const replacementMap = new Map();
14160
+ const conflictingNames = new Set();
14161
+ state.pre = (node) => {
14162
+ if (state.inType)
14163
+ return null;
14164
+ switch (node.type) {
14165
+ case "ModuleDeclaration":
14166
+ case "ClassDeclaration":
14167
+ case "FunctionDeclaration":
14168
+ return ["body"];
14169
+ case "Using":
14170
+ conflictingNames.add(node.as?.name ??
14171
+ (node.id.type === "Identifier"
14172
+ ? node.id.name
14173
+ : node.id.property.name));
14174
+ return [];
14175
+ case "ImportModule":
14176
+ conflictingNames.add(node.id.type === "Identifier" ? node.id.name : node.id.property.name);
14177
+ return [];
14178
+ case "Identifier":
14179
+ case "MemberExpression": {
14180
+ let current = node;
14181
+ const parts = [];
14182
+ while (current.type === "MemberExpression" && !current.computed) {
14183
+ parts.unshift(current);
14184
+ current = current.object;
14185
+ }
14186
+ if (current.type !== "Identifier" &&
14187
+ current.type !== "ThisExpression") {
14188
+ break;
14189
+ }
14190
+ let toReplace = null;
14191
+ let module = null;
14192
+ let addImport = false;
14193
+ let [, results] = state.lookupValue(current, null);
14194
+ let i = 0;
14195
+ for (; results &&
14196
+ results.length === 1 &&
14197
+ results[0].results.length === 1 &&
14198
+ (results[0].results[0].type === "Program" ||
14199
+ results[0].results[0].type === "ClassDeclaration" ||
14200
+ results[0].results[0].type === "ModuleDeclaration"); i++) {
14201
+ if (current.type === "Identifier" &&
14202
+ results[0].results[0].type === "ModuleDeclaration" &&
14203
+ isImportCandidate(results[0].results[0])) {
14204
+ const directResults = i
14205
+ ? state.lookupValue(current, null)
14206
+ : results;
14207
+ if (directResults &&
14208
+ directResults.length === 1 &&
14209
+ directResults[0].results.length === 1 &&
14210
+ directResults[0].results[0] === results[0].results[0]) {
14211
+ // we would find the same thing if we just looked up
14212
+ // current directly.
14213
+ toReplace = (i ? parts[i - 1] : current);
14214
+ module = results[0].results[0];
14215
+ if ((0,external_api_cjs_namespaceObject.findUsingForNode)(state, state.stack, state.stack.length - 1, current) === directResults[0].results[0]) {
14216
+ // we already find it via an import, so we don't need
14217
+ // a new import.
14218
+ addImport = false;
14219
+ }
14220
+ else {
14221
+ addImport = true;
14222
+ }
14223
+ }
14224
+ else {
14225
+ toReplace = parts[i - 1];
14226
+ module = results[0].results[0];
14227
+ addImport = true;
14228
+ }
14229
+ }
14230
+ if (i === parts.length)
14231
+ break;
14232
+ current = parts[i].property;
14233
+ results = (0,external_api_cjs_namespaceObject.lookupNext)(state, results, "decls", current);
14234
+ }
14235
+ if (toReplace) {
14236
+ external_node_assert_namespaceObject(module);
14237
+ replacementMap.set(toReplace, { module, addImport });
14238
+ }
14239
+ else if (parts.length === 0) {
14240
+ external_node_assert_namespaceObject(node.type === "Identifier");
14241
+ conflictingNames.add(node.name);
14242
+ }
14243
+ else if (parts[0].object.type === "Identifier") {
14244
+ conflictingNames.add(parts[0].object.name);
14245
+ }
14246
+ return [];
14247
+ }
14248
+ }
14249
+ return null;
14250
+ };
14251
+ (0,external_api_cjs_namespaceObject.collectNamespaces)(ast, state);
14252
+ const mappedNames = new Map();
14253
+ replacementMap.forEach((value, key) => {
14254
+ let name;
14255
+ if (value.addImport) {
14256
+ name = mappedNames.get(value.module);
14257
+ if (!name) {
14258
+ name = value.module.name;
14259
+ for (let i = 0; conflictingNames.has(name); i++) {
14260
+ name = `${value.module.name}_${i}`;
14261
+ }
14262
+ mappedNames.set(value.module, name);
14263
+ conflictingNames.add(name);
14264
+ }
14265
+ }
14266
+ else {
14267
+ name = key.type === "Identifier" ? key.name : key.property.name;
14268
+ }
14269
+ const original = (0,external_api_cjs_namespaceObject.formatAstLongLines)(key);
14270
+ const repl = key;
14271
+ repl.type = "Identifier";
14272
+ repl.name = name;
14273
+ if (name !== original) {
14274
+ repl.original = original;
14275
+ }
14276
+ delete repl.property;
14277
+ delete repl.object;
14278
+ delete repl.computed;
14279
+ });
14280
+ mappedNames.forEach((name, module) => {
14281
+ const id = makeScopedName(module.fullName.slice(2));
14282
+ const as = name !== (id.type === "Identifier" ? id : id.property).name &&
14283
+ makeIdentifier(name);
14284
+ const using = withLocDeep(as ? { type: "Using", id, as } : { type: "Using", id }, ast, false, true);
14285
+ ast.body.unshift(using);
14286
+ });
14287
+ }
14288
+ finally {
14289
+ state.pre = pre;
14290
+ state.post = post;
14291
+ }
14292
+ }
14293
+ /**
14294
+ * There's a bug in garmin's runtime (although the compiler could
14295
+ * work around it). See
14296
+ *
14297
+ * https://forums.garmin.com/developer/connect-iq/i/bug-reports/referencing-an-imported-module-doesn-t-run-its-parent-s-init
14298
+ *
14299
+ * What this means is that if a module's parent isn't `globals`
14300
+ * and it needs to be initialized, then we can't risk
14301
+ * importing it, because the parent module might not get initialized
14302
+ * in time.
14303
+ */
14304
+ function isImportCandidate(module) {
14305
+ if (module.fullName.startsWith("$.Toybox."))
14306
+ return true;
14307
+ if (module.fullName.startsWith("$.Rez."))
14308
+ return false;
14309
+ external_node_assert_namespaceObject(module.stack);
14310
+ if (module.stack.length === 1)
14311
+ return true;
14312
+ return module.stack.every((elem) => {
14313
+ if (!elem.sn.decls)
14314
+ return false;
14315
+ if (elem.sn.type === "Program")
14316
+ return true;
14317
+ if (elem.sn.type !== "ModuleDeclaration")
14318
+ return false;
14319
+ return Object.values(elem.sn.decls).every((decls) => decls.every((decl) => {
14320
+ if (decl.type !== "VariableDeclarator")
14321
+ return true;
14322
+ if (!decl.node.init)
14323
+ return true;
14324
+ if (decl.node.init.type === "UnaryExpression" &&
14325
+ decl.node.init.operator === ":") {
14326
+ return true;
14327
+ }
14328
+ if (decl.node.init.type !== "Literal")
14329
+ return false;
14330
+ switch (typeof decl.node.init.value) {
14331
+ case "boolean":
14332
+ return true;
14333
+ case "bigint":
14334
+ return false;
14335
+ case "number":
14336
+ return !/[dl]$/i.test(decl.node.init.raw);
14337
+ case "object":
14338
+ return decl.node.init.value === null;
14339
+ }
14340
+ return false;
14341
+ }));
14342
+ });
14343
+ }
14344
+
14184
14345
  ;// CONCATENATED MODULE: ./src/type-flow/optimize.ts
14185
14346
 
14186
14347
 
@@ -15031,6 +15192,7 @@ function cleanupUnusedVars(state, node) {
15031
15192
 
15032
15193
 
15033
15194
 
15195
+
15034
15196
  /*
15035
15197
  * Map each name to the list of StateNodes that declare that
15036
15198
  * name (excluding Functions, which are already in allFunctions)
@@ -15618,32 +15780,30 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
15618
15780
  break;
15619
15781
  case "Identifier": {
15620
15782
  const map = topLocals().map;
15621
- if (map) {
15622
- if ((0,external_api_cjs_namespaceObject.hasProperty)(map, node.name)) {
15623
- const name = map[node.name];
15624
- if (typeof name === "string") {
15625
- renameIdentifier(node, name);
15783
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(map, node.name)) {
15784
+ const name = map[node.name];
15785
+ if (typeof name === "string") {
15786
+ renameIdentifier(node, name);
15787
+ }
15788
+ const [, results] = state.lookupValue(node);
15789
+ if (results) {
15790
+ if (results.length !== 1 || results[0].results.length !== 1) {
15791
+ throw new Error(`Local ${node.name} had multiple lookup results`);
15626
15792
  }
15627
- const [, results] = state.lookupValue(node);
15628
- if (results) {
15629
- if (results.length !== 1 || results[0].results.length !== 1) {
15630
- throw new Error(`Local ${node.name} had multiple lookup results`);
15631
- }
15632
- const parent = results[0].parent;
15633
- if (!parent) {
15634
- throw new Error(`Local ${node.name} had no parent`);
15635
- }
15636
- const decl = results[0].results[0];
15637
- if (parent.type === "FunctionDeclaration" ||
15638
- decl.type !== "VariableDeclarator") {
15639
- // we can't optimize away function or catch parameters
15640
- return [];
15641
- }
15642
- if (parent.type !== "BlockStatement") {
15643
- throw new Error(`Local ${node.name} was not declared at block scope(??)`);
15644
- }
15645
- decl.used = true;
15793
+ const parent = results[0].parent;
15794
+ if (!parent) {
15795
+ throw new Error(`Local ${node.name} had no parent`);
15796
+ }
15797
+ const decl = results[0].results[0];
15798
+ if (parent.type === "FunctionDeclaration" ||
15799
+ decl.type !== "VariableDeclarator") {
15800
+ // we can't optimize away function or catch parameters
15801
+ return [];
15802
+ }
15803
+ if (parent.type !== "BlockStatement") {
15804
+ throw new Error(`Local ${node.name} was not declared at block scope(??)`);
15646
15805
  }
15806
+ decl.used = true;
15647
15807
  }
15648
15808
  }
15649
15809
  return [];
@@ -15931,6 +16091,11 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
15931
16091
  state.nextExposed = {};
15932
16092
  delete state.pre;
15933
16093
  delete state.post;
16094
+ if (state.config?.minimizeModules ?? true) {
16095
+ Object.values(fnMap).forEach((f) => {
16096
+ minimizeModules(f.ast, state);
16097
+ });
16098
+ }
15934
16099
  Object.values(state.allFunctions).forEach((fns) => fns.forEach((fn) => sizeBasedPRE(state, fn)));
15935
16100
  const cleanup = (node) => {
15936
16101
  switch (node.type) {
@@ -16576,6 +16741,7 @@ const configOptionsToCheck = [
16576
16741
  "propagateTypes",
16577
16742
  "singleUseCopyProp",
16578
16743
  "minimizeLocals",
16744
+ "minimizeModules",
16579
16745
  "extensionVersion",
16580
16746
  "typeCheckLevel",
16581
16747
  "covarianceWarnings",
@@ -16637,7 +16803,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
16637
16803
  // the oldest optimized file, we don't need to regenerate
16638
16804
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
16639
16805
  const opt_time = await (0,external_util_cjs_namespaceObject.first_modified)(Object.values(fnMap).map((v) => v.output));
16640
- if (source_time < opt_time && 1676156189652 < opt_time) {
16806
+ if (source_time < opt_time && 1676335488374 < opt_time) {
16641
16807
  return { hasTests, diagnostics: prevDiagnostics };
16642
16808
  }
16643
16809
  }
@@ -16664,7 +16830,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
16664
16830
  return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
16665
16831
  hasTests,
16666
16832
  diagnostics,
16667
- optimizerVersion: "1.1.12",
16833
+ optimizerVersion: "1.1.13",
16668
16834
  ...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
16669
16835
  }))
16670
16836
  .then(() => ({ hasTests, diagnostics }));