4
4
//! This quasiquoter uses macros 2.0 hygiene to reliably access
5
5
//! items from `proc_macro`, to build a `proc_macro::TokenStream`.
6
6
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
+ } ;
8
10
9
11
macro_rules! minimal_quote_tt {
10
12
( ( $( $t: tt) * ) ) => { Group :: new( Delimiter :: Parenthesis , minimal_quote!( $( $t) * ) ) } ;
@@ -24,16 +26,15 @@ macro_rules! minimal_quote_tt {
24
26
macro_rules! minimal_quote_ts {
25
27
( ( @ $( $t: tt) * ) ) => { $( $t) * } ;
26
28
( :: ) => {
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
+ }
37
38
} ;
38
39
( $t: tt) => { TokenTree :: from( minimal_quote_tt!( $t) ) } ;
39
40
}
@@ -50,8 +51,8 @@ macro_rules! minimal_quote {
50
51
( ) => { TokenStream :: new( ) } ;
51
52
( $( $t: tt) * ) => {
52
53
[
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 >( )
55
56
} ;
56
57
}
57
58
@@ -66,48 +67,56 @@ pub fn quote(stream: TokenStream) -> TokenStream {
66
67
}
67
68
let proc_macro_crate = minimal_quote ! ( crate ) ;
68
69
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 ;
86
80
}
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 ;
87
88
}
89
+ }
88
90
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(
91
94
( @ TokenTree :: from( Literal :: character( tt. as_char( ) ) ) ) ,
92
95
( @ match tt. spacing( ) {
93
96
Spacing :: Alone => minimal_quote!( crate :: Spacing :: Alone ) ,
94
97
Spacing :: Joint => minimal_quote!( crate :: Spacing :: Joint ) ,
95
98
} ) ,
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(
98
103
( @ match tt. delimiter( ) {
99
104
Delimiter :: Parenthesis => minimal_quote!( crate :: Delimiter :: Parenthesis ) ,
100
105
Delimiter :: Brace => minimal_quote!( crate :: Delimiter :: Brace ) ,
101
106
Delimiter :: Bracket => minimal_quote!( crate :: Delimiter :: Bracket ) ,
102
107
Delimiter :: None => minimal_quote!( crate :: Delimiter :: None ) ,
103
108
} ) ,
104
109
( @ 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(
107
114
( @ TokenTree :: from( Literal :: string( & tt. to_string( ) ) ) ) ,
108
115
( @ 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 ( {
111
120
let mut iter = ( @ TokenTree :: from( Literal :: string( & tt. to_string( ) ) ) )
112
121
. parse:: <crate :: TokenStream >( )
113
122
. unwrap( )
@@ -120,16 +129,22 @@ pub fn quote(stream: TokenStream) -> TokenStream {
120
129
} else {
121
130
unreachable!( )
122
131
}
123
- } ) )
124
- } ) ) , ) )
125
- } )
126
- . collect :: < TokenStream > ( ) ;
127
-
132
+ } ) , & mut ts ) ; )
133
+ }
134
+ }
135
+ . to_tokens ( & mut tokens ) ;
136
+ }
128
137
if after_dollar {
129
138
panic ! ( "unexpected trailing `$` in `quote!`" ) ;
130
139
}
131
140
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
+ }
133
148
}
134
149
135
150
/// Quote a `Span` into a `TokenStream`.
0 commit comments