Package ai.domain.expressions.bool

Source Code of ai.domain.expressions.bool.BooleanEvaluator

package ai.domain.expressions.bool;

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.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.VariableDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationExpression;

import ai.common.Pair;
import ai.domain.DomainException;
import ai.domain.DomainIntf;
import ai.domain.Variable;
import ai.domain.bool.Bool;
import ai.domain.expressions.AbstractExpressionVisitor;
import ai.domain.expressions.ExpressionEvaluatorIntf;
import ai.domain.intervals.eval.EvaluationUtils;

public class BooleanEvaluator<DI extends DomainIntf<DI>> implements ExpressionEvaluatorIntf<DI>, BooleanConditionEvaluatorIntf<DI>{
  public static class BooleanEvaluatorException extends RuntimeException {
    private static final long serialVersionUID = -5548898388891577924L;

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

  private BooleanEvaluationState<DI> createState(DI conditionMet, DI conditionNotMet) {
    return new BooleanEvaluationState<DI>(conditionMet, conditionNotMet);
  }
 
  protected class BooleanVisitor extends AbstractExpressionVisitor {
    private BooleanEvaluationState<DI> state;
    private DI input;
   
    protected void ensureBooleanType(Expression expr) {
      if (!EvaluationUtils.isBooleanType(expr))
        throw new BooleanEvaluatorException("I shouldn't be here? '%s'", expr);
    }

    protected void ensureBooleanTypeOrBoxing(Expression expr) {
      if (!EvaluationUtils.isBooleanType(expr) && !EvaluationUtils.isBooleanTypeBoxing(expr))
        throw new BooleanEvaluatorException("I shouldn't be here? '%s'", expr);
    }
   
    private BooleanEvaluationState<DI> acceptChild(Expression child, DI input) {
      if (input.isBottom())
        return BooleanEvaluationState.create(input, input);
      this.input = input;
      child.accept(this);
      if (state == null)
        throw new BooleanEvaluatorException("Child value not calculated? '%s'", child);
      if (state.conditionMet == null)
        throw new BooleanEvaluatorException("Child value not calculated? '%s'", child);
      if (state.conditionMet == null)
        throw new BooleanEvaluatorException("Child value not calculated? '%s'", child);
      return this.state;
    }   
   
    protected void setNewState(Expression expr, BooleanEvaluationState<DI> newState) {
      if (newState.conditionMet == null || newState.conditionNotMet == null)
        throw new BooleanEvaluatorException("Invalid expression semantics? '%s'", expr);
      state = newState;
    }
   
    @Override
    public boolean visit(ArrayAccess node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;     
    }

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

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

    @Override
    public boolean visit(Assignment node) {
      if (EvaluationUtils.isBooleanType(node)){
        Assignment.Operator op = node.getOperator();
        BooleanEvaluationState<DI> res;
        if (op == Assignment.Operator.ASSIGN)
          res = acceptChild(node.getRightHandSide(), input);
        else if (op == Assignment.Operator.BIT_AND_ASSIGN)
          res = handleAnd(node.getLeftHandSide(), node.getRightHandSide());
        else if (op == Assignment.Operator.BIT_OR_ASSIGN)
          res = handleOr(node.getLeftHandSide(), node.getRightHandSide());
        else if (op == Assignment.Operator.BIT_XOR_ASSIGN)
          res = handleXor(node.getLeftHandSide(), node.getRightHandSide());
        else
          throw new BooleanEvaluatorException("Unhandled operator '%s'", op);
        DI positive = res.conditionMet.isBottom()? res.conditionMet : expressionSemantics.processBooleanAssignment(res.conditionMet, node.getLeftHandSide(), Bool.TRUE);
        DI negative = res.conditionNotMet.isBottom() ? res.conditionNotMet : expressionSemantics.processBooleanAssignment(res.conditionNotMet, node.getLeftHandSide(), Bool.FALSE);
        setNewState(node, createState(positive, negative));
      } else if (EvaluationUtils.isBooleanTypeBoxing(node))
        setNewState(node, expressionSemantics.processBooleanBoxing(input, node));
      else
        throw new BooleanEvaluatorException("I shouldn't be here? '%s'", node);
      return false;
    }

    @Override
    public boolean visit(BooleanLiteral node) {
      boolean val = EvaluationUtils.getBooleanValue(node);
      setNewState(node, val ? createState(input, input.getBottom()) : createState(input.getBottom(), input));
      return false;
    }

    @Override
    public boolean visit(CastExpression node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;
    }

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

    @Override
    public boolean visit(ClassInstanceCreation node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;
    }

    @Override
    public boolean visit(ConditionalExpression node) {
      ensureBooleanTypeOrBoxing(node);
      //evaluate condition
      BooleanEvaluationState<DI> conditionEvalResult = acceptChild(node.getExpression(), input);
      BooleanEvaluationState<DI> thenResult = null;
      if (!conditionEvalResult.conditionMet.isBottom())
        thenResult = acceptChild(node.getThenExpression(), conditionEvalResult.conditionMet);
      BooleanEvaluationState<DI> elseResult = null;
      if (!conditionEvalResult.conditionNotMet.isBottom())
        elseResult = acceptChild(node.getElseExpression(), conditionEvalResult.conditionNotMet);
      if (thenResult == null)
        setNewState(node, elseResult);
      else if (elseResult == null)
        setNewState(node, thenResult);
      else // both have results
        setNewState(node, BooleanEvaluationState.create(thenResult.conditionMet.join(elseResult.conditionMet),
            thenResult.conditionNotMet.join(elseResult.conditionNotMet)));
      return false;
    }

    @Override
    public boolean visit(FieldAccess node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;
    }
   
    private BooleanEvaluationState<DI> handleXor(Expression leftOperand, Expression rightOperand) {
      BooleanEvaluationState<DI> left = acceptChild(leftOperand, input);
      BooleanEvaluationState<DI> rightIfLeft = acceptChild(rightOperand, left.conditionMet);
      BooleanEvaluationState<DI> rightIfNotLeft = acceptChild(rightOperand, left.conditionNotMet);
     
      return createState(
          //(LEFT and not RIGHT) or (not LEFT and RIGHT)
          rightIfLeft.conditionNotMet.join(rightIfNotLeft.conditionMet),
          //(LEFT and RIGHT) or (not LEFT and not RIGHT)
          rightIfLeft.conditionMet.join(rightIfNotLeft.conditionNotMet));
    }
   
    private BooleanEvaluationState<DI> handleAnd(Expression leftOperand, Expression rightOperand) {
      BooleanEvaluationState<DI> left = acceptChild(leftOperand, input);
      BooleanEvaluationState<DI> rightIfLeft = acceptChild(rightOperand, left.conditionMet);
      return createState(
          //LEFT and RIGHT
          rightIfLeft.conditionMet,
          //NOT LEFT or NOT RIGHT
          left.conditionNotMet.join(rightIfLeft.conditionNotMet)
          );
    }
   
    private BooleanEvaluationState<DI> handleOr(Expression leftOperand, Expression rightOperand) {
      BooleanEvaluationState<DI> left = acceptChild(leftOperand, input);
      BooleanEvaluationState<DI> rightIfNotLeft = acceptChild(rightOperand, left.conditionNotMet);
      return createState(
          //LEFT or RIGHT
          left.conditionMet.join(rightIfNotLeft.conditionMet),
          //NOT LEFT and NOT RIGHT
          rightIfNotLeft.conditionNotMet
          );
    }

    @Override
    public boolean visit(InfixExpression node) {
      ensureBooleanType(node);     
      InfixExpression.Operator op = node.getOperator();
      if (op == InfixExpression.Operator.XOR)
        setNewState(node, handleXor(node.getLeftOperand(), node.getRightOperand()));
      else if (op == InfixExpression.Operator.CONDITIONAL_AND)
        setNewState(node, handleAnd(node.getLeftOperand(), node.getRightOperand()));
      else if (op == InfixExpression.Operator.CONDITIONAL_OR)
        setNewState(node, handleOr(node.getLeftOperand(), node.getRightOperand()));
      else
        setNewState(node, expressionSemantics.processComparison(input, node));
//       
//      else if (op == InfixExpression.Operator.EQUALS || op == InfixExpression.Operator.NOT_EQUALS){
//        setNewState(node, expressionSemantics.processComparison(input, node));
//      } else
//        throw new BooleanEvaluatorException("Unhandled boolean operator '%s'", op);
      return false;
    }

    @Override
    public boolean visit(InstanceofExpression node) {
      ensureBooleanType(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;
    }

    @Override
    public boolean visit(MethodInvocation node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;     
    }

    @Override
    public boolean visit(SimpleName node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;
    }

    @Override
    public boolean visit(QualifiedName node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;
    }

    @Override
    public boolean visit(NullLiteral node) {
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;
    }

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

    @Override
    public boolean visit(ParenthesizedExpression node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, acceptChild(node.getExpression(), input));
      return false;
    }

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

    @Override
    public boolean visit(PrefixExpression node) {
      ensureBooleanType(node);
      PrefixExpression.Operator op = node.getOperator();
      if (op == PrefixExpression.Operator.NOT) {
        BooleanEvaluationState<DI> res = acceptChild(node.getOperand(), input);
        setNewState(node, createState(res.conditionNotMet, res.conditionMet));
      } else
        throw new BooleanEvaluatorException("Unhandled prefix boolean operator '%s'", op);
      return false;
    }

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

    @Override
    public boolean visit(SuperFieldAccess node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;
    }

    @Override
    public boolean visit(SuperMethodInvocation node) {
      ensureBooleanTypeOrBoxing(node);
      setNewState(node, expressionSemantics.processBooleanNode(input, node));
      return false;
    }

    @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 BooleanExpressionSemantics<DI> expressionSemantics;

  public BooleanEvaluator(BooleanExpressionSemantics<DI> expressionSemantics){
    this.expressionSemantics = expressionSemantics;
  }
 
  protected final RuntimeException unhandledNodeException(Expression node) {
    return new BooleanEvaluatorException("Unhandled node '%s(%s)'", node.getClass(), node);
  }
 
  protected boolean isInterestingType(Expression expr) {
    try {
      return EvaluationUtils.isBooleanType(expr);
    } catch (RuntimeException e) {
      System.err.println("Error evaluating: " + expr);
      throw e;
    }
  }

  private DI processNewVariable(DI input, Variable var, Bool initialValueOrNull, boolean isArgument) {
    return expressionSemantics.newBooleanVariable(input, var, initialValueOrNull, isArgument);
  }
 
  public BooleanEvaluationState<DI> evaluateCondition(DI input, Expression expr) {
    BooleanVisitor eval = new BooleanVisitor();
    try {
      return eval.acceptChild(expr, input);
    } catch (RuntimeException e) {
      System.err.println("ERROR evaluating: " + expr);
      e.printStackTrace(System.err);
      throw e;
    }
  }

//  public Pair<T, DI> evaluateExpression(Expression expr, DI input) {
//    ExpressionVisitorBase eval = getEvaluator(input);
//    expr.accept(eval);
//    Pair<T, DI> result = eval.result;
//    if (result == null)
//      throw new BooleanEvaluatorException("NO RESULT!! '%s'", expr);
//    if (result.left == null)
//      throw new BooleanEvaluatorException("NO RESULT!! '%s'", expr);
//    if (result.right == null)
//      throw new BooleanEvaluatorException("NO RESULT!! '%s'", expr);
//    return result;
//  }
// 
  @Override
  public DI evaluate(Expression expr, DI input) {
    if (!isInterestingType(expr))
      return null;
    BooleanEvaluationState<DI> x = evaluateCondition(input, expr);
    return x.conditionMet.join(x.conditionNotMet);
  }
 
  private Pair<Bool, DI> computeInitialValue(Expression exprOrNull, DI input) {
    if (exprOrNull == null)
      return Pair.create(null, input);
    BooleanEvaluationState<DI> x = evaluateCondition(input, exprOrNull);
    Bool resultVal = Bool.BOTTOM;
    DI resultState = x.conditionMet;
    if (!x.conditionMet.isBottom())
      resultVal = resultVal.join(Bool.TRUE);
    if (!x.conditionNotMet.isBottom()) {
      resultVal = resultVal.join(Bool.FALSE);
      resultState = resultState.join(x.conditionNotMet);
    }
    return Pair.create(resultVal, resultState);
  }

  @Override
  public DI evaluate(SimpleName name, Expression initializerOrNull, DI input,
      boolean asAssignment) {
    if (!isInterestingType(name))
      return null;
    Pair<Bool, DI> initializer = computeInitialValue(initializerOrNull, input);
    Variable variable = EvaluationUtils.tryGetVariable(name);
    if (variable == null)
      throw new DomainException("Error: '%s'", variable);
    if (asAssignment && initializerOrNull != null)
      return expressionSemantics.processBooleanAssignment(initializer.right, name, initializer.left);
    else
      return processNewVariable(initializer.right, variable, initializer.left, asAssignment);
  }

  @Override
  public DI evaluateNewArgument(SimpleName argument, DI input) {
    if (!isInterestingType(argument))
      return null;
    Variable variable = EvaluationUtils.tryGetVariable(argument);
    if (variable == null)
      throw new DomainException("Error: '%s'", variable);
    return processNewVariable(input, variable, null, true);
  }

  public static <DI extends DomainIntf<DI>> BooleanEvaluator<DI> create(BooleanExpressionSemantics<DI> semantics) {
    return new BooleanEvaluator<DI>(semantics);
  }

  public static <DI extends DomainIntf<DI>> BooleanEvaluationState<DI> createOutput(DI input, Bool value) {
    DI positive = input.getBottom();
    DI negative = input.getBottom();
    if (!value.meet(Bool.TRUE).isBottom())
      positive = input;
    if (!value.meet(Bool.FALSE).isBottom())
      negative = input;
    return BooleanEvaluationState.create(positive, negative);
  }
 
}
TOP

Related Classes of ai.domain.expressions.bool.BooleanEvaluator

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.