Skip to content

Commit 0351e73

Browse files
committed
Append TokenTree with ToTokens in proc_macro::quote!
1 parent 2a2e87b commit 0351e73

File tree

3 files changed

+83
-64
lines changed

3 files changed

+83
-64
lines changed

library/proc_macro/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ pub mod token_stream {
419419
/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
420420
/// To quote `$` itself, use `$$`.
421421
#[unstable(feature = "proc_macro_quote", issue = "54722")]
422-
#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals)]
422+
#[allow_internal_unstable(proc_macro_def_site, proc_macro_internals, proc_macro_totokens)]
423423
#[rustc_builtin_macro]
424424
pub macro quote($($t:tt)*) {
425425
/* compiler built-in */

library/proc_macro/src/quote.rs

+59-44
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
//! This quasiquoter uses macros 2.0 hygiene to reliably access
55
//! items from `proc_macro`, to build a `proc_macro::TokenStream`.
66
7-
use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
7+
use crate::{
8+
Delimiter, Group, Ident, Literal, Punct, Spacing, Span, ToTokens, TokenStream, TokenTree,
9+
};
810

911
macro_rules! minimal_quote_tt {
1012
(($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, minimal_quote!($($t)*)) };
@@ -24,16 +26,15 @@ macro_rules! minimal_quote_tt {
2426
macro_rules! minimal_quote_ts {
2527
((@ $($t:tt)*)) => { $($t)* };
2628
(::) => {
27-
[
28-
TokenTree::from(Punct::new(':', Spacing::Joint)),
29-
TokenTree::from(Punct::new(':', Spacing::Alone)),
30-
].iter()
31-
.cloned()
32-
.map(|mut x| {
33-
x.set_span(Span::def_site());
34-
x
35-
})
36-
.collect::<TokenStream>()
29+
{
30+
let mut c = (
31+
TokenTree::from(Punct::new(':', Spacing::Joint)),
32+
TokenTree::from(Punct::new(':', Spacing::Alone))
33+
);
34+
c.0.set_span(Span::def_site());
35+
c.1.set_span(Span::def_site());
36+
[c.0, c.1].into_iter().collect::<TokenStream>()
37+
}
3738
};
3839
($t:tt) => { TokenTree::from(minimal_quote_tt!($t)) };
3940
}
@@ -50,8 +51,8 @@ macro_rules! minimal_quote {
5051
() => { TokenStream::new() };
5152
($($t:tt)*) => {
5253
[
53-
$(TokenStream::from(minimal_quote_ts!($t)),)*
54-
].iter().cloned().collect::<TokenStream>()
54+
$(ToTokens::into_token_stream(minimal_quote_ts!($t)),)*
55+
].into_iter().collect::<TokenStream>()
5556
};
5657
}
5758

@@ -66,48 +67,56 @@ pub fn quote(stream: TokenStream) -> TokenStream {
6667
}
6768
let proc_macro_crate = minimal_quote!(crate);
6869
let mut after_dollar = false;
69-
let tokens = stream
70-
.into_iter()
71-
.filter_map(|tree| {
72-
if after_dollar {
73-
after_dollar = false;
74-
match tree {
75-
TokenTree::Ident(_) => {
76-
return Some(minimal_quote!(Into::<crate::TokenStream>::into(
77-
Clone::clone(&(@ tree))),));
78-
}
79-
TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
80-
_ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
81-
}
82-
} else if let TokenTree::Punct(ref tt) = tree {
83-
if tt.as_char() == '$' {
84-
after_dollar = true;
85-
return None;
70+
71+
let mut tokens = crate::TokenStream::new();
72+
for tree in stream {
73+
if after_dollar {
74+
after_dollar = false;
75+
match tree {
76+
TokenTree::Ident(_) => {
77+
minimal_quote!(crate::ToTokens::to_tokens(&(@ tree), &mut ts);)
78+
.to_tokens(&mut tokens);
79+
continue;
8680
}
81+
TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
82+
_ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
83+
}
84+
} else if let TokenTree::Punct(ref tt) = tree {
85+
if tt.as_char() == '$' {
86+
after_dollar = true;
87+
continue;
8788
}
89+
}
8890

89-
Some(minimal_quote!(crate::TokenStream::from((@ match tree {
90-
TokenTree::Punct(tt) => minimal_quote!(crate::TokenTree::Punct(crate::Punct::new(
91+
match tree {
92+
TokenTree::Punct(tt) => {
93+
minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(
9194
(@ TokenTree::from(Literal::character(tt.as_char()))),
9295
(@ match tt.spacing() {
9396
Spacing::Alone => minimal_quote!(crate::Spacing::Alone),
9497
Spacing::Joint => minimal_quote!(crate::Spacing::Joint),
9598
}),
96-
))),
97-
TokenTree::Group(tt) => minimal_quote!(crate::TokenTree::Group(crate::Group::new(
99+
)), &mut ts);)
100+
}
101+
TokenTree::Group(tt) => {
102+
minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Group(crate::Group::new(
98103
(@ match tt.delimiter() {
99104
Delimiter::Parenthesis => minimal_quote!(crate::Delimiter::Parenthesis),
100105
Delimiter::Brace => minimal_quote!(crate::Delimiter::Brace),
101106
Delimiter::Bracket => minimal_quote!(crate::Delimiter::Bracket),
102107
Delimiter::None => minimal_quote!(crate::Delimiter::None),
103108
}),
104109
(@ quote(tt.stream())),
105-
))),
106-
TokenTree::Ident(tt) => minimal_quote!(crate::TokenTree::Ident(crate::Ident::new(
110+
)), &mut ts);)
111+
}
112+
TokenTree::Ident(tt) => {
113+
minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new(
107114
(@ TokenTree::from(Literal::string(&tt.to_string()))),
108115
(@ quote_span(proc_macro_crate.clone(), tt.span())),
109-
))),
110-
TokenTree::Literal(tt) => minimal_quote!(crate::TokenTree::Literal({
116+
)), &mut ts);)
117+
}
118+
TokenTree::Literal(tt) => {
119+
minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Literal({
111120
let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string())))
112121
.parse::<crate::TokenStream>()
113122
.unwrap()
@@ -120,16 +129,22 @@ pub fn quote(stream: TokenStream) -> TokenStream {
120129
} else {
121130
unreachable!()
122131
}
123-
}))
124-
})),))
125-
})
126-
.collect::<TokenStream>();
127-
132+
}), &mut ts);)
133+
}
134+
}
135+
.to_tokens(&mut tokens);
136+
}
128137
if after_dollar {
129138
panic!("unexpected trailing `$` in `quote!`");
130139
}
131140

132-
minimal_quote!([(@ tokens)].iter().cloned().collect::<crate::TokenStream>())
141+
minimal_quote! {
142+
{
143+
let mut ts = crate::TokenStream::new();
144+
(@ tokens)
145+
ts
146+
}
147+
}
133148
}
134149

135150
/// Quote a `Span` into a `TokenStream`.

tests/ui/proc-macro/quote-debug.stdout

+23-19
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,29 @@ extern crate std;
1919
extern crate proc_macro;
2020

2121
fn main() {
22-
[crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("let",
23-
crate::Span::recover_proc_macro_span(0)))),
24-
crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello",
25-
crate::Span::recover_proc_macro_span(1)))),
26-
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('=',
27-
crate::Spacing::Alone))),
28-
crate::TokenStream::from(crate::TokenTree::Literal({
29-
let mut iter =
30-
"\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
31-
if let (Some(crate::TokenTree::Literal(mut lit)), None) =
32-
(iter.next(), iter.next()) {
33-
lit.set_span(crate::Span::recover_proc_macro_span(2));
34-
lit
35-
} else {
36-
::core::panicking::panic("internal error: entered unreachable code")
37-
}
38-
})),
39-
crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new(';',
40-
crate::Spacing::Alone)))].iter().cloned().collect::<crate::TokenStream>()
22+
{
23+
let mut ts = crate::TokenStream::new();
24+
crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("let",
25+
crate::Span::recover_proc_macro_span(0))), &mut ts);
26+
crate::ToTokens::to_tokens(&crate::TokenTree::Ident(crate::Ident::new("hello",
27+
crate::Span::recover_proc_macro_span(1))), &mut ts);
28+
crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new('=',
29+
crate::Spacing::Alone)), &mut ts);
30+
crate::ToTokens::to_tokens(&crate::TokenTree::Literal({
31+
let mut iter =
32+
"\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
33+
if let (Some(crate::TokenTree::Literal(mut lit)), None) =
34+
(iter.next(), iter.next()) {
35+
lit.set_span(crate::Span::recover_proc_macro_span(2));
36+
lit
37+
} else {
38+
::core::panicking::panic("internal error: entered unreachable code")
39+
}
40+
}), &mut ts);
41+
crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';',
42+
crate::Spacing::Alone)), &mut ts);
43+
ts
44+
}
4145
}
4246
const _: () =
4347
{

0 commit comments

Comments
 (0)