use crate::fa::{MultiFA, State};
use crate::mir::Mir;
use std::collections::HashMap;
use std::hash::Hash;
use std::{fmt, io};
#[derive(Debug)]
pub struct NFA<S, T>
where
S: Eq + Hash,
{
fa: MultiFA<Option<(S, S)>>,
tags: HashMap<usize, T>,
}
impl<S, T> NFA<S, T>
where
S: Eq + Hash,
{
pub fn new(mir: Mir<S, T>) -> Self {
match mir {
Mir::Empty => Self::new_nfa_with_symbol(None),
Mir::Range(l, r) => Self::new_nfa_with_symbol(Some((l, r))),
Mir::Concat(c) => c.into_iter().map(Self::new).reduce(Self::concat).unwrap(),
Mir::Alter(mut a) => {
if a.len() == 1 {
let (mir, tag) = a.swap_remove(0);
let mut nfa = Self::new(mir);
if let Some(tag) = tag {
let fs = nfa.normalize();
nfa.fa.set_final_state(fs);
nfa.tags.insert(fs, tag);
}
nfa
} else {
a.into_iter()
.map(|(mir, tag)| (Self::new(mir), tag))
.reduce(Self::alter)
.unwrap()
.0
}
}
Mir::Kleene(k) => {
let mut nfa = Self::new(*k);
let id = nfa.normalize();
let init = nfa.fa.init_id();
nfa.fa.state_mut(id).unwrap().add(None, init);
nfa.fa.set_final_state(init);
nfa
}
}
}
fn new_nfa_with_symbol(sym: Option<(S, S)>) -> Self {
let mut fa = MultiFA::new();
let fs = fa.add_final_state();
fa.init_mut().add(sym, fs);
Self {
fa,
tags: HashMap::new(),
}
}
fn alter(
(mut nfa1, tag1): (Self, Option<T>),
(mut nfa2, tag2): (Self, Option<T>),
) -> (Self, Option<T>) {
let fs1 = nfa1.normalize();
nfa1.fa.set_final_state(fs1);
if let Some(tag1) = tag1 {
nfa1.tags.insert(fs1, tag1);
}
nfa1.fa.init_mut().add(None, nfa2.fa.init_id());
if let Some(tag2) = tag2 {
let fs2 = nfa2.normalize();
nfa2.fa.set_final_state(fs2);
nfa1.tags.insert(fs2, tag2);
}
nfa1.fa.union(nfa2.fa);
nfa1.tags.extend(nfa2.tags);
(nfa1, None)
}
fn concat(mut nfa1: Self, nfa2: Self) -> Self {
let fs1 = nfa1.normalize();
nfa1.fa.state_mut(fs1).unwrap().add(None, nfa2.fa.init_id());
nfa1.fa.union(nfa2.fa);
nfa1.tags.extend(nfa2.tags);
nfa1
}
fn normalize(&mut self) -> usize {
let untagged = self
.fa
.finals()
.iter()
.copied()
.find(|id| !self.tags.contains_key(id));
let target = if let Some(untagged) = untagged {
self.fa.set_normal_state(untagged);
untagged
} else {
self.fa.add_state()
};
for id in self.fa.finals().clone() {
if id != target {
self.fa.state_mut(id).unwrap().add(None, target);
if !self.tags.contains_key(&id) {
self.fa.set_normal_state(id);
}
}
}
target
}
pub fn into_fa_tags(self) -> FATags<S, T> {
(self.fa, self.tags)
}
pub fn dump<W>(&self, writer: &mut W) -> io::Result<()>
where
S: fmt::Debug,
W: io::Write,
{
self.fa.dump(writer)
}
}
impl<S, T> From<Mir<S, T>> for NFA<S, T>
where
S: Eq + Hash,
{
fn from(mir: Mir<S, T>) -> Self {
Self::new(mir)
}
}
pub type FATags<S, T> = (MultiFA<Option<(S, S)>>, HashMap<usize, T>);