I'm trying to create a macro system and I suspect that it might not be possible with the current implementation of procedural macros, but I figured I'd check.
My desired system has three macros:
- A
child!
macro that does some useful work - A
def!
macro that generates thechild!
macro depending on the inputs todef!
- A
call!
macro that calls thechild!
macro, passing some of the parameters that were passed tocall!
The goal is that def!
and call!
will be the interface that I expose to my library's clients, and child!
will just be an implementation detail that the client doesn't have to care (or, ideally, know) about. Ideally, a client crate could have multiple (def!
, call!
) pairs (the exact name of child!
depends on the inputs to def!
and call!
).
My current approach is to define def!
and call!
as procedural macros in my library crate my_lib
and have child!
be a macro_rules!
macro that is generated by def!
. A client library will call def!
in one file (which will cause child!
to be defined) and then call call!
in a separate file (which will invoke child!
).
In code:
my_lib/lib.rs
:
#[proc_macro_attribute]
pub fn def(a: TokenStream, b: TokenStream) -> TokenStream {
parse a and b
return quote!(macro_rules! child_whose_name_depends_on_b {
() => {behavior that depends on b}
})
}
#[proc_macro_attribute]
pub fn call(a: TokenStream, b: TokenStream) -> TokenStream {
parse a and b
return quote!(child_whose_name_depends_on_b! {})
}
client_crate/file_one.rs
:
use my_lib::def;
#[def]
trait MyTrait {...}
client_crate/file_two.rs
:
use my_lib::call;
use crate::file_one::MyTrait;
struct MyStruct;
#[call]
impl MyTrait for MyStruct {...}
The problem I'm seeing right now is that child!
is not reliably defined. For the example above, the specific error I'm seeing is
error: cannot find macro `child_whose_name_depends_on_b` in this scope
--> client_crate/file_two.rs
Is there just something wrong with my implementation or is there a fundamental problem with this approach? Having read some posts about sharing state between procedural macros, I suspect that my problem might be that I can't rely on def!
being expanded before call!
.