Skip to content

Commit

Permalink
Add an adapter for legacy runtime to consume CelValueProvider. Add in…
Browse files Browse the repository at this point in the history
…terpreter test for CelValues.

PiperOrigin-RevId: 589918511
  • Loading branch information
l46kok authored and copybara-github committed Dec 11, 2023
1 parent 5477ae5 commit 0b27999
Show file tree
Hide file tree
Showing 22 changed files with 513 additions and 42 deletions.
38 changes: 38 additions & 0 deletions bundle/src/test/java/dev/cel/bundle/CelImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,24 @@ public void program_withVars() throws Exception {
assertThat(program.eval(ImmutableMap.of("variable", "hello"))).isEqualTo(true);
}

@Test
public void program_withCelValue() throws Exception {
Cel cel =
standardCelBuilderWithMacros()
.setOptions(CelOptions.current().enableCelValue(true).build())
.addDeclarations(
Decl.newBuilder()
.setName("variable")
.setIdent(IdentDecl.newBuilder().setType(CelTypes.STRING))
.build())
.setResultType(SimpleType.BOOL)
.build();

CelRuntime.Program program = cel.createProgram(cel.compile("variable == 'hello'").getAst());

assertThat(program.eval(ImmutableMap.of("variable", "hello"))).isEqualTo(true);
}

@Test
public void program_withProtoVars() throws Exception {
Cel cel =
Expand Down Expand Up @@ -1285,6 +1303,26 @@ public void programAdvanceEvaluation_nestedSelect() throws Exception {
.isEqualTo(CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("com.google.a")));
}

@Test
public void programAdvanceEvaluation_nestedSelect_withCelValue() throws Exception {
Cel cel =
standardCelBuilderWithMacros()
.setOptions(
CelOptions.current().enableUnknownTracking(true).enableCelValue(true).build())
.addVar("com", MapType.create(SimpleType.STRING, SimpleType.DYN))
.addFunctionBindings()
.setResultType(SimpleType.BOOL)
.build();
CelRuntime.Program program = cel.createProgram(cel.compile("com.google.a || false").getAst());

assertThat(
program.advanceEvaluation(
UnknownContext.create(
fromMap(ImmutableMap.of()),
ImmutableList.of(CelAttributePattern.fromQualifiedIdentifier("com.google.a")))))
.isEqualTo(CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("com.google.a")));
}

@Test
public void programAdvanceEvaluation_argumentMergeErrorPriority() throws Exception {
Cel cel =
Expand Down
12 changes: 12 additions & 0 deletions common/src/main/java/dev/cel/common/CelOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ public abstract class CelOptions {

public abstract boolean enableUnknownTracking();

public abstract boolean enableCelValue();

public abstract int comprehensionMaxIterations();

public abstract Builder toBuilder();
Expand Down Expand Up @@ -176,6 +178,7 @@ public static Builder newBuilder() {
.errorOnDuplicateMapKeys(false)
.resolveTypeDependencies(true)
.enableUnknownTracking(false)
.enableCelValue(false)
.comprehensionMaxIterations(-1);
}

Expand Down Expand Up @@ -428,6 +431,15 @@ public abstract static class Builder {
*/
public abstract Builder enableUnknownTracking(boolean value);

/**
* Enables the usage of {@code CelValue} for the runtime. It is a native value representation of
* CEL that wraps Java native objects, and comes with extended capabilities, such as allowing
* value constructs not understood by CEL (ex: POJOs).
*
* <p>Warning: This option is experimental.
*/
public abstract Builder enableCelValue(boolean value);

/**
* Limit the total number of iterations permitted within comprehension loops.
*
Expand Down
12 changes: 10 additions & 2 deletions common/src/main/java/dev/cel/common/types/TypeType.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
@Immutable
public abstract class TypeType extends CelType {

static final TypeType TYPE = create(SimpleType.DYN);

@Override
public CelKind kind() {
return CelKind.TYPE;
Expand All @@ -38,6 +36,16 @@ public String name() {
return "type";
}

/** Retrieves the underlying type name of the type-kind held. */
public String containingTypeName() {
CelType containingType = type();
if (containingType.kind() == CelKind.DYN) {
return "type";
}

return containingType.name();
}

@Override
public abstract ImmutableList<CelType> parameters();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public interface CelValueProvider {
final class CombinedCelValueProvider implements CelValueProvider {
private final ImmutableList<CelValueProvider> celValueProviders;

CombinedCelValueProvider(CelValueProvider first, CelValueProvider second) {
public CombinedCelValueProvider(CelValueProvider first, CelValueProvider second) {
Preconditions.checkNotNull(first);
Preconditions.checkNotNull(second);
celValueProviders = ImmutableList.of(first, second);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public void get_nonExistentKey_throws() {

CelRuntimeException exception =
assertThrows(CelRuntimeException.class, () -> mapValue.get(IntValue.create(100L)));
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
assertThat(exception).hasMessageThat().contains("key '100' is not present in map.");
}

Expand Down
6 changes: 6 additions & 0 deletions runtime/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,9 @@ java_library(
name = "evaluation_listener",
exports = ["//runtime/src/main/java/dev/cel/runtime:evaluation_listener"],
)

java_library(
name = "runtime_type_provider_legacy",
visibility = ["//visibility:public"],
exports = ["//runtime/src/main/java/dev/cel/runtime:runtime_type_provider_legacy"],
)
29 changes: 27 additions & 2 deletions runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,8 @@ java_library(
tags = [
],
deps = [
":base",
":evaluation_listener",
":interpreter",
":runtime_type_provider_legacy",
":unknown_attributes",
"//:auto_value",
"//common",
Expand All @@ -161,6 +160,9 @@ java_library(
"//common/internal:dynamic_proto",
"//common/internal:proto_message_factory",
"//common/types:cel_types",
"//common/values:cel_value_provider",
"//common/values:proto_message_value_provider",
"//runtime:interpreter",
"@maven//:com_google_code_findbugs_annotations",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand Down Expand Up @@ -212,6 +214,29 @@ java_library(
],
)

java_library(
name = "runtime_type_provider_legacy",
srcs = ["RuntimeTypeProviderLegacyImpl.java"],
deps = [
":unknown_attributes",
"//common:options",
"//common/annotations",
"//common/internal:cel_descriptor_pools",
"//common/internal:dynamic_proto",
"//common/types",
"//common/types:type_providers",
"//common/values",
"//common/values:cel_value",
"//common/values:cel_value_provider",
"//common/values:proto_message_value",
"//runtime:interpreter",
"@cel_spec//proto/cel/expr:expr_java_proto",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
"@maven//:org_jspecify_jspecify",
],
)

java_library(
name = "interpreter_util",
srcs = ["InterpreterUtil.java"],
Expand Down
5 changes: 5 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.Message;
import dev.cel.common.CelOptions;
import dev.cel.common.values.CelValueProvider;
import java.util.function.Function;

/** Interface for building an instance of CelRuntime */
Expand Down Expand Up @@ -138,6 +139,10 @@ public interface CelRuntimeBuilder {
@CanIgnoreReturnValue
CelRuntimeBuilder setTypeFactory(Function<String, Message.Builder> typeFactory);

/** Sets the {@code celValueProvider} for resolving values during evaluation. */
@CanIgnoreReturnValue
CelRuntimeBuilder setValueProvider(CelValueProvider celValueProvider);

/** Enable or disable the standard CEL library functions and variables. */
@CanIgnoreReturnValue
CelRuntimeBuilder setStandardEnvironmentEnabled(boolean value);
Expand Down
49 changes: 36 additions & 13 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
// CEL-Internal-3
import dev.cel.common.internal.ProtoMessageFactory;
import dev.cel.common.types.CelTypes;
import dev.cel.common.values.CelValueProvider;
import dev.cel.common.values.ProtoMessageValueProvider;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Function;
Expand Down Expand Up @@ -82,6 +84,7 @@ public static final class Builder implements CelRuntimeBuilder {
private boolean standardEnvironmentEnabled;
private Function<String, Message.Builder> customTypeFactory;
private ExtensionRegistry extensionRegistry;
private CelValueProvider celValueProvider;

@Override
@CanIgnoreReturnValue
Expand Down Expand Up @@ -142,6 +145,13 @@ public Builder setTypeFactory(Function<String, Message.Builder> typeFactory) {
return this;
}

@Override
@CanIgnoreReturnValue
public CelRuntimeBuilder setValueProvider(CelValueProvider celValueProvider) {
this.celValueProvider = celValueProvider;
return this;
}

@Override
@CanIgnoreReturnValue
public Builder setStandardEnvironmentEnabled(boolean value) {
Expand Down Expand Up @@ -179,11 +189,14 @@ public CelRuntimeLegacyImpl build() {
// Add libraries, such as extensions
celRuntimeLibraries.build().forEach(celLibrary -> celLibrary.setRuntimeOptions(this));

CelDescriptors celDescriptors =
CelDescriptorUtil.getAllDescriptorsFromFileDescriptor(
fileTypes.build(), options.resolveTypeDependencies());

CelDescriptorPool celDescriptorPool =
newDescriptorPool(
fileTypes.build(),
extensionRegistry,
options);
celDescriptors,
extensionRegistry);

@SuppressWarnings("Immutable")
ProtoMessageFactory runtimeTypeFactory =
Expand Down Expand Up @@ -222,20 +235,30 @@ public CelRuntimeLegacyImpl build() {
}
}));

RuntimeTypeProvider runtimeTypeProvider;

if (options.enableCelValue()) {
CelValueProvider messageValueProvider =
ProtoMessageValueProvider.newInstance(dynamicProto, options);
if (celValueProvider != null) {
messageValueProvider =
new CelValueProvider.CombinedCelValueProvider(celValueProvider, messageValueProvider);
}

runtimeTypeProvider =
new RuntimeTypeProviderLegacyImpl(
options, messageValueProvider, celDescriptorPool, dynamicProto);
} else {
runtimeTypeProvider = new DescriptorMessageProvider(runtimeTypeFactory, options);
}

return new CelRuntimeLegacyImpl(
new DefaultInterpreter(
new DescriptorMessageProvider(runtimeTypeFactory, options), dispatcher, options),
options);
new DefaultInterpreter(runtimeTypeProvider, dispatcher, options), options);
}

private static CelDescriptorPool newDescriptorPool(
ImmutableSet<FileDescriptor> fileTypeSet,
ExtensionRegistry extensionRegistry,
CelOptions celOptions) {
CelDescriptors celDescriptors =
CelDescriptorUtil.getAllDescriptorsFromFileDescriptor(
fileTypeSet, celOptions.resolveTypeDependencies());

CelDescriptors celDescriptors,
ExtensionRegistry extensionRegistry) {
ImmutableList.Builder<CelDescriptorPool> descriptorPools = new ImmutableList.Builder<>();

descriptorPools.add(DefaultDescriptorPool.create(celDescriptors, extensionRegistry));
Expand Down
Loading

0 comments on commit 0b27999

Please sign in to comment.