繁体   English   中英

rust 过程宏,如何找到标识符?

[英]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 中获取标识符,而我终其一生都无法弄清楚如何去做。

您可以使用synvisit_mut 实现VisitMut特征并覆盖visit_ident_mut()

但是,这有两个严重的缺点:

  1. 它不会遍历宏。
  2. 很难以这种方式识别无效的 Rust 构造的构造,例如[<... >]

而且,它把沉重的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM