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
}
}