From 8e425c1bce2df5bebd2e2f594bbe6b40053c3fab Mon Sep 17 00:00:00 2001 From: Steven Deutsch Date: Sat, 17 Mar 2018 18:58:58 -0500 Subject: [PATCH] Add Float# abs, ceil, floor --- vm/float.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++- vm/float_test.go | 58 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/vm/float.go b/vm/float.go index e15fec54c..b5d2e20d3 100644 --- a/vm/float.go +++ b/vm/float.go @@ -353,6 +353,76 @@ func builtinFloatInstanceMethods() []*BuiltinMethodObject { } }, }, + { + // Returns the Float as a positive value. + // + // ```Ruby + // -3.14.abs # => 3.14 + // 3.14.abs # => 3.14 + // ``` + // @return [Float] + Name: "abs", + Fn: func(receiver Object, sourceLine int) builtinMethodBody { + return func(t *thread, args []Object, blockFrame *normalCallFrame) Object { + if len(args) != 0 { + return t.vm.initErrorObject(errors.ArgumentError, sourceLine, "Expect 0 argument. got=%v", strconv.Itoa(len(args))) + } + r := receiver.(*FloatObject) + result := math.Abs(r.value) + return t.vm.initFloatObject(result) + } + }, + }, + { + // Returns the smallest Integer greater than or equal to self. + // + // ```Ruby + // 1.2.ceil # => 2 + // 2.ceil # => 2 + // -1.2.ceil # => -1 + // -2.ceil # => -2 + // ``` + // @return [Integer] + Name: "ceil", + Fn: func(receiver Object, sourceLine int) builtinMethodBody { + return func(t *thread, args []Object, blockFrame *normalCallFrame) Object { + // TODO: Make ceil accept arguments + if len(args) != 0 { + return t.vm.initErrorObject(errors.ArgumentError, sourceLine, "Expect 0 argument. got=%v", strconv.Itoa(len(args))) + } + r := receiver.(*FloatObject) + result := math.Ceil(r.value) + newInt := t.vm.initIntegerObject(int(result)) + newInt.flag = i + return newInt + } + }, + }, + { + // Returns the largest Integer less than or equal to self. + // + // ```Ruby + // 1.2.floor # => 1 + // 2.0.floor # => 2 + // -1.2.floor # => -2 + // -2.0.floor # => -2 + // ``` + // @return [Integer] + Name: "floor", + Fn: func(receiver Object, sourceLine int) builtinMethodBody { + return func(t *thread, args []Object, blockFrame *normalCallFrame) Object { + // TODO: Make floor accept arguments + if len(args) != 0 { + return t.vm.initErrorObject(errors.ArgumentError, sourceLine, "Expect 0 argument. got=%v", strconv.Itoa(len(args))) + } + r := receiver.(*FloatObject) + result := math.Floor(r.value) + newInt := t.vm.initIntegerObject(int(result)) + newInt.flag = i + return newInt + } + }, + }, } } @@ -453,4 +523,4 @@ func (f *FloatObject) toJSON(t *thread) string { // equal checks if the Float values between receiver and argument are equal func (f *FloatObject) equal(e *FloatObject) bool { return f.value == e.value -} +} \ No newline at end of file diff --git a/vm/float_test.go b/vm/float_test.go index 27f4423b5..725a72dff 100644 --- a/vm/float_test.go +++ b/vm/float_test.go @@ -266,3 +266,61 @@ func TestFloatZeroDivisionFail(t *testing.T) { v.checkSP(t, i, 1) } } + +func TestFloatAbs(t *testing.T) { + tests := []struct { + input string + expected interface{} + }{ + {"34.56.abs", 34.56}, + {"-34.56.abs", 34.56}, + } + + for i, tt := range tests { + v := initTestVM() + evaluated := v.testEval(t, tt.input, getFilename()) + verifyExpected(t, i, evaluated, tt.expected) + v.checkCFP(t, i, 0) + v.checkSP(t, i, 1) + } +} + +func TestFloatCeil(t *testing.T) { + tests := []struct { + input string + expected interface{} + }{ + {"1.2.ceil", 2}, + {"2.0.ceil", 2}, + {"-1.2.ceil", -1}, + {"-2.0.ceil", -2}, + } + + for i, tt := range tests { + v := initTestVM() + evaluated := v.testEval(t, tt.input, getFilename()) + verifyExpected(t, i, evaluated, tt.expected) + v.checkCFP(t, i, 0) + v.checkSP(t, i, 1) + } +} + +func TestFloatFloor(t *testing.T) { + tests := []struct { + input string + expected interface{} + }{ + {"1.2.floor", 1}, + {"2.0.floor", 2}, + {"-1.2.floor", -2}, + {"-2.0.floor", -2}, + } + + for i, tt := range tests { + v := initTestVM() + evaluated := v.testEval(t, tt.input, getFilename()) + verifyExpected(t, i, evaluated, tt.expected) + v.checkCFP(t, i, 0) + v.checkSP(t, i, 1) + } +}