1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/// A simple character reader that is useful for creating lexers
pub struct TokenReader {
    source: std::rc::Rc<str>,

    /// A cursor. Just a byte index, useful for spanning and then [codespan_reporting]
    pub cursor: usize,
}

impl TokenReader {
    /// Create new [TokenReader]. Just requires a source as Rc<str>, can be provided by the [crate::Codebase]
    pub fn new(source: std::rc::Rc<str>) -> Self {
        Self {
            source,
            cursor: 0,
        }
    }

    /// Peek a char
    pub fn peek_char(&mut self) -> Option<char> {
        self.source.get(self.cursor..)?.chars().next()
    }

    /// Peek a char, return it and move cursor forward
    pub fn next_char(&mut self) -> Option<char> {
        let peek = self.peek_char();
        if let Some(peek) = peek {
            self.cursor += peek.len_utf8();
        }
        peek
    }

    /// [`Self::next_char()`] but advances if predicate
    pub fn next_char_if(&mut self, pred: impl FnOnce(char) -> bool) -> Option<char> {
        let peek = self.peek_char();
        if let Some(peek) = peek {
            if pred(peek) {
                self.cursor += peek.len_utf8();
                return Some(peek);
            }
        }
        None
    }

    /// Takes characters and adds then to the buffer while predicate
    pub fn next_token(&mut self, pred: impl Fn(char) -> bool, prefix: char) -> String {
        let mut buffer = prefix.to_string();
        while let Some(char) = self.next_char_if(&pred) {
            buffer.push(char);
        }
        buffer
    }
}