diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index 3fddec3870..c26e0a0c06 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -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) diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index f0cd2d061f..6e57e097e3 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -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() { diff --git a/vlib/cli/command.v b/vlib/cli/command.v index 29f4704afe..c78481beac 100644 --- a/vlib/cli/command.v +++ b/vlib/cli/command.v @@ -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) - }) -} diff --git a/vlib/cli/command_test.v b/vlib/cli/command_test.v index d1ed0c18bd..1bd2014752 100644 --- a/vlib/cli/command_test.v +++ b/vlib/cli/command_test.v @@ -56,7 +56,7 @@ fn flag_should_be_set(cmd cli.Command) ? { flag := cmd.flags.get_string('flag')? assert flag == 'value' } - + fn test_if_flag_gets_set() { mut cmd := cli.Command{ name: 'command' diff --git a/vlib/cli/flag.v b/vlib/cli/flag.v index 3fc0fd0d36..4c79227e9a 100644 --- a/vlib/cli/flag.v +++ b/vlib/cli/flag.v @@ -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) - }) -} diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 44630db8d8..272877ce68 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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 } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 3e30ed29e5..4173a40c9f 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -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)