Skip to content

Commit ffb374f

Browse files
committed
Add sorted and list.sort
Mostly finished, needs some argument parsing changes.
1 parent 7bc4005 commit ffb374f

File tree

2 files changed

+159
-1
lines changed

2 files changed

+159
-1
lines changed

builtin/builtin.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func init() {
6060
py.MustNewMethod("repr", builtin_repr, 0, repr_doc),
6161
py.MustNewMethod("round", builtin_round, 0, round_doc),
6262
py.MustNewMethod("setattr", builtin_setattr, 0, setattr_doc),
63-
// py.MustNewMethod("sorted", builtin_sorted, 0, sorted_doc),
63+
py.MustNewMethod("sorted", builtin_sorted, 0, sorted_doc),
6464
py.MustNewMethod("sum", builtin_sum, 0, sum_doc),
6565
// py.MustNewMethod("vars", builtin_vars, 0, vars_doc),
6666
}
@@ -1074,3 +1074,28 @@ func builtin_sum(self py.Object, args py.Tuple) (py.Object, error) {
10741074
}
10751075
return start, nil
10761076
}
1077+
1078+
const sorted_doc = `sorted(iterable, key=None, reverse=False)
1079+
Return a new list containing all items from the iterable in ascending order.
1080+
1081+
A custom key function can be supplied to customize the sort order, and the
1082+
reverse flag can be set to request the result in descending order.`
1083+
1084+
func builtin_sorted(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) {
1085+
var iterable py.Object
1086+
var keyFunc py.Object = py.None
1087+
var reverse py.Object = py.False
1088+
err := py.ParseTupleAndKeywords(args, kwargs, "O|Op:sorted", []string{"iterable", "key", "reverse"}, &iterable, &keyFunc, &reverse)
1089+
if err != nil {
1090+
return nil, err
1091+
}
1092+
l, err := py.SequenceList(iterable)
1093+
if err != nil {
1094+
return nil, err
1095+
}
1096+
err = py.SortInPlace(l, keyFunc, reverse)
1097+
if err != nil {
1098+
return nil, err
1099+
}
1100+
return l, nil
1101+
}

py/list.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
package py
88

9+
import (
10+
"sort"
11+
)
12+
913
var ListType = ObjectType.NewType("list", "list() -> new empty list\nlist(iterable) -> new list initialized from iterable's items", ListNew, nil)
1014

1115
// FIXME lists are mutable so this should probably be struct { Tuple } then can use the sub methods on Tuple
@@ -34,6 +38,29 @@ func init() {
3438
return NoneType{}, nil
3539
}, 0, "extend([item])")
3640

41+
ListType.Dict["sort"] = MustNewMethod("sort", func(self Object, args Tuple, kwargs StringDict) (Object, error) {
42+
43+
if len(args) != 0 {
44+
return nil, ExceptionNewf(TypeError, "sort() takes no positional arguments")
45+
}
46+
47+
var keyFunc Object = None
48+
var reverse Object = False
49+
50+
err := ParseTupleAndKeywords(nil, kwargs, "|Op:sort", []string{"key", "reverse"}, &keyFunc, &reverse)
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
listSelf := self.(*List)
56+
57+
err = SortInPlace(listSelf, keyFunc, reverse)
58+
if err != nil {
59+
return nil, err
60+
}
61+
return NoneType{}, nil
62+
}, 0, "sort(key=None, reverse=False)")
63+
3764
}
3865

3966
// Type of this List object
@@ -331,3 +358,109 @@ func (a *List) M__ne__(other Object) (Object, error) {
331358
}
332359
return False, nil
333360
}
361+
362+
type sortable struct {
363+
l *List
364+
keyFunc Object
365+
reverse bool
366+
firstErr error
367+
}
368+
369+
type ptrSortable struct {
370+
s *sortable
371+
}
372+
373+
func (s ptrSortable) Len() int {
374+
return s.s.l.Len()
375+
}
376+
377+
func (s ptrSortable) Swap(i, j int) {
378+
elemI, err := s.s.l.M__getitem__(Int(i))
379+
if err != nil {
380+
if s.s.firstErr == nil {
381+
s.s.firstErr = err
382+
}
383+
return
384+
}
385+
elemJ, err := s.s.l.M__getitem__(Int(j))
386+
if err != nil {
387+
if s.s.firstErr == nil {
388+
s.s.firstErr = err
389+
}
390+
return
391+
}
392+
_, err = s.s.l.M__setitem__(Int(i), elemJ)
393+
if err != nil {
394+
if s.s.firstErr == nil {
395+
s.s.firstErr = err
396+
}
397+
}
398+
_, err = s.s.l.M__setitem__(Int(j), elemI)
399+
if err != nil {
400+
if s.s.firstErr == nil {
401+
s.s.firstErr = err
402+
}
403+
}
404+
}
405+
406+
func (s ptrSortable) Less(i, j int) bool {
407+
elemI, err := s.s.l.M__getitem__(Int(i))
408+
if err != nil {
409+
if s.s.firstErr == nil {
410+
s.s.firstErr = err
411+
}
412+
return false
413+
}
414+
elemJ, err := s.s.l.M__getitem__(Int(j))
415+
if err != nil {
416+
if s.s.firstErr == nil {
417+
s.s.firstErr = err
418+
}
419+
return false
420+
}
421+
422+
if s.s.keyFunc != None {
423+
elemI, err = Call(s.s.keyFunc, Tuple{elemI}, nil)
424+
if err != nil {
425+
if s.s.firstErr == nil {
426+
s.s.firstErr = err
427+
}
428+
}
429+
elemJ, err = Call(s.s.keyFunc, Tuple{elemJ}, nil)
430+
if err != nil {
431+
if s.s.firstErr == nil {
432+
s.s.firstErr = err
433+
}
434+
}
435+
}
436+
437+
var cmpResult Object
438+
if s.s.reverse {
439+
cmpResult, err = Lt(elemJ, elemI)
440+
} else {
441+
cmpResult, err = Lt(elemI, elemJ)
442+
}
443+
444+
if err != nil {
445+
if s.s.firstErr == nil {
446+
s.s.firstErr = err
447+
}
448+
}
449+
450+
if boolResult, ok := cmpResult.(Bool); ok {
451+
return bool(boolResult)
452+
}
453+
454+
return false
455+
}
456+
457+
func SortInPlace(l *List, keyFunc Object, reverse Object) error {
458+
switch keyFunc.(type) {
459+
case NoneType, I__call__:
460+
default:
461+
return ExceptionNewf(TypeError, "'%s' object is not callable", keyFunc.Type().Name)
462+
}
463+
s := ptrSortable{&sortable{l, keyFunc, ObjectIsTrue(reverse), nil}}
464+
sort.Stable(s)
465+
return s.s.firstErr
466+
}

0 commit comments

Comments
 (0)