mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
rebase: update kubernetes to 1.28.0 in main
updating kubernetes to 1.28.0 in the main repo. Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
committed by
mergify[bot]
parent
b2fdc269c3
commit
ff3e84ad67
5
vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
5
vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
@ -23,6 +23,7 @@ go_library(
|
||||
"//checker/decls:go_default_library",
|
||||
"//common:go_default_library",
|
||||
"//common/containers:go_default_library",
|
||||
"//common/operators:go_default_library",
|
||||
"//common/overloads:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/pb:go_default_library",
|
||||
@ -31,7 +32,7 @@ go_library(
|
||||
"//interpreter:go_default_library",
|
||||
"//interpreter/functions:go_default_library",
|
||||
"//parser:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protodesc:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
|
||||
@ -69,7 +70,7 @@ go_test(
|
||||
"//test/proto2pb:go_default_library",
|
||||
"//test/proto3pb:go_default_library",
|
||||
"@io_bazel_rules_go//proto/wkt:descriptor_go_proto",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
|
||||
],
|
||||
|
79
vendor/github.com/google/cel-go/cel/decls.go
generated
vendored
79
vendor/github.com/google/cel-go/cel/decls.go
generated
vendored
@ -139,7 +139,7 @@ var (
|
||||
kind: TypeKind,
|
||||
runtimeType: types.TypeType,
|
||||
}
|
||||
//UintType represents a uint type.
|
||||
// UintType represents a uint type.
|
||||
UintType = &Type{
|
||||
kind: UintKind,
|
||||
runtimeType: types.UintType,
|
||||
@ -222,7 +222,8 @@ func (t *Type) equals(other *Type) bool {
|
||||
// - The from types are the same instance
|
||||
// - The target type is dynamic
|
||||
// - The fromType has the same kind and type name as the target type, and all parameters of the target type
|
||||
// are IsAssignableType() from the parameters of the fromType.
|
||||
//
|
||||
// are IsAssignableType() from the parameters of the fromType.
|
||||
func (t *Type) defaultIsAssignableType(fromType *Type) bool {
|
||||
if t == fromType || t.isDyn() {
|
||||
return true
|
||||
@ -312,6 +313,11 @@ func NullableType(wrapped *Type) *Type {
|
||||
}
|
||||
}
|
||||
|
||||
// OptionalType creates an abstract parameterized type instance corresponding to CEL's notion of optional.
|
||||
func OptionalType(param *Type) *Type {
|
||||
return OpaqueType("optional", param)
|
||||
}
|
||||
|
||||
// OpaqueType creates an abstract parameterized type with a given name.
|
||||
func OpaqueType(name string, params ...*Type) *Type {
|
||||
return &Type{
|
||||
@ -365,7 +371,9 @@ func Variable(name string, t *Type) EnvOption {
|
||||
//
|
||||
// - Overloads are searched in the order they are declared
|
||||
// - Dynamic dispatch for lists and maps is limited by inspection of the list and map contents
|
||||
// at runtime. Empty lists and maps will result in a 'default dispatch'
|
||||
//
|
||||
// at runtime. Empty lists and maps will result in a 'default dispatch'
|
||||
//
|
||||
// - In the event that a default dispatch occurs, the first overload provided is the one invoked
|
||||
//
|
||||
// If you intend to use overloads which differentiate based on the key or element type of a list or
|
||||
@ -405,7 +413,7 @@ func Function(name string, opts ...FunctionOpt) EnvOption {
|
||||
// FunctionOpt defines a functional option for configuring a function declaration.
|
||||
type FunctionOpt func(*functionDecl) (*functionDecl, error)
|
||||
|
||||
// SingletonUnaryBinding creates a singleton function defintion to be used for all function overloads.
|
||||
// SingletonUnaryBinding creates a singleton function definition to be used for all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
@ -431,7 +439,17 @@ func SingletonUnaryBinding(fn functions.UnaryOp, traits ...int) FunctionOpt {
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
//
|
||||
// Deprecated: use SingletonBinaryBinding
|
||||
func SingletonBinaryImpl(fn functions.BinaryOp, traits ...int) FunctionOpt {
|
||||
return SingletonBinaryBinding(fn, traits...)
|
||||
}
|
||||
|
||||
// SingletonBinaryBinding creates a singleton function definition to be used with all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
func SingletonBinaryBinding(fn functions.BinaryOp, traits ...int) FunctionOpt {
|
||||
trait := 0
|
||||
for _, t := range traits {
|
||||
trait = trait | t
|
||||
@ -453,7 +471,17 @@ func SingletonBinaryImpl(fn functions.BinaryOp, traits ...int) FunctionOpt {
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
//
|
||||
// Deprecated: use SingletonFunctionBinding
|
||||
func SingletonFunctionImpl(fn functions.FunctionOp, traits ...int) FunctionOpt {
|
||||
return SingletonFunctionBinding(fn, traits...)
|
||||
}
|
||||
|
||||
// SingletonFunctionBinding creates a singleton function definition to be used with all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
func SingletonFunctionBinding(fn functions.FunctionOp, traits ...int) FunctionOpt {
|
||||
trait := 0
|
||||
for _, t := range traits {
|
||||
trait = trait | t
|
||||
@ -720,9 +748,8 @@ func (f *functionDecl) addOverload(overload *overloadDecl) error {
|
||||
// Allow redefinition of an overload implementation so long as the signatures match.
|
||||
f.overloads[index] = overload
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("overload redefinition in function. %s: %s has multiple definitions", f.name, o.id)
|
||||
}
|
||||
return fmt.Errorf("overload redefinition in function. %s: %s has multiple definitions", f.name, o.id)
|
||||
}
|
||||
}
|
||||
f.overloads = append(f.overloads, overload)
|
||||
@ -1177,3 +1204,43 @@ func collectParamNames(paramNames map[string]struct{}, arg *Type) {
|
||||
collectParamNames(paramNames, param)
|
||||
}
|
||||
}
|
||||
|
||||
func typeValueToKind(tv *types.TypeValue) (Kind, error) {
|
||||
switch tv {
|
||||
case types.BoolType:
|
||||
return BoolKind, nil
|
||||
case types.DoubleType:
|
||||
return DoubleKind, nil
|
||||
case types.IntType:
|
||||
return IntKind, nil
|
||||
case types.UintType:
|
||||
return UintKind, nil
|
||||
case types.ListType:
|
||||
return ListKind, nil
|
||||
case types.MapType:
|
||||
return MapKind, nil
|
||||
case types.StringType:
|
||||
return StringKind, nil
|
||||
case types.BytesType:
|
||||
return BytesKind, nil
|
||||
case types.DurationType:
|
||||
return DurationKind, nil
|
||||
case types.TimestampType:
|
||||
return TimestampKind, nil
|
||||
case types.NullType:
|
||||
return NullTypeKind, nil
|
||||
case types.TypeType:
|
||||
return TypeKind, nil
|
||||
default:
|
||||
switch tv.TypeName() {
|
||||
case "dyn":
|
||||
return DynKind, nil
|
||||
case "google.protobuf.Any":
|
||||
return AnyKind, nil
|
||||
case "optional":
|
||||
return OpaqueKind, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("no known conversion for type of %s", tv.TypeName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
126
vendor/github.com/google/cel-go/cel/env.go
generated
vendored
126
vendor/github.com/google/cel-go/cel/env.go
generated
vendored
@ -102,15 +102,18 @@ type Env struct {
|
||||
provider ref.TypeProvider
|
||||
features map[int]bool
|
||||
appliedFeatures map[int]bool
|
||||
libraries map[string]bool
|
||||
|
||||
// Internal parser representation
|
||||
prsr *parser.Parser
|
||||
prsr *parser.Parser
|
||||
prsrOpts []parser.Option
|
||||
|
||||
// Internal checker representation
|
||||
chk *checker.Env
|
||||
chkErr error
|
||||
chkOnce sync.Once
|
||||
chkOpts []checker.Option
|
||||
chkMutex sync.Mutex
|
||||
chk *checker.Env
|
||||
chkErr error
|
||||
chkOnce sync.Once
|
||||
chkOpts []checker.Option
|
||||
|
||||
// Program options tied to the environment
|
||||
progOpts []ProgramOption
|
||||
@ -159,6 +162,7 @@ func NewCustomEnv(opts ...EnvOption) (*Env, error) {
|
||||
provider: registry,
|
||||
features: map[int]bool{},
|
||||
appliedFeatures: map[int]bool{},
|
||||
libraries: map[string]bool{},
|
||||
progOpts: []ProgramOption{},
|
||||
}).configure(opts)
|
||||
}
|
||||
@ -175,14 +179,14 @@ func (e *Env) Check(ast *Ast) (*Ast, *Issues) {
|
||||
pe, _ := AstToParsedExpr(ast)
|
||||
|
||||
// Construct the internal checker env, erroring if there is an issue adding the declarations.
|
||||
err := e.initChecker()
|
||||
chk, err := e.initChecker()
|
||||
if err != nil {
|
||||
errs := common.NewErrors(ast.Source())
|
||||
errs.ReportError(common.NoLocation, e.chkErr.Error())
|
||||
errs.ReportError(common.NoLocation, err.Error())
|
||||
return nil, NewIssues(errs)
|
||||
}
|
||||
|
||||
res, errs := checker.Check(pe, ast.Source(), e.chk)
|
||||
res, errs := checker.Check(pe, ast.Source(), chk)
|
||||
if len(errs.GetErrors()) > 0 {
|
||||
return nil, NewIssues(errs)
|
||||
}
|
||||
@ -236,10 +240,14 @@ func (e *Env) CompileSource(src Source) (*Ast, *Issues) {
|
||||
// TypeProvider are immutable, or that their underlying implementations are based on the
|
||||
// ref.TypeRegistry which provides a Copy method which will be invoked by this method.
|
||||
func (e *Env) Extend(opts ...EnvOption) (*Env, error) {
|
||||
if e.chkErr != nil {
|
||||
return nil, e.chkErr
|
||||
chk, chkErr := e.getCheckerOrError()
|
||||
if chkErr != nil {
|
||||
return nil, chkErr
|
||||
}
|
||||
|
||||
prsrOptsCopy := make([]parser.Option, len(e.prsrOpts))
|
||||
copy(prsrOptsCopy, e.prsrOpts)
|
||||
|
||||
// The type-checker is configured with Declarations. The declarations may either be provided
|
||||
// as options which have not yet been validated, or may come from a previous checker instance
|
||||
// whose types have already been validated.
|
||||
@ -248,10 +256,10 @@ func (e *Env) Extend(opts ...EnvOption) (*Env, error) {
|
||||
|
||||
// Copy the declarations if needed.
|
||||
decsCopy := []*exprpb.Decl{}
|
||||
if e.chk != nil {
|
||||
if chk != nil {
|
||||
// If the type-checker has already been instantiated, then the e.declarations have been
|
||||
// valdiated within the chk instance.
|
||||
chkOptsCopy = append(chkOptsCopy, checker.ValidatedDeclarations(e.chk))
|
||||
// validated within the chk instance.
|
||||
chkOptsCopy = append(chkOptsCopy, checker.ValidatedDeclarations(chk))
|
||||
} else {
|
||||
// If the type-checker has not been instantiated, ensure the unvalidated declarations are
|
||||
// provided to the extended Env instance.
|
||||
@ -304,8 +312,11 @@ func (e *Env) Extend(opts ...EnvOption) (*Env, error) {
|
||||
for k, v := range e.functions {
|
||||
funcsCopy[k] = v
|
||||
}
|
||||
libsCopy := make(map[string]bool, len(e.libraries))
|
||||
for k, v := range e.libraries {
|
||||
libsCopy[k] = v
|
||||
}
|
||||
|
||||
// TODO: functions copy needs to happen here.
|
||||
ext := &Env{
|
||||
Container: e.Container,
|
||||
declarations: decsCopy,
|
||||
@ -315,8 +326,10 @@ func (e *Env) Extend(opts ...EnvOption) (*Env, error) {
|
||||
adapter: adapter,
|
||||
features: featuresCopy,
|
||||
appliedFeatures: appliedFeaturesCopy,
|
||||
libraries: libsCopy,
|
||||
provider: provider,
|
||||
chkOpts: chkOptsCopy,
|
||||
prsrOpts: prsrOptsCopy,
|
||||
}
|
||||
return ext.configure(opts)
|
||||
}
|
||||
@ -328,6 +341,12 @@ func (e *Env) HasFeature(flag int) bool {
|
||||
return has && enabled
|
||||
}
|
||||
|
||||
// HasLibrary returns whether a specific SingletonLibrary has been configured in the environment.
|
||||
func (e *Env) HasLibrary(libName string) bool {
|
||||
configured, exists := e.libraries[libName]
|
||||
return exists && configured
|
||||
}
|
||||
|
||||
// Parse parses the input expression value `txt` to a Ast and/or a set of Issues.
|
||||
//
|
||||
// This form of Parse creates a Source value for the input `txt` and forwards to the
|
||||
@ -422,8 +441,8 @@ func (e *Env) UnknownVars() interpreter.PartialActivation {
|
||||
// TODO: Consider adding an option to generate a Program.Residual to avoid round-tripping to an
|
||||
// Ast format and then Program again.
|
||||
func (e *Env) ResidualAst(a *Ast, details *EvalDetails) (*Ast, error) {
|
||||
pruned := interpreter.PruneAst(a.Expr(), details.State())
|
||||
expr, err := AstToString(ParsedExprToAst(&exprpb.ParsedExpr{Expr: pruned}))
|
||||
pruned := interpreter.PruneAst(a.Expr(), a.SourceInfo().GetMacroCalls(), details.State())
|
||||
expr, err := AstToString(ParsedExprToAst(pruned))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -443,12 +462,12 @@ func (e *Env) ResidualAst(a *Ast, details *EvalDetails) (*Ast, error) {
|
||||
|
||||
// EstimateCost estimates the cost of a type checked CEL expression using the length estimates of input data and
|
||||
// extension functions provided by estimator.
|
||||
func (e *Env) EstimateCost(ast *Ast, estimator checker.CostEstimator) (checker.CostEstimate, error) {
|
||||
func (e *Env) EstimateCost(ast *Ast, estimator checker.CostEstimator, opts ...checker.CostOption) (checker.CostEstimate, error) {
|
||||
checked, err := AstToCheckedExpr(ast)
|
||||
if err != nil {
|
||||
return checker.CostEstimate{}, fmt.Errorf("EsimateCost could not inspect Ast: %v", err)
|
||||
}
|
||||
return checker.Cost(checked, estimator), nil
|
||||
return checker.Cost(checked, estimator, opts...)
|
||||
}
|
||||
|
||||
// configure applies a series of EnvOptions to the current environment.
|
||||
@ -464,17 +483,9 @@ func (e *Env) configure(opts []EnvOption) (*Env, error) {
|
||||
}
|
||||
|
||||
// If the default UTC timezone fix has been enabled, make sure the library is configured
|
||||
if e.HasFeature(featureDefaultUTCTimeZone) {
|
||||
if _, found := e.appliedFeatures[featureDefaultUTCTimeZone]; !found {
|
||||
e, err = Lib(timeUTCLibrary{})(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// record that the feature has been applied since it will generate declarations
|
||||
// and functions which will be propagated on Extend() calls and which should only
|
||||
// be registered once.
|
||||
e.appliedFeatures[featureDefaultUTCTimeZone] = true
|
||||
}
|
||||
e, err = e.maybeApplyFeature(featureDefaultUTCTimeZone, Lib(timeUTCLibrary{}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize all of the functions configured within the environment.
|
||||
@ -486,7 +497,10 @@ func (e *Env) configure(opts []EnvOption) (*Env, error) {
|
||||
}
|
||||
|
||||
// Configure the parser.
|
||||
prsrOpts := []parser.Option{parser.Macros(e.macros...)}
|
||||
prsrOpts := []parser.Option{}
|
||||
prsrOpts = append(prsrOpts, e.prsrOpts...)
|
||||
prsrOpts = append(prsrOpts, parser.Macros(e.macros...))
|
||||
|
||||
if e.HasFeature(featureEnableMacroCallTracking) {
|
||||
prsrOpts = append(prsrOpts, parser.PopulateMacroCalls(true))
|
||||
}
|
||||
@ -497,7 +511,7 @@ func (e *Env) configure(opts []EnvOption) (*Env, error) {
|
||||
|
||||
// Ensure that the checker init happens eagerly rather than lazily.
|
||||
if e.HasFeature(featureEagerlyValidateDeclarations) {
|
||||
err := e.initChecker()
|
||||
_, err := e.initChecker()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -506,7 +520,7 @@ func (e *Env) configure(opts []EnvOption) (*Env, error) {
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (e *Env) initChecker() error {
|
||||
func (e *Env) initChecker() (*checker.Env, error) {
|
||||
e.chkOnce.Do(func() {
|
||||
chkOpts := []checker.Option{}
|
||||
chkOpts = append(chkOpts, e.chkOpts...)
|
||||
@ -518,32 +532,68 @@ func (e *Env) initChecker() error {
|
||||
|
||||
ce, err := checker.NewEnv(e.Container, e.provider, chkOpts...)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
e.setCheckerOrError(nil, err)
|
||||
return
|
||||
}
|
||||
// Add the statically configured declarations.
|
||||
err = ce.Add(e.declarations...)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
e.setCheckerOrError(nil, err)
|
||||
return
|
||||
}
|
||||
// Add the function declarations which are derived from the FunctionDecl instances.
|
||||
for _, fn := range e.functions {
|
||||
fnDecl, err := functionDeclToExprDecl(fn)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
e.setCheckerOrError(nil, err)
|
||||
return
|
||||
}
|
||||
err = ce.Add(fnDecl)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
e.setCheckerOrError(nil, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Add function declarations here separately.
|
||||
e.chk = ce
|
||||
e.setCheckerOrError(ce, nil)
|
||||
})
|
||||
return e.chkErr
|
||||
return e.getCheckerOrError()
|
||||
}
|
||||
|
||||
// setCheckerOrError sets the checker.Env or error state in a concurrency-safe manner
|
||||
func (e *Env) setCheckerOrError(chk *checker.Env, chkErr error) {
|
||||
e.chkMutex.Lock()
|
||||
e.chk = chk
|
||||
e.chkErr = chkErr
|
||||
e.chkMutex.Unlock()
|
||||
}
|
||||
|
||||
// getCheckerOrError gets the checker.Env or error state in a concurrency-safe manner
|
||||
func (e *Env) getCheckerOrError() (*checker.Env, error) {
|
||||
e.chkMutex.Lock()
|
||||
defer e.chkMutex.Unlock()
|
||||
return e.chk, e.chkErr
|
||||
}
|
||||
|
||||
// maybeApplyFeature determines whether the feature-guarded option is enabled, and if so applies
|
||||
// the feature if it has not already been enabled.
|
||||
func (e *Env) maybeApplyFeature(feature int, option EnvOption) (*Env, error) {
|
||||
if !e.HasFeature(feature) {
|
||||
return e, nil
|
||||
}
|
||||
_, applied := e.appliedFeatures[feature]
|
||||
if applied {
|
||||
return e, nil
|
||||
}
|
||||
e, err := option(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// record that the feature has been applied since it will generate declarations
|
||||
// and functions which will be propagated on Extend() calls and which should only
|
||||
// be registered once.
|
||||
e.appliedFeatures[feature] = true
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// Issues defines methods for inspecting the error details of parse and check calls.
|
||||
|
4
vendor/github.com/google/cel-go/cel/io.go
generated
vendored
4
vendor/github.com/google/cel-go/cel/io.go
generated
vendored
@ -19,14 +19,14 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
"github.com/google/cel-go/parser"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
)
|
||||
|
258
vendor/github.com/google/cel-go/cel/library.go
generated
vendored
258
vendor/github.com/google/cel-go/cel/library.go
generated
vendored
@ -20,10 +20,27 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/checker"
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
"github.com/google/cel-go/interpreter"
|
||||
"github.com/google/cel-go/interpreter/functions"
|
||||
"github.com/google/cel-go/parser"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
const (
|
||||
optMapMacro = "optMap"
|
||||
hasValueFunc = "hasValue"
|
||||
optionalNoneFunc = "optional.none"
|
||||
optionalOfFunc = "optional.of"
|
||||
optionalOfNonZeroValueFunc = "optional.ofNonZeroValue"
|
||||
valueFunc = "value"
|
||||
unusedIterVar = "#unused"
|
||||
)
|
||||
|
||||
// Library provides a collection of EnvOption and ProgramOption values used to configure a CEL
|
||||
@ -42,10 +59,27 @@ type Library interface {
|
||||
ProgramOptions() []ProgramOption
|
||||
}
|
||||
|
||||
// SingletonLibrary refines the Library interface to ensure that libraries in this format are only
|
||||
// configured once within the environment.
|
||||
type SingletonLibrary interface {
|
||||
Library
|
||||
|
||||
// LibraryName provides a namespaced name which is used to check whether the library has already
|
||||
// been configured in the environment.
|
||||
LibraryName() string
|
||||
}
|
||||
|
||||
// Lib creates an EnvOption out of a Library, allowing libraries to be provided as functional args,
|
||||
// and to be linked to each other.
|
||||
func Lib(l Library) EnvOption {
|
||||
singleton, isSingleton := l.(SingletonLibrary)
|
||||
return func(e *Env) (*Env, error) {
|
||||
if isSingleton {
|
||||
if e.HasLibrary(singleton.LibraryName()) {
|
||||
return e, nil
|
||||
}
|
||||
e.libraries[singleton.LibraryName()] = true
|
||||
}
|
||||
var err error
|
||||
for _, opt := range l.CompileOptions() {
|
||||
e, err = opt(e)
|
||||
@ -67,6 +101,11 @@ func StdLib() EnvOption {
|
||||
// features documented in the specification.
|
||||
type stdLibrary struct{}
|
||||
|
||||
// LibraryName implements the SingletonLibrary interface method.
|
||||
func (stdLibrary) LibraryName() string {
|
||||
return "cel.lib.std"
|
||||
}
|
||||
|
||||
// EnvOptions returns options for the standard CEL function declarations and macros.
|
||||
func (stdLibrary) CompileOptions() []EnvOption {
|
||||
return []EnvOption{
|
||||
@ -82,6 +121,225 @@ func (stdLibrary) ProgramOptions() []ProgramOption {
|
||||
}
|
||||
}
|
||||
|
||||
type optionalLibrary struct{}
|
||||
|
||||
// LibraryName implements the SingletonLibrary interface method.
|
||||
func (optionalLibrary) LibraryName() string {
|
||||
return "cel.lib.optional"
|
||||
}
|
||||
|
||||
// CompileOptions implements the Library interface method.
|
||||
func (optionalLibrary) CompileOptions() []EnvOption {
|
||||
paramTypeK := TypeParamType("K")
|
||||
paramTypeV := TypeParamType("V")
|
||||
optionalTypeV := OptionalType(paramTypeV)
|
||||
listTypeV := ListType(paramTypeV)
|
||||
mapTypeKV := MapType(paramTypeK, paramTypeV)
|
||||
|
||||
return []EnvOption{
|
||||
// Enable the optional syntax in the parser.
|
||||
enableOptionalSyntax(),
|
||||
|
||||
// Introduce the optional type.
|
||||
Types(types.OptionalType),
|
||||
|
||||
// Configure the optMap macro.
|
||||
Macros(NewReceiverMacro(optMapMacro, 2, optMap)),
|
||||
|
||||
// Global and member functions for working with optional values.
|
||||
Function(optionalOfFunc,
|
||||
Overload("optional_of", []*Type{paramTypeV}, optionalTypeV,
|
||||
UnaryBinding(func(value ref.Val) ref.Val {
|
||||
return types.OptionalOf(value)
|
||||
}))),
|
||||
Function(optionalOfNonZeroValueFunc,
|
||||
Overload("optional_ofNonZeroValue", []*Type{paramTypeV}, optionalTypeV,
|
||||
UnaryBinding(func(value ref.Val) ref.Val {
|
||||
v, isZeroer := value.(traits.Zeroer)
|
||||
if !isZeroer || !v.IsZeroValue() {
|
||||
return types.OptionalOf(value)
|
||||
}
|
||||
return types.OptionalNone
|
||||
}))),
|
||||
Function(optionalNoneFunc,
|
||||
Overload("optional_none", []*Type{}, optionalTypeV,
|
||||
FunctionBinding(func(values ...ref.Val) ref.Val {
|
||||
return types.OptionalNone
|
||||
}))),
|
||||
Function(valueFunc,
|
||||
MemberOverload("optional_value", []*Type{optionalTypeV}, paramTypeV,
|
||||
UnaryBinding(func(value ref.Val) ref.Val {
|
||||
opt := value.(*types.Optional)
|
||||
return opt.GetValue()
|
||||
}))),
|
||||
Function(hasValueFunc,
|
||||
MemberOverload("optional_hasValue", []*Type{optionalTypeV}, BoolType,
|
||||
UnaryBinding(func(value ref.Val) ref.Val {
|
||||
opt := value.(*types.Optional)
|
||||
return types.Bool(opt.HasValue())
|
||||
}))),
|
||||
|
||||
// Implementation of 'or' and 'orValue' are special-cased to support short-circuiting in the
|
||||
// evaluation chain.
|
||||
Function("or",
|
||||
MemberOverload("optional_or_optional", []*Type{optionalTypeV, optionalTypeV}, optionalTypeV)),
|
||||
Function("orValue",
|
||||
MemberOverload("optional_orValue_value", []*Type{optionalTypeV, paramTypeV}, paramTypeV)),
|
||||
|
||||
// OptSelect is handled specially by the type-checker, so the receiver's field type is used to determine the
|
||||
// optput type.
|
||||
Function(operators.OptSelect,
|
||||
Overload("select_optional_field", []*Type{DynType, StringType}, optionalTypeV)),
|
||||
|
||||
// OptIndex is handled mostly like any other indexing operation on a list or map, so the type-checker can use
|
||||
// these signatures to determine type-agreement without any special handling.
|
||||
Function(operators.OptIndex,
|
||||
Overload("list_optindex_optional_int", []*Type{listTypeV, IntType}, optionalTypeV),
|
||||
Overload("optional_list_optindex_optional_int", []*Type{OptionalType(listTypeV), IntType}, optionalTypeV),
|
||||
Overload("map_optindex_optional_value", []*Type{mapTypeKV, paramTypeK}, optionalTypeV),
|
||||
Overload("optional_map_optindex_optional_value", []*Type{OptionalType(mapTypeKV), paramTypeK}, optionalTypeV)),
|
||||
|
||||
// Index overloads to accommodate using an optional value as the operand.
|
||||
Function(operators.Index,
|
||||
Overload("optional_list_index_int", []*Type{OptionalType(listTypeV), IntType}, optionalTypeV),
|
||||
Overload("optional_map_index_optional_value", []*Type{OptionalType(mapTypeKV), paramTypeK}, optionalTypeV)),
|
||||
}
|
||||
}
|
||||
|
||||
func optMap(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
varIdent := args[0]
|
||||
varName := ""
|
||||
switch varIdent.GetExprKind().(type) {
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
varName = varIdent.GetIdentExpr().GetName()
|
||||
default:
|
||||
return nil, &common.Error{
|
||||
Message: "optMap() variable name must be a simple identifier",
|
||||
Location: meh.OffsetLocation(varIdent.GetId()),
|
||||
}
|
||||
}
|
||||
mapExpr := args[1]
|
||||
return meh.GlobalCall(
|
||||
operators.Conditional,
|
||||
meh.ReceiverCall(hasValueFunc, target),
|
||||
meh.GlobalCall(optionalOfFunc,
|
||||
meh.Fold(
|
||||
unusedIterVar,
|
||||
meh.NewList(),
|
||||
varName,
|
||||
meh.ReceiverCall(valueFunc, target),
|
||||
meh.LiteralBool(false),
|
||||
meh.Ident(varName),
|
||||
mapExpr,
|
||||
),
|
||||
),
|
||||
meh.GlobalCall(optionalNoneFunc),
|
||||
), nil
|
||||
}
|
||||
|
||||
// ProgramOptions implements the Library interface method.
|
||||
func (optionalLibrary) ProgramOptions() []ProgramOption {
|
||||
return []ProgramOption{
|
||||
CustomDecorator(decorateOptionalOr),
|
||||
}
|
||||
}
|
||||
|
||||
func enableOptionalSyntax() EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.prsrOpts = append(e.prsrOpts, parser.EnableOptionalSyntax(true))
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
func decorateOptionalOr(i interpreter.Interpretable) (interpreter.Interpretable, error) {
|
||||
call, ok := i.(interpreter.InterpretableCall)
|
||||
if !ok {
|
||||
return i, nil
|
||||
}
|
||||
args := call.Args()
|
||||
if len(args) != 2 {
|
||||
return i, nil
|
||||
}
|
||||
switch call.Function() {
|
||||
case "or":
|
||||
if call.OverloadID() != "" && call.OverloadID() != "optional_or_optional" {
|
||||
return i, nil
|
||||
}
|
||||
return &evalOptionalOr{
|
||||
id: call.ID(),
|
||||
lhs: args[0],
|
||||
rhs: args[1],
|
||||
}, nil
|
||||
case "orValue":
|
||||
if call.OverloadID() != "" && call.OverloadID() != "optional_orValue_value" {
|
||||
return i, nil
|
||||
}
|
||||
return &evalOptionalOrValue{
|
||||
id: call.ID(),
|
||||
lhs: args[0],
|
||||
rhs: args[1],
|
||||
}, nil
|
||||
default:
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
// evalOptionalOr selects between two optional values, either the first if it has a value, or
|
||||
// the second optional expression is evaluated and returned.
|
||||
type evalOptionalOr struct {
|
||||
id int64
|
||||
lhs interpreter.Interpretable
|
||||
rhs interpreter.Interpretable
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
func (opt *evalOptionalOr) ID() int64 {
|
||||
return opt.id
|
||||
}
|
||||
|
||||
// Eval evaluates the left-hand side optional to determine whether it contains a value, else
|
||||
// proceeds with the right-hand side evaluation.
|
||||
func (opt *evalOptionalOr) Eval(ctx interpreter.Activation) ref.Val {
|
||||
// short-circuit lhs.
|
||||
optLHS := opt.lhs.Eval(ctx)
|
||||
optVal, ok := optLHS.(*types.Optional)
|
||||
if !ok {
|
||||
return optLHS
|
||||
}
|
||||
if optVal.HasValue() {
|
||||
return optVal
|
||||
}
|
||||
return opt.rhs.Eval(ctx)
|
||||
}
|
||||
|
||||
// evalOptionalOrValue selects between an optional or a concrete value. If the optional has a value,
|
||||
// its value is returned, otherwise the alternative value expression is evaluated and returned.
|
||||
type evalOptionalOrValue struct {
|
||||
id int64
|
||||
lhs interpreter.Interpretable
|
||||
rhs interpreter.Interpretable
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
func (opt *evalOptionalOrValue) ID() int64 {
|
||||
return opt.id
|
||||
}
|
||||
|
||||
// Eval evaluates the left-hand side optional to determine whether it contains a value, else
|
||||
// proceeds with the right-hand side evaluation.
|
||||
func (opt *evalOptionalOrValue) Eval(ctx interpreter.Activation) ref.Val {
|
||||
// short-circuit lhs.
|
||||
optLHS := opt.lhs.Eval(ctx)
|
||||
optVal, ok := optLHS.(*types.Optional)
|
||||
if !ok {
|
||||
return optLHS
|
||||
}
|
||||
if optVal.HasValue() {
|
||||
return optVal.GetValue()
|
||||
}
|
||||
return opt.rhs.Eval(ctx)
|
||||
}
|
||||
|
||||
type timeUTCLibrary struct{}
|
||||
|
||||
func (timeUTCLibrary) CompileOptions() []EnvOption {
|
||||
|
14
vendor/github.com/google/cel-go/cel/macro.go
generated
vendored
14
vendor/github.com/google/cel-go/cel/macro.go
generated
vendored
@ -17,6 +17,7 @@ package cel
|
||||
import (
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/parser"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
@ -26,8 +27,11 @@ import (
|
||||
// a Macro should be created per arg-count or as a var arg macro.
|
||||
type Macro = parser.Macro
|
||||
|
||||
// MacroExpander converts a call and its associated arguments into a new CEL abstract syntax tree, or an error
|
||||
// if the input arguments are not suitable for the expansion requirements for the macro in question.
|
||||
// MacroExpander converts a call and its associated arguments into a new CEL abstract syntax tree.
|
||||
//
|
||||
// If the MacroExpander determines within the implementation that an expansion is not needed it may return
|
||||
// a nil Expr value to indicate a non-match. However, if an expansion is to be performed, but the arguments
|
||||
// are not well-formed, the result of the expansion will be an error.
|
||||
//
|
||||
// The MacroExpander accepts as arguments a MacroExprHelper as well as the arguments used in the function call
|
||||
// and produces as output an Expr ast node.
|
||||
@ -81,8 +85,10 @@ func ExistsOneMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*ex
|
||||
// input to produce an output list.
|
||||
//
|
||||
// There are two call patterns supported by map:
|
||||
// <iterRange>.map(<iterVar>, <transform>)
|
||||
// <iterRange>.map(<iterVar>, <predicate>, <transform>)
|
||||
//
|
||||
// <iterRange>.map(<iterVar>, <transform>)
|
||||
// <iterRange>.map(<iterVar>, <predicate>, <transform>)
|
||||
//
|
||||
// In the second form only iterVar values which return true when provided to the predicate expression
|
||||
// are transformed.
|
||||
func MapMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
|
64
vendor/github.com/google/cel-go/cel/options.go
generated
vendored
64
vendor/github.com/google/cel-go/cel/options.go
generated
vendored
@ -29,6 +29,7 @@ import (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/interpreter"
|
||||
"github.com/google/cel-go/interpreter/functions"
|
||||
"github.com/google/cel-go/parser"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
descpb "google.golang.org/protobuf/types/descriptorpb"
|
||||
@ -61,6 +62,10 @@ const (
|
||||
// on a CEL timestamp operation. This fixes the scenario where the input time
|
||||
// is not already in UTC.
|
||||
featureDefaultUTCTimeZone
|
||||
|
||||
// Enable the use of optional types in the syntax, type-system, type-checking,
|
||||
// and runtime.
|
||||
featureOptionalTypes
|
||||
)
|
||||
|
||||
// EnvOption is a functional interface for configuring the environment.
|
||||
@ -163,19 +168,19 @@ func Container(name string) EnvOption {
|
||||
// Abbreviations can be useful when working with variables, functions, and especially types from
|
||||
// multiple namespaces:
|
||||
//
|
||||
// // CEL object construction
|
||||
// qual.pkg.version.ObjTypeName{
|
||||
// field: alt.container.ver.FieldTypeName{value: ...}
|
||||
// }
|
||||
// // CEL object construction
|
||||
// qual.pkg.version.ObjTypeName{
|
||||
// field: alt.container.ver.FieldTypeName{value: ...}
|
||||
// }
|
||||
//
|
||||
// Only one the qualified names above may be used as the CEL container, so at least one of these
|
||||
// references must be a long qualified name within an otherwise short CEL program. Using the
|
||||
// following abbreviations, the program becomes much simpler:
|
||||
//
|
||||
// // CEL Go option
|
||||
// Abbrevs("qual.pkg.version.ObjTypeName", "alt.container.ver.FieldTypeName")
|
||||
// // Simplified Object construction
|
||||
// ObjTypeName{field: FieldTypeName{value: ...}}
|
||||
// // CEL Go option
|
||||
// Abbrevs("qual.pkg.version.ObjTypeName", "alt.container.ver.FieldTypeName")
|
||||
// // Simplified Object construction
|
||||
// ObjTypeName{field: FieldTypeName{value: ...}}
|
||||
//
|
||||
// There are a few rules for the qualified names and the simple abbreviations generated from them:
|
||||
// - Qualified names must be dot-delimited, e.g. `package.subpkg.name`.
|
||||
@ -188,9 +193,12 @@ func Container(name string) EnvOption {
|
||||
// - Expanded abbreviations do not participate in namespace resolution.
|
||||
// - Abbreviation expansion is done instead of the container search for a matching identifier.
|
||||
// - Containers follow C++ namespace resolution rules with searches from the most qualified name
|
||||
// to the least qualified name.
|
||||
//
|
||||
// to the least qualified name.
|
||||
//
|
||||
// - Container references within the CEL program may be relative, and are resolved to fully
|
||||
// qualified names at either type-check time or program plan time, whichever comes first.
|
||||
//
|
||||
// qualified names at either type-check time or program plan time, whichever comes first.
|
||||
//
|
||||
// If there is ever a case where an identifier could be in both the container and as an
|
||||
// abbreviation, the abbreviation wins as this will ensure that the meaning of a program is
|
||||
@ -216,7 +224,7 @@ func Abbrevs(qualifiedNames ...string) EnvOption {
|
||||
// environment by default.
|
||||
//
|
||||
// Note: This option must be specified after the CustomTypeProvider option when used together.
|
||||
func Types(addTypes ...interface{}) EnvOption {
|
||||
func Types(addTypes ...any) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
reg, isReg := e.provider.(ref.TypeRegistry)
|
||||
if !isReg {
|
||||
@ -253,7 +261,7 @@ func Types(addTypes ...interface{}) EnvOption {
|
||||
//
|
||||
// TypeDescs are hermetic to a single Env object, but may be copied to other Env values via
|
||||
// extension or by re-using the same EnvOption with another NewEnv() call.
|
||||
func TypeDescs(descs ...interface{}) EnvOption {
|
||||
func TypeDescs(descs ...any) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
reg, isReg := e.provider.(ref.TypeRegistry)
|
||||
if !isReg {
|
||||
@ -350,8 +358,8 @@ 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]interface{}`.
|
||||
func Globals(vars interface{}) ProgramOption {
|
||||
// The vars value may either be an `interpreter.Activation` instance or a `map[string]any`.
|
||||
func Globals(vars any) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
defaultVars, err := interpreter.NewActivation(vars)
|
||||
if err != nil {
|
||||
@ -404,6 +412,9 @@ const (
|
||||
// OptTrackCost enables the runtime cost calculation while validation and return cost within evalDetails
|
||||
// cost calculation is available via func ActualCost()
|
||||
OptTrackCost EvalOption = 1 << iota
|
||||
|
||||
// OptCheckStringFormat enables compile-time checking of string.format calls for syntax/cardinality.
|
||||
OptCheckStringFormat EvalOption = 1 << iota
|
||||
)
|
||||
|
||||
// EvalOptions sets one or more evaluation options which may affect the evaluation or Result.
|
||||
@ -534,6 +545,13 @@ func DefaultUTCTimeZone(enabled bool) EnvOption {
|
||||
return features(featureDefaultUTCTimeZone, enabled)
|
||||
}
|
||||
|
||||
// OptionalTypes enable support for optional syntax and types in CEL. The optional value type makes
|
||||
// it possible to express whether variables have been provided, whether a result has been computed,
|
||||
// and in the future whether an object field path, map key value, or list index has a value.
|
||||
func OptionalTypes() EnvOption {
|
||||
return Lib(optionalLibrary{})
|
||||
}
|
||||
|
||||
// features sets the given feature flags. See list of Feature constants above.
|
||||
func features(flag int, enabled bool) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
@ -541,3 +559,21 @@ func features(flag int, enabled bool) EnvOption {
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ParserRecursionLimit adjusts the AST depth the parser will tolerate.
|
||||
// Defaults defined in the parser package.
|
||||
func ParserRecursionLimit(limit int) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.prsrOpts = append(e.prsrOpts, parser.MaxRecursionDepth(limit))
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ParserExpressionSizeLimit adjusts the number of code points the expression parser is allowed to parse.
|
||||
// Defaults defined in the parser package.
|
||||
func ParserExpressionSizeLimit(limit int) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.prsrOpts = append(e.prsrOpts, parser.ExpressionSizeCodePointLimit(limit))
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
114
vendor/github.com/google/cel-go/cel/program.go
generated
vendored
114
vendor/github.com/google/cel-go/cel/program.go
generated
vendored
@ -17,21 +17,20 @@ package cel
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/interpreter"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Program is an evaluable view of an Ast.
|
||||
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]interface{}`.
|
||||
// The vars value may either be an `interpreter.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:
|
||||
@ -43,16 +42,16 @@ type Program interface {
|
||||
// An unsuccessful evaluation is typically the result of a series of incompatible `EnvOption`
|
||||
// or `ProgramOption` values used in the creation of the evaluation environment or executable
|
||||
// program.
|
||||
Eval(interface{}) (ref.Val, *EvalDetails, error)
|
||||
Eval(any) (ref.Val, *EvalDetails, error)
|
||||
|
||||
// ContextEval evaluates the program with a set of input variables and a context object in order
|
||||
// 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]interface{}`.
|
||||
// The vars value may either be an `interpreter.Activation` or `map[string]any`.
|
||||
//
|
||||
// The output contract for `ContextEval` is otherwise identical to the `Eval` method.
|
||||
ContextEval(context.Context, interface{}) (ref.Val, *EvalDetails, error)
|
||||
ContextEval(context.Context, any) (ref.Val, *EvalDetails, error)
|
||||
}
|
||||
|
||||
// NoVars returns an empty Activation.
|
||||
@ -65,7 +64,7 @@ func NoVars() interpreter.Activation {
|
||||
//
|
||||
// The `vars` value may either be an interpreter.Activation or any valid input to the
|
||||
// interpreter.NewActivation call.
|
||||
func PartialVars(vars interface{},
|
||||
func PartialVars(vars any,
|
||||
unknowns ...*interpreter.AttributePattern) (interpreter.PartialActivation, error) {
|
||||
return interpreter.NewPartialActivation(vars, unknowns...)
|
||||
}
|
||||
@ -207,6 +206,37 @@ func newProgram(e *Env, ast *Ast, opts []ProgramOption) (Program, error) {
|
||||
if len(p.regexOptimizations) > 0 {
|
||||
decorators = append(decorators, interpreter.CompileRegexConstants(p.regexOptimizations...))
|
||||
}
|
||||
// Enable compile-time checking of syntax/cardinality for string.format calls.
|
||||
if p.evalOpts&OptCheckStringFormat == OptCheckStringFormat {
|
||||
var isValidType func(id int64, validTypes ...*types.TypeValue) (bool, error)
|
||||
if ast.IsChecked() {
|
||||
isValidType = func(id int64, validTypes ...*types.TypeValue) (bool, error) {
|
||||
t, err := ExprTypeToType(ast.typeMap[id])
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if t.kind == DynKind {
|
||||
return true, nil
|
||||
}
|
||||
for _, vt := range validTypes {
|
||||
k, err := typeValueToKind(vt)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if k == t.kind {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
// if the AST isn't type-checked, short-circuit validation
|
||||
isValidType = func(id int64, validTypes ...*types.TypeValue) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
decorators = append(decorators, interpreter.InterpolateFormattedString(isValidType))
|
||||
}
|
||||
|
||||
// Enable exhaustive eval, state tracking and cost tracking last since they require a factory.
|
||||
if p.evalOpts&(OptExhaustiveEval|OptTrackState|OptTrackCost) != 0 {
|
||||
@ -268,7 +298,7 @@ func (p *prog) initInterpretable(ast *Ast, decs []interpreter.InterpretableDecor
|
||||
}
|
||||
|
||||
// Eval implements the Program interface method.
|
||||
func (p *prog) Eval(input interface{}) (v ref.Val, det *EvalDetails, err error) {
|
||||
func (p *prog) Eval(input any) (v ref.Val, det *EvalDetails, err error) {
|
||||
// Configure error recovery for unexpected panics during evaluation. Note, the use of named
|
||||
// return values makes it possible to modify the error response during the recovery
|
||||
// function.
|
||||
@ -287,11 +317,11 @@ func (p *prog) Eval(input interface{}) (v ref.Val, det *EvalDetails, err error)
|
||||
switch v := input.(type) {
|
||||
case interpreter.Activation:
|
||||
vars = v
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
vars = activationPool.Setup(v)
|
||||
defer activationPool.Put(vars)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid input, wanted Activation or map[string]interface{}, got: (%T)%v", input, input)
|
||||
return nil, nil, fmt.Errorf("invalid input, wanted Activation or map[string]any, got: (%T)%v", input, input)
|
||||
}
|
||||
if p.defaultVars != nil {
|
||||
vars = interpreter.NewHierarchicalActivation(p.defaultVars, vars)
|
||||
@ -307,7 +337,7 @@ func (p *prog) Eval(input interface{}) (v ref.Val, det *EvalDetails, err error)
|
||||
}
|
||||
|
||||
// ContextEval implements the Program interface.
|
||||
func (p *prog) ContextEval(ctx context.Context, input interface{}) (ref.Val, *EvalDetails, error) {
|
||||
func (p *prog) ContextEval(ctx context.Context, input any) (ref.Val, *EvalDetails, error) {
|
||||
if ctx == nil {
|
||||
return nil, nil, fmt.Errorf("context can not be nil")
|
||||
}
|
||||
@ -318,22 +348,17 @@ func (p *prog) ContextEval(ctx context.Context, input interface{}) (ref.Val, *Ev
|
||||
case interpreter.Activation:
|
||||
vars = ctxActivationPool.Setup(v, ctx.Done(), p.interruptCheckFrequency)
|
||||
defer ctxActivationPool.Put(vars)
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
rawVars := activationPool.Setup(v)
|
||||
defer activationPool.Put(rawVars)
|
||||
vars = ctxActivationPool.Setup(rawVars, ctx.Done(), p.interruptCheckFrequency)
|
||||
defer ctxActivationPool.Put(vars)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid input, wanted Activation or map[string]interface{}, got: (%T)%v", input, input)
|
||||
return nil, nil, fmt.Errorf("invalid input, wanted Activation or map[string]any, got: (%T)%v", input, input)
|
||||
}
|
||||
return p.Eval(vars)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (p *prog) Cost() (min, max int64) {
|
||||
return estimateCost(p.interpretable)
|
||||
}
|
||||
|
||||
// progFactory is a helper alias for marking a program creation factory function.
|
||||
type progFactory func(interpreter.EvalState, *interpreter.CostTracker) (Program, error)
|
||||
|
||||
@ -354,7 +379,7 @@ func newProgGen(factory progFactory) (Program, error) {
|
||||
}
|
||||
|
||||
// Eval implements the Program interface method.
|
||||
func (gen *progGen) Eval(input interface{}) (ref.Val, *EvalDetails, error) {
|
||||
func (gen *progGen) Eval(input any) (ref.Val, *EvalDetails, error) {
|
||||
// The factory based Eval() differs from the standard evaluation model in that it generates a
|
||||
// new EvalState instance for each call to ensure that unique evaluations yield unique stateful
|
||||
// results.
|
||||
@ -379,7 +404,7 @@ func (gen *progGen) Eval(input interface{}) (ref.Val, *EvalDetails, error) {
|
||||
}
|
||||
|
||||
// ContextEval implements the Program interface method.
|
||||
func (gen *progGen) ContextEval(ctx context.Context, input interface{}) (ref.Val, *EvalDetails, error) {
|
||||
func (gen *progGen) ContextEval(ctx context.Context, input any) (ref.Val, *EvalDetails, error) {
|
||||
if ctx == nil {
|
||||
return nil, nil, fmt.Errorf("context can not be nil")
|
||||
}
|
||||
@ -406,29 +431,6 @@ func (gen *progGen) ContextEval(ctx context.Context, input interface{}) (ref.Val
|
||||
return v, det, nil
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (gen *progGen) Cost() (min, max int64) {
|
||||
// Use an empty state value since no evaluation is performed.
|
||||
p, err := gen.factory(emptyEvalState, nil)
|
||||
if err != nil {
|
||||
return 0, math.MaxInt64
|
||||
}
|
||||
return estimateCost(p)
|
||||
}
|
||||
|
||||
// EstimateCost returns the heuristic cost interval for the program.
|
||||
func EstimateCost(p Program) (min, max int64) {
|
||||
return estimateCost(p)
|
||||
}
|
||||
|
||||
func estimateCost(i interface{}) (min, max int64) {
|
||||
c, ok := i.(interpreter.Coster)
|
||||
if !ok {
|
||||
return 0, math.MaxInt64
|
||||
}
|
||||
return c.Cost()
|
||||
}
|
||||
|
||||
type ctxEvalActivation struct {
|
||||
parent interpreter.Activation
|
||||
interrupt <-chan struct{}
|
||||
@ -438,7 +440,7 @@ type ctxEvalActivation struct {
|
||||
|
||||
// ResolveName implements the Activation interface method, but adds a special #interrupted variable
|
||||
// which is capable of testing whether a 'done' signal is provided from a context.Context channel.
|
||||
func (a *ctxEvalActivation) ResolveName(name string) (interface{}, bool) {
|
||||
func (a *ctxEvalActivation) ResolveName(name string) (any, bool) {
|
||||
if name == "#interrupted" {
|
||||
a.interruptCheckCount++
|
||||
if a.interruptCheckCount%a.interruptCheckFrequency == 0 {
|
||||
@ -461,7 +463,7 @@ func (a *ctxEvalActivation) Parent() interpreter.Activation {
|
||||
func newCtxEvalActivationPool() *ctxEvalActivationPool {
|
||||
return &ctxEvalActivationPool{
|
||||
Pool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
return &ctxEvalActivation{}
|
||||
},
|
||||
},
|
||||
@ -483,21 +485,21 @@ func (p *ctxEvalActivationPool) Setup(vars interpreter.Activation, done <-chan s
|
||||
}
|
||||
|
||||
type evalActivation struct {
|
||||
vars map[string]interface{}
|
||||
lazyVars map[string]interface{}
|
||||
vars map[string]any
|
||||
lazyVars map[string]any
|
||||
}
|
||||
|
||||
// ResolveName looks up the value of the input variable name, if found.
|
||||
//
|
||||
// Lazy bindings may be supplied within the map-based input in either of the following forms:
|
||||
// - func() interface{}
|
||||
// - func() any
|
||||
// - func() ref.Val
|
||||
//
|
||||
// The lazy binding will only be invoked once per evaluation.
|
||||
//
|
||||
// Values which are not represented as ref.Val types on input may be adapted to a ref.Val using
|
||||
// the ref.TypeAdapter configured in the environment.
|
||||
func (a *evalActivation) ResolveName(name string) (interface{}, bool) {
|
||||
func (a *evalActivation) ResolveName(name string) (any, bool) {
|
||||
v, found := a.vars[name]
|
||||
if !found {
|
||||
return nil, false
|
||||
@ -510,7 +512,7 @@ func (a *evalActivation) ResolveName(name string) (interface{}, bool) {
|
||||
lazy := obj()
|
||||
a.lazyVars[name] = lazy
|
||||
return lazy, true
|
||||
case func() interface{}:
|
||||
case func() any:
|
||||
if resolved, found := a.lazyVars[name]; found {
|
||||
return resolved, true
|
||||
}
|
||||
@ -530,8 +532,8 @@ func (a *evalActivation) Parent() interpreter.Activation {
|
||||
func newEvalActivationPool() *evalActivationPool {
|
||||
return &evalActivationPool{
|
||||
Pool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &evalActivation{lazyVars: make(map[string]interface{})}
|
||||
New: func() any {
|
||||
return &evalActivation{lazyVars: make(map[string]any)}
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -542,13 +544,13 @@ type evalActivationPool struct {
|
||||
}
|
||||
|
||||
// Setup initializes a pooled Activation object with the map input.
|
||||
func (p *evalActivationPool) Setup(vars map[string]interface{}) *evalActivation {
|
||||
func (p *evalActivationPool) Setup(vars map[string]any) *evalActivation {
|
||||
a := p.Pool.Get().(*evalActivation)
|
||||
a.vars = vars
|
||||
return a
|
||||
}
|
||||
|
||||
func (p *evalActivationPool) Put(value interface{}) {
|
||||
func (p *evalActivationPool) Put(value any) {
|
||||
a := value.(*evalActivation)
|
||||
for k := range a.lazyVars {
|
||||
delete(a.lazyVars, k)
|
||||
@ -559,7 +561,7 @@ func (p *evalActivationPool) Put(value interface{}) {
|
||||
var (
|
||||
emptyEvalState = interpreter.NewEvalState()
|
||||
|
||||
// activationPool is an internally managed pool of Activation values that wrap map[string]interface{} inputs
|
||||
// activationPool is an internally managed pool of Activation values that wrap map[string]any inputs
|
||||
activationPool = newEvalActivationPool()
|
||||
|
||||
// ctxActivationPool is an internally managed pool of Activation values that expose a special #interrupted variable
|
||||
|
4
vendor/github.com/google/cel-go/checker/BUILD.bazel
generated
vendored
4
vendor/github.com/google/cel-go/checker/BUILD.bazel
generated
vendored
@ -30,7 +30,7 @@ go_library(
|
||||
"//common/types/pb:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"//parser:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
|
||||
@ -54,7 +54,7 @@ go_test(
|
||||
"//test:go_default_library",
|
||||
"//test/proto2pb:go_default_library",
|
||||
"//test/proto3pb:go_default_library",
|
||||
"@com_github_antlr_antlr4_runtime_go_antlr//:go_default_library",
|
||||
"@com_github_antlr_antlr4_runtime_go_antlr_v4//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
|
137
vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
137
vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
@ -23,6 +23,7 @@ import (
|
||||
"github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
@ -173,8 +174,8 @@ func (c *checker) checkSelect(e *exprpb.Expr) {
|
||||
|
||||
// Rewrite the node to be a variable reference to the resolved fully-qualified
|
||||
// variable name.
|
||||
c.setType(e, ident.GetIdent().Type)
|
||||
c.setReference(e, newIdentReference(ident.GetName(), ident.GetIdent().Value))
|
||||
c.setType(e, ident.GetIdent().GetType())
|
||||
c.setReference(e, newIdentReference(ident.GetName(), ident.GetIdent().GetValue()))
|
||||
identName := ident.GetName()
|
||||
e.ExprKind = &exprpb.Expr_IdentExpr{
|
||||
IdentExpr: &exprpb.Expr_Ident{
|
||||
@ -185,9 +186,37 @@ func (c *checker) checkSelect(e *exprpb.Expr) {
|
||||
}
|
||||
}
|
||||
|
||||
resultType := c.checkSelectField(e, sel.GetOperand(), sel.GetField(), false)
|
||||
if sel.TestOnly {
|
||||
resultType = decls.Bool
|
||||
}
|
||||
c.setType(e, substitute(c.mappings, resultType, false))
|
||||
}
|
||||
|
||||
func (c *checker) checkOptSelect(e *exprpb.Expr) {
|
||||
// Collect metadata related to the opt select call packaged by the parser.
|
||||
call := e.GetCallExpr()
|
||||
operand := call.GetArgs()[0]
|
||||
field := call.GetArgs()[1]
|
||||
fieldName, isString := maybeUnwrapString(field)
|
||||
if !isString {
|
||||
c.errors.ReportError(c.location(field), "unsupported optional field selection: %v", field)
|
||||
return
|
||||
}
|
||||
|
||||
// Perform type-checking using the field selection logic.
|
||||
resultType := c.checkSelectField(e, operand, fieldName, true)
|
||||
c.setType(e, substitute(c.mappings, resultType, false))
|
||||
}
|
||||
|
||||
func (c *checker) checkSelectField(e, operand *exprpb.Expr, field string, optional bool) *exprpb.Type {
|
||||
// Interpret as field selection, first traversing down the operand.
|
||||
c.check(sel.GetOperand())
|
||||
targetType := substitute(c.mappings, c.getType(sel.GetOperand()), false)
|
||||
c.check(operand)
|
||||
operandType := substitute(c.mappings, c.getType(operand), false)
|
||||
|
||||
// If the target type is 'optional', unwrap it for the sake of this check.
|
||||
targetType, isOpt := maybeUnwrapOptional(operandType)
|
||||
|
||||
// Assume error type by default as most types do not support field selection.
|
||||
resultType := decls.Error
|
||||
switch kindOf(targetType) {
|
||||
@ -199,7 +228,7 @@ func (c *checker) checkSelect(e *exprpb.Expr) {
|
||||
// Objects yield their field type declaration as the selection result type, but only if
|
||||
// the field is defined.
|
||||
messageType := targetType
|
||||
if fieldType, found := c.lookupFieldType(c.location(e), messageType.GetMessageType(), sel.GetField()); found {
|
||||
if fieldType, found := c.lookupFieldType(c.location(e), messageType.GetMessageType(), field); found {
|
||||
resultType = fieldType.Type
|
||||
}
|
||||
case kindTypeParam:
|
||||
@ -212,16 +241,17 @@ func (c *checker) checkSelect(e *exprpb.Expr) {
|
||||
default:
|
||||
// Dynamic / error values are treated as DYN type. Errors are handled this way as well
|
||||
// in order to allow forward progress on the check.
|
||||
if isDynOrError(targetType) {
|
||||
resultType = decls.Dyn
|
||||
} else {
|
||||
if !isDynOrError(targetType) {
|
||||
c.errors.typeDoesNotSupportFieldSelection(c.location(e), targetType)
|
||||
}
|
||||
resultType = decls.Dyn
|
||||
}
|
||||
if sel.TestOnly {
|
||||
resultType = decls.Bool
|
||||
|
||||
// If the target type was optional coming in, then the result must be optional going out.
|
||||
if isOpt || optional {
|
||||
return decls.NewOptionalType(resultType)
|
||||
}
|
||||
c.setType(e, substitute(c.mappings, resultType, false))
|
||||
return resultType
|
||||
}
|
||||
|
||||
func (c *checker) checkCall(e *exprpb.Expr) {
|
||||
@ -229,15 +259,19 @@ func (c *checker) checkCall(e *exprpb.Expr) {
|
||||
// please consider the impact on planner.go and consolidate implementations or mirror code
|
||||
// as appropriate.
|
||||
call := e.GetCallExpr()
|
||||
target := call.GetTarget()
|
||||
args := call.GetArgs()
|
||||
fnName := call.GetFunction()
|
||||
if fnName == operators.OptSelect {
|
||||
c.checkOptSelect(e)
|
||||
return
|
||||
}
|
||||
|
||||
args := call.GetArgs()
|
||||
// Traverse arguments.
|
||||
for _, arg := range args {
|
||||
c.check(arg)
|
||||
}
|
||||
|
||||
target := call.GetTarget()
|
||||
// Regular static call with simple name.
|
||||
if target == nil {
|
||||
// Check for the existence of the function.
|
||||
@ -359,6 +393,9 @@ func (c *checker) resolveOverload(
|
||||
}
|
||||
|
||||
if resultType == nil {
|
||||
for i, arg := range argTypes {
|
||||
argTypes[i] = substitute(c.mappings, arg, true)
|
||||
}
|
||||
c.errors.noMatchingOverload(loc, fn.GetName(), argTypes, target != nil)
|
||||
resultType = decls.Error
|
||||
return nil
|
||||
@ -369,16 +406,29 @@ func (c *checker) resolveOverload(
|
||||
|
||||
func (c *checker) checkCreateList(e *exprpb.Expr) {
|
||||
create := e.GetListExpr()
|
||||
var elemType *exprpb.Type
|
||||
for _, e := range create.GetElements() {
|
||||
var elemsType *exprpb.Type
|
||||
optionalIndices := create.GetOptionalIndices()
|
||||
optionals := make(map[int32]bool, len(optionalIndices))
|
||||
for _, optInd := range optionalIndices {
|
||||
optionals[optInd] = true
|
||||
}
|
||||
for i, e := range create.GetElements() {
|
||||
c.check(e)
|
||||
elemType = c.joinTypes(c.location(e), elemType, c.getType(e))
|
||||
elemType := c.getType(e)
|
||||
if optionals[int32(i)] {
|
||||
var isOptional bool
|
||||
elemType, isOptional = maybeUnwrapOptional(elemType)
|
||||
if !isOptional && !isDyn(elemType) {
|
||||
c.errors.typeMismatch(c.location(e), decls.NewOptionalType(elemType), elemType)
|
||||
}
|
||||
}
|
||||
elemsType = c.joinTypes(c.location(e), elemsType, elemType)
|
||||
}
|
||||
if elemType == nil {
|
||||
if elemsType == nil {
|
||||
// If the list is empty, assign free type var to elem type.
|
||||
elemType = c.newTypeVar()
|
||||
elemsType = c.newTypeVar()
|
||||
}
|
||||
c.setType(e, decls.NewListType(elemType))
|
||||
c.setType(e, decls.NewListType(elemsType))
|
||||
}
|
||||
|
||||
func (c *checker) checkCreateStruct(e *exprpb.Expr) {
|
||||
@ -392,22 +442,31 @@ func (c *checker) checkCreateStruct(e *exprpb.Expr) {
|
||||
|
||||
func (c *checker) checkCreateMap(e *exprpb.Expr) {
|
||||
mapVal := e.GetStructExpr()
|
||||
var keyType *exprpb.Type
|
||||
var valueType *exprpb.Type
|
||||
var mapKeyType *exprpb.Type
|
||||
var mapValueType *exprpb.Type
|
||||
for _, ent := range mapVal.GetEntries() {
|
||||
key := ent.GetMapKey()
|
||||
c.check(key)
|
||||
keyType = c.joinTypes(c.location(key), keyType, c.getType(key))
|
||||
mapKeyType = c.joinTypes(c.location(key), mapKeyType, c.getType(key))
|
||||
|
||||
c.check(ent.Value)
|
||||
valueType = c.joinTypes(c.location(ent.Value), valueType, c.getType(ent.Value))
|
||||
val := ent.GetValue()
|
||||
c.check(val)
|
||||
valType := c.getType(val)
|
||||
if ent.GetOptionalEntry() {
|
||||
var isOptional bool
|
||||
valType, isOptional = maybeUnwrapOptional(valType)
|
||||
if !isOptional && !isDyn(valType) {
|
||||
c.errors.typeMismatch(c.location(val), decls.NewOptionalType(valType), valType)
|
||||
}
|
||||
}
|
||||
mapValueType = c.joinTypes(c.location(val), mapValueType, valType)
|
||||
}
|
||||
if keyType == nil {
|
||||
if mapKeyType == nil {
|
||||
// If the map is empty, assign free type variables to typeKey and value type.
|
||||
keyType = c.newTypeVar()
|
||||
valueType = c.newTypeVar()
|
||||
mapKeyType = c.newTypeVar()
|
||||
mapValueType = c.newTypeVar()
|
||||
}
|
||||
c.setType(e, decls.NewMapType(keyType, valueType))
|
||||
c.setType(e, decls.NewMapType(mapKeyType, mapValueType))
|
||||
}
|
||||
|
||||
func (c *checker) checkCreateMessage(e *exprpb.Expr) {
|
||||
@ -449,15 +508,21 @@ func (c *checker) checkCreateMessage(e *exprpb.Expr) {
|
||||
c.check(value)
|
||||
|
||||
fieldType := decls.Error
|
||||
if t, found := c.lookupFieldType(
|
||||
c.locationByID(ent.GetId()),
|
||||
messageType.GetMessageType(),
|
||||
field); found {
|
||||
fieldType = t.Type
|
||||
ft, found := c.lookupFieldType(c.locationByID(ent.GetId()), messageType.GetMessageType(), field)
|
||||
if found {
|
||||
fieldType = ft.Type
|
||||
}
|
||||
if !c.isAssignable(fieldType, c.getType(value)) {
|
||||
c.errors.fieldTypeMismatch(
|
||||
c.locationByID(ent.Id), field, fieldType, c.getType(value))
|
||||
|
||||
valType := c.getType(value)
|
||||
if ent.GetOptionalEntry() {
|
||||
var isOptional bool
|
||||
valType, isOptional = maybeUnwrapOptional(valType)
|
||||
if !isOptional && !isDyn(valType) {
|
||||
c.errors.typeMismatch(c.location(value), decls.NewOptionalType(valType), valType)
|
||||
}
|
||||
}
|
||||
if !c.isAssignable(fieldType, valType) {
|
||||
c.errors.fieldTypeMismatch(c.locationByID(ent.Id), field, fieldType, valType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
59
vendor/github.com/google/cel-go/checker/cost.go
generated
vendored
59
vendor/github.com/google/cel-go/checker/cost.go
generated
vendored
@ -92,7 +92,10 @@ func (e astNode) ComputedSize() *SizeEstimate {
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
switch ck := ek.ConstExpr.GetConstantKind().(type) {
|
||||
case *exprpb.Constant_StringValue:
|
||||
v = uint64(len(ck.StringValue))
|
||||
// converting to runes here is an O(n) operation, but
|
||||
// this is consistent with how size is computed at runtime,
|
||||
// and how the language definition defines string size
|
||||
v = uint64(len([]rune(ck.StringValue)))
|
||||
case *exprpb.Constant_BytesValue:
|
||||
v = uint64(len(ck.BytesValue))
|
||||
case *exprpb.Constant_BoolValue, *exprpb.Constant_DoubleValue, *exprpb.Constant_DurationValue,
|
||||
@ -258,6 +261,8 @@ type coster struct {
|
||||
computedSizes map[int64]SizeEstimate
|
||||
checkedExpr *exprpb.CheckedExpr
|
||||
estimator CostEstimator
|
||||
// presenceTestCost will either be a zero or one based on whether has() macros count against cost computations.
|
||||
presenceTestCost CostEstimate
|
||||
}
|
||||
|
||||
// Use a stack of iterVar -> iterRange Expr Ids to handle shadowed variable names.
|
||||
@ -280,16 +285,39 @@ func (vs iterRangeScopes) peek(varName string) (int64, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Cost estimates the cost of the parsed and type checked CEL expression.
|
||||
func Cost(checker *exprpb.CheckedExpr, estimator CostEstimator) CostEstimate {
|
||||
c := coster{
|
||||
checkedExpr: checker,
|
||||
estimator: estimator,
|
||||
exprPath: map[int64][]string{},
|
||||
iterRanges: map[string][]int64{},
|
||||
computedSizes: map[int64]SizeEstimate{},
|
||||
// CostOption configures flags which affect cost computations.
|
||||
type CostOption func(*coster) error
|
||||
|
||||
// PresenceTestHasCost determines whether presence testing has a cost of one or zero.
|
||||
// Defaults to presence test has a cost of one.
|
||||
func PresenceTestHasCost(hasCost bool) CostOption {
|
||||
return func(c *coster) error {
|
||||
if hasCost {
|
||||
c.presenceTestCost = selectAndIdentCost
|
||||
return nil
|
||||
}
|
||||
c.presenceTestCost = CostEstimate{Min: 0, Max: 0}
|
||||
return nil
|
||||
}
|
||||
return c.cost(checker.GetExpr())
|
||||
}
|
||||
|
||||
// Cost estimates the cost of the parsed and type checked CEL expression.
|
||||
func Cost(checker *exprpb.CheckedExpr, estimator CostEstimator, opts ...CostOption) (CostEstimate, error) {
|
||||
c := &coster{
|
||||
checkedExpr: checker,
|
||||
estimator: estimator,
|
||||
exprPath: map[int64][]string{},
|
||||
iterRanges: map[string][]int64{},
|
||||
computedSizes: map[int64]SizeEstimate{},
|
||||
presenceTestCost: CostEstimate{Min: 1, Max: 1},
|
||||
}
|
||||
for _, opt := range opts {
|
||||
err := opt(c)
|
||||
if err != nil {
|
||||
return CostEstimate{}, err
|
||||
}
|
||||
}
|
||||
return c.cost(checker.GetExpr()), nil
|
||||
}
|
||||
|
||||
func (c *coster) cost(e *exprpb.Expr) CostEstimate {
|
||||
@ -340,6 +368,12 @@ func (c *coster) costSelect(e *exprpb.Expr) CostEstimate {
|
||||
sel := e.GetSelectExpr()
|
||||
var sum CostEstimate
|
||||
if sel.GetTestOnly() {
|
||||
// recurse, but do not add any cost
|
||||
// this is equivalent to how evalTestOnly increments the runtime cost counter
|
||||
// but does not add any additional cost for the qualifier, except here we do
|
||||
// the reverse (ident adds cost)
|
||||
sum = sum.Add(c.presenceTestCost)
|
||||
sum = sum.Add(c.cost(sel.GetOperand()))
|
||||
return sum
|
||||
}
|
||||
sum = sum.Add(c.cost(sel.GetOperand()))
|
||||
@ -503,7 +537,10 @@ func (c *coster) functionCost(function, overloadID string, target *AstNode, args
|
||||
}
|
||||
switch overloadID {
|
||||
// O(n) functions
|
||||
case overloads.StartsWithString, overloads.EndsWithString, overloads.StringToBytes, overloads.BytesToString:
|
||||
case overloads.StartsWithString, overloads.EndsWithString, overloads.StringToBytes, overloads.BytesToString, overloads.ExtQuoteString, overloads.ExtFormatString:
|
||||
if overloadID == overloads.ExtFormatString {
|
||||
return CallEstimate{CostEstimate: c.sizeEstimate(*target).MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum())}
|
||||
}
|
||||
if len(args) == 1 {
|
||||
return CallEstimate{CostEstimate: c.sizeEstimate(args[0]).MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum())}
|
||||
}
|
||||
|
2
vendor/github.com/google/cel-go/checker/decls/BUILD.bazel
generated
vendored
2
vendor/github.com/google/cel-go/checker/decls/BUILD.bazel
generated
vendored
@ -13,7 +13,7 @@ go_library(
|
||||
],
|
||||
importpath = "github.com/google/cel-go/checker/decls",
|
||||
deps = [
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
|
||||
],
|
||||
|
8
vendor/github.com/google/cel-go/checker/decls/decls.go
generated
vendored
8
vendor/github.com/google/cel-go/checker/decls/decls.go
generated
vendored
@ -16,9 +16,9 @@
|
||||
package decls
|
||||
|
||||
import (
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -64,6 +64,12 @@ func NewAbstractType(name string, paramTypes ...*exprpb.Type) *exprpb.Type {
|
||||
ParameterTypes: paramTypes}}}
|
||||
}
|
||||
|
||||
// NewOptionalType constructs an abstract type indicating that the parameterized type
|
||||
// may be contained within the object.
|
||||
func NewOptionalType(paramType *exprpb.Type) *exprpb.Type {
|
||||
return NewAbstractType("optional", paramType)
|
||||
}
|
||||
|
||||
// NewFunctionType creates a function invocation contract, typically only used
|
||||
// by type-checking steps after overload resolution.
|
||||
func NewFunctionType(resultType *exprpb.Type,
|
||||
|
27
vendor/github.com/google/cel-go/checker/env.go
generated
vendored
27
vendor/github.com/google/cel-go/checker/env.go
generated
vendored
@ -226,7 +226,7 @@ func (e *Env) setFunction(decl *exprpb.Decl) []errorMsg {
|
||||
newOverloads := []*exprpb.Decl_FunctionDecl_Overload{}
|
||||
for _, overload := range overloads {
|
||||
existing, found := existingOverloads[overload.GetOverloadId()]
|
||||
if !found || !proto.Equal(existing, overload) {
|
||||
if !found || !overloadsEqual(existing, overload) {
|
||||
newOverloads = append(newOverloads, overload)
|
||||
}
|
||||
}
|
||||
@ -264,6 +264,31 @@ func (e *Env) isOverloadDisabled(overloadID string) bool {
|
||||
return found
|
||||
}
|
||||
|
||||
// overloadsEqual returns whether two overloads have identical signatures.
|
||||
//
|
||||
// type parameter names are ignored as they may be specified in any order and have no bearing on overload
|
||||
// equivalence
|
||||
func overloadsEqual(o1, o2 *exprpb.Decl_FunctionDecl_Overload) bool {
|
||||
return o1.GetOverloadId() == o2.GetOverloadId() &&
|
||||
o1.GetIsInstanceFunction() == o2.GetIsInstanceFunction() &&
|
||||
paramsEqual(o1.GetParams(), o2.GetParams()) &&
|
||||
proto.Equal(o1.GetResultType(), o2.GetResultType())
|
||||
}
|
||||
|
||||
// paramsEqual returns whether two lists have equal length and all types are equal
|
||||
func paramsEqual(p1, p2 []*exprpb.Type) bool {
|
||||
if len(p1) != len(p2) {
|
||||
return false
|
||||
}
|
||||
for i, a := range p1 {
|
||||
b := p2[i]
|
||||
if !proto.Equal(a, b) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// sanitizeFunction replaces well-known types referenced by message name with their equivalent
|
||||
// CEL built-in type instances.
|
||||
func sanitizeFunction(decl *exprpb.Decl) *exprpb.Decl {
|
||||
|
2
vendor/github.com/google/cel-go/checker/printer.go
generated
vendored
2
vendor/github.com/google/cel-go/checker/printer.go
generated
vendored
@ -26,7 +26,7 @@ type semanticAdorner struct {
|
||||
|
||||
var _ debug.Adorner = &semanticAdorner{}
|
||||
|
||||
func (a *semanticAdorner) GetMetadata(elem interface{}) string {
|
||||
func (a *semanticAdorner) GetMetadata(elem any) string {
|
||||
result := ""
|
||||
e, isExpr := elem.(*exprpb.Expr)
|
||||
if !isExpr {
|
||||
|
2
vendor/github.com/google/cel-go/checker/standard.go
generated
vendored
2
vendor/github.com/google/cel-go/checker/standard.go
generated
vendored
@ -287,6 +287,8 @@ func init() {
|
||||
decls.NewInstanceOverload(overloads.EndsWithString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
|
||||
decls.NewFunction(overloads.Matches,
|
||||
decls.NewOverload(overloads.Matches,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool),
|
||||
decls.NewInstanceOverload(overloads.MatchesString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
|
||||
decls.NewFunction(overloads.StartsWith,
|
||||
|
47
vendor/github.com/google/cel-go/checker/types.go
generated
vendored
47
vendor/github.com/google/cel-go/checker/types.go
generated
vendored
@ -90,6 +90,14 @@ func FormatCheckedType(t *exprpb.Type) string {
|
||||
return "!error!"
|
||||
case kindTypeParam:
|
||||
return t.GetTypeParam()
|
||||
case kindAbstract:
|
||||
at := t.GetAbstractType()
|
||||
params := at.GetParameterTypes()
|
||||
paramStrs := make([]string, len(params))
|
||||
for i, p := range params {
|
||||
paramStrs[i] = FormatCheckedType(p)
|
||||
}
|
||||
return fmt.Sprintf("%s(%s)", at.GetName(), strings.Join(paramStrs, ", "))
|
||||
}
|
||||
return t.String()
|
||||
}
|
||||
@ -110,12 +118,39 @@ func isDyn(t *exprpb.Type) bool {
|
||||
|
||||
// isDynOrError returns true if the input is either an Error, DYN, or well-known ANY message.
|
||||
func isDynOrError(t *exprpb.Type) bool {
|
||||
switch kindOf(t) {
|
||||
case kindError:
|
||||
return true
|
||||
default:
|
||||
return isDyn(t)
|
||||
return isError(t) || isDyn(t)
|
||||
}
|
||||
|
||||
func isError(t *exprpb.Type) bool {
|
||||
return kindOf(t) == kindError
|
||||
}
|
||||
|
||||
func isOptional(t *exprpb.Type) bool {
|
||||
if kindOf(t) == kindAbstract {
|
||||
at := t.GetAbstractType()
|
||||
return at.GetName() == "optional"
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func maybeUnwrapOptional(t *exprpb.Type) (*exprpb.Type, bool) {
|
||||
if isOptional(t) {
|
||||
at := t.GetAbstractType()
|
||||
return at.GetParameterTypes()[0], true
|
||||
}
|
||||
return t, false
|
||||
}
|
||||
|
||||
func maybeUnwrapString(e *exprpb.Expr) (string, bool) {
|
||||
switch e.GetExprKind().(type) {
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
literal := e.GetConstExpr()
|
||||
switch literal.GetConstantKind().(type) {
|
||||
case *exprpb.Constant_StringValue:
|
||||
return literal.GetStringValue(), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// isEqualOrLessSpecific checks whether one type is equal or less specific than the other one.
|
||||
@ -236,7 +271,7 @@ func internalIsAssignable(m *mapping, t1 *exprpb.Type, t2 *exprpb.Type) bool {
|
||||
// substitution for t1, and whether t2 has a type substitution in mapping m.
|
||||
//
|
||||
// The type t2 is a valid substitution for t1 if any of the following statements is true
|
||||
// - t2 has a type substitition (t2sub) equal to t1
|
||||
// - t2 has a type substitution (t2sub) equal to t1
|
||||
// - t2 has a type substitution (t2sub) assignable to t1
|
||||
// - t2 does not occur within t1.
|
||||
func isValidTypeSubstitution(m *mapping, t1, t2 *exprpb.Type) (valid, hasSub bool) {
|
||||
|
2
vendor/github.com/google/cel-go/common/BUILD.bazel
generated
vendored
2
vendor/github.com/google/cel-go/common/BUILD.bazel
generated
vendored
@ -17,7 +17,7 @@ go_library(
|
||||
importpath = "github.com/google/cel-go/common",
|
||||
deps = [
|
||||
"//common/runes:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_x_text//width:go_default_library",
|
||||
],
|
||||
)
|
||||
|
4
vendor/github.com/google/cel-go/common/containers/BUILD.bazel
generated
vendored
4
vendor/github.com/google/cel-go/common/containers/BUILD.bazel
generated
vendored
@ -12,7 +12,7 @@ go_library(
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/containers",
|
||||
deps = [
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -26,6 +26,6 @@ go_test(
|
||||
":go_default_library",
|
||||
],
|
||||
deps = [
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
2
vendor/github.com/google/cel-go/common/debug/BUILD.bazel
generated
vendored
2
vendor/github.com/google/cel-go/common/debug/BUILD.bazel
generated
vendored
@ -13,6 +13,6 @@ go_library(
|
||||
importpath = "github.com/google/cel-go/common/debug",
|
||||
deps = [
|
||||
"//common:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
14
vendor/github.com/google/cel-go/common/debug/debug.go
generated
vendored
14
vendor/github.com/google/cel-go/common/debug/debug.go
generated
vendored
@ -29,7 +29,7 @@ import (
|
||||
// representation of an expression.
|
||||
type Adorner interface {
|
||||
// GetMetadata for the input context.
|
||||
GetMetadata(ctx interface{}) string
|
||||
GetMetadata(ctx any) string
|
||||
}
|
||||
|
||||
// Writer manages writing expressions to an internal string.
|
||||
@ -46,7 +46,7 @@ type emptyDebugAdorner struct {
|
||||
|
||||
var emptyAdorner Adorner = &emptyDebugAdorner{}
|
||||
|
||||
func (a *emptyDebugAdorner) GetMetadata(e interface{}) string {
|
||||
func (a *emptyDebugAdorner) GetMetadata(e any) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -170,6 +170,9 @@ func (w *debugWriter) appendObject(obj *exprpb.Expr_CreateStruct) {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
if entry.GetOptionalEntry() {
|
||||
w.append("?")
|
||||
}
|
||||
w.append(entry.GetFieldKey())
|
||||
w.append(":")
|
||||
w.Buffer(entry.GetValue())
|
||||
@ -191,6 +194,9 @@ func (w *debugWriter) appendMap(obj *exprpb.Expr_CreateStruct) {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
if entry.GetOptionalEntry() {
|
||||
w.append("?")
|
||||
}
|
||||
w.Buffer(entry.GetMapKey())
|
||||
w.append(":")
|
||||
w.Buffer(entry.GetValue())
|
||||
@ -269,7 +275,7 @@ func (w *debugWriter) append(s string) {
|
||||
w.buffer.WriteString(s)
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendFormat(f string, args ...interface{}) {
|
||||
func (w *debugWriter) appendFormat(f string, args ...any) {
|
||||
w.append(fmt.Sprintf(f, args...))
|
||||
}
|
||||
|
||||
@ -280,7 +286,7 @@ func (w *debugWriter) doIndent() {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *debugWriter) adorn(e interface{}) {
|
||||
func (w *debugWriter) adorn(e any) {
|
||||
w.append(w.adorner.GetMetadata(e))
|
||||
}
|
||||
|
||||
|
2
vendor/github.com/google/cel-go/common/errors.go
generated
vendored
2
vendor/github.com/google/cel-go/common/errors.go
generated
vendored
@ -38,7 +38,7 @@ func NewErrors(source Source) *Errors {
|
||||
}
|
||||
|
||||
// ReportError records an error at a source location.
|
||||
func (e *Errors) ReportError(l Location, format string, args ...interface{}) {
|
||||
func (e *Errors) ReportError(l Location, format string, args ...any) {
|
||||
e.numErrors++
|
||||
if e.numErrors > e.maxErrorsToReport {
|
||||
return
|
||||
|
4
vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
4
vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
@ -37,6 +37,8 @@ const (
|
||||
Modulo = "_%_"
|
||||
Negate = "-_"
|
||||
Index = "_[_]"
|
||||
OptIndex = "_[?_]"
|
||||
OptSelect = "_?._"
|
||||
|
||||
// Macros, must have a valid identifier.
|
||||
Has = "has"
|
||||
@ -99,6 +101,8 @@ var (
|
||||
LogicalNot: {displayName: "!", precedence: 2, arity: 1},
|
||||
Negate: {displayName: "-", precedence: 2, arity: 1},
|
||||
Index: {displayName: "", precedence: 1, arity: 2},
|
||||
OptIndex: {displayName: "", precedence: 1, arity: 2},
|
||||
OptSelect: {displayName: "", precedence: 1, arity: 2},
|
||||
}
|
||||
)
|
||||
|
||||
|
10
vendor/github.com/google/cel-go/common/overloads/overloads.go
generated
vendored
10
vendor/github.com/google/cel-go/common/overloads/overloads.go
generated
vendored
@ -148,6 +148,11 @@ const (
|
||||
StartsWith = "startsWith"
|
||||
)
|
||||
|
||||
// Extension function overloads with complex behaviors that need to be referenced in runtime and static analysis cost computations.
|
||||
const (
|
||||
ExtQuoteString = "strings_quote"
|
||||
)
|
||||
|
||||
// String function overload names.
|
||||
const (
|
||||
ContainsString = "contains_string"
|
||||
@ -156,6 +161,11 @@ const (
|
||||
StartsWithString = "starts_with_string"
|
||||
)
|
||||
|
||||
// Extension function overloads with complex behaviors that need to be referenced in runtime and static analysis cost computations.
|
||||
const (
|
||||
ExtFormatString = "string_format"
|
||||
)
|
||||
|
||||
// Time-based functions.
|
||||
const (
|
||||
TimeGetFullYear = "getFullYear"
|
||||
|
10
vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
10
vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
@ -22,6 +22,7 @@ go_library(
|
||||
"map.go",
|
||||
"null.go",
|
||||
"object.go",
|
||||
"optional.go",
|
||||
"overflow.go",
|
||||
"provider.go",
|
||||
"string.go",
|
||||
@ -38,10 +39,8 @@ go_library(
|
||||
"//common/types/ref:go_default_library",
|
||||
"//common/types/traits:go_default_library",
|
||||
"@com_github_stoewer_go_strcase//:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/rpc/status:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_rpc//status:go_default_library",
|
||||
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
|
||||
@ -68,6 +67,7 @@ go_test(
|
||||
"map_test.go",
|
||||
"null_test.go",
|
||||
"object_test.go",
|
||||
"optional_test.go",
|
||||
"provider_test.go",
|
||||
"string_test.go",
|
||||
"timestamp_test.go",
|
||||
@ -80,7 +80,7 @@ go_test(
|
||||
"//common/types/ref:go_default_library",
|
||||
"//test:go_default_library",
|
||||
"//test/proto3pb:test_all_types_go_proto",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/anypb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
|
||||
|
9
vendor/github.com/google/cel-go/common/types/bool.go
generated
vendored
9
vendor/github.com/google/cel-go/common/types/bool.go
generated
vendored
@ -62,7 +62,7 @@ func (b Bool) Compare(other ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (b Bool) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (b Bool) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Bool:
|
||||
return reflect.ValueOf(b).Convert(typeDesc).Interface(), nil
|
||||
@ -114,6 +114,11 @@ func (b Bool) Equal(other ref.Val) ref.Val {
|
||||
return Bool(ok && b == otherBool)
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the boolean value is false.
|
||||
func (b Bool) IsZeroValue() bool {
|
||||
return b == False
|
||||
}
|
||||
|
||||
// Negate implements the traits.Negater interface method.
|
||||
func (b Bool) Negate() ref.Val {
|
||||
return !b
|
||||
@ -125,7 +130,7 @@ func (b Bool) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (b Bool) Value() interface{} {
|
||||
func (b Bool) Value() any {
|
||||
return bool(b)
|
||||
}
|
||||
|
||||
|
9
vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
9
vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
@ -63,7 +63,7 @@ func (b Bytes) Compare(other ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (b Bytes) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (b Bytes) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return reflect.ValueOf(b).Convert(typeDesc).Interface(), nil
|
||||
@ -116,6 +116,11 @@ func (b Bytes) Equal(other ref.Val) ref.Val {
|
||||
return Bool(ok && bytes.Equal(b, otherBytes))
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the byte array is empty.
|
||||
func (b Bytes) IsZeroValue() bool {
|
||||
return len(b) == 0
|
||||
}
|
||||
|
||||
// Size implements the traits.Sizer interface method.
|
||||
func (b Bytes) Size() ref.Val {
|
||||
return Int(len(b))
|
||||
@ -127,6 +132,6 @@ func (b Bytes) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (b Bytes) Value() interface{} {
|
||||
func (b Bytes) Value() any {
|
||||
return []byte(b)
|
||||
}
|
||||
|
13
vendor/github.com/google/cel-go/common/types/double.go
generated
vendored
13
vendor/github.com/google/cel-go/common/types/double.go
generated
vendored
@ -78,7 +78,7 @@ func (d Double) Compare(other ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (d Double) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (d Double) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Float32:
|
||||
v := float32(d)
|
||||
@ -134,13 +134,13 @@ func (d Double) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
case IntType:
|
||||
i, err := doubleToInt64Checked(float64(d))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Int(i)
|
||||
case UintType:
|
||||
i, err := doubleToUint64Checked(float64(d))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Uint(i)
|
||||
case DoubleType:
|
||||
@ -182,6 +182,11 @@ func (d Double) Equal(other ref.Val) ref.Val {
|
||||
}
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if double value is 0.0
|
||||
func (d Double) IsZeroValue() bool {
|
||||
return float64(d) == 0.0
|
||||
}
|
||||
|
||||
// Multiply implements traits.Multiplier.Multiply.
|
||||
func (d Double) Multiply(other ref.Val) ref.Val {
|
||||
otherDouble, ok := other.(Double)
|
||||
@ -211,6 +216,6 @@ func (d Double) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (d Double) Value() interface{} {
|
||||
func (d Double) Value() any {
|
||||
return float64(d)
|
||||
}
|
||||
|
17
vendor/github.com/google/cel-go/common/types/duration.go
generated
vendored
17
vendor/github.com/google/cel-go/common/types/duration.go
generated
vendored
@ -57,14 +57,14 @@ func (d Duration) Add(other ref.Val) ref.Val {
|
||||
dur2 := other.(Duration)
|
||||
val, err := addDurationChecked(d.Duration, dur2.Duration)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return durationOf(val)
|
||||
case TimestampType:
|
||||
ts := other.(Timestamp).Time
|
||||
val, err := addTimeDurationChecked(ts, d.Duration)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return timestampOf(val)
|
||||
}
|
||||
@ -90,7 +90,7 @@ func (d Duration) Compare(other ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (d Duration) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (d Duration) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
// If the duration is already assignable to the desired type return it.
|
||||
if reflect.TypeOf(d.Duration).AssignableTo(typeDesc) {
|
||||
return d.Duration, nil
|
||||
@ -138,11 +138,16 @@ func (d Duration) Equal(other ref.Val) ref.Val {
|
||||
return Bool(ok && d.Duration == otherDur.Duration)
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the duration value is zero
|
||||
func (d Duration) IsZeroValue() bool {
|
||||
return d.Duration == 0
|
||||
}
|
||||
|
||||
// Negate implements traits.Negater.Negate.
|
||||
func (d Duration) Negate() ref.Val {
|
||||
val, err := negateDurationChecked(d.Duration)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return durationOf(val)
|
||||
}
|
||||
@ -165,7 +170,7 @@ func (d Duration) Subtract(subtrahend ref.Val) ref.Val {
|
||||
}
|
||||
val, err := subtractDurationChecked(d.Duration, subtraDur.Duration)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return durationOf(val)
|
||||
}
|
||||
@ -176,7 +181,7 @@ func (d Duration) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (d Duration) Value() interface{} {
|
||||
func (d Duration) Value() any {
|
||||
return d.Duration
|
||||
}
|
||||
|
||||
|
25
vendor/github.com/google/cel-go/common/types/err.go
generated
vendored
25
vendor/github.com/google/cel-go/common/types/err.go
generated
vendored
@ -22,6 +22,12 @@ import (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// Error interface which allows types types.Err values to be treated as error values.
|
||||
type Error interface {
|
||||
error
|
||||
ref.Val
|
||||
}
|
||||
|
||||
// Err type which extends the built-in go error and implements ref.Val.
|
||||
type Err struct {
|
||||
error
|
||||
@ -51,7 +57,7 @@ var (
|
||||
|
||||
// NewErr creates a new Err described by the format string and args.
|
||||
// TODO: Audit the use of this function and standardize the error messages and codes.
|
||||
func NewErr(format string, args ...interface{}) ref.Val {
|
||||
func NewErr(format string, args ...any) ref.Val {
|
||||
return &Err{fmt.Errorf(format, args...)}
|
||||
}
|
||||
|
||||
@ -62,7 +68,7 @@ func NoSuchOverloadErr() ref.Val {
|
||||
|
||||
// UnsupportedRefValConversionErr returns a types.NewErr instance with a no such conversion
|
||||
// message that indicates that the native value could not be converted to a CEL ref.Val.
|
||||
func UnsupportedRefValConversionErr(val interface{}) ref.Val {
|
||||
func UnsupportedRefValConversionErr(val any) ref.Val {
|
||||
return NewErr("unsupported conversion to ref.Val: (%T)%v", val, val)
|
||||
}
|
||||
|
||||
@ -74,20 +80,20 @@ func MaybeNoSuchOverloadErr(val ref.Val) ref.Val {
|
||||
|
||||
// ValOrErr either returns the existing error or creates a new one.
|
||||
// TODO: Audit the use of this function and standardize the error messages and codes.
|
||||
func ValOrErr(val ref.Val, format string, args ...interface{}) ref.Val {
|
||||
func ValOrErr(val ref.Val, format string, args ...any) ref.Val {
|
||||
if val == nil || !IsUnknownOrError(val) {
|
||||
return NewErr(format, args...)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// wrapErr wraps an existing Go error value into a CEL Err value.
|
||||
func wrapErr(err error) ref.Val {
|
||||
// WrapErr wraps an existing Go error value into a CEL Err value.
|
||||
func WrapErr(err error) ref.Val {
|
||||
return &Err{error: err}
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (e *Err) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (e *Err) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
return nil, e.error
|
||||
}
|
||||
|
||||
@ -114,10 +120,15 @@ func (e *Err) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (e *Err) Value() interface{} {
|
||||
func (e *Err) Value() any {
|
||||
return e.error
|
||||
}
|
||||
|
||||
// Is implements errors.Is.
|
||||
func (e *Err) Is(target error) bool {
|
||||
return e.error.Error() == target.Error()
|
||||
}
|
||||
|
||||
// IsError returns whether the input element ref.Type or ref.Val is equal to
|
||||
// the ErrType singleton.
|
||||
func IsError(val ref.Val) bool {
|
||||
|
23
vendor/github.com/google/cel-go/common/types/int.go
generated
vendored
23
vendor/github.com/google/cel-go/common/types/int.go
generated
vendored
@ -66,7 +66,7 @@ func (i Int) Add(other ref.Val) ref.Val {
|
||||
}
|
||||
val, err := addInt64Checked(int64(i), int64(otherInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
@ -89,7 +89,7 @@ func (i Int) Compare(other ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (i Int) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (i Int) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Int, reflect.Int32:
|
||||
// Enums are also mapped as int32 derivations.
|
||||
@ -176,7 +176,7 @@ func (i Int) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
case UintType:
|
||||
u, err := int64ToUint64Checked(int64(i))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Uint(u)
|
||||
case DoubleType:
|
||||
@ -204,7 +204,7 @@ func (i Int) Divide(other ref.Val) ref.Val {
|
||||
}
|
||||
val, err := divideInt64Checked(int64(i), int64(otherInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
@ -226,6 +226,11 @@ func (i Int) Equal(other ref.Val) ref.Val {
|
||||
}
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if integer is equal to 0
|
||||
func (i Int) IsZeroValue() bool {
|
||||
return i == IntZero
|
||||
}
|
||||
|
||||
// Modulo implements traits.Modder.Modulo.
|
||||
func (i Int) Modulo(other ref.Val) ref.Val {
|
||||
otherInt, ok := other.(Int)
|
||||
@ -234,7 +239,7 @@ func (i Int) Modulo(other ref.Val) ref.Val {
|
||||
}
|
||||
val, err := moduloInt64Checked(int64(i), int64(otherInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
@ -247,7 +252,7 @@ func (i Int) Multiply(other ref.Val) ref.Val {
|
||||
}
|
||||
val, err := multiplyInt64Checked(int64(i), int64(otherInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
@ -256,7 +261,7 @@ func (i Int) Multiply(other ref.Val) ref.Val {
|
||||
func (i Int) Negate() ref.Val {
|
||||
val, err := negateInt64Checked(int64(i))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
@ -269,7 +274,7 @@ func (i Int) Subtract(subtrahend ref.Val) ref.Val {
|
||||
}
|
||||
val, err := subtractInt64Checked(int64(i), int64(subtraInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
@ -280,7 +285,7 @@ func (i Int) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (i Int) Value() interface{} {
|
||||
func (i Int) Value() any {
|
||||
return int64(i)
|
||||
}
|
||||
|
||||
|
4
vendor/github.com/google/cel-go/common/types/iterator.go
generated
vendored
4
vendor/github.com/google/cel-go/common/types/iterator.go
generated
vendored
@ -34,7 +34,7 @@ var (
|
||||
// interpreter.
|
||||
type baseIterator struct{}
|
||||
|
||||
func (*baseIterator) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (*baseIterator) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
return nil, fmt.Errorf("type conversion on iterators not supported")
|
||||
}
|
||||
|
||||
@ -50,6 +50,6 @@ func (*baseIterator) Type() ref.Type {
|
||||
return IteratorType
|
||||
}
|
||||
|
||||
func (*baseIterator) Value() interface{} {
|
||||
func (*baseIterator) Value() any {
|
||||
return nil
|
||||
}
|
||||
|
1
vendor/github.com/google/cel-go/common/types/json_value.go
generated
vendored
1
vendor/github.com/google/cel-go/common/types/json_value.go
generated
vendored
@ -25,4 +25,5 @@ var (
|
||||
jsonValueType = reflect.TypeOf(&structpb.Value{})
|
||||
jsonListValueType = reflect.TypeOf(&structpb.ListValue{})
|
||||
jsonStructType = reflect.TypeOf(&structpb.Struct{})
|
||||
jsonNullType = reflect.TypeOf(structpb.NullValue_NULL_VALUE)
|
||||
)
|
||||
|
88
vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
88
vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
@ -17,11 +17,13 @@ package types
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
@ -40,13 +42,13 @@ var (
|
||||
// NewDynamicList returns a traits.Lister with heterogenous elements.
|
||||
// value should be an array of "native" types, i.e. any type that
|
||||
// NativeToValue() can convert to a ref.Val.
|
||||
func NewDynamicList(adapter ref.TypeAdapter, value interface{}) traits.Lister {
|
||||
func NewDynamicList(adapter ref.TypeAdapter, value any) traits.Lister {
|
||||
refValue := reflect.ValueOf(value)
|
||||
return &baseList{
|
||||
TypeAdapter: adapter,
|
||||
value: value,
|
||||
size: refValue.Len(),
|
||||
get: func(i int) interface{} {
|
||||
get: func(i int) any {
|
||||
return refValue.Index(i).Interface()
|
||||
},
|
||||
}
|
||||
@ -58,7 +60,7 @@ func NewStringList(adapter ref.TypeAdapter, elems []string) traits.Lister {
|
||||
TypeAdapter: adapter,
|
||||
value: elems,
|
||||
size: len(elems),
|
||||
get: func(i int) interface{} { return elems[i] },
|
||||
get: func(i int) any { return elems[i] },
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +72,7 @@ func NewRefValList(adapter ref.TypeAdapter, elems []ref.Val) traits.Lister {
|
||||
TypeAdapter: adapter,
|
||||
value: elems,
|
||||
size: len(elems),
|
||||
get: func(i int) interface{} { return elems[i] },
|
||||
get: func(i int) any { return elems[i] },
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +82,7 @@ func NewProtoList(adapter ref.TypeAdapter, list protoreflect.List) traits.Lister
|
||||
TypeAdapter: adapter,
|
||||
value: list,
|
||||
size: list.Len(),
|
||||
get: func(i int) interface{} { return list.Get(i).Interface() },
|
||||
get: func(i int) any { return list.Get(i).Interface() },
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,22 +93,25 @@ func NewJSONList(adapter ref.TypeAdapter, l *structpb.ListValue) traits.Lister {
|
||||
TypeAdapter: adapter,
|
||||
value: l,
|
||||
size: len(vals),
|
||||
get: func(i int) interface{} { return vals[i] },
|
||||
get: func(i int) any { return vals[i] },
|
||||
}
|
||||
}
|
||||
|
||||
// NewMutableList creates a new mutable list whose internal state can be modified.
|
||||
func NewMutableList(adapter ref.TypeAdapter) traits.MutableLister {
|
||||
var mutableValues []ref.Val
|
||||
return &mutableList{
|
||||
l := &mutableList{
|
||||
baseList: &baseList{
|
||||
TypeAdapter: adapter,
|
||||
value: mutableValues,
|
||||
size: 0,
|
||||
get: func(i int) interface{} { return mutableValues[i] },
|
||||
},
|
||||
mutableValues: mutableValues,
|
||||
}
|
||||
l.get = func(i int) any {
|
||||
return l.mutableValues[i]
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// baseList points to a list containing elements of any type.
|
||||
@ -114,7 +119,7 @@ func NewMutableList(adapter ref.TypeAdapter) traits.MutableLister {
|
||||
// The `ref.TypeAdapter` enables native type to CEL type conversions.
|
||||
type baseList struct {
|
||||
ref.TypeAdapter
|
||||
value interface{}
|
||||
value any
|
||||
|
||||
// size indicates the number of elements within the list.
|
||||
// Since objects are immutable the size of a list is static.
|
||||
@ -122,7 +127,7 @@ type baseList struct {
|
||||
|
||||
// get returns a value at the specified integer index.
|
||||
// The index is guaranteed to be checked against the list index range.
|
||||
get func(int) interface{}
|
||||
get func(int) any
|
||||
}
|
||||
|
||||
// Add implements the traits.Adder interface method.
|
||||
@ -157,7 +162,7 @@ func (l *baseList) Contains(elem ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (l *baseList) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (l *baseList) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
// If the underlying list value is assignable to the reflected type return it.
|
||||
if reflect.TypeOf(l.value).AssignableTo(typeDesc) {
|
||||
return l.value, nil
|
||||
@ -240,7 +245,7 @@ func (l *baseList) Equal(other ref.Val) ref.Val {
|
||||
|
||||
// Get implements the traits.Indexer interface method.
|
||||
func (l *baseList) Get(index ref.Val) ref.Val {
|
||||
ind, err := indexOrError(index)
|
||||
ind, err := IndexOrError(index)
|
||||
if err != nil {
|
||||
return ValOrErr(index, err.Error())
|
||||
}
|
||||
@ -250,6 +255,11 @@ func (l *baseList) Get(index ref.Val) ref.Val {
|
||||
return l.NativeToValue(l.get(ind))
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the list is empty.
|
||||
func (l *baseList) IsZeroValue() bool {
|
||||
return l.size == 0
|
||||
}
|
||||
|
||||
// Iterator implements the traits.Iterable interface method.
|
||||
func (l *baseList) Iterator() traits.Iterator {
|
||||
return newListIterator(l)
|
||||
@ -266,10 +276,24 @@ func (l *baseList) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (l *baseList) Value() interface{} {
|
||||
func (l *baseList) Value() any {
|
||||
return l.value
|
||||
}
|
||||
|
||||
// String converts the list to a human readable string form.
|
||||
func (l *baseList) String() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("[")
|
||||
for i := 0; i < l.size; i++ {
|
||||
sb.WriteString(fmt.Sprintf("%v", l.get(i)))
|
||||
if i != l.size-1 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
}
|
||||
sb.WriteString("]")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// mutableList aggregates values into its internal storage. For use with internal CEL variables only.
|
||||
type mutableList struct {
|
||||
*baseList
|
||||
@ -305,7 +329,7 @@ func (l *mutableList) ToImmutableList() traits.Lister {
|
||||
// The `ref.TypeAdapter` enables native type to CEL type conversions.
|
||||
type concatList struct {
|
||||
ref.TypeAdapter
|
||||
value interface{}
|
||||
value any
|
||||
prevList traits.Lister
|
||||
nextList traits.Lister
|
||||
}
|
||||
@ -351,8 +375,8 @@ func (l *concatList) Contains(elem ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (l *concatList) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
combined := NewDynamicList(l.TypeAdapter, l.Value().([]interface{}))
|
||||
func (l *concatList) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
combined := NewDynamicList(l.TypeAdapter, l.Value().([]any))
|
||||
return combined.ConvertToNative(typeDesc)
|
||||
}
|
||||
|
||||
@ -396,7 +420,7 @@ func (l *concatList) Equal(other ref.Val) ref.Val {
|
||||
|
||||
// Get implements the traits.Indexer interface method.
|
||||
func (l *concatList) Get(index ref.Val) ref.Val {
|
||||
ind, err := indexOrError(index)
|
||||
ind, err := IndexOrError(index)
|
||||
if err != nil {
|
||||
return ValOrErr(index, err.Error())
|
||||
}
|
||||
@ -408,6 +432,11 @@ func (l *concatList) Get(index ref.Val) ref.Val {
|
||||
return l.nextList.Get(offset)
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the list is empty.
|
||||
func (l *concatList) IsZeroValue() bool {
|
||||
return l.Size().(Int) == 0
|
||||
}
|
||||
|
||||
// Iterator implements the traits.Iterable interface method.
|
||||
func (l *concatList) Iterator() traits.Iterator {
|
||||
return newListIterator(l)
|
||||
@ -418,15 +447,29 @@ func (l *concatList) Size() ref.Val {
|
||||
return l.prevList.Size().(Int).Add(l.nextList.Size())
|
||||
}
|
||||
|
||||
// String converts the concatenated list to a human-readable string.
|
||||
func (l *concatList) String() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("[")
|
||||
for i := Int(0); i < l.Size().(Int); i++ {
|
||||
sb.WriteString(fmt.Sprintf("%v", l.Get(i)))
|
||||
if i != l.Size().(Int)-1 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
}
|
||||
sb.WriteString("]")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (l *concatList) Type() ref.Type {
|
||||
return ListType
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (l *concatList) Value() interface{} {
|
||||
func (l *concatList) Value() any {
|
||||
if l.value == nil {
|
||||
merged := make([]interface{}, l.Size().(Int))
|
||||
merged := make([]any, l.Size().(Int))
|
||||
prevLen := l.prevList.Size().(Int)
|
||||
for i := Int(0); i < prevLen; i++ {
|
||||
merged[i] = l.prevList.Get(i).Value()
|
||||
@ -469,7 +512,8 @@ func (it *listIterator) Next() ref.Val {
|
||||
return nil
|
||||
}
|
||||
|
||||
func indexOrError(index ref.Val) (int, error) {
|
||||
// IndexOrError converts an input index value into either a lossless integer index or an error.
|
||||
func IndexOrError(index ref.Val) (int, error) {
|
||||
switch iv := index.(type) {
|
||||
case Int:
|
||||
return int(iv), nil
|
||||
|
59
vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
59
vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
@ -17,20 +17,22 @@ package types
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/stoewer/go-strcase"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/pb"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
"github.com/stoewer/go-strcase"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// NewDynamicMap returns a traits.Mapper value with dynamic key, value pairs.
|
||||
func NewDynamicMap(adapter ref.TypeAdapter, value interface{}) traits.Mapper {
|
||||
func NewDynamicMap(adapter ref.TypeAdapter, value any) traits.Mapper {
|
||||
refValue := reflect.ValueOf(value)
|
||||
return &baseMap{
|
||||
TypeAdapter: adapter,
|
||||
@ -65,7 +67,7 @@ func NewRefValMap(adapter ref.TypeAdapter, value map[ref.Val]ref.Val) traits.Map
|
||||
}
|
||||
|
||||
// NewStringInterfaceMap returns a specialized traits.Mapper with string keys and interface values.
|
||||
func NewStringInterfaceMap(adapter ref.TypeAdapter, value map[string]interface{}) traits.Mapper {
|
||||
func NewStringInterfaceMap(adapter ref.TypeAdapter, value map[string]any) traits.Mapper {
|
||||
return &baseMap{
|
||||
TypeAdapter: adapter,
|
||||
mapAccessor: newStringIfaceMapAccessor(adapter, value),
|
||||
@ -125,7 +127,7 @@ type baseMap struct {
|
||||
mapAccessor
|
||||
|
||||
// value is the native Go value upon which the map type operators.
|
||||
value interface{}
|
||||
value any
|
||||
|
||||
// size is the number of entries in the map.
|
||||
size int
|
||||
@ -138,7 +140,7 @@ func (m *baseMap) Contains(index ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (m *baseMap) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (m *baseMap) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
// If the map is already assignable to the desired type return it, e.g. interfaces and
|
||||
// maps with the same key value types.
|
||||
if reflect.TypeOf(m.value).AssignableTo(typeDesc) {
|
||||
@ -275,18 +277,42 @@ func (m *baseMap) Get(key ref.Val) ref.Val {
|
||||
return v
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the map is empty.
|
||||
func (m *baseMap) IsZeroValue() bool {
|
||||
return m.size == 0
|
||||
}
|
||||
|
||||
// Size implements the traits.Sizer interface method.
|
||||
func (m *baseMap) Size() ref.Val {
|
||||
return Int(m.size)
|
||||
}
|
||||
|
||||
// String converts the map into a human-readable string.
|
||||
func (m *baseMap) String() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("{")
|
||||
it := m.Iterator()
|
||||
i := 0
|
||||
for it.HasNext() == True {
|
||||
k := it.Next()
|
||||
v, _ := m.Find(k)
|
||||
sb.WriteString(fmt.Sprintf("%v: %v", k, v))
|
||||
if i != m.size-1 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
i++
|
||||
}
|
||||
sb.WriteString("}")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (m *baseMap) Type() ref.Type {
|
||||
return MapType
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (m *baseMap) Value() interface{} {
|
||||
func (m *baseMap) Value() any {
|
||||
return m.value
|
||||
}
|
||||
|
||||
@ -498,7 +524,7 @@ func (a *stringMapAccessor) Iterator() traits.Iterator {
|
||||
}
|
||||
}
|
||||
|
||||
func newStringIfaceMapAccessor(adapter ref.TypeAdapter, mapVal map[string]interface{}) mapAccessor {
|
||||
func newStringIfaceMapAccessor(adapter ref.TypeAdapter, mapVal map[string]any) mapAccessor {
|
||||
return &stringIfaceMapAccessor{
|
||||
TypeAdapter: adapter,
|
||||
mapVal: mapVal,
|
||||
@ -507,7 +533,7 @@ func newStringIfaceMapAccessor(adapter ref.TypeAdapter, mapVal map[string]interf
|
||||
|
||||
type stringIfaceMapAccessor struct {
|
||||
ref.TypeAdapter
|
||||
mapVal map[string]interface{}
|
||||
mapVal map[string]any
|
||||
}
|
||||
|
||||
// Find uses native map accesses to find the key, returning (value, true) if present.
|
||||
@ -556,7 +582,7 @@ func (m *protoMap) Contains(key ref.Val) ref.Val {
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
//
|
||||
// Note, assignment to Golang struct types is not yet supported.
|
||||
func (m *protoMap) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (m *protoMap) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
// If the map is already assignable to the desired type return it, e.g. interfaces and
|
||||
// maps with the same key value types.
|
||||
switch typeDesc {
|
||||
@ -601,9 +627,9 @@ func (m *protoMap) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
m.value.Range(func(key protoreflect.MapKey, val protoreflect.Value) bool {
|
||||
ntvKey := key.Interface()
|
||||
ntvVal := val.Interface()
|
||||
switch ntvVal.(type) {
|
||||
switch pv := ntvVal.(type) {
|
||||
case protoreflect.Message:
|
||||
ntvVal = ntvVal.(protoreflect.Message).Interface()
|
||||
ntvVal = pv.Interface()
|
||||
}
|
||||
if keyType == otherKeyType && valType == otherValType {
|
||||
mapVal.SetMapIndex(reflect.ValueOf(ntvKey), reflect.ValueOf(ntvVal))
|
||||
@ -732,6 +758,11 @@ func (m *protoMap) Get(key ref.Val) ref.Val {
|
||||
return v
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the map is empty.
|
||||
func (m *protoMap) IsZeroValue() bool {
|
||||
return m.value.Len() == 0
|
||||
}
|
||||
|
||||
// Iterator implements the traits.Iterable interface method.
|
||||
func (m *protoMap) Iterator() traits.Iterator {
|
||||
// Copy the keys to make their order stable.
|
||||
@ -758,7 +789,7 @@ func (m *protoMap) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (m *protoMap) Value() interface{} {
|
||||
func (m *protoMap) Value() any {
|
||||
return m.value
|
||||
}
|
||||
|
||||
|
26
vendor/github.com/google/cel-go/common/types/null.go
generated
vendored
26
vendor/github.com/google/cel-go/common/types/null.go
generated
vendored
@ -18,9 +18,10 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
@ -34,14 +35,20 @@ var (
|
||||
// NullValue singleton.
|
||||
NullValue = Null(structpb.NullValue_NULL_VALUE)
|
||||
|
||||
jsonNullType = reflect.TypeOf(structpb.NullValue_NULL_VALUE)
|
||||
// golang reflect type for Null values.
|
||||
nullReflectType = reflect.TypeOf(NullValue)
|
||||
)
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (n Null) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (n Null) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Int32:
|
||||
return reflect.ValueOf(n).Convert(typeDesc).Interface(), nil
|
||||
switch typeDesc {
|
||||
case jsonNullType:
|
||||
return structpb.NullValue_NULL_VALUE, nil
|
||||
case nullReflectType:
|
||||
return n, nil
|
||||
}
|
||||
case reflect.Ptr:
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
@ -54,6 +61,10 @@ func (n Null) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
return anypb.New(pb.(proto.Message))
|
||||
case jsonValueType:
|
||||
return structpb.NewNullValue(), nil
|
||||
case boolWrapperType, byteWrapperType, doubleWrapperType, floatWrapperType,
|
||||
int32WrapperType, int64WrapperType, stringWrapperType, uint32WrapperType,
|
||||
uint64WrapperType:
|
||||
return nil, nil
|
||||
}
|
||||
case reflect.Interface:
|
||||
nv := n.Value()
|
||||
@ -86,12 +97,17 @@ func (n Null) Equal(other ref.Val) ref.Val {
|
||||
return Bool(NullType == other.Type())
|
||||
}
|
||||
|
||||
// IsZeroValue returns true as null always represents an absent value.
|
||||
func (n Null) IsZeroValue() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (n Null) Type() ref.Type {
|
||||
return NullType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (n Null) Value() interface{} {
|
||||
func (n Null) Value() any {
|
||||
return structpb.NullValue_NULL_VALUE
|
||||
}
|
||||
|
14
vendor/github.com/google/cel-go/common/types/object.go
generated
vendored
14
vendor/github.com/google/cel-go/common/types/object.go
generated
vendored
@ -18,11 +18,12 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/pb"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/google/cel-go/common/types/pb"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
@ -52,7 +53,7 @@ func NewObject(adapter ref.TypeAdapter,
|
||||
typeValue: typeValue}
|
||||
}
|
||||
|
||||
func (o *protoObj) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (o *protoObj) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
srcPB := o.value
|
||||
if reflect.TypeOf(srcPB).AssignableTo(typeDesc) {
|
||||
return srcPB, nil
|
||||
@ -133,6 +134,11 @@ func (o *protoObj) IsSet(field ref.Val) ref.Val {
|
||||
return False
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the protobuf object is empty.
|
||||
func (o *protoObj) IsZeroValue() bool {
|
||||
return proto.Equal(o.value, o.typeDesc.Zero())
|
||||
}
|
||||
|
||||
func (o *protoObj) Get(index ref.Val) ref.Val {
|
||||
protoFieldName, ok := index.(String)
|
||||
if !ok {
|
||||
@ -154,6 +160,6 @@ func (o *protoObj) Type() ref.Type {
|
||||
return o.typeValue
|
||||
}
|
||||
|
||||
func (o *protoObj) Value() interface{} {
|
||||
func (o *protoObj) Value() any {
|
||||
return o.value
|
||||
}
|
||||
|
108
vendor/github.com/google/cel-go/common/types/optional.go
generated
vendored
Normal file
108
vendor/github.com/google/cel-go/common/types/optional.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
// 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
|
||||
//
|
||||
// http://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 types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
var (
|
||||
// OptionalType indicates the runtime type of an optional value.
|
||||
OptionalType = NewTypeValue("optional")
|
||||
|
||||
// OptionalNone is a sentinel value which is used to indicate an empty optional value.
|
||||
OptionalNone = &Optional{}
|
||||
)
|
||||
|
||||
// OptionalOf returns an optional value which wraps a concrete CEL value.
|
||||
func OptionalOf(value ref.Val) *Optional {
|
||||
return &Optional{value: value}
|
||||
}
|
||||
|
||||
// Optional value which points to a value if non-empty.
|
||||
type Optional struct {
|
||||
value ref.Val
|
||||
}
|
||||
|
||||
// HasValue returns true if the optional has a value.
|
||||
func (o *Optional) HasValue() bool {
|
||||
return o.value != nil
|
||||
}
|
||||
|
||||
// GetValue returns the wrapped value contained in the optional.
|
||||
func (o *Optional) GetValue() ref.Val {
|
||||
if !o.HasValue() {
|
||||
return NewErr("optional.none() dereference")
|
||||
}
|
||||
return o.value
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (o *Optional) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
if !o.HasValue() {
|
||||
return nil, errors.New("optional.none() dereference")
|
||||
}
|
||||
return o.value.ConvertToNative(typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements the ref.Val interface method.
|
||||
func (o *Optional) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case OptionalType:
|
||||
return o
|
||||
case TypeType:
|
||||
return OptionalType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", OptionalType, typeVal)
|
||||
}
|
||||
|
||||
// Equal determines whether the values contained by two optional values are equal.
|
||||
func (o *Optional) Equal(other ref.Val) ref.Val {
|
||||
otherOpt, isOpt := other.(*Optional)
|
||||
if !isOpt {
|
||||
return False
|
||||
}
|
||||
if !o.HasValue() {
|
||||
return Bool(!otherOpt.HasValue())
|
||||
}
|
||||
if !otherOpt.HasValue() {
|
||||
return False
|
||||
}
|
||||
return o.value.Equal(otherOpt.value)
|
||||
}
|
||||
|
||||
func (o *Optional) String() string {
|
||||
if o.HasValue() {
|
||||
return fmt.Sprintf("optional(%v)", o.GetValue())
|
||||
}
|
||||
return "optional.none()"
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (o *Optional) Type() ref.Type {
|
||||
return OptionalType
|
||||
}
|
||||
|
||||
// Value returns the underlying 'Value()' of the wrapped value, if present.
|
||||
func (o *Optional) Value() any {
|
||||
if o.value == nil {
|
||||
return nil
|
||||
}
|
||||
return o.value.Value()
|
||||
}
|
2
vendor/github.com/google/cel-go/common/types/pb/BUILD.bazel
generated
vendored
2
vendor/github.com/google/cel-go/common/types/pb/BUILD.bazel
generated
vendored
@ -17,7 +17,7 @@ go_library(
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/types/pb",
|
||||
deps = [
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//encoding/protowire:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
|
||||
|
4
vendor/github.com/google/cel-go/common/types/pb/enum.go
generated
vendored
4
vendor/github.com/google/cel-go/common/types/pb/enum.go
generated
vendored
@ -18,9 +18,9 @@ import (
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// NewEnumValueDescription produces an enum value description with the fully qualified enum value
|
||||
// newEnumValueDescription produces an enum value description with the fully qualified enum value
|
||||
// name and the enum value descriptor.
|
||||
func NewEnumValueDescription(name string, desc protoreflect.EnumValueDescriptor) *EnumValueDescription {
|
||||
func newEnumValueDescription(name string, desc protoreflect.EnumValueDescriptor) *EnumValueDescription {
|
||||
return &EnumValueDescription{
|
||||
enumValueName: name,
|
||||
desc: desc,
|
||||
|
83
vendor/github.com/google/cel-go/common/types/pb/file.go
generated
vendored
83
vendor/github.com/google/cel-go/common/types/pb/file.go
generated
vendored
@ -18,32 +18,66 @@ import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
dynamicpb "google.golang.org/protobuf/types/dynamicpb"
|
||||
)
|
||||
|
||||
// NewFileDescription returns a FileDescription instance with a complete listing of all the message
|
||||
// types and enum values declared within any scope in the file.
|
||||
func NewFileDescription(fileDesc protoreflect.FileDescriptor, pbdb *Db) *FileDescription {
|
||||
// newFileDescription returns a FileDescription instance with a complete listing of all the message
|
||||
// types and enum values, as well as a map of extensions declared within any scope in the file.
|
||||
func newFileDescription(fileDesc protoreflect.FileDescriptor, pbdb *Db) (*FileDescription, extensionMap) {
|
||||
metadata := collectFileMetadata(fileDesc)
|
||||
enums := make(map[string]*EnumValueDescription)
|
||||
for name, enumVal := range metadata.enumValues {
|
||||
enums[name] = NewEnumValueDescription(name, enumVal)
|
||||
enums[name] = newEnumValueDescription(name, enumVal)
|
||||
}
|
||||
types := make(map[string]*TypeDescription)
|
||||
for name, msgType := range metadata.msgTypes {
|
||||
types[name] = NewTypeDescription(name, msgType)
|
||||
types[name] = newTypeDescription(name, msgType, pbdb.extensions)
|
||||
}
|
||||
fileExtMap := make(extensionMap)
|
||||
for typeName, extensions := range metadata.msgExtensionMap {
|
||||
messageExtMap, found := fileExtMap[typeName]
|
||||
if !found {
|
||||
messageExtMap = make(map[string]*FieldDescription)
|
||||
}
|
||||
for _, ext := range extensions {
|
||||
extDesc := dynamicpb.NewExtensionType(ext).TypeDescriptor()
|
||||
messageExtMap[string(ext.FullName())] = newFieldDescription(extDesc)
|
||||
}
|
||||
fileExtMap[typeName] = messageExtMap
|
||||
}
|
||||
return &FileDescription{
|
||||
name: fileDesc.Path(),
|
||||
types: types,
|
||||
enums: enums,
|
||||
}
|
||||
}, fileExtMap
|
||||
}
|
||||
|
||||
// FileDescription holds a map of all types and enum values declared within a proto file.
|
||||
type FileDescription struct {
|
||||
name string
|
||||
types map[string]*TypeDescription
|
||||
enums map[string]*EnumValueDescription
|
||||
}
|
||||
|
||||
// Copy creates a copy of the FileDescription with updated Db references within its types.
|
||||
func (fd *FileDescription) Copy(pbdb *Db) *FileDescription {
|
||||
typesCopy := make(map[string]*TypeDescription, len(fd.types))
|
||||
for k, v := range fd.types {
|
||||
typesCopy[k] = v.Copy(pbdb)
|
||||
}
|
||||
return &FileDescription{
|
||||
name: fd.name,
|
||||
types: typesCopy,
|
||||
enums: fd.enums,
|
||||
}
|
||||
}
|
||||
|
||||
// GetName returns the fully qualified file path for the file.
|
||||
func (fd *FileDescription) GetName() string {
|
||||
return fd.name
|
||||
}
|
||||
|
||||
// GetEnumDescription returns an EnumDescription for a qualified enum value
|
||||
// name declared within the .proto file.
|
||||
func (fd *FileDescription) GetEnumDescription(enumName string) (*EnumValueDescription, bool) {
|
||||
@ -94,6 +128,10 @@ type fileMetadata struct {
|
||||
msgTypes map[string]protoreflect.MessageDescriptor
|
||||
// enumValues maps from fully-qualified enum value to enum value descriptor.
|
||||
enumValues map[string]protoreflect.EnumValueDescriptor
|
||||
// msgExtensionMap maps from the protobuf message name being extended to a set of extensions
|
||||
// for the type.
|
||||
msgExtensionMap map[string][]protoreflect.ExtensionDescriptor
|
||||
|
||||
// TODO: support enum type definitions for use in future type-check enhancements.
|
||||
}
|
||||
|
||||
@ -102,28 +140,38 @@ type fileMetadata struct {
|
||||
func collectFileMetadata(fileDesc protoreflect.FileDescriptor) *fileMetadata {
|
||||
msgTypes := make(map[string]protoreflect.MessageDescriptor)
|
||||
enumValues := make(map[string]protoreflect.EnumValueDescriptor)
|
||||
collectMsgTypes(fileDesc.Messages(), msgTypes, enumValues)
|
||||
msgExtensionMap := make(map[string][]protoreflect.ExtensionDescriptor)
|
||||
collectMsgTypes(fileDesc.Messages(), msgTypes, enumValues, msgExtensionMap)
|
||||
collectEnumValues(fileDesc.Enums(), enumValues)
|
||||
collectExtensions(fileDesc.Extensions(), msgExtensionMap)
|
||||
return &fileMetadata{
|
||||
msgTypes: msgTypes,
|
||||
enumValues: enumValues,
|
||||
msgTypes: msgTypes,
|
||||
enumValues: enumValues,
|
||||
msgExtensionMap: msgExtensionMap,
|
||||
}
|
||||
}
|
||||
|
||||
// collectMsgTypes recursively collects messages, nested messages, and nested enums into a map of
|
||||
// fully qualified protobuf names to descriptors.
|
||||
func collectMsgTypes(msgTypes protoreflect.MessageDescriptors, msgTypeMap map[string]protoreflect.MessageDescriptor, enumValueMap map[string]protoreflect.EnumValueDescriptor) {
|
||||
func collectMsgTypes(msgTypes protoreflect.MessageDescriptors,
|
||||
msgTypeMap map[string]protoreflect.MessageDescriptor,
|
||||
enumValueMap map[string]protoreflect.EnumValueDescriptor,
|
||||
msgExtensionMap map[string][]protoreflect.ExtensionDescriptor) {
|
||||
for i := 0; i < msgTypes.Len(); i++ {
|
||||
msgType := msgTypes.Get(i)
|
||||
msgTypeMap[string(msgType.FullName())] = msgType
|
||||
nestedMsgTypes := msgType.Messages()
|
||||
if nestedMsgTypes.Len() != 0 {
|
||||
collectMsgTypes(nestedMsgTypes, msgTypeMap, enumValueMap)
|
||||
collectMsgTypes(nestedMsgTypes, msgTypeMap, enumValueMap, msgExtensionMap)
|
||||
}
|
||||
nestedEnumTypes := msgType.Enums()
|
||||
if nestedEnumTypes.Len() != 0 {
|
||||
collectEnumValues(nestedEnumTypes, enumValueMap)
|
||||
}
|
||||
nestedExtensions := msgType.Extensions()
|
||||
if nestedExtensions.Len() != 0 {
|
||||
collectExtensions(nestedExtensions, msgExtensionMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,3 +187,16 @@ func collectEnumValues(enumTypes protoreflect.EnumDescriptors, enumValueMap map[
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func collectExtensions(extensions protoreflect.ExtensionDescriptors, msgExtensionMap map[string][]protoreflect.ExtensionDescriptor) {
|
||||
for i := 0; i < extensions.Len(); i++ {
|
||||
ext := extensions.Get(i)
|
||||
extendsMsg := string(ext.ContainingMessage().FullName())
|
||||
msgExts, found := msgExtensionMap[extendsMsg]
|
||||
if !found {
|
||||
msgExts = []protoreflect.ExtensionDescriptor{}
|
||||
}
|
||||
msgExts = append(msgExts, ext)
|
||||
msgExtensionMap[extendsMsg] = msgExts
|
||||
}
|
||||
}
|
||||
|
53
vendor/github.com/google/cel-go/common/types/pb/pb.go
generated
vendored
53
vendor/github.com/google/cel-go/common/types/pb/pb.go
generated
vendored
@ -40,13 +40,19 @@ type Db struct {
|
||||
revFileDescriptorMap map[string]*FileDescription
|
||||
// files contains the deduped set of FileDescriptions whose types are contained in the pb.Db.
|
||||
files []*FileDescription
|
||||
// extensions contains the mapping between a given type name, extension name and its FieldDescription
|
||||
extensions map[string]map[string]*FieldDescription
|
||||
}
|
||||
|
||||
// extensionsMap is a type alias to a map[typeName]map[extensionName]*FieldDescription
|
||||
type extensionMap = map[string]map[string]*FieldDescription
|
||||
|
||||
var (
|
||||
// DefaultDb used at evaluation time or unless overridden at check time.
|
||||
DefaultDb = &Db{
|
||||
revFileDescriptorMap: make(map[string]*FileDescription),
|
||||
files: []*FileDescription{},
|
||||
extensions: make(extensionMap),
|
||||
}
|
||||
)
|
||||
|
||||
@ -80,6 +86,7 @@ func NewDb() *Db {
|
||||
pbdb := &Db{
|
||||
revFileDescriptorMap: make(map[string]*FileDescription),
|
||||
files: []*FileDescription{},
|
||||
extensions: make(extensionMap),
|
||||
}
|
||||
// The FileDescription objects in the default db contain lazily initialized TypeDescription
|
||||
// values which may point to the state contained in the DefaultDb irrespective of this shallow
|
||||
@ -96,19 +103,34 @@ func NewDb() *Db {
|
||||
// Copy creates a copy of the current database with its own internal descriptor mapping.
|
||||
func (pbdb *Db) Copy() *Db {
|
||||
copy := NewDb()
|
||||
for k, v := range pbdb.revFileDescriptorMap {
|
||||
copy.revFileDescriptorMap[k] = v
|
||||
}
|
||||
for _, f := range pbdb.files {
|
||||
for _, fd := range pbdb.files {
|
||||
hasFile := false
|
||||
for _, f2 := range copy.files {
|
||||
if f2 == f {
|
||||
for _, fd2 := range copy.files {
|
||||
if fd2 == fd {
|
||||
hasFile = true
|
||||
}
|
||||
}
|
||||
if !hasFile {
|
||||
copy.files = append(copy.files, f)
|
||||
fd = fd.Copy(copy)
|
||||
copy.files = append(copy.files, fd)
|
||||
}
|
||||
for _, enumValName := range fd.GetEnumNames() {
|
||||
copy.revFileDescriptorMap[enumValName] = fd
|
||||
}
|
||||
for _, msgTypeName := range fd.GetTypeNames() {
|
||||
copy.revFileDescriptorMap[msgTypeName] = fd
|
||||
}
|
||||
copy.revFileDescriptorMap[fd.GetName()] = fd
|
||||
}
|
||||
for typeName, extFieldMap := range pbdb.extensions {
|
||||
copyExtFieldMap, found := copy.extensions[typeName]
|
||||
if !found {
|
||||
copyExtFieldMap = make(map[string]*FieldDescription, len(extFieldMap))
|
||||
}
|
||||
for extFieldName, fd := range extFieldMap {
|
||||
copyExtFieldMap[extFieldName] = fd
|
||||
}
|
||||
copy.extensions[typeName] = copyExtFieldMap
|
||||
}
|
||||
return copy
|
||||
}
|
||||
@ -137,17 +159,30 @@ func (pbdb *Db) RegisterDescriptor(fileDesc protoreflect.FileDescriptor) (*FileD
|
||||
if err == nil {
|
||||
fileDesc = globalFD
|
||||
}
|
||||
fd = NewFileDescription(fileDesc, pbdb)
|
||||
var fileExtMap extensionMap
|
||||
fd, fileExtMap = newFileDescription(fileDesc, pbdb)
|
||||
for _, enumValName := range fd.GetEnumNames() {
|
||||
pbdb.revFileDescriptorMap[enumValName] = fd
|
||||
}
|
||||
for _, msgTypeName := range fd.GetTypeNames() {
|
||||
pbdb.revFileDescriptorMap[msgTypeName] = fd
|
||||
}
|
||||
pbdb.revFileDescriptorMap[fileDesc.Path()] = fd
|
||||
pbdb.revFileDescriptorMap[fd.GetName()] = fd
|
||||
|
||||
// Return the specific file descriptor registered.
|
||||
pbdb.files = append(pbdb.files, fd)
|
||||
|
||||
// Index the protobuf message extensions from the file into the pbdb
|
||||
for typeName, extMap := range fileExtMap {
|
||||
typeExtMap, found := pbdb.extensions[typeName]
|
||||
if !found {
|
||||
pbdb.extensions[typeName] = extMap
|
||||
continue
|
||||
}
|
||||
for extName, field := range extMap {
|
||||
typeExtMap[extName] = field
|
||||
}
|
||||
}
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
|
66
vendor/github.com/google/cel-go/common/types/pb/type.go
generated
vendored
66
vendor/github.com/google/cel-go/common/types/pb/type.go
generated
vendored
@ -38,22 +38,23 @@ type description interface {
|
||||
Zero() proto.Message
|
||||
}
|
||||
|
||||
// NewTypeDescription produces a TypeDescription value for the fully-qualified proto type name
|
||||
// newTypeDescription produces a TypeDescription value for the fully-qualified proto type name
|
||||
// with a given descriptor.
|
||||
func NewTypeDescription(typeName string, desc protoreflect.MessageDescriptor) *TypeDescription {
|
||||
func newTypeDescription(typeName string, desc protoreflect.MessageDescriptor, extensions extensionMap) *TypeDescription {
|
||||
msgType := dynamicpb.NewMessageType(desc)
|
||||
msgZero := dynamicpb.NewMessage(desc)
|
||||
fieldMap := map[string]*FieldDescription{}
|
||||
fields := desc.Fields()
|
||||
for i := 0; i < fields.Len(); i++ {
|
||||
f := fields.Get(i)
|
||||
fieldMap[string(f.Name())] = NewFieldDescription(f)
|
||||
fieldMap[string(f.Name())] = newFieldDescription(f)
|
||||
}
|
||||
return &TypeDescription{
|
||||
typeName: typeName,
|
||||
desc: desc,
|
||||
msgType: msgType,
|
||||
fieldMap: fieldMap,
|
||||
extensions: extensions,
|
||||
reflectType: reflectTypeOf(msgZero),
|
||||
zeroMsg: zeroValueOf(msgZero),
|
||||
}
|
||||
@ -66,10 +67,24 @@ type TypeDescription struct {
|
||||
desc protoreflect.MessageDescriptor
|
||||
msgType protoreflect.MessageType
|
||||
fieldMap map[string]*FieldDescription
|
||||
extensions extensionMap
|
||||
reflectType reflect.Type
|
||||
zeroMsg proto.Message
|
||||
}
|
||||
|
||||
// Copy copies the type description with updated references to the Db.
|
||||
func (td *TypeDescription) Copy(pbdb *Db) *TypeDescription {
|
||||
return &TypeDescription{
|
||||
typeName: td.typeName,
|
||||
desc: td.desc,
|
||||
msgType: td.msgType,
|
||||
fieldMap: td.fieldMap,
|
||||
extensions: pbdb.extensions,
|
||||
reflectType: td.reflectType,
|
||||
zeroMsg: td.zeroMsg,
|
||||
}
|
||||
}
|
||||
|
||||
// FieldMap returns a string field name to FieldDescription map.
|
||||
func (td *TypeDescription) FieldMap() map[string]*FieldDescription {
|
||||
return td.fieldMap
|
||||
@ -78,16 +93,21 @@ func (td *TypeDescription) FieldMap() map[string]*FieldDescription {
|
||||
// FieldByName returns (FieldDescription, true) if the field name is declared within the type.
|
||||
func (td *TypeDescription) FieldByName(name string) (*FieldDescription, bool) {
|
||||
fd, found := td.fieldMap[name]
|
||||
if found {
|
||||
return fd, true
|
||||
}
|
||||
extFieldMap, found := td.extensions[td.typeName]
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
return fd, true
|
||||
fd, found = extFieldMap[name]
|
||||
return fd, found
|
||||
}
|
||||
|
||||
// MaybeUnwrap accepts a proto message as input and unwraps it to a primitive CEL type if possible.
|
||||
//
|
||||
// This method returns the unwrapped value and 'true', else the original value and 'false'.
|
||||
func (td *TypeDescription) MaybeUnwrap(msg proto.Message) (interface{}, bool, error) {
|
||||
func (td *TypeDescription) MaybeUnwrap(msg proto.Message) (any, bool, error) {
|
||||
return unwrap(td, msg)
|
||||
}
|
||||
|
||||
@ -111,8 +131,8 @@ func (td *TypeDescription) Zero() proto.Message {
|
||||
return td.zeroMsg
|
||||
}
|
||||
|
||||
// NewFieldDescription creates a new field description from a protoreflect.FieldDescriptor.
|
||||
func NewFieldDescription(fieldDesc protoreflect.FieldDescriptor) *FieldDescription {
|
||||
// newFieldDescription creates a new field description from a protoreflect.FieldDescriptor.
|
||||
func newFieldDescription(fieldDesc protoreflect.FieldDescriptor) *FieldDescription {
|
||||
var reflectType reflect.Type
|
||||
var zeroMsg proto.Message
|
||||
switch fieldDesc.Kind() {
|
||||
@ -124,9 +144,17 @@ func NewFieldDescription(fieldDesc protoreflect.FieldDescriptor) *FieldDescripti
|
||||
default:
|
||||
reflectType = reflectTypeOf(fieldDesc.Default().Interface())
|
||||
if fieldDesc.IsList() {
|
||||
parentMsg := dynamicpb.NewMessage(fieldDesc.ContainingMessage())
|
||||
listField := parentMsg.NewField(fieldDesc).List()
|
||||
elem := listField.NewElement().Interface()
|
||||
var elemValue protoreflect.Value
|
||||
if fieldDesc.IsExtension() {
|
||||
et := dynamicpb.NewExtensionType(fieldDesc)
|
||||
elemValue = et.New().List().NewElement()
|
||||
} else {
|
||||
parentMsgType := fieldDesc.ContainingMessage()
|
||||
parentMsg := dynamicpb.NewMessage(parentMsgType)
|
||||
listField := parentMsg.NewField(fieldDesc).List()
|
||||
elemValue = listField.NewElement()
|
||||
}
|
||||
elem := elemValue.Interface()
|
||||
switch elemType := elem.(type) {
|
||||
case protoreflect.Message:
|
||||
elem = elemType.Interface()
|
||||
@ -140,8 +168,8 @@ func NewFieldDescription(fieldDesc protoreflect.FieldDescriptor) *FieldDescripti
|
||||
}
|
||||
var keyType, valType *FieldDescription
|
||||
if fieldDesc.IsMap() {
|
||||
keyType = NewFieldDescription(fieldDesc.MapKey())
|
||||
valType = NewFieldDescription(fieldDesc.MapValue())
|
||||
keyType = newFieldDescription(fieldDesc.MapKey())
|
||||
valType = newFieldDescription(fieldDesc.MapValue())
|
||||
}
|
||||
return &FieldDescription{
|
||||
desc: fieldDesc,
|
||||
@ -195,7 +223,7 @@ func (fd *FieldDescription) Descriptor() protoreflect.FieldDescriptor {
|
||||
//
|
||||
// This function implements the FieldType.IsSet function contract which can be used to operate on
|
||||
// more than just protobuf field accesses; however, the target here must be a protobuf.Message.
|
||||
func (fd *FieldDescription) IsSet(target interface{}) bool {
|
||||
func (fd *FieldDescription) IsSet(target any) bool {
|
||||
switch v := target.(type) {
|
||||
case proto.Message:
|
||||
pbRef := v.ProtoReflect()
|
||||
@ -219,14 +247,14 @@ func (fd *FieldDescription) IsSet(target interface{}) bool {
|
||||
//
|
||||
// This function implements the FieldType.GetFrom function contract which can be used to operate
|
||||
// on more than just protobuf field accesses; however, the target here must be a protobuf.Message.
|
||||
func (fd *FieldDescription) GetFrom(target interface{}) (interface{}, error) {
|
||||
func (fd *FieldDescription) GetFrom(target any) (any, error) {
|
||||
v, ok := target.(proto.Message)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported field selection target: (%T)%v", target, target)
|
||||
}
|
||||
pbRef := v.ProtoReflect()
|
||||
pbDesc := pbRef.Descriptor()
|
||||
var fieldVal interface{}
|
||||
var fieldVal any
|
||||
if pbDesc == fd.desc.ContainingMessage() {
|
||||
// When the target protobuf shares the same message descriptor instance as the field
|
||||
// descriptor, use the cached field descriptor value.
|
||||
@ -289,7 +317,7 @@ func (fd *FieldDescription) IsList() bool {
|
||||
//
|
||||
// This function returns the unwrapped value and 'true' on success, or the original value
|
||||
// and 'false' otherwise.
|
||||
func (fd *FieldDescription) MaybeUnwrapDynamic(msg protoreflect.Message) (interface{}, bool, error) {
|
||||
func (fd *FieldDescription) MaybeUnwrapDynamic(msg protoreflect.Message) (any, bool, error) {
|
||||
return unwrapDynamic(fd, msg)
|
||||
}
|
||||
|
||||
@ -362,7 +390,7 @@ func checkedWrap(t *exprpb.Type) *exprpb.Type {
|
||||
// input message is a *dynamicpb.Message which obscures the typing information from Go.
|
||||
//
|
||||
// Returns the unwrapped value and 'true' if unwrapped, otherwise the input value and 'false'.
|
||||
func unwrap(desc description, msg proto.Message) (interface{}, bool, error) {
|
||||
func unwrap(desc description, msg proto.Message) (any, bool, error) {
|
||||
switch v := msg.(type) {
|
||||
case *anypb.Any:
|
||||
dynMsg, err := v.UnmarshalNew()
|
||||
@ -418,7 +446,7 @@ func unwrap(desc description, msg proto.Message) (interface{}, bool, error) {
|
||||
// unwrapDynamic unwraps a reflected protobuf Message value.
|
||||
//
|
||||
// Returns the unwrapped value and 'true' if unwrapped, otherwise the input value and 'false'.
|
||||
func unwrapDynamic(desc description, refMsg protoreflect.Message) (interface{}, bool, error) {
|
||||
func unwrapDynamic(desc description, refMsg protoreflect.Message) (any, bool, error) {
|
||||
msg := refMsg.Interface()
|
||||
if !refMsg.IsValid() {
|
||||
msg = desc.Zero()
|
||||
@ -508,7 +536,7 @@ func unwrapDynamic(desc description, refMsg protoreflect.Message) (interface{},
|
||||
|
||||
// reflectTypeOf intercepts the reflect.Type call to ensure that dynamicpb.Message types preserve
|
||||
// well-known protobuf reflected types expected by the CEL type system.
|
||||
func reflectTypeOf(val interface{}) reflect.Type {
|
||||
func reflectTypeOf(val any) reflect.Type {
|
||||
switch v := val.(type) {
|
||||
case proto.Message:
|
||||
return reflect.TypeOf(zeroValueOf(v))
|
||||
|
30
vendor/github.com/google/cel-go/common/types/provider.go
generated
vendored
30
vendor/github.com/google/cel-go/common/types/provider.go
generated
vendored
@ -19,11 +19,12 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/pb"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
@ -195,7 +196,7 @@ func (p *protoTypeRegistry) RegisterType(types ...ref.Type) error {
|
||||
// providing support for custom proto-based types.
|
||||
//
|
||||
// This method should be the inverse of ref.Val.ConvertToNative.
|
||||
func (p *protoTypeRegistry) NativeToValue(value interface{}) ref.Val {
|
||||
func (p *protoTypeRegistry) NativeToValue(value any) ref.Val {
|
||||
if val, found := nativeToValue(p, value); found {
|
||||
return val
|
||||
}
|
||||
@ -249,7 +250,7 @@ var (
|
||||
)
|
||||
|
||||
// NativeToValue implements the ref.TypeAdapter interface.
|
||||
func (a *defaultTypeAdapter) NativeToValue(value interface{}) ref.Val {
|
||||
func (a *defaultTypeAdapter) NativeToValue(value any) ref.Val {
|
||||
if val, found := nativeToValue(a, value); found {
|
||||
return val
|
||||
}
|
||||
@ -258,7 +259,7 @@ func (a *defaultTypeAdapter) NativeToValue(value interface{}) ref.Val {
|
||||
|
||||
// nativeToValue returns the converted (ref.Val, true) of a conversion is found,
|
||||
// otherwise (nil, false)
|
||||
func nativeToValue(a ref.TypeAdapter, value interface{}) (ref.Val, bool) {
|
||||
func nativeToValue(a ref.TypeAdapter, value any) (ref.Val, bool) {
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
return NullValue, true
|
||||
@ -364,7 +365,7 @@ func nativeToValue(a ref.TypeAdapter, value interface{}) (ref.Val, bool) {
|
||||
// specializations for common map types.
|
||||
case map[string]string:
|
||||
return NewStringStringMap(a, v), true
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
return NewStringInterfaceMap(a, v), true
|
||||
case map[ref.Val]ref.Val:
|
||||
return NewRefValMap(a, v), true
|
||||
@ -479,9 +480,12 @@ func msgSetField(target protoreflect.Message, field *pb.FieldDescription, val re
|
||||
if err != nil {
|
||||
return fieldTypeConversionError(field, err)
|
||||
}
|
||||
switch v.(type) {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
switch pv := v.(type) {
|
||||
case proto.Message:
|
||||
v = v.(proto.Message).ProtoReflect()
|
||||
v = pv.ProtoReflect()
|
||||
}
|
||||
target.Set(field.Descriptor(), protoreflect.ValueOf(v))
|
||||
return nil
|
||||
@ -495,6 +499,9 @@ func msgSetListField(target protoreflect.List, listField *pb.FieldDescription, l
|
||||
if err != nil {
|
||||
return fieldTypeConversionError(listField, err)
|
||||
}
|
||||
if elemVal == nil {
|
||||
continue
|
||||
}
|
||||
switch ev := elemVal.(type) {
|
||||
case proto.Message:
|
||||
elemVal = ev.ProtoReflect()
|
||||
@ -519,9 +526,12 @@ func msgSetMapField(target protoreflect.Map, mapField *pb.FieldDescription, mapV
|
||||
if err != nil {
|
||||
return fieldTypeConversionError(mapField, err)
|
||||
}
|
||||
switch v.(type) {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
switch pv := v.(type) {
|
||||
case proto.Message:
|
||||
v = v.(proto.Message).ProtoReflect()
|
||||
v = pv.ProtoReflect()
|
||||
}
|
||||
target.Set(protoreflect.ValueOf(k).MapKey(), protoreflect.ValueOf(v))
|
||||
}
|
||||
|
2
vendor/github.com/google/cel-go/common/types/ref/BUILD.bazel
generated
vendored
2
vendor/github.com/google/cel-go/common/types/ref/BUILD.bazel
generated
vendored
@ -13,7 +13,7 @@ go_library(
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/types/ref",
|
||||
deps = [
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
|
||||
],
|
||||
|
8
vendor/github.com/google/cel-go/common/types/ref/provider.go
generated
vendored
8
vendor/github.com/google/cel-go/common/types/ref/provider.go
generated
vendored
@ -39,8 +39,6 @@ type TypeProvider interface {
|
||||
|
||||
// FieldFieldType returns the field type for a checked type value. Returns
|
||||
// false if the field could not be found.
|
||||
//
|
||||
// Used during type-checking only.
|
||||
FindFieldType(messageType string, fieldName string) (*FieldType, bool)
|
||||
|
||||
// NewValue creates a new type value from a qualified name and map of field
|
||||
@ -55,7 +53,7 @@ type TypeProvider interface {
|
||||
// TypeAdapter converts native Go values of varying type and complexity to equivalent CEL values.
|
||||
type TypeAdapter interface {
|
||||
// NativeToValue converts the input `value` to a CEL `ref.Val`.
|
||||
NativeToValue(value interface{}) Val
|
||||
NativeToValue(value any) Val
|
||||
}
|
||||
|
||||
// TypeRegistry allows third-parties to add custom types to CEL. Not all `TypeProvider`
|
||||
@ -97,7 +95,7 @@ type FieldType struct {
|
||||
}
|
||||
|
||||
// FieldTester is used to test field presence on an input object.
|
||||
type FieldTester func(target interface{}) bool
|
||||
type FieldTester func(target any) bool
|
||||
|
||||
// FieldGetter is used to get the field value from an input object, if set.
|
||||
type FieldGetter func(target interface{}) (interface{}, error)
|
||||
type FieldGetter func(target any) (any, error)
|
||||
|
15
vendor/github.com/google/cel-go/common/types/ref/reference.go
generated
vendored
15
vendor/github.com/google/cel-go/common/types/ref/reference.go
generated
vendored
@ -37,9 +37,18 @@ type Type interface {
|
||||
type Val interface {
|
||||
// ConvertToNative converts the Value to a native Go struct according to the
|
||||
// reflected type description, or error if the conversion is not feasible.
|
||||
ConvertToNative(typeDesc reflect.Type) (interface{}, error)
|
||||
//
|
||||
// The ConvertToNative method is intended to be used to support conversion between CEL types
|
||||
// and native types during object creation expressions or by clients who need to adapt the,
|
||||
// returned CEL value into an equivalent Go value instance.
|
||||
//
|
||||
// When implementing or using ConvertToNative, the following guidelines apply:
|
||||
// - Use ConvertToNative when marshalling CEL evaluation results to native types.
|
||||
// - Do not use ConvertToNative within CEL extension functions.
|
||||
// - Document whether your implementation supports non-CEL field types, such as Go or Protobuf.
|
||||
ConvertToNative(typeDesc reflect.Type) (any, error)
|
||||
|
||||
// ConvertToType supports type conversions between value types supported by the expression language.
|
||||
// ConvertToType supports type conversions between CEL value types supported by the expression language.
|
||||
ConvertToType(typeValue Type) Val
|
||||
|
||||
// Equal returns true if the `other` value has the same type and content as the implementing struct.
|
||||
@ -50,5 +59,5 @@ type Val interface {
|
||||
|
||||
// Value returns the raw value of the instance which may not be directly compatible with the expression
|
||||
// language types.
|
||||
Value() interface{}
|
||||
Value() any
|
||||
}
|
||||
|
9
vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
9
vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
@ -72,7 +72,7 @@ func (s String) Compare(other ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (s String) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (s String) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.String:
|
||||
if reflect.TypeOf(s).AssignableTo(typeDesc) {
|
||||
@ -154,6 +154,11 @@ func (s String) Equal(other ref.Val) ref.Val {
|
||||
return Bool(ok && s == otherString)
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the string is empty.
|
||||
func (s String) IsZeroValue() bool {
|
||||
return len(s) == 0
|
||||
}
|
||||
|
||||
// Match implements traits.Matcher.Match.
|
||||
func (s String) Match(pattern ref.Val) ref.Val {
|
||||
pat, ok := pattern.(String)
|
||||
@ -189,7 +194,7 @@ func (s String) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (s String) Value() interface{} {
|
||||
func (s String) Value() any {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
|
19
vendor/github.com/google/cel-go/common/types/timestamp.go
generated
vendored
19
vendor/github.com/google/cel-go/common/types/timestamp.go
generated
vendored
@ -89,7 +89,7 @@ func (t Timestamp) Compare(other ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (t Timestamp) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (t Timestamp) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
// If the timestamp is already assignable to the desired type return it.
|
||||
if reflect.TypeOf(t.Time).AssignableTo(typeDesc) {
|
||||
return t.Time, nil
|
||||
@ -138,6 +138,11 @@ func (t Timestamp) Equal(other ref.Val) ref.Val {
|
||||
return Bool(ok && t.Time.Equal(otherTime.Time))
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the timestamp is epoch 0.
|
||||
func (t Timestamp) IsZeroValue() bool {
|
||||
return t.IsZero()
|
||||
}
|
||||
|
||||
// Receive implements traits.Receiver.Receive.
|
||||
func (t Timestamp) Receive(function string, overload string, args []ref.Val) ref.Val {
|
||||
switch len(args) {
|
||||
@ -160,14 +165,14 @@ func (t Timestamp) Subtract(subtrahend ref.Val) ref.Val {
|
||||
dur := subtrahend.(Duration)
|
||||
val, err := subtractTimeDurationChecked(t.Time, dur.Duration)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return timestampOf(val)
|
||||
case TimestampType:
|
||||
t2 := subtrahend.(Timestamp).Time
|
||||
val, err := subtractTimeChecked(t.Time, t2)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return durationOf(val)
|
||||
}
|
||||
@ -180,7 +185,7 @@ func (t Timestamp) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (t Timestamp) Value() interface{} {
|
||||
func (t Timestamp) Value() any {
|
||||
return t.Time
|
||||
}
|
||||
|
||||
@ -288,7 +293,7 @@ func timeZone(tz ref.Val, visitor timestampVisitor) timestampVisitor {
|
||||
if ind == -1 {
|
||||
loc, err := time.LoadLocation(val)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return visitor(t.In(loc))
|
||||
}
|
||||
@ -297,11 +302,11 @@ func timeZone(tz ref.Val, visitor timestampVisitor) timestampVisitor {
|
||||
// in the format ^(+|-)(0[0-9]|1[0-4]):[0-5][0-9]$. The numerical input is parsed in terms of hours and minutes.
|
||||
hr, err := strconv.Atoi(string(val[0:ind]))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
min, err := strconv.Atoi(string(val[ind+1:]))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
var offset int
|
||||
if string(val[0]) == "-" {
|
||||
|
1
vendor/github.com/google/cel-go/common/types/traits/BUILD.bazel
generated
vendored
1
vendor/github.com/google/cel-go/common/types/traits/BUILD.bazel
generated
vendored
@ -20,6 +20,7 @@ go_library(
|
||||
"receiver.go",
|
||||
"sizer.go",
|
||||
"traits.go",
|
||||
"zeroer.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/types/traits",
|
||||
deps = [
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2020 Google LLC
|
||||
// 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.
|
||||
@ -12,24 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package interpreter
|
||||
package traits
|
||||
|
||||
import "math"
|
||||
|
||||
// TODO: remove Coster.
|
||||
|
||||
// Coster calculates the heuristic cost incurred during evaluation.
|
||||
// Deprecated: Please migrate cel.EstimateCost, it supports length estimates for input data and cost estimates for
|
||||
// extension functions.
|
||||
type Coster interface {
|
||||
Cost() (min, max int64)
|
||||
}
|
||||
|
||||
// estimateCost returns the heuristic cost interval for the program.
|
||||
func estimateCost(i interface{}) (min, max int64) {
|
||||
c, ok := i.(Coster)
|
||||
if !ok {
|
||||
return 0, math.MaxInt64
|
||||
}
|
||||
return c.Cost()
|
||||
// Zeroer interface for testing whether a CEL value is a zero value for its type.
|
||||
type Zeroer interface {
|
||||
// IsZeroValue indicates whether the object is the zero value for the type.
|
||||
IsZeroValue() bool
|
||||
}
|
4
vendor/github.com/google/cel-go/common/types/type.go
generated
vendored
4
vendor/github.com/google/cel-go/common/types/type.go
generated
vendored
@ -53,7 +53,7 @@ func NewObjectTypeValue(name string) *TypeValue {
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (t *TypeValue) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (t *TypeValue) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
// TODO: replace the internal type representation with a proto-value.
|
||||
return nil, fmt.Errorf("type conversion not supported for 'type'")
|
||||
}
|
||||
@ -97,6 +97,6 @@ func (t *TypeValue) TypeName() string {
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (t *TypeValue) Value() interface{} {
|
||||
func (t *TypeValue) Value() any {
|
||||
return t.name
|
||||
}
|
||||
|
21
vendor/github.com/google/cel-go/common/types/uint.go
generated
vendored
21
vendor/github.com/google/cel-go/common/types/uint.go
generated
vendored
@ -59,7 +59,7 @@ func (i Uint) Add(other ref.Val) ref.Val {
|
||||
}
|
||||
val, err := addUint64Checked(uint64(i), uint64(otherUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Uint(val)
|
||||
}
|
||||
@ -82,7 +82,7 @@ func (i Uint) Compare(other ref.Val) ref.Val {
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (i Uint) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (i Uint) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Uint, reflect.Uint32:
|
||||
v, err := uint64ToUint32Checked(uint64(i))
|
||||
@ -149,7 +149,7 @@ func (i Uint) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
case IntType:
|
||||
v, err := uint64ToInt64Checked(uint64(i))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Int(v)
|
||||
case UintType:
|
||||
@ -172,7 +172,7 @@ func (i Uint) Divide(other ref.Val) ref.Val {
|
||||
}
|
||||
div, err := divideUint64Checked(uint64(i), uint64(otherUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Uint(div)
|
||||
}
|
||||
@ -194,6 +194,11 @@ func (i Uint) Equal(other ref.Val) ref.Val {
|
||||
}
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the uint is zero.
|
||||
func (i Uint) IsZeroValue() bool {
|
||||
return i == 0
|
||||
}
|
||||
|
||||
// Modulo implements traits.Modder.Modulo.
|
||||
func (i Uint) Modulo(other ref.Val) ref.Val {
|
||||
otherUint, ok := other.(Uint)
|
||||
@ -202,7 +207,7 @@ func (i Uint) Modulo(other ref.Val) ref.Val {
|
||||
}
|
||||
mod, err := moduloUint64Checked(uint64(i), uint64(otherUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Uint(mod)
|
||||
}
|
||||
@ -215,7 +220,7 @@ func (i Uint) Multiply(other ref.Val) ref.Val {
|
||||
}
|
||||
val, err := multiplyUint64Checked(uint64(i), uint64(otherUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Uint(val)
|
||||
}
|
||||
@ -228,7 +233,7 @@ func (i Uint) Subtract(subtrahend ref.Val) ref.Val {
|
||||
}
|
||||
val, err := subtractUint64Checked(uint64(i), uint64(subtraUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
return WrapErr(err)
|
||||
}
|
||||
return Uint(val)
|
||||
}
|
||||
@ -239,7 +244,7 @@ func (i Uint) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (i Uint) Value() interface{} {
|
||||
func (i Uint) Value() any {
|
||||
return uint64(i)
|
||||
}
|
||||
|
||||
|
4
vendor/github.com/google/cel-go/common/types/unknown.go
generated
vendored
4
vendor/github.com/google/cel-go/common/types/unknown.go
generated
vendored
@ -30,7 +30,7 @@ var (
|
||||
)
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (u Unknown) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
func (u Unknown) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
return u.Value(), nil
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ func (u Unknown) Type() ref.Type {
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (u Unknown) Value() interface{} {
|
||||
func (u Unknown) Value() any {
|
||||
return []int64(u)
|
||||
}
|
||||
|
||||
|
32
vendor/github.com/google/cel-go/ext/BUILD.bazel
generated
vendored
32
vendor/github.com/google/cel-go/ext/BUILD.bazel
generated
vendored
@ -9,14 +9,30 @@ go_library(
|
||||
srcs = [
|
||||
"encoders.go",
|
||||
"guards.go",
|
||||
"math.go",
|
||||
"native.go",
|
||||
"protos.go",
|
||||
"sets.go",
|
||||
"strings.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/ext",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cel:go_default_library",
|
||||
"//checker/decls:go_default_library",
|
||||
"//common:go_default_library",
|
||||
"//common/overloads:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/pb:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"//common/types/traits:go_default_library",
|
||||
"//interpreter:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb",
|
||||
"@org_golang_x_text//language:go_default_library",
|
||||
"@org_golang_x_text//message:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -25,6 +41,10 @@ go_test(
|
||||
size = "small",
|
||||
srcs = [
|
||||
"encoders_test.go",
|
||||
"math_test.go",
|
||||
"native_test.go",
|
||||
"protos_test.go",
|
||||
"sets_test.go",
|
||||
"strings_test.go",
|
||||
],
|
||||
embed = [
|
||||
@ -32,5 +52,17 @@ go_test(
|
||||
],
|
||||
deps = [
|
||||
"//cel:go_default_library",
|
||||
"//checker:go_default_library",
|
||||
"//common:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"//common/types/traits:go_default_library",
|
||||
"//test:go_default_library",
|
||||
"//test/proto2pb:go_default_library",
|
||||
"//test/proto3pb:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
|
||||
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
|
||||
],
|
||||
)
|
||||
|
205
vendor/github.com/google/cel-go/ext/README.md
generated
vendored
205
vendor/github.com/google/cel-go/ext/README.md
generated
vendored
@ -3,6 +3,30 @@
|
||||
CEL extensions are a related set of constants, functions, macros, or other
|
||||
features which may not be covered by the core CEL spec.
|
||||
|
||||
## Bindings
|
||||
|
||||
Returns a cel.EnvOption to configure support for local variable bindings
|
||||
in expressions.
|
||||
|
||||
# Cel.Bind
|
||||
|
||||
Binds a simple identifier to an initialization expression which may be used
|
||||
in a subsequenct result expression. Bindings may also be nested within each
|
||||
other.
|
||||
|
||||
cel.bind(<varName>, <initExpr>, <resultExpr>)
|
||||
|
||||
Examples:
|
||||
|
||||
cel.bind(a, 'hello',
|
||||
cel.bind(b, 'world', a + b + b + a)) // "helloworldworldhello"
|
||||
|
||||
// Avoid a list allocation within the exists comprehension.
|
||||
cel.bind(valid_values, [a, b, c],
|
||||
[d, e, f].exists(elem, elem in valid_values))
|
||||
|
||||
Local bindings are not guaranteed to be evaluated before use.
|
||||
|
||||
## Encoders
|
||||
|
||||
Encoding utilies for marshalling data into standardized representations.
|
||||
@ -31,6 +55,156 @@ Example:
|
||||
|
||||
base64.encode(b'hello') // return 'aGVsbG8='
|
||||
|
||||
## Math
|
||||
|
||||
Math helper macros and functions.
|
||||
|
||||
Note, all macros use the 'math' namespace; however, at the time of macro
|
||||
expansion the namespace looks just like any other identifier. If you are
|
||||
currently using a variable named 'math', the macro will likely work just as
|
||||
intended; however, there is some chance for collision.
|
||||
|
||||
### Math.Greatest
|
||||
|
||||
Returns the greatest valued number present in the arguments to the macro.
|
||||
|
||||
Greatest is a variable argument count macro which must take at least one
|
||||
argument. Simple numeric and list literals are supported as valid argument
|
||||
types; however, other literals will be flagged as errors during macro
|
||||
expansion. If the argument expression does not resolve to a numeric or
|
||||
list(numeric) type during type-checking, or during runtime then an error
|
||||
will be produced. If a list argument is empty, this too will produce an
|
||||
error.
|
||||
|
||||
math.greatest(<arg>, ...) -> <double|int|uint>
|
||||
|
||||
Examples:
|
||||
|
||||
math.greatest(1) // 1
|
||||
math.greatest(1u, 2u) // 2u
|
||||
math.greatest(-42.0, -21.5, -100.0) // -21.5
|
||||
math.greatest([-42.0, -21.5, -100.0]) // -21.5
|
||||
math.greatest(numbers) // numbers must be list(numeric)
|
||||
|
||||
math.greatest() // parse error
|
||||
math.greatest('string') // parse error
|
||||
math.greatest(a, b) // check-time error if a or b is non-numeric
|
||||
math.greatest(dyn('string')) // runtime error
|
||||
|
||||
### Math.Least
|
||||
|
||||
Returns the least valued number present in the arguments to the macro.
|
||||
|
||||
Least is a variable argument count macro which must take at least one
|
||||
argument. Simple numeric and list literals are supported as valid argument
|
||||
types; however, other literals will be flagged as errors during macro
|
||||
expansion. If the argument expression does not resolve to a numeric or
|
||||
list(numeric) type during type-checking, or during runtime then an error
|
||||
will be produced. If a list argument is empty, this too will produce an error.
|
||||
|
||||
math.least(<arg>, ...) -> <double|int|uint>
|
||||
|
||||
Examples:
|
||||
|
||||
math.least(1) // 1
|
||||
math.least(1u, 2u) // 1u
|
||||
math.least(-42.0, -21.5, -100.0) // -100.0
|
||||
math.least([-42.0, -21.5, -100.0]) // -100.0
|
||||
math.least(numbers) // numbers must be list(numeric)
|
||||
|
||||
math.least() // parse error
|
||||
math.least('string') // parse error
|
||||
math.least(a, b) // check-time error if a or b is non-numeric
|
||||
math.least(dyn('string')) // runtime error
|
||||
|
||||
## Protos
|
||||
|
||||
Protos configure extended macros and functions for proto manipulation.
|
||||
|
||||
Note, all macros use the 'proto' namespace; however, at the time of macro
|
||||
expansion the namespace looks just like any other identifier. If you are
|
||||
currently using a variable named 'proto', the macro will likely work just as
|
||||
you intend; however, there is some chance for collision.
|
||||
|
||||
### Protos.GetExt
|
||||
|
||||
Macro which generates a select expression that retrieves an extension field
|
||||
from the input proto2 syntax message. If the field is not set, the default
|
||||
value forthe extension field is returned according to safe-traversal semantics.
|
||||
|
||||
proto.getExt(<msg>, <fully.qualified.extension.name>) -> <field-type>
|
||||
|
||||
Example:
|
||||
|
||||
proto.getExt(msg, google.expr.proto2.test.int32_ext) // returns int value
|
||||
|
||||
### Protos.HasExt
|
||||
|
||||
Macro which generates a test-only select expression that determines whether
|
||||
an extension field is set on a proto2 syntax message.
|
||||
|
||||
proto.hasExt(<msg>, <fully.qualified.extension.name>) -> <bool>
|
||||
|
||||
Example:
|
||||
|
||||
proto.hasExt(msg, google.expr.proto2.test.int32_ext) // returns true || false
|
||||
|
||||
## Sets
|
||||
|
||||
Sets provides set relationship tests.
|
||||
|
||||
There is no set type within CEL, and while one may be introduced in the
|
||||
future, there are cases where a `list` type is known to behave like a set.
|
||||
For such cases, this library provides some basic functionality for
|
||||
determining set containment, equivalence, and intersection.
|
||||
|
||||
### Sets.Contains
|
||||
|
||||
Returns whether the first list argument contains all elements in the second
|
||||
list argument. The list may contain elements of any type and standard CEL
|
||||
equality is used to determine whether a value exists in both lists. If the
|
||||
second list is empty, the result will always return true.
|
||||
|
||||
sets.contains(list(T), list(T)) -> bool
|
||||
|
||||
Examples:
|
||||
|
||||
sets.contains([], []) // true
|
||||
sets.contains([], [1]) // false
|
||||
sets.contains([1, 2, 3, 4], [2, 3]) // true
|
||||
sets.contains([1, 2.0, 3u], [1.0, 2u, 3]) // true
|
||||
|
||||
### Sets.Equivalent
|
||||
|
||||
Returns whether the first and second list are set equivalent. Lists are set
|
||||
equivalent if for every item in the first list, there is an element in the
|
||||
second which is equal. The lists may not be of the same size as they do not
|
||||
guarantee the elements within them are unique, so size does not factor into
|
||||
the computation.
|
||||
|
||||
sets.equivalent(list(T), list(T)) -> bool
|
||||
|
||||
Examples:
|
||||
|
||||
sets.equivalent([], []) // true
|
||||
sets.equivalent([1], [1, 1]) // true
|
||||
sets.equivalent([1], [1u, 1.0]) // true
|
||||
sets.equivalent([1, 2, 3], [3u, 2.0, 1]) // true
|
||||
|
||||
### Sets.Intersects
|
||||
|
||||
Returns whether the first list has at least one element whose value is equal
|
||||
to an element in the second list. If either list is empty, the result will
|
||||
be false.
|
||||
|
||||
sets.intersects(list(T), list(T)) -> bool
|
||||
|
||||
Examples:
|
||||
|
||||
sets.intersects([1], []) // false
|
||||
sets.intersects([1], [1, 2]) // true
|
||||
sets.intersects([[1], [2, 3]], [[1, 2], [2, 3.0]]) // true
|
||||
|
||||
## Strings
|
||||
|
||||
Extended functions for string manipulation. As a general note, all indices are
|
||||
@ -70,6 +244,23 @@ Examples:
|
||||
'hello mellow'.indexOf('ello', 2) // returns 7
|
||||
'hello mellow'.indexOf('ello', 20) // error
|
||||
|
||||
### Join
|
||||
|
||||
Returns a new string where the elements of string list are concatenated.
|
||||
|
||||
The function also accepts an optional separator which is placed between
|
||||
elements in the resulting string.
|
||||
|
||||
<list<string>>.join() -> <string>
|
||||
<list<string>>.join(<string>) -> <string>
|
||||
|
||||
Examples:
|
||||
|
||||
['hello', 'mellow'].join() // returns 'hellomellow'
|
||||
['hello', 'mellow'].join(' ') // returns 'hello mellow'
|
||||
[].join() // returns ''
|
||||
[].join('/') // returns ''
|
||||
|
||||
### LastIndexOf
|
||||
|
||||
Returns the integer index of the last occurrence of the search string. If the
|
||||
@ -105,6 +296,20 @@ Examples:
|
||||
'TacoCat'.lowerAscii() // returns 'tacocat'
|
||||
'TacoCÆt Xii'.lowerAscii() // returns 'tacocÆt xii'
|
||||
|
||||
### Quote
|
||||
|
||||
**Introduced in version 1**
|
||||
|
||||
Takes the given string and makes it safe to print (without any formatting due to escape sequences).
|
||||
If any invalid UTF-8 characters are encountered, they are replaced with \uFFFD.
|
||||
|
||||
strings.quote(<string>)
|
||||
|
||||
Examples:
|
||||
|
||||
strings.quote('single-quote with "double quote"') // returns '"single-quote with \"double quote\""'
|
||||
strings.quote("two escape sequences \a\n") // returns '"two escape sequences \\a\\n"'
|
||||
|
||||
### Replace
|
||||
|
||||
Returns a new string based on the target, which replaces the occurrences of a
|
||||
|
100
vendor/github.com/google/cel-go/ext/bindings.go
generated
vendored
Normal file
100
vendor/github.com/google/cel-go/ext/bindings.go
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
// 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
|
||||
//
|
||||
// http://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 ext
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Bindings returns a cel.EnvOption to configure support for local variable
|
||||
// bindings in expressions.
|
||||
//
|
||||
// # Cel.Bind
|
||||
//
|
||||
// Binds a simple identifier to an initialization expression which may be used
|
||||
// in a subsequenct result expression. Bindings may also be nested within each
|
||||
// other.
|
||||
//
|
||||
// cel.bind(<varName>, <initExpr>, <resultExpr>)
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// cel.bind(a, 'hello',
|
||||
// cel.bind(b, 'world', a + b + b + a)) // "helloworldworldhello"
|
||||
//
|
||||
// // Avoid a list allocation within the exists comprehension.
|
||||
// cel.bind(valid_values, [a, b, c],
|
||||
// [d, e, f].exists(elem, elem in valid_values))
|
||||
//
|
||||
// Local bindings are not guaranteed to be evaluated before use.
|
||||
func Bindings() cel.EnvOption {
|
||||
return cel.Lib(celBindings{})
|
||||
}
|
||||
|
||||
const (
|
||||
celNamespace = "cel"
|
||||
bindMacro = "bind"
|
||||
unusedIterVar = "#unused"
|
||||
)
|
||||
|
||||
type celBindings struct{}
|
||||
|
||||
func (celBindings) LibraryName() string {
|
||||
return "cel.lib.ext.cel.bindings"
|
||||
}
|
||||
|
||||
func (celBindings) CompileOptions() []cel.EnvOption {
|
||||
return []cel.EnvOption{
|
||||
cel.Macros(
|
||||
// cel.bind(var, <init>, <expr>)
|
||||
cel.NewReceiverMacro(bindMacro, 3, celBind),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (celBindings) ProgramOptions() []cel.ProgramOption {
|
||||
return []cel.ProgramOption{}
|
||||
}
|
||||
|
||||
func celBind(meh cel.MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
if !macroTargetMatchesNamespace(celNamespace, target) {
|
||||
return nil, nil
|
||||
}
|
||||
varIdent := args[0]
|
||||
varName := ""
|
||||
switch varIdent.GetExprKind().(type) {
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
varName = varIdent.GetIdentExpr().GetName()
|
||||
default:
|
||||
return nil, &common.Error{
|
||||
Message: "cel.bind() variable names must be simple identifers",
|
||||
Location: meh.OffsetLocation(varIdent.GetId()),
|
||||
}
|
||||
}
|
||||
varInit := args[1]
|
||||
resultExpr := args[2]
|
||||
return meh.Fold(
|
||||
unusedIterVar,
|
||||
meh.NewList(),
|
||||
varName,
|
||||
varInit,
|
||||
meh.LiteralBool(false),
|
||||
meh.Ident(varName),
|
||||
resultExpr,
|
||||
), nil
|
||||
}
|
18
vendor/github.com/google/cel-go/ext/encoders.go
generated
vendored
18
vendor/github.com/google/cel-go/ext/encoders.go
generated
vendored
@ -26,34 +26,38 @@ import (
|
||||
// Encoders returns a cel.EnvOption to configure extended functions for string, byte, and object
|
||||
// encodings.
|
||||
//
|
||||
// Base64.Decode
|
||||
// # Base64.Decode
|
||||
//
|
||||
// Decodes base64-encoded string to bytes.
|
||||
//
|
||||
// This function will return an error if the string input is not base64-encoded.
|
||||
//
|
||||
// base64.decode(<string>) -> <bytes>
|
||||
// base64.decode(<string>) -> <bytes>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// base64.decode('aGVsbG8=') // return b'hello'
|
||||
// base64.decode('aGVsbG8') // error
|
||||
// base64.decode('aGVsbG8=') // return b'hello'
|
||||
// base64.decode('aGVsbG8') // error
|
||||
//
|
||||
// Base64.Encode
|
||||
// # Base64.Encode
|
||||
//
|
||||
// Encodes bytes to a base64-encoded string.
|
||||
//
|
||||
// base64.encode(<bytes>) -> <string>
|
||||
// base64.encode(<bytes>) -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// base64.encode(b'hello') // return b'aGVsbG8='
|
||||
// base64.encode(b'hello') // return b'aGVsbG8='
|
||||
func Encoders() cel.EnvOption {
|
||||
return cel.Lib(encoderLib{})
|
||||
}
|
||||
|
||||
type encoderLib struct{}
|
||||
|
||||
func (encoderLib) LibraryName() string {
|
||||
return "cel.lib.ext.encoders"
|
||||
}
|
||||
|
||||
func (encoderLib) CompileOptions() []cel.EnvOption {
|
||||
return []cel.EnvOption{
|
||||
cel.Function("base64.decode",
|
||||
|
13
vendor/github.com/google/cel-go/ext/guards.go
generated
vendored
13
vendor/github.com/google/cel-go/ext/guards.go
generated
vendored
@ -17,6 +17,7 @@ package ext
|
||||
import (
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// function invocation guards for common call signatures within extension functions.
|
||||
@ -48,3 +49,15 @@ func listStringOrError(strs []string, err error) ref.Val {
|
||||
}
|
||||
return types.DefaultTypeAdapter.NativeToValue(strs)
|
||||
}
|
||||
|
||||
func macroTargetMatchesNamespace(ns string, target *exprpb.Expr) bool {
|
||||
switch target.GetExprKind().(type) {
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
if target.GetIdentExpr().GetName() != ns {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
388
vendor/github.com/google/cel-go/ext/math.go
generated
vendored
Normal file
388
vendor/github.com/google/cel-go/ext/math.go
generated
vendored
Normal file
@ -0,0 +1,388 @@
|
||||
// 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
|
||||
//
|
||||
// http://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 ext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Math returns a cel.EnvOption to configure namespaced math helper macros and
|
||||
// functions.
|
||||
//
|
||||
// Note, all macros use the 'math' namespace; however, at the time of macro
|
||||
// expansion the namespace looks just like any other identifier. If you are
|
||||
// currently using a variable named 'math', the macro will likely work just as
|
||||
// intended; however, there is some chance for collision.
|
||||
//
|
||||
// # Math.Greatest
|
||||
//
|
||||
// Returns the greatest valued number present in the arguments to the macro.
|
||||
//
|
||||
// Greatest is a variable argument count macro which must take at least one
|
||||
// argument. Simple numeric and list literals are supported as valid argument
|
||||
// types; however, other literals will be flagged as errors during macro
|
||||
// expansion. If the argument expression does not resolve to a numeric or
|
||||
// list(numeric) type during type-checking, or during runtime then an error
|
||||
// will be produced. If a list argument is empty, this too will produce an
|
||||
// error.
|
||||
//
|
||||
// math.greatest(<arg>, ...) -> <double|int|uint>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// math.greatest(1) // 1
|
||||
// math.greatest(1u, 2u) // 2u
|
||||
// math.greatest(-42.0, -21.5, -100.0) // -21.5
|
||||
// math.greatest([-42.0, -21.5, -100.0]) // -21.5
|
||||
// math.greatest(numbers) // numbers must be list(numeric)
|
||||
//
|
||||
// math.greatest() // parse error
|
||||
// math.greatest('string') // parse error
|
||||
// math.greatest(a, b) // check-time error if a or b is non-numeric
|
||||
// math.greatest(dyn('string')) // runtime error
|
||||
//
|
||||
// # Math.Least
|
||||
//
|
||||
// Returns the least valued number present in the arguments to the macro.
|
||||
//
|
||||
// Least is a variable argument count macro which must take at least one
|
||||
// argument. Simple numeric and list literals are supported as valid argument
|
||||
// types; however, other literals will be flagged as errors during macro
|
||||
// expansion. If the argument expression does not resolve to a numeric or
|
||||
// list(numeric) type during type-checking, or during runtime then an error
|
||||
// will be produced. If a list argument is empty, this too will produce an
|
||||
// error.
|
||||
//
|
||||
// math.least(<arg>, ...) -> <double|int|uint>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// math.least(1) // 1
|
||||
// math.least(1u, 2u) // 1u
|
||||
// math.least(-42.0, -21.5, -100.0) // -100.0
|
||||
// math.least([-42.0, -21.5, -100.0]) // -100.0
|
||||
// math.least(numbers) // numbers must be list(numeric)
|
||||
//
|
||||
// math.least() // parse error
|
||||
// math.least('string') // parse error
|
||||
// math.least(a, b) // check-time error if a or b is non-numeric
|
||||
// math.least(dyn('string')) // runtime error
|
||||
func Math() cel.EnvOption {
|
||||
return cel.Lib(mathLib{})
|
||||
}
|
||||
|
||||
const (
|
||||
mathNamespace = "math"
|
||||
leastMacro = "least"
|
||||
greatestMacro = "greatest"
|
||||
minFunc = "math.@min"
|
||||
maxFunc = "math.@max"
|
||||
)
|
||||
|
||||
type mathLib struct{}
|
||||
|
||||
// LibraryName implements the SingletonLibrary interface method.
|
||||
func (mathLib) LibraryName() string {
|
||||
return "cel.lib.ext.math"
|
||||
}
|
||||
|
||||
// CompileOptions implements the Library interface method.
|
||||
func (mathLib) CompileOptions() []cel.EnvOption {
|
||||
return []cel.EnvOption{
|
||||
cel.Macros(
|
||||
// math.least(num, ...)
|
||||
cel.NewReceiverVarArgMacro(leastMacro, mathLeast),
|
||||
// math.greatest(num, ...)
|
||||
cel.NewReceiverVarArgMacro(greatestMacro, mathGreatest),
|
||||
),
|
||||
cel.Function(minFunc,
|
||||
cel.Overload("math_@min_double", []*cel.Type{cel.DoubleType}, cel.DoubleType,
|
||||
cel.UnaryBinding(identity)),
|
||||
cel.Overload("math_@min_int", []*cel.Type{cel.IntType}, cel.IntType,
|
||||
cel.UnaryBinding(identity)),
|
||||
cel.Overload("math_@min_uint", []*cel.Type{cel.UintType}, cel.UintType,
|
||||
cel.UnaryBinding(identity)),
|
||||
cel.Overload("math_@min_double_double", []*cel.Type{cel.DoubleType, cel.DoubleType}, cel.DoubleType,
|
||||
cel.BinaryBinding(minPair)),
|
||||
cel.Overload("math_@min_int_int", []*cel.Type{cel.IntType, cel.IntType}, cel.IntType,
|
||||
cel.BinaryBinding(minPair)),
|
||||
cel.Overload("math_@min_uint_uint", []*cel.Type{cel.UintType, cel.UintType}, cel.UintType,
|
||||
cel.BinaryBinding(minPair)),
|
||||
cel.Overload("math_@min_int_uint", []*cel.Type{cel.IntType, cel.UintType}, cel.DynType,
|
||||
cel.BinaryBinding(minPair)),
|
||||
cel.Overload("math_@min_int_double", []*cel.Type{cel.IntType, cel.DoubleType}, cel.DynType,
|
||||
cel.BinaryBinding(minPair)),
|
||||
cel.Overload("math_@min_double_int", []*cel.Type{cel.DoubleType, cel.IntType}, cel.DynType,
|
||||
cel.BinaryBinding(minPair)),
|
||||
cel.Overload("math_@min_double_uint", []*cel.Type{cel.DoubleType, cel.UintType}, cel.DynType,
|
||||
cel.BinaryBinding(minPair)),
|
||||
cel.Overload("math_@min_uint_int", []*cel.Type{cel.UintType, cel.IntType}, cel.DynType,
|
||||
cel.BinaryBinding(minPair)),
|
||||
cel.Overload("math_@min_uint_double", []*cel.Type{cel.UintType, cel.DoubleType}, cel.DynType,
|
||||
cel.BinaryBinding(minPair)),
|
||||
cel.Overload("math_@min_list_double", []*cel.Type{cel.ListType(cel.DoubleType)}, cel.DoubleType,
|
||||
cel.UnaryBinding(minList)),
|
||||
cel.Overload("math_@min_list_int", []*cel.Type{cel.ListType(cel.IntType)}, cel.IntType,
|
||||
cel.UnaryBinding(minList)),
|
||||
cel.Overload("math_@min_list_uint", []*cel.Type{cel.ListType(cel.UintType)}, cel.UintType,
|
||||
cel.UnaryBinding(minList)),
|
||||
),
|
||||
cel.Function(maxFunc,
|
||||
cel.Overload("math_@max_double", []*cel.Type{cel.DoubleType}, cel.DoubleType,
|
||||
cel.UnaryBinding(identity)),
|
||||
cel.Overload("math_@max_int", []*cel.Type{cel.IntType}, cel.IntType,
|
||||
cel.UnaryBinding(identity)),
|
||||
cel.Overload("math_@max_uint", []*cel.Type{cel.UintType}, cel.UintType,
|
||||
cel.UnaryBinding(identity)),
|
||||
cel.Overload("math_@max_double_double", []*cel.Type{cel.DoubleType, cel.DoubleType}, cel.DoubleType,
|
||||
cel.BinaryBinding(maxPair)),
|
||||
cel.Overload("math_@max_int_int", []*cel.Type{cel.IntType, cel.IntType}, cel.IntType,
|
||||
cel.BinaryBinding(maxPair)),
|
||||
cel.Overload("math_@max_uint_uint", []*cel.Type{cel.UintType, cel.UintType}, cel.UintType,
|
||||
cel.BinaryBinding(maxPair)),
|
||||
cel.Overload("math_@max_int_uint", []*cel.Type{cel.IntType, cel.UintType}, cel.DynType,
|
||||
cel.BinaryBinding(maxPair)),
|
||||
cel.Overload("math_@max_int_double", []*cel.Type{cel.IntType, cel.DoubleType}, cel.DynType,
|
||||
cel.BinaryBinding(maxPair)),
|
||||
cel.Overload("math_@max_double_int", []*cel.Type{cel.DoubleType, cel.IntType}, cel.DynType,
|
||||
cel.BinaryBinding(maxPair)),
|
||||
cel.Overload("math_@max_double_uint", []*cel.Type{cel.DoubleType, cel.UintType}, cel.DynType,
|
||||
cel.BinaryBinding(maxPair)),
|
||||
cel.Overload("math_@max_uint_int", []*cel.Type{cel.UintType, cel.IntType}, cel.DynType,
|
||||
cel.BinaryBinding(maxPair)),
|
||||
cel.Overload("math_@max_uint_double", []*cel.Type{cel.UintType, cel.DoubleType}, cel.DynType,
|
||||
cel.BinaryBinding(maxPair)),
|
||||
cel.Overload("math_@max_list_double", []*cel.Type{cel.ListType(cel.DoubleType)}, cel.DoubleType,
|
||||
cel.UnaryBinding(maxList)),
|
||||
cel.Overload("math_@max_list_int", []*cel.Type{cel.ListType(cel.IntType)}, cel.IntType,
|
||||
cel.UnaryBinding(maxList)),
|
||||
cel.Overload("math_@max_list_uint", []*cel.Type{cel.ListType(cel.UintType)}, cel.UintType,
|
||||
cel.UnaryBinding(maxList)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// ProgramOptions implements the Library interface method.
|
||||
func (mathLib) ProgramOptions() []cel.ProgramOption {
|
||||
return []cel.ProgramOption{}
|
||||
}
|
||||
|
||||
func mathLeast(meh cel.MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
if !macroTargetMatchesNamespace(mathNamespace, target) {
|
||||
return nil, nil
|
||||
}
|
||||
switch len(args) {
|
||||
case 0:
|
||||
return nil, &common.Error{
|
||||
Message: "math.least() requires at least one argument",
|
||||
Location: meh.OffsetLocation(target.GetId()),
|
||||
}
|
||||
case 1:
|
||||
if isListLiteralWithValidArgs(args[0]) || isValidArgType(args[0]) {
|
||||
return meh.GlobalCall(minFunc, args[0]), nil
|
||||
}
|
||||
return nil, &common.Error{
|
||||
Message: "math.least() invalid single argument value",
|
||||
Location: meh.OffsetLocation(args[0].GetId()),
|
||||
}
|
||||
case 2:
|
||||
err := checkInvalidArgs(meh, "math.least()", args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return meh.GlobalCall(minFunc, args...), nil
|
||||
default:
|
||||
err := checkInvalidArgs(meh, "math.least()", args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return meh.GlobalCall(minFunc, meh.NewList(args...)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func mathGreatest(meh cel.MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
if !macroTargetMatchesNamespace(mathNamespace, target) {
|
||||
return nil, nil
|
||||
}
|
||||
switch len(args) {
|
||||
case 0:
|
||||
return nil, &common.Error{
|
||||
Message: "math.greatest() requires at least one argument",
|
||||
Location: meh.OffsetLocation(target.GetId()),
|
||||
}
|
||||
case 1:
|
||||
if isListLiteralWithValidArgs(args[0]) || isValidArgType(args[0]) {
|
||||
return meh.GlobalCall(maxFunc, args[0]), nil
|
||||
}
|
||||
return nil, &common.Error{
|
||||
Message: "math.greatest() invalid single argument value",
|
||||
Location: meh.OffsetLocation(args[0].GetId()),
|
||||
}
|
||||
case 2:
|
||||
err := checkInvalidArgs(meh, "math.greatest()", args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return meh.GlobalCall(maxFunc, args...), nil
|
||||
default:
|
||||
err := checkInvalidArgs(meh, "math.greatest()", args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return meh.GlobalCall(maxFunc, meh.NewList(args...)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func identity(val ref.Val) ref.Val {
|
||||
return val
|
||||
}
|
||||
|
||||
func minPair(first, second ref.Val) ref.Val {
|
||||
cmp, ok := first.(traits.Comparer)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(first)
|
||||
}
|
||||
out := cmp.Compare(second)
|
||||
if types.IsUnknownOrError(out) {
|
||||
return maybeSuffixError(out, "math.@min")
|
||||
}
|
||||
if out == types.IntOne {
|
||||
return second
|
||||
}
|
||||
return first
|
||||
}
|
||||
|
||||
func minList(numList ref.Val) ref.Val {
|
||||
l := numList.(traits.Lister)
|
||||
size := l.Size().(types.Int)
|
||||
if size == types.IntZero {
|
||||
return types.NewErr("math.@min(list) argument must not be empty")
|
||||
}
|
||||
min := l.Get(types.IntZero)
|
||||
for i := types.IntOne; i < size; i++ {
|
||||
min = minPair(min, l.Get(i))
|
||||
}
|
||||
switch min.Type() {
|
||||
case types.IntType, types.DoubleType, types.UintType, types.UnknownType:
|
||||
return min
|
||||
default:
|
||||
return types.NewErr("no such overload: math.@min")
|
||||
}
|
||||
}
|
||||
|
||||
func maxPair(first, second ref.Val) ref.Val {
|
||||
cmp, ok := first.(traits.Comparer)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(first)
|
||||
}
|
||||
out := cmp.Compare(second)
|
||||
if types.IsUnknownOrError(out) {
|
||||
return maybeSuffixError(out, "math.@max")
|
||||
}
|
||||
if out == types.IntNegOne {
|
||||
return second
|
||||
}
|
||||
return first
|
||||
}
|
||||
|
||||
func maxList(numList ref.Val) ref.Val {
|
||||
l := numList.(traits.Lister)
|
||||
size := l.Size().(types.Int)
|
||||
if size == types.IntZero {
|
||||
return types.NewErr("math.@max(list) argument must not be empty")
|
||||
}
|
||||
max := l.Get(types.IntZero)
|
||||
for i := types.IntOne; i < size; i++ {
|
||||
max = maxPair(max, l.Get(i))
|
||||
}
|
||||
switch max.Type() {
|
||||
case types.IntType, types.DoubleType, types.UintType, types.UnknownType:
|
||||
return max
|
||||
default:
|
||||
return types.NewErr("no such overload: math.@max")
|
||||
}
|
||||
}
|
||||
|
||||
func checkInvalidArgs(meh cel.MacroExprHelper, funcName string, args []*exprpb.Expr) *common.Error {
|
||||
for _, arg := range args {
|
||||
err := checkInvalidArgLiteral(funcName, arg)
|
||||
if err != nil {
|
||||
return &common.Error{
|
||||
Message: err.Error(),
|
||||
Location: meh.OffsetLocation(arg.GetId()),
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkInvalidArgLiteral(funcName string, arg *exprpb.Expr) error {
|
||||
if !isValidArgType(arg) {
|
||||
return fmt.Errorf("%s simple literal arguments must be numeric", funcName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidArgType(arg *exprpb.Expr) bool {
|
||||
switch arg.GetExprKind().(type) {
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
c := arg.GetConstExpr()
|
||||
switch c.GetConstantKind().(type) {
|
||||
case *exprpb.Constant_DoubleValue, *exprpb.Constant_Int64Value, *exprpb.Constant_Uint64Value:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case *exprpb.Expr_ListExpr, *exprpb.Expr_StructExpr:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func isListLiteralWithValidArgs(arg *exprpb.Expr) bool {
|
||||
switch arg.GetExprKind().(type) {
|
||||
case *exprpb.Expr_ListExpr:
|
||||
list := arg.GetListExpr()
|
||||
if len(list.GetElements()) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, e := range list.GetElements() {
|
||||
if !isValidArgType(e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func maybeSuffixError(val ref.Val, suffix string) ref.Val {
|
||||
if types.IsError(val) {
|
||||
msg := val.(*types.Err).String()
|
||||
if !strings.Contains(msg, suffix) {
|
||||
return types.NewErr("%s: %s", msg, suffix)
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
574
vendor/github.com/google/cel-go/ext/native.go
generated
vendored
Normal file
574
vendor/github.com/google/cel-go/ext/native.go
generated
vendored
Normal file
@ -0,0 +1,574 @@
|
||||
// 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
|
||||
//
|
||||
// http://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 ext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/pb"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
var (
|
||||
nativeObjTraitMask = traits.FieldTesterType | traits.IndexerType
|
||||
jsonValueType = reflect.TypeOf(&structpb.Value{})
|
||||
jsonStructType = reflect.TypeOf(&structpb.Struct{})
|
||||
)
|
||||
|
||||
// NativeTypes creates a type provider which uses reflect.Type and reflect.Value instances
|
||||
// to produce type definitions that can be used within CEL.
|
||||
//
|
||||
// All struct types in Go are exposed to CEL via their simple package name and struct type name:
|
||||
//
|
||||
// ```go
|
||||
// package identity
|
||||
//
|
||||
// type Account struct {
|
||||
// ID int
|
||||
// }
|
||||
//
|
||||
// ```
|
||||
//
|
||||
// The type `identity.Account` would be exported to CEL using the same qualified name, e.g.
|
||||
// `identity.Account{ID: 1234}` would create a new `Account` instance with the `ID` field
|
||||
// populated.
|
||||
//
|
||||
// Only exported fields are exposed via NativeTypes, and the type-mapping between Go and CEL
|
||||
// is as follows:
|
||||
//
|
||||
// | Go type | CEL type |
|
||||
// |-------------------------------------|-----------|
|
||||
// | bool | bool |
|
||||
// | []byte | bytes |
|
||||
// | float32, float64 | double |
|
||||
// | int, int8, int16, int32, int64 | int |
|
||||
// | string | string |
|
||||
// | uint, uint8, uint16, uint32, uint64 | uint |
|
||||
// | time.Duration | duration |
|
||||
// | time.Time | timestamp |
|
||||
// | array, slice | list |
|
||||
// | map | map |
|
||||
//
|
||||
// Please note, if you intend to configure support for proto messages in addition to native
|
||||
// types, you will need to provide the protobuf types before the golang native types. The
|
||||
// same advice holds if you are using custom type adapters and type providers. The native type
|
||||
// provider composes over whichever type adapter and provider is configured in the cel.Env at
|
||||
// the time that it is invoked.
|
||||
func NativeTypes(refTypes ...any) cel.EnvOption {
|
||||
return func(env *cel.Env) (*cel.Env, error) {
|
||||
tp, err := newNativeTypeProvider(env.TypeAdapter(), env.TypeProvider(), refTypes...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
env, err = cel.CustomTypeAdapter(tp)(env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cel.CustomTypeProvider(tp)(env)
|
||||
}
|
||||
}
|
||||
|
||||
func newNativeTypeProvider(adapter ref.TypeAdapter, provider ref.TypeProvider, refTypes ...any) (*nativeTypeProvider, error) {
|
||||
nativeTypes := make(map[string]*nativeType, len(refTypes))
|
||||
for _, refType := range refTypes {
|
||||
switch rt := refType.(type) {
|
||||
case reflect.Type:
|
||||
t, err := newNativeType(rt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nativeTypes[t.TypeName()] = t
|
||||
case reflect.Value:
|
||||
t, err := newNativeType(rt.Type())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nativeTypes[t.TypeName()] = t
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported native type: %v (%T) must be reflect.Type or reflect.Value", rt, rt)
|
||||
}
|
||||
}
|
||||
return &nativeTypeProvider{
|
||||
nativeTypes: nativeTypes,
|
||||
baseAdapter: adapter,
|
||||
baseProvider: provider,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type nativeTypeProvider struct {
|
||||
nativeTypes map[string]*nativeType
|
||||
baseAdapter ref.TypeAdapter
|
||||
baseProvider ref.TypeProvider
|
||||
}
|
||||
|
||||
// EnumValue proxies to the ref.TypeProvider configured at the times the NativeTypes
|
||||
// option was configured.
|
||||
func (tp *nativeTypeProvider) EnumValue(enumName string) ref.Val {
|
||||
return tp.baseProvider.EnumValue(enumName)
|
||||
}
|
||||
|
||||
// FindIdent looks up natives type instances by qualified identifier, and if not found
|
||||
// proxies to the composed ref.TypeProvider.
|
||||
func (tp *nativeTypeProvider) FindIdent(typeName string) (ref.Val, bool) {
|
||||
if t, found := tp.nativeTypes[typeName]; found {
|
||||
return t, true
|
||||
}
|
||||
return tp.baseProvider.FindIdent(typeName)
|
||||
}
|
||||
|
||||
// FindType looks up CEL type-checker type definition by qualified identifier, and if not found
|
||||
// proxies to the composed ref.TypeProvider.
|
||||
func (tp *nativeTypeProvider) FindType(typeName string) (*exprpb.Type, bool) {
|
||||
if _, found := tp.nativeTypes[typeName]; found {
|
||||
return decls.NewTypeType(decls.NewObjectType(typeName)), true
|
||||
}
|
||||
return tp.baseProvider.FindType(typeName)
|
||||
}
|
||||
|
||||
// FindFieldType looks up a native type's field definition, and if the type name is not a native
|
||||
// type then proxies to the composed ref.TypeProvider
|
||||
func (tp *nativeTypeProvider) FindFieldType(typeName, fieldName string) (*ref.FieldType, bool) {
|
||||
t, found := tp.nativeTypes[typeName]
|
||||
if !found {
|
||||
return tp.baseProvider.FindFieldType(typeName, fieldName)
|
||||
}
|
||||
refField, isDefined := t.hasField(fieldName)
|
||||
if !found || !isDefined {
|
||||
return nil, false
|
||||
}
|
||||
exprType, ok := convertToExprType(refField.Type)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return &ref.FieldType{
|
||||
Type: exprType,
|
||||
IsSet: func(obj any) bool {
|
||||
refVal := reflect.Indirect(reflect.ValueOf(obj))
|
||||
refField := refVal.FieldByName(fieldName)
|
||||
return !refField.IsZero()
|
||||
},
|
||||
GetFrom: func(obj any) (any, error) {
|
||||
refVal := reflect.Indirect(reflect.ValueOf(obj))
|
||||
refField := refVal.FieldByName(fieldName)
|
||||
return getFieldValue(tp, refField), nil
|
||||
},
|
||||
}, true
|
||||
}
|
||||
|
||||
// NewValue implements the ref.TypeProvider interface method.
|
||||
func (tp *nativeTypeProvider) NewValue(typeName string, fields map[string]ref.Val) ref.Val {
|
||||
t, found := tp.nativeTypes[typeName]
|
||||
if !found {
|
||||
return tp.baseProvider.NewValue(typeName, fields)
|
||||
}
|
||||
refPtr := reflect.New(t.refType)
|
||||
refVal := refPtr.Elem()
|
||||
for fieldName, val := range fields {
|
||||
refFieldDef, isDefined := t.hasField(fieldName)
|
||||
if !isDefined {
|
||||
return types.NewErr("no such field: %s", fieldName)
|
||||
}
|
||||
fieldVal, err := val.ConvertToNative(refFieldDef.Type)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
refField := refVal.FieldByIndex(refFieldDef.Index)
|
||||
refFieldVal := reflect.ValueOf(fieldVal)
|
||||
refField.Set(refFieldVal)
|
||||
}
|
||||
return tp.NativeToValue(refPtr.Interface())
|
||||
}
|
||||
|
||||
// NewValue adapts native values to CEL values and will proxy to the composed type adapter
|
||||
// for non-native types.
|
||||
func (tp *nativeTypeProvider) NativeToValue(val any) ref.Val {
|
||||
if val == nil {
|
||||
return types.NullValue
|
||||
}
|
||||
if v, ok := val.(ref.Val); ok {
|
||||
return v
|
||||
}
|
||||
rawVal := reflect.ValueOf(val)
|
||||
refVal := rawVal
|
||||
if refVal.Kind() == reflect.Ptr {
|
||||
refVal = reflect.Indirect(refVal)
|
||||
}
|
||||
// This isn't quite right if you're also supporting proto,
|
||||
// but maybe an acceptable limitation.
|
||||
switch refVal.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
switch val := val.(type) {
|
||||
case []byte:
|
||||
return tp.baseAdapter.NativeToValue(val)
|
||||
default:
|
||||
return types.NewDynamicList(tp, val)
|
||||
}
|
||||
case reflect.Map:
|
||||
return types.NewDynamicMap(tp, val)
|
||||
case reflect.Struct:
|
||||
switch val := val.(type) {
|
||||
case proto.Message, *pb.Map, protoreflect.List, protoreflect.Message, protoreflect.Value,
|
||||
time.Time:
|
||||
return tp.baseAdapter.NativeToValue(val)
|
||||
default:
|
||||
return newNativeObject(tp, val, rawVal)
|
||||
}
|
||||
default:
|
||||
return tp.baseAdapter.NativeToValue(val)
|
||||
}
|
||||
}
|
||||
|
||||
// convertToExprType converts the Golang reflect.Type to a protobuf exprpb.Type.
|
||||
func convertToExprType(refType reflect.Type) (*exprpb.Type, bool) {
|
||||
switch refType.Kind() {
|
||||
case reflect.Bool:
|
||||
return decls.Bool, true
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return decls.Double, true
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if refType == durationType {
|
||||
return decls.Duration, true
|
||||
}
|
||||
return decls.Int, true
|
||||
case reflect.String:
|
||||
return decls.String, true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return decls.Uint, true
|
||||
case reflect.Array, reflect.Slice:
|
||||
refElem := refType.Elem()
|
||||
if refElem == reflect.TypeOf(byte(0)) {
|
||||
return decls.Bytes, true
|
||||
}
|
||||
elemType, ok := convertToExprType(refElem)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return decls.NewListType(elemType), true
|
||||
case reflect.Map:
|
||||
keyType, ok := convertToExprType(refType.Key())
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
// Ensure the key type is a int, bool, uint, string
|
||||
elemType, ok := convertToExprType(refType.Elem())
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return decls.NewMapType(keyType, elemType), true
|
||||
case reflect.Struct:
|
||||
if refType == timestampType {
|
||||
return decls.Timestamp, true
|
||||
}
|
||||
return decls.NewObjectType(
|
||||
fmt.Sprintf("%s.%s", simplePkgAlias(refType.PkgPath()), refType.Name()),
|
||||
), true
|
||||
case reflect.Pointer:
|
||||
if refType.Implements(pbMsgInterfaceType) {
|
||||
pbMsg := reflect.New(refType.Elem()).Interface().(protoreflect.ProtoMessage)
|
||||
return decls.NewObjectType(string(pbMsg.ProtoReflect().Descriptor().FullName())), true
|
||||
}
|
||||
return convertToExprType(refType.Elem())
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func newNativeObject(adapter ref.TypeAdapter, val any, refValue reflect.Value) ref.Val {
|
||||
valType, err := newNativeType(refValue.Type())
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return &nativeObj{
|
||||
TypeAdapter: adapter,
|
||||
val: val,
|
||||
valType: valType,
|
||||
refValue: refValue,
|
||||
}
|
||||
}
|
||||
|
||||
type nativeObj struct {
|
||||
ref.TypeAdapter
|
||||
val any
|
||||
valType *nativeType
|
||||
refValue reflect.Value
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
//
|
||||
// CEL does not have a notion of pointers, so whether a field is a pointer or value
|
||||
// is handled as part of this conversion step.
|
||||
func (o *nativeObj) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
if o.refValue.Type() == typeDesc {
|
||||
return o.val, nil
|
||||
}
|
||||
if o.refValue.Kind() == reflect.Pointer && o.refValue.Type().Elem() == typeDesc {
|
||||
return o.refValue.Elem().Interface(), nil
|
||||
}
|
||||
if typeDesc.Kind() == reflect.Pointer && o.refValue.Type() == typeDesc.Elem() {
|
||||
ptr := reflect.New(typeDesc.Elem())
|
||||
ptr.Elem().Set(o.refValue)
|
||||
return ptr.Interface(), nil
|
||||
}
|
||||
switch typeDesc {
|
||||
case jsonValueType:
|
||||
jsonStruct, err := o.ConvertToNative(jsonStructType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return structpb.NewStructValue(jsonStruct.(*structpb.Struct)), nil
|
||||
case jsonStructType:
|
||||
refVal := reflect.Indirect(o.refValue)
|
||||
refType := refVal.Type()
|
||||
fields := make(map[string]*structpb.Value, refVal.NumField())
|
||||
for i := 0; i < refVal.NumField(); i++ {
|
||||
fieldType := refType.Field(i)
|
||||
fieldValue := refVal.Field(i)
|
||||
if !fieldValue.IsValid() || fieldValue.IsZero() {
|
||||
continue
|
||||
}
|
||||
fieldCELVal := o.NativeToValue(fieldValue.Interface())
|
||||
fieldJSONVal, err := fieldCELVal.ConvertToNative(jsonValueType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fields[fieldType.Name] = fieldJSONVal.(*structpb.Value)
|
||||
}
|
||||
return &structpb.Struct{Fields: fields}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("type conversion error from '%v' to '%v'", o.Type(), typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements the ref.Val interface method.
|
||||
func (o *nativeObj) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case types.TypeType:
|
||||
return o.valType
|
||||
default:
|
||||
if typeVal.TypeName() == o.valType.typeName {
|
||||
return o
|
||||
}
|
||||
}
|
||||
return types.NewErr("type conversion error from '%s' to '%s'", o.Type(), typeVal)
|
||||
}
|
||||
|
||||
// Equal implements the ref.Val interface method.
|
||||
//
|
||||
// Note, that in Golang a pointer to a value is not equal to the value it contains.
|
||||
// In CEL pointers and values to which they point are equal.
|
||||
func (o *nativeObj) Equal(other ref.Val) ref.Val {
|
||||
otherNtv, ok := other.(*nativeObj)
|
||||
if !ok {
|
||||
return types.False
|
||||
}
|
||||
val := o.val
|
||||
otherVal := otherNtv.val
|
||||
refVal := o.refValue
|
||||
otherRefVal := otherNtv.refValue
|
||||
if refVal.Kind() != otherRefVal.Kind() {
|
||||
if refVal.Kind() == reflect.Pointer {
|
||||
val = refVal.Elem().Interface()
|
||||
} else if otherRefVal.Kind() == reflect.Pointer {
|
||||
otherVal = otherRefVal.Elem().Interface()
|
||||
}
|
||||
}
|
||||
return types.Bool(reflect.DeepEqual(val, otherVal))
|
||||
}
|
||||
|
||||
// IsZeroValue indicates whether the contained Golang value is a zero value.
|
||||
//
|
||||
// Golang largely follows proto3 semantics for zero values.
|
||||
func (o *nativeObj) IsZeroValue() bool {
|
||||
return reflect.Indirect(o.refValue).IsZero()
|
||||
}
|
||||
|
||||
// IsSet tests whether a field which is defined is set to a non-default value.
|
||||
func (o *nativeObj) IsSet(field ref.Val) ref.Val {
|
||||
refField, refErr := o.getReflectedField(field)
|
||||
if refErr != nil {
|
||||
return refErr
|
||||
}
|
||||
return types.Bool(!refField.IsZero())
|
||||
}
|
||||
|
||||
// Get returns the value fo a field name.
|
||||
func (o *nativeObj) Get(field ref.Val) ref.Val {
|
||||
refField, refErr := o.getReflectedField(field)
|
||||
if refErr != nil {
|
||||
return refErr
|
||||
}
|
||||
return adaptFieldValue(o, refField)
|
||||
}
|
||||
|
||||
func (o *nativeObj) getReflectedField(field ref.Val) (reflect.Value, ref.Val) {
|
||||
fieldName, ok := field.(types.String)
|
||||
if !ok {
|
||||
return reflect.Value{}, types.MaybeNoSuchOverloadErr(field)
|
||||
}
|
||||
fieldNameStr := string(fieldName)
|
||||
refField, isDefined := o.valType.hasField(fieldNameStr)
|
||||
if !isDefined {
|
||||
return reflect.Value{}, types.NewErr("no such field: %s", fieldName)
|
||||
}
|
||||
refVal := reflect.Indirect(o.refValue)
|
||||
return refVal.FieldByIndex(refField.Index), nil
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (o *nativeObj) Type() ref.Type {
|
||||
return o.valType
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (o *nativeObj) Value() any {
|
||||
return o.val
|
||||
}
|
||||
|
||||
func newNativeType(rawType reflect.Type) (*nativeType, error) {
|
||||
refType := rawType
|
||||
if refType.Kind() == reflect.Pointer {
|
||||
refType = refType.Elem()
|
||||
}
|
||||
if !isValidObjectType(refType) {
|
||||
return nil, fmt.Errorf("unsupported reflect.Type %v, must be reflect.Struct", rawType)
|
||||
}
|
||||
return &nativeType{
|
||||
typeName: fmt.Sprintf("%s.%s", simplePkgAlias(refType.PkgPath()), refType.Name()),
|
||||
refType: refType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type nativeType struct {
|
||||
typeName string
|
||||
refType reflect.Type
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (t *nativeType) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
return nil, fmt.Errorf("type conversion error for type to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (t *nativeType) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case types.TypeType:
|
||||
return types.TypeType
|
||||
}
|
||||
return types.NewErr("type conversion error from '%s' to '%s'", types.TypeType, typeVal)
|
||||
}
|
||||
|
||||
// Equal returns true of both type names are equal to each other.
|
||||
func (t *nativeType) Equal(other ref.Val) ref.Val {
|
||||
otherType, ok := other.(ref.Type)
|
||||
return types.Bool(ok && t.TypeName() == otherType.TypeName())
|
||||
}
|
||||
|
||||
// HasTrait implements the ref.Type interface method.
|
||||
func (t *nativeType) HasTrait(trait int) bool {
|
||||
return nativeObjTraitMask&trait == trait
|
||||
}
|
||||
|
||||
// String implements the strings.Stringer interface method.
|
||||
func (t *nativeType) String() string {
|
||||
return t.typeName
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (t *nativeType) Type() ref.Type {
|
||||
return types.TypeType
|
||||
}
|
||||
|
||||
// TypeName implements the ref.Type interface method.
|
||||
func (t *nativeType) TypeName() string {
|
||||
return t.typeName
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (t *nativeType) Value() any {
|
||||
return t.typeName
|
||||
}
|
||||
|
||||
// hasField returns whether a field name has a corresponding Golang reflect.StructField
|
||||
func (t *nativeType) hasField(fieldName string) (reflect.StructField, bool) {
|
||||
f, found := t.refType.FieldByName(fieldName)
|
||||
if !found || !f.IsExported() || !isSupportedType(f.Type) {
|
||||
return reflect.StructField{}, false
|
||||
}
|
||||
return f, true
|
||||
}
|
||||
|
||||
func adaptFieldValue(adapter ref.TypeAdapter, refField reflect.Value) ref.Val {
|
||||
return adapter.NativeToValue(getFieldValue(adapter, refField))
|
||||
}
|
||||
|
||||
func getFieldValue(adapter ref.TypeAdapter, refField reflect.Value) any {
|
||||
if refField.IsZero() {
|
||||
switch refField.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return types.NewDynamicList(adapter, []ref.Val{})
|
||||
case reflect.Map:
|
||||
return types.NewDynamicMap(adapter, map[ref.Val]ref.Val{})
|
||||
case reflect.Struct:
|
||||
if refField.Type() == timestampType {
|
||||
return types.Timestamp{Time: time.Unix(0, 0)}
|
||||
}
|
||||
return reflect.New(refField.Type()).Elem().Interface()
|
||||
case reflect.Pointer:
|
||||
return reflect.New(refField.Type().Elem()).Interface()
|
||||
}
|
||||
}
|
||||
return refField.Interface()
|
||||
}
|
||||
|
||||
func simplePkgAlias(pkgPath string) string {
|
||||
paths := strings.Split(pkgPath, "/")
|
||||
if len(paths) == 0 {
|
||||
return ""
|
||||
}
|
||||
return paths[len(paths)-1]
|
||||
}
|
||||
|
||||
func isValidObjectType(refType reflect.Type) bool {
|
||||
return refType.Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
func isSupportedType(refType reflect.Type) bool {
|
||||
switch refType.Kind() {
|
||||
case reflect.Chan, reflect.Complex64, reflect.Complex128, reflect.Func, reflect.UnsafePointer, reflect.Uintptr:
|
||||
return false
|
||||
case reflect.Array, reflect.Slice:
|
||||
return isSupportedType(refType.Elem())
|
||||
case reflect.Map:
|
||||
return isSupportedType(refType.Key()) && isSupportedType(refType.Elem())
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var (
|
||||
pbMsgInterfaceType = reflect.TypeOf((*protoreflect.ProtoMessage)(nil)).Elem()
|
||||
timestampType = reflect.TypeOf(time.Now())
|
||||
durationType = reflect.TypeOf(time.Nanosecond)
|
||||
)
|
145
vendor/github.com/google/cel-go/ext/protos.go
generated
vendored
Normal file
145
vendor/github.com/google/cel-go/ext/protos.go
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
// 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
|
||||
//
|
||||
// http://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 ext
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Protos returns a cel.EnvOption to configure extended macros and functions for
|
||||
// proto manipulation.
|
||||
//
|
||||
// Note, all macros use the 'proto' namespace; however, at the time of macro
|
||||
// expansion the namespace looks just like any other identifier. If you are
|
||||
// currently using a variable named 'proto', the macro will likely work just as
|
||||
// intended; however, there is some chance for collision.
|
||||
//
|
||||
// # Protos.GetExt
|
||||
//
|
||||
// Macro which generates a select expression that retrieves an extension field
|
||||
// from the input proto2 syntax message. If the field is not set, the default
|
||||
// value forthe extension field is returned according to safe-traversal semantics.
|
||||
//
|
||||
// proto.getExt(<msg>, <fully.qualified.extension.name>) -> <field-type>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// proto.getExt(msg, google.expr.proto2.test.int32_ext) // returns int value
|
||||
//
|
||||
// # Protos.HasExt
|
||||
//
|
||||
// Macro which generates a test-only select expression that determines whether
|
||||
// an extension field is set on a proto2 syntax message.
|
||||
//
|
||||
// proto.hasExt(<msg>, <fully.qualified.extension.name>) -> <bool>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// proto.hasExt(msg, google.expr.proto2.test.int32_ext) // returns true || false
|
||||
func Protos() cel.EnvOption {
|
||||
return cel.Lib(protoLib{})
|
||||
}
|
||||
|
||||
var (
|
||||
protoNamespace = "proto"
|
||||
hasExtension = "hasExt"
|
||||
getExtension = "getExt"
|
||||
)
|
||||
|
||||
type protoLib struct{}
|
||||
|
||||
// LibraryName implements the SingletonLibrary interface method.
|
||||
func (protoLib) LibraryName() string {
|
||||
return "cel.lib.ext.protos"
|
||||
}
|
||||
|
||||
// CompileOptions implements the Library interface method.
|
||||
func (protoLib) CompileOptions() []cel.EnvOption {
|
||||
return []cel.EnvOption{
|
||||
cel.Macros(
|
||||
// proto.getExt(msg, select_expression)
|
||||
cel.NewReceiverMacro(getExtension, 2, getProtoExt),
|
||||
// proto.hasExt(msg, select_expression)
|
||||
cel.NewReceiverMacro(hasExtension, 2, hasProtoExt),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// ProgramOptions implements the Library interface method.
|
||||
func (protoLib) ProgramOptions() []cel.ProgramOption {
|
||||
return []cel.ProgramOption{}
|
||||
}
|
||||
|
||||
// hasProtoExt generates a test-only select expression for a fully-qualified extension name on a protobuf message.
|
||||
func hasProtoExt(meh cel.MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
if !macroTargetMatchesNamespace(protoNamespace, target) {
|
||||
return nil, nil
|
||||
}
|
||||
extensionField, err := getExtFieldName(meh, args[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return meh.PresenceTest(args[0], extensionField), nil
|
||||
}
|
||||
|
||||
// getProtoExt generates a select expression for a fully-qualified extension name on a protobuf message.
|
||||
func getProtoExt(meh cel.MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
if !macroTargetMatchesNamespace(protoNamespace, target) {
|
||||
return nil, nil
|
||||
}
|
||||
extFieldName, err := getExtFieldName(meh, args[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return meh.Select(args[0], extFieldName), nil
|
||||
}
|
||||
|
||||
func getExtFieldName(meh cel.MacroExprHelper, expr *exprpb.Expr) (string, *common.Error) {
|
||||
isValid := false
|
||||
extensionField := ""
|
||||
switch expr.GetExprKind().(type) {
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
extensionField, isValid = validateIdentifier(expr)
|
||||
}
|
||||
if !isValid {
|
||||
return "", &common.Error{
|
||||
Message: "invalid extension field",
|
||||
Location: meh.OffsetLocation(expr.GetId()),
|
||||
}
|
||||
}
|
||||
return extensionField, nil
|
||||
}
|
||||
|
||||
func validateIdentifier(expr *exprpb.Expr) (string, bool) {
|
||||
switch expr.GetExprKind().(type) {
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
return expr.GetIdentExpr().GetName(), true
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
sel := expr.GetSelectExpr()
|
||||
if sel.GetTestOnly() {
|
||||
return "", false
|
||||
}
|
||||
opStr, isIdent := validateIdentifier(sel.GetOperand())
|
||||
if !isIdent {
|
||||
return "", false
|
||||
}
|
||||
return opStr + "." + sel.GetField(), true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
138
vendor/github.com/google/cel-go/ext/sets.go
generated
vendored
Normal file
138
vendor/github.com/google/cel-go/ext/sets.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// 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
|
||||
//
|
||||
// http://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 ext
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
)
|
||||
|
||||
// Sets returns a cel.EnvOption to configure namespaced set relationship
|
||||
// functions.
|
||||
//
|
||||
// There is no set type within CEL, and while one may be introduced in the
|
||||
// future, there are cases where a `list` type is known to behave like a set.
|
||||
// For such cases, this library provides some basic functionality for
|
||||
// determining set containment, equivalence, and intersection.
|
||||
//
|
||||
// # Sets.Contains
|
||||
//
|
||||
// Returns whether the first list argument contains all elements in the second
|
||||
// list argument. The list may contain elements of any type and standard CEL
|
||||
// equality is used to determine whether a value exists in both lists. If the
|
||||
// second list is empty, the result will always return true.
|
||||
//
|
||||
// sets.contains(list(T), list(T)) -> bool
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// sets.contains([], []) // true
|
||||
// sets.contains([], [1]) // false
|
||||
// sets.contains([1, 2, 3, 4], [2, 3]) // true
|
||||
// sets.contains([1, 2.0, 3u], [1.0, 2u, 3]) // true
|
||||
//
|
||||
// # Sets.Equivalent
|
||||
//
|
||||
// Returns whether the first and second list are set equivalent. Lists are set
|
||||
// equivalent if for every item in the first list, there is an element in the
|
||||
// second which is equal. The lists may not be of the same size as they do not
|
||||
// guarantee the elements within them are unique, so size does not factor into
|
||||
// the computation.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// sets.equivalent([], []) // true
|
||||
// sets.equivalent([1], [1, 1]) // true
|
||||
// sets.equivalent([1], [1u, 1.0]) // true
|
||||
// sets.equivalent([1, 2, 3], [3u, 2.0, 1]) // true
|
||||
//
|
||||
// # Sets.Intersects
|
||||
//
|
||||
// Returns whether the first list has at least one element whose value is equal
|
||||
// to an element in the second list. If either list is empty, the result will
|
||||
// be false.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// sets.intersects([1], []) // false
|
||||
// sets.intersects([1], [1, 2]) // true
|
||||
// sets.intersects([[1], [2, 3]], [[1, 2], [2, 3.0]]) // true
|
||||
func Sets() cel.EnvOption {
|
||||
return cel.Lib(setsLib{})
|
||||
}
|
||||
|
||||
type setsLib struct{}
|
||||
|
||||
// LibraryName implements the SingletonLibrary interface method.
|
||||
func (setsLib) LibraryName() string {
|
||||
return "cel.lib.ext.sets"
|
||||
}
|
||||
|
||||
// CompileOptions implements the Library interface method.
|
||||
func (setsLib) CompileOptions() []cel.EnvOption {
|
||||
listType := cel.ListType(cel.TypeParamType("T"))
|
||||
return []cel.EnvOption{
|
||||
cel.Function("sets.contains",
|
||||
cel.Overload("list_sets_contains_list", []*cel.Type{listType, listType}, cel.BoolType,
|
||||
cel.BinaryBinding(setsContains))),
|
||||
cel.Function("sets.equivalent",
|
||||
cel.Overload("list_sets_equivalent_list", []*cel.Type{listType, listType}, cel.BoolType,
|
||||
cel.BinaryBinding(setsEquivalent))),
|
||||
cel.Function("sets.intersects",
|
||||
cel.Overload("list_sets_intersects_list", []*cel.Type{listType, listType}, cel.BoolType,
|
||||
cel.BinaryBinding(setsIntersects))),
|
||||
}
|
||||
}
|
||||
|
||||
// ProgramOptions implements the Library interface method.
|
||||
func (setsLib) ProgramOptions() []cel.ProgramOption {
|
||||
return []cel.ProgramOption{}
|
||||
}
|
||||
|
||||
func setsIntersects(listA, listB ref.Val) ref.Val {
|
||||
lA := listA.(traits.Lister)
|
||||
lB := listB.(traits.Lister)
|
||||
it := lA.Iterator()
|
||||
for it.HasNext() == types.True {
|
||||
exists := lB.Contains(it.Next())
|
||||
if exists == types.True {
|
||||
return types.True
|
||||
}
|
||||
}
|
||||
return types.False
|
||||
}
|
||||
|
||||
func setsContains(list, sublist ref.Val) ref.Val {
|
||||
l := list.(traits.Lister)
|
||||
sub := sublist.(traits.Lister)
|
||||
it := sub.Iterator()
|
||||
for it.HasNext() == types.True {
|
||||
exists := l.Contains(it.Next())
|
||||
if exists != types.True {
|
||||
return exists
|
||||
}
|
||||
}
|
||||
return types.True
|
||||
}
|
||||
|
||||
func setsEquivalent(listA, listB ref.Val) ref.Val {
|
||||
aContainsB := setsContains(listA, listB)
|
||||
if aContainsB != types.True {
|
||||
return aContainsB
|
||||
}
|
||||
return setsContains(listB, listA)
|
||||
}
|
778
vendor/github.com/google/cel-go/ext/strings.go
generated
vendored
778
vendor/github.com/google/cel-go/ext/strings.go
generated
vendored
@ -19,32 +19,92 @@ package ext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
"github.com/google/cel-go/interpreter"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLocale = "en-US"
|
||||
defaultPrecision = 6
|
||||
)
|
||||
|
||||
// Strings returns a cel.EnvOption to configure extended functions for string manipulation.
|
||||
// As a general note, all indices are zero-based.
|
||||
//
|
||||
// CharAt
|
||||
// # CharAt
|
||||
//
|
||||
// Returns the character at the given position. If the position is negative, or greater than
|
||||
// the length of the string, the function will produce an error:
|
||||
//
|
||||
// <string>.charAt(<int>) -> <string>
|
||||
// <string>.charAt(<int>) -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'hello'.charAt(4) // return 'o'
|
||||
// 'hello'.charAt(5) // return ''
|
||||
// 'hello'.charAt(-1) // error
|
||||
// 'hello'.charAt(4) // return 'o'
|
||||
// 'hello'.charAt(5) // return ''
|
||||
// 'hello'.charAt(-1) // error
|
||||
//
|
||||
// IndexOf
|
||||
// # Format
|
||||
//
|
||||
// Introduced at version: 1
|
||||
//
|
||||
// Returns a new string with substitutions being performed, printf-style.
|
||||
// The valid formatting clauses are:
|
||||
//
|
||||
// `%s` - substitutes a string. This can also be used on bools, lists, maps, bytes,
|
||||
// Duration and Timestamp, in addition to all numerical types (int, uint, and double).
|
||||
// Note that the dot/period decimal separator will always be used when printing a list
|
||||
// or map that contains a double, and that null can be passed (which results in the
|
||||
// string "null") in addition to types.
|
||||
// `%d` - substitutes an integer.
|
||||
// `%f` - substitutes a double with fixed-point precision. The default precision is 6, but
|
||||
// this can be adjusted. The strings `Infinity`, `-Infinity`, and `NaN` are also valid input
|
||||
// for this clause.
|
||||
// `%e` - substitutes a double in scientific notation. The default precision is 6, but this
|
||||
// can be adjusted.
|
||||
// `%b` - substitutes an integer with its equivalent binary string. Can also be used on bools.
|
||||
// `%x` - substitutes an integer with its equivalent in hexadecimal, or if given a string or
|
||||
// bytes, will output each character's equivalent in hexadecimal.
|
||||
// `%X` - same as above, but with A-F capitalized.
|
||||
// `%o` - substitutes an integer with its equivalent in octal.
|
||||
//
|
||||
// <string>.format(<list>) -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// "this is a string: %s\nand an integer: %d".format(["str", 42]) // returns "this is a string: str\nand an integer: 42"
|
||||
// "a double substituted with %%s: %s".format([64.2]) // returns "a double substituted with %s: 64.2"
|
||||
// "string type: %s".format([type(string)]) // returns "string type: string"
|
||||
// "timestamp: %s".format([timestamp("2023-02-03T23:31:20+00:00")]) // returns "timestamp: 2023-02-03T23:31:20Z"
|
||||
// "duration: %s".format([duration("1h45m47s")]) // returns "duration: 6347s"
|
||||
// "%f".format([3.14]) // returns "3.140000"
|
||||
// "scientific notation: %e".format([2.71828]) // returns "scientific notation: 2.718280\u202f\u00d7\u202f10\u2070\u2070"
|
||||
// "5 in binary: %b".format([5]), // returns "5 in binary; 101"
|
||||
// "26 in hex: %x".format([26]), // returns "26 in hex: 1a"
|
||||
// "26 in hex (uppercase): %X".format([26]) // returns "26 in hex (uppercase): 1A"
|
||||
// "30 in octal: %o".format([30]) // returns "30 in octal: 36"
|
||||
// "a map inside a list: %s".format([[1, 2, 3, {"a": "x", "b": "y", "c": "z"}]]) // returns "a map inside a list: [1, 2, 3, {"a":"x", "b":"y", "c":"d"}]"
|
||||
// "true bool: %s - false bool: %s\nbinary bool: %b".format([true, false, true]) // returns "true bool: true - false bool: false\nbinary bool: 1"
|
||||
//
|
||||
// Passing an incorrect type (an integer to `%s`) is considered an error, as well as attempting
|
||||
// to use more formatting clauses than there are arguments (`%d %d %d` while passing two ints, for instance).
|
||||
// If compile-time checking is enabled, and the formatting string is a constant, and the argument list is a literal,
|
||||
// then letting any arguments go unused/unformatted is also considered an error.
|
||||
//
|
||||
// # IndexOf
|
||||
//
|
||||
// Returns the integer index of the first occurrence of the search string. If the search string is
|
||||
// not found the function returns -1.
|
||||
@ -52,19 +112,19 @@ import (
|
||||
// The function also accepts an optional position from which to begin the substring search. If the
|
||||
// substring is the empty string, the index where the search starts is returned (zero or custom).
|
||||
//
|
||||
// <string>.indexOf(<string>) -> <int>
|
||||
// <string>.indexOf(<string>, <int>) -> <int>
|
||||
// <string>.indexOf(<string>) -> <int>
|
||||
// <string>.indexOf(<string>, <int>) -> <int>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'hello mellow'.indexOf('') // returns 0
|
||||
// 'hello mellow'.indexOf('ello') // returns 1
|
||||
// 'hello mellow'.indexOf('jello') // returns -1
|
||||
// 'hello mellow'.indexOf('', 2) // returns 2
|
||||
// 'hello mellow'.indexOf('ello', 2) // returns 7
|
||||
// 'hello mellow'.indexOf('ello', 20) // error
|
||||
// 'hello mellow'.indexOf('') // returns 0
|
||||
// 'hello mellow'.indexOf('ello') // returns 1
|
||||
// 'hello mellow'.indexOf('jello') // returns -1
|
||||
// 'hello mellow'.indexOf('', 2) // returns 2
|
||||
// 'hello mellow'.indexOf('ello', 2) // returns 7
|
||||
// 'hello mellow'.indexOf('ello', 20) // error
|
||||
//
|
||||
// Join
|
||||
// # Join
|
||||
//
|
||||
// Returns a new string where the elements of string list are concatenated.
|
||||
//
|
||||
@ -75,12 +135,12 @@ import (
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ['hello', 'mellow'].join() // returns 'hellomellow'
|
||||
// ['hello', 'mellow'].join(' ') // returns 'hello mellow'
|
||||
// [].join() // returns ''
|
||||
// [].join('/') // returns ''
|
||||
// ['hello', 'mellow'].join() // returns 'hellomellow'
|
||||
// ['hello', 'mellow'].join(' ') // returns 'hello mellow'
|
||||
// [].join() // returns ''
|
||||
// [].join('/') // returns ''
|
||||
//
|
||||
// LastIndexOf
|
||||
// # LastIndexOf
|
||||
//
|
||||
// Returns the integer index at the start of the last occurrence of the search string. If the
|
||||
// search string is not found the function returns -1.
|
||||
@ -89,31 +149,45 @@ import (
|
||||
// considered as the beginning of the substring match. If the substring is the empty string,
|
||||
// the index where the search starts is returned (string length or custom).
|
||||
//
|
||||
// <string>.lastIndexOf(<string>) -> <int>
|
||||
// <string>.lastIndexOf(<string>, <int>) -> <int>
|
||||
// <string>.lastIndexOf(<string>) -> <int>
|
||||
// <string>.lastIndexOf(<string>, <int>) -> <int>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'hello mellow'.lastIndexOf('') // returns 12
|
||||
// 'hello mellow'.lastIndexOf('ello') // returns 7
|
||||
// 'hello mellow'.lastIndexOf('jello') // returns -1
|
||||
// 'hello mellow'.lastIndexOf('ello', 6) // returns 1
|
||||
// 'hello mellow'.lastIndexOf('ello', -1) // error
|
||||
// 'hello mellow'.lastIndexOf('') // returns 12
|
||||
// 'hello mellow'.lastIndexOf('ello') // returns 7
|
||||
// 'hello mellow'.lastIndexOf('jello') // returns -1
|
||||
// 'hello mellow'.lastIndexOf('ello', 6) // returns 1
|
||||
// 'hello mellow'.lastIndexOf('ello', -1) // error
|
||||
//
|
||||
// LowerAscii
|
||||
// # LowerAscii
|
||||
//
|
||||
// Returns a new string where all ASCII characters are lower-cased.
|
||||
//
|
||||
// This function does not perform Unicode case-mapping for characters outside the ASCII range.
|
||||
//
|
||||
// <string>.lowerAscii() -> <string>
|
||||
// <string>.lowerAscii() -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'TacoCat'.lowerAscii() // returns 'tacocat'
|
||||
// 'TacoCÆt Xii'.lowerAscii() // returns 'tacocÆt xii'
|
||||
// 'TacoCat'.lowerAscii() // returns 'tacocat'
|
||||
// 'TacoCÆt Xii'.lowerAscii() // returns 'tacocÆt xii'
|
||||
//
|
||||
// Replace
|
||||
// # Quote
|
||||
//
|
||||
// Introduced in version: 1
|
||||
//
|
||||
// Takes the given string and makes it safe to print (without any formatting due to escape sequences).
|
||||
// If any invalid UTF-8 characters are encountered, they are replaced with \uFFFD.
|
||||
//
|
||||
// strings.quote(<string>)
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// strings.quote('single-quote with "double quote"') // returns '"single-quote with \"double quote\""'
|
||||
// strings.quote("two escape sequences \a\n") // returns '"two escape sequences \\a\\n"'
|
||||
//
|
||||
// # Replace
|
||||
//
|
||||
// Returns a new string based on the target, which replaces the occurrences of a search string
|
||||
// with a replacement string if present. The function accepts an optional limit on the number of
|
||||
@ -122,17 +196,17 @@ import (
|
||||
// When the replacement limit is 0, the result is the original string. When the limit is a negative
|
||||
// number, the function behaves the same as replace all.
|
||||
//
|
||||
// <string>.replace(<string>, <string>) -> <string>
|
||||
// <string>.replace(<string>, <string>, <int>) -> <string>
|
||||
// <string>.replace(<string>, <string>) -> <string>
|
||||
// <string>.replace(<string>, <string>, <int>) -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'hello hello'.replace('he', 'we') // returns 'wello wello'
|
||||
// 'hello hello'.replace('he', 'we', -1) // returns 'wello wello'
|
||||
// 'hello hello'.replace('he', 'we', 1) // returns 'wello hello'
|
||||
// 'hello hello'.replace('he', 'we', 0) // returns 'hello hello'
|
||||
// 'hello hello'.replace('he', 'we') // returns 'wello wello'
|
||||
// 'hello hello'.replace('he', 'we', -1) // returns 'wello wello'
|
||||
// 'hello hello'.replace('he', 'we', 1) // returns 'wello hello'
|
||||
// 'hello hello'.replace('he', 'we', 0) // returns 'hello hello'
|
||||
//
|
||||
// Split
|
||||
// # Split
|
||||
//
|
||||
// Returns a list of strings split from the input by the given separator. The function accepts
|
||||
// an optional argument specifying a limit on the number of substrings produced by the split.
|
||||
@ -141,18 +215,18 @@ import (
|
||||
// target string to split. When the limit is a negative number, the function behaves the same as
|
||||
// split all.
|
||||
//
|
||||
// <string>.split(<string>) -> <list<string>>
|
||||
// <string>.split(<string>, <int>) -> <list<string>>
|
||||
// <string>.split(<string>) -> <list<string>>
|
||||
// <string>.split(<string>, <int>) -> <list<string>>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'hello hello hello'.split(' ') // returns ['hello', 'hello', 'hello']
|
||||
// 'hello hello hello'.split(' ', 0) // returns []
|
||||
// 'hello hello hello'.split(' ', 1) // returns ['hello hello hello']
|
||||
// 'hello hello hello'.split(' ', 2) // returns ['hello', 'hello hello']
|
||||
// 'hello hello hello'.split(' ', -1) // returns ['hello', 'hello', 'hello']
|
||||
// 'hello hello hello'.split(' ') // returns ['hello', 'hello', 'hello']
|
||||
// 'hello hello hello'.split(' ', 0) // returns []
|
||||
// 'hello hello hello'.split(' ', 1) // returns ['hello hello hello']
|
||||
// 'hello hello hello'.split(' ', 2) // returns ['hello', 'hello hello']
|
||||
// 'hello hello hello'.split(' ', -1) // returns ['hello', 'hello', 'hello']
|
||||
//
|
||||
// Substring
|
||||
// # Substring
|
||||
//
|
||||
// Returns the substring given a numeric range corresponding to character positions. Optionally
|
||||
// may omit the trailing range for a substring from a given character position until the end of
|
||||
@ -162,48 +236,102 @@ import (
|
||||
// error to specify an end range that is lower than the start range, or for either the start or end
|
||||
// index to be negative or exceed the string length.
|
||||
//
|
||||
// <string>.substring(<int>) -> <string>
|
||||
// <string>.substring(<int>, <int>) -> <string>
|
||||
// <string>.substring(<int>) -> <string>
|
||||
// <string>.substring(<int>, <int>) -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'tacocat'.substring(4) // returns 'cat'
|
||||
// 'tacocat'.substring(0, 4) // returns 'taco'
|
||||
// 'tacocat'.substring(-1) // error
|
||||
// 'tacocat'.substring(2, 1) // error
|
||||
// 'tacocat'.substring(4) // returns 'cat'
|
||||
// 'tacocat'.substring(0, 4) // returns 'taco'
|
||||
// 'tacocat'.substring(-1) // error
|
||||
// 'tacocat'.substring(2, 1) // error
|
||||
//
|
||||
// Trim
|
||||
// # Trim
|
||||
//
|
||||
// Returns a new string which removes the leading and trailing whitespace in the target string.
|
||||
// The trim function uses the Unicode definition of whitespace which does not include the
|
||||
// zero-width spaces. See: https://en.wikipedia.org/wiki/Whitespace_character#Unicode
|
||||
//
|
||||
// <string>.trim() -> <string>
|
||||
// <string>.trim() -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ' \ttrim\n '.trim() // returns 'trim'
|
||||
// ' \ttrim\n '.trim() // returns 'trim'
|
||||
//
|
||||
// UpperAscii
|
||||
// # UpperAscii
|
||||
//
|
||||
// Returns a new string where all ASCII characters are upper-cased.
|
||||
//
|
||||
// This function does not perform Unicode case-mapping for characters outside the ASCII range.
|
||||
//
|
||||
// <string>.upperAscii() -> <string>
|
||||
// <string>.upperAscii() -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'TacoCat'.upperAscii() // returns 'TACOCAT'
|
||||
// 'TacoCÆt Xii'.upperAscii() // returns 'TACOCÆT XII'
|
||||
func Strings() cel.EnvOption {
|
||||
return cel.Lib(stringLib{})
|
||||
// 'TacoCat'.upperAscii() // returns 'TACOCAT'
|
||||
// 'TacoCÆt Xii'.upperAscii() // returns 'TACOCÆT XII'
|
||||
func Strings(options ...StringsOption) cel.EnvOption {
|
||||
s := &stringLib{version: math.MaxUint32}
|
||||
for _, o := range options {
|
||||
s = o(s)
|
||||
}
|
||||
return cel.Lib(s)
|
||||
}
|
||||
|
||||
type stringLib struct{}
|
||||
type stringLib struct {
|
||||
locale string
|
||||
version uint32
|
||||
}
|
||||
|
||||
func (stringLib) CompileOptions() []cel.EnvOption {
|
||||
return []cel.EnvOption{
|
||||
// LibraryName implements the SingletonLibrary interface method.
|
||||
func (*stringLib) LibraryName() string {
|
||||
return "cel.lib.ext.strings"
|
||||
}
|
||||
|
||||
// StringsOption is a functional interface for configuring the strings library.
|
||||
type StringsOption func(*stringLib) *stringLib
|
||||
|
||||
// StringsLocale configures the library with the given locale. The locale tag will
|
||||
// be checked for validity at the time that EnvOptions are configured. If this option
|
||||
// is not passed, string.format will behave as if en_US was passed as the locale.
|
||||
func StringsLocale(locale string) StringsOption {
|
||||
return func(sl *stringLib) *stringLib {
|
||||
sl.locale = locale
|
||||
return sl
|
||||
}
|
||||
}
|
||||
|
||||
// StringsVersion configures the version of the string library. The version limits which
|
||||
// functions are available. Only functions introduced below or equal to the given
|
||||
// version included in the library. See the library documentation to determine
|
||||
// which version a function was introduced at. If the documentation does not
|
||||
// state which version a function was introduced at, it can be assumed to be
|
||||
// introduced at version 0, when the library was first created.
|
||||
// If this option is not set, all functions are available.
|
||||
func StringsVersion(version uint32) func(lib *stringLib) *stringLib {
|
||||
return func(sl *stringLib) *stringLib {
|
||||
sl.version = version
|
||||
return sl
|
||||
}
|
||||
}
|
||||
|
||||
// CompileOptions implements the Library interface method.
|
||||
func (sl *stringLib) CompileOptions() []cel.EnvOption {
|
||||
formatLocale := "en_US"
|
||||
if sl.locale != "" {
|
||||
// ensure locale is properly-formed if set
|
||||
_, err := language.Parse(sl.locale)
|
||||
if err != nil {
|
||||
return []cel.EnvOption{
|
||||
func(e *cel.Env) (*cel.Env, error) {
|
||||
return nil, fmt.Errorf("failed to parse locale: %w", err)
|
||||
},
|
||||
}
|
||||
}
|
||||
formatLocale = sl.locale
|
||||
}
|
||||
|
||||
opts := []cel.EnvOption{
|
||||
cel.Function("charAt",
|
||||
cel.MemberOverload("string_char_at_int", []*cel.Type{cel.StringType, cel.IntType}, cel.StringType,
|
||||
cel.BinaryBinding(func(str, ind ref.Val) ref.Val {
|
||||
@ -303,28 +431,64 @@ func (stringLib) CompileOptions() []cel.EnvOption {
|
||||
s := str.(types.String)
|
||||
return stringOrError(upperASCII(string(s)))
|
||||
}))),
|
||||
cel.Function("join",
|
||||
cel.MemberOverload("list_join", []*cel.Type{cel.ListType(cel.StringType)}, cel.StringType,
|
||||
cel.UnaryBinding(func(list ref.Val) ref.Val {
|
||||
l, err := list.ConvertToNative(stringListType)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return stringOrError(join(l.([]string)))
|
||||
})),
|
||||
cel.MemberOverload("list_join_string", []*cel.Type{cel.ListType(cel.StringType), cel.StringType}, cel.StringType,
|
||||
cel.BinaryBinding(func(list, delim ref.Val) ref.Val {
|
||||
l, err := list.ConvertToNative(stringListType)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
d := delim.(types.String)
|
||||
return stringOrError(joinSeparator(l.([]string), string(d)))
|
||||
}))),
|
||||
}
|
||||
if sl.version >= 1 {
|
||||
opts = append(opts, cel.Function("format",
|
||||
cel.MemberOverload("string_format", []*cel.Type{cel.StringType, cel.ListType(cel.DynType)}, cel.StringType,
|
||||
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
|
||||
s := string(args[0].(types.String))
|
||||
formatArgs := args[1].(traits.Lister)
|
||||
return stringOrError(interpreter.ParseFormatString(s, &stringFormatter{}, &stringArgList{formatArgs}, formatLocale))
|
||||
}))),
|
||||
cel.Function("strings.quote", cel.Overload("strings_quote", []*cel.Type{cel.StringType}, cel.StringType,
|
||||
cel.UnaryBinding(func(str ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
return stringOrError(quote(string(s)))
|
||||
}))))
|
||||
|
||||
}
|
||||
if sl.version >= 2 {
|
||||
opts = append(opts,
|
||||
cel.Function("join",
|
||||
cel.MemberOverload("list_join", []*cel.Type{cel.ListType(cel.StringType)}, cel.StringType,
|
||||
cel.UnaryBinding(func(list ref.Val) ref.Val {
|
||||
l := list.(traits.Lister)
|
||||
return stringOrError(joinValSeparator(l, ""))
|
||||
})),
|
||||
cel.MemberOverload("list_join_string", []*cel.Type{cel.ListType(cel.StringType), cel.StringType}, cel.StringType,
|
||||
cel.BinaryBinding(func(list, delim ref.Val) ref.Val {
|
||||
l := list.(traits.Lister)
|
||||
d := delim.(types.String)
|
||||
return stringOrError(joinValSeparator(l, string(d)))
|
||||
}))),
|
||||
)
|
||||
} else {
|
||||
opts = append(opts,
|
||||
cel.Function("join",
|
||||
cel.MemberOverload("list_join", []*cel.Type{cel.ListType(cel.StringType)}, cel.StringType,
|
||||
cel.UnaryBinding(func(list ref.Val) ref.Val {
|
||||
l, err := list.ConvertToNative(stringListType)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return stringOrError(join(l.([]string)))
|
||||
})),
|
||||
cel.MemberOverload("list_join_string", []*cel.Type{cel.ListType(cel.StringType), cel.StringType}, cel.StringType,
|
||||
cel.BinaryBinding(func(list, delim ref.Val) ref.Val {
|
||||
l, err := list.ConvertToNative(stringListType)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
d := delim.(types.String)
|
||||
return stringOrError(joinSeparator(l.([]string), string(d)))
|
||||
}))),
|
||||
)
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
func (stringLib) ProgramOptions() []cel.ProgramOption {
|
||||
// ProgramOptions implements the Library interface method.
|
||||
func (*stringLib) ProgramOptions() []cel.ProgramOption {
|
||||
return []cel.ProgramOption{}
|
||||
}
|
||||
|
||||
@ -478,6 +642,452 @@ func join(strs []string) (string, error) {
|
||||
return strings.Join(strs, ""), nil
|
||||
}
|
||||
|
||||
func joinValSeparator(strs traits.Lister, separator string) (string, error) {
|
||||
sz := strs.Size().(types.Int)
|
||||
var sb strings.Builder
|
||||
for i := types.Int(0); i < sz; i++ {
|
||||
if i != 0 {
|
||||
sb.WriteString(separator)
|
||||
}
|
||||
elem := strs.Get(i)
|
||||
str, ok := elem.(types.String)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("join: invalid input: %v", elem)
|
||||
}
|
||||
sb.WriteString(string(str))
|
||||
}
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
type clauseImpl func(ref.Val, string) (string, error)
|
||||
|
||||
func clauseForType(argType ref.Type) (clauseImpl, error) {
|
||||
switch argType {
|
||||
case types.IntType, types.UintType:
|
||||
return formatDecimal, nil
|
||||
case types.StringType, types.BytesType, types.BoolType, types.NullType, types.TypeType:
|
||||
return FormatString, nil
|
||||
case types.TimestampType, types.DurationType:
|
||||
// special case to ensure timestamps/durations get printed as CEL literals
|
||||
return func(arg ref.Val, locale string) (string, error) {
|
||||
argStrVal := arg.ConvertToType(types.StringType)
|
||||
argStr := argStrVal.Value().(string)
|
||||
if arg.Type() == types.TimestampType {
|
||||
return fmt.Sprintf("timestamp(%q)", argStr), nil
|
||||
}
|
||||
if arg.Type() == types.DurationType {
|
||||
return fmt.Sprintf("duration(%q)", argStr), nil
|
||||
}
|
||||
return "", fmt.Errorf("cannot convert argument of type %s to timestamp/duration", arg.Type().TypeName())
|
||||
}, nil
|
||||
case types.ListType:
|
||||
return formatList, nil
|
||||
case types.MapType:
|
||||
return formatMap, nil
|
||||
case types.DoubleType:
|
||||
// avoid formatFixed so we can output a period as the decimal separator in order
|
||||
// to always be a valid CEL literal
|
||||
return func(arg ref.Val, locale string) (string, error) {
|
||||
argDouble, ok := arg.Value().(float64)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("couldn't convert %s to float64", arg.Type().TypeName())
|
||||
}
|
||||
fmtStr := fmt.Sprintf("%%.%df", defaultPrecision)
|
||||
return fmt.Sprintf(fmtStr, argDouble), nil
|
||||
}, nil
|
||||
case types.TypeType:
|
||||
return func(arg ref.Val, locale string) (string, error) {
|
||||
return fmt.Sprintf("type(%s)", arg.Value().(string)), nil
|
||||
}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("no formatting function for %s", argType.TypeName())
|
||||
}
|
||||
}
|
||||
|
||||
func formatList(arg ref.Val, locale string) (string, error) {
|
||||
argList := arg.(traits.Lister)
|
||||
argIterator := argList.Iterator()
|
||||
var listStrBuilder strings.Builder
|
||||
_, err := listStrBuilder.WriteRune('[')
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing to list string: %w", err)
|
||||
}
|
||||
for argIterator.HasNext() == types.True {
|
||||
member := argIterator.Next()
|
||||
memberFormat, err := clauseForType(member.Type())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
unquotedStr, err := memberFormat(member, locale)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
str := quoteForCEL(member, unquotedStr)
|
||||
_, err = listStrBuilder.WriteString(str)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing to list string: %w", err)
|
||||
}
|
||||
if argIterator.HasNext() == types.True {
|
||||
_, err = listStrBuilder.WriteString(", ")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing to list string: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = listStrBuilder.WriteRune(']')
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing to list string: %w", err)
|
||||
}
|
||||
return listStrBuilder.String(), nil
|
||||
}
|
||||
|
||||
func formatMap(arg ref.Val, locale string) (string, error) {
|
||||
argMap := arg.(traits.Mapper)
|
||||
argIterator := argMap.Iterator()
|
||||
type mapPair struct {
|
||||
key string
|
||||
value string
|
||||
}
|
||||
argPairs := make([]mapPair, argMap.Size().Value().(int64))
|
||||
i := 0
|
||||
for argIterator.HasNext() == types.True {
|
||||
key := argIterator.Next()
|
||||
var keyFormat clauseImpl
|
||||
switch key.Type() {
|
||||
case types.StringType, types.BoolType:
|
||||
keyFormat = FormatString
|
||||
case types.IntType, types.UintType:
|
||||
keyFormat = formatDecimal
|
||||
default:
|
||||
return "", fmt.Errorf("no formatting function for map key of type %s", key.Type().TypeName())
|
||||
}
|
||||
unquotedKeyStr, err := keyFormat(key, locale)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
keyStr := quoteForCEL(key, unquotedKeyStr)
|
||||
value, found := argMap.Find(key)
|
||||
if !found {
|
||||
return "", fmt.Errorf("could not find key: %q", key)
|
||||
}
|
||||
valueFormat, err := clauseForType(value.Type())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
unquotedValueStr, err := valueFormat(value, locale)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
valueStr := quoteForCEL(value, unquotedValueStr)
|
||||
argPairs[i] = mapPair{keyStr, valueStr}
|
||||
i++
|
||||
}
|
||||
sort.SliceStable(argPairs, func(x, y int) bool {
|
||||
return argPairs[x].key < argPairs[y].key
|
||||
})
|
||||
var mapStrBuilder strings.Builder
|
||||
_, err := mapStrBuilder.WriteRune('{')
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing to map string: %w", err)
|
||||
}
|
||||
for i, entry := range argPairs {
|
||||
_, err = mapStrBuilder.WriteString(fmt.Sprintf("%s:%s", entry.key, entry.value))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing to map string: %w", err)
|
||||
}
|
||||
if i < len(argPairs)-1 {
|
||||
_, err = mapStrBuilder.WriteString(", ")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing to map string: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = mapStrBuilder.WriteRune('}')
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing to map string: %w", err)
|
||||
}
|
||||
return mapStrBuilder.String(), nil
|
||||
}
|
||||
|
||||
// quoteForCEL takes a formatted, unquoted value and quotes it in a manner
|
||||
// suitable for embedding directly in CEL.
|
||||
func quoteForCEL(refVal ref.Val, unquotedValue string) string {
|
||||
switch refVal.Type() {
|
||||
case types.StringType:
|
||||
return fmt.Sprintf("%q", unquotedValue)
|
||||
case types.BytesType:
|
||||
return fmt.Sprintf("b%q", unquotedValue)
|
||||
case types.DoubleType:
|
||||
// special case to handle infinity/NaN
|
||||
num := refVal.Value().(float64)
|
||||
if math.IsInf(num, 1) || math.IsInf(num, -1) || math.IsNaN(num) {
|
||||
return fmt.Sprintf("%q", unquotedValue)
|
||||
}
|
||||
return unquotedValue
|
||||
default:
|
||||
return unquotedValue
|
||||
}
|
||||
}
|
||||
|
||||
// FormatString returns the string representation of a CEL value.
|
||||
// It is used to implement the %s specifier in the (string).format() extension
|
||||
// function.
|
||||
func FormatString(arg ref.Val, locale string) (string, error) {
|
||||
switch arg.Type() {
|
||||
case types.ListType:
|
||||
return formatList(arg, locale)
|
||||
case types.MapType:
|
||||
return formatMap(arg, locale)
|
||||
case types.IntType, types.UintType, types.DoubleType,
|
||||
types.BoolType, types.StringType, types.TimestampType, types.BytesType, types.DurationType, types.TypeType:
|
||||
argStrVal := arg.ConvertToType(types.StringType)
|
||||
argStr, ok := argStrVal.Value().(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not convert argument %q to string", argStrVal)
|
||||
}
|
||||
return argStr, nil
|
||||
case types.NullType:
|
||||
return "null", nil
|
||||
default:
|
||||
return "", fmt.Errorf("string clause can only be used on strings, bools, bytes, ints, doubles, maps, lists, types, durations, and timestamps, was given %s", arg.Type().TypeName())
|
||||
}
|
||||
}
|
||||
|
||||
func formatDecimal(arg ref.Val, locale string) (string, error) {
|
||||
switch arg.Type() {
|
||||
case types.IntType:
|
||||
argInt, ok := arg.ConvertToType(types.IntType).Value().(int64)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not convert \"%s\" to int64", arg.Value())
|
||||
}
|
||||
return fmt.Sprintf("%d", argInt), nil
|
||||
case types.UintType:
|
||||
argInt, ok := arg.ConvertToType(types.UintType).Value().(uint64)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not convert \"%s\" to uint64", arg.Value())
|
||||
}
|
||||
return fmt.Sprintf("%d", argInt), nil
|
||||
default:
|
||||
return "", fmt.Errorf("decimal clause can only be used on integers, was given %s", arg.Type().TypeName())
|
||||
}
|
||||
}
|
||||
|
||||
func matchLanguage(locale string) (language.Tag, error) {
|
||||
matcher, err := makeMatcher(locale)
|
||||
if err != nil {
|
||||
return language.Und, err
|
||||
}
|
||||
tag, _ := language.MatchStrings(matcher, locale)
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
func makeMatcher(locale string) (language.Matcher, error) {
|
||||
tags := make([]language.Tag, 0)
|
||||
tag, err := language.Parse(locale)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
return language.NewMatcher(tags), nil
|
||||
}
|
||||
|
||||
// quote implements a string quoting function. The string will be wrapped in
|
||||
// double quotes, and all valid CEL escape sequences will be escaped to show up
|
||||
// literally if printed. If the input contains any invalid UTF-8, the invalid runes
|
||||
// will be replaced with utf8.RuneError.
|
||||
func quote(s string) (string, error) {
|
||||
var quotedStrBuilder strings.Builder
|
||||
for _, c := range sanitize(s) {
|
||||
switch c {
|
||||
case '\a':
|
||||
quotedStrBuilder.WriteString("\\a")
|
||||
case '\b':
|
||||
quotedStrBuilder.WriteString("\\b")
|
||||
case '\f':
|
||||
quotedStrBuilder.WriteString("\\f")
|
||||
case '\n':
|
||||
quotedStrBuilder.WriteString("\\n")
|
||||
case '\r':
|
||||
quotedStrBuilder.WriteString("\\r")
|
||||
case '\t':
|
||||
quotedStrBuilder.WriteString("\\t")
|
||||
case '\v':
|
||||
quotedStrBuilder.WriteString("\\v")
|
||||
case '\\':
|
||||
quotedStrBuilder.WriteString("\\\\")
|
||||
case '"':
|
||||
quotedStrBuilder.WriteString("\\\"")
|
||||
default:
|
||||
quotedStrBuilder.WriteRune(c)
|
||||
}
|
||||
}
|
||||
escapedStr := quotedStrBuilder.String()
|
||||
return "\"" + escapedStr + "\"", nil
|
||||
}
|
||||
|
||||
// sanitize replaces all invalid runes in the given string with utf8.RuneError.
|
||||
func sanitize(s string) string {
|
||||
var sanitizedStringBuilder strings.Builder
|
||||
for _, r := range s {
|
||||
if !utf8.ValidRune(r) {
|
||||
sanitizedStringBuilder.WriteRune(utf8.RuneError)
|
||||
} else {
|
||||
sanitizedStringBuilder.WriteRune(r)
|
||||
}
|
||||
}
|
||||
return sanitizedStringBuilder.String()
|
||||
}
|
||||
|
||||
type stringFormatter struct{}
|
||||
|
||||
func (c *stringFormatter) String(arg ref.Val, locale string) (string, error) {
|
||||
return FormatString(arg, locale)
|
||||
}
|
||||
|
||||
func (c *stringFormatter) Decimal(arg ref.Val, locale string) (string, error) {
|
||||
return formatDecimal(arg, locale)
|
||||
}
|
||||
|
||||
func (c *stringFormatter) Fixed(precision *int) func(ref.Val, string) (string, error) {
|
||||
if precision == nil {
|
||||
precision = new(int)
|
||||
*precision = defaultPrecision
|
||||
}
|
||||
return func(arg ref.Val, locale string) (string, error) {
|
||||
strException := false
|
||||
if arg.Type() == types.StringType {
|
||||
argStr := arg.Value().(string)
|
||||
if argStr == "NaN" || argStr == "Infinity" || argStr == "-Infinity" {
|
||||
strException = true
|
||||
}
|
||||
}
|
||||
if arg.Type() != types.DoubleType && !strException {
|
||||
return "", fmt.Errorf("fixed-point clause can only be used on doubles, was given %s", arg.Type().TypeName())
|
||||
}
|
||||
argFloatVal := arg.ConvertToType(types.DoubleType)
|
||||
argFloat, ok := argFloatVal.Value().(float64)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not convert \"%s\" to float64", argFloatVal.Value())
|
||||
}
|
||||
fmtStr := fmt.Sprintf("%%.%df", *precision)
|
||||
|
||||
matchedLocale, err := matchLanguage(locale)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error matching locale: %w", err)
|
||||
}
|
||||
return message.NewPrinter(matchedLocale).Sprintf(fmtStr, argFloat), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *stringFormatter) Scientific(precision *int) func(ref.Val, string) (string, error) {
|
||||
if precision == nil {
|
||||
precision = new(int)
|
||||
*precision = defaultPrecision
|
||||
}
|
||||
return func(arg ref.Val, locale string) (string, error) {
|
||||
strException := false
|
||||
if arg.Type() == types.StringType {
|
||||
argStr := arg.Value().(string)
|
||||
if argStr == "NaN" || argStr == "Infinity" || argStr == "-Infinity" {
|
||||
strException = true
|
||||
}
|
||||
}
|
||||
if arg.Type() != types.DoubleType && !strException {
|
||||
return "", fmt.Errorf("scientific clause can only be used on doubles, was given %s", arg.Type().TypeName())
|
||||
}
|
||||
argFloatVal := arg.ConvertToType(types.DoubleType)
|
||||
argFloat, ok := argFloatVal.Value().(float64)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not convert \"%s\" to float64", argFloatVal.Value())
|
||||
}
|
||||
matchedLocale, err := matchLanguage(locale)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error matching locale: %w", err)
|
||||
}
|
||||
fmtStr := fmt.Sprintf("%%%de", *precision)
|
||||
return message.NewPrinter(matchedLocale).Sprintf(fmtStr, argFloat), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *stringFormatter) Binary(arg ref.Val, locale string) (string, error) {
|
||||
switch arg.Type() {
|
||||
case types.IntType:
|
||||
argInt := arg.Value().(int64)
|
||||
// locale is intentionally unused as integers formatted as binary
|
||||
// strings are locale-independent
|
||||
return fmt.Sprintf("%b", argInt), nil
|
||||
case types.UintType:
|
||||
argInt := arg.Value().(uint64)
|
||||
return fmt.Sprintf("%b", argInt), nil
|
||||
case types.BoolType:
|
||||
argBool := arg.Value().(bool)
|
||||
if argBool {
|
||||
return "1", nil
|
||||
}
|
||||
return "0", nil
|
||||
default:
|
||||
return "", fmt.Errorf("only integers and bools can be formatted as binary, was given %s", arg.Type().TypeName())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *stringFormatter) Hex(useUpper bool) func(ref.Val, string) (string, error) {
|
||||
return func(arg ref.Val, locale string) (string, error) {
|
||||
fmtStr := "%x"
|
||||
if useUpper {
|
||||
fmtStr = "%X"
|
||||
}
|
||||
switch arg.Type() {
|
||||
case types.StringType, types.BytesType:
|
||||
if arg.Type() == types.BytesType {
|
||||
return fmt.Sprintf(fmtStr, arg.Value().([]byte)), nil
|
||||
}
|
||||
return fmt.Sprintf(fmtStr, arg.Value().(string)), nil
|
||||
case types.IntType:
|
||||
argInt, ok := arg.Value().(int64)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not convert \"%s\" to int64", arg.Value())
|
||||
}
|
||||
return fmt.Sprintf(fmtStr, argInt), nil
|
||||
case types.UintType:
|
||||
argInt, ok := arg.Value().(uint64)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("could not convert \"%s\" to uint64", arg.Value())
|
||||
}
|
||||
return fmt.Sprintf(fmtStr, argInt), nil
|
||||
default:
|
||||
return "", fmt.Errorf("only integers, byte buffers, and strings can be formatted as hex, was given %s", arg.Type().TypeName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *stringFormatter) Octal(arg ref.Val, locale string) (string, error) {
|
||||
switch arg.Type() {
|
||||
case types.IntType:
|
||||
argInt := arg.Value().(int64)
|
||||
return fmt.Sprintf("%o", argInt), nil
|
||||
case types.UintType:
|
||||
argInt := arg.Value().(uint64)
|
||||
return fmt.Sprintf("%o", argInt), nil
|
||||
default:
|
||||
return "", fmt.Errorf("octal clause can only be used on integers, was given %s", arg.Type().TypeName())
|
||||
}
|
||||
}
|
||||
|
||||
type stringArgList struct {
|
||||
args traits.Lister
|
||||
}
|
||||
|
||||
func (c *stringArgList) Arg(index int64) (ref.Val, error) {
|
||||
if index >= c.args.Size().Value().(int64) {
|
||||
return nil, fmt.Errorf("index %d out of range", index)
|
||||
}
|
||||
return c.args.Get(types.Int(index)), nil
|
||||
}
|
||||
|
||||
func (c *stringArgList) ArgSize() int64 {
|
||||
return c.args.Size().Value().(int64)
|
||||
}
|
||||
|
||||
var (
|
||||
stringListType = reflect.TypeOf([]string{})
|
||||
)
|
||||
|
7
vendor/github.com/google/cel-go/interpreter/BUILD.bazel
generated
vendored
7
vendor/github.com/google/cel-go/interpreter/BUILD.bazel
generated
vendored
@ -11,10 +11,10 @@ go_library(
|
||||
"activation.go",
|
||||
"attribute_patterns.go",
|
||||
"attributes.go",
|
||||
"coster.go",
|
||||
"decorators.go",
|
||||
"dispatcher.go",
|
||||
"evalstate.go",
|
||||
"formatting.go",
|
||||
"interpretable.go",
|
||||
"interpreter.go",
|
||||
"optimizations.go",
|
||||
@ -32,7 +32,7 @@ go_library(
|
||||
"//common/types/ref:go_default_library",
|
||||
"//common/types/traits:go_default_library",
|
||||
"//interpreter/functions:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
|
||||
@ -49,6 +49,7 @@ go_test(
|
||||
"attributes_test.go",
|
||||
"interpreter_test.go",
|
||||
"prune_test.go",
|
||||
"runtimecost_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
@ -65,7 +66,7 @@ go_test(
|
||||
"//test:go_default_library",
|
||||
"//test/proto2pb:go_default_library",
|
||||
"//test/proto3pb:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/anypb:go_default_library",
|
||||
],
|
||||
|
30
vendor/github.com/google/cel-go/interpreter/activation.go
generated
vendored
30
vendor/github.com/google/cel-go/interpreter/activation.go
generated
vendored
@ -28,7 +28,7 @@ import (
|
||||
type Activation interface {
|
||||
// ResolveName returns a value from the activation by qualified name, or false if the name
|
||||
// could not be found.
|
||||
ResolveName(name string) (interface{}, bool)
|
||||
ResolveName(name string) (any, bool)
|
||||
|
||||
// Parent returns the parent of the current activation, may be nil.
|
||||
// If non-nil, the parent will be searched during resolve calls.
|
||||
@ -43,23 +43,23 @@ func EmptyActivation() Activation {
|
||||
// emptyActivation is a variable-free activation.
|
||||
type emptyActivation struct{}
|
||||
|
||||
func (emptyActivation) ResolveName(string) (interface{}, bool) { return nil, false }
|
||||
func (emptyActivation) Parent() Activation { return nil }
|
||||
func (emptyActivation) ResolveName(string) (any, bool) { return nil, false }
|
||||
func (emptyActivation) Parent() Activation { return nil }
|
||||
|
||||
// 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]interface{}`.
|
||||
// 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() interface{}
|
||||
// - 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 ref.TypeAdapter configured in the environment.
|
||||
func NewActivation(bindings interface{}) (Activation, error) {
|
||||
func NewActivation(bindings any) (Activation, error) {
|
||||
if bindings == nil {
|
||||
return nil, errors.New("bindings must be non-nil")
|
||||
}
|
||||
@ -67,7 +67,7 @@ func NewActivation(bindings interface{}) (Activation, error) {
|
||||
if isActivation {
|
||||
return a, nil
|
||||
}
|
||||
m, isMap := bindings.(map[string]interface{})
|
||||
m, isMap := bindings.(map[string]any)
|
||||
if !isMap {
|
||||
return nil, fmt.Errorf(
|
||||
"activation input must be an activation or map[string]interface: got %T",
|
||||
@ -81,7 +81,7 @@ func NewActivation(bindings interface{}) (Activation, error) {
|
||||
// Named bindings may lazily supply values by providing a function which accepts no arguments and
|
||||
// produces an interface value.
|
||||
type mapActivation struct {
|
||||
bindings map[string]interface{}
|
||||
bindings map[string]any
|
||||
}
|
||||
|
||||
// Parent implements the Activation interface method.
|
||||
@ -90,7 +90,7 @@ func (a *mapActivation) Parent() Activation {
|
||||
}
|
||||
|
||||
// ResolveName implements the Activation interface method.
|
||||
func (a *mapActivation) ResolveName(name string) (interface{}, bool) {
|
||||
func (a *mapActivation) ResolveName(name string) (any, bool) {
|
||||
obj, found := a.bindings[name]
|
||||
if !found {
|
||||
return nil, false
|
||||
@ -100,7 +100,7 @@ func (a *mapActivation) ResolveName(name string) (interface{}, bool) {
|
||||
obj = fn()
|
||||
a.bindings[name] = obj
|
||||
}
|
||||
fnRaw, isLazy := obj.(func() interface{})
|
||||
fnRaw, isLazy := obj.(func() any)
|
||||
if isLazy {
|
||||
obj = fnRaw()
|
||||
a.bindings[name] = obj
|
||||
@ -121,7 +121,7 @@ func (a *hierarchicalActivation) Parent() Activation {
|
||||
}
|
||||
|
||||
// ResolveName implements the Activation interface method.
|
||||
func (a *hierarchicalActivation) ResolveName(name string) (interface{}, bool) {
|
||||
func (a *hierarchicalActivation) ResolveName(name string) (any, bool) {
|
||||
if object, found := a.child.ResolveName(name); found {
|
||||
return object, found
|
||||
}
|
||||
@ -138,8 +138,8 @@ func NewHierarchicalActivation(parent Activation, child Activation) Activation {
|
||||
// representing field and index operations that should result in a 'types.Unknown' result.
|
||||
//
|
||||
// The `bindings` value may be any value type supported by the interpreter.NewActivation call,
|
||||
// but is typically either an existing Activation or map[string]interface{}.
|
||||
func NewPartialActivation(bindings interface{},
|
||||
// but is typically either an existing Activation or map[string]any.
|
||||
func NewPartialActivation(bindings any,
|
||||
unknowns ...*AttributePattern) (PartialActivation, error) {
|
||||
a, err := NewActivation(bindings)
|
||||
if err != nil {
|
||||
@ -184,7 +184,7 @@ func (v *varActivation) Parent() Activation {
|
||||
}
|
||||
|
||||
// ResolveName implements the Activation interface method.
|
||||
func (v *varActivation) ResolveName(name string) (interface{}, bool) {
|
||||
func (v *varActivation) ResolveName(name string) (any, bool) {
|
||||
if name == v.name {
|
||||
return v.val, true
|
||||
}
|
||||
@ -194,7 +194,7 @@ func (v *varActivation) ResolveName(name string) (interface{}, bool) {
|
||||
var (
|
||||
// pool of var activations to reduce allocations during folds.
|
||||
varActivationPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
return &varActivation{}
|
||||
},
|
||||
}
|
||||
|
77
vendor/github.com/google/cel-go/interpreter/attribute_patterns.go
generated
vendored
77
vendor/github.com/google/cel-go/interpreter/attribute_patterns.go
generated
vendored
@ -15,8 +15,6 @@
|
||||
package interpreter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
@ -36,9 +34,9 @@ import (
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 1. ns.myvar["complex-value"]
|
||||
// 2. ns.myvar["complex-value"][0]
|
||||
// 3. ns.myvar["complex-value"].*.name
|
||||
// 1. ns.myvar["complex-value"]
|
||||
// 2. ns.myvar["complex-value"][0]
|
||||
// 3. ns.myvar["complex-value"].*.name
|
||||
//
|
||||
// The first example is simple: match an attribute where the variable is 'ns.myvar' with a
|
||||
// field access on 'complex-value'. The second example expands the match to indicate that only
|
||||
@ -108,7 +106,7 @@ func (apat *AttributePattern) QualifierPatterns() []*AttributeQualifierPattern {
|
||||
// AttributeQualifierPattern holds a wildcard or valued qualifier pattern.
|
||||
type AttributeQualifierPattern struct {
|
||||
wildcard bool
|
||||
value interface{}
|
||||
value any
|
||||
}
|
||||
|
||||
// Matches returns true if the qualifier pattern is a wildcard, or the Qualifier implements the
|
||||
@ -134,44 +132,44 @@ func (qpat *AttributeQualifierPattern) Matches(q Qualifier) bool {
|
||||
type qualifierValueEquator interface {
|
||||
// QualifierValueEquals returns true if the input value is equal to the value held in the
|
||||
// Qualifier.
|
||||
QualifierValueEquals(value interface{}) bool
|
||||
QualifierValueEquals(value any) bool
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for boolean qualifiers.
|
||||
func (q *boolQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
func (q *boolQualifier) QualifierValueEquals(value any) bool {
|
||||
bval, ok := value.(bool)
|
||||
return ok && q.value == bval
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for field qualifiers.
|
||||
func (q *fieldQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
func (q *fieldQualifier) QualifierValueEquals(value any) bool {
|
||||
sval, ok := value.(string)
|
||||
return ok && q.Name == sval
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for string qualifiers.
|
||||
func (q *stringQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
func (q *stringQualifier) QualifierValueEquals(value any) bool {
|
||||
sval, ok := value.(string)
|
||||
return ok && q.value == sval
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for int qualifiers.
|
||||
func (q *intQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
func (q *intQualifier) QualifierValueEquals(value any) bool {
|
||||
return numericValueEquals(value, q.celValue)
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for uint qualifiers.
|
||||
func (q *uintQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
func (q *uintQualifier) QualifierValueEquals(value any) bool {
|
||||
return numericValueEquals(value, q.celValue)
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for double qualifiers.
|
||||
func (q *doubleQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
func (q *doubleQualifier) QualifierValueEquals(value any) bool {
|
||||
return numericValueEquals(value, q.celValue)
|
||||
}
|
||||
|
||||
// numericValueEquals uses CEL equality to determine whether two number values are
|
||||
func numericValueEquals(value interface{}, celValue ref.Val) bool {
|
||||
func numericValueEquals(value any, celValue ref.Val) bool {
|
||||
val := types.DefaultTypeAdapter.NativeToValue(value)
|
||||
return celValue.Equal(val) == types.True
|
||||
}
|
||||
@ -272,13 +270,9 @@ func (fac *partialAttributeFactory) matchesUnknownPatterns(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unk, isUnk := val.(types.Unknown)
|
||||
if isUnk {
|
||||
return unk, nil
|
||||
}
|
||||
// If this resolution behavior ever changes, new implementations of the
|
||||
// qualifierValueEquator may be required to handle proper resolution.
|
||||
qual, err = fac.NewQualifier(nil, qual.ID(), val)
|
||||
qual, err = fac.NewQualifier(nil, qual.ID(), val, attr.IsOptional())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -338,24 +332,10 @@ func (m *attributeMatcher) AddQualifier(qual Qualifier) (Attribute, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Resolve is an implementation of the Attribute interface method which uses the
|
||||
// attributeMatcher TryResolve implementation rather than the embedded NamespacedAttribute
|
||||
// Resolve implementation.
|
||||
func (m *attributeMatcher) Resolve(vars Activation) (interface{}, error) {
|
||||
obj, found, err := m.TryResolve(vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !found {
|
||||
return nil, fmt.Errorf("no such attribute: %v", m.NamespacedAttribute)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// TryResolve is an implementation of the NamespacedAttribute interface method which tests
|
||||
// Resolve is an implementation of the NamespacedAttribute interface method which tests
|
||||
// for matching unknown attribute patterns and returns types.Unknown if present. Otherwise,
|
||||
// the standard Resolve logic applies.
|
||||
func (m *attributeMatcher) TryResolve(vars Activation) (interface{}, bool, error) {
|
||||
func (m *attributeMatcher) Resolve(vars Activation) (any, error) {
|
||||
id := m.NamespacedAttribute.ID()
|
||||
// Bug in how partial activation is resolved, should search parents as well.
|
||||
partial, isPartial := toPartialActivation(vars)
|
||||
@ -366,30 +346,23 @@ func (m *attributeMatcher) TryResolve(vars Activation) (interface{}, bool, error
|
||||
m.CandidateVariableNames(),
|
||||
m.qualifiers)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
return nil, err
|
||||
}
|
||||
if unk != nil {
|
||||
return unk, true, nil
|
||||
return unk, nil
|
||||
}
|
||||
}
|
||||
return m.NamespacedAttribute.TryResolve(vars)
|
||||
return m.NamespacedAttribute.Resolve(vars)
|
||||
}
|
||||
|
||||
// Qualify is an implementation of the Qualifier interface method.
|
||||
func (m *attributeMatcher) Qualify(vars Activation, obj interface{}) (interface{}, error) {
|
||||
val, err := m.Resolve(vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unk, isUnk := val.(types.Unknown)
|
||||
if isUnk {
|
||||
return unk, nil
|
||||
}
|
||||
qual, err := m.fac.NewQualifier(nil, m.ID(), val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return qual.Qualify(vars, obj)
|
||||
func (m *attributeMatcher) Qualify(vars Activation, obj any) (any, error) {
|
||||
return attrQualify(m.fac, vars, obj, m)
|
||||
}
|
||||
|
||||
// QualifyIfPresent is an implementation of the Qualifier interface method.
|
||||
func (m *attributeMatcher) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
|
||||
return attrQualifyIfPresent(m.fac, vars, obj, m, presenceOnly)
|
||||
}
|
||||
|
||||
func toPartialActivation(vars Activation) (PartialActivation, bool) {
|
||||
|
1098
vendor/github.com/google/cel-go/interpreter/attributes.go
generated
vendored
1098
vendor/github.com/google/cel-go/interpreter/attributes.go
generated
vendored
File diff suppressed because it is too large
Load Diff
11
vendor/github.com/google/cel-go/interpreter/decorators.go
generated
vendored
11
vendor/github.com/google/cel-go/interpreter/decorators.go
generated
vendored
@ -29,7 +29,7 @@ type InterpretableDecorator func(Interpretable) (Interpretable, error)
|
||||
func decObserveEval(observer EvalObserver) InterpretableDecorator {
|
||||
return func(i Interpretable) (Interpretable, error) {
|
||||
switch inst := i.(type) {
|
||||
case *evalWatch, *evalWatchAttr, *evalWatchConst:
|
||||
case *evalWatch, *evalWatchAttr, *evalWatchConst, *evalWatchConstructor:
|
||||
// these instruction are already watching, return straight-away.
|
||||
return i, nil
|
||||
case InterpretableAttribute:
|
||||
@ -42,6 +42,11 @@ func decObserveEval(observer EvalObserver) InterpretableDecorator {
|
||||
InterpretableConst: inst,
|
||||
observer: observer,
|
||||
}, nil
|
||||
case InterpretableConstructor:
|
||||
return &evalWatchConstructor{
|
||||
constructor: inst,
|
||||
observer: observer,
|
||||
}, nil
|
||||
default:
|
||||
return &evalWatch{
|
||||
Interpretable: i,
|
||||
@ -224,8 +229,8 @@ func maybeOptimizeSetMembership(i Interpretable, inlist InterpretableCall) (Inte
|
||||
valueSet := make(map[ref.Val]ref.Val)
|
||||
for it.HasNext() == types.True {
|
||||
elem := it.Next()
|
||||
if !types.IsPrimitiveType(elem) {
|
||||
// Note, non-primitive type are not yet supported.
|
||||
if !types.IsPrimitiveType(elem) || elem.Type() == types.BytesType {
|
||||
// Note, non-primitive type are not yet supported, and []byte isn't hashable.
|
||||
return i, nil
|
||||
}
|
||||
valueSet[elem] = types.True
|
||||
|
383
vendor/github.com/google/cel-go/interpreter/formatting.go
generated
vendored
Normal file
383
vendor/github.com/google/cel-go/interpreter/formatting.go
generated
vendored
Normal file
@ -0,0 +1,383 @@
|
||||
// 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
|
||||
//
|
||||
// http://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 interpreter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
type typeVerifier func(int64, ...*types.TypeValue) (bool, error)
|
||||
|
||||
// InterpolateFormattedString checks the syntax and cardinality of any string.format calls present in the expression and reports
|
||||
// any errors at compile time.
|
||||
func InterpolateFormattedString(verifier typeVerifier) InterpretableDecorator {
|
||||
return func(inter Interpretable) (Interpretable, error) {
|
||||
call, ok := inter.(InterpretableCall)
|
||||
if !ok {
|
||||
return inter, nil
|
||||
}
|
||||
if call.OverloadID() != "string_format" {
|
||||
return inter, nil
|
||||
}
|
||||
args := call.Args()
|
||||
if len(args) != 2 {
|
||||
return nil, fmt.Errorf("wrong number of arguments to string.format (expected 2, got %d)", len(args))
|
||||
}
|
||||
fmtStrInter, ok := args[0].(InterpretableConst)
|
||||
if !ok {
|
||||
return inter, nil
|
||||
}
|
||||
var fmtArgsInter InterpretableConstructor
|
||||
fmtArgsInter, ok = args[1].(InterpretableConstructor)
|
||||
if !ok {
|
||||
return inter, nil
|
||||
}
|
||||
if fmtArgsInter.Type() != types.ListType {
|
||||
// don't necessarily return an error since the list may be DynType
|
||||
return inter, nil
|
||||
}
|
||||
formatStr := fmtStrInter.Value().Value().(string)
|
||||
initVals := fmtArgsInter.InitVals()
|
||||
|
||||
formatCheck := &formatCheck{
|
||||
args: initVals,
|
||||
verifier: verifier,
|
||||
}
|
||||
// use a placeholder locale, since locale doesn't affect syntax
|
||||
_, err := ParseFormatString(formatStr, formatCheck, formatCheck, "en_US")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seenArgs := formatCheck.argsRequested
|
||||
if len(initVals) > seenArgs {
|
||||
return nil, fmt.Errorf("too many arguments supplied to string.format (expected %d, got %d)", seenArgs, len(initVals))
|
||||
}
|
||||
return inter, nil
|
||||
}
|
||||
}
|
||||
|
||||
type formatCheck struct {
|
||||
args []Interpretable
|
||||
argsRequested int
|
||||
curArgIndex int64
|
||||
enableCheckArgTypes bool
|
||||
verifier typeVerifier
|
||||
}
|
||||
|
||||
func (c *formatCheck) String(arg ref.Val, locale string) (string, error) {
|
||||
valid, err := verifyString(c.args[c.curArgIndex], c.verifier)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !valid {
|
||||
return "", errors.New("string clause can only be used on strings, bools, bytes, ints, doubles, maps, lists, types, durations, and timestamps")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (c *formatCheck) Decimal(arg ref.Val, locale string) (string, error) {
|
||||
id := c.args[c.curArgIndex].ID()
|
||||
valid, err := c.verifier(id, types.IntType, types.UintType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !valid {
|
||||
return "", errors.New("integer clause can only be used on integers")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (c *formatCheck) Fixed(precision *int) func(ref.Val, string) (string, error) {
|
||||
return func(arg ref.Val, locale string) (string, error) {
|
||||
id := c.args[c.curArgIndex].ID()
|
||||
// we allow StringType since "NaN", "Infinity", and "-Infinity" are also valid values
|
||||
valid, err := c.verifier(id, types.DoubleType, types.StringType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !valid {
|
||||
return "", errors.New("fixed-point clause can only be used on doubles")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *formatCheck) Scientific(precision *int) func(ref.Val, string) (string, error) {
|
||||
return func(arg ref.Val, locale string) (string, error) {
|
||||
id := c.args[c.curArgIndex].ID()
|
||||
valid, err := c.verifier(id, types.DoubleType, types.StringType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !valid {
|
||||
return "", errors.New("scientific clause can only be used on doubles")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *formatCheck) Binary(arg ref.Val, locale string) (string, error) {
|
||||
id := c.args[c.curArgIndex].ID()
|
||||
valid, err := c.verifier(id, types.IntType, types.UintType, types.BoolType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !valid {
|
||||
return "", errors.New("only integers and bools can be formatted as binary")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (c *formatCheck) Hex(useUpper bool) func(ref.Val, string) (string, error) {
|
||||
return func(arg ref.Val, locale string) (string, error) {
|
||||
id := c.args[c.curArgIndex].ID()
|
||||
valid, err := c.verifier(id, types.IntType, types.UintType, types.StringType, types.BytesType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !valid {
|
||||
return "", errors.New("only integers, byte buffers, and strings can be formatted as hex")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *formatCheck) Octal(arg ref.Val, locale string) (string, error) {
|
||||
id := c.args[c.curArgIndex].ID()
|
||||
valid, err := c.verifier(id, types.IntType, types.UintType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !valid {
|
||||
return "", errors.New("octal clause can only be used on integers")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (c *formatCheck) Arg(index int64) (ref.Val, error) {
|
||||
c.argsRequested++
|
||||
c.curArgIndex = index
|
||||
// return a dummy value - this is immediately passed to back to us
|
||||
// through one of the FormatCallback functions, so anything will do
|
||||
return types.Int(0), nil
|
||||
}
|
||||
|
||||
func (c *formatCheck) ArgSize() int64 {
|
||||
return int64(len(c.args))
|
||||
}
|
||||
|
||||
func verifyString(sub Interpretable, verifier typeVerifier) (bool, error) {
|
||||
subVerified, err := verifier(sub.ID(),
|
||||
types.ListType, types.MapType, types.IntType, types.UintType, types.DoubleType,
|
||||
types.BoolType, types.StringType, types.TimestampType, types.BytesType, types.DurationType, types.TypeType, types.NullType)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !subVerified {
|
||||
return false, nil
|
||||
}
|
||||
con, ok := sub.(InterpretableConstructor)
|
||||
if ok {
|
||||
members := con.InitVals()
|
||||
for _, m := range members {
|
||||
// recursively verify if we're dealing with a list/map
|
||||
verified, err := verifyString(m, verifier)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !verified {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
// FormatStringInterpolator is an interface that allows user-defined behavior
|
||||
// for formatting clause implementations, as well as argument retrieval.
|
||||
// Each function is expected to support the appropriate types as laid out in
|
||||
// the string.format documentation, and to return an error if given an inappropriate type.
|
||||
type FormatStringInterpolator interface {
|
||||
// String takes a ref.Val and a string representing the current locale identifier
|
||||
// and returns the Val formatted as a string, or an error if one occurred.
|
||||
String(ref.Val, string) (string, error)
|
||||
|
||||
// Decimal takes a ref.Val and a string representing the current locale identifier
|
||||
// and returns the Val formatted as a decimal integer, or an error if one occurred.
|
||||
Decimal(ref.Val, string) (string, error)
|
||||
|
||||
// Fixed takes an int pointer representing precision (or nil if none was given) and
|
||||
// returns a function operating in a similar manner to String and Decimal, taking a
|
||||
// ref.Val and locale and returning the appropriate string. A closure is returned
|
||||
// so precision can be set without needing an additional function call/configuration.
|
||||
Fixed(*int) func(ref.Val, string) (string, error)
|
||||
|
||||
// Scientific functions identically to Fixed, except the string returned from the closure
|
||||
// is expected to be in scientific notation.
|
||||
Scientific(*int) func(ref.Val, string) (string, error)
|
||||
|
||||
// Binary takes a ref.Val and a string representing the current locale identifier
|
||||
// and returns the Val formatted as a binary integer, or an error if one occurred.
|
||||
Binary(ref.Val, string) (string, error)
|
||||
|
||||
// Hex takes a boolean that, if true, indicates the hex string output by the returned
|
||||
// closure should use uppercase letters for A-F.
|
||||
Hex(bool) func(ref.Val, string) (string, error)
|
||||
|
||||
// Octal takes a ref.Val and a string representing the current locale identifier and
|
||||
// returns the Val formatted in octal, or an error if one occurred.
|
||||
Octal(ref.Val, string) (string, error)
|
||||
}
|
||||
|
||||
// FormatList is an interface that allows user-defined list-like datatypes to be used
|
||||
// for formatting clause implementations.
|
||||
type FormatList interface {
|
||||
// Arg returns the ref.Val at the given index, or an error if one occurred.
|
||||
Arg(int64) (ref.Val, error)
|
||||
// ArgSize returns the length of the argument list.
|
||||
ArgSize() int64
|
||||
}
|
||||
|
||||
type clauseImpl func(ref.Val, string) (string, error)
|
||||
|
||||
// ParseFormatString formats a string according to the string.format syntax, taking the clause implementations
|
||||
// from the provided FormatCallback and the args from the given FormatList.
|
||||
func ParseFormatString(formatStr string, callback FormatStringInterpolator, list FormatList, locale string) (string, error) {
|
||||
i := 0
|
||||
argIndex := 0
|
||||
var builtStr strings.Builder
|
||||
for i < len(formatStr) {
|
||||
if formatStr[i] == '%' {
|
||||
if i+1 < len(formatStr) && formatStr[i+1] == '%' {
|
||||
err := builtStr.WriteByte('%')
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing format string: %w", err)
|
||||
}
|
||||
i += 2
|
||||
continue
|
||||
} else {
|
||||
argAny, err := list.Arg(int64(argIndex))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if i+1 >= len(formatStr) {
|
||||
return "", errors.New("unexpected end of string")
|
||||
}
|
||||
if int64(argIndex) >= list.ArgSize() {
|
||||
return "", fmt.Errorf("index %d out of range", argIndex)
|
||||
}
|
||||
numRead, val, refErr := parseAndFormatClause(formatStr[i:], argAny, callback, list, locale)
|
||||
if refErr != nil {
|
||||
return "", refErr
|
||||
}
|
||||
_, err = builtStr.WriteString(val)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing format string: %w", err)
|
||||
}
|
||||
i += numRead
|
||||
argIndex++
|
||||
}
|
||||
} else {
|
||||
err := builtStr.WriteByte(formatStr[i])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing format string: %w", err)
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
return builtStr.String(), nil
|
||||
}
|
||||
|
||||
// parseAndFormatClause parses the format clause at the start of the given string with val, and returns
|
||||
// how many characters were consumed and the substituted string form of val, or an error if one occurred.
|
||||
func parseAndFormatClause(formatStr string, val ref.Val, callback FormatStringInterpolator, list FormatList, locale string) (int, string, error) {
|
||||
i := 1
|
||||
read, formatter, err := parseFormattingClause(formatStr[i:], callback)
|
||||
i += read
|
||||
if err != nil {
|
||||
return -1, "", fmt.Errorf("could not parse formatting clause: %s", err)
|
||||
}
|
||||
|
||||
valStr, err := formatter(val, locale)
|
||||
if err != nil {
|
||||
return -1, "", fmt.Errorf("error during formatting: %s", err)
|
||||
}
|
||||
return i, valStr, nil
|
||||
}
|
||||
|
||||
func parseFormattingClause(formatStr string, callback FormatStringInterpolator) (int, clauseImpl, error) {
|
||||
i := 0
|
||||
read, precision, err := parsePrecision(formatStr[i:])
|
||||
i += read
|
||||
if err != nil {
|
||||
return -1, nil, fmt.Errorf("error while parsing precision: %w", err)
|
||||
}
|
||||
r := rune(formatStr[i])
|
||||
i++
|
||||
switch r {
|
||||
case 's':
|
||||
return i, callback.String, nil
|
||||
case 'd':
|
||||
return i, callback.Decimal, nil
|
||||
case 'f':
|
||||
return i, callback.Fixed(precision), nil
|
||||
case 'e':
|
||||
return i, callback.Scientific(precision), nil
|
||||
case 'b':
|
||||
return i, callback.Binary, nil
|
||||
case 'x', 'X':
|
||||
return i, callback.Hex(unicode.IsUpper(r)), nil
|
||||
case 'o':
|
||||
return i, callback.Octal, nil
|
||||
default:
|
||||
return -1, nil, fmt.Errorf("unrecognized formatting clause \"%c\"", r)
|
||||
}
|
||||
}
|
||||
|
||||
func parsePrecision(formatStr string) (int, *int, error) {
|
||||
i := 0
|
||||
if formatStr[i] != '.' {
|
||||
return i, nil, nil
|
||||
}
|
||||
i++
|
||||
var buffer strings.Builder
|
||||
for {
|
||||
if i >= len(formatStr) {
|
||||
return -1, nil, errors.New("could not find end of precision specifier")
|
||||
}
|
||||
if !isASCIIDigit(rune(formatStr[i])) {
|
||||
break
|
||||
}
|
||||
buffer.WriteByte(formatStr[i])
|
||||
i++
|
||||
}
|
||||
precision, err := strconv.Atoi(buffer.String())
|
||||
if err != nil {
|
||||
return -1, nil, fmt.Errorf("error while converting precision to integer: %w", err)
|
||||
}
|
||||
return i, &precision, nil
|
||||
}
|
||||
|
||||
func isASCIIDigit(r rune) bool {
|
||||
return r <= unicode.MaxASCII && unicode.IsDigit(r)
|
||||
}
|
2
vendor/github.com/google/cel-go/interpreter/functions/functions.go
generated
vendored
2
vendor/github.com/google/cel-go/interpreter/functions/functions.go
generated
vendored
@ -58,5 +58,5 @@ type UnaryOp func(value ref.Val) ref.Val
|
||||
type BinaryOp func(lhs ref.Val, rhs ref.Val) ref.Val
|
||||
|
||||
// FunctionOp is a function with accepts zero or more arguments and produces
|
||||
// an value (as interface{}) or error as a result.
|
||||
// a value or error as a result.
|
||||
type FunctionOp func(values ...ref.Val) ref.Val
|
||||
|
473
vendor/github.com/google/cel-go/interpreter/interpretable.go
generated
vendored
473
vendor/github.com/google/cel-go/interpreter/interpretable.go
generated
vendored
@ -15,7 +15,7 @@
|
||||
package interpreter
|
||||
|
||||
import (
|
||||
"math"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
@ -64,10 +64,18 @@ type InterpretableAttribute interface {
|
||||
|
||||
// Qualify replicates the Attribute.Qualify method to permit extension and interception
|
||||
// of object qualification.
|
||||
Qualify(vars Activation, obj interface{}) (interface{}, error)
|
||||
Qualify(vars Activation, obj any) (any, error)
|
||||
|
||||
// QualifyIfPresent qualifies the object if the qualifier is declared or defined on the object.
|
||||
// The 'presenceOnly' flag indicates that the value is not necessary, just a boolean status as
|
||||
// to whether the qualifier is present.
|
||||
QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error)
|
||||
|
||||
// IsOptional indicates whether the resulting value is an optional type.
|
||||
IsOptional() bool
|
||||
|
||||
// Resolve returns the value of the Attribute given the current Activation.
|
||||
Resolve(Activation) (interface{}, error)
|
||||
Resolve(Activation) (any, error)
|
||||
}
|
||||
|
||||
// InterpretableCall interface for inspecting Interpretable instructions related to function calls.
|
||||
@ -103,10 +111,8 @@ type InterpretableConstructor interface {
|
||||
// Core Interpretable implementations used during the program planning phase.
|
||||
|
||||
type evalTestOnly struct {
|
||||
id int64
|
||||
op Interpretable
|
||||
field types.String
|
||||
fieldType *ref.FieldType
|
||||
id int64
|
||||
InterpretableAttribute
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
@ -116,44 +122,55 @@ func (test *evalTestOnly) ID() int64 {
|
||||
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (test *evalTestOnly) Eval(ctx Activation) ref.Val {
|
||||
// Handle field selection on a proto in the most efficient way possible.
|
||||
if test.fieldType != nil {
|
||||
opAttr, ok := test.op.(InterpretableAttribute)
|
||||
if ok {
|
||||
opVal, err := opAttr.Resolve(ctx)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
refVal, ok := opVal.(ref.Val)
|
||||
if ok {
|
||||
opVal = refVal.Value()
|
||||
}
|
||||
if test.fieldType.IsSet(opVal) {
|
||||
return types.True
|
||||
}
|
||||
return types.False
|
||||
}
|
||||
val, err := test.Resolve(ctx)
|
||||
// Return an error if the resolve step fails
|
||||
if err != nil {
|
||||
return types.WrapErr(err)
|
||||
}
|
||||
|
||||
obj := test.op.Eval(ctx)
|
||||
tester, ok := obj.(traits.FieldTester)
|
||||
if ok {
|
||||
return tester.IsSet(test.field)
|
||||
if optVal, isOpt := val.(*types.Optional); isOpt {
|
||||
return types.Bool(optVal.HasValue())
|
||||
}
|
||||
container, ok := obj.(traits.Container)
|
||||
if ok {
|
||||
return container.Contains(test.field)
|
||||
}
|
||||
return types.ValOrErr(obj, "invalid type for field selection.")
|
||||
return test.Adapter().NativeToValue(val)
|
||||
}
|
||||
|
||||
// Cost provides the heuristic cost of a `has(field)` macro. The cost has at least 1 for determining
|
||||
// if the field exists, apart from the cost of accessing the field.
|
||||
func (test *evalTestOnly) Cost() (min, max int64) {
|
||||
min, max = estimateCost(test.op)
|
||||
min++
|
||||
max++
|
||||
return
|
||||
// AddQualifier appends a qualifier that will always and only perform a presence test.
|
||||
func (test *evalTestOnly) AddQualifier(q Qualifier) (Attribute, error) {
|
||||
cq, ok := q.(ConstantQualifier)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("test only expressions must have constant qualifiers: %v", q)
|
||||
}
|
||||
return test.InterpretableAttribute.AddQualifier(&testOnlyQualifier{ConstantQualifier: cq})
|
||||
}
|
||||
|
||||
type testOnlyQualifier struct {
|
||||
ConstantQualifier
|
||||
}
|
||||
|
||||
// Qualify determines whether the test-only qualifier is present on the input object.
|
||||
func (q *testOnlyQualifier) Qualify(vars Activation, obj any) (any, error) {
|
||||
out, present, err := q.ConstantQualifier.QualifyIfPresent(vars, obj, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if unk, isUnk := out.(types.Unknown); isUnk {
|
||||
return unk, nil
|
||||
}
|
||||
if opt, isOpt := out.(types.Optional); isOpt {
|
||||
return opt.HasValue(), nil
|
||||
}
|
||||
return present, nil
|
||||
}
|
||||
|
||||
// QualifyIfPresent returns whether the target field in the test-only expression is present.
|
||||
func (q *testOnlyQualifier) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
|
||||
// Only ever test for presence.
|
||||
return q.ConstantQualifier.QualifyIfPresent(vars, obj, true)
|
||||
}
|
||||
|
||||
// QualifierValueEquals determines whether the test-only constant qualifier equals the input value.
|
||||
func (q *testOnlyQualifier) QualifierValueEquals(value any) bool {
|
||||
// The input qualifier will always be of type string
|
||||
return q.ConstantQualifier.Value().Value() == value
|
||||
}
|
||||
|
||||
// NewConstValue creates a new constant valued Interpretable.
|
||||
@ -179,11 +196,6 @@ func (cons *evalConst) Eval(ctx Activation) ref.Val {
|
||||
return cons.val
|
||||
}
|
||||
|
||||
// Cost returns zero for a constant valued Interpretable.
|
||||
func (cons *evalConst) Cost() (min, max int64) {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Value implements the InterpretableConst interface method.
|
||||
func (cons *evalConst) Value() ref.Val {
|
||||
return cons.val
|
||||
@ -233,12 +245,6 @@ func (or *evalOr) Eval(ctx Activation) ref.Val {
|
||||
return types.ValOrErr(rVal, "no such overload")
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method. The minimum possible cost incurs when the left-hand
|
||||
// side expr is sufficient in determining the evaluation result.
|
||||
func (or *evalOr) Cost() (min, max int64) {
|
||||
return calShortCircuitBinaryOpsCost(or.lhs, or.rhs)
|
||||
}
|
||||
|
||||
type evalAnd struct {
|
||||
id int64
|
||||
lhs Interpretable
|
||||
@ -283,18 +289,6 @@ func (and *evalAnd) Eval(ctx Activation) ref.Val {
|
||||
return types.ValOrErr(rVal, "no such overload")
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method. The minimum possible cost incurs when the left-hand
|
||||
// side expr is sufficient in determining the evaluation result.
|
||||
func (and *evalAnd) Cost() (min, max int64) {
|
||||
return calShortCircuitBinaryOpsCost(and.lhs, and.rhs)
|
||||
}
|
||||
|
||||
func calShortCircuitBinaryOpsCost(lhs, rhs Interpretable) (min, max int64) {
|
||||
lMin, lMax := estimateCost(lhs)
|
||||
_, rMax := estimateCost(rhs)
|
||||
return lMin, lMax + rMax + 1
|
||||
}
|
||||
|
||||
type evalEq struct {
|
||||
id int64
|
||||
lhs Interpretable
|
||||
@ -319,11 +313,6 @@ func (eq *evalEq) Eval(ctx Activation) ref.Val {
|
||||
return types.Equal(lVal, rVal)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (eq *evalEq) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(eq.lhs, eq.rhs)
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (*evalEq) Function() string {
|
||||
return operators.Equals
|
||||
@ -363,11 +352,6 @@ func (ne *evalNe) Eval(ctx Activation) ref.Val {
|
||||
return types.Bool(types.Equal(lVal, rVal) != types.True)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (ne *evalNe) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(ne.lhs, ne.rhs)
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (*evalNe) Function() string {
|
||||
return operators.NotEquals
|
||||
@ -400,11 +384,6 @@ func (zero *evalZeroArity) Eval(ctx Activation) ref.Val {
|
||||
return zero.impl()
|
||||
}
|
||||
|
||||
// Cost returns 1 representing the heuristic cost of the function.
|
||||
func (zero *evalZeroArity) Cost() (min, max int64) {
|
||||
return 1, 1
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (zero *evalZeroArity) Function() string {
|
||||
return zero.function
|
||||
@ -456,14 +435,6 @@ func (un *evalUnary) Eval(ctx Activation) ref.Val {
|
||||
return types.NewErr("no such overload: %s", un.function)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (un *evalUnary) Cost() (min, max int64) {
|
||||
min, max = estimateCost(un.arg)
|
||||
min++ // add cost for function
|
||||
max++
|
||||
return
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (un *evalUnary) Function() string {
|
||||
return un.function
|
||||
@ -522,11 +493,6 @@ func (bin *evalBinary) Eval(ctx Activation) ref.Val {
|
||||
return types.NewErr("no such overload: %s", bin.function)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (bin *evalBinary) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(bin.lhs, bin.rhs)
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (bin *evalBinary) Function() string {
|
||||
return bin.function
|
||||
@ -593,14 +559,6 @@ func (fn *evalVarArgs) Eval(ctx Activation) ref.Val {
|
||||
return types.NewErr("no such overload: %s", fn.function)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (fn *evalVarArgs) Cost() (min, max int64) {
|
||||
min, max = sumOfCost(fn.args)
|
||||
min++ // add cost for function
|
||||
max++
|
||||
return
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (fn *evalVarArgs) Function() string {
|
||||
return fn.function
|
||||
@ -617,9 +575,11 @@ func (fn *evalVarArgs) Args() []Interpretable {
|
||||
}
|
||||
|
||||
type evalList struct {
|
||||
id int64
|
||||
elems []Interpretable
|
||||
adapter ref.TypeAdapter
|
||||
id int64
|
||||
elems []Interpretable
|
||||
optionals []bool
|
||||
hasOptionals bool
|
||||
adapter ref.TypeAdapter
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
@ -629,14 +589,24 @@ func (l *evalList) ID() int64 {
|
||||
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (l *evalList) Eval(ctx Activation) ref.Val {
|
||||
elemVals := make([]ref.Val, len(l.elems))
|
||||
elemVals := make([]ref.Val, 0, len(l.elems))
|
||||
// If any argument is unknown or error early terminate.
|
||||
for i, elem := range l.elems {
|
||||
elemVal := elem.Eval(ctx)
|
||||
if types.IsUnknownOrError(elemVal) {
|
||||
return elemVal
|
||||
}
|
||||
elemVals[i] = elemVal
|
||||
if l.hasOptionals && l.optionals[i] {
|
||||
optVal, ok := elemVal.(*types.Optional)
|
||||
if !ok {
|
||||
return invalidOptionalElementInit(elemVal)
|
||||
}
|
||||
if !optVal.HasValue() {
|
||||
continue
|
||||
}
|
||||
elemVal = optVal.GetValue()
|
||||
}
|
||||
elemVals = append(elemVals, elemVal)
|
||||
}
|
||||
return l.adapter.NativeToValue(elemVals)
|
||||
}
|
||||
@ -649,16 +619,13 @@ func (l *evalList) Type() ref.Type {
|
||||
return types.ListType
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (l *evalList) Cost() (min, max int64) {
|
||||
return sumOfCost(l.elems)
|
||||
}
|
||||
|
||||
type evalMap struct {
|
||||
id int64
|
||||
keys []Interpretable
|
||||
vals []Interpretable
|
||||
adapter ref.TypeAdapter
|
||||
id int64
|
||||
keys []Interpretable
|
||||
vals []Interpretable
|
||||
optionals []bool
|
||||
hasOptionals bool
|
||||
adapter ref.TypeAdapter
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
@ -679,6 +646,17 @@ func (m *evalMap) Eval(ctx Activation) ref.Val {
|
||||
if types.IsUnknownOrError(valVal) {
|
||||
return valVal
|
||||
}
|
||||
if m.hasOptionals && m.optionals[i] {
|
||||
optVal, ok := valVal.(*types.Optional)
|
||||
if !ok {
|
||||
return invalidOptionalEntryInit(keyVal, valVal)
|
||||
}
|
||||
if !optVal.HasValue() {
|
||||
delete(entries, keyVal)
|
||||
continue
|
||||
}
|
||||
valVal = optVal.GetValue()
|
||||
}
|
||||
entries[keyVal] = valVal
|
||||
}
|
||||
return m.adapter.NativeToValue(entries)
|
||||
@ -704,19 +682,14 @@ func (m *evalMap) Type() ref.Type {
|
||||
return types.MapType
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (m *evalMap) Cost() (min, max int64) {
|
||||
kMin, kMax := sumOfCost(m.keys)
|
||||
vMin, vMax := sumOfCost(m.vals)
|
||||
return kMin + vMin, kMax + vMax
|
||||
}
|
||||
|
||||
type evalObj struct {
|
||||
id int64
|
||||
typeName string
|
||||
fields []string
|
||||
vals []Interpretable
|
||||
provider ref.TypeProvider
|
||||
id int64
|
||||
typeName string
|
||||
fields []string
|
||||
vals []Interpretable
|
||||
optionals []bool
|
||||
hasOptionals bool
|
||||
provider ref.TypeProvider
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
@ -733,6 +706,17 @@ func (o *evalObj) Eval(ctx Activation) ref.Val {
|
||||
if types.IsUnknownOrError(val) {
|
||||
return val
|
||||
}
|
||||
if o.hasOptionals && o.optionals[i] {
|
||||
optVal, ok := val.(*types.Optional)
|
||||
if !ok {
|
||||
return invalidOptionalEntryInit(field, val)
|
||||
}
|
||||
if !optVal.HasValue() {
|
||||
delete(fieldVals, field)
|
||||
continue
|
||||
}
|
||||
val = optVal.GetValue()
|
||||
}
|
||||
fieldVals[field] = val
|
||||
}
|
||||
return o.provider.NewValue(o.typeName, fieldVals)
|
||||
@ -746,21 +730,6 @@ func (o *evalObj) Type() ref.Type {
|
||||
return types.NewObjectTypeValue(o.typeName)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (o *evalObj) Cost() (min, max int64) {
|
||||
return sumOfCost(o.vals)
|
||||
}
|
||||
|
||||
func sumOfCost(interps []Interpretable) (min, max int64) {
|
||||
min, max = 0, 0
|
||||
for _, in := range interps {
|
||||
minT, maxT := estimateCost(in)
|
||||
min += minT
|
||||
max += maxT
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type evalFold struct {
|
||||
id int64
|
||||
accuVar string
|
||||
@ -842,38 +811,6 @@ func (fold *evalFold) Eval(ctx Activation) ref.Val {
|
||||
return res
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (fold *evalFold) Cost() (min, max int64) {
|
||||
// Compute the cost for evaluating iterRange.
|
||||
iMin, iMax := estimateCost(fold.iterRange)
|
||||
|
||||
// Compute the size of iterRange. If the size depends on the input, return the maximum possible
|
||||
// cost range.
|
||||
foldRange := fold.iterRange.Eval(EmptyActivation())
|
||||
if !foldRange.Type().HasTrait(traits.IterableType) {
|
||||
return 0, math.MaxInt64
|
||||
}
|
||||
var rangeCnt int64
|
||||
it := foldRange.(traits.Iterable).Iterator()
|
||||
for it.HasNext() == types.True {
|
||||
it.Next()
|
||||
rangeCnt++
|
||||
}
|
||||
aMin, aMax := estimateCost(fold.accu)
|
||||
cMin, cMax := estimateCost(fold.cond)
|
||||
sMin, sMax := estimateCost(fold.step)
|
||||
rMin, rMax := estimateCost(fold.result)
|
||||
if fold.exhaustive {
|
||||
cMin = cMin * rangeCnt
|
||||
sMin = sMin * rangeCnt
|
||||
}
|
||||
|
||||
// The cond and step costs are multiplied by size(iterRange). The minimum possible cost incurs
|
||||
// when the evaluation result can be determined by the first iteration.
|
||||
return iMin + aMin + cMin + sMin + rMin,
|
||||
iMax + aMax + cMax*rangeCnt + sMax*rangeCnt + rMax
|
||||
}
|
||||
|
||||
// Optional Interpretable implementations that specialize, subsume, or extend the core evaluation
|
||||
// plan via decorators.
|
||||
|
||||
@ -893,17 +830,15 @@ func (e *evalSetMembership) ID() int64 {
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (e *evalSetMembership) Eval(ctx Activation) ref.Val {
|
||||
val := e.arg.Eval(ctx)
|
||||
if types.IsUnknownOrError(val) {
|
||||
return val
|
||||
}
|
||||
if ret, found := e.valueSet[val]; found {
|
||||
return ret
|
||||
}
|
||||
return types.False
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalSetMembership) Cost() (min, max int64) {
|
||||
return estimateCost(e.arg)
|
||||
}
|
||||
|
||||
// evalWatch is an Interpretable implementation that wraps the execution of a given
|
||||
// expression so that it may observe the computed value and send it to an observer.
|
||||
type evalWatch struct {
|
||||
@ -918,15 +853,10 @@ func (e *evalWatch) Eval(ctx Activation) ref.Val {
|
||||
return val
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalWatch) Cost() (min, max int64) {
|
||||
return estimateCost(e.Interpretable)
|
||||
}
|
||||
|
||||
// evalWatchAttr describes a watcher of an instAttr Interpretable.
|
||||
// evalWatchAttr describes a watcher of an InterpretableAttribute Interpretable.
|
||||
//
|
||||
// Since the watcher may be selected against at a later stage in program planning, the watcher
|
||||
// must implement the instAttr interface by proxy.
|
||||
// must implement the InterpretableAttribute interface by proxy.
|
||||
type evalWatchAttr struct {
|
||||
InterpretableAttribute
|
||||
observer EvalObserver
|
||||
@ -953,11 +883,6 @@ func (e *evalWatchAttr) AddQualifier(q Qualifier) (Attribute, error) {
|
||||
return e, err
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalWatchAttr) Cost() (min, max int64) {
|
||||
return estimateCost(e.InterpretableAttribute)
|
||||
}
|
||||
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (e *evalWatchAttr) Eval(vars Activation) ref.Val {
|
||||
val := e.InterpretableAttribute.Eval(vars)
|
||||
@ -973,17 +898,12 @@ type evalWatchConstQual struct {
|
||||
adapter ref.TypeAdapter
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalWatchConstQual) Cost() (min, max int64) {
|
||||
return estimateCost(e.ConstantQualifier)
|
||||
}
|
||||
|
||||
// Qualify observes the qualification of a object via a constant boolean, int, string, or uint.
|
||||
func (e *evalWatchConstQual) Qualify(vars Activation, obj interface{}) (interface{}, error) {
|
||||
func (e *evalWatchConstQual) Qualify(vars Activation, obj any) (any, error) {
|
||||
out, err := e.ConstantQualifier.Qualify(vars, obj)
|
||||
var val ref.Val
|
||||
if err != nil {
|
||||
val = types.NewErr(err.Error())
|
||||
val = types.WrapErr(err)
|
||||
} else {
|
||||
val = e.adapter.NativeToValue(out)
|
||||
}
|
||||
@ -991,8 +911,25 @@ func (e *evalWatchConstQual) Qualify(vars Activation, obj interface{}) (interfac
|
||||
return out, err
|
||||
}
|
||||
|
||||
// QualifyIfPresent conditionally qualifies the variable and only records a value if one is present.
|
||||
func (e *evalWatchConstQual) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
|
||||
out, present, err := e.ConstantQualifier.QualifyIfPresent(vars, obj, presenceOnly)
|
||||
var val ref.Val
|
||||
if err != nil {
|
||||
val = types.WrapErr(err)
|
||||
} else if out != nil {
|
||||
val = e.adapter.NativeToValue(out)
|
||||
} else if presenceOnly {
|
||||
val = types.Bool(present)
|
||||
}
|
||||
if present || presenceOnly {
|
||||
e.observer(e.ID(), e.ConstantQualifier, val)
|
||||
}
|
||||
return out, present, err
|
||||
}
|
||||
|
||||
// QualifierValueEquals tests whether the incoming value is equal to the qualifying constant.
|
||||
func (e *evalWatchConstQual) QualifierValueEquals(value interface{}) bool {
|
||||
func (e *evalWatchConstQual) QualifierValueEquals(value any) bool {
|
||||
qve, ok := e.ConstantQualifier.(qualifierValueEquator)
|
||||
return ok && qve.QualifierValueEquals(value)
|
||||
}
|
||||
@ -1004,17 +941,12 @@ type evalWatchQual struct {
|
||||
adapter ref.TypeAdapter
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalWatchQual) Cost() (min, max int64) {
|
||||
return estimateCost(e.Qualifier)
|
||||
}
|
||||
|
||||
// Qualify observes the qualification of a object via a value computed at runtime.
|
||||
func (e *evalWatchQual) Qualify(vars Activation, obj interface{}) (interface{}, error) {
|
||||
func (e *evalWatchQual) Qualify(vars Activation, obj any) (any, error) {
|
||||
out, err := e.Qualifier.Qualify(vars, obj)
|
||||
var val ref.Val
|
||||
if err != nil {
|
||||
val = types.NewErr(err.Error())
|
||||
val = types.WrapErr(err)
|
||||
} else {
|
||||
val = e.adapter.NativeToValue(out)
|
||||
}
|
||||
@ -1022,6 +954,23 @@ func (e *evalWatchQual) Qualify(vars Activation, obj interface{}) (interface{},
|
||||
return out, err
|
||||
}
|
||||
|
||||
// QualifyIfPresent conditionally qualifies the variable and only records a value if one is present.
|
||||
func (e *evalWatchQual) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
|
||||
out, present, err := e.Qualifier.QualifyIfPresent(vars, obj, presenceOnly)
|
||||
var val ref.Val
|
||||
if err != nil {
|
||||
val = types.WrapErr(err)
|
||||
} else if out != nil {
|
||||
val = e.adapter.NativeToValue(out)
|
||||
} else if presenceOnly {
|
||||
val = types.Bool(present)
|
||||
}
|
||||
if present || presenceOnly {
|
||||
e.observer(e.ID(), e.Qualifier, val)
|
||||
}
|
||||
return out, present, err
|
||||
}
|
||||
|
||||
// evalWatchConst describes a watcher of an instConst Interpretable.
|
||||
type evalWatchConst struct {
|
||||
InterpretableConst
|
||||
@ -1035,11 +984,6 @@ func (e *evalWatchConst) Eval(vars Activation) ref.Val {
|
||||
return val
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalWatchConst) Cost() (min, max int64) {
|
||||
return estimateCost(e.InterpretableConst)
|
||||
}
|
||||
|
||||
// evalExhaustiveOr is just like evalOr, but does not short-circuit argument evaluation.
|
||||
type evalExhaustiveOr struct {
|
||||
id int64
|
||||
@ -1078,12 +1022,7 @@ func (or *evalExhaustiveOr) Eval(ctx Activation) ref.Val {
|
||||
if types.IsError(lVal) {
|
||||
return lVal
|
||||
}
|
||||
return types.ValOrErr(rVal, "no such overload")
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (or *evalExhaustiveOr) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(or.lhs, or.rhs)
|
||||
return types.MaybeNoSuchOverloadErr(rVal)
|
||||
}
|
||||
|
||||
// evalExhaustiveAnd is just like evalAnd, but does not short-circuit argument evaluation.
|
||||
@ -1124,18 +1063,7 @@ func (and *evalExhaustiveAnd) Eval(ctx Activation) ref.Val {
|
||||
if types.IsError(lVal) {
|
||||
return lVal
|
||||
}
|
||||
return types.ValOrErr(rVal, "no such overload")
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (and *evalExhaustiveAnd) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(and.lhs, and.rhs)
|
||||
}
|
||||
|
||||
func calExhaustiveBinaryOpsCost(lhs, rhs Interpretable) (min, max int64) {
|
||||
lMin, lMax := estimateCost(lhs)
|
||||
rMin, rMax := estimateCost(rhs)
|
||||
return lMin + rMin + 1, lMax + rMax + 1
|
||||
return types.MaybeNoSuchOverloadErr(rVal)
|
||||
}
|
||||
|
||||
// evalExhaustiveConditional is like evalConditional, but does not short-circuit argument
|
||||
@ -1154,77 +1082,114 @@ func (cond *evalExhaustiveConditional) ID() int64 {
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (cond *evalExhaustiveConditional) Eval(ctx Activation) ref.Val {
|
||||
cVal := cond.attr.expr.Eval(ctx)
|
||||
tVal, err := cond.attr.truthy.Resolve(ctx)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
fVal, err := cond.attr.falsy.Resolve(ctx)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
tVal, tErr := cond.attr.truthy.Resolve(ctx)
|
||||
fVal, fErr := cond.attr.falsy.Resolve(ctx)
|
||||
cBool, ok := cVal.(types.Bool)
|
||||
if !ok {
|
||||
return types.ValOrErr(cVal, "no such overload")
|
||||
}
|
||||
if cBool {
|
||||
if tErr != nil {
|
||||
return types.WrapErr(tErr)
|
||||
}
|
||||
return cond.adapter.NativeToValue(tVal)
|
||||
}
|
||||
if fErr != nil {
|
||||
return types.WrapErr(fErr)
|
||||
}
|
||||
return cond.adapter.NativeToValue(fVal)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (cond *evalExhaustiveConditional) Cost() (min, max int64) {
|
||||
return cond.attr.Cost()
|
||||
}
|
||||
|
||||
// evalAttr evaluates an Attribute value.
|
||||
type evalAttr struct {
|
||||
adapter ref.TypeAdapter
|
||||
attr Attribute
|
||||
adapter ref.TypeAdapter
|
||||
attr Attribute
|
||||
optional bool
|
||||
}
|
||||
|
||||
var _ InterpretableAttribute = &evalAttr{}
|
||||
|
||||
// ID of the attribute instruction.
|
||||
func (a *evalAttr) ID() int64 {
|
||||
return a.attr.ID()
|
||||
}
|
||||
|
||||
// AddQualifier implements the instAttr interface method.
|
||||
// AddQualifier implements the InterpretableAttribute interface method.
|
||||
func (a *evalAttr) AddQualifier(qual Qualifier) (Attribute, error) {
|
||||
attr, err := a.attr.AddQualifier(qual)
|
||||
a.attr = attr
|
||||
return attr, err
|
||||
}
|
||||
|
||||
// Attr implements the instAttr interface method.
|
||||
// Attr implements the InterpretableAttribute interface method.
|
||||
func (a *evalAttr) Attr() Attribute {
|
||||
return a.attr
|
||||
}
|
||||
|
||||
// Adapter implements the instAttr interface method.
|
||||
// Adapter implements the InterpretableAttribute interface method.
|
||||
func (a *evalAttr) Adapter() ref.TypeAdapter {
|
||||
return a.adapter
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (a *evalAttr) Cost() (min, max int64) {
|
||||
return estimateCost(a.attr)
|
||||
}
|
||||
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (a *evalAttr) Eval(ctx Activation) ref.Val {
|
||||
v, err := a.attr.Resolve(ctx)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
return types.WrapErr(err)
|
||||
}
|
||||
return a.adapter.NativeToValue(v)
|
||||
}
|
||||
|
||||
// Qualify proxies to the Attribute's Qualify method.
|
||||
func (a *evalAttr) Qualify(ctx Activation, obj interface{}) (interface{}, error) {
|
||||
func (a *evalAttr) Qualify(ctx Activation, obj any) (any, error) {
|
||||
return a.attr.Qualify(ctx, obj)
|
||||
}
|
||||
|
||||
// QualifyIfPresent proxies to the Attribute's QualifyIfPresent method.
|
||||
func (a *evalAttr) QualifyIfPresent(ctx Activation, obj any, presenceOnly bool) (any, bool, error) {
|
||||
return a.attr.QualifyIfPresent(ctx, obj, presenceOnly)
|
||||
}
|
||||
|
||||
func (a *evalAttr) IsOptional() bool {
|
||||
return a.optional
|
||||
}
|
||||
|
||||
// Resolve proxies to the Attribute's Resolve method.
|
||||
func (a *evalAttr) Resolve(ctx Activation) (interface{}, error) {
|
||||
func (a *evalAttr) Resolve(ctx Activation) (any, error) {
|
||||
return a.attr.Resolve(ctx)
|
||||
}
|
||||
|
||||
type evalWatchConstructor struct {
|
||||
constructor InterpretableConstructor
|
||||
observer EvalObserver
|
||||
}
|
||||
|
||||
// InitVals implements the InterpretableConstructor InitVals function.
|
||||
func (c *evalWatchConstructor) InitVals() []Interpretable {
|
||||
return c.constructor.InitVals()
|
||||
}
|
||||
|
||||
// Type implements the InterpretableConstructor Type function.
|
||||
func (c *evalWatchConstructor) Type() ref.Type {
|
||||
return c.constructor.Type()
|
||||
}
|
||||
|
||||
// ID implements the Interpretable ID function.
|
||||
func (c *evalWatchConstructor) ID() int64 {
|
||||
return c.constructor.ID()
|
||||
}
|
||||
|
||||
// Eval implements the Interpretable Eval function.
|
||||
func (c *evalWatchConstructor) Eval(ctx Activation) ref.Val {
|
||||
val := c.constructor.Eval(ctx)
|
||||
c.observer(c.ID(), c.constructor, val)
|
||||
return val
|
||||
}
|
||||
|
||||
func invalidOptionalEntryInit(field any, value ref.Val) ref.Val {
|
||||
return types.NewErr("cannot initialize optional entry '%v' from non-optional value %v", field, value)
|
||||
}
|
||||
|
||||
func invalidOptionalElementInit(value ref.Val) ref.Val {
|
||||
return types.NewErr("cannot initialize optional list element from non-optional value %v", value)
|
||||
}
|
||||
|
12
vendor/github.com/google/cel-go/interpreter/interpreter.go
generated
vendored
12
vendor/github.com/google/cel-go/interpreter/interpreter.go
generated
vendored
@ -29,19 +29,17 @@ import (
|
||||
type Interpreter interface {
|
||||
// NewInterpretable creates an Interpretable from a checked expression and an
|
||||
// optional list of InterpretableDecorator values.
|
||||
NewInterpretable(checked *exprpb.CheckedExpr,
|
||||
decorators ...InterpretableDecorator) (Interpretable, error)
|
||||
NewInterpretable(checked *exprpb.CheckedExpr, decorators ...InterpretableDecorator) (Interpretable, error)
|
||||
|
||||
// NewUncheckedInterpretable returns an Interpretable from a parsed expression
|
||||
// and an optional list of InterpretableDecorator values.
|
||||
NewUncheckedInterpretable(expr *exprpb.Expr,
|
||||
decorators ...InterpretableDecorator) (Interpretable, error)
|
||||
NewUncheckedInterpretable(expr *exprpb.Expr, decorators ...InterpretableDecorator) (Interpretable, error)
|
||||
}
|
||||
|
||||
// EvalObserver is a functional interface that accepts an expression id and an observed value.
|
||||
// The id identifies the expression that was evaluated, the programStep is the Interpretable or Qualifier that
|
||||
// was evaluated and value is the result of the evaluation.
|
||||
type EvalObserver func(id int64, programStep interface{}, value ref.Val)
|
||||
type EvalObserver func(id int64, programStep any, value ref.Val)
|
||||
|
||||
// Observe constructs a decorator that calls all the provided observers in order after evaluating each Interpretable
|
||||
// or Qualifier during program evaluation.
|
||||
@ -49,7 +47,7 @@ func Observe(observers ...EvalObserver) InterpretableDecorator {
|
||||
if len(observers) == 1 {
|
||||
return decObserveEval(observers[0])
|
||||
}
|
||||
observeFn := func(id int64, programStep interface{}, val ref.Val) {
|
||||
observeFn := func(id int64, programStep any, val ref.Val) {
|
||||
for _, observer := range observers {
|
||||
observer(id, programStep, val)
|
||||
}
|
||||
@ -96,7 +94,7 @@ func TrackState(state EvalState) InterpretableDecorator {
|
||||
// This decorator is not thread-safe, and the EvalState must be reset between Eval()
|
||||
// calls.
|
||||
func EvalStateObserver(state EvalState) EvalObserver {
|
||||
return func(id int64, programStep interface{}, val ref.Val) {
|
||||
return func(id int64, programStep any, val ref.Val) {
|
||||
state.SetValue(id, val)
|
||||
}
|
||||
}
|
||||
|
178
vendor/github.com/google/cel-go/interpreter/planner.go
generated
vendored
178
vendor/github.com/google/cel-go/interpreter/planner.go
generated
vendored
@ -20,7 +20,6 @@ import (
|
||||
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/interpreter/functions"
|
||||
|
||||
@ -189,16 +188,7 @@ func (p *planner) planSelect(expr *exprpb.Expr) (Interpretable, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Determine the field type if this is a proto message type.
|
||||
var fieldType *ref.FieldType
|
||||
opType := p.typeMap[sel.GetOperand().GetId()]
|
||||
if opType.GetMessageType() != "" {
|
||||
ft, found := p.provider.FindFieldType(opType.GetMessageType(), sel.GetField())
|
||||
if found && ft.IsSet != nil && ft.GetFrom != nil {
|
||||
fieldType = ft
|
||||
}
|
||||
}
|
||||
|
||||
// If the Select was marked TestOnly, this is a presence test.
|
||||
//
|
||||
@ -211,37 +201,31 @@ func (p *planner) planSelect(expr *exprpb.Expr) (Interpretable, error) {
|
||||
// If a string named 'a.b.c' is declared in the environment and referenced within `has(a.b.c)`,
|
||||
// it is not clear whether has should error or follow the convention defined for structured
|
||||
// values.
|
||||
if sel.TestOnly {
|
||||
// Return the test only eval expression.
|
||||
return &evalTestOnly{
|
||||
id: expr.GetId(),
|
||||
field: types.String(sel.GetField()),
|
||||
fieldType: fieldType,
|
||||
op: op,
|
||||
}, nil
|
||||
}
|
||||
// Build a qualifier.
|
||||
qual, err := p.attrFactory.NewQualifier(
|
||||
opType, expr.GetId(), sel.GetField())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Lastly, create a field selection Interpretable.
|
||||
|
||||
// Establish the attribute reference.
|
||||
attr, isAttr := op.(InterpretableAttribute)
|
||||
if isAttr {
|
||||
_, err = attr.AddQualifier(qual)
|
||||
return attr, err
|
||||
if !isAttr {
|
||||
attr, err = p.relativeAttr(op.ID(), op, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
relAttr, err := p.relativeAttr(op.ID(), op)
|
||||
// Build a qualifier for the attribute.
|
||||
qual, err := p.attrFactory.NewQualifier(opType, expr.GetId(), sel.GetField(), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = relAttr.AddQualifier(qual)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Modify the attribute to be test-only.
|
||||
if sel.GetTestOnly() {
|
||||
attr = &evalTestOnly{
|
||||
id: expr.GetId(),
|
||||
InterpretableAttribute: attr,
|
||||
}
|
||||
}
|
||||
return relAttr, nil
|
||||
// Append the qualifier on the attribute.
|
||||
_, err = attr.AddQualifier(qual)
|
||||
return attr, err
|
||||
}
|
||||
|
||||
// planCall creates a callable Interpretable while specializing for common functions and invocation
|
||||
@ -286,7 +270,9 @@ func (p *planner) planCall(expr *exprpb.Expr) (Interpretable, error) {
|
||||
case operators.NotEquals:
|
||||
return p.planCallNotEqual(expr, args)
|
||||
case operators.Index:
|
||||
return p.planCallIndex(expr, args)
|
||||
return p.planCallIndex(expr, args, false)
|
||||
case operators.OptSelect, operators.OptIndex:
|
||||
return p.planCallIndex(expr, args, true)
|
||||
}
|
||||
|
||||
// Otherwise, generate Interpretable calls specialized by argument count.
|
||||
@ -423,8 +409,7 @@ func (p *planner) planCallVarArgs(expr *exprpb.Expr,
|
||||
}
|
||||
|
||||
// planCallEqual generates an equals (==) Interpretable.
|
||||
func (p *planner) planCallEqual(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
func (p *planner) planCallEqual(expr *exprpb.Expr, args []Interpretable) (Interpretable, error) {
|
||||
return &evalEq{
|
||||
id: expr.GetId(),
|
||||
lhs: args[0],
|
||||
@ -433,8 +418,7 @@ func (p *planner) planCallEqual(expr *exprpb.Expr,
|
||||
}
|
||||
|
||||
// planCallNotEqual generates a not equals (!=) Interpretable.
|
||||
func (p *planner) planCallNotEqual(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
func (p *planner) planCallNotEqual(expr *exprpb.Expr, args []Interpretable) (Interpretable, error) {
|
||||
return &evalNe{
|
||||
id: expr.GetId(),
|
||||
lhs: args[0],
|
||||
@ -443,8 +427,7 @@ func (p *planner) planCallNotEqual(expr *exprpb.Expr,
|
||||
}
|
||||
|
||||
// planCallLogicalAnd generates a logical and (&&) Interpretable.
|
||||
func (p *planner) planCallLogicalAnd(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
func (p *planner) planCallLogicalAnd(expr *exprpb.Expr, args []Interpretable) (Interpretable, error) {
|
||||
return &evalAnd{
|
||||
id: expr.GetId(),
|
||||
lhs: args[0],
|
||||
@ -453,8 +436,7 @@ func (p *planner) planCallLogicalAnd(expr *exprpb.Expr,
|
||||
}
|
||||
|
||||
// planCallLogicalOr generates a logical or (||) Interpretable.
|
||||
func (p *planner) planCallLogicalOr(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
func (p *planner) planCallLogicalOr(expr *exprpb.Expr, args []Interpretable) (Interpretable, error) {
|
||||
return &evalOr{
|
||||
id: expr.GetId(),
|
||||
lhs: args[0],
|
||||
@ -463,10 +445,8 @@ func (p *planner) planCallLogicalOr(expr *exprpb.Expr,
|
||||
}
|
||||
|
||||
// planCallConditional generates a conditional / ternary (c ? t : f) Interpretable.
|
||||
func (p *planner) planCallConditional(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
func (p *planner) planCallConditional(expr *exprpb.Expr, args []Interpretable) (Interpretable, error) {
|
||||
cond := args[0]
|
||||
|
||||
t := args[1]
|
||||
var tAttr Attribute
|
||||
truthyAttr, isTruthyAttr := t.(InterpretableAttribute)
|
||||
@ -493,48 +473,54 @@ func (p *planner) planCallConditional(expr *exprpb.Expr,
|
||||
|
||||
// planCallIndex either extends an attribute with the argument to the index operation, or creates
|
||||
// a relative attribute based on the return of a function call or operation.
|
||||
func (p *planner) planCallIndex(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
func (p *planner) planCallIndex(expr *exprpb.Expr, args []Interpretable, optional bool) (Interpretable, error) {
|
||||
op := args[0]
|
||||
ind := args[1]
|
||||
opAttr, err := p.relativeAttr(op.ID(), op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opType := p.typeMap[expr.GetCallExpr().GetTarget().GetId()]
|
||||
indConst, isIndConst := ind.(InterpretableConst)
|
||||
if isIndConst {
|
||||
qual, err := p.attrFactory.NewQualifier(
|
||||
opType, expr.GetId(), indConst.Value())
|
||||
|
||||
// Establish the attribute reference.
|
||||
var err error
|
||||
attr, isAttr := op.(InterpretableAttribute)
|
||||
if !isAttr {
|
||||
attr, err = p.relativeAttr(op.ID(), op, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = opAttr.AddQualifier(qual)
|
||||
return opAttr, err
|
||||
}
|
||||
indAttr, isIndAttr := ind.(InterpretableAttribute)
|
||||
if isIndAttr {
|
||||
qual, err := p.attrFactory.NewQualifier(
|
||||
opType, expr.GetId(), indAttr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = opAttr.AddQualifier(qual)
|
||||
return opAttr, err
|
||||
|
||||
// Construct the qualifier type.
|
||||
var qual Qualifier
|
||||
switch ind := ind.(type) {
|
||||
case InterpretableConst:
|
||||
qual, err = p.attrFactory.NewQualifier(opType, expr.GetId(), ind.Value(), optional)
|
||||
case InterpretableAttribute:
|
||||
qual, err = p.attrFactory.NewQualifier(opType, expr.GetId(), ind, optional)
|
||||
default:
|
||||
qual, err = p.relativeAttr(expr.GetId(), ind, optional)
|
||||
}
|
||||
indQual, err := p.relativeAttr(expr.GetId(), ind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = opAttr.AddQualifier(indQual)
|
||||
return opAttr, err
|
||||
|
||||
// Add the qualifier to the attribute
|
||||
_, err = attr.AddQualifier(qual)
|
||||
return attr, err
|
||||
}
|
||||
|
||||
// planCreateList generates a list construction Interpretable.
|
||||
func (p *planner) planCreateList(expr *exprpb.Expr) (Interpretable, error) {
|
||||
list := expr.GetListExpr()
|
||||
elems := make([]Interpretable, len(list.GetElements()))
|
||||
for i, elem := range list.GetElements() {
|
||||
optionalIndices := list.GetOptionalIndices()
|
||||
elements := list.GetElements()
|
||||
optionals := make([]bool, len(elements))
|
||||
for _, index := range optionalIndices {
|
||||
if index < 0 || index >= int32(len(elements)) {
|
||||
return nil, fmt.Errorf("optional index %d out of element bounds [0, %d]", index, len(elements))
|
||||
}
|
||||
optionals[index] = true
|
||||
}
|
||||
elems := make([]Interpretable, len(elements))
|
||||
for i, elem := range elements {
|
||||
elemVal, err := p.Plan(elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -542,9 +528,11 @@ func (p *planner) planCreateList(expr *exprpb.Expr) (Interpretable, error) {
|
||||
elems[i] = elemVal
|
||||
}
|
||||
return &evalList{
|
||||
id: expr.GetId(),
|
||||
elems: elems,
|
||||
adapter: p.adapter,
|
||||
id: expr.GetId(),
|
||||
elems: elems,
|
||||
optionals: optionals,
|
||||
hasOptionals: len(optionals) != 0,
|
||||
adapter: p.adapter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -555,6 +543,7 @@ func (p *planner) planCreateStruct(expr *exprpb.Expr) (Interpretable, error) {
|
||||
return p.planCreateObj(expr)
|
||||
}
|
||||
entries := str.GetEntries()
|
||||
optionals := make([]bool, len(entries))
|
||||
keys := make([]Interpretable, len(entries))
|
||||
vals := make([]Interpretable, len(entries))
|
||||
for i, entry := range entries {
|
||||
@ -569,23 +558,27 @@ func (p *planner) planCreateStruct(expr *exprpb.Expr) (Interpretable, error) {
|
||||
return nil, err
|
||||
}
|
||||
vals[i] = valVal
|
||||
optionals[i] = entry.GetOptionalEntry()
|
||||
}
|
||||
return &evalMap{
|
||||
id: expr.GetId(),
|
||||
keys: keys,
|
||||
vals: vals,
|
||||
adapter: p.adapter,
|
||||
id: expr.GetId(),
|
||||
keys: keys,
|
||||
vals: vals,
|
||||
optionals: optionals,
|
||||
hasOptionals: len(optionals) != 0,
|
||||
adapter: p.adapter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCreateObj generates an object construction Interpretable.
|
||||
func (p *planner) planCreateObj(expr *exprpb.Expr) (Interpretable, error) {
|
||||
obj := expr.GetStructExpr()
|
||||
typeName, defined := p.resolveTypeName(obj.MessageName)
|
||||
typeName, defined := p.resolveTypeName(obj.GetMessageName())
|
||||
if !defined {
|
||||
return nil, fmt.Errorf("unknown type: %s", typeName)
|
||||
return nil, fmt.Errorf("unknown type: %s", obj.GetMessageName())
|
||||
}
|
||||
entries := obj.GetEntries()
|
||||
optionals := make([]bool, len(entries))
|
||||
fields := make([]string, len(entries))
|
||||
vals := make([]Interpretable, len(entries))
|
||||
for i, entry := range entries {
|
||||
@ -595,13 +588,16 @@ func (p *planner) planCreateObj(expr *exprpb.Expr) (Interpretable, error) {
|
||||
return nil, err
|
||||
}
|
||||
vals[i] = val
|
||||
optionals[i] = entry.GetOptionalEntry()
|
||||
}
|
||||
return &evalObj{
|
||||
id: expr.GetId(),
|
||||
typeName: typeName,
|
||||
fields: fields,
|
||||
vals: vals,
|
||||
provider: p.provider,
|
||||
id: expr.GetId(),
|
||||
typeName: typeName,
|
||||
fields: fields,
|
||||
vals: vals,
|
||||
optionals: optionals,
|
||||
hasOptionals: len(optionals) != 0,
|
||||
provider: p.provider,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -753,14 +749,18 @@ func (p *planner) resolveFunction(expr *exprpb.Expr) (*exprpb.Expr, string, stri
|
||||
return target, fnName, ""
|
||||
}
|
||||
|
||||
func (p *planner) relativeAttr(id int64, eval Interpretable) (InterpretableAttribute, error) {
|
||||
// relativeAttr indicates that the attribute in this case acts as a qualifier and as such needs to
|
||||
// be observed to ensure that it's evaluation value is properly recorded for state tracking.
|
||||
func (p *planner) relativeAttr(id int64, eval Interpretable, opt bool) (InterpretableAttribute, error) {
|
||||
eAttr, ok := eval.(InterpretableAttribute)
|
||||
if !ok {
|
||||
eAttr = &evalAttr{
|
||||
adapter: p.adapter,
|
||||
attr: p.attrFactory.RelativeAttribute(id, eval),
|
||||
adapter: p.adapter,
|
||||
attr: p.attrFactory.RelativeAttribute(id, eval),
|
||||
optional: opt,
|
||||
}
|
||||
}
|
||||
// This looks like it should either decorate the new evalAttr node, or early return the InterpretableAttribute
|
||||
decAttr, err := p.decorate(eAttr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
381
vendor/github.com/google/cel-go/interpreter/prune.go
generated
vendored
381
vendor/github.com/google/cel-go/interpreter/prune.go
generated
vendored
@ -16,6 +16,7 @@ package interpreter
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
@ -26,6 +27,7 @@ import (
|
||||
|
||||
type astPruner struct {
|
||||
expr *exprpb.Expr
|
||||
macroCalls map[int64]*exprpb.Expr
|
||||
state EvalState
|
||||
nextExprID int64
|
||||
}
|
||||
@ -65,13 +67,22 @@ type astPruner struct {
|
||||
// compiled and constant folded expressions, but is not willing to constant
|
||||
// fold(and thus cache results of) some external calls, then they can prepare
|
||||
// the overloads accordingly.
|
||||
func PruneAst(expr *exprpb.Expr, state EvalState) *exprpb.Expr {
|
||||
func PruneAst(expr *exprpb.Expr, macroCalls map[int64]*exprpb.Expr, state EvalState) *exprpb.ParsedExpr {
|
||||
pruneState := NewEvalState()
|
||||
for _, id := range state.IDs() {
|
||||
v, _ := state.Value(id)
|
||||
pruneState.SetValue(id, v)
|
||||
}
|
||||
pruner := &astPruner{
|
||||
expr: expr,
|
||||
state: state,
|
||||
nextExprID: 1}
|
||||
newExpr, _ := pruner.prune(expr)
|
||||
return newExpr
|
||||
macroCalls: macroCalls,
|
||||
state: pruneState,
|
||||
nextExprID: getMaxID(expr)}
|
||||
newExpr, _ := pruner.maybePrune(expr)
|
||||
return &exprpb.ParsedExpr{
|
||||
Expr: newExpr,
|
||||
SourceInfo: &exprpb.SourceInfo{MacroCalls: pruner.macroCalls},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *astPruner) createLiteral(id int64, val *exprpb.Constant) *exprpb.Expr {
|
||||
@ -84,28 +95,50 @@ func (p *astPruner) createLiteral(id int64, val *exprpb.Constant) *exprpb.Expr {
|
||||
}
|
||||
|
||||
func (p *astPruner) maybeCreateLiteral(id int64, val ref.Val) (*exprpb.Expr, bool) {
|
||||
switch val.Type() {
|
||||
case types.BoolType:
|
||||
switch v := val.(type) {
|
||||
case types.Bool:
|
||||
p.state.SetValue(id, val)
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_BoolValue{BoolValue: val.Value().(bool)}}), true
|
||||
case types.IntType:
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_BoolValue{BoolValue: bool(v)}}), true
|
||||
case types.Bytes:
|
||||
p.state.SetValue(id, val)
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_Int64Value{Int64Value: val.Value().(int64)}}), true
|
||||
case types.UintType:
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_BytesValue{BytesValue: []byte(v)}}), true
|
||||
case types.Double:
|
||||
p.state.SetValue(id, val)
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_Uint64Value{Uint64Value: val.Value().(uint64)}}), true
|
||||
case types.StringType:
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_DoubleValue{DoubleValue: float64(v)}}), true
|
||||
case types.Duration:
|
||||
p.state.SetValue(id, val)
|
||||
durationString := string(v.ConvertToType(types.StringType).(types.String))
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_CallExpr{
|
||||
CallExpr: &exprpb.Expr_Call{
|
||||
Function: overloads.TypeConvertDuration,
|
||||
Args: []*exprpb.Expr{
|
||||
p.createLiteral(p.nextID(),
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_StringValue{StringValue: durationString}}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}, true
|
||||
case types.Int:
|
||||
p.state.SetValue(id, val)
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_StringValue{StringValue: val.Value().(string)}}), true
|
||||
case types.DoubleType:
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_Int64Value{Int64Value: int64(v)}}), true
|
||||
case types.Uint:
|
||||
p.state.SetValue(id, val)
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_DoubleValue{DoubleValue: val.Value().(float64)}}), true
|
||||
case types.BytesType:
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_Uint64Value{Uint64Value: uint64(v)}}), true
|
||||
case types.String:
|
||||
p.state.SetValue(id, val)
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_BytesValue{BytesValue: val.Value().([]byte)}}), true
|
||||
case types.NullType:
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_StringValue{StringValue: string(v)}}), true
|
||||
case types.Null:
|
||||
p.state.SetValue(id, val)
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_NullValue{NullValue: val.Value().(structpb.NullValue)}}), true
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_NullValue{NullValue: v.Value().(structpb.NullValue)}}), true
|
||||
}
|
||||
|
||||
// Attempt to build a list literal.
|
||||
@ -123,6 +156,7 @@ func (p *astPruner) maybeCreateLiteral(id int64, val ref.Val) (*exprpb.Expr, boo
|
||||
}
|
||||
elemExprs[i] = elemExpr
|
||||
}
|
||||
p.state.SetValue(id, val)
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_ListExpr{
|
||||
@ -162,6 +196,7 @@ func (p *astPruner) maybeCreateLiteral(id int64, val ref.Val) (*exprpb.Expr, boo
|
||||
entries[i] = entry
|
||||
i++
|
||||
}
|
||||
p.state.SetValue(id, val)
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_StructExpr{
|
||||
@ -177,70 +212,147 @@ func (p *astPruner) maybeCreateLiteral(id int64, val ref.Val) (*exprpb.Expr, boo
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePruneAndOr(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
if !p.existsWithUnknownValue(node.GetId()) {
|
||||
func (p *astPruner) maybePruneOptional(elem *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
elemVal, found := p.value(elem.GetId())
|
||||
if found && elemVal.Type() == types.OptionalType {
|
||||
opt := elemVal.(*types.Optional)
|
||||
if !opt.HasValue() {
|
||||
return nil, true
|
||||
}
|
||||
if newElem, pruned := p.maybeCreateLiteral(elem.GetId(), opt.GetValue()); pruned {
|
||||
return newElem, true
|
||||
}
|
||||
}
|
||||
return elem, false
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePruneIn(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
// elem in list
|
||||
call := node.GetCallExpr()
|
||||
val, exists := p.maybeValue(call.GetArgs()[1].GetId())
|
||||
if !exists {
|
||||
return nil, false
|
||||
}
|
||||
if sz, ok := val.(traits.Sizer); ok && sz.Size() == types.IntZero {
|
||||
return p.maybeCreateLiteral(node.GetId(), types.False)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePruneLogicalNot(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
call := node.GetCallExpr()
|
||||
arg := call.GetArgs()[0]
|
||||
val, exists := p.maybeValue(arg.GetId())
|
||||
if !exists {
|
||||
return nil, false
|
||||
}
|
||||
if b, ok := val.(types.Bool); ok {
|
||||
return p.maybeCreateLiteral(node.GetId(), !b)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePruneOr(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
call := node.GetCallExpr()
|
||||
// We know result is unknown, so we have at least one unknown arg
|
||||
// and if one side is a known value, we know we can ignore it.
|
||||
if p.existsWithKnownValue(call.Args[0].GetId()) {
|
||||
return call.Args[1], true
|
||||
if v, exists := p.maybeValue(call.GetArgs()[0].GetId()); exists {
|
||||
if v == types.True {
|
||||
return p.maybeCreateLiteral(node.GetId(), types.True)
|
||||
}
|
||||
return call.GetArgs()[1], true
|
||||
}
|
||||
if p.existsWithKnownValue(call.Args[1].GetId()) {
|
||||
return call.Args[0], true
|
||||
if v, exists := p.maybeValue(call.GetArgs()[1].GetId()); exists {
|
||||
if v == types.True {
|
||||
return p.maybeCreateLiteral(node.GetId(), types.True)
|
||||
}
|
||||
return call.GetArgs()[0], true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePruneAnd(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
call := node.GetCallExpr()
|
||||
// We know result is unknown, so we have at least one unknown arg
|
||||
// and if one side is a known value, we know we can ignore it.
|
||||
if v, exists := p.maybeValue(call.GetArgs()[0].GetId()); exists {
|
||||
if v == types.False {
|
||||
return p.maybeCreateLiteral(node.GetId(), types.False)
|
||||
}
|
||||
return call.GetArgs()[1], true
|
||||
}
|
||||
if v, exists := p.maybeValue(call.GetArgs()[1].GetId()); exists {
|
||||
if v == types.False {
|
||||
return p.maybeCreateLiteral(node.GetId(), types.False)
|
||||
}
|
||||
return call.GetArgs()[0], true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePruneConditional(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
if !p.existsWithUnknownValue(node.GetId()) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
call := node.GetCallExpr()
|
||||
condVal, condValueExists := p.value(call.Args[0].GetId())
|
||||
if !condValueExists || types.IsUnknownOrError(condVal) {
|
||||
cond, exists := p.maybeValue(call.GetArgs()[0].GetId())
|
||||
if !exists {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if condVal.Value().(bool) {
|
||||
return call.Args[1], true
|
||||
if cond.Value().(bool) {
|
||||
return call.GetArgs()[1], true
|
||||
}
|
||||
return call.Args[2], true
|
||||
return call.GetArgs()[2], true
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePruneFunction(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
if _, exists := p.value(node.GetId()); !exists {
|
||||
return nil, false
|
||||
}
|
||||
call := node.GetCallExpr()
|
||||
if call.Function == operators.LogicalOr || call.Function == operators.LogicalAnd {
|
||||
return p.maybePruneAndOr(node)
|
||||
if call.Function == operators.LogicalOr {
|
||||
return p.maybePruneOr(node)
|
||||
}
|
||||
if call.Function == operators.LogicalAnd {
|
||||
return p.maybePruneAnd(node)
|
||||
}
|
||||
if call.Function == operators.Conditional {
|
||||
return p.maybePruneConditional(node)
|
||||
}
|
||||
|
||||
if call.Function == operators.In {
|
||||
return p.maybePruneIn(node)
|
||||
}
|
||||
if call.Function == operators.LogicalNot {
|
||||
return p.maybePruneLogicalNot(node)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePrune(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
return p.prune(node)
|
||||
}
|
||||
|
||||
func (p *astPruner) prune(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
if node == nil {
|
||||
return node, false
|
||||
}
|
||||
val, valueExists := p.value(node.GetId())
|
||||
if valueExists && !types.IsUnknownOrError(val) {
|
||||
val, valueExists := p.maybeValue(node.GetId())
|
||||
if valueExists {
|
||||
if newNode, ok := p.maybeCreateLiteral(node.GetId(), val); ok {
|
||||
delete(p.macroCalls, node.GetId())
|
||||
return newNode, true
|
||||
}
|
||||
}
|
||||
if macro, found := p.macroCalls[node.GetId()]; found {
|
||||
// prune the expression in terms of the macro call instead of the expanded form.
|
||||
if newMacro, pruned := p.prune(macro); pruned {
|
||||
p.macroCalls[node.GetId()] = newMacro
|
||||
}
|
||||
}
|
||||
|
||||
// We have either an unknown/error value, or something we don't want to
|
||||
// transform, or expression was not evaluated. If possible, drill down
|
||||
// more.
|
||||
|
||||
switch node.GetExprKind().(type) {
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
if operand, pruned := p.prune(node.GetSelectExpr().GetOperand()); pruned {
|
||||
if operand, pruned := p.maybePrune(node.GetSelectExpr().GetOperand()); pruned {
|
||||
return &exprpb.Expr{
|
||||
Id: node.GetId(),
|
||||
ExprKind: &exprpb.Expr_SelectExpr{
|
||||
@ -253,10 +365,6 @@ func (p *astPruner) prune(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
}, true
|
||||
}
|
||||
case *exprpb.Expr_CallExpr:
|
||||
if newExpr, pruned := p.maybePruneFunction(node); pruned {
|
||||
newExpr, _ = p.prune(newExpr)
|
||||
return newExpr, true
|
||||
}
|
||||
var prunedCall bool
|
||||
call := node.GetCallExpr()
|
||||
args := call.GetArgs()
|
||||
@ -268,40 +376,75 @@ func (p *astPruner) prune(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
}
|
||||
for i, arg := range args {
|
||||
newArgs[i] = arg
|
||||
if newArg, prunedArg := p.prune(arg); prunedArg {
|
||||
if newArg, prunedArg := p.maybePrune(arg); prunedArg {
|
||||
prunedCall = true
|
||||
newArgs[i] = newArg
|
||||
}
|
||||
}
|
||||
if newTarget, prunedTarget := p.prune(call.GetTarget()); prunedTarget {
|
||||
if newTarget, prunedTarget := p.maybePrune(call.GetTarget()); prunedTarget {
|
||||
prunedCall = true
|
||||
newCall.Target = newTarget
|
||||
}
|
||||
newNode := &exprpb.Expr{
|
||||
Id: node.GetId(),
|
||||
ExprKind: &exprpb.Expr_CallExpr{
|
||||
CallExpr: newCall,
|
||||
},
|
||||
}
|
||||
if newExpr, pruned := p.maybePruneFunction(newNode); pruned {
|
||||
newExpr, _ = p.maybePrune(newExpr)
|
||||
return newExpr, true
|
||||
}
|
||||
if prunedCall {
|
||||
return &exprpb.Expr{
|
||||
Id: node.GetId(),
|
||||
ExprKind: &exprpb.Expr_CallExpr{
|
||||
CallExpr: newCall,
|
||||
},
|
||||
}, true
|
||||
return newNode, true
|
||||
}
|
||||
case *exprpb.Expr_ListExpr:
|
||||
elems := node.GetListExpr().GetElements()
|
||||
newElems := make([]*exprpb.Expr, len(elems))
|
||||
optIndices := node.GetListExpr().GetOptionalIndices()
|
||||
optIndexMap := map[int32]bool{}
|
||||
for _, i := range optIndices {
|
||||
optIndexMap[i] = true
|
||||
}
|
||||
newOptIndexMap := make(map[int32]bool, len(optIndexMap))
|
||||
newElems := make([]*exprpb.Expr, 0, len(elems))
|
||||
var prunedList bool
|
||||
|
||||
prunedIdx := 0
|
||||
for i, elem := range elems {
|
||||
newElems[i] = elem
|
||||
if newElem, prunedElem := p.prune(elem); prunedElem {
|
||||
newElems[i] = newElem
|
||||
prunedList = true
|
||||
_, isOpt := optIndexMap[int32(i)]
|
||||
if isOpt {
|
||||
newElem, pruned := p.maybePruneOptional(elem)
|
||||
if pruned {
|
||||
prunedList = true
|
||||
if newElem != nil {
|
||||
newElems = append(newElems, newElem)
|
||||
prunedIdx++
|
||||
}
|
||||
continue
|
||||
}
|
||||
newOptIndexMap[int32(prunedIdx)] = true
|
||||
}
|
||||
if newElem, prunedElem := p.maybePrune(elem); prunedElem {
|
||||
newElems = append(newElems, newElem)
|
||||
prunedList = true
|
||||
} else {
|
||||
newElems = append(newElems, elem)
|
||||
}
|
||||
prunedIdx++
|
||||
}
|
||||
optIndices = make([]int32, len(newOptIndexMap))
|
||||
idx := 0
|
||||
for i := range newOptIndexMap {
|
||||
optIndices[idx] = i
|
||||
idx++
|
||||
}
|
||||
if prunedList {
|
||||
return &exprpb.Expr{
|
||||
Id: node.GetId(),
|
||||
ExprKind: &exprpb.Expr_ListExpr{
|
||||
ListExpr: &exprpb.Expr_CreateList{
|
||||
Elements: newElems,
|
||||
Elements: newElems,
|
||||
OptionalIndices: optIndices,
|
||||
},
|
||||
},
|
||||
}, true
|
||||
@ -313,8 +456,8 @@ func (p *astPruner) prune(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
newEntries := make([]*exprpb.Expr_CreateStruct_Entry, len(entries))
|
||||
for i, entry := range entries {
|
||||
newEntries[i] = entry
|
||||
newKey, prunedKey := p.prune(entry.GetMapKey())
|
||||
newValue, prunedValue := p.prune(entry.GetValue())
|
||||
newKey, prunedKey := p.maybePrune(entry.GetMapKey())
|
||||
newValue, prunedValue := p.maybePrune(entry.GetValue())
|
||||
if !prunedKey && !prunedValue {
|
||||
continue
|
||||
}
|
||||
@ -331,6 +474,7 @@ func (p *astPruner) prune(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
MapKey: newKey,
|
||||
}
|
||||
}
|
||||
newEntry.OptionalEntry = entry.GetOptionalEntry()
|
||||
newEntries[i] = newEntry
|
||||
}
|
||||
if prunedStruct {
|
||||
@ -344,27 +488,6 @@ func (p *astPruner) prune(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
},
|
||||
}, true
|
||||
}
|
||||
case *exprpb.Expr_ComprehensionExpr:
|
||||
compre := node.GetComprehensionExpr()
|
||||
// Only the range of the comprehension is pruned since the state tracking only records
|
||||
// the last iteration of the comprehension and not each step in the evaluation which
|
||||
// means that the any residuals computed in between might be inaccurate.
|
||||
if newRange, pruned := p.prune(compre.GetIterRange()); pruned {
|
||||
return &exprpb.Expr{
|
||||
Id: node.GetId(),
|
||||
ExprKind: &exprpb.Expr_ComprehensionExpr{
|
||||
ComprehensionExpr: &exprpb.Expr_Comprehension{
|
||||
IterVar: compre.GetIterVar(),
|
||||
IterRange: newRange,
|
||||
AccuVar: compre.GetAccuVar(),
|
||||
AccuInit: compre.GetAccuInit(),
|
||||
LoopCondition: compre.GetLoopCondition(),
|
||||
LoopStep: compre.GetLoopStep(),
|
||||
Result: compre.GetResult(),
|
||||
},
|
||||
},
|
||||
}, true
|
||||
}
|
||||
}
|
||||
return node, false
|
||||
}
|
||||
@ -374,24 +497,82 @@ func (p *astPruner) value(id int64) (ref.Val, bool) {
|
||||
return val, (found && val != nil)
|
||||
}
|
||||
|
||||
func (p *astPruner) existsWithUnknownValue(id int64) bool {
|
||||
val, valueExists := p.value(id)
|
||||
return valueExists && types.IsUnknown(val)
|
||||
}
|
||||
|
||||
func (p *astPruner) existsWithKnownValue(id int64) bool {
|
||||
val, valueExists := p.value(id)
|
||||
return valueExists && !types.IsUnknown(val)
|
||||
func (p *astPruner) maybeValue(id int64) (ref.Val, bool) {
|
||||
val, found := p.value(id)
|
||||
if !found || types.IsUnknownOrError(val) {
|
||||
return nil, false
|
||||
}
|
||||
return val, true
|
||||
}
|
||||
|
||||
func (p *astPruner) nextID() int64 {
|
||||
for {
|
||||
_, found := p.state.Value(p.nextExprID)
|
||||
if !found {
|
||||
next := p.nextExprID
|
||||
p.nextExprID++
|
||||
return next
|
||||
}
|
||||
p.nextExprID++
|
||||
next := p.nextExprID
|
||||
p.nextExprID++
|
||||
return next
|
||||
}
|
||||
|
||||
type astVisitor struct {
|
||||
// visitEntry is called on every expr node, including those within a map/struct entry.
|
||||
visitExpr func(expr *exprpb.Expr)
|
||||
// visitEntry is called before entering the key, value of a map/struct entry.
|
||||
visitEntry func(entry *exprpb.Expr_CreateStruct_Entry)
|
||||
}
|
||||
|
||||
func getMaxID(expr *exprpb.Expr) int64 {
|
||||
maxID := int64(1)
|
||||
visit(expr, maxIDVisitor(&maxID))
|
||||
return maxID
|
||||
}
|
||||
|
||||
func maxIDVisitor(maxID *int64) astVisitor {
|
||||
return astVisitor{
|
||||
visitExpr: func(e *exprpb.Expr) {
|
||||
if e.GetId() >= *maxID {
|
||||
*maxID = e.GetId() + 1
|
||||
}
|
||||
},
|
||||
visitEntry: func(e *exprpb.Expr_CreateStruct_Entry) {
|
||||
if e.GetId() >= *maxID {
|
||||
*maxID = e.GetId() + 1
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func visit(expr *exprpb.Expr, visitor astVisitor) {
|
||||
exprs := []*exprpb.Expr{expr}
|
||||
for len(exprs) != 0 {
|
||||
e := exprs[0]
|
||||
visitor.visitExpr(e)
|
||||
exprs = exprs[1:]
|
||||
switch e.GetExprKind().(type) {
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
exprs = append(exprs, e.GetSelectExpr().GetOperand())
|
||||
case *exprpb.Expr_CallExpr:
|
||||
call := e.GetCallExpr()
|
||||
if call.GetTarget() != nil {
|
||||
exprs = append(exprs, call.GetTarget())
|
||||
}
|
||||
exprs = append(exprs, call.GetArgs()...)
|
||||
case *exprpb.Expr_ComprehensionExpr:
|
||||
compre := e.GetComprehensionExpr()
|
||||
exprs = append(exprs,
|
||||
compre.GetIterRange(),
|
||||
compre.GetAccuInit(),
|
||||
compre.GetLoopCondition(),
|
||||
compre.GetLoopStep(),
|
||||
compre.GetResult())
|
||||
case *exprpb.Expr_ListExpr:
|
||||
list := e.GetListExpr()
|
||||
exprs = append(exprs, list.GetElements()...)
|
||||
case *exprpb.Expr_StructExpr:
|
||||
for _, entry := range e.GetStructExpr().GetEntries() {
|
||||
visitor.visitEntry(entry)
|
||||
if entry.GetMapKey() != nil {
|
||||
exprs = append(exprs, entry.GetMapKey())
|
||||
}
|
||||
exprs = append(exprs, entry.GetValue())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
58
vendor/github.com/google/cel-go/interpreter/runtimecost.go
generated
vendored
58
vendor/github.com/google/cel-go/interpreter/runtimecost.go
generated
vendored
@ -36,7 +36,7 @@ type ActualCostEstimator interface {
|
||||
|
||||
// CostObserver provides an observer that tracks runtime cost.
|
||||
func CostObserver(tracker *CostTracker) EvalObserver {
|
||||
observer := func(id int64, programStep interface{}, val ref.Val) {
|
||||
observer := func(id int64, programStep any, val ref.Val) {
|
||||
switch t := programStep.(type) {
|
||||
case ConstantQualifier:
|
||||
// TODO: Push identifiers on to the stack before observing constant qualifiers that apply to them
|
||||
@ -53,6 +53,11 @@ func CostObserver(tracker *CostTracker) EvalObserver {
|
||||
tracker.stack.drop(t.Attr().ID())
|
||||
tracker.cost += common.SelectAndIdentCost
|
||||
}
|
||||
if !tracker.presenceTestHasCost {
|
||||
if _, isTestOnly := programStep.(*evalTestOnly); isTestOnly {
|
||||
tracker.cost -= common.SelectAndIdentCost
|
||||
}
|
||||
}
|
||||
case *evalExhaustiveConditional:
|
||||
// Ternary has no direct cost. All cost is from the conditional and the true/false branch expressions.
|
||||
tracker.stack.drop(t.attr.falsy.ID(), t.attr.truthy.ID(), t.attr.expr.ID())
|
||||
@ -95,21 +100,58 @@ func CostObserver(tracker *CostTracker) EvalObserver {
|
||||
return observer
|
||||
}
|
||||
|
||||
// CostTracker represents the information needed for tacking runtime cost
|
||||
// CostTrackerOption configures the behavior of CostTracker objects.
|
||||
type CostTrackerOption func(*CostTracker) error
|
||||
|
||||
// CostTrackerLimit sets the runtime limit on the evaluation cost during execution and will terminate the expression
|
||||
// evaluation if the limit is exceeded.
|
||||
func CostTrackerLimit(limit uint64) CostTrackerOption {
|
||||
return func(tracker *CostTracker) error {
|
||||
tracker.Limit = &limit
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// PresenceTestHasCost determines whether presence testing has a cost of one or zero.
|
||||
// Defaults to presence test has a cost of one.
|
||||
func PresenceTestHasCost(hasCost bool) CostTrackerOption {
|
||||
return func(tracker *CostTracker) error {
|
||||
tracker.presenceTestHasCost = hasCost
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewCostTracker creates a new CostTracker with a given estimator and a set of functional CostTrackerOption values.
|
||||
func NewCostTracker(estimator ActualCostEstimator, opts ...CostTrackerOption) (*CostTracker, error) {
|
||||
tracker := &CostTracker{
|
||||
Estimator: estimator,
|
||||
presenceTestHasCost: true,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
err := opt(tracker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return tracker, nil
|
||||
}
|
||||
|
||||
// CostTracker represents the information needed for tracking runtime cost.
|
||||
type CostTracker struct {
|
||||
Estimator ActualCostEstimator
|
||||
Limit *uint64
|
||||
Estimator ActualCostEstimator
|
||||
Limit *uint64
|
||||
presenceTestHasCost bool
|
||||
|
||||
cost uint64
|
||||
stack refValStack
|
||||
}
|
||||
|
||||
// ActualCost returns the runtime cost
|
||||
func (c CostTracker) ActualCost() uint64 {
|
||||
func (c *CostTracker) ActualCost() uint64 {
|
||||
return c.cost
|
||||
}
|
||||
|
||||
func (c CostTracker) costCall(call InterpretableCall, argValues []ref.Val, result ref.Val) uint64 {
|
||||
func (c *CostTracker) costCall(call InterpretableCall, argValues []ref.Val, result ref.Val) uint64 {
|
||||
var cost uint64
|
||||
if c.Estimator != nil {
|
||||
callCost := c.Estimator.CallCost(call.Function(), call.OverloadID(), argValues, result)
|
||||
@ -122,7 +164,7 @@ func (c CostTracker) costCall(call InterpretableCall, argValues []ref.Val, resul
|
||||
// if user has their own implementation of ActualCostEstimator, make sure to cover the mapping between overloadId and cost calculation
|
||||
switch call.OverloadID() {
|
||||
// O(n) functions
|
||||
case overloads.StartsWithString, overloads.EndsWithString, overloads.StringToBytes, overloads.BytesToString:
|
||||
case overloads.StartsWithString, overloads.EndsWithString, overloads.StringToBytes, overloads.BytesToString, overloads.ExtQuoteString, overloads.ExtFormatString:
|
||||
cost += uint64(math.Ceil(float64(c.actualSize(argValues[0])) * common.StringTraversalCostFactor))
|
||||
case overloads.InList:
|
||||
// If a list is composed entirely of constant values this is O(1), but we don't account for that here.
|
||||
@ -179,7 +221,7 @@ func (c CostTracker) costCall(call InterpretableCall, argValues []ref.Val, resul
|
||||
}
|
||||
|
||||
// actualSize returns the size of value
|
||||
func (c CostTracker) actualSize(value ref.Val) uint64 {
|
||||
func (c *CostTracker) actualSize(value ref.Val) uint64 {
|
||||
if sz, ok := value.(traits.Sizer); ok {
|
||||
return uint64(sz.Size().(types.Int))
|
||||
}
|
||||
|
8
vendor/github.com/google/cel-go/parser/BUILD.bazel
generated
vendored
8
vendor/github.com/google/cel-go/parser/BUILD.bazel
generated
vendored
@ -23,8 +23,8 @@ go_library(
|
||||
"//common/operators:go_default_library",
|
||||
"//common/runes:go_default_library",
|
||||
"//parser/gen:go_default_library",
|
||||
"@com_github_antlr_antlr4_runtime_go_antlr//:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
"@com_github_antlr_antlr4_runtime_go_antlr_v4//:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
|
||||
],
|
||||
@ -34,6 +34,7 @@ go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"helper_test.go",
|
||||
"parser_test.go",
|
||||
"unescape_test.go",
|
||||
"unparser_test.go",
|
||||
@ -45,7 +46,8 @@ go_test(
|
||||
"//common/debug:go_default_library",
|
||||
"//parser/gen:go_default_library",
|
||||
"//test:go_default_library",
|
||||
"@com_github_antlr_antlr4_runtime_go_antlr//:go_default_library",
|
||||
"@com_github_antlr_antlr4_runtime_go_antlr_v4//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//testing/protocmp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
2
vendor/github.com/google/cel-go/parser/gen/BUILD.bazel
generated
vendored
2
vendor/github.com/google/cel-go/parser/gen/BUILD.bazel
generated
vendored
@ -21,6 +21,6 @@ go_library(
|
||||
],
|
||||
importpath = "github.com/google/cel-go/parser/gen",
|
||||
deps = [
|
||||
"@com_github_antlr_antlr4_runtime_go_antlr//:go_default_library",
|
||||
"@com_github_antlr_antlr4_runtime_go_antlr_v4//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
38
vendor/github.com/google/cel-go/parser/gen/CEL.g4
generated
vendored
38
vendor/github.com/google/cel-go/parser/gen/CEL.g4
generated
vendored
@ -52,16 +52,18 @@ unary
|
||||
|
||||
member
|
||||
: primary # PrimaryExpr
|
||||
| member op='.' id=IDENTIFIER (open='(' args=exprList? ')')? # SelectOrCall
|
||||
| member op='[' index=expr ']' # Index
|
||||
| member op='{' entries=fieldInitializerList? ','? '}' # CreateMessage
|
||||
| member op='.' (opt='?')? id=IDENTIFIER # Select
|
||||
| member op='.' id=IDENTIFIER open='(' args=exprList? ')' # MemberCall
|
||||
| member op='[' (opt='?')? index=expr ']' # Index
|
||||
;
|
||||
|
||||
primary
|
||||
: leadingDot='.'? id=IDENTIFIER (op='(' args=exprList? ')')? # IdentOrGlobalCall
|
||||
| '(' e=expr ')' # Nested
|
||||
| op='[' elems=exprList? ','? ']' # CreateList
|
||||
| op='[' elems=listInit? ','? ']' # CreateList
|
||||
| op='{' entries=mapInitializerList? ','? '}' # CreateStruct
|
||||
| leadingDot='.'? ids+=IDENTIFIER (ops+='.' ids+=IDENTIFIER)*
|
||||
op='{' entries=fieldInitializerList? ','? '}' # CreateMessage
|
||||
| literal # ConstantLiteral
|
||||
;
|
||||
|
||||
@ -69,23 +71,35 @@ exprList
|
||||
: e+=expr (',' e+=expr)*
|
||||
;
|
||||
|
||||
listInit
|
||||
: elems+=optExpr (',' elems+=optExpr)*
|
||||
;
|
||||
|
||||
fieldInitializerList
|
||||
: fields+=IDENTIFIER cols+=':' values+=expr (',' fields+=IDENTIFIER cols+=':' values+=expr)*
|
||||
: fields+=optField cols+=':' values+=expr (',' fields+=optField cols+=':' values+=expr)*
|
||||
;
|
||||
|
||||
optField
|
||||
: (opt='?')? IDENTIFIER
|
||||
;
|
||||
|
||||
mapInitializerList
|
||||
: keys+=expr cols+=':' values+=expr (',' keys+=expr cols+=':' values+=expr)*
|
||||
: keys+=optExpr cols+=':' values+=expr (',' keys+=optExpr cols+=':' values+=expr)*
|
||||
;
|
||||
|
||||
optExpr
|
||||
: (opt='?')? e=expr
|
||||
;
|
||||
|
||||
literal
|
||||
: sign=MINUS? tok=NUM_INT # Int
|
||||
| tok=NUM_UINT # Uint
|
||||
| tok=NUM_UINT # Uint
|
||||
| sign=MINUS? tok=NUM_FLOAT # Double
|
||||
| tok=STRING # String
|
||||
| tok=BYTES # Bytes
|
||||
| tok=CEL_TRUE # BoolTrue
|
||||
| tok=CEL_FALSE # BoolFalse
|
||||
| tok=NUL # Null
|
||||
| tok=STRING # String
|
||||
| tok=BYTES # Bytes
|
||||
| tok=CEL_TRUE # BoolTrue
|
||||
| tok=CEL_FALSE # BoolFalse
|
||||
| tok=NUL # Null
|
||||
;
|
||||
|
||||
// Lexer Rules
|
||||
|
5
vendor/github.com/google/cel-go/parser/gen/CEL.interp
generated
vendored
5
vendor/github.com/google/cel-go/parser/gen/CEL.interp
generated
vendored
File diff suppressed because one or more lines are too long
48
vendor/github.com/google/cel-go/parser/gen/cel_base_listener.go
generated
vendored
48
vendor/github.com/google/cel-go/parser/gen/cel_base_listener.go
generated
vendored
@ -1,7 +1,7 @@
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.10.1. DO NOT EDIT.
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.12.0. DO NOT EDIT.
|
||||
|
||||
package gen // CEL
|
||||
import "github.com/antlr/antlr4/runtime/Go/antlr"
|
||||
import "github.com/antlr/antlr4/runtime/Go/antlr/v4"
|
||||
|
||||
// BaseCELListener is a complete listener for a parse tree produced by CELParser.
|
||||
type BaseCELListener struct{}
|
||||
@ -74,11 +74,17 @@ func (s *BaseCELListener) EnterNegate(ctx *NegateContext) {}
|
||||
// ExitNegate is called when production Negate is exited.
|
||||
func (s *BaseCELListener) ExitNegate(ctx *NegateContext) {}
|
||||
|
||||
// EnterSelectOrCall is called when production SelectOrCall is entered.
|
||||
func (s *BaseCELListener) EnterSelectOrCall(ctx *SelectOrCallContext) {}
|
||||
// EnterMemberCall is called when production MemberCall is entered.
|
||||
func (s *BaseCELListener) EnterMemberCall(ctx *MemberCallContext) {}
|
||||
|
||||
// ExitSelectOrCall is called when production SelectOrCall is exited.
|
||||
func (s *BaseCELListener) ExitSelectOrCall(ctx *SelectOrCallContext) {}
|
||||
// ExitMemberCall is called when production MemberCall is exited.
|
||||
func (s *BaseCELListener) ExitMemberCall(ctx *MemberCallContext) {}
|
||||
|
||||
// EnterSelect is called when production Select is entered.
|
||||
func (s *BaseCELListener) EnterSelect(ctx *SelectContext) {}
|
||||
|
||||
// ExitSelect is called when production Select is exited.
|
||||
func (s *BaseCELListener) ExitSelect(ctx *SelectContext) {}
|
||||
|
||||
// EnterPrimaryExpr is called when production PrimaryExpr is entered.
|
||||
func (s *BaseCELListener) EnterPrimaryExpr(ctx *PrimaryExprContext) {}
|
||||
@ -92,12 +98,6 @@ func (s *BaseCELListener) EnterIndex(ctx *IndexContext) {}
|
||||
// ExitIndex is called when production Index is exited.
|
||||
func (s *BaseCELListener) ExitIndex(ctx *IndexContext) {}
|
||||
|
||||
// EnterCreateMessage is called when production CreateMessage is entered.
|
||||
func (s *BaseCELListener) EnterCreateMessage(ctx *CreateMessageContext) {}
|
||||
|
||||
// ExitCreateMessage is called when production CreateMessage is exited.
|
||||
func (s *BaseCELListener) ExitCreateMessage(ctx *CreateMessageContext) {}
|
||||
|
||||
// EnterIdentOrGlobalCall is called when production IdentOrGlobalCall is entered.
|
||||
func (s *BaseCELListener) EnterIdentOrGlobalCall(ctx *IdentOrGlobalCallContext) {}
|
||||
|
||||
@ -122,6 +122,12 @@ func (s *BaseCELListener) EnterCreateStruct(ctx *CreateStructContext) {}
|
||||
// ExitCreateStruct is called when production CreateStruct is exited.
|
||||
func (s *BaseCELListener) ExitCreateStruct(ctx *CreateStructContext) {}
|
||||
|
||||
// EnterCreateMessage is called when production CreateMessage is entered.
|
||||
func (s *BaseCELListener) EnterCreateMessage(ctx *CreateMessageContext) {}
|
||||
|
||||
// ExitCreateMessage is called when production CreateMessage is exited.
|
||||
func (s *BaseCELListener) ExitCreateMessage(ctx *CreateMessageContext) {}
|
||||
|
||||
// EnterConstantLiteral is called when production ConstantLiteral is entered.
|
||||
func (s *BaseCELListener) EnterConstantLiteral(ctx *ConstantLiteralContext) {}
|
||||
|
||||
@ -134,18 +140,36 @@ func (s *BaseCELListener) EnterExprList(ctx *ExprListContext) {}
|
||||
// ExitExprList is called when production exprList is exited.
|
||||
func (s *BaseCELListener) ExitExprList(ctx *ExprListContext) {}
|
||||
|
||||
// EnterListInit is called when production listInit is entered.
|
||||
func (s *BaseCELListener) EnterListInit(ctx *ListInitContext) {}
|
||||
|
||||
// ExitListInit is called when production listInit is exited.
|
||||
func (s *BaseCELListener) ExitListInit(ctx *ListInitContext) {}
|
||||
|
||||
// EnterFieldInitializerList is called when production fieldInitializerList is entered.
|
||||
func (s *BaseCELListener) EnterFieldInitializerList(ctx *FieldInitializerListContext) {}
|
||||
|
||||
// ExitFieldInitializerList is called when production fieldInitializerList is exited.
|
||||
func (s *BaseCELListener) ExitFieldInitializerList(ctx *FieldInitializerListContext) {}
|
||||
|
||||
// EnterOptField is called when production optField is entered.
|
||||
func (s *BaseCELListener) EnterOptField(ctx *OptFieldContext) {}
|
||||
|
||||
// ExitOptField is called when production optField is exited.
|
||||
func (s *BaseCELListener) ExitOptField(ctx *OptFieldContext) {}
|
||||
|
||||
// EnterMapInitializerList is called when production mapInitializerList is entered.
|
||||
func (s *BaseCELListener) EnterMapInitializerList(ctx *MapInitializerListContext) {}
|
||||
|
||||
// ExitMapInitializerList is called when production mapInitializerList is exited.
|
||||
func (s *BaseCELListener) ExitMapInitializerList(ctx *MapInitializerListContext) {}
|
||||
|
||||
// EnterOptExpr is called when production optExpr is entered.
|
||||
func (s *BaseCELListener) EnterOptExpr(ctx *OptExprContext) {}
|
||||
|
||||
// ExitOptExpr is called when production optExpr is exited.
|
||||
func (s *BaseCELListener) ExitOptExpr(ctx *OptExprContext) {}
|
||||
|
||||
// EnterInt is called when production Int is entered.
|
||||
func (s *BaseCELListener) EnterInt(ctx *IntContext) {}
|
||||
|
||||
|
30
vendor/github.com/google/cel-go/parser/gen/cel_base_visitor.go
generated
vendored
30
vendor/github.com/google/cel-go/parser/gen/cel_base_visitor.go
generated
vendored
@ -1,7 +1,7 @@
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.10.1. DO NOT EDIT.
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.12.0. DO NOT EDIT.
|
||||
|
||||
package gen // CEL
|
||||
import "github.com/antlr/antlr4/runtime/Go/antlr"
|
||||
import "github.com/antlr/antlr4/runtime/Go/antlr/v4"
|
||||
|
||||
type BaseCELVisitor struct {
|
||||
*antlr.BaseParseTreeVisitor
|
||||
@ -43,7 +43,11 @@ func (v *BaseCELVisitor) VisitNegate(ctx *NegateContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitSelectOrCall(ctx *SelectOrCallContext) interface{} {
|
||||
func (v *BaseCELVisitor) VisitMemberCall(ctx *MemberCallContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitSelect(ctx *SelectContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
@ -55,10 +59,6 @@ func (v *BaseCELVisitor) VisitIndex(ctx *IndexContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitCreateMessage(ctx *CreateMessageContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitIdentOrGlobalCall(ctx *IdentOrGlobalCallContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
@ -75,6 +75,10 @@ func (v *BaseCELVisitor) VisitCreateStruct(ctx *CreateStructContext) interface{}
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitCreateMessage(ctx *CreateMessageContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitConstantLiteral(ctx *ConstantLiteralContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
@ -83,14 +87,26 @@ func (v *BaseCELVisitor) VisitExprList(ctx *ExprListContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitListInit(ctx *ListInitContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitFieldInitializerList(ctx *FieldInitializerListContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitOptField(ctx *OptFieldContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitMapInitializerList(ctx *MapInitializerListContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitOptExpr(ctx *OptExprContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
||||
func (v *BaseCELVisitor) VisitInt(ctx *IntContext) interface{} {
|
||||
return v.VisitChildren(ctx)
|
||||
}
|
||||
|
4
vendor/github.com/google/cel-go/parser/gen/cel_lexer.go
generated
vendored
4
vendor/github.com/google/cel-go/parser/gen/cel_lexer.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.10.1. DO NOT EDIT.
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.12.0. DO NOT EDIT.
|
||||
|
||||
package gen
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"sync"
|
||||
"unicode"
|
||||
|
||||
"github.com/antlr/antlr4/runtime/Go/antlr"
|
||||
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
|
||||
)
|
||||
|
||||
// Suppress unused import error
|
||||
|
48
vendor/github.com/google/cel-go/parser/gen/cel_listener.go
generated
vendored
48
vendor/github.com/google/cel-go/parser/gen/cel_listener.go
generated
vendored
@ -1,7 +1,7 @@
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.10.1. DO NOT EDIT.
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.12.0. DO NOT EDIT.
|
||||
|
||||
package gen // CEL
|
||||
import "github.com/antlr/antlr4/runtime/Go/antlr"
|
||||
import "github.com/antlr/antlr4/runtime/Go/antlr/v4"
|
||||
|
||||
// CELListener is a complete listener for a parse tree produced by CELParser.
|
||||
type CELListener interface {
|
||||
@ -34,8 +34,11 @@ type CELListener interface {
|
||||
// EnterNegate is called when entering the Negate production.
|
||||
EnterNegate(c *NegateContext)
|
||||
|
||||
// EnterSelectOrCall is called when entering the SelectOrCall production.
|
||||
EnterSelectOrCall(c *SelectOrCallContext)
|
||||
// EnterMemberCall is called when entering the MemberCall production.
|
||||
EnterMemberCall(c *MemberCallContext)
|
||||
|
||||
// EnterSelect is called when entering the Select production.
|
||||
EnterSelect(c *SelectContext)
|
||||
|
||||
// EnterPrimaryExpr is called when entering the PrimaryExpr production.
|
||||
EnterPrimaryExpr(c *PrimaryExprContext)
|
||||
@ -43,9 +46,6 @@ type CELListener interface {
|
||||
// EnterIndex is called when entering the Index production.
|
||||
EnterIndex(c *IndexContext)
|
||||
|
||||
// EnterCreateMessage is called when entering the CreateMessage production.
|
||||
EnterCreateMessage(c *CreateMessageContext)
|
||||
|
||||
// EnterIdentOrGlobalCall is called when entering the IdentOrGlobalCall production.
|
||||
EnterIdentOrGlobalCall(c *IdentOrGlobalCallContext)
|
||||
|
||||
@ -58,18 +58,30 @@ type CELListener interface {
|
||||
// EnterCreateStruct is called when entering the CreateStruct production.
|
||||
EnterCreateStruct(c *CreateStructContext)
|
||||
|
||||
// EnterCreateMessage is called when entering the CreateMessage production.
|
||||
EnterCreateMessage(c *CreateMessageContext)
|
||||
|
||||
// EnterConstantLiteral is called when entering the ConstantLiteral production.
|
||||
EnterConstantLiteral(c *ConstantLiteralContext)
|
||||
|
||||
// EnterExprList is called when entering the exprList production.
|
||||
EnterExprList(c *ExprListContext)
|
||||
|
||||
// EnterListInit is called when entering the listInit production.
|
||||
EnterListInit(c *ListInitContext)
|
||||
|
||||
// EnterFieldInitializerList is called when entering the fieldInitializerList production.
|
||||
EnterFieldInitializerList(c *FieldInitializerListContext)
|
||||
|
||||
// EnterOptField is called when entering the optField production.
|
||||
EnterOptField(c *OptFieldContext)
|
||||
|
||||
// EnterMapInitializerList is called when entering the mapInitializerList production.
|
||||
EnterMapInitializerList(c *MapInitializerListContext)
|
||||
|
||||
// EnterOptExpr is called when entering the optExpr production.
|
||||
EnterOptExpr(c *OptExprContext)
|
||||
|
||||
// EnterInt is called when entering the Int production.
|
||||
EnterInt(c *IntContext)
|
||||
|
||||
@ -121,8 +133,11 @@ type CELListener interface {
|
||||
// ExitNegate is called when exiting the Negate production.
|
||||
ExitNegate(c *NegateContext)
|
||||
|
||||
// ExitSelectOrCall is called when exiting the SelectOrCall production.
|
||||
ExitSelectOrCall(c *SelectOrCallContext)
|
||||
// ExitMemberCall is called when exiting the MemberCall production.
|
||||
ExitMemberCall(c *MemberCallContext)
|
||||
|
||||
// ExitSelect is called when exiting the Select production.
|
||||
ExitSelect(c *SelectContext)
|
||||
|
||||
// ExitPrimaryExpr is called when exiting the PrimaryExpr production.
|
||||
ExitPrimaryExpr(c *PrimaryExprContext)
|
||||
@ -130,9 +145,6 @@ type CELListener interface {
|
||||
// ExitIndex is called when exiting the Index production.
|
||||
ExitIndex(c *IndexContext)
|
||||
|
||||
// ExitCreateMessage is called when exiting the CreateMessage production.
|
||||
ExitCreateMessage(c *CreateMessageContext)
|
||||
|
||||
// ExitIdentOrGlobalCall is called when exiting the IdentOrGlobalCall production.
|
||||
ExitIdentOrGlobalCall(c *IdentOrGlobalCallContext)
|
||||
|
||||
@ -145,18 +157,30 @@ type CELListener interface {
|
||||
// ExitCreateStruct is called when exiting the CreateStruct production.
|
||||
ExitCreateStruct(c *CreateStructContext)
|
||||
|
||||
// ExitCreateMessage is called when exiting the CreateMessage production.
|
||||
ExitCreateMessage(c *CreateMessageContext)
|
||||
|
||||
// ExitConstantLiteral is called when exiting the ConstantLiteral production.
|
||||
ExitConstantLiteral(c *ConstantLiteralContext)
|
||||
|
||||
// ExitExprList is called when exiting the exprList production.
|
||||
ExitExprList(c *ExprListContext)
|
||||
|
||||
// ExitListInit is called when exiting the listInit production.
|
||||
ExitListInit(c *ListInitContext)
|
||||
|
||||
// ExitFieldInitializerList is called when exiting the fieldInitializerList production.
|
||||
ExitFieldInitializerList(c *FieldInitializerListContext)
|
||||
|
||||
// ExitOptField is called when exiting the optField production.
|
||||
ExitOptField(c *OptFieldContext)
|
||||
|
||||
// ExitMapInitializerList is called when exiting the mapInitializerList production.
|
||||
ExitMapInitializerList(c *MapInitializerListContext)
|
||||
|
||||
// ExitOptExpr is called when exiting the optExpr production.
|
||||
ExitOptExpr(c *OptExprContext)
|
||||
|
||||
// ExitInt is called when exiting the Int production.
|
||||
ExitInt(c *IntContext)
|
||||
|
||||
|
1938
vendor/github.com/google/cel-go/parser/gen/cel_parser.go
generated
vendored
1938
vendor/github.com/google/cel-go/parser/gen/cel_parser.go
generated
vendored
File diff suppressed because it is too large
Load Diff
26
vendor/github.com/google/cel-go/parser/gen/cel_visitor.go
generated
vendored
26
vendor/github.com/google/cel-go/parser/gen/cel_visitor.go
generated
vendored
@ -1,7 +1,7 @@
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.10.1. DO NOT EDIT.
|
||||
// Code generated from /Users/tswadell/go/src/github.com/google/cel-go/parser/gen/CEL.g4 by ANTLR 4.12.0. DO NOT EDIT.
|
||||
|
||||
package gen // CEL
|
||||
import "github.com/antlr/antlr4/runtime/Go/antlr"
|
||||
import "github.com/antlr/antlr4/runtime/Go/antlr/v4"
|
||||
|
||||
// A complete Visitor for a parse tree produced by CELParser.
|
||||
type CELVisitor interface {
|
||||
@ -34,8 +34,11 @@ type CELVisitor interface {
|
||||
// Visit a parse tree produced by CELParser#Negate.
|
||||
VisitNegate(ctx *NegateContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#SelectOrCall.
|
||||
VisitSelectOrCall(ctx *SelectOrCallContext) interface{}
|
||||
// Visit a parse tree produced by CELParser#MemberCall.
|
||||
VisitMemberCall(ctx *MemberCallContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#Select.
|
||||
VisitSelect(ctx *SelectContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#PrimaryExpr.
|
||||
VisitPrimaryExpr(ctx *PrimaryExprContext) interface{}
|
||||
@ -43,9 +46,6 @@ type CELVisitor interface {
|
||||
// Visit a parse tree produced by CELParser#Index.
|
||||
VisitIndex(ctx *IndexContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#CreateMessage.
|
||||
VisitCreateMessage(ctx *CreateMessageContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#IdentOrGlobalCall.
|
||||
VisitIdentOrGlobalCall(ctx *IdentOrGlobalCallContext) interface{}
|
||||
|
||||
@ -58,18 +58,30 @@ type CELVisitor interface {
|
||||
// Visit a parse tree produced by CELParser#CreateStruct.
|
||||
VisitCreateStruct(ctx *CreateStructContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#CreateMessage.
|
||||
VisitCreateMessage(ctx *CreateMessageContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#ConstantLiteral.
|
||||
VisitConstantLiteral(ctx *ConstantLiteralContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#exprList.
|
||||
VisitExprList(ctx *ExprListContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#listInit.
|
||||
VisitListInit(ctx *ListInitContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#fieldInitializerList.
|
||||
VisitFieldInitializerList(ctx *FieldInitializerListContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#optField.
|
||||
VisitOptField(ctx *OptFieldContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#mapInitializerList.
|
||||
VisitMapInitializerList(ctx *MapInitializerListContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#optExpr.
|
||||
VisitOptExpr(ctx *OptExprContext) interface{}
|
||||
|
||||
// Visit a parse tree produced by CELParser#Int.
|
||||
VisitInt(ctx *IntContext) interface{}
|
||||
|
||||
|
2
vendor/github.com/google/cel-go/parser/gen/generate.sh
generated
vendored
2
vendor/github.com/google/cel-go/parser/gen/generate.sh
generated
vendored
@ -27,7 +27,7 @@
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
# Generate AntLR artifacts.
|
||||
java -Xmx500M -cp ${DIR}/antlr-4.10.1-complete.jar org.antlr.v4.Tool \
|
||||
java -Xmx500M -cp ${DIR}/antlr-4.12.0-complete.jar org.antlr.v4.Tool \
|
||||
-Dlanguage=Go \
|
||||
-package gen \
|
||||
-o ${DIR} \
|
||||
|
179
vendor/github.com/google/cel-go/parser/helper.go
generated
vendored
179
vendor/github.com/google/cel-go/parser/helper.go
generated
vendored
@ -17,7 +17,8 @@ package parser
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/antlr/antlr4/runtime/Go/antlr"
|
||||
antlr "github.com/antlr/antlr4/runtime/Go/antlr/v4"
|
||||
|
||||
"github.com/google/cel-go/common"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
@ -47,115 +48,122 @@ func (p *parserHelper) getSourceInfo() *exprpb.SourceInfo {
|
||||
MacroCalls: p.macroCalls}
|
||||
}
|
||||
|
||||
func (p *parserHelper) newLiteral(ctx interface{}, value *exprpb.Constant) *exprpb.Expr {
|
||||
func (p *parserHelper) newLiteral(ctx any, value *exprpb.Constant) *exprpb.Expr {
|
||||
exprNode := p.newExpr(ctx)
|
||||
exprNode.ExprKind = &exprpb.Expr_ConstExpr{ConstExpr: value}
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newLiteralBool(ctx interface{}, value bool) *exprpb.Expr {
|
||||
func (p *parserHelper) newLiteralBool(ctx any, value bool) *exprpb.Expr {
|
||||
return p.newLiteral(ctx,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_BoolValue{BoolValue: value}})
|
||||
}
|
||||
|
||||
func (p *parserHelper) newLiteralString(ctx interface{}, value string) *exprpb.Expr {
|
||||
func (p *parserHelper) newLiteralString(ctx any, value string) *exprpb.Expr {
|
||||
return p.newLiteral(ctx,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_StringValue{StringValue: value}})
|
||||
}
|
||||
|
||||
func (p *parserHelper) newLiteralBytes(ctx interface{}, value []byte) *exprpb.Expr {
|
||||
func (p *parserHelper) newLiteralBytes(ctx any, value []byte) *exprpb.Expr {
|
||||
return p.newLiteral(ctx,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_BytesValue{BytesValue: value}})
|
||||
}
|
||||
|
||||
func (p *parserHelper) newLiteralInt(ctx interface{}, value int64) *exprpb.Expr {
|
||||
func (p *parserHelper) newLiteralInt(ctx any, value int64) *exprpb.Expr {
|
||||
return p.newLiteral(ctx,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_Int64Value{Int64Value: value}})
|
||||
}
|
||||
|
||||
func (p *parserHelper) newLiteralUint(ctx interface{}, value uint64) *exprpb.Expr {
|
||||
func (p *parserHelper) newLiteralUint(ctx any, value uint64) *exprpb.Expr {
|
||||
return p.newLiteral(ctx, &exprpb.Constant{ConstantKind: &exprpb.Constant_Uint64Value{Uint64Value: value}})
|
||||
}
|
||||
|
||||
func (p *parserHelper) newLiteralDouble(ctx interface{}, value float64) *exprpb.Expr {
|
||||
func (p *parserHelper) newLiteralDouble(ctx any, value float64) *exprpb.Expr {
|
||||
return p.newLiteral(ctx,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_DoubleValue{DoubleValue: value}})
|
||||
}
|
||||
|
||||
func (p *parserHelper) newIdent(ctx interface{}, name string) *exprpb.Expr {
|
||||
func (p *parserHelper) newIdent(ctx any, name string) *exprpb.Expr {
|
||||
exprNode := p.newExpr(ctx)
|
||||
exprNode.ExprKind = &exprpb.Expr_IdentExpr{IdentExpr: &exprpb.Expr_Ident{Name: name}}
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newSelect(ctx interface{}, operand *exprpb.Expr, field string) *exprpb.Expr {
|
||||
func (p *parserHelper) newSelect(ctx any, operand *exprpb.Expr, field string) *exprpb.Expr {
|
||||
exprNode := p.newExpr(ctx)
|
||||
exprNode.ExprKind = &exprpb.Expr_SelectExpr{
|
||||
SelectExpr: &exprpb.Expr_Select{Operand: operand, Field: field}}
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newPresenceTest(ctx interface{}, operand *exprpb.Expr, field string) *exprpb.Expr {
|
||||
func (p *parserHelper) newPresenceTest(ctx any, operand *exprpb.Expr, field string) *exprpb.Expr {
|
||||
exprNode := p.newExpr(ctx)
|
||||
exprNode.ExprKind = &exprpb.Expr_SelectExpr{
|
||||
SelectExpr: &exprpb.Expr_Select{Operand: operand, Field: field, TestOnly: true}}
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newGlobalCall(ctx interface{}, function string, args ...*exprpb.Expr) *exprpb.Expr {
|
||||
func (p *parserHelper) newGlobalCall(ctx any, function string, args ...*exprpb.Expr) *exprpb.Expr {
|
||||
exprNode := p.newExpr(ctx)
|
||||
exprNode.ExprKind = &exprpb.Expr_CallExpr{
|
||||
CallExpr: &exprpb.Expr_Call{Function: function, Args: args}}
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newReceiverCall(ctx interface{}, function string, target *exprpb.Expr, args ...*exprpb.Expr) *exprpb.Expr {
|
||||
func (p *parserHelper) newReceiverCall(ctx any, function string, target *exprpb.Expr, args ...*exprpb.Expr) *exprpb.Expr {
|
||||
exprNode := p.newExpr(ctx)
|
||||
exprNode.ExprKind = &exprpb.Expr_CallExpr{
|
||||
CallExpr: &exprpb.Expr_Call{Function: function, Target: target, Args: args}}
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newList(ctx interface{}, elements ...*exprpb.Expr) *exprpb.Expr {
|
||||
func (p *parserHelper) newList(ctx any, elements []*exprpb.Expr, optionals ...int32) *exprpb.Expr {
|
||||
exprNode := p.newExpr(ctx)
|
||||
exprNode.ExprKind = &exprpb.Expr_ListExpr{
|
||||
ListExpr: &exprpb.Expr_CreateList{Elements: elements}}
|
||||
ListExpr: &exprpb.Expr_CreateList{
|
||||
Elements: elements,
|
||||
OptionalIndices: optionals,
|
||||
}}
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newMap(ctx interface{}, entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr {
|
||||
func (p *parserHelper) newMap(ctx any, entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr {
|
||||
exprNode := p.newExpr(ctx)
|
||||
exprNode.ExprKind = &exprpb.Expr_StructExpr{
|
||||
StructExpr: &exprpb.Expr_CreateStruct{Entries: entries}}
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newMapEntry(entryID int64, key *exprpb.Expr, value *exprpb.Expr) *exprpb.Expr_CreateStruct_Entry {
|
||||
func (p *parserHelper) newMapEntry(entryID int64, key *exprpb.Expr, value *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry {
|
||||
return &exprpb.Expr_CreateStruct_Entry{
|
||||
Id: entryID,
|
||||
KeyKind: &exprpb.Expr_CreateStruct_Entry_MapKey{MapKey: key},
|
||||
Value: value}
|
||||
Id: entryID,
|
||||
KeyKind: &exprpb.Expr_CreateStruct_Entry_MapKey{MapKey: key},
|
||||
Value: value,
|
||||
OptionalEntry: optional,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parserHelper) newObject(ctx interface{},
|
||||
typeName string,
|
||||
entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr {
|
||||
func (p *parserHelper) newObject(ctx any, typeName string, entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr {
|
||||
exprNode := p.newExpr(ctx)
|
||||
exprNode.ExprKind = &exprpb.Expr_StructExpr{
|
||||
StructExpr: &exprpb.Expr_CreateStruct{
|
||||
MessageName: typeName,
|
||||
Entries: entries}}
|
||||
Entries: entries,
|
||||
},
|
||||
}
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newObjectField(fieldID int64, field string, value *exprpb.Expr) *exprpb.Expr_CreateStruct_Entry {
|
||||
func (p *parserHelper) newObjectField(fieldID int64, field string, value *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry {
|
||||
return &exprpb.Expr_CreateStruct_Entry{
|
||||
Id: fieldID,
|
||||
KeyKind: &exprpb.Expr_CreateStruct_Entry_FieldKey{FieldKey: field},
|
||||
Value: value}
|
||||
Id: fieldID,
|
||||
KeyKind: &exprpb.Expr_CreateStruct_Entry_FieldKey{FieldKey: field},
|
||||
Value: value,
|
||||
OptionalEntry: optional,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parserHelper) newComprehension(ctx interface{}, iterVar string,
|
||||
func (p *parserHelper) newComprehension(ctx any, iterVar string,
|
||||
iterRange *exprpb.Expr,
|
||||
accuVar string,
|
||||
accuInit *exprpb.Expr,
|
||||
@ -175,7 +183,7 @@ func (p *parserHelper) newComprehension(ctx interface{}, iterVar string,
|
||||
return exprNode
|
||||
}
|
||||
|
||||
func (p *parserHelper) newExpr(ctx interface{}) *exprpb.Expr {
|
||||
func (p *parserHelper) newExpr(ctx any) *exprpb.Expr {
|
||||
id, isID := ctx.(int64)
|
||||
if isID {
|
||||
return &exprpb.Expr{Id: id}
|
||||
@ -183,7 +191,7 @@ func (p *parserHelper) newExpr(ctx interface{}) *exprpb.Expr {
|
||||
return &exprpb.Expr{Id: p.id(ctx)}
|
||||
}
|
||||
|
||||
func (p *parserHelper) id(ctx interface{}) int64 {
|
||||
func (p *parserHelper) id(ctx any) int64 {
|
||||
var location common.Location
|
||||
switch ctx.(type) {
|
||||
case antlr.ParserRuleContext:
|
||||
@ -251,7 +259,8 @@ func (p *parserHelper) buildMacroCallArg(expr *exprpb.Expr) *exprpb.Expr {
|
||||
Id: expr.GetId(),
|
||||
ExprKind: &exprpb.Expr_ListExpr{
|
||||
ListExpr: &exprpb.Expr_CreateList{
|
||||
Elements: macroListArgs,
|
||||
Elements: macroListArgs,
|
||||
OptionalIndices: listExpr.GetOptionalIndices(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -360,6 +369,95 @@ func (e *exprHelper) nextMacroID() int64 {
|
||||
return e.parserHelper.id(e.parserHelper.getLocation(e.id))
|
||||
}
|
||||
|
||||
// Copy implements the ExprHelper interface method by producing a copy of the input Expr value
|
||||
// with a fresh set of numeric identifiers the Expr and all its descendents.
|
||||
func (e *exprHelper) Copy(expr *exprpb.Expr) *exprpb.Expr {
|
||||
copy := e.parserHelper.newExpr(e.parserHelper.getLocation(expr.GetId()))
|
||||
switch expr.GetExprKind().(type) {
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
copy.ExprKind = &exprpb.Expr_ConstExpr{ConstExpr: expr.GetConstExpr()}
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
copy.ExprKind = &exprpb.Expr_IdentExpr{IdentExpr: expr.GetIdentExpr()}
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
op := expr.GetSelectExpr().GetOperand()
|
||||
copy.ExprKind = &exprpb.Expr_SelectExpr{SelectExpr: &exprpb.Expr_Select{
|
||||
Operand: e.Copy(op),
|
||||
Field: expr.GetSelectExpr().GetField(),
|
||||
TestOnly: expr.GetSelectExpr().GetTestOnly(),
|
||||
}}
|
||||
case *exprpb.Expr_CallExpr:
|
||||
call := expr.GetCallExpr()
|
||||
target := call.GetTarget()
|
||||
if target != nil {
|
||||
target = e.Copy(target)
|
||||
}
|
||||
args := call.GetArgs()
|
||||
argsCopy := make([]*exprpb.Expr, len(args))
|
||||
for i, arg := range args {
|
||||
argsCopy[i] = e.Copy(arg)
|
||||
}
|
||||
copy.ExprKind = &exprpb.Expr_CallExpr{
|
||||
CallExpr: &exprpb.Expr_Call{
|
||||
Function: call.GetFunction(),
|
||||
Target: target,
|
||||
Args: argsCopy,
|
||||
},
|
||||
}
|
||||
case *exprpb.Expr_ListExpr:
|
||||
elems := expr.GetListExpr().GetElements()
|
||||
elemsCopy := make([]*exprpb.Expr, len(elems))
|
||||
for i, elem := range elems {
|
||||
elemsCopy[i] = e.Copy(elem)
|
||||
}
|
||||
copy.ExprKind = &exprpb.Expr_ListExpr{
|
||||
ListExpr: &exprpb.Expr_CreateList{Elements: elemsCopy},
|
||||
}
|
||||
case *exprpb.Expr_StructExpr:
|
||||
entries := expr.GetStructExpr().GetEntries()
|
||||
entriesCopy := make([]*exprpb.Expr_CreateStruct_Entry, len(entries))
|
||||
for i, entry := range entries {
|
||||
entryCopy := &exprpb.Expr_CreateStruct_Entry{}
|
||||
entryCopy.Id = e.nextMacroID()
|
||||
switch entry.GetKeyKind().(type) {
|
||||
case *exprpb.Expr_CreateStruct_Entry_FieldKey:
|
||||
entryCopy.KeyKind = &exprpb.Expr_CreateStruct_Entry_FieldKey{
|
||||
FieldKey: entry.GetFieldKey(),
|
||||
}
|
||||
case *exprpb.Expr_CreateStruct_Entry_MapKey:
|
||||
entryCopy.KeyKind = &exprpb.Expr_CreateStruct_Entry_MapKey{
|
||||
MapKey: e.Copy(entry.GetMapKey()),
|
||||
}
|
||||
}
|
||||
entryCopy.Value = e.Copy(entry.GetValue())
|
||||
entriesCopy[i] = entryCopy
|
||||
}
|
||||
copy.ExprKind = &exprpb.Expr_StructExpr{
|
||||
StructExpr: &exprpb.Expr_CreateStruct{
|
||||
MessageName: expr.GetStructExpr().GetMessageName(),
|
||||
Entries: entriesCopy,
|
||||
},
|
||||
}
|
||||
case *exprpb.Expr_ComprehensionExpr:
|
||||
iterRange := e.Copy(expr.GetComprehensionExpr().GetIterRange())
|
||||
accuInit := e.Copy(expr.GetComprehensionExpr().GetAccuInit())
|
||||
cond := e.Copy(expr.GetComprehensionExpr().GetLoopCondition())
|
||||
step := e.Copy(expr.GetComprehensionExpr().GetLoopStep())
|
||||
result := e.Copy(expr.GetComprehensionExpr().GetResult())
|
||||
copy.ExprKind = &exprpb.Expr_ComprehensionExpr{
|
||||
ComprehensionExpr: &exprpb.Expr_Comprehension{
|
||||
IterRange: iterRange,
|
||||
IterVar: expr.GetComprehensionExpr().GetIterVar(),
|
||||
AccuInit: accuInit,
|
||||
AccuVar: expr.GetComprehensionExpr().GetAccuVar(),
|
||||
LoopCondition: cond,
|
||||
LoopStep: step,
|
||||
Result: result,
|
||||
},
|
||||
}
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
// LiteralBool implements the ExprHelper interface method.
|
||||
func (e *exprHelper) LiteralBool(value bool) *exprpb.Expr {
|
||||
return e.parserHelper.newLiteralBool(e.nextMacroID(), value)
|
||||
@ -392,7 +490,7 @@ func (e *exprHelper) LiteralUint(value uint64) *exprpb.Expr {
|
||||
|
||||
// NewList implements the ExprHelper interface method.
|
||||
func (e *exprHelper) NewList(elems ...*exprpb.Expr) *exprpb.Expr {
|
||||
return e.parserHelper.newList(e.nextMacroID(), elems...)
|
||||
return e.parserHelper.newList(e.nextMacroID(), elems)
|
||||
}
|
||||
|
||||
// NewMap implements the ExprHelper interface method.
|
||||
@ -401,21 +499,18 @@ func (e *exprHelper) NewMap(entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.
|
||||
}
|
||||
|
||||
// NewMapEntry implements the ExprHelper interface method.
|
||||
func (e *exprHelper) NewMapEntry(key *exprpb.Expr,
|
||||
val *exprpb.Expr) *exprpb.Expr_CreateStruct_Entry {
|
||||
return e.parserHelper.newMapEntry(e.nextMacroID(), key, val)
|
||||
func (e *exprHelper) NewMapEntry(key *exprpb.Expr, val *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry {
|
||||
return e.parserHelper.newMapEntry(e.nextMacroID(), key, val, optional)
|
||||
}
|
||||
|
||||
// NewObject implements the ExprHelper interface method.
|
||||
func (e *exprHelper) NewObject(typeName string,
|
||||
fieldInits ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr {
|
||||
func (e *exprHelper) NewObject(typeName string, fieldInits ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr {
|
||||
return e.parserHelper.newObject(e.nextMacroID(), typeName, fieldInits...)
|
||||
}
|
||||
|
||||
// NewObjectFieldInit implements the ExprHelper interface method.
|
||||
func (e *exprHelper) NewObjectFieldInit(field string,
|
||||
init *exprpb.Expr) *exprpb.Expr_CreateStruct_Entry {
|
||||
return e.parserHelper.newObjectField(e.nextMacroID(), field, init)
|
||||
func (e *exprHelper) NewObjectFieldInit(field string, init *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry {
|
||||
return e.parserHelper.newObjectField(e.nextMacroID(), field, init, optional)
|
||||
}
|
||||
|
||||
// Fold implements the ExprHelper interface method.
|
||||
@ -471,7 +566,7 @@ func (e *exprHelper) OffsetLocation(exprID int64) common.Location {
|
||||
var (
|
||||
// Thread-safe pool of ExprHelper values to minimize alloc overhead of ExprHelper creations.
|
||||
exprHelperPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
return &exprHelper{}
|
||||
},
|
||||
}
|
||||
|
3
vendor/github.com/google/cel-go/parser/input.go
generated
vendored
3
vendor/github.com/google/cel-go/parser/input.go
generated
vendored
@ -15,7 +15,8 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"github.com/antlr/antlr4/runtime/Go/antlr"
|
||||
antlr "github.com/antlr/antlr4/runtime/Go/antlr/v4"
|
||||
|
||||
"github.com/google/cel-go/common/runes"
|
||||
)
|
||||
|
||||
|
20
vendor/github.com/google/cel-go/parser/macro.go
generated
vendored
20
vendor/github.com/google/cel-go/parser/macro.go
generated
vendored
@ -132,8 +132,11 @@ func makeVarArgMacroKey(name string, receiverStyle bool) string {
|
||||
return fmt.Sprintf("%s:*:%v", name, receiverStyle)
|
||||
}
|
||||
|
||||
// MacroExpander converts a call and its associated arguments into a new CEL abstract syntax tree, or an error
|
||||
// if the input arguments are not suitable for the expansion requirements for the macro in question.
|
||||
// MacroExpander converts a call and its associated arguments into a new CEL abstract syntax tree.
|
||||
//
|
||||
// If the MacroExpander determines within the implementation that an expansion is not needed it may return
|
||||
// a nil Expr value to indicate a non-match. However, if an expansion is to be performed, but the arguments
|
||||
// are not well-formed, the result of the expansion will be an error.
|
||||
//
|
||||
// The MacroExpander accepts as arguments a MacroExprHelper as well as the arguments used in the function call
|
||||
// and produces as output an Expr ast node.
|
||||
@ -147,6 +150,9 @@ type MacroExpander func(eh ExprHelper,
|
||||
// consistent with the source position and expression id generation code leveraged by both
|
||||
// the parser and type-checker.
|
||||
type ExprHelper interface {
|
||||
// Copy the input expression with a brand new set of identifiers.
|
||||
Copy(*exprpb.Expr) *exprpb.Expr
|
||||
|
||||
// LiteralBool creates an Expr value for a bool literal.
|
||||
LiteralBool(value bool) *exprpb.Expr
|
||||
|
||||
@ -174,14 +180,14 @@ type ExprHelper interface {
|
||||
NewMap(entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr
|
||||
|
||||
// NewMapEntry creates a Map Entry for the key, value pair.
|
||||
NewMapEntry(key *exprpb.Expr, val *exprpb.Expr) *exprpb.Expr_CreateStruct_Entry
|
||||
NewMapEntry(key *exprpb.Expr, val *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry
|
||||
|
||||
// NewObject creates a CreateStruct instruction for an object with a given type name and
|
||||
// optional set of field initializers.
|
||||
NewObject(typeName string, fieldInits ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr
|
||||
|
||||
// NewObjectFieldInit creates a new Object field initializer from the field name and value.
|
||||
NewObjectFieldInit(field string, init *exprpb.Expr) *exprpb.Expr_CreateStruct_Entry
|
||||
NewObjectFieldInit(field string, init *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry
|
||||
|
||||
// Fold creates a fold comprehension instruction.
|
||||
//
|
||||
@ -309,8 +315,10 @@ func MakeExistsOne(eh ExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*ex
|
||||
// input to produce an output list.
|
||||
//
|
||||
// There are two call patterns supported by map:
|
||||
// <iterRange>.map(<iterVar>, <transform>)
|
||||
// <iterRange>.map(<iterVar>, <predicate>, <transform>)
|
||||
//
|
||||
// <iterRange>.map(<iterVar>, <transform>)
|
||||
// <iterRange>.map(<iterVar>, <predicate>, <transform>)
|
||||
//
|
||||
// In the second form only iterVar values which return true when provided to the predicate expression
|
||||
// are transformed.
|
||||
func MakeMap(eh ExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
|
25
vendor/github.com/google/cel-go/parser/options.go
generated
vendored
25
vendor/github.com/google/cel-go/parser/options.go
generated
vendored
@ -18,11 +18,13 @@ import "fmt"
|
||||
|
||||
type options struct {
|
||||
maxRecursionDepth int
|
||||
errorReportingLimit int
|
||||
errorRecoveryTokenLookaheadLimit int
|
||||
errorRecoveryLimit int
|
||||
expressionSizeCodePointLimit int
|
||||
macros map[string]Macro
|
||||
populateMacroCalls bool
|
||||
enableOptionalSyntax bool
|
||||
}
|
||||
|
||||
// Option configures the behavior of the parser.
|
||||
@ -45,7 +47,7 @@ func MaxRecursionDepth(limit int) Option {
|
||||
// successfully resume. In some pathological cases, the parser can look through quite a large set of input which
|
||||
// in turn generates a lot of back-tracking and performance degredation.
|
||||
//
|
||||
// The limit must be > 1, and is recommended to be less than the default of 256.
|
||||
// The limit must be >= 1, and is recommended to be less than the default of 256.
|
||||
func ErrorRecoveryLookaheadTokenLimit(limit int) Option {
|
||||
return func(opts *options) error {
|
||||
if limit < 1 {
|
||||
@ -67,6 +69,19 @@ func ErrorRecoveryLimit(limit int) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorReportingLimit limits the number of syntax error reports before terminating parsing.
|
||||
//
|
||||
// The limit must be at least 1. If unset, the limit will be 100.
|
||||
func ErrorReportingLimit(limit int) Option {
|
||||
return func(opts *options) error {
|
||||
if limit < 1 {
|
||||
return fmt.Errorf("error reporting limit must be at least 1: %d", limit)
|
||||
}
|
||||
opts.errorReportingLimit = limit
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExpressionSizeCodePointLimit is an option which limits the maximum code point count of an
|
||||
// expression.
|
||||
func ExpressionSizeCodePointLimit(expressionSizeCodePointLimit int) Option {
|
||||
@ -102,3 +117,11 @@ func PopulateMacroCalls(populateMacroCalls bool) Option {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableOptionalSyntax enables syntax for optional field and index selection.
|
||||
func EnableOptionalSyntax(optionalSyntax bool) Option {
|
||||
return func(opts *options) error {
|
||||
opts.enableOptionalSyntax = optionalSyntax
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
487
vendor/github.com/google/cel-go/parser/parser.go
generated
vendored
487
vendor/github.com/google/cel-go/parser/parser.go
generated
vendored
@ -18,11 +18,13 @@ package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/antlr/antlr4/runtime/Go/antlr"
|
||||
antlr "github.com/antlr/antlr4/runtime/Go/antlr/v4"
|
||||
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/runes"
|
||||
@ -45,6 +47,9 @@ func NewParser(opts ...Option) (*Parser, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if p.errorReportingLimit == 0 {
|
||||
p.errorReportingLimit = 100
|
||||
}
|
||||
if p.maxRecursionDepth == 0 {
|
||||
p.maxRecursionDepth = 250
|
||||
}
|
||||
@ -89,9 +94,11 @@ func (p *Parser) Parse(source common.Source) (*exprpb.ParsedExpr, *common.Errors
|
||||
helper: newParserHelper(source),
|
||||
macros: p.macros,
|
||||
maxRecursionDepth: p.maxRecursionDepth,
|
||||
errorReportingLimit: p.errorReportingLimit,
|
||||
errorRecoveryLimit: p.errorRecoveryLimit,
|
||||
errorRecoveryLookaheadTokenLimit: p.errorRecoveryTokenLookaheadLimit,
|
||||
populateMacroCalls: p.populateMacroCalls,
|
||||
enableOptionalSyntax: p.enableOptionalSyntax,
|
||||
}
|
||||
buf, ok := source.(runes.Buffer)
|
||||
if !ok {
|
||||
@ -178,7 +185,7 @@ func (rl *recursionListener) EnterEveryRule(ctx antlr.ParserRuleContext) {
|
||||
} else {
|
||||
*depth++
|
||||
}
|
||||
if *depth >= rl.maxDepth {
|
||||
if *depth > rl.maxDepth {
|
||||
panic(&recursionError{
|
||||
message: fmt.Sprintf("expression recursion limit exceeded: %d", rl.maxDepth),
|
||||
})
|
||||
@ -197,6 +204,16 @@ func (rl *recursionListener) ExitEveryRule(ctx antlr.ParserRuleContext) {
|
||||
|
||||
var _ antlr.ParseTreeListener = &recursionListener{}
|
||||
|
||||
type tooManyErrors struct {
|
||||
errorReportingLimit int
|
||||
}
|
||||
|
||||
func (t *tooManyErrors) Error() string {
|
||||
return fmt.Sprintf("More than %d syntax errors", t.errorReportingLimit)
|
||||
}
|
||||
|
||||
var _ error = &tooManyErrors{}
|
||||
|
||||
type recoveryLimitError struct {
|
||||
message string
|
||||
}
|
||||
@ -271,17 +288,20 @@ type parser struct {
|
||||
helper *parserHelper
|
||||
macros map[string]Macro
|
||||
recursionDepth int
|
||||
errorReports int
|
||||
maxRecursionDepth int
|
||||
errorReportingLimit int
|
||||
errorRecoveryLimit int
|
||||
errorRecoveryLookaheadTokenLimit int
|
||||
populateMacroCalls bool
|
||||
enableOptionalSyntax bool
|
||||
}
|
||||
|
||||
var (
|
||||
_ gen.CELVisitor = (*parser)(nil)
|
||||
|
||||
lexerPool *sync.Pool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
l := gen.NewCELLexer(nil)
|
||||
l.RemoveErrorListeners()
|
||||
return l
|
||||
@ -289,7 +309,7 @@ var (
|
||||
}
|
||||
|
||||
parserPool *sync.Pool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
p := gen.NewCELParser(nil)
|
||||
p.RemoveErrorListeners()
|
||||
return p
|
||||
@ -302,14 +322,14 @@ func (p *parser) parse(expr runes.Buffer, desc string) *exprpb.Expr {
|
||||
lexer := lexerPool.Get().(*gen.CELLexer)
|
||||
prsr := parserPool.Get().(*gen.CELParser)
|
||||
|
||||
// Unfortunately ANTLR Go runtime is missing (*antlr.BaseParser).RemoveParseListeners, so this is
|
||||
// good enough until that is exported.
|
||||
prsrListener := &recursionListener{
|
||||
maxDepth: p.maxRecursionDepth,
|
||||
ruleTypeDepth: map[int]*int{},
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Unfortunately ANTLR Go runtime is missing (*antlr.BaseParser).RemoveParseListeners,
|
||||
// so this is good enough until that is exported.
|
||||
// Reset the lexer and parser before putting them back in the pool.
|
||||
lexer.RemoveErrorListeners()
|
||||
prsr.RemoveParseListener(prsrListener)
|
||||
@ -340,6 +360,8 @@ func (p *parser) parse(expr runes.Buffer, desc string) *exprpb.Expr {
|
||||
p.errors.ReportError(common.NoLocation, err.Error())
|
||||
case *recursionError:
|
||||
p.errors.ReportError(common.NoLocation, err.Error())
|
||||
case *tooManyErrors:
|
||||
// do nothing
|
||||
case *recoveryLimitError:
|
||||
// do nothing, listeners already notified and error reported.
|
||||
default:
|
||||
@ -352,57 +374,85 @@ func (p *parser) parse(expr runes.Buffer, desc string) *exprpb.Expr {
|
||||
}
|
||||
|
||||
// Visitor implementations.
|
||||
func (p *parser) Visit(tree antlr.ParseTree) interface{} {
|
||||
p.recursionDepth++
|
||||
if p.recursionDepth > p.maxRecursionDepth {
|
||||
panic(&recursionError{message: "max recursion depth exceeded"})
|
||||
}
|
||||
defer func() {
|
||||
p.recursionDepth--
|
||||
}()
|
||||
switch tree.(type) {
|
||||
func (p *parser) Visit(tree antlr.ParseTree) any {
|
||||
t := unnest(tree)
|
||||
switch tree := t.(type) {
|
||||
case *gen.StartContext:
|
||||
return p.VisitStart(tree.(*gen.StartContext))
|
||||
return p.VisitStart(tree)
|
||||
case *gen.ExprContext:
|
||||
return p.VisitExpr(tree.(*gen.ExprContext))
|
||||
p.checkAndIncrementRecursionDepth()
|
||||
out := p.VisitExpr(tree)
|
||||
p.decrementRecursionDepth()
|
||||
return out
|
||||
case *gen.ConditionalAndContext:
|
||||
return p.VisitConditionalAnd(tree.(*gen.ConditionalAndContext))
|
||||
return p.VisitConditionalAnd(tree)
|
||||
case *gen.ConditionalOrContext:
|
||||
return p.VisitConditionalOr(tree.(*gen.ConditionalOrContext))
|
||||
return p.VisitConditionalOr(tree)
|
||||
case *gen.RelationContext:
|
||||
return p.VisitRelation(tree.(*gen.RelationContext))
|
||||
p.checkAndIncrementRecursionDepth()
|
||||
out := p.VisitRelation(tree)
|
||||
p.decrementRecursionDepth()
|
||||
return out
|
||||
case *gen.CalcContext:
|
||||
return p.VisitCalc(tree.(*gen.CalcContext))
|
||||
p.checkAndIncrementRecursionDepth()
|
||||
out := p.VisitCalc(tree)
|
||||
p.decrementRecursionDepth()
|
||||
return out
|
||||
case *gen.LogicalNotContext:
|
||||
return p.VisitLogicalNot(tree.(*gen.LogicalNotContext))
|
||||
case *gen.MemberExprContext:
|
||||
return p.VisitMemberExpr(tree.(*gen.MemberExprContext))
|
||||
case *gen.PrimaryExprContext:
|
||||
return p.VisitPrimaryExpr(tree.(*gen.PrimaryExprContext))
|
||||
case *gen.SelectOrCallContext:
|
||||
return p.VisitSelectOrCall(tree.(*gen.SelectOrCallContext))
|
||||
return p.VisitLogicalNot(tree)
|
||||
case *gen.IdentOrGlobalCallContext:
|
||||
return p.VisitIdentOrGlobalCall(tree)
|
||||
case *gen.SelectContext:
|
||||
p.checkAndIncrementRecursionDepth()
|
||||
out := p.VisitSelect(tree)
|
||||
p.decrementRecursionDepth()
|
||||
return out
|
||||
case *gen.MemberCallContext:
|
||||
p.checkAndIncrementRecursionDepth()
|
||||
out := p.VisitMemberCall(tree)
|
||||
p.decrementRecursionDepth()
|
||||
return out
|
||||
case *gen.MapInitializerListContext:
|
||||
return p.VisitMapInitializerList(tree.(*gen.MapInitializerListContext))
|
||||
return p.VisitMapInitializerList(tree)
|
||||
case *gen.NegateContext:
|
||||
return p.VisitNegate(tree.(*gen.NegateContext))
|
||||
return p.VisitNegate(tree)
|
||||
case *gen.IndexContext:
|
||||
return p.VisitIndex(tree.(*gen.IndexContext))
|
||||
p.checkAndIncrementRecursionDepth()
|
||||
out := p.VisitIndex(tree)
|
||||
p.decrementRecursionDepth()
|
||||
return out
|
||||
case *gen.UnaryContext:
|
||||
return p.VisitUnary(tree.(*gen.UnaryContext))
|
||||
return p.VisitUnary(tree)
|
||||
case *gen.CreateListContext:
|
||||
return p.VisitCreateList(tree.(*gen.CreateListContext))
|
||||
return p.VisitCreateList(tree)
|
||||
case *gen.CreateMessageContext:
|
||||
return p.VisitCreateMessage(tree.(*gen.CreateMessageContext))
|
||||
return p.VisitCreateMessage(tree)
|
||||
case *gen.CreateStructContext:
|
||||
return p.VisitCreateStruct(tree.(*gen.CreateStructContext))
|
||||
return p.VisitCreateStruct(tree)
|
||||
case *gen.IntContext:
|
||||
return p.VisitInt(tree)
|
||||
case *gen.UintContext:
|
||||
return p.VisitUint(tree)
|
||||
case *gen.DoubleContext:
|
||||
return p.VisitDouble(tree)
|
||||
case *gen.StringContext:
|
||||
return p.VisitString(tree)
|
||||
case *gen.BytesContext:
|
||||
return p.VisitBytes(tree)
|
||||
case *gen.BoolFalseContext:
|
||||
return p.VisitBoolFalse(tree)
|
||||
case *gen.BoolTrueContext:
|
||||
return p.VisitBoolTrue(tree)
|
||||
case *gen.NullContext:
|
||||
return p.VisitNull(tree)
|
||||
}
|
||||
|
||||
// Report at least one error if the parser reaches an unknown parse element.
|
||||
// Typically, this happens if the parser has already encountered a syntax error elsewhere.
|
||||
if len(p.errors.GetErrors()) == 0 {
|
||||
txt := "<<nil>>"
|
||||
if tree != nil {
|
||||
txt = fmt.Sprintf("<<%T>>", tree)
|
||||
if t != nil {
|
||||
txt = fmt.Sprintf("<<%T>>", t)
|
||||
}
|
||||
return p.reportError(common.NoLocation, "unknown parse element encountered: %s", txt)
|
||||
}
|
||||
@ -411,12 +461,12 @@ func (p *parser) Visit(tree antlr.ParseTree) interface{} {
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#start.
|
||||
func (p *parser) VisitStart(ctx *gen.StartContext) interface{} {
|
||||
func (p *parser) VisitStart(ctx *gen.StartContext) any {
|
||||
return p.Visit(ctx.Expr())
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#expr.
|
||||
func (p *parser) VisitExpr(ctx *gen.ExprContext) interface{} {
|
||||
func (p *parser) VisitExpr(ctx *gen.ExprContext) any {
|
||||
result := p.Visit(ctx.GetE()).(*exprpb.Expr)
|
||||
if ctx.GetOp() == nil {
|
||||
return result
|
||||
@ -428,11 +478,8 @@ func (p *parser) VisitExpr(ctx *gen.ExprContext) interface{} {
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#conditionalOr.
|
||||
func (p *parser) VisitConditionalOr(ctx *gen.ConditionalOrContext) interface{} {
|
||||
func (p *parser) VisitConditionalOr(ctx *gen.ConditionalOrContext) any {
|
||||
result := p.Visit(ctx.GetE()).(*exprpb.Expr)
|
||||
if ctx.GetOps() == nil {
|
||||
return result
|
||||
}
|
||||
b := newBalancer(p.helper, operators.LogicalOr, result)
|
||||
rest := ctx.GetE1()
|
||||
for i, op := range ctx.GetOps() {
|
||||
@ -447,11 +494,8 @@ func (p *parser) VisitConditionalOr(ctx *gen.ConditionalOrContext) interface{} {
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#conditionalAnd.
|
||||
func (p *parser) VisitConditionalAnd(ctx *gen.ConditionalAndContext) interface{} {
|
||||
func (p *parser) VisitConditionalAnd(ctx *gen.ConditionalAndContext) any {
|
||||
result := p.Visit(ctx.GetE()).(*exprpb.Expr)
|
||||
if ctx.GetOps() == nil {
|
||||
return result
|
||||
}
|
||||
b := newBalancer(p.helper, operators.LogicalAnd, result)
|
||||
rest := ctx.GetE1()
|
||||
for i, op := range ctx.GetOps() {
|
||||
@ -466,10 +510,7 @@ func (p *parser) VisitConditionalAnd(ctx *gen.ConditionalAndContext) interface{}
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#relation.
|
||||
func (p *parser) VisitRelation(ctx *gen.RelationContext) interface{} {
|
||||
if ctx.Calc() != nil {
|
||||
return p.Visit(ctx.Calc())
|
||||
}
|
||||
func (p *parser) VisitRelation(ctx *gen.RelationContext) any {
|
||||
opText := ""
|
||||
if ctx.GetOp() != nil {
|
||||
opText = ctx.GetOp().GetText()
|
||||
@ -484,10 +525,7 @@ func (p *parser) VisitRelation(ctx *gen.RelationContext) interface{} {
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#calc.
|
||||
func (p *parser) VisitCalc(ctx *gen.CalcContext) interface{} {
|
||||
if ctx.Unary() != nil {
|
||||
return p.Visit(ctx.Unary())
|
||||
}
|
||||
func (p *parser) VisitCalc(ctx *gen.CalcContext) any {
|
||||
opText := ""
|
||||
if ctx.GetOp() != nil {
|
||||
opText = ctx.GetOp().GetText()
|
||||
@ -501,27 +539,12 @@ func (p *parser) VisitCalc(ctx *gen.CalcContext) interface{} {
|
||||
return p.reportError(ctx, "operator not found")
|
||||
}
|
||||
|
||||
func (p *parser) VisitUnary(ctx *gen.UnaryContext) interface{} {
|
||||
func (p *parser) VisitUnary(ctx *gen.UnaryContext) any {
|
||||
return p.helper.newLiteralString(ctx, "<<error>>")
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#MemberExpr.
|
||||
func (p *parser) VisitMemberExpr(ctx *gen.MemberExprContext) interface{} {
|
||||
switch ctx.Member().(type) {
|
||||
case *gen.PrimaryExprContext:
|
||||
return p.VisitPrimaryExpr(ctx.Member().(*gen.PrimaryExprContext))
|
||||
case *gen.SelectOrCallContext:
|
||||
return p.VisitSelectOrCall(ctx.Member().(*gen.SelectOrCallContext))
|
||||
case *gen.IndexContext:
|
||||
return p.VisitIndex(ctx.Member().(*gen.IndexContext))
|
||||
case *gen.CreateMessageContext:
|
||||
return p.VisitCreateMessage(ctx.Member().(*gen.CreateMessageContext))
|
||||
}
|
||||
return p.reportError(ctx, "unsupported simple expression")
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#LogicalNot.
|
||||
func (p *parser) VisitLogicalNot(ctx *gen.LogicalNotContext) interface{} {
|
||||
func (p *parser) VisitLogicalNot(ctx *gen.LogicalNotContext) any {
|
||||
if len(ctx.GetOps())%2 == 0 {
|
||||
return p.Visit(ctx.Member())
|
||||
}
|
||||
@ -530,7 +553,7 @@ func (p *parser) VisitLogicalNot(ctx *gen.LogicalNotContext) interface{} {
|
||||
return p.globalCallOrMacro(opID, operators.LogicalNot, target)
|
||||
}
|
||||
|
||||
func (p *parser) VisitNegate(ctx *gen.NegateContext) interface{} {
|
||||
func (p *parser) VisitNegate(ctx *gen.NegateContext) any {
|
||||
if len(ctx.GetOps())%2 == 0 {
|
||||
return p.Visit(ctx.Member())
|
||||
}
|
||||
@ -539,60 +562,77 @@ func (p *parser) VisitNegate(ctx *gen.NegateContext) interface{} {
|
||||
return p.globalCallOrMacro(opID, operators.Negate, target)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#SelectOrCall.
|
||||
func (p *parser) VisitSelectOrCall(ctx *gen.SelectOrCallContext) interface{} {
|
||||
// VisitSelect visits a parse tree produced by CELParser#Select.
|
||||
func (p *parser) VisitSelect(ctx *gen.SelectContext) any {
|
||||
operand := p.Visit(ctx.Member()).(*exprpb.Expr)
|
||||
// Handle the error case where no valid identifier is specified.
|
||||
if ctx.GetId() == nil || ctx.GetOp() == nil {
|
||||
return p.helper.newExpr(ctx)
|
||||
}
|
||||
id := ctx.GetId().GetText()
|
||||
if ctx.GetOpt() != nil {
|
||||
if !p.enableOptionalSyntax {
|
||||
return p.reportError(ctx.GetOp(), "unsupported syntax '.?'")
|
||||
}
|
||||
return p.helper.newGlobalCall(
|
||||
ctx.GetOp(),
|
||||
operators.OptSelect,
|
||||
operand,
|
||||
p.helper.newLiteralString(ctx.GetId(), id))
|
||||
}
|
||||
return p.helper.newSelect(ctx.GetOp(), operand, id)
|
||||
}
|
||||
|
||||
// VisitMemberCall visits a parse tree produced by CELParser#MemberCall.
|
||||
func (p *parser) VisitMemberCall(ctx *gen.MemberCallContext) any {
|
||||
operand := p.Visit(ctx.Member()).(*exprpb.Expr)
|
||||
// Handle the error case where no valid identifier is specified.
|
||||
if ctx.GetId() == nil {
|
||||
return p.helper.newExpr(ctx)
|
||||
}
|
||||
id := ctx.GetId().GetText()
|
||||
if ctx.GetOpen() != nil {
|
||||
opID := p.helper.id(ctx.GetOpen())
|
||||
return p.receiverCallOrMacro(opID, id, operand, p.visitList(ctx.GetArgs())...)
|
||||
}
|
||||
return p.helper.newSelect(ctx.GetOp(), operand, id)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#PrimaryExpr.
|
||||
func (p *parser) VisitPrimaryExpr(ctx *gen.PrimaryExprContext) interface{} {
|
||||
switch ctx.Primary().(type) {
|
||||
case *gen.NestedContext:
|
||||
return p.VisitNested(ctx.Primary().(*gen.NestedContext))
|
||||
case *gen.IdentOrGlobalCallContext:
|
||||
return p.VisitIdentOrGlobalCall(ctx.Primary().(*gen.IdentOrGlobalCallContext))
|
||||
case *gen.CreateListContext:
|
||||
return p.VisitCreateList(ctx.Primary().(*gen.CreateListContext))
|
||||
case *gen.CreateStructContext:
|
||||
return p.VisitCreateStruct(ctx.Primary().(*gen.CreateStructContext))
|
||||
case *gen.ConstantLiteralContext:
|
||||
return p.VisitConstantLiteral(ctx.Primary().(*gen.ConstantLiteralContext))
|
||||
}
|
||||
|
||||
return p.reportError(ctx, "invalid primary expression")
|
||||
opID := p.helper.id(ctx.GetOpen())
|
||||
return p.receiverCallOrMacro(opID, id, operand, p.visitExprList(ctx.GetArgs())...)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#Index.
|
||||
func (p *parser) VisitIndex(ctx *gen.IndexContext) interface{} {
|
||||
func (p *parser) VisitIndex(ctx *gen.IndexContext) any {
|
||||
target := p.Visit(ctx.Member()).(*exprpb.Expr)
|
||||
// Handle the error case where no valid identifier is specified.
|
||||
if ctx.GetOp() == nil {
|
||||
return p.helper.newExpr(ctx)
|
||||
}
|
||||
opID := p.helper.id(ctx.GetOp())
|
||||
index := p.Visit(ctx.GetIndex()).(*exprpb.Expr)
|
||||
return p.globalCallOrMacro(opID, operators.Index, target, index)
|
||||
operator := operators.Index
|
||||
if ctx.GetOpt() != nil {
|
||||
if !p.enableOptionalSyntax {
|
||||
return p.reportError(ctx.GetOp(), "unsupported syntax '[?'")
|
||||
}
|
||||
operator = operators.OptIndex
|
||||
}
|
||||
return p.globalCallOrMacro(opID, operator, target, index)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#CreateMessage.
|
||||
func (p *parser) VisitCreateMessage(ctx *gen.CreateMessageContext) interface{} {
|
||||
target := p.Visit(ctx.Member()).(*exprpb.Expr)
|
||||
objID := p.helper.id(ctx.GetOp())
|
||||
if messageName, found := p.extractQualifiedName(target); found {
|
||||
entries := p.VisitIFieldInitializerList(ctx.GetEntries()).([]*exprpb.Expr_CreateStruct_Entry)
|
||||
return p.helper.newObject(objID, messageName, entries...)
|
||||
func (p *parser) VisitCreateMessage(ctx *gen.CreateMessageContext) any {
|
||||
messageName := ""
|
||||
for _, id := range ctx.GetIds() {
|
||||
if len(messageName) != 0 {
|
||||
messageName += "."
|
||||
}
|
||||
messageName += id.GetText()
|
||||
}
|
||||
return p.helper.newExpr(objID)
|
||||
if ctx.GetLeadingDot() != nil {
|
||||
messageName = "." + messageName
|
||||
}
|
||||
objID := p.helper.id(ctx.GetOp())
|
||||
entries := p.VisitIFieldInitializerList(ctx.GetEntries()).([]*exprpb.Expr_CreateStruct_Entry)
|
||||
return p.helper.newObject(objID, messageName, entries...)
|
||||
}
|
||||
|
||||
// Visit a parse tree of field initializers.
|
||||
func (p *parser) VisitIFieldInitializerList(ctx gen.IFieldInitializerListContext) interface{} {
|
||||
func (p *parser) VisitIFieldInitializerList(ctx gen.IFieldInitializerListContext) any {
|
||||
if ctx == nil || ctx.GetFields() == nil {
|
||||
// This is the result of a syntax error handled elswhere, return empty.
|
||||
return []*exprpb.Expr_CreateStruct_Entry{}
|
||||
@ -607,15 +647,27 @@ func (p *parser) VisitIFieldInitializerList(ctx gen.IFieldInitializerListContext
|
||||
return []*exprpb.Expr_CreateStruct_Entry{}
|
||||
}
|
||||
initID := p.helper.id(cols[i])
|
||||
optField := f.(*gen.OptFieldContext)
|
||||
optional := optField.GetOpt() != nil
|
||||
if !p.enableOptionalSyntax && optional {
|
||||
p.reportError(optField, "unsupported syntax '?'")
|
||||
continue
|
||||
}
|
||||
// The field may be empty due to a prior error.
|
||||
id := optField.IDENTIFIER()
|
||||
if id == nil {
|
||||
return []*exprpb.Expr_CreateStruct_Entry{}
|
||||
}
|
||||
fieldName := id.GetText()
|
||||
value := p.Visit(vals[i]).(*exprpb.Expr)
|
||||
field := p.helper.newObjectField(initID, f.GetText(), value)
|
||||
field := p.helper.newObjectField(initID, fieldName, value, optional)
|
||||
result[i] = field
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#IdentOrGlobalCall.
|
||||
func (p *parser) VisitIdentOrGlobalCall(ctx *gen.IdentOrGlobalCallContext) interface{} {
|
||||
func (p *parser) VisitIdentOrGlobalCall(ctx *gen.IdentOrGlobalCallContext) any {
|
||||
identName := ""
|
||||
if ctx.GetLeadingDot() != nil {
|
||||
identName = "."
|
||||
@ -632,24 +684,20 @@ func (p *parser) VisitIdentOrGlobalCall(ctx *gen.IdentOrGlobalCallContext) inter
|
||||
identName += id
|
||||
if ctx.GetOp() != nil {
|
||||
opID := p.helper.id(ctx.GetOp())
|
||||
return p.globalCallOrMacro(opID, identName, p.visitList(ctx.GetArgs())...)
|
||||
return p.globalCallOrMacro(opID, identName, p.visitExprList(ctx.GetArgs())...)
|
||||
}
|
||||
return p.helper.newIdent(ctx.GetId(), identName)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#Nested.
|
||||
func (p *parser) VisitNested(ctx *gen.NestedContext) interface{} {
|
||||
return p.Visit(ctx.GetE())
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#CreateList.
|
||||
func (p *parser) VisitCreateList(ctx *gen.CreateListContext) interface{} {
|
||||
func (p *parser) VisitCreateList(ctx *gen.CreateListContext) any {
|
||||
listID := p.helper.id(ctx.GetOp())
|
||||
return p.helper.newList(listID, p.visitList(ctx.GetElems())...)
|
||||
elems, optionals := p.visitListInit(ctx.GetElems())
|
||||
return p.helper.newList(listID, elems, optionals...)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#CreateStruct.
|
||||
func (p *parser) VisitCreateStruct(ctx *gen.CreateStructContext) interface{} {
|
||||
func (p *parser) VisitCreateStruct(ctx *gen.CreateStructContext) any {
|
||||
structID := p.helper.id(ctx.GetOp())
|
||||
entries := []*exprpb.Expr_CreateStruct_Entry{}
|
||||
if ctx.GetEntries() != nil {
|
||||
@ -658,31 +706,8 @@ func (p *parser) VisitCreateStruct(ctx *gen.CreateStructContext) interface{} {
|
||||
return p.helper.newMap(structID, entries...)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#ConstantLiteral.
|
||||
func (p *parser) VisitConstantLiteral(ctx *gen.ConstantLiteralContext) interface{} {
|
||||
switch ctx.Literal().(type) {
|
||||
case *gen.IntContext:
|
||||
return p.VisitInt(ctx.Literal().(*gen.IntContext))
|
||||
case *gen.UintContext:
|
||||
return p.VisitUint(ctx.Literal().(*gen.UintContext))
|
||||
case *gen.DoubleContext:
|
||||
return p.VisitDouble(ctx.Literal().(*gen.DoubleContext))
|
||||
case *gen.StringContext:
|
||||
return p.VisitString(ctx.Literal().(*gen.StringContext))
|
||||
case *gen.BytesContext:
|
||||
return p.VisitBytes(ctx.Literal().(*gen.BytesContext))
|
||||
case *gen.BoolFalseContext:
|
||||
return p.VisitBoolFalse(ctx.Literal().(*gen.BoolFalseContext))
|
||||
case *gen.BoolTrueContext:
|
||||
return p.VisitBoolTrue(ctx.Literal().(*gen.BoolTrueContext))
|
||||
case *gen.NullContext:
|
||||
return p.VisitNull(ctx.Literal().(*gen.NullContext))
|
||||
}
|
||||
return p.reportError(ctx, "invalid literal")
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#mapInitializerList.
|
||||
func (p *parser) VisitMapInitializerList(ctx *gen.MapInitializerListContext) interface{} {
|
||||
func (p *parser) VisitMapInitializerList(ctx *gen.MapInitializerListContext) any {
|
||||
if ctx == nil || ctx.GetKeys() == nil {
|
||||
// This is the result of a syntax error handled elswhere, return empty.
|
||||
return []*exprpb.Expr_CreateStruct_Entry{}
|
||||
@ -697,16 +722,22 @@ func (p *parser) VisitMapInitializerList(ctx *gen.MapInitializerListContext) int
|
||||
// This is the result of a syntax error detected elsewhere.
|
||||
return []*exprpb.Expr_CreateStruct_Entry{}
|
||||
}
|
||||
key := p.Visit(keys[i]).(*exprpb.Expr)
|
||||
optKey := keys[i]
|
||||
optional := optKey.GetOpt() != nil
|
||||
if !p.enableOptionalSyntax && optional {
|
||||
p.reportError(optKey, "unsupported syntax '?'")
|
||||
continue
|
||||
}
|
||||
key := p.Visit(optKey.GetE()).(*exprpb.Expr)
|
||||
value := p.Visit(vals[i]).(*exprpb.Expr)
|
||||
entry := p.helper.newMapEntry(colID, key, value)
|
||||
entry := p.helper.newMapEntry(colID, key, value, optional)
|
||||
result[i] = entry
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#Int.
|
||||
func (p *parser) VisitInt(ctx *gen.IntContext) interface{} {
|
||||
func (p *parser) VisitInt(ctx *gen.IntContext) any {
|
||||
text := ctx.GetTok().GetText()
|
||||
base := 10
|
||||
if strings.HasPrefix(text, "0x") {
|
||||
@ -724,7 +755,7 @@ func (p *parser) VisitInt(ctx *gen.IntContext) interface{} {
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#Uint.
|
||||
func (p *parser) VisitUint(ctx *gen.UintContext) interface{} {
|
||||
func (p *parser) VisitUint(ctx *gen.UintContext) any {
|
||||
text := ctx.GetTok().GetText()
|
||||
// trim the 'u' designator included in the uint literal.
|
||||
text = text[:len(text)-1]
|
||||
@ -741,7 +772,7 @@ func (p *parser) VisitUint(ctx *gen.UintContext) interface{} {
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#Double.
|
||||
func (p *parser) VisitDouble(ctx *gen.DoubleContext) interface{} {
|
||||
func (p *parser) VisitDouble(ctx *gen.DoubleContext) any {
|
||||
txt := ctx.GetTok().GetText()
|
||||
if ctx.GetSign() != nil {
|
||||
txt = ctx.GetSign().GetText() + txt
|
||||
@ -755,42 +786,66 @@ func (p *parser) VisitDouble(ctx *gen.DoubleContext) interface{} {
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#String.
|
||||
func (p *parser) VisitString(ctx *gen.StringContext) interface{} {
|
||||
func (p *parser) VisitString(ctx *gen.StringContext) any {
|
||||
s := p.unquote(ctx, ctx.GetText(), false)
|
||||
return p.helper.newLiteralString(ctx, s)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#Bytes.
|
||||
func (p *parser) VisitBytes(ctx *gen.BytesContext) interface{} {
|
||||
func (p *parser) VisitBytes(ctx *gen.BytesContext) any {
|
||||
b := []byte(p.unquote(ctx, ctx.GetTok().GetText()[1:], true))
|
||||
return p.helper.newLiteralBytes(ctx, b)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#BoolTrue.
|
||||
func (p *parser) VisitBoolTrue(ctx *gen.BoolTrueContext) interface{} {
|
||||
func (p *parser) VisitBoolTrue(ctx *gen.BoolTrueContext) any {
|
||||
return p.helper.newLiteralBool(ctx, true)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#BoolFalse.
|
||||
func (p *parser) VisitBoolFalse(ctx *gen.BoolFalseContext) interface{} {
|
||||
func (p *parser) VisitBoolFalse(ctx *gen.BoolFalseContext) any {
|
||||
return p.helper.newLiteralBool(ctx, false)
|
||||
}
|
||||
|
||||
// Visit a parse tree produced by CELParser#Null.
|
||||
func (p *parser) VisitNull(ctx *gen.NullContext) interface{} {
|
||||
func (p *parser) VisitNull(ctx *gen.NullContext) any {
|
||||
return p.helper.newLiteral(ctx,
|
||||
&exprpb.Constant{
|
||||
ConstantKind: &exprpb.Constant_NullValue{
|
||||
NullValue: structpb.NullValue_NULL_VALUE}})
|
||||
}
|
||||
|
||||
func (p *parser) visitList(ctx gen.IExprListContext) []*exprpb.Expr {
|
||||
func (p *parser) visitExprList(ctx gen.IExprListContext) []*exprpb.Expr {
|
||||
if ctx == nil {
|
||||
return []*exprpb.Expr{}
|
||||
}
|
||||
return p.visitSlice(ctx.GetE())
|
||||
}
|
||||
|
||||
func (p *parser) visitListInit(ctx gen.IListInitContext) ([]*exprpb.Expr, []int32) {
|
||||
if ctx == nil {
|
||||
return []*exprpb.Expr{}, []int32{}
|
||||
}
|
||||
elements := ctx.GetElems()
|
||||
result := make([]*exprpb.Expr, len(elements))
|
||||
optionals := []int32{}
|
||||
for i, e := range elements {
|
||||
ex := p.Visit(e.GetE()).(*exprpb.Expr)
|
||||
if ex == nil {
|
||||
return []*exprpb.Expr{}, []int32{}
|
||||
}
|
||||
result[i] = ex
|
||||
if e.GetOpt() != nil {
|
||||
if !p.enableOptionalSyntax {
|
||||
p.reportError(e.GetOpt(), "unsupported syntax '?'")
|
||||
continue
|
||||
}
|
||||
optionals = append(optionals, int32(i))
|
||||
}
|
||||
}
|
||||
return result, optionals
|
||||
}
|
||||
|
||||
func (p *parser) visitSlice(expressions []gen.IExprContext) []*exprpb.Expr {
|
||||
if expressions == nil {
|
||||
return []*exprpb.Expr{}
|
||||
@ -803,26 +858,7 @@ func (p *parser) visitSlice(expressions []gen.IExprContext) []*exprpb.Expr {
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *parser) extractQualifiedName(e *exprpb.Expr) (string, bool) {
|
||||
if e == nil {
|
||||
return "", false
|
||||
}
|
||||
switch e.GetExprKind().(type) {
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
return e.GetIdentExpr().GetName(), true
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
s := e.GetSelectExpr()
|
||||
if prefix, found := p.extractQualifiedName(s.GetOperand()); found {
|
||||
return prefix + "." + s.GetField(), true
|
||||
}
|
||||
}
|
||||
// TODO: Add a method to Source to get location from character offset.
|
||||
location := p.helper.getLocation(e.GetId())
|
||||
p.reportError(location, "expected a qualified name")
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (p *parser) unquote(ctx interface{}, value string, isBytes bool) string {
|
||||
func (p *parser) unquote(ctx any, value string, isBytes bool) string {
|
||||
text, err := unescape(value, isBytes)
|
||||
if err != nil {
|
||||
p.reportError(ctx, "%s", err.Error())
|
||||
@ -831,7 +867,7 @@ func (p *parser) unquote(ctx interface{}, value string, isBytes bool) string {
|
||||
return text
|
||||
}
|
||||
|
||||
func (p *parser) reportError(ctx interface{}, format string, args ...interface{}) *exprpb.Expr {
|
||||
func (p *parser) reportError(ctx any, format string, args ...any) *exprpb.Expr {
|
||||
var location common.Location
|
||||
switch ctx.(type) {
|
||||
case common.Location:
|
||||
@ -847,10 +883,24 @@ func (p *parser) reportError(ctx interface{}, format string, args ...interface{}
|
||||
}
|
||||
|
||||
// ANTLR Parse listener implementations
|
||||
func (p *parser) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
|
||||
// TODO: Snippet
|
||||
func (p *parser) SyntaxError(recognizer antlr.Recognizer, offendingSymbol any, line, column int, msg string, e antlr.RecognitionException) {
|
||||
l := p.helper.source.NewLocation(line, column)
|
||||
p.errors.syntaxError(l, msg)
|
||||
// Hack to keep existing error messages consistent with previous versions of CEL when a reserved word
|
||||
// is used as an identifier. This behavior needs to be overhauled to provide consistent, normalized error
|
||||
// messages out of ANTLR to prevent future breaking changes related to error message content.
|
||||
if strings.Contains(msg, "no viable alternative") {
|
||||
msg = reservedIdentifier.ReplaceAllString(msg, mismatchedReservedIdentifier)
|
||||
}
|
||||
// Ensure that no more than 100 syntax errors are reported as this will halt attempts to recover from a
|
||||
// seriously broken expression.
|
||||
if p.errorReports < p.errorReportingLimit {
|
||||
p.errorReports++
|
||||
p.errors.syntaxError(l, msg)
|
||||
} else {
|
||||
tme := &tooManyErrors{errorReportingLimit: p.errorReportingLimit}
|
||||
p.errors.syntaxError(l, tme.Error())
|
||||
panic(tme)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) ReportAmbiguity(recognizer antlr.Parser, dfa *antlr.DFA, startIndex, stopIndex int, exact bool, ambigAlts *antlr.BitSet, configs antlr.ATNConfigSet) {
|
||||
@ -892,14 +942,95 @@ func (p *parser) expandMacro(exprID int64, function string, target *exprpb.Expr,
|
||||
eh.parserHelper = p.helper
|
||||
eh.id = exprID
|
||||
expr, err := macro.Expander()(eh, target, args)
|
||||
// An error indicates that the macro was matched, but the arguments were not well-formed.
|
||||
if err != nil {
|
||||
if err.Location != nil {
|
||||
return p.reportError(err.Location, err.Message), true
|
||||
}
|
||||
return p.reportError(p.helper.getLocation(exprID), err.Message), true
|
||||
}
|
||||
// A nil value from the macro indicates that the macro implementation decided that
|
||||
// an expansion should not be performed.
|
||||
if expr == nil {
|
||||
return nil, false
|
||||
}
|
||||
if p.populateMacroCalls {
|
||||
p.helper.addMacroCall(expr.GetId(), function, target, args...)
|
||||
}
|
||||
return expr, true
|
||||
}
|
||||
|
||||
func (p *parser) checkAndIncrementRecursionDepth() {
|
||||
p.recursionDepth++
|
||||
if p.recursionDepth > p.maxRecursionDepth {
|
||||
panic(&recursionError{message: "max recursion depth exceeded"})
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) decrementRecursionDepth() {
|
||||
p.recursionDepth--
|
||||
}
|
||||
|
||||
// unnest traverses down the left-hand side of the parse graph until it encounters the first compound
|
||||
// parse node or the first leaf in the parse graph.
|
||||
func unnest(tree antlr.ParseTree) antlr.ParseTree {
|
||||
for tree != nil {
|
||||
switch t := tree.(type) {
|
||||
case *gen.ExprContext:
|
||||
// conditionalOr op='?' conditionalOr : expr
|
||||
if t.GetOp() != nil {
|
||||
return t
|
||||
}
|
||||
// conditionalOr
|
||||
tree = t.GetE()
|
||||
case *gen.ConditionalOrContext:
|
||||
// conditionalAnd (ops=|| conditionalAnd)*
|
||||
if t.GetOps() != nil && len(t.GetOps()) > 0 {
|
||||
return t
|
||||
}
|
||||
// conditionalAnd
|
||||
tree = t.GetE()
|
||||
case *gen.ConditionalAndContext:
|
||||
// relation (ops=&& relation)*
|
||||
if t.GetOps() != nil && len(t.GetOps()) > 0 {
|
||||
return t
|
||||
}
|
||||
// relation
|
||||
tree = t.GetE()
|
||||
case *gen.RelationContext:
|
||||
// relation op relation
|
||||
if t.GetOp() != nil {
|
||||
return t
|
||||
}
|
||||
// calc
|
||||
tree = t.Calc()
|
||||
case *gen.CalcContext:
|
||||
// calc op calc
|
||||
if t.GetOp() != nil {
|
||||
return t
|
||||
}
|
||||
// unary
|
||||
tree = t.Unary()
|
||||
case *gen.MemberExprContext:
|
||||
// member expands to one of: primary, select, index, or create message
|
||||
tree = t.Member()
|
||||
case *gen.PrimaryExprContext:
|
||||
// primary expands to one of identifier, nested, create list, create struct, literal
|
||||
tree = t.Primary()
|
||||
case *gen.NestedContext:
|
||||
// contains a nested 'expr'
|
||||
tree = t.GetE()
|
||||
case *gen.ConstantLiteralContext:
|
||||
// expands to a primitive literal
|
||||
tree = t.Literal()
|
||||
default:
|
||||
return t
|
||||
}
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
||||
var (
|
||||
reservedIdentifier = regexp.MustCompile("no viable alternative at input '.(true|false|null)'")
|
||||
mismatchedReservedIdentifier = "mismatched input '$1' expecting IDENTIFIER"
|
||||
)
|
||||
|
63
vendor/github.com/google/cel-go/parser/unparser.go
generated
vendored
63
vendor/github.com/google/cel-go/parser/unparser.go
generated
vendored
@ -106,9 +106,15 @@ func (un *unparser) visitCall(expr *exprpb.Expr) error {
|
||||
// ternary operator
|
||||
case operators.Conditional:
|
||||
return un.visitCallConditional(expr)
|
||||
// optional select operator
|
||||
case operators.OptSelect:
|
||||
return un.visitOptSelect(expr)
|
||||
// index operator
|
||||
case operators.Index:
|
||||
return un.visitCallIndex(expr)
|
||||
// optional index operator
|
||||
case operators.OptIndex:
|
||||
return un.visitCallOptIndex(expr)
|
||||
// unary operators
|
||||
case operators.LogicalNot, operators.Negate:
|
||||
return un.visitCallUnary(expr)
|
||||
@ -218,6 +224,14 @@ func (un *unparser) visitCallFunc(expr *exprpb.Expr) error {
|
||||
}
|
||||
|
||||
func (un *unparser) visitCallIndex(expr *exprpb.Expr) error {
|
||||
return un.visitCallIndexInternal(expr, "[")
|
||||
}
|
||||
|
||||
func (un *unparser) visitCallOptIndex(expr *exprpb.Expr) error {
|
||||
return un.visitCallIndexInternal(expr, "[?")
|
||||
}
|
||||
|
||||
func (un *unparser) visitCallIndexInternal(expr *exprpb.Expr, op string) error {
|
||||
c := expr.GetCallExpr()
|
||||
args := c.GetArgs()
|
||||
nested := isBinaryOrTernaryOperator(args[0])
|
||||
@ -225,7 +239,7 @@ func (un *unparser) visitCallIndex(expr *exprpb.Expr) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
un.str.WriteString("[")
|
||||
un.str.WriteString(op)
|
||||
err = un.visit(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
@ -262,6 +276,9 @@ func (un *unparser) visitConst(expr *exprpb.Expr) error {
|
||||
// represent the float using the minimum required digits
|
||||
d := strconv.FormatFloat(c.GetDoubleValue(), 'g', -1, 64)
|
||||
un.str.WriteString(d)
|
||||
if !strings.Contains(d, ".") {
|
||||
un.str.WriteString(".0")
|
||||
}
|
||||
case *exprpb.Constant_Int64Value:
|
||||
i := strconv.FormatInt(c.GetInt64Value(), 10)
|
||||
un.str.WriteString(i)
|
||||
@ -289,8 +306,15 @@ func (un *unparser) visitIdent(expr *exprpb.Expr) error {
|
||||
func (un *unparser) visitList(expr *exprpb.Expr) error {
|
||||
l := expr.GetListExpr()
|
||||
elems := l.GetElements()
|
||||
optIndices := make(map[int]bool, len(elems))
|
||||
for _, idx := range l.GetOptionalIndices() {
|
||||
optIndices[int(idx)] = true
|
||||
}
|
||||
un.str.WriteString("[")
|
||||
for i, elem := range elems {
|
||||
if optIndices[i] {
|
||||
un.str.WriteString("?")
|
||||
}
|
||||
err := un.visit(elem)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -303,20 +327,32 @@ func (un *unparser) visitList(expr *exprpb.Expr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (un *unparser) visitOptSelect(expr *exprpb.Expr) error {
|
||||
c := expr.GetCallExpr()
|
||||
args := c.GetArgs()
|
||||
operand := args[0]
|
||||
field := args[1].GetConstExpr().GetStringValue()
|
||||
return un.visitSelectInternal(operand, false, ".?", field)
|
||||
}
|
||||
|
||||
func (un *unparser) visitSelect(expr *exprpb.Expr) error {
|
||||
sel := expr.GetSelectExpr()
|
||||
return un.visitSelectInternal(sel.GetOperand(), sel.GetTestOnly(), ".", sel.GetField())
|
||||
}
|
||||
|
||||
func (un *unparser) visitSelectInternal(operand *exprpb.Expr, testOnly bool, op string, field string) error {
|
||||
// handle the case when the select expression was generated by the has() macro.
|
||||
if sel.GetTestOnly() {
|
||||
if testOnly {
|
||||
un.str.WriteString("has(")
|
||||
}
|
||||
nested := !sel.GetTestOnly() && isBinaryOrTernaryOperator(sel.GetOperand())
|
||||
err := un.visitMaybeNested(sel.GetOperand(), nested)
|
||||
nested := !testOnly && isBinaryOrTernaryOperator(operand)
|
||||
err := un.visitMaybeNested(operand, nested)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
un.str.WriteString(".")
|
||||
un.str.WriteString(sel.GetField())
|
||||
if sel.GetTestOnly() {
|
||||
un.str.WriteString(op)
|
||||
un.str.WriteString(field)
|
||||
if testOnly {
|
||||
un.str.WriteString(")")
|
||||
}
|
||||
return nil
|
||||
@ -339,6 +375,9 @@ func (un *unparser) visitStructMsg(expr *exprpb.Expr) error {
|
||||
un.str.WriteString("{")
|
||||
for i, entry := range entries {
|
||||
f := entry.GetFieldKey()
|
||||
if entry.GetOptionalEntry() {
|
||||
un.str.WriteString("?")
|
||||
}
|
||||
un.str.WriteString(f)
|
||||
un.str.WriteString(": ")
|
||||
v := entry.GetValue()
|
||||
@ -360,6 +399,9 @@ func (un *unparser) visitStructMap(expr *exprpb.Expr) error {
|
||||
un.str.WriteString("{")
|
||||
for i, entry := range entries {
|
||||
k := entry.GetMapKey()
|
||||
if entry.GetOptionalEntry() {
|
||||
un.str.WriteString("?")
|
||||
}
|
||||
err := un.visit(k)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -492,11 +534,10 @@ func (un *unparser) writeOperatorWithWrapping(fun string, unmangled string) bool
|
||||
un.str.WriteString(" ")
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
un.str.WriteString(" ")
|
||||
un.str.WriteString(unmangled)
|
||||
un.str.WriteString(" ")
|
||||
}
|
||||
un.str.WriteString(" ")
|
||||
un.str.WriteString(unmangled)
|
||||
un.str.WriteString(" ")
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ import (
|
||||
"github.com/golang/protobuf/ptypes/any"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
|
||||
extensions "github.com/google/gnostic/extensions"
|
||||
extensions "github.com/google/gnostic-models/extensions"
|
||||
)
|
||||
|
||||
// ExtensionHandler describes a binary that is called by the compiler to handle specification extensions.
|
@ -22,7 +22,7 @@ import (
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/google/gnostic/jsonschema"
|
||||
"github.com/google/gnostic-models/jsonschema"
|
||||
)
|
||||
|
||||
// compiler helper functions, usually called from generated code
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user