Skip to content

Commit e9ea10d

Browse files
l46kokcopybara-github
authored andcommitted
Add height property to CelNavigableExpr
PiperOrigin-RevId: 606419785
1 parent c916a11 commit e9ea10d

4 files changed

Lines changed: 308 additions & 45 deletions

File tree

common/src/main/java/dev/cel/common/navigation/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ java_library(
2020
"//:auto_value",
2121
"//common",
2222
"//common/ast",
23+
"@maven//:com_google_errorprone_error_prone_annotations",
2324
"@maven//:com_google_guava_guava",
2425
],
2526
)

common/src/main/java/dev/cel/common/navigation/CelNavigableExpr.java

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package dev.cel.common.navigation;
1616

1717
import com.google.auto.value.AutoValue;
18+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
19+
import com.google.errorprone.annotations.CheckReturnValue;
1820
import dev.cel.common.ast.CelExpr;
1921
import dev.cel.common.ast.CelExpr.CelComprehension;
2022
import dev.cel.common.ast.CelExpr.ExprKind;
@@ -59,6 +61,12 @@ public long id() {
5961
/** Represents the count of transitive parents. Depth of an AST's root is 0. */
6062
public abstract int depth();
6163

64+
/**
65+
* Represents the maximum count of children from any of its branches. Height of a leaf node is 0.
66+
* For example, the height of the call node 'func' in expression `(1 + 2 + 3).func(4 + 5)` is 3.
67+
*/
68+
public abstract int height();
69+
6270
/** Constructs a new instance of {@link CelNavigableExpr} from {@link CelExpr}. */
6371
public static CelNavigableExpr fromExpr(CelExpr expr) {
6472
return CelNavigableExpr.builder().setExpr(expr).build();
@@ -93,7 +101,8 @@ public Stream<CelNavigableExpr> descendants() {
93101
* the specified traversal order.
94102
*/
95103
public Stream<CelNavigableExpr> descendants(TraversalOrder traversalOrder) {
96-
return CelNavigableExprVisitor.collect(this, traversalOrder).filter(node -> !node.equals(this));
104+
return CelNavigableExprVisitor.collect(this, traversalOrder)
105+
.filter(node -> node.depth() > this.depth());
97106
}
98107

99108
/**
@@ -110,7 +119,7 @@ public Stream<CelNavigableExpr> children() {
110119
*/
111120
public Stream<CelNavigableExpr> children(TraversalOrder traversalOrder) {
112121
return CelNavigableExprVisitor.collect(this, this.depth() + 1, traversalOrder)
113-
.filter(node -> !node.equals(this));
122+
.filter(node -> node.depth() > this.depth());
114123
}
115124

116125
/** Returns the underlying kind of the {@link CelExpr}. */
@@ -120,21 +129,47 @@ public ExprKind.Kind getKind() {
120129

121130
/** Create a new builder to construct a {@link CelNavigableExpr} instance. */
122131
public static Builder builder() {
123-
return new AutoValue_CelNavigableExpr.Builder().setDepth(0);
132+
return new AutoValue_CelNavigableExpr.Builder().setDepth(0).setHeight(0);
124133
}
125134

126135
/** Builder to configure {@link CelNavigableExpr}. */
127136
@AutoValue.Builder
128137
public abstract static class Builder {
129138

139+
private Builder parentBuilder;
140+
130141
public abstract CelExpr expr();
131142

143+
public abstract int depth();
144+
145+
public ExprKind.Kind getKind() {
146+
return expr().exprKind().getKind();
147+
}
148+
132149
public abstract Builder setExpr(CelExpr value);
133150

134-
public abstract Builder setParent(CelNavigableExpr value);
151+
abstract Builder setParent(CelNavigableExpr value);
152+
153+
@CanIgnoreReturnValue
154+
public Builder setParentBuilder(CelNavigableExpr.Builder value) {
155+
parentBuilder = value;
156+
return this;
157+
}
135158

136159
public abstract Builder setDepth(int value);
137160

138-
public abstract CelNavigableExpr build();
161+
public abstract Builder setHeight(int value);
162+
163+
public abstract CelNavigableExpr autoBuild();
164+
165+
@CheckReturnValue
166+
public CelNavigableExpr build() {
167+
if (parentBuilder != null) {
168+
setParent(parentBuilder.build());
169+
}
170+
return autoBuild();
171+
}
139172
}
173+
174+
public abstract Builder toBuilder();
140175
}

common/src/main/java/dev/cel/common/navigation/CelNavigableExprVisitor.java

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
package dev.cel.common.navigation;
1616

17+
import static java.lang.Math.max;
18+
1719
import com.google.common.collect.ImmutableList;
1820
import dev.cel.common.ast.CelExpr;
1921
import dev.cel.common.ast.CelExpr.CelCall;
@@ -29,7 +31,7 @@
2931
final class CelNavigableExprVisitor {
3032
private static final int MAX_DESCENDANTS_RECURSION_DEPTH = 500;
3133

32-
private final Stream.Builder<CelNavigableExpr> streamBuilder;
34+
private final Stream.Builder<CelNavigableExpr.Builder> streamBuilder;
3335
private final TraversalOrder traversalOrder;
3436
private final int maxDepth;
3537

@@ -84,105 +86,124 @@ static Stream<CelNavigableExpr> collect(
8486
CelNavigableExpr navigableExpr, int maxDepth, TraversalOrder traversalOrder) {
8587
CelNavigableExprVisitor visitor = new CelNavigableExprVisitor(maxDepth, traversalOrder);
8688

87-
visitor.visit(navigableExpr);
89+
visitor.visit(navigableExpr.toBuilder());
8890

89-
return visitor.streamBuilder.build();
91+
return visitor.streamBuilder.build().map(CelNavigableExpr.Builder::build);
9092
}
9193

92-
private void visit(CelNavigableExpr navigableExpr) {
94+
private int visit(CelNavigableExpr.Builder navigableExpr) {
9395
if (navigableExpr.depth() > MAX_DESCENDANTS_RECURSION_DEPTH - 1) {
9496
throw new IllegalStateException("Max recursion depth reached.");
9597
}
9698
if (navigableExpr.depth() > maxDepth) {
97-
return;
99+
return -1;
98100
}
99101
if (traversalOrder.equals(TraversalOrder.PRE_ORDER)) {
100102
streamBuilder.add(navigableExpr);
101103
}
102104

105+
int height = 1;
103106
switch (navigableExpr.getKind()) {
104107
case CALL:
105-
visit(navigableExpr, navigableExpr.expr().call());
108+
height += visit(navigableExpr, navigableExpr.expr().call());
106109
break;
107110
case CREATE_LIST:
108-
visit(navigableExpr, navigableExpr.expr().createList());
111+
height += visit(navigableExpr, navigableExpr.expr().createList());
109112
break;
110113
case SELECT:
111-
visit(navigableExpr, navigableExpr.expr().select());
114+
height += visit(navigableExpr, navigableExpr.expr().select());
112115
break;
113116
case CREATE_STRUCT:
114-
visitStruct(navigableExpr, navigableExpr.expr().createStruct());
117+
height += visitStruct(navigableExpr, navigableExpr.expr().createStruct());
115118
break;
116119
case CREATE_MAP:
117-
visitMap(navigableExpr, navigableExpr.expr().createMap());
120+
height += visitMap(navigableExpr, navigableExpr.expr().createMap());
118121
break;
119122
case COMPREHENSION:
120-
visit(navigableExpr, navigableExpr.expr().comprehension());
123+
height += visit(navigableExpr, navigableExpr.expr().comprehension());
121124
break;
122125
default:
126+
// This is a leaf node
127+
height = 0;
123128
break;
124129
}
125130

131+
navigableExpr.setHeight(height);
126132
if (traversalOrder.equals(TraversalOrder.POST_ORDER)) {
127133
streamBuilder.add(navigableExpr);
128134
}
135+
136+
return height;
129137
}
130138

131-
private void visit(CelNavigableExpr navigableExpr, CelCall call) {
139+
private int visit(CelNavigableExpr.Builder navigableExpr, CelCall call) {
140+
int targetHeight = 0;
132141
if (call.target().isPresent()) {
133-
CelNavigableExpr target = newNavigableChild(navigableExpr, call.target().get());
134-
visit(target);
142+
CelNavigableExpr.Builder target = newNavigableChild(navigableExpr, call.target().get());
143+
targetHeight = visit(target);
135144
}
136145

137-
visitExprList(call.args(), navigableExpr);
146+
int argumentHeight = visitExprList(call.args(), navigableExpr);
147+
return max(targetHeight, argumentHeight);
138148
}
139149

140-
private void visit(CelNavigableExpr navigableExpr, CelCreateList createList) {
141-
visitExprList(createList.elements(), navigableExpr);
150+
private int visit(CelNavigableExpr.Builder navigableExpr, CelCreateList createList) {
151+
return visitExprList(createList.elements(), navigableExpr);
142152
}
143153

144-
private void visit(CelNavigableExpr navigableExpr, CelSelect selectExpr) {
145-
CelNavigableExpr operand = newNavigableChild(navigableExpr, selectExpr.operand());
146-
visit(operand);
154+
private int visit(CelNavigableExpr.Builder navigableExpr, CelSelect selectExpr) {
155+
CelNavigableExpr.Builder operand = newNavigableChild(navigableExpr, selectExpr.operand());
156+
return visit(operand);
147157
}
148158

149-
private void visit(CelNavigableExpr navigableExpr, CelComprehension comprehension) {
150-
visit(newNavigableChild(navigableExpr, comprehension.iterRange()));
151-
visit(newNavigableChild(navigableExpr, comprehension.accuInit()));
152-
visit(newNavigableChild(navigableExpr, comprehension.loopCondition()));
153-
visit(newNavigableChild(navigableExpr, comprehension.loopStep()));
154-
visit(newNavigableChild(navigableExpr, comprehension.result()));
159+
private int visit(CelNavigableExpr.Builder navigableExpr, CelComprehension comprehension) {
160+
int maxHeight = 0;
161+
maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.iterRange())), maxHeight);
162+
maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.accuInit())), maxHeight);
163+
maxHeight =
164+
max(visit(newNavigableChild(navigableExpr, comprehension.loopCondition())), maxHeight);
165+
maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.loopStep())), maxHeight);
166+
maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.result())), maxHeight);
167+
168+
return maxHeight;
155169
}
156170

157-
private void visitStruct(CelNavigableExpr navigableExpr, CelCreateStruct struct) {
171+
private int visitStruct(CelNavigableExpr.Builder navigableExpr, CelCreateStruct struct) {
172+
int maxHeight = 0;
158173
for (CelCreateStruct.Entry entry : struct.entries()) {
159-
CelNavigableExpr value = newNavigableChild(navigableExpr, entry.value());
160-
visit(value);
174+
CelNavigableExpr.Builder value = newNavigableChild(navigableExpr, entry.value());
175+
maxHeight = max(visit(value), maxHeight);
161176
}
177+
return maxHeight;
162178
}
163179

164-
private void visitMap(CelNavigableExpr navigableExpr, CelCreateMap map) {
180+
private int visitMap(CelNavigableExpr.Builder navigableExpr, CelCreateMap map) {
181+
int maxHeight = 0;
165182
for (CelCreateMap.Entry entry : map.entries()) {
166-
CelNavigableExpr key = newNavigableChild(navigableExpr, entry.key());
167-
visit(key);
183+
CelNavigableExpr.Builder key = newNavigableChild(navigableExpr, entry.key());
184+
maxHeight = max(visit(key), maxHeight);
168185

169-
CelNavigableExpr value = newNavigableChild(navigableExpr, entry.value());
170-
visit(value);
186+
CelNavigableExpr.Builder value = newNavigableChild(navigableExpr, entry.value());
187+
maxHeight = max(visit(value), maxHeight);
171188
}
189+
return 0;
172190
}
173191

174-
private void visitExprList(ImmutableList<CelExpr> createListExpr, CelNavigableExpr parent) {
192+
private int visitExprList(
193+
ImmutableList<CelExpr> createListExpr, CelNavigableExpr.Builder parent) {
194+
int maxHeight = 0;
175195
for (CelExpr expr : createListExpr) {
176-
CelNavigableExpr arg = newNavigableChild(parent, expr);
177-
visit(arg);
196+
CelNavigableExpr.Builder arg = newNavigableChild(parent, expr);
197+
maxHeight = max(visit(arg), maxHeight);
178198
}
199+
return maxHeight;
179200
}
180201

181-
private CelNavigableExpr newNavigableChild(CelNavigableExpr parent, CelExpr expr) {
202+
private CelNavigableExpr.Builder newNavigableChild(
203+
CelNavigableExpr.Builder parent, CelExpr expr) {
182204
return CelNavigableExpr.builder()
183205
.setExpr(expr)
184206
.setDepth(parent.depth() + 1)
185-
.setParent(parent)
186-
.build();
207+
.setParentBuilder(parent);
187208
}
188209
}

0 commit comments

Comments
 (0)