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