xref: /third_party/rust/crates/syn/src/ext.rs (revision fad3a1d3)
1//! Extension traits to provide parsing methods on foreign types.
2
3use crate::buffer::Cursor;
4use crate::parse::Peek;
5use crate::parse::{ParseStream, Result};
6use crate::sealed::lookahead;
7use crate::token::CustomToken;
8use 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`.
14pub 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    /// ```
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    /// ```
82    fn unraw(&self) -> Ident;
83}
84
85impl IdentExt for Ident {
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
93    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
103impl Peek for private::PeekFn {
104    type Token = private::IdentAny;
105}
106
107impl CustomToken for private::IdentAny {
108    fn peek(cursor: Cursor) -> bool {
109        cursor.ident().is_some()
110    }
111
112    fn display() -> &'static str {
113        "identifier"
114    }
115}
116
117impl lookahead::Sealed for private::PeekFn {}
118
119mod 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 {
131        fn clone(&self) -> Self {
132            *self
133        }
134    }
135}
136