From abf5942433cddc6492d0216259ba9460bdd73bd2 Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Tue, 21 Apr 2020 13:23:36 +1000 Subject: [PATCH] parser/cgen: anon fn var & calling (#4534) --- vlib/v/checker/checker.v | 3 ++- vlib/v/gen/cgen.v | 36 +++++++++++++++++------------------- vlib/v/parser/fn.v | 10 ++++++---- vlib/v/parser/parse_type.v | 2 +- vlib/v/table/table.v | 7 +++---- vlib/v/tests/fn_test.v | 11 +++++++++++ 6 files changed, 40 insertions(+), 29 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index dde892dccf..445ce7a5ae 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1341,6 +1341,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type { return table.string_type } ast.AnonFn { + c.stmts(it.decl.stmts) return it.typ } else { @@ -1441,7 +1442,7 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { } // Function object (not a call), e.g. `onclick(my_click)` if func := c.table.find_fn(name) { - fn_type := table.new_type(c.table.find_or_register_fn_type(func, true)) + fn_type := table.new_type(c.table.find_or_register_fn_type(func, false, true)) ident.name = name ident.kind = .function ident.info = ast.IdentFn{ diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 94e09435f8..e42e843259 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -269,7 +269,7 @@ pub fn (mut g Gen) write_typedef_types() { .function { info := typ.info as table.FnType func := info.func - if !info.has_decl { + if !info.has_decl && !info.is_anon { fn_name := if func.is_c { func.name.replace('.', '__') } else if info.is_anon { @@ -762,6 +762,18 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { or_stmts = it.or_block.stmts return_type = it.return_type } + ast.AnonFn { + g.expr(*it) + // TODO: no buffer fiddling + fsym := g.table.get_type_symbol(it.typ) + ret_styp := g.typ(it.decl.return_type) + g.write('$ret_styp (*$ident.name) (') + def_pos := g.definitions.len + g.fn_args(it.decl.args, it.decl.is_variadic) + g.definitions.go_back(g.definitions.len - def_pos) + g.writeln(') = &${fsym.name};') + continue + } else {} } gen_or := is_call && table.type_is(return_type, .optional) @@ -1104,28 +1116,14 @@ fn (mut g Gen) expr(node ast.Expr) { g.typeof_expr(it) } ast.AnonFn { - sym := g.table.get_type_symbol(it.typ) - func := it.decl - // TODO: Fix hack and write function implementation directly to definitions + // TODO: dont fiddle with buffers pos := g.out.len - type_name := g.typ(func.return_type) - g.write('$type_name ${sym.name}_impl(') - g.fn_args(func.args, func.is_variadic) - g.writeln(') {') - g.stmts(func.stmts) - if g.autofree { - g.free_scope_vars(func.pos.pos - 1) - } - if g.defer_stmts.len > 0 { - g.write_defer_stmts() - } - g.out.writeln('}') - g.defer_stmts = [] - g.fn_decl = 0 + def_pos := g.definitions.len + g.stmt(it.decl) fn_body := g.out.after(pos) + g.definitions.go_back(g.definitions.len - def_pos) g.definitions.write(fn_body) g.out.go_back(fn_body.len) - g.out.write('&${sym.name}_impl') } else { // #printf("node=%d\n", node.typ); diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index cd57e06aa5..8140717cdf 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -238,7 +238,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { fn (mut p Parser) anon_fn() ast.AnonFn { pos := p.tok.position() - p.open_scope() + // p.open_scope() p.check(.key_fn) // TODO generics args, is_variadic := p.fn_args() @@ -257,15 +257,17 @@ fn (mut p Parser) anon_fn() ast.AnonFn { if p.tok.kind == .lcbr { stmts = p.parse_block() } - p.close_scope() + // p.close_scope() func := table.Fn{ args: args is_variadic: is_variadic return_type: return_type } - idx := p.table.find_or_register_fn_type(func, false) + name := 'anon_${p.tok.pos}_$func.signature()' + func.name = name + idx := p.table.find_or_register_fn_type(func, true, false) typ := table.new_type(idx) - name := p.table.get_type_name(typ) + //name := p.table.get_type_name(typ) return ast.AnonFn{ decl: ast.FnDecl{ name: name diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index b0497f2284..36c437726d 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -80,7 +80,7 @@ pub fn (p mut Parser) parse_fn_type(name string) table.Type { is_variadic: is_variadic return_type: return_type } - idx := p.table.find_or_register_fn_type(func, false) + idx := p.table.find_or_register_fn_type(func, false, false) return table.new_type(idx) } diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 2e40d6dc46..2dec05f7b9 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -390,14 +390,13 @@ pub fn (var t Table) find_or_register_multi_return(mr_typs []Type) int { return t.register_type_symbol(mr_type) } -pub fn (var t Table) find_or_register_fn_type(f Fn, has_decl bool) int { - is_anon := f.name.len == 0 - name := if is_anon { 'anon_fn_$f.signature()' } else { f.name } +pub fn (var t Table) find_or_register_fn_type(f Fn, is_anon bool, has_decl bool) int { + name := if f.name.len == 0 { 'anon_fn_$f.signature()' } else { f.name } return t.register_type_symbol(TypeSymbol{ kind: .function name: name info: FnType{ - is_anon: is_anon + is_anon: f.name.len == 0 || is_anon has_decl: has_decl func: f } diff --git a/vlib/v/tests/fn_test.v b/vlib/v/tests/fn_test.v index 1a563844d8..a530ed298b 100644 --- a/vlib/v/tests/fn_test.v +++ b/vlib/v/tests/fn_test.v @@ -125,6 +125,16 @@ fn test_fns() { } fn test_anon_fn() { + f1 := fn(a int){ + println('hello from f1') + } + + f1(1) + f2 := fn(a int){ + println('hello from f2') + } + + f2(1) /* high_fn(fn (x int) int { println('hello') @@ -165,3 +175,4 @@ fn test_fn_type_call() { st1 := &MySt{f:test} assert st1.f(10) == 1010 } +