I'm trying to debug a complex procedural macro in a library I am using.
Since I cannot use a debugger with macros and various macro expansion tools have proved useless here, I'm looking for an alternative.
Can a procedural macro be run like a function with proper debugging? I imagine storing the resultant proc_macro::TokenStream
in a variable.
The proc-macro2
crate is a drop-in replacement for proc_macro
except that it is available outside of macros - which makes it testable. Its types are all convertible to and from the proc_macro
types and have identical methods.
The usual pattern for writing a nontrivial macro is to use proc_macro
only for the entry point, and use proc-macro2
for all of the real work:
extern crate proc_macro;
use proc_macro2::TokenStream;
#[proc_macro]
pub fn my_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let output = transform_stream(TokenStream::from(input));
proc_macro::TokenStream::from(output)
}
// A testable function!
fn transform_stream(input: TokenStream) -> TokenStream {
// actual work goes here
}
It's common to import items from proc-macro2
so they can be used unqualified, and just used fully qualified names for proc_macro
, since the only time you will use it is in the entry point. It's also usual to put the core components in a separate library crate, which does not have a dependency on proc_macro
.
In tests, you can create a TokenStream
from a string:
use std::str::FromStr;
let ts = TokenStream::from_str("fn foo() {}").unwrap();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.