1// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. 2// Use of this source code is governed by an MIT license 3// that can be found in the LICENSE file. 4module parser 5 6import v.ast 7import v.table 8 9fn (mut p Parser) for_stmt() ast.Stmt { 10 p.check(.key_for) 11 pos := p.tok.position() 12 p.open_scope() 13 p.inside_for = true 14 // defer { p.close_scope() } 15 // Infinite loop 16 if p.tok.kind == .lcbr { 17 p.inside_for = false 18 stmts := p.parse_block() 19 p.close_scope() 20 return ast.ForStmt{ 21 stmts: stmts 22 pos: pos 23 is_inf: true 24 } 25 } else if p.tok.kind == .key_mut { 26 p.error('`mut` is not needed in for loops') 27 } else if p.peek_tok.kind in [.decl_assign, .assign, .semicolon] || p.tok.kind == .semicolon { 28 // `for i := 0; i < 10; i++ {` 29 mut init := ast.Stmt{} 30 mut cond := p.new_true_expr() 31 mut inc := ast.Stmt{} 32 mut has_init := false 33 mut has_cond := false 34 mut has_inc := false 35 if p.peek_tok.kind in [.assign, .decl_assign] { 36 init = p.assign_stmt() 37 has_init = true 38 } 39 // Allow `for ;; i++ {` 40 // Allow `for i = 0; i < ...` 41 p.check(.semicolon) 42 if p.tok.kind != .semicolon { 43 // Disallow `for i := 0; i++; i < ...` 44 if p.tok.kind == .name && p.peek_tok.kind in [.inc, .dec] { 45 p.error('cannot use $p.tok.lit$p.peek_tok.kind as value') 46 } 47 cond = p.expr(0) 48 has_cond = true 49 } 50 p.check(.semicolon) 51 if p.tok.kind != .lcbr { 52 inc = p.stmt(false) 53 has_inc = true 54 } 55 p.inside_for = false 56 stmts := p.parse_block() 57 p.close_scope() 58 return ast.ForCStmt{ 59 stmts: stmts 60 has_init: has_init 61 has_cond: has_cond 62 has_inc: has_inc 63 init: init 64 cond: cond 65 inc: inc 66 pos: pos 67 } 68 } else if p.peek_tok.kind in [.key_in, .comma] { 69 // `for i in vals`, `for i in start .. end` 70 key_var_pos := p.tok.position() 71 mut val_var_pos := p.tok.position() 72 mut key_var_name := '' 73 mut val_var_name := p.check_name() 74 if p.tok.kind == .comma { 75 p.next() 76 key_var_name = val_var_name 77 val_var_pos = p.tok.position() 78 val_var_name = p.check_name() 79 if key_var_name == val_var_name && key_var_name != '_' { 80 p.error_with_pos('key and value in a for loop cannot be the same', val_var_pos) 81 } 82 if p.scope.known_var(key_var_name) { 83 p.error('redefinition of key iteration variable `$key_var_name`') 84 } 85 if p.scope.known_var(val_var_name) { 86 p.error('redefinition of value iteration variable `$val_var_name`') 87 } 88 p.scope.register(key_var_name, ast.Var{ 89 name: key_var_name 90 typ: table.int_type 91 pos: key_var_pos 92 }) 93 } else if p.scope.known_var(val_var_name) { 94 p.error('redefinition of value iteration variable `$val_var_name`') 95 } 96 p.check(.key_in) 97 if p.tok.kind == .name && p.tok.lit in [key_var_name, val_var_name] { 98 p.error('in a `for x in array` loop, the key or value iteration variable `$p.tok.lit` can not be the same as the array variable') 99 } 100 // arr_expr 101 cond := p.expr(0) 102 // 0 .. 10 103 // start := p.tok.lit.int() 104 // TODO use RangeExpr 105 mut high_expr := ast.Expr{} 106 mut is_range := false 107 if p.tok.kind == .dotdot { 108 is_range = true 109 p.next() 110 high_expr = p.expr(0) 111 p.scope.register(val_var_name, ast.Var{ 112 name: val_var_name 113 typ: table.int_type 114 pos: val_var_pos 115 }) 116 } else { 117 // this type will be set in checker 118 p.scope.register(val_var_name, ast.Var{ 119 name: val_var_name 120 pos: val_var_pos 121 }) 122 } 123 p.inside_for = false 124 stmts := p.parse_block() 125 // println('nr stmts=$stmts.len') 126 p.close_scope() 127 return ast.ForInStmt{ 128 stmts: stmts 129 cond: cond 130 key_var: key_var_name 131 val_var: val_var_name 132 high: high_expr 133 is_range: is_range 134 pos: pos 135 } 136 } 137 // `for cond {` 138 cond := p.expr(0) 139 p.inside_for = false 140 stmts := p.parse_block() 141 p.close_scope() 142 return ast.ForStmt{ 143 cond: cond 144 stmts: stmts 145 pos: pos 146 } 147} 148