Skip to content

Instantly share code, notes, and snippets.

@w0rm
Last active June 4, 2019 06:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save w0rm/bf5bf3253f8babb63a5718f8c872b569 to your computer and use it in GitHub Desktop.
Save w0rm/bf5bf3253f8babb63a5718f8c872b569 to your computer and use it in GitHub Desktop.
A highly experimental codemod to speed the compiled Elm code
/**
* 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