Bump cel-go to v0.16.0
This commit is contained in:
473
vendor/github.com/google/cel-go/interpreter/interpretable.go
generated
vendored
473
vendor/github.com/google/cel-go/interpreter/interpretable.go
generated
vendored
@@ -15,7 +15,7 @@
|
||||
package interpreter
|
||||
|
||||
import (
|
||||
"math"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/cel-go/common/operators"
|
||||
"github.com/google/cel-go/common/overloads"
|
||||
@@ -64,10 +64,18 @@ type InterpretableAttribute interface {
|
||||
|
||||
// Qualify replicates the Attribute.Qualify method to permit extension and interception
|
||||
// of object qualification.
|
||||
Qualify(vars Activation, obj interface{}) (interface{}, error)
|
||||
Qualify(vars Activation, obj any) (any, error)
|
||||
|
||||
// QualifyIfPresent qualifies the object if the qualifier is declared or defined on the object.
|
||||
// The 'presenceOnly' flag indicates that the value is not necessary, just a boolean status as
|
||||
// to whether the qualifier is present.
|
||||
QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error)
|
||||
|
||||
// IsOptional indicates whether the resulting value is an optional type.
|
||||
IsOptional() bool
|
||||
|
||||
// Resolve returns the value of the Attribute given the current Activation.
|
||||
Resolve(Activation) (interface{}, error)
|
||||
Resolve(Activation) (any, error)
|
||||
}
|
||||
|
||||
// InterpretableCall interface for inspecting Interpretable instructions related to function calls.
|
||||
@@ -103,10 +111,8 @@ type InterpretableConstructor interface {
|
||||
// Core Interpretable implementations used during the program planning phase.
|
||||
|
||||
type evalTestOnly struct {
|
||||
id int64
|
||||
op Interpretable
|
||||
field types.String
|
||||
fieldType *ref.FieldType
|
||||
id int64
|
||||
InterpretableAttribute
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
@@ -116,44 +122,55 @@ func (test *evalTestOnly) ID() int64 {
|
||||
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (test *evalTestOnly) Eval(ctx Activation) ref.Val {
|
||||
// Handle field selection on a proto in the most efficient way possible.
|
||||
if test.fieldType != nil {
|
||||
opAttr, ok := test.op.(InterpretableAttribute)
|
||||
if ok {
|
||||
opVal, err := opAttr.Resolve(ctx)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
refVal, ok := opVal.(ref.Val)
|
||||
if ok {
|
||||
opVal = refVal.Value()
|
||||
}
|
||||
if test.fieldType.IsSet(opVal) {
|
||||
return types.True
|
||||
}
|
||||
return types.False
|
||||
}
|
||||
val, err := test.Resolve(ctx)
|
||||
// Return an error if the resolve step fails
|
||||
if err != nil {
|
||||
return types.WrapErr(err)
|
||||
}
|
||||
|
||||
obj := test.op.Eval(ctx)
|
||||
tester, ok := obj.(traits.FieldTester)
|
||||
if ok {
|
||||
return tester.IsSet(test.field)
|
||||
if optVal, isOpt := val.(*types.Optional); isOpt {
|
||||
return types.Bool(optVal.HasValue())
|
||||
}
|
||||
container, ok := obj.(traits.Container)
|
||||
if ok {
|
||||
return container.Contains(test.field)
|
||||
}
|
||||
return types.ValOrErr(obj, "invalid type for field selection.")
|
||||
return test.Adapter().NativeToValue(val)
|
||||
}
|
||||
|
||||
// Cost provides the heuristic cost of a `has(field)` macro. The cost has at least 1 for determining
|
||||
// if the field exists, apart from the cost of accessing the field.
|
||||
func (test *evalTestOnly) Cost() (min, max int64) {
|
||||
min, max = estimateCost(test.op)
|
||||
min++
|
||||
max++
|
||||
return
|
||||
// AddQualifier appends a qualifier that will always and only perform a presence test.
|
||||
func (test *evalTestOnly) AddQualifier(q Qualifier) (Attribute, error) {
|
||||
cq, ok := q.(ConstantQualifier)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("test only expressions must have constant qualifiers: %v", q)
|
||||
}
|
||||
return test.InterpretableAttribute.AddQualifier(&testOnlyQualifier{ConstantQualifier: cq})
|
||||
}
|
||||
|
||||
type testOnlyQualifier struct {
|
||||
ConstantQualifier
|
||||
}
|
||||
|
||||
// Qualify determines whether the test-only qualifier is present on the input object.
|
||||
func (q *testOnlyQualifier) Qualify(vars Activation, obj any) (any, error) {
|
||||
out, present, err := q.ConstantQualifier.QualifyIfPresent(vars, obj, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if unk, isUnk := out.(types.Unknown); isUnk {
|
||||
return unk, nil
|
||||
}
|
||||
if opt, isOpt := out.(types.Optional); isOpt {
|
||||
return opt.HasValue(), nil
|
||||
}
|
||||
return present, nil
|
||||
}
|
||||
|
||||
// QualifyIfPresent returns whether the target field in the test-only expression is present.
|
||||
func (q *testOnlyQualifier) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
|
||||
// Only ever test for presence.
|
||||
return q.ConstantQualifier.QualifyIfPresent(vars, obj, true)
|
||||
}
|
||||
|
||||
// QualifierValueEquals determines whether the test-only constant qualifier equals the input value.
|
||||
func (q *testOnlyQualifier) QualifierValueEquals(value any) bool {
|
||||
// The input qualifier will always be of type string
|
||||
return q.ConstantQualifier.Value().Value() == value
|
||||
}
|
||||
|
||||
// NewConstValue creates a new constant valued Interpretable.
|
||||
@@ -179,11 +196,6 @@ func (cons *evalConst) Eval(ctx Activation) ref.Val {
|
||||
return cons.val
|
||||
}
|
||||
|
||||
// Cost returns zero for a constant valued Interpretable.
|
||||
func (cons *evalConst) Cost() (min, max int64) {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Value implements the InterpretableConst interface method.
|
||||
func (cons *evalConst) Value() ref.Val {
|
||||
return cons.val
|
||||
@@ -233,12 +245,6 @@ func (or *evalOr) Eval(ctx Activation) ref.Val {
|
||||
return types.ValOrErr(rVal, "no such overload")
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method. The minimum possible cost incurs when the left-hand
|
||||
// side expr is sufficient in determining the evaluation result.
|
||||
func (or *evalOr) Cost() (min, max int64) {
|
||||
return calShortCircuitBinaryOpsCost(or.lhs, or.rhs)
|
||||
}
|
||||
|
||||
type evalAnd struct {
|
||||
id int64
|
||||
lhs Interpretable
|
||||
@@ -283,18 +289,6 @@ func (and *evalAnd) Eval(ctx Activation) ref.Val {
|
||||
return types.ValOrErr(rVal, "no such overload")
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method. The minimum possible cost incurs when the left-hand
|
||||
// side expr is sufficient in determining the evaluation result.
|
||||
func (and *evalAnd) Cost() (min, max int64) {
|
||||
return calShortCircuitBinaryOpsCost(and.lhs, and.rhs)
|
||||
}
|
||||
|
||||
func calShortCircuitBinaryOpsCost(lhs, rhs Interpretable) (min, max int64) {
|
||||
lMin, lMax := estimateCost(lhs)
|
||||
_, rMax := estimateCost(rhs)
|
||||
return lMin, lMax + rMax + 1
|
||||
}
|
||||
|
||||
type evalEq struct {
|
||||
id int64
|
||||
lhs Interpretable
|
||||
@@ -319,11 +313,6 @@ func (eq *evalEq) Eval(ctx Activation) ref.Val {
|
||||
return types.Equal(lVal, rVal)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (eq *evalEq) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(eq.lhs, eq.rhs)
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (*evalEq) Function() string {
|
||||
return operators.Equals
|
||||
@@ -363,11 +352,6 @@ func (ne *evalNe) Eval(ctx Activation) ref.Val {
|
||||
return types.Bool(types.Equal(lVal, rVal) != types.True)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (ne *evalNe) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(ne.lhs, ne.rhs)
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (*evalNe) Function() string {
|
||||
return operators.NotEquals
|
||||
@@ -400,11 +384,6 @@ func (zero *evalZeroArity) Eval(ctx Activation) ref.Val {
|
||||
return zero.impl()
|
||||
}
|
||||
|
||||
// Cost returns 1 representing the heuristic cost of the function.
|
||||
func (zero *evalZeroArity) Cost() (min, max int64) {
|
||||
return 1, 1
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (zero *evalZeroArity) Function() string {
|
||||
return zero.function
|
||||
@@ -456,14 +435,6 @@ func (un *evalUnary) Eval(ctx Activation) ref.Val {
|
||||
return types.NewErr("no such overload: %s", un.function)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (un *evalUnary) Cost() (min, max int64) {
|
||||
min, max = estimateCost(un.arg)
|
||||
min++ // add cost for function
|
||||
max++
|
||||
return
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (un *evalUnary) Function() string {
|
||||
return un.function
|
||||
@@ -522,11 +493,6 @@ func (bin *evalBinary) Eval(ctx Activation) ref.Val {
|
||||
return types.NewErr("no such overload: %s", bin.function)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (bin *evalBinary) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(bin.lhs, bin.rhs)
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (bin *evalBinary) Function() string {
|
||||
return bin.function
|
||||
@@ -593,14 +559,6 @@ func (fn *evalVarArgs) Eval(ctx Activation) ref.Val {
|
||||
return types.NewErr("no such overload: %s", fn.function)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (fn *evalVarArgs) Cost() (min, max int64) {
|
||||
min, max = sumOfCost(fn.args)
|
||||
min++ // add cost for function
|
||||
max++
|
||||
return
|
||||
}
|
||||
|
||||
// Function implements the InterpretableCall interface method.
|
||||
func (fn *evalVarArgs) Function() string {
|
||||
return fn.function
|
||||
@@ -617,9 +575,11 @@ func (fn *evalVarArgs) Args() []Interpretable {
|
||||
}
|
||||
|
||||
type evalList struct {
|
||||
id int64
|
||||
elems []Interpretable
|
||||
adapter ref.TypeAdapter
|
||||
id int64
|
||||
elems []Interpretable
|
||||
optionals []bool
|
||||
hasOptionals bool
|
||||
adapter ref.TypeAdapter
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
@@ -629,14 +589,24 @@ func (l *evalList) ID() int64 {
|
||||
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (l *evalList) Eval(ctx Activation) ref.Val {
|
||||
elemVals := make([]ref.Val, len(l.elems))
|
||||
elemVals := make([]ref.Val, 0, len(l.elems))
|
||||
// If any argument is unknown or error early terminate.
|
||||
for i, elem := range l.elems {
|
||||
elemVal := elem.Eval(ctx)
|
||||
if types.IsUnknownOrError(elemVal) {
|
||||
return elemVal
|
||||
}
|
||||
elemVals[i] = elemVal
|
||||
if l.hasOptionals && l.optionals[i] {
|
||||
optVal, ok := elemVal.(*types.Optional)
|
||||
if !ok {
|
||||
return invalidOptionalElementInit(elemVal)
|
||||
}
|
||||
if !optVal.HasValue() {
|
||||
continue
|
||||
}
|
||||
elemVal = optVal.GetValue()
|
||||
}
|
||||
elemVals = append(elemVals, elemVal)
|
||||
}
|
||||
return l.adapter.NativeToValue(elemVals)
|
||||
}
|
||||
@@ -649,16 +619,13 @@ 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)
|
||||
}
|
||||
|
||||
type evalMap struct {
|
||||
id int64
|
||||
keys []Interpretable
|
||||
vals []Interpretable
|
||||
adapter ref.TypeAdapter
|
||||
id int64
|
||||
keys []Interpretable
|
||||
vals []Interpretable
|
||||
optionals []bool
|
||||
hasOptionals bool
|
||||
adapter ref.TypeAdapter
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
@@ -679,6 +646,17 @@ func (m *evalMap) Eval(ctx Activation) ref.Val {
|
||||
if types.IsUnknownOrError(valVal) {
|
||||
return valVal
|
||||
}
|
||||
if m.hasOptionals && m.optionals[i] {
|
||||
optVal, ok := valVal.(*types.Optional)
|
||||
if !ok {
|
||||
return invalidOptionalEntryInit(keyVal, valVal)
|
||||
}
|
||||
if !optVal.HasValue() {
|
||||
delete(entries, keyVal)
|
||||
continue
|
||||
}
|
||||
valVal = optVal.GetValue()
|
||||
}
|
||||
entries[keyVal] = valVal
|
||||
}
|
||||
return m.adapter.NativeToValue(entries)
|
||||
@@ -704,19 +682,14 @@ 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)
|
||||
vMin, vMax := sumOfCost(m.vals)
|
||||
return kMin + vMin, kMax + vMax
|
||||
}
|
||||
|
||||
type evalObj struct {
|
||||
id int64
|
||||
typeName string
|
||||
fields []string
|
||||
vals []Interpretable
|
||||
provider ref.TypeProvider
|
||||
id int64
|
||||
typeName string
|
||||
fields []string
|
||||
vals []Interpretable
|
||||
optionals []bool
|
||||
hasOptionals bool
|
||||
provider ref.TypeProvider
|
||||
}
|
||||
|
||||
// ID implements the Interpretable interface method.
|
||||
@@ -733,6 +706,17 @@ func (o *evalObj) Eval(ctx Activation) ref.Val {
|
||||
if types.IsUnknownOrError(val) {
|
||||
return val
|
||||
}
|
||||
if o.hasOptionals && o.optionals[i] {
|
||||
optVal, ok := val.(*types.Optional)
|
||||
if !ok {
|
||||
return invalidOptionalEntryInit(field, val)
|
||||
}
|
||||
if !optVal.HasValue() {
|
||||
delete(fieldVals, field)
|
||||
continue
|
||||
}
|
||||
val = optVal.GetValue()
|
||||
}
|
||||
fieldVals[field] = val
|
||||
}
|
||||
return o.provider.NewValue(o.typeName, fieldVals)
|
||||
@@ -746,21 +730,6 @@ 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)
|
||||
}
|
||||
|
||||
func sumOfCost(interps []Interpretable) (min, max int64) {
|
||||
min, max = 0, 0
|
||||
for _, in := range interps {
|
||||
minT, maxT := estimateCost(in)
|
||||
min += minT
|
||||
max += maxT
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type evalFold struct {
|
||||
id int64
|
||||
accuVar string
|
||||
@@ -842,38 +811,6 @@ func (fold *evalFold) Eval(ctx Activation) ref.Val {
|
||||
return res
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (fold *evalFold) 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)
|
||||
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.
|
||||
return iMin + aMin + cMin + sMin + rMin,
|
||||
iMax + aMax + cMax*rangeCnt + sMax*rangeCnt + rMax
|
||||
}
|
||||
|
||||
// Optional Interpretable implementations that specialize, subsume, or extend the core evaluation
|
||||
// plan via decorators.
|
||||
|
||||
@@ -893,17 +830,15 @@ 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 types.IsUnknownOrError(val) {
|
||||
return val
|
||||
}
|
||||
if ret, found := e.valueSet[val]; found {
|
||||
return ret
|
||||
}
|
||||
return types.False
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalSetMembership) Cost() (min, max int64) {
|
||||
return estimateCost(e.arg)
|
||||
}
|
||||
|
||||
// evalWatch is an Interpretable implementation that wraps the execution of a given
|
||||
// expression so that it may observe the computed value and send it to an observer.
|
||||
type evalWatch struct {
|
||||
@@ -918,15 +853,10 @@ func (e *evalWatch) Eval(ctx Activation) ref.Val {
|
||||
return val
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalWatch) Cost() (min, max int64) {
|
||||
return estimateCost(e.Interpretable)
|
||||
}
|
||||
|
||||
// evalWatchAttr describes a watcher of an instAttr Interpretable.
|
||||
// evalWatchAttr describes a watcher of an InterpretableAttribute Interpretable.
|
||||
//
|
||||
// Since the watcher may be selected against at a later stage in program planning, the watcher
|
||||
// must implement the instAttr interface by proxy.
|
||||
// must implement the InterpretableAttribute interface by proxy.
|
||||
type evalWatchAttr struct {
|
||||
InterpretableAttribute
|
||||
observer EvalObserver
|
||||
@@ -953,11 +883,6 @@ 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)
|
||||
@@ -973,17 +898,12 @@ type evalWatchConstQual struct {
|
||||
adapter ref.TypeAdapter
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalWatchConstQual) Cost() (min, max int64) {
|
||||
return estimateCost(e.ConstantQualifier)
|
||||
}
|
||||
|
||||
// Qualify observes the qualification of a object via a constant boolean, int, string, or uint.
|
||||
func (e *evalWatchConstQual) Qualify(vars Activation, obj interface{}) (interface{}, error) {
|
||||
func (e *evalWatchConstQual) Qualify(vars Activation, obj any) (any, error) {
|
||||
out, err := e.ConstantQualifier.Qualify(vars, obj)
|
||||
var val ref.Val
|
||||
if err != nil {
|
||||
val = types.NewErr(err.Error())
|
||||
val = types.WrapErr(err)
|
||||
} else {
|
||||
val = e.adapter.NativeToValue(out)
|
||||
}
|
||||
@@ -991,8 +911,25 @@ func (e *evalWatchConstQual) Qualify(vars Activation, obj interface{}) (interfac
|
||||
return out, err
|
||||
}
|
||||
|
||||
// QualifyIfPresent conditionally qualifies the variable and only records a value if one is present.
|
||||
func (e *evalWatchConstQual) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
|
||||
out, present, err := e.ConstantQualifier.QualifyIfPresent(vars, obj, presenceOnly)
|
||||
var val ref.Val
|
||||
if err != nil {
|
||||
val = types.WrapErr(err)
|
||||
} else if out != nil {
|
||||
val = e.adapter.NativeToValue(out)
|
||||
} else if presenceOnly {
|
||||
val = types.Bool(present)
|
||||
}
|
||||
if present || presenceOnly {
|
||||
e.observer(e.ID(), e.ConstantQualifier, val)
|
||||
}
|
||||
return out, present, err
|
||||
}
|
||||
|
||||
// QualifierValueEquals tests whether the incoming value is equal to the qualifying constant.
|
||||
func (e *evalWatchConstQual) QualifierValueEquals(value interface{}) bool {
|
||||
func (e *evalWatchConstQual) QualifierValueEquals(value any) bool {
|
||||
qve, ok := e.ConstantQualifier.(qualifierValueEquator)
|
||||
return ok && qve.QualifierValueEquals(value)
|
||||
}
|
||||
@@ -1004,17 +941,12 @@ type evalWatchQual struct {
|
||||
adapter ref.TypeAdapter
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalWatchQual) Cost() (min, max int64) {
|
||||
return estimateCost(e.Qualifier)
|
||||
}
|
||||
|
||||
// Qualify observes the qualification of a object via a value computed at runtime.
|
||||
func (e *evalWatchQual) Qualify(vars Activation, obj interface{}) (interface{}, error) {
|
||||
func (e *evalWatchQual) Qualify(vars Activation, obj any) (any, error) {
|
||||
out, err := e.Qualifier.Qualify(vars, obj)
|
||||
var val ref.Val
|
||||
if err != nil {
|
||||
val = types.NewErr(err.Error())
|
||||
val = types.WrapErr(err)
|
||||
} else {
|
||||
val = e.adapter.NativeToValue(out)
|
||||
}
|
||||
@@ -1022,6 +954,23 @@ func (e *evalWatchQual) Qualify(vars Activation, obj interface{}) (interface{},
|
||||
return out, err
|
||||
}
|
||||
|
||||
// QualifyIfPresent conditionally qualifies the variable and only records a value if one is present.
|
||||
func (e *evalWatchQual) QualifyIfPresent(vars Activation, obj any, presenceOnly bool) (any, bool, error) {
|
||||
out, present, err := e.Qualifier.QualifyIfPresent(vars, obj, presenceOnly)
|
||||
var val ref.Val
|
||||
if err != nil {
|
||||
val = types.WrapErr(err)
|
||||
} else if out != nil {
|
||||
val = e.adapter.NativeToValue(out)
|
||||
} else if presenceOnly {
|
||||
val = types.Bool(present)
|
||||
}
|
||||
if present || presenceOnly {
|
||||
e.observer(e.ID(), e.Qualifier, val)
|
||||
}
|
||||
return out, present, err
|
||||
}
|
||||
|
||||
// evalWatchConst describes a watcher of an instConst Interpretable.
|
||||
type evalWatchConst struct {
|
||||
InterpretableConst
|
||||
@@ -1035,11 +984,6 @@ func (e *evalWatchConst) Eval(vars Activation) ref.Val {
|
||||
return val
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (e *evalWatchConst) Cost() (min, max int64) {
|
||||
return estimateCost(e.InterpretableConst)
|
||||
}
|
||||
|
||||
// evalExhaustiveOr is just like evalOr, but does not short-circuit argument evaluation.
|
||||
type evalExhaustiveOr struct {
|
||||
id int64
|
||||
@@ -1078,12 +1022,7 @@ func (or *evalExhaustiveOr) Eval(ctx Activation) ref.Val {
|
||||
if types.IsError(lVal) {
|
||||
return lVal
|
||||
}
|
||||
return types.ValOrErr(rVal, "no such overload")
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (or *evalExhaustiveOr) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(or.lhs, or.rhs)
|
||||
return types.MaybeNoSuchOverloadErr(rVal)
|
||||
}
|
||||
|
||||
// evalExhaustiveAnd is just like evalAnd, but does not short-circuit argument evaluation.
|
||||
@@ -1124,18 +1063,7 @@ func (and *evalExhaustiveAnd) Eval(ctx Activation) ref.Val {
|
||||
if types.IsError(lVal) {
|
||||
return lVal
|
||||
}
|
||||
return types.ValOrErr(rVal, "no such overload")
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (and *evalExhaustiveAnd) Cost() (min, max int64) {
|
||||
return calExhaustiveBinaryOpsCost(and.lhs, and.rhs)
|
||||
}
|
||||
|
||||
func calExhaustiveBinaryOpsCost(lhs, rhs Interpretable) (min, max int64) {
|
||||
lMin, lMax := estimateCost(lhs)
|
||||
rMin, rMax := estimateCost(rhs)
|
||||
return lMin + rMin + 1, lMax + rMax + 1
|
||||
return types.MaybeNoSuchOverloadErr(rVal)
|
||||
}
|
||||
|
||||
// evalExhaustiveConditional is like evalConditional, but does not short-circuit argument
|
||||
@@ -1154,77 +1082,114 @@ func (cond *evalExhaustiveConditional) ID() int64 {
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (cond *evalExhaustiveConditional) Eval(ctx Activation) ref.Val {
|
||||
cVal := cond.attr.expr.Eval(ctx)
|
||||
tVal, err := cond.attr.truthy.Resolve(ctx)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
fVal, err := cond.attr.falsy.Resolve(ctx)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
}
|
||||
tVal, tErr := cond.attr.truthy.Resolve(ctx)
|
||||
fVal, fErr := cond.attr.falsy.Resolve(ctx)
|
||||
cBool, ok := cVal.(types.Bool)
|
||||
if !ok {
|
||||
return types.ValOrErr(cVal, "no such overload")
|
||||
}
|
||||
if cBool {
|
||||
if tErr != nil {
|
||||
return types.WrapErr(tErr)
|
||||
}
|
||||
return cond.adapter.NativeToValue(tVal)
|
||||
}
|
||||
if fErr != nil {
|
||||
return types.WrapErr(fErr)
|
||||
}
|
||||
return cond.adapter.NativeToValue(fVal)
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (cond *evalExhaustiveConditional) Cost() (min, max int64) {
|
||||
return cond.attr.Cost()
|
||||
}
|
||||
|
||||
// evalAttr evaluates an Attribute value.
|
||||
type evalAttr struct {
|
||||
adapter ref.TypeAdapter
|
||||
attr Attribute
|
||||
adapter ref.TypeAdapter
|
||||
attr Attribute
|
||||
optional bool
|
||||
}
|
||||
|
||||
var _ InterpretableAttribute = &evalAttr{}
|
||||
|
||||
// ID of the attribute instruction.
|
||||
func (a *evalAttr) ID() int64 {
|
||||
return a.attr.ID()
|
||||
}
|
||||
|
||||
// AddQualifier implements the instAttr interface method.
|
||||
// AddQualifier implements the InterpretableAttribute interface method.
|
||||
func (a *evalAttr) AddQualifier(qual Qualifier) (Attribute, error) {
|
||||
attr, err := a.attr.AddQualifier(qual)
|
||||
a.attr = attr
|
||||
return attr, err
|
||||
}
|
||||
|
||||
// Attr implements the instAttr interface method.
|
||||
// Attr implements the InterpretableAttribute interface method.
|
||||
func (a *evalAttr) Attr() Attribute {
|
||||
return a.attr
|
||||
}
|
||||
|
||||
// Adapter implements the instAttr interface method.
|
||||
// Adapter implements the InterpretableAttribute interface method.
|
||||
func (a *evalAttr) Adapter() ref.TypeAdapter {
|
||||
return a.adapter
|
||||
}
|
||||
|
||||
// Cost implements the Coster interface method.
|
||||
func (a *evalAttr) Cost() (min, max int64) {
|
||||
return estimateCost(a.attr)
|
||||
}
|
||||
|
||||
// Eval implements the Interpretable interface method.
|
||||
func (a *evalAttr) Eval(ctx Activation) ref.Val {
|
||||
v, err := a.attr.Resolve(ctx)
|
||||
if err != nil {
|
||||
return types.NewErr(err.Error())
|
||||
return types.WrapErr(err)
|
||||
}
|
||||
return a.adapter.NativeToValue(v)
|
||||
}
|
||||
|
||||
// Qualify proxies to the Attribute's Qualify method.
|
||||
func (a *evalAttr) Qualify(ctx Activation, obj interface{}) (interface{}, error) {
|
||||
func (a *evalAttr) Qualify(ctx Activation, obj any) (any, error) {
|
||||
return a.attr.Qualify(ctx, obj)
|
||||
}
|
||||
|
||||
// QualifyIfPresent proxies to the Attribute's QualifyIfPresent method.
|
||||
func (a *evalAttr) QualifyIfPresent(ctx Activation, obj any, presenceOnly bool) (any, bool, error) {
|
||||
return a.attr.QualifyIfPresent(ctx, obj, presenceOnly)
|
||||
}
|
||||
|
||||
func (a *evalAttr) IsOptional() bool {
|
||||
return a.optional
|
||||
}
|
||||
|
||||
// Resolve proxies to the Attribute's Resolve method.
|
||||
func (a *evalAttr) Resolve(ctx Activation) (interface{}, error) {
|
||||
func (a *evalAttr) Resolve(ctx Activation) (any, error) {
|
||||
return a.attr.Resolve(ctx)
|
||||
}
|
||||
|
||||
type evalWatchConstructor struct {
|
||||
constructor InterpretableConstructor
|
||||
observer EvalObserver
|
||||
}
|
||||
|
||||
// InitVals implements the InterpretableConstructor InitVals function.
|
||||
func (c *evalWatchConstructor) InitVals() []Interpretable {
|
||||
return c.constructor.InitVals()
|
||||
}
|
||||
|
||||
// Type implements the InterpretableConstructor Type function.
|
||||
func (c *evalWatchConstructor) Type() ref.Type {
|
||||
return c.constructor.Type()
|
||||
}
|
||||
|
||||
// ID implements the Interpretable ID function.
|
||||
func (c *evalWatchConstructor) ID() int64 {
|
||||
return c.constructor.ID()
|
||||
}
|
||||
|
||||
// Eval implements the Interpretable Eval function.
|
||||
func (c *evalWatchConstructor) Eval(ctx Activation) ref.Val {
|
||||
val := c.constructor.Eval(ctx)
|
||||
c.observer(c.ID(), c.constructor, val)
|
||||
return val
|
||||
}
|
||||
|
||||
func invalidOptionalEntryInit(field any, value ref.Val) ref.Val {
|
||||
return types.NewErr("cannot initialize optional entry '%v' from non-optional value %v", field, value)
|
||||
}
|
||||
|
||||
func invalidOptionalElementInit(value ref.Val) ref.Val {
|
||||
return types.NewErr("cannot initialize optional list element from non-optional value %v", value)
|
||||
}
|
||||
|
Reference in New Issue
Block a user