From 6c5b638202c14cc4127cedeaaf64cc1dc8c5ddfc Mon Sep 17 00:00:00 2001 From: yuyi Date: Wed, 1 Jul 2020 18:11:03 +0800 Subject: [PATCH] parser: fix array cross assign (fix #5577) (#5591) --- vlib/builtin/array_test.v | 13 +++++++++++++ vlib/v/ast/ast.v | 1 + vlib/v/gen/cgen.v | 30 +++++++++++++++++++++++++++++- vlib/v/parser/assign.v | 19 +++++++++++++++++-- vlib/v/parser/parser.v | 2 ++ vlib/v/scanner/scanner.v | 4 ++++ 6 files changed, 66 insertions(+), 3 deletions(-) diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index ffde01cce7..063a04df67 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -877,3 +877,16 @@ fn test_plus_assign_string() { a[0] += 'abc' assert a == ['abc'] } + +fn test_cross_assign() { + mut a := [0, 1] + a[0], a[1] = a[1], a[0] + assert a[0] == 1 + assert a[1] == 0 + + mut b1 := [1, 2, 3] + mut b2 := 4 + b1[2], b2, b1[0] = b1[0], b1[2], 5 + assert b1 == [5, 2, 1] + assert b2 == 3 +} diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 272ea22c75..e9b1ddcfac 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -410,6 +410,7 @@ pub: pub struct IndexExpr { pub: pos token.Position + expr string // a[0] m['a'] etc left Expr index Expr // [0], [start..end] etc pub mut: diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 69e3a5fac9..187e5fc251 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -683,7 +683,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { println('build module `$g.module_built` fn `$node.name`') } } - keep_fn_decl := g.fn_decl + keep_fn_decl := g.fn_decl g.fn_decl = node if node.name == 'main.main' { g.has_main = true @@ -1089,6 +1089,18 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { styp := g.typ(assign_stmt.left_types[i]) g.writeln('$styp _var_$left.pos.pos = $left.name;') } + ast.IndexExpr { + sym := g.table.get_type_symbol(left.left_type) + if sym.kind == .array { + info := sym.info as table.Array + styp := g.typ(info.elem_type) + g.write('$styp _var_$left.pos.pos = *($styp*)array_get(') + g.expr(it.left) + g.write(', ') + g.expr(it.index) + g.writeln(');') + } + } else {} } } @@ -1286,6 +1298,22 @@ fn (mut g Gen) gen_cross_tmp_variable(left []ast.Expr, val ast.Expr) { g.expr(val_) } } + ast.IndexExpr { + mut has_var := false + for lx in left { + if lx is ast.IndexExpr { + inx := lx as ast.IndexExpr + if val.expr == inx.expr { + g.write('_var_$inx.pos.pos') + has_var = true + break + } + } + } + if !has_var { + g.expr(val_) + } + } ast.InfixExpr { g.gen_cross_tmp_variable(left, val.left) g.write(val.op.str()) diff --git a/vlib/v/parser/assign.v b/vlib/v/parser/assign.v index 9878c45c65..18a105506a 100644 --- a/vlib/v/parser/assign.v +++ b/vlib/v/parser/assign.v @@ -45,14 +45,26 @@ fn (mut p Parser) check_undefined_variables(exprs []ast.Expr, val ast.Expr) { fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool { match val { - ast.Ident { for expr in exprs { + ast.Ident { + for expr in exprs { if expr is ast.Ident { ident := expr as ast.Ident 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 + } + } + } + } 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) } @@ -77,6 +89,9 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr) ast.Stmt { // a, b = b, a for r in right { has_cross_var = p.check_cross_variables(left, r) + if has_cross_var { + break + } } } for i, lx in left { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 9f96bae31e..d6ed7ea511 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -985,10 +985,12 @@ fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr { } } // [expr] + end := p.tok.position() p.check(.rsbr) return ast.IndexExpr{ left: left index: expr + expr: p.scanner.expr_string(left.position(), end).replace(' ', '') pos: p.tok.position() } } diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 59dc376c8f..0745bd86d0 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -1379,3 +1379,7 @@ pub fn (mut s Scanner) codegen(newtext string) { } } } + +pub fn (s Scanner) expr_string(start, end token.Position) string { + return s.text[start.pos..end.pos].trim_space() +}