diff --git a/compiler/fn.v b/compiler/fn.v index 50618bc3da..01749b77d7 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -25,11 +25,11 @@ mut: typ string // return type is_c bool receiver_typ string - is_public bool + is_public bool is_method bool returns_error bool is_decl bool // type myfn fn(int, int) - defer string + defer_text string } fn (f &Fn) find_var(name string) Var { @@ -380,7 +380,7 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ') if p.pref.is_prof && f.name != 'main' && f.name != 'time__ticks' { p.genln('double _PROF_START = time__ticks();//$f.name') cgen_name := p.table.cgen_name(f) - f.defer = ' ${cgen_name}_time += time__ticks() - _PROF_START;' + f.defer_text = ' ${cgen_name}_time += time__ticks() - _PROF_START;' } p.statements_no_curly_end() // Print counting result after all statements in main @@ -388,7 +388,7 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ') p.genln(p.print_prof_counters()) } // Counting or not, always need to add defer before the end - p.genln(f.defer) + p.genln(f.defer_text) if typ != 'void' && !p.returns && f.name != 'main' && f.name != 'WinMain' { p.error('$f.name must return "$typ"') } diff --git a/compiler/parser.v b/compiler/parser.v index 56ff18ec78..61442087fa 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -1022,6 +1022,9 @@ fn (p mut Parser) statement(add_semi bool) string { label := p.check_name() p.genln('goto $label;') return '' + case Token.key_defer: + p.defer_st() + return '' case Token.hash: p.chash() return '' @@ -1038,7 +1041,7 @@ fn (p mut Parser) statement(add_semi bool) string { case Token.key_return: p.return_st() case Token.lcbr:// {} block - p.next() + p.check(.lcbr) p.genln('{') p.statements() return '' @@ -3088,7 +3091,7 @@ else { } fn (p mut Parser) return_st() { - p.cgen.insert_before(p.cur_fn.defer) + p.cgen.insert_before(p.cur_fn.defer_text) p.check(.key_return) fn_returns := p.cur_fn.typ != 'void' @@ -3265,6 +3268,19 @@ fn (p mut Parser) attribute() { p.error('bad attribute usage') } +fn (p mut Parser) defer_st() { + p.check(.key_defer) + // Wrap everything inside the defer block in /**/ comments, and save it in + // `defer_text`. It will be inserted before every `return`. + p.genln('/*') + pos := p.cgen.lines.len + p.check(.lcbr) + p.genln('{') + p.statements() + p.cur_fn.defer_text = p.cgen.lines.right(pos).join('\n') + p.genln('*/') +} + /////////////////////////////////////////////////////////////////////////////// diff --git a/compiler/token.v b/compiler/token.v index c1c9e56400..e3e1071a15 100644 --- a/compiler/token.v +++ b/compiler/token.v @@ -75,6 +75,7 @@ enum Token { key_const key_continue key_default + key_defer key_else key_embed key_enum @@ -213,6 +214,7 @@ fn build_token_str() []string { s[Token.key_union] = 'union' s[Token.key_static] = 'static' s[Token.key_as] = 'as' + s[Token.key_defer] = 'defer' return s }