@Override
 public Expression caseAndExpression(AndExpression object) {
   if (object.getRight() == null) return doSwitch(object.getLeft());
   if (object.getLeft() == null) return doSwitch(object.getRight());
   Expression left = doSwitch(object.getLeft());
   Expression right = doSwitch(object.getRight());
   if (areSemanticallyEqual(left, right)) return left;
   object.setLeft(left);
   object.setRight(right);
   return object;
 }
 public boolean areSemanticallyEqual(Expression left, Expression right) {
   if (left.eClass() != right.eClass()) return false;
   if (left instanceof OrExpression) {
     OrExpression leftOrExpression = (OrExpression) left;
     OrExpression rightOrExpression = (OrExpression) right;
     return (areSemanticallyEqual(leftOrExpression.getLeft(), rightOrExpression.getLeft())
             && areSemanticallyEqual(leftOrExpression.getRight(), rightOrExpression.getRight()))
         || (areSemanticallyEqual(leftOrExpression.getRight(), rightOrExpression.getLeft())
             && areSemanticallyEqual(leftOrExpression.getLeft(), rightOrExpression.getRight()));
   }
   if (left instanceof AndExpression) {
     AndExpression leftAndExpression = (AndExpression) left;
     AndExpression rightAndExpression = (AndExpression) right;
     return (areSemanticallyEqual(leftAndExpression.getLeft(), rightAndExpression.getLeft())
             && areSemanticallyEqual(leftAndExpression.getRight(), rightAndExpression.getRight()))
         || (areSemanticallyEqual(leftAndExpression.getRight(), rightAndExpression.getLeft())
             && areSemanticallyEqual(leftAndExpression.getLeft(), rightAndExpression.getRight()));
   }
   if (left instanceof NotExpression) {
     return areSemanticallyEqual(
         ((NotExpression) left).getExpression(), ((NotExpression) right).getExpression());
   }
   if (left instanceof Comparison) {
     Comparison leftComparison = (Comparison) left;
     Comparison rightComparison = (Comparison) right;
     return ((Comparison) left).getOperator().equals(rightComparison.getOperator())
         && areSemanticallyEqual(leftComparison.getLeft(), rightComparison.getLeft())
         && areSemanticallyEqual(leftComparison.getRight(), rightComparison.getRight());
   }
   if (left instanceof NumberLiteral) {
     int leftValue = ((NumberLiteral) left).getValue();
     int rightValue = ((NumberLiteral) right).getValue();
     return leftValue == rightValue;
   }
   if (left instanceof MethodCall) {
     String leftMethod = ((MethodCall) left).getValue();
     String rightMethod = ((MethodCall) right).getValue();
     return leftMethod.equals(rightMethod);
   }
   throw new IllegalStateException(left + " - " + right);
 }
 @Override
 public Expression caseOrExpression(OrExpression object) {
   if (object.getRight() == null) return doSwitch(object.getLeft());
   if (object.getLeft() == null) return doSwitch(object.getRight());
   Expression left = doSwitch(object.getLeft());
   Expression right = doSwitch(object.getRight());
   if (areSemanticallyEqual(left, right)) return left;
   if (left instanceof AndExpression) {
     AndExpression leftAsAnd = (AndExpression) left;
     if (areSemanticallyEqual(leftAsAnd.getLeft(), right)
         || areSemanticallyEqual(leftAsAnd.getRight(), right)) return right;
   } else if (right instanceof AndExpression) {
     AndExpression rightAsAnd = (AndExpression) right;
     if (areSemanticallyEqual(rightAsAnd.getLeft(), left)
         || areSemanticallyEqual(rightAsAnd.getRight(), left)) return left;
   }
   if (left instanceof OrExpression) {
     OrExpression leftAsOr = (OrExpression) left;
     if (areSemanticallyEqual(leftAsOr.getLeft(), right)
         || areSemanticallyEqual(leftAsOr.getRight(), right)) return left;
   } else if (right instanceof OrExpression) {
     OrExpression rightAsOr = (OrExpression) right;
     if (areSemanticallyEqual(rightAsOr.getLeft(), left)
         || areSemanticallyEqual(rightAsOr.getRight(), left)) return right;
   }
   object.setLeft(left);
   object.setRight(right);
   return object;
 }