cgen: fix rune array sort (#9561)
parent
9ba8d02a5a
commit
3637bac716
|
@ -807,6 +807,21 @@ fn test_sort() {
|
||||||
// assert users.map(it.name).join(' ') == 'Alice Bob Peter'
|
// assert users.map(it.name).join(' ') == 'Alice Bob Peter'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_rune_sort() {
|
||||||
|
mut bs := [`f`, `e`, `d`, `b`, `c`, `a`]
|
||||||
|
bs.sort()
|
||||||
|
println(bs)
|
||||||
|
assert '$bs' == '[`a`, `b`, `c`, `d`, `e`, `f`]'
|
||||||
|
|
||||||
|
bs.sort(a > b)
|
||||||
|
println(bs)
|
||||||
|
assert '$bs' == '[`f`, `e`, `d`, `c`, `b`, `a`]'
|
||||||
|
|
||||||
|
bs.sort(a < b)
|
||||||
|
println(bs)
|
||||||
|
assert '$bs' == '[`a`, `b`, `c`, `d`, `e`, `f`]'
|
||||||
|
}
|
||||||
|
|
||||||
fn test_sort_by_different_order_of_a_b() {
|
fn test_sort_by_different_order_of_a_b() {
|
||||||
mut x := [1, 2, 3]
|
mut x := [1, 2, 3]
|
||||||
x.sort(a < b)
|
x.sort(a < b)
|
||||||
|
|
|
@ -248,46 +248,62 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
// Register a new custom `compare_xxx` function for qsort()
|
// Register a new custom `compare_xxx` function for qsort()
|
||||||
g.table.register_fn(name: compare_fn, return_type: ast.int_type)
|
g.table.register_fn(name: compare_fn, return_type: ast.int_type)
|
||||||
infix_expr := node.args[0].expr as ast.InfixExpr
|
|
||||||
// Variables `a` and `b` are used in the `.sort(a < b)` syntax, so we can reuse them
|
if node.args.len == 0 {
|
||||||
// when generating the function as long as the args are named the same.
|
styp_arg := g.typ(typ)
|
||||||
styp_arg := g.typ(typ)
|
g.definitions.writeln('int $compare_fn ($styp_arg* a, $styp_arg* b) {')
|
||||||
g.definitions.writeln('int $compare_fn ($styp_arg* a, $styp_arg* b) {')
|
sym := g.table.get_type_symbol(typ)
|
||||||
sym := g.table.get_type_symbol(typ)
|
if !is_reverse && sym.has_method('<') {
|
||||||
if !is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 {
|
g.definitions.writeln('\tif (${styp}__lt(*a, *b)) { return -1; } else { return 1; }}')
|
||||||
g.definitions.writeln('\tif (${styp}__lt(*a, *b)) { return -1; } else { return 1; }}')
|
} else if is_reverse && sym.has_method('<') {
|
||||||
} else if is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 {
|
g.definitions.writeln('\tif (${styp}__lt(*b, *a)) { return -1; } else { return 1; }}')
|
||||||
g.definitions.writeln('\tif (${styp}__lt(*b, *a)) { return -1; } else { return 1; }}')
|
|
||||||
} else {
|
|
||||||
field_type := g.typ(infix_expr.left_type)
|
|
||||||
mut left_expr_str := g.write_expr_to_string(infix_expr.left)
|
|
||||||
mut right_expr_str := g.write_expr_to_string(infix_expr.right)
|
|
||||||
if typ.is_ptr() {
|
|
||||||
left_expr_str = left_expr_str.replace_once('a', '(*a)')
|
|
||||||
right_expr_str = right_expr_str.replace_once('b', '(*b)')
|
|
||||||
}
|
|
||||||
g.definitions.writeln('$field_type a_ = $left_expr_str;')
|
|
||||||
g.definitions.writeln('$field_type b_ = $right_expr_str;')
|
|
||||||
mut op1, mut op2 := '', ''
|
|
||||||
if infix_expr.left_type == ast.string_type {
|
|
||||||
if is_reverse {
|
|
||||||
op1 = 'string_gt(a_, b_)'
|
|
||||||
op2 = 'string_lt(a_, b_)'
|
|
||||||
} else {
|
|
||||||
op1 = 'string_lt(a_, b_)'
|
|
||||||
op2 = 'string_gt(a_, b_)'
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if is_reverse {
|
g.definitions.writeln('if (*a < *b) return -1;')
|
||||||
op1 = 'a_ > b_'
|
g.definitions.writeln('if (*a > *b) return 1; return 0; }\n')
|
||||||
op2 = 'a_ < b_'
|
}
|
||||||
} else {
|
} else {
|
||||||
op1 = 'a_ < b_'
|
infix_expr := node.args[0].expr as ast.InfixExpr
|
||||||
op2 = 'a_ > b_'
|
// Variables `a` and `b` are used in the `.sort(a < b)` syntax, so we can reuse them
|
||||||
}
|
// when generating the function as long as the args are named the same.
|
||||||
|
styp_arg := g.typ(typ)
|
||||||
|
g.definitions.writeln('int $compare_fn ($styp_arg* a, $styp_arg* b) {')
|
||||||
|
sym := g.table.get_type_symbol(typ)
|
||||||
|
if !is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 {
|
||||||
|
g.definitions.writeln('\tif (${styp}__lt(*a, *b)) { return -1; } else { return 1; }}')
|
||||||
|
} else if is_reverse && sym.has_method('<') && infix_expr.left.str().len == 1 {
|
||||||
|
g.definitions.writeln('\tif (${styp}__lt(*b, *a)) { return -1; } else { return 1; }}')
|
||||||
|
} else {
|
||||||
|
field_type := g.typ(infix_expr.left_type)
|
||||||
|
mut left_expr_str := g.write_expr_to_string(infix_expr.left)
|
||||||
|
mut right_expr_str := g.write_expr_to_string(infix_expr.right)
|
||||||
|
if typ.is_ptr() {
|
||||||
|
left_expr_str = left_expr_str.replace_once('a', '(*a)')
|
||||||
|
right_expr_str = right_expr_str.replace_once('b', '(*b)')
|
||||||
|
}
|
||||||
|
g.definitions.writeln('$field_type a_ = $left_expr_str;')
|
||||||
|
g.definitions.writeln('$field_type b_ = $right_expr_str;')
|
||||||
|
mut op1, mut op2 := '', ''
|
||||||
|
if infix_expr.left_type == ast.string_type {
|
||||||
|
if is_reverse {
|
||||||
|
op1 = 'string_gt(a_, b_)'
|
||||||
|
op2 = 'string_lt(a_, b_)'
|
||||||
|
} else {
|
||||||
|
op1 = 'string_lt(a_, b_)'
|
||||||
|
op2 = 'string_gt(a_, b_)'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deref_str := if infix_expr.left_type.is_ptr() { '*' } else { '' }
|
||||||
|
if is_reverse {
|
||||||
|
op1 = '${deref_str}a_ > ${deref_str}b_'
|
||||||
|
op2 = '${deref_str}a_ < ${deref_str}b_'
|
||||||
|
} else {
|
||||||
|
op1 = '${deref_str}a_ < ${deref_str}b_'
|
||||||
|
op2 = '${deref_str}a_ > ${deref_str}b_'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.definitions.writeln('if ($op1) return -1;')
|
||||||
|
g.definitions.writeln('if ($op2) return 1; return 0; }\n')
|
||||||
}
|
}
|
||||||
g.definitions.writeln('if ($op1) return -1;')
|
|
||||||
g.definitions.writeln('if ($op2) return 1; return 0; }\n')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_reverse && !compare_fn.ends_with('_reverse') {
|
if is_reverse && !compare_fn.ends_with('_reverse') {
|
||||||
|
|
Loading…
Reference in New Issue