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