ext.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // SPDX-License-Identifier: Apache-2.0 OR MIT
  2. //! Extension traits to provide parsing methods on foreign types.
  3. use crate::buffer::Cursor;
  4. use crate::error::Result;
  5. use crate::parse::ParseStream;
  6. use crate::parse::Peek;
  7. use crate::sealed::lookahead;
  8. use crate::token::CustomToken;
  9. use proc_macro2::Ident;
  10. /// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro.
  11. ///
  12. /// This trait is sealed and cannot be implemented for types outside of Syn. It
  13. /// is implemented only for `proc_macro2::Ident`.
  14. pub trait IdentExt: Sized + private::Sealed {
  15. /// Parses any identifier including keywords.
  16. ///
  17. /// This is useful when parsing macro input which allows Rust keywords as
  18. /// identifiers.
  19. ///
  20. /// # Example
  21. ///
  22. /// ```
  23. /// use syn::{Error, Ident, Result, Token};
  24. /// use syn::ext::IdentExt;
  25. /// use syn::parse::ParseStream;
  26. ///
  27. /// mod kw {
  28. /// syn::custom_keyword!(name);
  29. /// }
  30. ///
  31. /// // Parses input that looks like `name = NAME` where `NAME` can be
  32. /// // any identifier.
  33. /// //
  34. /// // Examples:
  35. /// //
  36. /// // name = anything
  37. /// // name = impl
  38. /// fn parse_dsl(input: ParseStream) -> Result<Ident> {
  39. /// input.parse::<kw::name>()?;
  40. /// input.parse::<Token![=]>()?;
  41. /// let name = input.call(Ident::parse_any)?;
  42. /// Ok(name)
  43. /// }
  44. /// ```
  45. fn parse_any(input: ParseStream) -> Result<Self>;
  46. /// Peeks any identifier including keywords. Usage:
  47. /// `input.peek(Ident::peek_any)`
  48. ///
  49. /// This is different from `input.peek(Ident)` which only returns true in
  50. /// the case of an ident which is not a Rust keyword.
  51. #[allow(non_upper_case_globals)]
  52. const peek_any: private::PeekFn = private::PeekFn;
  53. /// Strips the raw marker `r#`, if any, from the beginning of an ident.
  54. ///
  55. /// - unraw(`x`) = `x`
  56. /// - unraw(`move`) = `move`
  57. /// - unraw(`r#move`) = `move`
  58. ///
  59. /// # Example
  60. ///
  61. /// In the case of interop with other languages like Python that have a
  62. /// different set of keywords than Rust, we might come across macro input
  63. /// that involves raw identifiers to refer to ordinary variables in the
  64. /// other language with a name that happens to be a Rust keyword.
  65. ///
  66. /// The function below appends an identifier from the caller's input onto a
  67. /// fixed prefix. Without using `unraw()`, this would tend to produce
  68. /// invalid identifiers like `__pyo3_get_r#move`.
  69. ///
  70. /// ```
  71. /// use proc_macro2::Span;
  72. /// use syn::Ident;
  73. /// use syn::ext::IdentExt;
  74. ///
  75. /// fn ident_for_getter(variable: &Ident) -> Ident {
  76. /// let getter = format!("__pyo3_get_{}", variable.unraw());
  77. /// Ident::new(&getter, Span::call_site())
  78. /// }
  79. /// ```
  80. fn unraw(&self) -> Ident;
  81. }
  82. impl IdentExt for Ident {
  83. fn parse_any(input: ParseStream) -> Result<Self> {
  84. input.step(|cursor| match cursor.ident() {
  85. Some((ident, rest)) => Ok((ident, rest)),
  86. None => Err(cursor.error("expected ident")),
  87. })
  88. }
  89. fn unraw(&self) -> Ident {
  90. let string = self.to_string();
  91. if let Some(string) = string.strip_prefix("r#") {
  92. Ident::new(string, self.span())
  93. } else {
  94. self.clone()
  95. }
  96. }
  97. }
  98. impl Peek for private::PeekFn {
  99. type Token = private::IdentAny;
  100. }
  101. impl CustomToken for private::IdentAny {
  102. fn peek(cursor: Cursor) -> bool {
  103. cursor.ident().is_some()
  104. }
  105. fn display() -> &'static str {
  106. "identifier"
  107. }
  108. }
  109. impl lookahead::Sealed for private::PeekFn {}
  110. mod private {
  111. use proc_macro2::Ident;
  112. pub trait Sealed {}
  113. impl Sealed for Ident {}
  114. pub struct PeekFn;
  115. pub struct IdentAny;
  116. impl Copy for PeekFn {}
  117. impl Clone for PeekFn {
  118. fn clone(&self) -> Self {
  119. *self
  120. }
  121. }
  122. }