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

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())))
}
}