diff --git a/bundle/src/main/java/dev/cel/bundle/CelBuilder.java b/bundle/src/main/java/dev/cel/bundle/CelBuilder.java index 1dadaeb39..9c0b5d3b2 100644 --- a/bundle/src/main/java/dev/cel/bundle/CelBuilder.java +++ b/bundle/src/main/java/dev/cel/bundle/CelBuilder.java @@ -197,8 +197,7 @@ public interface CelBuilder { * provider will be used first before falling back to the built-in {@link * dev.cel.common.values.ProtoMessageValueProvider} for resolving protobuf messages. * - *

Note that {@link CelOptions#enableCelValue()} must be enabled or this method will be a - * no-op. + *

Note that this option is only supported for planner-based runtime. */ @CanIgnoreReturnValue CelBuilder setValueProvider(CelValueProvider celValueProvider); diff --git a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java index 00b47494d..2154b8eb0 100644 --- a/bundle/src/test/java/dev/cel/bundle/CelImplTest.java +++ b/bundle/src/test/java/dev/cel/bundle/CelImplTest.java @@ -556,24 +556,6 @@ 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(CelProtoTypes.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 = @@ -1419,26 +1401,6 @@ 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 = diff --git a/common/BUILD.bazel b/common/BUILD.bazel index 815d8a1da..ef3cd70f8 100644 --- a/common/BUILD.bazel +++ b/common/BUILD.bazel @@ -22,6 +22,11 @@ java_library( exports = ["//common/src/main/java/dev/cel/common:container"], ) +cel_android_library( + name = "container_android", + exports = ["//common/src/main/java/dev/cel/common:container_android"], +) + java_library( name = "proto_ast", exports = ["//common/src/main/java/dev/cel/common:proto_ast"], @@ -126,3 +131,8 @@ java_library( name = "operator", exports = ["//common/src/main/java/dev/cel/common:operator"], ) + +cel_android_library( + name = "operator_android", + exports = ["//common/src/main/java/dev/cel/common:operator_android"], +) diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel index a5fffe049..54b37bf09 100644 --- a/common/src/main/java/dev/cel/common/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/BUILD.bazel @@ -353,6 +353,18 @@ java_library( ], ) +cel_android_library( + name = "container_android", + srcs = ["CelContainer.java"], + tags = [ + ], + deps = [ + "//:auto_value", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "operator", srcs = ["Operator.java"], @@ -360,3 +372,11 @@ java_library( ], deps = ["@maven//:com_google_guava_guava"], ) + +cel_android_library( + name = "operator_android", + srcs = ["Operator.java"], + tags = [ + ], + deps = ["@maven_android//:com_google_guava_guava"], +) diff --git a/common/src/main/java/dev/cel/common/CelOptions.java b/common/src/main/java/dev/cel/common/CelOptions.java index d39d53803..50db7026c 100644 --- a/common/src/main/java/dev/cel/common/CelOptions.java +++ b/common/src/main/java/dev/cel/common/CelOptions.java @@ -17,7 +17,6 @@ import com.google.auto.value.AutoValue; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; -import dev.cel.common.annotations.Beta; /** * Options to configure how the CEL parser, type-checker, and evaluator behave. @@ -105,8 +104,6 @@ public enum ProtoUnsetFieldOptions { public abstract boolean enableUnknownTracking(); - public abstract boolean enableCelValue(); - public abstract int comprehensionMaxIterations(); public abstract boolean evaluateCanonicalTypesToNativeValues(); @@ -162,7 +159,6 @@ public static Builder newBuilder() { .errorOnDuplicateMapKeys(false) .resolveTypeDependencies(true) .enableUnknownTracking(false) - .enableCelValue(false) .comprehensionMaxIterations(-1) .unwrapWellKnownTypesOnFunctionDispatch(true) .fromProtoUnsetFieldOption(ProtoUnsetFieldOptions.BIND_DEFAULT) @@ -432,16 +428,6 @@ 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). - * - *

Warning: This option is experimental. - */ - @Beta - public abstract Builder enableCelValue(boolean value); - /** * Limit the total number of iterations permitted within comprehension loops. * diff --git a/common/src/main/java/dev/cel/common/types/BUILD.bazel b/common/src/main/java/dev/cel/common/types/BUILD.bazel index a35a897b8..b079b9612 100644 --- a/common/src/main/java/dev/cel/common/types/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/types/BUILD.bazel @@ -183,6 +183,32 @@ java_library( ], ) +java_library( + name = "message_lite_type_provider", + srcs = [ + "ProtoMessageLiteTypeProvider.java", + ], + tags = [ + ], + deps = [ + "//common/types", + "//common/types:type_providers", + "//protobuf:cel_lite_descriptor", + "@maven//:com_google_guava_guava", + ], +) + +cel_android_library( + name = "message_lite_type_provider_android", + srcs = [ + "ProtoMessageLiteTypeProvider.java", + ], + tags = [ + ], + deps = [ + ], +) + java_library( name = "default_type_provider", srcs = [ @@ -197,6 +223,20 @@ java_library( ], ) +cel_android_library( + name = "default_type_provider_android", + srcs = [ + "DefaultTypeProvider.java", + ], + tags = [ + ], + deps = [ + "//common/types:type_providers_android", + "//common/types:types_android", + "@maven_android//:com_google_guava_guava", + ], +) + cel_android_library( name = "cel_types_android", srcs = ["CelTypes.java"], diff --git a/common/src/main/java/dev/cel/common/types/DefaultTypeProvider.java b/common/src/main/java/dev/cel/common/types/DefaultTypeProvider.java index 84e6c9ede..f72191e4e 100644 --- a/common/src/main/java/dev/cel/common/types/DefaultTypeProvider.java +++ b/common/src/main/java/dev/cel/common/types/DefaultTypeProvider.java @@ -16,9 +16,11 @@ import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableMap; +import com.google.errorprone.annotations.Immutable; import java.util.Optional; /** {@code DefaultTypeProvider} is a registry of common CEL types. */ +@Immutable public class DefaultTypeProvider implements CelTypeProvider { private static final DefaultTypeProvider INSTANCE = new DefaultTypeProvider(); diff --git a/common/src/main/java/dev/cel/common/types/ProtoMessageLiteTypeProvider.java b/common/src/main/java/dev/cel/common/types/ProtoMessageLiteTypeProvider.java new file mode 100644 index 000000000..29c102782 --- /dev/null +++ b/common/src/main/java/dev/cel/common/types/ProtoMessageLiteTypeProvider.java @@ -0,0 +1,120 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dev.cel.common.types; + +import static com.google.common.collect.ImmutableMap.toImmutableMap; + +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import dev.cel.protobuf.CelLiteDescriptor; +import dev.cel.protobuf.CelLiteDescriptor.FieldLiteDescriptor; +import dev.cel.protobuf.CelLiteDescriptor.MessageLiteDescriptor; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; + +/** TODO */ +public final class ProtoMessageLiteTypeProvider implements CelTypeProvider { + private static final ImmutableMap PROTO_TYPE_TO_CEL_TYPE = + ImmutableMap.builder() + .put(FieldLiteDescriptor.Type.DOUBLE, SimpleType.DOUBLE) + .put(FieldLiteDescriptor.Type.FLOAT, SimpleType.DOUBLE) + .put(FieldLiteDescriptor.Type.INT64, SimpleType.INT) + .put(FieldLiteDescriptor.Type.INT32, SimpleType.INT) + .put(FieldLiteDescriptor.Type.SFIXED32, SimpleType.INT) + .put(FieldLiteDescriptor.Type.SFIXED64, SimpleType.INT) + .put(FieldLiteDescriptor.Type.SINT32, SimpleType.INT) + .put(FieldLiteDescriptor.Type.SINT64, SimpleType.INT) + .put(FieldLiteDescriptor.Type.BOOL, SimpleType.BOOL) + .put(FieldLiteDescriptor.Type.STRING, SimpleType.STRING) + .put(FieldLiteDescriptor.Type.BYTES, SimpleType.BYTES) + .put(FieldLiteDescriptor.Type.FIXED32, SimpleType.UINT) + .put(FieldLiteDescriptor.Type.FIXED64, SimpleType.UINT) + .put(FieldLiteDescriptor.Type.UINT32, SimpleType.UINT) + .put(FieldLiteDescriptor.Type.UINT64, SimpleType.UINT) + .buildOrThrow(); + + private final ImmutableMap allTypes; + + @Override + public ImmutableCollection types() { + return allTypes.values(); + } + + @Override + public Optional findType(String typeName) { + return Optional.empty(); + } + + public static ProtoMessageLiteTypeProvider newInstance(CelLiteDescriptor... celLiteDescriptors) { + return newInstance(ImmutableSet.copyOf(celLiteDescriptors)); + } + + public static ProtoMessageLiteTypeProvider newInstance( + Set celLiteDescriptors) { + return new ProtoMessageLiteTypeProvider(celLiteDescriptors); + } + + private ProtoMessageLiteTypeProvider(Set celLiteDescriptors) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (CelLiteDescriptor descriptor : celLiteDescriptors) { + for (Entry entry : + descriptor.getProtoTypeNamesToDescriptors().entrySet()) { + builder.put(entry.getKey(), createMessageType(entry.getValue())); + } + } + + this.allTypes = builder.buildOrThrow(); + } + + private static ProtoMessageType createMessageType(MessageLiteDescriptor messageLiteDescriptor) { + ImmutableMap fields = + messageLiteDescriptor.getFieldDescriptors().stream() + .collect(toImmutableMap(FieldLiteDescriptor::getFieldName, Function.identity())); + + return new ProtoMessageType( + messageLiteDescriptor.getProtoTypeName(), + fields.keySet(), + new FieldResolver(fields), + extensionFieldName -> { + throw new UnsupportedOperationException( + "Proto extensions are not yet supported in MessageLite."); + }); + } + + private static class FieldResolver implements StructType.FieldResolver { + private final ImmutableMap fields; + + @Override + public Optional findField(String fieldName) { + FieldLiteDescriptor fieldDescriptor = fields.get(fieldName); + if (fieldDescriptor == null) { + return Optional.empty(); + } + + FieldLiteDescriptor.Type fieldType = fieldDescriptor.getProtoFieldType(); + switch (fieldDescriptor.getProtoFieldType()) { + default: + return Optional.of(PROTO_TYPE_TO_CEL_TYPE.get(fieldType)); + } + } + + private FieldResolver(ImmutableMap fields) { + this.fields = fields; + } + } +} diff --git a/common/src/main/java/dev/cel/common/values/BUILD.bazel b/common/src/main/java/dev/cel/common/values/BUILD.bazel index e9b4be4f1..c52a22c5f 100644 --- a/common/src/main/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/values/BUILD.bazel @@ -57,6 +57,7 @@ java_library( tags = [ ], deps = [ + ":values", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], @@ -68,6 +69,7 @@ cel_android_library( tags = [ ], deps = [ + "//common/values:values_android", "@maven//:com_google_errorprone_error_prone_annotations", "@maven_android//:com_google_guava_guava", ], @@ -79,6 +81,7 @@ java_library( tags = [ ], deps = [ + "//common/values", "//common/values:cel_value_provider", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", @@ -92,6 +95,7 @@ cel_android_library( ], deps = [ "//common/values:cel_value_provider_android", + "//common/values:values_android", "@maven//:com_google_errorprone_error_prone_annotations", "@maven_android//:com_google_guava_guava", ], @@ -213,7 +217,9 @@ java_library( "//common/annotations", "//common/internal:dynamic_proto", "//common/internal:proto_message_factory", + "//common/values", "//common/values:base_proto_cel_value_converter", + "//common/values:cel_value_provider", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_protobuf_protobuf_java", ], @@ -284,7 +290,9 @@ java_library( "//common/annotations", "//common/internal:cel_lite_descriptor_pool", "//common/internal:default_lite_descriptor_pool", + "//common/values", "//common/values:base_proto_cel_value_converter", + "//common/values:cel_value_provider", "//protobuf:cel_lite_descriptor", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", @@ -304,6 +312,8 @@ cel_android_library( "//common/internal:cel_lite_descriptor_pool_android", "//common/internal:default_lite_descriptor_pool_android", "//common/values:base_proto_cel_value_converter_android", + "//common/values:cel_value_provider_android", + "//common/values:values_android", "//protobuf:cel_lite_descriptor", "@maven//:com_google_errorprone_error_prone_annotations", "@maven_android//:com_google_guava_guava", diff --git a/common/src/main/java/dev/cel/common/values/BaseProtoMessageValueProvider.java b/common/src/main/java/dev/cel/common/values/BaseProtoMessageValueProvider.java index f42a16179..f9b7a6ce4 100644 --- a/common/src/main/java/dev/cel/common/values/BaseProtoMessageValueProvider.java +++ b/common/src/main/java/dev/cel/common/values/BaseProtoMessageValueProvider.java @@ -25,7 +25,4 @@ */ @Internal @Immutable -public abstract class BaseProtoMessageValueProvider implements CelValueProvider { - - public abstract BaseProtoCelValueConverter protoCelValueConverter(); -} +public abstract class BaseProtoMessageValueProvider implements CelValueProvider {} diff --git a/common/src/main/java/dev/cel/common/values/CelValueConverter.java b/common/src/main/java/dev/cel/common/values/CelValueConverter.java index c3f3727a1..ae0b40ef7 100644 --- a/common/src/main/java/dev/cel/common/values/CelValueConverter.java +++ b/common/src/main/java/dev/cel/common/values/CelValueConverter.java @@ -33,7 +33,13 @@ @SuppressWarnings("unchecked") // Unchecked cast of generics due to type-erasure (ex: MapValue). @Internal @Immutable -public abstract class CelValueConverter { +public class CelValueConverter { + + private static final CelValueConverter DEFAULT_INSTANCE = new CelValueConverter(); + + public static CelValueConverter getDefaultInstance() { + return DEFAULT_INSTANCE; + } /** Adapts a {@link CelValue} to a plain old Java Object. */ public Object unwrap(CelValue celValue) { diff --git a/common/src/main/java/dev/cel/common/values/CelValueProvider.java b/common/src/main/java/dev/cel/common/values/CelValueProvider.java index 717834660..20ae865e7 100644 --- a/common/src/main/java/dev/cel/common/values/CelValueProvider.java +++ b/common/src/main/java/dev/cel/common/values/CelValueProvider.java @@ -27,4 +27,8 @@ public interface CelValueProvider { * a wrapper. */ Optional newValue(String structType, Map fields); + + default CelValueConverter celValueConverter() { + return CelValueConverter.getDefaultInstance(); + } } diff --git a/common/src/main/java/dev/cel/common/values/CombinedCelValueProvider.java b/common/src/main/java/dev/cel/common/values/CombinedCelValueProvider.java index 8fe62cb7b..6aff39a45 100644 --- a/common/src/main/java/dev/cel/common/values/CombinedCelValueProvider.java +++ b/common/src/main/java/dev/cel/common/values/CombinedCelValueProvider.java @@ -30,6 +30,7 @@ @Immutable public final class CombinedCelValueProvider implements CelValueProvider { private final ImmutableList celValueProviders; + private final CelValueConverter celValueConverter; /** Combines the provided first and second {@link CelValueProvider}. */ public static CombinedCelValueProvider combine(CelValueProvider... providers) { @@ -49,12 +50,18 @@ public Optional newValue(String structType, Map fields) return Optional.empty(); } + @Override + public CelValueConverter celValueConverter() { + return celValueConverter; + } + /** Returns the underlying {@link CelValueProvider}s in order. */ public ImmutableList valueProviders() { return celValueProviders; } private CombinedCelValueProvider(ImmutableList providers) { - celValueProviders = checkNotNull(providers); + this.celValueProviders = checkNotNull(providers); + this.celValueConverter = providers.get(0).celValueConverter(); } } diff --git a/common/src/main/java/dev/cel/common/values/ProtoCelValueConverter.java b/common/src/main/java/dev/cel/common/values/ProtoCelValueConverter.java index 08f30b9d1..9400ae961 100644 --- a/common/src/main/java/dev/cel/common/values/ProtoCelValueConverter.java +++ b/common/src/main/java/dev/cel/common/values/ProtoCelValueConverter.java @@ -82,7 +82,13 @@ public Object toRuntimeValue(Object value) { } if (value instanceof MessageOrBuilder) { - MessageOrBuilder message = (MessageOrBuilder) value; + Message message; + if (value instanceof Message.Builder) { + message = ((Message.Builder) value).build(); + } else { + message = (Message) value; + } + // Attempt to convert the proto from a dynamic message into a concrete message if possible. if (message instanceof DynamicMessage) { message = dynamicProto.maybeAdaptDynamicMessage((DynamicMessage) message); diff --git a/common/src/main/java/dev/cel/common/values/ProtoLiteCelValueConverter.java b/common/src/main/java/dev/cel/common/values/ProtoLiteCelValueConverter.java index 3fbb0ad75..e064e1f48 100644 --- a/common/src/main/java/dev/cel/common/values/ProtoLiteCelValueConverter.java +++ b/common/src/main/java/dev/cel/common/values/ProtoLiteCelValueConverter.java @@ -28,6 +28,7 @@ import com.google.protobuf.CodedInputStream; import com.google.protobuf.ExtensionRegistryLite; import com.google.protobuf.MessageLite; +import com.google.protobuf.MessageLiteOrBuilder; import com.google.protobuf.WireFormat; import dev.cel.common.annotations.Internal; import dev.cel.common.internal.CelLiteDescriptorPool; @@ -163,8 +164,13 @@ Object getDefaultCelValue(String protoTypeName, String fieldName) { @SuppressWarnings("LiteProtoToString") // No alternative identifier to use. Debug only info is OK. public Object toRuntimeValue(Object value) { checkNotNull(value); - if (value instanceof MessageLite) { - MessageLite msg = (MessageLite) value; + if (value instanceof MessageLiteOrBuilder) { + MessageLite msg; + if (value instanceof MessageLite.Builder) { + msg = ((MessageLite.Builder) value).build(); + } else { + msg = (MessageLite) value; + } MessageLiteDescriptor descriptor = descriptorPool diff --git a/common/src/main/java/dev/cel/common/values/ProtoMessageLiteValueProvider.java b/common/src/main/java/dev/cel/common/values/ProtoMessageLiteValueProvider.java index 041d850a6..b3ee2ef04 100644 --- a/common/src/main/java/dev/cel/common/values/ProtoMessageLiteValueProvider.java +++ b/common/src/main/java/dev/cel/common/values/ProtoMessageLiteValueProvider.java @@ -32,12 +32,12 @@ */ @Immutable @Beta -public class ProtoMessageLiteValueProvider extends BaseProtoMessageValueProvider { +public class ProtoMessageLiteValueProvider implements CelValueProvider { private final CelLiteDescriptorPool descriptorPool; private final ProtoLiteCelValueConverter protoLiteCelValueConverter; @Override - public BaseProtoCelValueConverter protoCelValueConverter() { + public CelValueConverter celValueConverter() { return protoLiteCelValueConverter; } diff --git a/common/src/main/java/dev/cel/common/values/ProtoMessageValueProvider.java b/common/src/main/java/dev/cel/common/values/ProtoMessageValueProvider.java index 5bf2927ab..a05658c8f 100644 --- a/common/src/main/java/dev/cel/common/values/ProtoMessageValueProvider.java +++ b/common/src/main/java/dev/cel/common/values/ProtoMessageValueProvider.java @@ -34,13 +34,13 @@ */ @Immutable @Internal -public class ProtoMessageValueProvider extends BaseProtoMessageValueProvider { +public class ProtoMessageValueProvider implements CelValueProvider { private final ProtoAdapter protoAdapter; private final ProtoMessageFactory protoMessageFactory; private final ProtoCelValueConverter protoCelValueConverter; @Override - public BaseProtoCelValueConverter protoCelValueConverter() { + public CelValueConverter celValueConverter() { return protoCelValueConverter; } diff --git a/common/src/test/java/dev/cel/common/values/BUILD.bazel b/common/src/test/java/dev/cel/common/values/BUILD.bazel index ab7eae8dd..d1651379a 100644 --- a/common/src/test/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/values/BUILD.bazel @@ -9,7 +9,6 @@ java_library( srcs = glob(["*.java"]), deps = [ "//:java_truth", - "//bundle:cel", "//common:cel_ast", "//common:cel_descriptor_util", "//common:options", @@ -29,6 +28,9 @@ java_library( "//common/values:proto_message_lite_value_provider", "//common/values:proto_message_value", "//common/values:proto_message_value_provider", + "//compiler", + "//compiler:compiler_builder", + "//runtime", "//testing/protos:test_all_types_cel_java_proto3", "@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto", "@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_java_proto", diff --git a/common/src/test/java/dev/cel/common/values/ProtoMessageLiteValueProviderTest.java b/common/src/test/java/dev/cel/common/values/ProtoMessageLiteValueProviderTest.java index bbe116c80..95e0e031c 100644 --- a/common/src/test/java/dev/cel/common/values/ProtoMessageLiteValueProviderTest.java +++ b/common/src/test/java/dev/cel/common/values/ProtoMessageLiteValueProviderTest.java @@ -49,6 +49,6 @@ public void newValue_emptyFields_success() { @Test public void getProtoLiteCelValueConverter() { - assertThat(VALUE_PROVIDER.protoCelValueConverter()).isNotNull(); + assertThat(VALUE_PROVIDER.celValueConverter()).isNotNull(); } } diff --git a/common/src/test/java/dev/cel/common/values/StructValueTest.java b/common/src/test/java/dev/cel/common/values/StructValueTest.java index 1db147882..deb8e9be0 100644 --- a/common/src/test/java/dev/cel/common/values/StructValueTest.java +++ b/common/src/test/java/dev/cel/common/values/StructValueTest.java @@ -22,8 +22,6 @@ import com.google.common.collect.ImmutableSet; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import com.google.testing.junit.testparameterinjector.TestParameters; -import dev.cel.bundle.Cel; -import dev.cel.bundle.CelFactory; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelOptions; import dev.cel.common.internal.DynamicProto; @@ -31,7 +29,11 @@ import dev.cel.common.types.CelTypeProvider; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; import dev.cel.expr.conformance.proto3.TestAllTypes; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; import java.util.Map; import java.util.Optional; import org.junit.Test; @@ -115,72 +117,92 @@ public void celTypeTest() { @Test public void evaluate_usingCustomClass_createNewStruct() throws Exception { - Cel cel = - CelFactory.standardCelBuilder() - .setOptions(CelOptions.current().enableCelValue(true).build()) + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) + .build(); + CelRuntime plannerRuntime = + CelRuntimeFactory.plannerCelRuntimeBuilder() .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) .setValueProvider(CUSTOM_STRUCT_VALUE_PROVIDER) .build(); - CelAbstractSyntaxTree ast = cel.compile("custom_struct{data: 50}").getAst(); + CelAbstractSyntaxTree ast = compiler.compile("custom_struct{data: 50}").getAst(); - CelCustomStructValue result = (CelCustomStructValue) cel.createProgram(ast).eval(); + CelCustomStructValue result = (CelCustomStructValue) plannerRuntime.createProgram(ast).eval(); assertThat(result.data).isEqualTo(50); } @Test public void evaluate_usingCustomClass_asVariable() throws Exception { - Cel cel = - CelFactory.standardCelBuilder() - .setOptions(CelOptions.current().enableCelValue(true).build()) + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() .addVar("a", CUSTOM_STRUCT_TYPE) + .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) + .build(); + CelRuntime plannerRuntime = + CelRuntimeFactory.plannerCelRuntimeBuilder() .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) .setValueProvider(CUSTOM_STRUCT_VALUE_PROVIDER) .build(); - CelAbstractSyntaxTree ast = cel.compile("a").getAst(); + CelAbstractSyntaxTree ast = compiler.compile("a").getAst(); CelCustomStructValue result = (CelCustomStructValue) - cel.createProgram(ast).eval(ImmutableMap.of("a", new CelCustomStructValue(10))); + plannerRuntime + .createProgram(ast) + .eval(ImmutableMap.of("a", new CelCustomStructValue(10))); assertThat(result.data).isEqualTo(10); } @Test public void evaluate_usingCustomClass_asVariableSelectField() throws Exception { - Cel cel = - CelFactory.standardCelBuilder() - .setOptions(CelOptions.current().enableCelValue(true).build()) + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() .addVar("a", CUSTOM_STRUCT_TYPE) + .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) + .build(); + CelRuntime plannerRuntime = + CelRuntimeFactory.plannerCelRuntimeBuilder() .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) .setValueProvider(CUSTOM_STRUCT_VALUE_PROVIDER) .build(); - CelAbstractSyntaxTree ast = cel.compile("a.data").getAst(); + CelAbstractSyntaxTree ast = compiler.compile("a.data").getAst(); - assertThat(cel.createProgram(ast).eval(ImmutableMap.of("a", new CelCustomStructValue(20)))) + assertThat( + plannerRuntime + .createProgram(ast) + .eval(ImmutableMap.of("a", new CelCustomStructValue(20)))) .isEqualTo(20L); } @Test public void evaluate_usingCustomClass_selectField() throws Exception { - Cel cel = - CelFactory.standardCelBuilder() - .setOptions(CelOptions.current().enableCelValue(true).build()) + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) + .build(); + CelRuntime plannerRuntime = + CelRuntimeFactory.plannerCelRuntimeBuilder() .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) .setValueProvider(CUSTOM_STRUCT_VALUE_PROVIDER) .build(); - CelAbstractSyntaxTree ast = cel.compile("custom_struct{data: 5}.data").getAst(); + CelAbstractSyntaxTree ast = compiler.compile("custom_struct{data: 5}.data").getAst(); - Object result = cel.createProgram(ast).eval(); + Object result = plannerRuntime.createProgram(ast).eval(); assertThat(result).isEqualTo(5L); } @Test public void evaluate_usingMultipleProviders_selectFieldFromCustomClass() throws Exception { - Cel cel = - CelFactory.standardCelBuilder() - .setOptions(CelOptions.current().enableCelValue(true).build()) + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) + .build(); + CelRuntime plannerRuntime = + CelRuntimeFactory.plannerCelRuntimeBuilder() .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) .setValueProvider( CombinedCelValueProvider.combine( @@ -188,18 +210,22 @@ public void evaluate_usingMultipleProviders_selectFieldFromCustomClass() throws CelOptions.DEFAULT, DynamicProto.create(typeName -> Optional.empty())), CUSTOM_STRUCT_VALUE_PROVIDER)) .build(); - CelAbstractSyntaxTree ast = cel.compile("custom_struct{data: 5}.data").getAst(); + CelAbstractSyntaxTree ast = compiler.compile("custom_struct{data: 5}.data").getAst(); - Object result = cel.createProgram(ast).eval(); + Object result = plannerRuntime.createProgram(ast).eval(); assertThat(result).isEqualTo(5L); } @Test public void evaluate_usingMultipleProviders_selectFieldFromProtobufMessage() throws Exception { - Cel cel = - CelFactory.standardCelBuilder() - .setOptions(CelOptions.current().enableCelValue(true).build()) + CelCompiler compiler = + CelCompilerFactory.standardCelCompilerBuilder() + .addMessageTypes(TestAllTypes.getDescriptor()) + .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) + .build(); + CelRuntime plannerRuntime = + CelRuntimeFactory.plannerCelRuntimeBuilder() .addMessageTypes(TestAllTypes.getDescriptor()) .setTypeProvider(CUSTOM_STRUCT_TYPE_PROVIDER) .setValueProvider( @@ -218,10 +244,11 @@ public void evaluate_usingMultipleProviders_selectFieldFromProtobufMessage() thr CUSTOM_STRUCT_VALUE_PROVIDER)) .build(); CelAbstractSyntaxTree ast = - cel.compile("cel.expr.conformance.proto3.TestAllTypes{single_string: 'foo'}.single_string") + compiler + .compile("cel.expr.conformance.proto3.TestAllTypes{single_string: 'foo'}.single_string") .getAst(); - String result = (String) cel.createProgram(ast).eval(); + String result = (String) plannerRuntime.createProgram(ast).eval(); assertThat(result).isEqualTo("foo"); } diff --git a/common/types/BUILD.bazel b/common/types/BUILD.bazel index 41d3d59b2..7d00c8307 100644 --- a/common/types/BUILD.bazel +++ b/common/types/BUILD.bazel @@ -35,6 +35,18 @@ java_library( exports = ["//common/src/main/java/dev/cel/common/types:message_type_provider"], ) +java_library( + name = "message_lite_type_provider", + visibility = ["//:internal"], + exports = ["//common/src/main/java/dev/cel/common/types:message_lite_type_provider"], +) + +cel_android_library( + name = "message_lite_type_provider_android", + visibility = ["//:internal"], + exports = ["//common/src/main/java/dev/cel/common/types:message_lite_type_provider_android"], +) + java_library( name = "cel_types", exports = ["//common/src/main/java/dev/cel/common/types:cel_types"], @@ -56,6 +68,12 @@ java_library( exports = ["//common/src/main/java/dev/cel/common/types:default_type_provider"], ) +cel_android_library( + name = "default_type_provider_android", + visibility = ["//:internal"], + exports = ["//common/src/main/java/dev/cel/common/types:default_type_provider_android"], +) + java_library( name = "cel_v1alpha1_types", visibility = ["//:internal"], diff --git a/runtime/BUILD.bazel b/runtime/BUILD.bazel index 07bfdebbc..709b509f1 100644 --- a/runtime/BUILD.bazel +++ b/runtime/BUILD.bazel @@ -16,6 +16,7 @@ java_library( "//runtime/src/main/java/dev/cel/runtime:descriptor_message_provider", "//runtime/src/main/java/dev/cel/runtime:function_overload", "//runtime/src/main/java/dev/cel/runtime:runtime_type_provider", + "//runtime/src/main/java/dev/cel/runtime:variable_resolver", ], ) @@ -27,6 +28,14 @@ java_library( ], ) +cel_android_library( + name = "dispatcher_android", + visibility = ["//:internal"], + exports = [ + "//runtime/src/main/java/dev/cel/runtime:dispatcher_android", + ], +) + java_library( name = "standard_functions", exports = [ @@ -42,6 +51,14 @@ java_library( ], ) +cel_android_library( + name = "activation_android", + visibility = ["//:internal"], + exports = [ + "//runtime/src/main/java/dev/cel/runtime:activation_android", + ], +) + java_library( name = "proto_message_activation_factory", visibility = ["//:internal"], @@ -78,6 +95,7 @@ cel_android_library( java_library( name = "evaluation_exception_builder", + # used_by_android exports = ["//runtime/src/main/java/dev/cel/runtime:evaluation_exception_builder"], ) @@ -111,6 +129,12 @@ java_library( exports = ["//runtime/src/main/java/dev/cel/runtime:interpretable"], ) +cel_android_library( + name = "interpretable_android", + visibility = ["//:internal"], + exports = ["//runtime/src/main/java/dev/cel/runtime:interpretable_android"], +) + java_library( name = "runtime_helpers", visibility = ["//:internal"], @@ -252,12 +276,20 @@ cel_android_library( java_library( name = "metadata", + # used_by_android visibility = ["//:internal"], exports = ["//runtime/src/main/java/dev/cel/runtime:metadata"], ) +java_library( + name = "variable_resolver", + # used_by_android + exports = ["//runtime/src/main/java/dev/cel/runtime:variable_resolver"], +) + java_library( name = "concatenated_list_view", + # used_by_android visibility = ["//:internal"], exports = [ "//runtime/src/main/java/dev/cel/runtime:concatenated_list_view", diff --git a/runtime/planner/BUILD.bazel b/runtime/planner/BUILD.bazel index 8da29f270..b76391b54 100644 --- a/runtime/planner/BUILD.bazel +++ b/runtime/planner/BUILD.bazel @@ -1,4 +1,5 @@ load("@rules_java//java:defs.bzl", "java_library") +load("//:cel_android_rules.bzl", "cel_android_library") package( default_applicable_licenses = ["//:license"], @@ -9,3 +10,8 @@ java_library( name = "program_planner", exports = ["//runtime/src/main/java/dev/cel/runtime/planner:program_planner"], ) + +cel_android_library( + name = "program_planner_android", + exports = ["//runtime/src/main/java/dev/cel/runtime/planner:program_planner_android"], +) diff --git a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel index cf89d0a80..e17f60f68 100644 --- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel @@ -123,6 +123,7 @@ java_library( deps = [ ":evaluation_exception", ":evaluation_exception_builder", + ":function_binding", ":function_overload", ":function_resolver", ":resolved_overload", @@ -138,10 +139,12 @@ java_library( cel_android_library( name = "dispatcher_android", srcs = DISPATCHER_SOURCES, - visibility = ["//visibility:private"], + tags = [ + ], deps = [ ":evaluation_exception", ":evaluation_exception_builder", + ":function_binding_android", ":function_overload_android", ":function_resolver_android", ":resolved_overload_android", @@ -172,7 +175,8 @@ java_library( cel_android_library( name = "activation_android", srcs = ["Activation.java"], - visibility = ["//visibility:private"], + tags = [ + ], deps = [ ":interpretable_android", ":runtime_helpers_android", @@ -475,10 +479,9 @@ RUNTIME_SOURCES = [ "CelRuntime.java", "CelRuntimeBuilder.java", "CelRuntimeFactory.java", + "CelRuntimeImpl.java", "CelRuntimeLegacyImpl.java", "CelRuntimeLibrary.java", - "CelVariableResolver.java", - "HierarchicalVariableResolver.java", "ProgramImpl.java", "UnknownContext.java", ] @@ -570,6 +573,8 @@ java_library( name = "metadata", srcs = ["Metadata.java"], # used_by_android + tags = [ + ], deps = [ "//common/annotations", "@maven//:com_google_errorprone_error_prone_annotations", @@ -579,11 +584,13 @@ java_library( java_library( name = "interpretable", srcs = INTERPRABLE_SOURCES, + tags = [ + ], deps = [ ":evaluation_exception", - ":evaluation_listener", ":function_resolver", "//common/annotations", + "//runtime:evaluation_listener", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:org_jspecify_jspecify", ], @@ -592,7 +599,8 @@ java_library( cel_android_library( name = "interpretable_android", srcs = INTERPRABLE_SOURCES, - visibility = ["//visibility:private"], + tags = [ + ], deps = [ ":evaluation_exception", ":evaluation_listener_android", @@ -611,6 +619,7 @@ java_library( deps = [ ":function_binding", ":runtime_equality", + "//common:operator", "//common:options", "//common/annotations", "//runtime/standard:add", @@ -668,6 +677,7 @@ cel_android_library( deps = [ ":function_binding_android", ":runtime_equality_android", + "//common:operator_android", "//common:options", "//common/annotations", "//runtime/standard:add_android", @@ -725,7 +735,9 @@ java_library( tags = [ ], deps = [ + ":evaluation_exception", ":function_overload", + ":resolved_overload", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], @@ -737,7 +749,9 @@ cel_android_library( tags = [ ], deps = [ + ":evaluation_exception", ":function_overload_android", + ":resolved_overload_android", "@maven//:com_google_errorprone_error_prone_annotations", "@maven_android//:com_google_guava_guava", ], @@ -798,7 +812,6 @@ java_library( ], deps = [ ":activation", - ":cel_value_runtime_type_provider", ":descriptor_message_provider", ":descriptor_type_resolver", ":dispatcher", @@ -815,10 +828,12 @@ java_library( ":runtime_type_provider", ":standard_functions", ":unknown_attributes", + ":variable_resolver", "//:auto_value", "//common:cel_ast", "//common:cel_descriptor_util", "//common:cel_descriptors", + "//common:container", "//common:options", "//common/annotations", "//common/internal:cel_descriptor_pools", @@ -826,8 +841,16 @@ java_library( "//common/internal:dynamic_proto", "//common/internal:proto_message_factory", "//common/types:cel_types", + "//common/types:default_type_provider", + "//common/types:message_type_provider", + "//common/types:type_providers", + "//common/values", "//common/values:cel_value_provider", + "//common/values:combined_cel_value_provider", "//common/values:proto_message_value_provider", + "//runtime:proto_message_runtime_helpers", + "//runtime:runtime_helpers", + "//runtime/planner:program_planner", "//runtime/standard:add", "//runtime/standard:int", "//runtime/standard:timestamp", @@ -850,8 +873,10 @@ java_library( ":program", "//:auto_value", "//common:cel_ast", + "//common:container", "//common:options", "//common/annotations", + "//common/types:type_providers", "//common/values:cel_value_provider", "//runtime/standard:standard_function", "@maven//:com_google_code_findbugs_annotations", @@ -866,7 +891,6 @@ java_library( tags = [ ], deps = [ - ":cel_value_runtime_type_provider", ":dispatcher", ":function_binding", ":interpreter", @@ -878,10 +902,19 @@ java_library( ":type_resolver", "//:auto_value", "//common:cel_ast", + "//common:container", "//common:options", + "//common/types:default_type_provider", + "//common/types:type_providers", + "//common/values", + "//common/values:cel_value", "//common/values:cel_value_provider", + "//runtime:evaluation_exception", + "//runtime/planner:program_planner", "//runtime/standard:standard_function", + "//third_party/java/jsr305_annotations", "@maven//:com_google_code_findbugs_annotations", + "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", ], ) @@ -896,6 +929,7 @@ java_library( ":interpretable", ":program", "//:auto_value", + "//runtime:variable_resolver", "@maven//:com_google_errorprone_error_prone_annotations", ], ) @@ -909,6 +943,7 @@ cel_android_library( ":function_resolver_android", ":interpretable_android", ":program_android", + ":variable_resolver", "//:auto_value", "@maven//:com_google_errorprone_error_prone_annotations", ], @@ -920,8 +955,8 @@ cel_android_library( tags = [ ], deps = [ - ":cel_value_runtime_type_provider_android", ":dispatcher_android", + ":evaluation_exception", ":function_binding_android", ":interpreter_android", ":lite_program_impl_android", @@ -932,9 +967,16 @@ cel_android_library( ":type_resolver_android", "//:auto_value", "//common:cel_ast_android", + "//common:container_android", "//common:options", + "//common/types:default_type_provider_android", + "//common/types:type_providers_android", + "//common/values:cel_value_android", "//common/values:cel_value_provider_android", + "//common/values:values_android", + "//runtime/planner:program_planner_android", "//runtime/standard:standard_function_android", + "//third_party/java/jsr305_annotations", "@maven//:com_google_code_findbugs_annotations", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_guava", @@ -1026,48 +1068,6 @@ cel_android_library( ], ) -java_library( - name = "cel_value_runtime_type_provider", - srcs = ["CelValueRuntimeTypeProvider.java"], - deps = [ - ":runtime_type_provider", - ":unknown_attributes", - "//common:error_codes", - "//common:runtime_exception", - "//common/annotations", - "//common/values", - "//common/values:base_proto_cel_value_converter", - "//common/values:base_proto_message_value_provider", - "//common/values:cel_value", - "//common/values:cel_value_provider", - "//common/values:combined_cel_value_provider", - "@maven//:com_google_errorprone_error_prone_annotations", - "@maven//:com_google_guava_guava", - "@maven//:com_google_protobuf_protobuf_java", - ], -) - -cel_android_library( - name = "cel_value_runtime_type_provider_android", - srcs = ["CelValueRuntimeTypeProvider.java"], - deps = [ - ":runtime_type_provider_android", - ":unknown_attributes_android", - "//common:error_codes", - "//common:runtime_exception", - "//common/annotations", - "//common/values:base_proto_cel_value_converter_android", - "//common/values:base_proto_message_value_provider_android", - "//common/values:cel_value_android", - "//common/values:cel_value_provider_android", - "//common/values:combined_cel_value_provider_android", - "//common/values:values_android", - "@maven//:com_google_errorprone_error_prone_annotations", - "@maven_android//:com_google_guava_guava", - "@maven_android//:com_google_protobuf_protobuf_javalite", - ], -) - java_library( name = "interpreter_util", srcs = ["InterpreterUtil.java"], @@ -1131,8 +1131,10 @@ cel_android_library( ":program_android", "//:auto_value", "//common:cel_ast_android", + "//common:container_android", "//common:options", "//common/annotations", + "//common/types:type_providers_android", "//common/values:cel_value_provider_android", "//runtime/standard:standard_function_android", "@maven//:com_google_code_findbugs_annotations", @@ -1208,6 +1210,8 @@ java_library( deps = [ ":evaluation_exception", ":function_resolver", + ":variable_resolver", + "//runtime:variable_resolver", "@maven//:com_google_errorprone_error_prone_annotations", ], ) @@ -1220,6 +1224,7 @@ cel_android_library( deps = [ ":evaluation_exception", ":function_resolver_android", + ":variable_resolver", "//:auto_value", "@maven//:com_google_errorprone_error_prone_annotations", ], @@ -1250,3 +1255,14 @@ cel_android_library( "@maven_android//:com_google_guava_guava", ], ) + +java_library( + name = "variable_resolver", + srcs = [ + "CelVariableResolver.java", + "HierarchicalVariableResolver.java", + ], + # used_by_android + tags = [ + ], +) diff --git a/runtime/src/main/java/dev/cel/runtime/CelFunctionBinding.java b/runtime/src/main/java/dev/cel/runtime/CelFunctionBinding.java index 79b0f3f54..ae938ba4b 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelFunctionBinding.java +++ b/runtime/src/main/java/dev/cel/runtime/CelFunctionBinding.java @@ -14,8 +14,13 @@ package dev.cel.runtime; +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.Immutable; +import java.util.Collection; /** * Binding consisting of an overload id, a Java-native argument signature, and an overload @@ -35,7 +40,6 @@ * *

Examples: string_startsWith_string, mathMax_list, lessThan_money_money */ - @Immutable public interface CelFunctionBinding { String getOverloadId(); @@ -70,4 +74,20 @@ static CelFunctionBinding from( return new FunctionBindingImpl( overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true); } + + /** TODO */ + static ImmutableSet groupOverloads( + String functionName, CelFunctionBinding... overloadBindings) { + return groupOverloads(functionName, ImmutableList.copyOf(overloadBindings)); + } + + /** TODO */ + static ImmutableSet groupOverloads( + String functionName, Collection overloadBindings) { + checkArgument(!Strings.isNullOrEmpty(functionName), "Function name cannot be null or empty"); + checkArgument(!overloadBindings.isEmpty(), "You must provide at least one binding."); + + return FunctionBindingImpl.groupOverloadsToFunction( + functionName, ImmutableSet.copyOf(overloadBindings)); + } } diff --git a/runtime/src/main/java/dev/cel/runtime/CelLiteRuntimeBuilder.java b/runtime/src/main/java/dev/cel/runtime/CelLiteRuntimeBuilder.java index 48b51274d..ec5d0fa5d 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelLiteRuntimeBuilder.java +++ b/runtime/src/main/java/dev/cel/runtime/CelLiteRuntimeBuilder.java @@ -16,7 +16,9 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; +import dev.cel.common.CelContainer; import dev.cel.common.CelOptions; +import dev.cel.common.types.CelTypeProvider; import dev.cel.common.values.CelValueProvider; import dev.cel.runtime.standard.CelStandardFunction; @@ -47,6 +49,13 @@ CelLiteRuntimeBuilder setStandardFunctions( @CanIgnoreReturnValue CelLiteRuntimeBuilder addFunctionBindings(Iterable bindings); + /** + * Sets the {@link CelTypeProvider} for resolving CEL types during evaluation, such as a fully + * qualified type name to a struct or an enum value. + */ + @CanIgnoreReturnValue + CelLiteRuntimeBuilder setTypeProvider(CelTypeProvider celTypeProvider); + /** * Sets the {@link CelValueProvider} for resolving struct values during evaluation. Multiple * providers can be combined using {@code CombinedCelValueProvider}. Note that if you intend to @@ -62,6 +71,13 @@ CelLiteRuntimeBuilder setStandardFunctions( @CanIgnoreReturnValue CelLiteRuntimeBuilder addLibraries(Iterable libraries); + /** + * Set the {@link CelContainer} to use as the namespace for resolving CEL expression variables and + * functions. + */ + @CanIgnoreReturnValue + CelLiteRuntimeBuilder setContainer(CelContainer container); + @CheckReturnValue CelLiteRuntime build(); } diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntime.java b/runtime/src/main/java/dev/cel/runtime/CelRuntime.java index a42b7f969..71fef3173 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntime.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntime.java @@ -42,9 +42,6 @@ interface Program extends dev.cel.runtime.Program { /** Evaluate the expression using {@code message} fields as the source of input variables. */ Object eval(Message message) throws CelEvaluationException; - /** Evaluate a compiled program with a custom variable {@code resolver}. */ - Object eval(CelVariableResolver resolver) throws CelEvaluationException; - /** * Evaluate a compiled program with a custom variable {@code resolver} and late-bound functions * {@code lateBoundFunctionResolver}. diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java index e1e3c1b51..1467f32bb 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java @@ -22,6 +22,7 @@ import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Message; import dev.cel.common.CelOptions; +import dev.cel.common.types.CelTypeProvider; import dev.cel.common.values.CelValueProvider; import java.util.function.Function; @@ -123,6 +124,13 @@ public interface CelRuntimeBuilder { @CanIgnoreReturnValue CelRuntimeBuilder addFileTypes(FileDescriptorSet fileDescriptorSet); + /** + * Sets the {@link CelTypeProvider} for resolving CEL types during evaluation, such as a fully + * qualified type name to a struct or an enum value. + */ + @CanIgnoreReturnValue + CelRuntimeBuilder setTypeProvider(CelTypeProvider celTypeProvider); + /** * Set a custom type factory for the runtime. * @@ -145,7 +153,7 @@ public interface CelRuntimeBuilder { * support proto messages in addition to custom struct values, protobuf value provider must be * configured first before the custom value provider. * - *

Note {@link CelOptions#enableCelValue()} must be enabled or this method will be a no-op. + *

Note that this option is only supported for planner-based runtime. */ @CanIgnoreReturnValue CelRuntimeBuilder setValueProvider(CelValueProvider celValueProvider); diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeFactory.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeFactory.java index e19f9d765..61f29a790 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeFactory.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeFactory.java @@ -15,6 +15,7 @@ package dev.cel.runtime; import dev.cel.common.CelOptions; +import dev.cel.common.annotations.Beta; /** Helper class to construct new {@code CelRuntime} instances. */ public final class CelRuntimeFactory { @@ -31,5 +32,16 @@ public static CelRuntimeBuilder standardCelRuntimeBuilder() { .setStandardEnvironmentEnabled(true); } + @Beta + public static CelRuntimeBuilder plannerCelRuntimeBuilder() { + return CelRuntimeImpl.newBuilder() + .setStandardFunctions(CelStandardFunctions.newBuilder().build()) + .setOptions( + CelOptions.current() + .enableTimestampEpoch(true) + .enableHeterogeneousNumericComparisons(true) + .build()); + } + private CelRuntimeFactory() {} } diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java new file mode 100644 index 000000000..b5c218b0c --- /dev/null +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java @@ -0,0 +1,400 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package dev.cel.runtime; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.Immutable; +import com.google.protobuf.DescriptorProtos; +import com.google.protobuf.Descriptors; +import com.google.protobuf.ExtensionRegistry; +import com.google.protobuf.Message; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelContainer; +import dev.cel.common.CelDescriptorUtil; +import dev.cel.common.CelDescriptors; +import dev.cel.common.CelOptions; +import dev.cel.common.annotations.Internal; +import dev.cel.common.internal.CelDescriptorPool; +import dev.cel.common.internal.DefaultDescriptorPool; +import dev.cel.common.internal.DefaultMessageFactory; +import dev.cel.common.internal.DynamicProto; +import dev.cel.common.types.CelTypeProvider; +import dev.cel.common.types.DefaultTypeProvider; +import dev.cel.common.types.ProtoMessageTypeProvider; +import dev.cel.common.values.CelValueConverter; +import dev.cel.common.values.CelValueProvider; +import dev.cel.common.values.CombinedCelValueProvider; +import dev.cel.common.values.ProtoMessageValueProvider; +import dev.cel.runtime.planner.ProgramPlanner; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import org.jspecify.annotations.Nullable; + +@AutoValue +@Internal +@Immutable +abstract class CelRuntimeImpl implements CelRuntime { + + abstract ProgramPlanner planner(); + + abstract CelOptions options(); + + abstract ImmutableMap functionBindings(); + + abstract ImmutableSet fileDescriptors(); + + // Callers must guarantee that a custom runtime library is immutable. CEL provided ones are + // immutable by default. + @SuppressWarnings("Immutable") + @AutoValue.CopyAnnotations + abstract ImmutableSet runtimeLibraries(); + + abstract CelStandardFunctions standardFunctions(); + + abstract @Nullable CelTypeProvider typeProvider(); + + abstract @Nullable CelValueProvider valueProvider(); + + // Extension registry is unmodifiable. Just not marked as such from Protobuf's implementation. + @SuppressWarnings("Immutable") + @AutoValue.CopyAnnotations + abstract @Nullable ExtensionRegistry extensionRegistry(); + + public Program createProgram(CelAbstractSyntaxTree ast) throws CelEvaluationException { + return toRuntimeProgram(planner().plan(ast)); + } + + public Program toRuntimeProgram(dev.cel.runtime.Program program) { + return new Program() { + + @Override + public Object eval() throws CelEvaluationException { + return program.eval(); + } + + @Override + public Object eval(Map mapValue) throws CelEvaluationException { + return program.eval(mapValue); + } + + @Override + public Object eval(Map mapValue, CelFunctionResolver lateBoundFunctionResolver) + throws CelEvaluationException { + return program.eval(mapValue, lateBoundFunctionResolver); + } + + @Override + public Object eval(Message message) throws CelEvaluationException { + throw new UnsupportedOperationException("Not yet supported."); + } + + @Override + public Object eval(CelVariableResolver resolver) throws CelEvaluationException { + return program.eval(resolver); + } + + @Override + public Object eval( + CelVariableResolver resolver, CelFunctionResolver lateBoundFunctionResolver) + throws CelEvaluationException { + throw new UnsupportedOperationException("Not yet supported."); + } + + @Override + public Object trace(CelEvaluationListener listener) throws CelEvaluationException { + throw new UnsupportedOperationException("Trace is not yet supported."); + } + + @Override + public Object trace(Map mapValue, CelEvaluationListener listener) + throws CelEvaluationException { + throw new UnsupportedOperationException("Trace is not yet supported."); + } + + @Override + public Object trace(Message message, CelEvaluationListener listener) + throws CelEvaluationException { + throw new UnsupportedOperationException("Trace is not yet supported."); + } + + @Override + public Object trace(CelVariableResolver resolver, CelEvaluationListener listener) + throws CelEvaluationException { + throw new UnsupportedOperationException("Trace is not yet supported."); + } + + @Override + public Object trace( + CelVariableResolver resolver, + CelFunctionResolver lateBoundFunctionResolver, + CelEvaluationListener listener) + throws CelEvaluationException { + throw new UnsupportedOperationException("Trace is not yet supported."); + } + + @Override + public Object trace( + Map mapValue, + CelFunctionResolver lateBoundFunctionResolver, + CelEvaluationListener listener) + throws CelEvaluationException { + throw new UnsupportedOperationException("Trace is not yet supported."); + } + + @Override + public Object advanceEvaluation(UnknownContext context) throws CelEvaluationException { + throw new UnsupportedOperationException("Unsupported operation."); + } + }; + } + + public abstract Builder toRuntimeBuilder(); + + static Builder newBuilder() { + return new AutoValue_CelRuntimeImpl.Builder(); + } + + @AutoValue.Builder + abstract static class Builder implements CelRuntimeBuilder { + + public abstract Builder setPlanner(ProgramPlanner planner); + + public abstract Builder setOptions(CelOptions options); + + public abstract Builder setStandardFunctions(CelStandardFunctions standardFunctions); + + public abstract Builder setExtensionRegistry(ExtensionRegistry extensionRegistry); + + public abstract Builder setTypeProvider(CelTypeProvider celTypeProvider); + + public abstract Builder setValueProvider(CelValueProvider celValueProvider); + + abstract CelOptions options(); + + abstract CelTypeProvider typeProvider(); + + abstract CelValueProvider valueProvider(); + + abstract CelStandardFunctions standardFunctions(); + + abstract ImmutableSet.Builder fileDescriptorsBuilder(); + + abstract ImmutableSet.Builder runtimeLibrariesBuilder(); + + private final Map mutableFunctionBindings = new HashMap<>(); + + @CanIgnoreReturnValue + public Builder addFunctionBindings(CelFunctionBinding... bindings) { + checkNotNull(bindings); + return addFunctionBindings(Arrays.asList(bindings)); + } + + @CanIgnoreReturnValue + public Builder addFunctionBindings(Iterable bindings) { + checkNotNull(bindings); + bindings.forEach(o -> mutableFunctionBindings.putIfAbsent(o.getOverloadId(), o)); + return this; + } + + @CanIgnoreReturnValue + public Builder addMessageTypes(Descriptors.Descriptor... descriptors) { + checkNotNull(descriptors); + return addMessageTypes(Arrays.asList(descriptors)); + } + + @CanIgnoreReturnValue + public Builder addMessageTypes(Iterable descriptors) { + checkNotNull(descriptors); + return addFileTypes(CelDescriptorUtil.getFileDescriptorsForDescriptors(descriptors)); + } + + @CanIgnoreReturnValue + public Builder addFileTypes(DescriptorProtos.FileDescriptorSet fileDescriptorSet) { + checkNotNull(fileDescriptorSet); + return addFileTypes( + CelDescriptorUtil.getFileDescriptorsFromFileDescriptorSet(fileDescriptorSet)); + } + + @CanIgnoreReturnValue + public Builder addFileTypes(Descriptors.FileDescriptor... fileDescriptors) { + checkNotNull(fileDescriptors); + return addFileTypes(Arrays.asList(fileDescriptors)); + } + + @CanIgnoreReturnValue + public Builder addFileTypes(Iterable fileDescriptors) { + checkNotNull(fileDescriptors); + this.fileDescriptorsBuilder().addAll(fileDescriptors); + return this; + } + + @CanIgnoreReturnValue + public Builder addLibraries(CelRuntimeLibrary... libraries) { + checkNotNull(libraries); + return this.addLibraries(Arrays.asList(libraries)); + } + + @CanIgnoreReturnValue + public Builder addLibraries(Iterable libraries) { + checkNotNull(libraries); + this.runtimeLibrariesBuilder().addAll(libraries); + return this; + } + + abstract Builder setFunctionBindings(ImmutableMap value); + + public Builder setTypeFactory(Function typeFactory) { + throw new UnsupportedOperationException("Unsupported. Use a custom value provider instead."); + } + + public Builder setStandardEnvironmentEnabled(boolean value) { + throw new UnsupportedOperationException( + "Unsupported. Subset the environment using setStandardFunctions instead."); + } + + /** Throws if an unsupported flag in CelOptions is toggled. */ + private static void assertAllowedCelOptions(CelOptions celOptions) { + String prefix = "Misconfigured CelOptions: "; + if (!celOptions.enableUnsignedLongs()) { + throw new IllegalArgumentException(prefix + "enableUnsignedLongs cannot be disabled."); + } + if (!celOptions.unwrapWellKnownTypesOnFunctionDispatch()) { + throw new IllegalArgumentException( + prefix + "unwrapWellKnownTypesOnFunctionDispatch cannot be disabled."); + } + + // Disallowed options in favor of subsetting + String subsettingError = "Subset the environment instead using setStandardFunctions method."; + if (!celOptions.enableStringConcatenation()) { + throw new IllegalArgumentException( + prefix + "enableStringConcatenation cannot be disabled. " + subsettingError); + } + + if (!celOptions.enableStringConversion()) { + throw new IllegalArgumentException( + prefix + "enableStringConversion cannot be disabled. " + subsettingError); + } + + if (!celOptions.enableListConcatenation()) { + throw new IllegalArgumentException( + prefix + "enableListConcatenation cannot be disabled. " + subsettingError); + } + + if (!celOptions.enableTimestampEpoch()) { + throw new IllegalArgumentException( + prefix + "enableTimestampEpoch cannot be disabled. " + subsettingError); + } + + if (!celOptions.enableHeterogeneousNumericComparisons()) { + throw new IllegalArgumentException( + prefix + + "enableHeterogeneousNumericComparisons cannot be disabled. " + + subsettingError); + } + } + + abstract CelRuntimeImpl autoBuild(); + + private static DefaultDispatcher newDispatcher( + CelStandardFunctions standardFunctions, + Collection customFunctionBindings, + RuntimeEquality runtimeEquality, + CelOptions options) { + DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder(); + for (CelFunctionBinding binding : + standardFunctions.newFunctionBindings(runtimeEquality, options)) { + builder.addOverload( + binding.getOverloadId(), + binding.getArgTypes(), + binding.isStrict(), + binding.getDefinition()); + } + + for (CelFunctionBinding binding : customFunctionBindings) { + builder.addOverload( + binding.getOverloadId(), + binding.getArgTypes(), + binding.isStrict(), + binding.getDefinition()); + } + + return builder.build(); + } + + public CelRuntime build() { + assertAllowedCelOptions(options()); + CelDescriptors celDescriptors = + CelDescriptorUtil.getAllDescriptorsFromFileDescriptor(fileDescriptorsBuilder().build()); + + CelDescriptorPool descriptorPool = DefaultDescriptorPool.create(celDescriptors); + DefaultMessageFactory defaultMessageFactory = DefaultMessageFactory.create(descriptorPool); + DynamicProto dynamicProto = DynamicProto.create(defaultMessageFactory); + CelValueProvider protoMessageValueProvider = + ProtoMessageValueProvider.newInstance(options(), dynamicProto); + CelValueConverter celValueConverter = protoMessageValueProvider.celValueConverter(); + if (valueProvider() != null) { + protoMessageValueProvider = + CombinedCelValueProvider.combine(protoMessageValueProvider, valueProvider()); + } + + RuntimeEquality runtimeEquality = + RuntimeEquality.create( + ProtoMessageRuntimeHelpers.create(dynamicProto, options()), options()); + ImmutableSet runtimeLibraries = runtimeLibrariesBuilder().build(); + // Add libraries, such as extensions + for (CelRuntimeLibrary celLibrary : runtimeLibraries) { + if (celLibrary instanceof CelInternalRuntimeLibrary) { + ((CelInternalRuntimeLibrary) celLibrary) + .setRuntimeOptions(this, runtimeEquality, options()); + } else { + celLibrary.setRuntimeOptions(this); + } + } + + CelTypeProvider combinedTypeProvider = + new CelTypeProvider.CombinedCelTypeProvider( + new ProtoMessageTypeProvider(celDescriptors), DefaultTypeProvider.getInstance()); + if (typeProvider() != null) { + combinedTypeProvider = + new CelTypeProvider.CombinedCelTypeProvider(combinedTypeProvider, typeProvider()); + } + + DefaultDispatcher dispatcher = + newDispatcher( + standardFunctions(), mutableFunctionBindings.values(), runtimeEquality, options()); + + ProgramPlanner planner = + ProgramPlanner.newPlanner( + combinedTypeProvider, + protoMessageValueProvider, + dispatcher, + celValueConverter, + CelContainer.newBuilder().build(), // TODO: Accept CEL container + options()); + setPlanner(planner); + + setFunctionBindings(ImmutableMap.copyOf(mutableFunctionBindings)); + return autoBuild(); + } + } +} diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java index 15591e680..28f92eec7 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java @@ -40,9 +40,10 @@ import dev.cel.common.internal.DynamicProto; // CEL-Internal-3 import dev.cel.common.internal.ProtoMessageFactory; +import dev.cel.common.types.CelTypeProvider; import dev.cel.common.types.CelTypes; import dev.cel.common.values.CelValueProvider; -import dev.cel.common.values.ProtoMessageValueProvider; +import dev.cel.runtime.FunctionBindingImpl.DynamicDispatchBinding; import dev.cel.runtime.standard.AddOperator.AddOverload; import dev.cel.runtime.standard.IntFunction.IntOverload; import dev.cel.runtime.standard.TimestampFunction.TimestampOverload; @@ -77,7 +78,6 @@ public final class CelRuntimeLegacyImpl implements CelRuntime { private final Function customTypeFactory; private final CelStandardFunctions overriddenStandardFunctions; - private final CelValueProvider celValueProvider; private final ImmutableSet fileDescriptors; // This does not affect the evaluation behavior in any manner. @@ -111,10 +111,6 @@ public CelRuntimeBuilder toRuntimeBuilder() { builder.setStandardFunctions(overriddenStandardFunctions); } - if (celValueProvider != null) { - builder.setValueProvider(celValueProvider); - } - return builder; } @@ -134,7 +130,6 @@ public static final class Builder implements CelRuntimeBuilder { @VisibleForTesting final ImmutableSet.Builder celRuntimeLibraries; @VisibleForTesting Function customTypeFactory; - @VisibleForTesting CelValueProvider celValueProvider; @VisibleForTesting CelStandardFunctions overriddenStandardFunctions; private CelOptions options; @@ -188,14 +183,20 @@ public CelRuntimeBuilder addFileTypes(FileDescriptorSet fileDescriptorSet) { } @Override - public CelRuntimeBuilder setTypeFactory(Function typeFactory) { - this.customTypeFactory = typeFactory; - return this; + public CelRuntimeBuilder setTypeProvider(CelTypeProvider celTypeProvider) { + throw new UnsupportedOperationException( + "setTypeProvider is not supported for legacy runtime"); } @Override public CelRuntimeBuilder setValueProvider(CelValueProvider celValueProvider) { - this.celValueProvider = celValueProvider; + throw new UnsupportedOperationException( + "setValueProvider is not supported for legacy runtime"); + } + + @Override + public CelRuntimeBuilder setTypeFactory(Function typeFactory) { + this.customTypeFactory = typeFactory; return this; } @@ -281,6 +282,10 @@ public CelRuntimeLegacyImpl build() { ImmutableMap.builder(); for (CelFunctionBinding standardFunctionBinding : newStandardFunctionBindings(runtimeEquality)) { + if (standardFunctionBinding instanceof DynamicDispatchBinding) { + continue; + } + functionBindingsBuilder.put( standardFunctionBinding.getOverloadId(), standardFunctionBinding); } @@ -295,19 +300,8 @@ public CelRuntimeLegacyImpl build() { dispatcherBuilder.addOverload( overloadId, func.getArgTypes(), func.isStrict(), func.getDefinition())); - RuntimeTypeProvider runtimeTypeProvider; - - if (options.enableCelValue()) { - CelValueProvider messageValueProvider = celValueProvider; - - if (messageValueProvider == null) { - messageValueProvider = ProtoMessageValueProvider.newInstance(options, dynamicProto); - } - - runtimeTypeProvider = CelValueRuntimeTypeProvider.newInstance(messageValueProvider); - } else { - runtimeTypeProvider = new DescriptorMessageProvider(runtimeTypeFactory, options); - } + RuntimeTypeProvider runtimeTypeProvider = + new DescriptorMessageProvider(runtimeTypeFactory, options); DefaultInterpreter interpreter = new DefaultInterpreter( @@ -323,7 +317,6 @@ public CelRuntimeLegacyImpl build() { extensionRegistry, customTypeFactory, overriddenStandardFunctions, - celValueProvider, fileDescriptors, runtimeLibraries, ImmutableList.copyOf(customFunctionBindings.values())); @@ -366,7 +359,8 @@ private ImmutableSet newStandardFunctionBindings( break; default: if (!options.enableHeterogeneousNumericComparisons()) { - return !CelStandardFunctions.isHeterogeneousComparison(standardOverload); + return !CelStandardFunctions.isHeterogeneousComparison( + standardOverload); } break; } @@ -420,7 +414,6 @@ private CelRuntimeLegacyImpl( ExtensionRegistry extensionRegistry, @Nullable Function customTypeFactory, @Nullable CelStandardFunctions overriddenStandardFunctions, - @Nullable CelValueProvider celValueProvider, ImmutableSet fileDescriptors, ImmutableSet celRuntimeLibraries, ImmutableList celFunctionBindings) { @@ -430,7 +423,6 @@ private CelRuntimeLegacyImpl( this.extensionRegistry = extensionRegistry; this.customTypeFactory = customTypeFactory; this.overriddenStandardFunctions = overriddenStandardFunctions; - this.celValueProvider = celValueProvider; this.fileDescriptors = fileDescriptors; this.celRuntimeLibraries = celRuntimeLibraries; this.celFunctionBindings = celFunctionBindings; diff --git a/runtime/src/main/java/dev/cel/runtime/CelStandardFunctions.java b/runtime/src/main/java/dev/cel/runtime/CelStandardFunctions.java index bedd41728..8b5ab3b17 100644 --- a/runtime/src/main/java/dev/cel/runtime/CelStandardFunctions.java +++ b/runtime/src/main/java/dev/cel/runtime/CelStandardFunctions.java @@ -15,12 +15,15 @@ package dev.cel.runtime; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableSet.toImmutableSet; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelOptions; +import dev.cel.common.Operator; import dev.cel.common.annotations.Internal; import dev.cel.runtime.standard.AddOperator; import dev.cel.runtime.standard.AddOperator.AddOverload; @@ -104,6 +107,8 @@ import dev.cel.runtime.standard.TimestampFunction.TimestampOverload; import dev.cel.runtime.standard.UintFunction; import dev.cel.runtime.standard.UintFunction.UintOverload; +import java.util.Collection; +import java.util.Map; /** Runtime function bindings for the standard functions in CEL. */ @Immutable @@ -135,7 +140,7 @@ public final class CelStandardFunctions { GreaterEqualsOverload.GREATER_EQUALS_UINT64_DOUBLE, GreaterEqualsOverload.GREATER_EQUALS_DOUBLE_UINT64); - private final ImmutableSet standardOverloads; + private final ImmutableMultimap standardOverloads; public static final ImmutableSet ALL_STANDARD_FUNCTIONS = ImmutableSet.of( @@ -187,13 +192,15 @@ public final class CelStandardFunctions { * special-cased, and does not appear in this enum. */ public enum StandardFunction { - LOGICAL_NOT(LogicalNotOverload.LOGICAL_NOT), - IN(InOverload.IN_LIST, InOverload.IN_MAP), - NOT_STRICTLY_FALSE(NotStrictlyFalseOverload.NOT_STRICTLY_FALSE), - EQUALS(EqualsOverload.EQUALS), - NOT_EQUALS(NotEqualsOverload.NOT_EQUALS), - BOOL(BoolOverload.BOOL_TO_BOOL, BoolOverload.STRING_TO_BOOL), + LOGICAL_NOT(Operator.LOGICAL_NOT.getFunction(), LogicalNotOverload.LOGICAL_NOT), + IN(Operator.IN.getFunction(), InOverload.IN_LIST, InOverload.IN_MAP), + NOT_STRICTLY_FALSE( + Operator.NOT_STRICTLY_FALSE.getFunction(), NotStrictlyFalseOverload.NOT_STRICTLY_FALSE), + EQUALS(Operator.EQUALS.getFunction(), EqualsOverload.EQUALS), + NOT_EQUALS(Operator.NOT_EQUALS.getFunction(), NotEqualsOverload.NOT_EQUALS), + BOOL("bool", BoolOverload.BOOL_TO_BOOL, BoolOverload.STRING_TO_BOOL), ADD( + Operator.ADD.getFunction(), AddOverload.ADD_INT64, AddOverload.ADD_UINT64, AddOverload.ADD_DOUBLE, @@ -204,6 +211,7 @@ public enum StandardFunction { AddOverload.ADD_DURATION_TIMESTAMP, AddOverload.ADD_DURATION_DURATION), SUBTRACT( + Operator.SUBTRACT.getFunction(), SubtractOverload.SUBTRACT_INT64, SubtractOverload.SUBTRACT_TIMESTAMP_TIMESTAMP, SubtractOverload.SUBTRACT_TIMESTAMP_DURATION, @@ -211,14 +219,22 @@ public enum StandardFunction { SubtractOverload.SUBTRACT_DOUBLE, SubtractOverload.SUBTRACT_DURATION_DURATION), MULTIPLY( + Operator.MULTIPLY.getFunction(), MultiplyOverload.MULTIPLY_INT64, MultiplyOverload.MULTIPLY_DOUBLE, MultiplyOverload.MULTIPLY_UINT64), - DIVIDE(DivideOverload.DIVIDE_DOUBLE, DivideOverload.DIVIDE_INT64, DivideOverload.DIVIDE_UINT64), - MODULO(ModuloOverload.MODULO_INT64, ModuloOverload.MODULO_UINT64), - NEGATE(NegateOverload.NEGATE_INT64, NegateOverload.NEGATE_DOUBLE), - INDEX(IndexOverload.INDEX_LIST, IndexOverload.INDEX_MAP), + DIVIDE( + Operator.DIVIDE.getFunction(), + DivideOverload.DIVIDE_DOUBLE, + DivideOverload.DIVIDE_INT64, + DivideOverload.DIVIDE_UINT64), + MODULO( + Operator.MODULO.getFunction(), ModuloOverload.MODULO_INT64, ModuloOverload.MODULO_UINT64), + NEGATE( + Operator.NEGATE.getFunction(), NegateOverload.NEGATE_INT64, NegateOverload.NEGATE_DOUBLE), + INDEX(Operator.INDEX.getFunction(), IndexOverload.INDEX_LIST, IndexOverload.INDEX_MAP), SIZE( + "size", SizeOverload.SIZE_STRING, SizeOverload.SIZE_BYTES, SizeOverload.SIZE_LIST, @@ -228,22 +244,26 @@ public enum StandardFunction { SizeOverload.LIST_SIZE, SizeOverload.MAP_SIZE), INT( + "int", IntOverload.INT64_TO_INT64, IntOverload.UINT64_TO_INT64, IntOverload.DOUBLE_TO_INT64, IntOverload.STRING_TO_INT64, IntOverload.TIMESTAMP_TO_INT64), UINT( + "uint", UintOverload.UINT64_TO_UINT64, UintOverload.INT64_TO_UINT64, UintOverload.DOUBLE_TO_UINT64, UintOverload.STRING_TO_UINT64), DOUBLE( + "double", DoubleOverload.DOUBLE_TO_DOUBLE, DoubleOverload.INT64_TO_DOUBLE, DoubleOverload.STRING_TO_DOUBLE, DoubleOverload.UINT64_TO_DOUBLE), STRING( + "string", StringOverload.STRING_TO_STRING, StringOverload.INT64_TO_STRING, StringOverload.DOUBLE_TO_STRING, @@ -252,51 +272,67 @@ public enum StandardFunction { StringOverload.TIMESTAMP_TO_STRING, StringOverload.DURATION_TO_STRING, StringOverload.UINT64_TO_STRING), - BYTES(BytesOverload.BYTES_TO_BYTES, BytesOverload.STRING_TO_BYTES), - DURATION(DurationOverload.DURATION_TO_DURATION, DurationOverload.STRING_TO_DURATION), + BYTES("bytes", BytesOverload.BYTES_TO_BYTES, BytesOverload.STRING_TO_BYTES), + DURATION( + "duration", DurationOverload.DURATION_TO_DURATION, DurationOverload.STRING_TO_DURATION), TIMESTAMP( + "timestamp", TimestampOverload.STRING_TO_TIMESTAMP, TimestampOverload.TIMESTAMP_TO_TIMESTAMP, TimestampOverload.INT64_TO_TIMESTAMP), - DYN(DynOverload.TO_DYN), - MATCHES(MatchesOverload.MATCHES, MatchesOverload.MATCHES_STRING), - CONTAINS(ContainsOverload.CONTAINS_STRING), - ENDS_WITH(EndsWithOverload.ENDS_WITH_STRING), - STARTS_WITH(StartsWithOverload.STARTS_WITH_STRING), + DYN("dyn", DynOverload.TO_DYN), + MATCHES("matches", MatchesOverload.MATCHES, MatchesOverload.MATCHES_STRING), + CONTAINS("contains", ContainsOverload.CONTAINS_STRING), + ENDS_WITH("endsWith", EndsWithOverload.ENDS_WITH_STRING), + STARTS_WITH("startsWith", StartsWithOverload.STARTS_WITH_STRING), // Date/time Functions GET_FULL_YEAR( - GetFullYearOverload.TIMESTAMP_TO_YEAR, GetFullYearOverload.TIMESTAMP_TO_YEAR_WITH_TZ), - GET_MONTH(GetMonthOverload.TIMESTAMP_TO_MONTH, GetMonthOverload.TIMESTAMP_TO_MONTH_WITH_TZ), + "getFullYear", + GetFullYearOverload.TIMESTAMP_TO_YEAR, + GetFullYearOverload.TIMESTAMP_TO_YEAR_WITH_TZ), + GET_MONTH( + "getMonth", + GetMonthOverload.TIMESTAMP_TO_MONTH, + GetMonthOverload.TIMESTAMP_TO_MONTH_WITH_TZ), GET_DAY_OF_YEAR( + "getDayOfYear", GetDayOfYearOverload.TIMESTAMP_TO_DAY_OF_YEAR, GetDayOfYearOverload.TIMESTAMP_TO_DAY_OF_YEAR_WITH_TZ), GET_DAY_OF_MONTH( + "getDayOfMonth", GetDayOfMonthOverload.TIMESTAMP_TO_DAY_OF_MONTH, GetDayOfMonthOverload.TIMESTAMP_TO_DAY_OF_MONTH_WITH_TZ), GET_DATE( + "getDate", GetDateOverload.TIMESTAMP_TO_DAY_OF_MONTH_1_BASED, GetDateOverload.TIMESTAMP_TO_DAY_OF_MONTH_1_BASED_WITH_TZ), GET_DAY_OF_WEEK( + "getDayOfWeek", GetDayOfWeekOverload.TIMESTAMP_TO_DAY_OF_WEEK, GetDayOfWeekOverload.TIMESTAMP_TO_DAY_OF_WEEK_WITH_TZ), GET_HOURS( + "getHours", GetHoursOverload.TIMESTAMP_TO_HOURS, GetHoursOverload.TIMESTAMP_TO_HOURS_WITH_TZ, GetHoursOverload.DURATION_TO_HOURS), GET_MINUTES( + "getMinutes", GetMinutesOverload.TIMESTAMP_TO_MINUTES, GetMinutesOverload.TIMESTAMP_TO_MINUTES_WITH_TZ, GetMinutesOverload.DURATION_TO_MINUTES), GET_SECONDS( + "getSeconds", GetSecondsOverload.TIMESTAMP_TO_SECONDS, GetSecondsOverload.TIMESTAMP_TO_SECONDS_WITH_TZ, GetSecondsOverload.DURATION_TO_SECONDS), GET_MILLISECONDS( + "getMilliseconds", GetMillisecondsOverload.TIMESTAMP_TO_MILLISECONDS, GetMillisecondsOverload.TIMESTAMP_TO_MILLISECONDS_WITH_TZ, GetMillisecondsOverload.DURATION_TO_MILLISECONDS), LESS( + Operator.LESS.getFunction(), LessOverload.LESS_BOOL, LessOverload.LESS_INT64, LessOverload.LESS_UINT64, @@ -312,6 +348,7 @@ public enum StandardFunction { LessOverload.LESS_UINT64_DOUBLE, LessOverload.LESS_DOUBLE_UINT64), LESS_EQUALS( + Operator.LESS_EQUALS.getFunction(), LessEqualsOverload.LESS_EQUALS_BOOL, LessEqualsOverload.LESS_EQUALS_INT64, LessEqualsOverload.LESS_EQUALS_UINT64, @@ -327,6 +364,7 @@ public enum StandardFunction { LessEqualsOverload.LESS_EQUALS_UINT64_DOUBLE, LessEqualsOverload.LESS_EQUALS_DOUBLE_UINT64), GREATER( + Operator.GREATER.getFunction(), GreaterOverload.GREATER_BOOL, GreaterOverload.GREATER_INT64, GreaterOverload.GREATER_UINT64, @@ -342,6 +380,7 @@ public enum StandardFunction { GreaterOverload.GREATER_UINT64_DOUBLE, GreaterOverload.GREATER_DOUBLE_UINT64), GREATER_EQUALS( + Operator.GREATER_EQUALS.getFunction(), GreaterEqualsOverload.GREATER_EQUALS_BOOL, GreaterEqualsOverload.GREATER_EQUALS_BYTES, GreaterEqualsOverload.GREATER_EQUALS_DOUBLE, @@ -357,9 +396,11 @@ public enum StandardFunction { GreaterEqualsOverload.GREATER_EQUALS_UINT64_DOUBLE, GreaterEqualsOverload.GREATER_EQUALS_DOUBLE_UINT64); + private final String functionName; private final ImmutableSet standardOverloads; - StandardFunction(CelStandardOverload... overloads) { + StandardFunction(String functionName, CelStandardOverload... overloads) { + this.functionName = functionName; this.standardOverloads = ImmutableSet.copyOf(overloads); } @@ -371,15 +412,25 @@ ImmutableSet getOverloads() { @VisibleForTesting ImmutableSet getOverloads() { - return standardOverloads; + return ImmutableSet.copyOf(standardOverloads.values()); } @Internal public ImmutableSet newFunctionBindings( RuntimeEquality runtimeEquality, CelOptions celOptions) { ImmutableSet.Builder builder = ImmutableSet.builder(); - for (CelStandardOverload overload : standardOverloads) { - builder.add(overload.newFunctionBinding(celOptions, runtimeEquality)); + + for (Map.Entry> entry : + standardOverloads.asMap().entrySet()) { + String functionName = entry.getKey(); + Collection overloads = entry.getValue(); + + ImmutableSet bindings = + overloads.stream() + .map(o -> o.newFunctionBinding(celOptions, runtimeEquality)) + .collect(toImmutableSet()); + + builder.addAll(CelFunctionBinding.groupOverloads(functionName, bindings)); } return builder.build(); @@ -454,39 +505,36 @@ public CelStandardFunctions build() { "You may only populate one of the following builder methods: includeFunctions," + " excludeFunctions or filterFunctions"); - ImmutableSet.Builder standardOverloadBuilder = ImmutableSet.builder(); + ImmutableMultimap.Builder standardOverloadBuilder = + ImmutableMultimap.builder(); for (StandardFunction standardFunction : StandardFunction.values()) { if (hasIncludeFunctions) { if (this.includeFunctions.contains(standardFunction)) { - standardOverloadBuilder.addAll(standardFunction.standardOverloads); + standardOverloadBuilder.putAll( + standardFunction.functionName, standardFunction.standardOverloads); } continue; } if (hasExcludeFunctions) { if (!this.excludeFunctions.contains(standardFunction)) { - standardOverloadBuilder.addAll(standardFunction.standardOverloads); + standardOverloadBuilder.putAll( + standardFunction.functionName, standardFunction.standardOverloads); } continue; } if (hasFilterFunction) { - ImmutableSet.Builder filteredOverloadsBuilder = - ImmutableSet.builder(); for (CelStandardOverload standardOverload : standardFunction.standardOverloads) { boolean includeOverload = functionFilter.include(standardFunction, standardOverload); if (includeOverload) { - standardOverloadBuilder.add(standardOverload); + standardOverloadBuilder.put(standardFunction.functionName, standardOverload); } } - ImmutableSet filteredOverloads = filteredOverloadsBuilder.build(); - if (!filteredOverloads.isEmpty()) { - standardOverloadBuilder.addAll(filteredOverloads); - } - continue; } - standardOverloadBuilder.addAll(standardFunction.standardOverloads); + standardOverloadBuilder.putAll( + standardFunction.functionName, standardFunction.standardOverloads); } return new CelStandardFunctions(standardOverloadBuilder.build()); @@ -511,7 +559,7 @@ static boolean isHeterogeneousComparison(CelStandardOverload overload) { return HETEROGENEOUS_COMPARISON_OPERATORS.contains(overload); } - private CelStandardFunctions(ImmutableSet standardOverloads) { + private CelStandardFunctions(ImmutableMultimap standardOverloads) { this.standardOverloads = standardOverloads; } } diff --git a/runtime/src/main/java/dev/cel/runtime/CelValueRuntimeTypeProvider.java b/runtime/src/main/java/dev/cel/runtime/CelValueRuntimeTypeProvider.java deleted file mode 100644 index 989d3b7be..000000000 --- a/runtime/src/main/java/dev/cel/runtime/CelValueRuntimeTypeProvider.java +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dev.cel.runtime; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.errorprone.annotations.Immutable; -import com.google.protobuf.MessageLite; -import dev.cel.common.CelErrorCode; -import dev.cel.common.CelRuntimeException; -import dev.cel.common.annotations.Internal; -import dev.cel.common.values.BaseProtoCelValueConverter; -import dev.cel.common.values.BaseProtoMessageValueProvider; -import dev.cel.common.values.CelValue; -import dev.cel.common.values.CelValueProvider; -import dev.cel.common.values.CombinedCelValueProvider; -import dev.cel.common.values.SelectableValue; -import java.util.Map; -import java.util.NoSuchElementException; - -/** Bridge between the old RuntimeTypeProvider and CelValueProvider APIs. */ -@Internal -@Immutable -final class CelValueRuntimeTypeProvider implements RuntimeTypeProvider { - - private final CelValueProvider valueProvider; - private final BaseProtoCelValueConverter protoCelValueConverter; - private static final BaseProtoCelValueConverter DEFAULT_CEL_VALUE_CONVERTER = - new BaseProtoCelValueConverter() {}; - - static CelValueRuntimeTypeProvider newInstance(CelValueProvider valueProvider) { - BaseProtoCelValueConverter converter = DEFAULT_CEL_VALUE_CONVERTER; - - // Find the underlying ProtoCelValueConverter. - // This is required because DefaultInterpreter works with a resolved protobuf messages directly - // in evaluation flow. - // A new runtime should not directly depend on protobuf, thus this will not be needed in the - // future. - if (valueProvider instanceof BaseProtoMessageValueProvider) { - converter = ((BaseProtoMessageValueProvider) valueProvider).protoCelValueConverter(); - } else if (valueProvider instanceof CombinedCelValueProvider) { - converter = - ((CombinedCelValueProvider) valueProvider) - .valueProviders().stream() - .filter(p -> p instanceof BaseProtoMessageValueProvider) - .map(p -> ((BaseProtoMessageValueProvider) p).protoCelValueConverter()) - .findFirst() - .orElse(DEFAULT_CEL_VALUE_CONVERTER); - } - - return new CelValueRuntimeTypeProvider(valueProvider, converter); - } - - @Override - public Object createMessage(String messageName, Map values) { - return maybeUnwrapCelValue( - valueProvider - .newValue(messageName, values) - .orElseThrow( - () -> - new NoSuchElementException( - String.format("cannot resolve '%s' as a message", messageName)))); - } - - @Override - public Object selectField(Object message, String fieldName) { - if (message instanceof Map) { - Map map = (Map) message; - if (map.containsKey(fieldName)) { - return map.get(fieldName); - } - - throw new CelRuntimeException( - new IllegalArgumentException(String.format("key '%s' is not present in map.", fieldName)), - CelErrorCode.ATTRIBUTE_NOT_FOUND); - } - - SelectableValue selectableValue = getSelectableValueOrThrow(message, fieldName); - Object value = selectableValue.select(fieldName); - - return maybeUnwrapCelValue(value); - } - - @Override - public Object hasField(Object message, String fieldName) { - SelectableValue selectableValue = getSelectableValueOrThrow(message, fieldName); - - return selectableValue.find(fieldName).isPresent(); - } - - @SuppressWarnings("unchecked") - private SelectableValue getSelectableValueOrThrow(Object obj, String fieldName) { - Object convertedCelValue = protoCelValueConverter.toRuntimeValue(obj); - - if (!(convertedCelValue instanceof SelectableValue)) { - throwInvalidFieldSelection(fieldName); - } - - return (SelectableValue) convertedCelValue; - } - - @Override - public Object adapt(String messageName, Object message) { - if (message instanceof CelUnknownSet) { - return message; // CelUnknownSet is handled specially for iterative evaluation. No need to - // adapt to CelValue. - } - - if (message instanceof MessageLite.Builder) { - message = ((MessageLite.Builder) message).build(); - } - - if (message instanceof MessageLite) { - return maybeUnwrapCelValue(protoCelValueConverter.toRuntimeValue(message)); - } - - return message; - } - - /** - * DefaultInterpreter cannot handle CelValue and instead expects plain Java objects. - * - *

This will become unnecessary once we introduce a rewrite of a Cel runtime. - */ - private Object maybeUnwrapCelValue(Object object) { - if (object instanceof CelValue) { - return protoCelValueConverter.unwrap((CelValue) object); - } - return object; - } - - private static void throwInvalidFieldSelection(String fieldName) { - throw new CelRuntimeException( - new IllegalArgumentException( - String.format( - "Error resolving field '%s'. Field selections must be performed on messages or" - + " maps.", - fieldName)), - CelErrorCode.ATTRIBUTE_NOT_FOUND); - } - - private CelValueRuntimeTypeProvider( - CelValueProvider valueProvider, BaseProtoCelValueConverter protoCelValueConverter) { - this.valueProvider = checkNotNull(valueProvider); - this.protoCelValueConverter = checkNotNull(protoCelValueConverter); - } -} diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java b/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java index 35ce243b3..95c4ba01e 100644 --- a/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java +++ b/runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java @@ -19,11 +19,13 @@ import com.google.auto.value.AutoBuilder; import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelErrorCode; import dev.cel.common.annotations.Internal; +import dev.cel.runtime.FunctionBindingImpl.DynamicDispatchOverload; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -127,7 +129,7 @@ public abstract static class Builder { @CanIgnoreReturnValue public Builder addOverload( String overloadId, - List> argTypes, + ImmutableList> argTypes, boolean isStrict, CelFunctionOverload overload) { checkNotNull(overloadId); @@ -136,13 +138,35 @@ public Builder addOverload( checkNotNull(overload); overloadsBuilder() - .put(overloadId, CelResolvedOverload.of(overloadId, overload, isStrict, argTypes)); + .put( + overloadId, + CelResolvedOverload.of( + overloadId, + args -> guardedOp(overloadId, args, argTypes, isStrict, overload), + isStrict, + argTypes)); return this; } public abstract DefaultDispatcher build(); } + /** Creates an invocation guard around the overload definition. */ + private static Object guardedOp( + String functionName, + Object[] args, + ImmutableList> argTypes, + boolean isStrict, + CelFunctionOverload overload) + throws CelEvaluationException { + if (overload instanceof DynamicDispatchOverload + || CelResolvedOverload.canHandle(args, argTypes, isStrict)) { + return overload.apply(args); + } + + throw new IllegalArgumentException("No matching overload for function: " + functionName); + } + DefaultDispatcher(ImmutableMap overloads) { this.overloads = overloads; } diff --git a/runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java b/runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java index b554ce41a..b4f373e76 100644 --- a/runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java @@ -15,6 +15,8 @@ package dev.cel.runtime; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.errorprone.annotations.Immutable; @Immutable @@ -58,4 +60,86 @@ public boolean isStrict() { this.definition = definition; this.isStrict = isStrict; } + + static ImmutableSet groupOverloadsToFunction( + String functionName, ImmutableSet overloadBindings) { + if (overloadBindings.size() == 1) { + CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings); + FunctionBindingImpl functionBindingImpl = + new FunctionBindingImpl( + functionName, + singleBinding.getArgTypes(), + singleBinding.getDefinition(), + singleBinding.isStrict()); + + return ImmutableSet.of(singleBinding, functionBindingImpl); + } + + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (CelFunctionBinding binding : overloadBindings) { + builder.add(binding); + } + + // Setup dynamic dispatch + builder.add(new DynamicDispatchBinding(functionName, overloadBindings)); + + return builder.build(); + } + + @Immutable + static final class DynamicDispatchBinding implements CelFunctionBinding { + + private final boolean isStrict; + private final DynamicDispatchOverload dynamicDispatchOverload; + + @Override + public String getOverloadId() { + return dynamicDispatchOverload.functionName; + } + + @Override + public ImmutableList> getArgTypes() { + return ImmutableList.of(); + } + + @Override + public CelFunctionOverload getDefinition() { + return dynamicDispatchOverload; + } + + @Override + public boolean isStrict() { + return isStrict; + } + + private DynamicDispatchBinding( + String functionName, ImmutableSet overloadBindings) { + this.isStrict = overloadBindings.stream().allMatch(CelFunctionBinding::isStrict); + this.dynamicDispatchOverload = new DynamicDispatchOverload(functionName, overloadBindings); + } + } + + @Immutable + static final class DynamicDispatchOverload implements CelFunctionOverload { + private final String functionName; + private final ImmutableSet overloadBindings; + + @Override + public Object apply(Object[] args) throws CelEvaluationException { + for (CelFunctionBinding overload : overloadBindings) { + // TODO: Pull canHandle to somewhere else? + if (CelResolvedOverload.canHandle(args, overload.getArgTypes(), overload.isStrict())) { + return overload.getDefinition().apply(args); + } + } + + throw new IllegalArgumentException("No matching overload for function: " + functionName); + } + + private DynamicDispatchOverload( + String functionName, ImmutableSet overloadBindings) { + this.functionName = functionName; + this.overloadBindings = overloadBindings; + } + } } diff --git a/runtime/src/main/java/dev/cel/runtime/LiteProgramImpl.java b/runtime/src/main/java/dev/cel/runtime/LiteProgramImpl.java index e54f848b7..b6057269f 100644 --- a/runtime/src/main/java/dev/cel/runtime/LiteProgramImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/LiteProgramImpl.java @@ -40,6 +40,11 @@ public Object eval(Map mapValue, CelFunctionResolver lateBoundFunctio return interpretable().eval(Activation.copyOf(mapValue), lateBoundFunctionResolver); } + @Override + public Object eval(CelVariableResolver resolver) throws CelEvaluationException { + throw new UnsupportedOperationException("Unsupported"); + } + static Program plan(Interpretable interpretable) { return new AutoValue_LiteProgramImpl(interpretable); } diff --git a/runtime/src/main/java/dev/cel/runtime/LiteRuntimeImpl.java b/runtime/src/main/java/dev/cel/runtime/LiteRuntimeImpl.java index 45c322da9..45cc4503f 100644 --- a/runtime/src/main/java/dev/cel/runtime/LiteRuntimeImpl.java +++ b/runtime/src/main/java/dev/cel/runtime/LiteRuntimeImpl.java @@ -15,7 +15,6 @@ package dev.cel.runtime; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; @@ -23,29 +22,37 @@ import com.google.common.collect.ImmutableSet; import javax.annotation.concurrent.ThreadSafe; import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelContainer; import dev.cel.common.CelOptions; +import dev.cel.common.types.CelTypeProvider; +import dev.cel.common.types.DefaultTypeProvider; +import dev.cel.common.values.CelValue; +import dev.cel.common.values.CelValueConverter; import dev.cel.common.values.CelValueProvider; +import dev.cel.runtime.planner.ProgramPlanner; import dev.cel.runtime.standard.CelStandardFunction; import java.util.Arrays; import java.util.HashMap; +import java.util.Map; import java.util.Optional; @ThreadSafe final class LiteRuntimeImpl implements CelLiteRuntime { - private final Interpreter interpreter; + private final ProgramPlanner planner; private final CelOptions celOptions; private final ImmutableList customFunctionBindings; private final ImmutableSet celStandardFunctions; + private final CelTypeProvider celTypeProvider; private final CelValueProvider celValueProvider; + private final CelContainer celContainer; // This does not affect the evaluation behavior in any manner. // CEL-Internal-4 private final ImmutableSet runtimeLibraries; @Override - public Program createProgram(CelAbstractSyntaxTree ast) { - checkState(ast.isChecked(), "programs must be created from checked expressions"); - return LiteProgramImpl.plan(interpreter.createInterpretable(ast)); + public Program createProgram(CelAbstractSyntaxTree ast) throws CelEvaluationException { + return planner.plan(ast); } @Override @@ -55,22 +62,29 @@ public CelLiteRuntimeBuilder toRuntimeBuilder() { .setOptions(celOptions) .setStandardFunctions(celStandardFunctions) .addFunctionBindings(customFunctionBindings) - .addLibraries(runtimeLibraries); + .addLibraries(runtimeLibraries) + .setContainer(celContainer); if (celValueProvider != null) { builder.setValueProvider(celValueProvider); } + if (celTypeProvider != null) { + builder.setTypeProvider(celTypeProvider); + } + return builder; } static final class Builder implements CelLiteRuntimeBuilder { + private CelContainer container; // Following is visible to test `toBuilder`. @VisibleForTesting CelOptions celOptions; @VisibleForTesting final HashMap customFunctionBindings; @VisibleForTesting final ImmutableSet.Builder runtimeLibrariesBuilder; @VisibleForTesting final ImmutableSet.Builder standardFunctionBuilder; + @VisibleForTesting CelTypeProvider celTypeProvider; @VisibleForTesting CelValueProvider celValueProvider; @Override @@ -102,6 +116,12 @@ public CelLiteRuntimeBuilder addFunctionBindings(Iterable bi return this; } + @Override + public CelLiteRuntimeBuilder setTypeProvider(CelTypeProvider celTypeProvider) { + this.celTypeProvider = celTypeProvider; + return this; + } + @Override public CelLiteRuntimeBuilder setValueProvider(CelValueProvider celValueProvider) { this.celValueProvider = celValueProvider; @@ -119,12 +139,15 @@ public CelLiteRuntimeBuilder addLibraries(Iterable Optional.empty(); + this.celOptions = CelOptions.DEFAULT; + this.celValueProvider = + new CelValueProvider() { + @Override + public Optional newValue(String structType, Map fields) { + return Optional.empty(); + } + + @Override + public CelValueConverter celValueConverter() { + return new CelValueConverter() { + @Override + public Object unwrap(CelValue celValue) { + return super.unwrap(celValue); + } + }; + } + }; this.customFunctionBindings = new HashMap<>(); this.standardFunctionBuilder = ImmutableSet.builder(); this.runtimeLibrariesBuilder = ImmutableSet.builder(); + this.container = CelContainer.newBuilder().build(); } } @@ -217,17 +264,21 @@ static CelLiteRuntimeBuilder newBuilder() { } private LiteRuntimeImpl( - Interpreter interpreter, CelOptions celOptions, Iterable customFunctionBindings, ImmutableSet celStandardFunctions, ImmutableSet runtimeLibraries, - CelValueProvider celValueProvider) { - this.interpreter = interpreter; + CelValueProvider celValueProvider, + CelTypeProvider celTypeProvider, + CelContainer celContainer, + ProgramPlanner planner) { this.celOptions = celOptions; this.customFunctionBindings = ImmutableList.copyOf(customFunctionBindings); this.celStandardFunctions = celStandardFunctions; this.runtimeLibraries = runtimeLibraries; this.celValueProvider = celValueProvider; + this.celTypeProvider = celTypeProvider; + this.celContainer = celContainer; + this.planner = planner; } } diff --git a/runtime/src/main/java/dev/cel/runtime/Program.java b/runtime/src/main/java/dev/cel/runtime/Program.java index 3eb074317..88eeef10a 100644 --- a/runtime/src/main/java/dev/cel/runtime/Program.java +++ b/runtime/src/main/java/dev/cel/runtime/Program.java @@ -33,4 +33,7 @@ public interface Program { */ Object eval(Map mapValue, CelFunctionResolver lateBoundFunctionResolver) throws CelEvaluationException; + + /** Evaluate a compiled program with a custom variable {@code resolver}. */ + Object eval(CelVariableResolver resolver) throws CelEvaluationException; } diff --git a/runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel index b99b41fd5..6d8c01b9d 100644 --- a/runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel @@ -1,4 +1,5 @@ load("@rules_java//java:defs.bzl", "java_library") +load("//:cel_android_rules.bzl", "cel_android_library") package( default_applicable_licenses = ["//:license"], @@ -55,6 +56,53 @@ java_library( ], ) +cel_android_library( + name = "program_planner_android", + srcs = ["ProgramPlanner.java"], + tags = [ + ], + deps = [ + ":attribute_android", + ":error_metadata_android", + ":eval_and_android", + ":eval_attribute_android", + ":eval_conditional_android", + ":eval_const_android", + ":eval_create_list_android", + ":eval_create_map_android", + ":eval_create_struct_android", + ":eval_fold_android", + ":eval_or_android", + ":eval_test_only_android", + ":eval_unary_android", + ":eval_var_args_call_android", + ":eval_zero_arity_android", + ":interpretable_attribute_android", + ":planned_interpretable_android", + ":planned_program_android", + ":qualifier_android", + ":string_qualifier_android", + "//:auto_value", + "//common:cel_ast_android", + "//common:container_android", + "//common:operator_android", + "//common:options", + "//common/annotations", + "//common/ast:ast_android", + "//common/types:type_providers_android", + "//common/types:types_android", + "//common/values:cel_value_provider_android", + "//common/values:values_android", + "//runtime:dispatcher_android", + "//runtime:evaluation_exception", + "//runtime:evaluation_exception_builder", + "//runtime:program_android", + "//runtime:resolved_overload_android", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "planned_program", srcs = ["PlannedProgram.java"], @@ -67,13 +115,36 @@ java_library( "//common:options", "//common:runtime_exception", "//common/values", - "//runtime", "//runtime:activation", "//runtime:evaluation_exception", "//runtime:evaluation_exception_builder", "//runtime:function_resolver", "//runtime:interpretable", "//runtime:program", + "//runtime:variable_resolver", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + +cel_android_library( + name = "planned_program_android", + srcs = ["PlannedProgram.java"], + deps = [ + ":error_metadata_android", + ":execution_frame_android", + ":planned_interpretable_android", + ":strict_error_exception", + "//:auto_value", + "//common:options", + "//common:runtime_exception", + "//common/values:values_android", + "//runtime:activation_android", + "//runtime:evaluation_exception", + "//runtime:evaluation_exception_builder", + "//runtime:interpretable_android", + "//runtime:program_android", + "//runtime:variable_resolver", + "//runtime/src/main/java/dev/cel/runtime:function_resolver_android", "@maven//:com_google_errorprone_error_prone_annotations", ], ) @@ -92,6 +163,20 @@ java_library( ], ) +cel_android_library( + name = "eval_const_android", + srcs = ["EvalConstant.java"], + deps = [ + ":execution_frame_android", + ":planned_interpretable_android", + "//common/values:cel_byte_string", + "//common/values:values_android", + "//runtime:interpretable_android", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "interpretable_attribute", srcs = ["InterpretableAttribute.java"], @@ -102,16 +187,28 @@ java_library( ], ) +cel_android_library( + name = "interpretable_attribute_android", + srcs = ["InterpretableAttribute.java"], + deps = [ + ":planned_interpretable_android", + ":qualifier_android", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + +ATTRIBUTE_SOURCES = [ + "Attribute.java", + "AttributeFactory.java", + "MaybeAttribute.java", + "MissingAttribute.java", + "NamespacedAttribute.java", + "RelativeAttribute.java", +] + java_library( name = "attribute", - srcs = [ - "Attribute.java", - "AttributeFactory.java", - "MaybeAttribute.java", - "MissingAttribute.java", - "NamespacedAttribute.java", - "RelativeAttribute.java", - ], + srcs = ATTRIBUTE_SOURCES, deps = [ ":eval_helpers", ":execution_frame", @@ -129,6 +226,26 @@ java_library( ], ) +cel_android_library( + name = "attribute_android", + srcs = ATTRIBUTE_SOURCES, + deps = [ + ":eval_helpers_android", + ":execution_frame_android", + ":planned_interpretable_android", + ":qualifier_android", + "//common/exceptions:attribute_not_found", + "//common/src/main/java/dev/cel/common:container_android", + "//common/types:type_providers_android", + "//common/types:types_android", + "//common/values:cel_value_android", + "//common/values:values_android", + "//runtime:interpretable_android", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "qualifier", srcs = ["Qualifier.java"], @@ -137,6 +254,14 @@ java_library( ], ) +cel_android_library( + name = "qualifier_android", + srcs = ["Qualifier.java"], + deps = [ + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + java_library( name = "presence_test_qualifier", srcs = ["PresenceTestQualifier.java"], @@ -144,6 +269,18 @@ java_library( ":attribute", ":qualifier", "//common/values", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + +cel_android_library( + name = "presence_test_qualifier_android", + srcs = ["PresenceTestQualifier.java"], + deps = [ + ":attribute_android", + ":qualifier_android", + "//common/values:values_android", + "@maven//:com_google_errorprone_error_prone_annotations", ], ) @@ -154,6 +291,18 @@ java_library( ":qualifier", "//common/exceptions:attribute_not_found", "//common/values", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + +cel_android_library( + name = "string_qualifier_android", + srcs = ["StringQualifier.java"], + deps = [ + ":qualifier_android", + "//common/exceptions:attribute_not_found", + "//common/values:values_android", + "@maven//:com_google_errorprone_error_prone_annotations", ], ) @@ -171,6 +320,19 @@ java_library( ], ) +cel_android_library( + name = "eval_attribute_android", + srcs = ["EvalAttribute.java"], + deps = [ + ":attribute_android", + ":execution_frame_android", + ":interpretable_attribute_android", + ":qualifier_android", + "//runtime:interpretable_android", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + java_library( name = "eval_test_only", srcs = ["EvalTestOnly.java"], @@ -185,6 +347,20 @@ java_library( ], ) +cel_android_library( + name = "eval_test_only_android", + srcs = ["EvalTestOnly.java"], + deps = [ + ":execution_frame_android", + ":interpretable_attribute_android", + ":presence_test_qualifier_android", + ":qualifier_android", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + java_library( name = "eval_zero_arity", srcs = ["EvalZeroArity.java"], @@ -197,6 +373,18 @@ java_library( ], ) +cel_android_library( + name = "eval_zero_arity_android", + srcs = ["EvalZeroArity.java"], + deps = [ + ":execution_frame_android", + ":planned_interpretable_android", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "//runtime:resolved_overload_android", + ], +) + java_library( name = "eval_unary", srcs = ["EvalUnary.java"], @@ -210,6 +398,19 @@ java_library( ], ) +cel_android_library( + name = "eval_unary_android", + srcs = ["EvalUnary.java"], + deps = [ + ":eval_helpers_android", + ":execution_frame_android", + ":planned_interpretable_android", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "//runtime:resolved_overload_android", + ], +) + java_library( name = "eval_var_args_call", srcs = ["EvalVarArgsCall.java"], @@ -223,6 +424,19 @@ java_library( ], ) +cel_android_library( + name = "eval_var_args_call_android", + srcs = ["EvalVarArgsCall.java"], + deps = [ + ":eval_helpers_android", + ":execution_frame_android", + ":planned_interpretable_android", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "//runtime:resolved_overload_android", + ], +) + java_library( name = "eval_or", srcs = ["EvalOr.java"], @@ -236,6 +450,19 @@ java_library( ], ) +cel_android_library( + name = "eval_or_android", + srcs = ["EvalOr.java"], + deps = [ + ":eval_helpers_android", + ":execution_frame_android", + ":planned_interpretable_android", + "//common/values:values_android", + "//runtime:interpretable_android", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "eval_and", srcs = ["EvalAnd.java"], @@ -249,6 +476,19 @@ java_library( ], ) +cel_android_library( + name = "eval_and_android", + srcs = ["EvalAnd.java"], + deps = [ + ":eval_helpers_android", + ":execution_frame_android", + ":planned_interpretable_android", + "//common/values:values_android", + "//runtime:interpretable_android", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "eval_conditional", srcs = ["EvalConditional.java"], @@ -261,6 +501,18 @@ java_library( ], ) +cel_android_library( + name = "eval_conditional_android", + srcs = ["EvalConditional.java"], + deps = [ + ":execution_frame_android", + ":planned_interpretable_android", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "eval_create_struct", srcs = ["EvalCreateStruct.java"], @@ -277,6 +529,21 @@ java_library( ], ) +cel_android_library( + name = "eval_create_struct_android", + srcs = ["EvalCreateStruct.java"], + deps = [ + ":execution_frame_android", + ":planned_interpretable_android", + "//common/types:types_android", + "//common/values:cel_value_provider_android", + "//common/values:values_android", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) + java_library( name = "eval_create_list", srcs = ["EvalCreateList.java"], @@ -290,6 +557,19 @@ java_library( ], ) +cel_android_library( + name = "eval_create_list_android", + srcs = ["EvalCreateList.java"], + deps = [ + ":execution_frame_android", + ":planned_interpretable_android", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "eval_create_map", srcs = ["EvalCreateMap.java"], @@ -303,6 +583,19 @@ java_library( ], ) +cel_android_library( + name = "eval_create_map_android", + srcs = ["EvalCreateMap.java"], + deps = [ + ":execution_frame_android", + ":planned_interpretable_android", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "eval_fold", srcs = ["EvalFold.java"], @@ -318,6 +611,21 @@ java_library( ], ) +cel_android_library( + name = "eval_fold_android", + srcs = ["EvalFold.java"], + deps = [ + ":execution_frame_android", + ":planned_interpretable_android", + "//runtime:concatenated_list_view", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:org_jspecify_jspecify", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "execution_frame", srcs = ["ExecutionFrame.java"], @@ -329,6 +637,17 @@ java_library( ], ) +cel_android_library( + name = "execution_frame_android", + srcs = ["ExecutionFrame.java"], + deps = [ + "//common:options", + "//common/exceptions:iteration_budget_exceeded", + "//runtime:interpretable_android", + "@maven//:org_jspecify_jspecify", + ], +) + java_library( name = "eval_helpers", srcs = ["EvalHelpers.java"], @@ -343,9 +662,24 @@ java_library( ], ) +cel_android_library( + name = "eval_helpers_android", + srcs = ["EvalHelpers.java"], + deps = [ + ":execution_frame_android", + ":planned_interpretable_android", + ":strict_error_exception", + "//common:error_codes", + "//common:runtime_exception", + "//common/values:values_android", + "//runtime:interpretable_android", + ], +) + java_library( name = "strict_error_exception", srcs = ["StrictErrorException.java"], + # used_by_android deps = [ "//common:error_codes", "//common:runtime_exception", @@ -362,6 +696,16 @@ java_library( ], ) +cel_android_library( + name = "error_metadata_android", + srcs = ["ErrorMetadata.java"], + deps = [ + "//runtime:metadata", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven_android//:com_google_guava_guava", + ], +) + java_library( name = "planned_interpretable", srcs = ["PlannedInterpretable.java"], @@ -372,3 +716,14 @@ java_library( "@maven//:com_google_errorprone_error_prone_annotations", ], ) + +cel_android_library( + name = "planned_interpretable_android", + srcs = ["PlannedInterpretable.java"], + deps = [ + ":execution_frame_android", + "//runtime:evaluation_exception", + "//runtime:interpretable_android", + "@maven//:com_google_errorprone_error_prone_annotations", + ], +) diff --git a/runtime/src/main/java/dev/cel/runtime/planner/MissingAttribute.java b/runtime/src/main/java/dev/cel/runtime/planner/MissingAttribute.java index 596d1bae4..b64c3282c 100644 --- a/runtime/src/main/java/dev/cel/runtime/planner/MissingAttribute.java +++ b/runtime/src/main/java/dev/cel/runtime/planner/MissingAttribute.java @@ -15,10 +15,12 @@ package dev.cel.runtime.planner; import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.Immutable; import dev.cel.common.exceptions.CelAttributeNotFoundException; import dev.cel.runtime.GlobalResolver; /** Represents a missing attribute that is surfaced while resolving a struct field or a map key. */ +@Immutable final class MissingAttribute implements Attribute { private final ImmutableSet missingAttributes; diff --git a/runtime/src/main/java/dev/cel/runtime/planner/PlannedProgram.java b/runtime/src/main/java/dev/cel/runtime/planner/PlannedProgram.java index 646ad6c85..b9a74b60b 100644 --- a/runtime/src/main/java/dev/cel/runtime/planner/PlannedProgram.java +++ b/runtime/src/main/java/dev/cel/runtime/planner/PlannedProgram.java @@ -23,6 +23,7 @@ import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelEvaluationExceptionBuilder; import dev.cel.runtime.CelFunctionResolver; +import dev.cel.runtime.CelVariableResolver; import dev.cel.runtime.GlobalResolver; import dev.cel.runtime.Program; import java.util.Map; @@ -52,6 +53,11 @@ public Object eval(Map mapValue, CelFunctionResolver lateBoundFunctio throw new UnsupportedOperationException("Late bound functions not supported yet"); } + @Override + public Object eval(CelVariableResolver resolver) throws CelEvaluationException { + return evalOrThrow(interpretable(), ((name) -> resolver.find(name).orElse(null))); + } + private Object evalOrThrow(PlannedInterpretable interpretable, GlobalResolver resolver) throws CelEvaluationException { try { diff --git a/runtime/src/main/java/dev/cel/runtime/planner/PresenceTestQualifier.java b/runtime/src/main/java/dev/cel/runtime/planner/PresenceTestQualifier.java index 973182b9b..b527719f7 100644 --- a/runtime/src/main/java/dev/cel/runtime/planner/PresenceTestQualifier.java +++ b/runtime/src/main/java/dev/cel/runtime/planner/PresenceTestQualifier.java @@ -16,10 +16,12 @@ import static dev.cel.runtime.planner.MissingAttribute.newMissingAttribute; +import com.google.errorprone.annotations.Immutable; import dev.cel.common.values.SelectableValue; import java.util.Map; /** A qualifier for presence testing a field or a map key. */ +@Immutable final class PresenceTestQualifier implements Qualifier { @SuppressWarnings("Immutable") diff --git a/runtime/src/main/java/dev/cel/runtime/planner/ProgramPlanner.java b/runtime/src/main/java/dev/cel/runtime/planner/ProgramPlanner.java index 1559b8482..807230f2a 100644 --- a/runtime/src/main/java/dev/cel/runtime/planner/ProgramPlanner.java +++ b/runtime/src/main/java/dev/cel/runtime/planner/ProgramPlanner.java @@ -18,7 +18,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.CheckReturnValue; -import javax.annotation.concurrent.ThreadSafe; +import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelAbstractSyntaxTree; import dev.cel.common.CelContainer; import dev.cel.common.CelOptions; @@ -53,10 +53,9 @@ * {@code ProgramPlanner} resolves functions, types, and identifiers at plan time given a * parsed-only or a type-checked expression. */ -@ThreadSafe +@Immutable @Internal public final class ProgramPlanner { - private final CelTypeProvider typeProvider; private final CelValueProvider valueProvider; private final DefaultDispatcher dispatcher; @@ -217,6 +216,7 @@ private PlannedInterpretable planCall(CelExpr expr, PlannerContext ctx) { } } + // TODO: Handle all specialized calls (logical operators, conditionals, equals etc) CelResolvedOverload resolvedOverload = null; if (resolvedFunction.overloadId().isPresent()) { resolvedOverload = dispatcher.findOverload(resolvedFunction.overloadId().get()).orElse(null); diff --git a/runtime/src/main/java/dev/cel/runtime/planner/RelativeAttribute.java b/runtime/src/main/java/dev/cel/runtime/planner/RelativeAttribute.java index a913849f6..1049afc64 100644 --- a/runtime/src/main/java/dev/cel/runtime/planner/RelativeAttribute.java +++ b/runtime/src/main/java/dev/cel/runtime/planner/RelativeAttribute.java @@ -16,6 +16,7 @@ import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; +import dev.cel.common.values.CelValue; import dev.cel.common.values.CelValueConverter; import dev.cel.runtime.GlobalResolver; @@ -40,6 +41,9 @@ public Object resolve(GlobalResolver ctx, ExecutionFrame frame) { } // TODO: Handle unknowns + if (obj instanceof CelValue) { + obj = celValueConverter.unwrap((CelValue) obj); + } return obj; } diff --git a/runtime/src/main/java/dev/cel/runtime/planner/StringQualifier.java b/runtime/src/main/java/dev/cel/runtime/planner/StringQualifier.java index 4ceaa0e51..25503e65b 100644 --- a/runtime/src/main/java/dev/cel/runtime/planner/StringQualifier.java +++ b/runtime/src/main/java/dev/cel/runtime/planner/StringQualifier.java @@ -14,11 +14,13 @@ package dev.cel.runtime.planner; +import com.google.errorprone.annotations.Immutable; import dev.cel.common.exceptions.CelAttributeNotFoundException; import dev.cel.common.values.SelectableValue; import java.util.Map; /** A qualifier that accesses fields or map keys using a string identifier. */ +@Immutable final class StringQualifier implements Qualifier { private final String value; diff --git a/runtime/src/main/java/dev/cel/runtime/standard/AddOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/AddOperator.java index 783ddd81a..82bb308d1 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/AddOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/AddOperator.java @@ -14,6 +14,7 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.ADD; import static dev.cel.runtime.standard.ArithmeticHelpers.getArithmeticErrorCode; import com.google.common.collect.ImmutableSet; @@ -170,6 +171,6 @@ public CelFunctionBinding newFunctionBinding( } private AddOperator(ImmutableSet overloads) { - super(overloads); + super(ADD.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/standard/BUILD.bazel index 041d07dea..ed189014f 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/BUILD.bazel +++ b/runtime/src/main/java/dev/cel/runtime/standard/BUILD.bazel @@ -48,6 +48,7 @@ java_library( ":arithmetic_helpers", ":standard_function", ":standard_overload", + "//common:operator", "//common:options", "//common:runtime_exception", "//common/internal:date_time_helpers", @@ -70,6 +71,7 @@ cel_android_library( ":arithmetic_helpers", ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common:runtime_exception", "//common/internal:date_time_helpers_android", @@ -92,6 +94,7 @@ java_library( ":arithmetic_helpers", ":standard_function", ":standard_overload", + "//common:operator", "//common:options", "//common:runtime_exception", "//common/internal:date_time_helpers", @@ -113,6 +116,7 @@ cel_android_library( ":arithmetic_helpers", ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common:runtime_exception", "//common/internal:date_time_helpers_android", @@ -364,6 +368,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//runtime:function_binding", "//runtime:runtime_equality", @@ -380,6 +385,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//runtime:function_binding_android", "//runtime:runtime_equality_android", @@ -742,6 +748,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//common/internal:comparison_functions", "//common/internal:proto_time_utils", @@ -763,6 +770,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common/internal:comparison_functions_android", "//common/internal:proto_time_utils_android", @@ -782,6 +790,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//common/internal:comparison_functions", "//common/internal:proto_time_utils", @@ -803,6 +812,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common/internal:comparison_functions_android", "//common/internal:proto_time_utils_android", @@ -822,6 +832,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//runtime:function_binding", "//runtime:runtime_equality", @@ -838,6 +849,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//runtime:function_binding_android", "//runtime:runtime_equality_android", @@ -852,6 +864,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//runtime:function_binding", "//runtime:runtime_equality", @@ -869,6 +882,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//runtime:function_binding_android", "//runtime:runtime_equality_android", @@ -924,6 +938,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//common/internal:comparison_functions", "//common/internal:proto_time_utils", @@ -945,6 +960,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common/internal:comparison_functions_android", "//common/internal:proto_time_utils_android", @@ -964,6 +980,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//common/internal:comparison_functions", "//common/internal:proto_time_utils", @@ -985,6 +1002,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common/internal:comparison_functions_android", "//common/internal:proto_time_utils_android", @@ -1004,6 +1022,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//runtime:function_binding", "//runtime:runtime_equality", @@ -1020,6 +1039,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//runtime:function_binding_android", "//runtime:runtime_equality_android", @@ -1071,6 +1091,7 @@ java_library( deps = [ ":arithmetic_helpers", ":standard_overload", + "//common:operator", "//common:options", "//common:runtime_exception", "//runtime:function_binding", @@ -1090,6 +1111,7 @@ cel_android_library( ":arithmetic_helpers", ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common:runtime_exception", "//runtime:function_binding_android", @@ -1107,6 +1129,7 @@ java_library( deps = [ ":arithmetic_helpers", ":standard_overload", + "//common:operator", "//common:options", "//common:runtime_exception", "//runtime:function_binding", @@ -1126,6 +1149,7 @@ cel_android_library( ":arithmetic_helpers", ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common:runtime_exception", "//runtime:function_binding_android", @@ -1143,6 +1167,7 @@ java_library( deps = [ ":arithmetic_helpers", ":standard_overload", + "//common:operator", "//common:options", "//common:runtime_exception", "//runtime:function_binding", @@ -1162,6 +1187,7 @@ cel_android_library( ":arithmetic_helpers", ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common:runtime_exception", "//runtime:function_binding_android", @@ -1179,6 +1205,7 @@ java_library( deps = [ ":arithmetic_helpers", ":standard_overload", + "//common:operator", "//common:options", "//common:runtime_exception", "//runtime:function_binding", @@ -1198,6 +1225,7 @@ cel_android_library( ":arithmetic_helpers", ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//common:runtime_exception", "//runtime:function_binding_android", @@ -1214,6 +1242,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//runtime:function_binding", "//runtime:runtime_equality", @@ -1230,6 +1259,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//runtime:function_binding_android", "//runtime:runtime_equality_android", @@ -1426,6 +1456,7 @@ java_library( ], deps = [ ":standard_overload", + "//common:operator", "//common:options", "//runtime:function_binding", "//runtime:internal_function_binder", @@ -1443,6 +1474,7 @@ cel_android_library( deps = [ ":standard_function_android", ":standard_overload_android", + "//common:operator_android", "//common:options", "//runtime:function_binding_android", "//runtime:internal_function_binder_android", diff --git a/runtime/src/main/java/dev/cel/runtime/standard/BoolFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/BoolFunction.java index 5d9d3919c..60cc8b156 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/BoolFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/BoolFunction.java @@ -87,6 +87,6 @@ public CelFunctionBinding newFunctionBinding( } private BoolFunction(ImmutableSet overloads) { - super(overloads); + super("bool", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/BytesFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/BytesFunction.java index e2a5230ce..7e3ab2b2f 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/BytesFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/BytesFunction.java @@ -76,6 +76,6 @@ public CelFunctionBinding newFunctionBinding( } private BytesFunction(ImmutableSet overloads) { - super(overloads); + super("bytes", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/CelStandardFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/CelStandardFunction.java index bde6fa6b5..117730e62 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/CelStandardFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/CelStandardFunction.java @@ -14,8 +14,10 @@ package dev.cel.runtime.standard; -import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableSet.toImmutableSet; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.errorprone.annotations.Immutable; import dev.cel.common.CelOptions; @@ -28,20 +30,23 @@ */ @Immutable public abstract class CelStandardFunction { + private final String name; private final ImmutableSet overloads; public ImmutableSet newFunctionBindings( CelOptions celOptions, RuntimeEquality runtimeEquality) { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for (CelStandardOverload overload : overloads) { - builder.add(overload.newFunctionBinding(celOptions, runtimeEquality)); - } + ImmutableSet overloadBindings = + overloads.stream() + .map(overload -> overload.newFunctionBinding(celOptions, runtimeEquality)) + .collect(toImmutableSet()); - return builder.build(); + return CelFunctionBinding.groupOverloads(name, overloadBindings); } - CelStandardFunction(ImmutableSet overloads) { - checkState(!overloads.isEmpty(), "At least 1 overload must be provided."); + CelStandardFunction(String name, ImmutableSet overloads) { + checkArgument(!Strings.isNullOrEmpty(name), "Function name must be provided."); + checkArgument(!overloads.isEmpty(), "At least 1 overload must be provided."); this.overloads = overloads; + this.name = name; } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/ContainsFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/ContainsFunction.java index 21f8390b9..bf3f9f7a7 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/ContainsFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/ContainsFunction.java @@ -58,6 +58,6 @@ public CelFunctionBinding newFunctionBinding( } private ContainsFunction(ImmutableSet overloads) { - super(overloads); + super("contains", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/DivideOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/DivideOperator.java index b9fdad33c..a9c36b0ff 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/DivideOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/DivideOperator.java @@ -14,6 +14,7 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.DIVIDE; import static dev.cel.runtime.standard.ArithmeticHelpers.getArithmeticErrorCode; import com.google.common.collect.ImmutableSet; @@ -90,6 +91,6 @@ public CelFunctionBinding newFunctionBinding( } private DivideOperator(ImmutableSet overloads) { - super(overloads); + super(DIVIDE.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/DoubleFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/DoubleFunction.java index 508df1983..b541bd379 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/DoubleFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/DoubleFunction.java @@ -87,6 +87,6 @@ public CelFunctionBinding newFunctionBinding( } private DoubleFunction(ImmutableSet overloads) { - super(overloads); + super("double", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/DurationFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/DurationFunction.java index 72f96f785..436ffd1d4 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/DurationFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/DurationFunction.java @@ -88,6 +88,6 @@ public CelFunctionBinding newFunctionBinding( } private DurationFunction(ImmutableSet overloads) { - super(overloads); + super("duration", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/DynFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/DynFunction.java index d3cb34de9..da855de82 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/DynFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/DynFunction.java @@ -57,6 +57,6 @@ public CelFunctionBinding newFunctionBinding( } private DynFunction(ImmutableSet overloads) { - super(overloads); + super("dyn", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/EndsWithFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/EndsWithFunction.java index eeda546fe..7f4e8c035 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/EndsWithFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/EndsWithFunction.java @@ -59,6 +59,6 @@ public CelFunctionBinding newFunctionBinding( } private EndsWithFunction(ImmutableSet overloads) { - super(overloads); + super("endsWith", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/EqualsOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/EqualsOperator.java index ae78decbd..c505e069e 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/EqualsOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/EqualsOperator.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.EQUALS; + import com.google.common.collect.ImmutableSet; import dev.cel.common.CelOptions; import dev.cel.runtime.CelFunctionBinding; @@ -58,6 +60,6 @@ public CelFunctionBinding newFunctionBinding( } private EqualsOperator(ImmutableSet overloads) { - super(overloads); + super(EQUALS.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetDateFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetDateFunction.java index 04e046062..bb0fb0d79 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetDateFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetDateFunction.java @@ -89,6 +89,6 @@ public CelFunctionBinding newFunctionBinding( } private GetDateFunction(ImmutableSet overloads) { - super(overloads); + super("getDate", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfMonthFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfMonthFunction.java index b6f146aa9..e35888fb5 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfMonthFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfMonthFunction.java @@ -90,6 +90,6 @@ public CelFunctionBinding newFunctionBinding( } private GetDayOfMonthFunction(ImmutableSet overloads) { - super(overloads); + super("getDayOfMonth", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfWeekFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfWeekFunction.java index cede6c1e1..e2fa02961 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfWeekFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfWeekFunction.java @@ -106,6 +106,6 @@ public CelFunctionBinding newFunctionBinding( } private GetDayOfWeekFunction(ImmutableSet overloads) { - super(overloads); + super("getDayOfWeek", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfYearFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfYearFunction.java index 966c70bc6..4c0e62637 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfYearFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetDayOfYearFunction.java @@ -91,6 +91,6 @@ public CelFunctionBinding newFunctionBinding( } private GetDayOfYearFunction(ImmutableSet overloads) { - super(overloads); + super("getDayOfYear", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetFullYearFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetFullYearFunction.java index a91fffb72..925f61307 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetFullYearFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetFullYearFunction.java @@ -90,6 +90,6 @@ public CelFunctionBinding newFunctionBinding( } private GetFullYearFunction(ImmutableSet overloads) { - super(overloads); + super("getFullYear", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetHoursFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetHoursFunction.java index 94fb6391e..afe16556f 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetHoursFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetHoursFunction.java @@ -101,6 +101,6 @@ public CelFunctionBinding newFunctionBinding( } private GetHoursFunction(ImmutableSet overloads) { - super(overloads); + super("getHours", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetMillisecondsFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetMillisecondsFunction.java index 672226eaf..32b17cc88 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetMillisecondsFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetMillisecondsFunction.java @@ -112,6 +112,6 @@ public CelFunctionBinding newFunctionBinding( } private GetMillisecondsFunction(ImmutableSet overloads) { - super(overloads); + super("getMilliseconds", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetMinutesFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetMinutesFunction.java index 5f75d14ef..5f701f1e1 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetMinutesFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetMinutesFunction.java @@ -102,6 +102,6 @@ public CelFunctionBinding newFunctionBinding( } private GetMinutesFunction(ImmutableSet overloads) { - super(overloads); + super("getMinutes", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetMonthFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetMonthFunction.java index dc4e66889..a8a9ded68 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetMonthFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetMonthFunction.java @@ -89,6 +89,6 @@ public CelFunctionBinding newFunctionBinding( } private GetMonthFunction(ImmutableSet overloads) { - super(overloads); + super("getMonth", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GetSecondsFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/GetSecondsFunction.java index 70fe96ec4..80030f50f 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GetSecondsFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GetSecondsFunction.java @@ -114,6 +114,6 @@ public CelFunctionBinding newFunctionBinding( } private GetSecondsFunction(ImmutableSet overloads) { - super(overloads); + super("getSeconds", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GreaterEqualsOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/GreaterEqualsOperator.java index be41e0f5f..c04b4398f 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GreaterEqualsOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GreaterEqualsOperator.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.GREATER_EQUALS; + import com.google.common.collect.ImmutableSet; import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; @@ -197,6 +199,6 @@ public CelFunctionBinding newFunctionBinding( } private GreaterEqualsOperator(ImmutableSet overloads) { - super(overloads); + super(GREATER_EQUALS.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/GreaterOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/GreaterOperator.java index 21b59eebb..80edb8a9b 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/GreaterOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/GreaterOperator.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.GREATER; + import com.google.common.collect.ImmutableSet; import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; @@ -190,6 +192,6 @@ public CelFunctionBinding newFunctionBinding( } private GreaterOperator(ImmutableSet overloads) { - super(overloads); + super(GREATER.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/InOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/InOperator.java index 9a2c99f43..bf80cc6ff 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/InOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/InOperator.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.IN; + import com.google.common.collect.ImmutableSet; import dev.cel.common.CelOptions; import dev.cel.runtime.CelFunctionBinding; @@ -70,6 +72,6 @@ public CelFunctionBinding newFunctionBinding( } private InOperator(ImmutableSet overloads) { - super(overloads); + super(IN.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/IndexOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/IndexOperator.java index d1b88a88f..f48e8fbf5 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/IndexOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/IndexOperator.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.INDEX; + import com.google.common.collect.ImmutableSet; import dev.cel.common.CelOptions; import dev.cel.runtime.CelFunctionBinding; @@ -65,6 +67,6 @@ public CelFunctionBinding newFunctionBinding( } private IndexOperator(ImmutableSet overloads) { - super(overloads); + super(INDEX.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/IntFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/IntFunction.java index fda307a9d..248131865 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/IntFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/IntFunction.java @@ -130,6 +130,6 @@ public CelFunctionBinding newFunctionBinding( } private IntFunction(ImmutableSet overloads) { - super(overloads); + super("int", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/LessEqualsOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/LessEqualsOperator.java index e09fcce5e..7688acbc1 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/LessEqualsOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/LessEqualsOperator.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.LESS_EQUALS; + import com.google.common.collect.ImmutableSet; import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; @@ -194,6 +196,6 @@ public CelFunctionBinding newFunctionBinding( } private LessEqualsOperator(ImmutableSet overloads) { - super(overloads); + super(LESS_EQUALS.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/LessOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/LessOperator.java index 4afbc20a2..a53a13a92 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/LessOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/LessOperator.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.LESS; + import com.google.common.collect.ImmutableSet; import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; @@ -190,6 +192,6 @@ public CelFunctionBinding newFunctionBinding( } private LessOperator(ImmutableSet overloads) { - super(overloads); + super(LESS.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/LogicalNotOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/LogicalNotOperator.java index a4be6385b..6c2ec8efd 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/LogicalNotOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/LogicalNotOperator.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.LOGICAL_NOT; + import com.google.common.collect.ImmutableSet; import dev.cel.common.CelOptions; import dev.cel.runtime.CelFunctionBinding; @@ -57,6 +59,6 @@ public CelFunctionBinding newFunctionBinding( } private LogicalNotOperator(ImmutableSet overloads) { - super(overloads); + super(LOGICAL_NOT.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/MatchesFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/MatchesFunction.java index 7c24f65a2..62df04110 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/MatchesFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/MatchesFunction.java @@ -84,6 +84,6 @@ public CelFunctionBinding newFunctionBinding( } private MatchesFunction(ImmutableSet overloads) { - super(overloads); + super("matches", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/ModuloOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/ModuloOperator.java index e7246851c..01e02764d 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/ModuloOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/ModuloOperator.java @@ -14,6 +14,7 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.MODULO; import static dev.cel.runtime.standard.ArithmeticHelpers.getArithmeticErrorCode; import com.google.common.collect.ImmutableSet; @@ -85,6 +86,6 @@ public CelFunctionBinding newFunctionBinding( } private ModuloOperator(ImmutableSet overloads) { - super(overloads); + super(MODULO.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/MultiplyOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/MultiplyOperator.java index 7e9e2f352..c55a4c968 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/MultiplyOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/MultiplyOperator.java @@ -14,6 +14,7 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.MULTIPLY; import static dev.cel.runtime.standard.ArithmeticHelpers.getArithmeticErrorCode; import com.google.common.collect.ImmutableSet; @@ -103,6 +104,6 @@ public CelFunctionBinding newFunctionBinding( } private MultiplyOperator(ImmutableSet overloads) { - super(overloads); + super(MULTIPLY.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/NegateOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/NegateOperator.java index 2e3f094f5..cc072fdec 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/NegateOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/NegateOperator.java @@ -14,6 +14,7 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.NEGATE; import static dev.cel.runtime.standard.ArithmeticHelpers.getArithmeticErrorCode; import com.google.common.collect.ImmutableSet; @@ -72,6 +73,6 @@ public CelFunctionBinding newFunctionBinding( } private NegateOperator(ImmutableSet overloads) { - super(overloads); + super(NEGATE.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/NotEqualsOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/NotEqualsOperator.java index 5a0475f29..27b17676e 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/NotEqualsOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/NotEqualsOperator.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.NOT_EQUALS; + import com.google.common.collect.ImmutableSet; import dev.cel.common.CelOptions; import dev.cel.runtime.CelFunctionBinding; @@ -60,6 +62,6 @@ public CelFunctionBinding newFunctionBinding( } private NotEqualsOperator(ImmutableSet overloads) { - super(overloads); + super(NOT_EQUALS.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/NotStrictlyFalseFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/NotStrictlyFalseFunction.java index af7d1a3c2..8e0ceead4 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/NotStrictlyFalseFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/NotStrictlyFalseFunction.java @@ -14,6 +14,8 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.NOT_STRICTLY_FALSE; + import com.google.common.collect.ImmutableSet; import dev.cel.common.CelOptions; import dev.cel.runtime.CelFunctionBinding; @@ -63,6 +65,6 @@ public CelFunctionBinding newFunctionBinding( } private NotStrictlyFalseFunction(ImmutableSet overloads) { - super(overloads); + super(NOT_STRICTLY_FALSE.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/SizeFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/SizeFunction.java index 9f79605ed..a8f787665 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/SizeFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/SizeFunction.java @@ -98,6 +98,6 @@ public CelFunctionBinding newFunctionBinding( } private SizeFunction(ImmutableSet overloads) { - super(overloads); + super("size", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/StartsWithFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/StartsWithFunction.java index 6626d6912..457dd3cf1 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/StartsWithFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/StartsWithFunction.java @@ -58,6 +58,6 @@ public CelFunctionBinding newFunctionBinding( } private StartsWithFunction(ImmutableSet overloads) { - super(overloads); + super("startsWith", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/StringFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/StringFunction.java index c491bfe76..9311962ca 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/StringFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/StringFunction.java @@ -134,6 +134,6 @@ public CelFunctionBinding newFunctionBinding( } private StringFunction(ImmutableSet overloads) { - super(overloads); + super("string", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/SubtractOperator.java b/runtime/src/main/java/dev/cel/runtime/standard/SubtractOperator.java index 4b0ecd3ae..8a7595f92 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/SubtractOperator.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/SubtractOperator.java @@ -14,6 +14,7 @@ package dev.cel.runtime.standard; +import static dev.cel.common.Operator.SUBTRACT; import static dev.cel.runtime.standard.ArithmeticHelpers.getArithmeticErrorCode; import com.google.common.collect.ImmutableSet; @@ -157,6 +158,6 @@ public CelFunctionBinding newFunctionBinding( } private SubtractOperator(ImmutableSet overloads) { - super(overloads); + super(SUBTRACT.getFunction(), overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/TimestampFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/TimestampFunction.java index 34fb15768..27c495034 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/TimestampFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/TimestampFunction.java @@ -107,6 +107,6 @@ public CelFunctionBinding newFunctionBinding( } private TimestampFunction(ImmutableSet overloads) { - super(overloads); + super("timestamp", overloads); } } diff --git a/runtime/src/main/java/dev/cel/runtime/standard/UintFunction.java b/runtime/src/main/java/dev/cel/runtime/standard/UintFunction.java index 89424e7fc..d120c6b75 100644 --- a/runtime/src/main/java/dev/cel/runtime/standard/UintFunction.java +++ b/runtime/src/main/java/dev/cel/runtime/standard/UintFunction.java @@ -158,6 +158,6 @@ public CelFunctionBinding newFunctionBinding( } private UintFunction(ImmutableSet overloads) { - super(overloads); + super("uint", overloads); } } diff --git a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel index eb0d652f1..bb4ca4cb8 100644 --- a/runtime/src/test/java/dev/cel/runtime/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel @@ -19,8 +19,8 @@ java_library( # keep sorted exclude = [ "CelLiteInterpreterTest.java", - "CelValueInterpreterTest.java", "InterpreterTest.java", + "PlannerInterpreterTest.java", ] + ANDROID_TESTS, ), deps = [ @@ -48,6 +48,7 @@ java_library( "//common/internal:well_known_proto", "//common/types", "//common/types:cel_v1alpha1_types", + "//common/types:message_lite_type_provider", "//common/types:message_type_provider", "//common/values", "//common/values:cel_byte_string", @@ -122,16 +123,17 @@ java_library( ) java_library( - name = "cel_value_interpreter_test", + name = "planner_interpreter_test", testonly = 1, srcs = [ - "CelValueInterpreterTest.java", + "PlannerInterpreterTest.java", ], deps = [ - # "//java/com/google/testing/testsize:annotations", + "//extensions", + "//runtime", "//testing:base_interpreter_test", - "@maven//:junit_junit", "@maven//:com_google_testparameterinjector_test_parameter_injector", + "@maven//:junit_junit", ], ) @@ -155,6 +157,7 @@ cel_android_local_test( "//runtime:lite_runtime_android", "//runtime:lite_runtime_factory_android", "//runtime:lite_runtime_impl_android", + "//runtime:program_android", "//runtime:standard_functions_android", "//runtime:unknown_attributes_android", "//runtime/src/main/java/dev/cel/runtime:program_android", @@ -200,8 +203,8 @@ junit4_test_suites( src_dir = "src/test/java", deps = [ ":cel_lite_interpreter_test", - ":cel_value_interpreter_test", ":interpreter_test", + ":planner_interpreter_test", ":tests", ], ) diff --git a/runtime/src/test/java/dev/cel/runtime/CelLiteInterpreterTest.java b/runtime/src/test/java/dev/cel/runtime/CelLiteInterpreterTest.java index 088a2d7b0..734719f1a 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelLiteInterpreterTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelLiteInterpreterTest.java @@ -29,13 +29,13 @@ public class CelLiteInterpreterTest extends BaseInterpreterTest { public CelLiteInterpreterTest() { super( - CelRuntimeFactory.standardCelRuntimeBuilder() + CelRuntimeFactory.plannerCelRuntimeBuilder() .setValueProvider( ProtoMessageLiteValueProvider.newInstance( dev.cel.expr.conformance.proto2.TestAllTypesCelDescriptor.getDescriptor(), TestAllTypesCelDescriptor.getDescriptor())) .addLibraries(CelOptionalLibrary.INSTANCE) - .setOptions(newBaseCelOptions().toBuilder().enableCelValue(true).build()) + .setOptions(newBaseCelOptions()) .build()); } diff --git a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java index 638782c2e..07a9a3235 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeAndroidTest.java @@ -124,7 +124,7 @@ public void toRuntimeBuilder_isNewInstance() { @Test public void toRuntimeBuilder_propertiesCopied() { - CelOptions celOptions = CelOptions.current().enableCelValue(true).build(); + CelOptions celOptions = CelOptions.current().build(); CelLiteRuntimeLibrary runtimeExtension = CelLiteExtensions.sets(celOptions, SetsFunction.INTERSECTS); CelValueProvider celValueProvider = ProtoMessageLiteValueProvider.newInstance(); @@ -712,7 +712,6 @@ public void eval_protoMessage_mapFields(String checkedExpr) throws Exception { } private enum CelOptionsTestCase { - CEL_VALUE_DISABLED(newBaseTestOptions().enableCelValue(false).build()), UNSIGNED_LONG_DISABLED(newBaseTestOptions().enableUnsignedLongs(false).build()), UNWRAP_WKT_DISABLED(newBaseTestOptions().unwrapWellKnownTypesOnFunctionDispatch(false).build()), STRING_CONCAT_DISABLED(newBaseTestOptions().enableStringConcatenation(false).build()), @@ -723,7 +722,7 @@ private enum CelOptionsTestCase { private final CelOptions celOptions; private static CelOptions.Builder newBaseTestOptions() { - return CelOptions.current().enableCelValue(true); + return CelOptions.current(); } CelOptionsTestCase(CelOptions celOptions) { diff --git a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeTest.java index 4ffe0941c..fe03c5cbb 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelLiteRuntimeTest.java @@ -42,6 +42,7 @@ import dev.cel.common.CelFunctionDecl; import dev.cel.common.CelOverloadDecl; import dev.cel.common.internal.ProtoTimeUtils; +import dev.cel.common.types.ProtoMessageLiteTypeProvider; import dev.cel.common.types.SimpleType; import dev.cel.common.types.StructTypeReference; import dev.cel.common.values.CelByteString; @@ -74,22 +75,29 @@ /** Exercises tests for CelLiteRuntime using full version of protobuf messages. */ @RunWith(TestParameterInjector.class) public class CelLiteRuntimeTest { + private static final CelContainer CEL_CONTAINER = + CelContainer.ofName("cel.expr.conformance.proto3"); private static final CelCompiler CEL_COMPILER = CelCompilerFactory.standardCelCompilerBuilder() .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName())) .addVar("content", SimpleType.DYN) .addMessageTypes(TestAllTypes.getDescriptor()) - .setContainer(CelContainer.ofName("cel.expr.conformance.proto3")) + .setContainer(CEL_CONTAINER) .build(); private static final CelLiteRuntime CEL_RUNTIME = CelLiteRuntimeFactory.newLiteRuntimeBuilder() .setStandardFunctions(CelStandardFunctions.ALL_STANDARD_FUNCTIONS) + .setTypeProvider( + ProtoMessageLiteTypeProvider.newInstance( + dev.cel.expr.conformance.proto2.TestAllTypesCelDescriptor.getDescriptor(), + TestAllTypesCelDescriptor.getDescriptor())) .setValueProvider( ProtoMessageLiteValueProvider.newInstance( dev.cel.expr.conformance.proto2.TestAllTypesCelDescriptor.getDescriptor(), TestAllTypesCelDescriptor.getDescriptor())) + .setContainer(CEL_CONTAINER) .build(); @Test diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeFactoryTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeFactoryTest.java index 28676ebcb..3abf90f7e 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeFactoryTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeFactoryTest.java @@ -27,4 +27,10 @@ public final class CelRuntimeFactoryTest { public void standardCelRuntimeBuilder() { assertThat(CelRuntimeFactory.standardCelRuntimeBuilder().build()).isNotNull(); } + + @Test + public void plannerCelRuntimeBuilder() { + CelRuntime runtime = CelRuntimeFactory.plannerCelRuntimeBuilder().build(); + assertThat(runtime).isNotNull(); + } } diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java index c4a041f6a..d488095d4 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java @@ -18,12 +18,10 @@ import com.google.protobuf.Message; import dev.cel.common.CelException; -import dev.cel.common.values.CelValueProvider; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.runtime.CelStandardFunctions.StandardFunction; -import java.util.Optional; import java.util.function.Function; import org.junit.Assert; import org.junit.Test; @@ -107,13 +105,11 @@ public void toRuntimeBuilder_optionalProperties() { Function customTypeFactory = (typeName) -> TestAllTypes.newBuilder(); CelStandardFunctions overriddenStandardFunctions = CelStandardFunctions.newBuilder().includeFunctions(StandardFunction.ADD).build(); - CelValueProvider noOpValueProvider = (structType, fields) -> Optional.empty(); CelRuntimeBuilder celRuntimeBuilder = CelRuntimeFactory.standardCelRuntimeBuilder() .setStandardEnvironmentEnabled(false) .setTypeFactory(customTypeFactory) - .setStandardFunctions(overriddenStandardFunctions) - .setValueProvider(noOpValueProvider); + .setStandardFunctions(overriddenStandardFunctions); CelRuntime celRuntime = celRuntimeBuilder.build(); CelRuntimeLegacyImpl.Builder newRuntimeBuilder = @@ -122,6 +118,5 @@ public void toRuntimeBuilder_optionalProperties() { assertThat(newRuntimeBuilder.customTypeFactory).isEqualTo(customTypeFactory); assertThat(newRuntimeBuilder.overriddenStandardFunctions) .isEqualTo(overriddenStandardFunctions); - assertThat(newRuntimeBuilder.celValueProvider).isEqualTo(noOpValueProvider); } } diff --git a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java index 7d7243384..477a8fbf6 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java +++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeTest.java @@ -22,6 +22,7 @@ import com.google.api.expr.v1alpha1.Type.PrimitiveType; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.primitives.UnsignedLong; import com.google.protobuf.Any; import com.google.protobuf.BoolValue; import com.google.protobuf.ByteString; @@ -733,4 +734,15 @@ public void standardEnvironmentDisabledForRuntime_throws() throws Exception { .hasMessageThat() .contains("No matching overload for function 'size'. Overload candidates: size_string"); } + + @Test + public void uintConversion_dynamicDispatch() throws Exception { + CelCompiler celCompiler = CelCompilerFactory.standardCelCompilerBuilder().build(); + CelRuntime celRuntime = CelRuntimeFactory.plannerCelRuntimeBuilder().build(); + CelAbstractSyntaxTree ast = celCompiler.compile("uint(dyn(1u))").getAst(); + + Object result = celRuntime.createProgram(ast).eval(); + + assertThat(result).isEqualTo(UnsignedLong.valueOf(1L)); + } } diff --git a/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java b/runtime/src/test/java/dev/cel/runtime/PlannerInterpreterTest.java similarity index 66% rename from runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java rename to runtime/src/test/java/dev/cel/runtime/PlannerInterpreterTest.java index f56bb3012..660fe057b 100644 --- a/runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java +++ b/runtime/src/test/java/dev/cel/runtime/PlannerInterpreterTest.java @@ -1,4 +1,4 @@ -// Copyright 2023 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,16 +15,19 @@ package dev.cel.runtime; import com.google.testing.junit.testparameterinjector.TestParameterInjector; -// import com.google.testing.testsize.MediumTest; +import dev.cel.extensions.CelExtensions; import dev.cel.testing.BaseInterpreterTest; import org.junit.runner.RunWith; -/** Tests for {@link Interpreter} and related functionality using {@code CelValue}. */ -// @MediumTest @RunWith(TestParameterInjector.class) -public class CelValueInterpreterTest extends BaseInterpreterTest { +public class PlannerInterpreterTest extends BaseInterpreterTest { - public CelValueInterpreterTest() { - super(newBaseCelOptions().toBuilder().enableCelValue(true).build()); + public PlannerInterpreterTest() { + super( + CelRuntimeFactory.plannerCelRuntimeBuilder() + .setOptions(newBaseCelOptions()) + .addLibraries(CelExtensions.optional()) + .addFileTypes(TEST_FILE_DESCRIPTORS) + .build()); } } diff --git a/runtime/src/test/java/dev/cel/runtime/planner/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/planner/BUILD.bazel index 01df7c9ee..ffdc87c39 100644 --- a/runtime/src/test/java/dev/cel/runtime/planner/BUILD.bazel +++ b/runtime/src/test/java/dev/cel/runtime/planner/BUILD.bazel @@ -20,7 +20,6 @@ java_library( "//common:compiler_common", "//common:container", "//common:error_codes", - "//common:operator", "//common:options", "//common/ast", "//common/internal:cel_descriptor_pools", @@ -38,12 +37,12 @@ java_library( "//compiler", "//compiler:compiler_builder", "//extensions", + "//extensions:optional_library", "//parser:macro", "//runtime", "//runtime:dispatcher", "//runtime:function_binding", "//runtime:program", - "//runtime:resolved_overload", "//runtime:runtime_equality", "//runtime:runtime_helpers", "//runtime/planner:program_planner", diff --git a/runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java b/runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java index 968fdcc94..fac962093 100644 --- a/runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java +++ b/runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java @@ -25,7 +25,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; import com.google.common.primitives.UnsignedLong; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; @@ -36,7 +35,6 @@ import dev.cel.common.CelErrorCode; import dev.cel.common.CelOptions; import dev.cel.common.CelSource; -import dev.cel.common.Operator; import dev.cel.common.ast.CelExpr; import dev.cel.common.internal.CelDescriptorPool; import dev.cel.common.internal.DefaultDescriptorPool; @@ -65,11 +63,10 @@ import dev.cel.expr.conformance.proto3.TestAllTypes; import dev.cel.expr.conformance.proto3.TestAllTypes.NestedMessage; import dev.cel.extensions.CelExtensions; +import dev.cel.extensions.CelOptionalLibrary; import dev.cel.parser.CelStandardMacro; import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelFunctionBinding; -import dev.cel.runtime.CelFunctionOverload; -import dev.cel.runtime.CelResolvedOverload; import dev.cel.runtime.DefaultDispatcher; import dev.cel.runtime.Program; import dev.cel.runtime.RuntimeEquality; @@ -90,7 +87,7 @@ @RunWith(TestParameterInjector.class) public final class ProgramPlannerTest { - // Note that the following deps will be built from top-level builder APIs + // Note that the following deps are ordinarily built from top-level builder APIs private static final CelOptions CEL_OPTIONS = CelOptions.current().build(); private static final CelTypeProvider TYPE_PROVIDER = new CombinedCelTypeProvider( @@ -131,6 +128,8 @@ public final class ProgramPlannerTest { .addVar("int_var", SimpleType.INT) .addVar("dyn_var", SimpleType.DYN) .addVar("really.long.abbr.ident", SimpleType.DYN) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .setContainer(CEL_CONTAINER) .addFunctionDeclarations( newFunctionDeclaration("zero", newGlobalOverload("zero_overload", SimpleType.INT)), newFunctionDeclaration("error", newGlobalOverload("error_overload", SimpleType.INT)), @@ -148,9 +147,8 @@ public final class ProgramPlannerTest { "concat_bytes_bytes", SimpleType.BYTES, SimpleType.BYTES, SimpleType.BYTES), newMemberOverload( "bytes_concat_bytes", SimpleType.BYTES, SimpleType.BYTES, SimpleType.BYTES))) + .addLibraries(CelOptionalLibrary.INSTANCE, CelExtensions.comprehensions()) .addMessageTypes(TestAllTypes.getDescriptor()) - .addLibraries(CelExtensions.optional(), CelExtensions.comprehensions()) - .setContainer(CEL_CONTAINER) .build(); /** @@ -161,136 +159,95 @@ private static DefaultDispatcher newDispatcher() { DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder(); // Subsetted StdLib - addBindings( - builder, Operator.INDEX.getFunction(), fromStandardFunction(IndexOperator.create())); - addBindings( - builder, - Operator.LOGICAL_NOT.getFunction(), - fromStandardFunction(LogicalNotOperator.create())); - addBindings(builder, Operator.ADD.getFunction(), fromStandardFunction(AddOperator.create())); - addBindings( - builder, Operator.GREATER.getFunction(), fromStandardFunction(GreaterOperator.create())); - addBindings( - builder, - Operator.GREATER_EQUALS.getFunction(), - fromStandardFunction(GreaterEqualsOperator.create())); - addBindings(builder, Operator.LESS.getFunction(), fromStandardFunction(LessOperator.create())); - addBindings( - builder, Operator.DIVIDE.getFunction(), fromStandardFunction(DivideOperator.create())); - addBindings( - builder, Operator.EQUALS.getFunction(), fromStandardFunction(EqualsOperator.create())); - addBindings( - builder, - Operator.NOT_STRICTLY_FALSE.getFunction(), - fromStandardFunction(NotStrictlyFalseFunction.create())); - addBindings(builder, "dyn", fromStandardFunction(DynFunction.create())); + addStandardFuncBindings(builder, IndexOperator.create()); + addStandardFuncBindings(builder, LogicalNotOperator.create()); + addStandardFuncBindings(builder, AddOperator.create()); + addStandardFuncBindings(builder, GreaterOperator.create()); + addStandardFuncBindings(builder, GreaterEqualsOperator.create()); + addStandardFuncBindings(builder, LessOperator.create()); + addStandardFuncBindings(builder, DivideOperator.create()); + addStandardFuncBindings(builder, EqualsOperator.create()); + addStandardFuncBindings(builder, NotStrictlyFalseFunction.create()); + addStandardFuncBindings(builder, DynFunction.create()); // Custom functions - addBindings( + addCustomBindings( builder, - "zero", - CelFunctionBinding.from("zero_overload", ImmutableList.of(), (unused) -> 0L)); - addBindings( + CelFunctionBinding.groupOverloads( + "zero", CelFunctionBinding.from("zero_overload", ImmutableList.of(), (unused) -> 0L))); + + addCustomBindings( builder, - "error", - CelFunctionBinding.from( - "error_overload", - ImmutableList.of(), - (unused) -> { - throw new IllegalArgumentException("Intentional error"); - })); - addBindings( + CelFunctionBinding.groupOverloads( + "error", + CelFunctionBinding.from( + "error_overload", + ImmutableList.of(), + (unused) -> { + throw new IllegalArgumentException("Intentional error"); + }))); + + addCustomBindings( builder, - "neg", - CelFunctionBinding.from("neg_int", Long.class, arg -> -arg), - CelFunctionBinding.from("neg_double", Double.class, arg -> -arg)); - addBindings( + CelFunctionBinding.groupOverloads( + "neg", + CelFunctionBinding.from("neg_int", Long.class, arg -> -arg), + CelFunctionBinding.from("neg_double", Double.class, arg -> -arg))); + + addCustomBindings( builder, - "cel.expr.conformance.proto3.power", - CelFunctionBinding.from( - "power_int_int", - Long.class, - Long.class, - (value, power) -> (long) Math.pow(value, power))); - addBindings( + CelFunctionBinding.groupOverloads( + "cel.expr.conformance.proto3.power", + CelFunctionBinding.from( + "power_int_int", + Long.class, + Long.class, + (value, power) -> (long) Math.pow(value, power)))); + + addCustomBindings( builder, - "concat", - CelFunctionBinding.from( - "concat_bytes_bytes", - CelByteString.class, - CelByteString.class, - ProgramPlannerTest::concatenateByteArrays), - CelFunctionBinding.from( - "bytes_concat_bytes", - CelByteString.class, - CelByteString.class, - ProgramPlannerTest::concatenateByteArrays)); + CelFunctionBinding.groupOverloads( + "concat", + CelFunctionBinding.from( + "concat_bytes_bytes", + CelByteString.class, + CelByteString.class, + ProgramPlannerTest::concatenateByteArrays), + CelFunctionBinding.from( + "bytes_concat_bytes", + CelByteString.class, + CelByteString.class, + ProgramPlannerTest::concatenateByteArrays))); return builder.build(); } - private static void addBindings( - DefaultDispatcher.Builder builder, - String functionName, - CelFunctionBinding... functionBindings) { - addBindings(builder, functionName, ImmutableSet.copyOf(functionBindings)); + private static void addStandardFuncBindings( + DefaultDispatcher.Builder builder, CelStandardFunction standardFunction) { + standardFunction + .newFunctionBindings(CEL_OPTIONS, RUNTIME_EQUALITY) + .forEach( + binding -> + builder.addOverload( + binding.getOverloadId(), + binding.getArgTypes(), + binding.isStrict(), + binding.getDefinition())); } - private static void addBindings( - DefaultDispatcher.Builder builder, - String functionName, - ImmutableCollection overloadBindings) { + private static void addCustomBindings( + DefaultDispatcher.Builder builder, ImmutableCollection overloadBindings) { if (overloadBindings.isEmpty()) { throw new IllegalArgumentException("Invalid bindings"); } - // TODO: Runtime top-level APIs currently does not allow grouping overloads with - // the function name. This capability will have to be added. - if (overloadBindings.size() == 1) { - CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings); - builder.addOverload( - functionName, - singleBinding.getArgTypes(), - singleBinding.isStrict(), - args -> guardedOp(functionName, args, singleBinding)); - } else { - overloadBindings.forEach( - overload -> - builder.addOverload( - overload.getOverloadId(), - overload.getArgTypes(), - overload.isStrict(), - args -> guardedOp(functionName, args, overload))); - - // Setup dynamic dispatch - CelFunctionOverload dynamicDispatchDef = - args -> { - for (CelFunctionBinding overload : overloadBindings) { - if (CelResolvedOverload.canHandle( - args, overload.getArgTypes(), overload.isStrict())) { - return overload.getDefinition().apply(args); - } - } - - throw new IllegalArgumentException( - "No matching overload for function: " + functionName); - }; - - boolean allOverloadsStrict = overloadBindings.stream().allMatch(CelFunctionBinding::isStrict); - builder.addOverload( - functionName, ImmutableList.of(), /* isStrict= */ allOverloadsStrict, dynamicDispatchDef); - } - } - /** Creates an invocation guard around the overload definition. */ - private static Object guardedOp( - String functionName, Object[] args, CelFunctionBinding singleBinding) - throws CelEvaluationException { - if (!CelResolvedOverload.canHandle( - args, singleBinding.getArgTypes(), singleBinding.isStrict())) { - throw new IllegalArgumentException("No matching overload for function: " + functionName); - } - - return singleBinding.getDefinition().apply(args); + overloadBindings.forEach( + overload -> + builder.addOverload( + overload.getOverloadId(), + overload.getArgTypes(), + overload.isStrict(), + overload.getDefinition())); } @TestParameter boolean isParseOnly; @@ -871,11 +828,6 @@ private static CelByteString concatenateByteArrays(CelByteString bytes1, CelByte return bytes1.concat(bytes2); } - private static ImmutableSet fromStandardFunction( - CelStandardFunction standardFunction) { - return standardFunction.newFunctionBindings(CEL_OPTIONS, RUNTIME_EQUALITY); - } - @SuppressWarnings("ImmutableEnumChecker") // Test only private enum ConstantTestCase { NULL("null", NullValue.NULL_VALUE),