Bump cel-go to v0.10.0

This commit is contained in:
Joe Betz
2022-03-07 20:47:04 -05:00
parent f93be6584e
commit 2a6b85c395
66 changed files with 3332 additions and 817 deletions

View File

@@ -88,6 +88,18 @@ type InterpretableCall interface {
Args() []Interpretable
}
// InterpretableConstructor interface for inspecting Interpretable instructions that initialize a list, map
// or struct.
type InterpretableConstructor interface {
Interpretable
// InitVals returns all the list elements, map key and values or struct field values.
InitVals() []Interpretable
// Type returns the type constructed.
Type() ref.Type
}
// Core Interpretable implementations used during the program planning phase.
type evalTestOnly struct {
@@ -298,7 +310,13 @@ func (eq *evalEq) ID() int64 {
func (eq *evalEq) Eval(ctx Activation) ref.Val {
lVal := eq.lhs.Eval(ctx)
rVal := eq.rhs.Eval(ctx)
return lVal.Equal(rVal)
if types.IsUnknownOrError(lVal) {
return lVal
}
if types.IsUnknownOrError(rVal) {
return rVal
}
return types.Equal(lVal, rVal)
}
// Cost implements the Coster interface method.
@@ -336,12 +354,13 @@ func (ne *evalNe) ID() int64 {
func (ne *evalNe) Eval(ctx Activation) ref.Val {
lVal := ne.lhs.Eval(ctx)
rVal := ne.rhs.Eval(ctx)
eqVal := lVal.Equal(rVal)
eqBool, ok := eqVal.(types.Bool)
if !ok {
return types.ValOrErr(eqVal, "no such overload: _!=_")
if types.IsUnknownOrError(lVal) {
return lVal
}
return !eqBool
if types.IsUnknownOrError(rVal) {
return rVal
}
return types.Bool(types.Equal(lVal, rVal) != types.True)
}
// Cost implements the Coster interface method.
@@ -526,6 +545,17 @@ type evalVarArgs struct {
impl functions.FunctionOp
}
// NewCall creates a new call Interpretable.
func NewCall(id int64, function, overload string, args []Interpretable, impl functions.FunctionOp) InterpretableCall {
return &evalVarArgs{
id: id,
function: function,
overload: overload,
args: args,
impl: impl,
}
}
// ID implements the Interpretable interface method.
func (fn *evalVarArgs) ID() int64 {
return fn.id
@@ -603,6 +633,14 @@ func (l *evalList) Eval(ctx Activation) ref.Val {
return l.adapter.NativeToValue(elemVals)
}
func (l *evalList) InitVals() []Interpretable {
return l.elems
}
func (l *evalList) Type() ref.Type {
return types.ListType
}
// Cost implements the Coster interface method.
func (l *evalList) Cost() (min, max int64) {
return sumOfCost(l.elems)
@@ -638,6 +676,14 @@ func (m *evalMap) Eval(ctx Activation) ref.Val {
return m.adapter.NativeToValue(entries)
}
func (m *evalMap) InitVals() []Interpretable {
return append(m.keys, m.vals...)
}
func (m *evalMap) Type() ref.Type {
return types.MapType
}
// Cost implements the Coster interface method.
func (m *evalMap) Cost() (min, max int64) {
kMin, kMax := sumOfCost(m.keys)
@@ -672,6 +718,14 @@ func (o *evalObj) Eval(ctx Activation) ref.Val {
return o.provider.NewValue(o.typeName, fieldVals)
}
func (o *evalObj) InitVals() []Interpretable {
return o.vals
}
func (o *evalObj) Type() ref.Type {
return types.NewObjectTypeValue(o.typeName)
}
// Cost implements the Coster interface method.
func (o *evalObj) Cost() (min, max int64) {
return sumOfCost(o.vals)
@@ -688,14 +742,17 @@ func sumOfCost(interps []Interpretable) (min, max int64) {
}
type evalFold struct {
id int64
accuVar string
iterVar string
iterRange Interpretable
accu Interpretable
cond Interpretable
step Interpretable
result Interpretable
id int64
accuVar string
iterVar string
iterRange Interpretable
accu Interpretable
cond Interpretable
step Interpretable
result Interpretable
adapter ref.TypeAdapter
exhaustive bool
interruptable bool
}
// ID implements the Interpretable interface method.
@@ -714,9 +771,19 @@ func (fold *evalFold) Eval(ctx Activation) ref.Val {
accuCtx.parent = ctx
accuCtx.name = fold.accuVar
accuCtx.val = fold.accu.Eval(ctx)
// If the accumulator starts as an empty list, then the comprehension will build a list
// so create a mutable list to optimize the cost of the inner loop.
l, ok := accuCtx.val.(traits.Lister)
buildingList := false
if !fold.exhaustive && ok && l.Size() == types.IntZero {
buildingList = true
accuCtx.val = types.NewMutableList(fold.adapter)
}
iterCtx := varActivationPool.Get().(*varActivation)
iterCtx.parent = accuCtx
iterCtx.name = fold.iterVar
interrupted := false
it := foldRange.(traits.Iterable).Iterator()
for it.HasNext() == types.True {
// Modify the iter var in the fold activation.
@@ -725,17 +792,31 @@ func (fold *evalFold) Eval(ctx Activation) ref.Val {
// Evaluate the condition, terminate the loop if false.
cond := fold.cond.Eval(iterCtx)
condBool, ok := cond.(types.Bool)
if !types.IsUnknown(cond) && ok && condBool != types.True {
if !fold.exhaustive && ok && condBool != types.True {
break
}
// Evalute the evaluation step into accu var.
// Evaluate the evaluation step into accu var.
accuCtx.val = fold.step.Eval(iterCtx)
if fold.interruptable {
if stop, found := ctx.ResolveName("#interrupted"); found && stop == true {
interrupted = true
break
}
}
}
varActivationPool.Put(iterCtx)
if interrupted {
varActivationPool.Put(accuCtx)
return types.NewErr("operation interrupted")
}
// Compute the result.
res := fold.result.Eval(accuCtx)
varActivationPool.Put(iterCtx)
varActivationPool.Put(accuCtx)
// Convert a mutable list to an immutable one, if the comprehension has generated a list as a result.
if !types.IsUnknownOrError(res) && buildingList {
res = res.(traits.MutableLister).ToImmutableList()
}
return res
}
@@ -760,6 +841,10 @@ func (fold *evalFold) Cost() (min, max int64) {
cMin, cMax := estimateCost(fold.cond)
sMin, sMax := estimateCost(fold.step)
rMin, rMax := estimateCost(fold.result)
if fold.exhaustive {
cMin = cMin * rangeCnt
sMin = sMin * rangeCnt
}
// The cond and step costs are multiplied by size(iterRange). The minimum possible cost incurs
// when the evaluation result can be determined by the first iteration.
@@ -773,10 +858,9 @@ func (fold *evalFold) Cost() (min, max int64) {
// evalSetMembership is an Interpretable implementation which tests whether an input value
// exists within the set of map keys used to model a set.
type evalSetMembership struct {
inst Interpretable
arg Interpretable
argTypeName string
valueSet map[ref.Val]ref.Val
inst Interpretable
arg Interpretable
valueSet map[ref.Val]ref.Val
}
// ID implements the Interpretable interface method.
@@ -787,9 +871,6 @@ func (e *evalSetMembership) ID() int64 {
// Eval implements the Interpretable interface method.
func (e *evalSetMembership) Eval(ctx Activation) ref.Val {
val := e.arg.Eval(ctx)
if val.Type().TypeName() != e.argTypeName {
return types.ValOrErr(val, "no such overload")
}
if ret, found := e.valueSet[val]; found {
return ret
}
@@ -805,13 +886,13 @@ func (e *evalSetMembership) Cost() (min, max int64) {
// expression so that it may observe the computed value and send it to an observer.
type evalWatch struct {
Interpretable
observer evalObserver
observer EvalObserver
}
// Eval implements the Interpretable interface method.
func (e *evalWatch) Eval(ctx Activation) ref.Val {
val := e.Interpretable.Eval(ctx)
e.observer(e.ID(), val)
e.observer(e.ID(), e.Interpretable, val)
return val
}
@@ -826,7 +907,7 @@ func (e *evalWatch) Cost() (min, max int64) {
// must implement the instAttr interface by proxy.
type evalWatchAttr struct {
InterpretableAttribute
observer evalObserver
observer EvalObserver
}
// AddQualifier creates a wrapper over the incoming qualifier which observes the qualification
@@ -850,11 +931,23 @@ func (e *evalWatchAttr) AddQualifier(q Qualifier) (Attribute, error) {
return e, err
}
// Cost implements the Coster interface method.
func (e *evalWatchAttr) Cost() (min, max int64) {
return estimateCost(e.InterpretableAttribute)
}
// Eval implements the Interpretable interface method.
func (e *evalWatchAttr) Eval(vars Activation) ref.Val {
val := e.InterpretableAttribute.Eval(vars)
e.observer(e.ID(), e.InterpretableAttribute, val)
return val
}
// evalWatchConstQual observes the qualification of an object using a constant boolean, int,
// string, or uint.
type evalWatchConstQual struct {
ConstantQualifier
observer evalObserver
observer EvalObserver
adapter ref.TypeAdapter
}
@@ -872,7 +965,7 @@ func (e *evalWatchConstQual) Qualify(vars Activation, obj interface{}) (interfac
} else {
val = e.adapter.NativeToValue(out)
}
e.observer(e.ID(), val)
e.observer(e.ID(), e.ConstantQualifier, val)
return out, err
}
@@ -885,7 +978,7 @@ func (e *evalWatchConstQual) QualifierValueEquals(value interface{}) bool {
// evalWatchQual observes the qualification of an object by a value computed at runtime.
type evalWatchQual struct {
Qualifier
observer evalObserver
observer EvalObserver
adapter ref.TypeAdapter
}
@@ -903,32 +996,20 @@ func (e *evalWatchQual) Qualify(vars Activation, obj interface{}) (interface{},
} else {
val = e.adapter.NativeToValue(out)
}
e.observer(e.ID(), val)
e.observer(e.ID(), e.Qualifier, val)
return out, err
}
// Cost implements the Coster interface method.
func (e *evalWatchAttr) Cost() (min, max int64) {
return estimateCost(e.InterpretableAttribute)
}
// Eval implements the Interpretable interface method.
func (e *evalWatchAttr) Eval(vars Activation) ref.Val {
val := e.InterpretableAttribute.Eval(vars)
e.observer(e.ID(), val)
return val
}
// evalWatchConst describes a watcher of an instConst Interpretable.
type evalWatchConst struct {
InterpretableConst
observer evalObserver
observer EvalObserver
}
// Eval implements the Interpretable interface method.
func (e *evalWatchConst) Eval(vars Activation) ref.Val {
val := e.Value()
e.observer(e.ID(), val)
e.observer(e.ID(), e.InterpretableConst, val)
return val
}
@@ -1074,83 +1155,6 @@ func (cond *evalExhaustiveConditional) Cost() (min, max int64) {
return cond.attr.Cost()
}
// evalExhaustiveFold is like evalFold, but does not short-circuit argument evaluation.
type evalExhaustiveFold struct {
id int64
accuVar string
iterVar string
iterRange Interpretable
accu Interpretable
cond Interpretable
step Interpretable
result Interpretable
}
// ID implements the Interpretable interface method.
func (fold *evalExhaustiveFold) ID() int64 {
return fold.id
}
// Eval implements the Interpretable interface method.
func (fold *evalExhaustiveFold) Eval(ctx Activation) ref.Val {
foldRange := fold.iterRange.Eval(ctx)
if !foldRange.Type().HasTrait(traits.IterableType) {
return types.ValOrErr(foldRange, "got '%T', expected iterable type", foldRange)
}
// Configure the fold activation with the accumulator initial value.
accuCtx := varActivationPool.Get().(*varActivation)
accuCtx.parent = ctx
accuCtx.name = fold.accuVar
accuCtx.val = fold.accu.Eval(ctx)
iterCtx := varActivationPool.Get().(*varActivation)
iterCtx.parent = accuCtx
iterCtx.name = fold.iterVar
it := foldRange.(traits.Iterable).Iterator()
for it.HasNext() == types.True {
// Modify the iter var in the fold activation.
iterCtx.val = it.Next()
// Evaluate the condition, but don't terminate the loop as this is exhaustive eval!
fold.cond.Eval(iterCtx)
// Evalute the evaluation step into accu var.
accuCtx.val = fold.step.Eval(iterCtx)
}
// Compute the result.
res := fold.result.Eval(accuCtx)
varActivationPool.Put(iterCtx)
varActivationPool.Put(accuCtx)
return res
}
// Cost implements the Coster interface method.
func (fold *evalExhaustiveFold) Cost() (min, max int64) {
// Compute the cost for evaluating iterRange.
iMin, iMax := estimateCost(fold.iterRange)
// Compute the size of iterRange. If the size depends on the input, return the maximum possible
// cost range.
foldRange := fold.iterRange.Eval(EmptyActivation())
if !foldRange.Type().HasTrait(traits.IterableType) {
return 0, math.MaxInt64
}
var rangeCnt int64
it := foldRange.(traits.Iterable).Iterator()
for it.HasNext() == types.True {
it.Next()
rangeCnt++
}
aMin, aMax := estimateCost(fold.accu)
cMin, cMax := estimateCost(fold.cond)
sMin, sMax := estimateCost(fold.step)
rMin, rMax := estimateCost(fold.result)
// The cond and step costs are multiplied by size(iterRange).
return iMin + aMin + cMin*rangeCnt + sMin*rangeCnt + rMin,
iMax + aMax + cMax*rangeCnt + sMax*rangeCnt + rMax
}
// evalAttr evaluates an Attribute value.
type evalAttr struct {
adapter ref.TypeAdapter