use crate::position::*;
pub trait Token {
type Kind: PartialEq;
fn to_kind(&self) -> Self::Kind;
}
pub trait EndOfFile: Token {
fn eof() -> Self;
fn eof_kind() -> Self::Kind;
}
pub struct Parser<'a, T>
where
T: Token + EndOfFile,
{
check_points: Vec<usize>,
current: usize,
tokens: &'a [WithSpan<T>],
eof_token: &'a WithSpan<T>,
}
impl<'a, T> Parser<'a, T>
where
T: Token + EndOfFile,
{
pub fn new(tokens: &'a [WithSpan<T>], eof_token: &'a WithSpan<T>) -> Self {
Parser {
check_points: Vec::new(),
current: 0,
tokens: tokens,
eof_token: eof_token,
}
}
pub fn checkpoint(&mut self) {
self.check_points.push(self.current);
}
pub fn unwind(&mut self) {
self.check_points.pop();
}
pub fn rewind(&mut self) {
match self.check_points.pop() {
Some(checkpoint) => self.current = checkpoint,
None => {}
}
}
pub fn peek(&self) -> T::Kind {
return self.peek_token().value.to_kind();
}
pub fn peek_token(&self) -> &'a WithSpan<T> {
self.tokens.get(self.current).unwrap_or(&self.eof_token)
}
pub fn previous(&self) -> &'a WithSpan<T> {
return self.tokens.get(self.current - 1).unwrap_or(&self.eof_token);
}
pub fn is_at_end(&self) -> bool {
return self.peek() == T::eof_kind();
}
pub fn check(&self, token: T::Kind) -> bool {
if self.is_at_end() {
false
} else {
token == self.peek()
}
}
pub fn check_one_of(&mut self, tokens: &[T::Kind]) -> bool {
tokens.contains(&self.peek())
}
pub fn advance(&mut self) -> &'a WithSpan<T> {
if !self.is_at_end() {
self.current += 1;
}
return self.previous();
}
pub fn is_one_of<I: IntoIterator<Item = T::Kind>>(&mut self, tokens: I) -> bool {
for token in tokens {
if self.check(token) {
self.advance();
return true;
}
}
return false;
}
pub fn is(&mut self, token: T::Kind) -> bool {
if self.check(token) {
self.advance();
return true;
}
return false;
}
pub fn optional(&mut self, token: T::Kind) -> bool {
if self.check(token) {
self.advance();
return true;
}
return false;
}
pub fn drop_until(&mut self, tokens: &[T::Kind]) -> Option<Span> {
let mut dropped_span: Option<Span> = None;
while !self.is_at_end() && !tokens.contains(&self.peek()) {
let token = self.advance();
dropped_span = dropped_span
.map(|s| s.union(&token.span))
.or(Some(token.span));
}
dropped_span
}
}