Skip to content

Introduce cel package aliases for Activation #1123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 7, 2025
Merged
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
25 changes: 12 additions & 13 deletions cel/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,31 +502,30 @@ func (e *Env) TypeProvider() ref.TypeProvider {
return &interopLegacyTypeProvider{Provider: e.provider}
}

// UnknownVars returns an interpreter.PartialActivation which marks all variables declared in the
// Env as unknown AttributePattern values.
// UnknownVars returns a PartialActivation which marks all variables declared in the Env as
// unknown AttributePattern values.
//
// Note, the UnknownVars will behave the same as an interpreter.EmptyActivation unless the
// PartialAttributes option is provided as a ProgramOption.
func (e *Env) UnknownVars() interpreter.PartialActivation {
// Note, the UnknownVars will behave the same as an cel.NoVars() unless the PartialAttributes
// option is provided as a ProgramOption.
func (e *Env) UnknownVars() PartialActivation {
act := interpreter.EmptyActivation()
part, _ := PartialVars(act, e.computeUnknownVars(act)...)
return part
}

// PartialVars returns an interpreter.PartialActivation where all variables not in the input variable
// PartialVars returns a PartialActivation where all variables not in the input variable
// set, but which have been configured in the environment, are marked as unknown.
//
// The `vars` value may either be an interpreter.Activation or any valid input to the
// interpreter.NewActivation call.
// The `vars` value may either be an Activation or any valid input to the cel.NewActivation call.
//
// Note, this is equivalent to calling cel.PartialVars and manually configuring the set of unknown
// variables. For more advanced use cases of partial state where portions of an object graph, rather
// than top-level variables, are missing the PartialVars() method may be a more suitable choice.
//
// Note, the PartialVars will behave the same as an interpreter.EmptyActivation unless the
// PartialAttributes option is provided as a ProgramOption.
func (e *Env) PartialVars(vars any) (interpreter.PartialActivation, error) {
act, err := interpreter.NewActivation(vars)
// Note, the PartialVars will behave the same as cel.NoVars() unless the PartialAttributes
// option is provided as a ProgramOption.
func (e *Env) PartialVars(vars any) (PartialActivation, error) {
act, err := NewActivation(vars)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -708,7 +707,7 @@ func (e *Env) maybeApplyFeature(feature int, option EnvOption) (*Env, error) {

// computeUnknownVars determines a set of missing variables based on the input activation and the
// environment's configured declaration set.
func (e *Env) computeUnknownVars(vars interpreter.Activation) []*interpreter.AttributePattern {
func (e *Env) computeUnknownVars(vars Activation) []*interpreter.AttributePattern {
var unknownPatterns []*interpreter.AttributePattern
for _, v := range e.variables {
varName := v.Name()
Expand Down
8 changes: 4 additions & 4 deletions cel/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,10 @@ func Functions(funcs ...*functions.Overload) ProgramOption {
// variables with the same name provided to the Eval() call. If Globals is used in a Library with
// a Lib EnvOption, vars may shadow variables provided by previously added libraries.
//
// The vars value may either be an `interpreter.Activation` instance or a `map[string]any`.
// The vars value may either be an `cel.Activation` instance or a `map[string]any`.
func Globals(vars any) ProgramOption {
return func(p *prog) (*prog, error) {
defaultVars, err := interpreter.NewActivation(vars)
defaultVars, err := NewActivation(vars)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -588,7 +588,7 @@ func DeclareContextProto(descriptor protoreflect.MessageDescriptor) EnvOption {
//
// Consider using with `DeclareContextProto` to simplify variable type declarations and publishing when using
// protocol buffers.
func ContextProtoVars(ctx proto.Message) (interpreter.Activation, error) {
func ContextProtoVars(ctx proto.Message) (Activation, error) {
if ctx == nil || !ctx.ProtoReflect().IsValid() {
return interpreter.EmptyActivation(), nil
}
Expand All @@ -612,7 +612,7 @@ func ContextProtoVars(ctx proto.Message) (interpreter.Activation, error) {
}
vars[field.TextName()] = fieldVal
}
return interpreter.NewActivation(vars)
return NewActivation(vars)
}

// EnableMacroCallTracking ensures that call expressions which are replaced by macros
Expand Down
56 changes: 40 additions & 16 deletions cel/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
type Program interface {
// Eval returns the result of an evaluation of the Ast and environment against the input vars.
//
// The vars value may either be an `interpreter.Activation` or a `map[string]any`.
// The vars value may either be an `Activation` or a `map[string]any`.
//
// If the `OptTrackState`, `OptTrackCost` or `OptExhaustiveEval` flags are used, the `details` response will
// be non-nil. Given this caveat on `details`, the return state from evaluation will be:
Expand All @@ -47,14 +47,39 @@ type Program interface {
// to support cancellation and timeouts. This method must be used in conjunction with the
// InterruptCheckFrequency() option for cancellation interrupts to be impact evaluation.
//
// The vars value may either be an `interpreter.Activation` or `map[string]any`.
// The vars value may either be an `Activation` or `map[string]any`.
//
// The output contract for `ContextEval` is otherwise identical to the `Eval` method.
ContextEval(context.Context, any) (ref.Val, *EvalDetails, error)
}

// Activation used to resolve identifiers by name and references by id.
//
// An Activation is the primary mechanism by which a caller supplies input into a CEL program.
type Activation = interpreter.Activation

// NewActivation returns an activation based on a map-based binding where the map keys are
// expected to be qualified names used with ResolveName calls.
//
// The input `bindings` may either be of type `Activation` or `map[string]any`.
//
// Lazy bindings may be supplied within the map-based input in either of the following forms:
// - func() any
// - func() ref.Val
//
// The output of the lazy binding will overwrite the variable reference in the internal map.
//
// Values which are not represented as ref.Val types on input may be adapted to a ref.Val using
// the types.Adapter configured in the environment.
func NewActivation(bindings any) (Activation, error) {
return interpreter.NewActivation(bindings)
}

// PartialActivation extends the Activation interface with a set of UnknownAttributePatterns.
type PartialActivation = interpreter.PartialActivation

// NoVars returns an empty Activation.
func NoVars() interpreter.Activation {
func NoVars() Activation {
return interpreter.EmptyActivation()
}

Expand All @@ -64,10 +89,9 @@ func NoVars() interpreter.Activation {
// This method relies on manually configured sets of missing attribute patterns. For a method which
// infers the missing variables from the input and the configured environment, use Env.PartialVars().
//
// The `vars` value may either be an interpreter.Activation or any valid input to the
// interpreter.NewActivation call.
// The `vars` value may either be an Activation or any valid input to the NewActivation call.
func PartialVars(vars any,
unknowns ...*interpreter.AttributePattern) (interpreter.PartialActivation, error) {
unknowns ...*interpreter.AttributePattern) (PartialActivation, error) {
return interpreter.NewPartialActivation(vars, unknowns...)
}

Expand Down Expand Up @@ -120,7 +144,7 @@ func (ed *EvalDetails) ActualCost() *uint64 {
type prog struct {
*Env
evalOpts EvalOption
defaultVars interpreter.Activation
defaultVars Activation
dispatcher interpreter.Dispatcher
interpreter interpreter.Interpreter
interruptCheckFrequency uint
Expand Down Expand Up @@ -285,9 +309,9 @@ func (p *prog) Eval(input any) (v ref.Val, det *EvalDetails, err error) {
}
}()
// Build a hierarchical activation if there are default vars set.
var vars interpreter.Activation
var vars Activation
switch v := input.(type) {
case interpreter.Activation:
case Activation:
vars = v
case map[string]any:
vars = activationPool.Setup(v)
Expand Down Expand Up @@ -315,9 +339,9 @@ func (p *prog) ContextEval(ctx context.Context, input any) (ref.Val, *EvalDetail
}
// Configure the input, making sure to wrap Activation inputs in the special ctxActivation which
// exposes the #interrupted variable and manages rate-limited checks of the ctx.Done() state.
var vars interpreter.Activation
var vars Activation
switch v := input.(type) {
case interpreter.Activation:
case Activation:
vars = ctxActivationPool.Setup(v, ctx.Done(), p.interruptCheckFrequency)
defer ctxActivationPool.Put(vars)
case map[string]any:
Expand Down Expand Up @@ -414,7 +438,7 @@ func (gen *progGen) ContextEval(ctx context.Context, input any) (ref.Val, *EvalD
}

type ctxEvalActivation struct {
parent interpreter.Activation
parent Activation
interrupt <-chan struct{}
interruptCheckCount uint
interruptCheckFrequency uint
Expand All @@ -438,7 +462,7 @@ func (a *ctxEvalActivation) ResolveName(name string) (any, bool) {
return a.parent.ResolveName(name)
}

func (a *ctxEvalActivation) Parent() interpreter.Activation {
func (a *ctxEvalActivation) Parent() Activation {
return a.parent
}

Expand All @@ -457,7 +481,7 @@ type ctxEvalActivationPool struct {
}

// Setup initializes a pooled Activation with the ability check for context.Context cancellation
func (p *ctxEvalActivationPool) Setup(vars interpreter.Activation, done <-chan struct{}, interruptCheckRate uint) *ctxEvalActivation {
func (p *ctxEvalActivationPool) Setup(vars Activation, done <-chan struct{}, interruptCheckRate uint) *ctxEvalActivation {
a := p.Pool.Get().(*ctxEvalActivation)
a.parent = vars
a.interrupt = done
Expand Down Expand Up @@ -506,8 +530,8 @@ func (a *evalActivation) ResolveName(name string) (any, bool) {
}
}

// Parent implements the interpreter.Activation interface
func (a *evalActivation) Parent() interpreter.Activation {
// Parent implements the Activation interface
func (a *evalActivation) Parent() Activation {
return nil
}

Expand Down
8 changes: 4 additions & 4 deletions ext/bindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func (b *dynamicBlock) ID() int64 {
}

// Eval implements the Interpretable interface method.
func (b *dynamicBlock) Eval(activation interpreter.Activation) ref.Val {
func (b *dynamicBlock) Eval(activation cel.Activation) ref.Val {
sa := b.slotActivationPool.Get().(*dynamicSlotActivation)
sa.Activation = activation
defer b.clearSlots(sa)
Expand All @@ -242,7 +242,7 @@ type slotVal struct {
}

type dynamicSlotActivation struct {
interpreter.Activation
cel.Activation
slotExprs []interpreter.Interpretable
slotCount int
slotVals []*slotVal
Expand Down Expand Up @@ -295,13 +295,13 @@ func (b *constantBlock) ID() int64 {

// Eval implements the interpreter.Interpretable interface method, and will proxy @index prefixed variable
// lookups into a set of constant slots determined from the plan step.
func (b *constantBlock) Eval(activation interpreter.Activation) ref.Val {
func (b *constantBlock) Eval(activation cel.Activation) ref.Val {
vars := constantSlotActivation{Activation: activation, slots: b.slots, slotCount: b.slotCount}
return b.expr.Eval(vars)
}

type constantSlotActivation struct {
interpreter.Activation
cel.Activation
slots traits.Lister
slotCount int
}
Expand Down
3 changes: 1 addition & 2 deletions repl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ go_library(
"//common/types:go_default_library",
"//common/types/ref:go_default_library",
"//ext:go_default_library",
"//interpreter:go_default_library",
"//repl/parser:go_default_library",
"@com_github_antlr4_go_antlr_v4//:go_default_library",
"@dev_cel_expr//conformance/proto2:go_default_library",
Expand All @@ -46,7 +45,7 @@ go_library(
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
"@org_golang_google_protobuf//reflect/protodesc:go_default_library",
"@org_golang_google_protobuf//types/descriptorpb:go_default_library",
],
],
)

go_test(
Expand Down
5 changes: 2 additions & 3 deletions repl/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/ext"
"github.com/google/cel-go/interpreter"

"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/proto"
Expand Down Expand Up @@ -666,7 +665,7 @@ func (e *Evaluator) Status() string {
// applyContext evaluates the let expressions in the context to build an activation for the given expression.
// returns the environment for compiling and planning the top level CEL expression and an activation with the
// values of the let expressions.
func (e *Evaluator) applyContext() (*cel.Env, interpreter.Activation, error) {
func (e *Evaluator) applyContext() (*cel.Env, cel.Activation, error) {
var vars = make(map[string]any)

for _, el := range e.ctx.letVars {
Expand All @@ -683,7 +682,7 @@ func (e *Evaluator) applyContext() (*cel.Env, interpreter.Activation, error) {
}
}

act, err := interpreter.NewActivation(vars)
act, err := cel.NewActivation(vars)
if err != nil {
return nil, nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions test/bench/bench.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Case struct {
// Options indicate additional pieces of configuration such as CEL libraries, variables, and functions.
Options []cel.EnvOption

// In is expected to be a map[string]any or interpreter.Activation instance representing the input to the expression.
// In is expected to be a map[string]any or cel.Activation instance representing the input to the expression.
In any

// Out is the expected CEL valued output.
Expand All @@ -48,7 +48,7 @@ type DynamicEnvCase struct {
// Options indicate additional pieces of configuration such as CEL libraries, variables, and functions.
Options func(b *testing.B) *cel.Env

// In is expected to be a map[string]any or interpreter.Activation instance representing the input to the expression.
// In is expected to be a map[string]any or cel.Activation instance representing the input to the expression.
In any

// Out is the expected CEL valued output.
Expand Down