diff --git a/engine/number.go b/engine/number.go index 05e2dd6..d87d5c7 100644 --- a/engine/number.go +++ b/engine/number.go @@ -823,6 +823,44 @@ func IntFloorDiv(x, y Number) (Number, error) { } } +// Max returns the maximum of x or y. +func Max(x, y Number) (Number, error) { + switch x := x.(type) { + case Integer: + switch y := y.(type) { + case Integer: + if x < y { + return y, nil + } + return x, nil + case Float: + if floatItoF(x) < y { + return y, nil + } + return x, nil + default: + return nil, ErrUndefined + } + case Float: + switch y := y.(type) { + case Integer: + if x < floatItoF(y) { + return y, nil + } + return x, nil + case Float: + if x < y { + return y, nil + } + return x, nil + default: + return nil, ErrUndefined + } + default: + return nil, ErrUndefined + } +} + // Comparison func eqF(x, y Float) bool { diff --git a/engine/number_test.go b/engine/number_test.go index 1585ac6..0fd626d 100644 --- a/engine/number_test.go +++ b/engine/number_test.go @@ -1410,6 +1410,67 @@ func TestIntFloorDiv(t *testing.T) { }) } +func TestMax(t *testing.T) { + t.Run("integer", func(t *testing.T) { + t.Run("integer", func(t *testing.T) { + r, err := Max(Integer(1), Integer(2)) + assert.NoError(t, err) + assert.Equal(t, Integer(2), r) + + r, err = Max(Integer(1), Integer(1)) + assert.NoError(t, err) + assert.Equal(t, Integer(1), r) + }) + + t.Run("float", func(t *testing.T) { + r, err := Max(Integer(1), Float(2)) + assert.NoError(t, err) + assert.Equal(t, Float(2), r) + + r, err = Max(Integer(1), Float(1)) + assert.NoError(t, err) + assert.Equal(t, Integer(1), r) + }) + + t.Run("not a number", func(t *testing.T) { + _, err := Max(Integer(1), mockNumber{}) + assert.Equal(t, ErrUndefined, err) + }) + }) + + t.Run("float", func(t *testing.T) { + t.Run("integer", func(t *testing.T) { + r, err := Max(Float(1), Integer(2)) + assert.NoError(t, err) + assert.Equal(t, Integer(2), r) + + r, err = Max(Float(1), Integer(1)) + assert.NoError(t, err) + assert.Equal(t, Float(1), r) + }) + + t.Run("float", func(t *testing.T) { + r, err := Max(Float(1), Float(2)) + assert.NoError(t, err) + assert.Equal(t, Float(2), r) + + r, err = Max(Float(1), Float(1)) + assert.NoError(t, err) + assert.Equal(t, Float(1), r) + }) + + t.Run("not a number", func(t *testing.T) { + _, err := Max(Float(1), mockNumber{}) + assert.Equal(t, ErrUndefined, err) + }) + }) + + t.Run("not a number", func(t *testing.T) { + _, err := Max(mockNumber{}, Integer(1)) + assert.Equal(t, ErrUndefined, err) + }) +} + type mockNumber struct { mock.Mock }