mirror of
https://github.com/vlang/v.git
synced 2025-09-14 09:56:16 -04:00
checker: support nested labeled for statements (#21658)
This commit is contained in:
parent
dfc0c91295
commit
1af7b7c3de
@ -105,7 +105,7 @@ mut:
|
|||||||
cur_orm_ts ast.TypeSymbol
|
cur_orm_ts ast.TypeSymbol
|
||||||
cur_anon_fn &ast.AnonFn = unsafe { nil }
|
cur_anon_fn &ast.AnonFn = unsafe { nil }
|
||||||
vmod_file_content string // needed for @VMOD_FILE, contents of the file, *NOT its path**
|
vmod_file_content string // needed for @VMOD_FILE, contents of the file, *NOT its path**
|
||||||
loop_label string // set when inside a labelled for loop
|
loop_labels []string // filled, when inside labelled for loops: `a_label: for x in 0..10 {`
|
||||||
vweb_gen_types []ast.Type // vweb route checks
|
vweb_gen_types []ast.Type // vweb route checks
|
||||||
timers &util.Timers = util.get_timers()
|
timers &util.Timers = util.get_timers()
|
||||||
comptime_info_stack []comptime.ComptimeInfo // stores the values from the above on each $for loop, to make nesting them easier
|
comptime_info_stack []comptime.ComptimeInfo // stores the values from the above on each $for loop, to make nesting them easier
|
||||||
@ -183,7 +183,7 @@ fn (mut c Checker) reset_checker_state_at_start_of_new_file() {
|
|||||||
c.inside_sql = false
|
c.inside_sql = false
|
||||||
c.cur_orm_ts = ast.TypeSymbol{}
|
c.cur_orm_ts = ast.TypeSymbol{}
|
||||||
c.prevent_sum_type_unwrapping_once = false
|
c.prevent_sum_type_unwrapping_once = false
|
||||||
c.loop_label = ''
|
c.loop_labels = []
|
||||||
c.using_new_err_struct = false
|
c.using_new_err_struct = false
|
||||||
c.inside_selector_expr = false
|
c.inside_selector_expr = false
|
||||||
c.inside_interface_deref = false
|
c.inside_interface_deref = false
|
||||||
@ -2015,16 +2015,15 @@ fn (mut c Checker) check_enum_field_integer_literal(expr ast.IntegerLiteral, is_
|
|||||||
}
|
}
|
||||||
|
|
||||||
@[inline]
|
@[inline]
|
||||||
fn (mut c Checker) check_loop_label(label string, pos token.Pos) {
|
fn (mut c Checker) check_loop_labels(label string, pos token.Pos) {
|
||||||
if label == '' {
|
if label == '' {
|
||||||
// ignore
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if c.loop_label.len != 0 {
|
if label in c.loop_labels {
|
||||||
c.error('nesting of labelled `for` loops is not supported', pos)
|
c.error('the loop label was already defined before', pos)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.loop_label = label
|
c.loop_labels << label
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Checker) stmt(mut node ast.Stmt) {
|
fn (mut c Checker) stmt(mut node ast.Stmt) {
|
||||||
@ -2231,7 +2230,7 @@ fn (mut c Checker) branch_stmt(node ast.BranchStmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.label.len > 0 {
|
if node.label.len > 0 {
|
||||||
if node.label != c.loop_label {
|
if node.label !in c.loop_labels {
|
||||||
c.error('invalid label name `${node.label}`', node.pos)
|
c.error('invalid label name `${node.label}`', node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import v.token
|
|||||||
|
|
||||||
fn (mut c Checker) for_c_stmt(mut node ast.ForCStmt) {
|
fn (mut c Checker) for_c_stmt(mut node ast.ForCStmt) {
|
||||||
c.in_for_count++
|
c.in_for_count++
|
||||||
prev_loop_label := c.loop_label
|
prev_loop_labels := c.loop_labels
|
||||||
if node.has_init {
|
if node.has_init {
|
||||||
c.stmt(mut node.init)
|
c.stmt(mut node.init)
|
||||||
}
|
}
|
||||||
@ -22,15 +22,15 @@ fn (mut c Checker) for_c_stmt(mut node ast.ForCStmt) {
|
|||||||
}
|
}
|
||||||
c.stmt(mut node.inc)
|
c.stmt(mut node.inc)
|
||||||
}
|
}
|
||||||
c.check_loop_label(node.label, node.pos)
|
c.check_loop_labels(node.label, node.pos)
|
||||||
c.stmts(mut node.stmts)
|
c.stmts(mut node.stmts)
|
||||||
c.loop_label = prev_loop_label
|
c.loop_labels = prev_loop_labels
|
||||||
c.in_for_count--
|
c.in_for_count--
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
|
fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
|
||||||
c.in_for_count++
|
c.in_for_count++
|
||||||
prev_loop_label := c.loop_label
|
prev_loop_labels := c.loop_labels
|
||||||
mut typ := c.expr(mut node.cond)
|
mut typ := c.expr(mut node.cond)
|
||||||
if node.key_var.len > 0 && node.key_var != '_' {
|
if node.key_var.len > 0 && node.key_var != '_' {
|
||||||
c.check_valid_snake_case(node.key_var, 'variable name', node.pos)
|
c.check_valid_snake_case(node.key_var, 'variable name', node.pos)
|
||||||
@ -259,15 +259,15 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.check_loop_label(node.label, node.pos)
|
c.check_loop_labels(node.label, node.pos)
|
||||||
c.stmts(mut node.stmts)
|
c.stmts(mut node.stmts)
|
||||||
c.loop_label = prev_loop_label
|
c.loop_labels = prev_loop_labels
|
||||||
c.in_for_count--
|
c.in_for_count--
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
|
fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
|
||||||
c.in_for_count++
|
c.in_for_count++
|
||||||
prev_loop_label := c.loop_label
|
prev_loop_labels := c.loop_labels
|
||||||
c.expected_type = ast.bool_type
|
c.expected_type = ast.bool_type
|
||||||
if node.cond !is ast.EmptyExpr {
|
if node.cond !is ast.EmptyExpr {
|
||||||
typ := c.expr(mut node.cond)
|
typ := c.expr(mut node.cond)
|
||||||
@ -288,9 +288,9 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
|
|||||||
}
|
}
|
||||||
// TODO: update loop var type
|
// TODO: update loop var type
|
||||||
// how does this work currently?
|
// how does this work currently?
|
||||||
c.check_loop_label(node.label, node.pos)
|
c.check_loop_labels(node.label, node.pos)
|
||||||
c.stmts(mut node.stmts)
|
c.stmts(mut node.stmts)
|
||||||
c.loop_label = prev_loop_label
|
c.loop_labels = prev_loop_labels
|
||||||
c.in_for_count--
|
c.in_for_count--
|
||||||
if c.smartcast_mut_pos != token.Pos{} {
|
if c.smartcast_mut_pos != token.Pos{} {
|
||||||
c.smartcast_mut_pos = token.Pos{}
|
c.smartcast_mut_pos = token.Pos{}
|
||||||
|
@ -26,10 +26,3 @@ vlib/v/checker/tests/labelled_break_continue.vv:16:10: error: invalid label name
|
|||||||
| ~~~~~
|
| ~~~~~
|
||||||
17 | }
|
17 | }
|
||||||
18 | }
|
18 | }
|
||||||
vlib/v/checker/tests/labelled_break_continue.vv:21:11: error: nesting of labelled `for` loops is not supported
|
|
||||||
19 | // check nested loops (not supported ATM)
|
|
||||||
20 | L3: for ;; i++ {
|
|
||||||
21 | L4: for {
|
|
||||||
| ^
|
|
||||||
22 | if i < 17 {continue L3}
|
|
||||||
23 | else {break L3}
|
|
||||||
|
91
vlib/v/tests/nested_fors_with_labels_test.v
Normal file
91
vlib/v/tests/nested_fors_with_labels_test.v
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
const good = [
|
||||||
|
'> x: 0 | y: 0 | z: 0',
|
||||||
|
'> x: 0 | y: 0 | z: 1',
|
||||||
|
'> x: 0 | y: 1 | z: 0',
|
||||||
|
'> x: 0 | y: 1 | z: 1',
|
||||||
|
'> x: 1 | y: 0 | z: 0',
|
||||||
|
'> x: 1 | y: 0 | z: 1',
|
||||||
|
'> x: 1 | y: 1 | z: 0',
|
||||||
|
'> x: 1 | y: 1 | z: 1',
|
||||||
|
]
|
||||||
|
|
||||||
|
fn test_labeled_nested_loops_for_in() {
|
||||||
|
mut values := []string{}
|
||||||
|
abc: for x in 0 .. 2 {
|
||||||
|
def: for y in 0 .. 5 {
|
||||||
|
if y > 1 {
|
||||||
|
continue abc
|
||||||
|
}
|
||||||
|
xyz: for z in 0 .. 10 {
|
||||||
|
if z > 1 {
|
||||||
|
continue def
|
||||||
|
}
|
||||||
|
values << '> x: ${x} | y: ${y} | z: ${z}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert values == good
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_labeled_nested_loops_for_c_style() {
|
||||||
|
mut values := []string{}
|
||||||
|
abc: for x := 0; x < 2; x++ {
|
||||||
|
def: for y := 0; y < 5; y++ {
|
||||||
|
if y > 1 {
|
||||||
|
continue abc
|
||||||
|
}
|
||||||
|
xyz: for z := 0; z < 10; z++ {
|
||||||
|
if z > 1 {
|
||||||
|
continue def
|
||||||
|
}
|
||||||
|
values << '> x: ${x} | y: ${y} | z: ${z}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert values == good
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_labeled_nested_loops_for_in_array() {
|
||||||
|
mut values := []string{}
|
||||||
|
x_array := [0, 1]
|
||||||
|
y_array := [0, 1, 2, 3, 4]
|
||||||
|
z_array := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
abc: for x in x_array {
|
||||||
|
def: for y in y_array {
|
||||||
|
if y > 1 {
|
||||||
|
continue abc
|
||||||
|
}
|
||||||
|
xyz: for z in y_array {
|
||||||
|
if z > 1 {
|
||||||
|
continue def
|
||||||
|
}
|
||||||
|
values << '> x: ${x} | y: ${y} | z: ${z}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert values == good
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_labeled_nested_loops_for_condition() {
|
||||||
|
mut values := []string{}
|
||||||
|
mut x := -1
|
||||||
|
abc: for x < 1 {
|
||||||
|
x++
|
||||||
|
mut y := -1
|
||||||
|
def: for y < 5 {
|
||||||
|
y++
|
||||||
|
if y > 1 {
|
||||||
|
continue abc
|
||||||
|
}
|
||||||
|
mut z := -1
|
||||||
|
xyz: for z < 10 {
|
||||||
|
z++
|
||||||
|
if z > 1 {
|
||||||
|
continue def
|
||||||
|
}
|
||||||
|
values << '> x: ${x} | y: ${y} | z: ${z}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert values == good
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user