diff options
Diffstat (limited to 'crates/libsyntax2/src/yellow/syntax.rs')
-rw-r--r-- | crates/libsyntax2/src/yellow/syntax.rs | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/crates/libsyntax2/src/yellow/syntax.rs b/crates/libsyntax2/src/yellow/syntax.rs new file mode 100644 index 000000000..6e33310f1 --- /dev/null +++ b/crates/libsyntax2/src/yellow/syntax.rs | |||
@@ -0,0 +1,122 @@ | |||
1 | use std::{fmt, sync::Arc}; | ||
2 | |||
3 | use { | ||
4 | yellow::{RedNode, TreeRoot, SyntaxRoot, RedPtr}, | ||
5 | SyntaxKind::{self, *}, | ||
6 | TextRange, TextUnit, | ||
7 | }; | ||
8 | |||
9 | |||
10 | #[derive(Clone, Copy)] | ||
11 | pub struct SyntaxNode<R: TreeRoot = Arc<SyntaxRoot>> { | ||
12 | pub(crate) root: R, | ||
13 | // Guaranteed to not dangle, because `root` holds a | ||
14 | // strong reference to red's ancestor | ||
15 | red: RedPtr, | ||
16 | } | ||
17 | |||
18 | unsafe impl<R: TreeRoot> Send for SyntaxNode<R> {} | ||
19 | unsafe impl<R: TreeRoot> Sync for SyntaxNode<R> {} | ||
20 | |||
21 | impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> { | ||
22 | fn eq(&self, other: &SyntaxNode<R1>) -> bool { | ||
23 | self.red == other.red | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl<R: TreeRoot> Eq for SyntaxNode<R> {} | ||
28 | |||
29 | pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>; | ||
30 | |||
31 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
32 | pub struct SyntaxError { | ||
33 | pub msg: String, | ||
34 | pub offset: TextUnit, | ||
35 | } | ||
36 | |||
37 | impl SyntaxNode<Arc<SyntaxRoot>> { | ||
38 | pub(crate) fn new_owned(root: SyntaxRoot) -> Self { | ||
39 | let root = Arc::new(root); | ||
40 | let red = RedPtr::new(&root.red); | ||
41 | SyntaxNode { root, red } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | impl<R: TreeRoot> SyntaxNode<R> { | ||
46 | pub fn as_ref<'a>(&'a self) -> SyntaxNode<&'a SyntaxRoot> { | ||
47 | SyntaxNode { | ||
48 | root: &*self.root, | ||
49 | red: self.red, | ||
50 | } | ||
51 | } | ||
52 | |||
53 | pub fn kind(&self) -> SyntaxKind { | ||
54 | self.red().green().kind() | ||
55 | } | ||
56 | |||
57 | pub fn range(&self) -> TextRange { | ||
58 | let red = self.red(); | ||
59 | TextRange::offset_len(red.start_offset(), red.green().text_len()) | ||
60 | } | ||
61 | |||
62 | pub fn text(&self) -> String { | ||
63 | self.red().green().text() | ||
64 | } | ||
65 | |||
66 | pub fn children<'a>(&'a self) -> impl Iterator<Item = SyntaxNode<R>> + 'a { | ||
67 | let red = self.red(); | ||
68 | let n_children = red.n_children(); | ||
69 | (0..n_children).map(move |i| SyntaxNode { | ||
70 | root: self.root.clone(), | ||
71 | red: red.get_child(i).unwrap(), | ||
72 | }) | ||
73 | } | ||
74 | |||
75 | pub fn parent(&self) -> Option<SyntaxNode<R>> { | ||
76 | let parent = self.red().parent()?; | ||
77 | Some(SyntaxNode { | ||
78 | root: self.root.clone(), | ||
79 | red: parent, | ||
80 | }) | ||
81 | } | ||
82 | |||
83 | pub fn first_child(&self) -> Option<SyntaxNode<R>> { | ||
84 | self.children().next() | ||
85 | } | ||
86 | |||
87 | pub fn next_sibling(&self) -> Option<SyntaxNode<R>> { | ||
88 | let red = self.red(); | ||
89 | let parent = self.parent()?; | ||
90 | let next_sibling_idx = red.index_in_parent()? + 1; | ||
91 | let sibling_red = parent.red().get_child(next_sibling_idx)?; | ||
92 | Some(SyntaxNode { | ||
93 | root: self.root.clone(), | ||
94 | red: sibling_red, | ||
95 | }) | ||
96 | } | ||
97 | |||
98 | pub fn is_leaf(&self) -> bool { | ||
99 | self.first_child().is_none() | ||
100 | } | ||
101 | |||
102 | fn red(&self) -> &RedNode { | ||
103 | unsafe { self.red.get(&self.root) } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | impl<R: TreeRoot> fmt::Debug for SyntaxNode<R> { | ||
108 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
109 | write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; | ||
110 | if has_short_text(self.kind()) { | ||
111 | write!(fmt, " \"{}\"", self.text())?; | ||
112 | } | ||
113 | Ok(()) | ||
114 | } | ||
115 | } | ||
116 | |||
117 | fn has_short_text(kind: SyntaxKind) -> bool { | ||
118 | match kind { | ||
119 | IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true, | ||
120 | _ => false, | ||
121 | } | ||
122 | } | ||