@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 +11 -0
- package/build/api.cjs +390 -22
- package/build/optimizer.cjs +4799 -4453
- package/build/src/api.d.ts +1 -1
- package/build/src/data-flow.d.ts +4 -5
- package/build/src/type-flow/dead-store.d.ts +7 -2
- package/build/src/type-flow/live-range.d.ts +0 -0
- package/build/src/type-flow/minimize-locals.d.ts +2 -0
- package/build/src/type-flow/types.d.ts +1 -1
- package/build/src/type-flow.d.ts +13 -0
- package/package.json +2 -2
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)
|
|
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
|
|
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
|
|
4048
|
-
/* harmony import */ var
|
|
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 &&
|
|
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
|
|
6110
|
-
/* harmony import */ var
|
|
6111
|
-
/* harmony import */ var
|
|
6112
|
-
/* harmony import */ var
|
|
6113
|
-
/* harmony import */ var
|
|
6114
|
-
/* harmony import */ var
|
|
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
|
|
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
|
-
|
|
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
|
/******/ });
|