use crate::atn_simulator::IATNSimulator;
use crate::interval_set::IntervalSet;
use crate::parser::Parser;
use crate::rule_context::states_stack;
use crate::token::{OwningToken, Token};
use crate::token_factory::TokenFactory;
use crate::transition::PredicateTransition;
use crate::tree::TreeNode;
use std::borrow::Cow;
use std::error::Error;
use std::fmt;
use std::fmt::Formatter;
use std::fmt::{Debug, Display};
use std::ops::Deref;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum ANTLRErrorKind {
LexerNoAltError {
start_index: isize,
},
NoAltError(NoViableAltError),
InputMismatchError(InputMisMatchError),
PredicateError(FailedPredicateError),
IllegalStateError(String),
CustomError(String),
FallThrough(Arc<dyn Error + Send + Sync + 'static>),
OtherError(Arc<dyn Error + Send + Sync + 'static>),
}
#[derive(Debug, Clone)]
pub struct ANTLRError(pub Box<ANTLRErrorKind>);
impl Display for ANTLRError {
fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
match self.0.as_ref() {
ANTLRErrorKind::FallThrough(err) | ANTLRErrorKind::OtherError(err) => {
write!(_f, "{}", err)
}
_ => <Self as Debug>::fmt(self, _f),
}
}
}
impl Error for ANTLRError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self.0.as_ref() {
ANTLRErrorKind::FallThrough(x) => Some(x.as_ref()),
ANTLRErrorKind::OtherError(x) => Some(x.as_ref()),
_ => None,
}
}
}
impl From<ANTLRErrorKind> for ANTLRError {
fn from(value: ANTLRErrorKind) -> Self {
ANTLRError(Box::new(value))
}
}
impl From<Box<dyn Error + Send + Sync + 'static>> for ANTLRError {
fn from(value: Box<dyn Error + Send + Sync + 'static>) -> Self {
ANTLRErrorKind::OtherError(Arc::from(value)).into()
}
}
impl AsRef<ANTLRErrorKind> for ANTLRError {
fn as_ref(&self) -> &ANTLRErrorKind {
self.0.as_ref()
}
}
impl Deref for ANTLRError {
type Target = ANTLRErrorKind;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl ANTLRError {
pub fn custom_error(msg: String) -> Self {
ANTLRErrorKind::CustomError(msg).into()
}
pub fn lexer_no_alt(start_index: isize) -> Self {
ANTLRErrorKind::LexerNoAltError { start_index }.into()
}
pub fn illegal_state(msg: String) -> Self {
ANTLRErrorKind::IllegalStateError(msg).into()
}
pub fn fall_through<E: Error + Send + Sync + 'static>(err: E) -> Self {
ANTLRErrorKind::FallThrough(Arc::new(err)).into()
}
pub fn memory_limit_exceeded(
allocation_limit_bytes: usize,
context_cache_bytes: usize,
dfa_cache_bytes: usize,
) -> Self {
ANTLRErrorKind::FallThrough(Arc::new(MemoryLimitExceededError {
allocation_limit_bytes,
context_cache_bytes,
dfa_cache_bytes,
}))
.into()
}
pub fn no_alt<'input, 'arena, TF, P>(recog: &mut P) -> Self
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
ANTLRErrorKind::NoAltError(NoViableAltError {
base: BaseRecognitionError {
message: "".to_string(),
offending_token: OwningToken::from(recog.get_current_token() as &dyn Token),
offending_state: recog.get_state(),
states_stack: states_stack(recog.get_current_context()).collect(),
},
start_token: OwningToken::from(recog.get_current_token() as &dyn Token),
})
.into()
}
pub fn no_alt_full<'input, 'arena, TF, P>(
recog: &mut P,
start_token: OwningToken,
offending_token: OwningToken,
) -> Self
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
ANTLRErrorKind::NoAltError(NoViableAltError {
base: BaseRecognitionError {
message: "".to_string(),
offending_token,
offending_state: recog.get_state(),
states_stack: states_stack(recog.get_current_context()).collect(), },
start_token,
})
.into()
}
pub fn input_mismatch<'input, 'arena, TF, P>(recognizer: &mut P) -> Self
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
ANTLRErrorKind::InputMismatchError(InputMisMatchError {
base: BaseRecognitionError::new(recognizer),
})
.into()
}
pub fn input_mismatch_with_state<'input, 'arena, TF, P>(
recognizer: &mut P,
offending_state: i32,
ctx: &'arena TreeNode<'input, 'arena, P::Node>,
) -> Self
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let mut a = InputMisMatchError {
base: BaseRecognitionError::new(recognizer),
};
a.base.offending_state = offending_state;
a.base.states_stack = states_stack(ctx).collect();
ANTLRErrorKind::InputMismatchError(a).into()
}
pub fn failed_predicate<'input, 'arena, TF, P>(
recog: &mut P,
predicate: Option<String>,
msg: Option<String>,
) -> Self
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let tr = recog
.get_interpreter()
.atn()
.get_state(recog.get_state())
.get_transitions()
.first()
.unwrap();
let (rule_index, _) = if let Some(pr) = tr.try_as::<PredicateTransition>() {
(pr.rule_index(), pr.pred_index())
} else {
(0, 0)
};
ANTLRErrorKind::PredicateError(FailedPredicateError {
base: BaseRecognitionError {
message: msg.unwrap_or_else(|| {
format!(
"failed predicate: {}",
predicate.as_deref().unwrap_or("None")
)
}),
offending_token: OwningToken::from(recog.get_current_token() as &dyn Token),
offending_state: recog.get_state(),
states_stack: states_stack(recog.get_current_context()).collect(), },
rule_index,
predicate: predicate.unwrap_or_default(),
})
.into()
}
pub fn is_recoverable(&self) -> bool {
!matches!(self.0.as_ref(), ANTLRErrorKind::FallThrough(_))
}
pub fn get_offending_token(&self) -> Option<&OwningToken> {
Some(match self.0.as_ref() {
ANTLRErrorKind::NoAltError(e) => &e.base.offending_token,
ANTLRErrorKind::InputMismatchError(e) => &e.base.offending_token,
ANTLRErrorKind::PredicateError(e) => &e.base.offending_token,
_ => return None,
})
}
}
#[derive(Debug, Clone)]
pub struct MemoryLimitExceededError {
pub context_cache_bytes: usize,
pub dfa_cache_bytes: usize,
pub allocation_limit_bytes: usize,
}
impl Display for MemoryLimitExceededError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"Memory limit of {}B exceeded: total allocated Antlr cache size {}B\
(context cache {}B/DFA {}B)",
self.allocation_limit_bytes,
self.context_cache_bytes + self.dfa_cache_bytes,
self.context_cache_bytes,
self.dfa_cache_bytes
)
}
}
impl Error for MemoryLimitExceededError {}
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub struct BaseRecognitionError {
pub message: String,
pub offending_token: OwningToken,
pub offending_state: i32,
states_stack: Vec<i32>, }
impl BaseRecognitionError {
pub fn get_expected_tokens<'a, 'input, 'arena, TF, P>(
&'a self,
recognizer: &P,
) -> Cow<'a, IntervalSet>
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
recognizer
.get_interpreter()
.atn()
.get_expected_tokens(self.offending_state, self.states_stack.iter().copied())
}
fn new<'input, 'arena, TF, P>(recog: &mut P) -> BaseRecognitionError
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
BaseRecognitionError {
message: "".to_string(),
offending_token: OwningToken::from(recog.get_current_token() as &dyn Token),
offending_state: recog.get_state(),
states_stack: states_stack(recog.get_current_context()).collect(),
}
}
}
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub struct NoViableAltError {
pub base: BaseRecognitionError,
pub start_token: OwningToken,
}
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub struct InputMisMatchError {
pub base: BaseRecognitionError,
}
#[derive(Debug, Clone)]
#[allow(missing_docs)]
pub struct FailedPredicateError {
pub base: BaseRecognitionError,
pub rule_index: i32,
pub predicate: String,
}