use std::{collections::VecDeque, sync::mpsc::Sender};
use kind_report::data::Diagnostic;
use kind_span::Range;
use crate::{diagnostic::SyntaxDiagnostic, lexer::tokens::Token, Lexer};
pub struct Parser<'a> {
lexer: Lexer<'a>,
queue: VecDeque<(Token, Range)>,
breaks: VecDeque<bool>,
dignostic_channel: Sender<Box<dyn Diagnostic>>,
eaten: u32,
pub failed: bool,
}
impl<'a> Parser<'a> {
pub fn new(mut lexer: Lexer<'a>, sender: Sender<Box<dyn Diagnostic>>) -> Parser<'a> {
let mut queue = VecDeque::with_capacity(3);
let mut breaks = VecDeque::with_capacity(3);
for _ in 0..3 {
let (is_break, token, range) = lexer.get_next_no_error(sender.clone());
breaks.push_back(is_break);
queue.push_back((token, range));
}
Parser {
lexer,
queue,
breaks,
dignostic_channel: sender,
eaten: 0,
failed: false,
}
}
pub fn advance(&mut self) -> (Token, Range) {
let cur = self.queue.pop_front().unwrap();
self.breaks.pop_front();
let (is_break, token, range) = self.lexer.get_next_no_error(self.dignostic_channel.clone());
self.breaks.push_back(is_break);
self.queue.push_back((token, range));
self.eaten += 1;
cur
}
pub fn is_linebreak(&self) -> bool {
self.breaks[0]
}
#[inline]
pub fn get(&self) -> &Token {
&self.queue[0].0
}
#[inline]
pub fn peek(&self, lookhead: usize) -> &Token {
&self.queue[lookhead].0
}
#[inline]
pub fn range(&self) -> Range {
self.queue[0].1
}
#[inline]
pub fn fail<T>(&mut self, expect: Vec<Token>) -> Result<T, SyntaxDiagnostic> {
Err(SyntaxDiagnostic::UnexpectedToken(
self.get().clone(),
self.range(),
expect,
))
}
pub fn send_dignostic(&mut self, diagnostic: SyntaxDiagnostic) {
self.dignostic_channel.send(Box::new(diagnostic)).unwrap();
self.failed = true;
}
pub fn eat_closing_keyword(
&mut self,
expect: Token,
range: Range,
) -> Result<(), SyntaxDiagnostic> {
if !self.check_and_eat(expect.clone()) {
if self.get().is_eof() {
Err(SyntaxDiagnostic::Unclosed(range))
} else {
self.fail(vec![expect])
}
} else {
Ok(())
}
}
pub fn eat_variant(&mut self, expect: Token) -> Result<(Token, Range), SyntaxDiagnostic> {
if self.get().same_variant(&expect) {
Ok(self.advance())
} else {
self.fail(vec![expect])
}
}
pub fn eat_id(&mut self, expect: &str) -> Result<(Token, Range), SyntaxDiagnostic> {
match self.get() {
Token::LowerId(x) if x == expect => Ok(self.advance()),
_ => self.fail(vec![Token::LowerId(expect.to_string())]),
}
}
pub fn eat<T>(&mut self, expect: fn(&Token) -> Option<T>) -> Result<T, SyntaxDiagnostic> {
match expect(self.get()) {
None => self.fail(vec![]),
Some(res) => {
self.advance();
Ok(res)
}
}
}
pub fn check_and_eat(&mut self, expect: Token) -> bool {
if self.get().same_variant(&expect) {
self.advance();
true
} else {
false
}
}
pub fn check_actual(&mut self, expect: Token) -> bool {
self.get().same_variant(&expect)
}
pub fn check_actual_id(&self, expect: &str) -> bool {
matches!(self.get(), Token::LowerId(x) if x == expect)
}
pub fn try_single<T>(
&mut self,
fun: &dyn Fn(&mut Parser<'a>) -> Result<T, SyntaxDiagnostic>,
) -> Result<Option<T>, SyntaxDiagnostic> {
let current = self.eaten;
match fun(self) {
Err(_) if current == self.eaten => Ok(None),
Err(err) => Err(err),
Ok(res) => Ok(Some(res)),
}
}
}