cgen: implement equality on arrays

pull/4310/head
krischerven 2020-04-08 21:55:37 -04:00 committed by GitHub
parent 71190c27a9
commit 8f8f8c418e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 3 deletions

View File

@ -55,6 +55,7 @@ mut:
defer_ifdef string
str_types []string // types that need automatic str() generation
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
array_fn_definitions []string // array equality functions that have been defined
}
const (
@ -1300,7 +1301,6 @@ fn (g mut Gen) assign_expr(node ast.AssignExpr) {
}
fn (g mut Gen) infix_expr(node ast.InfixExpr) {
left_sym := g.table.get_type_symbol(node.left_type)
// println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr')
// g.write('/*infix*/')
// if it.left_type == table.string_type_idx {
@ -1308,6 +1308,8 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) {
// }
// string + string, string == string etc
// g.infix_op = node.op
left_sym := g.table.get_type_symbol(node.left_type)
right_sym := g.table.get_type_symbol(node.right_type)
if node.left_type == table.string_type_idx && node.op != .key_in {
fn_name := match node.op {
.plus {
@ -1340,8 +1342,23 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) {
g.write(', ')
g.expr(node.right)
g.write(')')
} else if node.op in [.eq, .ne] && left_sym.kind == .array && right_sym.kind == .array {
styp := g.table.value_type(node.left_type)
ptr_typ := g.typ(node.left_type).split('_')[1]
if !(ptr_typ in g.array_fn_definitions) {
sym := g.table.get_type_symbol(left_sym.array_info().elem_type)
g.generate_array_equality_fn(ptr_typ, styp, sym)
}
if node.op == .eq {
g.write('${ptr_typ}_arr_eq(')
} else if node.op == .ne {
g.write('!${ptr_typ}_arr_eq(')
}
g.expr(node.left)
g.write(', ')
g.expr(node.right)
g.write(')')
} else if node.op == .key_in {
right_sym := g.table.get_type_symbol(node.right_type)
if right_sym.kind == .array {
match node.right {
ast.ArrayInit {
@ -1379,7 +1396,6 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) {
tmp := g.new_tmp_var()
sym := g.table.get_type_symbol(node.left_type)
info := sym.info as table.Array
right_sym := g.table.get_type_symbol(node.right_type)
if right_sym.kind == .array && info.elem_type != node.right_type {
// push an array => PUSH_MANY, but not if pushing an array to 2d array (`[][]int << []int`)
g.write('_PUSH_MANY(&')
@ -2038,6 +2054,27 @@ fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
}
}
fn (g mut Gen) generate_array_equality_fn(ptr_typ string, styp table.Type, sym &table.TypeSymbol) {
g.array_fn_definitions << ptr_typ
g.definitions.writeln('bool ${ptr_typ}_arr_eq(array_${ptr_typ} a, array_${ptr_typ} b) {')
g.definitions.writeln('\tif (a.len != b.len) {')
g.definitions.writeln('\t\treturn false;')
g.definitions.writeln('\t}')
g.definitions.writeln('\tfor (int i = 0; i < a.len; i++) {')
if styp == table.string_type_idx {
g.definitions.writeln('\t\tif (string_ne(*((${ptr_typ}*)(a.data+(i*a.element_size))), *((${ptr_typ}*)(b.data+(i*b.element_size))))) {')
} else if sym.kind == .struct_ {
g.definitions.writeln('\t\tif (memcmp((void*)(a.data+(i*a.element_size)), (void*)(b.data+(i*b.element_size)), a.element_size)) {')
} else {
g.definitions.writeln('\t\tif (*((${ptr_typ}*)(a.data+(i*a.element_size))) != *((${ptr_typ}*)(b.data+(i*b.element_size)))) {')
}
g.definitions.writeln('\t\t\treturn false;')
g.definitions.writeln('\t\t}')
g.definitions.writeln('\t}')
g.definitions.writeln('\treturn true;')
g.definitions.writeln('}')
}
[inline]
fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs

View File

@ -0,0 +1,46 @@
struct Tester {
b bool
i int
}
enum Color {
red green blue
}
fn test_array_equality() {
strs := ["a", "b", "c"]
assert strs == ["a", "b", "c"]
assert strs != ["a", "c", "b"]
assert strs != ["b", "c", "a"]
assert strs != ["b", "a", "c"]
assert strs != ["c", "b", "a"]
assert strs != ["c", "a", "b"]
bools := [true, true, false]
assert bools == [true, true, false]
assert bools != [true, false, false]
assert bools != [false, true, true]
assert bools != [false, false, true]
assert bools != [false, false, false]
assert bools != [false, true, false]
ints := [1, 2, 3]
assert ints == [1, 2, 3]
assert ints != [1, 3, 2]
assert ints != [2, 3, 1]
assert ints != [2, 1, 3]
assert ints != [3, 2, 1]
assert ints != [3, 1, 2]
a := Tester{true, 100}
b := Tester{false, 200}
testers := [a, b]
assert testers == [a, b]
assert testers != [a, a]
assert testers != [b, b]
assert testers != [b, a]
colors := [Color.red, Color.green, Color.blue]
assert colors == [Color.red, Color.green, Color.blue]
assert colors != [Color.red, Color.blue, Color.green]
assert colors != [Color.green, Color.blue, Color.red]
assert colors != [Color.green, Color.red, Color.blue]
assert colors != [Color.blue, Color.green, Color.red]
assert colors != [Color.blue, Color.red, Color.green]
}