@alu0101350158/constant-folding
Version:
Constant Folding javascript code
184 lines (170 loc) • 5.27 kB
JavaScript
// See https://github.com/babel/minify/tree/master/packages/babel-plugin-minify-constant-folding
const fs = require("fs");
const deb = require('../src/deb.js');
const escodegen = require("escodegen");
const espree = require("espree");
const estraverse = require("estraverse");
const { Console } = require("console");
;
module.exports = constantFolding;
/**
* A function that takes js code in a string
* and applies constant folding to transform it
* @param {string} code A string containing the js code
*
* @returns {string} Returns the transformed code as a string
*/
function constantFolding(code) {
const t = espree.parse(code, { ecmaVersion: 6, loc: false });
estraverse.traverse(t, {
leave: function (n) {
if (
n.type == "MemberExpression" &&
n.object.type == "ArrayExpression") {
if (n.property.name == "length" ) {
replaceByArrayLength(n);
} else if (n.property.type == "Literal" || n.property.type == "BinaryExpression") {
replaceByArraySquare(n);
}
}
if (
n.type == "CallExpression" &&
n.callee.type == "MemberExpression" && n.callee.object.type == "ArrayExpression"
) {
if (n.callee.property.name == "concat" ) {
replaceByArrayConcat(n);
} else if (n.callee.property.name == "join") {
if (n.arguments[0] != null) {
replaceByArrayJoin(n, n.arguments[0].value);
} else {
replaceByArrayJoin(n);
}
} else if (n.callee.property.name == "pop") {
replaceByArrayPop(n);
}
}
if (
n.type == "BinaryExpression" &&
n.left.type == "Literal" && n.right.type == "Literal"
) { replaceByLiteral(n); }
},
});
deb(t);
let c = escodegen.generate(t);
return c;
}
/**
* A function that takes an ast node and evaluates
* it's binary expresion in order to replace it with
* it's value
*
* @param code An ast node
*/
function replaceByLiteral(n) {
n.type = "Literal";
n.value = eval(`${n.left.raw} ${n.operator} ${n.right.raw}`);
n.raw = String(n.value);
delete n.left;
delete n.right;
}
/**
* A function that takes an ast node and evaluates
* it's member expresion in order to replace it with
* it's value
* In this case the member expression is array.length
* @param code An ast node
*/
function replaceByArrayLength(n) {
n.type = "Literal";
n.value = n.object.elements.length;
n.raw = String(n.value);
delete n.object;
delete n.property;
}
/**
* A function that takes an ast node and evaluates
* it's member expresion in order to replace it with
* it's value
* In this case the member expression is array.join().
* @param code An ast node
*/
function replaceByArrayJoin(n, separator = ',') {
n.type = "Literal"
let resultstring = "";
for (let i = 0; i < n.callee.object.elements.length; i++) {
resultstring += n.callee.object.elements[i].value;
if (i >= n.callee.object.elements.length - 1) break;
resultstring += separator;
}
n.value = resultstring;
n.raw = String(resultstring);
}
/**
* A function that takes an ast node and evaluates
* it's member expresion in order to replace it with
* it's value
* In this case the member expression is array[].
* @param code An ast node
*/
function replaceByArraySquare(n){
n.type = "Literal";
let position = 0;
if (n.property.type == "BinaryExpression") {
position = eval(`${n.property.left.raw} ${n.property.operator} ${n.property.right.raw}`);
} else {
position = n.property.value;
}
for (let i = 0; i < n.object.elements.length; i++){
if(i == position) {
n.value = n.object.elements[i].value;
}
}
n.raw = String(n.value);
delete n.object
delete n.property;
}
/**
* A function that takes an ast node and evaluates
* it's member expresion in order to replace it with
* it's value
* In this case the member expression is array.pop().
* @param code An ast node
*/
function replaceByArrayPop(n) {
n.type = n.callee.object.elements[n.callee.object.elements.length -1].type;
if(n.type == "Identifier") {
n.name = n.callee.object.elements[n.callee.object.elements.length -1].name;
} else if (n.type == "Literal") {
n.value = n.callee.object.elements[n.callee.object.elements.length -1].value;
n.raw = String(n.value);
}
delete n.callee;
delete n.arguments;
}
/**
* A function that takes an ast node and evaluates
* it's member expresion in order to replace it with
* it's value
* In this case the member expression is array.concat().
* @param code An ast node
*/
function replaceByArrayConcat(n) {
n.type = "ArrayExpression";
let elements = [];
for (let i = 0; i < n.callee.object.elements.length; i++) {
//console.log(n.callee.object.elements[i].raw)
elements.push(n.callee.object.elements[i]);
}
for (let i = 0; i < n.arguments.length; i++) {
if(n.arguments[i].type == "ArrayExpression") {
for (let j = 0; j < n.arguments[i].elements.length; j++) {
elements.push(n.arguments[i].elements[j]);
}
} else {
elements.push(n.arguments[i]);
}
}
n.elements = elements;
delete n.callee;
delete n.arguments;
}