/** * */ package jayhorn.hornify.encoder; import java.math.BigInteger; import java.util.Map; import jayhorn.hornify.HornEncoderContext; import jayhorn.hornify.HornHelper; import jayhorn.solver.Prover; import jayhorn.solver.ProverExpr; import jayhorn.solver.ProverTupleExpr; import jayhorn.solver.ProverTupleType; import soottocfg.cfg.expression.BinaryExpression; import soottocfg.cfg.expression.Expression; import soottocfg.cfg.expression.IdentifierExpression; import soottocfg.cfg.expression.IteExpression; import soottocfg.cfg.expression.TupleAccessExpression; import soottocfg.cfg.expression.UnaryExpression; import soottocfg.cfg.expression.literal.BooleanLiteral; import soottocfg.cfg.expression.literal.IntegerLiteral; import soottocfg.cfg.expression.literal.NullLiteral; import soottocfg.cfg.variable.ClassVariable; import soottocfg.cfg.variable.Variable; /** * @author schaef * */ public class ExpressionEncoder { private final Prover p; private final HornEncoderContext hornContext; /** * */ public ExpressionEncoder(Prover p, HornEncoderContext hornContext) { this.p = p; this.hornContext = hornContext; } public HornEncoderContext getContext() { return this.hornContext; } /** * TODO: this is a hack! * * @param id * @return */ private ProverExpr typeIdToProverExpr(int id) { return p.mkLiteral(id); } public ProverExpr exprToProverExpr(Expression e, Map<Variable, ProverExpr> varMap) { if (e instanceof IdentifierExpression) { Variable var = ((IdentifierExpression) e).getVariable(); if (var instanceof ClassVariable) { return typeIdToProverExpr(hornContext.getTypeID((ClassVariable) var)); // return p.mkLiteral(hornContext.getTypeID((ClassVariable) // var)); } else { if (hornContext.getProgram().getGlobalVariables().contains(var)) { /* * For globals, we just use an integer number. * NOTE: The translation guarantees that this number is unique and different * from Null. */ int idx = hornContext.getProgram().getGlobalVariables().indexOf(var); return HornHelper.hh().findOrCreateUniqueVariable(p, var, varMap, idx); // return p.mkLiteral(hornContext.getProgram().getGlobalVariables().indexOf(var)); } else { return HornHelper.hh().findOrCreateProverVar(p, var, varMap); } } } else if (e instanceof TupleAccessExpression) { TupleAccessExpression tae = (TupleAccessExpression) e; ProverExpr tuple = varMap.get(tae.getVariable()); return p.mkTupleSelect(tuple, tae.getAccessPosition()); // return p.mkVariable("HACK_FreeVar" + HornHelper.hh().newVarNum(), // HornHelper.hh().getProverType(p, tae.getType())); } else if (e instanceof IntegerLiteral) { return p.mkLiteral(BigInteger.valueOf(((IntegerLiteral) e).getValue())); } else if (e instanceof NullLiteral) { return p.mkLiteral(HornHelper.NullValue); } else if (e instanceof BinaryExpression) { final BinaryExpression be = (BinaryExpression) e; ProverExpr left = exprToProverExpr(be.getLeft(), varMap); // if (left instanceof ProverTupleType) { // //in that case only use the projection to the first element // //of the tuple. // left = p.mkTupleSelect(left, 0); // } ProverExpr right = exprToProverExpr(be.getRight(), varMap); // if (right instanceof ProverTupleType) { // //in that case only use the projection to the first element // //of the tuple. // Verify.verify(right instanceof ProverTupleExpr, be.getRight()+" // becomes " +right +" of type " + right.getType().getClass()); // right = p.mkTupleSelect(right, 0); // } if (be.getLeft() instanceof NullLiteral && be.getRight() instanceof IdentifierExpression) { ProverTupleType ptt = (ProverTupleType)right.getType(); left = HornHelper.hh().mkNullExpression(p, ptt.getSubTypes()); } if (be.getRight() instanceof NullLiteral && be.getLeft() instanceof IdentifierExpression) { ProverTupleType ptt = (ProverTupleType)left.getType(); right = HornHelper.hh().mkNullExpression(p, ptt.getSubTypes()); } // TODO: the following choices encode Java semantics // of various operators; need a good schema to choose // how precise the encoding should be (probably // configurable) switch (be.getOp()) { case Plus: return p.mkPlus(left, right); case Minus: return p.mkMinus(left, right); case Mul: return p.mkMult(left, right); case Div: return p.mkTDiv(left, right); case Mod: return p.mkTMod(left, right); case Eq: if (left instanceof ProverTupleExpr) { ProverTupleExpr tLeft = (ProverTupleExpr)left; ProverTupleExpr tRight = (ProverTupleExpr)right; //TODO: this is sound if we assume that the first //element of a tuple is the sound identifier. return p.mkEq(tLeft.getSubExpr(0), tRight.getSubExpr(0)); } return p.mkEq(left, right); case Ne: return p.mkNot(p.mkEq(left, right)); case Gt: return p.mkGt(left, right); case Ge: return p.mkGeq(left, right); case Lt: return p.mkLt(left, right); case Le: return p.mkLeq(left, right); case PoLeq: if ((be.getRight() instanceof IdentifierExpression) && (((IdentifierExpression) be.getRight()).getVariable() instanceof ClassVariable)) { final ClassVariable var = (ClassVariable) ((IdentifierExpression) be.getRight()).getVariable(); ProverExpr disj = p.mkLiteral(false); for (Integer i : this.hornContext.getSubtypeIDs(var)) { // ProverExpr tmp = // p.mkTupleSelect(typeIdToProverExpr(i), 0); ProverExpr tmp = typeIdToProverExpr(i); disj = p.mkOr(disj, p.mkEq(left, tmp)); } return disj; } else { throw new RuntimeException("instanceof is only supported for concrete types"); } case And: return p.mkAnd(left, right); case Or: return p.mkOr(left, right); case Implies: return p.mkImplies(left, right); case Shl: case Shr: case Ushr: case BAnd: case BOr: case Xor: return p.mkVariable("HACK_FreeVar" + HornHelper.hh().newVarNum(), p.getIntType()); // Verify.verify(left.getType()==p.getIntType() && // right.getType()==p.getIntType()); // return binopFun.mkExpr(new ProverExpr[]{left, right}); default: { throw new RuntimeException("Not implemented for " + be.getOp()); } } } else if (e instanceof UnaryExpression) { final UnaryExpression ue = (UnaryExpression) e; final ProverExpr subExpr = exprToProverExpr(ue.getExpression(), varMap); // TODO: the following choices encode Java semantics // of various operators; need a good schema to choose // how precise the encoding should be (probably // configurable) switch (ue.getOp()) { case Neg: return p.mkNeg(subExpr); case LNot: return p.mkNot(subExpr); } } else if (e instanceof IteExpression) { final IteExpression ie = (IteExpression) e; final ProverExpr condExpr = exprToProverExpr(ie.getCondition(), varMap); final ProverExpr thenExpr = exprToProverExpr(ie.getThenExpr(), varMap); final ProverExpr elseExpr = exprToProverExpr(ie.getElseExpr(), varMap); return p.mkIte(condExpr, thenExpr, elseExpr); } else if (e instanceof BooleanLiteral) { return p.mkLiteral(((BooleanLiteral) e).getValue()); } throw new RuntimeException("Expression type " + e + " not implemented!"); } }