use super::super::ShiftOr;
pub struct ShiftOrInterpreter<'a> {
shift_or: &'a ShiftOr,
}
impl<'a> ShiftOrInterpreter<'a> {
pub fn new(shift_or: &'a ShiftOr) -> Self {
Self { shift_or }
}
pub fn is_match(&self, input: &[u8]) -> bool {
self.find(input).is_some()
}
pub fn find(&self, input: &[u8]) -> Option<(usize, usize)> {
if self.shift_or.has_start_anchor {
if let Some(end) = self.match_at(input, 0) {
if self.shift_or.has_end_anchor {
if end == input.len() {
return Some((0, end));
}
return None;
}
return Some((0, end));
}
if self.shift_or.nullable {
if self.shift_or.has_end_anchor {
if input.is_empty() {
return Some((0, 0));
}
return None;
}
return Some((0, 0));
}
return None;
}
if self.shift_or.has_end_anchor {
for start in 0..=input.len() {
if let Some(end) = self.match_at(input, start) {
if end == input.len() {
return Some((start, end));
}
}
}
if self.shift_or.nullable {
return Some((input.len(), input.len()));
}
return None;
}
for start in 0..=input.len() {
if let Some(end) = self.match_at(input, start) {
return Some((start, end));
}
}
if self.shift_or.nullable {
return Some((0, 0));
}
None
}
pub fn find_at(&self, input: &[u8], pos: usize) -> Option<(usize, usize)> {
if pos > input.len() {
return None;
}
if self.shift_or.has_start_anchor {
if pos > 0 {
return None; }
if let Some(end) = self.match_at(input, 0) {
if self.shift_or.has_end_anchor {
if end == input.len() {
return Some((0, end));
}
return None;
}
return Some((0, end));
}
return None;
}
if self.shift_or.has_end_anchor {
for start in pos..=input.len() {
if let Some(end) = self.match_at(input, start) {
if end == input.len() {
return Some((start, end));
}
}
}
return None;
}
for start in pos..=input.len() {
if let Some(end) = self.match_at(input, start) {
return Some((start, end));
}
}
None
}
pub fn try_match_at(&self, input: &[u8], pos: usize) -> Option<(usize, usize)> {
self.match_at(input, pos).map(|end| (pos, end))
}
fn match_at(&self, input: &[u8], start: usize) -> Option<usize> {
if start > input.len() {
return None;
}
let mut last_match = None;
if self.shift_or.nullable {
last_match = Some(start);
}
let mut state = !0u64;
for (i, &byte) in input[start..].iter().enumerate() {
let byte_mask = self.shift_or.masks[byte as usize];
if i == 0 {
state = (!self.shift_or.first) | byte_mask;
} else {
let mut active = !state;
let mut reachable = 0u64;
while active != 0 {
let pos = active.trailing_zeros() as usize;
reachable |= self.shift_or.follow[pos];
active &= active - 1; }
state = (!reachable) | byte_mask;
}
if (state | self.shift_or.accept) != !0u64 {
last_match = Some(start + i + 1);
}
if state == !0u64 {
break;
}
}
last_match
}
}