use crate::error::Location;
use crate::token::{Token, TokenType};
pub struct Lexer<'a> {
pub s: &'a str,
size: usize,
cursor: usize,
line: usize,
col: usize,
}
impl<'a> Lexer<'a> {
pub fn new(source: &str) -> Lexer {
let size = source.len();
let mut cursor = 0;
let mut line = 1;
let mut col = 1;
if source.starts_with("# ") {
while cursor < size && source.as_bytes()[cursor] != b'\n' {
cursor += 1;
col += 1;
}
if cursor < size && source.as_bytes()[cursor] == b'\n' {
cursor += 1;
line += 1;
col = 1;
}
}
Lexer {
s: source,
size,
cursor,
line,
col,
}
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Token<'a> {
let mut t = Token::<'_> {
loc: Location {
line: self.line,
col: self.col,
},
..Default::default()
};
if self.cursor == self.size {
t.typ = TokenType::Eof;
t.start = self.size;
t.end = self.size;
return t;
}
while self.cursor < self.size
&& (self.s.as_bytes()[self.cursor] == b' '
|| self.s.as_bytes()[self.cursor] == b'\n'
|| self.s.as_bytes()[self.cursor] == b'\r'
|| self.s.as_bytes()[self.cursor] == b'\t')
{
if self.s.as_bytes()[self.cursor] == b'\n' {
self.line += 1;
self.col = 1;
} else {
self.col += 1;
}
self.cursor += 1;
}
if self.cursor == self.size {
t.typ = TokenType::Eof;
t.start = self.size;
t.end = self.size;
return t;
}
t.loc = Location {
line: self.line,
col: self.col,
};
match self.s.as_bytes()[self.cursor] {
b'{' => {
t.typ = TokenType::OpenBrace;
t.start = self.cursor;
t.end = self.cursor + 1;
self.cursor += 1;
self.col += 1;
t
}
b'}' => {
t.typ = TokenType::CloseBrace;
t.start = self.cursor;
t.end = self.cursor + 1;
self.cursor += 1;
self.col += 1;
t
}
_ => {
t.typ = TokenType::Word;
t.start = self.cursor;
while self.cursor < self.size
&& self.s.as_bytes()[self.cursor] != b' '
&& self.s.as_bytes()[self.cursor] != b'\n'
&& self.s.as_bytes()[self.cursor] != b'\r'
&& self.s.as_bytes()[self.cursor] != b'\t'
&& self.s.as_bytes()[self.cursor] != b'}'
{
self.cursor += 1;
self.col += 1;
}
t.end = self.cursor;
t.word = &self.s[t.start..t.end];
t
}
}
}
}