我尝试使用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());
}
它创建AST的文件如下:
# [macro_use]
extern crate foo;
mod test;
fn init(handle: foo::InitHandle) {
handle.add_class::<Test::test>();
}
它的输出是这样的:
# [macro_use] extern crate foo ; mod test ; fn init (handle : foo :: InitHandle) { handle . add_class :: < Test :: test > () ; }
我甚至尝试过在将它写入文件后通过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),
}
但这似乎没有任何区别。
4条答案
按热度按时间cgfeq70w1#
quote
crate并不真正关心生成的代码的打印效果,你可以通过rustfmt运行它,你只需要执行rustfmt src/utils.rs
或cargo fmt -- src/utils.rs
。现在您可以执行:
另请参见Rust论坛上的"Any interest in a pretty-printing crate for Syn?"。
0s7z1bwu2#
正如Martin在他的回答中提到的,prettyplease可以用来格式化代码片段,这在测试proc宏时非常有用,因为
proc_macro2::TokenStream
上的标准to_string()
很难读取。下面是一个将
proc_macro2::TokenStream
解析为syn::Item
的代码示例:我在我的测试中使用了它来帮助我理解哪里是错误的生成代码:
xzv2uavs3#
请参阅新的prettyplease机箱。优点:
1.它可以直接用作库。
1.它可以处理代码片段,而
rustfmt
只能处理完整的文件。1.它之所以快是因为它使用了更简单的算法。
vtwuwzda4#
与其他答案类似,我也使用
prettyplease
。我使用这个小技巧来漂亮地打印一个
proc_macro2::TokenStream
(例如,通过调用quote::quote!
得到的结果):基本上,我将令牌流转换为未格式化的
String
,然后将String
解析为syn::File
,然后将其传递给prettyplease
包。用法: