Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/syn/ext.rs
38271 views
1
// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3
//! Extension traits to provide parsing methods on foreign types.
4
5
use crate::buffer::Cursor;
6
use crate::error::Result;
7
use crate::parse::ParseStream;
8
use crate::parse::Peek;
9
use crate::sealed::lookahead;
10
use crate::token::CustomToken;
11
use 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`.
17
pub 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
88
impl 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
106
impl Peek for private::PeekFn {
107
type Token = private::IdentAny;
108
}
109
110
impl 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
120
impl lookahead::Sealed for private::PeekFn {}
121
122
mod 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
}
139
140