Package ai.domain.interval

Source Code of ai.domain.interval.IntervalComparisonEvaluator$IntegerComparisonEvaluatorException

package ai.domain.interval;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;

import org.apache.log4j.Logger;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ArrayAccess;
import org.eclipse.jdt.core.dom.ArrayCreation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.BooleanLiteral;
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.Expression;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
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.ParenthesizedExpression;
import org.eclipse.jdt.core.dom.PostfixExpression;
import org.eclipse.jdt.core.dom.PrefixExpression;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.SuperFieldAccess;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
import org.eclipse.jdt.core.dom.ThisExpression;
import org.eclipse.jdt.core.dom.TypeLiteral;
import org.eclipse.jdt.core.dom.VariableDeclarationExpression;

import ai.common.Pair;
import ai.domain.DomainIntf;
import ai.domain.expressions.AbstractExpressionVisitor;
import ai.domain.expressions.bool.BooleanEvaluationState;
import ai.domain.expressions.bool.ComparisonEvaluatorIntf;
import ai.domain.expressions.integer.BackwardExpressionSemantics;
import ai.domain.expressions.integer.BackwardTestSemantics;
import ai.domain.expressions.integer.ExpressionEvaluationMap;
import ai.domain.generic.GenericReverseExpressionSemantics;
import ai.domain.intervals.eval.EvaluationUtils;

public class IntervalComparisonEvaluator<DI extends DomainIntf<DI>> implements
    ComparisonEvaluatorIntf<DI> {
  private final static Logger log = Logger.getLogger(IntervalComparisonEvaluator.class.getName());

  private static final int ITERATION_LIMIT = 10;

  public static class IntegerComparisonEvaluatorException extends RuntimeException {
    private static final long serialVersionUID = 4875197670183556218L;

    public IntegerComparisonEvaluatorException(String format, Object... args) {
      super(String.format(format, args));
    }
  }

  private static class WeWontHandleThis extends RuntimeException {
    private final Expression node;

    private static final long serialVersionUID = -8956297034163496655L;

    public WeWontHandleThis(Expression node) {
      super(String.format("Unhandled node '%s'", node));
      this.node = node;
    }
  }

  protected void ensureCorrectType(Expression expr) {
    if (!EvaluationUtils.isIntegerType(expr))
      throw new IntegerComparisonEvaluatorException("I shouldn't be here? '%s'", expr);
  }

  private class ReverseExpressionWalker extends AbstractExpressionVisitor {

    private DI state; // IMPORTANT: we do not change state!!
    private ExpressionEvaluationMap<Interval> nodeValuation;
    private Interval newValue;

    private RuntimeException unhandledNodeException(Expression node) {
      return new IntegerComparisonEvaluatorException("Unhandled node '%s'", node);
    }

    public DI process(Interval newValue, DI input, Expression node, ExpressionEvaluationMap<Interval> valuation) {
      this.state = input;
      this.nodeValuation = valuation;
      this.newValue = newValue;
      node.accept(this);
      return this.state;
    }

    @Override
    public boolean preVisit2(ASTNode node) {
      if (!(node instanceof Expression))
        throw new IntegerComparisonEvaluatorException("SHouldn't be here '%s'", node);
      Expression expr = (Expression) node;
      Interval existingValue = nodeValuation.get(expr);
      // we do not go inside if it is not required (note we do not change
      // state)
      return !newValue.equals(existingValue);
    }

    @Override
    public boolean visit(ArrayAccess node) {
      // TODO Auto-generated method stub
      throw new WeWontHandleThis(node);
//     
//      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(ArrayCreation node) {
      // TODO Auto-generated method stub
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(ArrayInitializer node) {
      // TODO Auto-generated method stub
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(Assignment node) {
      // TODO Auto-generated method stub
      throw new WeWontHandleThis(node);
//     
//      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(BooleanLiteral node) {
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(CastExpression node) {
      // TODO Auto-generated method stub
      throw new WeWontHandleThis(node);
//      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(CharacterLiteral node) {
      long value = EvaluationUtils.getIntegerValue(node);
      Interval v = backwardExprSemantics.getConstantValue(value);
      if (!v.equals(newValue))
        throw new IntegerComparisonEvaluatorException("Hmmm, something strange??");
      return false;
//     
//      // TODO Auto-generated method stub
//      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(ClassInstanceCreation node) {
      // TODO Auto-generated method stub
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(ConditionalExpression node) {
      // TODO Auto-generated method stub
      throw new WeWontHandleThis(node);
//      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(FieldAccess node) {
      throw new WeWontHandleThis(node);
//      // TODO Auto-generated method stub
//      throw unhandledNodeException(node);
    }

    private ArrayList<Expression> getOperands(InfixExpression node) {
      ArrayList<Expression> result = new ArrayList<Expression>(2 + (node.hasExtendedOperands() ? node
          .extendedOperands().size() : 0));
      result.add(node.getLeftOperand());
      result.add(node.getRightOperand());
      if (node.hasExtendedOperands())
        for (Object elem : node.extendedOperands())
          result.add((Expression) elem);
      return result;
    }

    private Pair<Interval, Interval> applyReverseOperator(InfixExpression.Operator op, Interval leftArg, Interval rightArg, Interval oldResult,
        Interval newResult) {
      if (newResult.equals(oldResult))
        return Pair.create(leftArg, rightArg);
      if (op == InfixExpression.Operator.PLUS)
        return res.backwardPlus(leftArg, rightArg, newResult);
      if (op == InfixExpression.Operator.MINUS)
        return res.backwardMinus(leftArg, rightArg, newResult);
      if (op == InfixExpression.Operator.TIMES)
        return res.backwardTimes(leftArg, rightArg, newResult);
      if (op == InfixExpression.Operator.DIVIDE)
        return res.backwardDivide(leftArg, rightArg, newResult);
      //we do not change anything since for these operators
      if (op == InfixExpression.Operator.AND)
        return Pair.create(leftArg, rightArg);
      if (op == InfixExpression.Operator.RIGHT_SHIFT_SIGNED)
        return Pair.create(leftArg, rightArg);
      if (op == InfixExpression.Operator.OR)
        return Pair.create(leftArg, rightArg);
      if (op == InfixExpression.Operator.REMAINDER)
        return Pair.create(leftArg, rightArg);
      if (op == InfixExpression.Operator.LEFT_SHIFT)
        return Pair.create(leftArg, rightArg);
      if (op == InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED)
        return Pair.create(leftArg, rightArg);
      throw new IntegerComparisonEvaluatorException("Unhandled operator '%s'", op);
    }

    private void processChild(Expression child, Interval newChildValue) {
      this.newValue = newChildValue;
      child.accept(this);
    }

    private void processOperandsHelper(InfixExpression.Operator op, ListIterator<Interval> valueIterator,
        ListIterator<Expression> operandsIterator, Interval oldCummulativeValue, Interval newCummulativeValue) {
      if (valueIterator.hasPrevious()) {
        Interval leftValue = valueIterator.previous();
        Expression rightOperand = operandsIterator.previous();
        Interval rightValue = nodeValuation.get(rightOperand);

        Pair<Interval, Interval> newValues = applyReverseOperator(op, leftValue, rightValue, oldCummulativeValue,
            newCummulativeValue);
        processOperandsHelper(op, valueIterator, operandsIterator, leftValue, newValues.left);
        processChild(rightOperand, newValues.right);
      } else {// last one
        Expression rightOperand = operandsIterator.previous();
        Expression leftOperand = operandsIterator.previous();
        if (operandsIterator.hasPrevious())
          throw new IntegerComparisonEvaluatorException("Shouldn't happen");
        Interval leftValue = nodeValuation.get(leftOperand);
        Interval rightValue = nodeValuation.get(rightOperand);
        Pair<Interval, Interval> newValues = applyReverseOperator(op, leftValue, rightValue, oldCummulativeValue,
            newCummulativeValue);
        processChild(leftOperand, newValues.left);
        processChild(rightOperand, newValues.right);
      }
    }

    @Override
    public boolean visit(InfixExpression node) {
      ensureCorrectType(node);
      ArrayList<Expression> operands = getOperands(node);
      LinkedList<Interval> operationValues = nodeValuation.get(node);
      if (operationValues.size() != operands.size() - 1)
        throw new IntegerComparisonEvaluatorException("Hmm,  invalid node valuation map??");
      // prepare arguments

      // we iterate backwards
      ListIterator<Interval> valueIterator = operationValues.listIterator(operationValues.size());
      ListIterator<Expression> operandsIterator = operands.listIterator(operands.size());
      // int rightOperandIdx = operands.size()-1;
      processOperandsHelper(node.getOperator(), valueIterator, operandsIterator, valueIterator.previous(),
          newValue);
      return false;
    }

    @Override
    public boolean visit(InstanceofExpression node) {
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(MethodInvocation node) {
      //FIXME: we should probably check if arguments are changed??
      throw new WeWontHandleThis(node);
//      // TODO Auto-generated method stub
//      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(SimpleName node) {
      state = backwardExprSemantics.processIntegerNode(state, node, newValue);
      return false;
    }

    @Override
    public boolean visit(QualifiedName node) {
      //this does not change state so nothing happens
      return false;
//      // TODO Auto-generated method stub
//      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(NullLiteral node) {
      // TODO Auto-generated method stub
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(NumberLiteral node) {
      long value = EvaluationUtils.getIntegerValue(node);
//     
//      Object constant = node.resolveConstantExpressionValue();
//      long value;
//      if (constant == null)
//        throw new IntegerComparisonEvaluatorException("Hmm");
//      if (constant instanceof Integer)
//        value = (Integer) constant;
//      else if (constant instanceof Long)
//        value = (Long) constant;
//      else
//        throw new IntegerComparisonEvaluatorException("Unhandled integer literal type '%s'(%s)", constant,
//            constant.getClass());
      Interval v = backwardExprSemantics.getConstantValue(value);
      if (!v.equals(newValue))
        throw new IntegerComparisonEvaluatorException("Hmmm, something strange??");
      return false;
    }

    @Override
    public boolean visit(ParenthesizedExpression node) {
      //we visit child with the same value
      processChild(node.getExpression(), newValue);
      return false;
    }

    @Override
    public boolean visit(PostfixExpression node) {
      throw new WeWontHandleThis(node);
    }

    @Override
    public boolean visit(PrefixExpression node) {
      PrefixExpression.Operator op = node.getOperator();
      if (op == PrefixExpression.Operator.PLUS)
        processChild(node.getOperand(), newValue);
      else if (op == PrefixExpression.Operator.MINUS) {
        Interval operandValue = nodeValuation.get(node.getOperand());
        Interval newOperandValue = res.backwardMinus(operandValue, newValue);
        processChild(node.getOperand(), newOperandValue);
      } else
        throw new WeWontHandleThis(node);
      return false;
    }

    @Override
    public boolean visit(StringLiteral node) {
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(SuperFieldAccess node) {
      // TODO Auto-generated method stub
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(SuperMethodInvocation node) {
      // TODO Auto-generated method stub
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(ThisExpression node) {
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(TypeLiteral node) {
      throw unhandledNodeException(node);
    }

    @Override
    public boolean visit(VariableDeclarationExpression node) {
      throw unhandledNodeException(node);
    }

  }

  private final IntervalExpressionEvaluator<DI> eval;
  private final BackwardTestSemantics<Interval> bts;
  private final BackwardExpressionSemantics<DI, Interval> backwardExprSemantics;
  private final ReverseExpressionWalker walker = new ReverseExpressionWalker();
  private final GenericReverseExpressionSemantics<Interval> res;

  private Pair<Interval, Interval> applyBackwardTestSemantics(Operator op, Interval leftValue, Interval rightValue) {
    if (op == Operator.LESS)
      return bts.less(leftValue, rightValue);
    if (op == Operator.LESS_EQUALS)
      return bts.leq(leftValue, rightValue);
    if (op == Operator.GREATER) {
      Pair<Interval, Interval> res = bts.less(rightValue, leftValue);
      return res == null ? null : res.swap();
    }
    if (op == Operator.GREATER_EQUALS) {
      Pair<Interval, Interval> res = bts.leq(rightValue, leftValue);
      return res == null ? null : res.swap();
    }
    if (op == Operator.EQUALS)
      return bts.equality(leftValue, rightValue);
    if (op == Operator.NOT_EQUALS)
      return bts.neq(leftValue, rightValue);
    throw new IntegerComparisonEvaluatorException("Unhandled operator '%s'", op);
  }
 
  private DI processOnce(DI input, Operator op, Pair<ExpressionEvaluationMap<Interval>, DI> evalResult,
      Expression left, Expression right) {
    ExpressionEvaluationMap<Interval> map = evalResult.left;
    Pair<Interval, Interval> before = Pair.create(map.get(left), map.get(right));
    Pair<Interval, Interval> after = applyBackwardTestSemantics(op, before.left, before.right);
    if (after == null)
      return input.getBottom();
    if (after.equals(before))
      return evalResult.right;
    try{
      input = walker.process(after.left, input, left, map);
      input = walker.process(after.right, input, right, map);
    } catch (WeWontHandleThis e) {
      log.warn(String.format("Unhandled node '%s' appered in '%s %s %s'", e.node, left, op, right));
      return evalResult.right;
    }
    return input;
  }

  private DI process(DI input, Operator op, Expression left, Expression right) {
    int iteration = 0;
    while (true) {
      Pair<ExpressionEvaluationMap<Interval>, DI> evalResult = eval.evaluateExpressionsMap(input, left, right);
      if (iteration == ITERATION_LIMIT) {
        log.warn(String.format("Iteration limit '%s' reached when computing '%s %s %s'", ITERATION_LIMIT, left, op, right));
        return evalResult.right;
      } else
        log.info(String.format("Processing iteration: '%s'", ++iteration));
      ExpressionEvaluationMap<Interval> map = evalResult.left;
      Pair<Interval, Interval> before = Pair.create(map.get(left), map.get(right));
      Pair<Interval, Interval> after = applyBackwardTestSemantics(op, before.left, before.right);
      if (after == null)
        return input.getBottom();
      if (after.equals(before))
        return evalResult.right;
      DI output = input;
      try{
        output = walker.process(after.left, input, left, map);
        output = walker.process(after.right, output, right, map);
      } catch (WeWontHandleThis e) {
        log.warn(String.format("Unhandled node '%s' appered in '%s %s %s'", e.node, left, op, right));
        return evalResult.right;
      }
      if (input.equals(output))
        return input;
      input = output;
    }
  }

  private Operator negate(Operator op) {
    if (op == Operator.GREATER)
      return Operator.LESS_EQUALS;
    if (op == Operator.GREATER_EQUALS)
      return Operator.LESS;
    if (op == Operator.LESS)
      return Operator.GREATER_EQUALS;
    if (op == Operator.LESS_EQUALS)
      return Operator.GREATER;
    if (op == Operator.EQUALS)
      return Operator.NOT_EQUALS;
    if (op == Operator.NOT_EQUALS)
      return Operator.EQUALS;
    throw new IntegerComparisonEvaluatorException("Unknown comparision operator '%s'", op);
  }

  private DI evaluateComparison(DI input, InfixExpression comparison, boolean negated) {
    if (input.isBottom())
      return input;
    Operator op = comparison.getOperator();
    if (negated)
      op = negate(op);
    if (negated)
      log.info("Processing negated comparison: " + comparison);
    else
      log.info("Processing comparison: " + comparison);
    DI result = process(input, op, comparison.getLeftOperand(), comparison.getRightOperand());
    if (result == null)
      throw new IntegerComparisonEvaluatorException("Something is wrong!!");
    return result;
  }

  @Override
  public BooleanEvaluationState<DI> evaluateComparison(DI input, InfixExpression comparison) {
    if (!EvaluationUtils.isIntegerType(comparison.getLeftOperand())
        || !EvaluationUtils.isIntegerType(comparison.getRightOperand()))
      return null;
    return BooleanEvaluationState.create(evaluateComparison(input, comparison, false),
        evaluateComparison(input, comparison, true));
  }

  private DI evaluateComparisonOnce(Pair<ExpressionEvaluationMap<Interval>, DI> evalResult,
      DI input, InfixExpression.Operator op, Expression left, Expression right, boolean negated) {
    if (input.isBottom())
      return input;
    if (negated)
      op = negate(op);
    if (negated)
      log.info("Processing once negated comparison");
    else
      log.info("Processing once comparison");
    DI result = processOnce(input, op, evalResult, left, right);
    if (result == null)
      throw new IntegerComparisonEvaluatorException("Something is wrong!!");
    return result;
  }
 
  public BooleanEvaluationState<DI> evaluateComparisonNoEval(DI input, InfixExpression.Operator op,
      Expression left, Expression right, Pair<ExpressionEvaluationMap<Interval>, DI> evalMap) {
    return BooleanEvaluationState.create(evaluateComparisonOnce(evalMap, input, op, left, right, false),
        evaluateComparisonOnce(evalMap, input, op, left, right, true));
  }
 
  public Pair<ExpressionEvaluationMap<Interval>, DI> prepareEvaluationMap(DI input, Expression... expressions){
    return eval.evaluateExpressionsMap(input, expressions);
  }

  private IntervalComparisonEvaluator(IntervalExpressionEvaluator<DI> eval,
      BackwardTestSemantics<Interval> backwardTestSemantics, GenericReverseExpressionSemantics<Interval> res,
      BackwardExpressionSemantics<DI, Interval> backwardExprSemantics) {
    this.eval = eval;
    this.bts = backwardTestSemantics;
    this.backwardExprSemantics = backwardExprSemantics;
    this.res = res;
  }

  public static <DI extends DomainIntf<DI>> IntervalComparisonEvaluator<DI> create(
      IntervalExpressionEvaluator<DI> eval, BackwardTestSemantics<Interval> backwardTestSemantics,
      GenericReverseExpressionSemantics<Interval> res, BackwardExpressionSemantics<DI, Interval> backwardExprSemantics) {
    return new IntervalComparisonEvaluator<DI>(eval, backwardTestSemantics, res, backwardExprSemantics);
  }
}
TOP

Related Classes of ai.domain.interval.IntervalComparisonEvaluator$IntegerComparisonEvaluatorException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.