Skip to content

Commit

Permalink
Add cel.block as an extension library
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 602536654
  • Loading branch information
l46kok authored and copybara-github committed Feb 7, 2024
1 parent 8f51c97 commit 731ce14
Show file tree
Hide file tree
Showing 30 changed files with 854 additions and 68 deletions.
4 changes: 3 additions & 1 deletion bundle/src/main/java/dev/cel/bundle/Cel.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@

/** Cel interface for parse, type-check, and evaluation of CEL programs. */
@ThreadSafe
public interface Cel extends CelCompiler, CelRuntime {}
public interface Cel extends CelCompiler, CelRuntime {
CelBuilder toCelBuilder();
}
7 changes: 6 additions & 1 deletion bundle/src/main/java/dev/cel/bundle/CelFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
import dev.cel.checker.CelCheckerLegacyImpl;
import dev.cel.common.CelOptions;
import dev.cel.compiler.CelCompiler;
import dev.cel.compiler.CelCompilerImpl;
import dev.cel.parser.CelParserImpl;
import dev.cel.runtime.CelRuntime;
import dev.cel.runtime.CelRuntimeLegacyImpl;

/** Helper class to configure the entire CEL stack in a common interface. */
public final class CelFactory {
Expand All @@ -33,7 +35,10 @@ private CelFactory() {}
* evaluation are enabled by default.
*/
public static CelBuilder standardCelBuilder() {
return CelImpl.newBuilder(CelParserImpl.newBuilder(), CelCheckerLegacyImpl.newBuilder())
return CelImpl.newBuilder(
CelCompilerImpl.newBuilder(
CelParserImpl.newBuilder(), CelCheckerLegacyImpl.newBuilder()),
CelRuntimeLegacyImpl.newBuilder())
.setOptions(CelOptions.current().build())
.setStandardEnvironmentEnabled(true);
}
Expand Down
38 changes: 31 additions & 7 deletions bundle/src/main/java/dev/cel/bundle/CelImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,13 @@
import dev.cel.common.values.CelValueProvider;
import dev.cel.compiler.CelCompiler;
import dev.cel.compiler.CelCompilerBuilder;
import dev.cel.compiler.CelCompilerImpl;
import dev.cel.compiler.CelCompilerLibrary;
import dev.cel.parser.CelMacro;
import dev.cel.parser.CelParserBuilder;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.CelRuntime;
import dev.cel.runtime.CelRuntimeBuilder;
import dev.cel.runtime.CelRuntimeLegacyImpl;
import dev.cel.runtime.CelRuntimeLibrary;
import java.util.Arrays;
import java.util.function.Function;
Expand Down Expand Up @@ -102,6 +100,31 @@ public void accept(EnvVisitor envVisitor) {
}
}

@Override
public CelBuilder toCelBuilder() {
return newBuilder(toCompilerBuilder(), toRuntimeBuilder());
}

@Override
public CelParserBuilder toParserBuilder() {
return compiler.get().toParserBuilder();
}

@Override
public CelCheckerBuilder toCheckerBuilder() {
return compiler.get().toCheckerBuilder();
}

@Override
public CelCompilerBuilder toCompilerBuilder() {
return compiler.get().toCompilerBuilder();
}

@Override
public CelRuntimeBuilder toRuntimeBuilder() {
return runtime.get().toRuntimeBuilder();
}

/** Combines a prebuilt {@link CelCompiler} and {@link CelRuntime} into {@link CelImpl}. */
static CelImpl combine(CelCompiler compiler, CelRuntime runtime) {
return new CelImpl(Suppliers.memoize(() -> compiler), Suppliers.memoize(() -> runtime));
Expand All @@ -112,8 +135,9 @@ static CelImpl combine(CelCompiler compiler, CelRuntime runtime) {
*
* <p>By default, {@link CelOptions#DEFAULT} are enabled, as is the CEL standard environment.
*/
static CelBuilder newBuilder(CelParserBuilder parserBuilder, CelCheckerBuilder checkerBuilder) {
return new CelImpl.Builder(parserBuilder, checkerBuilder);
static CelBuilder newBuilder(
CelCompilerBuilder compilerBuilder, CelRuntimeBuilder celRuntimeBuilder) {
return new CelImpl.Builder(compilerBuilder, celRuntimeBuilder);
}

/** Builder class for CelImpl instances. */
Expand All @@ -122,9 +146,9 @@ public static final class Builder implements CelBuilder {
private final CelCompilerBuilder compilerBuilder;
private final CelRuntimeBuilder runtimeBuilder;

private Builder(CelParserBuilder parserBuilder, CelCheckerBuilder checkerBuilder) {
this.compilerBuilder = CelCompilerImpl.newBuilder(parserBuilder, checkerBuilder);
this.runtimeBuilder = CelRuntimeLegacyImpl.newBuilder();
private Builder(CelCompilerBuilder celCompilerBuilder, CelRuntimeBuilder celRuntimeBuilder) {
this.compilerBuilder = celCompilerBuilder;
this.runtimeBuilder = celRuntimeBuilder;
}

@Override
Expand Down
2 changes: 2 additions & 0 deletions bundle/src/test/java/dev/cel/bundle/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ java_library(
"//:auto_value",
"//:java_truth",
"//bundle:cel",
"//checker",
"//checker:checker_legacy_environment",
"//checker:proto_type_mask",
"//common",
Expand All @@ -31,6 +32,7 @@ java_library(
"//common/types:type_providers",
"//compiler",
"//compiler:compiler_builder",
"//parser",
"//parser:macro",
"//runtime",
"//runtime:unknown_attributes",
Expand Down
25 changes: 25 additions & 0 deletions bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import com.google.testing.junit.testparameterinjector.TestParameter;
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import com.google.testing.junit.testparameterinjector.TestParameters;
import dev.cel.checker.CelCheckerLegacyImpl;
import dev.cel.checker.DescriptorTypeProvider;
import dev.cel.checker.ProtoTypeMask;
import dev.cel.checker.TypeProvider;
Expand Down Expand Up @@ -77,6 +78,8 @@
import dev.cel.common.types.StructTypeReference;
import dev.cel.compiler.CelCompiler;
import dev.cel.compiler.CelCompilerFactory;
import dev.cel.compiler.CelCompilerImpl;
import dev.cel.parser.CelParserImpl;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelAttribute;
import dev.cel.runtime.CelAttribute.Qualifier;
Expand All @@ -86,6 +89,7 @@
import dev.cel.runtime.CelRuntime.CelFunctionBinding;
import dev.cel.runtime.CelRuntime.Program;
import dev.cel.runtime.CelRuntimeFactory;
import dev.cel.runtime.CelRuntimeLegacyImpl;
import dev.cel.runtime.CelUnknownSet;
import dev.cel.runtime.CelVariableResolver;
import dev.cel.runtime.UnknownContext;
Expand Down Expand Up @@ -1812,6 +1816,27 @@ public boolean isAssignableFrom(CelType other) {
assertThat(result).isEqualTo("5");
}

@Test
public void toBuilder_isImmutable() {
CelBuilder celBuilder = CelFactory.standardCelBuilder();
CelImpl celImpl = (CelImpl) celBuilder.build();

CelImpl.Builder newCelBuilder = (CelImpl.Builder) celImpl.toCelBuilder();
CelParserImpl.Builder newParserBuilder = (CelParserImpl.Builder) celImpl.toParserBuilder();
CelCheckerLegacyImpl.Builder newCheckerBuilder =
(CelCheckerLegacyImpl.Builder) celImpl.toCheckerBuilder();
CelCompilerImpl.Builder newCompilerBuilder =
(CelCompilerImpl.Builder) celImpl.toCompilerBuilder();
CelRuntimeLegacyImpl.Builder newRuntimeBuilder =
(CelRuntimeLegacyImpl.Builder) celImpl.toRuntimeBuilder();

assertThat(newCelBuilder).isNotEqualTo(celBuilder);
assertThat(newParserBuilder).isNotEqualTo(celImpl.toParserBuilder());
assertThat(newCheckerBuilder).isNotEqualTo(celImpl.toCheckerBuilder());
assertThat(newCompilerBuilder).isNotEqualTo(celImpl.toCompilerBuilder());
assertThat(newRuntimeBuilder).isNotEqualTo(celImpl.toRuntimeBuilder());
}

private static TypeProvider aliasingProvider(ImmutableMap<String, Type> typeAliases) {
return new TypeProvider() {
@Override
Expand Down
2 changes: 2 additions & 0 deletions checker/src/main/java/dev/cel/checker/CelChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ public interface CelChecker {
* <p>Check validates the type-agreement of the parsed {@code CelAbstractSyntaxTree}.
*/
CelValidationResult check(CelAbstractSyntaxTree ast);

CelCheckerBuilder toCheckerBuilder();
}
99 changes: 84 additions & 15 deletions checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import dev.cel.expr.Decl;
import dev.cel.expr.Type;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
Expand Down Expand Up @@ -62,15 +63,19 @@ public final class CelCheckerLegacyImpl implements CelChecker, EnvVisitable {

private final CelOptions celOptions;
private final String container;
private final ImmutableList<CelIdentDecl> identDeclarations;
private final ImmutableList<CelFunctionDecl> functionDeclarations;
private final ImmutableSet<CelIdentDecl> identDeclarations;
private final ImmutableSet<CelFunctionDecl> functionDeclarations;
private final Optional<CelType> expectedResultType;

@SuppressWarnings("Immutable")
private final TypeProvider typeProvider;

private final boolean standardEnvironmentEnabled;

// Builder is mutable by design. APIs must make defensive copies in and out of this class.
@SuppressWarnings("Immutable")
private final Builder checkerBuilder;

@Override
public CelValidationResult check(CelAbstractSyntaxTree ast) {
CelSource source = ast.getSource();
Expand All @@ -88,6 +93,11 @@ public CelValidationResult check(CelAbstractSyntaxTree ast) {
return new CelValidationResult(checkedAst, ImmutableList.of());
}

@Override
public CelCheckerBuilder toCheckerBuilder() {
return new Builder(checkerBuilder);
}

@Override
public void accept(EnvVisitor envVisitor) {
Errors errors = new Errors("", "");
Expand Down Expand Up @@ -132,9 +142,9 @@ public static CelCheckerBuilder newBuilder() {
/** Builder class for the legacy {@code CelChecker} implementation. */
public static final class Builder implements CelCheckerBuilder {

private final ImmutableList.Builder<CelIdentDecl> identDeclarations;
private final ImmutableList.Builder<CelFunctionDecl> functionDeclarations;
private final ImmutableList.Builder<ProtoTypeMask> protoTypeMasks;
private final ImmutableSet.Builder<CelIdentDecl> identDeclarations;
private final ImmutableSet.Builder<CelFunctionDecl> functionDeclarations;
private final ImmutableSet.Builder<ProtoTypeMask> protoTypeMasks;
private final ImmutableSet.Builder<Descriptor> messageTypes;
private final ImmutableSet.Builder<FileDescriptor> fileTypes;
private final ImmutableSet.Builder<CelCheckerLibrary> celCheckerLibraries;
Expand Down Expand Up @@ -316,6 +326,38 @@ public CelCheckerBuilder addLibraries(Iterable<? extends CelCheckerLibrary> libr
return this;
}

// The following getters exist for asserting immutability for collections held by this builder,
// and shouldn't be exposed to the public.
@VisibleForTesting
ImmutableSet.Builder<CelFunctionDecl> getFunctionDecls() {
return this.functionDeclarations;
}

@VisibleForTesting
ImmutableSet.Builder<CelIdentDecl> getIdentDecls() {
return this.identDeclarations;
}

@VisibleForTesting
ImmutableSet.Builder<ProtoTypeMask> getProtoTypeMasks() {
return this.protoTypeMasks;
}

@VisibleForTesting
ImmutableSet.Builder<Descriptor> getMessageTypes() {
return this.messageTypes;
}

@VisibleForTesting
ImmutableSet.Builder<FileDescriptor> getFileTypes() {
return this.fileTypes;
}

@VisibleForTesting
ImmutableSet.Builder<CelCheckerLibrary> getCheckerLibraries() {
return this.celCheckerLibraries;
}

@Override
@CheckReturnValue
public CelCheckerLegacyImpl build() {
Expand Down Expand Up @@ -348,13 +390,13 @@ public CelCheckerLegacyImpl build() {
// Configure the declaration set, and possibly alter the type provider if ProtoDecl values
// are provided as they may prevent the use of certain field selection patterns against the
// proto.
ImmutableList<CelIdentDecl> identDeclarationSet = identDeclarations.build();
ImmutableList<ProtoTypeMask> protoTypeMaskSet = protoTypeMasks.build();
ImmutableSet<CelIdentDecl> identDeclarationSet = identDeclarations.build();
ImmutableSet<ProtoTypeMask> protoTypeMaskSet = protoTypeMasks.build();
if (!protoTypeMaskSet.isEmpty()) {
ProtoTypeMaskTypeProvider protoTypeMaskTypeProvider =
new ProtoTypeMaskTypeProvider(messageTypeProvider, protoTypeMaskSet);
identDeclarationSet =
ImmutableList.<CelIdentDecl>builder()
ImmutableSet.<CelIdentDecl>builder()
.addAll(identDeclarationSet)
.addAll(protoTypeMaskTypeProvider.computeDeclsFromProtoTypeMasks())
.build();
Expand All @@ -375,36 +417,63 @@ public CelCheckerLegacyImpl build() {
functionDeclarations.build(),
Optional.fromNullable(expectedResultType),
legacyProvider,
standardEnvironmentEnabled);
standardEnvironmentEnabled,
this);
}

private Builder() {
this.celOptions = CelOptions.newBuilder().build();
this.identDeclarations = ImmutableList.builder();
this.functionDeclarations = ImmutableList.builder();
this.identDeclarations = ImmutableSet.builder();
this.functionDeclarations = ImmutableSet.builder();
this.fileTypes = ImmutableSet.builder();
this.messageTypes = ImmutableSet.builder();
this.protoTypeMasks = ImmutableList.builder();
this.protoTypeMasks = ImmutableSet.builder();
this.celCheckerLibraries = ImmutableSet.builder();
this.container = "";
}

private Builder(Builder builder) {
// The following properties are either immutable or simple primitives, thus can be assigned
// directly.
this.celOptions = builder.celOptions;
this.celTypeProvider = builder.celTypeProvider;
this.container = builder.container;
this.customTypeProvider = builder.customTypeProvider;
this.expectedResultType = builder.expectedResultType;
this.standardEnvironmentEnabled = builder.standardEnvironmentEnabled;
// The following needs to be deep copied as they are collection builders
this.functionDeclarations = deepCopy(builder.functionDeclarations);
this.identDeclarations = deepCopy(builder.identDeclarations);
this.fileTypes = deepCopy(builder.fileTypes);
this.messageTypes = deepCopy(builder.messageTypes);
this.protoTypeMasks = deepCopy(builder.protoTypeMasks);
this.celCheckerLibraries = deepCopy(builder.celCheckerLibraries);
}

private static <T> ImmutableSet.Builder<T> deepCopy(ImmutableSet.Builder<T> builderToCopy) {
ImmutableSet.Builder<T> newBuilder = ImmutableSet.builder();
newBuilder.addAll(builderToCopy.build());
return newBuilder;
}
}

private CelCheckerLegacyImpl(
CelOptions celOptions,
String container,
ImmutableList<CelIdentDecl> identDeclarations,
ImmutableList<CelFunctionDecl> functionDeclarations,
ImmutableSet<CelIdentDecl> identDeclarations,
ImmutableSet<CelFunctionDecl> functionDeclarations,
Optional<CelType> expectedResultType,
TypeProvider typeProvider,
boolean standardEnvironmentEnabled) {
boolean standardEnvironmentEnabled,
Builder checkerBuilder) {
this.celOptions = celOptions;
this.container = container;
this.identDeclarations = identDeclarations;
this.functionDeclarations = functionDeclarations;
this.expectedResultType = expectedResultType;
this.typeProvider = typeProvider;
this.standardEnvironmentEnabled = standardEnvironmentEnabled;
this.checkerBuilder = new Builder(checkerBuilder);
}

private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
Expand Down
4 changes: 2 additions & 2 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line number Diff line number Diff line change
Expand Up @@ -958,15 +958,15 @@ private static CelFunctionDecl sanitizeFunction(CelFunctionDecl func) {
}

CelFunctionDecl.Builder funcBuilder = func.toBuilder();
ImmutableList.Builder<CelOverloadDecl> overloadsBuilder = new ImmutableList.Builder<>();
ImmutableSet.Builder<CelOverloadDecl> overloadsBuilder = new ImmutableSet.Builder<>();
for (CelOverloadDecl overloadDecl : funcBuilder.overloads()) {
CelOverloadDecl.Builder overloadBuilder = overloadDecl.toBuilder();
CelType resultType = overloadBuilder.build().resultType();
if (isWellKnownType(resultType)) {
overloadBuilder.setResultType(getWellKnownType(resultType));
}

ImmutableList.Builder<CelType> parameterTypeBuilder = ImmutableList.builder();
ImmutableSet.Builder<CelType> parameterTypeBuilder = ImmutableSet.builder();
for (CelType paramType : overloadBuilder.parameterTypes()) {
if (isWellKnownType(paramType)) {
parameterTypeBuilder.add(getWellKnownType(paramType));
Expand Down
Loading

0 comments on commit 731ce14

Please sign in to comment.