use crate::error::Error;
use crate::parser::error::Result;
use crate::parser::error::Type::{MissingOrUnexpectedToken, UnexpectedEof, Unrecoverable};
use crate::parser::lexer::Token;
use crate::parser::{error, Parser};
use crate::Span;
impl<'lt, 'source_map> Parser<'lt, 'source_map> {
#[inline]
pub fn parse_list_tail<F>(
&mut self,
mut parse_list_item: F,
end: Token,
consume_end: bool,
) -> Result
where
F: FnMut(&mut Self) -> Result,
{
self.parse_and_recover_on_tokens(Token::Comma, end, consume_end, false, |parser| {
match parser.next_with_span_and_previous_end()? {
(Token::Comma, _, _) => parse_list_item(parser).map(|_| true),
(_, source, expected_at) => Err(Error {
source,
error_type: MissingOrUnexpectedToken {
expected: vec![Token::Comma, end],
expected_at,
},
}),
}
})?;
Ok(())
}
#[inline]
pub fn parse_list<F>(&mut self, mut parse_list_item: F, end: Token, consume_end: bool) -> Result
where
F: FnMut(&mut Self) -> Result,
{
if let Err(error) = parse_list_item(self) {
self.non_critical_errors.push(error);
if self.recover_on(Token::Comma, end, consume_end, false)? {
return Ok(());
}
}
self.parse_list_tail(parse_list_item, end, consume_end)?;
Ok(())
}
#[inline]
pub fn parse_and_recover_on_tokens<F>(
&mut self,
recover: Token,
end: Token,
consume_end: bool,
consume_recover: bool,
mut parse: F,
) -> Result
where
F: FnMut(&mut Self) -> Result<bool>,
{
let mut recovered = true;
loop {
let error = match self.look_ahead_with_span() {
Ok((token, _)) if token == end => {
if consume_end {
self.consume_lookahead();
}
break;
}
Ok((Token::EOF, source)) => {
self.unrecoverable = true;
return Err(Error {
error_type: UnexpectedEof {
expected: vec![end],
},
source,
});
}
Ok(_) => match parse(self) {
Ok(false) => break,
Ok(true) => {
recovered = true;
continue;
}
Err(error) => error,
},
Err(error) => error,
};
if recovered {
self.non_critical_errors.push(error);
recovered = false;
}
if self.recover_on(end, recover, consume_end, consume_recover)? {
break;
}
}
Ok(())
}
#[inline]
pub fn recover_on(
&mut self,
end: Token,
recover: Token,
consume_end: bool,
consume_recover: bool,
) -> Result<bool> {
let start = self.preprocessor.current_start();
if self.unrecoverable {
return Err(Error {
error_type: Unrecoverable,
source: Span::new_short_empty_span(0),
});
}
loop {
match self.look_ahead_with_span() {
Ok((token, _)) if token == end => {
if consume_end {
self.consume_lookahead();
}
return Ok(true);
}
Ok((token, _)) if token == recover => {
if consume_recover {
self.consume_lookahead();
}
return Ok(false);
}
Ok((Token::EOF, source)) => {
self.consume_lookahead();
self.unrecoverable = true;
return Err(Error {
error_type: UnexpectedEof {
expected: vec![end],
},
source: Span::new(start - 1, source.get_start() - 1),
});
}
Ok(_) => {
self.consume_lookahead();
}
Err(error) => {
self.consume_lookahead();
self.non_critical_errors.push(error);
}
}
}
}
#[inline]
pub fn unrecoverable_error(&mut self, spanned_error: error::Type) -> error::Error {
let start = self.preprocessor.current_start();
self.unrecoverable = true;
loop {
if let Ok(Token::EOF) = self.next() {
return Error {
error_type: spanned_error,
source: Span::new(start - 1, self.preprocessor.current_start() - 1),
};
}
}
}
}
macro_rules! synchronize {
($parser:expr; $($production:stmt;),* sync $gen_token:expr => {$end_token:path => end , $($token:path => $parse:expr,)+}) => {
'mainloop: loop {
let mut try_parse = || {
$($production),*
let (token,source) = $gen_token?;
match token {
$end_token => return Ok(true),
$($token => $parse?,)+
_ => return Err(Error {
error_type: error::Type::UnexpectedToken {
expected: vec![$end_token $(,$token)+],
},
source,
}),
}
Ok(false)
};
let error = match try_parse() {
Ok(true) => break 'mainloop,
Ok(false) => continue,
Err(error) => error,
};
$parser.non_critical_errors.push(error);
loop {
match $parser.look_ahead() {
$(Ok($token) => break,)+
Ok($end_token) => break 'mainloop,
Ok(_) => {
$parser.lookahead.take();
}
Err(error) => {
$parser.lookahead.take();
$parser.non_critical_errors.push(error);
}
}
}
}
};
}