1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| function getJump(node, name) { if (!types.isExpressionStatement(node)) return; let { expression } = node; if (!types.isAssignmentExpression(expression)) return; if (expression.left.name !== name) return; return expression.right.value; }
function getCaseJump(map, name, node) { let { test, consequent } = node; let list = []; let con = consequent[consequent.length - 1]; let num = getJump(con, name); if (num !== undefined) { list.push(num); } if (types.isIfStatement(con)) { let { consequent, alternate } = con; let num = getJump(consequent, name); if (num !== undefined) { list.push(num); } num = getJump(alternate, name); if (num !== undefined) { list.push(num); } } map[test.value] = list; }
function removeDuplicates(arr1, arr2) { let result = [];
for (let i = 0; i < arr1.length; i++) { let found = false;
for (let j = 0; j < arr2.length; j++) { if (arr1[i] === arr2[j]) { result.push(arr1[i]); arr2.splice(j, 1); found = true; break; } } if (found) { arr1.splice(i, 1); i--; } } return result; }
function controlFlowStructure(si, map, cases, stack = [], body = []) { if (!map.loop) map.loop = []; if (stack.includes(si)) { if (map.loop.indexOf(si) === -1) map.loop.push(si); return body; } let item = map[si]; body = body.concat(cases[si].consequent); switch (item.length) { case 0: return body; case 1: return controlFlowStructure(item[0], map, cases, stack, body); case 2: stack.push(si); body[body.length - 1].consequent = types.blockStatement( controlFlowStructure(item[0], map, cases, stack, []) ); if (map.loop.includes(si)) { let { test, consequent } = body[body.length - 1]; body[body.length - 1] = types.whileStatement(test, consequent); body = body.concat( controlFlowStructure(item[1], map, cases, stack, []) ); } else { body[body.length - 1].alternate = types.blockStatement( controlFlowStructure(item[1], map, cases, stack, []) ); body = body.concat( removeDuplicates( body[body.length - 1].consequent.body, body[body.length - 1].alternate.body ) ); } stack.pop(); return body; } }
const MergeCases = { SwitchStatement(path) { const { discriminant, cases } = path.node; const name = discriminant.name; let binding = path.scope.getBinding(name); let start = binding.path.node.init.right.value; let map = {}; for (let i = 0; i < cases.length; i++) { getCaseJump(map, name, cases[i]); } path.replaceInline(controlFlowStructure(start, map, cases)); }, };
|