tt/
buffer.rs

1//! Stateful iteration over token trees.
2//!
3//! We use this as the source of tokens for parser.
4use crate::{Leaf, Subtree, TokenTree, TokenTreesView, dispatch_ref};
5
6pub struct Cursor<'a> {
7    buffer: TokenTreesView<'a>,
8    index: usize,
9    subtrees_stack: Vec<usize>,
10}
11
12impl<'a> Cursor<'a> {
13    pub fn new(buffer: TokenTreesView<'a>) -> Self {
14        Self { buffer, index: 0, subtrees_stack: Vec::new() }
15    }
16
17    /// Check whether it is eof
18    pub fn eof(&self) -> bool {
19        self.index == self.buffer.len() && self.subtrees_stack.is_empty()
20    }
21
22    pub fn is_root(&self) -> bool {
23        self.subtrees_stack.is_empty()
24    }
25
26    fn at(&self, idx: usize) -> Option<TokenTree> {
27        dispatch_ref! {
28            match self.buffer.repr => tt => Some(tt.get(idx)?.to_api(self.buffer.span_parts))
29        }
30    }
31
32    fn last_subtree(&self) -> Option<(usize, Subtree)> {
33        self.subtrees_stack.last().map(|&subtree_idx| {
34            let Some(TokenTree::Subtree(subtree)) = self.at(subtree_idx) else {
35                panic!("subtree pointing to non-subtree");
36            };
37            (subtree_idx, subtree)
38        })
39    }
40
41    pub fn end(&mut self) -> Subtree {
42        let (last_subtree_idx, last_subtree) =
43            self.last_subtree().expect("called `Cursor::end()` without an open subtree");
44        // +1 because `Subtree.len` excludes the subtree itself.
45        assert_eq!(
46            last_subtree_idx + last_subtree.usize_len() + 1,
47            self.index,
48            "called `Cursor::end()` without finishing a subtree"
49        );
50        self.subtrees_stack.pop();
51        last_subtree
52    }
53
54    /// Returns the `TokenTree` at the cursor if it is not at the end of a subtree.
55    pub fn token_tree(&self) -> Option<TokenTree> {
56        if let Some((last_subtree_idx, last_subtree)) = self.last_subtree() {
57            // +1 because `Subtree.len` excludes the subtree itself.
58            if last_subtree_idx + last_subtree.usize_len() + 1 == self.index {
59                return None;
60            }
61        }
62        self.at(self.index)
63    }
64
65    /// Bump the cursor, and enters a subtree if it is on one.
66    pub fn bump(&mut self) {
67        if let Some((last_subtree_idx, last_subtree)) = self.last_subtree() {
68            // +1 because `Subtree.len` excludes the subtree itself.
69            assert_ne!(
70                last_subtree_idx + last_subtree.usize_len() + 1,
71                self.index,
72                "called `Cursor::bump()` when at the end of a subtree"
73            );
74        }
75        if let Some(TokenTree::Subtree(_)) = self.at(self.index) {
76            self.subtrees_stack.push(self.index);
77        }
78        self.index += 1;
79    }
80
81    pub fn bump_or_end(&mut self) {
82        if let Some((last_subtree_idx, last_subtree)) = self.last_subtree() {
83            // +1 because `Subtree.len` excludes the subtree itself.
84            if last_subtree_idx + last_subtree.usize_len() + 1 == self.index {
85                self.subtrees_stack.pop();
86                return;
87            }
88        }
89        // +1 because `Subtree.len` excludes the subtree itself.
90        if let Some(TokenTree::Subtree(_)) = self.at(self.index) {
91            self.subtrees_stack.push(self.index);
92        }
93        self.index += 1;
94    }
95
96    pub fn peek_two_leaves(&self) -> Option<[Leaf; 2]> {
97        if let Some((last_subtree_idx, last_subtree)) = self.last_subtree() {
98            // +1 because `Subtree.len` excludes the subtree itself.
99            let last_end = last_subtree_idx + last_subtree.usize_len() + 1;
100            if last_end == self.index || last_end == self.index + 1 {
101                return None;
102            }
103        }
104        self.at(self.index).zip(self.at(self.index + 1)).and_then(|it| match it {
105            (TokenTree::Leaf(a), TokenTree::Leaf(b)) => Some([a, b]),
106            _ => None,
107        })
108    }
109
110    pub fn crossed(&self) -> TokenTreesView<'a> {
111        assert!(self.is_root());
112        TokenTreesView {
113            repr: self.buffer.repr.get(..self.index).unwrap(),
114            span_parts: self.buffer.span_parts,
115        }
116    }
117}