use std::sync::Arc;
use super::and_op::AndState;
use super::enumeration::enumerate_with_filter;
use super::kleene::{KleeneCapture, KleeneLimits};
use super::nfa::{Nfa, State, StateType};
use super::predicate::{eval_predicate, event_matches_state, predicate_references_alias};
use super::run::Run;
use super::types::{MatchResult, SelectionStrategy, SharedEvent};
use crate::clock::Timestamp;
use crate::ExprEvaluator;
#[derive(Debug)]
pub(crate) enum RunAdvanceResult {
Continue,
Complete(MatchResult),
CompleteAndContinue(MatchResult),
CompleteMulti(Vec<MatchResult>),
Invalidate,
NoMatch,
}
#[allow(dead_code)]
pub(crate) fn advance_run(
nfa: &Nfa,
strategy: SelectionStrategy,
run: &mut Run,
event: &varpulis_core::Event,
limits: KleeneLimits,
evaluator: Option<&dyn ExprEvaluator>,
) -> RunAdvanceResult {
advance_run_shared(
nfa,
strategy,
run,
Arc::new(event.clone()),
limits,
Timestamp::now(),
evaluator,
)
}
fn complete_run(
run: &mut Run,
limits: KleeneLimits,
evaluator: Option<&dyn ExprEvaluator>,
) -> RunAdvanceResult {
if let Some(ref kc) = run.kleene_capture {
if kc.deferred_predicate.is_some() {
return RunAdvanceResult::CompleteMulti(enumerate_with_filter(
run,
limits.max_results,
evaluator,
));
}
}
RunAdvanceResult::Complete(MatchResult {
captured: std::mem::take(&mut run.captured),
stack: std::mem::take(&mut run.stack),
duration: run.started_at.elapsed(),
})
}
pub(crate) fn advance_run_shared(
nfa: &Nfa,
strategy: SelectionStrategy,
run: &mut Run,
event: SharedEvent,
limits: KleeneLimits,
now: Timestamp,
evaluator: Option<&dyn ExprEvaluator>,
) -> RunAdvanceResult {
let current_state = &nfa.states[run.current_state];
for neg in &run.pending_negations {
if neg.is_violated_by(&event, &run.captured, evaluator) {
return RunAdvanceResult::Invalidate;
}
}
if current_state.state_type == StateType::And {
return advance_and_state(nfa, run, current_state, event, limits, evaluator);
}
if current_state.state_type == StateType::Negation {
if let Some(ref neg_info) = current_state.negation_info {
if *event.event_type == neg_info.forbidden_type {
let pred_matches = neg_info
.predicate
.as_ref()
.is_none_or(|p| eval_predicate(p, &event, &run.captured, evaluator));
if pred_matches {
return RunAdvanceResult::Invalidate;
}
}
}
return RunAdvanceResult::NoMatch;
}
if current_state.state_type == StateType::Accept {
return complete_run(run, limits, evaluator);
}
let kleene_matches =
current_state.state_type == StateType::Kleene && current_state.self_loop && {
let is_self_ref_first_entry = current_state.alias.as_ref().is_some_and(|a| {
!run.captured.contains_key(a.as_str())
&& current_state
.predicate
.as_ref()
.is_some_and(|p| predicate_references_alias(p, a))
});
if is_self_ref_first_entry {
current_state
.event_type
.as_ref()
.is_none_or(|et| *event.event_type == *et)
} else {
event_matches_state(nfa, &event, current_state, &run.captured, evaluator)
}
};
if kleene_matches {
if let Some(ref kc) = run.kleene_capture {
if kc.next_var >= limits.max_events {
return RunAdvanceResult::Continue;
}
}
run.push_at_kleene(Arc::clone(&event), ¤t_state.alias, now);
if current_state.has_epsilon_to_accept {
return RunAdvanceResult::CompleteAndContinue(MatchResult {
captured: run.captured.clone(),
stack: run.stack.clone(),
duration: run.started_at.elapsed(),
});
}
if run.kleene_capture.is_none() {
let mut kc = KleeneCapture::new();
if current_state.postponed_predicate.is_some() {
kc.deferred_predicate = current_state.postponed_predicate.clone();
kc.needs_zdd = true;
}
run.kleene_capture = Some(kc);
}
if let Some(ref mut kc) = run.kleene_capture {
if kc.needs_zdd {
kc.extend(Arc::clone(&event), current_state.alias.clone());
} else {
kc.extend_simple(Arc::clone(&event), current_state.alias.clone());
}
}
return RunAdvanceResult::Continue;
}
for &next_id in ¤t_state.transitions {
let next_state = &nfa.states[next_id];
if next_state.state_type == StateType::Negation {
if let Some(ref neg_info) = next_state.negation_info {
let negation_constraint = super::negation::NegationConstraint {
forbidden_type: neg_info.forbidden_type.clone(),
predicate: neg_info.predicate.clone(),
deadline: run.deadline, event_time_deadline: run.event_time_deadline,
next_state: neg_info.continue_state,
};
run.pending_negations.push(negation_constraint);
run.current_state = next_id;
return RunAdvanceResult::Continue;
}
}
if next_state.state_type == StateType::And {
run.current_state = next_id;
return advance_and_state(nfa, run, next_state, event, limits, evaluator);
}
let matches = if next_state.state_type == StateType::Kleene
&& next_state.self_loop
&& next_state.alias.as_ref().is_some_and(|a| {
!run.captured.contains_key(a.as_str())
&& next_state
.predicate
.as_ref()
.is_some_and(|p| predicate_references_alias(p, a))
}) {
next_state
.event_type
.as_ref()
.is_none_or(|et| *event.event_type == *et)
} else {
event_matches_state(nfa, &event, next_state, &run.captured, evaluator)
};
if matches {
run.current_state = next_id;
run.push_at(Arc::clone(&event), next_state.alias.clone(), now);
if next_state.state_type == StateType::Accept {
return complete_run(run, limits, evaluator);
}
if next_state.state_type == StateType::Kleene && next_state.self_loop {
if next_state.has_epsilon_to_accept {
return RunAdvanceResult::CompleteAndContinue(MatchResult {
captured: run.captured.clone(),
stack: run.stack.clone(),
duration: run.started_at.elapsed(),
});
}
if run.kleene_capture.is_none() {
let mut kc = KleeneCapture::new();
if next_state.postponed_predicate.is_some() {
kc.deferred_predicate = next_state.postponed_predicate.clone();
kc.needs_zdd = true;
}
run.kleene_capture = Some(kc);
}
if let Some(ref mut kc) = run.kleene_capture {
if kc.next_var >= limits.max_events {
return RunAdvanceResult::Continue;
}
if kc.needs_zdd {
kc.extend(Arc::clone(&event), next_state.alias.clone());
} else {
kc.extend_simple(Arc::clone(&event), next_state.alias.clone());
}
}
return RunAdvanceResult::Continue;
}
return RunAdvanceResult::Continue;
}
}
for &eps_id in ¤t_state.epsilon_transitions {
let eps_state = &nfa.states[eps_id];
if eps_state.state_type == StateType::Accept {
return complete_run(run, limits, evaluator);
}
for &next_id in &eps_state.transitions {
let next_state = &nfa.states[next_id];
if event_matches_state(nfa, &event, next_state, &run.captured, evaluator) {
run.current_state = next_id;
run.push_at(Arc::clone(&event), next_state.alias.clone(), now);
if next_state.state_type == StateType::Accept {
return complete_run(run, limits, evaluator);
}
return RunAdvanceResult::Continue;
}
}
}
match strategy {
SelectionStrategy::StrictContiguous => RunAdvanceResult::Invalidate,
_ => RunAdvanceResult::NoMatch,
}
}
fn advance_and_state(
nfa: &Nfa,
run: &mut Run,
state: &State,
event: SharedEvent,
limits: KleeneLimits,
evaluator: Option<&dyn ExprEvaluator>,
) -> RunAdvanceResult {
let config = match &state.and_config {
Some(c) => c,
None => return RunAdvanceResult::NoMatch,
};
if run.and_state.is_none() {
run.and_state = Some(AndState::new());
}
let mut matched_branch: Option<(usize, Option<String>)> = None;
let total_branches = config.branches.len();
{
let Some(and_state) = run.and_state.as_ref() else {
return RunAdvanceResult::Continue;
};
for (idx, branch) in config.branches.iter().enumerate() {
if and_state.is_branch_completed(idx) {
continue;
}
if *event.event_type == branch.event_type {
let pred_matches = branch
.predicate
.as_ref()
.is_none_or(|p| eval_predicate(p, &event, &run.captured, evaluator));
if pred_matches {
matched_branch = Some((idx, branch.alias.clone()));
break;
}
}
}
}
if let Some((idx, alias)) = matched_branch {
let Some(and_state) = run.and_state.as_mut() else {
return RunAdvanceResult::Continue;
};
and_state.complete_branch(idx, Arc::clone(&event));
if let Some(ref alias) = alias {
run.captured.insert(alias.clone(), Arc::clone(&event));
}
run.push(Arc::clone(&event), alias);
let all_completed = run
.and_state
.as_ref()
.is_some_and(|s| s.all_completed(total_branches));
if all_completed {
run.current_state = config.join_state;
run.and_state = None;
let join_state = &nfa.states[config.join_state];
if join_state.state_type == StateType::Accept {
return complete_run(run, limits, evaluator);
}
}
return RunAdvanceResult::Continue;
}
RunAdvanceResult::NoMatch
}