use std::collections::HashMap;
use std::convert::TryFrom;
use std::sync::Arc;
use crate::atn::ATN;
use crate::atn_config_set::ATNConfigSet;
use crate::atn_state::{ATNDecisionState, ATNStateRef, ATNStateType};
use crate::dfa_serializer::DFASerializer;
use crate::dfa_state::{DFAState, DFAStateRef};
use crate::vocabulary::Vocabulary;
pub(crate) trait ScopeExt: Sized {
fn convert_with<T, F: FnOnce(Self) -> T>(self, f: F) -> T { f(self) }
fn run<T, F: FnOnce(&Self) -> T>(&self, f: F) -> T { f(self) }
fn modify_with<F: FnOnce(&mut Self)>(mut self, f: F) -> Self {
f(&mut self);
self
}
fn apply<F: FnOnce(&mut Self)>(&mut self, f: F) -> &mut Self {
f(self);
self
}
fn drop(self) {}
}
impl<Any: Sized> ScopeExt for Any {}
#[derive(Debug)]
pub struct DFA {
pub atn_start_state: ATNStateRef,
pub decision: isize,
pub states: Vec<DFAState>,
pub(crate) states_map: HashMap< u64, Vec<DFAStateRef>>,
pub s0: Option<DFAStateRef>,
is_precedence_dfa: bool,
}
impl DFA {
pub fn new(atn: Arc<ATN>, atn_start_state: ATNStateRef, decision: isize) -> DFA {
let mut dfa = DFA {
atn_start_state,
decision,
states: Default::default(),
states_map: Default::default(),
s0: Default::default(),
is_precedence_dfa: false,
};
dfa.states.push(DFAState::new_dfastate(
usize::max_value(),
Box::new(ATNConfigSet::new_base_atnconfig_set(true)),
));
if let ATNStateType::DecisionState {
state:
ATNDecisionState::StarLoopEntry {
is_precedence: true,
..
},
..
} = atn.states[atn_start_state].get_state_type()
{
dfa.is_precedence_dfa = true;
let mut precedence_state = DFAState::new_dfastate(
dfa.states.len(),
Box::new(ATNConfigSet::new_base_atnconfig_set(true)),
);
precedence_state.edges = vec![];
precedence_state.is_accept_state = false;
precedence_state.requires_full_context = false;
dfa.s0 = Some(precedence_state.state_number);
dfa.states.push(precedence_state)
}
dfa
}
pub fn get_precedence_start_state(&self, _precedence: isize) -> Option<DFAStateRef> {
if !self.is_precedence_dfa {
panic!("dfa is supposed to be precedence here");
}
self.s0.and_then(|s0| {
self.states[s0]
.edges
.get(_precedence as usize)
.and_then(|it| match *it {
0 => None,
x => Some(x),
})
})
}
pub fn set_precedence_start_state(&mut self, precedence: isize, _start_state: DFAStateRef) {
if !self.is_precedence_dfa {
panic!("set_precedence_start_state called for not precedence dfa")
}
if precedence < 0 {
return;
}
let precedence = precedence as usize;
if let Some(x) = &self.s0 {
self.states[*x].edges.apply(|edges| {
if edges.len() <= precedence {
edges.resize(precedence + 1, 0);
}
edges[precedence] = _start_state;
});
}
}
pub fn is_precedence_dfa(&self) -> bool { self.is_precedence_dfa }
pub fn set_precedence_dfa(&mut self, precedence_dfa: bool) {
self.is_precedence_dfa = precedence_dfa
}
pub fn to_string(&self, vocabulary: &dyn Vocabulary) -> String {
if self.s0.is_none() {
return String::new();
}
return format!(
"{}",
DFASerializer::new(self, &|x| vocabulary
.get_display_name(x as isize - 1)
.into_owned(),)
);
}
pub fn to_lexer_string(&self) -> String {
if self.s0.is_none() {
return String::new();
}
format!(
"{}",
DFASerializer::new(self, &|x| format!(
"'{}'",
char::try_from(x as u32).unwrap()
))
)
}
}