1use super::traversal::{DescendantToken, DescendantTokens};
2use crate::{
3 AmberToken, GreenNode, NodeOrToken, SyntaxKind, SyntaxKindMatch, SyntaxNode, SyntaxNodePtr, green::GreenChild,
4};
5use text_size::{TextRange, TextSize};
6
7#[derive(Clone, Copy, PartialEq, Eq, Hash)]
8pub struct AmberNode<'a> {
14 green: &'a GreenNode,
15 range: TextRange,
16}
17
18impl<'a> AmberNode<'a> {
19 #[inline]
20 pub fn new_root(green: &'a GreenNode) -> Self {
22 Self {
23 green,
24 range: TextRange::new(0.into(), green.text_len()),
25 }
26 }
27
28 #[inline]
29 pub fn new(green: &'a GreenNode, start: TextSize) -> Self {
33 Self {
34 green,
35 range: TextRange::new(start, start + green.text_len()),
36 }
37 }
38
39 #[inline]
40 pub fn kind(&self) -> SyntaxKind {
42 self.green.kind()
43 }
44
45 #[inline]
46 pub fn text_range(&self) -> TextRange {
48 self.range
49 }
50
51 #[inline]
52 pub fn green(&self) -> &'a GreenNode {
54 self.green
55 }
56
57 #[inline]
58 pub fn to_ptr(&self) -> SyntaxNodePtr {
60 SyntaxNodePtr {
61 kind: self.green.kind(),
62 range: self.range,
63 }
64 }
65
66 #[inline]
67 pub fn children(&self) -> impl DoubleEndedIterator<Item = AmberNode<'a>> + Clone {
71 self.green.slice().iter().filter_map(|child| match child {
72 GreenChild::Node { offset, node } => Some(AmberNode::new(node, self.range.start() + offset)),
73 GreenChild::Token { .. } => None,
74 })
75 }
76
77 #[inline]
78 pub fn children_by_kind<M>(&self, matcher: M) -> impl DoubleEndedIterator<Item = AmberNode<'a>> + use<'_, 'a, M>
80 where
81 M: SyntaxKindMatch,
82 {
83 self.green().slice().iter().filter_map(move |child| match child {
84 GreenChild::Node { offset, node } if matcher.matches(node.kind()) => {
85 Some(AmberNode::new(node, self.range.start() + offset))
86 }
87 _ => None,
88 })
89 }
90
91 #[inline]
92 pub fn tokens_by_kind<M>(&self, matcher: M) -> impl DoubleEndedIterator<Item = AmberToken<'a>> + use<'_, 'a, M>
94 where
95 M: SyntaxKindMatch,
96 {
97 self.green().slice().iter().filter_map(move |child| match child {
98 GreenChild::Token { offset, token } if matcher.matches(token.kind()) => {
99 Some(AmberToken::new(token, self.range.start() + offset))
100 }
101 _ => None,
102 })
103 }
104
105 #[inline]
106 pub fn children_with_tokens(&self) -> impl DoubleEndedIterator<Item = NodeOrToken<AmberNode<'a>, AmberToken<'a>>> {
108 self.green.slice().iter().map(|child| match child {
109 GreenChild::Node { offset, node } => AmberNode::new(node, self.range.start() + offset).into(),
110 GreenChild::Token { offset, token } => AmberToken::new(token, self.range.start() + offset).into(),
111 })
112 }
113
114 #[inline]
115 pub fn descendant_tokens(&self) -> impl Iterator<Item = DescendantToken<'a>> + 'a {
122 DescendantTokens::new(*self)
123 }
124
125 #[inline]
126 pub(crate) fn child_or_token_at(&self, index: usize) -> Option<NodeOrToken<AmberNode<'a>, AmberToken<'a>>> {
127 self.green().slice().get(index).map(|child| match child {
128 GreenChild::Node { offset, node } => AmberNode::new(node, self.range.start() + offset).into(),
129 GreenChild::Token { offset, token } => AmberToken::new(token, self.range.start() + offset).into(),
130 })
131 }
132}
133
134impl<'a> From<&'a SyntaxNode> for AmberNode<'a> {
135 #[inline]
136 fn from(node: &'a SyntaxNode) -> Self {
137 Self {
138 green: node.green(),
139 range: node.text_range(),
140 }
141 }
142}