use std::fmt::Display;
use crate::error;
pub(crate) struct Tokenizer<'a> {
input: &'a str,
index: usize,
pub mode: Mode,
}
impl<'a> Tokenizer<'a> {
pub(crate) fn new(input: &'a str) -> Self {
Self {
input,
index: 0,
mode: Mode::Default,
}
}
pub(crate) fn index(&self) -> usize {
self.index
}
pub(crate) fn is_empty(&self) -> bool {
self.index == self.input.chars().count()
}
pub(crate) fn take_while<F>(&mut self, mut pred: F) -> Result<Vec<Token>, error::KeyParse>
where
F: FnMut(Token) -> bool,
{
let mut buffer = vec![];
loop {
let ch = self.next()?;
let should_continue = pred(ch);
if !should_continue {
break;
}
self.chomp();
buffer.push(ch);
}
Ok(buffer)
}
fn next(&self) -> Result<Token, error::KeyParse> {
if let Some(next) = self.maybe_next() {
next
} else {
Err(error::KeyParse::UnexpectedEnd)
}
}
fn maybe_next(&self) -> Option<Result<Token, error::KeyParse>> {
self.maybe_get(self.index)
}
fn maybe_get(&self, index: usize) -> Option<Result<Token, error::KeyParse>> {
let next = self.input.chars().nth(index)?;
if self.mode == Mode::NormalValue {
return Some(Ok(Token::Char(next)));
}
match next {
'<' => Some(Ok(Token::AngularBracketOpen)),
'>' => Some(Ok(Token::AngularBracketClose)),
'-' => Some(Ok(Token::Dash)),
other => Some(Ok(Token::Char(other))),
}
}
pub(crate) fn find(&self, token: Token) -> Result<Option<usize>, error::KeyParse> {
let mut current_index = self.index;
loop {
if let Some(next) = self.maybe_get(current_index) {
if next? == token {
return Ok(Some(current_index));
}
current_index += 1;
} else {
return Ok(None);
}
}
}
pub(crate) fn peek(&self, token: Token) -> Result<bool, error::KeyParse> {
if self.next()? == token {
Ok(true)
} else {
Ok(false)
}
}
pub(crate) fn expect_char(&mut self) -> Result<char, error::KeyParse> {
let next = self.next()?;
if let Token::Char(output) = next {
self.chomp();
Ok(output)
} else {
Err(error::KeyParse::ExpectedCharFound(next))
}
}
pub(crate) fn expect(&mut self, token: Token) -> Result<(), error::KeyParse> {
let next = self.next()?;
if next == token {
self.chomp();
Ok(())
} else {
Err(error::KeyParse::ExpectedButFound {
expected: token,
found: next,
})
}
}
fn chomp(&mut self) {
self.index += 1;
}
}
#[derive(PartialEq, Eq)]
pub(crate) enum Mode {
NormalValue,
Default,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Token {
AngularBracketOpen,
AngularBracketClose,
Dash,
Char(char),
}
impl Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as std::fmt::Debug>::fmt(self, f)
}
}
impl Token {
pub(crate) fn to_char(self) -> char {
match self {
Token::AngularBracketOpen => '<',
Token::AngularBracketClose => '>',
Token::Dash => '-',
Token::Char(ch) => ch,
}
}
}