Skip to content

Commit

Permalink
Support folding macros and lists
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 567719306
  • Loading branch information
l46kok authored and copybara-github committed Sep 26, 2023
1 parent 817b335 commit 3833e14
Show file tree
Hide file tree
Showing 27 changed files with 1,510 additions and 260 deletions.
9 changes: 8 additions & 1 deletion common/src/main/java/dev/cel/common/CelSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ private static LineAndOffset findLine(List<Integer> lineOffsets, int offset) {
public Builder toBuilder() {
return new Builder(codePoints, lineOffsets)
.setDescription(description)
.addPositionsMap(positions);
.addPositionsMap(positions)
.addAllMacroCalls(macroCalls);
}

public static Builder newBuilder() {
Expand Down Expand Up @@ -270,6 +271,12 @@ public Builder addAllMacroCalls(Map<Long, CelExpr> macroCalls) {
return this;
}

@CanIgnoreReturnValue
public Builder clearMacroCall(long exprId) {
this.macroCalls.remove(exprId);
return this;
}

/** See {@link #getLocationOffset(int, int)}. */
public Optional<Integer> getLocationOffset(CelSourceLocation location) {
checkNotNull(location);
Expand Down
43 changes: 43 additions & 0 deletions common/src/main/java/dev/cel/common/ast/CelConstant.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import com.google.auto.value.AutoOneOf;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.Immutable;
import com.google.protobuf.ByteString;
Expand All @@ -33,6 +34,16 @@
@Internal
@Immutable
public abstract class CelConstant {
private static final ImmutableSet<Class<?>> CONSTANT_CLASSES =
ImmutableSet.of(
NullValue.class,
Boolean.class,
Long.class,
UnsignedLong.class,
Double.class,
String.class,
ByteString.class);

/** Represents the type of the Constant */
public enum Kind {
NOT_SET,
Expand Down Expand Up @@ -127,6 +138,38 @@ public static CelConstant ofValue(ByteString value) {
return AutoOneOf_CelConstant.bytesValue(value);
}

/** Checks whether the provided Java object is a valid CelConstant value. */
public static boolean isConstantValue(Object value) {
return CONSTANT_CLASSES.contains(value.getClass());
}

/**
* Converts the given Java object into a CelConstant value. This is equivalent of calling {@link
* CelConstant#ofValue} with concrete types.
*
* @throws IllegalArgumentException If the value is not a supported CelConstant. This includes the
* deprecated duration and timestamp values.
*/
public static CelConstant ofObjectValue(Object value) {
if (value instanceof NullValue) {
return ofValue((NullValue) value);
} else if (value instanceof Boolean) {
return ofValue((boolean) value);
} else if (value instanceof Long) {
return ofValue((long) value);
} else if (value instanceof UnsignedLong) {
return ofValue((UnsignedLong) value);
} else if (value instanceof Double) {
return ofValue((double) value);
} else if (value instanceof String) {
return ofValue((String) value);
} else if (value instanceof ByteString) {
return ofValue((ByteString) value);
}

throw new IllegalArgumentException("Value is not a CelConstant: " + value);
}

/**
* @deprecated Do not use. Duration is no longer built-in CEL type.
*/
Expand Down
35 changes: 33 additions & 2 deletions common/src/main/java/dev/cel/common/ast/CelExpr.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package dev.cel.common.ast;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.auto.value.AutoOneOf;
import com.google.auto.value.AutoValue;
Expand Down Expand Up @@ -499,7 +500,8 @@ public abstract static class CelCall {
public abstract static class Builder {
private List<CelExpr> mutableArgs = new ArrayList<>();

public abstract ImmutableList<CelExpr> args();
// Not public. This only exists to make AutoValue.Builder work.
abstract ImmutableList<CelExpr> args();

public abstract Builder setTarget(CelExpr value);

Expand All @@ -512,6 +514,16 @@ public abstract static class Builder {
// Not public. This only exists to make AutoValue.Builder work.
abstract Builder setArgs(ImmutableList<CelExpr> value);

/** Returns an immutable copy of the current mutable arguments present in the builder. */
public ImmutableList<CelExpr> getArgs() {
return ImmutableList.copyOf(mutableArgs);
}

/** Returns an immutable copy of the builders from the current mutable arguments. */
public ImmutableList<CelExpr.Builder> getArgsBuilders() {
return mutableArgs.stream().map(CelExpr::toBuilder).collect(toImmutableList());
}

public Builder setArg(int index, CelExpr arg) {
checkNotNull(arg);
mutableArgs.set(index, arg);
Expand Down Expand Up @@ -599,6 +611,11 @@ public ImmutableList<CelExpr> getElements() {
return ImmutableList.copyOf(mutableElements);
}

/** Returns an immutable copy of the builders from the current mutable elements. */
public ImmutableList<CelExpr.Builder> getElementsBuilders() {
return mutableElements.stream().map(CelExpr::toBuilder).collect(toImmutableList());
}

@CanIgnoreReturnValue
public Builder setElement(int index, CelExpr element) {
checkNotNull(element);
Expand Down Expand Up @@ -691,6 +708,13 @@ public ImmutableList<CelCreateStruct.Entry> getEntries() {
return ImmutableList.copyOf(mutableEntries);
}

/** Returns an immutable copy of the builders from the current mutable entries. */
public ImmutableList<CelCreateStruct.Entry.Builder> getEntriesBuilders() {
return mutableEntries.stream()
.map(CelCreateStruct.Entry::toBuilder)
.collect(toImmutableList());
}

@CanIgnoreReturnValue
public Builder setEntry(int index, CelCreateStruct.Entry entry) {
checkNotNull(entry);
Expand Down Expand Up @@ -814,6 +838,13 @@ public ImmutableList<CelCreateMap.Entry> getEntries() {
return ImmutableList.copyOf(mutableEntries);
}

/** Returns an immutable copy of the builders from the current mutable entries. */
public ImmutableList<CelCreateMap.Entry.Builder> getEntriesBuilders() {
return mutableEntries.stream()
.map(CelCreateMap.Entry::toBuilder)
.collect(toImmutableList());
}

@CanIgnoreReturnValue
public Builder setEntry(int index, CelCreateMap.Entry entry) {
checkNotNull(entry);
Expand Down Expand Up @@ -905,7 +936,7 @@ public abstract static class Builder {
public abstract CelCreateMap.Entry.Builder toBuilder();

public static CelCreateMap.Entry.Builder newBuilder() {
return new AutoValue_CelExpr_CelCreateMap_Entry.Builder().setOptionalEntry(false);
return new AutoValue_CelExpr_CelCreateMap_Entry.Builder().setId(0).setOptionalEntry(false);
}
}
}
Expand Down
38 changes: 4 additions & 34 deletions common/src/main/java/dev/cel/common/ast/CelExprFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,16 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;

import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import com.google.protobuf.ByteString;
import java.util.Arrays;

/** Factory for generating expression nodes. */
public class CelExprFactory {
private final CelExprIdGenerator idGenerator;

/** Builder for configuring {@link CelExprFactory}. */
public static final class Builder {

private CelExprIdGenerator exprIdGenerator;

@CanIgnoreReturnValue
public Builder setIdGenerator(CelExprIdGenerator exprIdGenerator) {
this.exprIdGenerator = exprIdGenerator;
Preconditions.checkNotNull(exprIdGenerator);
return this;
}

@CheckReturnValue
public CelExprFactory build() {
return new CelExprFactory(exprIdGenerator);
}

private Builder() {
exprIdGenerator = CelExprIdGeneratorFactory.newMonotonicIdGenerator(0);
}
}

/** Creates a new builder to configure CelExprFactory. */
public static CelExprFactory.Builder newBuilder() {
return new Builder();
public static CelExprFactory newInstance() {
return new CelExprFactory();
}

/** Create a new constant expression. */
Expand Down Expand Up @@ -569,14 +543,10 @@ public final CelExpr newSelect(CelExpr operand, String field, boolean testOnly)

/** Returns the next unique expression ID. */
protected long nextExprId() {
return idGenerator.nextExprId();
}

protected CelExprFactory(CelExprIdGenerator idGenerator) {
this.idGenerator = idGenerator;
return idGenerator.generate(0);
}

protected CelExprFactory() {
this(CelExprIdGeneratorFactory.newMonotonicIdGenerator(0));
idGenerator = CelExprIdGeneratorFactory.newMonotonicIdGenerator(0);
}
}
10 changes: 3 additions & 7 deletions common/src/main/java/dev/cel/common/ast/CelExprIdGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,10 @@
* renumbering existing expression IDs
*/
public interface CelExprIdGenerator {
/** Returns the next unique expression ID. */
long nextExprId();

/**
* Renumber an existing expression ID, ensuring that new IDs are only created the first time they
* are encountered.
* Generates an expression ID. See {@code CelExprIdGeneratorFactory} for specifications on how an
* ID is generated.
*/
default long renumberId(long id) {
throw new UnsupportedOperationException();
}
long generate(long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,27 @@ public final class CelExprIdGeneratorFactory {
* MonotonicIdGenerator increments expression IDs from an initial seed value.
*
* @param exprId Seed value. Must be non-negative. For example, if 1 is provided {@link
* CelExprIdGenerator#nextExprId} will return 2.
* CelExprIdGenerator#generate} will return 2.
*/
public static CelExprIdGenerator newMonotonicIdGenerator(long exprId) {
return new MonotonicIdGenerator(exprId);
}

/** StableIdGenerator ensures new IDs are only created the first time they are encountered. */
static CelExprIdGenerator newStableIdGenerator(long exprId) {
/**
* StableIdGenerator ensures new IDs are only created the first time they are encountered.
*
* @param exprId Seed value. Must be non-negative. For example, if 1 is provided {@link
* CelExprIdGenerator#generate} will return 2.
*/
public static CelExprIdGenerator newStableIdGenerator(long exprId) {
return new StableIdGenerator(exprId);
}

private static class MonotonicIdGenerator implements CelExprIdGenerator {
private long exprId;

@Override
public long nextExprId() {
public long generate(long id) {
return ++exprId;
}

Expand All @@ -54,12 +59,7 @@ private static class StableIdGenerator implements CelExprIdGenerator {
private long exprId;

@Override
public long nextExprId() {
return ++exprId;
}

@Override
public long renumberId(long id) {
public long generate(long id) {
Preconditions.checkArgument(id >= 0);
if (id == 0) {
return 0;
Expand All @@ -69,7 +69,7 @@ public long renumberId(long id) {
return idSet.get(id);
}

long nextExprId = nextExprId();
long nextExprId = ++exprId;
idSet.put(id, nextExprId);
return nextExprId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
* node's children, descendants or its parent with ease.
*/
public final class CelNavigableAst {

private final CelAbstractSyntaxTree ast;
private final CelNavigableExpr root;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,36 +55,58 @@ public enum TraversalOrder {
/** Represents the count of transitive parents. Depth of an AST's root is 0. */
public abstract int depth();

/** Constructs a new instance of {@link CelNavigableExpr} from {@link CelExpr}. */
public static CelNavigableExpr fromExpr(CelExpr expr) {
return CelNavigableExpr.builder().setExpr(expr).build();
}

/**
* Returns a stream of {@link CelNavigableExpr} collected from the current node down to the last
* leaf-level member using post-order traversal.
*/
public Stream<CelNavigableExpr> descendants() {
return descendants(TraversalOrder.POST_ORDER);
public Stream<CelNavigableExpr> allNodes() {
return allNodes(TraversalOrder.POST_ORDER);
}

/**
* Returns a stream of {@link CelNavigableExpr} collected from the current node down to the last
* leaf-level member using the specified traversal order.
*/
public Stream<CelNavigableExpr> descendants(TraversalOrder traversalOrder) {
public Stream<CelNavigableExpr> allNodes(TraversalOrder traversalOrder) {
return CelNavigableExprVisitor.collect(this, traversalOrder);
}

/**
* Returns a stream of {@link CelNavigableExpr} collected from the current node to its immediate
* children using post-order traversal.
* Returns a stream of {@link CelNavigableExpr} collected down to the last leaf-level member using
* post-order traversal.
*/
public Stream<CelNavigableExpr> descendants() {
return descendants(TraversalOrder.POST_ORDER);
}

/**
* Returns a stream of {@link CelNavigableExpr} collected down to the last leaf-level member using
* the specified traversal order.
*/
public Stream<CelNavigableExpr> descendants(TraversalOrder traversalOrder) {
return CelNavigableExprVisitor.collect(this, traversalOrder).filter(node -> !node.equals(this));
}

/**
* Returns a stream of {@link CelNavigableExpr} collected from its immediate children using
* post-order traversal.
*/
public Stream<CelNavigableExpr> children() {
return children(TraversalOrder.POST_ORDER);
}

/**
* Returns a stream of {@link CelNavigableExpr} collected from the current node to its immediate
* children using the specified traversal order.
* Returns a stream of {@link CelNavigableExpr} collected from its immediate children using the
* specified traversal order.
*/
public Stream<CelNavigableExpr> children(TraversalOrder traversalOrder) {
return CelNavigableExprVisitor.collect(this, 1, traversalOrder);
return CelNavigableExprVisitor.collect(this, this.depth() + 1, traversalOrder)
.filter(node -> !node.equals(this));
}

/** Returns the underlying kind of the {@link CelExpr}. */
Expand All @@ -94,7 +116,7 @@ public ExprKind.Kind getKind() {

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

/** Builder to configure {@link CelNavigableExpr}. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

/** Visitor implementation to navigate an AST. */
final class CelNavigableExprVisitor {

private static final int MAX_DESCENDANTS_RECURSION_DEPTH = 500;

private final Stream.Builder<CelNavigableExpr> streamBuilder;
Expand Down
Loading

0 comments on commit 3833e14

Please sign in to comment.