v2 / vlib / v / parser / checks.v
347 lines · 328 sloc · 8.08 KB · b023a470b579004c3baaa1278ee13cfd69f51836
Raw
1module parser
2
3import v.ast
4import v.util
5import v.token
6
7// peek token `type Fn = fn () int`
8fn (p &Parser) is_fn_type_decl() bool {
9 mut n := 1
10 mut tok := p.tok
11 mut prev_tok := p.tok
12 cur_ln := p.tok.line_nr
13 for {
14 tok = p.scanner.peek_token(n)
15 if tok.kind == .eof {
16 break
17 }
18 if tok.kind in [.lpar, .rpar] {
19 n++
20 prev_tok = tok
21 continue
22 }
23 if tok.kind == .pipe {
24 if tok.pos - prev_tok.pos > prev_tok.len {
25 return false
26 }
27 }
28 if tok.line_nr > cur_ln {
29 break
30 }
31 prev_tok = tok
32 n++
33 }
34 return true
35}
36
37fn (p &Parser) has_prev_newline() bool {
38 mut tok := p.tok
39 mut prev_tok := p.prev_tok
40 mut idx := -1
41
42 for {
43 if tok.line_nr - prev_tok.line_nr - prev_tok.lit.count('\n') > 1 {
44 return true
45 }
46 if prev_tok.kind == .comment {
47 idx--
48 tok = prev_tok
49 prev_tok = p.peek_token(idx)
50 continue
51 }
52 break
53 }
54 return false
55}
56
57fn (p &Parser) has_prev_line_comment_or_label() bool {
58 return p.prev_tok.kind == .colon || (p.prev_tok.kind == .comment
59 && p.tok.line_nr - p.prev_tok.line_nr == 1
60 && p.prev_tok.line_nr - p.peek_token(-2).line_nr > 0)
61}
62
63fn (p &Parser) is_array_type() bool {
64 mut i := 1
65 mut tok := p.tok
66 line_nr := p.tok.line_nr
67 mut sbr_level := if p.tok.kind == .lsbr { 1 } else { 0 }
68
69 for {
70 tok = p.peek_token(i)
71 if tok.line_nr != line_nr {
72 return false
73 }
74 if sbr_level == 0
75 && tok.kind in [.name, .amp, .lpar, .question, .key_atomic, .key_fn, .key_shared, .key_struct] {
76 return true
77 }
78 if tok.kind == .lsbr {
79 sbr_level++
80 } else if tok.kind == .rsbr {
81 sbr_level--
82 }
83 if sbr_level == 0 && tok.kind in [.eof, .colon, .dot] {
84 break
85 }
86 i++
87 }
88 return false
89}
90
91fn (mut p Parser) is_following_concrete_types() bool {
92 if !(p.tok.kind == .lsbr && p.tok.is_next_to(p.prev_tok)) {
93 return false
94 }
95 mut i := 1
96 for {
97 cur_tok := p.peek_token(i)
98 if cur_tok.kind == .eof {
99 return false
100 } else if cur_tok.kind == .rsbr {
101 break
102 } else if cur_tok.kind == .name {
103 if p.peek_token(i + 1).kind == .dot {
104 if p.is_typename(cur_tok) {
105 return false
106 }
107 i++
108 } else if !(p.is_typename(cur_tok) && !(cur_tok.lit.len == 1
109 && !cur_tok.lit[0].is_capital())) {
110 return false
111 }
112 } else if cur_tok.kind != .comma {
113 return false
114 }
115 i++
116 }
117 return true
118}
119
120@[direct_array_access]
121fn (p &Parser) is_anon_struct_generic_arg(next_kind token.Kind) bool {
122 mut i := 2
123 mut nested_sbr_count := 0
124 mut nested_cbr_count := 0
125 for {
126 cur_tok := p.peek_token(i)
127 if cur_tok.kind == .eof {
128 return false
129 }
130 if cur_tok.kind == .lsbr {
131 nested_sbr_count++
132 } else if cur_tok.kind == .rsbr {
133 if nested_cbr_count == 0 && nested_sbr_count == 0 {
134 return p.peek_token(i + 1).kind == next_kind
135 }
136 if nested_sbr_count == 0 {
137 return false
138 }
139 nested_sbr_count--
140 } else if cur_tok.kind == .lcbr {
141 nested_cbr_count++
142 } else if cur_tok.kind == .rcbr {
143 if nested_cbr_count == 0 {
144 return false
145 }
146 nested_cbr_count--
147 }
148 i++
149 }
150 return false
151}
152
153@[direct_array_access]
154fn (p &Parser) is_generic_struct_init() bool {
155 lit0_is_capital := p.tok.kind != .eof && p.tok.lit.len > 0 && p.tok.lit[0].is_capital()
156 if !lit0_is_capital || p.peek_tok.kind != .lsbr {
157 return false
158 }
159 if p.peek_token(2).kind == .key_struct {
160 return p.is_anon_struct_generic_arg(.lcbr)
161 }
162 mut i := 2
163 mut nested_sbr_count := 0
164 for {
165 cur_tok := p.peek_token(i)
166 if cur_tok.kind == .eof
167 || cur_tok.kind !in [.amp, .dot, .comma, .name, .lpar, .rpar, .lsbr, .rsbr, .key_fn] {
168 break
169 }
170 if cur_tok.kind == .lsbr {
171 nested_sbr_count++
172 } else if cur_tok.kind == .rsbr {
173 if nested_sbr_count > 0 {
174 nested_sbr_count--
175 } else {
176 if p.peek_token(i + 1).kind == .lcbr {
177 return true
178 }
179 break
180 }
181 }
182 i++
183 }
184 return false
185}
186
187@[direct_array_access; inline]
188fn (p &Parser) is_typename(t token.Token) bool {
189 return t.kind == .name && (t.lit[0].is_capital() || p.table.known_type(t.lit))
190}
191
192// heuristics to detect `func[T]()` from `var [ expr`
193// 1. `f[[]` is generic(e.g. `f[[]int]`) because `var [ []` is invalid
194// 2. `f[map[` is generic(e.g. `f[map[string]string])
195// 3. `f[foo]` is generic because `v1 [ foo ] v2` is invalid syntax
196// 4. `f[foo[bar` is generic when bar is not generic T (f[foo[T](), in contrast, is not generic!)
197// 5. `f[Foo,` is generic when Foo is typename.
198// otherwise it is not generic because it may be multi-value (e.g. `return f [ foo, 0`).
199// 6. `f[mod.Foo]` is same as case 3
200// 7. `f[mod.Foo,` is same as case 5
201// 8. if there is a &, ignore the & and see if it is a type
202// 9. otherwise, it's not generic
203// see also test_generic_detection in vlib/v/tests/generics_test.v
204@[direct_array_access]
205fn (p &Parser) is_generic_call() bool {
206 lit0_is_capital := p.tok.kind != .eof && p.tok.lit.len > 0 && p.tok.lit[0].is_capital()
207 if lit0_is_capital || p.peek_tok.kind != .lsbr {
208 return false
209 }
210 mut tok2 := p.peek_token(2)
211 mut tok3 := p.peek_token(3)
212 mut tok4 := p.peek_token(4)
213 mut tok5 := p.peek_token(5)
214 mut kind2, mut kind3, mut kind4, mut kind5 := tok2.kind, tok3.kind, tok4.kind, tok5.kind
215 if kind2 == .amp { // if there is a & in front, shift everything left
216 tok2 = tok3
217 kind2 = kind3
218 tok3 = tok4
219 kind3 = kind4
220 tok4 = tok5
221 kind4 = kind5
222 tok5 = p.peek_token(6)
223 kind5 = tok5.kind
224 }
225 if (kind2 == .question || kind2 in [.key_shared, .key_atomic]) && kind3 == .key_fn {
226 tok2 = tok3
227 kind2 = kind3
228 tok3 = tok4
229 kind3 = kind4
230 tok4 = tok5
231 kind4 = kind5
232 tok5 = p.peek_token(6)
233 kind5 = tok5.kind
234 }
235
236 if kind2 == .lsbr {
237 // case 1 (array or fixed array type)
238 return tok3.kind == .rsbr || (tok4.kind == .rsbr && p.is_typename(tok5))
239 }
240 if kind2 == .key_struct {
241 return p.is_anon_struct_generic_arg(.lpar)
242 }
243 if kind2 == .key_fn {
244 mut i := 3
245 mut nested_sbr_count := 0
246 for {
247 cur_tok := p.peek_token(i)
248 if cur_tok.kind == .eof
249 || cur_tok.kind !in [.amp, .dot, .comma, .ellipsis, .name, .number, .lpar, .rpar, .lsbr, .rsbr, .question, .not, .key_fn, .key_mut, .key_shared, .key_atomic] {
250 break
251 }
252 if cur_tok.kind == .lsbr {
253 nested_sbr_count++
254 } else if cur_tok.kind == .rsbr {
255 if nested_sbr_count > 0 {
256 nested_sbr_count--
257 } else {
258 return p.peek_token(i + 1).kind == .lpar
259 }
260 }
261 i++
262 }
263 }
264
265 if kind2 == .name {
266 if kind3 == .lsbr && tok2.lit == 'map' {
267 // case 2
268 return true
269 }
270 if p.peek_tok.kind == .lsbr {
271 mut i := 3
272 mut nested_sbr_count := 0
273 for {
274 cur_tok := p.peek_token(i)
275 if cur_tok.kind == .eof
276 || cur_tok.kind !in [.amp, .dot, .comma, .name, .lpar, .rpar, .lsbr, .rsbr, .key_fn] {
277 break
278 }
279 if cur_tok.kind == .lsbr {
280 nested_sbr_count++
281 }
282 if cur_tok.kind == .rsbr {
283 if nested_sbr_count > 0 {
284 nested_sbr_count--
285 } else {
286 prev_tok := p.peek_token(i - 1)
287 // `funcs[i]()` is not generic call
288 if !(p.is_typename(prev_tok) || prev_tok.kind == .rsbr) {
289 return false
290 }
291 if p.peek_token(i + 1).kind == .lpar {
292 return true
293 }
294 break
295 }
296 }
297 i++
298 }
299 }
300 }
301 return false
302}
303
304const valid_tokens_inside_types = [token.Kind.lsbr, .rsbr, .name, .dot, .comma, .key_fn]
305
306fn (mut p Parser) is_generic_cast() bool {
307 if !ast.type_can_start_with_token(&p.tok) {
308 return false
309 }
310 mut i := 0
311 mut level := 0
312 mut lt_count := 0
313 for {
314 i++
315 tok := p.peek_token(i)
316
317 if tok.kind == .lsbr {
318 lt_count++
319 level++
320 } else if tok.kind == .rsbr {
321 level--
322 }
323 if lt_count > 0 && level == 0 {
324 break
325 }
326
327 if i > 20 || tok.kind !in valid_tokens_inside_types {
328 return false
329 }
330 }
331 next_tok := p.peek_token(i + 1)
332 // `next_tok` is the token following the closing `]` of the generic type: MyType[int]{
333 // ^
334 // if `next_tok` is a left paren, then the full expression looks something like
335 // `Foo[string](` or `Foo[mod.Type](`, which are valid type casts - return true
336 if next_tok.kind == .lpar {
337 return true
338 }
339 // any other token is not a valid generic cast, however
340 return false
341}
342
343// is_generic_name returns true if the current token is a generic name.
344@[inline]
345fn (p &Parser) is_generic_name() bool {
346 return p.tok.kind == .name && util.is_generic_type_name(p.tok.lit)
347}
348