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