use crate::classify::Classification;
use crate::rules::Rules;
use crate::text::{singularize, stem_key};
pub(crate) struct PredicateHit {
pub index: usize,
#[allow(dead_code)] pub value: String,
}
#[derive(Default)]
pub(crate) struct Reduced {
pub objects: Vec<String>,
pub subjects: Vec<String>,
pub before: Vec<(String, String)>,
pub after: Vec<(String, String)>,
}
pub(crate) struct Parts {
pub objects: Reduced,
pub subjects: Reduced,
pub predicate: Option<(String, String)>,
}
pub(crate) fn map_predicate(
text: &str,
vocabulary: &std::collections::HashMap<String, String>,
) -> Option<String> {
let key = stem_key(text);
vocabulary.get(&key).cloned()
}
pub(crate) fn first_predicate(
classification: &Classification,
rules: &Rules,
) -> Option<PredicateHit> {
for (index, (token, _tag)) in classification.parts.iter().enumerate() {
if let Some(value) = map_predicate(token, &rules.vocabulary) {
return Some(PredicateHit { index, value });
}
}
None
}
pub(crate) fn last_predicate(_classification: &Classification, _rules: &Rules) -> Option<String> {
None
}
pub(crate) fn reduce_parts(data: &[(String, String)], rules: &Rules) -> Reduced {
let mut result = Reduced::default();
for part in data {
let normalized = singularize(&part.0);
let mut added = false;
if rules.objects.contains_key(&normalized) {
result.objects.push(normalized.clone());
added = true;
}
if rules.subjects.contains_key(&normalized) {
result.subjects.push(normalized.clone());
added = true;
}
if !added && part.1 != "IN" && !part.1.starts_with('W') {
if result.subjects.is_empty() && result.objects.is_empty() {
result.before.push(part.clone());
} else {
result.after.push(part.clone());
}
}
}
result
}
pub(crate) fn parts(classification: &Classification, rules: &Rules) -> Parts {
let predicate = first_predicate(classification, rules);
let (before, after, predicate_part) = match &predicate {
Some(hit) if hit.index > 0 => (
classification.parts[..hit.index].to_vec(),
classification.parts[hit.index + 1..].to_vec(),
Some(classification.parts[hit.index].clone()),
),
Some(hit) => (
Vec::new(),
Vec::new(),
Some(classification.parts[hit.index].clone()),
),
None => (Vec::new(), Vec::new(), None),
};
Parts {
objects: reduce_parts(&after, rules),
subjects: reduce_parts(&before, rules),
predicate: predicate_part,
}
}