diff options
Diffstat (limited to 'crates/ra_syntax/src/yellow/syntax.rs')
-rw-r--r-- | crates/ra_syntax/src/yellow/syntax.rs | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/yellow/syntax.rs b/crates/ra_syntax/src/yellow/syntax.rs new file mode 100644 index 000000000..1d99cab4a --- /dev/null +++ b/crates/ra_syntax/src/yellow/syntax.rs | |||
@@ -0,0 +1,215 @@ | |||
1 | use std::{ | ||
2 | fmt, sync::Arc, | ||
3 | hash::{Hasher, Hash}, | ||
4 | ops::Range, | ||
5 | }; | ||
6 | |||
7 | use smol_str::SmolStr; | ||
8 | |||
9 | use { | ||
10 | yellow::{GreenNode, RedNode, TreeRoot, SyntaxRoot, RedPtr, RefRoot, OwnedRoot, SyntaxText}, | ||
11 | SyntaxKind::{self, *}, | ||
12 | TextRange, TextUnit, | ||
13 | }; | ||
14 | |||
15 | |||
16 | #[derive(Clone, Copy)] | ||
17 | pub struct SyntaxNode<R: TreeRoot = OwnedRoot> { | ||
18 | pub(crate) root: R, | ||
19 | // Guaranteed to not dangle, because `root` holds a | ||
20 | // strong reference to red's ancestor | ||
21 | red: RedPtr, | ||
22 | } | ||
23 | |||
24 | unsafe impl<R: TreeRoot> Send for SyntaxNode<R> {} | ||
25 | unsafe impl<R: TreeRoot> Sync for SyntaxNode<R> {} | ||
26 | |||
27 | impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> { | ||
28 | fn eq(&self, other: &SyntaxNode<R1>) -> bool { | ||
29 | self.red == other.red | ||
30 | } | ||
31 | } | ||
32 | |||
33 | impl<R: TreeRoot> Eq for SyntaxNode<R> {} | ||
34 | impl<R: TreeRoot> Hash for SyntaxNode<R> { | ||
35 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
36 | self.red.hash(state) | ||
37 | } | ||
38 | } | ||
39 | |||
40 | pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>; | ||
41 | |||
42 | #[test] | ||
43 | fn syntax_node_ref_is_copy() { | ||
44 | fn assert_copy<T: Copy>(){} | ||
45 | assert_copy::<SyntaxNodeRef>() | ||
46 | } | ||
47 | |||
48 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
49 | pub struct SyntaxError { | ||
50 | pub msg: String, | ||
51 | pub offset: TextUnit, | ||
52 | } | ||
53 | |||
54 | impl SyntaxNode<OwnedRoot> { | ||
55 | pub(crate) fn new_owned(root: SyntaxRoot) -> Self { | ||
56 | let root = OwnedRoot(Arc::new(root)); | ||
57 | let red = RedPtr::new(&root.syntax_root().red); | ||
58 | SyntaxNode { root, red } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | impl<'a> SyntaxNode<RefRoot<'a>> { | ||
63 | pub(crate) fn leaf_text_ref(self) -> Option<&'a SmolStr> { | ||
64 | let red = unsafe { self.red.get(self.root.syntax_root()) }; | ||
65 | red.green().leaf_text_ref() | ||
66 | } | ||
67 | } | ||
68 | |||
69 | impl<R: TreeRoot> SyntaxNode<R> { | ||
70 | pub fn borrowed<'a>(&'a self) -> SyntaxNodeRef<'a> { | ||
71 | SyntaxNode { | ||
72 | root: self.root.borrowed(), | ||
73 | red: self.red, | ||
74 | } | ||
75 | } | ||
76 | |||
77 | pub fn owned(&self) -> SyntaxNode { | ||
78 | SyntaxNode { | ||
79 | root: self.root.owned(), | ||
80 | red: self.red, | ||
81 | } | ||
82 | } | ||
83 | |||
84 | pub fn kind(&self) -> SyntaxKind { | ||
85 | self.red().green().kind() | ||
86 | } | ||
87 | |||
88 | pub fn range(&self) -> TextRange { | ||
89 | let red = self.red(); | ||
90 | TextRange::offset_len(red.start_offset(), red.green().text_len()) | ||
91 | } | ||
92 | |||
93 | pub fn text(&self) -> SyntaxText { | ||
94 | SyntaxText::new(self.borrowed()) | ||
95 | } | ||
96 | |||
97 | pub fn children(&self) -> SyntaxNodeChildren<R> { | ||
98 | SyntaxNodeChildren { | ||
99 | parent: self.clone(), | ||
100 | iter: (0..self.red().n_children()) | ||
101 | } | ||
102 | } | ||
103 | |||
104 | pub fn parent(&self) -> Option<SyntaxNode<R>> { | ||
105 | let parent = self.red().parent()?; | ||
106 | Some(SyntaxNode { | ||
107 | root: self.root.clone(), | ||
108 | red: parent, | ||
109 | }) | ||
110 | } | ||
111 | |||
112 | pub fn first_child(&self) -> Option<SyntaxNode<R>> { | ||
113 | let red = self.red().get_child(0)?; | ||
114 | Some(SyntaxNode { root: self.root.clone(), red }) | ||
115 | } | ||
116 | |||
117 | pub fn last_child(&self) -> Option<SyntaxNode<R>> { | ||
118 | let n = self.red().n_children(); | ||
119 | let n = n.checked_sub(1)?; | ||
120 | let red = self.red().get_child(n)?; | ||
121 | Some(SyntaxNode { root: self.root.clone(), red }) | ||
122 | } | ||
123 | |||
124 | pub fn next_sibling(&self) -> Option<SyntaxNode<R>> { | ||
125 | let red = self.red(); | ||
126 | let parent = self.parent()?; | ||
127 | let next_sibling_idx = red.index_in_parent()? + 1; | ||
128 | let sibling_red = parent.red().get_child(next_sibling_idx)?; | ||
129 | Some(SyntaxNode { | ||
130 | root: self.root.clone(), | ||
131 | red: sibling_red, | ||
132 | }) | ||
133 | } | ||
134 | |||
135 | pub fn prev_sibling(&self) -> Option<SyntaxNode<R>> { | ||
136 | let red = self.red(); | ||
137 | let parent = self.parent()?; | ||
138 | let prev_sibling_idx = red.index_in_parent()?.checked_sub(1)?; | ||
139 | let sibling_red = parent.red().get_child(prev_sibling_idx)?; | ||
140 | Some(SyntaxNode { | ||
141 | root: self.root.clone(), | ||
142 | red: sibling_red, | ||
143 | }) | ||
144 | } | ||
145 | |||
146 | pub fn is_leaf(&self) -> bool { | ||
147 | self.first_child().is_none() | ||
148 | } | ||
149 | |||
150 | pub fn leaf_text(&self) -> Option<SmolStr> { | ||
151 | self.borrowed().leaf_text_ref().map(|it| it.clone()) | ||
152 | } | ||
153 | |||
154 | pub(crate) fn replace_with(&self, green: GreenNode) -> GreenNode { | ||
155 | assert_eq!(self.kind(), green.kind()); | ||
156 | match self.parent() { | ||
157 | None => green, | ||
158 | Some(parent) => { | ||
159 | let children: Vec<_> = parent.children().map(|child| { | ||
160 | if child == *self { | ||
161 | green.clone() | ||
162 | } else { | ||
163 | child.red().green().clone() | ||
164 | } | ||
165 | }).collect(); | ||
166 | let new_parent = GreenNode::new_branch( | ||
167 | parent.kind(), | ||
168 | children.into_boxed_slice(), | ||
169 | ); | ||
170 | parent.replace_with(new_parent) | ||
171 | }, | ||
172 | } | ||
173 | } | ||
174 | |||
175 | fn red(&self) -> &RedNode { | ||
176 | unsafe { self.red.get(self.root.syntax_root()) } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | impl<R: TreeRoot> fmt::Debug for SyntaxNode<R> { | ||
181 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
182 | write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; | ||
183 | if has_short_text(self.kind()) { | ||
184 | write!(fmt, " \"{}\"", self.text())?; | ||
185 | } | ||
186 | Ok(()) | ||
187 | } | ||
188 | } | ||
189 | |||
190 | #[derive(Debug)] | ||
191 | pub struct SyntaxNodeChildren<R: TreeRoot> { | ||
192 | parent: SyntaxNode<R>, | ||
193 | iter: Range<usize>, | ||
194 | } | ||
195 | |||
196 | impl<R: TreeRoot> Iterator for SyntaxNodeChildren<R> { | ||
197 | type Item = SyntaxNode<R>; | ||
198 | |||
199 | fn next(&mut self) -> Option<SyntaxNode<R>> { | ||
200 | self.iter.next().map(|i| { | ||
201 | let red = self.parent.red(); | ||
202 | SyntaxNode { | ||
203 | root: self.parent.root.clone(), | ||
204 | red: red.get_child(i).unwrap(), | ||
205 | } | ||
206 | }) | ||
207 | } | ||
208 | } | ||
209 | |||
210 | fn has_short_text(kind: SyntaxKind) -> bool { | ||
211 | match kind { | ||
212 | IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true, | ||
213 | _ => false, | ||
214 | } | ||
215 | } | ||