Last active
November 5, 2017 17:55
-
-
Save mzgoddard/f0589052bc23d232960bd9fb27d37bf1 to your computer and use it in GitHub Desktop.
Rudimentary Boxart plugin transforming bablyon tree to flatten functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // function gen() { | |
| // return (function(fn) { | |
| // const f = function(t, state, begin, end) { | |
| // var b = {b: 1}; | |
| // var c = {f2: function(t) {return t;}}; | |
| // state.left = c.f2(b.b, state, begin, end) * 2; | |
| // return state; | |
| // }; | |
| // return f; | |
| // })((function(fn) { | |
| // const f = function(t) {return fn(t * 2) * 2;}; | |
| // return f; | |
| // })((function(fn) { | |
| // const f = function(t) {return fn(t * 2) * 2;}; | |
| // return f; | |
| // })((function(fn) { | |
| // const f = function(t) {return fn(t * 2) * 2;}; | |
| // return f; | |
| // })((function(c) { | |
| // const f = function(t) {return t * c;}; | |
| // return f; | |
| // })(3))))); | |
| // } | |
| export default function(babel) { | |
| const { types: t, traverse } = babel; | |
| let values = {}; | |
| const memberLookup = (path, state) => { | |
| let stack = []; | |
| let node = path.node; | |
| while (t.isMemberExpression(node)) { | |
| if (node.computed) {return;} | |
| if (!t.isIdentifier(node.property)) {return;} | |
| stack.unshift(node.property.name); | |
| node = node.object; | |
| } | |
| if (!t.isIdentifier(node)) {return;} | |
| let value = state[node.name]; | |
| while (t.isObjectExpression(value) && stack.length > 0) { | |
| const name = stack.shift(); | |
| value = value.properties.find(prop => prop.key.name === name); | |
| if (value) { | |
| value = value.value; | |
| } | |
| } | |
| if (t.isLiteral(value) || t.isIdentifier(value) || t.isFunctionExpression(value)) { | |
| path.replaceWith(t.cloneDeep(value)); | |
| } | |
| }; | |
| const inlineFunctions = { | |
| FunctionExpression(path, state) {}, | |
| Identifier(path, state) { | |
| // if ( | |
| // !path.parentPath.isVariableDeclarator() || | |
| // path.parent.id !== path.node | |
| // ) { | |
| // if (t.isLiteral(state[path.node.name]) || t.isFunction(state[path.node.name])) { | |
| // path.replaceWith(t.cloneDeep(state[path.node.name])); | |
| // } | |
| // } | |
| }, | |
| VariableDeclarator: { | |
| enter(path, state) { | |
| path.scope.rename(path.node.id.name); | |
| }, | |
| exit(path, state) { | |
| if (path.get("init").isIdentifier() && state[path.node.id.name]) { | |
| path.get('init').replaceWith(t.cloneDeep(state[path.node.id.name])); | |
| } | |
| if (path.get("init").isFunctionExpression()) { | |
| state[path.node.id.name] = path.node.init; | |
| } | |
| if (path.get("init").isNumericLiteral()) { | |
| state[path.node.id.name] = path.node.init; | |
| } | |
| if (path.get("init").isObjectExpression()) { | |
| state[path.node.id.name] = path.node.init; | |
| } | |
| } | |
| }, | |
| CallExpression: { | |
| enter(path, state) { | |
| if (path.get("callee").isMemberExpression()) { | |
| memberLookup(path.get('callee'), state); | |
| // path.get("callee").replaceWith(t.cloneDeep(state[path.node.callee.name])); | |
| } | |
| if ( | |
| path.get("callee").isIdentifier() && | |
| state[path.node.callee.name] | |
| ) { | |
| path.get("callee").replaceWith(t.cloneDeep(state[path.node.callee.name])); | |
| } | |
| if (path.get("callee").isFunctionExpression()) { | |
| state = Object.assign({}, state, { __parentstate: state }); | |
| const args = path.node.arguments; | |
| const params = path.node.callee.params; | |
| params.forEach((p, i) => { | |
| }); | |
| } | |
| }, | |
| exit(path, state) { | |
| if (path.get("callee").isFunctionExpression()) { | |
| const args = path.node.arguments; | |
| const params = path.node.callee.params; | |
| params.forEach((p, i) => { | |
| path.get("callee").scope.rename(p.name); | |
| path | |
| .getStatementParent() | |
| .insertBefore( | |
| t.variableDeclaration( | |
| "const", | |
| [t.variableDeclarator(t.identifier(p.name), args[i])] | |
| ) | |
| ); | |
| if ( | |
| path.get(`arguments.${i}`).isIdentifier() && | |
| t.isFunctionExpression(state[args[i].name]) | |
| ) { | |
| state[p.name] = state[args[i].name]; | |
| } | |
| if (path.get(`arguments.${i}`).isLiteral()) { | |
| state[p.name] = args[i]; | |
| } | |
| }); | |
| } | |
| if (path.get("callee").isFunctionExpression()) { | |
| path.get("callee.body").node.body.forEach(expr => { | |
| if (t.isReturnStatement(expr)) { | |
| path.replaceWith(t.cloneDeep(expr.argument)); | |
| } else { | |
| path.getStatementParent().insertBefore(t.cloneDeep(expr)); | |
| } | |
| }); | |
| } | |
| } | |
| } | |
| }; | |
| const lookupAndOps = { | |
| VariableDeclarator: { | |
| exit(path, state) { | |
| if ( | |
| path.get('init').isLiteral() || | |
| path.get('init').isObjectExpression() | |
| ) { | |
| state[path.node.id.name] = path.node.init; | |
| } | |
| }, | |
| }, | |
| MemberExpression(path, state) { | |
| let stack = []; | |
| let node = path.node; | |
| while (t.isMemberExpression(node)) { | |
| if (node.computed) {return;} | |
| if (!t.isIdentifier(node.property)) {return;} | |
| stack.unshift(node.property.name); | |
| node = node.object; | |
| } | |
| // path.getStatementParent().insertBefore(t.expressionStatement(t.stringLiteral(`${String(stack)}`))); | |
| if (!t.isIdentifier(node)) {return;} | |
| let value = state[node.name]; | |
| // path.getStatementParent().insertBefore(t.expressionStatement(t.stringLiteral(`${JSON.stringify(node.name)}`))); | |
| // path.getStatementParent().insertBefore(t.expressionStatement(t.stringLiteral(`${JSON.stringify(value)}`))); | |
| while (t.isObjectExpression(value) && stack.length > 0) { | |
| const name = stack.shift(); | |
| // path.getStatementParent().insertBefore(t.expressionStatement(t.stringLiteral(`${name}`))); | |
| value = value.properties.find(prop => prop.key.name === name); | |
| if (value) { | |
| value = value.value; | |
| } | |
| } | |
| // path.getStatementParent().insertBefore(t.expressionStatement(t.stringLiteral(`${stack.length} ${JSON.stringify(value)}`))); | |
| if (t.isLiteral(value)) { | |
| path.replaceWith(t.cloneDeep(value)); | |
| } | |
| }, | |
| Identifier(path, state) { | |
| if ( | |
| path.parent.id !== path.node | |
| ) { | |
| if (state[path.node.name]) { | |
| path.replaceWith(t.cloneDeep(state[path.node.name])); | |
| } | |
| } | |
| }, | |
| BinaryExpression: { | |
| exit(path, state) { | |
| // const e = path.evaluate(); | |
| // if (e.confident) { | |
| // } | |
| if ( | |
| path.get('left').isLiteral() && path.get('right').isLiteral() && | |
| path.node.operator === '*' | |
| ) { | |
| const e = path.evaluate(); | |
| if (e.confident && typeof e.value === 'number') { | |
| path.replaceWith(t.numericLiteral(e.value)); | |
| } | |
| } | |
| if ( | |
| path.get('left').isBinaryExpression() && | |
| path.node.left.operator === '*' && path.node.operator === '*' && | |
| path.get('left.right').isLiteral() && path.get('right').isLiteral() | |
| ) { | |
| path.replaceWith( | |
| t.binaryExpression( | |
| '*', | |
| path.node.left.left, | |
| t.binaryExpression('*', path.node.left.right, path.node.right) | |
| ) | |
| ); | |
| const e = path.get('right').evaluate(); | |
| if (e.confident && typeof e.value === 'number') { | |
| path.get('right').replaceWith(t.numericLiteral(e.value)); | |
| } | |
| } | |
| }, | |
| }, | |
| }; | |
| const refCount = { | |
| Identifier(path, state) { | |
| if (path.getStatementParent().parentPath.isProgram()) { | |
| return; | |
| } | |
| if (path.parent.id === path.node) { | |
| if (!(state[path.node.name] || {}).node) { | |
| // path.getStatementParent().insertBefore(t.expressionStatement(t.stringLiteral(path.node.name))); | |
| state[path.node.name] = {node: path.node, refs: [], refsFrom: []}; | |
| } | |
| } | |
| if ( | |
| path.getStatementParent().isVariableDeclaration() && | |
| path.findParent(t.isVariableDeclarator).node.id.name !== path.node.name | |
| ) { | |
| const declId = path.findParent(t.isVariableDeclarator).node.id.name; | |
| const id = path.node.name; | |
| if ((state[id] || {}).node) { | |
| // path.getStatementParent().insertBefore(t.expressionStatement(t.stringLiteral(String([declId, id])))); | |
| if (!(state[declId] || {}).node) { | |
| state[declId] = {node: path.parent.id, refs: [], refsFrom: []}; | |
| } | |
| state[declId].refs.push(id); | |
| if (!(state[id] || {}).node) { | |
| state[id] = {node: path.node, refs: [], refsFrom: []}; | |
| } | |
| state[id].refsFrom.push(declId); | |
| } | |
| } | |
| if (path.getStatementParent().isReturnStatement()) { | |
| const id = path.node.name; | |
| if (!(state[id] || {}).node) { | |
| state[id] = {node: path.node, refs: [], refsFrom: []}; | |
| } | |
| state[id].refsFrom.push('__return__'); | |
| } | |
| }, | |
| }; | |
| const deadCode = { | |
| Identifier(path, state) { | |
| if ( | |
| path.parent.id === path.node | |
| ) { | |
| // path.getStatementParent().insertBefore(t.expressionStatement(t.stringLiteral(`${path.node.name}: ${String((state[path.node.name] || {refsFrom: []}).refsFrom.length)}`))); | |
| } | |
| if ( | |
| path.parent.id === path.node && | |
| state[path.node.name] && | |
| state[path.node.name].refsFrom.length === 0 | |
| ) { | |
| if (!path.getStatementParent().parentPath.isProgram()) { | |
| path.getStatementParent().remove(); | |
| } | |
| } | |
| }, | |
| }; | |
| return { | |
| visitor: { | |
| Program(path) { | |
| path.traverse(inlineFunctions, {}); | |
| path.traverse(lookupAndOps, {}); | |
| let refs = {}; | |
| path.traverse(refCount, refs); | |
| let lastRefs = refs; | |
| let removed = Infinity; | |
| while (removed > 0) { | |
| removed = 0; | |
| refs = {}; | |
| path.traverse(deadCode, lastRefs); | |
| path.traverse(refCount, refs); | |
| if (Object.keys(refs).length < Object.keys(lastRefs).length) { | |
| removed = 1; | |
| } | |
| lastRefs = refs; | |
| } | |
| path.skip(); | |
| }, | |
| } | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment