Skip to content

Commit

Permalink
Add height property to CelNavigableExpr
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 606657258
  • Loading branch information
l46kok authored and copybara-github committed Feb 13, 2024
1 parent c916a11 commit f98b582
Showing 4 changed files with 308 additions and 45 deletions.
1 change: 1 addition & 0 deletions common/src/main/java/dev/cel/common/navigation/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ java_library(
"//:auto_value",
"//common",
"//common/ast",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
],
)
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@
package dev.cel.common.navigation;

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

/**
* Represents the maximum count of children from any of its branches. Height of a leaf node is 0.
* For example, the height of the call node 'func' in expression `(1 + 2 + 3).func(4 + 5)` is 3.
*/
public abstract int height();

/** Constructs a new instance of {@link CelNavigableExpr} from {@link CelExpr}. */
public static CelNavigableExpr fromExpr(CelExpr expr) {
return CelNavigableExpr.builder().setExpr(expr).build();
@@ -93,7 +101,8 @@ public Stream<CelNavigableExpr> descendants() {
* the specified traversal order.
*/
public Stream<CelNavigableExpr> descendants(TraversalOrder traversalOrder) {
return CelNavigableExprVisitor.collect(this, traversalOrder).filter(node -> !node.equals(this));
return CelNavigableExprVisitor.collect(this, traversalOrder)
.filter(node -> node.depth() > this.depth());
}

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

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

/** Create a new builder to construct a {@link CelNavigableExpr} instance. */
public static Builder builder() {
return new AutoValue_CelNavigableExpr.Builder().setDepth(0);
return new AutoValue_CelNavigableExpr.Builder().setDepth(0).setHeight(0);
}

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

private Builder parentBuilder;

public abstract CelExpr expr();

public abstract int depth();

public ExprKind.Kind getKind() {
return expr().exprKind().getKind();
}

public abstract Builder setExpr(CelExpr value);

public abstract Builder setParent(CelNavigableExpr value);
abstract Builder setParent(CelNavigableExpr value);

@CanIgnoreReturnValue
public Builder setParentBuilder(CelNavigableExpr.Builder value) {
parentBuilder = value;
return this;
}

public abstract Builder setDepth(int value);

public abstract CelNavigableExpr build();
public abstract Builder setHeight(int value);

public abstract CelNavigableExpr autoBuild();

@CheckReturnValue
public CelNavigableExpr build() {
if (parentBuilder != null) {
setParent(parentBuilder.build());
}
return autoBuild();
}
}

public abstract Builder toBuilder();
}
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@

package dev.cel.common.navigation;

import static java.lang.Math.max;

import com.google.common.collect.ImmutableList;
import dev.cel.common.ast.CelExpr;
import dev.cel.common.ast.CelExpr.CelCall;
@@ -29,7 +31,7 @@
final class CelNavigableExprVisitor {
private static final int MAX_DESCENDANTS_RECURSION_DEPTH = 500;

private final Stream.Builder<CelNavigableExpr> streamBuilder;
private final Stream.Builder<CelNavigableExpr.Builder> streamBuilder;
private final TraversalOrder traversalOrder;
private final int maxDepth;

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

visitor.visit(navigableExpr);
visitor.visit(navigableExpr.toBuilder());

return visitor.streamBuilder.build();
return visitor.streamBuilder.build().map(CelNavigableExpr.Builder::build);
}

private void visit(CelNavigableExpr navigableExpr) {
private int visit(CelNavigableExpr.Builder navigableExpr) {
if (navigableExpr.depth() > MAX_DESCENDANTS_RECURSION_DEPTH - 1) {
throw new IllegalStateException("Max recursion depth reached.");
}
if (navigableExpr.depth() > maxDepth) {
return;
return -1;
}
if (traversalOrder.equals(TraversalOrder.PRE_ORDER)) {
streamBuilder.add(navigableExpr);
}

int height = 1;
switch (navigableExpr.getKind()) {
case CALL:
visit(navigableExpr, navigableExpr.expr().call());
height += visit(navigableExpr, navigableExpr.expr().call());
break;
case CREATE_LIST:
visit(navigableExpr, navigableExpr.expr().createList());
height += visit(navigableExpr, navigableExpr.expr().createList());
break;
case SELECT:
visit(navigableExpr, navigableExpr.expr().select());
height += visit(navigableExpr, navigableExpr.expr().select());
break;
case CREATE_STRUCT:
visitStruct(navigableExpr, navigableExpr.expr().createStruct());
height += visitStruct(navigableExpr, navigableExpr.expr().createStruct());
break;
case CREATE_MAP:
visitMap(navigableExpr, navigableExpr.expr().createMap());
height += visitMap(navigableExpr, navigableExpr.expr().createMap());
break;
case COMPREHENSION:
visit(navigableExpr, navigableExpr.expr().comprehension());
height += visit(navigableExpr, navigableExpr.expr().comprehension());
break;
default:
// This is a leaf node
height = 0;
break;
}

navigableExpr.setHeight(height);
if (traversalOrder.equals(TraversalOrder.POST_ORDER)) {
streamBuilder.add(navigableExpr);
}

return height;
}

private void visit(CelNavigableExpr navigableExpr, CelCall call) {
private int visit(CelNavigableExpr.Builder navigableExpr, CelCall call) {
int targetHeight = 0;
if (call.target().isPresent()) {
CelNavigableExpr target = newNavigableChild(navigableExpr, call.target().get());
visit(target);
CelNavigableExpr.Builder target = newNavigableChild(navigableExpr, call.target().get());
targetHeight = visit(target);
}

visitExprList(call.args(), navigableExpr);
int argumentHeight = visitExprList(call.args(), navigableExpr);
return max(targetHeight, argumentHeight);
}

private void visit(CelNavigableExpr navigableExpr, CelCreateList createList) {
visitExprList(createList.elements(), navigableExpr);
private int visit(CelNavigableExpr.Builder navigableExpr, CelCreateList createList) {
return visitExprList(createList.elements(), navigableExpr);
}

private void visit(CelNavigableExpr navigableExpr, CelSelect selectExpr) {
CelNavigableExpr operand = newNavigableChild(navigableExpr, selectExpr.operand());
visit(operand);
private int visit(CelNavigableExpr.Builder navigableExpr, CelSelect selectExpr) {
CelNavigableExpr.Builder operand = newNavigableChild(navigableExpr, selectExpr.operand());
return visit(operand);
}

private void visit(CelNavigableExpr navigableExpr, CelComprehension comprehension) {
visit(newNavigableChild(navigableExpr, comprehension.iterRange()));
visit(newNavigableChild(navigableExpr, comprehension.accuInit()));
visit(newNavigableChild(navigableExpr, comprehension.loopCondition()));
visit(newNavigableChild(navigableExpr, comprehension.loopStep()));
visit(newNavigableChild(navigableExpr, comprehension.result()));
private int visit(CelNavigableExpr.Builder navigableExpr, CelComprehension comprehension) {
int maxHeight = 0;
maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.iterRange())), maxHeight);
maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.accuInit())), maxHeight);
maxHeight =
max(visit(newNavigableChild(navigableExpr, comprehension.loopCondition())), maxHeight);
maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.loopStep())), maxHeight);
maxHeight = max(visit(newNavigableChild(navigableExpr, comprehension.result())), maxHeight);

return maxHeight;
}

private void visitStruct(CelNavigableExpr navigableExpr, CelCreateStruct struct) {
private int visitStruct(CelNavigableExpr.Builder navigableExpr, CelCreateStruct struct) {
int maxHeight = 0;
for (CelCreateStruct.Entry entry : struct.entries()) {
CelNavigableExpr value = newNavigableChild(navigableExpr, entry.value());
visit(value);
CelNavigableExpr.Builder value = newNavigableChild(navigableExpr, entry.value());
maxHeight = max(visit(value), maxHeight);
}
return maxHeight;
}

private void visitMap(CelNavigableExpr navigableExpr, CelCreateMap map) {
private int visitMap(CelNavigableExpr.Builder navigableExpr, CelCreateMap map) {
int maxHeight = 0;
for (CelCreateMap.Entry entry : map.entries()) {
CelNavigableExpr key = newNavigableChild(navigableExpr, entry.key());
visit(key);
CelNavigableExpr.Builder key = newNavigableChild(navigableExpr, entry.key());
maxHeight = max(visit(key), maxHeight);

CelNavigableExpr value = newNavigableChild(navigableExpr, entry.value());
visit(value);
CelNavigableExpr.Builder value = newNavigableChild(navigableExpr, entry.value());
maxHeight = max(visit(value), maxHeight);
}
return 0;
}

private void visitExprList(ImmutableList<CelExpr> createListExpr, CelNavigableExpr parent) {
private int visitExprList(
ImmutableList<CelExpr> createListExpr, CelNavigableExpr.Builder parent) {
int maxHeight = 0;
for (CelExpr expr : createListExpr) {
CelNavigableExpr arg = newNavigableChild(parent, expr);
visit(arg);
CelNavigableExpr.Builder arg = newNavigableChild(parent, expr);
maxHeight = max(visit(arg), maxHeight);
}
return maxHeight;
}

private CelNavigableExpr newNavigableChild(CelNavigableExpr parent, CelExpr expr) {
private CelNavigableExpr.Builder newNavigableChild(
CelNavigableExpr.Builder parent, CelExpr expr) {
return CelNavigableExpr.builder()
.setExpr(expr)
.setDepth(parent.depth() + 1)
.setParent(parent)
.build();
.setParentBuilder(parent);
}
}
Loading

0 comments on commit f98b582

Please sign in to comment.