use std::collections::HashMap;
use crate::finite::deterministic::DeterministicFiniteAutomaton;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParseResult<State> {
pub state: State,
pub position_in_word: usize,
pub size: usize,
}
fn longest_accept_prefix_lengths<A: DeterministicFiniteAutomaton>(
automaton: &A,
word: &[A::Input],
) -> HashMap<A::State, Vec<usize>> {
let word_length = word.len();
let states = automaton.states().collect::<Vec<_>>();
let mut dp: HashMap<A::State, Vec<usize>> = HashMap::new();
for &state in &states {
dp.insert(state, vec![0; word_length + 1]);
}
for i in (0..word_length).rev() {
for &state in &states {
let input = &word[i];
let Some(next_state) = automaton.transition(state, input) else {
continue;
};
let mut max_len = 0;
if automaton.is_accepting_state(next_state) {
max_len = 1;
}
let next_value = dp.get(&next_state).unwrap()[i + 1];
if next_value > 0 {
max_len = 1 + next_value;
}
dp.get_mut(&state).unwrap()[i] = max_len;
}
}
dp
}
pub fn parse_by_longest_match<A: DeterministicFiniteAutomaton>(
automaton: &A,
word: &[A::Input],
) -> Option<Vec<ParseResult<A::State>>> {
let word_length = word.len();
if word_length == 0 {
return Some(Vec::new());
}
let dp = longest_accept_prefix_lengths(automaton, word);
let initial = automaton.initial_state();
let mut result = Vec::new();
let mut current_position = 0;
while current_position < word_length {
let token_length = dp.get(&initial).unwrap()[current_position];
if token_length == 0 {
return None;
}
let segment_start = current_position;
let segment = &word[current_position..current_position + token_length];
let last_state = automaton.run_from(initial, segment)?;
current_position += token_length;
result.push(ParseResult {
state: last_state,
position_in_word: segment_start,
size: token_length,
});
}
Some(result)
}