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