package bjc.dicelang.v1.ast.optimization; import bjc.dicelang.v1.ast.nodes.DiceASTType; import bjc.dicelang.v1.ast.nodes.IDiceASTNode; import bjc.dicelang.v1.ast.nodes.OperatorDiceNode; import bjc.utils.data.IHolder; import bjc.utils.data.ITree; import bjc.utils.data.Identity; import bjc.utils.data.TopDownTransformResult; import bjc.utils.data.Tree; /** * Condenses chained operations into a single level * * @author ben * */ public class OperationCondenser { /** * Condense chained similiar operations into a single level * * @param ast * The AST to condense * @return The condensed AST */ public static ITree condense(ITree ast) { return ast.topDownTransform(OperationCondenser::pickNode, OperationCondenser::doCondense); } private static ITree doCondense(ITree ast) { OperatorDiceNode operation = ast.transformHead((node) -> (OperatorDiceNode) node); IHolder canCondense = new Identity<>(true); ast.doForChildren((child) -> { if(canCondense.getValue()) { canCondense.replace(child.transformHead((node) -> { if(node.getType() == DiceASTType.OPERATOR) { if(operation.equals(node)) return true; return false; } return true; })); } }); if(!canCondense.getValue()) return ast; ITree condensedAST = new Tree<>(operation); ast.doForChildren((child) -> { if(child.getHead().getType() == DiceASTType.OPERATOR) { child.doForChildren((subChild) -> { condensedAST.addChild(subChild); }); } else { condensedAST.addChild(child); } }); return condensedAST; } private static TopDownTransformResult pickNode(IDiceASTNode node) { switch(node.getType()) { case LITERAL: return TopDownTransformResult.SKIP; case OPERATOR: return pickOperator((OperatorDiceNode) node); case VARIABLE: return TopDownTransformResult.SKIP; default: throw new UnsupportedOperationException("Attempted to traverse unknown node type " + node); } } private static TopDownTransformResult pickOperator(OperatorDiceNode node) { switch(node) { case ADD: case MULTIPLY: case SUBTRACT: case DIVIDE: case COMPOUND: return TopDownTransformResult.PUSHDOWN; case ARRAY: case ASSIGN: case GROUP: case LET: return TopDownTransformResult.PASSTHROUGH; default: throw new UnsupportedOperationException("Attempted to traverse unknown operator " + node); } } }