Bump CEL to 0.11.2
This commit is contained in:
3
vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
3
vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
@@ -44,7 +44,9 @@ go_library(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"cel_example_test.go",
|
||||
"cel_test.go",
|
||||
"env_test.go",
|
||||
"io_test.go",
|
||||
],
|
||||
data = [
|
||||
@@ -66,6 +68,7 @@ go_test(
|
||||
"//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_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
|
||||
],
|
||||
)
|
||||
|
124
vendor/github.com/google/cel-go/cel/env.go
generated
vendored
124
vendor/github.com/google/cel-go/cel/env.go
generated
vendored
@@ -32,9 +32,7 @@ import (
|
||||
)
|
||||
|
||||
// Source interface representing a user-provided expression.
|
||||
type Source interface {
|
||||
common.Source
|
||||
}
|
||||
type Source = common.Source
|
||||
|
||||
// Ast representing the checked or unchecked expression, its source, and related metadata such as
|
||||
// source position information.
|
||||
@@ -56,7 +54,7 @@ func (ast *Ast) IsChecked() bool {
|
||||
return ast.typeMap != nil && len(ast.typeMap) > 0
|
||||
}
|
||||
|
||||
// SourceInfo returns character offset and newling position information about expression elements.
|
||||
// SourceInfo returns character offset and newline position information about expression elements.
|
||||
func (ast *Ast) SourceInfo() *exprpb.SourceInfo {
|
||||
return ast.info
|
||||
}
|
||||
@@ -98,6 +96,7 @@ type Env struct {
|
||||
chk *checker.Env
|
||||
chkErr error
|
||||
chkOnce sync.Once
|
||||
chkOpts []checker.Option
|
||||
|
||||
// Program options tied to the environment
|
||||
progOpts []ProgramOption
|
||||
@@ -110,8 +109,16 @@ type Env struct {
|
||||
// See the EnvOption helper functions for the options that can be used to configure the
|
||||
// environment.
|
||||
func NewEnv(opts ...EnvOption) (*Env, error) {
|
||||
stdOpts := append([]EnvOption{StdLib()}, opts...)
|
||||
return NewCustomEnv(stdOpts...)
|
||||
// Extend the statically configured standard environment, disabling eager validation to ensure
|
||||
// the cost of setup for the environment is still just as cheap as it is in v0.11.x and earlier
|
||||
// releases. The user provided options can easily re-enable the eager validation as they are
|
||||
// processed after this default option.
|
||||
stdOpts := append([]EnvOption{EagerlyValidateDeclarations(false)}, opts...)
|
||||
env, err := getStdEnv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return env.Extend(stdOpts...)
|
||||
}
|
||||
|
||||
// NewCustomEnv creates a custom program environment which is not automatically configured with the
|
||||
@@ -152,25 +159,8 @@ 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.
|
||||
e.chkOnce.Do(func() {
|
||||
ce, err := checker.NewEnv(e.Container, e.provider,
|
||||
checker.HomogeneousAggregateLiterals(
|
||||
e.HasFeature(featureDisableDynamicAggregateLiterals)),
|
||||
checker.CrossTypeNumericComparisons(
|
||||
e.HasFeature(featureCrossTypeNumericComparisons)))
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
return
|
||||
}
|
||||
err = ce.Add(e.declarations...)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
return
|
||||
}
|
||||
e.chk = ce
|
||||
})
|
||||
// The once call will ensure that this value is set or nil for all invocations.
|
||||
if e.chkErr != nil {
|
||||
err := e.initChecker()
|
||||
if err != nil {
|
||||
errs := common.NewErrors(ast.Source())
|
||||
errs.ReportError(common.NoLocation, e.chkErr.Error())
|
||||
return nil, NewIssues(errs)
|
||||
@@ -210,7 +200,7 @@ func (e *Env) Compile(txt string) (*Ast, *Issues) {
|
||||
// issues discovered during Check.
|
||||
//
|
||||
// Note, for parse-only uses of CEL use Parse.
|
||||
func (e *Env) CompileSource(src common.Source) (*Ast, *Issues) {
|
||||
func (e *Env) CompileSource(src Source) (*Ast, *Issues) {
|
||||
ast, iss := e.ParseSource(src)
|
||||
if iss.Err() != nil {
|
||||
return nil, iss
|
||||
@@ -233,11 +223,29 @@ func (e *Env) Extend(opts ...EnvOption) (*Env, error) {
|
||||
if e.chkErr != nil {
|
||||
return nil, e.chkErr
|
||||
}
|
||||
// Copy slices.
|
||||
decsCopy := make([]*exprpb.Decl, len(e.declarations))
|
||||
|
||||
// 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.
|
||||
chkOptsCopy := make([]checker.Option, len(e.chkOpts))
|
||||
copy(chkOptsCopy, e.chkOpts)
|
||||
|
||||
// Copy the declarations if needed.
|
||||
decsCopy := []*exprpb.Decl{}
|
||||
if e.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))
|
||||
} else {
|
||||
// If the type-checker has not been instantiated, ensure the unvalidated declarations are
|
||||
// provided to the extended Env instance.
|
||||
decsCopy = make([]*exprpb.Decl, len(e.declarations))
|
||||
copy(decsCopy, e.declarations)
|
||||
}
|
||||
|
||||
// Copy macros and program options
|
||||
macsCopy := make([]parser.Macro, len(e.macros))
|
||||
progOptsCopy := make([]ProgramOption, len(e.progOpts))
|
||||
copy(decsCopy, e.declarations)
|
||||
copy(macsCopy, e.macros)
|
||||
copy(progOptsCopy, e.progOpts)
|
||||
|
||||
@@ -281,6 +289,7 @@ func (e *Env) Extend(opts ...EnvOption) (*Env, error) {
|
||||
adapter: adapter,
|
||||
features: featuresCopy,
|
||||
provider: provider,
|
||||
chkOpts: chkOptsCopy,
|
||||
}
|
||||
return ext.configure(opts)
|
||||
}
|
||||
@@ -294,7 +303,7 @@ func (e *Env) HasFeature(flag int) bool {
|
||||
|
||||
// Parse parses the input expression value `txt` to a Ast and/or a set of Issues.
|
||||
//
|
||||
// This form of Parse creates a common.Source value for the input `txt` and forwards to the
|
||||
// This form of Parse creates a Source value for the input `txt` and forwards to the
|
||||
// ParseSource method.
|
||||
func (e *Env) Parse(txt string) (*Ast, *Issues) {
|
||||
src := common.NewTextSource(txt)
|
||||
@@ -308,7 +317,7 @@ func (e *Env) Parse(txt string) (*Ast, *Issues) {
|
||||
//
|
||||
// It is possible to have both non-nil Ast and Issues values returned from this call; however,
|
||||
// the mere presence of an Ast does not imply that it is valid for use.
|
||||
func (e *Env) ParseSource(src common.Source) (*Ast, *Issues) {
|
||||
func (e *Env) ParseSource(src Source) (*Ast, *Issues) {
|
||||
res, errs := e.prsr.Parse(src)
|
||||
if len(errs.GetErrors()) > 0 {
|
||||
return nil, &Issues{errs: errs}
|
||||
@@ -316,7 +325,7 @@ func (e *Env) ParseSource(src common.Source) (*Ast, *Issues) {
|
||||
// Manually create the Ast to ensure that the text source information is propagated on
|
||||
// subsequent calls to Check.
|
||||
return &Ast{
|
||||
source: Source(src),
|
||||
source: src,
|
||||
expr: res.GetExpr(),
|
||||
info: res.GetSourceInfo()}, nil
|
||||
}
|
||||
@@ -426,6 +435,8 @@ func (e *Env) configure(opts []EnvOption) (*Env, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the parser.
|
||||
prsrOpts := []parser.Option{parser.Macros(e.macros...)}
|
||||
if e.HasFeature(featureEnableMacroCallTracking) {
|
||||
prsrOpts = append(prsrOpts, parser.PopulateMacroCalls(true))
|
||||
@@ -434,9 +445,44 @@ func (e *Env) configure(opts []EnvOption) (*Env, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The simplest way to eagerly validate declarations on environment creation is to compile
|
||||
// a dummy program and check for the presence of e.chkErr being non-nil.
|
||||
if e.HasFeature(featureEagerlyValidateDeclarations) {
|
||||
err := e.initChecker()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (e *Env) initChecker() error {
|
||||
e.chkOnce.Do(func() {
|
||||
chkOpts := []checker.Option{}
|
||||
chkOpts = append(chkOpts, e.chkOpts...)
|
||||
chkOpts = append(chkOpts,
|
||||
checker.HomogeneousAggregateLiterals(
|
||||
e.HasFeature(featureDisableDynamicAggregateLiterals)),
|
||||
checker.CrossTypeNumericComparisons(
|
||||
e.HasFeature(featureCrossTypeNumericComparisons)))
|
||||
|
||||
ce, err := checker.NewEnv(e.Container, e.provider, chkOpts...)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
return
|
||||
}
|
||||
err = ce.Add(e.declarations...)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
return
|
||||
}
|
||||
e.chk = ce
|
||||
})
|
||||
return e.chkErr
|
||||
}
|
||||
|
||||
// Issues defines methods for inspecting the error details of parse and check calls.
|
||||
//
|
||||
// Note: in the future, non-fatal warnings and notices may be inspectable via the Issues struct.
|
||||
@@ -488,3 +534,17 @@ func (i *Issues) String() string {
|
||||
}
|
||||
return i.errs.ToDisplayString()
|
||||
}
|
||||
|
||||
// getStdEnv lazy initializes the CEL standard environment.
|
||||
func getStdEnv() (*Env, error) {
|
||||
stdEnvInit.Do(func() {
|
||||
stdEnv, stdEnvErr = NewCustomEnv(StdLib(), EagerlyValidateDeclarations(true))
|
||||
})
|
||||
return stdEnv, stdEnvErr
|
||||
}
|
||||
|
||||
var (
|
||||
stdEnvInit sync.Once
|
||||
stdEnv *Env
|
||||
stdEnvErr error
|
||||
)
|
||||
|
4
vendor/github.com/google/cel-go/cel/io.go
generated
vendored
4
vendor/github.com/google/cel-go/cel/io.go
generated
vendored
@@ -44,7 +44,7 @@ func CheckedExprToAst(checkedExpr *exprpb.CheckedExpr) *Ast {
|
||||
// through future calls.
|
||||
//
|
||||
// Prefer CheckedExprToAst if loading expressions from storage.
|
||||
func CheckedExprToAstWithSource(checkedExpr *exprpb.CheckedExpr, src common.Source) *Ast {
|
||||
func CheckedExprToAstWithSource(checkedExpr *exprpb.CheckedExpr, src Source) *Ast {
|
||||
refMap := checkedExpr.GetReferenceMap()
|
||||
if refMap == nil {
|
||||
refMap = map[int64]*exprpb.Reference{}
|
||||
@@ -96,7 +96,7 @@ func ParsedExprToAst(parsedExpr *exprpb.ParsedExpr) *Ast {
|
||||
// expression, or if you need to separately check a subset of an expression.
|
||||
//
|
||||
// Prefer ParsedExprToAst if loading expressions from storage.
|
||||
func ParsedExprToAstWithSource(parsedExpr *exprpb.ParsedExpr, src common.Source) *Ast {
|
||||
func ParsedExprToAstWithSource(parsedExpr *exprpb.ParsedExpr, src Source) *Ast {
|
||||
si := parsedExpr.GetSourceInfo()
|
||||
if si == nil {
|
||||
si = &exprpb.SourceInfo{}
|
||||
|
4
vendor/github.com/google/cel-go/cel/library.go
generated
vendored
4
vendor/github.com/google/cel-go/cel/library.go
generated
vendored
@@ -20,14 +20,14 @@ import (
|
||||
"github.com/google/cel-go/parser"
|
||||
)
|
||||
|
||||
// Library provides a collection of EnvOption and ProgramOption values used to confiugre a CEL
|
||||
// Library provides a collection of EnvOption and ProgramOption values used to configure a CEL
|
||||
// environment for a particular use case or with a related set of functionality.
|
||||
//
|
||||
// Note, the ProgramOption values provided by a library are expected to be static and not vary
|
||||
// between calls to Env.Program(). If there is a need for such dynamic configuration, prefer to
|
||||
// configure these options outside the Library and within the Env.Program() call directly.
|
||||
type Library interface {
|
||||
// CompileOptions returns a collection of funcitional options for configuring the Parse / Check
|
||||
// CompileOptions returns a collection of functional options for configuring the Parse / Check
|
||||
// environment.
|
||||
CompileOptions() []EnvOption
|
||||
|
||||
|
16
vendor/github.com/google/cel-go/cel/options.go
generated
vendored
16
vendor/github.com/google/cel-go/cel/options.go
generated
vendored
@@ -53,6 +53,10 @@ const (
|
||||
|
||||
// Enable the use of cross-type numeric comparisons at the type-checker.
|
||||
featureCrossTypeNumericComparisons
|
||||
|
||||
// Enable eager validation of declarations to ensure that Env values created
|
||||
// with `Extend` inherit a validated list of declarations from the parent Env.
|
||||
featureEagerlyValidateDeclarations
|
||||
)
|
||||
|
||||
// EnvOption is a functional interface for configuring the environment.
|
||||
@@ -103,6 +107,18 @@ func Declarations(decls ...*exprpb.Decl) EnvOption {
|
||||
}
|
||||
}
|
||||
|
||||
// EagerlyValidateDeclarations ensures that any collisions between configured declarations are caught
|
||||
// at the time of the `NewEnv` call.
|
||||
//
|
||||
// Eagerly validating declarations is also useful for bootstrapping a base `cel.Env` value.
|
||||
// Calls to base `Env.Extend()` will be significantly faster when declarations are eagerly validated
|
||||
// as declarations will be collision-checked at most once and only incrementally by way of `Extend`
|
||||
//
|
||||
// Disabled by default as not all environments are used for type-checking.
|
||||
func EagerlyValidateDeclarations(enabled bool) EnvOption {
|
||||
return features(featureEagerlyValidateDeclarations, enabled)
|
||||
}
|
||||
|
||||
// HomogeneousAggregateLiterals option ensures that list and map literal entry types must agree
|
||||
// during type-checking.
|
||||
//
|
||||
|
2
vendor/github.com/google/cel-go/cel/program.go
generated
vendored
2
vendor/github.com/google/cel-go/cel/program.go
generated
vendored
@@ -49,7 +49,7 @@ type Program interface {
|
||||
// to support cancellation and timeouts. This method must be used in conjunction with the
|
||||
// InterruptCheckFrequency() option for cancellation interrupts to be impact evaluation.
|
||||
//
|
||||
// The vars value may eitehr be an `interpreter.Activation` or `map[string]interface{}`.
|
||||
// The vars value may either be an `interpreter.Activation` or `map[string]interface{}`.
|
||||
//
|
||||
// The output contract for `ContextEval` is otherwise identical to the `Eval` method.
|
||||
ContextEval(context.Context, interface{}) (ref.Val, *EvalDetails, error)
|
||||
|
30
vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
30
vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
@@ -168,11 +168,9 @@ func (c *checker) checkSelect(e *exprpb.Expr) {
|
||||
if found {
|
||||
ident := c.env.LookupIdent(qname)
|
||||
if ident != nil {
|
||||
if sel.TestOnly {
|
||||
c.errors.expressionDoesNotSelectField(c.location(e))
|
||||
c.setType(e, decls.Bool)
|
||||
return
|
||||
}
|
||||
// We don't check for a TestOnly expression here since the `found` result is
|
||||
// always going to be false for TestOnly expressions.
|
||||
|
||||
// Rewrite the node to be a variable reference to the resolved fully-qualified
|
||||
// variable name.
|
||||
c.setType(e, ident.GetIdent().Type)
|
||||
@@ -208,7 +206,7 @@ func (c *checker) checkSelect(e *exprpb.Expr) {
|
||||
resultType = fieldType.Type
|
||||
}
|
||||
case kindTypeParam:
|
||||
// Set the operand type to DYN to prevent assignment to a potentionally incorrect type
|
||||
// Set the operand type to DYN to prevent assignment to a potentially incorrect type
|
||||
// at a later point in type-checking. The isAssignable call will update the type
|
||||
// substitutions for the type param under the covers.
|
||||
c.isAssignable(decls.Dyn, targetType)
|
||||
@@ -323,6 +321,12 @@ func (c *checker) resolveOverload(
|
||||
var resultType *exprpb.Type
|
||||
var checkedRef *exprpb.Reference
|
||||
for _, overload := range fn.GetFunction().Overloads {
|
||||
// Determine whether the overload is currently considered.
|
||||
if c.env.isOverloadDisabled(overload.GetOverloadId()) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure the call style for the overload matches.
|
||||
if (target == nil && overload.IsInstanceFunction) ||
|
||||
(target != nil && !overload.IsInstanceFunction) {
|
||||
// not a compatible call style.
|
||||
@@ -330,26 +334,26 @@ func (c *checker) resolveOverload(
|
||||
}
|
||||
|
||||
overloadType := decls.NewFunctionType(overload.ResultType, overload.Params...)
|
||||
if len(overload.TypeParams) > 0 {
|
||||
if len(overload.GetTypeParams()) > 0 {
|
||||
// Instantiate overload's type with fresh type variables.
|
||||
substitutions := newMapping()
|
||||
for _, typePar := range overload.TypeParams {
|
||||
for _, typePar := range overload.GetTypeParams() {
|
||||
substitutions.add(decls.NewTypeParamType(typePar), c.newTypeVar())
|
||||
}
|
||||
overloadType = substitute(substitutions, overloadType, false)
|
||||
}
|
||||
|
||||
candidateArgTypes := overloadType.GetFunction().ArgTypes
|
||||
candidateArgTypes := overloadType.GetFunction().GetArgTypes()
|
||||
if c.isAssignableList(argTypes, candidateArgTypes) {
|
||||
if checkedRef == nil {
|
||||
checkedRef = newFunctionReference(overload.OverloadId)
|
||||
checkedRef = newFunctionReference(overload.GetOverloadId())
|
||||
} else {
|
||||
checkedRef.OverloadId = append(checkedRef.OverloadId, overload.OverloadId)
|
||||
checkedRef.OverloadId = append(checkedRef.OverloadId, overload.GetOverloadId())
|
||||
}
|
||||
|
||||
// First matching overload, determines result type.
|
||||
fnResultType := substitute(c.mappings,
|
||||
overloadType.GetFunction().ResultType,
|
||||
overloadType.GetFunction().GetResultType(),
|
||||
false)
|
||||
if resultType == nil {
|
||||
resultType = fnResultType
|
||||
@@ -478,7 +482,7 @@ func (c *checker) checkComprehension(e *exprpb.Expr) {
|
||||
// Ranges over the keys.
|
||||
varType = rangeType.GetMapType().KeyType
|
||||
case kindDyn, kindError, kindTypeParam:
|
||||
// Set the range type to DYN to prevent assignment to a potentionally incorrect type
|
||||
// Set the range type to DYN to prevent assignment to a potentially incorrect type
|
||||
// at a later point in type-checking. The isAssignable call will update the type
|
||||
// substitutions for the type param under the covers.
|
||||
c.isAssignable(decls.Dyn, rangeType)
|
||||
|
10
vendor/github.com/google/cel-go/checker/cost.go
generated
vendored
10
vendor/github.com/google/cel-go/checker/cost.go
generated
vendored
@@ -121,7 +121,7 @@ type SizeEstimate struct {
|
||||
}
|
||||
|
||||
// Add adds to another SizeEstimate and returns the sum.
|
||||
// If add would result in an uint64 overflow, the result is Maxuint64.
|
||||
// If add would result in an uint64 overflow, the result is math.MaxUint64.
|
||||
func (se SizeEstimate) Add(sizeEstimate SizeEstimate) SizeEstimate {
|
||||
return SizeEstimate{
|
||||
addUint64NoOverflow(se.Min, sizeEstimate.Min),
|
||||
@@ -130,7 +130,7 @@ func (se SizeEstimate) Add(sizeEstimate SizeEstimate) SizeEstimate {
|
||||
}
|
||||
|
||||
// Multiply multiplies by another SizeEstimate and returns the product.
|
||||
// If multiply would result in an uint64 overflow, the result is Maxuint64.
|
||||
// If multiply would result in an uint64 overflow, the result is math.MaxUint64.
|
||||
func (se SizeEstimate) Multiply(sizeEstimate SizeEstimate) SizeEstimate {
|
||||
return SizeEstimate{
|
||||
multiplyUint64NoOverflow(se.Min, sizeEstimate.Min),
|
||||
@@ -148,7 +148,7 @@ func (se SizeEstimate) MultiplyByCostFactor(costPerUnit float64) CostEstimate {
|
||||
}
|
||||
|
||||
// MultiplyByCost multiplies by the cost and returns the product.
|
||||
// If multiply would result in an uint64 overflow, the result is Maxuint64.
|
||||
// If multiply would result in an uint64 overflow, the result is math.MaxUint64.
|
||||
func (se SizeEstimate) MultiplyByCost(cost CostEstimate) CostEstimate {
|
||||
return CostEstimate{
|
||||
multiplyUint64NoOverflow(se.Min, cost.Min),
|
||||
@@ -175,7 +175,7 @@ type CostEstimate struct {
|
||||
}
|
||||
|
||||
// Add adds the costs and returns the sum.
|
||||
// If add would result in an uint64 overflow for the min or max, the value is set to Maxuint64.
|
||||
// If add would result in an uint64 overflow for the min or max, the value is set to math.MaxUint64.
|
||||
func (ce CostEstimate) Add(cost CostEstimate) CostEstimate {
|
||||
return CostEstimate{
|
||||
addUint64NoOverflow(ce.Min, cost.Min),
|
||||
@@ -184,7 +184,7 @@ func (ce CostEstimate) Add(cost CostEstimate) CostEstimate {
|
||||
}
|
||||
|
||||
// Multiply multiplies by the cost and returns the product.
|
||||
// If multiply would result in an uint64 overflow, the result is Maxuint64.
|
||||
// If multiply would result in an uint64 overflow, the result is math.MaxUint64.
|
||||
func (ce CostEstimate) Multiply(cost CostEstimate) CostEstimate {
|
||||
return CostEstimate{
|
||||
multiplyUint64NoOverflow(ce.Min, cost.Min),
|
||||
|
36
vendor/github.com/google/cel-go/checker/decls/scopes.go
generated
vendored
36
vendor/github.com/google/cel-go/checker/decls/scopes.go
generated
vendored
@@ -33,6 +33,19 @@ func NewScopes() *Scopes {
|
||||
}
|
||||
}
|
||||
|
||||
// Copy creates a copy of the current Scopes values, including a copy of its parent if non-nil.
|
||||
func (s *Scopes) Copy() *Scopes {
|
||||
cpy := NewScopes()
|
||||
if s == nil {
|
||||
return cpy
|
||||
}
|
||||
if s.parent != nil {
|
||||
cpy.parent = s.parent.Copy()
|
||||
}
|
||||
cpy.scopes = s.scopes.copy()
|
||||
return cpy
|
||||
}
|
||||
|
||||
// Push creates a new Scopes value which references the current Scope as its parent.
|
||||
func (s *Scopes) Push() *Scopes {
|
||||
return &Scopes{
|
||||
@@ -80,9 +93,9 @@ func (s *Scopes) FindIdentInScope(name string) *exprpb.Decl {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddFunction adds the function Decl to the current scope.
|
||||
// SetFunction adds the function Decl to the current scope.
|
||||
// Note: Any previous entry for a function in the current scope with the same name is overwritten.
|
||||
func (s *Scopes) AddFunction(fn *exprpb.Decl) {
|
||||
func (s *Scopes) SetFunction(fn *exprpb.Decl) {
|
||||
s.scopes.functions[fn.Name] = fn
|
||||
}
|
||||
|
||||
@@ -100,13 +113,30 @@ func (s *Scopes) FindFunction(name string) *exprpb.Decl {
|
||||
}
|
||||
|
||||
// Group is a set of Decls that is pushed on or popped off a Scopes as a unit.
|
||||
// Contains separate namespaces for idenifier and function Decls.
|
||||
// Contains separate namespaces for identifier and function Decls.
|
||||
// (Should be named "Scope" perhaps?)
|
||||
type Group struct {
|
||||
idents map[string]*exprpb.Decl
|
||||
functions map[string]*exprpb.Decl
|
||||
}
|
||||
|
||||
// copy creates a new Group instance with a shallow copy of the variables and functions.
|
||||
// If callers need to mutate the exprpb.Decl definitions for a Function, they should copy-on-write.
|
||||
func (g *Group) copy() *Group {
|
||||
cpy := &Group{
|
||||
idents: make(map[string]*exprpb.Decl, len(g.idents)),
|
||||
functions: make(map[string]*exprpb.Decl, len(g.functions)),
|
||||
}
|
||||
for n, id := range g.idents {
|
||||
cpy.idents[n] = id
|
||||
}
|
||||
for n, fn := range g.functions {
|
||||
cpy.functions[n] = fn
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
// newGroup creates a new Group with empty maps for identifiers and functions.
|
||||
func newGroup() *Group {
|
||||
return &Group{
|
||||
idents: make(map[string]*exprpb.Decl),
|
||||
|
31
vendor/github.com/google/cel-go/checker/env.go
generated
vendored
31
vendor/github.com/google/cel-go/checker/env.go
generated
vendored
@@ -18,6 +18,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
@@ -99,6 +101,9 @@ func NewEnv(container *containers.Container, provider ref.TypeProvider, opts ...
|
||||
if envOptions.crossTypeNumericComparisons {
|
||||
filteredOverloadIDs = make(map[string]struct{})
|
||||
}
|
||||
if envOptions.validatedDeclarations != nil {
|
||||
declarations = envOptions.validatedDeclarations.Copy()
|
||||
}
|
||||
return &Env{
|
||||
container: container,
|
||||
provider: provider,
|
||||
@@ -117,7 +122,7 @@ func (e *Env) Add(decls ...*exprpb.Decl) error {
|
||||
case *exprpb.Decl_Ident:
|
||||
errMsgs = append(errMsgs, e.addIdent(sanitizeIdent(decl)))
|
||||
case *exprpb.Decl_Function:
|
||||
errMsgs = append(errMsgs, e.addFunction(sanitizeFunction(decl))...)
|
||||
errMsgs = append(errMsgs, e.setFunction(sanitizeFunction(decl))...)
|
||||
}
|
||||
}
|
||||
return formatError(errMsgs)
|
||||
@@ -204,22 +209,22 @@ func (e *Env) addOverload(f *exprpb.Decl, overload *exprpb.Decl_FunctionDecl_Ove
|
||||
return errMsgs
|
||||
}
|
||||
|
||||
// addFunction adds the function Decl to the Env.
|
||||
// setFunction adds the function Decl to the Env.
|
||||
// Adds a function decl if one doesn't already exist, then adds all overloads from the Decl.
|
||||
// If overload overlaps with an existing overload, adds to the errors in the Env instead.
|
||||
func (e *Env) addFunction(decl *exprpb.Decl) []errorMsg {
|
||||
func (e *Env) setFunction(decl *exprpb.Decl) []errorMsg {
|
||||
current := e.declarations.FindFunction(decl.Name)
|
||||
if current == nil {
|
||||
//Add the function declaration without overloads and check the overloads below.
|
||||
current = decls.NewFunction(decl.Name)
|
||||
e.declarations.AddFunction(current)
|
||||
} else {
|
||||
// Copy on write since we don't know where this original definition came from.
|
||||
current = proto.Clone(current).(*exprpb.Decl)
|
||||
}
|
||||
e.declarations.SetFunction(current)
|
||||
|
||||
errorMsgs := make([]errorMsg, 0)
|
||||
for _, overload := range decl.GetFunction().GetOverloads() {
|
||||
if _, found := e.filteredOverloadIDs[overload.GetOverloadId()]; found {
|
||||
continue
|
||||
}
|
||||
errorMsgs = append(errorMsgs, e.addOverload(current, overload)...)
|
||||
}
|
||||
return errorMsgs
|
||||
@@ -236,6 +241,12 @@ func (e *Env) addIdent(decl *exprpb.Decl) errorMsg {
|
||||
return ""
|
||||
}
|
||||
|
||||
// isOverloadDisabled returns whether the overloadID is disabled in the current environment.
|
||||
func (e *Env) isOverloadDisabled(overloadID string) bool {
|
||||
_, found := e.filteredOverloadIDs[overloadID]
|
||||
return found
|
||||
}
|
||||
|
||||
// sanitizeFunction replaces well-known types referenced by message name with their equivalent
|
||||
// CEL built-in type instances.
|
||||
func sanitizeFunction(decl *exprpb.Decl) *exprpb.Decl {
|
||||
@@ -313,6 +324,12 @@ func getObjectWellKnownType(t *exprpb.Type) *exprpb.Type {
|
||||
return pb.CheckedWellKnowns[t.GetMessageType()]
|
||||
}
|
||||
|
||||
// validatedDeclarations returns a reference to the validated variable and function declaration scope stack.
|
||||
// must be copied before use.
|
||||
func (e *Env) validatedDeclarations() *decls.Scopes {
|
||||
return e.declarations
|
||||
}
|
||||
|
||||
// enterScope creates a new Env instance with a new innermost declaration scope.
|
||||
func (e *Env) enterScope() *Env {
|
||||
childDecls := e.declarations.Push()
|
||||
|
4
vendor/github.com/google/cel-go/checker/errors.go
generated
vendored
4
vendor/github.com/google/cel-go/checker/errors.go
generated
vendored
@@ -29,10 +29,6 @@ func (e *typeErrors) undeclaredReference(l common.Location, container string, na
|
||||
e.ReportError(l, "undeclared reference to '%s' (in container '%s')", name, container)
|
||||
}
|
||||
|
||||
func (e *typeErrors) expressionDoesNotSelectField(l common.Location) {
|
||||
e.ReportError(l, "expression does not select a field")
|
||||
}
|
||||
|
||||
func (e *typeErrors) typeDoesNotSupportFieldSelection(l common.Location, t *exprpb.Type) {
|
||||
e.ReportError(l, "type '%s' does not support field selection", t)
|
||||
}
|
||||
|
12
vendor/github.com/google/cel-go/checker/options.go
generated
vendored
12
vendor/github.com/google/cel-go/checker/options.go
generated
vendored
@@ -14,9 +14,12 @@
|
||||
|
||||
package checker
|
||||
|
||||
import "github.com/google/cel-go/checker/decls"
|
||||
|
||||
type options struct {
|
||||
crossTypeNumericComparisons bool
|
||||
homogeneousAggregateLiterals bool
|
||||
validatedDeclarations *decls.Scopes
|
||||
}
|
||||
|
||||
// Option is a functional option for configuring the type-checker
|
||||
@@ -39,3 +42,12 @@ func HomogeneousAggregateLiterals(enabled bool) Option {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ValidatedDeclarations provides a references to validated declarations which will be copied
|
||||
// into new checker instances.
|
||||
func ValidatedDeclarations(env *Env) Option {
|
||||
return func(opts *options) error {
|
||||
opts.validatedDeclarations = env.validatedDeclarations()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
102
vendor/github.com/google/cel-go/checker/types.go
generated
vendored
102
vendor/github.com/google/cel-go/checker/types.go
generated
vendored
@@ -149,21 +149,6 @@ func isEqualOrLessSpecific(t1 *exprpb.Type, t2 *exprpb.Type) bool {
|
||||
}
|
||||
}
|
||||
return true
|
||||
case kindFunction:
|
||||
fn1 := t1.GetFunction()
|
||||
fn2 := t2.GetFunction()
|
||||
if len(fn1.ArgTypes) != len(fn2.ArgTypes) {
|
||||
return false
|
||||
}
|
||||
if !isEqualOrLessSpecific(fn1.ResultType, fn2.ResultType) {
|
||||
return false
|
||||
}
|
||||
for i, a1 := range fn1.ArgTypes {
|
||||
if !isEqualOrLessSpecific(a1, fn2.ArgTypes[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case kindList:
|
||||
return isEqualOrLessSpecific(t1.GetListType().ElemType, t2.GetListType().ElemType)
|
||||
case kindMap:
|
||||
@@ -180,43 +165,26 @@ func isEqualOrLessSpecific(t1 *exprpb.Type, t2 *exprpb.Type) bool {
|
||||
|
||||
/// internalIsAssignable returns true if t1 is assignable to t2.
|
||||
func internalIsAssignable(m *mapping, t1 *exprpb.Type, t2 *exprpb.Type) bool {
|
||||
// A type is always assignable to itself.
|
||||
// Early terminate the call to avoid cases of infinite recursion.
|
||||
if proto.Equal(t1, t2) {
|
||||
return true
|
||||
}
|
||||
// Process type parameters.
|
||||
kind1, kind2 := kindOf(t1), kindOf(t2)
|
||||
if kind2 == kindTypeParam {
|
||||
if t2Sub, found := m.find(t2); found {
|
||||
// If the types are compatible, pick the more general type and return true
|
||||
if !internalIsAssignable(m, t1, t2Sub) {
|
||||
return false
|
||||
}
|
||||
m.add(t2, mostGeneral(t1, t2Sub))
|
||||
// If t2 is a valid type substitution for t1, return true.
|
||||
valid, t2HasSub := isValidTypeSubstitution(m, t1, t2)
|
||||
if valid {
|
||||
return true
|
||||
}
|
||||
if notReferencedIn(m, t2, t1) {
|
||||
m.add(t2, t1)
|
||||
return true
|
||||
// If t2 is not a valid type sub for t1, and already has a known substitution return false
|
||||
// since it is not possible for t1 to be a substitution for t2.
|
||||
if !valid && t2HasSub {
|
||||
return false
|
||||
}
|
||||
// Otherwise, fall through to check whether t1 is a possible substitution for t2.
|
||||
}
|
||||
if kind1 == kindTypeParam {
|
||||
// For the lower type bound, we currently do not perform adjustment. The restricted
|
||||
// way we use type parameters in lower type bounds, it is not necessary, but may
|
||||
// become if we generalize type unification.
|
||||
if t1Sub, found := m.find(t1); found {
|
||||
// If the types are compatible, pick the more general type and return true
|
||||
if !internalIsAssignable(m, t1Sub, t2) {
|
||||
return false
|
||||
}
|
||||
m.add(t1, mostGeneral(t1Sub, t2))
|
||||
return true
|
||||
}
|
||||
if notReferencedIn(m, t1, t2) {
|
||||
m.add(t1, t2)
|
||||
return true
|
||||
}
|
||||
// Return whether t1 is a valid substitution for t2. If not, do no additional checks as the
|
||||
// possible type substitutions have been searched in both directions.
|
||||
valid, _ := isValidTypeSubstitution(m, t2, t1)
|
||||
return valid
|
||||
}
|
||||
|
||||
// Next check for wildcard types.
|
||||
@@ -262,18 +230,40 @@ func internalIsAssignable(m *mapping, t1 *exprpb.Type, t2 *exprpb.Type) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// isValidTypeSubstitution returns whether t2 (or its type substitution) is a valid type
|
||||
// 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) assignable to t1
|
||||
// - t2 does not occur within t1.
|
||||
func isValidTypeSubstitution(m *mapping, t1, t2 *exprpb.Type) (valid, hasSub bool) {
|
||||
if t2Sub, found := m.find(t2); found {
|
||||
kind1, kind2 := kindOf(t1), kindOf(t2)
|
||||
if kind1 == kind2 && proto.Equal(t1, t2Sub) {
|
||||
return true, true
|
||||
}
|
||||
// If the types are compatible, pick the more general type and return true
|
||||
if internalIsAssignable(m, t1, t2Sub) {
|
||||
m.add(t2, mostGeneral(t1, t2Sub))
|
||||
return true, true
|
||||
}
|
||||
return false, true
|
||||
}
|
||||
if notReferencedIn(m, t2, t1) {
|
||||
m.add(t2, t1)
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
// internalIsAssignableAbstractType returns true if the abstract type names agree and all type
|
||||
// parameters are assignable.
|
||||
func internalIsAssignableAbstractType(m *mapping,
|
||||
a1 *exprpb.Type_AbstractType,
|
||||
a2 *exprpb.Type_AbstractType) bool {
|
||||
if a1.GetName() != a2.GetName() {
|
||||
return false
|
||||
}
|
||||
if internalIsAssignableList(m, a1.GetParameterTypes(), a2.GetParameterTypes()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return a1.GetName() == a2.GetName() &&
|
||||
internalIsAssignableList(m, a1.GetParameterTypes(), a2.GetParameterTypes())
|
||||
}
|
||||
|
||||
// internalIsAssignableFunction returns true if the function return type and arg types are
|
||||
@@ -421,15 +411,6 @@ func notReferencedIn(m *mapping, t *exprpb.Type, withinType *exprpb.Type) bool {
|
||||
}
|
||||
}
|
||||
return true
|
||||
case kindFunction:
|
||||
fn := withinType.GetFunction()
|
||||
types := flattenFunctionTypes(fn)
|
||||
for _, a := range types {
|
||||
if !notReferencedIn(m, t, a) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case kindList:
|
||||
return notReferencedIn(m, t, withinType.GetListType().ElemType)
|
||||
case kindMap:
|
||||
@@ -454,7 +435,6 @@ func substitute(m *mapping, t *exprpb.Type, typeParamToDyn bool) *exprpb.Type {
|
||||
}
|
||||
switch kind {
|
||||
case kindAbstract:
|
||||
// TODO: implement!
|
||||
at := t.GetAbstractType()
|
||||
params := make([]*exprpb.Type, len(at.GetParameterTypes()))
|
||||
for i, p := range at.GetParameterTypes() {
|
||||
|
2
vendor/github.com/google/cel-go/common/location.go
generated
vendored
2
vendor/github.com/google/cel-go/common/location.go
generated
vendored
@@ -27,7 +27,7 @@ type SourceLocation struct {
|
||||
}
|
||||
|
||||
var (
|
||||
// Location implements the SourcceLocation interface.
|
||||
// Location implements the SourceLocation interface.
|
||||
_ Location = &SourceLocation{}
|
||||
// NoLocation is a particular illegal location.
|
||||
NoLocation = &SourceLocation{-1, -1}
|
||||
|
2
vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
2
vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
@@ -14,7 +14,7 @@
|
||||
|
||||
// Package operators defines the internal function names of operators.
|
||||
//
|
||||
// ALl operators in the expression language are modelled as function calls.
|
||||
// All operators in the expression language are modelled as function calls.
|
||||
package operators
|
||||
|
||||
// String "names" for CEL operators.
|
||||
|
1
vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
1
vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
@@ -73,6 +73,7 @@ go_test(
|
||||
"timestamp_test.go",
|
||||
"type_test.go",
|
||||
"uint_test.go",
|
||||
"util_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
|
13
vendor/github.com/google/cel-go/common/types/bool.go
generated
vendored
13
vendor/github.com/google/cel-go/common/types/bool.go
generated
vendored
@@ -130,12 +130,11 @@ func (b Bool) Value() interface{} {
|
||||
}
|
||||
|
||||
// IsBool returns whether the input ref.Val or ref.Type is equal to BoolType.
|
||||
func IsBool(elem interface{}) bool {
|
||||
switch elem := elem.(type) {
|
||||
case ref.Type:
|
||||
return elem == BoolType
|
||||
case ref.Val:
|
||||
return IsBool(elem.Type())
|
||||
func IsBool(elem ref.Val) bool {
|
||||
switch elem.(type) {
|
||||
case Bool:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
2
vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
2
vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
@@ -53,7 +53,7 @@ func (b Bytes) Add(other ref.Val) ref.Val {
|
||||
return append(b, otherBytes...)
|
||||
}
|
||||
|
||||
// Compare implments traits.Comparer interface method by lexicographic ordering.
|
||||
// Compare implements traits.Comparer interface method by lexicographic ordering.
|
||||
func (b Bytes) Compare(other ref.Val) ref.Val {
|
||||
otherBytes, ok := other.(Bytes)
|
||||
if !ok {
|
||||
|
6
vendor/github.com/google/cel-go/common/types/compare.go
generated
vendored
6
vendor/github.com/google/cel-go/common/types/compare.go
generated
vendored
@@ -16,6 +16,8 @@ package types
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
func compareDoubleInt(d Double, i Int) Int {
|
||||
@@ -74,7 +76,7 @@ func compareDouble(a, b Double) Int {
|
||||
return IntZero
|
||||
}
|
||||
|
||||
func compareInt(a, b Int) Int {
|
||||
func compareInt(a, b Int) ref.Val {
|
||||
if a < b {
|
||||
return IntNegOne
|
||||
}
|
||||
@@ -84,7 +86,7 @@ func compareInt(a, b Int) Int {
|
||||
return IntZero
|
||||
}
|
||||
|
||||
func compareUint(a, b Uint) Int {
|
||||
func compareUint(a, b Uint) ref.Val {
|
||||
if a < b {
|
||||
return IntNegOne
|
||||
}
|
||||
|
13
vendor/github.com/google/cel-go/common/types/err.go
generated
vendored
13
vendor/github.com/google/cel-go/common/types/err.go
generated
vendored
@@ -78,12 +78,10 @@ func ValOrErr(val ref.Val, format string, args ...interface{}) ref.Val {
|
||||
if val == nil {
|
||||
return NewErr(format, args...)
|
||||
}
|
||||
switch val.Type() {
|
||||
case ErrType, UnknownType:
|
||||
if IsUnknownOrError(val) {
|
||||
return val
|
||||
default:
|
||||
return NewErr(format, args...)
|
||||
}
|
||||
return NewErr(format, args...)
|
||||
}
|
||||
|
||||
// wrapErr wraps an existing Go error value into a CEL Err value.
|
||||
@@ -126,5 +124,10 @@ func (e *Err) Value() interface{} {
|
||||
// IsError returns whether the input element ref.Type or ref.Val is equal to
|
||||
// the ErrType singleton.
|
||||
func IsError(val ref.Val) bool {
|
||||
return val.Type() == ErrType
|
||||
switch val.(type) {
|
||||
case *Err:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
75
vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
75
vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
@@ -96,14 +96,16 @@ func NewJSONList(adapter ref.TypeAdapter, l *structpb.ListValue) traits.Lister {
|
||||
}
|
||||
|
||||
// NewMutableList creates a new mutable list whose internal state can be modified.
|
||||
//
|
||||
// The mutable list only handles `Add` calls correctly as it is intended only for use within
|
||||
// comprehension loops which generate an immutable result upon completion.
|
||||
func NewMutableList(adapter ref.TypeAdapter) traits.Lister {
|
||||
func NewMutableList(adapter ref.TypeAdapter) traits.MutableLister {
|
||||
var mutableValues []ref.Val
|
||||
return &mutableList{
|
||||
TypeAdapter: adapter,
|
||||
baseList: nil,
|
||||
mutableValues: []ref.Val{},
|
||||
baseList: &baseList{
|
||||
TypeAdapter: adapter,
|
||||
value: mutableValues,
|
||||
size: 0,
|
||||
get: func(i int) interface{} { return mutableValues[i] },
|
||||
},
|
||||
mutableValues: mutableValues,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,16 +240,14 @@ 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 {
|
||||
i, ok := index.(Int)
|
||||
if !ok {
|
||||
return ValOrErr(index, "unsupported index type '%s' in list", index.Type())
|
||||
ind, err := indexOrError(index)
|
||||
if err != nil {
|
||||
return ValOrErr(index, err.Error())
|
||||
}
|
||||
iv := int(i)
|
||||
if iv < 0 || iv >= l.size {
|
||||
return NewErr("index '%d' out of range in list size '%d'", i, l.Size())
|
||||
if ind < 0 || ind >= l.size {
|
||||
return NewErr("index '%d' out of range in list size '%d'", ind, l.Size())
|
||||
}
|
||||
elem := l.get(iv)
|
||||
return l.NativeToValue(elem)
|
||||
return l.NativeToValue(l.get(ind))
|
||||
}
|
||||
|
||||
// Iterator implements the traits.Iterable interface method.
|
||||
@@ -272,20 +272,25 @@ func (l *baseList) Value() interface{} {
|
||||
|
||||
// mutableList aggregates values into its internal storage. For use with internal CEL variables only.
|
||||
type mutableList struct {
|
||||
ref.TypeAdapter
|
||||
*baseList
|
||||
mutableValues []ref.Val
|
||||
}
|
||||
|
||||
// Add copies elements from the other list into the internal storage of the mutable list.
|
||||
// The ref.Val returned by Add is the receiver.
|
||||
func (l *mutableList) Add(other ref.Val) ref.Val {
|
||||
otherList, ok := other.(traits.Lister)
|
||||
if !ok {
|
||||
switch otherList := other.(type) {
|
||||
case *mutableList:
|
||||
l.mutableValues = append(l.mutableValues, otherList.mutableValues...)
|
||||
l.size += len(otherList.mutableValues)
|
||||
case traits.Lister:
|
||||
for i := IntZero; i < otherList.Size().(Int); i++ {
|
||||
l.size++
|
||||
l.mutableValues = append(l.mutableValues, otherList.Get(i))
|
||||
}
|
||||
default:
|
||||
return MaybeNoSuchOverloadErr(otherList)
|
||||
}
|
||||
for i := IntZero; i < otherList.Size().(Int); i++ {
|
||||
l.mutableValues = append(l.mutableValues, otherList.Get(i))
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
@@ -323,7 +328,7 @@ func (l *concatList) Add(other ref.Val) ref.Val {
|
||||
nextList: otherList}
|
||||
}
|
||||
|
||||
// Contains implments the traits.Container interface method.
|
||||
// Contains implements the traits.Container interface method.
|
||||
func (l *concatList) Contains(elem ref.Val) ref.Val {
|
||||
// The concat list relies on the IsErrorOrUnknown checks against the input element to be
|
||||
// performed by the `prevList` and/or `nextList`.
|
||||
@@ -391,10 +396,11 @@ 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 {
|
||||
i, ok := index.(Int)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(index)
|
||||
ind, err := indexOrError(index)
|
||||
if err != nil {
|
||||
return ValOrErr(index, err.Error())
|
||||
}
|
||||
i := Int(ind)
|
||||
if i < l.prevList.Size().(Int) {
|
||||
return l.prevList.Get(i)
|
||||
}
|
||||
@@ -462,3 +468,22 @@ func (it *listIterator) Next() ref.Val {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func indexOrError(index ref.Val) (int, error) {
|
||||
switch iv := index.(type) {
|
||||
case Int:
|
||||
return int(iv), nil
|
||||
case Double:
|
||||
if ik, ok := doubleToInt64Lossless(float64(iv)); ok {
|
||||
return int(ik), nil
|
||||
}
|
||||
return -1, fmt.Errorf("unsupported index value %v in list", index)
|
||||
case Uint:
|
||||
if ik, ok := uint64ToInt64Lossless(uint64(iv)); ok {
|
||||
return int(ik), nil
|
||||
}
|
||||
return -1, fmt.Errorf("unsupported index value %v in list", index)
|
||||
default:
|
||||
return -1, fmt.Errorf("unsupported index type '%s' in list", index.Type())
|
||||
}
|
||||
}
|
||||
|
4
vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
4
vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
@@ -105,7 +105,7 @@ var (
|
||||
// This interface implements portions of the API surface area required by the traits.Mapper
|
||||
// interface.
|
||||
type mapAccessor interface {
|
||||
// Find returns a value, if one exists, for the inpput key.
|
||||
// Find returns a value, if one exists, for the input key.
|
||||
//
|
||||
// If the key is not found the function returns (nil, false).
|
||||
Find(ref.Val) (ref.Val, bool)
|
||||
@@ -429,7 +429,7 @@ func (a *refValMapAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
case Double:
|
||||
if ik, ok := doubleToInt64Lossless(float64(k)); ok {
|
||||
if keyVal, found := a.mapVal[Int(ik)]; found {
|
||||
return keyVal, true
|
||||
return keyVal, found
|
||||
}
|
||||
}
|
||||
if uk, ok := doubleToUint64Lossless(float64(k)); ok {
|
||||
|
8
vendor/github.com/google/cel-go/common/types/overflow.go
generated
vendored
8
vendor/github.com/google/cel-go/common/types/overflow.go
generated
vendored
@@ -316,7 +316,7 @@ func doubleToUint64Checked(v float64) (uint64, error) {
|
||||
return uint64(v), nil
|
||||
}
|
||||
|
||||
// int64toUint64Checked converts an int64 to a uint64 value.
|
||||
// int64ToUint64Checked converts an int64 to a uint64 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func int64ToUint64Checked(v int64) (uint64, error) {
|
||||
@@ -326,7 +326,7 @@ func int64ToUint64Checked(v int64) (uint64, error) {
|
||||
return uint64(v), nil
|
||||
}
|
||||
|
||||
// int64toInt32Checked converts an int64 to an int32 value.
|
||||
// int64ToInt32Checked converts an int64 to an int32 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func int64ToInt32Checked(v int64) (int32, error) {
|
||||
@@ -336,7 +336,7 @@ func int64ToInt32Checked(v int64) (int32, error) {
|
||||
return int32(v), nil
|
||||
}
|
||||
|
||||
// uint64toUint32Checked converts a uint64 to a uint32 value.
|
||||
// uint64ToUint32Checked converts a uint64 to a uint32 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func uint64ToUint32Checked(v uint64) (uint32, error) {
|
||||
@@ -346,7 +346,7 @@ func uint64ToUint32Checked(v uint64) (uint32, error) {
|
||||
return uint32(v), nil
|
||||
}
|
||||
|
||||
// uint64toInt64Checked converts a uint64 to an int64 value.
|
||||
// uint64ToInt64Checked converts a uint64 to an int64 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func uint64ToInt64Checked(v uint64) (int64, error) {
|
||||
|
2
vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
2
vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
@@ -167,7 +167,7 @@ func (s String) Match(pattern ref.Val) ref.Val {
|
||||
return Bool(matched)
|
||||
}
|
||||
|
||||
// Receive implements traits.Reciever.Receive.
|
||||
// Receive implements traits.Receiver.Receive.
|
||||
func (s String) Receive(function string, overload string, args []ref.Val) ref.Val {
|
||||
switch len(args) {
|
||||
case 1:
|
||||
|
2
vendor/github.com/google/cel-go/common/types/timestamp.go
generated
vendored
2
vendor/github.com/google/cel-go/common/types/timestamp.go
generated
vendored
@@ -138,7 +138,7 @@ func (t Timestamp) Equal(other ref.Val) ref.Val {
|
||||
return Bool(ok && t.Time.Equal(otherTime.Time))
|
||||
}
|
||||
|
||||
// Receive implements traits.Reciever.Receive.
|
||||
// Receive implements traits.Receiver.Receive.
|
||||
func (t Timestamp) Receive(function string, overload string, args []ref.Val) ref.Val {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
|
1
vendor/github.com/google/cel-go/common/types/traits/lister.go
generated
vendored
1
vendor/github.com/google/cel-go/common/types/traits/lister.go
generated
vendored
@@ -28,5 +28,6 @@ type Lister interface {
|
||||
|
||||
// MutableLister interface which emits an immutable result after an intermediate computation.
|
||||
type MutableLister interface {
|
||||
Lister
|
||||
ToImmutableList() Lister
|
||||
}
|
||||
|
11
vendor/github.com/google/cel-go/common/types/unknown.go
generated
vendored
11
vendor/github.com/google/cel-go/common/types/unknown.go
generated
vendored
@@ -34,12 +34,12 @@ func (u Unknown) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
return u.Value(), nil
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
// ConvertToType is an identity function since unknown values cannot be modified.
|
||||
func (u Unknown) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
return u
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
// Equal is an identity function since unknown values cannot be modified.
|
||||
func (u Unknown) Equal(other ref.Val) ref.Val {
|
||||
return u
|
||||
}
|
||||
@@ -57,5 +57,10 @@ func (u Unknown) Value() interface{} {
|
||||
// IsUnknown returns whether the element ref.Type or ref.Val is equal to the
|
||||
// UnknownType singleton.
|
||||
func IsUnknown(val ref.Val) bool {
|
||||
return val.Type() == UnknownType
|
||||
switch val.(type) {
|
||||
case Unknown:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
6
vendor/github.com/google/cel-go/common/types/util.go
generated
vendored
6
vendor/github.com/google/cel-go/common/types/util.go
generated
vendored
@@ -18,10 +18,10 @@ import (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// IsUnknownOrError returns whether the input element ref.Val is an ErrType or UnknonwType.
|
||||
// IsUnknownOrError returns whether the input element ref.Val is an ErrType or UnknownType.
|
||||
func IsUnknownOrError(val ref.Val) bool {
|
||||
switch val.Type() {
|
||||
case UnknownType, ErrType:
|
||||
switch val.(type) {
|
||||
case Unknown, *Err:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
12
vendor/github.com/google/cel-go/interpreter/activation.go
generated
vendored
12
vendor/github.com/google/cel-go/interpreter/activation.go
generated
vendored
@@ -35,13 +35,17 @@ type Activation interface {
|
||||
Parent() Activation
|
||||
}
|
||||
|
||||
// EmptyActivation returns a variable free activation.
|
||||
// EmptyActivation returns a variable-free activation.
|
||||
func EmptyActivation() Activation {
|
||||
// This call cannot fail.
|
||||
a, _ := NewActivation(map[string]interface{}{})
|
||||
return a
|
||||
return emptyActivation{}
|
||||
}
|
||||
|
||||
// emptyActivation is a variable-free activation.
|
||||
type emptyActivation struct{}
|
||||
|
||||
func (emptyActivation) ResolveName(string) (interface{}, 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.
|
||||
//
|
||||
|
6
vendor/github.com/google/cel-go/interpreter/attribute_patterns.go
generated
vendored
6
vendor/github.com/google/cel-go/interpreter/attribute_patterns.go
generated
vendored
@@ -105,7 +105,7 @@ func (apat *AttributePattern) QualifierPatterns() []*AttributeQualifierPattern {
|
||||
return apat.qualifierPatterns
|
||||
}
|
||||
|
||||
// AttributeQualifierPattern holds a wilcard or valued qualifier pattern.
|
||||
// AttributeQualifierPattern holds a wildcard or valued qualifier pattern.
|
||||
type AttributeQualifierPattern struct {
|
||||
wildcard bool
|
||||
value interface{}
|
||||
@@ -125,7 +125,7 @@ func (qpat *AttributeQualifierPattern) Matches(q Qualifier) bool {
|
||||
// type, is equal to the value held in the Qualifier. This interface is used by the
|
||||
// AttributeQualifierPattern to determine pattern matches for non-wildcard qualifier patterns.
|
||||
//
|
||||
// Note: Attribute values are also Qualifier values; however, Attriutes are resolved before
|
||||
// Note: Attribute values are also Qualifier values; however, Attributes are resolved before
|
||||
// qualification happens. This is an implementation detail, but one relevant to why the Attribute
|
||||
// types do not surface in the list of implementations.
|
||||
//
|
||||
@@ -206,7 +206,7 @@ func (fac *partialAttributeFactory) AbsoluteAttribute(id int64, names ...string)
|
||||
}
|
||||
|
||||
// MaybeAttribute implementation of the AttributeFactory interface which ensure that the set of
|
||||
// 'maybe' NamespacedAttribute values are produced using the PartialAttributeFactory rather than
|
||||
// 'maybe' NamespacedAttribute values are produced using the partialAttributeFactory rather than
|
||||
// the base AttributeFactory implementation.
|
||||
func (fac *partialAttributeFactory) MaybeAttribute(id int64, name string) Attribute {
|
||||
return &maybeAttribute{
|
||||
|
4
vendor/github.com/google/cel-go/interpreter/attributes.go
generated
vendored
4
vendor/github.com/google/cel-go/interpreter/attributes.go
generated
vendored
@@ -587,7 +587,7 @@ func (a *relativeAttribute) Resolve(vars Activation) (interface{}, error) {
|
||||
if types.IsUnknown(v) {
|
||||
return v, nil
|
||||
}
|
||||
// Next, qualify it. Qualification handles unkonwns as well, so there's no need to recheck.
|
||||
// Next, qualify it. Qualification handles unknowns as well, so there's no need to recheck.
|
||||
var err error
|
||||
var obj interface{} = v
|
||||
for _, qual := range a.qualifiers {
|
||||
@@ -637,6 +637,8 @@ func newQualifier(adapter ref.TypeAdapter, id int64, v interface{}) (Qualifier,
|
||||
qual = &uintQualifier{id: id, value: uint64(val), celValue: val, adapter: adapter}
|
||||
case types.Bool:
|
||||
qual = &boolQualifier{id: id, value: bool(val), celValue: val, adapter: adapter}
|
||||
case types.Double:
|
||||
qual = &doubleQualifier{id: id, value: float64(val), celValue: val, adapter: adapter}
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid qualifier type: %T", v)
|
||||
}
|
||||
|
2
vendor/github.com/google/cel-go/interpreter/decorators.go
generated
vendored
2
vendor/github.com/google/cel-go/interpreter/decorators.go
generated
vendored
@@ -98,7 +98,7 @@ func decDisableShortcircuits() InterpretableDecorator {
|
||||
}
|
||||
|
||||
// decOptimize optimizes the program plan by looking for common evaluation patterns and
|
||||
// conditionally precomputating the result.
|
||||
// conditionally precomputing the result.
|
||||
// - build list and map values with constant elements.
|
||||
// - convert 'in' operations to set membership tests if possible.
|
||||
func decOptimize() InterpretableDecorator {
|
||||
|
18
vendor/github.com/google/cel-go/interpreter/interpretable.go
generated
vendored
18
vendor/github.com/google/cel-go/interpreter/interpretable.go
generated
vendored
@@ -677,7 +677,19 @@ func (m *evalMap) Eval(ctx Activation) ref.Val {
|
||||
}
|
||||
|
||||
func (m *evalMap) InitVals() []Interpretable {
|
||||
return append(m.keys, m.vals...)
|
||||
if len(m.keys) != len(m.vals) {
|
||||
return nil
|
||||
}
|
||||
result := make([]Interpretable, len(m.keys)+len(m.vals))
|
||||
idx := 0
|
||||
for i, k := range m.keys {
|
||||
v := m.vals[i]
|
||||
result[idx] = k
|
||||
idx++
|
||||
result[idx] = v
|
||||
idx++
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *evalMap) Type() ref.Type {
|
||||
@@ -852,7 +864,7 @@ func (fold *evalFold) Cost() (min, max int64) {
|
||||
iMax + aMax + cMax*rangeCnt + sMax*rangeCnt + rMax
|
||||
}
|
||||
|
||||
// Optional Intepretable implementations that specialize, subsume, or extend the core evaluation
|
||||
// Optional Interpretable implementations that specialize, subsume, or extend the core evaluation
|
||||
// plan via decorators.
|
||||
|
||||
// evalSetMembership is an Interpretable implementation which tests whether an input value
|
||||
@@ -969,7 +981,7 @@ func (e *evalWatchConstQual) Qualify(vars Activation, obj interface{}) (interfac
|
||||
return out, err
|
||||
}
|
||||
|
||||
// QualifierValueEquals tests whether the incoming value is equal to the qualificying constant.
|
||||
// QualifierValueEquals tests whether the incoming value is equal to the qualifying constant.
|
||||
func (e *evalWatchConstQual) QualifierValueEquals(value interface{}) bool {
|
||||
qve, ok := e.ConstantQualifier.(qualifierValueEquator)
|
||||
return ok && qve.QualifierValueEquals(value)
|
||||
|
2
vendor/github.com/google/cel-go/interpreter/interpreter.go
generated
vendored
2
vendor/github.com/google/cel-go/interpreter/interpreter.go
generated
vendored
@@ -162,7 +162,7 @@ type exprInterpreter struct {
|
||||
}
|
||||
|
||||
// NewInterpreter builds an Interpreter from a Dispatcher and TypeProvider which will be used
|
||||
// throughout the Eval of all Interpretable instances gerenated from it.
|
||||
// throughout the Eval of all Interpretable instances generated from it.
|
||||
func NewInterpreter(dispatcher Dispatcher,
|
||||
container *containers.Container,
|
||||
provider ref.TypeProvider,
|
||||
|
2
vendor/github.com/google/cel-go/interpreter/planner.go
generated
vendored
2
vendor/github.com/google/cel-go/interpreter/planner.go
generated
vendored
@@ -77,7 +77,7 @@ func newUncheckedPlanner(disp Dispatcher,
|
||||
}
|
||||
}
|
||||
|
||||
// planner is an implementatio of the interpretablePlanner interface.
|
||||
// planner is an implementation of the interpretablePlanner interface.
|
||||
type planner struct {
|
||||
disp Dispatcher
|
||||
provider ref.TypeProvider
|
||||
|
2
vendor/github.com/google/cel-go/interpreter/prune.go
generated
vendored
2
vendor/github.com/google/cel-go/interpreter/prune.go
generated
vendored
@@ -228,7 +228,7 @@ func (p *astPruner) prune(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// We have either an unknown/error value, or something we dont want to
|
||||
// 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.
|
||||
|
||||
|
87
vendor/github.com/google/cel-go/interpreter/runtimecost.go
generated
vendored
87
vendor/github.com/google/cel-go/interpreter/runtimecost.go
generated
vendored
@@ -41,26 +41,42 @@ func CostObserver(tracker *CostTracker) EvalObserver {
|
||||
case ConstantQualifier:
|
||||
// TODO: Push identifiers on to the stack before observing constant qualifiers that apply to them
|
||||
// and enable the below pop. Once enabled this can case can be collapsed into the Qualifier case.
|
||||
//tracker.stack.pop(1)
|
||||
tracker.cost++
|
||||
case InterpretableConst:
|
||||
// zero cost
|
||||
case InterpretableAttribute:
|
||||
// Ternary has no direct cost. All cost is from the conditional and the true/false branch expressions.
|
||||
_, isConditional := t.Attr().(*conditionalAttribute)
|
||||
if !isConditional {
|
||||
switch a := t.Attr().(type) {
|
||||
case *conditionalAttribute:
|
||||
// Ternary has no direct cost. All cost is from the conditional and the true/false branch expressions.
|
||||
tracker.stack.drop(a.falsy.ID(), a.truthy.ID(), a.expr.ID())
|
||||
default:
|
||||
tracker.stack.drop(t.Attr().ID())
|
||||
tracker.cost += common.SelectAndIdentCost
|
||||
}
|
||||
case *evalExhaustiveConditional, *evalOr, *evalAnd, *evalExhaustiveOr, *evalExhaustiveAnd:
|
||||
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())
|
||||
|
||||
// While the field names are identical, the boolean operation eval structs do not share an interface and so
|
||||
// must be handled individually.
|
||||
case *evalOr:
|
||||
tracker.stack.drop(t.rhs.ID(), t.lhs.ID())
|
||||
case *evalAnd:
|
||||
tracker.stack.drop(t.rhs.ID(), t.lhs.ID())
|
||||
case *evalExhaustiveOr:
|
||||
tracker.stack.drop(t.rhs.ID(), t.lhs.ID())
|
||||
case *evalExhaustiveAnd:
|
||||
tracker.stack.drop(t.rhs.ID(), t.lhs.ID())
|
||||
case *evalFold:
|
||||
tracker.stack.drop(t.iterRange.ID())
|
||||
case Qualifier:
|
||||
tracker.stack.pop(1)
|
||||
tracker.cost++
|
||||
case InterpretableCall:
|
||||
if argVals, ok := tracker.stack.pop(len(t.Args())); ok {
|
||||
if argVals, ok := tracker.stack.dropArgs(t.Args()); ok {
|
||||
tracker.cost += tracker.costCall(t, argVals, val)
|
||||
}
|
||||
case InterpretableConstructor:
|
||||
tracker.stack.dropArgs(t.InitVals())
|
||||
switch t.Type() {
|
||||
case types.ListType:
|
||||
tracker.cost += common.ListCreateBaseCost
|
||||
@@ -70,7 +86,7 @@ func CostObserver(tracker *CostTracker) EvalObserver {
|
||||
tracker.cost += common.StructCreateBaseCost
|
||||
}
|
||||
}
|
||||
tracker.stack.push(val)
|
||||
tracker.stack.push(val, id)
|
||||
|
||||
if tracker.Limit != nil && tracker.cost > *tracker.Limit {
|
||||
panic(EvalCancelledError{Cause: CostLimitExceeded, Message: "operation cancelled: actual cost limit exceeded"})
|
||||
@@ -170,19 +186,56 @@ func (c CostTracker) actualSize(value ref.Val) uint64 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// refValStack keeps track of values of the stack for cost calculation purposes
|
||||
type refValStack []ref.Val
|
||||
type stackVal struct {
|
||||
Val ref.Val
|
||||
ID int64
|
||||
}
|
||||
|
||||
func (s *refValStack) push(value ref.Val) {
|
||||
// refValStack keeps track of values of the stack for cost calculation purposes
|
||||
type refValStack []stackVal
|
||||
|
||||
func (s *refValStack) push(val ref.Val, id int64) {
|
||||
value := stackVal{Val: val, ID: id}
|
||||
*s = append(*s, value)
|
||||
}
|
||||
|
||||
func (s *refValStack) pop(count int) ([]ref.Val, bool) {
|
||||
if len(*s) < count {
|
||||
// TODO: Allowing drop and dropArgs to remove stack items above the IDs they are provided is a workaround. drop and dropArgs
|
||||
// should find and remove only the stack items matching the provided IDs once all attributes are properly pushed and popped from stack.
|
||||
|
||||
// drop searches the stack for each ID and removes the ID and all stack items above it.
|
||||
// If none of the IDs are found, the stack is not modified.
|
||||
// WARNING: It is possible for multiple expressions with the same ID to exist (due to how macros are implemented) so it's
|
||||
// possible that a dropped ID will remain on the stack. They should be removed when IDs on the stack are popped.
|
||||
func (s *refValStack) drop(ids ...int64) {
|
||||
for _, id := range ids {
|
||||
for idx := len(*s) - 1; idx >= 0; idx-- {
|
||||
if (*s)[idx].ID == id {
|
||||
*s = (*s)[:idx]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dropArgs searches the stack for all the args by their IDs, accumulates their associated ref.Vals and drops any
|
||||
// stack items above any of the arg IDs. If any of the IDs are not found the stack, false is returned.
|
||||
// Args are assumed to be found in the stack in reverse order, i.e. the last arg is expected to be found highest in
|
||||
// the stack.
|
||||
// WARNING: It is possible for multiple expressions with the same ID to exist (due to how macros are implemented) so it's
|
||||
// possible that a dropped ID will remain on the stack. They should be removed when IDs on the stack are popped.
|
||||
func (s *refValStack) dropArgs(args []Interpretable) ([]ref.Val, bool) {
|
||||
result := make([]ref.Val, len(args))
|
||||
argloop:
|
||||
for nIdx := len(args) - 1; nIdx >= 0; nIdx-- {
|
||||
for idx := len(*s) - 1; idx >= 0; idx-- {
|
||||
if (*s)[idx].ID == args[nIdx].ID() {
|
||||
el := (*s)[idx]
|
||||
*s = (*s)[:idx]
|
||||
result[nIdx] = el.Val
|
||||
continue argloop
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
idx := len(*s) - count
|
||||
el := (*s)[idx:]
|
||||
*s = (*s)[:idx]
|
||||
return el, true
|
||||
return result, true
|
||||
}
|
||||
|
Reference in New Issue
Block a user