Skip to content

Commit b73c128

Browse files
committed
Simplify Unambiguous Qualified Names
1 parent d91f256 commit b73c128

3 files changed

Lines changed: 74 additions & 7 deletions

File tree

liquidjava-verifier/src/main/java/liquidjava/rj_language/ast/formatter/ExpressionFormatter.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,25 @@
1919
import liquidjava.rj_language.ast.UnaryExpression;
2020
import liquidjava.rj_language.ast.Var;
2121
import liquidjava.rj_language.visitors.ExpressionVisitor;
22-
import liquidjava.utils.Utils;
2322

2423
/**
2524
* Formatter for expressions that only adds parentheses when required by precedence and associativity rules and formats
2625
* variable names using {@link VariableFormatter}
2726
*/
2827
public class ExpressionFormatter implements ExpressionVisitor<String> {
2928

29+
private final ExpressionNameResolver nameResolver;
30+
31+
private ExpressionFormatter(Expression expression) {
32+
this.nameResolver = ExpressionNameResolver.forExpression(expression);
33+
}
34+
3035
public static String format(Predicate predicate) {
3136
return format(predicate.getExpression());
3237
}
3338

3439
public static String format(Expression expression) {
35-
return new ExpressionFormatter().formatExpression(expression);
40+
return new ExpressionFormatter(expression).formatExpression(expression);
3641
}
3742

3843
private String formatExpression(Expression expression) {
@@ -108,7 +113,7 @@ public String visitBinaryExpression(BinaryExpression exp) {
108113

109114
@Override
110115
public String visitFunctionInvocation(FunctionInvocation fun) {
111-
return Utils.getSimpleName(fun.getName()) + "(" + formatArguments(fun.getArgs()) + ")";
116+
return nameResolver.resolveFunction(fun.getName()) + "(" + formatArguments(fun.getArgs()) + ")";
112117
}
113118

114119
@Override
@@ -159,6 +164,6 @@ public String visitEnum(Enum en) {
159164

160165
@Override
161166
public String visitVar(Var var) {
162-
return VariableFormatter.format(var.getName());
167+
return nameResolver.resolveVariable(var.getName());
163168
}
164169
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package liquidjava.rj_language.ast.formatter;
2+
3+
import java.util.HashSet;
4+
import java.util.Set;
5+
6+
import liquidjava.rj_language.ast.Expression;
7+
import liquidjava.rj_language.ast.FunctionInvocation;
8+
import liquidjava.rj_language.ast.Var;
9+
import liquidjava.utils.Utils;
10+
11+
/** Simplifies unambiguous qualified names within one expression */
12+
final class ExpressionNameResolver {
13+
private final Set<String> variables = new HashSet<>();
14+
private final Set<String> functions = new HashSet<>();
15+
16+
public static ExpressionNameResolver forExpression(Expression expression) {
17+
ExpressionNameResolver resolver = new ExpressionNameResolver();
18+
resolver.collect(expression);
19+
return resolver;
20+
}
21+
22+
public String resolveVariable(String name) {
23+
return resolve(VariableFormatter.format(name), variables);
24+
}
25+
26+
public String resolveFunction(String name) {
27+
return resolve(name, functions);
28+
}
29+
30+
private void collect(Expression expression) {
31+
if (expression instanceof Var var)
32+
variables.add(VariableFormatter.format(var.getName()));
33+
else if (expression instanceof FunctionInvocation function)
34+
functions.add(function.getName());
35+
expression.getChildren().forEach(this::collect);
36+
}
37+
38+
private static String resolve(String name, Set<String> names) {
39+
String simpleName = Utils.getSimpleName(name);
40+
boolean ambiguous = names.stream()
41+
.anyMatch(other -> !other.equals(name) && Utils.getSimpleName(other).equals(simpleName));
42+
return ambiguous ? name : simpleName;
43+
}
44+
}

liquidjava-verifier/src/test/java/liquidjava/rj_language/ast/ExpressionFormatterTest.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@
99
class ExpressionFormatterTest {
1010

1111
private static Expression parse(String refinement) {
12-
return RefinementsParser.createAST(refinement, "");
12+
return parse(refinement, "");
13+
}
14+
15+
private static Expression parse(String refinement, String prefix) {
16+
return RefinementsParser.createAST(refinement, prefix);
1317
}
1418

1519
@Test
16-
void formatsUnaryAtoms() {
20+
void formatsUnary() {
1721
assertEquals("!x", parse("!x").toDisplayString());
1822
assertEquals("!false", parse("!false").toDisplayString());
1923
}
@@ -50,7 +54,7 @@ void formatsBinaryPrecedence() {
5054
}
5155

5256
@Test
53-
void omitsUnnecessaryGroupParentheses() {
57+
void formatsGrouping() {
5458
assertEquals("x", parse("(x)").toDisplayString());
5559
assertEquals("x", parse("((x))").toDisplayString());
5660
assertEquals("1", parse("(1)").toDisplayString());
@@ -97,4 +101,18 @@ void formatsTernaryExpressions() {
97101
assertEquals("a ? b : (c ? d : (e ? f : g))", parse("a ? b : c ? d : e ? f : g").toDisplayString());
98102
assertEquals("a ? b : c", parse("a ? b : c").toDisplayString());
99103
}
104+
105+
@Test
106+
void formatsWithQualifiedNames() {
107+
Expression exp = new BinaryExpression(parse("size(this)", "java.util.ArrayList"), "==",
108+
parse("size(this)", "java.util.ArrayDeque"));
109+
assertEquals("java.util.ArrayList.size(this) == java.util.ArrayDeque.size(this)",
110+
exp.toDisplayString());
111+
}
112+
113+
@Test
114+
void formatsWithoutQualifiedNames() {
115+
assertEquals("size(this)", parse("size(this)", "java.util.List").toDisplayString());
116+
assertEquals("size(this) == size(this)", parse("size(this) == size(this)", "java.util.List").toDisplayString());
117+
}
100118
}

0 commit comments

Comments
 (0)