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