From bd1f5ba222a1f5a44c20a9fcb70c3785a3758b20 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 2 Apr 2019 10:03:19 +0300 Subject: move ast traits to a separate file --- crates/ra_syntax/src/ast.rs | 151 ++----------------------------------- crates/ra_syntax/src/ast/traits.rs | 148 ++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 144 deletions(-) create mode 100644 crates/ra_syntax/src/ast/traits.rs (limited to 'crates/ra_syntax/src') diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index ffd115cef..3e81fa990 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -1,17 +1,22 @@ //! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s mod generated; +mod traits; use std::marker::PhantomData; use itertools::Itertools; -pub use self::generated::*; use crate::{ - syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement, SyntaxElementChildren}, + syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement}, SmolStr, SyntaxKind::*, }; +pub use self::{ + generated::*, + traits::*, +}; + /// The main trait to go from untyped `SyntaxNode` to a typed ast. The /// conversion itself has zero runtime cost: ast and syntax nodes have exactly /// the same representation: a pointer to the tree root and a pointer to the @@ -25,137 +30,6 @@ pub trait AstNode: fn syntax(&self) -> &SyntaxNode; } -pub trait TypeAscriptionOwner: AstNode { - fn ascribed_type(&self) -> Option<&TypeRef> { - child_opt(self) - } -} - -pub trait NameOwner: AstNode { - fn name(&self) -> Option<&Name> { - child_opt(self) - } -} - -pub trait VisibilityOwner: AstNode { - fn visibility(&self) -> Option<&Visibility> { - child_opt(self) - } -} - -pub trait LoopBodyOwner: AstNode { - fn loop_body(&self) -> Option<&Block> { - child_opt(self) - } -} - -pub trait ArgListOwner: AstNode { - fn arg_list(&self) -> Option<&ArgList> { - child_opt(self) - } -} - -pub trait FnDefOwner: AstNode { - fn functions(&self) -> AstChildren { - children(self) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ItemOrMacro<'a> { - Item(&'a ModuleItem), - Macro(&'a MacroCall), -} - -pub trait ModuleItemOwner: AstNode { - fn items(&self) -> AstChildren { - children(self) - } - fn items_with_macros(&self) -> ItemOrMacroIter { - ItemOrMacroIter(self.syntax().children()) - } -} - -#[derive(Debug)] -pub struct ItemOrMacroIter<'a>(SyntaxNodeChildren<'a>); - -impl<'a> Iterator for ItemOrMacroIter<'a> { - type Item = ItemOrMacro<'a>; - fn next(&mut self) -> Option> { - loop { - let n = self.0.next()?; - if let Some(item) = ModuleItem::cast(n) { - return Some(ItemOrMacro::Item(item)); - } - if let Some(call) = MacroCall::cast(n) { - return Some(ItemOrMacro::Macro(call)); - } - } - } -} - -pub trait TypeParamsOwner: AstNode { - fn type_param_list(&self) -> Option<&TypeParamList> { - child_opt(self) - } - - fn where_clause(&self) -> Option<&WhereClause> { - child_opt(self) - } -} - -pub trait TypeBoundsOwner: AstNode { - fn type_bound_list(&self) -> Option<&TypeBoundList> { - child_opt(self) - } -} - -pub trait AttrsOwner: AstNode { - fn attrs(&self) -> AstChildren { - children(self) - } - fn has_atom_attr(&self, atom: &str) -> bool { - self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom) - } -} - -pub trait DocCommentsOwner: AstNode { - 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. - /// That is, strips leading `///` (+ optional 1 character of whitespace) - /// and joins lines. - fn doc_comment_text(&self) -> Option { - let docs = self - .doc_comments() - .filter(|comment| comment.is_doc_comment()) - .map(|comment| { - let prefix_len = comment.prefix().len(); - - let line = comment.text().as_str(); - - // Determine if the prefix or prefix + 1 char is stripped - let pos = - if line.chars().nth(prefix_len).map(|c| c.is_whitespace()).unwrap_or(false) { - prefix_len + 1 - } else { - prefix_len - }; - - line[pos..].to_owned() - }) - .join("\n"); - - if docs.is_empty() { - None - } else { - Some(docs) - } - } -} - impl Attr { pub fn is_inner(&self) -> bool { let tt = match self.value() { @@ -245,17 +119,6 @@ impl<'a> Comment<'a> { } } -pub struct CommentIter<'a> { - iter: SyntaxElementChildren<'a>, -} - -impl<'a> Iterator for CommentIter<'a> { - type Item = Comment<'a>; - fn next(&mut self) -> Option> { - self.iter.by_ref().find_map(|el| el.as_token().and_then(Comment::cast)) - } -} - #[derive(Debug, PartialEq, Eq)] pub enum CommentFlavor { Line, diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs new file mode 100644 index 000000000..85fe6d5e1 --- /dev/null +++ b/crates/ra_syntax/src/ast/traits.rs @@ -0,0 +1,148 @@ +use itertools::Itertools; + +use crate::{ + syntax_node::{SyntaxNodeChildren, SyntaxElementChildren}, + ast::{self, child_opt, children, AstNode, AstChildren}, +}; + +pub trait TypeAscriptionOwner: AstNode { + fn ascribed_type(&self) -> Option<&ast::TypeRef> { + child_opt(self) + } +} + +pub trait NameOwner: AstNode { + fn name(&self) -> Option<&ast::Name> { + child_opt(self) + } +} + +pub trait VisibilityOwner: AstNode { + fn visibility(&self) -> Option<&ast::Visibility> { + child_opt(self) + } +} + +pub trait LoopBodyOwner: AstNode { + fn loop_body(&self) -> Option<&ast::Block> { + child_opt(self) + } +} + +pub trait ArgListOwner: AstNode { + fn arg_list(&self) -> Option<&ast::ArgList> { + child_opt(self) + } +} + +pub trait FnDefOwner: AstNode { + fn functions(&self) -> AstChildren { + children(self) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ItemOrMacro<'a> { + Item(&'a ast::ModuleItem), + Macro(&'a ast::MacroCall), +} + +pub trait ModuleItemOwner: AstNode { + fn items(&self) -> AstChildren { + children(self) + } + fn items_with_macros(&self) -> ItemOrMacroIter { + ItemOrMacroIter(self.syntax().children()) + } +} + +#[derive(Debug)] +pub struct ItemOrMacroIter<'a>(SyntaxNodeChildren<'a>); + +impl<'a> Iterator for ItemOrMacroIter<'a> { + type Item = ItemOrMacro<'a>; + fn next(&mut self) -> Option> { + loop { + let n = self.0.next()?; + if let Some(item) = ast::ModuleItem::cast(n) { + return Some(ItemOrMacro::Item(item)); + } + if let Some(call) = ast::MacroCall::cast(n) { + return Some(ItemOrMacro::Macro(call)); + } + } + } +} + +pub trait TypeParamsOwner: AstNode { + fn type_param_list(&self) -> Option<&ast::TypeParamList> { + child_opt(self) + } + + fn where_clause(&self) -> Option<&ast::WhereClause> { + child_opt(self) + } +} + +pub trait TypeBoundsOwner: AstNode { + fn type_bound_list(&self) -> Option<&ast::TypeBoundList> { + child_opt(self) + } +} + +pub trait AttrsOwner: AstNode { + fn attrs(&self) -> AstChildren { + children(self) + } + fn has_atom_attr(&self, atom: &str) -> bool { + self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom) + } +} + +pub trait DocCommentsOwner: AstNode { + 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. + /// That is, strips leading `///` (+ optional 1 character of whitespace) + /// and joins lines. + fn doc_comment_text(&self) -> Option { + let docs = self + .doc_comments() + .filter(|comment| comment.is_doc_comment()) + .map(|comment| { + let prefix_len = comment.prefix().len(); + + let line = comment.text().as_str(); + + // Determine if the prefix or prefix + 1 char is stripped + let pos = + if line.chars().nth(prefix_len).map(|c| c.is_whitespace()).unwrap_or(false) { + prefix_len + 1 + } else { + prefix_len + }; + + line[pos..].to_owned() + }) + .join("\n"); + + if docs.is_empty() { + None + } else { + Some(docs) + } + } +} + +pub struct CommentIter<'a> { + iter: SyntaxElementChildren<'a>, +} + +impl<'a> Iterator for CommentIter<'a> { + type Item = ast::Comment<'a>; + fn next(&mut self) -> Option> { + self.iter.by_ref().find_map(|el| el.as_token().and_then(ast::Comment::cast)) + } +} -- cgit v1.2.3