506 lines
17 KiB
Go
506 lines
17 KiB
Go
package expr
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"reflect"
|
|
)
|
|
|
|
type Env map[Var]interface{}
|
|
|
|
type runtimePanic string
|
|
|
|
func SafetyEvalBool(expr Expr, env Env) (value bool, err error) {
|
|
defer func() {
|
|
switch x := recover().(type) {
|
|
case nil:
|
|
// no panic
|
|
case runtimePanic:
|
|
value = false
|
|
err = fmt.Errorf("%s", x)
|
|
default:
|
|
// unexpected panic: resume state of panic.
|
|
panic(x)
|
|
}
|
|
}()
|
|
if expr == nil {
|
|
return false, nil
|
|
}
|
|
value = ConvertToBool(expr.Eval(env))
|
|
return
|
|
}
|
|
|
|
func (v Var) Eval(env Env) reflect.Value {
|
|
switch v {
|
|
case "true":
|
|
return reflect.ValueOf(true)
|
|
case "false":
|
|
return reflect.ValueOf(false)
|
|
default:
|
|
if i, ok := env[v]; ok {
|
|
return reflect.ValueOf(i)
|
|
}
|
|
panic(runtimePanic(fmt.Sprintf("undefined variable: %s", v)))
|
|
}
|
|
}
|
|
|
|
func (l literal) Eval(_ Env) reflect.Value {
|
|
return reflect.ValueOf(l.value)
|
|
}
|
|
|
|
func (u unary) Eval(env Env) reflect.Value {
|
|
switch u.op {
|
|
case "+":
|
|
return unaryPlus(u.x.Eval(env))
|
|
case "-":
|
|
return unaryMinus(u.x.Eval(env))
|
|
case "!":
|
|
return logicalNegation(u.x.Eval(env))
|
|
case "~":
|
|
return bitwiseComplement(u.x.Eval(env))
|
|
}
|
|
panic(runtimePanic(fmt.Sprintf("unsupported unary operator: %q", u.op)))
|
|
}
|
|
|
|
func (b binary) Eval(env Env) reflect.Value {
|
|
switch b.op {
|
|
case "+":
|
|
return addition(b.x.Eval(env), b.y.Eval(env))
|
|
case "-":
|
|
return subtraction(b.x.Eval(env), b.y.Eval(env))
|
|
case "*":
|
|
return multiplication(b.x.Eval(env), b.y.Eval(env))
|
|
case "/":
|
|
return division(b.x.Eval(env), b.y.Eval(env))
|
|
case "%":
|
|
return modulus(b.x.Eval(env), b.y.Eval(env))
|
|
case "&":
|
|
return bitwiseAnd(b.x.Eval(env), b.y.Eval(env))
|
|
case "&&":
|
|
return logicalAnd(b.x.Eval(env), b.y.Eval(env))
|
|
case "|":
|
|
return bitwiseOr(b.x.Eval(env), b.y.Eval(env))
|
|
case "||":
|
|
return logicalOr(b.x.Eval(env), b.y.Eval(env))
|
|
case "=", "==":
|
|
return comparisonEqual(b.x.Eval(env), b.y.Eval(env))
|
|
case ">":
|
|
return comparisonGreater(b.x.Eval(env), b.y.Eval(env))
|
|
case ">=":
|
|
return comparisonGreaterOrEqual(b.x.Eval(env), b.y.Eval(env))
|
|
case "<":
|
|
return comparisonLess(b.x.Eval(env), b.y.Eval(env))
|
|
case "<=":
|
|
return comparisonLessOrEqual(b.x.Eval(env), b.y.Eval(env))
|
|
case "!=":
|
|
return comparisonNotEqual(b.x.Eval(env), b.y.Eval(env))
|
|
}
|
|
panic(runtimePanic(fmt.Sprintf("unsupported binary operator: %q", b.op)))
|
|
}
|
|
|
|
func (c call) Eval(env Env) reflect.Value {
|
|
switch c.fn {
|
|
case "pow":
|
|
return reflect.ValueOf(math.Pow(ConvertToFloat(c.args[0].Eval(env)), ConvertToFloat(c.args[1].Eval(env))))
|
|
case "sin":
|
|
return reflect.ValueOf(math.Sin(ConvertToFloat(c.args[0].Eval(env))))
|
|
case "sqrt":
|
|
return reflect.ValueOf(math.Sqrt(ConvertToFloat(c.args[0].Eval(env))))
|
|
}
|
|
panic(runtimePanic(fmt.Sprintf("unsupported function call: %s", c.fn)))
|
|
}
|
|
|
|
func ConvertToBool(v reflect.Value) bool {
|
|
switch v.Kind() {
|
|
case reflect.Bool:
|
|
return v.Bool()
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return v.Int() != 0
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return v.Uint() != 0
|
|
case reflect.Float32, reflect.Float64:
|
|
return v.Float() != 0
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("cannot convert data type: %s to bool", v.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func ConvertToInt(v reflect.Value) int64 {
|
|
switch v.Kind() {
|
|
case reflect.Bool:
|
|
if v.Bool() {
|
|
return 1
|
|
} else {
|
|
return 0
|
|
}
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return v.Int()
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return int64(v.Uint())
|
|
case reflect.Float32, reflect.Float64:
|
|
return int64(v.Float())
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("cannot convert data type: %s to int", v.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func ConvertToUint(v reflect.Value) uint64 {
|
|
switch v.Kind() {
|
|
case reflect.Bool:
|
|
if v.Bool() {
|
|
return 1
|
|
} else {
|
|
return 0
|
|
}
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return uint64(v.Int())
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return v.Uint()
|
|
case reflect.Float32, reflect.Float64:
|
|
return uint64(v.Float())
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("cannot convert data type: %s to uint", v.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func ConvertToFloat(v reflect.Value) float64 {
|
|
switch v.Kind() {
|
|
case reflect.Bool:
|
|
if v.Bool() {
|
|
return 1
|
|
} else {
|
|
return 0
|
|
}
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return float64(v.Int())
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return float64(v.Uint())
|
|
case reflect.Float32, reflect.Float64:
|
|
return v.Float()
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("cannot convert data type: %s to float", v.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func unaryPlus(v reflect.Value) reflect.Value {
|
|
return v
|
|
}
|
|
|
|
func unaryMinus(v reflect.Value) reflect.Value {
|
|
switch v.Kind() {
|
|
case reflect.Bool:
|
|
return v
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return reflect.ValueOf(-v.Int())
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return reflect.ValueOf(-v.Uint())
|
|
case reflect.Float32, reflect.Float64:
|
|
return reflect.ValueOf(-v.Float())
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("unary minus not support type: %s", v.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func logicalNegation(v reflect.Value) reflect.Value {
|
|
return reflect.ValueOf(!ConvertToBool(v))
|
|
}
|
|
|
|
func bitwiseComplement(v reflect.Value) reflect.Value {
|
|
switch v.Kind() {
|
|
case reflect.Bool:
|
|
return reflect.ValueOf(!v.Bool())
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return reflect.ValueOf(^v.Int())
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return reflect.ValueOf(^v.Uint())
|
|
case reflect.Float32, reflect.Float64:
|
|
panic(runtimePanic("cannot eval ~ for float"))
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("bitwise complement not support type: %s", v.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func typeLevel(k reflect.Kind) int {
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
return 4
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return 3
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return 2
|
|
case reflect.Bool:
|
|
return 1
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func typeAscend(a reflect.Kind, b reflect.Kind) reflect.Kind {
|
|
if typeLevel(a) >= typeLevel(b) {
|
|
return a
|
|
} else {
|
|
return b
|
|
}
|
|
}
|
|
|
|
func addition(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) + ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) + ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) + ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) + ConvertToInt(right)
|
|
return reflect.ValueOf(r != 0)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support addition", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func subtraction(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) - ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) - ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) - ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) - ConvertToInt(right)
|
|
return reflect.ValueOf(r != 0)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support subtraction", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func multiplication(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) * ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) * ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) * ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) * ConvertToInt(right)
|
|
return reflect.ValueOf(r != 0)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support multiplication", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func division(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) / ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) / ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) / ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) / ConvertToInt(right)
|
|
return reflect.ValueOf(r != 0)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support division", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func modulus(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) % ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) % ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) % ConvertToInt(right)
|
|
return reflect.ValueOf(r != 0)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support division", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func bitwiseAnd(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) & ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) & ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToBool(left) && ConvertToBool(right)
|
|
return reflect.ValueOf(r)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support bitwise and", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func bitwiseOr(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) | ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) | ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToBool(left) || ConvertToBool(right)
|
|
return reflect.ValueOf(r)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support bitwise or", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func logicalAnd(left reflect.Value, right reflect.Value) reflect.Value {
|
|
r := ConvertToBool(left) && ConvertToBool(right)
|
|
return reflect.ValueOf(r)
|
|
}
|
|
|
|
func logicalOr(left reflect.Value, right reflect.Value) reflect.Value {
|
|
r := ConvertToBool(left) || ConvertToBool(right)
|
|
return reflect.ValueOf(r)
|
|
}
|
|
|
|
func comparisonEqual(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) == ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) == ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) == ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) == ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison equal", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func comparisonNotEqual(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) != ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) != ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) != ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) != ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison not equal", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func comparisonGreater(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) > ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) > ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) > ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) > ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison greater", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func comparisonGreaterOrEqual(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) >= ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) >= ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) >= ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) >= ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison greater or equal", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func comparisonLess(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) < ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) < ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) < ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) < ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison less", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|
|
|
|
func comparisonLessOrEqual(left reflect.Value, right reflect.Value) reflect.Value {
|
|
k := typeAscend(left.Kind(), right.Kind())
|
|
switch k {
|
|
case reflect.Float32, reflect.Float64:
|
|
r := ConvertToFloat(left) <= ConvertToFloat(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
r := ConvertToUint(left) <= ConvertToUint(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
r := ConvertToInt(left) <= ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
case reflect.Bool:
|
|
r := ConvertToInt(left) <= ConvertToInt(right)
|
|
return reflect.ValueOf(r)
|
|
default:
|
|
panic(runtimePanic(fmt.Sprintf("type %s and %s not support comparison less or equal", left.Kind().String(), right.Kind().String())))
|
|
}
|
|
}
|