use smallvec::{smallvec, SmallVec};
use super::{Number, Voice, Tense, Mood, Group, Person};
pub(super) type Suffix<'a> = SmallVec::<[&'a str; 3]>;
pub(super) type Suffixes<'a> = SmallVec::<[Suffix<'a>; 2]>;
fn generate_suffixes<'a>(group: Group, person: Person, number: Number, tense: Tense, voice: Voice, mood: Mood) -> Option<Suffixes<'a>> {
let mut suffixes = Suffixes::new();
let personal_endings = personal_endings(group, person, number, tense, voice, mood)?;
for _ in 0..personal_endings.len() {
suffixes.push(Suffix::new());
}
if let Some(stem_vowel) = stem_vowel(group, person, number, tense, voice, mood) {
suffixes.iter_mut().for_each(|suffix| suffix.push(stem_vowel));
}
if let Some(tense_particle) = tense_particle(group, person, number, tense, voice, mood) {
suffixes.iter_mut().for_each(|suffix| suffix.push(tense_particle));
}
for (suffixes, personal_ending) in suffixes.iter_mut().zip(personal_endings.iter()) {
suffixes.push(personal_ending);
}
Some(suffixes)
}
fn personal_endings(group: Group, person: Person, number: Number, tense: Tense, voice: Voice, mood: Mood) -> Option<Suffix<'static>> {
match (mood, voice, tense, person, number) {
(Mood::Indicative, Voice::Active, Tense::Present, Person::Third, Number::Plural) if group == Group::Third || group == Group::Fourth => Some(smallvec!["unt"]),
(Mood::Indicative, Voice::Active, Tense::Future, Person::First, Number::Singular) if group == Group::Third || group == Group::Fourth => Some(smallvec!["am"]),
(Mood::Indicative, Voice::Active, Tense::Future, Person::Third, Number::Plural) if group == Group::First || group == Group::Second => Some(smallvec!["unt"]),
(Mood::Indicative, Voice::Active, Tense::Perfect, Person::Third, Number::Plural) => Some(smallvec!["ērunt", "ēre"]),
(Mood::Indicative, Voice::Passive, Tense::Present, Person::Third, Number::Plural) if group == Group::Third || group == Group::Fourth => Some(smallvec!["untur"]),
(Mood::Indicative, Voice::Passive, Tense::Future, Person::Third, Number::Plural) if group == Group::First || group == Group::Second => Some(smallvec!["untur"]),
(Mood::Indicative, Voice::Active, Tense::Perfect, Person::First, Number::Singular) => Some(smallvec!["ī"]),
(Mood::Indicative, Voice::Active, Tense::Perfect, Person::First, Number::Plural) => Some(smallvec!["imus"]),
(Mood::Indicative, Voice::Active, Tense::Perfect, Person::Second, Number::Singular) => Some(smallvec!["istī"]),
(Mood::Indicative, Voice::Active, Tense::Perfect, Person::Second, Number::Plural) => Some(smallvec!["istis"]),
(Mood::Indicative, Voice::Active, Tense::Perfect, Person::Third, Number::Singular) => Some(smallvec!["it"]),
(Mood::Indicative, Voice::Active, Tense::Imperfect, Person::First, Number::Singular) => Some(smallvec!["m"]),
(Mood::Indicative, Voice::Active, Tense::Pluperfect, Person::First, Number::Singular) => Some(smallvec!["m"]),
(Mood::Subjunctive, Voice::Active, _, Person::First, Number::Singular) => Some(smallvec!["m"]),
(Mood::Subjunctive, Voice::Passive, Tense::Present, Person::First, Number::Singular) => Some(smallvec!["r"]),
(_, Voice::Passive, Tense::Future, Person::First, Number::Singular) if group == Group::Third || group == Group::Fourth => Some(smallvec!["r"]),
(_, Voice::Passive, Tense::Imperfect, Person::First, Number::Singular) => Some(smallvec!["r"]),
(_, Voice::Active, _, Person::First, Number::Singular) => Some(smallvec!["ō"]),
(_, Voice::Active, _, Person::First, Number::Plural) => Some(smallvec!["mus"]),
(_, Voice::Active, _, Person::Second, Number::Singular) => Some(smallvec!["s"]),
(_, Voice::Active, _, Person::Second, Number::Plural) => Some(smallvec!["tis"]),
(_, Voice::Active, _, Person::Third, Number::Singular) => Some(smallvec!["t"]),
(_, Voice::Active, _, Person::Third, Number::Plural) => Some(smallvec!["nt"]),
(_, Voice::Passive, _, Person::First, Number::Singular) => Some(smallvec!["or"]),
(_, Voice::Passive, _, Person::First, Number::Plural) => Some(smallvec!["mur"]),
(_, Voice::Passive, _, Person::Second, Number::Singular) => Some(smallvec!["ris", "re"]),
(_, Voice::Passive, _, Person::Second, Number::Plural) => Some(smallvec!["minī"]),
(_, Voice::Passive, _, Person::Third, Number::Singular) => Some(smallvec!["tur"]),
(_, Voice::Passive, _, Person::Third, Number::Plural) => Some(smallvec!["ntur"]),
_ => None,
}
}
fn tense_particle(group: Group, person: Person, number: Number, tense: Tense, voice: Voice, mood: Mood) -> Option<&'static str> {
match (mood, voice, tense, person, number) {
(Mood::Subjunctive, _, Tense::Imperfect, _, _) => None,
(Mood::Subjunctive, Voice::Active, Tense::Perfect, _, _) => Some("erī"),
(Mood::Subjunctive, Voice::Active, Tense::Pluperfect, _, _) => Some("issē"),
(_, Voice::Passive, Tense::Future, Person::First, Number::Singular) if group == Group::Third || group == Group::Fourth => None,
(_, Voice::Passive, Tense::Future, Person::Second, Number::Singular) if group == Group::First || group == Group::Second => Some("be"),
(_, _, Tense::Future, Person::First, Number::Singular) if group == Group::First || group == Group::Second => Some("b"),
(_, _, Tense::Future, Person::Third, Number::Plural) if group == Group::First || group == Group::Second => Some("b"),
(_, _, Tense::FuturePerfect, Person::First, Number::Singular) => Some("er"),
(_, _, Tense::Future, _, _) if group == Group::First || group == Group::Second => Some("bi"),
(_, _, Tense::Imperfect, _, _) => Some("bā"),
(_, _, Tense::Pluperfect, _, _) => Some("erā"),
(_, _, Tense::FuturePerfect, _, _) => Some("eri"),
_ => None,
}
}
fn stem_vowel(group: Group, person: Person, number: Number, tense: Tense, voice: Voice, mood: Mood) -> Option<&'static str> {
match (group, mood, voice, person, number) {
(Group::First, Mood::Indicative, Voice::Active, Person::First, Number::Singular) if tense == Tense::Present => None,
(Group::First, Mood::Indicative, Voice::Passive, Person::First, Number::Singular) if tense == Tense::Present => None,
(Group::First, Mood::Indicative, _, _, _) if tense == Tense::Present || tense == Tense::Imperfect || tense == Tense::Future => Some("ā"),
(Group::Second, Mood::Indicative, _, _, _) if tense == Tense::Present || tense == Tense::Imperfect || tense == Tense::Future => Some("ē"),
(Group::Third, Mood::Indicative, Voice::Active, Person::First, Number::Singular) if tense == Tense::Present || tense == Tense::Future => None,
(Group::Third, Mood::Indicative, Voice::Active, Person::Third, Number::Plural) if tense == Tense::Present => None,
(Group::Third, Mood::Indicative, Voice::Passive, Person::First, Number::Singular) if tense == Tense::Present => None,
(Group::Third, Mood::Indicative, Voice::Passive, Person::First, Number::Singular) if tense == Tense::Future => Some("a"),
(Group::Third, Mood::Indicative, Voice::Passive, Person::Second, Number::Singular) if tense == Tense::Present => Some("e"),
(Group::Third, Mood::Indicative, Voice::Passive, Person::Third, Number::Plural) if tense == Tense::Present => None,
(Group::Third, Mood::Indicative, _, _, _) if tense == Tense::Present => Some("i"),
(Group::Third, Mood::Indicative, _, _, _) if tense == Tense::Imperfect || tense == Tense::Future => Some("ē"),
(Group::Fourth, Mood::Indicative, Voice::Active, Person::First, Number::Singular) if tense == Tense::Future => Some("ī"),
(Group::Fourth, Mood::Indicative, Voice::Passive, Person::First, Number::Singular) if tense == Tense::Future => Some("ia"),
(Group::Fourth, Mood::Indicative, _, _, _) if tense == Tense::Imperfect || tense == Tense::Future => Some("iē"),
(Group::Fourth, Mood::Indicative, _, _, _) if tense == Tense::Present => Some("ī"),
(_, Mood::Subjunctive, _, _, _) if tense == Tense::Imperfect => Some("ē"),
(Group::First, Mood::Subjunctive, _, _, _) if tense == Tense::Present => Some("ē"),
(Group::Second, Mood::Subjunctive, _, _, _) if tense == Tense::Present => Some("eā"),
(Group::Third, Mood::Subjunctive, _, _, _) if tense == Tense::Present => Some("ā"),
(Group::Fourth, Mood::Subjunctive, _, _, _) if tense == Tense::Present => Some("iā"),
_ => None,
}
}
pub(super) fn endings<'a>(group: Group, person: Person, number: Number, tense: Tense, voice: Voice, mood: Mood) -> Option<Suffixes<'a>> {
match (mood, voice, tense, person, number) {
(Mood::Subjunctive, _, Tense::Future, _, _) => None,
(Mood::Subjunctive, _, Tense::FuturePerfect, _, _) => None,
(Mood::Indicative, Voice::Passive, Tense::Perfect, _, _) => None,
(Mood::Indicative, Voice::Passive, Tense::Pluperfect, _, _) => None,
(Mood::Subjunctive, Voice::Passive, Tense::Perfect, _, _) => None,
(Mood::Subjunctive, Voice::Passive, Tense::Pluperfect, _, _) => None,
_ => {
generate_suffixes(group, person, number, tense, voice, mood)
}
}
}
pub(super) fn perfect_passive_sum<'a>(person: Person, number: Number, tense: Tense, mood: Mood) -> Option<&'a str> {
match (mood, tense, person, number) {
(Mood::Indicative, Tense::Perfect, Person::First, Number::Singular) => Some("sum"),
(Mood::Indicative, Tense::Perfect, Person::Second, Number::Singular) => Some("es"),
(Mood::Indicative, Tense::Perfect, Person::Third, Number::Singular) => Some("est"),
(Mood::Indicative, Tense::Perfect, Person::First, Number::Plural) => Some("sumus"),
(Mood::Indicative, Tense::Perfect, Person::Second, Number::Plural) => Some("estis"),
(Mood::Indicative, Tense::Perfect, Person::Third, Number::Plural) => Some("sunt"),
(Mood::Indicative, Tense::Pluperfect, Person::First, Number::Singular) => Some("eram"),
(Mood::Indicative, Tense::Pluperfect, Person::Second, Number::Singular) => Some("erās"),
(Mood::Indicative, Tense::Pluperfect, Person::Third, Number::Singular) => Some("erat"),
(Mood::Indicative, Tense::Pluperfect, Person::First, Number::Plural) => Some("erāmus"),
(Mood::Indicative, Tense::Pluperfect, Person::Second, Number::Plural) => Some("erātis"),
(Mood::Indicative, Tense::Pluperfect, Person::Third, Number::Plural) => Some("erant"),
(Mood::Indicative, Tense::FuturePerfect, Person::First, Number::Singular) => Some("erō"),
(Mood::Indicative, Tense::FuturePerfect, Person::Second, Number::Singular) => Some("eris"),
(Mood::Indicative, Tense::FuturePerfect, Person::Third, Number::Singular) => Some("erit"),
(Mood::Indicative, Tense::FuturePerfect, Person::First, Number::Plural) => Some("erimus"),
(Mood::Indicative, Tense::FuturePerfect, Person::Second, Number::Plural) => Some("eritis"),
(Mood::Indicative, Tense::FuturePerfect, Person::Third, Number::Plural) => Some("erunt"),
(Mood::Subjunctive, Tense::Perfect, Person::First, Number::Singular) => Some("sim"),
(Mood::Subjunctive, Tense::Perfect, Person::Second, Number::Singular) => Some("sīs"),
(Mood::Subjunctive, Tense::Perfect, Person::Third, Number::Singular) => Some("sit"),
(Mood::Subjunctive, Tense::Perfect, Person::First, Number::Plural) => Some("sīmus"),
(Mood::Subjunctive, Tense::Perfect, Person::Second, Number::Plural) => Some("sītis"),
(Mood::Subjunctive, Tense::Perfect, Person::Third, Number::Plural) => Some("sint"),
(Mood::Subjunctive, Tense::Pluperfect, Person::First, Number::Singular) => Some("essem"),
(Mood::Subjunctive, Tense::Pluperfect, Person::Second, Number::Singular) => Some("essēs"),
(Mood::Subjunctive, Tense::Pluperfect, Person::Third, Number::Singular) => Some("esset"),
(Mood::Subjunctive, Tense::Pluperfect, Person::First, Number::Plural) => Some("essēmus"),
(Mood::Subjunctive, Tense::Pluperfect, Person::Second, Number::Plural) => Some("essētis"),
(Mood::Subjunctive, Tense::Pluperfect, Person::Third, Number::Plural) => Some("essent"),
_ => None,
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_combine_with_stem() {
let stem = "laud";
let stem_vowel = "ā";
let tense_particle = "bā";
let personal_ending = "mus";
let mut suffix = Suffix::new();
suffix.push("ō");
assert_eq!(suffix.spilled(), false, "Ending spilled onto heap with only one element added.");
assert_eq!(super::super::conjugate_from_fragments(stem, &suffix), "laudō".to_string(), "Failed to combine verb stem with an ending.");
let mut suffix = Suffix::new();
suffix.push(stem_vowel);
suffix.push(personal_ending);
assert_eq!(suffix.spilled(), false, "Ending spilled onto heap with only two elements added.");
assert_eq!(super::super::conjugate_from_fragments(stem, &suffix), "laudāmus".to_string(), "Failed to combine verb stem with an ending.");
let mut suffix = Suffix::new();
suffix.push(stem_vowel);
suffix.push(tense_particle);
suffix.push(personal_ending);
assert_eq!(suffix.spilled(), false, "Ending spilled onto heap with only three elements added.");
assert_eq!(super::super::conjugate_from_fragments(stem, &suffix), "laudābāmus".to_string(), "Failed to combine verb stem with an ending.");
match generate_suffixes(Group::First, Person::Third, Number::Plural, Tense::Present, Voice::Active, Mood::Indicative) {
Some(ref suffix) if suffix.len() == 1=> assert_eq!(super::super::conjugate_from_fragments(stem, &suffix[0]), "laudant" , "The stem vowel `ā` was not converted to `a` when followed with `nt`."),
_ => panic!("Failed to generate an Ending for third person plural present active indicative conjugation for the first conjugation group."),
}
match generate_suffixes(Group::First, Person::Third, Number::Plural, Tense::Imperfect, Voice::Active, Mood::Indicative) {
Some(ref suffix) if suffix.len() == 1 => assert_eq!(super::super::conjugate_from_fragments(stem, &suffix[0]), "laudābant" , "The imperfect tense particle `bā` was not converted to `ba` when followed with `nt`."),
_ => panic!("Failed to generate an Ending for third person plural imperfect active indicative conjugation for the first conjugation group."),
}
}
}