-
-
Save w0rm/bf5bf3253f8babb63a5718f8c872b569 to your computer and use it in GitHub Desktop.
A highly experimental codemod to speed the compiled Elm code
This file contains 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
/** | |
* A highly experimental codemod, that applies some of the proposed optimizations from this post: | |
* https://dev.to/skinney/improving-elm-s-compiler-output-5e1h | |
* | |
* npm i -g jscodeshift | |
* jscodeshift -t transform.js elm.js | |
* | |
* ACHTUNG! Only works with the output from Elm 0.19.0. Use with caution, this may break your code! | |
* | |
*/ | |
module.exports = function(file, api, options) { | |
const j = api.jscodeshift; | |
const functions = new Map(); // Map(functionName, { arity, name }) | |
const tree = j(file.source); | |
tree.find(j.VariableDeclarator).forEach(path => { | |
// Unify Maybe Nothing and Just | |
if ( | |
path.node.id.type === "Identifier" && | |
path.node.id.name === "elm$core$Maybe$Nothing" | |
) { | |
path.node.init.properties.push( | |
j.property("init", j.identifier("a"), j.identifier("null")) | |
); | |
} | |
// Unify List Nil and Const | |
if ( | |
path.node.id.type === "Identifier" && | |
path.node.id.name === "_List_Nil" | |
) { | |
path.node.init.properties.push( | |
j.property("init", j.identifier("a"), j.identifier("null")) | |
); | |
path.node.init.properties.push( | |
j.property("init", j.identifier("b"), j.identifier("null")) | |
); | |
} | |
// Remember all F2..7 declarations and take out unwrapped functions | |
if ( | |
path.node.id.type === "Identifier" && | |
path.node.init && | |
path.node.init.type === "CallExpression" && | |
path.node.init.callee.type === "Identifier" && | |
path.node.init.callee.name.match(/^F[2-7]$/) && | |
path.node.init.arguments.length == 1 | |
) { | |
functions.set(path.node.id.name, { | |
arity: Number(path.node.init.callee.name.substr(1)), | |
name: path.node.id.name + "____original" | |
}); | |
const newNode = j.variableDeclaration("var", [ | |
j.variableDeclarator( | |
j.identifier(path.node.id.name + "____original"), | |
path.node.init.arguments[0] | |
) | |
]); | |
path.node.init.arguments = [ | |
j.identifier(path.node.id.name + "____original") | |
]; | |
path.parent.insertBefore(newNode); | |
} | |
}); | |
// Add re-declarations of the existing functions | |
tree.find(j.VariableDeclarator).forEach(path => { | |
if ( | |
path.node.id.type === "Identifier" && | |
path.node.init && | |
path.node.init.type === "Identifier" && | |
functions.has(path.node.init.name) | |
) { | |
functions.set(path.node.id.name, functions.get(path.node.init.name)); | |
} | |
}); | |
// Transform the A2..7 calls | |
return tree | |
.find(j.CallExpression) | |
.forEach(path => { | |
if ( | |
path.node.callee.type === "Identifier" && | |
path.node.callee.name.match(/^A[2-7]$/) && | |
path.node.arguments.length > 1 && | |
path.node.arguments[0].type === "Identifier" && | |
functions.has(path.node.arguments[0].name) && | |
functions.get(path.node.arguments[0].name).arity === | |
Number(path.node.callee.name.substr(1)) | |
) { | |
path.node.callee = j.identifier( | |
functions.get(path.node.arguments[0].name).name | |
); | |
path.node.arguments.shift(); | |
} | |
}) | |
.toSource(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment