1use std::marker::PhantomData;
2
3use rowan::TextRange;
4
5use crate::{SyntaxKind, SyntaxNode};
6
7use super::AstNode;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub struct SyntaxNodePtr {
17 kind: SyntaxKind,
18 range: TextRange,
19}
20
21impl SyntaxNodePtr {
22 #[doc(hidden)]
24 pub fn from_range(range: TextRange) -> Self {
25 Self {
26 kind: SyntaxKind::ERROR,
27 range,
28 }
29 }
30
31 pub fn from_node(node: &SyntaxNode) -> Self {
33 Self {
34 kind: node.kind(),
35 range: node.text_range(),
36 }
37 }
38
39 pub fn text_range(&self) -> TextRange {
41 self.range
42 }
43
44 pub fn syntax_kind(&self) -> SyntaxKind {
46 self.kind
47 }
48
49 pub fn resolve(&self, root: &SyntaxNode) -> Option<SyntaxNode> {
51 let mut node = root.covering_element(self.range);
52 loop {
53 match &node {
54 rowan::NodeOrToken::Node(n) => {
55 if n.text_range() == self.range && n.kind() == self.kind {
56 return Some(n.clone());
57 }
58 if n.text_range().start() < self.range.start() {
59 return None;
60 }
61 {
62 let parent = n.parent()?;
63 node = rowan::NodeOrToken::Node(parent);
64 }
65 }
66 rowan::NodeOrToken::Token(t) => {
67 let parent = t.parent()?;
68 node = rowan::NodeOrToken::Node(parent);
69 }
70 }
71 }
72 }
73}
74
75impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {
76 fn from(ptr: AstPtr<N>) -> Self {
77 Self {
78 kind: ptr.syntax_kind(),
79 range: ptr.text_range(),
80 }
81 }
82}
83
84pub struct AstPtr<N: AstNode> {
93 kind: SyntaxKind,
94 range: TextRange,
95 _phantom: PhantomData<fn() -> N>,
96}
97
98impl<N: AstNode> Clone for AstPtr<N> {
102 fn clone(&self) -> Self {
103 *self
104 }
105}
106
107impl<N: AstNode> PartialEq for AstPtr<N> {
108 fn eq(&self, other: &Self) -> bool {
109 self.kind == other.kind && self.range == other.range
110 }
111}
112
113impl<N: AstNode> Eq for AstPtr<N> {}
114
115impl<N: AstNode> std::hash::Hash for AstPtr<N> {
116 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
117 self.kind.hash(state);
118 self.range.hash(state);
119 }
120}
121
122impl<N: AstNode> AstPtr<N> {
123 #[doc(hidden)]
125 pub fn from_range(range: TextRange) -> Self {
126 Self {
127 kind: SyntaxKind::ERROR,
128 range,
129 _phantom: PhantomData,
130 }
131 }
132
133 pub fn new(node: &N) -> Self {
135 let syntax = node.syntax();
136 Self {
137 kind: syntax.kind(),
138 range: syntax.text_range(),
139 _phantom: PhantomData,
140 }
141 }
142
143 pub fn text_range(&self) -> TextRange {
145 self.range
146 }
147
148 pub fn syntax_kind(&self) -> SyntaxKind {
150 self.kind
151 }
152
153 pub fn resolve(&self, root: &SyntaxNode) -> Option<N> {
159 self.resolve_syntax(root).and_then(N::cast)
162 }
163
164 fn resolve_syntax(&self, root: &SyntaxNode) -> Option<SyntaxNode> {
165 let mut node = root.covering_element(self.range);
167
168 loop {
170 match &node {
171 rowan::NodeOrToken::Node(n) => {
172 if n.text_range() == self.range && n.kind() == self.kind {
173 return Some(n.clone());
174 }
175 if n.text_range().start() < self.range.start() {
177 return None;
178 }
179 {
180 let parent = n.parent()?;
181 node = rowan::NodeOrToken::Node(parent);
182 }
183 }
184 rowan::NodeOrToken::Token(t) => {
185 let parent = t.parent()?;
186 node = rowan::NodeOrToken::Node(parent);
187 }
188 }
189 }
190 }
191}
192
193impl<N: AstNode> std::fmt::Debug for AstPtr<N> {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 f.debug_struct("AstPtr")
196 .field("kind", &self.kind)
197 .field("range", &self.range)
198 .finish()
199 }
200}
201
202impl<N: AstNode> Copy for AstPtr<N> {}