use crate::{ItemSet, LR1Conflict, LR1ResolvedConflict, LRConflictResolution, Rhs};
pub trait Config<'a, T, N, A> {
fn resolve_shift_reduce_conflict_in_favor_of_shift(&self) -> bool {
false
}
fn warn_on_resolved_conflicts(&self) -> bool {
false
}
fn on_resolved_conflict(&self, _conflict: LR1ResolvedConflict<'a, T, N, A>) {}
fn reduce_on(&self, _rhs: &Rhs<T, N, A>, _lookahead: Option<&T>) -> bool {
true
}
fn priority_of(&self, _rhs: &Rhs<T, N, A>, _lookahead: Option<&T>) -> i32 {
0
}
}
pub struct DefaultConfig<'a, T, N, A> {
_phantom: std::marker::PhantomData<(T, N, A)>,
_phantom2: std::marker::PhantomData<&'a ()>,
}
impl<'a, T, N, A> DefaultConfig<'a, T, N, A> {
pub fn new() -> Self {
DefaultConfig {
_phantom: std::marker::PhantomData,
_phantom2: std::marker::PhantomData,
}
}
}
impl<'a, T, N, A> Default for DefaultConfig<'a, T, N, A> {
fn default() -> Self {
DefaultConfig::new()
}
}
impl<'a, T, N, A> Config<'a, T, N, A> for DefaultConfig<'a, T, N, A> {}
pub(crate) struct ConflictWarner<'a, T, N, A> {
config: &'a dyn Config<'a, T, N, A>,
}
impl<'a, T, N, A> ConflictWarner<'a, T, N, A> {
pub fn new(config: &'a dyn Config<'a, T, N, A>) -> Self {
ConflictWarner { config }
}
pub fn warn_shift_reduce<'b>(
&self,
state: &'b ItemSet<'a, T, N, A>,
token: Option<&'a T>,
rule: (&'a N, &'a Rhs<T, N, A>),
) where
'a: 'b,
{
if self.config.warn_on_resolved_conflicts() {
self.config.on_resolved_conflict(LR1ResolvedConflict {
conflict: LR1Conflict::ShiftReduce {
state: state.clone(),
token,
rule,
},
applied_resolution: LRConflictResolution::ShiftOverReduce,
});
}
}
pub fn warn_reduce_reduce<'b>(
&self,
state: &'b ItemSet<'a, T, N, A>,
token: Option<&'a T>,
r1: (&'a N, &'a Rhs<T, N, A>),
r2: (&'a N, &'a Rhs<T, N, A>),
applied_resolution: LRConflictResolution,
) where
'a: 'b,
{
if self.config.warn_on_resolved_conflicts() {
self.config.on_resolved_conflict(LR1ResolvedConflict {
conflict: LR1Conflict::ReduceReduce {
state: state.clone(),
token,
r1,
r2,
},
applied_resolution,
});
}
}
}