I am not good at English. Sorry if there are any funny expressions.
Background
Today I am creating my first procedural macro.
(In my opinion, macro is useful but fearful, and procedural macro is more )
(IDE is not responding due to my infinite loop bug )
At my first attempt, auto-completion did not work within block of my macro.
(I am very forgetful. So, I cannot live without IDE and auto-completion🦮)
Solution?
After struggling a while, I found following rules.
(Inspired by tips about other than block.)
- Avoid errors where auto-completion is expected.
- Instead, output the code as it is entered.
Finally, I wrote the following code.
This code simply executes the given block.
- macros/src/lib.rs
use proc_macro as pm;
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{ParseStream, Parser};
use syn::{braced, Error, Result, Stmt};
#[proc_macro]
pub fn exec_block(input: pm::TokenStream) -> pm::TokenStream {
exec_block_impl(input.into()).into()
}
fn exec_block_impl(input: TokenStream) -> TokenStream {
exec_block_parse
.parse2(input)
.unwrap_or_else(Error::into_compile_error)
}
fn exec_block_parse(input: ParseStream) -> Result<TokenStream> {
let mut result = TokenStream::new();
let content;
braced!(content in input);
while !content.is_empty() {
let orig = content.fork().cursor().token_stream();
let stmt = content.parse::<Stmt>();
let trns = stmt.as_ref().map_or(orig, |x| quote! {#x});
result.extend(trns);
if stmt.is_err() {
break;
}
}
Ok(result)
}
- app/src/main.rs
use macros::exec_block;
fn main() {
let vec = vec!["Hello", "procedural", "macro"];
exec_block!({
let pos = 2;
// Input this code manually for auto-completion test.
assert_eq!(vec[pos].len(), 5);
});
}
My question.
Is this solution reasonable?
(When I am not feeling good in my code, I look for similar code by experts to reassure myself.)
(But in this case, I can't find any similar code when I Google the code fragment...)