mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
build: move e2e dependencies into e2e/go.mod
Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
15da101b1b
commit
bec6090996
233
e2e/vendor/github.com/google/cel-go/LICENSE
generated
vendored
Normal file
233
e2e/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.
|
91
e2e/vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
Normal file
91
e2e/vendor/github.com/google/cel-go/cel/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
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",
|
||||
"folding.go",
|
||||
"io.go",
|
||||
"inlining.go",
|
||||
"library.go",
|
||||
"macro.go",
|
||||
"optimizer.go",
|
||||
"options.go",
|
||||
"program.go",
|
||||
"validator.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/ast:go_default_library",
|
||||
"//common/containers:go_default_library",
|
||||
"//common/decls:go_default_library",
|
||||
"//common/functions:go_default_library",
|
||||
"//common/operators:go_default_library",
|
||||
"//common/overloads:go_default_library",
|
||||
"//common/stdlib: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",
|
||||
"//parser:go_default_library",
|
||||
"@dev_cel_expr//:expr",
|
||||
"@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",
|
||||
"folding_test.go",
|
||||
"io_test.go",
|
||||
"inlining_test.go",
|
||||
"optimizer_test.go",
|
||||
"validator_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",
|
||||
"//ext: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//encoding/prototext:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/structpb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
|
||||
],
|
||||
)
|
19
e2e/vendor/github.com/google/cel-go/cel/cel.go
generated
vendored
Normal file
19
e2e/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
|
370
e2e/vendor/github.com/google/cel-go/cel/decls.go
generated
vendored
Normal file
370
e2e/vendor/github.com/google/cel-go/cel/decls.go
generated
vendored
Normal file
@ -0,0 +1,370 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/decls"
|
||||
"github.com/google/cel-go/common/functions"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
celpb "cel.dev/expr"
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// Kind indicates a CEL type's kind which is used to differentiate quickly between simple and complex types.
|
||||
type Kind = types.Kind
|
||||
|
||||
const (
|
||||
// DynKind represents a dynamic type. This kind only exists at type-check time.
|
||||
DynKind Kind = types.DynKind
|
||||
|
||||
// AnyKind represents a google.protobuf.Any type. This kind only exists at type-check time.
|
||||
AnyKind = types.AnyKind
|
||||
|
||||
// BoolKind represents a boolean type.
|
||||
BoolKind = types.BoolKind
|
||||
|
||||
// BytesKind represents a bytes type.
|
||||
BytesKind = types.BytesKind
|
||||
|
||||
// DoubleKind represents a double type.
|
||||
DoubleKind = types.DoubleKind
|
||||
|
||||
// DurationKind represents a CEL duration type.
|
||||
DurationKind = types.DurationKind
|
||||
|
||||
// IntKind represents an integer type.
|
||||
IntKind = types.IntKind
|
||||
|
||||
// ListKind represents a list type.
|
||||
ListKind = types.ListKind
|
||||
|
||||
// MapKind represents a map type.
|
||||
MapKind = types.MapKind
|
||||
|
||||
// NullTypeKind represents a null type.
|
||||
NullTypeKind = types.NullTypeKind
|
||||
|
||||
// OpaqueKind represents an abstract type which has no accessible fields.
|
||||
OpaqueKind = types.OpaqueKind
|
||||
|
||||
// StringKind represents a string type.
|
||||
StringKind = types.StringKind
|
||||
|
||||
// StructKind represents a structured object with typed fields.
|
||||
StructKind = types.StructKind
|
||||
|
||||
// TimestampKind represents a a CEL time type.
|
||||
TimestampKind = types.TimestampKind
|
||||
|
||||
// TypeKind represents the CEL type.
|
||||
TypeKind = types.TypeKind
|
||||
|
||||
// TypeParamKind represents a parameterized type whose type name will be resolved at type-check time, if possible.
|
||||
TypeParamKind = types.TypeParamKind
|
||||
|
||||
// UintKind represents a uint type.
|
||||
UintKind = types.UintKind
|
||||
)
|
||||
|
||||
var (
|
||||
// AnyType represents the google.protobuf.Any type.
|
||||
AnyType = types.AnyType
|
||||
// BoolType represents the bool type.
|
||||
BoolType = types.BoolType
|
||||
// BytesType represents the bytes type.
|
||||
BytesType = types.BytesType
|
||||
// DoubleType represents the double type.
|
||||
DoubleType = types.DoubleType
|
||||
// DurationType represents the CEL duration type.
|
||||
DurationType = types.DurationType
|
||||
// DynType represents a dynamic CEL type whose type will be determined at runtime from context.
|
||||
DynType = types.DynType
|
||||
// IntType represents the int type.
|
||||
IntType = types.IntType
|
||||
// NullType represents the type of a null value.
|
||||
NullType = types.NullType
|
||||
// StringType represents the string type.
|
||||
StringType = types.StringType
|
||||
// TimestampType represents the time type.
|
||||
TimestampType = types.TimestampType
|
||||
// TypeType represents a CEL type
|
||||
TypeType = types.TypeType
|
||||
// UintType represents a uint type.
|
||||
UintType = types.UintType
|
||||
|
||||
// function references for instantiating new types.
|
||||
|
||||
// ListType creates an instances of a list type value with the provided element type.
|
||||
ListType = types.NewListType
|
||||
// MapType creates an instance of a map type value with the provided key and value types.
|
||||
MapType = types.NewMapType
|
||||
// NullableType creates an instance of a nullable type with the provided wrapped type.
|
||||
//
|
||||
// Note: only primitive types are supported as wrapped types.
|
||||
NullableType = types.NewNullableType
|
||||
// OptionalType creates an abstract parameterized type instance corresponding to CEL's notion of optional.
|
||||
OptionalType = types.NewOptionalType
|
||||
// OpaqueType creates an abstract parameterized type with a given name.
|
||||
OpaqueType = types.NewOpaqueType
|
||||
// ObjectType creates a type references to an externally defined type, e.g. a protobuf message type.
|
||||
ObjectType = types.NewObjectType
|
||||
// TypeParamType creates a parameterized type instance.
|
||||
TypeParamType = types.NewTypeParamType
|
||||
)
|
||||
|
||||
// Type holds a reference to a runtime type with an optional type-checked set of type parameters.
|
||||
type Type = types.Type
|
||||
|
||||
// Constant creates an instances of an identifier declaration with a variable name, type, and value.
|
||||
func Constant(name string, t *Type, v ref.Val) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.variables = append(e.variables, decls.NewConstant(name, t, v))
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Variable creates an instance of a variable declaration with a variable name and type.
|
||||
func Variable(name string, t *Type) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.variables = append(e.variables, decls.NewVariable(name, t))
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Function defines a function and overloads with optional singleton or per-overload bindings.
|
||||
//
|
||||
// Using Function is roughly equivalent to calling Declarations() to declare the function signatures
|
||||
// and Functions() to define the function bindings, if they have been defined. Specifying the
|
||||
// same function name more than once will result in the aggregation of the function overloads. If any
|
||||
// signatures conflict between the existing and new function definition an error will be raised.
|
||||
// However, if the signatures are identical and the overload ids are the same, the redefinition will
|
||||
// be considered a no-op.
|
||||
//
|
||||
// One key difference with using Function() is that each FunctionDecl provided will handle dynamic
|
||||
// dispatch based on the type-signatures of the overloads provided which means overload resolution at
|
||||
// runtime is handled out of the box rather than via a custom binding for overload resolution via
|
||||
// Functions():
|
||||
//
|
||||
// - Overloads are searched in the order they are declared
|
||||
// - Dynamic dispatch for lists and maps is limited by inspection of the list and map contents
|
||||
//
|
||||
// at runtime. Empty lists and maps will result in a 'default dispatch'
|
||||
//
|
||||
// - In the event that a default dispatch occurs, the first overload provided is the one invoked
|
||||
//
|
||||
// If you intend to use overloads which differentiate based on the key or element type of a list or
|
||||
// map, consider using a generic function instead: e.g. func(list(T)) or func(map(K, V)) as this
|
||||
// will allow your implementation to determine how best to handle dispatch and the default behavior
|
||||
// for empty lists and maps whose contents cannot be inspected.
|
||||
//
|
||||
// For functions which use parameterized opaque types (abstract types), consider using a singleton
|
||||
// function which is capable of inspecting the contents of the type and resolving the appropriate
|
||||
// overload as CEL can only make inferences by type-name regarding such types.
|
||||
func Function(name string, opts ...FunctionOpt) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
fn, err := decls.NewFunction(name, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing, found := e.functions[fn.Name()]; found {
|
||||
fn, err = existing.Merge(fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
e.functions[fn.Name()] = fn
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// FunctionOpt defines a functional option for configuring a function declaration.
|
||||
type FunctionOpt = decls.FunctionOpt
|
||||
|
||||
// SingletonUnaryBinding creates a singleton function definition to be used for all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
func SingletonUnaryBinding(fn functions.UnaryOp, traits ...int) FunctionOpt {
|
||||
return decls.SingletonUnaryBinding(fn, traits...)
|
||||
}
|
||||
|
||||
// SingletonBinaryImpl creates a singleton function definition to be used with all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
//
|
||||
// Deprecated: use SingletonBinaryBinding
|
||||
func SingletonBinaryImpl(fn functions.BinaryOp, traits ...int) FunctionOpt {
|
||||
return decls.SingletonBinaryBinding(fn, traits...)
|
||||
}
|
||||
|
||||
// SingletonBinaryBinding creates a singleton function definition to be used with all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
func SingletonBinaryBinding(fn functions.BinaryOp, traits ...int) FunctionOpt {
|
||||
return decls.SingletonBinaryBinding(fn, traits...)
|
||||
}
|
||||
|
||||
// SingletonFunctionImpl creates a singleton function definition to be used with all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
//
|
||||
// Deprecated: use SingletonFunctionBinding
|
||||
func SingletonFunctionImpl(fn functions.FunctionOp, traits ...int) FunctionOpt {
|
||||
return decls.SingletonFunctionBinding(fn, traits...)
|
||||
}
|
||||
|
||||
// SingletonFunctionBinding creates a singleton function definition to be used with all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
func SingletonFunctionBinding(fn functions.FunctionOp, traits ...int) FunctionOpt {
|
||||
return decls.SingletonFunctionBinding(fn, traits...)
|
||||
}
|
||||
|
||||
// DisableDeclaration disables the function signatures, effectively removing them from the type-check
|
||||
// environment while preserving the runtime bindings.
|
||||
func DisableDeclaration(value bool) FunctionOpt {
|
||||
return decls.DisableDeclaration(value)
|
||||
}
|
||||
|
||||
// Overload defines a new global overload with an overload id, argument types, and result type. Through the
|
||||
// use of OverloadOpt options, the overload may also be configured with a binding, an operand trait, and to
|
||||
// be non-strict.
|
||||
//
|
||||
// Note: function bindings should be commonly configured with Overload instances whereas operand traits and
|
||||
// strict-ness should be rare occurrences.
|
||||
func Overload(overloadID string, args []*Type, resultType *Type, opts ...OverloadOpt) FunctionOpt {
|
||||
return decls.Overload(overloadID, args, resultType, opts...)
|
||||
}
|
||||
|
||||
// MemberOverload defines a new receiver-style overload (or member function) with an overload id, argument types,
|
||||
// and result type. Through the use of OverloadOpt options, the overload may also be configured with a binding,
|
||||
// an operand trait, and to be non-strict.
|
||||
//
|
||||
// Note: function bindings should be commonly configured with Overload instances whereas operand traits and
|
||||
// strict-ness should be rare occurrences.
|
||||
func MemberOverload(overloadID string, args []*Type, resultType *Type, opts ...OverloadOpt) FunctionOpt {
|
||||
return decls.MemberOverload(overloadID, args, resultType, opts...)
|
||||
}
|
||||
|
||||
// OverloadOpt is a functional option for configuring a function overload.
|
||||
type OverloadOpt = decls.OverloadOpt
|
||||
|
||||
// UnaryBinding provides the implementation of a unary overload. The provided function is protected by a runtime
|
||||
// type-guard which ensures runtime type agreement between the overload signature and runtime argument types.
|
||||
func UnaryBinding(binding functions.UnaryOp) OverloadOpt {
|
||||
return decls.UnaryBinding(binding)
|
||||
}
|
||||
|
||||
// BinaryBinding provides the implementation of a binary overload. The provided function is protected by a runtime
|
||||
// type-guard which ensures runtime type agreement between the overload signature and runtime argument types.
|
||||
func BinaryBinding(binding functions.BinaryOp) OverloadOpt {
|
||||
return decls.BinaryBinding(binding)
|
||||
}
|
||||
|
||||
// FunctionBinding provides the implementation of a variadic overload. The provided function is protected by a runtime
|
||||
// type-guard which ensures runtime type agreement between the overload signature and runtime argument types.
|
||||
func FunctionBinding(binding functions.FunctionOp) OverloadOpt {
|
||||
return decls.FunctionBinding(binding)
|
||||
}
|
||||
|
||||
// OverloadIsNonStrict enables the function to be called with error and unknown argument values.
|
||||
//
|
||||
// Note: do not use this option unless absoluately necessary as it should be an uncommon feature.
|
||||
func OverloadIsNonStrict() OverloadOpt {
|
||||
return decls.OverloadIsNonStrict()
|
||||
}
|
||||
|
||||
// OverloadOperandTrait configures a set of traits which the first argument to the overload must implement in order to be
|
||||
// successfully invoked.
|
||||
func OverloadOperandTrait(trait int) OverloadOpt {
|
||||
return decls.OverloadOperandTrait(trait)
|
||||
}
|
||||
|
||||
// TypeToExprType converts a CEL-native type representation to a protobuf CEL Type representation.
|
||||
func TypeToExprType(t *Type) (*exprpb.Type, error) {
|
||||
return types.TypeToExprType(t)
|
||||
}
|
||||
|
||||
// ExprTypeToType converts a protobuf CEL type representation to a CEL-native type representation.
|
||||
func ExprTypeToType(t *exprpb.Type) (*Type, error) {
|
||||
return types.ExprTypeToType(t)
|
||||
}
|
||||
|
||||
// ExprDeclToDeclaration converts a protobuf CEL declaration to a CEL-native declaration, either a Variable or Function.
|
||||
func ExprDeclToDeclaration(d *exprpb.Decl) (EnvOption, error) {
|
||||
return AlphaProtoAsDeclaration(d)
|
||||
}
|
||||
|
||||
// AlphaProtoAsDeclaration converts a v1alpha1.Decl value describing a variable or function into an EnvOption.
|
||||
func AlphaProtoAsDeclaration(d *exprpb.Decl) (EnvOption, error) {
|
||||
canonical := &celpb.Decl{}
|
||||
if err := convertProto(d, canonical); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ProtoAsDeclaration(canonical)
|
||||
}
|
||||
|
||||
// ProtoAsDeclaration converts a canonical celpb.Decl value describing a variable or function into an EnvOption.
|
||||
func ProtoAsDeclaration(d *celpb.Decl) (EnvOption, error) {
|
||||
switch d.GetDeclKind().(type) {
|
||||
case *celpb.Decl_Function:
|
||||
overloads := d.GetFunction().GetOverloads()
|
||||
opts := make([]FunctionOpt, len(overloads))
|
||||
for i, o := range overloads {
|
||||
args := make([]*Type, len(o.GetParams()))
|
||||
for j, p := range o.GetParams() {
|
||||
a, err := types.ProtoAsType(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args[j] = a
|
||||
}
|
||||
res, err := types.ProtoAsType(o.GetResultType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if o.IsInstanceFunction {
|
||||
opts[i] = decls.MemberOverload(o.GetOverloadId(), args, res)
|
||||
} else {
|
||||
opts[i] = decls.Overload(o.GetOverloadId(), args, res)
|
||||
}
|
||||
}
|
||||
return Function(d.GetName(), opts...), nil
|
||||
case *celpb.Decl_Ident:
|
||||
t, err := types.ProtoAsType(d.GetIdent().GetType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if d.GetIdent().GetValue() == nil {
|
||||
return Variable(d.GetName(), t), nil
|
||||
}
|
||||
val, err := ast.ProtoConstantAsVal(d.GetIdent().GetValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Constant(d.GetName(), t, val), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported decl: %v", d)
|
||||
}
|
||||
}
|
894
e2e/vendor/github.com/google/cel-go/cel/env.go
generated
vendored
Normal file
894
e2e/vendor/github.com/google/cel-go/cel/env.go
generated
vendored
Normal file
@ -0,0 +1,894 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/google/cel-go/checker"
|
||||
chkdecls "github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common"
|
||||
celast "github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/decls"
|
||||
"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 {
|
||||
source Source
|
||||
impl *celast.AST
|
||||
}
|
||||
|
||||
// NativeRep converts the AST to a Go-native representation.
|
||||
func (ast *Ast) NativeRep() *celast.AST {
|
||||
if ast == nil {
|
||||
return nil
|
||||
}
|
||||
return ast.impl
|
||||
}
|
||||
|
||||
// Expr returns the proto serializable instance of the parsed/checked expression.
|
||||
//
|
||||
// Deprecated: prefer cel.AstToCheckedExpr() or cel.AstToParsedExpr() and call GetExpr()
|
||||
// the result instead.
|
||||
func (ast *Ast) Expr() *exprpb.Expr {
|
||||
if ast == nil {
|
||||
return nil
|
||||
}
|
||||
pbExpr, _ := celast.ExprToProto(ast.NativeRep().Expr())
|
||||
return pbExpr
|
||||
}
|
||||
|
||||
// IsChecked returns whether the Ast value has been successfully type-checked.
|
||||
func (ast *Ast) IsChecked() bool {
|
||||
return ast.NativeRep().IsChecked()
|
||||
}
|
||||
|
||||
// SourceInfo returns character offset and newline position information about expression elements.
|
||||
func (ast *Ast) SourceInfo() *exprpb.SourceInfo {
|
||||
if ast == nil {
|
||||
return nil
|
||||
}
|
||||
pbInfo, _ := celast.SourceInfoToProto(ast.NativeRep().SourceInfo())
|
||||
return pbInfo
|
||||
}
|
||||
|
||||
// ResultType returns the output type of the expression if the Ast has been type-checked, else
|
||||
// returns chkdecls.Dyn as the parse step cannot infer the type.
|
||||
//
|
||||
// Deprecated: use OutputType
|
||||
func (ast *Ast) ResultType() *exprpb.Type {
|
||||
out := ast.OutputType()
|
||||
t, err := TypeToExprType(out)
|
||||
if err != nil {
|
||||
return chkdecls.Dyn
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if ast == nil {
|
||||
return types.ErrorType
|
||||
}
|
||||
return ast.NativeRep().GetType(ast.NativeRep().Expr().ID())
|
||||
}
|
||||
|
||||
// Source returns a view of the input used to create the Ast. This source may be complete or
|
||||
// constructed from the SourceInfo.
|
||||
func (ast *Ast) Source() Source {
|
||||
if ast == nil {
|
||||
return nil
|
||||
}
|
||||
return ast.source
|
||||
}
|
||||
|
||||
// FormatType converts a type message into a string representation.
|
||||
//
|
||||
// Deprecated: prefer FormatCELType
|
||||
func FormatType(t *exprpb.Type) string {
|
||||
return checker.FormatCheckedType(t)
|
||||
}
|
||||
|
||||
// FormatCELType formats a cel.Type value to a string representation.
|
||||
//
|
||||
// The type formatting is identical to FormatType.
|
||||
func FormatCELType(t *Type) string {
|
||||
return checker.FormatCELType(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
|
||||
variables []*decls.VariableDecl
|
||||
functions map[string]*decls.FunctionDecl
|
||||
macros []parser.Macro
|
||||
adapter types.Adapter
|
||||
provider types.Provider
|
||||
features map[int]bool
|
||||
appliedFeatures map[int]bool
|
||||
libraries map[string]bool
|
||||
validators []ASTValidator
|
||||
costOptions []checker.CostOption
|
||||
|
||||
// Internal parser representation
|
||||
prsr *parser.Parser
|
||||
prsrOpts []parser.Option
|
||||
|
||||
// Internal checker representation
|
||||
chkMutex sync.Mutex
|
||||
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{
|
||||
variables: []*decls.VariableDecl{},
|
||||
functions: map[string]*decls.FunctionDecl{},
|
||||
macros: []parser.Macro{},
|
||||
Container: containers.DefaultContainer,
|
||||
adapter: registry,
|
||||
provider: registry,
|
||||
features: map[int]bool{},
|
||||
appliedFeatures: map[int]bool{},
|
||||
libraries: map[string]bool{},
|
||||
validators: []ASTValidator{},
|
||||
progOpts: []ProgramOption{},
|
||||
costOptions: []checker.CostOption{},
|
||||
}).configure(opts)
|
||||
}
|
||||
|
||||
// Check performs type-checking on the input Ast and yields a checked Ast and/or set of Issues.
|
||||
// If any `ASTValidators` are configured on the environment, they will be applied after a valid
|
||||
// type-check result. If any issues are detected, the validators will provide them on the
|
||||
// output Issues object.
|
||||
//
|
||||
// Either checking or validation 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) {
|
||||
// Construct the internal checker env, erroring if there is an issue adding the declarations.
|
||||
chk, err := e.initChecker()
|
||||
if err != nil {
|
||||
errs := common.NewErrors(ast.Source())
|
||||
errs.ReportError(common.NoLocation, err.Error())
|
||||
return nil, NewIssuesWithSourceInfo(errs, ast.NativeRep().SourceInfo())
|
||||
}
|
||||
|
||||
checked, errs := checker.Check(ast.NativeRep(), ast.Source(), chk)
|
||||
if len(errs.GetErrors()) > 0 {
|
||||
return nil, NewIssuesWithSourceInfo(errs, ast.NativeRep().SourceInfo())
|
||||
}
|
||||
// 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.
|
||||
ast = &Ast{
|
||||
source: ast.Source(),
|
||||
impl: checked}
|
||||
|
||||
// Avoid creating a validator config if it's not needed.
|
||||
if len(e.validators) == 0 {
|
||||
return ast, nil
|
||||
}
|
||||
|
||||
// Generate a validator configuration from the set of configured validators.
|
||||
vConfig := newValidatorConfig()
|
||||
for _, v := range e.validators {
|
||||
if cv, ok := v.(ASTValidatorConfigurer); ok {
|
||||
cv.Configure(vConfig)
|
||||
}
|
||||
}
|
||||
// Apply additional validators on the type-checked result.
|
||||
iss := NewIssuesWithSourceInfo(errs, ast.NativeRep().SourceInfo())
|
||||
for _, v := range e.validators {
|
||||
v.Validate(e, vConfig, checked, iss)
|
||||
}
|
||||
if iss.Err() != nil {
|
||||
return nil, iss
|
||||
}
|
||||
return ast, 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) {
|
||||
chk, chkErr := e.getCheckerOrError()
|
||||
if chkErr != nil {
|
||||
return nil, chkErr
|
||||
}
|
||||
|
||||
prsrOptsCopy := make([]parser.Option, len(e.prsrOpts))
|
||||
copy(prsrOptsCopy, e.prsrOpts)
|
||||
|
||||
// The type-checker is configured with Declarations. The declarations may either be provided
|
||||
// as options which have not yet been validated, or may come from a previous checker instance
|
||||
// whose types have already been validated.
|
||||
chkOptsCopy := make([]checker.Option, len(e.chkOpts))
|
||||
copy(chkOptsCopy, e.chkOpts)
|
||||
|
||||
// Copy the declarations if needed.
|
||||
if chk != nil {
|
||||
// If the type-checker has already been instantiated, then the e.declarations have been
|
||||
// validated within the chk instance.
|
||||
chkOptsCopy = append(chkOptsCopy, checker.ValidatedDeclarations(chk))
|
||||
}
|
||||
varsCopy := make([]*decls.VariableDecl, len(e.variables))
|
||||
copy(varsCopy, e.variables)
|
||||
|
||||
// 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.(*types.Registry)
|
||||
providerReg, isProviderReg := e.provider.(*types.Registry)
|
||||
// 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]*decls.FunctionDecl, len(e.functions))
|
||||
for k, v := range e.functions {
|
||||
funcsCopy[k] = v
|
||||
}
|
||||
libsCopy := make(map[string]bool, len(e.libraries))
|
||||
for k, v := range e.libraries {
|
||||
libsCopy[k] = v
|
||||
}
|
||||
validatorsCopy := make([]ASTValidator, len(e.validators))
|
||||
copy(validatorsCopy, e.validators)
|
||||
costOptsCopy := make([]checker.CostOption, len(e.costOptions))
|
||||
copy(costOptsCopy, e.costOptions)
|
||||
|
||||
ext := &Env{
|
||||
Container: e.Container,
|
||||
variables: varsCopy,
|
||||
functions: funcsCopy,
|
||||
macros: macsCopy,
|
||||
progOpts: progOptsCopy,
|
||||
adapter: adapter,
|
||||
features: featuresCopy,
|
||||
appliedFeatures: appliedFeaturesCopy,
|
||||
libraries: libsCopy,
|
||||
validators: validatorsCopy,
|
||||
provider: provider,
|
||||
chkOpts: chkOptsCopy,
|
||||
prsrOpts: prsrOptsCopy,
|
||||
costOptions: costOptsCopy,
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// HasLibrary returns whether a specific SingletonLibrary has been configured in the environment.
|
||||
func (e *Env) HasLibrary(libName string) bool {
|
||||
configured, exists := e.libraries[libName]
|
||||
return exists && configured
|
||||
}
|
||||
|
||||
// Libraries returns a list of SingletonLibrary that have been configured in the environment.
|
||||
func (e *Env) Libraries() []string {
|
||||
libraries := make([]string, 0, len(e.libraries))
|
||||
for libName := range e.libraries {
|
||||
libraries = append(libraries, libName)
|
||||
}
|
||||
return libraries
|
||||
}
|
||||
|
||||
// HasFunction returns whether a specific function has been configured in the environment
|
||||
func (e *Env) HasFunction(functionName string) bool {
|
||||
_, ok := e.functions[functionName]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Functions returns map of Functions, keyed by function name, that have been configured in the environment.
|
||||
func (e *Env) Functions() map[string]*decls.FunctionDecl {
|
||||
return e.functions
|
||||
}
|
||||
|
||||
// HasValidator returns whether a specific ASTValidator has been configured in the environment.
|
||||
func (e *Env) HasValidator(name string) bool {
|
||||
for _, v := range e.validators {
|
||||
if v.Name() == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 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) {
|
||||
parsed, errs := e.prsr.Parse(src)
|
||||
if len(errs.GetErrors()) > 0 {
|
||||
return nil, &Issues{errs: errs}
|
||||
}
|
||||
return &Ast{source: src, impl: parsed}, nil
|
||||
}
|
||||
|
||||
// Program generates an evaluable instance of the Ast within the environment (Env).
|
||||
func (e *Env) Program(ast *Ast, opts ...ProgramOption) (Program, error) {
|
||||
return e.PlanProgram(ast.NativeRep(), opts...)
|
||||
}
|
||||
|
||||
// PlanProgram generates an evaluable instance of the AST in the go-native representation within
|
||||
// the environment (Env).
|
||||
func (e *Env) PlanProgram(a *celast.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, a, optSet)
|
||||
}
|
||||
|
||||
// CELTypeAdapter returns the `types.Adapter` configured for the environment.
|
||||
func (e *Env) CELTypeAdapter() types.Adapter {
|
||||
return e.adapter
|
||||
}
|
||||
|
||||
// CELTypeProvider returns the `types.Provider` configured for the environment.
|
||||
func (e *Env) CELTypeProvider() types.Provider {
|
||||
return e.provider
|
||||
}
|
||||
|
||||
// TypeAdapter returns the `ref.TypeAdapter` configured for the environment.
|
||||
//
|
||||
// Deprecated: use CELTypeAdapter()
|
||||
func (e *Env) TypeAdapter() ref.TypeAdapter {
|
||||
return e.adapter
|
||||
}
|
||||
|
||||
// TypeProvider returns the `ref.TypeProvider` configured for the environment.
|
||||
//
|
||||
// Deprecated: use CELTypeProvider()
|
||||
func (e *Env) TypeProvider() ref.TypeProvider {
|
||||
if legacyProvider, ok := e.provider.(ref.TypeProvider); ok {
|
||||
return legacyProvider
|
||||
}
|
||||
return &interopLegacyTypeProvider{Provider: 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 {
|
||||
act := interpreter.EmptyActivation()
|
||||
part, _ := PartialVars(act, e.computeUnknownVars(act)...)
|
||||
return part
|
||||
}
|
||||
|
||||
// PartialVars returns an interpreter.PartialActivation where all variables not in the input variable
|
||||
// set, but which have been configured in the environment, are marked as unknown.
|
||||
//
|
||||
// The `vars` value may either be an interpreter.Activation or any valid input to the
|
||||
// interpreter.NewActivation call.
|
||||
//
|
||||
// Note, this is equivalent to calling cel.PartialVars and manually configuring the set of unknown
|
||||
// variables. For more advanced use cases of partial state where portions of an object graph, rather
|
||||
// than top-level variables, are missing the PartialVars() method may be a more suitable choice.
|
||||
//
|
||||
// Note, the PartialVars will behave the same as an interpreter.EmptyActivation unless the
|
||||
// PartialAttributes option is provided as a ProgramOption.
|
||||
func (e *Env) PartialVars(vars any) (interpreter.PartialActivation, error) {
|
||||
act, err := interpreter.NewActivation(vars)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return PartialVars(act, e.computeUnknownVars(act)...)
|
||||
}
|
||||
|
||||
// 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.impl.Expr(), a.impl.SourceInfo().MacroCalls(), details.State())
|
||||
newAST := &Ast{source: a.Source(), impl: pruned}
|
||||
expr, err := AstToString(newAST)
|
||||
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, opts ...checker.CostOption) (checker.CostEstimate, error) {
|
||||
extendedOpts := make([]checker.CostOption, 0, len(e.costOptions))
|
||||
extendedOpts = append(extendedOpts, opts...)
|
||||
extendedOpts = append(extendedOpts, e.costOptions...)
|
||||
return checker.Cost(ast.impl, estimator, extendedOpts...)
|
||||
}
|
||||
|
||||
// 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
|
||||
e, err = e.maybeApplyFeature(featureDefaultUTCTimeZone, Lib(timeUTCLibrary{}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Configure the parser.
|
||||
prsrOpts := []parser.Option{}
|
||||
prsrOpts = append(prsrOpts, e.prsrOpts...)
|
||||
prsrOpts = append(prsrOpts, parser.Macros(e.macros...))
|
||||
|
||||
if e.HasFeature(featureEnableMacroCallTracking) {
|
||||
prsrOpts = append(prsrOpts, parser.PopulateMacroCalls(true))
|
||||
}
|
||||
if e.HasFeature(featureVariadicLogicalASTs) {
|
||||
prsrOpts = append(prsrOpts, parser.EnableVariadicOperatorASTs(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() (*checker.Env, error) {
|
||||
e.chkOnce.Do(func() {
|
||||
chkOpts := []checker.Option{}
|
||||
chkOpts = append(chkOpts, e.chkOpts...)
|
||||
chkOpts = append(chkOpts,
|
||||
checker.CrossTypeNumericComparisons(
|
||||
e.HasFeature(featureCrossTypeNumericComparisons)))
|
||||
|
||||
ce, err := checker.NewEnv(e.Container, e.provider, chkOpts...)
|
||||
if err != nil {
|
||||
e.setCheckerOrError(nil, err)
|
||||
return
|
||||
}
|
||||
// Add the statically configured declarations.
|
||||
err = ce.AddIdents(e.variables...)
|
||||
if err != nil {
|
||||
e.setCheckerOrError(nil, err)
|
||||
return
|
||||
}
|
||||
// Add the function declarations which are derived from the FunctionDecl instances.
|
||||
for _, fn := range e.functions {
|
||||
if fn.IsDeclarationDisabled() {
|
||||
continue
|
||||
}
|
||||
err = ce.AddFunctions(fn)
|
||||
if err != nil {
|
||||
e.setCheckerOrError(nil, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Add function declarations here separately.
|
||||
e.setCheckerOrError(ce, nil)
|
||||
})
|
||||
return e.getCheckerOrError()
|
||||
}
|
||||
|
||||
// setCheckerOrError sets the checker.Env or error state in a concurrency-safe manner
|
||||
func (e *Env) setCheckerOrError(chk *checker.Env, chkErr error) {
|
||||
e.chkMutex.Lock()
|
||||
e.chk = chk
|
||||
e.chkErr = chkErr
|
||||
e.chkMutex.Unlock()
|
||||
}
|
||||
|
||||
// getCheckerOrError gets the checker.Env or error state in a concurrency-safe manner
|
||||
func (e *Env) getCheckerOrError() (*checker.Env, error) {
|
||||
e.chkMutex.Lock()
|
||||
defer e.chkMutex.Unlock()
|
||||
return e.chk, e.chkErr
|
||||
}
|
||||
|
||||
// maybeApplyFeature determines whether the feature-guarded option is enabled, and if so applies
|
||||
// the feature if it has not already been enabled.
|
||||
func (e *Env) maybeApplyFeature(feature int, option EnvOption) (*Env, error) {
|
||||
if !e.HasFeature(feature) {
|
||||
return e, nil
|
||||
}
|
||||
_, applied := e.appliedFeatures[feature]
|
||||
if applied {
|
||||
return e, nil
|
||||
}
|
||||
e, err := option(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// record that the feature has been applied since it will generate declarations
|
||||
// and functions which will be propagated on Extend() calls and which should only
|
||||
// be registered once.
|
||||
e.appliedFeatures[feature] = true
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// computeUnknownVars determines a set of missing variables based on the input activation and the
|
||||
// environment's configured declaration set.
|
||||
func (e *Env) computeUnknownVars(vars interpreter.Activation) []*interpreter.AttributePattern {
|
||||
var unknownPatterns []*interpreter.AttributePattern
|
||||
for _, v := range e.variables {
|
||||
varName := v.Name()
|
||||
if _, found := vars.ResolveName(varName); found {
|
||||
continue
|
||||
}
|
||||
unknownPatterns = append(unknownPatterns, interpreter.NewAttributePattern(varName))
|
||||
}
|
||||
return unknownPatterns
|
||||
}
|
||||
|
||||
// Error type which references an expression id, a location within source, and a message.
|
||||
type Error = common.Error
|
||||
|
||||
// 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
|
||||
info *celast.SourceInfo
|
||||
}
|
||||
|
||||
// NewIssues returns an Issues struct from a common.Errors object.
|
||||
func NewIssues(errs *common.Errors) *Issues {
|
||||
return NewIssuesWithSourceInfo(errs, nil)
|
||||
}
|
||||
|
||||
// NewIssuesWithSourceInfo returns an Issues struct from a common.Errors object with SourceInfo metatata
|
||||
// which can be used with the `ReportErrorAtID` method for additional error reports within the context
|
||||
// information that's inferred from an expression id.
|
||||
func NewIssuesWithSourceInfo(errs *common.Errors, info *celast.SourceInfo) *Issues {
|
||||
return &Issues{
|
||||
errs: errs,
|
||||
info: info,
|
||||
}
|
||||
}
|
||||
|
||||
// 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() []*Error {
|
||||
if i == nil {
|
||||
return []*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 || i == other {
|
||||
return i
|
||||
}
|
||||
return NewIssuesWithSourceInfo(i.errs.Append(other.errs.GetErrors()), i.info)
|
||||
}
|
||||
|
||||
// String converts the issues to a suitable display string.
|
||||
func (i *Issues) String() string {
|
||||
if i == nil {
|
||||
return ""
|
||||
}
|
||||
return i.errs.ToDisplayString()
|
||||
}
|
||||
|
||||
// ReportErrorAtID reports an error message with an optional set of formatting arguments.
|
||||
//
|
||||
// The source metadata for the expression at `id`, if present, is attached to the error report.
|
||||
// To ensure that source metadata is attached to error reports, use NewIssuesWithSourceInfo.
|
||||
func (i *Issues) ReportErrorAtID(id int64, message string, args ...any) {
|
||||
i.errs.ReportErrorAtID(id, i.info.GetStartLocation(id), message, args...)
|
||||
}
|
||||
|
||||
// getStdEnv lazy initializes the CEL standard environment.
|
||||
func getStdEnv() (*Env, error) {
|
||||
stdEnvInit.Do(func() {
|
||||
stdEnv, stdEnvErr = NewCustomEnv(StdLib(), EagerlyValidateDeclarations(true))
|
||||
})
|
||||
return stdEnv, stdEnvErr
|
||||
}
|
||||
|
||||
// interopCELTypeProvider layers support for the types.Provider interface on top of a ref.TypeProvider.
|
||||
type interopCELTypeProvider struct {
|
||||
ref.TypeProvider
|
||||
}
|
||||
|
||||
// FindStructType returns a types.Type instance for the given fully-qualified typeName if one exists.
|
||||
//
|
||||
// This method proxies to the underlying ref.TypeProvider's FindType method and converts protobuf type
|
||||
// into a native type representation. If the conversion fails, the type is listed as not found.
|
||||
func (p *interopCELTypeProvider) FindStructType(typeName string) (*types.Type, bool) {
|
||||
if et, found := p.FindType(typeName); found {
|
||||
t, err := types.ExprTypeToType(et)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return t, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// FindStructFieldNames returns an empty set of field for the interop provider.
|
||||
//
|
||||
// To inspect the field names, migrate to a `types.Provider` implementation.
|
||||
func (p *interopCELTypeProvider) FindStructFieldNames(typeName string) ([]string, bool) {
|
||||
return []string{}, false
|
||||
}
|
||||
|
||||
// FindStructFieldType returns a types.FieldType instance for the given fully-qualified typeName and field
|
||||
// name, if one exists.
|
||||
//
|
||||
// This method proxies to the underlying ref.TypeProvider's FindFieldType method and converts protobuf type
|
||||
// into a native type representation. If the conversion fails, the type is listed as not found.
|
||||
func (p *interopCELTypeProvider) FindStructFieldType(structType, fieldName string) (*types.FieldType, bool) {
|
||||
if ft, found := p.FindFieldType(structType, fieldName); found {
|
||||
t, err := types.ExprTypeToType(ft.Type)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return &types.FieldType{
|
||||
Type: t,
|
||||
IsSet: ft.IsSet,
|
||||
GetFrom: ft.GetFrom,
|
||||
}, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// interopLegacyTypeProvider layers support for the ref.TypeProvider interface on top of a types.Provider.
|
||||
type interopLegacyTypeProvider struct {
|
||||
types.Provider
|
||||
}
|
||||
|
||||
// FindType retruns the protobuf Type representation for the input type name if one exists.
|
||||
//
|
||||
// This method proxies to the underlying types.Provider FindStructType method and converts the types.Type
|
||||
// value to a protobuf Type representation.
|
||||
//
|
||||
// Failure to convert the type will result in the type not being found.
|
||||
func (p *interopLegacyTypeProvider) FindType(typeName string) (*exprpb.Type, bool) {
|
||||
if t, found := p.FindStructType(typeName); found {
|
||||
et, err := types.TypeToExprType(t)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return et, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// FindFieldType returns the protobuf-based FieldType representation for the input type name and field,
|
||||
// if one exists.
|
||||
//
|
||||
// This call proxies to the types.Provider FindStructFieldType method and converts the types.FIeldType
|
||||
// value to a protobuf-based ref.FieldType representation if found.
|
||||
//
|
||||
// Failure to convert the FieldType will result in the field not being found.
|
||||
func (p *interopLegacyTypeProvider) FindFieldType(structType, fieldName string) (*ref.FieldType, bool) {
|
||||
if cft, found := p.FindStructFieldType(structType, fieldName); found {
|
||||
et, err := types.TypeToExprType(cft.Type)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return &ref.FieldType{
|
||||
Type: et,
|
||||
IsSet: cft.IsSet,
|
||||
GetFrom: cft.GetFrom,
|
||||
}, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var (
|
||||
stdEnvInit sync.Once
|
||||
stdEnv *Env
|
||||
stdEnvErr error
|
||||
)
|
559
e2e/vendor/github.com/google/cel-go/cel/folding.go
generated
vendored
Normal file
559
e2e/vendor/github.com/google/cel-go/cel/folding.go
generated
vendored
Normal file
@ -0,0 +1,559 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
)
|
||||
|
||||
// ConstantFoldingOption defines a functional option for configuring constant folding.
|
||||
type ConstantFoldingOption func(opt *constantFoldingOptimizer) (*constantFoldingOptimizer, error)
|
||||
|
||||
// MaxConstantFoldIterations limits the number of times literals may be folding during optimization.
|
||||
//
|
||||
// Defaults to 100 if not set.
|
||||
func MaxConstantFoldIterations(limit int) ConstantFoldingOption {
|
||||
return func(opt *constantFoldingOptimizer) (*constantFoldingOptimizer, error) {
|
||||
opt.maxFoldIterations = limit
|
||||
return opt, nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewConstantFoldingOptimizer creates an optimizer which inlines constant scalar an aggregate
|
||||
// literal values within function calls and select statements with their evaluated result.
|
||||
func NewConstantFoldingOptimizer(opts ...ConstantFoldingOption) (ASTOptimizer, error) {
|
||||
folder := &constantFoldingOptimizer{
|
||||
maxFoldIterations: defaultMaxConstantFoldIterations,
|
||||
}
|
||||
var err error
|
||||
for _, o := range opts {
|
||||
folder, err = o(folder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
type constantFoldingOptimizer struct {
|
||||
maxFoldIterations int
|
||||
}
|
||||
|
||||
// Optimize queries the expression graph for scalar and aggregate literal expressions within call and
|
||||
// select statements and then evaluates them and replaces the call site with the literal result.
|
||||
//
|
||||
// Note: only values which can be represented as literals in CEL syntax are supported.
|
||||
func (opt *constantFoldingOptimizer) Optimize(ctx *OptimizerContext, a *ast.AST) *ast.AST {
|
||||
root := ast.NavigateAST(a)
|
||||
|
||||
// Walk the list of foldable expression and continue to fold until there are no more folds left.
|
||||
// All of the fold candidates returned by the constantExprMatcher should succeed unless there's
|
||||
// a logic bug with the selection of expressions.
|
||||
foldableExprs := ast.MatchDescendants(root, constantExprMatcher)
|
||||
foldCount := 0
|
||||
for len(foldableExprs) != 0 && foldCount < opt.maxFoldIterations {
|
||||
for _, fold := range foldableExprs {
|
||||
// If the expression could be folded because it's a non-strict call, and the
|
||||
// branches are pruned, continue to the next fold.
|
||||
if fold.Kind() == ast.CallKind && maybePruneBranches(ctx, fold) {
|
||||
continue
|
||||
}
|
||||
// Otherwise, assume all context is needed to evaluate the expression.
|
||||
err := tryFold(ctx, a, fold)
|
||||
if err != nil {
|
||||
ctx.ReportErrorAtID(fold.ID(), "constant-folding evaluation failed: %v", err.Error())
|
||||
return a
|
||||
}
|
||||
}
|
||||
foldCount++
|
||||
foldableExprs = ast.MatchDescendants(root, constantExprMatcher)
|
||||
}
|
||||
// Once all of the constants have been folded, try to run through the remaining comprehensions
|
||||
// one last time. In this case, there's no guarantee they'll run, so we only update the
|
||||
// target comprehension node with the literal value if the evaluation succeeds.
|
||||
for _, compre := range ast.MatchDescendants(root, ast.KindMatcher(ast.ComprehensionKind)) {
|
||||
tryFold(ctx, a, compre)
|
||||
}
|
||||
|
||||
// If the output is a list, map, or struct which contains optional entries, then prune it
|
||||
// to make sure that the optionals, if resolved, do not surface in the output literal.
|
||||
pruneOptionalElements(ctx, root)
|
||||
|
||||
// Ensure that all intermediate values in the folded expression can be represented as valid
|
||||
// CEL literals within the AST structure. Use `PostOrderVisit` rather than `MatchDescendents`
|
||||
// to avoid extra allocations during this final pass through the AST.
|
||||
ast.PostOrderVisit(root, ast.NewExprVisitor(func(e ast.Expr) {
|
||||
if e.Kind() != ast.LiteralKind {
|
||||
return
|
||||
}
|
||||
val := e.AsLiteral()
|
||||
adapted, err := adaptLiteral(ctx, val)
|
||||
if err != nil {
|
||||
ctx.ReportErrorAtID(root.ID(), "constant-folding evaluation failed: %v", err.Error())
|
||||
return
|
||||
}
|
||||
ctx.UpdateExpr(e, adapted)
|
||||
}))
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// tryFold attempts to evaluate a sub-expression to a literal.
|
||||
//
|
||||
// If the evaluation succeeds, the input expr value will be modified to become a literal, otherwise
|
||||
// the method will return an error.
|
||||
func tryFold(ctx *OptimizerContext, a *ast.AST, expr ast.Expr) error {
|
||||
// Assume all context is needed to evaluate the expression.
|
||||
subAST := &Ast{
|
||||
impl: ast.NewCheckedAST(ast.NewAST(expr, a.SourceInfo()), a.TypeMap(), a.ReferenceMap()),
|
||||
}
|
||||
prg, err := ctx.Program(subAST)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, _, err := prg.Eval(NoVars())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Update the fold expression to be a literal.
|
||||
ctx.UpdateExpr(expr, ctx.NewLiteral(out))
|
||||
return nil
|
||||
}
|
||||
|
||||
// maybePruneBranches inspects the non-strict call expression to determine whether
|
||||
// a branch can be removed. Evaluation will naturally prune logical and / or calls,
|
||||
// but conditional will not be pruned cleanly, so this is one small area where the
|
||||
// constant folding step reimplements a portion of the evaluator.
|
||||
func maybePruneBranches(ctx *OptimizerContext, expr ast.NavigableExpr) bool {
|
||||
call := expr.AsCall()
|
||||
args := call.Args()
|
||||
switch call.FunctionName() {
|
||||
case operators.LogicalAnd, operators.LogicalOr:
|
||||
return maybeShortcircuitLogic(ctx, call.FunctionName(), args, expr)
|
||||
case operators.Conditional:
|
||||
cond := args[0]
|
||||
truthy := args[1]
|
||||
falsy := args[2]
|
||||
if cond.Kind() != ast.LiteralKind {
|
||||
return false
|
||||
}
|
||||
if cond.AsLiteral() == types.True {
|
||||
ctx.UpdateExpr(expr, truthy)
|
||||
} else {
|
||||
ctx.UpdateExpr(expr, falsy)
|
||||
}
|
||||
return true
|
||||
case operators.In:
|
||||
haystack := args[1]
|
||||
if haystack.Kind() == ast.ListKind && haystack.AsList().Size() == 0 {
|
||||
ctx.UpdateExpr(expr, ctx.NewLiteral(types.False))
|
||||
return true
|
||||
}
|
||||
needle := args[0]
|
||||
if needle.Kind() == ast.LiteralKind && haystack.Kind() == ast.ListKind {
|
||||
needleValue := needle.AsLiteral()
|
||||
list := haystack.AsList()
|
||||
for _, e := range list.Elements() {
|
||||
if e.Kind() == ast.LiteralKind && e.AsLiteral().Equal(needleValue) == types.True {
|
||||
ctx.UpdateExpr(expr, ctx.NewLiteral(types.True))
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func maybeShortcircuitLogic(ctx *OptimizerContext, function string, args []ast.Expr, expr ast.NavigableExpr) bool {
|
||||
shortcircuit := types.False
|
||||
skip := types.True
|
||||
if function == operators.LogicalOr {
|
||||
shortcircuit = types.True
|
||||
skip = types.False
|
||||
}
|
||||
newArgs := []ast.Expr{}
|
||||
for _, arg := range args {
|
||||
if arg.Kind() != ast.LiteralKind {
|
||||
newArgs = append(newArgs, arg)
|
||||
continue
|
||||
}
|
||||
if arg.AsLiteral() == skip {
|
||||
continue
|
||||
}
|
||||
if arg.AsLiteral() == shortcircuit {
|
||||
ctx.UpdateExpr(expr, arg)
|
||||
return true
|
||||
}
|
||||
}
|
||||
if len(newArgs) == 0 {
|
||||
newArgs = append(newArgs, args[0])
|
||||
ctx.UpdateExpr(expr, newArgs[0])
|
||||
return true
|
||||
}
|
||||
if len(newArgs) == 1 {
|
||||
ctx.UpdateExpr(expr, newArgs[0])
|
||||
return true
|
||||
}
|
||||
ctx.UpdateExpr(expr, ctx.NewCall(function, newArgs...))
|
||||
return true
|
||||
}
|
||||
|
||||
// pruneOptionalElements works from the bottom up to resolve optional elements within
|
||||
// aggregate literals.
|
||||
//
|
||||
// Note, many aggregate literals will be resolved as arguments to functions or select
|
||||
// statements, so this method exists to handle the case where the literal could not be
|
||||
// fully resolved or exists outside of a call, select, or comprehension context.
|
||||
func pruneOptionalElements(ctx *OptimizerContext, root ast.NavigableExpr) {
|
||||
aggregateLiterals := ast.MatchDescendants(root, aggregateLiteralMatcher)
|
||||
for _, lit := range aggregateLiterals {
|
||||
switch lit.Kind() {
|
||||
case ast.ListKind:
|
||||
pruneOptionalListElements(ctx, lit)
|
||||
case ast.MapKind:
|
||||
pruneOptionalMapEntries(ctx, lit)
|
||||
case ast.StructKind:
|
||||
pruneOptionalStructFields(ctx, lit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pruneOptionalListElements(ctx *OptimizerContext, e ast.Expr) {
|
||||
l := e.AsList()
|
||||
elems := l.Elements()
|
||||
optIndices := l.OptionalIndices()
|
||||
if len(optIndices) == 0 {
|
||||
return
|
||||
}
|
||||
updatedElems := []ast.Expr{}
|
||||
updatedIndices := []int32{}
|
||||
newOptIndex := -1
|
||||
for _, e := range elems {
|
||||
newOptIndex++
|
||||
if !l.IsOptional(int32(newOptIndex)) {
|
||||
updatedElems = append(updatedElems, e)
|
||||
continue
|
||||
}
|
||||
if e.Kind() != ast.LiteralKind {
|
||||
updatedElems = append(updatedElems, e)
|
||||
updatedIndices = append(updatedIndices, int32(newOptIndex))
|
||||
continue
|
||||
}
|
||||
optElemVal, ok := e.AsLiteral().(*types.Optional)
|
||||
if !ok {
|
||||
updatedElems = append(updatedElems, e)
|
||||
updatedIndices = append(updatedIndices, int32(newOptIndex))
|
||||
continue
|
||||
}
|
||||
if !optElemVal.HasValue() {
|
||||
newOptIndex-- // Skipping causes the list to get smaller.
|
||||
continue
|
||||
}
|
||||
ctx.UpdateExpr(e, ctx.NewLiteral(optElemVal.GetValue()))
|
||||
updatedElems = append(updatedElems, e)
|
||||
}
|
||||
ctx.UpdateExpr(e, ctx.NewList(updatedElems, updatedIndices))
|
||||
}
|
||||
|
||||
func pruneOptionalMapEntries(ctx *OptimizerContext, e ast.Expr) {
|
||||
m := e.AsMap()
|
||||
entries := m.Entries()
|
||||
updatedEntries := []ast.EntryExpr{}
|
||||
modified := false
|
||||
for _, e := range entries {
|
||||
entry := e.AsMapEntry()
|
||||
key := entry.Key()
|
||||
val := entry.Value()
|
||||
// If the entry is not optional, or the value-side of the optional hasn't
|
||||
// been resolved to a literal, then preserve the entry as-is.
|
||||
if !entry.IsOptional() || val.Kind() != ast.LiteralKind {
|
||||
updatedEntries = append(updatedEntries, e)
|
||||
continue
|
||||
}
|
||||
optElemVal, ok := val.AsLiteral().(*types.Optional)
|
||||
if !ok {
|
||||
updatedEntries = append(updatedEntries, e)
|
||||
continue
|
||||
}
|
||||
// When the key is not a literal, but the value is, then it needs to be
|
||||
// restored to an optional value.
|
||||
if key.Kind() != ast.LiteralKind {
|
||||
undoOptVal, err := adaptLiteral(ctx, optElemVal)
|
||||
if err != nil {
|
||||
ctx.ReportErrorAtID(val.ID(), "invalid map value literal %v: %v", optElemVal, err)
|
||||
}
|
||||
ctx.UpdateExpr(val, undoOptVal)
|
||||
updatedEntries = append(updatedEntries, e)
|
||||
continue
|
||||
}
|
||||
modified = true
|
||||
if !optElemVal.HasValue() {
|
||||
continue
|
||||
}
|
||||
ctx.UpdateExpr(val, ctx.NewLiteral(optElemVal.GetValue()))
|
||||
updatedEntry := ctx.NewMapEntry(key, val, false)
|
||||
updatedEntries = append(updatedEntries, updatedEntry)
|
||||
}
|
||||
if modified {
|
||||
ctx.UpdateExpr(e, ctx.NewMap(updatedEntries))
|
||||
}
|
||||
}
|
||||
|
||||
func pruneOptionalStructFields(ctx *OptimizerContext, e ast.Expr) {
|
||||
s := e.AsStruct()
|
||||
fields := s.Fields()
|
||||
updatedFields := []ast.EntryExpr{}
|
||||
modified := false
|
||||
for _, f := range fields {
|
||||
field := f.AsStructField()
|
||||
val := field.Value()
|
||||
if !field.IsOptional() || val.Kind() != ast.LiteralKind {
|
||||
updatedFields = append(updatedFields, f)
|
||||
continue
|
||||
}
|
||||
optElemVal, ok := val.AsLiteral().(*types.Optional)
|
||||
if !ok {
|
||||
updatedFields = append(updatedFields, f)
|
||||
continue
|
||||
}
|
||||
modified = true
|
||||
if !optElemVal.HasValue() {
|
||||
continue
|
||||
}
|
||||
ctx.UpdateExpr(val, ctx.NewLiteral(optElemVal.GetValue()))
|
||||
updatedField := ctx.NewStructField(field.Name(), val, false)
|
||||
updatedFields = append(updatedFields, updatedField)
|
||||
}
|
||||
if modified {
|
||||
ctx.UpdateExpr(e, ctx.NewStruct(s.TypeName(), updatedFields))
|
||||
}
|
||||
}
|
||||
|
||||
// adaptLiteral converts a runtime CEL value to its equivalent literal expression.
|
||||
//
|
||||
// For strongly typed values, the type-provider will be used to reconstruct the fields
|
||||
// which are present in the literal and their equivalent initialization values.
|
||||
func adaptLiteral(ctx *OptimizerContext, val ref.Val) (ast.Expr, error) {
|
||||
switch t := val.Type().(type) {
|
||||
case *types.Type:
|
||||
switch t {
|
||||
case types.BoolType, types.BytesType, types.DoubleType, types.IntType,
|
||||
types.NullType, types.StringType, types.UintType:
|
||||
return ctx.NewLiteral(val), nil
|
||||
case types.DurationType:
|
||||
return ctx.NewCall(
|
||||
overloads.TypeConvertDuration,
|
||||
ctx.NewLiteral(val.ConvertToType(types.StringType)),
|
||||
), nil
|
||||
case types.TimestampType:
|
||||
return ctx.NewCall(
|
||||
overloads.TypeConvertTimestamp,
|
||||
ctx.NewLiteral(val.ConvertToType(types.StringType)),
|
||||
), nil
|
||||
case types.OptionalType:
|
||||
opt := val.(*types.Optional)
|
||||
if !opt.HasValue() {
|
||||
return ctx.NewCall("optional.none"), nil
|
||||
}
|
||||
target, err := adaptLiteral(ctx, opt.GetValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ctx.NewCall("optional.of", target), nil
|
||||
case types.TypeType:
|
||||
return ctx.NewIdent(val.(*types.Type).TypeName()), nil
|
||||
case types.ListType:
|
||||
l, ok := val.(traits.Lister)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to adapt %v to literal", val)
|
||||
}
|
||||
elems := make([]ast.Expr, l.Size().(types.Int))
|
||||
idx := 0
|
||||
it := l.Iterator()
|
||||
for it.HasNext() == types.True {
|
||||
elemVal := it.Next()
|
||||
elemExpr, err := adaptLiteral(ctx, elemVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elems[idx] = elemExpr
|
||||
idx++
|
||||
}
|
||||
return ctx.NewList(elems, []int32{}), nil
|
||||
case types.MapType:
|
||||
m, ok := val.(traits.Mapper)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to adapt %v to literal", val)
|
||||
}
|
||||
entries := make([]ast.EntryExpr, m.Size().(types.Int))
|
||||
idx := 0
|
||||
it := m.Iterator()
|
||||
for it.HasNext() == types.True {
|
||||
keyVal := it.Next()
|
||||
keyExpr, err := adaptLiteral(ctx, keyVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valVal := m.Get(keyVal)
|
||||
valExpr, err := adaptLiteral(ctx, valVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries[idx] = ctx.NewMapEntry(keyExpr, valExpr, false)
|
||||
idx++
|
||||
}
|
||||
return ctx.NewMap(entries), nil
|
||||
default:
|
||||
provider := ctx.CELTypeProvider()
|
||||
fields, found := provider.FindStructFieldNames(t.TypeName())
|
||||
if !found {
|
||||
return nil, fmt.Errorf("failed to adapt %v to literal", val)
|
||||
}
|
||||
tester := val.(traits.FieldTester)
|
||||
indexer := val.(traits.Indexer)
|
||||
fieldInits := []ast.EntryExpr{}
|
||||
for _, f := range fields {
|
||||
field := types.String(f)
|
||||
if tester.IsSet(field) != types.True {
|
||||
continue
|
||||
}
|
||||
fieldVal := indexer.Get(field)
|
||||
fieldExpr, err := adaptLiteral(ctx, fieldVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldInits = append(fieldInits, ctx.NewStructField(f, fieldExpr, false))
|
||||
}
|
||||
return ctx.NewStruct(t.TypeName(), fieldInits), nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("failed to adapt %v to literal", val)
|
||||
}
|
||||
|
||||
// constantExprMatcher matches calls, select statements, and comprehensions whose arguments
|
||||
// are all constant scalar or aggregate literal values.
|
||||
//
|
||||
// Only comprehensions which are not nested are included as possible constant folds, and only
|
||||
// if all variables referenced in the comprehension stack exist are only iteration or
|
||||
// accumulation variables.
|
||||
func constantExprMatcher(e ast.NavigableExpr) bool {
|
||||
switch e.Kind() {
|
||||
case ast.CallKind:
|
||||
return constantCallMatcher(e)
|
||||
case ast.SelectKind:
|
||||
sel := e.AsSelect() // guaranteed to be a navigable value
|
||||
return constantMatcher(sel.Operand().(ast.NavigableExpr))
|
||||
case ast.ComprehensionKind:
|
||||
if isNestedComprehension(e) {
|
||||
return false
|
||||
}
|
||||
vars := map[string]bool{}
|
||||
constantExprs := true
|
||||
visitor := ast.NewExprVisitor(func(e ast.Expr) {
|
||||
if e.Kind() == ast.ComprehensionKind {
|
||||
nested := e.AsComprehension()
|
||||
vars[nested.AccuVar()] = true
|
||||
vars[nested.IterVar()] = true
|
||||
}
|
||||
if e.Kind() == ast.IdentKind && !vars[e.AsIdent()] {
|
||||
constantExprs = false
|
||||
}
|
||||
})
|
||||
ast.PreOrderVisit(e, visitor)
|
||||
return constantExprs
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// constantCallMatcher identifies strict and non-strict calls which can be folded.
|
||||
func constantCallMatcher(e ast.NavigableExpr) bool {
|
||||
call := e.AsCall()
|
||||
children := e.Children()
|
||||
fnName := call.FunctionName()
|
||||
if fnName == operators.LogicalAnd {
|
||||
for _, child := range children {
|
||||
if child.Kind() == ast.LiteralKind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
if fnName == operators.LogicalOr {
|
||||
for _, child := range children {
|
||||
if child.Kind() == ast.LiteralKind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
if fnName == operators.Conditional {
|
||||
cond := children[0]
|
||||
if cond.Kind() == ast.LiteralKind && cond.AsLiteral().Type() == types.BoolType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if fnName == operators.In {
|
||||
haystack := children[1]
|
||||
if haystack.Kind() == ast.ListKind && haystack.AsList().Size() == 0 {
|
||||
return true
|
||||
}
|
||||
needle := children[0]
|
||||
if needle.Kind() == ast.LiteralKind && haystack.Kind() == ast.ListKind {
|
||||
needleValue := needle.AsLiteral()
|
||||
list := haystack.AsList()
|
||||
for _, e := range list.Elements() {
|
||||
if e.Kind() == ast.LiteralKind && e.AsLiteral().Equal(needleValue) == types.True {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// convert all other calls with constant arguments
|
||||
for _, child := range children {
|
||||
if !constantMatcher(child) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isNestedComprehension(e ast.NavigableExpr) bool {
|
||||
parent, found := e.Parent()
|
||||
for found {
|
||||
if parent.Kind() == ast.ComprehensionKind {
|
||||
return true
|
||||
}
|
||||
parent, found = parent.Parent()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func aggregateLiteralMatcher(e ast.NavigableExpr) bool {
|
||||
return e.Kind() == ast.ListKind || e.Kind() == ast.MapKind || e.Kind() == ast.StructKind
|
||||
}
|
||||
|
||||
var (
|
||||
constantMatcher = ast.ConstantValueMatcher()
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMaxConstantFoldIterations = 100
|
||||
)
|
228
e2e/vendor/github.com/google/cel-go/cel/inlining.go
generated
vendored
Normal file
228
e2e/vendor/github.com/google/cel-go/cel/inlining.go
generated
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cel
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
)
|
||||
|
||||
// InlineVariable holds a variable name to be matched and an AST representing
|
||||
// the expression graph which should be used to replace it.
|
||||
type InlineVariable struct {
|
||||
name string
|
||||
alias string
|
||||
def *ast.AST
|
||||
}
|
||||
|
||||
// Name returns the qualified variable or field selection to replace.
|
||||
func (v *InlineVariable) Name() string {
|
||||
return v.name
|
||||
}
|
||||
|
||||
// Alias returns the alias to use when performing cel.bind() calls during inlining.
|
||||
func (v *InlineVariable) Alias() string {
|
||||
return v.alias
|
||||
}
|
||||
|
||||
// Expr returns the inlined expression value.
|
||||
func (v *InlineVariable) Expr() ast.Expr {
|
||||
return v.def.Expr()
|
||||
}
|
||||
|
||||
// Type indicates the inlined expression type.
|
||||
func (v *InlineVariable) Type() *Type {
|
||||
return v.def.GetType(v.def.Expr().ID())
|
||||
}
|
||||
|
||||
// NewInlineVariable declares a variable name to be replaced by a checked expression.
|
||||
func NewInlineVariable(name string, definition *Ast) *InlineVariable {
|
||||
return NewInlineVariableWithAlias(name, name, definition)
|
||||
}
|
||||
|
||||
// NewInlineVariableWithAlias declares a variable name to be replaced by a checked expression.
|
||||
// If the variable occurs more than once, the provided alias will be used to replace the expressions
|
||||
// where the variable name occurs.
|
||||
func NewInlineVariableWithAlias(name, alias string, definition *Ast) *InlineVariable {
|
||||
return &InlineVariable{name: name, alias: alias, def: definition.impl}
|
||||
}
|
||||
|
||||
// NewInliningOptimizer creates and optimizer which replaces variables with expression definitions.
|
||||
//
|
||||
// If a variable occurs one time, the variable is replaced by the inline definition. If the
|
||||
// variable occurs more than once, the variable occurences are replaced by a cel.bind() call.
|
||||
func NewInliningOptimizer(inlineVars ...*InlineVariable) ASTOptimizer {
|
||||
return &inliningOptimizer{variables: inlineVars}
|
||||
}
|
||||
|
||||
type inliningOptimizer struct {
|
||||
variables []*InlineVariable
|
||||
}
|
||||
|
||||
func (opt *inliningOptimizer) Optimize(ctx *OptimizerContext, a *ast.AST) *ast.AST {
|
||||
root := ast.NavigateAST(a)
|
||||
for _, inlineVar := range opt.variables {
|
||||
matches := ast.MatchDescendants(root, opt.matchVariable(inlineVar.Name()))
|
||||
// Skip cases where the variable isn't in the expression graph
|
||||
if len(matches) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// For a single match, do a direct replacement of the expression sub-graph.
|
||||
if len(matches) == 1 || !isBindable(matches, inlineVar.Expr(), inlineVar.Type()) {
|
||||
for _, match := range matches {
|
||||
// Copy the inlined AST expr and source info.
|
||||
copyExpr := ctx.CopyASTAndMetadata(inlineVar.def)
|
||||
opt.inlineExpr(ctx, match, copyExpr, inlineVar.Type())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// For multiple matches, find the least common ancestor (lca) and insert the
|
||||
// variable as a cel.bind() macro.
|
||||
var lca ast.NavigableExpr = root
|
||||
lcaAncestorCount := 0
|
||||
ancestors := map[int64]int{}
|
||||
for _, match := range matches {
|
||||
// Update the identifier matches with the provided alias.
|
||||
parent, found := match, true
|
||||
for found {
|
||||
ancestorCount, hasAncestor := ancestors[parent.ID()]
|
||||
if !hasAncestor {
|
||||
ancestors[parent.ID()] = 1
|
||||
parent, found = parent.Parent()
|
||||
continue
|
||||
}
|
||||
if lcaAncestorCount < ancestorCount || (lcaAncestorCount == ancestorCount && lca.Depth() < parent.Depth()) {
|
||||
lca = parent
|
||||
lcaAncestorCount = ancestorCount
|
||||
}
|
||||
ancestors[parent.ID()] = ancestorCount + 1
|
||||
parent, found = parent.Parent()
|
||||
}
|
||||
aliasExpr := ctx.NewIdent(inlineVar.Alias())
|
||||
opt.inlineExpr(ctx, match, aliasExpr, inlineVar.Type())
|
||||
}
|
||||
|
||||
// Copy the inlined AST expr and source info.
|
||||
copyExpr := ctx.CopyASTAndMetadata(inlineVar.def)
|
||||
// Update the least common ancestor by inserting a cel.bind() call to the alias.
|
||||
inlined, bindMacro := ctx.NewBindMacro(lca.ID(), inlineVar.Alias(), copyExpr, lca)
|
||||
opt.inlineExpr(ctx, lca, inlined, inlineVar.Type())
|
||||
ctx.SetMacroCall(lca.ID(), bindMacro)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// inlineExpr replaces the current expression with the inlined one, unless the location of the inlining
|
||||
// happens within a presence test, e.g. has(a.b.c) -> inline alpha for a.b.c in which case an attempt is
|
||||
// made to determine whether the inlined value can be presence or existence tested.
|
||||
func (opt *inliningOptimizer) inlineExpr(ctx *OptimizerContext, prev ast.NavigableExpr, inlined ast.Expr, inlinedType *Type) {
|
||||
switch prev.Kind() {
|
||||
case ast.SelectKind:
|
||||
sel := prev.AsSelect()
|
||||
if !sel.IsTestOnly() {
|
||||
ctx.UpdateExpr(prev, inlined)
|
||||
return
|
||||
}
|
||||
opt.rewritePresenceExpr(ctx, prev, inlined, inlinedType)
|
||||
default:
|
||||
ctx.UpdateExpr(prev, inlined)
|
||||
}
|
||||
}
|
||||
|
||||
// rewritePresenceExpr converts the inlined expression, when it occurs within a has() macro, to type-safe
|
||||
// expression appropriate for the inlined type, if possible.
|
||||
//
|
||||
// If the rewrite is not possible an error is reported at the inline expression site.
|
||||
func (opt *inliningOptimizer) rewritePresenceExpr(ctx *OptimizerContext, prev, inlined ast.Expr, inlinedType *Type) {
|
||||
// If the input inlined expression is not a select expression it won't work with the has()
|
||||
// macro. Attempt to rewrite the presence test in terms of the typed input, otherwise error.
|
||||
if inlined.Kind() == ast.SelectKind {
|
||||
presenceTest, hasMacro := ctx.NewHasMacro(prev.ID(), inlined)
|
||||
ctx.UpdateExpr(prev, presenceTest)
|
||||
ctx.SetMacroCall(prev.ID(), hasMacro)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.ClearMacroCall(prev.ID())
|
||||
if inlinedType.IsAssignableType(NullType) {
|
||||
ctx.UpdateExpr(prev,
|
||||
ctx.NewCall(operators.NotEquals,
|
||||
inlined,
|
||||
ctx.NewLiteral(types.NullValue),
|
||||
))
|
||||
return
|
||||
}
|
||||
if inlinedType.HasTrait(traits.SizerType) {
|
||||
ctx.UpdateExpr(prev,
|
||||
ctx.NewCall(operators.NotEquals,
|
||||
ctx.NewMemberCall(overloads.Size, inlined),
|
||||
ctx.NewLiteral(types.IntZero),
|
||||
))
|
||||
return
|
||||
}
|
||||
ctx.ReportErrorAtID(prev.ID(), "unable to inline expression type %v into presence test", inlinedType)
|
||||
}
|
||||
|
||||
// isBindable indicates whether the inlined type can be used within a cel.bind() if the expression
|
||||
// being replaced occurs within a presence test. Value types with a size() method or field selection
|
||||
// support can be bound.
|
||||
//
|
||||
// In future iterations, support may also be added for indexer types which can be rewritten as an `in`
|
||||
// expression; however, this would imply a rewrite of the inlined expression that may not be necessary
|
||||
// in most cases.
|
||||
func isBindable(matches []ast.NavigableExpr, inlined ast.Expr, inlinedType *Type) bool {
|
||||
if inlinedType.IsAssignableType(NullType) ||
|
||||
inlinedType.HasTrait(traits.SizerType) {
|
||||
return true
|
||||
}
|
||||
for _, m := range matches {
|
||||
if m.Kind() != ast.SelectKind {
|
||||
continue
|
||||
}
|
||||
sel := m.AsSelect()
|
||||
if sel.IsTestOnly() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// matchVariable matches simple identifiers, select expressions, and presence test expressions
|
||||
// which match the (potentially) qualified variable name provided as input.
|
||||
//
|
||||
// Note, this function does not support inlining against select expressions which includes optional
|
||||
// field selection. This may be a future refinement.
|
||||
func (opt *inliningOptimizer) matchVariable(varName string) ast.ExprMatcher {
|
||||
return func(e ast.NavigableExpr) bool {
|
||||
if e.Kind() == ast.IdentKind && e.AsIdent() == varName {
|
||||
return true
|
||||
}
|
||||
if e.Kind() == ast.SelectKind {
|
||||
sel := e.AsSelect()
|
||||
// While the `ToQualifiedName` call could take the select directly, this
|
||||
// would skip presence tests from possible matches, which we would like
|
||||
// to include.
|
||||
qualName, found := containers.ToQualifiedName(sel.Operand())
|
||||
return found && qualName+"."+sel.FieldName() == varName
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
288
e2e/vendor/github.com/google/cel-go/cel/io.go
generated
vendored
Normal file
288
e2e/vendor/github.com/google/cel-go/cel/io.go
generated
vendored
Normal file
@ -0,0 +1,288 @@
|
||||
// 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"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"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"
|
||||
|
||||
celpb "cel.dev/expr"
|
||||
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 {
|
||||
checked, _ := CheckedExprToAstWithSource(checkedExpr, nil)
|
||||
return checked
|
||||
}
|
||||
|
||||
// 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, error) {
|
||||
checked, err := ast.ToAST(checkedExpr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Ast{source: src, impl: checked}, nil
|
||||
}
|
||||
|
||||
// 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 ast.ToProto(a.impl)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
info, _ := ast.ProtoToSourceInfo(parsedExpr.GetSourceInfo())
|
||||
if src == nil {
|
||||
src = common.NewInfoSource(parsedExpr.GetSourceInfo())
|
||||
}
|
||||
e, _ := ast.ProtoToExpr(parsedExpr.GetExpr())
|
||||
return &Ast{source: src, impl: ast.NewAST(e, info)}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return parser.Unparse(a.impl.Expr(), a.impl.SourceInfo())
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return ValueAsAlphaProto(res)
|
||||
}
|
||||
|
||||
func ValueAsAlphaProto(res ref.Val) (*exprpb.Value, error) {
|
||||
canonical, err := ValueAsProto(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
alpha := &exprpb.Value{}
|
||||
err = convertProto(canonical, alpha)
|
||||
return alpha, err
|
||||
}
|
||||
|
||||
func ValueAsProto(res ref.Val) (*celpb.Value, error) {
|
||||
switch res.Type() {
|
||||
case types.BoolType:
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_BoolValue{BoolValue: res.Value().(bool)}}, nil
|
||||
case types.BytesType:
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_BytesValue{BytesValue: res.Value().([]byte)}}, nil
|
||||
case types.DoubleType:
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_DoubleValue{DoubleValue: res.Value().(float64)}}, nil
|
||||
case types.IntType:
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_Int64Value{Int64Value: res.Value().(int64)}}, nil
|
||||
case types.ListType:
|
||||
l := res.(traits.Lister)
|
||||
sz := l.Size().(types.Int)
|
||||
elts := make([]*celpb.Value, 0, int64(sz))
|
||||
for i := types.Int(0); i < sz; i++ {
|
||||
v, err := ValueAsProto(l.Get(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elts = append(elts, v)
|
||||
}
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_ListValue{
|
||||
ListValue: &celpb.ListValue{Values: elts}}}, nil
|
||||
case types.MapType:
|
||||
mapper := res.(traits.Mapper)
|
||||
sz := mapper.Size().(types.Int)
|
||||
entries := make([]*celpb.MapValue_Entry, 0, int64(sz))
|
||||
for it := mapper.Iterator(); it.HasNext().(types.Bool); {
|
||||
k := it.Next()
|
||||
v := mapper.Get(k)
|
||||
kv, err := ValueAsProto(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vv, err := ValueAsProto(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries = append(entries, &celpb.MapValue_Entry{Key: kv, Value: vv})
|
||||
}
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_MapValue{
|
||||
MapValue: &celpb.MapValue{Entries: entries}}}, nil
|
||||
case types.NullType:
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_NullValue{}}, nil
|
||||
case types.StringType:
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_StringValue{StringValue: res.Value().(string)}}, nil
|
||||
case types.TypeType:
|
||||
typeName := res.(ref.Type).TypeName()
|
||||
return &celpb.Value{Kind: &celpb.Value_TypeValue{TypeValue: typeName}}, nil
|
||||
case types.UintType:
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_Uint64Value{Uint64Value: res.Value().(uint64)}}, nil
|
||||
default:
|
||||
any, err := res.ConvertToNative(anyPbType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &celpb.Value{
|
||||
Kind: &celpb.Value_ObjectValue{ObjectValue: any.(*anypb.Any)}}, nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
typeNameToTypeValue = map[string]ref.Val{
|
||||
"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 types.Adapter, v *exprpb.Value) (ref.Val, error) {
|
||||
return AlphaProtoAsValue(adapter, v)
|
||||
}
|
||||
|
||||
func AlphaProtoAsValue(adapter types.Adapter, v *exprpb.Value) (ref.Val, error) {
|
||||
canonical := &celpb.Value{}
|
||||
if err := convertProto(v, canonical); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ProtoAsValue(adapter, canonical)
|
||||
}
|
||||
|
||||
func ProtoAsValue(adapter types.Adapter, v *celpb.Value) (ref.Val, error) {
|
||||
switch v.Kind.(type) {
|
||||
case *celpb.Value_NullValue:
|
||||
return types.NullValue, nil
|
||||
case *celpb.Value_BoolValue:
|
||||
return types.Bool(v.GetBoolValue()), nil
|
||||
case *celpb.Value_Int64Value:
|
||||
return types.Int(v.GetInt64Value()), nil
|
||||
case *celpb.Value_Uint64Value:
|
||||
return types.Uint(v.GetUint64Value()), nil
|
||||
case *celpb.Value_DoubleValue:
|
||||
return types.Double(v.GetDoubleValue()), nil
|
||||
case *celpb.Value_StringValue:
|
||||
return types.String(v.GetStringValue()), nil
|
||||
case *celpb.Value_BytesValue:
|
||||
return types.Bytes(v.GetBytesValue()), nil
|
||||
case *celpb.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 *celpb.Value_MapValue:
|
||||
m := v.GetMapValue()
|
||||
entries := make(map[ref.Val]ref.Val)
|
||||
for _, entry := range m.Entries {
|
||||
key, err := ProtoAsValue(adapter, entry.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pb, err := ProtoAsValue(adapter, entry.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries[key] = pb
|
||||
}
|
||||
return adapter.NativeToValue(entries), nil
|
||||
case *celpb.Value_ListValue:
|
||||
l := v.GetListValue()
|
||||
elts := make([]ref.Val, len(l.Values))
|
||||
for i, e := range l.Values {
|
||||
rv, err := ProtoAsValue(adapter, e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elts[i] = rv
|
||||
}
|
||||
return adapter.NativeToValue(elts), nil
|
||||
case *celpb.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")
|
||||
}
|
||||
|
||||
func convertProto(src, dst proto.Message) error {
|
||||
pb, err := proto.Marshal(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = proto.Unmarshal(pb, dst)
|
||||
return err
|
||||
}
|
790
e2e/vendor/github.com/google/cel-go/cel/library.go
generated
vendored
Normal file
790
e2e/vendor/github.com/google/cel-go/cel/library.go
generated
vendored
Normal file
@ -0,0 +1,790 @@
|
||||
// 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 (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/stdlib"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
"github.com/google/cel-go/interpreter"
|
||||
"github.com/google/cel-go/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
optMapMacro = "optMap"
|
||||
optFlatMapMacro = "optFlatMap"
|
||||
hasValueFunc = "hasValue"
|
||||
optionalNoneFunc = "optional.none"
|
||||
optionalOfFunc = "optional.of"
|
||||
optionalOfNonZeroValueFunc = "optional.ofNonZeroValue"
|
||||
valueFunc = "value"
|
||||
unusedIterVar = "#unused"
|
||||
)
|
||||
|
||||
// Library provides a collection of EnvOption and ProgramOption values used to configure a CEL
|
||||
// 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
|
||||
}
|
||||
|
||||
// SingletonLibrary refines the Library interface to ensure that libraries in this format are only
|
||||
// configured once within the environment.
|
||||
type SingletonLibrary interface {
|
||||
Library
|
||||
|
||||
// LibraryName provides a namespaced name which is used to check whether the library has already
|
||||
// been configured in the environment.
|
||||
LibraryName() string
|
||||
}
|
||||
|
||||
// Lib creates an EnvOption out of a Library, allowing libraries to be provided as functional args,
|
||||
// and to be linked to each other.
|
||||
func Lib(l Library) EnvOption {
|
||||
singleton, isSingleton := l.(SingletonLibrary)
|
||||
return func(e *Env) (*Env, error) {
|
||||
if isSingleton {
|
||||
if e.HasLibrary(singleton.LibraryName()) {
|
||||
return e, nil
|
||||
}
|
||||
e.libraries[singleton.LibraryName()] = true
|
||||
}
|
||||
var err error
|
||||
for _, opt := range l.CompileOptions() {
|
||||
e, err = opt(e)
|
||||
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{}
|
||||
|
||||
// LibraryName implements the SingletonLibrary interface method.
|
||||
func (stdLibrary) LibraryName() string {
|
||||
return "cel.lib.std"
|
||||
}
|
||||
|
||||
// CompileOptions returns options for the standard CEL function declarations and macros.
|
||||
func (stdLibrary) CompileOptions() []EnvOption {
|
||||
return []EnvOption{
|
||||
func(e *Env) (*Env, error) {
|
||||
var err error
|
||||
for _, fn := range stdlib.Functions() {
|
||||
existing, found := e.functions[fn.Name()]
|
||||
if found {
|
||||
fn, err = existing.Merge(fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
e.functions[fn.Name()] = fn
|
||||
}
|
||||
return e, nil
|
||||
},
|
||||
func(e *Env) (*Env, error) {
|
||||
e.variables = append(e.variables, stdlib.Types()...)
|
||||
return e, nil
|
||||
},
|
||||
Macros(StandardMacros...),
|
||||
}
|
||||
}
|
||||
|
||||
// ProgramOptions returns function implementations for the standard CEL functions.
|
||||
func (stdLibrary) ProgramOptions() []ProgramOption {
|
||||
return []ProgramOption{}
|
||||
}
|
||||
|
||||
// OptionalTypes enable support for optional syntax and types in CEL.
|
||||
//
|
||||
// The optional value type makes it possible to express whether variables have
|
||||
// been provided, whether a result has been computed, and in the future whether
|
||||
// an object field path, map key value, or list index has a value.
|
||||
//
|
||||
// # Syntax Changes
|
||||
//
|
||||
// OptionalTypes are unlike other CEL extensions because they modify the CEL
|
||||
// syntax itself, notably through the use of a `?` preceding a field name or
|
||||
// index value.
|
||||
//
|
||||
// ## Field Selection
|
||||
//
|
||||
// The optional syntax in field selection is denoted as `obj.?field`. In other
|
||||
// words, if a field is set, return `optional.of(obj.field)“, else
|
||||
// `optional.none()`. The optional field selection is viral in the sense that
|
||||
// after the first optional selection all subsequent selections or indices
|
||||
// are treated as optional, i.e. the following expressions are equivalent:
|
||||
//
|
||||
// obj.?field.subfield
|
||||
// obj.?field.?subfield
|
||||
//
|
||||
// ## Indexing
|
||||
//
|
||||
// Similar to field selection, the optional syntax can be used in index
|
||||
// expressions on maps and lists:
|
||||
//
|
||||
// list[?0]
|
||||
// map[?key]
|
||||
//
|
||||
// ## Optional Field Setting
|
||||
//
|
||||
// When creating map or message literals, if a field may be optionally set
|
||||
// based on its presence, then placing a `?` before the field name or key
|
||||
// will ensure the type on the right-hand side must be optional(T) where T
|
||||
// is the type of the field or key-value.
|
||||
//
|
||||
// The following returns a map with the key expression set only if the
|
||||
// subfield is present, otherwise an empty map is created:
|
||||
//
|
||||
// {?key: obj.?field.subfield}
|
||||
//
|
||||
// ## Optional Element Setting
|
||||
//
|
||||
// When creating list literals, an element in the list may be optionally added
|
||||
// when the element expression is preceded by a `?`:
|
||||
//
|
||||
// [a, ?b, ?c] // return a list with either [a], [a, b], [a, b, c], or [a, c]
|
||||
//
|
||||
// # Optional.Of
|
||||
//
|
||||
// Create an optional(T) value of a given value with type T.
|
||||
//
|
||||
// optional.of(10)
|
||||
//
|
||||
// # Optional.OfNonZeroValue
|
||||
//
|
||||
// Create an optional(T) value of a given value with type T if it is not a
|
||||
// zero-value. A zero-value the default empty value for any given CEL type,
|
||||
// including empty protobuf message types. If the value is empty, the result
|
||||
// of this call will be optional.none().
|
||||
//
|
||||
// optional.ofNonZeroValue([1, 2, 3]) // optional(list(int))
|
||||
// optional.ofNonZeroValue([]) // optional.none()
|
||||
// optional.ofNonZeroValue(0) // optional.none()
|
||||
// optional.ofNonZeroValue("") // optional.none()
|
||||
//
|
||||
// # Optional.None
|
||||
//
|
||||
// Create an empty optional value.
|
||||
//
|
||||
// # HasValue
|
||||
//
|
||||
// Determine whether the optional contains a value.
|
||||
//
|
||||
// optional.of(b'hello').hasValue() // true
|
||||
// optional.ofNonZeroValue({}).hasValue() // false
|
||||
//
|
||||
// # Value
|
||||
//
|
||||
// Get the value contained by the optional. If the optional does not have a
|
||||
// value, the result will be a CEL error.
|
||||
//
|
||||
// optional.of(b'hello').value() // b'hello'
|
||||
// optional.ofNonZeroValue({}).value() // error
|
||||
//
|
||||
// # Or
|
||||
//
|
||||
// If the value on the left-hand side is optional.none(), the optional value
|
||||
// on the right hand side is returned. If the value on the left-hand set is
|
||||
// valued, then it is returned. This operation is short-circuiting and will
|
||||
// only evaluate as many links in the `or` chain as are needed to return a
|
||||
// non-empty optional value.
|
||||
//
|
||||
// obj.?field.or(m[?key])
|
||||
// l[?index].or(obj.?field.subfield).or(obj.?other)
|
||||
//
|
||||
// # OrValue
|
||||
//
|
||||
// Either return the value contained within the optional on the left-hand side
|
||||
// or return the alternative value on the right hand side.
|
||||
//
|
||||
// m[?key].orValue("none")
|
||||
//
|
||||
// # OptMap
|
||||
//
|
||||
// Apply a transformation to the optional's underlying value if it is not empty
|
||||
// and return an optional typed result based on the transformation. The
|
||||
// transformation expression type must return a type T which is wrapped into
|
||||
// an optional.
|
||||
//
|
||||
// msg.?elements.optMap(e, e.size()).orValue(0)
|
||||
//
|
||||
// # OptFlatMap
|
||||
//
|
||||
// Introduced in version: 1
|
||||
//
|
||||
// Apply a transformation to the optional's underlying value if it is not empty
|
||||
// and return the result. The transform expression must return an optional(T)
|
||||
// rather than type T. This can be useful when dealing with zero values and
|
||||
// conditionally generating an empty or non-empty result in ways which cannot
|
||||
// be expressed with `optMap`.
|
||||
//
|
||||
// msg.?elements.optFlatMap(e, e[?0]) // return the first element if present.
|
||||
func OptionalTypes(opts ...OptionalTypesOption) EnvOption {
|
||||
lib := &optionalLib{version: math.MaxUint32}
|
||||
for _, opt := range opts {
|
||||
lib = opt(lib)
|
||||
}
|
||||
return Lib(lib)
|
||||
}
|
||||
|
||||
type optionalLib struct {
|
||||
version uint32
|
||||
}
|
||||
|
||||
// OptionalTypesOption is a functional interface for configuring the strings library.
|
||||
type OptionalTypesOption func(*optionalLib) *optionalLib
|
||||
|
||||
// OptionalTypesVersion configures the version of the optional type library.
|
||||
//
|
||||
// The version limits which functions are available. Only functions introduced
|
||||
// below or equal to the given version included in the library. If this option
|
||||
// is not set, all functions are available.
|
||||
//
|
||||
// See the library documentation to determine which version a function was introduced.
|
||||
// If the documentation does not state which version a function was introduced, it can
|
||||
// be assumed to be introduced at version 0, when the library was first created.
|
||||
func OptionalTypesVersion(version uint32) OptionalTypesOption {
|
||||
return func(lib *optionalLib) *optionalLib {
|
||||
lib.version = version
|
||||
return lib
|
||||
}
|
||||
}
|
||||
|
||||
// LibraryName implements the SingletonLibrary interface method.
|
||||
func (lib *optionalLib) LibraryName() string {
|
||||
return "cel.lib.optional"
|
||||
}
|
||||
|
||||
// CompileOptions implements the Library interface method.
|
||||
func (lib *optionalLib) CompileOptions() []EnvOption {
|
||||
paramTypeK := TypeParamType("K")
|
||||
paramTypeV := TypeParamType("V")
|
||||
optionalTypeV := OptionalType(paramTypeV)
|
||||
listTypeV := ListType(paramTypeV)
|
||||
mapTypeKV := MapType(paramTypeK, paramTypeV)
|
||||
|
||||
opts := []EnvOption{
|
||||
// Enable the optional syntax in the parser.
|
||||
enableOptionalSyntax(),
|
||||
|
||||
// Introduce the optional type.
|
||||
Types(types.OptionalType),
|
||||
|
||||
// Configure the optMap and optFlatMap macros.
|
||||
Macros(ReceiverMacro(optMapMacro, 2, optMap)),
|
||||
|
||||
// Global and member functions for working with optional values.
|
||||
Function(optionalOfFunc,
|
||||
Overload("optional_of", []*Type{paramTypeV}, optionalTypeV,
|
||||
UnaryBinding(func(value ref.Val) ref.Val {
|
||||
return types.OptionalOf(value)
|
||||
}))),
|
||||
Function(optionalOfNonZeroValueFunc,
|
||||
Overload("optional_ofNonZeroValue", []*Type{paramTypeV}, optionalTypeV,
|
||||
UnaryBinding(func(value ref.Val) ref.Val {
|
||||
v, isZeroer := value.(traits.Zeroer)
|
||||
if !isZeroer || !v.IsZeroValue() {
|
||||
return types.OptionalOf(value)
|
||||
}
|
||||
return types.OptionalNone
|
||||
}))),
|
||||
Function(optionalNoneFunc,
|
||||
Overload("optional_none", []*Type{}, optionalTypeV,
|
||||
FunctionBinding(func(values ...ref.Val) ref.Val {
|
||||
return types.OptionalNone
|
||||
}))),
|
||||
Function(valueFunc,
|
||||
MemberOverload("optional_value", []*Type{optionalTypeV}, paramTypeV,
|
||||
UnaryBinding(func(value ref.Val) ref.Val {
|
||||
opt := value.(*types.Optional)
|
||||
return opt.GetValue()
|
||||
}))),
|
||||
Function(hasValueFunc,
|
||||
MemberOverload("optional_hasValue", []*Type{optionalTypeV}, BoolType,
|
||||
UnaryBinding(func(value ref.Val) ref.Val {
|
||||
opt := value.(*types.Optional)
|
||||
return types.Bool(opt.HasValue())
|
||||
}))),
|
||||
|
||||
// Implementation of 'or' and 'orValue' are special-cased to support short-circuiting in the
|
||||
// evaluation chain.
|
||||
Function("or",
|
||||
MemberOverload("optional_or_optional", []*Type{optionalTypeV, optionalTypeV}, optionalTypeV)),
|
||||
Function("orValue",
|
||||
MemberOverload("optional_orValue_value", []*Type{optionalTypeV, paramTypeV}, paramTypeV)),
|
||||
|
||||
// OptSelect is handled specially by the type-checker, so the receiver's field type is used to determine the
|
||||
// optput type.
|
||||
Function(operators.OptSelect,
|
||||
Overload("select_optional_field", []*Type{DynType, StringType}, optionalTypeV)),
|
||||
|
||||
// OptIndex is handled mostly like any other indexing operation on a list or map, so the type-checker can use
|
||||
// these signatures to determine type-agreement without any special handling.
|
||||
Function(operators.OptIndex,
|
||||
Overload("list_optindex_optional_int", []*Type{listTypeV, IntType}, optionalTypeV),
|
||||
Overload("optional_list_optindex_optional_int", []*Type{OptionalType(listTypeV), IntType}, optionalTypeV),
|
||||
Overload("map_optindex_optional_value", []*Type{mapTypeKV, paramTypeK}, optionalTypeV),
|
||||
Overload("optional_map_optindex_optional_value", []*Type{OptionalType(mapTypeKV), paramTypeK}, optionalTypeV)),
|
||||
|
||||
// Index overloads to accommodate using an optional value as the operand.
|
||||
Function(operators.Index,
|
||||
Overload("optional_list_index_int", []*Type{OptionalType(listTypeV), IntType}, optionalTypeV),
|
||||
Overload("optional_map_index_value", []*Type{OptionalType(mapTypeKV), paramTypeK}, optionalTypeV)),
|
||||
}
|
||||
if lib.version >= 1 {
|
||||
opts = append(opts, Macros(ReceiverMacro(optFlatMapMacro, 2, optFlatMap)))
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
// ProgramOptions implements the Library interface method.
|
||||
func (lib *optionalLib) ProgramOptions() []ProgramOption {
|
||||
return []ProgramOption{
|
||||
CustomDecorator(decorateOptionalOr),
|
||||
}
|
||||
}
|
||||
|
||||
func optMap(meh MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *Error) {
|
||||
varIdent := args[0]
|
||||
varName := ""
|
||||
switch varIdent.Kind() {
|
||||
case ast.IdentKind:
|
||||
varName = varIdent.AsIdent()
|
||||
default:
|
||||
return nil, meh.NewError(varIdent.ID(), "optMap() variable name must be a simple identifier")
|
||||
}
|
||||
mapExpr := args[1]
|
||||
return meh.NewCall(
|
||||
operators.Conditional,
|
||||
meh.NewMemberCall(hasValueFunc, target),
|
||||
meh.NewCall(optionalOfFunc,
|
||||
meh.NewComprehension(
|
||||
meh.NewList(),
|
||||
unusedIterVar,
|
||||
varName,
|
||||
meh.NewMemberCall(valueFunc, meh.Copy(target)),
|
||||
meh.NewLiteral(types.False),
|
||||
meh.NewIdent(varName),
|
||||
mapExpr,
|
||||
),
|
||||
),
|
||||
meh.NewCall(optionalNoneFunc),
|
||||
), nil
|
||||
}
|
||||
|
||||
func optFlatMap(meh MacroExprFactory, target ast.Expr, args []ast.Expr) (ast.Expr, *Error) {
|
||||
varIdent := args[0]
|
||||
varName := ""
|
||||
switch varIdent.Kind() {
|
||||
case ast.IdentKind:
|
||||
varName = varIdent.AsIdent()
|
||||
default:
|
||||
return nil, meh.NewError(varIdent.ID(), "optFlatMap() variable name must be a simple identifier")
|
||||
}
|
||||
mapExpr := args[1]
|
||||
return meh.NewCall(
|
||||
operators.Conditional,
|
||||
meh.NewMemberCall(hasValueFunc, target),
|
||||
meh.NewComprehension(
|
||||
meh.NewList(),
|
||||
unusedIterVar,
|
||||
varName,
|
||||
meh.NewMemberCall(valueFunc, meh.Copy(target)),
|
||||
meh.NewLiteral(types.False),
|
||||
meh.NewIdent(varName),
|
||||
mapExpr,
|
||||
),
|
||||
meh.NewCall(optionalNoneFunc),
|
||||
), nil
|
||||
}
|
||||
|
||||
func enableOptionalSyntax() EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.prsrOpts = append(e.prsrOpts, parser.EnableOptionalSyntax(true))
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableErrorOnBadPresenceTest enables error generation when a presence test or optional field
|
||||
// selection is performed on a primitive type.
|
||||
func EnableErrorOnBadPresenceTest(value bool) EnvOption {
|
||||
return features(featureEnableErrorOnBadPresenceTest, value)
|
||||
}
|
||||
|
||||
func decorateOptionalOr(i interpreter.Interpretable) (interpreter.Interpretable, error) {
|
||||
call, ok := i.(interpreter.InterpretableCall)
|
||||
if !ok {
|
||||
return i, nil
|
||||
}
|
||||
args := call.Args()
|
||||
if len(args) != 2 {
|
||||
return i, nil
|
||||
}
|
||||
switch call.Function() {
|
||||
case "or":
|
||||
if call.OverloadID() != "" && call.OverloadID() != "optional_or_optional" {
|
||||
return i, nil
|
||||
}
|
||||
return &evalOptionalOr{
|
||||
id: call.ID(),
|
||||
lhs: args[0],
|
||||
rhs: args[1],
|
||||
}, nil
|
||||
case "orValue":
|
||||
if call.OverloadID() != "" && call.OverloadID() != "optional_orValue_value" {
|
||||
return i, nil
|
||||
}
|
||||
return &evalOptionalOrValue{
|
||||
id: call.ID(),
|
||||
lhs: args[0],
|
||||
rhs: args[1],
|
||||
}, nil
|
||||
default:
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
// evalOptionalOr selects between two optional values, either the first if it has a value, or
|
||||
// the second optional expression is evaluated and returned.
|
||||
type evalOptionalOr struct {
|
||||
id int64
|
||||
lhs interpreter.Interpretable
|
||||
rhs interpreter.Interpretable
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
func (opt *evalOptionalOr) ID() int64 {
|
||||
return opt.id
|
||||
}
|
||||
|
||||
// Eval evaluates the left-hand side optional to determine whether it contains a value, else
|
||||
// proceeds with the right-hand side evaluation.
|
||||
func (opt *evalOptionalOr) Eval(ctx interpreter.Activation) ref.Val {
|
||||
// short-circuit lhs.
|
||||
optLHS := opt.lhs.Eval(ctx)
|
||||
optVal, ok := optLHS.(*types.Optional)
|
||||
if !ok {
|
||||
return optLHS
|
||||
}
|
||||
if optVal.HasValue() {
|
||||
return optVal
|
||||
}
|
||||
return opt.rhs.Eval(ctx)
|
||||
}
|
||||
|
||||
// evalOptionalOrValue selects between an optional or a concrete value. If the optional has a value,
|
||||
// its value is returned, otherwise the alternative value expression is evaluated and returned.
|
||||
type evalOptionalOrValue struct {
|
||||
id int64
|
||||
lhs interpreter.Interpretable
|
||||
rhs interpreter.Interpretable
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
func (opt *evalOptionalOrValue) ID() int64 {
|
||||
return opt.id
|
||||
}
|
||||
|
||||
// Eval evaluates the left-hand side optional to determine whether it contains a value, else
|
||||
// proceeds with the right-hand side evaluation.
|
||||
func (opt *evalOptionalOrValue) Eval(ctx interpreter.Activation) ref.Val {
|
||||
// short-circuit lhs.
|
||||
optLHS := opt.lhs.Eval(ctx)
|
||||
optVal, ok := optLHS.(*types.Optional)
|
||||
if !ok {
|
||||
return optLHS
|
||||
}
|
||||
if optVal.HasValue() {
|
||||
return optVal.GetValue()
|
||||
}
|
||||
return opt.rhs.Eval(ctx)
|
||||
}
|
||||
|
||||
type timeUTCLibrary struct{}
|
||||
|
||||
func (timeUTCLibrary) CompileOptions() []EnvOption {
|
||||
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(types.DurationGetHours))),
|
||||
Function(overloads.TimeGetMinutes,
|
||||
MemberOverload(overloads.DurationToMinutes, []*Type{DurationType}, IntType,
|
||||
UnaryBinding(types.DurationGetMinutes))),
|
||||
Function(overloads.TimeGetSeconds,
|
||||
MemberOverload(overloads.DurationToSeconds, []*Type{DurationType}, IntType,
|
||||
UnaryBinding(types.DurationGetSeconds))),
|
||||
Function(overloads.TimeGetMilliseconds,
|
||||
MemberOverload(overloads.DurationToMilliseconds, []*Type{DurationType}, IntType,
|
||||
UnaryBinding(types.DurationGetMilliseconds))),
|
||||
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
|
||||
}
|
576
e2e/vendor/github.com/google/cel-go/cel/macro.go
generated
vendored
Normal file
576
e2e/vendor/github.com/google/cel-go/cel/macro.go
generated
vendored
Normal file
@ -0,0 +1,576 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"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
|
||||
|
||||
// MacroFactory defines an expansion function which converts a call and its arguments to a cel.Expr value.
|
||||
type MacroFactory = parser.MacroExpander
|
||||
|
||||
// MacroExprFactory assists with the creation of Expr values in a manner which is consistent
|
||||
// the internal semantics and id generation behaviors of the parser and checker libraries.
|
||||
type MacroExprFactory = parser.ExprHelper
|
||||
|
||||
// MacroExpander converts a call and its associated arguments into a protobuf Expr representation.
|
||||
//
|
||||
// If the MacroExpander determines within the implementation that an expansion is not needed it may return
|
||||
// a nil Expr value to indicate a non-match. However, if an expansion is to be performed, but the arguments
|
||||
// are not well-formed, the result of the expansion will be an error.
|
||||
//
|
||||
// The MacroExpander accepts as arguments a MacroExprHelper as well as the arguments used in the function call
|
||||
// and produces as output an Expr ast node.
|
||||
//
|
||||
// Note: when the Macro.IsReceiverStyle() method returns true, the target argument will be nil.
|
||||
type MacroExpander func(eh MacroExprHelper, target *exprpb.Expr, args []*exprpb.Expr) (*exprpb.Expr, *Error)
|
||||
|
||||
// MacroExprHelper exposes helper methods for creating new expressions within a CEL abstract syntax tree.
|
||||
// ExprHelper assists with the manipulation of proto-based Expr values in a manner which is
|
||||
// consistent with the source position and expression id generation code leveraged by both
|
||||
// the parser and type-checker.
|
||||
type MacroExprHelper interface {
|
||||
// Copy the input expression with a brand new set of identifiers.
|
||||
Copy(*exprpb.Expr) *exprpb.Expr
|
||||
|
||||
// LiteralBool creates an Expr value for a bool literal.
|
||||
LiteralBool(value bool) *exprpb.Expr
|
||||
|
||||
// LiteralBytes creates an Expr value for a byte literal.
|
||||
LiteralBytes(value []byte) *exprpb.Expr
|
||||
|
||||
// LiteralDouble creates an Expr value for double literal.
|
||||
LiteralDouble(value float64) *exprpb.Expr
|
||||
|
||||
// LiteralInt creates an Expr value for an int literal.
|
||||
LiteralInt(value int64) *exprpb.Expr
|
||||
|
||||
// LiteralString creates am Expr value for a string literal.
|
||||
LiteralString(value string) *exprpb.Expr
|
||||
|
||||
// LiteralUint creates an Expr value for a uint literal.
|
||||
LiteralUint(value uint64) *exprpb.Expr
|
||||
|
||||
// NewList creates a CreateList instruction where the list is comprised of the optional set
|
||||
// of elements provided as arguments.
|
||||
NewList(elems ...*exprpb.Expr) *exprpb.Expr
|
||||
|
||||
// NewMap creates a CreateStruct instruction for a map where the map is comprised of the
|
||||
// optional set of key, value entries.
|
||||
NewMap(entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr
|
||||
|
||||
// NewMapEntry creates a Map Entry for the key, value pair.
|
||||
NewMapEntry(key *exprpb.Expr, val *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry
|
||||
|
||||
// NewObject creates a CreateStruct instruction for an object with a given type name and
|
||||
// optional set of field initializers.
|
||||
NewObject(typeName string, fieldInits ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr
|
||||
|
||||
// NewObjectFieldInit creates a new Object field initializer from the field name and value.
|
||||
NewObjectFieldInit(field string, init *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry
|
||||
|
||||
// Fold creates a fold comprehension instruction.
|
||||
//
|
||||
// - iterVar is the iteration variable name.
|
||||
// - iterRange represents the expression that resolves to a list or map where the elements or
|
||||
// keys (respectively) will be iterated over.
|
||||
// - accuVar is the accumulation variable name, typically parser.AccumulatorName.
|
||||
// - accuInit is the initial expression whose value will be set for the accuVar prior to
|
||||
// folding.
|
||||
// - condition is the expression to test to determine whether to continue folding.
|
||||
// - step is the expression to evaluation at the conclusion of a single fold iteration.
|
||||
// - result is the computation to evaluate at the conclusion of the fold.
|
||||
//
|
||||
// The accuVar should not shadow variable names that you would like to reference within the
|
||||
// environment in the step and condition expressions. Presently, the name __result__ is commonly
|
||||
// used by built-in macros but this may change in the future.
|
||||
Fold(iterVar string,
|
||||
iterRange *exprpb.Expr,
|
||||
accuVar string,
|
||||
accuInit *exprpb.Expr,
|
||||
condition *exprpb.Expr,
|
||||
step *exprpb.Expr,
|
||||
result *exprpb.Expr) *exprpb.Expr
|
||||
|
||||
// Ident creates an identifier Expr value.
|
||||
Ident(name string) *exprpb.Expr
|
||||
|
||||
// AccuIdent returns an accumulator identifier for use with comprehension results.
|
||||
AccuIdent() *exprpb.Expr
|
||||
|
||||
// GlobalCall creates a function call Expr value for a global (free) function.
|
||||
GlobalCall(function string, args ...*exprpb.Expr) *exprpb.Expr
|
||||
|
||||
// ReceiverCall creates a function call Expr value for a receiver-style function.
|
||||
ReceiverCall(function string, target *exprpb.Expr, args ...*exprpb.Expr) *exprpb.Expr
|
||||
|
||||
// PresenceTest creates a Select TestOnly Expr value for modelling has() semantics.
|
||||
PresenceTest(operand *exprpb.Expr, field string) *exprpb.Expr
|
||||
|
||||
// Select create a field traversal Expr value.
|
||||
Select(operand *exprpb.Expr, field string) *exprpb.Expr
|
||||
|
||||
// OffsetLocation returns the Location of the expression identifier.
|
||||
OffsetLocation(exprID int64) common.Location
|
||||
|
||||
// NewError associates an error message with a given expression id.
|
||||
NewError(exprID int64, message string) *Error
|
||||
}
|
||||
|
||||
// GlobalMacro creates a Macro for a global function with the specified arg count.
|
||||
func GlobalMacro(function string, argCount int, factory MacroFactory) Macro {
|
||||
return parser.NewGlobalMacro(function, argCount, factory)
|
||||
}
|
||||
|
||||
// ReceiverMacro creates a Macro for a receiver function matching the specified arg count.
|
||||
func ReceiverMacro(function string, argCount int, factory MacroFactory) Macro {
|
||||
return parser.NewReceiverMacro(function, argCount, factory)
|
||||
}
|
||||
|
||||
// GlobalVarArgMacro creates a Macro for a global function with a variable arg count.
|
||||
func GlobalVarArgMacro(function string, factory MacroFactory) Macro {
|
||||
return parser.NewGlobalVarArgMacro(function, factory)
|
||||
}
|
||||
|
||||
// ReceiverVarArgMacro creates a Macro for a receiver function matching a variable arg count.
|
||||
func ReceiverVarArgMacro(function string, factory MacroFactory) Macro {
|
||||
return parser.NewReceiverVarArgMacro(function, factory)
|
||||
}
|
||||
|
||||
// NewGlobalMacro creates a Macro for a global function with the specified arg count.
|
||||
//
|
||||
// Deprecated: use GlobalMacro
|
||||
func NewGlobalMacro(function string, argCount int, expander MacroExpander) Macro {
|
||||
expand := adaptingExpander{expander}
|
||||
return parser.NewGlobalMacro(function, argCount, expand.Expander)
|
||||
}
|
||||
|
||||
// NewReceiverMacro creates a Macro for a receiver function matching the specified arg count.
|
||||
//
|
||||
// Deprecated: use ReceiverMacro
|
||||
func NewReceiverMacro(function string, argCount int, expander MacroExpander) Macro {
|
||||
expand := adaptingExpander{expander}
|
||||
return parser.NewReceiverMacro(function, argCount, expand.Expander)
|
||||
}
|
||||
|
||||
// NewGlobalVarArgMacro creates a Macro for a global function with a variable arg count.
|
||||
//
|
||||
// Deprecated: use GlobalVarArgMacro
|
||||
func NewGlobalVarArgMacro(function string, expander MacroExpander) Macro {
|
||||
expand := adaptingExpander{expander}
|
||||
return parser.NewGlobalVarArgMacro(function, expand.Expander)
|
||||
}
|
||||
|
||||
// NewReceiverVarArgMacro creates a Macro for a receiver function matching a variable arg count.
|
||||
//
|
||||
// Deprecated: use ReceiverVarArgMacro
|
||||
func NewReceiverVarArgMacro(function string, expander MacroExpander) Macro {
|
||||
expand := adaptingExpander{expander}
|
||||
return parser.NewReceiverVarArgMacro(function, expand.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, *Error) {
|
||||
ph, err := toParserHelper(meh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
arg, err := adaptToExpr(args[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if arg.Kind() == ast.SelectKind {
|
||||
s := arg.AsSelect()
|
||||
return adaptToProto(ph.NewPresenceTest(s.Operand(), s.FieldName()))
|
||||
}
|
||||
return nil, ph.NewError(arg.ID(), "invalid argument to has() macro")
|
||||
}
|
||||
|
||||
// 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, *Error) {
|
||||
ph, err := toParserHelper(meh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := parser.MakeExists(ph, mustAdaptToExpr(target), mustAdaptToExprs(args))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adaptToProto(out)
|
||||
}
|
||||
|
||||
// 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, *Error) {
|
||||
ph, err := toParserHelper(meh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := parser.MakeExistsOne(ph, mustAdaptToExpr(target), mustAdaptToExprs(args))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adaptToProto(out)
|
||||
}
|
||||
|
||||
// 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, *Error) {
|
||||
ph, err := toParserHelper(meh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := parser.MakeMap(ph, mustAdaptToExpr(target), mustAdaptToExprs(args))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adaptToProto(out)
|
||||
}
|
||||
|
||||
// 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, *Error) {
|
||||
ph, err := toParserHelper(meh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := parser.MakeFilter(ph, mustAdaptToExpr(target), mustAdaptToExprs(args))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adaptToProto(out)
|
||||
}
|
||||
|
||||
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{}
|
||||
)
|
||||
|
||||
type adaptingExpander struct {
|
||||
legacyExpander MacroExpander
|
||||
}
|
||||
|
||||
func (adapt *adaptingExpander) Expander(eh parser.ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error) {
|
||||
var legacyTarget *exprpb.Expr = nil
|
||||
var err *Error = nil
|
||||
if target != nil {
|
||||
legacyTarget, err = adaptToProto(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
legacyArgs := make([]*exprpb.Expr, len(args))
|
||||
for i, arg := range args {
|
||||
legacyArgs[i], err = adaptToProto(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ah := &adaptingHelper{modernHelper: eh}
|
||||
legacyExpr, err := adapt.legacyExpander(ah, legacyTarget, legacyArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ex, err := adaptToExpr(legacyExpr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ex, nil
|
||||
}
|
||||
|
||||
func wrapErr(id int64, message string, err error) *common.Error {
|
||||
return &common.Error{
|
||||
Location: common.NoLocation,
|
||||
Message: fmt.Sprintf("%s: %v", message, err),
|
||||
ExprID: id,
|
||||
}
|
||||
}
|
||||
|
||||
type adaptingHelper struct {
|
||||
modernHelper parser.ExprHelper
|
||||
}
|
||||
|
||||
// Copy the input expression with a brand new set of identifiers.
|
||||
func (ah *adaptingHelper) Copy(e *exprpb.Expr) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.Copy(mustAdaptToExpr(e)))
|
||||
}
|
||||
|
||||
// LiteralBool creates an Expr value for a bool literal.
|
||||
func (ah *adaptingHelper) LiteralBool(value bool) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Bool(value)))
|
||||
}
|
||||
|
||||
// LiteralBytes creates an Expr value for a byte literal.
|
||||
func (ah *adaptingHelper) LiteralBytes(value []byte) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Bytes(value)))
|
||||
}
|
||||
|
||||
// LiteralDouble creates an Expr value for double literal.
|
||||
func (ah *adaptingHelper) LiteralDouble(value float64) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Double(value)))
|
||||
}
|
||||
|
||||
// LiteralInt creates an Expr value for an int literal.
|
||||
func (ah *adaptingHelper) LiteralInt(value int64) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Int(value)))
|
||||
}
|
||||
|
||||
// LiteralString creates am Expr value for a string literal.
|
||||
func (ah *adaptingHelper) LiteralString(value string) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewLiteral(types.String(value)))
|
||||
}
|
||||
|
||||
// LiteralUint creates an Expr value for a uint literal.
|
||||
func (ah *adaptingHelper) LiteralUint(value uint64) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewLiteral(types.Uint(value)))
|
||||
}
|
||||
|
||||
// NewList creates a CreateList instruction where the list is comprised of the optional set
|
||||
// of elements provided as arguments.
|
||||
func (ah *adaptingHelper) NewList(elems ...*exprpb.Expr) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewList(mustAdaptToExprs(elems)...))
|
||||
}
|
||||
|
||||
// NewMap creates a CreateStruct instruction for a map where the map is comprised of the
|
||||
// optional set of key, value entries.
|
||||
func (ah *adaptingHelper) NewMap(entries ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr {
|
||||
adaptedEntries := make([]ast.EntryExpr, len(entries))
|
||||
for i, e := range entries {
|
||||
adaptedEntries[i] = mustAdaptToEntryExpr(e)
|
||||
}
|
||||
return mustAdaptToProto(ah.modernHelper.NewMap(adaptedEntries...))
|
||||
}
|
||||
|
||||
// NewMapEntry creates a Map Entry for the key, value pair.
|
||||
func (ah *adaptingHelper) NewMapEntry(key *exprpb.Expr, val *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry {
|
||||
return mustAdaptToProtoEntry(
|
||||
ah.modernHelper.NewMapEntry(mustAdaptToExpr(key), mustAdaptToExpr(val), optional))
|
||||
}
|
||||
|
||||
// NewObject creates a CreateStruct instruction for an object with a given type name and
|
||||
// optional set of field initializers.
|
||||
func (ah *adaptingHelper) NewObject(typeName string, fieldInits ...*exprpb.Expr_CreateStruct_Entry) *exprpb.Expr {
|
||||
adaptedEntries := make([]ast.EntryExpr, len(fieldInits))
|
||||
for i, e := range fieldInits {
|
||||
adaptedEntries[i] = mustAdaptToEntryExpr(e)
|
||||
}
|
||||
return mustAdaptToProto(ah.modernHelper.NewStruct(typeName, adaptedEntries...))
|
||||
}
|
||||
|
||||
// NewObjectFieldInit creates a new Object field initializer from the field name and value.
|
||||
func (ah *adaptingHelper) NewObjectFieldInit(field string, init *exprpb.Expr, optional bool) *exprpb.Expr_CreateStruct_Entry {
|
||||
return mustAdaptToProtoEntry(
|
||||
ah.modernHelper.NewStructField(field, mustAdaptToExpr(init), optional))
|
||||
}
|
||||
|
||||
// Fold creates a fold comprehension instruction.
|
||||
//
|
||||
// - iterVar is the iteration variable name.
|
||||
// - iterRange represents the expression that resolves to a list or map where the elements or
|
||||
// keys (respectively) will be iterated over.
|
||||
// - accuVar is the accumulation variable name, typically parser.AccumulatorName.
|
||||
// - accuInit is the initial expression whose value will be set for the accuVar prior to
|
||||
// folding.
|
||||
// - condition is the expression to test to determine whether to continue folding.
|
||||
// - step is the expression to evaluation at the conclusion of a single fold iteration.
|
||||
// - result is the computation to evaluate at the conclusion of the fold.
|
||||
//
|
||||
// The accuVar should not shadow variable names that you would like to reference within the
|
||||
// environment in the step and condition expressions. Presently, the name __result__ is commonly
|
||||
// used by built-in macros but this may change in the future.
|
||||
func (ah *adaptingHelper) Fold(iterVar string,
|
||||
iterRange *exprpb.Expr,
|
||||
accuVar string,
|
||||
accuInit *exprpb.Expr,
|
||||
condition *exprpb.Expr,
|
||||
step *exprpb.Expr,
|
||||
result *exprpb.Expr) *exprpb.Expr {
|
||||
return mustAdaptToProto(
|
||||
ah.modernHelper.NewComprehension(
|
||||
mustAdaptToExpr(iterRange),
|
||||
iterVar,
|
||||
accuVar,
|
||||
mustAdaptToExpr(accuInit),
|
||||
mustAdaptToExpr(condition),
|
||||
mustAdaptToExpr(step),
|
||||
mustAdaptToExpr(result),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Ident creates an identifier Expr value.
|
||||
func (ah *adaptingHelper) Ident(name string) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewIdent(name))
|
||||
}
|
||||
|
||||
// AccuIdent returns an accumulator identifier for use with comprehension results.
|
||||
func (ah *adaptingHelper) AccuIdent() *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewAccuIdent())
|
||||
}
|
||||
|
||||
// GlobalCall creates a function call Expr value for a global (free) function.
|
||||
func (ah *adaptingHelper) GlobalCall(function string, args ...*exprpb.Expr) *exprpb.Expr {
|
||||
return mustAdaptToProto(ah.modernHelper.NewCall(function, mustAdaptToExprs(args)...))
|
||||
}
|
||||
|
||||
// ReceiverCall creates a function call Expr value for a receiver-style function.
|
||||
func (ah *adaptingHelper) ReceiverCall(function string, target *exprpb.Expr, args ...*exprpb.Expr) *exprpb.Expr {
|
||||
return mustAdaptToProto(
|
||||
ah.modernHelper.NewMemberCall(function, mustAdaptToExpr(target), mustAdaptToExprs(args)...))
|
||||
}
|
||||
|
||||
// PresenceTest creates a Select TestOnly Expr value for modelling has() semantics.
|
||||
func (ah *adaptingHelper) PresenceTest(operand *exprpb.Expr, field string) *exprpb.Expr {
|
||||
op := mustAdaptToExpr(operand)
|
||||
return mustAdaptToProto(ah.modernHelper.NewPresenceTest(op, field))
|
||||
}
|
||||
|
||||
// Select create a field traversal Expr value.
|
||||
func (ah *adaptingHelper) Select(operand *exprpb.Expr, field string) *exprpb.Expr {
|
||||
op := mustAdaptToExpr(operand)
|
||||
return mustAdaptToProto(ah.modernHelper.NewSelect(op, field))
|
||||
}
|
||||
|
||||
// OffsetLocation returns the Location of the expression identifier.
|
||||
func (ah *adaptingHelper) OffsetLocation(exprID int64) common.Location {
|
||||
return ah.modernHelper.OffsetLocation(exprID)
|
||||
}
|
||||
|
||||
// NewError associates an error message with a given expression id.
|
||||
func (ah *adaptingHelper) NewError(exprID int64, message string) *Error {
|
||||
return ah.modernHelper.NewError(exprID, message)
|
||||
}
|
||||
|
||||
func mustAdaptToExprs(exprs []*exprpb.Expr) []ast.Expr {
|
||||
adapted := make([]ast.Expr, len(exprs))
|
||||
for i, e := range exprs {
|
||||
adapted[i] = mustAdaptToExpr(e)
|
||||
}
|
||||
return adapted
|
||||
}
|
||||
|
||||
func mustAdaptToExpr(e *exprpb.Expr) ast.Expr {
|
||||
out, _ := adaptToExpr(e)
|
||||
return out
|
||||
}
|
||||
|
||||
func adaptToExpr(e *exprpb.Expr) (ast.Expr, *Error) {
|
||||
if e == nil {
|
||||
return nil, nil
|
||||
}
|
||||
out, err := ast.ProtoToExpr(e)
|
||||
if err != nil {
|
||||
return nil, wrapErr(e.GetId(), "proto conversion failure", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func mustAdaptToEntryExpr(e *exprpb.Expr_CreateStruct_Entry) ast.EntryExpr {
|
||||
out, _ := ast.ProtoToEntryExpr(e)
|
||||
return out
|
||||
}
|
||||
|
||||
func mustAdaptToProto(e ast.Expr) *exprpb.Expr {
|
||||
out, _ := adaptToProto(e)
|
||||
return out
|
||||
}
|
||||
|
||||
func adaptToProto(e ast.Expr) (*exprpb.Expr, *Error) {
|
||||
if e == nil {
|
||||
return nil, nil
|
||||
}
|
||||
out, err := ast.ExprToProto(e)
|
||||
if err != nil {
|
||||
return nil, wrapErr(e.ID(), "expr conversion failure", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func mustAdaptToProtoEntry(e ast.EntryExpr) *exprpb.Expr_CreateStruct_Entry {
|
||||
out, _ := ast.EntryExprToProto(e)
|
||||
return out
|
||||
}
|
||||
|
||||
func toParserHelper(meh MacroExprHelper) (parser.ExprHelper, *Error) {
|
||||
ah, ok := meh.(*adaptingHelper)
|
||||
if !ok {
|
||||
return nil, common.NewError(0,
|
||||
fmt.Sprintf("unsupported macro helper: %v (%T)", meh, meh),
|
||||
common.NoLocation)
|
||||
}
|
||||
return ah.modernHelper, nil
|
||||
}
|
535
e2e/vendor/github.com/google/cel-go/cel/optimizer.go
generated
vendored
Normal file
535
e2e/vendor/github.com/google/cel-go/cel/optimizer.go
generated
vendored
Normal file
@ -0,0 +1,535 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cel
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// StaticOptimizer contains a sequence of ASTOptimizer instances which will be applied in order.
|
||||
//
|
||||
// The static optimizer normalizes expression ids and type-checking run between optimization
|
||||
// passes to ensure that the final optimized output is a valid expression with metadata consistent
|
||||
// with what would have been generated from a parsed and checked expression.
|
||||
//
|
||||
// Note: source position information is best-effort and likely wrong, but optimized expressions
|
||||
// should be suitable for calls to parser.Unparse.
|
||||
type StaticOptimizer struct {
|
||||
optimizers []ASTOptimizer
|
||||
}
|
||||
|
||||
// NewStaticOptimizer creates a StaticOptimizer with a sequence of ASTOptimizer's to be applied
|
||||
// to a checked expression.
|
||||
func NewStaticOptimizer(optimizers ...ASTOptimizer) *StaticOptimizer {
|
||||
return &StaticOptimizer{
|
||||
optimizers: optimizers,
|
||||
}
|
||||
}
|
||||
|
||||
// Optimize applies a sequence of optimizations to an Ast within a given environment.
|
||||
//
|
||||
// If issues are encountered, the Issues.Err() return value will be non-nil.
|
||||
func (opt *StaticOptimizer) Optimize(env *Env, a *Ast) (*Ast, *Issues) {
|
||||
// Make a copy of the AST to be optimized.
|
||||
optimized := ast.Copy(a.impl)
|
||||
ids := newIDGenerator(ast.MaxID(a.impl))
|
||||
|
||||
// Create the optimizer context, could be pooled in the future.
|
||||
issues := NewIssues(common.NewErrors(a.Source()))
|
||||
baseFac := ast.NewExprFactory()
|
||||
exprFac := &optimizerExprFactory{
|
||||
idGenerator: ids,
|
||||
fac: baseFac,
|
||||
sourceInfo: optimized.SourceInfo(),
|
||||
}
|
||||
ctx := &OptimizerContext{
|
||||
optimizerExprFactory: exprFac,
|
||||
Env: env,
|
||||
Issues: issues,
|
||||
}
|
||||
|
||||
// Apply the optimizations sequentially.
|
||||
for _, o := range opt.optimizers {
|
||||
optimized = o.Optimize(ctx, optimized)
|
||||
if issues.Err() != nil {
|
||||
return nil, issues
|
||||
}
|
||||
// Normalize expression id metadata including coordination with macro call metadata.
|
||||
freshIDGen := newIDGenerator(0)
|
||||
info := optimized.SourceInfo()
|
||||
expr := optimized.Expr()
|
||||
normalizeIDs(freshIDGen.renumberStable, expr, info)
|
||||
cleanupMacroRefs(expr, info)
|
||||
|
||||
// Recheck the updated expression for any possible type-agreement or validation errors.
|
||||
parsed := &Ast{
|
||||
source: a.Source(),
|
||||
impl: ast.NewAST(expr, info)}
|
||||
checked, iss := ctx.Check(parsed)
|
||||
if iss.Err() != nil {
|
||||
return nil, iss
|
||||
}
|
||||
optimized = checked.impl
|
||||
}
|
||||
|
||||
// Return the optimized result.
|
||||
return &Ast{
|
||||
source: a.Source(),
|
||||
impl: optimized,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// normalizeIDs ensures that the metadata present with an AST is reset in a manner such
|
||||
// that the ids within the expression correspond to the ids within macros.
|
||||
func normalizeIDs(idGen ast.IDGenerator, optimized ast.Expr, info *ast.SourceInfo) {
|
||||
optimized.RenumberIDs(idGen)
|
||||
if len(info.MacroCalls()) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Sort the macro ids to make sure that the renumbering of macro-specific variables
|
||||
// is stable across normalization calls.
|
||||
sortedMacroIDs := []int64{}
|
||||
for id := range info.MacroCalls() {
|
||||
sortedMacroIDs = append(sortedMacroIDs, id)
|
||||
}
|
||||
sort.Slice(sortedMacroIDs, func(i, j int) bool { return sortedMacroIDs[i] < sortedMacroIDs[j] })
|
||||
|
||||
// First, update the macro call ids themselves.
|
||||
callIDMap := map[int64]int64{}
|
||||
for _, id := range sortedMacroIDs {
|
||||
callIDMap[id] = idGen(id)
|
||||
}
|
||||
// Then update the macro call definitions which refer to these ids, but
|
||||
// ensure that the updates don't collide and remove macro entries which haven't
|
||||
// been visited / updated yet.
|
||||
type macroUpdate struct {
|
||||
id int64
|
||||
call ast.Expr
|
||||
}
|
||||
macroUpdates := []macroUpdate{}
|
||||
for _, oldID := range sortedMacroIDs {
|
||||
newID := callIDMap[oldID]
|
||||
call, found := info.GetMacroCall(oldID)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
call.RenumberIDs(idGen)
|
||||
macroUpdates = append(macroUpdates, macroUpdate{id: newID, call: call})
|
||||
info.ClearMacroCall(oldID)
|
||||
}
|
||||
for _, u := range macroUpdates {
|
||||
info.SetMacroCall(u.id, u.call)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanupMacroRefs(expr ast.Expr, info *ast.SourceInfo) {
|
||||
if len(info.MacroCalls()) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Sanitize the macro call references once the optimized expression has been computed
|
||||
// and the ids normalized between the expression and the macros.
|
||||
exprRefMap := make(map[int64]struct{})
|
||||
ast.PostOrderVisit(expr, ast.NewExprVisitor(func(e ast.Expr) {
|
||||
if e.ID() == 0 {
|
||||
return
|
||||
}
|
||||
exprRefMap[e.ID()] = struct{}{}
|
||||
}))
|
||||
// Update the macro call id references to ensure that macro pointers are
|
||||
// updated consistently across macros.
|
||||
for _, call := range info.MacroCalls() {
|
||||
ast.PostOrderVisit(call, ast.NewExprVisitor(func(e ast.Expr) {
|
||||
if e.ID() == 0 {
|
||||
return
|
||||
}
|
||||
exprRefMap[e.ID()] = struct{}{}
|
||||
}))
|
||||
}
|
||||
for id := range info.MacroCalls() {
|
||||
if _, found := exprRefMap[id]; !found {
|
||||
info.ClearMacroCall(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// newIDGenerator ensures that new ids are only created the first time they are encountered.
|
||||
func newIDGenerator(seed int64) *idGenerator {
|
||||
return &idGenerator{
|
||||
idMap: make(map[int64]int64),
|
||||
seed: seed,
|
||||
}
|
||||
}
|
||||
|
||||
type idGenerator struct {
|
||||
idMap map[int64]int64
|
||||
seed int64
|
||||
}
|
||||
|
||||
func (gen *idGenerator) nextID() int64 {
|
||||
gen.seed++
|
||||
return gen.seed
|
||||
}
|
||||
|
||||
func (gen *idGenerator) renumberStable(id int64) int64 {
|
||||
if id == 0 {
|
||||
return 0
|
||||
}
|
||||
if newID, found := gen.idMap[id]; found {
|
||||
return newID
|
||||
}
|
||||
nextID := gen.nextID()
|
||||
gen.idMap[id] = nextID
|
||||
return nextID
|
||||
}
|
||||
|
||||
// OptimizerContext embeds Env and Issues instances to make it easy to type-check and evaluate
|
||||
// subexpressions and report any errors encountered along the way. The context also embeds the
|
||||
// optimizerExprFactory which can be used to generate new sub-expressions with expression ids
|
||||
// consistent with the expectations of a parsed expression.
|
||||
type OptimizerContext struct {
|
||||
*Env
|
||||
*optimizerExprFactory
|
||||
*Issues
|
||||
}
|
||||
|
||||
// ExtendEnv auguments the context's environment with the additional options.
|
||||
func (opt *OptimizerContext) ExtendEnv(opts ...EnvOption) error {
|
||||
e, err := opt.Env.Extend(opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opt.Env = e
|
||||
return nil
|
||||
}
|
||||
|
||||
// ASTOptimizer applies an optimization over an AST and returns the optimized result.
|
||||
type ASTOptimizer interface {
|
||||
// Optimize optimizes a type-checked AST within an Environment and accumulates any issues.
|
||||
Optimize(*OptimizerContext, *ast.AST) *ast.AST
|
||||
}
|
||||
|
||||
type optimizerExprFactory struct {
|
||||
*idGenerator
|
||||
fac ast.ExprFactory
|
||||
sourceInfo *ast.SourceInfo
|
||||
}
|
||||
|
||||
// NewAST creates an AST from the current expression using the tracked source info which
|
||||
// is modified and managed by the OptimizerContext.
|
||||
func (opt *optimizerExprFactory) NewAST(expr ast.Expr) *ast.AST {
|
||||
return ast.NewAST(expr, opt.sourceInfo)
|
||||
}
|
||||
|
||||
// CopyAST creates a renumbered copy of `Expr` and `SourceInfo` values of the input AST, where the
|
||||
// renumbering uses the same scheme as the core optimizer logic ensuring there are no collisions
|
||||
// between copies.
|
||||
//
|
||||
// Use this method before attempting to merge the expression from AST into another.
|
||||
func (opt *optimizerExprFactory) CopyAST(a *ast.AST) (ast.Expr, *ast.SourceInfo) {
|
||||
idGen := newIDGenerator(opt.nextID())
|
||||
defer func() { opt.seed = idGen.nextID() }()
|
||||
copyExpr := opt.fac.CopyExpr(a.Expr())
|
||||
copyInfo := ast.CopySourceInfo(a.SourceInfo())
|
||||
normalizeIDs(idGen.renumberStable, copyExpr, copyInfo)
|
||||
return copyExpr, copyInfo
|
||||
}
|
||||
|
||||
// CopyASTAndMetadata copies the input AST and propagates the macro metadata into the AST being
|
||||
// optimized.
|
||||
func (opt *optimizerExprFactory) CopyASTAndMetadata(a *ast.AST) ast.Expr {
|
||||
copyExpr, copyInfo := opt.CopyAST(a)
|
||||
for macroID, call := range copyInfo.MacroCalls() {
|
||||
opt.SetMacroCall(macroID, call)
|
||||
}
|
||||
return copyExpr
|
||||
}
|
||||
|
||||
// ClearMacroCall clears the macro at the given expression id.
|
||||
func (opt *optimizerExprFactory) ClearMacroCall(id int64) {
|
||||
opt.sourceInfo.ClearMacroCall(id)
|
||||
}
|
||||
|
||||
// SetMacroCall sets the macro call metadata for the given macro id within the tracked source info
|
||||
// metadata.
|
||||
func (opt *optimizerExprFactory) SetMacroCall(id int64, expr ast.Expr) {
|
||||
opt.sourceInfo.SetMacroCall(id, expr)
|
||||
}
|
||||
|
||||
// MacroCalls returns the map of macro calls currently in the context.
|
||||
func (opt *optimizerExprFactory) MacroCalls() map[int64]ast.Expr {
|
||||
return opt.sourceInfo.MacroCalls()
|
||||
}
|
||||
|
||||
// NewBindMacro creates an AST expression representing the expanded bind() macro, and a macro expression
|
||||
// representing the unexpanded call signature to be inserted into the source info macro call metadata.
|
||||
func (opt *optimizerExprFactory) NewBindMacro(macroID int64, varName string, varInit, remaining ast.Expr) (astExpr, macroExpr ast.Expr) {
|
||||
varID := opt.nextID()
|
||||
remainingID := opt.nextID()
|
||||
remaining = opt.fac.CopyExpr(remaining)
|
||||
remaining.RenumberIDs(func(id int64) int64 {
|
||||
if id == macroID {
|
||||
return remainingID
|
||||
}
|
||||
return id
|
||||
})
|
||||
if call, exists := opt.sourceInfo.GetMacroCall(macroID); exists {
|
||||
opt.SetMacroCall(remainingID, opt.fac.CopyExpr(call))
|
||||
}
|
||||
|
||||
astExpr = opt.fac.NewComprehension(macroID,
|
||||
opt.fac.NewList(opt.nextID(), []ast.Expr{}, []int32{}),
|
||||
"#unused",
|
||||
varName,
|
||||
opt.fac.CopyExpr(varInit),
|
||||
opt.fac.NewLiteral(opt.nextID(), types.False),
|
||||
opt.fac.NewIdent(varID, varName),
|
||||
remaining)
|
||||
|
||||
macroExpr = opt.fac.NewMemberCall(0, "bind",
|
||||
opt.fac.NewIdent(opt.nextID(), "cel"),
|
||||
opt.fac.NewIdent(varID, varName),
|
||||
opt.fac.CopyExpr(varInit),
|
||||
opt.fac.CopyExpr(remaining))
|
||||
opt.sanitizeMacro(macroID, macroExpr)
|
||||
return
|
||||
}
|
||||
|
||||
// NewCall creates a global function call invocation expression.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// countByField(list, fieldName)
|
||||
// - function: countByField
|
||||
// - args: [list, fieldName]
|
||||
func (opt *optimizerExprFactory) NewCall(function string, args ...ast.Expr) ast.Expr {
|
||||
return opt.fac.NewCall(opt.nextID(), function, args...)
|
||||
}
|
||||
|
||||
// NewMemberCall creates a member function call invocation expression where 'target' is the receiver of the call.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// list.countByField(fieldName)
|
||||
// - function: countByField
|
||||
// - target: list
|
||||
// - args: [fieldName]
|
||||
func (opt *optimizerExprFactory) NewMemberCall(function string, target ast.Expr, args ...ast.Expr) ast.Expr {
|
||||
return opt.fac.NewMemberCall(opt.nextID(), function, target, args...)
|
||||
}
|
||||
|
||||
// NewIdent creates a new identifier expression.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// - simple_var_name
|
||||
// - qualified.subpackage.var_name
|
||||
func (opt *optimizerExprFactory) NewIdent(name string) ast.Expr {
|
||||
return opt.fac.NewIdent(opt.nextID(), name)
|
||||
}
|
||||
|
||||
// NewLiteral creates a new literal expression value.
|
||||
//
|
||||
// The range of valid values for a literal generated during optimization is different than for expressions
|
||||
// generated via parsing / type-checking, as the ref.Val may be _any_ CEL value so long as the value can
|
||||
// be converted back to a literal-like form.
|
||||
func (opt *optimizerExprFactory) NewLiteral(value ref.Val) ast.Expr {
|
||||
return opt.fac.NewLiteral(opt.nextID(), value)
|
||||
}
|
||||
|
||||
// NewList creates a list expression with a set of optional indices.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// [a, b]
|
||||
// - elems: [a, b]
|
||||
// - optIndices: []
|
||||
//
|
||||
// [a, ?b, ?c]
|
||||
// - elems: [a, b, c]
|
||||
// - optIndices: [1, 2]
|
||||
func (opt *optimizerExprFactory) NewList(elems []ast.Expr, optIndices []int32) ast.Expr {
|
||||
return opt.fac.NewList(opt.nextID(), elems, optIndices)
|
||||
}
|
||||
|
||||
// NewMap creates a map from a set of entry expressions which contain a key and value expression.
|
||||
func (opt *optimizerExprFactory) NewMap(entries []ast.EntryExpr) ast.Expr {
|
||||
return opt.fac.NewMap(opt.nextID(), entries)
|
||||
}
|
||||
|
||||
// NewMapEntry creates a map entry with a key and value expression and a flag to indicate whether the
|
||||
// entry is optional.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// {a: b}
|
||||
// - key: a
|
||||
// - value: b
|
||||
// - optional: false
|
||||
//
|
||||
// {?a: ?b}
|
||||
// - key: a
|
||||
// - value: b
|
||||
// - optional: true
|
||||
func (opt *optimizerExprFactory) NewMapEntry(key, value ast.Expr, isOptional bool) ast.EntryExpr {
|
||||
return opt.fac.NewMapEntry(opt.nextID(), key, value, isOptional)
|
||||
}
|
||||
|
||||
// NewHasMacro generates a test-only select expression to be included within an AST and an unexpanded
|
||||
// has() macro call signature to be inserted into the source info macro call metadata.
|
||||
func (opt *optimizerExprFactory) NewHasMacro(macroID int64, s ast.Expr) (astExpr, macroExpr ast.Expr) {
|
||||
sel := s.AsSelect()
|
||||
astExpr = opt.fac.NewPresenceTest(macroID, sel.Operand(), sel.FieldName())
|
||||
macroExpr = opt.fac.NewCall(0, "has",
|
||||
opt.NewSelect(opt.fac.CopyExpr(sel.Operand()), sel.FieldName()))
|
||||
opt.sanitizeMacro(macroID, macroExpr)
|
||||
return
|
||||
}
|
||||
|
||||
// NewSelect creates a select expression where a field value is selected from an operand.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// msg.field_name
|
||||
// - operand: msg
|
||||
// - field: field_name
|
||||
func (opt *optimizerExprFactory) NewSelect(operand ast.Expr, field string) ast.Expr {
|
||||
return opt.fac.NewSelect(opt.nextID(), operand, field)
|
||||
}
|
||||
|
||||
// NewStruct creates a new typed struct value with an set of field initializations.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// pkg.TypeName{field: value}
|
||||
// - typeName: pkg.TypeName
|
||||
// - fields: [{field: value}]
|
||||
func (opt *optimizerExprFactory) NewStruct(typeName string, fields []ast.EntryExpr) ast.Expr {
|
||||
return opt.fac.NewStruct(opt.nextID(), typeName, fields)
|
||||
}
|
||||
|
||||
// NewStructField creates a struct field initialization.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// {count: 3u}
|
||||
// - field: count
|
||||
// - value: 3u
|
||||
// - optional: false
|
||||
//
|
||||
// {?count: x}
|
||||
// - field: count
|
||||
// - value: x
|
||||
// - optional: true
|
||||
func (opt *optimizerExprFactory) NewStructField(field string, value ast.Expr, isOptional bool) ast.EntryExpr {
|
||||
return opt.fac.NewStructField(opt.nextID(), field, value, isOptional)
|
||||
}
|
||||
|
||||
// UpdateExpr updates the target expression with the updated content while preserving macro metadata.
|
||||
//
|
||||
// There are four scenarios during the update to consider:
|
||||
// 1. target is not macro, updated is not macro
|
||||
// 2. target is macro, updated is not macro
|
||||
// 3. target is macro, updated is macro
|
||||
// 4. target is not macro, updated is macro
|
||||
//
|
||||
// When the target is a macro already, it may either be updated to a new macro function
|
||||
// body if the update is also a macro, or it may be removed altogether if the update is
|
||||
// a macro.
|
||||
//
|
||||
// When the update is a macro, then the target references within other macros must be
|
||||
// updated to point to the new updated macro. Otherwise, other macros which pointed to
|
||||
// the target body must be replaced with copies of the updated expression body.
|
||||
func (opt *optimizerExprFactory) UpdateExpr(target, updated ast.Expr) {
|
||||
// Update the expression
|
||||
target.SetKindCase(updated)
|
||||
|
||||
// Early return if there's no macros present sa the source info reflects the
|
||||
// macro set from the target and updated expressions.
|
||||
if len(opt.sourceInfo.MacroCalls()) == 0 {
|
||||
return
|
||||
}
|
||||
// Determine whether the target expression was a macro.
|
||||
_, targetIsMacro := opt.sourceInfo.GetMacroCall(target.ID())
|
||||
|
||||
// Determine whether the updated expression was a macro.
|
||||
updatedMacro, updatedIsMacro := opt.sourceInfo.GetMacroCall(updated.ID())
|
||||
|
||||
if updatedIsMacro {
|
||||
// If the updated call was a macro, then updated id maps to target id,
|
||||
// and the updated macro moves into the target id slot.
|
||||
opt.sourceInfo.ClearMacroCall(updated.ID())
|
||||
opt.sourceInfo.SetMacroCall(target.ID(), updatedMacro)
|
||||
} else if targetIsMacro {
|
||||
// Otherwise if the target expr was a macro, but is no longer, clear
|
||||
// the macro reference.
|
||||
opt.sourceInfo.ClearMacroCall(target.ID())
|
||||
}
|
||||
|
||||
// Punch holes in the updated value where macros references exist.
|
||||
macroExpr := opt.fac.CopyExpr(target)
|
||||
macroRefVisitor := ast.NewExprVisitor(func(e ast.Expr) {
|
||||
if _, exists := opt.sourceInfo.GetMacroCall(e.ID()); exists {
|
||||
e.SetKindCase(nil)
|
||||
}
|
||||
})
|
||||
ast.PostOrderVisit(macroExpr, macroRefVisitor)
|
||||
|
||||
// Update any references to the expression within a macro
|
||||
macroVisitor := ast.NewExprVisitor(func(call ast.Expr) {
|
||||
// Update the target expression to point to the macro expression which
|
||||
// will be empty if the updated expression was a macro.
|
||||
if call.ID() == target.ID() {
|
||||
call.SetKindCase(opt.fac.CopyExpr(macroExpr))
|
||||
}
|
||||
// Update the macro call expression if it refers to the updated expression
|
||||
// id which has since been remapped to the target id.
|
||||
if call.ID() == updated.ID() {
|
||||
// Either ensure the expression is a macro reference or a populated with
|
||||
// the relevant sub-expression if the updated expr was not a macro.
|
||||
if updatedIsMacro {
|
||||
call.SetKindCase(nil)
|
||||
} else {
|
||||
call.SetKindCase(opt.fac.CopyExpr(macroExpr))
|
||||
}
|
||||
// Since SetKindCase does not renumber the id, ensure the references to
|
||||
// the old 'updated' id are mapped to the target id.
|
||||
call.RenumberIDs(func(id int64) int64 {
|
||||
if id == updated.ID() {
|
||||
return target.ID()
|
||||
}
|
||||
return id
|
||||
})
|
||||
}
|
||||
})
|
||||
for _, call := range opt.sourceInfo.MacroCalls() {
|
||||
ast.PostOrderVisit(call, macroVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
func (opt *optimizerExprFactory) sanitizeMacro(macroID int64, macroExpr ast.Expr) {
|
||||
macroRefVisitor := ast.NewExprVisitor(func(e ast.Expr) {
|
||||
if _, exists := opt.sourceInfo.GetMacroCall(e.ID()); exists && e.ID() != macroID {
|
||||
e.SetKindCase(nil)
|
||||
}
|
||||
})
|
||||
ast.PostOrderVisit(macroExpr, macroRefVisitor)
|
||||
}
|
667
e2e/vendor/github.com/google/cel-go/cel/options.go
generated
vendored
Normal file
667
e2e/vendor/github.com/google/cel-go/cel/options.go
generated
vendored
Normal file
@ -0,0 +1,667 @@
|
||||
// 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"
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/functions"
|
||||
"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/interpreter"
|
||||
"github.com/google/cel-go/parser"
|
||||
|
||||
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
|
||||
|
||||
// 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
|
||||
|
||||
// Enable the serialization of logical operator ASTs as variadic calls, thus
|
||||
// compressing the logic graph to a single call when multiple like-operator
|
||||
// expressions occur: e.g. a && b && c && d -> call(_&&_, [a, b, c, d])
|
||||
featureVariadicLogicalASTs
|
||||
|
||||
// Enable error generation when a presence test or optional field selection is
|
||||
// performed on a primitive type.
|
||||
featureEnableErrorOnBadPresenceTest
|
||||
)
|
||||
|
||||
// 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 types.Adapter implementation with a custom one.
|
||||
//
|
||||
// Note: This option must be specified before the Types and TypeDescs options when used together.
|
||||
func CustomTypeAdapter(adapter types.Adapter) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.adapter = adapter
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CustomTypeProvider replaces the types.Provider implementation with a custom one.
|
||||
//
|
||||
// The `provider` variable type may either be types.Provider or ref.TypeProvider (deprecated)
|
||||
//
|
||||
// Note: This option must be specified before the Types and TypeDescs options when used together.
|
||||
func CustomTypeProvider(provider any) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
var err error
|
||||
e.provider, err = maybeInteropProvider(provider)
|
||||
return e, err
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
declOpts := []EnvOption{}
|
||||
var err error
|
||||
var opt EnvOption
|
||||
// Convert the declarations to `EnvOption` values ahead of time.
|
||||
// Surface any errors in conversion when the options are applied.
|
||||
for _, d := range decls {
|
||||
opt, err = ExprDeclToDeclaration(d)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
declOpts = append(declOpts, opt)
|
||||
}
|
||||
return func(e *Env) (*Env, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, o := range declOpts {
|
||||
e, err = o(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
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 disables mixed type list and map literal values.
|
||||
//
|
||||
// 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 ASTValidators(ValidateHomogeneousAggregateLiterals())
|
||||
}
|
||||
|
||||
// variadicLogicalOperatorASTs flatten like-operator chained logical expressions into a single
|
||||
// variadic call with N-terms. This behavior is useful when serializing to a protocol buffer as
|
||||
// it will reduce the number of recursive calls needed to deserialize the AST later.
|
||||
//
|
||||
// For example, given the following expression the call graph will be rendered accordingly:
|
||||
//
|
||||
// expression: a && b && c && (d || e)
|
||||
// ast: call(_&&_, [a, b, c, call(_||_, [d, e])])
|
||||
func variadicLogicalOperatorASTs() EnvOption {
|
||||
return features(featureVariadicLogicalASTs, 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
|
||||
}
|
||||
}
|
||||
|
||||
// customTypeRegistry is an internal-only interface containing the minimum methods required to support
|
||||
// custom types. It is a subset of methods from ref.TypeRegistry.
|
||||
type customTypeRegistry interface {
|
||||
RegisterDescriptor(protoreflect.FileDescriptor) error
|
||||
RegisterType(...ref.Type) error
|
||||
}
|
||||
|
||||
// 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 ...any) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
reg, isReg := e.provider.(customTypeRegistry)
|
||||
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 ...any) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
reg, isReg := e.provider.(customTypeRegistry)
|
||||
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 customTypeRegistry, 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 customTypeRegistry, 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]any`.
|
||||
func Globals(vars any) 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
|
||||
|
||||
// OptCheckStringFormat enables compile-time checking of string.format calls for syntax/cardinality.
|
||||
//
|
||||
// Deprecated: use ext.StringsValidateFormatCalls() as this option is now a no-op.
|
||||
OptCheckStringFormat 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
|
||||
}
|
||||
}
|
||||
|
||||
// CostEstimatorOptions configure type-check time options for estimating expression cost.
|
||||
func CostEstimatorOptions(costOpts ...checker.CostOption) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.costOptions = append(e.costOptions, costOpts...)
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// CostTrackerOptions configures a set of options for cost-tracking.
|
||||
//
|
||||
// Note, CostTrackerOptions is a no-op unless CostTracking is also enabled.
|
||||
func CostTrackerOptions(costOpts ...interpreter.CostTrackerOption) ProgramOption {
|
||||
return func(p *prog) (*prog, error) {
|
||||
p.costOptions = append(p.costOptions, costOpts...)
|
||||
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) (*Type, error) {
|
||||
if field.Kind() == protoreflect.MessageKind || field.Kind() == protoreflect.GroupKind {
|
||||
msgName := (string)(field.Message().FullName())
|
||||
return ObjectType(msgName), nil
|
||||
}
|
||||
if primitiveType, found := types.ProtoCELPrimitives[field.Kind()]; found {
|
||||
return primitiveType, nil
|
||||
}
|
||||
if field.Kind() == protoreflect.EnumKind {
|
||||
return IntType, nil
|
||||
}
|
||||
return nil, fmt.Errorf("field %s type %s not implemented", field.FullName(), field.Kind().String())
|
||||
}
|
||||
|
||||
func fieldToVariable(field protoreflect.FieldDescriptor) (EnvOption, 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 Variable(name, MapType(keyType, valueType)), nil
|
||||
}
|
||||
if field.IsList() {
|
||||
elemType, err := fieldToCELType(field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Variable(name, ListType(elemType)), nil
|
||||
}
|
||||
celType, err := fieldToCELType(field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Variable(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) {
|
||||
fields := descriptor.Fields()
|
||||
for i := 0; i < fields.Len(); i++ {
|
||||
field := fields.Get(i)
|
||||
variable, err := fieldToVariable(field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e, err = variable(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return Types(dynamicpb.NewMessage(descriptor))(e)
|
||||
}
|
||||
}
|
||||
|
||||
// ContextProtoVars uses the fields of the input proto.Messages as top-level variables within an Activation.
|
||||
//
|
||||
// Consider using with `DeclareContextProto` to simplify variable type declarations and publishing when using
|
||||
// protocol buffers.
|
||||
func ContextProtoVars(ctx proto.Message) (interpreter.Activation, error) {
|
||||
if ctx == nil || !ctx.ProtoReflect().IsValid() {
|
||||
return interpreter.EmptyActivation(), nil
|
||||
}
|
||||
reg, err := types.NewRegistry(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pbRef := ctx.ProtoReflect()
|
||||
typeName := string(pbRef.Descriptor().FullName())
|
||||
fields := pbRef.Descriptor().Fields()
|
||||
vars := make(map[string]any, fields.Len())
|
||||
for i := 0; i < fields.Len(); i++ {
|
||||
field := fields.Get(i)
|
||||
sft, found := reg.FindStructFieldType(typeName, field.TextName())
|
||||
if !found {
|
||||
return nil, fmt.Errorf("no such field: %s", field.TextName())
|
||||
}
|
||||
fieldVal, err := sft.GetFrom(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vars[field.TextName()] = fieldVal
|
||||
}
|
||||
return interpreter.NewActivation(vars)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// ParserRecursionLimit adjusts the AST depth the parser will tolerate.
|
||||
// Defaults defined in the parser package.
|
||||
func ParserRecursionLimit(limit int) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.prsrOpts = append(e.prsrOpts, parser.MaxRecursionDepth(limit))
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ParserExpressionSizeLimit adjusts the number of code points the expression parser is allowed to parse.
|
||||
// Defaults defined in the parser package.
|
||||
func ParserExpressionSizeLimit(limit int) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
e.prsrOpts = append(e.prsrOpts, parser.ExpressionSizeCodePointLimit(limit))
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
func maybeInteropProvider(provider any) (types.Provider, error) {
|
||||
switch p := provider.(type) {
|
||||
case types.Provider:
|
||||
return p, nil
|
||||
case ref.TypeProvider:
|
||||
return &interopCELTypeProvider{TypeProvider: p}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type provider: %T", provider)
|
||||
}
|
||||
}
|
546
e2e/vendor/github.com/google/cel-go/cel/program.go
generated
vendored
Normal file
546
e2e/vendor/github.com/google/cel-go/cel/program.go
generated
vendored
Normal file
@ -0,0 +1,546 @@
|
||||
// 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"
|
||||
"sync"
|
||||
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"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]any`.
|
||||
//
|
||||
// If the `OptTrackState`, `OptTrackCost` or `OptExhaustiveEval` flags are used, the `details` response will
|
||||
// be non-nil. Given this caveat on `details`, the return state from evaluation will be:
|
||||
//
|
||||
// * `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(any) (ref.Val, *EvalDetails, error)
|
||||
|
||||
// ContextEval evaluates the program with a set of input variables and a context object in order
|
||||
// to support cancellation and timeouts. This method must be used in conjunction with the
|
||||
// InterruptCheckFrequency() option for cancellation interrupts to be impact evaluation.
|
||||
//
|
||||
// The vars value may either be an `interpreter.Activation` or `map[string]any`.
|
||||
//
|
||||
// The output contract for `ContextEval` is otherwise identical to the `Eval` method.
|
||||
ContextEval(context.Context, any) (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.
|
||||
//
|
||||
// This method relies on manually configured sets of missing attribute patterns. For a method which
|
||||
// infers the missing variables from the input and the configured environment, use Env.PartialVars().
|
||||
//
|
||||
// The `vars` value may either be an interpreter.Activation or any valid input to the
|
||||
// interpreter.NewActivation call.
|
||||
func PartialVars(vars any,
|
||||
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 == nil || 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
|
||||
costOptions []interpreter.CostTrackerOption
|
||||
costLimit *uint64
|
||||
}
|
||||
|
||||
func (p *prog) clone() *prog {
|
||||
costOptsCopy := make([]interpreter.CostTrackerOption, len(p.costOptions))
|
||||
copy(costOptsCopy, p.costOptions)
|
||||
|
||||
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, a *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,
|
||||
costOptions: []interpreter.CostTrackerOption{},
|
||||
}
|
||||
|
||||
// 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
|
||||
attrFactorOpts := []interpreter.AttrFactoryOption{
|
||||
interpreter.EnableErrorOnBadPresenceTest(p.HasFeature(featureEnableErrorOnBadPresenceTest)),
|
||||
}
|
||||
if p.evalOpts&OptPartialEval == OptPartialEval {
|
||||
attrFactory = interpreter.NewPartialAttributeFactory(e.Container, e.adapter, e.provider, attrFactorOpts...)
|
||||
} else {
|
||||
attrFactory = interpreter.NewAttributeFactory(e.Container, e.adapter, e.provider, attrFactorOpts...)
|
||||
}
|
||||
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
|
||||
for _, costOpt := range p.costOptions {
|
||||
err := costOpt(costTracker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// 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(a, decs)
|
||||
}
|
||||
return newProgGen(factory)
|
||||
}
|
||||
return p.initInterpretable(a, decorators)
|
||||
}
|
||||
|
||||
func (p *prog) initInterpretable(a *ast.AST, decs []interpreter.InterpretableDecorator) (*prog, error) {
|
||||
// When the AST has been exprAST it contains metadata that can be used to speed up program execution.
|
||||
interpretable, err := p.interpreter.NewInterpretable(a, decs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.interpretable = interpretable
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Eval implements the Program interface method.
|
||||
func (p *prog) Eval(input any) (v ref.Val, det *EvalDetails, err error) {
|
||||
// Configure error recovery for unexpected panics during evaluation. Note, the use of named
|
||||
// return values makes it possible to modify the error response during the recovery
|
||||
// function.
|
||||
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]any:
|
||||
vars = activationPool.Setup(v)
|
||||
defer activationPool.Put(vars)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid input, wanted Activation or map[string]any, got: (%T)%v", input, input)
|
||||
}
|
||||
if p.defaultVars != nil {
|
||||
vars = interpreter.NewHierarchicalActivation(p.defaultVars, vars)
|
||||
}
|
||||
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 any) (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]any:
|
||||
rawVars := activationPool.Setup(v)
|
||||
defer activationPool.Put(rawVars)
|
||||
vars = ctxActivationPool.Setup(rawVars, ctx.Done(), p.interruptCheckFrequency)
|
||||
defer ctxActivationPool.Put(vars)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid input, wanted Activation or map[string]any, got: (%T)%v", input, input)
|
||||
}
|
||||
return p.Eval(vars)
|
||||
}
|
||||
|
||||
// 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
|
||||
tracker, err := interpreter.NewCostTracker(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = factory(interpreter.NewEvalState(), tracker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &progGen{factory: factory}, nil
|
||||
}
|
||||
|
||||
// Eval implements the Program interface method.
|
||||
func (gen *progGen) Eval(input any) (ref.Val, *EvalDetails, error) {
|
||||
// The factory based Eval() differs from the standard evaluation model in that it generates a
|
||||
// new EvalState instance for each call to ensure that unique evaluations yield unique stateful
|
||||
// results.
|
||||
state := interpreter.NewEvalState()
|
||||
costTracker, err := interpreter.NewCostTracker(nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
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 any) (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, err := interpreter.NewCostTracker(nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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) (any, 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() any {
|
||||
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]any
|
||||
lazyVars map[string]any
|
||||
}
|
||||
|
||||
// ResolveName looks up the value of the input variable name, if found.
|
||||
//
|
||||
// Lazy bindings may be supplied within the map-based input in either of the following forms:
|
||||
// - func() any
|
||||
// - func() ref.Val
|
||||
//
|
||||
// The lazy binding will only be invoked once per evaluation.
|
||||
//
|
||||
// Values which are not represented as ref.Val types on input may be adapted to a ref.Val using
|
||||
// the types.Adapter configured in the environment.
|
||||
func (a *evalActivation) ResolveName(name string) (any, 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() any:
|
||||
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() any {
|
||||
return &evalActivation{lazyVars: make(map[string]any)}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type evalActivationPool struct {
|
||||
sync.Pool
|
||||
}
|
||||
|
||||
// Setup initializes a pooled Activation object with the map input.
|
||||
func (p *evalActivationPool) Setup(vars map[string]any) *evalActivation {
|
||||
a := p.Pool.Get().(*evalActivation)
|
||||
a.vars = vars
|
||||
return a
|
||||
}
|
||||
|
||||
func (p *evalActivationPool) Put(value any) {
|
||||
a := value.(*evalActivation)
|
||||
for k := range a.lazyVars {
|
||||
delete(a.lazyVars, k)
|
||||
}
|
||||
p.Pool.Put(a)
|
||||
}
|
||||
|
||||
var (
|
||||
// activationPool is an internally managed pool of Activation values that wrap map[string]any inputs
|
||||
activationPool = newEvalActivationPool()
|
||||
|
||||
// ctxActivationPool is an internally managed pool of Activation values that expose a special #interrupted variable
|
||||
ctxActivationPool = newCtxEvalActivationPool()
|
||||
)
|
375
e2e/vendor/github.com/google/cel-go/cel/validator.go
generated
vendored
Normal file
375
e2e/vendor/github.com/google/cel-go/cel/validator.go
generated
vendored
Normal file
@ -0,0 +1,375 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
)
|
||||
|
||||
const (
|
||||
homogeneousValidatorName = "cel.lib.std.validate.types.homogeneous"
|
||||
|
||||
// HomogeneousAggregateLiteralExemptFunctions is the ValidatorConfig key used to configure
|
||||
// the set of function names which are exempt from homogeneous type checks. The expected type
|
||||
// is a string list of function names.
|
||||
//
|
||||
// As an example, the `<string>.format([args])` call expects the input arguments list to be
|
||||
// comprised of a variety of types which correspond to the types expected by the format control
|
||||
// clauses; however, all other uses of a mixed element type list, would be unexpected.
|
||||
HomogeneousAggregateLiteralExemptFunctions = homogeneousValidatorName + ".exempt"
|
||||
)
|
||||
|
||||
// ASTValidators configures a set of ASTValidator instances into the target environment.
|
||||
//
|
||||
// Validators are applied in the order in which the are specified and are treated as singletons.
|
||||
// The same ASTValidator with a given name will not be applied more than once.
|
||||
func ASTValidators(validators ...ASTValidator) EnvOption {
|
||||
return func(e *Env) (*Env, error) {
|
||||
for _, v := range validators {
|
||||
if !e.HasValidator(v.Name()) {
|
||||
e.validators = append(e.validators, v)
|
||||
}
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ASTValidator defines a singleton interface for validating a type-checked Ast against an environment.
|
||||
//
|
||||
// Note: the Issues argument is mutable in the sense that it is intended to collect errors which will be
|
||||
// reported to the caller.
|
||||
type ASTValidator interface {
|
||||
// Name returns the name of the validator. Names must be unique.
|
||||
Name() string
|
||||
|
||||
// Validate validates a given Ast within an Environment and collects a set of potential issues.
|
||||
//
|
||||
// The ValidatorConfig is generated from the set of ASTValidatorConfigurer instances prior to
|
||||
// the invocation of the Validate call. The expectation is that the validator configuration
|
||||
// is created in sequence and immutable once provided to the Validate call.
|
||||
//
|
||||
// See individual validators for more information on their configuration keys and configuration
|
||||
// properties.
|
||||
Validate(*Env, ValidatorConfig, *ast.AST, *Issues)
|
||||
}
|
||||
|
||||
// ValidatorConfig provides an accessor method for querying validator configuration state.
|
||||
type ValidatorConfig interface {
|
||||
GetOrDefault(name string, value any) any
|
||||
}
|
||||
|
||||
// MutableValidatorConfig provides mutation methods for querying and updating validator configuration
|
||||
// settings.
|
||||
type MutableValidatorConfig interface {
|
||||
ValidatorConfig
|
||||
Set(name string, value any) error
|
||||
}
|
||||
|
||||
// ASTValidatorConfigurer indicates that this object, currently expected to be an ASTValidator,
|
||||
// participates in validator configuration settings.
|
||||
//
|
||||
// This interface may be split from the expectation of being an ASTValidator instance in the future.
|
||||
type ASTValidatorConfigurer interface {
|
||||
Configure(MutableValidatorConfig) error
|
||||
}
|
||||
|
||||
// validatorConfig implements the ValidatorConfig and MutableValidatorConfig interfaces.
|
||||
type validatorConfig struct {
|
||||
data map[string]any
|
||||
}
|
||||
|
||||
// newValidatorConfig initializes the validator config with default values for core CEL validators.
|
||||
func newValidatorConfig() *validatorConfig {
|
||||
return &validatorConfig{
|
||||
data: map[string]any{
|
||||
HomogeneousAggregateLiteralExemptFunctions: []string{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrDefault returns the configured value for the name, if present, else the input default value.
|
||||
//
|
||||
// Note, the type-agreement between the input default and configured value is not checked on read.
|
||||
func (config *validatorConfig) GetOrDefault(name string, value any) any {
|
||||
v, found := config.data[name]
|
||||
if !found {
|
||||
return value
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Set configures a validator option with the given name and value.
|
||||
//
|
||||
// If the value had previously been set, the new value must have the same reflection type as the old one,
|
||||
// or the call will error.
|
||||
func (config *validatorConfig) Set(name string, value any) error {
|
||||
v, found := config.data[name]
|
||||
if found && reflect.TypeOf(v) != reflect.TypeOf(value) {
|
||||
return fmt.Errorf("incompatible configuration type for %s, got %T, wanted %T", name, value, v)
|
||||
}
|
||||
config.data[name] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtendedValidations collects a set of common AST validations which reduce the likelihood of runtime errors.
|
||||
//
|
||||
// - Validate duration and timestamp literals
|
||||
// - Ensure regex strings are valid
|
||||
// - Disable mixed type list and map literals
|
||||
func ExtendedValidations() EnvOption {
|
||||
return ASTValidators(
|
||||
ValidateDurationLiterals(),
|
||||
ValidateTimestampLiterals(),
|
||||
ValidateRegexLiterals(),
|
||||
ValidateHomogeneousAggregateLiterals(),
|
||||
)
|
||||
}
|
||||
|
||||
// ValidateDurationLiterals ensures that duration literal arguments are valid immediately after type-check.
|
||||
func ValidateDurationLiterals() ASTValidator {
|
||||
return newFormatValidator(overloads.TypeConvertDuration, 0, evalCall)
|
||||
}
|
||||
|
||||
// ValidateTimestampLiterals ensures that timestamp literal arguments are valid immediately after type-check.
|
||||
func ValidateTimestampLiterals() ASTValidator {
|
||||
return newFormatValidator(overloads.TypeConvertTimestamp, 0, evalCall)
|
||||
}
|
||||
|
||||
// ValidateRegexLiterals ensures that regex patterns are validated after type-check.
|
||||
func ValidateRegexLiterals() ASTValidator {
|
||||
return newFormatValidator(overloads.Matches, 0, compileRegex)
|
||||
}
|
||||
|
||||
// ValidateHomogeneousAggregateLiterals checks that all list and map literals entries have the same types, i.e.
|
||||
// no mixed list element types or mixed map key or map value types.
|
||||
//
|
||||
// Note: the string format call relies on a mixed element type list for ease of use, so this check skips all
|
||||
// literals which occur within string format calls.
|
||||
func ValidateHomogeneousAggregateLiterals() ASTValidator {
|
||||
return homogeneousAggregateLiteralValidator{}
|
||||
}
|
||||
|
||||
// ValidateComprehensionNestingLimit ensures that comprehension nesting does not exceed the specified limit.
|
||||
//
|
||||
// This validator can be useful for preventing arbitrarily nested comprehensions which can take high polynomial
|
||||
// time to complete.
|
||||
//
|
||||
// Note, this limit does not apply to comprehensions with an empty iteration range, as these comprehensions have
|
||||
// no actual looping cost. The cel.bind() utilizes the comprehension structure to perform local variable
|
||||
// assignments and supplies an empty iteration range, so they won't count against the nesting limit either.
|
||||
func ValidateComprehensionNestingLimit(limit int) ASTValidator {
|
||||
return nestingLimitValidator{limit: limit}
|
||||
}
|
||||
|
||||
type argChecker func(env *Env, call, arg ast.Expr) error
|
||||
|
||||
func newFormatValidator(funcName string, argNum int, check argChecker) formatValidator {
|
||||
return formatValidator{
|
||||
funcName: funcName,
|
||||
check: check,
|
||||
argNum: argNum,
|
||||
}
|
||||
}
|
||||
|
||||
type formatValidator struct {
|
||||
funcName string
|
||||
argNum int
|
||||
check argChecker
|
||||
}
|
||||
|
||||
// Name returns the unique name of this function format validator.
|
||||
func (v formatValidator) Name() string {
|
||||
return fmt.Sprintf("cel.lib.std.validate.functions.%s", v.funcName)
|
||||
}
|
||||
|
||||
// Validate searches the AST for uses of a given function name with a constant argument and performs a check
|
||||
// on whether the argument is a valid literal value.
|
||||
func (v formatValidator) Validate(e *Env, _ ValidatorConfig, a *ast.AST, iss *Issues) {
|
||||
root := ast.NavigateAST(a)
|
||||
funcCalls := ast.MatchDescendants(root, ast.FunctionMatcher(v.funcName))
|
||||
for _, call := range funcCalls {
|
||||
callArgs := call.AsCall().Args()
|
||||
if len(callArgs) <= v.argNum {
|
||||
continue
|
||||
}
|
||||
litArg := callArgs[v.argNum]
|
||||
if litArg.Kind() != ast.LiteralKind {
|
||||
continue
|
||||
}
|
||||
if err := v.check(e, call, litArg); err != nil {
|
||||
iss.ReportErrorAtID(litArg.ID(), "invalid %s argument", v.funcName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func evalCall(env *Env, call, arg ast.Expr) error {
|
||||
ast := &Ast{impl: ast.NewAST(call, ast.NewSourceInfo(nil))}
|
||||
prg, err := env.Program(ast)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, err = prg.Eval(NoVars())
|
||||
return err
|
||||
}
|
||||
|
||||
func compileRegex(_ *Env, _, arg ast.Expr) error {
|
||||
pattern := arg.AsLiteral().Value().(string)
|
||||
_, err := regexp.Compile(pattern)
|
||||
return err
|
||||
}
|
||||
|
||||
type homogeneousAggregateLiteralValidator struct{}
|
||||
|
||||
// Name returns the unique name of the homogeneous type validator.
|
||||
func (homogeneousAggregateLiteralValidator) Name() string {
|
||||
return homogeneousValidatorName
|
||||
}
|
||||
|
||||
// Validate validates that all lists and map literals have homogeneous types, i.e. don't contain dyn types.
|
||||
//
|
||||
// This validator makes an exception for list and map literals which occur at any level of nesting within
|
||||
// string format calls.
|
||||
func (v homogeneousAggregateLiteralValidator) Validate(_ *Env, c ValidatorConfig, a *ast.AST, iss *Issues) {
|
||||
var exemptedFunctions []string
|
||||
exemptedFunctions = c.GetOrDefault(HomogeneousAggregateLiteralExemptFunctions, exemptedFunctions).([]string)
|
||||
root := ast.NavigateAST(a)
|
||||
listExprs := ast.MatchDescendants(root, ast.KindMatcher(ast.ListKind))
|
||||
for _, listExpr := range listExprs {
|
||||
if inExemptFunction(listExpr, exemptedFunctions) {
|
||||
continue
|
||||
}
|
||||
l := listExpr.AsList()
|
||||
elements := l.Elements()
|
||||
optIndices := l.OptionalIndices()
|
||||
var elemType *Type
|
||||
for i, e := range elements {
|
||||
et := a.GetType(e.ID())
|
||||
if isOptionalIndex(i, optIndices) {
|
||||
et = et.Parameters()[0]
|
||||
}
|
||||
if elemType == nil {
|
||||
elemType = et
|
||||
continue
|
||||
}
|
||||
if !elemType.IsEquivalentType(et) {
|
||||
v.typeMismatch(iss, e.ID(), elemType, et)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
mapExprs := ast.MatchDescendants(root, ast.KindMatcher(ast.MapKind))
|
||||
for _, mapExpr := range mapExprs {
|
||||
if inExemptFunction(mapExpr, exemptedFunctions) {
|
||||
continue
|
||||
}
|
||||
m := mapExpr.AsMap()
|
||||
entries := m.Entries()
|
||||
var keyType, valType *Type
|
||||
for _, e := range entries {
|
||||
mapEntry := e.AsMapEntry()
|
||||
key, val := mapEntry.Key(), mapEntry.Value()
|
||||
kt, vt := a.GetType(key.ID()), a.GetType(val.ID())
|
||||
if mapEntry.IsOptional() {
|
||||
vt = vt.Parameters()[0]
|
||||
}
|
||||
if keyType == nil && valType == nil {
|
||||
keyType, valType = kt, vt
|
||||
continue
|
||||
}
|
||||
if !keyType.IsEquivalentType(kt) {
|
||||
v.typeMismatch(iss, key.ID(), keyType, kt)
|
||||
}
|
||||
if !valType.IsEquivalentType(vt) {
|
||||
v.typeMismatch(iss, val.ID(), valType, vt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func inExemptFunction(e ast.NavigableExpr, exemptFunctions []string) bool {
|
||||
parent, found := e.Parent()
|
||||
for found {
|
||||
if parent.Kind() == ast.CallKind {
|
||||
fnName := parent.AsCall().FunctionName()
|
||||
for _, exempt := range exemptFunctions {
|
||||
if exempt == fnName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
parent, found = parent.Parent()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isOptionalIndex(i int, optIndices []int32) bool {
|
||||
for _, optInd := range optIndices {
|
||||
if i == int(optInd) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (homogeneousAggregateLiteralValidator) typeMismatch(iss *Issues, id int64, expected, actual *Type) {
|
||||
iss.ReportErrorAtID(id, "expected type '%s' but found '%s'", FormatCELType(expected), FormatCELType(actual))
|
||||
}
|
||||
|
||||
type nestingLimitValidator struct {
|
||||
limit int
|
||||
}
|
||||
|
||||
func (v nestingLimitValidator) Name() string {
|
||||
return "cel.lib.std.validate.comprehension_nesting_limit"
|
||||
}
|
||||
|
||||
func (v nestingLimitValidator) Validate(e *Env, _ ValidatorConfig, a *ast.AST, iss *Issues) {
|
||||
root := ast.NavigateAST(a)
|
||||
comprehensions := ast.MatchDescendants(root, ast.KindMatcher(ast.ComprehensionKind))
|
||||
if len(comprehensions) <= v.limit {
|
||||
return
|
||||
}
|
||||
for _, comp := range comprehensions {
|
||||
count := 0
|
||||
e := comp
|
||||
hasParent := true
|
||||
for hasParent {
|
||||
// When the expression is not a comprehension, continue to the next ancestor.
|
||||
if e.Kind() != ast.ComprehensionKind {
|
||||
e, hasParent = e.Parent()
|
||||
continue
|
||||
}
|
||||
// When the comprehension has an empty range, continue to the next ancestor
|
||||
// as this comprehension does not have any associated cost.
|
||||
iterRange := e.AsComprehension().IterRange()
|
||||
if iterRange.Kind() == ast.ListKind && iterRange.AsList().Size() == 0 {
|
||||
e, hasParent = e.Parent()
|
||||
continue
|
||||
}
|
||||
// Otherwise check the nesting limit.
|
||||
count++
|
||||
if count > v.limit {
|
||||
iss.ReportErrorAtID(comp.ID(), "comprehension exceeds nesting limit")
|
||||
break
|
||||
}
|
||||
e, hasParent = e.Parent()
|
||||
}
|
||||
}
|
||||
}
|
64
e2e/vendor/github.com/google/cel-go/checker/BUILD.bazel
generated
vendored
Normal file
64
e2e/vendor/github.com/google/cel-go/checker/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"checker.go",
|
||||
"cost.go",
|
||||
"env.go",
|
||||
"errors.go",
|
||||
"format.go",
|
||||
"mapping.go",
|
||||
"options.go",
|
||||
"printer.go",
|
||||
"scopes.go",
|
||||
"types.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/checker",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//checker/decls:go_default_library",
|
||||
"//common:go_default_library",
|
||||
"//common/ast:go_default_library",
|
||||
"//common/containers:go_default_library",
|
||||
"//common/debug:go_default_library",
|
||||
"//common/decls:go_default_library",
|
||||
"//common/operators:go_default_library",
|
||||
"//common/overloads:go_default_library",
|
||||
"//common/stdlib: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",
|
||||
"format_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",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
711
e2e/vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
Normal file
711
e2e/vendor/github.com/google/cel-go/checker/checker.go
generated
vendored
Normal file
@ -0,0 +1,711 @@
|
||||
// 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/common"
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/containers"
|
||||
"github.com/google/cel-go/common/decls"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
type checker struct {
|
||||
*ast.AST
|
||||
ast.ExprFactory
|
||||
env *Env
|
||||
errors *typeErrors
|
||||
mappings *mapping
|
||||
freeTypeVarCounter int
|
||||
}
|
||||
|
||||
// Check performs type checking, giving a typed AST.
|
||||
//
|
||||
// The input is a parsed AST 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 type-checked AST, which might not be usable if there are errors in the error
|
||||
// registry.
|
||||
func Check(parsed *ast.AST, source common.Source, env *Env) (*ast.AST, *common.Errors) {
|
||||
errs := common.NewErrors(source)
|
||||
typeMap := make(map[int64]*types.Type)
|
||||
refMap := make(map[int64]*ast.ReferenceInfo)
|
||||
c := checker{
|
||||
AST: ast.NewCheckedAST(parsed, typeMap, refMap),
|
||||
ExprFactory: ast.NewExprFactory(),
|
||||
env: env,
|
||||
errors: &typeErrors{errs: errs},
|
||||
mappings: newMapping(),
|
||||
freeTypeVarCounter: 0,
|
||||
}
|
||||
c.check(c.Expr())
|
||||
|
||||
// Walk over the final type map substituting any type parameters either by their bound value
|
||||
// or by DYN.
|
||||
for id, t := range c.TypeMap() {
|
||||
c.SetType(id, substitute(c.mappings, t, true))
|
||||
}
|
||||
return c.AST, errs
|
||||
}
|
||||
|
||||
func (c *checker) check(e ast.Expr) {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
switch e.Kind() {
|
||||
case ast.LiteralKind:
|
||||
literal := ref.Val(e.AsLiteral())
|
||||
switch literal.Type() {
|
||||
case types.BoolType, types.BytesType, types.DoubleType, types.IntType,
|
||||
types.NullType, types.StringType, types.UintType:
|
||||
c.setType(e, literal.Type().(*types.Type))
|
||||
default:
|
||||
c.errors.unexpectedASTType(e.ID(), c.location(e), "literal", literal.Type().TypeName())
|
||||
}
|
||||
case ast.IdentKind:
|
||||
c.checkIdent(e)
|
||||
case ast.SelectKind:
|
||||
c.checkSelect(e)
|
||||
case ast.CallKind:
|
||||
c.checkCall(e)
|
||||
case ast.ListKind:
|
||||
c.checkCreateList(e)
|
||||
case ast.MapKind:
|
||||
c.checkCreateMap(e)
|
||||
case ast.StructKind:
|
||||
c.checkCreateStruct(e)
|
||||
case ast.ComprehensionKind:
|
||||
c.checkComprehension(e)
|
||||
default:
|
||||
c.errors.unexpectedASTType(e.ID(), c.location(e), "unspecified", reflect.TypeOf(e).Name())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *checker) checkIdent(e ast.Expr) {
|
||||
identName := e.AsIdent()
|
||||
// Check to see if the identifier is declared.
|
||||
if ident := c.env.LookupIdent(identName); ident != nil {
|
||||
c.setType(e, ident.Type())
|
||||
c.setReference(e, ast.NewIdentReference(ident.Name(), ident.Value()))
|
||||
// Overwrite the identifier with its fully qualified name.
|
||||
e.SetKindCase(c.NewIdent(e.ID(), ident.Name()))
|
||||
return
|
||||
}
|
||||
|
||||
c.setType(e, types.ErrorType)
|
||||
c.errors.undeclaredReference(e.ID(), c.location(e), c.env.container.Name(), identName)
|
||||
}
|
||||
|
||||
func (c *checker) checkSelect(e ast.Expr) {
|
||||
sel := e.AsSelect()
|
||||
// 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.Type())
|
||||
c.setReference(e, ast.NewIdentReference(ident.Name(), ident.Value()))
|
||||
e.SetKindCase(c.NewIdent(e.ID(), ident.Name()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
resultType := c.checkSelectField(e, sel.Operand(), sel.FieldName(), false)
|
||||
if sel.IsTestOnly() {
|
||||
resultType = types.BoolType
|
||||
}
|
||||
c.setType(e, substitute(c.mappings, resultType, false))
|
||||
}
|
||||
|
||||
func (c *checker) checkOptSelect(e ast.Expr) {
|
||||
// Collect metadata related to the opt select call packaged by the parser.
|
||||
call := e.AsCall()
|
||||
operand := call.Args()[0]
|
||||
field := call.Args()[1]
|
||||
fieldName, isString := maybeUnwrapString(field)
|
||||
if !isString {
|
||||
c.errors.notAnOptionalFieldSelection(field.ID(), c.location(field), field)
|
||||
return
|
||||
}
|
||||
|
||||
// Perform type-checking using the field selection logic.
|
||||
resultType := c.checkSelectField(e, operand, fieldName, true)
|
||||
c.setType(e, substitute(c.mappings, resultType, false))
|
||||
c.setReference(e, ast.NewFunctionReference("select_optional_field"))
|
||||
}
|
||||
|
||||
func (c *checker) checkSelectField(e, operand ast.Expr, field string, optional bool) *types.Type {
|
||||
// Interpret as field selection, first traversing down the operand.
|
||||
c.check(operand)
|
||||
operandType := substitute(c.mappings, c.getType(operand), false)
|
||||
|
||||
// If the target type is 'optional', unwrap it for the sake of this check.
|
||||
targetType, isOpt := maybeUnwrapOptional(operandType)
|
||||
|
||||
// Assume error type by default as most types do not support field selection.
|
||||
resultType := types.ErrorType
|
||||
switch targetType.Kind() {
|
||||
case types.MapKind:
|
||||
// Maps yield their value type as the selection result type.
|
||||
resultType = targetType.Parameters()[1]
|
||||
case types.StructKind:
|
||||
// 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(e.ID(), messageType.TypeName(), field); found {
|
||||
resultType = fieldType
|
||||
}
|
||||
case types.TypeParamKind:
|
||||
// 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(types.DynType, targetType)
|
||||
// Also, set the result type to DYN.
|
||||
resultType = types.DynType
|
||||
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) {
|
||||
c.errors.typeDoesNotSupportFieldSelection(e.ID(), c.location(e), targetType)
|
||||
}
|
||||
resultType = types.DynType
|
||||
}
|
||||
|
||||
// If the target type was optional coming in, then the result must be optional going out.
|
||||
if isOpt || optional {
|
||||
return types.NewOptionalType(resultType)
|
||||
}
|
||||
return resultType
|
||||
}
|
||||
|
||||
func (c *checker) checkCall(e ast.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.AsCall()
|
||||
fnName := call.FunctionName()
|
||||
if fnName == operators.OptSelect {
|
||||
c.checkOptSelect(e)
|
||||
return
|
||||
}
|
||||
|
||||
args := call.Args()
|
||||
// Traverse arguments.
|
||||
for _, arg := range args {
|
||||
c.check(arg)
|
||||
}
|
||||
|
||||
// Regular static call with simple name.
|
||||
if !call.IsMemberFunction() {
|
||||
// Check for the existence of the function.
|
||||
fn := c.env.LookupFunction(fnName)
|
||||
if fn == nil {
|
||||
c.errors.undeclaredReference(e.ID(), c.location(e), c.env.container.Name(), fnName)
|
||||
c.setType(e, types.ErrorType)
|
||||
return
|
||||
}
|
||||
// Overwrite the function name with its fully qualified resolved name.
|
||||
e.SetKindCase(c.NewCall(e.ID(), fn.Name(), args...))
|
||||
// Check to see whether the overload resolves.
|
||||
c.resolveOverloadOrError(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.
|
||||
target := call.Target()
|
||||
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.
|
||||
e.SetKindCase(c.NewCall(e.ID(), fn.Name(), args...))
|
||||
c.resolveOverloadOrError(e, fn, nil, args)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Regular instance call.
|
||||
c.check(target)
|
||||
fn := c.env.LookupFunction(fnName)
|
||||
// Function found, attempt overload resolution.
|
||||
if fn != nil {
|
||||
c.resolveOverloadOrError(e, fn, target, args)
|
||||
return
|
||||
}
|
||||
// Function name not declared, record error.
|
||||
c.setType(e, types.ErrorType)
|
||||
c.errors.undeclaredReference(e.ID(), c.location(e), c.env.container.Name(), fnName)
|
||||
}
|
||||
|
||||
func (c *checker) resolveOverloadOrError(
|
||||
e ast.Expr, fn *decls.FunctionDecl, target ast.Expr, args []ast.Expr) {
|
||||
// Attempt to resolve the overload.
|
||||
resolution := c.resolveOverload(e, fn, target, args)
|
||||
// No such overload, error noted in the resolveOverload call, type recorded here.
|
||||
if resolution == nil {
|
||||
c.setType(e, types.ErrorType)
|
||||
return
|
||||
}
|
||||
// Overload found.
|
||||
c.setType(e, resolution.Type)
|
||||
c.setReference(e, resolution.Reference)
|
||||
}
|
||||
|
||||
func (c *checker) resolveOverload(
|
||||
call ast.Expr, fn *decls.FunctionDecl, target ast.Expr, args []ast.Expr) *overloadResolution {
|
||||
|
||||
var argTypes []*types.Type
|
||||
if target != nil {
|
||||
argTypes = append(argTypes, c.getType(target))
|
||||
}
|
||||
for _, arg := range args {
|
||||
argTypes = append(argTypes, c.getType(arg))
|
||||
}
|
||||
|
||||
var resultType *types.Type
|
||||
var checkedRef *ast.ReferenceInfo
|
||||
for _, overload := range fn.OverloadDecls() {
|
||||
// Determine whether the overload is currently considered.
|
||||
if c.env.isOverloadDisabled(overload.ID()) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure the call style for the overload matches.
|
||||
if (target == nil && overload.IsMemberFunction()) ||
|
||||
(target != nil && !overload.IsMemberFunction()) {
|
||||
// not a compatible call style.
|
||||
continue
|
||||
}
|
||||
|
||||
// Alternative type-checking behavior when the logical operators are compacted into
|
||||
// variadic AST representations.
|
||||
if fn.Name() == operators.LogicalAnd || fn.Name() == operators.LogicalOr {
|
||||
checkedRef = ast.NewFunctionReference(overload.ID())
|
||||
for i, argType := range argTypes {
|
||||
if !c.isAssignable(argType, types.BoolType) {
|
||||
c.errors.typeMismatch(
|
||||
args[i].ID(),
|
||||
c.locationByID(args[i].ID()),
|
||||
types.BoolType,
|
||||
argType)
|
||||
resultType = types.ErrorType
|
||||
}
|
||||
}
|
||||
if isError(resultType) {
|
||||
return nil
|
||||
}
|
||||
return newResolution(checkedRef, types.BoolType)
|
||||
}
|
||||
|
||||
overloadType := newFunctionType(overload.ResultType(), overload.ArgTypes()...)
|
||||
typeParams := overload.TypeParams()
|
||||
if len(typeParams) != 0 {
|
||||
// Instantiate overload's type with fresh type variables.
|
||||
substitutions := newMapping()
|
||||
for _, typePar := range typeParams {
|
||||
substitutions.add(types.NewTypeParamType(typePar), c.newTypeVar())
|
||||
}
|
||||
overloadType = substitute(substitutions, overloadType, false)
|
||||
}
|
||||
|
||||
candidateArgTypes := overloadType.Parameters()[1:]
|
||||
if c.isAssignableList(argTypes, candidateArgTypes) {
|
||||
if checkedRef == nil {
|
||||
checkedRef = ast.NewFunctionReference(overload.ID())
|
||||
} else {
|
||||
checkedRef.AddOverload(overload.ID())
|
||||
}
|
||||
|
||||
// First matching overload, determines result type.
|
||||
fnResultType := substitute(c.mappings, overloadType.Parameters()[0], false)
|
||||
if resultType == nil {
|
||||
resultType = fnResultType
|
||||
} else if !isDyn(resultType) && !fnResultType.IsExactType(resultType) {
|
||||
resultType = types.DynType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if resultType == nil {
|
||||
for i, argType := range argTypes {
|
||||
argTypes[i] = substitute(c.mappings, argType, true)
|
||||
}
|
||||
c.errors.noMatchingOverload(call.ID(), c.location(call), fn.Name(), argTypes, target != nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
return newResolution(checkedRef, resultType)
|
||||
}
|
||||
|
||||
func (c *checker) checkCreateList(e ast.Expr) {
|
||||
create := e.AsList()
|
||||
var elemsType *types.Type
|
||||
optionalIndices := create.OptionalIndices()
|
||||
optionals := make(map[int32]bool, len(optionalIndices))
|
||||
for _, optInd := range optionalIndices {
|
||||
optionals[optInd] = true
|
||||
}
|
||||
for i, e := range create.Elements() {
|
||||
c.check(e)
|
||||
elemType := c.getType(e)
|
||||
if optionals[int32(i)] {
|
||||
var isOptional bool
|
||||
elemType, isOptional = maybeUnwrapOptional(elemType)
|
||||
if !isOptional && !isDyn(elemType) {
|
||||
c.errors.typeMismatch(e.ID(), c.location(e), types.NewOptionalType(elemType), elemType)
|
||||
}
|
||||
}
|
||||
elemsType = c.joinTypes(e, elemsType, elemType)
|
||||
}
|
||||
if elemsType == nil {
|
||||
// If the list is empty, assign free type var to elem type.
|
||||
elemsType = c.newTypeVar()
|
||||
}
|
||||
c.setType(e, types.NewListType(elemsType))
|
||||
}
|
||||
|
||||
func (c *checker) checkCreateMap(e ast.Expr) {
|
||||
mapVal := e.AsMap()
|
||||
var mapKeyType *types.Type
|
||||
var mapValueType *types.Type
|
||||
for _, e := range mapVal.Entries() {
|
||||
entry := e.AsMapEntry()
|
||||
key := entry.Key()
|
||||
c.check(key)
|
||||
mapKeyType = c.joinTypes(key, mapKeyType, c.getType(key))
|
||||
|
||||
val := entry.Value()
|
||||
c.check(val)
|
||||
valType := c.getType(val)
|
||||
if entry.IsOptional() {
|
||||
var isOptional bool
|
||||
valType, isOptional = maybeUnwrapOptional(valType)
|
||||
if !isOptional && !isDyn(valType) {
|
||||
c.errors.typeMismatch(val.ID(), c.location(val), types.NewOptionalType(valType), valType)
|
||||
}
|
||||
}
|
||||
mapValueType = c.joinTypes(val, mapValueType, valType)
|
||||
}
|
||||
if mapKeyType == nil {
|
||||
// If the map is empty, assign free type variables to typeKey and value type.
|
||||
mapKeyType = c.newTypeVar()
|
||||
mapValueType = c.newTypeVar()
|
||||
}
|
||||
c.setType(e, types.NewMapType(mapKeyType, mapValueType))
|
||||
}
|
||||
|
||||
func (c *checker) checkCreateStruct(e ast.Expr) {
|
||||
msgVal := e.AsStruct()
|
||||
// Determine the type of the message.
|
||||
resultType := types.ErrorType
|
||||
ident := c.env.LookupIdent(msgVal.TypeName())
|
||||
if ident == nil {
|
||||
c.errors.undeclaredReference(
|
||||
e.ID(), c.location(e), c.env.container.Name(), msgVal.TypeName())
|
||||
c.setType(e, types.ErrorType)
|
||||
return
|
||||
}
|
||||
// Ensure the type name is fully qualified in the AST.
|
||||
typeName := ident.Name()
|
||||
if msgVal.TypeName() != typeName {
|
||||
e.SetKindCase(c.NewStruct(e.ID(), typeName, msgVal.Fields()))
|
||||
msgVal = e.AsStruct()
|
||||
}
|
||||
c.setReference(e, ast.NewIdentReference(typeName, nil))
|
||||
identKind := ident.Type().Kind()
|
||||
if identKind != types.ErrorKind {
|
||||
if identKind != types.TypeKind {
|
||||
c.errors.notAType(e.ID(), c.location(e), ident.Type().DeclaredTypeName())
|
||||
} else {
|
||||
resultType = ident.Type().Parameters()[0]
|
||||
// Backwards compatibility test between well-known types and message types
|
||||
// In this context, the type is being instantiated by its protobuf name which
|
||||
// is not ideal or recommended, but some users expect this to work.
|
||||
if isWellKnownType(resultType) {
|
||||
typeName = getWellKnownTypeName(resultType)
|
||||
} else if resultType.Kind() == types.StructKind {
|
||||
typeName = resultType.DeclaredTypeName()
|
||||
} else {
|
||||
c.errors.notAMessageType(e.ID(), c.location(e), resultType.DeclaredTypeName())
|
||||
resultType = types.ErrorType
|
||||
}
|
||||
}
|
||||
}
|
||||
c.setType(e, resultType)
|
||||
|
||||
// Check the field initializers.
|
||||
for _, f := range msgVal.Fields() {
|
||||
field := f.AsStructField()
|
||||
fieldName := field.Name()
|
||||
value := field.Value()
|
||||
c.check(value)
|
||||
|
||||
fieldType := types.ErrorType
|
||||
ft, found := c.lookupFieldType(f.ID(), typeName, fieldName)
|
||||
if found {
|
||||
fieldType = ft
|
||||
}
|
||||
|
||||
valType := c.getType(value)
|
||||
if field.IsOptional() {
|
||||
var isOptional bool
|
||||
valType, isOptional = maybeUnwrapOptional(valType)
|
||||
if !isOptional && !isDyn(valType) {
|
||||
c.errors.typeMismatch(value.ID(), c.location(value), types.NewOptionalType(valType), valType)
|
||||
}
|
||||
}
|
||||
if !c.isAssignable(fieldType, valType) {
|
||||
c.errors.fieldTypeMismatch(f.ID(), c.locationByID(f.ID()), fieldName, fieldType, valType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *checker) checkComprehension(e ast.Expr) {
|
||||
comp := e.AsComprehension()
|
||||
c.check(comp.IterRange())
|
||||
c.check(comp.AccuInit())
|
||||
rangeType := substitute(c.mappings, c.getType(comp.IterRange()), false)
|
||||
|
||||
// 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.
|
||||
accuType := c.getType(comp.AccuInit())
|
||||
c.env = c.env.enterScope()
|
||||
c.env.AddIdents(decls.NewVariable(comp.AccuVar(), accuType))
|
||||
|
||||
var varType, var2Type *types.Type
|
||||
switch rangeType.Kind() {
|
||||
case types.ListKind:
|
||||
// varType represents the list element type for one-variable comprehensions.
|
||||
varType = rangeType.Parameters()[0]
|
||||
if comp.HasIterVar2() {
|
||||
// varType represents the list index (int) for two-variable comprehensions,
|
||||
// and var2Type represents the list element type.
|
||||
var2Type = varType
|
||||
varType = types.IntType
|
||||
}
|
||||
case types.MapKind:
|
||||
// varType represents the map entry key for all comprehension types.
|
||||
varType = rangeType.Parameters()[0]
|
||||
if comp.HasIterVar2() {
|
||||
// var2Type represents the map entry value for two-variable comprehensions.
|
||||
var2Type = rangeType.Parameters()[1]
|
||||
}
|
||||
case types.DynKind, types.ErrorKind, types.TypeParamKind:
|
||||
// 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(types.DynType, rangeType)
|
||||
// Set the range iteration variable to type DYN as well.
|
||||
varType = types.DynType
|
||||
default:
|
||||
c.errors.notAComprehensionRange(comp.IterRange().ID(), c.location(comp.IterRange()), rangeType)
|
||||
varType = types.ErrorType
|
||||
}
|
||||
|
||||
// Create a block scope for the loop.
|
||||
c.env = c.env.enterScope()
|
||||
c.env.AddIdents(decls.NewVariable(comp.IterVar(), varType))
|
||||
if comp.HasIterVar2() {
|
||||
c.env.AddIdents(decls.NewVariable(comp.IterVar2(), var2Type))
|
||||
}
|
||||
// Check the variable references in the condition and step.
|
||||
c.check(comp.LoopCondition())
|
||||
c.assertType(comp.LoopCondition(), types.BoolType)
|
||||
c.check(comp.LoopStep())
|
||||
c.assertType(comp.LoopStep(), accuType)
|
||||
// Exit the loop's block scope before checking the result.
|
||||
c.env = c.env.exitScope()
|
||||
c.check(comp.Result())
|
||||
// Exit the comprehension scope.
|
||||
c.env = c.env.exitScope()
|
||||
c.setType(e, substitute(c.mappings, c.getType(comp.Result()), false))
|
||||
}
|
||||
|
||||
// Checks compatibility of joined types, and returns the most general common type.
|
||||
func (c *checker) joinTypes(e ast.Expr, previous, current *types.Type) *types.Type {
|
||||
if previous == nil {
|
||||
return current
|
||||
}
|
||||
if c.isAssignable(previous, current) {
|
||||
return mostGeneral(previous, current)
|
||||
}
|
||||
if c.dynAggregateLiteralElementTypesEnabled() {
|
||||
return types.DynType
|
||||
}
|
||||
c.errors.typeMismatch(e.ID(), c.location(e), previous, current)
|
||||
return types.ErrorType
|
||||
}
|
||||
|
||||
func (c *checker) dynAggregateLiteralElementTypesEnabled() bool {
|
||||
return c.env.aggLitElemType == dynElementType
|
||||
}
|
||||
|
||||
func (c *checker) newTypeVar() *types.Type {
|
||||
id := c.freeTypeVarCounter
|
||||
c.freeTypeVarCounter++
|
||||
return types.NewTypeParamType(fmt.Sprintf("_var%d", id))
|
||||
}
|
||||
|
||||
func (c *checker) isAssignable(t1, t2 *types.Type) bool {
|
||||
subs := isAssignable(c.mappings, t1, t2)
|
||||
if subs != nil {
|
||||
c.mappings = subs
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *checker) isAssignableList(l1, l2 []*types.Type) bool {
|
||||
subs := isAssignableList(c.mappings, l1, l2)
|
||||
if subs != nil {
|
||||
c.mappings = subs
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func maybeUnwrapString(e ast.Expr) (string, bool) {
|
||||
switch e.Kind() {
|
||||
case ast.LiteralKind:
|
||||
literal := e.AsLiteral()
|
||||
switch v := literal.(type) {
|
||||
case types.String:
|
||||
return string(v), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (c *checker) setType(e ast.Expr, t *types.Type) {
|
||||
if old, found := c.TypeMap()[e.ID()]; found && !old.IsExactType(t) {
|
||||
c.errors.incompatibleType(e.ID(), c.location(e), e, old, t)
|
||||
return
|
||||
}
|
||||
c.SetType(e.ID(), t)
|
||||
}
|
||||
|
||||
func (c *checker) getType(e ast.Expr) *types.Type {
|
||||
return c.TypeMap()[e.ID()]
|
||||
}
|
||||
|
||||
func (c *checker) setReference(e ast.Expr, r *ast.ReferenceInfo) {
|
||||
if old, found := c.ReferenceMap()[e.ID()]; found && !old.Equals(r) {
|
||||
c.errors.referenceRedefinition(e.ID(), c.location(e), e, old, r)
|
||||
return
|
||||
}
|
||||
c.SetReference(e.ID(), r)
|
||||
}
|
||||
|
||||
func (c *checker) assertType(e ast.Expr, t *types.Type) {
|
||||
if !c.isAssignable(t, c.getType(e)) {
|
||||
c.errors.typeMismatch(e.ID(), c.location(e), t, c.getType(e))
|
||||
}
|
||||
}
|
||||
|
||||
type overloadResolution struct {
|
||||
Type *types.Type
|
||||
Reference *ast.ReferenceInfo
|
||||
}
|
||||
|
||||
func newResolution(r *ast.ReferenceInfo, t *types.Type) *overloadResolution {
|
||||
return &overloadResolution{
|
||||
Reference: r,
|
||||
Type: t,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *checker) location(e ast.Expr) common.Location {
|
||||
return c.locationByID(e.ID())
|
||||
}
|
||||
|
||||
func (c *checker) locationByID(id int64) common.Location {
|
||||
return c.SourceInfo().GetStartLocation(id)
|
||||
}
|
||||
|
||||
func (c *checker) lookupFieldType(exprID int64, structType, fieldName string) (*types.Type, bool) {
|
||||
if _, found := c.env.provider.FindStructType(structType); !found {
|
||||
// This should not happen, anyway, report an error.
|
||||
c.errors.unexpectedFailedResolution(exprID, c.locationByID(exprID), structType)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if ft, found := c.env.provider.FindStructFieldType(structType, fieldName); found {
|
||||
return ft.Type, found
|
||||
}
|
||||
|
||||
c.errors.undefinedField(exprID, c.locationByID(exprID), fieldName)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func isWellKnownType(t *types.Type) bool {
|
||||
switch t.Kind() {
|
||||
case types.AnyKind, types.TimestampKind, types.DurationKind, types.DynKind, types.NullTypeKind:
|
||||
return true
|
||||
case types.BoolKind, types.BytesKind, types.DoubleKind, types.IntKind, types.StringKind, types.UintKind:
|
||||
return t.IsAssignableType(types.NullType)
|
||||
case types.ListKind:
|
||||
return t.Parameters()[0] == types.DynType
|
||||
case types.MapKind:
|
||||
return t.Parameters()[0] == types.StringType && t.Parameters()[1] == types.DynType
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getWellKnownTypeName(t *types.Type) string {
|
||||
if name, found := wellKnownTypes[t.Kind()]; found {
|
||||
return name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var (
|
||||
wellKnownTypes = map[types.Kind]string{
|
||||
types.AnyKind: "google.protobuf.Any",
|
||||
types.BoolKind: "google.protobuf.BoolValue",
|
||||
types.BytesKind: "google.protobuf.BytesValue",
|
||||
types.DoubleKind: "google.protobuf.DoubleValue",
|
||||
types.DurationKind: "google.protobuf.Duration",
|
||||
types.DynKind: "google.protobuf.Value",
|
||||
types.IntKind: "google.protobuf.Int64Value",
|
||||
types.ListKind: "google.protobuf.ListValue",
|
||||
types.NullTypeKind: "google.protobuf.NullValue",
|
||||
types.MapKind: "google.protobuf.Struct",
|
||||
types.StringKind: "google.protobuf.StringValue",
|
||||
types.TimestampKind: "google.protobuf.Timestamp",
|
||||
types.UintKind: "google.protobuf.UInt64Value",
|
||||
}
|
||||
)
|
705
e2e/vendor/github.com/google/cel-go/checker/cost.go
generated
vendored
Normal file
705
e2e/vendor/github.com/google/cel-go/checker/cost.go
generated
vendored
Normal file
@ -0,0 +1,705 @@
|
||||
// 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/ast"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/parser"
|
||||
)
|
||||
|
||||
// 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() *types.Type
|
||||
// Expr returns the expression of the AstNode.
|
||||
Expr() ast.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 *types.Type
|
||||
expr ast.Expr
|
||||
derivedSize *SizeEstimate
|
||||
}
|
||||
|
||||
func (e astNode) Path() []string {
|
||||
return e.path
|
||||
}
|
||||
|
||||
func (e astNode) Type() *types.Type {
|
||||
return e.t
|
||||
}
|
||||
|
||||
func (e astNode) Expr() ast.Expr {
|
||||
return e.expr
|
||||
}
|
||||
|
||||
func (e astNode) ComputedSize() *SizeEstimate {
|
||||
if e.derivedSize != nil {
|
||||
return e.derivedSize
|
||||
}
|
||||
var v uint64
|
||||
switch e.expr.Kind() {
|
||||
case ast.LiteralKind:
|
||||
switch ck := e.expr.AsLiteral().(type) {
|
||||
case types.String:
|
||||
// converting to runes here is an O(n) operation, but
|
||||
// this is consistent with how size is computed at runtime,
|
||||
// and how the language definition defines string size
|
||||
v = uint64(len([]rune(ck)))
|
||||
case types.Bytes:
|
||||
v = uint64(len(ck))
|
||||
case types.Bool, types.Double, types.Duration,
|
||||
types.Int, types.Timestamp, types.Uint,
|
||||
types.Null:
|
||||
v = uint64(1)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
case ast.ListKind:
|
||||
v = uint64(e.expr.AsList().Size())
|
||||
case ast.MapKind:
|
||||
v = uint64(e.expr.AsMap().Size())
|
||||
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 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
|
||||
}
|
||||
ceil := math.Ceil(xFloat * y)
|
||||
if ceil >= doubleTwoTo64 {
|
||||
return math.MaxUint64
|
||||
}
|
||||
return uint64(ceil)
|
||||
}
|
||||
|
||||
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
|
||||
checkedAST *ast.AST
|
||||
estimator CostEstimator
|
||||
overloadEstimators map[string]FunctionEstimator
|
||||
// presenceTestCost will either be a zero or one based on whether has() macros count against cost computations.
|
||||
presenceTestCost CostEstimate
|
||||
}
|
||||
|
||||
// Use a stack of iterVar -> iterRange Expr Ids to handle shadowed variable names.
|
||||
type iterRangeScopes map[string][]int64
|
||||
|
||||
func (vs iterRangeScopes) push(varName string, expr ast.Expr) {
|
||||
vs[varName] = append(vs[varName], expr.ID())
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// CostOption configures flags which affect cost computations.
|
||||
type CostOption func(*coster) error
|
||||
|
||||
// PresenceTestHasCost determines whether presence testing has a cost of one or zero.
|
||||
//
|
||||
// Defaults to presence test has a cost of one.
|
||||
func PresenceTestHasCost(hasCost bool) CostOption {
|
||||
return func(c *coster) error {
|
||||
if hasCost {
|
||||
c.presenceTestCost = selectAndIdentCost
|
||||
return nil
|
||||
}
|
||||
c.presenceTestCost = CostEstimate{Min: 0, Max: 0}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// FunctionEstimator provides a CallEstimate given the target and arguments for a specific function, overload pair.
|
||||
type FunctionEstimator func(estimator CostEstimator, target *AstNode, args []AstNode) *CallEstimate
|
||||
|
||||
// OverloadCostEstimate binds a FunctionCoster to a specific function overload ID.
|
||||
//
|
||||
// When a OverloadCostEstimate is provided, it will override the cost calculation of the CostEstimator provided to
|
||||
// the Cost() call.
|
||||
func OverloadCostEstimate(overloadID string, functionCoster FunctionEstimator) CostOption {
|
||||
return func(c *coster) error {
|
||||
c.overloadEstimators[overloadID] = functionCoster
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Cost estimates the cost of the parsed and type checked CEL expression.
|
||||
func Cost(checked *ast.AST, estimator CostEstimator, opts ...CostOption) (CostEstimate, error) {
|
||||
c := &coster{
|
||||
checkedAST: checked,
|
||||
estimator: estimator,
|
||||
overloadEstimators: map[string]FunctionEstimator{},
|
||||
exprPath: map[int64][]string{},
|
||||
iterRanges: map[string][]int64{},
|
||||
computedSizes: map[int64]SizeEstimate{},
|
||||
presenceTestCost: CostEstimate{Min: 1, Max: 1},
|
||||
}
|
||||
for _, opt := range opts {
|
||||
err := opt(c)
|
||||
if err != nil {
|
||||
return CostEstimate{}, err
|
||||
}
|
||||
}
|
||||
return c.cost(checked.Expr()), nil
|
||||
}
|
||||
|
||||
func (c *coster) cost(e ast.Expr) CostEstimate {
|
||||
if e == nil {
|
||||
return CostEstimate{}
|
||||
}
|
||||
var cost CostEstimate
|
||||
switch e.Kind() {
|
||||
case ast.LiteralKind:
|
||||
cost = constCost
|
||||
case ast.IdentKind:
|
||||
cost = c.costIdent(e)
|
||||
case ast.SelectKind:
|
||||
cost = c.costSelect(e)
|
||||
case ast.CallKind:
|
||||
cost = c.costCall(e)
|
||||
case ast.ListKind:
|
||||
cost = c.costCreateList(e)
|
||||
case ast.MapKind:
|
||||
cost = c.costCreateMap(e)
|
||||
case ast.StructKind:
|
||||
cost = c.costCreateStruct(e)
|
||||
case ast.ComprehensionKind:
|
||||
cost = c.costComprehension(e)
|
||||
default:
|
||||
return CostEstimate{}
|
||||
}
|
||||
return cost
|
||||
}
|
||||
|
||||
func (c *coster) costIdent(e ast.Expr) CostEstimate {
|
||||
identName := e.AsIdent()
|
||||
// build and track the field path
|
||||
if iterRange, ok := c.iterRanges.peek(identName); ok {
|
||||
switch c.checkedAST.GetType(iterRange).Kind() {
|
||||
case types.ListKind:
|
||||
c.addPath(e, append(c.exprPath[iterRange], "@items"))
|
||||
case types.MapKind:
|
||||
c.addPath(e, append(c.exprPath[iterRange], "@keys"))
|
||||
}
|
||||
} else {
|
||||
c.addPath(e, []string{identName})
|
||||
}
|
||||
|
||||
return selectAndIdentCost
|
||||
}
|
||||
|
||||
func (c *coster) costSelect(e ast.Expr) CostEstimate {
|
||||
sel := e.AsSelect()
|
||||
var sum CostEstimate
|
||||
if sel.IsTestOnly() {
|
||||
// recurse, but do not add any cost
|
||||
// this is equivalent to how evalTestOnly increments the runtime cost counter
|
||||
// but does not add any additional cost for the qualifier, except here we do
|
||||
// the reverse (ident adds cost)
|
||||
sum = sum.Add(c.presenceTestCost)
|
||||
sum = sum.Add(c.cost(sel.Operand()))
|
||||
return sum
|
||||
}
|
||||
sum = sum.Add(c.cost(sel.Operand()))
|
||||
targetType := c.getType(sel.Operand())
|
||||
switch targetType.Kind() {
|
||||
case types.MapKind, types.StructKind, types.TypeParamKind:
|
||||
sum = sum.Add(selectAndIdentCost)
|
||||
}
|
||||
|
||||
// build and track the field path
|
||||
c.addPath(e, append(c.getPath(sel.Operand()), sel.FieldName()))
|
||||
|
||||
return sum
|
||||
}
|
||||
|
||||
func (c *coster) costCall(e ast.Expr) CostEstimate {
|
||||
call := e.AsCall()
|
||||
args := call.Args()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
overloadIDs := c.checkedAST.GetOverloadIDs(e.ID())
|
||||
if len(overloadIDs) == 0 {
|
||||
return CostEstimate{}
|
||||
}
|
||||
var targetType AstNode
|
||||
if call.IsMemberFunction() {
|
||||
sum = sum.Add(c.cost(call.Target()))
|
||||
targetType = c.newAstNode(call.Target())
|
||||
}
|
||||
// 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 overloadIDs {
|
||||
overloadCost := c.functionCost(call.FunctionName(), 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.ID()] = *resultSize
|
||||
}
|
||||
return sum.Add(fnCost)
|
||||
}
|
||||
|
||||
func (c *coster) costCreateList(e ast.Expr) CostEstimate {
|
||||
create := e.AsList()
|
||||
var sum CostEstimate
|
||||
for _, e := range create.Elements() {
|
||||
sum = sum.Add(c.cost(e))
|
||||
}
|
||||
return sum.Add(createListBaseCost)
|
||||
}
|
||||
|
||||
func (c *coster) costCreateMap(e ast.Expr) CostEstimate {
|
||||
mapVal := e.AsMap()
|
||||
var sum CostEstimate
|
||||
for _, ent := range mapVal.Entries() {
|
||||
entry := ent.AsMapEntry()
|
||||
sum = sum.Add(c.cost(entry.Key()))
|
||||
sum = sum.Add(c.cost(entry.Value()))
|
||||
}
|
||||
return sum.Add(createMapBaseCost)
|
||||
}
|
||||
|
||||
func (c *coster) costCreateStruct(e ast.Expr) CostEstimate {
|
||||
msgVal := e.AsStruct()
|
||||
var sum CostEstimate
|
||||
for _, ent := range msgVal.Fields() {
|
||||
field := ent.AsStructField()
|
||||
sum = sum.Add(c.cost(field.Value()))
|
||||
}
|
||||
return sum.Add(createMessageBaseCost)
|
||||
}
|
||||
|
||||
func (c *coster) costComprehension(e ast.Expr) CostEstimate {
|
||||
comp := e.AsComprehension()
|
||||
var sum CostEstimate
|
||||
sum = sum.Add(c.cost(comp.IterRange()))
|
||||
sum = sum.Add(c.cost(comp.AccuInit()))
|
||||
|
||||
// Track the iterRange of each IterVar for field path construction
|
||||
c.iterRanges.push(comp.IterVar(), comp.IterRange())
|
||||
loopCost := c.cost(comp.LoopCondition())
|
||||
stepCost := c.cost(comp.LoopStep())
|
||||
c.iterRanges.pop(comp.IterVar())
|
||||
sum = sum.Add(c.cost(comp.Result()))
|
||||
rangeCnt := c.sizeEstimate(c.newAstNode(comp.IterRange()))
|
||||
|
||||
c.computedSizes[e.ID()] = rangeCnt
|
||||
|
||||
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 len(c.overloadEstimators) != 0 {
|
||||
if estimator, found := c.overloadEstimators[overloadID]; found {
|
||||
if est := estimator(c.estimator, target, args); est != nil {
|
||||
callEst := *est
|
||||
return CallEstimate{CostEstimate: callEst.Add(argCostSum()), ResultSize: est.ResultSize}
|
||||
}
|
||||
}
|
||||
}
|
||||
if est := c.estimator.EstimateCallCost(function, overloadID, target, args); est != nil {
|
||||
callEst := *est
|
||||
return CallEstimate{CostEstimate: callEst.Add(argCostSum()), ResultSize: est.ResultSize}
|
||||
}
|
||||
switch overloadID {
|
||||
// O(n) functions
|
||||
case overloads.ExtFormatString:
|
||||
if target != nil {
|
||||
// ResultSize not calculated because we can't bound the max size.
|
||||
return CallEstimate{CostEstimate: c.sizeEstimate(*target).MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum())}
|
||||
}
|
||||
case overloads.StringToBytes:
|
||||
if len(args) == 1 {
|
||||
sz := c.sizeEstimate(args[0])
|
||||
// ResultSize max is when each char converts to 4 bytes.
|
||||
return CallEstimate{CostEstimate: sz.MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum()), ResultSize: &SizeEstimate{Min: sz.Min, Max: sz.Max * 4}}
|
||||
}
|
||||
case overloads.BytesToString:
|
||||
if len(args) == 1 {
|
||||
sz := c.sizeEstimate(args[0])
|
||||
// ResultSize min is when 4 bytes convert to 1 char.
|
||||
return CallEstimate{CostEstimate: sz.MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum()), ResultSize: &SizeEstimate{Min: sz.Min / 4, Max: sz.Max}}
|
||||
}
|
||||
case overloads.ExtQuoteString:
|
||||
if len(args) == 1 {
|
||||
sz := c.sizeEstimate(args[0])
|
||||
// ResultSize max is when each char is escaped. 2 quote chars always added.
|
||||
return CallEstimate{CostEstimate: sz.MultiplyByCostFactor(common.StringTraversalCostFactor).Add(argCostSum()), ResultSize: &SizeEstimate{Min: sz.Min + 2, Max: sz.Max*2 + 2}}
|
||||
}
|
||||
case overloads.StartsWithString, overloads.EndsWithString:
|
||||
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 ast.Expr) *types.Type {
|
||||
return c.checkedAST.GetType(e.ID())
|
||||
}
|
||||
|
||||
func (c *coster) getPath(e ast.Expr) []string {
|
||||
return c.exprPath[e.ID()]
|
||||
}
|
||||
|
||||
func (c *coster) addPath(e ast.Expr, path []string) {
|
||||
c.exprPath[e.ID()] = path
|
||||
}
|
||||
|
||||
func (c *coster) newAstNode(e ast.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.ID()]; 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 *types.Type) bool {
|
||||
switch t.Kind() {
|
||||
case types.BoolKind, types.DoubleKind, types.DurationKind, types.IntKind, types.TimestampKind, types.UintKind:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
doubleTwoTo64 = math.Ldexp(1.0, 64)
|
||||
)
|
19
e2e/vendor/github.com/google/cel-go/checker/decls/BUILD.bazel
generated
vendored
Normal file
19
e2e/vendor/github.com/google/cel-go/checker/decls/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
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",
|
||||
],
|
||||
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",
|
||||
],
|
||||
)
|
237
e2e/vendor/github.com/google/cel-go/checker/decls/decls.go
generated
vendored
Normal file
237
e2e/vendor/github.com/google/cel-go/checker/decls/decls.go
generated
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
// 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 (
|
||||
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 (
|
||||
// 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}}}
|
||||
}
|
||||
|
||||
// NewOptionalType constructs an abstract type indicating that the parameterized type
|
||||
// may be contained within the object.
|
||||
func NewOptionalType(paramType *exprpb.Type) *exprpb.Type {
|
||||
return NewAbstractType("optional_type", paramType)
|
||||
}
|
||||
|
||||
// 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}}
|
||||
}
|
284
e2e/vendor/github.com/google/cel-go/checker/env.go
generated
vendored
Normal file
284
e2e/vendor/github.com/google/cel-go/checker/env.go
generated
vendored
Normal file
@ -0,0 +1,284 @@
|
||||
// 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/common/containers"
|
||||
"github.com/google/cel-go/common/decls"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/parser"
|
||||
)
|
||||
|
||||
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 types.Provider
|
||||
declarations *Scopes
|
||||
aggLitElemType aggregateLiteralElementType
|
||||
filteredOverloadIDs map[string]struct{}
|
||||
}
|
||||
|
||||
// NewEnv returns a new *Env with the given parameters.
|
||||
func NewEnv(container *containers.Container, provider types.Provider, opts ...Option) (*Env, error) {
|
||||
declarations := 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
|
||||
}
|
||||
|
||||
// AddIdents configures the checker with a list of variable declarations.
|
||||
//
|
||||
// If there are overlapping declarations, the method will error.
|
||||
func (e *Env) AddIdents(declarations ...*decls.VariableDecl) error {
|
||||
errMsgs := make([]errorMsg, 0)
|
||||
for _, d := range declarations {
|
||||
errMsgs = append(errMsgs, e.addIdent(d))
|
||||
}
|
||||
return formatError(errMsgs)
|
||||
}
|
||||
|
||||
// AddFunctions configures the checker with a list of function declarations.
|
||||
//
|
||||
// If there are overlapping declarations, the method will error.
|
||||
func (e *Env) AddFunctions(declarations ...*decls.FunctionDecl) error {
|
||||
errMsgs := make([]errorMsg, 0)
|
||||
for _, d := range declarations {
|
||||
errMsgs = append(errMsgs, e.setFunction(d)...)
|
||||
}
|
||||
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) *decls.VariableDecl {
|
||||
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.FindStructType(candidate); found {
|
||||
decl := decls.NewVariable(candidate, t)
|
||||
e.declarations.AddIdent(decl)
|
||||
return decl
|
||||
}
|
||||
|
||||
if i, found := e.provider.FindIdent(candidate); found {
|
||||
if t, ok := i.(*types.Type); ok {
|
||||
decl := decls.NewVariable(candidate, types.NewTypeTypeWithParam(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.NewConstant(candidate, types.IntType, enumValue)
|
||||
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) *decls.FunctionDecl {
|
||||
for _, candidate := range e.container.ResolveCandidateNames(name) {
|
||||
if fn := e.declarations.FindFunction(candidate); fn != nil {
|
||||
return fn
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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(fn *decls.FunctionDecl) []errorMsg {
|
||||
errMsgs := make([]errorMsg, 0)
|
||||
current := e.declarations.FindFunction(fn.Name())
|
||||
if current != nil {
|
||||
var err error
|
||||
current, err = current.Merge(fn)
|
||||
if err != nil {
|
||||
return append(errMsgs, errorMsg(err.Error()))
|
||||
}
|
||||
} else {
|
||||
current = fn
|
||||
}
|
||||
for _, overload := range current.OverloadDecls() {
|
||||
for _, macro := range parser.AllMacros {
|
||||
if macro.Function() == current.Name() &&
|
||||
macro.IsReceiverStyle() == overload.IsMemberFunction() &&
|
||||
macro.ArgCount() == len(overload.ArgTypes()) {
|
||||
errMsgs = append(errMsgs, overlappingMacroError(current.Name(), macro.ArgCount()))
|
||||
}
|
||||
}
|
||||
if len(errMsgs) > 0 {
|
||||
return errMsgs
|
||||
}
|
||||
}
|
||||
e.declarations.SetFunction(current)
|
||||
return errMsgs
|
||||
}
|
||||
|
||||
// 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 *decls.VariableDecl) errorMsg {
|
||||
current := e.declarations.FindIdentInScope(decl.Name())
|
||||
if current != nil {
|
||||
if current.DeclarationIsEquivalent(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
|
||||
}
|
||||
|
||||
// validatedDeclarations returns a reference to the validated variable and function declaration scope stack.
|
||||
// must be copied before use.
|
||||
func (e *Env) validatedDeclarations() *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 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
|
||||
}
|
88
e2e/vendor/github.com/google/cel-go/checker/errors.go
generated
vendored
Normal file
88
e2e/vendor/github.com/google/cel-go/checker/errors.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
// 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"
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/types"
|
||||
)
|
||||
|
||||
// typeErrors is a specialization of Errors.
|
||||
type typeErrors struct {
|
||||
errs *common.Errors
|
||||
}
|
||||
|
||||
func (e *typeErrors) fieldTypeMismatch(id int64, l common.Location, name string, field, value *types.Type) {
|
||||
e.errs.ReportErrorAtID(id, l, "expected type of field '%s' is '%s' but provided type is '%s'",
|
||||
name, FormatCELType(field), FormatCELType(value))
|
||||
}
|
||||
|
||||
func (e *typeErrors) incompatibleType(id int64, l common.Location, ex ast.Expr, prev, next *types.Type) {
|
||||
e.errs.ReportErrorAtID(id, l,
|
||||
"incompatible type already exists for expression: %v(%d) old:%v, new:%v", ex, ex.ID(), prev, next)
|
||||
}
|
||||
|
||||
func (e *typeErrors) noMatchingOverload(id int64, l common.Location, name string, args []*types.Type, isInstance bool) {
|
||||
signature := formatFunctionDeclType(nil, args, isInstance)
|
||||
e.errs.ReportErrorAtID(id, l, "found no matching overload for '%s' applied to '%s'", name, signature)
|
||||
}
|
||||
|
||||
func (e *typeErrors) notAComprehensionRange(id int64, l common.Location, t *types.Type) {
|
||||
e.errs.ReportErrorAtID(id, l, "expression of type '%s' cannot be range of a comprehension (must be list, map, or dynamic)",
|
||||
FormatCELType(t))
|
||||
}
|
||||
|
||||
func (e *typeErrors) notAnOptionalFieldSelection(id int64, l common.Location, field ast.Expr) {
|
||||
e.errs.ReportErrorAtID(id, l, "unsupported optional field selection: %v", field)
|
||||
}
|
||||
|
||||
func (e *typeErrors) notAType(id int64, l common.Location, typeName string) {
|
||||
e.errs.ReportErrorAtID(id, l, "'%s' is not a type", typeName)
|
||||
}
|
||||
|
||||
func (e *typeErrors) notAMessageType(id int64, l common.Location, typeName string) {
|
||||
e.errs.ReportErrorAtID(id, l, "'%s' is not a message type", typeName)
|
||||
}
|
||||
|
||||
func (e *typeErrors) referenceRedefinition(id int64, l common.Location, ex ast.Expr, prev, next *ast.ReferenceInfo) {
|
||||
e.errs.ReportErrorAtID(id, l,
|
||||
"reference already exists for expression: %v(%d) old:%v, new:%v", ex, ex.ID(), prev, next)
|
||||
}
|
||||
|
||||
func (e *typeErrors) typeDoesNotSupportFieldSelection(id int64, l common.Location, t *types.Type) {
|
||||
e.errs.ReportErrorAtID(id, l, "type '%s' does not support field selection", FormatCELType(t))
|
||||
}
|
||||
|
||||
func (e *typeErrors) typeMismatch(id int64, l common.Location, expected, actual *types.Type) {
|
||||
e.errs.ReportErrorAtID(id, l, "expected type '%s' but found '%s'",
|
||||
FormatCELType(expected), FormatCELType(actual))
|
||||
}
|
||||
|
||||
func (e *typeErrors) undefinedField(id int64, l common.Location, field string) {
|
||||
e.errs.ReportErrorAtID(id, l, "undefined field '%s'", field)
|
||||
}
|
||||
|
||||
func (e *typeErrors) undeclaredReference(id int64, l common.Location, container string, name string) {
|
||||
e.errs.ReportErrorAtID(id, l, "undeclared reference to '%s' (in container '%s')", name, container)
|
||||
}
|
||||
|
||||
func (e *typeErrors) unexpectedFailedResolution(id int64, l common.Location, typeName string) {
|
||||
e.errs.ReportErrorAtID(id, l, "unexpected failed resolution of '%s'", typeName)
|
||||
}
|
||||
|
||||
func (e *typeErrors) unexpectedASTType(id int64, l common.Location, kind, typeName string) {
|
||||
e.errs.ReportErrorAtID(id, l, "unexpected %s type: %v", kind, typeName)
|
||||
}
|
216
e2e/vendor/github.com/google/cel-go/checker/format.go
generated
vendored
Normal file
216
e2e/vendor/github.com/google/cel-go/checker/format.go
generated
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
chkdecls "github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common/types"
|
||||
|
||||
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 formatFunctionExprType(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 || t.GetType().GetTypeKind() == 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(chkdecls.NewPrimitiveType(t.GetWrapper())))
|
||||
case kindError:
|
||||
return "!error!"
|
||||
case kindTypeParam:
|
||||
return t.GetTypeParam()
|
||||
case kindAbstract:
|
||||
at := t.GetAbstractType()
|
||||
params := at.GetParameterTypes()
|
||||
paramStrs := make([]string, len(params))
|
||||
for i, p := range params {
|
||||
paramStrs[i] = FormatCheckedType(p)
|
||||
}
|
||||
return fmt.Sprintf("%s(%s)", at.GetName(), strings.Join(paramStrs, ", "))
|
||||
}
|
||||
return t.String()
|
||||
}
|
||||
|
||||
type formatter func(any) string
|
||||
|
||||
// FormatCELType formats a types.Type value to a string representation.
|
||||
//
|
||||
// The type formatting is identical to FormatCheckedType.
|
||||
func FormatCELType(t any) string {
|
||||
dt := t.(*types.Type)
|
||||
switch dt.Kind() {
|
||||
case types.AnyKind:
|
||||
return "any"
|
||||
case types.DurationKind:
|
||||
return "duration"
|
||||
case types.ErrorKind:
|
||||
return "!error!"
|
||||
case types.NullTypeKind:
|
||||
return "null"
|
||||
case types.TimestampKind:
|
||||
return "timestamp"
|
||||
case types.TypeParamKind:
|
||||
return dt.TypeName()
|
||||
case types.OpaqueKind:
|
||||
if dt.TypeName() == "function" {
|
||||
// There is no explicit function type in the new types representation, so information like
|
||||
// whether the function is a member function is absent.
|
||||
return formatFunctionDeclType(dt.Parameters()[0], dt.Parameters()[1:], false)
|
||||
}
|
||||
case types.UnspecifiedKind:
|
||||
return ""
|
||||
}
|
||||
if len(dt.Parameters()) == 0 {
|
||||
return dt.DeclaredTypeName()
|
||||
}
|
||||
paramTypeNames := make([]string, 0, len(dt.Parameters()))
|
||||
for _, p := range dt.Parameters() {
|
||||
paramTypeNames = append(paramTypeNames, FormatCELType(p))
|
||||
}
|
||||
return fmt.Sprintf("%s(%s)", dt.TypeName(), strings.Join(paramTypeNames, ", "))
|
||||
}
|
||||
|
||||
func formatExprType(t any) string {
|
||||
if t == nil {
|
||||
return ""
|
||||
}
|
||||
return FormatCheckedType(t.(*exprpb.Type))
|
||||
}
|
||||
|
||||
func formatFunctionExprType(resultType *exprpb.Type, argTypes []*exprpb.Type, isInstance bool) string {
|
||||
return formatFunctionInternal[*exprpb.Type](resultType, argTypes, isInstance, formatExprType)
|
||||
}
|
||||
|
||||
func formatFunctionDeclType(resultType *types.Type, argTypes []*types.Type, isInstance bool) string {
|
||||
return formatFunctionInternal[*types.Type](resultType, argTypes, isInstance, FormatCELType)
|
||||
}
|
||||
|
||||
func formatFunctionInternal[T any](resultType T, argTypes []T, isInstance bool, format formatter) string {
|
||||
result := ""
|
||||
if isInstance {
|
||||
target := argTypes[0]
|
||||
argTypes = argTypes[1:]
|
||||
result += format(target)
|
||||
result += "."
|
||||
}
|
||||
result += "("
|
||||
for i, arg := range argTypes {
|
||||
if i > 0 {
|
||||
result += ", "
|
||||
}
|
||||
result += format(arg)
|
||||
}
|
||||
result += ")"
|
||||
rt := format(resultType)
|
||||
if rt != "" {
|
||||
result += " -> "
|
||||
result += rt
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
49
e2e/vendor/github.com/google/cel-go/checker/mapping.go
generated
vendored
Normal file
49
e2e/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 (
|
||||
"github.com/google/cel-go/common/types"
|
||||
)
|
||||
|
||||
type mapping struct {
|
||||
mapping map[string]*types.Type
|
||||
}
|
||||
|
||||
func newMapping() *mapping {
|
||||
return &mapping{
|
||||
mapping: make(map[string]*types.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mapping) add(from, to *types.Type) {
|
||||
m.mapping[FormatCELType(from)] = to
|
||||
}
|
||||
|
||||
func (m *mapping) find(from *types.Type) (*types.Type, bool) {
|
||||
if r, found := m.mapping[FormatCELType(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
|
||||
}
|
42
e2e/vendor/github.com/google/cel-go/checker/options.go
generated
vendored
Normal file
42
e2e/vendor/github.com/google/cel-go/checker/options.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
// 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
|
||||
|
||||
type options struct {
|
||||
crossTypeNumericComparisons bool
|
||||
homogeneousAggregateLiterals bool
|
||||
validatedDeclarations *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
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
74
e2e/vendor/github.com/google/cel-go/checker/printer.go
generated
vendored
Normal file
74
e2e/vendor/github.com/google/cel-go/checker/printer.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2018 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/debug"
|
||||
)
|
||||
|
||||
type semanticAdorner struct {
|
||||
checked *ast.AST
|
||||
}
|
||||
|
||||
var _ debug.Adorner = &semanticAdorner{}
|
||||
|
||||
func (a *semanticAdorner) GetMetadata(elem any) string {
|
||||
result := ""
|
||||
e, isExpr := elem.(ast.Expr)
|
||||
if !isExpr {
|
||||
return result
|
||||
}
|
||||
t := a.checked.TypeMap()[e.ID()]
|
||||
if t != nil {
|
||||
result += "~"
|
||||
result += FormatCELType(t)
|
||||
}
|
||||
|
||||
switch e.Kind() {
|
||||
case ast.IdentKind,
|
||||
ast.CallKind,
|
||||
ast.ListKind,
|
||||
ast.StructKind,
|
||||
ast.SelectKind:
|
||||
if ref, found := a.checked.ReferenceMap()[e.ID()]; found {
|
||||
if len(ref.OverloadIDs) == 0 {
|
||||
result += "^" + ref.Name
|
||||
} else {
|
||||
sort.Strings(ref.OverloadIDs)
|
||||
for i, overload := range ref.OverloadIDs {
|
||||
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 ast.Expr, checked *ast.AST) string {
|
||||
a := &semanticAdorner{checked: checked}
|
||||
return debug.ToAdornedDebugString(e, a)
|
||||
}
|
147
e2e/vendor/github.com/google/cel-go/checker/scopes.go
generated
vendored
Normal file
147
e2e/vendor/github.com/google/cel-go/checker/scopes.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
// 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/decls"
|
||||
)
|
||||
|
||||
// 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 *decls.VariableDecl) {
|
||||
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) *decls.VariableDecl {
|
||||
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) *decls.VariableDecl {
|
||||
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 *decls.FunctionDecl) {
|
||||
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) *decls.FunctionDecl {
|
||||
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]*decls.VariableDecl
|
||||
functions map[string]*decls.FunctionDecl
|
||||
}
|
||||
|
||||
// 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]*decls.VariableDecl, len(g.idents)),
|
||||
functions: make(map[string]*decls.FunctionDecl, 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]*decls.VariableDecl),
|
||||
functions: make(map[string]*decls.FunctionDecl),
|
||||
}
|
||||
}
|
314
e2e/vendor/github.com/google/cel-go/checker/types.go
generated
vendored
Normal file
314
e2e/vendor/github.com/google/cel-go/checker/types.go
generated
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
// 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/types"
|
||||
)
|
||||
|
||||
// isDyn returns true if the input t is either type DYN or a well-known ANY message.
|
||||
func isDyn(t *types.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 t.Kind() {
|
||||
case types.DynKind, types.AnyKind:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// isDynOrError returns true if the input is either an Error, DYN, or well-known ANY message.
|
||||
func isDynOrError(t *types.Type) bool {
|
||||
return isError(t) || isDyn(t)
|
||||
}
|
||||
|
||||
func isError(t *types.Type) bool {
|
||||
return t.Kind() == types.ErrorKind
|
||||
}
|
||||
|
||||
func isOptional(t *types.Type) bool {
|
||||
if t.Kind() == types.OpaqueKind {
|
||||
return t.TypeName() == "optional_type"
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func maybeUnwrapOptional(t *types.Type) (*types.Type, bool) {
|
||||
if isOptional(t) {
|
||||
return t.Parameters()[0], true
|
||||
}
|
||||
return t, false
|
||||
}
|
||||
|
||||
// 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, t2 *types.Type) bool {
|
||||
kind1, kind2 := t1.Kind(), t2.Kind()
|
||||
// The first type is less specific.
|
||||
if isDyn(t1) || kind1 == types.TypeParamKind {
|
||||
return true
|
||||
}
|
||||
// The first type is not less specific.
|
||||
if isDyn(t2) || kind2 == types.TypeParamKind {
|
||||
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 types.OpaqueKind:
|
||||
if t1.TypeName() != t2.TypeName() ||
|
||||
len(t1.Parameters()) != len(t2.Parameters()) {
|
||||
return false
|
||||
}
|
||||
for i, p1 := range t1.Parameters() {
|
||||
if !isEqualOrLessSpecific(p1, t2.Parameters()[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case types.ListKind:
|
||||
return isEqualOrLessSpecific(t1.Parameters()[0], t2.Parameters()[0])
|
||||
case types.MapKind:
|
||||
return isEqualOrLessSpecific(t1.Parameters()[0], t2.Parameters()[0]) &&
|
||||
isEqualOrLessSpecific(t1.Parameters()[1], t2.Parameters()[1])
|
||||
case types.TypeKind:
|
||||
return true
|
||||
default:
|
||||
return t1.IsExactType(t2)
|
||||
}
|
||||
}
|
||||
|
||||
// / internalIsAssignable returns true if t1 is assignable to t2.
|
||||
func internalIsAssignable(m *mapping, t1, t2 *types.Type) bool {
|
||||
// Process type parameters.
|
||||
kind1, kind2 := t1.Kind(), t2.Kind()
|
||||
if kind2 == types.TypeParamKind {
|
||||
// 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 == types.TypeParamKind {
|
||||
// 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
|
||||
}
|
||||
// Preserve the nullness checks of the legacy type-checker.
|
||||
if kind1 == types.NullTypeKind {
|
||||
return internalIsAssignableNull(t2)
|
||||
}
|
||||
if kind2 == types.NullTypeKind {
|
||||
return internalIsAssignableNull(t1)
|
||||
}
|
||||
|
||||
// Test for when the types do not need to agree, but are more specific than dyn.
|
||||
switch kind1 {
|
||||
case types.BoolKind, types.BytesKind, types.DoubleKind, types.IntKind, types.StringKind, types.UintKind,
|
||||
types.AnyKind, types.DurationKind, types.TimestampKind,
|
||||
types.StructKind:
|
||||
// Test whether t2 is assignable from t1. The order of this check won't usually matter;
|
||||
// however, there may be cases where type capabilities are expanded beyond what is supported
|
||||
// in the current common/types package. For example, an interface designation for a group of
|
||||
// Struct types.
|
||||
return t2.IsAssignableType(t1)
|
||||
case types.TypeKind:
|
||||
return kind2 == types.TypeKind
|
||||
case types.OpaqueKind, types.ListKind, types.MapKind:
|
||||
return t1.Kind() == t2.Kind() && t1.TypeName() == t2.TypeName() &&
|
||||
internalIsAssignableList(m, t1.Parameters(), t2.Parameters())
|
||||
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 substitution (t2sub) equal to t1
|
||||
// - t2 has a type substitution (t2sub) assignable to t1
|
||||
// - t2 does not occur within t1.
|
||||
func isValidTypeSubstitution(m *mapping, t1, t2 *types.Type) (valid, hasSub bool) {
|
||||
// Early return if the t1 and t2 are the same instance.
|
||||
kind1, kind2 := t1.Kind(), t2.Kind()
|
||||
if kind1 == kind2 && t1.IsExactType(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 == t2Sub.Kind() && t1.IsExactType(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
|
||||
}
|
||||
|
||||
// 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, l2 []*types.Type) bool {
|
||||
if len(l1) != len(l2) {
|
||||
return false
|
||||
}
|
||||
for i, t1 := range l1 {
|
||||
if !internalIsAssignable(m, t1, l2[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// internalIsAssignableNull returns true if the type is nullable.
|
||||
func internalIsAssignableNull(t *types.Type) bool {
|
||||
return isLegacyNullable(t) || t.IsAssignableType(types.NullType)
|
||||
}
|
||||
|
||||
// isLegacyNullable preserves the null-ness compatibility of the original type-checker implementation.
|
||||
func isLegacyNullable(t *types.Type) bool {
|
||||
switch t.Kind() {
|
||||
case types.OpaqueKind, types.StructKind, types.AnyKind, types.DurationKind, types.TimestampKind:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isAssignable returns an updated type substitution mapping if t1 is assignable to t2.
|
||||
func isAssignable(m *mapping, t1, t2 *types.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, l2 []*types.Type) *mapping {
|
||||
mCopy := m.copy()
|
||||
if internalIsAssignableList(mCopy, l1, l2) {
|
||||
return mCopy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mostGeneral returns the more general of two types which are known to unify.
|
||||
func mostGeneral(t1, t2 *types.Type) *types.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, withinType *types.Type) bool {
|
||||
if t.IsExactType(withinType) {
|
||||
return false
|
||||
}
|
||||
withinKind := withinType.Kind()
|
||||
switch withinKind {
|
||||
case types.TypeParamKind:
|
||||
wtSub, found := m.find(withinType)
|
||||
if !found {
|
||||
return true
|
||||
}
|
||||
return notReferencedIn(m, t, wtSub)
|
||||
case types.OpaqueKind, types.ListKind, types.MapKind, types.TypeKind:
|
||||
for _, pt := range withinType.Parameters() {
|
||||
if !notReferencedIn(m, t, pt) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
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 *types.Type, typeParamToDyn bool) *types.Type {
|
||||
if tSub, found := m.find(t); found {
|
||||
return substitute(m, tSub, typeParamToDyn)
|
||||
}
|
||||
kind := t.Kind()
|
||||
if typeParamToDyn && kind == types.TypeParamKind {
|
||||
return types.DynType
|
||||
}
|
||||
switch kind {
|
||||
case types.OpaqueKind:
|
||||
return types.NewOpaqueType(t.TypeName(), substituteParams(m, t.Parameters(), typeParamToDyn)...)
|
||||
case types.ListKind:
|
||||
return types.NewListType(substitute(m, t.Parameters()[0], typeParamToDyn))
|
||||
case types.MapKind:
|
||||
return types.NewMapType(substitute(m, t.Parameters()[0], typeParamToDyn),
|
||||
substitute(m, t.Parameters()[1], typeParamToDyn))
|
||||
case types.TypeKind:
|
||||
if len(t.Parameters()) > 0 {
|
||||
tParam := t.Parameters()[0]
|
||||
return types.NewTypeTypeWithParam(substitute(m, tParam, typeParamToDyn))
|
||||
}
|
||||
return t
|
||||
default:
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
func substituteParams(m *mapping, typeParams []*types.Type, typeParamToDyn bool) []*types.Type {
|
||||
subParams := make([]*types.Type, len(typeParams))
|
||||
for i, tp := range typeParams {
|
||||
subParams[i] = substitute(m, tp, typeParamToDyn)
|
||||
}
|
||||
return subParams
|
||||
}
|
||||
|
||||
func newFunctionType(resultType *types.Type, argTypes ...*types.Type) *types.Type {
|
||||
return types.NewOpaqueType("function", append([]*types.Type{resultType}, argTypes...)...)
|
||||
}
|
34
e2e/vendor/github.com/google/cel-go/common/BUILD.bazel
generated
vendored
Normal file
34
e2e/vendor/github.com/google/cel-go/common/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"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",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"errors_test.go",
|
||||
"source_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
)
|
57
e2e/vendor/github.com/google/cel-go/common/ast/BUILD.bazel
generated
vendored
Normal file
57
e2e/vendor/github.com/google/cel-go/common/ast/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
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 = [
|
||||
"ast.go",
|
||||
"conversion.go",
|
||||
"expr.go",
|
||||
"factory.go",
|
||||
"navigable.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/ast",
|
||||
deps = [
|
||||
"//common:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"@dev_cel_expr//:expr",
|
||||
"@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",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"ast_test.go",
|
||||
"conversion_test.go",
|
||||
"expr_test.go",
|
||||
"navigable_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
deps = [
|
||||
"//checker:go_default_library",
|
||||
"//checker/decls:go_default_library",
|
||||
"//common:go_default_library",
|
||||
"//common/containers:go_default_library",
|
||||
"//common/decls:go_default_library",
|
||||
"//common/operators:go_default_library",
|
||||
"//common/overloads:go_default_library",
|
||||
"//common/stdlib:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"//parser: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//encoding/prototext:go_default_library",
|
||||
],
|
||||
)
|
457
e2e/vendor/github.com/google/cel-go/common/ast/ast.go
generated
vendored
Normal file
457
e2e/vendor/github.com/google/cel-go/common/ast/ast.go
generated
vendored
Normal file
@ -0,0 +1,457 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package ast declares data structures useful for parsed and checked abstract syntax trees
|
||||
package ast
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// AST contains a protobuf expression and source info along with CEL-native type and reference information.
|
||||
type AST struct {
|
||||
expr Expr
|
||||
sourceInfo *SourceInfo
|
||||
typeMap map[int64]*types.Type
|
||||
refMap map[int64]*ReferenceInfo
|
||||
}
|
||||
|
||||
// Expr returns the root ast.Expr value in the AST.
|
||||
func (a *AST) Expr() Expr {
|
||||
if a == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return a.expr
|
||||
}
|
||||
|
||||
// SourceInfo returns the source metadata associated with the parse / type-check passes.
|
||||
func (a *AST) SourceInfo() *SourceInfo {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
return a.sourceInfo
|
||||
}
|
||||
|
||||
// GetType returns the type for the expression at the given id, if one exists, else types.DynType.
|
||||
func (a *AST) GetType(id int64) *types.Type {
|
||||
if t, found := a.TypeMap()[id]; found {
|
||||
return t
|
||||
}
|
||||
return types.DynType
|
||||
}
|
||||
|
||||
// SetType sets the type of the expression node at the given id.
|
||||
func (a *AST) SetType(id int64, t *types.Type) {
|
||||
if a == nil {
|
||||
return
|
||||
}
|
||||
a.typeMap[id] = t
|
||||
}
|
||||
|
||||
// TypeMap returns the map of expression ids to type-checked types.
|
||||
//
|
||||
// If the AST is not type-checked, the map will be empty.
|
||||
func (a *AST) TypeMap() map[int64]*types.Type {
|
||||
if a == nil {
|
||||
return map[int64]*types.Type{}
|
||||
}
|
||||
return a.typeMap
|
||||
}
|
||||
|
||||
// GetOverloadIDs returns the set of overload function names for a given expression id.
|
||||
//
|
||||
// If the expression id is not a function call, or the AST is not type-checked, the result will be empty.
|
||||
func (a *AST) GetOverloadIDs(id int64) []string {
|
||||
if ref, found := a.ReferenceMap()[id]; found {
|
||||
return ref.OverloadIDs
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// ReferenceMap returns the map of expression id to identifier, constant, and function references.
|
||||
func (a *AST) ReferenceMap() map[int64]*ReferenceInfo {
|
||||
if a == nil {
|
||||
return map[int64]*ReferenceInfo{}
|
||||
}
|
||||
return a.refMap
|
||||
}
|
||||
|
||||
// SetReference adds a reference to the checked AST type map.
|
||||
func (a *AST) SetReference(id int64, r *ReferenceInfo) {
|
||||
if a == nil {
|
||||
return
|
||||
}
|
||||
a.refMap[id] = r
|
||||
}
|
||||
|
||||
// IsChecked returns whether the AST is type-checked.
|
||||
func (a *AST) IsChecked() bool {
|
||||
return a != nil && len(a.TypeMap()) > 0
|
||||
}
|
||||
|
||||
// NewAST creates a base AST instance with an ast.Expr and ast.SourceInfo value.
|
||||
func NewAST(e Expr, sourceInfo *SourceInfo) *AST {
|
||||
if e == nil {
|
||||
e = nilExpr
|
||||
}
|
||||
return &AST{
|
||||
expr: e,
|
||||
sourceInfo: sourceInfo,
|
||||
typeMap: make(map[int64]*types.Type),
|
||||
refMap: make(map[int64]*ReferenceInfo),
|
||||
}
|
||||
}
|
||||
|
||||
// NewCheckedAST wraps an parsed AST and augments it with type and reference metadata.
|
||||
func NewCheckedAST(parsed *AST, typeMap map[int64]*types.Type, refMap map[int64]*ReferenceInfo) *AST {
|
||||
return &AST{
|
||||
expr: parsed.Expr(),
|
||||
sourceInfo: parsed.SourceInfo(),
|
||||
typeMap: typeMap,
|
||||
refMap: refMap,
|
||||
}
|
||||
}
|
||||
|
||||
// Copy creates a deep copy of the Expr and SourceInfo values in the input AST.
|
||||
//
|
||||
// Copies of the Expr value are generated using an internal default ExprFactory.
|
||||
func Copy(a *AST) *AST {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
e := defaultFactory.CopyExpr(a.expr)
|
||||
if !a.IsChecked() {
|
||||
return NewAST(e, CopySourceInfo(a.SourceInfo()))
|
||||
}
|
||||
typesCopy := make(map[int64]*types.Type, len(a.typeMap))
|
||||
for id, t := range a.typeMap {
|
||||
typesCopy[id] = t
|
||||
}
|
||||
refsCopy := make(map[int64]*ReferenceInfo, len(a.refMap))
|
||||
for id, r := range a.refMap {
|
||||
refsCopy[id] = r
|
||||
}
|
||||
return NewCheckedAST(NewAST(e, CopySourceInfo(a.SourceInfo())), typesCopy, refsCopy)
|
||||
}
|
||||
|
||||
// MaxID returns the upper-bound, non-inclusive, of ids present within the AST's Expr value.
|
||||
func MaxID(a *AST) int64 {
|
||||
visitor := &maxIDVisitor{maxID: 1}
|
||||
PostOrderVisit(a.Expr(), visitor)
|
||||
for id, call := range a.SourceInfo().MacroCalls() {
|
||||
PostOrderVisit(call, visitor)
|
||||
if id > visitor.maxID {
|
||||
visitor.maxID = id + 1
|
||||
}
|
||||
}
|
||||
return visitor.maxID + 1
|
||||
}
|
||||
|
||||
// NewSourceInfo creates a simple SourceInfo object from an input common.Source value.
|
||||
func NewSourceInfo(src common.Source) *SourceInfo {
|
||||
var lineOffsets []int32
|
||||
var desc string
|
||||
baseLine := int32(0)
|
||||
baseCol := int32(0)
|
||||
if src != nil {
|
||||
desc = src.Description()
|
||||
lineOffsets = src.LineOffsets()
|
||||
// Determine whether the source metadata should be computed relative
|
||||
// to a base line and column value. This can be determined by requesting
|
||||
// the location for offset 0 from the source object.
|
||||
if loc, found := src.OffsetLocation(0); found {
|
||||
baseLine = int32(loc.Line()) - 1
|
||||
baseCol = int32(loc.Column())
|
||||
}
|
||||
}
|
||||
return &SourceInfo{
|
||||
desc: desc,
|
||||
lines: lineOffsets,
|
||||
baseLine: baseLine,
|
||||
baseCol: baseCol,
|
||||
offsetRanges: make(map[int64]OffsetRange),
|
||||
macroCalls: make(map[int64]Expr),
|
||||
}
|
||||
}
|
||||
|
||||
// CopySourceInfo creates a deep copy of the MacroCalls within the input SourceInfo.
|
||||
//
|
||||
// Copies of macro Expr values are generated using an internal default ExprFactory.
|
||||
func CopySourceInfo(info *SourceInfo) *SourceInfo {
|
||||
if info == nil {
|
||||
return nil
|
||||
}
|
||||
rangesCopy := make(map[int64]OffsetRange, len(info.offsetRanges))
|
||||
for id, off := range info.offsetRanges {
|
||||
rangesCopy[id] = off
|
||||
}
|
||||
callsCopy := make(map[int64]Expr, len(info.macroCalls))
|
||||
for id, call := range info.macroCalls {
|
||||
callsCopy[id] = defaultFactory.CopyExpr(call)
|
||||
}
|
||||
return &SourceInfo{
|
||||
syntax: info.syntax,
|
||||
desc: info.desc,
|
||||
lines: info.lines,
|
||||
baseLine: info.baseLine,
|
||||
baseCol: info.baseCol,
|
||||
offsetRanges: rangesCopy,
|
||||
macroCalls: callsCopy,
|
||||
}
|
||||
}
|
||||
|
||||
// SourceInfo records basic information about the expression as a textual input and
|
||||
// as a parsed expression value.
|
||||
type SourceInfo struct {
|
||||
syntax string
|
||||
desc string
|
||||
lines []int32
|
||||
baseLine int32
|
||||
baseCol int32
|
||||
offsetRanges map[int64]OffsetRange
|
||||
macroCalls map[int64]Expr
|
||||
}
|
||||
|
||||
// SyntaxVersion returns the syntax version associated with the text expression.
|
||||
func (s *SourceInfo) SyntaxVersion() string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return s.syntax
|
||||
}
|
||||
|
||||
// Description provides information about where the expression came from.
|
||||
func (s *SourceInfo) Description() string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return s.desc
|
||||
}
|
||||
|
||||
// LineOffsets returns a list of the 0-based character offsets in the input text where newlines appear.
|
||||
func (s *SourceInfo) LineOffsets() []int32 {
|
||||
if s == nil {
|
||||
return []int32{}
|
||||
}
|
||||
return s.lines
|
||||
}
|
||||
|
||||
// MacroCalls returns a map of expression id to ast.Expr value where the id represents the expression
|
||||
// node where the macro was inserted into the AST, and the ast.Expr value represents the original call
|
||||
// signature which was replaced.
|
||||
func (s *SourceInfo) MacroCalls() map[int64]Expr {
|
||||
if s == nil {
|
||||
return map[int64]Expr{}
|
||||
}
|
||||
return s.macroCalls
|
||||
}
|
||||
|
||||
// GetMacroCall returns the original ast.Expr value for the given expression if it was generated via
|
||||
// a macro replacement.
|
||||
//
|
||||
// Note, parsing options must be enabled to track macro calls before this method will return a value.
|
||||
func (s *SourceInfo) GetMacroCall(id int64) (Expr, bool) {
|
||||
e, found := s.MacroCalls()[id]
|
||||
return e, found
|
||||
}
|
||||
|
||||
// SetMacroCall records a macro call at a specific location.
|
||||
func (s *SourceInfo) SetMacroCall(id int64, e Expr) {
|
||||
if s != nil {
|
||||
s.macroCalls[id] = e
|
||||
}
|
||||
}
|
||||
|
||||
// ClearMacroCall removes the macro call at the given expression id.
|
||||
func (s *SourceInfo) ClearMacroCall(id int64) {
|
||||
if s != nil {
|
||||
delete(s.macroCalls, id)
|
||||
}
|
||||
}
|
||||
|
||||
// OffsetRanges returns a map of expression id to OffsetRange values where the range indicates either:
|
||||
// the start and end position in the input stream where the expression occurs, or the start position
|
||||
// only. If the range only captures start position, the stop position of the range will be equal to
|
||||
// the start.
|
||||
func (s *SourceInfo) OffsetRanges() map[int64]OffsetRange {
|
||||
if s == nil {
|
||||
return map[int64]OffsetRange{}
|
||||
}
|
||||
return s.offsetRanges
|
||||
}
|
||||
|
||||
// GetOffsetRange retrieves an OffsetRange for the given expression id if one exists.
|
||||
func (s *SourceInfo) GetOffsetRange(id int64) (OffsetRange, bool) {
|
||||
if s == nil {
|
||||
return OffsetRange{}, false
|
||||
}
|
||||
o, found := s.offsetRanges[id]
|
||||
return o, found
|
||||
}
|
||||
|
||||
// SetOffsetRange sets the OffsetRange for the given expression id.
|
||||
func (s *SourceInfo) SetOffsetRange(id int64, o OffsetRange) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
s.offsetRanges[id] = o
|
||||
}
|
||||
|
||||
// ClearOffsetRange removes the OffsetRange for the given expression id.
|
||||
func (s *SourceInfo) ClearOffsetRange(id int64) {
|
||||
if s != nil {
|
||||
delete(s.offsetRanges, id)
|
||||
}
|
||||
}
|
||||
|
||||
// GetStartLocation calculates the human-readable 1-based line and 0-based column of the first character
|
||||
// of the expression node at the id.
|
||||
func (s *SourceInfo) GetStartLocation(id int64) common.Location {
|
||||
if o, found := s.GetOffsetRange(id); found {
|
||||
return s.GetLocationByOffset(o.Start)
|
||||
}
|
||||
return common.NoLocation
|
||||
}
|
||||
|
||||
// GetStopLocation calculates the human-readable 1-based line and 0-based column of the last character for
|
||||
// the expression node at the given id.
|
||||
//
|
||||
// If the SourceInfo was generated from a serialized protobuf representation, the stop location will
|
||||
// be identical to the start location for the expression.
|
||||
func (s *SourceInfo) GetStopLocation(id int64) common.Location {
|
||||
if o, found := s.GetOffsetRange(id); found {
|
||||
return s.GetLocationByOffset(o.Stop)
|
||||
}
|
||||
return common.NoLocation
|
||||
}
|
||||
|
||||
// GetLocationByOffset returns the line and column information for a given character offset.
|
||||
func (s *SourceInfo) GetLocationByOffset(offset int32) common.Location {
|
||||
line := 1
|
||||
col := int(offset)
|
||||
for _, lineOffset := range s.LineOffsets() {
|
||||
if lineOffset > offset {
|
||||
break
|
||||
}
|
||||
line++
|
||||
col = int(offset - lineOffset)
|
||||
}
|
||||
return common.NewLocation(line, col)
|
||||
}
|
||||
|
||||
// ComputeOffset calculates the 0-based character offset from a 1-based line and 0-based column.
|
||||
func (s *SourceInfo) ComputeOffset(line, col int32) int32 {
|
||||
if s != nil {
|
||||
line = s.baseLine + line
|
||||
col = s.baseCol + col
|
||||
}
|
||||
if line == 1 {
|
||||
return col
|
||||
}
|
||||
if line < 1 || line > int32(len(s.LineOffsets())) {
|
||||
return -1
|
||||
}
|
||||
offset := s.LineOffsets()[line-2]
|
||||
return offset + col
|
||||
}
|
||||
|
||||
// OffsetRange captures the start and stop positions of a section of text in the input expression.
|
||||
type OffsetRange struct {
|
||||
Start int32
|
||||
Stop int32
|
||||
}
|
||||
|
||||
// ReferenceInfo contains a CEL native representation of an identifier reference which may refer to
|
||||
// either a qualified identifier name, a set of overload ids, or a constant value from an enum.
|
||||
type ReferenceInfo struct {
|
||||
Name string
|
||||
OverloadIDs []string
|
||||
Value ref.Val
|
||||
}
|
||||
|
||||
// NewIdentReference creates a ReferenceInfo instance for an identifier with an optional constant value.
|
||||
func NewIdentReference(name string, value ref.Val) *ReferenceInfo {
|
||||
return &ReferenceInfo{Name: name, Value: value}
|
||||
}
|
||||
|
||||
// NewFunctionReference creates a ReferenceInfo instance for a set of function overloads.
|
||||
func NewFunctionReference(overloads ...string) *ReferenceInfo {
|
||||
info := &ReferenceInfo{}
|
||||
for _, id := range overloads {
|
||||
info.AddOverload(id)
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// AddOverload appends a function overload ID to the ReferenceInfo.
|
||||
func (r *ReferenceInfo) AddOverload(overloadID string) {
|
||||
for _, id := range r.OverloadIDs {
|
||||
if id == overloadID {
|
||||
return
|
||||
}
|
||||
}
|
||||
r.OverloadIDs = append(r.OverloadIDs, overloadID)
|
||||
}
|
||||
|
||||
// Equals returns whether two references are identical to each other.
|
||||
func (r *ReferenceInfo) Equals(other *ReferenceInfo) bool {
|
||||
if r.Name != other.Name {
|
||||
return false
|
||||
}
|
||||
if len(r.OverloadIDs) != len(other.OverloadIDs) {
|
||||
return false
|
||||
}
|
||||
if len(r.OverloadIDs) != 0 {
|
||||
overloadMap := make(map[string]struct{}, len(r.OverloadIDs))
|
||||
for _, id := range r.OverloadIDs {
|
||||
overloadMap[id] = struct{}{}
|
||||
}
|
||||
for _, id := range other.OverloadIDs {
|
||||
_, found := overloadMap[id]
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if r.Value == nil && other.Value == nil {
|
||||
return true
|
||||
}
|
||||
if r.Value == nil && other.Value != nil ||
|
||||
r.Value != nil && other.Value == nil ||
|
||||
r.Value.Equal(other.Value) != types.True {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type maxIDVisitor struct {
|
||||
maxID int64
|
||||
*baseVisitor
|
||||
}
|
||||
|
||||
// VisitExpr updates the max identifier if the incoming expression id is greater than previously observed.
|
||||
func (v *maxIDVisitor) VisitExpr(e Expr) {
|
||||
if v.maxID < e.ID() {
|
||||
v.maxID = e.ID()
|
||||
}
|
||||
}
|
||||
|
||||
// VisitEntryExpr updates the max identifier if the incoming entry id is greater than previously observed.
|
||||
func (v *maxIDVisitor) VisitEntryExpr(e EntryExpr) {
|
||||
if v.maxID < e.ID() {
|
||||
v.maxID = e.ID()
|
||||
}
|
||||
}
|
659
e2e/vendor/github.com/google/cel-go/common/ast/conversion.go
generated
vendored
Normal file
659
e2e/vendor/github.com/google/cel-go/common/ast/conversion.go
generated
vendored
Normal file
@ -0,0 +1,659 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
celpb "cel.dev/expr"
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// ToProto converts an AST to a CheckedExpr protobouf.
|
||||
func ToProto(ast *AST) (*exprpb.CheckedExpr, error) {
|
||||
refMap := make(map[int64]*exprpb.Reference, len(ast.ReferenceMap()))
|
||||
for id, ref := range ast.ReferenceMap() {
|
||||
r, err := ReferenceInfoToProto(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
refMap[id] = r
|
||||
}
|
||||
typeMap := make(map[int64]*exprpb.Type, len(ast.TypeMap()))
|
||||
for id, typ := range ast.TypeMap() {
|
||||
t, err := types.TypeToExprType(typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typeMap[id] = t
|
||||
}
|
||||
e, err := ExprToProto(ast.Expr())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info, err := SourceInfoToProto(ast.SourceInfo())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &exprpb.CheckedExpr{
|
||||
Expr: e,
|
||||
SourceInfo: info,
|
||||
ReferenceMap: refMap,
|
||||
TypeMap: typeMap,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToAST converts a CheckedExpr protobuf to an AST instance.
|
||||
func ToAST(checked *exprpb.CheckedExpr) (*AST, error) {
|
||||
refMap := make(map[int64]*ReferenceInfo, len(checked.GetReferenceMap()))
|
||||
for id, ref := range checked.GetReferenceMap() {
|
||||
r, err := ProtoToReferenceInfo(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
refMap[id] = r
|
||||
}
|
||||
typeMap := make(map[int64]*types.Type, len(checked.GetTypeMap()))
|
||||
for id, typ := range checked.GetTypeMap() {
|
||||
t, err := types.ExprTypeToType(typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typeMap[id] = t
|
||||
}
|
||||
info, err := ProtoToSourceInfo(checked.GetSourceInfo())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
root, err := ProtoToExpr(checked.GetExpr())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ast := NewCheckedAST(NewAST(root, info), typeMap, refMap)
|
||||
return ast, nil
|
||||
}
|
||||
|
||||
// ProtoToExpr converts a protobuf Expr value to an ast.Expr value.
|
||||
func ProtoToExpr(e *exprpb.Expr) (Expr, error) {
|
||||
factory := NewExprFactory()
|
||||
return exprInternal(factory, e)
|
||||
}
|
||||
|
||||
// ProtoToEntryExpr converts a protobuf struct/map entry to an ast.EntryExpr
|
||||
func ProtoToEntryExpr(e *exprpb.Expr_CreateStruct_Entry) (EntryExpr, error) {
|
||||
factory := NewExprFactory()
|
||||
switch e.GetKeyKind().(type) {
|
||||
case *exprpb.Expr_CreateStruct_Entry_FieldKey:
|
||||
return exprStructField(factory, e.GetId(), e)
|
||||
case *exprpb.Expr_CreateStruct_Entry_MapKey:
|
||||
return exprMapEntry(factory, e.GetId(), e)
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported expr entry kind: %v", e)
|
||||
}
|
||||
|
||||
func exprInternal(factory ExprFactory, e *exprpb.Expr) (Expr, error) {
|
||||
id := e.GetId()
|
||||
switch e.GetExprKind().(type) {
|
||||
case *exprpb.Expr_CallExpr:
|
||||
return exprCall(factory, id, e.GetCallExpr())
|
||||
case *exprpb.Expr_ComprehensionExpr:
|
||||
return exprComprehension(factory, id, e.GetComprehensionExpr())
|
||||
case *exprpb.Expr_ConstExpr:
|
||||
return exprLiteral(factory, id, e.GetConstExpr())
|
||||
case *exprpb.Expr_IdentExpr:
|
||||
return exprIdent(factory, id, e.GetIdentExpr())
|
||||
case *exprpb.Expr_ListExpr:
|
||||
return exprList(factory, id, e.GetListExpr())
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
return exprSelect(factory, id, e.GetSelectExpr())
|
||||
case *exprpb.Expr_StructExpr:
|
||||
s := e.GetStructExpr()
|
||||
if s.GetMessageName() != "" {
|
||||
return exprStruct(factory, id, s)
|
||||
}
|
||||
return exprMap(factory, id, s)
|
||||
}
|
||||
return factory.NewUnspecifiedExpr(id), nil
|
||||
}
|
||||
|
||||
func exprCall(factory ExprFactory, id int64, call *exprpb.Expr_Call) (Expr, error) {
|
||||
var err error
|
||||
args := make([]Expr, len(call.GetArgs()))
|
||||
for i, a := range call.GetArgs() {
|
||||
args[i], err = exprInternal(factory, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if call.GetTarget() == nil {
|
||||
return factory.NewCall(id, call.GetFunction(), args...), nil
|
||||
}
|
||||
|
||||
target, err := exprInternal(factory, call.GetTarget())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return factory.NewMemberCall(id, call.GetFunction(), target, args...), nil
|
||||
}
|
||||
|
||||
func exprComprehension(factory ExprFactory, id int64, comp *exprpb.Expr_Comprehension) (Expr, error) {
|
||||
iterRange, err := exprInternal(factory, comp.GetIterRange())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accuInit, err := exprInternal(factory, comp.GetAccuInit())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loopCond, err := exprInternal(factory, comp.GetLoopCondition())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loopStep, err := exprInternal(factory, comp.GetLoopStep())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := exprInternal(factory, comp.GetResult())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return factory.NewComprehensionTwoVar(id,
|
||||
iterRange,
|
||||
comp.GetIterVar(),
|
||||
comp.GetIterVar2(),
|
||||
comp.GetAccuVar(),
|
||||
accuInit,
|
||||
loopCond,
|
||||
loopStep,
|
||||
result), nil
|
||||
}
|
||||
|
||||
func exprLiteral(factory ExprFactory, id int64, c *exprpb.Constant) (Expr, error) {
|
||||
val, err := ConstantToVal(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return factory.NewLiteral(id, val), nil
|
||||
}
|
||||
|
||||
func exprIdent(factory ExprFactory, id int64, i *exprpb.Expr_Ident) (Expr, error) {
|
||||
return factory.NewIdent(id, i.GetName()), nil
|
||||
}
|
||||
|
||||
func exprList(factory ExprFactory, id int64, l *exprpb.Expr_CreateList) (Expr, error) {
|
||||
elems := make([]Expr, len(l.GetElements()))
|
||||
for i, e := range l.GetElements() {
|
||||
elem, err := exprInternal(factory, e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
elems[i] = elem
|
||||
}
|
||||
return factory.NewList(id, elems, l.GetOptionalIndices()), nil
|
||||
}
|
||||
|
||||
func exprMap(factory ExprFactory, id int64, s *exprpb.Expr_CreateStruct) (Expr, error) {
|
||||
entries := make([]EntryExpr, len(s.GetEntries()))
|
||||
var err error
|
||||
for i, entry := range s.GetEntries() {
|
||||
entries[i], err = exprMapEntry(factory, entry.GetId(), entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return factory.NewMap(id, entries), nil
|
||||
}
|
||||
|
||||
func exprMapEntry(factory ExprFactory, id int64, e *exprpb.Expr_CreateStruct_Entry) (EntryExpr, error) {
|
||||
k, err := exprInternal(factory, e.GetMapKey())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, err := exprInternal(factory, e.GetValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return factory.NewMapEntry(id, k, v, e.GetOptionalEntry()), nil
|
||||
}
|
||||
|
||||
func exprSelect(factory ExprFactory, id int64, s *exprpb.Expr_Select) (Expr, error) {
|
||||
op, err := exprInternal(factory, s.GetOperand())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.GetTestOnly() {
|
||||
return factory.NewPresenceTest(id, op, s.GetField()), nil
|
||||
}
|
||||
return factory.NewSelect(id, op, s.GetField()), nil
|
||||
}
|
||||
|
||||
func exprStruct(factory ExprFactory, id int64, s *exprpb.Expr_CreateStruct) (Expr, error) {
|
||||
fields := make([]EntryExpr, len(s.GetEntries()))
|
||||
var err error
|
||||
for i, field := range s.GetEntries() {
|
||||
fields[i], err = exprStructField(factory, field.GetId(), field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return factory.NewStruct(id, s.GetMessageName(), fields), nil
|
||||
}
|
||||
|
||||
func exprStructField(factory ExprFactory, id int64, f *exprpb.Expr_CreateStruct_Entry) (EntryExpr, error) {
|
||||
v, err := exprInternal(factory, f.GetValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return factory.NewStructField(id, f.GetFieldKey(), v, f.GetOptionalEntry()), nil
|
||||
}
|
||||
|
||||
// ExprToProto serializes an ast.Expr value to a protobuf Expr representation.
|
||||
func ExprToProto(e Expr) (*exprpb.Expr, error) {
|
||||
if e == nil {
|
||||
return &exprpb.Expr{}, nil
|
||||
}
|
||||
switch e.Kind() {
|
||||
case CallKind:
|
||||
return protoCall(e.ID(), e.AsCall())
|
||||
case ComprehensionKind:
|
||||
return protoComprehension(e.ID(), e.AsComprehension())
|
||||
case IdentKind:
|
||||
return protoIdent(e.ID(), e.AsIdent())
|
||||
case ListKind:
|
||||
return protoList(e.ID(), e.AsList())
|
||||
case LiteralKind:
|
||||
return protoLiteral(e.ID(), e.AsLiteral())
|
||||
case MapKind:
|
||||
return protoMap(e.ID(), e.AsMap())
|
||||
case SelectKind:
|
||||
return protoSelect(e.ID(), e.AsSelect())
|
||||
case StructKind:
|
||||
return protoStruct(e.ID(), e.AsStruct())
|
||||
case UnspecifiedExprKind:
|
||||
// Handle the case where a macro reference may be getting translated.
|
||||
// A nested macro 'pointer' is a non-zero expression id with no kind set.
|
||||
if e.ID() != 0 {
|
||||
return &exprpb.Expr{Id: e.ID()}, nil
|
||||
}
|
||||
return &exprpb.Expr{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported expr kind: %v", e)
|
||||
}
|
||||
|
||||
// EntryExprToProto converts an ast.EntryExpr to a protobuf CreateStruct entry
|
||||
func EntryExprToProto(e EntryExpr) (*exprpb.Expr_CreateStruct_Entry, error) {
|
||||
switch e.Kind() {
|
||||
case MapEntryKind:
|
||||
return protoMapEntry(e.ID(), e.AsMapEntry())
|
||||
case StructFieldKind:
|
||||
return protoStructField(e.ID(), e.AsStructField())
|
||||
case UnspecifiedEntryExprKind:
|
||||
return &exprpb.Expr_CreateStruct_Entry{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported expr entry kind: %v", e)
|
||||
}
|
||||
|
||||
func protoCall(id int64, call CallExpr) (*exprpb.Expr, error) {
|
||||
var err error
|
||||
var target *exprpb.Expr
|
||||
if call.IsMemberFunction() {
|
||||
target, err = ExprToProto(call.Target())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
callArgs := call.Args()
|
||||
args := make([]*exprpb.Expr, len(callArgs))
|
||||
for i, a := range callArgs {
|
||||
args[i], err = ExprToProto(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_CallExpr{
|
||||
CallExpr: &exprpb.Expr_Call{
|
||||
Function: call.FunctionName(),
|
||||
Target: target,
|
||||
Args: args,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func protoComprehension(id int64, comp ComprehensionExpr) (*exprpb.Expr, error) {
|
||||
iterRange, err := ExprToProto(comp.IterRange())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accuInit, err := ExprToProto(comp.AccuInit())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loopCond, err := ExprToProto(comp.LoopCondition())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loopStep, err := ExprToProto(comp.LoopStep())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := ExprToProto(comp.Result())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_ComprehensionExpr{
|
||||
ComprehensionExpr: &exprpb.Expr_Comprehension{
|
||||
IterVar: comp.IterVar(),
|
||||
IterVar2: comp.IterVar2(),
|
||||
IterRange: iterRange,
|
||||
AccuVar: comp.AccuVar(),
|
||||
AccuInit: accuInit,
|
||||
LoopCondition: loopCond,
|
||||
LoopStep: loopStep,
|
||||
Result: result,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func protoIdent(id int64, name string) (*exprpb.Expr, error) {
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_IdentExpr{
|
||||
IdentExpr: &exprpb.Expr_Ident{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func protoList(id int64, list ListExpr) (*exprpb.Expr, error) {
|
||||
var err error
|
||||
elems := make([]*exprpb.Expr, list.Size())
|
||||
for i, e := range list.Elements() {
|
||||
elems[i], err = ExprToProto(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_ListExpr{
|
||||
ListExpr: &exprpb.Expr_CreateList{
|
||||
Elements: elems,
|
||||
OptionalIndices: list.OptionalIndices(),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func protoLiteral(id int64, val ref.Val) (*exprpb.Expr, error) {
|
||||
c, err := ValToConstant(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_ConstExpr{
|
||||
ConstExpr: c,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func protoMap(id int64, m MapExpr) (*exprpb.Expr, error) {
|
||||
entries := make([]*exprpb.Expr_CreateStruct_Entry, len(m.Entries()))
|
||||
var err error
|
||||
for i, e := range m.Entries() {
|
||||
entries[i], err = EntryExprToProto(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_StructExpr{
|
||||
StructExpr: &exprpb.Expr_CreateStruct{
|
||||
Entries: entries,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func protoMapEntry(id int64, e MapEntry) (*exprpb.Expr_CreateStruct_Entry, error) {
|
||||
k, err := ExprToProto(e.Key())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, err := ExprToProto(e.Value())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &exprpb.Expr_CreateStruct_Entry{
|
||||
Id: id,
|
||||
KeyKind: &exprpb.Expr_CreateStruct_Entry_MapKey{
|
||||
MapKey: k,
|
||||
},
|
||||
Value: v,
|
||||
OptionalEntry: e.IsOptional(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func protoSelect(id int64, s SelectExpr) (*exprpb.Expr, error) {
|
||||
op, err := ExprToProto(s.Operand())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_SelectExpr{
|
||||
SelectExpr: &exprpb.Expr_Select{
|
||||
Operand: op,
|
||||
Field: s.FieldName(),
|
||||
TestOnly: s.IsTestOnly(),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func protoStruct(id int64, s StructExpr) (*exprpb.Expr, error) {
|
||||
entries := make([]*exprpb.Expr_CreateStruct_Entry, len(s.Fields()))
|
||||
var err error
|
||||
for i, e := range s.Fields() {
|
||||
entries[i], err = EntryExprToProto(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &exprpb.Expr{
|
||||
Id: id,
|
||||
ExprKind: &exprpb.Expr_StructExpr{
|
||||
StructExpr: &exprpb.Expr_CreateStruct{
|
||||
MessageName: s.TypeName(),
|
||||
Entries: entries,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func protoStructField(id int64, f StructField) (*exprpb.Expr_CreateStruct_Entry, error) {
|
||||
v, err := ExprToProto(f.Value())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &exprpb.Expr_CreateStruct_Entry{
|
||||
Id: id,
|
||||
KeyKind: &exprpb.Expr_CreateStruct_Entry_FieldKey{
|
||||
FieldKey: f.Name(),
|
||||
},
|
||||
Value: v,
|
||||
OptionalEntry: f.IsOptional(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SourceInfoToProto serializes an ast.SourceInfo value to a protobuf SourceInfo object.
|
||||
func SourceInfoToProto(info *SourceInfo) (*exprpb.SourceInfo, error) {
|
||||
if info == nil {
|
||||
return &exprpb.SourceInfo{}, nil
|
||||
}
|
||||
sourceInfo := &exprpb.SourceInfo{
|
||||
SyntaxVersion: info.SyntaxVersion(),
|
||||
Location: info.Description(),
|
||||
LineOffsets: info.LineOffsets(),
|
||||
Positions: make(map[int64]int32, len(info.OffsetRanges())),
|
||||
MacroCalls: make(map[int64]*exprpb.Expr, len(info.MacroCalls())),
|
||||
}
|
||||
for id, offset := range info.OffsetRanges() {
|
||||
sourceInfo.Positions[id] = offset.Start
|
||||
}
|
||||
for id, e := range info.MacroCalls() {
|
||||
call, err := ExprToProto(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sourceInfo.MacroCalls[id] = call
|
||||
}
|
||||
return sourceInfo, nil
|
||||
}
|
||||
|
||||
// ProtoToSourceInfo deserializes the protobuf into a native SourceInfo value.
|
||||
func ProtoToSourceInfo(info *exprpb.SourceInfo) (*SourceInfo, error) {
|
||||
sourceInfo := &SourceInfo{
|
||||
syntax: info.GetSyntaxVersion(),
|
||||
desc: info.GetLocation(),
|
||||
lines: info.GetLineOffsets(),
|
||||
offsetRanges: make(map[int64]OffsetRange, len(info.GetPositions())),
|
||||
macroCalls: make(map[int64]Expr, len(info.GetMacroCalls())),
|
||||
}
|
||||
for id, offset := range info.GetPositions() {
|
||||
sourceInfo.SetOffsetRange(id, OffsetRange{Start: offset, Stop: offset})
|
||||
}
|
||||
for id, e := range info.GetMacroCalls() {
|
||||
call, err := ProtoToExpr(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sourceInfo.SetMacroCall(id, call)
|
||||
}
|
||||
return sourceInfo, nil
|
||||
}
|
||||
|
||||
// ReferenceInfoToProto converts a ReferenceInfo instance to a protobuf Reference suitable for serialization.
|
||||
func ReferenceInfoToProto(info *ReferenceInfo) (*exprpb.Reference, error) {
|
||||
c, err := ValToConstant(info.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &exprpb.Reference{
|
||||
Name: info.Name,
|
||||
OverloadId: info.OverloadIDs,
|
||||
Value: c,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ProtoToReferenceInfo converts a protobuf Reference into a CEL-native ReferenceInfo instance.
|
||||
func ProtoToReferenceInfo(ref *exprpb.Reference) (*ReferenceInfo, error) {
|
||||
v, err := ConstantToVal(ref.GetValue())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ReferenceInfo{
|
||||
Name: ref.GetName(),
|
||||
OverloadIDs: ref.GetOverloadId(),
|
||||
Value: v,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ValToConstant converts a CEL-native ref.Val to a protobuf Constant.
|
||||
//
|
||||
// Only simple scalar types are supported by this method.
|
||||
func ValToConstant(v ref.Val) (*exprpb.Constant, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
switch v.Type() {
|
||||
case types.BoolType:
|
||||
return &exprpb.Constant{ConstantKind: &exprpb.Constant_BoolValue{BoolValue: v.Value().(bool)}}, nil
|
||||
case types.BytesType:
|
||||
return &exprpb.Constant{ConstantKind: &exprpb.Constant_BytesValue{BytesValue: v.Value().([]byte)}}, nil
|
||||
case types.DoubleType:
|
||||
return &exprpb.Constant{ConstantKind: &exprpb.Constant_DoubleValue{DoubleValue: v.Value().(float64)}}, nil
|
||||
case types.IntType:
|
||||
return &exprpb.Constant{ConstantKind: &exprpb.Constant_Int64Value{Int64Value: v.Value().(int64)}}, nil
|
||||
case types.NullType:
|
||||
return &exprpb.Constant{ConstantKind: &exprpb.Constant_NullValue{NullValue: structpb.NullValue_NULL_VALUE}}, nil
|
||||
case types.StringType:
|
||||
return &exprpb.Constant{ConstantKind: &exprpb.Constant_StringValue{StringValue: v.Value().(string)}}, nil
|
||||
case types.UintType:
|
||||
return &exprpb.Constant{ConstantKind: &exprpb.Constant_Uint64Value{Uint64Value: v.Value().(uint64)}}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported constant kind: %v", v.Type())
|
||||
}
|
||||
|
||||
// ConstantToVal converts a protobuf Constant to a CEL-native ref.Val.
|
||||
func ConstantToVal(c *exprpb.Constant) (ref.Val, error) {
|
||||
return AlphaProtoConstantAsVal(c)
|
||||
}
|
||||
|
||||
// AlphaProtoConstantAsVal converts a v1alpha1.Constant protobuf to a CEL-native ref.Val.
|
||||
func AlphaProtoConstantAsVal(c *exprpb.Constant) (ref.Val, error) {
|
||||
if c == nil {
|
||||
return nil, nil
|
||||
}
|
||||
canonical := &celpb.Constant{}
|
||||
if err := convertProto(c, canonical); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ProtoConstantAsVal(canonical)
|
||||
}
|
||||
|
||||
// ProtoConstantAsVal converts a canonical celpb.Constant protobuf to a CEL-native ref.Val.
|
||||
func ProtoConstantAsVal(c *celpb.Constant) (ref.Val, error) {
|
||||
switch c.GetConstantKind().(type) {
|
||||
case *celpb.Constant_BoolValue:
|
||||
return types.Bool(c.GetBoolValue()), nil
|
||||
case *celpb.Constant_BytesValue:
|
||||
return types.Bytes(c.GetBytesValue()), nil
|
||||
case *celpb.Constant_DoubleValue:
|
||||
return types.Double(c.GetDoubleValue()), nil
|
||||
case *celpb.Constant_Int64Value:
|
||||
return types.Int(c.GetInt64Value()), nil
|
||||
case *celpb.Constant_NullValue:
|
||||
return types.NullValue, nil
|
||||
case *celpb.Constant_StringValue:
|
||||
return types.String(c.GetStringValue()), nil
|
||||
case *celpb.Constant_Uint64Value:
|
||||
return types.Uint(c.GetUint64Value()), nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported constant kind: %v", c.GetConstantKind())
|
||||
}
|
||||
|
||||
func convertProto(src, dst proto.Message) error {
|
||||
pb, err := proto.Marshal(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = proto.Unmarshal(pb, dst)
|
||||
return err
|
||||
}
|
884
e2e/vendor/github.com/google/cel-go/common/ast/expr.go
generated
vendored
Normal file
884
e2e/vendor/github.com/google/cel-go/common/ast/expr.go
generated
vendored
Normal file
@ -0,0 +1,884 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ast
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// ExprKind represents the expression node kind.
|
||||
type ExprKind int
|
||||
|
||||
const (
|
||||
// UnspecifiedExprKind represents an unset expression with no specified properties.
|
||||
UnspecifiedExprKind ExprKind = iota
|
||||
|
||||
// CallKind represents a function call.
|
||||
CallKind
|
||||
|
||||
// ComprehensionKind represents a comprehension expression generated by a macro.
|
||||
ComprehensionKind
|
||||
|
||||
// IdentKind represents a simple variable, constant, or type identifier.
|
||||
IdentKind
|
||||
|
||||
// ListKind represents a list literal expression.
|
||||
ListKind
|
||||
|
||||
// LiteralKind represents a primitive scalar literal.
|
||||
LiteralKind
|
||||
|
||||
// MapKind represents a map literal expression.
|
||||
MapKind
|
||||
|
||||
// SelectKind represents a field selection expression.
|
||||
SelectKind
|
||||
|
||||
// StructKind represents a struct literal expression.
|
||||
StructKind
|
||||
)
|
||||
|
||||
// Expr represents the base expression node in a CEL abstract syntax tree.
|
||||
//
|
||||
// Depending on the `Kind()` value, the Expr may be converted to a concrete expression types
|
||||
// as indicated by the `As<Kind>` methods.
|
||||
type Expr interface {
|
||||
// ID of the expression as it appears in the AST
|
||||
ID() int64
|
||||
|
||||
// Kind of the expression node. See ExprKind for the valid enum values.
|
||||
Kind() ExprKind
|
||||
|
||||
// AsCall adapts the expr into a CallExpr
|
||||
//
|
||||
// The Kind() must be equal to a CallKind for the conversion to be well-defined.
|
||||
AsCall() CallExpr
|
||||
|
||||
// AsComprehension adapts the expr into a ComprehensionExpr.
|
||||
//
|
||||
// The Kind() must be equal to a ComprehensionKind for the conversion to be well-defined.
|
||||
AsComprehension() ComprehensionExpr
|
||||
|
||||
// AsIdent adapts the expr into an identifier string.
|
||||
//
|
||||
// The Kind() must be equal to an IdentKind for the conversion to be well-defined.
|
||||
AsIdent() string
|
||||
|
||||
// AsLiteral adapts the expr into a constant ref.Val.
|
||||
//
|
||||
// The Kind() must be equal to a LiteralKind for the conversion to be well-defined.
|
||||
AsLiteral() ref.Val
|
||||
|
||||
// AsList adapts the expr into a ListExpr.
|
||||
//
|
||||
// The Kind() must be equal to a ListKind for the conversion to be well-defined.
|
||||
AsList() ListExpr
|
||||
|
||||
// AsMap adapts the expr into a MapExpr.
|
||||
//
|
||||
// The Kind() must be equal to a MapKind for the conversion to be well-defined.
|
||||
AsMap() MapExpr
|
||||
|
||||
// AsSelect adapts the expr into a SelectExpr.
|
||||
//
|
||||
// The Kind() must be equal to a SelectKind for the conversion to be well-defined.
|
||||
AsSelect() SelectExpr
|
||||
|
||||
// AsStruct adapts the expr into a StructExpr.
|
||||
//
|
||||
// The Kind() must be equal to a StructKind for the conversion to be well-defined.
|
||||
AsStruct() StructExpr
|
||||
|
||||
// RenumberIDs performs an in-place update of the expression and all of its descendents numeric ids.
|
||||
RenumberIDs(IDGenerator)
|
||||
|
||||
// SetKindCase replaces the contents of the current expression with the contents of the other.
|
||||
//
|
||||
// The SetKindCase takes ownership of any expression instances references within the input Expr.
|
||||
// A shallow copy is made of the Expr value itself, but not a deep one.
|
||||
//
|
||||
// This method should only be used during AST rewrites using temporary Expr values.
|
||||
SetKindCase(Expr)
|
||||
|
||||
// isExpr is a marker interface.
|
||||
isExpr()
|
||||
}
|
||||
|
||||
// EntryExprKind represents the possible EntryExpr kinds.
|
||||
type EntryExprKind int
|
||||
|
||||
const (
|
||||
// UnspecifiedEntryExprKind indicates that the entry expr is not set.
|
||||
UnspecifiedEntryExprKind EntryExprKind = iota
|
||||
|
||||
// MapEntryKind indicates that the entry is a MapEntry type with key and value expressions.
|
||||
MapEntryKind
|
||||
|
||||
// StructFieldKind indicates that the entry is a StructField with a field name and initializer
|
||||
// expression.
|
||||
StructFieldKind
|
||||
)
|
||||
|
||||
// EntryExpr represents the base entry expression in a CEL map or struct literal.
|
||||
type EntryExpr interface {
|
||||
// ID of the entry as it appears in the AST.
|
||||
ID() int64
|
||||
|
||||
// Kind of the entry expression node. See EntryExprKind for valid enum values.
|
||||
Kind() EntryExprKind
|
||||
|
||||
// AsMapEntry casts the EntryExpr to a MapEntry.
|
||||
//
|
||||
// The Kind() must be equal to MapEntryKind for the conversion to be well-defined.
|
||||
AsMapEntry() MapEntry
|
||||
|
||||
// AsStructField casts the EntryExpr to a StructField
|
||||
//
|
||||
// The Kind() must be equal to StructFieldKind for the conversion to be well-defined.
|
||||
AsStructField() StructField
|
||||
|
||||
// RenumberIDs performs an in-place update of the expression and all of its descendents numeric ids.
|
||||
RenumberIDs(IDGenerator)
|
||||
|
||||
isEntryExpr()
|
||||
}
|
||||
|
||||
// IDGenerator produces unique ids suitable for tagging expression nodes
|
||||
type IDGenerator func(originalID int64) int64
|
||||
|
||||
// CallExpr defines an interface for inspecting a function call and its arguments.
|
||||
type CallExpr interface {
|
||||
// FunctionName returns the name of the function.
|
||||
FunctionName() string
|
||||
|
||||
// IsMemberFunction returns whether the call has a non-nil target indicating it is a member function
|
||||
IsMemberFunction() bool
|
||||
|
||||
// Target returns the target of the expression if one is present.
|
||||
Target() Expr
|
||||
|
||||
// Args returns the list of call arguments, excluding the target.
|
||||
Args() []Expr
|
||||
|
||||
// marker interface method
|
||||
isExpr()
|
||||
}
|
||||
|
||||
// ListExpr defines an interface for inspecting a list literal expression.
|
||||
type ListExpr interface {
|
||||
// Elements returns the list elements as navigable expressions.
|
||||
Elements() []Expr
|
||||
|
||||
// OptionalIndicies returns the list of optional indices in the list literal.
|
||||
OptionalIndices() []int32
|
||||
|
||||
// IsOptional indicates whether the given element index is optional.
|
||||
IsOptional(int32) bool
|
||||
|
||||
// Size returns the number of elements in the list.
|
||||
Size() int
|
||||
|
||||
// marker interface method
|
||||
isExpr()
|
||||
}
|
||||
|
||||
// SelectExpr defines an interface for inspecting a select expression.
|
||||
type SelectExpr interface {
|
||||
// Operand returns the selection operand expression.
|
||||
Operand() Expr
|
||||
|
||||
// FieldName returns the field name being selected from the operand.
|
||||
FieldName() string
|
||||
|
||||
// IsTestOnly indicates whether the select expression is a presence test generated by a macro.
|
||||
IsTestOnly() bool
|
||||
|
||||
// marker interface method
|
||||
isExpr()
|
||||
}
|
||||
|
||||
// MapExpr defines an interface for inspecting a map expression.
|
||||
type MapExpr interface {
|
||||
// Entries returns the map key value pairs as EntryExpr values.
|
||||
Entries() []EntryExpr
|
||||
|
||||
// Size returns the number of entries in the map.
|
||||
Size() int
|
||||
|
||||
// marker interface method
|
||||
isExpr()
|
||||
}
|
||||
|
||||
// MapEntry defines an interface for inspecting a map entry.
|
||||
type MapEntry interface {
|
||||
// Key returns the map entry key expression.
|
||||
Key() Expr
|
||||
|
||||
// Value returns the map entry value expression.
|
||||
Value() Expr
|
||||
|
||||
// IsOptional returns whether the entry is optional.
|
||||
IsOptional() bool
|
||||
|
||||
// marker interface method
|
||||
isEntryExpr()
|
||||
}
|
||||
|
||||
// StructExpr defines an interfaces for inspecting a struct and its field initializers.
|
||||
type StructExpr interface {
|
||||
// TypeName returns the struct type name.
|
||||
TypeName() string
|
||||
|
||||
// Fields returns the set of field initializers in the struct expression as EntryExpr values.
|
||||
Fields() []EntryExpr
|
||||
|
||||
// marker interface method
|
||||
isExpr()
|
||||
}
|
||||
|
||||
// StructField defines an interface for inspecting a struct field initialization.
|
||||
type StructField interface {
|
||||
// Name returns the name of the field.
|
||||
Name() string
|
||||
|
||||
// Value returns the field initialization expression.
|
||||
Value() Expr
|
||||
|
||||
// IsOptional returns whether the field is optional.
|
||||
IsOptional() bool
|
||||
|
||||
// marker interface method
|
||||
isEntryExpr()
|
||||
}
|
||||
|
||||
// ComprehensionExpr defines an interface for inspecting a comprehension expression.
|
||||
type ComprehensionExpr interface {
|
||||
// IterRange returns the iteration range expression.
|
||||
IterRange() Expr
|
||||
|
||||
// IterVar returns the iteration variable name.
|
||||
//
|
||||
// For one-variable comprehensions, the iter var refers to the element value
|
||||
// when iterating over a list, or the map key when iterating over a map.
|
||||
//
|
||||
// For two-variable comprehneions, the iter var refers to the list index or the
|
||||
// map key.
|
||||
IterVar() string
|
||||
|
||||
// IterVar2 returns the second iteration variable name.
|
||||
//
|
||||
// When the value is non-empty, the comprehension is a two-variable comprehension.
|
||||
IterVar2() string
|
||||
|
||||
// HasIterVar2 returns true if the second iteration variable is non-empty.
|
||||
HasIterVar2() bool
|
||||
|
||||
// AccuVar returns the accumulation variable name.
|
||||
AccuVar() string
|
||||
|
||||
// AccuInit returns the accumulation variable initialization expression.
|
||||
AccuInit() Expr
|
||||
|
||||
// LoopCondition returns the loop condition expression.
|
||||
LoopCondition() Expr
|
||||
|
||||
// LoopStep returns the loop step expression.
|
||||
LoopStep() Expr
|
||||
|
||||
// Result returns the comprehension result expression.
|
||||
Result() Expr
|
||||
|
||||
// marker interface method
|
||||
isExpr()
|
||||
}
|
||||
|
||||
var _ Expr = &expr{}
|
||||
|
||||
type expr struct {
|
||||
id int64
|
||||
exprKindCase
|
||||
}
|
||||
|
||||
type exprKindCase interface {
|
||||
Kind() ExprKind
|
||||
|
||||
renumberIDs(IDGenerator)
|
||||
|
||||
isExpr()
|
||||
}
|
||||
|
||||
func (e *expr) ID() int64 {
|
||||
if e == nil {
|
||||
return 0
|
||||
}
|
||||
return e.id
|
||||
}
|
||||
|
||||
func (e *expr) Kind() ExprKind {
|
||||
if e == nil || e.exprKindCase == nil {
|
||||
return UnspecifiedExprKind
|
||||
}
|
||||
return e.exprKindCase.Kind()
|
||||
}
|
||||
|
||||
func (e *expr) AsCall() CallExpr {
|
||||
if e.Kind() != CallKind {
|
||||
return nilCall
|
||||
}
|
||||
return e.exprKindCase.(CallExpr)
|
||||
}
|
||||
|
||||
func (e *expr) AsComprehension() ComprehensionExpr {
|
||||
if e.Kind() != ComprehensionKind {
|
||||
return nilCompre
|
||||
}
|
||||
return e.exprKindCase.(ComprehensionExpr)
|
||||
}
|
||||
|
||||
func (e *expr) AsIdent() string {
|
||||
if e.Kind() != IdentKind {
|
||||
return ""
|
||||
}
|
||||
return string(e.exprKindCase.(baseIdentExpr))
|
||||
}
|
||||
|
||||
func (e *expr) AsLiteral() ref.Val {
|
||||
if e.Kind() != LiteralKind {
|
||||
return nil
|
||||
}
|
||||
return e.exprKindCase.(*baseLiteral).Val
|
||||
}
|
||||
|
||||
func (e *expr) AsList() ListExpr {
|
||||
if e.Kind() != ListKind {
|
||||
return nilList
|
||||
}
|
||||
return e.exprKindCase.(ListExpr)
|
||||
}
|
||||
|
||||
func (e *expr) AsMap() MapExpr {
|
||||
if e.Kind() != MapKind {
|
||||
return nilMap
|
||||
}
|
||||
return e.exprKindCase.(MapExpr)
|
||||
}
|
||||
|
||||
func (e *expr) AsSelect() SelectExpr {
|
||||
if e.Kind() != SelectKind {
|
||||
return nilSel
|
||||
}
|
||||
return e.exprKindCase.(SelectExpr)
|
||||
}
|
||||
|
||||
func (e *expr) AsStruct() StructExpr {
|
||||
if e.Kind() != StructKind {
|
||||
return nilStruct
|
||||
}
|
||||
return e.exprKindCase.(StructExpr)
|
||||
}
|
||||
|
||||
func (e *expr) SetKindCase(other Expr) {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
if other == nil {
|
||||
e.exprKindCase = nil
|
||||
return
|
||||
}
|
||||
switch other.Kind() {
|
||||
case CallKind:
|
||||
c := other.AsCall()
|
||||
e.exprKindCase = &baseCallExpr{
|
||||
function: c.FunctionName(),
|
||||
target: c.Target(),
|
||||
args: c.Args(),
|
||||
isMember: c.IsMemberFunction(),
|
||||
}
|
||||
case ComprehensionKind:
|
||||
c := other.AsComprehension()
|
||||
e.exprKindCase = &baseComprehensionExpr{
|
||||
iterRange: c.IterRange(),
|
||||
iterVar: c.IterVar(),
|
||||
iterVar2: c.IterVar2(),
|
||||
accuVar: c.AccuVar(),
|
||||
accuInit: c.AccuInit(),
|
||||
loopCond: c.LoopCondition(),
|
||||
loopStep: c.LoopStep(),
|
||||
result: c.Result(),
|
||||
}
|
||||
case IdentKind:
|
||||
e.exprKindCase = baseIdentExpr(other.AsIdent())
|
||||
case ListKind:
|
||||
l := other.AsList()
|
||||
optIndexMap := make(map[int32]struct{}, len(l.OptionalIndices()))
|
||||
for _, idx := range l.OptionalIndices() {
|
||||
optIndexMap[idx] = struct{}{}
|
||||
}
|
||||
e.exprKindCase = &baseListExpr{
|
||||
elements: l.Elements(),
|
||||
optIndices: l.OptionalIndices(),
|
||||
optIndexMap: optIndexMap,
|
||||
}
|
||||
case LiteralKind:
|
||||
e.exprKindCase = &baseLiteral{Val: other.AsLiteral()}
|
||||
case MapKind:
|
||||
e.exprKindCase = &baseMapExpr{
|
||||
entries: other.AsMap().Entries(),
|
||||
}
|
||||
case SelectKind:
|
||||
s := other.AsSelect()
|
||||
e.exprKindCase = &baseSelectExpr{
|
||||
operand: s.Operand(),
|
||||
field: s.FieldName(),
|
||||
testOnly: s.IsTestOnly(),
|
||||
}
|
||||
case StructKind:
|
||||
s := other.AsStruct()
|
||||
e.exprKindCase = &baseStructExpr{
|
||||
typeName: s.TypeName(),
|
||||
fields: s.Fields(),
|
||||
}
|
||||
case UnspecifiedExprKind:
|
||||
e.exprKindCase = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *expr) RenumberIDs(idGen IDGenerator) {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
e.id = idGen(e.id)
|
||||
if e.exprKindCase != nil {
|
||||
e.exprKindCase.renumberIDs(idGen)
|
||||
}
|
||||
}
|
||||
|
||||
type baseCallExpr struct {
|
||||
function string
|
||||
target Expr
|
||||
args []Expr
|
||||
isMember bool
|
||||
}
|
||||
|
||||
func (*baseCallExpr) Kind() ExprKind {
|
||||
return CallKind
|
||||
}
|
||||
|
||||
func (e *baseCallExpr) FunctionName() string {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
return e.function
|
||||
}
|
||||
|
||||
func (e *baseCallExpr) IsMemberFunction() bool {
|
||||
if e == nil {
|
||||
return false
|
||||
}
|
||||
return e.isMember
|
||||
}
|
||||
|
||||
func (e *baseCallExpr) Target() Expr {
|
||||
if e == nil || !e.IsMemberFunction() {
|
||||
return nilExpr
|
||||
}
|
||||
return e.target
|
||||
}
|
||||
|
||||
func (e *baseCallExpr) Args() []Expr {
|
||||
if e == nil {
|
||||
return []Expr{}
|
||||
}
|
||||
return e.args
|
||||
}
|
||||
|
||||
func (e *baseCallExpr) renumberIDs(idGen IDGenerator) {
|
||||
if e.IsMemberFunction() {
|
||||
e.Target().RenumberIDs(idGen)
|
||||
}
|
||||
for _, arg := range e.Args() {
|
||||
arg.RenumberIDs(idGen)
|
||||
}
|
||||
}
|
||||
|
||||
func (*baseCallExpr) isExpr() {}
|
||||
|
||||
var _ ComprehensionExpr = &baseComprehensionExpr{}
|
||||
|
||||
type baseComprehensionExpr struct {
|
||||
iterRange Expr
|
||||
iterVar string
|
||||
iterVar2 string
|
||||
accuVar string
|
||||
accuInit Expr
|
||||
loopCond Expr
|
||||
loopStep Expr
|
||||
result Expr
|
||||
}
|
||||
|
||||
func (*baseComprehensionExpr) Kind() ExprKind {
|
||||
return ComprehensionKind
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) IterRange() Expr {
|
||||
if e == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return e.iterRange
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) IterVar() string {
|
||||
return e.iterVar
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) IterVar2() string {
|
||||
return e.iterVar2
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) HasIterVar2() bool {
|
||||
return e.iterVar2 != ""
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) AccuVar() string {
|
||||
return e.accuVar
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) AccuInit() Expr {
|
||||
if e == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return e.accuInit
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) LoopCondition() Expr {
|
||||
if e == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return e.loopCond
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) LoopStep() Expr {
|
||||
if e == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return e.loopStep
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) Result() Expr {
|
||||
if e == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return e.result
|
||||
}
|
||||
|
||||
func (e *baseComprehensionExpr) renumberIDs(idGen IDGenerator) {
|
||||
e.IterRange().RenumberIDs(idGen)
|
||||
e.AccuInit().RenumberIDs(idGen)
|
||||
e.LoopCondition().RenumberIDs(idGen)
|
||||
e.LoopStep().RenumberIDs(idGen)
|
||||
e.Result().RenumberIDs(idGen)
|
||||
}
|
||||
|
||||
func (*baseComprehensionExpr) isExpr() {}
|
||||
|
||||
var _ exprKindCase = baseIdentExpr("")
|
||||
|
||||
type baseIdentExpr string
|
||||
|
||||
func (baseIdentExpr) Kind() ExprKind {
|
||||
return IdentKind
|
||||
}
|
||||
|
||||
func (e baseIdentExpr) renumberIDs(IDGenerator) {}
|
||||
|
||||
func (baseIdentExpr) isExpr() {}
|
||||
|
||||
var _ exprKindCase = &baseLiteral{}
|
||||
var _ ref.Val = &baseLiteral{}
|
||||
|
||||
type baseLiteral struct {
|
||||
ref.Val
|
||||
}
|
||||
|
||||
func (*baseLiteral) Kind() ExprKind {
|
||||
return LiteralKind
|
||||
}
|
||||
|
||||
func (l *baseLiteral) renumberIDs(IDGenerator) {}
|
||||
|
||||
func (*baseLiteral) isExpr() {}
|
||||
|
||||
var _ ListExpr = &baseListExpr{}
|
||||
|
||||
type baseListExpr struct {
|
||||
elements []Expr
|
||||
optIndices []int32
|
||||
optIndexMap map[int32]struct{}
|
||||
}
|
||||
|
||||
func (*baseListExpr) Kind() ExprKind {
|
||||
return ListKind
|
||||
}
|
||||
|
||||
func (e *baseListExpr) Elements() []Expr {
|
||||
if e == nil {
|
||||
return []Expr{}
|
||||
}
|
||||
return e.elements
|
||||
}
|
||||
|
||||
func (e *baseListExpr) IsOptional(index int32) bool {
|
||||
_, found := e.optIndexMap[index]
|
||||
return found
|
||||
}
|
||||
|
||||
func (e *baseListExpr) OptionalIndices() []int32 {
|
||||
if e == nil {
|
||||
return []int32{}
|
||||
}
|
||||
return e.optIndices
|
||||
}
|
||||
|
||||
func (e *baseListExpr) Size() int {
|
||||
return len(e.Elements())
|
||||
}
|
||||
|
||||
func (e *baseListExpr) renumberIDs(idGen IDGenerator) {
|
||||
for _, elem := range e.Elements() {
|
||||
elem.RenumberIDs(idGen)
|
||||
}
|
||||
}
|
||||
|
||||
func (*baseListExpr) isExpr() {}
|
||||
|
||||
type baseMapExpr struct {
|
||||
entries []EntryExpr
|
||||
}
|
||||
|
||||
func (*baseMapExpr) Kind() ExprKind {
|
||||
return MapKind
|
||||
}
|
||||
|
||||
func (e *baseMapExpr) Entries() []EntryExpr {
|
||||
if e == nil {
|
||||
return []EntryExpr{}
|
||||
}
|
||||
return e.entries
|
||||
}
|
||||
|
||||
func (e *baseMapExpr) Size() int {
|
||||
return len(e.Entries())
|
||||
}
|
||||
|
||||
func (e *baseMapExpr) renumberIDs(idGen IDGenerator) {
|
||||
for _, entry := range e.Entries() {
|
||||
entry.RenumberIDs(idGen)
|
||||
}
|
||||
}
|
||||
|
||||
func (*baseMapExpr) isExpr() {}
|
||||
|
||||
type baseSelectExpr struct {
|
||||
operand Expr
|
||||
field string
|
||||
testOnly bool
|
||||
}
|
||||
|
||||
func (*baseSelectExpr) Kind() ExprKind {
|
||||
return SelectKind
|
||||
}
|
||||
|
||||
func (e *baseSelectExpr) Operand() Expr {
|
||||
if e == nil || e.operand == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return e.operand
|
||||
}
|
||||
|
||||
func (e *baseSelectExpr) FieldName() string {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
return e.field
|
||||
}
|
||||
|
||||
func (e *baseSelectExpr) IsTestOnly() bool {
|
||||
if e == nil {
|
||||
return false
|
||||
}
|
||||
return e.testOnly
|
||||
}
|
||||
|
||||
func (e *baseSelectExpr) renumberIDs(idGen IDGenerator) {
|
||||
e.Operand().RenumberIDs(idGen)
|
||||
}
|
||||
|
||||
func (*baseSelectExpr) isExpr() {}
|
||||
|
||||
type baseStructExpr struct {
|
||||
typeName string
|
||||
fields []EntryExpr
|
||||
}
|
||||
|
||||
func (*baseStructExpr) Kind() ExprKind {
|
||||
return StructKind
|
||||
}
|
||||
|
||||
func (e *baseStructExpr) TypeName() string {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
return e.typeName
|
||||
}
|
||||
|
||||
func (e *baseStructExpr) Fields() []EntryExpr {
|
||||
if e == nil {
|
||||
return []EntryExpr{}
|
||||
}
|
||||
return e.fields
|
||||
}
|
||||
|
||||
func (e *baseStructExpr) renumberIDs(idGen IDGenerator) {
|
||||
for _, f := range e.Fields() {
|
||||
f.RenumberIDs(idGen)
|
||||
}
|
||||
}
|
||||
|
||||
func (*baseStructExpr) isExpr() {}
|
||||
|
||||
type entryExprKindCase interface {
|
||||
Kind() EntryExprKind
|
||||
|
||||
renumberIDs(IDGenerator)
|
||||
|
||||
isEntryExpr()
|
||||
}
|
||||
|
||||
var _ EntryExpr = &entryExpr{}
|
||||
|
||||
type entryExpr struct {
|
||||
id int64
|
||||
entryExprKindCase
|
||||
}
|
||||
|
||||
func (e *entryExpr) ID() int64 {
|
||||
return e.id
|
||||
}
|
||||
|
||||
func (e *entryExpr) AsMapEntry() MapEntry {
|
||||
if e.Kind() != MapEntryKind {
|
||||
return nilMapEntry
|
||||
}
|
||||
return e.entryExprKindCase.(MapEntry)
|
||||
}
|
||||
|
||||
func (e *entryExpr) AsStructField() StructField {
|
||||
if e.Kind() != StructFieldKind {
|
||||
return nilStructField
|
||||
}
|
||||
return e.entryExprKindCase.(StructField)
|
||||
}
|
||||
|
||||
func (e *entryExpr) RenumberIDs(idGen IDGenerator) {
|
||||
e.id = idGen(e.id)
|
||||
e.entryExprKindCase.renumberIDs(idGen)
|
||||
}
|
||||
|
||||
type baseMapEntry struct {
|
||||
key Expr
|
||||
value Expr
|
||||
isOptional bool
|
||||
}
|
||||
|
||||
func (e *baseMapEntry) Kind() EntryExprKind {
|
||||
return MapEntryKind
|
||||
}
|
||||
|
||||
func (e *baseMapEntry) Key() Expr {
|
||||
if e == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return e.key
|
||||
}
|
||||
|
||||
func (e *baseMapEntry) Value() Expr {
|
||||
if e == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return e.value
|
||||
}
|
||||
|
||||
func (e *baseMapEntry) IsOptional() bool {
|
||||
if e == nil {
|
||||
return false
|
||||
}
|
||||
return e.isOptional
|
||||
}
|
||||
|
||||
func (e *baseMapEntry) renumberIDs(idGen IDGenerator) {
|
||||
e.Key().RenumberIDs(idGen)
|
||||
e.Value().RenumberIDs(idGen)
|
||||
}
|
||||
|
||||
func (*baseMapEntry) isEntryExpr() {}
|
||||
|
||||
type baseStructField struct {
|
||||
field string
|
||||
value Expr
|
||||
isOptional bool
|
||||
}
|
||||
|
||||
func (f *baseStructField) Kind() EntryExprKind {
|
||||
return StructFieldKind
|
||||
}
|
||||
|
||||
func (f *baseStructField) Name() string {
|
||||
if f == nil {
|
||||
return ""
|
||||
}
|
||||
return f.field
|
||||
}
|
||||
|
||||
func (f *baseStructField) Value() Expr {
|
||||
if f == nil {
|
||||
return nilExpr
|
||||
}
|
||||
return f.value
|
||||
}
|
||||
|
||||
func (f *baseStructField) IsOptional() bool {
|
||||
if f == nil {
|
||||
return false
|
||||
}
|
||||
return f.isOptional
|
||||
}
|
||||
|
||||
func (f *baseStructField) renumberIDs(idGen IDGenerator) {
|
||||
f.Value().RenumberIDs(idGen)
|
||||
}
|
||||
|
||||
func (*baseStructField) isEntryExpr() {}
|
||||
|
||||
var (
|
||||
nilExpr *expr = nil
|
||||
nilCall *baseCallExpr = nil
|
||||
nilCompre *baseComprehensionExpr = nil
|
||||
nilList *baseListExpr = nil
|
||||
nilMap *baseMapExpr = nil
|
||||
nilMapEntry *baseMapEntry = nil
|
||||
nilSel *baseSelectExpr = nil
|
||||
nilStruct *baseStructExpr = nil
|
||||
nilStructField *baseStructField = nil
|
||||
)
|
313
e2e/vendor/github.com/google/cel-go/common/ast/factory.go
generated
vendored
Normal file
313
e2e/vendor/github.com/google/cel-go/common/ast/factory.go
generated
vendored
Normal file
@ -0,0 +1,313 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ast
|
||||
|
||||
import "github.com/google/cel-go/common/types/ref"
|
||||
|
||||
// ExprFactory interfaces defines a set of methods necessary for building native expression values.
|
||||
type ExprFactory interface {
|
||||
// CopyExpr creates a deep copy of the input Expr value.
|
||||
CopyExpr(Expr) Expr
|
||||
|
||||
// CopyEntryExpr creates a deep copy of the input EntryExpr value.
|
||||
CopyEntryExpr(EntryExpr) EntryExpr
|
||||
|
||||
// NewCall creates an Expr value representing a global function call.
|
||||
NewCall(id int64, function string, args ...Expr) Expr
|
||||
|
||||
// NewComprehension creates an Expr value representing a one-variable comprehension over a value range.
|
||||
NewComprehension(id int64, iterRange Expr, iterVar, accuVar string, accuInit, loopCondition, loopStep, result Expr) Expr
|
||||
|
||||
// NewComprehensionTwoVar creates an Expr value representing a two-variable comprehension over a value range.
|
||||
NewComprehensionTwoVar(id int64, iterRange Expr, iterVar, iterVar2, accuVar string, accuInit, loopCondition, loopStep, result Expr) Expr
|
||||
|
||||
// NewMemberCall creates an Expr value representing a member function call.
|
||||
NewMemberCall(id int64, function string, receiver Expr, args ...Expr) Expr
|
||||
|
||||
// NewIdent creates an Expr value representing an identifier.
|
||||
NewIdent(id int64, name string) Expr
|
||||
|
||||
// NewAccuIdent creates an Expr value representing an accumulator identifier within a
|
||||
//comprehension.
|
||||
NewAccuIdent(id int64) Expr
|
||||
|
||||
// NewLiteral creates an Expr value representing a literal value, such as a string or integer.
|
||||
NewLiteral(id int64, value ref.Val) Expr
|
||||
|
||||
// NewList creates an Expr value representing a list literal expression with optional indices.
|
||||
//
|
||||
// Optional indicies will typically be empty unless the CEL optional types are enabled.
|
||||
NewList(id int64, elems []Expr, optIndices []int32) Expr
|
||||
|
||||
// NewMap creates an Expr value representing a map literal expression
|
||||
NewMap(id int64, entries []EntryExpr) Expr
|
||||
|
||||
// NewMapEntry creates a MapEntry with a given key, value, and a flag indicating whether
|
||||
// the key is optionally set.
|
||||
NewMapEntry(id int64, key, value Expr, isOptional bool) EntryExpr
|
||||
|
||||
// NewPresenceTest creates an Expr representing a field presence test on an operand expression.
|
||||
NewPresenceTest(id int64, operand Expr, field string) Expr
|
||||
|
||||
// NewSelect creates an Expr representing a field selection on an operand expression.
|
||||
NewSelect(id int64, operand Expr, field string) Expr
|
||||
|
||||
// NewStruct creates an Expr value representing a struct literal with a given type name and a
|
||||
// set of field initializers.
|
||||
NewStruct(id int64, typeName string, fields []EntryExpr) Expr
|
||||
|
||||
// NewStructField creates a StructField with a given field name, value, and a flag indicating
|
||||
// whether the field is optionally set.
|
||||
NewStructField(id int64, field string, value Expr, isOptional bool) EntryExpr
|
||||
|
||||
// NewUnspecifiedExpr creates an empty expression node.
|
||||
NewUnspecifiedExpr(id int64) Expr
|
||||
|
||||
isExprFactory()
|
||||
}
|
||||
|
||||
type baseExprFactory struct{}
|
||||
|
||||
// NewExprFactory creates an ExprFactory instance.
|
||||
func NewExprFactory() ExprFactory {
|
||||
return &baseExprFactory{}
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewCall(id int64, function string, args ...Expr) Expr {
|
||||
if len(args) == 0 {
|
||||
args = []Expr{}
|
||||
}
|
||||
return fac.newExpr(
|
||||
id,
|
||||
&baseCallExpr{
|
||||
function: function,
|
||||
target: nilExpr,
|
||||
args: args,
|
||||
isMember: false,
|
||||
})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewMemberCall(id int64, function string, target Expr, args ...Expr) Expr {
|
||||
if len(args) == 0 {
|
||||
args = []Expr{}
|
||||
}
|
||||
return fac.newExpr(
|
||||
id,
|
||||
&baseCallExpr{
|
||||
function: function,
|
||||
target: target,
|
||||
args: args,
|
||||
isMember: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewComprehension(id int64, iterRange Expr, iterVar, accuVar string, accuInit, loopCond, loopStep, result Expr) Expr {
|
||||
// Set the iter_var2 to empty string to indicate the second variable is omitted
|
||||
return fac.NewComprehensionTwoVar(id, iterRange, iterVar, "", accuVar, accuInit, loopCond, loopStep, result)
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewComprehensionTwoVar(id int64, iterRange Expr, iterVar, iterVar2, accuVar string, accuInit, loopCond, loopStep, result Expr) Expr {
|
||||
return fac.newExpr(
|
||||
id,
|
||||
&baseComprehensionExpr{
|
||||
iterRange: iterRange,
|
||||
iterVar: iterVar,
|
||||
iterVar2: iterVar2,
|
||||
accuVar: accuVar,
|
||||
accuInit: accuInit,
|
||||
loopCond: loopCond,
|
||||
loopStep: loopStep,
|
||||
result: result,
|
||||
})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewIdent(id int64, name string) Expr {
|
||||
return fac.newExpr(id, baseIdentExpr(name))
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewAccuIdent(id int64) Expr {
|
||||
return fac.NewIdent(id, "__result__")
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewLiteral(id int64, value ref.Val) Expr {
|
||||
return fac.newExpr(id, &baseLiteral{Val: value})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewList(id int64, elems []Expr, optIndices []int32) Expr {
|
||||
optIndexMap := make(map[int32]struct{}, len(optIndices))
|
||||
for _, idx := range optIndices {
|
||||
optIndexMap[idx] = struct{}{}
|
||||
}
|
||||
return fac.newExpr(id,
|
||||
&baseListExpr{
|
||||
elements: elems,
|
||||
optIndices: optIndices,
|
||||
optIndexMap: optIndexMap,
|
||||
})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewMap(id int64, entries []EntryExpr) Expr {
|
||||
return fac.newExpr(id, &baseMapExpr{entries: entries})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewMapEntry(id int64, key, value Expr, isOptional bool) EntryExpr {
|
||||
return fac.newEntryExpr(
|
||||
id,
|
||||
&baseMapEntry{
|
||||
key: key,
|
||||
value: value,
|
||||
isOptional: isOptional,
|
||||
})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewPresenceTest(id int64, operand Expr, field string) Expr {
|
||||
return fac.newExpr(
|
||||
id,
|
||||
&baseSelectExpr{
|
||||
operand: operand,
|
||||
field: field,
|
||||
testOnly: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewSelect(id int64, operand Expr, field string) Expr {
|
||||
return fac.newExpr(
|
||||
id,
|
||||
&baseSelectExpr{
|
||||
operand: operand,
|
||||
field: field,
|
||||
})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewStruct(id int64, typeName string, fields []EntryExpr) Expr {
|
||||
return fac.newExpr(
|
||||
id,
|
||||
&baseStructExpr{
|
||||
typeName: typeName,
|
||||
fields: fields,
|
||||
})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewStructField(id int64, field string, value Expr, isOptional bool) EntryExpr {
|
||||
return fac.newEntryExpr(
|
||||
id,
|
||||
&baseStructField{
|
||||
field: field,
|
||||
value: value,
|
||||
isOptional: isOptional,
|
||||
})
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) NewUnspecifiedExpr(id int64) Expr {
|
||||
return fac.newExpr(id, nil)
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) CopyExpr(e Expr) Expr {
|
||||
// unwrap navigable expressions to avoid unnecessary allocations during copying.
|
||||
if nav, ok := e.(*navigableExprImpl); ok {
|
||||
e = nav.Expr
|
||||
}
|
||||
switch e.Kind() {
|
||||
case CallKind:
|
||||
c := e.AsCall()
|
||||
argsCopy := make([]Expr, len(c.Args()))
|
||||
for i, arg := range c.Args() {
|
||||
argsCopy[i] = fac.CopyExpr(arg)
|
||||
}
|
||||
if !c.IsMemberFunction() {
|
||||
return fac.NewCall(e.ID(), c.FunctionName(), argsCopy...)
|
||||
}
|
||||
return fac.NewMemberCall(e.ID(), c.FunctionName(), fac.CopyExpr(c.Target()), argsCopy...)
|
||||
case ComprehensionKind:
|
||||
compre := e.AsComprehension()
|
||||
return fac.NewComprehensionTwoVar(e.ID(),
|
||||
fac.CopyExpr(compre.IterRange()),
|
||||
compre.IterVar(),
|
||||
compre.IterVar2(),
|
||||
compre.AccuVar(),
|
||||
fac.CopyExpr(compre.AccuInit()),
|
||||
fac.CopyExpr(compre.LoopCondition()),
|
||||
fac.CopyExpr(compre.LoopStep()),
|
||||
fac.CopyExpr(compre.Result()))
|
||||
case IdentKind:
|
||||
return fac.NewIdent(e.ID(), e.AsIdent())
|
||||
case ListKind:
|
||||
l := e.AsList()
|
||||
elemsCopy := make([]Expr, l.Size())
|
||||
for i, elem := range l.Elements() {
|
||||
elemsCopy[i] = fac.CopyExpr(elem)
|
||||
}
|
||||
return fac.NewList(e.ID(), elemsCopy, l.OptionalIndices())
|
||||
case LiteralKind:
|
||||
return fac.NewLiteral(e.ID(), e.AsLiteral())
|
||||
case MapKind:
|
||||
m := e.AsMap()
|
||||
entriesCopy := make([]EntryExpr, m.Size())
|
||||
for i, entry := range m.Entries() {
|
||||
entriesCopy[i] = fac.CopyEntryExpr(entry)
|
||||
}
|
||||
return fac.NewMap(e.ID(), entriesCopy)
|
||||
case SelectKind:
|
||||
s := e.AsSelect()
|
||||
if s.IsTestOnly() {
|
||||
return fac.NewPresenceTest(e.ID(), fac.CopyExpr(s.Operand()), s.FieldName())
|
||||
}
|
||||
return fac.NewSelect(e.ID(), fac.CopyExpr(s.Operand()), s.FieldName())
|
||||
case StructKind:
|
||||
s := e.AsStruct()
|
||||
fieldsCopy := make([]EntryExpr, len(s.Fields()))
|
||||
for i, field := range s.Fields() {
|
||||
fieldsCopy[i] = fac.CopyEntryExpr(field)
|
||||
}
|
||||
return fac.NewStruct(e.ID(), s.TypeName(), fieldsCopy)
|
||||
default:
|
||||
return fac.NewUnspecifiedExpr(e.ID())
|
||||
}
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) CopyEntryExpr(e EntryExpr) EntryExpr {
|
||||
switch e.Kind() {
|
||||
case MapEntryKind:
|
||||
entry := e.AsMapEntry()
|
||||
return fac.NewMapEntry(e.ID(),
|
||||
fac.CopyExpr(entry.Key()), fac.CopyExpr(entry.Value()), entry.IsOptional())
|
||||
case StructFieldKind:
|
||||
field := e.AsStructField()
|
||||
return fac.NewStructField(e.ID(),
|
||||
field.Name(), fac.CopyExpr(field.Value()), field.IsOptional())
|
||||
default:
|
||||
return fac.newEntryExpr(e.ID(), nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (*baseExprFactory) isExprFactory() {}
|
||||
|
||||
func (fac *baseExprFactory) newExpr(id int64, e exprKindCase) Expr {
|
||||
return &expr{
|
||||
id: id,
|
||||
exprKindCase: e,
|
||||
}
|
||||
}
|
||||
|
||||
func (fac *baseExprFactory) newEntryExpr(id int64, e entryExprKindCase) EntryExpr {
|
||||
return &entryExpr{
|
||||
id: id,
|
||||
entryExprKindCase: e,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
defaultFactory = &baseExprFactory{}
|
||||
)
|
660
e2e/vendor/github.com/google/cel-go/common/ast/navigable.go
generated
vendored
Normal file
660
e2e/vendor/github.com/google/cel-go/common/ast/navigable.go
generated
vendored
Normal file
@ -0,0 +1,660 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ast
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// NavigableExpr represents the base navigable expression value with methods to inspect the
|
||||
// parent and child expressions.
|
||||
type NavigableExpr interface {
|
||||
Expr
|
||||
|
||||
// Type of the expression.
|
||||
//
|
||||
// If the expression is type-checked, the type check metadata is returned. If the expression
|
||||
// has not been type-checked, the types.DynType value is returned.
|
||||
Type() *types.Type
|
||||
|
||||
// Parent returns the parent expression node, if one exists.
|
||||
Parent() (NavigableExpr, bool)
|
||||
|
||||
// Children returns a list of child expression nodes.
|
||||
Children() []NavigableExpr
|
||||
|
||||
// Depth indicates the depth in the expression tree.
|
||||
//
|
||||
// The root expression has depth 0.
|
||||
Depth() int
|
||||
}
|
||||
|
||||
// NavigateAST converts an AST to a NavigableExpr
|
||||
func NavigateAST(ast *AST) NavigableExpr {
|
||||
return NavigateExpr(ast, ast.Expr())
|
||||
}
|
||||
|
||||
// NavigateExpr creates a NavigableExpr whose type information is backed by the input AST.
|
||||
//
|
||||
// If the expression is already a NavigableExpr, the parent and depth information will be
|
||||
// propagated on the new NavigableExpr value; otherwise, the expr value will be treated
|
||||
// as though it is the root of the expression graph with a depth of 0.
|
||||
func NavigateExpr(ast *AST, expr Expr) NavigableExpr {
|
||||
depth := 0
|
||||
var parent NavigableExpr = nil
|
||||
if nav, ok := expr.(NavigableExpr); ok {
|
||||
depth = nav.Depth()
|
||||
parent, _ = nav.Parent()
|
||||
}
|
||||
return newNavigableExpr(ast, parent, expr, depth)
|
||||
}
|
||||
|
||||
// ExprMatcher takes a NavigableExpr in and indicates whether the value is a match.
|
||||
//
|
||||
// This function type should be use with the `Match` and `MatchList` calls.
|
||||
type ExprMatcher func(NavigableExpr) bool
|
||||
|
||||
// ConstantValueMatcher returns an ExprMatcher which will return true if the input NavigableExpr
|
||||
// is comprised of all constant values, such as a simple literal or even list and map literal.
|
||||
func ConstantValueMatcher() ExprMatcher {
|
||||
return matchIsConstantValue
|
||||
}
|
||||
|
||||
// KindMatcher returns an ExprMatcher which will return true if the input NavigableExpr.Kind() matches
|
||||
// the specified `kind`.
|
||||
func KindMatcher(kind ExprKind) ExprMatcher {
|
||||
return func(e NavigableExpr) bool {
|
||||
return e.Kind() == kind
|
||||
}
|
||||
}
|
||||
|
||||
// FunctionMatcher returns an ExprMatcher which will match NavigableExpr nodes of CallKind type whose
|
||||
// function name is equal to `funcName`.
|
||||
func FunctionMatcher(funcName string) ExprMatcher {
|
||||
return func(e NavigableExpr) bool {
|
||||
if e.Kind() != CallKind {
|
||||
return false
|
||||
}
|
||||
return e.AsCall().FunctionName() == funcName
|
||||
}
|
||||
}
|
||||
|
||||
// AllMatcher returns true for all descendants of a NavigableExpr, effectively flattening them into a list.
|
||||
//
|
||||
// Such a result would work well with subsequent MatchList calls.
|
||||
func AllMatcher() ExprMatcher {
|
||||
return func(NavigableExpr) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// MatchDescendants takes a NavigableExpr and ExprMatcher and produces a list of NavigableExpr values
|
||||
// matching the input criteria in post-order (bottom up).
|
||||
func MatchDescendants(expr NavigableExpr, matcher ExprMatcher) []NavigableExpr {
|
||||
matches := []NavigableExpr{}
|
||||
navVisitor := &baseVisitor{
|
||||
visitExpr: func(e Expr) {
|
||||
nav := e.(NavigableExpr)
|
||||
if matcher(nav) {
|
||||
matches = append(matches, nav)
|
||||
}
|
||||
},
|
||||
}
|
||||
visit(expr, navVisitor, postOrder, 0, 0)
|
||||
return matches
|
||||
}
|
||||
|
||||
// MatchSubset applies an ExprMatcher to a list of NavigableExpr values and their descendants, producing a
|
||||
// subset of NavigableExpr values which match.
|
||||
func MatchSubset(exprs []NavigableExpr, matcher ExprMatcher) []NavigableExpr {
|
||||
matches := []NavigableExpr{}
|
||||
navVisitor := &baseVisitor{
|
||||
visitExpr: func(e Expr) {
|
||||
nav := e.(NavigableExpr)
|
||||
if matcher(nav) {
|
||||
matches = append(matches, nav)
|
||||
}
|
||||
},
|
||||
}
|
||||
for _, expr := range exprs {
|
||||
visit(expr, navVisitor, postOrder, 0, 1)
|
||||
}
|
||||
return matches
|
||||
}
|
||||
|
||||
// Visitor defines an object for visiting Expr and EntryExpr nodes within an expression graph.
|
||||
type Visitor interface {
|
||||
// VisitExpr visits the input expression.
|
||||
VisitExpr(Expr)
|
||||
|
||||
// VisitEntryExpr visits the input entry expression, i.e. a struct field or map entry.
|
||||
VisitEntryExpr(EntryExpr)
|
||||
}
|
||||
|
||||
type baseVisitor struct {
|
||||
visitExpr func(Expr)
|
||||
visitEntryExpr func(EntryExpr)
|
||||
}
|
||||
|
||||
// VisitExpr visits the Expr if the internal expr visitor has been configured.
|
||||
func (v *baseVisitor) VisitExpr(e Expr) {
|
||||
if v.visitExpr != nil {
|
||||
v.visitExpr(e)
|
||||
}
|
||||
}
|
||||
|
||||
// VisitEntryExpr visits the entry if the internal expr entry visitor has been configured.
|
||||
func (v *baseVisitor) VisitEntryExpr(e EntryExpr) {
|
||||
if v.visitEntryExpr != nil {
|
||||
v.visitEntryExpr(e)
|
||||
}
|
||||
}
|
||||
|
||||
// NewExprVisitor creates a visitor which only visits expression nodes.
|
||||
func NewExprVisitor(v func(Expr)) Visitor {
|
||||
return &baseVisitor{
|
||||
visitExpr: v,
|
||||
visitEntryExpr: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// PostOrderVisit walks the expression graph and calls the visitor in post-order (bottom-up).
|
||||
func PostOrderVisit(expr Expr, visitor Visitor) {
|
||||
visit(expr, visitor, postOrder, 0, 0)
|
||||
}
|
||||
|
||||
// PreOrderVisit walks the expression graph and calls the visitor in pre-order (top-down).
|
||||
func PreOrderVisit(expr Expr, visitor Visitor) {
|
||||
visit(expr, visitor, preOrder, 0, 0)
|
||||
}
|
||||
|
||||
type visitOrder int
|
||||
|
||||
const (
|
||||
preOrder = iota + 1
|
||||
postOrder
|
||||
)
|
||||
|
||||
// TODO: consider exposing a way to configure a limit for the max visit depth.
|
||||
// It's possible that we could want to configure this on the NewExprVisitor()
|
||||
// and through MatchDescendents() / MaxID().
|
||||
func visit(expr Expr, visitor Visitor, order visitOrder, depth, maxDepth int) {
|
||||
if maxDepth > 0 && depth == maxDepth {
|
||||
return
|
||||
}
|
||||
if order == preOrder {
|
||||
visitor.VisitExpr(expr)
|
||||
}
|
||||
switch expr.Kind() {
|
||||
case CallKind:
|
||||
c := expr.AsCall()
|
||||
if c.IsMemberFunction() {
|
||||
visit(c.Target(), visitor, order, depth+1, maxDepth)
|
||||
}
|
||||
for _, arg := range c.Args() {
|
||||
visit(arg, visitor, order, depth+1, maxDepth)
|
||||
}
|
||||
case ComprehensionKind:
|
||||
c := expr.AsComprehension()
|
||||
visit(c.IterRange(), visitor, order, depth+1, maxDepth)
|
||||
visit(c.AccuInit(), visitor, order, depth+1, maxDepth)
|
||||
visit(c.LoopCondition(), visitor, order, depth+1, maxDepth)
|
||||
visit(c.LoopStep(), visitor, order, depth+1, maxDepth)
|
||||
visit(c.Result(), visitor, order, depth+1, maxDepth)
|
||||
case ListKind:
|
||||
l := expr.AsList()
|
||||
for _, elem := range l.Elements() {
|
||||
visit(elem, visitor, order, depth+1, maxDepth)
|
||||
}
|
||||
case MapKind:
|
||||
m := expr.AsMap()
|
||||
for _, e := range m.Entries() {
|
||||
if order == preOrder {
|
||||
visitor.VisitEntryExpr(e)
|
||||
}
|
||||
entry := e.AsMapEntry()
|
||||
visit(entry.Key(), visitor, order, depth+1, maxDepth)
|
||||
visit(entry.Value(), visitor, order, depth+1, maxDepth)
|
||||
if order == postOrder {
|
||||
visitor.VisitEntryExpr(e)
|
||||
}
|
||||
}
|
||||
case SelectKind:
|
||||
visit(expr.AsSelect().Operand(), visitor, order, depth+1, maxDepth)
|
||||
case StructKind:
|
||||
s := expr.AsStruct()
|
||||
for _, f := range s.Fields() {
|
||||
visitor.VisitEntryExpr(f)
|
||||
visit(f.AsStructField().Value(), visitor, order, depth+1, maxDepth)
|
||||
}
|
||||
}
|
||||
if order == postOrder {
|
||||
visitor.VisitExpr(expr)
|
||||
}
|
||||
}
|
||||
|
||||
func matchIsConstantValue(e NavigableExpr) bool {
|
||||
if e.Kind() == LiteralKind {
|
||||
return true
|
||||
}
|
||||
if e.Kind() == StructKind || e.Kind() == MapKind || e.Kind() == ListKind {
|
||||
for _, child := range e.Children() {
|
||||
if !matchIsConstantValue(child) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func newNavigableExpr(ast *AST, parent NavigableExpr, expr Expr, depth int) NavigableExpr {
|
||||
// Reduce navigable expression nesting by unwrapping the embedded Expr value.
|
||||
if nav, ok := expr.(*navigableExprImpl); ok {
|
||||
expr = nav.Expr
|
||||
}
|
||||
nav := &navigableExprImpl{
|
||||
Expr: expr,
|
||||
depth: depth,
|
||||
ast: ast,
|
||||
parent: parent,
|
||||
createChildren: getChildFactory(expr),
|
||||
}
|
||||
return nav
|
||||
}
|
||||
|
||||
type navigableExprImpl struct {
|
||||
Expr
|
||||
depth int
|
||||
ast *AST
|
||||
parent NavigableExpr
|
||||
createChildren childFactory
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) Parent() (NavigableExpr, bool) {
|
||||
if nav.parent != nil {
|
||||
return nav.parent, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) ID() int64 {
|
||||
return nav.Expr.ID()
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) Kind() ExprKind {
|
||||
return nav.Expr.Kind()
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) Type() *types.Type {
|
||||
return nav.ast.GetType(nav.ID())
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) Children() []NavigableExpr {
|
||||
return nav.createChildren(nav)
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) Depth() int {
|
||||
return nav.depth
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) AsCall() CallExpr {
|
||||
return navigableCallImpl{navigableExprImpl: nav}
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) AsComprehension() ComprehensionExpr {
|
||||
return navigableComprehensionImpl{navigableExprImpl: nav}
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) AsIdent() string {
|
||||
return nav.Expr.AsIdent()
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) AsList() ListExpr {
|
||||
return navigableListImpl{navigableExprImpl: nav}
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) AsLiteral() ref.Val {
|
||||
return nav.Expr.AsLiteral()
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) AsMap() MapExpr {
|
||||
return navigableMapImpl{navigableExprImpl: nav}
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) AsSelect() SelectExpr {
|
||||
return navigableSelectImpl{navigableExprImpl: nav}
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) AsStruct() StructExpr {
|
||||
return navigableStructImpl{navigableExprImpl: nav}
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) createChild(e Expr) NavigableExpr {
|
||||
return newNavigableExpr(nav.ast, nav, e, nav.depth+1)
|
||||
}
|
||||
|
||||
func (nav *navigableExprImpl) isExpr() {}
|
||||
|
||||
type navigableCallImpl struct {
|
||||
*navigableExprImpl
|
||||
}
|
||||
|
||||
func (call navigableCallImpl) FunctionName() string {
|
||||
return call.Expr.AsCall().FunctionName()
|
||||
}
|
||||
|
||||
func (call navigableCallImpl) IsMemberFunction() bool {
|
||||
return call.Expr.AsCall().IsMemberFunction()
|
||||
}
|
||||
|
||||
func (call navigableCallImpl) Target() Expr {
|
||||
t := call.Expr.AsCall().Target()
|
||||
if t != nil {
|
||||
return call.createChild(t)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (call navigableCallImpl) Args() []Expr {
|
||||
args := call.Expr.AsCall().Args()
|
||||
navArgs := make([]Expr, len(args))
|
||||
for i, a := range args {
|
||||
navArgs[i] = call.createChild(a)
|
||||
}
|
||||
return navArgs
|
||||
}
|
||||
|
||||
type navigableComprehensionImpl struct {
|
||||
*navigableExprImpl
|
||||
}
|
||||
|
||||
func (comp navigableComprehensionImpl) IterRange() Expr {
|
||||
return comp.createChild(comp.Expr.AsComprehension().IterRange())
|
||||
}
|
||||
|
||||
func (comp navigableComprehensionImpl) IterVar() string {
|
||||
return comp.Expr.AsComprehension().IterVar()
|
||||
}
|
||||
|
||||
func (comp navigableComprehensionImpl) IterVar2() string {
|
||||
return comp.Expr.AsComprehension().IterVar2()
|
||||
}
|
||||
|
||||
func (comp navigableComprehensionImpl) HasIterVar2() bool {
|
||||
return comp.Expr.AsComprehension().HasIterVar2()
|
||||
}
|
||||
|
||||
func (comp navigableComprehensionImpl) AccuVar() string {
|
||||
return comp.Expr.AsComprehension().AccuVar()
|
||||
}
|
||||
|
||||
func (comp navigableComprehensionImpl) AccuInit() Expr {
|
||||
return comp.createChild(comp.Expr.AsComprehension().AccuInit())
|
||||
}
|
||||
|
||||
func (comp navigableComprehensionImpl) LoopCondition() Expr {
|
||||
return comp.createChild(comp.Expr.AsComprehension().LoopCondition())
|
||||
}
|
||||
|
||||
func (comp navigableComprehensionImpl) LoopStep() Expr {
|
||||
return comp.createChild(comp.Expr.AsComprehension().LoopStep())
|
||||
}
|
||||
|
||||
func (comp navigableComprehensionImpl) Result() Expr {
|
||||
return comp.createChild(comp.Expr.AsComprehension().Result())
|
||||
}
|
||||
|
||||
type navigableListImpl struct {
|
||||
*navigableExprImpl
|
||||
}
|
||||
|
||||
func (l navigableListImpl) Elements() []Expr {
|
||||
pbElems := l.Expr.AsList().Elements()
|
||||
elems := make([]Expr, len(pbElems))
|
||||
for i := 0; i < len(pbElems); i++ {
|
||||
elems[i] = l.createChild(pbElems[i])
|
||||
}
|
||||
return elems
|
||||
}
|
||||
|
||||
func (l navigableListImpl) IsOptional(index int32) bool {
|
||||
return l.Expr.AsList().IsOptional(index)
|
||||
}
|
||||
|
||||
func (l navigableListImpl) OptionalIndices() []int32 {
|
||||
return l.Expr.AsList().OptionalIndices()
|
||||
}
|
||||
|
||||
func (l navigableListImpl) Size() int {
|
||||
return l.Expr.AsList().Size()
|
||||
}
|
||||
|
||||
type navigableMapImpl struct {
|
||||
*navigableExprImpl
|
||||
}
|
||||
|
||||
func (m navigableMapImpl) Entries() []EntryExpr {
|
||||
mapExpr := m.Expr.AsMap()
|
||||
entries := make([]EntryExpr, len(mapExpr.Entries()))
|
||||
for i, e := range mapExpr.Entries() {
|
||||
entry := e.AsMapEntry()
|
||||
entries[i] = &entryExpr{
|
||||
id: e.ID(),
|
||||
entryExprKindCase: navigableEntryImpl{
|
||||
key: m.createChild(entry.Key()),
|
||||
val: m.createChild(entry.Value()),
|
||||
isOpt: entry.IsOptional(),
|
||||
},
|
||||
}
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
func (m navigableMapImpl) Size() int {
|
||||
return m.Expr.AsMap().Size()
|
||||
}
|
||||
|
||||
type navigableEntryImpl struct {
|
||||
key NavigableExpr
|
||||
val NavigableExpr
|
||||
isOpt bool
|
||||
}
|
||||
|
||||
func (e navigableEntryImpl) Kind() EntryExprKind {
|
||||
return MapEntryKind
|
||||
}
|
||||
|
||||
func (e navigableEntryImpl) Key() Expr {
|
||||
return e.key
|
||||
}
|
||||
|
||||
func (e navigableEntryImpl) Value() Expr {
|
||||
return e.val
|
||||
}
|
||||
|
||||
func (e navigableEntryImpl) IsOptional() bool {
|
||||
return e.isOpt
|
||||
}
|
||||
|
||||
func (e navigableEntryImpl) renumberIDs(IDGenerator) {}
|
||||
|
||||
func (e navigableEntryImpl) isEntryExpr() {}
|
||||
|
||||
type navigableSelectImpl struct {
|
||||
*navigableExprImpl
|
||||
}
|
||||
|
||||
func (sel navigableSelectImpl) FieldName() string {
|
||||
return sel.Expr.AsSelect().FieldName()
|
||||
}
|
||||
|
||||
func (sel navigableSelectImpl) IsTestOnly() bool {
|
||||
return sel.Expr.AsSelect().IsTestOnly()
|
||||
}
|
||||
|
||||
func (sel navigableSelectImpl) Operand() Expr {
|
||||
return sel.createChild(sel.Expr.AsSelect().Operand())
|
||||
}
|
||||
|
||||
type navigableStructImpl struct {
|
||||
*navigableExprImpl
|
||||
}
|
||||
|
||||
func (s navigableStructImpl) TypeName() string {
|
||||
return s.Expr.AsStruct().TypeName()
|
||||
}
|
||||
|
||||
func (s navigableStructImpl) Fields() []EntryExpr {
|
||||
fieldInits := s.Expr.AsStruct().Fields()
|
||||
fields := make([]EntryExpr, len(fieldInits))
|
||||
for i, f := range fieldInits {
|
||||
field := f.AsStructField()
|
||||
fields[i] = &entryExpr{
|
||||
id: f.ID(),
|
||||
entryExprKindCase: navigableFieldImpl{
|
||||
name: field.Name(),
|
||||
val: s.createChild(field.Value()),
|
||||
isOpt: field.IsOptional(),
|
||||
},
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
type navigableFieldImpl struct {
|
||||
name string
|
||||
val NavigableExpr
|
||||
isOpt bool
|
||||
}
|
||||
|
||||
func (f navigableFieldImpl) Kind() EntryExprKind {
|
||||
return StructFieldKind
|
||||
}
|
||||
|
||||
func (f navigableFieldImpl) Name() string {
|
||||
return f.name
|
||||
}
|
||||
|
||||
func (f navigableFieldImpl) Value() Expr {
|
||||
return f.val
|
||||
}
|
||||
|
||||
func (f navigableFieldImpl) IsOptional() bool {
|
||||
return f.isOpt
|
||||
}
|
||||
|
||||
func (f navigableFieldImpl) renumberIDs(IDGenerator) {}
|
||||
|
||||
func (f navigableFieldImpl) isEntryExpr() {}
|
||||
|
||||
func getChildFactory(expr Expr) childFactory {
|
||||
if expr == nil {
|
||||
return noopFactory
|
||||
}
|
||||
switch expr.Kind() {
|
||||
case LiteralKind:
|
||||
return noopFactory
|
||||
case IdentKind:
|
||||
return noopFactory
|
||||
case SelectKind:
|
||||
return selectFactory
|
||||
case CallKind:
|
||||
return callArgFactory
|
||||
case ListKind:
|
||||
return listElemFactory
|
||||
case MapKind:
|
||||
return mapEntryFactory
|
||||
case StructKind:
|
||||
return structEntryFactory
|
||||
case ComprehensionKind:
|
||||
return comprehensionFactory
|
||||
default:
|
||||
return noopFactory
|
||||
}
|
||||
}
|
||||
|
||||
type childFactory func(*navigableExprImpl) []NavigableExpr
|
||||
|
||||
func noopFactory(*navigableExprImpl) []NavigableExpr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func selectFactory(nav *navigableExprImpl) []NavigableExpr {
|
||||
return []NavigableExpr{nav.createChild(nav.AsSelect().Operand())}
|
||||
}
|
||||
|
||||
func callArgFactory(nav *navigableExprImpl) []NavigableExpr {
|
||||
call := nav.Expr.AsCall()
|
||||
argCount := len(call.Args())
|
||||
if call.IsMemberFunction() {
|
||||
argCount++
|
||||
}
|
||||
navExprs := make([]NavigableExpr, argCount)
|
||||
i := 0
|
||||
if call.IsMemberFunction() {
|
||||
navExprs[i] = nav.createChild(call.Target())
|
||||
i++
|
||||
}
|
||||
for _, arg := range call.Args() {
|
||||
navExprs[i] = nav.createChild(arg)
|
||||
i++
|
||||
}
|
||||
return navExprs
|
||||
}
|
||||
|
||||
func listElemFactory(nav *navigableExprImpl) []NavigableExpr {
|
||||
l := nav.Expr.AsList()
|
||||
navExprs := make([]NavigableExpr, len(l.Elements()))
|
||||
for i, e := range l.Elements() {
|
||||
navExprs[i] = nav.createChild(e)
|
||||
}
|
||||
return navExprs
|
||||
}
|
||||
|
||||
func structEntryFactory(nav *navigableExprImpl) []NavigableExpr {
|
||||
s := nav.Expr.AsStruct()
|
||||
entries := make([]NavigableExpr, len(s.Fields()))
|
||||
for i, e := range s.Fields() {
|
||||
f := e.AsStructField()
|
||||
entries[i] = nav.createChild(f.Value())
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
func mapEntryFactory(nav *navigableExprImpl) []NavigableExpr {
|
||||
m := nav.Expr.AsMap()
|
||||
entries := make([]NavigableExpr, len(m.Entries())*2)
|
||||
j := 0
|
||||
for _, e := range m.Entries() {
|
||||
mapEntry := e.AsMapEntry()
|
||||
entries[j] = nav.createChild(mapEntry.Key())
|
||||
entries[j+1] = nav.createChild(mapEntry.Value())
|
||||
j += 2
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
func comprehensionFactory(nav *navigableExprImpl) []NavigableExpr {
|
||||
compre := nav.Expr.AsComprehension()
|
||||
return []NavigableExpr{
|
||||
nav.createChild(compre.IterRange()),
|
||||
nav.createChild(compre.AccuInit()),
|
||||
nav.createChild(compre.LoopCondition()),
|
||||
nav.createChild(compre.LoopStep()),
|
||||
nav.createChild(compre.Result()),
|
||||
}
|
||||
}
|
31
e2e/vendor/github.com/google/cel-go/common/containers/BUILD.bazel
generated
vendored
Normal file
31
e2e/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 = [
|
||||
"//common/ast:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"container_test.go",
|
||||
],
|
||||
embed = [
|
||||
":go_default_library",
|
||||
],
|
||||
deps = [
|
||||
"//common/ast:go_default_library",
|
||||
],
|
||||
)
|
328
e2e/vendor/github.com/google/cel-go/common/containers/container.go
generated
vendored
Normal file
328
e2e/vendor/github.com/google/cel-go/common/containers/container.go
generated
vendored
Normal file
@ -0,0 +1,328 @@
|
||||
// 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"
|
||||
"unicode"
|
||||
|
||||
"github.com/google/cel-go/common/ast"
|
||||
)
|
||||
|
||||
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 {
|
||||
qn = strings.TrimSpace(qn)
|
||||
for _, r := range qn {
|
||||
if !isIdentifierChar(r) {
|
||||
return nil, fmt.Errorf(
|
||||
"invalid qualified name: %s, wanted name of the form 'qualified.name'", qn)
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func isIdentifierChar(r rune) bool {
|
||||
return r <= unicode.MaxASCII && (r == '.' || r == '_' || unicode.IsLetter(r) || unicode.IsNumber(r))
|
||||
}
|
||||
|
||||
// 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 ast.Expr) (string, bool) {
|
||||
switch e.Kind() {
|
||||
case ast.IdentKind:
|
||||
id := e.AsIdent()
|
||||
return id, true
|
||||
case ast.SelectKind:
|
||||
sel := e.AsSelect()
|
||||
// Test only expressions are not valid as qualified names.
|
||||
if sel.IsTestOnly() {
|
||||
return "", false
|
||||
}
|
||||
if qual, found := ToQualifiedName(sel.Operand()); found {
|
||||
return qual + "." + sel.FieldName(), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
40
e2e/vendor/github.com/google/cel-go/common/cost.go
generated
vendored
Normal file
40
e2e/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
|
||||
)
|
20
e2e/vendor/github.com/google/cel-go/common/debug/BUILD.bazel
generated
vendored
Normal file
20
e2e/vendor/github.com/google/cel-go/common/debug/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 = [
|
||||
"debug.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/debug",
|
||||
deps = [
|
||||
"//common:go_default_library",
|
||||
"//common/ast:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
],
|
||||
)
|
314
e2e/vendor/github.com/google/cel-go/common/debug/debug.go
generated
vendored
Normal file
314
e2e/vendor/github.com/google/cel-go/common/debug/debug.go
generated
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
// 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"
|
||||
|
||||
"github.com/google/cel-go/common/ast"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// 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 any) 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 ast.Expr)
|
||||
}
|
||||
|
||||
type emptyDebugAdorner struct {
|
||||
}
|
||||
|
||||
var emptyAdorner Adorner = &emptyDebugAdorner{}
|
||||
|
||||
func (a *emptyDebugAdorner) GetMetadata(e any) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ToDebugString gives the unadorned string representation of the Expr.
|
||||
func ToDebugString(e ast.Expr) string {
|
||||
return ToAdornedDebugString(e, emptyAdorner)
|
||||
}
|
||||
|
||||
// ToAdornedDebugString gives the adorned string representation of the Expr.
|
||||
func ToAdornedDebugString(e ast.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 ast.Expr) {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
switch e.Kind() {
|
||||
case ast.LiteralKind:
|
||||
w.append(formatLiteral(e.AsLiteral()))
|
||||
case ast.IdentKind:
|
||||
w.append(e.AsIdent())
|
||||
case ast.SelectKind:
|
||||
w.appendSelect(e.AsSelect())
|
||||
case ast.CallKind:
|
||||
w.appendCall(e.AsCall())
|
||||
case ast.ListKind:
|
||||
w.appendList(e.AsList())
|
||||
case ast.MapKind:
|
||||
w.appendMap(e.AsMap())
|
||||
case ast.StructKind:
|
||||
w.appendStruct(e.AsStruct())
|
||||
case ast.ComprehensionKind:
|
||||
w.appendComprehension(e.AsComprehension())
|
||||
}
|
||||
w.adorn(e)
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendSelect(sel ast.SelectExpr) {
|
||||
w.Buffer(sel.Operand())
|
||||
w.append(".")
|
||||
w.append(sel.FieldName())
|
||||
if sel.IsTestOnly() {
|
||||
w.append("~test-only~")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendCall(call ast.CallExpr) {
|
||||
if call.IsMemberFunction() {
|
||||
w.Buffer(call.Target())
|
||||
w.append(".")
|
||||
}
|
||||
w.append(call.FunctionName())
|
||||
w.append("(")
|
||||
if len(call.Args()) > 0 {
|
||||
w.addIndent()
|
||||
w.appendLine()
|
||||
for i, arg := range call.Args() {
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
w.Buffer(arg)
|
||||
}
|
||||
w.removeIndent()
|
||||
w.appendLine()
|
||||
}
|
||||
w.append(")")
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendList(list ast.ListExpr) {
|
||||
w.append("[")
|
||||
if len(list.Elements()) > 0 {
|
||||
w.appendLine()
|
||||
w.addIndent()
|
||||
for i, elem := range list.Elements() {
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
w.Buffer(elem)
|
||||
}
|
||||
w.removeIndent()
|
||||
w.appendLine()
|
||||
}
|
||||
w.append("]")
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendStruct(obj ast.StructExpr) {
|
||||
w.append(obj.TypeName())
|
||||
w.append("{")
|
||||
if len(obj.Fields()) > 0 {
|
||||
w.appendLine()
|
||||
w.addIndent()
|
||||
for i, f := range obj.Fields() {
|
||||
field := f.AsStructField()
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
if field.IsOptional() {
|
||||
w.append("?")
|
||||
}
|
||||
w.append(field.Name())
|
||||
w.append(":")
|
||||
w.Buffer(field.Value())
|
||||
w.adorn(f)
|
||||
}
|
||||
w.removeIndent()
|
||||
w.appendLine()
|
||||
}
|
||||
w.append("}")
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendMap(m ast.MapExpr) {
|
||||
w.append("{")
|
||||
if m.Size() > 0 {
|
||||
w.appendLine()
|
||||
w.addIndent()
|
||||
for i, e := range m.Entries() {
|
||||
entry := e.AsMapEntry()
|
||||
if i > 0 {
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
if entry.IsOptional() {
|
||||
w.append("?")
|
||||
}
|
||||
w.Buffer(entry.Key())
|
||||
w.append(":")
|
||||
w.Buffer(entry.Value())
|
||||
w.adorn(e)
|
||||
}
|
||||
w.removeIndent()
|
||||
w.appendLine()
|
||||
}
|
||||
w.append("}")
|
||||
}
|
||||
|
||||
func (w *debugWriter) appendComprehension(comprehension ast.ComprehensionExpr) {
|
||||
w.append("__comprehension__(")
|
||||
w.addIndent()
|
||||
w.appendLine()
|
||||
w.append("// Variable")
|
||||
w.appendLine()
|
||||
w.append(comprehension.IterVar())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
if comprehension.HasIterVar2() {
|
||||
w.append(comprehension.IterVar2())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
}
|
||||
w.append("// Target")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.IterRange())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Accumulator")
|
||||
w.appendLine()
|
||||
w.append(comprehension.AccuVar())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Init")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.AccuInit())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// LoopCondition")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.LoopCondition())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// LoopStep")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.LoopStep())
|
||||
w.append(",")
|
||||
w.appendLine()
|
||||
w.append("// Result")
|
||||
w.appendLine()
|
||||
w.Buffer(comprehension.Result())
|
||||
w.append(")")
|
||||
w.removeIndent()
|
||||
}
|
||||
|
||||
func formatLiteral(c ref.Val) string {
|
||||
switch v := c.(type) {
|
||||
case types.Bool:
|
||||
return fmt.Sprintf("%t", v)
|
||||
case types.Bytes:
|
||||
return fmt.Sprintf("b\"%s\"", string(v))
|
||||
case types.Double:
|
||||
return fmt.Sprintf("%v", float64(v))
|
||||
case types.Int:
|
||||
return fmt.Sprintf("%d", int64(v))
|
||||
case types.String:
|
||||
return strconv.Quote(string(v))
|
||||
case types.Uint:
|
||||
return fmt.Sprintf("%du", uint64(v))
|
||||
case types.Null:
|
||||
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 ...any) {
|
||||
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 any) {
|
||||
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()
|
||||
}
|
39
e2e/vendor/github.com/google/cel-go/common/decls/BUILD.bazel
generated
vendored
Normal file
39
e2e/vendor/github.com/google/cel-go/common/decls/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
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 = [
|
||||
"decls.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/decls",
|
||||
deps = [
|
||||
"//checker/decls:go_default_library",
|
||||
"//common/functions:go_default_library",
|
||||
"//common/types:go_default_library",
|
||||
"//common/types/ref:go_default_library",
|
||||
"//common/types/traits:go_default_library",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"decls_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//checker/decls: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",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
846
e2e/vendor/github.com/google/cel-go/common/decls/decls.go
generated
vendored
Normal file
846
e2e/vendor/github.com/google/cel-go/common/decls/decls.go
generated
vendored
Normal file
@ -0,0 +1,846 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package decls contains function and variable declaration structs and helper methods.
|
||||
package decls
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
chkdecls "github.com/google/cel-go/checker/decls"
|
||||
"github.com/google/cel-go/common/functions"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
)
|
||||
|
||||
// NewFunction creates a new function declaration with a set of function options to configure overloads
|
||||
// and function definitions (implementations).
|
||||
//
|
||||
// Functions are checked for name collisions and singleton redefinition.
|
||||
func NewFunction(name string, opts ...FunctionOpt) (*FunctionDecl, error) {
|
||||
fn := &FunctionDecl{
|
||||
name: name,
|
||||
overloads: map[string]*OverloadDecl{},
|
||||
overloadOrdinals: []string{},
|
||||
}
|
||||
var err error
|
||||
for _, opt := range opts {
|
||||
fn, err = opt(fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(fn.overloads) == 0 {
|
||||
return nil, fmt.Errorf("function %s must have at least one overload", name)
|
||||
}
|
||||
return fn, nil
|
||||
}
|
||||
|
||||
// FunctionDecl defines a function name, overload set, and optionally a singleton definition for all
|
||||
// overload instances.
|
||||
type FunctionDecl struct {
|
||||
name string
|
||||
|
||||
// overloads associated with the function name.
|
||||
overloads map[string]*OverloadDecl
|
||||
|
||||
// singleton implementation of the function for all overloads.
|
||||
//
|
||||
// If this option is set, an error will occur if any overloads specify a per-overload implementation
|
||||
// or if another function with the same name attempts to redefine the singleton.
|
||||
singleton *functions.Overload
|
||||
|
||||
// disableTypeGuards is a performance optimization to disable detailed runtime type checks which could
|
||||
// add overhead on common operations. Setting this option true leaves error checks and argument checks
|
||||
// intact.
|
||||
disableTypeGuards bool
|
||||
|
||||
// state indicates that the binding should be provided as a declaration, as a runtime binding, or both.
|
||||
state declarationState
|
||||
|
||||
// overloadOrdinals indicates the order in which the overload was declared.
|
||||
overloadOrdinals []string
|
||||
}
|
||||
|
||||
type declarationState int
|
||||
|
||||
const (
|
||||
declarationStateUnset declarationState = iota
|
||||
declarationDisabled
|
||||
declarationEnabled
|
||||
)
|
||||
|
||||
// Name returns the function name in human-readable terms, e.g. 'contains' of 'math.least'
|
||||
func (f *FunctionDecl) Name() string {
|
||||
if f == nil {
|
||||
return ""
|
||||
}
|
||||
return f.name
|
||||
}
|
||||
|
||||
// IsDeclarationDisabled indicates that the function implementation should be added to the dispatcher, but the
|
||||
// declaration should not be exposed for use in expressions.
|
||||
func (f *FunctionDecl) IsDeclarationDisabled() bool {
|
||||
return f.state == declarationDisabled
|
||||
}
|
||||
|
||||
// Merge combines an existing function declaration with another.
|
||||
//
|
||||
// If a function is extended, by say adding new overloads to an existing function, then it is merged with the
|
||||
// prior definition of the function at which point its overloads must not collide with pre-existing overloads
|
||||
// and its bindings (singleton, or per-overload) must not conflict with previous definitions either.
|
||||
func (f *FunctionDecl) Merge(other *FunctionDecl) (*FunctionDecl, error) {
|
||||
if f == other {
|
||||
return f, nil
|
||||
}
|
||||
if f.Name() != other.Name() {
|
||||
return nil, fmt.Errorf("cannot merge unrelated functions. %s and %s", f.Name(), other.Name())
|
||||
}
|
||||
merged := &FunctionDecl{
|
||||
name: f.Name(),
|
||||
overloads: make(map[string]*OverloadDecl, len(f.overloads)),
|
||||
singleton: f.singleton,
|
||||
overloadOrdinals: make([]string, len(f.overloads)),
|
||||
// if one function is expecting type-guards and the other is not, then they
|
||||
// must not be disabled.
|
||||
disableTypeGuards: f.disableTypeGuards && other.disableTypeGuards,
|
||||
// default to the current functions declaration state.
|
||||
state: f.state,
|
||||
}
|
||||
// If the other state indicates that the declaration should be explicitly enabled or
|
||||
// disabled, then update the merged state with the most recent value.
|
||||
if other.state != declarationStateUnset {
|
||||
merged.state = other.state
|
||||
}
|
||||
// baseline copy of the overloads and their ordinals
|
||||
copy(merged.overloadOrdinals, f.overloadOrdinals)
|
||||
for oID, o := range f.overloads {
|
||||
merged.overloads[oID] = o
|
||||
}
|
||||
// overloads and their ordinals are added from the left
|
||||
for _, oID := range other.overloadOrdinals {
|
||||
o := other.overloads[oID]
|
||||
err := merged.AddOverload(o)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("function declaration merge failed: %v", err)
|
||||
}
|
||||
}
|
||||
if other.singleton != nil {
|
||||
if merged.singleton != nil && merged.singleton != other.singleton {
|
||||
return nil, fmt.Errorf("function already has a singleton binding: %s", f.Name())
|
||||
}
|
||||
merged.singleton = other.singleton
|
||||
}
|
||||
return merged, nil
|
||||
}
|
||||
|
||||
// AddOverload ensures that the new overload does not collide with an existing overload signature;
|
||||
// however, if the function signatures are identical, the implementation may be rewritten as its
|
||||
// difficult to compare functions by object identity.
|
||||
func (f *FunctionDecl) AddOverload(overload *OverloadDecl) error {
|
||||
if f == nil {
|
||||
return fmt.Errorf("nil function cannot add overload: %s", overload.ID())
|
||||
}
|
||||
for oID, o := range f.overloads {
|
||||
if oID != overload.ID() && o.SignatureOverlaps(overload) {
|
||||
return fmt.Errorf("overload signature collision in function %s: %s collides with %s", f.Name(), oID, overload.ID())
|
||||
}
|
||||
if oID == overload.ID() {
|
||||
if o.SignatureEquals(overload) && o.IsNonStrict() == overload.IsNonStrict() {
|
||||
// Allow redefinition of an overload implementation so long as the signatures match.
|
||||
if overload.hasBinding() {
|
||||
f.overloads[oID] = overload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("overload redefinition in function. %s: %s has multiple definitions", f.Name(), oID)
|
||||
}
|
||||
}
|
||||
f.overloadOrdinals = append(f.overloadOrdinals, overload.ID())
|
||||
f.overloads[overload.ID()] = overload
|
||||
return nil
|
||||
}
|
||||
|
||||
// OverloadDecls returns the overload declarations in the order in which they were declared.
|
||||
func (f *FunctionDecl) OverloadDecls() []*OverloadDecl {
|
||||
if f == nil {
|
||||
return []*OverloadDecl{}
|
||||
}
|
||||
overloads := make([]*OverloadDecl, 0, len(f.overloads))
|
||||
for _, oID := range f.overloadOrdinals {
|
||||
overloads = append(overloads, f.overloads[oID])
|
||||
}
|
||||
return overloads
|
||||
}
|
||||
|
||||
// Bindings produces a set of function bindings, if any are defined.
|
||||
func (f *FunctionDecl) Bindings() ([]*functions.Overload, error) {
|
||||
if f == nil {
|
||||
return []*functions.Overload{}, nil
|
||||
}
|
||||
overloads := []*functions.Overload{}
|
||||
nonStrict := false
|
||||
for _, oID := range f.overloadOrdinals {
|
||||
o := f.overloads[oID]
|
||||
if o.hasBinding() {
|
||||
overload := &functions.Overload{
|
||||
Operator: o.ID(),
|
||||
Unary: o.guardedUnaryOp(f.Name(), f.disableTypeGuards),
|
||||
Binary: o.guardedBinaryOp(f.Name(), f.disableTypeGuards),
|
||||
Function: o.guardedFunctionOp(f.Name(), f.disableTypeGuards),
|
||||
OperandTrait: o.OperandTrait(),
|
||||
NonStrict: o.IsNonStrict(),
|
||||
}
|
||||
overloads = append(overloads, overload)
|
||||
nonStrict = nonStrict || o.IsNonStrict()
|
||||
}
|
||||
}
|
||||
if f.singleton != nil {
|
||||
if len(overloads) != 0 {
|
||||
return nil, fmt.Errorf("singleton function incompatible with specialized overloads: %s", f.Name())
|
||||
}
|
||||
overloads = []*functions.Overload{
|
||||
{
|
||||
Operator: f.Name(),
|
||||
Unary: f.singleton.Unary,
|
||||
Binary: f.singleton.Binary,
|
||||
Function: f.singleton.Function,
|
||||
OperandTrait: f.singleton.OperandTrait,
|
||||
},
|
||||
}
|
||||
// fall-through to return single overload case.
|
||||
}
|
||||
if len(overloads) == 0 {
|
||||
return overloads, nil
|
||||
}
|
||||
// Single overload. Replicate an entry for it using the function name as well.
|
||||
if len(overloads) == 1 {
|
||||
if overloads[0].Operator == f.Name() {
|
||||
return overloads, nil
|
||||
}
|
||||
return append(overloads, &functions.Overload{
|
||||
Operator: f.Name(),
|
||||
Unary: overloads[0].Unary,
|
||||
Binary: overloads[0].Binary,
|
||||
Function: overloads[0].Function,
|
||||
NonStrict: overloads[0].NonStrict,
|
||||
OperandTrait: overloads[0].OperandTrait,
|
||||
}), nil
|
||||
}
|
||||
// All of the defined overloads are wrapped into a top-level function which
|
||||
// performs dynamic dispatch to the proper overload based on the argument types.
|
||||
bindings := append([]*functions.Overload{}, overloads...)
|
||||
funcDispatch := func(args ...ref.Val) ref.Val {
|
||||
for _, oID := range f.overloadOrdinals {
|
||||
o := f.overloads[oID]
|
||||
// During dynamic dispatch over multiple functions, signature agreement checks
|
||||
// are preserved in order to assist with the function resolution step.
|
||||
switch len(args) {
|
||||
case 1:
|
||||
if o.unaryOp != nil && o.matchesRuntimeSignature(f.disableTypeGuards, args...) {
|
||||
return o.unaryOp(args[0])
|
||||
}
|
||||
case 2:
|
||||
if o.binaryOp != nil && o.matchesRuntimeSignature(f.disableTypeGuards, args...) {
|
||||
return o.binaryOp(args[0], args[1])
|
||||
}
|
||||
}
|
||||
if o.functionOp != nil && o.matchesRuntimeSignature(f.disableTypeGuards, args...) {
|
||||
return o.functionOp(args...)
|
||||
}
|
||||
// eventually this will fall through to the noSuchOverload below.
|
||||
}
|
||||
return MaybeNoSuchOverload(f.Name(), args...)
|
||||
}
|
||||
function := &functions.Overload{
|
||||
Operator: f.Name(),
|
||||
Function: funcDispatch,
|
||||
NonStrict: nonStrict,
|
||||
}
|
||||
return append(bindings, function), nil
|
||||
}
|
||||
|
||||
// MaybeNoSuchOverload determines whether to propagate an error if one is provided as an argument, or
|
||||
// to return an unknown set, or to produce a new error for a missing function signature.
|
||||
func MaybeNoSuchOverload(funcName string, args ...ref.Val) ref.Val {
|
||||
argTypes := make([]string, len(args))
|
||||
var unk *types.Unknown = nil
|
||||
for i, arg := range args {
|
||||
if types.IsError(arg) {
|
||||
return arg
|
||||
}
|
||||
if types.IsUnknown(arg) {
|
||||
unk = types.MergeUnknowns(arg.(*types.Unknown), unk)
|
||||
}
|
||||
argTypes[i] = arg.Type().TypeName()
|
||||
}
|
||||
if unk != nil {
|
||||
return unk
|
||||
}
|
||||
signature := strings.Join(argTypes, ", ")
|
||||
return types.NewErr("no such overload: %s(%s)", funcName, signature)
|
||||
}
|
||||
|
||||
// FunctionOpt defines a functional option for mutating a function declaration.
|
||||
type FunctionOpt func(*FunctionDecl) (*FunctionDecl, error)
|
||||
|
||||
// DisableTypeGuards disables automatically generated function invocation guards on direct overload calls.
|
||||
// Type guards remain on during dynamic dispatch for parsed-only expressions.
|
||||
func DisableTypeGuards(value bool) FunctionOpt {
|
||||
return func(fn *FunctionDecl) (*FunctionDecl, error) {
|
||||
fn.disableTypeGuards = value
|
||||
return fn, nil
|
||||
}
|
||||
}
|
||||
|
||||
// DisableDeclaration indicates that the function declaration should be disabled, but the runtime function
|
||||
// binding should be provided. Marking a function as runtime-only is a safe way to manage deprecations
|
||||
// of function declarations while still preserving the runtime behavior for previously compiled expressions.
|
||||
func DisableDeclaration(value bool) FunctionOpt {
|
||||
return func(fn *FunctionDecl) (*FunctionDecl, error) {
|
||||
if value {
|
||||
fn.state = declarationDisabled
|
||||
} else {
|
||||
fn.state = declarationEnabled
|
||||
}
|
||||
return fn, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SingletonUnaryBinding creates a singleton function definition to be used for all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
func SingletonUnaryBinding(fn functions.UnaryOp, traits ...int) FunctionOpt {
|
||||
trait := 0
|
||||
for _, t := range traits {
|
||||
trait = trait | t
|
||||
}
|
||||
return func(f *FunctionDecl) (*FunctionDecl, error) {
|
||||
if f.singleton != nil {
|
||||
return nil, fmt.Errorf("function already has a singleton binding: %s", f.Name())
|
||||
}
|
||||
f.singleton = &functions.Overload{
|
||||
Operator: f.Name(),
|
||||
Unary: fn,
|
||||
OperandTrait: trait,
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SingletonBinaryBinding creates a singleton function definition to be used with all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
func SingletonBinaryBinding(fn functions.BinaryOp, traits ...int) FunctionOpt {
|
||||
trait := 0
|
||||
for _, t := range traits {
|
||||
trait = trait | t
|
||||
}
|
||||
return func(f *FunctionDecl) (*FunctionDecl, error) {
|
||||
if f.singleton != nil {
|
||||
return nil, fmt.Errorf("function already has a singleton binding: %s", f.Name())
|
||||
}
|
||||
f.singleton = &functions.Overload{
|
||||
Operator: f.Name(),
|
||||
Binary: fn,
|
||||
OperandTrait: trait,
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SingletonFunctionBinding creates a singleton function definition to be used with all function overloads.
|
||||
//
|
||||
// Note, this approach works well if operand is expected to have a specific trait which it implements,
|
||||
// e.g. traits.ContainerType. Otherwise, prefer per-overload function bindings.
|
||||
func SingletonFunctionBinding(fn functions.FunctionOp, traits ...int) FunctionOpt {
|
||||
trait := 0
|
||||
for _, t := range traits {
|
||||
trait = trait | t
|
||||
}
|
||||
return func(f *FunctionDecl) (*FunctionDecl, error) {
|
||||
if f.singleton != nil {
|
||||
return nil, fmt.Errorf("function already has a singleton binding: %s", f.Name())
|
||||
}
|
||||
f.singleton = &functions.Overload{
|
||||
Operator: f.Name(),
|
||||
Function: fn,
|
||||
OperandTrait: trait,
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Overload defines a new global overload with an overload id, argument types, and result type. Through the
|
||||
// use of OverloadOpt options, the overload may also be configured with a binding, an operand trait, and to
|
||||
// be non-strict.
|
||||
//
|
||||
// Note: function bindings should be commonly configured with Overload instances whereas operand traits and
|
||||
// strict-ness should be rare occurrences.
|
||||
func Overload(overloadID string,
|
||||
args []*types.Type, resultType *types.Type,
|
||||
opts ...OverloadOpt) FunctionOpt {
|
||||
return newOverload(overloadID, false, args, resultType, opts...)
|
||||
}
|
||||
|
||||
// MemberOverload defines a new receiver-style overload (or member function) with an overload id, argument types,
|
||||
// and result type. Through the use of OverloadOpt options, the overload may also be configured with a binding,
|
||||
// an operand trait, and to be non-strict.
|
||||
//
|
||||
// Note: function bindings should be commonly configured with Overload instances whereas operand traits and
|
||||
// strict-ness should be rare occurrences.
|
||||
func MemberOverload(overloadID string,
|
||||
args []*types.Type, resultType *types.Type,
|
||||
opts ...OverloadOpt) FunctionOpt {
|
||||
return newOverload(overloadID, true, args, resultType, opts...)
|
||||
}
|
||||
|
||||
func newOverload(overloadID string,
|
||||
memberFunction bool, args []*types.Type, resultType *types.Type,
|
||||
opts ...OverloadOpt) FunctionOpt {
|
||||
return func(f *FunctionDecl) (*FunctionDecl, error) {
|
||||
overload, err := newOverloadInternal(overloadID, memberFunction, args, resultType, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = f.AddOverload(overload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
func newOverloadInternal(overloadID string,
|
||||
memberFunction bool, args []*types.Type, resultType *types.Type,
|
||||
opts ...OverloadOpt) (*OverloadDecl, error) {
|
||||
overload := &OverloadDecl{
|
||||
id: overloadID,
|
||||
argTypes: args,
|
||||
resultType: resultType,
|
||||
isMemberFunction: memberFunction,
|
||||
}
|
||||
var err error
|
||||
for _, opt := range opts {
|
||||
overload, err = opt(overload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return overload, nil
|
||||
}
|
||||
|
||||
// OverloadDecl contains the definition of a single overload id with a specific signature, and an optional
|
||||
// implementation.
|
||||
type OverloadDecl struct {
|
||||
id string
|
||||
argTypes []*types.Type
|
||||
resultType *types.Type
|
||||
isMemberFunction bool
|
||||
// nonStrict indicates that the function will accept error and unknown arguments as inputs.
|
||||
nonStrict bool
|
||||
// operandTrait indicates whether the member argument should have a specific type-trait.
|
||||
//
|
||||
// This is useful for creating overloads which operate on a type-interface rather than a concrete type.
|
||||
operandTrait int
|
||||
|
||||
// Function implementation options. Optional, but encouraged.
|
||||
// unaryOp is a function binding that takes a single argument.
|
||||
unaryOp functions.UnaryOp
|
||||
// binaryOp is a function binding that takes two arguments.
|
||||
binaryOp functions.BinaryOp
|
||||
// functionOp is a catch-all for zero-arity and three-plus arity functions.
|
||||
functionOp functions.FunctionOp
|
||||
}
|
||||
|
||||
// ID mirrors the overload signature and provides a unique id which may be referenced within the type-checker
|
||||
// and interpreter to optimize performance.
|
||||
//
|
||||
// The ID format is usually one of two styles:
|
||||
// global: <functionName>_<argType>_<argTypeN>
|
||||
// member: <memberType>_<functionName>_<argType>_<argTypeN>
|
||||
func (o *OverloadDecl) ID() string {
|
||||
if o == nil {
|
||||
return ""
|
||||
}
|
||||
return o.id
|
||||
}
|
||||
|
||||
// ArgTypes contains the set of argument types expected by the overload.
|
||||
//
|
||||
// For member functions ArgTypes[0] represents the member operand type.
|
||||
func (o *OverloadDecl) ArgTypes() []*types.Type {
|
||||
if o == nil {
|
||||
return emptyArgs
|
||||
}
|
||||
return o.argTypes
|
||||
}
|
||||
|
||||
// IsMemberFunction indicates whether the overload is a member function
|
||||
func (o *OverloadDecl) IsMemberFunction() bool {
|
||||
if o == nil {
|
||||
return false
|
||||
}
|
||||
return o.isMemberFunction
|
||||
}
|
||||
|
||||
// IsNonStrict returns whether the overload accepts errors and unknown values as arguments.
|
||||
func (o *OverloadDecl) IsNonStrict() bool {
|
||||
if o == nil {
|
||||
return false
|
||||
}
|
||||
return o.nonStrict
|
||||
}
|
||||
|
||||
// OperandTrait returns the trait mask of the first operand to the overload call, e.g.
|
||||
// `traits.Indexer`
|
||||
func (o *OverloadDecl) OperandTrait() int {
|
||||
if o == nil {
|
||||
return 0
|
||||
}
|
||||
return o.operandTrait
|
||||
}
|
||||
|
||||
// ResultType indicates the output type from calling the function.
|
||||
func (o *OverloadDecl) ResultType() *types.Type {
|
||||
if o == nil {
|
||||
// *types.Type is nil-safe
|
||||
return nil
|
||||
}
|
||||
return o.resultType
|
||||
}
|
||||
|
||||
// TypeParams returns the type parameter names associated with the overload.
|
||||
func (o *OverloadDecl) TypeParams() []string {
|
||||
typeParams := map[string]struct{}{}
|
||||
collectParamNames(typeParams, o.ResultType())
|
||||
for _, arg := range o.ArgTypes() {
|
||||
collectParamNames(typeParams, arg)
|
||||
}
|
||||
params := make([]string, 0, len(typeParams))
|
||||
for param := range typeParams {
|
||||
params = append(params, param)
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
// SignatureEquals determines whether the incoming overload declaration signature is equal to the current signature.
|
||||
//
|
||||
// Result type, operand trait, and strict-ness are not considered as part of signature equality.
|
||||
func (o *OverloadDecl) SignatureEquals(other *OverloadDecl) bool {
|
||||
if o == other {
|
||||
return true
|
||||
}
|
||||
if o.ID() != other.ID() || o.IsMemberFunction() != other.IsMemberFunction() || len(o.ArgTypes()) != len(other.ArgTypes()) {
|
||||
return false
|
||||
}
|
||||
for i, at := range o.ArgTypes() {
|
||||
oat := other.ArgTypes()[i]
|
||||
if !at.IsEquivalentType(oat) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return o.ResultType().IsEquivalentType(other.ResultType())
|
||||
}
|
||||
|
||||
// SignatureOverlaps indicates whether two functions have non-equal, but overloapping function signatures.
|
||||
//
|
||||
// For example, list(dyn) collides with list(string) since the 'dyn' type can contain a 'string' type.
|
||||
func (o *OverloadDecl) SignatureOverlaps(other *OverloadDecl) bool {
|
||||
if o.IsMemberFunction() != other.IsMemberFunction() || len(o.ArgTypes()) != len(other.ArgTypes()) {
|
||||
return false
|
||||
}
|
||||
argsOverlap := true
|
||||
for i, argType := range o.ArgTypes() {
|
||||
otherArgType := other.ArgTypes()[i]
|
||||
argsOverlap = argsOverlap &&
|
||||
(argType.IsAssignableType(otherArgType) ||
|
||||
otherArgType.IsAssignableType(argType))
|
||||
}
|
||||
return argsOverlap
|
||||
}
|
||||
|
||||
// hasBinding indicates whether the overload already has a definition.
|
||||
func (o *OverloadDecl) hasBinding() bool {
|
||||
return o != nil && (o.unaryOp != nil || o.binaryOp != nil || o.functionOp != nil)
|
||||
}
|
||||
|
||||
// guardedUnaryOp creates an invocation guard around the provided unary operator, if one is defined.
|
||||
func (o *OverloadDecl) guardedUnaryOp(funcName string, disableTypeGuards bool) functions.UnaryOp {
|
||||
if o.unaryOp == nil {
|
||||
return nil
|
||||
}
|
||||
return func(arg ref.Val) ref.Val {
|
||||
if !o.matchesRuntimeUnarySignature(disableTypeGuards, arg) {
|
||||
return MaybeNoSuchOverload(funcName, arg)
|
||||
}
|
||||
return o.unaryOp(arg)
|
||||
}
|
||||
}
|
||||
|
||||
// guardedBinaryOp creates an invocation guard around the provided binary operator, if one is defined.
|
||||
func (o *OverloadDecl) guardedBinaryOp(funcName string, disableTypeGuards bool) functions.BinaryOp {
|
||||
if o.binaryOp == nil {
|
||||
return nil
|
||||
}
|
||||
return func(arg1, arg2 ref.Val) ref.Val {
|
||||
if !o.matchesRuntimeBinarySignature(disableTypeGuards, arg1, arg2) {
|
||||
return MaybeNoSuchOverload(funcName, arg1, arg2)
|
||||
}
|
||||
return o.binaryOp(arg1, arg2)
|
||||
}
|
||||
}
|
||||
|
||||
// guardedFunctionOp creates an invocation guard around the provided variadic function binding, if one is provided.
|
||||
func (o *OverloadDecl) guardedFunctionOp(funcName string, disableTypeGuards bool) functions.FunctionOp {
|
||||
if o.functionOp == nil {
|
||||
return nil
|
||||
}
|
||||
return func(args ...ref.Val) ref.Val {
|
||||
if !o.matchesRuntimeSignature(disableTypeGuards, args...) {
|
||||
return MaybeNoSuchOverload(funcName, args...)
|
||||
}
|
||||
return o.functionOp(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// matchesRuntimeUnarySignature indicates whether the argument type is runtime assiganble to the overload's expected argument.
|
||||
func (o *OverloadDecl) matchesRuntimeUnarySignature(disableTypeGuards bool, arg ref.Val) bool {
|
||||
return matchRuntimeArgType(o.IsNonStrict(), disableTypeGuards, o.ArgTypes()[0], arg) &&
|
||||
matchOperandTrait(o.OperandTrait(), arg)
|
||||
}
|
||||
|
||||
// matchesRuntimeBinarySignature indicates whether the argument types are runtime assiganble to the overload's expected arguments.
|
||||
func (o *OverloadDecl) matchesRuntimeBinarySignature(disableTypeGuards bool, arg1, arg2 ref.Val) bool {
|
||||
return matchRuntimeArgType(o.IsNonStrict(), disableTypeGuards, o.ArgTypes()[0], arg1) &&
|
||||
matchRuntimeArgType(o.IsNonStrict(), disableTypeGuards, o.ArgTypes()[1], arg2) &&
|
||||
matchOperandTrait(o.OperandTrait(), arg1)
|
||||
}
|
||||
|
||||
// matchesRuntimeSignature indicates whether the argument types are runtime assiganble to the overload's expected arguments.
|
||||
func (o *OverloadDecl) matchesRuntimeSignature(disableTypeGuards bool, args ...ref.Val) bool {
|
||||
if len(args) != len(o.ArgTypes()) {
|
||||
return false
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return true
|
||||
}
|
||||
for i, arg := range args {
|
||||
if !matchRuntimeArgType(o.IsNonStrict(), disableTypeGuards, o.ArgTypes()[i], arg) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return matchOperandTrait(o.OperandTrait(), args[0])
|
||||
}
|
||||
|
||||
func matchRuntimeArgType(nonStrict, disableTypeGuards bool, argType *types.Type, arg ref.Val) bool {
|
||||
if nonStrict && (disableTypeGuards || types.IsUnknownOrError(arg)) {
|
||||
return true
|
||||
}
|
||||
if types.IsUnknownOrError(arg) {
|
||||
return false
|
||||
}
|
||||
return disableTypeGuards || argType.IsAssignableRuntimeType(arg)
|
||||
}
|
||||
|
||||
func matchOperandTrait(trait int, arg ref.Val) bool {
|
||||
return trait == 0 || arg.Type().HasTrait(trait) || types.IsUnknownOrError(arg)
|
||||
}
|
||||
|
||||
// OverloadOpt is a functional option for configuring a function overload.
|
||||
type OverloadOpt func(*OverloadDecl) (*OverloadDecl, error)
|
||||
|
||||
// UnaryBinding provides the implementation of a unary overload. The provided function is protected by a runtime
|
||||
// type-guard which ensures runtime type agreement between the overload signature and runtime argument types.
|
||||
func UnaryBinding(binding functions.UnaryOp) OverloadOpt {
|
||||
return func(o *OverloadDecl) (*OverloadDecl, error) {
|
||||
if o.hasBinding() {
|
||||
return nil, fmt.Errorf("overload already has a binding: %s", o.ID())
|
||||
}
|
||||
if len(o.ArgTypes()) != 1 {
|
||||
return nil, fmt.Errorf("unary function bound to non-unary overload: %s", o.ID())
|
||||
}
|
||||
o.unaryOp = binding
|
||||
return o, nil
|
||||
}
|
||||
}
|
||||
|
||||
// BinaryBinding provides the implementation of a binary overload. The provided function is protected by a runtime
|
||||
// type-guard which ensures runtime type agreement between the overload signature and runtime argument types.
|
||||
func BinaryBinding(binding functions.BinaryOp) OverloadOpt {
|
||||
return func(o *OverloadDecl) (*OverloadDecl, error) {
|
||||
if o.hasBinding() {
|
||||
return nil, fmt.Errorf("overload already has a binding: %s", o.ID())
|
||||
}
|
||||
if len(o.ArgTypes()) != 2 {
|
||||
return nil, fmt.Errorf("binary function bound to non-binary overload: %s", o.ID())
|
||||
}
|
||||
o.binaryOp = binding
|
||||
return o, nil
|
||||
}
|
||||
}
|
||||
|
||||
// FunctionBinding provides the implementation of a variadic overload. The provided function is protected by a runtime
|
||||
// type-guard which ensures runtime type agreement between the overload signature and runtime argument types.
|
||||
func FunctionBinding(binding functions.FunctionOp) OverloadOpt {
|
||||
return func(o *OverloadDecl) (*OverloadDecl, error) {
|
||||
if o.hasBinding() {
|
||||
return nil, fmt.Errorf("overload already has a binding: %s", o.ID())
|
||||
}
|
||||
o.functionOp = binding
|
||||
return o, nil
|
||||
}
|
||||
}
|
||||
|
||||
// OverloadIsNonStrict enables the function to be called with error and unknown argument values.
|
||||
//
|
||||
// Note: do not use this option unless absoluately necessary as it should be an uncommon feature.
|
||||
func OverloadIsNonStrict() OverloadOpt {
|
||||
return func(o *OverloadDecl) (*OverloadDecl, error) {
|
||||
o.nonStrict = true
|
||||
return o, nil
|
||||
}
|
||||
}
|
||||
|
||||
// OverloadOperandTrait configures a set of traits which the first argument to the overload must implement in order to be
|
||||
// successfully invoked.
|
||||
func OverloadOperandTrait(trait int) OverloadOpt {
|
||||
return func(o *OverloadDecl) (*OverloadDecl, error) {
|
||||
o.operandTrait = trait
|
||||
return o, nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewConstant creates a new constant declaration.
|
||||
func NewConstant(name string, t *types.Type, v ref.Val) *VariableDecl {
|
||||
return &VariableDecl{name: name, varType: t, value: v}
|
||||
}
|
||||
|
||||
// NewVariable creates a new variable declaration.
|
||||
func NewVariable(name string, t *types.Type) *VariableDecl {
|
||||
return &VariableDecl{name: name, varType: t}
|
||||
}
|
||||
|
||||
// VariableDecl defines a variable declaration which may optionally have a constant value.
|
||||
type VariableDecl struct {
|
||||
name string
|
||||
varType *types.Type
|
||||
value ref.Val
|
||||
}
|
||||
|
||||
// Name returns the fully-qualified variable name
|
||||
func (v *VariableDecl) Name() string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
return v.name
|
||||
}
|
||||
|
||||
// Type returns the types.Type value associated with the variable.
|
||||
func (v *VariableDecl) Type() *types.Type {
|
||||
if v == nil {
|
||||
// types.Type is nil-safe
|
||||
return nil
|
||||
}
|
||||
return v.varType
|
||||
}
|
||||
|
||||
// Value returns the constant value associated with the declaration.
|
||||
func (v *VariableDecl) Value() ref.Val {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return v.value
|
||||
}
|
||||
|
||||
// DeclarationIsEquivalent returns true if one variable declaration has the same name and same type as the input.
|
||||
func (v *VariableDecl) DeclarationIsEquivalent(other *VariableDecl) bool {
|
||||
if v == other {
|
||||
return true
|
||||
}
|
||||
return v.Name() == other.Name() && v.Type().IsEquivalentType(other.Type())
|
||||
}
|
||||
|
||||
// TypeVariable creates a new type identifier for use within a types.Provider
|
||||
func TypeVariable(t *types.Type) *VariableDecl {
|
||||
return NewVariable(t.TypeName(), types.NewTypeTypeWithParam(t))
|
||||
}
|
||||
|
||||
// variableDeclToExprDecl converts a go-native variable declaration into a protobuf-type variable declaration.
|
||||
func variableDeclToExprDecl(v *VariableDecl) (*exprpb.Decl, error) {
|
||||
varType, err := types.TypeToExprType(v.Type())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return chkdecls.NewVar(v.Name(), varType), nil
|
||||
}
|
||||
|
||||
// functionDeclToExprDecl converts a go-native function declaration into a protobuf-typed function declaration.
|
||||
func functionDeclToExprDecl(f *FunctionDecl) (*exprpb.Decl, error) {
|
||||
overloads := make([]*exprpb.Decl_FunctionDecl_Overload, len(f.overloads))
|
||||
for i, oID := range f.overloadOrdinals {
|
||||
o := f.overloads[oID]
|
||||
paramNames := map[string]struct{}{}
|
||||
argTypes := make([]*exprpb.Type, len(o.ArgTypes()))
|
||||
for j, a := range o.ArgTypes() {
|
||||
collectParamNames(paramNames, a)
|
||||
at, err := types.TypeToExprType(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
argTypes[j] = at
|
||||
}
|
||||
collectParamNames(paramNames, o.ResultType())
|
||||
resultType, err := types.TypeToExprType(o.ResultType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(paramNames) == 0 {
|
||||
if o.IsMemberFunction() {
|
||||
overloads[i] = chkdecls.NewInstanceOverload(oID, argTypes, resultType)
|
||||
} else {
|
||||
overloads[i] = chkdecls.NewOverload(oID, argTypes, resultType)
|
||||
}
|
||||
} else {
|
||||
params := []string{}
|
||||
for pn := range paramNames {
|
||||
params = append(params, pn)
|
||||
}
|
||||
if o.IsMemberFunction() {
|
||||
overloads[i] = chkdecls.NewParameterizedInstanceOverload(oID, argTypes, resultType, params)
|
||||
} else {
|
||||
overloads[i] = chkdecls.NewParameterizedOverload(oID, argTypes, resultType, params)
|
||||
}
|
||||
}
|
||||
}
|
||||
return chkdecls.NewFunction(f.Name(), overloads...), nil
|
||||
}
|
||||
|
||||
func collectParamNames(paramNames map[string]struct{}, arg *types.Type) {
|
||||
if arg.Kind() == types.TypeParamKind {
|
||||
paramNames[arg.TypeName()] = struct{}{}
|
||||
}
|
||||
for _, param := range arg.Parameters() {
|
||||
collectParamNames(paramNames, param)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
emptyArgs = []*types.Type{}
|
||||
)
|
17
e2e/vendor/github.com/google/cel-go/common/doc.go
generated
vendored
Normal file
17
e2e/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
|
74
e2e/vendor/github.com/google/cel-go/common/error.go
generated
vendored
Normal file
74
e2e/vendor/github.com/google/cel-go/common/error.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2018 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// NewError creates an error associated with an expression id with the given message at the given location.
|
||||
func NewError(id int64, message string, location Location) *Error {
|
||||
return &Error{Message: message, Location: location, ExprID: id}
|
||||
}
|
||||
|
||||
// Error type which references an expression id, a location within source, and a message.
|
||||
type Error struct {
|
||||
Location Location
|
||||
Message string
|
||||
ExprID int64
|
||||
}
|
||||
|
||||
const (
|
||||
dot = "."
|
||||
ind = "^"
|
||||
wideDot = "\uff0e"
|
||||
wideInd = "\uff3e"
|
||||
|
||||
// maxSnippetLength is the largest number of characters which can be rendered in an error message snippet.
|
||||
maxSnippetLength = 16384
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
103
e2e/vendor/github.com/google/cel-go/common/errors.go
generated
vendored
Normal file
103
e2e/vendor/github.com/google/cel-go/common/errors.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 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 ...any) {
|
||||
e.ReportErrorAtID(0, l, format, args...)
|
||||
}
|
||||
|
||||
// ReportErrorAtID records an error at a source location and expression id.
|
||||
func (e *Errors) ReportErrorAtID(id int64, l Location, format string, args ...any) {
|
||||
e.numErrors++
|
||||
if e.numErrors > e.maxErrorsToReport {
|
||||
return
|
||||
}
|
||||
err := &Error{
|
||||
ExprID: id,
|
||||
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")
|
||||
}
|
17
e2e/vendor/github.com/google/cel-go/common/functions/BUILD.bazel
generated
vendored
Normal file
17
e2e/vendor/github.com/google/cel-go/common/functions/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"], # Apache 2.0
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"functions.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/functions",
|
||||
deps = [
|
||||
"//common/types/ref:go_default_library",
|
||||
],
|
||||
)
|
61
e2e/vendor/github.com/google/cel-go/common/functions/functions.go
generated
vendored
Normal file
61
e2e/vendor/github.com/google/cel-go/common/functions/functions.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package functions defines the standard builtin functions supported by the interpreter
|
||||
package functions
|
||||
|
||||
import "github.com/google/cel-go/common/types/ref"
|
||||
|
||||
// Overload defines a named overload of a function, indicating an operand trait
|
||||
// which must be present on the first argument to the overload as well as one
|
||||
// of either a unary, binary, or function implementation.
|
||||
//
|
||||
// The majority of operators within the expression language are unary or binary
|
||||
// and the specializations simplify the call contract for implementers of
|
||||
// types with operator overloads. Any added complexity is assumed to be handled
|
||||
// by the generic FunctionOp.
|
||||
type Overload struct {
|
||||
// Operator name as written in an expression or defined within
|
||||
// operators.go.
|
||||
Operator string
|
||||
|
||||
// Operand trait used to dispatch the call. The zero-value indicates a
|
||||
// global function overload or that one of the Unary / Binary / Function
|
||||
// definitions should be used to execute the call.
|
||||
OperandTrait int
|
||||
|
||||
// Unary defines the overload with a UnaryOp implementation. May be nil.
|
||||
Unary UnaryOp
|
||||
|
||||
// Binary defines the overload with a BinaryOp implementation. May be nil.
|
||||
Binary BinaryOp
|
||||
|
||||
// Function defines the overload with a FunctionOp implementation. May be
|
||||
// nil.
|
||||
Function FunctionOp
|
||||
|
||||
// NonStrict specifies whether the Overload will tolerate arguments that
|
||||
// are types.Err or types.Unknown.
|
||||
NonStrict bool
|
||||
}
|
||||
|
||||
// UnaryOp is a function that takes a single value and produces an output.
|
||||
type UnaryOp func(value ref.Val) ref.Val
|
||||
|
||||
// BinaryOp is a function that takes two values and produces an output.
|
||||
type BinaryOp func(lhs ref.Val, rhs ref.Val) ref.Val
|
||||
|
||||
// FunctionOp is a function with accepts zero or more arguments and produces
|
||||
// a value or error as a result.
|
||||
type FunctionOp func(values ...ref.Val) ref.Val
|
51
e2e/vendor/github.com/google/cel-go/common/location.go
generated
vendored
Normal file
51
e2e/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
e2e/vendor/github.com/google/cel-go/common/operators/BUILD.bazel
generated
vendored
Normal file
14
e2e/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",
|
||||
)
|
157
e2e/vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
Normal file
157
e2e/vendor/github.com/google/cel-go/common/operators/operators.go
generated
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
// 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 = "_[_]"
|
||||
OptIndex = "_[?_]"
|
||||
OptSelect = "_?._"
|
||||
|
||||
// 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},
|
||||
OptIndex: {displayName: "", precedence: 1, arity: 2},
|
||||
OptSelect: {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
e2e/vendor/github.com/google/cel-go/common/overloads/BUILD.bazel
generated
vendored
Normal file
14
e2e/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",
|
||||
)
|
327
e2e/vendor/github.com/google/cel-go/common/overloads/overloads.go
generated
vendored
Normal file
327
e2e/vendor/github.com/google/cel-go/common/overloads/overloads.go
generated
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// Extension function overloads with complex behaviors that need to be referenced in runtime and static analysis cost computations.
|
||||
const (
|
||||
ExtQuoteString = "strings_quote"
|
||||
)
|
||||
|
||||
// String function overload names.
|
||||
const (
|
||||
ContainsString = "contains_string"
|
||||
EndsWithString = "ends_with_string"
|
||||
MatchesString = "matches_string"
|
||||
StartsWithString = "starts_with_string"
|
||||
)
|
||||
|
||||
// Extension function overloads with complex behaviors that need to be referenced in runtime and static analysis cost computations.
|
||||
const (
|
||||
ExtFormatString = "string_format"
|
||||
)
|
||||
|
||||
// Time-based functions.
|
||||
const (
|
||||
TimeGetFullYear = "getFullYear"
|
||||
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
e2e/vendor/github.com/google/cel-go/common/runes/BUILD.bazel
generated
vendored
Normal file
25
e2e/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",
|
||||
],
|
||||
)
|
242
e2e/vendor/github.com/google/cel-go/common/runes/buffer.go
generated
vendored
Normal file
242
e2e/vendor/github.com/google/cel-go/common/runes/buffer.go
generated
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
// 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 {
|
||||
buf, _ := newBuffer(data, false)
|
||||
return buf
|
||||
}
|
||||
|
||||
// NewBufferAndLineOffsets returns an efficient implementation of Buffer for the given text based on
|
||||
// the ranges of the encoded code points contained within, as well as returning the line offsets.
|
||||
//
|
||||
// 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 NewBufferAndLineOffsets(data string) (Buffer, []int32) {
|
||||
return newBuffer(data, true)
|
||||
}
|
||||
|
||||
func newBuffer(data string, lines bool) (Buffer, []int32) {
|
||||
if len(data) == 0 {
|
||||
return nilBuffer, []int32{0}
|
||||
}
|
||||
var (
|
||||
idx = 0
|
||||
off int32 = 0
|
||||
buf8 = make([]byte, 0, len(data))
|
||||
buf16 []uint16
|
||||
buf32 []rune
|
||||
offs []int32
|
||||
)
|
||||
for idx < len(data) {
|
||||
r, s := utf8.DecodeRuneInString(data[idx:])
|
||||
idx += s
|
||||
if lines && r == '\n' {
|
||||
offs = append(offs, off+1)
|
||||
}
|
||||
if r < utf8.RuneSelf {
|
||||
buf8 = append(buf8, byte(r))
|
||||
off++
|
||||
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))
|
||||
off++
|
||||
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)
|
||||
off++
|
||||
goto copy32
|
||||
}
|
||||
if lines {
|
||||
offs = append(offs, off+1)
|
||||
}
|
||||
return &asciiBuffer{
|
||||
arr: buf8,
|
||||
}, offs
|
||||
copy16:
|
||||
for idx < len(data) {
|
||||
r, s := utf8.DecodeRuneInString(data[idx:])
|
||||
idx += s
|
||||
if lines && r == '\n' {
|
||||
offs = append(offs, off+1)
|
||||
}
|
||||
if r <= 0xffff {
|
||||
buf16 = append(buf16, uint16(r))
|
||||
off++
|
||||
continue
|
||||
}
|
||||
buf32 = make([]rune, len(buf16), len(data))
|
||||
for i, v := range buf16 {
|
||||
buf32[i] = rune(uint32(v))
|
||||
}
|
||||
buf16 = nil
|
||||
buf32 = append(buf32, r)
|
||||
off++
|
||||
goto copy32
|
||||
}
|
||||
if lines {
|
||||
offs = append(offs, off+1)
|
||||
}
|
||||
return &basicBuffer{
|
||||
arr: buf16,
|
||||
}, offs
|
||||
copy32:
|
||||
for idx < len(data) {
|
||||
r, s := utf8.DecodeRuneInString(data[idx:])
|
||||
idx += s
|
||||
if lines && r == '\n' {
|
||||
offs = append(offs, off+1)
|
||||
}
|
||||
buf32 = append(buf32, r)
|
||||
off++
|
||||
}
|
||||
if lines {
|
||||
offs = append(offs, off+1)
|
||||
}
|
||||
return &supplementalBuffer{
|
||||
arr: buf32,
|
||||
}, offs
|
||||
}
|
173
e2e/vendor/github.com/google/cel-go/common/source.go
generated
vendored
Normal file
173
e2e/vendor/github.com/google/cel-go/common/source.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
// 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 (
|
||||
"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
|
||||
}
|
||||
|
||||
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.
|
||||
buf, offs := runes.NewBufferAndLineOffsets(contents)
|
||||
return &sourceImpl{
|
||||
Buffer: buf,
|
||||
description: description,
|
||||
lineOffsets: offs,
|
||||
}
|
||||
}
|
||||
|
||||
// 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(),
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
line++
|
||||
}
|
||||
if line == 1 {
|
||||
return line, 0
|
||||
}
|
||||
return line, s.lineOffsets[line-2]
|
||||
}
|
23
e2e/vendor/github.com/google/cel-go/common/stdlib/BUILD.bazel
generated
vendored
Normal file
23
e2e/vendor/github.com/google/cel-go/common/stdlib/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
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 = [
|
||||
"standard.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/stdlib",
|
||||
deps = [
|
||||
"//common/decls:go_default_library",
|
||||
"//common/functions: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",
|
||||
],
|
||||
)
|
620
e2e/vendor/github.com/google/cel-go/common/stdlib/standard.go
generated
vendored
Normal file
620
e2e/vendor/github.com/google/cel-go/common/stdlib/standard.go
generated
vendored
Normal file
@ -0,0 +1,620 @@
|
||||
// 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 stdlib contains all of the standard library function declarations and definitions for CEL.
|
||||
package stdlib
|
||||
|
||||
import (
|
||||
"github.com/google/cel-go/common/decls"
|
||||
"github.com/google/cel-go/common/functions"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
)
|
||||
|
||||
var (
|
||||
stdFunctions []*decls.FunctionDecl
|
||||
stdTypes []*decls.VariableDecl
|
||||
)
|
||||
|
||||
func init() {
|
||||
paramA := types.NewTypeParamType("A")
|
||||
paramB := types.NewTypeParamType("B")
|
||||
listOfA := types.NewListType(paramA)
|
||||
mapOfAB := types.NewMapType(paramA, paramB)
|
||||
|
||||
stdTypes = []*decls.VariableDecl{
|
||||
decls.TypeVariable(types.BoolType),
|
||||
decls.TypeVariable(types.BytesType),
|
||||
decls.TypeVariable(types.DoubleType),
|
||||
decls.TypeVariable(types.DurationType),
|
||||
decls.TypeVariable(types.IntType),
|
||||
decls.TypeVariable(listOfA),
|
||||
decls.TypeVariable(mapOfAB),
|
||||
decls.TypeVariable(types.NullType),
|
||||
decls.TypeVariable(types.StringType),
|
||||
decls.TypeVariable(types.TimestampType),
|
||||
decls.TypeVariable(types.TypeType),
|
||||
decls.TypeVariable(types.UintType),
|
||||
}
|
||||
|
||||
stdFunctions = []*decls.FunctionDecl{
|
||||
// Logical operators. Special-cased within the interpreter.
|
||||
// Note, the singleton binding prevents extensions from overriding the operator behavior.
|
||||
function(operators.Conditional,
|
||||
decls.Overload(overloads.Conditional, argTypes(types.BoolType, paramA, paramA), paramA,
|
||||
decls.OverloadIsNonStrict()),
|
||||
decls.SingletonFunctionBinding(noFunctionOverrides)),
|
||||
function(operators.LogicalAnd,
|
||||
decls.Overload(overloads.LogicalAnd, argTypes(types.BoolType, types.BoolType), types.BoolType,
|
||||
decls.OverloadIsNonStrict()),
|
||||
decls.SingletonBinaryBinding(noBinaryOverrides)),
|
||||
function(operators.LogicalOr,
|
||||
decls.Overload(overloads.LogicalOr, argTypes(types.BoolType, types.BoolType), types.BoolType,
|
||||
decls.OverloadIsNonStrict()),
|
||||
decls.SingletonBinaryBinding(noBinaryOverrides)),
|
||||
function(operators.LogicalNot,
|
||||
decls.Overload(overloads.LogicalNot, argTypes(types.BoolType), types.BoolType),
|
||||
decls.SingletonUnaryBinding(func(val ref.Val) ref.Val {
|
||||
b, ok := val.(types.Bool)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
return b.Negate()
|
||||
})),
|
||||
|
||||
// Comprehension short-circuiting related function
|
||||
function(operators.NotStrictlyFalse,
|
||||
decls.Overload(overloads.NotStrictlyFalse, argTypes(types.BoolType), types.BoolType,
|
||||
decls.OverloadIsNonStrict(),
|
||||
decls.UnaryBinding(notStrictlyFalse))),
|
||||
// Deprecated: __not_strictly_false__
|
||||
function(operators.OldNotStrictlyFalse,
|
||||
decls.DisableDeclaration(true), // safe deprecation
|
||||
decls.Overload(operators.OldNotStrictlyFalse, argTypes(types.BoolType), types.BoolType,
|
||||
decls.OverloadIsNonStrict(),
|
||||
decls.UnaryBinding(notStrictlyFalse))),
|
||||
|
||||
// Equality / inequality. Special-cased in the interpreter
|
||||
function(operators.Equals,
|
||||
decls.Overload(overloads.Equals, argTypes(paramA, paramA), types.BoolType),
|
||||
decls.SingletonBinaryBinding(noBinaryOverrides)),
|
||||
function(operators.NotEquals,
|
||||
decls.Overload(overloads.NotEquals, argTypes(paramA, paramA), types.BoolType),
|
||||
decls.SingletonBinaryBinding(noBinaryOverrides)),
|
||||
|
||||
// Mathematical operators
|
||||
function(operators.Add,
|
||||
decls.Overload(overloads.AddBytes,
|
||||
argTypes(types.BytesType, types.BytesType), types.BytesType),
|
||||
decls.Overload(overloads.AddDouble,
|
||||
argTypes(types.DoubleType, types.DoubleType), types.DoubleType),
|
||||
decls.Overload(overloads.AddDurationDuration,
|
||||
argTypes(types.DurationType, types.DurationType), types.DurationType),
|
||||
decls.Overload(overloads.AddDurationTimestamp,
|
||||
argTypes(types.DurationType, types.TimestampType), types.TimestampType),
|
||||
decls.Overload(overloads.AddTimestampDuration,
|
||||
argTypes(types.TimestampType, types.DurationType), types.TimestampType),
|
||||
decls.Overload(overloads.AddInt64,
|
||||
argTypes(types.IntType, types.IntType), types.IntType),
|
||||
decls.Overload(overloads.AddList,
|
||||
argTypes(listOfA, listOfA), listOfA),
|
||||
decls.Overload(overloads.AddString,
|
||||
argTypes(types.StringType, types.StringType), types.StringType),
|
||||
decls.Overload(overloads.AddUint64,
|
||||
argTypes(types.UintType, types.UintType), types.UintType),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Adder).Add(rhs)
|
||||
}, traits.AdderType)),
|
||||
function(operators.Divide,
|
||||
decls.Overload(overloads.DivideDouble,
|
||||
argTypes(types.DoubleType, types.DoubleType), types.DoubleType),
|
||||
decls.Overload(overloads.DivideInt64,
|
||||
argTypes(types.IntType, types.IntType), types.IntType),
|
||||
decls.Overload(overloads.DivideUint64,
|
||||
argTypes(types.UintType, types.UintType), types.UintType),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Divider).Divide(rhs)
|
||||
}, traits.DividerType)),
|
||||
function(operators.Modulo,
|
||||
decls.Overload(overloads.ModuloInt64,
|
||||
argTypes(types.IntType, types.IntType), types.IntType),
|
||||
decls.Overload(overloads.ModuloUint64,
|
||||
argTypes(types.UintType, types.UintType), types.UintType),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Modder).Modulo(rhs)
|
||||
}, traits.ModderType)),
|
||||
function(operators.Multiply,
|
||||
decls.Overload(overloads.MultiplyDouble,
|
||||
argTypes(types.DoubleType, types.DoubleType), types.DoubleType),
|
||||
decls.Overload(overloads.MultiplyInt64,
|
||||
argTypes(types.IntType, types.IntType), types.IntType),
|
||||
decls.Overload(overloads.MultiplyUint64,
|
||||
argTypes(types.UintType, types.UintType), types.UintType),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Multiplier).Multiply(rhs)
|
||||
}, traits.MultiplierType)),
|
||||
function(operators.Negate,
|
||||
decls.Overload(overloads.NegateDouble, argTypes(types.DoubleType), types.DoubleType),
|
||||
decls.Overload(overloads.NegateInt64, argTypes(types.IntType), types.IntType),
|
||||
decls.SingletonUnaryBinding(func(val ref.Val) ref.Val {
|
||||
if types.IsBool(val) {
|
||||
return types.MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
return val.(traits.Negater).Negate()
|
||||
}, traits.NegatorType)),
|
||||
function(operators.Subtract,
|
||||
decls.Overload(overloads.SubtractDouble,
|
||||
argTypes(types.DoubleType, types.DoubleType), types.DoubleType),
|
||||
decls.Overload(overloads.SubtractDurationDuration,
|
||||
argTypes(types.DurationType, types.DurationType), types.DurationType),
|
||||
decls.Overload(overloads.SubtractInt64,
|
||||
argTypes(types.IntType, types.IntType), types.IntType),
|
||||
decls.Overload(overloads.SubtractTimestampDuration,
|
||||
argTypes(types.TimestampType, types.DurationType), types.TimestampType),
|
||||
decls.Overload(overloads.SubtractTimestampTimestamp,
|
||||
argTypes(types.TimestampType, types.TimestampType), types.DurationType),
|
||||
decls.Overload(overloads.SubtractUint64,
|
||||
argTypes(types.UintType, types.UintType), types.UintType),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Subtractor).Subtract(rhs)
|
||||
}, traits.SubtractorType)),
|
||||
|
||||
// Relations operators
|
||||
|
||||
function(operators.Less,
|
||||
decls.Overload(overloads.LessBool,
|
||||
argTypes(types.BoolType, types.BoolType), types.BoolType),
|
||||
decls.Overload(overloads.LessInt64,
|
||||
argTypes(types.IntType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.LessInt64Double,
|
||||
argTypes(types.IntType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.LessInt64Uint64,
|
||||
argTypes(types.IntType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.LessUint64,
|
||||
argTypes(types.UintType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.LessUint64Double,
|
||||
argTypes(types.UintType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.LessUint64Int64,
|
||||
argTypes(types.UintType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.LessDouble,
|
||||
argTypes(types.DoubleType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.LessDoubleInt64,
|
||||
argTypes(types.DoubleType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.LessDoubleUint64,
|
||||
argTypes(types.DoubleType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.LessString,
|
||||
argTypes(types.StringType, types.StringType), types.BoolType),
|
||||
decls.Overload(overloads.LessBytes,
|
||||
argTypes(types.BytesType, types.BytesType), types.BoolType),
|
||||
decls.Overload(overloads.LessTimestamp,
|
||||
argTypes(types.TimestampType, types.TimestampType), types.BoolType),
|
||||
decls.Overload(overloads.LessDuration,
|
||||
argTypes(types.DurationType, types.DurationType), types.BoolType),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
cmp := lhs.(traits.Comparer).Compare(rhs)
|
||||
if cmp == types.IntNegOne {
|
||||
return types.True
|
||||
}
|
||||
if cmp == types.IntOne || cmp == types.IntZero {
|
||||
return types.False
|
||||
}
|
||||
return cmp
|
||||
}, traits.ComparerType)),
|
||||
|
||||
function(operators.LessEquals,
|
||||
decls.Overload(overloads.LessEqualsBool,
|
||||
argTypes(types.BoolType, types.BoolType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsInt64,
|
||||
argTypes(types.IntType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsInt64Double,
|
||||
argTypes(types.IntType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsInt64Uint64,
|
||||
argTypes(types.IntType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsUint64,
|
||||
argTypes(types.UintType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsUint64Double,
|
||||
argTypes(types.UintType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsUint64Int64,
|
||||
argTypes(types.UintType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsDouble,
|
||||
argTypes(types.DoubleType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsDoubleInt64,
|
||||
argTypes(types.DoubleType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsDoubleUint64,
|
||||
argTypes(types.DoubleType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsString,
|
||||
argTypes(types.StringType, types.StringType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsBytes,
|
||||
argTypes(types.BytesType, types.BytesType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsTimestamp,
|
||||
argTypes(types.TimestampType, types.TimestampType), types.BoolType),
|
||||
decls.Overload(overloads.LessEqualsDuration,
|
||||
argTypes(types.DurationType, types.DurationType), types.BoolType),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
cmp := lhs.(traits.Comparer).Compare(rhs)
|
||||
if cmp == types.IntNegOne || cmp == types.IntZero {
|
||||
return types.True
|
||||
}
|
||||
if cmp == types.IntOne {
|
||||
return types.False
|
||||
}
|
||||
return cmp
|
||||
}, traits.ComparerType)),
|
||||
|
||||
function(operators.Greater,
|
||||
decls.Overload(overloads.GreaterBool,
|
||||
argTypes(types.BoolType, types.BoolType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterInt64,
|
||||
argTypes(types.IntType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterInt64Double,
|
||||
argTypes(types.IntType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterInt64Uint64,
|
||||
argTypes(types.IntType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterUint64,
|
||||
argTypes(types.UintType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterUint64Double,
|
||||
argTypes(types.UintType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterUint64Int64,
|
||||
argTypes(types.UintType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterDouble,
|
||||
argTypes(types.DoubleType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterDoubleInt64,
|
||||
argTypes(types.DoubleType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterDoubleUint64,
|
||||
argTypes(types.DoubleType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterString,
|
||||
argTypes(types.StringType, types.StringType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterBytes,
|
||||
argTypes(types.BytesType, types.BytesType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterTimestamp,
|
||||
argTypes(types.TimestampType, types.TimestampType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterDuration,
|
||||
argTypes(types.DurationType, types.DurationType), types.BoolType),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
cmp := lhs.(traits.Comparer).Compare(rhs)
|
||||
if cmp == types.IntOne {
|
||||
return types.True
|
||||
}
|
||||
if cmp == types.IntNegOne || cmp == types.IntZero {
|
||||
return types.False
|
||||
}
|
||||
return cmp
|
||||
}, traits.ComparerType)),
|
||||
|
||||
function(operators.GreaterEquals,
|
||||
decls.Overload(overloads.GreaterEqualsBool,
|
||||
argTypes(types.BoolType, types.BoolType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsInt64,
|
||||
argTypes(types.IntType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsInt64Double,
|
||||
argTypes(types.IntType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsInt64Uint64,
|
||||
argTypes(types.IntType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsUint64,
|
||||
argTypes(types.UintType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsUint64Double,
|
||||
argTypes(types.UintType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsUint64Int64,
|
||||
argTypes(types.UintType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsDouble,
|
||||
argTypes(types.DoubleType, types.DoubleType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsDoubleInt64,
|
||||
argTypes(types.DoubleType, types.IntType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsDoubleUint64,
|
||||
argTypes(types.DoubleType, types.UintType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsString,
|
||||
argTypes(types.StringType, types.StringType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsBytes,
|
||||
argTypes(types.BytesType, types.BytesType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsTimestamp,
|
||||
argTypes(types.TimestampType, types.TimestampType), types.BoolType),
|
||||
decls.Overload(overloads.GreaterEqualsDuration,
|
||||
argTypes(types.DurationType, types.DurationType), types.BoolType),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
cmp := lhs.(traits.Comparer).Compare(rhs)
|
||||
if cmp == types.IntOne || cmp == types.IntZero {
|
||||
return types.True
|
||||
}
|
||||
if cmp == types.IntNegOne {
|
||||
return types.False
|
||||
}
|
||||
return cmp
|
||||
}, traits.ComparerType)),
|
||||
|
||||
// Indexing
|
||||
function(operators.Index,
|
||||
decls.Overload(overloads.IndexList, argTypes(listOfA, types.IntType), paramA),
|
||||
decls.Overload(overloads.IndexMap, argTypes(mapOfAB, paramA), paramB),
|
||||
decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val {
|
||||
return lhs.(traits.Indexer).Get(rhs)
|
||||
}, traits.IndexerType)),
|
||||
|
||||
// Collections operators
|
||||
function(operators.In,
|
||||
decls.Overload(overloads.InList, argTypes(paramA, listOfA), types.BoolType),
|
||||
decls.Overload(overloads.InMap, argTypes(paramA, mapOfAB), types.BoolType),
|
||||
decls.SingletonBinaryBinding(inAggregate)),
|
||||
function(operators.OldIn,
|
||||
decls.DisableDeclaration(true), // safe deprecation
|
||||
decls.Overload(overloads.InList, argTypes(paramA, listOfA), types.BoolType),
|
||||
decls.Overload(overloads.InMap, argTypes(paramA, mapOfAB), types.BoolType),
|
||||
decls.SingletonBinaryBinding(inAggregate)),
|
||||
function(overloads.DeprecatedIn,
|
||||
decls.DisableDeclaration(true), // safe deprecation
|
||||
decls.Overload(overloads.InList, argTypes(paramA, listOfA), types.BoolType),
|
||||
decls.Overload(overloads.InMap, argTypes(paramA, mapOfAB), types.BoolType),
|
||||
decls.SingletonBinaryBinding(inAggregate)),
|
||||
function(overloads.Size,
|
||||
decls.Overload(overloads.SizeBytes, argTypes(types.BytesType), types.IntType),
|
||||
decls.MemberOverload(overloads.SizeBytesInst, argTypes(types.BytesType), types.IntType),
|
||||
decls.Overload(overloads.SizeList, argTypes(listOfA), types.IntType),
|
||||
decls.MemberOverload(overloads.SizeListInst, argTypes(listOfA), types.IntType),
|
||||
decls.Overload(overloads.SizeMap, argTypes(mapOfAB), types.IntType),
|
||||
decls.MemberOverload(overloads.SizeMapInst, argTypes(mapOfAB), types.IntType),
|
||||
decls.Overload(overloads.SizeString, argTypes(types.StringType), types.IntType),
|
||||
decls.MemberOverload(overloads.SizeStringInst, argTypes(types.StringType), types.IntType),
|
||||
decls.SingletonUnaryBinding(func(val ref.Val) ref.Val {
|
||||
return val.(traits.Sizer).Size()
|
||||
}, traits.SizerType)),
|
||||
|
||||
// Type conversions
|
||||
function(overloads.TypeConvertType,
|
||||
decls.Overload(overloads.TypeConvertType, argTypes(paramA), types.NewTypeTypeWithParam(paramA)),
|
||||
decls.SingletonUnaryBinding(convertToType(types.TypeType))),
|
||||
|
||||
// Bool conversions
|
||||
function(overloads.TypeConvertBool,
|
||||
decls.Overload(overloads.BoolToBool, argTypes(types.BoolType), types.BoolType,
|
||||
decls.UnaryBinding(identity)),
|
||||
decls.Overload(overloads.StringToBool, argTypes(types.StringType), types.BoolType,
|
||||
decls.UnaryBinding(convertToType(types.BoolType)))),
|
||||
|
||||
// Bytes conversions
|
||||
function(overloads.TypeConvertBytes,
|
||||
decls.Overload(overloads.BytesToBytes, argTypes(types.BytesType), types.BytesType,
|
||||
decls.UnaryBinding(identity)),
|
||||
decls.Overload(overloads.StringToBytes, argTypes(types.StringType), types.BytesType,
|
||||
decls.UnaryBinding(convertToType(types.BytesType)))),
|
||||
|
||||
// Double conversions
|
||||
function(overloads.TypeConvertDouble,
|
||||
decls.Overload(overloads.DoubleToDouble, argTypes(types.DoubleType), types.DoubleType,
|
||||
decls.UnaryBinding(identity)),
|
||||
decls.Overload(overloads.IntToDouble, argTypes(types.IntType), types.DoubleType,
|
||||
decls.UnaryBinding(convertToType(types.DoubleType))),
|
||||
decls.Overload(overloads.StringToDouble, argTypes(types.StringType), types.DoubleType,
|
||||
decls.UnaryBinding(convertToType(types.DoubleType))),
|
||||
decls.Overload(overloads.UintToDouble, argTypes(types.UintType), types.DoubleType,
|
||||
decls.UnaryBinding(convertToType(types.DoubleType)))),
|
||||
|
||||
// Duration conversions
|
||||
function(overloads.TypeConvertDuration,
|
||||
decls.Overload(overloads.DurationToDuration, argTypes(types.DurationType), types.DurationType,
|
||||
decls.UnaryBinding(identity)),
|
||||
decls.Overload(overloads.IntToDuration, argTypes(types.IntType), types.DurationType,
|
||||
decls.UnaryBinding(convertToType(types.DurationType))),
|
||||
decls.Overload(overloads.StringToDuration, argTypes(types.StringType), types.DurationType,
|
||||
decls.UnaryBinding(convertToType(types.DurationType)))),
|
||||
|
||||
// Dyn conversions
|
||||
function(overloads.TypeConvertDyn,
|
||||
decls.Overload(overloads.ToDyn, argTypes(paramA), types.DynType),
|
||||
decls.SingletonUnaryBinding(identity)),
|
||||
|
||||
// Int conversions
|
||||
function(overloads.TypeConvertInt,
|
||||
decls.Overload(overloads.IntToInt, argTypes(types.IntType), types.IntType,
|
||||
decls.UnaryBinding(identity)),
|
||||
decls.Overload(overloads.DoubleToInt, argTypes(types.DoubleType), types.IntType,
|
||||
decls.UnaryBinding(convertToType(types.IntType))),
|
||||
decls.Overload(overloads.DurationToInt, argTypes(types.DurationType), types.IntType,
|
||||
decls.UnaryBinding(convertToType(types.IntType))),
|
||||
decls.Overload(overloads.StringToInt, argTypes(types.StringType), types.IntType,
|
||||
decls.UnaryBinding(convertToType(types.IntType))),
|
||||
decls.Overload(overloads.TimestampToInt, argTypes(types.TimestampType), types.IntType,
|
||||
decls.UnaryBinding(convertToType(types.IntType))),
|
||||
decls.Overload(overloads.UintToInt, argTypes(types.UintType), types.IntType,
|
||||
decls.UnaryBinding(convertToType(types.IntType))),
|
||||
),
|
||||
|
||||
// String conversions
|
||||
function(overloads.TypeConvertString,
|
||||
decls.Overload(overloads.StringToString, argTypes(types.StringType), types.StringType,
|
||||
decls.UnaryBinding(identity)),
|
||||
decls.Overload(overloads.BoolToString, argTypes(types.BoolType), types.StringType,
|
||||
decls.UnaryBinding(convertToType(types.StringType))),
|
||||
decls.Overload(overloads.BytesToString, argTypes(types.BytesType), types.StringType,
|
||||
decls.UnaryBinding(convertToType(types.StringType))),
|
||||
decls.Overload(overloads.DoubleToString, argTypes(types.DoubleType), types.StringType,
|
||||
decls.UnaryBinding(convertToType(types.StringType))),
|
||||
decls.Overload(overloads.DurationToString, argTypes(types.DurationType), types.StringType,
|
||||
decls.UnaryBinding(convertToType(types.StringType))),
|
||||
decls.Overload(overloads.IntToString, argTypes(types.IntType), types.StringType,
|
||||
decls.UnaryBinding(convertToType(types.StringType))),
|
||||
decls.Overload(overloads.TimestampToString, argTypes(types.TimestampType), types.StringType,
|
||||
decls.UnaryBinding(convertToType(types.StringType))),
|
||||
decls.Overload(overloads.UintToString, argTypes(types.UintType), types.StringType,
|
||||
decls.UnaryBinding(convertToType(types.StringType)))),
|
||||
|
||||
// Timestamp conversions
|
||||
function(overloads.TypeConvertTimestamp,
|
||||
decls.Overload(overloads.TimestampToTimestamp, argTypes(types.TimestampType), types.TimestampType,
|
||||
decls.UnaryBinding(identity)),
|
||||
decls.Overload(overloads.IntToTimestamp, argTypes(types.IntType), types.TimestampType,
|
||||
decls.UnaryBinding(convertToType(types.TimestampType))),
|
||||
decls.Overload(overloads.StringToTimestamp, argTypes(types.StringType), types.TimestampType,
|
||||
decls.UnaryBinding(convertToType(types.TimestampType)))),
|
||||
|
||||
// Uint conversions
|
||||
function(overloads.TypeConvertUint,
|
||||
decls.Overload(overloads.UintToUint, argTypes(types.UintType), types.UintType,
|
||||
decls.UnaryBinding(identity)),
|
||||
decls.Overload(overloads.DoubleToUint, argTypes(types.DoubleType), types.UintType,
|
||||
decls.UnaryBinding(convertToType(types.UintType))),
|
||||
decls.Overload(overloads.IntToUint, argTypes(types.IntType), types.UintType,
|
||||
decls.UnaryBinding(convertToType(types.UintType))),
|
||||
decls.Overload(overloads.StringToUint, argTypes(types.StringType), types.UintType,
|
||||
decls.UnaryBinding(convertToType(types.UintType)))),
|
||||
|
||||
// String functions
|
||||
function(overloads.Contains,
|
||||
decls.MemberOverload(overloads.ContainsString,
|
||||
argTypes(types.StringType, types.StringType), types.BoolType,
|
||||
decls.BinaryBinding(types.StringContains)),
|
||||
decls.DisableTypeGuards(true)),
|
||||
function(overloads.EndsWith,
|
||||
decls.MemberOverload(overloads.EndsWithString,
|
||||
argTypes(types.StringType, types.StringType), types.BoolType,
|
||||
decls.BinaryBinding(types.StringEndsWith)),
|
||||
decls.DisableTypeGuards(true)),
|
||||
function(overloads.StartsWith,
|
||||
decls.MemberOverload(overloads.StartsWithString,
|
||||
argTypes(types.StringType, types.StringType), types.BoolType,
|
||||
decls.BinaryBinding(types.StringStartsWith)),
|
||||
decls.DisableTypeGuards(true)),
|
||||
function(overloads.Matches,
|
||||
decls.Overload(overloads.Matches, argTypes(types.StringType, types.StringType), types.BoolType),
|
||||
decls.MemberOverload(overloads.MatchesString,
|
||||
argTypes(types.StringType, types.StringType), types.BoolType),
|
||||
decls.SingletonBinaryBinding(func(str, pat ref.Val) ref.Val {
|
||||
return str.(traits.Matcher).Match(pat)
|
||||
}, traits.MatcherType)),
|
||||
|
||||
// Timestamp / duration functions
|
||||
function(overloads.TimeGetFullYear,
|
||||
decls.MemberOverload(overloads.TimestampToYear,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToYearWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType)),
|
||||
|
||||
function(overloads.TimeGetMonth,
|
||||
decls.MemberOverload(overloads.TimestampToMonth,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToMonthWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType)),
|
||||
|
||||
function(overloads.TimeGetDayOfYear,
|
||||
decls.MemberOverload(overloads.TimestampToDayOfYear,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToDayOfYearWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType)),
|
||||
|
||||
function(overloads.TimeGetDayOfMonth,
|
||||
decls.MemberOverload(overloads.TimestampToDayOfMonthZeroBased,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToDayOfMonthZeroBasedWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType)),
|
||||
|
||||
function(overloads.TimeGetDate,
|
||||
decls.MemberOverload(overloads.TimestampToDayOfMonthOneBased,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToDayOfMonthOneBasedWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType)),
|
||||
|
||||
function(overloads.TimeGetDayOfWeek,
|
||||
decls.MemberOverload(overloads.TimestampToDayOfWeek,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToDayOfWeekWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType)),
|
||||
|
||||
function(overloads.TimeGetHours,
|
||||
decls.MemberOverload(overloads.TimestampToHours,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToHoursWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType),
|
||||
decls.MemberOverload(overloads.DurationToHours,
|
||||
argTypes(types.DurationType), types.IntType)),
|
||||
|
||||
function(overloads.TimeGetMinutes,
|
||||
decls.MemberOverload(overloads.TimestampToMinutes,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToMinutesWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType),
|
||||
decls.MemberOverload(overloads.DurationToMinutes,
|
||||
argTypes(types.DurationType), types.IntType)),
|
||||
|
||||
function(overloads.TimeGetSeconds,
|
||||
decls.MemberOverload(overloads.TimestampToSeconds,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToSecondsWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType),
|
||||
decls.MemberOverload(overloads.DurationToSeconds,
|
||||
argTypes(types.DurationType), types.IntType)),
|
||||
|
||||
function(overloads.TimeGetMilliseconds,
|
||||
decls.MemberOverload(overloads.TimestampToMilliseconds,
|
||||
argTypes(types.TimestampType), types.IntType),
|
||||
decls.MemberOverload(overloads.TimestampToMillisecondsWithTz,
|
||||
argTypes(types.TimestampType, types.StringType), types.IntType),
|
||||
decls.MemberOverload(overloads.DurationToMilliseconds,
|
||||
argTypes(types.DurationType), types.IntType)),
|
||||
}
|
||||
}
|
||||
|
||||
// Functions returns the set of standard library function declarations and definitions for CEL.
|
||||
func Functions() []*decls.FunctionDecl {
|
||||
return stdFunctions
|
||||
}
|
||||
|
||||
// Types returns the set of standard library types for CEL.
|
||||
func Types() []*decls.VariableDecl {
|
||||
return stdTypes
|
||||
}
|
||||
|
||||
func notStrictlyFalse(value ref.Val) ref.Val {
|
||||
if types.IsBool(value) {
|
||||
return value
|
||||
}
|
||||
return types.True
|
||||
}
|
||||
|
||||
func inAggregate(lhs ref.Val, rhs ref.Val) ref.Val {
|
||||
if rhs.Type().HasTrait(traits.ContainerType) {
|
||||
return rhs.(traits.Container).Contains(lhs)
|
||||
}
|
||||
return types.ValOrErr(rhs, "no such overload")
|
||||
}
|
||||
|
||||
func function(name string, opts ...decls.FunctionOpt) *decls.FunctionDecl {
|
||||
fn, err := decls.NewFunction(name, opts...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
func argTypes(args ...*types.Type) []*types.Type {
|
||||
return args
|
||||
}
|
||||
|
||||
func noBinaryOverrides(rhs, lhs ref.Val) ref.Val {
|
||||
return types.NoSuchOverloadErr()
|
||||
}
|
||||
|
||||
func noFunctionOverrides(args ...ref.Val) ref.Val {
|
||||
return types.NoSuchOverloadErr()
|
||||
}
|
||||
|
||||
func identity(val ref.Val) ref.Val {
|
||||
return val
|
||||
}
|
||||
|
||||
func convertToType(t ref.Type) functions.UnaryOp {
|
||||
return func(val ref.Val) ref.Val {
|
||||
return val.ConvertToType(t)
|
||||
}
|
||||
}
|
92
e2e/vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
Normal file
92
e2e/vendor/github.com/google/cel-go/common/types/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
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",
|
||||
"optional.go",
|
||||
"overflow.go",
|
||||
"provider.go",
|
||||
"string.go",
|
||||
"timestamp.go",
|
||||
"types.go",
|
||||
"uint.go",
|
||||
"unknown.go",
|
||||
"util.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/types",
|
||||
deps = [
|
||||
"//checker/decls:go_default_library",
|
||||
"//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",
|
||||
"@dev_cel_expr//:expr",
|
||||
"@org_golang_google_genproto_googleapis_api//expr/v1alpha1:go_default_library",
|
||||
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
|
||||
"@org_golang_google_protobuf//types/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/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",
|
||||
"optional_test.go",
|
||||
"provider_test.go",
|
||||
"string_test.go",
|
||||
"timestamp_test.go",
|
||||
"types_test.go",
|
||||
"uint_test.go",
|
||||
"unknown_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
e2e/vendor/github.com/google/cel-go/common/types/any_value.go
generated
vendored
Normal file
24
e2e/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{})
|
141
e2e/vendor/github.com/google/cel-go/common/types/bool.go
generated
vendored
Normal file
141
e2e/vendor/github.com/google/cel-go/common/types/bool.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 types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
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 (
|
||||
// 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) (any, 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)
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the boolean value is false.
|
||||
func (b Bool) IsZeroValue() bool {
|
||||
return b == False
|
||||
}
|
||||
|
||||
// Negate implements the traits.Negater interface method.
|
||||
func (b Bool) Negate() ref.Val {
|
||||
return !b
|
||||
}
|
||||
|
||||
// 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() any {
|
||||
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
|
||||
}
|
||||
}
|
140
e2e/vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
Normal file
140
e2e/vendor/github.com/google/cel-go/common/types/bytes.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
// 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"
|
||||
|
||||
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 (
|
||||
// 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) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Array:
|
||||
if len(b) != typeDesc.Len() {
|
||||
return nil, fmt.Errorf("[%d]byte not assignable to [%d]byte array", len(b), typeDesc.Len())
|
||||
}
|
||||
refArrPtr := reflect.New(reflect.ArrayOf(len(b), typeDesc.Elem()))
|
||||
refArr := refArrPtr.Elem()
|
||||
for i, byt := range b {
|
||||
refArr.Index(i).Set(reflect.ValueOf(byt).Convert(typeDesc.Elem()))
|
||||
}
|
||||
return refArr.Interface(), nil
|
||||
case 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))
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the byte array is empty.
|
||||
func (b Bytes) IsZeroValue() bool {
|
||||
return len(b) == 0
|
||||
}
|
||||
|
||||
// Size implements the traits.Sizer interface method.
|
||||
func (b Bytes) Size() ref.Val {
|
||||
return Int(len(b))
|
||||
}
|
||||
|
||||
// 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() any {
|
||||
return []byte(b)
|
||||
}
|
97
e2e/vendor/github.com/google/cel-go/common/types/compare.go
generated
vendored
Normal file
97
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/doc.go
generated
vendored
Normal file
17
e2e/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
|
211
e2e/vendor/github.com/google/cel-go/common/types/double.go
generated
vendored
Normal file
211
e2e/vendor/github.com/google/cel-go/common/types/double.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
// 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"
|
||||
|
||||
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 (
|
||||
// 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) (any, 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
|
||||
}
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if double value is 0.0
|
||||
func (d Double) IsZeroValue() bool {
|
||||
return float64(d) == 0.0
|
||||
}
|
||||
|
||||
// Multiply implements traits.Multiplier.Multiply.
|
||||
func (d Double) Multiply(other ref.Val) ref.Val {
|
||||
otherDouble, ok := other.(Double)
|
||||
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() any {
|
||||
return float64(d)
|
||||
}
|
222
e2e/vendor/github.com/google/cel-go/common/types/duration.go
generated
vendored
Normal file
222
e2e/vendor/github.com/google/cel-go/common/types/duration.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
// 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"
|
||||
|
||||
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 (
|
||||
durationValueType = reflect.TypeOf(&dpb.Duration{})
|
||||
|
||||
durationZeroArgOverloads = map[string]func(ref.Val) ref.Val{
|
||||
overloads.TimeGetHours: DurationGetHours,
|
||||
overloads.TimeGetMinutes: DurationGetMinutes,
|
||||
overloads.TimeGetSeconds: DurationGetSeconds,
|
||||
overloads.TimeGetMilliseconds: DurationGetMilliseconds,
|
||||
}
|
||||
)
|
||||
|
||||
// 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) (any, error) {
|
||||
// If the duration is already assignable to the desired type return it.
|
||||
if reflect.TypeOf(d.Duration).AssignableTo(typeDesc) {
|
||||
return d.Duration, nil
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the duration value is zero
|
||||
func (d Duration) IsZeroValue() bool {
|
||||
return d.Duration == 0
|
||||
}
|
||||
|
||||
// Negate implements traits.Negater.Negate.
|
||||
func (d Duration) Negate() ref.Val {
|
||||
val, err := negateDurationChecked(d.Duration)
|
||||
if err != nil {
|
||||
return WrapErr(err)
|
||||
}
|
||||
return 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)
|
||||
}
|
||||
}
|
||||
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() any {
|
||||
return d.Duration
|
||||
}
|
||||
|
||||
// DurationGetHours returns the duration in hours.
|
||||
func DurationGetHours(val ref.Val) ref.Val {
|
||||
dur, ok := val.(Duration)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
return Int(dur.Hours())
|
||||
}
|
||||
|
||||
// DurationGetMinutes returns duration in minutes.
|
||||
func DurationGetMinutes(val ref.Val) ref.Val {
|
||||
dur, ok := val.(Duration)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
return Int(dur.Minutes())
|
||||
}
|
||||
|
||||
// DurationGetSeconds returns duration in seconds.
|
||||
func DurationGetSeconds(val ref.Val) ref.Val {
|
||||
dur, ok := val.(Duration)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
return Int(dur.Seconds())
|
||||
}
|
||||
|
||||
// DurationGetMilliseconds returns duration in milliseconds.
|
||||
func DurationGetMilliseconds(val ref.Val) ref.Val {
|
||||
dur, ok := val.(Duration)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(val)
|
||||
}
|
||||
return Int(dur.Milliseconds())
|
||||
}
|
169
e2e/vendor/github.com/google/cel-go/common/types/err.go
generated
vendored
Normal file
169
e2e/vendor/github.com/google/cel-go/common/types/err.go
generated
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// Error interface which allows types types.Err values to be treated as error values.
|
||||
type Error interface {
|
||||
error
|
||||
ref.Val
|
||||
}
|
||||
|
||||
// Err type which extends the built-in go error and implements ref.Val.
|
||||
type Err struct {
|
||||
error
|
||||
id int64
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrType singleton.
|
||||
ErrType = NewOpaqueType("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 ...any) ref.Val {
|
||||
return &Err{error: fmt.Errorf(format, args...)}
|
||||
}
|
||||
|
||||
// NewErrWithNodeID 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 NewErrWithNodeID(id int64, format string, args ...any) ref.Val {
|
||||
return &Err{error: fmt.Errorf(format, args...), id: id}
|
||||
}
|
||||
|
||||
// LabelErrNode returns val unaltered it is not an Err or if the error has a non-zero
|
||||
// AST node ID already present. Otherwise the id is added to the error for
|
||||
// recovery with the Err.NodeID method.
|
||||
func LabelErrNode(id int64, val ref.Val) ref.Val {
|
||||
if err, ok := val.(*Err); ok && err.id == 0 {
|
||||
err.id = id
|
||||
return err
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// 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 any) 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 ...any) ref.Val {
|
||||
if val == nil || !IsUnknownOrError(val) {
|
||||
return NewErr(format, args...)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// WrapErr wraps an existing Go error value into a CEL Err value.
|
||||
func WrapErr(err error) ref.Val {
|
||||
return &Err{error: err}
|
||||
}
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (e *Err) ConvertToNative(typeDesc reflect.Type) (any, 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() any {
|
||||
return e.error
|
||||
}
|
||||
|
||||
// NodeID returns the AST node ID of the expression that returned the error.
|
||||
func (e *Err) NodeID() int64 {
|
||||
return e.id
|
||||
}
|
||||
|
||||
// Is implements errors.Is.
|
||||
func (e *Err) Is(target error) bool {
|
||||
return e.error.Error() == target.Error()
|
||||
}
|
||||
|
||||
// Unwrap implements errors.Unwrap.
|
||||
func (e *Err) Unwrap() error {
|
||||
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
|
||||
}
|
||||
}
|
303
e2e/vendor/github.com/google/cel-go/common/types/int.go
generated
vendored
Normal file
303
e2e/vendor/github.com/google/cel-go/common/types/int.go
generated
vendored
Normal file
@ -0,0 +1,303 @@
|
||||
// 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"
|
||||
|
||||
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 (
|
||||
// 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) (any, 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.Int8:
|
||||
v, err := int64ToInt8Checked(int64(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reflect.ValueOf(v).Convert(typeDesc).Interface(), nil
|
||||
case reflect.Int16:
|
||||
v, err := int64ToInt16Checked(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
|
||||
}
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if integer is equal to 0
|
||||
func (i Int) IsZeroValue() bool {
|
||||
return i == IntZero
|
||||
}
|
||||
|
||||
// Modulo implements traits.Modder.Modulo.
|
||||
func (i Int) Modulo(other ref.Val) ref.Val {
|
||||
otherInt, ok := other.(Int)
|
||||
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() any {
|
||||
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
e2e/vendor/github.com/google/cel-go/common/types/iterator.go
generated
vendored
Normal file
55
e2e/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 = NewObjectType("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) (any, 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() any {
|
||||
return nil
|
||||
}
|
29
e2e/vendor/github.com/google/cel-go/common/types/json_value.go
generated
vendored
Normal file
29
e2e/vendor/github.com/google/cel-go/common/types/json_value.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// 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{})
|
||||
jsonNullType = reflect.TypeOf(structpb.NullValue_NULL_VALUE)
|
||||
)
|
574
e2e/vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
Normal file
574
e2e/vendor/github.com/google/cel-go/common/types/list.go
generated
vendored
Normal file
@ -0,0 +1,574 @@
|
||||
// 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"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// 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 Adapter, value any) traits.Lister {
|
||||
refValue := reflect.ValueOf(value)
|
||||
return &baseList{
|
||||
Adapter: adapter,
|
||||
value: value,
|
||||
size: refValue.Len(),
|
||||
get: func(i int) any {
|
||||
return refValue.Index(i).Interface()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringList returns a traits.Lister containing only strings.
|
||||
func NewStringList(adapter Adapter, elems []string) traits.Lister {
|
||||
return &baseList{
|
||||
Adapter: adapter,
|
||||
value: elems,
|
||||
size: len(elems),
|
||||
get: func(i int) any { 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 Adapter, elems []ref.Val) traits.Lister {
|
||||
return &baseList{
|
||||
Adapter: adapter,
|
||||
value: elems,
|
||||
size: len(elems),
|
||||
get: func(i int) any { return elems[i] },
|
||||
}
|
||||
}
|
||||
|
||||
// NewProtoList returns a traits.Lister based on a pb.List instance.
|
||||
func NewProtoList(adapter Adapter, list protoreflect.List) traits.Lister {
|
||||
return &baseList{
|
||||
Adapter: adapter,
|
||||
value: list,
|
||||
size: list.Len(),
|
||||
get: func(i int) any { return list.Get(i).Interface() },
|
||||
}
|
||||
}
|
||||
|
||||
// NewJSONList returns a traits.Lister based on structpb.ListValue instance.
|
||||
func NewJSONList(adapter Adapter, l *structpb.ListValue) traits.Lister {
|
||||
vals := l.GetValues()
|
||||
return &baseList{
|
||||
Adapter: adapter,
|
||||
value: l,
|
||||
size: len(vals),
|
||||
get: func(i int) any { return vals[i] },
|
||||
}
|
||||
}
|
||||
|
||||
// NewMutableList creates a new mutable list whose internal state can be modified.
|
||||
func NewMutableList(adapter Adapter) traits.MutableLister {
|
||||
var mutableValues []ref.Val
|
||||
l := &mutableList{
|
||||
baseList: &baseList{
|
||||
Adapter: adapter,
|
||||
value: mutableValues,
|
||||
size: 0,
|
||||
},
|
||||
mutableValues: mutableValues,
|
||||
}
|
||||
l.get = func(i int) any {
|
||||
return l.mutableValues[i]
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// 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 `Adapter` enables native type to CEL type conversions.
|
||||
type baseList struct {
|
||||
Adapter
|
||||
value any
|
||||
|
||||
// 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) any
|
||||
}
|
||||
|
||||
// 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{
|
||||
Adapter: l.Adapter,
|
||||
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) (any, error) {
|
||||
// If the underlying list value is assignable to the reflected type return it.
|
||||
if reflect.TypeOf(l.value).AssignableTo(typeDesc) {
|
||||
return l.value, nil
|
||||
}
|
||||
// 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
|
||||
var nativeList reflect.Value
|
||||
if typeDesc.Kind() == reflect.Array {
|
||||
nativeList = reflect.New(reflect.ArrayOf(elemCount, typeDesc)).Elem().Index(0)
|
||||
} else {
|
||||
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))
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the list is empty.
|
||||
func (l *baseList) IsZeroValue() bool {
|
||||
return l.size == 0
|
||||
}
|
||||
|
||||
// Fold calls the FoldEntry method for each (index, value) pair in the list.
|
||||
func (l *baseList) Fold(f traits.Folder) {
|
||||
for i := 0; i < l.size; i++ {
|
||||
if !f.FoldEntry(i, l.get(i)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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() any {
|
||||
return l.value
|
||||
}
|
||||
|
||||
// String converts the list to a human readable string form.
|
||||
func (l *baseList) String() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("[")
|
||||
for i := 0; i < l.size; i++ {
|
||||
sb.WriteString(fmt.Sprintf("%v", l.get(i)))
|
||||
if i != l.size-1 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
}
|
||||
sb.WriteString("]")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// mutableList aggregates values into its internal storage. For use with internal CEL variables only.
|
||||
type mutableList struct {
|
||||
*baseList
|
||||
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.Adapter, l.mutableValues)
|
||||
}
|
||||
|
||||
// concatList combines two list implementations together into a view.
|
||||
// The `Adapter` enables native type to CEL type conversions.
|
||||
type concatList struct {
|
||||
Adapter
|
||||
value any
|
||||
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{
|
||||
Adapter: l.Adapter,
|
||||
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) (any, error) {
|
||||
combined := NewDynamicList(l.Adapter, l.Value().([]any))
|
||||
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)
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the list is empty.
|
||||
func (l *concatList) IsZeroValue() bool {
|
||||
return l.Size().(Int) == 0
|
||||
}
|
||||
|
||||
// Fold calls the FoldEntry method for each (index, value) pair in the list.
|
||||
func (l *concatList) Fold(f traits.Folder) {
|
||||
for i := Int(0); i < l.Size().(Int); i++ {
|
||||
if !f.FoldEntry(i, l.Get(i)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
|
||||
// String converts the concatenated list to a human-readable string.
|
||||
func (l *concatList) String() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("[")
|
||||
for i := Int(0); i < l.Size().(Int); i++ {
|
||||
sb.WriteString(fmt.Sprintf("%v", l.Get(i)))
|
||||
if i != l.Size().(Int)-1 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
}
|
||||
sb.WriteString("]")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (l *concatList) Type() ref.Type {
|
||||
return ListType
|
||||
}
|
||||
|
||||
// Value implements the ref.Val interface method.
|
||||
func (l *concatList) Value() any {
|
||||
if l.value == nil {
|
||||
merged := make([]any, l.Size().(Int))
|
||||
prevLen := l.prevList.Size().(Int)
|
||||
for i := Int(0); i < prevLen; i++ {
|
||||
merged[i] = l.prevList.Get(i).Value()
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// IndexOrError converts an input index value into either a lossless integer index or an error.
|
||||
func IndexOrError(index ref.Val) (int, error) {
|
||||
switch iv := index.(type) {
|
||||
case Int:
|
||||
return int(iv), nil
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
// ToFoldableList will create a Foldable version of a list suitable for key-value pair iteration.
|
||||
//
|
||||
// For values which are already Foldable, this call is a no-op. For all other values, the fold is
|
||||
// driven via the Size() and Get() calls which means that the folding will function, but take a
|
||||
// performance hit.
|
||||
func ToFoldableList(l traits.Lister) traits.Foldable {
|
||||
if f, ok := l.(traits.Foldable); ok {
|
||||
return f
|
||||
}
|
||||
return interopFoldableList{Lister: l}
|
||||
}
|
||||
|
||||
type interopFoldableList struct {
|
||||
traits.Lister
|
||||
}
|
||||
|
||||
// Fold implements the traits.Foldable interface method and performs an iteration over the
|
||||
// range of elements of the list.
|
||||
func (l interopFoldableList) Fold(f traits.Folder) {
|
||||
sz := l.Size().(Int)
|
||||
for i := Int(0); i < sz; i++ {
|
||||
if !f.FoldEntry(i, l.Get(i)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
1002
e2e/vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
Normal file
1002
e2e/vendor/github.com/google/cel-go/common/types/map.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
119
e2e/vendor/github.com/google/cel-go/common/types/null.go
generated
vendored
Normal file
119
e2e/vendor/github.com/google/cel-go/common/types/null.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
// 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"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// Null type implementation.
|
||||
type Null structpb.NullValue
|
||||
|
||||
var (
|
||||
// NullValue singleton.
|
||||
NullValue = Null(structpb.NullValue_NULL_VALUE)
|
||||
|
||||
// golang reflect type for Null values.
|
||||
nullReflectType = reflect.TypeOf(NullValue)
|
||||
|
||||
protoIfaceType = reflect.TypeOf((*proto.Message)(nil)).Elem()
|
||||
)
|
||||
|
||||
// ConvertToNative implements ref.Val.ConvertToNative.
|
||||
func (n Null) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.Int32:
|
||||
switch typeDesc {
|
||||
case jsonNullType:
|
||||
return structpb.NullValue_NULL_VALUE, nil
|
||||
case nullReflectType:
|
||||
return n, 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 boolWrapperType, byteWrapperType, doubleWrapperType, floatWrapperType,
|
||||
int32WrapperType, int64WrapperType, stringWrapperType, uint32WrapperType,
|
||||
uint64WrapperType, durationValueType, timestampValueType, protoIfaceType:
|
||||
return nil, nil
|
||||
case jsonListValueType, jsonStructType:
|
||||
// skip handling
|
||||
default:
|
||||
if typeDesc.Implements(protoIfaceType) {
|
||||
return nil, 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())
|
||||
}
|
||||
|
||||
// IsZeroValue returns true as null always represents an absent value.
|
||||
func (n Null) IsZeroValue() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Type implements ref.Val.Type.
|
||||
func (n Null) Type() ref.Type {
|
||||
return NullType
|
||||
}
|
||||
|
||||
// Value implements ref.Val.Value.
|
||||
func (n Null) Value() any {
|
||||
return structpb.NullValue_NULL_VALUE
|
||||
}
|
165
e2e/vendor/github.com/google/cel-go/common/types/object.go
generated
vendored
Normal file
165
e2e/vendor/github.com/google/cel-go/common/types/object.go
generated
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
// 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"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/google/cel-go/common/types/pb"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
type protoObj struct {
|
||||
Adapter
|
||||
value proto.Message
|
||||
typeDesc *pb.TypeDescription
|
||||
typeValue ref.Val
|
||||
}
|
||||
|
||||
// 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 Adapter,
|
||||
typeDesc *pb.TypeDescription,
|
||||
typeValue ref.Val,
|
||||
value proto.Message) ref.Val {
|
||||
return &protoObj{
|
||||
Adapter: adapter,
|
||||
value: value,
|
||||
typeDesc: typeDesc,
|
||||
typeValue: typeValue}
|
||||
}
|
||||
|
||||
func (o *protoObj) ConvertToNative(typeDesc reflect.Type) (any, 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
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the protobuf object is empty.
|
||||
func (o *protoObj) IsZeroValue() bool {
|
||||
return proto.Equal(o.value, o.typeDesc.Zero())
|
||||
}
|
||||
|
||||
func (o *protoObj) Get(index ref.Val) ref.Val {
|
||||
protoFieldName, ok := index.(String)
|
||||
if !ok {
|
||||
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.(ref.Type)
|
||||
}
|
||||
|
||||
func (o *protoObj) Value() any {
|
||||
return o.value
|
||||
}
|
108
e2e/vendor/github.com/google/cel-go/common/types/optional.go
generated
vendored
Normal file
108
e2e/vendor/github.com/google/cel-go/common/types/optional.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
var (
|
||||
// OptionalType indicates the runtime type of an optional value.
|
||||
OptionalType = NewOpaqueType("optional_type")
|
||||
|
||||
// OptionalNone is a sentinel value which is used to indicate an empty optional value.
|
||||
OptionalNone = &Optional{}
|
||||
)
|
||||
|
||||
// OptionalOf returns an optional value which wraps a concrete CEL value.
|
||||
func OptionalOf(value ref.Val) *Optional {
|
||||
return &Optional{value: value}
|
||||
}
|
||||
|
||||
// Optional value which points to a value if non-empty.
|
||||
type Optional struct {
|
||||
value ref.Val
|
||||
}
|
||||
|
||||
// HasValue returns true if the optional has a value.
|
||||
func (o *Optional) HasValue() bool {
|
||||
return o.value != nil
|
||||
}
|
||||
|
||||
// GetValue returns the wrapped value contained in the optional.
|
||||
func (o *Optional) GetValue() ref.Val {
|
||||
if !o.HasValue() {
|
||||
return NewErr("optional.none() dereference")
|
||||
}
|
||||
return o.value
|
||||
}
|
||||
|
||||
// ConvertToNative implements the ref.Val interface method.
|
||||
func (o *Optional) ConvertToNative(typeDesc reflect.Type) (any, error) {
|
||||
if !o.HasValue() {
|
||||
return nil, errors.New("optional.none() dereference")
|
||||
}
|
||||
return o.value.ConvertToNative(typeDesc)
|
||||
}
|
||||
|
||||
// ConvertToType implements the ref.Val interface method.
|
||||
func (o *Optional) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case OptionalType:
|
||||
return o
|
||||
case TypeType:
|
||||
return OptionalType
|
||||
}
|
||||
return NewErr("type conversion error from '%s' to '%s'", OptionalType, typeVal)
|
||||
}
|
||||
|
||||
// Equal determines whether the values contained by two optional values are equal.
|
||||
func (o *Optional) Equal(other ref.Val) ref.Val {
|
||||
otherOpt, isOpt := other.(*Optional)
|
||||
if !isOpt {
|
||||
return False
|
||||
}
|
||||
if !o.HasValue() {
|
||||
return Bool(!otherOpt.HasValue())
|
||||
}
|
||||
if !otherOpt.HasValue() {
|
||||
return False
|
||||
}
|
||||
return o.value.Equal(otherOpt.value)
|
||||
}
|
||||
|
||||
func (o *Optional) String() string {
|
||||
if o.HasValue() {
|
||||
return fmt.Sprintf("optional(%v)", o.GetValue())
|
||||
}
|
||||
return "optional.none()"
|
||||
}
|
||||
|
||||
// Type implements the ref.Val interface method.
|
||||
func (o *Optional) Type() ref.Type {
|
||||
return OptionalType
|
||||
}
|
||||
|
||||
// Value returns the underlying 'Value()' of the wrapped value, if present.
|
||||
func (o *Optional) Value() any {
|
||||
if o.value == nil {
|
||||
return nil
|
||||
}
|
||||
return o.value.Value()
|
||||
}
|
429
e2e/vendor/github.com/google/cel-go/common/types/overflow.go
generated
vendored
Normal file
429
e2e/vendor/github.com/google/cel-go/common/types/overflow.go
generated
vendored
Normal file
@ -0,0 +1,429 @@
|
||||
// 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
|
||||
}
|
||||
|
||||
// int64ToInt8Checked converts an int64 to an int8 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func int64ToInt8Checked(v int64) (int8, error) {
|
||||
if v < math.MinInt8 || v > math.MaxInt8 {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return int8(v), nil
|
||||
}
|
||||
|
||||
// int64ToInt16Checked converts an int64 to an int16 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func int64ToInt16Checked(v int64) (int16, error) {
|
||||
if v < math.MinInt16 || v > math.MaxInt16 {
|
||||
return 0, errIntOverflow
|
||||
}
|
||||
return int16(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
|
||||
}
|
||||
|
||||
// uint64ToUint8Checked converts a uint64 to a uint8 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func uint64ToUint8Checked(v uint64) (uint8, error) {
|
||||
if v > math.MaxUint8 {
|
||||
return 0, errUintOverflow
|
||||
}
|
||||
return uint8(v), nil
|
||||
}
|
||||
|
||||
// uint64ToUint16Checked converts a uint64 to a uint16 value.
|
||||
//
|
||||
// If the conversion fails due to overflow the error return value will be non-nil.
|
||||
func uint64ToUint16Checked(v uint64) (uint16, error) {
|
||||
if v > math.MaxUint16 {
|
||||
return 0, errUintOverflow
|
||||
}
|
||||
return uint16(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
e2e/vendor/github.com/google/cel-go/common/types/pb/BUILD.bazel
generated
vendored
Normal file
53
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/pb/checked.go
generated
vendored
Normal file
93
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/pb/enum.go
generated
vendored
Normal file
44
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/pb/equal.go
generated
vendored
Normal file
206
e2e/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"
|
||||
}
|
202
e2e/vendor/github.com/google/cel-go/common/types/pb/file.go
generated
vendored
Normal file
202
e2e/vendor/github.com/google/cel-go/common/types/pb/file.go
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
// Copyright 2018 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
dynamicpb "google.golang.org/protobuf/types/dynamicpb"
|
||||
)
|
||||
|
||||
// newFileDescription returns a FileDescription instance with a complete listing of all the message
|
||||
// types and enum values, as well as a map of extensions declared within any scope in the file.
|
||||
func newFileDescription(fileDesc protoreflect.FileDescriptor, pbdb *Db) (*FileDescription, extensionMap) {
|
||||
metadata := collectFileMetadata(fileDesc)
|
||||
enums := make(map[string]*EnumValueDescription)
|
||||
for name, enumVal := range metadata.enumValues {
|
||||
enums[name] = newEnumValueDescription(name, enumVal)
|
||||
}
|
||||
types := make(map[string]*TypeDescription)
|
||||
for name, msgType := range metadata.msgTypes {
|
||||
types[name] = newTypeDescription(name, msgType, pbdb.extensions)
|
||||
}
|
||||
fileExtMap := make(extensionMap)
|
||||
for typeName, extensions := range metadata.msgExtensionMap {
|
||||
messageExtMap, found := fileExtMap[typeName]
|
||||
if !found {
|
||||
messageExtMap = make(map[string]*FieldDescription)
|
||||
}
|
||||
for _, ext := range extensions {
|
||||
extDesc := dynamicpb.NewExtensionType(ext).TypeDescriptor()
|
||||
messageExtMap[string(ext.FullName())] = newFieldDescription(extDesc)
|
||||
}
|
||||
fileExtMap[typeName] = messageExtMap
|
||||
}
|
||||
return &FileDescription{
|
||||
name: fileDesc.Path(),
|
||||
types: types,
|
||||
enums: enums,
|
||||
}, fileExtMap
|
||||
}
|
||||
|
||||
// FileDescription holds a map of all types and enum values declared within a proto file.
|
||||
type FileDescription struct {
|
||||
name string
|
||||
types map[string]*TypeDescription
|
||||
enums map[string]*EnumValueDescription
|
||||
}
|
||||
|
||||
// Copy creates a copy of the FileDescription with updated Db references within its types.
|
||||
func (fd *FileDescription) Copy(pbdb *Db) *FileDescription {
|
||||
typesCopy := make(map[string]*TypeDescription, len(fd.types))
|
||||
for k, v := range fd.types {
|
||||
typesCopy[k] = v.Copy(pbdb)
|
||||
}
|
||||
return &FileDescription{
|
||||
name: fd.name,
|
||||
types: typesCopy,
|
||||
enums: fd.enums,
|
||||
}
|
||||
}
|
||||
|
||||
// GetName returns the fully qualified file path for the file.
|
||||
func (fd *FileDescription) GetName() string {
|
||||
return fd.name
|
||||
}
|
||||
|
||||
// GetEnumDescription returns an EnumDescription for a qualified enum value
|
||||
// name declared within the .proto file.
|
||||
func (fd *FileDescription) GetEnumDescription(enumName string) (*EnumValueDescription, bool) {
|
||||
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
|
||||
// msgExtensionMap maps from the protobuf message name being extended to a set of extensions
|
||||
// for the type.
|
||||
msgExtensionMap map[string][]protoreflect.ExtensionDescriptor
|
||||
|
||||
// TODO: support enum type definitions for use in future type-check enhancements.
|
||||
}
|
||||
|
||||
// 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)
|
||||
msgExtensionMap := make(map[string][]protoreflect.ExtensionDescriptor)
|
||||
collectMsgTypes(fileDesc.Messages(), msgTypes, enumValues, msgExtensionMap)
|
||||
collectEnumValues(fileDesc.Enums(), enumValues)
|
||||
collectExtensions(fileDesc.Extensions(), msgExtensionMap)
|
||||
return &fileMetadata{
|
||||
msgTypes: msgTypes,
|
||||
enumValues: enumValues,
|
||||
msgExtensionMap: msgExtensionMap,
|
||||
}
|
||||
}
|
||||
|
||||
// collectMsgTypes recursively collects messages, nested messages, and nested enums into a map of
|
||||
// fully qualified protobuf names to descriptors.
|
||||
func collectMsgTypes(msgTypes protoreflect.MessageDescriptors,
|
||||
msgTypeMap map[string]protoreflect.MessageDescriptor,
|
||||
enumValueMap map[string]protoreflect.EnumValueDescriptor,
|
||||
msgExtensionMap map[string][]protoreflect.ExtensionDescriptor) {
|
||||
for i := 0; i < msgTypes.Len(); i++ {
|
||||
msgType := msgTypes.Get(i)
|
||||
msgTypeMap[string(msgType.FullName())] = msgType
|
||||
nestedMsgTypes := msgType.Messages()
|
||||
if nestedMsgTypes.Len() != 0 {
|
||||
collectMsgTypes(nestedMsgTypes, msgTypeMap, enumValueMap, msgExtensionMap)
|
||||
}
|
||||
nestedEnumTypes := msgType.Enums()
|
||||
if nestedEnumTypes.Len() != 0 {
|
||||
collectEnumValues(nestedEnumTypes, enumValueMap)
|
||||
}
|
||||
nestedExtensions := msgType.Extensions()
|
||||
if nestedExtensions.Len() != 0 {
|
||||
collectExtensions(nestedExtensions, msgExtensionMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func collectExtensions(extensions protoreflect.ExtensionDescriptors, msgExtensionMap map[string][]protoreflect.ExtensionDescriptor) {
|
||||
for i := 0; i < extensions.Len(); i++ {
|
||||
ext := extensions.Get(i)
|
||||
extendsMsg := string(ext.ContainingMessage().FullName())
|
||||
msgExts, found := msgExtensionMap[extendsMsg]
|
||||
if !found {
|
||||
msgExts = []protoreflect.ExtensionDescriptor{}
|
||||
}
|
||||
msgExts = append(msgExts, ext)
|
||||
msgExtensionMap[extendsMsg] = msgExts
|
||||
}
|
||||
}
|
258
e2e/vendor/github.com/google/cel-go/common/types/pb/pb.go
generated
vendored
Normal file
258
e2e/vendor/github.com/google/cel-go/common/types/pb/pb.go
generated
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
// 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
|
||||
// extensions contains the mapping between a given type name, extension name and its FieldDescription
|
||||
extensions map[string]map[string]*FieldDescription
|
||||
}
|
||||
|
||||
// extensionsMap is a type alias to a map[typeName]map[extensionName]*FieldDescription
|
||||
type extensionMap = map[string]map[string]*FieldDescription
|
||||
|
||||
var (
|
||||
// DefaultDb used at evaluation time or unless overridden at check time.
|
||||
DefaultDb = &Db{
|
||||
revFileDescriptorMap: make(map[string]*FileDescription),
|
||||
files: []*FileDescription{},
|
||||
extensions: make(extensionMap),
|
||||
}
|
||||
)
|
||||
|
||||
// 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{},
|
||||
extensions: make(extensionMap),
|
||||
}
|
||||
// The FileDescription objects in the default db contain lazily initialized TypeDescription
|
||||
// values which may point to the state contained in the DefaultDb irrespective of this shallow
|
||||
// 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 _, fd := range pbdb.files {
|
||||
hasFile := false
|
||||
for _, fd2 := range copy.files {
|
||||
if fd2 == fd {
|
||||
hasFile = true
|
||||
}
|
||||
}
|
||||
if !hasFile {
|
||||
fd = fd.Copy(copy)
|
||||
copy.files = append(copy.files, fd)
|
||||
}
|
||||
for _, enumValName := range fd.GetEnumNames() {
|
||||
copy.revFileDescriptorMap[enumValName] = fd
|
||||
}
|
||||
for _, msgTypeName := range fd.GetTypeNames() {
|
||||
copy.revFileDescriptorMap[msgTypeName] = fd
|
||||
}
|
||||
copy.revFileDescriptorMap[fd.GetName()] = fd
|
||||
}
|
||||
for typeName, extFieldMap := range pbdb.extensions {
|
||||
copyExtFieldMap, found := copy.extensions[typeName]
|
||||
if !found {
|
||||
copyExtFieldMap = make(map[string]*FieldDescription, len(extFieldMap))
|
||||
}
|
||||
for extFieldName, fd := range extFieldMap {
|
||||
copyExtFieldMap[extFieldName] = fd
|
||||
}
|
||||
copy.extensions[typeName] = copyExtFieldMap
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
var fileExtMap extensionMap
|
||||
fd, fileExtMap = newFileDescription(fileDesc, pbdb)
|
||||
for _, enumValName := range fd.GetEnumNames() {
|
||||
pbdb.revFileDescriptorMap[enumValName] = fd
|
||||
}
|
||||
for _, msgTypeName := range fd.GetTypeNames() {
|
||||
pbdb.revFileDescriptorMap[msgTypeName] = fd
|
||||
}
|
||||
pbdb.revFileDescriptorMap[fd.GetName()] = fd
|
||||
|
||||
// Return the specific file descriptor registered.
|
||||
pbdb.files = append(pbdb.files, fd)
|
||||
|
||||
// Index the protobuf message extensions from the file into the pbdb
|
||||
for typeName, extMap := range fileExtMap {
|
||||
typeExtMap, found := pbdb.extensions[typeName]
|
||||
if !found {
|
||||
pbdb.extensions[typeName] = extMap
|
||||
continue
|
||||
}
|
||||
for extName, field := range extMap {
|
||||
typeExtMap[extName] = field
|
||||
}
|
||||
}
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// 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{})
|
||||
}
|
614
e2e/vendor/github.com/google/cel-go/common/types/pb/type.go
generated
vendored
Normal file
614
e2e/vendor/github.com/google/cel-go/common/types/pb/type.go
generated
vendored
Normal file
@ -0,0 +1,614 @@
|
||||
// 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, extensions extensionMap) *TypeDescription {
|
||||
msgType := dynamicpb.NewMessageType(desc)
|
||||
msgZero := dynamicpb.NewMessage(desc)
|
||||
fieldMap := map[string]*FieldDescription{}
|
||||
fields := desc.Fields()
|
||||
for i := 0; i < fields.Len(); i++ {
|
||||
f := fields.Get(i)
|
||||
fieldMap[string(f.Name())] = newFieldDescription(f)
|
||||
}
|
||||
return &TypeDescription{
|
||||
typeName: typeName,
|
||||
desc: desc,
|
||||
msgType: msgType,
|
||||
fieldMap: fieldMap,
|
||||
extensions: extensions,
|
||||
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
|
||||
extensions extensionMap
|
||||
reflectType reflect.Type
|
||||
zeroMsg proto.Message
|
||||
}
|
||||
|
||||
// Copy copies the type description with updated references to the Db.
|
||||
func (td *TypeDescription) Copy(pbdb *Db) *TypeDescription {
|
||||
return &TypeDescription{
|
||||
typeName: td.typeName,
|
||||
desc: td.desc,
|
||||
msgType: td.msgType,
|
||||
fieldMap: td.fieldMap,
|
||||
extensions: pbdb.extensions,
|
||||
reflectType: td.reflectType,
|
||||
zeroMsg: td.zeroMsg,
|
||||
}
|
||||
}
|
||||
|
||||
// FieldMap returns a string field name to FieldDescription map.
|
||||
func (td *TypeDescription) FieldMap() map[string]*FieldDescription {
|
||||
return td.fieldMap
|
||||
}
|
||||
|
||||
// FieldByName returns (FieldDescription, true) if the field name is declared within the type.
|
||||
func (td *TypeDescription) FieldByName(name string) (*FieldDescription, bool) {
|
||||
fd, found := td.fieldMap[name]
|
||||
if found {
|
||||
return fd, true
|
||||
}
|
||||
extFieldMap, found := td.extensions[td.typeName]
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
fd, found = extFieldMap[name]
|
||||
return fd, found
|
||||
}
|
||||
|
||||
// MaybeUnwrap accepts a proto message as input and unwraps it to a primitive CEL type if possible.
|
||||
//
|
||||
// This method returns the unwrapped value and 'true', else the original value and 'false'.
|
||||
func (td *TypeDescription) MaybeUnwrap(msg proto.Message) (any, 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() {
|
||||
var elemValue protoreflect.Value
|
||||
if fieldDesc.IsExtension() {
|
||||
et := dynamicpb.NewExtensionType(fieldDesc)
|
||||
elemValue = et.New().List().NewElement()
|
||||
} else {
|
||||
parentMsgType := fieldDesc.ContainingMessage()
|
||||
parentMsg := dynamicpb.NewMessage(parentMsgType)
|
||||
listField := parentMsg.NewField(fieldDesc).List()
|
||||
elemValue = listField.NewElement()
|
||||
}
|
||||
elem := elemValue.Interface()
|
||||
switch elemType := elem.(type) {
|
||||
case protoreflect.Message:
|
||||
elem = elemType.Interface()
|
||||
}
|
||||
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 any) 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 any) (any, error) {
|
||||
v, ok := target.(proto.Message)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported field selection target: (%T)%v", target, target)
|
||||
}
|
||||
pbRef := v.ProtoReflect()
|
||||
pbDesc := pbRef.Descriptor()
|
||||
var fieldVal any
|
||||
if pbDesc == fd.desc.ContainingMessage() {
|
||||
// When the target protobuf shares the same message descriptor instance as the field
|
||||
// descriptor, use the cached field descriptor value.
|
||||
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.ProtoKind() == 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.ProtoKind()
|
||||
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) (any, 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())
|
||||
}
|
||||
|
||||
// ProtoKind returns the protobuf reflected kind of the field.
|
||||
func (fd *FieldDescription) ProtoKind() protoreflect.Kind {
|
||||
return fd.desc.Kind()
|
||||
}
|
||||
|
||||
// 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.IsMessage() {
|
||||
msgType := string(fd.desc.Message().FullName())
|
||||
if wk, found := CheckedWellKnowns[msgType]; found {
|
||||
return wk
|
||||
}
|
||||
return checkedMessageType(msgType)
|
||||
}
|
||||
if fd.IsEnum() {
|
||||
return checkedInt
|
||||
}
|
||||
return CheckedPrimitives[fd.ProtoKind()]
|
||||
}
|
||||
|
||||
// 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) (any, 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:
|
||||
if v == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.BytesValue:
|
||||
if v == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.DoubleValue:
|
||||
if v == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.FloatValue:
|
||||
if v == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
return float64(v.GetValue()), true, nil
|
||||
case *wrapperspb.Int32Value:
|
||||
if v == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
return int64(v.GetValue()), true, nil
|
||||
case *wrapperspb.Int64Value:
|
||||
if v == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.StringValue:
|
||||
if v == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
return v.GetValue(), true, nil
|
||||
case *wrapperspb.UInt32Value:
|
||||
if v == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
return uint64(v.GetValue()), true, nil
|
||||
case *wrapperspb.UInt64Value:
|
||||
if v == nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
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) (any, 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, fmt.Errorf("unwrap dynamic field failed: %v", 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, fmt.Errorf("unmarshal dynamic any failed: %v", 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 any) 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 (
|
||||
jsonValueTypeURL = "types.googleapis.com/google.protobuf.Value"
|
||||
|
||||
zeroValueMap = map[string]proto.Message{
|
||||
"google.protobuf.Any": &anypb.Any{TypeUrl: jsonValueTypeURL},
|
||||
"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),
|
||||
}
|
||||
)
|
766
e2e/vendor/github.com/google/cel-go/common/types/provider.go
generated
vendored
Normal file
766
e2e/vendor/github.com/google/cel-go/common/types/provider.go
generated
vendored
Normal file
@ -0,0 +1,766 @@
|
||||
// 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"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
"github.com/google/cel-go/common/types/pb"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Adapter converts native Go values of varying type and complexity to equivalent CEL values.
|
||||
type Adapter = ref.TypeAdapter
|
||||
|
||||
// Provider specifies functions for creating new object instances and for resolving
|
||||
// enum values by name.
|
||||
type Provider interface {
|
||||
// EnumValue returns the numeric value of the given enum value name.
|
||||
EnumValue(enumName string) ref.Val
|
||||
|
||||
// FindIdent takes a qualified identifier name and returns a ref.Val if one exists.
|
||||
FindIdent(identName string) (ref.Val, bool)
|
||||
|
||||
// FindStructType returns the Type give a qualified type name.
|
||||
//
|
||||
// For historical reasons, only struct types are expected to be returned through this
|
||||
// method, and the type values are expected to be wrapped in a TypeType instance using
|
||||
// TypeTypeWithParam(<structType>).
|
||||
//
|
||||
// Returns false if not found.
|
||||
FindStructType(structType string) (*Type, bool)
|
||||
|
||||
// FindStructFieldNames returns thet field names associated with the type, if the type
|
||||
// is found.
|
||||
FindStructFieldNames(structType string) ([]string, bool)
|
||||
|
||||
// FieldStructFieldType returns the field type for a checked type value. Returns
|
||||
// false if the field could not be found.
|
||||
FindStructFieldType(structType, 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(structType string, fields map[string]ref.Val) ref.Val
|
||||
}
|
||||
|
||||
// FieldType represents a field's type value and whether that field supports presence detection.
|
||||
type FieldType struct {
|
||||
// Type of the field as a CEL native type value.
|
||||
Type *Type
|
||||
|
||||
// IsSet indicates whether the field is set on an input object.
|
||||
IsSet ref.FieldTester
|
||||
|
||||
// GetFrom retrieves the field value on the input object, if set.
|
||||
GetFrom ref.FieldGetter
|
||||
}
|
||||
|
||||
// Registry provides type information for a set of registered types.
|
||||
type Registry struct {
|
||||
revTypeMap map[string]*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) (*Registry, error) {
|
||||
p := &Registry{
|
||||
revTypeMap: make(map[string]*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() *Registry {
|
||||
return &Registry{
|
||||
revTypeMap: make(map[string]*Type),
|
||||
pbdb: pb.NewDb(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy copies the current state of the registry into its own memory space.
|
||||
func (p *Registry) Copy() *Registry {
|
||||
copy := &Registry{
|
||||
revTypeMap: make(map[string]*Type),
|
||||
pbdb: p.pbdb.Copy(),
|
||||
}
|
||||
for k, v := range p.revTypeMap {
|
||||
copy.revTypeMap[k] = v
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
// EnumValue returns the numeric value of the given enum value name.
|
||||
func (p *Registry) EnumValue(enumName string) ref.Val {
|
||||
enumVal, found := p.pbdb.DescribeEnum(enumName)
|
||||
if !found {
|
||||
return NewErr("unknown enum name '%s'", enumName)
|
||||
}
|
||||
return Int(enumVal.Value())
|
||||
}
|
||||
|
||||
// FindFieldType returns the field type for a checked type value. Returns false if
|
||||
// the field could not be found.
|
||||
//
|
||||
// Deprecated: use FindStructFieldType
|
||||
func (p *Registry) FindFieldType(structType, fieldName string) (*ref.FieldType, bool) {
|
||||
msgType, found := p.pbdb.DescribeType(structType)
|
||||
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
|
||||
}
|
||||
|
||||
// FindStructFieldNames returns the set of field names for the given struct type,
|
||||
// if the type exists in the registry.
|
||||
func (p *Registry) FindStructFieldNames(structType string) ([]string, bool) {
|
||||
msgType, found := p.pbdb.DescribeType(structType)
|
||||
if !found {
|
||||
return []string{}, false
|
||||
}
|
||||
fieldMap := msgType.FieldMap()
|
||||
fields := make([]string, len(fieldMap))
|
||||
idx := 0
|
||||
for f := range fieldMap {
|
||||
fields[idx] = f
|
||||
idx++
|
||||
}
|
||||
return fields, true
|
||||
}
|
||||
|
||||
// FindStructFieldType returns the field type for a checked type value. Returns
|
||||
// false if the field could not be found.
|
||||
func (p *Registry) FindStructFieldType(structType, fieldName string) (*FieldType, bool) {
|
||||
msgType, found := p.pbdb.DescribeType(structType)
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
field, found := msgType.FieldByName(fieldName)
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
return &FieldType{
|
||||
Type: fieldDescToCELType(field),
|
||||
IsSet: field.IsSet,
|
||||
GetFrom: field.GetFrom}, true
|
||||
}
|
||||
|
||||
// FindIdent takes a qualified identifier name and returns a ref.Val if one exists.
|
||||
func (p *Registry) FindIdent(identName string) (ref.Val, bool) {
|
||||
if t, found := p.revTypeMap[identName]; found {
|
||||
return t, true
|
||||
}
|
||||
if enumVal, found := p.pbdb.DescribeEnum(identName); found {
|
||||
return Int(enumVal.Value()), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// FindType looks up the Type given a qualified typeName. Returns false if not found.
|
||||
//
|
||||
// Deprecated: use FindStructType
|
||||
func (p *Registry) FindType(structType string) (*exprpb.Type, bool) {
|
||||
if _, found := p.pbdb.DescribeType(structType); !found {
|
||||
return nil, false
|
||||
}
|
||||
if structType != "" && structType[0] == '.' {
|
||||
structType = structType[1:]
|
||||
}
|
||||
return &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_Type{
|
||||
Type: &exprpb.Type{
|
||||
TypeKind: &exprpb.Type_MessageType{
|
||||
MessageType: structType}}}}, true
|
||||
}
|
||||
|
||||
// FindStructType returns the Type give a qualified type name.
|
||||
//
|
||||
// For historical reasons, only struct types are expected to be returned through this
|
||||
// method, and the type values are expected to be wrapped in a TypeType instance using
|
||||
// TypeTypeWithParam(<structType>).
|
||||
//
|
||||
// Returns false if not found.
|
||||
func (p *Registry) FindStructType(structType string) (*Type, bool) {
|
||||
if _, found := p.pbdb.DescribeType(structType); !found {
|
||||
return nil, false
|
||||
}
|
||||
if structType != "" && structType[0] == '.' {
|
||||
structType = structType[1:]
|
||||
}
|
||||
return NewTypeTypeWithParam(NewObjectType(structType)), true
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (p *Registry) NewValue(structType string, fields map[string]ref.Val) ref.Val {
|
||||
td, found := p.pbdb.DescribeType(structType)
|
||||
if !found {
|
||||
return NewErr("unknown type '%s'", structType)
|
||||
}
|
||||
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{error: err}
|
||||
}
|
||||
}
|
||||
return p.NativeToValue(msg.Interface())
|
||||
}
|
||||
|
||||
// RegisterDescriptor registers the contents of a protocol buffer `FileDescriptor`.
|
||||
func (p *Registry) RegisterDescriptor(fileDesc protoreflect.FileDescriptor) error {
|
||||
fd, err := p.pbdb.RegisterDescriptor(fileDesc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.registerAllTypes(fd)
|
||||
}
|
||||
|
||||
// RegisterMessage registers a protocol buffer message and its dependencies.
|
||||
func (p *Registry) RegisterMessage(message proto.Message) error {
|
||||
fd, err := p.pbdb.RegisterMessage(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.registerAllTypes(fd)
|
||||
}
|
||||
|
||||
// RegisterType registers a type value with the provider which ensures the provider is aware of how to
|
||||
// map the type to an identifier.
|
||||
//
|
||||
// If the `ref.Type` value is a `*types.Type` it will be registered directly by its runtime type name.
|
||||
// If the `ref.Type` value is not a `*types.Type` instance, a `*types.Type` instance which reflects the
|
||||
// traits present on the input and the runtime type name. By default this foreign type will be treated
|
||||
// as a types.StructKind. To avoid potential issues where the `ref.Type` values does not match the
|
||||
// generated `*types.Type` instance, consider always using the `*types.Type` to represent type extensions
|
||||
// to CEL, even when they're not based on protobuf types.
|
||||
func (p *Registry) RegisterType(types ...ref.Type) error {
|
||||
for _, t := range types {
|
||||
celType := maybeForeignType(t)
|
||||
existing, found := p.revTypeMap[t.TypeName()]
|
||||
if !found {
|
||||
p.revTypeMap[t.TypeName()] = celType
|
||||
continue
|
||||
}
|
||||
if !existing.IsEquivalentType(celType) {
|
||||
return fmt.Errorf("type registration conflict. found: %v, input: %v", existing, celType)
|
||||
}
|
||||
if existing.traitMask != celType.traitMask {
|
||||
return fmt.Errorf(
|
||||
"type registered with conflicting traits: %v with traits %v, input: %v",
|
||||
existing.TypeName(), existing.traitMask, celType.traitMask)
|
||||
}
|
||||
}
|
||||
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 *Registry) NativeToValue(value any) 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, 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 *Registry) registerAllTypes(fd *pb.FileDescription) error {
|
||||
for _, typeName := range fd.GetTypeNames() {
|
||||
// skip well-known type names since they're automatically sanitized
|
||||
// during NewObjectType() calls.
|
||||
if _, found := checkedWellKnowns[typeName]; found {
|
||||
continue
|
||||
}
|
||||
err := p.RegisterType(NewObjectTypeValue(typeName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fieldDescToCELType(field *pb.FieldDescription) *Type {
|
||||
if field.IsMap() {
|
||||
return NewMapType(
|
||||
singularFieldDescToCELType(field.KeyType),
|
||||
singularFieldDescToCELType(field.ValueType))
|
||||
}
|
||||
if field.IsList() {
|
||||
return NewListType(singularFieldDescToCELType(field))
|
||||
}
|
||||
return singularFieldDescToCELType(field)
|
||||
}
|
||||
|
||||
func singularFieldDescToCELType(field *pb.FieldDescription) *Type {
|
||||
if field.IsMessage() {
|
||||
return NewObjectType(string(field.Descriptor().Message().FullName()))
|
||||
}
|
||||
if field.IsEnum() {
|
||||
return IntType
|
||||
}
|
||||
return ProtoCELPrimitives[field.ProtoKind()]
|
||||
}
|
||||
|
||||
// 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 any) 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 Adapter, value any) (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]any:
|
||||
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:
|
||||
if refValue.Type().Elem() == reflect.TypeOf(byte(0)) {
|
||||
if refValue.CanAddr() {
|
||||
return Bytes(refValue.Bytes()), true
|
||||
}
|
||||
tmp := reflect.New(refValue.Type())
|
||||
tmp.Elem().Set(refValue)
|
||||
return Bytes(tmp.Elem().Bytes()), true
|
||||
}
|
||||
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.Bool:
|
||||
boolTupe := reflect.TypeOf(false)
|
||||
return Bool(refValue.Convert(boolTupe).Interface().(bool)), true
|
||||
case reflect.Int:
|
||||
intType := reflect.TypeOf(int(0))
|
||||
return Int(refValue.Convert(intType).Interface().(int)), true
|
||||
case reflect.Int8:
|
||||
intType := reflect.TypeOf(int8(0))
|
||||
return Int(refValue.Convert(intType).Interface().(int8)), true
|
||||
case reflect.Int16:
|
||||
intType := reflect.TypeOf(int16(0))
|
||||
return Int(refValue.Convert(intType).Interface().(int16)), true
|
||||
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.Uint:
|
||||
uintType := reflect.TypeOf(uint(0))
|
||||
return Uint(refValue.Convert(uintType).Interface().(uint)), true
|
||||
case reflect.Uint8:
|
||||
uintType := reflect.TypeOf(uint8(0))
|
||||
return Uint(refValue.Convert(uintType).Interface().(uint8)), true
|
||||
case reflect.Uint16:
|
||||
uintType := reflect.TypeOf(uint16(0))
|
||||
return Uint(refValue.Convert(uintType).Interface().(uint16)), 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
|
||||
case reflect.String:
|
||||
stringType := reflect.TypeOf("")
|
||||
return String(refValue.Convert(stringType).Interface().(string)), 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)
|
||||
}
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
switch pv := v.(type) {
|
||||
case proto.Message:
|
||||
v = pv.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)
|
||||
}
|
||||
if elemVal == nil {
|
||||
continue
|
||||
}
|
||||
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)
|
||||
}
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
switch pv := v.(type) {
|
||||
case proto.Message:
|
||||
v = pv.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)
|
||||
}
|
||||
|
||||
var (
|
||||
// ProtoCELPrimitives provides a map from the protoreflect Kind to the equivalent CEL type.
|
||||
ProtoCELPrimitives = map[protoreflect.Kind]*Type{
|
||||
protoreflect.BoolKind: BoolType,
|
||||
protoreflect.BytesKind: BytesType,
|
||||
protoreflect.DoubleKind: DoubleType,
|
||||
protoreflect.FloatKind: DoubleType,
|
||||
protoreflect.Int32Kind: IntType,
|
||||
protoreflect.Int64Kind: IntType,
|
||||
protoreflect.Sint32Kind: IntType,
|
||||
protoreflect.Sint64Kind: IntType,
|
||||
protoreflect.Uint32Kind: UintType,
|
||||
protoreflect.Uint64Kind: UintType,
|
||||
protoreflect.Fixed32Kind: UintType,
|
||||
protoreflect.Fixed64Kind: UintType,
|
||||
protoreflect.Sfixed32Kind: IntType,
|
||||
protoreflect.Sfixed64Kind: IntType,
|
||||
protoreflect.StringKind: StringType,
|
||||
}
|
||||
)
|
20
e2e/vendor/github.com/google/cel-go/common/types/ref/BUILD.bazel
generated
vendored
Normal file
20
e2e/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",
|
||||
],
|
||||
)
|
102
e2e/vendor/github.com/google/cel-go/common/types/ref/provider.go
generated
vendored
Normal file
102
e2e/vendor/github.com/google/cel-go/common/types/ref/provider.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 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.
|
||||
//
|
||||
// Deprecated: use types.Provider
|
||||
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.
|
||||
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.
|
||||
FindFieldType(messageType, 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.
|
||||
//
|
||||
// Deprecated: use types.Adapter
|
||||
type TypeAdapter interface {
|
||||
// NativeToValue converts the input `value` to a CEL `ref.Val`.
|
||||
NativeToValue(value any) 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.
|
||||
//
|
||||
// Deprecated: use types.Registry
|
||||
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
|
||||
}
|
||||
|
||||
// FieldType represents a field's type value and whether that field supports
|
||||
// presence detection.
|
||||
//
|
||||
// Deprecated: use types.FieldType
|
||||
type FieldType struct {
|
||||
// Type of the field as a protobuf type value.
|
||||
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 any) bool
|
||||
|
||||
// FieldGetter is used to get the field value from an input object, if set.
|
||||
type FieldGetter func(target any) (any, error)
|
63
e2e/vendor/github.com/google/cel-go/common/types/ref/reference.go
generated
vendored
Normal file
63
e2e/vendor/github.com/google/cel-go/common/types/ref/reference.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
// 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.
|
||||
//
|
||||
// The ConvertToNative method is intended to be used to support conversion between CEL types
|
||||
// and native types during object creation expressions or by clients who need to adapt the,
|
||||
// returned CEL value into an equivalent Go value instance.
|
||||
//
|
||||
// When implementing or using ConvertToNative, the following guidelines apply:
|
||||
// - Use ConvertToNative when marshalling CEL evaluation results to native types.
|
||||
// - Do not use ConvertToNative within CEL extension functions.
|
||||
// - Document whether your implementation supports non-CEL field types, such as Go or Protobuf.
|
||||
ConvertToNative(typeDesc reflect.Type) (any, error)
|
||||
|
||||
// ConvertToType supports type conversions between CEL value types supported by the expression language.
|
||||
ConvertToType(typeValue Type) Val
|
||||
|
||||
// Equal returns true if the `other` value has the same type and content as the implementing struct.
|
||||
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() any
|
||||
}
|
226
e2e/vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
Normal file
226
e2e/vendor/github.com/google/cel-go/common/types/string.go
generated
vendored
Normal file
@ -0,0 +1,226 @@
|
||||
// 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"
|
||||
|
||||
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 (
|
||||
stringOneArgOverloads = map[string]func(ref.Val, 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) (any, error) {
|
||||
switch typeDesc.Kind() {
|
||||
case reflect.String:
|
||||
return reflect.ValueOf(s).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.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)
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the string is empty.
|
||||
func (s String) IsZeroValue() bool {
|
||||
return len(s) == 0
|
||||
}
|
||||
|
||||
// Match implements traits.Matcher.Match.
|
||||
func (s String) Match(pattern ref.Val) ref.Val {
|
||||
pat, ok := pattern.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(pattern)
|
||||
}
|
||||
matched, err := regexp.MatchString(pat.Value().(string), s.Value().(string))
|
||||
if err != nil {
|
||||
return &Err{error: 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() any {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// StringContains returns whether the string contains a substring.
|
||||
func StringContains(s, sub ref.Val) ref.Val {
|
||||
str, ok := s.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(s)
|
||||
}
|
||||
subStr, ok := sub.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(sub)
|
||||
}
|
||||
return Bool(strings.Contains(string(str), string(subStr)))
|
||||
}
|
||||
|
||||
// StringEndsWith returns whether the target string contains the input suffix.
|
||||
func StringEndsWith(s, suf ref.Val) ref.Val {
|
||||
str, ok := s.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(s)
|
||||
}
|
||||
sufStr, ok := suf.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(suf)
|
||||
}
|
||||
return Bool(strings.HasSuffix(string(str), string(sufStr)))
|
||||
}
|
||||
|
||||
// StringStartsWith returns whether the target string contains the input prefix.
|
||||
func StringStartsWith(s, pre ref.Val) ref.Val {
|
||||
str, ok := s.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(s)
|
||||
}
|
||||
preStr, ok := pre.(String)
|
||||
if !ok {
|
||||
return MaybeNoSuchOverloadErr(pre)
|
||||
}
|
||||
return Bool(strings.HasPrefix(string(str), string(preStr)))
|
||||
}
|
311
e2e/vendor/github.com/google/cel-go/common/types/timestamp.go
generated
vendored
Normal file
311
e2e/vendor/github.com/google/cel-go/common/types/timestamp.go
generated
vendored
Normal file
@ -0,0 +1,311 @@
|
||||
// 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"
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
// 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) (any, error) {
|
||||
// If the timestamp is already assignable to the desired type return it.
|
||||
if reflect.TypeOf(t.Time).AssignableTo(typeDesc) {
|
||||
return t.Time, nil
|
||||
}
|
||||
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))
|
||||
}
|
||||
|
||||
// IsZeroValue returns true if the timestamp is epoch 0.
|
||||
func (t Timestamp) IsZeroValue() bool {
|
||||
return t.IsZero()
|
||||
}
|
||||
|
||||
// Receive implements traits.Receiver.Receive.
|
||||
func (t Timestamp) Receive(function string, overload string, args []ref.Val) ref.Val {
|
||||
switch len(args) {
|
||||
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() any {
|
||||
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))
|
||||
}
|
||||
}
|
29
e2e/vendor/github.com/google/cel-go/common/types/traits/BUILD.bazel
generated
vendored
Normal file
29
e2e/vendor/github.com/google/cel-go/common/types/traits/BUILD.bazel
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
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",
|
||||
"zeroer.go",
|
||||
],
|
||||
importpath = "github.com/google/cel-go/common/types/traits",
|
||||
deps = [
|
||||
"//common/types/ref:go_default_library",
|
||||
],
|
||||
)
|
33
e2e/vendor/github.com/google/cel-go/common/types/traits/comparer.go
generated
vendored
Normal file
33
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/traits/container.go
generated
vendored
Normal file
23
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/traits/field_tester.go
generated
vendored
Normal file
30
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/traits/indexer.go
generated
vendored
Normal file
25
e2e/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
|
||||
}
|
49
e2e/vendor/github.com/google/cel-go/common/types/traits/iterator.go
generated
vendored
Normal file
49
e2e/vendor/github.com/google/cel-go/common/types/traits/iterator.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 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
|
||||
}
|
||||
|
||||
// Foldable aggregate types support iteration over (key, value) or (index, value) pairs.
|
||||
type Foldable interface {
|
||||
// Fold invokes the Folder.FoldEntry for all entries in the type
|
||||
Fold(Folder)
|
||||
}
|
||||
|
||||
// Folder performs a fold on a given entry and indicates whether to continue folding.
|
||||
type Folder interface {
|
||||
// FoldEntry indicates the key, value pair associated with the entry.
|
||||
// If the output is true, continue folding. Otherwise, terminate the fold.
|
||||
FoldEntry(key, val any) bool
|
||||
}
|
36
e2e/vendor/github.com/google/cel-go/common/types/traits/lister.go
generated
vendored
Normal file
36
e2e/vendor/github.com/google/cel-go/common/types/traits/lister.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"
|
||||
|
||||
// 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.
|
||||
//
|
||||
// Note, this interface is intended only to be used within Comprehensions where the mutable
|
||||
// value is not directly observable within the user-authored CEL expression.
|
||||
type MutableLister interface {
|
||||
Lister
|
||||
ToImmutableList() Lister
|
||||
}
|
48
e2e/vendor/github.com/google/cel-go/common/types/traits/mapper.go
generated
vendored
Normal file
48
e2e/vendor/github.com/google/cel-go/common/types/traits/mapper.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 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)
|
||||
}
|
||||
|
||||
// MutableMapper interface which emits an immutable result after an intermediate computation.
|
||||
//
|
||||
// Note, this interface is intended only to be used within Comprehensions where the mutable
|
||||
// value is not directly observable within the user-authored CEL expression.
|
||||
type MutableMapper interface {
|
||||
Mapper
|
||||
|
||||
// Insert a key, value pair into the map, returning the map if the insert is successful
|
||||
// and an error if key already exists in the mutable map.
|
||||
Insert(k, v ref.Val) ref.Val
|
||||
|
||||
// ToImmutableMap converts a mutable map into an immutable map.
|
||||
ToImmutableMap() Mapper
|
||||
}
|
23
e2e/vendor/github.com/google/cel-go/common/types/traits/matcher.go
generated
vendored
Normal file
23
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/traits/math.go
generated
vendored
Normal file
62
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/traits/receiver.go
generated
vendored
Normal file
24
e2e/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
e2e/vendor/github.com/google/cel-go/common/types/traits/sizer.go
generated
vendored
Normal file
25
e2e/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
|
||||
}
|
79
e2e/vendor/github.com/google/cel-go/common/types/traits/traits.go
generated
vendored
Normal file
79
e2e/vendor/github.com/google/cel-go/common/types/traits/traits.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// 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 types support '-' operations.
|
||||
SubtractorType
|
||||
|
||||
// FoldableType types support comprehensions v2 macros which iterate over (key, value) pairs.
|
||||
FoldableType
|
||||
)
|
||||
|
||||
const (
|
||||
// ListerType supports a set of traits necessary for list operations.
|
||||
//
|
||||
// The ListerType is syntactic sugar and not intended to be a perfect reflection of all List operators.
|
||||
ListerType = AdderType | ContainerType | IndexerType | IterableType | SizerType
|
||||
|
||||
// MapperType supports a set of traits necessary for map operations.
|
||||
//
|
||||
// The MapperType is syntactic sugar and not intended to be a perfect reflection of all Map operators.
|
||||
MapperType = ContainerType | IndexerType | IterableType | SizerType
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user