package com.laytonsmith.core.compiler;
import com.laytonsmith.core.MethodScriptCompiler;
import com.laytonsmith.core.ParseTree;
import com.laytonsmith.core.constructs.CArray;
import com.laytonsmith.core.constructs.CFunction;
import com.laytonsmith.core.constructs.CSlice;
import com.laytonsmith.core.constructs.CString;
import com.laytonsmith.core.constructs.IVariable;
import com.laytonsmith.core.constructs.Target;
import com.laytonsmith.core.constructs.Variable;
import com.laytonsmith.core.exceptions.ConfigCompileException;
import com.laytonsmith.core.exceptions.ConfigCompileGroupException;
import java.io.File;
import java.util.List;
/**
*
*
*/
public class OptimizationUtilities {
/**
* Goes one deep, and pulls up like children. This is only for use where the
* same function being chained doesn't make sense, for instance, in the case
* of adding, add(2, add(2, add(2, 2))) should just turn into add(2, 2, 2,
* 2).
*
* @param children
* @param functionName
*/
public static void pullUpLikeFunctions(List<ParseTree> children, String functionName) {
int size = children.size() - 1;
for (int i = size; i >= 0; i--) {
ParseTree tree = children.get(i);
if (tree.getData() instanceof CFunction && tree.getData().val().equals(functionName)) {
//We can pull it up. Just go through the children and insert them here. Remove the node
//that was this child though.
children.remove(i);
for (int j = tree.getChildren().size() - 1; j >= 0; j--) {
children.add(i, tree.getChildAt(j));
}
}
}
}
/**
* This function takes a string script, and returns an equivalent, optimized script.
* @param script
* @return
* @throws ConfigCompileException
*/
public static String optimize(String script, File source) throws ConfigCompileException, ConfigCompileGroupException{
ParseTree tree = MethodScriptCompiler.compile(MethodScriptCompiler.lex(script, source, true));
StringBuilder b = new StringBuilder();
//The root always contains null.
for(ParseTree child : tree.getChildren()){
b.append(optimize0(child));
}
return b.toString();
}
private static String optimize0(ParseTree node){
if(node.getData() instanceof CFunction){
StringBuilder b = new StringBuilder();
boolean first = true;
b.append(((CFunction)node.getData()).val()).append("(");
for(ParseTree child : node.getChildren()){
if(!first){
b.append(",");
}
first = false;
b.append(optimize0(child));
}
b.append(")");
return b.toString();
} else if(node.getData() instanceof CString){
//strings
return new StringBuilder().append("'").append(node.getData().val().replaceAll("\t", "\\t").replaceAll("\n", "\\n").replace("\\", "\\\\").replace("'", "\\'")).append("'").toString();
} else if(node.getData() instanceof IVariable){
return ((IVariable)node.getData()).getVariableName();
} else if(node.getData() instanceof Variable){
return ((Variable)node.getData()).getVariableName();
} else if(node.getData() instanceof CSlice){
return node.getData().val();
} else if(node.getData() instanceof CArray){
//It's a hardcoded array. This only happens in the course of optimization, if
//the optimizer adds a new array. We still need to handle it appropriately though.
//The values in the array will be constant, guaranteed.
StringBuilder b = new StringBuilder();
b.append("array(");
boolean first = true;
CArray n = (CArray)node.getData();
for(String key : n.stringKeySet()){
if(!first){
b.append(",");
}
first = false;
b.append(optimize0(new ParseTree(n.get(key, Target.UNKNOWN), node.getFileOptions())));
}
b.append(")");
return b.toString();
} else {
//static
return node.getData().toString();
}
}
}