/* * Copyright (C) 2016 Matthias Heizmann (heizmann@informatik.uni-freiburg.de) * Copyright (C) 2016 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.cfg; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ILocalProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramConst; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramFunction; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramNonOldVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramOldVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVarOrConst; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.HashRelation; /** * Default implementation of an {@link IIcfgSymbolTable} * * @author Matthias Heizmann (heizmann@informatik.uni-freiburg.de) * */ public class DefaultIcfgSymbolTable implements IIcfgSymbolTable { protected final Map mTermVariable2ProgramVar = new HashMap<>(); protected final Map mFunSym2ProgramFunction = new HashMap<>(); protected final Set mGlobals = new HashSet<>(); protected final Set mConstants = new HashSet<>(); protected final HashRelation mLocals = new HashRelation<>(); protected boolean mConstructionFinished = false; /** * Constructor for empty symbol table. */ public DefaultIcfgSymbolTable() { } /** * Constructs copy of {@link IIcfgSymbolTable} */ public DefaultIcfgSymbolTable(final IIcfgSymbolTable symbolTable, final Set procs) { for (final IProgramConst constant : symbolTable.getConstants()) { add(constant); } for (final IProgramNonOldVar nonold : symbolTable.getGlobals()) { add(nonold); } for (final String proc : procs) { for (final ILocalProgramVar local : symbolTable.getLocals(proc)) { add(local); } } assert checkGlobals(); } @Override public IProgramVar getProgramVar(final TermVariable tv) { return mTermVariable2ProgramVar.get(tv); } @Override public IProgramFunction getProgramFun(final FunctionSymbol funSym) { return mFunSym2ProgramFunction.get(funSym); } @Override public Set getGlobals() { return Collections.unmodifiableSet(mGlobals); } @Override public Set getConstants() { return Collections.unmodifiableSet(mConstants); } @Override public Set getLocals(final String proc) { final Set locals = mLocals.getImage(proc); if (locals == null) { return Collections.emptySet(); } return Collections.unmodifiableSet(mLocals.getImage(proc)); } public void addFun(final IProgramFunction fun) { mFunSym2ProgramFunction.put(fun.getFunctionSymbol(), fun); } public void add(final IProgramVarOrConst varOrConst) { if (mConstructionFinished) { throw new IllegalStateException("Construction finished, unable to add new variables or constants."); } if (varOrConst instanceof IProgramConst) { final IProgramConst pc = (IProgramConst) varOrConst; mConstants.add(pc); mFunSym2ProgramFunction.put(pc.getDefaultConstant().getFunction(), pc); } else if (varOrConst instanceof IProgramVar) { final IProgramVar var = (IProgramVar) varOrConst; mTermVariable2ProgramVar.put(var.getTermVariable(), var); if (var instanceof IProgramOldVar || var.isOldvar()) { throw new IllegalArgumentException("cannot add oldvar, add nonoldvar instead: " + var); } else if (var instanceof ILocalProgramVar) { mLocals.addPair(var.getProcedure(), (ILocalProgramVar) var); } else if (var instanceof IProgramNonOldVar) { final IProgramNonOldVar nonOldVar = (IProgramNonOldVar) var; mGlobals.add(nonOldVar); final IProgramOldVar oldVar = nonOldVar.getOldVar(); mTermVariable2ProgramVar.put(oldVar.getTermVariable(), oldVar); assert Objects.equals(oldVar.getNonOldVar(), var) : "getNonOldVar() and getOldVar() should match, but do not! Oldvar: " + oldVar + " Var: " + var; } else { throw new AssertionError("unknown kind of variable"); } } else { throw new AssertionError("unknown kind of variable"); } } /** * Make this {@link IIcfgSymbolTable} unmodifiable. */ public void finishConstruction() { mConstructionFinished = true; assert checkGlobals(); } private boolean checkGlobals() { if (mTermVariable2ProgramVar.entrySet().stream().anyMatch(a -> a.getValue() == null)) { throw new AssertionError("Null entry in TermVar2ProgramVar"); } final Set programVars = mTermVariable2ProgramVar.entrySet().stream() .map(Entry::getValue).collect(Collectors.toSet()); final Set oldVars = programVars.stream().filter(IProgramVar::isOldvar).collect(Collectors.toSet()); final Optional any = oldVars.stream().map(a -> (IProgramOldVar) a) .filter(a -> !programVars.contains(a.getNonOldVar())).findAny(); if (any.isPresent()) { throw new AssertionError("old var with no corresponding var: " + any.get()); } return true; } @Override public Set computeAllDefaultConstants() { final Set rtr = new LinkedHashSet<>(); mGlobals.stream().map(a -> a.getDefaultConstant()).forEachOrdered(rtr::add); mLocals.getSetOfPairs().stream().map(a -> a.getValue().getDefaultConstant()).forEachOrdered(rtr::add); return rtr; } }