use crate::input::Position;
use crate::input::lookahead::{LookAheadFrame, LookAheadHandler, TokenLocation};
use crate::input::source::InputSource;
use crate::input::token::TokenInputSource;
use std::collections::VecDeque;
use std::fmt::{Debug, Display};
pub trait InputToken: Clone {
type Token: PartialEq + Clone + Display + Debug;
fn token(&self) -> &Self::Token;
fn token_owned(self) -> Self::Token;
fn position(&self) -> Position;
}
pub struct Input<'a, IT> {
source: Box<dyn InputSource<Token = IT> + 'a>,
consumed_count: usize,
next_location: TokenLocation,
look_ahead_frames: Vec<LookAheadFrame>,
look_ahead_buffer: VecDeque<IT>,
last_token_position: Position,
}
impl<'a, IT> Input<'a, IT>
where
IT: InputToken,
{
pub(crate) fn new(source: Box<dyn InputSource<Token = IT> + 'a>) -> Self {
Input {
source,
consumed_count: 0,
next_location: TokenLocation::Stream,
look_ahead_frames: Vec::new(),
look_ahead_buffer: VecDeque::new(),
last_token_position: Position::new(1, 1),
}
}
pub fn new_from_tokens<S, I>(source: S, source_name: Option<String>) -> Input<'a, IT>
where
S: IntoIterator<Item = IT, IntoIter = I>,
I: Iterator<Item = IT> + 'a,
{
let source = TokenInputSource::new(source, source_name);
Input::new(Box::new(source))
}
pub(crate) fn next_token(&mut self) -> Option<IT> {
match self.next_location {
TokenLocation::Stream => {
let token = self.source.next_token()?;
self.last_token_position = token.position();
self.consumed_count += 1;
Some(token)
}
TokenLocation::StreamLookingAhead => {
let frame = self.look_ahead_frames.last_mut().unwrap();
match self.source.next_token() {
None => None,
Some(token) => {
self.last_token_position = token.position();
let cloned = token.clone();
self.look_ahead_buffer.push_back(token);
frame.increment();
self.consumed_count += 1;
Some(cloned)
}
}
}
TokenLocation::BufferHead => {
let output = self.look_ahead_buffer.pop_front();
self.next_location = if self.look_ahead_buffer.is_empty() {
TokenLocation::Stream
} else {
TokenLocation::BufferHead
};
let token = output?;
self.last_token_position = token.position();
self.consumed_count += 1;
Some(token)
}
TokenLocation::BufferTail => {
let frame = self.look_ahead_frames.last_mut().unwrap();
let token = self.look_ahead_buffer.get(frame.next_token_ix()).unwrap();
frame.increment();
self.next_location = if frame.next_token_ix() == self.look_ahead_buffer.len() {
TokenLocation::StreamLookingAhead
} else {
TokenLocation::BufferTail
};
self.last_token_position = token.position();
self.consumed_count += 1;
Some(token.clone())
}
}
}
pub(crate) fn peek(&mut self) -> Option<&IT> {
match self.next_location {
TokenLocation::Stream => self.source.peek(),
TokenLocation::StreamLookingAhead => self.source.peek(),
TokenLocation::BufferHead => self.look_ahead_buffer.front(),
TokenLocation::BufferTail => {
let frame = self.look_ahead_frames.last_mut().unwrap();
self.look_ahead_buffer.get(frame.next_token_ix())
}
}
}
pub(crate) fn consumed_count(&self) -> usize {
self.consumed_count
}
pub fn source_name(&self) -> Option<String> {
self.source.source_name().map(|s| (*s).clone())
}
pub fn position(&mut self) -> Position {
match self.peek() {
Some(token) => token.position(),
None => self.last_token_position,
}
}
pub(crate) fn start_look_ahead(&mut self) -> LookAheadHandler {
let new_frame = match self.look_ahead_frames.last() {
Some(previous) => LookAheadFrame::new(previous.next_token_ix()),
None => LookAheadFrame::new(0),
};
self.next_location = if self.look_ahead_buffer.is_empty()
|| new_frame.next_token_ix() == self.look_ahead_buffer.len()
{
TokenLocation::StreamLookingAhead
} else {
TokenLocation::BufferTail
};
let token_id = self.look_ahead_frames.len();
self.look_ahead_frames.push(new_frame);
LookAheadHandler::new(token_id)
}
pub(crate) fn stop_look_ahead(&mut self, handler: LookAheadHandler, backtrack: bool) {
let frame = self.look_ahead_frames.pop().unwrap();
if handler.id() != self.look_ahead_frames.len() {
panic!("Look ahead handler doesn't match current lookahead depth.")
}
if backtrack {
self.consumed_count -= frame.length();
} else {
let buffer_length = self.look_ahead_buffer.len();
self.look_ahead_buffer
.truncate(buffer_length - frame.length());
}
self.next_location = if self.look_ahead_frames.is_empty() {
if self.look_ahead_buffer.is_empty() {
TokenLocation::Stream
} else {
TokenLocation::BufferHead
}
} else {
let frame = self.look_ahead_frames.last_mut().unwrap();
if frame.next_token_ix() == self.look_ahead_buffer.len() {
TokenLocation::StreamLookingAhead
} else {
TokenLocation::BufferTail
}
};
if let Some(token) = self.peek() {
self.last_token_position = token.position();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::input::core::Input;
#[test]
fn lookahead_no_backtracking() {
let mut input = Input::new_from_chars("12".chars(), None);
let handler = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '1');
assert_eq!(input.next_token().unwrap().token_owned(), '2');
input.stop_look_ahead(handler, false);
assert!(input.look_ahead_buffer.is_empty());
assert_eq!(input.consumed_count(), 2);
assert_eq!(input.look_ahead_frames.len(), 0);
assert_eq!(input.next_token(), None);
}
#[test]
fn lookahead_backtracking() {
let mut input = Input::new_from_chars("12".chars(), None);
let handler = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '1');
assert_eq!(input.next_token().unwrap().token_owned(), '2');
input.stop_look_ahead(handler, true);
assert!(!input.look_ahead_buffer.is_empty());
assert_eq!(input.consumed_count(), 0);
assert_eq!(input.next_token().unwrap().token_owned(), '1');
}
#[test]
fn peek_twice() {
let mut input = Input::new_from_chars("12".chars(), None);
assert_eq!(input.peek().unwrap().token(), &'1');
assert_eq!(input.peek().unwrap().token(), &'1');
}
#[test]
fn peek_twice_while_looking_ahead_backtracking() {
let mut input = Input::new_from_chars("12".chars(), None);
let handler = input.start_look_ahead();
assert_eq!(input.peek().unwrap().token(), &'1');
assert_eq!(input.peek().unwrap().token(), &'1');
input.stop_look_ahead(handler, true);
assert_eq!(input.peek().unwrap().token(), &'1');
}
#[test]
fn peek_twice_while_looking_ahead_not_backtracking() {
let mut input = Input::new_from_chars("12".chars(), None);
let handler = input.start_look_ahead();
assert_eq!(input.peek().unwrap().token(), &'1');
assert_eq!(input.peek().unwrap().token(), &'1');
input.stop_look_ahead(handler, false);
assert_eq!(input.peek().unwrap().token(), &'1');
}
#[test]
fn repeat_peek_look_ahead_backtracking() {
let mut input = Input::new_from_chars("12".chars(), None);
let handler = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '1');
input.stop_look_ahead(handler, true);
assert_eq!(input.peek().unwrap().token(), &'1');
let handler = input.start_look_ahead();
assert_eq!(input.peek().unwrap().token(), &'1');
input.stop_look_ahead(handler, true);
assert_eq!(input.peek().unwrap().token(), &'1');
}
#[test]
fn repeat_peek_look_ahead_not_backtracking() {
let mut input = Input::new_from_chars("12".chars(), None);
let handler = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '1');
input.stop_look_ahead(handler, false);
assert_eq!(input.peek().unwrap().token(), &'2');
let handler = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '2');
input.stop_look_ahead(handler, true);
assert_eq!(input.peek().unwrap().token(), &'2');
assert_eq!(input.next_token().unwrap().token_owned(), '2');
}
#[test]
fn nested_lookahead_backtrack() {
let mut input = Input::new_from_chars("12345".chars(), None);
let handler1 = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '1');
let handler2 = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '2');
input.stop_look_ahead(handler2, true);
assert_eq!(input.next_token().unwrap().token_owned(), '2');
input.stop_look_ahead(handler1, true);
assert_eq!(input.next_token().unwrap().token_owned(), '1');
}
#[test]
fn nested_lookahead_no_backtrack() {
let mut input = Input::new_from_chars("12345".chars(), None);
let handler1 = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '1');
let handler2 = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '2');
input.stop_look_ahead(handler2, false);
assert_eq!(input.next_token().unwrap().token_owned(), '3');
input.stop_look_ahead(handler1, false);
assert_eq!(input.next_token().unwrap().token_owned(), '4');
}
#[test]
fn nested_look_ahead_backtrack_first() {
let mut input = Input::new_from_chars("12345".chars(), None);
let handler1 = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '1');
let handler2 = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '2');
input.stop_look_ahead(handler2, true);
assert_eq!(input.next_token().unwrap().token_owned(), '2');
input.stop_look_ahead(handler1, false);
assert_eq!(input.next_token().unwrap().token_owned(), '3');
}
#[test]
fn nested_look_ahead_backtrack_second() {
let mut input = Input::new_from_chars("12345".chars(), None);
let handler1 = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '1');
let handler2 = input.start_look_ahead();
assert_eq!(input.next_token().unwrap().token_owned(), '2');
input.stop_look_ahead(handler2, false);
assert_eq!(input.next_token().unwrap().token_owned(), '3');
input.stop_look_ahead(handler1, true);
assert_eq!(input.next_token().unwrap().token_owned(), '1');
}
#[test]
#[should_panic]
fn wrong_token() {
let mut input = Input::new_from_chars("12345".chars(), None);
let handler1 = input.start_look_ahead();
let _handler2 = input.start_look_ahead();
input.stop_look_ahead(handler1, false);
}
}