Skip to content

Commit

Permalink
Add evaluation listener
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 570177910
  • Loading branch information
l46kok authored and copybara-github committed Oct 2, 2023
1 parent 817b335 commit 4cf0ad7
Show file tree
Hide file tree
Showing 11 changed files with 372 additions and 57 deletions.
2 changes: 0 additions & 2 deletions common/src/main/java/dev/cel/common/CelDescriptorUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

package dev.cel.common;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
Expand Down Expand Up @@ -63,7 +62,6 @@ public static ImmutableSet<FileDescriptor> getFileDescriptorsForDescriptors(
* <p>Warning: This will produce unique FileDescriptor instances. Use with care especially in
* hermetic environments.
*/
@VisibleForTesting
public static ImmutableSet<FileDescriptor> getFileDescriptorsFromFileDescriptorSet(
FileDescriptorSet fileDescriptorSet) {
return FileDescriptorSetConverter.convert(fileDescriptorSet);
Expand Down
5 changes: 5 additions & 0 deletions runtime/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,8 @@ java_library(
name = "interpreter_util",
exports = ["//runtime/src/main/java/dev/cel/runtime:interpreter_util"],
)

java_library(
name = "evaluation_listener",
exports = ["//runtime/src/main/java/dev/cel/runtime:evaluation_listener"],
)
18 changes: 15 additions & 3 deletions runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ java_library(
exports = [":base"],
deps = [
":base",
":evaluation_listener",
":runtime_helper",
":unknown_attributes",
"//:auto_value",
Expand All @@ -85,7 +86,6 @@ java_library(
"//common/ast",
"//common/internal:dynamic_proto",
"//common/types:type_providers",
"//runtime:unknown_attributes",
"@cel_spec//proto/cel/expr:expr_java_proto",
"@maven//:com_google_code_findbugs_annotations",
"@maven//:com_google_errorprone_error_prone_annotations",
Expand Down Expand Up @@ -142,6 +142,7 @@ java_library(
],
deps = [
":base",
":evaluation_listener",
":interpreter",
":unknown_attributes",
"//:auto_value",
Expand All @@ -150,7 +151,6 @@ java_library(
"//common:options",
"//common/annotations",
"//common/internal:dynamic_proto",
"//runtime:unknown_attributes",
"@maven//:com_google_code_findbugs_annotations",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand Down Expand Up @@ -178,12 +178,12 @@ java_library(
tags = [
],
deps = [
":unknown_attributes",
"//common",
"//common:compiler_common",
"//parser",
"//parser:operator",
"//parser:parser_builder",
"//runtime:unknown_attributes",
"@cel_spec//proto/cel/expr:expr_java_proto",
"@maven//:com_google_guava_guava",
],
Expand Down Expand Up @@ -216,3 +216,15 @@ java_library(
"@maven//:org_jspecify_jspecify",
],
)

java_library(
name = "evaluation_listener",
srcs = ["CelEvaluationListener.java"],
tags = [
],
deps = [
"//common/ast",
"@maven//:com_google_code_findbugs_annotations",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)
40 changes: 40 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelEvaluationListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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 javax.annotation.concurrent.ThreadSafe;
import dev.cel.common.ast.CelExpr;

/**
* Functional interface for a callback method invoked by the runtime. Implementations must ensure
* that its instances are unconditionally thread-safe.
*/
@FunctionalInterface
@ThreadSafe
public interface CelEvaluationListener {

/**
* Callback method invoked by the CEL runtime as evaluation progresses through the AST.
*
* @param expr CelExpr that was evaluated to produce the evaluated result.
* @param evaluatedResult Evaluated result.
*/
void callback(CelExpr expr, Object evaluatedResult);

/** Construct a listener that does nothing. */
static CelEvaluationListener noOpListener() {
return (arg1, arg2) -> {};
}
}
52 changes: 47 additions & 5 deletions runtime/src/main/java/dev/cel/runtime/CelRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,41 @@ public Object eval(CelVariableResolver resolver) throws CelEvaluationException {
return evalInternal((name) -> resolver.find(name).orElse(null));
}

/**
* Trace evaluates a compiled program without any variables and invokes the listener as
* evaluation progresses through the AST.
*/
public Object trace(CelEvaluationListener listener) throws CelEvaluationException {
return evalInternal(Activation.EMPTY, listener);
}

/**
* Trace evaluates a compiled program using a {@code mapValue} as the source of input variables.
* The listener is invoked as evaluation progresses through the AST.
*/
public Object trace(Map<String, ?> mapValue, CelEvaluationListener listener)
throws CelEvaluationException {
return evalInternal(Activation.copyOf(mapValue), listener);
}

/**
* Trace evaluates a compiled program using {@code message} fields as the source of input
* variables. The listener is invoked as evaluation progresses through the AST.
*/
public Object trace(Message message, CelEvaluationListener listener)
throws CelEvaluationException {
return evalInternal(Activation.fromProto(message, getOptions()), listener);
}

/**
* Trace evaluates a compiled program using a custom variable {@code resolver}. The listener is
* invoked as evaluation progresses through the AST.
*/
public Object trace(CelVariableResolver resolver, CelEvaluationListener listener)
throws CelEvaluationException {
return evalInternal((name) -> resolver.find(name).orElse(null), listener);
}

/**
* Advance evaluation based on the current unknown context.
*
Expand All @@ -77,18 +112,24 @@ public Object eval(CelVariableResolver resolver) throws CelEvaluationException {
* UnknownTracking} is disabled, this is equivalent to eval.
*/
public Object advanceEvaluation(UnknownContext context) throws CelEvaluationException {
return evalInternal(context);
return evalInternal(context, CelEvaluationListener.noOpListener());
}

private Object evalInternal(GlobalResolver resolver) throws CelEvaluationException {
return evalInternal(UnknownContext.create(resolver));
return evalInternal(resolver, CelEvaluationListener.noOpListener());
}

private Object evalInternal(GlobalResolver resolver, CelEvaluationListener listener)
throws CelEvaluationException {
return evalInternal(UnknownContext.create(resolver), listener);
}

/**
* Evaluate an expr node with an UnknownContext (an activation annotated with which attributes
* are unknown).
*/
private Object evalInternal(UnknownContext context) throws CelEvaluationException {
private Object evalInternal(UnknownContext context, CelEvaluationListener listener)
throws CelEvaluationException {
try {
Interpretable impl = getInterpretable();
if (getOptions().enableUnknownTracking()) {
Expand All @@ -102,9 +143,10 @@ private Object evalInternal(UnknownContext context) throws CelEvaluationExceptio
RuntimeUnknownResolver.builder()
.setResolver(context.variableResolver())
.setAttributeResolver(context.createAttributeResolver())
.build());
.build(),
listener);
} else {
return impl.eval(context.variableResolver());
return impl.eval(context.variableResolver(), listener);
}
} catch (InterpreterException e) {
throw unwrapOrCreateEvaluationException(e);
Expand Down
12 changes: 0 additions & 12 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,91 +75,79 @@ public static final class Builder implements CelRuntimeBuilder {
private boolean standardEnvironmentEnabled;
private Function<String, Message.Builder> customTypeFactory;

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder setOptions(CelOptions options) {
this.options = options;
return this;
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder addFunctionBindings(CelFunctionBinding... bindings) {
return addFunctionBindings(Arrays.asList(bindings));
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder addFunctionBindings(Iterable<CelFunctionBinding> bindings) {
bindings.forEach(o -> functionBindings.put(o.getOverloadId(), o));
return this;
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder addMessageTypes(Descriptor... descriptors) {
return addMessageTypes(Arrays.asList(descriptors));
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder addMessageTypes(Iterable<Descriptor> descriptors) {
return addFileTypes(CelDescriptorUtil.getFileDescriptorsForDescriptors(descriptors));
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder addFileTypes(FileDescriptor... fileDescriptors) {
return addFileTypes(Arrays.asList(fileDescriptors));
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder addFileTypes(Iterable<FileDescriptor> fileDescriptors) {
this.fileTypes.addAll(checkNotNull(fileDescriptors));
return this;
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder addFileTypes(FileDescriptorSet fileDescriptorSet) {
return addFileTypes(
CelDescriptorUtil.getFileDescriptorsFromFileDescriptorSet(fileDescriptorSet));
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder setTypeFactory(Function<String, Message.Builder> typeFactory) {
this.customTypeFactory = typeFactory;
return this;
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder setStandardEnvironmentEnabled(boolean value) {
standardEnvironmentEnabled = value;
return this;
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder addLibraries(CelRuntimeLibrary... libraries) {
checkNotNull(libraries);
return this.addLibraries(Arrays.asList(libraries));
}

/** {@inheritDoc} */
@Override
@CanIgnoreReturnValue
public Builder addLibraries(Iterable<? extends CelRuntimeLibrary> libraries) {
Expand Down
Loading

0 comments on commit 4cf0ad7

Please sign in to comment.