我希望使用Rust解析器(lib语法)来解析一个Rust文件,并从其中提取类似于函数名称的信息。我开始挖掘文档和代码,所以我的第一个目标是在.rs文件中打印独立函数的所有函数名。
程序应该在打印函数名之前展开所有宏,这样就不会遗漏通过宏声明的函数。这就是为什么我不能自己写一些蹩脚的小解析器来完成这项工作。
我不得不承认,我还不太擅长编程Rust,所以我事先为这个问题中的任何愚蠢的陈述道歉。
我是如何理解它的,我需要执行以下步骤:
MacroExpander扩展宏Visitor来遍历AST并提取我需要的信息(例如。通过visit_fn)以下是我的问题:
MacroExpander我的想法是使用自定义皮棉检查而不是成熟的解析器。我在调查这个选项。
如果有关系,我用的是rustc 0.13.0-nightly (f168c12c5 2014-10-25 20:57:10 +0000)
发布于 2015-01-13 09:59:15
恐怕我不能直接回答你的问题,但我可以提出一个可能有帮助的替代办法。
如果您只需要AST,就可以使用rustc -Z ast-json以JSON格式检索它。然后使用您最喜欢的语言(Python很棒)来处理输出。
您还可以使用rustc --pretty=(expanded|normal|typed)获得打印良好的源代码。
例如,给定这个hello.rs
fn main() {
println!("hello world");
}我们得到:
$ rustc -Z ast-json hello.rs
{"module":{"inner":null,"view_items":[{"node":{"va... (etc.)$ rustc --pretty=normal hello.rs
#![no_std]
#[macro_use]
extern crate "std" as std;
#[prelude_import]
use std::prelude::v1::*;
fn main() { println!("hello world"); }$ rustc --pretty=expanded hello.rs
#![no_std]
#[macro_use]
extern crate "std" as std;
#[prelude_import]
use std::prelude::v1::*;
fn main() {
::std::io::stdio::println_args(::std::fmt::Arguments::new({
#[inline]
#[allow(dead_code)]
static __STATIC_FMTSTR:
&'static [&'static str]
=
&["hello world"];
__STATIC_FMTSTR
},
&match () {
() => [],
}));
}不过,如果你需要的不仅仅是这个,那么最好的选择就是一个衣领插件。适当地处理宏扩展、配置标志、模块系统和其他任何事情都是非常重要的。有了一个皮棉插件,你就可以立即得到类型检查的AST,而无需大惊小怪。Cargo也支持编译器插件,因此您的工具可以很好地适应其他人的项目。
发布于 2016-08-14 17:09:16
您可以使用syntex解析Rust,因此不需要使用不稳定的Rust。
下面是一个简单的例子:
// Tested against syntex_syntax v0.33
extern crate syntex_syntax as syntax;
use std::rc::Rc;
use syntax::codemap::{CodeMap};
use syntax::errors::{Handler};
use syntax::errors::emitter::{ColorConfig};
use syntax::parse::{self, ParseSess};
fn main() {
let codemap = Rc::new(CodeMap::new());
let tty_handler =
Handler::with_tty_emitter(ColorConfig::Auto, None, true, false, codemap.clone());
let parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());
let src = "fn foo(x: i64) { let y = x + 1; return y; }".to_owned();
let result = parse::parse_crate_from_source_str(String::new(), src, Vec::new(), &parse_session);
println!("parse result: {:?}", result);
}这个打印出整个AST:
parse result: Ok(Crate { module: Mod { inner: Span { lo: BytePos(0), hi: BytePos(43), expn_id: ExpnId(4294967295) },
items: [Item { ident: foo#0, attrs: [], id: 4294967295, node: Fn(FnDecl { inputs: [Arg { ty: type(i64), pat:
pat(4294967295: x), id: 4294967295 }], output: Default(Span { lo: BytePos(15), hi: BytePos(15), expn_id: ExpnId(4294967295) }),
variadic: false }, Normal, NotConst, Rust, Generics { lifetimes: [], ty_params: [], where_clause: WhereClause { id:
4294967295, predicates: [] } }, Block { stmts: [stmt(4294967295: let y = x + 1;), stmt(4294967295: return y;)], expr:
None, id: 4294967295, rules: Default, span: Span { lo: BytePos(15), hi: BytePos(43), expn_id: ExpnId(4294967295) } }),
vis: Inherited, span: Span { lo: BytePos(0), hi: BytePos(43), expn_id: ExpnId(4294967295) } }] }, attrs: [], config: [],
span: Span { lo: BytePos(0), hi: BytePos(42), expn_id: ExpnId(4294967295) }, exported_macros: [] })发布于 2021-10-01 09:42:12
syn机箱确实能工作。起初,我错误地认为它是用于编写过程宏(正如它的自述式宏建议的那样),但实际上它可以解析源代码文件。请看这个页面:https://docs.rs/syn/1.0.77/syn/struct.File.html。它甚至给出了一个输入.rs文件并输出AST的示例(当然,您可以使用它做任何事情--不仅仅是打印):
use std::env;
use std::fs::File;
use std::io::Read;
use std::process;
fn main() {
let mut args = env::args();
let _ = args.next(); // executable name
let filename = match (args.next(), args.next()) {
(Some(filename), None) => filename,
_ => {
eprintln!("Usage: dump-syntax path/to/filename.rs");
process::exit(1);
}
};
let mut file = File::open(&filename).expect("Unable to open file");
let mut src = String::new();
file.read_to_string(&mut src).expect("Unable to read file");
let syntax = syn::parse_file(&src).expect("Unable to parse file");
// Debug impl is available if Syn is built with "extra-traits" feature.
println!("{:#?}", syntax);
}谢谢@poolie指出了这个提示(尽管缺少一些细节)。
https://stackoverflow.com/questions/26575443
复制相似问题