1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

table/checker: proper parent field/method lookup & cleanup

This commit is contained in:
Joe Conigliaro 2020-03-11 20:48:45 +11:00
parent 0ad9eb5e16
commit 7513dab185
5 changed files with 63 additions and 85 deletions

View File

@ -155,17 +155,17 @@ pub:
pub struct CallExpr { pub struct CallExpr {
pub: pub:
// tok token.Token // tok token.Token
pos token.Position pos token.Position
mut: mut:
// func Expr // func Expr
name string name string
args []Expr args []Expr
arg_types []table.Type arg_types []table.Type
is_c bool is_c bool
muts []bool muts []bool
or_block OrExpr or_block OrExpr
typ table.Type return_type table.Type
} }
pub struct MethodCallExpr { pub struct MethodCallExpr {
@ -180,7 +180,7 @@ pub:
mut: mut:
expr_type table.Type // type of `user` expr_type table.Type // type of `user`
receiver_type table.Type // User receiver_type table.Type // User
typ table.Type return_type table.Type
} }
pub struct Return { pub struct Return {

View File

@ -207,7 +207,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
if !found { if !found {
c.error('unknown fn: $fn_name', call_expr.pos) c.error('unknown fn: $fn_name', call_expr.pos)
} }
call_expr.typ = f.return_type call_expr.return_type = f.return_type
if f.is_c || call_expr.is_c { if f.is_c || call_expr.is_c {
for expr in call_expr.args { for expr in call_expr.args {
c.expr(expr) c.expr(expr)
@ -255,57 +255,39 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr)
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
name := method_call_expr.name name := method_call_expr.name
// println('method call $name $method_call_expr.pos.line_nr') // println('method call $name $method_call_expr.pos.line_nr')
if typ_sym.kind == .array && name in ['filter', 'clone'] { if typ_sym.kind == .array && name in ['filter', 'clone', 'repeat'] {
if name == 'filter' { if name == 'filter' {
array_info := typ_sym.info as table.Array array_info := typ_sym.info as table.Array
elem_type_sym := c.table.get_type_symbol(array_info.elem_type)
mut scope := c.file.scope.innermost(method_call_expr.pos.pos) mut scope := c.file.scope.innermost(method_call_expr.pos.pos)
scope.override_var(ast.Var{ scope.override_var(ast.Var{
name: 'it' name: 'it'
typ: array_info.elem_type typ: array_info.elem_type
}) })
} }
if method := typ_sym.find_method(name) { else if name == 'repeat' {
method_call_expr.typ = method.return_type c.expr(method_call_expr.args[0])
for i, arg_expr in method_call_expr.args {
c.expected_type = method.args[i].typ
c.expr(arg_expr)
}
} }
// need to return `array_xxx` instead of `array`
method_call_expr.return_type = typ
return typ return typ
} }
else if typ_sym.kind == .array && name in ['first', 'last'] { else if typ_sym.kind == .array && name in ['first', 'last'] {
info := typ_sym.info as table.Array info := typ_sym.info as table.Array
method_call_expr.return_type = info.elem_type
return info.elem_type return info.elem_type
} }
// repeat() returns `array`, need to return `array_xxx` if method := c.table.type_find_method(typ_sym, name) {
else if typ_sym.kind == .array && name in ['repeat'] {
c.expr(method_call_expr.args[0])
return typ
}
if method := typ_sym.find_method(name) {
// if name == 'clone' { // if name == 'clone' {
// println('CLONE nr args=$method.args.len') // println('CLONE nr args=$method.args.len')
// } // }
method_call_expr.receiver_type = method.args[0].typ
for i, arg_expr in method_call_expr.args { for i, arg_expr in method_call_expr.args {
c.expected_type = method.args[i].typ c.expected_type = method.args[i].typ
c.expr(arg_expr) c.expr(arg_expr)
} }
method_call_expr.receiver_type = method.args[0].typ
method_call_expr.return_type = method.return_type
return method.return_type return method.return_type
} }
// check parent
if typ_sym.parent_idx != 0 {
parent := &c.table.types[typ_sym.parent_idx]
if method := parent.find_method(name) {
// println('got method $name, returning')
for i, arg_expr in method_call_expr.args {
c.expected_type = method.args[i].typ
c.expr(arg_expr)
}
return method.return_type
}
}
c.error('type `$typ_sym.name` has no method `$name`', method_call_expr.pos) c.error('type `$typ_sym.name` has no method `$name`', method_call_expr.pos)
return table.void_type return table.void_type
} }
@ -320,21 +302,14 @@ pub fn (c mut Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.T
// println('sel expr line_nr=$selector_expr.pos.line_nr typ=$selector_expr.expr_type') // println('sel expr line_nr=$selector_expr.pos.line_nr typ=$selector_expr.expr_type')
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
field_name := selector_expr.field field_name := selector_expr.field
if field := typ_sym.find_field(field_name) {
return field.typ
}
// variadic // variadic
if table.type_is_variadic(typ) { if table.type_is_variadic(typ) {
if field_name == 'len' { if field_name == 'len' {
return table.int_type return table.int_type
} }
} }
// check parent if field := c.table.struct_find_field(typ_sym, field_name) {
if typ_sym.parent_idx != 0 { return field.typ
parent := &c.table.types[typ_sym.parent_idx]
if field := parent.find_field(field_name) {
return field.typ
}
} }
if typ_sym.kind != .struct_ { if typ_sym.kind != .struct_ {
c.error('`$typ_sym.name` is not a struct', selector_expr.pos) c.error('`$typ_sym.name` is not a struct', selector_expr.pos)

View File

@ -291,10 +291,10 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
mut return_type := table.void_type mut return_type := table.void_type
match assign_stmt.right[0] { match assign_stmt.right[0] {
ast.CallExpr { ast.CallExpr {
return_type = it.typ return_type = it.return_type
} }
ast.MethodCallExpr { ast.MethodCallExpr {
return_type = it.typ return_type = it.return_type
} }
else { else {
panic('expected call') panic('expected call')

View File

@ -142,16 +142,13 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
} }
// Register // Register
if is_method { if is_method {
type_sym := p.table.get_type_symbol(rec_type) mut type_sym := p.table.get_type_symbol(rec_type)
// p.warn('reg method $type_sym.name . $name ()') // p.warn('reg method $type_sym.name . $name ()')
ok := p.table.register_method(type_sym, table.Fn{ type_sym.register_method(table.Fn{
name: name name: name
args: args args: args
return_type: typ return_type: typ
}) })
if !ok {
p.error('expected Struct')
}
} }
else { else {
if is_c { if is_c {

View File

@ -83,15 +83,8 @@ pub fn (t mut Table) register_fn(new_fn Fn) {
t.fns[new_fn.name] = new_fn t.fns[new_fn.name] = new_fn
} }
pub fn (t &Table) register_method(typ &TypeSymbol, new_fn Fn) bool { pub fn (t mut TypeSymbol) register_method(new_fn Fn) {
// println('register method `$new_fn.name` type=$typ.name idx=$typ.idx') t.methods << new_fn
// println('register method `$new_fn.name` type=$typ.name')
// TODO mut << bug
mut t1 := typ
mut methods := typ.methods
methods << new_fn
t1.methods = methods
return true
} }
pub fn (t &TypeSymbol) has_method(name string) bool { pub fn (t &TypeSymbol) has_method(name string) bool {
@ -131,37 +124,50 @@ pub fn (s &TypeSymbol) find_field(name string) ?Field {
return none return none
} }
pub fn (t &Table) type_has_method(s &TypeSymbol, name string) bool {
// println('type_has_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
if _ := t.type_find_method(s, name) {
return true
}
return false
}
// search from current type up through each parent looking for method
pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn {
// println('type_find_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
mut ts := s
for {
if method := ts.find_method(name) {
return method
}
if s.parent_idx == 0 {
break
}
ts = &t.types[ts.parent_idx]
}
return none
}
pub fn (t &Table) struct_has_field(s &TypeSymbol, name string) bool { pub fn (t &Table) struct_has_field(s &TypeSymbol, name string) bool {
if s.parent_idx != 0 { // println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
parent := &t.types[s.parent_idx]
println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent=$parent.name')
}
else {
println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent=none')
}
if _ := t.struct_find_field(s, name) { if _ := t.struct_find_field(s, name) {
return true return true
} }
return false return false
} }
// search from current type up through each parent looking for field
pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field { pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field {
if s.parent_idx != 0 { // println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
parent := &t.types[s.parent_idx] mut ts := s
println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent=$parent.name') for {
} if field := ts.find_field(name) {
else {
println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent=none')
}
if field := s.find_field(name) {
return field
}
if s.parent_idx != 0 {
parent := &t.types[s.parent_idx]
if field := parent.find_field(name) {
println('got parent $parent.name')
return field return field
} }
if s.parent_idx == 0 {
break
}
ts = &t.types[ts.parent_idx]
} }
return none return none
} }