304 lines
8.8 KiB
Go
304 lines
8.8 KiB
Go
// 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 comprehension over a value range.
|
|
NewComprehension(id int64, iterRange Expr, iterVar, 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 {
|
|
return fac.newExpr(
|
|
id,
|
|
&baseComprehensionExpr{
|
|
iterRange: iterRange,
|
|
iterVar: iterVar,
|
|
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.NewComprehension(e.ID(),
|
|
fac.CopyExpr(compre.IterRange()),
|
|
compre.IterVar(),
|
|
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{}
|
|
)
|