mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
Minor tweaks
This commit is contained in:
parent
80c3e57f96
commit
2c74af7ddc
1 changed files with 128 additions and 119 deletions
63
rfc.md
63
rfc.md
|
@ -38,8 +38,8 @@ be `0.1.0`.
|
|||
|
||||
## Reusability
|
||||
|
||||
In theory, parsing can be a pure function, which takes a `&str` as an
|
||||
input, and produces a `ParseTree` as an output.
|
||||
In theory, the parser can be a pure function, which takes a `&str` as
|
||||
an input, and produces a `ParseTree` as an output.
|
||||
|
||||
This is great for reusability: for example, you can compile this
|
||||
function to WASM and use it for fast client-side validation of syntax
|
||||
|
@ -64,7 +64,7 @@ Unfortunately, the current libsyntax is far from this ideal. For
|
|||
example, even the lexer makes use of the `FileMap` which is
|
||||
essentially a global state of the compiler which represents all know
|
||||
files. As a data point, it turned out to be easier to move `rustfmt`
|
||||
inside of main `rustc` repository than to move libsyntax outside!
|
||||
into the main `rustc` repository than to move libsyntax outside!
|
||||
|
||||
|
||||
## IDE support
|
||||
|
@ -86,9 +86,8 @@ necessary to correctly handle certain code-editing actions like
|
|||
autoindentation or joining lines. IDE also must be able to produce
|
||||
partial parse trees when some input is missing or invalid.
|
||||
|
||||
Currently rustc uses the AST approach, which preserves the source code
|
||||
information to some extent by storing spans in the AST.
|
||||
|
||||
Currently rustc uses the AST approach, and preserves some of the
|
||||
source code information in the form of spans in the AST.
|
||||
|
||||
|
||||
# Guide-level explanation
|
||||
|
@ -114,8 +113,8 @@ compiler.
|
|||
## Untyped Tree
|
||||
|
||||
The main idea is to store the minimal amount of information in the
|
||||
tree itself, and instead lean heavily on the source code string for
|
||||
the actual data about identifier names, constant values etc.
|
||||
tree itself, and instead lean heavily on the source code for the
|
||||
actual data about identifier names, constant values etc.
|
||||
|
||||
All nodes in the tree are of the same type and store a constant for
|
||||
the syntactic category of the element and a range in the source code.
|
||||
|
@ -273,10 +272,12 @@ Note several features of the tree:
|
|||
It's hard to work with this raw parse tree, because it is untyped:
|
||||
node containing a struct definition has the same API as the node for
|
||||
the struct field. But it's possible to add a strongly typed layer on
|
||||
top of this raw tree, and get a zero-cost typed AST. Here is an
|
||||
example which adds type-safe wrappers for structs and fields:
|
||||
top of this raw tree, and get a zero-cost AST. Here is an example
|
||||
which adds type-safe wrappers for structs and fields:
|
||||
|
||||
```rust
|
||||
// generic infrastructure
|
||||
|
||||
pub trait AstNode<'f>: Copy + 'f {
|
||||
fn new(node: Node<'f>) -> Option<Self>;
|
||||
fn node(&self) -> Node<'f>;
|
||||
|
@ -290,6 +291,8 @@ pub fn ast_children<'f, A: AstNode<'f>>(node: Node<'f>) -> Box<Iterator<Item=A>
|
|||
Box::new(node.children().filter_map(A::new))
|
||||
}
|
||||
|
||||
// AST elements, specific to Rust
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct StructDef<'f>(Node<'f>);
|
||||
|
||||
|
@ -315,22 +318,7 @@ impl<'f> AstNode<'f> for StructDef<'f> {
|
|||
fn node(&self) -> Node<'f> { self.0 }
|
||||
}
|
||||
|
||||
impl<'f> AstNode<'f> for FieldDef<'f> {
|
||||
fn new(node: Node<'f>) -> Option<Self> {
|
||||
if node.kind() == FIELD_DEF { Some(FieldDef(node)) } else { None }
|
||||
}
|
||||
fn node(&self) -> Node<'f> { self.0 }
|
||||
}
|
||||
|
||||
impl<'f> AstNode<'f> for TypeRef<'f> {
|
||||
fn new(node: Node<'f>) -> Option<Self> {
|
||||
if node.kind() == TYPE_REF { Some(TypeRef(node)) } else { None }
|
||||
}
|
||||
fn node(&self) -> Node<'f> { self.0 }
|
||||
}
|
||||
|
||||
impl<'f> NameOwner<'f> for StructDef<'f> {}
|
||||
impl<'f> NameOwner<'f> for FieldDef<'f> {}
|
||||
|
||||
impl<'f> StructDef<'f> {
|
||||
pub fn fields(&self) -> Box<Iterator<Item=FieldDef<'f>> + 'f> {
|
||||
|
@ -338,11 +326,29 @@ impl<'f> StructDef<'f> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'f> AstNode<'f> for FieldDef<'f> {
|
||||
fn new(node: Node<'f>) -> Option<Self> {
|
||||
if node.kind() == FIELD_DEF { Some(FieldDef(node)) } else { None }
|
||||
}
|
||||
fn node(&self) -> Node<'f> { self.0 }
|
||||
}
|
||||
|
||||
impl<'f> FieldDef<'f> {
|
||||
pub fn type_ref(&self) -> Option<TypeRef<'f>> {
|
||||
ast_children(self.node()).next()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f> NameOwner<'f> for FieldDef<'f> {}
|
||||
|
||||
|
||||
impl<'f> AstNode<'f> for TypeRef<'f> {
|
||||
fn new(node: Node<'f>) -> Option<Self> {
|
||||
if node.kind() == TYPE_REF { Some(TypeRef(node)) } else { None }
|
||||
}
|
||||
fn node(&self) -> Node<'f> { self.0 }
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
@ -371,9 +377,11 @@ plan is suggested:
|
|||
* RFC discussion about the theoretical feasibility of the proposal.
|
||||
|
||||
* Implementation of the proposal as a completely separate crates.io
|
||||
crate.
|
||||
crate, by refactoring existing libsyntax source code to produce a
|
||||
new tree.
|
||||
|
||||
* A prototype implementation of the macro expansion on top of the new sytnax tree.
|
||||
* A prototype implementation of the macro expansion on top of the new
|
||||
sytnax tree.
|
||||
|
||||
* Additional round of discussion/RFC about merging with the mainline
|
||||
compiler.
|
||||
|
@ -392,6 +400,7 @@ plan is suggested:
|
|||
- Incrementally add more information about source code to the current AST.
|
||||
- Move the current libsyntax to crates.io as is.
|
||||
- Explore alternative representations for the parse tree.
|
||||
- Use parser generator instead of hand written parser.
|
||||
|
||||
# Unresolved questions
|
||||
[unresolved]: #unresolved-questions
|
||||
|
|
Loading…
Reference in a new issue