1use proc_macro::{TokenStream, TokenTree};
4
5pub(crate) trait ToTokens {
6 fn to_tokens(&self, tokens: &mut TokenStream);
7}
8
9impl<T: ToTokens> ToTokens for Option<T> {
10 fn to_tokens(&self, tokens: &mut TokenStream) {
11 if let Some(v) = self {
12 v.to_tokens(tokens);
13 }
14 }
15}
16
17impl ToTokens for proc_macro::Group {
18 fn to_tokens(&self, tokens: &mut TokenStream) {
19 tokens.extend([TokenTree::from(self.clone())]);
20 }
21}
22
23impl ToTokens for proc_macro::Ident {
24 fn to_tokens(&self, tokens: &mut TokenStream) {
25 tokens.extend([TokenTree::from(self.clone())]);
26 }
27}
28
29impl ToTokens for TokenTree {
30 fn to_tokens(&self, tokens: &mut TokenStream) {
31 tokens.extend([self.clone()]);
32 }
33}
34
35impl ToTokens for TokenStream {
36 fn to_tokens(&self, tokens: &mut TokenStream) {
37 tokens.extend(self.clone());
38 }
39}
40
41macro_rules! quote_spanned {
48 ($span:expr => $($tt:tt)*) => {{
49 let mut tokens = ::proc_macro::TokenStream::new();
50 {
51 #[allow(unused_variables)]
52 let span = $span;
53 quote_spanned!(@proc tokens span $($tt)*);
54 }
55 tokens
56 }};
57 (@proc $v:ident $span:ident) => {};
58 (@proc $v:ident $span:ident #$id:ident $($tt:tt)*) => {
59 $crate::quote::ToTokens::to_tokens(&$id, &mut $v);
60 quote_spanned!(@proc $v $span $($tt)*);
61 };
62 (@proc $v:ident $span:ident #(#$id:ident)* $($tt:tt)*) => {
63 for token in $id {
64 $crate::quote::ToTokens::to_tokens(&token, &mut $v);
65 }
66 quote_spanned!(@proc $v $span $($tt)*);
67 };
68 (@proc $v:ident $span:ident ( $($inner:tt)* ) $($tt:tt)*) => {
69 #[allow(unused_mut)]
70 let mut tokens = ::proc_macro::TokenStream::new();
71 quote_spanned!(@proc tokens $span $($inner)*);
72 $v.extend([::proc_macro::TokenTree::Group(::proc_macro::Group::new(
73 ::proc_macro::Delimiter::Parenthesis,
74 tokens,
75 ))]);
76 quote_spanned!(@proc $v $span $($tt)*);
77 };
78 (@proc $v:ident $span:ident [ $($inner:tt)* ] $($tt:tt)*) => {
79 let mut tokens = ::proc_macro::TokenStream::new();
80 quote_spanned!(@proc tokens $span $($inner)*);
81 $v.extend([::proc_macro::TokenTree::Group(::proc_macro::Group::new(
82 ::proc_macro::Delimiter::Bracket,
83 tokens,
84 ))]);
85 quote_spanned!(@proc $v $span $($tt)*);
86 };
87 (@proc $v:ident $span:ident { $($inner:tt)* } $($tt:tt)*) => {
88 let mut tokens = ::proc_macro::TokenStream::new();
89 quote_spanned!(@proc tokens $span $($inner)*);
90 $v.extend([::proc_macro::TokenTree::Group(::proc_macro::Group::new(
91 ::proc_macro::Delimiter::Brace,
92 tokens,
93 ))]);
94 quote_spanned!(@proc $v $span $($tt)*);
95 };
96 (@proc $v:ident $span:ident :: $($tt:tt)*) => {
97 $v.extend([::proc_macro::Spacing::Joint, ::proc_macro::Spacing::Alone].map(|spacing| {
98 ::proc_macro::TokenTree::Punct(::proc_macro::Punct::new(':', spacing))
99 }));
100 quote_spanned!(@proc $v $span $($tt)*);
101 };
102 (@proc $v:ident $span:ident : $($tt:tt)*) => {
103 $v.extend([::proc_macro::TokenTree::Punct(
104 ::proc_macro::Punct::new(':', ::proc_macro::Spacing::Alone),
105 )]);
106 quote_spanned!(@proc $v $span $($tt)*);
107 };
108 (@proc $v:ident $span:ident , $($tt:tt)*) => {
109 $v.extend([::proc_macro::TokenTree::Punct(
110 ::proc_macro::Punct::new(',', ::proc_macro::Spacing::Alone),
111 )]);
112 quote_spanned!(@proc $v $span $($tt)*);
113 };
114 (@proc $v:ident $span:ident @ $($tt:tt)*) => {
115 $v.extend([::proc_macro::TokenTree::Punct(
116 ::proc_macro::Punct::new('@', ::proc_macro::Spacing::Alone),
117 )]);
118 quote_spanned!(@proc $v $span $($tt)*);
119 };
120 (@proc $v:ident $span:ident ! $($tt:tt)*) => {
121 $v.extend([::proc_macro::TokenTree::Punct(
122 ::proc_macro::Punct::new('!', ::proc_macro::Spacing::Alone),
123 )]);
124 quote_spanned!(@proc $v $span $($tt)*);
125 };
126 (@proc $v:ident $span:ident ; $($tt:tt)*) => {
127 $v.extend([::proc_macro::TokenTree::Punct(
128 ::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone),
129 )]);
130 quote_spanned!(@proc $v $span $($tt)*);
131 };
132 (@proc $v:ident $span:ident + $($tt:tt)*) => {
133 $v.extend([::proc_macro::TokenTree::Punct(
134 ::proc_macro::Punct::new('+', ::proc_macro::Spacing::Alone),
135 )]);
136 quote_spanned!(@proc $v $span $($tt)*);
137 };
138 (@proc $v:ident $span:ident = $($tt:tt)*) => {
139 $v.extend([::proc_macro::TokenTree::Punct(
140 ::proc_macro::Punct::new('=', ::proc_macro::Spacing::Alone),
141 )]);
142 quote_spanned!(@proc $v $span $($tt)*);
143 };
144 (@proc $v:ident $span:ident # $($tt:tt)*) => {
145 $v.extend([::proc_macro::TokenTree::Punct(
146 ::proc_macro::Punct::new('#', ::proc_macro::Spacing::Alone),
147 )]);
148 quote_spanned!(@proc $v $span $($tt)*);
149 };
150 (@proc $v:ident $span:ident & $($tt:tt)*) => {
151 $v.extend([::proc_macro::TokenTree::Punct(
152 ::proc_macro::Punct::new('&', ::proc_macro::Spacing::Alone),
153 )]);
154 quote_spanned!(@proc $v $span $($tt)*);
155 };
156 (@proc $v:ident $span:ident _ $($tt:tt)*) => {
157 $v.extend([::proc_macro::TokenTree::Ident(
158 ::proc_macro::Ident::new("_", $span),
159 )]);
160 quote_spanned!(@proc $v $span $($tt)*);
161 };
162 (@proc $v:ident $span:ident $id:ident $($tt:tt)*) => {
163 $v.extend([::proc_macro::TokenTree::Ident(
164 ::proc_macro::Ident::new(stringify!($id), $span),
165 )]);
166 quote_spanned!(@proc $v $span $($tt)*);
167 };
168}
169
170macro_rules! quote {
179 ($($tt:tt)*) => {
180 quote_spanned!(::proc_macro::Span::mixed_site() => $($tt)*)
181 }
182}