Note, the underlying {@link CelCompiler} and {@link CelRuntime} values are constructed lazily.
+ *
+ *
CEL Library Internals. Do Not Use. Consumers should use {@code CelFactory} instead.
+ *
+ *
TODO: Restrict visibility once factory is introduced
*/
@Immutable
-final class CelImpl implements Cel, EnvVisitable {
+@Internal
+public final class CelImpl implements Cel, EnvVisitable {
// The lazily constructed compiler and runtime values are memoized and guaranteed to be
// constructed only once without side effects, thus making them effectively immutable.
@@ -142,8 +149,13 @@ static CelImpl combine(CelCompiler compiler, CelRuntime runtime) {
* Create a new builder for constructing a {@code CelImpl} instance.
*
*
By default, {@link CelOptions#DEFAULT} are enabled, as is the CEL standard environment.
+ *
+ *
CEL Library Internals. Do Not Use. Consumers should use {@code CelFactory} instead.
+ *
+ *
TODO: Restrict visibility once factory is introduced
*/
- static CelBuilder newBuilder(
+ @Internal
+ public static CelBuilder newBuilder(
CelCompilerBuilder compilerBuilder, CelRuntimeBuilder celRuntimeBuilder) {
return new CelImpl.Builder(compilerBuilder, celRuntimeBuilder);
}
@@ -199,6 +211,10 @@ public CelContainer container() {
@Override
public CelBuilder setContainer(CelContainer container) {
compilerBuilder.setContainer(container);
+ if (runtimeBuilder instanceof CelRuntimeImpl.Builder) {
+ runtimeBuilder.setContainer(container);
+ }
+
return this;
}
diff --git a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel
index cd33dd67d..ffa3322fe 100644
--- a/bundle/src/test/java/dev/cel/bundle/BUILD.bazel
+++ b/bundle/src/test/java/dev/cel/bundle/BUILD.bazel
@@ -17,6 +17,7 @@ java_library(
deps = [
"//:java_truth",
"//bundle:cel",
+ "//bundle:cel_impl",
"//bundle:environment",
"//bundle:environment_exception",
"//bundle:environment_exporter",
diff --git a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java
index baa8acb59..a3777c759 100644
--- a/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java
+++ b/extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java
@@ -17,6 +17,9 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
+import static dev.cel.common.Operator.INDEX;
+import static dev.cel.common.Operator.OPTIONAL_INDEX;
+import static dev.cel.common.Operator.OPTIONAL_SELECT;
import static dev.cel.extensions.CelOptionalLibrary.Function.FIRST;
import static dev.cel.extensions.CelOptionalLibrary.Function.HAS_VALUE;
import static dev.cel.extensions.CelOptionalLibrary.Function.LAST;
@@ -342,54 +345,69 @@ public void setRuntimeOptions(
"optional_hasValue", Object.class, val -> ((Optional>) val).isPresent())));
runtimeBuilder.addFunctionBindings(
- CelFunctionBinding.from(
- "select_optional_field", // This only handles map selection. Proto selection is
- // special cased inside the interpreter.
- Map.class,
- String.class,
- runtimeEquality::findInMap),
- CelFunctionBinding.from(
- "map_optindex_optional_value", Map.class, Object.class, runtimeEquality::findInMap),
- CelFunctionBinding.from(
- "optional_map_optindex_optional_value",
- Optional.class,
- Object.class,
- (Optional optionalMap, Object key) ->
- indexOptionalMap(optionalMap, key, runtimeEquality)),
- CelFunctionBinding.from(
- "optional_map_index_value",
- Optional.class,
- Object.class,
- (Optional optionalMap, Object key) ->
- indexOptionalMap(optionalMap, key, runtimeEquality)),
- CelFunctionBinding.from(
- "optional_list_index_int",
- Optional.class,
- Long.class,
- CelOptionalLibrary::indexOptionalList),
- CelFunctionBinding.from(
- "list_optindex_optional_int",
- List.class,
- Long.class,
- (List list, Long index) -> {
- int castIndex = Ints.checkedCast(index);
- if (castIndex < 0 || castIndex >= list.size()) {
- return Optional.empty();
- }
- return Optional.of(list.get(castIndex));
- }),
- CelFunctionBinding.from(
- "optional_list_optindex_optional_int",
- Optional.class,
- Long.class,
- CelOptionalLibrary::indexOptionalList));
+ fromOverloads(
+ OPTIONAL_SELECT.getFunction(),
+ CelFunctionBinding.from(
+ "select_optional_field", // This only handles map selection. Proto selection is
+ // special cased inside the interpreter.
+ Map.class,
+ String.class,
+ runtimeEquality::findInMap)));
+
+ runtimeBuilder.addFunctionBindings(
+ fromOverloads(
+ OPTIONAL_INDEX.getFunction(),
+ CelFunctionBinding.from(
+ "list_optindex_optional_int",
+ List.class,
+ Long.class,
+ (List list, Long index) -> {
+ int castIndex = Ints.checkedCast(index);
+ if (castIndex < 0 || castIndex >= list.size()) {
+ return Optional.empty();
+ }
+ return Optional.of(list.get(castIndex));
+ }),
+ CelFunctionBinding.from(
+ "optional_list_optindex_optional_int",
+ Optional.class,
+ Long.class,
+ CelOptionalLibrary::indexOptionalList),
+ CelFunctionBinding.from(
+ "map_optindex_optional_value", Map.class, Object.class, runtimeEquality::findInMap),
+ CelFunctionBinding.from(
+ "optional_map_optindex_optional_value",
+ Optional.class,
+ Object.class,
+ (Optional optionalMap, Object key) ->
+ indexOptionalMap(optionalMap, key, runtimeEquality))));
+
+ runtimeBuilder.addFunctionBindings(
+ fromOverloads(
+ INDEX.getFunction(),
+ CelFunctionBinding.from(
+ "optional_list_index_int",
+ Optional.class,
+ Long.class,
+ CelOptionalLibrary::indexOptionalList),
+ CelFunctionBinding.from(
+ "optional_map_index_value",
+ Optional.class,
+ Object.class,
+ (Optional optionalMap, Object key) ->
+ indexOptionalMap(optionalMap, key, runtimeEquality))));
if (version >= 2) {
runtimeBuilder.addFunctionBindings(
- CelFunctionBinding.from(
- "optional_list_first", Collection.class, CelOptionalLibrary::listOptionalFirst),
- CelFunctionBinding.from(
- "optional_list_last", Collection.class, CelOptionalLibrary::listOptionalLast));
+ fromOverloads(
+ "first",
+ CelFunctionBinding.from(
+ "optional_list_first", Collection.class, CelOptionalLibrary::listOptionalFirst)));
+ runtimeBuilder.addFunctionBindings(
+ fromOverloads(
+ "last",
+ CelFunctionBinding.from(
+ "optional_list_last", Collection.class, CelOptionalLibrary::listOptionalLast)));
}
}
diff --git a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel
index d5155f662..b441c33cf 100644
--- a/extensions/src/test/java/dev/cel/extensions/BUILD.bazel
+++ b/extensions/src/test/java/dev/cel/extensions/BUILD.bazel
@@ -10,6 +10,8 @@ java_library(
deps = [
"//:java_truth",
"//bundle:cel",
+ "//bundle:cel_impl",
+ "//checker",
"//common:cel_ast",
"//common:compiler_common",
"//common:container",
@@ -30,6 +32,7 @@ java_library(
"//extensions:sets",
"//extensions:sets_function",
"//extensions:strings",
+ "//parser",
"//parser:macro",
"//parser:unparser",
"//runtime",
@@ -37,6 +40,7 @@ java_library(
"//runtime:interpreter_util",
"//runtime:lite_runtime",
"//runtime:lite_runtime_factory",
+ "//runtime:runtime_planner_impl",
"@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto",
"@cel_spec//proto/cel/expr/conformance/proto3:test_all_types_java_proto",
"@cel_spec//proto/cel/expr/conformance/test:simple_java_proto",
diff --git a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java
index dd94333c3..0f0c649f8 100644
--- a/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java
+++ b/extensions/src/test/java/dev/cel/extensions/CelOptionalLibraryTest.java
@@ -27,6 +27,8 @@
import dev.cel.bundle.Cel;
import dev.cel.bundle.CelBuilder;
import dev.cel.bundle.CelFactory;
+import dev.cel.bundle.CelImpl;
+import dev.cel.checker.CelCheckerLegacyImpl;
import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelContainer;
import dev.cel.common.CelFunctionDecl;
@@ -43,13 +45,17 @@
import dev.cel.common.types.TypeType;
import dev.cel.common.values.CelByteString;
import dev.cel.common.values.NullValue;
+import dev.cel.compiler.CelCompiler;
+import dev.cel.compiler.CelCompilerImpl;
import dev.cel.expr.conformance.proto3.TestAllTypes;
import dev.cel.expr.conformance.proto3.TestAllTypes.NestedMessage;
import dev.cel.parser.CelMacro;
+import dev.cel.parser.CelParserImpl;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.CelRuntime;
+import dev.cel.runtime.CelRuntimeImpl;
import dev.cel.runtime.InterpreterUtil;
import java.time.Duration;
import java.time.Instant;
@@ -63,6 +69,14 @@
@SuppressWarnings({"unchecked", "SingleTestParameter"})
public class CelOptionalLibraryTest {
+ private enum TestMode {
+ PLANNER_PARSE_ONLY,
+ PLANNER_CHECKED,
+ LEGACY_CHECKED
+ }
+
+ @TestParameter TestMode testMode;
+
@SuppressWarnings("ImmutableEnumChecker") // Test only
private enum ConstantTestCases {
INT("5", "0", SimpleType.INT, 5L),
@@ -92,15 +106,40 @@ private enum ConstantTestCases {
}
}
- private static CelBuilder newCelBuilder() {
+ private static CelBuilder plannerCelBuilder() {
+ // TODO: Replace with factory once available.
+ return CelImpl.newBuilder(
+ CelCompilerImpl.newBuilder(
+ CelParserImpl.newBuilder(),
+ CelCheckerLegacyImpl.newBuilder().setStandardEnvironmentEnabled(true)),
+ CelRuntimeImpl.newBuilder())
+ // CEL-Internal-2
+ .setOptions(CelOptions.current().build());
+ }
+
+ private CelBuilder newCelBuilder() {
return newCelBuilder(Integer.MAX_VALUE);
}
- private static CelBuilder newCelBuilder(int version) {
- return CelFactory.standardCelBuilder()
+ private CelBuilder newCelBuilder(int version) {
+ CelBuilder celBuilder;
+ switch (testMode) {
+ case PLANNER_PARSE_ONLY:
+ case PLANNER_CHECKED:
+ celBuilder = plannerCelBuilder();
+ break;
+ case LEGACY_CHECKED:
+ celBuilder = CelFactory.standardCelBuilder();
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown test mode: " + testMode);
+ }
+
+ return celBuilder
.setOptions(
CelOptions.current()
.enableTimestampEpoch(true)
+ .enableHeterogeneousNumericComparisons(true)
.build())
.setStandardMacros(CelStandardMacro.STANDARD_MACROS)
.setContainer(CelContainer.ofName("cel.expr.conformance.proto3"))
@@ -181,7 +220,7 @@ public void optionalOf_constant_success(@TestParameter ConstantTestCases testCas
throws Exception {
Cel cel = newCelBuilder().setResultType(OptionalType.create(testCase.type)).build();
String expression = String.format("optional.of(%s)", testCase.sourceWithNonZeroValue);
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -198,7 +237,7 @@ public void optionalType_runtimeEquality(@TestParameter ConstantTestCases testCa
.addVar("b", OptionalType.create(testCase.type))
.setResultType(SimpleType.BOOL)
.build();
- CelAbstractSyntaxTree ast = cel.compile("a == b").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "a == b");
boolean result =
(boolean)
@@ -216,7 +255,7 @@ public void optionalType_runtimeEquality(@TestParameter ConstantTestCases testCa
@Test
public void optionalType_adaptsIntegerToLong_success() throws Exception {
Cel cel = newCelBuilder().addVar("a", OptionalType.create(SimpleType.INT)).build();
- CelAbstractSyntaxTree ast = cel.compile("a").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "a");
Optional result =
(Optional) cel.createProgram(ast).eval(ImmutableMap.of("a", Optional.of(5)));
@@ -227,7 +266,7 @@ public void optionalType_adaptsIntegerToLong_success() throws Exception {
@Test
public void optionalType_adaptsFloatToLong_success() throws Exception {
Cel cel = newCelBuilder().addVar("a", OptionalType.create(SimpleType.DOUBLE)).build();
- CelAbstractSyntaxTree ast = cel.compile("a").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "a");
Optional result =
(Optional) cel.createProgram(ast).eval(ImmutableMap.of("a", Optional.of(5.5f)));
@@ -239,7 +278,7 @@ public void optionalType_adaptsFloatToLong_success() throws Exception {
public void optionalOf_nullValue_success() throws Exception {
Cel cel = newCelBuilder().setResultType(SimpleType.DYN).build();
String expression = "optional.of(TestAllTypes{}.single_value)";
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -252,7 +291,7 @@ public void optionalOfNonZeroValue_withZeroValue_returnsEmptyOptionalValue(
@TestParameter ConstantTestCases testCase) throws Exception {
Cel cel = newCelBuilder().setResultType(OptionalType.create(testCase.type)).build();
String expression = String.format("optional.ofNonZeroValue(%s)", testCase.sourceWithZeroValue);
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -266,7 +305,7 @@ public void optionalOfNonZeroValue_withNonZeroValue_returnsOptionalValue(
Cel cel = newCelBuilder().setResultType(OptionalType.create(testCase.type)).build();
String expression =
String.format("optional.ofNonZeroValue(%s)", testCase.sourceWithNonZeroValue);
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -278,7 +317,7 @@ public void optionalOfNonZeroValue_withNonZeroValue_returnsOptionalValue(
public void optionalOfNonZeroValue_withNullValue_returnsEmptyOptionalValue() throws Exception {
Cel cel = newCelBuilder().setResultType(SimpleType.DYN).build();
CelAbstractSyntaxTree ast =
- cel.compile("optional.ofNonZeroValue(TestAllTypes{}.single_value)").getAst();
+ compile(cel, "optional.ofNonZeroValue(TestAllTypes{}.single_value)");
Object result = cel.createProgram(ast).eval();
@@ -289,7 +328,7 @@ public void optionalOfNonZeroValue_withNullValue_returnsEmptyOptionalValue() thr
@Test
public void optionalOfNonZeroValue_withEmptyMessage_returnsEmptyOptionalValue() throws Exception {
Cel cel = newCelBuilder().setResultType(SimpleType.DYN).build();
- CelAbstractSyntaxTree ast = cel.compile("optional.ofNonZeroValue(TestAllTypes{})").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optional.ofNonZeroValue(TestAllTypes{})");
Object result = cel.createProgram(ast).eval();
@@ -300,7 +339,7 @@ public void optionalOfNonZeroValue_withEmptyMessage_returnsEmptyOptionalValue()
@Test
public void optionalNone_success() throws Exception {
Cel cel = newCelBuilder().setResultType(SimpleType.DYN).build();
- CelAbstractSyntaxTree ast = cel.compile("optional.none()").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optional.none()");
Object result = cel.createProgram(ast).eval();
@@ -312,7 +351,7 @@ public void optionalNone_success() throws Exception {
public void optionalValue_success(@TestParameter ConstantTestCases testCase) throws Exception {
Cel cel = newCelBuilder().setResultType(testCase.type).build();
String expression = String.format("optional.of(%s).value()", testCase.sourceWithNonZeroValue);
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -322,7 +361,7 @@ public void optionalValue_success(@TestParameter ConstantTestCases testCase) thr
@Test
public void optionalValue_whenOptionalValueEmpty_throws() throws Exception {
Cel cel = newCelBuilder().build();
- CelAbstractSyntaxTree ast = cel.compile("optional.none().value()").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optional.none().value()");
assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval());
}
@@ -333,7 +372,7 @@ public void optionalHasValue_whenOptionalValuePresent_returnsTrue(
Cel cel = newCelBuilder().setResultType(SimpleType.BOOL).build();
String expression =
String.format("optional.of(%s).hasValue()", testCase.sourceWithNonZeroValue);
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -346,7 +385,7 @@ public void optionalHasValue_whenOptionalValueEmpty_returnsFalse(
Cel cel = newCelBuilder().setResultType(SimpleType.BOOL).build();
String expression =
String.format("optional.ofNonZeroValue(%s).hasValue()", testCase.sourceWithZeroValue);
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -361,7 +400,7 @@ public void optionalOr_success() throws Exception {
.addVar("y", OptionalType.create(SimpleType.INT))
.setResultType(OptionalType.create(SimpleType.INT))
.build();
- CelRuntime.Program program = cel.createProgram(cel.compile("x.or(y)").getAst());
+ CelRuntime.Program program = cel.createProgram(compile(cel, "x.or(y)"));
Object resultLhs = program.eval(ImmutableMap.of("x", Optional.of(5), "y", Optional.empty()));
Object resultRhs = program.eval(ImmutableMap.of("x", Optional.empty(), "y", Optional.of(10)));
@@ -381,15 +420,18 @@ public void optionalOr_shortCircuits() throws Exception {
CelOverloadDecl.newGlobalOverload(
"error_overload", OptionalType.create(SimpleType.INT))))
.addFunctionBindings(
- CelFunctionBinding.from(
- "error_overload",
- ImmutableList.of(),
- val -> {
- throw new IllegalStateException("This function should not have been called!");
- }))
+ CelFunctionBinding.fromOverloads(
+ "errorFunc",
+ CelFunctionBinding.from(
+ "error_overload",
+ ImmutableList.of(),
+ val -> {
+ throw new IllegalStateException(
+ "This function should not have been called!");
+ })))
.setResultType(OptionalType.create(SimpleType.INT))
.build();
- CelRuntime.Program program = cel.createProgram(cel.compile("x.or(errorFunc())").getAst());
+ CelRuntime.Program program = cel.createProgram(compile(cel, "x.or(errorFunc())"));
Object resultLhs = program.eval(ImmutableMap.of("x", Optional.of(5)));
@@ -398,22 +440,17 @@ public void optionalOr_shortCircuits() throws Exception {
@Test
public void optionalOr_producesNonOptionalValue_throws() throws Exception {
- Cel cel =
- CelFactory.standardCelBuilder()
- .addFunctionDeclarations(
- CelFunctionDecl.newFunctionDeclaration(
- "or",
- CelOverloadDecl.newMemberOverload(
- "optional_or_optional", SimpleType.INT, SimpleType.INT, SimpleType.INT)))
- .addFunctionBindings(
- CelFunctionBinding.from("optional_or_optional", Long.class, Long.class, Long::sum))
- .build();
+ Cel cel = newCelBuilder().addVar("x", OptionalType.create(SimpleType.INT)).build();
- CelAbstractSyntaxTree ast = cel.compile("5.or(10)").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "x.or(optional.of(10))");
CelEvaluationException e =
- assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval());
- assertThat(e).hasMessageThat().contains("expected optional value, found: 5");
+ assertThrows(
+ CelEvaluationException.class,
+ () -> cel.createProgram(ast).eval(ImmutableMap.of("x", 5L)));
+ assertThat(e)
+ .hasMessageThat()
+ .contains("evaluation error at :4: No matching overload for function 'or'.");
}
@Test
@@ -424,7 +461,7 @@ public void optionalOrValue_lhsHasValue_success(@TestParameter ConstantTestCases
String.format(
"optional.of(%s).orValue(%s)",
testCase.sourceWithNonZeroValue, testCase.sourceWithZeroValue);
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -441,15 +478,18 @@ public void optionalOrValue_shortCircuits() throws Exception {
"errorFunc",
CelOverloadDecl.newGlobalOverload("error_overload", SimpleType.INT)))
.addFunctionBindings(
- CelFunctionBinding.from(
- "error_overload",
- ImmutableList.of(),
- val -> {
- throw new IllegalStateException("This function should not have been called!");
- }))
+ CelFunctionBinding.fromOverloads(
+ "errorFunc",
+ CelFunctionBinding.from(
+ "error_overload",
+ ImmutableList.of(),
+ val -> {
+ throw new IllegalStateException(
+ "This function should not have been called!");
+ })))
.setResultType(SimpleType.INT)
.build();
- CelRuntime.Program program = cel.createProgram(cel.compile("x.orValue(errorFunc())").getAst());
+ CelRuntime.Program program = cel.createProgram(compile(cel, "x.orValue(errorFunc())"));
Object resultLhs = program.eval(ImmutableMap.of("x", Optional.of(5)));
@@ -462,7 +502,7 @@ public void optionalOrValue_rhsHasValue_success(@TestParameter ConstantTestCases
Cel cel = newCelBuilder().setResultType(testCase.type).build();
String expression =
String.format("optional.none().orValue(%s)", testCase.sourceWithNonZeroValue);
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -475,32 +515,29 @@ public void optionalOrValue_rhsHasValue_success(@TestParameter ConstantTestCases
@TestParameters("{source: 5.orValue(optional.of(10))}")
@TestParameters("{source: 5.orValue(optional.none())}")
public void optionalOrValue_unmatchingTypes_throwsCompilationException(String source) {
+ if (testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ return;
+ }
Cel cel = newCelBuilder().build();
CelValidationException e =
- assertThrows(CelValidationException.class, () -> cel.compile(source).getAst());
+ assertThrows(CelValidationException.class, () -> compile(cel, source));
assertThat(e).hasMessageThat().contains("found no matching overload for 'orValue'");
}
@Test
public void optionalOrValue_producesNonOptionalValue_throws() throws Exception {
- Cel cel =
- CelFactory.standardCelBuilder()
- .addFunctionDeclarations(
- CelFunctionDecl.newFunctionDeclaration(
- "orValue",
- CelOverloadDecl.newMemberOverload(
- "optional_orValue_value", SimpleType.INT, SimpleType.INT, SimpleType.INT)))
- .addFunctionBindings(
- CelFunctionBinding.from(
- "optional_orValue_value", Long.class, Long.class, Long::sum))
- .build();
+ Cel cel = newCelBuilder().addVar("x", OptionalType.create(SimpleType.INT)).build();
- CelAbstractSyntaxTree ast = cel.compile("5.orValue(10)").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "x.orValue(10)");
CelEvaluationException e =
- assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval());
- assertThat(e).hasMessageThat().contains("expected optional value, found: 5");
+ assertThrows(
+ CelEvaluationException.class,
+ () -> cel.createProgram(ast).eval(ImmutableMap.of("x", 5)));
+ assertThat(e)
+ .hasMessageThat()
+ .contains("evaluation error at :9: No matching overload for function 'orValue'.");
}
@Test
@@ -508,7 +545,7 @@ public void optionalOrValue_producesNonOptionalValue_throws() throws Exception {
@TestParameters("{source: optional.none().or(optional.none()).orValue(42) == 42}")
public void optionalChainedFunctions_constants_success(String source) throws Exception {
Cel cel = newCelBuilder().setResultType(SimpleType.BOOL).build();
- CelAbstractSyntaxTree ast = cel.compile(source).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, source);
boolean result = (boolean) cel.createProgram(ast).eval();
@@ -527,7 +564,7 @@ public void optionalChainedFunctions_nestedMaps_success() throws Exception {
.build();
String expression =
"optional.ofNonZeroValue('').or(optional.of(m.c['dashed-index'])).orValue('default value')";
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
String result =
(String)
@@ -550,7 +587,7 @@ public void optionalChainedFunctions_nestedMapsInvalidAccess_throws() throws Exc
.setResultType(SimpleType.STRING)
.build();
String expression = "optional.ofNonZeroValue(m.a.z).orValue(m.c['dashed-index'])";
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
CelEvaluationException e =
assertThrows(
@@ -567,7 +604,7 @@ public void optionalChainedFunctions_nestedMapsInvalidAccess_throws() throws Exc
@Test
public void optionalFieldSelection_onMap_returnsOptionalEmpty() throws Exception {
Cel cel = newCelBuilder().setResultType(OptionalType.create(SimpleType.INT)).build();
- CelAbstractSyntaxTree ast = cel.compile("{'a': 2}.?x").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "{'a': 2}.?x");
Object result = cel.createProgram(ast).eval();
@@ -577,7 +614,7 @@ public void optionalFieldSelection_onMap_returnsOptionalEmpty() throws Exception
@Test
public void optionalFieldSelection_onMap_returnsOptionalValue() throws Exception {
Cel cel = newCelBuilder().setResultType(OptionalType.create(SimpleType.INT)).build();
- CelAbstractSyntaxTree ast = cel.compile("{'a': 2}.?a").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "{'a': 2}.?a");
Optional result = (Optional) cel.createProgram(ast).eval();
@@ -591,7 +628,7 @@ public void optionalFieldSelection_onProtoMessage_returnsOptionalEmpty() throws
.setResultType(OptionalType.create(SimpleType.INT))
.addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName()))
.build();
- CelAbstractSyntaxTree ast = cel.compile("msg.?single_int32").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "msg.?single_int32");
Optional result =
(Optional)
@@ -607,7 +644,7 @@ public void optionalFieldSelection_onProtoMessage_returnsOptionalValue() throws
.setResultType(OptionalType.create(SimpleType.INT))
.addVar("msg", StructTypeReference.create(TestAllTypes.getDescriptor().getFullName()))
.build();
- CelAbstractSyntaxTree ast = cel.compile("msg.?single_int32").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "msg.?single_int32");
Optional result =
(Optional)
@@ -621,8 +658,8 @@ public void optionalFieldSelection_onProtoMessage_returnsOptionalValue() throws
public void optionalFieldSelection_onProtoMessage_listValue() throws Exception {
Cel cel = newCelBuilder().build();
CelAbstractSyntaxTree ast =
- cel.compile("optional.of(TestAllTypes{repeated_string: ['foo']}).?repeated_string.value()")
- .getAst();
+ compile(
+ cel, "optional.of(TestAllTypes{repeated_string: ['foo']}).?repeated_string.value()");
List result = (List) cel.createProgram(ast).eval();
@@ -633,9 +670,8 @@ public void optionalFieldSelection_onProtoMessage_listValue() throws Exception {
public void optionalFieldSelection_onProtoMessage_indexValue() throws Exception {
Cel cel = newCelBuilder().build();
CelAbstractSyntaxTree ast =
- cel.compile(
- "optional.of(TestAllTypes{repeated_string: ['foo']}).?repeated_string[0].value()")
- .getAst();
+ compile(
+ cel, "optional.of(TestAllTypes{repeated_string: ['foo']}).?repeated_string[0].value()");
String result = (String) cel.createProgram(ast).eval();
@@ -656,7 +692,7 @@ public void optionalFieldSelection_onProtoMessage_chainedSuccess() throws Except
StructTypeReference.create(TestAllTypes.getDescriptor().getFullName()))))
.build();
CelAbstractSyntaxTree ast =
- cel.compile("m.?c.missing.or(m.?c['dashed-index']).value().?single_int32").getAst();
+ compile(cel, "m.?c.missing.or(m.?c['dashed-index']).value().?single_int32");
Optional result =
(Optional)
@@ -674,7 +710,10 @@ public void optionalFieldSelection_onProtoMessage_chainedSuccess() throws Except
}
@Test
- public void optionalFieldSelection_indexerOnProtoMessage_throwsException() {
+ public void optionalFieldSelection_indexerOnProtoMessage_typeCheck_throwsException() {
+ if (testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ return;
+ }
Cel cel =
newCelBuilder()
.setResultType(OptionalType.create(SimpleType.INT))
@@ -682,8 +721,7 @@ public void optionalFieldSelection_indexerOnProtoMessage_throwsException() {
.build();
CelValidationException e =
- assertThrows(
- CelValidationException.class, () -> cel.compile("msg[?single_int32]").getAst());
+ assertThrows(CelValidationException.class, () -> compile(cel, "msg[?single_int32]"));
assertThat(e).hasMessageThat().contains("undeclared reference to 'single_int32'");
}
@@ -696,8 +734,7 @@ public void optionalFieldSelection_onProtoMessage_presenceTest() throws Exceptio
.setResultType(SimpleType.BOOL)
.build();
CelAbstractSyntaxTree ast =
- cel.compile("!has(msg.?single_nested_message.bb) && has(msg.?standalone_message.bb)")
- .getAst();
+ compile(cel, "!has(msg.?single_nested_message.bb) && has(msg.?standalone_message.bb)");
boolean result =
(boolean)
@@ -718,7 +755,7 @@ public void optionalFieldSelection_onProtoMessage_presenceTest() throws Exceptio
public void optionalFieldSelection_onMap_hasValueReturnsBoolean(
String source, boolean expectedResult) throws Exception {
Cel cel = newCelBuilder().setResultType(SimpleType.BOOL).build();
- CelAbstractSyntaxTree ast = cel.compile(source).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, source);
boolean result = (boolean) cel.createProgram(ast).eval();
@@ -735,7 +772,7 @@ public void optionalFieldSelection_onMap_hasMacroReturnsTrue() throws Exception
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.setResultType(SimpleType.BOOL)
.build();
- CelAbstractSyntaxTree ast = cel.compile("has(m.?x.y)").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "has(m.?x.y)");
boolean result =
(boolean)
@@ -755,7 +792,7 @@ public void optionalFieldSelection_onMap_hasMacroReturnsFalse() throws Exception
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.setResultType(SimpleType.BOOL)
.build();
- CelAbstractSyntaxTree ast = cel.compile("has(m.?x.y)").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "has(m.?x.y)");
boolean result = (boolean) cel.createProgram(ast).eval(ImmutableMap.of("m", ImmutableMap.of()));
@@ -773,7 +810,7 @@ public void optionalFieldSelection_onOptionalMap_presenceTest() throws Exception
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING))))
.setResultType(SimpleType.BOOL)
.build();
- CelAbstractSyntaxTree ast = cel.compile("has(optm.c) && !has(optm.c.missing)").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "has(optm.c) && !has(optm.c.missing)");
boolean result =
(boolean)
@@ -798,7 +835,7 @@ public void optionalIndex_onOptionalMap_returnsOptionalValue() throws Exception
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING))))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("optm.c[?'dashed-index']").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optm.c[?'dashed-index']");
Object result =
cel.createProgram(ast)
@@ -821,7 +858,7 @@ public void optionalIndex_onOptionalMap_returnsOptionalEmpty() throws Exception
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING))))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("optm.c[?'dashed-index']").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optm.c[?'dashed-index']");
Object result =
cel.createProgram(ast)
@@ -840,7 +877,7 @@ public void optionalIndex_onMap_returnsOptionalEmpty() throws Exception {
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("m.c[?'dashed-index']").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "m.c[?'dashed-index']");
Object result =
cel.createProgram(ast).eval(ImmutableMap.of("m", ImmutableMap.of("c", ImmutableMap.of())));
@@ -858,7 +895,7 @@ public void optionalIndex_onMap_returnsOptionalValue() throws Exception {
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("m.c[?'dashed-index']").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "m.c[?'dashed-index']");
Object result =
cel.createProgram(ast)
@@ -875,8 +912,12 @@ public void optionalIndex_onMap_returnsOptionalValue() throws Exception {
@TestParameters("{source: '{?x: x}'}")
public void optionalIndex_onMapWithUnknownInput_returnsUnknownResult(String source)
throws Exception {
+ if (testMode.equals(TestMode.PLANNER_CHECKED) || testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ // TODO: Uncomment once unknowns is implemented
+ return;
+ }
Cel cel = newCelBuilder().addVar("x", OptionalType.create(SimpleType.INT)).build();
- CelAbstractSyntaxTree ast = cel.compile(source).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, source);
Object result = cel.createProgram(ast).eval();
@@ -894,7 +935,7 @@ public void optionalIndex_onOptionalMapUsingFieldSelection_returnsOptionalValue(
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("{?'key': optional.of('test')}.?key").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "{?'key': optional.of('test')}.?key");
Object result = cel.createProgram(ast).eval();
@@ -908,7 +949,7 @@ public void optionalIndex_onList_returnsOptionalEmpty() throws Exception {
.addVar("l", ListType.create(SimpleType.STRING))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("l[?0]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "l[?0]");
CelRuntime.Program program = cel.createProgram(ast);
assertThat(program.eval(ImmutableMap.of("l", ImmutableList.of()))).isEqualTo(Optional.empty());
@@ -921,7 +962,7 @@ public void optionalIndex_onList_returnsOptionalValue() throws Exception {
.addVar("l", ListType.create(SimpleType.STRING))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("l[?0]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "l[?0]");
Object result = cel.createProgram(ast).eval(ImmutableMap.of("l", ImmutableList.of("hello")));
@@ -935,7 +976,7 @@ public void optionalIndex_onOptionalList_returnsOptionalEmpty() throws Exception
.addVar("optl", OptionalType.create(ListType.create(SimpleType.STRING)))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("optl[?0]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optl[?0]");
CelRuntime.Program program = cel.createProgram(ast);
assertThat(program.eval(ImmutableMap.of("optl", Optional.empty()))).isEqualTo(Optional.empty());
@@ -950,7 +991,7 @@ public void optionalIndex_onOptionalList_returnsOptionalValue() throws Exception
.addVar("optl", OptionalType.create(ListType.create(SimpleType.STRING)))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("optl[?0]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optl[?0]");
Object result =
cel.createProgram(ast)
@@ -961,12 +1002,16 @@ public void optionalIndex_onOptionalList_returnsOptionalValue() throws Exception
@Test
public void optionalIndex_onListWithUnknownInput_returnsUnknownResult() throws Exception {
+ if (testMode.equals(TestMode.PLANNER_CHECKED) || testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ // TODO: Uncomment once unknowns is implemented
+ return;
+ }
Cel cel =
newCelBuilder()
.addVar("x", OptionalType.create(SimpleType.INT))
.setResultType(ListType.create(SimpleType.INT))
.build();
- CelAbstractSyntaxTree ast = cel.compile("[?x]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "[?x]");
Object result = cel.createProgram(ast).eval();
@@ -980,7 +1025,7 @@ public void traditionalIndex_onOptionalList_returnsOptionalEmpty() throws Except
.addVar("optl", OptionalType.create(ListType.create(SimpleType.STRING)))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("optl[0]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optl[0]");
Object result = cel.createProgram(ast).eval(ImmutableMap.of("optl", Optional.empty()));
@@ -996,12 +1041,16 @@ public void traditionalIndex_onOptionalList_returnsOptionalEmpty() throws Except
@TestParameters("{expression: 'optional.none().orValue(optx)'}")
public void optionalChainedFunctions_lhsIsUnknown_returnsUnknown(String expression)
throws Exception {
+ if (testMode.equals(TestMode.PLANNER_CHECKED) || testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ // TODO: Uncomment once unknowns is implemented
+ return;
+ }
Cel cel =
newCelBuilder()
.addVar("optx", OptionalType.create(SimpleType.INT))
.addVar("x", SimpleType.INT)
.build();
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
Object result = cel.createProgram(ast).eval();
@@ -1021,7 +1070,7 @@ public void optionalChainedFunctions_lhsIsError_returnsError(String expression)
.addVar("optx", OptionalType.create(SimpleType.INT))
.addVar("x", SimpleType.INT)
.build();
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
assertThrows(CelEvaluationException.class, () -> cel.createProgram(ast).eval());
}
@@ -1033,7 +1082,7 @@ public void traditionalIndex_onOptionalList_returnsOptionalValue() throws Except
.addVar("optl", OptionalType.create(ListType.create(SimpleType.STRING)))
.setResultType(OptionalType.create(SimpleType.STRING))
.build();
- CelAbstractSyntaxTree ast = cel.compile("optl[0]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optl[0]");
Object result =
cel.createProgram(ast)
@@ -1056,7 +1105,7 @@ public void optionalFieldSelection_onMap_chainedWithSelectorAndIndexer(String so
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.setResultType(SimpleType.BOOL)
.build();
- CelAbstractSyntaxTree ast = cel.compile(source).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, source);
boolean result =
(boolean)
@@ -1084,7 +1133,7 @@ public void traditionalIndexSelection_onOptionalMap_chainedOperatorSuccess(Strin
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING))))
.setResultType(SimpleType.BOOL)
.build();
- CelAbstractSyntaxTree ast = cel.compile(source).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, source);
boolean result =
(boolean)
@@ -1110,8 +1159,7 @@ public void traditionalIndexSelection_onOptionalMap_orChainedList() throws Excep
.setResultType(SimpleType.STRING)
.build();
- CelAbstractSyntaxTree ast =
- cel.compile("optm.c.missing.or(optl[0]).orValue('default value')").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optm.c.missing.or(optl[0]).orValue('default value')");
String result =
(String)
@@ -1129,7 +1177,7 @@ public void traditionalIndexSelection_onOptionalMap_orChainedList() throws Excep
@Test
public void optionalMapCreation_valueIsEmpty_returnsEmptyMap() throws Exception {
Cel cel = newCelBuilder().build();
- CelAbstractSyntaxTree ast = cel.compile("{?'key': optional.none()}").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "{?'key': optional.none()}");
Map result = (Map) cel.createProgram(ast).eval();
@@ -1139,7 +1187,7 @@ public void optionalMapCreation_valueIsEmpty_returnsEmptyMap() throws Exception
@Test
public void optionalMapCreation_valueIsPresent_returnsMap() throws Exception {
Cel cel = newCelBuilder().build();
- CelAbstractSyntaxTree ast = cel.compile("{?'key': optional.of(5)}").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "{?'key': optional.of(5)}");
Map result = (Map) cel.createProgram(ast).eval();
@@ -1161,7 +1209,7 @@ public void optionalMapCreation_withNestedMap_returnsNestedMap() throws Exceptio
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.build();
CelAbstractSyntaxTree ast =
- cel.compile("{?'nested_map': optional.ofNonZeroValue({?'map': m.?c})}").getAst();
+ compile(cel, "{?'nested_map': optional.ofNonZeroValue({?'map': m.?c})}");
Map>> result =
(Map>>)
@@ -1190,8 +1238,7 @@ public void optionalMapCreation_withNestedMapContainingEmptyValue_emptyValueStri
.build();
CelAbstractSyntaxTree ast =
- cel.compile("{?'nested_map': optional.ofNonZeroValue({?'map': m.?c}), 'singleton': true}")
- .getAst();
+ compile(cel, "{?'nested_map': optional.ofNonZeroValue({?'map': m.?c}), 'singleton': true}");
Object result = cel.createProgram(ast).eval(ImmutableMap.of("m", ImmutableMap.of()));
@@ -1199,11 +1246,14 @@ public void optionalMapCreation_withNestedMapContainingEmptyValue_emptyValueStri
}
@Test
- public void optionalMapCreation_valueIsNonOptional_throws() {
+ public void optionalMapCreation_valueIsNonOptional_typeCheck_throws() {
+ if (testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ return;
+ }
Cel cel = newCelBuilder().build();
CelValidationException e =
- assertThrows(CelValidationException.class, () -> cel.compile("{?'hi': 'world'}").getAst());
+ assertThrows(CelValidationException.class, () -> compile(cel, "{?'hi': 'world'}"));
assertThat(e)
.hasMessageThat()
@@ -1217,7 +1267,7 @@ public void optionalMessageCreation_fieldValueIsEmpty_returnsEmptyMessage() thro
.setResultType(StructTypeReference.create(TestAllTypes.getDescriptor().getFullName()))
.build();
CelAbstractSyntaxTree ast =
- cel.compile("TestAllTypes{?single_double_wrapper: optional.ofNonZeroValue(0.0)}").getAst();
+ compile(cel, "TestAllTypes{?single_double_wrapper: optional.ofNonZeroValue(0.0)}");
TestAllTypes result = (TestAllTypes) cel.createProgram(ast).eval();
@@ -1228,7 +1278,7 @@ public void optionalMessageCreation_fieldValueIsEmpty_returnsEmptyMessage() thro
public void optionalMessageCreation_fieldValueIsPresent_returnsMessage() throws Exception {
Cel cel = newCelBuilder().build();
CelAbstractSyntaxTree ast =
- cel.compile("TestAllTypes{?single_double_wrapper: optional.ofNonZeroValue(5.0)}").getAst();
+ compile(cel, "TestAllTypes{?single_double_wrapper: optional.ofNonZeroValue(5.0)}");
TestAllTypes result = (TestAllTypes) cel.createProgram(ast).eval();
@@ -1253,7 +1303,7 @@ public void optionalMessageCreation_fieldValueContainsEmptyMap_returnsEmptyMessa
MapType.create(
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.build();
- CelAbstractSyntaxTree ast = cel.compile(source).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, source);
TestAllTypes result =
(TestAllTypes) cel.createProgram(ast).eval(ImmutableMap.of("m", ImmutableMap.of()));
@@ -1270,8 +1320,7 @@ public void optionalMessageCreation_fieldValueContainsMap_returnsEmptyMessage()
MapType.create(
SimpleType.STRING, MapType.create(SimpleType.STRING, SimpleType.STRING)))
.build();
- CelAbstractSyntaxTree ast =
- cel.compile("TestAllTypes{?map_string_string: m[?'nested']}").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "TestAllTypes{?map_string_string: m[?'nested']}");
TestAllTypes result =
(TestAllTypes)
@@ -1293,7 +1342,7 @@ public void optionalListCreation_allElementsAreEmpty_returnsEmptyList() throws E
.addVar("x", OptionalType.create(SimpleType.INT))
.addVar("y", OptionalType.create(SimpleType.DYN))
.build();
- CelAbstractSyntaxTree ast = cel.compile("[?m.?c, ?x, ?y]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "[?m.?c, ?x, ?y]");
List> result =
(List>)
@@ -1315,7 +1364,7 @@ public void optionalListCreation_containsEmptyElements_emptyElementsAreStripped(
.addVar("x", OptionalType.create(SimpleType.INT))
.addVar("y", OptionalType.create(SimpleType.DYN))
.build();
- CelAbstractSyntaxTree ast = cel.compile("[?m.?c, ?x, ?y]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "[?m.?c, ?x, ?y]");
List> result =
(List>)
@@ -1340,7 +1389,7 @@ public void optionalListCreation_containsMixedTypeElements_success() throws Exce
.addVar("y", OptionalType.create(SimpleType.DYN))
.addVar("z", SimpleType.STRING)
.build();
- CelAbstractSyntaxTree ast = cel.compile("[?m.?c, ?x, ?y, z]").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "[?m.?c, ?x, ?y, z]");
List> result =
(List>)
@@ -1362,7 +1411,10 @@ public void optionalListCreation_containsMixedTypeElements_success() throws Exce
@Test
public void
- optionalListCreation_containsMixedTypeElements_throwsWhenHomogeneousLiteralsEnabled() {
+ optionalListCreation_containsMixedTypeElements_typeCheck_throwsWhenHomogeneousLiteralsEnabled() {
+ if (testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ return;
+ }
Cel cel =
newCelBuilder()
.setOptions(CelOptions.current().enableHomogeneousLiterals(true).build())
@@ -1375,7 +1427,7 @@ public void optionalListCreation_containsMixedTypeElements_success() throws Exce
.build();
CelValidationException e =
- assertThrows(CelValidationException.class, () -> cel.compile("[?m.?c, ?x, ?y]").getAst());
+ assertThrows(CelValidationException.class, () -> compile(cel, "[?m.?c, ?x, ?y]"));
assertThat(e).hasMessageThat().contains("expected type 'map(string, string)' but found 'int'");
}
@@ -1392,7 +1444,7 @@ public void optionalListCreation_withinProtoMessage_success() throws Exception {
String expression =
"TestAllTypes{repeated_string: ['greetings', ?m.nested.?hello], ?repeated_int32:"
+ " optional.ofNonZeroValue([?x, ?y])}";
- CelAbstractSyntaxTree ast = cel.compile(expression).getAst();
+ CelAbstractSyntaxTree ast = compile(cel, expression);
TestAllTypes result =
(TestAllTypes)
@@ -1418,7 +1470,7 @@ public void optionalMapMacro_receiverIsEmpty_returnsOptionalEmpty() throws Excep
.addVar("x", OptionalType.create(SimpleType.INT))
.setResultType(OptionalType.create(SimpleType.INT))
.build();
- CelAbstractSyntaxTree ast = cel.compile("x.optMap(y, y + 1)").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "x.optMap(y, y + 1)");
Optional> result =
(Optional>) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.empty()));
@@ -1433,7 +1485,7 @@ public void optionalMapMacro_receiverHasValue_returnsOptionalValue() throws Exce
.addVar("x", OptionalType.create(SimpleType.INT))
.setResultType(OptionalType.create(SimpleType.INT))
.build();
- CelAbstractSyntaxTree ast = cel.compile("x.optMap(y, y + 1)").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "x.optMap(y, y + 1)");
Optional> result =
(Optional>) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(42L)));
@@ -1450,8 +1502,7 @@ public void optionalMapMacro_withNonIdent_throws() {
.build();
CelValidationException e =
- assertThrows(
- CelValidationException.class, () -> cel.compile("x.optMap(y.z, y.z + 1)").getAst());
+ assertThrows(CelValidationException.class, () -> compile(cel, "x.optMap(y.z, y.z + 1)"));
assertThat(e).hasMessageThat().contains("optMap() variable name must be a simple identifier");
}
@@ -1463,7 +1514,7 @@ public void optionalFlatMapMacro_receiverIsEmpty_returnsOptionalEmpty() throws E
.addVar("x", OptionalType.create(SimpleType.INT))
.setResultType(OptionalType.create(SimpleType.INT))
.build();
- CelAbstractSyntaxTree ast = cel.compile("x.optFlatMap(y, optional.of(y + 1))").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "x.optFlatMap(y, optional.of(y + 1))");
Optional> result =
(Optional>) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.empty()));
@@ -1478,7 +1529,7 @@ public void optionalFlatMapMacro_receiverHasValue_returnsOptionalValue() throws
.addVar("x", OptionalType.create(SimpleType.INT))
.setResultType(OptionalType.create(SimpleType.INT))
.build();
- CelAbstractSyntaxTree ast = cel.compile("x.optFlatMap(y, optional.of(y + 1))").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "x.optFlatMap(y, optional.of(y + 1))");
Optional> result =
(Optional>) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(42L)));
@@ -1494,8 +1545,7 @@ public void optionalFlatMapMacro_withOptionalOfNonZeroValue_optionalEmptyWhenVal
.addVar("x", OptionalType.create(SimpleType.INT))
.setResultType(OptionalType.create(SimpleType.INT))
.build();
- CelAbstractSyntaxTree ast =
- cel.compile("x.optFlatMap(y, optional.ofNonZeroValue(y - 1))").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "x.optFlatMap(y, optional.ofNonZeroValue(y - 1))");
Optional> result =
(Optional>) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(1L)));
@@ -1511,8 +1561,7 @@ public void optionalFlatMapMacro_withOptionalOfNonZeroValue_optionalValueWhenVal
.addVar("x", OptionalType.create(SimpleType.INT))
.setResultType(OptionalType.create(SimpleType.INT))
.build();
- CelAbstractSyntaxTree ast =
- cel.compile("x.optFlatMap(y, optional.ofNonZeroValue(y + 1))").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "x.optFlatMap(y, optional.ofNonZeroValue(y + 1))");
Optional> result =
(Optional>) cel.createProgram(ast).eval(ImmutableMap.of("x", Optional.of(1L)));
@@ -1521,15 +1570,18 @@ public void optionalFlatMapMacro_withOptionalOfNonZeroValue_optionalValueWhenVal
}
@Test
- public void optionalFlatMapMacro_mappingExprIsNonOptional_throws() {
+ public void optionalFlatMapMacro_mappingExprIsNonOptional_typeCheck_throws() {
+ if (testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ return;
+ }
+
Cel cel =
newCelBuilder()
.addVar("x", OptionalType.create(SimpleType.INT))
.setResultType(OptionalType.create(SimpleType.INT))
.build();
CelValidationException e =
- assertThrows(
- CelValidationException.class, () -> cel.compile("x.optFlatMap(y, y + 1)").getAst());
+ assertThrows(CelValidationException.class, () -> compile(cel, "x.optFlatMap(y, y + 1)"));
assertThat(e).hasMessageThat().contains("found no matching overload for '_?_:_'");
}
@@ -1544,7 +1596,7 @@ public void optionalFlatMapMacro_withNonIdent_throws() {
CelValidationException e =
assertThrows(
- CelValidationException.class, () -> cel.compile("x.optFlatMap(y.z, y.z + 1)").getAst());
+ CelValidationException.class, () -> compile(cel, "x.optFlatMap(y.z, y.z + 1)"));
assertThat(e)
.hasMessageThat()
@@ -1554,7 +1606,7 @@ public void optionalFlatMapMacro_withNonIdent_throws() {
@Test
public void optionalType_typeResolution() throws Exception {
Cel cel = newCelBuilder().build();
- CelAbstractSyntaxTree ast = cel.compile("optional_type").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "optional_type");
TypeType optionalRuntimeType = (TypeType) cel.createProgram(ast).eval();
@@ -1566,7 +1618,7 @@ public void optionalType_typeResolution() throws Exception {
public void optionalType_typeComparison() throws Exception {
Cel cel = newCelBuilder().build();
- CelAbstractSyntaxTree ast = cel.compile("type(optional.none()) == optional_type").getAst();
+ CelAbstractSyntaxTree ast = compile(cel, "type(optional.none()) == optional_type");
assertThat(cel.createProgram(ast).eval()).isEqualTo(true);
}
@@ -1576,7 +1628,7 @@ public void optionalType_typeComparison() throws Exception {
@TestParameters("{expression: '[\"a\",\"b\",\"c\"].first().value() == \"a\"'}")
public void listFirst_success(String expression) throws Exception {
Cel cel = newCelBuilder().build();
- boolean result = (boolean) cel.createProgram(cel.compile(expression).getAst()).eval();
+ boolean result = (boolean) cel.createProgram(compile(cel, expression)).eval();
assertThat(result).isTrue();
}
@@ -1585,15 +1637,18 @@ public void listFirst_success(String expression) throws Exception {
@TestParameters("{expression: '[1, 2, 3].last().value() == 3'}")
public void listLast_success(String expression) throws Exception {
Cel cel = newCelBuilder().build();
- boolean result = (boolean) cel.createProgram(cel.compile(expression).getAst()).eval();
+ boolean result = (boolean) cel.createProgram(compile(cel, expression)).eval();
assertThat(result).isTrue();
}
@Test
@TestParameters("{expression: '[1].first()', expectedError: 'undeclared reference to ''first'''}")
@TestParameters("{expression: '[2].last()', expectedError: 'undeclared reference to ''last'''}")
- public void listFirstAndLast_throws_earlyVersion(String expression, String expectedError)
- throws Exception {
+ public void listFirstAndLast_typeCheck_throws_earlyVersion(
+ String expression, String expectedError) throws Exception {
+ if (testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ return;
+ }
// Configure Cel with an earlier version of the 'optional' library, which did not support
// 'first' and 'last'
Cel cel = newCelBuilder(1).build();
@@ -1601,9 +1656,59 @@ public void listFirstAndLast_throws_earlyVersion(String expression, String expec
assertThrows(
CelValidationException.class,
() -> {
- cel.createProgram(cel.compile(expression).getAst()).eval();
+ cel.createProgram(compile(cel, expression)).eval();
}))
.hasMessageThat()
.contains(expectedError);
}
+
+ @Test
+ public void optionalMapCreation_mapKeySetOnNonOptional_throws() {
+ String expression = "{?1: dyn(\"one\")}";
+ Cel cel = newCelBuilder().build();
+
+ CelEvaluationException e =
+ assertThrows(
+ CelEvaluationException.class, () -> cel.createProgram(compile(cel, expression)).eval());
+ assertThat(e)
+ .hasMessageThat()
+ .contains("Cannot initialize optional entry '1' from non-optional value one");
+ }
+
+ @Test
+ public void optionalListCreation_listKeySetOnNonOptional_throws() {
+ String expression = "[?dyn(1)]";
+ Cel cel = newCelBuilder().build();
+
+ CelEvaluationException e =
+ assertThrows(
+ CelEvaluationException.class, () -> cel.createProgram(compile(cel, expression)).eval());
+ assertThat(e)
+ .hasMessageThat()
+ .contains("Cannot initialize optional list element from non-optional value 1");
+ }
+
+ @Test
+ public void optionalMessageCreation_fieldKeySetOnNonOptional_throws() {
+ String expression = "TestAllTypes{?single_double_wrapper: dyn('foo')}";
+ Cel cel = newCelBuilder().build();
+
+ CelEvaluationException e =
+ assertThrows(
+ CelEvaluationException.class, () -> cel.createProgram(compile(cel, expression)).eval());
+ assertThat(e)
+ .hasMessageThat()
+ .contains(
+ "Cannot initialize optional entry 'single_double_wrapper' from non-optional value foo");
+ }
+
+ private CelAbstractSyntaxTree compile(CelCompiler compiler, String expression)
+ throws CelValidationException {
+ CelAbstractSyntaxTree ast = compiler.parse(expression).getAst();
+ if (testMode.equals(TestMode.PLANNER_PARSE_ONLY)) {
+ return ast;
+ }
+
+ return compiler.check(ast).getAst();
+ }
}
diff --git a/runtime/BUILD.bazel b/runtime/BUILD.bazel
index 074ef2059..72ec02d12 100644
--- a/runtime/BUILD.bazel
+++ b/runtime/BUILD.bazel
@@ -338,7 +338,6 @@ java_library(
java_library(
name = "runtime_planner_impl",
- testonly = 1, # TODO: Move to factory when ready for exposure
visibility = ["//:internal"],
exports = [
"//runtime/src/main/java/dev/cel/runtime:runtime_planner_impl",
diff --git a/runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java b/runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
index 44377db09..e910c77a9 100644
--- a/runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
+++ b/runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
@@ -54,10 +54,15 @@
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
+/**
+ * {@link CelRuntime} implementation based on the {@link ProgramPlanner}.
+ *
+ *
CEL Library Internals. Do Not Use.
+ */
@AutoValue
@Internal
@Immutable
-abstract class CelRuntimeImpl implements CelRuntime {
+public abstract class CelRuntimeImpl implements CelRuntime {
abstract ProgramPlanner planner();
@@ -180,7 +185,12 @@ public Object advanceEvaluation(UnknownContext context) throws CelEvaluationExce
@Override
public abstract Builder toRuntimeBuilder();
- static Builder newBuilder() {
+ /**
+ * CEL Library Internals. Do not use. Consumers should use {@code CelRuntimeFactory} instead.
+ *
+ *