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