proc-macro-workshop:seq-2
题解
// The macro invocation in the previous test case contained an empty loop body
// inside the braces. In reality we want for the macro to accept arbitrary
// tokens inside the braces.
//
// The caller should be free to write whatever they want inside the braces. The
// seq macro won't care whether they write a statement, or a function, or a
// struct, or whatever else. So we will work with the loop body as a TokenStream
// rather than as a syntax tree.
//
// Before moving on, ensure that your implementation knows what has been written
// inside the curly braces as a value of type TokenStream.
//
//
// Resources:
//
// - Explanation of the purpose of proc-macro2:
// https://docs.rs/proc-macro2/1.0/proc_macro2/
use seq::seq;
macro_rules! expand_to_nothing {
($arg:literal) => {
// nothing
};
}
seq!(N in 0..4 {
expand_to_nothing!(N);
});
fn main() {}
这一关我们主要解析的是整个数据的结构。
因为对于N in 0..4
并不是标准的语法,我们要解析并且操作,返回符合的标准语法。
解析
impl syn::parse::Parse for crate::parser::SeqParser {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let variable_ident = input.parse::<syn::Ident>()?;
let _ = input.parse::<syn::Token!(in)>()?;
let begin = input.parse::<syn::LitInt>()?.base10_parse()?;
let _ = input.parse::<syn::Token!(..)>()?;
let end = input.parse::<syn::LitInt>()?.base10_parse()?;
let body_buf;
let _ = syn::braced!(body_buf in input);
let body = body_buf.parse::<proc_macro2::TokenStream>()?;
syn::Result::Ok(crate::parser::SeqParser {
variable_ident,
begin,
end,
body,
})
}
}
比较值的一提的有三点
- 通过
parse
方法,我们可以自动解析自己想要的数据类型 - 使用
syn::Token(?)
我们可以匹配指定的token
syn::braced!
可以抽取{}
中的数据,然后慢慢解析
按照前面所述的每个token
,我们逐渐的解析了每一个数据。
当然,因为想要支持syn::parse_macro_input!
,结构体解析的时候必须要实现syn:: parse::Parse
。所以主干的题解可以改成这样了。
主干
#[proc_macro]
pub fn seq(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let _ = syn::parse_macro_input!(input as crate::parser::SeqParser);
proc_macro2::TokenStream::new().into
}
目前而言,已经支持parse_macro_input!
了。
本作品采用《CC 协议》,转载必须注明作者和本文链接