parser: implement a direct call to an array of functions (fix #6908) (#7322)

pull/7342/head
yuyi 2020-12-15 11:24:57 +08:00 committed by GitHub
parent a3c3fd4d20
commit 8ab59c5f0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 1 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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
}

View File

@ -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()

View File

@ -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
}