/*
* Copyright (C) 2018 Alexander Nutz (nutz@informatik.uni-freiburg.de)
* Copyright (C) 2018 University of Freiburg
*
* This file is part of the ULTIMATE ChcSmtPrinter plug-in.
*
* The ULTIMATE ChcSmtPrinter plug-in 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 ChcSmtPrinter plug-in 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 ChcSmtPrinter plug-in. If not, see .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify the ULTIMATE ChcSmtPrinter plug-in, 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 ChcSmtPrinter plug-in grant you additional permission
* to convey the resulting work.
*/
package de.uni_freiburg.informatik.ultimate.chcprinter;
import java.io.File;
import java.io.IOException;
import java.util.List;
import de.uni_freiburg.informatik.ultimate.chcprinter.preferences.ChcSmtPrinterPreferenceInitializer;
import de.uni_freiburg.informatik.ultimate.core.lib.observers.BaseObserver;
import de.uni_freiburg.informatik.ultimate.core.model.models.IElement;
import de.uni_freiburg.informatik.ultimate.core.model.models.ILocation;
import de.uni_freiburg.informatik.ultimate.core.model.services.ILogger;
import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider;
import de.uni_freiburg.informatik.ultimate.lib.chc.ChcAsserter;
import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable;
import de.uni_freiburg.informatik.ultimate.lib.chc.HornAnnot;
import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause;
import de.uni_freiburg.informatik.ultimate.lib.chc.HornClauseAST;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript;
import de.uni_freiburg.informatik.ultimate.logic.LoggingScript;
import de.uni_freiburg.informatik.ultimate.logic.Logics;
import de.uni_freiburg.informatik.ultimate.logic.NoopScript;
import de.uni_freiburg.informatik.ultimate.logic.QuotedObject;
import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants;
/**
* @author Alexander Nutz (nutz@informatik.uni-freiburg.de)
*/
public class ChcSmtPrinterObserver extends BaseObserver {
// TODO: make settings
/**
* Add a (get-unsat-core) command after the (check-sat) command. In order to make this command work, also set the
* :produce-unsat-cores option and give a name to each term.
*/
private static final boolean PRODUCE_UNSAT_CORES = false;
/**
* {@ HornClause}s can have comments attached to them. They might help understanding the meaning of each clause.
* This flag decides if they are printed as comments inside the smt2 file.
*/
private static final boolean ADD_COMMENTS = false;
private static final boolean USE_CSE = true;
private final ILogger mLogger;
private final IUltimateServiceProvider mServices;
public ChcSmtPrinterObserver(final IUltimateServiceProvider services) {
mServices = services;
mLogger = services.getLoggingService().getLogger(Activator.PLUGIN_ID);
}
@Override
public boolean process(final IElement root) throws IOException {
if (!(root instanceof HornClauseAST)) {
return true;
}
final HornAnnot annot = HornAnnot.getAnnotation(root);
if (mLogger.isDebugEnabled()) {
mLogger.debug("Printing the following HornClause set:");
mLogger.debug(annot);
}
final List hornClauses = annot.getHornClauses();
final HcSymbolTable symbolTable = annot.getSymbolTable();
final ManagedScript mgdScript = annot.getScript();
final File file = openTempFile(root);
final LoggingScript loggingScript = new LoggingScript(new NoopScript(), file.getAbsolutePath(), true, USE_CSE);
/*
* Write file using loggingScript
*/
// set logic
loggingScript.setLogic(Logics.HORN);
// add info
{
loggingScript.setInfo(":source",
new QuotedObject("CHC Constraint Logic: " + annot.getChcCategoryInfo().getConstraintLogic() + "\n"
+ " " + "Contains non-linear Horn clauses: "
+ annot.getChcCategoryInfo().containsNonLinearHornClauses()));
}
if (PRODUCE_UNSAT_CORES) {
loggingScript.setOption(SMTLIBConstants.PRODUCE_UNSAT_CORES, "true");
}
// declare functions and assert clauses
new ChcAsserter(mgdScript, loggingScript, PRODUCE_UNSAT_CORES, ADD_COMMENTS, true).assertClauses(symbolTable,
hornClauses);
// check-sat
loggingScript.checkSat();
if (PRODUCE_UNSAT_CORES) {
try {
loggingScript.getUnsatCore();
} catch (final UnsupportedOperationException e) {
// do nothing
}
}
return true;
}
/**
* modified from BoogiePrinter
*
* @param root
* @return
*/
private File openTempFile(final IElement root) {
String path;
String filename;
File file;
if (mServices.getPreferenceProvider(Activator.PLUGIN_ID)
.getBoolean(ChcSmtPrinterPreferenceInitializer.SAVE_IN_SOURCE_DIRECTORY_LABEL)) {
final ILocation loc = ILocation.getAnnotation(root);
final File inputFile = new File(loc.getFileName());
if (inputFile.isDirectory()) {
path = inputFile.getPath();
} else {
path = inputFile.getParent();
}
if (path == null) {
mLogger.warn("Model does not provide a valid source location, falling back to default dump path...");
path = mServices.getPreferenceProvider(Activator.PLUGIN_ID)
.getString(ChcSmtPrinterPreferenceInitializer.DUMP_PATH_LABEL);
}
} else {
path = mServices.getPreferenceProvider(Activator.PLUGIN_ID)
.getString(ChcSmtPrinterPreferenceInitializer.DUMP_PATH_LABEL);
}
try {
if (mServices.getPreferenceProvider(Activator.PLUGIN_ID)
.getBoolean(ChcSmtPrinterPreferenceInitializer.UNIQUE_NAME_LABEL)) {
file = File.createTempFile(
"ChcSmtPrinter_" + new File(ILocation.getAnnotation(root).getFileName()).getName() + "_UID",
".smt2", new File(path));
} else {
filename = mServices.getPreferenceProvider(Activator.PLUGIN_ID)
.getString(ChcSmtPrinterPreferenceInitializer.FILE_NAME_LABEL);
file = new File(path + File.separatorChar + filename);
if ((!file.isFile() || !file.canWrite()) && file.exists()) {
mLogger.warn("Cannot write to: " + file.getAbsolutePath());
return null;
}
if (file.exists()) {
mLogger.info("File already exists and will be overwritten: " + file.getAbsolutePath());
}
file.createNewFile();
}
mLogger.info("Writing to file " + file.getAbsolutePath());
return file;
} catch (final IOException e) {
mLogger.fatal("Cannot open file", e);
return null;
}
}
}