1use super::prelude::*;
4use proc_macro_crate::{crate_name, FoundCrate};
5
6macro_rules! impl_deref { { $ttype:ty, $fname:tt, $ftype:ty } => {
9 impl Deref for $ttype {
10 type Target = $ftype;
11 fn deref(&self) -> &$ftype {
12 &self.$fname
13 }
14 }
15} }
16macro_rules! impl_to_tokens { {
17 $ttype:ident $( [ $($tgen:tt)* ] )?,
18 $fname:tt
19} => {
20 impl $( < $($tgen)* > )? ToTokens for $ttype $( < $($tgen)* > )? {
21 fn to_tokens(&self, out: &mut TokenStream) {
22 self.$fname.to_tokens(out)
23 }
24 }
25} }
26macro_rules! impl_display { {
27 $ttype:ident $( [ $($tgen:tt)* ] )?,
28 $fname:tt
29} => {
30 impl $( < $($tgen)* > )? Display for $ttype $( < $($tgen)* > )? {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 Display::fmt(&self.$fname, f)
33 }
34 }
35} }
36
37#[cfg(not(derive_deftly_dprint))]
50#[macro_use]
51pub mod dprint {
52 macro_rules! dprintln { { $( $x:tt )* } => {} }
53
54 macro_rules! dprint_block { { $( $x:tt )* } => {} }
62}
63
64#[cfg(derive_deftly_dprint)]
65#[macro_use]
66pub mod dprint {
67 pub fn wanted() -> bool {
68 const VAR: &str = "DERIVE_DEFTLY_DPRINT";
69 match std::env::var_os(VAR) {
70 None => false,
71 Some(y) if y == "0" => false,
72 Some(y) if y == "1" => true,
73 other => panic!("bad value for {}: {:?}", VAR, other),
74 }
75 }
76
77 macro_rules! dprintln { { $( $x:tt )* } => { {
78 if dprint::wanted() {
79 eprintln!( $($x)* )
80 }
81 } } }
82
83 macro_rules! dprint_block { {
84 [ $($value:expr),* $(,)? ], $f:literal $( $x:tt )*
85 } => { {
86 dprintln!(concat!("---------- ", $f, " start ----------") $($x)*);
87 dprint_block!(@ $( $value, )*);
88 dprintln!(concat!("---------- ", $f, " end ----------") $($x)*);
89 } }; {
90 @ $value:expr,
91 } => { {
92 dprintln!("{}", $value);
93 } }; {
94 @ $value:expr, $($more:tt)+
95 } => { {
96 dprint_block!(@ $value,);
97 dprintln!("----------");
98 dprint_block!(@ $($more)+);
99 } }; {
100 $value:expr, $f:literal $( $x:tt )*
101 } => { {
102 dprint_block!([$value], $f $($x)*);
103 } } }
104}
105
106pub type ErrorGenerator<'c> = &'c (dyn Fn(Span) -> syn::Error + 'c);
109
110macro_rules! error_generator { { $msg:expr } => {
111 (&|span: Span| span.error($msg)) as ErrorGenerator
112} }
113
114pub fn braced_group(
119 brace_span: Span,
120 f: impl FnOnce(&mut TokenAccumulator) -> syn::Result<()>,
121) -> syn::Result<proc_macro2::Group> {
122 delimit_token_group(Delimiter::Brace, brace_span, f)
123}
124
125pub fn delimit_token_group(
126 delim: Delimiter,
127 delim_span: Span,
128 f: impl FnOnce(&mut TokenAccumulator) -> syn::Result<()>,
129) -> syn::Result<proc_macro2::Group> {
130 let mut out = TokenAccumulator::default();
131 f(&mut out)?;
132 let out = group_new_with_span(delim, delim_span, out.tokens()?);
133 Ok(out)
134}
135
136#[allow(dead_code)] pub struct Discard<T>(PhantomData<T>);
139
140impl<T: Parse> Parse for Discard<T> {
141 fn parse(input: ParseStream) -> syn::Result<Self> {
142 let _: T = input.parse()?;
143 Ok(Discard(PhantomData))
144 }
145}
146
147#[derive(Debug, Clone)]
149#[allow(dead_code)] pub struct Concatenated<T>(pub Vec<T>);
151
152impl<T: Parse> Parse for Concatenated<T> {
153 fn parse(input: ParseStream) -> syn::Result<Self> {
154 let mut out = vec![];
155 while !input.is_empty() {
156 out.push(input.parse()?);
157 }
158 Ok(Concatenated(out))
159 }
160}
161
162impl<T: ToTokens> Concatenated<T> {
163 pub fn is_empty(&self) -> bool {
164 self.0.is_empty()
165 }
166}
167
168impl<T: ToTokens> ToTokens for Concatenated<T> {
169 fn to_tokens(&self, out: &mut TokenStream) {
170 for item in &self.0 {
171 item.to_tokens(out);
172 }
173 }
174}
175
176pub fn group_new_with_span(
178 delimiter: Delimiter,
179 span: Span,
180 ts: TokenStream,
181) -> proc_macro2::Group {
182 let mut g_out = proc_macro2::Group::new(delimiter, ts);
183 g_out.set_span(span);
184 g_out
185}
186
187pub fn group_clone_set_stream(
189 g_in: &proc_macro2::Group,
190 ts: TokenStream,
191) -> proc_macro2::Group {
192 group_new_with_span(
193 g_in.delimiter(),
194 g_in.span(),
196 ts,
197 )
198}
199
200pub fn respan_hygiene(input: TokenStream, span: Span) -> TokenStream {
202 pub fn recurse(input: TokenStream, span: Span) -> TokenStream {
204 let map_span = |tok_span: Span| tok_span.resolved_at(span);
205
206 input
207 .into_iter()
208 .update(|tt| match tt {
209 TT::Group(g) => {
210 let new_span = map_span(g.span());
211 *g = proc_macro2::Group::new(
212 g.delimiter(),
213 recurse(g.stream(), span),
214 );
215 g.set_span(new_span);
216 }
217 TT::Ident(i) => i.set_span(map_span(i.span())),
218 TT::Punct(p) => p.set_span(map_span(p.span())),
219 TT::Literal(l) => l.set_span(map_span(l.span())),
220 })
221 .collect()
222 }
223 recurse(input, span)
224}
225
226pub fn typepath_add_missing_argument_colons(
233 type_path: &mut syn::TypePath,
234 te_span: Span,
235) {
236 for seg in &mut type_path.path.segments {
237 match &mut seg.arguments {
238 syn::PathArguments::None => {}
239 syn::PathArguments::Parenthesized(_) => {}
240 syn::PathArguments::AngleBracketed(args) => {
241 args.colon2_token.get_or_insert_with(|| {
242 Token
246 });
247 }
248 }
249 }
250}
251
252pub fn dummy_path() -> syn::Path {
253 syn::Path {
254 leading_colon: None,
255 segments: Punctuated::default(),
256 }
257}
258
259pub trait MakeError {
263 fn error<M: Display>(&self, m: M) -> syn::Error;
265}
266
267impl<T: Spanned> MakeError for T {
268 fn error<M: Display>(&self, m: M) -> syn::Error {
269 syn::Error::new(self.span(), m)
270 }
271}
272
273pub type ErrorLoc<'s> = (Span, &'s str);
280
281impl MakeError for [ErrorLoc<'_>] {
287 fn error<M: Display>(&self, m: M) -> syn::Error {
288 let mut locs = self.into_iter().cloned();
289 let mk = |(span, frag): (Span, _)| {
290 span.error(format_args!("{} ({})", &m, frag))
291 };
292 let first = locs.next().expect("at least one span needed!");
293 let mut build = mk(first);
294 for rest in locs {
295 build.combine(mk(rest))
296 }
297 build
298 }
299}
300
301pub fn spans_join(spans: impl IntoIterator<Item = Span>) -> Option<Span> {
310 spans.into_iter().reduce(|a, b| a.join(b).unwrap_or(b))
311}
312
313pub trait ToTokensPunctComposable {
317 fn to_tokens_punct_composable(&self, out: &mut TokenStream);
318}
319impl<T, P> ToTokensPunctComposable for Punctuated<T, P>
321where
322 T: ToTokens,
323 P: ToTokens + Default,
324{
325 fn to_tokens_punct_composable(&self, out: &mut TokenStream) {
326 self.to_tokens(out);
327 if !self.empty_or_trailing() {
328 P::default().to_tokens(out)
329 }
330 }
331}
332impl<P> ToTokensPunctComposable for Option<&&P>
337where
338 P: ToTokens,
339 P: Default,
340{
341 fn to_tokens_punct_composable(&self, out: &mut TokenStream) {
342 if let Some(self_) = self {
343 self_.to_tokens(out)
344 } else {
345 P::default().to_tokens(out)
346 }
347 }
348}
349
350#[derive(Debug, Default)]
360#[must_use]
361pub struct ErrorAccumulator {
362 bad: Option<syn::Error>,
363 defused: bool,
364}
365
366impl ErrorAccumulator {
367 pub fn handle_in<T, F>(&mut self, f: F) -> Option<T>
369 where
370 F: FnOnce() -> syn::Result<T>,
371 {
372 self.handle(f())
373 }
374
375 pub fn handle<T>(&mut self, result: syn::Result<T>) -> Option<T> {
377 match result {
378 Ok(y) => Some(y),
379 Err(e) => {
380 self.push(e);
381 None
382 }
383 }
384 }
385
386 pub fn push(&mut self, err: syn::Error) {
388 if let Some(bad) = &mut self.bad {
389 bad.combine(err)
390 } else {
391 self.bad = Some(err);
392 }
393 }
394
395 #[allow(dead_code)]
397 pub fn finish(self) -> syn::Result<()> {
398 self.finish_with(())
399 }
400
401 pub fn finish_with<T>(self, success: T) -> syn::Result<T> {
403 match self.into_inner() {
404 None => Ok(success),
405 Some(bad) => Err(bad),
406 }
407 }
408
409 pub fn into_inner(mut self) -> Option<syn::Error> {
411 self.defused = true;
412 self.bad.take()
413 }
414
415 pub fn examine(&self) -> Option<&syn::Error> {
417 self.bad.as_ref()
418 }
419}
420
421impl Drop for ErrorAccumulator {
422 fn drop(&mut self) {
423 assert!(panicking() || self.defused);
424 }
425}
426
427#[derive(Debug, Clone)]
433pub struct MacroExport(Span);
434
435impl Spanned for MacroExport {
436 fn span(&self) -> Span {
437 self.0
438 }
439}
440
441impl MacroExport {
442 pub fn parse_option(input: ParseStream) -> syn::Result<Option<Self>> {
443 let span = if let Some(vis) = input.parse::<Option<Token![pub]>>()? {
444 return Err(vis.error(
445 "You must now write `define_derive_deftly! { export Template: ... }`, not `puib Template:`, since derive-deftly version 0.14.0"
446 ));
447 } else if let Some(export) = (|| {
448 use syn::parse::discouraged::Speculative;
449 input.peek(syn::Ident).then(|| ())?;
450 let forked = input.fork();
451 let ident: syn::Ident = forked.parse().expect("it *was*");
452 (ident == "export").then(|| ())?;
453 input.advance_to(&forked);
454 Some(ident)
455 })() {
456 Some(export.span())
457 } else {
458 None
459 };
460 Ok(span.map(MacroExport))
461 }
462}
463
464#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
470pub enum Grouping {
471 Ungrouped,
472 Invisible,
473 Parens,
474}
475
476impl Grouping {
477 pub fn surround(&self, none_span: Span, ts: impl ToTokens) -> TokenStream {
483 let ts = ts.to_token_stream();
484 match self {
485 Grouping::Ungrouped => ts,
486 Grouping::Invisible => {
487 let mut g = proc_macro2::Group::new(Delimiter::None, ts);
488 g.set_span(none_span);
489 g.to_token_stream()
490 }
491 Grouping::Parens => {
492 proc_macro2::Group::new(Delimiter::Parenthesis, ts)
505 .to_token_stream()
506 }
507 }
508 }
509}
510
511#[derive(Debug, Clone)]
515pub struct DocAttributes(Concatenated<syn::Attribute>);
516
517impl Parse for DocAttributes {
518 fn parse(input: ParseStream) -> syn::Result<Self> {
519 let attrs = input.call(syn::Attribute::parse_outer)?;
520 for attr in &attrs {
521 if !attr.path().is_ident("doc") {
522 return Err(attr
523 .path()
524 .error("only doc attributes are supported"));
525 }
526 }
527 Ok(DocAttributes(Concatenated(attrs)))
528 }
529}
530
531impl Deref for DocAttributes {
532 type Target = Concatenated<syn::Attribute>;
533 fn deref(&self) -> &Concatenated<syn::Attribute> {
534 &self.0
535 }
536}
537impl DocAttributes {
538 pub fn to_tokens_with_addendum(
539 self,
540 addendum_text: fmt::Arguments<'_>,
541 ) -> TokenStream {
542 let addendum = if self.0.is_empty() {
543 None
544 } else {
545 Some(addendum_text.to_string())
546 };
547 let mut out = self.0.to_token_stream();
548 if let Some(addendum) = addendum {
549 out.extend(quote!( #[doc = #addendum] ))
550 }
551 out
552 }
553}
554
555pub struct IdentAny(pub syn::Ident);
565impl_deref!(IdentAny, 0, syn::Ident);
566impl_to_tokens!(IdentAny, 0);
567
568impl Parse for IdentAny {
569 fn parse(input: ParseStream) -> syn::Result<Self> {
570 Ok(IdentAny(Ident::parse_any(input)?))
571 }
572}
573impl<T: AsRef<str> + ?Sized> PartialEq<T> for IdentAny {
574 fn eq(&self, rhs: &T) -> bool {
575 self.0.eq(rhs)
576 }
577}
578
579pub struct TokenOutputTrimmer<'t, 'o> {
594 preamble: Option<&'t dyn ToTokens>,
595 sep: &'t dyn ToTokens,
596 sep_count: usize,
597 out: &'o mut TokenStream,
598}
599
600impl<'t, 'o> TokenOutputTrimmer<'t, 'o> {
601 pub fn new(
602 out: &'o mut TokenStream,
603 preamble: &'t dyn ToTokens,
604 sep: &'t dyn ToTokens,
605 ) -> Self {
606 TokenOutputTrimmer {
607 preamble: Some(preamble),
608 sep,
609 sep_count: 0,
610 out,
611 }
612 }
613 pub fn push_sep(&mut self) {
614 self.sep_count += 1;
615 }
616 fn reify(&mut self) {
617 if let Some(preamble) = self.preamble.take() {
618 preamble.to_tokens(&mut self.out);
619 }
620 for _ in 0..mem::take(&mut self.sep_count) {
621 self.sep.to_tokens(&mut self.out);
622 }
623 }
624 pub fn push_reified(&mut self, t: impl ToTokens) {
625 self.reify();
626 t.to_tokens(&mut self.out);
627 }
628 pub fn did_preamble(self) -> Option<()> {
630 if self.preamble.is_some() {
631 None
632 } else {
633 Some(())
634 }
635 }
636}
637
638pub type TemplateName = SyntheticMacroName<SyntheticMacroTemplate>;
641pub type ModuleName = SyntheticMacroName<SyntheticMacroModule>;
642
643#[derive(Debug, Clone)]
647pub struct SyntheticMacroName<Kind>(syn::Ident, Kind);
648
649pub trait SyntheticMacroKind: Default + Copy + Debug {
651 const WHAT: &'static str;
652}
653
654#[derive(Debug, Clone, Copy, Default)]
657pub struct SyntheticMacroTemplate;
658impl SyntheticMacroKind for SyntheticMacroTemplate {
659 const WHAT: &'static str = "template";
660}
661
662#[derive(Debug, Clone, Copy, Default)]
663pub struct SyntheticMacroModule;
664impl SyntheticMacroKind for SyntheticMacroModule {
665 const WHAT: &'static str = "module";
666}
667
668fn synthetic_macro_name_check(
671 ident: &syn::Ident,
672 what: &str,
673) -> syn::Result<()> {
674 let s = ident.to_string();
675 match s.chars().find(|&c| c != '_') {
676 None => Err(format!(
677 "{} name cannot consist entirely of underscores",
678 what,
679 )),
680 Some(c) => {
681 if c.is_lowercase() {
682 Err(format!(
683 "{} name may not start with a lowercase letter (after any underscores)", what,
684 ))
685 } else {
686 Ok(())
687 }
688 }
689 }
690 .map_err(|emsg| ident.error(emsg))
691}
692
693fn synthetic_macro_name_macro_name(
694 ident: &syn::Ident,
695 what: &str,
696) -> syn::Ident {
697 format_ident!("derive_deftly_{}_{}", what, ident)
698}
699
700impl_to_tokens!(SyntheticMacroName[K], 0);
703impl_display!(SyntheticMacroName[K], 0);
704
705impl<K: SyntheticMacroKind> SyntheticMacroName<K> {
706 pub fn macro_name(&self) -> syn::Ident {
707 synthetic_macro_name_macro_name(&self.0, K::WHAT)
708 }
709}
710
711impl<K: SyntheticMacroKind> Parse for SyntheticMacroName<K> {
712 fn parse(input: ParseStream) -> syn::Result<Self> {
713 let ident: syn::Ident = input.parse()?;
714 ident.try_into()
715 }
716}
717
718impl<K: SyntheticMacroKind> TryFrom<syn::Ident> for SyntheticMacroName<K> {
719 type Error = syn::Error;
720 fn try_from(ident: syn::Ident) -> syn::Result<SyntheticMacroName<K>> {
721 synthetic_macro_name_check(&ident, K::WHAT)?;
722 Ok(SyntheticMacroName(ident, K::default()))
723 }
724}
725impl<K> quote::IdentFragment for SyntheticMacroName<K> {
726 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
727 quote::IdentFragment::fmt(&self.0, f)
728 }
729 fn span(&self) -> Option<Span> {
730 quote::IdentFragment::span(&self.0)
731 }
732}
733
734pub type TemplatePath = SyntheticMacroPath<SyntheticMacroTemplate>;
737pub type ModulePath = SyntheticMacroPath<SyntheticMacroModule>;
738
739#[derive(Debug, Clone)]
741pub struct SyntheticMacroPath<Kind>(syn::Path, Kind);
742
743impl_to_tokens!(SyntheticMacroPath[K], 0);
744
745fn synthetic_macro_path_parse(
746 input: ParseStream,
747 what: &str,
748) -> syn::Result<syn::Path> {
749 let path = syn::Path::parse_mod_style(input)?;
750
751 let last = path.segments.last().ok_or_else(|| {
752 path.leading_colon
753 .as_ref()
754 .expect("path with no tokens!")
755 .error("empty path not allowed here")
756 })?;
757
758 synthetic_macro_name_check(&last.ident, what)?;
759
760 Ok(path)
761}
762
763fn synthetic_macro_path_macro_path(path: &syn::Path, what: &str) -> syn::Path {
764 let mut out = path.clone();
765 let last = &mut out.segments.last_mut().expect("became empty!").ident;
766 *last = synthetic_macro_name_macro_name(last, what);
767 out
768}
769
770impl<K: SyntheticMacroKind> Parse for SyntheticMacroPath<K> {
771 fn parse(input: ParseStream) -> syn::Result<Self> {
772 let path = synthetic_macro_path_parse(input, K::WHAT)?;
773 Ok(SyntheticMacroPath(path, K::default()))
774 }
775}
776
777impl<K: SyntheticMacroKind> SyntheticMacroPath<K> {
778 pub fn macro_path(&self) -> syn::Path {
779 synthetic_macro_path_macro_path(&self.0, K::WHAT)
780 }
781}
782
783pub fn engine_macro_name() -> Result<TokenStream, syn::Error> {
793 let name = crate_name("derive-deftly-macros")
794 .or_else(|_| crate_name("derive-deftly"));
795
796 #[cfg(feature = "bizarre")]
799 let name = name.or_else(|_| crate_name("bizarre-derive-deftly"));
800
801 match name {
802 Ok(FoundCrate::Itself) => Ok(quote!( crate::derive_deftly_engine )),
803 Ok(FoundCrate::Name(name)) => {
804 let ident = Ident::new(&name, Span::call_site());
805 Ok(quote!( ::#ident::derive_deftly_engine ))
806 }
807 Err(e) => Err(Span::call_site().error(
808 format_args!("Expected derive-deftly or derive-deftly-macro to be present in Cargo.toml: {}", e)
809 )),
810 }
811}
812
813macro_rules! keyword_general {
835 { $kw_var:ident $from_enum:ident $Enum:ident;
836 $kw:ident $( $rest:tt )* } => {
837 keyword_general!{ $kw_var $from_enum $Enum;
838 @ 1 stringify!($kw), $kw, $($rest)* }
839 };
840 { $kw_var:ident $from_enum:ident $Enum:ident;
841 $kw:literal: $constr:ident $( $rest:tt )* } => {
842 keyword_general!{ $kw_var $from_enum $Enum;
843 @ 1 $kw, $constr, $($rest)* }
844 };
845 { $kw_var:ident $from_enum:ident $Enum:ident;
846 @ 1 $kw:expr, $constr:ident, $( $ca:tt )? } => {
847 keyword_general!{ $kw_var $from_enum $Enum;
848 @ 2 $kw, $constr, { } $( $ca )? }
849 };
850 { $kw_var:ident $from_enum:ident $Enum:ident;
851 @ 1 $kw:expr, $constr:ident, { $( $bindings:tt )* } $ca:tt } => {
852 keyword_general!{ $kw_var $from_enum $Enum;
853 @ 2 $kw, $constr, { $( $bindings )* } $ca }
854 };
855 { $kw_var:ident $from_enum:ident $Enum:ident;
856 @ 2 $kw:expr, $constr:ident,
857 { $( $bindings:tt )* } $( $constr_args:tt )?
858 } => {
859 let _: &IdentAny = &$kw_var;
860 if $kw_var == $kw {
861 $( $bindings )*
862 return $from_enum($Enum::$constr $( $constr_args )*);
863 }
864 };
865 { $($x:tt)* } => { compile_error!(stringify!($($x)*)) };
866}