#[derive(Debug, PartialEq, Clone)]
pub struct Position {
pub(crate) line: usize,
pub(crate) col: usize,
}
impl std::fmt::Display for Position {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.line, self.col)
}
}
pub(crate) struct Reader<'a> {
input: &'a str,
read_pos: std::iter::Peekable<std::str::Bytes<'a>>,
idx: usize,
line: usize,
col: usize,
}
impl<'a> Reader<'a> {
pub fn new(input: &'a str) -> Reader<'a> {
Reader {
input,
read_pos: input.bytes().peekable(),
idx: 0,
line: 0,
col: 0,
}
}
pub fn next_byte(&mut self) -> Option<u8> {
match self.read_pos.next() {
r @ Some(b'\n') => {
self.line += 1;
self.col = 0;
self.idx += 1;
r
}
r @ Some(_) => {
self.col += 1;
self.idx += 1;
r
}
None => None,
}
}
pub fn skip_byte(&mut self) {
_ = self.next_byte();
}
pub fn peek_next_byte(&mut self) -> Option<u8> {
self.read_pos.peek().copied()
}
pub fn position(&self) -> Position {
Position {
line: self.line,
col: self.col,
}
}
pub fn skip_whitespace(&mut self) {
while self
.peek_next_byte()
.map(|b| b.is_ascii_whitespace())
.unwrap_or(false)
{
self.skip_byte();
}
}
pub fn is_eof(&mut self) -> bool {
self.peek_next_byte().is_some()
}
pub fn offset(&self) -> usize {
self.idx
}
pub fn get_str(&self, start: usize, end: usize) -> &'a str {
&self.input[start..end]
}
}