use std::collections::VecDeque;
use std::fmt::Debug;
use mago_database::file::FileId;
use mago_database::file::HasFileId;
use mago_span::Position;
use crate::error::ParseError;
use crate::error::SyntaxError;
use crate::lexer::TypeLexer;
use crate::token::TypeToken;
use crate::token::TypeTokenKind;
#[derive(Debug)]
pub struct TypeTokenStream<'input> {
pub(crate) lexer: TypeLexer<'input>,
buffer: VecDeque<TypeToken<'input>>,
position: Position,
}
impl<'input> TypeTokenStream<'input> {
#[inline]
pub fn new(lexer: TypeLexer<'input>) -> TypeTokenStream<'input> {
let position = lexer.current_position();
TypeTokenStream { lexer, buffer: VecDeque::with_capacity(4), position }
}
#[inline]
pub const fn current_position(&self) -> Position {
self.position
}
#[inline]
pub fn consume(&mut self) -> Result<TypeToken<'input>, ParseError> {
match self.advance() {
Some(Ok(token)) => Ok(token),
Some(Err(error)) => Err(error.into()),
None => Err(self.unexpected(None, &[])),
}
}
#[inline]
pub fn eat(&mut self, kind: TypeTokenKind) -> Result<TypeToken<'input>, ParseError> {
let token_result = self.consume();
match token_result {
Ok(token) => {
if kind == token.kind {
Ok(token)
} else {
Err(self.unexpected(Some(token), &[kind]))
}
}
Err(e) => Err(e),
}
}
#[inline]
fn advance(&mut self) -> Option<Result<TypeToken<'input>, SyntaxError>> {
match self.fill_buffer(1) {
Ok(true) => {
if let Some(token) = self.buffer.pop_front() {
self.position = token.end();
Some(Ok(token))
} else {
None
}
}
Ok(false) => None,
Err(error) => Some(Err(error)),
}
}
#[inline]
pub fn peek_kind(&mut self) -> Result<Option<TypeTokenKind>, ParseError> {
match self.fill_buffer(1) {
Ok(true) => Ok(self.buffer.front().map(|t| t.kind)),
Ok(false) => Ok(None),
Err(e) => Err(e.into()),
}
}
#[inline]
pub fn is_at(&mut self, kind: TypeTokenKind) -> Result<bool, ParseError> {
Ok(match self.peek_kind()? {
Some(k) => k == kind,
None => false,
})
}
#[inline]
pub fn peek(&mut self) -> Result<TypeToken<'input>, ParseError> {
match self.lookahead(0)? {
Some(token) => Ok(token),
None => Err(ParseError::UnexpectedEndOfFile(self.file_id(), vec![], self.current_position())),
}
}
#[inline]
pub fn lookahead(&mut self, n: usize) -> Result<Option<TypeToken<'input>>, ParseError> {
match self.fill_buffer(n + 1) {
Ok(true) => Ok(self.buffer.get(n).copied()),
Ok(false) => Ok(None),
Err(error) => Err(error.into()),
}
}
#[inline]
fn unexpected(&self, found: Option<TypeToken<'input>>, expected_one_of: &[TypeTokenKind]) -> ParseError {
if let Some(token) = found {
ParseError::UnexpectedToken(expected_one_of.to_vec(), token.kind, token.span_for(self.file_id()))
} else {
ParseError::UnexpectedEndOfFile(self.file_id(), expected_one_of.to_vec(), self.current_position())
}
}
#[inline]
fn fill_buffer(&mut self, n: usize) -> Result<bool, SyntaxError> {
while self.buffer.len() < n {
match self.lexer.advance() {
Some(Ok(token)) => {
if token.kind.is_trivia() {
continue; }
self.buffer.push_back(token);
}
Some(Err(error)) => return Err(error),
None => return Ok(false),
}
}
Ok(true) }
}
impl HasFileId for TypeTokenStream<'_> {
fn file_id(&self) -> FileId {
self.lexer.file_id()
}
}