From 7027b2354b350cd8ac2359b39f144aecfb67fd7a Mon Sep 17 00:00:00 2001 From: Ruofan XU <47302112+SleepyRoy@users.noreply.github.com> Date: Sun, 26 Jul 2020 20:22:02 +0800 Subject: [PATCH] cgen: fix array and map with fns (#5938) --- vlib/v/gen/cgen.v | 56 +++++++++++++++------- vlib/v/tests/map_and_array_with_fns_test.v | 40 +++++++++------- 2 files changed, 63 insertions(+), 33 deletions(-) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index ae647abaad..63e0129ed6 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1166,8 +1166,8 @@ fn (mut g Gen) write_fn_ptr_decl(func &table.FnType, ptr_name string) { g.write('$ret_styp (*$ptr_name) (') arg_len := func.func.args.len for i, arg in func.func.args { - arg_typ := g.table.get_type_symbol(arg.typ) - g.write('$arg_typ.str() $arg.name') + arg_styp := g.typ(arg.typ) + g.write('$arg_styp $arg.name') if i < arg_len - 1 { g.write(', ') } @@ -2165,13 +2165,17 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { } else { // push a single element elem_type_str := g.typ(info.elem_type) + elem_sym := g.table.get_type_symbol(info.elem_type) g.write('array_push(') if !left_type.is_ptr() { g.write('&') } g.expr(node.left) - g.write(', _MOV(($elem_type_str[]){ ') - elem_sym := g.table.get_type_symbol(info.elem_type) + if elem_sym.kind == .function { + g.write(', _MOV((voidptr[]){ ') + } else { + g.write(', _MOV(($elem_type_str[]){ ') + } if elem_sym.kind == .interface_ && node.right_type != info.elem_type { g.interface_call(node.right_type, info.elem_type) } @@ -3226,14 +3230,13 @@ fn (mut g Gen) gen_array_equality_fn(left table.Type) string { g.definitions.writeln('\t\treturn false;') g.definitions.writeln('\t}') g.definitions.writeln('\tfor (int i = 0; i < a.len; ++i) {') - if elem_sym.kind == .string { - g.definitions.writeln('\t\tif (string_ne(*(($ptr_typ*)((byte*)a.data+(i*a.element_size))), *(($ptr_typ*)((byte*)b.data+(i*b.element_size))))) {') - } else if elem_sym.kind == .struct_ { - g.definitions.writeln('\t\tif (memcmp((byte*)a.data+(i*a.element_size), (byte*)b.data+(i*b.element_size), a.element_size)) {') - } else if elem_sym.kind == .array { - g.definitions.writeln('\t\tif (!${ptr_elem_typ}_arr_eq((($elem_typ*)a.data)[i], (($elem_typ*)b.data)[i])) {') - } else { - g.definitions.writeln('\t\tif (*(($ptr_typ*)((byte*)a.data+(i*a.element_size))) != *(($ptr_typ*)((byte*)b.data+(i*b.element_size)))) {') + // compare every pair of elements of the two arrays + match elem_sym.kind { + .string { g.definitions.writeln('\t\tif (string_ne(*(($ptr_typ*)((byte*)a.data+(i*a.element_size))), *(($ptr_typ*)((byte*)b.data+(i*b.element_size))))) {') } + .struct_ { g.definitions.writeln('\t\tif (memcmp((byte*)a.data+(i*a.element_size), (byte*)b.data+(i*b.element_size), a.element_size)) {') } + .array { g.definitions.writeln('\t\tif (!${ptr_elem_typ}_arr_eq((($elem_typ*)a.data)[i], (($elem_typ*)b.data)[i])) {') } + .function { g.definitions.writeln('\t\tif (*((voidptr*)((byte*)a.data+(i*a.element_size))) != *((voidptr*)((byte*)b.data+(i*b.element_size)))) {') } + else { g.definitions.writeln('\t\tif (*(($ptr_typ*)((byte*)a.data+(i*a.element_size))) != *(($ptr_typ*)((byte*)b.data+(i*b.element_size)))) {') } } g.definitions.writeln('\t\t\treturn false;') g.definitions.writeln('\t\t}') @@ -3264,11 +3267,26 @@ fn (mut g Gen) gen_map_equality_fn(left table.Type) string { g.definitions.writeln('\tarray_string _keys = map_keys(&a);') g.definitions.writeln('\tfor (int i = 0; i < _keys.len; ++i) {') g.definitions.writeln('\t\tstring k = string_clone( ((string*)_keys.data)[i]);') - g.definitions.writeln('\t\t$value_typ v = (*($value_typ*)map_get(a, k, &($value_typ[]){ 0 }));') - if value_sym.kind == .string { - g.definitions.writeln('\t\tif (!map_exists(b, k) || string_ne((*($value_typ*)map_get(b, k, &($value_typ[]){tos_lit("")})), v)) {') + if value_sym.kind == .function { + func := value_sym.info as table.FnType + ret_styp := g.typ(func.func.return_type) + g.definitions.write('\t\t$ret_styp (*v) (') + arg_len := func.func.args.len + for i, arg in func.func.args { + arg_styp := g.typ(arg.typ) + g.definitions.write('$arg_styp $arg.name') + if i < arg_len - 1 { + g.definitions.write(', ') + } + } + g.definitions.writeln(') = (*(voidptr*)map_get(a, k, &(voidptr[]){ 0 }));') } else { - g.definitions.writeln('\t\tif (!map_exists(b, k) || (*($value_typ*)map_get(b, k, &($value_typ[]){ 0 })) != v) {') + g.definitions.writeln('\t\t$value_typ v = (*($value_typ*)map_get(a, k, &($value_typ[]){ 0 }));') + } + match value_sym.kind { + .string { g.definitions.writeln('\t\tif (!map_exists(b, k) || string_ne((*($value_typ*)map_get(b, k, &($value_typ[]){tos_lit("")})), v)) {') } + .function { g.definitions.writeln('\t\tif (!map_exists(b, k) || (*(voidptr*)map_get(b, k, &(voidptr[]){ 0 })) != v) {') } + else { g.definitions.writeln('\t\tif (!map_exists(b, k) || (*($value_typ*)map_get(b, k, &($value_typ[]){ 0 })) != v) {') } } g.definitions.writeln('\t\t\treturn false;') g.definitions.writeln('\t\t}') @@ -4877,7 +4895,11 @@ fn (mut g Gen) array_init(it ast.ArrayInit) { } else { g.write('0, ') } - g.write('sizeof($elem_type_str), ') + if elem_sym.kind == .function { + g.write('sizeof(voidptr), ') + } else { + g.write('sizeof($elem_type_str), ') + } if is_default_array { g.write('($elem_type_str[]){') g.expr(it.default_expr) diff --git a/vlib/v/tests/map_and_array_with_fns_test.v b/vlib/v/tests/map_and_array_with_fns_test.v index 5eac3c9d3b..0d9c123070 100644 --- a/vlib/v/tests/map_and_array_with_fns_test.v +++ b/vlib/v/tests/map_and_array_with_fns_test.v @@ -1,51 +1,59 @@ -fn foo(a string) int { - return 10 + a.len +fn foo(a, b string) int { + return 10 + a.len + b.len } -fn foo2(a string) int { - return 20 + a.len +fn foo2(a, b string) int { + return 20 + a.len + b.len } fn test_array_with_fns() { mut a := [foo, foo2] assert a.len == 2 + assert (a != [foo, foo2]) == false assert (foo in a) == true f0 := a[0] - assert f0('xx') == 12 + assert f0('xx', '') == 12 f1 := a[1] - assert f1('yyy') == 23 + assert f1('yyy', '') == 23 a[0], a[1] = a[1], a[0] f2 := a[0] - assert f2('zzzz') == 24 + assert f2('zzzz', '') == 24 f3 := a[1] - assert f3('aaaaa') == 15 + assert f3('aaaaa', '') == 15 mut b := [foo] assert (foo2 !in b) == true b[0] = a[0] f4 := b[0] - assert f4('bbbbbb') == 26 + assert f4('bbbbbb', '') == 26 for func in b { - assert func('ccccccc') == 27 + assert func('ccccccc', '') == 27 } + b = [] + b << foo + b << [foo2] + assert (b == [foo, foo2]) == true + f5 := b[0] + assert f5('dddddddd', '') == 18 } fn test_map_with_fns() { mut a := {'one':foo, 'two':foo2} assert a.len == 2 + assert (a == {'one':foo, 'two':foo2}) == true f0 := a['one'] - assert f0('xx') == 12 + assert f0('xx', '') == 12 f1 := a['two'] - assert f1('yyy') == 23 + assert f1('yyy', '') == 23 a['one'], a['two'] = a['two'], a['one'] f2 := a['one'] - assert f2('zzzz') == 24 + assert f2('zzzz', '') == 24 f3 := a['two'] - assert f3('aaaaa') == 15 + assert f3('aaaaa', '') == 15 mut b := {'one':foo} b['one'] = a['one'] f4 := b['one'] - assert f4('bbbbbb') == 26 + assert f4('bbbbbb', '') == 26 for _, func in b { - assert func('ccccccc') == 27 + assert func('ccccccc', '') == 27 } }