diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index dfddc60056..3ef0e4354f 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -170,6 +170,7 @@ pub: args []Expr muts []bool or_block OrExpr +mut: typ table.Type } diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index d5e8d41d0f..3e9b79bb9b 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -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 { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index ddac2c378c..8a4540cbb3 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index d4883fbe79..ffdfae85b9 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -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(', ') diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index a91677e391..19a326cc08 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -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 }