// 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` 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 arugments. 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. IterVar() string // 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(), 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 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) 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 )