/*
* Copyright (C) 2022 Dominik Klumpp (klumpp@informatik.uni-freiburg.de)
* Copyright (C) 2022 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.smt;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IIcfgSymbolTable;
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.smtlibutils.CommuhashNormalForm;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.IteRemover;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils;
import de.uni_freiburg.informatik.ultimate.logic.FormulaUnLet;
import de.uni_freiburg.informatik.ultimate.logic.QuantifiedFormula;
import de.uni_freiburg.informatik.ultimate.logic.Term;
import de.uni_freiburg.informatik.ultimate.logic.TermVariable;
import de.uni_freiburg.informatik.ultimate.smtsolver.external.TermParseUtils;
/**
* A helper class to parse strings into {@link Term}s.
*
* Specifically, the class helps with parsing into terms that contain {@code TermVariable}s rather than constant
* symbols. This is helpful when creating {@code UnmodifiableTransFormula}s or {@code IPredicate}s.
*
* The returned terms are in Ultimate normal form, and should be usable directly to create Ultimate date structures.
*
* This class can be helpful for instance (but not exclusively) to create test suites.
*
* @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de)
*/
public final class SmtParserUtils {
private SmtParserUtils() {
// no instances for static class
}
/**
* Parse a term using the script and symbol table of the given {@link CfgSmtToolkit}.
*
* @param syntax
* A string denoting an SMT-LIB term
* @param services
* Used to transform the result into Ultimate normal form
* @param csToolkit
* A toolkit containing a script and a symbol table. The syntax may refer to variables for any global
* variable in this symbol table.
* @return the parsed term
*/
public static Term parseWithVariables(final String syntax, final IUltimateServiceProvider services,
final CfgSmtToolkit csToolkit) {
return parseWithVariables(syntax, services, csToolkit.getManagedScript(), csToolkit.getSymbolTable());
}
/**
* Parse a term using a given script and symbol table.
*
* @param syntax
* A string denoting an SMT-LIB term
* @param services
* Used to transform the result into Ultimate normal form
* @param mgdScript
* A script used for parsing
* @param symbolTable
* The syntax may refer to variables for any global variable in this symbol table.
* @return the parsed term
*/
public static Term parseWithVariables(final String syntax, final IUltimateServiceProvider services,
final ManagedScript mgdScript, final IIcfgSymbolTable symbolTable) {
final var termVars = Stream
.concat(symbolTable.getGlobals().stream(),
symbolTable.getGlobals().stream().map(IProgramNonOldVar::getOldVar))
.map(IProgramVar::getTermVariable).collect(Collectors.toSet());
return parseWithVariables(syntax, services, mgdScript, termVars);
}
/**
* Parse a term using a given script and given variables.
*
* @param syntax
* A string denoting an SMT-LIB term
* @param services
* Used to transform the result into Ultimate normal form
* @param mgdScript
* A script used for parsing
* @param variables
* A set of variables to which the syntax may refer
* @return the parsed term
*/
public static Term parseWithVariables(final String syntax, final IUltimateServiceProvider services,
final ManagedScript mgdScript, final Set variables) {
if (variables.isEmpty()) {
return parse(syntax, services, mgdScript);
}
final String template = "(|%1$s| %2$s)";
final String declarations = variables.stream().map(tv -> String.format(template, tv.getName(), tv.getSort()))
.collect(Collectors.joining(" "));
final String fullSyntax = "(forall (" + declarations + ") " + syntax + ")";
final QuantifiedFormula quant = (QuantifiedFormula) TermParseUtils.parseTerm(mgdScript.getScript(), fullSyntax);
return normalize(quant.getSubformula(), services, mgdScript);
}
/**
* Parse a term (without any variables)
*
* @param syntax
* A string denoting an SMT-LIB term
* @param services
* Used to transform the result into Ultimate normal form
* @param mgdScript
* A script used for parsing
* @return the parsed term
*/
public static Term parse(final String syntax, final IUltimateServiceProvider services,
final ManagedScript mgdScript) {
final Term parsed = TermParseUtils.parseTerm(mgdScript.getScript(), syntax);
return normalize(parsed, services, mgdScript);
}
private static Term normalize(final Term term, final IUltimateServiceProvider services,
final ManagedScript mgdScript) {
final Term noLet = new FormulaUnLet().transform(term);
final Term noIte;
if (SmtSortUtils.isBoolSort(noLet.getSort())) {
noIte = new IteRemover(mgdScript).transform(noLet);
} else {
noIte = noLet;
}
return new CommuhashNormalForm(services, mgdScript.getScript()).transform(noIte);
}
}