use std::cmp::Ordering;
use char::Char;
pub type InstIdx = usize;
#[derive(Clone, Debug)]
pub enum Inst {
Match,
Save(InstSave),
Split(InstSplit),
EmptyLook(InstEmptyLook),
Char(InstChar),
Ranges(InstRanges),
}
#[derive(Clone, Debug)]
pub struct InstSave {
pub goto: InstIdx,
pub slot: usize,
}
#[derive(Clone, Debug)]
pub struct InstSplit {
pub goto1: InstIdx,
pub goto2: InstIdx,
}
#[derive(Clone, Debug)]
pub struct InstEmptyLook {
pub goto: InstIdx,
pub look: EmptyLook,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EmptyLook {
StartLine,
EndLine,
StartText,
EndText,
WordBoundary,
NotWordBoundary,
}
impl InstEmptyLook {
pub fn matches(&self, c1: Char, c2: Char) -> bool {
use self::EmptyLook::*;
match self.look {
StartLine => c1.is_none() || c1 == '\n',
EndLine => c2.is_none() || c2 == '\n',
StartText => c1.is_none(),
EndText => c2.is_none(),
ref wbty => {
let (w1, w2) = (c1.is_word_char(), c2.is_word_char());
(*wbty == WordBoundary && w1 ^ w2)
|| (*wbty == NotWordBoundary && !(w1 ^ w2))
}
}
}
}
#[derive(Clone, Debug)]
pub struct InstChar {
pub goto: InstIdx,
pub c: char,
}
#[derive(Clone, Debug)]
pub struct InstRanges {
pub goto: InstIdx,
pub ranges: Vec<(char, char)>,
}
impl InstRanges {
#[inline(always)] pub fn matches(&self, c: Char) -> bool {
for r in self.ranges.iter().take(4) {
if c < r.0 {
return false;
}
if c <= r.1 {
return true;
}
}
self.ranges.binary_search_by(|r| {
if r.1 < c {
Ordering::Less
} else if r.0 > c {
Ordering::Greater
} else {
Ordering::Equal
}
}).is_ok()
}
}