From 5fd5e558ae7f46ac6a4fe6cba829f651c1081d2e Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Wed, 8 Jul 2020 01:10:39 +1000 Subject: [PATCH] parser/checker/gen: anon fn direct call with args --- vlib/v/ast/ast.v | 4 +++- vlib/v/checker/checker.v | 16 +++++++++++----- vlib/v/fmt/fmt.v | 3 --- vlib/v/gen/cgen.v | 18 ++++++------------ vlib/v/gen/fn.v | 5 +++++ vlib/v/parser/fn.v | 7 ------- vlib/v/parser/pratt.v | 16 ++++++++++++++++ vlib/v/tests/fn_high_test.v | 11 +++++++++++ 8 files changed, 52 insertions(+), 28 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index aa33c3fb34..5ec7cb3bf7 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -213,7 +213,6 @@ pub: pub struct AnonFn { pub: decl FnDecl - is_called bool pub mut: typ table.Type } @@ -896,6 +895,9 @@ pub fn (expr Expr) is_blank_ident() bool { pub fn (expr Expr) position() token.Position { // all uncommented have to be implemented match mut expr { + AnonFn { + return expr.decl.pos + } ArrayInit { return expr.pos } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 894a777e5d..e7477e94ac 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1014,6 +1014,16 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { mut f := table.Fn{} mut found := false mut found_in_args := false + // anon fn direct call + if call_expr.left is ast.AnonFn { + // it was set to anon for checker errors, clear for gen + call_expr.name = '' + c.expr(call_expr.left) + anon_fn := call_expr.left as ast.AnonFn + anon_fn_sym := c.table.get_type_symbol(anon_fn.typ) + f = (anon_fn_sym.info as table.FnType).func + found = true + } // try prefix with current module as it would have never gotten prefixed if !fn_name.contains('.') && call_expr.mod !in ['builtin'] { name_prefixed := '${call_expr.mod}.$fn_name' @@ -2072,11 +2082,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { c.cur_fn = &node.decl c.stmts(node.decl.stmts) c.cur_fn = keep_fn - return if node.is_called { - node.decl.return_type - } else { - node.typ - } + return node.typ } ast.ArrayInit { return c.array_init(mut node) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 68163157f1..2ac33269ae 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -701,9 +701,6 @@ pub fn (mut f Fmt) expr(node ast.Expr) { match node { ast.AnonFn { f.fn_decl(node.decl) - if node.is_called { - f.write('()') - } } ast.ArrayInit { f.array_init(node) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index d9d4c0eaf8..41ec308163 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1210,18 +1210,12 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { g.write('{') } ret_styp := g.typ(val.decl.return_type) - if val.is_called { - g.write('$ret_styp $ident.name = ') - g.expr(*val) - g.write('()') - } else { - g.write('$ret_styp (*$ident.name) (') - def_pos := g.definitions.len - g.fn_args(val.decl.args, val.decl.is_variadic) - g.definitions.go_back(g.definitions.len - def_pos) - g.write(') = ') - g.expr(*val) - } + g.write('$ret_styp (*$ident.name) (') + def_pos := g.definitions.len + g.fn_args(val.decl.args, val.decl.is_variadic) + g.definitions.go_back(g.definitions.len - def_pos) + g.write(') = ') + g.expr(*val) g.writeln(';') if blank_assign { g.write('}') diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 0adee441e4..539ac9da76 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -241,6 +241,11 @@ fn (mut g Gen) fn_args(args []table.Arg, is_variadic bool) ([]string, []string) } fn (mut g Gen) call_expr(node ast.CallExpr) { + // NOTE: everything could be done this way + // see my comment in parser near anon_fn + if node.left is ast.AnonFn { + g.expr(node.left) + } if node.should_be_skipped { return } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 76f34fb840..c0fc44c91f 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -355,12 +355,6 @@ fn (mut p Parser) anon_fn() ast.AnonFn { return_type: return_type } name := 'anon_${p.tok.pos}_$func.signature()' - mut is_called := false - if p.tok.kind == .lpar { - is_called = true - p.check(.lpar) - p.check(.rpar) - } func.name = name idx := p.table.find_or_register_fn_type(p.mod, func, true, false) typ := table.new_type(idx) @@ -379,7 +373,6 @@ fn (mut p Parser) anon_fn() ast.AnonFn { pos: pos file: p.file_name } - is_called: is_called typ: typ } } diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index e5bdb1208d..b4bb18028d 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -166,6 +166,22 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { .key_fn { // Anonymous function node = p.anon_fn() + // its a call + // NOTE: this could be moved to just before the pratt loop + // then anything can be a call, eg. `index[2]()` or `stuct.field()` + // but this would take a bit of modification + if p.tok.kind == .lpar { + p.next() + pos := p.tok.position() + args := p.call_args() + p.check(.rpar) + node = ast.CallExpr{ + name: 'anon' + left: node + args: args + pos: pos + } + } return node } else { diff --git a/vlib/v/tests/fn_high_test.v b/vlib/v/tests/fn_high_test.v index 0cbdb4db80..ac06b9f826 100644 --- a/vlib/v/tests/fn_high_test.v +++ b/vlib/v/tests/fn_high_test.v @@ -101,6 +101,17 @@ fn test_anon_fn() { }) } +fn test_anon_fn_direct_call() { + fn(name string) { + println('hello $name') + }('from anon') + + b := fn(n int) int { + return 11+n + }(100) + assert b == 111 +} + // // Test assigning functions (IdentFn) //