sort: handle `.sort(a.field > b.field)`

pull/6115/head
Alexander Medvednikov 2020-08-12 06:11:40 +02:00
parent 4bc0dde413
commit e5e31f7210
7 changed files with 55 additions and 14 deletions

View File

@ -539,6 +539,16 @@ fn compare_ints(a, b &int) int {
return 0
}
fn compare_ints_reverse(a, b &int) int {
if *a > *b {
return -1
}
if *a < *b {
return 1
}
return 0
}
fn compare_floats(a, b &f64) int {
if *a < *b {
return -1
@ -549,6 +559,16 @@ fn compare_floats(a, b &f64) int {
return 0
}
fn compare_floats_reverse(a, b &f64) int {
if *a > *b {
return -1
}
if *a < *b {
return 1
}
return 0
}
// []int.sort sorts array of int in place in ascending order.
pub fn (mut a []int) sort() {
a.sort_with_compare(compare_ints)

View File

@ -695,6 +695,11 @@ fn test_eq() {
*/
}
struct User {
age int
name string
}
fn test_sort() {
mut a := ['hi', '1', '5', '3']
a.sort()
@ -717,6 +722,20 @@ fn test_sort() {
assert nums[2] == 42
assert nums[3] == 67
assert nums[4] == 108
//
mut users := [User{22, 'Peter'}, User{20, 'Bob'}, User{25, 'Alice'}]
users.sort(a.age < b.age)
assert(users[0].age == 20)
assert(users[1].age == 22)
assert(users[2].age == 25)
assert(users[0].name == 'Bob')
assert(users[1].name == 'Peter')
assert(users[2].name == 'Alice')
//
users.sort(a.age > b.age)
assert(users[0].age == 25)
assert(users[1].age == 22)
assert(users[2].age == 20)
}
fn test_f32_sort() {

View File

@ -109,10 +109,10 @@ pub fn (mut cmd Command) parse(args []string) {
}
cmd.add_default_commands()
if cmd.sort_flags {
cmd.flags.sort()
cmd.flags.sort(a.name < b.name)
}
if cmd.sort_commands {
cmd.commands.sort()
cmd.commands.sort(a.name < b.name)
}
cmd.args = args[1..]
for i in 0 .. cmd.commands.len {
@ -286,8 +286,3 @@ fn (cmds []Command) contains(name string) bool {
return false
}
fn (mut cmds []Command) sort() {
cmds.sort_with_compare(fn (a, b &Command) int {
return compare_strings(&a.name, &b.name)
})
}

View File

@ -183,8 +183,3 @@ fn (flags []Flag) contains(name string) bool {
return false
}
fn (mut flags []Flag) sort() {
flags.sort_with_compare(fn (a, b &Flag) int {
return compare_strings(&a.name, &b.name)
})
}

View File

@ -859,6 +859,13 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
} else if is_sort {
scope.update_var_type('a', array_info.elem_type)
scope.update_var_type('b', array_info.elem_type)
// Verify `.sort(a < b)`
if call_expr.args.len > 0 {
if call_expr.args[0].expr !is ast.InfixExpr {
c.error('`.sort()` requires a `<` or `>` comparison as the first and only argument' +
'\ne.g. `users.sort(a.id < b.id)`', call_expr.pos)
}
}
}
elem_typ = array_info.elem_type
}

View File

@ -3750,12 +3750,14 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
// No arguments means we are sorting an array of builtins (e.g. `numbers.sort()`)
// The type for the comparison fns is the type of the element itself.
mut typ := info.elem_type
mut is_reverse := false
// `users.sort(a.age > b.age)`
if node.args.len > 0 {
// Get the type of the field that's being compared
// `a.age > b.age` => `age int` => int
infix_expr := node.args[0].expr as ast.InfixExpr
typ = infix_expr.left_type
is_reverse = infix_expr.op == .gt
}
mut compare_fn := match typ {
table.int_type {
@ -3770,12 +3772,15 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
else {
q := g.table.get_type_symbol(typ)
if node.args.len == 0 {
verror('usage: .sort(a.field < b.field)')
verror('usage: .sort(a.field < b.field) $q.name')
}
verror('sort(): unhandled type $typ $q.name')
''
}
}
if is_reverse {
compare_fn += '_reverse'
}
//
g.write('qsort(')
g.expr(node.left)