PoignardAzur / venial

"A very small syn"
MIT License
192 stars 9 forks source link

Guidance on parsing proc-macro attributes #53

Open Bromeon opened 8 months ago

Bromeon commented 8 months ago

It's currently not obvious how venial should be used to parse a #[proc_macro_attribute] macro.

I typically used this pattern, where I simply treat the attribute macro as an attribute in the item.

use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;

#[proc_macro_attribute]
pub fn itest(meta: TokenStream, input: TokenStream) -> TokenStream {
    let self_name = format_ident!("itest"); // name of this function
    let input2 = TokenStream2::from(input);
    let meta2 = TokenStream2::from(meta);

    let input2 = quote! {
        #[#self_name(#meta2)]
        #input2
    };

    let result2 = venial::parse_declaration(input2)
    // now work with result2, as if it were a regular attribute
    ...
}

But this is not the only usage pattern. Sometimes people don't care about the attribute, and usually they want it removed from the output.

Do you think it makes sense to provide a dedicated API for this? For example:

// 1) above use case: macro becomes an attribute
pub fn parse_attribute_macro(
    meta: TokenStream,
    item: TokenStream,
    macro_name: &str,
) -> Result<Declaration, Error>;

and

// 2) separate meta and item -- former would just be left unparsed
pub fn parse_attribute_macro(
    meta: TokenStream,
    item: TokenStream,
) -> Result<(ValueExpr, Declaration), Error>;

Or should we rather document different approaches and guide the user towards parse_declaration()?

PoignardAzur commented 8 months ago

I'd rather have a function like parse_macro_attribute_stream that takes the "meta" TokenStream and returns a Result<Attribute, Err>, but I haven't given this a lot of thought.

Bromeon commented 8 months ago

I'd rather have a function like parse_macro_attribute_stream that takes the "meta" TokenStream and returns a Result<Attribute, Err>, but I haven't given this a lot of thought.

The Attribute needs a name, so that would have to be passed in -- I could make a PR proposal here, should be easy to add.

PoignardAzur commented 8 months ago

That works. Just keep in mind that name wouldn't necessarily be accurate, since the actual invocation could use a path and you'd have no way to know.