package cd.transform.analysis;

import cd.ir.Ast;
import cd.ir.Ast.Assign;
import cd.ir.CompileTimeEvaluator;
import cd.ir.ControlFlowGraph;
import cd.ir.Symbol.VariableSymbol;

import java.util.Map;
import java.util.Optional;

public class ArraySizeAnalysis extends MaybeFlowAnalysis<Integer> {

	public ArraySizeAnalysis(ControlFlowGraph cfg) {
		super(cfg, false, true);
	}

	@Override
	protected MaybeC<Integer> defaultInit(VariableSymbol varSym) {
		return MaybeC.notConstant();
	}

	@Override
	public void transferStmt(Ast.Stmt stmt, Map<VariableSymbol, MaybeC<Integer>> state) {
		CompileTimeEvaluator cte = new CompileTimeEvaluator();
		if (stmt instanceof Assign) {
			Assign assign = (Assign) stmt;
			if (assign.right() instanceof Ast.NewArray) {
				Ast.NewArray newArray = (Ast.NewArray) assign.right();
				VariableSymbol sym = getVarSym(assign.left());
				if (sym == null) return;
				Optional<Integer> arraySize = cte.calc(newArray.arg());
				if (arraySize.isPresent()) {
					state.put(sym, MaybeC.value(arraySize.get()));
				} else {
					state.get(sym).setNotConstant();
				}
			}
		}
	}

	private VariableSymbol getVarSym(Ast.Expr expr) {
		if (expr instanceof Ast.Var) {
			return ((Ast.Var) expr).sym;
		} else if (expr instanceof Ast.Field) {
			return ((Ast.Field) expr).sym;
		}
		return null;
	}

}
