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
911macro_rules! minimal_quote_tt {
1012 ( ( $( $t: tt) * ) ) => { Group :: new( Delimiter :: Parenthesis , minimal_quote!( $( $t) * ) ) } ;
@@ -24,16 +26,15 @@ macro_rules! minimal_quote_tt {
2426macro_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`.
0 commit comments