use std::fmt::{Debug, Formatter, Error as FmtError};
use std::u32;
pub type TableStateIdx = u32;
#[derive(Clone)]
pub struct TableInsts<Ret> {
pub log_num_classes: u32,
pub byte_class: Vec<u8>,
pub table: Vec<TableStateIdx>,
pub accept: Vec<Option<Ret>>,
pub accept_at_eoi: Vec<Option<Ret>>,
}
impl<Ret: Debug> Debug for TableInsts<Ret> {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
try!(f.write_fmt(format_args!("TableInsts ({} log_classes, {} instructions):\n",
self.log_num_classes,
self.accept.len())));
try!(f.write_str("Byte classes: "));
try!(f.debug_map()
.entries((0..256).map(|b| (b, self.byte_class[b])))
.finish());
let num_classes = 1 << self.log_num_classes;
for idx in 0..self.accept.len() {
try!(f.write_fmt(format_args!("State {}:\n", idx)));
try!(f.debug_map()
.entries((0usize..num_classes)
.map(|c| (c, self.table[(idx << self.log_num_classes) + c]))
.filter(|x| x.1 != u32::MAX))
.finish());
try!(f.write_str("\n"));
}
try!(f.write_str("Accept: "));
for idx in 0..self.accept.len() {
if let Some(ref ret) = self.accept[idx] {
try!(f.write_fmt(format_args!("{} -> {:?}, ", idx, ret)));
}
}
try!(f.write_str("Accept_at_eoi: "));
for idx in 0..self.accept_at_eoi.len() {
if let Some(ref ret) = self.accept_at_eoi[idx] {
try!(f.write_fmt(format_args!("{} -> {:?}, ", idx, ret)));
}
}
Ok(())
}
}
impl<Ret: Copy + Debug> TableInsts<Ret> {
fn next_state(&self, state: usize, input: u8) -> Option<usize> {
let class = self.byte_class[input as usize];
let next_state = self.table[(state << self.log_num_classes) + class as usize];
if next_state != u32::MAX {
Some(next_state as usize)
} else {
None
}
}
pub fn num_states(&self) -> usize {
self.accept.len()
}
pub fn find_from(&self, input: &[u8], pos: usize, state: usize)
-> Result<(usize, Ret), usize> {
let mut state = state as u32;
let mut ret = Err(input.len());
if state as usize >= self.accept.len() {
panic!("BUG");
}
for pos in pos..input.len() {
if let Some(accept_ret) = self.accept[state as usize] {
ret = Ok((pos, accept_ret));
}
let class = self.byte_class[input[pos] as usize];
state = self.table[((state as usize) << self.log_num_classes) + class as usize];
if state as usize >= self.accept.len() {
if ret.is_err() {
return Err(pos);
}
break;
}
}
if (state as usize) < self.accept.len() {
if let Some(accept_ret) = self.accept_at_eoi[state as usize] {
return Ok((input.len(), accept_ret))
}
}
ret
}
pub fn longest_backward_find_from(&self, input: &[u8], pos: usize, mut state: usize)
-> Option<(usize, Ret)> {
let mut ret = None;
for pos in (0..pos).rev() {
if let Some(next_ret) = self.accept[state] {
ret = Some((pos + 1, next_ret));
}
if let Some(next_state) = self.next_state(state, input[pos]) {
state = next_state;
} else {
return ret;
}
}
if let Some(end_ret) = self.accept_at_eoi[state] {
Some((0, end_ret))
} else {
ret
}
}
pub fn is_empty(&self) -> bool {
self.num_states() == 0
}
}