Hi,
I'm writting a proc macro to generate some wrapper code. When I call syn::parse2
, it returns an Err
saying that unexpected token, expected
]``. I inspected in debugger and found Input::parse
already returns Ok(Input)
.
I read the doc on syn::parse2
and it says:
This function enforces that the input is fully parsed. If there are any unparsed tokens at the end of the stream, an error is returned.
So maybe the error is coming from unparsed tokens. But I don't find unparsed tokens... Anyone can help me
extern crate proc_macro;
use proc_macro::TokenStream;
use syn::{
braced, bracketed, parenthesized,
parse::{Parse, ParseStream},
parse_macro_input,
punctuated::Punctuated,
token::{Brace, Comma, Semi},
Attribute, FnArg, Generics, Ident, Meta, Token, Type,
};
fn parse_meta(input: ParseStream) -> syn::Result<bool> {
let is_wrapped = if input.parse::<Token![#]>().is_ok() {
let content;
let _ = bracketed!(content in input);
let r = content.to_string();
if r == "rhi" {
true
} else {
panic!("expected #[rhi] attribute, found #[{}]", r);
}
} else {
false
};
Ok(is_wrapped)
}
#[derive(Clone)]
struct FunctionArg {
is_wrapped: bool,
arg: FnArg,
}
impl Parse for FunctionArg {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(FunctionArg {
is_wrapped: parse_meta(input)?,
arg: FnArg::parse(input)?,
})
}
}
// -> #[rhi] Result<RenderPass>
#[derive(Clone)]
struct FunctionReturn {
is_wrapped: bool,
ty: Type,
generics: Generics,
}
impl Parse for FunctionReturn {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
// #[rhi] Result<GraphicsPipeline, Error>
let is_wrapped = parse_meta(input)?;
let ty = input.parse()?;
let generics = input.parse()?;
Ok(Self {
is_wrapped,
ty,
generics,
})
}
}
// fn bind_shader_resource_group(&mut self, index: u32, #[rhi] srg: &ShaderResourceGroup) -> &mut Self;
#[derive(Clone)]
struct FunctionDecl {
fn_name: Ident,
args: Vec<FunctionArg>,
return_ty: FunctionReturn,
}
impl Parse for FunctionDecl {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
// fn bind_shader_resource_group(&mut self, index: u32, #[rhi] srg: &ShaderResourceGroup) -> &mut Self;
let _: Token![fn] = input.parse()?;
let fn_name: Ident = input.parse()?;
let name_str = fn_name.to_string();
println!("fn_name: {:?}", name_str);
let args;
let _ = parenthesized!(args in input);
let args = args.parse_terminated(FunctionArg::parse, Token![,]).unwrap();
let args = args.iter().map(|a| a.to_owned()).collect();
let _ = input.parse::<Token![->]>().unwrap();
let return_ty: FunctionReturn = input.parse().unwrap();
Ok(Self {
fn_name,
args,
return_ty,
})
}
}
struct Input {
trait_name: Ident,
impl_generics: Generics,
target: Type,
target_generics: Generics,
functions: Vec<FunctionDecl>,
}
impl Parse for Input {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let _: Token![impl] = input.parse()?;
let trait_name: Ident = input.parse()?;
let impl_generics: Generics = input.parse()?;
let _: Token![for] = input.parse()?;
let target = input.parse()?;
let target_generics = input.parse()?;
let content;
let _ = braced!(content in input);
let functions = content.parse_terminated(FunctionDecl::parse, Token![;])?;
let functions: Vec<FunctionDecl> = functions.iter().map(|f| f.to_owned()).collect();
Ok(Input {
trait_name,
impl_generics,
target,
target_generics,
functions,
})
}
}
// #[proc_macro]
// pub fn make_answer(input: TokenStream) -> TokenStream {
// let input = parse_macro_input!(input as Input);
// todo!()
// }
#[cfg(test)]
mod test {
use crate::Input;
#[test]
fn test_rhi_proc_macro_parse() {
use quote::quote;
let input = quote! {
impl IRhiGraphicsCommandEncoder<RhiDevice> for RhiGraphicsCommandEncoder<'_> {
fn create_renderpass(&self, desc: &RenderPassDesc<'_>) -> #[rhi] Result<RenderPass>;
fn set_vertex_buffer(&mut self, index: u32, #[rhi] buffer: &RhiBuffer, offset: u64) -> &mut Self;
}
};
let input: syn::Result<Input> = syn::parse2(input);
match input {
Ok(input) => (),
Err(e) => {
let msg = e.to_string();
panic!("{}", msg);
}
}
}
}