From 88c8e194d0bc809a778cd111fd7eafef998fcf37 Mon Sep 17 00:00:00 2001 From: Ruofan XU <47302112+SleepyRoy@users.noreply.github.com> Date: Tue, 21 Jul 2020 00:53:02 +0800 Subject: [PATCH] cgen: fix map and array with fns (#5894) --- vlib/v/gen/cgen.v | 102 ++++++++++++++++++--- vlib/v/tests/array_init_test.v | 19 ---- vlib/v/tests/map_and_array_with_fns_test.v | 45 +++++++++ 3 files changed, 133 insertions(+), 33 deletions(-) create mode 100644 vlib/v/tests/map_and_array_with_fns_test.v diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 1b16567fff..4945392907 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1207,7 +1207,25 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { if sym.kind == .array { info := sym.info as table.Array styp := g.typ(info.elem_type) - g.write('$styp _var_$left.pos.pos = *($styp*)array_get(') + elem_typ := g.table.get_type_symbol(info.elem_type) + if elem_typ.kind == .function { + var_type := assign_stmt.left_types[i] + left_sym := g.table.get_type_symbol(var_type) + func := left_sym.info as table.FnType + ret_styp := g.typ(func.func.return_type) + g.write('$ret_styp (*_var_$left.pos.pos) (') + arg_len := func.func.args.len + for j, arg in func.func.args { + arg_type := g.table.get_type_symbol(arg.typ) + g.write('$arg_type.str() $arg.name') + if j < arg_len - 1 { + g.write(', ') + } + } + g.write(') = *(voidptr*)array_get(') + } else { + g.write('$styp _var_$left.pos.pos = *($styp*)array_get(') + } if left.left_type.is_ptr() { g.write('*') } @@ -1219,14 +1237,36 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { info := sym.info as table.Map styp := g.typ(info.value_type) zero := g.type_default(info.value_type) - g.write('$styp _var_$left.pos.pos = *($styp*)map_get(') + value_typ := g.table.get_type_symbol(info.value_type) + if value_typ.kind == .function { + var_type := assign_stmt.left_types[i] + left_sym := g.table.get_type_symbol(var_type) + func := left_sym.info as table.FnType + ret_styp := g.typ(func.func.return_type) + g.write('$ret_styp (*_var_$left.pos.pos) (') + arg_len := func.func.args.len + for j, arg in func.func.args { + arg_type := g.table.get_type_symbol(arg.typ) + g.write('$arg_type.str() $arg.name') + if j < arg_len - 1 { + g.write(', ') + } + } + g.write(') = *(voidptr*)map_get(') + } else { + g.write('$styp _var_$left.pos.pos = *($styp*)map_get(') + } if left.left_type.is_ptr() { g.write('*') } g.expr(left.left) g.write(', ') g.expr(left.index) - g.writeln(', &($styp[]){ $zero });') + if value_typ.kind == .function { + g.writeln(', &(voidptr[]){ $zero });') + } else { + g.writeln(', &($styp[]){ $zero });') + } } } ast.SelectorExpr { @@ -1738,14 +1778,23 @@ fn (mut g Gen) expr(node ast.Expr) { ast.MapInit { key_typ_str := g.typ(node.key_type) value_typ_str := g.typ(node.value_type) + value_typ := g.table.get_type_symbol(node.value_type) size := node.vals.len if size > 0 { - g.write('new_map_init($size, sizeof($value_typ_str), _MOV(($key_typ_str[$size]){') + if value_typ.kind == .function { + g.write('new_map_init($size, sizeof(voidptr), _MOV(($key_typ_str[$size]){') + } else { + g.write('new_map_init($size, sizeof($value_typ_str), _MOV(($key_typ_str[$size]){') + } for expr in node.keys { g.expr(expr) g.write(', ') } - g.write('}), _MOV(($value_typ_str[$size]){') + if value_typ.kind == .function { + g.write('}), _MOV((voidptr[$size]){') + } else { + g.write('}), _MOV(($value_typ_str[$size]){') + } for expr in node.vals { g.expr(expr) g.write(', ') @@ -2053,8 +2102,12 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { } else {} } - styp := g.typ(g.table.mktyp(left_type)) - g.write('_IN($styp, ') + if left_sym.kind == .function { + g.write('_IN(u64, ') + } else { + styp := g.typ(g.table.mktyp(left_type)) + g.write('_IN($styp, ') + } g.expr(node.left) g.write(', ') if node.right_type.is_ptr() { @@ -2499,6 +2552,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { } else if sym.kind == .array { info := sym.info as table.Array elem_type_str := g.typ(info.elem_type) + elem_typ := g.table.get_type_symbol(info.elem_type) // `vals[i].field = x` is an exception and requires `array_get`: // `(*(Val*)array_get(vals, i)).field = x;` is_selector := node.left is ast.SelectorExpr @@ -2530,7 +2584,11 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { } */ if need_wrapper { - g.write(', &($elem_type_str[]) { ') + if elem_typ.kind == .function { + g.write(', &(voidptr[]) { ') + } else { + g.write(', &($elem_type_str[]) { ') + } } else { g.write(', &') } @@ -2570,7 +2628,11 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { g.write(op) } } else { - g.write('(*($elem_type_str*)array_get(') + if elem_typ.kind == .function { + g.write('(*(voidptr*)array_get(') + } else { + g.write('(*($elem_type_str*)array_get(') + } if left_is_ptr && !node.left_type.has_flag(.shared_f) { g.write('*') } @@ -2589,6 +2651,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { } else if sym.kind == .map { info := sym.info as table.Map elem_type_str := g.typ(info.value_type) + elem_typ := g.table.get_type_symbol(info.value_type) if g.is_assign_lhs && !g.is_array_set { g.is_array_set = true g.write('map_set(') @@ -2598,7 +2661,11 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { g.expr(node.left) g.write(', ') g.expr(node.index) - g.write(', &($elem_type_str[]) { ') + if elem_typ.kind == .function { + g.write(', &(voidptr[]) { ') + } else { + g.write(', &($elem_type_str[]) { ') + } } else if g.inside_map_postfix || g.inside_map_infix { zero := g.type_default(info.value_type) g.write('(*($elem_type_str*)map_get_and_set(') @@ -2611,14 +2678,22 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { g.write(', &($elem_type_str[]){ $zero }))') } else { zero := g.type_default(info.value_type) - g.write('(*($elem_type_str*)map_get(') + if elem_typ.kind == .function { + g.write('(*(voidptr*)map_get(') + } else { + g.write('(*($elem_type_str*)map_get(') + } if node.left_type.is_ptr() { g.write('*') } g.expr(node.left) g.write(', ') g.expr(node.index) - g.write(', &($elem_type_str[]){ $zero }))') + if elem_typ.kind == .function { + g.write(', &(voidptr[]){ $zero }))') + } else { + g.write(', &($elem_type_str[]){ $zero }))') + } } } else if sym.kind == .string && !node.left_type.is_ptr() { g.write('string_at(') @@ -4793,8 +4868,7 @@ fn (mut g Gen) array_init(it ast.ArrayInit) { elem_sym := g.table.get_type_symbol(it.elem_type) if elem_sym.kind == .function { g.write('new_array_from_c_array($len, $len, sizeof(voidptr), _MOV((voidptr[$len]){') - } - else { + } else { g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), _MOV(($elem_type_str[$len]){') } if len > 8 { diff --git a/vlib/v/tests/array_init_test.v b/vlib/v/tests/array_init_test.v index 26ea170623..eebe939c87 100644 --- a/vlib/v/tests/array_init_test.v +++ b/vlib/v/tests/array_init_test.v @@ -194,22 +194,3 @@ fn test_array_init_direct_call() { assert []int{len: 2, init: 0}.len == 2 assert []int{len: 3, init: 1}.map(it*2) == [2,2,2] } - - -fn foo(a string) int { - return 10 + a.len -} - -fn foo2(a string) int { - return 20 + a.len -} - -type FnFoo fn(a string) int -fn test_array_of_fns_init() { - a := [FnFoo(foo), foo2] - assert a.len == 2 - f0 := a[0] - assert f0('xx') == 12 - f1 := a[1] - assert f1('yyy') == 23 -} diff --git a/vlib/v/tests/map_and_array_with_fns_test.v b/vlib/v/tests/map_and_array_with_fns_test.v new file mode 100644 index 0000000000..98640a435c --- /dev/null +++ b/vlib/v/tests/map_and_array_with_fns_test.v @@ -0,0 +1,45 @@ +fn foo(a string) int { + return 10 + a.len +} + +fn foo2(a string) int { + return 20 + a.len +} + +fn test_array_with_fns() { + mut a := [foo, foo2] + assert a.len == 2 + assert (foo in a) == true + f0 := a[0] + assert f0('xx') == 12 + f1 := a[1] + assert f1('yyy') == 23 + a[0], a[1] = a[1], a[0] + f2 := a[0] + assert f2('zzzz') == 24 + f3 := a[1] + assert f3('aaaaa') == 15 + mut b := [foo] + assert (foo2 !in b) == true + b[0] = a[0] + f4 := b[0] + assert f4('bbbbbb') == 26 +} + +fn test_map_with_fns() { + mut a := {'one':foo, 'two':foo2} + assert a.len == 2 + f0 := a['one'] + assert f0('xx') == 12 + f1 := a['two'] + assert f1('yyy') == 23 + a['one'], a['two'] = a['two'], a['one'] + f2 := a['one'] + assert f2('zzzz') == 24 + f3 := a['two'] + assert f3('aaaaa') == 15 + mut b := {'one':foo} + b['one'] = a['one'] + f4 := b['one'] + assert f4('bbbbbb') == 26 +}