orecc_front/
token_reader.rs

1/// A simple character reader that is useful for creating lexers
2#[derive(Debug)]
3pub struct TokenReader {
4    source: std::rc::Rc<str>,
5
6    /// A cursor. Just a byte index, useful for spanning and then [codespan_reporting]
7    pub cursor: usize,
8}
9
10impl TokenReader {
11    /// Create new [TokenReader]. Just requires a source as Rc<str>, can be provided by the [crate::Codebase]
12    pub fn new(source: std::rc::Rc<str>) -> Self {
13        Self {
14            source,
15            cursor: 0,
16        }
17    }
18
19    /// Peek a char
20    pub fn peek_char(&mut self) -> Option<char> {
21        self.source.get(self.cursor..)?.chars().next()
22    }
23
24    /// Peek a char, return it and move cursor forward
25    pub fn next_char(&mut self) -> Option<char> {
26        let peek = self.peek_char();
27        if let Some(peek) = peek {
28            self.cursor += peek.len_utf8();
29        }
30        peek
31    }
32
33    /// [`Self::next_char()`] but advances if predicate
34    pub fn next_char_if(&mut self, pred: impl FnOnce(char) -> bool) -> Option<char> {
35        let peek = self.peek_char();
36        if let Some(peek) = peek {
37            if pred(peek) {
38                self.cursor += peek.len_utf8();
39                return Some(peek);
40            }
41        }
42        None
43    }
44
45    /// Takes characters and adds then to the buffer while predicate
46    pub fn next_token(&mut self, pred: impl Fn(char) -> bool, prefix: impl Into<String>) -> String {
47        let mut buffer = prefix.into();
48        while let Some(char) = self.next_char_if(&pred) {
49            buffer.push(char);
50        }
51        buffer
52    }
53}