use std::fmt;
use crate::adjective::{Adjective};
use crate::adjective as A;
use crate::verb::endings as E;
use crate::unicode as U;
use super::{Number, Voice, Tense, Mood, Group, Person};
pub struct Regular {
present_active_indicative: String,
present_active_infinitive: String,
perfect_active_indicative: String,
perfect_passive_participle: A::Regular, }
impl fmt::Display for Regular {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match &self.perfect_passive_participle.decline(Number::Singular, A::Case::Nominative, A::Gender::Neuter) {
Some(declension) => {
match declension.first() {
Some(first) => write!(f, "{}, {}, {}, {}", &self.present_active_indicative, &self.present_active_infinitive, &self.perfect_active_indicative, first),
None => write!(f, "{} {} {}", &self.present_active_indicative, &self.present_active_infinitive, &self.perfect_active_indicative),
}
},
None => unreachable!(),
}
}
}
#[derive(Clone, Debug)]
pub enum RegularError {
InvalidPresentActiveIndicativeEnding(),
InvalidPresentActiveInfinitiveEnding(),
InvalidPerfectActiveIndicativeEnding(),
InvalidPerfectPassiveParticipleEnding(),
FailedToCreateParticiple(A::RegularError),
}
impl fmt::Display for RegularError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
RegularError::InvalidPresentActiveIndicativeEnding() => {
write!(f, "The ending of the present active indiciative form is incorrect.")
},
RegularError::InvalidPresentActiveInfinitiveEnding() => {
write!(f, "The ending of the present active infinitive form does not match that of any conjugation group.")
},
RegularError::InvalidPerfectActiveIndicativeEnding() => {
write!(f, "The ending of the perfect active indiciative form is incorrect.")
},
RegularError::InvalidPerfectPassiveParticipleEnding() => {
write!(f, "The ending of the perfect passive participle form is does not match that of any first and second declension adjective gender.")
},
RegularError::FailedToCreateParticiple(adjective_error) => {
write!(f, "Failed to create the participle form. Received the following error from crate::adjective::Regular::new: {}", adjective_error)
},
}
}
}
impl Regular {
fn create_participle_dictionary(stem: &str) -> A::DictionaryForm {
A::DictionaryForm::Three(format!("{}{}", stem, "us"), format!("{}{}", stem, "a"), format!("{}{}", stem, "um"))
}
pub fn new(present_active_indicative: String, present_active_infinitive: String, perfect_active_indicative: String, perfect_passive_participle: String) -> Result<Regular, RegularError> {
let present_active_indicative = U::normalize(present_active_indicative);
let present_active_infinitive = U::normalize(present_active_infinitive);
let perfect_active_indicative = U::normalize(perfect_active_indicative);
let perfect_passive_participle = U::normalize(perfect_passive_participle);
if !present_active_indicative.ends_with("ō") {
return Err(RegularError::InvalidPresentActiveIndicativeEnding())
}
if super::not_normalized_group(&present_active_infinitive).is_none() {
return Err(RegularError::InvalidPresentActiveInfinitiveEnding())
}
if super::not_normalized_perfect_stem(&perfect_active_indicative).is_none() {
return Err(RegularError::InvalidPerfectActiveIndicativeEnding())
}
match super::not_normalized_participle_stem(&perfect_passive_participle) {
Some(stem) => {
match A::Regular::new(Regular::create_participle_dictionary(stem)) {
Ok(adjective) => {
Ok(Regular {
present_active_indicative,
present_active_infinitive,
perfect_active_indicative,
perfect_passive_participle: adjective,
})
},
Err(error) => Err(RegularError::FailedToCreateParticiple(error))
}
},
None => Err(RegularError::InvalidPerfectPassiveParticipleEnding())
}
}
fn stem(&self, tense: Tense) -> Option<&str> {
match tense {
Tense::Perfect | Tense::Pluperfect | Tense::FuturePerfect => {
super::not_normalized_perfect_stem(&self.perfect_active_indicative)
},
Tense::Present | Tense::Imperfect | Tense::Future => {
super::not_normalized_present_stem(&self.present_active_infinitive)
},
}
}
fn is_third_io(&self) -> bool {
if let Some(Group::Third) = super::not_normalized_group(&self.present_active_infinitive) {
self.present_active_indicative.ends_with("iō")
} else {
false
}
}
fn stem_with_endings(&self, person: Person, number: Number, tense: Tense, voice: Voice, mood: Mood) -> Option<super::Conjugation> {
let group = super::not_normalized_group(&self.present_active_infinitive)?;
self.stem_with_endings_for_group(group, person, number, tense, voice, mood)
}
fn stem_with_endings_for_group(&self, group: Group, person: Person, number: Number, tense: Tense, voice: Voice, mood: Mood) -> Option<super::Conjugation> {
let stem = self.stem(tense)?;
self.endings_for_group(stem, group, person, number, tense, voice, mood)
}
fn endings_for_group(&self, stem: &str, group: Group, person: Person, number: Number, tense: Tense, voice: Voice, mood: Mood) -> Option<super::Conjugation> {
let suffixes = E::endings(group, person, number, tense, voice, mood)?;
let mut combined = Vec::new();
for fragments in suffixes {
combined.push(super::conjugate_from_fragments(stem, &fragments));
}
Some(super::Conjugation::Complete(combined))
}
fn perfect_passive(&self, person: Person, number: Number, tense: Tense, mood: Mood) -> Option<super::Conjugation> {
let sum = E::perfect_passive_sum(person, number, tense, mood)?;
Some(super::Conjugation::PassivePerfect(&self.perfect_passive_participle, sum))
}
}
impl super::Verb for Regular {
fn present_stem(&self) -> Option<&str> {
super::not_normalized_present_stem(&self.present_active_infinitive)
}
fn perfect_stem(&self) -> Option<&str> {
super::not_normalized_perfect_stem(&self.perfect_active_indicative)
}
fn group(&self) -> Option<Group> {
super::not_normalized_group(&self.present_active_infinitive)
}
fn conjugate(&self, person: Person, number: Number, tense: Tense, voice: Voice, mood: Mood) -> Option<super::Conjugation> {
match (mood, voice, tense, person, number) {
(Mood::Indicative, _, Tense::Present, Person::First, Number::Singular) if self.is_third_io() => self.stem_with_endings_for_group(Group::Fourth, person, number, tense, voice, mood),
(Mood::Indicative, _, Tense::Present, Person::Third, Number::Plural) if self.is_third_io() => self.stem_with_endings_for_group(Group::Fourth, person, number, tense, voice, mood),
(Mood::Indicative, _, Tense::Imperfect, _, _) if self.is_third_io() => self.stem_with_endings_for_group(Group::Fourth, person, number, tense, voice, mood),
(Mood::Indicative, _, Tense::Future, _, _) if self.is_third_io() => self.stem_with_endings_for_group(Group::Fourth, person, number, tense, voice, mood),
(Mood::Subjunctive, _, Tense::Present, _, _) if self.is_third_io() => self.stem_with_endings_for_group(Group::Fourth, person, number, tense, voice, mood),
(Mood::Indicative, Voice::Passive, Tense::Perfect, _, _) |
(Mood::Indicative, Voice::Passive, Tense::Pluperfect, _, _) |
(Mood::Indicative, Voice::Passive, Tense::FuturePerfect, _, _) => self.perfect_passive(person, number, tense, mood),
(Mood::Subjunctive, Voice::Passive, Tense::Perfect, _, _) |
(Mood::Subjunctive, Voice::Passive, Tense::Pluperfect, _, _) =>self.perfect_passive(person, number, tense, mood),
(Mood::Subjunctive, _, Tense::Imperfect, _, _) => self.endings_for_group(self.present_active_infinitive.trim_end_matches('e'), super::not_normalized_group(&self.present_active_infinitive)?, person, number, tense, voice, mood),
_ => self.stem_with_endings(person, number, tense, voice, mood),
}
}
}
#[cfg(test)]
mod test {
use super::*;
use unicode_normalization::{is_nfc};
use crate::verb::{Verb};
use crate::adjective::{Adjective};
use crate::adjective as A;
fn verify_normalization(verb: &Regular) {
assert!(is_nfc(&verb.present_active_indicative), "The present active indicative form is not stored in NFC form.");
assert!(is_nfc(&verb.present_active_infinitive), "The present active infinitive form is not stored in NFC form.");
assert!(is_nfc(&verb.perfect_active_indicative), "The perfect active indicative form is not stored in NFC form.");
}
fn verify_struct(verb: &Regular, present_active_indicative: &str, present_active_infinitive: &str, perfect_active_indicative: &str, perfect_passive_participle: &str) {
assert_eq!(verb.present_active_indicative, present_active_indicative.to_string(), "The stored present active indicative is incorrect.");
assert_eq!(verb.present_active_infinitive, present_active_infinitive.to_string(), "The stored present active infinitive is incorrect.");
assert_eq!(verb.perfect_active_indicative, perfect_active_indicative.to_string(), "The stored perfect passive indicative is incorrect.");
match verb.perfect_passive_participle.decline(Number::Singular, A::Case::Nominative, A::Gender::Neuter) {
Some(declension) => {
match declension.first() {
Some(first) => assert_eq!(format!("{}", first), perfect_passive_participle.to_string(), "The stored perfect passive participle is incorrect."),
None => panic!("The declension for the singular nominative neuter form of the perfect passive participle contained no elements."),
}
},
None => panic!("Received a None value when attempting to decline the singular nominative neuter form of the perfect passive participle."),
}
}
fn verify_stem(verb: &Regular, tense: Tense, expected: Option<&str>) {
let verb_stem = verb.stem(tense);
assert_eq!(verb_stem, expected, "verb.stem({:?}) returned {:?} but {:?} was expected.", tense, verb_stem, expected);
}
fn verify_regular(present_active_indicative: &str, present_active_infinitive: &str, perfect_active_indicative: &str, perfect_passive_participle: &str, present_stem: Option<&str>, perfect_stem: Option<&str>, group: Group) {
match Regular::new(present_active_indicative.to_string(), present_active_infinitive.to_string(), perfect_active_indicative.to_string(), perfect_passive_participle.to_string()) {
Ok(verb) => {
verify_normalization(&verb);
verify_struct(&verb, present_active_indicative, present_active_infinitive, perfect_active_indicative, perfect_passive_participle);
let verb_group = verb.group();
assert_eq!(verb_group, Some(group), "verb.group() returned {:?} but {:?} was expected.", verb_group, group);
let verb_present_stem = verb.present_stem();
assert_eq!(verb_present_stem, present_stem, "verb.present_stem() returned {:?} but {:?} was expected.", verb_present_stem, present_stem);
let verb_perfect_stem = verb.perfect_stem();
assert_eq!(verb_perfect_stem, perfect_stem, "verb.perfect_stem() returned {:?} but {:?} was expected.", verb_perfect_stem, perfect_stem);
verify_stem(&verb, Tense::Present, present_stem);
verify_stem(&verb, Tense::Imperfect, present_stem);
verify_stem(&verb, Tense::Future, present_stem);
verify_stem(&verb, Tense::Perfect, perfect_stem);
verify_stem(&verb, Tense::Pluperfect, perfect_stem);
verify_stem(&verb, Tense::FuturePerfect, perfect_stem);
},
Err(error) => panic!("Failed to create regular verb {}, {}, {}, {}. Received the following error: {}", present_active_indicative, present_active_infinitive, perfect_active_indicative, perfect_passive_participle, error),
}
}
#[test]
fn test_new_first() {
verify_regular("laudō", "laudāre", "laudāvī", "laudātum", Some("laud"), Some("laudāv"), Group::First)
}
#[test]
fn test_new_second() {
verify_regular("moneō", "monēre", "monuī", "monitum", Some("mon"), Some("monu"), Group::Second)
}
#[test]
fn test_new_third() {
verify_regular("agō", "agere", "ēgī", "āctum", Some("ag"), Some("ēg"), Group::Third)
}
#[test]
fn test_new_third_io() {
verify_regular("capiō", "capere", "cēpī", "captum", Some("cap"), Some("cēp"), Group::Third)
}
#[test]
fn test_new_fourth() {
verify_regular("audiō", "audīre", "audīvī", "audītum", Some("aud"), Some("audīv"), Group::Fourth)
}
#[test]
fn test_is_third_io() {
let present_active_indicative = "capiō";
let present_active_infinitive = "capere";
let perfect_active_indicative = "cēpī";
let perfect_passive_participle = "captum";
match Regular::new(present_active_indicative.to_string(), present_active_infinitive.to_string(), perfect_active_indicative.to_string(), perfect_passive_participle.to_string()) {
Ok(verb) => {
assert!(verb.is_third_io(), "is_third_io should return true for capiō.");
},
Err(error) => panic!("Failed to create regular verb {}, {}, {}, {}. Received the following error: {}", present_active_indicative, present_active_infinitive, perfect_active_indicative, perfect_passive_participle, error),
}
}
}