/*
* Copyright (C) 2014-2015 Daniel Dietsch (dietsch@informatik.uni-freiburg.de)
* Copyright (C) 2015 University of Freiburg
* Copyright (C) 2015 Vincent Langenfeld (langenfv@informatik.uni-freiburg.de)
*
* This file is part of the ULTIMATE LTL2Aut plug-in.
*
* The ULTIMATE LTL2Aut 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 LTL2Aut 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 LTL2Aut plug-in. If not, see .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify the ULTIMATE LTL2Aut 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 LTL2Aut plug-in grant you additional permission
* to convey the resulting work.
*/
package de.uni_freiburg.informatik.ultimate.ltl2aut;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import de.uni_freiburg.informatik.ultimate.core.lib.util.MonitoredProcess;
import de.uni_freiburg.informatik.ultimate.core.lib.util.MonitoredProcess.MonitoredProcessState;
import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider;
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.ltl2aut.ast.AstNode;
import de.uni_freiburg.informatik.ultimate.ltl2aut.preferences.PreferenceInitializer;
import de.uni_freiburg.informatik.ultimate.util.CoreUtil;
/**
* This class handles the communication of with the external tool for translating an LTL formula into a Promela never
* claim and can parse that claim into an AST.
*
* @author Langenfeld
*/
public class LTLXBAExecutor {
private final ILogger mLogger;
private final IUltimateServiceProvider mServices;
public LTLXBAExecutor(final IUltimateServiceProvider services) {
mServices = services;
mLogger = mServices.getLoggingService().getLogger(Activator.PLUGIN_ID);
}
/**
* Returns the AST of the Promela never claim description of the Büchi automaton returned by the ltl2büchi tool.
*
* @param ltlFormula
* LTL formula in the format accepted by the tool
* @return AST of Büchi automaton description
* @throws Exception
*/
public AstNode ltl2Ast(final String ltlFormula) throws Exception {
final String toolOutput = execLTLXBA(ltlFormula.trim());
mLogger.debug(String.format("LTLXBA said: %s", toolOutput));
final InputStreamReader isReader = new InputStreamReader(IOUtils.toInputStream(toolOutput));
try {
return (AstNode) new Parser(new Lexer(isReader)).parse().value;
} catch (final Exception ex) {
mLogger.fatal("Exception during parsing of LTLXBA output for formula " + ltlFormula, ex);
mLogger.fatal("Parser input was:");
mLogger.fatal(toolOutput);
throw ex;
}
}
/**
* Returns a Büchi automaton for the ltl formula as a promela never claim.
*
* @param ltlFormula
* ltl formula in the form accepted by the called tool
* @throws IOException
* @throws InterruptedException
* @return whole return string of the called tool
*/
private String execLTLXBA(final String ltlFormula) throws IOException, InterruptedException {
final String[] command = getCommand(ltlFormula);
final MonitoredProcess process = MonitoredProcess.exec(command, null, null, mServices);
final MonitoredProcessState state = process.waitfor();
final String in = convertStreamToString(process.getInputStream());
final String err = convertStreamToString(process.getErrorStream());
if (in == null || in.isEmpty()) {
final String cmd = CoreUtil.join(command, " ");
mLogger.fatal(cmd + " did not produce any output on stdout");
mLogger.fatal("stderr output:");
mLogger.fatal(err);
mLogger.fatal("Returncode: " + state.getReturnCode());
throw new IllegalArgumentException(cmd + " did not produce any output on stdout");
}
return in;
}
private static String convertStreamToString(final InputStream is) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(is));
final StringBuilder out = new StringBuilder();
String line;
try {
while ((line = reader.readLine()) != null) {
out.append(line).append(CoreUtil.getPlatformLineSeparator());
}
reader.close();
} catch (final IOException e) {
throw new RuntimeException(e);
}
return out.toString();
}
private String[] getCommand(String ltlFormula) {
final IPreferenceProvider prefs = mServices.getPreferenceProvider(Activator.PLUGIN_ID);
ltlFormula = prefs.getString(PreferenceInitializer.LABEL_TOOLARGUMENT).replace("$1", ltlFormula);
ltlFormula = ltlFormula.replaceAll("\\(", " ( ");
ltlFormula = ltlFormula.replaceAll("\\)", " ) ");
ltlFormula = ltlFormula.replaceAll("\\s+", " ");
final List rtr = new ArrayList<>();
rtr.add(prefs.getString(PreferenceInitializer.LABEL_TOOLLOCATION));
rtr.add("-f");
rtr.add(ltlFormula);
return rtr.toArray(new String[rtr.size()]);
}
}