Skip to content

Instantly share code, notes, and snippets.

@erukiti
Created October 12, 2017 11:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erukiti/a9527ab25fb828d2fe72a3dfda0b3cef to your computer and use it in GitHub Desktop.
Save erukiti/a9527ab25fb828d2fe72a3dfda0b3cef to your computer and use it in GitHub Desktop.
最適化プラグイン
const {transform} = require('babel-core')
const babylon = require('babylon')
const WasCreated = Symbol('WasCreated')
const source = `
let b = 0
console.log(b)
b = b + 2
console.log(b)
b += 3
console.log(b)
`
const optimizePlugin = ({types: t}) => {
const valueToLiteral = value => {
let node
switch (typeof value) {
case 'string': {
node = t.stringLiteral(value)
node[WasCreated] = true
return node
}
case 'number': {
node = t.numericLiteral(value)
node[WasCreated] = true
return node
}
case 'boolean': {
node = t.booleanLiteral(value)
node[WasCreated] = true
return node
}
}
}
const evaluateVisitor = {
exit: (nodePath) => {
if (nodePath.node[WasCreated]) {
nodePath.node[WasCreated] = false
return
}
nodePath.scope.crawl()
const {confident, value} = nodePath.evaluate()
if (confident) {
nodePath.replaceWith(valueToLiteral(value))
}
},
ReferencedIdentifier: (nodePath) => {
nodePath.scope.crawl()
const {name} = nodePath.node
if (name in nodePath.scope.bindings) {
const binding = nodePath.scope.bindings[name]
const statement = nodePath.getStatementParent()
const violations = statement.getAllPrevSiblings().filter(p => {
return binding.constantViolations.filter(v => v.node.start === p.node.start).length > 0
})
if (violations.length === 0) {
const {confident, value} = binding.path.get('init').evaluate()
nodePath.replaceWith(valueToLiteral(value))
return
}
// console.log('!', violations.getSource())
}
},
AssignmentExpression: {
exit: (nodePath) => {
nodePath.scope.crawl()
if (nodePath.get('left').isIdentifier()) {
const {name} = nodePath.node.left
if (name in nodePath.scope.bindings) {
const binding = nodePath.scope.bindings[name]
const statement = nodePath.getStatementParent()
const refs = statement.getAllPrevSiblings().filter(p => {
return binding.referencePaths.filter(r => r.node.start === p.node.start).length > 0
})
if (refs.length === 0) {
const {operator, right} = nodePath.node
if (operator === '=') {
binding.path.get('init').replaceWith(right)
} else {
const left = binding.path.node.init
const init = t.binaryExpression(operator.substr(0, 1), left, right)
binding.path.get('init').replaceWith(init)
}
nodePath.remove()
}
}
}
}
},
}
return {
visitor: {
Program: (nodePath) => {
nodePath.traverse(evaluateVisitor)
},
VariableDeclarator: (nodePath) => {
nodePath.scope.crawl()
if (nodePath.get('id').isIdentifier()) {
const {name} = nodePath.node.id
if (name in nodePath.scope.bindings) {
const binding = nodePath.scope.bindings[name]
nodePath.remove()
}
}
}
}
}
}
console.log(transform(source, {plugins: [optimizePlugin]}).code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment