diff options
Diffstat (limited to 'crates/ra_parser/src/grammar/type_params.rs')
-rw-r--r-- | crates/ra_parser/src/grammar/type_params.rs | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs new file mode 100644 index 000000000..40f998682 --- /dev/null +++ b/crates/ra_parser/src/grammar/type_params.rs | |||
@@ -0,0 +1,175 @@ | |||
1 | use super::*; | ||
2 | |||
3 | pub(super) fn opt_type_param_list(p: &mut Parser) { | ||
4 | if !p.at(L_ANGLE) { | ||
5 | return; | ||
6 | } | ||
7 | type_param_list(p); | ||
8 | } | ||
9 | |||
10 | fn type_param_list(p: &mut Parser) { | ||
11 | assert!(p.at(L_ANGLE)); | ||
12 | let m = p.start(); | ||
13 | p.bump(); | ||
14 | |||
15 | while !p.at(EOF) && !p.at(R_ANGLE) { | ||
16 | let m = p.start(); | ||
17 | |||
18 | // test generic_lifetime_type_attribute | ||
19 | // fn foo<#[derive(Lifetime)] 'a, #[derive(Type)] T>(_: &'a T) { | ||
20 | // } | ||
21 | attributes::outer_attributes(p); | ||
22 | |||
23 | match p.current() { | ||
24 | LIFETIME => lifetime_param(p, m), | ||
25 | IDENT => type_param(p, m), | ||
26 | _ => { | ||
27 | m.abandon(p); | ||
28 | p.err_and_bump("expected type parameter") | ||
29 | } | ||
30 | } | ||
31 | if !p.at(R_ANGLE) && !p.expect(COMMA) { | ||
32 | break; | ||
33 | } | ||
34 | } | ||
35 | p.expect(R_ANGLE); | ||
36 | m.complete(p, TYPE_PARAM_LIST); | ||
37 | } | ||
38 | |||
39 | fn lifetime_param(p: &mut Parser, m: Marker) { | ||
40 | assert!(p.at(LIFETIME)); | ||
41 | p.bump(); | ||
42 | if p.at(COLON) { | ||
43 | lifetime_bounds(p); | ||
44 | } | ||
45 | m.complete(p, LIFETIME_PARAM); | ||
46 | } | ||
47 | |||
48 | fn type_param(p: &mut Parser, m: Marker) { | ||
49 | assert!(p.at(IDENT)); | ||
50 | name(p); | ||
51 | if p.at(COLON) { | ||
52 | bounds(p); | ||
53 | } | ||
54 | // test type_param_default | ||
55 | // struct S<T = i32>; | ||
56 | if p.at(EQ) { | ||
57 | p.bump(); | ||
58 | types::type_(p) | ||
59 | } | ||
60 | m.complete(p, TYPE_PARAM); | ||
61 | } | ||
62 | |||
63 | // test type_param_bounds | ||
64 | // struct S<T: 'a + ?Sized + (Copy)>; | ||
65 | pub(super) fn bounds(p: &mut Parser) { | ||
66 | assert!(p.at(COLON)); | ||
67 | p.bump(); | ||
68 | bounds_without_colon(p); | ||
69 | } | ||
70 | |||
71 | fn lifetime_bounds(p: &mut Parser) { | ||
72 | assert!(p.at(COLON)); | ||
73 | p.bump(); | ||
74 | while p.at(LIFETIME) { | ||
75 | p.bump(); | ||
76 | if !p.eat(PLUS) { | ||
77 | break; | ||
78 | } | ||
79 | } | ||
80 | } | ||
81 | |||
82 | pub(super) fn bounds_without_colon(p: &mut Parser) { | ||
83 | loop { | ||
84 | let has_paren = p.eat(L_PAREN); | ||
85 | p.eat(QUESTION); | ||
86 | match p.current() { | ||
87 | LIFETIME => p.bump(), | ||
88 | FOR_KW => types::for_type(p), | ||
89 | _ if paths::is_path_start(p) => types::path_type(p), | ||
90 | _ => break, | ||
91 | } | ||
92 | if has_paren { | ||
93 | p.expect(R_PAREN); | ||
94 | } | ||
95 | if !p.eat(PLUS) { | ||
96 | break; | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | |||
101 | // test where_clause | ||
102 | // fn foo() | ||
103 | // where | ||
104 | // 'a: 'b + 'c, | ||
105 | // T: Clone + Copy + 'static, | ||
106 | // Iterator::Item: 'a, | ||
107 | // <T as Iterator>::Item: 'a | ||
108 | // {} | ||
109 | pub(super) fn opt_where_clause(p: &mut Parser) { | ||
110 | if !p.at(WHERE_KW) { | ||
111 | return; | ||
112 | } | ||
113 | let m = p.start(); | ||
114 | p.bump(); | ||
115 | |||
116 | while is_where_predicate(p) { | ||
117 | where_predicate(p); | ||
118 | |||
119 | let comma = p.eat(COMMA); | ||
120 | |||
121 | if is_where_clause_end(p) { | ||
122 | break; | ||
123 | } | ||
124 | |||
125 | if !comma { | ||
126 | p.error("expected comma"); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | m.complete(p, WHERE_CLAUSE); | ||
131 | } | ||
132 | |||
133 | fn is_where_predicate(p: &mut Parser) -> bool { | ||
134 | match p.current() { | ||
135 | LIFETIME => true, | ||
136 | IMPL_KW => false, | ||
137 | token => types::TYPE_FIRST.contains(token), | ||
138 | } | ||
139 | } | ||
140 | |||
141 | fn is_where_clause_end(p: &mut Parser) -> bool { | ||
142 | p.current() == L_CURLY || p.current() == SEMI || p.current() == EQ | ||
143 | } | ||
144 | |||
145 | fn where_predicate(p: &mut Parser) { | ||
146 | let m = p.start(); | ||
147 | match p.current() { | ||
148 | LIFETIME => { | ||
149 | p.bump(); | ||
150 | if p.at(COLON) { | ||
151 | lifetime_bounds(p); | ||
152 | } else { | ||
153 | p.error("expected colon"); | ||
154 | } | ||
155 | } | ||
156 | IMPL_KW => { | ||
157 | p.error("expected lifetime or type"); | ||
158 | } | ||
159 | _ => { | ||
160 | // test where_pred_for | ||
161 | // fn test<F>() | ||
162 | // where | ||
163 | // for<'a> F: Fn(&'a str) | ||
164 | // { } | ||
165 | types::type_(p); | ||
166 | |||
167 | if p.at(COLON) { | ||
168 | bounds(p); | ||
169 | } else { | ||
170 | p.error("expected colon"); | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | m.complete(p, WHERE_PRED); | ||
175 | } | ||