]>
Commit | Line | Data |
---|---|---|
83c7162d XL |
1 | // Copyright 2018 Syn Developers |
2 | // | |
3 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
4 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
5 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
6 | // option. This file may not be copied, modified, or distributed | |
7 | // except according to those terms. | |
8 | ||
9 | use super::*; | |
10 | use punctuated::{Iter, IterMut, Punctuated}; | |
11 | ||
12 | ast_struct! { | |
13 | /// Lifetimes and type parameters attached to a declaration of a function, | |
14 | /// enum, trait, etc. | |
15 | /// | |
16 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
17 | /// feature.* | |
18 | #[derive(Default)] | |
19 | pub struct Generics { | |
20 | pub lt_token: Option<Token![<]>, | |
21 | pub params: Punctuated<GenericParam, Token![,]>, | |
22 | pub gt_token: Option<Token![>]>, | |
23 | pub where_clause: Option<WhereClause>, | |
24 | } | |
25 | } | |
26 | ||
27 | ast_enum_of_structs! { | |
28 | /// A generic type parameter, lifetime, or const generic: `T: Into<String>`, | |
29 | /// `'a: 'b`, `const LEN: usize`. | |
30 | /// | |
31 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
32 | /// feature.* | |
33 | /// | |
34 | /// # Syntax tree enum | |
35 | /// | |
36 | /// This type is a [syntax tree enum]. | |
37 | /// | |
38 | /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums | |
39 | pub enum GenericParam { | |
40 | /// A generic type parameter: `T: Into<String>`. | |
41 | /// | |
42 | /// *This type is available if Syn is built with the `"derive"` or | |
43 | /// `"full"` feature.* | |
44 | pub Type(TypeParam { | |
45 | pub attrs: Vec<Attribute>, | |
46 | pub ident: Ident, | |
47 | pub colon_token: Option<Token![:]>, | |
48 | pub bounds: Punctuated<TypeParamBound, Token![+]>, | |
49 | pub eq_token: Option<Token![=]>, | |
50 | pub default: Option<Type>, | |
51 | }), | |
52 | ||
53 | /// A lifetime definition: `'a: 'b + 'c + 'd`. | |
54 | /// | |
55 | /// *This type is available if Syn is built with the `"derive"` or | |
56 | /// `"full"` feature.* | |
57 | pub Lifetime(LifetimeDef { | |
58 | pub attrs: Vec<Attribute>, | |
59 | pub lifetime: Lifetime, | |
60 | pub colon_token: Option<Token![:]>, | |
61 | pub bounds: Punctuated<Lifetime, Token![+]>, | |
62 | }), | |
63 | ||
64 | /// A const generic parameter: `const LENGTH: usize`. | |
65 | /// | |
66 | /// *This type is available if Syn is built with the `"derive"` or | |
67 | /// `"full"` feature.* | |
68 | pub Const(ConstParam { | |
69 | pub attrs: Vec<Attribute>, | |
70 | pub const_token: Token![const], | |
71 | pub ident: Ident, | |
72 | pub colon_token: Token![:], | |
73 | pub ty: Type, | |
74 | pub eq_token: Option<Token![=]>, | |
75 | pub default: Option<Expr>, | |
76 | }), | |
77 | } | |
78 | } | |
79 | ||
80 | impl Generics { | |
81 | /// Returns an | |
82 | /// <code | |
83 | /// style="padding-right:0;">Iterator<Item = &</code><a | |
84 | /// href="struct.TypeParam.html"><code | |
85 | /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code | |
86 | /// style="padding-left:0;">></code> | |
87 | /// over the type parameters in `self.params`. | |
88 | pub fn type_params(&self) -> TypeParams { | |
89 | TypeParams(self.params.iter()) | |
90 | } | |
91 | ||
92 | /// Returns an | |
93 | /// <code | |
94 | /// style="padding-right:0;">Iterator<Item = &mut </code><a | |
95 | /// href="struct.TypeParam.html"><code | |
96 | /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code | |
97 | /// style="padding-left:0;">></code> | |
98 | /// over the type parameters in `self.params`. | |
99 | pub fn type_params_mut(&mut self) -> TypeParamsMut { | |
100 | TypeParamsMut(self.params.iter_mut()) | |
101 | } | |
102 | ||
103 | /// Returns an | |
104 | /// <code | |
105 | /// style="padding-right:0;">Iterator<Item = &</code><a | |
106 | /// href="struct.LifetimeDef.html"><code | |
107 | /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code | |
108 | /// style="padding-left:0;">></code> | |
109 | /// over the lifetime parameters in `self.params`. | |
110 | pub fn lifetimes(&self) -> Lifetimes { | |
111 | Lifetimes(self.params.iter()) | |
112 | } | |
113 | ||
114 | /// Returns an | |
115 | /// <code | |
116 | /// style="padding-right:0;">Iterator<Item = &mut </code><a | |
117 | /// href="struct.LifetimeDef.html"><code | |
118 | /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code | |
119 | /// style="padding-left:0;">></code> | |
120 | /// over the lifetime parameters in `self.params`. | |
121 | pub fn lifetimes_mut(&mut self) -> LifetimesMut { | |
122 | LifetimesMut(self.params.iter_mut()) | |
123 | } | |
124 | ||
125 | /// Returns an | |
126 | /// <code | |
127 | /// style="padding-right:0;">Iterator<Item = &</code><a | |
128 | /// href="struct.ConstParam.html"><code | |
129 | /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code | |
130 | /// style="padding-left:0;">></code> | |
131 | /// over the constant parameters in `self.params`. | |
132 | pub fn const_params(&self) -> ConstParams { | |
133 | ConstParams(self.params.iter()) | |
134 | } | |
135 | ||
136 | /// Returns an | |
137 | /// <code | |
138 | /// style="padding-right:0;">Iterator<Item = &mut </code><a | |
139 | /// href="struct.ConstParam.html"><code | |
140 | /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code | |
141 | /// style="padding-left:0;">></code> | |
142 | /// over the constant parameters in `self.params`. | |
143 | pub fn const_params_mut(&mut self) -> ConstParamsMut { | |
144 | ConstParamsMut(self.params.iter_mut()) | |
145 | } | |
146 | } | |
147 | ||
148 | pub struct TypeParams<'a>(Iter<'a, GenericParam, Token![,]>); | |
149 | ||
150 | impl<'a> Iterator for TypeParams<'a> { | |
151 | type Item = &'a TypeParam; | |
152 | ||
153 | fn next(&mut self) -> Option<Self::Item> { | |
154 | // FIXME: Remove this when ? on Option is stable | |
155 | let next = match self.0.next() { | |
156 | Some(item) => item, | |
157 | None => return None, | |
158 | }; | |
159 | if let GenericParam::Type(ref type_param) = *next { | |
160 | Some(type_param) | |
161 | } else { | |
162 | self.next() | |
163 | } | |
164 | } | |
165 | } | |
166 | ||
167 | pub struct TypeParamsMut<'a>(IterMut<'a, GenericParam, Token![,]>); | |
168 | ||
169 | impl<'a> Iterator for TypeParamsMut<'a> { | |
170 | type Item = &'a mut TypeParam; | |
171 | ||
172 | fn next(&mut self) -> Option<Self::Item> { | |
173 | // FIXME: Remove this when ? on Option is stable | |
174 | let next = match self.0.next() { | |
175 | Some(item) => item, | |
176 | None => return None, | |
177 | }; | |
178 | if let GenericParam::Type(ref mut type_param) = *next { | |
179 | Some(type_param) | |
180 | } else { | |
181 | self.next() | |
182 | } | |
183 | } | |
184 | } | |
185 | ||
186 | pub struct Lifetimes<'a>(Iter<'a, GenericParam, Token![,]>); | |
187 | ||
188 | impl<'a> Iterator for Lifetimes<'a> { | |
189 | type Item = &'a LifetimeDef; | |
190 | ||
191 | fn next(&mut self) -> Option<Self::Item> { | |
192 | // FIXME: Remove this when ? on Option is stable | |
193 | let next = match self.0.next() { | |
194 | Some(item) => item, | |
195 | None => return None, | |
196 | }; | |
197 | if let GenericParam::Lifetime(ref lifetime) = *next { | |
198 | Some(lifetime) | |
199 | } else { | |
200 | self.next() | |
201 | } | |
202 | } | |
203 | } | |
204 | ||
205 | pub struct LifetimesMut<'a>(IterMut<'a, GenericParam, Token![,]>); | |
206 | ||
207 | impl<'a> Iterator for LifetimesMut<'a> { | |
208 | type Item = &'a mut LifetimeDef; | |
209 | ||
210 | fn next(&mut self) -> Option<Self::Item> { | |
211 | // FIXME: Remove this when ? on Option is stable | |
212 | let next = match self.0.next() { | |
213 | Some(item) => item, | |
214 | None => return None, | |
215 | }; | |
216 | if let GenericParam::Lifetime(ref mut lifetime) = *next { | |
217 | Some(lifetime) | |
218 | } else { | |
219 | self.next() | |
220 | } | |
221 | } | |
222 | } | |
223 | ||
224 | pub struct ConstParams<'a>(Iter<'a, GenericParam, Token![,]>); | |
225 | ||
226 | impl<'a> Iterator for ConstParams<'a> { | |
227 | type Item = &'a ConstParam; | |
228 | ||
229 | fn next(&mut self) -> Option<Self::Item> { | |
230 | // FIXME: Remove this when ? on Option is stable | |
231 | let next = match self.0.next() { | |
232 | Some(item) => item, | |
233 | None => return None, | |
234 | }; | |
235 | if let GenericParam::Const(ref const_param) = *next { | |
236 | Some(const_param) | |
237 | } else { | |
238 | self.next() | |
239 | } | |
240 | } | |
241 | } | |
242 | ||
243 | pub struct ConstParamsMut<'a>(IterMut<'a, GenericParam, Token![,]>); | |
244 | ||
245 | impl<'a> Iterator for ConstParamsMut<'a> { | |
246 | type Item = &'a mut ConstParam; | |
247 | ||
248 | fn next(&mut self) -> Option<Self::Item> { | |
249 | // FIXME: Remove this when ? on Option is stable | |
250 | let next = match self.0.next() { | |
251 | Some(item) => item, | |
252 | None => return None, | |
253 | }; | |
254 | if let GenericParam::Const(ref mut const_param) = *next { | |
255 | Some(const_param) | |
256 | } else { | |
257 | self.next() | |
258 | } | |
259 | } | |
260 | } | |
261 | ||
262 | /// Returned by `Generics::split_for_impl`. | |
263 | /// | |
264 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
265 | /// feature and the `"printing"` feature.* | |
266 | #[cfg(feature = "printing")] | |
267 | #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] | |
268 | #[cfg_attr(feature = "clone-impls", derive(Clone))] | |
269 | pub struct ImplGenerics<'a>(&'a Generics); | |
270 | ||
271 | /// Returned by `Generics::split_for_impl`. | |
272 | /// | |
273 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
274 | /// feature and the `"printing"` feature.* | |
275 | #[cfg(feature = "printing")] | |
276 | #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] | |
277 | #[cfg_attr(feature = "clone-impls", derive(Clone))] | |
278 | pub struct TypeGenerics<'a>(&'a Generics); | |
279 | ||
280 | /// Returned by `TypeGenerics::as_turbofish`. | |
281 | /// | |
282 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
283 | /// feature and the `"printing"` feature.* | |
284 | #[cfg(feature = "printing")] | |
285 | #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] | |
286 | #[cfg_attr(feature = "clone-impls", derive(Clone))] | |
287 | pub struct Turbofish<'a>(&'a Generics); | |
288 | ||
289 | #[cfg(feature = "printing")] | |
290 | impl Generics { | |
291 | /// Split a type's generics into the pieces required for impl'ing a trait | |
292 | /// for that type. | |
293 | /// | |
294 | /// ``` | |
295 | /// # extern crate syn; | |
296 | /// # #[macro_use] | |
297 | /// # extern crate quote; | |
298 | /// # fn main() { | |
299 | /// # let generics: syn::Generics = Default::default(); | |
300 | /// # let name = syn::Ident::from("MyType"); | |
301 | /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); | |
302 | /// quote! { | |
303 | /// impl #impl_generics MyTrait for #name #ty_generics #where_clause { | |
304 | /// // ... | |
305 | /// } | |
306 | /// } | |
307 | /// # ; | |
308 | /// # } | |
309 | /// ``` | |
310 | /// | |
311 | /// *This method is available if Syn is built with the `"derive"` or | |
312 | /// `"full"` feature and the `"printing"` feature.* | |
313 | pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) { | |
314 | ( | |
315 | ImplGenerics(self), | |
316 | TypeGenerics(self), | |
317 | self.where_clause.as_ref(), | |
318 | ) | |
319 | } | |
320 | } | |
321 | ||
322 | #[cfg(feature = "printing")] | |
323 | impl<'a> TypeGenerics<'a> { | |
324 | /// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`. | |
325 | /// | |
326 | /// *This method is available if Syn is built with the `"derive"` or | |
327 | /// `"full"` feature and the `"printing"` feature.* | |
328 | pub fn as_turbofish(&self) -> Turbofish { | |
329 | Turbofish(self.0) | |
330 | } | |
331 | } | |
332 | ||
333 | ast_struct! { | |
334 | /// A set of bound lifetimes: `for<'a, 'b, 'c>`. | |
335 | /// | |
336 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
337 | /// feature.* | |
338 | #[derive(Default)] | |
339 | pub struct BoundLifetimes { | |
340 | pub for_token: Token![for], | |
341 | pub lt_token: Token![<], | |
342 | pub lifetimes: Punctuated<LifetimeDef, Token![,]>, | |
343 | pub gt_token: Token![>], | |
344 | } | |
345 | } | |
346 | ||
347 | impl LifetimeDef { | |
348 | pub fn new(lifetime: Lifetime) -> Self { | |
349 | LifetimeDef { | |
350 | attrs: Vec::new(), | |
351 | lifetime: lifetime, | |
352 | colon_token: None, | |
353 | bounds: Punctuated::new(), | |
354 | } | |
355 | } | |
356 | } | |
357 | ||
358 | impl From<Ident> for TypeParam { | |
359 | fn from(ident: Ident) -> Self { | |
360 | TypeParam { | |
361 | attrs: vec![], | |
362 | ident: ident, | |
363 | colon_token: None, | |
364 | bounds: Punctuated::new(), | |
365 | eq_token: None, | |
366 | default: None, | |
367 | } | |
368 | } | |
369 | } | |
370 | ||
371 | ast_enum_of_structs! { | |
372 | /// A trait or lifetime used as a bound on a type parameter. | |
373 | /// | |
374 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
375 | /// feature.* | |
376 | pub enum TypeParamBound { | |
377 | pub Trait(TraitBound), | |
378 | pub Lifetime(Lifetime), | |
379 | } | |
380 | } | |
381 | ||
382 | ast_struct! { | |
383 | /// A trait used as a bound on a type parameter. | |
384 | /// | |
385 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
386 | /// feature.* | |
387 | pub struct TraitBound { | |
388 | pub modifier: TraitBoundModifier, | |
389 | /// The `for<'a>` in `for<'a> Foo<&'a T>` | |
390 | pub lifetimes: Option<BoundLifetimes>, | |
391 | /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>` | |
392 | pub path: Path, | |
393 | } | |
394 | } | |
395 | ||
396 | ast_enum! { | |
397 | /// A modifier on a trait bound, currently only used for the `?` in | |
398 | /// `?Sized`. | |
399 | /// | |
400 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
401 | /// feature.* | |
402 | #[cfg_attr(feature = "clone-impls", derive(Copy))] | |
403 | pub enum TraitBoundModifier { | |
404 | None, | |
405 | Maybe(Token![?]), | |
406 | } | |
407 | } | |
408 | ||
409 | ast_struct! { | |
410 | /// A `where` clause in a definition: `where T: Deserialize<'de>, D: | |
411 | /// 'static`. | |
412 | /// | |
413 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
414 | /// feature.* | |
415 | pub struct WhereClause { | |
416 | pub where_token: Token![where], | |
417 | pub predicates: Punctuated<WherePredicate, Token![,]>, | |
418 | } | |
419 | } | |
420 | ||
421 | ast_enum_of_structs! { | |
422 | /// A single predicate in a `where` clause: `T: Deserialize<'de>`. | |
423 | /// | |
424 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
425 | /// feature.* | |
426 | /// | |
427 | /// # Syntax tree enum | |
428 | /// | |
429 | /// This type is a [syntax tree enum]. | |
430 | /// | |
431 | /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums | |
432 | pub enum WherePredicate { | |
433 | /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`. | |
434 | /// | |
435 | /// *This type is available if Syn is built with the `"derive"` or | |
436 | /// `"full"` feature.* | |
437 | pub Type(PredicateType { | |
438 | /// Any lifetimes from a `for` binding | |
439 | pub lifetimes: Option<BoundLifetimes>, | |
440 | /// The type being bounded | |
441 | pub bounded_ty: Type, | |
442 | pub colon_token: Token![:], | |
443 | /// Trait and lifetime bounds (`Clone+Send+'static`) | |
444 | pub bounds: Punctuated<TypeParamBound, Token![+]>, | |
445 | }), | |
446 | ||
447 | /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`. | |
448 | /// | |
449 | /// *This type is available if Syn is built with the `"derive"` or | |
450 | /// `"full"` feature.* | |
451 | pub Lifetime(PredicateLifetime { | |
452 | pub lifetime: Lifetime, | |
453 | pub colon_token: Option<Token![:]>, | |
454 | pub bounds: Punctuated<Lifetime, Token![+]>, | |
455 | }), | |
456 | ||
457 | /// An equality predicate in a `where` clause (unsupported). | |
458 | /// | |
459 | /// *This type is available if Syn is built with the `"derive"` or | |
460 | /// `"full"` feature.* | |
461 | pub Eq(PredicateEq { | |
462 | pub lhs_ty: Type, | |
463 | pub eq_token: Token![=], | |
464 | pub rhs_ty: Type, | |
465 | }), | |
466 | } | |
467 | } | |
468 | ||
469 | #[cfg(feature = "parsing")] | |
470 | pub mod parsing { | |
471 | use super::*; | |
472 | ||
473 | use synom::Synom; | |
474 | use punctuated::Pair; | |
475 | ||
476 | impl Synom for Generics { | |
477 | named!(parse -> Self, map!( | |
478 | alt!( | |
479 | do_parse!( | |
480 | lt: punct!(<) >> | |
481 | lifetimes: call!(Punctuated::<LifetimeDef, Token![,]>::parse_terminated) >> | |
482 | ty_params: cond!( | |
483 | lifetimes.empty_or_trailing(), | |
484 | Punctuated::<TypeParam, Token![,]>::parse_terminated | |
485 | ) >> | |
486 | gt: punct!(>) >> | |
487 | (lifetimes, ty_params, Some(lt), Some(gt)) | |
488 | ) | |
489 | | | |
490 | epsilon!() => { |_| (Punctuated::new(), None, None, None) } | |
491 | ), | |
492 | |(lifetimes, ty_params, lt, gt)| Generics { | |
493 | lt_token: lt, | |
494 | params: lifetimes.into_pairs() | |
495 | .map(Pair::into_tuple) | |
496 | .map(|(life, comma)| Pair::new(GenericParam::Lifetime(life), comma)) | |
497 | .chain(ty_params.unwrap_or_default() | |
498 | .into_pairs() | |
499 | .map(Pair::into_tuple) | |
500 | .map(|(ty, comma)| Pair::new(GenericParam::Type(ty), comma))) | |
501 | .collect(), | |
502 | gt_token: gt, | |
503 | where_clause: None, | |
504 | } | |
505 | )); | |
506 | ||
507 | fn description() -> Option<&'static str> { | |
508 | Some("generic parameters in declaration") | |
509 | } | |
510 | } | |
511 | ||
512 | impl Synom for GenericParam { | |
513 | named!(parse -> Self, alt!( | |
514 | syn!(TypeParam) => { GenericParam::Type } | |
515 | | | |
516 | syn!(LifetimeDef) => { GenericParam::Lifetime } | |
517 | | | |
518 | syn!(ConstParam) => { GenericParam::Const } | |
519 | )); | |
520 | ||
521 | fn description() -> Option<&'static str> { | |
522 | Some("generic parameter") | |
523 | } | |
524 | } | |
525 | ||
526 | impl Synom for LifetimeDef { | |
527 | named!(parse -> Self, do_parse!( | |
528 | attrs: many0!(Attribute::parse_outer) >> | |
529 | life: syn!(Lifetime) >> | |
530 | colon: option!(punct!(:)) >> | |
531 | bounds: cond!( | |
532 | colon.is_some(), | |
533 | Punctuated::parse_separated_nonempty | |
534 | ) >> | |
535 | (LifetimeDef { | |
536 | attrs: attrs, | |
537 | lifetime: life, | |
538 | bounds: bounds.unwrap_or_default(), | |
539 | colon_token: colon, | |
540 | }) | |
541 | )); | |
542 | ||
543 | fn description() -> Option<&'static str> { | |
544 | Some("lifetime definition") | |
545 | } | |
546 | } | |
547 | ||
548 | impl Synom for BoundLifetimes { | |
549 | named!(parse -> Self, do_parse!( | |
550 | for_: keyword!(for) >> | |
551 | lt: punct!(<) >> | |
552 | lifetimes: call!(Punctuated::parse_terminated) >> | |
553 | gt: punct!(>) >> | |
554 | (BoundLifetimes { | |
555 | for_token: for_, | |
556 | lt_token: lt, | |
557 | gt_token: gt, | |
558 | lifetimes: lifetimes, | |
559 | }) | |
560 | )); | |
561 | ||
562 | fn description() -> Option<&'static str> { | |
563 | Some("bound lifetimes") | |
564 | } | |
565 | } | |
566 | ||
567 | impl Synom for TypeParam { | |
568 | named!(parse -> Self, do_parse!( | |
569 | attrs: many0!(Attribute::parse_outer) >> | |
570 | id: syn!(Ident) >> | |
571 | colon: option!(punct!(:)) >> | |
572 | bounds: cond!( | |
573 | colon.is_some(), | |
574 | Punctuated::parse_separated_nonempty | |
575 | ) >> | |
576 | default: option!(do_parse!( | |
577 | eq: punct!(=) >> | |
578 | ty: syn!(Type) >> | |
579 | (eq, ty) | |
580 | )) >> | |
581 | (TypeParam { | |
582 | attrs: attrs, | |
583 | ident: id, | |
584 | bounds: bounds.unwrap_or_default(), | |
585 | colon_token: colon, | |
586 | eq_token: default.as_ref().map(|d| Token![=]((d.0).0)), | |
587 | default: default.map(|d| d.1), | |
588 | }) | |
589 | )); | |
590 | ||
591 | fn description() -> Option<&'static str> { | |
592 | Some("type parameter") | |
593 | } | |
594 | } | |
595 | ||
596 | impl Synom for TypeParamBound { | |
597 | named!(parse -> Self, alt!( | |
598 | syn!(Lifetime) => { TypeParamBound::Lifetime } | |
599 | | | |
600 | syn!(TraitBound) => { TypeParamBound::Trait } | |
601 | | | |
602 | parens!(syn!(TraitBound)) => { |bound| TypeParamBound::Trait(bound.1) } | |
603 | )); | |
604 | ||
605 | fn description() -> Option<&'static str> { | |
606 | Some("type parameter bound") | |
607 | } | |
608 | } | |
609 | ||
610 | impl Synom for TraitBound { | |
611 | named!(parse -> Self, do_parse!( | |
612 | modifier: syn!(TraitBoundModifier) >> | |
613 | lifetimes: option!(syn!(BoundLifetimes)) >> | |
614 | mut path: syn!(Path) >> | |
615 | parenthesized: option!(cond_reduce!( | |
616 | path.segments.last().unwrap().value().arguments.is_empty(), | |
617 | syn!(ParenthesizedGenericArguments) | |
618 | )) >> | |
619 | ({ | |
620 | if let Some(parenthesized) = parenthesized { | |
621 | let parenthesized = PathArguments::Parenthesized(parenthesized); | |
622 | path.segments.last_mut().unwrap().value_mut().arguments = parenthesized; | |
623 | } | |
624 | TraitBound { | |
625 | modifier: modifier, | |
626 | lifetimes: lifetimes, | |
627 | path: path, | |
628 | } | |
629 | }) | |
630 | )); | |
631 | ||
632 | fn description() -> Option<&'static str> { | |
633 | Some("trait bound") | |
634 | } | |
635 | } | |
636 | ||
637 | impl Synom for TraitBoundModifier { | |
638 | named!(parse -> Self, alt!( | |
639 | punct!(?) => { TraitBoundModifier::Maybe } | |
640 | | | |
641 | epsilon!() => { |_| TraitBoundModifier::None } | |
642 | )); | |
643 | ||
644 | fn description() -> Option<&'static str> { | |
645 | Some("trait bound modifier") | |
646 | } | |
647 | } | |
648 | ||
649 | impl Synom for ConstParam { | |
650 | named!(parse -> Self, do_parse!( | |
651 | attrs: many0!(Attribute::parse_outer) >> | |
652 | const_: keyword!(const) >> | |
653 | ident: syn!(Ident) >> | |
654 | colon: punct!(:) >> | |
655 | ty: syn!(Type) >> | |
656 | eq_def: option!(tuple!(punct!(=), syn!(Expr))) >> | |
657 | ({ | |
658 | let (eq_token, default) = match eq_def { | |
659 | Some((eq_token, default)) => (Some(eq_token), Some(default)), | |
660 | None => (None, None), | |
661 | }; | |
662 | ConstParam { | |
663 | attrs: attrs, | |
664 | const_token: const_, | |
665 | ident: ident, | |
666 | colon_token: colon, | |
667 | ty: ty, | |
668 | eq_token: eq_token, | |
669 | default: default, | |
670 | } | |
671 | }) | |
672 | )); | |
673 | ||
674 | fn description() -> Option<&'static str> { | |
675 | Some("generic `const` parameter") | |
676 | } | |
677 | } | |
678 | ||
679 | impl Synom for WhereClause { | |
680 | named!(parse -> Self, do_parse!( | |
681 | where_: keyword!(where) >> | |
682 | predicates: call!(Punctuated::parse_terminated) >> | |
683 | (WhereClause { | |
684 | predicates: predicates, | |
685 | where_token: where_, | |
686 | }) | |
687 | )); | |
688 | ||
689 | fn description() -> Option<&'static str> { | |
690 | Some("where clause") | |
691 | } | |
692 | } | |
693 | ||
694 | impl Synom for WherePredicate { | |
695 | named!(parse -> Self, alt!( | |
696 | do_parse!( | |
697 | ident: syn!(Lifetime) >> | |
698 | colon: option!(punct!(:)) >> | |
699 | bounds: cond!( | |
700 | colon.is_some(), | |
701 | Punctuated::parse_separated | |
702 | ) >> | |
703 | (WherePredicate::Lifetime(PredicateLifetime { | |
704 | lifetime: ident, | |
705 | bounds: bounds.unwrap_or_default(), | |
706 | colon_token: colon, | |
707 | })) | |
708 | ) | |
709 | | | |
710 | do_parse!( | |
711 | lifetimes: option!(syn!(BoundLifetimes)) >> | |
712 | bounded_ty: syn!(Type) >> | |
713 | colon: punct!(:) >> | |
714 | bounds: call!(Punctuated::parse_separated_nonempty) >> | |
715 | (WherePredicate::Type(PredicateType { | |
716 | lifetimes: lifetimes, | |
717 | bounded_ty: bounded_ty, | |
718 | bounds: bounds, | |
719 | colon_token: colon, | |
720 | })) | |
721 | ) | |
722 | )); | |
723 | ||
724 | fn description() -> Option<&'static str> { | |
725 | Some("predicate in where clause") | |
726 | } | |
727 | } | |
728 | } | |
729 | ||
730 | #[cfg(feature = "printing")] | |
731 | mod printing { | |
732 | use super::*; | |
733 | use attr::FilterAttrs; | |
734 | use quote::{ToTokens, Tokens}; | |
735 | ||
736 | impl ToTokens for Generics { | |
737 | fn to_tokens(&self, tokens: &mut Tokens) { | |
738 | if self.params.is_empty() { | |
739 | return; | |
740 | } | |
741 | ||
742 | TokensOrDefault(&self.lt_token).to_tokens(tokens); | |
743 | ||
744 | // Print lifetimes before types and consts, regardless of their | |
745 | // order in self.params. | |
746 | // | |
747 | // TODO: ordering rules for const parameters vs type parameters have | |
748 | // not been settled yet. https://github.com/rust-lang/rust/issues/44580 | |
749 | let mut trailing_or_empty = true; | |
750 | for param in self.params.pairs() { | |
751 | if let GenericParam::Lifetime(_) = **param.value() { | |
752 | param.to_tokens(tokens); | |
753 | trailing_or_empty = param.punct().is_some(); | |
754 | } | |
755 | } | |
756 | for param in self.params.pairs() { | |
757 | match **param.value() { | |
758 | GenericParam::Type(_) | GenericParam::Const(_) => { | |
759 | if !trailing_or_empty { | |
760 | <Token![,]>::default().to_tokens(tokens); | |
761 | trailing_or_empty = true; | |
762 | } | |
763 | param.to_tokens(tokens); | |
764 | } | |
765 | GenericParam::Lifetime(_) => {} | |
766 | } | |
767 | } | |
768 | ||
769 | TokensOrDefault(&self.gt_token).to_tokens(tokens); | |
770 | } | |
771 | } | |
772 | ||
773 | impl<'a> ToTokens for ImplGenerics<'a> { | |
774 | fn to_tokens(&self, tokens: &mut Tokens) { | |
775 | if self.0.params.is_empty() { | |
776 | return; | |
777 | } | |
778 | ||
779 | TokensOrDefault(&self.0.lt_token).to_tokens(tokens); | |
780 | ||
781 | // Print lifetimes before types and consts, regardless of their | |
782 | // order in self.params. | |
783 | // | |
784 | // TODO: ordering rules for const parameters vs type parameters have | |
785 | // not been settled yet. https://github.com/rust-lang/rust/issues/44580 | |
786 | let mut trailing_or_empty = true; | |
787 | for param in self.0.params.pairs() { | |
788 | if let GenericParam::Lifetime(_) = **param.value() { | |
789 | param.to_tokens(tokens); | |
790 | trailing_or_empty = param.punct().is_some(); | |
791 | } | |
792 | } | |
793 | for param in self.0.params.pairs() { | |
794 | if let GenericParam::Lifetime(_) = **param.value() { | |
795 | continue; | |
796 | } | |
797 | if !trailing_or_empty { | |
798 | <Token![,]>::default().to_tokens(tokens); | |
799 | trailing_or_empty = true; | |
800 | } | |
801 | match **param.value() { | |
802 | GenericParam::Lifetime(_) => unreachable!(), | |
803 | GenericParam::Type(ref param) => { | |
804 | // Leave off the type parameter defaults | |
805 | tokens.append_all(param.attrs.outer()); | |
806 | param.ident.to_tokens(tokens); | |
807 | if !param.bounds.is_empty() { | |
808 | TokensOrDefault(¶m.colon_token).to_tokens(tokens); | |
809 | param.bounds.to_tokens(tokens); | |
810 | } | |
811 | } | |
812 | GenericParam::Const(ref param) => { | |
813 | // Leave off the const parameter defaults | |
814 | tokens.append_all(param.attrs.outer()); | |
815 | param.const_token.to_tokens(tokens); | |
816 | param.ident.to_tokens(tokens); | |
817 | param.colon_token.to_tokens(tokens); | |
818 | param.ty.to_tokens(tokens); | |
819 | } | |
820 | } | |
821 | param.punct().to_tokens(tokens); | |
822 | } | |
823 | ||
824 | TokensOrDefault(&self.0.gt_token).to_tokens(tokens); | |
825 | } | |
826 | } | |
827 | ||
828 | impl<'a> ToTokens for TypeGenerics<'a> { | |
829 | fn to_tokens(&self, tokens: &mut Tokens) { | |
830 | if self.0.params.is_empty() { | |
831 | return; | |
832 | } | |
833 | ||
834 | TokensOrDefault(&self.0.lt_token).to_tokens(tokens); | |
835 | ||
836 | // Print lifetimes before types and consts, regardless of their | |
837 | // order in self.params. | |
838 | // | |
839 | // TODO: ordering rules for const parameters vs type parameters have | |
840 | // not been settled yet. https://github.com/rust-lang/rust/issues/44580 | |
841 | let mut trailing_or_empty = true; | |
842 | for param in self.0.params.pairs() { | |
843 | if let GenericParam::Lifetime(ref def) = **param.value() { | |
844 | // Leave off the lifetime bounds and attributes | |
845 | def.lifetime.to_tokens(tokens); | |
846 | param.punct().to_tokens(tokens); | |
847 | trailing_or_empty = param.punct().is_some(); | |
848 | } | |
849 | } | |
850 | for param in self.0.params.pairs() { | |
851 | if let GenericParam::Lifetime(_) = **param.value() { | |
852 | continue; | |
853 | } | |
854 | if !trailing_or_empty { | |
855 | <Token![,]>::default().to_tokens(tokens); | |
856 | trailing_or_empty = true; | |
857 | } | |
858 | match **param.value() { | |
859 | GenericParam::Lifetime(_) => unreachable!(), | |
860 | GenericParam::Type(ref param) => { | |
861 | // Leave off the type parameter defaults | |
862 | param.ident.to_tokens(tokens); | |
863 | } | |
864 | GenericParam::Const(ref param) => { | |
865 | // Leave off the const parameter defaults | |
866 | param.ident.to_tokens(tokens); | |
867 | } | |
868 | } | |
869 | param.punct().to_tokens(tokens); | |
870 | } | |
871 | ||
872 | TokensOrDefault(&self.0.gt_token).to_tokens(tokens); | |
873 | } | |
874 | } | |
875 | ||
876 | impl<'a> ToTokens for Turbofish<'a> { | |
877 | fn to_tokens(&self, tokens: &mut Tokens) { | |
878 | if !self.0.params.is_empty() { | |
879 | <Token![::]>::default().to_tokens(tokens); | |
880 | TypeGenerics(self.0).to_tokens(tokens); | |
881 | } | |
882 | } | |
883 | } | |
884 | ||
885 | impl ToTokens for BoundLifetimes { | |
886 | fn to_tokens(&self, tokens: &mut Tokens) { | |
887 | self.for_token.to_tokens(tokens); | |
888 | self.lt_token.to_tokens(tokens); | |
889 | self.lifetimes.to_tokens(tokens); | |
890 | self.gt_token.to_tokens(tokens); | |
891 | } | |
892 | } | |
893 | ||
894 | impl ToTokens for LifetimeDef { | |
895 | fn to_tokens(&self, tokens: &mut Tokens) { | |
896 | tokens.append_all(self.attrs.outer()); | |
897 | self.lifetime.to_tokens(tokens); | |
898 | if !self.bounds.is_empty() { | |
899 | TokensOrDefault(&self.colon_token).to_tokens(tokens); | |
900 | self.bounds.to_tokens(tokens); | |
901 | } | |
902 | } | |
903 | } | |
904 | ||
905 | impl ToTokens for TypeParam { | |
906 | fn to_tokens(&self, tokens: &mut Tokens) { | |
907 | tokens.append_all(self.attrs.outer()); | |
908 | self.ident.to_tokens(tokens); | |
909 | if !self.bounds.is_empty() { | |
910 | TokensOrDefault(&self.colon_token).to_tokens(tokens); | |
911 | self.bounds.to_tokens(tokens); | |
912 | } | |
913 | if self.default.is_some() { | |
914 | TokensOrDefault(&self.eq_token).to_tokens(tokens); | |
915 | self.default.to_tokens(tokens); | |
916 | } | |
917 | } | |
918 | } | |
919 | ||
920 | impl ToTokens for TraitBound { | |
921 | fn to_tokens(&self, tokens: &mut Tokens) { | |
922 | self.modifier.to_tokens(tokens); | |
923 | self.lifetimes.to_tokens(tokens); | |
924 | self.path.to_tokens(tokens); | |
925 | } | |
926 | } | |
927 | ||
928 | impl ToTokens for TraitBoundModifier { | |
929 | fn to_tokens(&self, tokens: &mut Tokens) { | |
930 | match *self { | |
931 | TraitBoundModifier::None => {} | |
932 | TraitBoundModifier::Maybe(ref t) => t.to_tokens(tokens), | |
933 | } | |
934 | } | |
935 | } | |
936 | ||
937 | impl ToTokens for ConstParam { | |
938 | fn to_tokens(&self, tokens: &mut Tokens) { | |
939 | tokens.append_all(self.attrs.outer()); | |
940 | self.const_token.to_tokens(tokens); | |
941 | self.ident.to_tokens(tokens); | |
942 | self.colon_token.to_tokens(tokens); | |
943 | self.ty.to_tokens(tokens); | |
944 | if self.default.is_some() { | |
945 | TokensOrDefault(&self.eq_token).to_tokens(tokens); | |
946 | self.default.to_tokens(tokens); | |
947 | } | |
948 | } | |
949 | } | |
950 | ||
951 | impl ToTokens for WhereClause { | |
952 | fn to_tokens(&self, tokens: &mut Tokens) { | |
953 | if !self.predicates.is_empty() { | |
954 | self.where_token.to_tokens(tokens); | |
955 | self.predicates.to_tokens(tokens); | |
956 | } | |
957 | } | |
958 | } | |
959 | ||
960 | impl ToTokens for PredicateType { | |
961 | fn to_tokens(&self, tokens: &mut Tokens) { | |
962 | self.lifetimes.to_tokens(tokens); | |
963 | self.bounded_ty.to_tokens(tokens); | |
964 | self.colon_token.to_tokens(tokens); | |
965 | self.bounds.to_tokens(tokens); | |
966 | } | |
967 | } | |
968 | ||
969 | impl ToTokens for PredicateLifetime { | |
970 | fn to_tokens(&self, tokens: &mut Tokens) { | |
971 | self.lifetime.to_tokens(tokens); | |
972 | if !self.bounds.is_empty() { | |
973 | TokensOrDefault(&self.colon_token).to_tokens(tokens); | |
974 | self.bounds.to_tokens(tokens); | |
975 | } | |
976 | } | |
977 | } | |
978 | ||
979 | impl ToTokens for PredicateEq { | |
980 | fn to_tokens(&self, tokens: &mut Tokens) { | |
981 | self.lhs_ty.to_tokens(tokens); | |
982 | self.eq_token.to_tokens(tokens); | |
983 | self.rhs_ty.to_tokens(tokens); | |
984 | } | |
985 | } | |
986 | } |