cgen: fix mutliple_assign swap
parent
64173c792f
commit
bb48851092
|
@ -538,6 +538,7 @@ pub mut:
|
|||
left_types []table.Type
|
||||
right_types []table.Type
|
||||
is_static bool // for translated code only
|
||||
has_cross_var bool
|
||||
}
|
||||
|
||||
pub struct AsCast {
|
||||
|
|
|
@ -384,10 +384,8 @@ typedef struct {
|
|||
.alias {
|
||||
parent := &g.table.types[typ.parent_idx]
|
||||
styp := typ.name.replace('.', '__')
|
||||
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('.',
|
||||
'__') }
|
||||
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('.', '__') }
|
||||
g.definitions.writeln('typedef $parent_styp $styp;')
|
||||
}
|
||||
.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()
|
||||
expected_is_ptr := expected_type.is_ptr()
|
||||
neither_void := table.voidptr_type !in [got_type, expected_type]
|
||||
if got_is_ptr && !expected_is_ptr && neither_void && expected_sym.kind !in [.interface_,
|
||||
.placeholder
|
||||
] {
|
||||
if got_is_ptr && !expected_is_ptr && neither_void && expected_sym.kind !in [.interface_, .placeholder] {
|
||||
got_deref_type := got_type.deref()
|
||||
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]
|
||||
|
@ -905,8 +901,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
if return_type != table.void_type && return_type != 0 {
|
||||
sym := g.table.get_type_symbol(return_type)
|
||||
// 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 >
|
||||
1 {
|
||||
if sym.kind == .multi_return || assign_stmt.left.len > assign_stmt.right.len || assign_stmt.left.len > 1 {
|
||||
// multi return
|
||||
// TODO Handle in if_expr
|
||||
is_optional := return_type.flag_is(.optional)
|
||||
|
@ -942,6 +937,12 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
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`
|
||||
for i, ident in assign_stmt.left {
|
||||
val := assign_stmt.right[i]
|
||||
|
@ -1042,7 +1043,11 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
if is_decl {
|
||||
g.expr(val)
|
||||
} else {
|
||||
g.expr_with_cast(val, assign_stmt.left_types[i], ident_var_info.typ)
|
||||
if assign_stmt.has_cross_var {
|
||||
g.gen_cross_tmp_variable(assign_stmt.left, val)
|
||||
} else {
|
||||
g.expr_with_cast(val, assign_stmt.left_types[i], ident_var_info.typ)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
mut is_fixed_array_init := false
|
||||
mut has_val := false
|
||||
|
@ -1797,8 +1828,7 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
|
|||
g.writeln('// match 0')
|
||||
return
|
||||
}
|
||||
is_expr := (node.is_expr && node.return_type != table.void_type) || g.inside_ternary >
|
||||
0
|
||||
is_expr := (node.is_expr && node.return_type != table.void_type) || g.inside_ternary > 0
|
||||
if is_expr {
|
||||
g.inside_ternary++
|
||||
// g.write('/* EM ret type=${g.typ(node.return_type)} expected_type=${g.typ(node.expected_type)} */')
|
||||
|
|
|
@ -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 {
|
||||
mut idents := known_lhs
|
||||
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()
|
||||
exprs := p.parse_assign_rhs()
|
||||
is_decl := op == .decl_assign
|
||||
mut has_cross_var := false
|
||||
if is_decl {
|
||||
// a, b := a + 1, b
|
||||
for expr in exprs {
|
||||
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 {
|
||||
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
|
||||
pos: pos
|
||||
is_static: false // individual idents may be static
|
||||
has_cross_var: has_cross_var
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,3 +4,33 @@ fn test_multiple_assign() {
|
|||
assert b == 2
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue