[英]rust procedural macros, how to find an identifier?
我正把头撞在墙上,试图弄清楚这一点。
我想要的是:
一个程序宏,它用同一个单词的复数形式替换标识符的所有标记实例。
我已经设置了宏本身:
extern crate proc_macro;
use syn::{parse_macro_input, DataEnum, DataUnion, DeriveInput, FieldsNamed, FieldsUnnamed};
use regex::Regex;
extern crate quote;
use proc_macro::TokenStream;
#[proc_macro]
pub fn pluralize(input: TokenStream) -> TokenStream
{
//let DeriveInput { ident, data, .. } = parse_macro_input!(input);
return input;
}
我已经完成了测试,并且可以正确调用它。 我还有一个 function 使用正则表达式来查找需要替换的标记部分。
let input_str = input.to_string();
let re_token = Regex::new(r"\[<.*s\s*>\]").unwrap();
let re_name = Regex::new(r"\w+").unwrap();
for m in re_token.find_iter(&input_str)
{
let name = re_name.find(m.as_str()).unwrap();
println!("{}", m.as_str());
}
完成这项工作所需要做的就是从 TokenStream 中获取标识符,而我终其一生都无法弄清楚如何去做。
您可以使用syn
的visit_mut
。 实现VisitMut
特征并覆盖visit_ident_mut()
。
但是,这有两个严重的缺点:
[<... >]
。 而且,它把沉重的syn
作为依赖,甚至需要full
的功能(和visit-mut
)。
更好的方法是直接使用TokenStream
。 查找以[]
分隔的Group
,如果它们包含<
和>
作为第一个和最后一个标记,则将所有标识符复数。 递归组。 这可能是这样的:
fn process_token_stream(tokens: TokenStream, pluralize: bool) -> TokenStream {
tokens
.into_iter()
.map(|token_tree| match token_tree {
TokenTree::Ident(ident) if pluralize => {
TokenTree::Ident(Ident::new(&(ident.to_string() + "s"), ident.span()))
}
TokenTree::Group(group) => {
let mut pluralize = pluralize;
let mut stream = VecDeque::from_iter(group.stream());
let mut delimiter = group.delimiter();
if group.delimiter() == Delimiter::Bracket {
if let (Some(TokenTree::Punct(first)), Some(TokenTree::Punct(last))) =
(stream.front(), stream.back())
{
if first.as_char() == '<' && last.as_char() == '>' {
pluralize = true;
stream.pop_front();
stream.pop_back();
delimiter = Delimiter::None;
}
}
}
let mut new_group = Group::new(
delimiter,
process_token_stream(TokenStream::from_iter(stream), pluralize),
);
new_group.set_span(group.span());
TokenTree::Group(new_group)
}
other => other,
})
.collect()
}
游乐场。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.