diff --git a/docs/lexicon.html b/docs/lexicon.html
index 3090834c8b..49ee4c2660 100644
--- a/docs/lexicon.html
+++ b/docs/lexicon.html
@@ -159,11 +159,13 @@
sorted(seq[,key])][,reverse])
- returns a copy of seq with the contents
sorted. key is a function that is applied
- to each item before comparison.
+ to each item before comparison. If reverse is true, the items are sorted in reverse order.
diff --git a/rules/builtins.build_defs b/rules/builtins.build_defs
index 5488f9f105..a8c9fcfd2e 100644
--- a/rules/builtins.build_defs
+++ b/rules/builtins.build_defs
@@ -125,7 +125,7 @@ def glob(include:list|str, exclude:list|str&excludes=[], hidden:bool=CONFIG.BAZE
def package():
pass
-def sorted(seq:list, key:function=None) -> list:
+def sorted(seq:list, key:function=None, reverse:bool=False) -> list:
pass
def reversed(seq:list) -> list:
diff --git a/src/parse/asp/builtins.go b/src/parse/asp/builtins.go
index 8ce3e24680..69c2564c17 100644
--- a/src/parse/asp/builtins.go
+++ b/src/parse/asp/builtins.go
@@ -800,11 +800,17 @@ func dictCopy(s *scope, args []pyObject) pyObject {
func sorted(s *scope, args []pyObject) pyObject {
l, isList := args[0].(pyList)
key, isFunc := args[1].(*pyFunc)
+ reverse, isBool := args[2].(pyBool)
s.Assert(isList, "Argument seq must be a list, not %s", args[0].Type())
+ s.Assert(isBool, "Argument reverse must be a bool, not %s", args[2].Type())
+ order := LessThan
+ if reverse {
+ order = GreaterThan
+ }
l = l[:]
if key == nil {
sort.Slice(l, func(i, j int) bool {
- return s.operator(LessThan, l[i], l[j]).IsTruthy()
+ return s.operator(order, l[i], l[j]).IsTruthy()
})
} else {
s.Assert(isFunc, "Argument key must be callable, not %s", args[1].Type())
@@ -819,7 +825,7 @@ func sorted(s *scope, args []pyObject) pyObject {
Value: Expression{optimised: &optimisedExpression{Constant: l[j]}},
}},
})
- return s.operator(LessThan, iKey, jKey).IsTruthy()
+ return s.operator(order, iKey, jKey).IsTruthy()
})
}
return l
diff --git a/src/parse/asp/interpreter_test.go b/src/parse/asp/interpreter_test.go
index 6a8faa3c11..d94fce0f6c 100644
--- a/src/parse/asp/interpreter_test.go
+++ b/src/parse/asp/interpreter_test.go
@@ -172,6 +172,8 @@ func TestInterpreterSorting(t *testing.T) {
// N.B. sorted() sorts in-place, unlike Python's one. We may change that later.
assert.Equal(t, pyList{pyInt(1), pyInt(2), pyInt(3)}, s.Lookup("r1"))
assert.Equal(t, pyList{pyString("ONE"), pyString("THREE"), pyString("two")}, s.Lookup("r2"))
+ assert.Equal(t, pyList{pyInt(4), pyInt(3), pyInt(2), pyInt(1)}, s.Lookup("r3"))
+ assert.Equal(t, pyList{pyInt(1), pyInt(2), pyInt(3), pyInt(4)}, s.Lookup("r4"))
}
func TestReversed(t *testing.T) {
diff --git a/src/parse/asp/test_data/interpreter/sorted.build b/src/parse/asp/test_data/interpreter/sorted.build
index 29e2d58f33..4125a388cb 100644
--- a/src/parse/asp/test_data/interpreter/sorted.build
+++ b/src/parse/asp/test_data/interpreter/sorted.build
@@ -4,3 +4,7 @@ r1 = sorted(l1)
# key parameter test
l2 = ["ONE", "two", "THREE"]
r2 = sorted(l2, key=lambda s: s.lower())
+
+# reverse parameter test
+r3 = sorted([2, 4, 1, 3], reverse=True)
+r4 = sorted([2, 4, 1, 3], reverse=False)