use std::collections::HashMap;
use std::hash::Hash;
use crate::labeled::finite::DeterministicFiniteLabeledAutomaton;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParseResult<State> {
pub state: State,
pub position_in_word: usize,
pub size: usize,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LabeledParseResult<State, Label> {
pub state: State,
pub position_in_word: usize,
pub size: usize,
pub label: Label,
}
pub fn parse_by_longest_match<
Label: Hash + Eq + Clone,
A: DeterministicFiniteLabeledAutomaton<Label>,
>(
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)
}
pub fn parse_by_longest_match_labeled<
Label: Hash + Eq + Clone,
A: DeterministicFiniteLabeledAutomaton<Label>,
>(
automaton: &A,
word: &[A::Input],
) -> Option<Vec<LabeledParseResult<A::State, Label>>> {
let tokens = parse_by_longest_match(automaton, word)?;
let result = tokens
.into_iter()
.map(|token| {
let label = automaton.get_label(token.state).unwrap();
enrich_with_label(token, label)
})
.collect();
Some(result)
}
fn enrich_with_label<State, Label>(
result: ParseResult<State>,
label: Label,
) -> LabeledParseResult<State, Label> {
LabeledParseResult {
state: result.state,
position_in_word: result.position_in_word,
size: result.size,
label: label,
}
}
fn longest_accept_prefix_lengths<
Label: Hash + Eq + Clone,
A: DeterministicFiniteLabeledAutomaton<Label>,
>(
automaton: &A,
word: &[A::Input],
) -> HashMap<A::State, Vec<usize>> {
let word_length = word.len();
let states = automaton.states_set();
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.has_label(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
}