use crate::{
Automaton, ByteDomain, ByteOffset, CaptureId, CodeUnitDomain, CodeUnitOffset, ExecutionLimit,
ExecutionOutcome, ExecutionReceipt, ScalarDomain, ScalarOffset, SymbolDomain, TextLimits,
UnsupportedFeature, execute_regular,
};
use sim_text::CodeUnitString;
use std::collections::BTreeMap;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct DomainCaptureSpan<D: SymbolDomain> {
pub start: D::Offset,
pub end: D::Offset,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DomainMatch<D: SymbolDomain> {
pub start: D::Offset,
pub end: D::Offset,
pub captures: BTreeMap<CaptureId, DomainCaptureSpan<D>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DomainExecutionOutcome<D: SymbolDomain> {
Match {
matched: DomainMatch<D>,
receipt: ExecutionReceipt,
},
NoMatch {
receipt: ExecutionReceipt,
},
Limit {
limit: ExecutionLimit,
receipt: ExecutionReceipt,
},
Unsupported {
feature: UnsupportedFeature,
receipt: ExecutionReceipt,
},
}
trait IndexedDomain: SymbolDomain {
fn offset(index: usize) -> Self::Offset;
}
impl IndexedDomain for ByteDomain {
fn offset(index: usize) -> Self::Offset {
ByteOffset(index)
}
}
impl IndexedDomain for ScalarDomain {
fn offset(index: usize) -> Self::Offset {
ScalarOffset::new(index)
}
}
impl IndexedDomain for CodeUnitDomain {
fn offset(index: usize) -> Self::Offset {
CodeUnitOffset::new(index)
}
}
fn typed<D: IndexedDomain>(outcome: ExecutionOutcome) -> DomainExecutionOutcome<D> {
match outcome {
ExecutionOutcome::Match { matched, receipt } => DomainExecutionOutcome::Match {
matched: DomainMatch {
start: D::offset(matched.start),
end: D::offset(matched.end),
captures: matched
.captures
.into_iter()
.map(|(id, span)| {
(
id,
DomainCaptureSpan {
start: D::offset(span.start),
end: D::offset(span.end),
},
)
})
.collect(),
},
receipt,
},
ExecutionOutcome::NoMatch { receipt } => DomainExecutionOutcome::NoMatch { receipt },
ExecutionOutcome::Limit { limit, receipt } => {
DomainExecutionOutcome::Limit { limit, receipt }
}
ExecutionOutcome::Unsupported { feature, receipt } => {
DomainExecutionOutcome::Unsupported { feature, receipt }
}
}
}
pub fn execute_bytes<E>(
automaton: &Automaton<u8, E>,
subject: &[u8],
limits: TextLimits,
extension_matches: impl Fn(&E, &u8) -> bool,
) -> DomainExecutionOutcome<ByteDomain> {
typed(execute_regular(
automaton,
subject,
limits,
extension_matches,
))
}
pub fn execute_scalars<E>(
automaton: &Automaton<char, E>,
subject: &[char],
limits: TextLimits,
extension_matches: impl Fn(&E, &char) -> bool,
) -> DomainExecutionOutcome<ScalarDomain> {
typed(execute_regular(
automaton,
subject,
limits,
extension_matches,
))
}
pub fn execute_code_units<E>(
automaton: &Automaton<u16, E>,
subject: &CodeUnitString,
limits: TextLimits,
extension_matches: impl Fn(&E, &u16) -> bool,
) -> DomainExecutionOutcome<CodeUnitDomain> {
typed(execute_regular(
automaton,
subject.as_code_units(),
limits,
extension_matches,
))
}
pub const fn require_code_unit_offset(offset: CodeUnitOffset) -> CodeUnitOffset {
offset
}