86 lines
1.4 KiB
Rust
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,
|
|
}
|
|
}
|
|
}
|