use crate::matcher::{self, wrap_matcher};
use crate::repr::{AnchorLocation, Pattern, Repetition};
use crate::state::{State, StateGraph, StateRef, Submatch};
pub trait Compile {
fn to_state(&self, sg: &mut StateGraph) -> (StateRef, Vec<StateRef>);
}
pub fn start_compile(re: &Pattern) -> StateGraph {
let mut state_graph = Vec::with_capacity(64);
let mut before = State::default();
before.sub = Some(Submatch::Start);
let beforeref = 0;
state_graph.push(before);
let (s, sp) = re.to_state(&mut state_graph);
state_graph[beforeref].out = Some(s);
let mut end = State::default();
end.sub = Some(Submatch::End);
let endref = state_graph.len();
state_graph.push(end);
for p in sp {
state_graph[p].patch(endref);
}
state_graph
}
impl Compile for Pattern {
fn to_state(&self, sg: &mut StateGraph) -> (StateRef, Vec<StateRef>) {
match *self {
Pattern::Concat(ref ps) => {
if ps.is_empty() {
panic!("invalid Concat len: 0")
} else if ps.len() == 1 {
return ps[0].to_state(sg);
}
let (init, mut lastp) = ps[0].to_state(sg);
for i in 1..ps.len() {
let (next, nextp) = ps[i].to_state(sg);
for p in lastp {
sg[p].patch(next);
}
lastp = nextp;
}
(init, lastp)
}
Pattern::Any => {
let s = State {
out: None,
out1: None,
matcher: wrap_matcher(Box::new(matcher::AnyMatcher)),
sub: None,
};
let sref = sg.len();
sg.push(s);
(sref, vec![sref])
}
Pattern::Char(c) => {
let s = State {
out: None,
out1: None,
matcher: wrap_matcher(Box::new(matcher::CharMatcher(c))),
sub: None,
};
let sref = sg.len();
sg.push(s);
(sref, vec![sref])
}
Pattern::Str(ref s) => {
let s = State {
out: None,
out1: None,
matcher: wrap_matcher(Box::new(matcher::StringMatcher::new(s))),
sub: None,
};
let sref = sg.len();
sg.push(s);
(sref, vec![sref])
}
Pattern::CharRange(from, to) => {
let s = State {
out: None,
out1: None,
matcher: wrap_matcher(Box::new(matcher::CharRangeMatcher(from, to))),
sub: None,
};
let sref = sg.len();
sg.push(s);
(sref, vec![sref])
}
Pattern::CharSet(ref set) => {
let s = State {
out: None,
out1: None,
matcher: wrap_matcher(Box::new(matcher::CharSetMatcher(set.clone()))),
sub: None,
};
let sref = sg.len();
sg.push(s);
(sref, vec![sref])
}
Pattern::Alternate(ref r) => alternate(sg, &r, &vec![]),
Pattern::Submatch(ref p) => {
let (s, sp) = p.to_state(sg);
let before = State {
out: Some(s),
out1: None,
matcher: None,
sub: Some(Submatch::Start),
};
let after = State {
out: None,
out1: None,
matcher: None,
sub: Some(Submatch::End),
};
let beforeref = sg.len();
sg.push(before);
let afterref = sg.len();
sg.push(after);
for p in sp {
sg[p].patch(afterref);
}
(beforeref, vec![afterref])
}
Pattern::Repeated(ref p) => p.to_state(sg),
Pattern::Anchor(ref loc) => {
let mut m = matcher::AnchorMatcher::Begin;
match loc {
&AnchorLocation::End => m = matcher::AnchorMatcher::End,
_ => (),
};
let s = State {
out: None,
out1: None,
matcher: wrap_matcher(Box::new(m)),
sub: None,
};
let sref = sg.len();
sg.push(s);
(sref, vec![sref])
}
}
}
}
fn alternate(
sg: &mut StateGraph,
ps: &[Pattern],
to_patch: &[StateRef],
) -> (StateRef, Vec<StateRef>) {
if ps.len() == 1 {
let (s, sp) = ps[0].to_state(sg);
for e in to_patch {
sg[*e].patch(s);
}
(s, sp)
} else {
let mut init = State {
out: None,
out1: None,
matcher: None,
sub: None,
};
let mid = ps.len() / 2;
let (left, mut leftpatch) = alternate(sg, &ps[..mid], &vec![]);
let (right, mut rightpatch) = alternate(sg, &ps[mid..], &vec![]);
init.patch(left);
init.patch(right);
leftpatch.append(&mut rightpatch);
let initref = sg.len();
sg.push(init);
(initref, leftpatch)
}
}
impl Compile for Repetition {
fn to_state(&self, sg: &mut StateGraph) -> (StateRef, Vec<StateRef>) {
match *self {
Repetition::ZeroOrOnce(ref p) => {
let (s, to_patch) = p.to_state(sg);
let after = State {
out: None,
out1: None,
matcher: None,
sub: None,
};
let afterref = sg.len();
sg.push(after);
let before = State {
out: Some(s),
out1: Some(afterref),
matcher: None,
sub: None,
};
let beforeref = sg.len();
sg.push(before);
for p in to_patch {
sg[p].patch(afterref);
}
(beforeref, vec![afterref])
}
Repetition::ZeroOrMore(ref p) => {
let (s, to_patch) = p.to_state(sg);
let before = State {
out: Some(s.clone()),
out1: None,
matcher: None,
sub: None,
};
let beforeref = sg.len();
sg.push(before);
let after = State {
out: Some(s.clone()),
out1: None,
matcher: None,
sub: None,
};
let afterref = sg.len();
sg.push(after);
sg[beforeref].patch(afterref);
for p in to_patch {
sg[p].patch(afterref);
}
(beforeref, vec![afterref])
}
Repetition::OnceOrMore(ref p) => {
let (s, to_patch) = p.to_state(sg);
let after = State {
out: Some(s.clone()),
out1: None,
matcher: None,
sub: None,
};
let afterref = sg.len();
sg.push(after);
for p in to_patch {
sg[p].patch(afterref);
}
(s, vec![afterref])
}
Repetition::Specific(ref p, min, max_) => {
let cap = max_.unwrap_or(min) as usize;
assert!(cap >= min as usize);
let mut repetition = Vec::with_capacity(cap);
for _ in 0..min {
repetition.push(p.clone());
}
if let Some(max) = max_ {
for _ in 0..(max - min) {
repetition.push(Pattern::Repeated(Box::new(Repetition::ZeroOrOnce(
p.clone(),
))));
}
} else {
repetition.push(Pattern::Repeated(Box::new(Repetition::ZeroOrMore(
p.clone(),
))));
}
Pattern::Concat(repetition).to_state(sg)
}
}
}
}