v/vlib/v/parser/assign.v

150 lines
3.4 KiB
V
Raw Normal View History

// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module parser
import v.ast
2020-04-23 01:16:58 +02:00
fn (mut p Parser) assign_stmt() ast.Stmt {
return p.partial_assign_stmt(p.expr_list())
2020-05-15 23:14:53 +02:00
}
fn (mut p Parser) check_undefined_variables(exprs []ast.Expr, val ast.Expr) {
match val {
ast.Ident {
for expr in exprs {
if expr is ast.Ident {
ident := expr as ast.Ident
2020-06-27 15:00:28 +02:00
if ident.name == val.name {
p.error_with_pos('undefined variable: `$val.name`', val.pos)
}
}
}
}
ast.InfixExpr {
2020-06-27 15:00:28 +02:00
p.check_undefined_variables(exprs, val.left)
p.check_undefined_variables(exprs, val.right)
2020-05-25 11:31:04 +02:00
}
ast.ParExpr {
2020-06-27 15:00:28 +02:00
p.check_undefined_variables(exprs, val.expr)
}
ast.PostfixExpr {
2020-06-27 15:00:28 +02:00
p.check_undefined_variables(exprs, val.expr)
}
ast.PrefixExpr {
2020-06-27 15:00:28 +02:00
p.check_undefined_variables(exprs, val.right)
}
2020-05-25 11:31:04 +02:00
ast.StringInterLiteral {
2020-06-27 15:00:28 +02:00
for expr_ in val.exprs {
p.check_undefined_variables(exprs, expr_)
2020-05-25 11:31:04 +02:00
}
}
else {}
}
}
fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool {
match val {
ast.Ident {
for expr in exprs {
if expr is ast.Ident {
ident := expr as ast.Ident
2020-06-27 15:00:28 +02:00
if ident.name == val.name {
return true
}
}
}
}
ast.IndexExpr {
for expr in exprs {
if expr is ast.IndexExpr {
idx := expr as ast.IndexExpr
if idx.expr == val.expr {
return true
}
}
}
}
2020-06-27 15:00:28 +02:00
ast.InfixExpr { return p.check_cross_variables(exprs, val.left) || p.check_cross_variables(exprs, val.right) }
ast.PrefixExpr { return p.check_cross_variables(exprs, val.right) }
ast.PostfixExpr { return p.check_cross_variables(exprs, val.expr) }
2020-05-26 18:00:51 +02:00
else {}
}
return false
}
fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt {
p.is_stmt_ident = false
op := p.tok.kind
pos := p.tok.position()
p.next()
right := p.expr_list()
2020-05-26 18:00:51 +02:00
mut has_cross_var := false
if op == .decl_assign {
// a, b := a + 1, b
for r in right {
p.check_undefined_variables(left, r)
}
2020-06-27 15:00:28 +02:00
} else if left.len > 1 {
2020-05-26 18:00:51 +02:00
// a, b = b, a
for r in right {
has_cross_var = p.check_cross_variables(left, r)
if has_cross_var {
break
}
2020-05-26 18:00:51 +02:00
}
}
for i, lx in left {
match lx {
ast.Ident {
if op == .decl_assign {
2020-06-18 22:16:38 +02:00
if p.scope.known_var(lx.name) {
p.error_with_pos('redefinition of `$lx.name`', lx.pos)
}
if left.len == right.len {
2020-06-18 22:16:38 +02:00
p.scope.register(lx.name, ast.Var{
name: lx.name
expr: right[i]
2020-06-18 22:16:38 +02:00
is_mut: lx.is_mut || p.inside_for
pos: lx.pos
})
} else {
2020-06-18 22:16:38 +02:00
p.scope.register(lx.name, ast.Var{
name: lx.name
is_mut: lx.is_mut || p.inside_for
pos: lx.pos
})
}
}
}
ast.IndexExpr {
if op == .decl_assign {
2020-06-27 15:00:28 +02:00
p.error_with_pos('non-name `$lx.left[$lx.index]` on left side of `:=`',
lx.pos)
}
2020-06-18 22:16:38 +02:00
lx.is_setter = true
}
ast.ParExpr {}
ast.PrefixExpr {}
ast.SelectorExpr {
if op == .decl_assign {
2020-06-27 15:00:28 +02:00
p.error_with_pos('struct fields can only be declared during the initialization',
lx.pos)
}
}
2020-06-27 15:00:28 +02:00
else {
// TODO: parexpr ( check vars)
// else { p.error_with_pos('unexpected `${typeof(lx)}`', lx.position()) }
}
}
}
2020-06-27 15:00:28 +02:00
return ast.AssignStmt{
op: op
left: left
right: right
pos: pos
has_cross_var: has_cross_var
is_simple: p.inside_for && p.tok.kind == .lcbr
}
}