blob: c2ad34af9ced43010e4fa873c90a027e6abeaafe [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// 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
David Tolnay056de302018-01-05 14:29:05 -08009use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -070010use punctuated::Punctuated;
David Tolnay056de302018-01-05 14:29:05 -080011
12ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080013 /// A path at which a named item is exported: `std::collections::HashMap`.
David Tolnay461d98e2018-01-07 11:07:19 -080014 ///
15 /// *This type is available if Syn is built with the `"derive"` or `"full"`
16 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -080017 pub struct Path {
David Tolnay056de302018-01-05 14:29:05 -080018 pub leading_colon: Option<Token![::]>,
David Tolnay056de302018-01-05 14:29:05 -080019 pub segments: Punctuated<PathSegment, Token![::]>,
20 }
21}
22
23impl Path {
24 pub fn global(&self) -> bool {
25 self.leading_colon.is_some()
26 }
27}
28
David Tolnay05658502018-01-07 09:56:37 -080029/// A helper for printing a self-type qualified path as tokens.
30///
31/// ```rust
32/// extern crate syn;
33/// extern crate quote;
Alex Crichtonf0fea9a2018-05-17 11:19:34 -070034/// extern crate proc_macro2;
David Tolnay05658502018-01-07 09:56:37 -080035///
36/// use syn::{QSelf, Path, PathTokens};
Alex Crichtonf0fea9a2018-05-17 11:19:34 -070037/// use proc_macro2::TokenStream;
38/// use quote::ToTokens;
David Tolnay05658502018-01-07 09:56:37 -080039///
40/// struct MyNode {
41/// qself: Option<QSelf>,
42/// path: Path,
43/// }
44///
45/// impl ToTokens for MyNode {
Alex Crichtona74a1c82018-05-16 10:20:44 -070046/// fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay05658502018-01-07 09:56:37 -080047/// PathTokens(&self.qself, &self.path).to_tokens(tokens);
48/// }
49/// }
50/// #
51/// # fn main() {}
52/// ```
David Tolnay461d98e2018-01-07 11:07:19 -080053///
54/// *This type is available if Syn is built with the `"derive"` or `"full"`
55/// feature and the `"printing"` feature.*
David Tolnay056de302018-01-05 14:29:05 -080056#[cfg(feature = "printing")]
57#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
58#[cfg_attr(feature = "clone-impls", derive(Clone))]
59pub struct PathTokens<'a>(pub &'a Option<QSelf>, pub &'a Path);
60
61impl<T> From<T> for Path
62where
63 T: Into<PathSegment>,
64{
65 fn from(segment: T) -> Self {
66 let mut path = Path {
67 leading_colon: None,
68 segments: Punctuated::new(),
69 };
David Tolnay56080682018-01-06 14:01:52 -080070 path.segments.push_value(segment.into());
David Tolnay056de302018-01-05 14:29:05 -080071 path
72 }
73}
74
75ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080076 /// A segment of a path together with any path arguments on that segment.
David Tolnay461d98e2018-01-07 11:07:19 -080077 ///
78 /// *This type is available if Syn is built with the `"derive"` or `"full"`
79 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -080080 pub struct PathSegment {
David Tolnay056de302018-01-05 14:29:05 -080081 pub ident: Ident,
David Tolnay056de302018-01-05 14:29:05 -080082 pub arguments: PathArguments,
83 }
84}
85
86impl<T> From<T> for PathSegment
87where
88 T: Into<Ident>,
89{
90 fn from(ident: T) -> Self {
91 PathSegment {
92 ident: ident.into(),
93 arguments: PathArguments::None,
94 }
95 }
96}
97
98ast_enum! {
David Tolnayc0435192018-01-07 11:46:08 -080099 /// Angle bracketed or parenthesized arguments of a path segment.
David Tolnay461d98e2018-01-07 11:07:19 -0800100 ///
101 /// *This type is available if Syn is built with the `"derive"` or `"full"`
102 /// feature.*
David Tolnayc0435192018-01-07 11:46:08 -0800103 ///
104 /// ## Angle bracketed
105 ///
106 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
107 ///
108 /// ## Parenthesized
109 ///
110 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -0800111 pub enum PathArguments {
112 None,
David Tolnaye826d812018-01-06 23:59:39 -0800113 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
David Tolnay056de302018-01-05 14:29:05 -0800114 AngleBracketed(AngleBracketedGenericArguments),
David Tolnayc0435192018-01-07 11:46:08 -0800115 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -0800116 Parenthesized(ParenthesizedGenericArguments),
117 }
118}
119
120impl Default for PathArguments {
121 fn default() -> Self {
122 PathArguments::None
123 }
124}
125
126impl PathArguments {
127 pub fn is_empty(&self) -> bool {
128 match *self {
129 PathArguments::None => true,
130 PathArguments::AngleBracketed(ref bracketed) => bracketed.args.is_empty(),
131 PathArguments::Parenthesized(_) => false,
132 }
133 }
134}
135
136ast_enum! {
David Tolnaya454c8f2018-01-07 01:01:10 -0800137 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
David Tolnay461d98e2018-01-07 11:07:19 -0800138 ///
139 /// *This type is available if Syn is built with the `"derive"` or `"full"`
140 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800141 pub enum GenericArgument {
David Tolnaye826d812018-01-06 23:59:39 -0800142 /// A lifetime argument.
David Tolnay056de302018-01-05 14:29:05 -0800143 Lifetime(Lifetime),
David Tolnaye826d812018-01-06 23:59:39 -0800144 /// A type argument.
David Tolnay056de302018-01-05 14:29:05 -0800145 Type(Type),
David Tolnayc0435192018-01-07 11:46:08 -0800146 /// A binding (equality constraint) on an associated type: the `Item =
147 /// u8` in `Iterator<Item = u8>`.
David Tolnay056de302018-01-05 14:29:05 -0800148 Binding(Binding),
David Tolnaye826d812018-01-06 23:59:39 -0800149 /// A const expression. Must be inside of a block.
David Tolnay056de302018-01-05 14:29:05 -0800150 ///
151 /// NOTE: Identity expressions are represented as Type arguments, as
152 /// they are indistinguishable syntactically.
153 Const(Expr),
154 }
155}
156
157ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800158 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
159 /// V>`.
David Tolnay461d98e2018-01-07 11:07:19 -0800160 ///
161 /// *This type is available if Syn is built with the `"derive"` or `"full"`
162 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800163 pub struct AngleBracketedGenericArguments {
164 pub colon2_token: Option<Token![::]>,
165 pub lt_token: Token![<],
166 pub args: Punctuated<GenericArgument, Token![,]>,
167 pub gt_token: Token![>],
168 }
169}
170
171ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800172 /// A binding (equality constraint) on an associated type: `Item = u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800173 ///
174 /// *This type is available if Syn is built with the `"derive"` or `"full"`
175 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800176 pub struct Binding {
177 pub ident: Ident,
178 pub eq_token: Token![=],
179 pub ty: Type,
180 }
181}
182
183ast_struct! {
David Tolnayc0435192018-01-07 11:46:08 -0800184 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
185 /// C`.
David Tolnay461d98e2018-01-07 11:07:19 -0800186 ///
187 /// *This type is available if Syn is built with the `"derive"` or `"full"`
188 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800189 pub struct ParenthesizedGenericArguments {
190 pub paren_token: token::Paren,
191 /// `(A, B)`
192 pub inputs: Punctuated<Type, Token![,]>,
193 /// `C`
194 pub output: ReturnType,
195 }
196}
197
198ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800199 /// The explicit Self type in a qualified path: the `T` in `<T as
David Tolnay05658502018-01-07 09:56:37 -0800200 /// Display>::fmt`.
David Tolnaye826d812018-01-06 23:59:39 -0800201 ///
202 /// The actual path, including the trait and the associated item, is stored
203 /// separately. The `position` field represents the index of the associated
David Tolnay056de302018-01-05 14:29:05 -0800204 /// item qualified with this Self type.
205 ///
206 /// ```text
207 /// <Vec<T> as a::b::Trait>::AssociatedItem
208 /// ^~~~~~ ~~~~~~~~~~~~~~^
209 /// ty position = 3
210 ///
211 /// <Vec<T>>::AssociatedItem
212 /// ^~~~~~ ^
213 /// ty position = 0
214 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800215 ///
216 /// *This type is available if Syn is built with the `"derive"` or `"full"`
217 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800218 pub struct QSelf {
219 pub lt_token: Token![<],
220 pub ty: Box<Type>,
221 pub position: usize,
222 pub as_token: Option<Token![as]>,
223 pub gt_token: Token![>],
224 }
225}
226
227#[cfg(feature = "parsing")]
228pub mod parsing {
229 use super::*;
David Tolnay4fb71232018-08-25 23:14:50 -0400230 use parse::{Parse, ParseStream, Result};
231 use synom::ext::IdentExt;
David Tolnay056de302018-01-05 14:29:05 -0800232
David Tolnay4fb71232018-08-25 23:14:50 -0400233 impl Parse for Path {
234 fn parse(input: ParseStream) -> Result<Self> {
235 if input.peek(Token![dyn]) {
236 return Err(input.error("expected path"));
237 }
238
239 Ok(Path {
240 leading_colon: input.parse()?,
241 segments: input.parse_synom(Punctuated::parse_separated_nonempty)?,
David Tolnay056de302018-01-05 14:29:05 -0800242 })
David Tolnay056de302018-01-05 14:29:05 -0800243 }
244 }
245
David Tolnay4fb71232018-08-25 23:14:50 -0400246 impl Parse for GenericArgument {
247 fn parse(input: ParseStream) -> Result<Self> {
248 if input.peek(Lifetime) && !input.peek3(Token![+]) {
249 return Ok(GenericArgument::Lifetime(input.parse()?));
250 }
David Tolnay056de302018-01-05 14:29:05 -0800251
David Tolnay4fb71232018-08-25 23:14:50 -0400252 if input.peek(Ident) && input.peek2(Token![=]) {
253 return Ok(GenericArgument::Binding(input.parse()?));
254 }
David Tolnay056de302018-01-05 14:29:05 -0800255
David Tolnay4fb71232018-08-25 23:14:50 -0400256 #[cfg(feature = "full")]
257 {
258 if input.peek(Lit) {
259 let lit = input.parse_synom(ExprLit::parse)?;
260 return Ok(GenericArgument::Const(Expr::Lit(lit)));
261 }
262
263 if input.peek(token::Brace) {
264 let block = input.parse_synom(ExprBlock::parse)?;
265 return Ok(GenericArgument::Const(Expr::Block(block)));
266 }
267 }
268
269 Ok(GenericArgument::Type(input.parse_synom(ty_no_eq_after)?))
David Tolnay056de302018-01-05 14:29:05 -0800270 }
271 }
272
David Tolnay4fb71232018-08-25 23:14:50 -0400273 impl Parse for AngleBracketedGenericArguments {
274 fn parse(input: ParseStream) -> Result<Self> {
275 Ok(AngleBracketedGenericArguments {
276 colon2_token: input.parse()?,
277 lt_token: input.parse()?,
278 args: {
279 let mut args = Punctuated::new();
280 loop {
281 if input.peek(Token![>]) {
282 break;
283 }
284 let value = input.parse()?;
285 args.push_value(value);
286 if input.peek(Token![>]) {
287 break;
288 }
289 let punct = input.parse()?;
290 args.push_punct(punct);
291 }
292 args
293 },
294 gt_token: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800295 })
David Tolnay056de302018-01-05 14:29:05 -0800296 }
297 }
298
David Tolnay4fb71232018-08-25 23:14:50 -0400299 impl Parse for ParenthesizedGenericArguments {
300 fn parse(input: ParseStream) -> Result<Self> {
301 let content;
302 Ok(ParenthesizedGenericArguments {
303 paren_token: parenthesized!(content in input),
304 inputs: content.parse_synom(Punctuated::parse_terminated)?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400305 output: input.call(ReturnType::without_plus)?,
David Tolnay056de302018-01-05 14:29:05 -0800306 })
David Tolnay056de302018-01-05 14:29:05 -0800307 }
308 }
309
David Tolnay4fb71232018-08-25 23:14:50 -0400310 impl Parse for PathSegment {
311 fn parse(input: ParseStream) -> Result<Self> {
312 if input.peek(Token![super])
313 || input.peek(Token![self])
314 || input.peek(Token![Self])
315 || input.peek(Token![crate])
316 || input.peek(Token![extern])
317 {
318 let ident = input.parse_synom(Ident::parse_any)?;
319 return Ok(PathSegment::from(ident));
320 }
321
322 let ident = input.parse()?;
David Tolnaya7d69fc2018-08-26 13:30:24 -0400323 if input.peek(Token![<]) && !input.peek(Token![<=])
David Tolnay4fb71232018-08-25 23:14:50 -0400324 || input.peek(Token![::]) && input.peek3(Token![<])
325 {
326 Ok(PathSegment {
David Tolnay056de302018-01-05 14:29:05 -0800327 ident: ident,
David Tolnay4fb71232018-08-25 23:14:50 -0400328 arguments: PathArguments::AngleBracketed(input.parse()?),
David Tolnay056de302018-01-05 14:29:05 -0800329 })
David Tolnay4fb71232018-08-25 23:14:50 -0400330 } else {
331 Ok(PathSegment::from(ident))
332 }
David Tolnay056de302018-01-05 14:29:05 -0800333 }
334 }
335
David Tolnay4fb71232018-08-25 23:14:50 -0400336 impl Parse for Binding {
337 fn parse(input: ParseStream) -> Result<Self> {
338 Ok(Binding {
339 ident: input.parse()?,
340 eq_token: input.parse()?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400341 ty: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800342 })
David Tolnay056de302018-01-05 14:29:05 -0800343 }
344 }
345
346 impl Path {
David Tolnaya7d69fc2018-08-26 13:30:24 -0400347 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
348 Ok(Path {
349 leading_colon: input.parse()?,
350 segments: {
351 let mut segments = Punctuated::new();
352 loop {
353 if !input.peek(Ident)
354 && !input.peek(Token![super])
355 && !input.peek(Token![self])
356 && !input.peek(Token![Self])
357 && !input.peek(Token![crate])
358 && !input.peek(Token![extern])
359 {
360 break;
361 }
362 let ident = Ident::parse_any2(input)?;
363 segments.push_value(PathSegment::from(ident));
364 if !input.peek(Token![::]) {
365 break;
366 }
367 let punct = input.parse()?;
368 segments.push_punct(punct);
369 }
370 if segments.is_empty() {
371 return Err(input.error("expected path"));
372 } else if segments.trailing_punct() {
373 return Err(input.error("expected path segment"));
374 }
375 segments
376 },
377 })
378 }
379
380 named!(pub old_parse_mod_style -> Self, do_parse!(
David Tolnay056de302018-01-05 14:29:05 -0800381 colon: option!(punct!(::)) >>
382 segments: call!(Punctuated::parse_separated_nonempty_with,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400383 old_mod_style_path_segment) >>
David Tolnay056de302018-01-05 14:29:05 -0800384 (Path {
385 leading_colon: colon,
386 segments: segments,
387 })
388 ));
389 }
390
David Tolnaya7d69fc2018-08-26 13:30:24 -0400391 // FIXME
392 /*
393 pub fn mod_style_path_segment(input: ParseStream) -> Result<PathSegment> {
394 let lookahead = input.lookahead1();
395 let ident = if lookahead.peek(Ident) {
396 input.parse()?
397 } else if lookahead.peek(Token![super]) {
398 Ident::from(input.parse::<Token![super]>()?)
399 } else if lookahead.peek(Token![self]) {
400 Ident::from(input.parse::<Token![self]>()?)
401 } else if lookahead.peek(Token![Self]) {
402 Ident::from(input.parse::<Token![Self]>()?)
403 } else if lookahead.peek(Token![crate]) {
404 Ident::from(input.parse::<Token![crate]>()?)
405 } else if lookahead.peek(Token![extern]) {
406 Ident::from(input.parse::<Token![extern]>()?)
407 } else {
408 return Err(lookahead.error());
409 };
410 Ok(PathSegment::from(ident))
411 }
412 */
413
414 named!(pub old_mod_style_path_segment -> PathSegment, alt!(
David Tolnay056de302018-01-05 14:29:05 -0800415 syn!(Ident) => { Into::into }
416 |
417 keyword!(super) => { Into::into }
418 |
419 keyword!(self) => { Into::into }
420 |
421 keyword!(Self) => { Into::into }
422 |
423 keyword!(crate) => { Into::into }
David Tolnay0a4d4e92018-07-21 15:31:45 -0700424 |
425 keyword!(extern) => { Into::into }
David Tolnay056de302018-01-05 14:29:05 -0800426 ));
427
David Tolnay056de302018-01-05 14:29:05 -0800428 named!(pub ty_no_eq_after -> Type, do_parse!(
429 ty: syn!(Type) >>
430 not!(punct!(=)) >>
431 (ty)
432 ));
433}
434
435#[cfg(feature = "printing")]
436mod printing {
437 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700438 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700439 use quote::ToTokens;
David Tolnay056de302018-01-05 14:29:05 -0800440
441 impl ToTokens for Path {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700442 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800443 self.leading_colon.to_tokens(tokens);
444 self.segments.to_tokens(tokens);
445 }
446 }
447
448 impl ToTokens for PathSegment {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700449 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800450 self.ident.to_tokens(tokens);
451 self.arguments.to_tokens(tokens);
452 }
453 }
454
455 impl ToTokens for PathArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700456 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800457 match *self {
458 PathArguments::None => {}
459 PathArguments::AngleBracketed(ref arguments) => {
460 arguments.to_tokens(tokens);
461 }
462 PathArguments::Parenthesized(ref arguments) => {
463 arguments.to_tokens(tokens);
464 }
465 }
466 }
467 }
468
469 impl ToTokens for GenericArgument {
470 #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
Alex Crichtona74a1c82018-05-16 10:20:44 -0700471 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800472 match *self {
473 GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
474 GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
475 GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
476 GenericArgument::Const(ref e) => match *e {
477 Expr::Lit(_) => e.to_tokens(tokens),
478
479 // NOTE: We should probably support parsing blocks with only
480 // expressions in them without the full feature for const
481 // generics.
482 #[cfg(feature = "full")]
483 Expr::Block(_) => e.to_tokens(tokens),
484
485 // ERROR CORRECTION: Add braces to make sure that the
486 // generated code is valid.
487 _ => token::Brace::default().surround(tokens, |tokens| {
488 e.to_tokens(tokens);
489 }),
490 },
491 }
492 }
493 }
494
495 impl ToTokens for AngleBracketedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700496 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800497 self.colon2_token.to_tokens(tokens);
498 self.lt_token.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800499
500 // Print lifetimes before types and consts, all before bindings,
501 // regardless of their order in self.args.
502 //
503 // TODO: ordering rules for const arguments vs type arguments have
504 // not been settled yet. https://github.com/rust-lang/rust/issues/44580
505 let mut trailing_or_empty = true;
506 for param in self.args.pairs() {
507 if let GenericArgument::Lifetime(_) = **param.value() {
508 param.to_tokens(tokens);
509 trailing_or_empty = param.punct().is_some();
510 }
511 }
512 for param in self.args.pairs() {
513 match **param.value() {
514 GenericArgument::Type(_) | GenericArgument::Const(_) => {
515 if !trailing_or_empty {
516 <Token![,]>::default().to_tokens(tokens);
517 }
518 param.to_tokens(tokens);
519 trailing_or_empty = param.punct().is_some();
520 }
521 GenericArgument::Lifetime(_) | GenericArgument::Binding(_) => {}
522 }
523 }
524 for param in self.args.pairs() {
525 if let GenericArgument::Binding(_) = **param.value() {
526 if !trailing_or_empty {
527 <Token![,]>::default().to_tokens(tokens);
528 trailing_or_empty = true;
529 }
530 param.to_tokens(tokens);
531 }
532 }
533
David Tolnay056de302018-01-05 14:29:05 -0800534 self.gt_token.to_tokens(tokens);
535 }
536 }
537
538 impl ToTokens for Binding {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700539 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800540 self.ident.to_tokens(tokens);
541 self.eq_token.to_tokens(tokens);
542 self.ty.to_tokens(tokens);
543 }
544 }
545
546 impl ToTokens for ParenthesizedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700547 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800548 self.paren_token.surround(tokens, |tokens| {
549 self.inputs.to_tokens(tokens);
550 });
551 self.output.to_tokens(tokens);
552 }
553 }
David Tolnay05658502018-01-07 09:56:37 -0800554
555 impl<'a> ToTokens for PathTokens<'a> {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700556 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay05658502018-01-07 09:56:37 -0800557 let qself = match *self.0 {
558 Some(ref qself) => qself,
559 None => return self.1.to_tokens(tokens),
560 };
561 qself.lt_token.to_tokens(tokens);
562 qself.ty.to_tokens(tokens);
563
564 // XXX: Gross.
565 let pos = if qself.position > 0 && qself.position >= self.1.segments.len() {
566 self.1.segments.len() - 1
567 } else {
568 qself.position
569 };
570 let mut segments = self.1.segments.pairs();
571 if pos > 0 {
572 TokensOrDefault(&qself.as_token).to_tokens(tokens);
573 self.1.leading_colon.to_tokens(tokens);
574 for (i, segment) in segments.by_ref().take(pos).enumerate() {
575 if i + 1 == pos {
576 segment.value().to_tokens(tokens);
577 qself.gt_token.to_tokens(tokens);
578 segment.punct().to_tokens(tokens);
579 } else {
580 segment.to_tokens(tokens);
581 }
582 }
583 } else {
584 qself.gt_token.to_tokens(tokens);
585 self.1.leading_colon.to_tokens(tokens);
586 }
587 for segment in segments {
588 segment.to_tokens(tokens);
589 }
590 }
591 }
David Tolnay056de302018-01-05 14:29:05 -0800592}