use std::iter::Peekable;
use std::str::Chars;
#[derive(Debug, PartialEq)]
pub enum Token {
Ident,
Int(u32),
Float(f64),
Char(char),
Str(String),
Add,
Sub,
Mul,
Div,
Mod,
Pow,
}
pub struct Lexer<'a> {
input: &'a str,
chars: Peekable<Chars<'a>>,
current: Option<char>,
position: usize,
}
impl<'a> Lexer<'a> {
pub fn new(input: &'a str) -> Self {
Self {
input,
chars: input.chars().peekable(),
current: None,
position: 0,
}
}
fn skip_whitespace(&mut self) {
while let Some(ch) = self.current {
if ch.is_whitespace() {
self.advance();
} else {
break;
}
}
}
fn advance(&mut self) {
self.current = self.chars.next();
self.position += 1;
}
fn int(&mut self) -> Option<Token> {
let position = self.position;
while let Some(ch) = self.current {
if ch.is_digit(10) {
self.advance();
} else {
break;
}
}
let s = &self.input[position..self.position + 1];
dbg!(&s);
Some(Token::Int(s.parse().unwrap()))
}
}
impl Iterator for Lexer<'_> {
type Item = Token;
fn next(&mut self) -> Option<Token> {
self.advance();
self.skip_whitespace();
self.current.and_then(|ch| {
match ch {
ch if ch.is_digit(10) => self.int(),
'+' => Some(Token::Add),
'-' => Some(Token::Sub),
'*' => Some(Token::Mul),
'/' => Some(Token::Div),
ch => {
dbg!(ch);
todo!()
},
}
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lexer() {
let input = "1 + 2 / 3";
let lexer = Lexer::new(input);
let tokens: Vec<_> = lexer.collect();
assert_eq!(tokens, vec![
Token::Int(1),
Token::Add,
Token::Int(2),
Token::Div,
Token::Int(3),
]);
}
}