Skip to main content

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
244fn hash_will_be_processed(next: Option<&TokenTree>, rest: &VecDeque<TokenTree>) -> bool {
245	match next {
246		Some(TokenTree::Ident(_)) => true,
247		Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => true,
248		Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => {
249			match (rest.front(), rest.get(1)) {
250				(Some(TokenTree::Group(group2)), _)
251					if group2.delimiter() == Delimiter::Brace =>
252				{
253					true
254				}
255				(Some(TokenTree::Punct(punct)), _) if punct.as_char() == '*' => true,
256				(Some(TokenTree::Punct(_)), Some(TokenTree::Punct(punct2)))
257					if punct2.as_char() == '*' =>
258				{
259					true
260				}
261				(Some(TokenTree::Punct(_)), Some(TokenTree::Group(group2)))
262					if group2.delimiter() == Delimiter::Brace =>
263				{
264					true
265				}
266				_ => false,
267			}
268		}
269		_ => false,
270	}
271}
272
273fn keep_joint_before_processed_hash(punct: char) -> bool {
274	matches!(punct, '+' | '-' | ':' | '<' | '>')
275}
276
277impl ParseEnvironment {
278	fn emit_ident(&self, ident: &Ident) -> TokenStream2 {
279		let Self {
280			span,
281			path_proc_macro2,
282			path_quote,
283			id_stream,
284			..
285		} = self;
286		let s = ident.to_string();
287		if s.starts_with("r#") {
288			let s = &s[2..];
289			qquote! {
290				<_ as #path_quote::ToTokens>::to_tokens(&#path_proc_macro2::Ident::new_raw(#s, (#span)), &mut #id_stream);
291			}
292		} else {
293			qquote! {
294				<_ as #path_quote::ToTokens>::to_tokens(&#path_proc_macro2::Ident::new(#s, (#span)), &mut #id_stream);
295			}
296		}
297	}
298
299	fn emit_literal(&self, lit: &Literal) -> TokenStream2 {
300		let Self {
301			span,
302			path_proc_macro2,
303			id_stream,
304			..
305		} = self;
306		let s = lit.to_string();
307		qquote! {
308			{
309				let ts: #path_proc_macro2::TokenStream = #s.parse().expect("Invalid literal str");
310				#id_stream.extend(ts.into_iter().map(|mut t| {
311					t.set_span(#span);
312					t
313				}));
314			}
315		}
316	}
317
318	fn emit_punct(&self, punct: &Punct) -> TokenStream2 {
319		let Self {
320			span,
321			path_proc_macro2,
322			path_quote,
323			id_stream,
324			..
325		} = self;
326		let p = punct.as_char();
327		let spacing = match punct.spacing() {
328			Spacing::Alone => qquote! {#path_proc_macro2::Spacing::Alone},
329			Spacing::Joint => qquote! {#path_proc_macro2::Spacing::Joint},
330		};
331		qquote! {
332			<_ as #path_quote::ToTokens>::to_tokens(&{
333				let mut p = #path_proc_macro2::Punct::new(#p, #spacing);
334				p.set_span(#span);
335				p
336			}, &mut #id_stream);
337		}
338	}
339
340	fn emit_punct_with_spacing(&self, punct: &Punct, spacing: Spacing) -> TokenStream2 {
341		let mut p = Punct::new(punct.as_char(), spacing);
342		p.set_span(punct.span());
343		self.emit_punct(&p)
344	}
345
346	fn emit_group(&self, delim: &Delimiter, inner: TokenStream2) -> TokenStream2 {
347		let Self {
348			span,
349			path_proc_macro2,
350			path_core,
351			id_stream,
352			..
353		} = self;
354		let delim = match delim {
355			Delimiter::Parenthesis => qquote! { #path_proc_macro2::Delimiter::Parenthesis },
356			Delimiter::Brace => qquote! { #path_proc_macro2::Delimiter::Brace },
357			Delimiter::Bracket => qquote! { #path_proc_macro2::Delimiter::Bracket },
358			Delimiter::None => qquote! { #path_proc_macro2::Delimiter::None },
359		};
360		qquote! {
361			#id_stream.extend(
362				#path_core::option::Option::Some(
363					#path_proc_macro2::TokenTree::Group(
364						{
365							let mut g = #path_proc_macro2::Group::new(#delim, {
366								let mut #id_stream = #path_proc_macro2::TokenStream::new();
367								{ #inner }
368								#id_stream
369							});
370							g.set_span(#span);
371							g
372						}
373					)
374				)
375			);
376		}
377	}
378
379	fn parse_conditional(
380		&self,
381		conditional: TokenStream2,
382		input: VecDeque<TokenTree>,
383		vals: &mut HashSet<Ident>,
384		sep: Option<Punct>,
385		inline_expr_dict: &mut Vec<(Ident, TokenStream2, Span)>,
386	) -> TokenStream2 {
387		fn parse_if_inner(
388			mut cond: VecDeque<TokenTree>,
389		) -> (Vec<Ident>, Vec<Ident>, Vec<TokenTree>) {
390			let mut bak: Vec<_> = cond.iter().cloned().collect();
391			match cond.pop_front() {
392				Some(TokenTree::Ident(id_let)) if &id_let.to_string() == "let" => {
393					let removing_ids =
394						collect_ident_eq(&mut cond).expect("Bad format in if-let conditional");
395					bak.truncate(bak.len() - cond.len());
396					let (appending_ids, rem) = collect_punct_in_expr(cond);
397					bak.extend(rem);
398					(removing_ids, appending_ids, bak)
399				}
400				Some(o) => {
401					cond.push_front(o);
402					bak.truncate(bak.len() - cond.len());
403					let (appending_ids, rem) = collect_punct_in_expr(cond);
404					bak.extend(rem);
405					(vec![], appending_ids, bak)
406				}
407				None => panic!("if syntax is empty"),
408			}
409		}
410		let mut cond: VecDeque<TokenTree> = conditional.clone().into_iter().collect();
411		let cond_len = cond.len();
412		let (removing_ids, appending_ids, cond) = match (cond.pop_front(), sep.is_some()) {
413			(Some(TokenTree::Ident(id)), false) if &id.to_string() == "if" => {
414				let (removing_ids, appending_ids, rem) = parse_if_inner(cond);
415				(
416					removing_ids,
417					appending_ids,
418					Some(TokenTree::Ident(id)).into_iter().chain(rem).collect(),
419				)
420			}
421			(Some(TokenTree::Ident(id)), false) if &id.to_string() == "else" => {
422				match cond.pop_front() {
423					// else if
424					Some(TokenTree::Ident(id_if)) if &id_if.to_string() == "if" => {
425						let (removing_ids, appending_ids, rem) = parse_if_inner(cond);
426						(
427							removing_ids,
428							appending_ids,
429							vec![TokenTree::Ident(id), TokenTree::Ident(id_if)]
430								.into_iter()
431								.chain(rem)
432								.collect(),
433						)
434					}
435					Some(_) => panic!("Bad format in else conditional"),
436					None => (vec![], vec![], conditional),
437				}
438			}
439			(Some(TokenTree::Ident(id)), false) if id.to_string() == "let" => {
440				let removing_ids = collect_ident_eq(&mut cond).expect("Bad format in let binding");
441				let n = cond_len - cond.len();
442				let (appending_ids, rem) = collect_punct_in_expr(cond);
443				let conditional: TokenStream2 =
444					conditional.clone().into_iter().take(n).chain(rem).collect();
445				(removing_ids, appending_ids, qquote! {#conditional ;})
446			}
447			(Some(TokenTree::Ident(id)), _) if id.to_string() == "while" => {
448				match cond.pop_front() {
449					Some(TokenTree::Ident(id_let)) if &id_let.to_string() == "let" => {
450						let removing_ids =
451							collect_ident_eq(&mut cond).expect("Bad format in while-let loop");
452						let n = cond_len - cond.len();
453						let (appending_ids, rem) = collect_punct_in_expr(cond);
454						let conditional: TokenStream2 =
455							conditional.clone().into_iter().take(n).chain(rem).collect();
456						(removing_ids, appending_ids, conditional)
457					}
458					Some(o) => {
459						cond.push_front(o);
460						let n = cond_len - cond.len();
461						let (appending_ids, rem) = collect_punct_in_expr(cond);
462						let conditional: TokenStream2 =
463							conditional.clone().into_iter().take(n).chain(rem).collect();
464						(vec![], appending_ids, conditional)
465					}
466					None => panic!("while syntax is empty"),
467				}
468			}
469			(Some(TokenTree::Ident(id)), _) if id.to_string() == "for" => {
470				match (collect_ident(&mut cond), cond.pop_front()) {
471					(Ok(v), Some(TokenTree::Ident(id_in))) if &id_in.to_string() == "in" => {
472						let n = cond_len - cond.len();
473						let (appending_ids, rem) = collect_punct_in_expr(cond);
474						let conditional: TokenStream2 =
475							conditional.clone().into_iter().take(n).chain(rem).collect();
476						(v, appending_ids, conditional)
477					}
478					_ => panic!("Bad format in for loop"),
479				}
480			}
481			_ => panic!("Bad format in conditional"),
482		};
483		let inner = self.parse_inner(input, vals, inline_expr_dict);
484		for id in removing_ids {
485			vals.remove(&id);
486		}
487		for id in appending_ids {
488			vals.insert(id);
489		}
490		if let Some(sep) = sep {
491			let code_sep = self.emit_punct(&sep);
492			let id_counter = &self.id_counter;
493			qquote! {
494				{
495					let mut #id_counter = false;
496					#cond {
497						if #id_counter { #code_sep }
498						#id_counter = true;
499						#inner
500					}
501				}
502			}
503		} else {
504			qquote! {
505				#cond {
506					#inner
507				}
508			}
509		}
510	}
511
512	fn parse_iteration(
513		&self,
514		input: VecDeque<TokenTree>,
515		vals: &mut HashSet<Ident>,
516		sep: Option<Punct>,
517		inline_expr_dict: &mut Vec<(Ident, TokenStream2, Span)>,
518	) -> TokenStream2 {
519		let Self {
520			path_quote,
521			id_repeat,
522			..
523		} = self;
524		let debug_str = input
525			.iter()
526			.take(6)
527			.map(|item| match item {
528				TokenTree::Group(g) => match g.delimiter() {
529					Delimiter::Parenthesis => "( .. )".to_owned(),
530					Delimiter::Brace => "{ .. }".to_owned(),
531					Delimiter::Bracket => "[ .. ]".to_owned(),
532					Delimiter::None => "..".to_owned(),
533				},
534				_ => format!("{}", item),
535			})
536			.chain(if input.len() > 6 {
537				Some("..".to_owned())
538			} else {
539				None
540			})
541			.collect::<Vec<_>>()
542			.join(" ");
543		let mut inner_vals = HashSet::new();
544		let inner_output = self.parse_inner(input, &mut inner_vals, inline_expr_dict);
545		let code_sep = sep.map(|sep| self.emit_punct(&Punct::new(sep.as_char(), Spacing::Alone)));
546		let val_nam = code_sep
547			.as_ref()
548			.map(|_| self.id_counter.clone())
549			.into_iter()
550			.collect::<Vec<_>>();
551		vals.extend(inner_vals.iter().cloned());
552		let mut iter = inner_vals.iter();
553		let first = iter.next().expect("Iterative vals not found");
554		let idents_in_tuple = iter.clone().cloned().fold(qquote! {#first}, |prev, next| {
555			qquote! {
556				(#prev, #next)
557			}
558		});
559		let zip_iterators = iter
560			.clone()
561			.map(|ident| {
562				qquote! {
563					.zip(#ident .__template_quote__as_repeat())
564				}
565			})
566			.collect::<Vec<_>>();
567		let zip_iterator_checkers = inner_vals.iter().fold(qquote! {false}, |acc, ident| {
568			qquote! {#acc || (&#ident).__template_quote_is_iterable()}
569		});
570		qquote! {
571			{
572				#(let mut #val_nam = false;)*
573				use #path_quote::Repeat as #id_repeat;
574				if !(#zip_iterator_checkers) {
575					::core::panic!("Cannot iterate the group: #( {} )*", #debug_str);
576				}
577				for #idents_in_tuple in #first .__template_quote__as_repeat() #(#zip_iterators)* {
578					#(
579						if #val_nam { #code_sep }
580						#val_nam = true;
581					)*
582					#inner_output
583				}
584			}
585		}
586	}
587
588	fn parse(&self, input: TokenStream2) -> TokenStream2 {
589		let Self {
590			path_proc_macro2,
591			id_stream,
592			..
593		} = self;
594		let mut hs = HashSet::new();
595		let mut dict = Vec::new();
596		let result = self.parse_inner(input.into_iter().collect(), &mut hs, &mut dict);
597		let inline_vals_code =
598			dict.into_iter()
599				.fold(TokenStream2::new(), |acc, (id, inner, span)| {
600					qquote_spanned! { span =>
601						#acc
602						let #id = { #inner };
603					}
604				});
605		qquote! {
606			{
607				let mut #id_stream= #path_proc_macro2::TokenStream::new();
608				#inline_vals_code
609				{ #result }
610				#id_stream
611			}
612		}
613	}
614
615	fn parse_inner(
616		&self,
617		mut input: VecDeque<TokenTree>,
618		vals: &mut HashSet<Ident>,
619		inline_expr_dict: &mut Vec<(Ident, TokenStream2, Span)>,
620	) -> TokenStream2 {
621		let Self {
622			path_quote,
623			id_stream,
624			..
625		} = self;
626		let mut output = TokenStream2::new();
627		while let Some(token) = input.pop_front() {
628			match token {
629				TokenTree::Group(group) => {
630					let inner = group.stream().into_iter().collect();
631					let result = self.parse_inner(inner, vals, inline_expr_dict);
632					let result = self.emit_group(&group.delimiter(), result);
633					output.append_all(result);
634				}
635				TokenTree::Punct(punct) => match (punct.as_char(), input.pop_front()) {
636					// # val
637					('#', Some(TokenTree::Ident(ident))) => {
638						vals.insert(ident.clone());
639						output.append_all(
640							qquote! { <_ as #path_quote::ToTokens>::to_tokens(&#ident, &mut #id_stream); },
641						);
642					}
643					// # { ... }
644					('#', Some(TokenTree::Group(group)))
645						if group.delimiter() == Delimiter::Brace =>
646					{
647						let inner = group.stream().into_iter().collect::<VecDeque<_>>();
648						// Check if the inner stream ends with ';'
649						let is_expr = match inner.get(core::cmp::max(0, inner.len() - 1)) {
650							Some(TokenTree::Punct(p)) if p.as_char() == ';' => false,
651							_ => true,
652						};
653						let (appending_ids, inner) = collect_punct_in_expr(inner);
654						for id in appending_ids {
655							vals.insert(id);
656						}
657						let stream: TokenStream2 = inner.into_iter().collect();
658						if is_expr {
659							output.append_all(qquote! {
660								<_ as #path_quote::ToTokens>::to_tokens(&{
661									#stream
662								}, &mut #id_stream);
663							});
664						} else {
665							output.append_all(qquote! {
666								{ #stream }
667							});
668						}
669					}
670					('#', Some(TokenTree::Group(group)))
671						if group.delimiter() == Delimiter::Parenthesis =>
672					{
673						match input.pop_front() {
674							// # ( ... ) { ... }
675							Some(TokenTree::Group(group2))
676								if group2.delimiter() == Delimiter::Brace =>
677							{
678								output.append_all(self.parse_conditional(
679									group.stream().into(),
680									group2.stream().into_iter().collect(),
681									vals,
682									None,
683									inline_expr_dict,
684								));
685							}
686							// # ( ... ) *
687							Some(TokenTree::Punct(punct)) if punct.as_char() == '*' => output
688								.append_all(self.parse_iteration(
689									group.stream().into_iter().collect(),
690									vals,
691									None,
692									inline_expr_dict,
693								)),
694							Some(TokenTree::Punct(punct0)) => match input.pop_front() {
695								// # ( ... ) [SEP] *
696								Some(TokenTree::Punct(punct1)) if punct1.as_char() == '*' => output
697									.append_all(self.parse_iteration(
698										group.stream().into_iter().collect(),
699										vals,
700										Some(punct0),
701										inline_expr_dict,
702									)),
703								// # ( ... ) [SEP] { ... }
704								Some(TokenTree::Group(group2))
705									if group2.delimiter() == Delimiter::Brace =>
706								{
707									output.append_all(self.parse_conditional(
708										group.stream().into(),
709										group2.stream().into_iter().collect(),
710										vals,
711										Some(punct0),
712										inline_expr_dict,
713									));
714								}
715								o => {
716									if let Some(o) = o {
717										input.push_front(o);
718									}
719									input.push_front(TokenTree::Punct(punct0));
720									input.push_front(TokenTree::Group(group));
721									output.append_all(self.emit_punct(&punct));
722								}
723							},
724							o => {
725								if let Some(o) = o {
726									input.push_front(o)
727								}
728								input.push_front(TokenTree::Group(group));
729								output.append_all(self.emit_punct(&punct));
730							}
731						}
732					}
733					(_, o) => {
734						let adjust_joint_before_hash = punct.spacing() == Spacing::Joint
735							&& matches!(o, Some(TokenTree::Punct(ref p)) if p.as_char() == '#')
736							&& !keep_joint_before_processed_hash(punct.as_char())
737							&& hash_will_be_processed(input.front(), &input);
738						if let Some(o) = o {
739							input.push_front(o);
740						}
741						if adjust_joint_before_hash {
742							output.append_all(self.emit_punct_with_spacing(&punct, Spacing::Alone));
743						} else {
744							output.append_all(self.emit_punct(&punct));
745						}
746					}
747				},
748				TokenTree::Ident(o) => output.append_all(self.emit_ident(&o)),
749				TokenTree::Literal(o) => output.append_all(self.emit_literal(&o)),
750			}
751		}
752		output
753	}
754}
755
756#[proc_macro]
757pub fn quote(input: TokenStream) -> TokenStream {
758	let env: ParseEnvironment = Default::default();
759	env.parse(input.into()).into()
760}
761
762#[proc_macro]
763pub fn quote_configured(input: TokenStream) -> TokenStream {
764	let input0: TokenStream2 = input.into();
765	let mut input = VecDeque::new();
766	input.extend(input0.into_iter());
767	let env: ParseEnvironment = match input.pop_front() {
768		Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => {
769			syn::parse2(g.stream()).expect_or_abort("Bad config format")
770		}
771		_ => panic!("Bad config format"),
772	};
773	match input.pop_front() {
774		Some(TokenTree::Punct(p)) if p.as_char() == '=' && p.spacing() == Spacing::Joint => (),
775		_ => panic!("Bad config format"),
776	}
777	match input.pop_front() {
778		Some(TokenTree::Punct(p)) if p.as_char() == '>' && p.spacing() == Spacing::Alone => (),
779		_ => panic!("Bad config format"),
780	}
781	let mut stream = TokenStream2::new();
782	stream.extend(input);
783	env.parse(stream).into()
784}
785
786#[proc_macro]
787pub fn quote_spanned(input: TokenStream) -> TokenStream {
788	let input0: TokenStream2 = input.into();
789	let mut input = VecDeque::new();
790	input.extend(input0.into_iter());
791	let mut span = TokenStream2::new(); // Tokens before '=>'
792	loop {
793		match input.pop_front() {
794			Some(TokenTree::Punct(p)) if p.as_char() == '=' && p.spacing() == Spacing::Joint => {
795				match input.pop_front() {
796					Some(TokenTree::Punct(p))
797						if p.as_char() == '>' && p.spacing() == Spacing::Alone =>
798					{
799						// Found '=>'.
800						break;
801					}
802					Some(o) => {
803						span.extend(Some(TokenTree::Punct(p)));
804						input.push_front(o);
805					}
806					None => {
807						span.extend(Some(TokenTree::Punct(p)));
808					}
809				}
810			}
811			Some(o) => span.extend(Some(o)),
812			None => panic!("wrong quote_spanned format"),
813		}
814	}
815	let mut env: ParseEnvironment = Default::default();
816	env.span = syn::parse2(span).expect_or_abort("Span must be expr");
817	let mut stream = TokenStream2::new();
818	stream.extend(input);
819	env.parse(stream).into()
820}