Add TokenInfo for error logging, hopefully

This commit is contained in:
mars 2022-02-27 17:07:09 -07:00
parent f473fe324e
commit 2e170879ea
1 changed files with 64 additions and 7 deletions

View File

@ -1,4 +1,5 @@
use logos::Logos;
use std::fmt::{Display, Formatter, Result as FmtResult};
#[rustfmt::skip]
#[derive(Logos, Debug, PartialEq)]
@ -52,22 +53,55 @@ pub enum Token {
#[regex(r"//[^\n]*", logos::skip)]
SingleLineComment,
#[regex(r"[ \t\n\f ]+", logos::skip)]
#[regex(r"[ \t\f ]+", logos::skip)]
Whitespace,
#[token("\n")]
Newline,
#[error]
Error,
}
pub struct Lexer<'a>(logos::Lexer<'a, Token>);
pub struct TokenInfo<'a> {
pub line: &'a str,
pub line_num: usize,
pub token_start: usize,
pub token_end: usize,
}
impl<'a> Display for TokenInfo<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{:04}| {}\n |", self.line_num, self.line)?;
write!(f, "{} ^", " ".repeat(self.token_start))?;
let token_len = self.token_end - self.token_start;
if token_len > 1 {
write!(f, "{}^", "-".repeat(token_len - 2))?;
}
Ok(())
}
}
pub struct Lexer<'a> {
inner: logos::Lexer<'a, Token>,
line_num: usize,
line_start: usize,
}
impl<'a> Lexer<'a> {
pub fn new(source: &'a str) -> Self {
Self(Token::lexer(source))
Self {
inner: Token::lexer(source),
line_num: 0,
line_start: 0,
}
}
pub fn slice(&self) -> &'a str {
self.0.slice()
self.inner.slice()
}
pub fn eat_id(&mut self) -> Result<&'a str, Option<Token>> {
@ -78,14 +112,37 @@ impl<'a> Lexer<'a> {
Err(tok)
}
}
pub fn get_info(&self) -> TokenInfo<'a> {
let from_start = &self.inner.source()[self.line_start..];
let line_end = from_start.find("\n").unwrap_or(from_start.len());
let line = &from_start[..line_end];
let span = self.inner.span();
TokenInfo {
line,
line_num: self.line_num,
token_start: span.start - self.line_start,
token_end: span.end - self.line_start,
}
}
}
impl<'a> Iterator for Lexer<'a> {
type Item = Token;
fn next(&mut self) -> Option<Self::Item> {
let tok = self.0.next();
println!("ate: {:?}", tok);
tok
while let Some(tok) = self.inner.next() {
println!("ate: {:?}", tok);
if tok == Token::Newline {
self.line_start = self.inner.span().end;
self.line_num += 1;
} else {
println!("{}", self.get_info());
return Some(tok);
}
}
None
}
}