Skip to content

Commit 6764cc3

Browse files
l46kokcopybara-github
authored andcommitted
Create a base navigable class that accepts a bound generic type of an expression.
PiperOrigin-RevId: 625400984
1 parent 38484af commit 6764cc3

9 files changed

Lines changed: 269 additions & 174 deletions

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ package(
1010
java_library(
1111
name = "navigation",
1212
srcs = [
13+
"BaseNavigableExpr.java",
1314
"CelNavigableAst.java",
1415
"CelNavigableExpr.java",
1516
"CelNavigableExprVisitor.java",
1617
"ExprHeightCalculator.java",
18+
"TraversalOrder.java",
1719
],
1820
tags = [
1921
],
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.common.navigation;
16+
17+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
18+
import com.google.errorprone.annotations.CheckReturnValue;
19+
import dev.cel.common.ast.CelExpr;
20+
import dev.cel.common.ast.CelExpr.ExprKind;
21+
import dev.cel.common.ast.Expression;
22+
import java.util.Optional;
23+
import java.util.stream.Stream;
24+
25+
/**
26+
* BaseNavigableExpr represents the base navigable expression value with methods to inspect the
27+
* parent and child expressions.
28+
*/
29+
@SuppressWarnings("unchecked") // Generic types are properly bound to Expression
30+
abstract class BaseNavigableExpr<E extends Expression> {
31+
32+
public abstract E expr();
33+
34+
public long id() {
35+
return expr().id();
36+
}
37+
38+
public abstract <T extends BaseNavigableExpr<E>> Optional<T> parent();
39+
40+
/** Represents the count of transitive parents. Depth of an AST's root is 0. */
41+
public abstract int depth();
42+
43+
/**
44+
* Represents the maximum count of children from any of its branches. Height of a leaf node is 0.
45+
* For example, the height of the call node 'func' in expression `(1 + 2 + 3).func(4 + 5)` is 3.
46+
*/
47+
public abstract int height();
48+
49+
/**
50+
* Returns a stream of {@link BaseNavigableExpr} collected from the current node down to the last
51+
* leaf-level member using post-order traversal.
52+
*/
53+
public <T extends BaseNavigableExpr<E>> Stream<T> allNodes() {
54+
return allNodes(TraversalOrder.POST_ORDER);
55+
}
56+
57+
/**
58+
* Returns a stream of {@link BaseNavigableExpr} collected from the current node down to the last
59+
* leaf-level member using the specified traversal order.
60+
*/
61+
public <T extends BaseNavigableExpr<E>> Stream<T> allNodes(TraversalOrder traversalOrder) {
62+
return CelNavigableExprVisitor.collect((T) this, traversalOrder);
63+
}
64+
65+
/**
66+
* Returns a stream of {@link BaseNavigableExpr} collected down to the last leaf-level member
67+
* using post-order traversal.
68+
*/
69+
public <T extends BaseNavigableExpr<E>> Stream<T> descendants() {
70+
return descendants(TraversalOrder.POST_ORDER);
71+
}
72+
73+
/**
74+
* Returns a stream of {@link BaseNavigableExpr} collected down to the last leaf-level member
75+
* using the specified traversal order.
76+
*/
77+
public <T extends BaseNavigableExpr<E>> Stream<T> descendants(TraversalOrder traversalOrder) {
78+
return CelNavigableExprVisitor.collect((T) this, traversalOrder)
79+
.filter(node -> node.depth() > this.depth());
80+
}
81+
82+
/**
83+
* Returns a stream of {@link BaseNavigableExpr} collected from its immediate children using
84+
* post-order traversal.
85+
*/
86+
public <T extends BaseNavigableExpr<E>> Stream<T> children() {
87+
return children(TraversalOrder.POST_ORDER);
88+
}
89+
90+
/**
91+
* Returns a stream of {@link BaseNavigableExpr} collected from its immediate children using the
92+
* specified traversal order.
93+
*/
94+
public <T extends BaseNavigableExpr<E>> Stream<T> children(TraversalOrder traversalOrder) {
95+
return CelNavigableExprVisitor.collect((T) this, this.depth() + 1, traversalOrder)
96+
.filter(node -> node.depth() > this.depth());
97+
}
98+
99+
/** Returns the underlying kind of the {@link CelExpr}. */
100+
public ExprKind.Kind getKind() {
101+
return expr().getKind();
102+
}
103+
104+
public abstract <T extends BaseNavigableExpr<E>> Builder<E, T> builderFromInstance();
105+
106+
interface Builder<E extends Expression, T extends BaseNavigableExpr<E>> {
107+
108+
E expr();
109+
110+
int depth();
111+
112+
default ExprKind.Kind getKind() {
113+
return expr().getKind();
114+
}
115+
116+
@CanIgnoreReturnValue
117+
Builder<E, T> setExpr(E value);
118+
119+
@CanIgnoreReturnValue
120+
Builder<E, T> setParent(T value);
121+
122+
@CanIgnoreReturnValue
123+
Builder<E, T> setDepth(int value);
124+
125+
@CanIgnoreReturnValue
126+
Builder<E, T> setHeight(int value);
127+
128+
@CheckReturnValue
129+
T build();
130+
}
131+
}

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

Lines changed: 33 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -16,118 +16,60 @@
1616

1717
import com.google.auto.value.AutoValue;
1818
import dev.cel.common.ast.CelExpr;
19-
import dev.cel.common.ast.CelExpr.CelComprehension;
20-
import dev.cel.common.ast.CelExpr.ExprKind;
2119
import java.util.Optional;
2220
import java.util.stream.Stream;
2321

2422
/**
25-
* CelNavigableExpr represents the base navigable expression value with methods to inspect the
26-
* parent and child expressions.
23+
* CelNavigableExpr decorates {@link CelExpr} with capabilities to inspect the parent and its
24+
* descendants with ease.
2725
*/
2826
@AutoValue
29-
public abstract class CelNavigableExpr {
30-
31-
/**
32-
* Specifies the traversal order of AST navigation.
33-
*
34-
* <p>For call expressions, the target is visited before its arguments.
35-
*
36-
* <p>For comprehensions, the visiting order is as follows:
37-
*
38-
* <ol>
39-
* <li>{@link CelComprehension#iterRange}
40-
* <li>{@link CelComprehension#accuInit}
41-
* <li>{@link CelComprehension#loopCondition}
42-
* <li>{@link CelComprehension#loopStep}
43-
* <li>{@link CelComprehension#result}
44-
* </ol>
45-
*/
46-
public enum TraversalOrder {
47-
PRE_ORDER,
48-
POST_ORDER
49-
}
50-
51-
public abstract CelExpr expr();
52-
53-
public long id() {
54-
return expr().id();
55-
}
56-
57-
public abstract Optional<CelNavigableExpr> parent();
58-
59-
/** Represents the count of transitive parents. Depth of an AST's root is 0. */
60-
public abstract int depth();
61-
62-
/**
63-
* Represents the maximum count of children from any of its branches. Height of a leaf node is 0.
64-
* For example, the height of the call node 'func' in expression `(1 + 2 + 3).func(4 + 5)` is 3.
65-
*/
66-
public abstract int height();
67-
27+
// unchecked: Generic types are properly bound to BaseNavigableExpr
28+
// redundant override: Overriding is required to specify the return type to a concrete type.
29+
@SuppressWarnings({"unchecked", "RedundantOverride"})
30+
public abstract class CelNavigableExpr extends BaseNavigableExpr<CelExpr> {
6831
/** Constructs a new instance of {@link CelNavigableExpr} from {@link CelExpr}. */
6932
public static CelNavigableExpr fromExpr(CelExpr expr) {
70-
ExprHeightCalculator exprHeightCalculator = new ExprHeightCalculator(expr);
71-
72-
return CelNavigableExpr.builder()
73-
.setExpr(expr)
74-
.setHeight(exprHeightCalculator.getHeight(expr.id()))
75-
.build();
33+
ExprHeightCalculator<CelExpr> exprHeightCalculator = new ExprHeightCalculator<>(expr);
34+
return builder().setExpr(expr).setHeight(exprHeightCalculator.getHeight(expr.id())).build();
7635
}
7736

78-
/**
79-
* Returns a stream of {@link CelNavigableExpr} collected from the current node down to the last
80-
* leaf-level member using post-order traversal.
81-
*/
37+
@Override
8238
public Stream<CelNavigableExpr> allNodes() {
83-
return allNodes(TraversalOrder.POST_ORDER);
39+
return super.allNodes();
8440
}
8541

86-
/**
87-
* Returns a stream of {@link CelNavigableExpr} collected from the current node down to the last
88-
* leaf-level member using the specified traversal order.
89-
*/
42+
@Override
9043
public Stream<CelNavigableExpr> allNodes(TraversalOrder traversalOrder) {
91-
return CelNavigableExprVisitor.collect(this, traversalOrder);
44+
return super.allNodes(traversalOrder);
9245
}
9346

94-
/**
95-
* Returns a stream of {@link CelNavigableExpr} collected down to the last leaf-level member using
96-
* post-order traversal.
97-
*/
47+
@Override
48+
public abstract Optional<CelNavigableExpr> parent();
49+
50+
@Override
9851
public Stream<CelNavigableExpr> descendants() {
99-
return descendants(TraversalOrder.POST_ORDER);
52+
return super.descendants();
10053
}
10154

102-
/**
103-
* Returns a stream of {@link CelNavigableExpr} collected down to the last leaf-level member using
104-
* the specified traversal order.
105-
*/
55+
@Override
10656
public Stream<CelNavigableExpr> descendants(TraversalOrder traversalOrder) {
107-
return CelNavigableExprVisitor.collect(this, traversalOrder)
108-
.filter(node -> node.depth() > this.depth());
57+
return super.descendants(traversalOrder);
10958
}
11059

111-
/**
112-
* Returns a stream of {@link CelNavigableExpr} collected from its immediate children using
113-
* post-order traversal.
114-
*/
60+
@Override
11561
public Stream<CelNavigableExpr> children() {
116-
return children(TraversalOrder.POST_ORDER);
62+
return super.children();
11763
}
11864

119-
/**
120-
* Returns a stream of {@link CelNavigableExpr} collected from its immediate children using the
121-
* specified traversal order.
122-
*/
65+
@Override
12366
public Stream<CelNavigableExpr> children(TraversalOrder traversalOrder) {
124-
return CelNavigableExprVisitor.collect(this, this.depth() + 1, traversalOrder)
125-
.filter(node -> node.depth() > this.depth());
67+
return super.children(traversalOrder);
12668
}
12769

128-
/** Returns the underlying kind of the {@link CelExpr}. */
129-
public ExprKind.Kind getKind() {
130-
return expr().exprKind().getKind();
70+
@Override
71+
public Builder builderFromInstance() {
72+
return builder();
13173
}
13274

13375
/** Create a new builder to construct a {@link CelNavigableExpr} instance. */
@@ -137,25 +79,20 @@ public static Builder builder() {
13779

13880
/** Builder to configure {@link CelNavigableExpr}. */
13981
@AutoValue.Builder
140-
public abstract static class Builder {
82+
public abstract static class Builder
83+
implements BaseNavigableExpr.Builder<CelExpr, CelNavigableExpr> {
14184

142-
public abstract CelExpr expr();
143-
144-
public abstract int depth();
145-
146-
public ExprKind.Kind getKind() {
147-
return expr().exprKind().getKind();
148-
}
85+
@Override
86+
public abstract Builder setParent(CelNavigableExpr value);
14987

88+
@Override
15089
public abstract Builder setExpr(CelExpr value);
15190

152-
abstract Builder setParent(CelNavigableExpr value);
153-
91+
@Override
15492
public abstract Builder setDepth(int value);
15593

94+
@Override
15695
public abstract Builder setHeight(int value);
157-
158-
public abstract CelNavigableExpr build();
15996
}
16097

16198
public abstract Builder toBuilder();

0 commit comments

Comments
 (0)