crftng-intrprtrs/src/lexer/lexer_iter.rs

86 lines
1.4 KiB
Rust

use crate::error::Location;
use std::str::Chars;
#[derive(Debug)]
pub struct LexerIter<'a> {
inner: Chars<'a>,
line: usize,
col: usize,
}
impl<'a> Iterator for LexerIter<'a> {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
let char = self.inner.next()?;
self.col += 1;
if char == '\n' {
self.line += 1;
self.col = 1;
}
Some(char)
}
}
impl<'a> LexerIter<'a> {
pub fn new(src: &'a str) -> Self {
Self {
inner: src.chars(),
line: 0,
col: 0,
}
}
pub fn peek(&self) -> Option<char> {
self.as_str().chars().next()
}
pub fn as_str(&'a self) -> &'a str {
self.inner.as_str()
}
pub fn as_str_while<F: FnMut(char) -> bool>(&mut self, mut predicate: F) -> &'a str {
let str = self.inner.as_str();
let mut iter = str.char_indices();
let end_indice = loop {
match iter.next() {
Some((i, c)) => {
if !predicate(c) {
break i;
}
}
None => {
break iter.offset();
}
}
};
unsafe {
self.inner = str.get_unchecked(end_indice..).chars();
str.get_unchecked(0..end_indice) as _
}
}
pub fn next_if(&mut self, func: impl FnOnce(char) -> bool) -> Option<char> {
if func(self.peek()?) {
self.next()
} else {
None
}
}
pub fn next_if_eq(&mut self, expected: char) -> Option<char> {
self.next_if(|c| c == expected)
}
pub fn get_location<'b>(&self, file: Option<&'b str>) -> Location<'b> {
Location {
line: self.line,
col: self.col,
file,
}
}
}