template_quote_impl/
lib.rs

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, Literal, Punct, Spacing, Span, TokenTree};
8use proc_macro_error::ResultExt;
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
13/// The parser for `quote!` macro.
14///
15/// this struct has some global configs to be initialized using
16/// `Default::default()` or `syn::parse::Parse::parse()`. User can specify
17/// configs using `quote_configured!` macro.
18struct ParseEnvironment {
19	span: Expr,
20	path_proc_macro2: Path,
21	path_quote: Path,
22	path_core: Path,
23	id_stream: Ident,
24	id_repeat: Ident,
25	id_counter: Ident,
26}
27
28impl syn::parse::Parse for ParseEnvironment {
29	fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result<Self> {
30		// Read comma-separated `key = value` fields
31		let mut fields: Vec<(Ident, Expr)> = Vec::new();
32		while !input.is_empty() {
33			let ident = input.parse()?;
34			input.parse::<Token![:]>()?;
35			let expr = input.parse()?;
36			fields.push((ident, expr));
37			if !input.is_empty() {
38				input.parse::<Token![,]>()?;
39			}
40		}
41		let mut this: ParseEnvironment = Default::default();
42		for (id, expr) in fields {
43			match (id.to_string().as_str(), expr) {
44				("proc_macro2", Expr::Path(pat)) => {
45					this.path_proc_macro2 = pat.path;
46				}
47				("quote", Expr::Path(pat)) => {
48					this.path_quote = pat.path;
49				}
50				("core", Expr::Path(pat)) => {
51					this.path_core = pat.path;
52				}
53				("span", expr) => {
54					this.span = expr;
55				}
56				(key, _) => {
57					return Err(input.error(&format!("Bad config name: {}", key)));
58				}
59			}
60		}
61		Ok(this)
62	}
63}
64
65impl core::default::Default for ParseEnvironment {
66	fn default() -> Self {
67		Self {
68			span: parse_quote! { ::proc_macro2::Span::call_site() },
69			path_proc_macro2: parse_quote! { ::proc_macro2 },
70			path_quote: parse_quote! { ::template_quote },
71			path_core: parse_quote! { ::core },
72			id_stream: parse_quote! { __template_quote_stream },
73			id_repeat: parse_quote! { __TemplateQuote_Repeat },
74			id_counter: parse_quote! { __template_quote_idcnt },
75		}
76	}
77}
78
79fn eat_terminator(input: &mut VecDeque<TokenTree>) -> bool {
80	match (input.pop_front(), input.pop_front(), input.pop_front()) {
81		(Some(TokenTree::Punct(p1)), Some(TokenTree::Punct(p2)), None)
82			if p1.as_char() == '.'
83				&& p2.as_char() == '.'
84				&& p1.spacing() == Spacing::Joint
85				&& p2.spacing() == Spacing::Alone =>
86		{
87			return true;
88		}
89		(Some(tt1), Some(tt2), Some(tt3)) => {
90			input.push_front(tt3);
91			input.push_front(tt2);
92			input.push_front(tt1);
93		}
94		(Some(tt1), Some(tt2), None) => {
95			input.push_front(tt2);
96			input.push_front(tt1);
97		}
98		(Some(tt1), None, None) => {
99			input.push_front(tt1);
100		}
101		_ => (),
102	}
103	false
104}
105fn eat_comma(input: &mut VecDeque<TokenTree>) -> bool {
106	match input.pop_front() {
107		Some(TokenTree::Punct(p)) if p.as_char() == ',' && p.spacing() == Spacing::Alone => true,
108		Some(tt) => {
109			input.push_front(tt);
110			false
111		}
112		_ => false,
113	}
114}
115fn collect_ident(input: &mut VecDeque<TokenTree>) -> Result<Vec<Ident>, ()> {
116	fn collect_paren_stream(
117		mut input: VecDeque<TokenTree>,
118		ret: &mut Vec<Ident>,
119	) -> Result<(), ()> {
120		while input.len() > 0 && !eat_terminator(&mut input) {
121			ret.extend(collect_ident(&mut input)?);
122			if input.len() > 0 && !eat_comma(&mut input) {
123				return Err(());
124			}
125		}
126		Ok(())
127	}
128	let mut ret = Vec::new();
129	match input.pop_front() {
130		// Parse `let (..) = ..`
131		Some(TokenTree::Group(g))
132			if (g.delimiter() == Delimiter::Parenthesis || g.delimiter() == Delimiter::Bracket) =>
133		{
134			collect_paren_stream(g.stream().into_iter().collect(), &mut ret)?;
135			Ok(ret)
136		}
137		Some(TokenTree::Ident(id)) => {
138			loop {
139				match input.pop_front() {
140					Some(TokenTree::Punct(colon))
141						if colon.as_char() == ':' && colon.spacing() == Spacing::Joint =>
142					{
143						if matches!(
144						input.pop_front(),
145						Some(TokenTree::Punct(colon)) if colon.as_char() == ':' && colon.spacing() == Spacing::Alone
146						) && matches!(input.pop_front(), Some(TokenTree::Ident(_)))
147						{
148							continue;
149						} else {
150							return Err(());
151						}
152					}
153					Some(o) => input.push_front(o),
154					None => (),
155				}
156				break;
157			}
158			match input.pop_front() {
159				// Parse `let Ident ( .. ) = ..`
160				Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => {
161					collect_paren_stream(g.stream().into_iter().collect(), &mut ret)?;
162					Ok(ret)
163				}
164				// Parse `let Ident { key: value, value2, ... } = ..`
165				Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => {
166					let mut inner: VecDeque<TokenTree> = g.stream().into_iter().collect();
167					while inner.len() > 0 && !eat_terminator(&mut inner) {
168						match inner.pop_front().unwrap() {
169							TokenTree::Ident(key) => match (inner.pop_front(), inner.pop_front()) {
170								(Some(TokenTree::Punct(colon)), Some(TokenTree::Ident(value)))
171									if colon.as_char() == ':'
172										&& colon.spacing() == Spacing::Alone =>
173								{
174									ret.push(value);
175								}
176								(item1, item2) => {
177									if let Some(tt2) = item2 {
178										inner.push_front(tt2);
179									}
180									if let Some(tt1) = item1 {
181										inner.push_front(tt1);
182									}
183									ret.push(key)
184								}
185							},
186							_ => return Err(()),
187						}
188						if inner.len() > 0 && !eat_comma(&mut inner) {
189							return Err(());
190						}
191					}
192					Ok(ret)
193				}
194				// Parse `let ident = ..`
195				Some(o) => {
196					input.push_front(o);
197					ret.push(id);
198					Ok(ret)
199				}
200				None => {
201					ret.push(id);
202					Ok(ret)
203				}
204			}
205		}
206		_ => Err(()),
207	}
208}
209
210fn collect_ident_eq(input: &mut VecDeque<TokenTree>) -> Result<Vec<Ident>, ()> {
211	let v = collect_ident(input)?;
212	match input.pop_front() {
213		Some(TokenTree::Punct(eq)) if eq.as_char() == '=' && eq.spacing() == Spacing::Alone => {
214			Ok(v)
215		}
216		_ => Err(()),
217	}
218}
219
220fn collect_punct_in_expr(mut stream: VecDeque<TokenTree>) -> (Vec<Ident>, VecDeque<TokenTree>) {
221	let mut output = VecDeque::new();
222	let mut ids = Vec::new();
223	while let Some(tt) = stream.pop_front() {
224		match tt {
225			TokenTree::Punct(punct) if punct.as_char() == '#' => match stream.pop_front() {
226				Some(TokenTree::Ident(id)) => {
227					ids.push(id.clone());
228					output.push_back(TokenTree::Ident(id));
229				}
230				Some(o) => {
231					output.push_back(TokenTree::Punct(punct));
232					output.push_back(o);
233				}
234				None => {
235					output.push_back(TokenTree::Punct(punct));
236				}
237			},
238			o => output.push_back(o),
239		}
240	}
241	(ids, output)
242}
243
244impl ParseEnvironment {
245	fn emit_ident(&self, ident: &Ident) -> TokenStream2 {
246		let Self {
247			span,
248			path_proc_macro2,
249			path_quote,
250			id_stream,
251			..
252		} = self;
253		let s = ident.to_string();
254		if s.starts_with("r#") {
255			let s = &s[2..];
256			qquote! {
257				<_ as #path_quote::ToTokens>::to_tokens(&#path_proc_macro2::Ident::new_raw(#s, (#span)), &mut #id_stream);
258			}
259		} else {
260			qquote! {
261				<_ as #path_quote::ToTokens>::to_tokens(&#path_proc_macro2::Ident::new(#s, (#span)), &mut #id_stream);
262			}
263		}
264	}
265
266	fn emit_literal(&self, lit: &Literal) -> TokenStream2 {
267		let Self {
268			span,
269			path_proc_macro2,
270			id_stream,
271			..
272		} = self;
273		let s = lit.to_string();
274		qquote! {
275			{
276				let ts: #path_proc_macro2::TokenStream = #s.parse().expect("Invalid literal str");
277				#id_stream.extend(ts.into_iter().map(|mut t| {
278					t.set_span(#span);
279					t
280				}));
281			}
282		}
283	}
284
285	fn emit_punct(&self, punct: &Punct) -> TokenStream2 {
286		let Self {
287			span,
288			path_proc_macro2,
289			path_quote,
290			id_stream,
291			..
292		} = self;
293		let p = punct.as_char();
294		let spacing = match punct.spacing() {
295			Spacing::Alone => qquote! {#path_proc_macro2::Spacing::Alone},
296			Spacing::Joint => qquote! {#path_proc_macro2::Spacing::Joint},
297		};
298		qquote! {
299			<_ as #path_quote::ToTokens>::to_tokens(&{
300				let mut p = #path_proc_macro2::Punct::new(#p, #spacing);
301				p.set_span(#span);
302				p
303			}, &mut #id_stream);
304		}
305	}
306
307	fn emit_group(&self, delim: &Delimiter, inner: TokenStream2) -> TokenStream2 {
308		let Self {
309			span,
310			path_proc_macro2,
311			path_core,
312			id_stream,
313			..
314		} = self;
315		let delim = match delim {
316			Delimiter::Parenthesis => qquote! { #path_proc_macro2::Delimiter::Parenthesis },
317			Delimiter::Brace => qquote! { #path_proc_macro2::Delimiter::Brace },
318			Delimiter::Bracket => qquote! { #path_proc_macro2::Delimiter::Bracket },
319			Delimiter::None => qquote! { #path_proc_macro2::Delimiter::None },
320		};
321		qquote! {
322			#id_stream.extend(
323				#path_core::option::Option::Some(
324					#path_proc_macro2::TokenTree::Group(
325						{
326							let mut g = #path_proc_macro2::Group::new(#delim, {
327								let mut #id_stream = #path_proc_macro2::TokenStream::new();
328								{ #inner }
329								#id_stream
330							});
331							g.set_span(#span);
332							g
333						}
334					)
335				)
336			);
337		}
338	}
339
340	fn parse_conditional(
341		&self,
342		conditional: TokenStream2,
343		input: VecDeque<TokenTree>,
344		vals: &mut HashSet<Ident>,
345		sep: Option<Punct>,
346		inline_expr_dict: &mut Vec<(Ident, TokenStream2, Span)>,
347	) -> TokenStream2 {
348		fn parse_if_inner(
349			mut cond: VecDeque<TokenTree>,
350		) -> (Vec<Ident>, Vec<Ident>, Vec<TokenTree>) {
351			let mut bak: Vec<_> = cond.iter().cloned().collect();
352			match cond.pop_front() {
353				Some(TokenTree::Ident(id_let)) if &id_let.to_string() == "let" => {
354					let removing_ids =
355						collect_ident_eq(&mut cond).expect("Bad format in if-let conditional");
356					bak.truncate(bak.len() - cond.len());
357					let (appending_ids, rem) = collect_punct_in_expr(cond);
358					bak.extend(rem);
359					(removing_ids, appending_ids, bak)
360				}
361				Some(o) => {
362					cond.push_front(o);
363					bak.truncate(bak.len() - cond.len());
364					let (appending_ids, rem) = collect_punct_in_expr(cond);
365					bak.extend(rem);
366					(vec![], appending_ids, bak)
367				}
368				None => panic!("if syntax is empty"),
369			}
370		}
371		let mut cond: VecDeque<TokenTree> = conditional.clone().into_iter().collect();
372		let cond_len = cond.len();
373		let (removing_ids, appending_ids, cond) = match (cond.pop_front(), sep.is_some()) {
374			(Some(TokenTree::Ident(id)), false) if &id.to_string() == "if" => {
375				let (removing_ids, appending_ids, rem) = parse_if_inner(cond);
376				(
377					removing_ids,
378					appending_ids,
379					Some(TokenTree::Ident(id)).into_iter().chain(rem).collect(),
380				)
381			}
382			(Some(TokenTree::Ident(id)), false) if &id.to_string() == "else" => {
383				match cond.pop_front() {
384					// else if
385					Some(TokenTree::Ident(id_if)) if &id_if.to_string() == "if" => {
386						let (removing_ids, appending_ids, rem) = parse_if_inner(cond);
387						(
388							removing_ids,
389							appending_ids,
390							vec![TokenTree::Ident(id), TokenTree::Ident(id_if)]
391								.into_iter()
392								.chain(rem)
393								.collect(),
394						)
395					}
396					Some(_) => panic!("Bad format in else conditional"),
397					None => (vec![], vec![], conditional),
398				}
399			}
400			(Some(TokenTree::Ident(id)), false) if id.to_string() == "let" => {
401				let removing_ids = collect_ident_eq(&mut cond).expect("Bad format in let binding");
402				let n = cond_len - cond.len();
403				let (appending_ids, rem) = collect_punct_in_expr(cond);
404				let conditional: TokenStream2 =
405					conditional.clone().into_iter().take(n).chain(rem).collect();
406				(removing_ids, appending_ids, qquote! {#conditional ;})
407			}
408			(Some(TokenTree::Ident(id)), _) if id.to_string() == "while" => {
409				match cond.pop_front() {
410					Some(TokenTree::Ident(id_let)) if &id_let.to_string() == "let" => {
411						let removing_ids =
412							collect_ident_eq(&mut cond).expect("Bad format in while-let loop");
413						let n = cond_len - cond.len();
414						let (appending_ids, rem) = collect_punct_in_expr(cond);
415						let conditional: TokenStream2 =
416							conditional.clone().into_iter().take(n).chain(rem).collect();
417						(removing_ids, appending_ids, conditional)
418					}
419					Some(o) => {
420						cond.push_front(o);
421						let n = cond_len - cond.len();
422						let (appending_ids, rem) = collect_punct_in_expr(cond);
423						let conditional: TokenStream2 =
424							conditional.clone().into_iter().take(n).chain(rem).collect();
425						(vec![], appending_ids, conditional)
426					}
427					None => panic!("while syntax is empty"),
428				}
429			}
430			(Some(TokenTree::Ident(id)), _) if id.to_string() == "for" => {
431				match (collect_ident(&mut cond), cond.pop_front()) {
432					(Ok(v), Some(TokenTree::Ident(id_in))) if &id_in.to_string() == "in" => {
433						let n = cond_len - cond.len();
434						let (appending_ids, rem) = collect_punct_in_expr(cond);
435						let conditional: TokenStream2 =
436							conditional.clone().into_iter().take(n).chain(rem).collect();
437						(v, appending_ids, conditional)
438					}
439					_ => panic!("Bad format in for loop"),
440				}
441			}
442			_ => panic!("Bad format in conditional"),
443		};
444		let inner = self.parse_inner(input, vals, inline_expr_dict);
445		for id in removing_ids {
446			vals.remove(&id);
447		}
448		for id in appending_ids {
449			vals.insert(id);
450		}
451		if let Some(sep) = sep {
452			let code_sep = self.emit_punct(&sep);
453			let id_counter = &self.id_counter;
454			qquote! {
455				{
456					let mut #id_counter = false;
457					#cond {
458						if #id_counter { #code_sep }
459						#id_counter = true;
460						#inner
461					}
462				}
463			}
464		} else {
465			qquote! {
466				#cond {
467					#inner
468				}
469			}
470		}
471	}
472
473	fn parse_iteration(
474		&self,
475		input: VecDeque<TokenTree>,
476		vals: &mut HashSet<Ident>,
477		sep: Option<Punct>,
478		inline_expr_dict: &mut Vec<(Ident, TokenStream2, Span)>,
479	) -> TokenStream2 {
480		let Self {
481			path_quote,
482			id_repeat,
483			..
484		} = self;
485		let debug_str = input
486			.iter()
487			.take(5)
488			.map(|item| match item {
489				TokenTree::Group(g) => match g.delimiter() {
490					Delimiter::Parenthesis => "( .. )".to_owned(),
491					Delimiter::Brace => "{ .. }".to_owned(),
492					Delimiter::Bracket => "[ .. ]".to_owned(),
493					Delimiter::None => "..".to_owned(),
494				},
495				_ => format!("{}", item),
496			})
497			.collect::<Vec<_>>()
498			.join(" ");
499		let mut inner_vals = HashSet::new();
500		let inner_output = self.parse_inner(input, &mut inner_vals, inline_expr_dict);
501		let code_sep = sep.map(|sep| self.emit_punct(&Punct::new(sep.as_char(), Spacing::Alone)));
502		let val_nam = code_sep
503			.as_ref()
504			.map(|_| self.id_counter.clone())
505			.into_iter()
506			.collect::<Vec<_>>();
507		vals.extend(inner_vals.iter().cloned());
508		let mut iter = inner_vals.iter();
509		let first = iter.next().expect("Iterative vals not found");
510		let idents_in_tuple = iter.clone().cloned().fold(qquote! {#first}, |prev, next| {
511			qquote! {
512				(#prev, #next)
513			}
514		});
515		let zip_iterators = iter
516			.clone()
517			.map(|ident| {
518				qquote! {
519					.zip(#ident .__template_quote__as_repeat())
520				}
521			})
522			.collect::<Vec<_>>();
523		let zip_iterator_checkers = inner_vals.iter().fold(qquote! {false}, |acc, ident| {
524			qquote! {#acc || (&#ident).__template_quote_is_iterable()}
525		});
526		qquote! {
527			{
528				#(let mut #val_nam = false;)*
529				use #path_quote::Repeat as #id_repeat;
530				if !(#zip_iterator_checkers) {
531					::core::panic!("Cannot iterate the group: #( {} )*", #debug_str);
532				}
533				for #idents_in_tuple in #first .__template_quote__as_repeat() #(#zip_iterators)* {
534					#(
535						if #val_nam { #code_sep }
536						#val_nam = true;
537					)*
538					#inner_output
539				}
540			}
541		}
542	}
543
544	fn parse(&self, input: TokenStream2) -> TokenStream2 {
545		let Self {
546			path_proc_macro2,
547			id_stream,
548			..
549		} = self;
550		let mut hs = HashSet::new();
551		let mut dict = Vec::new();
552		let result = self.parse_inner(input.into_iter().collect(), &mut hs, &mut dict);
553		let inline_vals_code =
554			dict.into_iter()
555				.fold(TokenStream2::new(), |acc, (id, inner, span)| {
556					qquote_spanned! { span =>
557						#acc
558						let #id = { #inner };
559					}
560				});
561		qquote! {
562			{
563				let mut #id_stream= #path_proc_macro2::TokenStream::new();
564				#inline_vals_code
565				{ #result }
566				#id_stream
567			}
568		}
569	}
570
571	fn parse_inner(
572		&self,
573		mut input: VecDeque<TokenTree>,
574		vals: &mut HashSet<Ident>,
575		inline_expr_dict: &mut Vec<(Ident, TokenStream2, Span)>,
576	) -> TokenStream2 {
577		let Self {
578			path_quote,
579			id_stream,
580			..
581		} = self;
582		let mut output = TokenStream2::new();
583		while let Some(token) = input.pop_front() {
584			match token {
585				TokenTree::Group(group) => {
586					let inner = group.stream().into_iter().collect();
587					let result = self.parse_inner(inner, vals, inline_expr_dict);
588					let result = self.emit_group(&group.delimiter(), result);
589					output.append_all(result);
590				}
591				TokenTree::Punct(punct) => match (punct.as_char(), input.pop_front()) {
592					// # val
593					('#', Some(TokenTree::Ident(ident))) => {
594						vals.insert(ident.clone());
595						output.append_all(
596							qquote! { <_ as #path_quote::ToTokens>::to_tokens(&#ident, &mut #id_stream); },
597						);
598					}
599					// # { ... }
600					('#', Some(TokenTree::Group(group)))
601						if group.delimiter() == Delimiter::Brace =>
602					{
603						let inner = group.stream().into_iter().collect::<VecDeque<_>>();
604						// Check if the inner stream ends with ';'
605						let is_expr = match inner.get(core::cmp::max(0, inner.len() - 1)) {
606							Some(TokenTree::Punct(p)) if p.as_char() == ';' => false,
607							_ => true,
608						};
609						let (appending_ids, inner) = collect_punct_in_expr(inner);
610						for id in appending_ids {
611							vals.insert(id);
612						}
613						let stream: TokenStream2 = inner.into_iter().collect();
614						if is_expr {
615							output.append_all(qquote! {
616								<_ as #path_quote::ToTokens>::to_tokens(&{
617									#stream
618								}, &mut #id_stream);
619							});
620						} else {
621							output.append_all(qquote! {
622								{ #stream }
623							});
624						}
625					}
626					('#', Some(TokenTree::Group(group)))
627						if group.delimiter() == Delimiter::Parenthesis =>
628					{
629						match input.pop_front() {
630							// # ( ... ) { ... }
631							Some(TokenTree::Group(group2))
632								if group2.delimiter() == Delimiter::Brace =>
633							{
634								output.append_all(self.parse_conditional(
635									group.stream().into(),
636									group2.stream().into_iter().collect(),
637									vals,
638									None,
639									inline_expr_dict,
640								));
641							}
642							// # ( ... ) *
643							Some(TokenTree::Punct(punct)) if punct.as_char() == '*' => output
644								.append_all(self.parse_iteration(
645									group.stream().into_iter().collect(),
646									vals,
647									None,
648									inline_expr_dict,
649								)),
650							Some(TokenTree::Punct(punct0)) => match input.pop_front() {
651								// # ( ... ) [SEP] *
652								Some(TokenTree::Punct(punct1)) if punct1.as_char() == '*' => output
653									.append_all(self.parse_iteration(
654										group.stream().into_iter().collect(),
655										vals,
656										Some(punct0),
657										inline_expr_dict,
658									)),
659								// # ( ... ) [SEP] { ... }
660								Some(TokenTree::Group(group2))
661									if group2.delimiter() == Delimiter::Brace =>
662								{
663									output.append_all(self.parse_conditional(
664										group.stream().into(),
665										group2.stream().into_iter().collect(),
666										vals,
667										Some(punct0),
668										inline_expr_dict,
669									));
670								}
671								o => {
672									if let Some(o) = o {
673										input.push_front(o);
674									}
675									input.push_front(TokenTree::Punct(punct0));
676									input.push_front(TokenTree::Group(group));
677									output.append_all(self.emit_punct(&punct));
678								}
679							},
680							o => {
681								if let Some(o) = o {
682									input.push_front(o)
683								}
684								input.push_front(TokenTree::Group(group));
685								output.append_all(self.emit_punct(&punct));
686							}
687						}
688					}
689					(_, o) => {
690						if let Some(o) = o {
691							input.push_front(o);
692						}
693						output.append_all(self.emit_punct(&punct));
694					}
695				},
696				TokenTree::Ident(o) => output.append_all(self.emit_ident(&o)),
697				TokenTree::Literal(o) => output.append_all(self.emit_literal(&o)),
698			}
699		}
700		output
701	}
702}
703
704#[proc_macro]
705pub fn quote(input: TokenStream) -> TokenStream {
706	let env: ParseEnvironment = Default::default();
707	env.parse(input.into()).into()
708}
709
710#[proc_macro]
711pub fn quote_configured(input: TokenStream) -> TokenStream {
712	let input0: TokenStream2 = input.into();
713	let mut input = VecDeque::new();
714	input.extend(input0.into_iter());
715	let env: ParseEnvironment = match input.pop_front() {
716		Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => {
717			syn::parse2(g.stream()).expect_or_abort("Bad config format")
718		}
719		_ => panic!("Bad config format"),
720	};
721	match input.pop_front() {
722		Some(TokenTree::Punct(p)) if p.as_char() == '=' && p.spacing() == Spacing::Joint => (),
723		_ => panic!("Bad config format"),
724	}
725	match input.pop_front() {
726		Some(TokenTree::Punct(p)) if p.as_char() == '>' && p.spacing() == Spacing::Alone => (),
727		_ => panic!("Bad config format"),
728	}
729	let mut stream = TokenStream2::new();
730	stream.extend(input);
731	env.parse(stream).into()
732}
733
734#[proc_macro]
735pub fn quote_spanned(input: TokenStream) -> TokenStream {
736	let input0: TokenStream2 = input.into();
737	let mut input = VecDeque::new();
738	input.extend(input0.into_iter());
739	let mut span = TokenStream2::new(); // Tokens before '=>'
740	loop {
741		match input.pop_front() {
742			Some(TokenTree::Punct(p)) if p.as_char() == '=' && p.spacing() == Spacing::Joint => {
743				match input.pop_front() {
744					Some(TokenTree::Punct(p))
745						if p.as_char() == '>' && p.spacing() == Spacing::Alone =>
746					{
747						// Found '=>'.
748						break;
749					}
750					Some(o) => {
751						span.extend(Some(TokenTree::Punct(p)));
752						input.push_front(o);
753					}
754					None => {
755						span.extend(Some(TokenTree::Punct(p)));
756					}
757				}
758			}
759			Some(o) => span.extend(Some(o)),
760			None => panic!("wrong quote_spanned format"),
761		}
762	}
763	let mut env: ParseEnvironment = Default::default();
764	env.span = syn::parse2(span).expect_or_abort("Span must be expr");
765	let mut stream = TokenStream2::new();
766	stream.extend(input);
767	env.parse(stream).into()
768}