parser: fix array cross assign (fix #5577) (#5591)

pull/5602/head
yuyi 2020-07-01 18:11:03 +08:00 committed by GitHub
parent 7386adfc99
commit 6c5b638202
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 66 additions and 3 deletions

View File

@ -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
}

View File

@ -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:

View File

@ -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())

View File

@ -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 {

View File

@ -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()
}
}

View File

@ -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()
}