@markw65/monkeyc-optimizer 1.1.12 → 1.1.14

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.
@@ -1,4 +1,4 @@
1
- 0 && (module.exports = {buildOptimizedProject,copyRecursiveAsNeeded,defaultConfig,display,generateApiMirTests,generateOptimizedProject,getProjectAnalysis,get_jungle,isErrorWithLocation,launchSimulator,manifestProducts,mctree,simulateProgram});
1
+ 0 && (module.exports = {buildOptimizedProject,copyRecursiveAsNeeded,defaultConfig,display,generateApiMirTests,generateOptimizedProject,getConfig,getProjectAnalysis,get_jungle,isErrorWithLocation,launchSimulator,manifestProducts,mctree,simulateProgram});
2
2
  /******/ (() => { // webpackBootstrap
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
@@ -3416,6 +3416,7 @@ __webpack_require__.d(__webpack_exports__, {
3416
3416
  "display": () => (/* reexport */ display),
3417
3417
  "generateApiMirTests": () => (/* binding */ generateApiMirTests),
3418
3418
  "generateOptimizedProject": () => (/* binding */ generateOptimizedProject),
3419
+ "getConfig": () => (/* binding */ getConfig),
3419
3420
  "getProjectAnalysis": () => (/* binding */ getProjectAnalysis),
3420
3421
  "get_jungle": () => (/* reexport */ get_jungle),
3421
3422
  "isErrorWithLocation": () => (/* binding */ isErrorWithLocation),
@@ -4523,7 +4524,13 @@ async function launchSimulator(force = true) {
4523
4524
  if (!force && (await checkIfSimulatorRunning()))
4524
4525
  return;
4525
4526
  const sdk = await (0,external_sdk_util_cjs_namespaceObject.getSdkPath)();
4526
- const child = (0,external_child_process_namespaceObject.execFile)(external_path_.resolve(sdk, "bin", external_sdk_util_cjs_namespaceObject.isWin ? "simulator" : "connectiq"));
4527
+ const child = force || process.platform !== "darwin"
4528
+ ? (0,external_child_process_namespaceObject.execFile)(external_path_.resolve(sdk, "bin", external_sdk_util_cjs_namespaceObject.isWin ? "simulator" : "connectiq"))
4529
+ : (0,external_child_process_namespaceObject.execFile)("/usr/bin/open", [
4530
+ "-g",
4531
+ "-a",
4532
+ external_path_.resolve(sdk, "bin", "ConnectIQ.App", "Contents/MacOS/simulator"),
4533
+ ]);
4527
4534
  child.unref();
4528
4535
  for (let i = 0;; i++) {
4529
4536
  if (await checkIfSimulatorRunning())
@@ -5380,8 +5387,9 @@ function inlineRequested(state, func) {
5380
5387
  return false;
5381
5388
  }
5382
5389
  function shouldInline(state, func, call, context) {
5383
- if (state.inlining)
5390
+ if (state.inlining || (state.localsStack?.length ?? 0) <= 1) {
5384
5391
  return false;
5392
+ }
5385
5393
  let autoInline = false;
5386
5394
  let inlineAsExpression = false;
5387
5395
  const args = call.arguments;
@@ -6029,7 +6037,7 @@ function pragmaChecker(state, ast, diagnostics) {
6029
6037
  if (kind === "match") {
6030
6038
  const haystack = (0,external_api_cjs_namespaceObject.formatAst)(node)
6031
6039
  .replace(/([\r\n]|\s)+/g, " ")
6032
- .replace(/\b\w+\s\/\*>(\w+)<\*\//g, "$1");
6040
+ .replace(/\b\w+\s\/\*>([\w.]+)<\*\//g, "$1");
6033
6041
  if (!matcher(quote, needle, haystack)) {
6034
6042
  matcher(quote, needle, haystack);
6035
6043
  (0,external_api_cjs_namespaceObject.diagnostic)(state, comment, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
@@ -11183,6 +11191,7 @@ const external_node_assert_namespaceObject = require("node:assert");
11183
11191
 
11184
11192
 
11185
11193
 
11194
+
11186
11195
  function cloneAnt(antMap) {
11187
11196
  return new Map(antMap);
11188
11197
  }
@@ -11443,7 +11452,10 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
11443
11452
  console.log(`${(0,external_api_cjs_namespaceObject.formatAst)(dead)} (${sourceLocation(dead.loc)})`));
11444
11453
  }
11445
11454
  let changes = false;
11446
- (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, null, (node, parent) => {
11455
+ (0,external_api_cjs_namespaceObject.traverseAst)(func.node.body, null, (node) => {
11456
+ const cleaned = variableCleanup(node);
11457
+ if (cleaned !== null)
11458
+ return cleaned;
11447
11459
  if (node.type === "ExpressionStatement" &&
11448
11460
  node.expression.type === "AssignmentExpression" &&
11449
11461
  deadStores.has(node.expression)) {
@@ -11465,40 +11477,17 @@ function eliminateDeadStores(state, func, graph, logThisRun) {
11465
11477
  changes = true;
11466
11478
  return { type: "Literal", value: null, raw: "null" };
11467
11479
  }
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);
11480
+ if (node.type === "VariableDeclarator") {
11481
+ const decl = node;
11482
+ if (decl.init && deadStores.has(decl)) {
11483
+ const body = unused(state, decl.init);
11484
+ delete decl.init;
11485
+ changes = true;
11486
+ if (!body.length) {
11487
+ return null;
11500
11488
  }
11501
- return result;
11489
+ body.unshift(decl);
11490
+ return body;
11502
11491
  }
11503
11492
  }
11504
11493
  return null;
@@ -11578,8 +11567,8 @@ function buildConflictGraph(state, func) {
11578
11567
  function addEquiv(ts, key, equiv) {
11579
11568
  if (key === equiv)
11580
11569
  return true;
11581
- let keyVal = ts.get(key);
11582
- let equivVal = ts.get(equiv);
11570
+ const keyVal = ts.get(key);
11571
+ const equivVal = ts.get(equiv);
11583
11572
  if (!keyVal || !equivVal)
11584
11573
  return false;
11585
11574
  if (equivVal.equivSet) {
@@ -11591,31 +11580,25 @@ function addEquiv(ts, key, equiv) {
11591
11580
  }
11592
11581
  // equiv is not (or no longer) part of an equivSet
11593
11582
  if (!keyVal.equivSet) {
11594
- keyVal = { ...keyVal };
11595
11583
  keyVal.equivSet = new Set([key, equiv]);
11596
- ts.set(key, keyVal);
11597
11584
  }
11598
11585
  else {
11599
11586
  keyVal.equivSet.add(equiv);
11600
11587
  }
11601
- equivVal = { ...equivVal, equivSet: keyVal.equivSet };
11602
- ts.set(equiv, equivVal);
11588
+ equivVal.equivSet = keyVal.equivSet;
11603
11589
  return false;
11604
11590
  }
11605
11591
  function removeEquiv(ts, equiv) {
11606
- let equivVal = ts.get(equiv);
11592
+ const equivVal = ts.get(equiv);
11607
11593
  if (!equivVal?.equivSet)
11608
11594
  return;
11609
11595
  equivVal.equivSet.delete(equiv);
11610
11596
  if (equivVal.equivSet.size === 1) {
11611
11597
  const other = Array.from(equivVal.equivSet)[0];
11612
- const otherVal = { ...ts.get(other) };
11598
+ const otherVal = ts.get(other);
11613
11599
  delete otherVal.equivSet;
11614
- ts.set(other, otherVal);
11615
11600
  }
11616
- equivVal = { ...equivVal };
11617
11601
  delete equivVal.equivSet;
11618
- ts.set(equiv, equivVal);
11619
11602
  }
11620
11603
  function getEquivSet(ts, k) {
11621
11604
  const keys = ts.get(k)?.equivSet;
@@ -11669,9 +11652,14 @@ function cloneTypeState(blockState) {
11669
11652
  const { map, trackedMemberDecls, liveCopyPropEvents, ...rest } = blockState;
11670
11653
  const clone = { map: new Map(map), ...rest };
11671
11654
  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 }));
11655
+ if (value.equivSet) {
11656
+ if (key === Array.from(value.equivSet)[0]) {
11657
+ const equivSet = new Set(value.equivSet);
11658
+ equivSet.forEach((k) => clone.map.set(k, { ...clone.map.get(k), equivSet }));
11659
+ }
11660
+ }
11661
+ else {
11662
+ clone.map.set(key, { ...value });
11675
11663
  }
11676
11664
  });
11677
11665
  if (trackedMemberDecls) {
@@ -11708,12 +11696,9 @@ function addCopyPropEvent(blockState, item) {
11708
11696
  const liveCopyPropEvents = blockState.liveCopyPropEvents;
11709
11697
  const decl = item.event.decl;
11710
11698
  external_node_assert_namespaceObject(declIsLocal(decl));
11711
- let tov = blockState.map.get(decl);
11699
+ const tov = blockState.map.get(decl);
11712
11700
  external_node_assert_namespaceObject(tov);
11713
- if (tov.copyPropItem !== item) {
11714
- tov = { ...tov, copyPropItem: item };
11715
- blockState.map.set(decl, tov);
11716
- }
11701
+ tov.copyPropItem = item;
11717
11702
  item.contained.forEach((value, key) => {
11718
11703
  const decls = liveCopyPropEvents.get(key);
11719
11704
  if (!decls) {
@@ -11746,15 +11731,13 @@ function clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp) {
11746
11731
  blockState.liveCopyPropEvents
11747
11732
  ?.get(decl)
11748
11733
  ?.forEach((cpDecl) => {
11749
- let value = blockState.map.get(cpDecl);
11734
+ const value = blockState.map.get(cpDecl);
11750
11735
  external_node_assert_namespaceObject(value && value.copyPropItem);
11751
11736
  external_node_assert_namespaceObject(Array.from(value.copyPropItem.contained).some(([key]) => {
11752
11737
  return decl === key;
11753
11738
  }));
11754
11739
  copyPropFailed(blockState, value.copyPropItem, nodeCopyProp);
11755
- value = { ...value };
11756
11740
  delete value.copyPropItem;
11757
- blockState.map.set(cpDecl, value);
11758
11741
  });
11759
11742
  }
11760
11743
  function validateTypeState(curState) {
@@ -11797,11 +11780,9 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11797
11780
  if (tov.equivSet) {
11798
11781
  if (intersectEquiv(to.map, from.map, k)) {
11799
11782
  changes = true;
11800
- tov = to.map.get(k);
11801
11783
  }
11802
11784
  }
11803
11785
  if (tov.assocPaths) {
11804
- tov = { ...tov };
11805
11786
  if (!fromv.assocPaths) {
11806
11787
  changes = true;
11807
11788
  delete tov.assocPaths;
@@ -11824,7 +11805,6 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11824
11805
  delete tov.assocPaths;
11825
11806
  }
11826
11807
  }
11827
- to.map.set(k, tov);
11828
11808
  }
11829
11809
  // if both from and to have copyPropEvents, we can only
11830
11810
  // keep it if they're the same event.
@@ -11842,10 +11822,8 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11842
11822
  }
11843
11823
  nodeCopyProp.set(fromv.copyPropItem.event.node, false);
11844
11824
  }
11845
- tov = { ...tov };
11846
11825
  delete tov.copyPropItem;
11847
11826
  changes = true;
11848
- to.map.set(k, tov);
11849
11827
  }
11850
11828
  else {
11851
11829
  external_node_assert_namespaceObject(k === tov.copyPropItem.event.decl);
@@ -11856,7 +11834,7 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11856
11834
  if (subtypeOf(fromv.curType, tov.curType))
11857
11835
  return;
11858
11836
  if (subtypeOf(tov.curType, fromv.curType)) {
11859
- to.map.set(k, { ...tov, curType: fromv.curType });
11837
+ tov.curType = fromv.curType;
11860
11838
  changes = true;
11861
11839
  return;
11862
11840
  }
@@ -11869,7 +11847,7 @@ function mergeTypeState(blockStates, index, from, nodeCopyProp) {
11869
11847
  if (wide)
11870
11848
  result = wide;
11871
11849
  }
11872
- to.map.set(k, { ...tov, curType: result });
11850
+ tov.curType = result;
11873
11851
  changes = true;
11874
11852
  });
11875
11853
  return changes;
@@ -11894,7 +11872,6 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11894
11872
  let droppedComponents = null;
11895
11873
  const entry = blockState.map.get(key);
11896
11874
  external_node_assert_namespaceObject(entry && entry.assocPaths);
11897
- let newEntry = entry;
11898
11875
  entry.assocPaths.forEach((path) => {
11899
11876
  if (key === baseDecl && path === assignedPath) {
11900
11877
  return;
@@ -11913,12 +11890,9 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11913
11890
  });
11914
11891
  if (pathItem === affectedName && couldBeShallow(type, objectType)) {
11915
11892
  const newAssocKey = assocPath.map((av) => av.name ?? "*").join(".");
11916
- if (newEntry === entry) {
11917
- newEntry = { ...entry };
11918
- }
11919
11893
  if (newAssocKey !== path) {
11920
- newEntry.assocPaths = new Set(newEntry.assocPaths);
11921
- newEntry.assocPaths.delete(path);
11894
+ entry.assocPaths = new Set(entry.assocPaths);
11895
+ entry.assocPaths.delete(path);
11922
11896
  // the "extra" path components will also have entries
11923
11897
  // in blockState.trackedMemberDecls. Since they're gone
11924
11898
  // from here, we (may) need to remove them from there
@@ -11930,8 +11904,7 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11930
11904
  }
11931
11905
  break;
11932
11906
  }
11933
- const baseType = updateByAssocPath(assocPath, assignedType, true);
11934
- newEntry.curType = baseType;
11907
+ entry.curType = updateByAssocPath(assocPath, assignedType, true);
11935
11908
  break;
11936
11909
  }
11937
11910
  if (pathItem === "*") {
@@ -11961,14 +11934,11 @@ function updateAffected(blockState, objectType, baseDecl, assignedPath, affected
11961
11934
  }
11962
11935
  }
11963
11936
  });
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);
11937
+ if (droppedComponents) {
11938
+ entry.assocPaths.forEach((path) => path
11939
+ .split(".")
11940
+ .forEach((pathComponent) => droppedComponents.delete(pathComponent)));
11941
+ droppedComponents.forEach((pathComponent) => blockState.trackedMemberDecls.get(pathComponent).delete(key));
11972
11942
  }
11973
11943
  });
11974
11944
  }
@@ -12075,10 +12045,9 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12075
12045
  const assocKey = assocValue.map((av) => av.name ?? "*").join(".");
12076
12046
  const newType = updateByAssocPath(assocValue, next, false);
12077
12047
  setStateEvent(blockState, decl.base, newType, newValue ? 1 /* UpdateKind.Inner */ : 0 /* UpdateKind.None */);
12078
- const tsv = { ...blockState.map.get(decl.base) };
12048
+ const tsv = blockState.map.get(decl.base);
12079
12049
  tsv.assocPaths = new Set(tsv.assocPaths);
12080
12050
  tsv.assocPaths.add(assocKey);
12081
- blockState.map.set(decl.base, tsv);
12082
12051
  addTrackedMemberDecl(blockState, decl.base, assocKey);
12083
12052
  if (newValue) {
12084
12053
  const baseElem = assocValue[decl.path.length - 1];
@@ -12156,34 +12125,39 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12156
12125
  // that foo is side-effect free, and accesses no globals.
12157
12126
  clearRelatedCopyPropEvents(blockState, decl, nodeCopyProp);
12158
12127
  }
12128
+ const v = blockState.map.get(decl);
12129
+ if (!v) {
12130
+ blockState.map.set(decl, { curType: value });
12131
+ return;
12132
+ }
12159
12133
  if (updateKind !== 2 /* UpdateKind.Reassign */) {
12160
12134
  /*
12161
12135
  * If we're not re-assigning, the equivalencies don't
12162
12136
  * change, so this update must be applied to every
12163
12137
  * element of the set
12164
12138
  */
12165
- const v = blockState.map.get(decl);
12166
- if (v?.equivSet) {
12139
+ if (v.equivSet) {
12167
12140
  v.equivSet.forEach((s) => {
12168
12141
  const next = blockState.map.get(s);
12169
12142
  external_node_assert_namespaceObject(next && next.equivSet?.has(s));
12170
- blockState.map.set(s, { ...next, curType: value });
12143
+ next.curType = value;
12171
12144
  });
12172
12145
  }
12173
12146
  else {
12174
- blockState.map.set(decl, { ...v, curType: value });
12147
+ v.curType = value;
12175
12148
  }
12176
12149
  }
12177
12150
  else {
12178
- const v = blockState.map.get(decl);
12179
12151
  removeEquiv(blockState.map, decl);
12180
- if (v?.assocPaths?.size) {
12152
+ if (v.assocPaths?.size) {
12181
12153
  clearAssocPaths(blockState, decl, v);
12154
+ delete v.assocPaths;
12182
12155
  }
12183
- if (v?.copyPropItem) {
12156
+ if (v.copyPropItem) {
12184
12157
  copyPropFailed(blockState, v.copyPropItem, nodeCopyProp);
12158
+ delete v.copyPropItem;
12185
12159
  }
12186
- blockState.map.set(decl, { curType: value });
12160
+ v.curType = value;
12187
12161
  }
12188
12162
  return;
12189
12163
  }
@@ -12517,7 +12491,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12517
12491
  break;
12518
12492
  }
12519
12493
  case "ref": {
12520
- let curEntry = getStateEntry(curState, event.decl);
12494
+ const curEntry = getStateEntry(curState, event.decl);
12521
12495
  typeMap.set(event.node, curEntry.curType);
12522
12496
  nodeEquivs.delete(event.node);
12523
12497
  if (curEntry.equivSet) {
@@ -12541,9 +12515,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12541
12515
  nodeCopyProp.set(curEntry.copyPropItem.event.node, event.node);
12542
12516
  }
12543
12517
  clearCopyProp(curState, curEntry.copyPropItem);
12544
- curEntry = { ...curEntry };
12545
12518
  delete curEntry.copyPropItem;
12546
- curState.map.set(event.decl, curEntry);
12547
12519
  }
12548
12520
  else if (declIsNonLocal(event.decl)) {
12549
12521
  clearRelatedCopyPropEvents(curState, null, nodeCopyProp);
@@ -12618,10 +12590,9 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12618
12590
  setUnionComponent(type, 32768 /* TypeTag.Object */, newData);
12619
12591
  if (tsv.assocPaths) {
12620
12592
  clearAssocPaths(curState, decl, tsv);
12621
- tsv = { ...tsv };
12622
12593
  delete tsv.assocPaths;
12623
12594
  }
12624
- curState.map.set(decl, { ...tsv, curType: type });
12595
+ tsv.curType = type;
12625
12596
  }
12626
12597
  }
12627
12598
  clearRelatedCopyPropEvents(curState, decl, nodeCopyProp);
@@ -12646,10 +12617,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, copyPropStore
12646
12617
  (event.node.type !== "AssignmentExpression" ||
12647
12618
  event.node.operator !== "=")) {
12648
12619
  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);
12620
+ delete before.copyPropItem;
12653
12621
  }
12654
12622
  }
12655
12623
  const expr = event.node.type === "VariableDeclarator"
@@ -13318,11 +13286,6 @@ function minimizeLocals(state, func) {
13318
13286
  return null;
13319
13287
  }
13320
13288
  break;
13321
- case "ExpressionStatement":
13322
- if (node.expression.type === "Literal") {
13323
- return false;
13324
- }
13325
- break;
13326
13289
  case "UpdateExpression":
13327
13290
  if (info) {
13328
13291
  external_node_assert_namespaceObject(node.argument.type === "Identifier");
@@ -13343,7 +13306,7 @@ function minimizeLocals(state, func) {
13343
13306
  }
13344
13307
  // VariableDeclarations aren't allowed to have
13345
13308
  // AssignmentExpressions in them, but we'll fix that
13346
- // below
13309
+ // via variableCleanup
13347
13310
  return withLoc({
13348
13311
  type: "AssignmentExpression",
13349
13312
  operator: "=",
@@ -13356,79 +13319,92 @@ function minimizeLocals(state, func) {
13356
13319
  }, node, node);
13357
13320
  }
13358
13321
  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);
13322
+ }
13323
+ external_node_assert_namespaceObject(!info);
13324
+ return variableCleanup(node);
13325
+ });
13326
+ return;
13327
+ }
13328
+ function variableCleanup(node) {
13329
+ switch (node.type) {
13330
+ case "ExpressionStatement":
13331
+ if (node.expression.type === "Literal") {
13332
+ return false;
13333
+ }
13334
+ break;
13335
+ case "VariableDeclaration":
13336
+ if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
13337
+ const results = [];
13338
+ node.declarations.forEach((decl) => {
13339
+ if (isStatement(decl)) {
13340
+ results.push(decl);
13391
13341
  }
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;
13342
+ else if (isExpression(decl)) {
13343
+ results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
13344
+ }
13345
+ else if (decl.init) {
13346
+ results.push(withLoc({
13347
+ type: "ExpressionStatement",
13348
+ expression: withLoc({
13349
+ type: "AssignmentExpression",
13350
+ operator: "=",
13351
+ left: withLoc({
13352
+ type: "Identifier",
13353
+ name: (0,external_api_cjs_namespaceObject.variableDeclarationName)(decl.id),
13354
+ }, decl.id, decl.id),
13355
+ right: decl.init,
13356
+ }, decl, decl),
13357
+ }, decl, decl));
13416
13358
  }
13417
- if (node.init.type === "Literal") {
13418
- delete node.init;
13359
+ });
13360
+ node.declarations = node.declarations.filter((decl) => {
13361
+ if (decl.type === "VariableDeclarator") {
13362
+ delete decl.init;
13363
+ return true;
13419
13364
  }
13365
+ return false;
13366
+ });
13367
+ if (node.declarations.length) {
13368
+ withLocDeep(node, node, false);
13369
+ results.unshift(node);
13420
13370
  }
13421
- break;
13422
- case "SequenceExpression":
13423
- if (node.expressions.some((e) => e.type === "Literal")) {
13424
- node.expressions = node.expressions.filter((e) => e.type !== "Literal");
13371
+ // if this was the init of a ForStatement, this will
13372
+ // replace its init with a BlockStatement, so we have to
13373
+ // fix that below.
13374
+ return results;
13375
+ }
13376
+ break;
13377
+ case "ForStatement":
13378
+ if (node.init) {
13379
+ if (node.init.type === "BlockStatement") {
13380
+ const result = node.init;
13381
+ delete node.init;
13382
+ result.body.push(node);
13383
+ if (node.loc && result.loc) {
13384
+ // result has the range of the original VariableDeclaration
13385
+ // but now we're moving that ahead of the 'for', so to keep
13386
+ // things straight, we need to set the for's start to be
13387
+ // where result ended, and result's end to be where the for
13388
+ // ends (since that block now encloses the for)
13389
+ node.start = result.end;
13390
+ node.loc.start = result.loc.end;
13391
+ result.end = node.end;
13392
+ result.loc.end = node.loc.end;
13393
+ }
13394
+ return result;
13425
13395
  }
13426
- break;
13427
- }
13428
- external_node_assert_namespaceObject(!info);
13429
- return null;
13430
- });
13431
- return;
13396
+ if (node.init.type === "Literal") {
13397
+ delete node.init;
13398
+ }
13399
+ }
13400
+ break;
13401
+ case "SequenceExpression":
13402
+ if (node.expressions.some((e) => e.type === "Literal")) {
13403
+ node.expressions = node.expressions.filter((e) => e.type !== "Literal");
13404
+ }
13405
+ break;
13406
+ }
13407
+ return null;
13432
13408
  }
13433
13409
 
13434
13410
  ;// CONCATENATED MODULE: ./src/pre.ts
@@ -14181,6 +14157,199 @@ function applyReplacements(func, nodeMap, declMap) {
14181
14157
  });
14182
14158
  }
14183
14159
 
14160
+ ;// CONCATENATED MODULE: ./src/type-flow/minimize-modules.ts
14161
+
14162
+
14163
+
14164
+ function minimizeModules(ast, state) {
14165
+ const { pre, post } = state;
14166
+ try {
14167
+ const replacementMap = new Map();
14168
+ const conflictingNames = new Set();
14169
+ state.pre = (node) => {
14170
+ if (state.inType)
14171
+ return null;
14172
+ switch (node.type) {
14173
+ case "ModuleDeclaration":
14174
+ case "ClassDeclaration":
14175
+ case "FunctionDeclaration":
14176
+ return ["body"];
14177
+ case "Using":
14178
+ conflictingNames.add(node.as?.name ??
14179
+ (node.id.type === "Identifier"
14180
+ ? node.id.name
14181
+ : node.id.property.name));
14182
+ return [];
14183
+ case "ImportModule":
14184
+ conflictingNames.add(node.id.type === "Identifier" ? node.id.name : node.id.property.name);
14185
+ return [];
14186
+ case "Identifier":
14187
+ case "MemberExpression": {
14188
+ let current = node;
14189
+ const parts = [];
14190
+ while (current.type === "MemberExpression" && !current.computed) {
14191
+ parts.unshift(current);
14192
+ current = current.object;
14193
+ }
14194
+ if (current.type !== "Identifier" &&
14195
+ current.type !== "ThisExpression") {
14196
+ break;
14197
+ }
14198
+ let toReplace = null;
14199
+ let module = null;
14200
+ let addImport = false;
14201
+ let [, results] = state.lookupValue(current, null);
14202
+ let i = 0;
14203
+ for (; results &&
14204
+ results.length === 1 &&
14205
+ results[0].results.length === 1 &&
14206
+ (results[0].results[0].type === "Program" ||
14207
+ results[0].results[0].type === "ClassDeclaration" ||
14208
+ results[0].results[0].type === "ModuleDeclaration"); i++) {
14209
+ if (current.type === "Identifier" &&
14210
+ results[0].results[0].type === "ModuleDeclaration" &&
14211
+ isImportCandidate(results[0].results[0])) {
14212
+ const directResults = i
14213
+ ? state.lookupValue(current, null)
14214
+ : results;
14215
+ if (directResults &&
14216
+ directResults.length === 1 &&
14217
+ directResults[0].results.length === 1 &&
14218
+ directResults[0].results[0] === results[0].results[0]) {
14219
+ // we would find the same thing if we just looked up
14220
+ // current directly.
14221
+ toReplace = (i ? parts[i - 1] : current);
14222
+ module = results[0].results[0];
14223
+ if ((0,external_api_cjs_namespaceObject.findUsingForNode)(state, state.stack, state.stack.length - 1, current) === directResults[0].results[0]) {
14224
+ // we already find it via an import, so we don't need
14225
+ // a new import.
14226
+ addImport = false;
14227
+ }
14228
+ else {
14229
+ addImport = true;
14230
+ }
14231
+ }
14232
+ else {
14233
+ toReplace = parts[i - 1];
14234
+ module = results[0].results[0];
14235
+ addImport = true;
14236
+ }
14237
+ }
14238
+ if (i === parts.length)
14239
+ break;
14240
+ current = parts[i].property;
14241
+ results = (0,external_api_cjs_namespaceObject.lookupNext)(state, results, "decls", current);
14242
+ }
14243
+ if (toReplace) {
14244
+ external_node_assert_namespaceObject(module);
14245
+ replacementMap.set(toReplace, { module, addImport });
14246
+ }
14247
+ else if (parts.length === 0) {
14248
+ external_node_assert_namespaceObject(node.type === "Identifier");
14249
+ conflictingNames.add(node.name);
14250
+ }
14251
+ else if (parts[0].object.type === "Identifier") {
14252
+ conflictingNames.add(parts[0].object.name);
14253
+ }
14254
+ return [];
14255
+ }
14256
+ }
14257
+ return null;
14258
+ };
14259
+ (0,external_api_cjs_namespaceObject.collectNamespaces)(ast, state);
14260
+ const mappedNames = new Map();
14261
+ replacementMap.forEach((value, key) => {
14262
+ let name;
14263
+ if (value.addImport) {
14264
+ name = mappedNames.get(value.module);
14265
+ if (!name) {
14266
+ name = value.module.name;
14267
+ for (let i = 0; conflictingNames.has(name); i++) {
14268
+ name = `${value.module.name}_${i}`;
14269
+ }
14270
+ mappedNames.set(value.module, name);
14271
+ conflictingNames.add(name);
14272
+ }
14273
+ }
14274
+ else {
14275
+ name = key.type === "Identifier" ? key.name : key.property.name;
14276
+ }
14277
+ const original = (0,external_api_cjs_namespaceObject.formatAstLongLines)(key);
14278
+ const repl = key;
14279
+ repl.type = "Identifier";
14280
+ repl.name = name;
14281
+ if (name !== original) {
14282
+ repl.original = original;
14283
+ }
14284
+ delete repl.property;
14285
+ delete repl.object;
14286
+ delete repl.computed;
14287
+ });
14288
+ mappedNames.forEach((name, module) => {
14289
+ const id = makeScopedName(module.fullName.slice(2));
14290
+ const as = name !== (id.type === "Identifier" ? id : id.property).name &&
14291
+ makeIdentifier(name);
14292
+ const using = withLocDeep(as ? { type: "Using", id, as } : { type: "Using", id }, ast, false, true);
14293
+ ast.body.unshift(using);
14294
+ });
14295
+ }
14296
+ finally {
14297
+ state.pre = pre;
14298
+ state.post = post;
14299
+ }
14300
+ }
14301
+ /**
14302
+ * There's a bug in garmin's runtime (although the compiler could
14303
+ * work around it). See
14304
+ *
14305
+ * https://forums.garmin.com/developer/connect-iq/i/bug-reports/referencing-an-imported-module-doesn-t-run-its-parent-s-init
14306
+ *
14307
+ * What this means is that if a module's parent isn't `globals`
14308
+ * and it needs to be initialized, then we can't risk
14309
+ * importing it, because the parent module might not get initialized
14310
+ * in time.
14311
+ */
14312
+ function isImportCandidate(module) {
14313
+ if (module.fullName.startsWith("$.Toybox."))
14314
+ return true;
14315
+ if (module.fullName.startsWith("$.Rez."))
14316
+ return false;
14317
+ external_node_assert_namespaceObject(module.stack);
14318
+ if (module.stack.length === 1)
14319
+ return true;
14320
+ return module.stack.every((elem) => {
14321
+ if (!elem.sn.decls)
14322
+ return false;
14323
+ if (elem.sn.type === "Program")
14324
+ return true;
14325
+ if (elem.sn.type !== "ModuleDeclaration")
14326
+ return false;
14327
+ return Object.values(elem.sn.decls).every((decls) => decls.every((decl) => {
14328
+ if (decl.type !== "VariableDeclarator")
14329
+ return true;
14330
+ if (!decl.node.init)
14331
+ return true;
14332
+ if (decl.node.init.type === "UnaryExpression" &&
14333
+ decl.node.init.operator === ":") {
14334
+ return true;
14335
+ }
14336
+ if (decl.node.init.type !== "Literal")
14337
+ return false;
14338
+ switch (typeof decl.node.init.value) {
14339
+ case "boolean":
14340
+ return true;
14341
+ case "bigint":
14342
+ return false;
14343
+ case "number":
14344
+ return !/[dl]$/i.test(decl.node.init.raw);
14345
+ case "object":
14346
+ return decl.node.init.value === null;
14347
+ }
14348
+ return false;
14349
+ }));
14350
+ });
14351
+ }
14352
+
14184
14353
  ;// CONCATENATED MODULE: ./src/type-flow/optimize.ts
14185
14354
 
14186
14355
 
@@ -15031,6 +15200,7 @@ function cleanupUnusedVars(state, node) {
15031
15200
 
15032
15201
 
15033
15202
 
15203
+
15034
15204
  /*
15035
15205
  * Map each name to the list of StateNodes that declare that
15036
15206
  * name (excluding Functions, which are already in allFunctions)
@@ -15618,32 +15788,30 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
15618
15788
  break;
15619
15789
  case "Identifier": {
15620
15790
  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);
15791
+ if ((0,external_api_cjs_namespaceObject.hasProperty)(map, node.name)) {
15792
+ const name = map[node.name];
15793
+ if (typeof name === "string") {
15794
+ renameIdentifier(node, name);
15795
+ }
15796
+ const [, results] = state.lookupValue(node);
15797
+ if (results) {
15798
+ if (results.length !== 1 || results[0].results.length !== 1) {
15799
+ throw new Error(`Local ${node.name} had multiple lookup results`);
15626
15800
  }
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;
15801
+ const parent = results[0].parent;
15802
+ if (!parent) {
15803
+ throw new Error(`Local ${node.name} had no parent`);
15804
+ }
15805
+ const decl = results[0].results[0];
15806
+ if (parent.type === "FunctionDeclaration" ||
15807
+ decl.type !== "VariableDeclarator") {
15808
+ // we can't optimize away function or catch parameters
15809
+ return [];
15810
+ }
15811
+ if (parent.type !== "BlockStatement") {
15812
+ throw new Error(`Local ${node.name} was not declared at block scope(??)`);
15646
15813
  }
15814
+ decl.used = true;
15647
15815
  }
15648
15816
  }
15649
15817
  return [];
@@ -15931,6 +16099,11 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
15931
16099
  state.nextExposed = {};
15932
16100
  delete state.pre;
15933
16101
  delete state.post;
16102
+ if (state.config?.minimizeModules ?? true) {
16103
+ Object.values(fnMap).forEach((f) => {
16104
+ minimizeModules(f.ast, state);
16105
+ });
16106
+ }
15934
16107
  Object.values(state.allFunctions).forEach((fns) => fns.forEach((fn) => sizeBasedPRE(state, fn)));
15935
16108
  const cleanup = (node) => {
15936
16109
  switch (node.type) {
@@ -16576,6 +16749,7 @@ const configOptionsToCheck = [
16576
16749
  "propagateTypes",
16577
16750
  "singleUseCopyProp",
16578
16751
  "minimizeLocals",
16752
+ "minimizeModules",
16579
16753
  "extensionVersion",
16580
16754
  "typeCheckLevel",
16581
16755
  "covarianceWarnings",
@@ -16637,7 +16811,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
16637
16811
  // the oldest optimized file, we don't need to regenerate
16638
16812
  const source_time = await (0,external_util_cjs_namespaceObject.last_modified)(Object.keys(fnMap).concat(dependencyFiles));
16639
16813
  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) {
16814
+ if (source_time < opt_time && 1676942537698 < opt_time) {
16641
16815
  return { hasTests, diagnostics: prevDiagnostics };
16642
16816
  }
16643
16817
  }
@@ -16664,7 +16838,7 @@ async function generateOneConfig(buildConfig, manifestXML, dependencyFiles, conf
16664
16838
  return promises_namespaceObject.writeFile(external_path_.join(output, "build-info.json"), JSON.stringify({
16665
16839
  hasTests,
16666
16840
  diagnostics,
16667
- optimizerVersion: "1.1.12",
16841
+ optimizerVersion: "1.1.14",
16668
16842
  ...Object.fromEntries(configOptionsToCheck.map((option) => [option, config[option]])),
16669
16843
  }))
16670
16844
  .then(() => ({ hasTests, diagnostics }));