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