proc_macro_nested/
lib.rs

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
43include!(concat!(env!("OUT_DIR"), env!("PATH_SEPARATOR"), "count.rs"));
44
45#[doc(hidden)]
46#[macro_export]
47macro_rules! dispatch {
48    (() $($bang:tt)*) => {
49        $crate::count!($($bang)*)
50    };
51    ((($($first:tt)*) $($rest:tt)*) $($bang:tt)*) => {
52        $crate::dispatch!(($($first)* $($rest)*) $($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    ((! $($rest:tt)*) $($bang:tt)*) => {
61        $crate::dispatch!(($($rest)*) $($bang)* !)
62    };
63    ((!= $($rest:tt)*) $($bang:tt)*) => {
64        $crate::dispatch!(($($rest)*) $($bang)* !)
65    };
66    (($first:tt $($rest:tt)*) $($bang:tt)*) => {
67        $crate::dispatch!(($($rest)*) $($bang)*)
68    };
69}