/*
* Copyright (C) 2017 Marius Greitschus
* 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.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import de.uni_freiburg.informatik.ultimate.boogie.DeclarationInformation;
import de.uni_freiburg.informatik.ultimate.boogie.DeclarationInformation.StorageClass;
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.BoogieASTNode;
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.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.ProgramFunction;
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.ScopedHashMap;
/**
* Translates SMT Terms to Boogie Expressions where occurring term variable names and corresponding Boogie variable
* names are known.
*
* @author Marius Greitschus (greitsch@informatik.uni-freiburg.de)
*
*/
public final class MappedTerm2Expression implements Serializable {
private static final long serialVersionUID = -3407883192314998843L;
private final Script mScript;
private final ScopedHashMap mQuantifiedVariables;
private int mFreshIdentiferCounter;
private final TypeSortTranslator mTypeSortTranslator;
private final Boogie2SmtSymbolTable mBoogie2SmtSymbolTable;
private final Set mFreeVariables;
public MappedTerm2Expression(final TypeSortTranslator tsTranslation,
final Boogie2SmtSymbolTable boogie2SmtSymbolTable, final ManagedScript maScript) {
mTypeSortTranslator = tsTranslation;
mBoogie2SmtSymbolTable = boogie2SmtSymbolTable;
mScript = maScript.getScript();
mFreeVariables = new HashSet<>();
mFreshIdentiferCounter = 0;
mQuantifiedVariables = new ScopedHashMap<>();
}
private String getFreshIdenfier() {
mFreshIdentiferCounter++;
return "freshIdentifier" + mFreshIdentiferCounter;
}
public Expression translate(final Term term, final Set variableNameRetainment,
final Map alternateOldNames) {
Expression result;
if (term instanceof AnnotatedTerm) {
result = translate((AnnotatedTerm) term, variableNameRetainment, alternateOldNames);
} else if (term instanceof ApplicationTerm) {
return translate((ApplicationTerm) term, variableNameRetainment, alternateOldNames);
} else if (term instanceof ConstantTerm) {
result = translate((ConstantTerm) term, variableNameRetainment, alternateOldNames);
} else if (term instanceof LetTerm) {
result = translate((LetTerm) term, variableNameRetainment, alternateOldNames);
} else if (term instanceof QuantifiedFormula) {
result = translate((QuantifiedFormula) term, variableNameRetainment, alternateOldNames);
} else if (term instanceof TermVariable) {
result = translate((TermVariable) term, variableNameRetainment, alternateOldNames);
} else {
throw new UnsupportedOperationException("unknown kind of Term");
}
assert result != null;
return result;
}
private static Expression translate(final AnnotatedTerm term, final Set variableMapRetainment,
final Map alternateOldNames) {
throw new UnsupportedOperationException("annotations not supported yet" + term);
}
private Expression translate(final ApplicationTerm term, final Set variableRewriteMap,
final Map alternateOldNames) {
final FunctionSymbol symb = term.getFunction();
if (symb.isIntern() && "select".equals(symb.getName())) {
return translateSelect(term, variableRewriteMap, alternateOldNames);
} else if (symb.isIntern() && "store".equals(symb.getName())) {
return translateStore(term, variableRewriteMap, alternateOldNames);
} 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], variableRewriteMap, alternateOldNames);
}
final IBoogieType type = mTypeSortTranslator.getType(symb.getReturnSort());
final Expression symbResult =
translateWithSymbolTable(symb, type, termParams, variableRewriteMap, alternateOldNames);
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 ProgramFunction 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()) {
if (symb.getParameterSorts().length > 0
&& (SmtSortUtils.isBitvecSort(symb.getParameterSorts()[0])
|| SmtSortUtils.isFloatingpointSort(symb.getReturnSort()))
&& !"=".equals(symb.getName()) && !"distinct".equals(symb.getName())) {
if ("extract".equals(symb.getName())) {
return translateBitvectorAccess(type, term, variableRewriteMap, alternateOldNames);
} 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], variableRewriteMap, alternateOldNames);
return new UnaryExpression(null, type, UnaryExpression.Operator.LOGICNEG, param);
} else if ("-".equals(symb.getName())) {
final Expression param = translate(term.getParameters()[0], variableRewriteMap, alternateOldNames);
return new UnaryExpression(null, type, UnaryExpression.Operator.ARITHNEGATIVE, param);
} 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,
final Set variableNameRetainment, final Map alternateOldNames) {
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], variableNameRetainment, alternateOldNames);
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);
}
/**
* Use symbol table to translate a SMT function application into a Boogie function application.
*
* @param alternateOldNames
*/
private Expression translateWithSymbolTable(final FunctionSymbol symb, final IBoogieType type,
final Term[] termParams, final Set variableNameRetainment,
final Map alternateOldNames) {
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], variableNameRetainment, alternateOldNames);
}
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, name.length());
final IBoogieType type = mTypeSortTranslator.getType(term.getSort());
final String length = term.getSort().getIndices()[0];
return new BitvecLiteral(null, type, decimalValue, Integer.valueOf(length));
}
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 Set variableNameRetainment, final Map alternateOldNames) {
final Expression array = translate(term.getParameters()[0], variableNameRetainment, alternateOldNames);
final Expression index = translate(term.getParameters()[1], variableNameRetainment, alternateOldNames);
final Expression[] indices = { index };
final Expression value = translate(term.getParameters()[2], variableNameRetainment, alternateOldNames);
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.
*
* @param alternateOldNames
*/
private ArrayAccessExpression translateSelect(final ApplicationTerm term,
final Set variableRewriteMap, final Map alternateOldNames) {
final Expression array = translate(term.getParameters()[0], variableRewriteMap, alternateOldNames);
final Expression index = translate(term.getParameters()[1], variableRewriteMap, alternateOldNames);
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)
*
* @param alternateOldNames
*/
private ArrayAccessExpression translateArray(final ApplicationTerm term,
final Set variableNameRetainment, final Map alternateOldNames) {
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], variableNameRetainment, alternateOldNames);
reverseIndices.add(index);
localTerm = (ApplicationTerm) localTerm.getParameters()[0];
}
assert localTerm.getParameters().length == 2;
final Expression index = translate(localTerm.getParameters()[1], variableNameRetainment, alternateOldNames);
reverseIndices.add(index);
final Expression array = translate(localTerm.getParameters()[0], variableNameRetainment, alternateOldNames);
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 Set variableNameRetainment,
final Map alternateOldNames) {
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");
}
BigInteger decimalValue;
if (value.toString().startsWith("#x")) {
decimalValue = new BigInteger(value.toString().substring(2), 16);
} else if (value.toString().startsWith("#b")) {
decimalValue = new BigInteger(value.toString().substring(2), 2);
} else {
throw new UnsupportedOperationException("only hexadecimal values and boolean values supported yet");
}
final int length = Integer.valueOf(indices[0]);
return new BitvecLiteral(null, type, String.valueOf(decimalValue), 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, final Set variableNameRetainment,
final Map alternateOldNames) {
throw new IllegalArgumentException("unlet Term first");
}
private Expression translate(final QuantifiedFormula term, final Set variableNameRetainment,
final Map alternateOldNames) {
mQuantifiedVariables.beginScope();
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;
mQuantifiedVariables.put(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 = new String[0];
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], variableNameRetainment, alternateOldNames);
}
final Trigger trigger = new Trigger(null, triggers);
attributes = new Attribute[1];
attributes[0] = trigger;
}
} else {
attributes = new Attribute[0];
}
final Expression subformula = translate(subTerm, variableNameRetainment, alternateOldNames);
final QuantifierExpression result =
new QuantifierExpression(null, type, isUniversal, typeParams, parameters, attributes, subformula);
mQuantifiedVariables.endScope();
return result;
}
private Expression translate(final TermVariable term, final Set variableNameRetainment,
final Map alternateOldNames) {
final Expression result;
final IBoogieType type = mTypeSortTranslator.getType(term.getSort());
if (alternateOldNames.containsKey(term)) {
result = new IdentifierExpression(null, type, alternateOldNames.get(term),
new DeclarationInformation(StorageClass.IMPLEMENTATION, null));
} else if (variableNameRetainment.contains(term)) {
result = new IdentifierExpression(null, type, term.getName(),
new DeclarationInformation(StorageClass.IMPLEMENTATION, null));
} else {
if (mQuantifiedVariables.containsKey(term)) {
final VarList varList = mQuantifiedVariables.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
result = new IdentifierExpression(null, type, getFreshIdenfier(),
new DeclarationInformation(StorageClass.QUANTIFIED, null));
mFreeVariables.add((IdentifierExpression) result);
} else {
final IProgramVar pv = mBoogie2SmtSymbolTable.getProgramVar(term);
final BoogieASTNode astNode = mBoogie2SmtSymbolTable.getAstNode(pv);
assert astNode != null : "There is no AstNode for the IProgramVar " + pv;
final ILocation loc = astNode.getLocation();
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 {
throw new AssertionError("unsupported kind of variable " + pv.getClass().getSimpleName());
}
}
}
return result;
}
/*
* TODO escape all sequences that are not allowed in Boogie
*/
private 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;
}
}