]> git.lizzy.rs Git - rust.git/blob - crates/parser/src/grammar/paths.rs
05a52c984a37fee2d34746085dca54c3e7e43c29
[rust.git] / crates / parser / src / grammar / paths.rs
1 use super::*;
2
3 pub(super) const PATH_FIRST: TokenSet =
4     TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![:], T![<]]);
5
6 pub(super) fn is_path_start(p: &Parser) -> bool {
7     is_use_path_start(p) || p.at(T![<])
8 }
9
10 pub(super) fn is_use_path_start(p: &Parser) -> bool {
11     match p.current() {
12         IDENT | T![self] | T![super] | T![crate] => true,
13         T![:] if p.at(T![::]) => true,
14         _ => false,
15     }
16 }
17
18 pub(super) fn use_path(p: &mut Parser) {
19     path(p, Mode::Use)
20 }
21
22 pub(crate) fn type_path(p: &mut Parser) {
23     path(p, Mode::Type)
24 }
25
26 pub(super) fn expr_path(p: &mut Parser) {
27     path(p, Mode::Expr)
28 }
29
30 pub(crate) fn type_path_for_qualifier(p: &mut Parser, qual: CompletedMarker) -> CompletedMarker {
31     path_for_qualifier(p, Mode::Type, qual)
32 }
33
34 #[derive(Clone, Copy, Eq, PartialEq)]
35 enum Mode {
36     Use,
37     Type,
38     Expr,
39 }
40
41 fn path(p: &mut Parser, mode: Mode) {
42     let path = p.start();
43     path_segment(p, mode, true);
44     let qual = path.complete(p, PATH);
45     path_for_qualifier(p, mode, qual);
46 }
47
48 fn path_for_qualifier(p: &mut Parser, mode: Mode, mut qual: CompletedMarker) -> CompletedMarker {
49     loop {
50         let use_tree = matches!(p.nth(2), T![*] | T!['{']);
51         if p.at(T![::]) && !use_tree {
52             let path = qual.precede(p);
53             p.bump(T![::]);
54             path_segment(p, mode, false);
55             let path = path.complete(p, PATH);
56             qual = path;
57         } else {
58             return qual;
59         }
60     }
61 }
62
63 fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
64     let m = p.start();
65     // test qual_paths
66     // type X = <A as B>::Output;
67     // fn foo() { <usize as Default>::default(); }
68     if first && p.eat(T![<]) {
69         types::type_(p);
70         if p.eat(T![as]) {
71             if is_use_path_start(p) {
72                 types::path_type(p);
73             } else {
74                 p.error("expected a trait");
75             }
76         }
77         p.expect(T![>]);
78     } else {
79         let mut empty = true;
80         if first {
81             p.eat(T![::]);
82             empty = false;
83         }
84         match p.current() {
85             IDENT => {
86                 name_ref(p);
87                 opt_path_type_args(p, mode);
88             }
89             // test crate_path
90             // use crate::foo;
91             T![self] | T![super] | T![crate] => {
92                 let m = p.start();
93                 p.bump_any();
94                 m.complete(p, NAME_REF);
95             }
96             _ => {
97                 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
98                 if empty {
99                     // test_err empty_segment
100                     // use crate::;
101                     m.abandon(p);
102                     return;
103                 }
104             }
105         };
106     }
107     m.complete(p, PATH_SEGMENT);
108 }
109
110 fn opt_path_type_args(p: &mut Parser, mode: Mode) {
111     match mode {
112         Mode::Use => {}
113         Mode::Type => {
114             // test path_fn_trait_args
115             // type F = Box<Fn(i32) -> ()>;
116             if p.at(T!['(']) {
117                 params::param_list_fn_trait(p);
118                 opt_ret_type(p);
119             } else {
120                 generic_args::opt_generic_arg_list(p, false)
121             }
122         }
123         Mode::Expr => generic_args::opt_generic_arg_list(p, true),
124     }
125 }