From 1ed25147787b2c1b4445f9f863f575ecf4061b41 Mon Sep 17 00:00:00 2001 From: Furkan Date: Fri, 4 Nov 2022 21:51:13 +0300 Subject: [PATCH] Fix DivideOp: change resulting type to float64 Fixes #270 Signed-off-by: Furkan --- expr_test.go | 61 +++++++++++ vm/runtime/generate/main.go | 4 + vm/runtime/helpers.go | 204 ++++++++++++++++++------------------ vm/vm.go | 2 +- 4 files changed, 168 insertions(+), 103 deletions(-) diff --git a/expr_test.go b/expr_test.go index 3c90ebd81..507482687 100644 --- a/expr_test.go +++ b/expr_test.go @@ -1449,6 +1449,67 @@ func TestIssue154(t *testing.T) { } } +func TestIssue270(t *testing.T) { + env := map[string]interface{}{ + "int8": int8(1), + "int16": int16(3), + "int32": int32(5), + "int64": int64(7), + "uint8": uint8(11), + "uint16": uint16(13), + "uint32": uint32(17), + "uint64": uint64(19), + "int8a": uint(23), + "int8b": uint(29), + "int16a": uint(31), + "int16b": uint(37), + "int32a": uint(41), + "int32b": uint(43), + "int64a": uint(47), + "int64b": uint(53), + "uint8a": uint(59), + "uint8b": uint(61), + "uint16a": uint(67), + "uint16b": uint(71), + "uint32a": uint(73), + "uint32b": uint(79), + "uint64a": uint(83), + "uint64b": uint(89), + "float32a": float32(97), + "float32b": float32(101), + "float64a": float64(103), + "float64b": float64(107), + } + for _, each := range []struct { + input string + expected float64 + }{ + {"int8 / int16", 0.3333333333333333}, + {"int32 / int64", 0.7142857142857143}, + {"uint8 / uint16", 0.8461538461538461}, + {"uint32 / uint64", 0.8947368421052632}, + {"int8 / uint64", 0.05263157894736842}, + {"int64 / uint8", 0.6363636363636364}, + {"int8a / int8b", 0.7931034482758621}, + {"int16a / int16b", 0.8378378378378378}, + {"int32a / int32b", 0.9534883720930233}, + {"int64a / int64b", 0.8867924528301887}, + {"uint8a / uint8b", 0.9672131147540983}, + {"uint16a / uint16b", 0.9436619718309859}, + {"uint32a / uint32b", 0.9240506329113924}, + {"uint64a / uint64b", 0.9325842696629213}, + {"float32a / float32b", 0.9603960514068604}, + {"float64a / float64b", 0.9626168224299065}, + } { + p, err := expr.Compile(each.input, expr.Env(env)) + require.NoError(t, err) + + out, err := expr.Run(p, env) + require.NoError(t, err) + require.Equal(t, each.expected, out) + } +} + // Mock types type mockEnv struct { Any interface{} diff --git a/vm/runtime/generate/main.go b/vm/runtime/generate/main.go index cff33d274..2222ba906 100644 --- a/vm/runtime/generate/main.go +++ b/vm/runtime/generate/main.go @@ -66,6 +66,10 @@ func cases(op string, noFloat bool) string { t = "float64" } echo(`case %v:`, b) + if op == "/" { + echo(`return float64(x) / float64(y)`) + continue + } if i == j { echo(`return x %v y`, op) } diff --git a/vm/runtime/helpers.go b/vm/runtime/helpers.go index 707b66bc1..b84071030 100644 --- a/vm/runtime/helpers.go +++ b/vm/runtime/helpers.go @@ -2726,25 +2726,25 @@ func Divide(a, b interface{}) interface{} { case uint: switch y := b.(type) { case uint: - return x / y + return float64(x) / float64(y) case uint8: - return int(x) / int(y) + return float64(x) / float64(y) case uint16: - return int(x) / int(y) + return float64(x) / float64(y) case uint32: - return int(x) / int(y) + return float64(x) / float64(y) case uint64: - return int(x) / int(y) + return float64(x) / float64(y) case int: - return int(x) / int(y) + return float64(x) / float64(y) case int8: - return int(x) / int(y) + return float64(x) / float64(y) case int16: - return int(x) / int(y) + return float64(x) / float64(y) case int32: - return int(x) / int(y) + return float64(x) / float64(y) case int64: - return int(x) / int(y) + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -2753,25 +2753,25 @@ func Divide(a, b interface{}) interface{} { case uint8: switch y := b.(type) { case uint: - return int(x) / int(y) + return float64(x) / float64(y) case uint8: - return x / y + return float64(x) / float64(y) case uint16: - return int(x) / int(y) + return float64(x) / float64(y) case uint32: - return int(x) / int(y) + return float64(x) / float64(y) case uint64: - return int(x) / int(y) + return float64(x) / float64(y) case int: - return int(x) / int(y) + return float64(x) / float64(y) case int8: - return int(x) / int(y) + return float64(x) / float64(y) case int16: - return int(x) / int(y) + return float64(x) / float64(y) case int32: - return int(x) / int(y) + return float64(x) / float64(y) case int64: - return int(x) / int(y) + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -2780,25 +2780,25 @@ func Divide(a, b interface{}) interface{} { case uint16: switch y := b.(type) { case uint: - return int(x) / int(y) + return float64(x) / float64(y) case uint8: - return int(x) / int(y) + return float64(x) / float64(y) case uint16: - return x / y + return float64(x) / float64(y) case uint32: - return int(x) / int(y) + return float64(x) / float64(y) case uint64: - return int(x) / int(y) + return float64(x) / float64(y) case int: - return int(x) / int(y) + return float64(x) / float64(y) case int8: - return int(x) / int(y) + return float64(x) / float64(y) case int16: - return int(x) / int(y) + return float64(x) / float64(y) case int32: - return int(x) / int(y) + return float64(x) / float64(y) case int64: - return int(x) / int(y) + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -2807,25 +2807,25 @@ func Divide(a, b interface{}) interface{} { case uint32: switch y := b.(type) { case uint: - return int(x) / int(y) + return float64(x) / float64(y) case uint8: - return int(x) / int(y) + return float64(x) / float64(y) case uint16: - return int(x) / int(y) + return float64(x) / float64(y) case uint32: - return x / y + return float64(x) / float64(y) case uint64: - return int(x) / int(y) + return float64(x) / float64(y) case int: - return int(x) / int(y) + return float64(x) / float64(y) case int8: - return int(x) / int(y) + return float64(x) / float64(y) case int16: - return int(x) / int(y) + return float64(x) / float64(y) case int32: - return int(x) / int(y) + return float64(x) / float64(y) case int64: - return int(x) / int(y) + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -2834,25 +2834,25 @@ func Divide(a, b interface{}) interface{} { case uint64: switch y := b.(type) { case uint: - return int(x) / int(y) + return float64(x) / float64(y) case uint8: - return int(x) / int(y) + return float64(x) / float64(y) case uint16: - return int(x) / int(y) + return float64(x) / float64(y) case uint32: - return int(x) / int(y) + return float64(x) / float64(y) case uint64: - return x / y + return float64(x) / float64(y) case int: - return int(x) / int(y) + return float64(x) / float64(y) case int8: - return int(x) / int(y) + return float64(x) / float64(y) case int16: - return int(x) / int(y) + return float64(x) / float64(y) case int32: - return int(x) / int(y) + return float64(x) / float64(y) case int64: - return int(x) / int(y) + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -2861,25 +2861,25 @@ func Divide(a, b interface{}) interface{} { case int: switch y := b.(type) { case uint: - return int(x) / int(y) + return float64(x) / float64(y) case uint8: - return int(x) / int(y) + return float64(x) / float64(y) case uint16: - return int(x) / int(y) + return float64(x) / float64(y) case uint32: - return int(x) / int(y) + return float64(x) / float64(y) case uint64: - return int(x) / int(y) + return float64(x) / float64(y) case int: - return x / y + return float64(x) / float64(y) case int8: - return int(x) / int(y) + return float64(x) / float64(y) case int16: - return int(x) / int(y) + return float64(x) / float64(y) case int32: - return int(x) / int(y) + return float64(x) / float64(y) case int64: - return int(x) / int(y) + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -2888,25 +2888,25 @@ func Divide(a, b interface{}) interface{} { case int8: switch y := b.(type) { case uint: - return int(x) / int(y) + return float64(x) / float64(y) case uint8: - return int(x) / int(y) + return float64(x) / float64(y) case uint16: - return int(x) / int(y) + return float64(x) / float64(y) case uint32: - return int(x) / int(y) + return float64(x) / float64(y) case uint64: - return int(x) / int(y) + return float64(x) / float64(y) case int: - return int(x) / int(y) + return float64(x) / float64(y) case int8: - return x / y + return float64(x) / float64(y) case int16: - return int(x) / int(y) + return float64(x) / float64(y) case int32: - return int(x) / int(y) + return float64(x) / float64(y) case int64: - return int(x) / int(y) + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -2915,25 +2915,25 @@ func Divide(a, b interface{}) interface{} { case int16: switch y := b.(type) { case uint: - return int(x) / int(y) + return float64(x) / float64(y) case uint8: - return int(x) / int(y) + return float64(x) / float64(y) case uint16: - return int(x) / int(y) + return float64(x) / float64(y) case uint32: - return int(x) / int(y) + return float64(x) / float64(y) case uint64: - return int(x) / int(y) + return float64(x) / float64(y) case int: - return int(x) / int(y) + return float64(x) / float64(y) case int8: - return int(x) / int(y) + return float64(x) / float64(y) case int16: - return x / y + return float64(x) / float64(y) case int32: - return int(x) / int(y) + return float64(x) / float64(y) case int64: - return int(x) / int(y) + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -2942,25 +2942,25 @@ func Divide(a, b interface{}) interface{} { case int32: switch y := b.(type) { case uint: - return int(x) / int(y) + return float64(x) / float64(y) case uint8: - return int(x) / int(y) + return float64(x) / float64(y) case uint16: - return int(x) / int(y) + return float64(x) / float64(y) case uint32: - return int(x) / int(y) + return float64(x) / float64(y) case uint64: - return int(x) / int(y) + return float64(x) / float64(y) case int: - return int(x) / int(y) + return float64(x) / float64(y) case int8: - return int(x) / int(y) + return float64(x) / float64(y) case int16: - return int(x) / int(y) + return float64(x) / float64(y) case int32: - return x / y + return float64(x) / float64(y) case int64: - return int(x) / int(y) + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -2969,25 +2969,25 @@ func Divide(a, b interface{}) interface{} { case int64: switch y := b.(type) { case uint: - return int(x) / int(y) + return float64(x) / float64(y) case uint8: - return int(x) / int(y) + return float64(x) / float64(y) case uint16: - return int(x) / int(y) + return float64(x) / float64(y) case uint32: - return int(x) / int(y) + return float64(x) / float64(y) case uint64: - return int(x) / int(y) + return float64(x) / float64(y) case int: - return int(x) / int(y) + return float64(x) / float64(y) case int8: - return int(x) / int(y) + return float64(x) / float64(y) case int16: - return int(x) / int(y) + return float64(x) / float64(y) case int32: - return int(x) / int(y) + return float64(x) / float64(y) case int64: - return x / y + return float64(x) / float64(y) case float32: return float64(x) / float64(y) case float64: @@ -3016,7 +3016,7 @@ func Divide(a, b interface{}) interface{} { case int64: return float64(x) / float64(y) case float32: - return x / y + return float64(x) / float64(y) case float64: return float64(x) / float64(y) } @@ -3045,7 +3045,7 @@ func Divide(a, b interface{}) interface{} { case float32: return float64(x) / float64(y) case float64: - return x / y + return float64(x) / float64(y) } } panic(fmt.Sprintf("invalid operation: %T / %T", a, b)) diff --git a/vm/vm.go b/vm/vm.go index 5f4afaa63..f51785424 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -225,7 +225,7 @@ func (vm *VM) Run(program *Program, env interface{}) (out interface{}, err error case OpDivide: b := vm.pop() a := vm.pop() - vm.push(runtime.Divide(a, b)) + vm.push(runtime.ToFloat64(runtime.Divide(a, b))) case OpModulo: b := vm.pop()