go-common/app/service/live/zeus/expr/eval.go
2019-04-22 18:49:16 +08:00

603 lines
20 KiB
Go

package expr
import (
"fmt"
"hash/crc32"
"math"
"math/rand"
"reflect"
"strings"
)
const kEpsilon = 1e-7
type Env map[Var]interface{}
type runtimePanic string
func EvalBool(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 EvalInt(expr Expr, env Env) (value int64, err error) {
defer func() {
switch x := recover().(type) {
case nil:
// no panic
case runtimePanic:
value = 0
err = fmt.Errorf("%s", x)
default:
// unexpected panic: resume state of panic.
panic(x)
}
}()
if expr == nil {
return 0, nil
}
value = ConvertToInt(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":
v := ConvertToFloat(c.args[0].Eval(env))
if v < 0 {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept normal number", c.fn)))
}
return reflect.ValueOf(math.Sqrt(v))
case "rand":
return reflect.ValueOf(rand.Float64())
case "log":
v := ConvertToFloat(c.args[0].Eval(env))
if v < 0 {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept normal number", c.fn)))
}
return reflect.ValueOf(math.Log10(v))
case "to_upper":
v := c.args[0].Eval(env)
if v.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept string", c.fn)))
}
return reflect.ValueOf(strings.ToUpper(v.String()))
case "to_lower":
v := c.args[0].Eval(env)
if v.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept string", c.fn)))
}
return reflect.ValueOf(strings.ToLower(v.String()))
case "crc32":
v := c.args[0].Eval(env)
if v.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("function call: %s only accept string", c.fn)))
}
return reflect.ValueOf(crc32.ChecksumIEEE([]byte(v.String())))
}
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
case reflect.String:
return v.String() != ""
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("%v(%s) not support unary minus", v.Interface(), 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("%v(%s) not support bitwise complement", v.Interface(), v.Kind().String())))
}
}
func typeLevel(k reflect.Kind) int {
switch k {
case reflect.String:
return 5
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("%v(%s) and %v(%s) not support addition",
left.Interface(), left.Kind().String(), right.Interface(), 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("%v(%s) and %v(%s) not support subtraction",
left.Interface(), left.Kind().String(), right.Interface(), 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("%v(%s) and %v(%s) not support multiplication",
left.Interface(), left.Kind().String(), right.Interface(), 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:
lv := ConvertToFloat(left)
rv := ConvertToFloat(right)
if math.Abs(rv) < kEpsilon {
panic(runtimePanic(fmt.Sprintf("%f div %f, divide by zero", lv, rv)))
}
return reflect.ValueOf(lv / rv)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
lv := ConvertToUint(left)
rv := ConvertToUint(right)
if rv == 0 {
panic(runtimePanic(fmt.Sprintf("%d div %d, divide by zero", lv, rv)))
}
return reflect.ValueOf(lv / rv)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
lv := ConvertToInt(left)
rv := ConvertToInt(right)
if rv == 0 {
panic(runtimePanic(fmt.Sprintf("%d div %d, divide by zero", lv, rv)))
}
return reflect.ValueOf(lv / rv)
case reflect.Bool:
lv := ConvertToInt(left)
rv := ConvertToInt(right)
if rv == 0 {
panic(runtimePanic(fmt.Sprintf("%d div %d, divide by zero", lv, rv)))
}
return reflect.ValueOf(lv/rv != 0)
default:
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support division",
left.Interface(), left.Kind().String(), right.Interface(), 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("%v(%s) and %v(%s) not support division",
left.Interface(), left.Kind().String(), right.Interface(), 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("%v(%s) and %v(%s) not support bitwise and",
left.Interface(), left.Kind().String(), right.Interface(), 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("%v(%s) and %v(%s) not support bitwise or",
left.Interface(), left.Kind().String(), right.Interface(), 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.String:
if left.Kind() != reflect.String || right.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support comparison equal",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
r := strings.Compare(left.String(), right.String()) == 0
return reflect.ValueOf(r)
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("%v(%s) and %v(%s) not support comparison equal",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
}
func comparisonNotEqual(left reflect.Value, right reflect.Value) reflect.Value {
k := typeAscend(left.Kind(), right.Kind())
switch k {
case reflect.String:
if left.Kind() != reflect.String || right.Kind() != reflect.String {
panic(runtimePanic(fmt.Sprintf("%v(%s) and %v(%s) not support comparison equal",
left.Interface(), left.Kind().String(), right.Interface(), right.Kind().String())))
}
r := strings.Compare(left.String(), right.String()) != 0
return reflect.ValueOf(r)
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())))
}
}