cgen: fix mutliple_assign swap

pull/5060/head
yuyi 2020-05-27 00:00:51 +08:00 committed by GitHub
parent 64173c792f
commit bb48851092
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 12 deletions

View File

@ -538,6 +538,7 @@ pub mut:
left_types []table.Type left_types []table.Type
right_types []table.Type right_types []table.Type
is_static bool // for translated code only is_static bool // for translated code only
has_cross_var bool
} }
pub struct AsCast { pub struct AsCast {

View File

@ -384,10 +384,8 @@ typedef struct {
.alias { .alias {
parent := &g.table.types[typ.parent_idx] parent := &g.table.types[typ.parent_idx]
styp := typ.name.replace('.', '__') styp := typ.name.replace('.', '__')
is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == `.`
`.` parent_styp := if is_c_parent { 'struct ' + parent.name[2..].replace('.', '__') } else { parent.name.replace('.', '__') }
parent_styp := if is_c_parent { 'struct ' + parent.name[2..].replace('.', '__') } else { parent.name.replace('.',
'__') }
g.definitions.writeln('typedef $parent_styp $styp;') g.definitions.writeln('typedef $parent_styp $styp;')
} }
.array { .array {
@ -844,9 +842,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, expected_type table.Type)
got_is_ptr := got_type.is_ptr() got_is_ptr := got_type.is_ptr()
expected_is_ptr := expected_type.is_ptr() expected_is_ptr := expected_type.is_ptr()
neither_void := table.voidptr_type !in [got_type, expected_type] neither_void := table.voidptr_type !in [got_type, expected_type]
if got_is_ptr && !expected_is_ptr && neither_void && expected_sym.kind !in [.interface_, if got_is_ptr && !expected_is_ptr && neither_void && expected_sym.kind !in [.interface_, .placeholder] {
.placeholder
] {
got_deref_type := got_type.deref() got_deref_type := got_type.deref()
deref_sym := g.table.get_type_symbol(got_deref_type) deref_sym := g.table.get_type_symbol(got_deref_type)
deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx] deref_will_match := expected_type in [got_type, got_deref_type, deref_sym.parent_idx]
@ -905,8 +901,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
if return_type != table.void_type && return_type != 0 { if return_type != table.void_type && return_type != 0 {
sym := g.table.get_type_symbol(return_type) sym := g.table.get_type_symbol(return_type)
// the left vs. right is ugly and should be removed // the left vs. right is ugly and should be removed
if sym.kind == .multi_return || assign_stmt.left.len > assign_stmt.right.len || assign_stmt.left.len > if sym.kind == .multi_return || assign_stmt.left.len > assign_stmt.right.len || assign_stmt.left.len > 1 {
1 {
// multi return // multi return
// TODO Handle in if_expr // TODO Handle in if_expr
is_optional := return_type.flag_is(.optional) is_optional := return_type.flag_is(.optional)
@ -942,6 +937,12 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
return return
} }
} }
if assign_stmt.has_cross_var {
for ident in assign_stmt.left {
type_str := g.typ(ident.var_info().typ)
g.writeln('$type_str _var_$ident.pos.pos = $ident.name;')
}
}
// `a := 1` | `a,b := 1,2` // `a := 1` | `a,b := 1,2`
for i, ident in assign_stmt.left { for i, ident in assign_stmt.left {
val := assign_stmt.right[i] val := assign_stmt.right[i]
@ -1041,11 +1042,15 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
g.write(' = ') g.write(' = ')
if is_decl { if is_decl {
g.expr(val) g.expr(val)
} else {
if assign_stmt.has_cross_var {
g.gen_cross_tmp_variable(assign_stmt.left, val)
} else { } else {
g.expr_with_cast(val, assign_stmt.left_types[i], ident_var_info.typ) g.expr_with_cast(val, assign_stmt.left_types[i], ident_var_info.typ)
} }
} }
} }
}
g.is_assign_rhs = false g.is_assign_rhs = false
if g.inside_ternary == 0 { if g.inside_ternary == 0 {
g.writeln(';') g.writeln(';')
@ -1053,6 +1058,32 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
} }
} }
fn (mut g Gen) gen_cross_tmp_variable(idents []ast.Ident, val ast.Expr) {
match val {
ast.Ident {
mut has_var := false
for ident in idents {
if it.name == ident.name {
g.write('_var_${ident.pos.pos}')
has_var = true
break
}
}
if !has_var {
g.expr(val)
}
}
ast.InfixExpr {
g.gen_cross_tmp_variable(idents, it.left)
g.write(it.op.str())
g.gen_cross_tmp_variable(idents, it.right)
}
else {
g.expr(val)
}
}
}
fn (mut g Gen) gen_default_init_value(val ast.Expr) (bool, bool) { fn (mut g Gen) gen_default_init_value(val ast.Expr) (bool, bool) {
mut is_fixed_array_init := false mut is_fixed_array_init := false
mut has_val := false mut has_val := false
@ -1797,8 +1828,7 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
g.writeln('// match 0') g.writeln('// match 0')
return return
} }
is_expr := (node.is_expr && node.return_type != table.void_type) || g.inside_ternary > is_expr := (node.is_expr && node.return_type != table.void_type) || g.inside_ternary > 0
0
if is_expr { if is_expr {
g.inside_ternary++ g.inside_ternary++
// g.write('/* EM ret type=${g.typ(node.return_type)} expected_type=${g.typ(node.expected_type)} */') // g.write('/* EM ret type=${g.typ(node.return_type)} expected_type=${g.typ(node.expected_type)} */')

View File

@ -31,6 +31,35 @@ fn (mut p Parser) check_undefined_variables(idents []ast.Ident, expr ast.Expr) {
} }
} }
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
}
}
}
ast.InfixExpr {
if p.check_cross_variables(idents, it.left) {
return true
}
if p.check_cross_variables(idents, it.right) {
return true
}
}
ast.StringInterLiteral {
for expr_ in it.exprs {
if p.check_cross_variables(idents, expr_) {
return true
}
}
}
else {}
}
return false
}
fn (mut p Parser) partial_assign_stmt(known_lhs []ast.Ident) ast.Stmt { fn (mut p Parser) partial_assign_stmt(known_lhs []ast.Ident) ast.Stmt {
mut idents := known_lhs mut idents := known_lhs
mut op := p.tok.kind mut op := p.tok.kind
@ -46,11 +75,19 @@ fn (mut p Parser) partial_assign_stmt(known_lhs []ast.Ident) ast.Stmt {
pos := p.tok.position() pos := p.tok.position()
exprs := p.parse_assign_rhs() exprs := p.parse_assign_rhs()
is_decl := op == .decl_assign is_decl := op == .decl_assign
mut has_cross_var := false
if is_decl { if is_decl {
// a, b := a + 1, b // a, b := a + 1, b
for expr in exprs { for expr in exprs {
p.check_undefined_variables(idents, expr) p.check_undefined_variables(idents, expr)
} }
} 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 { for i, ident in idents {
known_var := p.scope.known_var(ident.name) known_var := p.scope.known_var(ident.name)
@ -83,6 +120,7 @@ fn (mut p Parser) partial_assign_stmt(known_lhs []ast.Ident) ast.Stmt {
op: op op: op
pos: pos pos: pos
is_static: false // individual idents may be static is_static: false // individual idents may be static
has_cross_var: has_cross_var
} }
} }

View File

@ -4,3 +4,33 @@ fn test_multiple_assign() {
assert b == 2 assert b == 2
assert c == 3 assert c == 3
} }
fn test_multiple_assign_swap_simple() {
mut a := 11
mut b := 22
a, b = b, a
assert a == 22
assert b == 11
}
fn test_multiple_assign_swap_complex() {
mut a := 11
mut b := 22
mut c := 33
mut d := 44
a, b, c, d = b, a, d, c
assert a == 22
assert b == 11
assert c == 44
assert d == 33
}
fn test_multiple_assign_infix_expr() {
mut a := 11
mut b := 22
mut c := 33
a, b, c = b + 1, a * 2, c - a
assert a == 23
assert b == 22
assert c == 22
}