mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-08 13:02:50 +00:00
move ast traits to a separate file
This commit is contained in:
parent
c2912892ef
commit
bd1f5ba222
@ -1,17 +1,22 @@
|
|||||||
//! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s
|
//! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s
|
||||||
mod generated;
|
mod generated;
|
||||||
|
mod traits;
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
pub use self::generated::*;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement, SyntaxElementChildren},
|
syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement},
|
||||||
SmolStr,
|
SmolStr,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use self::{
|
||||||
|
generated::*,
|
||||||
|
traits::*,
|
||||||
|
};
|
||||||
|
|
||||||
/// The main trait to go from untyped `SyntaxNode` to a typed ast. The
|
/// 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
|
/// 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
|
/// 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;
|
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<FnDef> {
|
|
||||||
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<ModuleItem> {
|
|
||||||
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<ItemOrMacro<'a>> {
|
|
||||||
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<Attr> {
|
|
||||||
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<std::string::String> {
|
|
||||||
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 {
|
impl Attr {
|
||||||
pub fn is_inner(&self) -> bool {
|
pub fn is_inner(&self) -> bool {
|
||||||
let tt = match self.value() {
|
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<Comment<'a>> {
|
|
||||||
self.iter.by_ref().find_map(|el| el.as_token().and_then(Comment::cast))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum CommentFlavor {
|
pub enum CommentFlavor {
|
||||||
Line,
|
Line,
|
||||||
|
148
crates/ra_syntax/src/ast/traits.rs
Normal file
148
crates/ra_syntax/src/ast/traits.rs
Normal file
@ -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<ast::FnDef> {
|
||||||
|
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<ast::ModuleItem> {
|
||||||
|
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<ItemOrMacro<'a>> {
|
||||||
|
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<ast::Attr> {
|
||||||
|
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<std::string::String> {
|
||||||
|
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<ast::Comment<'a>> {
|
||||||
|
self.iter.by_ref().find_map(|el| el.as_token().and_then(ast::Comment::cast))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user