v/vlib/v/parser/assign.v

161 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 {
2020-05-15 23:14:53 +02:00
return p.partial_assign_stmt([])
}
2020-05-25 11:31:04 +02:00
fn (mut p Parser) check_undefined_variables(idents []ast.Ident, expr ast.Expr) {
match expr {
ast.Ident {
for ident in idents {
if ident.name == it.name {
p.error_with_pos('undefined variable: `$it.name`', it.pos)
}
}
}
ast.InfixExpr {
2020-05-25 11:31:04 +02:00
p.check_undefined_variables(idents, it.left)
p.check_undefined_variables(idents, it.right)
}
ast.StringInterLiteral {
for expr_ in it.exprs {
p.check_undefined_variables(idents, expr_)
}
}
else {}
}
}
2020-05-26 18:00:51 +02:00
fn (mut p Parser) check_cross_variables(idents []ast.Ident, expr ast.Expr) bool {
match expr {
ast.Ident {
for ident in idents {
if ident.name == it.name { return true }
2020-05-26 18:00:51 +02:00
}
}
ast.InfixExpr {
if p.check_cross_variables(idents, it.left) { return true }
if p.check_cross_variables(idents, it.right) { return true }
2020-05-26 18:00:51 +02:00
}
ast.PrefixExpr {
if p.check_cross_variables(idents, it.right) { return true }
}
ast.PostfixExpr {
if p.check_cross_variables(idents, it.expr) { return true }
2020-05-26 18:00:51 +02:00
}
else {}
}
return false
}
2020-05-15 23:14:53 +02:00
fn (mut p Parser) partial_assign_stmt(known_lhs []ast.Ident) ast.Stmt {
mut idents := known_lhs
mut op := p.tok.kind
// read (more) idents until assignment sign
for op !in [.decl_assign, .assign] {
idents << p.parse_assign_ident()
if p.tok.kind == .comma {
p.next()
}
op = p.tok.kind
}
2020-05-15 23:14:53 +02:00
p.next()
pos := p.tok.position()
exprs := p.parse_assign_rhs()
is_decl := op == .decl_assign
2020-05-26 18:00:51 +02:00
mut has_cross_var := false
if is_decl {
// a, b := a + 1, b
for expr in exprs {
2020-05-25 11:31:04 +02:00
p.check_undefined_variables(idents, expr)
}
2020-05-26 18:00:51 +02:00
} else if idents.len > 1 {
// a, b = b, a
for expr in exprs {
if p.check_cross_variables(idents, expr) {
has_cross_var = true
}
}
}
for i, ident in idents {
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 p.scope.known_var(ident.name) {
p.error('redefinition of `$ident.name`')
}
if idents.len == exprs.len {
p.scope.register(ident.name, ast.Var{
name: ident.name
expr: exprs[i]
is_mut: ident.is_mut || p.inside_for
pos: ident.pos
})
} else {
p.scope.register(ident.name, ast.Var{
name: ident.name
is_mut: ident.is_mut || p.inside_for
pos: ident.pos
})
}
}
}
return ast.AssignStmt{
left: idents
right: exprs
op: op
pos: pos
2020-05-15 23:14:53 +02:00
is_static: false // individual idents may be static
2020-05-26 18:00:51 +02:00
has_cross_var: has_cross_var
}
}
// TODO: is it possible to merge with AssignStmt?
2020-04-23 01:16:58 +02:00
pub fn (mut p Parser) assign_expr(left ast.Expr) ast.AssignExpr {
op := p.tok.kind
pos := p.tok.position()
p.next()
val := p.expr(0)
match left {
ast.IndexExpr {
// it.mark_as_setter()
it.is_setter = true
}
else {}
}
node := ast.AssignExpr{
left: left
val: val
op: op
pos: pos
}
return node
}
2020-05-15 23:14:53 +02:00
fn (mut p Parser) parse_assign_ident() ast.Ident {
/// returns a single parsed ident
return p.parse_ident(.v)
}
// right hand side of `=` or `:=` in `a,b,c := 1,2,3`
2020-04-23 01:16:58 +02:00
fn (mut p Parser) parse_assign_rhs() []ast.Expr {
mut exprs := []ast.Expr{}
for {
expr := p.expr(0)
exprs << expr
if p.tok.kind == .comma {
p.next()
} else {
break
}
}
return exprs
}