I guess this must have been implemented inside the Rust compiler - otherwise it is surely impossible to compile Rust code. Therefore, to avoid duplicating the code (the DRY principle), I hope to somehow reuse existing code, instead of looking at spec and write down a parsing logic by myself. I would appreciate it if I could know whether this is possible or suggested? Thanks!
This is not a question of parsing, but one of name resolution. Parsing means turning a flat representation (in the case of programming languages, a string that is the source code) into a structured one (a so-called abstract syntax tree or AST). Parsing is context-independent and doesn't add information – the AST doesn't contain any more information than the source code did, it's "only" vastly easier and more practical to work with.
What you are looking for is more than mere parsing; it already involves an early stage of type checking, i.e., mapping the context-sensitive source code into entities that don't require further name lookup, so basically this adds information about the relationship between modules and crates.
That crate looks complicated, and seems not to be used by end users (e.g. not on crates.io: Rust Package Registry). Therefore, do you suggest me to manually write down code to resolve it, or to call that code?
I have no strong opinion about that, as I haven't tried doing either.
My guess would be that re-implementing Rust's complete name resolution algorithm from scratch, and doing so correctly, would be more of a challenge than figuring out how to use a crate.
As an alternative you could consider trying to hook into rust-analyzer (this part should be handled by the hir-def crate). In any case you'll need something that handles macro expansion and name resolution, be it an existing crate or your own. I don't think it will be easy to write by yourself, but integrating with an existing create may also be pretty challenging.
Ah I see: seems -Zunpretty has some interesting variants! I quickly checked some of them, e.g. expanded,hygiene looks interesting (but does not fully solve the question...).
It wasn't nothing technical, I just meant to use rust-analyzer's crate.
That won't always work correctly as it's lossy around hygiene. Consider for example this code:
macro_rules! foo {
($i:ident) => {
let a = 10;
println!("{}", $i);
}
}
fn main() {
let a = 5;
foo!(a); // prints 5
}
If you expand it you'll get the equivalent of this:
fn main() {
let a = 5;
let a = 10;
println!("{}", a); // now prints 10
}
The problem is that the two as are different identifiers for the compiler due to having different syntax context, even though their name is the same. Once expanded the syntax context is lost and they compare equal.
-Zunpretty=expanded,hygiene handles the hygiene problem and may give you enough informations to recover the name resolution informations, however note that there's nothing guaranteeing it will continue to have this output format.
To be more specific, I only care about types on signatures - function input argument types, function output types, struct field types, enum field types, etc, but do not care about function body code.
I checked -Zunpretty=expanded,hygiene, but in some cases, it does not seem to produce enough information in some cases either. For example,
use std::result::*;
fn main() -> Result<(), ()> {
panic!()
}