rune/grammar/
grammar.rs

1use crate::ast::{self, Delimiter, Kind};
2use crate::compile::{ErrorKind, Result};
3
4use super::{Checkpoint, Parser};
5
6use Kind::*;
7
8trait ExprCx {
9    fn recover(&self, p: &mut Parser<'_>) -> Result<()>;
10}
11
12/// Simple context which performs no recovery.
13struct ErrorCx;
14
15impl ExprCx for ErrorCx {
16    fn recover(&self, p: &mut Parser<'_>) -> Result<()> {
17        Err(p.expected_at(0, Kind::Expr)?)
18    }
19}
20
21#[derive(Default)]
22struct Modifiers {
23    is_pub: bool,
24    is_const: bool,
25    is_async: bool,
26}
27
28#[derive(Debug, Clone, Copy)]
29enum Brace {
30    Yes,
31    No,
32}
33
34#[derive(Debug, Clone, Copy)]
35enum Binary {
36    Yes,
37    No,
38}
39
40#[derive(Debug, Clone, Copy)]
41enum Range {
42    Yes,
43    No,
44}
45
46macro_rules! __ws {
47    () => {
48        $crate::ast::Kind::Whitespace
49            | $crate::ast::Kind::Comment
50            | $crate::ast::Kind::MultilineComment(..)
51    };
52}
53
54macro_rules! __object_key {
55    () => {
56        K![ident] | K![str]
57    };
58}
59
60pub(crate) use __object_key as object_key;
61pub(crate) use __ws as ws;
62
63macro_rules! lit {
64    () => {
65        K![true] | K![false] | K![number] | K![str] | K![bytestr] | K![char] | K![byte]
66    };
67}
68
69macro_rules! path_component {
70    () => {
71        K![::] | K![ident] | K![super] | K![crate] | K![self] | K![Self]
72    }
73}
74
75pub(super) fn root(p: &mut Parser<'_>) -> Result<()> {
76    p.open(Root)?;
77
78    while !p.is_eof()? {
79        stmt(p)?;
80    }
81
82    p.flush_ws()?;
83    p.close()?;
84    Ok(())
85}
86
87/// Parse comma-separated expressions.
88pub(super) fn exprs(p: &mut Parser<'_>, separator: Kind) -> Result<()> {
89    p.open(Root)?;
90
91    while !p.is_eof()? {
92        expr(p)?;
93        p.bump_while(separator)?;
94    }
95
96    p.flush_ws()?;
97    p.close()?;
98    Ok(())
99}
100
101/// Parse comma-separated expressions.
102pub(super) fn format(p: &mut Parser<'_>) -> Result<()> {
103    p.open(Root)?;
104    expr(p)?;
105
106    while !p.is_eof()? {
107        p.bump()?;
108    }
109
110    p.flush_ws()?;
111    p.close()?;
112    Ok(())
113}
114
115#[tracing::instrument(skip_all)]
116fn stmt(p: &mut Parser<'_>) -> Result<()> {
117    struct StmtCx;
118
119    #[tracing::instrument(skip(p))]
120    fn is_stmt_recovering(p: &mut Parser<'_>) -> Result<bool> {
121        let is = match p.peek()? {
122            Eof => false,
123            K![;] => false,
124            K![let] => false,
125            K![use] => false,
126            K![struct] => false,
127            K![enum] => false,
128            K![fn] => false,
129            K![impl] => false,
130            K![mod] => false,
131            K![ident] => false,
132            K![pub] => false,
133            K![const] => false,
134            K![async] => false,
135            K![#] => !matches!(p.nth(1)?, K!['['] | K![!]),
136            _ => true,
137        };
138
139        Ok(is)
140    }
141
142    impl ExprCx for StmtCx {
143        fn recover(&self, p: &mut Parser<'_>) -> Result<()> {
144            while is_stmt_recovering(p)? {
145                p.bump()?;
146            }
147
148            Ok(())
149        }
150    }
151
152    inner_attributes(p)?;
153
154    let c = p.checkpoint()?;
155    attributes(p)?;
156
157    let inner_c = p.checkpoint()?;
158    let m = modifiers(p)?;
159
160    let cx = StmtCx;
161
162    let kind = match p.peek()? {
163        K![let] => {
164            local(p, &cx)?;
165            Local
166        }
167        K![use] => {
168            item_use(p)?;
169            p.close_at(&inner_c, ItemUse)?;
170            Item
171        }
172        K![struct] => {
173            item_struct(p)?;
174            p.close_at(&inner_c, ItemStruct)?;
175            Item
176        }
177        K![enum] => {
178            item_enum(p)?;
179            p.close_at(&inner_c, ItemEnum)?;
180            Item
181        }
182        K![fn] => {
183            item_fn(p)?;
184            p.close_at(&inner_c, ItemFn)?;
185            Item
186        }
187        K![impl] => {
188            item_impl(p)?;
189            p.close_at(&inner_c, ItemImpl)?;
190            Item
191        }
192        K![mod] => {
193            if item_mod(p)? {
194                p.close_at(&inner_c, ItemMod)?;
195            } else {
196                p.close_at(&inner_c, ItemFileMod)?;
197            }
198
199            Item
200        }
201        K![ident] if m.is_const => {
202            item_const(p)?;
203            p.close_at(&inner_c, ItemConst)?;
204            Item
205        }
206        _ => {
207            labels(p)?;
208
209            if matches!(
210                outer_expr_with(p, Brace::Yes, Range::Yes, Binary::Yes, &cx)?,
211                Error
212            ) {
213                Error
214            } else {
215                Expr
216            }
217        }
218    };
219
220    p.close_at(&c, kind)?;
221    p.bump_while(K![;])?;
222    Ok(())
223}
224
225#[tracing::instrument(skip_all)]
226fn item_const(p: &mut Parser<'_>) -> Result<()> {
227    p.bump()?;
228    p.bump_if(K![=])?;
229    expr(p)?;
230    Ok(())
231}
232
233#[tracing::instrument(skip_all)]
234fn inner_attributes(p: &mut Parser<'_>) -> Result<()> {
235    while matches!((p.peek()?, p.glued(1)?), (K![#], K![!])) {
236        let c = p.checkpoint()?;
237
238        p.bump()?;
239        p.bump_if(K![!])?;
240
241        if p.bump_if(K!['['])? {
242            token_stream(p, brackets)?;
243            p.bump()?;
244        }
245
246        p.close_at(&c, InnerAttribute)?;
247    }
248
249    Ok(())
250}
251
252#[tracing::instrument(skip_all)]
253fn attributes(p: &mut Parser<'_>) -> Result<()> {
254    while matches!((p.peek()?, p.glued(1)?), (K![#], K!['['])) {
255        let c = p.checkpoint()?;
256
257        p.bump()?;
258
259        if p.bump_if(K!['['])? {
260            token_stream(p, brackets)?;
261            p.bump()?;
262        }
263
264        p.close_at(&c, Attribute)?;
265    }
266
267    Ok(())
268}
269
270#[tracing::instrument(skip_all)]
271fn modifiers(p: &mut Parser<'_>) -> Result<Modifiers> {
272    let c = p.checkpoint()?;
273
274    let mut mods = Modifiers::default();
275    let mut has_mods = false;
276
277    loop {
278        match p.peek()? {
279            K![pub] => {
280                mods.is_pub = true;
281                p.bump()?;
282
283                if p.peek()? == K!['('] {
284                    let c = p.checkpoint()?;
285                    p.bump()?;
286
287                    let kind = match p.peek()? {
288                        K![super] => {
289                            p.bump()?;
290                            ModifierSuper
291                        }
292                        K![self] => {
293                            p.bump()?;
294                            ModifierSelf
295                        }
296                        K![crate] => {
297                            p.bump()?;
298                            ModifierCrate
299                        }
300                        K![in] => {
301                            p.bump()?;
302                            path(p)?;
303                            ModifierIn
304                        }
305                        _ => Error,
306                    };
307
308                    p.bump_if(K![')'])?;
309                    p.close_at(&c, kind)?;
310                }
311            }
312            K![const] => {
313                mods.is_const = true;
314                p.bump()?;
315            }
316            K![async] => {
317                mods.is_async = true;
318                p.bump()?;
319            }
320            K![move] => {
321                p.bump()?;
322            }
323            _ => {
324                break;
325            }
326        }
327
328        has_mods = true;
329    }
330
331    if has_mods {
332        p.close_at(&c, Modifiers)?;
333    }
334
335    Ok(mods)
336}
337
338#[tracing::instrument(skip_all)]
339fn local(p: &mut Parser<'_>, cx: &dyn ExprCx) -> Result<()> {
340    p.bump()?;
341    pat(p)?;
342    p.bump_if(K![=])?;
343    expr_with(p, Brace::Yes, Range::Yes, Binary::Yes, cx)?;
344    Ok(())
345}
346
347#[tracing::instrument(skip_all)]
348fn item_struct(p: &mut Parser<'_>) -> Result<()> {
349    p.bump()?;
350
351    if matches!(p.peek()?, K![ident]) {
352        p.bump()?;
353    }
354
355    match p.peek()? {
356        K!['{'] => {
357            struct_body(p)?;
358        }
359        K!['('] => {
360            tuple_body(p)?;
361        }
362        _ => {
363            empty_body(p)?;
364        }
365    }
366
367    Ok(())
368}
369
370#[tracing::instrument(skip_all)]
371fn item_use(p: &mut Parser<'_>) -> Result<()> {
372    p.bump()?;
373
374    loop {
375        match p.peek()? {
376            path_component!() | K![*] => {
377                p.bump()?;
378            }
379            K!['{'] => {
380                let c = p.checkpoint()?;
381                p.bump()?;
382
383                while matches!(p.peek()?, path_component!() | K!['{'] | K![*]) {
384                    let c = p.checkpoint()?;
385                    item_use(p)?;
386                    p.close_at(&c, ItemUsePath)?;
387                    p.bump_while(K![,])?;
388                }
389
390                p.bump_if(K!['}'])?;
391                p.close_at(&c, ItemUseGroup)?;
392            }
393            K![as] => {
394                p.bump()?;
395                p.bump_if_matches(|k| matches!(k, K![ident]))?;
396            }
397            _ => break,
398        }
399    }
400
401    Ok(())
402}
403
404#[tracing::instrument(skip_all)]
405fn item_enum(p: &mut Parser<'_>) -> Result<()> {
406    p.bump()?;
407
408    if matches!(p.peek()?, K![ident]) {
409        p.bump()?;
410    }
411
412    if p.bump_if(K!['{'])? {
413        while matches!(p.peek()?, K![ident]) {
414            let variant = p.checkpoint()?;
415
416            p.bump()?;
417
418            match p.peek()? {
419                K!['{'] => {
420                    struct_body(p)?;
421                }
422                K!['('] => {
423                    tuple_body(p)?;
424                }
425                _ => {
426                    p.empty(EmptyBody)?;
427                }
428            }
429
430            p.close_at(&variant, Variant)?;
431            p.bump_while(K![,])?;
432        }
433
434        p.bump_if(K!['}'])?;
435    }
436
437    Ok(())
438}
439
440#[tracing::instrument(skip_all)]
441fn empty_body(p: &mut Parser<'_>) -> Result<()> {
442    let c = p.checkpoint()?;
443    p.close_at(&c, EmptyBody)?;
444    Ok(())
445}
446
447#[tracing::instrument(skip_all)]
448fn struct_body(p: &mut Parser<'_>) -> Result<()> {
449    let c = p.checkpoint()?;
450
451    p.bump()?;
452
453    while matches!(p.peek()?, K![ident]) {
454        let c = p.checkpoint()?;
455        p.bump()?;
456        p.close_at(&c, Field)?;
457        p.bump_while(K![,])?;
458    }
459
460    p.bump_if(K!['}'])?;
461    p.close_at(&c, StructBody)?;
462    Ok(())
463}
464
465#[tracing::instrument(skip_all)]
466fn tuple_body(p: &mut Parser<'_>) -> Result<()> {
467    let c = p.checkpoint()?;
468
469    p.bump()?;
470
471    while matches!(p.peek()?, K![ident]) {
472        let c = p.checkpoint()?;
473        p.bump()?;
474        p.close_at(&c, Field)?;
475        p.bump_while(K![,])?;
476    }
477
478    p.bump_if(K![')'])?;
479    p.close_at(&c, TupleBody)?;
480    Ok(())
481}
482
483#[tracing::instrument(skip_all)]
484fn item_fn(p: &mut Parser<'_>) -> Result<()> {
485    p.bump()?;
486
487    if matches!(p.peek()?, K![ident]) {
488        p.bump()?;
489    }
490
491    if p.peek()? == K!['('] {
492        let c = p.checkpoint()?;
493        p.bump()?;
494
495        p.bump_while(K![,])?;
496
497        while is_pat(p)? {
498            pat(p)?;
499            p.bump_while(K![,])?;
500        }
501
502        p.bump_if(K![')'])?;
503        p.close_at(&c, FnArgs)?;
504    }
505
506    if p.peek()? == K!['{'] {
507        block(p)?;
508    }
509
510    Ok(())
511}
512
513#[tracing::instrument(skip_all)]
514fn item_impl(p: &mut Parser<'_>) -> Result<()> {
515    p.bump()?;
516
517    if matches!(p.peek()?, path_component!()) {
518        path(p)?;
519    }
520
521    block(p)?;
522    Ok(())
523}
524
525#[tracing::instrument(skip_all)]
526fn item_mod(p: &mut Parser<'_>) -> Result<bool> {
527    p.bump()?;
528
529    if matches!(p.peek()?, K![ident]) {
530        p.bump()?;
531    }
532
533    if matches!(p.peek()?, K!['{']) {
534        block(p)?;
535        Ok(true)
536    } else {
537        Ok(false)
538    }
539}
540
541#[tracing::instrument(skip_all)]
542fn is_pat(p: &mut Parser<'_>) -> Result<bool> {
543    Ok(match p.peek()? {
544        path_component!() => true,
545        lit!() => true,
546        K![_] => true,
547        K!['('] => true,
548        K!['['] => true,
549        K![-] => matches!(p.glued(1)?, K![number]),
550        K![#] => matches!(p.glued(1)?, K!['{']),
551        _ => false,
552    })
553}
554
555#[tracing::instrument(skip_all)]
556fn pat(p: &mut Parser<'_>) -> Result<()> {
557    let c = p.checkpoint()?;
558    attributes(p)?;
559
560    match p.peek()? {
561        lit!() => {
562            let c = p.checkpoint()?;
563            p.bump()?;
564            p.close_at(&c, Lit)?;
565        }
566        K![-] => {
567            let c = p.checkpoint()?;
568            p.bump()?;
569
570            if matches!(p.peek()?, K![number]) {
571                p.bump()?;
572            }
573
574            p.close_at(&c, Lit)?;
575        }
576        K![_] => {
577            let c = p.checkpoint()?;
578            p.bump()?;
579            p.close_at(&c, PatIgnore)?;
580        }
581        path_component!() => {
582            let c = p.checkpoint()?;
583            path(p)?;
584
585            match p.peek()? {
586                K!['{'] => {
587                    pat_object(p)?;
588                    p.close_at(&c, PatObject)?;
589                }
590                K!['('] => {
591                    pat_parens(p, K![')'])?;
592                    p.close_at(&c, PatTuple)?;
593                }
594                _ => {}
595            }
596        }
597        K!['['] => {
598            let c = p.checkpoint()?;
599            pat_parens(p, K![']'])?;
600            p.close_at(&c, PatArray)?;
601        }
602        K!['('] => {
603            let c = p.checkpoint()?;
604            pat_parens(p, K![')'])?;
605            p.close_at(&c, PatTuple)?;
606        }
607        K![#] if matches!(p.glued(1)?, K!['{']) => {
608            let c = p.checkpoint()?;
609            p.bump()?;
610            p.close_at(&c, AnonymousObjectKey)?;
611            pat_object(p)?;
612            p.close_at(&c, PatObject)?;
613        }
614        _ => {
615            let c = p.checkpoint()?;
616            p.close_at(&c, Error)?;
617        }
618    }
619
620    p.close_at(&c, Pat)?;
621    Ok(())
622}
623
624fn is_expr(p: &mut Parser<'_>) -> Result<bool> {
625    is_expr_with(p, Brace::Yes, Range::Yes)
626}
627
628#[tracing::instrument(skip(p))]
629fn is_expr_with(p: &mut Parser<'_>, brace: Brace, range: Range) -> Result<bool> {
630    Ok(match p.peek()? {
631        path_component!() => true,
632        K![async] => true,
633        K![break] => true,
634        K![continue] => true,
635        K![for] => true,
636        K![if] => true,
637        K![let] => true,
638        K![loop] => true,
639        K![match] => true,
640        K![return] => true,
641        K![select] => true,
642        K![while] => true,
643        lit!() => true,
644        K![||] | K![|] => true,
645        K![#] => true,
646        K![-] => true,
647        K![!] => true,
648        K![&] => true,
649        K![*] => true,
650        K!['label] => matches!(p.glued(1)?, K![:]),
651        Kind::Open(Delimiter::Empty) => true,
652        K!['('] => true,
653        K!['['] => true,
654        K!['{'] => matches!(brace, Brace::Yes),
655        K![..] => matches!(range, Range::Yes),
656        K![..=] => matches!(range, Range::Yes),
657        TemplateString => true,
658        _ => false,
659    })
660}
661
662#[tracing::instrument(skip_all)]
663fn expr(p: &mut Parser<'_>) -> Result<()> {
664    let c = p.checkpoint()?;
665    attributes(p)?;
666    modifiers(p)?;
667    labels(p)?;
668    let cx = ErrorCx;
669    outer_expr_with(p, Brace::Yes, Range::Yes, Binary::Yes, &cx)?;
670    p.close_at(&c, Expr)?;
671    Ok(())
672}
673
674#[tracing::instrument(skip_all)]
675fn expr_with(
676    p: &mut Parser<'_>,
677    brace: Brace,
678    range: Range,
679    binary: Binary,
680    cx: &dyn ExprCx,
681) -> Result<()> {
682    let c = p.checkpoint()?;
683    attributes(p)?;
684    modifiers(p)?;
685    labels(p)?;
686    outer_expr_with(p, brace, range, binary, cx)?;
687    p.close_at(&c, Expr)?;
688    Ok(())
689}
690
691fn is_range(kind: Kind) -> bool {
692    match kind {
693        ExprRangeTo => true,
694        ExprRangeToInclusive => true,
695        ExprRangeFull => true,
696        ExprRange => true,
697        ExprRangeInclusive => true,
698        ExprRangeFrom => true,
699        _ => false,
700    }
701}
702
703fn outer_expr_with(
704    p: &mut Parser<'_>,
705    brace: Brace,
706    range: Range,
707    binary: Binary,
708    cx: &dyn ExprCx,
709) -> Result<Kind> {
710    let c = p.checkpoint()?;
711    let mut kind = expr_primary(p, brace, range, cx)?;
712
713    if is_range(kind) {
714        return Ok(kind);
715    }
716
717    kind = expr_chain(p, &c, kind)?;
718
719    if p.peek()? == K![=] {
720        p.close_at(&c, Expr)?;
721        p.bump()?;
722        expr_with(p, brace, Range::Yes, Binary::Yes, cx)?;
723        p.close_at(&c, ExprAssign)?;
724        return Ok(ExprAssign);
725    }
726
727    if matches!(binary, Binary::Yes) {
728        let slice = p.array::<2>()?;
729        let lookahead = ast::BinOp::from_slice(&slice);
730
731        kind = if expr_binary(p, lookahead, 0, brace, cx)? {
732            p.close_at(&c, ExprBinary)?;
733            ExprBinary
734        } else {
735            kind
736        };
737    }
738
739    if matches!(range, Range::Yes) {
740        kind = expr_range(p, &c, kind, brace)?;
741    }
742
743    Ok(kind)
744}
745
746fn labels(p: &mut Parser<'_>) -> Result<()> {
747    while matches!(p.peek()?, K!['label]) {
748        p.bump()?;
749        p.bump_while(K![:])?;
750    }
751
752    Ok(())
753}
754
755#[tracing::instrument(skip_all)]
756fn expr_primary(p: &mut Parser<'_>, brace: Brace, range: Range, cx: &dyn ExprCx) -> Result<Kind> {
757    let c = p.checkpoint()?;
758
759    let kind = match p.peek()? {
760        lit!() => {
761            p.bump()?;
762            Lit
763        }
764        path_component!() => {
765            path(p)?;
766
767            match p.peek()? {
768                K!['{'] if matches!(brace, Brace::Yes) => {
769                    expr_object(p)?;
770                    ExprObject
771                }
772                K![!] if matches!(p.glued(1)?, K!['(']) => {
773                    p.bump()?;
774                    p.bump()?;
775                    token_stream(p, parens)?;
776                    p.bump()?;
777                    ExprMacroCall
778                }
779                K![!] if matches!(p.glued(1)?, K!['{']) => {
780                    p.bump()?;
781                    p.bump()?;
782                    token_stream(p, braces)?;
783                    p.bump()?;
784                    ExprMacroCall
785                }
786                _ => return Ok(Path),
787            }
788        }
789        Kind::Open(Delimiter::Empty) => empty_group(p)?,
790        K!['('] => expr_tuple_or_group(p)?,
791        K!['['] => {
792            parenthesized(p, is_expr, expr, K![']'])?;
793            ExprArray
794        }
795        K!['{'] => {
796            block_with(p)?;
797            Block
798        }
799        TemplateString => {
800            p.bump()?;
801            TemplateString
802        }
803        K![||] => {
804            p.push(ClosureArguments)?;
805            expr_with(p, brace, range, Binary::Yes, cx)?;
806            ExprClosure
807        }
808        K![|] => {
809            let args = p.checkpoint()?;
810            parenthesized(p, is_pat, pat, K![|])?;
811            p.close_at(&args, ClosureArguments)?;
812
813            expr_with(p, brace, range, Binary::Yes, cx)?;
814            ExprClosure
815        }
816        K![-] if matches!(p.glued(1)?, K![number]) => {
817            p.bump()?;
818            p.bump()?;
819            Lit
820        }
821        K![!] | K![-] | K![&] | K![*] => {
822            p.bump()?;
823            outer_expr_with(p, brace, range, Binary::No, cx)?;
824            ExprUnary
825        }
826        K![if] => {
827            expr_if(p)?;
828            ExprIf
829        }
830        K![while] => {
831            expr_while(p)?;
832            ExprWhile
833        }
834        K![loop] => {
835            expr_loop(p)?;
836            ExprLoop
837        }
838        K![break] => {
839            p.bump()?;
840
841            labels(p)?;
842
843            if is_expr_with(p, brace, range)? {
844                let cx = ErrorCx;
845                expr_with(p, brace, range, Binary::Yes, &cx)?;
846            }
847
848            ExprBreak
849        }
850        K![continue] => {
851            p.bump()?;
852            labels(p)?;
853            ExprContinue
854        }
855        K![return] => {
856            p.bump()?;
857
858            if is_expr_with(p, brace, range)? {
859                let cx = ErrorCx;
860                expr_with(p, brace, range, Binary::Yes, &cx)?;
861            }
862
863            ExprReturn
864        }
865        K![yield] => {
866            p.bump()?;
867
868            if is_expr_with(p, brace, range)? {
869                let cx = ErrorCx;
870                expr_with(p, brace, range, Binary::Yes, &cx)?;
871            }
872
873            ExprYield
874        }
875        K![for] => {
876            expr_for(p)?;
877            ExprFor
878        }
879        K![select] => {
880            expr_select(p)?;
881            ExprSelect
882        }
883        K![match] => {
884            expr_match(p)?;
885            ExprMatch
886        }
887        K![..] if matches!(range, Range::Yes) => {
888            p.bump()?;
889
890            if is_expr_with(p, brace, Range::No)? {
891                let cx = ErrorCx;
892                outer_expr_with(p, brace, Range::No, Binary::Yes, &cx)?;
893                ExprRangeTo
894            } else {
895                ExprRangeFull
896            }
897        }
898        K![..=] if matches!(range, Range::Yes) => {
899            p.bump()?;
900            let cx = ErrorCx;
901            outer_expr_with(p, brace, Range::No, Binary::Yes, &cx)?;
902            ExprRangeToInclusive
903        }
904        K![#] if matches!(p.glued(1)?, K!['{']) => {
905            let key = p.checkpoint()?;
906            p.bump()?;
907            p.close_at(&key, AnonymousObjectKey)?;
908            expr_object(p)?;
909            ExprObject
910        }
911        _ => {
912            cx.recover(p)?;
913            Error
914        }
915    };
916
917    p.close_at(&c, kind)?;
918    Ok(kind)
919}
920
921fn kind_is_callable(kind: Kind) -> bool {
922    match kind {
923        ExprWhile => false,
924        ExprLoop => true,
925        ExprFor => false,
926        ExprIf => true,
927        ExprMatch => true,
928        ExprSelect => true,
929        _ => true,
930    }
931}
932
933#[tracing::instrument(skip_all)]
934fn expr_chain(p: &mut Parser<'_>, c: &Checkpoint, mut kind: Kind) -> Result<Kind> {
935    let mut before = p.checkpoint()?;
936    let mut has_chain = false;
937
938    while !p.is_eof()? {
939        let is_callable = kind_is_callable(kind);
940
941        let k = match p.peek()? {
942            K!['['] if is_callable => {
943                p.bump()?;
944                expr(p)?;
945                p.bump_if(K![']'])?;
946                ExprIndex
947            }
948            // Chained function call.
949            K!['('] if is_callable => {
950                parenthesized(p, is_expr, expr, K![')'])?;
951                ExprCall
952            }
953            K![?] => {
954                p.bump()?;
955                ExprTry
956            }
957            K![.] => {
958                p.bump()?;
959
960                match p.peek()? {
961                    // <expr>.await
962                    K![await] => {
963                        p.bump()?;
964                        ExprAwait
965                    }
966                    // <expr>.field
967                    path_component!() => {
968                        path(p)?;
969                        ExprField
970                    }
971                    // <expr>.<number>
972                    K![number] => {
973                        p.bump()?;
974                        ExprField
975                    }
976                    _ => Error,
977                }
978            }
979            _ => {
980                break;
981            }
982        };
983
984        p.close_at(&before, k)?;
985        kind = k;
986        before = p.checkpoint()?;
987        has_chain = true;
988    }
989
990    if has_chain {
991        p.close_at(c, ExprChain)?;
992    }
993
994    Ok(kind)
995}
996
997#[tracing::instrument(skip_all)]
998fn empty_group(p: &mut Parser<'_>) -> Result<Kind> {
999    p.bump()?;
1000    expr(p)?;
1001    p.bump_if(Kind::Close(Delimiter::Empty))?;
1002    Ok(ExprEmptyGroup)
1003}
1004
1005#[tracing::instrument(skip_all)]
1006fn expr_tuple_or_group(p: &mut Parser<'_>) -> Result<Kind> {
1007    p.bump()?;
1008
1009    let mut is_tuple = false;
1010
1011    while is_expr(p)? {
1012        expr(p)?;
1013
1014        if p.bump_while(K![,])? {
1015            is_tuple = true;
1016        }
1017    }
1018
1019    p.bump_if(K![')'])?;
1020    let kind = if is_tuple { ExprTuple } else { ExprGroup };
1021    Ok(kind)
1022}
1023
1024#[tracing::instrument(skip_all)]
1025fn expr_object(p: &mut Parser<'_>) -> Result<()> {
1026    p.bump()?;
1027
1028    while matches!(p.peek()?, object_key!()) {
1029        p.bump()?;
1030
1031        if p.bump_if(K![:])? {
1032            expr(p)?;
1033        }
1034
1035        p.bump_while(K![,])?;
1036    }
1037
1038    p.bump_if(K!['}'])?;
1039    Ok(())
1040}
1041
1042#[tracing::instrument(skip_all)]
1043fn pat_object(p: &mut Parser<'_>) -> Result<()> {
1044    p.bump()?;
1045
1046    loop {
1047        match p.peek()? {
1048            K![..] => {
1049                p.bump()?;
1050            }
1051            object_key!() => {
1052                p.bump()?;
1053
1054                if p.bump_if(K![:])? {
1055                    pat(p)?;
1056                }
1057
1058                p.bump_while(K![,])?;
1059            }
1060            _ => {
1061                break;
1062            }
1063        }
1064    }
1065
1066    p.bump_if(K!['}'])?;
1067    Ok(())
1068}
1069
1070#[tracing::instrument(skip_all)]
1071fn expr_if(p: &mut Parser<'_>) -> Result<()> {
1072    p.bump()?;
1073    condition(p)?;
1074    block(p)?;
1075
1076    while p.peek()? == K![else] {
1077        let c = p.checkpoint()?;
1078        p.bump()?;
1079
1080        let else_if = if p.bump_if(K![if])? {
1081            condition(p)?;
1082            true
1083        } else {
1084            false
1085        };
1086
1087        block(p)?;
1088
1089        if else_if {
1090            p.close_at(&c, ExprElseIf)?;
1091        } else {
1092            p.close_at(&c, ExprElse)?;
1093        }
1094    }
1095
1096    Ok(())
1097}
1098
1099#[tracing::instrument(skip_all)]
1100fn expr_while(p: &mut Parser<'_>) -> Result<()> {
1101    p.bump()?;
1102    condition(p)?;
1103    block(p)?;
1104    Ok(())
1105}
1106
1107#[tracing::instrument(skip_all)]
1108fn expr_loop(p: &mut Parser<'_>) -> Result<()> {
1109    p.bump()?;
1110    block(p)?;
1111    Ok(())
1112}
1113
1114#[tracing::instrument(skip_all)]
1115fn expr_for(p: &mut Parser<'_>) -> Result<()> {
1116    p.bump()?;
1117    pat(p)?;
1118
1119    if p.bump_if(K![in])? {
1120        let cx = ErrorCx;
1121        expr_with(p, Brace::No, Range::Yes, Binary::Yes, &cx)?;
1122    }
1123
1124    block(p)?;
1125    Ok(())
1126}
1127
1128#[tracing::instrument(skip_all)]
1129fn expr_match(p: &mut Parser<'_>) -> Result<()> {
1130    p.bump()?;
1131
1132    let cx = ErrorCx;
1133    expr_with(p, Brace::No, Range::Yes, Binary::Yes, &cx)?;
1134
1135    if matches!(p.peek()?, K!['{']) {
1136        p.bump()?;
1137
1138        while is_pat(p)? {
1139            let c = p.checkpoint()?;
1140            pat(p)?;
1141
1142            if p.bump_if(K![if])? {
1143                expr(p)?;
1144            }
1145
1146            if p.bump_if(K![=>])? {
1147                expr(p)?;
1148            }
1149
1150            p.close_at(&c, ExprMatchArm)?;
1151            p.bump_while(K![,])?;
1152        }
1153
1154        p.bump_if(K!['}'])?;
1155    }
1156
1157    Ok(())
1158}
1159
1160#[tracing::instrument(skip_all)]
1161fn expr_select(p: &mut Parser<'_>) -> Result<()> {
1162    p.bump()?;
1163
1164    if matches!(p.peek()?, K!['{']) {
1165        p.bump()?;
1166
1167        while is_pat(p)? || p.peek()? == K![default] {
1168            let c = p.checkpoint()?;
1169
1170            match p.peek()? {
1171                K![default] => {
1172                    p.bump()?;
1173                }
1174                _ => {
1175                    pat(p)?;
1176
1177                    if p.bump_if(K![=])? {
1178                        expr(p)?;
1179                    }
1180                }
1181            }
1182
1183            if p.bump_if(K![=>])? {
1184                expr(p)?;
1185            }
1186
1187            p.close_at(&c, ExprSelectArm)?;
1188            p.bump_while(K![,])?;
1189        }
1190
1191        p.bump_if(K!['}'])?;
1192    }
1193
1194    Ok(())
1195}
1196
1197#[tracing::instrument(skip_all)]
1198fn condition(p: &mut Parser<'_>) -> Result<()> {
1199    if p.peek()? == K![let] {
1200        let c = p.checkpoint()?;
1201        p.bump()?;
1202        pat(p)?;
1203
1204        if p.peek()? == K![=] {
1205            p.bump()?;
1206            let cx = ErrorCx;
1207            expr_with(p, Brace::No, Range::Yes, Binary::Yes, &cx)?;
1208        }
1209
1210        p.close_at(&c, Condition)?;
1211    } else {
1212        let cx = ErrorCx;
1213        expr_with(p, Brace::No, Range::Yes, Binary::Yes, &cx)?;
1214    }
1215
1216    Ok(())
1217}
1218
1219#[tracing::instrument(skip_all)]
1220fn path(p: &mut Parser<'_>) -> Result<()> {
1221    let c = p.checkpoint()?;
1222
1223    while matches!(p.peek()?, path_component!()) {
1224        // Parse a generic path if we are in a context supporting binary
1225        // expressions, or if we just parsed the prefix `::` of the turbofish
1226        // syntax.
1227        let has_generics = matches!(p.peek()?, K![::]);
1228        p.bump()?;
1229
1230        // We can't parse generics in binary expressions, since they would be
1231        // ambiguous with expressions such as `self::FOO< 10`.
1232        while has_generics && matches!(p.peek()?, K![<]) {
1233            let c = p.checkpoint()?;
1234            p.bump()?;
1235
1236            while matches!(p.peek()?, path_component!()) {
1237                // Inner paths are unambiguous.
1238                path(p)?;
1239                p.bump_while(K![,])?;
1240            }
1241
1242            p.bump_if(K![>])?;
1243            p.close_at(&c, PathGenerics)?;
1244        }
1245    }
1246
1247    p.close_at(&c, Path)?;
1248    Ok(())
1249}
1250
1251#[tracing::instrument(skip_all)]
1252fn expr_binary(
1253    p: &mut Parser<'_>,
1254    mut lookahead: Option<ast::BinOp>,
1255    min_precedence: usize,
1256    brace: Brace,
1257    cx: &dyn ExprCx,
1258) -> Result<bool> {
1259    let mut has_any = false;
1260
1261    while let Some(op) = lookahead.take() {
1262        let precedence = op.precedence();
1263
1264        if precedence < min_precedence {
1265            break;
1266        }
1267
1268        let op_c = p.checkpoint()?;
1269        op.advance(p)?;
1270        p.close_at(&op_c, ExprOperator)?;
1271
1272        let c = p.checkpoint()?;
1273        outer_expr_with(p, brace, Range::No, Binary::No, cx)?;
1274
1275        has_any = true;
1276
1277        let slice = p.array::<2>()?;
1278        lookahead = ast::BinOp::from_slice(&slice);
1279
1280        while let Some(next) = lookahead {
1281            match (precedence, next.precedence()) {
1282                (lh, rh) if lh < rh => {
1283                    // Higher precedence elements require us to recurse.
1284                    if expr_binary(p, Some(next), lh + 1, brace, cx)? {
1285                        p.close_at(&c, ExprBinary)?;
1286                    }
1287
1288                    let slice = p.array::<2>()?;
1289                    lookahead = ast::BinOp::from_slice(&slice);
1290                    continue;
1291                }
1292                (lh, rh) if lh == rh => {
1293                    if !next.is_assoc() {
1294                        return Err(p.error(c.span(), ErrorKind::PrecedenceGroupRequired)?);
1295                    }
1296                }
1297                _ => {}
1298            };
1299
1300            break;
1301        }
1302    }
1303
1304    Ok(has_any)
1305}
1306
1307#[tracing::instrument(skip_all)]
1308fn expr_range(p: &mut Parser<'_>, c: &Checkpoint, kind: Kind, brace: Brace) -> Result<Kind> {
1309    let kind = match p.peek()? {
1310        K![..] => {
1311            p.bump()?;
1312
1313            if is_expr_with(p, brace, Range::No)? {
1314                let cx = ErrorCx;
1315                outer_expr_with(p, brace, Range::No, Binary::Yes, &cx)?;
1316                ExprRange
1317            } else {
1318                ExprRangeFrom
1319            }
1320        }
1321        K![..=] => {
1322            p.bump()?;
1323
1324            if is_expr_with(p, brace, Range::No)? {
1325                let cx = ErrorCx;
1326                outer_expr_with(p, brace, Range::No, Binary::Yes, &cx)?;
1327                ExprRangeInclusive
1328            } else {
1329                Error
1330            }
1331        }
1332        _ => {
1333            return Ok(kind);
1334        }
1335    };
1336
1337    p.close_at(c, kind)?;
1338    Ok(kind)
1339}
1340#[tracing::instrument(skip_all)]
1341fn block(p: &mut Parser<'_>) -> Result<()> {
1342    let c = p.checkpoint()?;
1343    block_with(p)?;
1344    p.close_at(&c, Block)?;
1345    Ok(())
1346}
1347
1348#[tracing::instrument(skip_all)]
1349fn block_with(p: &mut Parser<'_>) -> Result<()> {
1350    if p.bump_if(K!['{'])? {
1351        let c = p.checkpoint()?;
1352
1353        while !matches!(p.peek()?, K!['}'] | Eof) {
1354            stmt(p)?;
1355        }
1356
1357        p.close_at(&c, BlockBody)?;
1358    }
1359
1360    p.bump_if(K!['}'])?;
1361    Ok(())
1362}
1363
1364#[tracing::instrument(skip(p))]
1365fn pat_parens(p: &mut Parser, end: Kind) -> Result<()> {
1366    p.bump()?;
1367
1368    while is_pat(p)? || p.peek()? == K![..] {
1369        match p.peek()? {
1370            K![..] => {
1371                p.bump()?;
1372            }
1373            _ => {
1374                pat(p)?;
1375            }
1376        }
1377
1378        p.bump_while(K![,])?;
1379    }
1380
1381    p.bump_if(end)?;
1382    Ok(())
1383}
1384
1385#[tracing::instrument(skip(p, is, parser))]
1386fn parenthesized(
1387    p: &mut Parser,
1388    is: fn(&mut Parser<'_>) -> Result<bool>,
1389    parser: fn(&mut Parser<'_>) -> Result<()>,
1390    end: Kind,
1391) -> Result<()> {
1392    p.bump()?;
1393
1394    while is(p)? {
1395        parser(p)?;
1396        p.bump_while(K![,])?;
1397    }
1398
1399    p.bump_if(end)?;
1400    Ok(())
1401}
1402
1403fn brackets(kind: Kind) -> i32 {
1404    match kind {
1405        K!['['] => 1,
1406        K![']'] => -1,
1407        _ => 0,
1408    }
1409}
1410
1411fn parens(kind: Kind) -> i32 {
1412    match kind {
1413        K!['('] => 1,
1414        K![')'] => -1,
1415        _ => 0,
1416    }
1417}
1418
1419fn braces(kind: Kind) -> i32 {
1420    match kind {
1421        K!['{'] => 1,
1422        K!['}'] => -1,
1423        _ => 0,
1424    }
1425}
1426
1427/// Consumes a token stream out of balanced brackets.
1428#[tracing::instrument(skip_all)]
1429fn token_stream(p: &mut Parser<'_>, matcher: fn(Kind) -> i32) -> Result<()> {
1430    let c = p.checkpoint()?;
1431
1432    let mut level = 1u32;
1433
1434    while level > 0 {
1435        let m = matcher(p.peek()?);
1436
1437        level = level.wrapping_add_signed(m);
1438
1439        if level == 0 {
1440            break;
1441        }
1442
1443        p.bump()?;
1444    }
1445
1446    p.close_at(&c, TokenStream)?;
1447    Ok(())
1448}