1 //! Extension traits to provide parsing methods on foreign types. 2 3 use crate::buffer::Cursor; 4 use crate::parse::Peek; 5 use crate::parse::{ParseStream, Result}; 6 use crate::sealed::lookahead; 7 use crate::token::CustomToken; 8 use proc_macro2::Ident; 9 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 /// ``` parse_any(input: ParseStream) -> Result<Self>45 fn parse_any(input: ParseStream) -> Result<Self>; 46 47 /// Peeks any identifier including keywords. Usage: 48 /// `input.peek(Ident::peek_any)` 49 /// 50 /// This is different from `input.peek(Ident)` which only returns true in 51 /// the case of an ident which is not a Rust keyword. 52 #[allow(non_upper_case_globals)] 53 const peek_any: private::PeekFn = private::PeekFn; 54 55 /// Strips the raw marker `r#`, if any, from the beginning of an ident. 56 /// 57 /// - unraw(`x`) = `x` 58 /// - unraw(`move`) = `move` 59 /// - unraw(`r#move`) = `move` 60 /// 61 /// # Example 62 /// 63 /// In the case of interop with other languages like Python that have a 64 /// different set of keywords than Rust, we might come across macro input 65 /// that involves raw identifiers to refer to ordinary variables in the 66 /// other language with a name that happens to be a Rust keyword. 67 /// 68 /// The function below appends an identifier from the caller's input onto a 69 /// fixed prefix. Without using `unraw()`, this would tend to produce 70 /// invalid identifiers like `__pyo3_get_r#move`. 71 /// 72 /// ``` 73 /// use proc_macro2::Span; 74 /// use syn::Ident; 75 /// use syn::ext::IdentExt; 76 /// 77 /// fn ident_for_getter(variable: &Ident) -> Ident { 78 /// let getter = format!("__pyo3_get_{}", variable.unraw()); 79 /// Ident::new(&getter, Span::call_site()) 80 /// } 81 /// ``` unraw(&self) -> Ident82 fn unraw(&self) -> Ident; 83 } 84 85 impl IdentExt for Ident { parse_any(input: ParseStream) -> Result<Self>86 fn parse_any(input: ParseStream) -> Result<Self> { 87 input.step(|cursor| match cursor.ident() { 88 Some((ident, rest)) => Ok((ident, rest)), 89 None => Err(cursor.error("expected ident")), 90 }) 91 } 92 unraw(&self) -> Ident93 fn unraw(&self) -> Ident { 94 let string = self.to_string(); 95 if let Some(string) = string.strip_prefix("r#") { 96 Ident::new(string, self.span()) 97 } else { 98 self.clone() 99 } 100 } 101 } 102 103 impl Peek for private::PeekFn { 104 type Token = private::IdentAny; 105 } 106 107 impl CustomToken for private::IdentAny { peek(cursor: Cursor) -> bool108 fn peek(cursor: Cursor) -> bool { 109 cursor.ident().is_some() 110 } 111 display() -> &'static str112 fn display() -> &'static str { 113 "identifier" 114 } 115 } 116 117 impl lookahead::Sealed for private::PeekFn {} 118 119 mod private { 120 use proc_macro2::Ident; 121 122 pub trait Sealed {} 123 124 impl Sealed for Ident {} 125 126 pub struct PeekFn; 127 pub struct IdentAny; 128 129 impl Copy for PeekFn {} 130 impl Clone for PeekFn { clone(&self) -> Self131 fn clone(&self) -> Self { 132 *self 133 } 134 } 135 } 136