v2 / vlib / v / parser / expr.v
1391 lines · 1347 sloc · 34.63 KB · 8b5f74e6a7b52c1100cb52ef2832fd0c090fb407
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.peek_tok.kind == .dot && p.peek_token(2).kind == .name
89 && p.peek_token(2).lit[0].is_capital() && p.peek_token(3).kind == .lcbr
90 && p.peek_token(4).kind in [.rcbr, .name])) {
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.left_comments = p.eat_comments()
505 }
506 return p.expr_with_left(node, precedence, is_stmt_ident)
507}
508
509fn (p &Parser) is_explicit_anon_struct_init() bool {
510 mut n := 2
511 mut curlies := 1
512 for curlies > 0 {
513 tok := p.peek_token(n)
514 if tok.kind == .eof {
515 return false
516 }
517 if tok.kind == .lcbr {
518 curlies++
519 } else if tok.kind == .rcbr {
520 curlies--
521 }
522 n++
523 }
524 return p.peek_token(n).kind == .lcbr
525}
526
527fn (mut p Parser) parse_typeof_expr(start_pos token.Pos) ast.Expr {
528 p.next() // typeof
529 if p.tok.kind == .lsbr {
530 p.check(.lsbr)
531 type_pos := p.tok.pos()
532 typ := p.parse_type()
533 p.check(.rsbr)
534 p.check(.lpar)
535 p.check(.rpar)
536 return ast.TypeOf{
537 is_type: true
538 typ: typ
539 pos: type_pos.extend(p.tok.pos())
540 }
541 }
542 p.check(.lpar)
543 expr := p.expr(0)
544 p.check(.rpar)
545 if p.tok.kind != .dot && p.tok.line_nr == p.prev_tok.line_nr && !p.inside_array_init_type_expr {
546 if !p.inside_unsafe {
547 p.warn_with_pos('use e.g. `typeof(expr).name` or `sum_type_instance.type_name()` instead',
548 start_pos)
549 }
550 }
551 return ast.TypeOf{
552 is_type: false
553 expr: expr
554 pos: start_pos.extend(p.tok.pos())
555 }
556}
557
558fn (mut p Parser) parse_sizeof_or_isreftype_expr() ast.Expr {
559 is_reftype := p.tok.kind == .key_isreftype
560 p.next() // sizeof or isreftype
561 if p.tok.kind == .lsbr {
562 // parse sizeof[T]() and isreftype[T]() without guessing:
563 p.check(.lsbr)
564 mut type_pos := p.tok.pos()
565 typ := p.parse_type()
566 type_pos = type_pos.extend(p.tok.pos())
567 p.check(.rsbr)
568 p.check(.lpar)
569 p.check(.rpar)
570 if is_reftype {
571 return ast.IsRefType{
572 is_type: true
573 typ: typ
574 pos: type_pos
575 }
576 }
577 return ast.SizeOf{
578 is_type: true
579 typ: typ
580 pos: type_pos
581 }
582 }
583 p.check(.lpar)
584 pos := p.tok.pos()
585 mut is_known_var := p.scope.mark_var_as_used(p.tok.lit)
586 || p.table.global_scope.known_const(p.mod + '.' + p.tok.lit)
587 //|| p.table.known_fn(p.mod + '.' + p.tok.lit)
588 // assume `mod.` prefix leads to a type
589 mut is_type := p.known_import(p.tok.lit) || p.tok.kind.is_start_of_type()
590 || (p.tok.lit.len > 0 && p.tok.lit[0].is_capital())
591 if p.peek_tok.kind == .string && p.tok.lit in ['c', 'r'] {
592 is_known_var = false
593 is_type = false
594 }
595 if is_known_var || !is_type {
596 expr := p.expr(0)
597 if is_reftype {
598 result := ast.IsRefType{
599 is_type: false
600 expr: expr
601 pos: pos
602 }
603 p.check(.rpar)
604 return result
605 }
606 result := ast.SizeOf{
607 is_type: false
608 expr: expr
609 pos: pos
610 }
611 p.check(.rpar)
612 return result
613 }
614 if p.tok.kind == .name {
615 p.register_used_import(p.tok.lit)
616 }
617 save_expr_mod := p.expr_mod
618 p.expr_mod = ''
619 arg_type := p.parse_type()
620 p.expr_mod = save_expr_mod
621 p.check(.rpar)
622 if is_reftype {
623 return ast.IsRefType{
624 guessed_type: true
625 is_type: true
626 typ: arg_type
627 pos: pos
628 }
629 }
630 return ast.SizeOf{
631 guessed_type: true
632 is_type: true
633 typ: arg_type
634 pos: pos
635 }
636}
637
638fn (mut p Parser) parse_dump_expr(start_pos token.Pos) ast.Expr {
639 p.next() // dump
640 p.check(.lpar)
641 expr := p.expr(0)
642 if p.tok.kind == .comma && p.peek_tok.kind == .rpar {
643 p.next()
644 }
645 p.check(.rpar)
646 mut pos := p.tok.pos()
647 pos.update_last_line(p.prev_tok.line_nr)
648 return ast.DumpExpr{
649 expr: expr
650 pos: start_pos.extend(pos)
651 }
652}
653
654fn (mut p Parser) parse_offsetof_expr(start_pos token.Pos) ast.Expr {
655 p.next() // __offsetof
656 p.check(.lpar)
657 st := p.parse_type()
658 p.check(.comma)
659 if p.tok.kind != .name {
660 return p.unexpected(got: '`${p.tok.lit}`', additional_msg: 'expecting struct field')
661 }
662 field := p.tok.lit
663 p.next()
664 p.check(.rpar)
665 return ast.OffsetOf{
666 struct_type: st
667 field: field
668 pos: start_pos
669 }
670}
671
672fn (p &Parser) can_use_expr_as_struct_init_type(expr ast.Expr) bool {
673 return match expr {
674 ast.ParExpr {
675 p.can_use_expr_as_struct_init_type(expr.expr)
676 }
677 ast.SelectorExpr {
678 expr.expr is ast.TypeOf
679 && expr.field_name in ['idx', 'typ', 'unaliased_typ', 'key_type', 'value_type', 'element_type', 'pointee_type', 'payload_type']
680 }
681 else {
682 false
683 }
684 }
685}
686
687fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_ident bool) ast.Expr {
688 mut node := left
689 if p.inside_asm && p.prev_tok.pos().line_nr < p.tok.pos().line_nr {
690 return node
691 }
692
693 p.process_custom_orm_operators()
694
695 // Infix
696 for {
697 if p.tok.kind == .lpar && p.tok.line_nr == p.prev_tok.line_nr
698 && node in [ast.CallExpr, ast.IndexExpr, ast.ParExpr, ast.SelectorExpr] {
699 p.promote_if_expr_to_value(mut node)
700 node = p.call_expr_with_left(node)
701 p.is_stmt_ident = is_stmt_ident
702 continue
703 }
704 if !p.inside_array_init_type_expr && p.tok.kind == .lcbr && p.tok.is_next_to(p.prev_tok)
705 && p.can_use_expr_as_struct_init_type(node) {
706 node = p.struct_init_with_type_expr(node, .normal)
707 p.is_stmt_ident = is_stmt_ident
708 continue
709 }
710 if precedence >= p.tok.kind.precedence() {
711 return node
712 }
713 if p.tok.kind == .dot {
714 // no spaces or line break before dot in map_init
715 if (p.inside_map_init || p.inside_array_lit)
716 && p.tok.pos - p.prev_tok.pos > p.prev_tok.len {
717 return node
718 }
719 p.promote_if_expr_to_value(mut node)
720 node = p.dot_expr(node)
721 if p.name_error {
722 return node
723 }
724 p.is_stmt_ident = is_stmt_ident
725 } else if left !is ast.IntegerLiteral && p.tok.kind in [.lsbr, .nilsbr]
726 && (p.tok.line_nr == p.prev_tok.line_nr || (p.prev_tok.kind == .string
727 && p.tok.line_nr == p.prev_tok.line_nr + p.prev_tok.lit.count('\n'))) {
728 p.promote_if_expr_to_value(mut node)
729 if p.peek_tok.kind == .question && p.peek_token(2).kind == .name {
730 p.next()
731 p.error_with_pos('cannot use Option type name as concrete type', p.tok.pos())
732 } else if p.tok.kind == .nilsbr {
733 node = p.index_expr(node, true)
734 } else {
735 node = p.index_expr(node, false)
736 }
737 p.is_stmt_ident = is_stmt_ident
738 } else if p.tok.kind == .key_as && p.tok.line_nr == p.prev_tok.line_nr {
739 // sum type as cast `x := SumType as Variant`
740 if !p.inside_asm {
741 pos := p.tok.pos()
742 p.promote_if_expr_to_value(mut node)
743 p.next()
744 typ := p.parse_type()
745 node = ast.AsCast{
746 expr: node
747 typ: typ
748 pos: pos
749 }
750 } else {
751 return node
752 }
753 } else if node !is ast.CastExpr && p.tok.kind == .left_shift && p.is_stmt_ident {
754 // arr << elem
755 tok := p.tok
756 mut pos := tok.pos()
757 p.next()
758 old_assign_rhs := p.inside_assign_rhs
759 p.inside_assign_rhs = true
760 right := p.expr(precedence - 1)
761 p.inside_assign_rhs = old_assign_rhs
762 pos.update_last_line(p.prev_tok.line_nr)
763 if mut node is ast.IndexExpr {
764 node.recursive_arraymap_set_is_setter()
765 }
766 node = ast.InfixExpr{
767 left: node
768 right: right
769 op: tok.kind
770 pos: pos
771 is_stmt: true
772 }
773 } else if p.tok.kind.is_infix()
774 && !(p.tok.kind in [.minus, .amp, .mul, .arrow, .key_as, .key_in, .key_is]
775 && p.tok.line_nr != p.prev_tok.line_nr) {
776 // continue on infix expr
777 p.promote_if_expr_to_value(mut node)
778 node = p.infix_expr(node)
779 // return early `if bar is SumType as b {`
780 if p.tok.kind == .key_as && p.inside_if {
781 return node
782 }
783 } else if p.tok.kind in [.inc, .dec] || (p.tok.kind == .question && p.inside_ct_if_expr) {
784 // Postfix
785 // detect `f(x++)`, `a[x++]`
786 if p.peek_tok.kind in [.rpar, .rsbr] {
787 if !p.inside_ct_if_expr {
788 if !p.pref.translated && !p.is_translated {
789 p.warn_with_pos('`${p.tok.kind}` operator can only be used as a statement',
790 p.tok.pos())
791 }
792 }
793 }
794
795 inc_dec_tok := p.tok.kind in [.inc, .dec]
796 same_line_with_prev := p.tok.line_nr == p.prev_tok.line_nr
797 same_line_with_next := p.tok.line_nr == p.peek_tok.line_nr
798 next_tok_name := p.peek_tok.kind == .name
799
800 // 1. name
801 // 2. ++
802 // ^^ current token
803 if inc_dec_tok && !same_line_with_prev && !next_tok_name {
804 p.error_with_pos('${p.tok} must be on the same line as the previous token',
805 p.tok.pos())
806 }
807
808 // a++ a--
809 // ^^ current token
810 // a[i]++ a--
811 // ^^ current token
812 // check if op attached to previous name
813 prev_name_or_rsbr := p.prev_tok.kind in [.name, .rsbr]
814 // 1. ++name
815 // ^^ current token
816 if inc_dec_tok && same_line_with_next && next_tok_name
817 && (!prev_name_or_rsbr || !same_line_with_prev) {
818 p.prefix_inc_dec_error()
819 }
820
821 if mut node is ast.IndexExpr {
822 node.recursive_mapset_is_setter(true)
823 }
824 is_c2v_prefix := p.peek_tok.kind == .dollar && p.peek_tok.is_next_to(p.tok)
825 node = ast.PostfixExpr{
826 op: p.tok.kind
827 expr: node
828 pos: p.tok.pos()
829 is_c2v_prefix: is_c2v_prefix
830 }
831 if is_c2v_prefix {
832 p.next()
833 }
834 p.next()
835 // return node // TODO: bring back, only allow ++/-- in exprs in translated code
836 } else {
837 return node
838 }
839 }
840 return node
841}
842
843fn (mut p Parser) promote_if_expr_to_value(mut expr ast.Expr) {
844 match mut expr {
845 ast.IfExpr {
846 expr.is_expr = true
847 expr.force_expr = true
848 }
849 else {}
850 }
851}
852
853fn unwrap_parenthesized_call_left(expr ast.Expr) ast.Expr {
854 return match expr {
855 ast.ParExpr { unwrap_parenthesized_call_left(expr.expr) }
856 else { expr }
857 }
858}
859
860fn (mut p Parser) call_expr_with_left(left ast.Expr) ast.CallExpr {
861 p.next()
862 pos := p.tok.pos()
863 args := p.call_args()
864 p.check(.rpar)
865 or_block := p.gen_or_block()
866 unwrapped_left := unwrap_parenthesized_call_left(left)
867 mut name := ''
868 mut name_pos := token.Pos{}
869 mut mod := ''
870 mut kind := ast.CallKind.unknown
871 if unwrapped_left is ast.Ident {
872 ident := unwrapped_left as ast.Ident
873 mut fn_name := ident.name
874 if p.is_imported_symbol(fn_name) {
875 check := !p.imported_symbols_used[fn_name]
876 fn_name = p.imported_symbols[fn_name]
877 if check {
878 p.register_used_import_for_symbol_name(fn_name)
879 }
880 }
881 name = fn_name
882 name_pos = ident.pos
883 mod = p.mod
884 kind = p.call_kind(fn_name)
885 }
886 return ast.CallExpr{
887 name: name
888 name_pos: name_pos
889 mod: mod
890 kind: kind
891 left: unwrapped_left
892 args: args
893 pos: pos
894 scope: p.scope
895 or_block: or_block
896 is_return_used: p.expecting_value
897 is_paren_wrapped_call: left is ast.ParExpr
898 }
899}
900
901fn (mut p Parser) gen_or_block() ast.OrExpr {
902 if p.tok.kind == .key_orelse {
903 // `foo() or {}``
904 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
905 return ast.OrExpr{
906 kind: ast.OrKind.block
907 stmts: or_stmts
908 pos: or_pos
909 scope: or_scope
910 }
911 } else if p.tok.kind in [.question, .not] {
912 or_pos := p.tok.pos()
913 is_not := p.tok.kind == .not
914 // `foo()?`
915 p.next()
916 if p.inside_defer {
917 p.error_with_pos('error propagation not allowed inside `defer` blocks',
918 p.prev_tok.pos())
919 }
920 return ast.OrExpr{
921 kind: if is_not { ast.OrKind.propagate_result } else { ast.OrKind.propagate_option }
922 scope: p.scope
923 pos: or_pos
924 }
925 } else {
926 return ast.OrExpr{
927 kind: ast.OrKind.absent
928 scope: ast.empty_scope
929 pos: p.tok.pos()
930 }
931 }
932}
933
934fn (mut p Parser) attach_or_block_to_parenthesized_expr(mut expr ast.Expr) bool {
935 if p.tok.kind != .key_orelse {
936 return false
937 }
938 match mut expr {
939 ast.CallExpr {
940 if expr.or_block.kind == .block {
941 return false
942 }
943 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
944 expr.or_block = ast.OrExpr{
945 kind: .block
946 stmts: or_stmts
947 pos: or_pos
948 scope: or_scope
949 }
950 return true
951 }
952 ast.ComptimeCall {
953 if expr.or_block.kind == .block {
954 return false
955 }
956 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
957 expr.or_block = ast.OrExpr{
958 kind: .block
959 stmts: or_stmts
960 pos: or_pos
961 scope: or_scope
962 }
963 return true
964 }
965 ast.Ident {
966 if expr.or_expr.kind == .block {
967 return false
968 }
969 err_var_mode := if expr.or_expr.kind in [.propagate_option, .propagate_result] {
970 OrBlockErrVarMode.with_err_var
971 } else {
972 OrBlockErrVarMode.no_err_var
973 }
974 or_stmts, or_pos, or_scope := p.or_block(err_var_mode)
975 expr.or_expr = ast.OrExpr{
976 kind: .block
977 stmts: or_stmts
978 pos: or_pos
979 scope: or_scope
980 }
981 return true
982 }
983 ast.IndexExpr {
984 if expr.or_expr.kind == .block {
985 return false
986 }
987 err_var_mode := if expr.or_expr.kind in [.propagate_option, .propagate_result] {
988 OrBlockErrVarMode.with_err_var
989 } else {
990 OrBlockErrVarMode.no_err_var
991 }
992 or_stmts, or_pos, or_scope := p.or_block(err_var_mode)
993 expr.or_expr = ast.OrExpr{
994 kind: .block
995 stmts: or_stmts
996 pos: or_pos
997 scope: or_scope
998 }
999 return true
1000 }
1001 ast.InfixExpr {
1002 if expr.op != .arrow || expr.or_block.kind == .block {
1003 return false
1004 }
1005 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
1006 expr.or_block = ast.OrExpr{
1007 kind: .block
1008 stmts: or_stmts
1009 pos: or_pos
1010 scope: or_scope
1011 }
1012 return true
1013 }
1014 ast.ParExpr {
1015 return p.attach_or_block_to_parenthesized_expr(mut expr.expr)
1016 }
1017 ast.PrefixExpr {
1018 if expr.op != .arrow || expr.or_block.kind == .block {
1019 return false
1020 }
1021 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
1022 expr.or_block = ast.OrExpr{
1023 kind: .block
1024 stmts: or_stmts
1025 pos: or_pos
1026 scope: or_scope
1027 }
1028 return true
1029 }
1030 ast.SelectorExpr {
1031 if expr.or_block.kind == .block {
1032 return false
1033 }
1034 or_stmts, or_pos, or_scope := p.or_block(.with_err_var)
1035 expr.or_block = ast.OrExpr{
1036 kind: .block
1037 stmts: or_stmts
1038 pos: or_pos
1039 scope: or_scope
1040 }
1041 return true
1042 }
1043 else {
1044 return false
1045 }
1046 }
1047}
1048
1049fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
1050 prev_inside_infix := p.inside_infix
1051 p.inside_infix = true
1052 defer {
1053 p.inside_infix = prev_inside_infix
1054 }
1055 op := p.tok.kind
1056 if op == .arrow {
1057 p.or_is_handled = true
1058 p.register_auto_import('sync')
1059 } else if op == .power {
1060 p.register_auto_import('math')
1061 }
1062 precedence := p.tok.kind.precedence()
1063 mut pos := p.tok.pos()
1064 p.next()
1065 if p.inside_if_cond {
1066 p.if_cond_comments << p.eat_comments()
1067 }
1068 mut before_op_comments := []ast.Comment{}
1069 if p.pref.is_fmt && p.left_comments.len > 0 {
1070 before_op_comments = p.left_comments.clone()
1071 p.left_comments = []
1072 }
1073 p.left_comments = []
1074 after_op_comments := p.eat_comments()
1075 mut right := ast.empty_expr
1076 prev_expecting_type := p.expecting_type
1077 if op in [.key_is, .not_is] {
1078 p.expecting_type = true
1079 }
1080 is_key_in := op in [.key_in, .not_in]
1081 if is_key_in {
1082 p.inside_in_array = true
1083 }
1084
1085 right_op_pos := p.tok.pos()
1086 old_assign_rhs := p.inside_assign_rhs
1087 if op in [.decl_assign, .assign] {
1088 p.inside_assign_rhs = true
1089 }
1090 if p.inside_match_case && p.tok.kind == .lcbr {
1091 // In a match branch, a bare `{` opens the branch body; it is not the rhs of
1092 // the infix operator.
1093 p.unexpected(prepend_msg: 'invalid expression:')
1094 } else {
1095 right = p.expr(if op == .power { precedence - 1 } else { precedence })
1096 }
1097 p.inside_assign_rhs = old_assign_rhs
1098 // Keep rejecting doubled operator forms like `5 - - -5`, but allow valid
1099 // infix rhs expressions such as `a == -(-2)` and `a == +2`.
1100 if op in [.plus, .minus, .mul] && mut right is ast.PrefixExpr {
1101 mut right_expr := right.right
1102 right_expr = right_expr.remove_par()
1103 if right.op == op && right_expr.is_pure_literal() {
1104 p.error_with_pos('invalid expression: unexpected token `${op}`', right_op_pos)
1105 }
1106 }
1107 if is_key_in {
1108 if p.tok.kind == .dotdot {
1109 p.check(.dotdot)
1110 pos_high := p.tok.pos()
1111 right = ast.RangeExpr{
1112 low: right
1113 has_low: true
1114 high: p.expr(int(token.Precedence.in_as))
1115 has_high: true
1116 pos: pos_high
1117 is_gated: false
1118 }
1119 }
1120 p.inside_in_array = false
1121 }
1122 p.expecting_type = prev_expecting_type
1123 mut or_stmts := []ast.Stmt{}
1124 mut or_kind := ast.OrKind.absent
1125 mut or_pos := p.tok.pos()
1126 mut or_scope := ast.empty_scope
1127 // allow `x := <-ch or {...}` to handle closed channel
1128 if op == .arrow {
1129 if mut right is ast.SelectorExpr {
1130 or_kind = right.or_block.kind
1131 or_stmts = right.or_block.stmts.clone()
1132 right.or_block = ast.OrExpr{}
1133 }
1134 if mut right is ast.CallExpr {
1135 or_kind = right.or_block.kind
1136 or_stmts = right.or_block.stmts.clone()
1137 or_scope = right.or_block.scope
1138 right.or_block = ast.OrExpr{}
1139 }
1140 if p.tok.kind == .key_orelse {
1141 or_kind = .block
1142 or_stmts, or_pos, or_scope = p.or_block(.with_err_var)
1143 }
1144 if p.tok.kind == .question {
1145 p.next()
1146 or_kind = .propagate_option
1147 or_scope = p.scope
1148 }
1149 p.or_is_handled = false
1150 }
1151 pos.update_last_line(p.prev_tok.line_nr)
1152 return ast.InfixExpr{
1153 left: left
1154 right: right
1155 op: op
1156 pos: pos
1157 is_stmt: p.is_stmt_ident
1158 before_op_comments: before_op_comments
1159 after_op_comments: after_op_comments
1160 or_block: ast.OrExpr{
1161 stmts: or_stmts
1162 kind: or_kind
1163 pos: or_pos
1164 scope: or_scope
1165 }
1166 }
1167}
1168
1169fn (p &Parser) fileis(s string) bool {
1170 return p.file_path.contains(s)
1171}
1172
1173fn (mut p Parser) prefix_expr() ast.Expr {
1174 mut pos := p.tok.pos()
1175 is_option := p.tok.kind == .question
1176 if is_option {
1177 p.next()
1178 }
1179 op := p.tok.kind
1180 if op == .amp {
1181 p.is_amp = true
1182 }
1183 if op == .arrow {
1184 p.or_is_handled = true
1185 p.register_auto_import('sync')
1186 }
1187 // if op == .mul && !p.inside_unsafe {
1188 // p.warn('unsafe')
1189 // }
1190 p.next()
1191 mut right := p.expr(int(token.Precedence.prefix))
1192 p.is_amp = false
1193 if op == .amp {
1194 if mut right is ast.CastExpr {
1195 // Handle &Type(x), as well as &&Type(x) etc:
1196 p.recast_as_pointer(mut right, pos)
1197 if is_option {
1198 right.typ = right.typ.set_flag(.option)
1199 }
1200 return right
1201 }
1202 if mut right is ast.SelectorExpr {
1203 // Handle &Type(x).name :
1204 if mut right.expr is ast.CastExpr {
1205 p.recast_as_pointer(mut right.expr, pos)
1206 return right
1207 }
1208 }
1209 if mut right is ast.IndexExpr {
1210 // Handle &u64(x)[idx] :
1211 if mut right.left is ast.CastExpr {
1212 p.recast_as_pointer(mut right.left, pos)
1213 return right
1214 }
1215 }
1216 mut unwrapped_right := ast.Expr(ast.EmptyExpr{})
1217 if mut right is ast.ParExpr {
1218 if right.expr is ast.StructInit {
1219 p.note_with_pos('unnecessary `()`, use `&${ast.Expr(right.expr)}` instead of `&(${ast.Expr(right.expr)})`',
1220 right.pos)
1221 unwrapped_right = right.expr
1222 }
1223 }
1224 if unwrapped_right !is ast.EmptyExpr {
1225 right = unwrapped_right
1226 }
1227 if mut right is ast.TypeNode {
1228 right.typ = right.typ.ref()
1229 return right
1230 }
1231 }
1232 mut or_stmts := []ast.Stmt{}
1233 mut or_kind := ast.OrKind.absent
1234 mut or_pos := p.tok.pos()
1235 mut or_scope := ast.empty_scope
1236 // allow `x := <-ch or {...}` to handle closed channel
1237 if op == .arrow {
1238 if mut right is ast.SelectorExpr {
1239 or_kind = right.or_block.kind
1240 or_stmts = right.or_block.stmts.clone()
1241 right.or_block = ast.OrExpr{}
1242 } else if p.tok.kind == .key_orelse {
1243 or_kind = .block
1244 or_stmts, or_pos, or_scope = p.or_block(.with_err_var)
1245 } else if p.tok.kind == .question {
1246 p.next()
1247 or_kind = .propagate_option
1248 or_scope = p.scope
1249 }
1250 p.or_is_handled = false
1251 }
1252 pos.update_last_line(p.prev_tok.line_nr)
1253 return ast.PrefixExpr{
1254 op: op
1255 right: right
1256 pos: pos
1257 or_block: ast.OrExpr{
1258 stmts: or_stmts
1259 kind: or_kind
1260 pos: or_pos
1261 scope: or_scope
1262 }
1263 }
1264}
1265
1266fn (mut p Parser) power_prefix_expr() ast.Expr {
1267 pos := p.tok.pos()
1268 p.next()
1269 mut right := p.expr(int(token.Precedence.prefix))
1270 for _ in 0 .. 2 {
1271 right = ast.PrefixExpr{
1272 op: .mul
1273 right: right
1274 pos: pos
1275 }
1276 }
1277 return right
1278}
1279
1280fn (mut p Parser) recast_as_pointer(mut cast_expr ast.CastExpr, pos token.Pos) {
1281 cast_expr.typ = cast_expr.typ.ref()
1282 cast_expr.typname = if cast_expr.typ == 0 {
1283 p.table.sym(cast_expr.typ).name
1284 } else {
1285 'unknown type name'
1286 }
1287 cast_expr.pos = pos.extend(cast_expr.pos)
1288}
1289
1290// prefix_inc_dec_error reports an error for a prefix increment or decrement.
1291// prefix increments and decrements are not allowed in V.
1292fn (mut p Parser) prefix_inc_dec_error() {
1293 op := if p.tok.kind == .inc { '++' } else { '--' }
1294 op_pos := p.tok.pos()
1295
1296 p.next()
1297 expr := p.expr(0) // expression `mp["name"]` after `--` in `--mp["name"]`
1298 full_expr_pos := op_pos.extend(expr.pos()) // position of full `--mp["name"]`
1299
1300 p.error_with_pos('prefix `${op}${expr}` is unsupported, use suffix form `${expr}${op}`',
1301 full_expr_pos)
1302}
1303
1304// process_custom_orm_operators checks whether a word in infix expressions is an ORM operator.
1305// If it is, then a new kind is assigned to it, so that the parser will process it as a keyword.
1306// This is necessary to ensure that parts of the ORM expression do not function
1307// outside of the ORM and are not recognized as keywords in the language.
1308// For example, there is a `like` operator in ORM, which should be used
1309// in expressions like `name like 'M%'`, but it should not be used in V directly.
1310@[inline]
1311fn (mut p Parser) process_custom_orm_operators() {
1312 if !p.inside_orm {
1313 return
1314 }
1315
1316 is_like_operator := p.tok.kind == .name && p.tok.lit == 'like'
1317 is_ilike_operator := p.tok.kind == .name && p.tok.lit == 'ilike'
1318
1319 if is_like_operator {
1320 p.tok = token.Token{
1321 ...p.tok
1322 kind: .key_like
1323 }
1324 } else if is_ilike_operator {
1325 p.tok = token.Token{
1326 ...p.tok
1327 kind: .key_ilike
1328 }
1329 }
1330}
1331
1332fn (mut p Parser) lambda_expr() ?ast.LambdaExpr {
1333 // a) `f(||expr)` for a callback lambda expression with 0 arguments
1334 // b) `f(|a_1,...,a_n| expr_with_a_1_etc_till_a_n)` for a callback with several arguments
1335 if !(p.tok.kind == .logical_or
1336 || (p.peek_token(1).kind == .key_mut && p.peek_token(2).kind == .name)
1337 || (p.peek_token(1).kind == .name && p.peek_token(2).kind == .pipe)
1338 || (p.peek_token(1).kind == .name && p.peek_token(2).kind == .comma)) {
1339 return none
1340 }
1341
1342 p.open_scope()
1343 defer {
1344 p.close_scope()
1345 }
1346 p.scope.detached_from_parent = true
1347
1348 mut pos := p.tok.pos()
1349 mut params := []ast.Ident{}
1350 if p.tok.kind == .logical_or {
1351 p.check(.logical_or)
1352 } else {
1353 p.check(.pipe)
1354 for {
1355 if p.tok.kind == .eof {
1356 break
1357 }
1358 ident := p.ident(.v)
1359 if p.scope.known_var(ident.name) {
1360 p.error_with_pos('redefinition of parameter `${ident.name}`', ident.pos)
1361 }
1362 params << ident
1363
1364 p.scope.register(ast.Var{
1365 name: ident.name
1366 is_mut: p.scope_var_is_mut(ident.is_mut)
1367 is_stack_obj: true
1368 pos: ident.pos
1369 is_used: true
1370 is_arg: true
1371 })
1372
1373 if p.tok.kind == .pipe {
1374 p.next()
1375 break
1376 }
1377 p.check(.comma)
1378 }
1379 }
1380 pos_expr := p.tok.pos()
1381 e := p.expr(0)
1382 pos_end := p.tok.pos()
1383 return ast.LambdaExpr{
1384 pos: pos.extend(e.pos())
1385 pos_expr: pos_expr
1386 pos_end: pos_end
1387 params: params
1388 expr: e
1389 scope: p.scope
1390 }
1391}
1392