1extern crate proc_macro;
2extern crate proc_macro2;
3extern crate syn;
4
5use proc_macro::TokenStream;
6use proc_macro2::TokenStream as TokenStream2;
7use proc_macro2::{Delimiter, Group, Literal, Punct, Spacing, Span, TokenTree};
8use proc_macro_error::{abort, proc_macro_error};
9use quote::{quote as qquote, quote_spanned as qquote_spanned, TokenStreamExt};
10use std::collections::{HashSet, VecDeque};
11use syn::{parse_quote, Expr, Ident, Path, Token};
12
13struct ParseEnvironment {
19 span: Expr,
20 path_proc_macro2: Path,
21 path_quote: Path,
22 path_core: Path,
23 id_stream: Ident,
24 id_counter: Ident,
25}
26
27impl syn::parse::Parse for ParseEnvironment {
28 fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result<Self> {
29 let mut fields: Vec<(Ident, Expr)> = Vec::new();
31 while !input.is_empty() {
32 let ident = input.parse()?;
33 input.parse::<Token![:]>()?;
34 let expr = input.parse()?;
35 fields.push((ident, expr));
36 if !input.is_empty() {
37 input.parse::<Token![,]>()?;
38 }
39 }
40 let mut this: ParseEnvironment = Default::default();
41 for (id, expr) in fields {
42 match (id.to_string().as_str(), expr) {
43 ("proc_macro2", Expr::Path(pat)) => {
44 this.path_proc_macro2 = pat.path;
45 }
46 ("quote", Expr::Path(pat)) => {
47 this.path_quote = pat.path;
48 }
49 ("core", Expr::Path(pat)) => {
50 this.path_core = pat.path;
51 }
52 ("span", expr) => {
53 this.span = expr;
54 }
55 (key, _) => {
56 return Err(input.error(format!("Bad config name: {}", key)));
57 }
58 }
59 }
60 Ok(this)
61 }
62}
63
64impl core::default::Default for ParseEnvironment {
65 fn default() -> Self {
66 Self {
67 span: parse_quote! { ::proc_macro2::Span::call_site() },
68 path_proc_macro2: parse_quote! { ::proc_macro2 },
69 path_quote: parse_quote! { ::template_quote },
70 path_core: parse_quote! { ::core },
71 id_stream: Ident::new("__template_quote_stream", Span::mixed_site()),
72 id_counter: Ident::new("__template_quote_idcnt", Span::mixed_site()),
73 }
74 }
75}
76
77fn eat_terminator(input: &mut VecDeque<TokenTree>) -> bool {
78 match (input.pop_front(), input.pop_front()) {
81 (Some(TokenTree::Punct(p1)), Some(TokenTree::Punct(p2)))
82 if p1.as_char() == '.' && p2.as_char() == '.' && p1.spacing() == Spacing::Joint =>
83 {
84 true
85 }
86 (a, b) => {
87 if let Some(b) = b {
88 input.push_front(b);
89 }
90 if let Some(a) = a {
91 input.push_front(a);
92 }
93 false
94 }
95 }
96}
97fn eat_comma(input: &mut VecDeque<TokenTree>) -> bool {
98 match input.pop_front() {
99 Some(TokenTree::Punct(p)) if p.as_char() == ',' && p.spacing() == Spacing::Alone => true,
100 Some(tt) => {
101 input.push_front(tt);
102 false
103 }
104 _ => false,
105 }
106}
107fn collect_ident(input: &mut VecDeque<TokenTree>) -> Result<Vec<Ident>, ()> {
108 fn collect_paren_stream(
109 mut input: VecDeque<TokenTree>,
110 ret: &mut Vec<Ident>,
111 ) -> Result<(), ()> {
112 while !input.is_empty() {
113 if eat_terminator(&mut input) {
116 if !input.is_empty() && !eat_comma(&mut input) {
117 return Err(());
118 }
119 continue;
120 }
121 ret.extend(collect_ident(&mut input)?);
122 if !input.is_empty() && !eat_comma(&mut input) {
123 return Err(());
124 }
125 }
126 Ok(())
127 }
128 let mut ret = Vec::new();
129 if matches!(
131 (input.front(), input.get(1)),
132 (Some(TokenTree::Punct(p1)), Some(TokenTree::Punct(p2)))
133 if p1.as_char() == ':' && p2.as_char() == ':' && p1.spacing() == Spacing::Joint
134 ) {
135 input.pop_front();
136 input.pop_front();
137 }
138 while matches!(input.front(), Some(TokenTree::Ident(id)) if id == "ref" || id == "mut") {
140 input.pop_front();
141 }
142 match input.pop_front() {
143 Some(TokenTree::Group(g))
145 if (g.delimiter() == Delimiter::Parenthesis || g.delimiter() == Delimiter::Bracket) =>
146 {
147 collect_paren_stream(g.stream().into_iter().collect(), &mut ret)?;
148 Ok(ret)
149 }
150 Some(TokenTree::Ident(id)) => {
151 loop {
152 match input.pop_front() {
153 Some(TokenTree::Punct(colon))
154 if colon.as_char() == ':' && colon.spacing() == Spacing::Joint =>
155 {
156 if matches!(
157 input.pop_front(),
158 Some(TokenTree::Punct(colon)) if colon.as_char() == ':' && colon.spacing() == Spacing::Alone
159 ) && matches!(input.pop_front(), Some(TokenTree::Ident(_)))
160 {
161 continue;
162 } else {
163 return Err(());
164 }
165 }
166 Some(o) => input.push_front(o),
167 None => (),
168 }
169 break;
170 }
171 match input.pop_front() {
172 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => {
174 collect_paren_stream(g.stream().into_iter().collect(), &mut ret)?;
175 Ok(ret)
176 }
177 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => {
179 let mut inner: VecDeque<TokenTree> = g.stream().into_iter().collect();
180 while !inner.is_empty() && !eat_terminator(&mut inner) {
181 while matches!(inner.front(), Some(TokenTree::Ident(id)) if id == "ref" || id == "mut")
183 {
184 inner.pop_front();
185 }
186 match inner.pop_front() {
187 Some(TokenTree::Ident(key)) => {
188 if matches!(inner.front(), Some(TokenTree::Punct(colon)) if colon.as_char() == ':')
192 {
193 inner.pop_front(); ret.extend(collect_ident(&mut inner)?);
195 } else {
196 ret.push(key);
197 }
198 }
199 _ => return Err(()),
200 }
201 if !inner.is_empty() && !eat_comma(&mut inner) {
202 return Err(());
203 }
204 }
205 Ok(ret)
206 }
207 Some(o) => {
209 input.push_front(o);
210 ret.push(id);
211 Ok(ret)
212 }
213 None => {
214 ret.push(id);
215 Ok(ret)
216 }
217 }
218 }
219 _ => Err(()),
220 }
221}
222
223fn collect_ident_eq(input: &mut VecDeque<TokenTree>) -> Result<Vec<Ident>, ()> {
224 let v = collect_ident(input)?;
225 match input.pop_front() {
226 Some(TokenTree::Punct(eq)) if eq.as_char() == '=' && eq.spacing() == Spacing::Alone => {
227 Ok(v)
228 }
229 _ => Err(()),
230 }
231}
232
233fn collect_punct_in_expr(mut stream: VecDeque<TokenTree>) -> (Vec<Ident>, VecDeque<TokenTree>) {
234 let mut output = VecDeque::new();
235 let mut ids = Vec::new();
236 while let Some(tt) = stream.pop_front() {
237 match tt {
238 TokenTree::Punct(punct) if punct.as_char() == '#' => match stream.pop_front() {
239 Some(TokenTree::Ident(id)) => {
240 ids.push(id.clone());
241 output.push_back(TokenTree::Ident(id));
242 }
243 Some(o) => {
244 output.push_back(TokenTree::Punct(punct));
245 output.push_back(o);
246 }
247 None => {
248 output.push_back(TokenTree::Punct(punct));
249 }
250 },
251 TokenTree::Group(group) => {
255 let (inner_ids, inner) =
256 collect_punct_in_expr(group.stream().into_iter().collect());
257 ids.extend(inner_ids);
258 let mut new_group = Group::new(group.delimiter(), inner.into_iter().collect());
259 new_group.set_span(group.span());
260 output.push_back(TokenTree::Group(new_group));
261 }
262 o => output.push_back(o),
263 }
264 }
265 (ids, output)
266}
267
268fn hash_will_be_processed(next: Option<&TokenTree>, rest: &VecDeque<TokenTree>) -> bool {
269 match next {
270 Some(TokenTree::Ident(_)) => true,
271 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => true,
272 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => {
273 match (rest.front(), rest.get(1)) {
274 (Some(TokenTree::Group(group2)), _) if group2.delimiter() == Delimiter::Brace => {
275 true
276 }
277 (Some(TokenTree::Punct(punct)), _) if punct.as_char() == '*' => true,
278 (Some(TokenTree::Punct(_)), Some(TokenTree::Punct(punct2)))
279 if punct2.as_char() == '*' =>
280 {
281 true
282 }
283 (Some(TokenTree::Punct(_)), Some(TokenTree::Group(group2)))
284 if group2.delimiter() == Delimiter::Brace =>
285 {
286 true
287 }
288 _ => false,
289 }
290 }
291 _ => false,
292 }
293}
294
295impl ParseEnvironment {
296 fn emit_ident(&self, ident: &Ident) -> TokenStream2 {
297 let Self {
298 span,
299 path_proc_macro2,
300 path_quote,
301 id_stream,
302 ..
303 } = self;
304 let s = ident.to_string();
305 if let Some(s) = s.strip_prefix("r#") {
306 qquote! {
307 <_ as #path_quote::ToTokens>::to_tokens(&#path_proc_macro2::Ident::new_raw(#s, (#span)), &mut #id_stream);
308 }
309 } else {
310 qquote! {
311 <_ as #path_quote::ToTokens>::to_tokens(&#path_proc_macro2::Ident::new(#s, (#span)), &mut #id_stream);
312 }
313 }
314 }
315
316 fn emit_literal(&self, lit: &Literal) -> TokenStream2 {
317 let Self {
318 span,
319 path_proc_macro2,
320 id_stream,
321 ..
322 } = self;
323 let s = lit.to_string();
324 qquote! {
325 {
326 let ts: #path_proc_macro2::TokenStream = #s.parse().expect("Invalid literal str");
327 #id_stream.extend(ts.into_iter().map(|mut t| {
328 t.set_span(#span);
329 t
330 }));
331 }
332 }
333 }
334
335 fn emit_punct(&self, punct: &Punct) -> TokenStream2 {
336 let Self {
337 span,
338 path_proc_macro2,
339 path_quote,
340 id_stream,
341 ..
342 } = self;
343 let p = punct.as_char();
344 let spacing = match punct.spacing() {
345 Spacing::Alone => qquote! {#path_proc_macro2::Spacing::Alone},
346 Spacing::Joint => qquote! {#path_proc_macro2::Spacing::Joint},
347 };
348 qquote! {
349 <_ as #path_quote::ToTokens>::to_tokens(&{
350 let mut p = #path_proc_macro2::Punct::new(#p, #spacing);
351 p.set_span(#span);
352 p
353 }, &mut #id_stream);
354 }
355 }
356
357 fn emit_punct_with_spacing(&self, punct: &Punct, spacing: Spacing) -> TokenStream2 {
358 let mut p = Punct::new(punct.as_char(), spacing);
359 p.set_span(punct.span());
360 self.emit_punct(&p)
361 }
362
363 fn emit_group(&self, delim: &Delimiter, inner: TokenStream2) -> TokenStream2 {
364 let Self {
365 span,
366 path_proc_macro2,
367 path_core,
368 id_stream,
369 ..
370 } = self;
371 let delim = match delim {
372 Delimiter::Parenthesis => qquote! { #path_proc_macro2::Delimiter::Parenthesis },
373 Delimiter::Brace => qquote! { #path_proc_macro2::Delimiter::Brace },
374 Delimiter::Bracket => qquote! { #path_proc_macro2::Delimiter::Bracket },
375 Delimiter::None => qquote! { #path_proc_macro2::Delimiter::None },
376 };
377 qquote! {
378 #id_stream.extend(
379 #path_core::option::Option::Some(
380 #path_proc_macro2::TokenTree::Group(
381 {
382 let mut g = #path_proc_macro2::Group::new(#delim, {
383 let mut #id_stream = #path_proc_macro2::TokenStream::new();
384 { #inner }
385 #id_stream
386 });
387 g.set_span(#span);
388 g
389 }
390 )
391 )
392 );
393 }
394 }
395
396 fn parse_conditional(
397 &self,
398 conditional: TokenStream2,
399 input: VecDeque<TokenTree>,
400 vals: &mut HashSet<Ident>,
401 sep: Option<Punct>,
402 inline_expr_dict: &mut Vec<(Ident, TokenStream2, Span)>,
403 ) -> TokenStream2 {
404 fn parse_if_inner(
405 mut cond: VecDeque<TokenTree>,
406 ) -> (Vec<Ident>, Vec<Ident>, Vec<TokenTree>) {
407 let span_ts: TokenStream2 = cond.iter().cloned().collect();
408 let mut bak: Vec<_> = cond.iter().cloned().collect();
409 match cond.pop_front() {
410 Some(TokenTree::Ident(id_let)) if id_let == "let" => {
411 let removing_ids = collect_ident_eq(&mut cond).unwrap_or_else(|_| {
412 abort!(span_ts, "malformed `if let` conditional in template")
413 });
414 bak.truncate(bak.len() - cond.len());
415 let (appending_ids, rem) = collect_punct_in_expr(cond);
416 bak.extend(rem);
417 (removing_ids, appending_ids, bak)
418 }
419 Some(o) => {
420 cond.push_front(o);
421 bak.truncate(bak.len() - cond.len());
422 let (appending_ids, rem) = collect_punct_in_expr(cond);
423 bak.extend(rem);
424 (vec![], appending_ids, bak)
425 }
426 None => abort!(span_ts, "empty `if` conditional in template"),
427 }
428 }
429 let mut cond: VecDeque<TokenTree> = conditional.clone().into_iter().collect();
430 let cond_len = cond.len();
431 let (removing_ids, appending_ids, cond) = match (cond.pop_front(), sep.is_some()) {
432 (Some(TokenTree::Ident(id)), false) if id == "if" => {
433 let (removing_ids, appending_ids, rem) = parse_if_inner(cond);
434 (
435 removing_ids,
436 appending_ids,
437 Some(TokenTree::Ident(id)).into_iter().chain(rem).collect(),
438 )
439 }
440 (Some(TokenTree::Ident(id)), false) if id == "else" => {
441 match cond.pop_front() {
442 Some(TokenTree::Ident(id_if)) if id_if == "if" => {
444 let (removing_ids, appending_ids, rem) = parse_if_inner(cond);
445 (
446 removing_ids,
447 appending_ids,
448 vec![TokenTree::Ident(id), TokenTree::Ident(id_if)]
449 .into_iter()
450 .chain(rem)
451 .collect(),
452 )
453 }
454 Some(_) => {
455 abort!(
456 conditional.clone(),
457 "malformed `else` in template (expected `else` or `else if`)"
458 )
459 }
460 None => (vec![], vec![], conditional),
461 }
462 }
463 (Some(TokenTree::Ident(id)), false) if id == "let" => {
464 let removing_ids = collect_ident_eq(&mut cond).unwrap_or_else(|_| {
465 abort!(conditional.clone(), "malformed `let` binding in template")
466 });
467 let n = cond_len - cond.len();
468 let (appending_ids, rem) = collect_punct_in_expr(cond);
469 let conditional: TokenStream2 =
470 conditional.clone().into_iter().take(n).chain(rem).collect();
471 (removing_ids, appending_ids, qquote! {#conditional ;})
472 }
473 (Some(TokenTree::Ident(id)), _) if id == "while" => match cond.pop_front() {
474 Some(TokenTree::Ident(id_let)) if id_let == "let" => {
475 let removing_ids = collect_ident_eq(&mut cond).unwrap_or_else(|_| {
476 abort!(
477 conditional.clone(),
478 "malformed `while let` loop in template"
479 )
480 });
481 let n = cond_len - cond.len();
482 let (appending_ids, rem) = collect_punct_in_expr(cond);
483 let conditional: TokenStream2 =
484 conditional.clone().into_iter().take(n).chain(rem).collect();
485 (removing_ids, appending_ids, conditional)
486 }
487 Some(o) => {
488 cond.push_front(o);
489 let n = cond_len - cond.len();
490 let (appending_ids, rem) = collect_punct_in_expr(cond);
491 let conditional: TokenStream2 =
492 conditional.clone().into_iter().take(n).chain(rem).collect();
493 (vec![], appending_ids, conditional)
494 }
495 None => abort!(conditional.clone(), "empty `while` conditional in template"),
496 },
497 (Some(TokenTree::Ident(id)), _) if id == "for" => {
498 match (collect_ident(&mut cond), cond.pop_front()) {
499 (Ok(v), Some(TokenTree::Ident(id_in))) if id_in == "in" => {
500 let n = cond_len - cond.len();
501 let (appending_ids, rem) = collect_punct_in_expr(cond);
502 let conditional: TokenStream2 =
503 conditional.clone().into_iter().take(n).chain(rem).collect();
504 (v, appending_ids, conditional)
505 }
506 _ => abort!(
507 conditional.clone(),
508 "malformed `for` loop in template (expected `for <pat> in <expr>`)"
509 ),
510 }
511 }
512 _ => abort!(
513 conditional.clone(),
514 "malformed conditional in template (expected `if`, `else`, `let`, `while` or `for`)"
515 ),
516 };
517 let inner = self.parse_inner(input, vals, inline_expr_dict);
518 for id in removing_ids {
519 vals.remove(&id);
520 }
521 for id in appending_ids {
522 vals.insert(id);
523 }
524 if let Some(sep) = sep {
525 let code_sep = self.emit_punct(&sep);
526 let id_counter = &self.id_counter;
527 qquote! {
528 {
529 let mut #id_counter = false;
530 #cond {
531 if #id_counter { #code_sep }
532 #id_counter = true;
533 #inner
534 }
535 }
536 }
537 } else {
538 qquote! {
539 #cond {
540 #inner
541 }
542 }
543 }
544 }
545
546 fn parse_iteration(
547 &self,
548 input: VecDeque<TokenTree>,
549 vals: &mut HashSet<Ident>,
550 sep: Option<Punct>,
551 inline_expr_dict: &mut Vec<(Ident, TokenStream2, Span)>,
552 ) -> TokenStream2 {
553 let Self {
554 path_quote,
555 path_core,
556 ..
557 } = self;
558 let debug_str = input
559 .iter()
560 .take(6)
561 .map(|item| match item {
562 TokenTree::Group(g) => match g.delimiter() {
563 Delimiter::Parenthesis => "( .. )".to_owned(),
564 Delimiter::Brace => "{ .. }".to_owned(),
565 Delimiter::Bracket => "[ .. ]".to_owned(),
566 Delimiter::None => "..".to_owned(),
567 },
568 _ => format!("{}", item),
569 })
570 .chain(if input.len() > 6 {
571 Some("..".to_owned())
572 } else {
573 None
574 })
575 .collect::<Vec<_>>()
576 .join(" ");
577 let group_tokens: TokenStream2 = input.iter().cloned().collect();
580 let mut inner_vals = HashSet::new();
581 let inner_output = self.parse_inner(input, &mut inner_vals, inline_expr_dict);
582 let code_sep = sep.map(|sep| self.emit_punct(&Punct::new(sep.as_char(), Spacing::Alone)));
583 let val_nam = code_sep
584 .as_ref()
585 .map(|_| self.id_counter.clone())
586 .into_iter()
587 .collect::<Vec<_>>();
588 vals.extend(inner_vals.iter().cloned());
589 let vars: Vec<Ident> = inner_vals.iter().cloned().collect();
590 if vars.is_empty() {
591 abort!(
592 group_tokens,
593 "Repetition group `#( {} )*` contains no interpolation variable (`#var`)", debug_str;
594 note = "a repetition needs at least one `#var` inside it to drive the iteration"
595 );
596 }
597 let it_idents: Vec<Ident> = (0..vars.len())
600 .map(|i| Ident::new(&format!("__template_quote_it_{}", i), Span::mixed_site()))
601 .collect();
602 let m_idents: Vec<Ident> = (0..vars.len())
603 .map(|i| Ident::new(&format!("__template_quote_m_{}", i), Span::mixed_site()))
604 .collect();
605 let bindings = vars
606 .iter()
607 .zip(&it_idents)
608 .zip(&m_idents)
609 .map(|((var, it), m)| {
610 qquote! {
611 #[allow(unused_mut)]
612 let (mut #it, #m) = (#var).__template_quote_into_iter();
613 }
614 });
615 let checker = m_idents
617 .iter()
618 .fold(qquote! {false}, |acc, m| qquote! {#acc || #m});
619 let (first_var, rest_vars) = vars.split_first().unwrap();
622 let (first_it, rest_it) = it_idents.split_first().unwrap();
623 let idents_in_tuple = rest_vars
624 .iter()
625 .fold(qquote! {#first_var}, |prev, next| qquote! {(#prev, #next)});
626 let zipped = rest_it
627 .iter()
628 .fold(qquote! {#first_it}, |prev, next| qquote! {#prev.zip(#next)});
629 qquote! {
630 {
631 #(let mut #val_nam = false;)*
632 #[allow(unused_imports)]
633 use #path_quote::__private::ext::{
634 RepAsIteratorExt as _, RepIteratorExt as _, RepToTokensExt as _,
635 };
636 #(#bindings)*
637 if !(#checker) {
638 #path_core::panic!("Cannot iterate the group: #( {} )*", #debug_str);
639 }
640 for #idents_in_tuple in #zipped {
641 #(
642 if #val_nam { #code_sep }
643 #val_nam = true;
644 )*
645 #inner_output
646 }
647 }
648 }
649 }
650
651 fn parse(&self, input: TokenStream2) -> TokenStream2 {
652 let Self {
653 path_proc_macro2,
654 id_stream,
655 ..
656 } = self;
657 let mut hs = HashSet::new();
658 let mut dict = Vec::new();
659 let result = self.parse_inner(input.into_iter().collect(), &mut hs, &mut dict);
660 let inline_vals_code =
661 dict.into_iter()
662 .fold(TokenStream2::new(), |acc, (id, inner, span)| {
663 qquote_spanned! { span =>
664 #acc
665 let #id = { #inner };
666 }
667 });
668 qquote! {
669 {
670 let mut #id_stream= #path_proc_macro2::TokenStream::new();
671 #inline_vals_code
672 { #result }
673 #id_stream
674 }
675 }
676 }
677
678 fn parse_inner(
679 &self,
680 mut input: VecDeque<TokenTree>,
681 vals: &mut HashSet<Ident>,
682 inline_expr_dict: &mut Vec<(Ident, TokenStream2, Span)>,
683 ) -> TokenStream2 {
684 let Self {
685 path_quote,
686 id_stream,
687 ..
688 } = self;
689 let mut output = TokenStream2::new();
690 while let Some(token) = input.pop_front() {
691 match token {
692 TokenTree::Group(group) => {
693 let inner = group.stream().into_iter().collect();
694 let result = self.parse_inner(inner, vals, inline_expr_dict);
695 let result = self.emit_group(&group.delimiter(), result);
696 output.append_all(result);
697 }
698 TokenTree::Punct(punct) => match (punct.as_char(), input.pop_front()) {
699 ('#', Some(TokenTree::Ident(ident))) => {
701 vals.insert(ident.clone());
702 output.append_all(
703 qquote! { <_ as #path_quote::ToTokens>::to_tokens(&#ident, &mut #id_stream); },
704 );
705 }
706 ('#', Some(TokenTree::Group(group)))
708 if group.delimiter() == Delimiter::Brace =>
709 {
710 let inner = group.stream().into_iter().collect::<VecDeque<_>>();
711 if inner.is_empty() {
712 } else {
714 let is_expr = !matches!(
717 inner.back(),
718 Some(TokenTree::Punct(p)) if p.as_char() == ';'
719 );
720 let (appending_ids, inner) = collect_punct_in_expr(inner);
721 for id in appending_ids {
722 vals.insert(id);
723 }
724 let stream: TokenStream2 = inner.into_iter().collect();
725 if is_expr {
726 output.append_all(qquote! {
727 <_ as #path_quote::ToTokens>::to_tokens(&{
728 #stream
729 }, &mut #id_stream);
730 });
731 } else {
732 output.append_all(qquote! {
733 { #stream }
734 });
735 }
736 }
737 }
738 ('#', Some(TokenTree::Group(group)))
739 if group.delimiter() == Delimiter::Parenthesis =>
740 {
741 match input.pop_front() {
742 Some(TokenTree::Group(group2))
744 if group2.delimiter() == Delimiter::Brace =>
745 {
746 output.append_all(self.parse_conditional(
747 group.stream(),
748 group2.stream().into_iter().collect(),
749 vals,
750 None,
751 inline_expr_dict,
752 ));
753 }
754 Some(TokenTree::Punct(punct)) if punct.as_char() == '*' => output
756 .append_all(self.parse_iteration(
757 group.stream().into_iter().collect(),
758 vals,
759 None,
760 inline_expr_dict,
761 )),
762 Some(TokenTree::Punct(punct0)) => match input.pop_front() {
763 Some(TokenTree::Punct(punct1)) if punct1.as_char() == '*' => output
765 .append_all(self.parse_iteration(
766 group.stream().into_iter().collect(),
767 vals,
768 Some(punct0),
769 inline_expr_dict,
770 )),
771 Some(TokenTree::Group(group2))
773 if group2.delimiter() == Delimiter::Brace =>
774 {
775 output.append_all(self.parse_conditional(
776 group.stream(),
777 group2.stream().into_iter().collect(),
778 vals,
779 Some(punct0),
780 inline_expr_dict,
781 ));
782 }
783 o => {
784 if let Some(o) = o {
785 input.push_front(o);
786 }
787 input.push_front(TokenTree::Punct(punct0));
788 input.push_front(TokenTree::Group(group));
789 output.append_all(self.emit_punct(&punct));
790 }
791 },
792 o => {
793 if let Some(o) = o {
794 input.push_front(o)
795 }
796 input.push_front(TokenTree::Group(group));
797 output.append_all(self.emit_punct(&punct));
798 }
799 }
800 }
801 (_, o) => {
802 let adjust_joint_before_hash = punct.spacing() == Spacing::Joint
809 && matches!(o, Some(TokenTree::Punct(ref p)) if p.as_char() == '#')
810 && hash_will_be_processed(input.front(), &input);
811 if let Some(o) = o {
812 input.push_front(o);
813 }
814 if adjust_joint_before_hash {
815 output.append_all(self.emit_punct_with_spacing(&punct, Spacing::Alone));
816 } else {
817 output.append_all(self.emit_punct(&punct));
818 }
819 }
820 },
821 TokenTree::Ident(o) => output.append_all(self.emit_ident(&o)),
822 TokenTree::Literal(o) => output.append_all(self.emit_literal(&o)),
823 }
824 }
825 output
826 }
827}
828
829#[proc_macro]
830#[proc_macro_error]
831pub fn quote(input: TokenStream) -> TokenStream {
832 let env: ParseEnvironment = Default::default();
833 env.parse(input.into()).into()
834}
835
836#[proc_macro]
837#[proc_macro_error]
838pub fn quote_configured(input: TokenStream) -> TokenStream {
839 let input0: TokenStream2 = input.into();
840 let mut input = VecDeque::new();
841 input.extend(input0.into_iter());
842 let env: ParseEnvironment = match input.pop_front() {
843 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => syn::parse2(g.stream())
844 .unwrap_or_else(|e| abort!(g, "malformed `quote_configured!` config block: {}", e)),
845 Some(other) => abort!(
846 other,
847 "`quote_configured!` expects a `{{ key: path, ... }}` config block first"
848 ),
849 None => abort!(
850 Span::call_site(),
851 "`quote_configured!` expects a `{{ key: path, ... }} => ...` invocation"
852 ),
853 };
854 match input.pop_front() {
855 Some(TokenTree::Punct(p)) if p.as_char() == '=' && p.spacing() == Spacing::Joint => (),
856 Some(other) => abort!(
857 other,
858 "`quote_configured!` expects `=>` after the config block"
859 ),
860 None => abort!(
861 Span::call_site(),
862 "`quote_configured!` expects `=>` after the config block"
863 ),
864 }
865 match input.pop_front() {
866 Some(TokenTree::Punct(p)) if p.as_char() == '>' && p.spacing() == Spacing::Alone => (),
867 Some(other) => abort!(
868 other,
869 "`quote_configured!` expects `=>` after the config block"
870 ),
871 None => abort!(
872 Span::call_site(),
873 "`quote_configured!` expects `=>` after the config block"
874 ),
875 }
876 let mut stream = TokenStream2::new();
877 stream.extend(input);
878 env.parse(stream).into()
879}
880
881#[proc_macro]
882#[proc_macro_error]
883pub fn quote_spanned(input: TokenStream) -> TokenStream {
884 let input0: TokenStream2 = input.into();
885 let mut input = VecDeque::new();
886 input.extend(input0.into_iter());
887 let mut span = TokenStream2::new(); loop {
889 match input.pop_front() {
890 Some(TokenTree::Punct(p)) if p.as_char() == '=' && p.spacing() == Spacing::Joint => {
891 match input.pop_front() {
892 Some(TokenTree::Punct(p))
893 if p.as_char() == '>' && p.spacing() == Spacing::Alone =>
894 {
895 break;
897 }
898 Some(o) => {
899 span.extend(Some(TokenTree::Punct(p)));
900 input.push_front(o);
901 }
902 None => {
903 span.extend(Some(TokenTree::Punct(p)));
904 }
905 }
906 }
907 Some(o) => span.extend(Some(o)),
908 None => abort!(
909 Span::call_site(),
910 "`quote_spanned!` expects `<span-expr> => <tokens>` (no `=>` found)"
911 ),
912 }
913 }
914 let mut env: ParseEnvironment = Default::default();
915 let span_tokens = span.clone();
916 env.span = syn::parse2(span).unwrap_or_else(|e| {
917 abort!(
918 span_tokens,
919 "the `<span>` before `=>` in `quote_spanned!` must be an expression: {}",
920 e
921 )
922 });
923 let mut stream = TokenStream2::new();
924 stream.extend(input);
925 env.parse(stream).into()
926}