All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.cel.runtime.CelRuntime Maven / Gradle / Ivy

// Copyright 2022 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.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import com.google.errorprone.annotations.Immutable;
import javax.annotation.concurrent.ThreadSafe;
import com.google.protobuf.Message;
import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelOptions;
import java.util.Map;

/**
 * The CelRuntime creates executable {@code Program} instances from {@code CelAbstractSyntaxTree}
 * values.
 */
@ThreadSafe
public interface CelRuntime {

  /** Creates a {@code Program} from the input {@code ast}. */
  @CanIgnoreReturnValue
  Program createProgram(CelAbstractSyntaxTree ast) throws CelEvaluationException;

  /** Creates an evaluable {@code Program} instance which is thread-safe and immutable. */
  @AutoValue
  @Immutable
  abstract class Program {

    /** Evaluate the expression without any variables. */
    public Object eval() throws CelEvaluationException {
      return evalInternal(Activation.EMPTY);
    }

    /** Evaluate the expression using a {@code mapValue} as the source of input variables. */
    public Object eval(Map mapValue) throws CelEvaluationException {
      return evalInternal(Activation.copyOf(mapValue));
    }

    /** Evaluate the expression using {@code message} fields as the source of input variables. */
    public Object eval(Message message) throws CelEvaluationException {
      return evalInternal(Activation.fromProto(message, getOptions()));
    }

    /** Evaluate a compiled program with a custom variable {@code resolver}. */
    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 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.
     *
     * 

This represents one round of incremental evaluation and may return a final result or a * CelUnknownSet. * *

If no unknowns are declared in the context or {@link CelOptions#enableUnknownTracking() * UnknownTracking} is disabled, this is equivalent to eval. */ public Object advanceEvaluation(UnknownContext context) throws CelEvaluationException { return evalInternal(context, CelEvaluationListener.noOpListener()); } private Object evalInternal(GlobalResolver resolver) throws CelEvaluationException { 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, CelEvaluationListener listener) throws CelEvaluationException { try { Interpretable impl = getInterpretable(); if (getOptions().enableUnknownTracking()) { Preconditions.checkState( impl instanceof UnknownTrackingInterpretable, "Environment misconfigured. Requested unknown tracking without a compatible" + " implementation."); UnknownTrackingInterpretable interpreter = (UnknownTrackingInterpretable) impl; return interpreter.evalTrackingUnknowns( RuntimeUnknownResolver.builder() .setResolver(context.variableResolver()) .setAttributeResolver(context.createAttributeResolver()) .build(), listener); } else { return impl.eval(context.variableResolver(), listener); } } catch (InterpreterException e) { throw unwrapOrCreateEvaluationException(e); } } /** Get the underlying {@link Interpretable} for the {@code Program}. */ abstract Interpretable getInterpretable(); /** Get the {@code CelOptions} configured for this program. */ abstract CelOptions getOptions(); /** Instantiate a new {@code Program} from the input {@code interpretable}. */ static Program from(Interpretable interpretable, CelOptions options) { return new AutoValue_CelRuntime_Program(interpretable, options); } @CheckReturnValue private static CelEvaluationException unwrapOrCreateEvaluationException( InterpreterException e) { if (e.getCause() instanceof CelEvaluationException) { return (CelEvaluationException) e.getCause(); } return new CelEvaluationException(e, e.getErrorCode()); } } /** * Binding consisting of an overload id, a Java-native argument signature, and an overload * definition. * *

While the CEL function has a human-readable {@code camelCase} name, overload ids should use * the following convention where all {@code } names should be ASCII lower-cased. For types * prefer the unparameterized simple name of time, or unqualified package name of any proto-based * type: * *

    *
  • unary member function: _ *
  • binary member function: __ *
  • unary global function: _ *
  • binary global function: __ *
  • global function: ___ *
* *

Examples: string_startsWith_string, mathMax_list, lessThan_money_money */ @AutoValue @Immutable abstract class CelFunctionBinding { public abstract String getOverloadId(); abstract ImmutableList> getArgTypes(); abstract CelFunctionOverload getDefinition(); /** * Create a unary function binding from the {@code overloadId}, {@code arg}, and {@code impl}. */ @SuppressWarnings("unchecked") public static CelFunctionBinding from( String overloadId, Class arg, CelFunctionOverload.Unary impl) { return new AutoValue_CelRuntime_CelFunctionBinding( overloadId, ImmutableList.of(arg), (args) -> impl.apply((T) args[0])); } /** * Create a binary function binding from the {@code overloadId}, {@code arg1}, {@code arg2}, and * {@code impl}. */ @SuppressWarnings("unchecked") public static CelFunctionBinding from( String overloadId, Class arg1, Class arg2, CelFunctionOverload.Binary impl) { return new AutoValue_CelRuntime_CelFunctionBinding( overloadId, ImmutableList.of(arg1, arg2), (args) -> impl.apply((T1) args[0], (T2) args[1])); } /** * Create a function binding from the {@code overloadId}, {@code argTypes}, and {@code impl}. */ public static CelFunctionBinding from( String overloadId, Iterable> argTypes, CelFunctionOverload impl) { return new AutoValue_CelRuntime_CelFunctionBinding( overloadId, ImmutableList.copyOf(argTypes), impl); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy