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