table/checker: proper parent field/method lookup & cleanup
parent
0ad9eb5e16
commit
7513dab185
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue