/**
*
*/
package soottocfg.cfg.expression;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Preconditions;
import soottocfg.cfg.SourceLocation;
import soottocfg.cfg.expression.literal.BooleanLiteral;
import soottocfg.cfg.expression.literal.IntegerLiteral;
import soottocfg.cfg.type.BoolType;
import soottocfg.cfg.type.Type;
import soottocfg.cfg.variable.Variable;
import soottocfg.soot.util.SootTranslationHelpers;
/**
* @author schaef
*
*/
public class BinaryExpression extends Expression {
/**
*
*/
private static final long serialVersionUID = 1992559147136566989L;
public enum BinaryOperator {
Plus("+"), Minus("-"), Mul("*"), Div("/"), Mod("%"), And("&&"), Or("||"), Xor("^"), Implies("->"), Eq("=="), Ne(
"!="), Gt(">"), Ge(">="), Lt("<"), Le("<="), Shl("<<"), Shr(">>"), Ushr("u>>"), BOr("|"), BAnd("&"),
PoLeq("<:");
private final String name;
private BinaryOperator(String s) {
name = s;
}
public boolean equalsName(String otherName) {
return (otherName == null) ? false : name.equals(otherName);
}
@Override
public String toString() {
return this.name;
}
}
private Expression left, right;
private final BinaryOperator op;
public BinaryExpression(SourceLocation loc, BinaryOperator op, Expression left, Expression right) {
super(loc);
if (left.getType().getClass() != right.getType().getClass()
&& !SootTranslationHelpers.v().getMemoryModel().isNullReference(right)) {
// TODO: this should be somewhere in the translation.
if (left.getType() == BoolType.instance() && right instanceof IntegerLiteral) {
if (((IntegerLiteral) right).getValue() == 0L) {
right = BooleanLiteral.falseLiteral();
} else if (((IntegerLiteral) right).getValue() == 1L) {
right = BooleanLiteral.trueLiteral();
} else {
throw new RuntimeException("BinaryExpression: bool/int confusion");
}
} else if (right.getType() == BoolType.instance() && left instanceof IntegerLiteral) {
if (((IntegerLiteral) left).getValue() == 0L) {
left = BooleanLiteral.falseLiteral();
} else if (((IntegerLiteral) left).getValue() == 1L) {
left = BooleanLiteral.trueLiteral();
} else {
throw new RuntimeException("BinaryExpression: bool/int confusion");
}
}
}
Preconditions.checkArgument(
left.getType().getClass() == right.getType().getClass()
|| SootTranslationHelpers.v().getMemoryModel().isNullReference(right)
|| SootTranslationHelpers.v().getMemoryModel().isNullReference(left),
"Types don't match: " + left.getType() + " and " + right.getType() + " for "+left.toString()+op+right.toString());
// TODO: more type checking depending on operator
this.left = left;
this.right = right;
this.op = op;
}
public Expression getLeft() {
return left;
}
public Expression getRight() {
return right;
}
public BinaryOperator getOp() {
return op;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append(this.left);
sb.append(" " + this.op + " ");
sb.append(this.right);
sb.append(")");
return sb.toString();
}
@Override
public Set<IdentifierExpression> getUseIdentifierExpressions() {
Set<IdentifierExpression> ret = new HashSet<IdentifierExpression>();
ret.addAll(left.getUseIdentifierExpressions());
ret.addAll(right.getUseIdentifierExpressions());
return ret;
}
@Override
public Set<Variable> getDefVariables() {
// because this can't happen on the left.
Set<Variable> used = new HashSet<Variable>();
return used;
}
@Override
public Type getType() {
switch (op) {
case Plus:
case Minus:
case Mul:
case Div:
case Mod: {
assert (left.getType().equals(right.getType()));
return left.getType();
}
case Eq:
case Ne:
case Gt:
case Ge:
case Lt:
case Le: {
// assert(left.getType().equals(right.getType()));
return BoolType.instance();
}
case And:
case Or:
case Implies: {
assert (left.getType() == BoolType.instance() && right.getType() == BoolType.instance());
return BoolType.instance();
}
case PoLeq: {
return BoolType.instance();
}
default: {
//TODO: more testing here?
return left.getType();
}
}
}
@Override
public BinaryExpression deepCopy() {
return new BinaryExpression(getSourceLocation(), op, left.deepCopy(), right.deepCopy());
}
public BinaryExpression substitute(Map<Variable, Variable> subs) {
return new BinaryExpression(getSourceLocation(), op, left.substitute(subs), right.substitute(subs));
}
public BinaryExpression substituteVarWithExpression(Map<Variable, Expression> subs) {
return new BinaryExpression(getSourceLocation(), op, left.substituteVarWithExpression(subs), right.substituteVarWithExpression(subs));
}
}