vxx2 / vlib / v / parser / expr.v
1392 lines · 1348 sloc · 34.67 KB · b6358f093b6e7fea3f6021f9b3035b9e879b9504
Raw
1// Copyright (c) 2019-2024 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.token
8
9const max_expr_level = 100
10
11@[inline]
12fn (mut p Parser) check_expr_level() ! {
13 if p.expr_level > max_expr_level {
14 return error('expr level > ${max_expr_level}')
15 }
16}
17
18fn (mut p Parser) expr_no_value(precedence int) ast.Expr {
19 old_expecting_value := p.expecting_value
20 p.expecting_value = false
21 defer {
22 p.expecting_value = old_expecting_value
23 }
24 return p.check_expr(precedence) or {
25 if token.is_decl(p.tok.kind) && p.disallow_declarations_in_script_mode() {
26 return ast.empty_expr
27 }
28 p.unexpected(prepend_msg: 'invalid expression:')
29 }
30}
31
32fn (mut p Parser) expr(precedence int) ast.Expr {
33 old_expecting_value := p.expecting_value
34 p.expecting_value = true
35 defer {
36 p.expecting_value = old_expecting_value
37 }
38 return p.check_expr(precedence) or {
39 if token.is_decl(p.tok.kind) && p.disallow_declarations_in_script_mode() {
40 return ast.empty_expr
41 }
42 p.unexpected(prepend_msg: 'invalid expression:')
43 }
44}
45
46fn (mut p Parser) check_expr(precedence int) !ast.Expr {
47 p.trace_parser('expr(${precedence})')
48 p.expr_level++
49 defer {
50 p.expr_level--
51 }
52 p.check_expr_level()!
53 mut node := ast.empty_expr
54 is_stmt_ident := p.is_stmt_ident
55 p.is_stmt_ident = false
56 if !p.pref.is_fmt {
57 p.eat_comments()
58 }
59 if p.inside_if_cond {
60 p.if_cond_comments << p.eat_comments()
61 }
62 // Prefix
63 match p.tok.kind {
64 .key_mut, .key_shared, .key_atomic, .key_static, .key_volatile {
65 if p.peek_tok.kind in [.lpar, .lsbr] && p.peek_tok.is_next_to(p.tok) {
66 node = p.call_expr(p.language, p.mod)
67 } else {
68 ident := p.ident(.v)
69 node = ident
70 if p.peek_tok.kind != .assign && (p.inside_if_cond || p.inside_match) {
71 p.scope.mark_var_as_used(ident.name)
72 }
73 p.add_defer_var(ident)
74 p.is_stmt_ident = is_stmt_ident
75 }
76 }
77 .name, .question {
78 if p.peek_tok.kind == .name && p.tok.lit == 'sql' {
79 node = p.sql_expr()
80 } else if p.peek_tok.kind == .lcbr && p.tok.lit == 'map' && !(p.builtin_mod
81 && p.file_base in ['map.v', 'map_d_gcboehm_opt.v']) {
82 p.error_with_pos("deprecated map syntax, use syntax like `{'age': 20}`",
83 p.tok.pos())
84 } else if p.tok.kind == .question && p.peek_tok.kind == .amp {
85 node = p.prefix_expr()
86 } else if p.inside_for_expr && p.tok.kind == .name && ((p.tok.lit[0].is_capital()
87 && p.peek_tok.kind == .lcbr && (p.peek_token(2).kind in [.rcbr, .name]
88 || p.inside_array_lit)) || (p.inside_array_lit && p.peek_tok.kind == .dot
89 && p.peek_token(2).kind == .name && p.peek_token(2).lit[0].is_capital()
90 && p.peek_token(3).kind == .lcbr)) {
91 node = p.struct_init(p.mod + '.' + p.tok.lit, .normal, false)
92 } else if p.is_generic_name() && p.peek_tok.kind == .lcbr
93 && p.peek_token(2).kind == .rcbr && p.peek_token(2).line_nr == p.tok.line_nr {
94 node = p.struct_init(p.mod + '.' + p.tok.lit, .normal, false)
95 } else {
96 if p.inside_comptime_if && p.is_generic_name() && p.peek_tok.kind != .dot {
97 // $if T is string {}
98 p.expecting_type = true
99 }
100 node = p.name_expr()
101 p.is_stmt_ident = is_stmt_ident
102 }
103 }
104 .string {
105 node = p.string_expr()
106 }
107 .comment {
108 node = p.comment()
109 return node
110 }
111 .dot {
112 // .enum_val
113 node = p.enum_val()
114 }
115 .at {
116 node = p.at()
117 }
118 .dollar {
119 match p.peek_tok.kind {
120 .key_typeof, .key_sizeof, .key_isreftype, .key_dump, .key_offsetof {
121 start_pos := p.tok.pos()
122 p.check(.dollar)
123 match p.tok.kind {
124 .key_typeof {
125 node = p.parse_typeof_expr(start_pos)
126 }
127 .key_sizeof, .key_isreftype {
128 node = p.parse_sizeof_or_isreftype_expr()
129 }
130 .key_dump {
131 node = p.parse_dump_expr(start_pos)
132 }
133 .key_offsetof {
134 node = p.parse_offsetof_expr(start_pos)
135 }
136 else {}
137 }
138
139 p.is_stmt_ident = is_stmt_ident
140 }
141 .name, .key_struct, .key_enum, .key_interface, .key_shared {
142 if p.peek_tok.lit in comptime_types {
143 node = p.parse_comptime_type()
144 } else {
145 node = p.comptime_call()
146 }
147 p.is_stmt_ident = is_stmt_ident
148 }
149 .key_if {
150 mut is_expr := false
151 if p.prev_tok.kind.is_assign() {
152 is_expr = true
153 }
154 return p.if_expr(true, is_expr)
155 }
156 .key_match {
157 return p.match_expr(true, p.prev_tok.kind.is_assign())
158 }
159 else {
160 return p.unexpected_with_pos(p.peek_tok.pos(),
161 got: '`$`'
162 )
163 }
164 }
165 }
166 .chartoken {
167 node = ast.CharLiteral{
168 val: p.tok.lit
169 pos: p.tok.pos()
170 }
171 p.next()
172 }
173 .amp, .mul, .not, .bit_not, .arrow {
174 // &x, *x, !x, ~x, <-x
175 node = p.prefix_expr()
176 }
177 .power {
178 node = p.power_prefix_expr()
179 }
180 .plus {
181 // +1, +a
182 node = p.prefix_expr()
183 }
184 .minus {
185 // -1, -a
186 if p.peek_tok.kind == .number && !(p.peek_token(2).kind == .power
187 && p.peek_token(2).line_nr == p.tok.line_nr) {
188 node = p.parse_number_literal()
189 } else {
190 node = p.prefix_expr()
191 }
192 }
193 .key_go, .key_spawn {
194 if p.peek_tok.kind in [.lpar, .lsbr] && p.peek_tok.is_next_to(p.tok) {
195 node = p.call_expr(p.language, p.mod)
196 } else {
197 if (p.pref.use_coroutines || p.pref.is_fmt) && p.tok.kind == .key_go {
198 mut go_expr := p.go_expr()
199 go_expr.is_expr = true
200 node = go_expr
201 } else {
202 mut spawn_expr := p.spawn_expr()
203 spawn_expr.is_expr = true
204 node = spawn_expr
205 }
206 }
207 }
208 .key_true, .key_false {
209 if p.peek_tok.kind in [.lpar, .lsbr] && p.peek_tok.is_next_to(p.tok) {
210 node = p.call_expr(p.language, p.mod)
211 } else {
212 node = ast.BoolLiteral{
213 val: p.tok.kind == .key_true
214 pos: p.tok.pos()
215 }
216 p.next()
217 }
218 }
219 .key_match {
220 node = if p.peek_tok.kind in [.lpar, .lsbr] && p.peek_tok.is_next_to(p.tok) {
221 p.call_expr(p.language, p.mod)
222 } else {
223 p.match_expr(false, false)
224 }
225 }
226 .key_select {
227 if p.peek_tok.kind in [.lpar, .lsbr] && p.peek_tok.is_next_to(p.tok) {
228 node = p.call_expr(p.language, p.mod)
229 } else {
230 node = p.select_expr()
231 }
232 }
233 .key_nil {
234 node = ast.Nil{
235 pos: p.tok.pos()
236 }
237 p.next()
238 }
239 .number {
240 node = p.parse_number_literal()
241 }
242 .lpar {
243 mut pos := p.tok.pos()
244 p.check(.lpar)
245 mut comments := p.eat_comments()
246 node = p.expr(0)
247 comments << p.eat_comments()
248 p.check(.rpar)
249 rpar_pos := p.prev_tok.pos()
250 p.attach_or_block_to_parenthesized_expr(mut node)
251 node = ast.ParExpr{
252 expr: node
253 pos: pos.extend(rpar_pos)
254 comments: comments
255 }
256 }
257 .key_if {
258 if p.peek_tok.kind in [.lpar, .lsbr] && p.peek_tok.is_next_to(p.tok) {
259 node = p.call_expr(p.language, p.mod)
260 } else {
261 mut is_expr := false
262 if p.prev_tok.kind.is_assign() {
263 is_expr = true
264 }
265 node = p.if_expr(false, is_expr)
266 }
267 }
268 .key_unsafe {
269 // unsafe {
270 mut pos := p.tok.pos()
271 p.next()
272 if p.inside_unsafe {
273 err := p.error_with_pos('already inside `unsafe` block', pos)
274 if p.tok.kind != .eof {
275 p.recover_until_closing_rcbr()
276 }
277 return err
278 }
279 p.inside_unsafe = true
280 p.check(.lcbr)
281 e := p.expr(0)
282 p.check(.rcbr)
283 pos.update_last_line(p.prev_tok.line_nr)
284 node = ast.UnsafeExpr{
285 expr: e
286 pos: pos
287 }
288 p.inside_unsafe = false
289 }
290 .pipe, .logical_or {
291 if nnn := p.lambda_expr() {
292 node = nnn
293 } else {
294 return error('unexpected lambda expression')
295 }
296 }
297 .key_lock, .key_rlock {
298 if p.peek_tok.kind in [.lpar, .lsbr] && p.peek_tok.is_next_to(p.tok) {
299 node = p.call_expr(p.language, p.mod)
300 } else {
301 node = p.lock_expr()
302 }
303 }
304 .lsbr {
305 if p.expecting_type {
306 // parse json.decode type (`json.decode([]User, s)`)
307 node = p.name_expr()
308 } else {
309 // check is `cast_expr` or `array_init`
310 // [name.name][]a{} => array_init
311 // [name.name][]a(expr) => cast_expr, same line
312 line_nr := p.tok.line_nr
313 mut n := 1
314 mut prev_n_tok := p.tok
315 mut peek_n_tok := p.peek_token(n)
316 mut sbr_level := 1
317 for peek_n_tok.kind in [.name, .dot, .lsbr, .rsbr, .number] {
318 if peek_n_tok.kind == .rsbr {
319 sbr_level--
320 } else if peek_n_tok.kind == .lsbr {
321 sbr_level++
322 }
323 if peek_n_tok.kind == .dot && prev_n_tok.kind != .name {
324 // [xxx].method()
325 break
326 }
327 n++
328 prev_n_tok = peek_n_tok
329 peek_n_tok = p.peek_token(n)
330 }
331 mut is_cast_expr := peek_n_tok.kind == .lpar && sbr_level == 0
332 && peek_n_tok.line_nr == line_nr
333 // If the matching `)` is followed by `{`, this can still be an array init when
334 // the element type itself contains parentheses, e.g. `[](?Type){}` or
335 // `[]thread (T1, T2){}`.
336 if is_cast_expr && (prev_n_tok.kind == .rsbr || prev_n_tok.lit == 'thread') {
337 mut par_level := 0
338 for i := n; true; i++ {
339 tk := p.peek_token(i)
340 if tk.kind == .eof {
341 break
342 }
343 if tk.kind == .lpar {
344 par_level++
345 } else if tk.kind == .rpar {
346 par_level--
347 if par_level == 0 {
348 if p.peek_token(i + 1).kind == .lcbr {
349 is_cast_expr = false
350 }
351 break
352 }
353 }
354 }
355 }
356 if is_cast_expr {
357 pos := p.tok.pos()
358 typ := p.parse_type()
359 typname := p.table.sym(typ).name
360 p.check(.lpar)
361 expr := p.expr(0)
362 p.check(.rpar)
363 node = ast.CastExpr{
364 typ: typ
365 typname: typname
366 expr: expr
367 pos: pos
368 }
369 } else {
370 node = p.array_init(false, ast.void_type)
371 }
372 }
373 }
374 .key_none {
375 pos := p.tok.pos()
376 p.next()
377 node = ast.None{
378 pos: pos
379 }
380 }
381 .key_typeof {
382 node = p.parse_typeof_expr(p.tok.pos())
383 }
384 .key_sizeof, .key_isreftype {
385 node = p.parse_sizeof_or_isreftype_expr()
386 }
387 .key_dump {
388 node = p.parse_dump_expr(p.tok.pos())
389 }
390 .key_offsetof {
391 node = p.parse_offsetof_expr(p.tok.pos())
392 }
393 .key_likely, .key_unlikely {
394 is_likely := p.tok.kind == .key_likely
395 p.next()
396 p.check(.lpar)
397 lpos := p.tok.pos()
398 expr := p.expr(0)
399 p.check(.rpar)
400 node = ast.Likely{
401 expr: expr
402 pos: lpos
403 is_likely: is_likely
404 }
405 }
406 .lcbr {
407 if p.is_sql_query_data_expr() {
408 node = p.sql_query_data_expr()
409 } else {
410 // Map `{"age": 20}`
411 p.next()
412 node = p.map_init()
413 p.check(.rcbr)
414 }
415 }
416 .key_fn {
417 if p.expecting_type {
418 // Anonymous function type
419 start_pos := p.tok.pos()
420 return ast.TypeNode{
421 typ: p.parse_type()
422 pos: start_pos.extend(p.prev_tok.pos())
423 }
424 } else {
425 // Anonymous function
426 node = p.anon_fn()
427 if p.file_backend_mode == .v || p.file_backend_mode == .c {
428 p.register_auto_import('builtin.closure')
429 }
430 // its a call
431 // NOTE: this could be moved to just before the pratt loop
432 // then anything can be a call, eg. `index[2]()` or `struct.field()`
433 // but this would take a bit of modification
434 if p.tok.kind == .lpar {
435 p.next()
436 pos := p.tok.pos()
437 args := p.call_args()
438 p.check(.rpar)
439 or_block := p.gen_or_block()
440 node = ast.CallExpr{
441 name: 'anon'
442 left: node
443 args: args
444 pos: pos
445 or_block: or_block
446 scope: p.scope
447 is_return_used: p.expecting_value
448 }
449 }
450 return node
451 }
452 }
453 .inc, .dec {
454 same_line_with_next := p.tok.line_nr == p.peek_tok.line_nr
455 next_tok_name := p.peek_tok.kind == .name
456
457 if next_tok_name && same_line_with_next {
458 p.prefix_inc_dec_error()
459 }
460 }
461 else {
462 if p.tok.kind == .key_struct && p.peek_tok.kind == .lcbr {
463 if p.expecting_type && p.inside_call_args {
464 // Anonymous struct for json.decode
465 tok_pos := p.tok.pos()
466 return ast.TypeNode{
467 stmt: p.struct_decl(true)
468 pos: tok_pos
469 typ: ast.void_type
470 }
471 } else {
472 // Anonymous struct
473 if !p.is_explicit_anon_struct_init() {
474 p.next()
475 }
476 return p.struct_init('', .anon, false)
477 }
478 } else if p.tok.kind == .key_type {
479 // variable name: type
480 ident := p.ident(.v)
481 node = ident
482 p.scope.mark_var_as_used(ident.name)
483 p.add_defer_var(ident)
484 p.is_stmt_ident = is_stmt_ident
485 } else if p.tok.kind != .eof && !(p.tok.kind == .rsbr && p.inside_asm) {
486 // eof should be handled where it happens
487 return error('none')
488 // return p.unexpected(prepend_msg: 'invalid expression: ')
489 }
490 }
491 }
492
493 if p.inside_array_lit {
494 if p.tok.kind in [.minus, .mul, .amp, .arrow] && p.tok.pos + 1 == p.peek_tok.pos
495 && p.prev_tok.pos + p.prev_tok.len + 1 != p.peek_tok.pos {
496 return node
497 }
498 }
499 if p.inside_if_cond {
500 p.if_cond_comments << p.eat_comments()
501 }
502 if p.pref.is_fmt && p.tok.kind == .comment && p.peek_tok.kind.is_infix() && !p.inside_map_init
503 && !(p.peek_tok.kind == .mul && p.peek_tok.pos().line_nr != p.tok.pos().line_nr)
504 && !(p.peek_tok.kind == .dot && p.inside_array_lit) {
505 p.left_comments = p.eat_comments()
506 }
507 return p.expr_with_left(node, precedence, is_stmt_ident)
508}
509
510fn (p &Parser) is_explicit_anon_struct_init() bool {
511 mut n := 2
512 mut curlies := 1
513 for curlies > 0 {
514 tok := p.peek_token(n)
515 if tok.kind == .eof {
516 return false
517 }
518 if tok.kind == .lcbr {
519 curlies++
520 } else if tok.kind == .rcbr {
521 curlies--
522 }
523 n++
524 }
525 return p.peek_token(n).kind == .lcbr
526}
527
528fn (mut p Parser) parse_typeof_expr(start_pos token.Pos) ast.Expr {
529 p.next() // typeof
530 if p.tok.kind == .lsbr {
531 p.check(.lsbr)
532 type_pos := p.tok.pos()
533 typ := p.parse_type()
534 p.check(.rsbr)
535 p.check(.lpar)
536 p.check(.rpar)
537 return ast.TypeOf{
538 is_type: true
539 typ: typ
540 pos: type_pos.extend(p.tok.pos())
541 }
542 }
543 p.check(.lpar)
544 expr := p.expr(0)
545 p.check(.rpar)
546 if p.tok.kind != .dot && p.tok.line_nr == p.prev_tok.line_nr && !p.inside_array_init_type_expr {
547 if !p.inside_unsafe {
548 p.warn_with_pos('use e.g. `typeof(expr).name` or `sum_type_instance.type_name()` instead',
549 start_pos)
550 }
551 }
552 return ast.TypeOf{
553 is_type: false
554 expr: expr
555 pos: start_pos.extend(p.tok.pos())
556 }
557}
558
559fn (mut p Parser) parse_sizeof_or_isreftype_expr() ast.Expr {
560 is_reftype := p.tok.kind == .key_isreftype
561 p.next() // sizeof or isreftype
562 if p.tok.kind == .lsbr {
563 // parse sizeof[T]() and isreftype[T]() without guessing:
564 p.check(.lsbr)
565 mut type_pos := p.tok.pos()
566 typ := p.parse_type()
567 type_pos = type_pos.extend(p.tok.pos())
568 p.check(.rsbr)
569 p.check(.lpar)
570 p.check(.rpar)
571 if is_reftype {
572 return ast.IsRefType{
573 is_type: true
574 typ: typ
575 pos: type_pos
576 }
577 }
578 return ast.SizeOf{
579 is_type: true
580 typ: typ
581 pos: type_pos
582 }
583 }
584 p.check(.lpar)
585 pos := p.tok.pos()
586 mut is_known_var := p.scope.mark_var_as_used(p.tok.lit)
587 || p.table.global_scope.known_const(p.mod + '.' + p.tok.lit)
588 //|| p.table.known_fn(p.mod + '.' + p.tok.lit)
589 // assume `mod.` prefix leads to a type
590 mut is_type := p.known_import(p.tok.lit) || p.tok.kind.is_start_of_type()
591 || (p.tok.lit.len > 0 && p.tok.lit[0].is_capital())
592 if p.peek_tok.kind == .string && p.tok.lit in ['c', 'r'] {
593 is_known_var = false
594 is_type = false
595 }
596 if is_known_var || !is_type {
597 expr := p.expr(0)
598 if is_reftype {
599 result := ast.IsRefType{
600 is_type: false
601 expr: expr
602 pos: pos
603 }
604 p.check(.rpar)
605 return result
606 }
607 result := ast.SizeOf{
608 is_type: false
609 expr: expr
610 pos: pos
611 }
612 p.check(.rpar)
613 return result
614 }
615 if p.tok.kind == .name {
616 p.register_used_import(p.tok.lit)
617 }
618 save_expr_mod := p.expr_mod
619 p.expr_mod = ''
620 arg_type := p.parse_type()
621 p.expr_mod = save_expr_mod
622 p.check(.rpar)
623 if is_reftype {
624 return ast.IsRefType{
625 guessed_type: true
626 is_type: true
627 typ: arg_type
628 pos: pos
629 }
630 }
631 return ast.SizeOf{
632 guessed_type: true
633 is_type: true
634 typ: arg_type
635 pos: pos
636 }
637}
638
639fn (mut p Parser) parse_dump_expr(start_pos token.Pos) ast.Expr {
640 p.next() // dump
641 p.check(.lpar)
642 expr := p.expr(0)
643 if p.tok.kind == .comma && p.peek_tok.kind == .rpar {
644 p.next()
645 }
646 p.check(.rpar)
647 mut pos := p.tok.pos()
648 pos.update_last_line(p.prev_tok.line_nr)
649 return ast.DumpExpr{
650 expr: expr
651 pos: start_pos.extend(pos)
652 }
653}
654
655fn (mut p Parser) parse_offsetof_expr(start_pos token.Pos) ast.Expr {
656 p.next() // __offsetof
657 p.check(.lpar)
658 st := p.parse_type()
659 p.check(.comma)
660 if p.tok.kind != .name {
661 return p.unexpected(got: '`${p.tok.lit}`', additional_msg: 'expecting struct field')
662 }
663 field := p.tok.lit
664 p.next()
665 p.check(.rpar)
666 return ast.OffsetOf{
667 struct_type: st
668 field: field
669 pos: start_pos
670 }
671}
672
673fn (p &Parser) can_use_expr_as_struct_init_type(expr ast.Expr) bool {
674 return match expr {
675 ast.ParExpr {
676 p.can_use_expr_as_struct_init_type(expr.expr)
677 }
678 ast.SelectorExpr {
679 expr.expr is ast.TypeOf
680 && expr.field_name in ['idx', 'typ', 'unaliased_typ', 'key_type', 'value_type', 'element_type', 'pointee_type', 'payload_type']
681 }
682 else {
683 false
684 }
685 }
686}
687
688fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_ident bool) ast.Expr {
689 mut node := left
690 if p.inside_asm && p.prev_tok.pos().line_nr < p.tok.pos().line_nr {
691 return node
692 }
693
694 p.process_custom_orm_operators()
695
696 // Infix
697 for {
698 if p.tok.kind == .lpar && p.tok.line_nr == p.prev_tok.line_nr
699 && node in [ast.CallExpr, ast.IndexExpr, ast.ParExpr, ast.SelectorExpr] {
700 p.promote_if_expr_to_value(mut node)
701 node = p.call_expr_with_left(node)
702 p.is_stmt_ident = is_stmt_ident
703 continue
704 }
705 if !p.inside_array_init_type_expr && p.tok.kind == .lcbr && p.tok.is_next_to(p.prev_tok)
706 && p.can_use_expr_as_struct_init_type(node) {
707 node = p.struct_init_with_type_expr(node, .normal)
708 p.is_stmt_ident = is_stmt_ident
709 continue
710 }
711 if precedence >= p.tok.kind.precedence() {
712 return node
713 }
714 if p.tok.kind == .dot {
715 // no spaces or line break before dot in map_init
716 if (p.inside_map_init || p.inside_array_lit)
717 && p.tok.pos - p.prev_tok.pos > p.prev_tok.len {
718 return node
719 }
720 p.promote_if_expr_to_value(mut node)
721 node = p.dot_expr(node)
722 if p.name_error {
723 return node
724 }
725 p.is_stmt_ident = is_stmt_ident
726 } else if left !is ast.IntegerLiteral && p.tok.kind in [.lsbr, .nilsbr]
727 && (p.tok.line_nr == p.prev_tok.line_nr || (p.prev_tok.kind == .string
728 && p.tok.line_nr == p.prev_tok.line_nr + p.prev_tok.lit.count('\n'))) {
729 p.promote_if_expr_to_value(mut node)
730 if p.peek_tok.kind == .question && p.peek_token(2).kind == .name {
731 p.next()
732 p.error_with_pos('cannot use Option type name as concrete type', p.tok.pos())
733 } else if p.tok.kind == .nilsbr {
734 node = p.index_expr(node, true)
735 } else {
736 node = p.index_expr(node, false)
737 }
738 p.is_stmt_ident = is_stmt_ident
739 } else if p.tok.kind == .key_as && p.tok.line_nr == p.prev_tok.line_nr {
740 // sum type as cast `x := SumType as Variant`
741 if !p.inside_asm {
742 pos := p.tok.pos()
743 p.promote_if_expr_to_value(mut node)
744 p.next()
745 typ := p.parse_type()
746 node = ast.AsCast{
747 expr: node
748 typ: typ
749 pos: pos
750 }
751 } else {
752 return node
753 }
754 } else if node !is ast.CastExpr && p.tok.kind == .left_shift && p.is_stmt_ident {
755 // arr << elem
756 tok := p.tok
757 mut pos := tok.pos()
758 p.next()
759 old_assign_rhs := p.inside_assign_rhs
760 p.inside_assign_rhs = true
761 right := p.expr(precedence - 1)
762 p.inside_assign_rhs = old_assign_rhs
763 pos.update_last_line(p.prev_tok.line_nr)
764 if mut node is ast.IndexExpr {
765 node.recursive_arraymap_set_is_setter()
766 }
767 node = ast.InfixExpr{
768 left: node
769 right: right
770 op: tok.kind
771 pos: pos
772 is_stmt: true
773 }
774 } else if p.tok.kind.is_infix()
775 && !(p.tok.kind in [.minus, .amp, .mul, .arrow, .key_as, .key_in, .key_is]
776 && p.tok.line_nr != p.prev_tok.line_nr) {
777 // continue on infix expr
778 p.promote_if_expr_to_value(mut node)
779 node = p.infix_expr(node)
780 // return early `if bar is SumType as b {`
781 if p.tok.kind == .key_as && p.inside_if {
782 return node
783 }
784 } else if p.tok.kind in [.inc, .dec] || (p.tok.kind == .question && p.inside_ct_if_expr) {
785 // Postfix
786 // detect `f(x++)`, `a[x++]`
787 if p.peek_tok.kind in [.rpar, .rsbr] {
788 if !p.inside_ct_if_expr {
789 if !p.pref.translated && !p.is_translated {
790 p.warn_with_pos('`${p.tok.kind}` operator can only be used as a statement',
791 p.tok.pos())
792 }
793 }
794 }
795
796 inc_dec_tok := p.tok.kind in [.inc, .dec]
797 same_line_with_prev := p.tok.line_nr == p.prev_tok.line_nr
798 same_line_with_next := p.tok.line_nr == p.peek_tok.line_nr
799 next_tok_name := p.peek_tok.kind == .name
800
801 // 1. name
802 // 2. ++
803 // ^^ current token
804 if inc_dec_tok && !same_line_with_prev && !next_tok_name {
805 p.error_with_pos('${p.tok} must be on the same line as the previous token',
806 p.tok.pos())
807 }
808
809 // a++ a--
810 // ^^ current token
811 // a[i]++ a--
812 // ^^ current token
813 // check if op attached to previous name
814 prev_name_or_rsbr := p.prev_tok.kind in [.name, .rsbr]
815 // 1. ++name
816 // ^^ current token
817 if inc_dec_tok && same_line_with_next && next_tok_name
818 && (!prev_name_or_rsbr || !same_line_with_prev) {
819 p.prefix_inc_dec_error()
820 }
821
822 if mut node is ast.IndexExpr {
823 node.recursive_mapset_is_setter(true)
824 }
825 is_c2v_prefix := p.peek_tok.kind == .dollar && p.peek_tok.is_next_to(p.tok)
826 node = ast.PostfixExpr{
827 op: p.tok.kind
828 expr: node
829 pos: p.tok.pos()
830 is_c2v_prefix: is_c2v_prefix
831 }
832 if is_c2v_prefix {
833 p.next()
834 }
835 p.next()
836 // return node // TODO: bring back, only allow ++/-- in exprs in translated code
837 } else {
838 return node
839 }
840 }
841 return node
842}
843
844fn (mut p Parser) promote_if_expr_to_value(mut expr ast.Expr) {
845 match mut expr {
846 ast.IfExpr {
847 expr.is_expr = true
848 expr.force_expr = true
849 }
850 else {}
851 }
852}
853
854fn unwrap_parenthesized_call_left(expr ast.Expr) ast.Expr {
855 return match expr {
856 ast.ParExpr { unwrap_parenthesized_call_left(expr.expr) }
857 else { expr }
858 }
859}
860
861fn (mut p Parser) call_expr_with_left(left ast.Expr) ast.CallExpr {
862 p.next()
863 pos := p.tok.pos()
864 args := p.call_args()
865 p.check(.rpar)
866 or_block := p.gen_or_block()
867 unwrapped_left := unwrap_parenthesized_call_left(left)
868 mut name := ''
869 mut name_pos := token.Pos{}
870 mut mod := ''
871 mut kind := ast.CallKind.unknown
872 if unwrapped_left is ast.Ident {
873 ident := unwrapped_left as ast.Ident
874 mut fn_name := ident.name
875 if p.is_imported_symbol(fn_name) {
876 check := !p.imported_symbols_used[fn_name]
877 fn_name = p.imported_symbols[fn_name]
878 if check {
879 p.register_used_import_for_symbol_name(fn_name)
880 }
881 }
882 name = fn_name
883 name_pos = ident.pos
884 mod = p.mod
885 kind = p.call_kind(fn_name)
886 }
887 return ast.CallExpr{
888 name: name
889 name_pos: name_pos
890 mod: mod
891 kind: kind
892 left: unwrapped_left
893 args: args
894 pos: pos
895 scope: p.scope
896 or_block: or_block
897 is_return_used: p.expecting_value
898 is_paren_wrapped_call: left is ast.ParExpr
899 }
900}
901
902fn (mut p Parser) gen_or_block() ast.OrExpr {
903 if p.tok.kind == .key_orelse {
904 // `foo() or {}``
905 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
906 return ast.OrExpr{
907 kind: ast.OrKind.block
908 stmts: or_stmts
909 pos: or_pos
910 scope: or_scope
911 }
912 } else if p.tok.kind in [.question, .not] {
913 or_pos := p.tok.pos()
914 is_not := p.tok.kind == .not
915 // `foo()?`
916 p.next()
917 if p.inside_defer {
918 p.error_with_pos('error propagation not allowed inside `defer` blocks',
919 p.prev_tok.pos())
920 }
921 return ast.OrExpr{
922 kind: if is_not { ast.OrKind.propagate_result } else { ast.OrKind.propagate_option }
923 scope: p.scope
924 pos: or_pos
925 }
926 } else {
927 return ast.OrExpr{
928 kind: ast.OrKind.absent
929 scope: ast.empty_scope
930 pos: p.tok.pos()
931 }
932 }
933}
934
935fn (mut p Parser) attach_or_block_to_parenthesized_expr(mut expr ast.Expr) bool {
936 if p.tok.kind != .key_orelse {
937 return false
938 }
939 match mut expr {
940 ast.CallExpr {
941 if expr.or_block.kind == .block {
942 return false
943 }
944 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
945 expr.or_block = ast.OrExpr{
946 kind: .block
947 stmts: or_stmts
948 pos: or_pos
949 scope: or_scope
950 }
951 return true
952 }
953 ast.ComptimeCall {
954 if expr.or_block.kind == .block {
955 return false
956 }
957 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
958 expr.or_block = ast.OrExpr{
959 kind: .block
960 stmts: or_stmts
961 pos: or_pos
962 scope: or_scope
963 }
964 return true
965 }
966 ast.Ident {
967 if expr.or_expr.kind == .block {
968 return false
969 }
970 err_var_mode := if expr.or_expr.kind in [.propagate_option, .propagate_result] {
971 OrBlockErrVarMode.with_err_var
972 } else {
973 OrBlockErrVarMode.no_err_var
974 }
975 or_stmts, or_pos, or_scope := p.or_block(err_var_mode)
976 expr.or_expr = ast.OrExpr{
977 kind: .block
978 stmts: or_stmts
979 pos: or_pos
980 scope: or_scope
981 }
982 return true
983 }
984 ast.IndexExpr {
985 if expr.or_expr.kind == .block {
986 return false
987 }
988 err_var_mode := if expr.or_expr.kind in [.propagate_option, .propagate_result] {
989 OrBlockErrVarMode.with_err_var
990 } else {
991 OrBlockErrVarMode.no_err_var
992 }
993 or_stmts, or_pos, or_scope := p.or_block(err_var_mode)
994 expr.or_expr = ast.OrExpr{
995 kind: .block
996 stmts: or_stmts
997 pos: or_pos
998 scope: or_scope
999 }
1000 return true
1001 }
1002 ast.InfixExpr {
1003 if expr.op != .arrow || expr.or_block.kind == .block {
1004 return false
1005 }
1006 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
1007 expr.or_block = ast.OrExpr{
1008 kind: .block
1009 stmts: or_stmts
1010 pos: or_pos
1011 scope: or_scope
1012 }
1013 return true
1014 }
1015 ast.ParExpr {
1016 return p.attach_or_block_to_parenthesized_expr(mut expr.expr)
1017 }
1018 ast.PrefixExpr {
1019 if expr.op != .arrow || expr.or_block.kind == .block {
1020 return false
1021 }
1022 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
1023 expr.or_block = ast.OrExpr{
1024 kind: .block
1025 stmts: or_stmts
1026 pos: or_pos
1027 scope: or_scope
1028 }
1029 return true
1030 }
1031 ast.SelectorExpr {
1032 if expr.or_block.kind == .block {
1033 return false
1034 }
1035 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
1036 expr.or_block = ast.OrExpr{
1037 kind: .block
1038 stmts: or_stmts
1039 pos: or_pos
1040 scope: or_scope
1041 }
1042 return true
1043 }
1044 else {
1045 return false
1046 }
1047 }
1048}
1049
1050fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
1051 prev_inside_infix := p.inside_infix
1052 p.inside_infix = true
1053 defer {
1054 p.inside_infix = prev_inside_infix
1055 }
1056 op := p.tok.kind
1057 if op == .arrow {
1058 p.or_is_handled = true
1059 p.register_auto_import('sync')
1060 } else if op == .power {
1061 p.register_auto_import('math')
1062 }
1063 precedence := p.tok.kind.precedence()
1064 mut pos := p.tok.pos()
1065 p.next()
1066 if p.inside_if_cond {
1067 p.if_cond_comments << p.eat_comments()
1068 }
1069 mut before_op_comments := []ast.Comment{}
1070 if p.pref.is_fmt && p.left_comments.len > 0 {
1071 before_op_comments = p.left_comments.clone()
1072 p.left_comments = []
1073 }
1074 p.left_comments = []
1075 after_op_comments := p.eat_comments()
1076 mut right := ast.empty_expr
1077 prev_expecting_type := p.expecting_type
1078 if op in [.key_is, .not_is] {
1079 p.expecting_type = true
1080 }
1081 is_key_in := op in [.key_in, .not_in]
1082 if is_key_in {
1083 p.inside_in_array = true
1084 }
1085
1086 right_op_pos := p.tok.pos()
1087 old_assign_rhs := p.inside_assign_rhs
1088 if op in [.decl_assign, .assign] {
1089 p.inside_assign_rhs = true
1090 }
1091 if p.inside_match_case && p.tok.kind == .lcbr {
1092 // In a match branch, a bare `{` opens the branch body; it is not the rhs of
1093 // the infix operator.
1094 p.unexpected(prepend_msg: 'invalid expression:')
1095 } else {
1096 right = p.expr(if op == .power { precedence - 1 } else { precedence })
1097 }
1098 p.inside_assign_rhs = old_assign_rhs
1099 // Keep rejecting doubled operator forms like `5 - - -5`, but allow valid
1100 // infix rhs expressions such as `a == -(-2)` and `a == +2`.
1101 if op in [.plus, .minus, .mul] && mut right is ast.PrefixExpr {
1102 mut right_expr := right.right
1103 right_expr = right_expr.remove_par()
1104 if right.op == op && right_expr.is_pure_literal() {
1105 p.error_with_pos('invalid expression: unexpected token `${op}`', right_op_pos)
1106 }
1107 }
1108 if is_key_in {
1109 if p.tok.kind == .dotdot {
1110 p.check(.dotdot)
1111 pos_high := p.tok.pos()
1112 right = ast.RangeExpr{
1113 low: right
1114 has_low: true
1115 high: p.expr(int(token.Precedence.in_as))
1116 has_high: true
1117 pos: pos_high
1118 is_gated: false
1119 }
1120 }
1121 p.inside_in_array = false
1122 }
1123 p.expecting_type = prev_expecting_type
1124 mut or_stmts := []ast.Stmt{}
1125 mut or_kind := ast.OrKind.absent
1126 mut or_pos := p.tok.pos()
1127 mut or_scope := ast.empty_scope
1128 // allow `x := <-ch or {...}` to handle closed channel
1129 if op == .arrow {
1130 if mut right is ast.SelectorExpr {
1131 or_kind = right.or_block.kind
1132 or_stmts = right.or_block.stmts.clone()
1133 right.or_block = ast.OrExpr{}
1134 }
1135 if mut right is ast.CallExpr {
1136 or_kind = right.or_block.kind
1137 or_stmts = right.or_block.stmts.clone()
1138 or_scope = right.or_block.scope
1139 right.or_block = ast.OrExpr{}
1140 }
1141 if p.tok.kind == .key_orelse {
1142 or_kind = .block
1143 or_stmts, or_pos, or_scope = p.or_block(.with_err_var)
1144 }
1145 if p.tok.kind == .question {
1146 p.next()
1147 or_kind = .propagate_option
1148 or_scope = p.scope
1149 }
1150 p.or_is_handled = false
1151 }
1152 pos.update_last_line(p.prev_tok.line_nr)
1153 return ast.InfixExpr{
1154 left: left
1155 right: right
1156 op: op
1157 pos: pos
1158 is_stmt: p.is_stmt_ident
1159 before_op_comments: before_op_comments
1160 after_op_comments: after_op_comments
1161 or_block: ast.OrExpr{
1162 stmts: or_stmts
1163 kind: or_kind
1164 pos: or_pos
1165 scope: or_scope
1166 }
1167 }
1168}
1169
1170fn (p &Parser) fileis(s string) bool {
1171 return p.file_path.contains(s)
1172}
1173
1174fn (mut p Parser) prefix_expr() ast.Expr {
1175 mut pos := p.tok.pos()
1176 is_option := p.tok.kind == .question
1177 if is_option {
1178 p.next()
1179 }
1180 op := p.tok.kind
1181 if op == .amp {
1182 p.is_amp = true
1183 }
1184 if op == .arrow {
1185 p.or_is_handled = true
1186 p.register_auto_import('sync')
1187 }
1188 // if op == .mul && !p.inside_unsafe {
1189 // p.warn('unsafe')
1190 // }
1191 p.next()
1192 mut right := p.expr(int(token.Precedence.prefix))
1193 p.is_amp = false
1194 if op == .amp {
1195 if mut right is ast.CastExpr {
1196 // Handle &Type(x), as well as &&Type(x) etc:
1197 p.recast_as_pointer(mut right, pos)
1198 if is_option {
1199 right.typ = right.typ.set_flag(.option)
1200 }
1201 return right
1202 }
1203 if mut right is ast.SelectorExpr {
1204 // Handle &Type(x).name :
1205 if mut right.expr is ast.CastExpr {
1206 p.recast_as_pointer(mut right.expr, pos)
1207 return right
1208 }
1209 }
1210 if mut right is ast.IndexExpr {
1211 // Handle &u64(x)[idx] :
1212 if mut right.left is ast.CastExpr {
1213 p.recast_as_pointer(mut right.left, pos)
1214 return right
1215 }
1216 }
1217 mut unwrapped_right := ast.Expr(ast.EmptyExpr{})
1218 if mut right is ast.ParExpr {
1219 if right.expr is ast.StructInit {
1220 p.note_with_pos('unnecessary `()`, use `&${ast.Expr(right.expr)}` instead of `&(${ast.Expr(right.expr)})`',
1221 right.pos)
1222 unwrapped_right = right.expr
1223 }
1224 }
1225 if unwrapped_right !is ast.EmptyExpr {
1226 right = unwrapped_right
1227 }
1228 if mut right is ast.TypeNode {
1229 right.typ = right.typ.ref()
1230 return right
1231 }
1232 }
1233 mut or_stmts := []ast.Stmt{}
1234 mut or_kind := ast.OrKind.absent
1235 mut or_pos := p.tok.pos()
1236 mut or_scope := ast.empty_scope
1237 // allow `x := <-ch or {...}` to handle closed channel
1238 if op == .arrow {
1239 if mut right is ast.SelectorExpr {
1240 or_kind = right.or_block.kind
1241 or_stmts = right.or_block.stmts.clone()
1242 right.or_block = ast.OrExpr{}
1243 } else if p.tok.kind == .key_orelse {
1244 or_kind = .block
1245 or_stmts, or_pos, or_scope = p.or_block(.with_err_var)
1246 } else if p.tok.kind == .question {
1247 p.next()
1248 or_kind = .propagate_option
1249 or_scope = p.scope
1250 }
1251 p.or_is_handled = false
1252 }
1253 pos.update_last_line(p.prev_tok.line_nr)
1254 return ast.PrefixExpr{
1255 op: op
1256 right: right
1257 pos: pos
1258 or_block: ast.OrExpr{
1259 stmts: or_stmts
1260 kind: or_kind
1261 pos: or_pos
1262 scope: or_scope
1263 }
1264 }
1265}
1266
1267fn (mut p Parser) power_prefix_expr() ast.Expr {
1268 pos := p.tok.pos()
1269 p.next()
1270 mut right := p.expr(int(token.Precedence.prefix))
1271 for _ in 0 .. 2 {
1272 right = ast.PrefixExpr{
1273 op: .mul
1274 right: right
1275 pos: pos
1276 }
1277 }
1278 return right
1279}
1280
1281fn (mut p Parser) recast_as_pointer(mut cast_expr ast.CastExpr, pos token.Pos) {
1282 cast_expr.typ = cast_expr.typ.ref()
1283 cast_expr.typname = if cast_expr.typ == 0 {
1284 p.table.sym(cast_expr.typ).name
1285 } else {
1286 'unknown type name'
1287 }
1288 cast_expr.pos = pos.extend(cast_expr.pos)
1289}
1290
1291// prefix_inc_dec_error reports an error for a prefix increment or decrement.
1292// prefix increments and decrements are not allowed in V.
1293fn (mut p Parser) prefix_inc_dec_error() {
1294 op := if p.tok.kind == .inc { '++' } else { '--' }
1295 op_pos := p.tok.pos()
1296
1297 p.next()
1298 expr := p.expr(0) // expression `mp["name"]` after `--` in `--mp["name"]`
1299 full_expr_pos := op_pos.extend(expr.pos()) // position of full `--mp["name"]`
1300
1301 p.error_with_pos('prefix `${op}${expr}` is unsupported, use suffix form `${expr}${op}`',
1302 full_expr_pos)
1303}
1304
1305// process_custom_orm_operators checks whether a word in infix expressions is an ORM operator.
1306// If it is, then a new kind is assigned to it, so that the parser will process it as a keyword.
1307// This is necessary to ensure that parts of the ORM expression do not function
1308// outside of the ORM and are not recognized as keywords in the language.
1309// For example, there is a `like` operator in ORM, which should be used
1310// in expressions like `name like 'M%'`, but it should not be used in V directly.
1311@[inline]
1312fn (mut p Parser) process_custom_orm_operators() {
1313 if !p.inside_orm {
1314 return
1315 }
1316
1317 is_like_operator := p.tok.kind == .name && p.tok.lit == 'like'
1318 is_ilike_operator := p.tok.kind == .name && p.tok.lit == 'ilike'
1319
1320 if is_like_operator {
1321 p.tok = token.Token{
1322 ...p.tok
1323 kind: .key_like
1324 }
1325 } else if is_ilike_operator {
1326 p.tok = token.Token{
1327 ...p.tok
1328 kind: .key_ilike
1329 }
1330 }
1331}
1332
1333fn (mut p Parser) lambda_expr() ?ast.LambdaExpr {
1334 // a) `f(||expr)` for a callback lambda expression with 0 arguments
1335 // b) `f(|a_1,...,a_n| expr_with_a_1_etc_till_a_n)` for a callback with several arguments
1336 if !(p.tok.kind == .logical_or
1337 || (p.peek_token(1).kind == .key_mut && p.peek_token(2).kind == .name)
1338 || (p.peek_token(1).kind == .name && p.peek_token(2).kind == .pipe)
1339 || (p.peek_token(1).kind == .name && p.peek_token(2).kind == .comma)) {
1340 return none
1341 }
1342
1343 p.open_scope()
1344 defer {
1345 p.close_scope()
1346 }
1347 p.scope.detached_from_parent = true
1348
1349 mut pos := p.tok.pos()
1350 mut params := []ast.Ident{}
1351 if p.tok.kind == .logical_or {
1352 p.check(.logical_or)
1353 } else {
1354 p.check(.pipe)
1355 for {
1356 if p.tok.kind == .eof {
1357 break
1358 }
1359 ident := p.ident(.v)
1360 if p.scope.known_var(ident.name) {
1361 p.error_with_pos('redefinition of parameter `${ident.name}`', ident.pos)
1362 }
1363 params << ident
1364
1365 p.scope.register(ast.Var{
1366 name: ident.name
1367 is_mut: p.scope_var_is_mut(ident.is_mut)
1368 is_stack_obj: true
1369 pos: ident.pos
1370 is_used: true
1371 is_arg: true
1372 })
1373
1374 if p.tok.kind == .pipe {
1375 p.next()
1376 break
1377 }
1378 p.check(.comma)
1379 }
1380 }
1381 pos_expr := p.tok.pos()
1382 e := p.expr(0)
1383 pos_end := p.tok.pos()
1384 return ast.LambdaExpr{
1385 pos: pos.extend(e.pos())
1386 pos_expr: pos_expr
1387 pos_end: pos_end
1388 params: params
1389 expr: e
1390 scope: p.scope
1391 }
1392}
1393