在编写过程宏时,经常需要对TokenStream
进行解析和处理。 而Syn库就是专门用于对TokenStream
进行解析。
Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree of Rust source code.
Syn 用于将Rust tokens 解析为Rust 源码语法树。
在过程宏使用Syn解析的流程:
syn::parse::Parse
parse_macro_input!()
生成源码树。// 定义自己的存储结构
struct ItemStruct {
pub struct_token: Token![struct],
pub ident: Ident,
pub brace_token: token::Brace,
}
// 实现syn::parse::Parse 接口
impl Parse for ItemStruct {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let content;
let lookahead = input.lookahead1();
// 只针对struct类型
if lookahead.peek(Token![struct]) {
return Ok(ItemStruct {
struct_token: input.parse()?,
ident: input.parse()?,
brace_token: braced!(content in input),
});
}
Err(lookahead.error())
}
}
// 在派生宏中使用 parse_macro_input
#[proc_macro_derive(SynTest)]
pub fn syn_test(input: TokenStream)->TokenStream{
let input = parse_macro_input!(input as ItemStruct);
println!("MyParse:{:?}", input.struct_token.to_token_stream());
println!("MyIdent:{:?}", input.ident.to_token_stream());
TokenStream::new()
}
// main.rs
// #[derive(SynTest)]
// struct World{}
// 程序输出:
// MyParse:TokenStream [Ident { ident: "struct", span: #0 bytes(290..296) }]
// MyIdent:TokenStream [Ident { ident: "World", span: #0 bytes(297..302) }]
----
当然,Syn已经内置一个DeriveInput
类型, 用于struct、enum、unions类型的解析,改写下上面的例子。
/* Struct syn::DeriveInput
pub struct DeriveInput {
pub attrs: Vec<Attribute>,
pub vis: Visibility,
pub ident: Ident,
pub generics: Generics,
pub data: Data,
}
*/
#[proc_macro_derive(SynTest)]
pub fn syn_test(input: TokenStream)->TokenStream{
// 将ItemStruct => DeriveInput
let input = parse_macro_input!(input as DeriveInput);
println!("MyIdent:{:?}", input.ident.to_token_stream());
TokenStream::new()
}
通过Syn生成语法树后,后面可用使用quote!
处理源码树,实现需要的扩展功能。
使用过程宏为struct添加hello方法:
parse_macro_input
解析到DeriveInput#[proc_macro_derive(Hello)]
pub fn hello_derive(input: TokenStream)->TokenStream {
let input = parse_macro_input!(input as DeriveInput);
println!("{:?}", input.ident.to_token_stream());
let name = input.ident.to_token_stream();
// #name 为上面获取的struct name
let expanded = quote! {
impl #name {
pub fn hello(){
println!("Hello World!");
}
}
};
expanded.into()
}
// main.rs
#[derive(Hello)]
struct Test{}
fn main() {
Test::hello();
}
// 输出:
// Hello World!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。