use super::once::{MatchedRuleCommit, OnceStateSet};
use super::state::{State, StateMatch};
use crate::error::RunError;
use crate::inspect::RuleView;
use crate::rule::{Rule, RuleAnchorSyntax};
#[derive(Debug)]
pub(crate) enum RuleSearch<'program, 'once> {
Matched(MatchedRuleApplication<'program, 'once>),
Stable,
}
#[derive(Debug)]
pub(crate) struct MatchedRuleApplication<'program, 'once> {
rule: &'program Rule,
commit: MatchedRuleCommit<'once>,
state_match: StateMatch,
}
struct MatchedRuleCandidate<'program> {
rule: &'program Rule,
state_match: StateMatch,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct CommittedRule<'program> {
rule: RuleView<'program>,
}
impl<'program> MatchedRuleCandidate<'program> {
const fn new(rule: &'program Rule, state_match: StateMatch) -> Self {
Self { rule, state_match }
}
const fn into_application<'once>(
self,
commit: MatchedRuleCommit<'once>,
) -> MatchedRuleApplication<'program, 'once> {
MatchedRuleApplication::new(self.rule, self.state_match, commit)
}
}
impl<'program, 'once> MatchedRuleApplication<'program, 'once> {
const fn new(
rule: &'program Rule,
state_match: StateMatch,
commit: MatchedRuleCommit<'once>,
) -> Self {
Self {
rule,
commit,
state_match,
}
}
pub(crate) const fn rule(&self) -> &'program Rule {
self.rule
}
pub(crate) const fn state_match(&self) -> StateMatch {
self.state_match
}
pub(crate) fn commit(self) -> CommittedRule<'program> {
self.commit.commit();
CommittedRule {
rule: RuleView::new(self.rule),
}
}
}
impl<'program> CommittedRule<'program> {
pub(crate) const fn rule(self) -> RuleView<'program> {
self.rule
}
}
pub(crate) fn find_next_match<'program, 'once>(
rules: &'program [Rule],
once_states: &'once mut OnceStateSet,
state: &State,
) -> Result<RuleSearch<'program, 'once>, RunError> {
for rule in rules {
if !once_states.is_available(rule)? {
continue;
}
let Some(candidate) = matched_candidate_for_rule(rule, state) else {
continue;
};
let commit = once_states.reserve_available_commit(rule)?;
return Ok(RuleSearch::Matched(candidate.into_application(commit)));
}
Ok(RuleSearch::Stable)
}
fn matched_candidate_for_rule<'program>(
rule: &'program Rule,
state: &State,
) -> Option<MatchedRuleCandidate<'program>> {
let state_match = find_match(state, rule)?;
Some(MatchedRuleCandidate::new(rule, state_match))
}
fn find_match(state: &State, rule: &Rule) -> Option<StateMatch> {
match rule.anchor() {
RuleAnchorSyntax::Anywhere => state.find_payload(rule.lhs()),
RuleAnchorSyntax::Start => state.starts_with_payload(rule.lhs()),
RuleAnchorSyntax::End => state.ends_with_payload(rule.lhs()),
}
}