/* * Copyright (C) 2014-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.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.function.Function; import java.util.stream.Stream; 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.Attribute; import de.uni_freiburg.informatik.ultimate.boogie.ast.BoogieASTNode; import de.uni_freiburg.informatik.ultimate.boogie.ast.ConstDeclaration; import de.uni_freiburg.informatik.ultimate.boogie.ast.Declaration; import de.uni_freiburg.informatik.ultimate.boogie.ast.Expression; import de.uni_freiburg.informatik.ultimate.boogie.ast.FunctionDeclaration; import de.uni_freiburg.informatik.ultimate.boogie.ast.IntegerLiteral; import de.uni_freiburg.informatik.ultimate.boogie.ast.NamedAttribute; import de.uni_freiburg.informatik.ultimate.boogie.ast.Procedure; import de.uni_freiburg.informatik.ultimate.boogie.ast.StringLiteral; import de.uni_freiburg.informatik.ultimate.boogie.ast.VarList; import de.uni_freiburg.informatik.ultimate.boogie.ast.VariableDeclaration; import de.uni_freiburg.informatik.ultimate.boogie.type.BoogieArrayType; import de.uni_freiburg.informatik.ultimate.boogie.type.StructExpanderUtil; 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.DefaultIcfgSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IIcfgSymbolTable; 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.IProgramNonOldVar; 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.modelcheckerutils.cfg.variables.ProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramVarUtils; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.scripttransfer.DeclarableFunctionSymbol; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.scripttransfer.ISmtDeclarable; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol; import de.uni_freiburg.informatik.ultimate.logic.QuotedObject; import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.HashRelation; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; /** * Stores a mapping from Boogie identifiers to {@link ProgramVar}s and a mapping * from TermVariables that are representatives of {@link ProgramVar}s to their * {@link ProgramVar}. * * TODO 2018-09-15 Matthias: This class was build before we had * {@link DeclarationInformation} and might be unnecessarily complicated. * * @author Matthias Heizmann * */ public class Boogie2SmtSymbolTable implements IIcfgSymbolTable, IBoogieSymbolTableVariableProvider, ITerm2ExpressionSymbolTable { /** * Identifier of attribute that we use to state that * * */ public static final String ID_BUILTIN = "builtin"; /** * Identifier of attribute that we use to declare a function symbol that should be mapped to an SMT term */ public static final String ID_SMTDEFINED = "smtdefined"; private static final String ID_INDICES = "indices"; /** * Identifier of attribute that indicates that this function defines a const array function. */ private static final String ID_CONST_ARRAY = StructExpanderUtil.ATTRIBUTE_CONST_ARRAY; /** * Identifier of attribute that indicates the position this function takes in its struct. */ private static final String ID_STRUCTPOS = StructExpanderUtil.ATTRIBUTE_STRUCTPOS; private final BoogieDeclarations mBoogieDeclarations; private final ManagedScript mScript; private final TypeSortTranslator mTypeSortTranslator; private final Map mGlobals = new HashMap<>(); private final Map mOldGlobals = new HashMap<>(); private final Map> mSpecificationInParam = new HashMap<>(); private final Map> mSpecificationOutParam = new HashMap<>(); private final Map> mImplementationInParam = new HashMap<>(); private final Map> mImplementationOutParam = new HashMap<>(); private final Map> mProc2InParams = new HashMap<>(); private final Map> mProc2OutParams = new HashMap<>(); private final Map> mImplementationLocals = new HashMap<>(); private final Map mConstants = new HashMap<>(); private final Map mSmtVar2ProgramVar = new HashMap<>(); private final Map mProgramVar2DeclarationInformation = new HashMap<>(); private final Map mProgramVar2AstNode = new HashMap<>(); private final Map mSmtConst2ProgramConst = new HashMap<>(); private final Map mBoogieFunction2SmtFunction = new HashMap<>(); private final NestedMap2 mSmtFunction2BoogieFunction = new NestedMap2<>(); private final Map> mBoogieFunction2Attributes = new HashMap<>(); private final DefaultIcfgSymbolTable mIcfgSymbolTable = new DefaultIcfgSymbolTable(); public Boogie2SmtSymbolTable(final BoogieDeclarations boogieDeclarations, final ManagedScript script, final TypeSortTranslator typeSortTranslator) { mScript = script; mTypeSortTranslator = typeSortTranslator; mBoogieDeclarations = boogieDeclarations; mScript.lock(this); mScript.echo(this, new QuotedObject("Start declaration of constants")); for (final ConstDeclaration decl : mBoogieDeclarations.getConstDeclarations()) { declareConstants(decl); } mScript.echo(this, new QuotedObject("Finished declaration of constants")); mScript.echo(this, new QuotedObject("Start declaration of functions")); for (final FunctionDeclaration decl : mBoogieDeclarations.getFunctionDeclarations()) { declareFunction(decl); } mScript.echo(this, new QuotedObject("Finished declaration of functions")); mScript.echo(this, new QuotedObject("Start declaration of global variables")); for (final VariableDeclaration decl : mBoogieDeclarations.getGlobalVarDeclarations()) { declareGlobalVariables(decl); } mScript.echo(this, new QuotedObject("Finished declaration global variables")); mScript.echo(this, new QuotedObject("Start declaration of local variables")); for (final String procId : mBoogieDeclarations.getProcSpecification().keySet()) { final Procedure procSpec = mBoogieDeclarations.getProcSpecification().get(procId); final Procedure procImpl = mBoogieDeclarations.getProcImplementation().get(procId); if (procImpl == null) { declareSpec(procSpec); } else { declareSpecImpl(procSpec, procImpl); } } mScript.echo(this, new QuotedObject("Finished declaration local variables")); mScript.unlock(this); } private static void putNew(final String procId, final String varId, final T pv, final Map> map) { Map varId2ProgramVar = map.get(procId); if (varId2ProgramVar == null) { varId2ProgramVar = new HashMap<>(); map.put(procId, varId2ProgramVar); } final IProgramVar previousValue = varId2ProgramVar.put(varId, pv); assert previousValue == null : "variable already contained"; } private static void putNew(final String varId, final VALUE value, final Map map) { final VALUE previousValue = map.put(varId, value); assert previousValue == null : "variable already contained"; } private static T get(final String varId, final String procId, final Map> map) { final Map varId2ProgramVar = map.get(procId); if (varId2ProgramVar == null) { return null; } return varId2ProgramVar.get(varId); } public static boolean isSpecification(final Procedure spec) { return spec.getSpecification() != null; } public static boolean isImplementation(final Procedure impl) { return impl.getBody() != null; } @Override public IProgramVar getBoogieVar(final String varId, final DeclarationInformation declarationInformation, final boolean inOldContext) { final StorageClass storageClass = declarationInformation.getStorageClass(); final String procedure = declarationInformation.getProcedure(); switch (storageClass) { case GLOBAL: if (inOldContext) { return mOldGlobals.get(varId); } return mGlobals.get(varId); case PROC_FUNC_INPARAM: case IMPLEMENTATION_INPARAM: return get(varId, procedure, mImplementationInParam); case PROC_FUNC_OUTPARAM: case IMPLEMENTATION_OUTPARAM: return get(varId, procedure, mImplementationOutParam); case LOCAL: return get(varId, procedure, mImplementationLocals); case IMPLEMENTATION: case PROC_FUNC: case QUANTIFIED: default: throw new AssertionError("inappropriate decl info " + declarationInformation); } } /** * Get IProgramVar for in our outparams. * * @param varId * The id of the param. * @param procedure * The procedure. * @param isInParam * true iff its an inparam, false if its an outparam. * @return The IProgramVar. */ @Override public IProgramVar getBoogieVar(final String varId, final String procedure, final boolean isInParam) { if (isInParam) { return get(varId, procedure, mImplementationInParam); } return get(varId, procedure, mImplementationOutParam); } @Override public IProgramVar getProgramVar(final TermVariable tv) { return mIcfgSymbolTable.getProgramVar(tv); } @Override public DeclarationInformation getDeclarationInformation(final IProgramVar pv) { return mProgramVar2DeclarationInformation.get(pv); } public BoogieASTNode getAstNode(final IProgramVar pv) { return mProgramVar2AstNode.get(pv); } private void declareConstants(final ConstDeclaration constdecl) { final VarList varlist = constdecl.getVarList(); final Map attributes = extractAttributes(constdecl); if (attributes != null) { final String attributeDefinedIdentifier = checkForAttributeDefinedIdentifier(attributes, ID_BUILTIN); if (attributeDefinedIdentifier != null) { if (varlist.getIdentifiers().length > 1) { throw new IllegalArgumentException( "if builtin identifier is " + "used we support only one constant per const declaration"); } final String constId = varlist.getIdentifiers()[0]; final String[] indices = Boogie2SmtSymbolTable.checkForIndices(attributes); final ApplicationTerm constant = (ApplicationTerm) mScript.term(this, attributeDefinedIdentifier, indices, null); final ProgramConst programConst = new ProgramConst(constId, constant, true); final ProgramConst previousValue = mConstants.put(constId, programConst); assert previousValue == null : "constant already contained"; mSmtConst2ProgramConst.put(constant, programConst); mIcfgSymbolTable.add(programConst); return; } } final Sort[] paramTypes = new Sort[0]; final IBoogieType iType = varlist.getType().getBoogieType(); final Sort sort = mTypeSortTranslator.getSort(iType, varlist); for (final String constId : varlist.getIdentifiers()) { mScript.declareFun(this, constId, paramTypes, sort); final ApplicationTerm constant = (ApplicationTerm) mScript.term(this, constId); final ProgramConst programConst = new ProgramConst(constId, constant, false); final ProgramConst previousValue = mConstants.put(constId, programConst); assert previousValue == null : "constant already contained"; mSmtConst2ProgramConst.put(constant, programConst); mIcfgSymbolTable.add(programConst); } } @Override public ProgramConst getBoogieConst(final String constId) { return mConstants.get(constId); } @Override public ProgramFunction getProgramFun(final FunctionSymbol smtFunSym) { return (ProgramFunction) mIcfgSymbolTable.getProgramFun(smtFunSym); } public Map getAttributes(final String boogieFunctionId) { final Map attributes = mBoogieFunction2Attributes.get(boogieFunctionId); if (attributes == null) { throw new AssertionError("Undeclared function: " + boogieFunctionId); } return Collections.unmodifiableMap(attributes); } private void declareFunction(final FunctionDeclaration funcdecl) { final Map attributes = extractAttributes(funcdecl); final String id = funcdecl.getIdentifier(); mBoogieFunction2Attributes.put(id, attributes); final boolean attributeConstArray = checkForAttributeWithoutValue(attributes, ID_CONST_ARRAY); final String attributeDefinedIdentifier = checkForAttributeDefinedIdentifier(attributes, ID_BUILTIN); final String smtDefinedBody = checkForAttributeDefinedIdentifier(attributes, ID_SMTDEFINED); final String smtID; int numParams = 0; for (final VarList vl : funcdecl.getInParams()) { final int ids = vl.getIdentifiers().length; numParams += ids == 0 ? 1 : ids; } final Sort[] paramSorts = new Sort[numParams]; final String[] paramIds = new String[numParams]; int paramNr = 0; for (final VarList vl : funcdecl.getInParams()) { int ids = vl.getIdentifiers().length; if (ids == 0) { ids = 1; } final IBoogieType paramType = vl.getType().getBoogieType(); final Sort paramSort = mTypeSortTranslator.getSort(paramType, funcdecl); for (int i = 0; i < ids; i++) { paramSorts[paramNr] = paramSort; if (i < vl.getIdentifiers().length) { paramIds[paramNr] = vl.getIdentifiers()[i]; } else { paramIds[paramNr] = null; } paramNr++; } } final IBoogieType resultType = funcdecl.getOutParam().getType().getBoogieType(); final Sort resultSort = mTypeSortTranslator.getSort(resultType, funcdecl); if (attributeConstArray) { // Builtin const function needs special handling for struct types. // We create a define fun, that calls the SMT builtin function const with the correct return type // and the correct parameter. smtID = Boogie2SMT.quoteId(id); final String structPos = checkForAttributeDefinedIdentifier(attributes, ID_STRUCTPOS); final int paramPos = structPos == null ? 0 : Integer.parseInt(structPos); if (structPos == null && paramIds.length > 1) { throw new ISmtDeclarable.IllegalSmtDeclarableUsageException( "Internal problem with expanding const-array function: " + id); } if (!(resultType instanceof BoogieArrayType) || ((BoogieArrayType) resultType) .getValueType() != funcdecl.getInParams()[paramPos].getType().getBoogieType()) { throw new ISmtDeclarable.IllegalSmtDeclarableUsageException( "Type mismatch in const-array function: " + id); } final TermVariable[] paramTVs = new TermVariable[paramIds.length]; for (int i = 0; i < paramTVs.length; i++) { paramTVs[i] = mScript.getScript().variable(paramIds[i], paramSorts[i]); } final Deque sortHierarchy = new ArrayDeque<>(); Sort sort = resultSort; while (sort != paramSorts[paramPos]) { sortHierarchy.addLast(sort); assert sort.getName().equals("Array"); sort = sort.getArguments()[1]; } assert sortHierarchy.size() >= 1; Term smtBody = paramTVs[paramPos]; while (!sortHierarchy.isEmpty()) { final Sort arraySort = sortHierarchy.removeLast(); smtBody = mScript.getScript().term("const", null, arraySort, smtBody); } final DeclarableFunctionSymbol smtFunctionDefinition = DeclarableFunctionSymbol.createFromScriptDefineFun(smtID, paramTVs, resultSort, smtBody); smtFunctionDefinition.defineOrDeclare(mScript.getScript()); } else if (attributeDefinedIdentifier == null) { // no builtin function, we have to declare it smtID = Boogie2SMT.quoteId(id); final DeclarableFunctionSymbol smtFunctionDefinition = DeclarableFunctionSymbol .createFromString(mScript.getScript(), smtID, smtDefinedBody, paramIds, paramSorts, resultSort); smtFunctionDefinition.defineOrDeclare(mScript.getScript()); final FunctionSymbol funSymb = mScript.getScript().getFunctionSymbol(smtID); final ProgramFunction progFunc = new ProgramFunction(funSymb); mIcfgSymbolTable.addFun(progFunc); } else { smtID = attributeDefinedIdentifier; if (smtDefinedBody != null) { throw new ISmtDeclarable.IllegalSmtDeclarableUsageException( id + " has " + ID_SMTDEFINED + " and " + ID_BUILTIN + " attributes"); } } mBoogieFunction2SmtFunction.put(id, smtID); mSmtFunction2BoogieFunction.put(smtID, resultType, id); } /** * Returns true, if there is a NamedAttribute with the given name n and without any values. */ public static boolean checkForAttributeWithoutValue(final Map attributes, final String n) { final Expression[] values = attributes.get(n); if (values == null) { // no such name return false; } if (values.length == 0) { return true; } throw new IllegalArgumentException("Attribute has an argument: " + n); } /** * Returns the single StringLiteral value of the NamedAttribute with name n. Throws an IllegalArgumentException if * there is a NamedAttribute with name whose value is not a single StringLiteral. Returns null if there is no * NamedAttribute with name n. */ public static String checkForAttributeDefinedIdentifier(final Map attributes, final String n) { final Expression[] values = attributes.get(n); if (values == null) { // no such name return null; } if (values.length == 1 && values[0] instanceof StringLiteral) { final StringLiteral sl = (StringLiteral) values[0]; return sl.getValue(); } throw new IllegalArgumentException("Attribute has more than one argument or argument is not String: " + n); } /** * Checks if there is an annotation with the name {@link #ID_INDICES} According to our convention this attribute * defines the indices for the corresponding SMT function. Returns the array of indices if there is an attribute * with this name and null otherwise. */ public static String[] checkForIndices(final Map attributes) { final Expression[] values = attributes.get(ID_INDICES); if (values == null) { // no such name return null; } final String[] result = new String[values.length]; for (int i = 0; i < values.length; i++) { if (values[i] instanceof IntegerLiteral) { result[i] = ((IntegerLiteral) values[i]).getValue(); } else { throw new IllegalArgumentException("no single value attribute"); } } return result; } public static Map extractAttributes(final Declaration decl) { final Map result = new HashMap<>(); for (final Attribute attr : decl.getAttributes()) { if (attr instanceof NamedAttribute) { final NamedAttribute nattr = (NamedAttribute) attr; result.put(nattr.getName(), ((NamedAttribute) attr).getValues()); } } return result; } @Override public String translateToBoogieFunction(final String smtFunctionName, final IBoogieType type) { return mSmtFunction2BoogieFunction.get(smtFunctionName, type); } public Map getBoogieFunction2SmtFunction() { return Collections.unmodifiableMap(mBoogieFunction2SmtFunction); } private void declareGlobalVariables(final VariableDeclaration vardecl) { for (final VarList vl : vardecl.getVariables()) { for (final String id : vl.getIdentifiers()) { final IBoogieType type = vl.getType().getBoogieType(); final ProgramNonOldVar global = constructGlobalBoogieVar(id, type, vl); putNew(id, global, mGlobals); final ProgramOldVar oldGlobal = global.getOldVar(); putNew(id, oldGlobal, mOldGlobals); } } } @Override public Set getGlobals() { return mIcfgSymbolTable.getGlobals(); } /** * Return global variables; * * @return Map that assigns to each variable identifier the non-old global variable */ public Map getGlobalsMap() { return Collections.unmodifiableMap(mGlobals); } /** * Return old variables. */ public Map getOldVars() { return Collections.unmodifiableMap(mOldGlobals); } @Override public Set getLocals(final String proc) { return mIcfgSymbolTable.getLocals(proc); } @Override public Set getConstants() { return mIcfgSymbolTable.getConstants(); } /** * Return global constants; */ public Map getConstsMap() { return Collections.unmodifiableMap(mConstants); } private void declareSpecImpl(final Procedure spec, final Procedure impl) { final String procId = spec.getIdentifier(); assert procId.equals(impl.getIdentifier()); DeclarationInformation declInfoInParam; DeclarationInformation declInfoOutParam; if (spec == impl) { // implementation is given in procedure declaration, in this case // we consider all in/out-params as procedure variables declInfoInParam = new DeclarationInformation(StorageClass.PROC_FUNC_INPARAM, procId); declInfoOutParam = new DeclarationInformation(StorageClass.PROC_FUNC_OUTPARAM, procId); } else { assert isSpecAndImpl(spec, impl); // implementation is given in a separate declaration, in this case // we consider all in/out-params as implementation variables declInfoInParam = new DeclarationInformation(StorageClass.IMPLEMENTATION_INPARAM, procId); declInfoOutParam = new DeclarationInformation(StorageClass.IMPLEMENTATION_OUTPARAM, procId); } declareParams(procId, spec.getInParams(), impl.getInParams(), mSpecificationInParam, mImplementationInParam, declInfoInParam, mProc2InParams); declareParams(procId, spec.getOutParams(), impl.getOutParams(), mSpecificationOutParam, mImplementationOutParam, declInfoOutParam, mProc2OutParams); declareLocals(impl); } /** * Returns true if spec contains only a specification or impl contains only an implementation. */ private static boolean isSpecAndImpl(final Procedure spec, final Procedure impl) { return isSpecification(spec) && !isImplementation(spec) && isImplementation(impl) && !isSpecification(impl); } private void declareSpec(final Procedure spec) { assert isSpecification(spec) : "no specification"; assert !isImplementation(spec) : "is implementation"; final String procId = spec.getIdentifier(); declareParams(procId, spec.getInParams(), mSpecificationInParam, new DeclarationInformation(StorageClass.PROC_FUNC_INPARAM, procId), mProc2InParams); declareParams(procId, spec.getOutParams(), mSpecificationOutParam, new DeclarationInformation(StorageClass.PROC_FUNC_OUTPARAM, procId), mProc2OutParams); } private void declareParams(final String procId, final VarList[] specVl, final VarList[] implVl, final Map> specMap, final Map> implMap, final DeclarationInformation declarationInformation, final Map> proc2params) { if (specVl.length != implVl.length) { throw new IllegalArgumentException("specification and implementation have different param length"); } final List params = new ArrayList<>(); final List previous = proc2params.put(procId, Collections.unmodifiableList(params)); if (previous != null) { throw new AssertionError("params for procedure " + procId + " already added"); } for (int i = 0; i < specVl.length; i++) { final IBoogieType specType = specVl[i].getType().getBoogieType(); final IBoogieType implType = implVl[i].getType().getBoogieType(); if (!specType.equals(implType)) { throw new IllegalArgumentException("specification and implementation have different types"); } final String[] specIds = specVl[i].getIdentifiers(); final String[] implIds = implVl[i].getIdentifiers(); if (specIds.length != implIds.length) { throw new IllegalArgumentException("specification and implementation have different param length"); } for (int j = 0; j < specIds.length; j++) { final LocalProgramVar pv = constructLocalProgramVar(implIds[j], procId, implType, implVl[i], declarationInformation); putNew(procId, implIds[j], pv, implMap); putNew(procId, specIds[j], pv, specMap); params.add(pv); } } } /** * Declare in or our parameters of a specification. * * @param procId * name of procedure * @param vl * Varlist defining the parameters * @param specMap * map for the specification * @param declarationInformation * StorageClass of the constructed IProgramVar */ private void declareParams(final String procId, final VarList[] vl, final Map> specMap, final DeclarationInformation declarationInformation, final Map> proc2params) { final ArrayList params = new ArrayList<>(); final List previous = proc2params.put(procId, Collections.unmodifiableList(params)); if (previous != null) { throw new AssertionError("params for procedure " + procId + " already added"); } for (int i = 0; i < vl.length; i++) { final IBoogieType type = vl[i].getType().getBoogieType(); final String[] ids = vl[i].getIdentifiers(); for (int j = 0; j < ids.length; j++) { final LocalProgramVar pv = constructLocalProgramVar(ids[j], procId, type, vl[i], declarationInformation); putNew(procId, ids[j], pv, specMap); params.add(pv); } } } public void declareLocals(final Procedure proc) { if (proc.getBody() != null) { final DeclarationInformation declarationInformation = new DeclarationInformation(StorageClass.LOCAL, proc.getIdentifier()); for (final VariableDeclaration vdecl : proc.getBody().getLocalVars()) { for (final VarList vl : vdecl.getVariables()) { for (final String id : vl.getIdentifiers()) { final IBoogieType type = vl.getType().getBoogieType(); final LocalProgramVar pv = constructLocalProgramVar(id, proc.getIdentifier(), type, vl, declarationInformation); putNew(proc.getIdentifier(), id, pv, mImplementationLocals); } } } } } /** * Construct IProgramVar and store it. Expects that no IProgramVar with the same identifier has already been * constructed. * * @param identifier * @param procedure * @param iType * @param isOldvar * @param boogieASTNode * BoogieASTNode for which errors (e.g., unsupported syntax) are reported * @param declarationInformation */ public LocalProgramVar constructLocalProgramVar(final String identifier, final String procedure, final IBoogieType iType, final VarList varList, final DeclarationInformation declarationInformation) { final Sort sort = mTypeSortTranslator.getSort(iType, varList); final String name = ProgramVarUtils.buildBoogieVarName(identifier, procedure, false, false); final TermVariable termVariable = mScript.variable(name, sort); final ApplicationTerm defaultConstant = ProgramVarUtils.constructDefaultConstant(mScript, this, sort, name); final ApplicationTerm primedConstant = ProgramVarUtils.constructPrimedConstant(mScript, this, sort, name); final LocalProgramVar pv = new LocalProgramVar(identifier, procedure, termVariable, defaultConstant, primedConstant); mSmtVar2ProgramVar.put(termVariable, pv); mProgramVar2DeclarationInformation.put(pv, declarationInformation); mProgramVar2AstNode.put(pv, varList); mIcfgSymbolTable.add(pv); return pv; } /** * Construct global IProgramVar and the corresponding oldVar and store both. Expects that no local BoogieVarwith the * same identifier has already been constructed. * * @param boogieASTNode * BoogieASTNode for which errors (e.g., unsupported syntax) are reported */ private ProgramNonOldVar constructGlobalBoogieVar(final String identifier, final IBoogieType iType, final VarList varlist) { final Sort sort = mTypeSortTranslator.getSort(iType, varlist); final DeclarationInformation declarationInformation = new DeclarationInformation(StorageClass.GLOBAL, null); final ProgramNonOldVar nonOldVar = ProgramVarUtils.constructGlobalProgramVarPair(identifier, sort, mScript, this); mSmtVar2ProgramVar.put(nonOldVar.getTermVariable(), nonOldVar); mProgramVar2DeclarationInformation.put(nonOldVar, declarationInformation); mProgramVar2AstNode.put(nonOldVar, varlist); final ProgramOldVar oldVar = nonOldVar.getOldVar(); mSmtVar2ProgramVar.put(oldVar.getTermVariable(), oldVar); mProgramVar2DeclarationInformation.put(oldVar, declarationInformation); mProgramVar2AstNode.put(oldVar, varlist); mIcfgSymbolTable.add(nonOldVar); return nonOldVar; } public HashRelation constructProc2ModifiableGlobalsMapping() { final HashRelation result = new HashRelation<>(); for (final Entry> proc2vars : mBoogieDeclarations.getModifiedVars().entrySet()) { for (final String var : proc2vars.getValue()) { final IProgramNonOldVar pv = getGlobalsMap().get(var); result.addPair(proc2vars.getKey(), pv); } } // assume that add auxVar are modifiable by all procedures final Set procedures = new HashSet<>(); for (final String procId : mSpecificationInParam.keySet()) { procedures.add(procId); } for (final String procId : mImplementationInParam.keySet()) { procedures.add(procId); } return result; } @Override public ILocation getLocation(final IProgramVar pv) { final BoogieASTNode astNode = getAstNode(pv); assert astNode != null : "There is no AstNode for the IProgramVar " + pv; final ILocation loc = astNode.getLocation(); return loc; } public Map> getProc2InParams() { return Collections.unmodifiableMap(mProc2InParams); } public Map> getProc2OutParams() { return Collections.unmodifiableMap(mProc2OutParams); } @Override public Set computeAllDefaultConstants() { final Set rtr = new LinkedHashSet<>(); final Function fun = IProgramVar::getDefaultConstant; getAll(mSpecificationInParam, fun).forEachOrdered(rtr::add); getAll(mSpecificationOutParam, fun).forEachOrdered(rtr::add); getAll(mImplementationInParam, fun).forEachOrdered(rtr::add); getAll(mImplementationOutParam, fun).forEachOrdered(rtr::add); mImplementationLocals.entrySet().stream().flatMap(a -> a.getValue().entrySet().stream()) .map(a -> fun.apply(a.getValue())).forEachOrdered(rtr::add); mProc2InParams.entrySet().stream().flatMap(a -> a.getValue().stream()).map(fun::apply).forEachOrdered(rtr::add); mProc2OutParams.entrySet().stream().flatMap(a -> a.getValue().stream()).map(fun::apply) .forEachOrdered(rtr::add); mGlobals.entrySet().stream().map(a -> fun.apply(a.getValue())).forEachOrdered(rtr::add); mOldGlobals.entrySet().stream().map(a -> fun.apply(a.getValue())).forEachOrdered(rtr::add); return rtr; } private static Stream getAll(final Map> map, final Function fun) { return map.entrySet().stream().flatMap(a -> a.getValue().entrySet().stream()).map(a -> fun.apply(a.getValue())); } }