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