From 8ab59c5f0fbc95590318aa090eda80e7866455de Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 15 Dec 2020 11:24:57 +0800 Subject: [PATCH] parser: implement a direct call to an array of functions (fix #6908) (#7322) --- vlib/v/checker/checker.v | 14 ++++++++++++++ vlib/v/gen/cgen.v | 16 +++++++++++++++- vlib/v/gen/fn.v | 5 +++++ vlib/v/parser/pratt.v | 13 +++++++++++++ vlib/v/tests/fn_array_direct_call_test.v | 17 +++++++++++++++++ 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/fn_array_direct_call_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 04a6ac0281..26d7eb3453 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1431,6 +1431,20 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { f = f1 } } + if !found && call_expr.left is ast.IndexExpr { + c.expr(call_expr.left) + expr := call_expr.left as ast.IndexExpr + sym := c.table.get_type_symbol(expr.left_type) + if sym.kind == .array { + info := sym.info as table.Array + elem_typ := c.table.get_type_symbol(info.elem_type) + if elem_typ.info is table.FnType { + return elem_typ.info.func.return_type + } + } + found = true + return table.string_type + } // already prefixed (mod.fn) or C/builtin/main if !found { if f1 := c.table.find_fn(fn_name) { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 2f8bf3df3b..ad5ef6456b 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -116,6 +116,7 @@ mut: called_fn_name string cur_mod ast.Module is_js_call bool // for handling a special type arg #1 `json.decode(User, ...)` + is_fn_index_call bool // nr_vars_to_free int // doing_autofree_tmp bool inside_lambda bool @@ -3763,6 +3764,12 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { } if is_direct_array_access { g.write('(($array_ptr_type_str)') + } else if g.is_fn_index_call { + if elem_typ.info is table.FnType { + g.write('((') + g.write_fn_ptr_decl(&elem_typ.info, '') + g.write(')(*($array_ptr_type_str)/*ee elem_typ */array_get(') + } } else { g.write('(*($array_ptr_type_str)/*ee elem_typ */array_get(') if left_is_ptr && !node.left_type.has_flag(.shared_f) { @@ -3790,7 +3797,11 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { } else { g.write(', ') g.expr(node.index) - g.write('))') + if g.is_fn_index_call { + g.write(')))') + } else { + g.write('))') + } } if needs_clone { g.write(')') @@ -4314,6 +4325,9 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { if field.name in inited_fields { sfield := struct_init.fields[inited_fields[field.name]] field_name := c_name(sfield.name) + if sfield.typ == 0 { + continue + } g.write('.$field_name = ') field_type_sym := g.table.get_type_symbol(sfield.typ) mut cloned := false diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index dd8541bc27..0300ea9fb8 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -254,6 +254,11 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { if node.left is ast.AnonFn { g.expr(node.left) } + if node.left is ast.IndexExpr && node.name == '' { + g.is_fn_index_call = true + g.expr(node.left) + g.is_fn_index_call = false + } if node.should_be_skipped { return } diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index 1bc27881cc..3207d8892c 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -263,6 +263,19 @@ pub fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_iden } else if p.tok.kind == .lsbr { node = p.index_expr(node) p.is_stmt_ident = is_stmt_ident + if p.tok.kind == .lpar && p.tok.line_nr == p.prev_tok.line_nr && node is ast.IndexExpr { + p.next() + pos := p.tok.position() + args := p.call_args() + p.check(.rpar) + node = ast.CallExpr{ + left: node + args: args + pos: pos + scope: p.scope + } + p.is_stmt_ident = is_stmt_ident + } } else if p.tok.kind == .key_as { // sum type as cast `x := SumType as Variant` pos := p.tok.position() diff --git a/vlib/v/tests/fn_array_direct_call_test.v b/vlib/v/tests/fn_array_direct_call_test.v new file mode 100644 index 0000000000..501167ec4f --- /dev/null +++ b/vlib/v/tests/fn_array_direct_call_test.v @@ -0,0 +1,17 @@ +struct Placeholder { + name string +} + +struct FnStruct { +mut: + array_of_fn []fn(int, &Placeholder, string)bool +} + +fn test_fn_array_direct_call() { + mut fs := FnStruct{} + fs.array_of_fn << fn(x int, y &Placeholder, z string) bool { + return false + } + + assert fs.array_of_fn[0](1, &Placeholder{name: 'Bob'}, 'Builder') == false +}