use std::fmt::Debug;
use mago_allocator::prelude::*;
use mago_database::file::FileId;
use mago_database::file::HasFileId;
use mago_span::Position;
use mago_span::Span;
use mago_syntax_core::parser::LookaheadBuf;
use crate::error::ParseError;
use crate::error::SyntaxError;
use crate::lexer::TypeLexer;
use crate::token::TypeToken;
use crate::token::TypeTokenKind;
#[derive(Debug)]
#[allow(clippy::field_scoped_visibility_modifiers)]
pub struct TypeTokenStream<'arena, A>
where
A: Arena,
{
pub(crate) arena: &'arena A,
pub(crate) lexer: TypeLexer<'arena>,
file_id: FileId,
buffer: LookaheadBuf<TypeToken<'arena>, 64>,
position: Position,
depth: u16,
}
pub(crate) const MAX_RECURSION_DEPTH: u16 = 512;
impl<'arena, A> TypeTokenStream<'arena, A>
where
A: Arena,
{
#[inline]
pub fn new(arena: &'arena A, lexer: TypeLexer<'arena>) -> TypeTokenStream<'arena, A> {
let position = lexer.current_position();
let file_id = lexer.file_id();
TypeTokenStream { arena, lexer, file_id, buffer: LookaheadBuf::new(), position, depth: 0 }
}
#[inline]
pub fn enter_recursion(&mut self) -> Result<(), ParseError> {
self.depth += 1;
if self.depth > MAX_RECURSION_DEPTH {
self.depth -= 1;
let position = self.current_position();
return Err(ParseError::RecursionLimitExceeded(Span::new(self.file_id, position, position)));
}
Ok(())
}
#[inline]
pub fn leave_recursion(&mut self) {
self.depth -= 1;
}
#[inline]
pub fn consume_span(&mut self) -> Result<Span, ParseError> {
let token = self.consume()?;
Ok(Span::new(self.file_id, token.start, token.end()))
}
#[inline]
pub fn eat_span(&mut self, kind: TypeTokenKind) -> Result<Span, ParseError> {
let token = self.eat(kind)?;
Ok(Span::new(self.file_id, token.start, token.end()))
}
#[inline]
pub fn consume_keyword(&mut self) -> Result<crate::cst::Keyword<'arena>, ParseError> {
let token = self.consume()?;
let span = Span::new(self.file_id, token.start, token.end());
Ok(crate::cst::Keyword { span, value: token.value })
}
#[inline]
pub fn eat_keyword(&mut self, kind: TypeTokenKind) -> Result<crate::cst::Keyword<'arena>, ParseError> {
let token = self.eat(kind)?;
let span = Span::new(self.file_id, token.start, token.end());
Ok(crate::cst::Keyword { span, value: token.value })
}
#[inline]
#[must_use]
pub fn alloc<T>(&self, value: T) -> &'arena T {
self.arena.alloc(value)
}
#[inline]
#[must_use]
pub fn new_bvec<T>(&self) -> Vec<'arena, T, A> {
Vec::new_in(self.arena)
}
#[inline]
pub const fn current_position(&self) -> Position {
self.position
}
#[inline]
pub fn consume(&mut self) -> Result<TypeToken<'arena>, 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<'arena>, ParseError> {
if let Some(token) = self.buffer.get(0) {
if kind == token.kind {
let _ = self.buffer.pop_front();
self.position = token.end();
return Ok(token);
}
return Err(self.unexpected(Some(token), &[kind]));
}
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<'arena>, 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> {
if let Some(t) = self.buffer.get(0) {
return Ok(Some(t.kind));
}
match self.fill_buffer(1) {
Ok(true) => Ok(self.buffer.get(0).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> {
if let Some(t) = self.buffer.get(0) {
return Ok(t.kind == kind);
}
Ok(match self.peek_kind()? {
Some(k) => k == kind,
None => false,
})
}
#[inline]
pub fn peek(&mut self) -> Result<TypeToken<'arena>, 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<'arena>>, ParseError> {
if n < self.buffer.len() {
return Ok(self.buffer.get(n));
}
match self.fill_buffer(n + 1) {
Ok(true) => Ok(self.buffer.get(n)),
Ok(false) => Ok(None),
Err(error) => Err(error.into()),
}
}
#[inline]
fn unexpected(&self, found: Option<TypeToken<'arena>>, 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> {
if self.buffer.len() >= n {
return Ok(true);
}
self.fill_buffer_slow(n)
}
#[inline(never)]
fn fill_buffer_slow(&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<A> HasFileId for TypeTokenStream<'_, A>
where
A: Arena,
{
#[inline]
fn file_id(&self) -> FileId {
self.file_id
}
}