extern crate bit_set;
extern crate multimap;
use super::*;
use multimap::MultiMap;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied,Vacant};
use std::sync::mpsc;
pub trait IntoDFA {
fn dfa(self) -> Result<Automaton>;
}
trait HasStates {
fn add(&mut self, s: StateID) -> &mut NFAStates;
fn plus(self, s: StateID) -> NFAStates;
fn union(mut self, other: NFAStates) -> NFAStates;
}
type NFAStates = bit_set::BitSet;
struct StateMapper {
dfa_states: Vec<State>,
map: HashMap<NFAStates,StateID>,
state_notifier: mpsc::Sender<StateMapping>,
}
type StateMapping = (NFAStates, StateID);
impl IntoDFA for Automaton {
fn dfa(self) -> Result<Automaton> {
let all_nfa_states = (0..self.states.len())
.map(|s| s as StateID)
.collect::<Vec<_>>()
;
let (mut state_map, state_rx) = StateMapper::new();
let mut dfa_transitions = MultiMap::<StateID, (Transition, StateID)>::new();
try![state_map.add_epsilon_closures(&all_nfa_states, &self)];
while let Ok((nfa_source,dfa_source)) = state_rx.try_recv() {
let mut state_transitions = HashMap::<&Transition, NFAStates>::new();
for (s, transitions) in self.transitions.iter_all() {
if !nfa_source.contains(*s as usize) {
continue
}
for &(ref transition, destination) in transitions {
if let Event::Epsilon = transition.cause {
continue
}
let dest_closure = epsilon_closure(destination, &self.transitions);
match state_transitions.entry(transition) {
Occupied(ref mut o) => { o.get_mut().union_with(&dest_closure); },
Vacant(v) => { v.insert(dest_closure); },
};
}
}
for (transition, destination) in state_transitions {
let dest = try![state_map.dfa_state(destination, &self)];
dfa_transitions.insert(dfa_source, (transition.clone(), dest));
}
}
Ok(Automaton {
name: self.name,
description: self.description,
states: state_map.dfa_states,
transitions: dfa_transitions,
variables: self.variables,
})
}
}
impl HasStates for NFAStates {
fn add(&mut self, s: StateID) -> &mut NFAStates {
self.insert(s as usize);
self
}
fn plus(mut self, s: StateID) -> NFAStates {
self.add(s);
self
}
fn union(mut self, other: NFAStates) -> NFAStates {
self.union_with(&other);
self
}
}
impl StateMapper {
fn new() -> (StateMapper, mpsc::Receiver<StateMapping>) {
let (tx, rx): (mpsc::Sender<StateMapping>, mpsc::Receiver<StateMapping>) = mpsc::channel();
let map = StateMapper {
dfa_states: Vec::new(),
map: HashMap::new(),
state_notifier: tx,
};
(map, rx)
}
fn dfa_state(&mut self, nfa_states: NFAStates, a: &Automaton) -> Result<StateID> {
if nfa_states.is_empty() {
return Err(Error::Automaton("empty set of NFA states".to_string()))
}
let tmp_states = nfa_states.clone();
match self.map.entry(nfa_states) {
Occupied(entry) => Ok(*entry.get()),
Vacant(entry) => {
let mut mask:Mask = 0;
let mut accepting = false;
for i in tmp_states.iter() {
let ref s = a.states[i];
if mask == 0 {
mask = s.variable_mask;
} else if mask != s.variable_mask {
return Err(
Error::Automaton(
format!["inconsistent masks in {:?}: {} has {}, not {}",
tmp_states, i, s.variable_mask, mask])
)
}
accepting |= s.accepting;
}
let id = self.dfa_states.len() as StateID;
let name = Some(format!["{:?}", tmp_states]);
self.dfa_states.push(State::new(mask, accepting, name));
try![self.state_notifier
.send((tmp_states, id))
.map_err(|e| Error::Internal(format!["channel error: {}", e]))];
entry.insert(id);
Ok(id)
},
}
}
fn add_epsilon_closures(&mut self, states: &[StateID], a: &Automaton) -> Result<()> {
let mut done = NFAStates::new();
for &s in states {
if done.contains(s as usize) {
continue
}
let e_closure = epsilon_closure(s, &a.transitions);
done.union_with(&e_closure);
try![self.dfa_state(e_closure, a)];
}
Ok(())
}
}
fn epsilon_closure(source: StateID, transitions: &TransitionMap) -> NFAStates {
let empty = Vec::<(Transition,StateID)>::new();
transitions
.get_vec(&source)
.unwrap_or(&empty)
.into_iter()
.map(|x| match x {
&(Transition { cause:Event::Epsilon, .. }, ref dest) => Some(dest),
_ => None,
})
.filter(Option::is_some)
.map(Option::unwrap)
.map(|&source| epsilon_closure(source, transitions))
.fold(NFAStates::new(), HasStates::union)
.plus(source)
}