package jayhorn.hornify;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import jayhorn.Log;
import jayhorn.hornify.encoder.MethodEncoder;
import jayhorn.solver.Prover;
import jayhorn.solver.ProverFactory;
import jayhorn.solver.ProverFun;
import jayhorn.solver.ProverHornClause;
import soottocfg.cfg.Program;
import soottocfg.cfg.method.Method;
/**
* Class to hornify Java program
*
* @author teme
*
*/
public class Hornify {
private final ProverFactory factory;
private Prover prover;
public final List<ProverHornClause> clauses = new LinkedList<ProverHornClause>();
public Hornify(ProverFactory fac) {
this.factory = fac;
}
/**
* Main method to encode into Horn
* @param program
*/
public HornEncoderContext toHorn(Program program){
prover = factory.spawn();
prover.setHornLogic(true);
HornEncoderContext hornContext = new HornEncoderContext(prover, program);
Log.info("Transform Program Methods into Horn Clauses ... ");
for (Method method : program.getMethods()) {
final MethodEncoder encoder = new MethodEncoder(prover, method, hornContext);
clauses.addAll(encoder.encode());
}
return hornContext;
}
/**
* Return the current prover object
* @return prover
*/
public Prover getProver() {
return prover;
}
/**
* Write clauses
* @return
*/
public String writeHorn() {
StringBuilder st = new StringBuilder();
for (ProverHornClause clause : clauses)
st.append("\t\t" + clause + "\n");
st.append("\t\t-------------\n");
return st.toString();
}
/**
* Write Horn clauses to file
*/
public static void hornToFile(List<ProverHornClause> clauses,
int num) {
// write Horn clauses to file
String out = jayhorn.Options.v().getOutDir();
if (out != null) {
String basename = jayhorn.Options.v().getOutBasename();
Path file = Paths.get(out + basename + "_" + num + ".horn");
LinkedList<String> it = new LinkedList<String>();
for (ProverHornClause clause : clauses)
it.add("\t\t" + clause);
writeToFile(file, it);
}
}
/**
* Write Horn clauses to an SMT-LIB file
*/
public static void hornToSMTLIBFile(List<ProverHornClause> clauses,
int num,
Prover prover) {
String out = jayhorn.Options.v().getOutDir();
if (out != null) {
String basename = jayhorn.Options.v().getOutBasename();
Path file = Paths.get(out + basename + "_" + num + ".smt2");
Log.info("Writing Horn clauses to " + file);
LinkedList<String> it = new LinkedList<String>();
it.add("(set-info :origin \"Horn clauses generated by JayHorn\")");
it.add("(set-logic HORN)");
it.add("");
Set<ProverFun> predicates = new LinkedHashSet<ProverFun>();
for (ProverHornClause clause : clauses) {
// null indicates that the head of the clause is "false"
if (clause.getHeadFun() != null)
predicates.add(clause.getHeadFun());
for (int i = 0; i < clause.getArity(); ++i)
predicates.add(clause.getBodyFun(i));
}
for (ProverFun fun : predicates)
it.add(prover.toSMTLIBDeclaration(fun));
it.add("");
for (ProverHornClause clause : clauses)
it.add("(assert " + prover.toSMTLIBFormula(clause) + ")");
it.add("");
it.add("(check-sat)");
writeToFile(file, it);
}
}
private static void writeToFile(Path file, List<String> it) {
try {
Path parent = file.getParent();
if (parent != null)
Files.createDirectories(parent);
Files.write(file, it, Charset.forName("UTF-8"));
} catch (Exception e) {
System.err.println("Error writing file " + file);
}
}
}