@markw65/monkeyc-optimizer 1.1.8 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -666,3 +666,14 @@ Bug Fixes
666
666
  - Add support for comletion style lookups - find all the names available in the current context that fuzzy match a given string
667
667
  - Add helpers to read the function documentation from api.debug.xml
668
668
  - Add an option to visitReferences to only find a specific definition, rather than all definitions for that name in the current scope.
669
+
670
+ ### 1.1.9
671
+
672
+ - Update to [@markw65/prettier-plugin-monkeyc@1.0.43](https://github.com/markw65/prettier-plugin-monkeyc#1043)
673
+
674
+ - Bug fixes
675
+
676
+ - fix an interaction between inlining and removing unused local vars that could cause unlimited recursion leading to stack overflow
677
+
678
+ - New optimizations
679
+ - Adds a `minimizeLocals` pass which runs after `sizeBasedPRE` and attempts to re-use local variables in order to reduce the total number, and hence reduce the stack size.
package/build/api.cjs CHANGED
@@ -3483,7 +3483,7 @@ async function optimizeMonkeyC(fnMap, resourcesMap, manifestXML, config) {
3483
3483
  break;
3484
3484
  case "BlockStatement":
3485
3485
  case "ForStatement":
3486
- if (locals.map && cleanupUnusedVars(state, node)) {
3486
+ if (locals.map && cleanupUnusedVars(state, node) && !state.inlining) {
3487
3487
  again = true;
3488
3488
  }
3489
3489
  break;
@@ -3971,7 +3971,9 @@ function pragmaChecker(state, ast, diagnostics) {
3971
3971
  if (node.start && node.start >= (comment.end || Infinity)) {
3972
3972
  const { kind, quote, needle } = matchers.shift();
3973
3973
  if (kind === "match") {
3974
- const haystack = formatAst(node).replace(/([\r\n]|\s)+/g, " ");
3974
+ const haystack = formatAst(node)
3975
+ .replace(/([\r\n]|\s)+/g, " ")
3976
+ .replace(/\b\w+\s\/\*>(\w+)<\*\//g, "$1");
3975
3977
  if (!matcher(quote, needle, haystack)) {
3976
3978
  matcher(quote, needle, haystack);
3977
3979
  diagnostic(state, comment, `Didn't find '${needle}' in '${haystack}'`, "ERROR");
@@ -3989,7 +3991,7 @@ function pragmaChecker(state, ast, diagnostics) {
3989
3991
  }
3990
3992
  if (a.end.line > b.end.line)
3991
3993
  return 1;
3992
- if (a.end.line === b.end.line && a.end.column >= b.end.column) {
3994
+ if (a.end.line === b.end.line && a.end.column > b.end.column) {
3993
3995
  return 1;
3994
3996
  }
3995
3997
  return 0;
@@ -4044,8 +4046,10 @@ function pragmaChecker(state, ast, diagnostics) {
4044
4046
  /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5101);
4045
4047
  /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8180);
4046
4048
  /* harmony import */ var _function_info__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(819);
4047
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(6906);
4048
- /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_5__);
4049
+ /* harmony import */ var _type_flow_minimize_locals__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(736);
4050
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(6906);
4051
+ /* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_util__WEBPACK_IMPORTED_MODULE_6__);
4052
+
4049
4053
 
4050
4054
 
4051
4055
 
@@ -4150,6 +4154,7 @@ function sizeBasedPRE(state, func) {
4150
4154
  applyReplacements(func.node, nodeMap, declMap);
4151
4155
  func.node.body.body.unshift(variableDecl);
4152
4156
  }
4157
+ minimizeLocals(state, func);
4153
4158
  }
4154
4159
  function buildPREGraph(state, func) {
4155
4160
  const result = buildDataFlowGraph(state, func, (literal) => refCost(literal) > LocalRefCost, true, false);
@@ -4800,7 +4805,7 @@ function applyReplacements(func, nodeMap, declMap) {
4800
4805
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
4801
4806
  /* harmony export */ "nK": () => (/* binding */ findObjectDeclsByProperty)
4802
4807
  /* harmony export */ });
4803
- /* unused harmony exports missingNullWorkaround, buildTypeInfo, resolveDottedMember */
4808
+ /* unused harmony exports missingNullWorkaround, buildTypeInfo, buildConflictGraph, resolveDottedMember */
4804
4809
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
4805
4810
  /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
4806
4811
  /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
@@ -4836,10 +4841,20 @@ const logging = true;
4836
4841
  // To avoid over zealous optimizations, we don't optimize
4837
4842
  // away any Null checks for now.
4838
4843
  const missingNullWorkaround = true;
4844
+ function loggingEnabledFor(env, func) {
4845
+ const pattern = process.env[env];
4846
+ if (!pattern)
4847
+ return false;
4848
+ const match = pattern.match(/^\/(.*)\/(i?)$/);
4849
+ if (match) {
4850
+ return new RegExp(match[1], match[2]).test(func.fullName);
4851
+ }
4852
+ return pattern === func.fullName;
4853
+ }
4839
4854
  function buildTypeInfo(state, func, optimizeEquivalencies) {
4840
4855
  if (!func.node.body || !func.stack)
4841
4856
  return;
4842
- const logThisRun = logging && process.env["TYPEFLOW_FUNC"] === func.fullName;
4857
+ const logThisRun = logging && loggingEnabledFor("TYPEFLOW_FUNC", func);
4843
4858
  while (true) {
4844
4859
  const { graph } = buildDataFlowGraph(state, func, () => false, false, true);
4845
4860
  if (optimizeEquivalencies &&
@@ -4850,9 +4865,18 @@ function buildTypeInfo(state, func, optimizeEquivalencies) {
4850
4865
  */
4851
4866
  continue;
4852
4867
  }
4853
- return propagateTypes({ ...state, stack: func.stack }, func, graph, optimizeEquivalencies, logThisRun);
4868
+ return propagateTypes({ ...state, stack: func.stack }, func, graph, optimizeEquivalencies, logThisRun).istate;
4854
4869
  }
4855
4870
  }
4871
+ function buildConflictGraph(state, func) {
4872
+ if (!func.node.body || !func.stack)
4873
+ return;
4874
+ const logThisRun = logging && loggingEnabledFor("CONFLICT_FUNC", func);
4875
+ const { graph, identifiers } = buildDataFlowGraph(state, func, () => false, false, true);
4876
+ const { nodeEquivs } = propagateTypes({ ...state, stack: func.stack }, func, graph, false, false);
4877
+ const { locals, localConflicts } = findDeadStores(func, graph, nodeEquivs, logThisRun);
4878
+ return { graph, localConflicts, locals, identifiers, logThisRun };
4879
+ }
4856
4880
  function addEquiv(ts, key, equiv) {
4857
4881
  if (key === equiv)
4858
4882
  return true;
@@ -5828,7 +5852,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5828
5852
  }
5829
5853
  if (optimizeEquivalencies) {
5830
5854
  if (!nodeEquivs.size && !selfAssignments.size) {
5831
- return istate;
5855
+ return { istate, nodeEquivs };
5832
5856
  }
5833
5857
  if (logThisRun) {
5834
5858
  if (selfAssignments.size) {
@@ -5928,7 +5952,7 @@ function propagateTypes(state, func, graph, optimizeEquivalencies, logThisRun) {
5928
5952
  return replacement;
5929
5953
  });
5930
5954
  }
5931
- return istate;
5955
+ return { istate, nodeEquivs };
5932
5956
  }
5933
5957
 
5934
5958
 
@@ -6106,12 +6130,12 @@ function couldBeObj(a, b) {
6106
6130
 
6107
6131
  "use strict";
6108
6132
  /* unused harmony exports findDeadStores, eliminateDeadStores */
6109
- /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6652);
6110
- /* harmony import */ var _inliner__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(333);
6111
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6817);
6112
- /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_2__);
6113
- /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5101);
6114
- /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8180);
6133
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6817);
6134
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_0__);
6135
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6652);
6136
+ /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5101);
6137
+ /* harmony import */ var _data_flow__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8180);
6138
+ /* harmony import */ var _inliner__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(333);
6115
6139
  /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1638);
6116
6140
 
6117
6141
 
@@ -6119,12 +6143,13 @@ function couldBeObj(a, b) {
6119
6143
 
6120
6144
 
6121
6145
 
6122
- function findDeadStores(graph, logThisRun) {
6146
+ function findDeadStores(func, graph, nodeEquivs, logThisRun) {
6123
6147
  const order = getPostOrder(graph);
6124
6148
  order.forEach((block, i) => {
6125
6149
  block.order = i;
6126
6150
  });
6127
6151
  const blockStates = [];
6152
+ const nodeConflicts = nodeEquivs && new Map();
6128
6153
  const mergeStates = (to, from) => {
6129
6154
  return Array.from(to).reduce((changed, decl) => {
6130
6155
  if (!from.has(decl)) {
@@ -6135,11 +6160,13 @@ function findDeadStores(graph, logThisRun) {
6135
6160
  }, false);
6136
6161
  };
6137
6162
  const queue = new DataflowQueue();
6138
- const locals = new Set(order.flatMap((block) => block.events
6163
+ const locals = new Set(order
6164
+ .flatMap((block) => block.events
6139
6165
  ? block.events
6140
6166
  .filter((event) => event.type === "def" && declIsLocal(event.decl))
6141
6167
  .map((def) => def.decl)
6142
- : []));
6168
+ : [])
6169
+ .concat(func.node.params));
6143
6170
  const deadStores = new Set();
6144
6171
  order.forEach((block) => {
6145
6172
  if (!block.succs) {
@@ -6180,13 +6207,34 @@ function findDeadStores(graph, logThisRun) {
6180
6207
  }
6181
6208
  break;
6182
6209
  case "def":
6183
- if (isTypeStateKey(event.decl)) {
6210
+ if (isTypeStateKey(event.decl) &&
6211
+ (event.node.type !== "VariableDeclarator" || event.node.init)) {
6184
6212
  if (curState.has(event.decl)) {
6185
6213
  deadStores.add(event.node);
6186
6214
  }
6187
6215
  else {
6188
6216
  deadStores.delete(event.node);
6189
6217
  }
6218
+ if (nodeConflicts) {
6219
+ const conflicts = new Set(locals);
6220
+ curState.forEach((dead) => conflicts.delete(dead));
6221
+ if (event.rhs) {
6222
+ conflicts.delete(event.rhs);
6223
+ const equiv = event.node.type === "AssignmentExpression" &&
6224
+ event.node.operator === "="
6225
+ ? nodeEquivs.get(event.node.right)
6226
+ : event.node.type === "VariableDeclarator" &&
6227
+ event.node.init
6228
+ ? nodeEquivs.get(event.node.init)
6229
+ : null;
6230
+ if (equiv) {
6231
+ equiv.equiv.forEach((e) => isTypeStateKey(e) && conflicts.delete(e));
6232
+ isTypeStateKey(equiv.decl) && conflicts.delete(equiv.decl);
6233
+ }
6234
+ }
6235
+ conflicts.add(event.decl);
6236
+ nodeConflicts.set(event.node, conflicts);
6237
+ }
6190
6238
  if ((event.node.type === "AssignmentExpression" &&
6191
6239
  event.node.operator === "=") ||
6192
6240
  (event.node.type === "VariableDeclarator" && event.node.init)) {
@@ -6231,10 +6279,27 @@ function findDeadStores(graph, logThisRun) {
6231
6279
  doMerge(top.bogopred);
6232
6280
  }
6233
6281
  }
6234
- return deadStores;
6282
+ let localConflicts = null;
6283
+ if (nodeConflicts) {
6284
+ localConflicts = new Map();
6285
+ const addConflicts = (conflict, conflicts) => {
6286
+ let set = localConflicts.get(conflict);
6287
+ if (set) {
6288
+ conflicts.forEach((c) => c !== conflict && set.add(c));
6289
+ }
6290
+ else {
6291
+ set = new Set(conflicts);
6292
+ set.delete(conflict);
6293
+ localConflicts.set(conflict, set);
6294
+ }
6295
+ };
6296
+ nodeConflicts.forEach((conflicts) => conflicts.forEach((conflict) => addConflicts(conflict, conflicts)));
6297
+ func.node.params.forEach((param, index, arr) => addConflicts(param, arr));
6298
+ }
6299
+ return { deadStores, locals, localConflicts };
6235
6300
  }
6236
6301
  function eliminateDeadStores(state, func, graph, logThisRun) {
6237
- const deadStores = findDeadStores(graph, logThisRun);
6302
+ const { deadStores } = findDeadStores(func, graph, null, logThisRun);
6238
6303
  if (!deadStores.size)
6239
6304
  return false;
6240
6305
  if (logThisRun) {
@@ -8536,6 +8601,301 @@ function restrictByEquality(a, b) {
8536
8601
  }
8537
8602
 
8538
8603
 
8604
+ /***/ }),
8605
+
8606
+ /***/ 736:
8607
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
8608
+
8609
+ "use strict";
8610
+ /* unused harmony export minimizeLocals */
8611
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4143);
8612
+ /* harmony import */ var node_assert__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_assert__WEBPACK_IMPORTED_MODULE_0__);
8613
+ /* harmony import */ var _control_flow__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5101);
8614
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6817);
8615
+ /* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_api__WEBPACK_IMPORTED_MODULE_2__);
8616
+ /* harmony import */ var _ast__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6652);
8617
+ /* harmony import */ var _type_flow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4859);
8618
+ /* harmony import */ var _type_flow_util__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1638);
8619
+
8620
+
8621
+
8622
+
8623
+
8624
+
8625
+ function minimizeLocals(state, func) {
8626
+ const result = buildConflictGraph(state, func);
8627
+ if (!result)
8628
+ return;
8629
+ const { graph, localConflicts, locals: localSet, identifiers, logThisRun, } = result;
8630
+ if (!localConflicts)
8631
+ return;
8632
+ const colors = new Map();
8633
+ const locals = Array.from(localSet)
8634
+ .sort((a, b) => (localConflicts.get(a)?.size ?? 0) - (localConflicts.get(b)?.size ?? 0))
8635
+ .filter((key) => key.type === "VariableDeclarator" ||
8636
+ key.type === "Identifier" ||
8637
+ key.type === "BinaryExpression");
8638
+ const merge = [];
8639
+ locals.forEach((local) => {
8640
+ let inUse = 0n;
8641
+ localConflicts.get(local)?.forEach((conflict) => {
8642
+ const color = colors.get(conflict);
8643
+ if (color != null) {
8644
+ inUse |= 1n << BigInt(color);
8645
+ }
8646
+ });
8647
+ let lowest = 0;
8648
+ while (inUse & 1n) {
8649
+ lowest++;
8650
+ inUse >>= 1n;
8651
+ }
8652
+ colors.set(local, lowest);
8653
+ if (!merge[lowest]) {
8654
+ merge[lowest] = [local];
8655
+ }
8656
+ else {
8657
+ merge[lowest].push(local);
8658
+ }
8659
+ });
8660
+ const didMerge = merge.some((merged) => merged.length > 1);
8661
+ if (didMerge !== (merge.length !== locals.length)) {
8662
+ throw new Error("WTF?");
8663
+ }
8664
+ if (!didMerge)
8665
+ return;
8666
+ if (logThisRun) {
8667
+ console.log(`>>> Merging locals in ${func.fullName}`);
8668
+ merge.forEach((merged) => merged.length > 1 &&
8669
+ console.log(` - merging ${merged.map((k) => tsKey(k)).join(" | ")}`));
8670
+ }
8671
+ const remap = new Map();
8672
+ merge.forEach((merged) => {
8673
+ if (merged.length === 1)
8674
+ return;
8675
+ const info = merged.reduce((cur, decl) => {
8676
+ if (decl.type === "Identifier" || decl.type === "BinaryExpression") {
8677
+ return {
8678
+ decl,
8679
+ stack: func.stack,
8680
+ depth: func.stack.length,
8681
+ name: variableDeclarationName(decl),
8682
+ };
8683
+ }
8684
+ if (cur === null) {
8685
+ return {
8686
+ decl,
8687
+ stack: decl.stack,
8688
+ depth: decl.stack.length,
8689
+ name: decl.name,
8690
+ };
8691
+ }
8692
+ let depth = cur.depth < decl.stack.length ? cur.depth : decl.stack.length;
8693
+ while (true) {
8694
+ if (cur.stack[depth - 1].sn === decl.stack[depth - 1].sn) {
8695
+ break;
8696
+ }
8697
+ depth--;
8698
+ }
8699
+ if (cur.stack.length > decl.stack.length) {
8700
+ return { decl, stack: decl.stack, depth, name: decl.name };
8701
+ }
8702
+ cur.depth = depth;
8703
+ return cur;
8704
+ }, null);
8705
+ assert(info);
8706
+ merged.forEach((decl) => remap.set(decl, info));
8707
+ if (info.decl.type === "VariableDeclarator") {
8708
+ let name = info.name;
8709
+ if (locals.some((local) => local !== info.decl &&
8710
+ local.type === "VariableDeclarator" &&
8711
+ local.name === name)) {
8712
+ // There's a variable in another scope with the same name, so
8713
+ // produce a new one.
8714
+ let i = 0;
8715
+ do {
8716
+ name = `${info.decl.name}_${i++}`;
8717
+ } while (identifiers.has(name));
8718
+ identifiers.add(name);
8719
+ info.name = name;
8720
+ }
8721
+ let depth = info.depth - 1;
8722
+ let sn = info.stack[depth].sn;
8723
+ while (true) {
8724
+ assert(sn.type === "BlockStatement");
8725
+ if (sn.node.type !== "ForStatement") {
8726
+ break;
8727
+ }
8728
+ sn = info.stack[--depth].sn;
8729
+ }
8730
+ const varDecl = {
8731
+ type: "VariableDeclarator",
8732
+ kind: "var",
8733
+ id: { type: "Identifier", name },
8734
+ };
8735
+ if (sn.node.body.length &&
8736
+ sn.node.body[0].type === "VariableDeclaration") {
8737
+ sn.node.body[0].declarations.unshift(withLocDeep(varDecl, sn.node.body[0], false, true));
8738
+ }
8739
+ else {
8740
+ sn.node.body.unshift(withLocDeep({
8741
+ type: "VariableDeclaration",
8742
+ declarations: [varDecl],
8743
+ kind: "var",
8744
+ }, sn.node, false, true));
8745
+ }
8746
+ }
8747
+ });
8748
+ const order = getPostOrder(graph);
8749
+ const nodeMap = new Map();
8750
+ order.forEach((block) => block.events?.forEach((event) => {
8751
+ if ((event.type !== "ref" && event.type !== "def") ||
8752
+ !isTypeStateKey(event.decl) ||
8753
+ !localSet.has(event.decl)) {
8754
+ return;
8755
+ }
8756
+ const rep = remap.get(event.decl);
8757
+ if (!rep)
8758
+ return;
8759
+ nodeMap.set(event.node, rep);
8760
+ }));
8761
+ traverseAst(func.node.body, null, (node) => {
8762
+ const info = nodeMap.get(node);
8763
+ switch (node.type) {
8764
+ case "Identifier":
8765
+ if (info && info.name !== node.name) {
8766
+ node.original = node.name;
8767
+ node.name = info.name;
8768
+ }
8769
+ return null;
8770
+ case "AssignmentExpression":
8771
+ if (info) {
8772
+ assert(node.left.type === "Identifier");
8773
+ if (node.right.type === "Identifier" &&
8774
+ node.right.name === info.name) {
8775
+ return withLoc({ type: "Literal", value: null, raw: "null" }, node, node);
8776
+ }
8777
+ if (node.left.name !== info.name) {
8778
+ node.left.original = node.left.name;
8779
+ node.left.name = info.name;
8780
+ }
8781
+ return null;
8782
+ }
8783
+ break;
8784
+ case "ExpressionStatement":
8785
+ if (node.expression.type === "Literal") {
8786
+ return false;
8787
+ }
8788
+ break;
8789
+ case "UpdateExpression":
8790
+ if (info) {
8791
+ assert(node.argument.type === "Identifier");
8792
+ if (node.argument.name !== info.name) {
8793
+ node.argument.original = node.argument.name;
8794
+ node.argument.name = info.name;
8795
+ }
8796
+ return null;
8797
+ }
8798
+ break;
8799
+ case "VariableDeclarator":
8800
+ if (info) {
8801
+ if (!node.init) {
8802
+ return false; // delete this entry
8803
+ }
8804
+ if (node.init.type === "Identifier" && node.init.name === info.name) {
8805
+ // this would create a self assignment, so just drop it
8806
+ return false;
8807
+ }
8808
+ // VariableDeclarations aren't allowed to have
8809
+ // AssignmentExpressions in them, but we'll fix that
8810
+ // below
8811
+ return withLoc({
8812
+ type: "AssignmentExpression",
8813
+ operator: "=",
8814
+ left: withLoc({
8815
+ type: "Identifier",
8816
+ name: info.name,
8817
+ original: variableDeclarationName(node.id),
8818
+ }, node.id, node.id),
8819
+ right: node.init,
8820
+ }, node, node);
8821
+ }
8822
+ break;
8823
+ case "VariableDeclaration":
8824
+ if (node.declarations.some((decl) => decl.type !== "VariableDeclarator")) {
8825
+ const results = [];
8826
+ node.declarations.forEach((decl) => {
8827
+ if (isExpression(decl)) {
8828
+ results.push(withLoc({ type: "ExpressionStatement", expression: decl }, decl, decl));
8829
+ }
8830
+ else if (decl.init) {
8831
+ results.push(withLoc({
8832
+ type: "ExpressionStatement",
8833
+ expression: withLoc({
8834
+ type: "AssignmentExpression",
8835
+ operator: "=",
8836
+ left: withLoc({
8837
+ type: "Identifier",
8838
+ name: variableDeclarationName(decl.id),
8839
+ }, decl.id, decl.id),
8840
+ right: decl.init,
8841
+ }, decl, decl),
8842
+ }, decl, decl));
8843
+ }
8844
+ });
8845
+ node.declarations = node.declarations.filter((decl) => {
8846
+ if (decl.type === "VariableDeclarator") {
8847
+ delete decl.init;
8848
+ return true;
8849
+ }
8850
+ return false;
8851
+ });
8852
+ if (node.declarations.length) {
8853
+ withLocDeep(node, node, false);
8854
+ results.unshift(node);
8855
+ }
8856
+ // if this was the init of a ForStatement, this will
8857
+ // replace its init with a BlockStatement, so we have to
8858
+ // fix that below.
8859
+ return results;
8860
+ }
8861
+ break;
8862
+ case "ForStatement":
8863
+ if (node.init) {
8864
+ if (node.init.type === "BlockStatement") {
8865
+ const result = node.init;
8866
+ delete node.init;
8867
+ result.body.push(node);
8868
+ if (node.loc && result.loc) {
8869
+ // result has the range of the original VariableDeclaration
8870
+ // but now we're moving that ahead of the 'for', so to keep
8871
+ // things straight, we need to set the for's start to be
8872
+ // where result ended, and result's end to be where the for
8873
+ // ends (since that block now encloses the for)
8874
+ node.start = result.end;
8875
+ node.loc.start = result.loc.end;
8876
+ result.end = node.end;
8877
+ result.loc.end = node.loc.end;
8878
+ }
8879
+ return result;
8880
+ }
8881
+ if (node.init.type === "Literal") {
8882
+ delete node.init;
8883
+ }
8884
+ }
8885
+ break;
8886
+ case "SequenceExpression":
8887
+ if (node.expressions.some((e) => e.type === "Literal")) {
8888
+ node.expressions = node.expressions.filter((e) => e.type !== "Literal");
8889
+ }
8890
+ break;
8891
+ }
8892
+ assert(!info);
8893
+ return null;
8894
+ });
8895
+ return;
8896
+ }
8897
+
8898
+
8539
8899
  /***/ }),
8540
8900
 
8541
8901
  /***/ 3687:
@@ -10917,6 +11277,14 @@ module.exports = require("@markw65/prettier-plugin-monkeyc");
10917
11277
  "use strict";
10918
11278
  module.exports = require("fs/promises");
10919
11279
 
11280
+ /***/ }),
11281
+
11282
+ /***/ 4143:
11283
+ /***/ ((module) => {
11284
+
11285
+ "use strict";
11286
+ module.exports = require("node:assert");
11287
+
10920
11288
  /***/ })
10921
11289
 
10922
11290
  /******/ });