Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/macros/helpers.rs
49410 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
use proc_macro::{token_stream, Group, Ident, TokenStream, TokenTree};
4
5
pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
6
if let Some(TokenTree::Ident(ident)) = it.next() {
7
Some(ident.to_string())
8
} else {
9
None
10
}
11
}
12
13
pub(crate) fn try_sign(it: &mut token_stream::IntoIter) -> Option<char> {
14
let peek = it.clone().next();
15
match peek {
16
Some(TokenTree::Punct(punct)) if punct.as_char() == '-' => {
17
let _ = it.next();
18
Some(punct.as_char())
19
}
20
_ => None,
21
}
22
}
23
24
pub(crate) fn try_literal(it: &mut token_stream::IntoIter) -> Option<String> {
25
if let Some(TokenTree::Literal(literal)) = it.next() {
26
Some(literal.to_string())
27
} else {
28
None
29
}
30
}
31
32
pub(crate) fn try_string(it: &mut token_stream::IntoIter) -> Option<String> {
33
try_literal(it).and_then(|string| {
34
if string.starts_with('\"') && string.ends_with('\"') {
35
let content = &string[1..string.len() - 1];
36
if content.contains('\\') {
37
panic!("Escape sequences in string literals not yet handled");
38
}
39
Some(content.to_string())
40
} else if string.starts_with("r\"") {
41
panic!("Raw string literals are not yet handled");
42
} else {
43
None
44
}
45
})
46
}
47
48
pub(crate) fn expect_ident(it: &mut token_stream::IntoIter) -> String {
49
try_ident(it).expect("Expected Ident")
50
}
51
52
pub(crate) fn expect_punct(it: &mut token_stream::IntoIter) -> char {
53
if let TokenTree::Punct(punct) = it.next().expect("Reached end of token stream for Punct") {
54
punct.as_char()
55
} else {
56
panic!("Expected Punct");
57
}
58
}
59
60
pub(crate) fn expect_string(it: &mut token_stream::IntoIter) -> String {
61
try_string(it).expect("Expected string")
62
}
63
64
pub(crate) fn expect_string_ascii(it: &mut token_stream::IntoIter) -> String {
65
let string = try_string(it).expect("Expected string");
66
assert!(string.is_ascii(), "Expected ASCII string");
67
string
68
}
69
70
pub(crate) fn expect_group(it: &mut token_stream::IntoIter) -> Group {
71
if let TokenTree::Group(group) = it.next().expect("Reached end of token stream for Group") {
72
group
73
} else {
74
panic!("Expected Group");
75
}
76
}
77
78
pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {
79
if it.next().is_some() {
80
panic!("Expected end");
81
}
82
}
83
84
/// Given a function declaration, finds the name of the function.
85
pub(crate) fn function_name(input: TokenStream) -> Option<Ident> {
86
let mut input = input.into_iter();
87
while let Some(token) = input.next() {
88
match token {
89
TokenTree::Ident(i) if i.to_string() == "fn" => {
90
if let Some(TokenTree::Ident(i)) = input.next() {
91
return Some(i);
92
}
93
return None;
94
}
95
_ => continue,
96
}
97
}
98
None
99
}
100
101
pub(crate) fn file() -> String {
102
#[cfg(not(CONFIG_RUSTC_HAS_SPAN_FILE))]
103
{
104
proc_macro::Span::call_site()
105
.source_file()
106
.path()
107
.to_string_lossy()
108
.into_owned()
109
}
110
111
#[cfg(CONFIG_RUSTC_HAS_SPAN_FILE)]
112
#[allow(clippy::incompatible_msrv)]
113
{
114
proc_macro::Span::call_site().file()
115
}
116
}
117
118
/// Parse a token stream of the form `expected_name: "value",` and return the
119
/// string in the position of "value".
120
///
121
/// # Panics
122
///
123
/// - On parse error.
124
pub(crate) fn expect_string_field(it: &mut token_stream::IntoIter, expected_name: &str) -> String {
125
assert_eq!(expect_ident(it), expected_name);
126
assert_eq!(expect_punct(it), ':');
127
let string = expect_string(it);
128
assert_eq!(expect_punct(it), ',');
129
string
130
}
131
132