use quote::{quote};
use syn::{NestedMeta, ItemStruct, parse_macro_input, Lit, Fields};
use syn::parse::Parser;
fn parse_args(metadata: Vec<NestedMeta>) -> Vec<String> {
metadata.iter().map(|i| {
match i {
NestedMeta::Lit(Lit::Int(i)) => format!("add_{}", i),
_ => panic!("error value ")
}
}).collect()
}
#[proc_macro_attribute]
pub fn extend(args: TokenStream, input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as ItemStruct);
let args = parse_macro_input!(args as Vec<NestedMeta>);
match &mut ast.fields {
Fields::Named(ref mut fields) => {
let arg = parse_args(args);
for name in arg {
fields.named.push(syn::Field::parse_named.parse2(quote! { pub #name: String }).unwrap());
}
}
_ => panic!("error")
}
return quote! {
#ast
}.into();
}
i have took a look at here
but the quote! { pub #name: String }
parse failed.
error output
= help: message: called `Result::unwrap()` on an `Err` value: Error("expected identifier")
here is a test code
.
#[extend(1, 2, 3)]
#[derive(Debug, Default)]
pub struct Example
{
pub b: i32,
}
fn main() {
let example = Example { b: 2, ..Default::default() };
println!("{:?}", example)
}
H2CO3
February 6, 2023, 6:43pm
2
Strings quote to a string literal, so your expanded result won't contain identifiers but string literals. You should use proc_macro2::Ident
instead.
can you give me a example? ...
H2CO3
February 6, 2023, 6:51pm
4
You need to replace the String
return type of parse_args
with Ident
. You can look up the API of Ident
in its official documentation .
By the way, there are other problems with your code too:
don't use parse2(quote!{ … }).unwrap()
, that'd be parse_quote!{ … }
instead.
explicit returns at the end of the function are unnecessary and non-idiomatic. Rust is an expression language.
quoting a single variable is unnecessary. Just use its ToTokens
impl to turn it into a TokenStream
directly.
All in all, something like this should work. (Untested; the Playground can't run proc-macro code so you'll likely need to adjust some trivial errors such as missing imports.)
1 Like
thank for you suggestions.
use proc_macro::{TokenStream};
use std::hint::unreachable_unchecked;
use proc_macro2::{Ident, Span};
use quote::{quote};
use syn::{NestedMeta, ItemStruct, parse_macro_input, Lit, Fields};
use syn::parse::Parser;
fn parse_args(metadata: Vec<NestedMeta>) -> Vec<(Ident, &'static str)> {
metadata.iter().map(|i| {
match i {
NestedMeta::Lit(Lit::Int(i)) => (Ident::new(format!("add_{}", i).as_str(), Span::call_site()), "i32"),
NestedMeta::Lit(Lit::Float(i)) => (Ident::new(format!("add_{}", i.base10_digits().parse::<f64>().unwrap() as i32).as_str(), Span::call_site()), "f64"),
_ => panic!("error type of value ")
}
}).collect()
}
#[proc_macro_attribute]
pub fn extend(args: TokenStream, input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as ItemStruct);
let args = parse_macro_input!(args as Vec<NestedMeta>);
match &mut ast.fields {
Fields::Named(ref mut fields) => {
let arg = parse_args(args);
for (name, ori) in arg {
match ori {
"i32" => fields.named.push(syn::Field::parse_named.parse2(quote! { pub #name: i32 }).unwrap()),
"f64" => fields.named.push(syn::Field::parse_named.parse2(quote! { pub #name: f64 }).unwrap()),
_ => unsafe { unreachable_unchecked() }
}
}
}
_ => panic!("error")
}
(quote! { #ast }).into()
}
this worked for me.
system
Closed
May 7, 2023, 7:08pm
6
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.