我如何自己使用Rust解析器(libsyntax)?

le_*_*_me 7 parsing abstract-syntax-tree rust

我想使用Rust解析器(libsyntax)来解析Rust文件并从中提取函数名称等信息.我开始深入研究文档和代码,所以我的第一个目标是在.rs文件中打印独立函数的所有函数名称.

程序应该在打印函数名之前扩展所有宏,因此不会遗漏通过宏声明的函数.这就是为什么我不能自己写一些蹩脚的小解析器来完成这项工作.

我不得不承认我还不是很擅长编程Rust,所以我提前为这个问题中的任何愚蠢的陈述道歉.

我是如何理解的,我需要执行以下步骤:

  1. 通过struct解析文件Parser
  2. 用.展开宏 MacroExpander
  3. ???
  4. 用a Visitor来走AST并提取我需要的信息(例如via visit_fn)

所以这是我的问题:

  1. 我该怎么用MacroExpander
  2. 如何使用自定义访问者浏览扩展的AST?

我有想法使用自定义lint检查而不是完全成熟的解析器.我在调查这个选项.

如果重要,我正在使用 rustc 0.13.0-nightly (f168c12c5 2014-10-25 20:57:10 +0000)

Lam*_*iry 5

我担心我不能直接回答你的问题; 但我可以提出一个可能有帮助的替代方案.

如果您只需要AST,则可以使用JSON格式检索它rustc -Z ast-json.然后使用您喜欢的语言(Python很棒)来处理输出.

您还可以使用漂亮的打印源rustc --pretty=(expanded|normal|typed).

例如,鉴于此hello.rs:

fn main() {
    println!("hello world");
}
Run Code Online (Sandbox Code Playgroud)

我们得到:

$ rustc -Z ast-json hello.rs
{"module":{"inner":null,"view_items":[{"node":{"va... (etc.)
Run Code Online (Sandbox Code Playgroud)
$ 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"); }
Run Code Online (Sandbox Code Playgroud)
$ 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 () {
                                                                   () => [],
                                                               }));
}
Run Code Online (Sandbox Code Playgroud)

如果您需要更多,那么lint插件将是最佳选择.正确处理宏扩展,配置标志,模块系统以及其他任何出现的问题都非常重要.使用lint插件,您可以立即获得经过类型检查的AST,而不会大惊小怪.Cargo也支持编译器插件,因此您的工具可以很好地适应其他人的项目.


Wil*_*hes 5

您可以使用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);
}
Run Code Online (Sandbox Code Playgroud)

这打印整个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: [] })
Run Code Online (Sandbox Code Playgroud)

  • 我认为 Syntex 不会继续下去。[问题](https://github.com/serde-rs/syntex/issues/114) (2认同)