1use crate::{
8 BitOr, Delimiter, Group, Ident, Literal, Punct, Spacing, Span, ToTokens, TokenStream, TokenTree,
9};
10
11#[doc(hidden)]
12pub struct HasIterator; #[doc(hidden)]
14pub struct ThereIsNoIteratorInRepetition; impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
17 type Output = ThereIsNoIteratorInRepetition;
18 fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
19 ThereIsNoIteratorInRepetition
20 }
21}
22
23impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
24 type Output = HasIterator;
25 fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
26 HasIterator
27 }
28}
29
30impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
31 type Output = HasIterator;
32 fn bitor(self, _rhs: HasIterator) -> HasIterator {
33 HasIterator
34 }
35}
36
37impl BitOr<HasIterator> for HasIterator {
38 type Output = HasIterator;
39 fn bitor(self, _rhs: HasIterator) -> HasIterator {
40 HasIterator
41 }
42}
43
44#[doc(hidden)]
51pub mod ext {
52 use core::slice;
53 use std::collections::btree_set::{self, BTreeSet};
54
55 use super::{
56 HasIterator as HasIter, RepInterp, ThereIsNoIteratorInRepetition as DoesNotHaveIter,
57 };
58 use crate::ToTokens;
59
60 #[doc(hidden)]
62 pub trait RepIteratorExt: Iterator + Sized {
63 fn quote_into_iter(self) -> (Self, HasIter) {
64 (self, HasIter)
65 }
66 }
67
68 impl<T: Iterator> RepIteratorExt for T {}
69
70 #[doc(hidden)]
74 pub trait RepToTokensExt {
75 fn next(&self) -> Option<&Self> {
79 Some(self)
80 }
81
82 fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) {
83 (self, DoesNotHaveIter)
84 }
85 }
86
87 impl<T: ToTokens + ?Sized> RepToTokensExt for T {}
88
89 #[doc(hidden)]
92 pub trait RepAsIteratorExt<'q> {
93 type Iter: Iterator;
94
95 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter);
96 }
97
98 impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &T {
99 type Iter = T::Iter;
100
101 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
102 <T as RepAsIteratorExt>::quote_into_iter(*self)
103 }
104 }
105
106 impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &mut T {
107 type Iter = T::Iter;
108
109 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
110 <T as RepAsIteratorExt>::quote_into_iter(*self)
111 }
112 }
113
114 impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
115 type Iter = slice::Iter<'q, T>;
116
117 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
118 (self.iter(), HasIter)
119 }
120 }
121
122 impl<'q, T: 'q, const N: usize> RepAsIteratorExt<'q> for [T; N] {
123 type Iter = slice::Iter<'q, T>;
124
125 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
126 (self.iter(), HasIter)
127 }
128 }
129
130 impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
131 type Iter = slice::Iter<'q, T>;
132
133 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
134 (self.iter(), HasIter)
135 }
136 }
137
138 impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
139 type Iter = btree_set::Iter<'q, T>;
140
141 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
142 (self.iter(), HasIter)
143 }
144 }
145
146 impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
147 type Iter = T::Iter;
148
149 fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
150 self.0.quote_into_iter()
151 }
152 }
153}
154
155#[derive(Copy, Clone)]
158#[doc(hidden)]
159pub struct RepInterp<T>(pub T);
160
161impl<T> RepInterp<T> {
162 pub fn next(self) -> Option<T> {
167 Some(self.0)
168 }
169}
170
171impl<T: Iterator> Iterator for RepInterp<T> {
172 type Item = T::Item;
173
174 fn next(&mut self) -> Option<Self::Item> {
175 self.0.next()
176 }
177}
178
179impl<T: ToTokens> ToTokens for RepInterp<T> {
180 fn to_tokens(&self, tokens: &mut TokenStream) {
181 self.0.to_tokens(tokens);
182 }
183}
184
185macro_rules! minimal_quote_tt {
186 (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, minimal_quote!($($t)*)) };
187 ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, minimal_quote!($($t)*)) };
188 ({$($t:tt)*}) => { Group::new(Delimiter::Brace, minimal_quote!($($t)*)) };
189 (,) => { Punct::new(',', Spacing::Alone) };
190 (.) => { Punct::new('.', Spacing::Alone) };
191 (;) => { Punct::new(';', Spacing::Alone) };
192 (!) => { Punct::new('!', Spacing::Alone) };
193 (<) => { Punct::new('<', Spacing::Alone) };
194 (>) => { Punct::new('>', Spacing::Alone) };
195 (&) => { Punct::new('&', Spacing::Alone) };
196 (=) => { Punct::new('=', Spacing::Alone) };
197 (#) => { Punct::new('#', Spacing::Alone) };
198 (|) => { Punct::new('|', Spacing::Alone) };
199 (:) => { Punct::new(':', Spacing::Alone) };
200 (*) => { Punct::new('*', Spacing::Alone) };
201 (_) => { Ident::new("_", Span::def_site()) };
202 ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) };
203 ($lit:literal) => { stringify!($lit).parse::<Literal>().unwrap() };
204}
205
206macro_rules! minimal_quote_ts {
207 ((@ $($t:tt)*)) => { $($t)* };
208 (::) => {
209 {
210 let mut c = (
211 TokenTree::from(Punct::new(':', Spacing::Joint)),
212 TokenTree::from(Punct::new(':', Spacing::Alone))
213 );
214 c.0.set_span(Span::def_site());
215 c.1.set_span(Span::def_site());
216 [c.0, c.1].into_iter().collect::<TokenStream>()
217 }
218 };
219 (=>) => {
220 {
221 let mut c = (
222 TokenTree::from(Punct::new('=', Spacing::Joint)),
223 TokenTree::from(Punct::new('>', Spacing::Alone))
224 );
225 c.0.set_span(Span::def_site());
226 c.1.set_span(Span::def_site());
227 [c.0, c.1].into_iter().collect::<TokenStream>()
228 }
229 };
230 (+=) => {
231 {
232 let mut c = (
233 TokenTree::from(Punct::new('+', Spacing::Joint)),
234 TokenTree::from(Punct::new('=', Spacing::Alone))
235 );
236 c.0.set_span(Span::def_site());
237 c.1.set_span(Span::def_site());
238 [c.0, c.1].into_iter().collect::<TokenStream>()
239 }
240 };
241 (!=) => {
242 {
243 let mut c = (
244 TokenTree::from(Punct::new('!', Spacing::Joint)),
245 TokenTree::from(Punct::new('=', Spacing::Alone))
246 );
247 c.0.set_span(Span::def_site());
248 c.1.set_span(Span::def_site());
249 [c.0, c.1].into_iter().collect::<TokenStream>()
250 }
251 };
252 ($t:tt) => { TokenTree::from(minimal_quote_tt!($t)) };
253}
254
255macro_rules! minimal_quote {
264 ($($t:tt)*) => {
265 {
266 #[allow(unused_mut)] let mut ts = TokenStream::new();
268 $(ToTokens::to_tokens(&minimal_quote_ts!($t), &mut ts);)*
269 ts
270 }
271 };
272}
273
274#[unstable(feature = "proc_macro_quote", issue = "54722")]
279pub fn quote(stream: TokenStream) -> TokenStream {
280 if stream.is_empty() {
281 return minimal_quote!(crate::TokenStream::new());
282 }
283 let proc_macro_crate = minimal_quote!(crate);
284 let mut after_dollar = false;
285
286 let mut tokens = crate::TokenStream::new();
287 let mut iter = stream.into_iter().peekable();
288 while let Some(tree) = iter.next() {
289 if after_dollar {
290 after_dollar = false;
291 match tree {
292 TokenTree::Group(tt) => {
293 let contents = tt.stream();
295
296 let sep_opt: Option<Punct> = match (iter.next(), iter.peek()) {
298 (Some(TokenTree::Punct(sep)), Some(TokenTree::Punct(star)))
299 if sep.spacing() == Spacing::Joint && star.as_char() == '*' =>
300 {
301 iter.next();
302 Some(sep)
303 }
304 (Some(TokenTree::Punct(star)), _) if star.as_char() == '*' => None,
305 _ => panic!("`$(...)` must be followed by `*` in `quote!`"),
306 };
307
308 let mut rep_expanded = TokenStream::new();
309
310 let meta_vars = collect_meta_vars(contents.clone());
313 minimal_quote!(
314 use crate::ext::*;
315 (@ if sep_opt.is_some() {
316 minimal_quote!(let mut _i = 0usize;)
317 } else {
318 minimal_quote!(();)
319 })
320 let has_iter = crate::ThereIsNoIteratorInRepetition;
321 )
322 .to_tokens(&mut rep_expanded);
323 for meta_var in &meta_vars {
324 minimal_quote!(
325 #[allow(unused_mut)]
326 let (mut (@ meta_var), i) = (@ meta_var).quote_into_iter();
327 let has_iter = has_iter | i;
328 )
329 .to_tokens(&mut rep_expanded);
330 }
331 minimal_quote!(let _: crate::HasIterator = has_iter;)
332 .to_tokens(&mut rep_expanded);
333
334 let mut while_body = TokenStream::new();
336 for meta_var in &meta_vars {
337 minimal_quote!(
338 let (@ meta_var) = match (@ meta_var).next() {
339 Some(_x) => crate::RepInterp(_x),
340 None => break,
341 };
342 )
343 .to_tokens(&mut while_body);
344 }
345 minimal_quote!(
346 (@ if let Some(sep) = sep_opt {
347 minimal_quote!(
348 if _i > 0 {
349 (@ minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(
350 (@ TokenTree::from(Literal::character(sep.as_char()))),
351 (@ minimal_quote!(crate::Spacing::Alone)),
352 )), &mut ts);))
353 }
354 _i += 1;
355 )
356 } else {
357 minimal_quote!(();)
358 })
359 (@ quote(contents.clone())).to_tokens(&mut ts);
360 )
361 .to_tokens(&mut while_body);
362 rep_expanded.extend(vec![
363 TokenTree::Ident(Ident::new("while", Span::call_site())),
364 TokenTree::Ident(Ident::new("true", Span::call_site())),
365 TokenTree::Group(Group::new(Delimiter::Brace, while_body)),
366 ]);
367
368 minimal_quote!((@ TokenTree::Group(Group::new(Delimiter::Brace, rep_expanded)))).to_tokens(&mut tokens);
369 continue;
370 }
371 TokenTree::Ident(_) => {
372 minimal_quote!(crate::ToTokens::to_tokens(&(@ tree), &mut ts);)
373 .to_tokens(&mut tokens);
374 continue;
375 }
376 TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
377 _ => panic!(
378 "`$` must be followed by an ident or `$` or a repetition group in `quote!`"
379 ),
380 }
381 } else if let TokenTree::Punct(ref tt) = tree {
382 if tt.as_char() == '$' {
383 after_dollar = true;
384 continue;
385 }
386 }
387
388 match tree {
389 TokenTree::Punct(tt) => {
390 minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(
391 (@ TokenTree::from(Literal::character(tt.as_char()))),
392 (@ match tt.spacing() {
393 Spacing::Alone => minimal_quote!(crate::Spacing::Alone),
394 Spacing::Joint => minimal_quote!(crate::Spacing::Joint),
395 }),
396 )), &mut ts);)
397 }
398 TokenTree::Group(tt) => {
399 minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Group(crate::Group::new(
400 (@ match tt.delimiter() {
401 Delimiter::Parenthesis => minimal_quote!(crate::Delimiter::Parenthesis),
402 Delimiter::Brace => minimal_quote!(crate::Delimiter::Brace),
403 Delimiter::Bracket => minimal_quote!(crate::Delimiter::Bracket),
404 Delimiter::None => minimal_quote!(crate::Delimiter::None),
405 }),
406 (@ quote(tt.stream())),
407 )), &mut ts);)
408 }
409 TokenTree::Ident(tt) => {
410 let literal = tt.to_string();
411 let (literal, ctor) = if let Some(stripped) = literal.strip_prefix("r#") {
412 (stripped, minimal_quote!(crate::Ident::new_raw))
413 } else {
414 (literal.as_str(), minimal_quote!(crate::Ident::new))
415 };
416 minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Ident((@ ctor)(
417 (@ TokenTree::from(Literal::string(literal))),
418 (@ quote_span(proc_macro_crate.clone(), tt.span())),
419 )), &mut ts);)
420 }
421 TokenTree::Literal(tt) => {
422 minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Literal({
423 let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string())))
424 .parse::<crate::TokenStream>()
425 .unwrap()
426 .into_iter();
427 if let (Some(crate::TokenTree::Literal(mut lit)), None) =
428 (iter.next(), iter.next())
429 {
430 lit.set_span((@ quote_span(proc_macro_crate.clone(), tt.span())));
431 lit
432 } else {
433 unreachable!()
434 }
435 }), &mut ts);)
436 }
437 }
438 .to_tokens(&mut tokens);
439 }
440 if after_dollar {
441 panic!("unexpected trailing `$` in `quote!`");
442 }
443
444 minimal_quote! {
445 {
446 let mut ts = crate::TokenStream::new();
447 (@ tokens)
448 ts
449 }
450 }
451}
452
453fn collect_meta_vars(content_stream: TokenStream) -> Vec<Ident> {
457 fn helper(stream: TokenStream, out: &mut Vec<Ident>) {
458 let mut iter = stream.into_iter().peekable();
459 while let Some(tree) = iter.next() {
460 match &tree {
461 TokenTree::Punct(tt) if tt.as_char() == '$' => {
462 if let Some(TokenTree::Ident(id)) = iter.peek() {
463 out.push(id.clone());
464 iter.next();
465 }
466 }
467 TokenTree::Group(tt) => {
468 helper(tt.stream(), out);
469 }
470 _ => {}
471 }
472 }
473 }
474
475 let mut vars = Vec::new();
476 helper(content_stream, &mut vars);
477 vars
478}
479
480#[unstable(feature = "proc_macro_quote", issue = "54722")]
483pub fn quote_span(proc_macro_crate: TokenStream, span: Span) -> TokenStream {
484 let id = span.save_span();
485 minimal_quote!((@ proc_macro_crate ) ::Span::recover_proc_macro_span((@ TokenTree::from(Literal::usize_unsuffixed(id)))))
486}