diff --git a/grumpy-runtime-src/runtime/builtin_types.go b/grumpy-runtime-src/runtime/builtin_types.go index 888951e7..6fe1c107 100644 --- a/grumpy-runtime-src/runtime/builtin_types.go +++ b/grumpy-runtime-src/runtime/builtin_types.go @@ -669,7 +669,7 @@ func builtinSetAttr(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { return None, SetAttr(f, args[0], toStrUnsafe(args[1]), args[2]) } -func builtinSorted(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { +func builtinSorted(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { // TODO: Support (cmp=None, key=None, reverse=False) if raised := checkFunctionArgs(f, "sorted", args, ObjectType); raised != nil { return nil, raised @@ -679,6 +679,14 @@ func builtinSorted(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { return nil, raised } toListUnsafe(result).Sort(f) + // Implement reverse. + reverse, raised := IsTrue(f, kwargs.get("reverse", None)) + if raised != nil { + return nil, raised + } + if reverse { + toListUnsafe(result).Reverse() + } return result, nil } diff --git a/grumpy-runtime-src/runtime/builtin_types_test.go b/grumpy-runtime-src/runtime/builtin_types_test.go index 732db19d..0ab97248 100644 --- a/grumpy-runtime-src/runtime/builtin_types_test.go +++ b/grumpy-runtime-src/runtime/builtin_types_test.go @@ -328,6 +328,11 @@ func TestBuiltinFuncs(t *testing.T) { {f: "sorted", args: wrapArgs(newTestDict("foo", 1, "bar", 2)), want: newTestList("bar", "foo").ToObject()}, {f: "sorted", args: wrapArgs(1), wantExc: mustCreateException(TypeErrorType, "'int' object is not iterable")}, {f: "sorted", args: wrapArgs(newTestList("foo", "bar"), 2), wantExc: mustCreateException(TypeErrorType, "'sorted' requires 1 arguments")}, + {f: "sorted", args: wrapArgs(newTestList(1, 2, 0, 3)), kwargs: wrapKWArgs("reverse", False), want: newTestRange(4).ToObject()}, + {f: "sorted", args: wrapArgs(newTestList(1, 2, 0, 3)), kwargs: wrapKWArgs("reverse", 0), want: newTestRange(4).ToObject()}, + {f: "sorted", args: wrapArgs(newTestList(1, 2, 0, 3)), kwargs: wrapKWArgs("reverse", None), want: newTestRange(4).ToObject()}, + {f: "sorted", args: wrapArgs(newTestList(1, 2, 0, 3)), kwargs: wrapKWArgs("reverse", True), want: newTestList(3, 2, 1, 0).ToObject()}, + {f: "sorted", args: wrapArgs(newTestList(1, 2, 0, 3)), kwargs: wrapKWArgs("reverse", 1), want: newTestList(3, 2, 1, 0).ToObject()}, {f: "sum", args: wrapArgs(newTestList(1, 2, 3, 4)), want: NewInt(10).ToObject()}, {f: "sum", args: wrapArgs(newTestList(1, 2), 3), want: NewFloat(6).ToObject()}, {f: "sum", args: wrapArgs(newTestList(2, 1.1)), want: NewFloat(3.1).ToObject()}, diff --git a/grumpy-runtime-src/runtime/list.go b/grumpy-runtime-src/runtime/list.go index 41e4c442..72b26a77 100644 --- a/grumpy-runtime-src/runtime/list.go +++ b/grumpy-runtime-src/runtime/list.go @@ -61,6 +61,17 @@ func (l *List) Append(o *Object) { l.mutex.Unlock() } +// Reverse the list in place. +func (l *List) Reverse() { + l.mutex.Lock() + halfLen := len(l.elems) / 2 + for i := 0; i < halfLen; i++ { + j := len(l.elems) - i - 1 + l.elems[i], l.elems[j] = l.elems[j], l.elems[i] + } + l.mutex.Unlock() +} + // DelItem removes the index'th element of l. func (l *List) DelItem(f *Frame, index int) *BaseException { l.mutex.Lock() @@ -485,13 +496,7 @@ func listReverse(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { return nil, raised } l := toListUnsafe(args[0]) - l.mutex.Lock() - halfLen := len(l.elems) / 2 - for i := 0; i < halfLen; i++ { - j := len(l.elems) - i - 1 - l.elems[i], l.elems[j] = l.elems[j], l.elems[i] - } - l.mutex.Unlock() + l.Reverse() return None, nil } diff --git a/grumpy-runtime-src/testing/builtin_test.py b/grumpy-runtime-src/testing/builtin_test.py index c7932682..5f099111 100644 --- a/grumpy-runtime-src/testing/builtin_test.py +++ b/grumpy-runtime-src/testing/builtin_test.py @@ -310,6 +310,9 @@ class Foo(object): assert sorted(["a", "e", "c", "b"]) == ["a", "b", "c", "e"] assert sorted((3, 1, 5, 2, 4)) == [1, 2, 3, 4, 5] assert sorted({"foo": 1, "bar": 2}) == ["bar", "foo"] +assert sorted([1, 2], reverse=True) == [2, 1] +assert sorted([1, 2], reverse=42) == [2, 1] +assert sorted([1, 2], reverse=0) == [1, 2] # Test zip