mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
rebase: bump k8s.io/kubernetes from 1.26.2 to 1.27.2
Bumps [k8s.io/kubernetes](https://github.com/kubernetes/kubernetes) from 1.26.2 to 1.27.2. - [Release notes](https://github.com/kubernetes/kubernetes/releases) - [Commits](https://github.com/kubernetes/kubernetes/compare/v1.26.2...v1.27.2) --- updated-dependencies: - dependency-name: k8s.io/kubernetes dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
mergify[bot]
parent
0e79135419
commit
07b05616a0
233
vendor/github.com/google/cel-go/LICENSE
generated
vendored
Normal file
233
vendor/github.com/google/cel-go/LICENSE
generated
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
|
||||
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.
|
||||
|
||||
===========================================================================
|
||||
The common/types/pb/equal.go modification of proto.Equal logic
|
||||
===========================================================================
|
||||
Copyright (c) 2018 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
76
vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
Normal file
76
vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
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",
|
||||
"decls.go",
|
||||
"env.go",
|
||||
"io.go",
|
||||
"library.go",
|
||||
"macro.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/overloads:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/pb:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"//common/types/traits:go_default_library",
|
||||
"//interpreter:go_default_library",
|
||||
"//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",
|
||||
"@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",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"cel_example_test.go",
|
||||
"cel_test.go",
|
||||
"decls_test.go",
|
||||
"env_test.go",
|
||||
"io_test.go",
|
||||
],
|
||||
data = [
|
||||
"//cel/testdata:gen_test_fds",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
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",
|
||||
"//test: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",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb: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
|
1179
vendor/github.com/google/cel-go/cel/decls.go
generated
vendored
Normal file
1179
vendor/github.com/google/cel-go/cel/decls.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
613
vendor/github.com/google/cel-go/cel/env.go
generated
vendored
Normal file
613
vendor/github.com/google/cel-go/cel/env.go
generated
vendored
Normal file
@ -0,0 +1,613 @@
|
||||
// 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"
|
||||
"fmt"
|
||||
"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 = 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 newline 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.
|
||||
//
|
||||
// Deprecated: use OutputType
|
||||
func (ast *Ast) ResultType() *exprpb.Type {
|
||||
if !ast.IsChecked() {
|
||||
return decls.Dyn
|
||||
}
|
||||
return ast.typeMap[ast.expr.GetId()]
|
||||
}
|
||||
|
||||
// OutputType returns the output type of the expression if the Ast has been type-checked, else
|
||||
// returns cel.DynType as the parse step cannot infer types.
|
||||
func (ast *Ast) OutputType() *Type {
|
||||
t, err := ExprTypeToType(ast.ResultType())
|
||||
if err != nil {
|
||||
return DynType
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// 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
|
||||
functions map[string]*functionDecl
|
||||
declarations []*exprpb.Decl
|
||||
macros []parser.Macro
|
||||
adapter ref.TypeAdapter
|
||||
provider ref.TypeProvider
|
||||
features map[int]bool
|
||||
appliedFeatures map[int]bool
|
||||
|
||||
// Internal parser representation
|
||||
prsr *parser.Parser
|
||||
|
||||
// Internal checker representation
|
||||
chk *checker.Env
|
||||
chkErr error
|
||||
chkOnce sync.Once
|
||||
chkOpts []checker.Option
|
||||
|
||||
// Program options tied to the environment
|
||||
progOpts []ProgramOption
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Extend the statically configured standard environment, disabling eager validation to ensure
|
||||
// the cost of setup for the environment is still just as cheap as it is in v0.11.x and earlier
|
||||
// releases. The user provided options can easily re-enable the eager validation as they are
|
||||
// processed after this default option.
|
||||
stdOpts := append([]EnvOption{EagerlyValidateDeclarations(false)}, opts...)
|
||||
env, err := getStdEnv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return env.Extend(stdOpts...)
|
||||
}
|
||||
|
||||
// NewCustomEnv creates a custom program environment which is not automatically configured with the
|
||||
// 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{},
|
||||
functions: map[string]*functionDecl{},
|
||||
macros: []parser.Macro{},
|
||||
Container: containers.DefaultContainer,
|
||||
adapter: registry,
|
||||
provider: registry,
|
||||
features: map[int]bool{},
|
||||
appliedFeatures: 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.
|
||||
err := e.initChecker()
|
||||
if err != 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 Source) (*Ast, *Issues) {
|
||||
ast, iss := e.ParseSource(src)
|
||||
if iss.Err() != nil {
|
||||
return nil, iss
|
||||
}
|
||||
checked, iss2 := e.Check(ast)
|
||||
if iss2.Err() != nil {
|
||||
return nil, iss2
|
||||
}
|
||||
return checked, iss2
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// The type-checker is configured with Declarations. The declarations may either be provided
|
||||
// as options which have not yet been validated, or may come from a previous checker instance
|
||||
// whose types have already been validated.
|
||||
chkOptsCopy := make([]checker.Option, len(e.chkOpts))
|
||||
copy(chkOptsCopy, e.chkOpts)
|
||||
|
||||
// Copy the declarations if needed.
|
||||
decsCopy := []*exprpb.Decl{}
|
||||
if e.chk != nil {
|
||||
// If the type-checker has already been instantiated, then the e.declarations have been
|
||||
// valdiated within the chk instance.
|
||||
chkOptsCopy = append(chkOptsCopy, checker.ValidatedDeclarations(e.chk))
|
||||
} else {
|
||||
// If the type-checker has not been instantiated, ensure the unvalidated declarations are
|
||||
// provided to the extended Env instance.
|
||||
decsCopy = make([]*exprpb.Decl, len(e.declarations))
|
||||
copy(decsCopy, e.declarations)
|
||||
}
|
||||
|
||||
// Copy macros and program options
|
||||
macsCopy := make([]parser.Macro, len(e.macros))
|
||||
progOptsCopy := make([]ProgramOption, len(e.progOpts))
|
||||
copy(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
|
||||
}
|
||||
appliedFeaturesCopy := make(map[int]bool, len(e.appliedFeatures))
|
||||
for k, v := range e.appliedFeatures {
|
||||
appliedFeaturesCopy[k] = v
|
||||
}
|
||||
funcsCopy := make(map[string]*functionDecl, len(e.functions))
|
||||
for k, v := range e.functions {
|
||||
funcsCopy[k] = v
|
||||
}
|
||||
|
||||
// TODO: functions copy needs to happen here.
|
||||
ext := &Env{
|
||||
Container: e.Container,
|
||||
declarations: decsCopy,
|
||||
functions: funcsCopy,
|
||||
macros: macsCopy,
|
||||
progOpts: progOptsCopy,
|
||||
adapter: adapter,
|
||||
features: featuresCopy,
|
||||
appliedFeatures: appliedFeaturesCopy,
|
||||
provider: provider,
|
||||
chkOpts: chkOptsCopy,
|
||||
}
|
||||
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 {
|
||||
enabled, has := e.features[flag]
|
||||
return has && enabled
|
||||
}
|
||||
|
||||
// Parse parses the input expression value `txt` to a Ast and/or a set of Issues.
|
||||
//
|
||||
// This form of Parse creates a Source value for the input `txt` and forwards to the
|
||||
// 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 Source) (*Ast, *Issues) {
|
||||
res, errs := e.prsr.Parse(src)
|
||||
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: 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// EstimateCost estimates the cost of a type checked CEL expression using the length estimates of input data and
|
||||
// extension functions provided by estimator.
|
||||
func (e *Env) EstimateCost(ast *Ast, estimator checker.CostEstimator) (checker.CostEstimate, error) {
|
||||
checked, err := AstToCheckedExpr(ast)
|
||||
if err != nil {
|
||||
return checker.CostEstimate{}, fmt.Errorf("EsimateCost could not inspect Ast: %v", err)
|
||||
}
|
||||
return checker.Cost(checked, estimator), nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// If the default UTC timezone fix has been enabled, make sure the library is configured
|
||||
if e.HasFeature(featureDefaultUTCTimeZone) {
|
||||
if _, found := e.appliedFeatures[featureDefaultUTCTimeZone]; !found {
|
||||
e, err = Lib(timeUTCLibrary{})(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// record that the feature has been applied since it will generate declarations
|
||||
// and functions which will be propagated on Extend() calls and which should only
|
||||
// be registered once.
|
||||
e.appliedFeatures[featureDefaultUTCTimeZone] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize all of the functions configured within the environment.
|
||||
for _, fn := range e.functions {
|
||||
err = fn.init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Configure the parser.
|
||||
prsrOpts := []parser.Option{parser.Macros(e.macros...)}
|
||||
if e.HasFeature(featureEnableMacroCallTracking) {
|
||||
prsrOpts = append(prsrOpts, parser.PopulateMacroCalls(true))
|
||||
}
|
||||
e.prsr, err = parser.NewParser(prsrOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure that the checker init happens eagerly rather than lazily.
|
||||
if e.HasFeature(featureEagerlyValidateDeclarations) {
|
||||
err := e.initChecker()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (e *Env) initChecker() error {
|
||||
e.chkOnce.Do(func() {
|
||||
chkOpts := []checker.Option{}
|
||||
chkOpts = append(chkOpts, e.chkOpts...)
|
||||
chkOpts = append(chkOpts,
|
||||
checker.HomogeneousAggregateLiterals(
|
||||
e.HasFeature(featureDisableDynamicAggregateLiterals)),
|
||||
checker.CrossTypeNumericComparisons(
|
||||
e.HasFeature(featureCrossTypeNumericComparisons)))
|
||||
|
||||
ce, err := checker.NewEnv(e.Container, e.provider, chkOpts...)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
return
|
||||
}
|
||||
// Add the statically configured declarations.
|
||||
err = ce.Add(e.declarations...)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
return
|
||||
}
|
||||
// Add the function declarations which are derived from the FunctionDecl instances.
|
||||
for _, fn := range e.functions {
|
||||
fnDecl, err := functionDeclToExprDecl(fn)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
return
|
||||
}
|
||||
err = ce.Add(fnDecl)
|
||||
if err != nil {
|
||||
e.chkErr = err
|
||||
return
|
||||
}
|
||||
}
|
||||
// Add function declarations here separately.
|
||||
e.chk = ce
|
||||
})
|
||||
return e.chkErr
|
||||
}
|
||||
|
||||
// Issues defines methods for inspecting the error details of parse and check calls.
|
||||
//
|
||||
// Note: in the future, non-fatal warnings and notices may be inspectable via the Issues struct.
|
||||
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
|
||||
}
|
||||
if other == nil {
|
||||
return i
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
||||
// getStdEnv lazy initializes the CEL standard environment.
|
||||
func getStdEnv() (*Env, error) {
|
||||
stdEnvInit.Do(func() {
|
||||
stdEnv, stdEnvErr = NewCustomEnv(StdLib(), EagerlyValidateDeclarations(true))
|
||||
})
|
||||
return stdEnv, stdEnvErr
|
||||
}
|
||||
|
||||
var (
|
||||
stdEnvInit sync.Once
|
||||
stdEnv *Env
|
||||
stdEnvErr error
|
||||
)
|
280
vendor/github.com/google/cel-go/cel/io.go
generated
vendored
Normal file
280
vendor/github.com/google/cel-go/cel/io.go
generated
vendored
Normal file
@ -0,0 +1,280 @@
|
||||
// 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"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
"github.com/google/cel-go/parser"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
)
|
||||
|
||||
// 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 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 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)
|
||||
}
|
||||
|
||||
// RefValueToValue converts between ref.Val and api.expr.Value.
|
||||
// The result Value is the serialized proto form. The ref.Val must not be error or unknown.
|
||||
func RefValueToValue(res ref.Val) (*exprpb.Value, error) {
|
||||
switch res.Type() {
|
||||
case types.BoolType:
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_BoolValue{BoolValue: res.Value().(bool)}}, nil
|
||||
case types.BytesType:
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_BytesValue{BytesValue: res.Value().([]byte)}}, nil
|
||||
case types.DoubleType:
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_DoubleValue{DoubleValue: res.Value().(float64)}}, nil
|
||||
case types.IntType:
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_Int64Value{Int64Value: res.Value().(int64)}}, nil
|
||||
case types.ListType:
|
||||
l := res.(traits.Lister)
|
||||
sz := l.Size().(types.Int)
|
||||
elts := make([]*exprpb.Value, 0, int64(sz))
|
||||
for i := types.Int(0); i < sz; i++ {
|
||||
v, err := RefValueToValue(l.Get(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elts = append(elts, v)
|
||||
}
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_ListValue{
|
||||
ListValue: &exprpb.ListValue{Values: elts}}}, nil
|
||||
case types.MapType:
|
||||
mapper := res.(traits.Mapper)
|
||||
sz := mapper.Size().(types.Int)
|
||||
entries := make([]*exprpb.MapValue_Entry, 0, int64(sz))
|
||||
for it := mapper.Iterator(); it.HasNext().(types.Bool); {
|
||||
k := it.Next()
|
||||
v := mapper.Get(k)
|
||||
kv, err := RefValueToValue(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vv, err := RefValueToValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries = append(entries, &exprpb.MapValue_Entry{Key: kv, Value: vv})
|
||||
}
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_MapValue{
|
||||
MapValue: &exprpb.MapValue{Entries: entries}}}, nil
|
||||
case types.NullType:
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_NullValue{}}, nil
|
||||
case types.StringType:
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_StringValue{StringValue: res.Value().(string)}}, nil
|
||||
case types.TypeType:
|
||||
typeName := res.(ref.Type).TypeName()
|
||||
return &exprpb.Value{Kind: &exprpb.Value_TypeValue{TypeValue: typeName}}, nil
|
||||
case types.UintType:
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_Uint64Value{Uint64Value: res.Value().(uint64)}}, nil
|
||||
default:
|
||||
any, err := res.ConvertToNative(anyPbType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &exprpb.Value{
|
||||
Kind: &exprpb.Value_ObjectValue{ObjectValue: any.(*anypb.Any)}}, nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
typeNameToTypeValue = map[string]*types.TypeValue{
|
||||
"bool": types.BoolType,
|
||||
"bytes": types.BytesType,
|
||||
"double": types.DoubleType,
|
||||
"null_type": types.NullType,
|
||||
"int": types.IntType,
|
||||
"list": types.ListType,
|
||||
"map": types.MapType,
|
||||
"string": types.StringType,
|
||||
"type": types.TypeType,
|
||||
"uint": types.UintType,
|
||||
}
|
||||
|
||||
anyPbType = reflect.TypeOf(&anypb.Any{})
|
||||
)
|
||||
|
||||
// ValueToRefValue converts between exprpb.Value and ref.Val.
|
||||
func ValueToRefValue(adapter ref.TypeAdapter, v *exprpb.Value) (ref.Val, error) {
|
||||
switch v.Kind.(type) {
|
||||
case *exprpb.Value_NullValue:
|
||||
return types.NullValue, nil
|
||||
case *exprpb.Value_BoolValue:
|
||||
return types.Bool(v.GetBoolValue()), nil
|
||||
case *exprpb.Value_Int64Value:
|
||||
return types.Int(v.GetInt64Value()), nil
|
||||
case *exprpb.Value_Uint64Value:
|
||||
return types.Uint(v.GetUint64Value()), nil
|
||||
case *exprpb.Value_DoubleValue:
|
||||
return types.Double(v.GetDoubleValue()), nil
|
||||
case *exprpb.Value_StringValue:
|
||||
return types.String(v.GetStringValue()), nil
|
||||
case *exprpb.Value_BytesValue:
|
||||
return types.Bytes(v.GetBytesValue()), nil
|
||||
case *exprpb.Value_ObjectValue:
|
||||
any := v.GetObjectValue()
|
||||
msg, err := anypb.UnmarshalNew(any, proto.UnmarshalOptions{DiscardUnknown: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adapter.NativeToValue(msg), nil
|
||||
case *exprpb.Value_MapValue:
|
||||
m := v.GetMapValue()
|
||||
entries := make(map[ref.Val]ref.Val)
|
||||
for _, entry := range m.Entries {
|
||||
key, err := ValueToRefValue(adapter, entry.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pb, err := ValueToRefValue(adapter, entry.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries[key] = pb
|
||||
}
|
||||
return adapter.NativeToValue(entries), nil
|
||||
case *exprpb.Value_ListValue:
|
||||
l := v.GetListValue()
|
||||
elts := make([]ref.Val, len(l.Values))
|
||||
for i, e := range l.Values {
|
||||
rv, err := ValueToRefValue(adapter, e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elts[i] = rv
|
||||
}
|
||||
return adapter.NativeToValue(elts), nil
|
||||
case *exprpb.Value_TypeValue:
|
||||
typeName := v.GetTypeValue()
|
||||
tv, ok := typeNameToTypeValue[typeName]
|
||||
if ok {
|
||||
return tv, nil
|
||||
}
|
||||
return types.NewObjectTypeValue(typeName), nil
|
||||
}
|
||||
return nil, errors.New("unknown value")
|
||||
}
|
343
vendor/github.com/google/cel-go/cel/library.go
generated
vendored
Normal file
343
vendor/github.com/google/cel-go/cel/library.go
generated
vendored
Normal file
@ -0,0 +1,343 @@
|
||||
// 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 (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/checker"
|
||||
"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/interpreter/functions"
|
||||
)
|
||||
|
||||
// Library provides a collection of EnvOption and ProgramOption values used to configure a CEL
|
||||
// environment for a particular use case or with a related set of functionality.
|
||||
//
|
||||
// Note, the ProgramOption values provided by a library are expected to be static and not vary
|
||||
// between calls to Env.Program(). If there is a need for such dynamic configuration, prefer to
|
||||
// configure these options outside the Library and within the Env.Program() call directly.
|
||||
type Library interface {
|
||||
// CompileOptions returns a collection of functional 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(StandardMacros...),
|
||||
}
|
||||
}
|
||||
|
||||
// ProgramOptions returns function implementations for the standard CEL functions.
|
||||
func (stdLibrary) ProgramOptions() []ProgramOption {
|
||||
return []ProgramOption{
|
||||
Functions(functions.StandardOverloads()...),
|
||||
}
|
||||
}
|
||||
|
||||
type timeUTCLibrary struct{}
|
||||
|
||||
func (timeUTCLibrary) CompileOptions() []EnvOption {
|
||||
return timeOverloadDeclarations
|
||||
}
|
||||
|
||||
func (timeUTCLibrary) ProgramOptions() []ProgramOption {
|
||||
return []ProgramOption{}
|
||||
}
|
||||
|
||||
// Declarations and functions which enable using UTC on time.Time inputs when the timezone is unspecified
|
||||
// in the CEL expression.
|
||||
var (
|
||||
utcTZ = types.String("UTC")
|
||||
|
||||
timeOverloadDeclarations = []EnvOption{
|
||||
Function(overloads.TimeGetHours,
|
||||
MemberOverload(overloads.DurationToHours, []*Type{DurationType}, IntType,
|
||||
UnaryBinding(func(dur ref.Val) ref.Val {
|
||||
d := dur.(types.Duration)
|
||||
return types.Int(d.Hours())
|
||||
}))),
|
||||
Function(overloads.TimeGetMinutes,
|
||||
MemberOverload(overloads.DurationToMinutes, []*Type{DurationType}, IntType,
|
||||
UnaryBinding(func(dur ref.Val) ref.Val {
|
||||
d := dur.(types.Duration)
|
||||
return types.Int(d.Minutes())
|
||||
}))),
|
||||
Function(overloads.TimeGetSeconds,
|
||||
MemberOverload(overloads.DurationToSeconds, []*Type{DurationType}, IntType,
|
||||
UnaryBinding(func(dur ref.Val) ref.Val {
|
||||
d := dur.(types.Duration)
|
||||
return types.Int(d.Seconds())
|
||||
}))),
|
||||
Function(overloads.TimeGetMilliseconds,
|
||||
MemberOverload(overloads.DurationToMilliseconds, []*Type{DurationType}, IntType,
|
||||
UnaryBinding(func(dur ref.Val) ref.Val {
|
||||
d := dur.(types.Duration)
|
||||
return types.Int(d.Milliseconds())
|
||||
}))),
|
||||
Function(overloads.TimeGetFullYear,
|
||||
MemberOverload(overloads.TimestampToYear, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetFullYear(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToYearWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(timestampGetFullYear),
|
||||
),
|
||||
),
|
||||
Function(overloads.TimeGetMonth,
|
||||
MemberOverload(overloads.TimestampToMonth, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetMonth(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToMonthWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(timestampGetMonth),
|
||||
),
|
||||
),
|
||||
Function(overloads.TimeGetDayOfYear,
|
||||
MemberOverload(overloads.TimestampToDayOfYear, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetDayOfYear(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToDayOfYearWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(func(ts, tz ref.Val) ref.Val {
|
||||
return timestampGetDayOfYear(ts, tz)
|
||||
}),
|
||||
),
|
||||
),
|
||||
Function(overloads.TimeGetDayOfMonth,
|
||||
MemberOverload(overloads.TimestampToDayOfMonthZeroBased, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetDayOfMonthZeroBased(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToDayOfMonthZeroBasedWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(timestampGetDayOfMonthZeroBased),
|
||||
),
|
||||
),
|
||||
Function(overloads.TimeGetDate,
|
||||
MemberOverload(overloads.TimestampToDayOfMonthOneBased, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetDayOfMonthOneBased(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToDayOfMonthOneBasedWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(timestampGetDayOfMonthOneBased),
|
||||
),
|
||||
),
|
||||
Function(overloads.TimeGetDayOfWeek,
|
||||
MemberOverload(overloads.TimestampToDayOfWeek, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetDayOfWeek(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToDayOfWeekWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(timestampGetDayOfWeek),
|
||||
),
|
||||
),
|
||||
Function(overloads.TimeGetHours,
|
||||
MemberOverload(overloads.TimestampToHours, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetHours(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToHoursWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(timestampGetHours),
|
||||
),
|
||||
),
|
||||
Function(overloads.TimeGetMinutes,
|
||||
MemberOverload(overloads.TimestampToMinutes, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetMinutes(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToMinutesWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(timestampGetMinutes),
|
||||
),
|
||||
),
|
||||
Function(overloads.TimeGetSeconds,
|
||||
MemberOverload(overloads.TimestampToSeconds, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetSeconds(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToSecondsWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(timestampGetSeconds),
|
||||
),
|
||||
),
|
||||
Function(overloads.TimeGetMilliseconds,
|
||||
MemberOverload(overloads.TimestampToMilliseconds, []*Type{TimestampType}, IntType,
|
||||
UnaryBinding(func(ts ref.Val) ref.Val {
|
||||
return timestampGetMilliseconds(ts, utcTZ)
|
||||
}),
|
||||
),
|
||||
MemberOverload(overloads.TimestampToMillisecondsWithTz, []*Type{TimestampType, StringType}, IntType,
|
||||
BinaryBinding(timestampGetMilliseconds),
|
||||
),
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
func timestampGetFullYear(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(t.Year())
|
||||
}
|
||||
|
||||
func timestampGetMonth(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
// CEL spec indicates that the month should be 0-based, but the Time value
|
||||
// for Month() is 1-based.
|
||||
return types.Int(t.Month() - 1)
|
||||
}
|
||||
|
||||
func timestampGetDayOfYear(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(t.YearDay() - 1)
|
||||
}
|
||||
|
||||
func timestampGetDayOfMonthZeroBased(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(t.Day() - 1)
|
||||
}
|
||||
|
||||
func timestampGetDayOfMonthOneBased(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(t.Day())
|
||||
}
|
||||
|
||||
func timestampGetDayOfWeek(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(t.Weekday())
|
||||
}
|
||||
|
||||
func timestampGetHours(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(t.Hour())
|
||||
}
|
||||
|
||||
func timestampGetMinutes(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(t.Minute())
|
||||
}
|
||||
|
||||
func timestampGetSeconds(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(t.Second())
|
||||
}
|
||||
|
||||
func timestampGetMilliseconds(ts, tz ref.Val) ref.Val {
|
||||
t, err := inTimeZone(ts, tz)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(t.Nanosecond() / 1000000)
|
||||
}
|
||||
|
||||
func inTimeZone(ts, tz ref.Val) (time.Time, error) {
|
||||
t := ts.(types.Timestamp)
|
||||
val := string(tz.(types.String))
|
||||
ind := strings.Index(val, ":")
|
||||
if ind == -1 {
|
||||
loc, err := time.LoadLocation(val)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return t.In(loc), nil
|
||||
}
|
||||
|
||||
// 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 time.Time{}, err
|
||||
}
|
||||
min, err := strconv.Atoi(string(val[ind+1:]))
|
||||
if err != nil {
|
||||
return time.Time{}, 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 t.In(timezone), nil
|
||||
}
|
139
vendor/github.com/google/cel-go/cel/macro.go
generated
vendored
Normal file
139
vendor/github.com/google/cel-go/cel/macro.go
generated
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cel
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/parser"
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Macro describes a function signature to match and the MacroExpander to apply.
|
||||
//
|
||||
// Note: when a Macro should apply to multiple overloads (based on arg count) of a given function,
|
||||
// a Macro should be created per arg-count or as a var arg macro.
|
||||
type Macro = parser.Macro
|
||||
|
||||
// MacroExpander converts a call and its associated arguments into a new CEL abstract syntax tree, or an error
|
||||
// if the input arguments are not suitable for the expansion requirements for the macro in question.
|
||||
//
|
||||
// The MacroExpander accepts as arguments a MacroExprHelper as well as the arguments used in the function call
|
||||
// and produces as output an Expr ast node.
|
||||
//
|
||||
// Note: when the Macro.IsReceiverStyle() method returns true, the target argument will be nil.
|
||||
type MacroExpander = parser.MacroExpander
|
||||
|
||||
// MacroExprHelper exposes helper methods for creating new expressions within a CEL abstract syntax tree.
|
||||
type MacroExprHelper = parser.ExprHelper
|
||||
|
||||
// NewGlobalMacro creates a Macro for a global function with the specified arg count.
|
||||
func NewGlobalMacro(function string, argCount int, expander MacroExpander) Macro {
|
||||
return parser.NewGlobalMacro(function, argCount, expander)
|
||||
}
|
||||
|
||||
// NewReceiverMacro creates a Macro for a receiver function matching the specified arg count.
|
||||
func NewReceiverMacro(function string, argCount int, expander MacroExpander) Macro {
|
||||
return parser.NewReceiverMacro(function, argCount, expander)
|
||||
}
|
||||
|
||||
// NewGlobalVarArgMacro creates a Macro for a global function with a variable arg count.
|
||||
func NewGlobalVarArgMacro(function string, expander MacroExpander) Macro {
|
||||
return parser.NewGlobalVarArgMacro(function, expander)
|
||||
}
|
||||
|
||||
// NewReceiverVarArgMacro creates a Macro for a receiver function matching a variable arg count.
|
||||
func NewReceiverVarArgMacro(function string, expander MacroExpander) Macro {
|
||||
return parser.NewReceiverVarArgMacro(function, expander)
|
||||
}
|
||||
|
||||
// HasMacroExpander expands the input call arguments into a presence test, e.g. has(<operand>.field)
|
||||
func HasMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
return parser.MakeHas(meh, target, args)
|
||||
}
|
||||
|
||||
// ExistsMacroExpander expands the input call arguments into a comprehension that returns true if any of the
|
||||
// elements in the range match the predicate expressions:
|
||||
// <iterRange>.exists(<iterVar>, <predicate>)
|
||||
func ExistsMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
return parser.MakeExists(meh, target, args)
|
||||
}
|
||||
|
||||
// ExistsOneMacroExpander expands the input call arguments into a comprehension that returns true if exactly
|
||||
// one of the elements in the range match the predicate expressions:
|
||||
// <iterRange>.exists_one(<iterVar>, <predicate>)
|
||||
func ExistsOneMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
return parser.MakeExistsOne(meh, target, args)
|
||||
}
|
||||
|
||||
// MapMacroExpander expands the input call arguments into a comprehension that transforms each element in the
|
||||
// input to produce an output list.
|
||||
//
|
||||
// There are two call patterns supported by map:
|
||||
// <iterRange>.map(<iterVar>, <transform>)
|
||||
// <iterRange>.map(<iterVar>, <predicate>, <transform>)
|
||||
// In the second form only iterVar values which return true when provided to the predicate expression
|
||||
// are transformed.
|
||||
func MapMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
return parser.MakeMap(meh, target, args)
|
||||
}
|
||||
|
||||
// FilterMacroExpander expands the input call arguments into a comprehension which produces a list which contains
|
||||
// only elements which match the provided predicate expression:
|
||||
// <iterRange>.filter(<iterVar>, <predicate>)
|
||||
func FilterMacroExpander(meh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *common.Error) {
|
||||
return parser.MakeFilter(meh, target, args)
|
||||
}
|
||||
|
||||
var (
|
||||
// Aliases to each macro in the CEL standard environment.
|
||||
// Note: reassigning these macro variables may result in undefined behavior.
|
||||
|
||||
// HasMacro expands "has(m.f)" which tests the presence of a field, avoiding the need to
|
||||
// specify the field as a string.
|
||||
HasMacro = parser.HasMacro
|
||||
|
||||
// AllMacro expands "range.all(var, predicate)" into a comprehension which ensures that all
|
||||
// elements in the range satisfy the predicate.
|
||||
AllMacro = parser.AllMacro
|
||||
|
||||
// ExistsMacro expands "range.exists(var, predicate)" into a comprehension which ensures that
|
||||
// some element in the range satisfies the predicate.
|
||||
ExistsMacro = parser.ExistsMacro
|
||||
|
||||
// ExistsOneMacro expands "range.exists_one(var, predicate)", which is true if for exactly one
|
||||
// element in range the predicate holds.
|
||||
ExistsOneMacro = parser.ExistsOneMacro
|
||||
|
||||
// MapMacro expands "range.map(var, function)" into a comprehension which applies the function
|
||||
// to each element in the range to produce a new list.
|
||||
MapMacro = parser.MapMacro
|
||||
|
||||
// MapFilterMacro expands "range.map(var, predicate, function)" into a comprehension which
|
||||
// first filters the elements in the range by the predicate, then applies the transform function
|
||||
// to produce a new list.
|
||||
MapFilterMacro = parser.MapFilterMacro
|
||||
|
||||
// FilterMacro expands "range.filter(var, predicate)" into a comprehension which filters
|
||||
// elements in the range, producing a new list from the elements that satisfy the predicate.
|
||||
FilterMacro = parser.FilterMacro
|
||||
|
||||
// StandardMacros provides an alias to all the CEL macros defined in the standard environment.
|
||||
StandardMacros = []Macro{
|
||||
HasMacro, AllMacro, ExistsMacro, ExistsOneMacro, MapMacro, MapFilterMacro, FilterMacro,
|
||||
}
|
||||
|
||||
// NoMacros provides an alias to an empty list of macros
|
||||
NoMacros = []Macro{}
|
||||
)
|
543
vendor/github.com/google/cel-go/cel/options.go
generated
vendored
Normal file
543
vendor/github.com/google/cel-go/cel/options.go
generated
vendored
Normal file
@ -0,0 +1,543 @@
|
||||
// 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"
|
||||
|
||||
"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"
|
||||
|
||||
"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"
|
||||
|
||||
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
|
||||
|
||||
// Enable the tracking of function call expressions replaced by macros.
|
||||
featureEnableMacroCallTracking
|
||||
|
||||
// Enable the use of cross-type numeric comparisons at the type-checker.
|
||||
featureCrossTypeNumericComparisons
|
||||
|
||||
// Enable eager validation of declarations to ensure that Env values created
|
||||
// with `Extend` inherit a validated list of declarations from the parent Env.
|
||||
featureEagerlyValidateDeclarations
|
||||
|
||||
// Enable the use of the default UTC timezone when a timezone is not specified
|
||||
// on a CEL timestamp operation. This fixes the scenario where the input time
|
||||
// is not already in UTC.
|
||||
featureDefaultUTCTimeZone
|
||||
)
|
||||
|
||||
// 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 = 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 {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.declarations = append(e.declarations, decls...)
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// EagerlyValidateDeclarations ensures that any collisions between configured declarations are caught
|
||||
// at the time of the `NewEnv` call.
|
||||
//
|
||||
// Eagerly validating declarations is also useful for bootstrapping a base `cel.Env` value.
|
||||
// Calls to base `Env.Extend()` will be significantly faster when declarations are eagerly validated
|
||||
// as declarations will be collision-checked at most once and only incrementally by way of `Extend`
|
||||
//
|
||||
// Disabled by default as not all environments are used for type-checking.
|
||||
func EagerlyValidateDeclarations(enabled bool) EnvOption {
|
||||
return features(featureEagerlyValidateDeclarations, enabled)
|
||||
}
|
||||
|
||||
// HomogeneousAggregateLiterals option ensures that list and map literal entry types must agree
|
||||
// during type-checking.
|
||||
//
|
||||
// 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, true)
|
||||
}
|
||||
|
||||
// Macros option extends the macro set configured in the environment.
|
||||
//
|
||||
// Note: This option must be specified after ClearMacros if used together.
|
||||
func Macros(macros ...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.
|
||||
//
|
||||
// Deprecated: use Function() instead to declare the function, its overload signatures,
|
||||
// and the overload implementations.
|
||||
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. If Globals is used in a Library with
|
||||
// a Lib EnvOption, vars may shadow variables provided by previously added libraries.
|
||||
//
|
||||
// The vars value may either be an `interpreter.Activation` instance or a `map[string]interface{}`.
|
||||
func Globals(vars interface{}) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
defaultVars, err := interpreter.NewActivation(vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.defaultVars != nil {
|
||||
defaultVars = interpreter.NewHierarchicalActivation(p.defaultVars, defaultVars)
|
||||
}
|
||||
p.defaultVars = defaultVars
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
// OptimizeRegex provides a way to replace the InterpretableCall for regex functions. This can be used
|
||||
// to compile regex string constants at program creation time and report any errors and then use the
|
||||
// compiled regex for all regex function invocations.
|
||||
func OptimizeRegex(regexOptimizations ...*interpreter.RegexOptimization) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
p.regexOptimizations = append(p.regexOptimizations, regexOptimizations...)
|
||||
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. It also pre-compiles regex pattern constants passed to 'matches', reports any compilation errors
|
||||
// at program creation and uses the compiled regex pattern for all 'matches' function invocations.
|
||||
// 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() call is created via PartialVars().
|
||||
OptPartialEval EvalOption = 1 << iota
|
||||
|
||||
// OptTrackCost enables the runtime cost calculation while validation and return cost within evalDetails
|
||||
// cost calculation is available via func ActualCost()
|
||||
OptTrackCost 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
|
||||
}
|
||||
}
|
||||
|
||||
// InterruptCheckFrequency configures the number of iterations within a comprehension to evaluate
|
||||
// before checking whether the function evaluation has been interrupted.
|
||||
func InterruptCheckFrequency(checkFrequency uint) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
p.interruptCheckFrequency = checkFrequency
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CostTracking enables cost tracking and registers a ActualCostEstimator that can optionally provide a runtime cost estimate for any function calls.
|
||||
func CostTracking(costEstimator interpreter.ActualCostEstimator) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
p.callCostEstimator = costEstimator
|
||||
p.evalOpts |= OptTrackCost
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CostLimit enables cost tracking and sets configures program evaluation to exit early with a
|
||||
// "runtime cost limit exceeded" error if the runtime cost exceeds the costLimit.
|
||||
// The CostLimit is a metric that corresponds to the number and estimated expense of operations
|
||||
// performed while evaluating an expression. It is indicative of CPU usage, not memory usage.
|
||||
func CostLimit(costLimit uint64) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
p.costLimit = &costLimit
|
||||
p.evalOpts |= OptTrackCost
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
||||
func fieldToCELType(field protoreflect.FieldDescriptor) (*exprpb.Type, error) {
|
||||
if field.Kind() == protoreflect.MessageKind || field.Kind() == protoreflect.GroupKind {
|
||||
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
|
||||
}
|
||||
if field.IsList() {
|
||||
elemType, err := fieldToCELType(field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return decls.NewVar(name, decls.NewListType(elemType)), nil
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// EnableMacroCallTracking ensures that call expressions which are replaced by macros
|
||||
// are tracked in the `SourceInfo` of parsed and checked expressions.
|
||||
func EnableMacroCallTracking() EnvOption {
|
||||
return features(featureEnableMacroCallTracking, true)
|
||||
}
|
||||
|
||||
// CrossTypeNumericComparisons makes it possible to compare across numeric types, e.g. double < int
|
||||
func CrossTypeNumericComparisons(enabled bool) EnvOption {
|
||||
return features(featureCrossTypeNumericComparisons, enabled)
|
||||
}
|
||||
|
||||
// DefaultUTCTimeZone ensures that time-based operations use the UTC timezone rather than the
|
||||
// input time's local timezone.
|
||||
func DefaultUTCTimeZone(enabled bool) EnvOption {
|
||||
return features(featureDefaultUTCTimeZone, enabled)
|
||||
}
|
||||
|
||||
// features sets the given feature flags. See list of Feature constants above.
|
||||
func features(flag int, enabled bool) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.features[flag] = enabled
|
||||
return e, nil
|
||||
}
|
||||
}
|
567
vendor/github.com/google/cel-go/cel/program.go
generated
vendored
Normal file
567
vendor/github.com/google/cel-go/cel/program.go
generated
vendored
Normal file
@ -0,0 +1,567 @@
|
||||
// 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 (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/interpreter"
|
||||
)
|
||||
|
||||
// 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`, `OptTrackCost` or `OptExhaustiveEval` flags are used, the `details` response will
|
||||
// be non-nil. Given this caveat on `details`, the return state from evaluation will be:
|
||||
//
|
||||
// * `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(interface{}) (ref.Val, *EvalDetails, error)
|
||||
|
||||
// ContextEval evaluates the program with a set of input variables and a context object in order
|
||||
// to support cancellation and timeouts. This method must be used in conjunction with the
|
||||
// InterruptCheckFrequency() option for cancellation interrupts to be impact evaluation.
|
||||
//
|
||||
// The vars value may either be an `interpreter.Activation` or `map[string]interface{}`.
|
||||
//
|
||||
// The output contract for `ContextEval` is otherwise identical to the `Eval` method.
|
||||
ContextEval(context.Context, 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
|
||||
costTracker *interpreter.CostTracker
|
||||
}
|
||||
|
||||
// State of the evaluation, non-nil if the OptTrackState or OptExhaustiveEval is specified
|
||||
// within EvalOptions.
|
||||
func (ed *EvalDetails) State() interpreter.EvalState {
|
||||
return ed.state
|
||||
}
|
||||
|
||||
// ActualCost returns the tracked cost through the course of execution when `CostTracking` is enabled.
|
||||
// Otherwise, returns nil if the cost was not enabled.
|
||||
func (ed *EvalDetails) ActualCost() *uint64 {
|
||||
if ed.costTracker == nil {
|
||||
return nil
|
||||
}
|
||||
cost := ed.costTracker.ActualCost()
|
||||
return &cost
|
||||
}
|
||||
|
||||
// prog is the internal implementation of the Program interface.
|
||||
type prog struct {
|
||||
*Env
|
||||
evalOpts EvalOption
|
||||
defaultVars interpreter.Activation
|
||||
dispatcher interpreter.Dispatcher
|
||||
interpreter interpreter.Interpreter
|
||||
interruptCheckFrequency uint
|
||||
|
||||
// Intermediate state used to configure the InterpretableDecorator set provided
|
||||
// to the initInterpretable call.
|
||||
decorators []interpreter.InterpretableDecorator
|
||||
regexOptimizations []*interpreter.RegexOptimization
|
||||
|
||||
// Interpretable configured from an Ast and aggregate decorator set based on program options.
|
||||
interpretable interpreter.Interpretable
|
||||
callCostEstimator interpreter.ActualCostEstimator
|
||||
costLimit *uint64
|
||||
}
|
||||
|
||||
func (p *prog) clone() *prog {
|
||||
return &prog{
|
||||
Env: p.Env,
|
||||
evalOpts: p.evalOpts,
|
||||
defaultVars: p.defaultVars,
|
||||
dispatcher: p.dispatcher,
|
||||
interpreter: p.interpreter,
|
||||
interruptCheckFrequency: p.interruptCheckFrequency,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
p, err = opt(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Add the function bindings created via Function() options.
|
||||
for _, fn := range e.functions {
|
||||
bindings, err := fn.bindings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = disp.Add(bindings...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Set the attribute factory after the options have been set.
|
||||
var attrFactory interpreter.AttributeFactory
|
||||
if p.evalOpts&OptPartialEval == OptPartialEval {
|
||||
attrFactory = interpreter.NewPartialAttributeFactory(e.Container, e.adapter, e.provider)
|
||||
} else {
|
||||
attrFactory = interpreter.NewAttributeFactory(e.Container, e.adapter, e.provider)
|
||||
}
|
||||
interp := interpreter.NewInterpreter(disp, e.Container, e.provider, e.adapter, attrFactory)
|
||||
p.interpreter = interp
|
||||
|
||||
// Translate the EvalOption flags into InterpretableDecorator instances.
|
||||
decorators := make([]interpreter.InterpretableDecorator, len(p.decorators))
|
||||
copy(decorators, p.decorators)
|
||||
|
||||
// Enable interrupt checking if there's a non-zero check frequency
|
||||
if p.interruptCheckFrequency > 0 {
|
||||
decorators = append(decorators, interpreter.InterruptableEval())
|
||||
}
|
||||
// Enable constant folding first.
|
||||
if p.evalOpts&OptOptimize == OptOptimize {
|
||||
decorators = append(decorators, interpreter.Optimize())
|
||||
p.regexOptimizations = append(p.regexOptimizations, interpreter.MatchesRegexOptimization)
|
||||
}
|
||||
// Enable regex compilation of constants immediately after folding constants.
|
||||
if len(p.regexOptimizations) > 0 {
|
||||
decorators = append(decorators, interpreter.CompileRegexConstants(p.regexOptimizations...))
|
||||
}
|
||||
|
||||
// Enable exhaustive eval, state tracking and cost tracking last since they require a factory.
|
||||
if p.evalOpts&(OptExhaustiveEval|OptTrackState|OptTrackCost) != 0 {
|
||||
factory := func(state interpreter.EvalState, costTracker *interpreter.CostTracker) (Program, error) {
|
||||
costTracker.Estimator = p.callCostEstimator
|
||||
costTracker.Limit = p.costLimit
|
||||
// Limit capacity to guarantee a reallocation when calling 'append(decs, ...)' below. This
|
||||
// prevents the underlying memory from being shared between factory function calls causing
|
||||
// undesired mutations.
|
||||
decs := decorators[:len(decorators):len(decorators)]
|
||||
var observers []interpreter.EvalObserver
|
||||
|
||||
if p.evalOpts&(OptExhaustiveEval|OptTrackState) != 0 {
|
||||
// EvalStateObserver is required for OptExhaustiveEval.
|
||||
observers = append(observers, interpreter.EvalStateObserver(state))
|
||||
}
|
||||
if p.evalOpts&OptTrackCost == OptTrackCost {
|
||||
observers = append(observers, interpreter.CostObserver(costTracker))
|
||||
}
|
||||
|
||||
// Enable exhaustive eval over a basic observer since it offers a superset of features.
|
||||
if p.evalOpts&OptExhaustiveEval == OptExhaustiveEval {
|
||||
decs = append(decs, interpreter.ExhaustiveEval(), interpreter.Observe(observers...))
|
||||
} else if len(observers) > 0 {
|
||||
decs = append(decs, interpreter.Observe(observers...))
|
||||
}
|
||||
|
||||
return p.clone().initInterpretable(ast, decs)
|
||||
}
|
||||
return newProgGen(factory)
|
||||
}
|
||||
return p.initInterpretable(ast, decorators)
|
||||
}
|
||||
|
||||
func (p *prog) initInterpretable(ast *Ast, decs []interpreter.InterpretableDecorator) (*prog, error) {
|
||||
// Unchecked programs do not contain type and reference information and may be slower to execute.
|
||||
if !ast.IsChecked() {
|
||||
interpretable, err :=
|
||||
p.interpreter.NewUncheckedInterpretable(ast.Expr(), decs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.interpretable = interpretable
|
||||
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
|
||||
}
|
||||
interpretable, err := p.interpreter.NewInterpretable(checked, decs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.interpretable = interpretable
|
||||
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 {
|
||||
switch t := r.(type) {
|
||||
case interpreter.EvalCancelledError:
|
||||
err = t
|
||||
default:
|
||||
err = fmt.Errorf("internal error: %v", r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
// Build a hierarchical activation if there are default vars set.
|
||||
var vars interpreter.Activation
|
||||
switch v := input.(type) {
|
||||
case interpreter.Activation:
|
||||
vars = v
|
||||
case map[string]interface{}:
|
||||
vars = activationPool.Setup(v)
|
||||
defer activationPool.Put(vars)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid input, wanted Activation or map[string]interface{}, got: (%T)%v", input, input)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// ContextEval implements the Program interface.
|
||||
func (p *prog) ContextEval(ctx context.Context, input interface{}) (ref.Val, *EvalDetails, error) {
|
||||
if ctx == nil {
|
||||
return nil, nil, fmt.Errorf("context can not be nil")
|
||||
}
|
||||
// Configure the input, making sure to wrap Activation inputs in the special ctxActivation which
|
||||
// exposes the #interrupted variable and manages rate-limited checks of the ctx.Done() state.
|
||||
var vars interpreter.Activation
|
||||
switch v := input.(type) {
|
||||
case interpreter.Activation:
|
||||
vars = ctxActivationPool.Setup(v, ctx.Done(), p.interruptCheckFrequency)
|
||||
defer ctxActivationPool.Put(vars)
|
||||
case map[string]interface{}:
|
||||
rawVars := activationPool.Setup(v)
|
||||
defer activationPool.Put(rawVars)
|
||||
vars = ctxActivationPool.Setup(rawVars, ctx.Done(), p.interruptCheckFrequency)
|
||||
defer ctxActivationPool.Put(vars)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid input, wanted Activation or map[string]interface{}, got: (%T)%v", input, input)
|
||||
}
|
||||
return p.Eval(vars)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (p *prog) Cost() (min, max int64) {
|
||||
return estimateCost(p.interpretable)
|
||||
}
|
||||
|
||||
// progFactory is a helper alias for marking a program creation factory function.
|
||||
type progFactory func(interpreter.EvalState, *interpreter.CostTracker) (Program, error)
|
||||
|
||||
// progGen holds a reference to a progFactory instance and implements the Program interface.
|
||||
type progGen struct {
|
||||
factory progFactory
|
||||
}
|
||||
|
||||
// newProgGen tests the factory object by calling it once and returns a factory-based Program if
|
||||
// the test is successful.
|
||||
func newProgGen(factory progFactory) (Program, error) {
|
||||
// Test the factory to make sure that configuration errors are spotted at config
|
||||
_, err := factory(interpreter.NewEvalState(), &interpreter.CostTracker{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &progGen{factory: factory}, nil
|
||||
}
|
||||
|
||||
// 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()
|
||||
costTracker := &interpreter.CostTracker{}
|
||||
det := &EvalDetails{state: state, costTracker: costTracker}
|
||||
|
||||
// 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, costTracker)
|
||||
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
|
||||
}
|
||||
|
||||
// ContextEval implements the Program interface method.
|
||||
func (gen *progGen) ContextEval(ctx context.Context, input interface{}) (ref.Val, *EvalDetails, error) {
|
||||
if ctx == nil {
|
||||
return nil, nil, fmt.Errorf("context can not be nil")
|
||||
}
|
||||
// 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()
|
||||
costTracker := &interpreter.CostTracker{}
|
||||
det := &EvalDetails{state: state, costTracker: costTracker}
|
||||
|
||||
// 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, costTracker)
|
||||
if err != nil {
|
||||
return nil, det, err
|
||||
}
|
||||
|
||||
// Evaluate the input, returning the result and the 'state' within EvalDetails.
|
||||
v, _, err := p.ContextEval(ctx, 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, nil)
|
||||
if err != nil {
|
||||
return 0, math.MaxInt64
|
||||
}
|
||||
return estimateCost(p)
|
||||
}
|
||||
|
||||
// EstimateCost returns the heuristic cost interval for the program.
|
||||
func EstimateCost(p Program) (min, max int64) {
|
||||
return estimateCost(p)
|
||||
}
|
||||
|
||||
func estimateCost(i interface{}) (min, max int64) {
|
||||
c, ok := i.(interpreter.Coster)
|
||||
if !ok {
|
||||
return 0, math.MaxInt64
|
||||
}
|
||||
return c.Cost()
|
||||
}
|
||||
|
||||
type ctxEvalActivation struct {
|
||||
parent interpreter.Activation
|
||||
interrupt <-chan struct{}
|
||||
interruptCheckCount uint
|
||||
interruptCheckFrequency uint
|
||||
}
|
||||
|
||||
// ResolveName implements the Activation interface method, but adds a special #interrupted variable
|
||||
// which is capable of testing whether a 'done' signal is provided from a context.Context channel.
|
||||
func (a *ctxEvalActivation) ResolveName(name string) (interface{}, bool) {
|
||||
if name == "#interrupted" {
|
||||
a.interruptCheckCount++
|
||||
if a.interruptCheckCount%a.interruptCheckFrequency == 0 {
|
||||
select {
|
||||
case <-a.interrupt:
|
||||
return true, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
return a.parent.ResolveName(name)
|
||||
}
|
||||
|
||||
func (a *ctxEvalActivation) Parent() interpreter.Activation {
|
||||
return a.parent
|
||||
}
|
||||
|
||||
func newCtxEvalActivationPool() *ctxEvalActivationPool {
|
||||
return &ctxEvalActivationPool{
|
||||
Pool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &ctxEvalActivation{}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type ctxEvalActivationPool struct {
|
||||
sync.Pool
|
||||
}
|
||||
|
||||
// Setup initializes a pooled Activation with the ability check for context.Context cancellation
|
||||
func (p *ctxEvalActivationPool) Setup(vars interpreter.Activation, done <-chan struct{}, interruptCheckRate uint) *ctxEvalActivation {
|
||||
a := p.Pool.Get().(*ctxEvalActivation)
|
||||
a.parent = vars
|
||||
a.interrupt = done
|
||||
a.interruptCheckCount = 0
|
||||
a.interruptCheckFrequency = interruptCheckRate
|
||||
return a
|
||||
}
|
||||
|
||||
type evalActivation struct {
|
||||
vars map[string]interface{}
|
||||
lazyVars map[string]interface{}
|
||||
}
|
||||
|
||||
// ResolveName looks up the value of the input variable name, if found.
|
||||
//
|
||||
// Lazy bindings may be supplied within the map-based input in either of the following forms:
|
||||
// - func() interface{}
|
||||
// - func() ref.Val
|
||||
//
|
||||
// The lazy binding will only be invoked once per evaluation.
|
||||
//
|
||||
// Values which are not represented as ref.Val types on input may be adapted to a ref.Val using
|
||||
// the ref.TypeAdapter configured in the environment.
|
||||
func (a *evalActivation) ResolveName(name string) (interface{}, bool) {
|
||||
v, found := a.vars[name]
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
switch obj := v.(type) {
|
||||
case func() ref.Val:
|
||||
if resolved, found := a.lazyVars[name]; found {
|
||||
return resolved, true
|
||||
}
|
||||
lazy := obj()
|
||||
a.lazyVars[name] = lazy
|
||||
return lazy, true
|
||||
case func() interface{}:
|
||||
if resolved, found := a.lazyVars[name]; found {
|
||||
return resolved, true
|
||||
}
|
||||
lazy := obj()
|
||||
a.lazyVars[name] = lazy
|
||||
return lazy, true
|
||||
default:
|
||||
return obj, true
|
||||
}
|
||||
}
|
||||
|
||||
// Parent implements the interpreter.Activation interface
|
||||
func (a *evalActivation) Parent() interpreter.Activation {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newEvalActivationPool() *evalActivationPool {
|
||||
return &evalActivationPool{
|
||||
Pool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &evalActivation{lazyVars: make(map[string]interface{})}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type evalActivationPool struct {
|
||||
sync.Pool
|
||||
}
|
||||
|
||||
// Setup initializes a pooled Activation object with the map input.
|
||||
func (p *evalActivationPool) Setup(vars map[string]interface{}) *evalActivation {
|
||||
a := p.Pool.Get().(*evalActivation)
|
||||
a.vars = vars
|
||||
return a
|
||||
}
|
||||
|
||||
func (p *evalActivationPool) Put(value interface{}) {
|
||||
a := value.(*evalActivation)
|
||||
for k := range a.lazyVars {
|
||||
delete(a.lazyVars, k)
|
||||
}
|
||||
p.Pool.Put(a)
|
||||
}
|
||||
|
||||
var (
|
||||
emptyEvalState = interpreter.NewEvalState()
|
||||
|
||||
// activationPool is an internally managed pool of Activation values that wrap map[string]interface{} inputs
|
||||
activationPool = newEvalActivationPool()
|
||||
|
||||
// ctxActivationPool is an internally managed pool of Activation values that expose a special #interrupted variable
|
||||
ctxActivationPool = newCtxEvalActivationPool()
|
||||
)
|
60
vendor/github.com/google/cel-go/checker/BUILD.bazel
generated
vendored
Normal file
60
vendor/github.com/google/cel-go/checker/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
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",
|
||||
"cost.go",
|
||||
"env.go",
|
||||
"errors.go",
|
||||
"mapping.go",
|
||||
"options.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",
|
||||
"cost_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_antlr4_runtime_go_antlr//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
641
vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
Normal file
641
vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
Normal file
@ -0,0 +1,641 @@
|
||||
// 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.GetExprKind().(type) {
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
literal := e.GetConstExpr()
|
||||
switch literal.GetConstantKind().(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().GetType())
|
||||
c.setReference(e, newIdentReference(ident.GetName(), ident.GetIdent().GetValue()))
|
||||
// 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 {
|
||||
// We don't check for a TestOnly expression here since the `found` result is
|
||||
// always going to be false for TestOnly expressions.
|
||||
|
||||
// Rewrite the node to be a variable reference to the resolved fully-qualified
|
||||
// variable name.
|
||||
c.setType(e, ident.GetIdent().Type)
|
||||
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.GetOperand())
|
||||
targetType := substitute(c.mappings, c.getType(sel.GetOperand()), false)
|
||||
// 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.GetValueType()
|
||||
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.GetField()); found {
|
||||
resultType = fieldType.Type
|
||||
}
|
||||
case kindTypeParam:
|
||||
// Set the operand type to DYN to prevent assignment to a potentially incorrect type
|
||||
// at a later point in type-checking. The isAssignable call will update the type
|
||||
// substitutions for the type param under the covers.
|
||||
c.isAssignable(decls.Dyn, targetType)
|
||||
// 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, substitute(c.mappings, resultType, false))
|
||||
}
|
||||
|
||||
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().GetOverloads() {
|
||||
// Determine whether the overload is currently considered.
|
||||
if c.env.isOverloadDisabled(overload.GetOverloadId()) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure the call style for the overload matches.
|
||||
if (target == nil && overload.GetIsInstanceFunction()) ||
|
||||
(target != nil && !overload.GetIsInstanceFunction()) {
|
||||
// not a compatible call style.
|
||||
continue
|
||||
}
|
||||
|
||||
overloadType := decls.NewFunctionType(overload.ResultType, overload.Params...)
|
||||
if len(overload.GetTypeParams()) > 0 {
|
||||
// Instantiate overload's type with fresh type variables.
|
||||
substitutions := newMapping()
|
||||
for _, typePar := range overload.GetTypeParams() {
|
||||
substitutions.add(decls.NewTypeParamType(typePar), c.newTypeVar())
|
||||
}
|
||||
overloadType = substitute(substitutions, overloadType, false)
|
||||
}
|
||||
|
||||
candidateArgTypes := overloadType.GetFunction().GetArgTypes()
|
||||
if c.isAssignableList(argTypes, candidateArgTypes) {
|
||||
if checkedRef == nil {
|
||||
checkedRef = newFunctionReference(overload.GetOverloadId())
|
||||
} else {
|
||||
checkedRef.OverloadId = append(checkedRef.GetOverloadId(), overload.GetOverloadId())
|
||||
}
|
||||
|
||||
// First matching overload, determines result type.
|
||||
fnResultType := substitute(c.mappings, overloadType.GetFunction().GetResultType(), 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.GetElements() {
|
||||
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.GetMessageName() != "" {
|
||||
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.GetMessageName())
|
||||
if decl == nil {
|
||||
c.errors.undeclaredReference(
|
||||
c.location(e), c.env.container.Name(), msgVal.GetMessageName())
|
||||
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.GetType())
|
||||
if identKind != kindError {
|
||||
if identKind != kindType {
|
||||
c.errors.notAType(c.location(e), ident.GetType())
|
||||
} else {
|
||||
messageType = ident.GetType().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.GetValue()
|
||||
c.check(value)
|
||||
|
||||
fieldType := decls.Error
|
||||
if t, found := c.lookupFieldType(
|
||||
c.locationByID(ent.GetId()),
|
||||
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.GetIterRange())
|
||||
c.check(comp.GetAccuInit())
|
||||
accuType := c.getType(comp.GetAccuInit())
|
||||
rangeType := substitute(c.mappings, c.getType(comp.GetIterRange()), false)
|
||||
var varType *exprpb.Type
|
||||
|
||||
switch kindOf(rangeType) {
|
||||
case kindList:
|
||||
varType = rangeType.GetListType().GetElemType()
|
||||
case kindMap:
|
||||
// Ranges over the keys.
|
||||
varType = rangeType.GetMapType().GetKeyType()
|
||||
case kindDyn, kindError, kindTypeParam:
|
||||
// Set the range type to DYN to prevent assignment to a potentially incorrect type
|
||||
// at a later point in type-checking. The isAssignable call will update the type
|
||||
// substitutions for the type param under the covers.
|
||||
c.isAssignable(decls.Dyn, rangeType)
|
||||
// Set the range iteration variable to type DYN as well.
|
||||
varType = decls.Dyn
|
||||
default:
|
||||
c.errors.notAComprehensionRange(c.location(comp.GetIterRange()), 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.GetAccuVar(), accuType))
|
||||
// Create a block scope for the loop.
|
||||
c.env = c.env.enterScope()
|
||||
c.env.Add(decls.NewVar(comp.GetIterVar(), varType))
|
||||
// Check the variable references in the condition and step.
|
||||
c.check(comp.GetLoopCondition())
|
||||
c.assertType(comp.GetLoopCondition(), decls.Bool)
|
||||
c.check(comp.GetLoopStep())
|
||||
c.assertType(comp.GetLoopStep(), accuType)
|
||||
// Exit the loop's block scope before checking the result.
|
||||
c.env = c.env.exitScope()
|
||||
c.check(comp.GetResult())
|
||||
// Exit the comprehension scope.
|
||||
c.env = c.env.exitScope()
|
||||
c.setType(e, substitute(c.mappings, c.getType(comp.GetResult()), false))
|
||||
}
|
||||
|
||||
// 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.GetId()]; 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.GetId()] = t
|
||||
}
|
||||
|
||||
func (c *checker) getType(e *exprpb.Expr) *exprpb.Type {
|
||||
return c.types[e.GetId()]
|
||||
}
|
||||
|
||||
func (c *checker) setReference(e *exprpb.Expr, r *exprpb.Reference) {
|
||||
if old, found := c.references[e.GetId()]; found && !proto.Equal(old, r) {
|
||||
c.errors.ReportError(c.location(e),
|
||||
"Reference already exists for expression: %v(%d) old:%v, new:%v", e, e.GetId(), old, r)
|
||||
return
|
||||
}
|
||||
c.references[e.GetId()] = 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.GetId())
|
||||
}
|
||||
|
||||
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.GetLineOffsets() {
|
||||
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}
|
||||
}
|
627
vendor/github.com/google/cel-go/checker/cost.go
generated
vendored
Normal file
627
vendor/github.com/google/cel-go/checker/cost.go
generated
vendored
Normal file
@ -0,0 +1,627 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/parser"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// WARNING: Any changes to cost calculations in this file require a corresponding change in interpreter/runtimecost.go
|
||||
|
||||
// CostEstimator estimates the sizes of variable length input data and the costs of functions.
|
||||
type CostEstimator interface {
|
||||
// EstimateSize returns a SizeEstimate for the given AstNode, or nil if
|
||||
// the estimator has no estimate to provide. The size is equivalent to the result of the CEL `size()` function:
|
||||
// length of strings and bytes, number of map entries or number of list items.
|
||||
// EstimateSize is only called for AstNodes where
|
||||
// CEL does not know the size; EstimateSize is not called for values defined inline in CEL where the size
|
||||
// is already obvious to CEL.
|
||||
EstimateSize(element AstNode) *SizeEstimate
|
||||
// EstimateCallCost returns the estimated cost of an invocation, or nil if
|
||||
// the estimator has no estimate to provide.
|
||||
EstimateCallCost(function, overloadID string, target *AstNode, args []AstNode) *CallEstimate
|
||||
}
|
||||
|
||||
// CallEstimate includes a CostEstimate for the call, and an optional estimate of the result object size.
|
||||
// The ResultSize should only be provided if the call results in a map, list, string or bytes.
|
||||
type CallEstimate struct {
|
||||
CostEstimate
|
||||
ResultSize *SizeEstimate
|
||||
}
|
||||
|
||||
// AstNode represents an AST node for the purpose of cost estimations.
|
||||
type AstNode interface {
|
||||
// Path returns a field path through the provided type declarations to the type of the AstNode, or nil if the AstNode does not
|
||||
// represent type directly reachable from the provided type declarations.
|
||||
// The first path element is a variable. All subsequent path elements are one of: field name, '@items', '@keys', '@values'.
|
||||
Path() []string
|
||||
// Type returns the deduced type of the AstNode.
|
||||
Type() *exprpb.Type
|
||||
// Expr returns the expression of the AstNode.
|
||||
Expr() *exprpb.Expr
|
||||
// ComputedSize returns a size estimate of the AstNode derived from information available in the CEL expression.
|
||||
// For constants and inline list and map declarations, the exact size is returned. For concatenated list, strings
|
||||
// and bytes, the size is derived from the size estimates of the operands. nil is returned if there is no
|
||||
// computed size available.
|
||||
ComputedSize() *SizeEstimate
|
||||
}
|
||||
|
||||
type astNode struct {
|
||||
path []string
|
||||
t *exprpb.Type
|
||||
expr *exprpb.Expr
|
||||
derivedSize *SizeEstimate
|
||||
}
|
||||
|
||||
func (e astNode) Path() []string {
|
||||
return e.path
|
||||
}
|
||||
|
||||
func (e astNode) Type() *exprpb.Type {
|
||||
return e.t
|
||||
}
|
||||
|
||||
func (e astNode) Expr() *exprpb.Expr {
|
||||
return e.expr
|
||||
}
|
||||
|
||||
func (e astNode) ComputedSize() *SizeEstimate {
|
||||
if e.derivedSize != nil {
|
||||
return e.derivedSize
|
||||
}
|
||||
var v uint64
|
||||
switch ek := e.expr.GetExprKind().(type) {
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
switch ck := ek.ConstExpr.GetConstantKind().(type) {
|
||||
case *exprpb.Constant_StringValue:
|
||||
v = uint64(len(ck.StringValue))
|
||||
case *exprpb.Constant_BytesValue:
|
||||
v = uint64(len(ck.BytesValue))
|
||||
case *exprpb.Constant_BoolValue, *exprpb.Constant_DoubleValue, *exprpb.Constant_DurationValue,
|
||||
*exprpb.Constant_Int64Value, *exprpb.Constant_TimestampValue, *exprpb.Constant_Uint64Value,
|
||||
*exprpb.Constant_NullValue:
|
||||
v = uint64(1)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
case *exprpb.Expr_ListExpr:
|
||||
v = uint64(len(ek.ListExpr.GetElements()))
|
||||
case *exprpb.Expr_StructExpr:
|
||||
if ek.StructExpr.GetMessageName() == "" {
|
||||
v = uint64(len(ek.StructExpr.GetEntries()))
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
return &SizeEstimate{Min: v, Max: v}
|
||||
}
|
||||
|
||||
// SizeEstimate represents an estimated size of a variable length string, bytes, map or list.
|
||||
type SizeEstimate struct {
|
||||
Min, Max uint64
|
||||
}
|
||||
|
||||
// Add adds to another SizeEstimate and returns the sum.
|
||||
// If add would result in an uint64 overflow, the result is math.MaxUint64.
|
||||
func (se SizeEstimate) Add(sizeEstimate SizeEstimate) SizeEstimate {
|
||||
return SizeEstimate{
|
||||
addUint64NoOverflow(se.Min, sizeEstimate.Min),
|
||||
addUint64NoOverflow(se.Max, sizeEstimate.Max),
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply multiplies by another SizeEstimate and returns the product.
|
||||
// If multiply would result in an uint64 overflow, the result is math.MaxUint64.
|
||||
func (se SizeEstimate) Multiply(sizeEstimate SizeEstimate) SizeEstimate {
|
||||
return SizeEstimate{
|
||||
multiplyUint64NoOverflow(se.Min, sizeEstimate.Min),
|
||||
multiplyUint64NoOverflow(se.Max, sizeEstimate.Max),
|
||||
}
|
||||
}
|
||||
|
||||
// MultiplyByCostFactor multiplies a SizeEstimate by a cost factor and returns the CostEstimate with the
|
||||
// nearest integer of the result, rounded up.
|
||||
func (se SizeEstimate) MultiplyByCostFactor(costPerUnit float64) CostEstimate {
|
||||
return CostEstimate{
|
||||
multiplyByCostFactor(se.Min, costPerUnit),
|
||||
multiplyByCostFactor(se.Max, costPerUnit),
|
||||
}
|
||||
}
|
||||
|
||||
// MultiplyByCost multiplies by the cost and returns the product.
|
||||
// If multiply would result in an uint64 overflow, the result is math.MaxUint64.
|
||||
func (se SizeEstimate) MultiplyByCost(cost CostEstimate) CostEstimate {
|
||||
return CostEstimate{
|
||||
multiplyUint64NoOverflow(se.Min, cost.Min),
|
||||
multiplyUint64NoOverflow(se.Max, cost.Max),
|
||||
}
|
||||
}
|
||||
|
||||
// Union returns a SizeEstimate that encompasses both input the SizeEstimate.
|
||||
func (se SizeEstimate) Union(size SizeEstimate) SizeEstimate {
|
||||
result := se
|
||||
if size.Min < result.Min {
|
||||
result.Min = size.Min
|
||||
}
|
||||
if size.Max > result.Max {
|
||||
result.Max = size.Max
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CostEstimate represents an estimated cost range and provides add and multiply operations
|
||||
// that do not overflow.
|
||||
type CostEstimate struct {
|
||||
Min, Max uint64
|
||||
}
|
||||
|
||||
// Add adds the costs and returns the sum.
|
||||
// If add would result in an uint64 overflow for the min or max, the value is set to math.MaxUint64.
|
||||
func (ce CostEstimate) Add(cost CostEstimate) CostEstimate {
|
||||
return CostEstimate{
|
||||
addUint64NoOverflow(ce.Min, cost.Min),
|
||||
addUint64NoOverflow(ce.Max, cost.Max),
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply multiplies by the cost and returns the product.
|
||||
// If multiply would result in an uint64 overflow, the result is math.MaxUint64.
|
||||
func (ce CostEstimate) Multiply(cost CostEstimate) CostEstimate {
|
||||
return CostEstimate{
|
||||
multiplyUint64NoOverflow(ce.Min, cost.Min),
|
||||
multiplyUint64NoOverflow(ce.Max, cost.Max),
|
||||
}
|
||||
}
|
||||
|
||||
// MultiplyByCostFactor multiplies a CostEstimate by a cost factor and returns the CostEstimate with the
|
||||
// nearest integer of the result, rounded up.
|
||||
func (ce CostEstimate) MultiplyByCostFactor(costPerUnit float64) CostEstimate {
|
||||
return CostEstimate{
|
||||
multiplyByCostFactor(ce.Min, costPerUnit),
|
||||
multiplyByCostFactor(ce.Max, costPerUnit),
|
||||
}
|
||||
}
|
||||
|
||||
// Union returns a CostEstimate that encompasses both input the CostEstimates.
|
||||
func (ce CostEstimate) Union(size CostEstimate) CostEstimate {
|
||||
result := ce
|
||||
if size.Min < result.Min {
|
||||
result.Min = size.Min
|
||||
}
|
||||
if size.Max > result.Max {
|
||||
result.Max = size.Max
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// addUint64NoOverflow adds non-negative ints. If the result is exceeds math.MaxUint64, math.MaxUint64
|
||||
// is returned.
|
||||
func addUint64NoOverflow(x, y uint64) uint64 {
|
||||
if y > 0 && x > math.MaxUint64-y {
|
||||
return math.MaxUint64
|
||||
}
|
||||
return x + y
|
||||
}
|
||||
|
||||
// multiplyUint64NoOverflow multiplies non-negative ints. If the result is exceeds math.MaxUint64, math.MaxUint64
|
||||
// is returned.
|
||||
func multiplyUint64NoOverflow(x, y uint64) uint64 {
|
||||
if x > 0 && y > 0 && x > math.MaxUint64/y {
|
||||
return math.MaxUint64
|
||||
}
|
||||
return x * y
|
||||
}
|
||||
|
||||
// multiplyByFactor multiplies an integer by a cost factor float and returns the nearest integer value, rounded up.
|
||||
func multiplyByCostFactor(x uint64, y float64) uint64 {
|
||||
xFloat := float64(x)
|
||||
if xFloat > 0 && y > 0 && xFloat > math.MaxUint64/y {
|
||||
return math.MaxUint64
|
||||
}
|
||||
return uint64(math.Ceil(xFloat * y))
|
||||
}
|
||||
|
||||
var (
|
||||
selectAndIdentCost = CostEstimate{Min: common.SelectAndIdentCost, Max: common.SelectAndIdentCost}
|
||||
constCost = CostEstimate{Min: common.ConstCost, Max: common.ConstCost}
|
||||
|
||||
createListBaseCost = CostEstimate{Min: common.ListCreateBaseCost, Max: common.ListCreateBaseCost}
|
||||
createMapBaseCost = CostEstimate{Min: common.MapCreateBaseCost, Max: common.MapCreateBaseCost}
|
||||
createMessageBaseCost = CostEstimate{Min: common.StructCreateBaseCost, Max: common.StructCreateBaseCost}
|
||||
)
|
||||
|
||||
type coster struct {
|
||||
// exprPath maps from Expr Id to field path.
|
||||
exprPath map[int64][]string
|
||||
// iterRanges tracks the iterRange of each iterVar.
|
||||
iterRanges iterRangeScopes
|
||||
// computedSizes tracks the computed sizes of call results.
|
||||
computedSizes map[int64]SizeEstimate
|
||||
checkedExpr *exprpb.CheckedExpr
|
||||
estimator CostEstimator
|
||||
}
|
||||
|
||||
// Use a stack of iterVar -> iterRange Expr Ids to handle shadowed variable names.
|
||||
type iterRangeScopes map[string][]int64
|
||||
|
||||
func (vs iterRangeScopes) push(varName string, expr *exprpb.Expr) {
|
||||
vs[varName] = append(vs[varName], expr.GetId())
|
||||
}
|
||||
|
||||
func (vs iterRangeScopes) pop(varName string) {
|
||||
varStack := vs[varName]
|
||||
vs[varName] = varStack[:len(varStack)-1]
|
||||
}
|
||||
|
||||
func (vs iterRangeScopes) peek(varName string) (int64, bool) {
|
||||
varStack := vs[varName]
|
||||
if len(varStack) > 0 {
|
||||
return varStack[len(varStack)-1], true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Cost estimates the cost of the parsed and type checked CEL expression.
|
||||
func Cost(checker *exprpb.CheckedExpr, estimator CostEstimator) CostEstimate {
|
||||
c := coster{
|
||||
checkedExpr: checker,
|
||||
estimator: estimator,
|
||||
exprPath: map[int64][]string{},
|
||||
iterRanges: map[string][]int64{},
|
||||
computedSizes: map[int64]SizeEstimate{},
|
||||
}
|
||||
return c.cost(checker.GetExpr())
|
||||
}
|
||||
|
||||
func (c *coster) cost(e *exprpb.Expr) CostEstimate {
|
||||
if e == nil {
|
||||
return CostEstimate{}
|
||||
}
|
||||
var cost CostEstimate
|
||||
switch e.GetExprKind().(type) {
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
cost = constCost
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
cost = c.costIdent(e)
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
cost = c.costSelect(e)
|
||||
case *exprpb.Expr_CallExpr:
|
||||
cost = c.costCall(e)
|
||||
case *exprpb.Expr_ListExpr:
|
||||
cost = c.costCreateList(e)
|
||||
case *exprpb.Expr_StructExpr:
|
||||
cost = c.costCreateStruct(e)
|
||||
case *exprpb.Expr_ComprehensionExpr:
|
||||
cost = c.costComprehension(e)
|
||||
default:
|
||||
return CostEstimate{}
|
||||
}
|
||||
return cost
|
||||
}
|
||||
|
||||
func (c *coster) costIdent(e *exprpb.Expr) CostEstimate {
|
||||
identExpr := e.GetIdentExpr()
|
||||
|
||||
// build and track the field path
|
||||
if iterRange, ok := c.iterRanges.peek(identExpr.GetName()); ok {
|
||||
switch c.checkedExpr.TypeMap[iterRange].GetTypeKind().(type) {
|
||||
case *exprpb.Type_ListType_:
|
||||
c.addPath(e, append(c.exprPath[iterRange], "@items"))
|
||||
case *exprpb.Type_MapType_:
|
||||
c.addPath(e, append(c.exprPath[iterRange], "@keys"))
|
||||
}
|
||||
} else {
|
||||
c.addPath(e, []string{identExpr.GetName()})
|
||||
}
|
||||
|
||||
return selectAndIdentCost
|
||||
}
|
||||
|
||||
func (c *coster) costSelect(e *exprpb.Expr) CostEstimate {
|
||||
sel := e.GetSelectExpr()
|
||||
var sum CostEstimate
|
||||
if sel.GetTestOnly() {
|
||||
return sum
|
||||
}
|
||||
sum = sum.Add(c.cost(sel.GetOperand()))
|
||||
targetType := c.getType(sel.GetOperand())
|
||||
switch kindOf(targetType) {
|
||||
case kindMap, kindObject, kindTypeParam:
|
||||
sum = sum.Add(selectAndIdentCost)
|
||||
}
|
||||
|
||||
// build and track the field path
|
||||
c.addPath(e, append(c.getPath(sel.GetOperand()), sel.GetField()))
|
||||
|
||||
return sum
|
||||
}
|
||||
|
||||
func (c *coster) costCall(e *exprpb.Expr) CostEstimate {
|
||||
call := e.GetCallExpr()
|
||||
target := call.GetTarget()
|
||||
args := call.GetArgs()
|
||||
|
||||
var sum CostEstimate
|
||||
|
||||
argTypes := make([]AstNode, len(args))
|
||||
argCosts := make([]CostEstimate, len(args))
|
||||
for i, arg := range args {
|
||||
argCosts[i] = c.cost(arg)
|
||||
argTypes[i] = c.newAstNode(arg)
|
||||
}
|
||||
|
||||
ref := c.checkedExpr.ReferenceMap[e.GetId()]
|
||||
if ref == nil || len(ref.GetOverloadId()) == 0 {
|
||||
return CostEstimate{}
|
||||
}
|
||||
var targetType AstNode
|
||||
if target != nil {
|
||||
if call.Target != nil {
|
||||
sum = sum.Add(c.cost(call.GetTarget()))
|
||||
targetType = c.newAstNode(call.GetTarget())
|
||||
}
|
||||
}
|
||||
// Pick a cost estimate range that covers all the overload cost estimation ranges
|
||||
fnCost := CostEstimate{Min: uint64(math.MaxUint64), Max: 0}
|
||||
var resultSize *SizeEstimate
|
||||
for _, overload := range ref.GetOverloadId() {
|
||||
overloadCost := c.functionCost(call.GetFunction(), overload, &targetType, argTypes, argCosts)
|
||||
fnCost = fnCost.Union(overloadCost.CostEstimate)
|
||||
if overloadCost.ResultSize != nil {
|
||||
if resultSize == nil {
|
||||
resultSize = overloadCost.ResultSize
|
||||
} else {
|
||||
size := resultSize.Union(*overloadCost.ResultSize)
|
||||
resultSize = &size
|
||||
}
|
||||
}
|
||||
// build and track the field path for index operations
|
||||
switch overload {
|
||||
case overloads.IndexList:
|
||||
if len(args) > 0 {
|
||||
c.addPath(e, append(c.getPath(args[0]), "@items"))
|
||||
}
|
||||
case overloads.IndexMap:
|
||||
if len(args) > 0 {
|
||||
c.addPath(e, append(c.getPath(args[0]), "@values"))
|
||||
}
|
||||
}
|
||||
}
|
||||
if resultSize != nil {
|
||||
c.computedSizes[e.GetId()] = *resultSize
|
||||
}
|
||||
return sum.Add(fnCost)
|
||||
}
|
||||
|
||||
func (c *coster) costCreateList(e *exprpb.Expr) CostEstimate {
|
||||
create := e.GetListExpr()
|
||||
var sum CostEstimate
|
||||
for _, e := range create.GetElements() {
|
||||
sum = sum.Add(c.cost(e))
|
||||
}
|
||||
return sum.Add(createListBaseCost)
|
||||
}
|
||||
|
||||
func (c *coster) costCreateStruct(e *exprpb.Expr) CostEstimate {
|
||||
str := e.GetStructExpr()
|
||||
if str.MessageName != "" {
|
||||
return c.costCreateMessage(e)
|
||||
}
|
||||
return c.costCreateMap(e)
|
||||
}
|
||||
|
||||
func (c *coster) costCreateMap(e *exprpb.Expr) CostEstimate {
|
||||
mapVal := e.GetStructExpr()
|
||||
var sum CostEstimate
|
||||
for _, ent := range mapVal.GetEntries() {
|
||||
key := ent.GetMapKey()
|
||||
sum = sum.Add(c.cost(key))
|
||||
|
||||
sum = sum.Add(c.cost(ent.GetValue()))
|
||||
}
|
||||
return sum.Add(createMapBaseCost)
|
||||
}
|
||||
|
||||
func (c *coster) costCreateMessage(e *exprpb.Expr) CostEstimate {
|
||||
msgVal := e.GetStructExpr()
|
||||
var sum CostEstimate
|
||||
for _, ent := range msgVal.GetEntries() {
|
||||
sum = sum.Add(c.cost(ent.GetValue()))
|
||||
}
|
||||
return sum.Add(createMessageBaseCost)
|
||||
}
|
||||
|
||||
func (c *coster) costComprehension(e *exprpb.Expr) CostEstimate {
|
||||
comp := e.GetComprehensionExpr()
|
||||
var sum CostEstimate
|
||||
sum = sum.Add(c.cost(comp.GetIterRange()))
|
||||
sum = sum.Add(c.cost(comp.GetAccuInit()))
|
||||
|
||||
// Track the iterRange of each IterVar for field path construction
|
||||
c.iterRanges.push(comp.GetIterVar(), comp.GetIterRange())
|
||||
loopCost := c.cost(comp.GetLoopCondition())
|
||||
stepCost := c.cost(comp.GetLoopStep())
|
||||
c.iterRanges.pop(comp.GetIterVar())
|
||||
sum = sum.Add(c.cost(comp.Result))
|
||||
rangeCnt := c.sizeEstimate(c.newAstNode(comp.GetIterRange()))
|
||||
rangeCost := rangeCnt.MultiplyByCost(stepCost.Add(loopCost))
|
||||
sum = sum.Add(rangeCost)
|
||||
|
||||
return sum
|
||||
}
|
||||
|
||||
func (c *coster) sizeEstimate(t AstNode) SizeEstimate {
|
||||
if l := t.ComputedSize(); l != nil {
|
||||
return *l
|
||||
}
|
||||
if l := c.estimator.EstimateSize(t); l != nil {
|
||||
return *l
|
||||
}
|
||||
// return an estimate of 1 for return types of set
|
||||
// lengths, since strings/bytes/more complex objects could be of
|
||||
// variable length
|
||||
if isScalar(t.Type()) {
|
||||
// TODO: since the logic for size estimation is split between
|
||||
// ComputedSize and isScalar, changing one will likely require changing
|
||||
// the other, so they should be merged in the future if possible
|
||||
return SizeEstimate{Min: 1, Max: 1}
|
||||
}
|
||||
return SizeEstimate{Min: 0, Max: math.MaxUint64}
|
||||
}
|
||||
|
||||
func (c *coster) functionCost(function, overloadID string, target *AstNode, args []AstNode, argCosts []CostEstimate) CallEstimate {
|
||||
argCostSum := func() CostEstimate {
|
||||
var sum CostEstimate
|
||||
for _, a := range argCosts {
|
||||
sum = sum.Add(a)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
if est := c.estimator.EstimateCallCost(function, overloadID, target, args); est != nil {
|
||||
callEst := *est
|
||||
return CallEstimate{CostEstimate: callEst.Add(argCostSum())}
|
||||
}
|
||||
switch overloadID {
|
||||
// O(n) functions
|
||||
case overloads.StartsWithString, overloads.EndsWithString, overloads.StringToBytes, overloads.BytesToString:
|
||||
if len(args) == 1 {
|
||||
return CallEstimate{CostEstimate: c.sizeEstimate(args[0]).MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum())}
|
||||
}
|
||||
case overloads.InList:
|
||||
// If a list is composed entirely of constant values this is O(1), but we don't account for that here.
|
||||
// We just assume all list containment checks are O(n).
|
||||
if len(args) == 2 {
|
||||
return CallEstimate{CostEstimate: c.sizeEstimate(args[1]).MultiplyByCostFactor(1).Add(argCostSum())}
|
||||
}
|
||||
// O(nm) functions
|
||||
case overloads.MatchesString:
|
||||
// https://swtch.com/~rsc/regexp/regexp1.html applies to RE2 implementation supported by CEL
|
||||
if target != nil && len(args) == 1 {
|
||||
// Add one to string length for purposes of cost calculation to prevent product of string and regex to be 0
|
||||
// in case where string is empty but regex is still expensive.
|
||||
strCost := c.sizeEstimate(*target).Add(SizeEstimate{Min: 1, Max: 1}).MultiplyByCostFactor(common.StringTraversalCostFactor)
|
||||
// We don't know how many expressions are in the regex, just the string length (a huge
|
||||
// improvement here would be to somehow get a count the number of expressions in the regex or
|
||||
// how many states are in the regex state machine and use that to measure regex cost).
|
||||
// For now, we're making a guess that each expression in a regex is typically at least 4 chars
|
||||
// in length.
|
||||
regexCost := c.sizeEstimate(args[0]).MultiplyByCostFactor(common.RegexStringLengthCostFactor)
|
||||
return CallEstimate{CostEstimate: strCost.Multiply(regexCost).Add(argCostSum())}
|
||||
}
|
||||
case overloads.ContainsString:
|
||||
if target != nil && len(args) == 1 {
|
||||
strCost := c.sizeEstimate(*target).MultiplyByCostFactor(common.StringTraversalCostFactor)
|
||||
substrCost := c.sizeEstimate(args[0]).MultiplyByCostFactor(common.StringTraversalCostFactor)
|
||||
return CallEstimate{CostEstimate: strCost.Multiply(substrCost).Add(argCostSum())}
|
||||
}
|
||||
case overloads.LogicalOr, overloads.LogicalAnd:
|
||||
lhs := argCosts[0]
|
||||
rhs := argCosts[1]
|
||||
// min cost is min of LHS for short circuited && or ||
|
||||
argCost := CostEstimate{Min: lhs.Min, Max: lhs.Add(rhs).Max}
|
||||
return CallEstimate{CostEstimate: argCost}
|
||||
case overloads.Conditional:
|
||||
size := c.sizeEstimate(args[1]).Union(c.sizeEstimate(args[2]))
|
||||
conditionalCost := argCosts[0]
|
||||
ifTrueCost := argCosts[1]
|
||||
ifFalseCost := argCosts[2]
|
||||
argCost := conditionalCost.Add(ifTrueCost.Union(ifFalseCost))
|
||||
return CallEstimate{CostEstimate: argCost, ResultSize: &size}
|
||||
case overloads.AddString, overloads.AddBytes, overloads.AddList:
|
||||
if len(args) == 2 {
|
||||
lhsSize := c.sizeEstimate(args[0])
|
||||
rhsSize := c.sizeEstimate(args[1])
|
||||
resultSize := lhsSize.Add(rhsSize)
|
||||
switch overloadID {
|
||||
case overloads.AddList:
|
||||
// list concatenation is O(1), but we handle it here to track size
|
||||
return CallEstimate{CostEstimate: CostEstimate{Min: 1, Max: 1}.Add(argCostSum()), ResultSize: &resultSize}
|
||||
default:
|
||||
return CallEstimate{CostEstimate: resultSize.MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum()), ResultSize: &resultSize}
|
||||
}
|
||||
}
|
||||
case overloads.LessString, overloads.GreaterString, overloads.LessEqualsString, overloads.GreaterEqualsString,
|
||||
overloads.LessBytes, overloads.GreaterBytes, overloads.LessEqualsBytes, overloads.GreaterEqualsBytes,
|
||||
overloads.Equals, overloads.NotEquals:
|
||||
lhsCost := c.sizeEstimate(args[0])
|
||||
rhsCost := c.sizeEstimate(args[1])
|
||||
min := uint64(0)
|
||||
smallestMax := lhsCost.Max
|
||||
if rhsCost.Max < smallestMax {
|
||||
smallestMax = rhsCost.Max
|
||||
}
|
||||
if smallestMax > 0 {
|
||||
min = 1
|
||||
}
|
||||
// equality of 2 scalar values results in a cost of 1
|
||||
return CallEstimate{CostEstimate: CostEstimate{Min: min, Max: smallestMax}.MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum())}
|
||||
}
|
||||
// O(1) functions
|
||||
// See CostTracker.costCall for more details about O(1) cost calculations
|
||||
|
||||
// Benchmarks suggest that most of the other operations take +/- 50% of a base cost unit
|
||||
// which on an Intel xeon 2.20GHz CPU is 50ns.
|
||||
return CallEstimate{CostEstimate: CostEstimate{Min: 1, Max: 1}.Add(argCostSum())}
|
||||
}
|
||||
|
||||
func (c *coster) getType(e *exprpb.Expr) *exprpb.Type {
|
||||
return c.checkedExpr.TypeMap[e.GetId()]
|
||||
}
|
||||
|
||||
func (c *coster) getPath(e *exprpb.Expr) []string {
|
||||
return c.exprPath[e.GetId()]
|
||||
}
|
||||
|
||||
func (c *coster) addPath(e *exprpb.Expr, path []string) {
|
||||
c.exprPath[e.GetId()] = path
|
||||
}
|
||||
|
||||
func (c *coster) newAstNode(e *exprpb.Expr) *astNode {
|
||||
path := c.getPath(e)
|
||||
if len(path) > 0 && path[0] == parser.AccumulatorName {
|
||||
// only provide paths to root vars; omit accumulator vars
|
||||
path = nil
|
||||
}
|
||||
var derivedSize *SizeEstimate
|
||||
if size, ok := c.computedSizes[e.GetId()]; ok {
|
||||
derivedSize = &size
|
||||
}
|
||||
return &astNode{path: path, t: c.getType(e), expr: e, derivedSize: derivedSize}
|
||||
}
|
||||
|
||||
// isScalar returns true if the given type is known to be of a constant size at
|
||||
// compile time. isScalar will return false for strings (they are variable-width)
|
||||
// in addition to protobuf.Any and protobuf.Value (their size is not knowable at compile time).
|
||||
func isScalar(t *exprpb.Type) bool {
|
||||
switch kindOf(t) {
|
||||
case kindPrimitive:
|
||||
if t.GetPrimitive() != exprpb.Type_STRING && t.GetPrimitive() != exprpb.Type_BYTES {
|
||||
return true
|
||||
}
|
||||
case kindWellKnown:
|
||||
if t.GetWellKnown() == exprpb.Type_DURATION || t.GetWellKnown() == exprpb.Type_TIMESTAMP {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
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}}
|
||||
}
|
145
vendor/github.com/google/cel-go/checker/decls/scopes.go
generated
vendored
Normal file
145
vendor/github.com/google/cel-go/checker/decls/scopes.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 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(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy creates a copy of the current Scopes values, including a copy of its parent if non-nil.
|
||||
func (s *Scopes) Copy() *Scopes {
|
||||
cpy := NewScopes()
|
||||
if s == nil {
|
||||
return cpy
|
||||
}
|
||||
if s.parent != nil {
|
||||
cpy.parent = s.parent.Copy()
|
||||
}
|
||||
cpy.scopes = s.scopes.copy()
|
||||
return cpy
|
||||
}
|
||||
|
||||
// Push creates a new Scopes value which references the current Scope as its parent.
|
||||
func (s *Scopes) Push() *Scopes {
|
||||
return &Scopes{
|
||||
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
|
||||
}
|
||||
|
||||
// SetFunction adds the function Decl to the current scope.
|
||||
// Note: Any previous entry for a function in the current scope with the same name is overwritten.
|
||||
func (s *Scopes) SetFunction(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 identifier and function Decls.
|
||||
// (Should be named "Scope" perhaps?)
|
||||
type Group struct {
|
||||
idents map[string]*exprpb.Decl
|
||||
functions map[string]*exprpb.Decl
|
||||
}
|
||||
|
||||
// copy creates a new Group instance with a shallow copy of the variables and functions.
|
||||
// If callers need to mutate the exprpb.Decl definitions for a Function, they should copy-on-write.
|
||||
func (g *Group) copy() *Group {
|
||||
cpy := &Group{
|
||||
idents: make(map[string]*exprpb.Decl, len(g.idents)),
|
||||
functions: make(map[string]*exprpb.Decl, len(g.functions)),
|
||||
}
|
||||
for n, id := range g.idents {
|
||||
cpy.idents[n] = id
|
||||
}
|
||||
for n, fn := range g.functions {
|
||||
cpy.functions[n] = fn
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
// newGroup creates a new Group with empty maps for identifiers and functions.
|
||||
func newGroup() *Group {
|
||||
return &Group{
|
||||
idents: make(map[string]*exprpb.Decl),
|
||||
functions: make(map[string]*exprpb.Decl),
|
||||
}
|
||||
}
|
411
vendor/github.com/google/cel-go/checker/env.go
generated
vendored
Normal file
411
vendor/github.com/google/cel-go/checker/env.go
generated
vendored
Normal file
@ -0,0 +1,411 @@
|
||||
// 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"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"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
|
||||
)
|
||||
|
||||
var (
|
||||
crossTypeNumericComparisonOverloads = map[string]struct{}{
|
||||
// double <-> int | uint
|
||||
overloads.LessDoubleInt64: {},
|
||||
overloads.LessDoubleUint64: {},
|
||||
overloads.LessEqualsDoubleInt64: {},
|
||||
overloads.LessEqualsDoubleUint64: {},
|
||||
overloads.GreaterDoubleInt64: {},
|
||||
overloads.GreaterDoubleUint64: {},
|
||||
overloads.GreaterEqualsDoubleInt64: {},
|
||||
overloads.GreaterEqualsDoubleUint64: {},
|
||||
// int <-> double | uint
|
||||
overloads.LessInt64Double: {},
|
||||
overloads.LessInt64Uint64: {},
|
||||
overloads.LessEqualsInt64Double: {},
|
||||
overloads.LessEqualsInt64Uint64: {},
|
||||
overloads.GreaterInt64Double: {},
|
||||
overloads.GreaterInt64Uint64: {},
|
||||
overloads.GreaterEqualsInt64Double: {},
|
||||
overloads.GreaterEqualsInt64Uint64: {},
|
||||
// uint <-> double | int
|
||||
overloads.LessUint64Double: {},
|
||||
overloads.LessUint64Int64: {},
|
||||
overloads.LessEqualsUint64Double: {},
|
||||
overloads.LessEqualsUint64Int64: {},
|
||||
overloads.GreaterUint64Double: {},
|
||||
overloads.GreaterUint64Int64: {},
|
||||
overloads.GreaterEqualsUint64Double: {},
|
||||
overloads.GreaterEqualsUint64Int64: {},
|
||||
}
|
||||
)
|
||||
|
||||
// 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
|
||||
filteredOverloadIDs map[string]struct{}
|
||||
}
|
||||
|
||||
// NewEnv returns a new *Env with the given parameters.
|
||||
func NewEnv(container *containers.Container, provider ref.TypeProvider, opts ...Option) (*Env, error) {
|
||||
declarations := decls.NewScopes()
|
||||
declarations.Push()
|
||||
|
||||
envOptions := &options{}
|
||||
for _, opt := range opts {
|
||||
if err := opt(envOptions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
aggLitElemType := dynElementType
|
||||
if envOptions.homogeneousAggregateLiterals {
|
||||
aggLitElemType = homogenousElementType
|
||||
}
|
||||
filteredOverloadIDs := crossTypeNumericComparisonOverloads
|
||||
if envOptions.crossTypeNumericComparisons {
|
||||
filteredOverloadIDs = make(map[string]struct{})
|
||||
}
|
||||
if envOptions.validatedDeclarations != nil {
|
||||
declarations = envOptions.validatedDeclarations.Copy()
|
||||
}
|
||||
return &Env{
|
||||
container: container,
|
||||
provider: provider,
|
||||
declarations: declarations,
|
||||
aggLitElemType: aggLitElemType,
|
||||
filteredOverloadIDs: filteredOverloadIDs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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.setFunction(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
|
||||
}
|
||||
|
||||
// setFunction adds the function Decl to the Env.
|
||||
// Adds a function decl if one doesn't already exist, then adds all overloads from the Decl.
|
||||
// If overload overlaps with an existing overload, adds to the errors in the Env instead.
|
||||
func (e *Env) setFunction(decl *exprpb.Decl) []errorMsg {
|
||||
errorMsgs := make([]errorMsg, 0)
|
||||
overloads := decl.GetFunction().GetOverloads()
|
||||
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)
|
||||
} else {
|
||||
existingOverloads := map[string]*exprpb.Decl_FunctionDecl_Overload{}
|
||||
for _, overload := range current.GetFunction().GetOverloads() {
|
||||
existingOverloads[overload.GetOverloadId()] = overload
|
||||
}
|
||||
newOverloads := []*exprpb.Decl_FunctionDecl_Overload{}
|
||||
for _, overload := range overloads {
|
||||
existing, found := existingOverloads[overload.GetOverloadId()]
|
||||
if !found || !proto.Equal(existing, overload) {
|
||||
newOverloads = append(newOverloads, overload)
|
||||
}
|
||||
}
|
||||
overloads = newOverloads
|
||||
if len(newOverloads) == 0 {
|
||||
return errorMsgs
|
||||
}
|
||||
// Copy on write since we don't know where this original definition came from.
|
||||
current = proto.Clone(current).(*exprpb.Decl)
|
||||
}
|
||||
e.declarations.SetFunction(current)
|
||||
for _, overload := range overloads {
|
||||
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 {
|
||||
if proto.Equal(current, decl) {
|
||||
return ""
|
||||
}
|
||||
return overlappingIdentifierError(decl.Name)
|
||||
}
|
||||
e.declarations.AddIdent(decl)
|
||||
return ""
|
||||
}
|
||||
|
||||
// isOverloadDisabled returns whether the overloadID is disabled in the current environment.
|
||||
func (e *Env) isOverloadDisabled(overloadID string) bool {
|
||||
_, found := e.filteredOverloadIDs[overloadID]
|
||||
return found
|
||||
}
|
||||
|
||||
// sanitizeFunction replaces well-known types referenced by message name with their equivalent
|
||||
// CEL built-in type instances.
|
||||
func sanitizeFunction(decl *exprpb.Decl) *exprpb.Decl {
|
||||
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()]
|
||||
}
|
||||
|
||||
// validatedDeclarations returns a reference to the validated variable and function declaration scope stack.
|
||||
// must be copied before use.
|
||||
func (e *Env) validatedDeclarations() *decls.Scopes {
|
||||
return e.declarations
|
||||
}
|
||||
|
||||
// enterScope creates a new Env instance with a new innermost declaration scope.
|
||||
func (e *Env) enterScope() *Env {
|
||||
childDecls := e.declarations.Push()
|
||||
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
|
||||
}
|
96
vendor/github.com/google/cel-go/checker/errors.go
generated
vendored
Normal file
96
vendor/github.com/google/cel-go/checker/errors.go
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
// 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) 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
|
||||
}
|
53
vendor/github.com/google/cel-go/checker/options.go
generated
vendored
Normal file
53
vendor/github.com/google/cel-go/checker/options.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package checker
|
||||
|
||||
import "github.com/google/cel-go/checker/decls"
|
||||
|
||||
type options struct {
|
||||
crossTypeNumericComparisons bool
|
||||
homogeneousAggregateLiterals bool
|
||||
validatedDeclarations *decls.Scopes
|
||||
}
|
||||
|
||||
// Option is a functional option for configuring the type-checker
|
||||
type Option func(*options) error
|
||||
|
||||
// CrossTypeNumericComparisons toggles type-checker support for numeric comparisons across type
|
||||
// See https://github.com/google/cel-spec/wiki/proposal-210 for more details.
|
||||
func CrossTypeNumericComparisons(enabled bool) Option {
|
||||
return func(opts *options) error {
|
||||
opts.crossTypeNumericComparisons = enabled
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// HomogeneousAggregateLiterals toggles support for constructing lists and maps whose elements all
|
||||
// have the same type.
|
||||
func HomogeneousAggregateLiterals(enabled bool) Option {
|
||||
return func(opts *options) error {
|
||||
opts.homogeneousAggregateLiterals = enabled
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ValidatedDeclarations provides a references to validated declarations which will be copied
|
||||
// into new checker instances.
|
||||
func ValidatedDeclarations(env *Env) Option {
|
||||
return func(opts *options) error {
|
||||
opts.validatedDeclarations = env.validatedDeclarations()
|
||||
return nil
|
||||
}
|
||||
}
|
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.GetId()]
|
||||
if t != nil {
|
||||
result += "~"
|
||||
result += FormatCheckedType(t)
|
||||
}
|
||||
|
||||
switch e.GetExprKind().(type) {
|
||||
case *exprpb.Expr_IdentExpr,
|
||||
*exprpb.Expr_CallExpr,
|
||||
*exprpb.Expr_StructExpr,
|
||||
*exprpb.Expr_SelectExpr:
|
||||
if ref, found := a.checks.ReferenceMap[e.GetId()]; found {
|
||||
if len(ref.GetOverloadId()) == 0 {
|
||||
result += "^" + ref.Name
|
||||
} else {
|
||||
for i, overload := range ref.GetOverloadId() {
|
||||
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)
|
||||
}
|
492
vendor/github.com/google/cel-go/checker/standard.go
generated
vendored
Normal file
492
vendor/github.com/google/cel-go/checker/standard.go
generated
vendored
Normal file
@ -0,0 +1,492 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
var (
|
||||
standardDeclarations []*exprpb.Decl
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 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))))
|
||||
|
||||
standardDeclarations = append(standardDeclarations, idents...)
|
||||
standardDeclarations = append(standardDeclarations, []*exprpb.Decl{
|
||||
// Booleans
|
||||
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)),
|
||||
|
||||
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)),
|
||||
|
||||
// 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)),
|
||||
|
||||
// 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)),
|
||||
|
||||
// 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.LessInt64Double,
|
||||
[]*exprpb.Type{decls.Int, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessInt64Uint64,
|
||||
[]*exprpb.Type{decls.Int, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessUint64Double,
|
||||
[]*exprpb.Type{decls.Uint, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessUint64Int64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessDoubleInt64,
|
||||
[]*exprpb.Type{decls.Double, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessDoubleUint64,
|
||||
[]*exprpb.Type{decls.Double, decls.Uint}, 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.LessEqualsInt64Double,
|
||||
[]*exprpb.Type{decls.Int, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsInt64Uint64,
|
||||
[]*exprpb.Type{decls.Int, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsUint64Double,
|
||||
[]*exprpb.Type{decls.Uint, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsUint64Int64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsDoubleInt64,
|
||||
[]*exprpb.Type{decls.Double, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.LessEqualsDoubleUint64,
|
||||
[]*exprpb.Type{decls.Double, decls.Uint}, 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.GreaterInt64Double,
|
||||
[]*exprpb.Type{decls.Int, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterInt64Uint64,
|
||||
[]*exprpb.Type{decls.Int, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterUint64Double,
|
||||
[]*exprpb.Type{decls.Uint, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterUint64Int64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterDoubleInt64,
|
||||
[]*exprpb.Type{decls.Double, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterDoubleUint64,
|
||||
[]*exprpb.Type{decls.Double, decls.Uint}, 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.GreaterEqualsInt64Double,
|
||||
[]*exprpb.Type{decls.Int, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsInt64Uint64,
|
||||
[]*exprpb.Type{decls.Int, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsUint64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Uint}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsUint64Double,
|
||||
[]*exprpb.Type{decls.Uint, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsUint64Int64,
|
||||
[]*exprpb.Type{decls.Uint, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsDouble,
|
||||
[]*exprpb.Type{decls.Double, decls.Double}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsDoubleInt64,
|
||||
[]*exprpb.Type{decls.Double, decls.Int}, decls.Bool),
|
||||
decls.NewOverload(overloads.GreaterEqualsDoubleUint64,
|
||||
[]*exprpb.Type{decls.Double, decls.Uint}, 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)),
|
||||
}...)
|
||||
}
|
||||
|
||||
// StandardDeclarations returns the Decls for all functions and constants in the evaluator.
|
||||
func StandardDeclarations() []*exprpb.Decl {
|
||||
return standardDeclarations
|
||||
}
|
494
vendor/github.com/google/cel-go/checker/types.go
generated
vendored
Normal file
494
vendor/github.com/google/cel-go/checker/types.go
generated
vendored
Normal file
@ -0,0 +1,494 @@
|
||||
// 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().GetElemType()))
|
||||
case kindObject:
|
||||
return t.GetMessageType()
|
||||
case kindMap:
|
||||
return fmt.Sprintf("map(%s, %s)",
|
||||
FormatCheckedType(t.GetMapType().GetKeyType()),
|
||||
FormatCheckedType(t.GetMapType().GetValueType()))
|
||||
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!"
|
||||
case kindTypeParam:
|
||||
return t.GetTypeParam()
|
||||
}
|
||||
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 kindList:
|
||||
return isEqualOrLessSpecific(t1.GetListType().GetElemType(), t2.GetListType().GetElemType())
|
||||
case kindMap:
|
||||
m1 := t1.GetMapType()
|
||||
m2 := t2.GetMapType()
|
||||
return isEqualOrLessSpecific(m1.GetKeyType(), m2.GetKeyType()) &&
|
||||
isEqualOrLessSpecific(m1.GetValueType(), m2.GetValueType())
|
||||
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 {
|
||||
// Process type parameters.
|
||||
kind1, kind2 := kindOf(t1), kindOf(t2)
|
||||
if kind2 == kindTypeParam {
|
||||
// If t2 is a valid type substitution for t1, return true.
|
||||
valid, t2HasSub := isValidTypeSubstitution(m, t1, t2)
|
||||
if valid {
|
||||
return true
|
||||
}
|
||||
// If t2 is not a valid type sub for t1, and already has a known substitution return false
|
||||
// since it is not possible for t1 to be a substitution for t2.
|
||||
if !valid && t2HasSub {
|
||||
return false
|
||||
}
|
||||
// Otherwise, fall through to check whether t1 is a possible substitution for t2.
|
||||
}
|
||||
if kind1 == kindTypeParam {
|
||||
// Return whether t1 is a valid substitution for t2. If not, do no additional checks as the
|
||||
// possible type substitutions have been searched in both directions.
|
||||
valid, _ := isValidTypeSubstitution(m, t2, t1)
|
||||
return valid
|
||||
}
|
||||
|
||||
// Next check for wildcard types.
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// isValidTypeSubstitution returns whether t2 (or its type substitution) is a valid type
|
||||
// substitution for t1, and whether t2 has a type substitution in mapping m.
|
||||
//
|
||||
// The type t2 is a valid substitution for t1 if any of the following statements is true
|
||||
// - t2 has a type substitition (t2sub) equal to t1
|
||||
// - t2 has a type substitution (t2sub) assignable to t1
|
||||
// - t2 does not occur within t1.
|
||||
func isValidTypeSubstitution(m *mapping, t1, t2 *exprpb.Type) (valid, hasSub bool) {
|
||||
// Early return if the t1 and t2 are the same instance.
|
||||
kind1, kind2 := kindOf(t1), kindOf(t2)
|
||||
if kind1 == kind2 && (t1 == t2 || proto.Equal(t1, t2)) {
|
||||
return true, true
|
||||
}
|
||||
if t2Sub, found := m.find(t2); found {
|
||||
// Early return if t1 and t2Sub are the same instance as otherwise the mapping
|
||||
// might mark a type as being a subtitution for itself.
|
||||
if kind1 == kindOf(t2Sub) && (t1 == t2Sub || proto.Equal(t1, t2Sub)) {
|
||||
return true, true
|
||||
}
|
||||
// If the types are compatible, pick the more general type and return true
|
||||
if internalIsAssignable(m, t1, t2Sub) {
|
||||
t2New := mostGeneral(t1, t2Sub)
|
||||
// only update the type reference map if the target type does not occur within it.
|
||||
if notReferencedIn(m, t2, t2New) {
|
||||
m.add(t2, t2New)
|
||||
}
|
||||
// acknowledge the type agreement, and that the substitution is already tracked.
|
||||
return true, true
|
||||
}
|
||||
return false, true
|
||||
}
|
||||
if notReferencedIn(m, t2, t1) {
|
||||
m.add(t2, t1)
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
// internalIsAssignableAbstractType returns true if the abstract type names agree and all type
|
||||
// parameters are assignable.
|
||||
func internalIsAssignableAbstractType(m *mapping, a1 *exprpb.Type_AbstractType, a2 *exprpb.Type_AbstractType) bool {
|
||||
return a1.GetName() == a2.GetName() &&
|
||||
internalIsAssignableList(m, a1.GetParameterTypes(), a2.GetParameterTypes())
|
||||
}
|
||||
|
||||
// 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.GetTypeKind().(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 kindList:
|
||||
return notReferencedIn(m, t, withinType.GetListType().GetElemType())
|
||||
case kindMap:
|
||||
mt := withinType.GetMapType()
|
||||
return notReferencedIn(m, t, mt.GetKeyType()) && notReferencedIn(m, t, mt.GetValueType())
|
||||
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:
|
||||
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.GetArgTypes()))
|
||||
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().GetElemType(), typeParamToDyn))
|
||||
case kindMap:
|
||||
mt := t.GetMapType()
|
||||
return decls.NewMapType(substitute(m, mt.GetKeyType(), typeParamToDyn),
|
||||
substitute(m, mt.GetValueType(), 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
|
||||
}
|
35
vendor/github.com/google/cel-go/common/BUILD.bazel
generated
vendored
Normal file
35
vendor/github.com/google/cel-go/common/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
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 = [
|
||||
"cost.go",
|
||||
"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.GetExprKind().(type) {
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
id := e.GetIdentExpr()
|
||||
return id.GetName(), 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.GetOperand()); found {
|
||||
return qual + "." + sel.GetField(), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
40
vendor/github.com/google/cel-go/common/cost.go
generated
vendored
Normal file
40
vendor/github.com/google/cel-go/common/cost.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package common
|
||||
|
||||
const (
|
||||
// SelectAndIdentCost is the cost of an operation that accesses an identifier or performs a select.
|
||||
SelectAndIdentCost = 1
|
||||
|
||||
// ConstCost is the cost of an operation that accesses a constant.
|
||||
ConstCost = 0
|
||||
|
||||
// ListCreateBaseCost is the base cost of any operation that creates a new list.
|
||||
ListCreateBaseCost = 10
|
||||
|
||||
// MapCreateBaseCost is the base cost of any operation that creates a new map.
|
||||
MapCreateBaseCost = 30
|
||||
|
||||
// StructCreateBaseCost is the base cost of any operation that creates a new struct.
|
||||
StructCreateBaseCost = 40
|
||||
|
||||
// StringTraversalCostFactor is multiplied to a length of a string when computing the cost of traversing the entire
|
||||
// string once.
|
||||
StringTraversalCostFactor = 0.1
|
||||
|
||||
// RegexStringLengthCostFactor is multiplied ot the length of a regex string pattern when computing the cost of
|
||||
// applying the regex to a string of unit cost.
|
||||
RegexStringLengthCostFactor = 0.25
|
||||
)
|
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.GetOperand())
|
||||
w.append(".")
|
||||
w.append(sel.GetField())
|
||||
if sel.TestOnly {
|
||||
w.append("~test-only~")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendCall(call *exprpb.Expr_Call) {
|
||||
if call.Target != nil {
|
||||
w.Buffer(call.GetTarget())
|
||||
w.append(".")
|
||||
}
|
||||
w.append(call.GetFunction())
|
||||
w.append("(")
|
||||
if len(call.GetArgs()) > 0 {
|
||||
w.addIndent()
|
||||
w.appendLine()
|
||||
for i, arg := range call.GetArgs() {
|
||||
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.GetElements() {
|
||||
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.GetMessageName())
|
||||
w.append("{")
|
||||
if len(obj.GetEntries()) > 0 {
|
||||
w.appendLine()
|
||||
w.addIndent()
|
||||
for i, entry := range obj.GetEntries() {
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
w.append(entry.GetFieldKey())
|
||||
w.append(":")
|
||||
w.Buffer(entry.GetValue())
|
||||
w.adorn(entry)
|
||||
}
|
||||
w.removeIndent()
|
||||
w.appendLine()
|
||||
}
|
||||
w.append("}")
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendMap(obj *exprpb.Expr_CreateStruct) {
|
||||
w.append("{")
|
||||
if len(obj.GetEntries()) > 0 {
|
||||
w.appendLine()
|
||||
w.addIndent()
|
||||
for i, entry := range obj.GetEntries() {
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
w.Buffer(entry.GetMapKey())
|
||||
w.append(":")
|
||||
w.Buffer(entry.GetValue())
|
||||
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.GetIterVar())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Target")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.GetIterRange())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Accumulator")
|
||||
w.appendLine()
|
||||
w.append(comprehension.GetAccuVar())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Init")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.GetAccuInit())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// LoopCondition")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.GetLoopCondition())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// LoopStep")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.GetLoopStep())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Result")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.GetResult())
|
||||
w.append(")")
|
||||
w.removeIndent()
|
||||
}
|
||||
|
||||
func formatLiteral(c *exprpb.Constant) string {
|
||||
switch c.GetConstantKind().(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
|
73
vendor/github.com/google/cel-go/common/error.go
generated
vendored
Normal file
73
vendor/github.com/google/cel-go/common/error.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
// 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 = "^"
|
||||
|
||||
// maxSnippetLength is the largest number of characters which can be rendered in an error message snippet.
|
||||
maxSnippetLength = 16384
|
||||
)
|
||||
|
||||
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 && len(snippet) <= maxSnippetLength {
|
||||
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
|
||||
}
|
97
vendor/github.com/google/cel-go/common/errors.go
generated
vendored
Normal file
97
vendor/github.com/google/cel-go/common/errors.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// 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"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Errors type which contains a list of errors observed during parsing.
|
||||
type Errors struct {
|
||||
errors []Error
|
||||
source Source
|
||||
numErrors int
|
||||
maxErrorsToReport int
|
||||
}
|
||||
|
||||
// NewErrors creates a new instance of the Errors type.
|
||||
func NewErrors(source Source) *Errors {
|
||||
return &Errors{
|
||||
errors: []Error{},
|
||||
source: source,
|
||||
maxErrorsToReport: 100,
|
||||
}
|
||||
}
|
||||
|
||||
// ReportError records an error at a source location.
|
||||
func (e *Errors) ReportError(l Location, format string, args ...interface{}) {
|
||||
e.numErrors++
|
||||
if e.numErrors > e.maxErrorsToReport {
|
||||
return
|
||||
}
|
||||
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 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,
|
||||
numErrors: e.numErrors + len(errs),
|
||||
maxErrorsToReport: e.maxErrorsToReport,
|
||||
}
|
||||
}
|
||||
|
||||
// ToDisplayString returns the error set to a newline delimited string.
|
||||
func (e *Errors) ToDisplayString() string {
|
||||
errorsInString := e.maxErrorsToReport
|
||||
if e.numErrors > e.maxErrorsToReport {
|
||||
// add one more error to indicate the number of errors truncated.
|
||||
errorsInString++
|
||||
} else {
|
||||
// otherwise the error set will just contain the number of errors.
|
||||
errorsInString = e.numErrors
|
||||
}
|
||||
|
||||
result := make([]string, errorsInString)
|
||||
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 {
|
||||
// This can happen during the append of two errors objects
|
||||
if i >= e.maxErrorsToReport {
|
||||
break
|
||||
}
|
||||
result[i] = err.ToDisplayString(e.source)
|
||||
}
|
||||
if e.numErrors > e.maxErrorsToReport {
|
||||
result[e.maxErrorsToReport] = fmt.Sprintf("%d more errors were truncated", e.numErrors-e.maxErrorsToReport)
|
||||
}
|
||||
return strings.Join(result, "\n")
|
||||
}
|
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 SourceLocation 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",
|
||||
)
|
153
vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
Normal file
153
vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
// 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,
|
||||
}
|
||||
// operatorMap of the operator symbol which refers to a struct containing the display name,
|
||||
// if applicable, the operator precedence, and the arity.
|
||||
//
|
||||
// If the symbol does not have a display name listed in the map, it is only because it requires
|
||||
// special casing to render properly as text.
|
||||
operatorMap = map[string]struct {
|
||||
displayName string
|
||||
precedence int
|
||||
arity int
|
||||
}{
|
||||
Conditional: {displayName: "", precedence: 8, arity: 3},
|
||||
LogicalOr: {displayName: "||", precedence: 7, arity: 2},
|
||||
LogicalAnd: {displayName: "&&", precedence: 6, arity: 2},
|
||||
Equals: {displayName: "==", precedence: 5, arity: 2},
|
||||
Greater: {displayName: ">", precedence: 5, arity: 2},
|
||||
GreaterEquals: {displayName: ">=", precedence: 5, arity: 2},
|
||||
In: {displayName: "in", precedence: 5, arity: 2},
|
||||
Less: {displayName: "<", precedence: 5, arity: 2},
|
||||
LessEquals: {displayName: "<=", precedence: 5, arity: 2},
|
||||
NotEquals: {displayName: "!=", precedence: 5, arity: 2},
|
||||
OldIn: {displayName: "in", precedence: 5, arity: 2},
|
||||
Add: {displayName: "+", precedence: 4, arity: 2},
|
||||
Subtract: {displayName: "-", precedence: 4, arity: 2},
|
||||
Divide: {displayName: "/", precedence: 3, arity: 2},
|
||||
Modulo: {displayName: "%", precedence: 3, arity: 2},
|
||||
Multiply: {displayName: "*", precedence: 3, arity: 2},
|
||||
LogicalNot: {displayName: "!", precedence: 2, arity: 1},
|
||||
Negate: {displayName: "-", precedence: 2, arity: 1},
|
||||
Index: {displayName: "", precedence: 1, arity: 2},
|
||||
}
|
||||
)
|
||||
|
||||
// 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(symbol string) (string, bool) {
|
||||
op, found := operatorMap[symbol]
|
||||
if !found {
|
||||
return "", false
|
||||
}
|
||||
return op.displayName, true
|
||||
}
|
||||
|
||||
// FindReverseBinaryOperator returns the unmangled, text representation of a binary operator.
|
||||
//
|
||||
// If the symbol does refer to an operator, but the operator does not have a display name the
|
||||
// result is false.
|
||||
func FindReverseBinaryOperator(symbol string) (string, bool) {
|
||||
op, found := operatorMap[symbol]
|
||||
if !found || op.arity != 2 {
|
||||
return "", false
|
||||
}
|
||||
if op.displayName == "" {
|
||||
return "", false
|
||||
}
|
||||
return op.displayName, true
|
||||
}
|
||||
|
||||
// Precedence returns the operator precedence, where the higher the number indicates
|
||||
// higher precedence operations.
|
||||
func Precedence(symbol string) int {
|
||||
op, found := operatorMap[symbol]
|
||||
if !found {
|
||||
return 0
|
||||
}
|
||||
return op.precedence
|
||||
}
|
||||
|
||||
// Arity returns the number of argument the operator takes
|
||||
// -1 is returned if an undefined symbol is provided
|
||||
func Arity(symbol string) int {
|
||||
op, found := operatorMap[symbol]
|
||||
if !found {
|
||||
return -1
|
||||
}
|
||||
return op.arity
|
||||
}
|
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",
|
||||
)
|
317
vendor/github.com/google/cel-go/common/overloads/overloads.go
generated
vendored
Normal file
317
vendor/github.com/google/cel-go/common/overloads/overloads.go
generated
vendored
Normal file
@ -0,0 +1,317 @@
|
||||
// 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"
|
||||
LessInt64Double = "less_int64_double"
|
||||
LessInt64Uint64 = "less_int64_uint64"
|
||||
LessUint64 = "less_uint64"
|
||||
LessUint64Double = "less_uint64_double"
|
||||
LessUint64Int64 = "less_uint64_int64"
|
||||
LessDouble = "less_double"
|
||||
LessDoubleInt64 = "less_double_int64"
|
||||
LessDoubleUint64 = "less_double_uint64"
|
||||
LessString = "less_string"
|
||||
LessBytes = "less_bytes"
|
||||
LessTimestamp = "less_timestamp"
|
||||
LessDuration = "less_duration"
|
||||
LessEqualsBool = "less_equals_bool"
|
||||
LessEqualsInt64 = "less_equals_int64"
|
||||
LessEqualsInt64Double = "less_equals_int64_double"
|
||||
LessEqualsInt64Uint64 = "less_equals_int64_uint64"
|
||||
LessEqualsUint64 = "less_equals_uint64"
|
||||
LessEqualsUint64Double = "less_equals_uint64_double"
|
||||
LessEqualsUint64Int64 = "less_equals_uint64_int64"
|
||||
LessEqualsDouble = "less_equals_double"
|
||||
LessEqualsDoubleInt64 = "less_equals_double_int64"
|
||||
LessEqualsDoubleUint64 = "less_equals_double_uint64"
|
||||
LessEqualsString = "less_equals_string"
|
||||
LessEqualsBytes = "less_equals_bytes"
|
||||
LessEqualsTimestamp = "less_equals_timestamp"
|
||||
LessEqualsDuration = "less_equals_duration"
|
||||
GreaterBool = "greater_bool"
|
||||
GreaterInt64 = "greater_int64"
|
||||
GreaterInt64Double = "greater_int64_double"
|
||||
GreaterInt64Uint64 = "greater_int64_uint64"
|
||||
GreaterUint64 = "greater_uint64"
|
||||
GreaterUint64Double = "greater_uint64_double"
|
||||
GreaterUint64Int64 = "greater_uint64_int64"
|
||||
GreaterDouble = "greater_double"
|
||||
GreaterDoubleInt64 = "greater_double_int64"
|
||||
GreaterDoubleUint64 = "greater_double_uint64"
|
||||
GreaterString = "greater_string"
|
||||
GreaterBytes = "greater_bytes"
|
||||
GreaterTimestamp = "greater_timestamp"
|
||||
GreaterDuration = "greater_duration"
|
||||
GreaterEqualsBool = "greater_equals_bool"
|
||||
GreaterEqualsInt64 = "greater_equals_int64"
|
||||
GreaterEqualsInt64Double = "greater_equals_int64_double"
|
||||
GreaterEqualsInt64Uint64 = "greater_equals_int64_uint64"
|
||||
GreaterEqualsUint64 = "greater_equals_uint64"
|
||||
GreaterEqualsUint64Double = "greater_equals_uint64_double"
|
||||
GreaterEqualsUint64Int64 = "greater_equals_uint64_int64"
|
||||
GreaterEqualsDouble = "greater_equals_double"
|
||||
GreaterEqualsDoubleInt64 = "greater_equals_double_int64"
|
||||
GreaterEqualsDoubleUint64 = "greater_equals_double_uint64"
|
||||
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]
|
||||
}
|
89
vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
Normal file
89
vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
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",
|
||||
"compare.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_genproto//googleapis/rpc/status:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
"@org_golang_google_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",
|
||||
"util_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{})
|
142
vendor/github.com/google/cel-go/common/types/bool.go
generated
vendored
Normal file
142
vendor/github.com/google/cel-go/common/types/bool.go
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
// 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)
|
||||
return Bool(ok && 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 ref.Val) bool {
|
||||
switch v := elem.(type) {
|
||||
case Bool:
|
||||
return true
|
||||
case ref.Val:
|
||||
return v.Type() == BoolType
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
132
vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
Normal file
132
vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
// 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 implements 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)
|
||||
return Bool(ok && 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)
|
||||
}
|
97
vendor/github.com/google/cel-go/common/types/compare.go
generated
vendored
Normal file
97
vendor/github.com/google/cel-go/common/types/compare.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// 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"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
func compareDoubleInt(d Double, i Int) Int {
|
||||
if d < math.MinInt64 {
|
||||
return IntNegOne
|
||||
}
|
||||
if d > math.MaxInt64 {
|
||||
return IntOne
|
||||
}
|
||||
return compareDouble(d, Double(i))
|
||||
}
|
||||
|
||||
func compareIntDouble(i Int, d Double) Int {
|
||||
return -compareDoubleInt(d, i)
|
||||
}
|
||||
|
||||
func compareDoubleUint(d Double, u Uint) Int {
|
||||
if d < 0 {
|
||||
return IntNegOne
|
||||
}
|
||||
if d > math.MaxUint64 {
|
||||
return IntOne
|
||||
}
|
||||
return compareDouble(d, Double(u))
|
||||
}
|
||||
|
||||
func compareUintDouble(u Uint, d Double) Int {
|
||||
return -compareDoubleUint(d, u)
|
||||
}
|
||||
|
||||
func compareIntUint(i Int, u Uint) Int {
|
||||
if i < 0 || u > math.MaxInt64 {
|
||||
return IntNegOne
|
||||
}
|
||||
cmp := i - Int(u)
|
||||
if cmp < 0 {
|
||||
return IntNegOne
|
||||
}
|
||||
if cmp > 0 {
|
||||
return IntOne
|
||||
}
|
||||
return IntZero
|
||||
}
|
||||
|
||||
func compareUintInt(u Uint, i Int) Int {
|
||||
return -compareIntUint(i, u)
|
||||
}
|
||||
|
||||
func compareDouble(a, b Double) Int {
|
||||
if a < b {
|
||||
return IntNegOne
|
||||
}
|
||||
if a > b {
|
||||
return IntOne
|
||||
}
|
||||
return IntZero
|
||||
}
|
||||
|
||||
func compareInt(a, b Int) ref.Val {
|
||||
if a < b {
|
||||
return IntNegOne
|
||||
}
|
||||
if a > b {
|
||||
return IntOne
|
||||
}
|
||||
return IntZero
|
||||
}
|
||||
|
||||
func compareUint(a, b Uint) ref.Val {
|
||||
if a < b {
|
||||
return IntNegOne
|
||||
}
|
||||
if a > b {
|
||||
return IntOne
|
||||
}
|
||||
return IntZero
|
||||
}
|
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
|
216
vendor/github.com/google/cel-go/common/types/double.go
generated
vendored
Normal file
216
vendor/github.com/google/cel-go/common/types/double.go
generated
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
// 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"
|
||||
"math"
|
||||
"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 {
|
||||
if math.IsNaN(float64(d)) {
|
||||
return NewErr("NaN values cannot be ordered")
|
||||
}
|
||||
switch ov := other.(type) {
|
||||
case Double:
|
||||
if math.IsNaN(float64(ov)) {
|
||||
return NewErr("NaN values cannot be ordered")
|
||||
}
|
||||
return compareDouble(d, ov)
|
||||
case Int:
|
||||
return compareDoubleInt(d, ov)
|
||||
case Uint:
|
||||
return compareDoubleUint(d, ov)
|
||||
default:
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if math.IsNaN(float64(d)) {
|
||||
return False
|
||||
}
|
||||
switch ov := other.(type) {
|
||||
case Double:
|
||||
if math.IsNaN(float64(ov)) {
|
||||
return False
|
||||
}
|
||||
return Bool(d == ov)
|
||||
case Int:
|
||||
return Bool(compareDoubleInt(d, ov) == 0)
|
||||
case Uint:
|
||||
return Bool(compareDoubleUint(d, ov) == 0)
|
||||
default:
|
||||
return False
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
199
vendor/github.com/google/cel-go/common/types/duration.go
generated
vendored
Normal file
199
vendor/github.com/google/cel-go/common/types/duration.go
generated
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
// 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)
|
||||
return Bool(ok && 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 creates a new one.
|
||||
// TODO: Audit the use of this function and standardize the error messages and codes.
|
||||
func ValOrErr(val ref.Val, format string, args ...interface{}) ref.Val {
|
||||
if val == nil || !IsUnknownOrError(val) {
|
||||
return NewErr(format, args...)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// wrapErr wraps an existing Go error value into a CEL Err value.
|
||||
func wrapErr(err error) ref.Val {
|
||||
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 {
|
||||
switch val.(type) {
|
||||
case *Err:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
297
vendor/github.com/google/cel-go/common/types/int.go
generated
vendored
Normal file
297
vendor/github.com/google/cel-go/common/types/int.go
generated
vendored
Normal file
@ -0,0 +1,297 @@
|
||||
// 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"
|
||||
"math"
|
||||
"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 {
|
||||
switch ov := other.(type) {
|
||||
case Double:
|
||||
if math.IsNaN(float64(ov)) {
|
||||
return NewErr("NaN values cannot be ordered")
|
||||
}
|
||||
return compareIntDouble(i, ov)
|
||||
case Int:
|
||||
return compareInt(i, ov)
|
||||
case Uint:
|
||||
return compareIntUint(i, ov)
|
||||
default:
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
switch ov := other.(type) {
|
||||
case Double:
|
||||
if math.IsNaN(float64(ov)) {
|
||||
return False
|
||||
}
|
||||
return Bool(compareIntDouble(i, ov) == 0)
|
||||
case Int:
|
||||
return Bool(i == ov)
|
||||
case Uint:
|
||||
return Bool(compareIntUint(i, ov) == 0)
|
||||
default:
|
||||
return False
|
||||
}
|
||||
}
|
||||
|
||||
// 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{})
|
||||
)
|
489
vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
Normal file
489
vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
Normal file
@ -0,0 +1,489 @@
|
||||
// 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] },
|
||||
}
|
||||
}
|
||||
|
||||
// NewMutableList creates a new mutable list whose internal state can be modified.
|
||||
func NewMutableList(adapter ref.TypeAdapter) traits.MutableLister {
|
||||
var mutableValues []ref.Val
|
||||
return &mutableList{
|
||||
baseList: &baseList{
|
||||
TypeAdapter: adapter,
|
||||
value: mutableValues,
|
||||
size: 0,
|
||||
get: func(i int) interface{} { return mutableValues[i] },
|
||||
},
|
||||
mutableValues: mutableValues,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
for i := 0; i < l.size; i++ {
|
||||
val := l.NativeToValue(l.get(i))
|
||||
cmp := elem.Equal(val)
|
||||
b, ok := cmp.(Bool)
|
||||
if ok && b == True {
|
||||
return True
|
||||
}
|
||||
}
|
||||
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 False
|
||||
}
|
||||
if l.Size() != otherList.Size() {
|
||||
return False
|
||||
}
|
||||
for i := IntZero; i < l.Size().(Int); i++ {
|
||||
thisElem := l.Get(i)
|
||||
otherElem := otherList.Get(i)
|
||||
elemEq := Equal(thisElem, otherElem)
|
||||
if elemEq == False {
|
||||
return False
|
||||
}
|
||||
}
|
||||
return True
|
||||
}
|
||||
|
||||
// Get implements the traits.Indexer interface method.
|
||||
func (l *baseList) Get(index ref.Val) ref.Val {
|
||||
ind, err := indexOrError(index)
|
||||
if err != nil {
|
||||
return ValOrErr(index, err.Error())
|
||||
}
|
||||
if ind < 0 || ind >= l.size {
|
||||
return NewErr("index '%d' out of range in list size '%d'", ind, l.Size())
|
||||
}
|
||||
return l.NativeToValue(l.get(ind))
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// mutableList aggregates values into its internal storage. For use with internal CEL variables only.
|
||||
type mutableList struct {
|
||||
*baseList
|
||||
mutableValues []ref.Val
|
||||
}
|
||||
|
||||
// Add copies elements from the other list into the internal storage of the mutable list.
|
||||
// The ref.Val returned by Add is the receiver.
|
||||
func (l *mutableList) Add(other ref.Val) ref.Val {
|
||||
switch otherList := other.(type) {
|
||||
case *mutableList:
|
||||
l.mutableValues = append(l.mutableValues, otherList.mutableValues...)
|
||||
l.size += len(otherList.mutableValues)
|
||||
case traits.Lister:
|
||||
for i := IntZero; i < otherList.Size().(Int); i++ {
|
||||
l.size++
|
||||
l.mutableValues = append(l.mutableValues, otherList.Get(i))
|
||||
}
|
||||
default:
|
||||
return MaybeNoSuchOverloadErr(otherList)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// ToImmutableList returns an immutable list based on the internal storage of the mutable list.
|
||||
func (l *mutableList) ToImmutableList() traits.Lister {
|
||||
// The reference to internal state is guaranteed to be safe as this call is only performed
|
||||
// when mutations have been completed.
|
||||
return NewRefValList(l.TypeAdapter, l.mutableValues)
|
||||
}
|
||||
|
||||
// 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 implements the traits.Container interface method.
|
||||
func (l *concatList) Contains(elem ref.Val) ref.Val {
|
||||
// The concat list relies on the IsErrorOrUnknown checks against the input element to be
|
||||
// performed by the `prevList` and/or `nextList`.
|
||||
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 False
|
||||
}
|
||||
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 := Equal(thisElem, 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 {
|
||||
ind, err := indexOrError(index)
|
||||
if err != nil {
|
||||
return ValOrErr(index, err.Error())
|
||||
}
|
||||
i := Int(ind)
|
||||
if i < l.prevList.Size().(Int) {
|
||||
return l.prevList.Get(i)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func indexOrError(index ref.Val) (int, error) {
|
||||
switch iv := index.(type) {
|
||||
case Int:
|
||||
return int(iv), nil
|
||||
case Double:
|
||||
if ik, ok := doubleToInt64Lossless(float64(iv)); ok {
|
||||
return int(ik), nil
|
||||
}
|
||||
return -1, fmt.Errorf("unsupported index value %v in list", index)
|
||||
case Uint:
|
||||
if ik, ok := uint64ToInt64Lossless(uint64(iv)); ok {
|
||||
return int(ik), nil
|
||||
}
|
||||
return -1, fmt.Errorf("unsupported index value %v in list", index)
|
||||
default:
|
||||
return -1, fmt.Errorf("unsupported index type '%s' in list", index.Type())
|
||||
}
|
||||
}
|
832
vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
Normal file
832
vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
Normal file
@ -0,0 +1,832 @@
|
||||
// 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 input key.
|
||||
//
|
||||
// If the key is not found the function returns (nil, 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 {
|
||||
_, found := m.Find(index)
|
||||
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 False
|
||||
}
|
||||
if m.Size() != otherMap.Size() {
|
||||
return False
|
||||
}
|
||||
it := m.Iterator()
|
||||
for it.HasNext() == True {
|
||||
key := it.Next()
|
||||
thisVal, _ := m.Find(key)
|
||||
otherVal, found := otherMap.Find(key)
|
||||
if !found {
|
||||
return False
|
||||
}
|
||||
valEq := Equal(thisVal, otherVal)
|
||||
if valEq == False {
|
||||
return False
|
||||
}
|
||||
}
|
||||
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).
|
||||
func (a *jsonStructAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
strKey, ok := key.(String)
|
||||
if !ok {
|
||||
return nil, 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).
|
||||
func (m *reflectMapAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
if m.refValue.Len() == 0 {
|
||||
return nil, false
|
||||
}
|
||||
if keyVal, found := m.findInternal(key); found {
|
||||
return keyVal, true
|
||||
}
|
||||
switch k := key.(type) {
|
||||
// Double is not a valid proto map key type, so check for the key as an int or uint.
|
||||
case Double:
|
||||
if ik, ok := doubleToInt64Lossless(float64(k)); ok {
|
||||
if keyVal, found := m.findInternal(Int(ik)); found {
|
||||
return keyVal, true
|
||||
}
|
||||
}
|
||||
if uk, ok := doubleToUint64Lossless(float64(k)); ok {
|
||||
return m.findInternal(Uint(uk))
|
||||
}
|
||||
// map keys of type double are not supported.
|
||||
case Int:
|
||||
if uk, ok := int64ToUint64Lossless(int64(k)); ok {
|
||||
return m.findInternal(Uint(uk))
|
||||
}
|
||||
case Uint:
|
||||
if ik, ok := uint64ToInt64Lossless(uint64(k)); ok {
|
||||
return m.findInternal(Int(ik))
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// findInternal attempts to convert the incoming key to the map's internal native type
|
||||
// and then returns the value, if found.
|
||||
func (m *reflectMapAccessor) findInternal(key ref.Val) (ref.Val, bool) {
|
||||
k, err := key.ConvertToNative(m.keyType)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
refKey := reflect.ValueOf(k)
|
||||
val := m.refValue.MapIndex(refKey)
|
||||
if val.IsValid() {
|
||||
return m.NativeToValue(val.Interface()), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Iterator creates a Golang reflection based traits.Iterator.
|
||||
func (m *reflectMapAccessor) Iterator() traits.Iterator {
|
||||
return &mapIterator{
|
||||
TypeAdapter: m.TypeAdapter,
|
||||
mapKeys: m.refValue.MapRange(),
|
||||
len: m.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).
|
||||
func (a *refValMapAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
if len(a.mapVal) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
if keyVal, found := a.mapVal[key]; found {
|
||||
return keyVal, true
|
||||
}
|
||||
switch k := key.(type) {
|
||||
case Double:
|
||||
if ik, ok := doubleToInt64Lossless(float64(k)); ok {
|
||||
if keyVal, found := a.mapVal[Int(ik)]; found {
|
||||
return keyVal, found
|
||||
}
|
||||
}
|
||||
if uk, ok := doubleToUint64Lossless(float64(k)); ok {
|
||||
keyVal, found := a.mapVal[Uint(uk)]
|
||||
return keyVal, found
|
||||
}
|
||||
// map keys of type double are not supported.
|
||||
case Int:
|
||||
if uk, ok := int64ToUint64Lossless(int64(k)); ok {
|
||||
keyVal, found := a.mapVal[Uint(uk)]
|
||||
return keyVal, found
|
||||
}
|
||||
case Uint:
|
||||
if ik, ok := uint64ToInt64Lossless(uint64(k)); ok {
|
||||
keyVal, found := a.mapVal[Int(ik)]
|
||||
return keyVal, found
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// 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).
|
||||
func (a *stringMapAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
strKey, ok := key.(String)
|
||||
if !ok {
|
||||
return nil, 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).
|
||||
func (a *stringIfaceMapAccessor) Find(key ref.Val) (ref.Val, bool) {
|
||||
strKey, ok := key.(String)
|
||||
if !ok {
|
||||
return nil, 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 {
|
||||
_, found := m.Find(key)
|
||||
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 False
|
||||
}
|
||||
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 {
|
||||
retVal = False
|
||||
return false
|
||||
}
|
||||
valEq := Equal(valVal, 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).
|
||||
func (m *protoMap) Find(key ref.Val) (ref.Val, bool) {
|
||||
if keyVal, found := m.findInternal(key); found {
|
||||
return keyVal, true
|
||||
}
|
||||
switch k := key.(type) {
|
||||
// Double is not a valid proto map key type, so check for the key as an int or uint.
|
||||
case Double:
|
||||
if ik, ok := doubleToInt64Lossless(float64(k)); ok {
|
||||
if keyVal, found := m.findInternal(Int(ik)); found {
|
||||
return keyVal, true
|
||||
}
|
||||
}
|
||||
if uk, ok := doubleToUint64Lossless(float64(k)); ok {
|
||||
return m.findInternal(Uint(uk))
|
||||
}
|
||||
// map keys of type double are not supported.
|
||||
case Int:
|
||||
if uk, ok := int64ToUint64Lossless(int64(k)); ok {
|
||||
return m.findInternal(Uint(uk))
|
||||
}
|
||||
case Uint:
|
||||
if ik, ok := uint64ToInt64Lossless(uint64(k)); ok {
|
||||
return m.findInternal(Int(ik))
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// findInternal attempts to convert the incoming key to the map's internal native type
|
||||
// and then returns the value, if found.
|
||||
func (m *protoMap) findInternal(key ref.Val) (ref.Val, bool) {
|
||||
// Convert the input key to the expected protobuf key type.
|
||||
ntvKey, err := key.ConvertToNative(m.value.KeyType.ReflectType())
|
||||
if err != nil {
|
||||
return nil, 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 nil, 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
|
||||
}
|
97
vendor/github.com/google/cel-go/common/types/null.go
generated
vendored
Normal file
97
vendor/github.com/google/cel-go/common/types/null.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// 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 {
|
||||
return Bool(NullType == other.Type())
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
159
vendor/github.com/google/cel-go/common/types/object.go
generated
vendored
Normal file
159
vendor/github.com/google/cel-go/common/types/object.go
generated
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
// 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) {
|
||||
srcPB := o.value
|
||||
if reflect.TypeOf(srcPB).AssignableTo(typeDesc) {
|
||||
return srcPB, nil
|
||||
}
|
||||
if reflect.TypeOf(o).AssignableTo(typeDesc) {
|
||||
return o, nil
|
||||
}
|
||||
switch typeDesc {
|
||||
case anyValueType:
|
||||
_, isAny := srcPB.(*anypb.Any)
|
||||
if isAny {
|
||||
return srcPB, nil
|
||||
}
|
||||
return anypb.New(srcPB)
|
||||
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(srcPB)
|
||||
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 {
|
||||
err := pb.Merge(dstPB, srcPB)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("type conversion error: %v", err)
|
||||
}
|
||||
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 {
|
||||
otherPB, ok := other.Value().(proto.Message)
|
||||
return Bool(ok && pb.Equal(o.value, otherPB))
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
389
vendor/github.com/google/cel-go/common/types/overflow.go
generated
vendored
Normal file
389
vendor/github.com/google/cel-go/common/types/overflow.go
generated
vendored
Normal file
@ -0,0 +1,389 @@
|
||||
// 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
|
||||
}
|
||||
|
||||
func doubleToUint64Lossless(v float64) (uint64, bool) {
|
||||
u, err := doubleToUint64Checked(v)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
if float64(u) != v {
|
||||
return 0, false
|
||||
}
|
||||
return u, true
|
||||
}
|
||||
|
||||
func doubleToInt64Lossless(v float64) (int64, bool) {
|
||||
i, err := doubleToInt64Checked(v)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
if float64(i) != v {
|
||||
return 0, false
|
||||
}
|
||||
return i, true
|
||||
}
|
||||
|
||||
func int64ToUint64Lossless(v int64) (uint64, bool) {
|
||||
u, err := int64ToUint64Checked(v)
|
||||
return u, err == nil
|
||||
}
|
||||
|
||||
func uint64ToInt64Lossless(v uint64) (int64, bool) {
|
||||
i, err := uint64ToInt64Checked(v)
|
||||
return i, err == nil
|
||||
}
|
53
vendor/github.com/google/cel-go/common/types/pb/BUILD.bazel
generated
vendored
Normal file
53
vendor/github.com/google/cel-go/common/types/pb/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
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",
|
||||
"equal.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//encoding/protowire: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 = [
|
||||
"equal_test.go",
|
||||
"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())
|
||||
}
|
206
vendor/github.com/google/cel-go/common/types/pb/equal.go
generated
vendored
Normal file
206
vendor/github.com/google/cel-go/common/types/pb/equal.go
generated
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protowire"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
)
|
||||
|
||||
// Equal returns whether two proto.Message instances are equal using the following criteria:
|
||||
//
|
||||
// - Messages must share the same instance of the type descriptor
|
||||
// - Known set fields are compared using semantics equality
|
||||
// - Bytes are compared using bytes.Equal
|
||||
// - Scalar values are compared with operator ==
|
||||
// - List and map types are equal if they have the same length and all elements are equal
|
||||
// - Messages are equal if they share the same descriptor and all set fields are equal
|
||||
// - Unknown fields are compared using byte equality
|
||||
// - NaN values are not equal to each other
|
||||
// - google.protobuf.Any values are unpacked before comparison
|
||||
// - If the type descriptor for a protobuf.Any cannot be found, byte equality is used rather than
|
||||
// semantic equality.
|
||||
//
|
||||
// This method of proto equality mirrors the behavior of the C++ protobuf MessageDifferencer
|
||||
// whereas the golang proto.Equal implementation mirrors the Java protobuf equals() methods
|
||||
// behaviors which needed to treat NaN values as equal due to Java semantics.
|
||||
func Equal(x, y proto.Message) bool {
|
||||
if x == nil || y == nil {
|
||||
return x == nil && y == nil
|
||||
}
|
||||
xRef := x.ProtoReflect()
|
||||
yRef := y.ProtoReflect()
|
||||
return equalMessage(xRef, yRef)
|
||||
}
|
||||
|
||||
func equalMessage(mx, my protoreflect.Message) bool {
|
||||
// Note, the original proto.Equal upon which this implementation is based does not specifically handle the
|
||||
// case when both messages are invalid. It is assumed that the descriptors will be equal and that byte-wise
|
||||
// comparison will be used, though the semantics of validity are neither clear, nor promised within the
|
||||
// proto.Equal implementation.
|
||||
if mx.IsValid() != my.IsValid() || mx.Descriptor() != my.Descriptor() {
|
||||
return false
|
||||
}
|
||||
|
||||
// This is an innovation on the default proto.Equal where protobuf.Any values are unpacked before comparison
|
||||
// as otherwise the Any values are compared by bytes rather than structurally.
|
||||
if isAny(mx) && isAny(my) {
|
||||
ax := mx.Interface().(*anypb.Any)
|
||||
ay := my.Interface().(*anypb.Any)
|
||||
// If the values are not the same type url, return false.
|
||||
if ax.GetTypeUrl() != ay.GetTypeUrl() {
|
||||
return false
|
||||
}
|
||||
// If the values are byte equal, then return true.
|
||||
if bytes.Equal(ax.GetValue(), ay.GetValue()) {
|
||||
return true
|
||||
}
|
||||
// Otherwise fall through to the semantic comparison of the any values.
|
||||
x, err := ax.UnmarshalNew()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
y, err := ay.UnmarshalNew()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// Recursively compare the unwrapped messages to ensure nested Any values are unwrapped accordingly.
|
||||
return equalMessage(x.ProtoReflect(), y.ProtoReflect())
|
||||
}
|
||||
|
||||
// Walk the set fields to determine field-wise equality
|
||||
nx := 0
|
||||
equal := true
|
||||
mx.Range(func(fd protoreflect.FieldDescriptor, vx protoreflect.Value) bool {
|
||||
nx++
|
||||
equal = my.Has(fd) && equalField(fd, vx, my.Get(fd))
|
||||
return equal
|
||||
})
|
||||
if !equal {
|
||||
return false
|
||||
}
|
||||
// Establish the count of set fields on message y
|
||||
ny := 0
|
||||
my.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool {
|
||||
ny++
|
||||
return true
|
||||
})
|
||||
// If the number of set fields is not equal return false.
|
||||
if nx != ny {
|
||||
return false
|
||||
}
|
||||
|
||||
return equalUnknown(mx.GetUnknown(), my.GetUnknown())
|
||||
}
|
||||
|
||||
func equalField(fd protoreflect.FieldDescriptor, x, y protoreflect.Value) bool {
|
||||
switch {
|
||||
case fd.IsMap():
|
||||
return equalMap(fd, x.Map(), y.Map())
|
||||
case fd.IsList():
|
||||
return equalList(fd, x.List(), y.List())
|
||||
default:
|
||||
return equalValue(fd, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func equalMap(fd protoreflect.FieldDescriptor, x, y protoreflect.Map) bool {
|
||||
if x.Len() != y.Len() {
|
||||
return false
|
||||
}
|
||||
equal := true
|
||||
x.Range(func(k protoreflect.MapKey, vx protoreflect.Value) bool {
|
||||
vy := y.Get(k)
|
||||
equal = y.Has(k) && equalValue(fd.MapValue(), vx, vy)
|
||||
return equal
|
||||
})
|
||||
return equal
|
||||
}
|
||||
|
||||
func equalList(fd protoreflect.FieldDescriptor, x, y protoreflect.List) bool {
|
||||
if x.Len() != y.Len() {
|
||||
return false
|
||||
}
|
||||
for i := x.Len() - 1; i >= 0; i-- {
|
||||
if !equalValue(fd, x.Get(i), y.Get(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func equalValue(fd protoreflect.FieldDescriptor, x, y protoreflect.Value) bool {
|
||||
switch fd.Kind() {
|
||||
case protoreflect.BoolKind:
|
||||
return x.Bool() == y.Bool()
|
||||
case protoreflect.EnumKind:
|
||||
return x.Enum() == y.Enum()
|
||||
case protoreflect.Int32Kind, protoreflect.Sint32Kind,
|
||||
protoreflect.Int64Kind, protoreflect.Sint64Kind,
|
||||
protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind:
|
||||
return x.Int() == y.Int()
|
||||
case protoreflect.Uint32Kind, protoreflect.Uint64Kind,
|
||||
protoreflect.Fixed32Kind, protoreflect.Fixed64Kind:
|
||||
return x.Uint() == y.Uint()
|
||||
case protoreflect.FloatKind, protoreflect.DoubleKind:
|
||||
return x.Float() == y.Float()
|
||||
case protoreflect.StringKind:
|
||||
return x.String() == y.String()
|
||||
case protoreflect.BytesKind:
|
||||
return bytes.Equal(x.Bytes(), y.Bytes())
|
||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||||
return equalMessage(x.Message(), y.Message())
|
||||
default:
|
||||
return x.Interface() == y.Interface()
|
||||
}
|
||||
}
|
||||
|
||||
func equalUnknown(x, y protoreflect.RawFields) bool {
|
||||
lenX := len(x)
|
||||
lenY := len(y)
|
||||
if lenX != lenY {
|
||||
return false
|
||||
}
|
||||
if lenX == 0 {
|
||||
return true
|
||||
}
|
||||
if bytes.Equal([]byte(x), []byte(y)) {
|
||||
return true
|
||||
}
|
||||
|
||||
mx := make(map[protoreflect.FieldNumber]protoreflect.RawFields)
|
||||
my := make(map[protoreflect.FieldNumber]protoreflect.RawFields)
|
||||
for len(x) > 0 {
|
||||
fnum, _, n := protowire.ConsumeField(x)
|
||||
mx[fnum] = append(mx[fnum], x[:n]...)
|
||||
x = x[n:]
|
||||
}
|
||||
for len(y) > 0 {
|
||||
fnum, _, n := protowire.ConsumeField(y)
|
||||
my[fnum] = append(my[fnum], y[:n]...)
|
||||
y = y[n:]
|
||||
}
|
||||
return reflect.DeepEqual(mx, my)
|
||||
}
|
||||
|
||||
func isAny(m protoreflect.Message) bool {
|
||||
return string(m.Descriptor().FullName()) == "google.protobuf.Any"
|
||||
}
|
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
|
||||
}
|
||||
}
|
||||
}
|
223
vendor/github.com/google/cel-go/common/types/pb/pb.go
generated
vendored
Normal file
223
vendor/github.com/google/cel-go/common/types/pb/pb.go
generated
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
"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{},
|
||||
}
|
||||
)
|
||||
|
||||
// Merge will copy the source proto message into the destination, or error if the merge cannot be completed.
|
||||
//
|
||||
// Unlike the proto.Merge, this method will fallback to proto.Marshal/Unmarshal of the two proto messages do not
|
||||
// share the same instance of their type descriptor.
|
||||
func Merge(dstPB, srcPB proto.Message) error {
|
||||
src, dst := srcPB.ProtoReflect(), dstPB.ProtoReflect()
|
||||
if src.Descriptor() == dst.Descriptor() {
|
||||
proto.Merge(dstPB, srcPB)
|
||||
return nil
|
||||
}
|
||||
if src.Descriptor().FullName() != dst.Descriptor().FullName() {
|
||||
return fmt.Errorf("pb.Merge() arguments must be the same type. got: %v, %v",
|
||||
dst.Descriptor().FullName(), src.Descriptor().FullName())
|
||||
}
|
||||
bytes, err := proto.Marshal(srcPB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("pb.Merge(dstPB, srcPB) failed to marshal source proto: %v", err)
|
||||
}
|
||||
err = proto.Unmarshal(bytes, dstPB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("pb.Merge(dstPB, srcPB) failed to unmarshal to dest proto: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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{})
|
||||
}
|
552
vendor/github.com/google/cel-go/common/types/pb/type.go
generated
vendored
Normal file
552
vendor/github.com/google/cel-go/common/types/pb/type.go
generated
vendored
Normal file
@ -0,0 +1,552 @@
|
||||
// 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, error) {
|
||||
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.GroupKind, 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, _, err := fd.MaybeUnwrapDynamic(fv)
|
||||
return unwrapped, err
|
||||
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 {
|
||||
kind := fd.desc.Kind()
|
||||
return kind == protoreflect.MessageKind || kind == protoreflect.GroupKind
|
||||
}
|
||||
|
||||
// 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, error) {
|
||||
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 || fd.desc.Kind() == protoreflect.GroupKind {
|
||||
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, error) {
|
||||
switch v := msg.(type) {
|
||||
case *anypb.Any:
|
||||
dynMsg, err := v.UnmarshalNew()
|
||||
if err != nil {
|
||||
return v, false, err
|
||||
}
|
||||
return unwrapDynamic(desc, dynMsg.ProtoReflect())
|
||||
case *dynamicpb.Message:
|
||||
return unwrapDynamic(desc, v)
|
||||
case *dpb.Duration:
|
||||
return v.AsDuration(), true, nil
|
||||
case *tpb.Timestamp:
|
||||
return v.AsTime(), true, nil
|
||||
case *structpb.Value:
|
||||
switch v.GetKind().(type) {
|
||||
case *structpb.Value_BoolValue:
|
||||
return v.GetBoolValue(), true, nil
|
||||
case *structpb.Value_ListValue:
|
||||
return v.GetListValue(), true, nil
|
||||
case *structpb.Value_NullValue:
|
||||
return structpb.NullValue_NULL_VALUE, true, nil
|
||||
case *structpb.Value_NumberValue:
|
||||
return v.GetNumberValue(), true, nil
|
||||
case *structpb.Value_StringValue:
|
||||
return v.GetStringValue(), true, nil
|
||||
case *structpb.Value_StructValue:
|
||||
return v.GetStructValue(), true, nil
|
||||
default:
|
||||
return structpb.NullValue_NULL_VALUE, true, nil
|
||||
}
|
||||
case *wrapperspb.BoolValue:
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.BytesValue:
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.DoubleValue:
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.FloatValue:
|
||||
return float64(v.GetValue()), true, nil
|
||||
case *wrapperspb.Int32Value:
|
||||
return int64(v.GetValue()), true, nil
|
||||
case *wrapperspb.Int64Value:
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.StringValue:
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.UInt32Value:
|
||||
return uint64(v.GetValue()), true, nil
|
||||
case *wrapperspb.UInt64Value:
|
||||
return v.GetValue(), true, nil
|
||||
}
|
||||
return msg, false, nil
|
||||
}
|
||||
|
||||
// unwrapDynamic unwraps a reflected protobuf Message value.
|
||||
//
|
||||
// Returns the unwrapped value and 'true' if unwrapped, otherwise the input value and 'false'.
|
||||
func unwrapDynamic(desc description, refMsg protoreflect.Message) (interface{}, bool, error) {
|
||||
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{}
|
||||
err := Merge(unwrappedAny, msg)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
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 nil, false, err
|
||||
}
|
||||
// Attempt to unwrap the dynamic type, otherwise return the dynamic message.
|
||||
unwrapped, nested, err := unwrapDynamic(desc, dynMsg.ProtoReflect())
|
||||
if err == nil && nested {
|
||||
return unwrapped, true, nil
|
||||
}
|
||||
return dynMsg, true, err
|
||||
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, nil
|
||||
}
|
||||
valueField := refMsg.Descriptor().Fields().ByName("value")
|
||||
return refMsg.Get(valueField).Interface(), true, nil
|
||||
case "google.protobuf.Duration":
|
||||
unwrapped := &dpb.Duration{}
|
||||
err := Merge(unwrapped, msg)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return unwrapped.AsDuration(), true, nil
|
||||
case "google.protobuf.ListValue":
|
||||
unwrapped := &structpb.ListValue{}
|
||||
err := Merge(unwrapped, msg)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return unwrapped, true, nil
|
||||
case "google.protobuf.NullValue":
|
||||
return structpb.NullValue_NULL_VALUE, true, nil
|
||||
case "google.protobuf.Struct":
|
||||
unwrapped := &structpb.Struct{}
|
||||
err := Merge(unwrapped, msg)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return unwrapped, true, nil
|
||||
case "google.protobuf.Timestamp":
|
||||
unwrapped := &tpb.Timestamp{}
|
||||
err := Merge(unwrapped, msg)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return unwrapped.AsTime(), true, nil
|
||||
case "google.protobuf.Value":
|
||||
unwrapped := &structpb.Value{}
|
||||
err := Merge(unwrapped, msg)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return unwrap(desc, unwrapped)
|
||||
}
|
||||
return msg, false, nil
|
||||
}
|
||||
|
||||
// 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),
|
||||
}
|
||||
)
|
539
vendor/github.com/google/cel-go/common/types/provider.go
generated
vendored
Normal file
539
vendor/github.com/google/cel-go/common/types/provider.go
generated
vendored
Normal file
@ -0,0 +1,539 @@
|
||||
// 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, err := td.MaybeUnwrap(v)
|
||||
if err != nil {
|
||||
return UnsupportedRefValConversionErr(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, err := td.MaybeUnwrap(v)
|
||||
if err != nil {
|
||||
return UnsupportedRefValConversionErr(v), true
|
||||
}
|
||||
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)
|
54
vendor/github.com/google/cel-go/common/types/ref/reference.go
generated
vendored
Normal file
54
vendor/github.com/google/cel-go/common/types/ref/reference.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
// 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{}
|
||||
}
|
218
vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
Normal file
218
vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
// 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)
|
||||
return Bool(ok && 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.Receiver.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)))
|
||||
}
|
316
vendor/github.com/google/cel-go/common/types/timestamp.go
generated
vendored
Normal file
316
vendor/github.com/google/cel-go/common/types/timestamp.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 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 {
|
||||
otherTime, ok := other.(Timestamp)
|
||||
return Bool(ok && t.Time.Equal(otherTime.Time))
|
||||
}
|
||||
|
||||
// Receive implements traits.Receiver.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
|
||||
}
|
33
vendor/github.com/google/cel-go/common/types/traits/lister.go
generated
vendored
Normal file
33
vendor/github.com/google/cel-go/common/types/traits/lister.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"
|
||||
|
||||
// Lister interface which aggregates the traits of a list.
|
||||
type Lister interface {
|
||||
ref.Val
|
||||
Adder
|
||||
Container
|
||||
Indexer
|
||||
Iterable
|
||||
Sizer
|
||||
}
|
||||
|
||||
// MutableLister interface which emits an immutable result after an intermediate computation.
|
||||
type MutableLister interface {
|
||||
Lister
|
||||
ToImmutableList() Lister
|
||||
}
|
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
|
||||
)
|
102
vendor/github.com/google/cel-go/common/types/type.go
generated
vendored
Normal file
102
vendor/github.com/google/cel-go/common/types/type.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
// 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 {
|
||||
otherType, ok := other.(ref.Type)
|
||||
return Bool(ok && t.TypeName() == otherType.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
|
||||
}
|
249
vendor/github.com/google/cel-go/common/types/uint.go
generated
vendored
Normal file
249
vendor/github.com/google/cel-go/common/types/uint.go
generated
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
// 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"
|
||||
"math"
|
||||
"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 {
|
||||
switch ov := other.(type) {
|
||||
case Double:
|
||||
if math.IsNaN(float64(ov)) {
|
||||
return NewErr("NaN values cannot be ordered")
|
||||
}
|
||||
return compareUintDouble(i, ov)
|
||||
case Int:
|
||||
return compareUintInt(i, ov)
|
||||
case Uint:
|
||||
return compareUint(i, ov)
|
||||
default:
|
||||
return MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
switch ov := other.(type) {
|
||||
case Double:
|
||||
if math.IsNaN(float64(ov)) {
|
||||
return False
|
||||
}
|
||||
return Bool(compareUintDouble(i, ov) == 0)
|
||||
case Int:
|
||||
return Bool(compareUintInt(i, ov) == 0)
|
||||
case Uint:
|
||||
return Bool(i == ov)
|
||||
default:
|
||||
return False
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
66
vendor/github.com/google/cel-go/common/types/unknown.go
generated
vendored
Normal file
66
vendor/github.com/google/cel-go/common/types/unknown.go
generated
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
// 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 is an identity function since unknown values cannot be modified.
|
||||
func (u Unknown) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
return u
|
||||
}
|
||||
|
||||
// Equal is an identity function since unknown values cannot be modified.
|
||||
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 {
|
||||
switch val.(type) {
|
||||
case Unknown:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
48
vendor/github.com/google/cel-go/common/types/util.go
generated
vendored
Normal file
48
vendor/github.com/google/cel-go/common/types/util.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
// 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 UnknownType.
|
||||
func IsUnknownOrError(val ref.Val) bool {
|
||||
switch val.(type) {
|
||||
case Unknown, *Err:
|
||||
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
|
||||
}
|
||||
|
||||
// Equal returns whether the two ref.Value are heterogeneously equivalent.
|
||||
func Equal(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
lNull := lhs == NullValue
|
||||
rNull := rhs == NullValue
|
||||
if lNull || rNull {
|
||||
return Bool(lNull == rNull)
|
||||
}
|
||||
return lhs.Equal(rhs)
|
||||
}
|
36
vendor/github.com/google/cel-go/ext/BUILD.bazel
generated
vendored
Normal file
36
vendor/github.com/google/cel-go/ext/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
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",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/ref: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'
|
88
vendor/github.com/google/cel-go/ext/encoders.go
generated
vendored
Normal file
88
vendor/github.com/google/cel-go/ext/encoders.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
// 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"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// 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.Function("base64.decode",
|
||||
cel.Overload("base64_decode_string", []*cel.Type{cel.StringType}, cel.BytesType,
|
||||
cel.UnaryBinding(func(str ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
return bytesOrError(base64DecodeString(string(s)))
|
||||
}))),
|
||||
cel.Function("base64.encode",
|
||||
cel.Overload("base64_encode_bytes", []*cel.Type{cel.BytesType}, cel.StringType,
|
||||
cel.UnaryBinding(func(bytes ref.Val) ref.Val {
|
||||
b := bytes.(types.Bytes)
|
||||
return stringOrError(base64EncodeBytes([]byte(b)))
|
||||
}))),
|
||||
}
|
||||
}
|
||||
|
||||
func (encoderLib) ProgramOptions() []cel.ProgramOption {
|
||||
return []cel.ProgramOption{}
|
||||
}
|
||||
|
||||
func base64DecodeString(str string) ([]byte, error) {
|
||||
return base64.StdEncoding.DecodeString(str)
|
||||
}
|
||||
|
||||
func base64EncodeBytes(bytes []byte) (string, error) {
|
||||
return base64.StdEncoding.EncodeToString(bytes), nil
|
||||
}
|
||||
|
||||
var (
|
||||
bytesListType = reflect.TypeOf([]byte{})
|
||||
)
|
50
vendor/github.com/google/cel-go/ext/guards.go
generated
vendored
Normal file
50
vendor/github.com/google/cel-go/ext/guards.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// function invocation guards for common call signatures within extension functions.
|
||||
|
||||
func intOrError(i int64, err error) ref.Val {
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Int(i)
|
||||
}
|
||||
|
||||
func bytesOrError(bytes []byte, err error) ref.Val {
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.Bytes(bytes)
|
||||
}
|
||||
|
||||
func stringOrError(str string, err error) ref.Val {
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.String(str)
|
||||
}
|
||||
|
||||
func listStringOrError(strs []string, err error) ref.Val {
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return types.DefaultTypeAdapter.NativeToValue(strs)
|
||||
}
|
483
vendor/github.com/google/cel-go/ext/strings.go
generated
vendored
Normal file
483
vendor/github.com/google/cel-go/ext/strings.go
generated
vendored
Normal file
@ -0,0 +1,483 @@
|
||||
// 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"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// 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
|
||||
//
|
||||
// Join
|
||||
//
|
||||
// Returns a new string where the elements of string list are concatenated.
|
||||
//
|
||||
// The function also accepts an optional separator which is placed between elements in the resulting string.
|
||||
//
|
||||
// <list<string>>.join() -> <string>
|
||||
// <list<string>>.join(<string>) -> <string>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ['hello', 'mellow'].join() // returns 'hellomellow'
|
||||
// ['hello', 'mellow'].join(' ') // returns 'hello mellow'
|
||||
// [].join() // returns ''
|
||||
// [].join('/') // returns ''
|
||||
//
|
||||
// LastIndexOf
|
||||
//
|
||||
// Returns the integer index 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.Function("charAt",
|
||||
cel.MemberOverload("string_char_at_int", []*cel.Type{cel.StringType, cel.IntType}, cel.StringType,
|
||||
cel.BinaryBinding(func(str, ind ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
i := ind.(types.Int)
|
||||
return stringOrError(charAt(string(s), int64(i)))
|
||||
}))),
|
||||
cel.Function("indexOf",
|
||||
cel.MemberOverload("string_index_of_string", []*cel.Type{cel.StringType, cel.StringType}, cel.IntType,
|
||||
cel.BinaryBinding(func(str, substr ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
sub := substr.(types.String)
|
||||
return intOrError(indexOf(string(s), string(sub)))
|
||||
})),
|
||||
cel.MemberOverload("string_index_of_string_int", []*cel.Type{cel.StringType, cel.StringType, cel.IntType}, cel.IntType,
|
||||
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
|
||||
s := args[0].(types.String)
|
||||
sub := args[1].(types.String)
|
||||
offset := args[2].(types.Int)
|
||||
return intOrError(indexOfOffset(string(s), string(sub), int64(offset)))
|
||||
}))),
|
||||
cel.Function("lastIndexOf",
|
||||
cel.MemberOverload("string_last_index_of_string", []*cel.Type{cel.StringType, cel.StringType}, cel.IntType,
|
||||
cel.BinaryBinding(func(str, substr ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
sub := substr.(types.String)
|
||||
return intOrError(lastIndexOf(string(s), string(sub)))
|
||||
})),
|
||||
cel.MemberOverload("string_last_index_of_string_int", []*cel.Type{cel.StringType, cel.StringType, cel.IntType}, cel.IntType,
|
||||
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
|
||||
s := args[0].(types.String)
|
||||
sub := args[1].(types.String)
|
||||
offset := args[2].(types.Int)
|
||||
return intOrError(lastIndexOfOffset(string(s), string(sub), int64(offset)))
|
||||
}))),
|
||||
cel.Function("lowerAscii",
|
||||
cel.MemberOverload("string_lower_ascii", []*cel.Type{cel.StringType}, cel.StringType,
|
||||
cel.UnaryBinding(func(str ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
return stringOrError(lowerASCII(string(s)))
|
||||
}))),
|
||||
cel.Function("replace",
|
||||
cel.MemberOverload(
|
||||
"string_replace_string_string", []*cel.Type{cel.StringType, cel.StringType, cel.StringType}, cel.StringType,
|
||||
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
|
||||
str := args[0].(types.String)
|
||||
old := args[1].(types.String)
|
||||
new := args[2].(types.String)
|
||||
return stringOrError(replace(string(str), string(old), string(new)))
|
||||
})),
|
||||
cel.MemberOverload(
|
||||
"string_replace_string_string_int", []*cel.Type{cel.StringType, cel.StringType, cel.StringType, cel.IntType}, cel.StringType,
|
||||
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
|
||||
str := args[0].(types.String)
|
||||
old := args[1].(types.String)
|
||||
new := args[2].(types.String)
|
||||
n := args[3].(types.Int)
|
||||
return stringOrError(replaceN(string(str), string(old), string(new), int64(n)))
|
||||
}))),
|
||||
cel.Function("split",
|
||||
cel.MemberOverload("string_split_string", []*cel.Type{cel.StringType, cel.StringType}, cel.ListType(cel.StringType),
|
||||
cel.BinaryBinding(func(str, separator ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
sep := separator.(types.String)
|
||||
return listStringOrError(split(string(s), string(sep)))
|
||||
})),
|
||||
cel.MemberOverload("string_split_string_int", []*cel.Type{cel.StringType, cel.StringType, cel.IntType}, cel.ListType(cel.StringType),
|
||||
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
|
||||
s := args[0].(types.String)
|
||||
sep := args[1].(types.String)
|
||||
n := args[2].(types.Int)
|
||||
return listStringOrError(splitN(string(s), string(sep), int64(n)))
|
||||
}))),
|
||||
cel.Function("substring",
|
||||
cel.MemberOverload("string_substring_int", []*cel.Type{cel.StringType, cel.IntType}, cel.StringType,
|
||||
cel.BinaryBinding(func(str, offset ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
off := offset.(types.Int)
|
||||
return stringOrError(substr(string(s), int64(off)))
|
||||
})),
|
||||
cel.MemberOverload("string_substring_int_int", []*cel.Type{cel.StringType, cel.IntType, cel.IntType}, cel.StringType,
|
||||
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
|
||||
s := args[0].(types.String)
|
||||
start := args[1].(types.Int)
|
||||
end := args[2].(types.Int)
|
||||
return stringOrError(substrRange(string(s), int64(start), int64(end)))
|
||||
}))),
|
||||
cel.Function("trim",
|
||||
cel.MemberOverload("string_trim", []*cel.Type{cel.StringType}, cel.StringType,
|
||||
cel.UnaryBinding(func(str ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
return stringOrError(trimSpace(string(s)))
|
||||
}))),
|
||||
cel.Function("upperAscii",
|
||||
cel.MemberOverload("string_upper_ascii", []*cel.Type{cel.StringType}, cel.StringType,
|
||||
cel.UnaryBinding(func(str ref.Val) ref.Val {
|
||||
s := str.(types.String)
|
||||
return stringOrError(upperASCII(string(s)))
|
||||
}))),
|
||||
cel.Function("join",
|
||||
cel.MemberOverload("list_join", []*cel.Type{cel.ListType(cel.StringType)}, cel.StringType,
|
||||
cel.UnaryBinding(func(list ref.Val) ref.Val {
|
||||
l, err := list.ConvertToNative(stringListType)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
return stringOrError(join(l.([]string)))
|
||||
})),
|
||||
cel.MemberOverload("list_join_string", []*cel.Type{cel.ListType(cel.StringType), cel.StringType}, cel.StringType,
|
||||
cel.BinaryBinding(func(list, delim ref.Val) ref.Val {
|
||||
l, err := list.ConvertToNative(stringListType)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
d := delim.(types.String)
|
||||
return stringOrError(joinSeparator(l.([]string), string(d)))
|
||||
}))),
|
||||
}
|
||||
}
|
||||
|
||||
func (stringLib) ProgramOptions() []cel.ProgramOption {
|
||||
return []cel.ProgramOption{}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func joinSeparator(strs []string, separator string) (string, error) {
|
||||
return strings.Join(strs, separator), nil
|
||||
}
|
||||
|
||||
func join(strs []string) (string, error) {
|
||||
return strings.Join(strs, ""), nil
|
||||
}
|
||||
|
||||
var (
|
||||
stringListType = reflect.TypeOf([]string{})
|
||||
)
|
72
vendor/github.com/google/cel-go/interpreter/BUILD.bazel
generated
vendored
Normal file
72
vendor/github.com/google/cel-go/interpreter/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
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",
|
||||
"optimizations.go",
|
||||
"planner.go",
|
||||
"prune.go",
|
||||
"runtimecost.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",
|
||||
],
|
||||
)
|
201
vendor/github.com/google/cel-go/interpreter/activation.go
generated
vendored
Normal file
201
vendor/github.com/google/cel-go/interpreter/activation.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 (
|
||||
"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 {
|
||||
return emptyActivation{}
|
||||
}
|
||||
|
||||
// emptyActivation is a variable-free activation.
|
||||
type emptyActivation struct{}
|
||||
|
||||
func (emptyActivation) ResolveName(string) (interface{}, bool) { return nil, false }
|
||||
func (emptyActivation) Parent() Activation { return nil }
|
||||
|
||||
// NewActivation returns an activation based on a map-based binding where the map keys are
|
||||
// expected to be qualified names used with ResolveName calls.
|
||||
//
|
||||
// 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{}
|
||||
},
|
||||
}
|
||||
)
|
404
vendor/github.com/google/cel-go/interpreter/attribute_patterns.go
generated
vendored
Normal file
404
vendor/github.com/google/cel-go/interpreter/attribute_patterns.go
generated
vendored
Normal file
@ -0,0 +1,404 @@
|
||||
// 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 wildcard 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, Attributes are resolved before
|
||||
// qualification happens. This is an implementation detail, but one relevant to why the Attribute
|
||||
// types do not surface in the list of implementations.
|
||||
//
|
||||
// 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 {
|
||||
return numericValueEquals(value, q.celValue)
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for uint qualifiers.
|
||||
func (q *uintQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
return numericValueEquals(value, q.celValue)
|
||||
}
|
||||
|
||||
// QualifierValueEquals implementation for double qualifiers.
|
||||
func (q *doubleQualifier) QualifierValueEquals(value interface{}) bool {
|
||||
return numericValueEquals(value, q.celValue)
|
||||
}
|
||||
|
||||
// numericValueEquals uses CEL equality to determine whether two number values are
|
||||
func numericValueEquals(value interface{}, celValue ref.Val) bool {
|
||||
val := types.DefaultTypeAdapter.NativeToValue(value)
|
||||
return celValue.Equal(val) == types.True
|
||||
}
|
||||
|
||||
// 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()
|
||||
// Bug in how partial activation is resolved, should search parents as well.
|
||||
partial, isPartial := toPartialActivation(vars)
|
||||
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)
|
||||
}
|
||||
|
||||
func toPartialActivation(vars Activation) (PartialActivation, bool) {
|
||||
pv, ok := vars.(PartialActivation)
|
||||
if ok {
|
||||
return pv, true
|
||||
}
|
||||
if vars.Parent() != nil {
|
||||
return toPartialActivation(vars.Parent())
|
||||
}
|
||||
return nil, false
|
||||
}
|
1051
vendor/github.com/google/cel-go/interpreter/attributes.go
generated
vendored
Normal file
1051
vendor/github.com/google/cel-go/interpreter/attributes.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
35
vendor/github.com/google/cel-go/interpreter/coster.go
generated
vendored
Normal file
35
vendor/github.com/google/cel-go/interpreter/coster.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// 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"
|
||||
|
||||
// TODO: remove Coster.
|
||||
|
||||
// Coster calculates the heuristic cost incurred during evaluation.
|
||||
// Deprecated: Please migrate cel.EstimateCost, it supports length estimates for input data and cost estimates for
|
||||
// extension functions.
|
||||
type Coster interface {
|
||||
Cost() (min, max int64)
|
||||
}
|
||||
|
||||
// estimateCost returns the heuristic cost interval for the program.
|
||||
func estimateCost(i interface{}) (min, max int64) {
|
||||
c, ok := i.(Coster)
|
||||
if !ok {
|
||||
return 0, math.MaxInt64
|
||||
}
|
||||
return c.Cost()
|
||||
}
|
269
vendor/github.com/google/cel-go/interpreter/decorators.go
generated
vendored
Normal file
269
vendor/github.com/google/cel-go/interpreter/decorators.go
generated
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
// 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)
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decInterruptFolds creates an intepretable decorator which marks comprehensions as interruptable
|
||||
// where the interrupt state is communicated via a hidden variable on the Activation.
|
||||
func decInterruptFolds() InterpretableDecorator {
|
||||
return func(i Interpretable) (Interpretable, error) {
|
||||
fold, ok := i.(*evalFold)
|
||||
if !ok {
|
||||
return i, nil
|
||||
}
|
||||
fold.interruptable = true
|
||||
return fold, 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:
|
||||
expr.exhaustive = true
|
||||
return expr, 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 precomputing 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
|
||||
}
|
||||
}
|
||||
|
||||
// decRegexOptimizer compiles regex pattern string constants.
|
||||
func decRegexOptimizer(regexOptimizations ...*RegexOptimization) InterpretableDecorator {
|
||||
functionMatchMap := make(map[string]*RegexOptimization)
|
||||
overloadMatchMap := make(map[string]*RegexOptimization)
|
||||
for _, m := range regexOptimizations {
|
||||
functionMatchMap[m.Function] = m
|
||||
if m.OverloadID != "" {
|
||||
overloadMatchMap[m.OverloadID] = m
|
||||
}
|
||||
}
|
||||
|
||||
return func(i Interpretable) (Interpretable, error) {
|
||||
call, ok := i.(InterpretableCall)
|
||||
if !ok {
|
||||
return i, nil
|
||||
}
|
||||
|
||||
var matcher *RegexOptimization
|
||||
var found bool
|
||||
if call.OverloadID() != "" {
|
||||
matcher, found = overloadMatchMap[call.OverloadID()]
|
||||
}
|
||||
if !found {
|
||||
matcher, found = functionMatchMap[call.Function()]
|
||||
}
|
||||
if !found || matcher.RegexIndex >= len(call.Args()) {
|
||||
return i, nil
|
||||
}
|
||||
args := call.Args()
|
||||
regexArg := args[matcher.RegexIndex]
|
||||
regexStr, isConst := regexArg.(InterpretableConst)
|
||||
if !isConst {
|
||||
return i, nil
|
||||
}
|
||||
pattern, ok := regexStr.Value().(types.String)
|
||||
if !ok {
|
||||
return i, nil
|
||||
}
|
||||
return matcher.Factory(call, string(pattern))
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
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
|
||||
}
|
||||
valueSet[elem] = types.True
|
||||
switch ev := elem.(type) {
|
||||
case types.Double:
|
||||
iv := ev.ConvertToType(types.IntType)
|
||||
// Ensure that only lossless conversions are added to the set
|
||||
if !types.IsError(iv) && iv.Equal(ev) == types.True {
|
||||
valueSet[iv] = types.True
|
||||
}
|
||||
// Ensure that only lossless conversions are added to the set
|
||||
uv := ev.ConvertToType(types.UintType)
|
||||
if !types.IsError(uv) && uv.Equal(ev) == types.True {
|
||||
valueSet[uv] = types.True
|
||||
}
|
||||
case types.Int:
|
||||
dv := ev.ConvertToType(types.DoubleType)
|
||||
if !types.IsError(dv) {
|
||||
valueSet[dv] = types.True
|
||||
}
|
||||
uv := ev.ConvertToType(types.UintType)
|
||||
if !types.IsError(uv) {
|
||||
valueSet[uv] = types.True
|
||||
}
|
||||
case types.Uint:
|
||||
dv := ev.ConvertToType(types.DoubleType)
|
||||
if !types.IsError(dv) {
|
||||
valueSet[dv] = types.True
|
||||
}
|
||||
iv := ev.ConvertToType(types.IntType)
|
||||
if !types.IsError(iv) {
|
||||
valueSet[iv] = types.True
|
||||
}
|
||||
}
|
||||
}
|
||||
return &evalSetMembership{
|
||||
inst: inlist,
|
||||
arg: lhs,
|
||||
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{}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user