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:
Niels de Vos
2025-03-04 08:57:28 +01:00
committed by mergify[bot]
parent 15da101b1b
commit bec6090996
8047 changed files with 1407827 additions and 3453 deletions

View 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
View 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()
}
}

View 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
View 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
)

View 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{}
)

View 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()),
}
}