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