2022-01-04 10:21:08 +01:00
|
|
|
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
2020-04-17 18:16:55 +02:00
|
|
|
// 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 {
|
2021-05-31 13:43:44 +02:00
|
|
|
mut defer_vars := p.defer_vars
|
|
|
|
p.defer_vars = []ast.Ident{}
|
|
|
|
|
2020-07-17 19:13:22 +02:00
|
|
|
exprs, comments := p.expr_list()
|
2021-05-31 13:43:44 +02:00
|
|
|
|
|
|
|
if !(p.inside_defer && p.tok.kind == .decl_assign) {
|
|
|
|
defer_vars << p.defer_vars
|
|
|
|
}
|
|
|
|
p.defer_vars = defer_vars
|
2020-07-17 19:13:22 +02:00
|
|
|
return p.partial_assign_stmt(exprs, comments)
|
2020-05-15 23:14:53 +02:00
|
|
|
}
|
|
|
|
|
2022-02-17 08:21:03 +01:00
|
|
|
const max_expr_level = 100
|
2021-12-27 11:30:17 +01:00
|
|
|
|
2020-12-04 19:34:05 +01:00
|
|
|
fn (mut p Parser) check_undefined_variables(exprs []ast.Expr, val ast.Expr) ? {
|
2021-12-27 11:30:17 +01:00
|
|
|
p.expr_level++
|
|
|
|
defer {
|
|
|
|
p.expr_level--
|
|
|
|
}
|
|
|
|
if p.expr_level > parser.max_expr_level {
|
|
|
|
return error('expr level > $parser.max_expr_level')
|
|
|
|
}
|
2020-11-25 12:09:40 +01:00
|
|
|
match val {
|
2020-05-24 19:33:53 +02:00
|
|
|
ast.Ident {
|
2020-06-16 13:20:16 +02:00
|
|
|
for expr in exprs {
|
|
|
|
if expr is ast.Ident {
|
2021-07-11 18:09:35 +02:00
|
|
|
if expr.name == val.name && expr.kind != .blank_ident {
|
2020-06-27 15:00:28 +02:00
|
|
|
p.error_with_pos('undefined variable: `$val.name`', val.pos)
|
2020-12-04 19:34:05 +01:00
|
|
|
return error('undefined variable: `$val.name`')
|
2020-06-16 13:20:16 +02:00
|
|
|
}
|
2020-05-24 19:33:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-11 02:49:07 +02:00
|
|
|
ast.ArrayInit {
|
|
|
|
if val.has_cap {
|
|
|
|
p.check_undefined_variables(exprs, val.cap_expr) ?
|
|
|
|
}
|
|
|
|
if val.has_len {
|
|
|
|
p.check_undefined_variables(exprs, val.len_expr) ?
|
|
|
|
}
|
|
|
|
if val.has_default {
|
|
|
|
p.check_undefined_variables(exprs, val.default_expr) ?
|
|
|
|
}
|
2021-07-11 18:09:35 +02:00
|
|
|
for expr in val.exprs {
|
|
|
|
p.check_undefined_variables(exprs, expr) ?
|
|
|
|
}
|
2021-07-11 02:49:07 +02:00
|
|
|
}
|
2021-01-27 13:52:10 +01:00
|
|
|
ast.CallExpr {
|
|
|
|
p.check_undefined_variables(exprs, val.left) ?
|
2021-02-08 15:55:01 +01:00
|
|
|
for arg in val.args {
|
|
|
|
p.check_undefined_variables(exprs, arg.expr) ?
|
|
|
|
}
|
2021-01-27 13:52:10 +01:00
|
|
|
}
|
2020-05-24 19:33:53 +02:00
|
|
|
ast.InfixExpr {
|
2020-12-04 19:34:05 +01:00
|
|
|
p.check_undefined_variables(exprs, val.left) ?
|
|
|
|
p.check_undefined_variables(exprs, val.right) ?
|
2020-05-25 11:31:04 +02:00
|
|
|
}
|
2022-03-04 09:33:14 +01:00
|
|
|
ast.IfExpr {
|
|
|
|
p.check_undefined_variables(exprs, val.left) ?
|
|
|
|
for branch in val.branches {
|
|
|
|
p.check_undefined_variables(exprs, branch.cond) ?
|
|
|
|
for stmt in branch.stmts {
|
|
|
|
if stmt is ast.ExprStmt {
|
|
|
|
p.check_undefined_variables(exprs, stmt.expr) ?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-11 18:09:35 +02:00
|
|
|
ast.MapInit {
|
|
|
|
for key in val.keys {
|
|
|
|
p.check_undefined_variables(exprs, key) ?
|
|
|
|
}
|
|
|
|
for value in val.vals {
|
|
|
|
p.check_undefined_variables(exprs, value) ?
|
|
|
|
}
|
|
|
|
}
|
2022-03-04 09:33:14 +01:00
|
|
|
ast.MatchExpr {
|
|
|
|
p.check_undefined_variables(exprs, val.cond) ?
|
|
|
|
for branch in val.branches {
|
|
|
|
for expr in branch.exprs {
|
|
|
|
p.check_undefined_variables(exprs, expr) ?
|
|
|
|
}
|
|
|
|
for stmt in branch.stmts {
|
|
|
|
if stmt is ast.ExprStmt {
|
|
|
|
p.check_undefined_variables(exprs, stmt.expr) ?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-29 17:38:40 +02:00
|
|
|
ast.ParExpr {
|
2020-12-04 19:34:05 +01:00
|
|
|
p.check_undefined_variables(exprs, val.expr) ?
|
2020-05-29 17:38:40 +02:00
|
|
|
}
|
|
|
|
ast.PostfixExpr {
|
2020-12-04 19:34:05 +01:00
|
|
|
p.check_undefined_variables(exprs, val.expr) ?
|
2020-05-29 17:38:40 +02:00
|
|
|
}
|
|
|
|
ast.PrefixExpr {
|
2020-12-04 19:34:05 +01:00
|
|
|
p.check_undefined_variables(exprs, val.right) ?
|
2020-05-29 17:38:40 +02:00
|
|
|
}
|
2020-05-25 11:31:04 +02:00
|
|
|
ast.StringInterLiteral {
|
2020-06-27 15:00:28 +02:00
|
|
|
for expr_ in val.exprs {
|
2020-12-04 19:34:05 +01:00
|
|
|
p.check_undefined_variables(exprs, expr_) ?
|
2020-05-25 11:31:04 +02:00
|
|
|
}
|
2020-05-24 19:33:53 +02:00
|
|
|
}
|
2022-02-17 08:21:03 +01:00
|
|
|
ast.StructInit {
|
2022-02-17 09:16:52 +01:00
|
|
|
for field in val.fields {
|
2022-02-17 08:21:03 +01:00
|
|
|
p.check_undefined_variables(exprs, field.expr) ?
|
|
|
|
}
|
|
|
|
}
|
2020-05-24 19:33:53 +02:00
|
|
|
else {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 13:20:16 +02:00
|
|
|
fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool {
|
2021-07-12 11:10:42 +02:00
|
|
|
val_str := val.str()
|
|
|
|
match val {
|
2020-07-01 12:11:03 +02:00
|
|
|
ast.Ident {
|
|
|
|
for expr in exprs {
|
2020-06-16 13:20:16 +02:00
|
|
|
if expr is ast.Ident {
|
2021-07-12 11:10:42 +02:00
|
|
|
if expr.name == val.name {
|
2020-06-27 15:00:28 +02:00
|
|
|
return true
|
|
|
|
}
|
2020-06-16 13:20:16 +02:00
|
|
|
}
|
2020-07-01 12:11:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.IndexExpr {
|
|
|
|
for expr in exprs {
|
2021-07-12 11:10:42 +02:00
|
|
|
if expr.str() == val_str {
|
2020-07-01 16:43:13 +02:00
|
|
|
return true
|
2020-07-01 12:11:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-15 22:12:59 +02:00
|
|
|
ast.InfixExpr {
|
2021-07-12 11:10:42 +02:00
|
|
|
return p.check_cross_variables(exprs, val.left)
|
|
|
|
|| p.check_cross_variables(exprs, val.right)
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
|
|
|
ast.PrefixExpr {
|
2021-07-12 11:10:42 +02:00
|
|
|
return p.check_cross_variables(exprs, val.right)
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
|
|
|
ast.PostfixExpr {
|
2021-07-12 11:10:42 +02:00
|
|
|
return p.check_cross_variables(exprs, val.expr)
|
2020-10-15 22:12:59 +02:00
|
|
|
}
|
2020-07-01 18:43:14 +02:00
|
|
|
ast.SelectorExpr {
|
|
|
|
for expr in exprs {
|
2021-07-12 11:10:42 +02:00
|
|
|
if expr.str() == val_str {
|
2020-07-01 18:43:14 +02:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-26 18:00:51 +02:00
|
|
|
else {}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-07-17 19:13:22 +02:00
|
|
|
fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comment) ast.Stmt {
|
2020-06-16 13:20:16 +02:00
|
|
|
p.is_stmt_ident = false
|
|
|
|
op := p.tok.kind
|
2022-01-26 11:36:28 +01:00
|
|
|
mut pos := p.tok.pos()
|
2020-06-16 13:20:16 +02:00
|
|
|
p.next()
|
2021-01-15 18:47:49 +01:00
|
|
|
mut comments := []ast.Comment{cap: 2 * left_comments.len + 1}
|
|
|
|
comments << left_comments
|
2021-07-20 10:17:08 +02:00
|
|
|
comments << p.eat_comments()
|
2021-01-15 13:45:26 +01:00
|
|
|
mut right_comments := []ast.Comment{}
|
|
|
|
mut right := []ast.Expr{cap: left.len}
|
2021-02-22 14:08:52 +01:00
|
|
|
right, right_comments = p.expr_list()
|
2020-07-17 19:13:22 +02:00
|
|
|
comments << right_comments
|
2021-02-08 17:16:02 +01:00
|
|
|
end_comments := p.eat_comments(same_line: true)
|
2020-05-26 18:00:51 +02:00
|
|
|
mut has_cross_var := false
|
2020-10-09 21:20:58 +02:00
|
|
|
mut is_static := false
|
2021-09-22 12:06:30 +02:00
|
|
|
mut is_volatile := false
|
2022-03-13 08:53:29 +01:00
|
|
|
for i, lx_ in left {
|
|
|
|
mut lx := unsafe { lx_ }
|
2020-11-25 12:09:40 +01:00
|
|
|
match mut lx {
|
2020-06-16 13:20:16 +02:00
|
|
|
ast.Ident {
|
|
|
|
if op == .decl_assign {
|
2020-06-18 22:16:38 +02:00
|
|
|
if p.scope.known_var(lx.name) {
|
2021-03-30 09:33:29 +02:00
|
|
|
return p.error_with_pos('redefinition of `$lx.name`', lx.pos)
|
2020-06-18 22:16:38 +02:00
|
|
|
}
|
2021-04-02 00:57:09 +02:00
|
|
|
mut share := ast.ShareType(0)
|
2022-03-03 09:48:31 +01:00
|
|
|
if mut lx.info is ast.IdentVar {
|
|
|
|
share = lx.info.share
|
|
|
|
if lx.info.is_static {
|
2022-02-05 23:16:02 +01:00
|
|
|
if !p.pref.translated && !p.is_translated && !p.pref.is_fmt
|
|
|
|
&& !p.inside_unsafe_fn {
|
|
|
|
return p.error_with_pos('static variables are supported only in translated mode or in [unsafe] fn',
|
2020-10-15 22:12:59 +02:00
|
|
|
lx.pos)
|
2020-10-09 21:20:58 +02:00
|
|
|
}
|
|
|
|
is_static = true
|
|
|
|
}
|
2022-03-03 09:48:31 +01:00
|
|
|
if lx.info.is_volatile {
|
2021-09-22 12:06:30 +02:00
|
|
|
is_volatile = true
|
|
|
|
}
|
2020-07-04 12:44:25 +02:00
|
|
|
}
|
2020-12-04 18:06:53 +01:00
|
|
|
r0 := right[0]
|
2020-07-22 18:10:31 +02:00
|
|
|
mut v := ast.Var{
|
|
|
|
name: lx.name
|
2021-03-31 10:13:15 +02:00
|
|
|
expr: if left.len == right.len { right[i] } else { ast.empty_expr() }
|
2020-07-22 18:10:31 +02:00
|
|
|
share: share
|
2021-02-28 18:38:22 +01:00
|
|
|
is_mut: lx.is_mut || p.inside_for
|
2020-07-22 18:10:31 +02:00
|
|
|
pos: lx.pos
|
2021-04-25 20:40:38 +02:00
|
|
|
is_stack_obj: p.inside_for
|
2020-06-16 13:20:16 +02:00
|
|
|
}
|
2020-12-04 18:06:53 +01:00
|
|
|
if p.pref.autofree {
|
|
|
|
if r0 is ast.CallExpr {
|
|
|
|
// Set correct variable position (after the or block)
|
|
|
|
// so that autofree doesn't free it in cgen before
|
|
|
|
// it's declared. (`Or` variables are declared after the or block).
|
2020-12-04 20:44:33 +01:00
|
|
|
if r0.or_block.pos.pos > 0 && r0.or_block.stmts.len > 0 {
|
2020-12-04 18:06:53 +01:00
|
|
|
v.is_or = true
|
|
|
|
// v.pos = r0.or_block.pos.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-22 18:10:31 +02:00
|
|
|
obj := ast.ScopeObject(v)
|
|
|
|
lx.obj = obj
|
2020-12-02 14:40:25 +01:00
|
|
|
p.scope.register(obj)
|
2020-06-16 13:20:16 +02:00
|
|
|
}
|
2020-04-17 18:16:55 +02:00
|
|
|
}
|
2020-06-16 13:20:16 +02:00
|
|
|
ast.IndexExpr {
|
2020-06-20 14:30:03 +02:00
|
|
|
if op == .decl_assign {
|
2021-03-30 09:33:29 +02:00
|
|
|
return p.error_with_pos('non-name `$lx.left[$lx.index]` on left side of `:=`',
|
2020-06-27 15:00:28 +02:00
|
|
|
lx.pos)
|
2020-06-20 14:30:03 +02:00
|
|
|
}
|
2020-06-18 22:16:38 +02:00
|
|
|
lx.is_setter = true
|
2020-04-17 18:16:55 +02:00
|
|
|
}
|
2020-06-16 13:20:16 +02:00
|
|
|
ast.ParExpr {}
|
|
|
|
ast.PrefixExpr {}
|
|
|
|
ast.SelectorExpr {
|
|
|
|
if op == .decl_assign {
|
2021-03-30 09:33:29 +02:00
|
|
|
return p.error_with_pos('struct fields can only be declared during the initialization',
|
2020-06-27 15:00:28 +02:00
|
|
|
lx.pos)
|
2020-06-16 13:20:16 +02:00
|
|
|
}
|
|
|
|
}
|
2020-06-27 15:00:28 +02:00
|
|
|
else {
|
|
|
|
// TODO: parexpr ( check vars)
|
2022-01-26 11:36:28 +01:00
|
|
|
// else { p.error_with_pos('unexpected `${typeof(lx)}`', lx.pos()) }
|
2020-06-27 15:00:28 +02:00
|
|
|
}
|
2020-04-17 18:16:55 +02:00
|
|
|
}
|
|
|
|
}
|
2021-12-29 12:44:08 +01:00
|
|
|
if op == .decl_assign {
|
|
|
|
// a, b := a + 1, b
|
|
|
|
for r in right {
|
2022-02-11 14:52:33 +01:00
|
|
|
p.check_undefined_variables(left, r) or { return p.error_with_pos(err.msg(), pos) }
|
2021-12-29 12:44:08 +01:00
|
|
|
}
|
|
|
|
} else if left.len > 1 {
|
|
|
|
// a, b = b, a
|
|
|
|
for r in right {
|
|
|
|
has_cross_var = p.check_cross_variables(left, r)
|
|
|
|
if op !in [.assign, .decl_assign] {
|
|
|
|
return p.error_with_pos('unexpected $op.str(), expecting := or = or comma',
|
|
|
|
pos)
|
|
|
|
}
|
|
|
|
if has_cross_var {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-19 14:49:40 +01:00
|
|
|
pos.update_last_line(p.prev_tok.line_nr)
|
2020-06-27 15:00:28 +02:00
|
|
|
return ast.AssignStmt{
|
|
|
|
op: op
|
|
|
|
left: left
|
|
|
|
right: right
|
2020-07-17 19:13:22 +02:00
|
|
|
comments: comments
|
2020-12-11 18:20:24 +01:00
|
|
|
end_comments: end_comments
|
2020-06-27 15:00:28 +02:00
|
|
|
pos: pos
|
|
|
|
has_cross_var: has_cross_var
|
|
|
|
is_simple: p.inside_for && p.tok.kind == .lcbr
|
2020-10-09 21:20:58 +02:00
|
|
|
is_static: is_static
|
2021-09-22 12:06:30 +02:00
|
|
|
is_volatile: is_volatile
|
2020-06-27 15:00:28 +02:00
|
|
|
}
|
2020-04-17 18:16:55 +02:00
|
|
|
}
|