use super::{BudgetTracker, ParseBudget};
use perl_ast_v2::Node;
use perl_lexer::TokenType;
use perl_position_tracking::Range;
#[derive(Debug, Clone)]
pub struct ParseError {
pub message: String,
pub range: Range,
pub expected: Vec<String>,
pub found: String,
pub recovery_hint: Option<String>,
}
impl ParseError {
pub fn new(message: String, range: Range) -> Self {
ParseError {
message,
range,
expected: Vec::new(),
found: String::new(),
recovery_hint: None,
}
}
pub fn with_expected(mut self, expected: Vec<String>) -> Self {
self.expected = expected;
self
}
pub fn with_found(mut self, found: String) -> Self {
self.found = found;
self
}
pub fn with_hint(mut self, hint: String) -> Self {
self.recovery_hint = Some(hint);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SyncPoint {
Semicolon,
CloseBrace,
Keyword,
Eof,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecoveryResult {
Recovered(usize),
AtSyncPoint,
BudgetExhausted,
ReachedEof,
}
pub trait ErrorRecovery {
fn create_error_node(
&mut self,
message: String,
expected: Vec<String>,
partial: Option<Node>,
) -> Node;
fn synchronize(&mut self, sync_points: &[SyncPoint]) -> bool;
fn recover_with_node(&mut self, error: ParseError) -> Node;
fn skip_until(&mut self, sync_points: &[SyncPoint]) -> usize;
fn skip_until_with_budget(
&mut self,
sync_points: &[SyncPoint],
budget: &ParseBudget,
tracker: &mut BudgetTracker,
) -> RecoveryResult;
fn is_sync_point(&self, sync_point: SyncPoint) -> bool;
}
pub trait ParserErrorRecovery {
fn parse_with_recovery(&mut self) -> (Node, Vec<ParseError>);
fn try_parse<F>(&mut self, parse_fn: F) -> Node
where
F: FnOnce(&mut Self) -> Option<Node>;
fn parse_list_with_recovery<F>(
&mut self,
parse_element: F,
separator: TokenType,
terminator: TokenType,
) -> Vec<Node>
where
F: Fn(&mut Self) -> Node;
}
pub trait StatementRecovery {
fn parse_statement_with_recovery(&mut self) -> Node;
fn parse_expression_with_recovery(&mut self) -> Node;
fn parse_block_with_recovery(&mut self) -> Node;
}