v2: add method call receiver to cgen & check method args

pull/3940/head
Joe Conigliaro 2020-03-06 20:52:03 +11:00
parent 7a92a47eb3
commit 49f3ce0571
5 changed files with 67 additions and 38 deletions

View File

@ -170,6 +170,7 @@ pub:
args []Expr args []Expr
muts []bool muts []bool
or_block OrExpr or_block OrExpr
mut:
typ table.Type typ table.Type
} }

View File

@ -117,7 +117,7 @@ pub fn (s &Scope) innermost(pos int) ?&Scope {
[inline] [inline]
fn (s &Scope) contains(pos int) bool { fn (s &Scope) contains(pos int) bool {
return pos > s.start_pos && pos < s.end_pos return pos >= s.start_pos && pos <= s.end_pos
} }
pub fn (sc &Scope) show(level int) string { pub fn (sc &Scope) show(level int) string {

View File

@ -145,7 +145,7 @@ pub fn (c mut Checker) infix_expr(infix_expr ast.InfixExpr) table.Type {
return left_type return left_type
} }
fn (c mut Checker) check_assign_expr(assign_expr ast.AssignExpr) { fn (c mut Checker) assign_expr(assign_expr ast.AssignExpr) {
match assign_expr.left { match assign_expr.left {
ast.Ident { ast.Ident {
if it.kind == .blank_ident { if it.kind == .blank_ident {
@ -239,25 +239,52 @@ pub fn (c mut Checker) call_expr(call_expr ast.CallExpr) table.Type {
return f.return_type return f.return_type
} }
pub fn (c mut Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) table.Type { // TODO: clean this up, remove dupe code & consider merging method/fn call everywhere
pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) table.Type {
typ := c.expr(method_call_expr.expr) typ := c.expr(method_call_expr.expr)
method_call_expr.typ = typ
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
if method := typ_sym.find_method(name) {
return method.return_type
}
if typ_sym.kind == .array && name in ['filter', 'clone'] { if typ_sym.kind == .array && name in ['filter', 'clone'] {
if name == 'filter' {
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) or {
c.file.scope
}
scope.override_var(ast.VarDecl{
name: 'it'
typ: array_info.elem_type
})
}
if method := typ_sym.find_method(name) {
for i, arg_expr in method_call_expr.args {
c.expected_type = method.args[i].typ
c.expr(arg_expr)
}
}
return typ return typ
} }
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
return info.elem_type return info.elem_type
} }
if method := typ_sym.find_method(name) {
for i, arg_expr in method_call_expr.args {
c.expected_type = method.args[i].typ
c.expr(arg_expr)
}
return method.return_type
}
// check parent // check parent
if typ_sym.parent_idx != 0 { if typ_sym.parent_idx != 0 {
parent := &c.table.types[typ_sym.parent_idx] parent := &c.table.types[typ_sym.parent_idx]
if method := parent.find_method(name) { if method := parent.find_method(name) {
// println('got method $name, returning') // 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 return method.return_type
} }
} }
@ -493,7 +520,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
return it.typ return it.typ
} }
ast.AssignExpr { ast.AssignExpr {
c.check_assign_expr(it) c.assign_expr(it)
} }
ast.Assoc { ast.Assoc {
scope := c.file.scope.innermost(it.pos.pos) or { scope := c.file.scope.innermost(it.pos.pos) or {
@ -547,7 +574,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
return c.match_expr(mut it) return c.match_expr(mut it)
} }
ast.MethodCallExpr { ast.MethodCallExpr {
return c.check_method_call_expr(it) return c.method_call_expr(mut it)
} }
ast.PostfixExpr { ast.PostfixExpr {
return c.postfix_expr(it) return c.postfix_expr(it)

View File

@ -491,9 +491,17 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
} }
ast.MethodCallExpr { ast.MethodCallExpr {
typ := 'TODO' mut receiver_name := 'TODO'
name := it.name.replace('.', '__') // TODO: there are still due to unchecked exprs (opt/some fn arg)
g.write('${typ}_${name}(') if it.typ != 0 {
typ_sym := g.table.get_type_symbol(it.typ)
receiver_name = typ_sym.name
}
name := '${receiver_name}_$it.name'.replace('.', '__')
if table.type_is_ptr(it.typ) {
g.write('&')
}
g.write('${name}(')
g.expr(it.expr) g.expr(it.expr)
if it.args.len > 0 { if it.args.len > 0 {
g.write(', ') g.write(', ')

View File

@ -450,12 +450,13 @@ pub fn (p &Parser) warn(s string) {
pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident { pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident {
// p.warn('name ') // p.warn('name ')
pos := p.tok.position()
mut name := p.check_name() mut name := p.check_name()
if name == '_' { if name == '_' {
return ast.Ident{ return ast.Ident{
name: '_' name: '_'
kind: .blank_ident kind: .blank_ident
pos: p.tok.position() pos: pos
} }
} }
if p.expr_mod.len > 0 { if p.expr_mod.len > 0 {
@ -465,7 +466,7 @@ pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident {
kind: .unresolved kind: .unresolved
name: name name: name
is_c: is_c is_c: is_c
pos: p.tok.position() pos: pos
} }
// variable // variable
if p.expr_mod.len == 0 { if p.expr_mod.len == 0 {
@ -635,11 +636,9 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
} }
.dot { .dot {
// .enum_val // .enum_val
// node,typ = p.enum_val()
node = p.enum_val() node = p.enum_val()
} }
.chartoken { .chartoken {
typ = table.byte_type
node = ast.CharLiteral{ node = ast.CharLiteral{
val: p.tok.lit val: p.tok.lit
} }
@ -656,11 +655,9 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
node = ast.BoolLiteral{ node = ast.BoolLiteral{
val: p.tok.kind == .key_true val: p.tok.kind == .key_true
} }
typ = table.bool_type
p.next() p.next()
} }
.key_match { .key_match {
// node,typ = p.match_expr()
node = p.match_expr() node = p.match_expr()
} }
.number { .number {
@ -682,7 +679,6 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
} }
.key_none { .key_none {
p.next() p.next()
typ = table.none_type
node = ast.None{} node = ast.None{}
} }
.key_sizeof { .key_sizeof {
@ -700,7 +696,6 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
node = ast.SizeOf{ node = ast.SizeOf{
type_name: type_name type_name: type_name
} }
typ = table.int_type
} }
// Map `{"age": 20}` or `{ x | foo:bar, a:10 }` // Map `{"age": 20}` or `{ x | foo:bar, a:10 }`
.lcbr { .lcbr {
@ -761,7 +756,7 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
node = p.assign_expr(node) node = p.assign_expr(node)
} }
else if p.tok.kind == .dot { else if p.tok.kind == .dot {
node = p.dot_expr(node, typ) node = p.dot_expr(node)
} }
else if p.tok.kind == .lsbr { else if p.tok.kind == .lsbr {
node = p.index_expr(node) node = p.index_expr(node)
@ -852,15 +847,6 @@ fn (p mut Parser) index_expr(left ast.Expr) ast.IndexExpr {
} }
} }
} }
// get the element type
/*
mut typ := left_type
left_type_sym := p.table.get_type_symbol(left_type)
if left_type_sym.kind == .array {
info := left_type_sym.info as table.Array
typ = info.elem_type
}
*/
// [expr] // [expr]
p.check(.rsbr) p.check(.rsbr)
return ast.IndexExpr{ return ast.IndexExpr{
@ -870,24 +856,25 @@ fn (p mut Parser) index_expr(left ast.Expr) ast.IndexExpr {
} }
} }
fn (p mut Parser) filter(typ table.Type) { fn (p mut Parser) filter() {
p.scope.register_var(ast.VarDecl{ p.scope.register_var(ast.VarDecl{
name: 'it' name: 'it'
typ: typ
}) })
} }
fn (p mut Parser) dot_expr(left ast.Expr, left_type table.Type) ast.Expr { fn (p mut Parser) dot_expr(left ast.Expr) ast.Expr {
p.next() p.next()
field_name := p.check_name() field_name := p.check_name()
if field_name == 'filter' { if field_name == 'filter' {
p.open_scope() p.open_scope()
p.filter(left_type) p.filter()
defer { // wrong tok position when using defer
p.close_scope() // defer {
} // p.close_scope()
// }
} }
// Method call // Method call
pos := p.tok.position()
if p.tok.kind == .lpar { if p.tok.kind == .lpar {
p.next() p.next()
args,muts := p.call_args() args,muts := p.call_args()
@ -901,13 +888,16 @@ fn (p mut Parser) dot_expr(left ast.Expr, left_type table.Type) ast.Expr {
name: field_name name: field_name
args: args args: args
muts: muts muts: muts
pos: p.tok.position() pos: pos
or_block: ast.OrExpr{ or_block: ast.OrExpr{
stmts: or_stmts stmts: or_stmts
} }
} }
mut node := ast.Expr{} mut node := ast.Expr{}
node = mcall_expr node = mcall_expr
if field_name == 'filter' {
p.close_scope()
}
return node return node
} }
sel_expr := ast.SelectorExpr{ sel_expr := ast.SelectorExpr{
@ -917,6 +907,9 @@ fn (p mut Parser) dot_expr(left ast.Expr, left_type table.Type) ast.Expr {
} }
mut node := ast.Expr{} mut node := ast.Expr{}
node = sel_expr node = sel_expr
if field_name == 'filter' {
p.close_scope()
}
return node return node
} }