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