use std::collections::VecDeque;
use crate::language::tokenizer::tokenizer::{ Token, Tokenizer, TokenizerError };
pub struct TokenBuffer<'tokenizer, 'input>
{
tokenizer: &'tokenizer mut Tokenizer<'input>,
lookahead_buffer: Vec<Token>,
position: usize,
lookahead_stack: VecDeque<usize>
}
const LOOKAHEAD_BUFFER_CAPACITY: usize = 50;
impl<'tokenizer, 'input> TokenBuffer<'tokenizer, 'input>
{
pub fn new(tokenizer: &'tokenizer mut Tokenizer<'input>) -> Self
{
Self
{
tokenizer,
lookahead_buffer: Vec::with_capacity(LOOKAHEAD_BUFFER_CAPACITY),
position: 0,
lookahead_stack: VecDeque::with_capacity(LOOKAHEAD_BUFFER_CAPACITY)
}
}
pub fn mark_lookahead(&mut self)
{
let lookahead = if self.is_peeking()
{
self.lookahead_stack.front().copied()
}
else
{
Some(self.position)
};
if let Some(lookahead) = lookahead
{
self.lookahead_stack.push_front(lookahead);
}
}
pub fn commit_lookahead(&mut self)
{
if let Some(lookahead) = self.lookahead_stack.pop_front()
{
if self.is_peeking()
{
self.lookahead_stack[0] = lookahead;
}
else
{
self.position = lookahead;
self.clear_finished_buffer();
}
}
}
pub fn rollback_lookahead(&mut self)
{
if self.lookahead_stack.pop_front().is_some()
{
self.clear_finished_buffer();
}
}
pub fn next(&mut self) -> Result<Option<Token>, TokenizerError>
{
let index = self.lookahead_stack.front().copied().unwrap_or(self.position);
if index >= self.lookahead_buffer.len()
{
match self.tokenizer.next_token()?
{
Some(token) => self.lookahead_buffer.push(token),
None => return Ok(None)
}
}
let token = self.lookahead_buffer[index].clone();
if let Some(cursor) = self.lookahead_stack.front_mut()
{
*cursor += 1;
}
else
{
self.position += 1;
self.clear_finished_buffer();
}
Ok(Some(token))
}
pub(crate) fn position(&self) -> usize
{
self.lookahead_stack.front().copied().unwrap_or(self.position)
}
fn is_peeking(&self) -> bool
{
!self.lookahead_stack.is_empty()
}
fn clear_finished_buffer(&mut self)
{
if self.position >= self.lookahead_buffer.len()
&& !self.is_peeking()
{
self.lookahead_buffer.clear();
self.position = 0;
}
}
}