Minor tweaks

This commit is contained in:
Aleksey Kladov 2017-12-22 19:21:45 +03:00
parent 80c3e57f96
commit 2c74af7ddc

63
rfc.md
View file

@ -38,8 +38,8 @@ be `0.1.0`.
## Reusability ## Reusability
In theory, parsing can be a pure function, which takes a `&str` as an In theory, the parser can be a pure function, which takes a `&str` as
input, and produces a `ParseTree` as an output. an input, and produces a `ParseTree` as an output.
This is great for reusability: for example, you can compile this This is great for reusability: for example, you can compile this
function to WASM and use it for fast client-side validation of syntax 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 example, even the lexer makes use of the `FileMap` which is
essentially a global state of the compiler which represents all know 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` 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 ## 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 autoindentation or joining lines. IDE also must be able to produce
partial parse trees when some input is missing or invalid. partial parse trees when some input is missing or invalid.
Currently rustc uses the AST approach, which preserves the source code Currently rustc uses the AST approach, and preserves some of the
information to some extent by storing spans in the AST. source code information in the form of spans in the AST.
# Guide-level explanation # Guide-level explanation
@ -114,8 +113,8 @@ compiler.
## Untyped Tree ## Untyped Tree
The main idea is to store the minimal amount of information in the 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 tree itself, and instead lean heavily on the source code for the
the actual data about identifier names, constant values etc. actual data about identifier names, constant values etc.
All nodes in the tree are of the same type and store a constant for 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. 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: 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 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 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 top of this raw tree, and get a zero-cost AST. Here is an example
example which adds type-safe wrappers for structs and fields: which adds type-safe wrappers for structs and fields:
```rust ```rust
// generic infrastructure
pub trait AstNode<'f>: Copy + 'f { pub trait AstNode<'f>: Copy + 'f {
fn new(node: Node<'f>) -> Option<Self>; fn new(node: Node<'f>) -> Option<Self>;
fn node(&self) -> Node<'f>; 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)) Box::new(node.children().filter_map(A::new))
} }
// AST elements, specific to Rust
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct StructDef<'f>(Node<'f>); pub struct StructDef<'f>(Node<'f>);
@ -315,22 +318,7 @@ impl<'f> AstNode<'f> for StructDef<'f> {
fn node(&self) -> Node<'f> { self.0 } 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 StructDef<'f> {}
impl<'f> NameOwner<'f> for FieldDef<'f> {}
impl<'f> StructDef<'f> { impl<'f> StructDef<'f> {
pub fn fields(&self) -> Box<Iterator<Item=FieldDef<'f>> + '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> { impl<'f> FieldDef<'f> {
pub fn type_ref(&self) -> Option<TypeRef<'f>> { pub fn type_ref(&self) -> Option<TypeRef<'f>> {
ast_children(self.node()).next() 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. * RFC discussion about the theoretical feasibility of the proposal.
* Implementation of the proposal as a completely separate crates.io * 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 * Additional round of discussion/RFC about merging with the mainline
compiler. compiler.
@ -392,6 +400,7 @@ plan is suggested:
- Incrementally add more information about source code to the current AST. - Incrementally add more information about source code to the current AST.
- Move the current libsyntax to crates.io as is. - Move the current libsyntax to crates.io as is.
- Explore alternative representations for the parse tree. - Explore alternative representations for the parse tree.
- Use parser generator instead of hand written parser.
# Unresolved questions # Unresolved questions
[unresolved]: #unresolved-questions [unresolved]: #unresolved-questions