Programmatically macro-expand a TokenStream during proc macro function execution

Hi folks,

I was wondering - is it possible to programmatically expand a TokenStream during proc macro execution?

I have a token stream that gets copied into N branches of a match, and if that token stream itself contains a macro, this will result in that inner macro being executed N times. (Or really, N^depth times).

Unfortunately, I cannot store the results of that token stream into a variable at run time, as that would create borrowck issues, and ruin the whole point of the exercise :slight_smile:

So I'm thinking - I either cache the results of that macro (which we all know is a hard problem, especially since there is no thread-local storage), or expand it in advance, and insert the expanded tokenstream into the N branches of the match. Is this possible?

Thank you!

You need to have access to a
proc_macro::TokenStream -> proc_macro::TokenStream
function for that.

If the inner macro is defined within the same crate as your procedural macro, then you should be able to just call it.

Else, that macro needs to exist / be exported in a non proc-macro crate as a
::proc_macro2::TokenStream -> ::proc_macro2::TokenStream
function (that's the whole point of the ::proc_macro2 crate, by the way: getting access to meta-programming tools as if they were just classic functions).

You can then use that function by just wrapping the function's input and ouput with .into() calls.

@Yandros -

To clarify, the TokenStream that is duplicated N times is arbitrary. (It is whatever is between curly braces). So, all of the following would be valid:

macro!(<div>{ macro!(<span />) }</div>)
macro!(<div>{ if (foo) { macro!(<span />) } else { <div /> } }</div>)
macro!(<div>{ some_variable }</div>)

I could grep the TokenStream for macro! calls, but that sounds fragile.

So, I guess what I'm saying is that my (mere mortal) programming skills aren't up to the task of macro-expanding arbitrary Rust by hand, and was hoping that functionality was already exposed somehow :wink:

Although, on closer inspection, it's clear that macro! in the above actually depends on what macros are in scope. i.e. use foo::macro and use bar::macro would result in different macros being executed. I don't think this sort of contextual information is available at proc-macro execution time :confused: