v2: add method call receiver to cgen & check method args
							parent
							
								
									7a92a47eb3
								
							
						
					
					
						commit
						49f3ce0571
					
				| 
						 | 
				
			
			@ -170,6 +170,7 @@ pub:
 | 
			
		|||
	args     []Expr
 | 
			
		||||
	muts     []bool
 | 
			
		||||
	or_block OrExpr
 | 
			
		||||
mut:
 | 
			
		||||
	typ      table.Type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,7 +117,7 @@ pub fn (s &Scope) innermost(pos int) ?&Scope {
 | 
			
		|||
 | 
			
		||||
[inline]
 | 
			
		||||
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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -145,7 +145,7 @@ pub fn (c mut Checker) infix_expr(infix_expr ast.InfixExpr) table.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 {
 | 
			
		||||
		ast.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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
	method_call_expr.typ = typ
 | 
			
		||||
	typ_sym := c.table.get_type_symbol(typ)
 | 
			
		||||
	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 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
 | 
			
		||||
	}
 | 
			
		||||
	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
 | 
			
		||||
		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
 | 
			
		||||
	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
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -493,7 +520,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
 | 
			
		|||
			return it.typ
 | 
			
		||||
		}
 | 
			
		||||
		ast.AssignExpr {
 | 
			
		||||
			c.check_assign_expr(it)
 | 
			
		||||
			c.assign_expr(it)
 | 
			
		||||
		}
 | 
			
		||||
		ast.Assoc {
 | 
			
		||||
			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)
 | 
			
		||||
		}
 | 
			
		||||
		ast.MethodCallExpr {
 | 
			
		||||
			return c.check_method_call_expr(it)
 | 
			
		||||
			return c.method_call_expr(mut it)
 | 
			
		||||
		}
 | 
			
		||||
		ast.PostfixExpr {
 | 
			
		||||
			return c.postfix_expr(it)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -491,9 +491,17 @@ fn (g mut Gen) expr(node ast.Expr) {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ast.MethodCallExpr {
 | 
			
		||||
			typ := 'TODO'
 | 
			
		||||
			name := it.name.replace('.', '__')
 | 
			
		||||
			g.write('${typ}_${name}(')
 | 
			
		||||
			mut receiver_name := 'TODO'
 | 
			
		||||
			// TODO: there are still due to unchecked exprs (opt/some fn arg)
 | 
			
		||||
			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)
 | 
			
		||||
			if it.args.len > 0 {
 | 
			
		||||
				g.write(', ')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -450,12 +450,13 @@ pub fn (p &Parser) warn(s string) {
 | 
			
		|||
 | 
			
		||||
pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident {
 | 
			
		||||
	// p.warn('name ')
 | 
			
		||||
	pos := p.tok.position()
 | 
			
		||||
	mut name := p.check_name()
 | 
			
		||||
	if name == '_' {
 | 
			
		||||
		return ast.Ident{
 | 
			
		||||
			name: '_'
 | 
			
		||||
			kind: .blank_ident
 | 
			
		||||
			pos: p.tok.position()
 | 
			
		||||
			pos: pos
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if p.expr_mod.len > 0 {
 | 
			
		||||
| 
						 | 
				
			
			@ -465,7 +466,7 @@ pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident {
 | 
			
		|||
		kind: .unresolved
 | 
			
		||||
		name: name
 | 
			
		||||
		is_c: is_c
 | 
			
		||||
		pos: p.tok.position()
 | 
			
		||||
		pos: pos
 | 
			
		||||
	}
 | 
			
		||||
	// variable
 | 
			
		||||
	if p.expr_mod.len == 0 {
 | 
			
		||||
| 
						 | 
				
			
			@ -635,11 +636,9 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
 | 
			
		|||
		}
 | 
			
		||||
		.dot {
 | 
			
		||||
			// .enum_val
 | 
			
		||||
			// node,typ = p.enum_val()
 | 
			
		||||
			node = p.enum_val()
 | 
			
		||||
		}
 | 
			
		||||
		.chartoken {
 | 
			
		||||
			typ = table.byte_type
 | 
			
		||||
			node = ast.CharLiteral{
 | 
			
		||||
				val: p.tok.lit
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -656,11 +655,9 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
 | 
			
		|||
			node = ast.BoolLiteral{
 | 
			
		||||
				val: p.tok.kind == .key_true
 | 
			
		||||
			}
 | 
			
		||||
			typ = table.bool_type
 | 
			
		||||
			p.next()
 | 
			
		||||
		}
 | 
			
		||||
		.key_match {
 | 
			
		||||
			// node,typ = p.match_expr()
 | 
			
		||||
			node = p.match_expr()
 | 
			
		||||
		}
 | 
			
		||||
		.number {
 | 
			
		||||
| 
						 | 
				
			
			@ -682,7 +679,6 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
 | 
			
		|||
		}
 | 
			
		||||
		.key_none {
 | 
			
		||||
			p.next()
 | 
			
		||||
			typ = table.none_type
 | 
			
		||||
			node = ast.None{}
 | 
			
		||||
		}
 | 
			
		||||
		.key_sizeof {
 | 
			
		||||
| 
						 | 
				
			
			@ -700,7 +696,6 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
 | 
			
		|||
			node = ast.SizeOf{
 | 
			
		||||
				type_name: type_name
 | 
			
		||||
			}
 | 
			
		||||
			typ = table.int_type
 | 
			
		||||
		}
 | 
			
		||||
		// Map `{"age": 20}` or `{ x | foo:bar, a:10 }`
 | 
			
		||||
		.lcbr {
 | 
			
		||||
| 
						 | 
				
			
			@ -761,7 +756,7 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr {
 | 
			
		|||
			node = p.assign_expr(node)
 | 
			
		||||
		}
 | 
			
		||||
		else if p.tok.kind == .dot {
 | 
			
		||||
			node = p.dot_expr(node, typ)
 | 
			
		||||
			node = p.dot_expr(node)
 | 
			
		||||
		}
 | 
			
		||||
		else if p.tok.kind == .lsbr {
 | 
			
		||||
			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]
 | 
			
		||||
	p.check(.rsbr)
 | 
			
		||||
	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{
 | 
			
		||||
		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()
 | 
			
		||||
	field_name := p.check_name()
 | 
			
		||||
	if field_name == 'filter' {
 | 
			
		||||
		p.open_scope()
 | 
			
		||||
		p.filter(left_type)
 | 
			
		||||
		defer {
 | 
			
		||||
			p.close_scope()
 | 
			
		||||
		}
 | 
			
		||||
		p.filter()
 | 
			
		||||
		// wrong tok position when using defer
 | 
			
		||||
		// defer {
 | 
			
		||||
		// 	p.close_scope()
 | 
			
		||||
		// }
 | 
			
		||||
	}
 | 
			
		||||
	// Method call
 | 
			
		||||
	pos := p.tok.position()
 | 
			
		||||
	if p.tok.kind == .lpar {
 | 
			
		||||
		p.next()
 | 
			
		||||
		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
 | 
			
		||||
			args: args
 | 
			
		||||
			muts: muts
 | 
			
		||||
			pos: p.tok.position()
 | 
			
		||||
			pos: pos
 | 
			
		||||
			or_block: ast.OrExpr{
 | 
			
		||||
				stmts: or_stmts
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		mut node := ast.Expr{}
 | 
			
		||||
		node = mcall_expr
 | 
			
		||||
		if field_name == 'filter' {
 | 
			
		||||
			p.close_scope()
 | 
			
		||||
		}
 | 
			
		||||
		return node
 | 
			
		||||
	}
 | 
			
		||||
	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{}
 | 
			
		||||
	node = sel_expr
 | 
			
		||||
	if field_name == 'filter' {
 | 
			
		||||
		p.close_scope()
 | 
			
		||||
	}
 | 
			
		||||
	return node
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue