From c4b9ef388f55b7d76a19ae6a34caf4ef319f5e41 Mon Sep 17 00:00:00 2001 From: Joe Conigliaro Date: Fri, 28 Feb 2020 23:29:04 +1100 Subject: [PATCH] v2: handle var decl & assign stmt together 1st step combining --- vlib/v/ast/ast.v | 5 +- vlib/v/ast/scope.v | 8 ++ vlib/v/checker/checker.v | 20 ++++- vlib/v/gen/tests/4.vv | 2 +- vlib/v/parser/parser.v | 182 +++++++++++++++++++-------------------- vlib/v/table/table.v | 4 + vlib/v/table/types.v | 2 +- 7 files changed, 124 insertions(+), 99 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index a13dc5c361..6bad0cb34f 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -229,8 +229,9 @@ pub mut: pub struct IdentVar { pub mut: - typ table.Type - is_mut bool + typ table.Type + is_mut bool + is_static bool } type IdentInfo = IdentFunc | IdentVar diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index 36d1e58844..d5e8d41d0f 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -63,6 +63,14 @@ pub fn (s mut Scope) override_var(var VarDecl) { s.vars[var.name] = var } +pub fn (s &Scope) outermost() &Scope { + mut sc := s + for !isnil(sc.parent) { + sc = sc.parent + } + return sc +} + // returns the innermost scope containing pos pub fn (s &Scope) innermost(pos int) ?&Scope { if s.contains(pos) { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index f9e96e6ed0..35e7ab1f20 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -538,8 +538,14 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { // Handle indents with unresolved types during the parsing step // (declared after first usage) else if ident.kind == .unresolved { + // prepend mod to look for fn call or const + mut name := ident.name + if !name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) { + name = '${c.file.mod.name}.$ident.name' + } + // println('# name: $name') // constant - if constant := c.table.find_const(ident.name) { + if constant := c.table.find_const(name) { ident.kind = .constant ident.info = ast.IdentVar{ typ: constant.typ @@ -547,7 +553,7 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { return constant.typ } // Function object (not a call), e.g. `onclick(my_click)` - if func := c.table.find_fn(ident.name) { + if func := c.table.find_fn(name) { ident.kind = .function ident.info = ast.IdentFunc{ return_type: func.return_type @@ -564,8 +570,10 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type { t := c.expr(node.cond) for i, block in node.blocks { - match_expr := node.match_exprs[i] - c.expr(match_expr) + if i < node.match_exprs.len { + match_expr := node.match_exprs[i] + c.expr(match_expr) + } for stmt in block.stmts { c.stmt(stmt) } @@ -680,6 +688,10 @@ pub fn (c mut Checker) index_expr(node ast.IndexExpr) table.Type { return info.value_type } else if typ_sym.kind in [.byteptr, .string] { + // TODO: hack need to handle &a[0] comment to see wyahsh errors + if typ_sym.kind == .byteptr { + return table.type_to_ptr(table.byte_type) + } return table.byte_type } // else { diff --git a/vlib/v/gen/tests/4.vv b/vlib/v/gen/tests/4.vv index 19b722c288..b761c733ad 100644 --- a/vlib/v/gen/tests/4.vv +++ b/vlib/v/gen/tests/4.vv @@ -24,7 +24,7 @@ fn main() { mut d := testb(1) d = 'hello' - mut e = 'hello' + mut e := 'hello' e = testb(111) e = 'world' diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 6bb31cd726..ae7c7b37a4 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -272,7 +272,7 @@ pub fn (p mut Parser) stmt() ast.Stmt { } } .key_mut { - return p.var_decl() + return p.var_decl_and_assign_stmt() } .key_for { return p.for_statement() @@ -313,12 +313,8 @@ pub fn (p mut Parser) stmt() ast.Stmt { } else { // `x := ...` - // if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign, .comma] { - if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign] { - return p.var_decl() - } - else if p.tok.kind == .name && p.peek_tok.kind in [.comma] { - return p.assign_stmt() + if p.tok.kind == .name && p.peek_tok.kind in [.decl_assign, .comma] { + return p.var_decl_and_assign_stmt() } // `label:` else if p.tok.kind == .name && p.peek_tok.kind == .colon { @@ -339,6 +335,7 @@ pub fn (p mut Parser) stmt() ast.Stmt { } } +// TODO: merge wtih AssignStmt & VarDecl pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr { op := p.tok.kind p.next() @@ -456,40 +453,32 @@ pub fn (p &Parser) warn(s string) { pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident { // p.warn('name ') - // left := p.parse_ident() - name := p.check_name() + mut name := p.check_name() if name == '_' { return ast.Ident{ + name: '_' kind: .blank_ident pos: p.tok.position() } } + if p.expr_mod.len > 0 { + name = '${p.expr_mod}.$name' + } mut ident := ast.Ident{ + kind: .unresolved name: name is_c: is_c pos: p.tok.position() } - mut known_var := false - if var := p.scope.find_var(name) { - known_var = true - // typ = var.typ - } // variable - if known_var { - // || p.tok.kind in [.comma, .decl_assign, .assign] - // println('#### IDENT: $var.name: $var.typ.typ.name - $var.typ.idx') - ident.kind = .variable - ident.info = ast.IdentVar{} - return ident - } - else { - // handle consts/fns in checker - ident.kind = .unresolved - return { - ident | - name:p.prepend_mod(name) + if p.expr_mod.len == 0 { + if var := p.scope.find_var(name) { + ident.kind = .variable + ident.info = ast.IdentVar{} } } + // handle consts/fns in checker + return ident } fn (p mut Parser) struct_init() ast.StructInit { @@ -565,7 +554,7 @@ pub fn (p mut Parser) name_expr() ast.Expr { map_type := p.parse_map_type() return node } - if p.peek_tok.kind == .dot && (is_c || p.known_import(p.tok.lit)) { + if p.peek_tok.kind == .dot && (is_c || p.known_import(p.tok.lit) || p.mod.all_after('.') == p.tok.lit) { if !is_c { // prepend the full import mod = p.imports[p.tok.lit] @@ -998,11 +987,8 @@ fn (p mut Parser) for_statement() ast.Stmt { mut init := ast.Stmt{} mut cond := ast.Expr{} mut inc := ast.Stmt{} - if p.peek_tok.kind == .decl_assign { - init = p.var_decl() - } - else if p.peek_tok.kind == .assign { - init = p.assign_stmt() + if p.peek_tok.kind in [.assign, .decl_assign] { + init = p.var_decl_and_assign_stmt() } else if p.tok.kind != .semicolon {} // allow `for ;; i++ {` @@ -1528,11 +1514,23 @@ fn (p mut Parser) return_stmt() ast.Return { return stmt } -pub fn (p mut Parser) assign_stmt() ast.AssignStmt { - // TODO: multiple return & multiple assign +// left hand side of `=` or `:=` in `a,b,c := 1,2,3` +fn (p mut Parser) parse_assign_lhs() []ast.Ident { mut idents := []ast.Ident for { - ident := p.parse_ident(false) + is_mut := p.tok.kind == .key_mut + if is_mut { + p.check(.key_mut) + } + is_static := p.tok.kind == .key_static + if is_static { + p.check(.key_static) + } + mut ident := p.parse_ident(false) + ident.info = ast.IdentVar{ + is_mut: is_mut + is_static: is_static + } idents << ident if p.tok.kind == .comma { p.check(.comma) @@ -1541,10 +1539,63 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt { break } } + return idents +} + +// right hand side of `=` or `:=` in `a,b,c := 1,2,3` +fn (p mut Parser) parse_assign_rhs() []ast.Expr { + mut exprs := []ast.Expr + for { + expr,_ := p.expr(0) + exprs << expr + if p.tok.kind == .comma { + p.check(.comma) + } + else { + break + } + } + return exprs +} + +fn (p mut Parser) var_decl_and_assign_stmt() ast.Stmt { + idents := p.parse_assign_lhs() op := p.tok.kind p.next() // :=, = - expr,_ := p.expr(0) + exprs := p.parse_assign_rhs() is_decl := op == .decl_assign + // VarDecl + if idents.len == 1 { + ident := idents[0] + expr := exprs[0] + info0 := ident.var_info() + known_var := p.scope.known_var(ident.name) + if !is_decl && !known_var { + p.error('unknown variable `$ident.name`') + } + if is_decl && ident.kind != .blank_ident { + if known_var { + p.error('redefinition of `$ident.name`') + } + p.scope.register_var(ast.VarDecl{ + name: ident.name + expr: expr + }) + } + return ast.VarDecl{ + name: ident.name + // name2: name2 + + expr: expr // p.expr(token.lowest_prec) + + is_mut: info0.is_mut + // typ: typ + + pos: p.tok.position() + } + // return p.var_decl(ident[0], exprs[0]) + } + // AssignStmt for ident in idents { if is_decl && ident.kind != .blank_ident { if p.scope.known_var(ident.name) { @@ -1557,65 +1608,14 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt { } return ast.AssignStmt{ left: idents - right: [expr] + right: exprs op: op pos: p.tok.position() } } -fn (p mut Parser) var_decl() ast.VarDecl { - is_mut := p.tok.kind == .key_mut // || p.prev_tok == .key_for - // is_static := p.tok.kind == .key_static - if p.tok.kind == .key_mut { - p.check(.key_mut) - // p.fspace() - } - if p.tok.kind == .key_static { - p.check(.key_static) - // p.fspace() - } - name := p.check_name() - mut name2 := '' - if p.tok.kind == .comma { - p.check(.comma) - name2 = p.check_name() - } - p.next() // := - // expr,typ := p.expr(0) - expr,_ := p.expr(0) - // if _ := p.table.find_var(name) { - // p.error('redefinition of `$name`') - // } - // p.table.register_var(table.Var{ - // name: name - // is_mut: is_mut - // typ: typ - // }) - if _ := p.scope.find_var(name) { - p.error('redefinition of `$name`') - } - // p.scope.register_var(table.Var{ - // name: name - // is_mut: is_mut - // typ: typ - // }) - // typ_sym := p.table.get_type_symbol(typ) - // p.warn('var decl name=$name typ=$typ_sym.name') - // println(p.table.names) - node := ast.VarDecl{ - name: name - name2: name2 - expr: expr // p.expr(token.lowest_prec) - - is_mut: is_mut - // typ: typ - - pos: p.tok.position() - } - p.scope.register_var(node) - return node -} - +// pub fn (p mut Parser) assign_stmt() ast.AssignStmt {} +// fn (p mut Parser) var_decl() ast.VarDecl {} fn (p mut Parser) hash() ast.HashStmt { p.next() return ast.HashStmt{ diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 15f0cd4551..832ed0122f 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -370,6 +370,10 @@ pub fn (t &Table) check(got, expected Type) bool { if got_type_sym.is_number() && exp_type_sym.is_number() { return true } + // check hack in checker IndexExpr line #691 + if type_is_ptr(got) && got_type_sym.kind == .byte && exp_type_sym.kind == .byteptr { + return true + } // TODO // if got_type_sym.kind == .array && exp_type_sym.kind == .array { // return true diff --git a/vlib/v/table/types.v b/vlib/v/table/types.v index c194e4d3bd..14e20b2128 100644 --- a/vlib/v/table/types.v +++ b/vlib/v/table/types.v @@ -98,7 +98,7 @@ pub fn new_type_ptr(idx int, nr_muls int) Type { } pub const ( - number_idxs = [int_type_idx, byte_type_idx, u64_type_idx] + number_idxs = [int_type_idx, byte_type_idx, u32_type_idx, u64_type_idx] ) /*