I'm obviously struggling with parsing in the context of a proc-macro-attribute....
I've also had difficulty getting a fully working example in the playground, so please excuse the code pasting.
Context:
Take an attribute with these forms:
-
#[trace]
, -
#[trace("own")]
, -
#[trace(other=true)]
,
and after parsing have an argument list as Vec<NestedMeta>
that would be equivalent to:
-
#[trace(name="__default")]
, -
#[trace(name="own")]
, #[trace(name="__default", other=true)]
Status:
I am able to take the TokenStream
and rewrite or append the name
parameter. The relevant code for this is:
let parser = syn::punctuated::Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated;
let mut stream = syn::parse::Parser::parse2(parser, (*args).clone()).expect("Token stream");
let mut name_pair: syn::Expr = syn::parse_str::<syn::Expr>("name = __default").unwrap();
stream.iter_mut().for_each(|e| {
#[allow(clippy::single_match)]
match e {
syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit_str),
attrs: _,
}) => {
let value = (*lit_str).value();
let name = format!("name = {}", value);
name_pair = syn::parse_str::<syn::Expr>(name.as_str()).unwrap();
}
_ => {} //?
}
});
stream.push(name_pair);
However, this 'new' TokenStream
, say ts
, breaks parse_macro_input!(ts as AttributeArgs)
with the error, error: expected literal
I'm obviously missing something obvious, or going about this all wrong.
The attribute code is:
#[proc_macro_attribute]
#[proc_macro_error]
pub fn trace(
args: proc_macro::TokenStream,
items: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
println!("args: {:#?}", args);
let nm_args = parse_macro_input!(args as AttributeArgs);
let validated = trace::validate(&args.clone().into(), &items.clone().into());
let va: proc_macro::TokenStream = validated.into();
println!("va: {:#?}", va);
let nm_vargs = parse_macro_input!(va as AttributeArgs);
items
}
Given the test case is:
#[trace(enter_on_poll = true)]
fn f(a: u32) -> u32 {
a
}
fn main() {
f(1);
}
When I run this test case, then the error is:
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error: expected literal
--> tests/trace/ui/ok/002-has-enter_on_poll-ident.rs:3:1
|
3 | #[trace(enter_on_poll=true)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `trace` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0425]: cannot find function `f` in this scope
--> tests/trace/ui/ok/002-has-enter_on_poll-ident.rs:9:5
|
9 | f(1);
| ^ not found in this scope
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
If I comment out the parse_macro_input!(va as AttributeArgs)
, the print statements show these 2 data structures:
-
args: TokenStream [ Ident { ident: "enter_on_poll", span: #0 bytes(31..44), }, Punct { ch: '=', spacing: Alone, span: #0 bytes(44..45), }, Ident { ident: "true", span: #0 bytes(45..49), }, ]
-
va: TokenStream [ Ident { ident: "enter_on_poll", span: #0 bytes(31..44), }, Punct { ch: '=', spacing: Alone, span: #0 bytes(44..45), }, Ident { ident: "true", span: #0 bytes(45..49), }, Punct { ch: ',', spacing: Alone, span: #4 bytes(23..51), }, Ident { ident: "name", span: #4 bytes(23..51), }, Punct { ch: '=', spacing: Alone, span: #4 bytes(23..51), }, Ident { ident: "__default", span: #4 bytes(23..51), }, ]
Appreciate any hints or tips about what I might be doing incorrectly.