1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: implement for_stmt of multi_init_vars or multi_assign_vars (#8917)

This commit is contained in:
yuyi 2021-02-24 20:58:45 +08:00 committed by GitHub
parent 63ed3c0d41
commit 05a08530ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 152 additions and 61 deletions

View File

@ -766,6 +766,7 @@ pub:
has_cond bool
inc Stmt // i++; i += 2
has_inc bool
is_multi bool // for a,b := 0,1; a < 10; a,b = a+b, a {...}
stmts []Stmt
pos token.Position
pub mut:

View File

@ -1091,74 +1091,21 @@ fn (mut g Gen) stmt(node ast.Stmt) {
prev_branch_parent_pos := g.branch_parent_pos
g.branch_parent_pos = node.pos.pos
g.write_v_source_line_info(node.pos)
g.is_vlines_enabled = false
if node.label.len > 0 {
g.writeln('$node.label:')
}
g.write('for (')
if !node.has_init {
g.write('; ')
} else {
g.stmt(node.init)
// Remove excess return and add space
if g.out.last_n(1) == '\n' {
g.out.go_back(1)
g.empty_line = false
g.write(' ')
}
}
if node.has_cond {
g.expr(node.cond)
}
g.write('; ')
if node.has_inc {
g.stmt(node.inc)
}
g.writeln(') {')
g.is_vlines_enabled = true
g.stmts(node.stmts)
if node.label.len > 0 {
g.writeln('${node.label}__continue: {}')
}
g.writeln('}')
if node.label.len > 0 {
g.writeln('${node.label}__break: {}')
}
g.for_c_stmt(node)
g.branch_parent_pos = prev_branch_parent_pos
}
ast.ForInStmt {
prev_branch_parent_pos := g.branch_parent_pos
g.branch_parent_pos = node.pos.pos
g.write_v_source_line_info(node.pos)
g.for_in(node)
g.for_in_stmt(node)
g.branch_parent_pos = prev_branch_parent_pos
}
ast.ForStmt {
prev_branch_parent_pos := g.branch_parent_pos
g.branch_parent_pos = node.pos.pos
g.write_v_source_line_info(node.pos)
g.is_vlines_enabled = false
if node.label.len > 0 {
g.writeln('$node.label:')
}
g.writeln('for (;;) {')
if !node.is_inf {
g.indent++
g.stmt_path_pos << g.out.len
g.write('if (!(')
g.expr(node.cond)
g.writeln(')) break;')
g.indent--
}
g.is_vlines_enabled = true
g.stmts(node.stmts)
if node.label.len > 0 {
g.writeln('\t${node.label}__continue: {}')
}
g.writeln('}')
if node.label.len > 0 {
g.writeln('${node.label}__break: {}')
}
g.for_stmt(node)
g.branch_parent_pos = prev_branch_parent_pos
}
ast.GlobalDecl {
@ -1286,7 +1233,108 @@ fn (mut g Gen) write_defer_stmts() {
}
}
fn (mut g Gen) for_in(it ast.ForInStmt) {
fn (mut g Gen) for_c_stmt(node ast.ForCStmt) {
if node.is_multi {
g.is_vlines_enabled = false
if node.label.len > 0 {
g.writeln('$node.label:')
}
g.writeln('{')
g.indent++
if node.has_init {
g.stmt(node.init)
}
g.writeln('bool _is_first = true;')
g.writeln('while (true) {')
g.writeln('\tif (_is_first) {')
g.writeln('\t\t_is_first = false;')
g.writeln('\t} else {')
if node.has_inc {
g.indent++
g.stmt(node.inc)
g.writeln(';')
g.indent--
}
g.writeln('}')
if node.has_cond {
g.write('if (!(')
g.expr(node.cond)
g.writeln(')) break;')
}
g.is_vlines_enabled = true
g.stmts(node.stmts)
if node.label.len > 0 {
g.writeln('${node.label}__continue: {}')
}
g.writeln('}')
g.indent--
g.writeln('}')
if node.label.len > 0 {
g.writeln('${node.label}__break: {}')
}
} else {
g.is_vlines_enabled = false
if node.label.len > 0 {
g.writeln('$node.label:')
}
g.write('for (')
if !node.has_init {
g.write('; ')
} else {
g.stmt(node.init)
// Remove excess return and add space
if g.out.last_n(1) == '\n' {
g.out.go_back(1)
g.empty_line = false
g.write(' ')
}
}
if node.has_cond {
g.expr(node.cond)
}
g.write('; ')
if node.has_inc {
g.stmt(node.inc)
}
g.writeln(') {')
g.is_vlines_enabled = true
g.stmts(node.stmts)
if node.label.len > 0 {
g.writeln('${node.label}__continue: {}')
}
g.writeln('}')
if node.label.len > 0 {
g.writeln('${node.label}__break: {}')
}
}
}
fn (mut g Gen) for_stmt(node ast.ForStmt) {
g.is_vlines_enabled = false
if node.label.len > 0 {
g.writeln('$node.label:')
}
g.writeln('for (;;) {')
if !node.is_inf {
g.indent++
g.stmt_path_pos << g.out.len
g.write('if (!(')
g.expr(node.cond)
g.writeln(')) break;')
g.indent--
}
g.is_vlines_enabled = true
g.stmts(node.stmts)
if node.label.len > 0 {
g.writeln('\t${node.label}__continue: {}')
}
g.writeln('}')
if node.label.len > 0 {
g.writeln('${node.label}__break: {}')
}
}
fn (mut g Gen) for_in_stmt(it ast.ForInStmt) {
if it.label.len > 0 {
g.writeln('\t$it.label: {}')
}
@ -2191,7 +2239,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
}
g.right_is_opt = false
g.is_assign_rhs = false
if g.inside_ternary == 0 && !assign_stmt.is_simple {
if g.inside_ternary == 0 && (assign_stmt.left.len > 1 || !assign_stmt.is_simple) {
g.writeln(';')
}
}

View File

@ -29,8 +29,10 @@ fn (mut p Parser) for_stmt() ast.Stmt {
}
p.close_scope()
return for_stmt
} else if p.peek_tok.kind in [.decl_assign, .assign, .semicolon] || p.tok.kind == .semicolon {
// `for i := 0; i < 10; i++ {`
} else if p.peek_tok.kind in [.decl_assign, .assign, .semicolon]
|| p.tok.kind == .semicolon || (p.peek_tok.kind == .comma && p.peek_tok2.kind != .key_mut
&& p.peek_tok3.kind != .key_in) {
// `for i := 0; i < 10; i++ {` or `for a,b := 0,1; a < 10; a++ {`
if p.tok.kind == .key_mut {
p.error('`mut` is not needed in `for ;;` loops: use `for i := 0; i < n; i ++ {`')
return ast.Stmt{}
@ -41,7 +43,9 @@ fn (mut p Parser) for_stmt() ast.Stmt {
mut has_init := false
mut has_cond := false
mut has_inc := false
if p.peek_tok.kind in [.assign, .decl_assign] {
mut is_multi := p.peek_tok.kind == .comma && p.peek_tok2.kind != .key_mut
&& p.peek_tok3.kind != .key_in
if p.peek_tok.kind in [.assign, .decl_assign] || is_multi {
init = p.assign_stmt()
has_init = true
}
@ -58,6 +62,9 @@ fn (mut p Parser) for_stmt() ast.Stmt {
has_cond = true
}
p.check(.semicolon)
if !is_multi {
is_multi = p.peek_tok.kind == .comma
}
if p.tok.kind != .lcbr {
inc = p.stmt(false)
has_inc = true
@ -70,6 +77,7 @@ fn (mut p Parser) for_stmt() ast.Stmt {
has_init: has_init
has_cond: has_cond
has_inc: has_inc
is_multi: is_multi
init: init
cond: cond
inc: inc

View File

@ -0,0 +1,34 @@
fn test_for_c_multi_init_vars() {
mut rets := []string{}
for a,b := 0,1; a < 5; a++ {
if a == 3 {
continue
}
b = a + 1
println('$a, $b')
rets << '$a, $b'
}
println(rets)
assert rets[0] == '0, 1'
assert rets[1] == '1, 2'
assert rets[2] == '2, 3'
assert rets[3] == '4, 5'
}
fn test_for_c_multi_inc_vars() {
mut rets := []string{}
mut b := 1
for a := 0; a < 10; a,b = b,a+b {
if a in [2, 3] {
continue
}
println('$a, $b')
rets << '$a, $b'
}
println(rets)
assert rets[0] == '0, 1'
assert rets[1] == '1, 1'
assert rets[2] == '1, 2'
assert rets[3] == '5, 8'
assert rets[4] == '8, 13'
}