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