use crate::token::{Kind, Token};
pub struct Lexer {
source_code: String,
position: usize,
current: Option<Token>,
errors: Vec<String>,
}
impl Lexer {
pub fn new(source_code: String) -> Self {
Self {
source_code,
position: 0,
current: None,
errors: Vec::new(),
}
}
fn current_char(&self) -> Option<char> {
self.source_code.chars().nth(self.position)
}
fn current_token(&self) -> Option<Token> {
self.current.clone()
}
fn advance_token(&mut self) {
self.current = self.next();
}
pub fn check_source_code(&mut self) -> Result<(), String> {
loop {
match self.consume() {
Ok(token) => {
if let Some(token) = token {
if token.kind == Kind::EOF {
break;
}
}
}
Err(err) => return Err(err),
}
}
Ok(())
}
pub fn consume(&mut self) -> Result<Option<Token>, String> {
self.advance_token();
if self.errors.len() > 0 {
return Err(format!("{}", self.errors.first().unwrap()));
}
Ok(self.current_token())
}
}
impl Iterator for Lexer {
type Item = Token;
fn next(&mut self) -> Option<Self::Item> {
let current: Option<char> = self.current_char();
let kind: Result<Kind, String> = Kind::classify(current.clone());
self.position += 1;
match kind {
Ok(k) => match k {
Kind::EOF => Some(Token::new(k, format!("eof"))),
Kind::String => {
let mut string: Vec<char> = Vec::new();
loop {
let cc: Option<char> = self.current_char();
self.position += 1;
let kc: Result<Kind, String> = Kind::classify(cc.clone());
if let Ok(Kind::EOF) = kc {
self.errors
.push(format!("unterminated double quote string"));
break None;
} else if let Ok(Kind::String) = kc {
break Some(Token::new(k, string.into_iter().collect()));
} else {
string.push(cc.unwrap())
}
}
}
_ => Some(Token::new(k, current.unwrap().to_string())),
},
Err(err) => {
self.errors.push(err);
None
}
}
}
}