Remove code duplication

This commit is contained in:
Aleksey Kladov 2020-04-09 22:22:58 +02:00
parent 33df20868d
commit e07d3c94de
5 changed files with 49 additions and 60 deletions

View file

@ -42,11 +42,6 @@ pub trait AstNode {
fn syntax(&self) -> &SyntaxNode; fn syntax(&self) -> &SyntaxNode;
} }
#[test]
fn assert_ast_is_object_safe() {
fn _f(_: &dyn AstNode, _: &dyn NameOwner) {}
}
/// Like `AstNode`, but wraps tokens rather than interior nodes. /// Like `AstNode`, but wraps tokens rather than interior nodes.
pub trait AstToken { pub trait AstToken {
fn can_cast(token: SyntaxKind) -> bool fn can_cast(token: SyntaxKind) -> bool
@ -64,22 +59,6 @@ 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> {
@ -100,12 +79,25 @@ impl<N: AstNode> Iterator for AstChildren<N> {
} }
} }
fn child_opt<P: AstNode + ?Sized, C: AstNode>(parent: &P) -> Option<C> { mod support {
children(parent).next() 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)
}
} }
fn children<P: AstNode + ?Sized, C: AstNode>(parent: &P) -> AstChildren<C> { #[test]
AstChildren::new(parent.syntax()) fn assert_ast_is_object_safe() {
fn _f(_: &dyn AstNode, _: &dyn NameOwner) {}
} }
#[test] #[test]

View file

@ -6,7 +6,7 @@ use std::{iter, ops::RangeInclusive};
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use crate::{ use crate::{
algo, algo::{self, neighbor, SyntaxRewriter},
ast::{ ast::{
self, self,
make::{self, tokens}, make::{self, tokens},
@ -16,7 +16,6 @@ use crate::{
SyntaxKind::{ATTR, COMMENT, WHITESPACE}, SyntaxKind::{ATTR, COMMENT, WHITESPACE},
SyntaxNode, SyntaxToken, T, SyntaxNode, SyntaxToken, T,
}; };
use algo::{neighbor, SyntaxRewriter};
impl ast::BinExpr { impl ast::BinExpr {
#[must_use] #[must_use]

View file

@ -1,7 +1,7 @@
//! Various extension methods to ast Expr Nodes, which are hard to code-generate. //! Various extension methods to ast Expr Nodes, which are hard to code-generate.
use crate::{ use crate::{
ast::{self, child_opt, children, AstChildren, AstNode}, ast::{self, support, AstChildren, AstNode},
SmolStr, SmolStr,
SyntaxKind::*, SyntaxKind::*,
SyntaxToken, T, SyntaxToken, T,
@ -36,7 +36,7 @@ impl ast::IfExpr {
let res = match self.blocks().nth(1) { let res = match self.blocks().nth(1) {
Some(block) => ElseBranch::Block(block), Some(block) => ElseBranch::Block(block),
None => { None => {
let elif: ast::IfExpr = child_opt(self)?; let elif: ast::IfExpr = support::child(self.syntax())?;
ElseBranch::IfExpr(elif) ElseBranch::IfExpr(elif)
} }
}; };
@ -44,7 +44,7 @@ impl ast::IfExpr {
} }
fn blocks(&self) -> AstChildren<ast::BlockExpr> { fn blocks(&self) -> AstChildren<ast::BlockExpr> {
children(self) support::children(self.syntax())
} }
} }
@ -212,15 +212,15 @@ impl ast::BinExpr {
} }
pub fn lhs(&self) -> Option<ast::Expr> { pub fn lhs(&self) -> Option<ast::Expr> {
children(self).next() support::children(self.syntax()).next()
} }
pub fn rhs(&self) -> Option<ast::Expr> { pub fn rhs(&self) -> Option<ast::Expr> {
children(self).nth(1) support::children(self.syntax()).nth(1)
} }
pub fn sub_exprs(&self) -> (Option<ast::Expr>, Option<ast::Expr>) { pub fn sub_exprs(&self) -> (Option<ast::Expr>, Option<ast::Expr>) {
let mut children = children(self); let mut children = support::children(self.syntax());
let first = children.next(); let first = children.next();
let second = children.next(); let second = children.next();
(first, second) (first, second)
@ -275,10 +275,10 @@ impl ast::RangeExpr {
impl ast::IndexExpr { impl ast::IndexExpr {
pub fn base(&self) -> Option<ast::Expr> { pub fn base(&self) -> Option<ast::Expr> {
children(self).next() support::children(self.syntax()).next()
} }
pub fn index(&self) -> Option<ast::Expr> { pub fn index(&self) -> Option<ast::Expr> {
children(self).nth(1) support::children(self.syntax()).nth(1)
} }
} }
@ -291,11 +291,11 @@ impl ast::ArrayExpr {
pub fn kind(&self) -> ArrayExprKind { pub fn kind(&self) -> ArrayExprKind {
if self.is_repeat() { if self.is_repeat() {
ArrayExprKind::Repeat { ArrayExprKind::Repeat {
initializer: children(self).next(), initializer: support::children(self.syntax()).next(),
repeat: children(self).nth(1), repeat: support::children(self.syntax()).nth(1),
} }
} else { } else {
ArrayExprKind::ElementList(children(self)) ArrayExprKind::ElementList(support::children(self.syntax()))
} }
} }

View file

@ -5,9 +5,7 @@ use itertools::Itertools;
use ra_parser::SyntaxKind; use ra_parser::SyntaxKind;
use crate::{ use crate::{
ast::{ ast::{self, support, AstNode, AstToken, AttrInput, NameOwner, SyntaxNode},
self, child_opt, children, support, AstNode, AstToken, AttrInput, NameOwner, SyntaxNode,
},
SmolStr, SyntaxElement, SyntaxToken, T, SmolStr, SyntaxElement, SyntaxToken, T,
}; };
@ -161,7 +159,7 @@ impl ast::ImplDef {
} }
fn target(&self) -> (Option<ast::TypeRef>, Option<ast::TypeRef>) { fn target(&self) -> (Option<ast::TypeRef>, Option<ast::TypeRef>) {
let mut types = children(self); let mut types = support::children(self.syntax());
let first = types.next(); let first = types.next();
let second = types.next(); let second = types.next();
(first, second) (first, second)
@ -177,9 +175,9 @@ pub enum StructKind {
impl StructKind { impl StructKind {
fn from_node<N: AstNode>(node: &N) -> StructKind { fn from_node<N: AstNode>(node: &N) -> StructKind {
if let Some(nfdl) = child_opt::<_, ast::RecordFieldDefList>(node) { if let Some(nfdl) = support::child::<ast::RecordFieldDefList>(node.syntax()) {
StructKind::Record(nfdl) StructKind::Record(nfdl)
} else if let Some(pfl) = child_opt::<_, ast::TupleFieldDefList>(node) { } else if let Some(pfl) = support::child::<ast::TupleFieldDefList>(node.syntax()) {
StructKind::Tuple(pfl) StructKind::Tuple(pfl)
} else { } else {
StructKind::Unit StructKind::Unit
@ -322,9 +320,9 @@ pub enum TypeBoundKind {
impl ast::TypeBound { impl ast::TypeBound {
pub fn kind(&self) -> TypeBoundKind { pub fn kind(&self) -> TypeBoundKind {
if let Some(path_type) = children(self).next() { if let Some(path_type) = support::children(self.syntax()).next() {
TypeBoundKind::PathType(path_type) TypeBoundKind::PathType(path_type)
} else if let Some(for_type) = children(self).next() { } else if let Some(for_type) = support::children(self.syntax()).next() {
TypeBoundKind::ForType(for_type) TypeBoundKind::ForType(for_type)
} else if let Some(lifetime) = self.lifetime_token() { } else if let Some(lifetime) = self.lifetime_token() {
TypeBoundKind::Lifetime(lifetime) TypeBoundKind::Lifetime(lifetime)
@ -364,7 +362,7 @@ pub enum VisibilityKind {
impl ast::Visibility { impl ast::Visibility {
pub fn kind(&self) -> VisibilityKind { pub fn kind(&self) -> VisibilityKind {
if let Some(path) = children(self).next() { if let Some(path) = support::children(self.syntax()).next() {
VisibilityKind::In(path) VisibilityKind::In(path)
} else if self.crate_kw_token().is_some() { } else if self.crate_kw_token().is_some() {
VisibilityKind::PubCrate VisibilityKind::PubCrate

View file

@ -5,69 +5,69 @@
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::{
ast::{self, child_opt, children, support, AstChildren, AstNode, AstToken}, ast::{self, support, AstChildren, AstNode, AstToken},
syntax_node::SyntaxElementChildren, syntax_node::SyntaxElementChildren,
}; };
pub trait TypeAscriptionOwner: AstNode { pub trait TypeAscriptionOwner: AstNode {
fn ascribed_type(&self) -> Option<ast::TypeRef> { fn ascribed_type(&self) -> Option<ast::TypeRef> {
child_opt(self) support::child(self.syntax())
} }
} }
pub trait NameOwner: AstNode { pub trait NameOwner: AstNode {
fn name(&self) -> Option<ast::Name> { fn name(&self) -> Option<ast::Name> {
child_opt(self) support::child(self.syntax())
} }
} }
pub trait VisibilityOwner: AstNode { pub trait VisibilityOwner: AstNode {
fn visibility(&self) -> Option<ast::Visibility> { fn visibility(&self) -> Option<ast::Visibility> {
child_opt(self) support::child(self.syntax())
} }
} }
pub trait LoopBodyOwner: AstNode { pub trait LoopBodyOwner: AstNode {
fn loop_body(&self) -> Option<ast::BlockExpr> { fn loop_body(&self) -> Option<ast::BlockExpr> {
child_opt(self) support::child(self.syntax())
} }
fn label(&self) -> Option<ast::Label> { fn label(&self) -> Option<ast::Label> {
child_opt(self) support::child(self.syntax())
} }
} }
pub trait ArgListOwner: AstNode { pub trait ArgListOwner: AstNode {
fn arg_list(&self) -> Option<ast::ArgList> { fn arg_list(&self) -> Option<ast::ArgList> {
child_opt(self) support::child(self.syntax())
} }
} }
pub trait FnDefOwner: AstNode { pub trait FnDefOwner: AstNode {
fn functions(&self) -> AstChildren<ast::FnDef> { fn functions(&self) -> AstChildren<ast::FnDef> {
children(self) support::children(self.syntax())
} }
} }
pub trait ModuleItemOwner: AstNode { pub trait ModuleItemOwner: AstNode {
fn items(&self) -> AstChildren<ast::ModuleItem> { fn items(&self) -> AstChildren<ast::ModuleItem> {
children(self) support::children(self.syntax())
} }
} }
pub trait TypeParamsOwner: AstNode { pub trait TypeParamsOwner: AstNode {
fn type_param_list(&self) -> Option<ast::TypeParamList> { fn type_param_list(&self) -> Option<ast::TypeParamList> {
child_opt(self) support::child(self.syntax())
} }
fn where_clause(&self) -> Option<ast::WhereClause> { fn where_clause(&self) -> Option<ast::WhereClause> {
child_opt(self) support::child(self.syntax())
} }
} }
pub trait TypeBoundsOwner: AstNode { pub trait TypeBoundsOwner: AstNode {
fn type_bound_list(&self) -> Option<ast::TypeBoundList> { fn type_bound_list(&self) -> Option<ast::TypeBoundList> {
child_opt(self) support::child(self.syntax())
} }
fn colon(&self) -> Option<ast::Colon> { fn colon(&self) -> Option<ast::Colon> {
@ -77,7 +77,7 @@ pub trait TypeBoundsOwner: AstNode {
pub trait AttrsOwner: AstNode { pub trait AttrsOwner: AstNode {
fn attrs(&self) -> AstChildren<ast::Attr> { fn attrs(&self) -> AstChildren<ast::Attr> {
children(self) support::children(self.syntax())
} }
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)