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}