use super::once::{MatchedRuleCommit, OnceRuleReadiness, OnceStateSet, RuntimeRule};
use super::state::{State, StateMatch};
use crate::error::RuleRuntimeStateError;
use crate::program::{RuleScan, RuleTarget};
use crate::rule::{Rule, RuleAnchorSyntax};
#[derive(Debug)]
pub(crate) enum RuleSearch<'program, 'state, 'once> {
Matched(MatchedRuleApplication<'program, 'state, 'once>),
Stable,
}
#[derive(Debug)]
pub(crate) enum RuleAttempt<'program, 'state, 'once> {
Matched(MatchedRuleApplication<'program, 'state, 'once>),
Missed(RuleAttemptMiss<'program>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuleMissReason {
StateMismatch,
OnceConsumed,
}
#[derive(Debug)]
pub(crate) struct MatchedRuleApplication<'program, 'state, 'once> {
rule: &'program Rule,
commit: MatchedRuleCommit<'once>,
state_match: StateMatch<'state>,
}
#[derive(Debug)]
pub(crate) struct PreparedMatchedRule<'program, 'once> {
rule: &'program Rule,
commit: MatchedRuleCommit<'once>,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct RuleAttemptMiss<'program> {
rule: &'program Rule,
reason: RuleMissReason,
}
struct MatchedRuleCandidate<'program, 'state> {
rule: &'program Rule,
state_match: StateMatch<'state>,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct CommittedRule<'program> {
rule: &'program Rule,
}
impl<'program> RuleAttemptMiss<'program> {
const fn new(rule: &'program Rule, reason: RuleMissReason) -> Self {
Self { rule, reason }
}
pub(crate) const fn rule(self) -> &'program Rule {
self.rule
}
pub(crate) const fn reason(self) -> RuleMissReason {
self.reason
}
}
impl<'program, 'state> MatchedRuleCandidate<'program, 'state> {
const fn new(rule: &'program Rule, state_match: StateMatch<'state>) -> Self {
Self { rule, state_match }
}
const fn into_application<'once>(
self,
commit: MatchedRuleCommit<'once>,
) -> MatchedRuleApplication<'program, 'state, 'once> {
MatchedRuleApplication::new(self.rule, self.state_match, commit)
}
}
impl<'program, 'state, 'once> MatchedRuleApplication<'program, 'state, 'once> {
const fn new(
rule: &'program Rule,
state_match: StateMatch<'state>,
commit: MatchedRuleCommit<'once>,
) -> Self {
Self {
rule,
commit,
state_match,
}
}
pub(crate) fn into_prepare_parts(
self,
) -> (StateMatch<'state>, PreparedMatchedRule<'program, 'once>) {
(
self.state_match,
PreparedMatchedRule {
rule: self.rule,
commit: self.commit,
},
)
}
}
impl<'program> PreparedMatchedRule<'program, '_> {
pub(crate) const fn rule(&self) -> &'program Rule {
self.rule
}
pub(crate) fn commit(self) -> CommittedRule<'program> {
self.commit.commit();
CommittedRule { rule: self.rule }
}
}
impl<'program> CommittedRule<'program> {
pub(crate) const fn rule(self) -> &'program Rule {
self.rule
}
}
pub(crate) fn find_next_match<'program, 'state, 'once>(
rules: RuleScan<'program>,
once_states: &'once mut OnceStateSet,
state: &'state State,
) -> Result<RuleSearch<'program, 'state, 'once>, RuleRuntimeStateError> {
for runtime_rule in once_states.runtime_rules_mut(rules) {
let runtime_rule = runtime_rule?;
let rule = runtime_rule.rule();
let Some(candidate) = matched_candidate_for_rule(rule, state) else {
continue;
};
match runtime_rule.readiness() {
OnceRuleReadiness::Available(commit) => {
return Ok(RuleSearch::Matched(candidate.into_application(commit)));
}
OnceRuleReadiness::Consumed => {}
}
}
Ok(RuleSearch::Stable)
}
pub(crate) fn attempt_rule<'program, 'state, 'once>(
runtime_rule: RuntimeRule<'program, 'once>,
state: &'state State,
) -> RuleAttempt<'program, 'state, 'once> {
let rule = runtime_rule.rule();
let commit = match runtime_rule.readiness() {
OnceRuleReadiness::Available(commit) => commit,
OnceRuleReadiness::Consumed => {
return RuleAttempt::Missed(RuleAttemptMiss::new(rule, RuleMissReason::OnceConsumed));
}
};
let Some(candidate) = matched_candidate_for_rule(rule, state) else {
return RuleAttempt::Missed(RuleAttemptMiss::new(rule, RuleMissReason::StateMismatch));
};
RuleAttempt::Matched(candidate.into_application(commit))
}
pub(crate) fn runtime_rule_for_target<'program, 'once>(
once_states: &'once mut OnceStateSet,
target: RuleTarget<'program>,
) -> Result<RuntimeRule<'program, 'once>, RuleRuntimeStateError> {
once_states.runtime_rule_mut(target.rule())
}
fn matched_candidate_for_rule<'program, 'state>(
rule: &'program Rule,
state: &'state State,
) -> Option<MatchedRuleCandidate<'program, 'state>> {
let state_match = find_match(state, rule)?;
Some(MatchedRuleCandidate::new(rule, state_match))
}
fn find_match<'state>(state: &'state State, rule: &Rule) -> Option<StateMatch<'state>> {
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()),
}
}