use alloc::{collections::BTreeMap, vec, vec::Vec};
use super::parse::Hir;
const STATE_LIMIT: usize = 1 << 20;
#[derive(Clone, Debug)]
pub(crate) enum State {
Range { lo: u16, hi: u16, next: u32 },
Split(Vec<u32>),
Match(u32),
}
#[derive(Debug)]
pub(crate) struct Nfa {
pub(crate) states: Vec<State>,
pub(crate) start: u32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct TooLarge;
pub(crate) type Symbols<'a> = BTreeMap<&'a [(u32, u32)], Vec<(u16, u16)>>;
pub(crate) struct Builder<'a> {
states: Vec<State>,
starts: Vec<u32>,
symbols: &'a Symbols<'a>,
}
impl<'a> Builder<'a> {
pub(crate) fn new(symbols: &'a Symbols<'a>) -> Self {
Self {
states: Vec::new(),
starts: Vec::new(),
symbols,
}
}
pub(crate) fn add(&mut self, hir: &Hir, token: u32) -> Result<u32, TooLarge> {
let accept = self.push(State::Match(token))?;
let start = self.compile(hir, accept)?;
self.starts.push(start);
Ok(accept)
}
pub(crate) fn finish(mut self) -> Result<Nfa, TooLarge> {
let starts = core::mem::take(&mut self.starts);
let start = self.push(State::Split(starts))?;
Ok(Nfa {
states: self.states,
start,
})
}
fn push(&mut self, state: State) -> Result<u32, TooLarge> {
if self.states.len() >= STATE_LIMIT {
return Err(TooLarge);
}
self.states.push(state);
Ok((self.states.len() - 1) as u32)
}
fn compile(&mut self, hir: &Hir, next: u32) -> Result<u32, TooLarge> {
match hir {
Hir::Empty => Ok(next),
Hir::Class(ranges) => self.class(ranges, next),
Hir::Concat(parts) => {
let mut target = next;
for part in parts.iter().rev() {
target = self.compile(part, target)?;
}
Ok(target)
}
Hir::Alt(branches) => {
let mut entries = Vec::with_capacity(branches.len());
for branch in branches {
entries.push(self.compile(branch, next)?);
}
self.push(State::Split(entries))
}
Hir::Repeat { hir, min, max } => {
let mut target = match max {
None => {
let entry = self.push(State::Split(Vec::new()))?;
let body = self.compile(hir, entry)?;
self.states[entry as usize] = State::Split(vec![body, next]);
entry
}
Some(max) => {
let mut target = next;
for _ in *min..*max {
let body = self.compile(hir, target)?;
target = self.push(State::Split(vec![body, next]))?;
}
target
}
};
for _ in 0..*min {
target = self.compile(hir, target)?;
}
Ok(target)
}
}
}
fn class(&mut self, ranges: &[(u32, u32)], next: u32) -> Result<u32, TooLarge> {
let runs = self.symbols.get(ranges).cloned().unwrap_or_default();
let mut entries = Vec::with_capacity(runs.len());
for (lo, hi) in runs {
entries.push(self.push(State::Range { lo, hi, next })?);
}
if entries.len() == 1 {
Ok(entries[0])
} else {
self.push(State::Split(entries))
}
}
}