macro_magic icon indicating copy to clipboard operation
macro_magic copied to clipboard

Does macro_magic::import_tokens_proc require function like macros to only accept a single argument?

Open m1212e opened this issue 1 year ago • 4 comments

Hi,

I'm trying to write a function like proc macro which I intend to be used like this:

let query = find_one!(Person).unwrap();

which works perfectly fine. My macro implementation looks like this:

#[macro_magic::import_tokens_proc]
#[proc_macro]
pub fn find_one(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as FindOneArgs);
    find_one_internal(input).into()
}

Everything is as expected, the input stream gets fed the struct Person { ... } tokens, then I can use syn to parse it and do stuff.

Now I would like to allow the user of my macro to pass a second argument.

let query = find_one!(Person, db).unwrap();

I'd expect the stream to just concat the db token which I could in return parse into an Ident. But as soon as I add a second argument separated by a , I get unexpected token rust-analyzer[macro-error]) for the ,. My parsing logic allows for the second argument and works in an isolated environment, the error is not coming from my impl Parse for the argument struct. Am I doing something wrong? I'm afraid I don't quite fully understand what I'm doing/how macro_magic works and would be very thankful for any advice! Thank you very much for this awesome tool!

m1212e avatar Feb 12 '25 22:02 m1212e

you will have to use #[with_custom_parsing(..)] for that, since the argument to the macro is no longer a simple path to an item that macro_magic knows how to resolve.

https://docs.rs/macro_magic/0.5.1/macro_magic/attr.with_custom_parsing.html

But this might be an edge case, I don't know if it actually works with import_tokens_proc. In any case is should so let me know if it doesn't.

The way #[with_custom_parsing(..)] works is you just provide the name of a struct that implements Parse. See https://docs.rs/macro_magic/0.5.1/macro_magic/attr.import_tokens_attr.html#optional-feature-with_custom_parsing

That said, import_tokens_proc does support passing code that evaluates to a path string at macro run-time: https://docs.rs/macro_magic/0.5.1/macro_magic/attr.import_tokens_proc.html#overriding-macro_magic_root so there may be a way you could abuse that

But yeah looks like we need #[with_custom_parsing(..)] for import_tokens_proc. Let me know if it doesn't work out of the box and I'll add it

sam0x17 avatar Feb 14 '25 03:02 sam0x17

another common approach here btw is to just have yet another macro with the exact syntax you want that expands to something that calls the macro_magic macro, in some scenarios that is enough

sam0x17 avatar Feb 14 '25 03:02 sam0x17

but yeah the arg to macros created via import_tokens_proc is automatically interpreted as a path to an item that effectively has #[export_tokens] on it, directly or indirectly

sam0x17 avatar Feb 14 '25 03:02 sam0x17

Doesn't seem to work by default. I worked around it by using a regular proc macro (could just use macro_rules for simple cases) that expands to an expression with the attribute macro that actually imports the tokens. With this I didn't even need custom parsing since I could just expand to the form I wanted for the attribute macro and parse it from the regular tokens.

pandarrr avatar Apr 02 '25 15:04 pandarrr