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 21a124565..bffc1af37 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"],
diff --git a/common/exceptions/BUILD.bazel b/common/exceptions/BUILD.bazel
index 4e52113e7..3464632d9 100644
--- a/common/exceptions/BUILD.bazel
+++ b/common/exceptions/BUILD.bazel
@@ -53,6 +53,12 @@ java_library(
exports = ["//common/src/main/java/dev/cel/common/exceptions:iteration_budget_exceeded"],
)
+java_library(
+ name = "duplicate_key",
+ # used_by_android
+ exports = ["//common/src/main/java/dev/cel/common/exceptions:duplicate_key"],
+)
+
java_library(
name = "overload_not_found",
# used_by_android
diff --git a/common/src/main/java/dev/cel/common/BUILD.bazel b/common/src/main/java/dev/cel/common/BUILD.bazel
index ba223d213..f11ba2d63 100644
--- a/common/src/main/java/dev/cel/common/BUILD.bazel
+++ b/common/src/main/java/dev/cel/common/BUILD.bazel
@@ -341,6 +341,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"],
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/exceptions/BUILD.bazel b/common/src/main/java/dev/cel/common/exceptions/BUILD.bazel
index 755e037d9..672238cf0 100644
--- a/common/src/main/java/dev/cel/common/exceptions/BUILD.bazel
+++ b/common/src/main/java/dev/cel/common/exceptions/BUILD.bazel
@@ -111,6 +111,19 @@ java_library(
],
)
+java_library(
+ name = "duplicate_key",
+ srcs = ["CelDuplicateKeyException.java"],
+ # used_by_android
+ tags = [
+ ],
+ deps = [
+ ":runtime_exception",
+ "//common:error_codes",
+ "//common/annotations",
+ ],
+)
+
java_library(
name = "overload_not_found",
srcs = ["CelOverloadNotFoundException.java"],
diff --git a/common/src/main/java/dev/cel/common/exceptions/CelDuplicateKeyException.java b/common/src/main/java/dev/cel/common/exceptions/CelDuplicateKeyException.java
new file mode 100644
index 000000000..f4c99d516
--- /dev/null
+++ b/common/src/main/java/dev/cel/common/exceptions/CelDuplicateKeyException.java
@@ -0,0 +1,31 @@
+// Copyright 2026 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.exceptions;
+
+import dev.cel.common.CelErrorCode;
+import dev.cel.common.annotations.Internal;
+
+/** Indicates an attempt to create a map using duplicate keys. */
+@Internal
+public final class CelDuplicateKeyException extends CelRuntimeException {
+
+ public static CelDuplicateKeyException of(Object key) {
+ return new CelDuplicateKeyException(String.format("duplicate map key [%s]", key));
+ }
+
+ private CelDuplicateKeyException(String message) {
+ super(message, CelErrorCode.DUPLICATE_ATTRIBUTE);
+ }
+}
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..793943f1b
--- /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: Add */
+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 244145960..709b509f1 100644
--- a/runtime/BUILD.bazel
+++ b/runtime/BUILD.bazel
@@ -28,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 = [
@@ -43,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"],
@@ -79,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"],
)
@@ -112,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"],
@@ -253,21 +276,22 @@ cel_android_library(
java_library(
name = "metadata",
+ # used_by_android
visibility = ["//:internal"],
exports = ["//runtime/src/main/java/dev/cel/runtime:metadata"],
)
java_library(
- name = "concatenated_list_view",
- visibility = ["//:internal"],
- exports = [
- "//runtime/src/main/java/dev/cel/runtime:concatenated_list_view",
- ],
+ name = "variable_resolver",
+ # used_by_android
+ exports = ["//runtime/src/main/java/dev/cel/runtime:variable_resolver"],
)
java_library(
- name = "variable_resolver",
+ name = "concatenated_list_view",
+ # used_by_android
+ visibility = ["//:internal"],
exports = [
- "//runtime/src/main/java/dev/cel/runtime:variable_resolver",
+ "//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 d253edba3..70d95383b 100644
--- a/runtime/src/main/java/dev/cel/runtime/BUILD.bazel
+++ b/runtime/src/main/java/dev/cel/runtime/BUILD.bazel
@@ -44,11 +44,6 @@ LITE_RUNTIME_IMPL_SOURCES = [
"LiteRuntimeImpl.java",
]
-# keep sorted
-LITE_PROGRAM_IMPL_SOURCES = [
- "LiteProgramImpl.java",
-]
-
# keep sorted
FUNCTION_BINDING_SOURCES = [
"CelFunctionBinding.java",
@@ -139,7 +134,8 @@ java_library(
cel_android_library(
name = "dispatcher_android",
srcs = DISPATCHER_SOURCES,
- visibility = ["//visibility:private"],
+ tags = [
+ ],
deps = [
":evaluation_exception",
":evaluation_exception_builder",
@@ -175,7 +171,8 @@ java_library(
cel_android_library(
name = "activation_android",
srcs = ["Activation.java"],
- visibility = ["//visibility:private"],
+ tags = [
+ ],
deps = [
":interpretable_android",
":runtime_helpers_android",
@@ -477,6 +474,7 @@ RUNTIME_SOURCES = [
"CelRuntime.java",
"CelRuntimeBuilder.java",
"CelRuntimeFactory.java",
+ "CelRuntimeImpl.java",
"CelRuntimeLegacyImpl.java",
"CelRuntimeLibrary.java",
"ProgramImpl.java",
@@ -570,6 +568,8 @@ java_library(
name = "metadata",
srcs = ["Metadata.java"],
# used_by_android
+ tags = [
+ ],
deps = [
"//common/annotations",
"@maven//:com_google_errorprone_error_prone_annotations",
@@ -579,11 +579,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 +594,8 @@ java_library(
cel_android_library(
name = "interpretable_android",
srcs = INTERPRABLE_SOURCES,
- visibility = ["//visibility:private"],
+ tags = [
+ ],
deps = [
":evaluation_exception",
":evaluation_listener_android",
@@ -808,7 +811,6 @@ java_library(
],
deps = [
":activation",
- ":cel_value_runtime_type_provider",
":descriptor_message_provider",
":descriptor_type_resolver",
":dispatcher",
@@ -825,10 +827,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",
@@ -836,9 +840,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:variable_resolver",
+ "//runtime/planner:program_planner",
"//runtime/standard:add",
"//runtime/standard:int",
"//runtime/standard:timestamp",
@@ -861,8 +872,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",
@@ -877,53 +890,27 @@ java_library(
tags = [
],
deps = [
- ":cel_value_runtime_type_provider",
":dispatcher",
":function_binding",
- ":interpreter",
- ":lite_program_impl",
":lite_runtime",
":program",
":runtime_equality",
":runtime_helpers",
- ":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",
"@maven//:com_google_code_findbugs_annotations",
- "@maven//:com_google_guava_guava",
- ],
-)
-
-java_library(
- name = "lite_program_impl",
- srcs = LITE_PROGRAM_IMPL_SOURCES,
- deps = [
- ":activation",
- ":evaluation_exception",
- ":function_resolver",
- ":interpretable",
- ":program",
- "//:auto_value",
- "//runtime:variable_resolver",
- "@maven//:com_google_errorprone_error_prone_annotations",
- ],
-)
-
-cel_android_library(
- name = "lite_program_impl_android",
- srcs = LITE_PROGRAM_IMPL_SOURCES,
- deps = [
- ":activation_android",
- ":evaluation_exception",
- ":function_resolver_android",
- ":interpretable_android",
- ":program_android",
- ":variable_resolver",
- "//:auto_value",
"@maven//:com_google_errorprone_error_prone_annotations",
+ "@maven//:com_google_guava_guava",
],
)
@@ -933,20 +920,23 @@ cel_android_library(
tags = [
],
deps = [
- ":cel_value_runtime_type_provider_android",
":dispatcher_android",
+ ":evaluation_exception",
":function_binding_android",
- ":interpreter_android",
- ":lite_program_impl_android",
":lite_runtime_android",
":program_android",
":runtime_equality_android",
":runtime_helpers_android",
- ":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",
"@maven//:com_google_code_findbugs_annotations",
"@maven//:com_google_errorprone_error_prone_annotations",
@@ -1039,46 +1029,6 @@ cel_android_library(
],
)
-java_library(
- name = "cel_value_runtime_type_provider",
- srcs = ["CelValueRuntimeTypeProvider.java"],
- deps = [
- ":runtime_type_provider",
- ":unknown_attributes",
- "//common/annotations",
- "//common/exceptions:attribute_not_found",
- "//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/annotations",
- "//common/exceptions:attribute_not_found",
- "//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"],
@@ -1142,8 +1092,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",
@@ -1209,19 +1161,6 @@ cel_android_library(
],
)
-java_library(
- name = "variable_resolver",
- srcs = [
- "CelVariableResolver.java",
- "HierarchicalVariableResolver.java",
- ],
- # used_by_android
- tags = [
- ],
- deps = [
- ],
-)
-
java_library(
name = "program",
srcs = ["Program.java"],
@@ -1231,6 +1170,7 @@ java_library(
":evaluation_exception",
":function_resolver",
":variable_resolver",
+ "//runtime:variable_resolver",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)
@@ -1274,3 +1214,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/CelLateFunctionBindings.java b/runtime/src/main/java/dev/cel/runtime/CelLateFunctionBindings.java
index c1f4b236f..c929b96e9 100644
--- a/runtime/src/main/java/dev/cel/runtime/CelLateFunctionBindings.java
+++ b/runtime/src/main/java/dev/cel/runtime/CelLateFunctionBindings.java
@@ -35,6 +35,10 @@ private CelLateFunctionBindings(ImmutableMap functi
this.functions = functions;
}
+ public boolean containsFunction(String functionName) {
+ return functions.containsKey(functionName);
+ }
+
@Override
public Optional findOverloadMatchingArgs(
String functionName, Collection overloadIds, Object[] args)
diff --git a/runtime/src/main/java/dev/cel/runtime/CelLiteRuntimeBuilder.java b/runtime/src/main/java/dev/cel/runtime/CelLiteRuntimeBuilder.java
index 48b51274d..c7b1e63a4 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,25 @@ CelLiteRuntimeBuilder setStandardFunctions(
@CanIgnoreReturnValue
CelLiteRuntimeBuilder addFunctionBindings(Iterable bindings);
+ /**
+ * Adds bindings for functions that are allowed to be late-bound (resolved at execution time).
+ */
+ @CanIgnoreReturnValue
+ CelLiteRuntimeBuilder addLateBoundFunctions(String... lateBoundFunctionNames);
+
+ /**
+ * Adds bindings for functions that are allowed to be late-bound (resolved at execution time).
+ */
+ @CanIgnoreReturnValue
+ CelLiteRuntimeBuilder addLateBoundFunctions(Iterable lateBoundFunctionNames);
+
+ /**
+ * 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 +83,13 @@ CelLiteRuntimeBuilder setStandardFunctions(
@CanIgnoreReturnValue
CelLiteRuntimeBuilder addLibraries(Iterable extends CelLiteRuntimeLibrary> 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/CelRuntimeBuilder.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeBuilder.java
index e1e3c1b51..01057e140 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;
@@ -48,6 +49,14 @@ public interface CelRuntimeBuilder {
@CanIgnoreReturnValue
CelRuntimeBuilder addFunctionBindings(Iterable bindings);
+ /** Adds bindings for functions that are allowed to be late-bound (resolved at execution time). */
+ @CanIgnoreReturnValue
+ CelRuntimeBuilder addLateBoundFunctions(String... lateBoundFunctionNames);
+
+ /** Adds bindings for functions that are allowed to be late-bound (resolved at execution time). */
+ @CanIgnoreReturnValue
+ CelRuntimeBuilder addLateBoundFunctions(Iterable lateBoundFunctionNames);
+
/**
* Add message {@link Descriptor}s to the builder for type-checking and object creation at
* interpretation time.
@@ -123,6 +132,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 +161,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..7737788df
--- /dev/null
+++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
@@ -0,0 +1,418 @@
+// 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 ImmutableSet lateBoundFunctionNames();
+
+ 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 {
+ return program.eval(resolver, lateBoundFunctionResolver);
+ }
+
+ @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();
+
+ abstract ImmutableSet.Builder lateBoundFunctionNamesBuilder();
+
+ 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 addLateBoundFunctions(String... lateBoundFunctionNames) {
+ checkNotNull(lateBoundFunctionNames);
+ return addLateBoundFunctions(Arrays.asList(lateBoundFunctionNames));
+ }
+
+ @CanIgnoreReturnValue
+ public Builder addLateBoundFunctions(Iterable lateBoundFunctionNames) {
+ checkNotNull(lateBoundFunctionNames);
+ this.lateBoundFunctionNamesBuilder().addAll(lateBoundFunctionNames);
+ 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 extends CelRuntimeLibrary> 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(),
+ lateBoundFunctionNamesBuilder().build());
+ 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..23cfb5dcf 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;
@@ -160,6 +155,18 @@ public CelRuntimeBuilder addFunctionBindings(Iterable bindin
return this;
}
+ @Override
+ public CelRuntimeBuilder addLateBoundFunctions(String... lateBoundFunctionNames) {
+ throw new UnsupportedOperationException(
+ "This method is not supported for the legacy runtime");
+ }
+
+ @Override
+ public CelRuntimeBuilder addLateBoundFunctions(Iterable lateBoundFunctionNames) {
+ throw new UnsupportedOperationException(
+ "This method is not supported for the legacy runtime");
+ }
+
@Override
public CelRuntimeBuilder addMessageTypes(Descriptor... descriptors) {
return addMessageTypes(Arrays.asList(descriptors));
@@ -188,14 +195,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 +294,10 @@ public CelRuntimeLegacyImpl build() {
ImmutableMap.builder();
for (CelFunctionBinding standardFunctionBinding :
newStandardFunctionBindings(runtimeEquality)) {
+ if (standardFunctionBinding instanceof DynamicDispatchBinding) {
+ continue;
+ }
+
functionBindingsBuilder.put(
standardFunctionBinding.getOverloadId(), standardFunctionBinding);
}
@@ -295,19 +312,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 +329,6 @@ public CelRuntimeLegacyImpl build() {
extensionRegistry,
customTypeFactory,
overriddenStandardFunctions,
- celValueProvider,
fileDescriptors,
runtimeLibraries,
ImmutableList.copyOf(customFunctionBindings.values()));
@@ -366,7 +371,8 @@ private ImmutableSet newStandardFunctionBindings(
break;
default:
if (!options.enableHeterogeneousNumericComparisons()) {
- return !CelStandardFunctions.isHeterogeneousComparison(standardOverload);
+ return !CelStandardFunctions.isHeterogeneousComparison(
+ standardOverload);
}
break;
}
@@ -420,7 +426,6 @@ private CelRuntimeLegacyImpl(
ExtensionRegistry extensionRegistry,
@Nullable Function customTypeFactory,
@Nullable CelStandardFunctions overriddenStandardFunctions,
- @Nullable CelValueProvider celValueProvider,
ImmutableSet fileDescriptors,
ImmutableSet celRuntimeLibraries,
ImmutableList celFunctionBindings) {
@@ -430,7 +435,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/CelValueRuntimeTypeProvider.java b/runtime/src/main/java/dev/cel/runtime/CelValueRuntimeTypeProvider.java
deleted file mode 100644
index e071289ca..000000000
--- a/runtime/src/main/java/dev/cel/runtime/CelValueRuntimeTypeProvider.java
+++ /dev/null
@@ -1,150 +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.annotations.Internal;
-import dev.cel.common.exceptions.CelAttributeNotFoundException;
-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 CelAttributeNotFoundException.forMissingMapKey(fieldName);
- }
-
- 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 CelAttributeNotFoundException.forFieldResolution(fieldName);
- }
-
- private CelValueRuntimeTypeProvider(
- CelValueProvider valueProvider, BaseProtoCelValueConverter protoCelValueConverter) {
- this.valueProvider = checkNotNull(valueProvider);
- this.protoCelValueConverter = checkNotNull(protoCelValueConverter);
- }
-}
diff --git a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java
index ba5d05915..e49658190 100644
--- a/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java
+++ b/runtime/src/main/java/dev/cel/runtime/DefaultInterpreter.java
@@ -864,7 +864,7 @@ private IntermediateResult evalMap(ExecutionFrame frame, CelMap mapExpr)
throw CelEvaluationExceptionBuilder.newBuilder(
"duplicate map key [%s]", keyResult.value())
.setErrorCode(CelErrorCode.DUPLICATE_ATTRIBUTE)
- .setMetadata(metadata, entry.id())
+ .setMetadata(metadata, entry.key().id())
.build();
}
@@ -967,7 +967,7 @@ private IntermediateResult maybeAdaptViewToList(IntermediateResult accuValue) {
@SuppressWarnings("unchecked")
private IntermediateResult evalComprehension(
- ExecutionFrame frame, CelExpr unusedExpr, CelComprehension compre)
+ ExecutionFrame frame, CelExpr compreExpr, CelComprehension compre)
throws CelEvaluationException {
String accuVar = compre.accuVar();
String iterVar = compre.iterVar();
@@ -1000,7 +1000,7 @@ private IntermediateResult evalComprehension(
}
int i = 0;
for (Object elem : iterRange) {
- frame.incrementIterations();
+ frame.incrementIterations(metadata, compreExpr.id());
CelAttribute iterAttr = CelAttribute.EMPTY;
if (iterRange instanceof List) {
@@ -1183,13 +1183,14 @@ private Optional findOverload(
return Optional.empty();
}
- private void incrementIterations() throws CelEvaluationException {
+ private void incrementIterations(Metadata metadata, long exprId) throws CelEvaluationException {
if (maxIterations < 0) {
return;
}
if (++iterations > maxIterations) {
throw CelEvaluationExceptionBuilder.newBuilder(
String.format("Iteration budget exceeded: %d", maxIterations))
+ .setMetadata(metadata, exprId)
.setErrorCode(CelErrorCode.ITERATION_BUDGET_EXCEEDED)
.build();
}
diff --git a/runtime/src/main/java/dev/cel/runtime/LiteProgramImpl.java b/runtime/src/main/java/dev/cel/runtime/LiteProgramImpl.java
deleted file mode 100644
index 5e57f497b..000000000
--- a/runtime/src/main/java/dev/cel/runtime/LiteProgramImpl.java
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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 com.google.auto.value.AutoValue;
-import com.google.errorprone.annotations.Immutable;
-import java.util.Map;
-
-@Immutable
-@AutoValue
-abstract class LiteProgramImpl implements Program {
-
- abstract Interpretable interpretable();
-
- @Override
- public Object eval() throws CelEvaluationException {
- return interpretable().eval(GlobalResolver.EMPTY);
- }
-
- @Override
- public Object eval(Map mapValue) throws CelEvaluationException {
- return interpretable().eval(Activation.copyOf(mapValue));
- }
-
- @Override
- public Object eval(Map mapValue, CelFunctionResolver lateBoundFunctionResolver)
- throws CelEvaluationException {
- return interpretable().eval(Activation.copyOf(mapValue), lateBoundFunctionResolver);
- }
-
- @Override
- public Object eval(CelVariableResolver resolver, CelFunctionResolver lateBoundFunctionResolver) {
- // TODO: Wire in program planner
- throw new UnsupportedOperationException("To be implemented");
- }
-
- @Override
- public Object eval(CelVariableResolver resolver) throws CelEvaluationException {
- // TODO: Wire in program planner
- throw new UnsupportedOperationException("To be implemented");
- }
-
- 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..9141b2419 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,36 @@
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 +61,30 @@ 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 lateBoundFunctionNamesBuilder;
@VisibleForTesting final ImmutableSet.Builder runtimeLibrariesBuilder;
@VisibleForTesting final ImmutableSet.Builder standardFunctionBuilder;
+ @VisibleForTesting CelTypeProvider celTypeProvider;
@VisibleForTesting CelValueProvider celValueProvider;
@Override
@@ -102,6 +116,23 @@ public CelLiteRuntimeBuilder addFunctionBindings(Iterable bi
return this;
}
+ @Override
+ public CelLiteRuntimeBuilder addLateBoundFunctions(String... lateBoundFunctionNames) {
+ return addLateBoundFunctions(Arrays.asList(lateBoundFunctionNames));
+ }
+
+ @Override
+ public CelLiteRuntimeBuilder addLateBoundFunctions(Iterable lateBoundFunctionNames) {
+ lateBoundFunctionNamesBuilder.addAll(lateBoundFunctionNames);
+ return this;
+ }
+
+ @Override
+ public CelLiteRuntimeBuilder setTypeProvider(CelTypeProvider celTypeProvider) {
+ this.celTypeProvider = celTypeProvider;
+ return this;
+ }
+
@Override
public CelLiteRuntimeBuilder setValueProvider(CelValueProvider celValueProvider) {
this.celValueProvider = celValueProvider;
@@ -119,12 +150,15 @@ public CelLiteRuntimeBuilder addLibraries(Iterable extends CelLiteRuntimeLibra
return this;
}
+ @Override
+ public CelLiteRuntimeBuilder setContainer(CelContainer container) {
+ this.container = checkNotNull(container);
+ return this;
+ }
+
/** Throws if an unsupported flag in CelOptions is toggled. */
private static void assertAllowedCelOptions(CelOptions celOptions) {
String prefix = "Misconfigured CelOptions: ";
- if (!celOptions.enableCelValue()) {
- throw new IllegalArgumentException(prefix + "enableCelValue must be enabled.");
- }
if (!celOptions.enableUnsignedLongs()) {
throw new IllegalArgumentException(prefix + "enableUnsignedLongs cannot be disabled.");
}
@@ -184,31 +218,57 @@ public CelLiteRuntime build() {
dispatcherBuilder.addOverload(
overloadId, func.getArgTypes(), func.isStrict(), func.getDefinition()));
- Interpreter interpreter =
- new DefaultInterpreter(
- TypeResolver.create(),
- CelValueRuntimeTypeProvider.newInstance(celValueProvider),
+ CelTypeProvider celTypeProvider = DefaultTypeProvider.getInstance();
+ if (this.celTypeProvider != null) {
+ celTypeProvider =
+ new CelTypeProvider.CombinedCelTypeProvider(celTypeProvider, this.celTypeProvider);
+ }
+
+ ProgramPlanner planner =
+ ProgramPlanner.newPlanner(
+ celTypeProvider,
+ celValueProvider,
dispatcherBuilder.build(),
- celOptions);
+ celValueProvider.celValueConverter(),
+ CelContainer.newBuilder().build(),
+ celOptions,
+ lateBoundFunctionNamesBuilder.build());
return new LiteRuntimeImpl(
- interpreter,
celOptions,
customFunctionBindings.values(),
standardFunctions,
runtimeLibs,
- celValueProvider);
+ celValueProvider,
+ celTypeProvider,
+ container,
+ planner);
}
private Builder() {
- this.celOptions =
- CelOptions.current()
- .enableCelValue(true)
- .build();
- this.celValueProvider = (structType, fields) -> 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.lateBoundFunctionNamesBuilder = ImmutableSet.builder();
+ this.container = CelContainer.newBuilder().build();
}
}
@@ -217,17 +277,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/planner/BUILD.bazel b/runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel
index 92733b1b8..2a2d449ea 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"],
@@ -57,19 +58,68 @@ 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_late_bound_call_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/exceptions:overload_not_found",
+ "//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:late_function_binding_android",
+ "//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"],
deps = [
":error_metadata",
":execution_frame",
+ ":localized_evaluation_exception",
":planned_interpretable",
- ":strict_error_exception",
"//:auto_value",
"//common:options",
"//common/exceptions:runtime_exception",
"//common/values",
- "//runtime",
"//runtime:activation",
"//runtime:evaluation_exception",
"//runtime:evaluation_exception_builder",
@@ -77,6 +127,31 @@ java_library(
"//runtime:interpretable",
"//runtime:program",
"//runtime:resolved_overload",
+ "//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",
+ ":localized_evaluation_exception",
+ ":planned_interpretable_android",
+ "//:auto_value",
+ "//common:options",
+ "//common/exceptions:runtime_exception",
+ "//common/values:values_android",
+ "//runtime:activation_android",
+ "//runtime:evaluation_exception",
+ "//runtime:evaluation_exception_builder",
+ "//runtime:interpretable_android",
+ "//runtime:program_android",
+ "//runtime:resolved_overload_android",
+ "//runtime:variable_resolver",
+ "//runtime/src/main/java/dev/cel/runtime:function_resolver_android",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)
@@ -87,14 +162,26 @@ java_library(
deps = [
":execution_frame",
":planned_interpretable",
- "//common/values",
- "//common/values:cel_byte_string",
"//runtime:interpretable",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
],
)
+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"],
@@ -105,16 +192,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",
@@ -132,6 +231,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"],
@@ -140,6 +259,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"],
@@ -147,6 +274,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",
],
)
@@ -157,6 +296,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",
],
)
@@ -174,6 +325,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"],
@@ -188,6 +352,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"],
@@ -202,6 +380,20 @@ java_library(
],
)
+cel_android_library(
+ name = "eval_zero_arity_android",
+ srcs = ["EvalZeroArity.java"],
+ deps = [
+ ":execution_frame_android",
+ ":planned_interpretable_android",
+ "//common/values:cel_value_android",
+ "//common/values:values_android",
+ "//runtime:evaluation_exception",
+ "//runtime:interpretable_android",
+ "//runtime:resolved_overload_android",
+ ],
+)
+
java_library(
name = "eval_unary",
srcs = ["EvalUnary.java"],
@@ -217,6 +409,21 @@ java_library(
],
)
+cel_android_library(
+ name = "eval_unary_android",
+ srcs = ["EvalUnary.java"],
+ deps = [
+ ":eval_helpers_android",
+ ":execution_frame_android",
+ ":planned_interpretable_android",
+ "//common/values:cel_value_android",
+ "//common/values:values_android",
+ "//runtime:evaluation_exception",
+ "//runtime:interpretable_android",
+ "//runtime:resolved_overload_android",
+ ],
+)
+
java_library(
name = "eval_var_args_call",
srcs = ["EvalVarArgsCall.java"],
@@ -232,6 +439,21 @@ java_library(
],
)
+cel_android_library(
+ name = "eval_var_args_call_android",
+ srcs = ["EvalVarArgsCall.java"],
+ deps = [
+ ":eval_helpers_android",
+ ":execution_frame_android",
+ ":planned_interpretable_android",
+ "//common/values:cel_value_android",
+ "//common/values:values_android",
+ "//runtime:evaluation_exception",
+ "//runtime:interpretable_android",
+ "//runtime:resolved_overload_android",
+ ],
+)
+
java_library(
name = "eval_late_bound_call",
srcs = ["EvalLateBoundCall.java"],
@@ -249,6 +471,23 @@ java_library(
],
)
+cel_android_library(
+ name = "eval_late_bound_call_android",
+ srcs = ["EvalLateBoundCall.java"],
+ deps = [
+ ":eval_helpers_android",
+ ":execution_frame_android",
+ ":planned_interpretable_android",
+ "//common/exceptions:overload_not_found",
+ "//common/values:cel_value_android",
+ "//common/values:values_android",
+ "//runtime:evaluation_exception",
+ "//runtime:interpretable_android",
+ "//runtime:resolved_overload_android",
+ "@maven_android//:com_google_guava_guava",
+ ],
+)
+
java_library(
name = "eval_or",
srcs = ["EvalOr.java"],
@@ -262,6 +501,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"],
@@ -275,6 +527,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"],
@@ -287,6 +552,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"],
@@ -303,10 +580,26 @@ 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"],
deps = [
+ ":eval_helpers",
":execution_frame",
":planned_interpretable",
"//runtime:evaluation_exception",
@@ -316,12 +609,28 @@ java_library(
],
)
+cel_android_library(
+ name = "eval_create_list_android",
+ srcs = ["EvalCreateList.java"],
+ deps = [
+ ":eval_helpers_android",
+ ":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"],
deps = [
":execution_frame",
+ ":localized_evaluation_exception",
":planned_interpretable",
+ "//common/exceptions:duplicate_key",
"//runtime:evaluation_exception",
"//runtime:interpretable",
"@maven//:com_google_errorprone_error_prone_annotations",
@@ -329,6 +638,21 @@ java_library(
],
)
+cel_android_library(
+ name = "eval_create_map_android",
+ srcs = ["EvalCreateMap.java"],
+ deps = [
+ ":execution_frame_android",
+ ":localized_evaluation_exception",
+ ":planned_interpretable_android",
+ "//common/exceptions:duplicate_key",
+ "//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"],
@@ -344,6 +668,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"],
@@ -356,13 +695,25 @@ java_library(
],
)
+cel_android_library(
+ name = "execution_frame_android",
+ srcs = ["ExecutionFrame.java"],
+ deps = [
+ "//common:options",
+ "//common/exceptions:iteration_budget_exceeded",
+ "//runtime:evaluation_exception",
+ "//runtime:resolved_overload_android",
+ "//runtime/src/main/java/dev/cel/runtime:function_resolver_android",
+ ],
+)
+
java_library(
name = "eval_helpers",
srcs = ["EvalHelpers.java"],
deps = [
":execution_frame",
+ ":localized_evaluation_exception",
":planned_interpretable",
- ":strict_error_exception",
"//common:error_codes",
"//common/exceptions:runtime_exception",
"//common/values",
@@ -370,9 +721,24 @@ java_library(
],
)
+cel_android_library(
+ name = "eval_helpers_android",
+ srcs = ["EvalHelpers.java"],
+ deps = [
+ ":execution_frame_android",
+ ":localized_evaluation_exception",
+ ":planned_interpretable_android",
+ "//common:error_codes",
+ "//common/exceptions:runtime_exception",
+ "//common/values:values_android",
+ "//runtime:interpretable_android",
+ ],
+)
+
java_library(
- name = "strict_error_exception",
- srcs = ["StrictErrorException.java"],
+ name = "localized_evaluation_exception",
+ srcs = ["LocalizedEvaluationException.java"],
+ # used_by_android
deps = [
"//common:error_codes",
"//common/exceptions:runtime_exception",
@@ -389,6 +755,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"],
@@ -399,3 +775,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/EvalConstant.java b/runtime/src/main/java/dev/cel/runtime/planner/EvalConstant.java
index 74d2811ea..2bebb059b 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/EvalConstant.java
+++ b/runtime/src/main/java/dev/cel/runtime/planner/EvalConstant.java
@@ -14,26 +14,12 @@
package dev.cel.runtime.planner;
-import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.Immutable;
-import dev.cel.common.values.CelByteString;
-import dev.cel.common.values.NullValue;
import dev.cel.runtime.GlobalResolver;
@Immutable
final class EvalConstant extends PlannedInterpretable {
- // Pre-allocation of common constants
- private static final EvalConstant NULL_VALUE = new EvalConstant(NullValue.NULL_VALUE);
- private static final EvalConstant TRUE = new EvalConstant(true);
- private static final EvalConstant FALSE = new EvalConstant(false);
- private static final EvalConstant ZERO = new EvalConstant(0L);
- private static final EvalConstant ONE = new EvalConstant(1L);
- private static final EvalConstant UNSIGNED_ZERO = new EvalConstant(UnsignedLong.ZERO);
- private static final EvalConstant UNSIGNED_ONE = new EvalConstant(UnsignedLong.ONE);
- private static final EvalConstant EMPTY_STRING = new EvalConstant("");
- private static final EvalConstant EMPTY_BYTES = new EvalConstant(CelByteString.EMPTY);
-
@SuppressWarnings("Immutable") // Known CEL constants that aren't mutated are stored
private final Object constant;
@@ -42,59 +28,12 @@ public Object eval(GlobalResolver resolver, ExecutionFrame frame) {
return constant;
}
- static EvalConstant create(boolean value) {
- return value ? TRUE : FALSE;
- }
-
- static EvalConstant create(String value) {
- if (value.isEmpty()) {
- return EMPTY_STRING;
- }
-
- return new EvalConstant(value);
- }
-
- static EvalConstant create(long value) {
- if (value == 0L) {
- return ZERO;
- } else if (value == 1L) {
- return ONE;
- }
-
- return new EvalConstant(Long.valueOf(value));
- }
-
- static EvalConstant create(double value) {
- return new EvalConstant(Double.valueOf(value));
- }
-
- static EvalConstant create(UnsignedLong unsignedLong) {
- if (unsignedLong.longValue() == 0L) {
- return UNSIGNED_ZERO;
- } else if (unsignedLong.longValue() == 1L) {
- return UNSIGNED_ONE;
- }
-
- return new EvalConstant(unsignedLong);
- }
-
- static EvalConstant create(NullValue unused) {
- return NULL_VALUE;
- }
-
- static EvalConstant create(CelByteString byteString) {
- if (byteString.isEmpty()) {
- return EMPTY_BYTES;
- }
- return new EvalConstant(byteString);
- }
-
- static EvalConstant create(Object value) {
- return new EvalConstant(value);
+ static EvalConstant create(long exprId, Object value) {
+ return new EvalConstant(exprId, value);
}
- private EvalConstant(Object constant) {
- super(/* exprId= */ -1); // It's not possible to throw while evaluating a constant
+ private EvalConstant(long exprId, Object constant) {
+ super(exprId);
this.constant = constant;
}
}
diff --git a/runtime/src/main/java/dev/cel/runtime/planner/EvalCreateList.java b/runtime/src/main/java/dev/cel/runtime/planner/EvalCreateList.java
index e519b968c..389a21a82 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/EvalCreateList.java
+++ b/runtime/src/main/java/dev/cel/runtime/planner/EvalCreateList.java
@@ -30,7 +30,7 @@ final class EvalCreateList extends PlannedInterpretable {
public Object eval(GlobalResolver resolver, ExecutionFrame frame) throws CelEvaluationException {
ImmutableList.Builder builder = ImmutableList.builderWithExpectedSize(values.length);
for (PlannedInterpretable value : values) {
- builder.add(value.eval(resolver, frame));
+ builder.add(EvalHelpers.evalStrictly(value, resolver, frame));
}
return builder.build();
}
diff --git a/runtime/src/main/java/dev/cel/runtime/planner/EvalCreateMap.java b/runtime/src/main/java/dev/cel/runtime/planner/EvalCreateMap.java
index abdba90db..4c5a1f0bf 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/EvalCreateMap.java
+++ b/runtime/src/main/java/dev/cel/runtime/planner/EvalCreateMap.java
@@ -16,9 +16,12 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
import com.google.errorprone.annotations.Immutable;
+import dev.cel.common.exceptions.CelDuplicateKeyException;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.GlobalResolver;
+import java.util.HashSet;
@Immutable
final class EvalCreateMap extends PlannedInterpretable {
@@ -35,13 +38,23 @@ final class EvalCreateMap extends PlannedInterpretable {
public Object eval(GlobalResolver resolver, ExecutionFrame frame) throws CelEvaluationException {
ImmutableMap.Builder builder =
ImmutableMap.builderWithExpectedSize(keys.length);
+ HashSet keysSeen = Sets.newHashSetWithExpectedSize(keys.length);
+
for (int i = 0; i < keys.length; i++) {
- builder.put(keys[i].eval(resolver, frame), values[i].eval(resolver, frame));
+ Object key = keys[i].eval(resolver, frame);
+
+ if (!keysSeen.add(key)) {
+ throw new LocalizedEvaluationException(CelDuplicateKeyException.of(key), keys[i].exprId());
+ }
+
+ builder.put(key, values[i].eval(resolver, frame));
}
+
return builder.buildOrThrow();
}
- static EvalCreateMap create(long exprId, PlannedInterpretable[] keys, PlannedInterpretable[] values) {
+ static EvalCreateMap create(
+ long exprId, PlannedInterpretable[] keys, PlannedInterpretable[] values) {
return new EvalCreateMap(exprId, keys, values);
}
diff --git a/runtime/src/main/java/dev/cel/runtime/planner/EvalHelpers.java b/runtime/src/main/java/dev/cel/runtime/planner/EvalHelpers.java
index de034d035..ee86c9dd6 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/EvalHelpers.java
+++ b/runtime/src/main/java/dev/cel/runtime/planner/EvalHelpers.java
@@ -25,8 +25,8 @@ static Object evalNonstrictly(
PlannedInterpretable interpretable, GlobalResolver resolver, ExecutionFrame frame) {
try {
return interpretable.eval(resolver, frame);
- } catch (StrictErrorException e) {
- // Intercept the strict exception to get a more localized expr ID for error reporting purposes
+ } catch (LocalizedEvaluationException e) {
+ // Intercept the localized exception to get a more specific expr ID for error reporting
// Example: foo [1] && strict_err [2] -> ID 2 is propagated.
return ErrorValue.create(e.exprId(), e);
} catch (Exception e) {
@@ -38,10 +38,15 @@ static Object evalStrictly(
PlannedInterpretable interpretable, GlobalResolver resolver, ExecutionFrame frame) {
try {
return interpretable.eval(resolver, frame);
+ } catch (LocalizedEvaluationException e) {
+ // Already localized - propagate as-is to preserve inner expression ID
+ throw e;
} catch (CelRuntimeException e) {
- throw new StrictErrorException(e, interpretable.exprId());
+ // Wrap with current interpretable's location
+ throw new LocalizedEvaluationException(e, interpretable.exprId());
} catch (Exception e) {
- throw new StrictErrorException(
+ // Wrap generic exceptions with location
+ throw new LocalizedEvaluationException(
e.getCause(), CelErrorCode.INTERNAL_ERROR, interpretable.exprId());
}
}
diff --git a/runtime/src/main/java/dev/cel/runtime/planner/StrictErrorException.java b/runtime/src/main/java/dev/cel/runtime/planner/LocalizedEvaluationException.java
similarity index 55%
rename from runtime/src/main/java/dev/cel/runtime/planner/StrictErrorException.java
rename to runtime/src/main/java/dev/cel/runtime/planner/LocalizedEvaluationException.java
index 441a1f27c..603f0b0a5 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/StrictErrorException.java
+++ b/runtime/src/main/java/dev/cel/runtime/planner/LocalizedEvaluationException.java
@@ -1,4 +1,4 @@
-// Copyright 2025 Google LLC
+// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -18,12 +18,16 @@
import dev.cel.common.exceptions.CelRuntimeException;
/**
- * An exception that's raised when a strict call failed to invoke, which includes the source of
- * expression ID, along with canonical CelErrorCode.
+ * Wraps a {@link CelRuntimeException} with its source expression ID for error reporting.
*
- * Note that StrictErrorException should not be surfaced directly back to the user.
+ *
This is the ONLY exception type that propagates through evaluation in the planner. All
+ * CelRuntimeExceptions from runtime helpers are immediately wrapped with location information to
+ * track where the error occurred in the expression tree.
+ *
+ *
Note: This exception should not be surfaced directly to users - it's unwrapped in {@link
+ * PlannedProgram}.
*/
-final class StrictErrorException extends CelRuntimeException {
+final class LocalizedEvaluationException extends CelRuntimeException {
private final long exprId;
@@ -31,11 +35,11 @@ long exprId() {
return exprId;
}
- StrictErrorException(CelRuntimeException cause, long exprId) {
+ LocalizedEvaluationException(CelRuntimeException cause, long exprId) {
this(cause, cause.getErrorCode(), exprId);
}
- StrictErrorException(Throwable cause, CelErrorCode errorCode, long exprId) {
+ LocalizedEvaluationException(Throwable cause, CelErrorCode errorCode, long exprId) {
super(cause, errorCode);
this.exprId = exprId;
}
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/PlannedInterpretable.java b/runtime/src/main/java/dev/cel/runtime/planner/PlannedInterpretable.java
index 5ce3208f8..6f3a9d7ff 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/PlannedInterpretable.java
+++ b/runtime/src/main/java/dev/cel/runtime/planner/PlannedInterpretable.java
@@ -25,8 +25,6 @@ abstract class PlannedInterpretable {
/** Runs interpretation with the given activation which supplies name/value bindings. */
abstract Object eval(GlobalResolver resolver, ExecutionFrame frame) throws CelEvaluationException;
- // TODO: Implement support for late-bound functions and evaluation listener
-
long exprId() {
return exprId;
}
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 aaf26ecb0..22aff43c8 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/PlannedProgram.java
+++ b/runtime/src/main/java/dev/cel/runtime/planner/PlannedProgram.java
@@ -106,9 +106,12 @@ private Object evalOrThrow(
private CelEvaluationException newCelEvaluationException(long exprId, Exception e) {
CelEvaluationExceptionBuilder builder;
- if (e instanceof StrictErrorException) {
- // Preserve detailed error, including error codes if one exists.
- builder = CelEvaluationExceptionBuilder.newBuilder((CelRuntimeException) e.getCause());
+ if (e instanceof LocalizedEvaluationException) {
+ // Use the localized expr ID (most specific error location)
+ LocalizedEvaluationException localized = (LocalizedEvaluationException) e;
+ exprId = localized.exprId();
+ builder =
+ CelEvaluationExceptionBuilder.newBuilder((CelRuntimeException) localized.getCause());
} else if (e instanceof CelRuntimeException) {
builder = CelEvaluationExceptionBuilder.newBuilder((CelRuntimeException) e);
} else {
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 d8c29884e..a24adf214 100644
--- a/runtime/src/main/java/dev/cel/runtime/planner/ProgramPlanner.java
+++ b/runtime/src/main/java/dev/cel/runtime/planner/ProgramPlanner.java
@@ -19,7 +19,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
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;
@@ -55,10 +55,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;
@@ -91,7 +90,7 @@ public Program plan(CelAbstractSyntaxTree ast) throws CelEvaluationException {
private PlannedInterpretable plan(CelExpr celExpr, PlannerContext ctx) {
switch (celExpr.getKind()) {
case CONSTANT:
- return planConstant(celExpr.constant());
+ return planConstant(celExpr.id(), celExpr.constant());
case IDENT:
return planIdent(celExpr, ctx);
case SELECT:
@@ -134,22 +133,22 @@ private PlannedInterpretable planSelect(CelExpr celExpr, PlannerContext ctx) {
return attribute.addQualifier(celExpr.id(), qualifier);
}
- private PlannedInterpretable planConstant(CelConstant celConstant) {
+ private PlannedInterpretable planConstant(long exprId, CelConstant celConstant) {
switch (celConstant.getKind()) {
case NULL_VALUE:
- return EvalConstant.create(celConstant.nullValue());
+ return EvalConstant.create(exprId, celConstant.nullValue());
case BOOLEAN_VALUE:
- return EvalConstant.create(celConstant.booleanValue());
+ return EvalConstant.create(exprId, celConstant.booleanValue());
case INT64_VALUE:
- return EvalConstant.create(celConstant.int64Value());
+ return EvalConstant.create(exprId, celConstant.int64Value());
case UINT64_VALUE:
- return EvalConstant.create(celConstant.uint64Value());
+ return EvalConstant.create(exprId, celConstant.uint64Value());
case DOUBLE_VALUE:
- return EvalConstant.create(celConstant.doubleValue());
+ return EvalConstant.create(exprId, celConstant.doubleValue());
case STRING_VALUE:
- return EvalConstant.create(celConstant.stringValue());
+ return EvalConstant.create(exprId, celConstant.stringValue());
case BYTES_VALUE:
- return EvalConstant.create(celConstant.bytesValue());
+ return EvalConstant.create(exprId, celConstant.bytesValue());
default:
throw new IllegalStateException("Unsupported kind: " + celConstant.getKind());
}
@@ -168,7 +167,7 @@ private PlannedInterpretable planIdent(CelExpr celExpr, PlannerContext ctx) {
private PlannedInterpretable planCheckedIdent(
long id, CelReference identRef, ImmutableMap typeMap) {
if (identRef.value().isPresent()) {
- return planConstant(identRef.value().get());
+ return planConstant(id, identRef.value().get());
}
CelType type = typeMap.get(id);
@@ -181,7 +180,7 @@ private PlannedInterpretable planCheckedIdent(
() ->
new NoSuchElementException(
"Reference to an undefined type: " + identRef.name()));
- return EvalConstant.create(identType);
+ return EvalConstant.create(id, identType);
}
return EvalAttribute.create(id, attributeFactory.newAbsoluteAttribute(identRef.name()));
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/test/java/dev/cel/runtime/BUILD.bazel b/runtime/src/test/java/dev/cel/runtime/BUILD.bazel
index ed76fdbe7..ddaf2d222 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 = [
@@ -51,6 +51,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",
@@ -125,16 +126,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",
],
)
@@ -158,6 +160,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",
@@ -203,8 +206,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..fc4c3762e 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();
@@ -284,6 +284,7 @@ public void eval_customFunctions() throws Exception {
public void eval_customFunctions_asLateBoundFunctions() throws Exception {
CelLiteRuntime runtime =
CelLiteRuntimeFactory.newLiteRuntimeBuilder()
+ .addLateBoundFunctions("isEmpty")
.addFunctionBindings(CelFunctionBinding.from("list_isEmpty", List.class, List::isEmpty))
.setStandardFunctions(CelStandardFunctions.ALL_STANDARD_FUNCTIONS)
.build();
@@ -712,7 +713,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 +723,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..52570b0a3 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
@@ -623,7 +631,10 @@ public void eval_withLateBoundFunction() throws Exception {
CelOverloadDecl.newGlobalOverload(
"lateBoundFunc_string", SimpleType.STRING, SimpleType.STRING)))
.build();
- CelLiteRuntime celRuntime = CelLiteRuntimeFactory.newLiteRuntimeBuilder().build();
+ CelLiteRuntime celRuntime =
+ CelLiteRuntimeFactory.newLiteRuntimeBuilder()
+ .addLateBoundFunctions("lateBoundFunc")
+ .build();
CelAbstractSyntaxTree ast = celCompiler.compile("lateBoundFunc('hello')").getAst();
String result =
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 fa3b5f4ae..fec5fab41 100644
--- a/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java
+++ b/runtime/src/test/java/dev/cel/runtime/CelRuntimeLegacyImplTest.java
@@ -19,12 +19,10 @@
import com.google.protobuf.Message;
import dev.cel.common.CelException;
import dev.cel.common.exceptions.CelDivideByZeroException;
-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;
@@ -108,13 +106,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 =
@@ -123,6 +119,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 63%
rename from runtime/src/test/java/dev/cel/runtime/CelValueInterpreterTest.java
rename to runtime/src/test/java/dev/cel/runtime/PlannerInterpreterTest.java
index f56bb3012..7e98df293 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,20 @@
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()
+ .addLateBoundFunctions("record")
+ .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 6749be24f..6f4b2d991 100644
--- a/runtime/src/test/java/dev/cel/runtime/planner/BUILD.bazel
+++ b/runtime/src/test/java/dev/cel/runtime/planner/BUILD.bazel
@@ -38,6 +38,7 @@ java_library(
"//compiler",
"//compiler:compiler_builder",
"//extensions",
+ "//extensions:optional_library",
"//parser:macro",
"//runtime",
"//runtime:dispatcher",
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 44fb16417..060b40447 100644
--- a/runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java
+++ b/runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java
@@ -64,6 +64,7 @@
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;
@@ -79,7 +80,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(
@@ -126,6 +127,7 @@ public final class ProgramPlannerTest {
.addVar("int_var", SimpleType.INT)
.addVar("dyn_var", SimpleType.DYN)
.addVar("really.long.abbr.ident", SimpleType.DYN)
+ .setContainer(CEL_CONTAINER)
.addFunctionDeclarations(
newFunctionDeclaration("zero", newGlobalOverload("zero_overload", SimpleType.INT)),
newFunctionDeclaration("error", newGlobalOverload("error_overload", SimpleType.INT)),
@@ -143,9 +145,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();
/**
@@ -326,6 +327,17 @@ public void plan_createMap() throws Exception {
assertThat(result).containsExactly("foo", 1L, true, "bar").inOrder();
}
+ @Test
+ public void plan_createMap_containsDuplicateKey_throws() throws Exception {
+ CelAbstractSyntaxTree ast = compile("{true: 1, false: 2, true: 3}");
+ Program program = PLANNER.plan(ast);
+
+ CelEvaluationException e = assertThrows(CelEvaluationException.class, program::eval);
+ assertThat(e)
+ .hasMessageThat()
+ .contains("evaluation error at :20: duplicate map key [true]");
+ }
+
@Test
public void plan_createStruct() throws Exception {
CelAbstractSyntaxTree ast = compile("cel.expr.conformance.proto3.TestAllTypes{}");
diff --git a/runtime/src/test/resources/maps.baseline b/runtime/src/test/resources/maps.baseline
index 1e79b815e..ec89b09c6 100644
--- a/runtime/src/test/resources/maps.baseline
+++ b/runtime/src/test/resources/maps.baseline
@@ -121,7 +121,7 @@ declare map {
}
=====>
bindings: {}
-error: evaluation error at test_location:24: duplicate map key [true]
+error: evaluation error at test_location:20: duplicate map key [true]
error_code: DUPLICATE_ATTRIBUTE
Source: {b: 1, !b: 2, b: 3}[true]
@@ -139,5 +139,5 @@ declare b {
}
=====>
bindings: {b=true}
-error: evaluation error at test_location:15: duplicate map key [true]
+error: evaluation error at test_location:14: duplicate map key [true]
error_code: DUPLICATE_ATTRIBUTE
diff --git a/runtime/src/test/resources/maxComprehension.baseline b/runtime/src/test/resources/maxComprehension.baseline
index fc0cc7555..cad955d0f 100644
--- a/runtime/src/test/resources/maxComprehension.baseline
+++ b/runtime/src/test/resources/maxComprehension.baseline
@@ -4,7 +4,7 @@ declare longlist {
}
=====>
bindings: {longlist=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000]}
-error: evaluation error: Iteration budget exceeded: 1000
+error: evaluation error at test_location:17: Iteration budget exceeded: 1000
error_code: ITERATION_BUDGET_EXCEEDED
Source: longlist.filter(i, i % 2 == 0).map(i, i * 2).map(i, i / 2).size() == 250
@@ -21,7 +21,7 @@ declare longlist {
}
=====>
bindings: {longlist=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499]}
-error: evaluation error: Iteration budget exceeded: 1000
+error: evaluation error at test_location:56: Iteration budget exceeded: 1000
error_code: ITERATION_BUDGET_EXCEEDED
Source: longlist.map(i, longlist.map(j, longlist.map(k, [i, j, k]))).size() == 9
@@ -38,5 +38,5 @@ declare longlist {
}
=====>
bindings: {longlist=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
-error: evaluation error: Iteration budget exceeded: 1000
+error: evaluation error at test_location:28: Iteration budget exceeded: 1000
error_code: ITERATION_BUDGET_EXCEEDED