如何漂亮地打印 Syn AST?

Mr.*_*yyy 8 abstract-syntax-tree rust rustfmt

我正在尝试使用syn从 Rust 文件创建 AST,然后使用quote将其写入另一个文件。然而,当我写它时,它在所有内容之间放置了额外的空格。

请注意,下面的示例只是为了演示我遇到的最小可重现问题。我意识到,如果我只是想复制代码,我可以复制文件,但它不适合我的情况,我需要使用 AST。

pub fn build_file() {
    let current_dir = std::env::current_dir().expect("Unable to get current directory");
    let rust_file = std::fs::read_to_string(current_dir.join("src").join("lib.rs")).expect("Unable to read rust file");
    let ast = syn::parse_file(&rust_file).expect("Unable to create AST from rust file");

    match std::fs::write("src/utils.rs", quote::quote!(#ast).to_string());
}
Run Code Online (Sandbox Code Playgroud)

它创建 AST 的文件是这样的:

#[macro_use]
extern crate foo;
mod test;
fn init(handle: foo::InitHandle) {
    handle.add_class::<Test::test>();
}
Run Code Online (Sandbox Code Playgroud)

它输出的内容是这样的:

# [macro_use] extern crate foo ; mod test ; fn init (handle : foo :: InitHandle) { handle . add_class :: < Test :: test > () ; }
Run Code Online (Sandbox Code Playgroud)

rustfmt我什至尝试在将其写入文件后运行它,如下所示:

utils::write_file("src/utils.rs", quote::quote!(#ast).to_string());

match std::process::Command::new("cargo").arg("fmt").output() {
    Ok(_v) => (),
    Err(e) => std::process::exit(1),
}
Run Code Online (Sandbox Code Playgroud)

但这似乎没有什么区别。

Val*_*tin 5

quote板条箱并不真正关心如何漂亮地打印生成的代码。您可以通过rustfmt运行它,只需执行rustfmt src/utils.rsor cargo fmt -- src/utils.rs

use std::fs;
use std::io;
use std::path::Path;
use std::process::Command;

fn write_and_fmt<P: AsRef<Path>, S: ToString>(path: P, code: S) -> io::Result<()> {
    fs::write(&path, code.to_string())?;

    Command::new("rustfmt")
        .arg(path.as_ref())
        .spawn()?
        .wait()?;

    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

现在你可以执行:

write_and_fmt("src/utils.rs", quote::quote!(#ast)).expect("unable to save or format");
Run Code Online (Sandbox Code Playgroud)

另请参阅“对 Syn 的漂亮印刷板条箱感兴趣吗?” 在 Rust 论坛上。