/**
   * translate boogie statement to prover expression
   *
   * @param s
   * @return
   */
  protected ProverExpr statement2ProverExpr(Statement s) {
    if (s instanceof AssignStatement) {
      AssignStatement st = (AssignStatement) s;
      if (st.getLeft() instanceof SimpleHeapAccess || st.getLeft() instanceof ArrayReadExpression) {
        return arrayWrite2ProverExpr(st.getLeft(), expression2ProverExpr(st.getRight()));
      } else {

        return theoremProver.mkEq(
            expression2ProverExpr(st.getLeft()), expression2ProverExpr(st.getRight()));
      }
    } else if (s instanceof AssumeStatement) {
      AssumeStatement st = (AssumeStatement) s;
      return guardExpression2ProverExpr(st.getExpression());
    } else if (s instanceof AssertStatement) {
      AssertStatement st = (AssertStatement) s;
      return guardExpression2ProverExpr(st.getExpression());
    } else if (s instanceof InvokeStatement) {
      InvokeStatement st = (InvokeStatement) s;
      if (st.getReturnTargets().size() > 1) {
        Log.error("A method with too many return parameters! Should have been removed in SSA");
        return null;
      }
      ProverFun fun = procedure2ProverExpr(st.getInvokedProcedure());

      Log.error(
          "This should not happen as calls are removed by SSA: "
              + fun.toString()); // TODO: proper error handling?
      // This can never happen.
      LinkedList<ProverExpr> args = new LinkedList<ProverExpr>();
      for (Expression e : st.getArguments()) {
        args.add(expression2ProverExpr(e));
      }
      ProverExpr ret = fun.mkExpr((ProverExpr[]) args.toArray(new ProverExpr[args.size()]));

      if (st.getReturnTargets().size() > 0) {
        ProverExpr lhs = expression2ProverExpr(st.getReturnTargets().get(0));
        if (st.getReturnTargets().get(0) instanceof SimpleHeapAccess
            || st.getReturnTargets().get(0) instanceof ArrayReadExpression) {
          ret = arrayWrite2ProverExpr(st.getReturnTargets().get(0), ret);
          // ((NAryExpression)lhs).addArgument(ret);
          // ret = VCExpressionGenerator.binOp(TmpConstants.Eq,
          // ((NAryExpression)lhs).getArgument(0),lhs);
        } else {
          ret = theoremProver.mkEq(lhs, ret);
        }
      }
      return ret;
    } else if (s instanceof ExpressionStatement) {
      ExpressionStatement es = (ExpressionStatement) s;
      return expression2ProverExpr(es.getExpression());
    } else {
      Log.error("Unmatched Statement " + s.toString());
      return null;
    }
  }
  private ProverFun procedure2ProverExpr(BoogieProcedure proc) {
    HashMap<Variable, ProverExpr> localbound = new HashMap<Variable, ProverExpr>();
    if (!usedFunctions.containsKey(proc)) {
      LinkedList<ProverType> args = new LinkedList<ProverType>();
      int idx = 0;
      for (Variable v : proc.getParameterList()) {
        ProverExpr arg = theoremProver.mkBoundVariable(idx++, type2ProverSort(v.getType()));
        args.add(arg.getType());
        localbound.put(v, arg);
      }

      ProverFun vcf = null;
      ProverType[] arr = args.toArray(new ProverType[args.size()]);
      if (proc.isPure()
          && proc.getRootBlock() != null
          && proc.getRootBlock().getStatements().size() == 1) {
        // TODO: this is a hack:
        // we assume that this case only occurs for prelude functions
        // which have only one statement
        // this will not work in any other case
        Statement stmt = proc.getRootBlock().getStatements().get(0);
        ProverExpr b = null;
        if (stmt instanceof ExpressionStatement) {
          ExpressionStatement es = (ExpressionStatement) stmt;
          b = expression2ProverExpr(es.getExpression(), localbound);
        } else {
          throw new RuntimeException("procedure2ProverExpr failed");
        }
        vcf = theoremProver.mkDefinedFunction(getProverFriendlyName(proc.getName()), arr, b);
      } else {
        vcf =
            theoremProver.mkUnintFunction(
                getProverFriendlyName(proc.getName()),
                arr,
                type2ProverSort(proc.getReturnVariable().getType()));

        // TODO: uninterpreted functions?
      }
      usedFunctions.put(proc, vcf);
    }
    return usedFunctions.get(proc);
  }