Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions extensions/src/test/java/dev/cel/extensions/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ java_library(
"//runtime:interpreter_util",
"//runtime:lite_runtime",
"//runtime:lite_runtime_factory",
"//runtime:partial_vars",
"//runtime:unknown_attributes",
"@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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@
import dev.cel.expr.conformance.proto3.TestAllTypes.NestedMessage;
import dev.cel.parser.CelMacro;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelAttributePattern;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.CelRuntime;
import dev.cel.runtime.InterpreterUtil;
import dev.cel.runtime.PartialVars;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
Expand Down Expand Up @@ -897,14 +899,14 @@ 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 = compile(cel, source);

Object result = cel.createProgram(ast).eval();
Object result =
cel.createProgram(ast)
.eval(
PartialVars.of(
ImmutableMap.of(), CelAttributePattern.fromQualifiedIdentifier("x")));

assertThat(InterpreterUtil.isUnknown(result)).isTrue();
}
Expand Down Expand Up @@ -987,18 +989,18 @@ 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 = compile(cel, "[?x]");

Object result = cel.createProgram(ast).eval();
Object result =
cel.createProgram(ast)
.eval(
PartialVars.of(
ImmutableMap.of(), CelAttributePattern.fromQualifiedIdentifier("x")));

assertThat(InterpreterUtil.isUnknown(result)).isTrue();
}
Expand Down Expand Up @@ -1026,18 +1028,18 @@ 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 = compile(cel, expression);

Object result = cel.createProgram(ast).eval();
Object result =
cel.createProgram(ast)
.eval(
PartialVars.of(
ImmutableMap.of(), CelAttributePattern.fromQualifiedIdentifier("optx")));

assertThat(InterpreterUtil.isUnknown(result)).isTrue();
}
Expand Down
6 changes: 6 additions & 0 deletions runtime/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,9 @@ java_library(
"//runtime/src/main/java/dev/cel/runtime:runtime_planner_impl",
],
)

java_library(
name = "partial_vars",
visibility = ["//:internal"],
exports = ["//runtime/src/main/java/dev/cel/runtime:partial_vars"],
)
37 changes: 35 additions & 2 deletions runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,7 @@ java_library(
":evaluation_listener",
":function_binding",
":function_resolver",
":partial_vars",
":program",
":proto_message_runtime_equality",
":runtime",
Expand Down Expand Up @@ -938,6 +939,7 @@ java_library(
":function_resolver",
":interpretable",
":interpreter",
":partial_vars",
":program",
":proto_message_activation_factory",
":runtime_equality",
Expand All @@ -955,7 +957,6 @@ java_library(
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
"@maven//:org_jspecify_jspecify",
],
)

Expand Down Expand Up @@ -1014,6 +1015,7 @@ java_library(
":evaluation_exception",
":function_resolver",
":interpretable",
":partial_vars",
":program",
":variable_resolver",
"//:auto_value",
Expand All @@ -1029,6 +1031,7 @@ cel_android_library(
":evaluation_exception",
":function_resolver_android",
":interpretable_android",
":partial_vars_android",
":program_android",
":variable_resolver",
"//:auto_value",
Expand Down Expand Up @@ -1318,6 +1321,35 @@ cel_android_library(
],
)

java_library(
name = "partial_vars",
srcs = ["PartialVars.java"],
tags = [
],
deps = [
":variable_resolver",
"//:auto_value",
"//runtime:unknown_attributes",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
],
)

cel_android_library(
name = "partial_vars_android",
srcs = ["PartialVars.java"],
tags = [
],
visibility = ["//third_party/java/cel:__subpackages__"],
deps = [
":variable_resolver",
"//:auto_value",
"//runtime:unknown_attributes_android",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
],
)

java_library(
name = "program",
srcs = ["Program.java"],
Expand All @@ -1326,6 +1358,7 @@ java_library(
deps = [
":evaluation_exception",
":function_resolver",
":partial_vars",
":variable_resolver",
"@maven//:com_google_errorprone_error_prone_annotations",
],
Expand All @@ -1339,8 +1372,8 @@ cel_android_library(
deps = [
":evaluation_exception",
":function_resolver_android",
":partial_vars_android",
":variable_resolver",
"//:auto_value",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)
Expand Down
11 changes: 11 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,17 @@ public Object eval(
return program.eval(resolver, lateBoundFunctionResolver);
}

@Override
public Object eval(PartialVars partialVars) throws CelEvaluationException {
return program.eval(partialVars);
}

@Override
public Object eval(PartialVars partialVars, CelFunctionResolver lateBoundFunctionResolver)
throws CelEvaluationException {
return program.eval(partialVars, lateBoundFunctionResolver);
}

@Override
public Object trace(CelEvaluationListener listener) throws CelEvaluationException {
throw new UnsupportedOperationException("Trace is not yet supported.");
Expand Down
13 changes: 13 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/LiteProgramImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ public Object eval(CelVariableResolver resolver) throws CelEvaluationException {
throw new UnsupportedOperationException("To be implemented");
}

@Override
public Object eval(PartialVars partialVars) throws CelEvaluationException {
// TODO: Wire in program planner
throw new UnsupportedOperationException("To be implemented");
}

@Override
public Object eval(PartialVars partialVars, CelFunctionResolver lateBoundFunctionResolver)
throws CelEvaluationException {
// TODO: Wire in program planner
throw new UnsupportedOperationException("To be implemented");
}

static Program plan(Interpretable interpretable) {
return new AutoValue_LiteProgramImpl(interpretable);
}
Expand Down
64 changes: 64 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/PartialVars.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// 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.common.collect.ImmutableList;
import java.util.Map;
import java.util.Optional;

/**
* A holder for a {@link CelVariableResolver} and a set of {@link CelAttributePattern}s that dictate
* which missing attributes should evaluate to {@code dev.cel.runtime.CelUnknownSet}.
*/
@AutoValue
public abstract class PartialVars {

/** The resolver to use for resolving evaluation variables. */
public abstract CelVariableResolver resolver();

/**
* A list of attribute patterns specifying which missing attribute paths should be tracked as
* unknown values.
*/
public abstract ImmutableList<CelAttributePattern> unknowns();

/**
* Constructs a new {@code PartialVars} from a {@link CelVariableResolver} and a list of {@link
* CelAttributePattern}s.
*/
public static PartialVars of(
CelVariableResolver resolver, Iterable<CelAttributePattern> unknowns) {
return new AutoValue_PartialVars(resolver, ImmutableList.copyOf(unknowns));
}

/**
* Constructs a new {@code PartialVars} from a map of variables and an array of {@link
* CelAttributePattern}s.
*/
public static PartialVars of(Map<String, ?> variables, CelAttributePattern... unknowns) {
return of(
(name) -> variables.containsKey(name) ? Optional.of(variables.get(name)) : Optional.empty(),
unknowns);
}

/**
* Constructs a new {@code PartialVars} from a {@link CelVariableResolver} and an array of {@link
* CelAttributePattern}s.
*/
public static PartialVars of(CelVariableResolver resolver, CelAttributePattern... unknowns) {
return of(resolver, ImmutableList.copyOf(unknowns));
}
}
6 changes: 6 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/Program.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,10 @@ Object eval(Map<String, ?> mapValue, CelFunctionResolver lateBoundFunctionResolv
*/
Object eval(CelVariableResolver resolver, CelFunctionResolver lateBoundFunctionResolver)
throws CelEvaluationException;

/** Evaluate a compiled program with unknown attribute patterns {@code partialVars}. */
Object eval(PartialVars partialVars) throws CelEvaluationException;

Object eval(PartialVars partialVars, CelFunctionResolver lateBoundFunctionResolver)
throws CelEvaluationException;
}
17 changes: 17 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/ProgramImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,23 @@ public Object eval(Map<String, ?> mapValue, CelFunctionResolver lateBoundFunctio
return evalInternal(Activation.copyOf(mapValue), lateBoundFunctionResolver);
}

@Override
public Object eval(PartialVars partialVars) throws CelEvaluationException {
return evalInternal(
UnknownContext.create(partialVars.resolver(), partialVars.unknowns()),
Optional.empty(),
Optional.empty());
}

@Override
public Object eval(PartialVars partialVars, CelFunctionResolver lateBoundFunctionResolver)
throws CelEvaluationException {
return evalInternal(
UnknownContext.create(partialVars.resolver(), partialVars.unknowns()),
Optional.of(lateBoundFunctionResolver),
Optional.empty());
}

@Override
public Object trace(CelEvaluationListener listener) throws CelEvaluationException {
return evalInternal(Activation.EMPTY, listener);
Expand Down
Loading
Loading