简体   繁体   中英

No main function error when parsing the attributes of the proc macro

In a procedural macro attached to a main function, I am parsing the attributes passed as AttributeArgs to the macro.

#[proc_macro_attribute]
pub fn macro(_meta: CompilerTokenStream, input: CompilerTokenStream) -> CompilerTokenStream {
    let attrs = syn::parse_macro_input!(_meta as syn::AttributeArgs);
    for nested_meta in attrs {
        match nested_meta {
            syn::NestedMeta::Meta(m) =>
                println!("Parsed metadata: {:?}", &m.path().get_ident().unwrap().to_string()),
            syn::NestedMeta::Lit(lit) => match lit {
                syn::Lit::Str(ref l) => return report_literals_not_allowed(&l.value(), &lit),
                syn::Lit::ByteStr(ref l) => return report_literals_not_allowed(&String::from_utf8_lossy(&l.value()), &lit),
                syn::Lit::Byte(ref l) => return report_literals_not_allowed(&l.value().to_string(), &lit),
                syn::Lit::Char(ref l) => return report_literals_not_allowed(&l.value().to_string(), &lit),
                syn::Lit::Int(ref l) => return report_literals_not_allowed(&l.to_string(), &lit),
                syn::Lit::Float(ref l) => return report_literals_not_allowed(&l.to_string(), &lit),
                syn::Lit::Bool(ref l) => return report_literals_not_allowed(&l.value().to_string(), &lit),
                syn::Lit::Verbatim(ref l) => return report_literals_not_allowed(&l.to_string(), &lit)
            }
        }
    }

    // Parses the function that this attribute is attached to
    let func_res = syn::parse::<FunctionParser>(input);
    
    if func_res.is_err() {
        return quote! { fn main() {} }.into()
    }
    
    let func = func_res.ok().unwrap();
    let sign = func.clone().sig;
    let body = func.clone().block.stmts;

    let rt = tokio::runtime::Runtime::new().unwrap();
    rt.block_on(async {
        Handler::run().await;
    });

    let mut queries_tokens: Vec<TokenStream> = Vec::new();
    wire_queries_to_execute(&mut queries_tokens);
    
    // The final code wired in main()
    quote! {
        #[tokio::main]
        async #sign {
            {
                #(#queries_tokens)*
            }
            #(#body)*
        }
    }.into()

}

When the user of this macro, makes an error inside main, I return this:

let func_res = syn::parse::<FunctionParser>(input);

    if func_res.is_err() {
        return quote! { fn main() {} }.into()
    }

Rust analyzer and the compiler reports fine the errors on the code, and then a new main() is wired again, so there's no error main function not found in crate. Please, consider add a main function... main function not found in crate. Please, consider add a main function... which is the problem that I want to solve.

But, when an error is detected on the parsed attributes, I am not able to get rid out of that error. What I've tried so far is this:

pub fn report_literals_not_allowed(ident: &str, s: &Lit) -> TokenStream {
    syn::Error::new_spanned(ident, s.span.into()), 
        "No literals allowed in the `macro` proc-macro"
    ).into_compile_error().into()
}

Which reports exactly where the user is passing a literal, which is a feature not allowed in the arguments of the attribute.

I've tried to solve it like this:

pub fn report_literals_not_allowed(ident: &str, s: &Lit) -> TokenStream {
    let ident = Ident::new(ident, s.span().into());
    syn::Error::new_spanned(
        quote! {
            #ident
            fn main() {}
        }, 
        "No literals allowed in the `macro` proc-macro"
    ).into_compile_error().into()
}

but I still have the same error of no 'main' funcion found in crate...

How can I report the error of that the macro does not accept literal values, and remove the error of not main found at the same time?

syn::Error just generates code that calls compile_error!() . It is a normal TokenStream . You just need to extend it with the code you want:

pub fn report_literals_not_allowed(ident: &str, s: &Lit) -> TokenStream {
    let error = syn::Error::new_spanned(s, "No literals allowed in the `macro` proc-macro")
        .into_compile_error();
    quote! {
        #error

        fn main() {}
    }
    .into()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM