#![allow(dead_code)]
use std::collections::HashSet;
use std::collections::LinkedList;
use std::fmt::Write;
use std::iter::FromIterator;
use std::rc::Rc;
use std::vec::Vec;
use crate::matcher::{Matchee, Matcher};
pub type StateGraph = Vec<State>;
pub type StateRef = usize;
pub struct CompiledRE(pub(crate) StateGraph);
#[derive(Debug, Default, Clone)]
pub struct State {
pub out: Option<StateRef>,
pub out1: Option<StateRef>,
pub matcher: Option<Rc<Box<dyn Matcher>>>,
pub sub: Option<Submatch>,
}
#[derive(Clone, Debug)]
pub enum Submatch {
Start,
End,
}
impl State {
pub fn patch(&mut self, next: StateRef) {
if self.out.is_none() {
self.out = Some(next);
} else if self.out1.is_none() {
self.out1 = Some(next);
} else {
unimplemented!()
}
}
pub fn is_last(&self) -> bool {
self.out.is_none() && self.out1.is_none()
}
pub fn has_matcher(&self) -> bool {
self.matcher.is_some()
}
pub fn matches(&self, me: &Matchee) -> Option<(bool, usize)> {
self.matcher.as_ref().map(|m| m.matches(me))
}
pub fn next_states(&self) -> (Option<StateRef>, Option<StateRef>) {
(self.out.clone(), self.out1.clone())
}
pub fn to_string(&self) -> String {
format!(
"m:{} sub:{}",
if let Some(ref m) = self.matcher {
format!("{:?}", m)
} else {
"_".to_string()
},
if let Some(ref s) = self.sub {
format!("{:?}", s)
} else {
"".to_string()
}
)
}
}
pub fn dot(stateg: &StateGraph) -> String {
let mut result = String::new();
let mut visited = HashSet::new();
let mut todo = LinkedList::from_iter(vec![0 as StateRef]);
loop {
if todo.is_empty() {
break;
}
let current = todo.pop_front().unwrap();
if visited.contains(¤t) {
continue;
}
visited.insert(current);
for next in [stateg[current].out.clone(), stateg[current].out1.clone()].iter() {
if let &Some(nextid) = next {
let o = &stateg[nextid];
write!(
&mut result,
"\"{} {}\" -> \"{} {}\";\n",
current,
stateg[current].to_string(),
nextid,
o.to_string(),
)
.unwrap();
if !visited.contains(&nextid) {
todo.push_front(nextid);
}
}
}
}
result
}