use std::{error::Error, fmt, hash::Hash, mem::size_of};
use num_traits::{PrimInt, Unsigned};
#[derive(Copy, Clone, Debug)]
pub struct LexError {
pub idx: usize
}
impl Error for LexError {}
impl fmt::Display for LexError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Couldn't lex input at position {}", self.idx)
}
}
pub trait Lexer<StorageT: Hash + PrimInt + Unsigned> {
fn next(&mut self) -> Option<Result<Lexeme<StorageT>, LexError>>;
fn lexeme_str(&self, &Lexeme<StorageT>) -> &str;
fn offset_line_col(&self, usize) -> (usize, usize);
fn all_lexemes(&mut self) -> Result<Vec<Lexeme<StorageT>>, LexError> {
let mut lxs = Vec::new();
let mut n = self.next();
while let Some(r) = n {
lxs.push(r?);
n = self.next();
}
Ok(lxs)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Lexeme<StorageT> {
start: usize,
len: u32,
tok_id: StorageT
}
impl<StorageT: Copy> Lexeme<StorageT> {
pub fn new(tok_id: StorageT, start: usize, len: Option<usize>) -> Self {
debug_assert!(size_of::<usize>() >= size_of::<u32>());
let len = if let Some(l) = len {
if l >= u32::max_value() as usize {
panic!("Can't currently represent lexeme of length {}.", l);
}
l as u32
} else {
u32::max_value()
};
Lexeme { start, len, tok_id }
}
pub fn tok_id(&self) -> StorageT {
self.tok_id
}
pub fn start(&self) -> usize {
self.start
}
pub fn end(&self) -> Option<usize> {
if let Some(l) = self.len() {
Some(self.start() + l)
} else {
None
}
}
pub fn len(&self) -> Option<usize> {
if self.len == u32::max_value() {
None
} else {
debug_assert!(size_of::<usize>() >= size_of::<u32>());
Some(self.len as usize)
}
}
}