Skip to content

Commit d9c0b9a

Browse files
committed
Modified CLI
Added picocli to extend flag usage, with the implementation of --debug to presentraw expressions, counterexamples and all expressions sent to the SMT solver. Logging should be improved as it's not incredibly readable.
1 parent f8d3f3e commit d9c0b9a

5 files changed

Lines changed: 72 additions & 17 deletions

File tree

liquidjava-verifier/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,11 @@
316316
<version>2.10.1</version>
317317
</dependency>
318318

319+
<dependency>
320+
<groupId>info.picocli</groupId>
321+
<artifactId>picocli</artifactId>
322+
<version>4.7.7</version>
323+
</dependency>
319324
</dependencies>
320325
<dependencyManagement>
321326
<dependencies>

liquidjava-verifier/src/main/java/liquidjava/api/CommandLineLauncher.java

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@
33
import java.io.File;
44
import java.util.Arrays;
55
import java.util.List;
6+
import java.util.concurrent.Callable;
67

78
import liquidjava.diagnostics.Diagnostics;
89
import liquidjava.diagnostics.errors.CustomError;
910
import liquidjava.diagnostics.warnings.CustomWarning;
1011
import liquidjava.processor.RefinementProcessor;
1112
import liquidjava.processor.context.ContextHistory;
13+
import picocli.CommandLine;
14+
import picocli.CommandLine.Command;
15+
import picocli.CommandLine.Option;
16+
import picocli.CommandLine.Parameters;
1217
import spoon.Launcher;
1318
import spoon.compiler.Environment;
1419
import spoon.processing.ProcessingManager;
@@ -22,25 +27,43 @@ public class CommandLineLauncher {
2227
private static final ContextHistory contextHistory = ContextHistory.getInstance();
2328

2429
public static void main(String[] args) {
25-
if (args.length == 0) {
26-
System.out.println("No input paths provided");
27-
System.out.println("\nUsage: ./liquidjava <...paths>");
28-
System.out.println(" <...paths>: Paths to be verified by LiquidJava");
29-
System.out.println(
30-
"\nExample: ./liquidjava liquidjava-example/src/main/java/test liquidjava-example/src/main/java/testingInProgress/Account.java");
31-
return;
30+
CommandLine commandLine = new CommandLine(new CliArguments());
31+
int exitCode = commandLine.execute(args);
32+
if (exitCode != 0) {
33+
System.exit(exitCode);
3234
}
33-
List<String> paths = Arrays.asList(args);
34-
launch(paths.toArray(new String[0]));
35+
}
36+
37+
@Command(name = "liquidjava", mixinStandardHelpOptions = true, customSynopsis = "./liquidjava <...paths> <options>")
38+
private static class CliArguments implements Callable<Integer> {
39+
40+
@Option(names = { "-d", "--debug" }, description = "Enable debug mode for more detailed output")
41+
private boolean debugMode;
42+
43+
@Parameters(arity = "1..*", paramLabel = "<...paths>", description = "Paths to be verified by LiquidJava")
44+
private List<String> paths;
45+
46+
@Override
47+
public Integer call() {
48+
if (debugMode) {
49+
System.out.println("Debug mode enabled");
50+
System.out.println("Input paths: " + paths);
51+
diagnostics.setDebugMode();
52+
}
53+
54+
launch(paths.stream().toArray(String[]::new));
55+
56+
// print diagnostics
57+
if (diagnostics.foundWarning()) {
58+
System.out.println(diagnostics.getWarningOutput());
59+
}
60+
if (diagnostics.foundError()) {
61+
System.out.println(diagnostics.getErrorOutput());
62+
return 1;
63+
}
3564

36-
// print diagnostics
37-
if (diagnostics.foundWarning()) {
38-
System.out.println(diagnostics.getWarningOutput());
39-
}
40-
if (diagnostics.foundError()) {
41-
System.out.println(diagnostics.getErrorOutput());
42-
} else {
4365
System.out.println("Correct! Passed Verification.");
66+
return 0;
4467
}
4568
}
4669

liquidjava-verifier/src/main/java/liquidjava/diagnostics/Diagnostics.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ public class Diagnostics {
1515

1616
private final LinkedHashSet<LJError> errors;
1717
private final LinkedHashSet<LJWarning> warnings;
18+
private boolean debugMode;
1819

1920
private Diagnostics() {
2021
this.errors = new LinkedHashSet<>();
2122
this.warnings = new LinkedHashSet<>();
23+
this.debugMode = false;
2224
}
2325

2426
public static Diagnostics getInstance() {
@@ -33,6 +35,14 @@ public void add(LJWarning warning) {
3335
this.warnings.add(warning);
3436
}
3537

38+
public boolean isDebugMode() {
39+
return this.debugMode;
40+
}
41+
42+
public void setDebugMode() {
43+
this.debugMode = true;
44+
}
45+
3646
public boolean foundError() {
3747
return !this.errors.isEmpty();
3848
}

liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ExpressionSimplifier.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package liquidjava.rj_language.opt;
22

3+
import liquidjava.diagnostics.Diagnostics;
34
import liquidjava.rj_language.ast.BinaryExpression;
45
import liquidjava.rj_language.ast.Expression;
56
import liquidjava.rj_language.ast.LiteralBoolean;
@@ -9,13 +10,19 @@
910

1011
public class ExpressionSimplifier {
1112

13+
private static final Diagnostics diagnostics = Diagnostics.getInstance();
14+
1215
/**
1316
* Simplifies an expression by applying constant propagation, constant folding and removing redundant conjuncts
1417
* Returns a derivation node representing the tree of simplifications applied
1518
*/
1619
public static ValDerivationNode simplify(Expression exp) {
1720
ValDerivationNode fixedPoint = simplifyToFixedPoint(null, exp);
18-
return simplifyValDerivationNode(fixedPoint);
21+
ValDerivationNode simplified = simplifyValDerivationNode(fixedPoint);
22+
if (diagnostics.isDebugMode()) {
23+
System.out.println("Simplified expression: original: " + exp + " | simplified: " + simplified.getValue());
24+
}
25+
return simplified;
1926
}
2027

2128
/**

liquidjava-verifier/src/main/java/liquidjava/smt/SMTEvaluator.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99
import com.microsoft.z3.Status;
1010
import com.microsoft.z3.Z3Exception;
1111

12+
import liquidjava.diagnostics.Diagnostics;
1213
import liquidjava.processor.context.Context;
1314
import liquidjava.rj_language.Predicate;
1415
import liquidjava.rj_language.ast.Expression;
1516

1617
public class SMTEvaluator {
1718

19+
private static final Diagnostics diagnostics = Diagnostics.getInstance();
20+
1821
/**
1922
* Verifies that subRef is a subtype of supRef by checking the satisfiability of subRef && !supRef. Creates a parser
2023
* for our SMT-ready refinement language and discharges the verification to Z3
@@ -27,6 +30,9 @@ public class SMTEvaluator {
2730
*/
2831
public SMTResult verifySubtype(Predicate subRef, Predicate supRef, Context context) throws Exception {
2932
Predicate toVerify = Predicate.createConjunction(subRef, supRef.negate());
33+
if (diagnostics.isDebugMode()) {
34+
System.out.println("Verifying: " + toVerify);
35+
}
3036
try {
3137
Expression exp = toVerify.getExpression();
3238
try (TranslatorToZ3 tz3 = new TranslatorToZ3(context)) {
@@ -39,6 +45,10 @@ public SMTResult verifySubtype(Predicate subRef, Predicate supRef, Context conte
3945
if (result.equals(Status.SATISFIABLE)) {
4046
Model model = solver.getModel();
4147
Counterexample counterexample = tz3.getCounterexample(model);
48+
if (diagnostics.isDebugMode()) {
49+
System.out.println("Verification failed. Counterexample:");
50+
System.out.println(counterexample);
51+
}
4252
return SMTResult.error(counterexample);
4353
}
4454
}

0 commit comments

Comments
 (0)