You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用syn遍历Rust文件中所有嵌套宏调用?

Traverse Nested Macro Calls in Rust Using Syn

The core issue with your current implementation is that syn::visit::visit_macro doesn’t traverse the token stream inside a macro call—you need to explicitly parse those tokens into an AST and visit that structure to uncover nested macros.

Step 1: Modify the Visitor to Parse Macro Tokens

Extend your custom Visitor to parse the token stream of each macro call and recursively visit the resulting AST. This will catch any nested macro calls within the arguments.

use syn::{visit::Visit, Macro, File, parse2};
use std::error::Error;

struct MacroCallVisitor;

impl Visit for MacroCallVisitor {
    fn visit_macro(&mut self, node: &Macro) {
        // Print the name of the current macro call
        let macro_name = node.path.segments.last().unwrap().ident.to_string();
        println!("Macro call: {}", macro_name);

        // Parse the macro's token stream into a File (handles statements/expressions)
        match parse2::<File>(node.tokens.clone()) {
            Ok(file) => self.visit_file(&file),
            Err(e) => eprintln!("Warning: Could not parse tokens for macro '{}': {}", macro_name, e),
        }
    }
}

Step 2: Run the Visitor on Your Rust File

Parse your target Rust file into a syn::File and execute the visitor to traverse all macro calls (including nested ones):

fn main() -> Result<(), Box<dyn Error>> {
    // Replace with your file content or read from disk
    let source_code = r#"
        fn main() {
            println!("Count: {}", format!("{}", add_one!(5)));
            let values = vec![1, mul_two!(2), 3];
            outer_macro!(inner_macro!(nested_macro!()));
        }

        // Macro definitions (not calls, so they won't be printed)
        macro_rules! add_one { ($x:expr) => { $x + 1 } }
        macro_rules! mul_two { ($x:expr) => { $x * 2 } }
        macro_rules! inner_macro { ($x:expr) => { $x } }
        macro_rules! nested_macro { () => { 42 } }
    "#;

    let ast = syn::parse_file(source_code)?;
    let mut visitor = MacroCallVisitor;
    visitor.visit_file(&ast);

    Ok(())
}

Key Details

  • Parsing Flexibility: Using syn::File to parse macro tokens works for most cases because it handles both standalone expressions and sequences of statements, covering common macro argument patterns.
  • Error Handling: If a macro’s tokens can’t be parsed as valid Rust (common for macros with non-standard syntax), the code logs a warning but continues processing other macros.
  • Definitions vs Calls: This implementation only prints macro calls (e.g., add_one!(5)), not macro definitions (e.g., macro_rules! add_one { ... }), which aligns with your requirement to output macro calls.

Dependencies

Add syn with the full feature to your Cargo.toml to enable full syntax parsing:

[dependencies]
syn = { version = "2.0", features = ["full"] }

内容的提问来源于stack exchange,提问作者Steve Lau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 19:25:11