1 //! Support for nested invocations of proc-macro-hack expression macros. 2 //! 3 //! By default, macros defined through proc-macro-hack do not support nested 4 //! invocations, i.e. the code emitted by a proc-macro-hack macro invocation 5 //! cannot contain recursive calls to the same proc-macro-hack macro nor calls 6 //! to any other proc-macro-hack macros. 7 //! 8 //! This crate provides opt-in support for such nested invocations. 9 //! 10 //! To make a macro callable recursively, add a dependency on this crate from 11 //! your declaration crate and update the `#[proc_macro_hack]` re-export as 12 //! follows. 13 //! 14 //! ``` 15 //! // Before 16 //! # const IGNORE: &str = stringify! { 17 //! #[proc_macro_hack] 18 //! pub use demo_hack_impl::add_one; 19 //! # }; 20 //! ``` 21 //! 22 //! ``` 23 //! // After 24 //! # const IGNORE: &str = stringify! { 25 //! #[proc_macro_hack(support_nested)] 26 //! pub use demo_hack_impl::add_one; 27 //! # }; 28 //! ``` 29 //! 30 //! No change is required within your definition crate, only to the re-export in 31 //! the declaration crate. 32 //! 33 //! # Limitations 34 //! 35 //! - Nested invocations are preprocessed by a TT-muncher, so the caller's crate 36 //! will be required to contain `#![recursion_limit = "..."]` if there are 37 //! lengthy macro invocations. 38 //! 39 //! - Only up to 64 nested invocations are supported. 40 41 #![no_std] 42 43 // ANDROID: Use std to allow building as a dylib. 44 extern crate std; 45 46 include!(concat!(env!("OUT_DIR"), "/count.rs")); 47 48 #[doc(hidden)] 49 #[macro_export] 50 macro_rules! dispatch { 51 (() $($bang:tt)*) => { 52 $crate::count!($($bang)*) 53 }; 54 ((($($first:tt)*) $($rest:tt)*) $($bang:tt)*) => { 55 $crate::dispatch!(($($first)* $($rest)*) $($bang)*) 56 }; 57 (([$($first:tt)*] $($rest:tt)*) $($bang:tt)*) => { 58 $crate::dispatch!(($($first)* $($rest)*) $($bang)*) 59 }; 60 (({$($first:tt)*} $($rest:tt)*) $($bang:tt)*) => { 61 $crate::dispatch!(($($first)* $($rest)*) $($bang)*) 62 }; 63 ((! $($rest:tt)*) $($bang:tt)*) => { 64 $crate::dispatch!(($($rest)*) $($bang)* !) 65 }; 66 ((!= $($rest:tt)*) $($bang:tt)*) => { 67 $crate::dispatch!(($($rest)*) $($bang)* !) 68 }; 69 (($first:tt $($rest:tt)*) $($bang:tt)*) => { 70 $crate::dispatch!(($($rest)*) $($bang)*) 71 }; 72 } 73