@Override
 public Collection<LassoUnderConstruction> process(final LassoUnderConstruction lasso)
     throws TermException {
   final MapEliminator elim =
       new MapEliminator(
           mServices,
           mManagedScript,
           mSymbolTable,
           mReplacementVarFactory,
           Arrays.asList(lasso.getStem(), lasso.getLoop()),
           mSettings);
   final EqualityAnalysisResult equalityAnalysisStem =
       new EqualityAnalysisResult(elim.getDoubletons());
   final EqualitySupportingInvariantAnalysis esia =
       new EqualitySupportingInvariantAnalysis(
           elim.getDoubletons(),
           mSymbolTable,
           mManagedScript.getScript(),
           mOriginalStem,
           mOriginalLoop,
           mModifiableGlobalsAtHonda);
   final EqualityAnalysisResult equalityAnalysisLoop = esia.getEqualityAnalysisResult();
   mArrayIndexSupportingInvariants.addAll(
       equalityAnalysisLoop.constructListOfEqualities(mManagedScript.getScript()));
   mArrayIndexSupportingInvariants.addAll(
       equalityAnalysisLoop.constructListOfNotEquals(mManagedScript.getScript()));
   final TransFormulaLR newStem =
       elim.getRewrittenTransFormula(lasso.getStem(), equalityAnalysisStem, equalityAnalysisLoop);
   final TransFormulaLR newLoop =
       elim.getRewrittenTransFormula(lasso.getLoop(), equalityAnalysisLoop, equalityAnalysisLoop);
   final LassoUnderConstruction newLasso = new LassoUnderConstruction(newStem, newLoop);
   assert RewriteArrays2.checkStemImplication(
           mServices,
           mServices.getLoggingService().getLogger(Activator.s_PLUGIN_ID),
           lasso,
           newLasso,
           mSymbolTable,
           mManagedScript)
       : "result of RewriteArrays too strong";
   return Collections.singleton(newLasso);
 }
  private Term translate(final Expression exp) {
    if (exp instanceof ArrayAccessExpression) {
      final ArrayAccessExpression arrexp = (ArrayAccessExpression) exp;
      final Expression[] indices = arrexp.getIndices();
      Term result = translate(arrexp.getArray());
      for (int i = 0; i < indices.length; i++) {
        final Term indexiTerm = translate(indices[i]);
        result = mScript.term("select", result, indexiTerm);
      }
      return result;

    } else if (exp instanceof ArrayStoreExpression) {
      final ArrayStoreExpression arrexp = (ArrayStoreExpression) exp;
      final Expression[] indices = arrexp.getIndices();
      assert indices.length > 0;
      // arrayBeforeIndex[i] represents the array, where all indices
      // before the i'th index have already been selected
      final Term[] arrayBeforeIndex = new Term[indices.length];
      final Term[] indexTerm = new Term[indices.length];
      arrayBeforeIndex[0] = translate(arrexp.getArray());
      for (int i = 0; i < indices.length - 1; i++) {
        indexTerm[i] = translate(indices[i]);
        arrayBeforeIndex[i + 1] = mScript.term("select", arrayBeforeIndex[i], indexTerm[i]);
      }
      indexTerm[indices.length - 1] = translate(indices[indices.length - 1]);
      Term result = translate(arrexp.getValue());
      for (int i = indices.length - 1; i >= 0; i--) {
        result = mScript.term("store", arrayBeforeIndex[i], indexTerm[i], result);
      }
      assert (result != null);
      assert resultContainsNoNull(result);
      return result;

    } else if (exp instanceof BinaryExpression) {
      final BinaryExpression binexp = (BinaryExpression) exp;
      final BinaryExpression.Operator op = binexp.getOperator();
      // Sort sort = mSmt2Boogie.getSort(binexp.getLeft().getType());
      if (op == BinaryExpression.Operator.COMPNEQ) {
        final String equalityFuncname =
            mOperationTranslator.opTranslation(
                BinaryExpression.Operator.COMPEQ,
                binexp.getLeft().getType(),
                binexp.getRight().getType());
        final String negationFuncname =
            mOperationTranslator.opTranslation(
                UnaryExpression.Operator.LOGICNEG, PrimitiveType.TYPE_BOOL);
        final BigInteger[] indices = new BigInteger[0];
        return SmtUtils.termWithLocalSimplification(
            mScript,
            negationFuncname,
            indices,
            SmtUtils.termWithLocalSimplification(
                mScript,
                equalityFuncname,
                indices,
                translate(binexp.getLeft()),
                translate(binexp.getRight())));
      } else {
        final String funcname =
            mOperationTranslator.opTranslation(
                op, binexp.getLeft().getType(), binexp.getRight().getType());
        final BigInteger[] indices = null;
        return SmtUtils.termWithLocalSimplification(
            mScript, funcname, indices, translate(binexp.getLeft()), translate(binexp.getRight()));
      }
    } else if (exp instanceof UnaryExpression) {
      final UnaryExpression unexp = (UnaryExpression) exp;
      final UnaryExpression.Operator op = unexp.getOperator();
      if (op == UnaryExpression.Operator.OLD) {
        mOldContextScopeDepth++;
        final Term term = translate(unexp.getExpr());
        mOldContextScopeDepth--;
        return term;
      } else {
        final String funcname = mOperationTranslator.opTranslation(op, unexp.getExpr().getType());
        final BigInteger[] indices = null;
        return SmtUtils.termWithLocalSimplification(
            mScript, funcname, indices, translate(unexp.getExpr()));
      }
    } else if (exp instanceof RealLiteral) {
      final Term result = mOperationTranslator.realTranslation((RealLiteral) exp);
      assert result != null;
      return result;

    } else if (exp instanceof BitvecLiteral) {
      final Term result = mOperationTranslator.bitvecTranslation((BitvecLiteral) exp);
      assert result != null;
      return result;

    } else if (exp instanceof BitVectorAccessExpression) {
      final BigInteger[] indices = new BigInteger[2];
      indices[0] = new BigInteger(Integer.toString(((BitVectorAccessExpression) exp).getEnd() - 1));
      indices[1] = new BigInteger(Integer.toString(((BitVectorAccessExpression) exp).getStart()));

      final Term result =
          mScript.term(
              "extract", indices, null, translate(((BitVectorAccessExpression) exp).getBitvec()));
      assert result != null;
      return result;

    } else if (exp instanceof BooleanLiteral) {
      final Term result = mOperationTranslator.booleanTranslation((BooleanLiteral) exp);
      assert result != null;
      return result;

    } else if (exp instanceof FunctionApplication) {
      final FunctionApplication func = ((FunctionApplication) exp);
      final Term result;
      final Map<String, Expression[]> attributes =
          mBoogie2SmtSymbolTable.getAttributes(func.getIdentifier());
      final String overapproximation =
          Boogie2SmtSymbolTable.checkForAttributeDefinedIdentifier(attributes, s_Overapproximation);
      if (mOverapproximateFunctions || overapproximation != null) {
        final Sort resultSort = mTypeSortTranslator.getSort(exp.getType(), exp);
        final TermVariable auxVar =
            mVariableManager.constructFreshTermVariable(func.getIdentifier(), resultSort);
        mAuxVars.add(auxVar);
        mOverapproximations.put(overapproximation, exp.getLocation());
        result = auxVar;
      } else {
        final BigInteger[] indices = Boogie2SmtSymbolTable.checkForIndices(attributes);
        final IBoogieType[] argumentTypes = new IBoogieType[func.getArguments().length];
        for (int i = 0; i < func.getArguments().length; i++) {
          argumentTypes[i] = func.getArguments()[i].getType();
        }

        final Sort[] params = new Sort[func.getArguments().length];
        for (int i = 0; i < func.getArguments().length; i++) {
          params[i] = mTypeSortTranslator.getSort(func.getArguments()[i].getType(), exp);
        }

        final Term[] parameters = new Term[func.getArguments().length];
        for (int i = 0; i < func.getArguments().length; i++) {
          parameters[i] = translate(func.getArguments()[i]);
        }

        final String funcSymb =
            mOperationTranslator.funcApplication(func.getIdentifier(), argumentTypes);
        if (funcSymb == null) {
          throw new IllegalArgumentException("unknown function" + func.getIdentifier());
        }
        //				result = mScript.term(funcSymb, indices, null, parameters);
        // overkill, this should be called only for bitvector operations.
        result = SmtUtils.termWithLocalSimplification(mScript, funcSymb, indices, parameters);
      }
      return result;
    } else if (exp instanceof IdentifierExpression) {
      final IdentifierExpression var = (IdentifierExpression) exp;
      assert var.getDeclarationInformation() != null : " no declaration information";
      final Term result =
          getSmtIdentifier(
              var.getIdentifier(), var.getDeclarationInformation(), isOldContext(), exp);
      assert result != null;
      return result;

    } else if (exp instanceof IntegerLiteral) {
      final Term result = mOperationTranslator.integerTranslation((IntegerLiteral) exp);
      assert result != null;
      return result;

    } else if (exp instanceof IfThenElseExpression) {
      final IfThenElseExpression ite = (IfThenElseExpression) exp;
      final Term cond = translate(ite.getCondition());
      final Term thenPart = translate(ite.getThenPart());
      final Term elsePart = translate(ite.getElsePart());
      final Term result = Util.ite(mScript, cond, thenPart, elsePart);
      assert result != null;
      return result;

    } else if (exp instanceof QuantifierExpression) {
      // throw new
      // UnsupportedOperationException("QuantifierExpression not implemented yet");
      final QuantifierExpression quant = (QuantifierExpression) exp;
      final String[] typeParams = quant.getTypeParams();
      final VarList[] variables = quant.getParameters();
      int numvars = typeParams.length;
      for (int i = 0; i < variables.length; i++) {
        numvars += variables[i].getIdentifiers().length;
      }
      final TermVariable[] vars = new TermVariable[numvars];
      // TODO is this really unused code
      // HashMap<String,Term> newVars = new HashMap<String, Term>();
      int offset = 0;
      // for (int j = 0; j < typeParams.length; j++) {
      // vars[offset] = mScript.createTermVariable("q" +
      // quoteId(typeParams[j]), intSort);
      // typeStack.push(vars[offset]);
      // offset++;
      // }
      mQuantifiedVariables.beginScope();
      for (int i = 0; i < variables.length; i++) {
        final IBoogieType type = variables[i].getType().getBoogieType();
        final Sort sort = mTypeSortTranslator.getSort(type, exp);
        for (int j = 0; j < variables[i].getIdentifiers().length; j++) {
          final String identifier = variables[i].getIdentifiers()[j];
          final String smtVarName = "q" + Boogie2SMT.quoteId(variables[i].getIdentifiers()[j]);
          vars[offset] = mScript.variable(smtVarName, sort);
          mQuantifiedVariables.put(identifier, vars[offset]);
          offset++;
        }
      }
      final Term form = translate(quant.getSubformula());

      final Attribute[] attrs = quant.getAttributes();
      int numTrigs = 0;
      for (final Attribute a : attrs) {
        if (a instanceof Trigger) {
          numTrigs++;
        }
      }
      final Term[][] triggers = new Term[numTrigs][];
      offset = 0;
      for (final Attribute a : attrs) {
        if (a instanceof Trigger) {
          final Expression[] trigs = ((Trigger) a).getTriggers();
          final Term[] smttrigs = new Term[trigs.length];
          for (int i = 0; i < trigs.length; i++) {
            final Term trig = translate(trigs[i]);
            // if (trig instanceof ITETerm
            // && ((ITETerm)trig).getTrueCase() == ONE
            // && ((ITETerm)trig).getFalseCase() == ZERO)
            // smttrigs[i] = ((ITETerm) trig).getCondition();
            // else
            smttrigs[i] = trig;
          }
          triggers[offset++] = smttrigs;
        }
      }
      // throw new
      // UnsupportedOperationException("QuantifierExpression not implemented yet");
      // identStack.pop();
      // for (int j = 0; j < typeParams.length; j++) {
      // typeStack.pop();
      // }
      mQuantifiedVariables.endScope();

      Term result = null;
      try {
        result =
            quant.isUniversal()
                ? mScript.quantifier(Script.FORALL, vars, form, triggers)
                : mScript.quantifier(Script.EXISTS, vars, form, triggers);
      } catch (final SMTLIBException e) {
        if (e.getMessage().equals("Cannot create quantifier in quantifier-free logic")) {
          Boogie2SMT.reportUnsupportedSyntax(
              exp, "Setting does not support quantifiers", mServices);
          throw e;
        } else {
          throw new AssertionError();
        }
      }
      assert resultContainsNoNull(result);
      return result;
    } else {
      throw new AssertionError("Unsupported expression " + exp);
    }
  }