parser/grammar/expressions/
atom.rs

1use crate::grammar::types::type_;
2
3use super::*;
4
5// test expr_literals
6// fn foo() {
7//     let _ = true;
8//     let _ = false;
9//     let _ = 1;
10//     let _ = 2.0;
11//     let _ = b'a';
12//     let _ = 'b';
13//     let _ = "c";
14//     let _ = r"d";
15//     let _ = b"e";
16//     let _ = br"f";
17//     let _ = c"g";
18//     let _ = cr"h";
19// }
20pub(crate) const LITERAL_FIRST: TokenSet = TokenSet::new(&[
21    T![true],
22    T![false],
23    INT_NUMBER,
24    FLOAT_NUMBER,
25    BYTE,
26    CHAR,
27    STRING,
28    BYTE_STRING,
29    C_STRING,
30]);
31
32pub(crate) fn literal(p: &mut Parser<'_>) -> Option<CompletedMarker> {
33    if !p.at_ts(LITERAL_FIRST) {
34        return None;
35    }
36    let m = p.start();
37    p.bump_any();
38    Some(m.complete(p, LITERAL))
39}
40
41// E.g. for after the break in `if break {}`, this should not match
42pub(super) const ATOM_EXPR_FIRST: TokenSet =
43    LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[
44        T!['('],
45        T!['{'],
46        T!['['],
47        T![|],
48        T![async],
49        T![break],
50        T![const],
51        T![continue],
52        T![do],
53        T![gen],
54        T![for],
55        T![if],
56        T![let],
57        T![loop],
58        T![match],
59        T![move],
60        T![return],
61        T![become],
62        T![static],
63        T![try],
64        T![unsafe],
65        T![while],
66        T![yield],
67        LIFETIME_IDENT,
68    ]));
69
70pub(in crate::grammar) const EXPR_RECOVERY_SET: TokenSet =
71    TokenSet::new(&[T!['}'], T![')'], T![']'], T![,]]);
72
73pub(super) fn atom_expr(
74    p: &mut Parser<'_>,
75    r: Restrictions,
76) -> Option<(CompletedMarker, BlockLike)> {
77    if let Some(m) = literal(p) {
78        return Some((m, BlockLike::NotBlock));
79    }
80    if p.at_contextual_kw(T![builtin]) && p.nth_at(1, T![#]) {
81        return Some((builtin_expr(p)?, BlockLike::NotBlock));
82    }
83    if paths::is_path_start(p) {
84        return Some(path_expr(p, r));
85    }
86    let la = p.nth(1);
87    let done = match p.current() {
88        T!['('] => tuple_expr(p),
89        T!['['] => array_expr(p),
90        T![if] => if_expr(p),
91        T![let] => let_expr(p),
92        T![_] => {
93            // test destructuring_assignment_wildcard_pat
94            // fn foo() {
95            //     _ = 1;
96            //     Some(_) = None;
97            // }
98            let m = p.start();
99            p.bump(T![_]);
100            m.complete(p, UNDERSCORE_EXPR)
101        }
102        T![loop] => loop_expr(p, None),
103        T![while] => while_expr(p, None),
104        // test try_macro_fallback 2015
105        // fn foo() { try!(Ok(())); }
106        T![try] => try_block_expr(p, None),
107        T![match] => match_expr(p),
108        T![return] => return_expr(p),
109        T![become] => become_expr(p),
110        T![yield] => yield_expr(p),
111        T![do] if p.nth_at_contextual_kw(1, T![yeet]) => yeet_expr(p),
112        T![continue] => continue_expr(p),
113        T![break] => break_expr(p, r),
114
115        LIFETIME_IDENT if la == T![:] => {
116            let m = p.start();
117            label(p);
118            match p.current() {
119                T![loop] => loop_expr(p, Some(m)),
120                T![for] => for_expr(p, Some(m)),
121                T![while] => while_expr(p, Some(m)),
122                // test labeled_block
123                // fn f() { 'label: {}; }
124                T!['{'] => {
125                    stmt_list(p);
126                    m.complete(p, BLOCK_EXPR)
127                }
128                _ => {
129                    // test_err misplaced_label_err
130                    // fn main() {
131                    //     'loop: impl
132                    // }
133                    p.error("expected a loop or block");
134                    m.complete(p, ERROR);
135                    return None;
136                }
137            }
138        }
139        // test effect_blocks
140        // fn f() { unsafe { } }
141        // fn f() { const { } }
142        // fn f() { async { } }
143        // fn f() { async move { } }
144        T![const] | T![unsafe] | T![async] | T![gen] if la == T!['{'] => {
145            let m = p.start();
146            p.bump_any();
147            stmt_list(p);
148            m.complete(p, BLOCK_EXPR)
149        }
150        // test gen_blocks 2024
151        // pub fn main() {
152        //     gen { yield ""; };
153        //     async gen { yield ""; };
154        //     gen move { yield ""; };
155        //     async gen move { yield ""; };
156        // }
157        T![async] if la == T![gen] && p.nth(2) == T!['{'] => {
158            let m = p.start();
159            p.bump(T![async]);
160            p.eat(T![gen]);
161            stmt_list(p);
162            m.complete(p, BLOCK_EXPR)
163        }
164        T![async] | T![gen] if la == T![move] && p.nth(2) == T!['{'] => {
165            let m = p.start();
166            p.bump_any();
167            p.bump(T![move]);
168            stmt_list(p);
169            m.complete(p, BLOCK_EXPR)
170        }
171        T![async] if la == T![gen] && p.nth(2) == T![move] && p.nth(3) == T!['{'] => {
172            let m = p.start();
173            p.bump(T![async]);
174            p.bump(T![gen]);
175            p.bump(T![move]);
176            stmt_list(p);
177            m.complete(p, BLOCK_EXPR)
178        }
179        T!['{'] => {
180            // test for_range_from
181            // fn foo() {
182            //    for x in 0 .. {
183            //        break;
184            //    }
185            // }
186            let m = p.start();
187            stmt_list(p);
188            m.complete(p, BLOCK_EXPR)
189        }
190
191        T![const] | T![static] | T![async] | T![move] | T![|] => closure_expr(p),
192        T![for] if la == T![<] => closure_expr(p),
193        T![for] => for_expr(p, None),
194
195        _ => {
196            p.err_and_bump("expected expression");
197            return None;
198        }
199    };
200    let blocklike =
201        if BlockLike::is_blocklike(done.kind()) { BlockLike::Block } else { BlockLike::NotBlock };
202    Some((done, blocklike))
203}
204
205// test tuple_expr
206// fn foo() {
207//     ();
208//     (1);
209//     (1,);
210// }
211fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {
212    assert!(p.at(T!['(']));
213    let m = p.start();
214    p.expect(T!['(']);
215
216    let mut saw_comma = false;
217    let mut saw_expr = false;
218
219    // test_err tuple_expr_leading_comma
220    // fn foo() {
221    //     (,);
222    // }
223    if p.eat(T![,]) {
224        p.error("expected expression");
225        saw_comma = true;
226    }
227
228    while !p.at(EOF) && !p.at(T![')']) {
229        saw_expr = true;
230
231        // test tuple_attrs
232        // const A: (i64, i64) = (1, #[cfg(test)] 2);
233        if expr(p).is_none() {
234            break;
235        }
236
237        if !p.at(T![')']) {
238            saw_comma = true;
239            p.expect(T![,]);
240        }
241    }
242    p.expect(T![')']);
243    m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
244}
245
246// test builtin_expr
247// fn foo() {
248//     builtin#asm("");
249//     builtin#format_args("", 0, 1, a = 2 + 3, a + b);
250//     builtin#offset_of(Foo, bar.baz.0);
251// }
252fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
253    let m = p.start();
254    p.bump_remap(T![builtin]);
255    p.bump(T![#]);
256    if p.eat_contextual_kw(T![offset_of]) {
257        p.expect(T!['(']);
258        type_(p);
259        p.expect(T![,]);
260        // Due to our incomplete handling of macro groups, especially
261        // those with empty delimiters, we wrap `expr` fragments in
262        // parentheses sometimes. Since `offset_of` is a macro, and takes
263        // `expr`, the field names could be wrapped in parentheses.
264        let wrapped_in_parens = p.eat(T!['(']);
265        // test offset_of_parens
266        // fn foo() {
267        //     builtin#offset_of(Foo, (bar.baz.0));
268        // }
269        while !p.at(EOF) && !p.at(T![')']) {
270            name_ref_mod_path_or_index(p);
271            if !p.at(T![')']) {
272                p.expect(T![.]);
273            }
274        }
275        p.expect(T![')']);
276        if wrapped_in_parens {
277            p.expect(T![')']);
278        }
279        Some(m.complete(p, OFFSET_OF_EXPR))
280    } else if p.eat_contextual_kw(T![format_args]) {
281        p.expect(T!['(']);
282        expr(p);
283        if p.eat(T![,]) {
284            while !p.at(EOF) && !p.at(T![')']) {
285                let m = p.start();
286                if p.at(IDENT) && p.nth_at(1, T![=]) && !p.nth_at(2, T![=]) {
287                    name(p);
288                    p.bump(T![=]);
289                }
290                if expr(p).is_none() {
291                    m.abandon(p);
292                    break;
293                }
294                m.complete(p, FORMAT_ARGS_ARG);
295
296                if !p.at(T![')']) {
297                    p.expect(T![,]);
298                }
299            }
300        }
301        p.expect(T![')']);
302        Some(m.complete(p, FORMAT_ARGS_EXPR))
303    } else if p.eat_contextual_kw(T![asm])
304        || p.eat_contextual_kw(T![global_asm])
305        || p.eat_contextual_kw(T![naked_asm])
306    {
307        // test asm_kinds
308        // fn foo() {
309        //     builtin#asm("");
310        //     builtin#global_asm("");
311        //     builtin#naked_asm("");
312        // }
313        parse_asm_expr(p, m)
314    } else {
315        m.abandon(p);
316        None
317    }
318}
319
320// test asm_expr
321// fn foo() {
322//     builtin#asm(
323//         "mov {tmp}, {x}",
324//         "shl {tmp}, 1",
325//         "shl {x}, 2",
326//         "add {x}, {tmp}",
327//         x = inout(reg) x,
328//         tmp = out(reg) _,
329//     );
330// }
331pub(crate) fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> {
332    p.expect(T!['(']);
333    if expr(p).is_none() {
334        p.err_and_bump("expected asm template");
335    }
336    let mut allow_templates = true;
337    while !p.at(EOF) && !p.at(T![')']) {
338        p.expect(T![,]);
339        // accept trailing commas
340        if p.at(T![')']) {
341            break;
342        }
343
344        let op_n = p.start();
345        // Parse clobber_abi
346        if p.eat_contextual_kw(T![clobber_abi]) {
347            parse_clobber_abi(p);
348            op_n.complete(p, ASM_CLOBBER_ABI);
349            allow_templates = false;
350            continue;
351        }
352
353        // Parse options
354        if p.eat_contextual_kw(T![options]) {
355            parse_options(p);
356            op_n.complete(p, ASM_OPTIONS);
357            allow_templates = false;
358            continue;
359        }
360
361        // Parse operand names
362        if p.at(T![ident]) && p.nth_at(1, T![=]) {
363            name(p);
364            p.bump(T![=]);
365            allow_templates = false;
366        }
367
368        let op = p.start();
369        let dir_spec = p.start();
370        if p.eat(T![in]) || p.eat_contextual_kw(T![out]) || p.eat_contextual_kw(T![lateout]) {
371            dir_spec.complete(p, ASM_DIR_SPEC);
372            parse_reg(p);
373            let op_expr = p.start();
374            expr(p);
375            op_expr.complete(p, ASM_OPERAND_EXPR);
376            op.complete(p, ASM_REG_OPERAND);
377            op_n.complete(p, ASM_OPERAND_NAMED);
378        } else if p.eat_contextual_kw(T![inout]) || p.eat_contextual_kw(T![inlateout]) {
379            dir_spec.complete(p, ASM_DIR_SPEC);
380            parse_reg(p);
381            let op_expr = p.start();
382            expr(p);
383            if p.eat(T![=>]) {
384                expr(p);
385            }
386            op_expr.complete(p, ASM_OPERAND_EXPR);
387            op.complete(p, ASM_REG_OPERAND);
388            op_n.complete(p, ASM_OPERAND_NAMED);
389        } else if p.eat_contextual_kw(T![label]) {
390            // test asm_label
391            // fn foo() {
392            //     builtin#asm("", label {});
393            // }
394            dir_spec.abandon(p);
395            block_expr(p);
396            op.complete(p, ASM_LABEL);
397            op_n.complete(p, ASM_OPERAND_NAMED);
398        } else if p.eat(T![const]) {
399            dir_spec.abandon(p);
400            expr(p);
401            op.complete(p, ASM_CONST);
402            op_n.complete(p, ASM_OPERAND_NAMED);
403        } else if p.eat_contextual_kw(T![sym]) {
404            dir_spec.abandon(p);
405            paths::type_path(p);
406            op.complete(p, ASM_SYM);
407            op_n.complete(p, ASM_OPERAND_NAMED);
408        } else if allow_templates {
409            dir_spec.abandon(p);
410            op.abandon(p);
411            op_n.abandon(p);
412            if expr(p).is_none() {
413                p.err_and_bump("expected asm template");
414            }
415            continue;
416        } else {
417            dir_spec.abandon(p);
418            op.abandon(p);
419            op_n.abandon(p);
420
421            // improves error recovery
422            if p.at(T!['{']) {
423                p.error("expected asm operand");
424                // test_err bad_asm_expr
425                // fn foo() {
426                //     builtin#asm(
427                //         label crashy = { return; }
428                //     );
429                // }
430                expr(p);
431            } else {
432                p.err_and_bump("expected asm operand");
433            }
434
435            if p.at(T!['}']) {
436                break;
437            }
438            continue;
439        };
440        allow_templates = false;
441    }
442    p.expect(T![')']);
443    Some(m.complete(p, ASM_EXPR))
444}
445
446fn parse_options(p: &mut Parser<'_>) {
447    p.expect(T!['(']);
448
449    while !p.eat(T![')']) && !p.at(EOF) {
450        const OPTIONS: &[SyntaxKind] = &[
451            T![pure],
452            T![nomem],
453            T![readonly],
454            T![preserves_flags],
455            T![noreturn],
456            T![nostack],
457            T![may_unwind],
458            T![att_syntax],
459            T![raw],
460        ];
461        let m = p.start();
462        if !OPTIONS.iter().any(|&syntax| p.eat_contextual_kw(syntax)) {
463            p.err_and_bump("expected asm option");
464            m.abandon(p);
465            continue;
466        }
467        m.complete(p, ASM_OPTION);
468
469        // Allow trailing commas
470        if p.eat(T![')']) {
471            break;
472        }
473        p.expect(T![,]);
474    }
475}
476
477fn parse_clobber_abi(p: &mut Parser<'_>) {
478    p.expect(T!['(']);
479
480    while !p.eat(T![')']) && !p.at(EOF) {
481        if !p.expect(T![string]) {
482            break;
483        }
484
485        // Allow trailing commas
486        if p.eat(T![')']) {
487            break;
488        }
489        p.expect(T![,]);
490    }
491}
492
493fn parse_reg(p: &mut Parser<'_>) {
494    p.expect(T!['(']);
495    if p.at_ts(PATH_NAME_REF_KINDS) {
496        let m = p.start();
497        name_ref_mod_path(p);
498        m.complete(p, ASM_REG_SPEC);
499    } else if p.at(T![string]) {
500        let m = p.start();
501        p.bump_any();
502        m.complete(p, ASM_REG_SPEC);
503    } else {
504        p.err_and_bump("expected register name");
505    }
506    p.expect(T![')']);
507}
508
509// test array_expr
510// fn foo() {
511//     [];
512//     [1];
513//     [1, 2,];
514//     [1; 2];
515// }
516fn array_expr(p: &mut Parser<'_>) -> CompletedMarker {
517    assert!(p.at(T!['[']));
518    let m = p.start();
519
520    let mut n_exprs = 0u32;
521    let mut has_semi = false;
522
523    p.bump(T!['[']);
524    while !p.at(EOF) && !p.at(T![']']) {
525        n_exprs += 1;
526
527        // test array_attrs
528        // const A: &[i64] = &[1, #[cfg(test)] 2];
529        if expr(p).is_none() {
530            break;
531        }
532
533        if n_exprs == 1 && p.eat(T![;]) {
534            has_semi = true;
535            continue;
536        }
537
538        if has_semi || !p.at(T![']']) && !p.expect(T![,]) {
539            break;
540        }
541    }
542    p.expect(T![']']);
543
544    m.complete(p, ARRAY_EXPR)
545}
546
547// test lambda_expr
548// fn foo() {
549//     || ();
550//     || -> i32 { 92 };
551//     |x| x;
552//     move |x: i32,| x;
553//     async || {};
554//     move || {};
555//     async move || {};
556//     static || {};
557//     static move || {};
558//     static async || {};
559//     static async move || {};
560//     for<'a> || {};
561//     for<'a> move || {};
562// }
563fn closure_expr(p: &mut Parser<'_>) -> CompletedMarker {
564    assert!(match p.current() {
565        T![const] | T![static] | T![async] | T![move] | T![|] => true,
566        T![for] => p.nth(1) == T![<],
567        _ => false,
568    });
569
570    let m = p.start();
571
572    // test closure_binder
573    // fn main() { for<'a> || (); }
574    if p.at(T![for]) {
575        types::for_binder(p);
576    }
577    // test const_closure
578    // fn main() { let cl = const || _ = 0; }
579    p.eat(T![const]);
580    p.eat(T![static]);
581    p.eat(T![async]);
582    p.eat(T![gen]);
583    p.eat(T![move]);
584
585    if !p.at(T![|]) {
586        p.error("expected `|`");
587        return m.complete(p, CLOSURE_EXPR);
588    }
589    params::param_list_closure(p);
590    if opt_ret_type(p) {
591        // test_err closure_ret_recovery
592        // fn foo() { || -> A> { let x = 1; } }
593        while p.at(T![>]) {
594            // recover from unbalanced return type brackets
595            p.err_and_bump("expected a curly brace");
596        }
597        // test lambda_ret_block
598        // fn main() { || -> i32 { 92 }(); }
599        block_expr(p);
600    } else if p.at_ts(EXPR_FIRST) {
601        // test closure_body_underscore_assignment
602        // fn main() { || _ = 0; }
603        expr(p);
604    } else {
605        p.error("expected expression");
606    }
607    m.complete(p, CLOSURE_EXPR)
608}
609
610// test if_expr
611// fn foo() {
612//     if true {};
613//     if true {} else {};
614//     if true {} else if false {} else {};
615//     if S {};
616//     if { true } { } else { };
617// }
618fn if_expr(p: &mut Parser<'_>) -> CompletedMarker {
619    assert!(p.at(T![if]));
620    let m = p.start();
621    p.bump(T![if]);
622    expr_no_struct(p);
623    block_expr(p);
624    if p.eat(T![else]) {
625        if p.at(T![if]) {
626            if_expr(p);
627        } else {
628            block_expr(p);
629        }
630    }
631    m.complete(p, IF_EXPR)
632}
633
634// test label
635// fn foo() {
636//     'a: loop {}
637//     'b: while true {}
638//     'c: for x in () {}
639// }
640fn label(p: &mut Parser<'_>) {
641    assert!(p.at(LIFETIME_IDENT) && p.nth(1) == T![:]);
642    let m = p.start();
643    lifetime(p);
644    p.bump_any();
645    m.complete(p, LABEL);
646}
647
648// test loop_expr
649// fn foo() {
650//     loop {};
651// }
652fn loop_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
653    assert!(p.at(T![loop]));
654    let m = m.unwrap_or_else(|| p.start());
655    p.bump(T![loop]);
656    block_expr(p);
657    m.complete(p, LOOP_EXPR)
658}
659
660// test while_expr
661// fn foo() {
662//     while true {};
663//     while let Some(x) = it.next() {};
664//     while { true } {};
665// }
666fn while_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
667    assert!(p.at(T![while]));
668    let m = m.unwrap_or_else(|| p.start());
669    p.bump(T![while]);
670    expr_no_struct(p);
671    block_expr(p);
672    m.complete(p, WHILE_EXPR)
673}
674
675// test for_expr
676// fn foo() {
677//     for x in [] {};
678// }
679fn for_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
680    assert!(p.at(T![for]));
681    let m = m.unwrap_or_else(|| p.start());
682    p.bump(T![for]);
683    patterns::pattern(p);
684    p.expect(T![in]);
685    expr_no_struct(p);
686    block_expr(p);
687    m.complete(p, FOR_EXPR)
688}
689
690// test let_expr
691// fn foo() {
692//     if let Some(_) = None && true {}
693//     while 1 == 5 && (let None = None) {}
694// }
695fn let_expr(p: &mut Parser<'_>) -> CompletedMarker {
696    let m = p.start();
697    p.bump(T![let]);
698    patterns::pattern(p);
699    p.expect(T![=]);
700    expr_let(p);
701    m.complete(p, LET_EXPR)
702}
703
704// test match_expr
705// fn foo() {
706//     match () { };
707//     match S {};
708//     match { } { _ => () };
709//     match { S {} } {};
710// }
711fn match_expr(p: &mut Parser<'_>) -> CompletedMarker {
712    assert!(p.at(T![match]));
713    let m = p.start();
714    p.bump(T![match]);
715    expr_no_struct(p);
716    if p.at(T!['{']) {
717        match_arm_list(p);
718    } else {
719        p.error("expected `{`");
720    }
721    m.complete(p, MATCH_EXPR)
722}
723
724// test_err match_arms_recovery
725// fn foo() {
726//     match () {
727//         _ => (),,
728//         _ => ,
729//         _ => (),
730//          => (),
731//         if true => (),
732//         _ => (),
733//         () if => (),
734//     }
735// }
736pub(crate) fn match_arm_list(p: &mut Parser<'_>) {
737    assert!(p.at(T!['{']));
738    let m = p.start();
739    p.eat(T!['{']);
740
741    // test match_arms_inner_attribute
742    // fn foo() {
743    //     match () {
744    //         #![doc("Inner attribute")]
745    //         #![doc("Can be")]
746    //         #![doc("Stacked")]
747    //         _ => (),
748    //     }
749    // }
750    attributes::inner_attrs(p);
751
752    while !p.at(EOF) && !p.at(T!['}']) {
753        if p.at(T!['{']) {
754            error_block(p, "expected match arm");
755            continue;
756        }
757        if p.at(T![,]) {
758            p.err_and_bump("expected pattern");
759            continue;
760        }
761        match_arm(p);
762    }
763    p.expect(T!['}']);
764    m.complete(p, MATCH_ARM_LIST);
765}
766
767// test match_arm
768// fn foo() {
769//     match () {
770//         _ => (),
771//         _ if Test > Test{field: 0} => (),
772//         X | Y if Z => (),
773//         | X | Y if Z => (),
774//         | X => (),
775//     };
776// }
777fn match_arm(p: &mut Parser<'_>) {
778    let m = p.start();
779    // test match_arms_outer_attributes
780    // fn foo() {
781    //     match () {
782    //         #[cfg(feature = "some")]
783    //         _ => (),
784    //         #[cfg(feature = "other")]
785    //         _ => (),
786    //         #[cfg(feature = "many")]
787    //         #[cfg(feature = "attributes")]
788    //         #[cfg(feature = "before")]
789    //         _ => (),
790    //     }
791    // }
792    attributes::outer_attrs(p);
793
794    patterns::pattern_top_r(p, TokenSet::new(&[T![=], T![if]]));
795    if p.at(T![if]) {
796        match_guard(p);
797    }
798    p.expect(T![=>]);
799    if p.eat(T![,]) {
800        p.error("expected expression");
801    } else {
802        let blocklike = match expr_stmt(p, None) {
803            Some((_, blocklike)) => blocklike,
804            None => BlockLike::NotBlock,
805        };
806
807        // test match_arms_commas
808        // fn foo() {
809        //     match () {
810        //         _ => (),
811        //         _ => {}
812        //         _ => ()
813        //     }
814        // }
815        if !p.eat(T![,]) && !blocklike.is_block() && !p.at(T!['}']) {
816            p.error("expected `,`");
817        }
818    }
819    m.complete(p, MATCH_ARM);
820}
821
822// test match_guard
823// fn foo() {
824//     match () {
825//         _ if foo => (),
826//         _ if let foo = bar => (),
827//     }
828// }
829fn match_guard(p: &mut Parser<'_>) -> CompletedMarker {
830    assert!(p.at(T![if]));
831    let m = p.start();
832    p.bump(T![if]);
833    if p.at(T![=]) {
834        p.error("expected expression");
835    } else {
836        expr(p);
837    }
838    m.complete(p, MATCH_GUARD)
839}
840
841// test block
842// fn a() {}
843// fn b() { let _ = 1; }
844// fn c() { 1; 2; }
845// fn d() { 1; 2 }
846pub(crate) fn block_expr(p: &mut Parser<'_>) {
847    if !p.at(T!['{']) {
848        p.error("expected a block");
849        return;
850    }
851    let m = p.start();
852    stmt_list(p);
853    m.complete(p, BLOCK_EXPR);
854}
855
856fn stmt_list(p: &mut Parser<'_>) -> CompletedMarker {
857    assert!(p.at(T!['{']));
858    let m = p.start();
859    p.bump(T!['{']);
860    expr_block_contents(p);
861    p.expect(T!['}']);
862    m.complete(p, STMT_LIST)
863}
864
865// test return_expr
866// fn foo() {
867//     return;
868//     return 92;
869// }
870fn return_expr(p: &mut Parser<'_>) -> CompletedMarker {
871    assert!(p.at(T![return]));
872    let m = p.start();
873    p.bump(T![return]);
874    if p.at_ts(EXPR_FIRST) {
875        expr(p);
876    }
877    m.complete(p, RETURN_EXPR)
878}
879
880// test become_expr
881// fn foo() {
882//     become foo();
883// }
884fn become_expr(p: &mut Parser<'_>) -> CompletedMarker {
885    assert!(p.at(T![become]));
886    let m = p.start();
887    p.bump(T![become]);
888    expr(p);
889    m.complete(p, BECOME_EXPR)
890}
891
892// test yield_expr
893// fn foo() {
894//     yield;
895//     yield 1;
896// }
897fn yield_expr(p: &mut Parser<'_>) -> CompletedMarker {
898    assert!(p.at(T![yield]));
899    let m = p.start();
900    p.bump(T![yield]);
901    if p.at_ts(EXPR_FIRST) {
902        expr(p);
903    }
904    m.complete(p, YIELD_EXPR)
905}
906
907// test yeet_expr
908// fn foo() {
909//     do yeet;
910//     do yeet 1
911// }
912fn yeet_expr(p: &mut Parser<'_>) -> CompletedMarker {
913    assert!(p.at(T![do]));
914    assert!(p.nth_at_contextual_kw(1, T![yeet]));
915    let m = p.start();
916    p.bump(T![do]);
917    p.bump_remap(T![yeet]);
918    if p.at_ts(EXPR_FIRST) {
919        expr(p);
920    }
921    m.complete(p, YEET_EXPR)
922}
923
924// test continue_expr
925// fn foo() {
926//     loop {
927//         continue;
928//         continue 'l;
929//     }
930// }
931fn continue_expr(p: &mut Parser<'_>) -> CompletedMarker {
932    assert!(p.at(T![continue]));
933    let m = p.start();
934    p.bump(T![continue]);
935    if p.at(LIFETIME_IDENT) {
936        lifetime(p);
937    }
938    m.complete(p, CONTINUE_EXPR)
939}
940
941// test break_expr
942// fn foo() {
943//     loop {
944//         break;
945//         break 'l;
946//         break 92;
947//         break 'l 92;
948//     }
949// }
950fn break_expr(p: &mut Parser<'_>, r: Restrictions) -> CompletedMarker {
951    assert!(p.at(T![break]));
952    let m = p.start();
953    p.bump(T![break]);
954    if p.at(LIFETIME_IDENT) {
955        lifetime(p);
956    }
957    // test break_ambiguity
958    // fn foo(){
959    //     if break {}
960    //     while break {}
961    //     for i in break {}
962    //     match break {}
963    // }
964    if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
965        expr(p);
966    }
967    m.complete(p, BREAK_EXPR)
968}
969
970// test try_block_expr
971// fn foo() {
972//     let _ = try {};
973// }
974fn try_block_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
975    assert!(p.at(T![try]));
976    let m = m.unwrap_or_else(|| p.start());
977    p.bump(T![try]);
978    if p.at(T!['{']) {
979        stmt_list(p);
980    } else {
981        p.error("expected a block");
982    }
983    m.complete(p, BLOCK_EXPR)
984}