You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
505 lines
17 KiB
505 lines
17 KiB
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()))) |
|
} |
|
}
|
|
|