1 use super::*; 2 use punctuated::Punctuated; 3 4 ast_struct! { 5 /// A path at which a named item is exported: `std::collections::HashMap`. 6 /// 7 /// *This type is available if Syn is built with the `"derive"` or `"full"` 8 /// feature.* 9 pub struct Path { 10 pub leading_colon: Option<Token![::]>, 11 pub segments: Punctuated<PathSegment, Token![::]>, 12 } 13 } 14 15 impl<T> From<T> for Path 16 where 17 T: Into<PathSegment>, 18 { from(segment: T) -> Self19 fn from(segment: T) -> Self { 20 let mut path = Path { 21 leading_colon: None, 22 segments: Punctuated::new(), 23 }; 24 path.segments.push_value(segment.into()); 25 path 26 } 27 } 28 29 ast_struct! { 30 /// A segment of a path together with any path arguments on that segment. 31 /// 32 /// *This type is available if Syn is built with the `"derive"` or `"full"` 33 /// feature.* 34 pub struct PathSegment { 35 pub ident: Ident, 36 pub arguments: PathArguments, 37 } 38 } 39 40 impl<T> From<T> for PathSegment 41 where 42 T: Into<Ident>, 43 { from(ident: T) -> Self44 fn from(ident: T) -> Self { 45 PathSegment { 46 ident: ident.into(), 47 arguments: PathArguments::None, 48 } 49 } 50 } 51 52 ast_enum! { 53 /// Angle bracketed or parenthesized arguments of a path segment. 54 /// 55 /// *This type is available if Syn is built with the `"derive"` or `"full"` 56 /// feature.* 57 /// 58 /// ## Angle bracketed 59 /// 60 /// The `<'a, T>` in `std::slice::iter<'a, T>`. 61 /// 62 /// ## Parenthesized 63 /// 64 /// The `(A, B) -> C` in `Fn(A, B) -> C`. 65 pub enum PathArguments { 66 None, 67 /// The `<'a, T>` in `std::slice::iter<'a, T>`. 68 AngleBracketed(AngleBracketedGenericArguments), 69 /// The `(A, B) -> C` in `Fn(A, B) -> C`. 70 Parenthesized(ParenthesizedGenericArguments), 71 } 72 } 73 74 impl Default for PathArguments { default() -> Self75 fn default() -> Self { 76 PathArguments::None 77 } 78 } 79 80 impl PathArguments { is_empty(&self) -> bool81 pub fn is_empty(&self) -> bool { 82 match *self { 83 PathArguments::None => true, 84 PathArguments::AngleBracketed(ref bracketed) => bracketed.args.is_empty(), 85 PathArguments::Parenthesized(_) => false, 86 } 87 } 88 89 #[cfg(feature = "parsing")] is_none(&self) -> bool90 fn is_none(&self) -> bool { 91 match *self { 92 PathArguments::None => true, 93 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false, 94 } 95 } 96 } 97 98 ast_enum! { 99 /// An individual generic argument, like `'a`, `T`, or `Item = T`. 100 /// 101 /// *This type is available if Syn is built with the `"derive"` or `"full"` 102 /// feature.* 103 pub enum GenericArgument { 104 /// A lifetime argument. 105 Lifetime(Lifetime), 106 /// A type argument. 107 Type(Type), 108 /// A binding (equality constraint) on an associated type: the `Item = 109 /// u8` in `Iterator<Item = u8>`. 110 Binding(Binding), 111 /// An associated type bound: `Iterator<Item: Display>`. 112 Constraint(Constraint), 113 /// A const expression. Must be inside of a block. 114 /// 115 /// NOTE: Identity expressions are represented as Type arguments, as 116 /// they are indistinguishable syntactically. 117 Const(Expr), 118 } 119 } 120 121 ast_struct! { 122 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K, 123 /// V>`. 124 /// 125 /// *This type is available if Syn is built with the `"derive"` or `"full"` 126 /// feature.* 127 pub struct AngleBracketedGenericArguments { 128 pub colon2_token: Option<Token![::]>, 129 pub lt_token: Token![<], 130 pub args: Punctuated<GenericArgument, Token![,]>, 131 pub gt_token: Token![>], 132 } 133 } 134 135 ast_struct! { 136 /// A binding (equality constraint) on an associated type: `Item = u8`. 137 /// 138 /// *This type is available if Syn is built with the `"derive"` or `"full"` 139 /// feature.* 140 pub struct Binding { 141 pub ident: Ident, 142 pub eq_token: Token![=], 143 pub ty: Type, 144 } 145 } 146 147 ast_struct! { 148 /// An associated type bound: `Iterator<Item: Display>`. 149 /// 150 /// *This type is available if Syn is built with the `"derive"` or `"full"` 151 /// feature.* 152 pub struct Constraint { 153 pub ident: Ident, 154 pub colon_token: Token![:], 155 pub bounds: Punctuated<TypeParamBound, Token![+]>, 156 } 157 } 158 159 ast_struct! { 160 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) -> 161 /// C`. 162 /// 163 /// *This type is available if Syn is built with the `"derive"` or `"full"` 164 /// feature.* 165 pub struct ParenthesizedGenericArguments { 166 pub paren_token: token::Paren, 167 /// `(A, B)` 168 pub inputs: Punctuated<Type, Token![,]>, 169 /// `C` 170 pub output: ReturnType, 171 } 172 } 173 174 ast_struct! { 175 /// The explicit Self type in a qualified path: the `T` in `<T as 176 /// Display>::fmt`. 177 /// 178 /// The actual path, including the trait and the associated item, is stored 179 /// separately. The `position` field represents the index of the associated 180 /// item qualified with this Self type. 181 /// 182 /// ```text 183 /// <Vec<T> as a::b::Trait>::AssociatedItem 184 /// ^~~~~~ ~~~~~~~~~~~~~~^ 185 /// ty position = 3 186 /// 187 /// <Vec<T>>::AssociatedItem 188 /// ^~~~~~ ^ 189 /// ty position = 0 190 /// ``` 191 /// 192 /// *This type is available if Syn is built with the `"derive"` or `"full"` 193 /// feature.* 194 pub struct QSelf { 195 pub lt_token: Token![<], 196 pub ty: Box<Type>, 197 pub position: usize, 198 pub as_token: Option<Token![as]>, 199 pub gt_token: Token![>], 200 } 201 } 202 203 #[cfg(feature = "parsing")] 204 pub mod parsing { 205 use super::*; 206 207 #[cfg(feature = "full")] 208 use expr; 209 use ext::IdentExt; 210 use parse::{Parse, ParseStream, Result}; 211 212 impl Parse for Path { parse(input: ParseStream) -> Result<Self>213 fn parse(input: ParseStream) -> Result<Self> { 214 Self::parse_helper(input, false) 215 } 216 } 217 218 impl Parse for GenericArgument { parse(input: ParseStream) -> Result<Self>219 fn parse(input: ParseStream) -> Result<Self> { 220 if input.peek(Lifetime) && !input.peek2(Token![+]) { 221 return Ok(GenericArgument::Lifetime(input.parse()?)); 222 } 223 224 if input.peek(Ident) && input.peek2(Token![=]) { 225 return Ok(GenericArgument::Binding(input.parse()?)); 226 } 227 228 #[cfg(feature = "full")] 229 { 230 if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) { 231 return Ok(GenericArgument::Constraint(input.parse()?)); 232 } 233 234 if input.peek(Lit) { 235 let lit = input.parse()?; 236 return Ok(GenericArgument::Const(Expr::Lit(lit))); 237 } 238 239 if input.peek(token::Brace) { 240 let block = input.call(expr::parsing::expr_block)?; 241 return Ok(GenericArgument::Const(Expr::Block(block))); 242 } 243 } 244 245 input.parse().map(GenericArgument::Type) 246 } 247 } 248 249 impl Parse for AngleBracketedGenericArguments { parse(input: ParseStream) -> Result<Self>250 fn parse(input: ParseStream) -> Result<Self> { 251 Ok(AngleBracketedGenericArguments { 252 colon2_token: input.parse()?, 253 lt_token: input.parse()?, 254 args: { 255 let mut args = Punctuated::new(); 256 loop { 257 if input.peek(Token![>]) { 258 break; 259 } 260 let value = input.parse()?; 261 args.push_value(value); 262 if input.peek(Token![>]) { 263 break; 264 } 265 let punct = input.parse()?; 266 args.push_punct(punct); 267 } 268 args 269 }, 270 gt_token: input.parse()?, 271 }) 272 } 273 } 274 275 impl Parse for ParenthesizedGenericArguments { parse(input: ParseStream) -> Result<Self>276 fn parse(input: ParseStream) -> Result<Self> { 277 let content; 278 Ok(ParenthesizedGenericArguments { 279 paren_token: parenthesized!(content in input), 280 inputs: content.parse_terminated(Type::parse)?, 281 output: input.call(ReturnType::without_plus)?, 282 }) 283 } 284 } 285 286 impl Parse for PathSegment { parse(input: ParseStream) -> Result<Self>287 fn parse(input: ParseStream) -> Result<Self> { 288 Self::parse_helper(input, false) 289 } 290 } 291 292 impl PathSegment { parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>293 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 294 if input.peek(Token![super]) 295 || input.peek(Token![self]) 296 || input.peek(Token![crate]) 297 || input.peek(Token![extern]) 298 { 299 let ident = input.call(Ident::parse_any)?; 300 return Ok(PathSegment::from(ident)); 301 } 302 303 let ident = if input.peek(Token![Self]) { 304 input.call(Ident::parse_any)? 305 } else { 306 input.parse()? 307 }; 308 309 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=]) 310 || input.peek(Token![::]) && input.peek3(Token![<]) 311 { 312 Ok(PathSegment { 313 ident: ident, 314 arguments: PathArguments::AngleBracketed(input.parse()?), 315 }) 316 } else { 317 Ok(PathSegment::from(ident)) 318 } 319 } 320 } 321 322 impl Parse for Binding { parse(input: ParseStream) -> Result<Self>323 fn parse(input: ParseStream) -> Result<Self> { 324 Ok(Binding { 325 ident: input.parse()?, 326 eq_token: input.parse()?, 327 ty: input.parse()?, 328 }) 329 } 330 } 331 332 #[cfg(feature = "full")] 333 impl Parse for Constraint { parse(input: ParseStream) -> Result<Self>334 fn parse(input: ParseStream) -> Result<Self> { 335 Ok(Constraint { 336 ident: input.parse()?, 337 colon_token: input.parse()?, 338 bounds: { 339 let mut bounds = Punctuated::new(); 340 loop { 341 if input.peek(Token![,]) || input.peek(Token![>]) { 342 break; 343 } 344 let value = input.parse()?; 345 bounds.push_value(value); 346 if !input.peek(Token![+]) { 347 break; 348 } 349 let punct = input.parse()?; 350 bounds.push_punct(punct); 351 } 352 bounds 353 }, 354 }) 355 } 356 } 357 358 impl Path { 359 /// Parse a `Path` containing no path arguments on any of its segments. 360 /// 361 /// *This function is available if Syn is built with the `"parsing"` 362 /// feature.* 363 /// 364 /// # Example 365 /// 366 /// ```edition2018 367 /// use syn::{Path, Result, Token}; 368 /// use syn::parse::{Parse, ParseStream}; 369 /// 370 /// // A simplified single `use` statement like: 371 /// // 372 /// // use std::collections::HashMap; 373 /// // 374 /// // Note that generic parameters are not allowed in a `use` statement 375 /// // so the following must not be accepted. 376 /// // 377 /// // use a::<b>::c; 378 /// struct SingleUse { 379 /// use_token: Token![use], 380 /// path: Path, 381 /// } 382 /// 383 /// impl Parse for SingleUse { 384 /// fn parse(input: ParseStream) -> Result<Self> { 385 /// Ok(SingleUse { 386 /// use_token: input.parse()?, 387 /// path: input.call(Path::parse_mod_style)?, 388 /// }) 389 /// } 390 /// } 391 /// ``` parse_mod_style(input: ParseStream) -> Result<Self>392 pub fn parse_mod_style(input: ParseStream) -> Result<Self> { 393 Ok(Path { 394 leading_colon: input.parse()?, 395 segments: { 396 let mut segments = Punctuated::new(); 397 loop { 398 if !input.peek(Ident) 399 && !input.peek(Token![super]) 400 && !input.peek(Token![self]) 401 && !input.peek(Token![Self]) 402 && !input.peek(Token![crate]) 403 && !input.peek(Token![extern]) 404 { 405 break; 406 } 407 let ident = Ident::parse_any(input)?; 408 segments.push_value(PathSegment::from(ident)); 409 if !input.peek(Token![::]) { 410 break; 411 } 412 let punct = input.parse()?; 413 segments.push_punct(punct); 414 } 415 if segments.is_empty() { 416 return Err(input.error("expected path")); 417 } else if segments.trailing_punct() { 418 return Err(input.error("expected path segment")); 419 } 420 segments 421 }, 422 }) 423 } 424 425 /// Determines whether this is a path of length 1 equal to the given 426 /// ident. 427 /// 428 /// For them to compare equal, it must be the case that: 429 /// 430 /// - the path has no leading colon, 431 /// - the number of path segments is 1, 432 /// - the first path segment has no angle bracketed or parenthesized 433 /// path arguments 434 /// - and the ident of the first path segment is equal to the given one. 435 /// 436 /// *This function is available if Syn is built with the `"parsing"` 437 /// feature.* is_ident<I>(&self, ident: I) -> bool where Ident: PartialEq<I>,438 pub fn is_ident<I>(&self, ident: I) -> bool 439 where 440 Ident: PartialEq<I>, 441 { 442 self.leading_colon.is_none() 443 && self.segments.len() == 1 444 && self.segments[0].arguments.is_none() 445 && self.segments[0].ident == ident 446 } 447 parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>448 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 449 Ok(Path { 450 leading_colon: input.parse()?, 451 segments: { 452 let mut segments = Punctuated::new(); 453 let value = PathSegment::parse_helper(input, expr_style)?; 454 segments.push_value(value); 455 while input.peek(Token![::]) { 456 let punct: Token![::] = input.parse()?; 457 segments.push_punct(punct); 458 let value = PathSegment::parse_helper(input, expr_style)?; 459 segments.push_value(value); 460 } 461 segments 462 }, 463 }) 464 } 465 } 466 qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)>467 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> { 468 if input.peek(Token![<]) { 469 let lt_token: Token![<] = input.parse()?; 470 let this: Type = input.parse()?; 471 let path = if input.peek(Token![as]) { 472 let as_token: Token![as] = input.parse()?; 473 let path: Path = input.parse()?; 474 Some((as_token, path)) 475 } else { 476 None 477 }; 478 let gt_token: Token![>] = input.parse()?; 479 let colon2_token: Token![::] = input.parse()?; 480 let mut rest = Punctuated::new(); 481 loop { 482 let path = PathSegment::parse_helper(input, expr_style)?; 483 rest.push_value(path); 484 if !input.peek(Token![::]) { 485 break; 486 } 487 let punct: Token![::] = input.parse()?; 488 rest.push_punct(punct); 489 } 490 let (position, as_token, path) = match path { 491 Some((as_token, mut path)) => { 492 let pos = path.segments.len(); 493 path.segments.push_punct(colon2_token); 494 path.segments.extend(rest.into_pairs()); 495 (pos, Some(as_token), path) 496 } 497 None => { 498 let path = Path { 499 leading_colon: Some(colon2_token), 500 segments: rest, 501 }; 502 (0, None, path) 503 } 504 }; 505 let qself = QSelf { 506 lt_token: lt_token, 507 ty: Box::new(this), 508 position: position, 509 as_token: as_token, 510 gt_token: gt_token, 511 }; 512 Ok((Some(qself), path)) 513 } else { 514 let path = Path::parse_helper(input, expr_style)?; 515 Ok((None, path)) 516 } 517 } 518 } 519 520 #[cfg(feature = "printing")] 521 mod printing { 522 use super::*; 523 524 use proc_macro2::TokenStream; 525 use quote::ToTokens; 526 527 use print::TokensOrDefault; 528 529 impl ToTokens for Path { to_tokens(&self, tokens: &mut TokenStream)530 fn to_tokens(&self, tokens: &mut TokenStream) { 531 self.leading_colon.to_tokens(tokens); 532 self.segments.to_tokens(tokens); 533 } 534 } 535 536 impl ToTokens for PathSegment { to_tokens(&self, tokens: &mut TokenStream)537 fn to_tokens(&self, tokens: &mut TokenStream) { 538 self.ident.to_tokens(tokens); 539 self.arguments.to_tokens(tokens); 540 } 541 } 542 543 impl ToTokens for PathArguments { to_tokens(&self, tokens: &mut TokenStream)544 fn to_tokens(&self, tokens: &mut TokenStream) { 545 match *self { 546 PathArguments::None => {} 547 PathArguments::AngleBracketed(ref arguments) => { 548 arguments.to_tokens(tokens); 549 } 550 PathArguments::Parenthesized(ref arguments) => { 551 arguments.to_tokens(tokens); 552 } 553 } 554 } 555 } 556 557 impl ToTokens for GenericArgument { 558 #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))] to_tokens(&self, tokens: &mut TokenStream)559 fn to_tokens(&self, tokens: &mut TokenStream) { 560 match *self { 561 GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens), 562 GenericArgument::Type(ref ty) => ty.to_tokens(tokens), 563 GenericArgument::Binding(ref tb) => tb.to_tokens(tokens), 564 GenericArgument::Constraint(ref tc) => tc.to_tokens(tokens), 565 GenericArgument::Const(ref e) => match *e { 566 Expr::Lit(_) => e.to_tokens(tokens), 567 568 // NOTE: We should probably support parsing blocks with only 569 // expressions in them without the full feature for const 570 // generics. 571 #[cfg(feature = "full")] 572 Expr::Block(_) => e.to_tokens(tokens), 573 574 // ERROR CORRECTION: Add braces to make sure that the 575 // generated code is valid. 576 _ => token::Brace::default().surround(tokens, |tokens| { 577 e.to_tokens(tokens); 578 }), 579 }, 580 } 581 } 582 } 583 584 impl ToTokens for AngleBracketedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)585 fn to_tokens(&self, tokens: &mut TokenStream) { 586 self.colon2_token.to_tokens(tokens); 587 self.lt_token.to_tokens(tokens); 588 589 // Print lifetimes before types and consts, all before bindings, 590 // regardless of their order in self.args. 591 // 592 // TODO: ordering rules for const arguments vs type arguments have 593 // not been settled yet. https://github.com/rust-lang/rust/issues/44580 594 let mut trailing_or_empty = true; 595 for param in self.args.pairs() { 596 match **param.value() { 597 GenericArgument::Lifetime(_) => { 598 param.to_tokens(tokens); 599 trailing_or_empty = param.punct().is_some(); 600 } 601 GenericArgument::Type(_) 602 | GenericArgument::Binding(_) 603 | GenericArgument::Constraint(_) 604 | GenericArgument::Const(_) => {} 605 } 606 } 607 for param in self.args.pairs() { 608 match **param.value() { 609 GenericArgument::Type(_) | GenericArgument::Const(_) => { 610 if !trailing_or_empty { 611 <Token![,]>::default().to_tokens(tokens); 612 } 613 param.to_tokens(tokens); 614 trailing_or_empty = param.punct().is_some(); 615 } 616 GenericArgument::Lifetime(_) 617 | GenericArgument::Binding(_) 618 | GenericArgument::Constraint(_) => {} 619 } 620 } 621 for param in self.args.pairs() { 622 match **param.value() { 623 GenericArgument::Binding(_) | GenericArgument::Constraint(_) => { 624 if !trailing_or_empty { 625 <Token![,]>::default().to_tokens(tokens); 626 trailing_or_empty = true; 627 } 628 param.to_tokens(tokens); 629 } 630 GenericArgument::Lifetime(_) 631 | GenericArgument::Type(_) 632 | GenericArgument::Const(_) => {} 633 } 634 } 635 636 self.gt_token.to_tokens(tokens); 637 } 638 } 639 640 impl ToTokens for Binding { to_tokens(&self, tokens: &mut TokenStream)641 fn to_tokens(&self, tokens: &mut TokenStream) { 642 self.ident.to_tokens(tokens); 643 self.eq_token.to_tokens(tokens); 644 self.ty.to_tokens(tokens); 645 } 646 } 647 648 impl ToTokens for Constraint { to_tokens(&self, tokens: &mut TokenStream)649 fn to_tokens(&self, tokens: &mut TokenStream) { 650 self.ident.to_tokens(tokens); 651 self.colon_token.to_tokens(tokens); 652 self.bounds.to_tokens(tokens); 653 } 654 } 655 656 impl ToTokens for ParenthesizedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)657 fn to_tokens(&self, tokens: &mut TokenStream) { 658 self.paren_token.surround(tokens, |tokens| { 659 self.inputs.to_tokens(tokens); 660 }); 661 self.output.to_tokens(tokens); 662 } 663 } 664 665 impl private { print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path)666 pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) { 667 let qself = match *qself { 668 Some(ref qself) => qself, 669 None => { 670 path.to_tokens(tokens); 671 return; 672 } 673 }; 674 qself.lt_token.to_tokens(tokens); 675 qself.ty.to_tokens(tokens); 676 677 let pos = if qself.position > 0 && qself.position >= path.segments.len() { 678 path.segments.len() - 1 679 } else { 680 qself.position 681 }; 682 let mut segments = path.segments.pairs(); 683 if pos > 0 { 684 TokensOrDefault(&qself.as_token).to_tokens(tokens); 685 path.leading_colon.to_tokens(tokens); 686 for (i, segment) in segments.by_ref().take(pos).enumerate() { 687 if i + 1 == pos { 688 segment.value().to_tokens(tokens); 689 qself.gt_token.to_tokens(tokens); 690 segment.punct().to_tokens(tokens); 691 } else { 692 segment.to_tokens(tokens); 693 } 694 } 695 } else { 696 qself.gt_token.to_tokens(tokens); 697 path.leading_colon.to_tokens(tokens); 698 } 699 for segment in segments { 700 segment.to_tokens(tokens); 701 } 702 } 703 } 704 } 705