aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/ast.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-04-02 08:03:19 +0100
committerAleksey Kladov <[email protected]>2019-04-02 08:03:19 +0100
commitbd1f5ba222a1f5a44c20a9fcb70c3785a3758b20 (patch)
tree2fee5aa024ffdeaf16c76f9ef83cdce2c58462f0 /crates/ra_syntax/src/ast.rs
parentc2912892effbcf24d94da235b9ac0d2a7fccea5d (diff)
move ast traits to a separate file
Diffstat (limited to 'crates/ra_syntax/src/ast.rs')
-rw-r--r--crates/ra_syntax/src/ast.rs151
1 files changed, 7 insertions, 144 deletions
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 @@
1//! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s 1//! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s
2mod generated; 2mod generated;
3mod traits;
3 4
4use std::marker::PhantomData; 5use std::marker::PhantomData;
5 6
6use itertools::Itertools; 7use itertools::Itertools;
7 8
8pub use self::generated::*;
9use crate::{ 9use crate::{
10 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement, SyntaxElementChildren}, 10 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement},
11 SmolStr, 11 SmolStr,
12 SyntaxKind::*, 12 SyntaxKind::*,
13}; 13};
14 14
15pub use self::{
16 generated::*,
17 traits::*,
18};
19
15/// The main trait to go from untyped `SyntaxNode` to a typed ast. The 20/// The main trait to go from untyped `SyntaxNode` to a typed ast. The
16/// conversion itself has zero runtime cost: ast and syntax nodes have exactly 21/// conversion itself has zero runtime cost: ast and syntax nodes have exactly
17/// the same representation: a pointer to the tree root and a pointer to the 22/// the same representation: a pointer to the tree root and a pointer to the
@@ -25,137 +30,6 @@ pub trait AstNode:
25 fn syntax(&self) -> &SyntaxNode; 30 fn syntax(&self) -> &SyntaxNode;
26} 31}
27 32
28pub trait TypeAscriptionOwner: AstNode {
29 fn ascribed_type(&self) -> Option<&TypeRef> {
30 child_opt(self)
31 }
32}
33
34pub trait NameOwner: AstNode {
35 fn name(&self) -> Option<&Name> {
36 child_opt(self)
37 }
38}
39
40pub trait VisibilityOwner: AstNode {
41 fn visibility(&self) -> Option<&Visibility> {
42 child_opt(self)
43 }
44}
45
46pub trait LoopBodyOwner: AstNode {
47 fn loop_body(&self) -> Option<&Block> {
48 child_opt(self)
49 }
50}
51
52pub trait ArgListOwner: AstNode {
53 fn arg_list(&self) -> Option<&ArgList> {
54 child_opt(self)
55 }
56}
57
58pub trait FnDefOwner: AstNode {
59 fn functions(&self) -> AstChildren<FnDef> {
60 children(self)
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum ItemOrMacro<'a> {
66 Item(&'a ModuleItem),
67 Macro(&'a MacroCall),
68}
69
70pub trait ModuleItemOwner: AstNode {
71 fn items(&self) -> AstChildren<ModuleItem> {
72 children(self)
73 }
74 fn items_with_macros(&self) -> ItemOrMacroIter {
75 ItemOrMacroIter(self.syntax().children())
76 }
77}
78
79#[derive(Debug)]
80pub struct ItemOrMacroIter<'a>(SyntaxNodeChildren<'a>);
81
82impl<'a> Iterator for ItemOrMacroIter<'a> {
83 type Item = ItemOrMacro<'a>;
84 fn next(&mut self) -> Option<ItemOrMacro<'a>> {
85 loop {
86 let n = self.0.next()?;
87 if let Some(item) = ModuleItem::cast(n) {
88 return Some(ItemOrMacro::Item(item));
89 }
90 if let Some(call) = MacroCall::cast(n) {
91 return Some(ItemOrMacro::Macro(call));
92 }
93 }
94 }
95}
96
97pub trait TypeParamsOwner: AstNode {
98 fn type_param_list(&self) -> Option<&TypeParamList> {
99 child_opt(self)
100 }
101
102 fn where_clause(&self) -> Option<&WhereClause> {
103 child_opt(self)
104 }
105}
106
107pub trait TypeBoundsOwner: AstNode {
108 fn type_bound_list(&self) -> Option<&TypeBoundList> {
109 child_opt(self)
110 }
111}
112
113pub trait AttrsOwner: AstNode {
114 fn attrs(&self) -> AstChildren<Attr> {
115 children(self)
116 }
117 fn has_atom_attr(&self, atom: &str) -> bool {
118 self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom)
119 }
120}
121
122pub trait DocCommentsOwner: AstNode {
123 fn doc_comments(&self) -> CommentIter {
124 CommentIter { iter: self.syntax().children_with_tokens() }
125 }
126
127 /// Returns the textual content of a doc comment block as a single string.
128 /// That is, strips leading `///` (+ optional 1 character of whitespace)
129 /// and joins lines.
130 fn doc_comment_text(&self) -> Option<std::string::String> {
131 let docs = self
132 .doc_comments()
133 .filter(|comment| comment.is_doc_comment())
134 .map(|comment| {
135 let prefix_len = comment.prefix().len();
136
137 let line = comment.text().as_str();
138
139 // Determine if the prefix or prefix + 1 char is stripped
140 let pos =
141 if line.chars().nth(prefix_len).map(|c| c.is_whitespace()).unwrap_or(false) {
142 prefix_len + 1
143 } else {
144 prefix_len
145 };
146
147 line[pos..].to_owned()
148 })
149 .join("\n");
150
151 if docs.is_empty() {
152 None
153 } else {
154 Some(docs)
155 }
156 }
157}
158
159impl Attr { 33impl Attr {
160 pub fn is_inner(&self) -> bool { 34 pub fn is_inner(&self) -> bool {
161 let tt = match self.value() { 35 let tt = match self.value() {
@@ -245,17 +119,6 @@ impl<'a> Comment<'a> {
245 } 119 }
246} 120}
247 121
248pub struct CommentIter<'a> {
249 iter: SyntaxElementChildren<'a>,
250}
251
252impl<'a> Iterator for CommentIter<'a> {
253 type Item = Comment<'a>;
254 fn next(&mut self) -> Option<Comment<'a>> {
255 self.iter.by_ref().find_map(|el| el.as_token().and_then(Comment::cast))
256 }
257}
258
259#[derive(Debug, PartialEq, Eq)] 122#[derive(Debug, PartialEq, Eq)]
260pub enum CommentFlavor { 123pub enum CommentFlavor {
261 Line, 124 Line,