diff --git a/liquidjava-verifier/pom.xml b/liquidjava-verifier/pom.xml index 43aa8422..f77a5e11 100644 --- a/liquidjava-verifier/pom.xml +++ b/liquidjava-verifier/pom.xml @@ -319,6 +319,11 @@ 2.10.1 + + info.picocli + picocli + 4.7.7 + diff --git a/liquidjava-verifier/src/main/java/liquidjava/api/CommandLineArgs.java b/liquidjava-verifier/src/main/java/liquidjava/api/CommandLineArgs.java new file mode 100644 index 00000000..6927f4ba --- /dev/null +++ b/liquidjava-verifier/src/main/java/liquidjava/api/CommandLineArgs.java @@ -0,0 +1,37 @@ +package liquidjava.api; + +import java.io.FileReader; +import java.nio.file.Path; +import java.util.List; + +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; + +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; +import picocli.CommandLine.Parameters; + +@Command(name = "liquidjava", mixinStandardHelpOptions = false, customSynopsis = "./liquidjava <...paths> ") +public class CommandLineArgs { + @Option(names = {"-h", "--help"}, usageHelp = true, description = "Display this help message") + public boolean help; + + @Option(names = { "-v", "--version" }, versionHelp = true, description = "Display the version of LiquidJava") + public boolean version; + + @Option(names = { "-d", "--debug" }, description = "Enable debug mode for more detailed output") + public boolean debugMode; + + @Parameters(arity = "1..*", paramLabel = "<...paths>", description = "Paths to be verified by LiquidJava") + public List paths; + + public String getVersionString() { + Path pomPath = Path.of("liquidjava-verifier", "pom.xml"); + try (FileReader fileReader = new FileReader(pomPath.toFile())) { + Model model = new MavenXpp3Reader().read(fileReader); + return model.getVersion(); + } catch (Exception ignored) { + return "unknown"; + } + } +} diff --git a/liquidjava-verifier/src/main/java/liquidjava/api/CommandLineLauncher.java b/liquidjava-verifier/src/main/java/liquidjava/api/CommandLineLauncher.java index e473562c..38fe5d0c 100644 --- a/liquidjava-verifier/src/main/java/liquidjava/api/CommandLineLauncher.java +++ b/liquidjava-verifier/src/main/java/liquidjava/api/CommandLineLauncher.java @@ -2,13 +2,13 @@ import java.io.File; import java.util.Arrays; -import java.util.List; import liquidjava.diagnostics.Diagnostics; import liquidjava.diagnostics.errors.CustomError; import liquidjava.diagnostics.warnings.CustomWarning; import liquidjava.processor.RefinementProcessor; import liquidjava.processor.context.ContextHistory; +import picocli.CommandLine; import spoon.Launcher; import spoon.compiler.Environment; import spoon.processing.ProcessingManager; @@ -20,18 +20,23 @@ public class CommandLineLauncher { private static final Diagnostics diagnostics = Diagnostics.getInstance(); private static final ContextHistory contextHistory = ContextHistory.getInstance(); + public static final CommandLineArgs cmdArgs = new CommandLineArgs(); public static void main(String[] args) { - if (args.length == 0) { - System.out.println("No input paths provided"); - System.out.println("\nUsage: ./liquidjava <...paths>"); - System.out.println(" <...paths>: Paths to be verified by LiquidJava"); - System.out.println( - "\nExample: ./liquidjava liquidjava-example/src/main/java/test liquidjava-example/src/main/java/testingInProgress/Account.java"); + CommandLine cmd = new CommandLine(cmdArgs); + cmd.parseArgs(args); + + if (cmd.isUsageHelpRequested()) { + cmd.usage(System.out); + return; + } + + if (cmd.isVersionHelpRequested()) { + System.out.println("liquidjava " + cmdArgs.getVersionString()); return; } - List paths = Arrays.asList(args); - launch(paths.toArray(new String[0])); + + launch(cmdArgs.paths.stream().toArray(String[]::new)); // print diagnostics if (diagnostics.foundWarning()) { @@ -39,9 +44,10 @@ public static void main(String[] args) { } if (diagnostics.foundError()) { System.out.println(diagnostics.getErrorOutput()); - } else { - System.out.println("Correct! Passed Verification."); + return; } + + System.out.println("Correct! Passed Verification."); } public static void launch(String... paths) { diff --git a/liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/RefinementError.java b/liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/RefinementError.java index 39a81d92..a1ba3c3c 100644 --- a/liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/RefinementError.java +++ b/liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/RefinementError.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.stream.Collectors; +import liquidjava.api.CommandLineLauncher; import liquidjava.diagnostics.TranslationTable; import liquidjava.rj_language.opt.derivation_node.ValDerivationNode; import liquidjava.smt.Counterexample; @@ -48,7 +49,7 @@ public String getCounterExampleString() { found.getValue().getVariableNames(foundVarNames); String counterexampleString = counterexample.assignments().stream() // only include variables that appear in the found value - .filter(a -> foundVarNames.contains(a.first())) + .filter(a -> CommandLineLauncher.cmdArgs.debugMode || foundVarNames.contains(a.first())) // format as "var == value" .map(a -> VariableFormatter.formatVariable(a.first()) + " == " + a.second()) // join with "&&" diff --git a/liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java b/liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java index d757f2a7..80014606 100644 --- a/liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java +++ b/liquidjava-verifier/src/main/java/liquidjava/processor/refinement_checker/VCChecker.java @@ -10,6 +10,7 @@ import java.util.stream.Collectors; import liquidjava.diagnostics.errors.*; +import liquidjava.api.CommandLineLauncher; import liquidjava.diagnostics.TranslationTable; import liquidjava.processor.VCImplication; import liquidjava.processor.context.*; @@ -22,6 +23,7 @@ import liquidjava.smt.SMTResult; import liquidjava.utils.Utils; import liquidjava.utils.constants.Keys; +import liquidjava.utils.Utils; import spoon.reflect.cu.SourcePosition; import spoon.reflect.declaration.CtElement; import spoon.reflect.factory.Factory; @@ -102,6 +104,12 @@ public void processSubtyping(Predicate type, Predicate expectedType, List