Skip to content

Commit 70a21e5

Browse files
nbdd0121ojeda
authored andcommitted
rust: macros: add quote! macro
Add the `quote!` macro for creating `TokenStream`s directly via the given Rust tokens. It also supports repetitions using iterators. It will be used by the pin-init API proc-macros to generate code. Signed-off-by: Gary Guo <[email protected]> Signed-off-by: Benno Lossin <[email protected]> Reviewed-by: Andreas Hindborg <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 2d19d36 commit 70a21e5

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

rust/macros/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
//! Crate for all kernel procedural macros.
44
5+
#[macro_use]
6+
mod quote;
57
mod concat_idents;
68
mod helpers;
79
mod module;

rust/macros/quote.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
3+
use proc_macro::{TokenStream, TokenTree};
4+
5+
pub(crate) trait ToTokens {
6+
fn to_tokens(&self, tokens: &mut TokenStream);
7+
}
8+
9+
impl<T: ToTokens> ToTokens for Option<T> {
10+
fn to_tokens(&self, tokens: &mut TokenStream) {
11+
if let Some(v) = self {
12+
v.to_tokens(tokens);
13+
}
14+
}
15+
}
16+
17+
impl ToTokens for proc_macro::Group {
18+
fn to_tokens(&self, tokens: &mut TokenStream) {
19+
tokens.extend([TokenTree::from(self.clone())]);
20+
}
21+
}
22+
23+
impl ToTokens for TokenTree {
24+
fn to_tokens(&self, tokens: &mut TokenStream) {
25+
tokens.extend([self.clone()]);
26+
}
27+
}
28+
29+
impl ToTokens for TokenStream {
30+
fn to_tokens(&self, tokens: &mut TokenStream) {
31+
tokens.extend(self.clone());
32+
}
33+
}
34+
35+
/// Converts tokens into [`proc_macro::TokenStream`] and performs variable interpolations with
36+
/// the given span.
37+
///
38+
/// This is a similar to the
39+
/// [`quote_spanned!`](https://docs.rs/quote/latest/quote/macro.quote_spanned.html) macro from the
40+
/// `quote` crate but provides only just enough functionality needed by the current `macros` crate.
41+
#[allow(unused_macros)]
42+
macro_rules! quote_spanned {
43+
($span:expr => $($tt:tt)*) => {
44+
#[allow(clippy::vec_init_then_push)]
45+
{
46+
let mut tokens = ::std::vec::Vec::new();
47+
let span = $span;
48+
quote_spanned!(@proc tokens span $($tt)*);
49+
::proc_macro::TokenStream::from_iter(tokens)
50+
}};
51+
(@proc $v:ident $span:ident) => {};
52+
(@proc $v:ident $span:ident #$id:ident $($tt:tt)*) => {
53+
let mut ts = ::proc_macro::TokenStream::new();
54+
$crate::quote::ToTokens::to_tokens(&$id, &mut ts);
55+
$v.extend(ts);
56+
quote_spanned!(@proc $v $span $($tt)*);
57+
};
58+
(@proc $v:ident $span:ident #(#$id:ident)* $($tt:tt)*) => {
59+
for token in $id {
60+
let mut ts = ::proc_macro::TokenStream::new();
61+
$crate::quote::ToTokens::to_tokens(&token, &mut ts);
62+
$v.extend(ts);
63+
}
64+
quote_spanned!(@proc $v $span $($tt)*);
65+
};
66+
(@proc $v:ident $span:ident ( $($inner:tt)* ) $($tt:tt)*) => {
67+
let mut tokens = ::std::vec::Vec::new();
68+
quote_spanned!(@proc tokens $span $($inner)*);
69+
$v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
70+
::proc_macro::Delimiter::Parenthesis,
71+
::proc_macro::TokenStream::from_iter(tokens)
72+
)));
73+
quote_spanned!(@proc $v $span $($tt)*);
74+
};
75+
(@proc $v:ident $span:ident [ $($inner:tt)* ] $($tt:tt)*) => {
76+
let mut tokens = ::std::vec::Vec::new();
77+
quote_spanned!(@proc tokens $span $($inner)*);
78+
$v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
79+
::proc_macro::Delimiter::Bracket,
80+
::proc_macro::TokenStream::from_iter(tokens)
81+
)));
82+
quote_spanned!(@proc $v $span $($tt)*);
83+
};
84+
(@proc $v:ident $span:ident { $($inner:tt)* } $($tt:tt)*) => {
85+
let mut tokens = ::std::vec::Vec::new();
86+
quote_spanned!(@proc tokens $span $($inner)*);
87+
$v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
88+
::proc_macro::Delimiter::Brace,
89+
::proc_macro::TokenStream::from_iter(tokens)
90+
)));
91+
quote_spanned!(@proc $v $span $($tt)*);
92+
};
93+
(@proc $v:ident $span:ident :: $($tt:tt)*) => {
94+
$v.push(::proc_macro::TokenTree::Punct(
95+
::proc_macro::Punct::new(':', ::proc_macro::Spacing::Joint)
96+
));
97+
$v.push(::proc_macro::TokenTree::Punct(
98+
::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
99+
));
100+
quote_spanned!(@proc $v $span $($tt)*);
101+
};
102+
(@proc $v:ident $span:ident : $($tt:tt)*) => {
103+
$v.push(::proc_macro::TokenTree::Punct(
104+
::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone)
105+
));
106+
quote_spanned!(@proc $v $span $($tt)*);
107+
};
108+
(@proc $v:ident $span:ident , $($tt:tt)*) => {
109+
$v.push(::proc_macro::TokenTree::Punct(
110+
::proc_macro::Punct::new(',', ::proc_macro::Spacing::Alone)
111+
));
112+
quote_spanned!(@proc $v $span $($tt)*);
113+
};
114+
(@proc $v:ident $span:ident @ $($tt:tt)*) => {
115+
$v.push(::proc_macro::TokenTree::Punct(
116+
::proc_macro::Punct::new('@', ::proc_macro::Spacing::Alone)
117+
));
118+
quote_spanned!(@proc $v $span $($tt)*);
119+
};
120+
(@proc $v:ident $span:ident ! $($tt:tt)*) => {
121+
$v.push(::proc_macro::TokenTree::Punct(
122+
::proc_macro::Punct::new('!', ::proc_macro::Spacing::Alone)
123+
));
124+
quote_spanned!(@proc $v $span $($tt)*);
125+
};
126+
(@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
127+
$v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span)));
128+
quote_spanned!(@proc $v $span $($tt)*);
129+
};
130+
}
131+
132+
/// Converts tokens into [`proc_macro::TokenStream`] and performs variable interpolations with
133+
/// mixed site span ([`Span::mixed_site()`]).
134+
///
135+
/// This is a similar to the [`quote!`](https://docs.rs/quote/latest/quote/macro.quote.html) macro
136+
/// from the `quote` crate but provides only just enough functionality needed by the current
137+
/// `macros` crate.
138+
///
139+
/// [`Span::mixed_site()`]: https://doc.rust-lang.org/proc_macro/struct.Span.html#method.mixed_site
140+
#[allow(unused_macros)]
141+
macro_rules! quote {
142+
($($tt:tt)*) => {
143+
quote_spanned!(::proc_macro::Span::mixed_site() => $($tt)*)
144+
}
145+
}

0 commit comments

Comments
 (0)