mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-11-06 21:28:16 +00:00
Pin new dependency: github.com/google/cel-go v0.9.0
This commit is contained in:
202
vendor/github.com/google/cel-go/LICENSE
generated
vendored
Normal file
202
vendor/github.com/google/cel-go/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
64
vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
Normal file
64
vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cel.go",
|
||||
"env.go",
|
||||
"io.go",
|
||||
"library.go",
|
||||
"options.go",
|
||||
"program.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/cel",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//checker:go_default_library",
|
||||
"//checker/decls:go_default_library",
|
||||
"//common:go_default_library",
|
||||
"//common/containers:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/pb:go_default_library",
|
||||
"//common/types/ref:go_default_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_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protodesc:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protoregistry:go_default_library",
|
||||
"@org_golang_google_protobuf//types/descriptorpb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/dynamicpb:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"cel_test.go",
|
||||
],
|
||||
data = [
|
||||
"//cel/testdata:gen_test_fds",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
deps = [
|
||||
"//checker/decls:go_default_library",
|
||||
"//common/operators:go_default_library",
|
||||
"//common/overloads:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"//common/types/traits:go_default_library",
|
||||
"//interpreter/functions:go_default_library",
|
||||
"//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",
|
||||
],
|
||||
)
|
||||
19
vendor/github.com/google/cel-go/cel/cel.go
generated
vendored
Normal file
19
vendor/github.com/google/cel-go/cel/cel.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2019 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 cel defines the top-level interface for the Common Expression Language (CEL).
|
||||
//
|
||||
// CEL is a non-Turing complete expression language designed to parse, check, and evaluate
|
||||
// expressions against user-defined environments.
|
||||
package cel
|
||||
466
vendor/github.com/google/cel-go/cel/env.go
generated
vendored
Normal file
466
vendor/github.com/google/cel-go/cel/env.go
generated
vendored
Normal file
@@ -0,0 +1,466 @@
|
||||
// Copyright 2019 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 cel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/google/cel-go/checker"
|
||||
"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/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/interpreter"
|
||||
"github.com/google/cel-go/parser"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Source interface representing a user-provided expression.
|
||||
type Source interface {
|
||||
common.Source
|
||||
}
|
||||
|
||||
// Ast representing the checked or unchecked expression, its source, and related metadata such as
|
||||
// source position information.
|
||||
type Ast struct {
|
||||
expr *exprpb.Expr
|
||||
info *exprpb.SourceInfo
|
||||
source Source
|
||||
refMap map[int64]*exprpb.Reference
|
||||
typeMap map[int64]*exprpb.Type
|
||||
}
|
||||
|
||||
// Expr returns the proto serializable instance of the parsed/checked expression.
|
||||
func (ast *Ast) Expr() *exprpb.Expr {
|
||||
return ast.expr
|
||||
}
|
||||
|
||||
// IsChecked returns whether the Ast value has been successfully type-checked.
|
||||
func (ast *Ast) IsChecked() bool {
|
||||
return ast.typeMap != nil && len(ast.typeMap) > 0
|
||||
}
|
||||
|
||||
// SourceInfo returns character offset and newling position information about expression elements.
|
||||
func (ast *Ast) SourceInfo() *exprpb.SourceInfo {
|
||||
return ast.info
|
||||
}
|
||||
|
||||
// ResultType returns the output type of the expression if the Ast has been type-checked, else
|
||||
// returns decls.Dyn as the parse step cannot infer the type.
|
||||
func (ast *Ast) ResultType() *exprpb.Type {
|
||||
if !ast.IsChecked() {
|
||||
return decls.Dyn
|
||||
}
|
||||
return ast.typeMap[ast.expr.Id]
|
||||
}
|
||||
|
||||
// Source returns a view of the input used to create the Ast. This source may be complete or
|
||||
// constructed from the SourceInfo.
|
||||
func (ast *Ast) Source() Source {
|
||||
return ast.source
|
||||
}
|
||||
|
||||
// FormatType converts a type message into a string representation.
|
||||
func FormatType(t *exprpb.Type) string {
|
||||
return checker.FormatCheckedType(t)
|
||||
}
|
||||
|
||||
// Env encapsulates the context necessary to perform parsing, type checking, or generation of
|
||||
// evaluable programs for different expressions.
|
||||
type Env struct {
|
||||
Container *containers.Container
|
||||
declarations []*exprpb.Decl
|
||||
macros []parser.Macro
|
||||
adapter ref.TypeAdapter
|
||||
provider ref.TypeProvider
|
||||
features map[int]bool
|
||||
// program options tied to the environment.
|
||||
progOpts []ProgramOption
|
||||
|
||||
// Internal checker representation
|
||||
chk *checker.Env
|
||||
chkErr error
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
// NewEnv creates a program environment configured with the standard library of CEL functions and
|
||||
// macros. The Env value returned can parse and check any CEL program which builds upon the core
|
||||
// features documented in the CEL specification.
|
||||
//
|
||||
// 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...)
|
||||
}
|
||||
|
||||
// NewCustomEnv creates a custom program environment which is not automatically configured with the
|
||||
// standard library of functions and macros documented in the CEL spec.
|
||||
//
|
||||
// The purpose for using a custom environment might be for subsetting the standard library produced
|
||||
// by the cel.StdLib() function. Subsetting CEL is a core aspect of its design that allows users to
|
||||
// limit the compute and memory impact of a CEL program by controlling the functions and macros
|
||||
// that may appear in a given expression.
|
||||
//
|
||||
// See the EnvOption helper functions for the options that can be used to configure the
|
||||
// environment.
|
||||
func NewCustomEnv(opts ...EnvOption) (*Env, error) {
|
||||
registry, err := types.NewRegistry()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (&Env{
|
||||
declarations: []*exprpb.Decl{},
|
||||
macros: []parser.Macro{},
|
||||
Container: containers.DefaultContainer,
|
||||
adapter: registry,
|
||||
provider: registry,
|
||||
features: map[int]bool{},
|
||||
progOpts: []ProgramOption{},
|
||||
}).configure(opts)
|
||||
}
|
||||
|
||||
// Check performs type-checking on the input Ast and yields a checked Ast and/or set of Issues.
|
||||
//
|
||||
// Checking has failed if the returned Issues value and its Issues.Err() value are non-nil.
|
||||
// Issues should be inspected if they are non-nil, but may not represent a fatal error.
|
||||
//
|
||||
// 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) Check(ast *Ast) (*Ast, *Issues) {
|
||||
// Note, errors aren't currently possible on the Ast to ParsedExpr conversion.
|
||||
pe, _ := AstToParsedExpr(ast)
|
||||
|
||||
// Construct the internal checker env, erroring if there is an issue adding the declarations.
|
||||
e.once.Do(func() {
|
||||
ce := checker.NewEnv(e.Container, e.provider)
|
||||
ce.EnableDynamicAggregateLiterals(true)
|
||||
if e.HasFeature(FeatureDisableDynamicAggregateLiterals) {
|
||||
ce.EnableDynamicAggregateLiterals(false)
|
||||
}
|
||||
err := ce.Add(e.declarations...)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
} else {
|
||||
e.chk = ce
|
||||
}
|
||||
})
|
||||
// The once call will ensure that this value is set or nil for all invocations.
|
||||
if e.chkErr != nil {
|
||||
errs := common.NewErrors(ast.Source())
|
||||
errs.ReportError(common.NoLocation, e.chkErr.Error())
|
||||
return nil, NewIssues(errs)
|
||||
}
|
||||
|
||||
res, errs := checker.Check(pe, ast.Source(), e.chk)
|
||||
if len(errs.GetErrors()) > 0 {
|
||||
return nil, NewIssues(errs)
|
||||
}
|
||||
// Manually create the Ast to ensure that the Ast source information (which may be more
|
||||
// detailed than the information provided by Check), is returned to the caller.
|
||||
return &Ast{
|
||||
source: ast.Source(),
|
||||
expr: res.GetExpr(),
|
||||
info: res.GetSourceInfo(),
|
||||
refMap: res.GetReferenceMap(),
|
||||
typeMap: res.GetTypeMap()}, nil
|
||||
}
|
||||
|
||||
// Compile combines the Parse and Check phases CEL program compilation to produce an Ast and
|
||||
// associated issues.
|
||||
//
|
||||
// If an error is encountered during parsing the Compile step will not continue with the Check
|
||||
// phase. If non-error issues are encountered during Parse, they may be combined with any issues
|
||||
// discovered during Check.
|
||||
//
|
||||
// Note, for parse-only uses of CEL use Parse.
|
||||
func (e *Env) Compile(txt string) (*Ast, *Issues) {
|
||||
return e.CompileSource(common.NewTextSource(txt))
|
||||
}
|
||||
|
||||
// CompileSource combines the Parse and Check phases CEL program compilation to produce an Ast and
|
||||
// associated issues.
|
||||
//
|
||||
// If an error is encountered during parsing the CompileSource step will not continue with the
|
||||
// Check phase. If non-error issues are encountered during Parse, they may be combined with any
|
||||
// issues discovered during Check.
|
||||
//
|
||||
// Note, for parse-only uses of CEL use Parse.
|
||||
func (e *Env) CompileSource(src common.Source) (*Ast, *Issues) {
|
||||
ast, iss := e.ParseSource(src)
|
||||
if iss.Err() != nil {
|
||||
return nil, iss
|
||||
}
|
||||
checked, iss2 := e.Check(ast)
|
||||
iss = iss.Append(iss2)
|
||||
if iss.Err() != nil {
|
||||
return nil, iss
|
||||
}
|
||||
return checked, iss
|
||||
}
|
||||
|
||||
// Extend the current environment with additional options to produce a new Env.
|
||||
//
|
||||
// Note, the extended Env value should not share memory with the original. It is possible, however,
|
||||
// that a CustomTypeAdapter or CustomTypeProvider options could provide values which are mutable.
|
||||
// To ensure separation of state between extended environments either make sure the TypeAdapter and
|
||||
// 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
|
||||
}
|
||||
// Copy slices.
|
||||
decsCopy := make([]*exprpb.Decl, len(e.declarations))
|
||||
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)
|
||||
|
||||
// Copy the adapter / provider if they appear to be mutable.
|
||||
adapter := e.adapter
|
||||
provider := e.provider
|
||||
adapterReg, isAdapterReg := e.adapter.(ref.TypeRegistry)
|
||||
providerReg, isProviderReg := e.provider.(ref.TypeRegistry)
|
||||
// In most cases the provider and adapter will be a ref.TypeRegistry;
|
||||
// however, in the rare cases where they are not, they are assumed to
|
||||
// be immutable. Since it is possible to set the TypeProvider separately
|
||||
// from the TypeAdapter, the possible configurations which could use a
|
||||
// TypeRegistry as the base implementation are captured below.
|
||||
if isAdapterReg && isProviderReg {
|
||||
reg := providerReg.Copy()
|
||||
provider = reg
|
||||
// If the adapter and provider are the same object, set the adapter
|
||||
// to the same ref.TypeRegistry as the provider.
|
||||
if adapterReg == providerReg {
|
||||
adapter = reg
|
||||
} else {
|
||||
// Otherwise, make a copy of the adapter.
|
||||
adapter = adapterReg.Copy()
|
||||
}
|
||||
} else if isProviderReg {
|
||||
provider = providerReg.Copy()
|
||||
} else if isAdapterReg {
|
||||
adapter = adapterReg.Copy()
|
||||
}
|
||||
|
||||
featuresCopy := make(map[int]bool, len(e.features))
|
||||
for k, v := range e.features {
|
||||
featuresCopy[k] = v
|
||||
}
|
||||
|
||||
ext := &Env{
|
||||
Container: e.Container,
|
||||
declarations: decsCopy,
|
||||
macros: macsCopy,
|
||||
progOpts: progOptsCopy,
|
||||
adapter: adapter,
|
||||
features: featuresCopy,
|
||||
provider: provider,
|
||||
}
|
||||
return ext.configure(opts)
|
||||
}
|
||||
|
||||
// HasFeature checks whether the environment enables the given feature
|
||||
// flag, as enumerated in options.go.
|
||||
func (e *Env) HasFeature(flag int) bool {
|
||||
_, has := e.features[flag]
|
||||
return has
|
||||
}
|
||||
|
||||
// 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
|
||||
// ParseSource method.
|
||||
func (e *Env) Parse(txt string) (*Ast, *Issues) {
|
||||
src := common.NewTextSource(txt)
|
||||
return e.ParseSource(src)
|
||||
}
|
||||
|
||||
// ParseSource parses the input source to an Ast and/or set of Issues.
|
||||
//
|
||||
// Parsing has failed if the returned Issues value and its Issues.Err() value is non-nil.
|
||||
// Issues should be inspected if they are non-nil, but may not represent a fatal error.
|
||||
//
|
||||
// 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) {
|
||||
res, errs := parser.ParseWithMacros(src, e.macros)
|
||||
if len(errs.GetErrors()) > 0 {
|
||||
return nil, &Issues{errs: errs}
|
||||
}
|
||||
// Manually create the Ast to ensure that the text source information is propagated on
|
||||
// subsequent calls to Check.
|
||||
return &Ast{
|
||||
source: Source(src),
|
||||
expr: res.GetExpr(),
|
||||
info: res.GetSourceInfo()}, nil
|
||||
}
|
||||
|
||||
// Program generates an evaluable instance of the Ast within the environment (Env).
|
||||
func (e *Env) Program(ast *Ast, opts ...ProgramOption) (Program, error) {
|
||||
optSet := e.progOpts
|
||||
if len(opts) != 0 {
|
||||
mergedOpts := []ProgramOption{}
|
||||
mergedOpts = append(mergedOpts, e.progOpts...)
|
||||
mergedOpts = append(mergedOpts, opts...)
|
||||
optSet = mergedOpts
|
||||
}
|
||||
return newProgram(e, ast, optSet)
|
||||
}
|
||||
|
||||
// SetFeature sets the given feature flag, as enumerated in options.go.
|
||||
func (e *Env) SetFeature(flag int) {
|
||||
e.features[flag] = true
|
||||
}
|
||||
|
||||
// TypeAdapter returns the `ref.TypeAdapter` configured for the environment.
|
||||
func (e *Env) TypeAdapter() ref.TypeAdapter {
|
||||
return e.adapter
|
||||
}
|
||||
|
||||
// TypeProvider returns the `ref.TypeProvider` configured for the environment.
|
||||
func (e *Env) TypeProvider() ref.TypeProvider {
|
||||
return e.provider
|
||||
}
|
||||
|
||||
// UnknownVars returns an interpreter.PartialActivation which marks all variables
|
||||
// declared in the Env as unknown AttributePattern values.
|
||||
//
|
||||
// Note, the UnknownVars will behave the same as an interpreter.EmptyActivation
|
||||
// unless the PartialAttributes option is provided as a ProgramOption.
|
||||
func (e *Env) UnknownVars() interpreter.PartialActivation {
|
||||
var unknownPatterns []*interpreter.AttributePattern
|
||||
for _, d := range e.declarations {
|
||||
switch d.GetDeclKind().(type) {
|
||||
case *exprpb.Decl_Ident:
|
||||
unknownPatterns = append(unknownPatterns,
|
||||
interpreter.NewAttributePattern(d.GetName()))
|
||||
}
|
||||
}
|
||||
part, _ := PartialVars(
|
||||
interpreter.EmptyActivation(),
|
||||
unknownPatterns...)
|
||||
return part
|
||||
}
|
||||
|
||||
// ResidualAst takes an Ast and its EvalDetails to produce a new Ast which only contains the
|
||||
// attribute references which are unknown.
|
||||
//
|
||||
// Residual expressions are beneficial in a few scenarios:
|
||||
//
|
||||
// - Optimizing constant expression evaluations away.
|
||||
// - Indexing and pruning expressions based on known input arguments.
|
||||
// - Surfacing additional requirements that are needed in order to complete an evaluation.
|
||||
// - Sharing the evaluation of an expression across multiple machines/nodes.
|
||||
//
|
||||
// For example, if an expression targets a 'resource' and 'request' attribute and the possible
|
||||
// values for the resource are known, a PartialActivation could mark the 'request' as an unknown
|
||||
// interpreter.AttributePattern and the resulting ResidualAst would be reduced to only the parts
|
||||
// of the expression that reference the 'request'.
|
||||
//
|
||||
// Note, the expression ids within the residual AST generated through this method have no
|
||||
// correlation to the expression ids of the original AST.
|
||||
//
|
||||
// See the PartialVars helper for how to construct a 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}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsed, iss := e.Parse(expr)
|
||||
if iss != nil && iss.Err() != nil {
|
||||
return nil, iss.Err()
|
||||
}
|
||||
if !a.IsChecked() {
|
||||
return parsed, nil
|
||||
}
|
||||
checked, iss := e.Check(parsed)
|
||||
if iss != nil && iss.Err() != nil {
|
||||
return nil, iss.Err()
|
||||
}
|
||||
return checked, nil
|
||||
}
|
||||
|
||||
// configure applies a series of EnvOptions to the current environment.
|
||||
func (e *Env) configure(opts []EnvOption) (*Env, error) {
|
||||
// Customized the environment using the provided EnvOption values. If an error is
|
||||
// generated at any step this, will be returned as a nil Env with a non-nil error.
|
||||
var err error
|
||||
for _, opt := range opts {
|
||||
e, err = opt(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
type Issues struct {
|
||||
errs *common.Errors
|
||||
}
|
||||
|
||||
// NewIssues returns an Issues struct from a common.Errors object.
|
||||
func NewIssues(errs *common.Errors) *Issues {
|
||||
return &Issues{
|
||||
errs: errs,
|
||||
}
|
||||
}
|
||||
|
||||
// Err returns an error value if the issues list contains one or more errors.
|
||||
func (i *Issues) Err() error {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if len(i.Errors()) > 0 {
|
||||
return errors.New(i.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Errors returns the collection of errors encountered in more granular detail.
|
||||
func (i *Issues) Errors() []common.Error {
|
||||
if i == nil {
|
||||
return []common.Error{}
|
||||
}
|
||||
return i.errs.GetErrors()
|
||||
}
|
||||
|
||||
// Append collects the issues from another Issues struct into a new Issues object.
|
||||
func (i *Issues) Append(other *Issues) *Issues {
|
||||
if i == nil {
|
||||
return other
|
||||
}
|
||||
return NewIssues(i.errs.Append(other.errs.GetErrors()))
|
||||
}
|
||||
|
||||
// String converts the issues to a suitable display string.
|
||||
func (i *Issues) String() string {
|
||||
if i == nil {
|
||||
return ""
|
||||
}
|
||||
return i.errs.ToDisplayString()
|
||||
}
|
||||
122
vendor/github.com/google/cel-go/cel/io.go
generated
vendored
Normal file
122
vendor/github.com/google/cel-go/cel/io.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2019 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 cel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/parser"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// CheckedExprToAst converts a checked expression proto message to an Ast.
|
||||
func CheckedExprToAst(checkedExpr *exprpb.CheckedExpr) *Ast {
|
||||
return CheckedExprToAstWithSource(checkedExpr, nil)
|
||||
}
|
||||
|
||||
// CheckedExprToAstWithSource converts a checked expression proto message to an Ast,
|
||||
// using the provided Source as the textual contents.
|
||||
//
|
||||
// In general the source is not necessary unless the AST has been modified between the
|
||||
// `Parse` and `Check` calls as an `Ast` created from the `Parse` step will carry the source
|
||||
// through future calls.
|
||||
//
|
||||
// Prefer CheckedExprToAst if loading expressions from storage.
|
||||
func CheckedExprToAstWithSource(checkedExpr *exprpb.CheckedExpr, src common.Source) *Ast {
|
||||
refMap := checkedExpr.GetReferenceMap()
|
||||
if refMap == nil {
|
||||
refMap = map[int64]*exprpb.Reference{}
|
||||
}
|
||||
typeMap := checkedExpr.GetTypeMap()
|
||||
if typeMap == nil {
|
||||
typeMap = map[int64]*exprpb.Type{}
|
||||
}
|
||||
si := checkedExpr.GetSourceInfo()
|
||||
if si == nil {
|
||||
si = &exprpb.SourceInfo{}
|
||||
}
|
||||
if src == nil {
|
||||
src = common.NewInfoSource(si)
|
||||
}
|
||||
return &Ast{
|
||||
expr: checkedExpr.GetExpr(),
|
||||
info: si,
|
||||
source: src,
|
||||
refMap: refMap,
|
||||
typeMap: typeMap,
|
||||
}
|
||||
}
|
||||
|
||||
// AstToCheckedExpr converts an Ast to an protobuf CheckedExpr value.
|
||||
//
|
||||
// If the Ast.IsChecked() returns false, this conversion method will return an error.
|
||||
func AstToCheckedExpr(a *Ast) (*exprpb.CheckedExpr, error) {
|
||||
if !a.IsChecked() {
|
||||
return nil, fmt.Errorf("cannot convert unchecked ast")
|
||||
}
|
||||
return &exprpb.CheckedExpr{
|
||||
Expr: a.Expr(),
|
||||
SourceInfo: a.SourceInfo(),
|
||||
ReferenceMap: a.refMap,
|
||||
TypeMap: a.typeMap,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParsedExprToAst converts a parsed expression proto message to an Ast.
|
||||
func ParsedExprToAst(parsedExpr *exprpb.ParsedExpr) *Ast {
|
||||
return ParsedExprToAstWithSource(parsedExpr, nil)
|
||||
}
|
||||
|
||||
// ParsedExprToAstWithSource converts a parsed expression proto message to an Ast,
|
||||
// using the provided Source as the textual contents.
|
||||
//
|
||||
// In general you only need this if you need to recheck a previously checked
|
||||
// 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 {
|
||||
si := parsedExpr.GetSourceInfo()
|
||||
if si == nil {
|
||||
si = &exprpb.SourceInfo{}
|
||||
}
|
||||
if src == nil {
|
||||
src = common.NewInfoSource(si)
|
||||
}
|
||||
return &Ast{
|
||||
expr: parsedExpr.GetExpr(),
|
||||
info: si,
|
||||
source: src,
|
||||
}
|
||||
}
|
||||
|
||||
// AstToParsedExpr converts an Ast to an protobuf ParsedExpr value.
|
||||
func AstToParsedExpr(a *Ast) (*exprpb.ParsedExpr, error) {
|
||||
return &exprpb.ParsedExpr{
|
||||
Expr: a.Expr(),
|
||||
SourceInfo: a.SourceInfo(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AstToString converts an Ast back to a string if possible.
|
||||
//
|
||||
// Note, the conversion may not be an exact replica of the original expression, but will produce
|
||||
// a string that is semantically equivalent and whose textual representation is stable.
|
||||
func AstToString(a *Ast) (string, error) {
|
||||
expr := a.Expr()
|
||||
info := a.SourceInfo()
|
||||
return parser.Unparse(expr, info)
|
||||
}
|
||||
77
vendor/github.com/google/cel-go/cel/library.go
generated
vendored
Normal file
77
vendor/github.com/google/cel-go/cel/library.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright 2020 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 cel
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/checker"
|
||||
"github.com/google/cel-go/interpreter/functions"
|
||||
"github.com/google/cel-go/parser"
|
||||
)
|
||||
|
||||
// Library provides a collection of EnvOption and ProgramOption values used to confiugre 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
|
||||
// environment.
|
||||
CompileOptions() []EnvOption
|
||||
|
||||
// ProgramOptions returns a collection of functional options which should be included in every
|
||||
// Program generated from the Env.Program() call.
|
||||
ProgramOptions() []ProgramOption
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return func(e *Env) (*Env, error) {
|
||||
var err error
|
||||
for _, opt := range l.CompileOptions() {
|
||||
e, err = opt(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
e.progOpts = append(e.progOpts, l.ProgramOptions()...)
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// StdLib returns an EnvOption for the standard library of CEL functions and macros.
|
||||
func StdLib() EnvOption {
|
||||
return Lib(stdLibrary{})
|
||||
}
|
||||
|
||||
// stdLibrary implements the Library interface and provides functional options for the core CEL
|
||||
// features documented in the specification.
|
||||
type stdLibrary struct{}
|
||||
|
||||
// EnvOptions returns options for the standard CEL function declarations and macros.
|
||||
func (stdLibrary) CompileOptions() []EnvOption {
|
||||
return []EnvOption{
|
||||
Declarations(checker.StandardDeclarations()...),
|
||||
Macros(parser.AllMacros...),
|
||||
}
|
||||
}
|
||||
|
||||
// ProgramOptions returns function implementations for the standard CEL functions.
|
||||
func (stdLibrary) ProgramOptions() []ProgramOption {
|
||||
return []ProgramOption{
|
||||
Functions(functions.StandardOverloads()...),
|
||||
}
|
||||
}
|
||||
451
vendor/github.com/google/cel-go/cel/options.go
generated
vendored
Normal file
451
vendor/github.com/google/cel-go/cel/options.go
generated
vendored
Normal file
@@ -0,0 +1,451 @@
|
||||
// Copyright 2019 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 cel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/types/pb"
|
||||
"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"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protodesc"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
"google.golang.org/protobuf/types/dynamicpb"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
descpb "google.golang.org/protobuf/types/descriptorpb"
|
||||
)
|
||||
|
||||
// These constants beginning with "Feature" enable optional behavior in
|
||||
// the library. See the documentation for each constant to see its
|
||||
// effects, compatibility restrictions, and standard conformance.
|
||||
const (
|
||||
_ = iota
|
||||
|
||||
// Disallow heterogeneous aggregate (list, map) literals.
|
||||
// Note, it is still possible to have heterogeneous aggregates when
|
||||
// provided as variables to the expression, as well as via conversion
|
||||
// of well-known dynamic types, or with unchecked expressions.
|
||||
// Affects checking. Provides a subset of standard behavior.
|
||||
FeatureDisableDynamicAggregateLiterals
|
||||
)
|
||||
|
||||
// EnvOption is a functional interface for configuring the environment.
|
||||
type EnvOption func(e *Env) (*Env, error)
|
||||
|
||||
// ClearMacros options clears all parser macros.
|
||||
//
|
||||
// Clearing macros will ensure CEL expressions can only contain linear evaluation paths, as
|
||||
// comprehensions such as `all` and `exists` are enabled only via macros.
|
||||
func ClearMacros() EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.macros = parser.NoMacros
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CustomTypeAdapter swaps the default ref.TypeAdapter implementation with a custom one.
|
||||
//
|
||||
// Note: This option must be specified before the Types and TypeDescs options when used together.
|
||||
func CustomTypeAdapter(adapter ref.TypeAdapter) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.adapter = adapter
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CustomTypeProvider swaps the default ref.TypeProvider implementation with a custom one.
|
||||
//
|
||||
// Note: This option must be specified before the Types and TypeDescs options when used together.
|
||||
func CustomTypeProvider(provider ref.TypeProvider) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.provider = provider
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Declarations option extends the declaration set configured in the environment.
|
||||
//
|
||||
// Note: Declarations will by default be appended to the pre-existing declaration set configured
|
||||
// for the environment. The NewEnv call builds on top of the standard CEL declarations. For a
|
||||
// purely custom set of declarations use NewCustomEnv.
|
||||
func Declarations(decls ...*exprpb.Decl) EnvOption {
|
||||
// TODO: provide an alternative means of specifying declarations that doesn't refer
|
||||
// to the underlying proto implementations.
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.declarations = append(e.declarations, decls...)
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Features sets the given feature flags. See list of Feature constants above.
|
||||
func Features(flags ...int) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
for _, flag := range flags {
|
||||
e.SetFeature(flag)
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// HomogeneousAggregateLiterals option ensures that list and map literal entry types must agree
|
||||
// during type-checking.
|
||||
//
|
||||
// Note, it is still possible to have heterogeneous aggregates when provided as variables to the
|
||||
// expression, as well as via conversion of well-known dynamic types, or with unchecked
|
||||
// expressions.
|
||||
func HomogeneousAggregateLiterals() EnvOption {
|
||||
return Features(FeatureDisableDynamicAggregateLiterals)
|
||||
}
|
||||
|
||||
// Macros option extends the macro set configured in the environment.
|
||||
//
|
||||
// Note: This option must be specified after ClearMacros if used together.
|
||||
func Macros(macros ...parser.Macro) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.macros = append(e.macros, macros...)
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Container sets the container for resolving variable names. Defaults to an empty container.
|
||||
//
|
||||
// If all references within an expression are relative to a protocol buffer package, then
|
||||
// specifying a container of `google.type` would make it possible to write expressions such as
|
||||
// `Expr{expression: 'a < b'}` instead of having to write `google.type.Expr{...}`.
|
||||
func Container(name string) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
cont, err := e.Container.Extend(containers.Name(name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.Container = cont
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Abbrevs configures a set of simple names as abbreviations for fully-qualified names.
|
||||
//
|
||||
// An abbreviation (abbrev for short) is a simple name that expands to a fully-qualified name.
|
||||
// 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: ...}
|
||||
// }
|
||||
//
|
||||
// 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: ...}}
|
||||
//
|
||||
// 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`.
|
||||
// - The last element in the qualified name is the abbreviation.
|
||||
// - Abbreviations must not collide with each other.
|
||||
// - The abbreviation must not collide with unqualified names in use.
|
||||
//
|
||||
// Abbreviations are distinct from container-based references in the following important ways:
|
||||
// - Abbreviations must expand to a fully-qualified name.
|
||||
// - 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.
|
||||
// - 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.
|
||||
//
|
||||
// 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
|
||||
// preserved between compilations even as the container evolves.
|
||||
func Abbrevs(qualifiedNames ...string) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
cont, err := e.Container.Extend(containers.Abbrevs(qualifiedNames...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.Container = cont
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Types adds one or more type declarations to the environment, allowing for construction of
|
||||
// type-literals whose definitions are included in the common expression built-in set.
|
||||
//
|
||||
// The input types may either be instances of `proto.Message` or `ref.Type`. Any other type
|
||||
// provided to this option will result in an error.
|
||||
//
|
||||
// Well-known protobuf types within the `google.protobuf.*` package are included in the standard
|
||||
// environment by default.
|
||||
//
|
||||
// Note: This option must be specified after the CustomTypeProvider option when used together.
|
||||
func Types(addTypes ...interface{}) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
reg, isReg := e.provider.(ref.TypeRegistry)
|
||||
if !isReg {
|
||||
return nil, fmt.Errorf("custom types not supported by provider: %T", e.provider)
|
||||
}
|
||||
for _, t := range addTypes {
|
||||
switch v := t.(type) {
|
||||
case proto.Message:
|
||||
fdMap := pb.CollectFileDescriptorSet(v)
|
||||
for _, fd := range fdMap {
|
||||
err := reg.RegisterDescriptor(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case ref.Type:
|
||||
err := reg.RegisterType(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type: %T", t)
|
||||
}
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// TypeDescs adds type declarations from any protoreflect.FileDescriptor, protoregistry.Files,
|
||||
// google.protobuf.FileDescriptorProto or google.protobuf.FileDescriptorSet provided.
|
||||
//
|
||||
// Note that messages instantiated from these descriptors will be *dynamicpb.Message values
|
||||
// rather than the concrete message type.
|
||||
//
|
||||
// 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 {
|
||||
return func(e *Env) (*Env, error) {
|
||||
reg, isReg := e.provider.(ref.TypeRegistry)
|
||||
if !isReg {
|
||||
return nil, fmt.Errorf("custom types not supported by provider: %T", e.provider)
|
||||
}
|
||||
// Scan the input descriptors for FileDescriptorProto messages and accumulate them into a
|
||||
// synthetic FileDescriptorSet as the FileDescriptorProto messages may refer to each other
|
||||
// and will not resolve properly unless they are part of the same set.
|
||||
var fds *descpb.FileDescriptorSet
|
||||
for _, d := range descs {
|
||||
switch f := d.(type) {
|
||||
case *descpb.FileDescriptorProto:
|
||||
if fds == nil {
|
||||
fds = &descpb.FileDescriptorSet{
|
||||
File: []*descpb.FileDescriptorProto{},
|
||||
}
|
||||
}
|
||||
fds.File = append(fds.File, f)
|
||||
}
|
||||
}
|
||||
if fds != nil {
|
||||
if err := registerFileSet(reg, fds); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, d := range descs {
|
||||
switch f := d.(type) {
|
||||
case *protoregistry.Files:
|
||||
if err := registerFiles(reg, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case protoreflect.FileDescriptor:
|
||||
if err := reg.RegisterDescriptor(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case *descpb.FileDescriptorSet:
|
||||
if err := registerFileSet(reg, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case *descpb.FileDescriptorProto:
|
||||
// skip, handled as a synthetic file descriptor set.
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type descriptor: %T", d)
|
||||
}
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
func registerFileSet(reg ref.TypeRegistry, fileSet *descpb.FileDescriptorSet) error {
|
||||
files, err := protodesc.NewFiles(fileSet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("protodesc.NewFiles(%v) failed: %v", fileSet, err)
|
||||
}
|
||||
return registerFiles(reg, files)
|
||||
}
|
||||
|
||||
func registerFiles(reg ref.TypeRegistry, files *protoregistry.Files) error {
|
||||
var err error
|
||||
files.RangeFiles(func(fd protoreflect.FileDescriptor) bool {
|
||||
err = reg.RegisterDescriptor(fd)
|
||||
return err == nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// ProgramOption is a functional interface for configuring evaluation bindings and behaviors.
|
||||
type ProgramOption func(p *prog) (*prog, error)
|
||||
|
||||
// CustomDecorator appends an InterpreterDecorator to the program.
|
||||
//
|
||||
// InterpretableDecorators can be used to inspect, alter, or replace the Program plan.
|
||||
func CustomDecorator(dec interpreter.InterpretableDecorator) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
p.decorators = append(p.decorators, dec)
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Functions adds function overloads that extend or override the set of CEL built-ins.
|
||||
func Functions(funcs ...*functions.Overload) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
if err := p.dispatcher.Add(funcs...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Globals sets the global variable values for a given program. These values may be shadowed by
|
||||
// variables with the same name provided to the Eval() call.
|
||||
//
|
||||
// The vars value may either be an `interpreter.Activation` instance or a `map[string]interface{}`.
|
||||
func Globals(vars interface{}) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
defaultVars, err :=
|
||||
interpreter.NewActivation(vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.defaultVars = defaultVars
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
// EvalOption indicates an evaluation option that may affect the evaluation behavior or information
|
||||
// in the output result.
|
||||
type EvalOption int
|
||||
|
||||
const (
|
||||
// OptTrackState will cause the runtime to return an immutable EvalState value in the Result.
|
||||
OptTrackState EvalOption = 1 << iota
|
||||
|
||||
// OptExhaustiveEval causes the runtime to disable short-circuits and track state.
|
||||
OptExhaustiveEval EvalOption = 1<<iota | OptTrackState
|
||||
|
||||
// OptOptimize precomputes functions and operators with constants as arguments at program
|
||||
// creation time. This flag is useful when the expression will be evaluated repeatedly against
|
||||
// a series of different inputs.
|
||||
OptOptimize EvalOption = 1 << iota
|
||||
|
||||
// OptPartialEval enables the evaluation of a partial state where the input data that may be
|
||||
// known to be missing, either as top-level variables, or somewhere within a variable's object
|
||||
// member graph.
|
||||
//
|
||||
// By itself, OptPartialEval does not change evaluation behavior unless the input to the
|
||||
// Program Eval is an PartialVars.
|
||||
OptPartialEval EvalOption = 1 << iota
|
||||
)
|
||||
|
||||
// EvalOptions sets one or more evaluation options which may affect the evaluation or Result.
|
||||
func EvalOptions(opts ...EvalOption) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
for _, opt := range opts {
|
||||
p.evalOpts |= opt
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
func fieldToCELType(field protoreflect.FieldDescriptor) (*exprpb.Type, error) {
|
||||
if field.Kind() == protoreflect.MessageKind {
|
||||
msgName := (string)(field.Message().FullName())
|
||||
wellKnownType, found := pb.CheckedWellKnowns[msgName]
|
||||
if found {
|
||||
return wellKnownType, nil
|
||||
}
|
||||
return decls.NewObjectType(msgName), nil
|
||||
}
|
||||
if primitiveType, found := pb.CheckedPrimitives[field.Kind()]; found {
|
||||
return primitiveType, nil
|
||||
}
|
||||
if field.Kind() == protoreflect.EnumKind {
|
||||
return decls.Int, nil
|
||||
}
|
||||
return nil, fmt.Errorf("field %s type %s not implemented", field.FullName(), field.Kind().String())
|
||||
}
|
||||
|
||||
func fieldToDecl(field protoreflect.FieldDescriptor) (*exprpb.Decl, error) {
|
||||
name := string(field.Name())
|
||||
if field.IsMap() {
|
||||
mapKey := field.MapKey()
|
||||
mapValue := field.MapValue()
|
||||
keyType, err := fieldToCELType(mapKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valueType, err := fieldToCELType(mapValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decls.NewVar(name, decls.NewMapType(keyType, valueType)), nil
|
||||
} else if field.IsList() {
|
||||
elemType, err := fieldToCELType(field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decls.NewVar(name, decls.NewListType(elemType)), nil
|
||||
} else {
|
||||
celType, err := fieldToCELType(field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decls.NewVar(name, celType), nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeclareContextProto returns an option to extend CEL environment with declarations from the given context proto.
|
||||
// Each field of the proto defines a variable of the same name in the environment.
|
||||
// https://github.com/google/cel-spec/blob/master/doc/langdef.md#evaluation-environment
|
||||
func DeclareContextProto(descriptor protoreflect.MessageDescriptor) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
var decls []*exprpb.Decl
|
||||
fields := descriptor.Fields()
|
||||
for i := 0; i < fields.Len(); i++ {
|
||||
field := fields.Get(i)
|
||||
decl, err := fieldToDecl(field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decls = append(decls, decl)
|
||||
}
|
||||
var err error
|
||||
e, err = Declarations(decls...)(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Types(dynamicpb.NewMessage(descriptor))(e)
|
||||
}
|
||||
}
|
||||
318
vendor/github.com/google/cel-go/cel/program.go
generated
vendored
Normal file
318
vendor/github.com/google/cel-go/cel/program.go
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
// Copyright 2019 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 cel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"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{}`.
|
||||
//
|
||||
// If the `OptTrackState` or `OptExhaustiveEval` flags are used, the `details` response will
|
||||
// be non-nil. Given this caveat on `details`, the return state from evaluation will be:
|
||||
//
|
||||
// * `val`, `details`, `nil` - Successful evaluation of a non-error result.
|
||||
// * `val`, `details`, `err` - Successful evaluation to an error result.
|
||||
// * `nil`, `details`, `err` - Unsuccessful evaluation.
|
||||
//
|
||||
// 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(vars interface{}) (ref.Val, *EvalDetails, error)
|
||||
}
|
||||
|
||||
// NoVars returns an empty Activation.
|
||||
func NoVars() interpreter.Activation {
|
||||
return interpreter.EmptyActivation()
|
||||
}
|
||||
|
||||
// PartialVars returns a PartialActivation which contains variables and a set of AttributePattern
|
||||
// values that indicate variables or parts of variables whose value are not yet known.
|
||||
//
|
||||
// The `vars` value may either be an interpreter.Activation or any valid input to the
|
||||
// interpreter.NewActivation call.
|
||||
func PartialVars(vars interface{},
|
||||
unknowns ...*interpreter.AttributePattern) (interpreter.PartialActivation, error) {
|
||||
return interpreter.NewPartialActivation(vars, unknowns...)
|
||||
}
|
||||
|
||||
// AttributePattern returns an AttributePattern that matches a top-level variable. The pattern is
|
||||
// mutable, and its methods support the specification of one or more qualifier patterns.
|
||||
//
|
||||
// For example, the AttributePattern(`a`).QualString(`b`) represents a variable access `a` with a
|
||||
// string field or index qualification `b`. This pattern will match Attributes `a`, and `a.b`,
|
||||
// but not `a.c`.
|
||||
//
|
||||
// When using a CEL expression within a container, e.g. a package or namespace, the variable name
|
||||
// in the pattern must match the qualified name produced during the variable namespace resolution.
|
||||
// For example, when variable `a` is declared within an expression whose container is `ns.app`, the
|
||||
// fully qualified variable name may be `ns.app.a`, `ns.a`, or `a` per the CEL namespace resolution
|
||||
// rules. Pick the fully qualified variable name that makes sense within the container as the
|
||||
// AttributePattern `varName` argument.
|
||||
//
|
||||
// See the interpreter.AttributePattern and interpreter.AttributeQualifierPattern for more info
|
||||
// about how to create and manipulate AttributePattern values.
|
||||
func AttributePattern(varName string) *interpreter.AttributePattern {
|
||||
return interpreter.NewAttributePattern(varName)
|
||||
}
|
||||
|
||||
// EvalDetails holds additional information observed during the Eval() call.
|
||||
type EvalDetails struct {
|
||||
state interpreter.EvalState
|
||||
}
|
||||
|
||||
// State of the evaluation, non-nil if the OptTrackState or OptExhaustiveEval is specified
|
||||
// within EvalOptions.
|
||||
func (ed *EvalDetails) State() interpreter.EvalState {
|
||||
return ed.state
|
||||
}
|
||||
|
||||
// prog is the internal implementation of the Program interface.
|
||||
type prog struct {
|
||||
*Env
|
||||
evalOpts EvalOption
|
||||
decorators []interpreter.InterpretableDecorator
|
||||
defaultVars interpreter.Activation
|
||||
dispatcher interpreter.Dispatcher
|
||||
interpreter interpreter.Interpreter
|
||||
interpretable interpreter.Interpretable
|
||||
attrFactory interpreter.AttributeFactory
|
||||
}
|
||||
|
||||
// progFactory is a helper alias for marking a program creation factory function.
|
||||
type progFactory func(interpreter.EvalState) (Program, error)
|
||||
|
||||
// progGen holds a reference to a progFactory instance and implements the Program interface.
|
||||
type progGen struct {
|
||||
factory progFactory
|
||||
}
|
||||
|
||||
// newProgram creates a program instance with an environment, an ast, and an optional list of
|
||||
// ProgramOption values.
|
||||
//
|
||||
// If the program cannot be configured the prog will be nil, with a non-nil error response.
|
||||
func newProgram(e *Env, ast *Ast, opts []ProgramOption) (Program, error) {
|
||||
// Build the dispatcher, interpreter, and default program value.
|
||||
disp := interpreter.NewDispatcher()
|
||||
|
||||
// Ensure the default attribute factory is set after the adapter and provider are
|
||||
// configured.
|
||||
p := &prog{
|
||||
Env: e,
|
||||
decorators: []interpreter.InterpretableDecorator{},
|
||||
dispatcher: disp,
|
||||
}
|
||||
|
||||
// Configure the program via the ProgramOption values.
|
||||
var err error
|
||||
for _, opt := range opts {
|
||||
if opt == nil {
|
||||
return nil, fmt.Errorf("program options should be non-nil")
|
||||
}
|
||||
p, err = opt(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Set the attribute factory after the options have been set.
|
||||
if p.evalOpts&OptPartialEval == OptPartialEval {
|
||||
p.attrFactory = interpreter.NewPartialAttributeFactory(e.Container, e.adapter, e.provider)
|
||||
} else {
|
||||
p.attrFactory = interpreter.NewAttributeFactory(e.Container, e.adapter, e.provider)
|
||||
}
|
||||
|
||||
interp := interpreter.NewInterpreter(disp, e.Container, e.provider, e.adapter, p.attrFactory)
|
||||
p.interpreter = interp
|
||||
|
||||
// Translate the EvalOption flags into InterpretableDecorator instances.
|
||||
decorators := make([]interpreter.InterpretableDecorator, len(p.decorators))
|
||||
copy(decorators, p.decorators)
|
||||
|
||||
// Enable constant folding first.
|
||||
if p.evalOpts&OptOptimize == OptOptimize {
|
||||
decorators = append(decorators, interpreter.Optimize())
|
||||
}
|
||||
// Enable exhaustive eval over state tracking since it offers a superset of features.
|
||||
if p.evalOpts&OptExhaustiveEval == OptExhaustiveEval {
|
||||
// State tracking requires that each Eval() call operate on an isolated EvalState
|
||||
// object; hence, the presence of the factory.
|
||||
factory := func(state interpreter.EvalState) (Program, error) {
|
||||
decs := append(decorators, interpreter.ExhaustiveEval(state))
|
||||
clone := &prog{
|
||||
evalOpts: p.evalOpts,
|
||||
defaultVars: p.defaultVars,
|
||||
Env: e,
|
||||
dispatcher: disp,
|
||||
interpreter: interp}
|
||||
return initInterpretable(clone, ast, decs)
|
||||
}
|
||||
return initProgGen(factory)
|
||||
}
|
||||
// Enable state tracking last since it too requires the factory approach but is less
|
||||
// featured than the ExhaustiveEval decorator.
|
||||
if p.evalOpts&OptTrackState == OptTrackState {
|
||||
factory := func(state interpreter.EvalState) (Program, error) {
|
||||
decs := append(decorators, interpreter.TrackState(state))
|
||||
clone := &prog{
|
||||
evalOpts: p.evalOpts,
|
||||
defaultVars: p.defaultVars,
|
||||
Env: e,
|
||||
dispatcher: disp,
|
||||
interpreter: interp}
|
||||
return initInterpretable(clone, ast, decs)
|
||||
}
|
||||
return initProgGen(factory)
|
||||
}
|
||||
return initInterpretable(p, ast, decorators)
|
||||
}
|
||||
|
||||
// initProgGen tests the factory object by calling it once and returns a factory-based Program if
|
||||
// the test is successful.
|
||||
func initProgGen(factory progFactory) (Program, error) {
|
||||
// Test the factory to make sure that configuration errors are spotted at config
|
||||
_, err := factory(interpreter.NewEvalState())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &progGen{factory: factory}, nil
|
||||
}
|
||||
|
||||
// initIterpretable creates a checked or unchecked interpretable depending on whether the Ast
|
||||
// has been run through the type-checker.
|
||||
func initInterpretable(
|
||||
p *prog,
|
||||
ast *Ast,
|
||||
decorators []interpreter.InterpretableDecorator) (Program, error) {
|
||||
var err error
|
||||
// Unchecked programs do not contain type and reference information and may be
|
||||
// slower to execute than their checked counterparts.
|
||||
if !ast.IsChecked() {
|
||||
p.interpretable, err =
|
||||
p.interpreter.NewUncheckedInterpretable(ast.Expr(), decorators...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
// When the AST has been checked it contains metadata that can be used to speed up program
|
||||
// execution.
|
||||
var checked *exprpb.CheckedExpr
|
||||
checked, err = AstToCheckedExpr(ast)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.interpretable, err = p.interpreter.NewInterpretable(checked, decorators...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Eval implements the Program interface method.
|
||||
func (p *prog) Eval(input interface{}) (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.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("internal error: %v", r)
|
||||
}
|
||||
}()
|
||||
// Build a hierarchical activation if there are default vars set.
|
||||
vars, err := interpreter.NewActivation(input)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if p.defaultVars != nil {
|
||||
vars = interpreter.NewHierarchicalActivation(p.defaultVars, vars)
|
||||
}
|
||||
v = p.interpretable.Eval(vars)
|
||||
// The output of an internal Eval may have a value (`v`) that is a types.Err. This step
|
||||
// translates the CEL value to a Go error response. This interface does not quite match the
|
||||
// RPC signature which allows for multiple errors to be returned, but should be sufficient.
|
||||
if types.IsError(v) {
|
||||
err = v.(*types.Err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (p *prog) Cost() (min, max int64) {
|
||||
return estimateCost(p.interpretable)
|
||||
}
|
||||
|
||||
// Eval implements the Program interface method.
|
||||
func (gen *progGen) Eval(input interface{}) (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.
|
||||
state := interpreter.NewEvalState()
|
||||
det := &EvalDetails{state: state}
|
||||
|
||||
// Generate a new instance of the interpretable using the factory configured during the call to
|
||||
// newProgram(). It is incredibly unlikely that the factory call will generate an error given
|
||||
// the factory test performed within the Program() call.
|
||||
p, err := gen.factory(state)
|
||||
if err != nil {
|
||||
return nil, det, err
|
||||
}
|
||||
|
||||
// Evaluate the input, returning the result and the 'state' within EvalDetails.
|
||||
v, _, err := p.Eval(input)
|
||||
if err != nil {
|
||||
return v, det, err
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
return 0, math.MaxInt64
|
||||
}
|
||||
return estimateCost(p)
|
||||
}
|
||||
|
||||
var (
|
||||
emptyEvalState = interpreter.NewEvalState()
|
||||
)
|
||||
|
||||
// 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()
|
||||
}
|
||||
57
vendor/github.com/google/cel-go/checker/BUILD.bazel
generated
vendored
Normal file
57
vendor/github.com/google/cel-go/checker/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"checker.go",
|
||||
"env.go",
|
||||
"errors.go",
|
||||
"mapping.go",
|
||||
"printer.go",
|
||||
"standard.go",
|
||||
"types.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/checker",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//checker/decls:go_default_library",
|
||||
"//common:go_default_library",
|
||||
"//common/containers:go_default_library",
|
||||
"//common/debug:go_default_library",
|
||||
"//common/operators: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",
|
||||
"//parser: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",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"checker_test.go",
|
||||
"env_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
deps = [
|
||||
"//common/types:go_default_library",
|
||||
"//parser:go_default_library",
|
||||
"//test:go_default_library",
|
||||
"//test/proto2pb:go_default_library",
|
||||
"//test/proto3pb:go_default_library",
|
||||
"@com_github_antlr//runtime/Go/antlr:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
642
vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
Normal file
642
vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
Normal file
@@ -0,0 +1,642 @@
|
||||
// Copyright 2018 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 checker defines functions to type-checked a parsed expression
|
||||
// against a set of identifier and function declarations.
|
||||
package checker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"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/types/ref"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
type checker struct {
|
||||
env *Env
|
||||
errors *typeErrors
|
||||
mappings *mapping
|
||||
freeTypeVarCounter int
|
||||
sourceInfo *exprpb.SourceInfo
|
||||
types map[int64]*exprpb.Type
|
||||
references map[int64]*exprpb.Reference
|
||||
}
|
||||
|
||||
// Check performs type checking, giving a typed AST.
|
||||
// The input is a ParsedExpr proto and an env which encapsulates
|
||||
// type binding of variables, declarations of built-in functions,
|
||||
// descriptions of protocol buffers, and a registry for errors.
|
||||
// Returns a CheckedExpr proto, which might not be usable if
|
||||
// there are errors in the error registry.
|
||||
func Check(parsedExpr *exprpb.ParsedExpr,
|
||||
source common.Source,
|
||||
env *Env) (*exprpb.CheckedExpr, *common.Errors) {
|
||||
c := checker{
|
||||
env: env,
|
||||
errors: &typeErrors{common.NewErrors(source)},
|
||||
mappings: newMapping(),
|
||||
freeTypeVarCounter: 0,
|
||||
sourceInfo: parsedExpr.GetSourceInfo(),
|
||||
types: make(map[int64]*exprpb.Type),
|
||||
references: make(map[int64]*exprpb.Reference),
|
||||
}
|
||||
c.check(parsedExpr.GetExpr())
|
||||
|
||||
// Walk over the final type map substituting any type parameters either by their bound value or
|
||||
// by DYN.
|
||||
m := make(map[int64]*exprpb.Type)
|
||||
for k, v := range c.types {
|
||||
m[k] = substitute(c.mappings, v, true)
|
||||
}
|
||||
|
||||
return &exprpb.CheckedExpr{
|
||||
Expr: parsedExpr.GetExpr(),
|
||||
SourceInfo: parsedExpr.GetSourceInfo(),
|
||||
TypeMap: m,
|
||||
ReferenceMap: c.references,
|
||||
}, c.errors.Errors
|
||||
}
|
||||
|
||||
func (c *checker) check(e *exprpb.Expr) {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch e.ExprKind.(type) {
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
literal := e.GetConstExpr()
|
||||
switch literal.ConstantKind.(type) {
|
||||
case *exprpb.Constant_BoolValue:
|
||||
c.checkBoolLiteral(e)
|
||||
case *exprpb.Constant_BytesValue:
|
||||
c.checkBytesLiteral(e)
|
||||
case *exprpb.Constant_DoubleValue:
|
||||
c.checkDoubleLiteral(e)
|
||||
case *exprpb.Constant_Int64Value:
|
||||
c.checkInt64Literal(e)
|
||||
case *exprpb.Constant_NullValue:
|
||||
c.checkNullLiteral(e)
|
||||
case *exprpb.Constant_StringValue:
|
||||
c.checkStringLiteral(e)
|
||||
case *exprpb.Constant_Uint64Value:
|
||||
c.checkUint64Literal(e)
|
||||
}
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
c.checkIdent(e)
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
c.checkSelect(e)
|
||||
case *exprpb.Expr_CallExpr:
|
||||
c.checkCall(e)
|
||||
case *exprpb.Expr_ListExpr:
|
||||
c.checkCreateList(e)
|
||||
case *exprpb.Expr_StructExpr:
|
||||
c.checkCreateStruct(e)
|
||||
case *exprpb.Expr_ComprehensionExpr:
|
||||
c.checkComprehension(e)
|
||||
default:
|
||||
c.errors.ReportError(
|
||||
c.location(e), "Unrecognized ast type: %v", reflect.TypeOf(e))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *checker) checkInt64Literal(e *exprpb.Expr) {
|
||||
c.setType(e, decls.Int)
|
||||
}
|
||||
|
||||
func (c *checker) checkUint64Literal(e *exprpb.Expr) {
|
||||
c.setType(e, decls.Uint)
|
||||
}
|
||||
|
||||
func (c *checker) checkStringLiteral(e *exprpb.Expr) {
|
||||
c.setType(e, decls.String)
|
||||
}
|
||||
|
||||
func (c *checker) checkBytesLiteral(e *exprpb.Expr) {
|
||||
c.setType(e, decls.Bytes)
|
||||
}
|
||||
|
||||
func (c *checker) checkDoubleLiteral(e *exprpb.Expr) {
|
||||
c.setType(e, decls.Double)
|
||||
}
|
||||
|
||||
func (c *checker) checkBoolLiteral(e *exprpb.Expr) {
|
||||
c.setType(e, decls.Bool)
|
||||
}
|
||||
|
||||
func (c *checker) checkNullLiteral(e *exprpb.Expr) {
|
||||
c.setType(e, decls.Null)
|
||||
}
|
||||
|
||||
func (c *checker) checkIdent(e *exprpb.Expr) {
|
||||
identExpr := e.GetIdentExpr()
|
||||
// Check to see if the identifier is declared.
|
||||
if ident := c.env.LookupIdent(identExpr.GetName()); ident != nil {
|
||||
c.setType(e, ident.GetIdent().Type)
|
||||
c.setReference(e, newIdentReference(ident.GetName(), ident.GetIdent().Value))
|
||||
// Overwrite the identifier with its fully qualified name.
|
||||
identExpr.Name = ident.GetName()
|
||||
return
|
||||
}
|
||||
|
||||
c.setType(e, decls.Error)
|
||||
c.errors.undeclaredReference(
|
||||
c.location(e), c.env.container.Name(), identExpr.GetName())
|
||||
}
|
||||
|
||||
func (c *checker) checkSelect(e *exprpb.Expr) {
|
||||
sel := e.GetSelectExpr()
|
||||
// Before traversing down the tree, try to interpret as qualified name.
|
||||
qname, found := containers.ToQualifiedName(e)
|
||||
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
|
||||
}
|
||||
// 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))
|
||||
identName := ident.GetName()
|
||||
e.ExprKind = &exprpb.Expr_IdentExpr{
|
||||
IdentExpr: &exprpb.Expr_Ident{
|
||||
Name: identName,
|
||||
},
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Interpret as field selection, first traversing down the operand.
|
||||
c.check(sel.Operand)
|
||||
targetType := c.getType(sel.Operand)
|
||||
// Assume error type by default as most types do not support field selection.
|
||||
resultType := decls.Error
|
||||
switch kindOf(targetType) {
|
||||
case kindMap:
|
||||
// Maps yield their value type as the selection result type.
|
||||
mapType := targetType.GetMapType()
|
||||
resultType = mapType.ValueType
|
||||
case kindObject:
|
||||
// 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.Field); found {
|
||||
resultType = fieldType.Type
|
||||
}
|
||||
case kindTypeParam:
|
||||
// Set the operand type to DYN to prevent assignment to a potentionally 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)
|
||||
// Also, set the result type to DYN.
|
||||
resultType = decls.Dyn
|
||||
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 {
|
||||
c.errors.typeDoesNotSupportFieldSelection(c.location(e), targetType)
|
||||
}
|
||||
}
|
||||
if sel.TestOnly {
|
||||
resultType = decls.Bool
|
||||
}
|
||||
c.setType(e, resultType)
|
||||
}
|
||||
|
||||
func (c *checker) checkCall(e *exprpb.Expr) {
|
||||
// Note: similar logic exists within the `interpreter/planner.go`. If making changes here
|
||||
// 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()
|
||||
|
||||
// Traverse arguments.
|
||||
for _, arg := range args {
|
||||
c.check(arg)
|
||||
}
|
||||
|
||||
// Regular static call with simple name.
|
||||
if target == nil {
|
||||
// Check for the existence of the function.
|
||||
fn := c.env.LookupFunction(fnName)
|
||||
if fn == nil {
|
||||
c.errors.undeclaredReference(
|
||||
c.location(e), c.env.container.Name(), fnName)
|
||||
c.setType(e, decls.Error)
|
||||
return
|
||||
}
|
||||
// Overwrite the function name with its fully qualified resolved name.
|
||||
call.Function = fn.GetName()
|
||||
// Check to see whether the overload resolves.
|
||||
c.resolveOverloadOrError(c.location(e), e, fn, nil, args)
|
||||
return
|
||||
}
|
||||
|
||||
// If a receiver 'target' is present, it may either be a receiver function, or a namespaced
|
||||
// function, but not both. Given a.b.c() either a.b.c is a function or c is a function with
|
||||
// target a.b.
|
||||
//
|
||||
// Check whether the target is a namespaced function name.
|
||||
qualifiedPrefix, maybeQualified := containers.ToQualifiedName(target)
|
||||
if maybeQualified {
|
||||
maybeQualifiedName := qualifiedPrefix + "." + fnName
|
||||
fn := c.env.LookupFunction(maybeQualifiedName)
|
||||
if fn != nil {
|
||||
// The function name is namespaced and so preserving the target operand would
|
||||
// be an inaccurate representation of the desired evaluation behavior.
|
||||
// Overwrite with fully-qualified resolved function name sans receiver target.
|
||||
call.Target = nil
|
||||
call.Function = fn.GetName()
|
||||
c.resolveOverloadOrError(c.location(e), e, fn, nil, args)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Regular instance call.
|
||||
c.check(call.Target)
|
||||
fn := c.env.LookupFunction(fnName)
|
||||
// Function found, attempt overload resolution.
|
||||
if fn != nil {
|
||||
c.resolveOverloadOrError(c.location(e), e, fn, target, args)
|
||||
return
|
||||
}
|
||||
// Function name not declared, record error.
|
||||
c.errors.undeclaredReference(c.location(e), c.env.container.Name(), fnName)
|
||||
}
|
||||
|
||||
func (c *checker) resolveOverloadOrError(
|
||||
loc common.Location,
|
||||
e *exprpb.Expr,
|
||||
fn *exprpb.Decl, target *exprpb.Expr, args []*exprpb.Expr) {
|
||||
// Attempt to resolve the overload.
|
||||
resolution := c.resolveOverload(loc, fn, target, args)
|
||||
// No such overload, error noted in the resolveOverload call, type recorded here.
|
||||
if resolution == nil {
|
||||
c.setType(e, decls.Error)
|
||||
return
|
||||
}
|
||||
// Overload found.
|
||||
c.setType(e, resolution.Type)
|
||||
c.setReference(e, resolution.Reference)
|
||||
}
|
||||
|
||||
func (c *checker) resolveOverload(
|
||||
loc common.Location,
|
||||
fn *exprpb.Decl, target *exprpb.Expr, args []*exprpb.Expr) *overloadResolution {
|
||||
|
||||
var argTypes []*exprpb.Type
|
||||
if target != nil {
|
||||
argTypes = append(argTypes, c.getType(target))
|
||||
}
|
||||
for _, arg := range args {
|
||||
argTypes = append(argTypes, c.getType(arg))
|
||||
}
|
||||
|
||||
var resultType *exprpb.Type
|
||||
var checkedRef *exprpb.Reference
|
||||
for _, overload := range fn.GetFunction().Overloads {
|
||||
if (target == nil && overload.IsInstanceFunction) ||
|
||||
(target != nil && !overload.IsInstanceFunction) {
|
||||
// not a compatible call style.
|
||||
continue
|
||||
}
|
||||
|
||||
overloadType := decls.NewFunctionType(overload.ResultType, overload.Params...)
|
||||
if len(overload.TypeParams) > 0 {
|
||||
// Instantiate overload's type with fresh type variables.
|
||||
substitutions := newMapping()
|
||||
for _, typePar := range overload.TypeParams {
|
||||
substitutions.add(decls.NewTypeParamType(typePar), c.newTypeVar())
|
||||
}
|
||||
overloadType = substitute(substitutions, overloadType, false)
|
||||
}
|
||||
|
||||
candidateArgTypes := overloadType.GetFunction().ArgTypes
|
||||
if c.isAssignableList(argTypes, candidateArgTypes) {
|
||||
if checkedRef == nil {
|
||||
checkedRef = newFunctionReference(overload.OverloadId)
|
||||
} else {
|
||||
checkedRef.OverloadId = append(checkedRef.OverloadId, overload.OverloadId)
|
||||
}
|
||||
|
||||
// First matching overload, determines result type.
|
||||
fnResultType := substitute(c.mappings,
|
||||
overloadType.GetFunction().ResultType,
|
||||
false)
|
||||
if resultType == nil {
|
||||
resultType = fnResultType
|
||||
} else if !isDyn(resultType) && !proto.Equal(fnResultType, resultType) {
|
||||
resultType = decls.Dyn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if resultType == nil {
|
||||
c.errors.noMatchingOverload(loc, fn.GetName(), argTypes, target != nil)
|
||||
resultType = decls.Error
|
||||
return nil
|
||||
}
|
||||
|
||||
return newResolution(checkedRef, resultType)
|
||||
}
|
||||
|
||||
func (c *checker) checkCreateList(e *exprpb.Expr) {
|
||||
create := e.GetListExpr()
|
||||
var elemType *exprpb.Type
|
||||
for _, e := range create.Elements {
|
||||
c.check(e)
|
||||
elemType = c.joinTypes(c.location(e), elemType, c.getType(e))
|
||||
}
|
||||
if elemType == nil {
|
||||
// If the list is empty, assign free type var to elem type.
|
||||
elemType = c.newTypeVar()
|
||||
}
|
||||
c.setType(e, decls.NewListType(elemType))
|
||||
}
|
||||
|
||||
func (c *checker) checkCreateStruct(e *exprpb.Expr) {
|
||||
str := e.GetStructExpr()
|
||||
if str.MessageName != "" {
|
||||
c.checkCreateMessage(e)
|
||||
} else {
|
||||
c.checkCreateMap(e)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *checker) checkCreateMap(e *exprpb.Expr) {
|
||||
mapVal := e.GetStructExpr()
|
||||
var keyType *exprpb.Type
|
||||
var valueType *exprpb.Type
|
||||
for _, ent := range mapVal.GetEntries() {
|
||||
key := ent.GetMapKey()
|
||||
c.check(key)
|
||||
keyType = c.joinTypes(c.location(key), keyType, c.getType(key))
|
||||
|
||||
c.check(ent.Value)
|
||||
valueType = c.joinTypes(c.location(ent.Value), valueType, c.getType(ent.Value))
|
||||
}
|
||||
if keyType == nil {
|
||||
// If the map is empty, assign free type variables to typeKey and value type.
|
||||
keyType = c.newTypeVar()
|
||||
valueType = c.newTypeVar()
|
||||
}
|
||||
c.setType(e, decls.NewMapType(keyType, valueType))
|
||||
}
|
||||
|
||||
func (c *checker) checkCreateMessage(e *exprpb.Expr) {
|
||||
msgVal := e.GetStructExpr()
|
||||
// Determine the type of the message.
|
||||
messageType := decls.Error
|
||||
decl := c.env.LookupIdent(msgVal.MessageName)
|
||||
if decl == nil {
|
||||
c.errors.undeclaredReference(
|
||||
c.location(e), c.env.container.Name(), msgVal.MessageName)
|
||||
return
|
||||
}
|
||||
// Ensure the type name is fully qualified in the AST.
|
||||
msgVal.MessageName = decl.GetName()
|
||||
c.setReference(e, newIdentReference(decl.GetName(), nil))
|
||||
ident := decl.GetIdent()
|
||||
identKind := kindOf(ident.Type)
|
||||
if identKind != kindError {
|
||||
if identKind != kindType {
|
||||
c.errors.notAType(c.location(e), ident.Type)
|
||||
} else {
|
||||
messageType = ident.Type.GetType()
|
||||
if kindOf(messageType) != kindObject {
|
||||
c.errors.notAMessageType(c.location(e), messageType)
|
||||
messageType = decls.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
if isObjectWellKnownType(messageType) {
|
||||
c.setType(e, getObjectWellKnownType(messageType))
|
||||
} else {
|
||||
c.setType(e, messageType)
|
||||
}
|
||||
|
||||
// Check the field initializers.
|
||||
for _, ent := range msgVal.GetEntries() {
|
||||
field := ent.GetFieldKey()
|
||||
value := ent.Value
|
||||
c.check(value)
|
||||
|
||||
fieldType := decls.Error
|
||||
if t, found := c.lookupFieldType(
|
||||
c.locationByID(ent.Id),
|
||||
messageType.GetMessageType(),
|
||||
field); found {
|
||||
fieldType = t.Type
|
||||
}
|
||||
if !c.isAssignable(fieldType, c.getType(value)) {
|
||||
c.errors.fieldTypeMismatch(
|
||||
c.locationByID(ent.Id), field, fieldType, c.getType(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *checker) checkComprehension(e *exprpb.Expr) {
|
||||
comp := e.GetComprehensionExpr()
|
||||
c.check(comp.IterRange)
|
||||
c.check(comp.AccuInit)
|
||||
accuType := c.getType(comp.AccuInit)
|
||||
rangeType := c.getType(comp.IterRange)
|
||||
var varType *exprpb.Type
|
||||
|
||||
switch kindOf(rangeType) {
|
||||
case kindList:
|
||||
varType = rangeType.GetListType().ElemType
|
||||
case kindMap:
|
||||
// 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
|
||||
// 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)
|
||||
// Set the range iteration variable to type DYN as well.
|
||||
varType = decls.Dyn
|
||||
default:
|
||||
c.errors.notAComprehensionRange(c.location(comp.IterRange), rangeType)
|
||||
varType = decls.Error
|
||||
}
|
||||
|
||||
// Create a scope for the comprehension since it has a local accumulation variable.
|
||||
// This scope will contain the accumulation variable used to compute the result.
|
||||
c.env = c.env.enterScope()
|
||||
c.env.Add(decls.NewVar(comp.AccuVar, accuType))
|
||||
// Create a block scope for the loop.
|
||||
c.env = c.env.enterScope()
|
||||
c.env.Add(decls.NewVar(comp.IterVar, varType))
|
||||
// Check the variable references in the condition and step.
|
||||
c.check(comp.LoopCondition)
|
||||
c.assertType(comp.LoopCondition, decls.Bool)
|
||||
c.check(comp.LoopStep)
|
||||
c.assertType(comp.LoopStep, accuType)
|
||||
// Exit the loop's block scope before checking the result.
|
||||
c.env = c.env.exitScope()
|
||||
c.check(comp.Result)
|
||||
// Exit the comprehension scope.
|
||||
c.env = c.env.exitScope()
|
||||
c.setType(e, c.getType(comp.Result))
|
||||
}
|
||||
|
||||
// Checks compatibility of joined types, and returns the most general common type.
|
||||
func (c *checker) joinTypes(loc common.Location,
|
||||
previous *exprpb.Type,
|
||||
current *exprpb.Type) *exprpb.Type {
|
||||
if previous == nil {
|
||||
return current
|
||||
}
|
||||
if c.isAssignable(previous, current) {
|
||||
return mostGeneral(previous, current)
|
||||
}
|
||||
if c.dynAggregateLiteralElementTypesEnabled() {
|
||||
return decls.Dyn
|
||||
}
|
||||
c.errors.typeMismatch(loc, previous, current)
|
||||
return decls.Error
|
||||
}
|
||||
|
||||
func (c *checker) dynAggregateLiteralElementTypesEnabled() bool {
|
||||
return c.env.aggLitElemType == dynElementType
|
||||
}
|
||||
|
||||
func (c *checker) newTypeVar() *exprpb.Type {
|
||||
id := c.freeTypeVarCounter
|
||||
c.freeTypeVarCounter++
|
||||
return decls.NewTypeParamType(fmt.Sprintf("_var%d", id))
|
||||
}
|
||||
|
||||
func (c *checker) isAssignable(t1 *exprpb.Type, t2 *exprpb.Type) bool {
|
||||
subs := isAssignable(c.mappings, t1, t2)
|
||||
if subs != nil {
|
||||
c.mappings = subs
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *checker) isAssignableList(l1 []*exprpb.Type, l2 []*exprpb.Type) bool {
|
||||
subs := isAssignableList(c.mappings, l1, l2)
|
||||
if subs != nil {
|
||||
c.mappings = subs
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *checker) lookupFieldType(l common.Location, messageType string, fieldName string) (*ref.FieldType, bool) {
|
||||
if _, found := c.env.provider.FindType(messageType); !found {
|
||||
// This should not happen, anyway, report an error.
|
||||
c.errors.unexpectedFailedResolution(l, messageType)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if ft, found := c.env.provider.FindFieldType(messageType, fieldName); found {
|
||||
return ft, found
|
||||
}
|
||||
|
||||
c.errors.undefinedField(l, fieldName)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (c *checker) setType(e *exprpb.Expr, t *exprpb.Type) {
|
||||
if old, found := c.types[e.Id]; found && !proto.Equal(old, t) {
|
||||
c.errors.ReportError(c.location(e),
|
||||
"(Incompatible) Type already exists for expression: %v(%d) old:%v, new:%v", e, e.GetId(), old, t)
|
||||
return
|
||||
}
|
||||
c.types[e.Id] = t
|
||||
}
|
||||
|
||||
func (c *checker) getType(e *exprpb.Expr) *exprpb.Type {
|
||||
return c.types[e.Id]
|
||||
}
|
||||
|
||||
func (c *checker) setReference(e *exprpb.Expr, r *exprpb.Reference) {
|
||||
if old, found := c.references[e.Id]; found && !proto.Equal(old, r) {
|
||||
c.errors.ReportError(c.location(e),
|
||||
"Reference already exists for expression: %v(%d) old:%v, new:%v", e, e.Id, old, r)
|
||||
return
|
||||
}
|
||||
c.references[e.Id] = r
|
||||
}
|
||||
|
||||
func (c *checker) assertType(e *exprpb.Expr, t *exprpb.Type) {
|
||||
if !c.isAssignable(t, c.getType(e)) {
|
||||
c.errors.typeMismatch(c.location(e), t, c.getType(e))
|
||||
}
|
||||
}
|
||||
|
||||
type overloadResolution struct {
|
||||
Reference *exprpb.Reference
|
||||
Type *exprpb.Type
|
||||
}
|
||||
|
||||
func newResolution(checkedRef *exprpb.Reference, t *exprpb.Type) *overloadResolution {
|
||||
return &overloadResolution{
|
||||
Reference: checkedRef,
|
||||
Type: t,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *checker) location(e *exprpb.Expr) common.Location {
|
||||
return c.locationByID(e.Id)
|
||||
}
|
||||
|
||||
func (c *checker) locationByID(id int64) common.Location {
|
||||
positions := c.sourceInfo.GetPositions()
|
||||
var line = 1
|
||||
if offset, found := positions[id]; found {
|
||||
col := int(offset)
|
||||
for _, lineOffset := range c.sourceInfo.LineOffsets {
|
||||
if lineOffset < offset {
|
||||
line++
|
||||
col = int(offset - lineOffset)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return common.NewLocation(line, col)
|
||||
}
|
||||
return common.NoLocation
|
||||
}
|
||||
|
||||
func newIdentReference(name string, value *exprpb.Constant) *exprpb.Reference {
|
||||
return &exprpb.Reference{Name: name, Value: value}
|
||||
}
|
||||
|
||||
func newFunctionReference(overloads ...string) *exprpb.Reference {
|
||||
return &exprpb.Reference{OverloadId: overloads}
|
||||
}
|
||||
20
vendor/github.com/google/cel-go/checker/decls/BUILD.bazel
generated
vendored
Normal file
20
vendor/github.com/google/cel-go/checker/decls/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"decls.go",
|
||||
"scopes.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/checker/decls",
|
||||
deps = [
|
||||
"@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",
|
||||
],
|
||||
)
|
||||
231
vendor/github.com/google/cel-go/checker/decls/decls.go
generated
vendored
Normal file
231
vendor/github.com/google/cel-go/checker/decls/decls.go
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
// Copyright 2018 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 decls provides helpers for creating variable and function declarations.
|
||||
package decls
|
||||
|
||||
import (
|
||||
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 (
|
||||
// Error type used to communicate issues during type-checking.
|
||||
Error = &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Error{
|
||||
Error: &emptypb.Empty{}}}
|
||||
|
||||
// Dyn is a top-type used to represent any value.
|
||||
Dyn = &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Dyn{
|
||||
Dyn: &emptypb.Empty{}}}
|
||||
)
|
||||
|
||||
// Commonly used types.
|
||||
var (
|
||||
Bool = NewPrimitiveType(exprpb.Type_BOOL)
|
||||
Bytes = NewPrimitiveType(exprpb.Type_BYTES)
|
||||
Double = NewPrimitiveType(exprpb.Type_DOUBLE)
|
||||
Int = NewPrimitiveType(exprpb.Type_INT64)
|
||||
Null = &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Null{
|
||||
Null: structpb.NullValue_NULL_VALUE}}
|
||||
String = NewPrimitiveType(exprpb.Type_STRING)
|
||||
Uint = NewPrimitiveType(exprpb.Type_UINT64)
|
||||
)
|
||||
|
||||
// Well-known types.
|
||||
// TODO: Replace with an abstract type registry.
|
||||
var (
|
||||
Any = NewWellKnownType(exprpb.Type_ANY)
|
||||
Duration = NewWellKnownType(exprpb.Type_DURATION)
|
||||
Timestamp = NewWellKnownType(exprpb.Type_TIMESTAMP)
|
||||
)
|
||||
|
||||
// NewAbstractType creates an abstract type declaration which references a proto
|
||||
// message name and may also include type parameters.
|
||||
func NewAbstractType(name string, paramTypes ...*exprpb.Type) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_AbstractType_{
|
||||
AbstractType: &exprpb.Type_AbstractType{
|
||||
Name: name,
|
||||
ParameterTypes: paramTypes}}}
|
||||
}
|
||||
|
||||
// NewFunctionType creates a function invocation contract, typically only used
|
||||
// by type-checking steps after overload resolution.
|
||||
func NewFunctionType(resultType *exprpb.Type,
|
||||
argTypes ...*exprpb.Type) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Function{
|
||||
Function: &exprpb.Type_FunctionType{
|
||||
ResultType: resultType,
|
||||
ArgTypes: argTypes}}}
|
||||
}
|
||||
|
||||
// NewFunction creates a named function declaration with one or more overloads.
|
||||
func NewFunction(name string,
|
||||
overloads ...*exprpb.Decl_FunctionDecl_Overload) *exprpb.Decl {
|
||||
return &exprpb.Decl{
|
||||
Name: name,
|
||||
DeclKind: &exprpb.Decl_Function{
|
||||
Function: &exprpb.Decl_FunctionDecl{
|
||||
Overloads: overloads}}}
|
||||
}
|
||||
|
||||
// NewIdent creates a named identifier declaration with an optional literal
|
||||
// value.
|
||||
//
|
||||
// Literal values are typically only associated with enum identifiers.
|
||||
//
|
||||
// Deprecated: Use NewVar or NewConst instead.
|
||||
func NewIdent(name string, t *exprpb.Type, v *exprpb.Constant) *exprpb.Decl {
|
||||
return &exprpb.Decl{
|
||||
Name: name,
|
||||
DeclKind: &exprpb.Decl_Ident{
|
||||
Ident: &exprpb.Decl_IdentDecl{
|
||||
Type: t,
|
||||
Value: v}}}
|
||||
}
|
||||
|
||||
// NewConst creates a constant identifier with a CEL constant literal value.
|
||||
func NewConst(name string, t *exprpb.Type, v *exprpb.Constant) *exprpb.Decl {
|
||||
return NewIdent(name, t, v)
|
||||
}
|
||||
|
||||
// NewVar creates a variable identifier.
|
||||
func NewVar(name string, t *exprpb.Type) *exprpb.Decl {
|
||||
return NewIdent(name, t, nil)
|
||||
}
|
||||
|
||||
// NewInstanceOverload creates a instance function overload contract.
|
||||
// First element of argTypes is instance.
|
||||
func NewInstanceOverload(id string, argTypes []*exprpb.Type,
|
||||
resultType *exprpb.Type) *exprpb.Decl_FunctionDecl_Overload {
|
||||
return &exprpb.Decl_FunctionDecl_Overload{
|
||||
OverloadId: id,
|
||||
ResultType: resultType,
|
||||
Params: argTypes,
|
||||
IsInstanceFunction: true}
|
||||
}
|
||||
|
||||
// NewListType generates a new list with elements of a certain type.
|
||||
func NewListType(elem *exprpb.Type) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_ListType_{
|
||||
ListType: &exprpb.Type_ListType{
|
||||
ElemType: elem}}}
|
||||
}
|
||||
|
||||
// NewMapType generates a new map with typed keys and values.
|
||||
func NewMapType(key *exprpb.Type, value *exprpb.Type) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_MapType_{
|
||||
MapType: &exprpb.Type_MapType{
|
||||
KeyType: key,
|
||||
ValueType: value}}}
|
||||
}
|
||||
|
||||
// NewObjectType creates an object type for a qualified type name.
|
||||
func NewObjectType(typeName string) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_MessageType{
|
||||
MessageType: typeName}}
|
||||
}
|
||||
|
||||
// NewOverload creates a function overload declaration which contains a unique
|
||||
// overload id as well as the expected argument and result types. Overloads
|
||||
// must be aggregated within a Function declaration.
|
||||
func NewOverload(id string, argTypes []*exprpb.Type,
|
||||
resultType *exprpb.Type) *exprpb.Decl_FunctionDecl_Overload {
|
||||
return &exprpb.Decl_FunctionDecl_Overload{
|
||||
OverloadId: id,
|
||||
ResultType: resultType,
|
||||
Params: argTypes,
|
||||
IsInstanceFunction: false}
|
||||
}
|
||||
|
||||
// NewParameterizedInstanceOverload creates a parametric function instance overload type.
|
||||
func NewParameterizedInstanceOverload(id string,
|
||||
argTypes []*exprpb.Type,
|
||||
resultType *exprpb.Type,
|
||||
typeParams []string) *exprpb.Decl_FunctionDecl_Overload {
|
||||
return &exprpb.Decl_FunctionDecl_Overload{
|
||||
OverloadId: id,
|
||||
ResultType: resultType,
|
||||
Params: argTypes,
|
||||
TypeParams: typeParams,
|
||||
IsInstanceFunction: true}
|
||||
}
|
||||
|
||||
// NewParameterizedOverload creates a parametric function overload type.
|
||||
func NewParameterizedOverload(id string,
|
||||
argTypes []*exprpb.Type,
|
||||
resultType *exprpb.Type,
|
||||
typeParams []string) *exprpb.Decl_FunctionDecl_Overload {
|
||||
return &exprpb.Decl_FunctionDecl_Overload{
|
||||
OverloadId: id,
|
||||
ResultType: resultType,
|
||||
Params: argTypes,
|
||||
TypeParams: typeParams,
|
||||
IsInstanceFunction: false}
|
||||
}
|
||||
|
||||
// NewPrimitiveType creates a type for a primitive value. See the var declarations
|
||||
// for Int, Uint, etc.
|
||||
func NewPrimitiveType(primitive exprpb.Type_PrimitiveType) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Primitive{
|
||||
Primitive: primitive}}
|
||||
}
|
||||
|
||||
// NewTypeType creates a new type designating a type.
|
||||
func NewTypeType(nested *exprpb.Type) *exprpb.Type {
|
||||
if nested == nil {
|
||||
// must set the nested field for a valid oneof option
|
||||
nested = &exprpb.Type{}
|
||||
}
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Type{
|
||||
Type: nested}}
|
||||
}
|
||||
|
||||
// NewTypeParamType creates a type corresponding to a named, contextual parameter.
|
||||
func NewTypeParamType(name string) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_TypeParam{
|
||||
TypeParam: name}}
|
||||
}
|
||||
|
||||
// NewWellKnownType creates a type corresponding to a protobuf well-known type
|
||||
// value.
|
||||
func NewWellKnownType(wellKnown exprpb.Type_WellKnownType) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_WellKnown{
|
||||
WellKnown: wellKnown}}
|
||||
}
|
||||
|
||||
// NewWrapperType creates a wrapped primitive type instance. Wrapped types
|
||||
// are roughly equivalent to a nullable, or optionally valued type.
|
||||
func NewWrapperType(wrapped *exprpb.Type) *exprpb.Type {
|
||||
primitive := wrapped.GetPrimitive()
|
||||
if primitive == exprpb.Type_PRIMITIVE_TYPE_UNSPECIFIED {
|
||||
// TODO: return an error
|
||||
panic("Wrapped type must be a primitive")
|
||||
}
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Wrapper{
|
||||
Wrapper: primitive}}
|
||||
}
|
||||
115
vendor/github.com/google/cel-go/checker/decls/scopes.go
generated
vendored
Normal file
115
vendor/github.com/google/cel-go/checker/decls/scopes.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2018 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 decls
|
||||
|
||||
import exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
|
||||
// Scopes represents nested Decl sets where the Scopes value contains a Groups containing all
|
||||
// identifiers in scope and an optional parent representing outer scopes.
|
||||
// Each Groups value is a mapping of names to Decls in the ident and function namespaces.
|
||||
// Lookups are performed such that bindings in inner scopes shadow those in outer scopes.
|
||||
type Scopes struct {
|
||||
parent *Scopes
|
||||
scopes *Group
|
||||
}
|
||||
|
||||
// NewScopes creates a new, empty Scopes.
|
||||
// Some operations can't be safely performed until a Group is added with Push.
|
||||
func NewScopes() *Scopes {
|
||||
return &Scopes{
|
||||
scopes: newGroup(),
|
||||
}
|
||||
}
|
||||
|
||||
// Push creates a new Scopes value which references the current Scope as its parent.
|
||||
func (s *Scopes) Push() *Scopes {
|
||||
return &Scopes{
|
||||
parent: s,
|
||||
scopes: newGroup(),
|
||||
}
|
||||
}
|
||||
|
||||
// Pop returns the parent Scopes value for the current scope, or the current scope if the parent
|
||||
// is nil.
|
||||
func (s *Scopes) Pop() *Scopes {
|
||||
if s.parent != nil {
|
||||
return s.parent
|
||||
}
|
||||
// TODO: Consider whether this should be an error / panic.
|
||||
return s
|
||||
}
|
||||
|
||||
// AddIdent adds the ident Decl in the current scope.
|
||||
// Note: If the name collides with an existing identifier in the scope, the Decl is overwritten.
|
||||
func (s *Scopes) AddIdent(decl *exprpb.Decl) {
|
||||
s.scopes.idents[decl.Name] = decl
|
||||
}
|
||||
|
||||
// FindIdent finds the first ident Decl with a matching name in Scopes, or nil if one cannot be
|
||||
// found.
|
||||
// Note: The search is performed from innermost to outermost.
|
||||
func (s *Scopes) FindIdent(name string) *exprpb.Decl {
|
||||
if ident, found := s.scopes.idents[name]; found {
|
||||
return ident
|
||||
}
|
||||
if s.parent != nil {
|
||||
return s.parent.FindIdent(name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindIdentInScope finds the first ident Decl with a matching name in the current Scopes value, or
|
||||
// nil if one does not exist.
|
||||
// Note: The search is only performed on the current scope and does not search outer scopes.
|
||||
func (s *Scopes) FindIdentInScope(name string) *exprpb.Decl {
|
||||
if ident, found := s.scopes.idents[name]; found {
|
||||
return ident
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddFunction 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) {
|
||||
s.scopes.functions[fn.Name] = fn
|
||||
}
|
||||
|
||||
// FindFunction finds the first function Decl with a matching name in Scopes.
|
||||
// The search is performed from innermost to outermost.
|
||||
// Returns nil if no such function in Scopes.
|
||||
func (s *Scopes) FindFunction(name string) *exprpb.Decl {
|
||||
if fn, found := s.scopes.functions[name]; found {
|
||||
return fn
|
||||
}
|
||||
if s.parent != nil {
|
||||
return s.parent.FindFunction(name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
// (Should be named "Scope" perhaps?)
|
||||
type Group struct {
|
||||
idents map[string]*exprpb.Decl
|
||||
functions map[string]*exprpb.Decl
|
||||
}
|
||||
|
||||
func newGroup() *Group {
|
||||
return &Group{
|
||||
idents: make(map[string]*exprpb.Decl),
|
||||
functions: make(map[string]*exprpb.Decl),
|
||||
}
|
||||
}
|
||||
346
vendor/github.com/google/cel-go/checker/env.go
generated
vendored
Normal file
346
vendor/github.com/google/cel-go/checker/env.go
generated
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
// Copyright 2018 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 checker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"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/parser"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
type aggregateLiteralElementType int
|
||||
|
||||
const (
|
||||
dynElementType aggregateLiteralElementType = iota
|
||||
homogenousElementType aggregateLiteralElementType = 1 << iota
|
||||
)
|
||||
|
||||
// Env is the environment for type checking.
|
||||
//
|
||||
// The Env is comprised of a container, type provider, declarations, and other related objects
|
||||
// which can be used to assist with type-checking.
|
||||
type Env struct {
|
||||
container *containers.Container
|
||||
provider ref.TypeProvider
|
||||
declarations *decls.Scopes
|
||||
aggLitElemType aggregateLiteralElementType
|
||||
}
|
||||
|
||||
// NewEnv returns a new *Env with the given parameters.
|
||||
func NewEnv(container *containers.Container, provider ref.TypeProvider) *Env {
|
||||
declarations := decls.NewScopes()
|
||||
declarations.Push()
|
||||
|
||||
return &Env{
|
||||
container: container,
|
||||
provider: provider,
|
||||
declarations: declarations,
|
||||
}
|
||||
}
|
||||
|
||||
// NewStandardEnv returns a new *Env with the given params plus standard declarations.
|
||||
func NewStandardEnv(container *containers.Container, provider ref.TypeProvider) *Env {
|
||||
e := NewEnv(container, provider)
|
||||
if err := e.Add(StandardDeclarations()...); err != nil {
|
||||
// The standard declaration set should never have duplicate declarations.
|
||||
panic(err)
|
||||
}
|
||||
// TODO: isolate standard declarations from the custom set which may be provided layer.
|
||||
return e
|
||||
}
|
||||
|
||||
// EnableDynamicAggregateLiterals detmerines whether list and map literals may support mixed
|
||||
// element types at check-time. This does not preclude the presence of a dynamic list or map
|
||||
// somewhere in the CEL evaluation process.
|
||||
func (e *Env) EnableDynamicAggregateLiterals(enabled bool) *Env {
|
||||
e.aggLitElemType = dynElementType
|
||||
if !enabled {
|
||||
e.aggLitElemType = homogenousElementType
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// Add adds new Decl protos to the Env.
|
||||
// Returns an error for identifier redeclarations.
|
||||
func (e *Env) Add(decls ...*exprpb.Decl) error {
|
||||
errMsgs := make([]errorMsg, 0)
|
||||
for _, decl := range decls {
|
||||
switch decl.DeclKind.(type) {
|
||||
case *exprpb.Decl_Ident:
|
||||
errMsgs = append(errMsgs, e.addIdent(sanitizeIdent(decl)))
|
||||
case *exprpb.Decl_Function:
|
||||
errMsgs = append(errMsgs, e.addFunction(sanitizeFunction(decl))...)
|
||||
}
|
||||
}
|
||||
return formatError(errMsgs)
|
||||
}
|
||||
|
||||
// LookupIdent returns a Decl proto for typeName as an identifier in the Env.
|
||||
// Returns nil if no such identifier is found in the Env.
|
||||
func (e *Env) LookupIdent(name string) *exprpb.Decl {
|
||||
for _, candidate := range e.container.ResolveCandidateNames(name) {
|
||||
if ident := e.declarations.FindIdent(candidate); ident != nil {
|
||||
return ident
|
||||
}
|
||||
|
||||
// Next try to import the name as a reference to a message type. If found,
|
||||
// the declaration is added to the outest (global) scope of the
|
||||
// environment, so next time we can access it faster.
|
||||
if t, found := e.provider.FindType(candidate); found {
|
||||
decl := decls.NewVar(candidate, t)
|
||||
e.declarations.AddIdent(decl)
|
||||
return decl
|
||||
}
|
||||
|
||||
// Next try to import this as an enum value by splitting the name in a type prefix and
|
||||
// the enum inside.
|
||||
if enumValue := e.provider.EnumValue(candidate); enumValue.Type() != types.ErrType {
|
||||
decl := decls.NewIdent(candidate,
|
||||
decls.Int,
|
||||
&exprpb.Constant{
|
||||
ConstantKind: &exprpb.Constant_Int64Value{
|
||||
Int64Value: int64(enumValue.(types.Int))}})
|
||||
e.declarations.AddIdent(decl)
|
||||
return decl
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LookupFunction returns a Decl proto for typeName as a function in env.
|
||||
// Returns nil if no such function is found in env.
|
||||
func (e *Env) LookupFunction(name string) *exprpb.Decl {
|
||||
for _, candidate := range e.container.ResolveCandidateNames(name) {
|
||||
if fn := e.declarations.FindFunction(candidate); fn != nil {
|
||||
return fn
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// addOverload adds overload to function declaration f.
|
||||
// Returns one or more errorMsg values if the overload overlaps with an existing overload or macro.
|
||||
func (e *Env) addOverload(f *exprpb.Decl, overload *exprpb.Decl_FunctionDecl_Overload) []errorMsg {
|
||||
errMsgs := make([]errorMsg, 0)
|
||||
function := f.GetFunction()
|
||||
emptyMappings := newMapping()
|
||||
overloadFunction := decls.NewFunctionType(overload.GetResultType(),
|
||||
overload.GetParams()...)
|
||||
overloadErased := substitute(emptyMappings, overloadFunction, true)
|
||||
for _, existing := range function.GetOverloads() {
|
||||
existingFunction := decls.NewFunctionType(existing.GetResultType(),
|
||||
existing.GetParams()...)
|
||||
existingErased := substitute(emptyMappings, existingFunction, true)
|
||||
overlap := isAssignable(emptyMappings, overloadErased, existingErased) != nil ||
|
||||
isAssignable(emptyMappings, existingErased, overloadErased) != nil
|
||||
if overlap &&
|
||||
overload.GetIsInstanceFunction() == existing.GetIsInstanceFunction() {
|
||||
errMsgs = append(errMsgs,
|
||||
overlappingOverloadError(f.Name,
|
||||
overload.GetOverloadId(), overloadFunction,
|
||||
existing.GetOverloadId(), existingFunction))
|
||||
}
|
||||
}
|
||||
|
||||
for _, macro := range parser.AllMacros {
|
||||
if macro.Function() == f.Name &&
|
||||
macro.IsReceiverStyle() == overload.GetIsInstanceFunction() &&
|
||||
macro.ArgCount() == len(overload.GetParams()) {
|
||||
errMsgs = append(errMsgs, overlappingMacroError(f.Name, macro.ArgCount()))
|
||||
}
|
||||
}
|
||||
if len(errMsgs) > 0 {
|
||||
return errMsgs
|
||||
}
|
||||
function.Overloads = append(function.GetOverloads(), overload)
|
||||
return errMsgs
|
||||
}
|
||||
|
||||
// addFunction 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 {
|
||||
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)
|
||||
}
|
||||
|
||||
errorMsgs := make([]errorMsg, 0)
|
||||
for _, overload := range decl.GetFunction().GetOverloads() {
|
||||
errorMsgs = append(errorMsgs, e.addOverload(current, overload)...)
|
||||
}
|
||||
return errorMsgs
|
||||
}
|
||||
|
||||
// addIdent adds the Decl to the declarations in the Env.
|
||||
// Returns a non-empty errorMsg if the identifier is already declared in the scope.
|
||||
func (e *Env) addIdent(decl *exprpb.Decl) errorMsg {
|
||||
current := e.declarations.FindIdentInScope(decl.Name)
|
||||
if current != nil {
|
||||
return overlappingIdentifierError(decl.Name)
|
||||
}
|
||||
e.declarations.AddIdent(decl)
|
||||
return ""
|
||||
}
|
||||
|
||||
// sanitizeFunction replaces well-known types referenced by message name with their equivalent
|
||||
// CEL built-in type instances.
|
||||
func sanitizeFunction(decl *exprpb.Decl) *exprpb.Decl {
|
||||
fn := decl.GetFunction()
|
||||
// Determine whether the declaration requires replacements from proto-based message type
|
||||
// references to well-known CEL type references.
|
||||
var needsSanitizing bool
|
||||
for _, o := range fn.GetOverloads() {
|
||||
if isObjectWellKnownType(o.GetResultType()) {
|
||||
needsSanitizing = true
|
||||
break
|
||||
}
|
||||
for _, p := range o.GetParams() {
|
||||
if isObjectWellKnownType(p) {
|
||||
needsSanitizing = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Early return if the declaration requires no modification.
|
||||
if !needsSanitizing {
|
||||
return decl
|
||||
}
|
||||
|
||||
// Sanitize all of the overloads if any overload requires an update to its type references.
|
||||
overloads := make([]*exprpb.Decl_FunctionDecl_Overload, len(fn.GetOverloads()))
|
||||
for i, o := range fn.GetOverloads() {
|
||||
rt := o.GetResultType()
|
||||
if isObjectWellKnownType(rt) {
|
||||
rt = getObjectWellKnownType(rt)
|
||||
}
|
||||
params := make([]*exprpb.Type, len(o.GetParams()))
|
||||
copy(params, o.GetParams())
|
||||
for j, p := range params {
|
||||
if isObjectWellKnownType(p) {
|
||||
params[j] = getObjectWellKnownType(p)
|
||||
}
|
||||
}
|
||||
// If sanitized, replace the overload definition.
|
||||
if o.IsInstanceFunction {
|
||||
overloads[i] =
|
||||
decls.NewInstanceOverload(o.GetOverloadId(), params, rt)
|
||||
} else {
|
||||
overloads[i] =
|
||||
decls.NewOverload(o.GetOverloadId(), params, rt)
|
||||
}
|
||||
}
|
||||
return decls.NewFunction(decl.GetName(), overloads...)
|
||||
}
|
||||
|
||||
// sanitizeIdent replaces the identifier's well-known types referenced by message name with
|
||||
// references to CEL built-in type instances.
|
||||
func sanitizeIdent(decl *exprpb.Decl) *exprpb.Decl {
|
||||
id := decl.GetIdent()
|
||||
t := id.GetType()
|
||||
if !isObjectWellKnownType(t) {
|
||||
return decl
|
||||
}
|
||||
return decls.NewIdent(decl.GetName(), getObjectWellKnownType(t), id.GetValue())
|
||||
}
|
||||
|
||||
// isObjectWellKnownType returns true if the input type is an OBJECT type with a message name
|
||||
// that corresponds the message name of a built-in CEL type.
|
||||
func isObjectWellKnownType(t *exprpb.Type) bool {
|
||||
if kindOf(t) != kindObject {
|
||||
return false
|
||||
}
|
||||
_, found := pb.CheckedWellKnowns[t.GetMessageType()]
|
||||
return found
|
||||
}
|
||||
|
||||
// getObjectWellKnownType returns the built-in CEL type declaration for input type's message name.
|
||||
func getObjectWellKnownType(t *exprpb.Type) *exprpb.Type {
|
||||
return pb.CheckedWellKnowns[t.GetMessageType()]
|
||||
}
|
||||
|
||||
// enterScope creates a new Env instance with a new innermost declaration scope.
|
||||
func (e *Env) enterScope() *Env {
|
||||
childDecls := e.declarations.Push()
|
||||
return &Env{
|
||||
declarations: childDecls,
|
||||
container: e.container,
|
||||
provider: e.provider,
|
||||
aggLitElemType: e.aggLitElemType,
|
||||
}
|
||||
}
|
||||
|
||||
// exitScope creates a new Env instance with the nearest outer declaration scope.
|
||||
func (e *Env) exitScope() *Env {
|
||||
parentDecls := e.declarations.Pop()
|
||||
return &Env{
|
||||
declarations: parentDecls,
|
||||
container: e.container,
|
||||
provider: e.provider,
|
||||
aggLitElemType: e.aggLitElemType,
|
||||
}
|
||||
}
|
||||
|
||||
// errorMsg is a type alias meant to represent error-based return values which
|
||||
// may be accumulated into an error at a later point in execution.
|
||||
type errorMsg string
|
||||
|
||||
func overlappingIdentifierError(name string) errorMsg {
|
||||
return errorMsg(fmt.Sprintf("overlapping identifier for name '%s'", name))
|
||||
}
|
||||
|
||||
func overlappingOverloadError(name string,
|
||||
overloadID1 string, f1 *exprpb.Type,
|
||||
overloadID2 string, f2 *exprpb.Type) errorMsg {
|
||||
return errorMsg(fmt.Sprintf(
|
||||
"overlapping overload for name '%s' (type '%s' with overloadId: '%s' "+
|
||||
"cannot be distinguished from '%s' with overloadId: '%s')",
|
||||
name,
|
||||
FormatCheckedType(f1),
|
||||
overloadID1,
|
||||
FormatCheckedType(f2),
|
||||
overloadID2))
|
||||
}
|
||||
|
||||
func overlappingMacroError(name string, argCount int) errorMsg {
|
||||
return errorMsg(fmt.Sprintf(
|
||||
"overlapping macro for name '%s' with %d args", name, argCount))
|
||||
}
|
||||
|
||||
func formatError(errMsgs []errorMsg) error {
|
||||
errStrs := make([]string, 0)
|
||||
if len(errMsgs) > 0 {
|
||||
for i := 0; i < len(errMsgs); i++ {
|
||||
if errMsgs[i] != "" {
|
||||
errStrs = append(errStrs, string(errMsgs[i]))
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errStrs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errStrs, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
100
vendor/github.com/google/cel-go/checker/errors.go
generated
vendored
Normal file
100
vendor/github.com/google/cel-go/checker/errors.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright 2018 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 checker
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// typeErrors is a specialization of Errors.
|
||||
type typeErrors struct {
|
||||
*common.Errors
|
||||
}
|
||||
|
||||
func (e *typeErrors) undeclaredReference(l common.Location, container string, name string) {
|
||||
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)
|
||||
}
|
||||
|
||||
func (e *typeErrors) undefinedField(l common.Location, field string) {
|
||||
e.ReportError(l, "undefined field '%s'", field)
|
||||
}
|
||||
|
||||
func (e *typeErrors) noMatchingOverload(l common.Location, name string, args []*exprpb.Type, isInstance bool) {
|
||||
signature := formatFunction(nil, args, isInstance)
|
||||
e.ReportError(l, "found no matching overload for '%s' applied to '%s'", name, signature)
|
||||
}
|
||||
|
||||
func (e *typeErrors) notAType(l common.Location, t *exprpb.Type) {
|
||||
e.ReportError(l, "'%s(%v)' is not a type", FormatCheckedType(t), t)
|
||||
}
|
||||
|
||||
func (e *typeErrors) notAMessageType(l common.Location, t *exprpb.Type) {
|
||||
e.ReportError(l, "'%s' is not a message type", FormatCheckedType(t))
|
||||
}
|
||||
|
||||
func (e *typeErrors) fieldTypeMismatch(l common.Location, name string, field *exprpb.Type, value *exprpb.Type) {
|
||||
e.ReportError(l, "expected type of field '%s' is '%s' but provided type is '%s'",
|
||||
name, FormatCheckedType(field), FormatCheckedType(value))
|
||||
}
|
||||
|
||||
func (e *typeErrors) unexpectedFailedResolution(l common.Location, typeName string) {
|
||||
e.ReportError(l, "[internal] unexpected failed resolution of '%s'", typeName)
|
||||
}
|
||||
|
||||
func (e *typeErrors) notAComprehensionRange(l common.Location, t *exprpb.Type) {
|
||||
e.ReportError(l, "expression of type '%s' cannot be range of a comprehension (must be list, map, or dynamic)",
|
||||
FormatCheckedType(t))
|
||||
}
|
||||
|
||||
func (e *typeErrors) typeMismatch(l common.Location, expected *exprpb.Type, actual *exprpb.Type) {
|
||||
e.ReportError(l, "expected type '%s' but found '%s'",
|
||||
FormatCheckedType(expected), FormatCheckedType(actual))
|
||||
}
|
||||
|
||||
func formatFunction(resultType *exprpb.Type, argTypes []*exprpb.Type, isInstance bool) string {
|
||||
result := ""
|
||||
if isInstance {
|
||||
target := argTypes[0]
|
||||
argTypes = argTypes[1:]
|
||||
|
||||
result += FormatCheckedType(target)
|
||||
result += "."
|
||||
}
|
||||
|
||||
result += "("
|
||||
for i, arg := range argTypes {
|
||||
if i > 0 {
|
||||
result += ", "
|
||||
}
|
||||
result += FormatCheckedType(arg)
|
||||
}
|
||||
result += ")"
|
||||
if resultType != nil {
|
||||
result += " -> "
|
||||
result += FormatCheckedType(resultType)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
49
vendor/github.com/google/cel-go/checker/mapping.go
generated
vendored
Normal file
49
vendor/github.com/google/cel-go/checker/mapping.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2018 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 checker
|
||||
|
||||
import (
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
type mapping struct {
|
||||
mapping map[string]*exprpb.Type
|
||||
}
|
||||
|
||||
func newMapping() *mapping {
|
||||
return &mapping{
|
||||
mapping: make(map[string]*exprpb.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mapping) add(from *exprpb.Type, to *exprpb.Type) {
|
||||
m.mapping[typeKey(from)] = to
|
||||
}
|
||||
|
||||
func (m *mapping) find(from *exprpb.Type) (*exprpb.Type, bool) {
|
||||
if r, found := m.mapping[typeKey(from)]; found {
|
||||
return r, found
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (m *mapping) copy() *mapping {
|
||||
c := newMapping()
|
||||
|
||||
for k, v := range m.mapping {
|
||||
c.mapping[k] = v
|
||||
}
|
||||
return c
|
||||
}
|
||||
71
vendor/github.com/google/cel-go/checker/printer.go
generated
vendored
Normal file
71
vendor/github.com/google/cel-go/checker/printer.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2018 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 checker
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/debug"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
type semanticAdorner struct {
|
||||
checks *exprpb.CheckedExpr
|
||||
}
|
||||
|
||||
var _ debug.Adorner = &semanticAdorner{}
|
||||
|
||||
func (a *semanticAdorner) GetMetadata(elem interface{}) string {
|
||||
result := ""
|
||||
e, isExpr := elem.(*exprpb.Expr)
|
||||
if !isExpr {
|
||||
return result
|
||||
}
|
||||
t := a.checks.TypeMap[e.Id]
|
||||
if t != nil {
|
||||
result += "~"
|
||||
result += FormatCheckedType(t)
|
||||
}
|
||||
|
||||
switch e.ExprKind.(type) {
|
||||
case *exprpb.Expr_IdentExpr,
|
||||
*exprpb.Expr_CallExpr,
|
||||
*exprpb.Expr_StructExpr,
|
||||
*exprpb.Expr_SelectExpr:
|
||||
if ref, found := a.checks.ReferenceMap[e.Id]; found {
|
||||
if len(ref.GetOverloadId()) == 0 {
|
||||
result += "^" + ref.Name
|
||||
} else {
|
||||
for i, overload := range ref.OverloadId {
|
||||
if i == 0 {
|
||||
result += "^"
|
||||
} else {
|
||||
result += "|"
|
||||
}
|
||||
result += overload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Print returns a string representation of the Expr message,
|
||||
// annotated with types from the CheckedExpr. The Expr must
|
||||
// be a sub-expression embedded in the CheckedExpr.
|
||||
func Print(e *exprpb.Expr, checks *exprpb.CheckedExpr) string {
|
||||
a := &semanticAdorner{checks: checks}
|
||||
return debug.ToAdornedDebugString(e, a)
|
||||
}
|
||||
440
vendor/github.com/google/cel-go/checker/standard.go
generated
vendored
Normal file
440
vendor/github.com/google/cel-go/checker/standard.go
generated
vendored
Normal file
@@ -0,0 +1,440 @@
|
||||
// Copyright 2018 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 checker
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// StandardDeclarations returns the Decls for all functions and constants in the evaluator.
|
||||
func StandardDeclarations() []*exprpb.Decl {
|
||||
// Some shortcuts we use when building declarations.
|
||||
paramA := decls.NewTypeParamType("A")
|
||||
typeParamAList := []string{"A"}
|
||||
listOfA := decls.NewListType(paramA)
|
||||
paramB := decls.NewTypeParamType("B")
|
||||
typeParamABList := []string{"A", "B"}
|
||||
mapOfAB := decls.NewMapType(paramA, paramB)
|
||||
|
||||
var idents []*exprpb.Decl
|
||||
for _, t := range []*exprpb.Type{
|
||||
decls.Int, decls.Uint, decls.Bool,
|
||||
decls.Double, decls.Bytes, decls.String} {
|
||||
idents = append(idents,
|
||||
decls.NewVar(FormatCheckedType(t), decls.NewTypeType(t)))
|
||||
}
|
||||
idents = append(idents,
|
||||
decls.NewVar("list", decls.NewTypeType(listOfA)),
|
||||
decls.NewVar("map", decls.NewTypeType(mapOfAB)),
|
||||
decls.NewVar("null_type", decls.NewTypeType(decls.Null)),
|
||||
decls.NewVar("type", decls.NewTypeType(decls.NewTypeType(nil))))
|
||||
|
||||
// Booleans
|
||||
// TODO: allow the conditional to return a heterogenous type.
|
||||
return append(idents, []*exprpb.Decl{
|
||||
decls.NewFunction(operators.Conditional,
|
||||
decls.NewParameterizedOverload(overloads.Conditional,
|
||||
[]*exprpb.Type{decls.Bool, paramA, paramA}, paramA,
|
||||
typeParamAList)),
|
||||
|
||||
decls.NewFunction(operators.LogicalAnd,
|
||||
decls.NewOverload(overloads.LogicalAnd,
|
||||
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool)),
|
||||
|
||||
decls.NewFunction(operators.LogicalOr,
|
||||
decls.NewOverload(overloads.LogicalOr,
|
||||
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool)),
|
||||
|
||||
decls.NewFunction(operators.LogicalNot,
|
||||
decls.NewOverload(overloads.LogicalNot,
|
||||
[]*exprpb.Type{decls.Bool}, decls.Bool)),
|
||||
|
||||
decls.NewFunction(operators.NotStrictlyFalse,
|
||||
decls.NewOverload(overloads.NotStrictlyFalse,
|
||||
[]*exprpb.Type{decls.Bool}, decls.Bool)),
|
||||
|
||||
// Relations.
|
||||
|
||||
decls.NewFunction(operators.Less,
|
||||
decls.NewOverload(overloads.LessBool,
|
||||
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessInt64,
|
||||
[]*exprpb.Type{decls.Int, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessBytes,
|
||||
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessTimestamp,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessDuration,
|
||||
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Bool)),
|
||||
|
||||
decls.NewFunction(operators.LessEquals,
|
||||
decls.NewOverload(overloads.LessEqualsBool,
|
||||
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsInt64,
|
||||
[]*exprpb.Type{decls.Int, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsBytes,
|
||||
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsTimestamp,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsDuration,
|
||||
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Bool)),
|
||||
|
||||
decls.NewFunction(operators.Greater,
|
||||
decls.NewOverload(overloads.GreaterBool,
|
||||
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterInt64,
|
||||
[]*exprpb.Type{decls.Int, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterBytes,
|
||||
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterTimestamp,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterDuration,
|
||||
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Bool)),
|
||||
|
||||
decls.NewFunction(operators.GreaterEquals,
|
||||
decls.NewOverload(overloads.GreaterEqualsBool,
|
||||
[]*exprpb.Type{decls.Bool, decls.Bool}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsInt64,
|
||||
[]*exprpb.Type{decls.Int, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsBytes,
|
||||
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsTimestamp,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsDuration,
|
||||
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Bool)),
|
||||
|
||||
decls.NewFunction(operators.Equals,
|
||||
decls.NewParameterizedOverload(overloads.Equals,
|
||||
[]*exprpb.Type{paramA, paramA}, decls.Bool,
|
||||
typeParamAList)),
|
||||
|
||||
decls.NewFunction(operators.NotEquals,
|
||||
decls.NewParameterizedOverload(overloads.NotEquals,
|
||||
[]*exprpb.Type{paramA, paramA}, decls.Bool,
|
||||
typeParamAList)),
|
||||
|
||||
// Algebra.
|
||||
|
||||
decls.NewFunction(operators.Subtract,
|
||||
decls.NewOverload(overloads.SubtractInt64,
|
||||
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
|
||||
decls.NewOverload(overloads.SubtractUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint),
|
||||
decls.NewOverload(overloads.SubtractDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Double),
|
||||
decls.NewOverload(overloads.SubtractTimestampTimestamp,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.Timestamp}, decls.Duration),
|
||||
decls.NewOverload(overloads.SubtractTimestampDuration,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.Duration}, decls.Timestamp),
|
||||
decls.NewOverload(overloads.SubtractDurationDuration,
|
||||
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Duration)),
|
||||
|
||||
decls.NewFunction(operators.Multiply,
|
||||
decls.NewOverload(overloads.MultiplyInt64,
|
||||
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
|
||||
decls.NewOverload(overloads.MultiplyUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint),
|
||||
decls.NewOverload(overloads.MultiplyDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Double)),
|
||||
|
||||
decls.NewFunction(operators.Divide,
|
||||
decls.NewOverload(overloads.DivideInt64,
|
||||
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
|
||||
decls.NewOverload(overloads.DivideUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint),
|
||||
decls.NewOverload(overloads.DivideDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Double)),
|
||||
|
||||
decls.NewFunction(operators.Modulo,
|
||||
decls.NewOverload(overloads.ModuloInt64,
|
||||
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
|
||||
decls.NewOverload(overloads.ModuloUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint)),
|
||||
|
||||
decls.NewFunction(operators.Add,
|
||||
decls.NewOverload(overloads.AddInt64,
|
||||
[]*exprpb.Type{decls.Int, decls.Int}, decls.Int),
|
||||
decls.NewOverload(overloads.AddUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Uint),
|
||||
decls.NewOverload(overloads.AddDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Double),
|
||||
decls.NewOverload(overloads.AddString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.String),
|
||||
decls.NewOverload(overloads.AddBytes,
|
||||
[]*exprpb.Type{decls.Bytes, decls.Bytes}, decls.Bytes),
|
||||
decls.NewParameterizedOverload(overloads.AddList,
|
||||
[]*exprpb.Type{listOfA, listOfA}, listOfA,
|
||||
typeParamAList),
|
||||
decls.NewOverload(overloads.AddTimestampDuration,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.Duration}, decls.Timestamp),
|
||||
decls.NewOverload(overloads.AddDurationTimestamp,
|
||||
[]*exprpb.Type{decls.Duration, decls.Timestamp}, decls.Timestamp),
|
||||
decls.NewOverload(overloads.AddDurationDuration,
|
||||
[]*exprpb.Type{decls.Duration, decls.Duration}, decls.Duration)),
|
||||
|
||||
decls.NewFunction(operators.Negate,
|
||||
decls.NewOverload(overloads.NegateInt64,
|
||||
[]*exprpb.Type{decls.Int}, decls.Int),
|
||||
decls.NewOverload(overloads.NegateDouble,
|
||||
[]*exprpb.Type{decls.Double}, decls.Double)),
|
||||
|
||||
// Index.
|
||||
|
||||
decls.NewFunction(operators.Index,
|
||||
decls.NewParameterizedOverload(overloads.IndexList,
|
||||
[]*exprpb.Type{listOfA, decls.Int}, paramA,
|
||||
typeParamAList),
|
||||
decls.NewParameterizedOverload(overloads.IndexMap,
|
||||
[]*exprpb.Type{mapOfAB, paramA}, paramB,
|
||||
typeParamABList)),
|
||||
//decls.NewOverload(overloads.IndexMessage,
|
||||
// []*expr.Type{decls.Dyn, decls.String}, decls.Dyn)),
|
||||
|
||||
// Collections.
|
||||
|
||||
decls.NewFunction(overloads.Size,
|
||||
decls.NewInstanceOverload(overloads.SizeStringInst,
|
||||
[]*exprpb.Type{decls.String}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.SizeBytesInst,
|
||||
[]*exprpb.Type{decls.Bytes}, decls.Int),
|
||||
decls.NewParameterizedInstanceOverload(overloads.SizeListInst,
|
||||
[]*exprpb.Type{listOfA}, decls.Int, typeParamAList),
|
||||
decls.NewParameterizedInstanceOverload(overloads.SizeMapInst,
|
||||
[]*exprpb.Type{mapOfAB}, decls.Int, typeParamABList),
|
||||
decls.NewOverload(overloads.SizeString,
|
||||
[]*exprpb.Type{decls.String}, decls.Int),
|
||||
decls.NewOverload(overloads.SizeBytes,
|
||||
[]*exprpb.Type{decls.Bytes}, decls.Int),
|
||||
decls.NewParameterizedOverload(overloads.SizeList,
|
||||
[]*exprpb.Type{listOfA}, decls.Int, typeParamAList),
|
||||
decls.NewParameterizedOverload(overloads.SizeMap,
|
||||
[]*exprpb.Type{mapOfAB}, decls.Int, typeParamABList)),
|
||||
|
||||
decls.NewFunction(operators.In,
|
||||
decls.NewParameterizedOverload(overloads.InList,
|
||||
[]*exprpb.Type{paramA, listOfA}, decls.Bool,
|
||||
typeParamAList),
|
||||
decls.NewParameterizedOverload(overloads.InMap,
|
||||
[]*exprpb.Type{paramA, mapOfAB}, decls.Bool,
|
||||
typeParamABList)),
|
||||
|
||||
// Deprecated 'in()' function.
|
||||
|
||||
decls.NewFunction(overloads.DeprecatedIn,
|
||||
decls.NewParameterizedOverload(overloads.InList,
|
||||
[]*exprpb.Type{paramA, listOfA}, decls.Bool,
|
||||
typeParamAList),
|
||||
decls.NewParameterizedOverload(overloads.InMap,
|
||||
[]*exprpb.Type{paramA, mapOfAB}, decls.Bool,
|
||||
typeParamABList)),
|
||||
//decls.NewOverload(overloads.InMessage,
|
||||
// []*expr.Type{Dyn, decls.String},decls.Bool)),
|
||||
|
||||
// Conversions to type.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertType,
|
||||
decls.NewParameterizedOverload(overloads.TypeConvertType,
|
||||
[]*exprpb.Type{paramA}, decls.NewTypeType(paramA), typeParamAList)),
|
||||
|
||||
// Conversions to int.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertInt,
|
||||
decls.NewOverload(overloads.IntToInt, []*exprpb.Type{decls.Int}, decls.Int),
|
||||
decls.NewOverload(overloads.UintToInt, []*exprpb.Type{decls.Uint}, decls.Int),
|
||||
decls.NewOverload(overloads.DoubleToInt, []*exprpb.Type{decls.Double}, decls.Int),
|
||||
decls.NewOverload(overloads.StringToInt, []*exprpb.Type{decls.String}, decls.Int),
|
||||
decls.NewOverload(overloads.TimestampToInt, []*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewOverload(overloads.DurationToInt, []*exprpb.Type{decls.Duration}, decls.Int)),
|
||||
|
||||
// Conversions to uint.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertUint,
|
||||
decls.NewOverload(overloads.UintToUint, []*exprpb.Type{decls.Uint}, decls.Uint),
|
||||
decls.NewOverload(overloads.IntToUint, []*exprpb.Type{decls.Int}, decls.Uint),
|
||||
decls.NewOverload(overloads.DoubleToUint, []*exprpb.Type{decls.Double}, decls.Uint),
|
||||
decls.NewOverload(overloads.StringToUint, []*exprpb.Type{decls.String}, decls.Uint)),
|
||||
|
||||
// Conversions to double.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertDouble,
|
||||
decls.NewOverload(overloads.DoubleToDouble, []*exprpb.Type{decls.Double}, decls.Double),
|
||||
decls.NewOverload(overloads.IntToDouble, []*exprpb.Type{decls.Int}, decls.Double),
|
||||
decls.NewOverload(overloads.UintToDouble, []*exprpb.Type{decls.Uint}, decls.Double),
|
||||
decls.NewOverload(overloads.StringToDouble, []*exprpb.Type{decls.String}, decls.Double)),
|
||||
|
||||
// Conversions to bool.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertBool,
|
||||
decls.NewOverload(overloads.BoolToBool, []*exprpb.Type{decls.Bool}, decls.Bool),
|
||||
decls.NewOverload(overloads.StringToBool, []*exprpb.Type{decls.String}, decls.Bool)),
|
||||
|
||||
// Conversions to string.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertString,
|
||||
decls.NewOverload(overloads.StringToString, []*exprpb.Type{decls.String}, decls.String),
|
||||
decls.NewOverload(overloads.BoolToString, []*exprpb.Type{decls.Bool}, decls.String),
|
||||
decls.NewOverload(overloads.IntToString, []*exprpb.Type{decls.Int}, decls.String),
|
||||
decls.NewOverload(overloads.UintToString, []*exprpb.Type{decls.Uint}, decls.String),
|
||||
decls.NewOverload(overloads.DoubleToString, []*exprpb.Type{decls.Double}, decls.String),
|
||||
decls.NewOverload(overloads.BytesToString, []*exprpb.Type{decls.Bytes}, decls.String),
|
||||
decls.NewOverload(overloads.TimestampToString, []*exprpb.Type{decls.Timestamp}, decls.String),
|
||||
decls.NewOverload(overloads.DurationToString, []*exprpb.Type{decls.Duration}, decls.String)),
|
||||
|
||||
// Conversions to bytes.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertBytes,
|
||||
decls.NewOverload(overloads.BytesToBytes, []*exprpb.Type{decls.Bytes}, decls.Bytes),
|
||||
decls.NewOverload(overloads.StringToBytes, []*exprpb.Type{decls.String}, decls.Bytes)),
|
||||
|
||||
// Conversions to timestamps.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertTimestamp,
|
||||
decls.NewOverload(overloads.TimestampToTimestamp,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Timestamp),
|
||||
decls.NewOverload(overloads.StringToTimestamp,
|
||||
[]*exprpb.Type{decls.String}, decls.Timestamp),
|
||||
decls.NewOverload(overloads.IntToTimestamp,
|
||||
[]*exprpb.Type{decls.Int}, decls.Timestamp)),
|
||||
|
||||
// Conversions to durations.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertDuration,
|
||||
decls.NewOverload(overloads.DurationToDuration,
|
||||
[]*exprpb.Type{decls.Duration}, decls.Duration),
|
||||
decls.NewOverload(overloads.StringToDuration,
|
||||
[]*exprpb.Type{decls.String}, decls.Duration),
|
||||
decls.NewOverload(overloads.IntToDuration,
|
||||
[]*exprpb.Type{decls.Int}, decls.Duration)),
|
||||
|
||||
// Conversions to Dyn.
|
||||
|
||||
decls.NewFunction(overloads.TypeConvertDyn,
|
||||
decls.NewParameterizedOverload(overloads.ToDyn,
|
||||
[]*exprpb.Type{paramA}, decls.Dyn,
|
||||
typeParamAList)),
|
||||
|
||||
// String functions.
|
||||
|
||||
decls.NewFunction(overloads.Contains,
|
||||
decls.NewInstanceOverload(overloads.ContainsString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
|
||||
decls.NewFunction(overloads.EndsWith,
|
||||
decls.NewInstanceOverload(overloads.EndsWithString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
|
||||
decls.NewFunction(overloads.Matches,
|
||||
decls.NewInstanceOverload(overloads.MatchesString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
|
||||
decls.NewFunction(overloads.StartsWith,
|
||||
decls.NewInstanceOverload(overloads.StartsWithString,
|
||||
[]*exprpb.Type{decls.String, decls.String}, decls.Bool)),
|
||||
|
||||
// Date/time functions.
|
||||
|
||||
decls.NewFunction(overloads.TimeGetFullYear,
|
||||
decls.NewInstanceOverload(overloads.TimestampToYear,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToYearWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
|
||||
|
||||
decls.NewFunction(overloads.TimeGetMonth,
|
||||
decls.NewInstanceOverload(overloads.TimestampToMonth,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToMonthWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
|
||||
|
||||
decls.NewFunction(overloads.TimeGetDayOfYear,
|
||||
decls.NewInstanceOverload(overloads.TimestampToDayOfYear,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToDayOfYearWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
|
||||
|
||||
decls.NewFunction(overloads.TimeGetDayOfMonth,
|
||||
decls.NewInstanceOverload(overloads.TimestampToDayOfMonthZeroBased,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToDayOfMonthZeroBasedWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
|
||||
|
||||
decls.NewFunction(overloads.TimeGetDate,
|
||||
decls.NewInstanceOverload(overloads.TimestampToDayOfMonthOneBased,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToDayOfMonthOneBasedWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
|
||||
|
||||
decls.NewFunction(overloads.TimeGetDayOfWeek,
|
||||
decls.NewInstanceOverload(overloads.TimestampToDayOfWeek,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToDayOfWeekWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int)),
|
||||
|
||||
decls.NewFunction(overloads.TimeGetHours,
|
||||
decls.NewInstanceOverload(overloads.TimestampToHours,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToHoursWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.DurationToHours,
|
||||
[]*exprpb.Type{decls.Duration}, decls.Int)),
|
||||
|
||||
decls.NewFunction(overloads.TimeGetMinutes,
|
||||
decls.NewInstanceOverload(overloads.TimestampToMinutes,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToMinutesWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.DurationToMinutes,
|
||||
[]*exprpb.Type{decls.Duration}, decls.Int)),
|
||||
|
||||
decls.NewFunction(overloads.TimeGetSeconds,
|
||||
decls.NewInstanceOverload(overloads.TimestampToSeconds,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToSecondsWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.DurationToSeconds,
|
||||
[]*exprpb.Type{decls.Duration}, decls.Int)),
|
||||
|
||||
decls.NewFunction(overloads.TimeGetMilliseconds,
|
||||
decls.NewInstanceOverload(overloads.TimestampToMilliseconds,
|
||||
[]*exprpb.Type{decls.Timestamp}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.TimestampToMillisecondsWithTz,
|
||||
[]*exprpb.Type{decls.Timestamp, decls.String}, decls.Int),
|
||||
decls.NewInstanceOverload(overloads.DurationToMilliseconds,
|
||||
[]*exprpb.Type{decls.Duration}, decls.Int))}...)
|
||||
}
|
||||
505
vendor/github.com/google/cel-go/checker/types.go
generated
vendored
Normal file
505
vendor/github.com/google/cel-go/checker/types.go
generated
vendored
Normal file
@@ -0,0 +1,505 @@
|
||||
// Copyright 2018 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 checker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/cel-go/checker/decls"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
const (
|
||||
kindUnknown = iota + 1
|
||||
kindError
|
||||
kindFunction
|
||||
kindDyn
|
||||
kindPrimitive
|
||||
kindWellKnown
|
||||
kindWrapper
|
||||
kindNull
|
||||
kindAbstract
|
||||
kindType
|
||||
kindList
|
||||
kindMap
|
||||
kindObject
|
||||
kindTypeParam
|
||||
)
|
||||
|
||||
// FormatCheckedType converts a type message into a string representation.
|
||||
func FormatCheckedType(t *exprpb.Type) string {
|
||||
switch kindOf(t) {
|
||||
case kindDyn:
|
||||
return "dyn"
|
||||
case kindFunction:
|
||||
return formatFunction(t.GetFunction().GetResultType(),
|
||||
t.GetFunction().GetArgTypes(),
|
||||
false)
|
||||
case kindList:
|
||||
return fmt.Sprintf("list(%s)", FormatCheckedType(t.GetListType().ElemType))
|
||||
case kindObject:
|
||||
return t.GetMessageType()
|
||||
case kindMap:
|
||||
return fmt.Sprintf("map(%s, %s)",
|
||||
FormatCheckedType(t.GetMapType().KeyType),
|
||||
FormatCheckedType(t.GetMapType().ValueType))
|
||||
case kindNull:
|
||||
return "null"
|
||||
case kindPrimitive:
|
||||
switch t.GetPrimitive() {
|
||||
case exprpb.Type_UINT64:
|
||||
return "uint"
|
||||
case exprpb.Type_INT64:
|
||||
return "int"
|
||||
}
|
||||
return strings.Trim(strings.ToLower(t.GetPrimitive().String()), " ")
|
||||
case kindType:
|
||||
if t.GetType() == nil {
|
||||
return "type"
|
||||
}
|
||||
return fmt.Sprintf("type(%s)", FormatCheckedType(t.GetType()))
|
||||
case kindWellKnown:
|
||||
switch t.GetWellKnown() {
|
||||
case exprpb.Type_ANY:
|
||||
return "any"
|
||||
case exprpb.Type_DURATION:
|
||||
return "duration"
|
||||
case exprpb.Type_TIMESTAMP:
|
||||
return "timestamp"
|
||||
}
|
||||
case kindWrapper:
|
||||
return fmt.Sprintf("wrapper(%s)",
|
||||
FormatCheckedType(decls.NewPrimitiveType(t.GetWrapper())))
|
||||
case kindError:
|
||||
return "!error!"
|
||||
}
|
||||
return t.String()
|
||||
}
|
||||
|
||||
// isDyn returns true if the input t is either type DYN or a well-known ANY message.
|
||||
func isDyn(t *exprpb.Type) bool {
|
||||
// Note: object type values that are well-known and map to a DYN value in practice
|
||||
// are sanitized prior to being added to the environment.
|
||||
switch kindOf(t) {
|
||||
case kindDyn:
|
||||
return true
|
||||
case kindWellKnown:
|
||||
return t.GetWellKnown() == exprpb.Type_ANY
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// isEqualOrLessSpecific checks whether one type is equal or less specific than the other one.
|
||||
// A type is less specific if it matches the other type using the DYN type.
|
||||
func isEqualOrLessSpecific(t1 *exprpb.Type, t2 *exprpb.Type) bool {
|
||||
kind1, kind2 := kindOf(t1), kindOf(t2)
|
||||
// The first type is less specific.
|
||||
if isDyn(t1) || kind1 == kindTypeParam {
|
||||
return true
|
||||
}
|
||||
// The first type is not less specific.
|
||||
if isDyn(t2) || kind2 == kindTypeParam {
|
||||
return false
|
||||
}
|
||||
// Types must be of the same kind to be equal.
|
||||
if kind1 != kind2 {
|
||||
return false
|
||||
}
|
||||
|
||||
// With limited exceptions for ANY and JSON values, the types must agree and be equivalent in
|
||||
// order to return true.
|
||||
switch kind1 {
|
||||
case kindAbstract:
|
||||
a1 := t1.GetAbstractType()
|
||||
a2 := t2.GetAbstractType()
|
||||
if a1.GetName() != a2.GetName() ||
|
||||
len(a1.GetParameterTypes()) != len(a2.GetParameterTypes()) {
|
||||
return false
|
||||
}
|
||||
for i, p1 := range a1.GetParameterTypes() {
|
||||
if !isEqualOrLessSpecific(p1, a2.GetParameterTypes()[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
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:
|
||||
m1 := t1.GetMapType()
|
||||
m2 := t2.GetMapType()
|
||||
return isEqualOrLessSpecific(m1.KeyType, m2.KeyType) &&
|
||||
isEqualOrLessSpecific(m1.ValueType, m2.ValueType)
|
||||
case kindType:
|
||||
return true
|
||||
default:
|
||||
return proto.Equal(t1, t2)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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))
|
||||
return true
|
||||
}
|
||||
if notReferencedIn(m, t2, t1) {
|
||||
m.add(t2, t1)
|
||||
return true
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// Next check for wildcard types.
|
||||
if isDynOrError(t1) || isDynOrError(t2) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Test for when the types do not need to agree, but are more specific than dyn.
|
||||
switch kind1 {
|
||||
case kindNull:
|
||||
return internalIsAssignableNull(t2)
|
||||
case kindPrimitive:
|
||||
return internalIsAssignablePrimitive(t1.GetPrimitive(), t2)
|
||||
case kindWrapper:
|
||||
return internalIsAssignable(m, decls.NewPrimitiveType(t1.GetWrapper()), t2)
|
||||
default:
|
||||
if kind1 != kind2 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Test for when the types must agree.
|
||||
switch kind1 {
|
||||
// ERROR, TYPE_PARAM, and DYN handled above.
|
||||
case kindAbstract:
|
||||
return internalIsAssignableAbstractType(m, t1.GetAbstractType(), t2.GetAbstractType())
|
||||
case kindFunction:
|
||||
return internalIsAssignableFunction(m, t1.GetFunction(), t2.GetFunction())
|
||||
case kindList:
|
||||
return internalIsAssignable(m, t1.GetListType().GetElemType(), t2.GetListType().GetElemType())
|
||||
case kindMap:
|
||||
return internalIsAssignableMap(m, t1.GetMapType(), t2.GetMapType())
|
||||
case kindObject:
|
||||
return t1.GetMessageType() == t2.GetMessageType()
|
||||
case kindType:
|
||||
// A type is a type is a type, any additional parameterization of the
|
||||
// type cannot affect method resolution or assignability.
|
||||
return true
|
||||
case kindWellKnown:
|
||||
return t1.GetWellKnown() == t2.GetWellKnown()
|
||||
default:
|
||||
return 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
|
||||
}
|
||||
|
||||
// internalIsAssignableFunction returns true if the function return type and arg types are
|
||||
// assignable.
|
||||
func internalIsAssignableFunction(m *mapping,
|
||||
f1 *exprpb.Type_FunctionType,
|
||||
f2 *exprpb.Type_FunctionType) bool {
|
||||
f1ArgTypes := flattenFunctionTypes(f1)
|
||||
f2ArgTypes := flattenFunctionTypes(f2)
|
||||
if internalIsAssignableList(m, f1ArgTypes, f2ArgTypes) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// internalIsAssignableList returns true if the element types at each index in the list are
|
||||
// assignable from l1[i] to l2[i]. The list lengths must also agree for the lists to be
|
||||
// assignable.
|
||||
func internalIsAssignableList(m *mapping, l1 []*exprpb.Type, l2 []*exprpb.Type) bool {
|
||||
if len(l1) != len(l2) {
|
||||
return false
|
||||
}
|
||||
for i, t1 := range l1 {
|
||||
if !internalIsAssignable(m, t1, l2[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// internalIsAssignableMap returns true if map m1 may be assigned to map m2.
|
||||
func internalIsAssignableMap(m *mapping, m1 *exprpb.Type_MapType, m2 *exprpb.Type_MapType) bool {
|
||||
if internalIsAssignableList(m,
|
||||
[]*exprpb.Type{m1.GetKeyType(), m1.GetValueType()},
|
||||
[]*exprpb.Type{m2.GetKeyType(), m2.GetValueType()}) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// internalIsAssignableNull returns true if the type is nullable.
|
||||
func internalIsAssignableNull(t *exprpb.Type) bool {
|
||||
switch kindOf(t) {
|
||||
case kindAbstract, kindObject, kindNull, kindWellKnown, kindWrapper:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// internalIsAssignablePrimitive returns true if the target type is the same or if it is a wrapper
|
||||
// for the primitive type.
|
||||
func internalIsAssignablePrimitive(p exprpb.Type_PrimitiveType, target *exprpb.Type) bool {
|
||||
switch kindOf(target) {
|
||||
case kindPrimitive:
|
||||
return p == target.GetPrimitive()
|
||||
case kindWrapper:
|
||||
return p == target.GetWrapper()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// isAssignable returns an updated type substitution mapping if t1 is assignable to t2.
|
||||
func isAssignable(m *mapping, t1 *exprpb.Type, t2 *exprpb.Type) *mapping {
|
||||
mCopy := m.copy()
|
||||
if internalIsAssignable(mCopy, t1, t2) {
|
||||
return mCopy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// isAssignableList returns an updated type substitution mapping if l1 is assignable to l2.
|
||||
func isAssignableList(m *mapping, l1 []*exprpb.Type, l2 []*exprpb.Type) *mapping {
|
||||
mCopy := m.copy()
|
||||
if internalIsAssignableList(mCopy, l1, l2) {
|
||||
return mCopy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// kindOf returns the kind of the type as defined in the checked.proto.
|
||||
func kindOf(t *exprpb.Type) int {
|
||||
if t == nil || t.TypeKind == nil {
|
||||
return kindUnknown
|
||||
}
|
||||
switch t.TypeKind.(type) {
|
||||
case *exprpb.Type_Error:
|
||||
return kindError
|
||||
case *exprpb.Type_Function:
|
||||
return kindFunction
|
||||
case *exprpb.Type_Dyn:
|
||||
return kindDyn
|
||||
case *exprpb.Type_Primitive:
|
||||
return kindPrimitive
|
||||
case *exprpb.Type_WellKnown:
|
||||
return kindWellKnown
|
||||
case *exprpb.Type_Wrapper:
|
||||
return kindWrapper
|
||||
case *exprpb.Type_Null:
|
||||
return kindNull
|
||||
case *exprpb.Type_Type:
|
||||
return kindType
|
||||
case *exprpb.Type_ListType_:
|
||||
return kindList
|
||||
case *exprpb.Type_MapType_:
|
||||
return kindMap
|
||||
case *exprpb.Type_MessageType:
|
||||
return kindObject
|
||||
case *exprpb.Type_TypeParam:
|
||||
return kindTypeParam
|
||||
case *exprpb.Type_AbstractType_:
|
||||
return kindAbstract
|
||||
}
|
||||
return kindUnknown
|
||||
}
|
||||
|
||||
// mostGeneral returns the more general of two types which are known to unify.
|
||||
func mostGeneral(t1 *exprpb.Type, t2 *exprpb.Type) *exprpb.Type {
|
||||
if isEqualOrLessSpecific(t1, t2) {
|
||||
return t1
|
||||
}
|
||||
return t2
|
||||
}
|
||||
|
||||
// notReferencedIn checks whether the type doesn't appear directly or transitively within the other
|
||||
// type. This is a standard requirement for type unification, commonly referred to as the "occurs
|
||||
// check".
|
||||
func notReferencedIn(m *mapping, t *exprpb.Type, withinType *exprpb.Type) bool {
|
||||
if proto.Equal(t, withinType) {
|
||||
return false
|
||||
}
|
||||
withinKind := kindOf(withinType)
|
||||
switch withinKind {
|
||||
case kindTypeParam:
|
||||
wtSub, found := m.find(withinType)
|
||||
if !found {
|
||||
return true
|
||||
}
|
||||
return notReferencedIn(m, t, wtSub)
|
||||
case kindAbstract:
|
||||
for _, pt := range withinType.GetAbstractType().GetParameterTypes() {
|
||||
if !notReferencedIn(m, t, pt) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
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:
|
||||
mt := withinType.GetMapType()
|
||||
return notReferencedIn(m, t, mt.KeyType) && notReferencedIn(m, t, mt.ValueType)
|
||||
case kindWrapper:
|
||||
return notReferencedIn(m, t, decls.NewPrimitiveType(withinType.GetWrapper()))
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// substitute replaces all direct and indirect occurrences of bound type parameters. Unbound type
|
||||
// parameters are replaced by DYN if typeParamToDyn is true.
|
||||
func substitute(m *mapping, t *exprpb.Type, typeParamToDyn bool) *exprpb.Type {
|
||||
if tSub, found := m.find(t); found {
|
||||
return substitute(m, tSub, typeParamToDyn)
|
||||
}
|
||||
kind := kindOf(t)
|
||||
if typeParamToDyn && kind == kindTypeParam {
|
||||
return decls.Dyn
|
||||
}
|
||||
switch kind {
|
||||
case kindAbstract:
|
||||
// TODO: implement!
|
||||
at := t.GetAbstractType()
|
||||
params := make([]*exprpb.Type, len(at.GetParameterTypes()))
|
||||
for i, p := range at.GetParameterTypes() {
|
||||
params[i] = substitute(m, p, typeParamToDyn)
|
||||
}
|
||||
return decls.NewAbstractType(at.GetName(), params...)
|
||||
case kindFunction:
|
||||
fn := t.GetFunction()
|
||||
rt := substitute(m, fn.ResultType, typeParamToDyn)
|
||||
args := make([]*exprpb.Type, len(fn.ArgTypes))
|
||||
for i, a := range fn.ArgTypes {
|
||||
args[i] = substitute(m, a, typeParamToDyn)
|
||||
}
|
||||
return decls.NewFunctionType(rt, args...)
|
||||
case kindList:
|
||||
return decls.NewListType(substitute(m, t.GetListType().ElemType, typeParamToDyn))
|
||||
case kindMap:
|
||||
mt := t.GetMapType()
|
||||
return decls.NewMapType(substitute(m, mt.KeyType, typeParamToDyn),
|
||||
substitute(m, mt.ValueType, typeParamToDyn))
|
||||
case kindType:
|
||||
if t.GetType() != nil {
|
||||
return decls.NewTypeType(substitute(m, t.GetType(), typeParamToDyn))
|
||||
}
|
||||
return t
|
||||
default:
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
func typeKey(t *exprpb.Type) string {
|
||||
return FormatCheckedType(t)
|
||||
}
|
||||
|
||||
// flattenFunctionTypes takes a function with arg types T1, T2, ..., TN and result type TR
|
||||
// and returns a slice containing {T1, T2, ..., TN, TR}.
|
||||
func flattenFunctionTypes(f *exprpb.Type_FunctionType) []*exprpb.Type {
|
||||
argTypes := f.GetArgTypes()
|
||||
if len(argTypes) == 0 {
|
||||
return []*exprpb.Type{f.GetResultType()}
|
||||
}
|
||||
flattend := make([]*exprpb.Type, len(argTypes)+1, len(argTypes)+1)
|
||||
for i, at := range argTypes {
|
||||
flattend[i] = at
|
||||
}
|
||||
flattend[len(argTypes)] = f.GetResultType()
|
||||
return flattend
|
||||
}
|
||||
34
vendor/github.com/google/cel-go/common/BUILD.bazel
generated
vendored
Normal file
34
vendor/github.com/google/cel-go/common/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"error.go",
|
||||
"errors.go",
|
||||
"location.go",
|
||||
"source.go",
|
||||
],
|
||||
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_x_text//width:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"errors_test.go",
|
||||
"source_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
)
|
||||
31
vendor/github.com/google/cel-go/common/containers/BUILD.bazel
generated
vendored
Normal file
31
vendor/github.com/google/cel-go/common/containers/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"container.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/containers",
|
||||
deps = [
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"container_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
deps = [
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
316
vendor/github.com/google/cel-go/common/containers/container.go
generated
vendored
Normal file
316
vendor/github.com/google/cel-go/common/containers/container.go
generated
vendored
Normal file
@@ -0,0 +1,316 @@
|
||||
// Copyright 2018 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 containers defines types and functions for resolving qualified names within a namespace
|
||||
// or type provided to CEL.
|
||||
package containers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultContainer has an empty container name.
|
||||
DefaultContainer *Container = nil
|
||||
|
||||
// Empty map to search for aliases when needed.
|
||||
noAliases = make(map[string]string)
|
||||
)
|
||||
|
||||
// NewContainer creates a new Container with the fully-qualified name.
|
||||
func NewContainer(opts ...ContainerOption) (*Container, error) {
|
||||
var c *Container
|
||||
var err error
|
||||
for _, opt := range opts {
|
||||
c, err = opt(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Container holds a reference to an optional qualified container name and set of aliases.
|
||||
//
|
||||
// The program container can be used to simplify variable, function, and type specification within
|
||||
// CEL programs and behaves more or less like a C++ namespace. See ResolveCandidateNames for more
|
||||
// details.
|
||||
type Container struct {
|
||||
name string
|
||||
aliases map[string]string
|
||||
}
|
||||
|
||||
// Extend creates a new Container with the existing settings and applies a series of
|
||||
// ContainerOptions to further configure the new container.
|
||||
func (c *Container) Extend(opts ...ContainerOption) (*Container, error) {
|
||||
if c == nil {
|
||||
return NewContainer(opts...)
|
||||
}
|
||||
// Copy the name and aliases of the existing container.
|
||||
ext := &Container{name: c.Name()}
|
||||
if len(c.aliasSet()) > 0 {
|
||||
aliasSet := make(map[string]string, len(c.aliasSet()))
|
||||
for k, v := range c.aliasSet() {
|
||||
aliasSet[k] = v
|
||||
}
|
||||
ext.aliases = aliasSet
|
||||
}
|
||||
// Apply the new options to the container.
|
||||
var err error
|
||||
for _, opt := range opts {
|
||||
ext, err = opt(ext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return ext, nil
|
||||
}
|
||||
|
||||
// Name returns the fully-qualified name of the container.
|
||||
//
|
||||
// The name may conceptually be a namespace, package, or type.
|
||||
func (c *Container) Name() string {
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
return c.name
|
||||
}
|
||||
|
||||
// ResolveCandidateNames returns the candidates name of namespaced identifiers in C++ resolution
|
||||
// order.
|
||||
//
|
||||
// Names which shadow other names are returned first. If a name includes a leading dot ('.'),
|
||||
// the name is treated as an absolute identifier which cannot be shadowed.
|
||||
//
|
||||
// Given a container name a.b.c.M.N and a type name R.s, this will deliver in order:
|
||||
//
|
||||
// a.b.c.M.N.R.s
|
||||
// a.b.c.M.R.s
|
||||
// a.b.c.R.s
|
||||
// a.b.R.s
|
||||
// a.R.s
|
||||
// R.s
|
||||
//
|
||||
// If aliases or abbreviations are configured for the container, then alias names will take
|
||||
// precedence over containerized names.
|
||||
func (c *Container) ResolveCandidateNames(name string) []string {
|
||||
if strings.HasPrefix(name, ".") {
|
||||
qn := name[1:]
|
||||
alias, isAlias := c.findAlias(qn)
|
||||
if isAlias {
|
||||
return []string{alias}
|
||||
}
|
||||
return []string{qn}
|
||||
}
|
||||
alias, isAlias := c.findAlias(name)
|
||||
if isAlias {
|
||||
return []string{alias}
|
||||
}
|
||||
if c.Name() == "" {
|
||||
return []string{name}
|
||||
}
|
||||
nextCont := c.Name()
|
||||
candidates := []string{nextCont + "." + name}
|
||||
for i := strings.LastIndex(nextCont, "."); i >= 0; i = strings.LastIndex(nextCont, ".") {
|
||||
nextCont = nextCont[:i]
|
||||
candidates = append(candidates, nextCont+"."+name)
|
||||
}
|
||||
return append(candidates, name)
|
||||
}
|
||||
|
||||
// aliasSet returns the alias to fully-qualified name mapping stored in the container.
|
||||
func (c *Container) aliasSet() map[string]string {
|
||||
if c == nil || c.aliases == nil {
|
||||
return noAliases
|
||||
}
|
||||
return c.aliases
|
||||
}
|
||||
|
||||
// findAlias takes a name as input and returns an alias expansion if one exists.
|
||||
//
|
||||
// If the name is qualified, the first component of the qualified name is checked against known
|
||||
// aliases. Any alias that is found in a qualified name is expanded in the result:
|
||||
//
|
||||
// alias: R -> my.alias.R
|
||||
// name: R.S.T
|
||||
// output: my.alias.R.S.T
|
||||
//
|
||||
// Note, the name must not have a leading dot.
|
||||
func (c *Container) findAlias(name string) (string, bool) {
|
||||
// If an alias exists for the name, ensure it is searched last.
|
||||
simple := name
|
||||
qualifier := ""
|
||||
dot := strings.Index(name, ".")
|
||||
if dot >= 0 {
|
||||
simple = name[0:dot]
|
||||
qualifier = name[dot:]
|
||||
}
|
||||
alias, found := c.aliasSet()[simple]
|
||||
if !found {
|
||||
return "", false
|
||||
}
|
||||
return alias + qualifier, true
|
||||
}
|
||||
|
||||
// ContainerOption specifies a functional configuration option for a Container.
|
||||
//
|
||||
// Note, ContainerOption implementations must be able to handle nil container inputs.
|
||||
type ContainerOption func(*Container) (*Container, error)
|
||||
|
||||
// Abbrevs configures a set of simple names as abbreviations for fully-qualified names.
|
||||
//
|
||||
// An abbreviation (abbrev for short) is a simple name that expands to a fully-qualified name.
|
||||
// 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: ...}
|
||||
// }
|
||||
//
|
||||
// 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: ...}}
|
||||
//
|
||||
// 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`.
|
||||
// - The last element in the qualified name is the abbreviation.
|
||||
// - Abbreviations must not collide with each other.
|
||||
// - The abbreviation must not collide with unqualified names in use.
|
||||
//
|
||||
// Abbreviations are distinct from container-based references in the following important ways:
|
||||
// - Abbreviations must expand to a fully-qualified name.
|
||||
// - 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.
|
||||
// - 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.
|
||||
//
|
||||
// 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
|
||||
// preserved between compilations even as the container evolves.
|
||||
func Abbrevs(qualifiedNames ...string) ContainerOption {
|
||||
return func(c *Container) (*Container, error) {
|
||||
for _, qn := range qualifiedNames {
|
||||
ind := strings.LastIndex(qn, ".")
|
||||
if ind <= 0 || ind >= len(qn)-1 {
|
||||
return nil, fmt.Errorf(
|
||||
"invalid qualified name: %s, wanted name of the form 'qualified.name'", qn)
|
||||
}
|
||||
alias := qn[ind+1:]
|
||||
var err error
|
||||
c, err = aliasAs("abbreviation", qn, alias)(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Alias associates a fully-qualified name with a user-defined alias.
|
||||
//
|
||||
// In general, Abbrevs is preferred to Alias since the names generated from the Abbrevs option
|
||||
// are more easily traced back to source code. The Alias option is useful for propagating alias
|
||||
// configuration from one Container instance to another, and may also be useful for remapping
|
||||
// poorly chosen protobuf message / package names.
|
||||
//
|
||||
// Note: all of the rules that apply to Abbrevs also apply to Alias.
|
||||
func Alias(qualifiedName, alias string) ContainerOption {
|
||||
return aliasAs("alias", qualifiedName, alias)
|
||||
}
|
||||
|
||||
func aliasAs(kind, qualifiedName, alias string) ContainerOption {
|
||||
return func(c *Container) (*Container, error) {
|
||||
if len(alias) == 0 || strings.Contains(alias, ".") {
|
||||
return nil, fmt.Errorf(
|
||||
"%s must be non-empty and simple (not qualified): %s=%s", kind, kind, alias)
|
||||
}
|
||||
|
||||
if qualifiedName[0:1] == "." {
|
||||
return nil, fmt.Errorf("qualified name must not begin with a leading '.': %s",
|
||||
qualifiedName)
|
||||
}
|
||||
ind := strings.LastIndex(qualifiedName, ".")
|
||||
if ind <= 0 || ind == len(qualifiedName)-1 {
|
||||
return nil, fmt.Errorf("%s must refer to a valid qualified name: %s",
|
||||
kind, qualifiedName)
|
||||
}
|
||||
aliasRef, found := c.aliasSet()[alias]
|
||||
if found {
|
||||
return nil, fmt.Errorf(
|
||||
"%s collides with existing reference: name=%s, %s=%s, existing=%s",
|
||||
kind, qualifiedName, kind, alias, aliasRef)
|
||||
}
|
||||
if strings.HasPrefix(c.Name(), alias+".") || c.Name() == alias {
|
||||
return nil, fmt.Errorf(
|
||||
"%s collides with container name: name=%s, %s=%s, container=%s",
|
||||
kind, qualifiedName, kind, alias, c.Name())
|
||||
}
|
||||
if c == nil {
|
||||
c = &Container{}
|
||||
}
|
||||
if c.aliases == nil {
|
||||
c.aliases = make(map[string]string)
|
||||
}
|
||||
c.aliases[alias] = qualifiedName
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Name sets the fully-qualified name of the Container.
|
||||
func Name(name string) ContainerOption {
|
||||
return func(c *Container) (*Container, error) {
|
||||
if len(name) > 0 && name[0:1] == "." {
|
||||
return nil, fmt.Errorf("container name must not contain a leading '.': %s", name)
|
||||
}
|
||||
if c.Name() == name {
|
||||
return c, nil
|
||||
}
|
||||
if c == nil {
|
||||
return &Container{name: name}, nil
|
||||
}
|
||||
c.name = name
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ToQualifiedName converts an expression AST into a qualified name if possible, with a boolean
|
||||
// 'found' value that indicates if the conversion is successful.
|
||||
func ToQualifiedName(e *exprpb.Expr) (string, bool) {
|
||||
switch e.ExprKind.(type) {
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
id := e.GetIdentExpr()
|
||||
return id.Name, true
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
sel := e.GetSelectExpr()
|
||||
// Test only expressions are not valid as qualified names.
|
||||
if sel.GetTestOnly() {
|
||||
return "", false
|
||||
}
|
||||
if qual, found := ToQualifiedName(sel.Operand); found {
|
||||
return qual + "." + sel.Field, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
18
vendor/github.com/google/cel-go/common/debug/BUILD.bazel
generated
vendored
Normal file
18
vendor/github.com/google/cel-go/common/debug/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"debug.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/debug",
|
||||
deps = [
|
||||
"//common:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
305
vendor/github.com/google/cel-go/common/debug/debug.go
generated
vendored
Normal file
305
vendor/github.com/google/cel-go/common/debug/debug.go
generated
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
// Copyright 2018 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 debug provides tools to print a parsed expression graph and
|
||||
// adorn each expression element with additional metadata.
|
||||
package debug
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Adorner returns debug metadata that will be tacked on to the string
|
||||
// representation of an expression.
|
||||
type Adorner interface {
|
||||
// GetMetadata for the input context.
|
||||
GetMetadata(ctx interface{}) string
|
||||
}
|
||||
|
||||
// Writer manages writing expressions to an internal string.
|
||||
type Writer interface {
|
||||
fmt.Stringer
|
||||
|
||||
// Buffer pushes an expression into an internal queue of expressions to
|
||||
// write to a string.
|
||||
Buffer(e *exprpb.Expr)
|
||||
}
|
||||
|
||||
type emptyDebugAdorner struct {
|
||||
}
|
||||
|
||||
var emptyAdorner Adorner = &emptyDebugAdorner{}
|
||||
|
||||
func (a *emptyDebugAdorner) GetMetadata(e interface{}) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ToDebugString gives the unadorned string representation of the Expr.
|
||||
func ToDebugString(e *exprpb.Expr) string {
|
||||
return ToAdornedDebugString(e, emptyAdorner)
|
||||
}
|
||||
|
||||
// ToAdornedDebugString gives the adorned string representation of the Expr.
|
||||
func ToAdornedDebugString(e *exprpb.Expr, adorner Adorner) string {
|
||||
w := newDebugWriter(adorner)
|
||||
w.Buffer(e)
|
||||
return w.String()
|
||||
}
|
||||
|
||||
// debugWriter is used to print out pretty-printed debug strings.
|
||||
type debugWriter struct {
|
||||
adorner Adorner
|
||||
buffer bytes.Buffer
|
||||
indent int
|
||||
lineStart bool
|
||||
}
|
||||
|
||||
func newDebugWriter(a Adorner) *debugWriter {
|
||||
return &debugWriter{
|
||||
adorner: a,
|
||||
indent: 0,
|
||||
lineStart: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *debugWriter) Buffer(e *exprpb.Expr) {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
switch e.ExprKind.(type) {
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
w.append(formatLiteral(e.GetConstExpr()))
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
w.append(e.GetIdentExpr().Name)
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
w.appendSelect(e.GetSelectExpr())
|
||||
case *exprpb.Expr_CallExpr:
|
||||
w.appendCall(e.GetCallExpr())
|
||||
case *exprpb.Expr_ListExpr:
|
||||
w.appendList(e.GetListExpr())
|
||||
case *exprpb.Expr_StructExpr:
|
||||
w.appendStruct(e.GetStructExpr())
|
||||
case *exprpb.Expr_ComprehensionExpr:
|
||||
w.appendComprehension(e.GetComprehensionExpr())
|
||||
}
|
||||
w.adorn(e)
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendSelect(sel *exprpb.Expr_Select) {
|
||||
w.Buffer(sel.Operand)
|
||||
w.append(".")
|
||||
w.append(sel.Field)
|
||||
if sel.TestOnly {
|
||||
w.append("~test-only~")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendCall(call *exprpb.Expr_Call) {
|
||||
if call.Target != nil {
|
||||
w.Buffer(call.Target)
|
||||
w.append(".")
|
||||
}
|
||||
w.append(call.Function)
|
||||
w.append("(")
|
||||
if len(call.GetArgs()) > 0 {
|
||||
w.addIndent()
|
||||
w.appendLine()
|
||||
for i, arg := range call.Args {
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
w.Buffer(arg)
|
||||
}
|
||||
w.removeIndent()
|
||||
w.appendLine()
|
||||
}
|
||||
w.append(")")
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendList(list *exprpb.Expr_CreateList) {
|
||||
w.append("[")
|
||||
if len(list.GetElements()) > 0 {
|
||||
w.appendLine()
|
||||
w.addIndent()
|
||||
for i, elem := range list.Elements {
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
w.Buffer(elem)
|
||||
}
|
||||
w.removeIndent()
|
||||
w.appendLine()
|
||||
}
|
||||
w.append("]")
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendStruct(obj *exprpb.Expr_CreateStruct) {
|
||||
if obj.MessageName != "" {
|
||||
w.appendObject(obj)
|
||||
} else {
|
||||
w.appendMap(obj)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendObject(obj *exprpb.Expr_CreateStruct) {
|
||||
w.append(obj.MessageName)
|
||||
w.append("{")
|
||||
if len(obj.Entries) > 0 {
|
||||
w.appendLine()
|
||||
w.addIndent()
|
||||
for i, entry := range obj.Entries {
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
w.append(entry.GetFieldKey())
|
||||
w.append(":")
|
||||
w.Buffer(entry.Value)
|
||||
w.adorn(entry)
|
||||
}
|
||||
w.removeIndent()
|
||||
w.appendLine()
|
||||
}
|
||||
w.append("}")
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendMap(obj *exprpb.Expr_CreateStruct) {
|
||||
w.append("{")
|
||||
if len(obj.Entries) > 0 {
|
||||
w.appendLine()
|
||||
w.addIndent()
|
||||
for i, entry := range obj.Entries {
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
w.Buffer(entry.GetMapKey())
|
||||
w.append(":")
|
||||
w.Buffer(entry.Value)
|
||||
w.adorn(entry)
|
||||
}
|
||||
w.removeIndent()
|
||||
w.appendLine()
|
||||
}
|
||||
w.append("}")
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendComprehension(comprehension *exprpb.Expr_Comprehension) {
|
||||
w.append("__comprehension__(")
|
||||
w.addIndent()
|
||||
w.appendLine()
|
||||
w.append("// Variable")
|
||||
w.appendLine()
|
||||
w.append(comprehension.IterVar)
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Target")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.IterRange)
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Accumulator")
|
||||
w.appendLine()
|
||||
w.append(comprehension.AccuVar)
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Init")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.AccuInit)
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// LoopCondition")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.LoopCondition)
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// LoopStep")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.LoopStep)
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Result")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.Result)
|
||||
w.append(")")
|
||||
w.removeIndent()
|
||||
}
|
||||
|
||||
func formatLiteral(c *exprpb.Constant) string {
|
||||
switch c.ConstantKind.(type) {
|
||||
case *exprpb.Constant_BoolValue:
|
||||
return fmt.Sprintf("%t", c.GetBoolValue())
|
||||
case *exprpb.Constant_BytesValue:
|
||||
return fmt.Sprintf("b\"%s\"", string(c.GetBytesValue()))
|
||||
case *exprpb.Constant_DoubleValue:
|
||||
return fmt.Sprintf("%v", c.GetDoubleValue())
|
||||
case *exprpb.Constant_Int64Value:
|
||||
return fmt.Sprintf("%d", c.GetInt64Value())
|
||||
case *exprpb.Constant_StringValue:
|
||||
return strconv.Quote(c.GetStringValue())
|
||||
case *exprpb.Constant_Uint64Value:
|
||||
return fmt.Sprintf("%du", c.GetUint64Value())
|
||||
case *exprpb.Constant_NullValue:
|
||||
return "null"
|
||||
default:
|
||||
panic("Unknown constant type")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *debugWriter) append(s string) {
|
||||
w.doIndent()
|
||||
w.buffer.WriteString(s)
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendFormat(f string, args ...interface{}) {
|
||||
w.append(fmt.Sprintf(f, args...))
|
||||
}
|
||||
|
||||
func (w *debugWriter) doIndent() {
|
||||
if w.lineStart {
|
||||
w.lineStart = false
|
||||
w.buffer.WriteString(strings.Repeat(" ", w.indent))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *debugWriter) adorn(e interface{}) {
|
||||
w.append(w.adorner.GetMetadata(e))
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendLine() {
|
||||
w.buffer.WriteString("\n")
|
||||
w.lineStart = true
|
||||
}
|
||||
|
||||
func (w *debugWriter) addIndent() {
|
||||
w.indent++
|
||||
}
|
||||
|
||||
func (w *debugWriter) removeIndent() {
|
||||
w.indent--
|
||||
if w.indent < 0 {
|
||||
panic("negative indent")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *debugWriter) String() string {
|
||||
return w.buffer.String()
|
||||
}
|
||||
17
vendor/github.com/google/cel-go/common/doc.go
generated
vendored
Normal file
17
vendor/github.com/google/cel-go/common/doc.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2018 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 common defines types and utilities common to expression parsing,
|
||||
// checking, and interpretation
|
||||
package common
|
||||
70
vendor/github.com/google/cel-go/common/error.go
generated
vendored
Normal file
70
vendor/github.com/google/cel-go/common/error.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2018 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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/width"
|
||||
)
|
||||
|
||||
// Error type which references a location within source and a message.
|
||||
type Error struct {
|
||||
Location Location
|
||||
Message string
|
||||
}
|
||||
|
||||
const (
|
||||
dot = "."
|
||||
ind = "^"
|
||||
)
|
||||
|
||||
var (
|
||||
wideDot = width.Widen.String(dot)
|
||||
wideInd = width.Widen.String(ind)
|
||||
)
|
||||
|
||||
// ToDisplayString decorates the error message with the source location.
|
||||
func (e *Error) ToDisplayString(source Source) string {
|
||||
var result = fmt.Sprintf("ERROR: %s:%d:%d: %s",
|
||||
source.Description(),
|
||||
e.Location.Line(),
|
||||
e.Location.Column()+1, // add one to the 0-based column for display
|
||||
e.Message)
|
||||
if snippet, found := source.Snippet(e.Location.Line()); found {
|
||||
snippet := strings.Replace(snippet, "\t", " ", -1)
|
||||
srcLine := "\n | " + snippet
|
||||
var bytes = []byte(snippet)
|
||||
var indLine = "\n | "
|
||||
for i := 0; i < e.Location.Column() && len(bytes) > 0; i++ {
|
||||
_, sz := utf8.DecodeRune(bytes)
|
||||
bytes = bytes[sz:]
|
||||
if sz > 1 {
|
||||
indLine += wideDot
|
||||
} else {
|
||||
indLine += dot
|
||||
}
|
||||
}
|
||||
if _, sz := utf8.DecodeRune(bytes); sz > 1 {
|
||||
indLine += wideInd
|
||||
} else {
|
||||
indLine += ind
|
||||
}
|
||||
result += srcLine + indLine
|
||||
}
|
||||
return result
|
||||
}
|
||||
74
vendor/github.com/google/cel-go/common/errors.go
generated
vendored
Normal file
74
vendor/github.com/google/cel-go/common/errors.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2018 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 common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Errors type which contains a list of errors observed during parsing.
|
||||
type Errors struct {
|
||||
errors []Error
|
||||
source Source
|
||||
}
|
||||
|
||||
// NewErrors creates a new instance of the Errors type.
|
||||
func NewErrors(source Source) *Errors {
|
||||
return &Errors{
|
||||
errors: []Error{},
|
||||
source: source}
|
||||
}
|
||||
|
||||
// ReportError records an error at a source location.
|
||||
func (e *Errors) ReportError(l Location, format string, args ...interface{}) {
|
||||
err := Error{
|
||||
Location: l,
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
}
|
||||
e.errors = append(e.errors, err)
|
||||
}
|
||||
|
||||
// GetErrors returns the list of observed errors.
|
||||
func (e *Errors) GetErrors() []Error {
|
||||
return e.errors[:]
|
||||
}
|
||||
|
||||
// Append takes an Errors object as input creates a new Errors object with the current and input
|
||||
// errors.
|
||||
func (e *Errors) Append(errs []Error) *Errors {
|
||||
return &Errors{
|
||||
errors: append(e.errors, errs...),
|
||||
source: e.source,
|
||||
}
|
||||
}
|
||||
|
||||
// ToDisplayString returns the error set to a newline delimited string.
|
||||
func (e *Errors) ToDisplayString() string {
|
||||
var result = ""
|
||||
sort.SliceStable(e.errors, func(i, j int) bool {
|
||||
ei := e.errors[i].Location
|
||||
ej := e.errors[j].Location
|
||||
return ei.Line() < ej.Line() ||
|
||||
(ei.Line() == ej.Line() && ei.Column() < ej.Column())
|
||||
})
|
||||
for i, err := range e.errors {
|
||||
if i >= 1 {
|
||||
result += "\n"
|
||||
}
|
||||
result += err.ToDisplayString(e.source)
|
||||
}
|
||||
return result
|
||||
}
|
||||
51
vendor/github.com/google/cel-go/common/location.go
generated
vendored
Normal file
51
vendor/github.com/google/cel-go/common/location.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2018 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 common
|
||||
|
||||
// Location interface to represent a location within Source.
|
||||
type Location interface {
|
||||
Line() int // 1-based line number within source.
|
||||
Column() int // 0-based column number within source.
|
||||
}
|
||||
|
||||
// SourceLocation helper type to manually construct a location.
|
||||
type SourceLocation struct {
|
||||
line int
|
||||
column int
|
||||
}
|
||||
|
||||
var (
|
||||
// Location implements the SourcceLocation interface.
|
||||
_ Location = &SourceLocation{}
|
||||
// NoLocation is a particular illegal location.
|
||||
NoLocation = &SourceLocation{-1, -1}
|
||||
)
|
||||
|
||||
// NewLocation creates a new location.
|
||||
func NewLocation(line, column int) Location {
|
||||
return &SourceLocation{
|
||||
line: line,
|
||||
column: column}
|
||||
}
|
||||
|
||||
// Line returns the 1-based line of the location.
|
||||
func (l *SourceLocation) Line() int {
|
||||
return l.line
|
||||
}
|
||||
|
||||
// Column returns the 0-based column number of the location.
|
||||
func (l *SourceLocation) Column() int {
|
||||
return l.column
|
||||
}
|
||||
14
vendor/github.com/google/cel-go/common/operators/BUILD.bazel
generated
vendored
Normal file
14
vendor/github.com/google/cel-go/common/operators/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"operators.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/operators",
|
||||
)
|
||||
145
vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
Normal file
145
vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright 2018 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 operators defines the internal function names of operators.
|
||||
//
|
||||
// ALl operators in the expression language are modelled as function calls.
|
||||
package operators
|
||||
|
||||
// String "names" for CEL operators.
|
||||
const (
|
||||
// Symbolic operators.
|
||||
Conditional = "_?_:_"
|
||||
LogicalAnd = "_&&_"
|
||||
LogicalOr = "_||_"
|
||||
LogicalNot = "!_"
|
||||
Equals = "_==_"
|
||||
NotEquals = "_!=_"
|
||||
Less = "_<_"
|
||||
LessEquals = "_<=_"
|
||||
Greater = "_>_"
|
||||
GreaterEquals = "_>=_"
|
||||
Add = "_+_"
|
||||
Subtract = "_-_"
|
||||
Multiply = "_*_"
|
||||
Divide = "_/_"
|
||||
Modulo = "_%_"
|
||||
Negate = "-_"
|
||||
Index = "_[_]"
|
||||
|
||||
// Macros, must have a valid identifier.
|
||||
Has = "has"
|
||||
All = "all"
|
||||
Exists = "exists"
|
||||
ExistsOne = "exists_one"
|
||||
Map = "map"
|
||||
Filter = "filter"
|
||||
|
||||
// Named operators, must not have be valid identifiers.
|
||||
NotStrictlyFalse = "@not_strictly_false"
|
||||
In = "@in"
|
||||
|
||||
// Deprecated: named operators with valid identifiers.
|
||||
OldNotStrictlyFalse = "__not_strictly_false__"
|
||||
OldIn = "_in_"
|
||||
)
|
||||
|
||||
var (
|
||||
operators = map[string]string{
|
||||
"+": Add,
|
||||
"/": Divide,
|
||||
"==": Equals,
|
||||
">": Greater,
|
||||
">=": GreaterEquals,
|
||||
"in": In,
|
||||
"<": Less,
|
||||
"<=": LessEquals,
|
||||
"%": Modulo,
|
||||
"*": Multiply,
|
||||
"!=": NotEquals,
|
||||
"-": Subtract,
|
||||
}
|
||||
reverseOperators = map[string]string{
|
||||
Add: "+",
|
||||
Divide: "/",
|
||||
Equals: "==",
|
||||
Greater: ">",
|
||||
GreaterEquals: ">=",
|
||||
In: "in",
|
||||
Less: "<",
|
||||
LessEquals: "<=",
|
||||
LogicalAnd: "&&",
|
||||
LogicalNot: "!",
|
||||
LogicalOr: "||",
|
||||
Modulo: "%",
|
||||
Multiply: "*",
|
||||
Negate: "-",
|
||||
NotEquals: "!=",
|
||||
OldIn: "in",
|
||||
Subtract: "-",
|
||||
}
|
||||
// precedence of the operator, where the higher value means higher.
|
||||
precedence = map[string]int{
|
||||
Conditional: 8,
|
||||
LogicalOr: 7,
|
||||
LogicalAnd: 6,
|
||||
Equals: 5,
|
||||
Greater: 5,
|
||||
GreaterEquals: 5,
|
||||
In: 5,
|
||||
Less: 5,
|
||||
LessEquals: 5,
|
||||
NotEquals: 5,
|
||||
OldIn: 5,
|
||||
Add: 4,
|
||||
Subtract: 4,
|
||||
Divide: 3,
|
||||
Modulo: 3,
|
||||
Multiply: 3,
|
||||
LogicalNot: 2,
|
||||
Negate: 2,
|
||||
Index: 1,
|
||||
}
|
||||
)
|
||||
|
||||
// Find the internal function name for an operator, if the input text is one.
|
||||
func Find(text string) (string, bool) {
|
||||
op, found := operators[text]
|
||||
return op, found
|
||||
}
|
||||
|
||||
// FindReverse returns the unmangled, text representation of the operator.
|
||||
func FindReverse(op string) (string, bool) {
|
||||
txt, found := reverseOperators[op]
|
||||
return txt, found
|
||||
}
|
||||
|
||||
// FindReverseBinaryOperator returns the unmangled, text representation of a binary operator.
|
||||
func FindReverseBinaryOperator(op string) (string, bool) {
|
||||
if op == LogicalNot || op == Negate {
|
||||
return "", false
|
||||
}
|
||||
txt, found := reverseOperators[op]
|
||||
return txt, found
|
||||
}
|
||||
|
||||
// Precedence returns the operator precedence, where the higher the number indicates
|
||||
// higher precedence operations.
|
||||
func Precedence(op string) int {
|
||||
p, found := precedence[op]
|
||||
if found {
|
||||
return p
|
||||
}
|
||||
return 0
|
||||
}
|
||||
14
vendor/github.com/google/cel-go/common/overloads/BUILD.bazel
generated
vendored
Normal file
14
vendor/github.com/google/cel-go/common/overloads/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"overloads.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/overloads",
|
||||
)
|
||||
293
vendor/github.com/google/cel-go/common/overloads/overloads.go
generated
vendored
Normal file
293
vendor/github.com/google/cel-go/common/overloads/overloads.go
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
// Copyright 2018 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 overloads defines the internal overload identifiers for function and
|
||||
// operator overloads.
|
||||
package overloads
|
||||
|
||||
// Boolean logic overloads
|
||||
const (
|
||||
Conditional = "conditional"
|
||||
LogicalAnd = "logical_and"
|
||||
LogicalOr = "logical_or"
|
||||
LogicalNot = "logical_not"
|
||||
NotStrictlyFalse = "not_strictly_false"
|
||||
Equals = "equals"
|
||||
NotEquals = "not_equals"
|
||||
LessBool = "less_bool"
|
||||
LessInt64 = "less_int64"
|
||||
LessUint64 = "less_uint64"
|
||||
LessDouble = "less_double"
|
||||
LessString = "less_string"
|
||||
LessBytes = "less_bytes"
|
||||
LessTimestamp = "less_timestamp"
|
||||
LessDuration = "less_duration"
|
||||
LessEqualsBool = "less_equals_bool"
|
||||
LessEqualsInt64 = "less_equals_int64"
|
||||
LessEqualsUint64 = "less_equals_uint64"
|
||||
LessEqualsDouble = "less_equals_double"
|
||||
LessEqualsString = "less_equals_string"
|
||||
LessEqualsBytes = "less_equals_bytes"
|
||||
LessEqualsTimestamp = "less_equals_timestamp"
|
||||
LessEqualsDuration = "less_equals_duration"
|
||||
GreaterBool = "greater_bool"
|
||||
GreaterInt64 = "greater_int64"
|
||||
GreaterUint64 = "greater_uint64"
|
||||
GreaterDouble = "greater_double"
|
||||
GreaterString = "greater_string"
|
||||
GreaterBytes = "greater_bytes"
|
||||
GreaterTimestamp = "greater_timestamp"
|
||||
GreaterDuration = "greater_duration"
|
||||
GreaterEqualsBool = "greater_equals_bool"
|
||||
GreaterEqualsInt64 = "greater_equals_int64"
|
||||
GreaterEqualsUint64 = "greater_equals_uint64"
|
||||
GreaterEqualsDouble = "greater_equals_double"
|
||||
GreaterEqualsString = "greater_equals_string"
|
||||
GreaterEqualsBytes = "greater_equals_bytes"
|
||||
GreaterEqualsTimestamp = "greater_equals_timestamp"
|
||||
GreaterEqualsDuration = "greater_equals_duration"
|
||||
)
|
||||
|
||||
// Math overloads
|
||||
const (
|
||||
AddInt64 = "add_int64"
|
||||
AddUint64 = "add_uint64"
|
||||
AddDouble = "add_double"
|
||||
AddString = "add_string"
|
||||
AddBytes = "add_bytes"
|
||||
AddList = "add_list"
|
||||
AddTimestampDuration = "add_timestamp_duration"
|
||||
AddDurationTimestamp = "add_duration_timestamp"
|
||||
AddDurationDuration = "add_duration_duration"
|
||||
SubtractInt64 = "subtract_int64"
|
||||
SubtractUint64 = "subtract_uint64"
|
||||
SubtractDouble = "subtract_double"
|
||||
SubtractTimestampTimestamp = "subtract_timestamp_timestamp"
|
||||
SubtractTimestampDuration = "subtract_timestamp_duration"
|
||||
SubtractDurationDuration = "subtract_duration_duration"
|
||||
MultiplyInt64 = "multiply_int64"
|
||||
MultiplyUint64 = "multiply_uint64"
|
||||
MultiplyDouble = "multiply_double"
|
||||
DivideInt64 = "divide_int64"
|
||||
DivideUint64 = "divide_uint64"
|
||||
DivideDouble = "divide_double"
|
||||
ModuloInt64 = "modulo_int64"
|
||||
ModuloUint64 = "modulo_uint64"
|
||||
NegateInt64 = "negate_int64"
|
||||
NegateDouble = "negate_double"
|
||||
)
|
||||
|
||||
// Index overloads
|
||||
const (
|
||||
IndexList = "index_list"
|
||||
IndexMap = "index_map"
|
||||
IndexMessage = "index_message" // TODO: introduce concept of types.Message
|
||||
)
|
||||
|
||||
// In operators
|
||||
const (
|
||||
DeprecatedIn = "in"
|
||||
InList = "in_list"
|
||||
InMap = "in_map"
|
||||
InMessage = "in_message" // TODO: introduce concept of types.Message
|
||||
)
|
||||
|
||||
// Size overloads
|
||||
const (
|
||||
Size = "size"
|
||||
SizeString = "size_string"
|
||||
SizeBytes = "size_bytes"
|
||||
SizeList = "size_list"
|
||||
SizeMap = "size_map"
|
||||
SizeStringInst = "string_size"
|
||||
SizeBytesInst = "bytes_size"
|
||||
SizeListInst = "list_size"
|
||||
SizeMapInst = "map_size"
|
||||
)
|
||||
|
||||
// String function names.
|
||||
const (
|
||||
Contains = "contains"
|
||||
EndsWith = "endsWith"
|
||||
Matches = "matches"
|
||||
StartsWith = "startsWith"
|
||||
)
|
||||
|
||||
// String function overload names.
|
||||
const (
|
||||
ContainsString = "contains_string"
|
||||
EndsWithString = "ends_with_string"
|
||||
MatchesString = "matches_string"
|
||||
StartsWithString = "starts_with_string"
|
||||
)
|
||||
|
||||
// Time-based functions.
|
||||
const (
|
||||
TimeGetFullYear = "getFullYear"
|
||||
TimeGetMonth = "getMonth"
|
||||
TimeGetDayOfYear = "getDayOfYear"
|
||||
TimeGetDate = "getDate"
|
||||
TimeGetDayOfMonth = "getDayOfMonth"
|
||||
TimeGetDayOfWeek = "getDayOfWeek"
|
||||
TimeGetHours = "getHours"
|
||||
TimeGetMinutes = "getMinutes"
|
||||
TimeGetSeconds = "getSeconds"
|
||||
TimeGetMilliseconds = "getMilliseconds"
|
||||
)
|
||||
|
||||
// Timestamp overloads for time functions without timezones.
|
||||
const (
|
||||
TimestampToYear = "timestamp_to_year"
|
||||
TimestampToMonth = "timestamp_to_month"
|
||||
TimestampToDayOfYear = "timestamp_to_day_of_year"
|
||||
TimestampToDayOfMonthZeroBased = "timestamp_to_day_of_month"
|
||||
TimestampToDayOfMonthOneBased = "timestamp_to_day_of_month_1_based"
|
||||
TimestampToDayOfWeek = "timestamp_to_day_of_week"
|
||||
TimestampToHours = "timestamp_to_hours"
|
||||
TimestampToMinutes = "timestamp_to_minutes"
|
||||
TimestampToSeconds = "timestamp_to_seconds"
|
||||
TimestampToMilliseconds = "timestamp_to_milliseconds"
|
||||
)
|
||||
|
||||
// Timestamp overloads for time functions with timezones.
|
||||
const (
|
||||
TimestampToYearWithTz = "timestamp_to_year_with_tz"
|
||||
TimestampToMonthWithTz = "timestamp_to_month_with_tz"
|
||||
TimestampToDayOfYearWithTz = "timestamp_to_day_of_year_with_tz"
|
||||
TimestampToDayOfMonthZeroBasedWithTz = "timestamp_to_day_of_month_with_tz"
|
||||
TimestampToDayOfMonthOneBasedWithTz = "timestamp_to_day_of_month_1_based_with_tz"
|
||||
TimestampToDayOfWeekWithTz = "timestamp_to_day_of_week_with_tz"
|
||||
TimestampToHoursWithTz = "timestamp_to_hours_with_tz"
|
||||
TimestampToMinutesWithTz = "timestamp_to_minutes_with_tz"
|
||||
TimestampToSecondsWithTz = "timestamp_to_seconds_tz"
|
||||
TimestampToMillisecondsWithTz = "timestamp_to_milliseconds_with_tz"
|
||||
)
|
||||
|
||||
// Duration overloads for time functions.
|
||||
const (
|
||||
DurationToHours = "duration_to_hours"
|
||||
DurationToMinutes = "duration_to_minutes"
|
||||
DurationToSeconds = "duration_to_seconds"
|
||||
DurationToMilliseconds = "duration_to_milliseconds"
|
||||
)
|
||||
|
||||
// Type conversion methods and overloads
|
||||
const (
|
||||
TypeConvertInt = "int"
|
||||
TypeConvertUint = "uint"
|
||||
TypeConvertDouble = "double"
|
||||
TypeConvertBool = "bool"
|
||||
TypeConvertString = "string"
|
||||
TypeConvertBytes = "bytes"
|
||||
TypeConvertTimestamp = "timestamp"
|
||||
TypeConvertDuration = "duration"
|
||||
TypeConvertType = "type"
|
||||
TypeConvertDyn = "dyn"
|
||||
)
|
||||
|
||||
// Int conversion functions.
|
||||
const (
|
||||
IntToInt = "int64_to_int64"
|
||||
UintToInt = "uint64_to_int64"
|
||||
DoubleToInt = "double_to_int64"
|
||||
StringToInt = "string_to_int64"
|
||||
TimestampToInt = "timestamp_to_int64"
|
||||
DurationToInt = "duration_to_int64"
|
||||
)
|
||||
|
||||
// Uint conversion functions.
|
||||
const (
|
||||
UintToUint = "uint64_to_uint64"
|
||||
IntToUint = "int64_to_uint64"
|
||||
DoubleToUint = "double_to_uint64"
|
||||
StringToUint = "string_to_uint64"
|
||||
)
|
||||
|
||||
// Double conversion functions.
|
||||
const (
|
||||
DoubleToDouble = "double_to_double"
|
||||
IntToDouble = "int64_to_double"
|
||||
UintToDouble = "uint64_to_double"
|
||||
StringToDouble = "string_to_double"
|
||||
)
|
||||
|
||||
// Bool conversion functions.
|
||||
const (
|
||||
BoolToBool = "bool_to_bool"
|
||||
StringToBool = "string_to_bool"
|
||||
)
|
||||
|
||||
// Bytes conversion functions.
|
||||
const (
|
||||
BytesToBytes = "bytes_to_bytes"
|
||||
StringToBytes = "string_to_bytes"
|
||||
)
|
||||
|
||||
// String conversion functions.
|
||||
const (
|
||||
StringToString = "string_to_string"
|
||||
BoolToString = "bool_to_string"
|
||||
IntToString = "int64_to_string"
|
||||
UintToString = "uint64_to_string"
|
||||
DoubleToString = "double_to_string"
|
||||
BytesToString = "bytes_to_string"
|
||||
TimestampToString = "timestamp_to_string"
|
||||
DurationToString = "duration_to_string"
|
||||
)
|
||||
|
||||
// Timestamp conversion functions
|
||||
const (
|
||||
TimestampToTimestamp = "timestamp_to_timestamp"
|
||||
StringToTimestamp = "string_to_timestamp"
|
||||
IntToTimestamp = "int64_to_timestamp"
|
||||
)
|
||||
|
||||
// Convert duration from string
|
||||
const (
|
||||
DurationToDuration = "duration_to_duration"
|
||||
StringToDuration = "string_to_duration"
|
||||
IntToDuration = "int64_to_duration"
|
||||
)
|
||||
|
||||
// Convert to dyn
|
||||
const (
|
||||
ToDyn = "to_dyn"
|
||||
)
|
||||
|
||||
// Comprehensions helper methods, not directly accessible via a developer.
|
||||
const (
|
||||
Iterator = "@iterator"
|
||||
HasNext = "@hasNext"
|
||||
Next = "@next"
|
||||
)
|
||||
|
||||
// IsTypeConversionFunction returns whether the input function is a standard library type
|
||||
// conversion function.
|
||||
func IsTypeConversionFunction(function string) bool {
|
||||
switch function {
|
||||
case TypeConvertBool,
|
||||
TypeConvertBytes,
|
||||
TypeConvertDouble,
|
||||
TypeConvertDuration,
|
||||
TypeConvertDyn,
|
||||
TypeConvertInt,
|
||||
TypeConvertString,
|
||||
TypeConvertTimestamp,
|
||||
TypeConvertType,
|
||||
TypeConvertUint:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
25
vendor/github.com/google/cel-go/common/runes/BUILD.bazel
generated
vendored
Normal file
25
vendor/github.com/google/cel-go/common/runes/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"buffer.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/runes",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"buffer_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
)
|
||||
194
vendor/github.com/google/cel-go/common/runes/buffer.go
generated
vendored
Normal file
194
vendor/github.com/google/cel-go/common/runes/buffer.go
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
// Copyright 2021 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 runes provides interfaces and utilities for working with runes.
|
||||
package runes
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Buffer is an interface for accessing a contiguous array of code points.
|
||||
type Buffer interface {
|
||||
Get(i int) rune
|
||||
Slice(i, j int) string
|
||||
Len() int
|
||||
}
|
||||
|
||||
type emptyBuffer struct{}
|
||||
|
||||
func (e *emptyBuffer) Get(i int) rune {
|
||||
panic("slice index out of bounds")
|
||||
}
|
||||
|
||||
func (e *emptyBuffer) Slice(i, j int) string {
|
||||
if i != 0 || i != j {
|
||||
panic("slice index out of bounds")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *emptyBuffer) Len() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
var _ Buffer = &emptyBuffer{}
|
||||
|
||||
// asciiBuffer is an implementation for an array of code points that contain code points only from
|
||||
// the ASCII character set.
|
||||
type asciiBuffer struct {
|
||||
arr []byte
|
||||
}
|
||||
|
||||
func (a *asciiBuffer) Get(i int) rune {
|
||||
return rune(uint32(a.arr[i]))
|
||||
}
|
||||
|
||||
func (a *asciiBuffer) Slice(i, j int) string {
|
||||
return string(a.arr[i:j])
|
||||
}
|
||||
|
||||
func (a *asciiBuffer) Len() int {
|
||||
return len(a.arr)
|
||||
}
|
||||
|
||||
var _ Buffer = &asciiBuffer{}
|
||||
|
||||
// basicBuffer is an implementation for an array of code points that contain code points from both
|
||||
// the Latin-1 character set and Basic Multilingual Plane.
|
||||
type basicBuffer struct {
|
||||
arr []uint16
|
||||
}
|
||||
|
||||
func (b *basicBuffer) Get(i int) rune {
|
||||
return rune(uint32(b.arr[i]))
|
||||
}
|
||||
|
||||
func (b *basicBuffer) Slice(i, j int) string {
|
||||
var str strings.Builder
|
||||
str.Grow((j - i) * 3) // Worst case encoding size for 0xffff is 3.
|
||||
for ; i < j; i++ {
|
||||
str.WriteRune(rune(uint32(b.arr[i])))
|
||||
}
|
||||
return str.String()
|
||||
}
|
||||
|
||||
func (b *basicBuffer) Len() int {
|
||||
return len(b.arr)
|
||||
}
|
||||
|
||||
var _ Buffer = &basicBuffer{}
|
||||
|
||||
// supplementalBuffer is an implementation for an array of code points that contain code points from
|
||||
// the Latin-1 character set, Basic Multilingual Plane, or the Supplemental Multilingual Plane.
|
||||
type supplementalBuffer struct {
|
||||
arr []rune
|
||||
}
|
||||
|
||||
func (s *supplementalBuffer) Get(i int) rune {
|
||||
return rune(uint32(s.arr[i]))
|
||||
}
|
||||
|
||||
func (s *supplementalBuffer) Slice(i, j int) string {
|
||||
return string(s.arr[i:j])
|
||||
}
|
||||
|
||||
func (s *supplementalBuffer) Len() int {
|
||||
return len(s.arr)
|
||||
}
|
||||
|
||||
var _ Buffer = &supplementalBuffer{}
|
||||
|
||||
var nilBuffer = &emptyBuffer{}
|
||||
|
||||
// NewBuffer returns an efficient implementation of Buffer for the given text based on the ranges of
|
||||
// the encoded code points contained within.
|
||||
//
|
||||
// Code points are represented as an array of byte, uint16, or rune. This approach ensures that
|
||||
// each index represents a code point by itself without needing to use an array of rune. At first
|
||||
// we assume all code points are less than or equal to '\u007f'. If this holds true, the
|
||||
// underlying storage is a byte array containing only ASCII characters. If we encountered a code
|
||||
// point above this range but less than or equal to '\uffff' we allocate a uint16 array, copy the
|
||||
// elements of previous byte array to the uint16 array, and continue. If this holds true, the
|
||||
// underlying storage is a uint16 array containing only Unicode characters in the Basic Multilingual
|
||||
// Plane. If we encounter a code point above '\uffff' we allocate an rune array, copy the previous
|
||||
// elements of the byte or uint16 array, and continue. The underlying storage is an rune array
|
||||
// containing any Unicode character.
|
||||
func NewBuffer(data string) Buffer {
|
||||
if len(data) == 0 {
|
||||
return nilBuffer
|
||||
}
|
||||
var (
|
||||
idx = 0
|
||||
buf8 = make([]byte, 0, len(data))
|
||||
buf16 []uint16
|
||||
buf32 []rune
|
||||
)
|
||||
for idx < len(data) {
|
||||
r, s := utf8.DecodeRuneInString(data[idx:])
|
||||
idx += s
|
||||
if r < utf8.RuneSelf {
|
||||
buf8 = append(buf8, byte(r))
|
||||
continue
|
||||
}
|
||||
if r <= 0xffff {
|
||||
buf16 = make([]uint16, len(buf8), len(data))
|
||||
for i, v := range buf8 {
|
||||
buf16[i] = uint16(v)
|
||||
}
|
||||
buf8 = nil
|
||||
buf16 = append(buf16, uint16(r))
|
||||
goto copy16
|
||||
}
|
||||
buf32 = make([]rune, len(buf8), len(data))
|
||||
for i, v := range buf8 {
|
||||
buf32[i] = rune(uint32(v))
|
||||
}
|
||||
buf8 = nil
|
||||
buf32 = append(buf32, r)
|
||||
goto copy32
|
||||
}
|
||||
return &asciiBuffer{
|
||||
arr: buf8,
|
||||
}
|
||||
copy16:
|
||||
for idx < len(data) {
|
||||
r, s := utf8.DecodeRuneInString(data[idx:])
|
||||
idx += s
|
||||
if r <= 0xffff {
|
||||
buf16 = append(buf16, uint16(r))
|
||||
continue
|
||||
}
|
||||
buf32 = make([]rune, len(buf16), len(data))
|
||||
for i, v := range buf16 {
|
||||
buf32[i] = rune(uint32(v))
|
||||
}
|
||||
buf16 = nil
|
||||
buf32 = append(buf32, r)
|
||||
goto copy32
|
||||
}
|
||||
return &basicBuffer{
|
||||
arr: buf16,
|
||||
}
|
||||
copy32:
|
||||
for idx < len(data) {
|
||||
r, s := utf8.DecodeRuneInString(data[idx:])
|
||||
idx += s
|
||||
buf32 = append(buf32, r)
|
||||
}
|
||||
return &supplementalBuffer{
|
||||
arr: buf32,
|
||||
}
|
||||
}
|
||||
186
vendor/github.com/google/cel-go/common/source.go
generated
vendored
Normal file
186
vendor/github.com/google/cel-go/common/source.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright 2018 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 common
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/google/cel-go/common/runes"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Source interface for filter source contents.
|
||||
type Source interface {
|
||||
// Content returns the source content represented as a string.
|
||||
// Examples contents are the single file contents, textbox field,
|
||||
// or url parameter.
|
||||
Content() string
|
||||
|
||||
// Description gives a brief description of the source.
|
||||
// Example descriptions are a file name or ui element.
|
||||
Description() string
|
||||
|
||||
// LineOffsets gives the character offsets at which lines occur.
|
||||
// The zero-th entry should refer to the break between the first
|
||||
// and second line, or EOF if there is only one line of source.
|
||||
LineOffsets() []int32
|
||||
|
||||
// LocationOffset translates a Location to an offset.
|
||||
// Given the line and column of the Location returns the
|
||||
// Location's character offset in the Source, and a bool
|
||||
// indicating whether the Location was found.
|
||||
LocationOffset(location Location) (int32, bool)
|
||||
|
||||
// OffsetLocation translates a character offset to a Location, or
|
||||
// false if the conversion was not feasible.
|
||||
OffsetLocation(offset int32) (Location, bool)
|
||||
|
||||
// NewLocation takes an input line and column and produces a Location.
|
||||
// The default behavior is to treat the line and column as absolute,
|
||||
// but concrete derivations may use this method to convert a relative
|
||||
// line and column position into an absolute location.
|
||||
NewLocation(line, col int) Location
|
||||
|
||||
// Snippet returns a line of content and whether the line was found.
|
||||
Snippet(line int) (string, bool)
|
||||
}
|
||||
|
||||
// The sourceImpl type implementation of the Source interface.
|
||||
type sourceImpl struct {
|
||||
runes.Buffer
|
||||
description string
|
||||
lineOffsets []int32
|
||||
idOffsets map[int64]int32
|
||||
}
|
||||
|
||||
var _ runes.Buffer = &sourceImpl{}
|
||||
|
||||
// TODO(jimlarson) "Character offsets" should index the code points
|
||||
// within the UTF-8 encoded string. It currently indexes bytes.
|
||||
// Can be accomplished by using rune[] instead of string for contents.
|
||||
|
||||
// NewTextSource creates a new Source from the input text string.
|
||||
func NewTextSource(text string) Source {
|
||||
return NewStringSource(text, "<input>")
|
||||
}
|
||||
|
||||
// NewStringSource creates a new Source from the given contents and description.
|
||||
func NewStringSource(contents string, description string) Source {
|
||||
// Compute line offsets up front as they are referred to frequently.
|
||||
lines := strings.Split(contents, "\n")
|
||||
offsets := make([]int32, len(lines))
|
||||
var offset int32
|
||||
for i, line := range lines {
|
||||
offset = offset + int32(utf8.RuneCountInString(line)) + 1
|
||||
offsets[int32(i)] = offset
|
||||
}
|
||||
return &sourceImpl{
|
||||
Buffer: runes.NewBuffer(contents),
|
||||
description: description,
|
||||
lineOffsets: offsets,
|
||||
idOffsets: map[int64]int32{},
|
||||
}
|
||||
}
|
||||
|
||||
// NewInfoSource creates a new Source from a SourceInfo.
|
||||
func NewInfoSource(info *exprpb.SourceInfo) Source {
|
||||
return &sourceImpl{
|
||||
Buffer: runes.NewBuffer(""),
|
||||
description: info.GetLocation(),
|
||||
lineOffsets: info.GetLineOffsets(),
|
||||
idOffsets: info.GetPositions(),
|
||||
}
|
||||
}
|
||||
|
||||
// Content implements the Source interface method.
|
||||
func (s *sourceImpl) Content() string {
|
||||
return s.Slice(0, s.Len())
|
||||
}
|
||||
|
||||
// Description implements the Source interface method.
|
||||
func (s *sourceImpl) Description() string {
|
||||
return s.description
|
||||
}
|
||||
|
||||
// LineOffsets implements the Source interface method.
|
||||
func (s *sourceImpl) LineOffsets() []int32 {
|
||||
return s.lineOffsets
|
||||
}
|
||||
|
||||
// LocationOffset implements the Source interface method.
|
||||
func (s *sourceImpl) LocationOffset(location Location) (int32, bool) {
|
||||
if lineOffset, found := s.findLineOffset(location.Line()); found {
|
||||
return lineOffset + int32(location.Column()), true
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
// NewLocation implements the Source interface method.
|
||||
func (s *sourceImpl) NewLocation(line, col int) Location {
|
||||
return NewLocation(line, col)
|
||||
}
|
||||
|
||||
// OffsetLocation implements the Source interface method.
|
||||
func (s *sourceImpl) OffsetLocation(offset int32) (Location, bool) {
|
||||
line, lineOffset := s.findLine(offset)
|
||||
return NewLocation(int(line), int(offset-lineOffset)), true
|
||||
}
|
||||
|
||||
// Snippet implements the Source interface method.
|
||||
func (s *sourceImpl) Snippet(line int) (string, bool) {
|
||||
charStart, found := s.findLineOffset(line)
|
||||
if !found || s.Len() == 0 {
|
||||
return "", false
|
||||
}
|
||||
charEnd, found := s.findLineOffset(line + 1)
|
||||
if found {
|
||||
return s.Slice(int(charStart), int(charEnd-1)), true
|
||||
}
|
||||
return s.Slice(int(charStart), s.Len()), true
|
||||
}
|
||||
|
||||
// findLineOffset returns the offset where the (1-indexed) line begins,
|
||||
// or false if line doesn't exist.
|
||||
func (s *sourceImpl) findLineOffset(line int) (int32, bool) {
|
||||
if line == 1 {
|
||||
return 0, true
|
||||
}
|
||||
if line > 1 && line <= int(len(s.lineOffsets)) {
|
||||
offset := s.lineOffsets[line-2]
|
||||
return offset, true
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
// findLine finds the line that contains the given character offset and
|
||||
// returns the line number and offset of the beginning of that line.
|
||||
// Note that the last line is treated as if it contains all offsets
|
||||
// beyond the end of the actual source.
|
||||
func (s *sourceImpl) findLine(characterOffset int32) (int32, int32) {
|
||||
var line int32 = 1
|
||||
for _, lineOffset := range s.lineOffsets {
|
||||
if lineOffset > characterOffset {
|
||||
break
|
||||
} else {
|
||||
line++
|
||||
}
|
||||
}
|
||||
if line == 1 {
|
||||
return line, 0
|
||||
}
|
||||
return line, s.lineOffsets[line-2]
|
||||
}
|
||||
84
vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
Normal file
84
vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"any_value.go",
|
||||
"bool.go",
|
||||
"bytes.go",
|
||||
"double.go",
|
||||
"duration.go",
|
||||
"err.go",
|
||||
"int.go",
|
||||
"iterator.go",
|
||||
"json_value.go",
|
||||
"list.go",
|
||||
"map.go",
|
||||
"null.go",
|
||||
"object.go",
|
||||
"overflow.go",
|
||||
"provider.go",
|
||||
"string.go",
|
||||
"timestamp.go",
|
||||
"type.go",
|
||||
"uint.go",
|
||||
"unknown.go",
|
||||
"util.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/types",
|
||||
deps = [
|
||||
"//common/overloads:go_default_library",
|
||||
"//common/types/pb:go_default_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_protobuf//encoding/protojson: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/anypb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"bool_test.go",
|
||||
"bytes_test.go",
|
||||
"double_test.go",
|
||||
"duration_test.go",
|
||||
"int_test.go",
|
||||
"json_list_test.go",
|
||||
"json_struct_test.go",
|
||||
"list_test.go",
|
||||
"map_test.go",
|
||||
"null_test.go",
|
||||
"object_test.go",
|
||||
"provider_test.go",
|
||||
"string_test.go",
|
||||
"timestamp_test.go",
|
||||
"type_test.go",
|
||||
"uint_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//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_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",
|
||||
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
|
||||
],
|
||||
)
|
||||
24
vendor/github.com/google/cel-go/common/types/any_value.go
generated
vendored
Normal file
24
vendor/github.com/google/cel-go/common/types/any_value.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018 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 (
|
||||
"reflect"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
)
|
||||
|
||||
// anyValueType constant representing the reflected type of google.protobuf.Any.
|
||||
var anyValueType = reflect.TypeOf(&anypb.Any{})
|
||||
144
vendor/github.com/google/cel-go/common/types/bool.go
generated
vendored
Normal file
144
vendor/github.com/google/cel-go/common/types/bool.go
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
// Bool type that implements ref.Val and supports comparison and negation.
|
||||
type Bool bool
|
||||
|
||||
var (
|
||||
// BoolType singleton.
|
||||
BoolType = NewTypeValue("bool",
|
||||
traits.ComparerType,
|
||||
traits.NegatorType)
|
||||
|
||||
// boolWrapperType golang reflected type for protobuf bool wrapper type.
|
||||
boolWrapperType = reflect.TypeOf(&wrapperspb.BoolValue{})
|
||||
)
|
||||
|
||||
// Boolean constants
|
||||
const (
|
||||
False = Bool(false)
|
||||
True = Bool(true)
|
||||
)
|
||||
|
||||
// Compare implements the traits.Comparer interface method.
|
||||
func (b Bool) Compare(other ref.Val) ref.Val {
|
||||
otherBool, ok := other.(Bool)
|
||||
if !ok {
|
||||
return ValOrErr(other, "no such overload")
|
||||
}
|
||||
if b == otherBool {
|
||||
return IntZero
|
||||
}
|
||||
if !b && otherBool {
|
||||
return IntNegOne
|
||||
}
|
||||
return IntOne
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (b Bool) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Bool:
|
||||
return reflect.ValueOf(b).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Ptr:
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
// Primitives must be wrapped to a wrapperspb.BoolValue before being packed into an Any.
|
||||
return anypb.New(wrapperspb.Bool(bool(b)))
|
||||
case boolWrapperType:
|
||||
// Convert the bool to a wrapperspb.BoolValue.
|
||||
return wrapperspb.Bool(bool(b)), nil
|
||||
case jsonValueType:
|
||||
// Return the bool as a new structpb.Value.
|
||||
return structpb.NewBoolValue(bool(b)), nil
|
||||
default:
|
||||
if typeDesc.Elem().Kind() == reflect.Bool {
|
||||
p := bool(b)
|
||||
return &p, nil
|
||||
}
|
||||
}
|
||||
case reflect.Interface:
|
||||
bv := b.Value()
|
||||
if reflect.TypeOf(bv).Implements(typeDesc) {
|
||||
return bv, nil
|
||||
}
|
||||
if reflect.TypeOf(b).Implements(typeDesc) {
|
||||
return b, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("type conversion error from bool to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements the ref.Val interface method.
|
||||
func (b Bool) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case StringType:
|
||||
return String(strconv.FormatBool(bool(b)))
|
||||
case BoolType:
|
||||
return b
|
||||
case TypeType:
|
||||
return BoolType
|
||||
}
|
||||
return NewErr("type conversion error from '%v' to '%v'", BoolType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements the ref.Val interface method.
|
||||
func (b Bool) Equal(other ref.Val) ref.Val {
|
||||
otherBool, ok := other.(Bool)
|
||||
if !ok {
|
||||
return ValOrErr(other, "no such overload")
|
||||
}
|
||||
return Bool(b == otherBool)
|
||||
}
|
||||
|
||||
// Negate implements the traits.Negater interface method.
|
||||
func (b Bool) Negate() ref.Val {
|
||||
return !b
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (b Bool) Type() ref.Type {
|
||||
return BoolType
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (b Bool) Value() interface{} {
|
||||
return bool(b)
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
return false
|
||||
}
|
||||
135
vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
Normal file
135
vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright 2018 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 (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
// Bytes type that implements ref.Val and supports add, compare, and size
|
||||
// operations.
|
||||
type Bytes []byte
|
||||
|
||||
var (
|
||||
// BytesType singleton.
|
||||
BytesType = NewTypeValue("bytes",
|
||||
traits.AdderType,
|
||||
traits.ComparerType,
|
||||
traits.SizerType)
|
||||
|
||||
// byteWrapperType golang reflected type for protobuf bytes wrapper type.
|
||||
byteWrapperType = reflect.TypeOf(&wrapperspb.BytesValue{})
|
||||
)
|
||||
|
||||
// Add implements traits.Adder interface method by concatenating byte sequences.
|
||||
func (b Bytes) Add(other ref.Val) ref.Val {
|
||||
otherBytes, ok := other.(Bytes)
|
||||
if !ok {
|
||||
return ValOrErr(other, "no such overload")
|
||||
}
|
||||
return append(b, otherBytes...)
|
||||
}
|
||||
|
||||
// Compare implments traits.Comparer interface method by lexicographic ordering.
|
||||
func (b Bytes) Compare(other ref.Val) ref.Val {
|
||||
otherBytes, ok := other.(Bytes)
|
||||
if !ok {
|
||||
return ValOrErr(other, "no such overload")
|
||||
}
|
||||
return Int(bytes.Compare(b, otherBytes))
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (b Bytes) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return reflect.ValueOf(b).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Ptr:
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
// Primitives must be wrapped before being set on an Any field.
|
||||
return anypb.New(wrapperspb.Bytes([]byte(b)))
|
||||
case byteWrapperType:
|
||||
// Convert the bytes to a wrapperspb.BytesValue.
|
||||
return wrapperspb.Bytes([]byte(b)), nil
|
||||
case jsonValueType:
|
||||
// CEL follows the proto3 to JSON conversion by encoding bytes to a string via base64.
|
||||
// The encoding below matches the golang 'encoding/json' behavior during marshaling,
|
||||
// which uses base64.StdEncoding.
|
||||
str := base64.StdEncoding.EncodeToString([]byte(b))
|
||||
return structpb.NewStringValue(str), nil
|
||||
}
|
||||
case reflect.Interface:
|
||||
bv := b.Value()
|
||||
if reflect.TypeOf(bv).Implements(typeDesc) {
|
||||
return bv, nil
|
||||
}
|
||||
if reflect.TypeOf(b).Implements(typeDesc) {
|
||||
return b, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("type conversion error from Bytes to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements the ref.Val interface method.
|
||||
func (b Bytes) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case StringType:
|
||||
if !utf8.Valid(b) {
|
||||
return NewErr("invalid UTF-8 in bytes, cannot convert to string")
|
||||
}
|
||||
return String(b)
|
||||
case BytesType:
|
||||
return b
|
||||
case TypeType:
|
||||
return BytesType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", BytesType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements the ref.Val interface method.
|
||||
func (b Bytes) Equal(other ref.Val) ref.Val {
|
||||
otherBytes, ok := other.(Bytes)
|
||||
if !ok {
|
||||
return ValOrErr(other, "no such overload")
|
||||
}
|
||||
return Bool(bytes.Equal(b, otherBytes))
|
||||
}
|
||||
|
||||
// Size implements the traits.Sizer interface method.
|
||||
func (b Bytes) Size() ref.Val {
|
||||
return Int(len(b))
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (b Bytes) Type() ref.Type {
|
||||
return BytesType
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (b Bytes) Value() interface{} {
|
||||
return []byte(b)
|
||||
}
|
||||
17
vendor/github.com/google/cel-go/common/types/doc.go
generated
vendored
Normal file
17
vendor/github.com/google/cel-go/common/types/doc.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2018 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 contains the types, traits, and utilities common to all
|
||||
// components of expression handling.
|
||||
package types
|
||||
200
vendor/github.com/google/cel-go/common/types/double.go
generated
vendored
Normal file
200
vendor/github.com/google/cel-go/common/types/double.go
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
// Double type that implements ref.Val, comparison, and mathematical
|
||||
// operations.
|
||||
type Double float64
|
||||
|
||||
var (
|
||||
// DoubleType singleton.
|
||||
DoubleType = NewTypeValue("double",
|
||||
traits.AdderType,
|
||||
traits.ComparerType,
|
||||
traits.DividerType,
|
||||
traits.MultiplierType,
|
||||
traits.NegatorType,
|
||||
traits.SubtractorType)
|
||||
|
||||
// doubleWrapperType reflected type for protobuf double wrapper type.
|
||||
doubleWrapperType = reflect.TypeOf(&wrapperspb.DoubleValue{})
|
||||
|
||||
// floatWrapperType reflected type for protobuf float wrapper type.
|
||||
floatWrapperType = reflect.TypeOf(&wrapperspb.FloatValue{})
|
||||
)
|
||||
|
||||
// Add implements traits.Adder.Add.
|
||||
func (d Double) Add(other ref.Val) ref.Val {
|
||||
otherDouble, ok := other.(Double)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return d + otherDouble
|
||||
}
|
||||
|
||||
// Compare implements traits.Comparer.Compare.
|
||||
func (d Double) Compare(other ref.Val) ref.Val {
|
||||
otherDouble, ok := other.(Double)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
if d < otherDouble {
|
||||
return IntNegOne
|
||||
}
|
||||
if d > otherDouble {
|
||||
return IntOne
|
||||
}
|
||||
return IntZero
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (d Double) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Float32:
|
||||
v := float32(d)
|
||||
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Float64:
|
||||
v := float64(d)
|
||||
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Ptr:
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
// Primitives must be wrapped before being set on an Any field.
|
||||
return anypb.New(wrapperspb.Double(float64(d)))
|
||||
case doubleWrapperType:
|
||||
// Convert to a wrapperspb.DoubleValue
|
||||
return wrapperspb.Double(float64(d)), nil
|
||||
case floatWrapperType:
|
||||
// Convert to a wrapperspb.FloatValue (with truncation).
|
||||
return wrapperspb.Float(float32(d)), nil
|
||||
case jsonValueType:
|
||||
// Note, there are special cases for proto3 to json conversion that
|
||||
// expect the floating point value to be converted to a NaN,
|
||||
// Infinity, or -Infinity string values, but the jsonpb string
|
||||
// marshaling of the protobuf.Value will handle this conversion.
|
||||
return structpb.NewNumberValue(float64(d)), nil
|
||||
}
|
||||
switch typeDesc.Elem().Kind() {
|
||||
case reflect.Float32:
|
||||
v := float32(d)
|
||||
p := reflect.New(typeDesc.Elem())
|
||||
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
|
||||
return p.Interface(), nil
|
||||
case reflect.Float64:
|
||||
v := float64(d)
|
||||
p := reflect.New(typeDesc.Elem())
|
||||
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
|
||||
return p.Interface(), nil
|
||||
}
|
||||
case reflect.Interface:
|
||||
dv := d.Value()
|
||||
if reflect.TypeOf(dv).Implements(typeDesc) {
|
||||
return dv, nil
|
||||
}
|
||||
if reflect.TypeOf(d).Implements(typeDesc) {
|
||||
return d, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("type conversion error from Double to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (d Double) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case IntType:
|
||||
i, err := doubleToInt64Checked(float64(d))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Int(i)
|
||||
case UintType:
|
||||
i, err := doubleToUint64Checked(float64(d))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Uint(i)
|
||||
case DoubleType:
|
||||
return d
|
||||
case StringType:
|
||||
return String(fmt.Sprintf("%g", float64(d)))
|
||||
case TypeType:
|
||||
return DoubleType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", DoubleType, typeVal)
|
||||
}
|
||||
|
||||
// Divide implements traits.Divider.Divide.
|
||||
func (d Double) Divide(other ref.Val) ref.Val {
|
||||
otherDouble, ok := other.(Double)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return d / otherDouble
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (d Double) Equal(other ref.Val) ref.Val {
|
||||
otherDouble, ok := other.(Double)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
// TODO: Handle NaNs properly.
|
||||
return Bool(d == otherDouble)
|
||||
}
|
||||
|
||||
// Multiply implements traits.Multiplier.Multiply.
|
||||
func (d Double) Multiply(other ref.Val) ref.Val {
|
||||
otherDouble, ok := other.(Double)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return d * otherDouble
|
||||
}
|
||||
|
||||
// Negate implements traits.Negater.Negate.
|
||||
func (d Double) Negate() ref.Val {
|
||||
return -d
|
||||
}
|
||||
|
||||
// Subtract implements traits.Subtractor.Subtract.
|
||||
func (d Double) Subtract(subtrahend ref.Val) ref.Val {
|
||||
subtraDouble, ok := subtrahend.(Double)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(subtrahend)
|
||||
}
|
||||
return d - subtraDouble
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (d Double) Type() ref.Type {
|
||||
return DoubleType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (d Double) Value() interface{} {
|
||||
return float64(d)
|
||||
}
|
||||
202
vendor/github.com/google/cel-go/common/types/duration.go
generated
vendored
Normal file
202
vendor/github.com/google/cel-go/common/types/duration.go
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
dpb "google.golang.org/protobuf/types/known/durationpb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// Duration type that implements ref.Val and supports add, compare, negate,
|
||||
// and subtract operators. This type is also a receiver which means it can
|
||||
// participate in dispatch to receiver functions.
|
||||
type Duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func durationOf(d time.Duration) Duration {
|
||||
return Duration{Duration: d}
|
||||
}
|
||||
|
||||
var (
|
||||
// DurationType singleton.
|
||||
DurationType = NewTypeValue("google.protobuf.Duration",
|
||||
traits.AdderType,
|
||||
traits.ComparerType,
|
||||
traits.NegatorType,
|
||||
traits.ReceiverType,
|
||||
traits.SubtractorType)
|
||||
)
|
||||
|
||||
// Add implements traits.Adder.Add.
|
||||
func (d Duration) Add(other ref.Val) ref.Val {
|
||||
switch other.Type() {
|
||||
case DurationType:
|
||||
dur2 := other.(Duration)
|
||||
val, err := addDurationChecked(d.Duration, dur2.Duration)
|
||||
if err != nil {
|
||||
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 timestampOf(val)
|
||||
}
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
|
||||
// Compare implements traits.Comparer.Compare.
|
||||
func (d Duration) Compare(other ref.Val) ref.Val {
|
||||
otherDur, ok := other.(Duration)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
d1 := d.Duration
|
||||
d2 := otherDur.Duration
|
||||
switch {
|
||||
case d1 < d2:
|
||||
return IntNegOne
|
||||
case d1 > d2:
|
||||
return IntOne
|
||||
default:
|
||||
return IntZero
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (d Duration) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
// If the duration is already assignable to the desired type return it.
|
||||
if reflect.TypeOf(d.Duration).AssignableTo(typeDesc) {
|
||||
return d.Duration, nil
|
||||
}
|
||||
if reflect.TypeOf(d).AssignableTo(typeDesc) {
|
||||
return d, nil
|
||||
}
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
// Pack the duration as a dpb.Duration into an Any value.
|
||||
return anypb.New(dpb.New(d.Duration))
|
||||
case durationValueType:
|
||||
// Unwrap the CEL value to its underlying proto value.
|
||||
return dpb.New(d.Duration), nil
|
||||
case jsonValueType:
|
||||
// CEL follows the proto3 to JSON conversion.
|
||||
// Note, using jsonpb would wrap the result in extra double quotes.
|
||||
v := d.ConvertToType(StringType)
|
||||
if IsError(v) {
|
||||
return nil, v.(*Err)
|
||||
}
|
||||
return structpb.NewStringValue(string(v.(String))), nil
|
||||
}
|
||||
return nil, fmt.Errorf("type conversion error from 'Duration' to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (d Duration) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case StringType:
|
||||
return String(strconv.FormatFloat(d.Seconds(), 'f', -1, 64) + "s")
|
||||
case IntType:
|
||||
return Int(d.Duration)
|
||||
case DurationType:
|
||||
return d
|
||||
case TypeType:
|
||||
return DurationType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", DurationType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (d Duration) Equal(other ref.Val) ref.Val {
|
||||
otherDur, ok := other.(Duration)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return Bool(d.Duration == otherDur.Duration)
|
||||
}
|
||||
|
||||
// Negate implements traits.Negater.Negate.
|
||||
func (d Duration) Negate() ref.Val {
|
||||
val, err := negateDurationChecked(d.Duration)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return durationOf(val)
|
||||
}
|
||||
|
||||
// Receive implements traits.Receiver.Receive.
|
||||
func (d Duration) Receive(function string, overload string, args []ref.Val) ref.Val {
|
||||
if len(args) == 0 {
|
||||
if f, found := durationZeroArgOverloads[function]; found {
|
||||
return f(d.Duration)
|
||||
}
|
||||
}
|
||||
return NoSuchOverloadErr()
|
||||
}
|
||||
|
||||
// Subtract implements traits.Subtractor.Subtract.
|
||||
func (d Duration) Subtract(subtrahend ref.Val) ref.Val {
|
||||
subtraDur, ok := subtrahend.(Duration)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(subtrahend)
|
||||
}
|
||||
val, err := subtractDurationChecked(d.Duration, subtraDur.Duration)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return durationOf(val)
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (d Duration) Type() ref.Type {
|
||||
return DurationType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (d Duration) Value() interface{} {
|
||||
return d.Duration
|
||||
}
|
||||
|
||||
var (
|
||||
durationValueType = reflect.TypeOf(&dpb.Duration{})
|
||||
|
||||
durationZeroArgOverloads = map[string]func(time.Duration) ref.Val{
|
||||
overloads.TimeGetHours: func(dur time.Duration) ref.Val {
|
||||
return Int(dur.Hours())
|
||||
},
|
||||
overloads.TimeGetMinutes: func(dur time.Duration) ref.Val {
|
||||
return Int(dur.Minutes())
|
||||
},
|
||||
overloads.TimeGetSeconds: func(dur time.Duration) ref.Val {
|
||||
return Int(dur.Seconds())
|
||||
},
|
||||
overloads.TimeGetMilliseconds: func(dur time.Duration) ref.Val {
|
||||
return Int(dur.Milliseconds())
|
||||
}}
|
||||
)
|
||||
130
vendor/github.com/google/cel-go/common/types/err.go
generated
vendored
Normal file
130
vendor/github.com/google/cel-go/common/types/err.go
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2018 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"
|
||||
)
|
||||
|
||||
// Err type which extends the built-in go error and implements ref.Val.
|
||||
type Err struct {
|
||||
error
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrType singleton.
|
||||
ErrType = NewTypeValue("error")
|
||||
|
||||
// errDivideByZero is an error indicating a division by zero of an integer value.
|
||||
errDivideByZero = errors.New("division by zero")
|
||||
// errModulusByZero is an error indicating a modulus by zero of an integer value.
|
||||
errModulusByZero = errors.New("modulus by zero")
|
||||
// errIntOverflow is an error representing integer overflow.
|
||||
errIntOverflow = errors.New("integer overflow")
|
||||
// errUintOverflow is an error representing unsigned integer overflow.
|
||||
errUintOverflow = errors.New("unsigned integer overflow")
|
||||
// errDurationOverflow is an error representing duration overflow.
|
||||
errDurationOverflow = errors.New("duration overflow")
|
||||
// errTimestampOverflow is an error representing timestamp overflow.
|
||||
errTimestampOverflow = errors.New("timestamp overflow")
|
||||
celErrTimestampOverflow = &Err{error: errTimestampOverflow}
|
||||
|
||||
// celErrNoSuchOverload indicates that the call arguments did not match a supported method signature.
|
||||
celErrNoSuchOverload = NewErr("no such overload")
|
||||
)
|
||||
|
||||
// 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 {
|
||||
return &Err{fmt.Errorf(format, args...)}
|
||||
}
|
||||
|
||||
// NoSuchOverloadErr returns a new types.Err instance with a no such overload message.
|
||||
func NoSuchOverloadErr() ref.Val {
|
||||
return celErrNoSuchOverload
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return NewErr("unsupported conversion to ref.Val: (%T)%v", val, val)
|
||||
}
|
||||
|
||||
// MaybeNoSuchOverloadErr returns the error or unknown if the input ref.Val is one of these types,
|
||||
// else a new no such overload error.
|
||||
func MaybeNoSuchOverloadErr(val ref.Val) ref.Val {
|
||||
return ValOrErr(val, "no such overload")
|
||||
}
|
||||
|
||||
// ValOrErr either returns the existing error or create 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 {
|
||||
if val == nil {
|
||||
return NewErr(format, args...)
|
||||
}
|
||||
switch val.Type() {
|
||||
case ErrType, UnknownType:
|
||||
return val
|
||||
default:
|
||||
return NewErr(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return nil, e.error
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (e *Err) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
// Errors are not convertible to other representations.
|
||||
return e
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (e *Err) Equal(other ref.Val) ref.Val {
|
||||
// An error cannot be equal to any other value, so it returns itself.
|
||||
return e
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (e *Err) String() string {
|
||||
return e.error.Error()
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (e *Err) Type() ref.Type {
|
||||
return ErrType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (e *Err) Value() interface{} {
|
||||
return e.error
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
286
vendor/github.com/google/cel-go/common/types/int.go
generated
vendored
Normal file
286
vendor/github.com/google/cel-go/common/types/int.go
generated
vendored
Normal file
@@ -0,0 +1,286 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
// Int type that implements ref.Val as well as comparison and math operators.
|
||||
type Int int64
|
||||
|
||||
// Int constants used for comparison results.
|
||||
const (
|
||||
// IntZero is the zero-value for Int
|
||||
IntZero = Int(0)
|
||||
IntOne = Int(1)
|
||||
IntNegOne = Int(-1)
|
||||
)
|
||||
|
||||
var (
|
||||
// IntType singleton.
|
||||
IntType = NewTypeValue("int",
|
||||
traits.AdderType,
|
||||
traits.ComparerType,
|
||||
traits.DividerType,
|
||||
traits.ModderType,
|
||||
traits.MultiplierType,
|
||||
traits.NegatorType,
|
||||
traits.SubtractorType)
|
||||
|
||||
// int32WrapperType reflected type for protobuf int32 wrapper type.
|
||||
int32WrapperType = reflect.TypeOf(&wrapperspb.Int32Value{})
|
||||
|
||||
// int64WrapperType reflected type for protobuf int64 wrapper type.
|
||||
int64WrapperType = reflect.TypeOf(&wrapperspb.Int64Value{})
|
||||
)
|
||||
|
||||
// Add implements traits.Adder.Add.
|
||||
func (i Int) Add(other ref.Val) ref.Val {
|
||||
otherInt, ok := other.(Int)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
val, err := addInt64Checked(int64(i), int64(otherInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
|
||||
// Compare implements traits.Comparer.Compare.
|
||||
func (i Int) Compare(other ref.Val) ref.Val {
|
||||
otherInt, ok := other.(Int)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
if i < otherInt {
|
||||
return IntNegOne
|
||||
}
|
||||
if i > otherInt {
|
||||
return IntOne
|
||||
}
|
||||
return IntZero
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (i Int) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Int, reflect.Int32:
|
||||
// Enums are also mapped as int32 derivations.
|
||||
// Note, the code doesn't convert to the enum value directly since this is not known, but
|
||||
// the net effect with respect to proto-assignment is handled correctly by the reflection
|
||||
// Convert method.
|
||||
v, err := int64ToInt32Checked(int64(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Int64:
|
||||
return reflect.ValueOf(i).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Ptr:
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
// Primitives must be wrapped before being set on an Any field.
|
||||
return anypb.New(wrapperspb.Int64(int64(i)))
|
||||
case int32WrapperType:
|
||||
// Convert the value to a wrapperspb.Int32Value, error on overflow.
|
||||
v, err := int64ToInt32Checked(int64(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wrapperspb.Int32(v), nil
|
||||
case int64WrapperType:
|
||||
// Convert the value to a wrapperspb.Int64Value.
|
||||
return wrapperspb.Int64(int64(i)), nil
|
||||
case jsonValueType:
|
||||
// The proto-to-JSON conversion rules would convert all 64-bit integer values to JSON
|
||||
// decimal strings. Because CEL ints might come from the automatic widening of 32-bit
|
||||
// values in protos, the JSON type is chosen dynamically based on the value.
|
||||
//
|
||||
// - Integers -2^53-1 < n < 2^53-1 are encoded as JSON numbers.
|
||||
// - Integers outside this range are encoded as JSON strings.
|
||||
//
|
||||
// The integer to float range represents the largest interval where such a conversion
|
||||
// can round-trip accurately. Thus, conversions from a 32-bit source can expect a JSON
|
||||
// number as with protobuf. Those consuming JSON from a 64-bit source must be able to
|
||||
// handle either a JSON number or a JSON decimal string. To handle these cases safely
|
||||
// the string values must be explicitly converted to int() within a CEL expression;
|
||||
// however, it is best to simply stay within the JSON number range when building JSON
|
||||
// objects in CEL.
|
||||
if i.isJSONSafe() {
|
||||
return structpb.NewNumberValue(float64(i)), nil
|
||||
}
|
||||
// Proto3 to JSON conversion requires string-formatted int64 values
|
||||
// since the conversion to floating point would result in truncation.
|
||||
return structpb.NewStringValue(strconv.FormatInt(int64(i), 10)), nil
|
||||
}
|
||||
switch typeDesc.Elem().Kind() {
|
||||
case reflect.Int32:
|
||||
// Convert the value to a wrapperspb.Int32Value, error on overflow.
|
||||
v, err := int64ToInt32Checked(int64(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := reflect.New(typeDesc.Elem())
|
||||
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
|
||||
return p.Interface(), nil
|
||||
case reflect.Int64:
|
||||
v := int64(i)
|
||||
p := reflect.New(typeDesc.Elem())
|
||||
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
|
||||
return p.Interface(), nil
|
||||
}
|
||||
case reflect.Interface:
|
||||
iv := i.Value()
|
||||
if reflect.TypeOf(iv).Implements(typeDesc) {
|
||||
return iv, nil
|
||||
}
|
||||
if reflect.TypeOf(i).Implements(typeDesc) {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported type conversion from 'int' to %v", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (i Int) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case IntType:
|
||||
return i
|
||||
case UintType:
|
||||
u, err := int64ToUint64Checked(int64(i))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Uint(u)
|
||||
case DoubleType:
|
||||
return Double(i)
|
||||
case StringType:
|
||||
return String(fmt.Sprintf("%d", int64(i)))
|
||||
case TimestampType:
|
||||
// The maximum positive value that can be passed to time.Unix is math.MaxInt64 minus the number
|
||||
// of seconds between year 1 and year 1970. See comments on unixToInternal.
|
||||
if int64(i) < minUnixTime || int64(i) > maxUnixTime {
|
||||
return celErrTimestampOverflow
|
||||
}
|
||||
return timestampOf(time.Unix(int64(i), 0).UTC())
|
||||
case TypeType:
|
||||
return IntType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", IntType, typeVal)
|
||||
}
|
||||
|
||||
// Divide implements traits.Divider.Divide.
|
||||
func (i Int) Divide(other ref.Val) ref.Val {
|
||||
otherInt, ok := other.(Int)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
val, err := divideInt64Checked(int64(i), int64(otherInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (i Int) Equal(other ref.Val) ref.Val {
|
||||
otherInt, ok := other.(Int)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return Bool(i == otherInt)
|
||||
}
|
||||
|
||||
// Modulo implements traits.Modder.Modulo.
|
||||
func (i Int) Modulo(other ref.Val) ref.Val {
|
||||
otherInt, ok := other.(Int)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
val, err := moduloInt64Checked(int64(i), int64(otherInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
|
||||
// Multiply implements traits.Multiplier.Multiply.
|
||||
func (i Int) Multiply(other ref.Val) ref.Val {
|
||||
otherInt, ok := other.(Int)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
val, err := multiplyInt64Checked(int64(i), int64(otherInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
|
||||
// Negate implements traits.Negater.Negate.
|
||||
func (i Int) Negate() ref.Val {
|
||||
val, err := negateInt64Checked(int64(i))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
|
||||
// Subtract implements traits.Subtractor.Subtract.
|
||||
func (i Int) Subtract(subtrahend ref.Val) ref.Val {
|
||||
subtraInt, ok := subtrahend.(Int)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(subtrahend)
|
||||
}
|
||||
val, err := subtractInt64Checked(int64(i), int64(subtraInt))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Int(val)
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (i Int) Type() ref.Type {
|
||||
return IntType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (i Int) Value() interface{} {
|
||||
return int64(i)
|
||||
}
|
||||
|
||||
// isJSONSafe indicates whether the int is safely representable as a floating point value in JSON.
|
||||
func (i Int) isJSONSafe() bool {
|
||||
return i >= minIntJSON && i <= maxIntJSON
|
||||
}
|
||||
|
||||
const (
|
||||
// maxIntJSON is defined as the Number.MAX_SAFE_INTEGER value per EcmaScript 6.
|
||||
maxIntJSON = 1<<53 - 1
|
||||
// minIntJSON is defined as the Number.MIN_SAFE_INTEGER value per EcmaScript 6.
|
||||
minIntJSON = -maxIntJSON
|
||||
)
|
||||
55
vendor/github.com/google/cel-go/common/types/iterator.go
generated
vendored
Normal file
55
vendor/github.com/google/cel-go/common/types/iterator.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
)
|
||||
|
||||
var (
|
||||
// IteratorType singleton.
|
||||
IteratorType = NewTypeValue("iterator", traits.IteratorType)
|
||||
)
|
||||
|
||||
// baseIterator is the basis for list, map, and object iterators.
|
||||
//
|
||||
// An iterator in and of itself should not be a valid value for comparison, but must implement the
|
||||
// `ref.Val` methods in order to be well-supported within instruction arguments processed by the
|
||||
// interpreter.
|
||||
type baseIterator struct{}
|
||||
|
||||
func (*baseIterator) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
return nil, fmt.Errorf("type conversion on iterators not supported")
|
||||
}
|
||||
|
||||
func (*baseIterator) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
return NewErr("no such overload")
|
||||
}
|
||||
|
||||
func (*baseIterator) Equal(other ref.Val) ref.Val {
|
||||
return NewErr("no such overload")
|
||||
}
|
||||
|
||||
func (*baseIterator) Type() ref.Type {
|
||||
return IteratorType
|
||||
}
|
||||
|
||||
func (*baseIterator) Value() interface{} {
|
||||
return nil
|
||||
}
|
||||
28
vendor/github.com/google/cel-go/common/types/json_value.go
generated
vendored
Normal file
28
vendor/github.com/google/cel-go/common/types/json_value.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2018 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 (
|
||||
"reflect"
|
||||
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// JSON type constants representing the reflected types of protobuf JSON values.
|
||||
var (
|
||||
jsonValueType = reflect.TypeOf(&structpb.Value{})
|
||||
jsonListValueType = reflect.TypeOf(&structpb.ListValue{})
|
||||
jsonStructType = reflect.TypeOf(&structpb.Struct{})
|
||||
)
|
||||
447
vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
Normal file
447
vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
Normal file
@@ -0,0 +1,447 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
var (
|
||||
// ListType singleton.
|
||||
ListType = NewTypeValue("list",
|
||||
traits.AdderType,
|
||||
traits.ContainerType,
|
||||
traits.IndexerType,
|
||||
traits.IterableType,
|
||||
traits.SizerType)
|
||||
)
|
||||
|
||||
// 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 {
|
||||
refValue := reflect.ValueOf(value)
|
||||
return &baseList{
|
||||
TypeAdapter: adapter,
|
||||
value: value,
|
||||
size: refValue.Len(),
|
||||
get: func(i int) interface{} {
|
||||
return refValue.Index(i).Interface()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringList returns a traits.Lister containing only strings.
|
||||
func NewStringList(adapter ref.TypeAdapter, elems []string) traits.Lister {
|
||||
return &baseList{
|
||||
TypeAdapter: adapter,
|
||||
value: elems,
|
||||
size: len(elems),
|
||||
get: func(i int) interface{} { return elems[i] },
|
||||
}
|
||||
}
|
||||
|
||||
// NewRefValList returns a traits.Lister with ref.Val elements.
|
||||
//
|
||||
// This type specialization is used with list literals within CEL expressions.
|
||||
func NewRefValList(adapter ref.TypeAdapter, elems []ref.Val) traits.Lister {
|
||||
return &baseList{
|
||||
TypeAdapter: adapter,
|
||||
value: elems,
|
||||
size: len(elems),
|
||||
get: func(i int) interface{} { return elems[i] },
|
||||
}
|
||||
}
|
||||
|
||||
// NewProtoList returns a traits.Lister based on a pb.List instance.
|
||||
func NewProtoList(adapter ref.TypeAdapter, list protoreflect.List) traits.Lister {
|
||||
return &baseList{
|
||||
TypeAdapter: adapter,
|
||||
value: list,
|
||||
size: list.Len(),
|
||||
get: func(i int) interface{} { return list.Get(i).Interface() },
|
||||
}
|
||||
}
|
||||
|
||||
// NewJSONList returns a traits.Lister based on structpb.ListValue instance.
|
||||
func NewJSONList(adapter ref.TypeAdapter, l *structpb.ListValue) traits.Lister {
|
||||
vals := l.GetValues()
|
||||
return &baseList{
|
||||
TypeAdapter: adapter,
|
||||
value: l,
|
||||
size: len(vals),
|
||||
get: func(i int) interface{} { return vals[i] },
|
||||
}
|
||||
}
|
||||
|
||||
// baseList points to a list containing elements of any type.
|
||||
// The `value` is an array of native values, and refValue is its reflection object.
|
||||
// The `ref.TypeAdapter` enables native type to CEL type conversions.
|
||||
type baseList struct {
|
||||
ref.TypeAdapter
|
||||
value interface{}
|
||||
|
||||
// size indicates the number of elements within the list.
|
||||
// Since objects are immutable the size of a list is static.
|
||||
size int
|
||||
|
||||
// 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{}
|
||||
}
|
||||
|
||||
// Add implements the traits.Adder interface method.
|
||||
func (l *baseList) Add(other ref.Val) ref.Val {
|
||||
otherList, ok := other.(traits.Lister)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
if l.Size() == IntZero {
|
||||
return other
|
||||
}
|
||||
if otherList.Size() == IntZero {
|
||||
return l
|
||||
}
|
||||
return &concatList{
|
||||
TypeAdapter: l.TypeAdapter,
|
||||
prevList: l,
|
||||
nextList: otherList}
|
||||
}
|
||||
|
||||
// Contains implements the traits.Container interface method.
|
||||
func (l *baseList) Contains(elem ref.Val) ref.Val {
|
||||
if IsUnknownOrError(elem) {
|
||||
return elem
|
||||
}
|
||||
var err ref.Val
|
||||
for i := 0; i < l.size; i++ {
|
||||
val := l.NativeToValue(l.get(i))
|
||||
cmp := elem.Equal(val)
|
||||
b, ok := cmp.(Bool)
|
||||
// When there is an error on the contain check, this is not necessarily terminal.
|
||||
// The contains call could find the element and return True, just as though the user
|
||||
// had written a per-element comparison in an exists() macro or logical ||, e.g.
|
||||
// list.exists(e, e == elem)
|
||||
if !ok && err == nil {
|
||||
err = ValOrErr(cmp, "no such overload")
|
||||
}
|
||||
if b == True {
|
||||
return True
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return False
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (l *baseList) ConvertToNative(typeDesc reflect.Type) (interface{}, 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
|
||||
}
|
||||
// If the list wrapper is assignable to the desired type return it.
|
||||
if reflect.TypeOf(l).AssignableTo(typeDesc) {
|
||||
return l, nil
|
||||
}
|
||||
// Attempt to convert the list to a set of well known protobuf types.
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
json, err := l.ConvertToNative(jsonListValueType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return anypb.New(json.(proto.Message))
|
||||
case jsonValueType, jsonListValueType:
|
||||
jsonValues, err :=
|
||||
l.ConvertToNative(reflect.TypeOf([]*structpb.Value{}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonList := &structpb.ListValue{Values: jsonValues.([]*structpb.Value)}
|
||||
if typeDesc == jsonListValueType {
|
||||
return jsonList, nil
|
||||
}
|
||||
return structpb.NewListValue(jsonList), nil
|
||||
}
|
||||
// Non-list conversion.
|
||||
if typeDesc.Kind() != reflect.Slice && typeDesc.Kind() != reflect.Array {
|
||||
return nil, fmt.Errorf("type conversion error from list to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
// List conversion.
|
||||
// Allow the element ConvertToNative() function to determine whether conversion is possible.
|
||||
otherElemType := typeDesc.Elem()
|
||||
elemCount := l.size
|
||||
nativeList := reflect.MakeSlice(typeDesc, elemCount, elemCount)
|
||||
for i := 0; i < elemCount; i++ {
|
||||
elem := l.NativeToValue(l.get(i))
|
||||
nativeElemVal, err := elem.ConvertToNative(otherElemType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nativeList.Index(i).Set(reflect.ValueOf(nativeElemVal))
|
||||
}
|
||||
return nativeList.Interface(), nil
|
||||
}
|
||||
|
||||
// ConvertToType implements the ref.Val interface method.
|
||||
func (l *baseList) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case ListType:
|
||||
return l
|
||||
case TypeType:
|
||||
return ListType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", ListType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements the ref.Val interface method.
|
||||
func (l *baseList) Equal(other ref.Val) ref.Val {
|
||||
otherList, ok := other.(traits.Lister)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
if l.Size() != otherList.Size() {
|
||||
return False
|
||||
}
|
||||
var maybeErr ref.Val
|
||||
for i := IntZero; i < l.Size().(Int); i++ {
|
||||
thisElem := l.Get(i)
|
||||
otherElem := otherList.Get(i)
|
||||
elemEq := thisElem.Equal(otherElem)
|
||||
if elemEq == False {
|
||||
return False
|
||||
}
|
||||
if maybeErr == nil && IsUnknownOrError(elemEq) {
|
||||
maybeErr = elemEq
|
||||
}
|
||||
}
|
||||
if maybeErr != nil {
|
||||
return maybeErr
|
||||
}
|
||||
return True
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
iv := int(i)
|
||||
if iv < 0 || iv >= l.size {
|
||||
return NewErr("index '%d' out of range in list size '%d'", i, l.Size())
|
||||
}
|
||||
elem := l.get(iv)
|
||||
return l.NativeToValue(elem)
|
||||
}
|
||||
|
||||
// Iterator implements the traits.Iterable interface method.
|
||||
func (l *baseList) Iterator() traits.Iterator {
|
||||
return newListIterator(l)
|
||||
}
|
||||
|
||||
// Size implements the traits.Sizer interface method.
|
||||
func (l *baseList) Size() ref.Val {
|
||||
return Int(l.size)
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (l *baseList) Type() ref.Type {
|
||||
return ListType
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (l *baseList) Value() interface{} {
|
||||
return l.value
|
||||
}
|
||||
|
||||
// concatList combines two list implementations together into a view.
|
||||
// The `ref.TypeAdapter` enables native type to CEL type conversions.
|
||||
type concatList struct {
|
||||
ref.TypeAdapter
|
||||
value interface{}
|
||||
prevList traits.Lister
|
||||
nextList traits.Lister
|
||||
}
|
||||
|
||||
// Add implements the traits.Adder interface method.
|
||||
func (l *concatList) Add(other ref.Val) ref.Val {
|
||||
otherList, ok := other.(traits.Lister)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
if l.Size() == IntZero {
|
||||
return other
|
||||
}
|
||||
if otherList.Size() == IntZero {
|
||||
return l
|
||||
}
|
||||
return &concatList{
|
||||
TypeAdapter: l.TypeAdapter,
|
||||
prevList: l,
|
||||
nextList: otherList}
|
||||
}
|
||||
|
||||
// Contains implments 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`.
|
||||
prev := l.prevList.Contains(elem)
|
||||
// Short-circuit the return if the elem was found in the prev list.
|
||||
if prev == True {
|
||||
return prev
|
||||
}
|
||||
// Return if the elem was found in the next list.
|
||||
next := l.nextList.Contains(elem)
|
||||
if next == True {
|
||||
return next
|
||||
}
|
||||
// Handle the case where an error or unknown was encountered before checking next.
|
||||
if IsUnknownOrError(prev) {
|
||||
return prev
|
||||
}
|
||||
// Otherwise, rely on the next value as the representative result.
|
||||
return next
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (l *concatList) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
combined := NewDynamicList(l.TypeAdapter, l.Value().([]interface{}))
|
||||
return combined.ConvertToNative(typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements the ref.Val interface method.
|
||||
func (l *concatList) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case ListType:
|
||||
return l
|
||||
case TypeType:
|
||||
return ListType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", ListType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements the ref.Val interface method.
|
||||
func (l *concatList) Equal(other ref.Val) ref.Val {
|
||||
otherList, ok := other.(traits.Lister)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
if l.Size() != otherList.Size() {
|
||||
return False
|
||||
}
|
||||
var maybeErr ref.Val
|
||||
for i := IntZero; i < l.Size().(Int); i++ {
|
||||
thisElem := l.Get(i)
|
||||
otherElem := otherList.Get(i)
|
||||
elemEq := thisElem.Equal(otherElem)
|
||||
if elemEq == False {
|
||||
return False
|
||||
}
|
||||
if maybeErr == nil && IsUnknownOrError(elemEq) {
|
||||
maybeErr = elemEq
|
||||
}
|
||||
}
|
||||
if maybeErr != nil {
|
||||
return maybeErr
|
||||
}
|
||||
return True
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
if i < l.prevList.Size().(Int) {
|
||||
return l.prevList.Get(i)
|
||||
}
|
||||
offset := i - l.prevList.Size().(Int)
|
||||
return l.nextList.Get(offset)
|
||||
}
|
||||
|
||||
// Iterator implements the traits.Iterable interface method.
|
||||
func (l *concatList) Iterator() traits.Iterator {
|
||||
return newListIterator(l)
|
||||
}
|
||||
|
||||
// Size implements the traits.Sizer interface method.
|
||||
func (l *concatList) Size() ref.Val {
|
||||
return l.prevList.Size().(Int).Add(l.nextList.Size())
|
||||
}
|
||||
|
||||
// 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{} {
|
||||
if l.value == nil {
|
||||
merged := make([]interface{}, l.Size().(Int))
|
||||
prevLen := l.prevList.Size().(Int)
|
||||
for i := Int(0); i < prevLen; i++ {
|
||||
merged[i] = l.prevList.Get(i).Value()
|
||||
}
|
||||
nextLen := l.nextList.Size().(Int)
|
||||
for j := Int(0); j < nextLen; j++ {
|
||||
merged[prevLen+j] = l.nextList.Get(j).Value()
|
||||
}
|
||||
l.value = merged
|
||||
}
|
||||
return l.value
|
||||
}
|
||||
|
||||
func newListIterator(listValue traits.Lister) traits.Iterator {
|
||||
return &listIterator{
|
||||
listValue: listValue,
|
||||
len: listValue.Size().(Int),
|
||||
}
|
||||
}
|
||||
|
||||
type listIterator struct {
|
||||
*baseIterator
|
||||
listValue traits.Lister
|
||||
cursor Int
|
||||
len Int
|
||||
}
|
||||
|
||||
// HasNext implements the traits.Iterator interface method.
|
||||
func (it *listIterator) HasNext() ref.Val {
|
||||
return Bool(it.cursor < it.len)
|
||||
}
|
||||
|
||||
// Next implements the traits.Iterator interface method.
|
||||
func (it *listIterator) Next() ref.Val {
|
||||
if it.HasNext() == True {
|
||||
index := it.cursor
|
||||
it.cursor++
|
||||
return it.listValue.Get(index)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
809
vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
Normal file
809
vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
Normal file
@@ -0,0 +1,809 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"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 {
|
||||
refValue := reflect.ValueOf(value)
|
||||
return &baseMap{
|
||||
TypeAdapter: adapter,
|
||||
mapAccessor: newReflectMapAccessor(adapter, refValue),
|
||||
value: value,
|
||||
size: refValue.Len(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewJSONStruct creates a traits.Mapper implementation backed by a JSON struct that has been
|
||||
// encoded in protocol buffer form.
|
||||
//
|
||||
// The `adapter` argument provides type adaptation capabilities from proto to CEL.
|
||||
func NewJSONStruct(adapter ref.TypeAdapter, value *structpb.Struct) traits.Mapper {
|
||||
fields := value.GetFields()
|
||||
return &baseMap{
|
||||
TypeAdapter: adapter,
|
||||
mapAccessor: newJSONStructAccessor(adapter, fields),
|
||||
value: value,
|
||||
size: len(fields),
|
||||
}
|
||||
}
|
||||
|
||||
// NewRefValMap returns a specialized traits.Mapper with CEL valued keys and values.
|
||||
func NewRefValMap(adapter ref.TypeAdapter, value map[ref.Val]ref.Val) traits.Mapper {
|
||||
return &baseMap{
|
||||
TypeAdapter: adapter,
|
||||
mapAccessor: newRefValMapAccessor(value),
|
||||
value: value,
|
||||
size: len(value),
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringInterfaceMap returns a specialized traits.Mapper with string keys and interface values.
|
||||
func NewStringInterfaceMap(adapter ref.TypeAdapter, value map[string]interface{}) traits.Mapper {
|
||||
return &baseMap{
|
||||
TypeAdapter: adapter,
|
||||
mapAccessor: newStringIfaceMapAccessor(adapter, value),
|
||||
value: value,
|
||||
size: len(value),
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringStringMap returns a specialized traits.Mapper with string keys and values.
|
||||
func NewStringStringMap(adapter ref.TypeAdapter, value map[string]string) traits.Mapper {
|
||||
return &baseMap{
|
||||
TypeAdapter: adapter,
|
||||
mapAccessor: newStringMapAccessor(value),
|
||||
value: value,
|
||||
size: len(value),
|
||||
}
|
||||
}
|
||||
|
||||
// NewProtoMap returns a specialized traits.Mapper for handling protobuf map values.
|
||||
func NewProtoMap(adapter ref.TypeAdapter, value *pb.Map) traits.Mapper {
|
||||
return &protoMap{
|
||||
TypeAdapter: adapter,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// MapType singleton.
|
||||
MapType = NewTypeValue("map",
|
||||
traits.ContainerType,
|
||||
traits.IndexerType,
|
||||
traits.IterableType,
|
||||
traits.SizerType)
|
||||
)
|
||||
|
||||
// mapAccessor is a private interface for finding values within a map and iterating over the keys.
|
||||
// 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.
|
||||
//
|
||||
// If the key is not found the function returns (nil, false).
|
||||
// If the input key is not valid for the map, or is Err or Unknown the function returns
|
||||
// (Unknown|Err, false).
|
||||
Find(ref.Val) (ref.Val, bool)
|
||||
|
||||
// Iterator returns an Iterator over the map key set.
|
||||
Iterator() traits.Iterator
|
||||
}
|
||||
|
||||
// baseMap is a reflection based map implementation designed to handle a variety of map-like types.
|
||||
//
|
||||
// Since CEL is side-effect free, the base map represents an immutable object.
|
||||
type baseMap struct {
|
||||
// TypeAdapter used to convert keys and values accessed within the map.
|
||||
ref.TypeAdapter
|
||||
|
||||
// mapAccessor interface implementation used to find and iterate over map keys.
|
||||
mapAccessor
|
||||
|
||||
// value is the native Go value upon which the map type operators.
|
||||
value interface{}
|
||||
|
||||
// size is the number of entries in the map.
|
||||
size int
|
||||
}
|
||||
|
||||
// Contains implements the traits.Container interface method.
|
||||
func (m *baseMap) Contains(index ref.Val) ref.Val {
|
||||
val, found := m.Find(index)
|
||||
// When the index is not found and val is non-nil, this is an error or unknown value.
|
||||
if !found && val != nil && IsUnknownOrError(val) {
|
||||
return val
|
||||
}
|
||||
return Bool(found)
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (m *baseMap) ConvertToNative(typeDesc reflect.Type) (interface{}, 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) {
|
||||
return m.value, nil
|
||||
}
|
||||
if reflect.TypeOf(m).AssignableTo(typeDesc) {
|
||||
return m, nil
|
||||
}
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
json, err := m.ConvertToNative(jsonStructType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return anypb.New(json.(proto.Message))
|
||||
case jsonValueType, jsonStructType:
|
||||
jsonEntries, err :=
|
||||
m.ConvertToNative(reflect.TypeOf(map[string]*structpb.Value{}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonMap := &structpb.Struct{Fields: jsonEntries.(map[string]*structpb.Value)}
|
||||
if typeDesc == jsonStructType {
|
||||
return jsonMap, nil
|
||||
}
|
||||
return structpb.NewStructValue(jsonMap), nil
|
||||
}
|
||||
|
||||
// Unwrap pointers, but track their use.
|
||||
isPtr := false
|
||||
if typeDesc.Kind() == reflect.Ptr {
|
||||
tk := typeDesc
|
||||
typeDesc = typeDesc.Elem()
|
||||
if typeDesc.Kind() == reflect.Ptr {
|
||||
return nil, fmt.Errorf("unsupported type conversion to '%v'", tk)
|
||||
}
|
||||
isPtr = true
|
||||
}
|
||||
switch typeDesc.Kind() {
|
||||
// Map conversion.
|
||||
case reflect.Map:
|
||||
otherKey := typeDesc.Key()
|
||||
otherElem := typeDesc.Elem()
|
||||
nativeMap := reflect.MakeMapWithSize(typeDesc, m.size)
|
||||
it := m.Iterator()
|
||||
for it.HasNext() == True {
|
||||
key := it.Next()
|
||||
refKeyValue, err := key.ConvertToNative(otherKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
refElemValue, err := m.Get(key).ConvertToNative(otherElem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nativeMap.SetMapIndex(reflect.ValueOf(refKeyValue), reflect.ValueOf(refElemValue))
|
||||
}
|
||||
return nativeMap.Interface(), nil
|
||||
case reflect.Struct:
|
||||
nativeStructPtr := reflect.New(typeDesc)
|
||||
nativeStruct := nativeStructPtr.Elem()
|
||||
it := m.Iterator()
|
||||
for it.HasNext() == True {
|
||||
key := it.Next()
|
||||
// Ensure the field name being referenced is exported.
|
||||
// Only exported (public) field names can be set by reflection, where the name
|
||||
// must be at least one character in length and start with an upper-case letter.
|
||||
fieldName := key.ConvertToType(StringType)
|
||||
if IsError(fieldName) {
|
||||
return nil, fieldName.(*Err)
|
||||
}
|
||||
name := string(fieldName.(String))
|
||||
name = strcase.UpperCamelCase(name)
|
||||
fieldRef := nativeStruct.FieldByName(name)
|
||||
if !fieldRef.IsValid() {
|
||||
return nil, fmt.Errorf("type conversion error, no such field '%s' in type '%v'", name, typeDesc)
|
||||
}
|
||||
fieldValue, err := m.Get(key).ConvertToNative(fieldRef.Type())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldRef.Set(reflect.ValueOf(fieldValue))
|
||||
}
|
||||
if isPtr {
|
||||
return nativeStructPtr.Interface(), nil
|
||||
}
|
||||
return nativeStruct.Interface(), nil
|
||||
}
|
||||
return nil, fmt.Errorf("type conversion error from map to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements the ref.Val interface method.
|
||||
func (m *baseMap) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case MapType:
|
||||
return m
|
||||
case TypeType:
|
||||
return MapType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", MapType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements the ref.Val interface method.
|
||||
func (m *baseMap) Equal(other ref.Val) ref.Val {
|
||||
otherMap, ok := other.(traits.Mapper)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
if m.Size() != otherMap.Size() {
|
||||
return False
|
||||
}
|
||||
it := m.Iterator()
|
||||
var maybeErr ref.Val
|
||||
for it.HasNext() == True {
|
||||
key := it.Next()
|
||||
thisVal, _ := m.Find(key)
|
||||
otherVal, found := otherMap.Find(key)
|
||||
if !found {
|
||||
if otherVal == nil {
|
||||
return False
|
||||
}
|
||||
if maybeErr == nil {
|
||||
maybeErr = MaybeNoSuchOverloadErr(otherVal)
|
||||
}
|
||||
continue
|
||||
}
|
||||
valEq := thisVal.Equal(otherVal)
|
||||
if valEq == False {
|
||||
return False
|
||||
}
|
||||
if maybeErr == nil && IsUnknownOrError(valEq) {
|
||||
maybeErr = valEq
|
||||
}
|
||||
}
|
||||
if maybeErr != nil {
|
||||
return maybeErr
|
||||
}
|
||||
return True
|
||||
}
|
||||
|
||||
// Get implements the traits.Indexer interface method.
|
||||
func (m *baseMap) Get(key ref.Val) ref.Val {
|
||||
v, found := m.Find(key)
|
||||
if !found {
|
||||
return ValOrErr(v, "no such key: %v", key)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Size implements the traits.Sizer interface method.
|
||||
func (m *baseMap) Size() ref.Val {
|
||||
return Int(m.size)
|
||||
}
|
||||
|
||||
// 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{} {
|
||||
return m.value
|
||||
}
|
||||
|
||||
func newJSONStructAccessor(adapter ref.TypeAdapter, st map[string]*structpb.Value) mapAccessor {
|
||||
return &jsonStructAccessor{
|
||||
TypeAdapter: adapter,
|
||||
st: st,
|
||||
}
|
||||
}
|
||||
|
||||
type jsonStructAccessor struct {
|
||||
ref.TypeAdapter
|
||||
st map[string]*structpb.Value
|
||||
}
|
||||
|
||||
// Find searches the json struct field map for the input key value and returns (value, true) if
|
||||
// found.
|
||||
//
|
||||
// If the key is not found the function returns (nil, false).
|
||||
// If the input key is not a String, or is an Err or Unknown, the function returns
|
||||
// (Unknown|Err, false).
|
||||
func (a *jsonStructAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
strKey, ok := key.(String)
|
||||
if !ok {
|
||||
return ValOrErr(key, "unsupported key type: %v", key.Type()), false
|
||||
}
|
||||
keyVal, found := a.st[string(strKey)]
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
return a.NativeToValue(keyVal), true
|
||||
}
|
||||
|
||||
// Iterator creates a new traits.Iterator from the set of JSON struct field names.
|
||||
func (a *jsonStructAccessor) Iterator() traits.Iterator {
|
||||
// Copy the keys to make their order stable.
|
||||
mapKeys := make([]string, len(a.st))
|
||||
i := 0
|
||||
for k := range a.st {
|
||||
mapKeys[i] = k
|
||||
i++
|
||||
}
|
||||
return &stringKeyIterator{
|
||||
mapKeys: mapKeys,
|
||||
len: len(mapKeys),
|
||||
}
|
||||
}
|
||||
|
||||
func newReflectMapAccessor(adapter ref.TypeAdapter, value reflect.Value) mapAccessor {
|
||||
keyType := value.Type().Key()
|
||||
return &reflectMapAccessor{
|
||||
TypeAdapter: adapter,
|
||||
refValue: value,
|
||||
keyType: keyType,
|
||||
}
|
||||
}
|
||||
|
||||
type reflectMapAccessor struct {
|
||||
ref.TypeAdapter
|
||||
refValue reflect.Value
|
||||
keyType reflect.Type
|
||||
}
|
||||
|
||||
// Find converts the input key to a native Golang type and then uses reflection to find the key,
|
||||
// returning (value, true) if present.
|
||||
//
|
||||
// If the key is not found the function returns (nil, false).
|
||||
// If the input key is not a String, or is an Err or Unknown, the function returns
|
||||
// (Unknown|Err, false).
|
||||
func (a *reflectMapAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
if IsUnknownOrError(key) {
|
||||
return MaybeNoSuchOverloadErr(key), false
|
||||
}
|
||||
if a.refValue.Len() == 0 {
|
||||
return nil, false
|
||||
}
|
||||
k, err := key.ConvertToNative(a.keyType)
|
||||
if err != nil {
|
||||
return NewErr("unsupported key type: %v", key.Type()), false
|
||||
}
|
||||
refKey := reflect.ValueOf(k)
|
||||
val := a.refValue.MapIndex(refKey)
|
||||
if val.IsValid() {
|
||||
return a.NativeToValue(val.Interface()), true
|
||||
}
|
||||
mapIt := a.refValue.MapRange()
|
||||
for mapIt.Next() {
|
||||
if refKey.Kind() == mapIt.Key().Kind() {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return NewErr("unsupported key type: %v", key.Type()), false
|
||||
}
|
||||
|
||||
// Iterator creates a Golang reflection based traits.Iterator.
|
||||
func (a *reflectMapAccessor) Iterator() traits.Iterator {
|
||||
return &mapIterator{
|
||||
TypeAdapter: a.TypeAdapter,
|
||||
mapKeys: a.refValue.MapRange(),
|
||||
len: a.refValue.Len(),
|
||||
}
|
||||
}
|
||||
|
||||
func newRefValMapAccessor(mapVal map[ref.Val]ref.Val) mapAccessor {
|
||||
return &refValMapAccessor{mapVal: mapVal}
|
||||
}
|
||||
|
||||
type refValMapAccessor struct {
|
||||
mapVal map[ref.Val]ref.Val
|
||||
}
|
||||
|
||||
// Find uses native map accesses to find the key, returning (value, true) if present.
|
||||
//
|
||||
// If the key is not found the function returns (nil, false).
|
||||
// If the input key is an Err or Unknown, the function returns (Unknown|Err, false).
|
||||
func (a *refValMapAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
if IsUnknownOrError(key) {
|
||||
return key, false
|
||||
}
|
||||
if len(a.mapVal) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
keyVal, found := a.mapVal[key]
|
||||
if found {
|
||||
return keyVal, true
|
||||
}
|
||||
for k := range a.mapVal {
|
||||
if k.Type().TypeName() == key.Type().TypeName() {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return NewErr("unsupported key type: %v", key.Type()), found
|
||||
}
|
||||
|
||||
// Iterator produces a new traits.Iterator which iterates over the map keys via Golang reflection.
|
||||
func (a *refValMapAccessor) Iterator() traits.Iterator {
|
||||
return &mapIterator{
|
||||
TypeAdapter: DefaultTypeAdapter,
|
||||
mapKeys: reflect.ValueOf(a.mapVal).MapRange(),
|
||||
len: len(a.mapVal),
|
||||
}
|
||||
}
|
||||
|
||||
func newStringMapAccessor(strMap map[string]string) mapAccessor {
|
||||
return &stringMapAccessor{mapVal: strMap}
|
||||
}
|
||||
|
||||
type stringMapAccessor struct {
|
||||
mapVal map[string]string
|
||||
}
|
||||
|
||||
// Find uses native map accesses to find the key, returning (value, true) if present.
|
||||
//
|
||||
// If the key is not found the function returns (nil, false).
|
||||
// If the input key is not a String, or is an Err or Unknown, the function returns
|
||||
// (Unknown|Err, false).
|
||||
func (a *stringMapAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
strKey, ok := key.(String)
|
||||
if !ok {
|
||||
return ValOrErr(key, "unsupported key type: %v", key.Type()), false
|
||||
}
|
||||
keyVal, found := a.mapVal[string(strKey)]
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
return String(keyVal), true
|
||||
}
|
||||
|
||||
// Iterator creates a new traits.Iterator from the string key set of the map.
|
||||
func (a *stringMapAccessor) Iterator() traits.Iterator {
|
||||
// Copy the keys to make their order stable.
|
||||
mapKeys := make([]string, len(a.mapVal))
|
||||
i := 0
|
||||
for k := range a.mapVal {
|
||||
mapKeys[i] = k
|
||||
i++
|
||||
}
|
||||
return &stringKeyIterator{
|
||||
mapKeys: mapKeys,
|
||||
len: len(mapKeys),
|
||||
}
|
||||
}
|
||||
|
||||
func newStringIfaceMapAccessor(adapter ref.TypeAdapter, mapVal map[string]interface{}) mapAccessor {
|
||||
return &stringIfaceMapAccessor{
|
||||
TypeAdapter: adapter,
|
||||
mapVal: mapVal,
|
||||
}
|
||||
}
|
||||
|
||||
type stringIfaceMapAccessor struct {
|
||||
ref.TypeAdapter
|
||||
mapVal map[string]interface{}
|
||||
}
|
||||
|
||||
// Find uses native map accesses to find the key, returning (value, true) if present.
|
||||
//
|
||||
// If the key is not found the function returns (nil, false).
|
||||
// If the input key is not a String, or is an Err or Unknown, the function returns
|
||||
// (Unknown|Err, false).
|
||||
func (a *stringIfaceMapAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
strKey, ok := key.(String)
|
||||
if !ok {
|
||||
return ValOrErr(key, "unsupported key type: %v", key.Type()), false
|
||||
}
|
||||
keyVal, found := a.mapVal[string(strKey)]
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
return a.NativeToValue(keyVal), true
|
||||
}
|
||||
|
||||
// Iterator creates a new traits.Iterator from the string key set of the map.
|
||||
func (a *stringIfaceMapAccessor) Iterator() traits.Iterator {
|
||||
// Copy the keys to make their order stable.
|
||||
mapKeys := make([]string, len(a.mapVal))
|
||||
i := 0
|
||||
for k := range a.mapVal {
|
||||
mapKeys[i] = k
|
||||
i++
|
||||
}
|
||||
return &stringKeyIterator{
|
||||
mapKeys: mapKeys,
|
||||
len: len(mapKeys),
|
||||
}
|
||||
}
|
||||
|
||||
// protoMap is a specialized, separate implementation of the traits.Mapper interfaces tailored to
|
||||
// accessing protoreflect.Map values.
|
||||
type protoMap struct {
|
||||
ref.TypeAdapter
|
||||
value *pb.Map
|
||||
}
|
||||
|
||||
// Contains returns whether the map contains the given key.
|
||||
func (m *protoMap) Contains(key ref.Val) ref.Val {
|
||||
val, found := m.Find(key)
|
||||
// When the index is not found and val is non-nil, this is an error or unknown value.
|
||||
if !found && val != nil && IsUnknownOrError(val) {
|
||||
return val
|
||||
}
|
||||
return Bool(found)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 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 {
|
||||
case anyValueType:
|
||||
json, err := m.ConvertToNative(jsonStructType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return anypb.New(json.(proto.Message))
|
||||
case jsonValueType, jsonStructType:
|
||||
jsonEntries, err :=
|
||||
m.ConvertToNative(reflect.TypeOf(map[string]*structpb.Value{}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonMap := &structpb.Struct{
|
||||
Fields: jsonEntries.(map[string]*structpb.Value)}
|
||||
if typeDesc == jsonStructType {
|
||||
return jsonMap, nil
|
||||
}
|
||||
return structpb.NewStructValue(jsonMap), nil
|
||||
}
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Struct, reflect.Ptr:
|
||||
if reflect.TypeOf(m.value).AssignableTo(typeDesc) {
|
||||
return m.value, nil
|
||||
}
|
||||
if reflect.TypeOf(m).AssignableTo(typeDesc) {
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
if typeDesc.Kind() != reflect.Map {
|
||||
return nil, fmt.Errorf("unsupported type conversion: %v to map", typeDesc)
|
||||
}
|
||||
|
||||
keyType := m.value.KeyType.ReflectType()
|
||||
valType := m.value.ValueType.ReflectType()
|
||||
otherKeyType := typeDesc.Key()
|
||||
otherValType := typeDesc.Elem()
|
||||
mapVal := reflect.MakeMapWithSize(typeDesc, m.value.Len())
|
||||
var err error
|
||||
m.value.Range(func(key protoreflect.MapKey, val protoreflect.Value) bool {
|
||||
ntvKey := key.Interface()
|
||||
ntvVal := val.Interface()
|
||||
switch ntvVal.(type) {
|
||||
case protoreflect.Message:
|
||||
ntvVal = ntvVal.(protoreflect.Message).Interface()
|
||||
}
|
||||
if keyType == otherKeyType && valType == otherValType {
|
||||
mapVal.SetMapIndex(reflect.ValueOf(ntvKey), reflect.ValueOf(ntvVal))
|
||||
return true
|
||||
}
|
||||
celKey := m.NativeToValue(ntvKey)
|
||||
celVal := m.NativeToValue(ntvVal)
|
||||
ntvKey, err = celKey.ConvertToNative(otherKeyType)
|
||||
if err != nil {
|
||||
// early terminate the range loop.
|
||||
return false
|
||||
}
|
||||
ntvVal, err = celVal.ConvertToNative(otherValType)
|
||||
if err != nil {
|
||||
// early terminate the range loop.
|
||||
return false
|
||||
}
|
||||
mapVal.SetMapIndex(reflect.ValueOf(ntvKey), reflect.ValueOf(ntvVal))
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapVal.Interface(), nil
|
||||
}
|
||||
|
||||
// ConvertToType implements the ref.Val interface method.
|
||||
func (m *protoMap) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case MapType:
|
||||
return m
|
||||
case TypeType:
|
||||
return MapType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", MapType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements the ref.Val interface method.
|
||||
func (m *protoMap) Equal(other ref.Val) ref.Val {
|
||||
otherMap, ok := other.(traits.Mapper)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
if m.value.Map.Len() != int(otherMap.Size().(Int)) {
|
||||
return False
|
||||
}
|
||||
var retVal ref.Val = True
|
||||
m.value.Range(func(key protoreflect.MapKey, val protoreflect.Value) bool {
|
||||
keyVal := m.NativeToValue(key.Interface())
|
||||
valVal := m.NativeToValue(val)
|
||||
otherVal, found := otherMap.Find(keyVal)
|
||||
if !found {
|
||||
if otherVal == nil {
|
||||
retVal = False
|
||||
return false
|
||||
}
|
||||
retVal = MaybeNoSuchOverloadErr(otherVal)
|
||||
return false
|
||||
}
|
||||
valEq := valVal.Equal(otherVal)
|
||||
if valEq != True {
|
||||
retVal = valEq
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Find returns whether the protoreflect.Map contains the input key.
|
||||
//
|
||||
// If the key is not found the function returns (nil, false).
|
||||
// If the input key is not a supported proto map key type, or is an Err or Unknown,
|
||||
// the function returns
|
||||
// (Unknown|Err, false).
|
||||
func (m *protoMap) Find(key ref.Val) (ref.Val, bool) {
|
||||
if IsUnknownOrError(key) {
|
||||
return key, false
|
||||
}
|
||||
// Convert the input key to the expected protobuf key type.
|
||||
ntvKey, err := key.ConvertToNative(m.value.KeyType.ReflectType())
|
||||
if err != nil {
|
||||
return NewErr("unsupported key type: %v", key.Type()), false
|
||||
}
|
||||
// Use protoreflection to get the key value.
|
||||
val := m.value.Get(protoreflect.ValueOf(ntvKey).MapKey())
|
||||
if !val.IsValid() {
|
||||
return nil, false
|
||||
}
|
||||
// Perform nominal type unwrapping from the input value.
|
||||
switch v := val.Interface().(type) {
|
||||
case protoreflect.List, protoreflect.Map:
|
||||
// Maps do not support list or map values
|
||||
return NewErr("unsupported map element type: (%T)%v", v, v), false
|
||||
default:
|
||||
return m.NativeToValue(v), true
|
||||
}
|
||||
}
|
||||
|
||||
// Get implements the traits.Indexer interface method.
|
||||
func (m *protoMap) Get(key ref.Val) ref.Val {
|
||||
v, found := m.Find(key)
|
||||
if !found {
|
||||
return ValOrErr(v, "no such key: %v", key)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Iterator implements the traits.Iterable interface method.
|
||||
func (m *protoMap) Iterator() traits.Iterator {
|
||||
// Copy the keys to make their order stable.
|
||||
mapKeys := make([]protoreflect.MapKey, 0, m.value.Len())
|
||||
m.value.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
|
||||
mapKeys = append(mapKeys, k)
|
||||
return true
|
||||
})
|
||||
return &protoMapIterator{
|
||||
TypeAdapter: m.TypeAdapter,
|
||||
mapKeys: mapKeys,
|
||||
len: m.value.Len(),
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the number of entries in the protoreflect.Map.
|
||||
func (m *protoMap) Size() ref.Val {
|
||||
return Int(m.value.Len())
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (m *protoMap) Type() ref.Type {
|
||||
return MapType
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (m *protoMap) Value() interface{} {
|
||||
return m.value
|
||||
}
|
||||
|
||||
type mapIterator struct {
|
||||
*baseIterator
|
||||
ref.TypeAdapter
|
||||
mapKeys *reflect.MapIter
|
||||
cursor int
|
||||
len int
|
||||
}
|
||||
|
||||
// HasNext implements the traits.Iterator interface method.
|
||||
func (it *mapIterator) HasNext() ref.Val {
|
||||
return Bool(it.cursor < it.len)
|
||||
}
|
||||
|
||||
// Next implements the traits.Iterator interface method.
|
||||
func (it *mapIterator) Next() ref.Val {
|
||||
if it.HasNext() == True && it.mapKeys.Next() {
|
||||
it.cursor++
|
||||
refKey := it.mapKeys.Key()
|
||||
return it.NativeToValue(refKey.Interface())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type protoMapIterator struct {
|
||||
*baseIterator
|
||||
ref.TypeAdapter
|
||||
mapKeys []protoreflect.MapKey
|
||||
cursor int
|
||||
len int
|
||||
}
|
||||
|
||||
// HasNext implements the traits.Iterator interface method.
|
||||
func (it *protoMapIterator) HasNext() ref.Val {
|
||||
return Bool(it.cursor < it.len)
|
||||
}
|
||||
|
||||
// Next implements the traits.Iterator interface method.
|
||||
func (it *protoMapIterator) Next() ref.Val {
|
||||
if it.HasNext() == True {
|
||||
index := it.cursor
|
||||
it.cursor++
|
||||
refKey := it.mapKeys[index]
|
||||
return it.NativeToValue(refKey.Interface())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type stringKeyIterator struct {
|
||||
*baseIterator
|
||||
mapKeys []string
|
||||
cursor int
|
||||
len int
|
||||
}
|
||||
|
||||
// HasNext implements the traits.Iterator interface method.
|
||||
func (it *stringKeyIterator) HasNext() ref.Val {
|
||||
return Bool(it.cursor < it.len)
|
||||
}
|
||||
|
||||
// Next implements the traits.Iterator interface method.
|
||||
func (it *stringKeyIterator) Next() ref.Val {
|
||||
if it.HasNext() == True {
|
||||
index := it.cursor
|
||||
it.cursor++
|
||||
return String(it.mapKeys[index])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
100
vendor/github.com/google/cel-go/common/types/null.go
generated
vendored
Normal file
100
vendor/github.com/google/cel-go/common/types/null.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// Null type implementation.
|
||||
type Null structpb.NullValue
|
||||
|
||||
var (
|
||||
// NullType singleton.
|
||||
NullType = NewTypeValue("null_type")
|
||||
// NullValue singleton.
|
||||
NullValue = Null(structpb.NullValue_NULL_VALUE)
|
||||
|
||||
jsonNullType = reflect.TypeOf(structpb.NullValue_NULL_VALUE)
|
||||
)
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (n Null) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Int32:
|
||||
return reflect.ValueOf(n).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Ptr:
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
// Convert to a JSON-null before packing to an Any field since the enum value for JSON
|
||||
// null cannot be packed directly.
|
||||
pb, err := n.ConvertToNative(jsonValueType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return anypb.New(pb.(proto.Message))
|
||||
case jsonValueType:
|
||||
return structpb.NewNullValue(), nil
|
||||
}
|
||||
case reflect.Interface:
|
||||
nv := n.Value()
|
||||
if reflect.TypeOf(nv).Implements(typeDesc) {
|
||||
return nv, nil
|
||||
}
|
||||
if reflect.TypeOf(n).Implements(typeDesc) {
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
// If the type conversion isn't supported return an error.
|
||||
return nil, fmt.Errorf("type conversion error from '%v' to '%v'", NullType, typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (n Null) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case StringType:
|
||||
return String("null")
|
||||
case NullType:
|
||||
return n
|
||||
case TypeType:
|
||||
return NullType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", NullType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (n Null) Equal(other ref.Val) ref.Val {
|
||||
if NullType != other.Type() {
|
||||
return ValOrErr(other, "no such overload")
|
||||
}
|
||||
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{} {
|
||||
return structpb.NullValue_NULL_VALUE
|
||||
}
|
||||
158
vendor/github.com/google/cel-go/common/types/object.go
generated
vendored
Normal file
158
vendor/github.com/google/cel-go/common/types/object.go
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
// Copyright 2018 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 (
|
||||
"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"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
type protoObj struct {
|
||||
ref.TypeAdapter
|
||||
value proto.Message
|
||||
typeDesc *pb.TypeDescription
|
||||
typeValue *TypeValue
|
||||
}
|
||||
|
||||
// NewObject returns an object based on a proto.Message value which handles
|
||||
// conversion between protobuf type values and expression type values.
|
||||
// Objects support indexing and iteration.
|
||||
//
|
||||
// Note: the type value is pulled from the list of registered types within the
|
||||
// type provider. If the proto type is not registered within the type provider,
|
||||
// then this will result in an error within the type adapter / provider.
|
||||
func NewObject(adapter ref.TypeAdapter,
|
||||
typeDesc *pb.TypeDescription,
|
||||
typeValue *TypeValue,
|
||||
value proto.Message) ref.Val {
|
||||
return &protoObj{
|
||||
TypeAdapter: adapter,
|
||||
value: value,
|
||||
typeDesc: typeDesc,
|
||||
typeValue: typeValue}
|
||||
}
|
||||
|
||||
func (o *protoObj) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
pb := o.value
|
||||
if reflect.TypeOf(pb).AssignableTo(typeDesc) {
|
||||
return pb, nil
|
||||
}
|
||||
if reflect.TypeOf(o).AssignableTo(typeDesc) {
|
||||
return o, nil
|
||||
}
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
_, isAny := pb.(*anypb.Any)
|
||||
if isAny {
|
||||
return pb, nil
|
||||
}
|
||||
return anypb.New(pb)
|
||||
case jsonValueType:
|
||||
// Marshal the proto to JSON first, and then rehydrate as protobuf.Value as there is no
|
||||
// support for direct conversion from proto.Message to protobuf.Value.
|
||||
bytes, err := protojson.Marshal(pb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json := &structpb.Value{}
|
||||
err = protojson.Unmarshal(bytes, json)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json, nil
|
||||
default:
|
||||
if typeDesc == o.typeDesc.ReflectType() {
|
||||
return o.value, nil
|
||||
}
|
||||
if typeDesc.Kind() == reflect.Ptr {
|
||||
val := reflect.New(typeDesc.Elem()).Interface()
|
||||
dstPB, ok := val.(proto.Message)
|
||||
if ok {
|
||||
proto.Merge(dstPB, pb)
|
||||
return dstPB, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("type conversion error from '%T' to '%v'", o.value, typeDesc)
|
||||
}
|
||||
|
||||
func (o *protoObj) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
default:
|
||||
if o.Type().TypeName() == typeVal.TypeName() {
|
||||
return o
|
||||
}
|
||||
case TypeType:
|
||||
return o.typeValue
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", o.typeDesc.Name(), typeVal)
|
||||
}
|
||||
|
||||
func (o *protoObj) Equal(other ref.Val) ref.Val {
|
||||
if o.typeDesc.Name() != other.Type().TypeName() {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return Bool(proto.Equal(o.value, other.Value().(proto.Message)))
|
||||
}
|
||||
|
||||
// IsSet tests whether a field which is defined is set to a non-default value.
|
||||
func (o *protoObj) IsSet(field ref.Val) ref.Val {
|
||||
protoFieldName, ok := field.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(field)
|
||||
}
|
||||
protoFieldStr := string(protoFieldName)
|
||||
fd, found := o.typeDesc.FieldByName(protoFieldStr)
|
||||
if !found {
|
||||
return NewErr("no such field '%s'", field)
|
||||
}
|
||||
if fd.IsSet(o.value) {
|
||||
return True
|
||||
}
|
||||
return False
|
||||
}
|
||||
|
||||
func (o *protoObj) Get(index ref.Val) ref.Val {
|
||||
protoFieldName, ok := index.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(index)
|
||||
}
|
||||
protoFieldStr := string(protoFieldName)
|
||||
fd, found := o.typeDesc.FieldByName(protoFieldStr)
|
||||
if !found {
|
||||
return NewErr("no such field '%s'", index)
|
||||
}
|
||||
fv, err := fd.GetFrom(o.value)
|
||||
if err != nil {
|
||||
return NewErr(err.Error())
|
||||
}
|
||||
return o.NativeToValue(fv)
|
||||
}
|
||||
|
||||
func (o *protoObj) Type() ref.Type {
|
||||
return o.typeValue
|
||||
}
|
||||
|
||||
func (o *protoObj) Value() interface{} {
|
||||
return o.value
|
||||
}
|
||||
357
vendor/github.com/google/cel-go/common/types/overflow.go
generated
vendored
Normal file
357
vendor/github.com/google/cel-go/common/types/overflow.go
generated
vendored
Normal file
@@ -0,0 +1,357 @@
|
||||
// Copyright 2021 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 (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
doubleTwoTo64 = math.Ldexp(1.0, 64)
|
||||
)
|
||||
|
||||
// addInt64Checked performs addition with overflow detection of two int64 values.
|
||||
//
|
||||
// If the operation fails the error return value will be non-nil.
|
||||
func addInt64Checked(x, y int64) (int64, error) {
|
||||
if (y > 0 && x > math.MaxInt64-y) || (y < 0 && x < math.MinInt64-y) {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return x + y, nil
|
||||
}
|
||||
|
||||
// subtractInt64Checked performs subtraction with overflow detection of two int64 values.
|
||||
//
|
||||
// If the operation fails the error return value will be non-nil.
|
||||
func subtractInt64Checked(x, y int64) (int64, error) {
|
||||
if (y < 0 && x > math.MaxInt64+y) || (y > 0 && x < math.MinInt64+y) {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return x - y, nil
|
||||
}
|
||||
|
||||
// negateInt64Checked performs negation with overflow detection of an int64.
|
||||
//
|
||||
// If the operation fails the error return value will be non-nil.
|
||||
func negateInt64Checked(x int64) (int64, error) {
|
||||
// In twos complement, negating MinInt64 would result in a valid of MaxInt64+1.
|
||||
if x == math.MinInt64 {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return -x, nil
|
||||
}
|
||||
|
||||
// multiplyInt64Checked performs multiplication with overflow detection of two int64 value.
|
||||
//
|
||||
// If the operation fails the error return value will be non-nil.
|
||||
func multiplyInt64Checked(x, y int64) (int64, error) {
|
||||
// Detecting multiplication overflow is more complicated than the others. The first two detect
|
||||
// attempting to negate MinInt64, which would result in MaxInt64+1. The other four detect normal
|
||||
// overflow conditions.
|
||||
if (x == -1 && y == math.MinInt64) || (y == -1 && x == math.MinInt64) ||
|
||||
// x is positive, y is positive
|
||||
(x > 0 && y > 0 && x > math.MaxInt64/y) ||
|
||||
// x is positive, y is negative
|
||||
(x > 0 && y < 0 && y < math.MinInt64/x) ||
|
||||
// x is negative, y is positive
|
||||
(x < 0 && y > 0 && x < math.MinInt64/y) ||
|
||||
// x is negative, y is negative
|
||||
(x < 0 && y < 0 && y < math.MaxInt64/x) {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return x * y, nil
|
||||
}
|
||||
|
||||
// divideInt64Checked performs division with overflow detection of two int64 values,
|
||||
// as well as a division by zero check.
|
||||
//
|
||||
// If the operation fails the error return value will be non-nil.
|
||||
func divideInt64Checked(x, y int64) (int64, error) {
|
||||
// Division by zero.
|
||||
if y == 0 {
|
||||
return 0, errDivideByZero
|
||||
}
|
||||
// In twos complement, negating MinInt64 would result in a valid of MaxInt64+1.
|
||||
if x == math.MinInt64 && y == -1 {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return x / y, nil
|
||||
}
|
||||
|
||||
// moduloInt64Checked performs modulo with overflow detection of two int64 values
|
||||
// as well as a modulus by zero check.
|
||||
//
|
||||
// If the operation fails the error return value will be non-nil.
|
||||
func moduloInt64Checked(x, y int64) (int64, error) {
|
||||
// Modulus by zero.
|
||||
if y == 0 {
|
||||
return 0, errModulusByZero
|
||||
}
|
||||
// In twos complement, negating MinInt64 would result in a valid of MaxInt64+1.
|
||||
if x == math.MinInt64 && y == -1 {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return x % y, nil
|
||||
}
|
||||
|
||||
// addUint64Checked performs addition with overflow detection of two uint64 values.
|
||||
//
|
||||
// If the operation fails due to overflow the error return value will be non-nil.
|
||||
func addUint64Checked(x, y uint64) (uint64, error) {
|
||||
if y > 0 && x > math.MaxUint64-y {
|
||||
return 0, errUintOverflow
|
||||
}
|
||||
return x + y, nil
|
||||
}
|
||||
|
||||
// subtractUint64Checked performs subtraction with overflow detection of two uint64 values.
|
||||
//
|
||||
// If the operation fails due to overflow the error return value will be non-nil.
|
||||
func subtractUint64Checked(x, y uint64) (uint64, error) {
|
||||
if y > x {
|
||||
return 0, errUintOverflow
|
||||
}
|
||||
return x - y, nil
|
||||
}
|
||||
|
||||
// multiplyUint64Checked performs multiplication with overflow detection of two uint64 values.
|
||||
//
|
||||
// If the operation fails due to overflow the error return value will be non-nil.
|
||||
func multiplyUint64Checked(x, y uint64) (uint64, error) {
|
||||
if y != 0 && x > math.MaxUint64/y {
|
||||
return 0, errUintOverflow
|
||||
}
|
||||
return x * y, nil
|
||||
}
|
||||
|
||||
// divideUint64Checked performs division with a test for division by zero.
|
||||
//
|
||||
// If the operation fails the error return value will be non-nil.
|
||||
func divideUint64Checked(x, y uint64) (uint64, error) {
|
||||
if y == 0 {
|
||||
return 0, errDivideByZero
|
||||
}
|
||||
return x / y, nil
|
||||
}
|
||||
|
||||
// moduloUint64Checked performs modulo with a test for modulus by zero.
|
||||
//
|
||||
// If the operation fails the error return value will be non-nil.
|
||||
func moduloUint64Checked(x, y uint64) (uint64, error) {
|
||||
if y == 0 {
|
||||
return 0, errModulusByZero
|
||||
}
|
||||
return x % y, nil
|
||||
}
|
||||
|
||||
// addDurationChecked performs addition with overflow detection of two time.Durations.
|
||||
//
|
||||
// If the operation fails due to overflow the error return value will be non-nil.
|
||||
func addDurationChecked(x, y time.Duration) (time.Duration, error) {
|
||||
val, err := addInt64Checked(int64(x), int64(y))
|
||||
if err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
return time.Duration(val), nil
|
||||
}
|
||||
|
||||
// subtractDurationChecked performs subtraction with overflow detection of two time.Durations.
|
||||
//
|
||||
// If the operation fails due to overflow the error return value will be non-nil.
|
||||
func subtractDurationChecked(x, y time.Duration) (time.Duration, error) {
|
||||
val, err := subtractInt64Checked(int64(x), int64(y))
|
||||
if err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
return time.Duration(val), nil
|
||||
}
|
||||
|
||||
// negateDurationChecked performs negation with overflow detection of a time.Duration.
|
||||
//
|
||||
// If the operation fails due to overflow the error return value will be non-nil.
|
||||
func negateDurationChecked(x time.Duration) (time.Duration, error) {
|
||||
val, err := negateInt64Checked(int64(x))
|
||||
if err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
return time.Duration(val), nil
|
||||
}
|
||||
|
||||
// addDurationChecked performs addition with overflow detection of a time.Time and time.Duration.
|
||||
//
|
||||
// If the operation fails due to overflow the error return value will be non-nil.
|
||||
func addTimeDurationChecked(x time.Time, y time.Duration) (time.Time, error) {
|
||||
// This is tricky. A time is represented as (int64, int32) where the first is seconds and second
|
||||
// is nanoseconds. A duration is int64 representing nanoseconds. We cannot normalize time to int64
|
||||
// as it could potentially overflow. The only way to proceed is to break time and duration into
|
||||
// second and nanosecond components.
|
||||
|
||||
// First we break time into its components by truncating and subtracting.
|
||||
sec1 := x.Truncate(time.Second).Unix() // Truncate to seconds.
|
||||
nsec1 := x.Sub(x.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting.
|
||||
|
||||
// Second we break duration into its components by dividing and modulo.
|
||||
sec2 := int64(y) / int64(time.Second) // Truncate to seconds.
|
||||
nsec2 := int64(y) % int64(time.Second) // Get remainder.
|
||||
|
||||
// Add seconds first, detecting any overflow.
|
||||
sec, err := addInt64Checked(sec1, sec2)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
// Nanoseconds cannot overflow as time.Time normalizes them to [0, 999999999].
|
||||
nsec := nsec1 + nsec2
|
||||
|
||||
// We need to normalize nanoseconds to be positive and carry extra nanoseconds to seconds.
|
||||
// Adapted from time.Unix(int64, int64).
|
||||
if nsec < 0 || nsec >= int64(time.Second) {
|
||||
// Add seconds.
|
||||
sec, err = addInt64Checked(sec, nsec/int64(time.Second))
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
nsec -= (nsec / int64(time.Second)) * int64(time.Second)
|
||||
if nsec < 0 {
|
||||
// Subtract an extra second
|
||||
sec, err = addInt64Checked(sec, -1)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
nsec += int64(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the the number of seconds from Unix epoch is within our acceptable range.
|
||||
if sec < minUnixTime || sec > maxUnixTime {
|
||||
return time.Time{}, errTimestampOverflow
|
||||
}
|
||||
|
||||
// Return resulting time and propagate time zone.
|
||||
return time.Unix(sec, nsec).In(x.Location()), nil
|
||||
}
|
||||
|
||||
// subtractTimeChecked performs subtraction with overflow detection of two time.Time.
|
||||
//
|
||||
// If the operation fails due to overflow the error return value will be non-nil.
|
||||
func subtractTimeChecked(x, y time.Time) (time.Duration, error) {
|
||||
// Similar to addTimeDurationOverflow() above.
|
||||
|
||||
// First we break time into its components by truncating and subtracting.
|
||||
sec1 := x.Truncate(time.Second).Unix() // Truncate to seconds.
|
||||
nsec1 := x.Sub(x.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting.
|
||||
|
||||
// Second we break duration into its components by truncating and subtracting.
|
||||
sec2 := y.Truncate(time.Second).Unix() // Truncate to seconds.
|
||||
nsec2 := y.Sub(y.Truncate(time.Second)).Nanoseconds() // Get nanoseconds by truncating and subtracting.
|
||||
|
||||
// Subtract seconds first, detecting any overflow.
|
||||
sec, err := subtractInt64Checked(sec1, sec2)
|
||||
if err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
|
||||
// Nanoseconds cannot overflow as time.Time normalizes them to [0, 999999999].
|
||||
nsec := nsec1 - nsec2
|
||||
|
||||
// Scale seconds to nanoseconds detecting overflow.
|
||||
tsec, err := multiplyInt64Checked(sec, int64(time.Second))
|
||||
if err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
|
||||
// Lastly we need to add the two nanoseconds together.
|
||||
val, err := addInt64Checked(tsec, nsec)
|
||||
if err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
|
||||
return time.Duration(val), nil
|
||||
}
|
||||
|
||||
// subtractTimeDurationChecked performs subtraction with overflow detection of a time.Time and
|
||||
// time.Duration.
|
||||
//
|
||||
// If the operation fails due to overflow the error return value will be non-nil.
|
||||
func subtractTimeDurationChecked(x time.Time, y time.Duration) (time.Time, error) {
|
||||
// The easiest way to implement this is to negate y and add them.
|
||||
// x - y = x + -y
|
||||
val, err := negateDurationChecked(y)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return addTimeDurationChecked(x, val)
|
||||
}
|
||||
|
||||
// doubleToInt64Checked converts a double to an int64 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func doubleToInt64Checked(v float64) (int64, error) {
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return int64(v), nil
|
||||
}
|
||||
|
||||
// doubleToInt64Checked converts a double to a uint64 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func doubleToUint64Checked(v float64) (uint64, error) {
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) || v < 0 || v >= doubleTwoTo64 {
|
||||
return 0, errUintOverflow
|
||||
}
|
||||
return uint64(v), nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if v < 0 {
|
||||
return 0, errUintOverflow
|
||||
}
|
||||
return uint64(v), nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if v < math.MinInt32 || v > math.MaxInt32 {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return int32(v), nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if v > math.MaxUint32 {
|
||||
return 0, errUintOverflow
|
||||
}
|
||||
return uint32(v), nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if v > math.MaxInt64 {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return int64(v), nil
|
||||
}
|
||||
50
vendor/github.com/google/cel-go/common/types/pb/BUILD.bazel
generated
vendored
Normal file
50
vendor/github.com/google/cel-go/common/types/pb/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"checked.go",
|
||||
"enum.go",
|
||||
"file.go",
|
||||
"pb.go",
|
||||
"type.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/types/pb",
|
||||
deps = [
|
||||
"@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//reflect/protoregistry:go_default_library",
|
||||
"@org_golang_google_protobuf//types/dynamicpb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/anypb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/durationpb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"file_test.go",
|
||||
"pb_test.go",
|
||||
"type_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//checker/decls:go_default_library",
|
||||
"//test/proto2pb:test_all_types_go_proto",
|
||||
"//test/proto3pb:test_all_types_go_proto",
|
||||
"@org_golang_google_protobuf//reflect/protodesc:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
|
||||
"@org_golang_google_protobuf//types/descriptorpb:go_default_library",
|
||||
],
|
||||
)
|
||||
93
vendor/github.com/google/cel-go/common/types/pb/checked.go
generated
vendored
Normal file
93
vendor/github.com/google/cel-go/common/types/pb/checked.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2018 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 pb
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
var (
|
||||
// CheckedPrimitives map from proto field descriptor type to expr.Type.
|
||||
CheckedPrimitives = map[protoreflect.Kind]*exprpb.Type{
|
||||
protoreflect.BoolKind: checkedBool,
|
||||
protoreflect.BytesKind: checkedBytes,
|
||||
protoreflect.DoubleKind: checkedDouble,
|
||||
protoreflect.FloatKind: checkedDouble,
|
||||
protoreflect.Int32Kind: checkedInt,
|
||||
protoreflect.Int64Kind: checkedInt,
|
||||
protoreflect.Sint32Kind: checkedInt,
|
||||
protoreflect.Sint64Kind: checkedInt,
|
||||
protoreflect.Uint32Kind: checkedUint,
|
||||
protoreflect.Uint64Kind: checkedUint,
|
||||
protoreflect.Fixed32Kind: checkedUint,
|
||||
protoreflect.Fixed64Kind: checkedUint,
|
||||
protoreflect.Sfixed32Kind: checkedInt,
|
||||
protoreflect.Sfixed64Kind: checkedInt,
|
||||
protoreflect.StringKind: checkedString}
|
||||
|
||||
// CheckedWellKnowns map from qualified proto type name to expr.Type for
|
||||
// well-known proto types.
|
||||
CheckedWellKnowns = map[string]*exprpb.Type{
|
||||
// Wrapper types.
|
||||
"google.protobuf.BoolValue": checkedWrap(checkedBool),
|
||||
"google.protobuf.BytesValue": checkedWrap(checkedBytes),
|
||||
"google.protobuf.DoubleValue": checkedWrap(checkedDouble),
|
||||
"google.protobuf.FloatValue": checkedWrap(checkedDouble),
|
||||
"google.protobuf.Int64Value": checkedWrap(checkedInt),
|
||||
"google.protobuf.Int32Value": checkedWrap(checkedInt),
|
||||
"google.protobuf.UInt64Value": checkedWrap(checkedUint),
|
||||
"google.protobuf.UInt32Value": checkedWrap(checkedUint),
|
||||
"google.protobuf.StringValue": checkedWrap(checkedString),
|
||||
// Well-known types.
|
||||
"google.protobuf.Any": checkedAny,
|
||||
"google.protobuf.Duration": checkedDuration,
|
||||
"google.protobuf.Timestamp": checkedTimestamp,
|
||||
// Json types.
|
||||
"google.protobuf.ListValue": checkedListDyn,
|
||||
"google.protobuf.NullValue": checkedNull,
|
||||
"google.protobuf.Struct": checkedMapStringDyn,
|
||||
"google.protobuf.Value": checkedDyn,
|
||||
}
|
||||
|
||||
// common types
|
||||
checkedDyn = &exprpb.Type{TypeKind: &exprpb.Type_Dyn{Dyn: &emptypb.Empty{}}}
|
||||
// Wrapper and primitive types.
|
||||
checkedBool = checkedPrimitive(exprpb.Type_BOOL)
|
||||
checkedBytes = checkedPrimitive(exprpb.Type_BYTES)
|
||||
checkedDouble = checkedPrimitive(exprpb.Type_DOUBLE)
|
||||
checkedInt = checkedPrimitive(exprpb.Type_INT64)
|
||||
checkedString = checkedPrimitive(exprpb.Type_STRING)
|
||||
checkedUint = checkedPrimitive(exprpb.Type_UINT64)
|
||||
// Well-known type equivalents.
|
||||
checkedAny = checkedWellKnown(exprpb.Type_ANY)
|
||||
checkedDuration = checkedWellKnown(exprpb.Type_DURATION)
|
||||
checkedTimestamp = checkedWellKnown(exprpb.Type_TIMESTAMP)
|
||||
// Json-based type equivalents.
|
||||
checkedNull = &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Null{
|
||||
Null: structpb.NullValue_NULL_VALUE}}
|
||||
checkedListDyn = &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_ListType_{
|
||||
ListType: &exprpb.Type_ListType{ElemType: checkedDyn}}}
|
||||
checkedMapStringDyn = &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_MapType_{
|
||||
MapType: &exprpb.Type_MapType{
|
||||
KeyType: checkedString,
|
||||
ValueType: checkedDyn}}}
|
||||
)
|
||||
44
vendor/github.com/google/cel-go/common/types/pb/enum.go
generated
vendored
Normal file
44
vendor/github.com/google/cel-go/common/types/pb/enum.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2018 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 pb
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
return &EnumValueDescription{
|
||||
enumValueName: name,
|
||||
desc: desc,
|
||||
}
|
||||
}
|
||||
|
||||
// EnumValueDescription maps a fully-qualified enum value name to its numeric value.
|
||||
type EnumValueDescription struct {
|
||||
enumValueName string
|
||||
desc protoreflect.EnumValueDescriptor
|
||||
}
|
||||
|
||||
// Name returns the fully-qualified identifier name for the enum value.
|
||||
func (ed *EnumValueDescription) Name() string {
|
||||
return ed.enumValueName
|
||||
}
|
||||
|
||||
// Value returns the (numeric) value of the enum.
|
||||
func (ed *EnumValueDescription) Value() int32 {
|
||||
return int32(ed.desc.Number())
|
||||
}
|
||||
141
vendor/github.com/google/cel-go/common/types/pb/file.go
generated
vendored
Normal file
141
vendor/github.com/google/cel-go/common/types/pb/file.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright 2018 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 pb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
metadata := collectFileMetadata(fileDesc)
|
||||
enums := make(map[string]*EnumValueDescription)
|
||||
for name, enumVal := range metadata.enumValues {
|
||||
enums[name] = NewEnumValueDescription(name, enumVal)
|
||||
}
|
||||
types := make(map[string]*TypeDescription)
|
||||
for name, msgType := range metadata.msgTypes {
|
||||
types[name] = NewTypeDescription(name, msgType)
|
||||
}
|
||||
return &FileDescription{
|
||||
types: types,
|
||||
enums: enums,
|
||||
}
|
||||
}
|
||||
|
||||
// FileDescription holds a map of all types and enum values declared within a proto file.
|
||||
type FileDescription struct {
|
||||
types map[string]*TypeDescription
|
||||
enums map[string]*EnumValueDescription
|
||||
}
|
||||
|
||||
// GetEnumDescription returns an EnumDescription for a qualified enum value
|
||||
// name declared within the .proto file.
|
||||
func (fd *FileDescription) GetEnumDescription(enumName string) (*EnumValueDescription, bool) {
|
||||
ed, found := fd.enums[sanitizeProtoName(enumName)]
|
||||
return ed, found
|
||||
}
|
||||
|
||||
// GetEnumNames returns the string names of all enum values in the file.
|
||||
func (fd *FileDescription) GetEnumNames() []string {
|
||||
enumNames := make([]string, len(fd.enums))
|
||||
i := 0
|
||||
for _, e := range fd.enums {
|
||||
enumNames[i] = e.Name()
|
||||
i++
|
||||
}
|
||||
return enumNames
|
||||
}
|
||||
|
||||
// GetTypeDescription returns a TypeDescription for a qualified protobuf message type name
|
||||
// declared within the .proto file.
|
||||
func (fd *FileDescription) GetTypeDescription(typeName string) (*TypeDescription, bool) {
|
||||
td, found := fd.types[sanitizeProtoName(typeName)]
|
||||
return td, found
|
||||
}
|
||||
|
||||
// GetTypeNames returns the list of all type names contained within the file.
|
||||
func (fd *FileDescription) GetTypeNames() []string {
|
||||
typeNames := make([]string, len(fd.types))
|
||||
i := 0
|
||||
for _, t := range fd.types {
|
||||
typeNames[i] = t.Name()
|
||||
i++
|
||||
}
|
||||
return typeNames
|
||||
}
|
||||
|
||||
// sanitizeProtoName strips the leading '.' from the proto message name.
|
||||
func sanitizeProtoName(name string) string {
|
||||
if name != "" && name[0] == '.' {
|
||||
return name[1:]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// fileMetadata is a flattened view of message types and enum values within a file descriptor.
|
||||
type fileMetadata struct {
|
||||
// msgTypes maps from fully-qualified message name to descriptor.
|
||||
msgTypes map[string]protoreflect.MessageDescriptor
|
||||
// enumValues maps from fully-qualified enum value to enum value descriptor.
|
||||
enumValues map[string]protoreflect.EnumValueDescriptor
|
||||
// TODO: support enum type definitions for use in future type-check enhancements.
|
||||
}
|
||||
|
||||
// collectFileMetadata traverses the proto file object graph to collect message types and enum
|
||||
// values and index them by their fully qualified names.
|
||||
func collectFileMetadata(fileDesc protoreflect.FileDescriptor) *fileMetadata {
|
||||
msgTypes := make(map[string]protoreflect.MessageDescriptor)
|
||||
enumValues := make(map[string]protoreflect.EnumValueDescriptor)
|
||||
collectMsgTypes(fileDesc.Messages(), msgTypes, enumValues)
|
||||
collectEnumValues(fileDesc.Enums(), enumValues)
|
||||
return &fileMetadata{
|
||||
msgTypes: msgTypes,
|
||||
enumValues: enumValues,
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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)
|
||||
}
|
||||
nestedEnumTypes := msgType.Enums()
|
||||
if nestedEnumTypes.Len() != 0 {
|
||||
collectEnumValues(nestedEnumTypes, enumValueMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// collectEnumValues accumulates the enum values within an enum declaration.
|
||||
func collectEnumValues(enumTypes protoreflect.EnumDescriptors, enumValueMap map[string]protoreflect.EnumValueDescriptor) {
|
||||
for i := 0; i < enumTypes.Len(); i++ {
|
||||
enumType := enumTypes.Get(i)
|
||||
enumTypeValues := enumType.Values()
|
||||
for j := 0; j < enumTypeValues.Len(); j++ {
|
||||
enumValue := enumTypeValues.Get(j)
|
||||
enumValueName := fmt.Sprintf("%s.%s", string(enumType.FullName()), string(enumValue.Name()))
|
||||
enumValueMap[enumValueName] = enumValue
|
||||
}
|
||||
}
|
||||
}
|
||||
196
vendor/github.com/google/cel-go/common/types/pb/pb.go
generated
vendored
Normal file
196
vendor/github.com/google/cel-go/common/types/pb/pb.go
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
// Copyright 2018 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 pb reflects over protocol buffer descriptors to generate objects
|
||||
// that simplify type, enum, and field lookup.
|
||||
package pb
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
durpb "google.golang.org/protobuf/types/known/durationpb"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
tspb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
// Db maps from file / message / enum name to file description.
|
||||
//
|
||||
// Each Db is isolated from each other, and while information about protobuf descriptors may be
|
||||
// fetched from the global protobuf registry, no descriptors are added to this registry, else
|
||||
// the isolation guarantees of the Db object would be violated.
|
||||
type Db struct {
|
||||
revFileDescriptorMap map[string]*FileDescription
|
||||
// files contains the deduped set of FileDescriptions whose types are contained in the pb.Db.
|
||||
files []*FileDescription
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultDb used at evaluation time or unless overridden at check time.
|
||||
DefaultDb = &Db{
|
||||
revFileDescriptorMap: make(map[string]*FileDescription),
|
||||
files: []*FileDescription{},
|
||||
}
|
||||
)
|
||||
|
||||
// NewDb creates a new `pb.Db` with an empty type name to file description map.
|
||||
func NewDb() *Db {
|
||||
pbdb := &Db{
|
||||
revFileDescriptorMap: make(map[string]*FileDescription),
|
||||
files: []*FileDescription{},
|
||||
}
|
||||
// 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
|
||||
// copy; however, the type graph for a field is idempotently computed, and is guaranteed to
|
||||
// only be initialized once thanks to atomic values within the TypeDescription objects, so it
|
||||
// is safe to share these values across instances.
|
||||
for k, v := range DefaultDb.revFileDescriptorMap {
|
||||
pbdb.revFileDescriptorMap[k] = v
|
||||
}
|
||||
pbdb.files = append(pbdb.files, DefaultDb.files...)
|
||||
return pbdb
|
||||
}
|
||||
|
||||
// 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 {
|
||||
hasFile := false
|
||||
for _, f2 := range copy.files {
|
||||
if f2 == f {
|
||||
hasFile = true
|
||||
}
|
||||
}
|
||||
if !hasFile {
|
||||
copy.files = append(copy.files, f)
|
||||
}
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
// FileDescriptions returns the set of file descriptions associated with this db.
|
||||
func (pbdb *Db) FileDescriptions() []*FileDescription {
|
||||
return pbdb.files
|
||||
}
|
||||
|
||||
// RegisterDescriptor produces a `FileDescription` from a `FileDescriptor` and registers the
|
||||
// message and enum types into the `pb.Db`.
|
||||
func (pbdb *Db) RegisterDescriptor(fileDesc protoreflect.FileDescriptor) (*FileDescription, error) {
|
||||
fd, found := pbdb.revFileDescriptorMap[fileDesc.Path()]
|
||||
if found {
|
||||
return fd, nil
|
||||
}
|
||||
// Make sure to search the global registry to see if a protoreflect.FileDescriptor for
|
||||
// the file specified has been linked into the binary. If so, use the copy of the descriptor
|
||||
// from the global cache.
|
||||
//
|
||||
// Note: Proto reflection relies on descriptor values being object equal rather than object
|
||||
// equivalence. This choice means that a FieldDescriptor generated from a FileDescriptorProto
|
||||
// will be incompatible with the FieldDescriptor in the global registry and any message created
|
||||
// from that global registry.
|
||||
globalFD, err := protoregistry.GlobalFiles.FindFileByPath(fileDesc.Path())
|
||||
if err == nil {
|
||||
fileDesc = globalFD
|
||||
}
|
||||
fd = 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
|
||||
|
||||
// Return the specific file descriptor registered.
|
||||
pbdb.files = append(pbdb.files, fd)
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// RegisterMessage produces a `FileDescription` from a `message` and registers the message and all
|
||||
// other definitions within the message file into the `pb.Db`.
|
||||
func (pbdb *Db) RegisterMessage(message proto.Message) (*FileDescription, error) {
|
||||
msgDesc := message.ProtoReflect().Descriptor()
|
||||
msgName := msgDesc.FullName()
|
||||
typeName := sanitizeProtoName(string(msgName))
|
||||
if fd, found := pbdb.revFileDescriptorMap[typeName]; found {
|
||||
return fd, nil
|
||||
}
|
||||
return pbdb.RegisterDescriptor(msgDesc.ParentFile())
|
||||
}
|
||||
|
||||
// DescribeEnum takes a qualified enum name and returns an `EnumDescription` if it exists in the
|
||||
// `pb.Db`.
|
||||
func (pbdb *Db) DescribeEnum(enumName string) (*EnumValueDescription, bool) {
|
||||
enumName = sanitizeProtoName(enumName)
|
||||
if fd, found := pbdb.revFileDescriptorMap[enumName]; found {
|
||||
return fd.GetEnumDescription(enumName)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// DescribeType returns a `TypeDescription` for the `typeName` if it exists in the `pb.Db`.
|
||||
func (pbdb *Db) DescribeType(typeName string) (*TypeDescription, bool) {
|
||||
typeName = sanitizeProtoName(typeName)
|
||||
if fd, found := pbdb.revFileDescriptorMap[typeName]; found {
|
||||
return fd.GetTypeDescription(typeName)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// CollectFileDescriptorSet builds a file descriptor set associated with the file where the input
|
||||
// message is declared.
|
||||
func CollectFileDescriptorSet(message proto.Message) map[string]protoreflect.FileDescriptor {
|
||||
fdMap := map[string]protoreflect.FileDescriptor{}
|
||||
parentFile := message.ProtoReflect().Descriptor().ParentFile()
|
||||
fdMap[parentFile.Path()] = parentFile
|
||||
// Initialize list of dependencies
|
||||
deps := make([]protoreflect.FileImport, parentFile.Imports().Len())
|
||||
for i := 0; i < parentFile.Imports().Len(); i++ {
|
||||
deps[i] = parentFile.Imports().Get(i)
|
||||
}
|
||||
// Expand list for new dependencies
|
||||
for i := 0; i < len(deps); i++ {
|
||||
dep := deps[i]
|
||||
if _, found := fdMap[dep.Path()]; found {
|
||||
continue
|
||||
}
|
||||
fdMap[dep.Path()] = dep.FileDescriptor
|
||||
for j := 0; j < dep.FileDescriptor.Imports().Len(); j++ {
|
||||
deps = append(deps, dep.FileDescriptor.Imports().Get(j))
|
||||
}
|
||||
}
|
||||
return fdMap
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Describe well-known types to ensure they can always be resolved by the check and interpret
|
||||
// execution phases.
|
||||
//
|
||||
// The following subset of message types is enough to ensure that all well-known types can
|
||||
// resolved in the runtime, since describing the value results in describing the whole file
|
||||
// where the message is declared.
|
||||
DefaultDb.RegisterMessage(&anypb.Any{})
|
||||
DefaultDb.RegisterMessage(&durpb.Duration{})
|
||||
DefaultDb.RegisterMessage(&emptypb.Empty{})
|
||||
DefaultDb.RegisterMessage(&tspb.Timestamp{})
|
||||
DefaultDb.RegisterMessage(&structpb.Value{})
|
||||
DefaultDb.RegisterMessage(&wrapperspb.BoolValue{})
|
||||
}
|
||||
532
vendor/github.com/google/cel-go/common/types/pb/type.go
generated
vendored
Normal file
532
vendor/github.com/google/cel-go/common/types/pb/type.go
generated
vendored
Normal file
@@ -0,0 +1,532 @@
|
||||
// Copyright 2018 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 pb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
dynamicpb "google.golang.org/protobuf/types/dynamicpb"
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
dpb "google.golang.org/protobuf/types/known/durationpb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
tpb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
// description is a private interface used to make it convenient to perform type unwrapping at
|
||||
// the TypeDescription or FieldDescription level.
|
||||
type description interface {
|
||||
// Zero returns an empty immutable protobuf message when the description is a protobuf message
|
||||
// type.
|
||||
Zero() proto.Message
|
||||
}
|
||||
|
||||
// NewTypeDescription produces a TypeDescription value for the fully-qualified proto type name
|
||||
// with a given descriptor.
|
||||
func NewTypeDescription(typeName string, desc protoreflect.MessageDescriptor) *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)
|
||||
}
|
||||
return &TypeDescription{
|
||||
typeName: typeName,
|
||||
desc: desc,
|
||||
msgType: msgType,
|
||||
fieldMap: fieldMap,
|
||||
reflectType: reflectTypeOf(msgZero),
|
||||
zeroMsg: zeroValueOf(msgZero),
|
||||
}
|
||||
}
|
||||
|
||||
// TypeDescription is a collection of type metadata relevant to expression
|
||||
// checking and evaluation.
|
||||
type TypeDescription struct {
|
||||
typeName string
|
||||
desc protoreflect.MessageDescriptor
|
||||
msgType protoreflect.MessageType
|
||||
fieldMap map[string]*FieldDescription
|
||||
reflectType reflect.Type
|
||||
zeroMsg proto.Message
|
||||
}
|
||||
|
||||
// FieldMap returns a string field name to FieldDescription map.
|
||||
func (td *TypeDescription) FieldMap() map[string]*FieldDescription {
|
||||
return td.fieldMap
|
||||
}
|
||||
|
||||
// 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 nil, false
|
||||
}
|
||||
return fd, true
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return unwrap(td, msg)
|
||||
}
|
||||
|
||||
// Name returns the fully-qualified name of the type.
|
||||
func (td *TypeDescription) Name() string {
|
||||
return string(td.desc.FullName())
|
||||
}
|
||||
|
||||
// New returns a mutable proto message
|
||||
func (td *TypeDescription) New() protoreflect.Message {
|
||||
return td.msgType.New()
|
||||
}
|
||||
|
||||
// ReflectType returns the Golang reflect.Type for this type.
|
||||
func (td *TypeDescription) ReflectType() reflect.Type {
|
||||
return td.reflectType
|
||||
}
|
||||
|
||||
// Zero returns the zero proto.Message value for this type.
|
||||
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 {
|
||||
var reflectType reflect.Type
|
||||
var zeroMsg proto.Message
|
||||
switch fieldDesc.Kind() {
|
||||
case protoreflect.EnumKind:
|
||||
reflectType = reflectTypeOf(protoreflect.EnumNumber(0))
|
||||
case protoreflect.MessageKind:
|
||||
zeroMsg = dynamicpb.NewMessage(fieldDesc.Message())
|
||||
reflectType = reflectTypeOf(zeroMsg)
|
||||
default:
|
||||
reflectType = reflectTypeOf(fieldDesc.Default().Interface())
|
||||
if fieldDesc.IsList() {
|
||||
parentMsg := dynamicpb.NewMessage(fieldDesc.ContainingMessage())
|
||||
listField := parentMsg.NewField(fieldDesc).List()
|
||||
elem := listField.NewElement().Interface()
|
||||
switch elemType := elem.(type) {
|
||||
case protoreflect.Message:
|
||||
elem = elemType.Interface()
|
||||
}
|
||||
reflectType = reflectTypeOf(elem)
|
||||
}
|
||||
}
|
||||
// Ensure the list type is appropriately reflected as a Go-native list.
|
||||
if fieldDesc.IsList() {
|
||||
reflectType = reflect.SliceOf(reflectType)
|
||||
}
|
||||
var keyType, valType *FieldDescription
|
||||
if fieldDesc.IsMap() {
|
||||
keyType = NewFieldDescription(fieldDesc.MapKey())
|
||||
valType = NewFieldDescription(fieldDesc.MapValue())
|
||||
}
|
||||
return &FieldDescription{
|
||||
desc: fieldDesc,
|
||||
KeyType: keyType,
|
||||
ValueType: valType,
|
||||
reflectType: reflectType,
|
||||
zeroMsg: zeroValueOf(zeroMsg),
|
||||
}
|
||||
}
|
||||
|
||||
// FieldDescription holds metadata related to fields declared within a type.
|
||||
type FieldDescription struct {
|
||||
// KeyType holds the key FieldDescription for map fields.
|
||||
KeyType *FieldDescription
|
||||
// ValueType holds the value FieldDescription for map fields.
|
||||
ValueType *FieldDescription
|
||||
|
||||
desc protoreflect.FieldDescriptor
|
||||
reflectType reflect.Type
|
||||
zeroMsg proto.Message
|
||||
}
|
||||
|
||||
// CheckedType returns the type-definition used at type-check time.
|
||||
func (fd *FieldDescription) CheckedType() *exprpb.Type {
|
||||
if fd.desc.IsMap() {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_MapType_{
|
||||
MapType: &exprpb.Type_MapType{
|
||||
KeyType: fd.KeyType.typeDefToType(),
|
||||
ValueType: fd.ValueType.typeDefToType(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
if fd.desc.IsList() {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_ListType_{
|
||||
ListType: &exprpb.Type_ListType{
|
||||
ElemType: fd.typeDefToType()}}}
|
||||
}
|
||||
return fd.typeDefToType()
|
||||
}
|
||||
|
||||
// Descriptor returns the protoreflect.FieldDescriptor for this type.
|
||||
func (fd *FieldDescription) Descriptor() protoreflect.FieldDescriptor {
|
||||
return fd.desc
|
||||
}
|
||||
|
||||
// IsSet returns whether the field is set on the target value, per the proto presence conventions
|
||||
// of proto2 or proto3 accordingly.
|
||||
//
|
||||
// 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 {
|
||||
switch v := target.(type) {
|
||||
case proto.Message:
|
||||
pbRef := v.ProtoReflect()
|
||||
pbDesc := pbRef.Descriptor()
|
||||
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.
|
||||
return pbRef.Has(fd.desc)
|
||||
}
|
||||
// Otherwise, fallback to a dynamic lookup of the field descriptor from the target
|
||||
// instance as an attempt to use the cached field descriptor will result in a panic.
|
||||
return pbRef.Has(pbDesc.Fields().ByName(protoreflect.Name(fd.Name())))
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// GetFrom returns the accessor method associated with the field on the proto generated struct.
|
||||
//
|
||||
// If the field is not set, the proto default value is returned instead.
|
||||
//
|
||||
// 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) {
|
||||
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{}
|
||||
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.
|
||||
fieldVal = pbRef.Get(fd.desc).Interface()
|
||||
} else {
|
||||
// Otherwise, fallback to a dynamic lookup of the field descriptor from the target
|
||||
// instance as an attempt to use the cached field descriptor will result in a panic.
|
||||
fieldVal = pbRef.Get(pbDesc.Fields().ByName(protoreflect.Name(fd.Name()))).Interface()
|
||||
}
|
||||
switch fv := fieldVal.(type) {
|
||||
// Fast-path return for primitive types.
|
||||
case bool, []byte, float32, float64, int32, int64, string, uint32, uint64, protoreflect.List:
|
||||
return fv, nil
|
||||
case protoreflect.EnumNumber:
|
||||
return int64(fv), nil
|
||||
case protoreflect.Map:
|
||||
// Return a wrapper around the protobuf-reflected Map types which carries additional
|
||||
// information about the key and value definitions of the map.
|
||||
return &Map{Map: fv, KeyType: fd.KeyType, ValueType: fd.ValueType}, nil
|
||||
case protoreflect.Message:
|
||||
// Make sure to unwrap well-known protobuf types before returning.
|
||||
unwrapped, _ := fd.MaybeUnwrapDynamic(fv)
|
||||
return unwrapped, nil
|
||||
default:
|
||||
return fv, nil
|
||||
}
|
||||
}
|
||||
|
||||
// IsEnum returns true if the field type refers to an enum value.
|
||||
func (fd *FieldDescription) IsEnum() bool {
|
||||
return fd.desc.Kind() == protoreflect.EnumKind
|
||||
}
|
||||
|
||||
// IsMap returns true if the field is of map type.
|
||||
func (fd *FieldDescription) IsMap() bool {
|
||||
return fd.desc.IsMap()
|
||||
}
|
||||
|
||||
// IsMessage returns true if the field is of message type.
|
||||
func (fd *FieldDescription) IsMessage() bool {
|
||||
return fd.desc.Kind() == protoreflect.MessageKind
|
||||
}
|
||||
|
||||
// IsOneof returns true if the field is declared within a oneof block.
|
||||
func (fd *FieldDescription) IsOneof() bool {
|
||||
return fd.desc.ContainingOneof() != nil
|
||||
}
|
||||
|
||||
// IsList returns true if the field is a repeated value.
|
||||
//
|
||||
// This method will also return true for map values, so check whether the
|
||||
// field is also a map.
|
||||
func (fd *FieldDescription) IsList() bool {
|
||||
return fd.desc.IsList()
|
||||
}
|
||||
|
||||
// MaybeUnwrapDynamic takes the reflected protoreflect.Message and determines whether the
|
||||
// value can be unwrapped to a more primitive CEL type.
|
||||
//
|
||||
// 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) {
|
||||
return unwrapDynamic(fd, msg)
|
||||
}
|
||||
|
||||
// Name returns the CamelCase name of the field within the proto-based struct.
|
||||
func (fd *FieldDescription) Name() string {
|
||||
return string(fd.desc.Name())
|
||||
}
|
||||
|
||||
// ReflectType returns the Golang reflect.Type for this field.
|
||||
func (fd *FieldDescription) ReflectType() reflect.Type {
|
||||
return fd.reflectType
|
||||
}
|
||||
|
||||
// String returns the fully qualified name of the field within its type as well as whether the
|
||||
// field occurs within a oneof.
|
||||
func (fd *FieldDescription) String() string {
|
||||
return fmt.Sprintf("%v.%s `oneof=%t`", fd.desc.ContainingMessage().FullName(), fd.Name(), fd.IsOneof())
|
||||
}
|
||||
|
||||
// Zero returns the zero value for the protobuf message represented by this field.
|
||||
//
|
||||
// If the field is not a proto.Message type, the zero value is nil.
|
||||
func (fd *FieldDescription) Zero() proto.Message {
|
||||
return fd.zeroMsg
|
||||
}
|
||||
|
||||
func (fd *FieldDescription) typeDefToType() *exprpb.Type {
|
||||
if fd.desc.Kind() == protoreflect.MessageKind {
|
||||
msgType := string(fd.desc.Message().FullName())
|
||||
if wk, found := CheckedWellKnowns[msgType]; found {
|
||||
return wk
|
||||
}
|
||||
return checkedMessageType(msgType)
|
||||
}
|
||||
if fd.desc.Kind() == protoreflect.EnumKind {
|
||||
return checkedInt
|
||||
}
|
||||
return CheckedPrimitives[fd.desc.Kind()]
|
||||
}
|
||||
|
||||
// Map wraps the protoreflect.Map object with a key and value FieldDescription for use in
|
||||
// retrieving individual elements within CEL value data types.
|
||||
type Map struct {
|
||||
protoreflect.Map
|
||||
KeyType *FieldDescription
|
||||
ValueType *FieldDescription
|
||||
}
|
||||
|
||||
func checkedMessageType(name string) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_MessageType{MessageType: name}}
|
||||
}
|
||||
|
||||
func checkedPrimitive(primitive exprpb.Type_PrimitiveType) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Primitive{Primitive: primitive}}
|
||||
}
|
||||
|
||||
func checkedWellKnown(wellKnown exprpb.Type_WellKnownType) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_WellKnown{WellKnown: wellKnown}}
|
||||
}
|
||||
|
||||
func checkedWrap(t *exprpb.Type) *exprpb.Type {
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Wrapper{Wrapper: t.GetPrimitive()}}
|
||||
}
|
||||
|
||||
// unwrap unwraps the provided proto.Message value, potentially based on the description if the
|
||||
// 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) {
|
||||
switch v := msg.(type) {
|
||||
case *anypb.Any:
|
||||
dynMsg, err := v.UnmarshalNew()
|
||||
if err != nil {
|
||||
return v, false
|
||||
}
|
||||
return unwrapDynamic(desc, dynMsg.ProtoReflect())
|
||||
case *dynamicpb.Message:
|
||||
return unwrapDynamic(desc, v)
|
||||
case *dpb.Duration:
|
||||
return v.AsDuration(), true
|
||||
case *tpb.Timestamp:
|
||||
return v.AsTime(), true
|
||||
case *structpb.Value:
|
||||
switch v.GetKind().(type) {
|
||||
case *structpb.Value_BoolValue:
|
||||
return v.GetBoolValue(), true
|
||||
case *structpb.Value_ListValue:
|
||||
return v.GetListValue(), true
|
||||
case *structpb.Value_NullValue:
|
||||
return structpb.NullValue_NULL_VALUE, true
|
||||
case *structpb.Value_NumberValue:
|
||||
return v.GetNumberValue(), true
|
||||
case *structpb.Value_StringValue:
|
||||
return v.GetStringValue(), true
|
||||
case *structpb.Value_StructValue:
|
||||
return v.GetStructValue(), true
|
||||
default:
|
||||
return structpb.NullValue_NULL_VALUE, true
|
||||
}
|
||||
case *wrapperspb.BoolValue:
|
||||
return v.GetValue(), true
|
||||
case *wrapperspb.BytesValue:
|
||||
return v.GetValue(), true
|
||||
case *wrapperspb.DoubleValue:
|
||||
return v.GetValue(), true
|
||||
case *wrapperspb.FloatValue:
|
||||
return float64(v.GetValue()), true
|
||||
case *wrapperspb.Int32Value:
|
||||
return int64(v.GetValue()), true
|
||||
case *wrapperspb.Int64Value:
|
||||
return v.GetValue(), true
|
||||
case *wrapperspb.StringValue:
|
||||
return v.GetValue(), true
|
||||
case *wrapperspb.UInt32Value:
|
||||
return uint64(v.GetValue()), true
|
||||
case *wrapperspb.UInt64Value:
|
||||
return v.GetValue(), true
|
||||
}
|
||||
return msg, false
|
||||
}
|
||||
|
||||
// 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) {
|
||||
msg := refMsg.Interface()
|
||||
if !refMsg.IsValid() {
|
||||
msg = desc.Zero()
|
||||
}
|
||||
// In order to ensure that these wrapped types match the expectations of the CEL type system
|
||||
// the dynamicpb.Message must be merged with an protobuf instance of the well-known type value.
|
||||
typeName := string(refMsg.Descriptor().FullName())
|
||||
switch typeName {
|
||||
case "google.protobuf.Any":
|
||||
// Note, Any values require further unwrapping; however, this unwrapping may or may not
|
||||
// be to a well-known type. If the unwrapped value is a well-known type it will be further
|
||||
// unwrapped before being returned to the caller. Otherwise, the dynamic protobuf object
|
||||
// represented by the Any will be returned.
|
||||
unwrappedAny := &anypb.Any{}
|
||||
proto.Merge(unwrappedAny, msg)
|
||||
dynMsg, err := unwrappedAny.UnmarshalNew()
|
||||
if err != nil {
|
||||
// Allow the error to move further up the stack as it should result in an type
|
||||
// conversion error if the caller does not recover it somehow.
|
||||
return unwrappedAny, true
|
||||
}
|
||||
// Attempt to unwrap the dynamic type, otherwise return the dynamic message.
|
||||
if unwrapped, nested := unwrapDynamic(desc, dynMsg.ProtoReflect()); nested {
|
||||
return unwrapped, true
|
||||
}
|
||||
return dynMsg, true
|
||||
case "google.protobuf.BoolValue",
|
||||
"google.protobuf.BytesValue",
|
||||
"google.protobuf.DoubleValue",
|
||||
"google.protobuf.FloatValue",
|
||||
"google.protobuf.Int32Value",
|
||||
"google.protobuf.Int64Value",
|
||||
"google.protobuf.StringValue",
|
||||
"google.protobuf.UInt32Value",
|
||||
"google.protobuf.UInt64Value":
|
||||
// The msg value is ignored when dealing with wrapper types as they have a null or value
|
||||
// behavior, rather than the standard zero value behavior of other proto message types.
|
||||
if !refMsg.IsValid() {
|
||||
return structpb.NullValue_NULL_VALUE, true
|
||||
}
|
||||
valueField := refMsg.Descriptor().Fields().ByName("value")
|
||||
return refMsg.Get(valueField).Interface(), true
|
||||
case "google.protobuf.Duration":
|
||||
unwrapped := &dpb.Duration{}
|
||||
proto.Merge(unwrapped, msg)
|
||||
return unwrapped.AsDuration(), true
|
||||
case "google.protobuf.ListValue":
|
||||
unwrapped := &structpb.ListValue{}
|
||||
proto.Merge(unwrapped, msg)
|
||||
return unwrapped, true
|
||||
case "google.protobuf.NullValue":
|
||||
return structpb.NullValue_NULL_VALUE, true
|
||||
case "google.protobuf.Struct":
|
||||
unwrapped := &structpb.Struct{}
|
||||
proto.Merge(unwrapped, msg)
|
||||
return unwrapped, true
|
||||
case "google.protobuf.Timestamp":
|
||||
unwrapped := &tpb.Timestamp{}
|
||||
proto.Merge(unwrapped, msg)
|
||||
return unwrapped.AsTime(), true
|
||||
case "google.protobuf.Value":
|
||||
unwrapped := &structpb.Value{}
|
||||
proto.Merge(unwrapped, msg)
|
||||
return unwrap(desc, unwrapped)
|
||||
}
|
||||
return msg, false
|
||||
}
|
||||
|
||||
// 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 {
|
||||
switch v := val.(type) {
|
||||
case proto.Message:
|
||||
return reflect.TypeOf(zeroValueOf(v))
|
||||
default:
|
||||
return reflect.TypeOf(v)
|
||||
}
|
||||
}
|
||||
|
||||
// zeroValueOf will return the strongest possible proto.Message representing the default protobuf
|
||||
// message value of the input msg type.
|
||||
func zeroValueOf(msg proto.Message) proto.Message {
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
typeName := string(msg.ProtoReflect().Descriptor().FullName())
|
||||
zeroVal, found := zeroValueMap[typeName]
|
||||
if found {
|
||||
return zeroVal
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
var (
|
||||
zeroValueMap = map[string]proto.Message{
|
||||
"google.protobuf.Any": &anypb.Any{},
|
||||
"google.protobuf.Duration": &dpb.Duration{},
|
||||
"google.protobuf.ListValue": &structpb.ListValue{},
|
||||
"google.protobuf.Struct": &structpb.Struct{},
|
||||
"google.protobuf.Timestamp": &tpb.Timestamp{},
|
||||
"google.protobuf.Value": &structpb.Value{},
|
||||
"google.protobuf.BoolValue": wrapperspb.Bool(false),
|
||||
"google.protobuf.BytesValue": wrapperspb.Bytes([]byte{}),
|
||||
"google.protobuf.DoubleValue": wrapperspb.Double(0.0),
|
||||
"google.protobuf.FloatValue": wrapperspb.Float(0.0),
|
||||
"google.protobuf.Int32Value": wrapperspb.Int32(0),
|
||||
"google.protobuf.Int64Value": wrapperspb.Int64(0),
|
||||
"google.protobuf.StringValue": wrapperspb.String(""),
|
||||
"google.protobuf.UInt32Value": wrapperspb.UInt32(0),
|
||||
"google.protobuf.UInt64Value": wrapperspb.UInt64(0),
|
||||
}
|
||||
)
|
||||
533
vendor/github.com/google/cel-go/common/types/provider.go
generated
vendored
Normal file
533
vendor/github.com/google/cel-go/common/types/provider.go
generated
vendored
Normal file
@@ -0,0 +1,533 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
dpb "google.golang.org/protobuf/types/known/durationpb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
tpb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type protoTypeRegistry struct {
|
||||
revTypeMap map[string]ref.Type
|
||||
pbdb *pb.Db
|
||||
}
|
||||
|
||||
// NewRegistry accepts a list of proto message instances and returns a type
|
||||
// provider which can create new instances of the provided message or any
|
||||
// message that proto depends upon in its FileDescriptor.
|
||||
func NewRegistry(types ...proto.Message) (ref.TypeRegistry, error) {
|
||||
p := &protoTypeRegistry{
|
||||
revTypeMap: make(map[string]ref.Type),
|
||||
pbdb: pb.NewDb(),
|
||||
}
|
||||
err := p.RegisterType(
|
||||
BoolType,
|
||||
BytesType,
|
||||
DoubleType,
|
||||
DurationType,
|
||||
IntType,
|
||||
ListType,
|
||||
MapType,
|
||||
NullType,
|
||||
StringType,
|
||||
TimestampType,
|
||||
TypeType,
|
||||
UintType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// This block ensures that the well-known protobuf types are registered by default.
|
||||
for _, fd := range p.pbdb.FileDescriptions() {
|
||||
err = p.registerAllTypes(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, msgType := range types {
|
||||
err = p.RegisterMessage(msgType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// NewEmptyRegistry returns a registry which is completely unconfigured.
|
||||
func NewEmptyRegistry() ref.TypeRegistry {
|
||||
return &protoTypeRegistry{
|
||||
revTypeMap: make(map[string]ref.Type),
|
||||
pbdb: pb.NewDb(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy implements the ref.TypeRegistry interface method which copies the current state of the
|
||||
// registry into its own memory space.
|
||||
func (p *protoTypeRegistry) Copy() ref.TypeRegistry {
|
||||
copy := &protoTypeRegistry{
|
||||
revTypeMap: make(map[string]ref.Type),
|
||||
pbdb: p.pbdb.Copy(),
|
||||
}
|
||||
for k, v := range p.revTypeMap {
|
||||
copy.revTypeMap[k] = v
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
func (p *protoTypeRegistry) EnumValue(enumName string) ref.Val {
|
||||
enumVal, found := p.pbdb.DescribeEnum(enumName)
|
||||
if !found {
|
||||
return NewErr("unknown enum name '%s'", enumName)
|
||||
}
|
||||
return Int(enumVal.Value())
|
||||
}
|
||||
|
||||
func (p *protoTypeRegistry) FindFieldType(messageType string,
|
||||
fieldName string) (*ref.FieldType, bool) {
|
||||
msgType, found := p.pbdb.DescribeType(messageType)
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
field, found := msgType.FieldByName(fieldName)
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
return &ref.FieldType{
|
||||
Type: field.CheckedType(),
|
||||
IsSet: field.IsSet,
|
||||
GetFrom: field.GetFrom},
|
||||
true
|
||||
}
|
||||
|
||||
func (p *protoTypeRegistry) FindIdent(identName string) (ref.Val, bool) {
|
||||
if t, found := p.revTypeMap[identName]; found {
|
||||
return t.(ref.Val), true
|
||||
}
|
||||
if enumVal, found := p.pbdb.DescribeEnum(identName); found {
|
||||
return Int(enumVal.Value()), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *protoTypeRegistry) FindType(typeName string) (*exprpb.Type, bool) {
|
||||
if _, found := p.pbdb.DescribeType(typeName); !found {
|
||||
return nil, false
|
||||
}
|
||||
if typeName != "" && typeName[0] == '.' {
|
||||
typeName = typeName[1:]
|
||||
}
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Type{
|
||||
Type: &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_MessageType{
|
||||
MessageType: typeName}}}}, true
|
||||
}
|
||||
|
||||
func (p *protoTypeRegistry) NewValue(typeName string, fields map[string]ref.Val) ref.Val {
|
||||
td, found := p.pbdb.DescribeType(typeName)
|
||||
if !found {
|
||||
return NewErr("unknown type '%s'", typeName)
|
||||
}
|
||||
msg := td.New()
|
||||
fieldMap := td.FieldMap()
|
||||
for name, value := range fields {
|
||||
field, found := fieldMap[name]
|
||||
if !found {
|
||||
return NewErr("no such field: %s", name)
|
||||
}
|
||||
err := msgSetField(msg, field, value)
|
||||
if err != nil {
|
||||
return &Err{err}
|
||||
}
|
||||
}
|
||||
return p.NativeToValue(msg.Interface())
|
||||
}
|
||||
|
||||
func (p *protoTypeRegistry) RegisterDescriptor(fileDesc protoreflect.FileDescriptor) error {
|
||||
fd, err := p.pbdb.RegisterDescriptor(fileDesc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.registerAllTypes(fd)
|
||||
}
|
||||
|
||||
func (p *protoTypeRegistry) RegisterMessage(message proto.Message) error {
|
||||
fd, err := p.pbdb.RegisterMessage(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.registerAllTypes(fd)
|
||||
}
|
||||
|
||||
func (p *protoTypeRegistry) RegisterType(types ...ref.Type) error {
|
||||
for _, t := range types {
|
||||
p.revTypeMap[t.TypeName()] = t
|
||||
}
|
||||
// TODO: generate an error when the type name is registered more than once.
|
||||
return nil
|
||||
}
|
||||
|
||||
// NativeToValue converts various "native" types to ref.Val with this specific implementation
|
||||
// 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 {
|
||||
if val, found := nativeToValue(p, value); found {
|
||||
return val
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case proto.Message:
|
||||
typeName := string(v.ProtoReflect().Descriptor().FullName())
|
||||
td, found := p.pbdb.DescribeType(typeName)
|
||||
if !found {
|
||||
return NewErr("unknown type: '%s'", typeName)
|
||||
}
|
||||
unwrapped, isUnwrapped := td.MaybeUnwrap(v)
|
||||
if isUnwrapped {
|
||||
return p.NativeToValue(unwrapped)
|
||||
}
|
||||
typeVal, found := p.FindIdent(typeName)
|
||||
if !found {
|
||||
return NewErr("unknown type: '%s'", typeName)
|
||||
}
|
||||
return NewObject(p, td, typeVal.(*TypeValue), v)
|
||||
case *pb.Map:
|
||||
return NewProtoMap(p, v)
|
||||
case protoreflect.List:
|
||||
return NewProtoList(p, v)
|
||||
case protoreflect.Message:
|
||||
return p.NativeToValue(v.Interface())
|
||||
case protoreflect.Value:
|
||||
return p.NativeToValue(v.Interface())
|
||||
}
|
||||
return UnsupportedRefValConversionErr(value)
|
||||
}
|
||||
|
||||
func (p *protoTypeRegistry) registerAllTypes(fd *pb.FileDescription) error {
|
||||
for _, typeName := range fd.GetTypeNames() {
|
||||
err := p.RegisterType(NewObjectTypeValue(typeName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// defaultTypeAdapter converts go native types to CEL values.
|
||||
type defaultTypeAdapter struct{}
|
||||
|
||||
var (
|
||||
// DefaultTypeAdapter adapts canonical CEL types from their equivalent Go values.
|
||||
DefaultTypeAdapter = &defaultTypeAdapter{}
|
||||
)
|
||||
|
||||
// NativeToValue implements the ref.TypeAdapter interface.
|
||||
func (a *defaultTypeAdapter) NativeToValue(value interface{}) ref.Val {
|
||||
if val, found := nativeToValue(a, value); found {
|
||||
return val
|
||||
}
|
||||
return UnsupportedRefValConversionErr(value)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
switch v := value.(type) {
|
||||
case nil:
|
||||
return NullValue, true
|
||||
case *Bool:
|
||||
if v != nil {
|
||||
return *v, true
|
||||
}
|
||||
case *Bytes:
|
||||
if v != nil {
|
||||
return *v, true
|
||||
}
|
||||
case *Double:
|
||||
if v != nil {
|
||||
return *v, true
|
||||
}
|
||||
case *Int:
|
||||
if v != nil {
|
||||
return *v, true
|
||||
}
|
||||
case *String:
|
||||
if v != nil {
|
||||
return *v, true
|
||||
}
|
||||
case *Uint:
|
||||
if v != nil {
|
||||
return *v, true
|
||||
}
|
||||
case bool:
|
||||
return Bool(v), true
|
||||
case int:
|
||||
return Int(v), true
|
||||
case int32:
|
||||
return Int(v), true
|
||||
case int64:
|
||||
return Int(v), true
|
||||
case uint:
|
||||
return Uint(v), true
|
||||
case uint32:
|
||||
return Uint(v), true
|
||||
case uint64:
|
||||
return Uint(v), true
|
||||
case float32:
|
||||
return Double(v), true
|
||||
case float64:
|
||||
return Double(v), true
|
||||
case string:
|
||||
return String(v), true
|
||||
case *dpb.Duration:
|
||||
return Duration{Duration: v.AsDuration()}, true
|
||||
case time.Duration:
|
||||
return Duration{Duration: v}, true
|
||||
case *tpb.Timestamp:
|
||||
return Timestamp{Time: v.AsTime()}, true
|
||||
case time.Time:
|
||||
return Timestamp{Time: v}, true
|
||||
case *bool:
|
||||
if v != nil {
|
||||
return Bool(*v), true
|
||||
}
|
||||
case *float32:
|
||||
if v != nil {
|
||||
return Double(*v), true
|
||||
}
|
||||
case *float64:
|
||||
if v != nil {
|
||||
return Double(*v), true
|
||||
}
|
||||
case *int:
|
||||
if v != nil {
|
||||
return Int(*v), true
|
||||
}
|
||||
case *int32:
|
||||
if v != nil {
|
||||
return Int(*v), true
|
||||
}
|
||||
case *int64:
|
||||
if v != nil {
|
||||
return Int(*v), true
|
||||
}
|
||||
case *string:
|
||||
if v != nil {
|
||||
return String(*v), true
|
||||
}
|
||||
case *uint:
|
||||
if v != nil {
|
||||
return Uint(*v), true
|
||||
}
|
||||
case *uint32:
|
||||
if v != nil {
|
||||
return Uint(*v), true
|
||||
}
|
||||
case *uint64:
|
||||
if v != nil {
|
||||
return Uint(*v), true
|
||||
}
|
||||
case []byte:
|
||||
return Bytes(v), true
|
||||
// specializations for common lists types.
|
||||
case []string:
|
||||
return NewStringList(a, v), true
|
||||
case []ref.Val:
|
||||
return NewRefValList(a, v), true
|
||||
// specializations for common map types.
|
||||
case map[string]string:
|
||||
return NewStringStringMap(a, v), true
|
||||
case map[string]interface{}:
|
||||
return NewStringInterfaceMap(a, v), true
|
||||
case map[ref.Val]ref.Val:
|
||||
return NewRefValMap(a, v), true
|
||||
// additional specializations may be added upon request / need.
|
||||
case *anypb.Any:
|
||||
if v == nil {
|
||||
return UnsupportedRefValConversionErr(v), true
|
||||
}
|
||||
unpackedAny, err := v.UnmarshalNew()
|
||||
if err != nil {
|
||||
return NewErr("anypb.UnmarshalNew() failed for type %q: %v", v.GetTypeUrl(), err), true
|
||||
}
|
||||
return a.NativeToValue(unpackedAny), true
|
||||
case *structpb.NullValue, structpb.NullValue:
|
||||
return NullValue, true
|
||||
case *structpb.ListValue:
|
||||
return NewJSONList(a, v), true
|
||||
case *structpb.Struct:
|
||||
return NewJSONStruct(a, v), true
|
||||
case ref.Val:
|
||||
return v, true
|
||||
case protoreflect.EnumNumber:
|
||||
return Int(v), true
|
||||
case proto.Message:
|
||||
if v == nil {
|
||||
return UnsupportedRefValConversionErr(v), true
|
||||
}
|
||||
typeName := string(v.ProtoReflect().Descriptor().FullName())
|
||||
td, found := pb.DefaultDb.DescribeType(typeName)
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
val, unwrapped := td.MaybeUnwrap(v)
|
||||
if !unwrapped {
|
||||
return nil, false
|
||||
}
|
||||
return a.NativeToValue(val), true
|
||||
// Note: dynamicpb.Message implements the proto.Message _and_ protoreflect.Message interfaces
|
||||
// which means that this case must appear after handling a proto.Message type.
|
||||
case protoreflect.Message:
|
||||
return a.NativeToValue(v.Interface()), true
|
||||
default:
|
||||
refValue := reflect.ValueOf(v)
|
||||
if refValue.Kind() == reflect.Ptr {
|
||||
if refValue.IsNil() {
|
||||
return UnsupportedRefValConversionErr(v), true
|
||||
}
|
||||
refValue = refValue.Elem()
|
||||
}
|
||||
refKind := refValue.Kind()
|
||||
switch refKind {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return NewDynamicList(a, v), true
|
||||
case reflect.Map:
|
||||
return NewDynamicMap(a, v), true
|
||||
// type aliases of primitive types cannot be asserted as that type, but rather need
|
||||
// to be downcast to int32 before being converted to a CEL representation.
|
||||
case reflect.Int32:
|
||||
intType := reflect.TypeOf(int32(0))
|
||||
return Int(refValue.Convert(intType).Interface().(int32)), true
|
||||
case reflect.Int64:
|
||||
intType := reflect.TypeOf(int64(0))
|
||||
return Int(refValue.Convert(intType).Interface().(int64)), true
|
||||
case reflect.Uint32:
|
||||
uintType := reflect.TypeOf(uint32(0))
|
||||
return Uint(refValue.Convert(uintType).Interface().(uint32)), true
|
||||
case reflect.Uint64:
|
||||
uintType := reflect.TypeOf(uint64(0))
|
||||
return Uint(refValue.Convert(uintType).Interface().(uint64)), true
|
||||
case reflect.Float32:
|
||||
doubleType := reflect.TypeOf(float32(0))
|
||||
return Double(refValue.Convert(doubleType).Interface().(float32)), true
|
||||
case reflect.Float64:
|
||||
doubleType := reflect.TypeOf(float64(0))
|
||||
return Double(refValue.Convert(doubleType).Interface().(float64)), true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func msgSetField(target protoreflect.Message, field *pb.FieldDescription, val ref.Val) error {
|
||||
if field.IsList() {
|
||||
lv := target.NewField(field.Descriptor())
|
||||
list, ok := val.(traits.Lister)
|
||||
if !ok {
|
||||
return unsupportedTypeConversionError(field, val)
|
||||
}
|
||||
err := msgSetListField(lv.List(), field, list)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target.Set(field.Descriptor(), lv)
|
||||
return nil
|
||||
}
|
||||
if field.IsMap() {
|
||||
mv := target.NewField(field.Descriptor())
|
||||
mp, ok := val.(traits.Mapper)
|
||||
if !ok {
|
||||
return unsupportedTypeConversionError(field, val)
|
||||
}
|
||||
err := msgSetMapField(mv.Map(), field, mp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target.Set(field.Descriptor(), mv)
|
||||
return nil
|
||||
}
|
||||
v, err := val.ConvertToNative(field.ReflectType())
|
||||
if err != nil {
|
||||
return fieldTypeConversionError(field, err)
|
||||
}
|
||||
switch v.(type) {
|
||||
case proto.Message:
|
||||
v = v.(proto.Message).ProtoReflect()
|
||||
}
|
||||
target.Set(field.Descriptor(), protoreflect.ValueOf(v))
|
||||
return nil
|
||||
}
|
||||
|
||||
func msgSetListField(target protoreflect.List, listField *pb.FieldDescription, listVal traits.Lister) error {
|
||||
elemReflectType := listField.ReflectType().Elem()
|
||||
for i := Int(0); i < listVal.Size().(Int); i++ {
|
||||
elem := listVal.Get(i)
|
||||
elemVal, err := elem.ConvertToNative(elemReflectType)
|
||||
if err != nil {
|
||||
return fieldTypeConversionError(listField, err)
|
||||
}
|
||||
switch ev := elemVal.(type) {
|
||||
case proto.Message:
|
||||
elemVal = ev.ProtoReflect()
|
||||
}
|
||||
target.Append(protoreflect.ValueOf(elemVal))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func msgSetMapField(target protoreflect.Map, mapField *pb.FieldDescription, mapVal traits.Mapper) error {
|
||||
targetKeyType := mapField.KeyType.ReflectType()
|
||||
targetValType := mapField.ValueType.ReflectType()
|
||||
it := mapVal.Iterator()
|
||||
for it.HasNext() == True {
|
||||
key := it.Next()
|
||||
val := mapVal.Get(key)
|
||||
k, err := key.ConvertToNative(targetKeyType)
|
||||
if err != nil {
|
||||
return fieldTypeConversionError(mapField, err)
|
||||
}
|
||||
v, err := val.ConvertToNative(targetValType)
|
||||
if err != nil {
|
||||
return fieldTypeConversionError(mapField, err)
|
||||
}
|
||||
switch v.(type) {
|
||||
case proto.Message:
|
||||
v = v.(proto.Message).ProtoReflect()
|
||||
}
|
||||
target.Set(protoreflect.ValueOf(k).MapKey(), protoreflect.ValueOf(v))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unsupportedTypeConversionError(field *pb.FieldDescription, val ref.Val) error {
|
||||
msgName := field.Descriptor().ContainingMessage().FullName()
|
||||
return fmt.Errorf("unsupported field type for %v.%v: %v", msgName, field.Name(), val.Type())
|
||||
}
|
||||
|
||||
func fieldTypeConversionError(field *pb.FieldDescription, err error) error {
|
||||
msgName := field.Descriptor().ContainingMessage().FullName()
|
||||
return fmt.Errorf("field type conversion error for %v.%v value type: %v", msgName, field.Name(), err)
|
||||
}
|
||||
20
vendor/github.com/google/cel-go/common/types/ref/BUILD.bazel
generated
vendored
Normal file
20
vendor/github.com/google/cel-go/common/types/ref/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"provider.go",
|
||||
"reference.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/types/ref",
|
||||
deps = [
|
||||
"@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",
|
||||
],
|
||||
)
|
||||
103
vendor/github.com/google/cel-go/common/types/ref/provider.go
generated
vendored
Normal file
103
vendor/github.com/google/cel-go/common/types/ref/provider.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2018 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 ref
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// TypeProvider specifies functions for creating new object instances and for
|
||||
// resolving enum values by name.
|
||||
type TypeProvider interface {
|
||||
// EnumValue returns the numeric value of the given enum value name.
|
||||
EnumValue(enumName string) Val
|
||||
|
||||
// FindIdent takes a qualified identifier name and returns a Value if one
|
||||
// exists.
|
||||
FindIdent(identName string) (Val, bool)
|
||||
|
||||
// FindType looks up the Type given a qualified typeName. Returns false
|
||||
// if not found.
|
||||
//
|
||||
// Used during type-checking only.
|
||||
FindType(typeName string) (*exprpb.Type, bool)
|
||||
|
||||
// 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
|
||||
// name to value.
|
||||
//
|
||||
// Note, for each value, the Val.ConvertToNative function will be invoked
|
||||
// to convert the Val to the field's native type. If an error occurs during
|
||||
// conversion, the NewValue will be a types.Err.
|
||||
NewValue(typeName string, fields map[string]Val) Val
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// TypeRegistry allows third-parties to add custom types to CEL. Not all `TypeProvider`
|
||||
// implementations support type-customization, so these features are optional. However, a
|
||||
// `TypeRegistry` should be a `TypeProvider` and a `TypeAdapter` to ensure that types
|
||||
// which are registered can be converted to CEL representations.
|
||||
type TypeRegistry interface {
|
||||
TypeAdapter
|
||||
TypeProvider
|
||||
|
||||
// RegisterDescriptor registers the contents of a protocol buffer `FileDescriptor`.
|
||||
RegisterDescriptor(fileDesc protoreflect.FileDescriptor) error
|
||||
|
||||
// RegisterMessage registers a protocol buffer message and its dependencies.
|
||||
RegisterMessage(message proto.Message) error
|
||||
|
||||
// RegisterType registers a type value with the provider which ensures the
|
||||
// provider is aware of how to map the type to an identifier.
|
||||
//
|
||||
// If a type is provided more than once with an alternative definition, the
|
||||
// call will result in an error.
|
||||
RegisterType(types ...Type) error
|
||||
|
||||
// Copy the TypeRegistry and return a new registry whose mutable state is isolated.
|
||||
Copy() TypeRegistry
|
||||
}
|
||||
|
||||
// FieldType represents a field's type value and whether that field supports
|
||||
// presence detection.
|
||||
type FieldType struct {
|
||||
// Type of the field.
|
||||
Type *exprpb.Type
|
||||
|
||||
// IsSet indicates whether the field is set on an input object.
|
||||
IsSet FieldTester
|
||||
|
||||
// GetFrom retrieves the field value on the input object, if set.
|
||||
GetFrom FieldGetter
|
||||
}
|
||||
|
||||
// FieldTester is used to test field presence on an input object.
|
||||
type FieldTester func(target interface{}) bool
|
||||
|
||||
// FieldGetter is used to get the field value from an input object, if set.
|
||||
type FieldGetter func(target interface{}) (interface{}, error)
|
||||
59
vendor/github.com/google/cel-go/common/types/ref/reference.go
generated
vendored
Normal file
59
vendor/github.com/google/cel-go/common/types/ref/reference.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2018 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 ref contains the reference interfaces used throughout the types
|
||||
// components.
|
||||
package ref
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Type interface indicate the name of a given type.
|
||||
type Type interface {
|
||||
// HasTrait returns whether the type has a given trait associated with it.
|
||||
//
|
||||
// See common/types/traits/traits.go for a list of supported traits.
|
||||
HasTrait(trait int) bool
|
||||
|
||||
// TypeName returns the qualified type name of the type.
|
||||
//
|
||||
// The type name is also used as the type's identifier name at type-check
|
||||
// and interpretation time.
|
||||
TypeName() string
|
||||
}
|
||||
|
||||
// Val interface defines the functions supported by all expression values.
|
||||
// Val implementations may specialize the behavior of the value through the
|
||||
// addition of traits.
|
||||
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)
|
||||
|
||||
// ConvertToType supports type conversions between 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.
|
||||
Equal(other Val) Val
|
||||
|
||||
// Type returns the TypeValue of the value.
|
||||
Type() Type
|
||||
|
||||
// Value returns the raw value of the instance which may not be directly
|
||||
// compatible with the expression language types.
|
||||
Value() interface{}
|
||||
}
|
||||
221
vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
Normal file
221
vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
// String type implementation which supports addition, comparison, matching,
|
||||
// and size functions.
|
||||
type String string
|
||||
|
||||
var (
|
||||
// StringType singleton.
|
||||
StringType = NewTypeValue("string",
|
||||
traits.AdderType,
|
||||
traits.ComparerType,
|
||||
traits.MatcherType,
|
||||
traits.ReceiverType,
|
||||
traits.SizerType)
|
||||
|
||||
stringOneArgOverloads = map[string]func(String, ref.Val) ref.Val{
|
||||
overloads.Contains: stringContains,
|
||||
overloads.EndsWith: stringEndsWith,
|
||||
overloads.StartsWith: stringStartsWith,
|
||||
}
|
||||
|
||||
stringWrapperType = reflect.TypeOf(&wrapperspb.StringValue{})
|
||||
)
|
||||
|
||||
// Add implements traits.Adder.Add.
|
||||
func (s String) Add(other ref.Val) ref.Val {
|
||||
otherString, ok := other.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return s + otherString
|
||||
}
|
||||
|
||||
// Compare implements traits.Comparer.Compare.
|
||||
func (s String) Compare(other ref.Val) ref.Val {
|
||||
otherString, ok := other.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return Int(strings.Compare(s.Value().(string), otherString.Value().(string)))
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (s String) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.String:
|
||||
if reflect.TypeOf(s).AssignableTo(typeDesc) {
|
||||
return s, nil
|
||||
}
|
||||
return s.Value(), nil
|
||||
case reflect.Ptr:
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
// Primitives must be wrapped before being set on an Any field.
|
||||
return anypb.New(wrapperspb.String(string(s)))
|
||||
case jsonValueType:
|
||||
// Convert to a protobuf representation of a JSON String.
|
||||
return structpb.NewStringValue(string(s)), nil
|
||||
case stringWrapperType:
|
||||
// Convert to a wrapperspb.StringValue.
|
||||
return wrapperspb.String(string(s)), nil
|
||||
}
|
||||
if typeDesc.Elem().Kind() == reflect.String {
|
||||
p := s.Value().(string)
|
||||
return &p, nil
|
||||
}
|
||||
case reflect.Interface:
|
||||
sv := s.Value()
|
||||
if reflect.TypeOf(sv).Implements(typeDesc) {
|
||||
return sv, nil
|
||||
}
|
||||
if reflect.TypeOf(s).Implements(typeDesc) {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf(
|
||||
"unsupported native conversion from string to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (s String) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case IntType:
|
||||
if n, err := strconv.ParseInt(s.Value().(string), 10, 64); err == nil {
|
||||
return Int(n)
|
||||
}
|
||||
case UintType:
|
||||
if n, err := strconv.ParseUint(s.Value().(string), 10, 64); err == nil {
|
||||
return Uint(n)
|
||||
}
|
||||
case DoubleType:
|
||||
if n, err := strconv.ParseFloat(s.Value().(string), 64); err == nil {
|
||||
return Double(n)
|
||||
}
|
||||
case BoolType:
|
||||
if b, err := strconv.ParseBool(s.Value().(string)); err == nil {
|
||||
return Bool(b)
|
||||
}
|
||||
case BytesType:
|
||||
return Bytes(s)
|
||||
case DurationType:
|
||||
if d, err := time.ParseDuration(s.Value().(string)); err == nil {
|
||||
return durationOf(d)
|
||||
}
|
||||
case TimestampType:
|
||||
if t, err := time.Parse(time.RFC3339, s.Value().(string)); err == nil {
|
||||
if t.Unix() < minUnixTime || t.Unix() > maxUnixTime {
|
||||
return celErrTimestampOverflow
|
||||
}
|
||||
return timestampOf(t)
|
||||
}
|
||||
case StringType:
|
||||
return s
|
||||
case TypeType:
|
||||
return StringType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", StringType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (s String) Equal(other ref.Val) ref.Val {
|
||||
otherString, ok := other.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return Bool(s == otherString)
|
||||
}
|
||||
|
||||
// Match implements traits.Matcher.Match.
|
||||
func (s String) Match(pattern ref.Val) ref.Val {
|
||||
pat, ok := pattern.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(pattern)
|
||||
}
|
||||
matched, err := regexp.MatchString(pat.Value().(string), s.Value().(string))
|
||||
if err != nil {
|
||||
return &Err{err}
|
||||
}
|
||||
return Bool(matched)
|
||||
}
|
||||
|
||||
// Receive implements traits.Reciever.Receive.
|
||||
func (s String) Receive(function string, overload string, args []ref.Val) ref.Val {
|
||||
switch len(args) {
|
||||
case 1:
|
||||
if f, found := stringOneArgOverloads[function]; found {
|
||||
return f(s, args[0])
|
||||
}
|
||||
}
|
||||
return NoSuchOverloadErr()
|
||||
}
|
||||
|
||||
// Size implements traits.Sizer.Size.
|
||||
func (s String) Size() ref.Val {
|
||||
return Int(len([]rune(s.Value().(string))))
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (s String) Type() ref.Type {
|
||||
return StringType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (s String) Value() interface{} {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func stringContains(s String, sub ref.Val) ref.Val {
|
||||
subStr, ok := sub.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(sub)
|
||||
}
|
||||
return Bool(strings.Contains(string(s), string(subStr)))
|
||||
}
|
||||
|
||||
func stringEndsWith(s String, suf ref.Val) ref.Val {
|
||||
sufStr, ok := suf.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(suf)
|
||||
}
|
||||
return Bool(strings.HasSuffix(string(s), string(sufStr)))
|
||||
}
|
||||
|
||||
func stringStartsWith(s String, pre ref.Val) ref.Val {
|
||||
preStr, ok := pre.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(pre)
|
||||
}
|
||||
return Bool(strings.HasPrefix(string(s), string(preStr)))
|
||||
}
|
||||
318
vendor/github.com/google/cel-go/common/types/timestamp.go
generated
vendored
Normal file
318
vendor/github.com/google/cel-go/common/types/timestamp.go
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
tpb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// Timestamp type implementation which supports add, compare, and subtract
|
||||
// operations. Timestamps are also capable of participating in dynamic
|
||||
// function dispatch to instance methods.
|
||||
type Timestamp struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
func timestampOf(t time.Time) Timestamp {
|
||||
// Note that this function does not validate that time.Time is in our supported range.
|
||||
return Timestamp{Time: t}
|
||||
}
|
||||
|
||||
const (
|
||||
// The number of seconds between year 1 and year 1970. This is borrowed from
|
||||
// https://golang.org/src/time/time.go.
|
||||
unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * (60 * 60 * 24)
|
||||
|
||||
// Number of seconds between `0001-01-01T00:00:00Z` and the Unix epoch.
|
||||
minUnixTime int64 = -62135596800
|
||||
// Number of seconds between `9999-12-31T23:59:59.999999999Z` and the Unix epoch.
|
||||
maxUnixTime int64 = 253402300799
|
||||
)
|
||||
|
||||
var (
|
||||
// TimestampType singleton.
|
||||
TimestampType = NewTypeValue("google.protobuf.Timestamp",
|
||||
traits.AdderType,
|
||||
traits.ComparerType,
|
||||
traits.ReceiverType,
|
||||
traits.SubtractorType)
|
||||
)
|
||||
|
||||
// Add implements traits.Adder.Add.
|
||||
func (t Timestamp) Add(other ref.Val) ref.Val {
|
||||
switch other.Type() {
|
||||
case DurationType:
|
||||
return other.(Duration).Add(t)
|
||||
}
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
|
||||
// Compare implements traits.Comparer.Compare.
|
||||
func (t Timestamp) Compare(other ref.Val) ref.Val {
|
||||
if TimestampType != other.Type() {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
ts1 := t.Time
|
||||
ts2 := other.(Timestamp).Time
|
||||
switch {
|
||||
case ts1.Before(ts2):
|
||||
return IntNegOne
|
||||
case ts1.After(ts2):
|
||||
return IntOne
|
||||
default:
|
||||
return IntZero
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (t Timestamp) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
// If the timestamp is already assignable to the desired type return it.
|
||||
if reflect.TypeOf(t.Time).AssignableTo(typeDesc) {
|
||||
return t.Time, nil
|
||||
}
|
||||
if reflect.TypeOf(t).AssignableTo(typeDesc) {
|
||||
return t, nil
|
||||
}
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
// Pack the underlying time as a tpb.Timestamp into an Any value.
|
||||
return anypb.New(tpb.New(t.Time))
|
||||
case jsonValueType:
|
||||
// CEL follows the proto3 to JSON conversion which formats as an RFC 3339 encoded JSON
|
||||
// string.
|
||||
v := t.ConvertToType(StringType)
|
||||
if IsError(v) {
|
||||
return nil, v.(*Err)
|
||||
}
|
||||
return structpb.NewStringValue(string(v.(String))), nil
|
||||
case timestampValueType:
|
||||
// Unwrap the underlying tpb.Timestamp.
|
||||
return tpb.New(t.Time), nil
|
||||
}
|
||||
return nil, fmt.Errorf("type conversion error from 'Timestamp' to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (t Timestamp) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case StringType:
|
||||
return String(t.Format(time.RFC3339Nano))
|
||||
case IntType:
|
||||
// Return the Unix time in seconds since 1970
|
||||
return Int(t.Unix())
|
||||
case TimestampType:
|
||||
return t
|
||||
case TypeType:
|
||||
return TimestampType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", TimestampType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (t Timestamp) Equal(other ref.Val) ref.Val {
|
||||
if TimestampType != other.Type() {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return Bool(t.Time.Equal(other.(Timestamp).Time))
|
||||
}
|
||||
|
||||
// Receive implements traits.Reciever.Receive.
|
||||
func (t Timestamp) Receive(function string, overload string, args []ref.Val) ref.Val {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
if f, found := timestampZeroArgOverloads[function]; found {
|
||||
return f(t.Time)
|
||||
}
|
||||
case 1:
|
||||
if f, found := timestampOneArgOverloads[function]; found {
|
||||
return f(t.Time, args[0])
|
||||
}
|
||||
}
|
||||
return NoSuchOverloadErr()
|
||||
}
|
||||
|
||||
// Subtract implements traits.Subtractor.Subtract.
|
||||
func (t Timestamp) Subtract(subtrahend ref.Val) ref.Val {
|
||||
switch subtrahend.Type() {
|
||||
case DurationType:
|
||||
dur := subtrahend.(Duration)
|
||||
val, err := subtractTimeDurationChecked(t.Time, dur.Duration)
|
||||
if err != nil {
|
||||
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 durationOf(val)
|
||||
}
|
||||
return MaybeNoSuchOverloadErr(subtrahend)
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (t Timestamp) Type() ref.Type {
|
||||
return TimestampType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (t Timestamp) Value() interface{} {
|
||||
return t.Time
|
||||
}
|
||||
|
||||
var (
|
||||
timestampValueType = reflect.TypeOf(&tpb.Timestamp{})
|
||||
|
||||
timestampZeroArgOverloads = map[string]func(time.Time) ref.Val{
|
||||
overloads.TimeGetFullYear: timestampGetFullYear,
|
||||
overloads.TimeGetMonth: timestampGetMonth,
|
||||
overloads.TimeGetDayOfYear: timestampGetDayOfYear,
|
||||
overloads.TimeGetDate: timestampGetDayOfMonthOneBased,
|
||||
overloads.TimeGetDayOfMonth: timestampGetDayOfMonthZeroBased,
|
||||
overloads.TimeGetDayOfWeek: timestampGetDayOfWeek,
|
||||
overloads.TimeGetHours: timestampGetHours,
|
||||
overloads.TimeGetMinutes: timestampGetMinutes,
|
||||
overloads.TimeGetSeconds: timestampGetSeconds,
|
||||
overloads.TimeGetMilliseconds: timestampGetMilliseconds}
|
||||
|
||||
timestampOneArgOverloads = map[string]func(time.Time, ref.Val) ref.Val{
|
||||
overloads.TimeGetFullYear: timestampGetFullYearWithTz,
|
||||
overloads.TimeGetMonth: timestampGetMonthWithTz,
|
||||
overloads.TimeGetDayOfYear: timestampGetDayOfYearWithTz,
|
||||
overloads.TimeGetDate: timestampGetDayOfMonthOneBasedWithTz,
|
||||
overloads.TimeGetDayOfMonth: timestampGetDayOfMonthZeroBasedWithTz,
|
||||
overloads.TimeGetDayOfWeek: timestampGetDayOfWeekWithTz,
|
||||
overloads.TimeGetHours: timestampGetHoursWithTz,
|
||||
overloads.TimeGetMinutes: timestampGetMinutesWithTz,
|
||||
overloads.TimeGetSeconds: timestampGetSecondsWithTz,
|
||||
overloads.TimeGetMilliseconds: timestampGetMillisecondsWithTz}
|
||||
)
|
||||
|
||||
type timestampVisitor func(time.Time) ref.Val
|
||||
|
||||
func timestampGetFullYear(t time.Time) ref.Val {
|
||||
return Int(t.Year())
|
||||
}
|
||||
func timestampGetMonth(t time.Time) ref.Val {
|
||||
// CEL spec indicates that the month should be 0-based, but the Time value
|
||||
// for Month() is 1-based.
|
||||
return Int(t.Month() - 1)
|
||||
}
|
||||
func timestampGetDayOfYear(t time.Time) ref.Val {
|
||||
return Int(t.YearDay() - 1)
|
||||
}
|
||||
func timestampGetDayOfMonthZeroBased(t time.Time) ref.Val {
|
||||
return Int(t.Day() - 1)
|
||||
}
|
||||
func timestampGetDayOfMonthOneBased(t time.Time) ref.Val {
|
||||
return Int(t.Day())
|
||||
}
|
||||
func timestampGetDayOfWeek(t time.Time) ref.Val {
|
||||
return Int(t.Weekday())
|
||||
}
|
||||
func timestampGetHours(t time.Time) ref.Val {
|
||||
return Int(t.Hour())
|
||||
}
|
||||
func timestampGetMinutes(t time.Time) ref.Val {
|
||||
return Int(t.Minute())
|
||||
}
|
||||
func timestampGetSeconds(t time.Time) ref.Val {
|
||||
return Int(t.Second())
|
||||
}
|
||||
func timestampGetMilliseconds(t time.Time) ref.Val {
|
||||
return Int(t.Nanosecond() / 1000000)
|
||||
}
|
||||
|
||||
func timestampGetFullYearWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetFullYear)(t)
|
||||
}
|
||||
func timestampGetMonthWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetMonth)(t)
|
||||
}
|
||||
func timestampGetDayOfYearWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetDayOfYear)(t)
|
||||
}
|
||||
func timestampGetDayOfMonthZeroBasedWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetDayOfMonthZeroBased)(t)
|
||||
}
|
||||
func timestampGetDayOfMonthOneBasedWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetDayOfMonthOneBased)(t)
|
||||
}
|
||||
func timestampGetDayOfWeekWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetDayOfWeek)(t)
|
||||
}
|
||||
func timestampGetHoursWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetHours)(t)
|
||||
}
|
||||
func timestampGetMinutesWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetMinutes)(t)
|
||||
}
|
||||
func timestampGetSecondsWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetSeconds)(t)
|
||||
}
|
||||
func timestampGetMillisecondsWithTz(t time.Time, tz ref.Val) ref.Val {
|
||||
return timeZone(tz, timestampGetMilliseconds)(t)
|
||||
}
|
||||
|
||||
func timeZone(tz ref.Val, visitor timestampVisitor) timestampVisitor {
|
||||
return func(t time.Time) ref.Val {
|
||||
if StringType != tz.Type() {
|
||||
return MaybeNoSuchOverloadErr(tz)
|
||||
}
|
||||
val := string(tz.(String))
|
||||
ind := strings.Index(val, ":")
|
||||
if ind == -1 {
|
||||
loc, err := time.LoadLocation(val)
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return visitor(t.In(loc))
|
||||
}
|
||||
|
||||
// If the input is not the name of a timezone (for example, 'US/Central'), it should be a numerical offset from UTC
|
||||
// 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)
|
||||
}
|
||||
min, err := strconv.Atoi(string(val[ind+1]))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
var offset int
|
||||
if string(val[0]) == "-" {
|
||||
offset = hr*60 - min
|
||||
} else {
|
||||
offset = hr*60 + min
|
||||
}
|
||||
secondsEastOfUTC := int((time.Duration(offset) * time.Minute).Seconds())
|
||||
timezone := time.FixedZone("", secondsEastOfUTC)
|
||||
return visitor(t.In(timezone))
|
||||
}
|
||||
}
|
||||
28
vendor/github.com/google/cel-go/common/types/traits/BUILD.bazel
generated
vendored
Normal file
28
vendor/github.com/google/cel-go/common/types/traits/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"comparer.go",
|
||||
"container.go",
|
||||
"field_tester.go",
|
||||
"indexer.go",
|
||||
"iterator.go",
|
||||
"lister.go",
|
||||
"mapper.go",
|
||||
"matcher.go",
|
||||
"math.go",
|
||||
"receiver.go",
|
||||
"sizer.go",
|
||||
"traits.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/types/traits",
|
||||
deps = [
|
||||
"//common/types/ref:go_default_library",
|
||||
],
|
||||
)
|
||||
33
vendor/github.com/google/cel-go/common/types/traits/comparer.go
generated
vendored
Normal file
33
vendor/github.com/google/cel-go/common/types/traits/comparer.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// Comparer interface for ordering comparisons between values in order to
|
||||
// support '<', '<=', '>=', '>' overloads.
|
||||
type Comparer interface {
|
||||
// Compare this value to the input other value, returning an Int:
|
||||
//
|
||||
// this < other -> Int(-1)
|
||||
// this == other -> Int(0)
|
||||
// this > other -> Int(1)
|
||||
//
|
||||
// If the comparison cannot be made or is not supported, an error should
|
||||
// be returned.
|
||||
Compare(other ref.Val) ref.Val
|
||||
}
|
||||
23
vendor/github.com/google/cel-go/common/types/traits/container.go
generated
vendored
Normal file
23
vendor/github.com/google/cel-go/common/types/traits/container.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import "github.com/google/cel-go/common/types/ref"
|
||||
|
||||
// Container interface which permits containment tests such as 'a in b'.
|
||||
type Container interface {
|
||||
// Contains returns true if the value exists within the object.
|
||||
Contains(value ref.Val) ref.Val
|
||||
}
|
||||
30
vendor/github.com/google/cel-go/common/types/traits/field_tester.go
generated
vendored
Normal file
30
vendor/github.com/google/cel-go/common/types/traits/field_tester.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// FieldTester indicates if a defined field on an object type is set to a
|
||||
// non-default value.
|
||||
//
|
||||
// For use with the `has()` macro.
|
||||
type FieldTester interface {
|
||||
// IsSet returns true if the field is defined and set to a non-default
|
||||
// value. The method will return false if defined and not set, and an error
|
||||
// if the field is not defined.
|
||||
IsSet(field ref.Val) ref.Val
|
||||
}
|
||||
25
vendor/github.com/google/cel-go/common/types/traits/indexer.go
generated
vendored
Normal file
25
vendor/github.com/google/cel-go/common/types/traits/indexer.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// Indexer permits random access of elements by index 'a[b()]'.
|
||||
type Indexer interface {
|
||||
// Get the value at the specified index or error.
|
||||
Get(index ref.Val) ref.Val
|
||||
}
|
||||
36
vendor/github.com/google/cel-go/common/types/traits/iterator.go
generated
vendored
Normal file
36
vendor/github.com/google/cel-go/common/types/traits/iterator.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// Iterable aggregate types permit traversal over their elements.
|
||||
type Iterable interface {
|
||||
// Iterator returns a new iterator view of the struct.
|
||||
Iterator() Iterator
|
||||
}
|
||||
|
||||
// Iterator permits safe traversal over the contents of an aggregate type.
|
||||
type Iterator interface {
|
||||
ref.Val
|
||||
|
||||
// HasNext returns true if there are unvisited elements in the Iterator.
|
||||
HasNext() ref.Val
|
||||
|
||||
// Next returns the next element.
|
||||
Next() ref.Val
|
||||
}
|
||||
27
vendor/github.com/google/cel-go/common/types/traits/lister.go
generated
vendored
Normal file
27
vendor/github.com/google/cel-go/common/types/traits/lister.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import "github.com/google/cel-go/common/types/ref"
|
||||
|
||||
// Lister interface which aggregates the traits of a list.
|
||||
type Lister interface {
|
||||
ref.Val
|
||||
Adder
|
||||
Container
|
||||
Indexer
|
||||
Iterable
|
||||
Sizer
|
||||
}
|
||||
33
vendor/github.com/google/cel-go/common/types/traits/mapper.go
generated
vendored
Normal file
33
vendor/github.com/google/cel-go/common/types/traits/mapper.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import "github.com/google/cel-go/common/types/ref"
|
||||
|
||||
// Mapper interface which aggregates the traits of a maps.
|
||||
type Mapper interface {
|
||||
ref.Val
|
||||
Container
|
||||
Indexer
|
||||
Iterable
|
||||
Sizer
|
||||
|
||||
// Find returns a value, if one exists, for the input key.
|
||||
//
|
||||
// If the key is not found the function returns (nil, false).
|
||||
// If the input key is not valid for the map, or is Err or Unknown the function returns
|
||||
// (Unknown|Err, false).
|
||||
Find(key ref.Val) (ref.Val, bool)
|
||||
}
|
||||
23
vendor/github.com/google/cel-go/common/types/traits/matcher.go
generated
vendored
Normal file
23
vendor/github.com/google/cel-go/common/types/traits/matcher.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import "github.com/google/cel-go/common/types/ref"
|
||||
|
||||
// Matcher interface for supporting 'matches()' overloads.
|
||||
type Matcher interface {
|
||||
// Match returns true if the pattern matches the current value.
|
||||
Match(pattern ref.Val) ref.Val
|
||||
}
|
||||
62
vendor/github.com/google/cel-go/common/types/traits/math.go
generated
vendored
Normal file
62
vendor/github.com/google/cel-go/common/types/traits/math.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import "github.com/google/cel-go/common/types/ref"
|
||||
|
||||
// Adder interface to support '+' operator overloads.
|
||||
type Adder interface {
|
||||
// Add returns a combination of the current value and other value.
|
||||
//
|
||||
// If the other value is an unsupported type, an error is returned.
|
||||
Add(other ref.Val) ref.Val
|
||||
}
|
||||
|
||||
// Divider interface to support '/' operator overloads.
|
||||
type Divider interface {
|
||||
// Divide returns the result of dividing the current value by the input
|
||||
// denominator.
|
||||
//
|
||||
// A denominator value of zero results in an error.
|
||||
Divide(denominator ref.Val) ref.Val
|
||||
}
|
||||
|
||||
// Modder interface to support '%' operator overloads.
|
||||
type Modder interface {
|
||||
// Modulo returns the result of taking the modulus of the current value
|
||||
// by the denominator.
|
||||
//
|
||||
// A denominator value of zero results in an error.
|
||||
Modulo(denominator ref.Val) ref.Val
|
||||
}
|
||||
|
||||
// Multiplier interface to support '*' operator overloads.
|
||||
type Multiplier interface {
|
||||
// Multiply returns the result of multiplying the current and input value.
|
||||
Multiply(other ref.Val) ref.Val
|
||||
}
|
||||
|
||||
// Negater interface to support unary '-' and '!' operator overloads.
|
||||
type Negater interface {
|
||||
// Negate returns the complement of the current value.
|
||||
Negate() ref.Val
|
||||
}
|
||||
|
||||
// Subtractor interface to support binary '-' operator overloads.
|
||||
type Subtractor interface {
|
||||
// Subtract returns the result of subtracting the input from the current
|
||||
// value.
|
||||
Subtract(subtrahend ref.Val) ref.Val
|
||||
}
|
||||
24
vendor/github.com/google/cel-go/common/types/traits/receiver.go
generated
vendored
Normal file
24
vendor/github.com/google/cel-go/common/types/traits/receiver.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import "github.com/google/cel-go/common/types/ref"
|
||||
|
||||
// Receiver interface for routing instance method calls within a value.
|
||||
type Receiver interface {
|
||||
// Receive accepts a function name, overload id, and arguments and returns
|
||||
// a value.
|
||||
Receive(function string, overload string, args []ref.Val) ref.Val
|
||||
}
|
||||
25
vendor/github.com/google/cel-go/common/types/traits/sizer.go
generated
vendored
Normal file
25
vendor/github.com/google/cel-go/common/types/traits/sizer.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2018 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 traits
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// Sizer interface for supporting 'size()' overloads.
|
||||
type Sizer interface {
|
||||
// Size returns the number of elements or length of the value.
|
||||
Size() ref.Val
|
||||
}
|
||||
64
vendor/github.com/google/cel-go/common/types/traits/traits.go
generated
vendored
Normal file
64
vendor/github.com/google/cel-go/common/types/traits/traits.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2018 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 traits defines interfaces that a type may implement to participate
|
||||
// in operator overloads and function dispatch.
|
||||
package traits
|
||||
|
||||
const (
|
||||
// AdderType types provide a '+' operator overload.
|
||||
AdderType = 1 << iota
|
||||
|
||||
// ComparerType types support ordering comparisons '<', '<=', '>', '>='.
|
||||
ComparerType
|
||||
|
||||
// ContainerType types support 'in' operations.
|
||||
ContainerType
|
||||
|
||||
// DividerType types support '/' operations.
|
||||
DividerType
|
||||
|
||||
// FieldTesterType types support the detection of field value presence.
|
||||
FieldTesterType
|
||||
|
||||
// IndexerType types support index access with dynamic values.
|
||||
IndexerType
|
||||
|
||||
// IterableType types can be iterated over in comprehensions.
|
||||
IterableType
|
||||
|
||||
// IteratorType types support iterator semantics.
|
||||
IteratorType
|
||||
|
||||
// MatcherType types support pattern matching via 'matches' method.
|
||||
MatcherType
|
||||
|
||||
// ModderType types support modulus operations '%'
|
||||
ModderType
|
||||
|
||||
// MultiplierType types support '*' operations.
|
||||
MultiplierType
|
||||
|
||||
// NegatorType types support either negation via '!' or '-'
|
||||
NegatorType
|
||||
|
||||
// ReceiverType types support dynamic dispatch to instance methods.
|
||||
ReceiverType
|
||||
|
||||
// SizerType types support the size() method.
|
||||
SizerType
|
||||
|
||||
// SubtractorType type support '-' operations.
|
||||
SubtractorType
|
||||
)
|
||||
104
vendor/github.com/google/cel-go/common/types/type.go
generated
vendored
Normal file
104
vendor/github.com/google/cel-go/common/types/type.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
)
|
||||
|
||||
var (
|
||||
// TypeType is the type of a TypeValue.
|
||||
TypeType = NewTypeValue("type")
|
||||
)
|
||||
|
||||
// TypeValue is an instance of a Value that describes a value's type.
|
||||
type TypeValue struct {
|
||||
name string
|
||||
traitMask int
|
||||
}
|
||||
|
||||
// NewTypeValue returns *TypeValue which is both a ref.Type and ref.Val.
|
||||
func NewTypeValue(name string, traits ...int) *TypeValue {
|
||||
traitMask := 0
|
||||
for _, trait := range traits {
|
||||
traitMask |= trait
|
||||
}
|
||||
return &TypeValue{
|
||||
name: name,
|
||||
traitMask: traitMask}
|
||||
}
|
||||
|
||||
// NewObjectTypeValue returns a *TypeValue based on the input name, which is
|
||||
// annotated with the traits relevant to all objects.
|
||||
func NewObjectTypeValue(name string) *TypeValue {
|
||||
return NewTypeValue(name,
|
||||
traits.FieldTesterType,
|
||||
traits.IndexerType)
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (t *TypeValue) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
// TODO: replace the internal type representation with a proto-value.
|
||||
return nil, fmt.Errorf("type conversion not supported for 'type'")
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (t *TypeValue) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case TypeType:
|
||||
return TypeType
|
||||
case StringType:
|
||||
return String(t.TypeName())
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", TypeType, typeVal)
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (t *TypeValue) Equal(other ref.Val) ref.Val {
|
||||
if TypeType != other.Type() {
|
||||
return ValOrErr(other, "no such overload")
|
||||
}
|
||||
return Bool(t.TypeName() == other.(ref.Type).TypeName())
|
||||
}
|
||||
|
||||
// HasTrait indicates whether the type supports the given trait.
|
||||
// Trait codes are defined in the traits package, e.g. see traits.AdderType.
|
||||
func (t *TypeValue) HasTrait(trait int) bool {
|
||||
return trait&t.traitMask == trait
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (t *TypeValue) String() string {
|
||||
return t.name
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (t *TypeValue) Type() ref.Type {
|
||||
return TypeType
|
||||
}
|
||||
|
||||
// TypeName gives the type's name as a string.
|
||||
func (t *TypeValue) TypeName() string {
|
||||
return t.name
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (t *TypeValue) Value() interface{} {
|
||||
return t.name
|
||||
}
|
||||
238
vendor/github.com/google/cel-go/common/types/uint.go
generated
vendored
Normal file
238
vendor/github.com/google/cel-go/common/types/uint.go
generated
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
// Uint type implementation which supports comparison and math operators.
|
||||
type Uint uint64
|
||||
|
||||
var (
|
||||
// UintType singleton.
|
||||
UintType = NewTypeValue("uint",
|
||||
traits.AdderType,
|
||||
traits.ComparerType,
|
||||
traits.DividerType,
|
||||
traits.ModderType,
|
||||
traits.MultiplierType,
|
||||
traits.SubtractorType)
|
||||
|
||||
uint32WrapperType = reflect.TypeOf(&wrapperspb.UInt32Value{})
|
||||
|
||||
uint64WrapperType = reflect.TypeOf(&wrapperspb.UInt64Value{})
|
||||
)
|
||||
|
||||
// Uint constants
|
||||
const (
|
||||
uintZero = Uint(0)
|
||||
)
|
||||
|
||||
// Add implements traits.Adder.Add.
|
||||
func (i Uint) Add(other ref.Val) ref.Val {
|
||||
otherUint, ok := other.(Uint)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
val, err := addUint64Checked(uint64(i), uint64(otherUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Uint(val)
|
||||
}
|
||||
|
||||
// Compare implements traits.Comparer.Compare.
|
||||
func (i Uint) Compare(other ref.Val) ref.Val {
|
||||
otherUint, ok := other.(Uint)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
if i < otherUint {
|
||||
return IntNegOne
|
||||
}
|
||||
if i > otherUint {
|
||||
return IntOne
|
||||
}
|
||||
return IntZero
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (i Uint) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Uint, reflect.Uint32:
|
||||
v, err := uint64ToUint32Checked(uint64(i))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Uint64:
|
||||
return reflect.ValueOf(i).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Ptr:
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
// Primitives must be wrapped before being set on an Any field.
|
||||
return anypb.New(wrapperspb.UInt64(uint64(i)))
|
||||
case jsonValueType:
|
||||
// JSON can accurately represent 32-bit uints as floating point values.
|
||||
if i.isJSONSafe() {
|
||||
return structpb.NewNumberValue(float64(i)), nil
|
||||
}
|
||||
// Proto3 to JSON conversion requires string-formatted uint64 values
|
||||
// since the conversion to floating point would result in truncation.
|
||||
return structpb.NewStringValue(strconv.FormatUint(uint64(i), 10)), nil
|
||||
case uint32WrapperType:
|
||||
// Convert the value to a wrapperspb.UInt32Value, error on overflow.
|
||||
v, err := uint64ToUint32Checked(uint64(i))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return wrapperspb.UInt32(v), nil
|
||||
case uint64WrapperType:
|
||||
// Convert the value to a wrapperspb.UInt64Value.
|
||||
return wrapperspb.UInt64(uint64(i)), nil
|
||||
}
|
||||
switch typeDesc.Elem().Kind() {
|
||||
case reflect.Uint32:
|
||||
v, err := uint64ToUint32Checked(uint64(i))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
p := reflect.New(typeDesc.Elem())
|
||||
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
|
||||
return p.Interface(), nil
|
||||
case reflect.Uint64:
|
||||
v := uint64(i)
|
||||
p := reflect.New(typeDesc.Elem())
|
||||
p.Elem().Set(reflect.ValueOf(v).Convert(typeDesc.Elem()))
|
||||
return p.Interface(), nil
|
||||
}
|
||||
case reflect.Interface:
|
||||
iv := i.Value()
|
||||
if reflect.TypeOf(iv).Implements(typeDesc) {
|
||||
return iv, nil
|
||||
}
|
||||
if reflect.TypeOf(i).Implements(typeDesc) {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported type conversion from 'uint' to %v", typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (i Uint) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case IntType:
|
||||
v, err := uint64ToInt64Checked(uint64(i))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Int(v)
|
||||
case UintType:
|
||||
return i
|
||||
case DoubleType:
|
||||
return Double(i)
|
||||
case StringType:
|
||||
return String(fmt.Sprintf("%d", uint64(i)))
|
||||
case TypeType:
|
||||
return UintType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", UintType, typeVal)
|
||||
}
|
||||
|
||||
// Divide implements traits.Divider.Divide.
|
||||
func (i Uint) Divide(other ref.Val) ref.Val {
|
||||
otherUint, ok := other.(Uint)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
div, err := divideUint64Checked(uint64(i), uint64(otherUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Uint(div)
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (i Uint) Equal(other ref.Val) ref.Val {
|
||||
otherUint, ok := other.(Uint)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return Bool(i == otherUint)
|
||||
}
|
||||
|
||||
// Modulo implements traits.Modder.Modulo.
|
||||
func (i Uint) Modulo(other ref.Val) ref.Val {
|
||||
otherUint, ok := other.(Uint)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
mod, err := moduloUint64Checked(uint64(i), uint64(otherUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Uint(mod)
|
||||
}
|
||||
|
||||
// Multiply implements traits.Multiplier.Multiply.
|
||||
func (i Uint) Multiply(other ref.Val) ref.Val {
|
||||
otherUint, ok := other.(Uint)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
val, err := multiplyUint64Checked(uint64(i), uint64(otherUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Uint(val)
|
||||
}
|
||||
|
||||
// Subtract implements traits.Subtractor.Subtract.
|
||||
func (i Uint) Subtract(subtrahend ref.Val) ref.Val {
|
||||
subtraUint, ok := subtrahend.(Uint)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(subtrahend)
|
||||
}
|
||||
val, err := subtractUint64Checked(uint64(i), uint64(subtraUint))
|
||||
if err != nil {
|
||||
return wrapErr(err)
|
||||
}
|
||||
return Uint(val)
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (i Uint) Type() ref.Type {
|
||||
return UintType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (i Uint) Value() interface{} {
|
||||
return uint64(i)
|
||||
}
|
||||
|
||||
// isJSONSafe indicates whether the uint is safely representable as a floating point value in JSON.
|
||||
func (i Uint) isJSONSafe() bool {
|
||||
return i <= maxIntJSON
|
||||
}
|
||||
61
vendor/github.com/google/cel-go/common/types/unknown.go
generated
vendored
Normal file
61
vendor/github.com/google/cel-go/common/types/unknown.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2018 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 (
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// Unknown type implementation which collects expression ids which caused the
|
||||
// current value to become unknown.
|
||||
type Unknown []int64
|
||||
|
||||
var (
|
||||
// UnknownType singleton.
|
||||
UnknownType = NewTypeValue("unknown")
|
||||
)
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (u Unknown) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
return u.Value(), nil
|
||||
}
|
||||
|
||||
// ConvertToType implements ref.Val.ConvertToType.
|
||||
func (u Unknown) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
return u
|
||||
}
|
||||
|
||||
// Equal implements ref.Val.Equal.
|
||||
func (u Unknown) Equal(other ref.Val) ref.Val {
|
||||
return u
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (u Unknown) Type() ref.Type {
|
||||
return UnknownType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (u Unknown) Value() interface{} {
|
||||
return []int64(u)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
38
vendor/github.com/google/cel-go/common/types/util.go
generated
vendored
Normal file
38
vendor/github.com/google/cel-go/common/types/util.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2018 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 (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// IsUnknownOrError returns whether the input element ref.Val is an ErrType or UnknonwType.
|
||||
func IsUnknownOrError(val ref.Val) bool {
|
||||
switch val.Type() {
|
||||
case UnknownType, ErrType:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsPrimitiveType returns whether the input element ref.Val is a primitive type.
|
||||
// Note, primitive types do not include well-known types such as Duration and Timestamp.
|
||||
func IsPrimitiveType(val ref.Val) bool {
|
||||
switch val.Type() {
|
||||
case BoolType, BytesType, DoubleType, IntType, StringType, UintType:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
39
vendor/github.com/google/cel-go/ext/BUILD.bazel
generated
vendored
Normal file
39
vendor/github.com/google/cel-go/ext/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"encoders.go",
|
||||
"guards.go",
|
||||
"strings.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/ext",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cel:go_default_library",
|
||||
"//checker/decls:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"//interpreter/functions:go_default_library",
|
||||
"@org_golang_google_genproto//googleapis/api/expr/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"encoders_test.go",
|
||||
"strings_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
deps = [
|
||||
"//cel:go_default_library",
|
||||
],
|
||||
)
|
||||
194
vendor/github.com/google/cel-go/ext/README.md
generated
vendored
Normal file
194
vendor/github.com/google/cel-go/ext/README.md
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
# Extensions
|
||||
|
||||
CEL extensions are a related set of constants, functions, macros, or other
|
||||
features which may not be covered by the core CEL spec.
|
||||
|
||||
## Encoders
|
||||
|
||||
Encoding utilies for marshalling data into standardized representations.
|
||||
|
||||
### 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>
|
||||
|
||||
Examples:
|
||||
|
||||
base64.decode('aGVsbG8=') // return b'hello'
|
||||
base64.decode('aGVsbG8') // error
|
||||
|
||||
### Base64.Encode
|
||||
|
||||
Encodes bytes to a base64-encoded string.
|
||||
|
||||
base64.encode(<bytes>) -> <string>
|
||||
|
||||
Example:
|
||||
|
||||
base64.encode(b'hello') // return 'aGVsbG8='
|
||||
|
||||
## Strings
|
||||
|
||||
Extended functions for string manipulation. As a general note, all indices are
|
||||
zero-based.
|
||||
|
||||
### 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>
|
||||
|
||||
Examples:
|
||||
|
||||
'hello'.charAt(4) // return 'o'
|
||||
'hello'.charAt(5) // return ''
|
||||
'hello'.charAt(-1) // 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.
|
||||
|
||||
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>
|
||||
|
||||
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
|
||||
|
||||
### LastIndexOf
|
||||
|
||||
Returns the integer index of the last occurrence of the search string. If the
|
||||
search string is not found the function returns -1.
|
||||
|
||||
The function also accepts an optional position which represents the last index
|
||||
to be 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>
|
||||
|
||||
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
|
||||
|
||||
### 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>
|
||||
|
||||
Examples:
|
||||
|
||||
'TacoCat'.lowerAscii() // returns 'tacocat'
|
||||
'TacoCÆt Xii'.lowerAscii() // returns 'tacocÆt xii'
|
||||
|
||||
### 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 substring replacements to be made.
|
||||
|
||||
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>
|
||||
|
||||
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'
|
||||
|
||||
### 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.
|
||||
|
||||
When the split limit is 0, the result is an empty list. When the limit is 1,
|
||||
the result is the 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>>
|
||||
|
||||
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']
|
||||
|
||||
### 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 a string.
|
||||
|
||||
Character offsets are 0-based with an inclusive start range and exclusive end
|
||||
range. It is an 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>
|
||||
|
||||
Examples:
|
||||
|
||||
'tacocat'.substring(4) // returns 'cat'
|
||||
'tacocat'.substring(0, 4) // returns 'taco'
|
||||
'tacocat'.substring(-1) // error
|
||||
'tacocat'.substring(2, 1) // error
|
||||
|
||||
### 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>
|
||||
|
||||
Examples:
|
||||
|
||||
' \ttrim\n '.trim() // returns 'trim'
|
||||
|
||||
### 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>
|
||||
|
||||
Examples:
|
||||
|
||||
'TacoCat'.upperAscii() // returns 'TACOCAT'
|
||||
'TacoCÆt Xii'.upperAscii() // returns 'TACOCÆT XII'
|
||||
104
vendor/github.com/google/cel-go/ext/encoders.go
generated
vendored
Normal file
104
vendor/github.com/google/cel-go/ext/encoders.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright 2020 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 (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/interpreter/functions"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Encoders returns a cel.EnvOption to configure extended functions for string, byte, and object
|
||||
// encodings.
|
||||
//
|
||||
// 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>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// base64.decode('aGVsbG8=') // return b'hello'
|
||||
// base64.decode('aGVsbG8') // error
|
||||
//
|
||||
// Base64.Encode
|
||||
//
|
||||
// Encodes bytes to a base64-encoded string.
|
||||
//
|
||||
// base64.encode(<bytes>) -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// base64.encode(b'hello') // return b'aGVsbG8='
|
||||
func Encoders() cel.EnvOption {
|
||||
return cel.Lib(encoderLib{})
|
||||
}
|
||||
|
||||
type encoderLib struct{}
|
||||
|
||||
func (encoderLib) CompileOptions() []cel.EnvOption {
|
||||
return []cel.EnvOption{
|
||||
cel.Declarations(
|
||||
decls.NewFunction("base64.decode",
|
||||
decls.NewOverload("base64_decode_string",
|
||||
[]*exprpb.Type{decls.String},
|
||||
decls.Bytes)),
|
||||
decls.NewFunction("base64.encode",
|
||||
decls.NewOverload("base64_encode_bytes",
|
||||
[]*exprpb.Type{decls.Bytes},
|
||||
decls.String)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (encoderLib) ProgramOptions() []cel.ProgramOption {
|
||||
wrappedBase64EncodeBytes := callInBytesOutString(base64EncodeBytes)
|
||||
wrappedBase64DecodeString := callInStrOutBytes(base64DecodeString)
|
||||
return []cel.ProgramOption{
|
||||
cel.Functions(
|
||||
&functions.Overload{
|
||||
Operator: "base64.decode",
|
||||
Unary: wrappedBase64DecodeString,
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "base64_decode_string",
|
||||
Unary: wrappedBase64DecodeString,
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "base64.encode",
|
||||
Unary: wrappedBase64EncodeBytes,
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "base64_encode_bytes",
|
||||
Unary: wrappedBase64EncodeBytes,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func base64DecodeString(str string) ([]byte, error) {
|
||||
return base64.StdEncoding.DecodeString(str)
|
||||
}
|
||||
|
||||
func base64EncodeBytes(bytes []byte) (string, error) {
|
||||
return base64.StdEncoding.EncodeToString(bytes), nil
|
||||
}
|
||||
248
vendor/github.com/google/cel-go/ext/guards.go
generated
vendored
Normal file
248
vendor/github.com/google/cel-go/ext/guards.go
generated
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
// Copyright 2020 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/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/interpreter/functions"
|
||||
)
|
||||
|
||||
// function invocation guards for common call signatures within extension functions.
|
||||
|
||||
func callInBytesOutString(fn func([]byte) (string, error)) functions.UnaryOp {
|
||||
return func(val ref.Val) ref.Val {
|
||||
vVal, ok := val.(types.Bytes)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
str, err := fn([]byte(vVal))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.String(str)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrOutBytes(fn func(string) ([]byte, error)) functions.UnaryOp {
|
||||
return func(val ref.Val) ref.Val {
|
||||
vVal, ok := val.(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
byt, err := fn(string(vVal))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Bytes(byt)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrOutStr(fn func(string) (string, error)) functions.UnaryOp {
|
||||
return func(val ref.Val) ref.Val {
|
||||
vVal, ok := val.(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
str, err := fn(string(vVal))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.String(str)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrIntOutStr(fn func(string, int64) (string, error)) functions.BinaryOp {
|
||||
return func(val, arg ref.Val) ref.Val {
|
||||
vVal, ok := val.(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
argVal, ok := arg.(types.Int)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
out, err := fn(string(vVal), int64(argVal))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.String(out)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrStrOutInt(fn func(string, string) (int64, error)) functions.BinaryOp {
|
||||
return func(val, arg ref.Val) ref.Val {
|
||||
vVal, ok := val.(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
argVal, ok := arg.(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
out, err := fn(string(vVal), string(argVal))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(out)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrStrOutListStr(fn func(string, string) ([]string, error)) functions.BinaryOp {
|
||||
return func(val, arg ref.Val) ref.Val {
|
||||
vVal, ok := val.(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
argVal, ok := arg.(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
out, err := fn(string(vVal), string(argVal))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.DefaultTypeAdapter.NativeToValue(out)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrIntIntOutStr(fn func(string, int64, int64) (string, error)) functions.FunctionOp {
|
||||
return func(args ...ref.Val) ref.Val {
|
||||
if len(args) != 3 {
|
||||
return types.NoSuchOverloadErr()
|
||||
}
|
||||
vVal, ok := args[0].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[0])
|
||||
}
|
||||
arg1Val, ok := args[1].(types.Int)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[1])
|
||||
}
|
||||
arg2Val, ok := args[2].(types.Int)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[2])
|
||||
}
|
||||
out, err := fn(string(vVal), int64(arg1Val), int64(arg2Val))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.String(out)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrStrStrOutStr(fn func(string, string, string) (string, error)) functions.FunctionOp {
|
||||
return func(args ...ref.Val) ref.Val {
|
||||
if len(args) != 3 {
|
||||
return types.NoSuchOverloadErr()
|
||||
}
|
||||
vVal, ok := args[0].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[0])
|
||||
}
|
||||
arg1Val, ok := args[1].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[1])
|
||||
}
|
||||
arg2Val, ok := args[2].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[2])
|
||||
}
|
||||
out, err := fn(string(vVal), string(arg1Val), string(arg2Val))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.String(out)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrStrIntOutInt(fn func(string, string, int64) (int64, error)) functions.FunctionOp {
|
||||
return func(args ...ref.Val) ref.Val {
|
||||
if len(args) != 3 {
|
||||
return types.NoSuchOverloadErr()
|
||||
}
|
||||
vVal, ok := args[0].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[0])
|
||||
}
|
||||
arg1Val, ok := args[1].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[1])
|
||||
}
|
||||
arg2Val, ok := args[2].(types.Int)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[2])
|
||||
}
|
||||
out, err := fn(string(vVal), string(arg1Val), int64(arg2Val))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(out)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrStrIntOutListStr(fn func(string, string, int64) ([]string, error)) functions.FunctionOp {
|
||||
return func(args ...ref.Val) ref.Val {
|
||||
if len(args) != 3 {
|
||||
return types.NoSuchOverloadErr()
|
||||
}
|
||||
vVal, ok := args[0].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[0])
|
||||
}
|
||||
arg1Val, ok := args[1].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[1])
|
||||
}
|
||||
arg2Val, ok := args[2].(types.Int)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[2])
|
||||
}
|
||||
out, err := fn(string(vVal), string(arg1Val), int64(arg2Val))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.DefaultTypeAdapter.NativeToValue(out)
|
||||
}
|
||||
}
|
||||
|
||||
func callInStrStrStrIntOutStr(fn func(string, string, string, int64) (string, error)) functions.FunctionOp {
|
||||
return func(args ...ref.Val) ref.Val {
|
||||
if len(args) != 4 {
|
||||
return types.NoSuchOverloadErr()
|
||||
}
|
||||
vVal, ok := args[0].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[0])
|
||||
}
|
||||
arg1Val, ok := args[1].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[1])
|
||||
}
|
||||
arg2Val, ok := args[2].(types.String)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[2])
|
||||
}
|
||||
arg3Val, ok := args[3].(types.Int)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(args[3])
|
||||
}
|
||||
out, err := fn(string(vVal), string(arg1Val), string(arg2Val), int64(arg3Val))
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.String(out)
|
||||
}
|
||||
}
|
||||
503
vendor/github.com/google/cel-go/ext/strings.go
generated
vendored
Normal file
503
vendor/github.com/google/cel-go/ext/strings.go
generated
vendored
Normal file
@@ -0,0 +1,503 @@
|
||||
// Copyright 2020 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 contains CEL extension libraries where each library defines a related set of
|
||||
// constants, functions, macros, or other configuration settings which may not be covered by
|
||||
// the core CEL spec.
|
||||
package ext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"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/ref"
|
||||
"github.com/google/cel-go/interpreter/functions"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Strings returns a cel.EnvOption to configure extended functions for string manipulation.
|
||||
// As a general note, all indices are zero-based.
|
||||
//
|
||||
// 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>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'hello'.charAt(4) // return 'o'
|
||||
// 'hello'.charAt(5) // return ''
|
||||
// 'hello'.charAt(-1) // 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.
|
||||
//
|
||||
// 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>
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// The function also accepts an optional position which represents the last index to be
|
||||
// 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>
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'TacoCat'.lowerAscii() // returns 'tacocat'
|
||||
// 'TacoCÆt Xii'.lowerAscii() // returns 'tacocÆt xii'
|
||||
//
|
||||
// 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
|
||||
// substring replacements to be made.
|
||||
//
|
||||
// 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>
|
||||
//
|
||||
// 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'
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// When the split limit is 0, the result is an empty list. When the limit is 1, the result is the
|
||||
// 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>>
|
||||
//
|
||||
// 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']
|
||||
//
|
||||
// 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
|
||||
// a string.
|
||||
//
|
||||
// Character offsets are 0-based with an inclusive start range and exclusive end range. It is an
|
||||
// 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>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'tacocat'.substring(4) // returns 'cat'
|
||||
// 'tacocat'.substring(0, 4) // returns 'taco'
|
||||
// 'tacocat'.substring(-1) // error
|
||||
// 'tacocat'.substring(2, 1) // error
|
||||
//
|
||||
// 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>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ' \ttrim\n '.trim() // returns 'trim'
|
||||
//
|
||||
// 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>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'TacoCat'.upperAscii() // returns 'TACOCAT'
|
||||
// 'TacoCÆt Xii'.upperAscii() // returns 'TACOCÆT XII'
|
||||
func Strings() cel.EnvOption {
|
||||
return cel.Lib(stringLib{})
|
||||
}
|
||||
|
||||
type stringLib struct{}
|
||||
|
||||
func (stringLib) CompileOptions() []cel.EnvOption {
|
||||
return []cel.EnvOption{
|
||||
cel.Declarations(
|
||||
decls.NewFunction("charAt",
|
||||
decls.NewInstanceOverload("string_char_at_int",
|
||||
[]*exprpb.Type{decls.String, decls.Int},
|
||||
decls.String)),
|
||||
decls.NewFunction("indexOf",
|
||||
decls.NewInstanceOverload("string_index_of_string",
|
||||
[]*exprpb.Type{decls.String, decls.String},
|
||||
decls.Int),
|
||||
decls.NewInstanceOverload("string_index_of_string_int",
|
||||
[]*exprpb.Type{decls.String, decls.String, decls.Int},
|
||||
decls.Int)),
|
||||
decls.NewFunction("lastIndexOf",
|
||||
decls.NewInstanceOverload("string_last_index_of_string",
|
||||
[]*exprpb.Type{decls.String, decls.String},
|
||||
decls.Int),
|
||||
decls.NewInstanceOverload("string_last_index_of_string_int",
|
||||
[]*exprpb.Type{decls.String, decls.String, decls.Int},
|
||||
decls.Int)),
|
||||
decls.NewFunction("lowerAscii",
|
||||
decls.NewInstanceOverload("string_lower_ascii",
|
||||
[]*exprpb.Type{decls.String},
|
||||
decls.String)),
|
||||
decls.NewFunction("replace",
|
||||
decls.NewInstanceOverload("string_replace_string_string",
|
||||
[]*exprpb.Type{decls.String, decls.String, decls.String},
|
||||
decls.String),
|
||||
decls.NewInstanceOverload("string_replace_string_string_int",
|
||||
[]*exprpb.Type{decls.String, decls.String, decls.String, decls.Int},
|
||||
decls.String)),
|
||||
decls.NewFunction("split",
|
||||
decls.NewInstanceOverload("string_split_string",
|
||||
[]*exprpb.Type{decls.String, decls.String},
|
||||
decls.NewListType(decls.String)),
|
||||
decls.NewInstanceOverload("string_split_string_int",
|
||||
[]*exprpb.Type{decls.String, decls.String, decls.Int},
|
||||
decls.NewListType(decls.String))),
|
||||
decls.NewFunction("substring",
|
||||
decls.NewInstanceOverload("string_substring_int",
|
||||
[]*exprpb.Type{decls.String, decls.Int},
|
||||
decls.String),
|
||||
decls.NewInstanceOverload("string_substring_int_int",
|
||||
[]*exprpb.Type{decls.String, decls.Int, decls.Int},
|
||||
decls.String)),
|
||||
decls.NewFunction("trim",
|
||||
decls.NewInstanceOverload("string_trim",
|
||||
[]*exprpb.Type{decls.String},
|
||||
decls.String)),
|
||||
decls.NewFunction("upperAscii",
|
||||
decls.NewInstanceOverload("string_upper_ascii",
|
||||
[]*exprpb.Type{decls.String},
|
||||
decls.String)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (stringLib) ProgramOptions() []cel.ProgramOption {
|
||||
wrappedReplace := callInStrStrStrOutStr(replace)
|
||||
wrappedReplaceN := callInStrStrStrIntOutStr(replaceN)
|
||||
return []cel.ProgramOption{
|
||||
cel.Functions(
|
||||
&functions.Overload{
|
||||
Operator: "charAt",
|
||||
Binary: callInStrIntOutStr(charAt),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_char_at_int",
|
||||
Binary: callInStrIntOutStr(charAt),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "indexOf",
|
||||
Binary: callInStrStrOutInt(indexOf),
|
||||
Function: callInStrStrIntOutInt(indexOfOffset),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_index_of_string",
|
||||
Binary: callInStrStrOutInt(indexOf),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_index_of_string_int",
|
||||
Function: callInStrStrIntOutInt(indexOfOffset),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "lastIndexOf",
|
||||
Binary: callInStrStrOutInt(lastIndexOf),
|
||||
Function: callInStrStrIntOutInt(lastIndexOfOffset),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_last_index_of_string",
|
||||
Binary: callInStrStrOutInt(lastIndexOf),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_last_index_of_string_int",
|
||||
Function: callInStrStrIntOutInt(lastIndexOfOffset),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "lowerAscii",
|
||||
Unary: callInStrOutStr(lowerASCII),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_lower_ascii",
|
||||
Unary: callInStrOutStr(lowerASCII),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "replace",
|
||||
Function: func(values ...ref.Val) ref.Val {
|
||||
if len(values) == 3 {
|
||||
return wrappedReplace(values...)
|
||||
}
|
||||
if len(values) == 4 {
|
||||
return wrappedReplaceN(values...)
|
||||
}
|
||||
return types.NoSuchOverloadErr()
|
||||
},
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_replace_string_string",
|
||||
Function: wrappedReplace,
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_replace_string_string_int",
|
||||
Function: wrappedReplaceN,
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "split",
|
||||
Binary: callInStrStrOutListStr(split),
|
||||
Function: callInStrStrIntOutListStr(splitN),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_split_string",
|
||||
Binary: callInStrStrOutListStr(split),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_split_string_int",
|
||||
Function: callInStrStrIntOutListStr(splitN),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "substring",
|
||||
Binary: callInStrIntOutStr(substr),
|
||||
Function: callInStrIntIntOutStr(substrRange),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_substring_int",
|
||||
Binary: callInStrIntOutStr(substr),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_substring_int_int",
|
||||
Function: callInStrIntIntOutStr(substrRange),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "trim",
|
||||
Unary: callInStrOutStr(trimSpace),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_trim",
|
||||
Unary: callInStrOutStr(trimSpace),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "upperAscii",
|
||||
Unary: callInStrOutStr(upperASCII),
|
||||
},
|
||||
&functions.Overload{
|
||||
Operator: "string_upper_ascii",
|
||||
Unary: callInStrOutStr(upperASCII),
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func charAt(str string, ind int64) (string, error) {
|
||||
i := int(ind)
|
||||
runes := []rune(str)
|
||||
if i < 0 || i > len(runes) {
|
||||
return "", fmt.Errorf("index out of range: %d", ind)
|
||||
}
|
||||
if i == len(runes) {
|
||||
return "", nil
|
||||
}
|
||||
return string(runes[i]), nil
|
||||
}
|
||||
|
||||
func indexOf(str, substr string) (int64, error) {
|
||||
return indexOfOffset(str, substr, int64(0))
|
||||
}
|
||||
|
||||
func indexOfOffset(str, substr string, offset int64) (int64, error) {
|
||||
if substr == "" {
|
||||
return offset, nil
|
||||
}
|
||||
off := int(offset)
|
||||
runes := []rune(str)
|
||||
subrunes := []rune(substr)
|
||||
if off < 0 || off >= len(runes) {
|
||||
return -1, fmt.Errorf("index out of range: %d", off)
|
||||
}
|
||||
for i := off; i < len(runes)-(len(subrunes)-1); i++ {
|
||||
found := true
|
||||
for j := 0; j < len(subrunes); j++ {
|
||||
if runes[i+j] != subrunes[j] {
|
||||
found = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
return int64(i), nil
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func lastIndexOf(str, substr string) (int64, error) {
|
||||
runes := []rune(str)
|
||||
if substr == "" {
|
||||
return int64(len(runes)), nil
|
||||
}
|
||||
return lastIndexOfOffset(str, substr, int64(len(runes)-1))
|
||||
}
|
||||
|
||||
func lastIndexOfOffset(str, substr string, offset int64) (int64, error) {
|
||||
if substr == "" {
|
||||
return offset, nil
|
||||
}
|
||||
off := int(offset)
|
||||
runes := []rune(str)
|
||||
subrunes := []rune(substr)
|
||||
if off < 0 || off >= len(runes) {
|
||||
return -1, fmt.Errorf("index out of range: %d", off)
|
||||
}
|
||||
if off > len(runes)-len(subrunes) {
|
||||
off = len(runes) - len(subrunes)
|
||||
}
|
||||
for i := off; i >= 0; i-- {
|
||||
found := true
|
||||
for j := 0; j < len(subrunes); j++ {
|
||||
if runes[i+j] != subrunes[j] {
|
||||
found = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
return int64(i), nil
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func lowerASCII(str string) (string, error) {
|
||||
runes := []rune(str)
|
||||
for i, r := range runes {
|
||||
if r <= unicode.MaxASCII {
|
||||
r = unicode.ToLower(r)
|
||||
runes[i] = r
|
||||
}
|
||||
}
|
||||
return string(runes), nil
|
||||
}
|
||||
|
||||
func replace(str, old, new string) (string, error) {
|
||||
return strings.ReplaceAll(str, old, new), nil
|
||||
}
|
||||
|
||||
func replaceN(str, old, new string, n int64) (string, error) {
|
||||
return strings.Replace(str, old, new, int(n)), nil
|
||||
}
|
||||
|
||||
func split(str, sep string) ([]string, error) {
|
||||
return strings.Split(str, sep), nil
|
||||
}
|
||||
|
||||
func splitN(str, sep string, n int64) ([]string, error) {
|
||||
return strings.SplitN(str, sep, int(n)), nil
|
||||
}
|
||||
|
||||
func substr(str string, start int64) (string, error) {
|
||||
runes := []rune(str)
|
||||
if int(start) < 0 || int(start) > len(runes) {
|
||||
return "", fmt.Errorf("index out of range: %d", start)
|
||||
}
|
||||
return string(runes[start:]), nil
|
||||
}
|
||||
|
||||
func substrRange(str string, start, end int64) (string, error) {
|
||||
runes := []rune(str)
|
||||
l := len(runes)
|
||||
if start > end {
|
||||
return "", fmt.Errorf("invalid substring range. start: %d, end: %d", start, end)
|
||||
}
|
||||
if int(start) < 0 || int(start) > l {
|
||||
return "", fmt.Errorf("index out of range: %d", start)
|
||||
}
|
||||
if int(end) < 0 || int(end) > l {
|
||||
return "", fmt.Errorf("index out of range: %d", end)
|
||||
}
|
||||
return string(runes[int(start):int(end)]), nil
|
||||
}
|
||||
|
||||
func trimSpace(str string) (string, error) {
|
||||
return strings.TrimSpace(str), nil
|
||||
}
|
||||
|
||||
func upperASCII(str string) (string, error) {
|
||||
runes := []rune(str)
|
||||
for i, r := range runes {
|
||||
if r <= unicode.MaxASCII {
|
||||
r = unicode.ToUpper(r)
|
||||
runes[i] = r
|
||||
}
|
||||
}
|
||||
return string(runes), nil
|
||||
}
|
||||
70
vendor/github.com/google/cel-go/interpreter/BUILD.bazel
generated
vendored
Normal file
70
vendor/github.com/google/cel-go/interpreter/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"activation.go",
|
||||
"attribute_patterns.go",
|
||||
"attributes.go",
|
||||
"coster.go",
|
||||
"decorators.go",
|
||||
"dispatcher.go",
|
||||
"evalstate.go",
|
||||
"interpretable.go",
|
||||
"interpreter.go",
|
||||
"planner.go",
|
||||
"prune.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/interpreter",
|
||||
deps = [
|
||||
"//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/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_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",
|
||||
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"activation_test.go",
|
||||
"attribute_patterns_test.go",
|
||||
"attributes_test.go",
|
||||
"interpreter_test.go",
|
||||
"prune_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
deps = [
|
||||
"//checker:go_default_library",
|
||||
"//checker/decls:go_default_library",
|
||||
"//common/containers:go_default_library",
|
||||
"//common/debug:go_default_library",
|
||||
"//common/operators:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//interpreter/functions:go_default_library",
|
||||
"//parser: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/anypb:go_default_library",
|
||||
],
|
||||
)
|
||||
197
vendor/github.com/google/cel-go/interpreter/activation.go
generated
vendored
Normal file
197
vendor/github.com/google/cel-go/interpreter/activation.go
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
// Copyright 2018 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"
|
||||
"sync"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// Activation used to resolve identifiers by name and references by id.
|
||||
//
|
||||
// An Activation is the primary mechanism by which a caller supplies input into a CEL program.
|
||||
type Activation 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)
|
||||
|
||||
// Parent returns the parent of the current activation, may be nil.
|
||||
// If non-nil, the parent will be searched during resolve calls.
|
||||
Parent() Activation
|
||||
}
|
||||
|
||||
// EmptyActivation returns a variable free activation.
|
||||
func EmptyActivation() Activation {
|
||||
// This call cannot fail.
|
||||
a, _ := NewActivation(map[string]interface{}{})
|
||||
return a
|
||||
}
|
||||
|
||||
// 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{}`.
|
||||
//
|
||||
// Lazy bindings may be supplied within the map-based input in either of the following forms:
|
||||
// - func() interface{}
|
||||
// - 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) {
|
||||
if bindings == nil {
|
||||
return nil, errors.New("bindings must be non-nil")
|
||||
}
|
||||
a, isActivation := bindings.(Activation)
|
||||
if isActivation {
|
||||
return a, nil
|
||||
}
|
||||
m, isMap := bindings.(map[string]interface{})
|
||||
if !isMap {
|
||||
return nil, fmt.Errorf(
|
||||
"activation input must be an activation or map[string]interface: got %T",
|
||||
bindings)
|
||||
}
|
||||
return &mapActivation{bindings: m}, nil
|
||||
}
|
||||
|
||||
// mapActivation which implements Activation and maps of named values.
|
||||
//
|
||||
// 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{}
|
||||
}
|
||||
|
||||
// Parent implements the Activation interface method.
|
||||
func (a *mapActivation) Parent() Activation {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResolveName implements the Activation interface method.
|
||||
func (a *mapActivation) ResolveName(name string) (interface{}, bool) {
|
||||
obj, found := a.bindings[name]
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
fn, isLazy := obj.(func() ref.Val)
|
||||
if isLazy {
|
||||
obj = fn()
|
||||
a.bindings[name] = obj
|
||||
}
|
||||
fnRaw, isLazy := obj.(func() interface{})
|
||||
if isLazy {
|
||||
obj = fnRaw()
|
||||
a.bindings[name] = obj
|
||||
}
|
||||
return obj, found
|
||||
}
|
||||
|
||||
// hierarchicalActivation which implements Activation and contains a parent and
|
||||
// child activation.
|
||||
type hierarchicalActivation struct {
|
||||
parent Activation
|
||||
child Activation
|
||||
}
|
||||
|
||||
// Parent implements the Activation interface method.
|
||||
func (a *hierarchicalActivation) Parent() Activation {
|
||||
return a.parent
|
||||
}
|
||||
|
||||
// ResolveName implements the Activation interface method.
|
||||
func (a *hierarchicalActivation) ResolveName(name string) (interface{}, bool) {
|
||||
if object, found := a.child.ResolveName(name); found {
|
||||
return object, found
|
||||
}
|
||||
return a.parent.ResolveName(name)
|
||||
}
|
||||
|
||||
// NewHierarchicalActivation takes two activations and produces a new one which prioritizes
|
||||
// resolution in the child first and parent(s) second.
|
||||
func NewHierarchicalActivation(parent Activation, child Activation) Activation {
|
||||
return &hierarchicalActivation{parent, child}
|
||||
}
|
||||
|
||||
// NewPartialActivation returns an Activation which contains a list of AttributePattern values
|
||||
// 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{},
|
||||
unknowns ...*AttributePattern) (PartialActivation, error) {
|
||||
a, err := NewActivation(bindings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &partActivation{Activation: a, unknowns: unknowns}, nil
|
||||
}
|
||||
|
||||
// PartialActivation extends the Activation interface with a set of UnknownAttributePatterns.
|
||||
type PartialActivation interface {
|
||||
Activation
|
||||
|
||||
// UnknownAttributePaths returns a set of AttributePattern values which match Attribute
|
||||
// expressions for data accesses whose values are not yet known.
|
||||
UnknownAttributePatterns() []*AttributePattern
|
||||
}
|
||||
|
||||
// partActivation is the default implementations of the PartialActivation interface.
|
||||
type partActivation struct {
|
||||
Activation
|
||||
unknowns []*AttributePattern
|
||||
}
|
||||
|
||||
// UnknownAttributePatterns implements the PartialActivation interface method.
|
||||
func (a *partActivation) UnknownAttributePatterns() []*AttributePattern {
|
||||
return a.unknowns
|
||||
}
|
||||
|
||||
// varActivation represents a single mutable variable binding.
|
||||
//
|
||||
// This activation type should only be used within folds as the fold loop controls the object
|
||||
// life-cycle.
|
||||
type varActivation struct {
|
||||
parent Activation
|
||||
name string
|
||||
val ref.Val
|
||||
}
|
||||
|
||||
// Parent implements the Activation interface method.
|
||||
func (v *varActivation) Parent() Activation {
|
||||
return v.parent
|
||||
}
|
||||
|
||||
// ResolveName implements the Activation interface method.
|
||||
func (v *varActivation) ResolveName(name string) (interface{}, bool) {
|
||||
if name == v.name {
|
||||
return v.val, true
|
||||
}
|
||||
return v.parent.ResolveName(name)
|
||||
}
|
||||
|
||||
var (
|
||||
// pool of var activations to reduce allocations during folds.
|
||||
varActivationPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &varActivation{}
|
||||
},
|
||||
}
|
||||
)
|
||||
383
vendor/github.com/google/cel-go/interpreter/attribute_patterns.go
generated
vendored
Normal file
383
vendor/github.com/google/cel-go/interpreter/attribute_patterns.go
generated
vendored
Normal file
@@ -0,0 +1,383 @@
|
||||
// Copyright 2020 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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// AttributePattern represents a top-level variable with an optional set of qualifier patterns.
|
||||
//
|
||||
// When using a CEL expression within a container, e.g. a package or namespace, the variable name
|
||||
// in the pattern must match the qualified name produced during the variable namespace resolution.
|
||||
// For example, if variable `c` appears in an expression whose container is `a.b`, the variable
|
||||
// name supplied to the pattern must be `a.b.c`
|
||||
//
|
||||
// The qualifier patterns for attribute matching must be one of the following:
|
||||
//
|
||||
// - valid map key type: string, int, uint, bool
|
||||
// - wildcard (*)
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 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
|
||||
// a specific index `0` should match. And lastly, the third example matches any indexed access
|
||||
// that later selects the 'name' field.
|
||||
type AttributePattern struct {
|
||||
variable string
|
||||
qualifierPatterns []*AttributeQualifierPattern
|
||||
}
|
||||
|
||||
// NewAttributePattern produces a new mutable AttributePattern based on a variable name.
|
||||
func NewAttributePattern(variable string) *AttributePattern {
|
||||
return &AttributePattern{
|
||||
variable: variable,
|
||||
qualifierPatterns: []*AttributeQualifierPattern{},
|
||||
}
|
||||
}
|
||||
|
||||
// QualString adds a string qualifier pattern to the AttributePattern. The string may be a valid
|
||||
// identifier, or string map key including empty string.
|
||||
func (apat *AttributePattern) QualString(pattern string) *AttributePattern {
|
||||
apat.qualifierPatterns = append(apat.qualifierPatterns,
|
||||
&AttributeQualifierPattern{value: pattern})
|
||||
return apat
|
||||
}
|
||||
|
||||
// QualInt adds an int qualifier pattern to the AttributePattern. The index may be either a map or
|
||||
// list index.
|
||||
func (apat *AttributePattern) QualInt(pattern int64) *AttributePattern {
|
||||
apat.qualifierPatterns = append(apat.qualifierPatterns,
|
||||
&AttributeQualifierPattern{value: pattern})
|
||||
return apat
|
||||
}
|
||||
|
||||
// QualUint adds an uint qualifier pattern for a map index operation to the AttributePattern.
|
||||
func (apat *AttributePattern) QualUint(pattern uint64) *AttributePattern {
|
||||
apat.qualifierPatterns = append(apat.qualifierPatterns,
|
||||
&AttributeQualifierPattern{value: pattern})
|
||||
return apat
|
||||
}
|
||||
|
||||
// QualBool adds a bool qualifier pattern for a map index operation to the AttributePattern.
|
||||
func (apat *AttributePattern) QualBool(pattern bool) *AttributePattern {
|
||||
apat.qualifierPatterns = append(apat.qualifierPatterns,
|
||||
&AttributeQualifierPattern{value: pattern})
|
||||
return apat
|
||||
}
|
||||
|
||||
// Wildcard adds a special sentinel qualifier pattern that will match any single qualifier.
|
||||
func (apat *AttributePattern) Wildcard() *AttributePattern {
|
||||
apat.qualifierPatterns = append(apat.qualifierPatterns,
|
||||
&AttributeQualifierPattern{wildcard: true})
|
||||
return apat
|
||||
}
|
||||
|
||||
// VariableMatches returns true if the fully qualified variable matches the AttributePattern
|
||||
// fully qualified variable name.
|
||||
func (apat *AttributePattern) VariableMatches(variable string) bool {
|
||||
return apat.variable == variable
|
||||
}
|
||||
|
||||
// QualifierPatterns returns the set of AttributeQualifierPattern values on the AttributePattern.
|
||||
func (apat *AttributePattern) QualifierPatterns() []*AttributeQualifierPattern {
|
||||
return apat.qualifierPatterns
|
||||
}
|
||||
|
||||
// AttributeQualifierPattern holds a wilcard or valued qualifier pattern.
|
||||
type AttributeQualifierPattern struct {
|
||||
wildcard bool
|
||||
value interface{}
|
||||
}
|
||||
|
||||
// Matches returns true if the qualifier pattern is a wildcard, or the Qualifier implements the
|
||||
// qualifierValueEquator interface and its IsValueEqualTo returns true for the qualifier pattern.
|
||||
func (qpat *AttributeQualifierPattern) Matches(q Qualifier) bool {
|
||||
if qpat.wildcard {
|
||||
return true
|
||||
}
|
||||
qve, ok := q.(qualifierValueEquator)
|
||||
return ok && qve.QualifierValueEquals(qpat.value)
|
||||
}
|
||||
|
||||
// qualifierValueEquator defines an interface for determining if an input value, of valid map key
|
||||
// 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
|
||||
// qualification happens. This is an implementation detail, but one relevant to why the Attribute
|
||||
// types do not surface in the list of implementations.
|
||||
//
|
||||
// See: partialAttributeFactory.matchesUnknownPatterns for more details on how this interface is
|
||||
// used.
|
||||
type qualifierValueEquator interface {
|
||||
// QualifierValueEquals returns true if the input value is equal to the value held in the
|
||||
// Qualifier.
|
||||
QualifierValueEquals(value interface{}) bool
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for boolean qualifiers.
|
||||
func (q *boolQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
bval, ok := value.(bool)
|
||||
return ok && q.value == bval
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for field qualifiers.
|
||||
func (q *fieldQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
sval, ok := value.(string)
|
||||
return ok && q.Name == sval
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for string qualifiers.
|
||||
func (q *stringQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
sval, ok := value.(string)
|
||||
return ok && q.value == sval
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for int qualifiers.
|
||||
func (q *intQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
ival, ok := value.(int64)
|
||||
return ok && q.value == ival
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for uint qualifiers.
|
||||
func (q *uintQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
uval, ok := value.(uint64)
|
||||
return ok && q.value == uval
|
||||
}
|
||||
|
||||
// NewPartialAttributeFactory returns an AttributeFactory implementation capable of performing
|
||||
// AttributePattern matches with PartialActivation inputs.
|
||||
func NewPartialAttributeFactory(container *containers.Container,
|
||||
adapter ref.TypeAdapter,
|
||||
provider ref.TypeProvider) AttributeFactory {
|
||||
fac := NewAttributeFactory(container, adapter, provider)
|
||||
return &partialAttributeFactory{
|
||||
AttributeFactory: fac,
|
||||
container: container,
|
||||
adapter: adapter,
|
||||
provider: provider,
|
||||
}
|
||||
}
|
||||
|
||||
type partialAttributeFactory struct {
|
||||
AttributeFactory
|
||||
container *containers.Container
|
||||
adapter ref.TypeAdapter
|
||||
provider ref.TypeProvider
|
||||
}
|
||||
|
||||
// AbsoluteAttribute implementation of the AttributeFactory interface which wraps the
|
||||
// NamespacedAttribute resolution in an internal attributeMatcher object to dynamically match
|
||||
// unknown patterns from PartialActivation inputs if given.
|
||||
func (fac *partialAttributeFactory) AbsoluteAttribute(id int64, names ...string) NamespacedAttribute {
|
||||
attr := fac.AttributeFactory.AbsoluteAttribute(id, names...)
|
||||
return &attributeMatcher{fac: fac, NamespacedAttribute: attr}
|
||||
}
|
||||
|
||||
// MaybeAttribute implementation of the AttributeFactory interface which ensure that the set of
|
||||
// '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{
|
||||
id: id,
|
||||
attrs: []NamespacedAttribute{
|
||||
fac.AbsoluteAttribute(id, fac.container.ResolveCandidateNames(name)...),
|
||||
},
|
||||
adapter: fac.adapter,
|
||||
provider: fac.provider,
|
||||
fac: fac,
|
||||
}
|
||||
}
|
||||
|
||||
// matchesUnknownPatterns returns true if the variable names and qualifiers for a given
|
||||
// Attribute value match any of the ActivationPattern objects in the set of unknown activation
|
||||
// patterns on the given PartialActivation.
|
||||
//
|
||||
// For example, in the expression `a.b`, the Attribute is composed of variable `a`, with string
|
||||
// qualifier `b`. When a PartialActivation is supplied, it indicates that some or all of the data
|
||||
// provided in the input is unknown by specifying unknown AttributePatterns. An AttributePattern
|
||||
// that refers to variable `a` with a string qualifier of `c` will not match `a.b`; however, any
|
||||
// of the following patterns will match Attribute `a.b`:
|
||||
//
|
||||
// - `AttributePattern("a")`
|
||||
// - `AttributePattern("a").Wildcard()`
|
||||
// - `AttributePattern("a").QualString("b")`
|
||||
// - `AttributePattern("a").QualString("b").QualInt(0)`
|
||||
//
|
||||
// Any AttributePattern which overlaps an Attribute or vice-versa will produce an Unknown result
|
||||
// for the last pattern matched variable or qualifier in the Attribute. In the first matching
|
||||
// example, the expression id representing variable `a` would be listed in the Unknown result,
|
||||
// whereas in the other pattern examples, the qualifier `b` would be returned as the Unknown.
|
||||
func (fac *partialAttributeFactory) matchesUnknownPatterns(
|
||||
vars PartialActivation,
|
||||
attrID int64,
|
||||
variableNames []string,
|
||||
qualifiers []Qualifier) (types.Unknown, error) {
|
||||
patterns := vars.UnknownAttributePatterns()
|
||||
candidateIndices := map[int]struct{}{}
|
||||
for _, variable := range variableNames {
|
||||
for i, pat := range patterns {
|
||||
if pat.VariableMatches(variable) {
|
||||
candidateIndices[i] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Determine whether to return early if there are no candidate unknown patterns.
|
||||
if len(candidateIndices) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
// Determine whether to return early if there are no qualifiers.
|
||||
if len(qualifiers) == 0 {
|
||||
return types.Unknown{attrID}, nil
|
||||
}
|
||||
// Resolve the attribute qualifiers into a static set. This prevents more dynamic
|
||||
// Attribute resolutions than necessary when there are multiple unknown patterns
|
||||
// that traverse the same Attribute-based qualifier field.
|
||||
newQuals := make([]Qualifier, len(qualifiers))
|
||||
for i, qual := range qualifiers {
|
||||
attr, isAttr := qual.(Attribute)
|
||||
if isAttr {
|
||||
val, err := attr.Resolve(vars)
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
newQuals[i] = qual
|
||||
}
|
||||
// Determine whether any of the unknown patterns match.
|
||||
for patIdx := range candidateIndices {
|
||||
pat := patterns[patIdx]
|
||||
isUnk := true
|
||||
matchExprID := attrID
|
||||
qualPats := pat.QualifierPatterns()
|
||||
for i, qual := range newQuals {
|
||||
if i >= len(qualPats) {
|
||||
break
|
||||
}
|
||||
matchExprID = qual.ID()
|
||||
qualPat := qualPats[i]
|
||||
// Note, the AttributeQualifierPattern relies on the input Qualifier not being an
|
||||
// Attribute, since there is no way to resolve the Attribute with the information
|
||||
// provided to the Matches call.
|
||||
if !qualPat.Matches(qual) {
|
||||
isUnk = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if isUnk {
|
||||
return types.Unknown{matchExprID}, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// attributeMatcher embeds the NamespacedAttribute interface which allows it to participate in
|
||||
// AttributePattern matching against Attribute values without having to modify the code paths that
|
||||
// identify Attributes in expressions.
|
||||
type attributeMatcher struct {
|
||||
NamespacedAttribute
|
||||
qualifiers []Qualifier
|
||||
fac *partialAttributeFactory
|
||||
}
|
||||
|
||||
// AddQualifier implements the Attribute interface method.
|
||||
func (m *attributeMatcher) AddQualifier(qual Qualifier) (Attribute, error) {
|
||||
// Add the qualifier to the embedded NamespacedAttribute. If the input to the Resolve
|
||||
// method is not a PartialActivation, or does not match an unknown attribute pattern, the
|
||||
// Resolve method is directly invoked on the underlying NamespacedAttribute.
|
||||
_, err := m.NamespacedAttribute.AddQualifier(qual)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The attributeMatcher overloads TryResolve and will attempt to match unknown patterns against
|
||||
// the variable name and qualifier set contained within the Attribute. These values are not
|
||||
// directly inspectable on the top-level NamespacedAttribute interface and so are tracked within
|
||||
// the attributeMatcher.
|
||||
m.qualifiers = append(m.qualifiers, qual)
|
||||
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
|
||||
// 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) {
|
||||
id := m.NamespacedAttribute.ID()
|
||||
partial, isPartial := vars.(PartialActivation)
|
||||
if isPartial {
|
||||
unk, err := m.fac.matchesUnknownPatterns(
|
||||
partial,
|
||||
id,
|
||||
m.CandidateVariableNames(),
|
||||
m.qualifiers)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
if unk != nil {
|
||||
return unk, true, nil
|
||||
}
|
||||
}
|
||||
return m.NamespacedAttribute.TryResolve(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)
|
||||
}
|
||||
1032
vendor/github.com/google/cel-go/interpreter/attributes.go
generated
vendored
Normal file
1032
vendor/github.com/google/cel-go/interpreter/attributes.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
31
vendor/github.com/google/cel-go/interpreter/coster.go
generated
vendored
Normal file
31
vendor/github.com/google/cel-go/interpreter/coster.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2020 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 "math"
|
||||
|
||||
// Coster calculates the heuristic cost incurred during evaluation.
|
||||
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()
|
||||
}
|
||||
201
vendor/github.com/google/cel-go/interpreter/decorators.go
generated
vendored
Normal file
201
vendor/github.com/google/cel-go/interpreter/decorators.go
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
// Copyright 2018 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 (
|
||||
"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"
|
||||
)
|
||||
|
||||
// InterpretableDecorator is a functional interface for decorating or replacing
|
||||
// Interpretable expression nodes at construction time.
|
||||
type InterpretableDecorator func(Interpretable) (Interpretable, error)
|
||||
|
||||
// evalObserver is a functional interface that accepts an expression id and an observed value.
|
||||
type evalObserver func(int64, ref.Val)
|
||||
|
||||
// decObserveEval records evaluation state into an EvalState object.
|
||||
func decObserveEval(observer evalObserver) InterpretableDecorator {
|
||||
return func(i Interpretable) (Interpretable, error) {
|
||||
switch inst := i.(type) {
|
||||
case *evalWatch, *evalWatchAttr, *evalWatchConst:
|
||||
// these instruction are already watching, return straight-away.
|
||||
return i, nil
|
||||
case InterpretableAttribute:
|
||||
return &evalWatchAttr{
|
||||
InterpretableAttribute: inst,
|
||||
observer: observer,
|
||||
}, nil
|
||||
case InterpretableConst:
|
||||
return &evalWatchConst{
|
||||
InterpretableConst: inst,
|
||||
observer: observer,
|
||||
}, nil
|
||||
default:
|
||||
return &evalWatch{
|
||||
Interpretable: i,
|
||||
observer: observer,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decDisableShortcircuits ensures that all branches of an expression will be evaluated, no short-circuiting.
|
||||
func decDisableShortcircuits() InterpretableDecorator {
|
||||
return func(i Interpretable) (Interpretable, error) {
|
||||
switch expr := i.(type) {
|
||||
case *evalOr:
|
||||
return &evalExhaustiveOr{
|
||||
id: expr.id,
|
||||
lhs: expr.lhs,
|
||||
rhs: expr.rhs,
|
||||
}, nil
|
||||
case *evalAnd:
|
||||
return &evalExhaustiveAnd{
|
||||
id: expr.id,
|
||||
lhs: expr.lhs,
|
||||
rhs: expr.rhs,
|
||||
}, nil
|
||||
case *evalFold:
|
||||
return &evalExhaustiveFold{
|
||||
id: expr.id,
|
||||
accu: expr.accu,
|
||||
accuVar: expr.accuVar,
|
||||
iterRange: expr.iterRange,
|
||||
iterVar: expr.iterVar,
|
||||
cond: expr.cond,
|
||||
step: expr.step,
|
||||
result: expr.result,
|
||||
}, nil
|
||||
case InterpretableAttribute:
|
||||
cond, isCond := expr.Attr().(*conditionalAttribute)
|
||||
if isCond {
|
||||
return &evalExhaustiveConditional{
|
||||
id: cond.id,
|
||||
attr: cond,
|
||||
adapter: expr.Adapter(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
// decOptimize optimizes the program plan by looking for common evaluation patterns and
|
||||
// conditionally precomputating the result.
|
||||
// - build list and map values with constant elements.
|
||||
// - convert 'in' operations to set membership tests if possible.
|
||||
func decOptimize() InterpretableDecorator {
|
||||
return func(i Interpretable) (Interpretable, error) {
|
||||
switch inst := i.(type) {
|
||||
case *evalList:
|
||||
return maybeBuildListLiteral(i, inst)
|
||||
case *evalMap:
|
||||
return maybeBuildMapLiteral(i, inst)
|
||||
case InterpretableCall:
|
||||
if inst.OverloadID() == overloads.InList {
|
||||
return maybeOptimizeSetMembership(i, inst)
|
||||
}
|
||||
if overloads.IsTypeConversionFunction(inst.Function()) {
|
||||
return maybeOptimizeConstUnary(i, inst)
|
||||
}
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
func maybeOptimizeConstUnary(i Interpretable, call InterpretableCall) (Interpretable, error) {
|
||||
args := call.Args()
|
||||
if len(args) != 1 {
|
||||
return i, nil
|
||||
}
|
||||
_, isConst := args[0].(InterpretableConst)
|
||||
if !isConst {
|
||||
return i, nil
|
||||
}
|
||||
val := call.Eval(EmptyActivation())
|
||||
if types.IsError(val) {
|
||||
return nil, val.(*types.Err)
|
||||
}
|
||||
return NewConstValue(call.ID(), val), nil
|
||||
}
|
||||
|
||||
func maybeBuildListLiteral(i Interpretable, l *evalList) (Interpretable, error) {
|
||||
for _, elem := range l.elems {
|
||||
_, isConst := elem.(InterpretableConst)
|
||||
if !isConst {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
return NewConstValue(l.ID(), l.Eval(EmptyActivation())), nil
|
||||
}
|
||||
|
||||
func maybeBuildMapLiteral(i Interpretable, mp *evalMap) (Interpretable, error) {
|
||||
for idx, key := range mp.keys {
|
||||
_, isConst := key.(InterpretableConst)
|
||||
if !isConst {
|
||||
return i, nil
|
||||
}
|
||||
_, isConst = mp.vals[idx].(InterpretableConst)
|
||||
if !isConst {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
return NewConstValue(mp.ID(), mp.Eval(EmptyActivation())), nil
|
||||
}
|
||||
|
||||
// maybeOptimizeSetMembership may convert an 'in' operation against a list to map key membership
|
||||
// test if the following conditions are true:
|
||||
// - the list is a constant with homogeneous element types.
|
||||
// - the elements are all of primitive type.
|
||||
func maybeOptimizeSetMembership(i Interpretable, inlist InterpretableCall) (Interpretable, error) {
|
||||
args := inlist.Args()
|
||||
lhs := args[0]
|
||||
rhs := args[1]
|
||||
l, isConst := rhs.(InterpretableConst)
|
||||
if !isConst {
|
||||
return i, nil
|
||||
}
|
||||
// When the incoming binary call is flagged with as the InList overload, the value will
|
||||
// always be convertible to a `traits.Lister` type.
|
||||
list := l.Value().(traits.Lister)
|
||||
if list.Size() == types.IntZero {
|
||||
return NewConstValue(inlist.ID(), types.False), nil
|
||||
}
|
||||
it := list.Iterator()
|
||||
var typ ref.Type
|
||||
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.
|
||||
return i, nil
|
||||
}
|
||||
if typ == nil {
|
||||
typ = elem.Type()
|
||||
} else if typ.TypeName() != elem.Type().TypeName() {
|
||||
return i, nil
|
||||
}
|
||||
valueSet[elem] = types.True
|
||||
}
|
||||
return &evalSetMembership{
|
||||
inst: inlist,
|
||||
arg: lhs,
|
||||
argTypeName: typ.TypeName(),
|
||||
valueSet: valueSet,
|
||||
}, nil
|
||||
}
|
||||
100
vendor/github.com/google/cel-go/interpreter/dispatcher.go
generated
vendored
Normal file
100
vendor/github.com/google/cel-go/interpreter/dispatcher.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/interpreter/functions"
|
||||
)
|
||||
|
||||
// Dispatcher resolves function calls to their appropriate overload.
|
||||
type Dispatcher interface {
|
||||
// Add one or more overloads, returning an error if any Overload has the same Overload#Name.
|
||||
Add(overloads ...*functions.Overload) error
|
||||
|
||||
// FindOverload returns an Overload definition matching the provided name.
|
||||
FindOverload(overload string) (*functions.Overload, bool)
|
||||
|
||||
// OverloadIds returns the set of all overload identifiers configured for dispatch.
|
||||
OverloadIds() []string
|
||||
}
|
||||
|
||||
// NewDispatcher returns an empty Dispatcher instance.
|
||||
func NewDispatcher() Dispatcher {
|
||||
return &defaultDispatcher{
|
||||
overloads: make(map[string]*functions.Overload)}
|
||||
}
|
||||
|
||||
// ExtendDispatcher returns a Dispatcher which inherits the overloads of its parent, and
|
||||
// provides an isolation layer between built-ins and extension functions which is useful
|
||||
// for forward compatibility.
|
||||
func ExtendDispatcher(parent Dispatcher) Dispatcher {
|
||||
return &defaultDispatcher{
|
||||
parent: parent,
|
||||
overloads: make(map[string]*functions.Overload)}
|
||||
}
|
||||
|
||||
// overloadMap helper type for indexing overloads by function name.
|
||||
type overloadMap map[string]*functions.Overload
|
||||
|
||||
// defaultDispatcher struct which contains an overload map.
|
||||
type defaultDispatcher struct {
|
||||
parent Dispatcher
|
||||
overloads overloadMap
|
||||
}
|
||||
|
||||
// Add implements the Dispatcher.Add interface method.
|
||||
func (d *defaultDispatcher) Add(overloads ...*functions.Overload) error {
|
||||
for _, o := range overloads {
|
||||
// add the overload unless an overload of the same name has already been provided.
|
||||
if _, found := d.overloads[o.Operator]; found {
|
||||
return fmt.Errorf("overload already exists '%s'", o.Operator)
|
||||
}
|
||||
// index the overload by function name.
|
||||
d.overloads[o.Operator] = o
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindOverload implements the Dispatcher.FindOverload interface method.
|
||||
func (d *defaultDispatcher) FindOverload(overload string) (*functions.Overload, bool) {
|
||||
o, found := d.overloads[overload]
|
||||
// Attempt to dispatch to an overload defined in the parent.
|
||||
if !found && d.parent != nil {
|
||||
return d.parent.FindOverload(overload)
|
||||
}
|
||||
return o, found
|
||||
}
|
||||
|
||||
// OverloadIds implements the Dispatcher interface method.
|
||||
func (d *defaultDispatcher) OverloadIds() []string {
|
||||
i := 0
|
||||
overloads := make([]string, len(d.overloads))
|
||||
for name := range d.overloads {
|
||||
overloads[i] = name
|
||||
i++
|
||||
}
|
||||
if d.parent == nil {
|
||||
return overloads
|
||||
}
|
||||
parentOverloads := d.parent.OverloadIds()
|
||||
for _, pName := range parentOverloads {
|
||||
if _, found := d.overloads[pName]; !found {
|
||||
overloads = append(overloads, pName)
|
||||
}
|
||||
}
|
||||
return overloads
|
||||
}
|
||||
75
vendor/github.com/google/cel-go/interpreter/evalstate.go
generated
vendored
Normal file
75
vendor/github.com/google/cel-go/interpreter/evalstate.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright 2018 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 (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// EvalState tracks the values associated with expression ids during execution.
|
||||
type EvalState interface {
|
||||
// IDs returns the list of ids with recorded values.
|
||||
IDs() []int64
|
||||
|
||||
// Value returns the observed value of the given expression id if found, and a nil false
|
||||
// result if not.
|
||||
Value(int64) (ref.Val, bool)
|
||||
|
||||
// SetValue sets the observed value of the expression id.
|
||||
SetValue(int64, ref.Val)
|
||||
|
||||
// Reset clears the previously recorded expression values.
|
||||
Reset()
|
||||
}
|
||||
|
||||
// evalState permits the mutation of evaluation state for a given expression id.
|
||||
type evalState struct {
|
||||
values map[int64]ref.Val
|
||||
}
|
||||
|
||||
// NewEvalState returns an EvalState instanced used to observe the intermediate
|
||||
// evaluations of an expression.
|
||||
func NewEvalState() EvalState {
|
||||
return &evalState{
|
||||
values: make(map[int64]ref.Val),
|
||||
}
|
||||
}
|
||||
|
||||
// IDs implements the EvalState interface method.
|
||||
func (s *evalState) IDs() []int64 {
|
||||
var ids []int64
|
||||
for k, v := range s.values {
|
||||
if v != nil {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// Value is an implementation of the EvalState interface method.
|
||||
func (s *evalState) Value(exprID int64) (ref.Val, bool) {
|
||||
val, found := s.values[exprID]
|
||||
return val, found
|
||||
}
|
||||
|
||||
// SetValue is an implementation of the EvalState interface method.
|
||||
func (s *evalState) SetValue(exprID int64, val ref.Val) {
|
||||
s.values[exprID] = val
|
||||
}
|
||||
|
||||
// Reset implements the EvalState interface method.
|
||||
func (s *evalState) Reset() {
|
||||
s.values = map[int64]ref.Val{}
|
||||
}
|
||||
22
vendor/github.com/google/cel-go/interpreter/functions/BUILD.bazel
generated
vendored
Normal file
22
vendor/github.com/google/cel-go/interpreter/functions/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"functions.go",
|
||||
"standard.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/interpreter/functions",
|
||||
deps = [
|
||||
"//common/operators:go_default_library",
|
||||
"//common/overloads:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"//common/types/traits:go_default_library",
|
||||
],
|
||||
)
|
||||
58
vendor/github.com/google/cel-go/interpreter/functions/functions.go
generated
vendored
Normal file
58
vendor/github.com/google/cel-go/interpreter/functions/functions.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2018 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 functions defines the standard builtin functions supported by the
|
||||
// interpreter and as declared within the checker#StandardDeclarations.
|
||||
package functions
|
||||
|
||||
import "github.com/google/cel-go/common/types/ref"
|
||||
|
||||
// Overload defines a named overload of a function, indicating an operand trait
|
||||
// which must be present on the first argument to the overload as well as one
|
||||
// of either a unary, binary, or function implementation.
|
||||
//
|
||||
// The majority of operators within the expression language are unary or binary
|
||||
// and the specializations simplify the call contract for implementers of
|
||||
// types with operator overloads. Any added complexity is assumed to be handled
|
||||
// by the generic FunctionOp.
|
||||
type Overload struct {
|
||||
// Operator name as written in an expression or defined within
|
||||
// operators.go.
|
||||
Operator string
|
||||
|
||||
// Operand trait used to dispatch the call. The zero-value indicates a
|
||||
// global function overload or that one of the Unary / Binary / Function
|
||||
// definitions should be used to execute the call.
|
||||
OperandTrait int
|
||||
|
||||
// Unary defines the overload with a UnaryOp implementation. May be nil.
|
||||
Unary UnaryOp
|
||||
|
||||
// Binary defines the overload with a BinaryOp implementation. May be nil.
|
||||
Binary BinaryOp
|
||||
|
||||
// Function defines the overload with a FunctionOp implementation. May be
|
||||
// nil.
|
||||
Function FunctionOp
|
||||
}
|
||||
|
||||
// UnaryOp is a function that takes a single value and produces an output.
|
||||
type UnaryOp func(value ref.Val) ref.Val
|
||||
|
||||
// BinaryOp is a function that takes two values and produces an output.
|
||||
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.
|
||||
type FunctionOp func(values ...ref.Val) ref.Val
|
||||
272
vendor/github.com/google/cel-go/interpreter/functions/standard.go
generated
vendored
Normal file
272
vendor/github.com/google/cel-go/interpreter/functions/standard.go
generated
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
// Copyright 2018 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 functions
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// StandardOverloads returns the definitions of the built-in overloads.
|
||||
func StandardOverloads() []*Overload {
|
||||
return []*Overload{
|
||||
// Logical not (!a)
|
||||
{
|
||||
Operator: operators.LogicalNot,
|
||||
OperandTrait: traits.NegatorType,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
if !types.IsBool(value) {
|
||||
return types.ValOrErr(value, "no such overload")
|
||||
}
|
||||
return value.(traits.Negater).Negate()
|
||||
}},
|
||||
// Not strictly false: IsBool(a) ? a : true
|
||||
{
|
||||
Operator: operators.NotStrictlyFalse,
|
||||
Unary: notStrictlyFalse},
|
||||
// Deprecated: not strictly false, may be overridden in the environment.
|
||||
{
|
||||
Operator: operators.OldNotStrictlyFalse,
|
||||
Unary: notStrictlyFalse},
|
||||
|
||||
// Less than operator
|
||||
{Operator: operators.Less,
|
||||
OperandTrait: traits.ComparerType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
cmp := lhs.(traits.Comparer).Compare(rhs)
|
||||
if cmp == types.IntNegOne {
|
||||
return types.True
|
||||
}
|
||||
if cmp == types.IntOne || cmp == types.IntZero {
|
||||
return types.False
|
||||
}
|
||||
return cmp
|
||||
}},
|
||||
|
||||
// Less than or equal operator
|
||||
{Operator: operators.LessEquals,
|
||||
OperandTrait: traits.ComparerType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
cmp := lhs.(traits.Comparer).Compare(rhs)
|
||||
if cmp == types.IntNegOne || cmp == types.IntZero {
|
||||
return types.True
|
||||
}
|
||||
if cmp == types.IntOne {
|
||||
return types.False
|
||||
}
|
||||
return cmp
|
||||
}},
|
||||
|
||||
// Greater than operator
|
||||
{Operator: operators.Greater,
|
||||
OperandTrait: traits.ComparerType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
cmp := lhs.(traits.Comparer).Compare(rhs)
|
||||
if cmp == types.IntOne {
|
||||
return types.True
|
||||
}
|
||||
if cmp == types.IntNegOne || cmp == types.IntZero {
|
||||
return types.False
|
||||
}
|
||||
return cmp
|
||||
}},
|
||||
|
||||
// Greater than equal operators
|
||||
{Operator: operators.GreaterEquals,
|
||||
OperandTrait: traits.ComparerType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
cmp := lhs.(traits.Comparer).Compare(rhs)
|
||||
if cmp == types.IntOne || cmp == types.IntZero {
|
||||
return types.True
|
||||
}
|
||||
if cmp == types.IntNegOne {
|
||||
return types.False
|
||||
}
|
||||
return cmp
|
||||
}},
|
||||
|
||||
// TODO: Verify overflow, NaN, underflow cases for numeric values.
|
||||
|
||||
// Add operator
|
||||
{Operator: operators.Add,
|
||||
OperandTrait: traits.AdderType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Adder).Add(rhs)
|
||||
}},
|
||||
|
||||
// Subtract operators
|
||||
{Operator: operators.Subtract,
|
||||
OperandTrait: traits.SubtractorType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Subtractor).Subtract(rhs)
|
||||
}},
|
||||
|
||||
// Multiply operator
|
||||
{Operator: operators.Multiply,
|
||||
OperandTrait: traits.MultiplierType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Multiplier).Multiply(rhs)
|
||||
}},
|
||||
|
||||
// Divide operator
|
||||
{Operator: operators.Divide,
|
||||
OperandTrait: traits.DividerType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Divider).Divide(rhs)
|
||||
}},
|
||||
|
||||
// Modulo operator
|
||||
{Operator: operators.Modulo,
|
||||
OperandTrait: traits.ModderType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Modder).Modulo(rhs)
|
||||
}},
|
||||
|
||||
// Negate operator
|
||||
{Operator: operators.Negate,
|
||||
OperandTrait: traits.NegatorType,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
if types.IsBool(value) {
|
||||
return types.ValOrErr(value, "no such overload")
|
||||
}
|
||||
return value.(traits.Negater).Negate()
|
||||
}},
|
||||
|
||||
// Index operator
|
||||
{Operator: operators.Index,
|
||||
OperandTrait: traits.IndexerType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Indexer).Get(rhs)
|
||||
}},
|
||||
|
||||
// Size function
|
||||
{Operator: overloads.Size,
|
||||
OperandTrait: traits.SizerType,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.(traits.Sizer).Size()
|
||||
}},
|
||||
|
||||
// In operator
|
||||
{Operator: operators.In, Binary: inAggregate},
|
||||
// Deprecated: in operator, may be overridden in the environment.
|
||||
{Operator: operators.OldIn, Binary: inAggregate},
|
||||
|
||||
// Matches function
|
||||
{Operator: overloads.Matches,
|
||||
OperandTrait: traits.MatcherType,
|
||||
Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Matcher).Match(rhs)
|
||||
}},
|
||||
|
||||
// Type conversion functions
|
||||
// TODO: verify type conversion safety of numeric values.
|
||||
|
||||
// Int conversions.
|
||||
{Operator: overloads.TypeConvertInt,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.ConvertToType(types.IntType)
|
||||
}},
|
||||
|
||||
// Uint conversions.
|
||||
{Operator: overloads.TypeConvertUint,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.ConvertToType(types.UintType)
|
||||
}},
|
||||
|
||||
// Double conversions.
|
||||
{Operator: overloads.TypeConvertDouble,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.ConvertToType(types.DoubleType)
|
||||
}},
|
||||
|
||||
// Bool conversions.
|
||||
{Operator: overloads.TypeConvertBool,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.ConvertToType(types.BoolType)
|
||||
}},
|
||||
|
||||
// Bytes conversions.
|
||||
{Operator: overloads.TypeConvertBytes,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.ConvertToType(types.BytesType)
|
||||
}},
|
||||
|
||||
// String conversions.
|
||||
{Operator: overloads.TypeConvertString,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.ConvertToType(types.StringType)
|
||||
}},
|
||||
|
||||
// Timestamp conversions.
|
||||
{Operator: overloads.TypeConvertTimestamp,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.ConvertToType(types.TimestampType)
|
||||
}},
|
||||
|
||||
// Duration conversions.
|
||||
{Operator: overloads.TypeConvertDuration,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.ConvertToType(types.DurationType)
|
||||
}},
|
||||
|
||||
// Type operations.
|
||||
{Operator: overloads.TypeConvertType,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.ConvertToType(types.TypeType)
|
||||
}},
|
||||
|
||||
// Dyn conversion (identity function).
|
||||
{Operator: overloads.TypeConvertDyn,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value
|
||||
}},
|
||||
|
||||
{Operator: overloads.Iterator,
|
||||
OperandTrait: traits.IterableType,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.(traits.Iterable).Iterator()
|
||||
}},
|
||||
|
||||
{Operator: overloads.HasNext,
|
||||
OperandTrait: traits.IteratorType,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.(traits.Iterator).HasNext()
|
||||
}},
|
||||
|
||||
{Operator: overloads.Next,
|
||||
OperandTrait: traits.IteratorType,
|
||||
Unary: func(value ref.Val) ref.Val {
|
||||
return value.(traits.Iterator).Next()
|
||||
}},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func notStrictlyFalse(value ref.Val) ref.Val {
|
||||
if types.IsBool(value) {
|
||||
return value
|
||||
}
|
||||
return types.True
|
||||
}
|
||||
|
||||
func inAggregate(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
if rhs.Type().HasTrait(traits.ContainerType) {
|
||||
return rhs.(traits.Container).Contains(lhs)
|
||||
}
|
||||
return types.ValOrErr(rhs, "no such overload")
|
||||
}
|
||||
1204
vendor/github.com/google/cel-go/interpreter/interpretable.go
generated
vendored
Normal file
1204
vendor/github.com/google/cel-go/interpreter/interpretable.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
137
vendor/github.com/google/cel-go/interpreter/interpreter.go
generated
vendored
Normal file
137
vendor/github.com/google/cel-go/interpreter/interpreter.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2018 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 provides functions to evaluate parsed expressions with
|
||||
// the option to augment the evaluation with inputs and functions supplied at
|
||||
// evaluation time.
|
||||
package interpreter
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/interpreter/functions"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Interpreter generates a new Interpretable from a checked or unchecked expression.
|
||||
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)
|
||||
|
||||
// NewUncheckedInterpretable returns an Interpretable from a parsed expression
|
||||
// and an optional list of InterpretableDecorator values.
|
||||
NewUncheckedInterpretable(expr *exprpb.Expr,
|
||||
decorators ...InterpretableDecorator) (Interpretable, error)
|
||||
}
|
||||
|
||||
// TrackState decorates each expression node with an observer which records the value
|
||||
// associated with the given expression id. EvalState must be provided to the decorator.
|
||||
// This decorator is not thread-safe, and the EvalState must be reset between Eval()
|
||||
// calls.
|
||||
func TrackState(state EvalState) InterpretableDecorator {
|
||||
observer := func(id int64, val ref.Val) {
|
||||
state.SetValue(id, val)
|
||||
}
|
||||
return decObserveEval(observer)
|
||||
}
|
||||
|
||||
// ExhaustiveEval replaces operations that short-circuit with versions that evaluate
|
||||
// expressions and couples this behavior with the TrackState() decorator to provide
|
||||
// insight into the evaluation state of the entire expression. EvalState must be
|
||||
// provided to the decorator. This decorator is not thread-safe, and the EvalState
|
||||
// must be reset between Eval() calls.
|
||||
func ExhaustiveEval(state EvalState) InterpretableDecorator {
|
||||
ex := decDisableShortcircuits()
|
||||
obs := TrackState(state)
|
||||
return func(i Interpretable) (Interpretable, error) {
|
||||
var err error
|
||||
i, err = ex(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return obs(i)
|
||||
}
|
||||
}
|
||||
|
||||
// Optimize will pre-compute operations such as list and map construction and optimize
|
||||
// call arguments to set membership tests. The set of optimizations will increase over time.
|
||||
func Optimize() InterpretableDecorator {
|
||||
return decOptimize()
|
||||
}
|
||||
|
||||
type exprInterpreter struct {
|
||||
dispatcher Dispatcher
|
||||
container *containers.Container
|
||||
provider ref.TypeProvider
|
||||
adapter ref.TypeAdapter
|
||||
attrFactory AttributeFactory
|
||||
}
|
||||
|
||||
// NewInterpreter builds an Interpreter from a Dispatcher and TypeProvider which will be used
|
||||
// throughout the Eval of all Interpretable instances gerenated from it.
|
||||
func NewInterpreter(dispatcher Dispatcher,
|
||||
container *containers.Container,
|
||||
provider ref.TypeProvider,
|
||||
adapter ref.TypeAdapter,
|
||||
attrFactory AttributeFactory) Interpreter {
|
||||
return &exprInterpreter{
|
||||
dispatcher: dispatcher,
|
||||
container: container,
|
||||
provider: provider,
|
||||
adapter: adapter,
|
||||
attrFactory: attrFactory}
|
||||
}
|
||||
|
||||
// NewStandardInterpreter builds a Dispatcher and TypeProvider with support for all of the CEL
|
||||
// builtins defined in the language definition.
|
||||
func NewStandardInterpreter(container *containers.Container,
|
||||
provider ref.TypeProvider,
|
||||
adapter ref.TypeAdapter,
|
||||
resolver AttributeFactory) Interpreter {
|
||||
dispatcher := NewDispatcher()
|
||||
dispatcher.Add(functions.StandardOverloads()...)
|
||||
return NewInterpreter(dispatcher, container, provider, adapter, resolver)
|
||||
}
|
||||
|
||||
// NewIntepretable implements the Interpreter interface method.
|
||||
func (i *exprInterpreter) NewInterpretable(
|
||||
checked *exprpb.CheckedExpr,
|
||||
decorators ...InterpretableDecorator) (Interpretable, error) {
|
||||
p := newPlanner(
|
||||
i.dispatcher,
|
||||
i.provider,
|
||||
i.adapter,
|
||||
i.attrFactory,
|
||||
i.container,
|
||||
checked,
|
||||
decorators...)
|
||||
return p.Plan(checked.GetExpr())
|
||||
}
|
||||
|
||||
// NewUncheckedIntepretable implements the Interpreter interface method.
|
||||
func (i *exprInterpreter) NewUncheckedInterpretable(
|
||||
expr *exprpb.Expr,
|
||||
decorators ...InterpretableDecorator) (Interpretable, error) {
|
||||
p := newUncheckedPlanner(
|
||||
i.dispatcher,
|
||||
i.provider,
|
||||
i.adapter,
|
||||
i.attrFactory,
|
||||
i.container,
|
||||
decorators...)
|
||||
return p.Plan(expr)
|
||||
}
|
||||
773
vendor/github.com/google/cel-go/interpreter/planner.go
generated
vendored
Normal file
773
vendor/github.com/google/cel-go/interpreter/planner.go
generated
vendored
Normal file
@@ -0,0 +1,773 @@
|
||||
// Copyright 2018 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 (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"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"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// interpretablePlanner creates an Interpretable evaluation plan from a proto Expr value.
|
||||
type interpretablePlanner interface {
|
||||
// Plan generates an Interpretable value (or error) from the input proto Expr.
|
||||
Plan(expr *exprpb.Expr) (Interpretable, error)
|
||||
}
|
||||
|
||||
// newPlanner creates an interpretablePlanner which references a Dispatcher, TypeProvider,
|
||||
// TypeAdapter, Container, and CheckedExpr value. These pieces of data are used to resolve
|
||||
// functions, types, and namespaced identifiers at plan time rather than at runtime since
|
||||
// it only needs to be done once and may be semi-expensive to compute.
|
||||
func newPlanner(disp Dispatcher,
|
||||
provider ref.TypeProvider,
|
||||
adapter ref.TypeAdapter,
|
||||
attrFactory AttributeFactory,
|
||||
cont *containers.Container,
|
||||
checked *exprpb.CheckedExpr,
|
||||
decorators ...InterpretableDecorator) interpretablePlanner {
|
||||
return &planner{
|
||||
disp: disp,
|
||||
provider: provider,
|
||||
adapter: adapter,
|
||||
attrFactory: attrFactory,
|
||||
container: cont,
|
||||
refMap: checked.GetReferenceMap(),
|
||||
typeMap: checked.GetTypeMap(),
|
||||
decorators: decorators,
|
||||
}
|
||||
}
|
||||
|
||||
// newUncheckedPlanner creates an interpretablePlanner which references a Dispatcher, TypeProvider,
|
||||
// TypeAdapter, and Container to resolve functions and types at plan time. Namespaces present in
|
||||
// Select expressions are resolved lazily at evaluation time.
|
||||
func newUncheckedPlanner(disp Dispatcher,
|
||||
provider ref.TypeProvider,
|
||||
adapter ref.TypeAdapter,
|
||||
attrFactory AttributeFactory,
|
||||
cont *containers.Container,
|
||||
decorators ...InterpretableDecorator) interpretablePlanner {
|
||||
return &planner{
|
||||
disp: disp,
|
||||
provider: provider,
|
||||
adapter: adapter,
|
||||
attrFactory: attrFactory,
|
||||
container: cont,
|
||||
refMap: make(map[int64]*exprpb.Reference),
|
||||
typeMap: make(map[int64]*exprpb.Type),
|
||||
decorators: decorators,
|
||||
}
|
||||
}
|
||||
|
||||
// planner is an implementatio of the interpretablePlanner interface.
|
||||
type planner struct {
|
||||
disp Dispatcher
|
||||
provider ref.TypeProvider
|
||||
adapter ref.TypeAdapter
|
||||
attrFactory AttributeFactory
|
||||
container *containers.Container
|
||||
refMap map[int64]*exprpb.Reference
|
||||
typeMap map[int64]*exprpb.Type
|
||||
decorators []InterpretableDecorator
|
||||
}
|
||||
|
||||
// Plan implements the interpretablePlanner interface. This implementation of the Plan method also
|
||||
// applies decorators to each Interpretable generated as part of the overall plan. Decorators are
|
||||
// useful for layering functionality into the evaluation that is not natively understood by CEL,
|
||||
// such as state-tracking, expression re-write, and possibly efficient thread-safe memoization of
|
||||
// repeated expressions.
|
||||
func (p *planner) Plan(expr *exprpb.Expr) (Interpretable, error) {
|
||||
switch expr.ExprKind.(type) {
|
||||
case *exprpb.Expr_CallExpr:
|
||||
return p.decorate(p.planCall(expr))
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
return p.decorate(p.planIdent(expr))
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
return p.decorate(p.planSelect(expr))
|
||||
case *exprpb.Expr_ListExpr:
|
||||
return p.decorate(p.planCreateList(expr))
|
||||
case *exprpb.Expr_StructExpr:
|
||||
return p.decorate(p.planCreateStruct(expr))
|
||||
case *exprpb.Expr_ComprehensionExpr:
|
||||
return p.decorate(p.planComprehension(expr))
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
return p.decorate(p.planConst(expr))
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported expr: %v", expr)
|
||||
}
|
||||
|
||||
// decorate applies the InterpretableDecorator functions to the given Interpretable.
|
||||
// Both the Interpretable and error generated by a Plan step are accepted as arguments
|
||||
// for convenience.
|
||||
func (p *planner) decorate(i Interpretable, err error) (Interpretable, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, dec := range p.decorators {
|
||||
i, err = dec(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// planIdent creates an Interpretable that resolves an identifier from an Activation.
|
||||
func (p *planner) planIdent(expr *exprpb.Expr) (Interpretable, error) {
|
||||
// Establish whether the identifier is in the reference map.
|
||||
if identRef, found := p.refMap[expr.GetId()]; found {
|
||||
return p.planCheckedIdent(expr.GetId(), identRef)
|
||||
}
|
||||
// Create the possible attribute list for the unresolved reference.
|
||||
ident := expr.GetIdentExpr()
|
||||
return &evalAttr{
|
||||
adapter: p.adapter,
|
||||
attr: p.attrFactory.MaybeAttribute(expr.GetId(), ident.Name),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *planner) planCheckedIdent(id int64, identRef *exprpb.Reference) (Interpretable, error) {
|
||||
// Plan a constant reference if this is the case for this simple identifier.
|
||||
if identRef.Value != nil {
|
||||
return p.Plan(&exprpb.Expr{Id: id,
|
||||
ExprKind: &exprpb.Expr_ConstExpr{
|
||||
ConstExpr: identRef.Value,
|
||||
}})
|
||||
}
|
||||
|
||||
// Check to see whether the type map indicates this is a type name. All types should be
|
||||
// registered with the provider.
|
||||
cType := p.typeMap[id]
|
||||
if cType.GetType() != nil {
|
||||
cVal, found := p.provider.FindIdent(identRef.Name)
|
||||
if !found {
|
||||
return nil, fmt.Errorf("reference to undefined type: %s", identRef.Name)
|
||||
}
|
||||
return NewConstValue(id, cVal), nil
|
||||
}
|
||||
|
||||
// Otherwise, return the attribute for the resolved identifier name.
|
||||
return &evalAttr{
|
||||
adapter: p.adapter,
|
||||
attr: p.attrFactory.AbsoluteAttribute(id, identRef.Name),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planSelect creates an Interpretable with either:
|
||||
// a) selects a field from a map or proto.
|
||||
// b) creates a field presence test for a select within a has() macro.
|
||||
// c) resolves the select expression to a namespaced identifier.
|
||||
func (p *planner) planSelect(expr *exprpb.Expr) (Interpretable, error) {
|
||||
// If the Select id appears in the reference map from the CheckedExpr proto then it is either
|
||||
// a namespaced identifier or enum value.
|
||||
if identRef, found := p.refMap[expr.GetId()]; found {
|
||||
return p.planCheckedIdent(expr.GetId(), identRef)
|
||||
}
|
||||
|
||||
sel := expr.GetSelectExpr()
|
||||
// Plan the operand evaluation.
|
||||
op, err := p.Plan(sel.GetOperand())
|
||||
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.Field)
|
||||
if found && ft.IsSet != nil && ft.GetFrom != nil {
|
||||
fieldType = ft
|
||||
}
|
||||
}
|
||||
|
||||
// If the Select was marked TestOnly, this is a presence test.
|
||||
//
|
||||
// Note: presence tests are defined for structured (e.g. proto) and dynamic values (map, json)
|
||||
// as follows:
|
||||
// - True if the object field has a non-default value, e.g. obj.str != ""
|
||||
// - True if the dynamic value has the field defined, e.g. key in map
|
||||
//
|
||||
// However, presence tests are not defined for qualified identifier names with primitive types.
|
||||
// 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.Id,
|
||||
field: types.String(sel.Field),
|
||||
fieldType: fieldType,
|
||||
op: op,
|
||||
}, nil
|
||||
}
|
||||
// Build a qualifier.
|
||||
qual, err := p.attrFactory.NewQualifier(
|
||||
opType, expr.Id, sel.Field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Lastly, create a field selection Interpretable.
|
||||
attr, isAttr := op.(InterpretableAttribute)
|
||||
if isAttr {
|
||||
_, err = attr.AddQualifier(qual)
|
||||
return attr, err
|
||||
}
|
||||
|
||||
relAttr, err := p.relativeAttr(op.ID(), op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = relAttr.AddQualifier(qual)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return relAttr, nil
|
||||
}
|
||||
|
||||
// planCall creates a callable Interpretable while specializing for common functions and invocation
|
||||
// patterns. Specifically, conditional operators &&, ||, ?:, and (in)equality functions result in
|
||||
// optimized Interpretable values.
|
||||
func (p *planner) planCall(expr *exprpb.Expr) (Interpretable, error) {
|
||||
call := expr.GetCallExpr()
|
||||
target, fnName, oName := p.resolveFunction(expr)
|
||||
argCount := len(call.GetArgs())
|
||||
var offset int
|
||||
if target != nil {
|
||||
argCount++
|
||||
offset++
|
||||
}
|
||||
|
||||
args := make([]Interpretable, argCount)
|
||||
if target != nil {
|
||||
arg, err := p.Plan(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args[0] = arg
|
||||
}
|
||||
for i, argExpr := range call.GetArgs() {
|
||||
arg, err := p.Plan(argExpr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args[i+offset] = arg
|
||||
}
|
||||
|
||||
// Generate specialized Interpretable operators by function name if possible.
|
||||
switch fnName {
|
||||
case operators.LogicalAnd:
|
||||
return p.planCallLogicalAnd(expr, args)
|
||||
case operators.LogicalOr:
|
||||
return p.planCallLogicalOr(expr, args)
|
||||
case operators.Conditional:
|
||||
return p.planCallConditional(expr, args)
|
||||
case operators.Equals:
|
||||
return p.planCallEqual(expr, args)
|
||||
case operators.NotEquals:
|
||||
return p.planCallNotEqual(expr, args)
|
||||
case operators.Index:
|
||||
return p.planCallIndex(expr, args)
|
||||
}
|
||||
|
||||
// Otherwise, generate Interpretable calls specialized by argument count.
|
||||
// Try to find the specific function by overload id.
|
||||
var fnDef *functions.Overload
|
||||
if oName != "" {
|
||||
fnDef, _ = p.disp.FindOverload(oName)
|
||||
}
|
||||
// If the overload id couldn't resolve the function, try the simple function name.
|
||||
if fnDef == nil {
|
||||
fnDef, _ = p.disp.FindOverload(fnName)
|
||||
}
|
||||
switch argCount {
|
||||
case 0:
|
||||
return p.planCallZero(expr, fnName, oName, fnDef)
|
||||
case 1:
|
||||
return p.planCallUnary(expr, fnName, oName, fnDef, args)
|
||||
case 2:
|
||||
return p.planCallBinary(expr, fnName, oName, fnDef, args)
|
||||
default:
|
||||
return p.planCallVarArgs(expr, fnName, oName, fnDef, args)
|
||||
}
|
||||
}
|
||||
|
||||
// planCallZero generates a zero-arity callable Interpretable.
|
||||
func (p *planner) planCallZero(expr *exprpb.Expr,
|
||||
function string,
|
||||
overload string,
|
||||
impl *functions.Overload) (Interpretable, error) {
|
||||
if impl == nil || impl.Function == nil {
|
||||
return nil, fmt.Errorf("no such overload: %s()", function)
|
||||
}
|
||||
return &evalZeroArity{
|
||||
id: expr.Id,
|
||||
function: function,
|
||||
overload: overload,
|
||||
impl: impl.Function,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCallUnary generates a unary callable Interpretable.
|
||||
func (p *planner) planCallUnary(expr *exprpb.Expr,
|
||||
function string,
|
||||
overload string,
|
||||
impl *functions.Overload,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
var fn functions.UnaryOp
|
||||
var trait int
|
||||
if impl != nil {
|
||||
if impl.Unary == nil {
|
||||
return nil, fmt.Errorf("no such overload: %s(arg)", function)
|
||||
}
|
||||
fn = impl.Unary
|
||||
trait = impl.OperandTrait
|
||||
}
|
||||
return &evalUnary{
|
||||
id: expr.Id,
|
||||
function: function,
|
||||
overload: overload,
|
||||
arg: args[0],
|
||||
trait: trait,
|
||||
impl: fn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCallBinary generates a binary callable Interpretable.
|
||||
func (p *planner) planCallBinary(expr *exprpb.Expr,
|
||||
function string,
|
||||
overload string,
|
||||
impl *functions.Overload,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
var fn functions.BinaryOp
|
||||
var trait int
|
||||
if impl != nil {
|
||||
if impl.Binary == nil {
|
||||
return nil, fmt.Errorf("no such overload: %s(lhs, rhs)", function)
|
||||
}
|
||||
fn = impl.Binary
|
||||
trait = impl.OperandTrait
|
||||
}
|
||||
return &evalBinary{
|
||||
id: expr.Id,
|
||||
function: function,
|
||||
overload: overload,
|
||||
lhs: args[0],
|
||||
rhs: args[1],
|
||||
trait: trait,
|
||||
impl: fn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCallVarArgs generates a variable argument callable Interpretable.
|
||||
func (p *planner) planCallVarArgs(expr *exprpb.Expr,
|
||||
function string,
|
||||
overload string,
|
||||
impl *functions.Overload,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
var fn functions.FunctionOp
|
||||
var trait int
|
||||
if impl != nil {
|
||||
if impl.Function == nil {
|
||||
return nil, fmt.Errorf("no such overload: %s(...)", function)
|
||||
}
|
||||
fn = impl.Function
|
||||
trait = impl.OperandTrait
|
||||
}
|
||||
return &evalVarArgs{
|
||||
id: expr.Id,
|
||||
function: function,
|
||||
overload: overload,
|
||||
args: args,
|
||||
trait: trait,
|
||||
impl: fn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCallEqual generates an equals (==) Interpretable.
|
||||
func (p *planner) planCallEqual(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
return &evalEq{
|
||||
id: expr.Id,
|
||||
lhs: args[0],
|
||||
rhs: args[1],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCallNotEqual generates a not equals (!=) Interpretable.
|
||||
func (p *planner) planCallNotEqual(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
return &evalNe{
|
||||
id: expr.Id,
|
||||
lhs: args[0],
|
||||
rhs: args[1],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCallLogicalAnd generates a logical and (&&) Interpretable.
|
||||
func (p *planner) planCallLogicalAnd(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
return &evalAnd{
|
||||
id: expr.Id,
|
||||
lhs: args[0],
|
||||
rhs: args[1],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCallLogicalOr generates a logical or (||) Interpretable.
|
||||
func (p *planner) planCallLogicalOr(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
return &evalOr{
|
||||
id: expr.Id,
|
||||
lhs: args[0],
|
||||
rhs: args[1],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCallConditional generates a conditional / ternary (c ? t : f) Interpretable.
|
||||
func (p *planner) planCallConditional(expr *exprpb.Expr,
|
||||
args []Interpretable) (Interpretable, error) {
|
||||
cond := args[0]
|
||||
|
||||
t := args[1]
|
||||
var tAttr Attribute
|
||||
truthyAttr, isTruthyAttr := t.(InterpretableAttribute)
|
||||
if isTruthyAttr {
|
||||
tAttr = truthyAttr.Attr()
|
||||
} else {
|
||||
tAttr = p.attrFactory.RelativeAttribute(t.ID(), t)
|
||||
}
|
||||
|
||||
f := args[2]
|
||||
var fAttr Attribute
|
||||
falsyAttr, isFalsyAttr := f.(InterpretableAttribute)
|
||||
if isFalsyAttr {
|
||||
fAttr = falsyAttr.Attr()
|
||||
} else {
|
||||
fAttr = p.attrFactory.RelativeAttribute(f.ID(), f)
|
||||
}
|
||||
|
||||
return &evalAttr{
|
||||
adapter: p.adapter,
|
||||
attr: p.attrFactory.ConditionalAttribute(expr.Id, cond, tAttr, fAttr),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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())
|
||||
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
|
||||
}
|
||||
indQual, err := p.relativeAttr(expr.GetId(), ind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = opAttr.AddQualifier(indQual)
|
||||
return opAttr, 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() {
|
||||
elemVal, err := p.Plan(elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elems[i] = elemVal
|
||||
}
|
||||
return &evalList{
|
||||
id: expr.Id,
|
||||
elems: elems,
|
||||
adapter: p.adapter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planCreateStruct generates a map or object construction Interpretable.
|
||||
func (p *planner) planCreateStruct(expr *exprpb.Expr) (Interpretable, error) {
|
||||
str := expr.GetStructExpr()
|
||||
if len(str.MessageName) != 0 {
|
||||
return p.planCreateObj(expr)
|
||||
}
|
||||
entries := str.GetEntries()
|
||||
keys := make([]Interpretable, len(entries))
|
||||
vals := make([]Interpretable, len(entries))
|
||||
for i, entry := range entries {
|
||||
keyVal, err := p.Plan(entry.GetMapKey())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys[i] = keyVal
|
||||
|
||||
valVal, err := p.Plan(entry.GetValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vals[i] = valVal
|
||||
}
|
||||
return &evalMap{
|
||||
id: expr.Id,
|
||||
keys: keys,
|
||||
vals: vals,
|
||||
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)
|
||||
if !defined {
|
||||
return nil, fmt.Errorf("unknown type: %s", typeName)
|
||||
}
|
||||
entries := obj.GetEntries()
|
||||
fields := make([]string, len(entries))
|
||||
vals := make([]Interpretable, len(entries))
|
||||
for i, entry := range entries {
|
||||
fields[i] = entry.GetFieldKey()
|
||||
val, err := p.Plan(entry.GetValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vals[i] = val
|
||||
}
|
||||
return &evalObj{
|
||||
id: expr.Id,
|
||||
typeName: typeName,
|
||||
fields: fields,
|
||||
vals: vals,
|
||||
provider: p.provider,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planComprehension generates an Interpretable fold operation.
|
||||
func (p *planner) planComprehension(expr *exprpb.Expr) (Interpretable, error) {
|
||||
fold := expr.GetComprehensionExpr()
|
||||
accu, err := p.Plan(fold.GetAccuInit())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iterRange, err := p.Plan(fold.GetIterRange())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cond, err := p.Plan(fold.GetLoopCondition())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
step, err := p.Plan(fold.GetLoopStep())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := p.Plan(fold.GetResult())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &evalFold{
|
||||
id: expr.Id,
|
||||
accuVar: fold.AccuVar,
|
||||
accu: accu,
|
||||
iterVar: fold.IterVar,
|
||||
iterRange: iterRange,
|
||||
cond: cond,
|
||||
step: step,
|
||||
result: result,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// planConst generates a constant valued Interpretable.
|
||||
func (p *planner) planConst(expr *exprpb.Expr) (Interpretable, error) {
|
||||
val, err := p.constValue(expr.GetConstExpr())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewConstValue(expr.Id, val), nil
|
||||
}
|
||||
|
||||
// constValue converts a proto Constant value to a ref.Val.
|
||||
func (p *planner) constValue(c *exprpb.Constant) (ref.Val, error) {
|
||||
switch c.ConstantKind.(type) {
|
||||
case *exprpb.Constant_BoolValue:
|
||||
return p.adapter.NativeToValue(c.GetBoolValue()), nil
|
||||
case *exprpb.Constant_BytesValue:
|
||||
return p.adapter.NativeToValue(c.GetBytesValue()), nil
|
||||
case *exprpb.Constant_DoubleValue:
|
||||
return p.adapter.NativeToValue(c.GetDoubleValue()), nil
|
||||
case *exprpb.Constant_DurationValue:
|
||||
return p.adapter.NativeToValue(c.GetDurationValue().AsDuration()), nil
|
||||
case *exprpb.Constant_Int64Value:
|
||||
return p.adapter.NativeToValue(c.GetInt64Value()), nil
|
||||
case *exprpb.Constant_NullValue:
|
||||
return p.adapter.NativeToValue(c.GetNullValue()), nil
|
||||
case *exprpb.Constant_StringValue:
|
||||
return p.adapter.NativeToValue(c.GetStringValue()), nil
|
||||
case *exprpb.Constant_TimestampValue:
|
||||
return p.adapter.NativeToValue(c.GetTimestampValue().AsTime()), nil
|
||||
case *exprpb.Constant_Uint64Value:
|
||||
return p.adapter.NativeToValue(c.GetUint64Value()), nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown constant type: %v", c)
|
||||
}
|
||||
|
||||
// resolveTypeName takes a qualified string constructed at parse time, applies the proto
|
||||
// namespace resolution rules to it in a scan over possible matching types in the TypeProvider.
|
||||
func (p *planner) resolveTypeName(typeName string) (string, bool) {
|
||||
for _, qualifiedTypeName := range p.container.ResolveCandidateNames(typeName) {
|
||||
if _, found := p.provider.FindType(qualifiedTypeName); found {
|
||||
return qualifiedTypeName, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// resolveFunction determines the call target, function name, and overload name from a given Expr
|
||||
// value.
|
||||
//
|
||||
// The resolveFunction resolves ambiguities where a function may either be a receiver-style
|
||||
// invocation or a qualified global function name.
|
||||
// - The target expression may only consist of ident and select expressions.
|
||||
// - The function is declared in the environment using its fully-qualified name.
|
||||
// - The fully-qualified function name matches the string serialized target value.
|
||||
func (p *planner) resolveFunction(expr *exprpb.Expr) (*exprpb.Expr, string, string) {
|
||||
// Note: similar logic exists within the `checker/checker.go`. If making changes here
|
||||
// please consider the impact on checker.go and consolidate implementations or mirror code
|
||||
// as appropriate.
|
||||
call := expr.GetCallExpr()
|
||||
target := call.GetTarget()
|
||||
fnName := call.GetFunction()
|
||||
|
||||
// Checked expressions always have a reference map entry, and _should_ have the fully qualified
|
||||
// function name as the fnName value.
|
||||
oRef, hasOverload := p.refMap[expr.GetId()]
|
||||
if hasOverload {
|
||||
if len(oRef.GetOverloadId()) == 1 {
|
||||
return target, fnName, oRef.GetOverloadId()[0]
|
||||
}
|
||||
// Note, this namespaced function name will not appear as a fully qualified name in ASTs
|
||||
// built and stored before cel-go v0.5.0; however, this functionality did not work at all
|
||||
// before the v0.5.0 release.
|
||||
return target, fnName, ""
|
||||
}
|
||||
|
||||
// Parse-only expressions need to handle the same logic as is normally performed at check time,
|
||||
// but with potentially much less information. The only reliable source of information about
|
||||
// which functions are configured is the dispatcher.
|
||||
if target == nil {
|
||||
// If the user has a parse-only expression, then it should have been configured as such in
|
||||
// the interpreter dispatcher as it may have been omitted from the checker environment.
|
||||
for _, qualifiedName := range p.container.ResolveCandidateNames(fnName) {
|
||||
_, found := p.disp.FindOverload(qualifiedName)
|
||||
if found {
|
||||
return nil, qualifiedName, ""
|
||||
}
|
||||
}
|
||||
// It's possible that the overload was not found, but this situation is accounted for in
|
||||
// the planCall phase; however, the leading dot used for denoting fully-qualified
|
||||
// namespaced identifiers must be stripped, as all declarations already use fully-qualified
|
||||
// names. This stripping behavior is handled automatically by the ResolveCandidateNames
|
||||
// call.
|
||||
return target, stripLeadingDot(fnName), ""
|
||||
}
|
||||
|
||||
// Handle the situation where the function target actually indicates a qualified function name.
|
||||
qualifiedPrefix, maybeQualified := p.toQualifiedName(target)
|
||||
if maybeQualified {
|
||||
maybeQualifiedName := qualifiedPrefix + "." + fnName
|
||||
for _, qualifiedName := range p.container.ResolveCandidateNames(maybeQualifiedName) {
|
||||
_, found := p.disp.FindOverload(qualifiedName)
|
||||
if found {
|
||||
// Clear the target to ensure the proper arity is used for finding the
|
||||
// implementation.
|
||||
return nil, qualifiedName, ""
|
||||
}
|
||||
}
|
||||
}
|
||||
// In the default case, the function is exactly as it was advertised: a receiver call on with
|
||||
// an expression-based target with the given simple function name.
|
||||
return target, fnName, ""
|
||||
}
|
||||
|
||||
func (p *planner) relativeAttr(id int64, eval Interpretable) (InterpretableAttribute, error) {
|
||||
eAttr, ok := eval.(InterpretableAttribute)
|
||||
if !ok {
|
||||
eAttr = &evalAttr{
|
||||
adapter: p.adapter,
|
||||
attr: p.attrFactory.RelativeAttribute(id, eval),
|
||||
}
|
||||
}
|
||||
decAttr, err := p.decorate(eAttr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eAttr, ok = decAttr.(InterpretableAttribute)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid attribute decoration: %v(%T)", decAttr, decAttr)
|
||||
}
|
||||
return eAttr, nil
|
||||
}
|
||||
|
||||
// toQualifiedName converts an expression AST into a qualified name if possible, with a boolean
|
||||
// 'found' value that indicates if the conversion is successful.
|
||||
func (p *planner) toQualifiedName(operand *exprpb.Expr) (string, bool) {
|
||||
// If the checker identified the expression as an attribute by the type-checker, then it can't
|
||||
// possibly be part of qualified name in a namespace.
|
||||
_, isAttr := p.refMap[operand.GetId()]
|
||||
if isAttr {
|
||||
return "", false
|
||||
}
|
||||
// Since functions cannot be both namespaced and receiver functions, if the operand is not an
|
||||
// qualified variable name, return the (possibly) qualified name given the expressions.
|
||||
return containers.ToQualifiedName(operand)
|
||||
}
|
||||
|
||||
func stripLeadingDot(name string) string {
|
||||
if strings.HasPrefix(name, ".") {
|
||||
return name[1:]
|
||||
}
|
||||
return name
|
||||
}
|
||||
391
vendor/github.com/google/cel-go/interpreter/prune.go
generated
vendored
Normal file
391
vendor/github.com/google/cel-go/interpreter/prune.go
generated
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
// Copyright 2018 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 (
|
||||
"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/common/types/traits"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
type astPruner struct {
|
||||
expr *exprpb.Expr
|
||||
state EvalState
|
||||
nextExprID int64
|
||||
}
|
||||
|
||||
// TODO Consider having a separate walk of the AST that finds common
|
||||
// subexpressions. This can be called before or after constant folding to find
|
||||
// common subexpressions.
|
||||
|
||||
// PruneAst prunes the given AST based on the given EvalState and generates a new AST.
|
||||
// Given AST is copied on write and a new AST is returned.
|
||||
// Couple of typical use cases this interface would be:
|
||||
//
|
||||
// A)
|
||||
// 1) Evaluate expr with some unknowns,
|
||||
// 2) If result is unknown:
|
||||
// a) PruneAst
|
||||
// b) Goto 1
|
||||
// Functional call results which are known would be effectively cached across
|
||||
// iterations.
|
||||
//
|
||||
// B)
|
||||
// 1) Compile the expression (maybe via a service and maybe after checking a
|
||||
// compiled expression does not exists in local cache)
|
||||
// 2) Prepare the environment and the interpreter. Activation might be empty.
|
||||
// 3) Eval the expression. This might return unknown or error or a concrete
|
||||
// value.
|
||||
// 4) PruneAst
|
||||
// 4) Maybe cache the expression
|
||||
// This is effectively constant folding the expression. How the environment is
|
||||
// prepared in step 2 is flexible. For example, If the caller caches the
|
||||
// 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 {
|
||||
pruner := &astPruner{
|
||||
expr: expr,
|
||||
state: state,
|
||||
nextExprID: 1}
|
||||
newExpr, _ := pruner.prune(expr)
|
||||
return newExpr
|
||||
}
|
||||
|
||||
func (p *astPruner) createLiteral(id int64, val *exprpb.Constant) *exprpb.Expr {
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_ConstExpr{
|
||||
ConstExpr: val,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *astPruner) maybeCreateLiteral(id int64, val ref.Val) (*exprpb.Expr, bool) {
|
||||
switch val.Type() {
|
||||
case types.BoolType:
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_BoolValue{BoolValue: val.Value().(bool)}}), true
|
||||
case types.IntType:
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_Int64Value{Int64Value: val.Value().(int64)}}), true
|
||||
case types.UintType:
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_Uint64Value{Uint64Value: val.Value().(uint64)}}), true
|
||||
case types.StringType:
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_StringValue{StringValue: val.Value().(string)}}), true
|
||||
case types.DoubleType:
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_DoubleValue{DoubleValue: val.Value().(float64)}}), true
|
||||
case types.BytesType:
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_BytesValue{BytesValue: val.Value().([]byte)}}), true
|
||||
case types.NullType:
|
||||
return p.createLiteral(id,
|
||||
&exprpb.Constant{ConstantKind: &exprpb.Constant_NullValue{NullValue: val.Value().(structpb.NullValue)}}), true
|
||||
}
|
||||
|
||||
// Attempt to build a list literal.
|
||||
if list, isList := val.(traits.Lister); isList {
|
||||
sz := list.Size().(types.Int)
|
||||
elemExprs := make([]*exprpb.Expr, sz)
|
||||
for i := types.Int(0); i < sz; i++ {
|
||||
elem := list.Get(i)
|
||||
if types.IsUnknownOrError(elem) {
|
||||
return nil, false
|
||||
}
|
||||
elemExpr, ok := p.maybeCreateLiteral(p.nextID(), elem)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
elemExprs[i] = elemExpr
|
||||
}
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_ListExpr{
|
||||
ListExpr: &exprpb.Expr_CreateList{
|
||||
Elements: elemExprs,
|
||||
},
|
||||
},
|
||||
}, true
|
||||
}
|
||||
|
||||
// Create a map literal if possible.
|
||||
if mp, isMap := val.(traits.Mapper); isMap {
|
||||
it := mp.Iterator()
|
||||
entries := make([]*exprpb.Expr_CreateStruct_Entry, mp.Size().(types.Int))
|
||||
i := 0
|
||||
for it.HasNext() != types.False {
|
||||
key := it.Next()
|
||||
val := mp.Get(key)
|
||||
if types.IsUnknownOrError(key) || types.IsUnknownOrError(val) {
|
||||
return nil, false
|
||||
}
|
||||
keyExpr, ok := p.maybeCreateLiteral(p.nextID(), key)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
valExpr, ok := p.maybeCreateLiteral(p.nextID(), val)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
entry := &exprpb.Expr_CreateStruct_Entry{
|
||||
Id: p.nextID(),
|
||||
KeyKind: &exprpb.Expr_CreateStruct_Entry_MapKey{
|
||||
MapKey: keyExpr,
|
||||
},
|
||||
Value: valExpr,
|
||||
}
|
||||
entries[i] = entry
|
||||
i++
|
||||
}
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_StructExpr{
|
||||
StructExpr: &exprpb.Expr_CreateStruct{
|
||||
Entries: entries,
|
||||
},
|
||||
},
|
||||
}, true
|
||||
}
|
||||
|
||||
// TODO(issues/377) To construct message literals, the type provider will need to support
|
||||
// the enumeration the fields for a given message.
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePruneAndOr(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
if !p.existsWithUnknownValue(node.GetId()) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
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 p.existsWithKnownValue(call.Args[1].GetId()) {
|
||||
return call.Args[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) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if condVal.Value().(bool) {
|
||||
return call.Args[1], true
|
||||
}
|
||||
return call.Args[2], true
|
||||
}
|
||||
|
||||
func (p *astPruner) maybePruneFunction(node *exprpb.Expr) (*exprpb.Expr, bool) {
|
||||
call := node.GetCallExpr()
|
||||
if call.Function == operators.LogicalOr || call.Function == operators.LogicalAnd {
|
||||
return p.maybePruneAndOr(node)
|
||||
}
|
||||
if call.Function == operators.Conditional {
|
||||
return p.maybePruneConditional(node)
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
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) {
|
||||
if newNode, ok := p.maybeCreateLiteral(node.GetId(), val); ok {
|
||||
return newNode, true
|
||||
}
|
||||
}
|
||||
|
||||
// We have either an unknown/error value, or something we dont want to
|
||||
// transform, or expression was not evaluated. If possible, drill down
|
||||
// more.
|
||||
|
||||
switch node.ExprKind.(type) {
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
if operand, pruned := p.prune(node.GetSelectExpr().Operand); pruned {
|
||||
return &exprpb.Expr{
|
||||
Id: node.GetId(),
|
||||
ExprKind: &exprpb.Expr_SelectExpr{
|
||||
SelectExpr: &exprpb.Expr_Select{
|
||||
Operand: operand,
|
||||
Field: node.GetSelectExpr().GetField(),
|
||||
TestOnly: node.GetSelectExpr().GetTestOnly(),
|
||||
},
|
||||
},
|
||||
}, 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()
|
||||
newArgs := make([]*exprpb.Expr, len(args))
|
||||
newCall := &exprpb.Expr_Call{
|
||||
Function: call.GetFunction(),
|
||||
Target: call.GetTarget(),
|
||||
Args: newArgs,
|
||||
}
|
||||
for i, arg := range args {
|
||||
newArgs[i] = arg
|
||||
if newArg, prunedArg := p.prune(arg); prunedArg {
|
||||
prunedCall = true
|
||||
newArgs[i] = newArg
|
||||
}
|
||||
}
|
||||
if newTarget, prunedTarget := p.prune(call.GetTarget()); prunedTarget {
|
||||
prunedCall = true
|
||||
newCall.Target = newTarget
|
||||
}
|
||||
if prunedCall {
|
||||
return &exprpb.Expr{
|
||||
Id: node.GetId(),
|
||||
ExprKind: &exprpb.Expr_CallExpr{
|
||||
CallExpr: newCall,
|
||||
},
|
||||
}, true
|
||||
}
|
||||
case *exprpb.Expr_ListExpr:
|
||||
elems := node.GetListExpr().GetElements()
|
||||
newElems := make([]*exprpb.Expr, len(elems))
|
||||
var prunedList bool
|
||||
for i, elem := range elems {
|
||||
newElems[i] = elem
|
||||
if newElem, prunedElem := p.prune(elem); prunedElem {
|
||||
newElems[i] = newElem
|
||||
prunedList = true
|
||||
}
|
||||
}
|
||||
if prunedList {
|
||||
return &exprpb.Expr{
|
||||
Id: node.GetId(),
|
||||
ExprKind: &exprpb.Expr_ListExpr{
|
||||
ListExpr: &exprpb.Expr_CreateList{
|
||||
Elements: newElems,
|
||||
},
|
||||
},
|
||||
}, true
|
||||
}
|
||||
case *exprpb.Expr_StructExpr:
|
||||
var prunedStruct bool
|
||||
entries := node.GetStructExpr().GetEntries()
|
||||
messageType := node.GetStructExpr().GetMessageName()
|
||||
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())
|
||||
if !prunedKey && !prunedValue {
|
||||
continue
|
||||
}
|
||||
prunedStruct = true
|
||||
newEntry := &exprpb.Expr_CreateStruct_Entry{
|
||||
Value: newValue,
|
||||
}
|
||||
if messageType != "" {
|
||||
newEntry.KeyKind = &exprpb.Expr_CreateStruct_Entry_FieldKey{
|
||||
FieldKey: entry.GetFieldKey(),
|
||||
}
|
||||
} else {
|
||||
newEntry.KeyKind = &exprpb.Expr_CreateStruct_Entry_MapKey{
|
||||
MapKey: newKey,
|
||||
}
|
||||
}
|
||||
newEntries[i] = newEntry
|
||||
}
|
||||
if prunedStruct {
|
||||
return &exprpb.Expr{
|
||||
Id: node.GetId(),
|
||||
ExprKind: &exprpb.Expr_StructExpr{
|
||||
StructExpr: &exprpb.Expr_CreateStruct{
|
||||
MessageName: messageType,
|
||||
Entries: newEntries,
|
||||
},
|
||||
},
|
||||
}, 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
|
||||
}
|
||||
|
||||
func (p *astPruner) value(id int64) (ref.Val, bool) {
|
||||
val, found := p.state.Value(id)
|
||||
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) nextID() int64 {
|
||||
for {
|
||||
_, found := p.state.Value(p.nextExprID)
|
||||
if !found {
|
||||
next := p.nextExprID
|
||||
p.nextExprID++
|
||||
return next
|
||||
}
|
||||
p.nextExprID++
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user