package ai.domain.interval;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.ArrayAccess;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.CharacterLiteral;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.ConditionalExpression;
import org.eclipse.jdt.core.dom.ConstructorInvocation;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.InstanceofExpression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.NullLiteral;
import org.eclipse.jdt.core.dom.NumberLiteral;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.jdt.core.dom.SuperFieldAccess;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
import ai.common.Pair;
import ai.domain.AbstractSemanticsIntf;
import ai.domain.Variable;
import ai.domain.bool.Bool;
import ai.domain.expressions.MainExpressionEvaluator;
import ai.domain.expressions.bool.BooleanEvaluationState;
import ai.domain.expressions.bool.BooleanEvaluator;
import ai.domain.expressions.bool.BooleanExpressionSemantics;
import ai.domain.expressions.integer.BackwardExpressionSemantics;
import ai.domain.generic.GenericReverseExpressionSemantics;
import ai.domain.generic.NonRelationalDomain;
import ai.domain.intervals.eval.EvaluationUtils;
import ai.domain.widening.DefaultWideningOperator;
import ai.domain.widening.WideningOperator;
public class IntervalsSemantics implements AbstractSemanticsIntf<NonRelationalDomain<Interval>> {
private class MyBooleanSemantics implements BooleanExpressionSemantics<NonRelationalDomain<Interval>> {
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, ArrayAccess node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, FieldAccess node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, InstanceofExpression node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, MethodInvocation node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, SimpleName node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, QualifiedName node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, NullLiteral node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, SuperFieldAccess node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, SuperMethodInvocation node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, ClassInstanceCreation node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanNode(
NonRelationalDomain<Interval> input, CastExpression node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processComparison(
NonRelationalDomain<Interval> input, InfixExpression node) {
return defaultEval.evaluateComparison(input, node);
}
@Override
public NonRelationalDomain<Interval> processBooleanAssignment(NonRelationalDomain<Interval> input,
Expression toWhat, Bool value) {
return defaultEval.evaluate(toWhat, input);
}
@Override
public NonRelationalDomain<Interval> newBooleanVariable(NonRelationalDomain<Interval> input, Variable var,
Bool initialValurOrNull, boolean isArgument) {
return input;
}
@Override
public BooleanEvaluationState<NonRelationalDomain<Interval>> processBooleanBoxing(
NonRelationalDomain<Interval> input, Assignment node) {
return BooleanEvaluator.createOutput(input, Bool.TOP);
}
}
private class MyIntegerSemantics implements
IntervalsExpressionSemantics<Pair<Interval, NonRelationalDomain<Interval>>> {
@Override
public Pair<Interval, NonRelationalDomain<Interval>> newIntegerVariable(
Pair<Interval, NonRelationalDomain<Interval>> input, Variable variable, boolean isArgument) {
Interval value = input.left;
if (value == null)
value = Interval.TOP;
return Pair.create(value, input.right.addNewVariable(variable, value, isArgument));
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, ArrayAccess node) {
return Pair.create(Interval.TOP, defaultEval.evaluate(node.getIndex(), input.right));
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, FieldAccess node) {
IntervalValue value = EvaluationUtils.tryGetIntervalValue(node);
return Pair.create(value != null ? new Interval(value) : Interval.TOP, input.right);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, MethodInvocation node) {
NonRelationalDomain<Interval> output = input.right;
for (Object arg : node.arguments())
output = defaultEval.evaluate((Expression) arg, output);
return Pair.create(Interval.TOP, output);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, SimpleName node) {
Interval value;
if (EvaluationUtils.isIntegerType(node)){
IntervalValue aValue = EvaluationUtils.tryGetIntervalValue(node);
if (aValue != null) { // a constant??
value = new Interval(aValue);
} else {// variable??
Variable var = EvaluationUtils.tryGetVariable(node);
if (var == null) { // not a variable, we know nothing :(
value = Interval.TOP;
} else
value = input.right.getValueFor(var);
}
} else // unboxing
value = Interval.TOP;
return Pair.create(value, input.right);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, QualifiedName node) {
IntervalValue aValue = EvaluationUtils.tryGetIntervalValue(node);
return Pair.create((aValue != null) ? new Interval(aValue) : Interval.TOP, input.right);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, SuperFieldAccess node) {
IntervalValue value = EvaluationUtils.tryGetIntervalValue(node);
return Pair.create(value != null ? new Interval(value) : Interval.TOP, input.right);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, SuperMethodInvocation node) {
NonRelationalDomain<Interval> output = input.right;
for (Object arg : node.arguments())
output = defaultEval.evaluate((Expression) arg, output);
return Pair.create(Interval.TOP, output);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, ConditionalExpression node) {
return EvaluationUtils.evaluateConditionalExpression(node, beval, input, ieval);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, ClassInstanceCreation node) {
NonRelationalDomain<Interval> output = input.right;
for (Object arg : node.arguments())
output = defaultEval.evaluate((Expression) arg, output);
return Pair.create(Interval.TOP, output);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, CastExpression node) {
NonRelationalDomain<Interval> output = defaultEval.evaluate(node.getExpression(), input.right);
return Pair.create(Interval.TOP, output);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, NullLiteral node) {
return Pair.create(Interval.TOP, input.right);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, NumberLiteral node, long value) {
return Pair.create(new Interval(value, value), input.right);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerNode(
Pair<Interval, NonRelationalDomain<Interval>> input, CharacterLiteral node, long value) {
return Pair.create(new Interval(value, value), input.right);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerValueChange(
Pair<Interval, NonRelationalDomain<Interval>> input, Expression ofWhat, int delta,
boolean postfixOrPrefix) {
Interval valueBeforeChange = input.left;
Interval valueAfterChange = sem.delta(valueBeforeChange, delta);
Variable var = EvaluationUtils.tryGetVariable(ofWhat);
NonRelationalDomain<Interval> output = input.right;
if (var != null && EvaluationUtils.isIntegerType(ofWhat))
output = output.updateVariable(var, valueAfterChange);
return Pair.create(postfixOrPrefix ? valueBeforeChange : valueAfterChange, output);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerUnaryPlus(
Pair<Interval, NonRelationalDomain<Interval>> input) {
return input;
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerUnaryMinus(
Pair<Interval, NonRelationalDomain<Interval>> input) {
return input.setLeft(sem.minus(input.left));
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerUnaryComplement(
Pair<Interval, NonRelationalDomain<Interval>> input) {
return input.setLeft(sem.complement(input.left));
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerAssignment(
Pair<Interval, NonRelationalDomain<Interval>> input, Expression toWhat) {
Variable var = EvaluationUtils.tryGetVariable(toWhat);
if (var != null)
return input.setRight(input.right.updateVariable(var, input.left));
else
return input;
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processIntegerBoxing(
Pair<Interval, NonRelationalDomain<Interval>> input, Assignment node) {
NonRelationalDomain<Interval> res = defaultEval.evaluate(node.getLeftHandSide(), input.right);
res = defaultEval.evaluate(node.getRightHandSide(), res);
return Pair.create(Interval.TOP, res);
}
@Override
public Pair<Interval, NonRelationalDomain<Interval>> processFloatNode(
Pair<Interval, NonRelationalDomain<Interval>> input, Expression node) {
// TODO Auto-generated method stub
NonRelationalDomain<Interval> res = defaultEval.evaluate(node, input.right);
return Pair.create(Interval.TOP, res);
}
}
private class MyIntergerBackwardSemantics implements
BackwardExpressionSemantics<NonRelationalDomain<Interval>, Interval> {
@Override
public NonRelationalDomain<Interval> processIntegerNode(NonRelationalDomain<Interval> input, SimpleName node,
Interval value) {
if (input.isBottom())
return input;
if (value.isBottom())
return input.getBottom();
Variable var = EvaluationUtils.tryGetVariable(node);
if (var == null) // no change in state
return input;
else
return input.updateVariable(var, value);
}
@Override
public Interval getConstantValue(long value) {
return new Interval(value, value);
}
}
private final MainExpressionEvaluator<NonRelationalDomain<Interval>> defaultEval;
private final BooleanEvaluator<NonRelationalDomain<Interval>> beval;
private final IntervalExpressionSemantics sem = new IntervalExpressionSemantics();
private final IntervalComparisonEvaluator<NonRelationalDomain<Interval>> iCondEval;
private final IntervalExpressionEvaluator<NonRelationalDomain<Interval>> ieval;
public IntervalsSemantics() {
MyBooleanSemantics bSemantics = new MyBooleanSemantics();
this.beval = new BooleanEvaluator<NonRelationalDomain<Interval>>(bSemantics);
MyIntegerSemantics eSemantics = new MyIntegerSemantics();
MyIntergerBackwardSemantics backSemantics = new MyIntergerBackwardSemantics();
this.defaultEval = MainExpressionEvaluator.create(this.beval);
defaultEval.addEvaluator(beval);
this.ieval = IntervalExpressionEvaluator.create(eSemantics, sem);
defaultEval.addEvaluator(ieval);
GenericReverseExpressionSemantics<Interval> bes = new GenericReverseExpressionSemantics<Interval>(sem);
iCondEval = IntervalComparisonEvaluator.create(ieval, new IntervalBackwardTestSemantics(), bes, backSemantics);
defaultEval.addComparisonEvaluator(iCondEval);
}
@Override
public NonRelationalDomain<Interval> processEmptyEdge(NonRelationalDomain<Interval> input, List<SimpleName> variablesToRemove) {
for(SimpleName name: variablesToRemove){
Variable var = EvaluationUtils.tryGetVariable(name);
if (var == null)
continue;
input = input.removeVariable(var);
}
return input;
}
@Override
public final NonRelationalDomain<Interval> processNewVariable(NonRelationalDomain<Interval> input,
SimpleName name, Expression initializerOrNull, boolean asAssignment) {
return defaultEval.evaluate(name, initializerOrNull, input, asAssignment);
}
@Override
public NonRelationalDomain<Interval> getInitialValue() {
return NonRelationalDomain.getInitialValue();
}
@Override
public NonRelationalDomain<Interval> processExpression(NonRelationalDomain<Interval> input, Expression expression) {
return defaultEval.evaluate(expression, input);
}
@Override
public Pair<NonRelationalDomain<Interval>, NonRelationalDomain<Interval>> processCondition(NonRelationalDomain<Interval> input,
Expression conditionOrNull) {
if (conditionOrNull == null)
return Pair.create(input, input);
BooleanEvaluationState<NonRelationalDomain<Interval>> x = beval.evaluateCondition(input, conditionOrNull);
return Pair.create(x.conditionMet, x.conditionNotMet);
}
@Override
public NonRelationalDomain<Interval> processArgument(NonRelationalDomain<Interval> input, SimpleName argument) {
return defaultEval.evaluateNewArgument(argument, input);
}
@Override
public NonRelationalDomain<Interval> processFinallyOrException(NonRelationalDomain<Interval> input,
SingleVariableDeclaration excOrNull) {
if (input.isBottom())
return input;
for (Variable var : input.getVariables())
input = input.updateVariable(var, new Interval(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
return input;
}
@Override
public NonRelationalDomain<Interval> processConstructorInvocation(NonRelationalDomain<Interval> input,
ConstructorInvocation constructorInvocation) {
if (constructorInvocation.arguments() == null)
return input;
for(Object arg: constructorInvocation.arguments())
input = defaultEval.evaluate((Expression)arg, input);
return input;
}
@Override
public NonRelationalDomain<Interval> processSuperConstructorInvocation(NonRelationalDomain<Interval> input,
SuperConstructorInvocation superConstructorInvocation) {
if (superConstructorInvocation.arguments() == null)
return input;
for(Object arg: superConstructorInvocation.arguments())
input = defaultEval.evaluate((Expression)arg, input);
return input;
}
@Override
public Pair<NonRelationalDomain<Interval>, ArrayList<NonRelationalDomain<Interval>>> processSwitchCases(
NonRelationalDomain<Interval> input, Expression expr, Expression[] switchCases) {
if (!EvaluationUtils.isIntegerType(expr))
return EvaluationUtils.defaultSwitchProcess(defaultEval, input, expr, switchCases);
return EvaluationUtils.evaluateSwitchInteger(input, expr, switchCases, iCondEval);
}
@Override
public WideningOperator<NonRelationalDomain<Interval>> getWideningOperator() {
return DefaultWideningOperator.create();
}
}