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