@@ -20,6 +20,12 @@ fn to_tokens(&self, tokens: &mut TokenStream) {
}
}
+impl ToTokens for proc_macro::Ident {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ tokens.extend([TokenTree::from(self.clone())]);
+ }
+}
+
impl ToTokens for TokenTree {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend([self.clone()]);
@@ -40,7 +46,7 @@ fn to_tokens(&self, tokens: &mut TokenStream) {
/// `quote` crate but provides only just enough functionality needed by the current `macros` crate.
macro_rules! quote_spanned {
($span:expr => $($tt:tt)*) => {{
- let mut tokens;
+ let mut tokens: ::std::vec::Vec<::proc_macro::TokenTree>;
#[allow(clippy::vec_init_then_push)]
{
tokens = ::std::vec::Vec::new();
@@ -65,7 +71,8 @@ macro_rules! quote_spanned {
quote_spanned!(@proc $v $span $($tt)*);
};
(@proc $v:ident $span:ident ( $($inner:tt)* ) $($tt:tt)*) => {
- let mut tokens = ::std::vec::Vec::new();
+ #[allow(unused_mut)]
+ let mut tokens = ::std::vec::Vec::<::proc_macro::TokenTree>::new();
quote_spanned!(@proc tokens $span $($inner)*);
$v.push(::proc_macro::TokenTree::Group(::proc_macro::Group::new(
::proc_macro::Delimiter::Parenthesis,
@@ -136,6 +143,16 @@ macro_rules! quote_spanned {
));
quote_spanned!(@proc $v $span $($tt)*);
};
+ (@proc $v:ident $span:ident = $($tt:tt)*) => {
+ $v.push(::proc_macro::TokenTree::Punct(
+ ::proc_macro::Punct::new('=', ::proc_macro::Spacing::Alone)
+ ));
+ quote_spanned!(@proc $v $span $($tt)*);
+ };
+ (@proc $v:ident $span:ident _ $($tt:tt)*) => {
+ $v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new("_", $span)));
+ quote_spanned!(@proc $v $span $($tt)*);
+ };
(@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
$v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span)));
quote_spanned!(@proc $v $span $($tt)*);
This gives the quote! macro support for the following additional tokens: * The = token. * The _ token. * Using #my_var with variables of type Ident. Additionally, some type annotations are added to allow cases where groups are empty. For example, quote! does support () in the input, but only when it is *not* empty. When it is empty, the compiler cannot infer the item type of `tokens`. These additional quote! features are used by a new proc macro that generates code looking like this: const _: () = { if true { ::kernel::bindings::#name } else { #name }; }; where #name has type Ident. Signed-off-by: Alice Ryhl <aliceryhl@google.com> --- rust/macros/quote.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)