Skip to content

Commit 9beac1e

Browse files
committed
Cleanup ExpressionSimplifier
1 parent f6cd691 commit 9beac1e

2 files changed

Lines changed: 49 additions & 46 deletions

File tree

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

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,12 @@
22

33
import java.util.ArrayList;
44
import java.util.List;
5-
import java.util.stream.Collectors;
6-
75
import liquidjava.api.CommandLineLauncher;
86
import liquidjava.processor.VCImplication;
97
import liquidjava.rj_language.Predicate;
108
import liquidjava.rj_language.ast.BinaryExpression;
119
import liquidjava.rj_language.ast.Expression;
1210
import liquidjava.rj_language.ast.GroupExpression;
13-
import liquidjava.smt.Counterexample;
1411
import liquidjava.utils.Utils;
1512
import spoon.reflect.cu.SourcePosition;
1613
import spoon.reflect.reference.CtTypeReference;
@@ -156,33 +153,45 @@ private static void printSplitConjunction(String header, String color, Expressio
156153

157154
private static final String PASS_NAME_COLOR = Colors.GOLD;
158155
private static final int PASS_NAME_WIDTH = 28;
156+
private static int simplificationPass;
157+
private static String previousSimplification;
159158

160159
/**
161-
* One line per simplifier phase. {@code pass} is a running counter inside a single {@code simplify()} call.
160+
* Start a simplification log. DebugLog owns the running pass number and the previous expression snapshot because
161+
* both are only needed for debug output.
162162
*/
163-
public static void simplificationPass(int pass, String name, Expression result) {
163+
public static void simplificationStart(Expression input) {
164164
if (!enabled()) {
165165
return;
166166
}
167-
System.out.printf("%s pass %02d: %s%n %s%n", SMP_TAG, pass, paintPassName(name), result);
167+
previousSimplification = input.toString();
168+
simplificationPass = 0;
169+
printSimplificationPass(simplificationPass, "initial expression", previousSimplification);
168170
}
169171

170172
/**
171-
* Same as {@link #simplificationPass(int, String, Expression)} but prints {@code (no change)} when the step left
172-
* the expression unchanged, and otherwise emits a unified-diff-style pair (red {@code -} for the previous
173-
* expression with removed tokens highlighted, green {@code +} for the new one with added tokens highlighted), so
174-
* substitutions inside a long predicate are obvious at a glance.
173+
* One line per simplifier phase.
174+
*/
175+
public static void simplificationPass(String name, Expression result) {
176+
if (!enabled()) {
177+
return;
178+
}
179+
String resultStr = result.toString();
180+
printSimplificationPass(++simplificationPass, name, previousSimplification, resultStr);
181+
previousSimplification = resultStr;
182+
}
183+
184+
/**
185+
* Prints {@code (no change)} when the step left the expression unchanged, and otherwise emits a unified-diff-style
186+
* pair (red {@code -} for the previous expression with removed tokens highlighted, green {@code +} for the new one
187+
* with added tokens highlighted), so substitutions inside a long predicate are obvious at a glance.
175188
*
176189
* <p>
177190
* {@code previous} is taken as a string rather than an {@link Expression} because the simplifier mutates the AST in
178191
* place: caching an {@code Expression} reference and re-stringifying it after a later pass would yield the
179-
* already-mutated form, masking real changes as "no change". The caller is expected to snapshot the printed form at
180-
* the moment the previous pass ran.
192+
* already-mutated form, masking real changes as "no change".
181193
*/
182-
public static void simplificationPass(int pass, String name, String previous, String result) {
183-
if (!enabled()) {
184-
return;
185-
}
194+
private static void printSimplificationPass(int pass, String name, String previous, String result) {
186195
if (previous != null && previous.equals(result)) {
187196
System.out.printf("%s pass %02d: %s %s(no change)%s%n", SMP_TAG, pass, paintPassName(name), Colors.GREY,
188197
Colors.RESET);
@@ -198,6 +207,10 @@ public static void simplificationPass(int pass, String name, String previous, St
198207
System.out.printf("%s %s+%s %s%n", SMP_TAG, Colors.GREEN, Colors.RESET, diff[1]);
199208
}
200209

210+
private static void printSimplificationPass(int pass, String name, String result) {
211+
System.out.printf("%s pass %02d: %s%n %s%n", SMP_TAG, pass, paintPassName(name), result);
212+
}
213+
201214
/**
202215
* Color the pass name without breaking column alignment: pad to {@link #PASS_NAME_WIDTH} first, then wrap only the
203216
* visible characters in {@link #PASS_NAME_COLOR}. The trailing spaces stay uncolored so {@code printf}'s width

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

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,48 +24,28 @@ public class ExpressionSimplifier {
2424
* expanding aliases Returns a derivation node representing the tree of simplifications applied
2525
*/
2626
public static ValDerivationNode simplify(Expression exp, Map<String, AliasDTO> aliases) {
27-
int[] pass = { 0 };
28-
// String, not Expression: the simplification passes mutate the AST in place, so storing an Expression
29-
// reference would always compare equal to itself after the next pass runs. Snapshot the printed form instead.
30-
String[] prev = { null };
31-
DebugLog.simplificationPass(0, "initial expression", exp);
32-
prev[0] = exp.toString();
33-
ValDerivationNode fixedPoint = simplifyToFixedPoint(null, exp, pass, prev);
34-
logStep(pass, prev, "fixed-point reached", fixedPoint.getValue());
27+
DebugLog.simplificationStart(exp);
28+
ValDerivationNode fixedPoint = simplifyToFixedPoint(null, exp);
29+
DebugLog.simplificationPass("fixed-point reached", fixedPoint.getValue());
3530
ValDerivationNode simplified = simplifyValDerivationNode(fixedPoint);
36-
logStep(pass, prev, "remove redundant &&", simplified.getValue());
31+
DebugLog.simplificationPass("remove redundant &&", simplified.getValue());
3732
ValDerivationNode unwrapped = unwrapBooleanLiterals(simplified);
38-
logStep(pass, prev, "unwrap boolean literals", unwrapped.getValue());
33+
DebugLog.simplificationPass("unwrap boolean literals", unwrapped.getValue());
3934
ValDerivationNode expanded = AliasExpansion.expand(unwrapped, aliases);
40-
logStep(pass, prev, "expand aliases", expanded.getValue());
35+
DebugLog.simplificationPass("expand aliases", expanded.getValue());
4136
return expanded;
4237
}
4338

4439
public static ValDerivationNode simplify(Expression exp) {
4540
return simplify(exp, Map.of());
4641
}
4742

48-
private static void logStep(int[] pass, String[] prev, String name, Expression result) {
49-
String resultStr = result.toString();
50-
DebugLog.simplificationPass(++pass[0], name, prev[0], resultStr);
51-
prev[0] = resultStr;
52-
}
53-
5443
/**
5544
* Recursively applies propagation and folding until the expression stops changing (fixed point) Stops early if the
56-
* expression simplifies to a boolean literal, which means we've simplified too much. {@code pass} and {@code prev}
57-
* are running counters shared with {@link #simplify} so debug output keeps a single monotonic numbering and can
58-
* detect no-op steps.
45+
* expression simplifies to a boolean literal, which means we've simplified too much.
5946
*/
60-
private static ValDerivationNode simplifyToFixedPoint(ValDerivationNode current, Expression prevExp, int[] pass,
61-
String[] prev) {
62-
// apply propagation and folding
63-
ValDerivationNode prop = VariablePropagation.propagate(prevExp, current);
64-
logStep(pass, prev, "variable propagation", prop.getValue());
65-
ValDerivationNode fold = ExpressionFolding.fold(prop);
66-
logStep(pass, prev, "expression folding", fold.getValue());
67-
ValDerivationNode simplified = simplifyValDerivationNode(fold);
68-
logStep(pass, prev, "remove redundant && (loop)", simplified.getValue());
47+
private static ValDerivationNode simplifyToFixedPoint(ValDerivationNode current, Expression prevExp) {
48+
ValDerivationNode simplified = simplifyOnce(current, prevExp);
6949
Expression currExp = simplified.getValue();
7050

7151
// fixed point reached — compare on toString() because propagate/fold/reduce mutate the AST in place, so a
@@ -80,7 +60,17 @@ private static ValDerivationNode simplifyToFixedPoint(ValDerivationNode current,
8060
}
8161

8262
// continue simplifying
83-
return simplifyToFixedPoint(simplified, simplified.getValue(), pass, prev);
63+
return simplifyToFixedPoint(simplified, simplified.getValue());
64+
}
65+
66+
private static ValDerivationNode simplifyOnce(ValDerivationNode current, Expression prevExp) {
67+
ValDerivationNode prop = VariablePropagation.propagate(prevExp, current);
68+
DebugLog.simplificationPass("variable propagation", prop.getValue());
69+
ValDerivationNode fold = ExpressionFolding.fold(prop);
70+
DebugLog.simplificationPass("expression folding", fold.getValue());
71+
ValDerivationNode simplified = simplifyValDerivationNode(fold);
72+
DebugLog.simplificationPass("remove redundant && (loop)", simplified.getValue());
73+
return simplified;
8474
}
8575

8676
/**

0 commit comments

Comments
 (0)