package ai.domain.boxes;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.jdt.core.dom.ConstructorInvocation;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import ai.common.Pair;
import ai.domain.AbstractSemanticsIntf;
import ai.domain.Variable;
import ai.domain.bool.Bool;
import ai.domain.boolintv.BoolIntvSemantics;
import ai.domain.generic.NonRelationalDomain;
import ai.domain.generic.ProductDomain;
import ai.domain.interval.Interval;
import ai.domain.intervals.eval.EvaluationUtils;
import ai.domain.widening.WideningOperator;
public class IntegerBoxesSemantics implements AbstractSemanticsIntf<ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>>{
private static final ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> BOTTOM = ProductDomain.getStaticBottom();
public static class IntegerBoxesSemanticsException extends RuntimeException {
private static final long serialVersionUID = 6663131240946755203L;
public IntegerBoxesSemanticsException(String format, Object... args) {
super(String.format(format, args));
}
}
private static class ResultStore {
public NonRelationalDomain<Bool> boolPart = NonRelationalDomain.getStaticBottom();
public IntegerBoxes boxesPart = IntegerBoxes.BOTTOM;
public void update(ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> boolIntvBox) {
if (boolIntvBox.isBottom())
return;
boolPart = boolPart.join(boolIntvBox.getLeft());
boxesPart = boxesPart.join(IntegerBoxesHelper.fromIntervalBox(boolIntvBox.getRight()));
}
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> getResult(){
if (boolPart.isBottom() || boxesPart.isBottom())
return BOTTOM;
return ProductDomain.create(boolPart, boxesPart);
}
}
private final BoolIntvSemantics boolIntvSem;
private final String wideningDescription;
public IntegerBoxesSemantics(String wideningDescription) {
this.boolIntvSem = new BoolIntvSemantics();
this.wideningDescription = wideningDescription;
}
private interface Applier {
public ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> apply(ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> arg);
}
private ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> apply(ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input,
Applier applier) {
if (input.isBottom())
return input;
ResultStore rs = new ResultStore();
for(NonRelationalDomain<Interval> box: IntegerBoxesHelper.split(input.getRight()))
rs.update(applier.apply(ProductDomain.create(input.getLeft(), box)));
return rs.getResult();
}
@Override
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> processArgument(ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input,
final SimpleName argument) {
return apply(input, new Applier() {
@Override
public ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> apply(
ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> arg) {
return boolIntvSem.processArgument(arg, argument);
}
});
}
@Override
public Pair<ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>, ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>> processCondition(ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input,
final Expression conditionOrNull) {
if (conditionOrNull == null)
return Pair.create(input, input);
NonRelationalDomain<Bool> positiveBool = NonRelationalDomain.getStaticBottom();
IntegerBoxes positiveBoxes = IntegerBoxes.BOTTOM;
NonRelationalDomain<Bool> negativeBool = NonRelationalDomain.getStaticBottom();
IntegerBoxes negativeBoxes = IntegerBoxes.BOTTOM;
List<NonRelationalDomain<Interval>> split = IntegerBoxesHelper.split(input.getRight());
for(NonRelationalDomain<Interval> box: split) {
Pair<ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>>, ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>>> x = boolIntvSem.processCondition(ProductDomain.create(input.getLeft(), box), conditionOrNull);
if (!x.left.isBottom()) {
positiveBool = positiveBool.join(x.left.getLeft());
positiveBoxes = positiveBoxes.join(IntegerBoxesHelper.fromIntervalBox(x.left.getRight()));
}
if (!x.right.isBottom()) {
negativeBool = negativeBool.join(x.right.getLeft());
negativeBoxes = negativeBoxes.join(IntegerBoxesHelper.fromIntervalBox(x.right.getRight()));
}
}
ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> positive;
if (positiveBool.isBottom() || positiveBoxes.isBottom())
positive = input.getBottom();
else
positive = ProductDomain.create(positiveBool, positiveBoxes);
ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> negative;
if (negativeBool.isBottom() || negativeBoxes.isBottom())
negative = input.getBottom();
else
negative = ProductDomain.create(negativeBool, negativeBoxes);
return Pair.create(positive, negative);
}
@Override
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> processEmptyEdge(ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input,
List<SimpleName> variablesToRemove) {
if (input.isBottom())
return input;
NonRelationalDomain<Bool> bools = input.getLeft();
List<Variable> boxVariablesToRemove = new LinkedList<Variable>();
for(SimpleName name: variablesToRemove){
Variable var = EvaluationUtils.tryGetVariable(name);
if (var == null)
continue;
if (bools.containsValue(var))
bools = bools.removeVariable(var);
else
boxVariablesToRemove.add(var);
}
IntegerBoxes boxes = IntegerBoxesHelper.removeVariables(input.getRight(), boxVariablesToRemove);
return ProductDomain.create(bools, boxes);
}
@Override
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> processExpression(ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input,
final Expression expression) {
return apply(input, new Applier() {
@Override
public ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> apply(
ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> arg) {
return boolIntvSem.processExpression(arg, expression);
}
});
}
@Override
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> processNewVariable(ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input,
final SimpleName name, final Expression initializerOrNull, final boolean asAssignment) {
return apply(input, new Applier() {
@Override
public ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> apply(
ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> arg) {
return boolIntvSem.processNewVariable(arg, name, initializerOrNull, asAssignment);
}
});
}
@Override
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> getInitialValue() {
NonRelationalDomain<Bool> initialBools = NonRelationalDomain.getInitialValue();
IntegerBoxes initialBoxes = IntegerBoxes.getInitialValue();
return ProductDomain.create(initialBools, initialBoxes);
}
@Override
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> processFinallyOrException(
ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input, SingleVariableDeclaration excOrNull) {
if (input.isBottom())
return input;
//process booleans
NonRelationalDomain<Bool> bools = input.getLeft();
for(Variable var: bools.getVariables())
bools = bools.updateVariable(var, Bool.TOP);
//process integers
NonRelationalDomain<Interval> intv = NonRelationalDomain.getInitialValue();
for(Variable var: input.getRight().getVariables())
intv = intv.addNewVariable(var, new Interval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), false);
IntegerBoxes boxes = IntegerBoxesHelper.fromIntervalBox(intv);
return ProductDomain.create(bools, boxes);
}
@Override
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> processConstructorInvocation(
ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input, final ConstructorInvocation constructorInvocation) {
return apply(input, new Applier() {
@Override
public ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> apply(
ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> arg) {
return boolIntvSem.processConstructorInvocation(arg, constructorInvocation);
}
});
}
@Override
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> processSuperConstructorInvocation(
ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input, final SuperConstructorInvocation superConstructorInvocation) {
return apply(input, new Applier() {
@Override
public ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> apply(
ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>> arg) {
return boolIntvSem.processSuperConstructorInvocation(arg, superConstructorInvocation);
}
});
}
@Override
public Pair<ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>, ArrayList<ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>>> processSwitchCases(
ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> input, Expression expr, Expression[] switchCases) {
ArrayList<ResultStore> results = new ArrayList<IntegerBoxesSemantics.ResultStore>(switchCases.length + 1);
for(int i=0; i< switchCases.length + 1 ; i++)
results.add(new ResultStore());
for(NonRelationalDomain<Interval> box: IntegerBoxesHelper.split(input.getRight())) {
Pair<ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>>, ArrayList<ProductDomain<NonRelationalDomain<Bool>, NonRelationalDomain<Interval>>>> boxResult = boolIntvSem.processSwitchCases(ProductDomain.create(input.getLeft(), box), expr, switchCases);
results.get(0).update(boxResult.left);
for(int i=0; i< switchCases.length; i++)
results.get(i+1).update(boxResult.right.get(i));
}
ArrayList<ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>> casesResults = new ArrayList<ProductDomain<NonRelationalDomain<Bool>,IntegerBoxes>>(switchCases.length);
for(int i=0; i< switchCases.length; i++)
casesResults.add(results.get(i+1).getResult());
return Pair.create(results.get(0).getResult(), casesResults);
}
@Override
public WideningOperator<ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>> getWideningOperator() {
return BoxesWideningFactory.getWideningOperator(wideningDescription);
}
public String toString(){
return this.getClass().toString() + "(" + wideningDescription + ")";
}
}