From ff71246139837ff3fd9495dff6a77b9f65cb34c0 Mon Sep 17 00:00:00 2001 From: Qi Xiao Date: Sat, 3 Feb 2018 22:47:08 -0800 Subject: [PATCH] eval: Convert return values in ReflectBuiltinFn. --- eval/builtin_fn_num.go | 39 +++++++++++---------------------- eval/reflect_builtin_fn.go | 18 +++++++++++++-- eval/reflect_builtin_fn_test.go | 12 ++++++++++ 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/eval/builtin_fn_num.go b/eval/builtin_fn_num.go index c871828e..4dadacce 100644 --- a/eval/builtin_fn_num.go +++ b/eval/builtin_fn_num.go @@ -3,7 +3,6 @@ package eval import ( "math" "math/rand" - "strconv" ) // Numerical operations. @@ -22,11 +21,11 @@ func init() { "+": plus, "-": minus, "*": times, - "^": pow, - "%": mod, + "^": math.Pow, + "%": func(a, b int) int { return a % b }, // Random - "rand": randFn, + "rand": rand.Float64, "randint": randint, }) addToBuiltinFns([]*BuiltinFn{ @@ -34,31 +33,31 @@ func init() { }) } -func plus(nums ...float64) string { +func plus(nums ...float64) float64 { sum := 0.0 for _, f := range nums { sum += f } - return floatToString(sum) + return sum } -func minus(sum float64, nums ...float64) string { +func minus(sum float64, nums ...float64) float64 { if len(nums) == 0 { // Unary - - return floatToString(-sum) + return -sum } for _, f := range nums { sum -= f } - return floatToString(sum) + return sum } -func times(nums ...float64) string { +func times(nums ...float64) float64 { prod := 1.0 for _, f := range nums { prod *= f } - return floatToString(prod) + return prod } func slash(ec *Frame, args []interface{}, opts map[string]interface{}) { @@ -87,21 +86,9 @@ func divide(ec *Frame, args []interface{}, opts map[string]interface{}) { out <- floatToString(prod) } -func pow(b, p float64) string { - return floatToString(math.Pow(b, p)) -} - -func mod(a, b int) string { - return strconv.Itoa(a % b) -} - -func randFn() string { - return floatToString(rand.Float64()) -} - -func randint(low, high int) (string, error) { +func randint(low, high int) (int, error) { if low >= high { - return "", ErrArgs + return 0, ErrArgs } - return strconv.Itoa(low + rand.Intn(high-low)), nil + return low + rand.Intn(high-low), nil } diff --git a/eval/reflect_builtin_fn.go b/eval/reflect_builtin_fn.go index 340c30eb..c4c7d8d3 100644 --- a/eval/reflect_builtin_fn.go +++ b/eval/reflect_builtin_fn.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "reflect" + "strconv" "unsafe" "github.com/elves/elvish/eval/types" @@ -33,7 +34,8 @@ func addToReflectBuiltinFns(moreFns map[string]interface{}) { // Return values go to the channel part of the stdout port. However, if the last // return value has type error and is not nil, it is turned into an exception // and no ouputting happens. If the last return value is a nil error, it is -// ignored. +// ignored. Return values of type int or float64 are converted to strings with +// strconv.Itoa and strconv.FormatFloat(f, 'g', -1, 64) respectively. type ReflectBuiltinFn struct { name string impl interface{} @@ -157,7 +159,7 @@ func (b *ReflectBuiltinFn) Call(f *Frame, args []interface{}, opts map[string]in } for _, out := range outs { - f.OutputChan() <- out.Interface() + f.OutputChan() <- convertRet(out.Interface()) } return nil } @@ -188,3 +190,15 @@ func convertArg(arg interface{}, typ reflect.Type) (interface{}, error) { types.Kind(reflect.Zero(typ).Interface()), types.Kind(arg)) } } + +// convertRet converts the return value. +func convertRet(ret interface{}) interface{} { + switch ret := ret.(type) { + case int: + return strconv.Itoa(ret) + case float64: + return strconv.FormatFloat(ret, 'g', -1, 64) + default: + return ret + } +} diff --git a/eval/reflect_builtin_fn_test.go b/eval/reflect_builtin_fn_test.go index 5120deaf..dcf78b10 100644 --- a/eval/reflect_builtin_fn_test.go +++ b/eval/reflect_builtin_fn_test.go @@ -95,6 +95,18 @@ func TestReflectBuiltinFnCall(t *testing.T) { t.Errorf("Return value is not outputted") } + // Conversion of return values. + f = NewReflectBuiltinFn("f", func() int { return 314 }) + callGood(outFrame, nil, theOptions) + select { + case ret := <-ch: + if ret != "314" { + t.Errorf("Return value is not converted to string") + } + default: + t.Errorf("Return value is not outputted") + } + // Passing of error return value. theError := errors.New("the error") f = NewReflectBuiltinFn("f", func() (string, error) {