1// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. 2// Use of this source code is governed by an MIT license 3// that can be found in the LICENSE file. 4module parser 5 6import v.ast 7import v.table 8 9fn (mut p Parser) assign_stmt() ast.Stmt { 10 exprs, comments := p.expr_list() 11 return p.partial_assign_stmt(exprs, comments) 12} 13 14fn (mut p Parser) check_undefined_variables(exprs []ast.Expr, val ast.Expr) { 15 match val { 16 ast.Ident { 17 for expr in exprs { 18 if expr is ast.Ident { 19 if expr.name == val.name { 20 p.error_with_pos('undefined variable: `$val.name`', val.pos) 21 } 22 } 23 } 24 } 25 ast.InfixExpr { 26 p.check_undefined_variables(exprs, val.left) 27 p.check_undefined_variables(exprs, val.right) 28 } 29 ast.ParExpr { 30 p.check_undefined_variables(exprs, val.expr) 31 } 32 ast.PostfixExpr { 33 p.check_undefined_variables(exprs, val.expr) 34 } 35 ast.PrefixExpr { 36 p.check_undefined_variables(exprs, val.right) 37 } 38 ast.StringInterLiteral { 39 for expr_ in val.exprs { 40 p.check_undefined_variables(exprs, expr_) 41 } 42 } 43 else {} 44 } 45} 46 47fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool { 48 val_ := val 49 match val_ { 50 ast.Ident { 51 for expr in exprs { 52 if expr is ast.Ident { 53 if expr.name == val_.name { 54 return true 55 } 56 } 57 } 58 } 59 ast.IndexExpr { 60 for expr in exprs { 61 if expr.str() == val.str() { 62 return true 63 } 64 } 65 } 66 ast.InfixExpr { return p.check_cross_variables(exprs, val_.left) || p.check_cross_variables(exprs, val_.right) } 67 ast.PrefixExpr { return p.check_cross_variables(exprs, val_.right) } 68 ast.PostfixExpr { return p.check_cross_variables(exprs, val_.expr) } 69 ast.SelectorExpr { 70 for expr in exprs { 71 if expr.str() == val.str() { 72 return true 73 } 74 } 75 } 76 else {} 77 } 78 return false 79} 80 81fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comment) ast.Stmt { 82 p.is_stmt_ident = false 83 op := p.tok.kind 84 pos := p.tok.position() 85 p.next() 86 right, right_comments := p.expr_list() 87 mut comments := []ast.Comment{cap: left_comments.len + right_comments.len} 88 comments << left_comments 89 comments << right_comments 90 mut has_cross_var := false 91 if op == .decl_assign { 92 // a, b := a + 1, b 93 for r in right { 94 p.check_undefined_variables(left, r) 95 } 96 } else if left.len > 1 { 97 // a, b = b, a 98 for r in right { 99 has_cross_var = p.check_cross_variables(left, r) 100 if op !in [.assign, .decl_assign] { 101 p.error('unexpected $op.str(), expecting := or = or comma') 102 } 103 if has_cross_var { 104 break 105 } 106 } 107 } 108 for i, lx in left { 109 match mut lx { 110 ast.Ident { 111 if op == .decl_assign { 112 if p.scope.known_var(lx.name) { 113 p.error_with_pos('redefinition of `$lx.name`', lx.pos) 114 } 115 mut share := table.ShareType(0) 116 if lx.info is ast.IdentVar { 117 share = (lx.info as ast.IdentVar).share 118 } 119 mut v := ast.Var{ 120 name: lx.name 121 expr: if left.len == right.len { right[i] } else { ast.Expr{} } 122 share: share 123 is_mut: lx.is_mut || p.inside_for 124 pos: lx.pos 125 } 126 obj := ast.ScopeObject(v) 127 lx.obj = obj 128 p.scope.register(lx.name, obj) 129 } 130 } 131 ast.IndexExpr { 132 if op == .decl_assign { 133 p.error_with_pos('non-name `$lx.left[$lx.index]` on left side of `:=`', 134 lx.pos) 135 } 136 lx.is_setter = true 137 } 138 ast.ParExpr {} 139 ast.PrefixExpr {} 140 ast.SelectorExpr { 141 if op == .decl_assign { 142 p.error_with_pos('struct fields can only be declared during the initialization', 143 lx.pos) 144 } 145 } 146 else { 147 // TODO: parexpr ( check vars) 148 // else { p.error_with_pos('unexpected `${typeof(lx)}`', lx.position()) } 149 } 150 } 151 } 152 return ast.AssignStmt{ 153 op: op 154 left: left 155 right: right 156 comments: comments 157 pos: pos 158 has_cross_var: has_cross_var 159 is_simple: p.inside_for && p.tok.kind == .lcbr 160 } 161} 162