package cd.transform;

import cd.ir.Ast.ClassDecl;
import cd.ir.Ast.MethodDecl;
import cd.ir.Symbol.TypeSymbol;
import cd.transform.optimizers.*;

import java.util.List;

public class AstOptimizer {
	private static final IOptimizer[] optimizers = {
			new TrivialOpRemoval(),  // 100% accuracy
			new BranchElimination(), // 100% accuracy
			new BlockRemoval(),      // 100% accuracy
			new ConstantPropagator(),//  98% accuracy on its own
//			new WriteOnlyVarRemoval(),
	};

	private static final IGlobalOptimizer[] globalOptimizers = {
//			new UnusedClassRemoval(),//  98% accuracy on its own
//			new UnusedMethodRemoval(),
	};

	public void go(List<ClassDecl> classDeclList, List<TypeSymbol> allTypeSymbols) {
		// Local optimizations inside methods/blocks always comes first
		for (ClassDecl classDecl : classDeclList) {
			for (MethodDecl methodDecl : classDecl.methods()) {
				boolean changed = true;
				while (changed) {
					changed = false;
					for (IOptimizer optimizer : optimizers) {
						changed |= optimizer.go(methodDecl.cfg);
					}
				}
			}
		}

		boolean globalChange = true;
		while (globalChange) {
			globalChange = false;
			for (IGlobalOptimizer globalOptimizer : globalOptimizers) {
				globalChange |= globalOptimizer.go(classDeclList, allTypeSymbols);
			}
		}
	}
}
