#is there a clean way to go from Literal to Ident in proc_macro2?

1 messages · Page 1 of 1 (latest)

dusky mantle
#

is there a clean way to go from proc_macro2::TokenTree::Literal(_) to proc_macro2::TokenTree::Ident(_) ?

dusky mantle
#

I tried going from TokenTree::Literal to a TokenStream in hopes that parse_macro_input(my_token_stream as Ident) would solve my issue but I am getting conflicting errors

let ss = tti.next().expect("Expect <field identifier>");
    let ts: TokenStream2 = ss.to_token_stream();
    let ts: TokenStream = proc_macro::TokenStream::from(ts);
    let ident = parse_macro_input!(ts as Ident);

ss is a TokenTree::Literal

As you can see I make sure to pass proc_macro::TokenStream and not from proc_macro2 but if I do that the compiler says expected proc_macro2::TokenStream. if I pass in that, the macro wants proc_macro::TokenStream

I don't understand how can both types fail here

#
   // TokenTree::Literal(Literal { .. })
    let ss : TokenTree = tti.next().expect("Expect <field identifier>");

    let ts2: TokenStream2 = ss.to_token_stream();
    let ts: TokenStream = proc_macro::TokenStream::from(ts2);
    // Doesn't work with either ts2 or ts
    let ident = parse_macro_input!(ts as Ident);
remote anchor
#

The real rule of thumb is to have:

use ::syn::Result;

// Input uses `TokenStream2` types.
fn function_impl(…) -> Result<TokenStream2> {
    … /* use `?` for Fun And Profit™ */
}

// Input uses `TokenStream` types.
#[proc_macro…] pub
fn function(…) -> TokenStream {
    function_impl(….into() …)
        .unwrap_or_else(::syn::Error::into_compile_error)
        .into()
}
#

No parse_macro_input! magic, just straight honest code

#

(parse_macro_input! is designed to be used exactly within a #[proc_macro…]-annotated fn, since it expects the return type to be a ::proc_macro::TokenStream)

remote anchor
#

(but you'll often rather use ::syn::parse2 at this point)

#

Finally, you may want to consider directly receiving an ident rather than a string literal

dusky mantle
dusky mantle
remote anchor
remote anchor
#

It comes from the old way attributes were shaped, which was quite restrictive and required string literals

#

Which is why, for instance, serde does that too

#

If you've already written the code using Meta, then don't bother changing that nit (since it would require more effort than it may be worth), and use that .parse() on the LitStr

#

What I personally use for attributes is just another layer of a custom Parse impl

#
// if you can write a proc-macro able to handle
stuff!(foo, bar(helper)); // <- you wouldn't parse this input as `Meta`

// then you can use that same logic to have an attribute able to handle
#[stuff(foo, bar(helper))]
dusky mantle
remote anchor
#

(since said Parse impl would depend on it)

dusky mantle
#

Currently I am going through dtolnay's workshop and exercise 7 wants you to parse this :

    #[builder(each = "arg")]
remote anchor
dusky mantle
#

Well, either ways, I'd like to not restrict myself to using Metas cuz I find myself writing too many if lets

#

I'd prefer the token_stream.next() way

remote anchor
#

Then, you can checker it starts with builder by checking that attr.is_ident("builder") holds