Scale back to only two traits

This commit is contained in:
Aleksey Kladov 2020-04-09 13:00:09 +02:00
parent 60f4d7bd8c
commit 689661c959
8 changed files with 2020 additions and 228 deletions

View File

@ -1,5 +1,5 @@
use ra_syntax::{
ast::{self, AstElement, AstNode},
ast::{self, AstNode},
SyntaxKind::{
BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR,
WHITESPACE,
@ -124,7 +124,7 @@ fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> {
}
}
if ast::Stmt::cast_element(node.clone().into()).is_some() {
if ast::Stmt::cast(node.clone().into()).is_some() {
return Some((node, false));
}

View File

@ -492,7 +492,6 @@ impl ExprCollector<'_> {
ast::Stmt::ExprStmt(stmt) => {
Some(Statement::Expr(self.collect_expr_opt(stmt.expr())))
}
ast::Stmt::ModuleItem(_) => None,
})
.collect();
let tail = block.expr().map(|e| self.collect_expr(e));

View File

@ -64,6 +64,22 @@ pub trait AstToken {
}
}
mod support {
use super::{AstChildren, AstNode, AstToken, SyntaxNode};
pub(super) fn child<N: AstNode>(parent: &SyntaxNode) -> Option<N> {
parent.children().find_map(N::cast)
}
pub(super) fn children<N: AstNode>(parent: &SyntaxNode) -> AstChildren<N> {
AstChildren::new(parent)
}
pub(super) fn token<T: AstToken>(parent: &SyntaxNode) -> Option<T> {
parent.children_with_tokens().filter_map(|it| it.into_token()).find_map(T::cast)
}
}
/// An iterator over `SyntaxNode` children of a particular AST type.
#[derive(Debug, Clone)]
pub struct AstChildren<N> {

View File

@ -5,8 +5,7 @@ use itertools::Itertools;
use crate::{
ast::{
self, child_opt, child_token_opt, children, AstElement, AstNode, AstToken, AttrInput,
NameOwner, SyntaxNode,
self, child_opt, children, support, AstNode, AstToken, AttrInput, NameOwner, SyntaxNode,
},
SmolStr, SyntaxElement,
SyntaxKind::*,
@ -437,7 +436,7 @@ impl ast::TypeBound {
.skip_while(|it| it.kind() != T![const])
.find_map(ast::Question::cast)
} else {
child_token_opt(self)
support::token(&self.syntax)
}
}
}
@ -509,7 +508,7 @@ impl ast::RangePat {
pub fn start(&self) -> Option<ast::Pat> {
self.syntax()
.children_with_tokens()
.take_while(|it| !ast::RangeSeparator::can_cast_element(it.kind()))
.take_while(|it| !ast::RangeSeparator::can_cast(it.kind()))
.filter_map(|it| it.into_node())
.find_map(ast::Pat::cast)
}
@ -517,7 +516,7 @@ impl ast::RangePat {
pub fn end(&self) -> Option<ast::Pat> {
self.syntax()
.children_with_tokens()
.skip_while(|it| !ast::RangeSeparator::can_cast_element(it.kind()))
.skip_while(|it| !ast::RangeSeparator::can_cast(it.kind()))
.filter_map(|it| it.into_node())
.find_map(ast::Pat::cast)
}
@ -525,10 +524,10 @@ impl ast::RangePat {
impl ast::TokenTree {
pub fn left_delimiter(&self) -> Option<ast::LeftDelimiter> {
self.syntax().first_child_or_token().and_then(ast::LeftDelimiter::cast_element)
self.syntax().first_child_or_token()?.into_token().and_then(ast::LeftDelimiter::cast)
}
pub fn right_delimiter(&self) -> Option<ast::RightDelimiter> {
self.syntax().last_child_or_token().and_then(ast::RightDelimiter::cast_element)
self.syntax().last_child_or_token()?.into_token().and_then(ast::RightDelimiter::cast)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -4,9 +4,9 @@
use itertools::Itertools;
use crate::ast::{
self, child_elements, child_opt, child_token_opt, child_tokens, children, AstChildElements,
AstChildTokens, AstChildren, AstNode, AstToken,
use crate::{
ast::{self, child_opt, children, support, AstChildren, AstNode, AstToken},
syntax_node::SyntaxElementChildren,
};
pub trait TypeAscriptionOwner: AstNode {
@ -71,7 +71,7 @@ pub trait TypeBoundsOwner: AstNode {
}
fn colon(&self) -> Option<ast::Colon> {
child_token_opt(self)
support::token(self.syntax())
}
}
@ -82,14 +82,11 @@ pub trait AttrsOwner: AstNode {
fn has_atom_attr(&self, atom: &str) -> bool {
self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom)
}
fn attr_or_comments(&self) -> AstChildElements<ast::AttrOrComment> {
child_elements(self)
}
}
pub trait DocCommentsOwner: AstNode {
fn doc_comments(&self) -> AstChildTokens<ast::Comment> {
child_tokens(self)
fn doc_comments(&self) -> CommentIter {
CommentIter { iter: self.syntax().children_with_tokens() }
}
/// Returns the textual content of a doc comment block as a single string.
@ -134,3 +131,14 @@ pub trait DocCommentsOwner: AstNode {
}
}
}
pub struct CommentIter {
iter: SyntaxElementChildren,
}
impl Iterator for CommentIter {
type Item = ast::Comment;
fn next(&mut self) -> Option<ast::Comment> {
self.iter.by_ref().find_map(|el| el.into_token().and_then(ast::Comment::cast))
}
}

View File

@ -549,7 +549,6 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
struct Block: AttrsOwner, ModuleItemOwner {
LCurly,
statements: [Stmt],
statements_or_semi: [StmtOrSemi],
Expr,
RCurly,
}
@ -749,12 +748,10 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
enum AttrInput { Literal, TokenTree }
enum Stmt {
ModuleItem,
LetStmt,
ExprStmt,
// macro calls are parsed as expression statements */
}
enum StmtOrSemi {Stmt, Semi}
enum LeftDelimiter { LParen, LBrack, LCurly }
enum RightDelimiter { RParen, RBrack, RCurly }
@ -825,10 +822,5 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
RecordFieldDefList,
TupleFieldDefList,
}
enum AttrOrComment {
Attr,
Comment
}
},
};

View File

@ -146,14 +146,23 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
FieldSrc::Many(_) => {
quote! {
pub fn #method_name(&self) -> AstChildren<#ty> {
AstChildren::new(&self.syntax)
support::children(&self.syntax)
}
}
}
FieldSrc::Optional(_) | FieldSrc::Shorthand => {
quote! {
pub fn #method_name(&self) -> Option<#ty> {
AstChildren::new(&self.syntax).next()
let is_token = element_kinds_map[&ty.to_string()].has_tokens;
if is_token {
quote! {
pub fn #method_name(&self) -> Option<#ty> {
support::token(&self.syntax)
}
}
} else {
quote! {
pub fn #method_name(&self) -> Option<#ty> {
support::child(&self.syntax)
}
}
}
}
@ -205,6 +214,48 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
quote!(impl ast::#trait_name for #name {})
});
let element_kinds = &element_kinds_map[&en.name.to_string()];
assert!(
element_kinds.has_nodes ^ element_kinds.has_tokens,
"{}: {:#?}",
name,
element_kinds
);
let specific_ast_trait = {
let (ast_trait, syntax_type) = if element_kinds.has_tokens {
(quote!(AstToken), quote!(SyntaxToken))
} else {
(quote!(AstNode), quote!(SyntaxNode))
};
quote! {
impl #ast_trait for #name {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
#(#kinds)|* => true,
_ => false,
}
}
fn cast(syntax: #syntax_type) -> Option<Self> {
let res = match syntax.kind() {
#(
#kinds => #name::#variants(#variants { syntax }),
)*
_ => return None,
};
Some(res)
}
fn syntax(&self) -> &#syntax_type {
match self {
#(
#name::#variants(it) => &it.syntax,
)*
}
}
}
}
};
quote! {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum #name {
@ -225,30 +276,8 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
}
}
impl AstNode for #name {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
#(#kinds)|* => true,
_ => false,
}
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
#(
#kinds => #name::#variants(#variants { syntax }),
)*
_ => return None,
};
Some(res)
}
fn syntax(&self) -> &SyntaxNode {
match self {
#(
#name::#variants(it) => &it.syntax,
)*
}
}
}
#specific_ast_trait
#(#traits)*
}
});
@ -268,7 +297,7 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
#[allow(unused_imports)]
use crate::{
SyntaxNode, SyntaxToken, SyntaxElement, NodeOrToken, SyntaxKind::{self, *},
ast::{self, AstNode, AstToken, AstChildren},
ast::{self, AstNode, AstToken, AstChildren, support},
};
#(#tokens)*