package cd.transform.analysis;

import cd.ir.Ast;
import cd.ir.Ast.Assign;
import cd.ir.Ast.NewArray;
import cd.ir.Ast.NewObject;
import cd.ir.ControlFlowGraph;
import cd.ir.ExprVisitor;
import cd.ir.Symbol.VariableSymbol;

import java.util.Map;

public class NullAnalysis extends MaybeFlowAnalysis<Boolean> {
	public NullAnalysis(ControlFlowGraph cfg) {
		super(cfg, false, true);
	}

	@Override
	protected MaybeC<Boolean> defaultInit(VariableSymbol varSym) {
		if (varSym.kind == VariableSymbol.Kind.LOCAL)
			return MaybeC.value(true);
		else
			return MaybeC.notConstant();
	}

	@Override
	public void transferStmt(Ast.Stmt stmt, Map<VariableSymbol, MaybeC<Boolean>> state) {
		if (stmt instanceof Assign) {
			Assign assign = (Assign) stmt;
			if (assign.left() instanceof Ast.Var &&
					state.containsKey(((Ast.Var) assign.left()).sym)) {
				VariableSymbol sym = ((Ast.Var) assign.left()).sym;
				if (!state.containsKey(sym)) return;
				Boolean rightHandSide = new NullVisitor().visit(assign.right(), null);
				if (rightHandSide != null)
					state.put(sym, MaybeC.value(rightHandSide));
				else
					state.get(sym).setNotConstant();
			}
		}
	}

	static class NullVisitor extends ExprVisitor<Boolean, Void> {
		@Override
		public Boolean newObject(NewObject ast, Void arg) {
			return false;
		}

		@Override
		public Boolean newArray(NewArray ast, Void arg) {
			return false;
		}

		@Override
		public Boolean nullConst(Ast.NullConst ast, Void arg) {
			return true;
		}
	}
}
