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