biome_rowan/cursor/
node.rs

1use crate::cursor::{NodeData, SyntaxElement, SyntaxToken, SyntaxTrivia};
2use crate::green::{Child, Children, GreenElementRef, Slot};
3use crate::{
4    Direction, GreenNode, GreenNodeData, NodeOrToken, RawSyntaxKind, SyntaxNodeText, TokenAtOffset,
5    WalkEvent,
6};
7use biome_text_size::{TextRange, TextSize};
8use std::hash::{Hash, Hasher};
9use std::iter::FusedIterator;
10use std::ops;
11use std::ptr::NonNull;
12use std::rc::Rc;
13use std::{fmt, iter};
14
15use super::{GreenElement, NodeKind, WeakGreenElement};
16
17#[derive(Clone)]
18pub(crate) struct SyntaxNode {
19    pub(super) ptr: Rc<NodeData>,
20}
21
22impl SyntaxNode {
23    pub(crate) fn new_root(green: GreenNode) -> SyntaxNode {
24        SyntaxNode {
25            ptr: NodeData::new(
26                NodeKind::Root {
27                    green: GreenElement::Node(green),
28                },
29                0,
30                0.into(),
31            ),
32        }
33    }
34
35    pub(super) fn new_child(
36        green: &GreenNodeData,
37        parent: SyntaxNode,
38        slot: u32,
39        offset: TextSize,
40    ) -> SyntaxNode {
41        SyntaxNode {
42            ptr: NodeData::new(
43                NodeKind::Child {
44                    green: WeakGreenElement::new(GreenElementRef::Node(green)),
45                    parent: parent.ptr,
46                },
47                slot,
48                offset,
49            ),
50        }
51    }
52
53    pub fn clone_subtree(&self) -> SyntaxNode {
54        SyntaxNode::new_root(self.green().into())
55    }
56
57    #[inline]
58    pub(super) fn data(&self) -> &NodeData {
59        self.ptr.as_ref()
60    }
61
62    #[inline]
63    pub fn kind(&self) -> RawSyntaxKind {
64        self.data().kind()
65    }
66
67    #[inline]
68    pub(super) fn offset(&self) -> TextSize {
69        self.data().offset()
70    }
71
72    pub(crate) fn element_in_slot(&self, slot_index: u32) -> Option<SyntaxElement> {
73        let slot = self
74            .slots()
75            .nth(slot_index as usize)
76            .expect("Slot index out of bounds");
77
78        slot.map(|element| element)
79    }
80
81    #[inline]
82    pub(crate) fn slots(&self) -> SyntaxSlots {
83        SyntaxSlots::new(self.clone())
84    }
85
86    #[inline]
87    pub fn text_range(&self) -> TextRange {
88        self.data().text_range()
89    }
90
91    pub fn text_trimmed_range(&self) -> TextRange {
92        let range = self.text_range();
93        let mut start = range.start();
94        let mut end = range.end();
95
96        // Remove all trivia from the start of the node
97        let mut token = self.first_token();
98        while let Some(t) = token.take() {
99            let (leading_len, trailing_len, total_len) = t.green().leading_trailing_total_len();
100            let token_len: u32 = (total_len - leading_len - trailing_len).into();
101            if token_len == 0 {
102                start += total_len;
103                token = t.next_token();
104            } else {
105                start += leading_len;
106            }
107        }
108
109        // Remove all trivia from the end of the node
110        let mut token = self.last_token();
111        while let Some(t) = token.take() {
112            let (leading_len, trailing_len, total_len) = t.green().leading_trailing_total_len();
113            let token_len: u32 = (total_len - leading_len - trailing_len).into();
114            if token_len == 0 {
115                end -= total_len;
116                token = t.prev_token();
117            } else {
118                end -= trailing_len;
119            }
120        }
121
122        TextRange::new(start, end.max(start))
123    }
124
125    pub fn first_leading_trivia(&self) -> Option<SyntaxTrivia> {
126        self.first_token().map(|x| x.leading_trivia())
127    }
128
129    pub fn last_trailing_trivia(&self) -> Option<SyntaxTrivia> {
130        self.last_token().map(|x| x.trailing_trivia())
131    }
132
133    #[inline]
134    pub fn index(&self) -> usize {
135        self.data().slot() as usize
136    }
137
138    #[inline]
139    pub fn text(&self) -> SyntaxNodeText {
140        SyntaxNodeText::new(self.clone())
141    }
142
143    #[inline]
144    pub fn text_trimmed(&self) -> SyntaxNodeText {
145        SyntaxNodeText::with_range(self.clone(), self.text_trimmed_range())
146    }
147
148    #[inline]
149    pub(crate) fn key(&self) -> (NonNull<()>, TextSize) {
150        self.data().key()
151    }
152
153    #[inline]
154    pub(crate) fn green(&self) -> &GreenNodeData {
155        self.data().green().into_node().unwrap()
156    }
157
158    #[inline]
159    pub fn parent(&self) -> Option<SyntaxNode> {
160        self.data().parent_node()
161    }
162
163    #[inline]
164    pub fn ancestors(&self) -> impl Iterator<Item = SyntaxNode> {
165        iter::successors(Some(self.clone()), SyntaxNode::parent)
166    }
167
168    #[inline]
169    pub fn children(&self) -> SyntaxNodeChildren {
170        SyntaxNodeChildren::new(self.clone())
171    }
172
173    #[inline]
174    pub fn children_with_tokens(&self) -> SyntaxElementChildren {
175        SyntaxElementChildren::new(self.clone())
176    }
177
178    #[inline]
179    pub fn tokens(&self) -> impl DoubleEndedIterator<Item = SyntaxToken> + '_ {
180        self.green().children().filter_map(|child| {
181            child.element().into_token().map(|token| {
182                SyntaxToken::new(
183                    token,
184                    self.clone(),
185                    child.slot(),
186                    self.offset() + child.rel_offset(),
187                )
188            })
189        })
190    }
191
192    pub fn first_child(&self) -> Option<SyntaxNode> {
193        self.green().children().find_map(|child| {
194            child.element().into_node().map(|green| {
195                SyntaxNode::new_child(
196                    green,
197                    self.clone(),
198                    child.slot(),
199                    self.offset() + child.rel_offset(),
200                )
201            })
202        })
203    }
204
205    pub fn last_child(&self) -> Option<SyntaxNode> {
206        self.green().children().rev().find_map(|child| {
207            child.element().into_node().map(|green| {
208                SyntaxNode::new_child(
209                    green,
210                    self.clone(),
211                    child.slot(),
212                    self.offset() + child.rel_offset(),
213                )
214            })
215        })
216    }
217
218    pub fn first_child_or_token(&self) -> Option<SyntaxElement> {
219        self.green().children().next().map(|child| {
220            SyntaxElement::new(
221                child.element(),
222                self.clone(),
223                child.slot(),
224                self.offset() + child.rel_offset(),
225            )
226        })
227    }
228    pub fn last_child_or_token(&self) -> Option<SyntaxElement> {
229        self.green().children().next_back().map(|child| {
230            SyntaxElement::new(
231                child.element(),
232                self.clone(),
233                child.slot(),
234                self.offset() + child.rel_offset(),
235            )
236        })
237    }
238
239    pub fn next_sibling(&self) -> Option<SyntaxNode> {
240        self.data().next_sibling()
241    }
242    pub fn prev_sibling(&self) -> Option<SyntaxNode> {
243        self.data().prev_sibling()
244    }
245
246    pub fn next_sibling_or_token(&self) -> Option<SyntaxElement> {
247        self.data().next_sibling_or_token()
248    }
249    pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> {
250        self.data().prev_sibling_or_token()
251    }
252
253    pub fn first_token(&self) -> Option<SyntaxToken> {
254        self.descendants_with_tokens(Direction::Next)
255            .find_map(|x| x.into_token())
256    }
257
258    pub fn last_token(&self) -> Option<SyntaxToken> {
259        PreorderWithTokens::new(self.clone(), Direction::Prev)
260            .filter_map(|event| match event {
261                WalkEvent::Enter(it) => Some(it),
262                WalkEvent::Leave(_) => None,
263            })
264            .find_map(|x| x.into_token())
265    }
266
267    #[inline]
268    pub fn siblings(&self, direction: Direction) -> impl Iterator<Item = SyntaxNode> {
269        iter::successors(Some(self.clone()), move |node| match direction {
270            Direction::Next => node.next_sibling(),
271            Direction::Prev => node.prev_sibling(),
272        })
273    }
274
275    #[inline]
276    pub fn siblings_with_tokens(
277        &self,
278        direction: Direction,
279    ) -> impl Iterator<Item = SyntaxElement> {
280        let me: SyntaxElement = self.clone().into();
281        iter::successors(Some(me), move |el| match direction {
282            Direction::Next => el.next_sibling_or_token(),
283            Direction::Prev => el.prev_sibling_or_token(),
284        })
285    }
286
287    #[inline]
288    pub fn descendants(&self) -> impl Iterator<Item = SyntaxNode> {
289        self.preorder().filter_map(|event| match event {
290            WalkEvent::Enter(node) => Some(node),
291            WalkEvent::Leave(_) => None,
292        })
293    }
294
295    #[inline]
296    pub fn descendants_with_tokens(
297        &self,
298        direction: Direction,
299    ) -> impl Iterator<Item = SyntaxElement> {
300        self.preorder_with_tokens(direction)
301            .filter_map(|event| match event {
302                WalkEvent::Enter(it) => Some(it),
303                WalkEvent::Leave(_) => None,
304            })
305    }
306
307    #[inline]
308    pub fn preorder(&self) -> Preorder {
309        Preorder::new(self.clone())
310    }
311
312    #[inline]
313    pub fn preorder_with_tokens(&self, direction: Direction) -> PreorderWithTokens {
314        PreorderWithTokens::new(self.clone(), direction)
315    }
316
317    pub(crate) fn preorder_slots(&self) -> SlotsPreorder {
318        SlotsPreorder::new(self.clone())
319    }
320
321    pub fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> {
322        // TODO: this could be faster if we first drill-down to node, and only
323        // then switch to token search. We should also replace explicit
324        // recursion with a loop.
325        let range = self.text_range();
326        assert!(
327            range.start() <= offset && offset <= range.end(),
328            "Bad offset: range {range:?} offset {offset:?}"
329        );
330        if range.is_empty() {
331            return TokenAtOffset::None;
332        }
333
334        let mut children = self.children_with_tokens().filter(|child| {
335            let child_range = child.text_range();
336            !child_range.is_empty() && child_range.contains_inclusive(offset)
337        });
338
339        let left = children.next().unwrap();
340        let right = children.next();
341        assert!(children.next().is_none());
342
343        if let Some(right) = right {
344            match (left.token_at_offset(offset), right.token_at_offset(offset)) {
345                (TokenAtOffset::Single(left), TokenAtOffset::Single(right)) => {
346                    TokenAtOffset::Between(left, right)
347                }
348                _ => unreachable!(),
349            }
350        } else {
351            left.token_at_offset(offset)
352        }
353    }
354
355    pub fn covering_element(&self, range: TextRange) -> SyntaxElement {
356        let mut res: SyntaxElement = self.clone().into();
357        loop {
358            assert!(
359                res.text_range().contains_range(range),
360                "Bad range: node range {:?}, range {:?}",
361                res.text_range(),
362                range,
363            );
364            res = match &res {
365                NodeOrToken::Token(_) => return res,
366                NodeOrToken::Node(node) => match node.child_or_token_at_range(range) {
367                    Some(it) => it,
368                    None => return res,
369                },
370            };
371        }
372    }
373
374    pub fn child_or_token_at_range(&self, range: TextRange) -> Option<SyntaxElement> {
375        let rel_range = range - self.offset();
376        self.green()
377            .slot_at_range(rel_range)
378            .and_then(|(index, rel_offset, slot)| {
379                slot.as_ref().map(|green| {
380                    SyntaxElement::new(
381                        green,
382                        self.clone(),
383                        index as u32,
384                        self.offset() + rel_offset,
385                    )
386                })
387            })
388    }
389
390    #[must_use = "syntax elements are immutable, the result of update methods must be propagated to have any effect"]
391    pub fn detach(self) -> Self {
392        Self {
393            ptr: self.ptr.detach(),
394        }
395    }
396
397    #[must_use = "syntax elements are immutable, the result of update methods must be propagated to have any effect"]
398    pub fn splice_slots<R, I>(self, range: R, replace_with: I) -> Self
399    where
400        R: ops::RangeBounds<usize>,
401        I: Iterator<Item = Option<SyntaxElement>>,
402    {
403        Self {
404            ptr: self.ptr.splice_slots(
405                range,
406                replace_with.into_iter().map(|element| {
407                    element.map(|child| match child.detach() {
408                        NodeOrToken::Node(it) => it.ptr.into_green(),
409                        NodeOrToken::Token(it) => it.into_green(),
410                    })
411                }),
412            ),
413        }
414    }
415
416    #[must_use = "syntax elements are immutable, the result of update methods must be propagated to have any effect"]
417    pub fn replace_child(self, prev_elem: SyntaxElement, next_elem: SyntaxElement) -> Option<Self> {
418        Some(Self {
419            ptr: self.ptr.replace_child(prev_elem, next_elem)?,
420        })
421    }
422}
423
424// Identity semantics for hash & eq
425impl PartialEq for SyntaxNode {
426    #[inline]
427    fn eq(&self, other: &SyntaxNode) -> bool {
428        self.data().key() == other.data().key()
429    }
430}
431
432impl Eq for SyntaxNode {}
433
434impl Hash for SyntaxNode {
435    #[inline]
436    fn hash<H: Hasher>(&self, state: &mut H) {
437        self.data().key().hash(state);
438    }
439}
440
441impl fmt::Debug for SyntaxNode {
442    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443        f.debug_struct("SyntaxNode")
444            .field("kind", &self.kind())
445            .field("text_range", &self.text_range())
446            .finish()
447    }
448}
449
450impl fmt::Display for SyntaxNode {
451    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452        self.preorder_with_tokens(Direction::Next)
453            .filter_map(|event| match event {
454                WalkEvent::Enter(NodeOrToken::Token(token)) => Some(token),
455                _ => None,
456            })
457            .try_for_each(|it| fmt::Display::fmt(&it, f))
458    }
459}
460
461// region: iterators
462
463#[derive(Clone, Debug)]
464pub(crate) struct SyntaxNodeChildren {
465    next: Option<SyntaxNode>,
466}
467
468impl SyntaxNodeChildren {
469    fn new(parent: SyntaxNode) -> SyntaxNodeChildren {
470        SyntaxNodeChildren {
471            next: parent.first_child(),
472        }
473    }
474}
475
476impl Iterator for SyntaxNodeChildren {
477    type Item = SyntaxNode;
478    fn next(&mut self) -> Option<SyntaxNode> {
479        self.next.take().inspect(|next| {
480            self.next = next.next_sibling();
481        })
482    }
483}
484
485impl FusedIterator for SyntaxNodeChildren {}
486
487#[derive(Clone, Debug, Default)]
488pub(crate) struct SyntaxElementChildren {
489    next: Option<SyntaxElement>,
490}
491
492impl SyntaxElementChildren {
493    fn new(parent: SyntaxNode) -> SyntaxElementChildren {
494        SyntaxElementChildren {
495            next: parent.first_child_or_token(),
496        }
497    }
498}
499
500impl Iterator for SyntaxElementChildren {
501    type Item = SyntaxElement;
502    fn next(&mut self) -> Option<SyntaxElement> {
503        self.next.take().inspect(|next| {
504            self.next = next.next_sibling_or_token();
505        })
506    }
507}
508
509impl FusedIterator for SyntaxElementChildren {}
510
511pub(crate) struct Preorder {
512    start: SyntaxNode,
513    next: Option<WalkEvent<SyntaxNode>>,
514    skip_subtree: bool,
515}
516
517impl Preorder {
518    fn new(start: SyntaxNode) -> Preorder {
519        let next = Some(WalkEvent::Enter(start.clone()));
520        Preorder {
521            start,
522            next,
523            skip_subtree: false,
524        }
525    }
526
527    pub fn skip_subtree(&mut self) {
528        self.skip_subtree = true;
529    }
530
531    #[cold]
532    fn do_skip(&mut self) {
533        self.next = self.next.take().map(|next| match next {
534            WalkEvent::Enter(first_child) => WalkEvent::Leave(first_child.parent().unwrap()),
535            WalkEvent::Leave(parent) => WalkEvent::Leave(parent),
536        })
537    }
538}
539
540impl Iterator for Preorder {
541    type Item = WalkEvent<SyntaxNode>;
542
543    fn next(&mut self) -> Option<WalkEvent<SyntaxNode>> {
544        if self.skip_subtree {
545            self.do_skip();
546            self.skip_subtree = false;
547        }
548        let next = self.next.take();
549        self.next = next.as_ref().and_then(|next| {
550            Some(match next {
551                WalkEvent::Enter(node) => match node.first_child() {
552                    Some(child) => WalkEvent::Enter(child),
553                    None => WalkEvent::Leave(node.clone()),
554                },
555                WalkEvent::Leave(node) => {
556                    if node == &self.start {
557                        return None;
558                    }
559                    match node.next_sibling() {
560                        Some(sibling) => WalkEvent::Enter(sibling),
561                        None => WalkEvent::Leave(node.parent()?),
562                    }
563                }
564            })
565        });
566        next
567    }
568}
569
570impl FusedIterator for Preorder {}
571
572pub(crate) struct PreorderWithTokens {
573    start: SyntaxElement,
574    next: Option<WalkEvent<SyntaxElement>>,
575    skip_subtree: bool,
576    direction: Direction,
577}
578
579impl PreorderWithTokens {
580    fn new(start: SyntaxNode, direction: Direction) -> PreorderWithTokens {
581        let next = Some(WalkEvent::Enter(start.clone().into()));
582        PreorderWithTokens {
583            start: start.into(),
584            next,
585            direction,
586            skip_subtree: false,
587        }
588    }
589
590    pub fn skip_subtree(&mut self) {
591        self.skip_subtree = true;
592    }
593
594    #[cold]
595    fn do_skip(&mut self) {
596        self.next = self.next.take().map(|next| match next {
597            WalkEvent::Enter(first_child) => WalkEvent::Leave(first_child.parent().unwrap().into()),
598            WalkEvent::Leave(parent) => WalkEvent::Leave(parent),
599        })
600    }
601}
602
603impl Iterator for PreorderWithTokens {
604    type Item = WalkEvent<SyntaxElement>;
605
606    fn next(&mut self) -> Option<WalkEvent<SyntaxElement>> {
607        if self.skip_subtree {
608            self.do_skip();
609            self.skip_subtree = false;
610        }
611        let next = self.next.take();
612        self.next = next.as_ref().and_then(|next| {
613            Some(match next {
614                WalkEvent::Enter(el) => match el {
615                    NodeOrToken::Node(node) => {
616                        let next = match self.direction {
617                            Direction::Next => node.first_child_or_token(),
618                            Direction::Prev => node.last_child_or_token(),
619                        };
620                        match next {
621                            Some(child) => WalkEvent::Enter(child),
622                            None => WalkEvent::Leave(node.clone().into()),
623                        }
624                    }
625                    NodeOrToken::Token(token) => WalkEvent::Leave(token.clone().into()),
626                },
627                WalkEvent::Leave(el) if el == &self.start => return None,
628                WalkEvent::Leave(el) => {
629                    let next = match self.direction {
630                        Direction::Next => el.next_sibling_or_token(),
631                        Direction::Prev => el.prev_sibling_or_token(),
632                    };
633
634                    match next {
635                        Some(sibling) => WalkEvent::Enter(sibling),
636                        None => WalkEvent::Leave(el.parent()?.into()),
637                    }
638                }
639            })
640        });
641        next
642    }
643}
644
645impl FusedIterator for PreorderWithTokens {}
646
647/// Represents a cursor to a green node slot. A slot either contains an element or is empty
648/// if the child isn't present in the source.
649#[derive(Debug, Clone)]
650pub(crate) enum SyntaxSlot {
651    Node(SyntaxNode),
652    Token(SyntaxToken),
653    Empty { parent: SyntaxNode, index: u32 },
654}
655
656impl From<SyntaxElement> for SyntaxSlot {
657    fn from(element: SyntaxElement) -> Self {
658        match element {
659            SyntaxElement::Node(node) => SyntaxSlot::Node(node),
660            SyntaxElement::Token(token) => SyntaxSlot::Token(token),
661        }
662    }
663}
664
665impl SyntaxSlot {
666    #[inline]
667    pub fn map<F, R>(self, mapper: F) -> Option<R>
668    where
669        F: FnOnce(SyntaxElement) -> R,
670    {
671        match self {
672            SyntaxSlot::Node(node) => Some(mapper(SyntaxElement::Node(node))),
673            SyntaxSlot::Token(token) => Some(mapper(SyntaxElement::Token(token))),
674            SyntaxSlot::Empty { .. } => None,
675        }
676    }
677}
678
679/// Iterator over a node's slots
680#[derive(Debug, Clone)]
681pub(crate) struct SyntaxSlots {
682    /// Position of the next element to return.
683    pos: u32,
684
685    /// Position of the last returned element from the back.
686    /// Initially points one element past the last slot.
687    ///
688    /// [nth_back]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.nth_back
689    back_pos: u32,
690    parent: SyntaxNode,
691}
692
693impl SyntaxSlots {
694    #[inline]
695    fn new(parent: SyntaxNode) -> Self {
696        Self {
697            pos: 0,
698            back_pos: parent.green().slice().len() as u32,
699            parent,
700        }
701    }
702
703    /// Returns a slice containing the remaining elements to iterate over
704    /// an empty slice if the iterator reached the end.
705    #[inline]
706    fn slice(&self) -> &[Slot] {
707        if self.pos < self.back_pos {
708            &self.parent.green().slice()[self.pos as usize..self.back_pos as usize]
709        } else {
710            &[]
711        }
712    }
713
714    fn map_slot(&self, slot: &Slot, slot_index: u32) -> SyntaxSlot {
715        match slot {
716            Slot::Empty { .. } => SyntaxSlot::Empty {
717                parent: self.parent.clone(),
718                index: slot_index,
719            },
720            Slot::Token { rel_offset, token } => SyntaxSlot::Token(SyntaxToken::new(
721                token,
722                self.parent.clone(),
723                slot_index,
724                self.parent.offset() + rel_offset,
725            )),
726            Slot::Node { rel_offset, node } => SyntaxSlot::Node(SyntaxNode::new_child(
727                node,
728                self.parent.clone(),
729                slot_index,
730                self.parent.offset() + rel_offset,
731            )),
732        }
733    }
734}
735
736impl Iterator for SyntaxSlots {
737    type Item = SyntaxSlot;
738
739    #[inline]
740    fn next(&mut self) -> Option<Self::Item> {
741        let slot = self.slice().first()?;
742        let mapped = self.map_slot(slot, self.pos);
743        self.pos += 1;
744        Some(mapped)
745    }
746
747    #[inline(always)]
748    fn size_hint(&self) -> (usize, Option<usize>) {
749        let len = self.slice().len();
750        (len, Some(len))
751    }
752
753    #[inline(always)]
754    fn count(self) -> usize
755    where
756        Self: Sized,
757    {
758        self.len()
759    }
760
761    #[inline]
762    fn last(mut self) -> Option<Self::Item>
763    where
764        Self: Sized,
765    {
766        self.next_back()
767    }
768
769    #[inline]
770    fn nth(&mut self, n: usize) -> Option<Self::Item> {
771        self.pos += n as u32;
772        self.next()
773    }
774}
775
776impl ExactSizeIterator for SyntaxSlots {
777    #[inline(always)]
778    fn len(&self) -> usize {
779        self.slice().len()
780    }
781}
782
783impl FusedIterator for SyntaxSlots {}
784
785impl DoubleEndedIterator for SyntaxSlots {
786    #[inline]
787    fn next_back(&mut self) -> Option<Self::Item> {
788        let slot = self.slice().last()?;
789        let mapped = self.map_slot(slot, self.back_pos - 1);
790        self.back_pos -= 1;
791        Some(mapped)
792    }
793
794    #[inline]
795    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
796        self.back_pos -= n as u32;
797        self.next_back()
798    }
799}
800
801/// Iterator to visit a node's slots in pre-order.
802pub(crate) struct SlotsPreorder {
803    start: SyntaxNode,
804    next: Option<WalkEvent<SyntaxSlot>>,
805}
806
807impl SlotsPreorder {
808    fn new(start: SyntaxNode) -> Self {
809        let next = Some(WalkEvent::Enter(SyntaxSlot::Node(start.clone())));
810        SlotsPreorder { start, next }
811    }
812}
813
814impl Iterator for SlotsPreorder {
815    type Item = WalkEvent<SyntaxSlot>;
816
817    fn next(&mut self) -> Option<WalkEvent<SyntaxSlot>> {
818        let next = self.next.take();
819        self.next = next.as_ref().and_then(|next| {
820            Some(match next {
821                WalkEvent::Enter(slot) => match slot {
822                    SyntaxSlot::Empty { .. } | SyntaxSlot::Token(_) => {
823                        WalkEvent::Leave(slot.clone())
824                    }
825                    SyntaxSlot::Node(node) => match node.slots().next() {
826                        None => WalkEvent::Leave(SyntaxSlot::Node(node.clone())),
827                        Some(first_slot) => WalkEvent::Enter(first_slot),
828                    },
829                },
830                WalkEvent::Leave(slot) => {
831                    let (parent, slot_index) = match slot {
832                        SyntaxSlot::Empty { parent, index } => (parent.clone(), *index as usize),
833                        SyntaxSlot::Token(token) => (token.parent()?, token.index()),
834                        SyntaxSlot::Node(node) => {
835                            if node == &self.start {
836                                return None;
837                            }
838
839                            (node.parent()?, node.index())
840                        }
841                    };
842
843                    let next_slot = parent.slots().nth(slot_index + 1);
844                    match next_slot {
845                        Some(slot) => WalkEvent::Enter(slot),
846                        None => WalkEvent::Leave(SyntaxSlot::Node(parent)),
847                    }
848                }
849            })
850        });
851        next
852    }
853}
854
855impl FusedIterator for SlotsPreorder {}
856
857#[derive(Debug, Clone)]
858pub(crate) struct Siblings<'a> {
859    parent: &'a GreenNodeData,
860    start_slot: u32,
861}
862
863impl<'a> Siblings<'a> {
864    pub fn new(parent: &'a GreenNodeData, start_slot: u32) -> Self {
865        assert!(
866            (start_slot as usize) < parent.slots().len(),
867            "Start slot {} out of bounds {}",
868            start_slot,
869            parent.slots().len()
870        );
871
872        Self { parent, start_slot }
873    }
874
875    /// Creates an iterator over the siblings following the start node.
876    /// For example, the following siblings of the if statement's condition are
877    /// * the consequence
878    /// * potentially the else clause
879    pub fn following(&self) -> Children<'a> {
880        let mut slots = self.parent.slots().enumerate();
881
882        // Navigate to the start slot so that calling `next` returns the first following sibling
883        slots.nth(self.start_slot as usize);
884
885        Children::new(slots)
886    }
887
888    /// Creates an iterator over the siblings preceding the start node in reverse order.
889    /// For example, the preceding siblings of the if statement's condition are:
890    /// * opening parentheses: (
891    /// * if keyword: if
892    pub fn previous(&self) -> impl Iterator<Item = Child<'a>> {
893        let mut slots = self.parent.slots().enumerate();
894
895        // Navigate to the start slot from the back so that calling `next_back` (or rev().next()) returns
896        // the first slot preceding the start node
897        slots.nth_back(slots.len() - 1 - self.start_slot as usize);
898
899        Children::new(slots).rev()
900    }
901}
902
903// endregion
904
905#[cfg(test)]
906mod tests {
907    use crate::raw_language::{RawLanguageKind, RawSyntaxTreeBuilder};
908
909    #[test]
910    fn slots_iter() {
911        let mut builder = RawSyntaxTreeBuilder::new();
912        builder.start_node(RawLanguageKind::EXPRESSION_LIST);
913
914        for number in [1, 2, 3, 4] {
915            builder.start_node(RawLanguageKind::LITERAL_EXPRESSION);
916            builder.token(RawLanguageKind::NUMBER_TOKEN, &number.to_string());
917            builder.finish_node();
918        }
919        builder.finish_node();
920
921        let list = builder.finish();
922
923        let mut iter = list.slots();
924
925        assert_eq!(iter.size_hint(), (4, Some(4)));
926
927        assert_eq!(
928            iter.next()
929                .and_then(|slot| slot.into_node())
930                .map(|node| node.text().to_string())
931                .as_deref(),
932            Some("1")
933        );
934
935        assert_eq!(iter.size_hint(), (3, Some(3)));
936
937        assert_eq!(
938            iter.next_back()
939                .and_then(|slot| slot.into_node())
940                .map(|node| node.text().to_string())
941                .as_deref(),
942            Some("4")
943        );
944
945        assert_eq!(iter.size_hint(), (2, Some(2)));
946
947        assert_eq!(
948            iter.last()
949                .and_then(|slot| slot.into_node())
950                .map(|node| node.text().to_string())
951                .as_deref(),
952            Some("3")
953        );
954    }
955}