#![allow(dead_code)]
use std::cell::RefCell;
use std::collections::{HashSet, HashMap};
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use crate::matcher::Matchee;
use crate::state::{StateGraph, StateRef, Submatch};
#[derive(Clone, Debug)]
pub struct MatchState {
node: StateRef,
matchee: Matchee,
submatches: Rc<RefCell<Vec<Option<usize>>>>,
submatches_todo: Rc<Vec<usize>>,
debug: bool,
}
impl MatchState {
fn new(s: &str, ws: StateRef) -> MatchState {
MatchState {
node: ws,
matchee: Matchee::from_string(s),
submatches: Rc::new(RefCell::new(vec![None; s.len()])),
submatches_todo: Rc::new(Vec::with_capacity(4)),
debug: false,
}
}
fn fork(&self, next: StateRef, advance: usize) -> MatchState {
let mut n = self.clone();
n.matchee.advance(advance);
n.node = next;
n
}
fn update(&mut self, next: StateRef, advance: usize) {
self.matchee.advance(advance);
self.node = next;
}
fn reset(&mut self, new_start: usize) {
self.submatches = Rc::new(RefCell::new(vec![None; self.matchee.len()]));
self.submatches_todo = Rc::new(Vec::with_capacity(4));
self.matchee.reset(new_start);
}
fn start_submatch(&mut self) {
if self.matchee.pos() < self.matchee.len() {
let mut new_submatches = self.submatches_todo.deref().clone();
new_submatches.push(self.matchee.pos());
self.submatches_todo = Rc::new(new_submatches);
}
}
fn stop_submatch(&mut self) {
if self.submatches_todo.deref().len() > 0 {
let mut new_submatches = self.submatches_todo.deref().clone();
let begin = new_submatches.pop().unwrap();
self.submatches_todo = Rc::new(new_submatches);
self.submatches.borrow_mut()[begin] = Some(self.matchee.pos());
}
}
fn debug(&self, sg: &StateGraph) -> String {
let m = self.matchee.string();
let out = sg[self.node]
.out
.map_or("".to_owned(), |ix| sg[ix].to_string());
let out1 = sg[self.node]
.out1
.map_or("".to_owned(), |ix| sg[ix].to_string());
let full = format!(
"{} (<{}> next: 1. <{:?}> {} 2. <{:?}> {})\n",
m, self.node, sg[self.node].out, out, sg[self.node].out1, out1
);
full
}
}
pub fn do_match(sg: &StateGraph, s: &str) -> (bool, Vec<(usize, usize)>) {
let mut ms = MatchState::new(s, 0);
let (mut i, len) = (0, s.len());
while i < len || i == 0 {
ms.reset(i);
let m = start_match(sg, ms.clone());
match m {
(false, skip, _) => i = skip + 1,
(true, _, matchpos) => {
let mut matches = vec![];
for i in 0..matchpos.len() {
if matchpos[i].is_some() {
matches.push((i, matchpos[i].unwrap()));
}
}
return (true, matches);
}
}
}
(false, vec![])
}
fn state_key(m: &MatchState) -> (usize, StateRef) {
(m.matchee.pos(), m.node)
}
pub fn start_match(sg: &StateGraph, m: MatchState) -> (bool, usize, Vec<Option<usize>>) {
let mut states_map = HashMap::new();
let mut states_map_next = HashMap::new();
states_map.insert(state_key(&m), m);
let (mut ismatch, mut matches) = (false, vec![]);
let mut longestmatch = 0;
let mut longest_partial_match = 0;
loop {
if states_map.is_empty() {
break;
}
for (_, mut matchst) in states_map.drain() {
let (next1, next2) = sg[matchst.node].next_states();
let sub = sg[matchst.node].sub.as_ref();
match sub {
Some(&Submatch::Start) => matchst.start_submatch(),
Some(&Submatch::End) => matchst.stop_submatch(),
None => {}
}
if next1.is_none()
&& next2.is_none()
&& (matchst.matchee.pos() > longestmatch || longestmatch == 0)
{
ismatch = true;
matches = matchst.submatches.borrow().clone();
longestmatch = matchst.matchee.pos();
continue;
}
if matchst.matchee.pos() > longest_partial_match {
longest_partial_match = matchst.matchee.pos();
}
let mut advance_by = 0;
if let Some((matched, howmany)) = sg[matchst.node].matches(&matchst.matchee) {
if !matched {
continue;
}
advance_by = howmany;
}
if next1.is_some() && next2.is_some() {
let nextst = matchst.fork(next1.unwrap(), advance_by);
states_map_next.entry(state_key(&nextst)).or_insert(nextst);
matchst.update(next2.unwrap(), advance_by);
states_map_next.entry(state_key(&matchst)).or_insert(matchst);
} else if let Some(n1) = next1 {
matchst.update(n1, advance_by);
states_map_next.entry(state_key(&matchst)).or_insert(matchst);
} else if let Some(n2) = next2 {
matchst.update(n2, advance_by);
states_map_next.entry(state_key(&matchst)).or_insert(matchst);
}
}
mem::swap(&mut states_map, &mut states_map_next);
}
return (ismatch, longest_partial_match, matches);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::compile::*;
use crate::parse;
use crate::repr::*;
use crate::state::*;
fn simple_re0() -> Pattern {
parse::parse("aa+$").unwrap()
}
fn raw_re() -> Pattern {
Pattern::Concat(vec![
Pattern::CharRange('a', 'a'),
Pattern::Submatch(Box::new(Pattern::Alternate(vec![
(Pattern::Char('b')),
(Pattern::Char('c')),
]))),
Pattern::Submatch(Box::new(Pattern::Repeated(Box::new(
Repetition::ZeroOrOnce(Pattern::Str("xx".to_string())),
)))),
Pattern::Anchor(AnchorLocation::End),
])
}
#[test]
fn test_match_simple() {
let re = simple_re0();
println!("{:?}", re);
println!("{:?}", do_match(&start_compile(&re), "aaab"));
let dot = dot(&start_compile(&re));
println!("digraph st {{ {} }}", dot);
}
}