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::{ use ra_syntax::{
ast::{self, AstElement, AstNode}, ast::{self, AstNode},
SyntaxKind::{ SyntaxKind::{
BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR,
WHITESPACE, 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)); return Some((node, false));
} }

View file

@ -492,7 +492,6 @@ impl ExprCollector<'_> {
ast::Stmt::ExprStmt(stmt) => { ast::Stmt::ExprStmt(stmt) => {
Some(Statement::Expr(self.collect_expr_opt(stmt.expr()))) Some(Statement::Expr(self.collect_expr_opt(stmt.expr())))
} }
ast::Stmt::ModuleItem(_) => None,
}) })
.collect(); .collect();
let tail = block.expr().map(|e| self.collect_expr(e)); 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. /// An iterator over `SyntaxNode` children of a particular AST type.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AstChildren<N> { pub struct AstChildren<N> {

View file

@ -5,8 +5,7 @@ use itertools::Itertools;
use crate::{ use crate::{
ast::{ ast::{
self, child_opt, child_token_opt, children, AstElement, AstNode, AstToken, AttrInput, self, child_opt, children, support, AstNode, AstToken, AttrInput, NameOwner, SyntaxNode,
NameOwner, SyntaxNode,
}, },
SmolStr, SyntaxElement, SmolStr, SyntaxElement,
SyntaxKind::*, SyntaxKind::*,
@ -437,7 +436,7 @@ impl ast::TypeBound {
.skip_while(|it| it.kind() != T![const]) .skip_while(|it| it.kind() != T![const])
.find_map(ast::Question::cast) .find_map(ast::Question::cast)
} else { } else {
child_token_opt(self) support::token(&self.syntax)
} }
} }
} }
@ -509,7 +508,7 @@ impl ast::RangePat {
pub fn start(&self) -> Option<ast::Pat> { pub fn start(&self) -> Option<ast::Pat> {
self.syntax() self.syntax()
.children_with_tokens() .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()) .filter_map(|it| it.into_node())
.find_map(ast::Pat::cast) .find_map(ast::Pat::cast)
} }
@ -517,7 +516,7 @@ impl ast::RangePat {
pub fn end(&self) -> Option<ast::Pat> { pub fn end(&self) -> Option<ast::Pat> {
self.syntax() self.syntax()
.children_with_tokens() .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()) .filter_map(|it| it.into_node())
.find_map(ast::Pat::cast) .find_map(ast::Pat::cast)
} }
@ -525,10 +524,10 @@ impl ast::RangePat {
impl ast::TokenTree { impl ast::TokenTree {
pub fn left_delimiter(&self) -> Option<ast::LeftDelimiter> { 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> { 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 itertools::Itertools;
use crate::ast::{ use crate::{
self, child_elements, child_opt, child_token_opt, child_tokens, children, AstChildElements, ast::{self, child_opt, children, support, AstChildren, AstNode, AstToken},
AstChildTokens, AstChildren, AstNode, AstToken, syntax_node::SyntaxElementChildren,
}; };
pub trait TypeAscriptionOwner: AstNode { pub trait TypeAscriptionOwner: AstNode {
@ -71,7 +71,7 @@ pub trait TypeBoundsOwner: AstNode {
} }
fn colon(&self) -> Option<ast::Colon> { 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 { fn has_atom_attr(&self, atom: &str) -> bool {
self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom) 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 { pub trait DocCommentsOwner: AstNode {
fn doc_comments(&self) -> AstChildTokens<ast::Comment> { fn doc_comments(&self) -> CommentIter {
child_tokens(self) CommentIter { iter: self.syntax().children_with_tokens() }
} }
/// Returns the textual content of a doc comment block as a single string. /// 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 { struct Block: AttrsOwner, ModuleItemOwner {
LCurly, LCurly,
statements: [Stmt], statements: [Stmt],
statements_or_semi: [StmtOrSemi],
Expr, Expr,
RCurly, RCurly,
} }
@ -749,12 +748,10 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
enum AttrInput { Literal, TokenTree } enum AttrInput { Literal, TokenTree }
enum Stmt { enum Stmt {
ModuleItem,
LetStmt, LetStmt,
ExprStmt, ExprStmt,
// macro calls are parsed as expression statements */ // macro calls are parsed as expression statements */
} }
enum StmtOrSemi {Stmt, Semi}
enum LeftDelimiter { LParen, LBrack, LCurly } enum LeftDelimiter { LParen, LBrack, LCurly }
enum RightDelimiter { RParen, RBrack, RCurly } enum RightDelimiter { RParen, RBrack, RCurly }
@ -825,10 +822,5 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
RecordFieldDefList, RecordFieldDefList,
TupleFieldDefList, TupleFieldDefList,
} }
enum AttrOrComment {
Attr,
Comment
}
}, },
}; };

View file

@ -146,14 +146,23 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
FieldSrc::Many(_) => { FieldSrc::Many(_) => {
quote! { quote! {
pub fn #method_name(&self) -> AstChildren<#ty> { pub fn #method_name(&self) -> AstChildren<#ty> {
AstChildren::new(&self.syntax) support::children(&self.syntax)
} }
} }
} }
FieldSrc::Optional(_) | FieldSrc::Shorthand => { FieldSrc::Optional(_) | FieldSrc::Shorthand => {
let is_token = element_kinds_map[&ty.to_string()].has_tokens;
if is_token {
quote! { quote! {
pub fn #method_name(&self) -> Option<#ty> { pub fn #method_name(&self) -> Option<#ty> {
AstChildren::new(&self.syntax).next() 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 {}) 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! { quote! {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum #name { pub enum #name {
@ -225,30 +276,8 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
} }
impl AstNode for #name { #specific_ast_trait
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,
)*
}
}
}
#(#traits)* #(#traits)*
} }
}); });
@ -268,7 +297,7 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
#[allow(unused_imports)] #[allow(unused_imports)]
use crate::{ use crate::{
SyntaxNode, SyntaxToken, SyntaxElement, NodeOrToken, SyntaxKind::{self, *}, SyntaxNode, SyntaxToken, SyntaxElement, NodeOrToken, SyntaxKind::{self, *},
ast::{self, AstNode, AstToken, AstChildren}, ast::{self, AstNode, AstToken, AstChildren, support},
}; };
#(#tokens)* #(#tokens)*