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