compiler: add support for `[if myflag]` void fn/methods

pull/4580/head
Delyan Angelov 2020-04-25 16:57:11 +03:00
parent 945f964c0c
commit 9a19531909
6 changed files with 30 additions and 0 deletions

View File

@ -211,6 +211,7 @@ pub:
is_js bool is_js bool
no_body bool // just a definition `fn C.malloc()` no_body bool // just a definition `fn C.malloc()`
is_builtin bool // this function is defined in builtin/strconv is_builtin bool // this function is defined in builtin/strconv
ctdefine string // has [if myflag] tag
pos token.Position pos token.Position
} }
@ -235,6 +236,7 @@ mut:
left_type table.Type // type of `user` left_type table.Type // type of `user`
receiver_type table.Type // User receiver_type table.Type // User
return_type table.Type return_type table.Type
should_be_skipped bool
} }
pub struct CallArg { pub struct CallArg {

View File

@ -120,6 +120,11 @@ fn (c mut Checker) check_file_in_main(file ast.File) bool {
c.warn('function `$it.name` $no_pub_in_main_warning', it.pos) c.warn('function `$it.name` $no_pub_in_main_warning', it.pos)
} }
} }
if it.ctdefine.len > 0 {
if it.return_type != table.void_type {
c.error('only functions that do NOT return values can have `[if ${it.ctdefine}]` tags', it.pos)
}
}
} }
ast.StructDecl { ast.StructDecl {
if it.is_pub { if it.is_pub {
@ -497,6 +502,9 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
//println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod') //println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos) c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos)
} }
if method.return_type == table.void_type && method.ctdefine.len > 0 && method.ctdefine !in c.pref.compile_defines {
call_expr.should_be_skipped = true
}
nr_args := if method.args.len == 0 { 0 } else {method.args.len - 1} nr_args := if method.args.len == 0 { 0 } else {method.args.len - 1}
min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 } min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 }
if call_expr.args.len < min_required_args { if call_expr.args.len < min_required_args {
@ -612,6 +620,11 @@ pub fn (c mut Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
return table.void_type return table.void_type
} }
call_expr.return_type = f.return_type call_expr.return_type = f.return_type
if f.return_type == table.void_type && f.ctdefine.len > 0 && f.ctdefine !in c.pref.compile_defines {
call_expr.should_be_skipped = true
}
if f.is_c || call_expr.is_c || f.is_js || call_expr.is_js { if f.is_c || call_expr.is_c || f.is_js || call_expr.is_js {
for arg in call_expr.args { for arg in call_expr.args {
c.expr(arg.expr) c.expr(arg.expr)

View File

@ -224,6 +224,9 @@ fn (mut g Gen) fn_args(args []table.Arg, is_variadic bool) {
} }
fn (mut g Gen) call_expr(node ast.CallExpr) { fn (mut g Gen) call_expr(node ast.CallExpr) {
if node.should_be_skipped {
return
}
gen_or := !g.is_assign_rhs && node.or_block.stmts.len > 0 gen_or := !g.is_assign_rhs && node.or_block.stmts.len > 0
tmp_opt := if gen_or { g.new_tmp_var() } else { '' } tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
if gen_or { if gen_or {

View File

@ -170,6 +170,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
end_pos = p.tok.position() end_pos = p.tok.position()
return_type = p.parse_type() return_type = p.parse_type()
} }
ctdefine := p.attr_ctdefine
// Register // Register
if is_method { if is_method {
mut type_sym := p.table.get_type_symbol(rec_type) mut type_sym := p.table.get_type_symbol(rec_type)
@ -181,6 +182,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_variadic: is_variadic is_variadic: is_variadic
is_generic: is_generic is_generic: is_generic
is_pub: is_pub is_pub: is_pub
ctdefine: ctdefine
}) })
} else { } else {
if is_c { if is_c {
@ -202,6 +204,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_js: is_js is_js: is_js
is_generic: is_generic is_generic: is_generic
is_pub: is_pub is_pub: is_pub
ctdefine: ctdefine
}) })
} }
// Body // Body
@ -212,6 +215,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
} }
p.close_scope() p.close_scope()
p.attr = '' p.attr = ''
p.attr_ctdefine = ''
return ast.FnDecl{ return ast.FnDecl{
name: name name: name
stmts: stmts stmts: stmts
@ -231,6 +235,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
no_body: no_body no_body: no_body
pos: start_pos.extend(end_pos) pos: start_pos.extend(end_pos)
is_builtin: p.builtin_mod || p.mod in util.builtin_module_parts is_builtin: p.builtin_mod || p.mod in util.builtin_module_parts
ctdefine: ctdefine
} }
} }

View File

@ -31,6 +31,7 @@ mut:
builtin_mod bool // are we in the `builtin` module? builtin_mod bool // are we in the `builtin` module?
mod string // current module name mod string // current module name
attr string attr string
attr_ctdefine string
expr_mod string expr_mod string
scope &ast.Scope scope &ast.Scope
global_scope &ast.Scope global_scope &ast.Scope
@ -490,8 +491,10 @@ pub fn (mut p Parser) stmt() ast.Stmt {
fn (mut p Parser) attribute() ast.Attr { fn (mut p Parser) attribute() ast.Attr {
p.check(.lsbr) p.check(.lsbr)
mut is_if_attr := false
if p.tok.kind == .key_if { if p.tok.kind == .key_if {
p.next() p.next()
is_if_attr = true
} }
mut name := p.check_name() mut name := p.check_name()
if p.tok.kind == .colon { if p.tok.kind == .colon {
@ -505,6 +508,9 @@ fn (mut p Parser) attribute() ast.Attr {
} }
p.check(.rsbr) p.check(.rsbr)
p.attr = name p.attr = name
if is_if_attr {
p.attr_ctdefine = name
}
return ast.Attr{ return ast.Attr{
name: name name: name
} }

View File

@ -27,6 +27,7 @@ pub:
is_generic bool is_generic bool
is_pub bool is_pub bool
mod string mod string
ctdefine string // compile time define. myflag, when [if myflag] tag
} }
pub struct Arg { pub struct Arg {