Skip to content

Commit 6668db4

Browse files
authored
Merge branch 'main' into fix-has-usage
2 parents 7177e49 + 886c172 commit 6668db4

8 files changed

Lines changed: 61 additions & 12 deletions

File tree

CONTRIBUTING.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ To verify a single file from the CLI, run:
2323
./liquidjava path/to/File.java
2424
```
2525

26+
This script recompiles `liquidjava-api` and `liquidjava-verifier` when local sources or Maven files have changed.
27+
2628
## Testing
2729

2830
To run all tests, run:

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,17 @@ mvn exec:java -pl liquidjava-verifier -Dexec.mainClass="liquidjava.api.CommandLi
8383
```
8484

8585
If you're on Linux/macOS, you can use the `liquidjava` script (from the repository root) to simplify the process.
86+
The script recompiles the verifier only when local sources or Maven files have changed.
87+
88+
The LiquidJava verifier can be run from the command line with the following options:
89+
90+
| Option | Description |
91+
| --- | --- |
92+
| `<...paths>` | Paths (files or directories) to be verified by LiquidJava |
93+
| `-h`, `--help` | Show the help message with available options |
94+
| `-v`, `--version` | Show the current version of the verifier |
95+
| `-d`, `--debug` | Enable debug logging and skip expression simplification for troubleshooting |
96+
| `-lsp`, `--language-server` | Enable language server mode for editor support |
8697

8798
**Test a correct case**:
8899
```bash

liquidjava

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
11
#!/bin/bash
2+
set -e
3+
4+
cd "$(dirname "$0")"
5+
6+
MARKER="liquidjava-verifier/target/.liquidjava-last-compile"
7+
8+
if [ ! -d liquidjava-api/target/classes ] || \
9+
[ ! -d liquidjava-verifier/target/classes ] || \
10+
[ ! -f "$MARKER" ] || \
11+
find pom.xml liquidjava-api/pom.xml liquidjava-api/src/main/java \
12+
liquidjava-verifier/pom.xml liquidjava-verifier/src/main/java liquidjava-verifier/src/main/antlr4 \
13+
-newer "$MARKER" -print -quit | grep -q .; then
14+
mvn compile -pl liquidjava-verifier -am -Dmaven.compiler.useIncrementalCompilation=false
15+
touch "$MARKER"
16+
fi
17+
218
mvn exec:java -pl liquidjava-verifier \
319
-Dexec.mainClass="liquidjava.api.CommandLineLauncher" \
420
-Dexec.args="$*"

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ public class CommandLineArgs {
2222
@Option(names = { "-d", "--debug" }, description = "Enable debug mode for more detailed output")
2323
public boolean debugMode;
2424

25+
@Option(names = { "-lsp", "--language-server" }, description = "Enable language server mode for editor support")
26+
public boolean lspMode;
27+
2528
@Parameters(arity = "1..*", paramLabel = "<...paths>", description = "Paths to be verified by LiquidJava")
2629
public List<String> paths;
2730

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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import java.util.ArrayList;
44
import java.util.List;
5+
import java.util.stream.Collectors;
56

67
import liquidjava.api.CommandLineLauncher;
78
import liquidjava.processor.VCImplication;
89
import liquidjava.rj_language.Predicate;
910
import liquidjava.rj_language.ast.BinaryExpression;
1011
import liquidjava.rj_language.ast.Expression;
1112
import liquidjava.rj_language.ast.GroupExpression;
13+
import liquidjava.smt.Counterexample;
1214
import liquidjava.utils.Utils;
1315
import spoon.reflect.cu.SourcePosition;
1416
import spoon.reflect.reference.CtTypeReference;
@@ -29,6 +31,7 @@ public final class DebugLog {
2931

3032
private static final String SMT_TAG = Colors.BLUE + "[SMT]" + Colors.RESET;
3133
private static final String SMT_CHECK = Colors.SALMON + "[SMT CHECK]" + Colors.RESET;
34+
private static final String SMP_TAG = Colors.YELLOW + "[SMP]" + Colors.RESET;
3235

3336
private DebugLog() {
3437
}
@@ -123,6 +126,18 @@ public static void smtStart(VCImplication chain, Predicate extraPremise, Predica
123126
System.out.println(SMT_TAG + " " + formatConclusion(conclusion));
124127
}
125128

129+
/**
130+
* Print the simplifier input and output side by side. This keeps the raw expression visible in debug traces while
131+
* callers continue using the simplified expression for user-facing diagnostics.
132+
*/
133+
public static void simplification(Expression input, Expression output) {
134+
if (!enabled()) {
135+
return;
136+
}
137+
System.out.println(SMP_TAG + " Before simplification: " + Colors.YELLOW + input + Colors.RESET);
138+
System.out.println(SMP_TAG + " After simplification: " + Colors.BOLD_YELLOW + output + Colors.RESET);
139+
}
140+
126141
private static String plainLabel(VCImplication node) {
127142
return node.getName() + " : " + simpleType(node.getType());
128143
}
@@ -215,14 +230,14 @@ public static void smtUnsat() {
215230
if (!enabled()) {
216231
return;
217232
}
218-
System.out.println(SMT_TAG + " result: " + Colors.GREEN + "UNSAT (subtype holds)" + Colors.RESET);
233+
System.out.println(SMT_TAG + " Result: " + Colors.GREEN + "UNSAT (subtype holds)" + Colors.RESET);
219234
}
220235

221236
public static void smtSat(Object counterexample) {
222237
if (!enabled()) {
223238
return;
224239
}
225-
String header = SMT_TAG + " result: " + Colors.RED + "SAT (subtype fails)" + Colors.RESET;
240+
String header = SMT_TAG + " Result: " + Colors.RED + "SAT (subtype fails)" + Colors.RESET;
226241
String pretty = formatCounterexample(counterexample);
227242
if (pretty == null) {
228243
System.out.println(header);
@@ -266,7 +281,7 @@ public static void smtUnknown() {
266281
if (!enabled()) {
267282
return;
268283
}
269-
System.out.println(SMT_TAG + " result: " + Colors.YELLOW + "UNKNOWN (treated as OK)" + Colors.RESET);
284+
System.out.println(SMT_TAG + " Result: " + Colors.YELLOW + "UNKNOWN (treated as OK)" + Colors.RESET);
270285
}
271286

272287
/**
@@ -292,7 +307,7 @@ public static void smtError(String message) {
292307
if (!enabled()) {
293308
return;
294309
}
295-
System.out.println(SMT_TAG + " result: " + Colors.RED + "ERROR" + Colors.RESET + " — "
310+
System.out.println(SMT_TAG + " Result: " + Colors.RED + "ERROR" + Colors.RESET + " — "
296311
+ (message == null ? "(no message)" : message));
297312
}
298313
}

liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/RefinementError.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import java.util.List;
55
import java.util.stream.Collectors;
66

7-
import liquidjava.api.CommandLineLauncher;
87
import liquidjava.diagnostics.TranslationTable;
98
import liquidjava.rj_language.ast.Expression;
109
import liquidjava.rj_language.ast.formatter.VariableFormatter;
@@ -53,8 +52,8 @@ public String getCounterExampleString() {
5352
List<String> foundAssignments = found.getValue().getConjuncts().stream().map(Expression::toString).toList();
5453
String counterexampleString = counterexample.assignments().stream()
5554
// only include variables that appear in the found value and are not already fixed there
56-
.filter(a -> CommandLineLauncher.cmdArgs.debugMode || (foundVarNames.contains(a.first())
57-
&& !foundAssignments.contains(a.first() + " == " + a.second())))
55+
.filter(a -> foundVarNames.contains(a.first())
56+
&& !foundAssignments.contains(a.first() + " == " + a.second()))
5857
// format as "var == value"
5958
.map(a -> VariableFormatter.format(a.first()) + " == " + a.second())
6059
// join with "&&"

liquidjava-verifier/src/main/java/liquidjava/processor/context/ContextHistory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.Map;
66
import java.util.Set;
77

8+
import liquidjava.api.CommandLineLauncher;
89
import liquidjava.utils.Utils;
910
import spoon.reflect.cu.SourcePosition;
1011
import spoon.reflect.declaration.CtElement;
@@ -44,6 +45,9 @@ public void clearHistory() {
4445
}
4546

4647
public void saveContext(CtElement element, Context context) {
48+
if (!CommandLineLauncher.cmdArgs.lspMode)
49+
return;
50+
4751
String file = Utils.getFile(element);
4852
if (file == null)
4953
return;

liquidjava-verifier/src/main/java/liquidjava/rj_language/Predicate.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import java.util.Map;
77
import java.util.stream.Collectors;
88

9-
import liquidjava.api.CommandLineLauncher;
9+
import liquidjava.diagnostics.DebugLog;
1010
import liquidjava.diagnostics.errors.LJError;
1111
import liquidjava.diagnostics.errors.NotFoundError;
1212
import liquidjava.processor.context.AliasWrapper;
@@ -257,11 +257,10 @@ public ValDerivationNode simplify(Context context) {
257257
for (AliasWrapper aw : context.getAliases()) {
258258
aliases.put(aw.getName(), aw.createAliasDTO());
259259
}
260-
if (CommandLineLauncher.cmdArgs.debugMode) {
261-
return new ValDerivationNode(exp.clone(), null);
262-
}
263260
// simplify expression
264-
return ExpressionSimplifier.simplify(exp.clone(), aliases);
261+
ValDerivationNode result = ExpressionSimplifier.simplify(exp.clone(), aliases);
262+
DebugLog.simplification(this.getExpression(), result.getValue());
263+
return result;
265264
}
266265

267266
private static boolean isBooleanLiteral(Expression expr, boolean value) {

0 commit comments

Comments
 (0)