2014-10-26 5 views
6

Chcę użyć parsera rdzy (libsyntax) do przeanalizowania pliku Rust i wyodrębnienia z niego informacji, takich jak nazwy funkcji. Zacząłem drążyć dokument i kod, więc moim pierwszym celem jest program, który drukuje wszystkie nazwy funkcji wolnostojących funkcji w pliku .rs.Jak sam używać parsera rdzy (libsyntax)?

Program powinien rozwinąć wszystkie makra zanim wypisze nazwy funkcji, więc funkcje zadeklarowane za pomocą makra nie zostaną pominięte. Dlatego nie mogę sam napisać jakiegoś małego parsera, żeby wykonać to zadanie.

Muszę przyznać, że nie jestem jeszcze perfekcyjnie dobry w programowaniu Rust, więc z góry przepraszam za wszelkie głupie stwierdzenia w tym pytaniu.

Jak mam rozumieć to trzeba wykonać następujące czynności:

  1. Przetwarza plik poprzez Parser struct
  2. Rozwiń makra z MacroExpander
  3. ???
  4. Użyj Visitor chodzić AST i wyodrębnić informacje potrzebne

Więc tutaj są moje pytania (np. Poprzez visit_fn)

  1. Jak używać MacroExpander?
  2. Jak przejść rozszerzoną tabelę AST z niestandardowym użytkownikiem?

Wpadłem na pomysł użycia custom lint check zamiast w pełni rozwiniętego parsera. Sprawdzam tę opcję.

Jeżeli sprawy, używam rustc 0.13.0-nightly (f168c12c5 2014-10-25 20:57:10 +0000)

+1

Ekstrakcja ciekawych faktów zwykle wymaga dużo więcej niż „tylko parser” Zobacz mój artykuł na temat „Życie po parsowania "(google lub za pośrednictwem strony bio). –

Odpowiedz

5

Obawiam się, że nie może odpowiedzieć na to pytanie bezpośrednio; ale mogę przedstawić alternatywę, która może pomóc.

Jeśli wszystko czego potrzebujesz to AST, możesz pobrać go w formacie JSON, używając rustc -Z ast-json. Następnie użyj swojego ulubionego języka (Python jest świetny), aby przetworzyć wynik.

Możesz również uzyskać ładnie wydrukowane źródło, używając rustc --pretty=(expanded|normal|typed).

Na przykład, biorąc pod uwagę to hello.rs:

fn main() { 
    println!("hello world"); 
} 

Dostajemy:

$ 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() { 
                    () => [], 
                   })); 
} 

Jeśli potrzebujesz więcej niż to jednak plugin szarpie będzie być najlepszą opcją. Właściwa obsługa rozszerzenia makro, config flags, systemu modułów i wszystkiego, co się pojawia, jest dość nietrywialna. Z wtyczką Lint otrzymujesz AST sprawdzoną od razu bez problemu. Cargo obsługuje również wtyczki kompilatora, więc Twoje narzędzie będzie dobrze pasowało do projektów innych osób.

+0

dziękuję! Ja też mam ochotę nie używać niestabilnych wewnętrznych kompilatorów, to jest sposób, aby przejść tutaj! –

5

Możesz użyć syntex do analizy Rust, więc nie musisz używać niestabilnej rdzy.

Oto prosty przykład:

// 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); 
} 

Drukuje cały 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: [] }) 
+0

Myślę, że syntex nie będzie kontynuowany. [wydanie] (https://github.com/serde-rs/syntex/issues/114) –