use super::lexer::{Kind, Token};
use crate::error::{PrismError, Result};
pub(crate) struct Stream<'t, 'a> {
tokens: &'t [Token<'a>],
at: usize,
}
impl<'t, 'a> Stream<'t, 'a> {
pub(crate) fn new(tokens: &'t [Token<'a>]) -> Self {
Self { tokens, at: 0 }
}
pub(crate) fn peek(&self) -> Token<'a> {
self.tokens[self.at.min(self.tokens.len() - 1)]
}
pub(crate) fn peek_at(&self, ahead: usize) -> Token<'a> {
self.tokens[(self.at + ahead).min(self.tokens.len() - 1)]
}
pub(crate) fn kind(&self) -> Kind {
self.peek().kind
}
pub(crate) fn line(&self) -> usize {
self.peek().line
}
pub(crate) fn at_end(&self) -> bool {
self.kind() == Kind::Eof
}
pub(crate) fn advance(&mut self) -> Token<'a> {
let token = self.peek();
if token.kind != Kind::Eof {
self.at += 1;
}
token
}
pub(crate) fn eat(&mut self, kind: Kind) -> bool {
if self.kind() == kind {
self.advance();
true
} else {
false
}
}
pub(crate) fn eat_keyword(&mut self, word: &str) -> bool {
if self.is_keyword(word) {
self.advance();
true
} else {
false
}
}
pub(crate) fn is_keyword(&self, word: &str) -> bool {
let token = self.peek();
token.kind == Kind::Ident && token.text == word
}
pub(crate) fn expect(&mut self, kind: Kind) -> Result<Token<'a>> {
if self.kind() == kind {
return Ok(self.advance());
}
Err(self.expected(kind.describe()))
}
pub(crate) fn expect_ident(&mut self) -> Result<&'a str> {
Ok(self.expect(Kind::Ident)?.text)
}
pub(crate) fn expected(&self, wanted: &str) -> PrismError {
let token = self.peek();
PrismError::Parse {
line: token.line,
message: format!(
"expected {wanted}, found {} at column {}",
token.describe(),
token.column
),
}
}
pub(crate) fn mark(&self) -> usize {
self.at
}
pub(crate) fn rewind(&mut self, mark: usize) {
self.at = mark;
}
}