/*
* Copyright 2013 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.errorprone.refaster;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.errorprone.refaster.Unifier.unifications;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableBiMap;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.TreeVisitor;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCBinary;
/**
* {@link UTree} version of {@link BinaryTree}.
*
* @author lowasser@google.com (Louis Wasserman)
*/
@AutoValue
abstract class UBinary extends UExpression implements BinaryTree {
static final ImmutableBiMap<Kind, JCTree.Tag> OP_CODES =
new ImmutableBiMap.Builder<Kind, JCTree.Tag>()
.put(Kind.PLUS, JCTree.Tag.PLUS)
.put(Kind.MINUS, JCTree.Tag.MINUS)
.put(Kind.MULTIPLY, JCTree.Tag.MUL)
.put(Kind.DIVIDE, JCTree.Tag.DIV)
.put(Kind.REMAINDER, JCTree.Tag.MOD)
.put(Kind.LEFT_SHIFT, JCTree.Tag.SL)
.put(Kind.RIGHT_SHIFT, JCTree.Tag.SR)
.put(Kind.UNSIGNED_RIGHT_SHIFT, JCTree.Tag.USR)
.put(Kind.OR, JCTree.Tag.BITOR)
.put(Kind.AND, JCTree.Tag.BITAND)
.put(Kind.XOR, JCTree.Tag.BITXOR)
.put(Kind.CONDITIONAL_AND, JCTree.Tag.AND)
.put(Kind.CONDITIONAL_OR, JCTree.Tag.OR)
.put(Kind.LESS_THAN, JCTree.Tag.LT)
.put(Kind.LESS_THAN_EQUAL, JCTree.Tag.LE)
.put(Kind.GREATER_THAN, JCTree.Tag.GT)
.put(Kind.GREATER_THAN_EQUAL, JCTree.Tag.GE)
.put(Kind.EQUAL_TO, JCTree.Tag.EQ)
.put(Kind.NOT_EQUAL_TO, JCTree.Tag.NE)
.build();
static final ImmutableBiMap<Kind, Kind> NEGATION =
new ImmutableBiMap.Builder<Kind, Kind>()
.put(Kind.LESS_THAN, Kind.GREATER_THAN_EQUAL)
.put(Kind.LESS_THAN_EQUAL, Kind.GREATER_THAN)
.put(Kind.GREATER_THAN, Kind.LESS_THAN_EQUAL)
.put(Kind.GREATER_THAN_EQUAL, Kind.LESS_THAN)
.put(Kind.EQUAL_TO, Kind.NOT_EQUAL_TO)
.put(Kind.NOT_EQUAL_TO, Kind.EQUAL_TO)
.build();
static final ImmutableBiMap<Kind, Kind> DEMORGAN =
new ImmutableBiMap.Builder<Kind, Kind>()
.put(Kind.CONDITIONAL_AND, Kind.CONDITIONAL_OR)
.put(Kind.CONDITIONAL_OR, Kind.CONDITIONAL_AND)
.put(Kind.AND, Kind.OR)
.put(Kind.OR, Kind.AND)
.build();
public static UBinary create(Kind binaryOp, UExpression lhs, UExpression rhs) {
checkArgument(OP_CODES.containsKey(binaryOp),
"%s is not a supported binary operation", binaryOp);
return new AutoValue_UBinary(binaryOp, lhs, rhs);
}
@Override
public abstract Kind getKind();
@Override
public abstract UExpression getLeftOperand();
@Override
public abstract UExpression getRightOperand();
@Override
public Choice<Unifier> visitBinary(BinaryTree binary, Unifier unifier) {
return Choice.condition(getKind().equals(binary.getKind()), unifier)
.thenChoose(unifications(getLeftOperand(), binary.getLeftOperand()))
.thenChoose(unifications(getRightOperand(), binary.getRightOperand()));
}
@Override
public <R, D> R accept(TreeVisitor<R, D> visitor, D data) {
return visitor.visitBinary(this, data);
}
@Override
public JCBinary inline(Inliner inliner) throws CouldNotResolveImportException {
return inliner.maker().Binary(
OP_CODES.get(getKind()),
getLeftOperand().inline(inliner),
getRightOperand().inline(inliner));
}
@Override
public UExpression negate() {
if (NEGATION.containsKey(getKind())) {
return UBinary.create(NEGATION.get(getKind()), getLeftOperand(), getRightOperand());
} else if (DEMORGAN.containsKey(getKind())) {
return UBinary.create(
DEMORGAN.get(getKind()),
getLeftOperand().negate(),
getRightOperand().negate());
} else {
return super.negate();
}
}
}