diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..7a73a41bf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/vm/float.go b/vm/float.go index e15fec54c..5952126ca 100644 --- a/vm/float.go +++ b/vm/float.go @@ -353,6 +353,135 @@ func builtinFloatInstanceMethods() []*BuiltinMethodObject { } }, }, + { + // Returns the Float as a positive value. + // + // ```Ruby + // -34.56.abs # => 34.56 + // 34.56.abs # => 34.56 + // ``` + // @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 + } + }, + }, + { + // Returns true if Float is equal to 0.0 + // + // ```Ruby + // 0.0.zero? # => true + // 1.0.zero? # => false + // ``` + // @return [Boolean] + Name: "zero?", + 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) + return toBooleanObject(r.value == 0.0) + } + }, + }, + { + // Returns true if Float is larger than 0.0 + // + // ```Ruby + // -1.0.positive? # => false + // 0.0.positive? # => false + // 1.0.positive? # => true + // ``` + // @return [Boolean] + Name: "positive?", + 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) + return toBooleanObject(r.value > 0.0) + } + }, + }, + { + // Returns true if Float is less than 0.0 + // + // ```Ruby + // -1.0.negative? # => true + // 0.0.negative? # => false + // 1.0.negative? # => false + // ``` + // @return [Boolean] + Name: "negative?", + 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) + return toBooleanObject(r.value < 0.0) + } + }, + }, } } diff --git a/vm/float_test.go b/vm/float_test.go index 27f4423b5..b955c4e25 100644 --- a/vm/float_test.go +++ b/vm/float_test.go @@ -266,3 +266,117 @@ 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) + } +} + +func TestZero(t *testing.T) { + tests := []struct { + input string + expected interface{} + }{ + {"0.0.zero?", true}, + {"1.0.zero?", false}, + } + + 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 TestPositive(t *testing.T) { + tests := []struct { + input string + expected interface{} + }{ + {"-1.0.positive?", false}, + {"0.0.positive?", false}, + {"1.0.positive?", true}, + } + + 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 TestNegative(t *testing.T) { + tests := []struct { + input string + expected interface{} + }{ + {"-1.0.negative?", true}, + {"0.0.negative?", false}, + {"1.0.negative?", false}, + } + + 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) + } +}