55//! items from `proc_macro`, to build a `proc_macro::TokenStream`. 
66
77use  crate :: { 
8-     Delimiter ,  Group ,  Ident ,  Literal ,  Punct ,  Spacing ,  Span ,  ToTokens ,  TokenStream ,  TokenTree , 
8+     BitOr ,   Delimiter ,  Group ,  Ident ,  Literal ,  Punct ,  Spacing ,  Span ,  ToTokens ,  TokenStream ,  TokenTree , 
99} ; 
1010
11+ #[ doc( hidden) ]  
12+ pub  struct  HasIterator ;  // True 
13+ #[ doc( hidden) ]  
14+ pub  struct  ThereIsNoIteratorInRepetition ;  // False 
15+ 
16+ impl  BitOr < ThereIsNoIteratorInRepetition >  for  ThereIsNoIteratorInRepetition  { 
17+     type  Output  = ThereIsNoIteratorInRepetition ; 
18+     fn  bitor ( self ,  _rhs :  ThereIsNoIteratorInRepetition )  -> ThereIsNoIteratorInRepetition  { 
19+         ThereIsNoIteratorInRepetition 
20+     } 
21+ } 
22+ 
23+ impl  BitOr < ThereIsNoIteratorInRepetition >  for  HasIterator  { 
24+     type  Output  = HasIterator ; 
25+     fn  bitor ( self ,  _rhs :  ThereIsNoIteratorInRepetition )  -> HasIterator  { 
26+         HasIterator 
27+     } 
28+ } 
29+ 
30+ impl  BitOr < HasIterator >  for  ThereIsNoIteratorInRepetition  { 
31+     type  Output  = HasIterator ; 
32+     fn  bitor ( self ,  _rhs :  HasIterator )  -> HasIterator  { 
33+         HasIterator 
34+     } 
35+ } 
36+ 
37+ impl  BitOr < HasIterator >  for  HasIterator  { 
38+     type  Output  = HasIterator ; 
39+     fn  bitor ( self ,  _rhs :  HasIterator )  -> HasIterator  { 
40+         HasIterator 
41+     } 
42+ } 
43+ 
44+ /// Extension traits used by the implementation of `quote!`. These are defined 
45+ /// in separate traits, rather than as a single trait due to ambiguity issues. 
46+ /// 
47+ /// These traits expose a `quote_into_iter` method which should allow calling 
48+ /// whichever impl happens to be applicable. Calling that method repeatedly on 
49+ /// the returned value should be idempotent. 
50+ #[ doc( hidden) ]  
51+ pub  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+     /// Extension trait providing the `quote_into_iter` method on iterators. 
61+ #[ 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+     /// Extension trait providing the `quote_into_iter` method for 
71+ /// non-iterable types. These types interpolate the same value in each 
72+ /// iteration of the repetition. 
73+ #[ doc( hidden) ]  
74+     pub  trait  RepToTokensExt  { 
75+         /// Pretend to be an iterator for the purposes of `quote_into_iter`. 
76+ /// This allows repeated calls to `quote_into_iter` to continue 
77+ /// correctly returning DoesNotHaveIter. 
78+ 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+     /// Extension trait providing the `quote_into_iter` method for types that 
90+ /// can be referenced as an iterator. 
91+ #[ 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+ // Helper type used within interpolations to allow for repeated binding names. 
156+ // Implements the relevant traits, and exports a dummy `next()` method. 
157+ #[ derive( Copy ,  Clone ) ]  
158+ #[ doc( hidden) ]  
159+ pub  struct  RepInterp < T > ( pub  T ) ; 
160+ 
161+ impl < T >  RepInterp < T >  { 
162+     // This method is intended to look like `Iterator::next`, and is called when 
163+     // a name is bound multiple times, as the previous binding will shadow the 
164+     // original `Iterator` object. This allows us to avoid advancing the 
165+     // iterator multiple times per iteration. 
166+     pub  fn  next ( self )  -> Option < T >  { 
167+         Some ( self . 0 ) 
168+     } 
169+ } 
170+ 
171+ impl < 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+ 
179+ impl < T :  ToTokens >  ToTokens  for  RepInterp < T >  { 
180+     fn  to_tokens ( & self ,  tokens :  & mut  TokenStream )  { 
181+         self . 0 . to_tokens ( tokens) ; 
182+     } 
183+ } 
184+ 
11185macro_rules!  minimal_quote_tt { 
12186    ( ( $( $t: tt) * ) )  => {  Group :: new( Delimiter :: Parenthesis ,  minimal_quote!( $( $t) * ) )  } ; 
13187    ( [ $( $t: tt) * ] )  => {  Group :: new( Delimiter :: Bracket ,  minimal_quote!( $( $t) * ) )  } ; 
@@ -20,7 +194,13 @@ macro_rules! minimal_quote_tt {
20194    ( >)  => {  Punct :: new( '>' ,  Spacing :: Alone )  } ; 
21195    ( & )  => {  Punct :: new( '&' ,  Spacing :: Alone )  } ; 
22196    ( =)  => {  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( ) )  } ; 
23202    ( $i: ident)  => {  Ident :: new( stringify!( $i) ,  Span :: def_site( ) )  } ; 
203+     ( $lit: literal)  => {  stringify!( $lit) . parse:: <Literal >( ) . unwrap( )  } ; 
24204} 
25205
26206macro_rules!  minimal_quote_ts { 
@@ -36,6 +216,39 @@ macro_rules! minimal_quote_ts {
36216            [ c. 0 ,  c. 1 ] . into_iter( ) . collect:: <TokenStream >( ) 
37217        } 
38218    } ; 
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+     } ; 
39252    ( $t: tt)  => {  TokenTree :: from( minimal_quote_tt!( $t) )  } ; 
40253} 
41254
@@ -71,17 +284,99 @@ pub fn quote(stream: TokenStream) -> TokenStream {
71284    let  mut  after_dollar = false ; 
72285
73286    let  mut  tokens = crate :: TokenStream :: new ( ) ; 
74-     for  tree in  stream { 
287+     let  mut  iter = stream. into_iter ( ) . peekable ( ) ; 
288+     while  let  Some ( tree)  = iter. next ( )  { 
75289        if  after_dollar { 
76290            after_dollar = false ; 
77291            match  tree { 
292+                 TokenTree :: Group ( tt)  => { 
293+                     // Handles repetition by expanding `$( CONTENTS ) SEP_OPT *` to `{ REP_EXPANDED }`. 
294+                     let  contents = tt. stream ( ) ; 
295+ 
296+                     // The `*` token is also consumed here. 
297+                     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+                     // Append setup code for a `while`, where recursively quoted `CONTENTS` 
311+                     // and `SEP_OPT` are repeatedly processed, to `REP_EXPANDED`. 
312+                     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+                     // Append the `while` to `REP_EXPANDED`. 
335+                     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+                 } 
78371                TokenTree :: Ident ( _)  => { 
79372                    minimal_quote ! ( crate :: ToTokens :: to_tokens( & ( @ tree) ,  & mut  ts) ; ) 
80373                        . to_tokens ( & mut  tokens) ; 
81374                    continue ; 
82375                } 
83376                TokenTree :: Punct ( ref  tt)  if  tt. as_char ( )  == '$'  => { } 
84-                 _ => panic ! ( "`$` must be followed by an ident or `$` in `quote!`" ) , 
377+                 _ => panic ! ( 
378+                     "`$` must be followed by an ident or `$` or a repetition group in `quote!`" 
379+                 ) , 
85380            } 
86381        }  else  if  let  TokenTree :: Punct ( ref  tt)  = tree { 
87382            if  tt. as_char ( )  == '$'  { 
@@ -155,6 +450,33 @@ pub fn quote(stream: TokenStream) -> TokenStream {
155450    } 
156451} 
157452
453+ /// Helper function to support macro repetitions like `$( CONTENTS ) SEP_OPT *` in `quote!`. 
454+ /// Recursively collects all `Ident`s (meta-variables) that follow a `$` 
455+ /// from the given `CONTENTS` stream, preserving their order of appearance. 
456+ fn  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+ 
158480/// Quote a `Span` into a `TokenStream`. 
159481/// This is needed to implement a custom quoter. 
160482#[ unstable( feature = "proc_macro_quote" ,  issue = "54722" ) ]  
0 commit comments