Syn 获取平面令牌流

Syn get flat token stream

为了这个例子:我想写一个 proc 宏属性来修改函数体中的所有数字文字。

我有 syn::Block 来自 syn::FnItem。我想映射块中的所有标记并更改文字。我目前有:

let token_stream = func
    .block
    .to_token_stream()
    .into_iter()
    .map(|token| ...)

func.block = Box::new(syn::parse2::<Block>(token_stream.collect()).unwrap());

问题是 to_token_stream 来自 Quote::ToTokens returns 一个 proc_macro2::TokenStream 并且它的 into_iter 项目是 proc_macro2::TokenTree 这是一个嵌套表示代币。

所以对于代表 2 + (3 + 4)

的块

迭代器遍历以下单个项目:

Group {
    delimiter: Brace,
    stream: TokenStream [
        Literal {
            kind: Integer,
            symbol: "2",
            suffix: None,
            span: #0 bytes(209..210),
        },
        Punct {
            ch: '+',
            spacing: Alone,
            span: #0 bytes(211..212),
        },
        Group {
            delimiter: Parenthesis,
            stream: TokenStream [
                Literal {
                    kind: Integer,
                    symbol: "3",
                    suffix: None,
                    span: #0 bytes(214..215),
                },
                Punct {
                    ch: '+',
                    spacing: Alone,
                    span: #0 bytes(216..217),
                },
                Literal {
                    kind: Integer,
                    symbol: "4",
                    suffix: None,
                    span: #0 bytes(218..219),
                },
            ],
            span: #0 bytes(213..220),
        },
    ],
    span: #0 bytes(203..222),
}

令牌在结构中深度嵌套的位置。

我需要一个如下所示的平面表示:

Literal("2")
Plus
ParenthesisOpen
Literal("3")
Plus
Literal("4")
ParenthesisClose

这可能吗?我可以在 map 之前编写自己的 flat_map thinh 以使其工作,但这需要大量工作。 syn 会公开任何东西吗?也许我不应该在进行转换之前将其解析为 syn::Block...?

原来syn有一个mutable visiting module。您可以像这样使用递归访问者,而不是接触令牌流:

use syn::{visit_mut::{self, VisitMut}, LitInt};

struct MyNumberLiteralModifier;

impl VisitMut for MyNumberLiteralModifier {
    fn visit_lit_int_mut(&mut self, node: &mut LitInt) {
        *node = LitInt::new("10", node.span());   
    }
}

MyNumberLiteralModifier.walk_block(&mut my_block);

为此必须为 syn

启用 "visit-mut" 功能