/* * Copyright (C) 2012-2015 Evren Ermis * Copyright (C) 2012-2015 Matthias Heizmann (heizmann@informatik.uni-freiburg.de) * Copyright (C) 2012-2015 University of Freiburg * * This file is part of the ULTIMATE ModelCheckerUtils Library. * * The ULTIMATE ModelCheckerUtils Library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The ULTIMATE ModelCheckerUtils Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the ULTIMATE ModelCheckerUtils Library. If not, see . * * Additional permission under GNU GPL version 3 section 7: * If you modify the ULTIMATE ModelCheckerUtils Library, or any covered work, by linking * or combining it with Eclipse RCP (or a modified version of Eclipse RCP), * containing parts covered by the terms of the Eclipse Public License, the * licensors of the ULTIMATE ModelCheckerUtils Library grant you additional permission * to convey the resulting work. */ package de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.boogie; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import de.uni_freiburg.informatik.ultimate.boogie.BitvectorFactory; import de.uni_freiburg.informatik.ultimate.boogie.DeclarationInformation; import de.uni_freiburg.informatik.ultimate.boogie.DeclarationInformation.StorageClass; import de.uni_freiburg.informatik.ultimate.boogie.ExpressionFactory; import de.uni_freiburg.informatik.ultimate.boogie.ast.ASTType; import de.uni_freiburg.informatik.ultimate.boogie.ast.ArrayAccessExpression; import de.uni_freiburg.informatik.ultimate.boogie.ast.ArrayStoreExpression; import de.uni_freiburg.informatik.ultimate.boogie.ast.Attribute; import de.uni_freiburg.informatik.ultimate.boogie.ast.BinaryExpression; import de.uni_freiburg.informatik.ultimate.boogie.ast.BinaryExpression.Operator; import de.uni_freiburg.informatik.ultimate.boogie.ast.BitVectorAccessExpression; import de.uni_freiburg.informatik.ultimate.boogie.ast.BitvecLiteral; import de.uni_freiburg.informatik.ultimate.boogie.ast.BooleanLiteral; import de.uni_freiburg.informatik.ultimate.boogie.ast.Expression; import de.uni_freiburg.informatik.ultimate.boogie.ast.FunctionApplication; import de.uni_freiburg.informatik.ultimate.boogie.ast.IdentifierExpression; import de.uni_freiburg.informatik.ultimate.boogie.ast.IfThenElseExpression; import de.uni_freiburg.informatik.ultimate.boogie.ast.IntegerLiteral; import de.uni_freiburg.informatik.ultimate.boogie.ast.PrimitiveType; import de.uni_freiburg.informatik.ultimate.boogie.ast.QuantifierExpression; import de.uni_freiburg.informatik.ultimate.boogie.ast.RealLiteral; import de.uni_freiburg.informatik.ultimate.boogie.ast.StringLiteral; import de.uni_freiburg.informatik.ultimate.boogie.ast.Trigger; import de.uni_freiburg.informatik.ultimate.boogie.ast.UnaryExpression; import de.uni_freiburg.informatik.ultimate.boogie.ast.VarList; import de.uni_freiburg.informatik.ultimate.boogie.type.BoogieType; import de.uni_freiburg.informatik.ultimate.core.model.models.IBoogieType; import de.uni_freiburg.informatik.ultimate.core.model.models.ILocation; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramFunction; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.LocalProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramConst; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramNonOldVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramOldVar; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.BitvectorUtils; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.logic.AnnotatedTerm; import de.uni_freiburg.informatik.ultimate.logic.Annotation; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; import de.uni_freiburg.informatik.ultimate.logic.ConstantTerm; import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol; import de.uni_freiburg.informatik.ultimate.logic.LetTerm; import de.uni_freiburg.informatik.ultimate.logic.QuantifiedFormula; import de.uni_freiburg.informatik.ultimate.logic.Rational; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.util.datastructures.BitvectorConstant.BvOp; import de.uni_freiburg.informatik.ultimate.util.datastructures.BitvectorConstant.ExtendOperation; import de.uni_freiburg.informatik.ultimate.util.datastructures.ScopedHashMap; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; /** * Translates SMT Terms to Boogie Expressions. * * @author heizmann@informatik.uni-freiburg.de * */ public final class Term2Expression implements Serializable { private static final long serialVersionUID = -4519646474900935398L; private final Script mScript; private TranslateState mTranslateState; private final TypeSortTranslator mTypeSortTranslator; private final ITerm2ExpressionSymbolTable mBoogie2SmtSymbolTable; private final Set mFreeVariables; private final NestedMap2 mCache; public Term2Expression(final TypeSortTranslator tsTranslation, final ITerm2ExpressionSymbolTable boogie2SmtSymbolTable, final ManagedScript maScript) { mTypeSortTranslator = tsTranslation; mBoogie2SmtSymbolTable = boogie2SmtSymbolTable; mScript = maScript.getScript(); mFreeVariables = new HashSet<>(); mTranslateState = new TranslateState(); mCache = new NestedMap2<>(); } private String getFreshIdentifier() { mTranslateState = mTranslateState.incrementIdentifierCounter(); return "freshIdentifier" + mTranslateState.getFreshIdentiferCounter(); } public Expression translate(final Term term) { final TranslateState stateAtStart = mTranslateState; Expression result = mCache.get(term, mTranslateState); if (result == null) { if (term instanceof AnnotatedTerm) { result = translate((AnnotatedTerm) term); } else if (term instanceof ApplicationTerm) { result = translate((ApplicationTerm) term); } else if (term instanceof ConstantTerm) { result = translate((ConstantTerm) term); } else if (term instanceof LetTerm) { result = translate((LetTerm) term); } else if (term instanceof QuantifiedFormula) { result = translate((QuantifiedFormula) term); } else if (term instanceof TermVariable) { result = translate((TermVariable) term); } else { throw new UnsupportedOperationException("unknown kind of Term"); } assert result != null; mCache.put(term, stateAtStart, result); } return result; } private static Expression translate(final AnnotatedTerm term) { throw new UnsupportedOperationException("annotations not supported yet" + term); } private Expression translate(final ApplicationTerm term) { final FunctionSymbol symb = term.getFunction(); if (symb.isIntern() && "select".equals(symb.getName())) { return translateSelect(term); } else if (symb.isIntern() && "store".equals(symb.getName())) { return translateStore(term); } else if (BitvectorUtils.isBitvectorConstant(symb)) { return translateBitvectorConstant(term); } final Term[] termParams = term.getParameters(); final Expression[] params = new Expression[termParams.length]; for (int i = 0; i < termParams.length; i++) { params[i] = translate(termParams[i]); } final IBoogieType type = mTypeSortTranslator.getType(symb.getReturnSort()); final Expression symbResult = translateWithSymbolTable(symb, type, termParams); if (symbResult != null) { return symbResult; } if (symb.getParameterSorts().length == 0) { if (SmtUtils.isTrueLiteral(term)) { final IBoogieType booleanType = mTypeSortTranslator.getType(SmtSortUtils.getBoolSort(mScript)); return new BooleanLiteral(null, booleanType, true); } if (SmtUtils.isFalseLiteral(term)) { final IBoogieType booleanType = mTypeSortTranslator.getType(SmtSortUtils.getBoolSort(mScript)); return new BooleanLiteral(null, booleanType, false); } final IProgramFunction programFun = mBoogie2SmtSymbolTable.getProgramFun(term.getFunction()); if (programFun instanceof ProgramConst) { return new IdentifierExpression(null, mTypeSortTranslator.getType(term.getSort()), ((ProgramConst) programFun).getIdentifier(), new DeclarationInformation(StorageClass.GLOBAL, null)); } throw new IllegalArgumentException(); } else if ("ite".equals(symb.getName())) { return new IfThenElseExpression(null, type, params[0], params[1], params[2]); } else if (symb.isIntern()) { // 2018-09-21 Matthias: This is a workaround for detecting if we have an // SMT function that has to be translated to an Boogie function and not // to a built-in Boogie operator. final boolean someParamIsBitvec = Arrays.stream(symb.getParameterSorts()).anyMatch(SmtSortUtils::isBitvecSort); final boolean someParamIsFloatingPoint = Arrays.stream(symb.getParameterSorts()).anyMatch(SmtSortUtils::isFloatingpointSort); final boolean someParamIsRoundingMode = Arrays.stream(symb.getParameterSorts()).anyMatch(SmtSortUtils::isRoundingmodeSort); final boolean resultIsBitvec = SmtSortUtils.isBitvecSort(symb.getReturnSort()); final boolean resultIsFloatingPoint = SmtSortUtils.isFloatingpointSort(symb.getReturnSort()); final boolean resultIsRoundingmodeSort = SmtSortUtils.isRoundingmodeSort(symb.getReturnSort()); if ((someParamIsBitvec || someParamIsFloatingPoint || someParamIsRoundingMode || resultIsBitvec || resultIsFloatingPoint || resultIsRoundingmodeSort) && !"=".equals(symb.getName()) && !"distinct".equals(symb.getName())) { if ("extract".equals(symb.getName())) { return translateBitvectorAccess(type, term); } else if ("concat".equals(symb.getName())) { return translateBitvectorConcat(type, term); } else if (Arrays.asList("bvsle", "bvslt", "bvsge", "bvsgt", "bvule", "bvult", "bvuge", "bvugt") .contains(symb.getName())) { return BitvectorFactory.constructBinaryOperationForMultipleArguments(null, BvOp.valueOf(symb.getName()), params); } else if (Arrays.asList("zero_extend", "sign_extend").contains(symb.getName())) { return BitvectorFactory.constructExtendOperation(null, ExtendOperation.valueOf(symb.getName()), new BigInteger(symb.getIndices()[0]), params[0]); } else if (Arrays.asList("bvnot", "bvneg").contains(symb.getName())) { return BitvectorFactory.constructUnaryOperation(null, BvOp.valueOf(symb.getName()), params[0]); } else if (Arrays.asList("bvadd", "bvsub", "bvmul", "bvudiv", "bvurem", "bvsdiv", "bvsrem", "bvsmod", "bvand", "bvor", "bvxor", "bvshl", "bvlshr", "bvashr").contains(symb.getName())) { return BitvectorFactory.constructBinaryOperationForMultipleArguments(null, BvOp.valueOf(symb.getName()), params); } else { throw new UnsupportedOperationException( "translation of " + symb + " not yet implemented, please contact Matthias"); } } else if (symb.getParameterSorts().length == 1) { if ("not".equals(symb.getName())) { final Expression param = translate(term.getParameters()[0]); if (param instanceof BinaryExpression) { // Translate (not (= (x y)) to x != y final BinaryExpression binary = (BinaryExpression) param; if (binary.getOperator() == Operator.COMPEQ) { return new BinaryExpression(binary.getLoc(), binary.getType(), Operator.COMPNEQ, binary.getLeft(), binary.getRight()); } } return new UnaryExpression(null, type, UnaryExpression.Operator.LOGICNEG, param); } else if ("-".equals(symb.getName())) { final Expression param = translate(term.getParameters()[0]); return new UnaryExpression(null, type, UnaryExpression.Operator.ARITHNEGATIVE, param); } else if ("to_real".equals(symb.getName())) { final Term param = term.getParameters()[0]; if (param instanceof ConstantTerm) { return ExpressionFactory.createRealLiteral(null, param.toString()); } else if (param instanceof ApplicationTerm) { final ApplicationTerm at = (ApplicationTerm) param; if (SmtUtils.isFunctionApplication(param, "-")) { if (at.getParameters().length == 1) { // unary minus return ExpressionFactory.createRealLiteral(null, "-" + at.getParameters()[0].toString()); } throw new UnsupportedOperationException("todo: implement more comprehensive to_real"); } throw new UnsupportedOperationException("todo: implement more comprehensive to_real"); } else { throw new UnsupportedOperationException("todo: implement more comprehensive to_real"); } } else if ("const".equals(symb.getName())) { // We don't support the backtranslation for now // If we want to backtranslate the Boogie expression to C, null is handled there // TODO: Backtranslate const properly return null; } else { throw new IllegalArgumentException("unknown symbol " + symb); } } else { if ("xor".equals(symb.getName())) { return xor(params); } else if ("mod".equals(symb.getName())) { return mod(params); } final Operator op = getBinaryOperator(symb); if (symb.isLeftAssoc()) { return leftAssoc(op, type, params); } else if (symb.isRightAssoc()) { return rightAssoc(op, type, params); } else if (symb.isChainable()) { return chainable(op, type, params); } else if (symb.isPairwise()) { return pairwise(op, type, params); } else { throw new UnsupportedOperationException( "don't know symbol" + " which is neither leftAssoc, rightAssoc, chainable, or pairwise."); } } } throw new UnsupportedOperationException( "translation of " + symb + " not yet implemented, please contact Matthias"); } private Expression translateBitvectorAccess(final IBoogieType type, final ApplicationTerm term) { assert "extract".equals(term.getFunction().getName()) : "no extract"; assert term.getParameters().length == 1; assert term.getFunction().getIndices().length == 2; final Expression bitvector = translate(term.getParameters()[0]); final int start = Integer.valueOf(term.getFunction().getIndices()[1]); final int end = Integer.valueOf(term.getFunction().getIndices()[0]); return new BitVectorAccessExpression(null, type, bitvector, end, start); } private Expression translateBitvectorConcat(final IBoogieType type, final ApplicationTerm term) { assert "concat".equals(term.getFunction().getName()) : "no extract"; assert term.getParameters().length == 2; final Expression op1 = translate(term.getParameters()[0]); final Expression op2 = translate(term.getParameters()[1]); return new BinaryExpression(null, type, Operator.BITVECCONCAT, op1, op2); } /** * Use symbol table to translate a SMT function application into a Boogie function application. */ private Expression translateWithSymbolTable(final FunctionSymbol symb, final IBoogieType type, final Term[] termParams) { final String identifier = mBoogie2SmtSymbolTable.translateToBoogieFunction(symb.getName(), type); if (identifier == null) { return null; } final Expression[] arguments = new Expression[termParams.length]; for (int i = 0; i < termParams.length; i++) { arguments[i] = translate(termParams[i]); } return new FunctionApplication(null, type, identifier, arguments); } /** * Translate term in case it is a bitvector constant as defined as an extension of the BV logic. */ private Expression translateBitvectorConstant(final ApplicationTerm term) { assert term.getSort().getIndices().length == 1; final String name = term.getFunction().getName(); assert name.startsWith("bv"); final String decimalValue = name.substring(2); final IBoogieType type = mTypeSortTranslator.getType(term.getSort()); final BigInteger length = new BigInteger(term.getSort().getIndices()[0]); return new BitvecLiteral(null, type, decimalValue, length.intValue()); } private static Expression mod(final Expression[] params) { if (params.length != 2) { throw new AssertionError("mod has two parameters"); } return new BinaryExpression(null, BoogieType.TYPE_INT, Operator.ARITHMOD, params[0], params[1]); } private ArrayStoreExpression translateStore(final ApplicationTerm term) { final Expression array = translate(term.getParameters()[0]); final Expression index = translate(term.getParameters()[1]); final Expression[] indices = { index }; final Expression value = translate(term.getParameters()[2]); final IBoogieType type = mTypeSortTranslator.getType(term.getSort()); return new ArrayStoreExpression(null, type, array, indices, value); } /** * Translate a single select expression to an ArrayAccessExpression. If we have nested select expressions this leads * to nested ArrayAccessExpressions, hence arrays which do not occur in the boogie program. */ private ArrayAccessExpression translateSelect(final ApplicationTerm term) { final Expression array = translate(term.getParameters()[0]); final Expression index = translate(term.getParameters()[1]); final Expression[] indices = { index }; final IBoogieType type = mTypeSortTranslator.getType(term.getSort()); return new ArrayAccessExpression(null, type, array, indices); } /** * Translate a nested sequence of select expressions to a single ArrayAccessExpression. (see translateSelect why * this might be useful) */ private ArrayAccessExpression translateArray(final ApplicationTerm term) { final List reverseIndices = new ArrayList<>(); ApplicationTerm localTerm = term; while ("select".equals(localTerm.getFunction().getName()) && localTerm.getParameters()[0] instanceof ApplicationTerm) { assert localTerm.getParameters().length == 2; final Expression index = translate(localTerm.getParameters()[1]); reverseIndices.add(index); localTerm = (ApplicationTerm) localTerm.getParameters()[0]; } assert localTerm.getParameters().length == 2; final Expression index = translate(localTerm.getParameters()[1]); reverseIndices.add(index); final Expression array = translate(localTerm.getParameters()[0]); final Expression[] indices = new Expression[reverseIndices.size()]; for (int i = 0; i < indices.length; i++) { indices[i] = reverseIndices.get(indices.length - 1 - i); } final IBoogieType type = mTypeSortTranslator.getType(localTerm.getSort()); return new ArrayAccessExpression(null, type, array, indices); } private Expression translate(final ConstantTerm term) { final Object value = term.getValue(); final IBoogieType type = mTypeSortTranslator.getType(term.getSort()); if (SmtSortUtils.isBitvecSort(term.getSort())) { final String[] indices = term.getSort().getIndices(); if (indices.length != 1) { throw new AssertionError("BitVec has exactly one index"); } final BigInteger bigInteger = BitvectorUtils.extractValueFromBitvectorConstant(term); final int length = Integer.valueOf(indices[0]); return new BitvecLiteral(null, type, String.valueOf(bigInteger), length); } if (value instanceof String) { return new StringLiteral(null, type, value.toString()); } else if (value instanceof BigInteger) { return new IntegerLiteral(null, type, value.toString()); } else if (value instanceof BigDecimal) { return new RealLiteral(null, type, value.toString()); } else if (value instanceof Rational) { if (SmtSortUtils.isIntSort(term.getSort())) { return new IntegerLiteral(null, type, value.toString()); } else if (SmtSortUtils.isRealSort(term.getSort())) { return new RealLiteral(null, type, value.toString()); } else { throw new UnsupportedOperationException("unknown Sort"); } } else { throw new UnsupportedOperationException("unknown kind of Term"); } } private static Expression translate(final LetTerm term) { throw new IllegalArgumentException("unlet Term first"); } private Expression translate(final QuantifiedFormula term) { mTranslateState = mTranslateState.beginQuantifiedVariablesScope(); final VarList[] parameters = new VarList[term.getVariables().length]; int offset = 0; for (final TermVariable tv : term.getVariables()) { final IBoogieType boogieType = mTypeSortTranslator.getType(tv.getSort()); final String[] identifiers = { tv.getName() }; final ASTType astType = new PrimitiveType(null, boogieType, boogieType.toString()); final VarList varList = new VarList(null, identifiers, astType); parameters[offset] = varList; mTranslateState = mTranslateState.putInQuantifiedVariables(tv, varList); offset++; } final IBoogieType type = mTypeSortTranslator.getType(term.getSort()); assert term.getQuantifier() == QuantifiedFormula.FORALL || term.getQuantifier() == QuantifiedFormula.EXISTS; final boolean isUniversal = term.getQuantifier() == QuantifiedFormula.FORALL; final String[] typeParams = {}; Attribute[] attributes; Term subTerm = term.getSubformula(); if (subTerm instanceof AnnotatedTerm) { assert ":pattern".equals(((AnnotatedTerm) subTerm).getAnnotations()[0].getKey()); final Annotation[] annotations = ((AnnotatedTerm) subTerm).getAnnotations(); // FIXME: does not have to be the case, allow several annotations assert annotations.length == 1 : "expecting only one annotation at a time"; final Annotation annotation = annotations[0]; final Object value = annotation.getValue(); assert value instanceof Term[] : "expecting Term[]" + value; subTerm = ((AnnotatedTerm) subTerm).getSubterm(); final Term[] pattern = (Term[]) value; if (pattern.length == 0) { attributes = new Attribute[0]; } else { final Expression[] triggers = new Expression[pattern.length]; for (int i = 0; i < pattern.length; i++) { triggers[i] = translate(pattern[i]); } final Trigger trigger = new Trigger(null, triggers); attributes = new Attribute[1]; attributes[0] = trigger; } } else { attributes = new Attribute[0]; } // TODO: This is wrong. The scope of the subterms has to be QUANTIFIED final Expression subformula = translate(subTerm); final QuantifierExpression result = new QuantifierExpression(null, type, isUniversal, typeParams, parameters, attributes, subformula); mTranslateState = mTranslateState.endQuantifiedVariablesScope(); return result; } private Expression translate(final TermVariable term) { final Expression result; final IBoogieType type = mTypeSortTranslator.getType(term.getSort()); if (mTranslateState.getQuantifiedVariables().containsKey(term)) { final VarList varList = mTranslateState.getQuantifiedVariables().get(term); assert varList.getIdentifiers().length == 1; final String id = varList.getIdentifiers()[0]; result = new IdentifierExpression(null, type, translateIdentifier(id), new DeclarationInformation(StorageClass.QUANTIFIED, null)); } else if (mBoogie2SmtSymbolTable.getProgramVar(term) == null) { // Case where term contains some auxilliary variable that was // introduced during model checking. // TODO: Matthias: I think we want closed expressions, we should // quantify auxilliary variables // TODO: DD: This can also happen if we add new program variables during IcfgTransformation that have no // counterpart in the boogie program (and do not add it to the symbol table) result = new IdentifierExpression(null, type, getFreshIdentifier(), new DeclarationInformation(StorageClass.QUANTIFIED, null)); mFreeVariables.add((IdentifierExpression) result); } else { final IProgramVar pv = mBoogie2SmtSymbolTable.getProgramVar(term); final ILocation loc = mBoogie2SmtSymbolTable.getLocation(pv); final DeclarationInformation declInfo = mBoogie2SmtSymbolTable.getDeclarationInformation(pv); if (pv instanceof LocalProgramVar) { result = new IdentifierExpression(loc, type, translateIdentifier(((LocalProgramVar) pv).getIdentifier()), declInfo); } else if (pv instanceof ProgramNonOldVar) { result = new IdentifierExpression(loc, type, translateIdentifier(((ProgramNonOldVar) pv).getIdentifier()), declInfo); } else if (pv instanceof ProgramOldVar) { assert pv.isGlobal(); final Expression nonOldExpression = new IdentifierExpression(loc, type, translateIdentifier(((ProgramOldVar) pv).getIdentifierOfNonOldVar()), declInfo); result = new UnaryExpression(loc, type, UnaryExpression.Operator.OLD, nonOldExpression); } else if (pv instanceof ProgramConst) { result = new IdentifierExpression(loc, type, translateIdentifier(((ProgramConst) pv).getIdentifier()), declInfo); } else { result = new IdentifierExpression(loc, type, pv.getGloballyUniqueId(), declInfo); } } return result; } /* * TODO escape all sequences that are not allowed in Boogie */ private static String translateIdentifier(final String id) { return id.replace(" ", "_").replace("(", "_").replace(")", "_").replace("+", "PLUS").replace("-", "MINUS") .replace("*", "MUL"); } private static Operator getBinaryOperator(final FunctionSymbol symb) { if ("and".equals(symb.getName())) { return Operator.LOGICAND; } else if ("or".equals(symb.getName())) { return Operator.LOGICOR; } else if ("=>".equals(symb.getName())) { return Operator.LOGICIMPLIES; } else if ("=".equals(symb.getName()) && "bool".equals(symb.getParameterSort(0).getName())) { return Operator.LOGICIFF; } else if ("=".equals(symb.getName())) { return Operator.COMPEQ; } else if ("distinct".equals(symb.getName())) { return Operator.COMPNEQ; } else if ("<=".equals(symb.getName())) { return Operator.COMPLEQ; } else if (">=".equals(symb.getName())) { return Operator.COMPGEQ; } else if ("<".equals(symb.getName())) { return Operator.COMPLT; } else if (">".equals(symb.getName())) { return Operator.COMPGT; } else if ("+".equals(symb.getName())) { return Operator.ARITHPLUS; } else if ("-".equals(symb.getName())) { return Operator.ARITHMINUS; } else if ("*".equals(symb.getName())) { return Operator.ARITHMUL; } else if ("/".equals(symb.getName())) { return Operator.ARITHDIV; } else if ("div".equals(symb.getName())) { return Operator.ARITHDIV; } else if ("mod".equals(symb.getName())) { return Operator.ARITHMOD; } else if ("ite".equals(symb.getName())) { throw new UnsupportedOperationException("not yet implemented"); } else if ("abs".equals(symb.getName())) { throw new UnsupportedOperationException("not yet implemented"); } else { throw new IllegalArgumentException("unknown symbol " + symb); } } private static Expression leftAssoc(final Operator op, final IBoogieType type, final Expression[] params) { Expression result = params[0]; for (int i = 0; i < params.length - 1; i++) { result = new BinaryExpression(null, type, op, result, params[i + 1]); } return result; } private static Expression rightAssoc(final Operator op, final IBoogieType type, final Expression[] params) { Expression result = params[params.length - 1]; for (int i = params.length - 1; i > 0; i--) { result = new BinaryExpression(null, type, op, params[i - 1], result); } return result; } private static Expression chainable(final Operator op, final IBoogieType type, final Expression[] params) { assert type == BoogieType.TYPE_BOOL; Expression result = new BinaryExpression(null, type, op, params[0], params[1]); Expression chain; for (int i = 1; i < params.length - 1; i++) { chain = new BinaryExpression(null, type, op, params[i], params[i + 1]); result = new BinaryExpression(null, BoogieType.TYPE_BOOL, Operator.LOGICAND, result, chain); } return result; } private static Expression pairwise(final Operator op, final IBoogieType type, final Expression[] params) { assert type == BoogieType.TYPE_BOOL; Expression result = new BinaryExpression(null, type, op, params[0], params[1]); Expression neq; for (int i = 0; i < params.length - 1; i++) { for (int j = i + 1; j < params.length - 1; j++) { if (i == 0 && j == 1) { continue; } neq = new BinaryExpression(null, type, op, params[j], params[j + 1]); result = new BinaryExpression(null, BoogieType.TYPE_BOOL, Operator.LOGICAND, result, neq); } } return result; } private static Expression xor(final Expression[] params) { final IBoogieType type = BoogieType.TYPE_BOOL; final Operator iff = Operator.LOGICIFF; final UnaryExpression.Operator neg = UnaryExpression.Operator.LOGICNEG; Expression result = params[0]; for (int i = 0; i < params.length - 1; i++) { result = new BinaryExpression(null, type, iff, params[i + 1], result); result = new UnaryExpression(null, type, neg, result); } return result; } /** * Represents the state that the result of a call to a translate*(Term) method in this class may depend on. * Immutable. Necessary for caching. * * @author Alexander Nutz (nutz@informatik.uni-freiburg.de) * */ private static class TranslateState { private final int mFreshIdentiferCounter; private final ScopedHashMap mQuantifiedVariables; /** * Create the initial translate state. */ TranslateState() { mFreshIdentiferCounter = 0; mQuantifiedVariables = new ScopedHashMap<>(); } /** * copy constructor * * @param freshIdentiferCounter * @param quantifiedVariables * Caller has to make sure this object is not used in other instances of TranslateState! */ private TranslateState(final int freshIdentiferCounter, final ScopedHashMap quantifiedVariables) { mFreshIdentiferCounter = freshIdentiferCounter; mQuantifiedVariables = quantifiedVariables; } TranslateState incrementIdentifierCounter() { return new TranslateState(mFreshIdentiferCounter + 1, mQuantifiedVariables); } TranslateState beginQuantifiedVariablesScope() { final ScopedHashMap copy = new ScopedHashMap<>(mQuantifiedVariables); copy.beginScope(); return new TranslateState(mFreshIdentiferCounter, copy); } TranslateState endQuantifiedVariablesScope() { final ScopedHashMap copy = new ScopedHashMap<>(mQuantifiedVariables); copy.endScope(); return new TranslateState(mFreshIdentiferCounter, copy); } TranslateState putInQuantifiedVariables(final TermVariable tv, final VarList vl) { final ScopedHashMap copy = new ScopedHashMap<>(mQuantifiedVariables); copy.put(tv, vl); return new TranslateState(mFreshIdentiferCounter, copy); } int getFreshIdentiferCounter() { return mFreshIdentiferCounter; } ScopedHashMap getQuantifiedVariables() { return mQuantifiedVariables; } @Override public int hashCode() { return Objects.hash(mFreshIdentiferCounter, mQuantifiedVariables); } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final TranslateState other = (TranslateState) obj; if (mFreshIdentiferCounter != other.mFreshIdentiferCounter) { return false; } if (mQuantifiedVariables == null) { if (other.mQuantifiedVariables != null) { return false; } } else if (!mQuantifiedVariables.equals(other.mQuantifiedVariables)) { return false; } return true; } } }