]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
1 | use crate::{IdentFragment, ToTokens, TokenStreamExt}; |
2 | use std::fmt; | |
3 | use std::ops::BitOr; | |
4 | ||
5 | pub use proc_macro2::*; | |
6 | ||
7 | pub struct HasIterator; // True | |
8 | pub struct ThereIsNoIteratorInRepetition; // False | |
9 | ||
10 | impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition { | |
11 | type Output = ThereIsNoIteratorInRepetition; | |
12 | fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition { | |
13 | ThereIsNoIteratorInRepetition | |
14 | } | |
15 | } | |
16 | ||
17 | impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator { | |
18 | type Output = HasIterator; | |
19 | fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator { | |
20 | HasIterator | |
21 | } | |
22 | } | |
23 | ||
24 | impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition { | |
25 | type Output = HasIterator; | |
26 | fn bitor(self, _rhs: HasIterator) -> HasIterator { | |
27 | HasIterator | |
28 | } | |
29 | } | |
30 | ||
31 | impl BitOr<HasIterator> for HasIterator { | |
32 | type Output = HasIterator; | |
33 | fn bitor(self, _rhs: HasIterator) -> HasIterator { | |
34 | HasIterator | |
35 | } | |
36 | } | |
37 | ||
38 | /// Extension traits used by the implementation of `quote!`. These are defined | |
39 | /// in separate traits, rather than as a single trait due to ambiguity issues. | |
40 | /// | |
41 | /// These traits expose a `quote_into_iter` method which should allow calling | |
42 | /// whichever impl happens to be applicable. Calling that method repeatedly on | |
43 | /// the returned value should be idempotent. | |
44 | pub mod ext { | |
45 | use super::RepInterp; | |
46 | use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter}; | |
47 | use crate::ToTokens; | |
48 | use std::collections::btree_set::{self, BTreeSet}; | |
49 | use std::slice; | |
50 | ||
51 | /// Extension trait providing the `quote_into_iter` method on iterators. | |
52 | pub trait RepIteratorExt: Iterator + Sized { | |
53 | fn quote_into_iter(self) -> (Self, HasIter) { | |
54 | (self, HasIter) | |
55 | } | |
56 | } | |
57 | ||
58 | impl<T: Iterator> RepIteratorExt for T {} | |
59 | ||
60 | /// Extension trait providing the `quote_into_iter` method for | |
61 | /// non-iterable types. These types interpolate the same value in each | |
62 | /// iteration of the repetition. | |
63 | pub trait RepToTokensExt { | |
64 | /// Pretend to be an iterator for the purposes of `quote_into_iter`. | |
65 | /// This allows repeated calls to `quote_into_iter` to continue | |
66 | /// correctly returning DoesNotHaveIter. | |
67 | fn next(&self) -> Option<&Self> { | |
68 | Some(self) | |
69 | } | |
70 | ||
71 | fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) { | |
72 | (self, DoesNotHaveIter) | |
73 | } | |
74 | } | |
75 | ||
76 | impl<T: ToTokens + ?Sized> RepToTokensExt for T {} | |
77 | ||
78 | /// Extension trait providing the `quote_into_iter` method for types that | |
79 | /// can be referenced as an iterator. | |
80 | pub trait RepAsIteratorExt<'q> { | |
81 | type Iter: Iterator; | |
82 | ||
83 | fn quote_into_iter(&'q self) -> (Self::Iter, HasIter); | |
84 | } | |
85 | ||
86 | impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a T { | |
87 | type Iter = T::Iter; | |
88 | ||
89 | fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { | |
90 | <T as RepAsIteratorExt>::quote_into_iter(*self) | |
91 | } | |
92 | } | |
93 | ||
94 | impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a mut T { | |
95 | type Iter = T::Iter; | |
96 | ||
97 | fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { | |
98 | <T as RepAsIteratorExt>::quote_into_iter(*self) | |
99 | } | |
100 | } | |
101 | ||
102 | impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] { | |
103 | type Iter = slice::Iter<'q, T>; | |
104 | ||
105 | fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { | |
106 | (self.iter(), HasIter) | |
107 | } | |
108 | } | |
109 | ||
110 | impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> { | |
111 | type Iter = slice::Iter<'q, T>; | |
112 | ||
113 | fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { | |
114 | (self.iter(), HasIter) | |
115 | } | |
116 | } | |
117 | ||
118 | impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> { | |
119 | type Iter = btree_set::Iter<'q, T>; | |
120 | ||
121 | fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { | |
122 | (self.iter(), HasIter) | |
123 | } | |
124 | } | |
125 | ||
126 | macro_rules! array_rep_slice { | |
127 | ($($l:tt)*) => { | |
128 | $( | |
129 | impl<'q, T: 'q> RepAsIteratorExt<'q> for [T; $l] { | |
130 | type Iter = slice::Iter<'q, T>; | |
131 | ||
132 | fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { | |
133 | (self.iter(), HasIter) | |
134 | } | |
135 | } | |
136 | )* | |
137 | } | |
138 | } | |
139 | ||
140 | array_rep_slice!( | |
141 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
142 | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
143 | ); | |
144 | ||
145 | impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> { | |
146 | type Iter = T::Iter; | |
147 | ||
148 | fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { | |
149 | self.0.quote_into_iter() | |
150 | } | |
151 | } | |
152 | } | |
153 | ||
154 | // Helper type used within interpolations to allow for repeated binding names. | |
155 | // Implements the relevant traits, and exports a dummy `next()` method. | |
156 | #[derive(Copy, Clone)] | |
157 | pub struct RepInterp<T>(pub T); | |
158 | ||
159 | impl<T> RepInterp<T> { | |
160 | // This method is intended to look like `Iterator::next`, and is called when | |
161 | // a name is bound multiple times, as the previous binding will shadow the | |
162 | // original `Iterator` object. This allows us to avoid advancing the | |
163 | // iterator multiple times per iteration. | |
164 | pub fn next(self) -> Option<T> { | |
165 | Some(self.0) | |
166 | } | |
167 | } | |
168 | ||
169 | impl<T: Iterator> Iterator for RepInterp<T> { | |
170 | type Item = T::Item; | |
171 | ||
172 | fn next(&mut self) -> Option<Self::Item> { | |
173 | self.0.next() | |
174 | } | |
175 | } | |
176 | ||
177 | impl<T: ToTokens> ToTokens for RepInterp<T> { | |
178 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
179 | self.0.to_tokens(tokens); | |
180 | } | |
181 | } | |
182 | ||
f035d41b XL |
183 | pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) { |
184 | tokens.append(Group::new(delimiter, inner)); | |
e74abb32 XL |
185 | } |
186 | ||
f035d41b XL |
187 | pub fn push_group_spanned( |
188 | tokens: &mut TokenStream, | |
189 | span: Span, | |
190 | delimiter: Delimiter, | |
191 | inner: TokenStream, | |
192 | ) { | |
193 | let mut g = Group::new(delimiter, inner); | |
194 | g.set_span(span); | |
195 | tokens.append(g); | |
e74abb32 XL |
196 | } |
197 | ||
f035d41b XL |
198 | pub fn parse(tokens: &mut TokenStream, s: &str) { |
199 | let s: TokenStream = s.parse().expect("invalid token stream"); | |
200 | tokens.extend(s); | |
201 | } | |
e74abb32 | 202 | |
f035d41b XL |
203 | pub fn parse_spanned(tokens: &mut TokenStream, span: Span, s: &str) { |
204 | let s: TokenStream = s.parse().expect("invalid token stream"); | |
205 | tokens.extend(s.into_iter().map(|mut t| { | |
206 | t.set_span(span); | |
207 | t | |
208 | })); | |
e74abb32 XL |
209 | } |
210 | ||
f035d41b XL |
211 | pub fn push_ident(tokens: &mut TokenStream, s: &str) { |
212 | // Optimization over `mk_ident`, as `s` is guaranteed to be a valid ident. | |
213 | // | |
214 | // FIXME: When `Ident::new_raw` becomes stable, this method should be | |
215 | // updated to call it when available. | |
216 | if s.starts_with("r#") { | |
217 | parse(tokens, s); | |
e74abb32 | 218 | } else { |
f035d41b XL |
219 | tokens.append(Ident::new(s, Span::call_site())); |
220 | } | |
221 | } | |
222 | ||
223 | pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) { | |
224 | // Optimization over `mk_ident`, as `s` is guaranteed to be a valid ident. | |
225 | // | |
226 | // FIXME: When `Ident::new_raw` becomes stable, this method should be | |
227 | // updated to call it when available. | |
228 | if s.starts_with("r#") { | |
229 | parse_spanned(tokens, span, s); | |
230 | } else { | |
231 | tokens.append(Ident::new(s, span)); | |
e74abb32 XL |
232 | } |
233 | } | |
234 | ||
235 | macro_rules! push_punct { | |
f035d41b XL |
236 | ($name:ident $spanned:ident $char1:tt) => { |
237 | pub fn $name(tokens: &mut TokenStream) { | |
238 | tokens.append(Punct::new($char1, Spacing::Alone)); | |
239 | } | |
240 | pub fn $spanned(tokens: &mut TokenStream, span: Span) { | |
e74abb32 XL |
241 | let mut punct = Punct::new($char1, Spacing::Alone); |
242 | punct.set_span(span); | |
243 | tokens.append(punct); | |
244 | } | |
245 | }; | |
f035d41b XL |
246 | ($name:ident $spanned:ident $char1:tt $char2:tt) => { |
247 | pub fn $name(tokens: &mut TokenStream) { | |
248 | tokens.append(Punct::new($char1, Spacing::Joint)); | |
249 | tokens.append(Punct::new($char2, Spacing::Alone)); | |
250 | } | |
251 | pub fn $spanned(tokens: &mut TokenStream, span: Span) { | |
e74abb32 XL |
252 | let mut punct = Punct::new($char1, Spacing::Joint); |
253 | punct.set_span(span); | |
254 | tokens.append(punct); | |
255 | let mut punct = Punct::new($char2, Spacing::Alone); | |
256 | punct.set_span(span); | |
257 | tokens.append(punct); | |
258 | } | |
259 | }; | |
f035d41b XL |
260 | ($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => { |
261 | pub fn $name(tokens: &mut TokenStream) { | |
262 | tokens.append(Punct::new($char1, Spacing::Joint)); | |
263 | tokens.append(Punct::new($char2, Spacing::Joint)); | |
264 | tokens.append(Punct::new($char3, Spacing::Alone)); | |
265 | } | |
266 | pub fn $spanned(tokens: &mut TokenStream, span: Span) { | |
e74abb32 XL |
267 | let mut punct = Punct::new($char1, Spacing::Joint); |
268 | punct.set_span(span); | |
269 | tokens.append(punct); | |
270 | let mut punct = Punct::new($char2, Spacing::Joint); | |
271 | punct.set_span(span); | |
272 | tokens.append(punct); | |
273 | let mut punct = Punct::new($char3, Spacing::Alone); | |
274 | punct.set_span(span); | |
275 | tokens.append(punct); | |
276 | } | |
277 | }; | |
278 | } | |
279 | ||
f035d41b XL |
280 | push_punct!(push_add push_add_spanned '+'); |
281 | push_punct!(push_add_eq push_add_eq_spanned '+' '='); | |
282 | push_punct!(push_and push_and_spanned '&'); | |
283 | push_punct!(push_and_and push_and_and_spanned '&' '&'); | |
284 | push_punct!(push_and_eq push_and_eq_spanned '&' '='); | |
285 | push_punct!(push_at push_at_spanned '@'); | |
286 | push_punct!(push_bang push_bang_spanned '!'); | |
287 | push_punct!(push_caret push_caret_spanned '^'); | |
288 | push_punct!(push_caret_eq push_caret_eq_spanned '^' '='); | |
289 | push_punct!(push_colon push_colon_spanned ':'); | |
290 | push_punct!(push_colon2 push_colon2_spanned ':' ':'); | |
291 | push_punct!(push_comma push_comma_spanned ','); | |
292 | push_punct!(push_div push_div_spanned '/'); | |
293 | push_punct!(push_div_eq push_div_eq_spanned '/' '='); | |
294 | push_punct!(push_dot push_dot_spanned '.'); | |
295 | push_punct!(push_dot2 push_dot2_spanned '.' '.'); | |
296 | push_punct!(push_dot3 push_dot3_spanned '.' '.' '.'); | |
297 | push_punct!(push_dot_dot_eq push_dot_dot_eq_spanned '.' '.' '='); | |
298 | push_punct!(push_eq push_eq_spanned '='); | |
299 | push_punct!(push_eq_eq push_eq_eq_spanned '=' '='); | |
300 | push_punct!(push_ge push_ge_spanned '>' '='); | |
301 | push_punct!(push_gt push_gt_spanned '>'); | |
302 | push_punct!(push_le push_le_spanned '<' '='); | |
303 | push_punct!(push_lt push_lt_spanned '<'); | |
304 | push_punct!(push_mul_eq push_mul_eq_spanned '*' '='); | |
305 | push_punct!(push_ne push_ne_spanned '!' '='); | |
306 | push_punct!(push_or push_or_spanned '|'); | |
307 | push_punct!(push_or_eq push_or_eq_spanned '|' '='); | |
308 | push_punct!(push_or_or push_or_or_spanned '|' '|'); | |
309 | push_punct!(push_pound push_pound_spanned '#'); | |
310 | push_punct!(push_question push_question_spanned '?'); | |
311 | push_punct!(push_rarrow push_rarrow_spanned '-' '>'); | |
312 | push_punct!(push_larrow push_larrow_spanned '<' '-'); | |
313 | push_punct!(push_rem push_rem_spanned '%'); | |
314 | push_punct!(push_rem_eq push_rem_eq_spanned '%' '='); | |
315 | push_punct!(push_fat_arrow push_fat_arrow_spanned '=' '>'); | |
316 | push_punct!(push_semi push_semi_spanned ';'); | |
317 | push_punct!(push_shl push_shl_spanned '<' '<'); | |
318 | push_punct!(push_shl_eq push_shl_eq_spanned '<' '<' '='); | |
319 | push_punct!(push_shr push_shr_spanned '>' '>'); | |
320 | push_punct!(push_shr_eq push_shr_eq_spanned '>' '>' '='); | |
321 | push_punct!(push_star push_star_spanned '*'); | |
322 | push_punct!(push_sub push_sub_spanned '-'); | |
323 | push_punct!(push_sub_eq push_sub_eq_spanned '-' '='); | |
e74abb32 XL |
324 | |
325 | // Helper method for constructing identifiers from the `format_ident!` macro, | |
326 | // handling `r#` prefixes. | |
327 | // | |
328 | // Directly parsing the input string may produce a valid identifier, | |
329 | // although the input string was invalid, due to ignored characters such as | |
330 | // whitespace and comments. Instead, we always create a non-raw identifier | |
331 | // to validate that the string is OK, and only parse again if needed. | |
e74abb32 XL |
332 | pub fn mk_ident(id: &str, span: Option<Span>) -> Ident { |
333 | let span = span.unwrap_or_else(Span::call_site); | |
334 | ||
335 | let is_raw = id.starts_with("r#"); | |
336 | let unraw = Ident::new(if is_raw { &id[2..] } else { id }, span); | |
337 | if !is_raw { | |
338 | return unraw; | |
339 | } | |
340 | ||
341 | // At this point, the identifier is raw, and the unraw-ed version of it was | |
342 | // successfully converted into an identifier. Try to produce a valid raw | |
343 | // identifier by running the `TokenStream` parser, and unwrapping the first | |
344 | // token as an `Ident`. | |
345 | // | |
346 | // FIXME: When `Ident::new_raw` becomes stable, this method should be | |
347 | // updated to call it when available. | |
5869c6ff XL |
348 | if let Ok(ts) = id.parse::<TokenStream>() { |
349 | let mut iter = ts.into_iter(); | |
350 | if let (Some(TokenTree::Ident(mut id)), None) = (iter.next(), iter.next()) { | |
351 | id.set_span(span); | |
352 | return id; | |
e74abb32 | 353 | } |
e74abb32 | 354 | } |
5869c6ff XL |
355 | |
356 | panic!("not allowed as a raw identifier: `{}`", id); | |
e74abb32 XL |
357 | } |
358 | ||
359 | // Adapts from `IdentFragment` to `fmt::Display` for use by the `format_ident!` | |
360 | // macro, and exposes span information from these fragments. | |
361 | // | |
362 | // This struct also has forwarding implementations of the formatting traits | |
363 | // `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within | |
364 | // `format_ident!`. | |
365 | #[derive(Copy, Clone)] | |
366 | pub struct IdentFragmentAdapter<T: IdentFragment>(pub T); | |
367 | ||
368 | impl<T: IdentFragment> IdentFragmentAdapter<T> { | |
369 | pub fn span(&self) -> Option<Span> { | |
370 | self.0.span() | |
371 | } | |
372 | } | |
373 | ||
374 | impl<T: IdentFragment> fmt::Display for IdentFragmentAdapter<T> { | |
375 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
376 | IdentFragment::fmt(&self.0, f) | |
377 | } | |
378 | } | |
379 | ||
380 | impl<T: IdentFragment + fmt::Octal> fmt::Octal for IdentFragmentAdapter<T> { | |
381 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
382 | fmt::Octal::fmt(&self.0, f) | |
383 | } | |
384 | } | |
385 | ||
386 | impl<T: IdentFragment + fmt::LowerHex> fmt::LowerHex for IdentFragmentAdapter<T> { | |
387 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
388 | fmt::LowerHex::fmt(&self.0, f) | |
389 | } | |
390 | } | |
391 | ||
392 | impl<T: IdentFragment + fmt::UpperHex> fmt::UpperHex for IdentFragmentAdapter<T> { | |
393 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
394 | fmt::UpperHex::fmt(&self.0, f) | |
395 | } | |
396 | } | |
397 | ||
398 | impl<T: IdentFragment + fmt::Binary> fmt::Binary for IdentFragmentAdapter<T> { | |
399 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
400 | fmt::Binary::fmt(&self.0, f) | |
401 | } | |
402 | } |