1use serde::{Deserialize, Deserializer};
2use std::collections::HashMap;
3use std::error::Error;
4
5pub type NounMap = HashMap<String, NounRecord>;
6pub type AdjectiveMap = HashMap<String, AdjectiveRecord>;
7pub type VerbMap = HashMap<String, VerbRecord>;
8pub type Verb = String;
9
10#[derive(Debug, Deserialize, Clone, Default)]
11pub struct Latin {
12 pub noun_map: NounMap,
13 pub adj_map: AdjectiveMap,
14 pub verb_map: VerbMap,
15}
16
17pub struct ComplexNoun {
18 pub head_noun: String,
21 pub adjective: Vec<String>,
22 pub adposition_noun: Vec<String>,
23}
24
25impl Default for ComplexNoun {
26 fn default() -> Self {
27 Self {
28 head_noun: "exemplum".into(),
29 adposition_noun: Vec::new(),
30 adjective: Vec::new(),
31 }
32 }
33}
34
35#[derive(Debug, Deserialize, Clone, Default)]
36pub struct NounRecord {
37 pub word: String,
38 pub nom_sg: String,
39 pub gen_sg: String,
40 pub dat_sg: String,
41 pub acc_sg: String,
42 pub abl_sg: String,
43 pub voc_sg: String,
44 pub loc_sg: String,
45 pub nom_pl: String,
46 pub gen_pl: String,
47 pub dat_pl: String,
48 pub acc_pl: String,
49 pub abl_pl: String,
50 pub voc_pl: String,
51 pub loc_pl: String,
52
53 #[serde(deserialize_with = "deserialize_gender")]
54 pub gender: Gender,
55}
56
57#[derive(Debug, PartialEq, Clone)]
58pub enum Mood {
59 Indicative,
60 Subjunctive,
61 Imperative,
62 Infinitive,
63 Participle,
64 VerbalNoun,
65}
66
67#[derive(Debug, PartialEq, Clone)]
68pub enum Voice {
69 Active,
70 Passive,
71}
72#[derive(Debug, PartialEq, Clone)]
73pub enum Tense {
74 Present,
75 Imperfect,
76 Future,
77 Perfect,
78 Pluperfect,
79 FuturePerfect,
80}
81
82impl Default for Gender {
83 fn default() -> Gender {
84 Gender::Masculine
85 }
86}
87
88#[derive(Debug, Deserialize, Clone, Default)]
90pub struct VerbRecord {
91 pub word: String,
92 pub canonical: String,
93 pub present_infinitive: String,
94 pub perfect_active: String,
95 pub supine: String,
96 pub indicative_active_present_singular_first: String,
97 pub indicative_active_present_singular_second: String,
98 pub indicative_active_present_singular_third: String,
99 pub indicative_active_present_plural_first: String,
100 pub indicative_active_present_plural_second: String,
101 pub indicative_active_present_plural_third: String,
102 pub indicative_active_imperfect_singular_first: String,
103 pub indicative_active_imperfect_singular_second: String,
104 pub indicative_active_imperfect_singular_third: String,
105 pub indicative_active_imperfect_plural_first: String,
106 pub indicative_active_imperfect_plural_second: String,
107 pub indicative_active_imperfect_plural_third: String,
108 pub indicative_active_future_singular_first: String,
109 pub indicative_active_future_singular_second: String,
110 pub indicative_active_future_singular_third: String,
111 pub indicative_active_future_plural_first: String,
112 pub indicative_active_future_plural_second: String,
113 pub indicative_active_future_plural_third: String,
114 pub indicative_active_perfect_singular_first: String,
115 pub indicative_active_perfect_singular_second: String,
116 pub indicative_active_perfect_singular_third: String,
117 pub indicative_active_perfect_plural_first: String,
118 pub indicative_active_perfect_plural_second: String,
119 pub indicative_active_perfect_plural_third: String,
120 pub indicative_active_pluperfect_singular_first: String,
121 pub indicative_active_pluperfect_singular_second: String,
122 pub indicative_active_pluperfect_singular_third: String,
123 pub indicative_active_pluperfect_plural_first: String,
124 pub indicative_active_pluperfect_plural_second: String,
125 pub indicative_active_pluperfect_plural_third: String,
126}
127
128#[derive(Debug, Deserialize, Clone, Default)]
130pub struct AdjectiveRecord {
131 pub word: String,
132
133 pub comparative: String,
134 pub superlative: String,
135 pub adverb: String,
136 pub nom_sg_masc: String,
137 pub gen_sg_masc: String,
138 pub dat_sg_masc: String,
139 pub acc_sg_masc: String,
140 pub abl_sg_masc: String,
141 pub nom_sg_fem: String,
142 pub gen_sg_fem: String,
143 pub dat_sg_fem: String,
144 pub acc_sg_fem: String,
145 pub abl_sg_fem: String,
146 pub nom_sg_neut: String,
147 pub gen_sg_neut: String,
148 pub dat_sg_neut: String,
149 pub acc_sg_neut: String,
150 pub abl_sg_neut: String,
151 pub nom_pl_masc: String,
152 pub gen_pl_masc: String,
153 pub dat_pl_masc: String,
154 pub acc_pl_masc: String,
155 pub abl_pl_masc: String,
156 pub nom_pl_fem: String,
157 pub gen_pl_fem: String,
158 pub dat_pl_fem: String,
159 pub acc_pl_fem: String,
160 pub abl_pl_fem: String,
161 pub nom_pl_neut: String,
162 pub gen_pl_neut: String,
163 pub dat_pl_neut: String,
164 pub acc_pl_neut: String,
165 pub abl_pl_neut: String,
166}
167
168fn deserialize_gender<'de, D>(deserializer: D) -> Result<Gender, D::Error>
169where
170 D: Deserializer<'de>,
171{
172 let s: String = String::deserialize(deserializer)?;
173 match s.as_str() {
174 "m" => Ok(Gender::Masculine),
175 "f" => Ok(Gender::Feminine),
176 "n" => Ok(Gender::Neuter),
177 _ => Err(serde::de::Error::custom("unknown gender")),
178 }
179}
180
181fn deserialize_pluralia<'de, D>(deserializer: D) -> Result<bool, D::Error>
182where
183 D: Deserializer<'de>,
184{
185 let s: String = String::deserialize(deserializer)?;
186 match s.as_str() {
187 "fa" => Ok(false),
188 "tr" => Ok(true),
189
190 _ => Err(serde::de::Error::custom("unknown pluralia")),
191 }
192}
193
194#[derive(Debug, PartialEq, Clone)]
195pub enum Gender {
196 Masculine,
197 Feminine,
198 Neuter,
199}
200#[derive(Debug, PartialEq, Clone)]
201pub enum Case {
202 Nom,
203 Gen,
204 Dat,
205 Acc,
206 Abl,
207 Loc,
208 Voc,
209}
210
211#[derive(Debug, PartialEq, Clone)]
212pub struct CaseEndings {
213 pub gender: Gender,
214 pub nom_sg: &'static str,
215 pub acc_sg: &'static str,
216 pub gen_sg: &'static str,
217 pub dat_sg: &'static str,
218 pub abl_sg: &'static str,
219
220 pub nom_pl: &'static str,
221 pub acc_pl: &'static str,
222 pub gen_pl: &'static str,
223 pub dat_pl: &'static str,
224 pub abl_pl: &'static str,
225}
226
227impl CaseEndings {
228 pub fn ending(&self, case: &Case, number: &Number) -> &str {
229 match number {
230 Number::Singular => match case {
231 Case::Nom => self.nom_sg,
232 Case::Acc => self.acc_sg,
233 Case::Gen => self.gen_sg,
234 Case::Dat => self.dat_sg,
235 Case::Abl => self.abl_sg,
236 Case::Loc => self.abl_sg,
237 Case::Voc => self.nom_sg,
238 },
239 Number::Plural => match case {
240 Case::Nom => self.nom_pl,
241 Case::Acc => self.acc_pl,
242 Case::Gen => self.gen_pl,
243 Case::Dat => self.dat_pl,
244 Case::Abl => self.abl_pl,
245 Case::Loc => self.abl_pl,
246 Case::Voc => self.nom_pl,
247 },
248 }
249 }
250}
251
252pub const ONE_LETTER_ENDINGS: [CaseEndings; 4] = [
253 A_DECLENSION_ENDINGS,
254 E_DECLENSION_ENDINGS,
255 O_DECLENSION_ENDINGS,
256 U_DECLENSION_ENDINGS,
257];
258pub const TWO_LETTER_ENDINGS: [CaseEndings; 23] = [
259 AL_DECLENSION_ENDINGS,
260 AR_DECLENSION_ENDINGS,
261 AR_DECLENSION_ENDINGS,
262 AS_DECLENSION_ENDINGS,
263 AX_DECLENSION_ENDINGS,
264 EN_DECLENSION_ENDINGS,
265 ER_DECLENSION_ENDINGS,
266 ES_DECLENSION_ENDINGS,
267 EX_DECLENSION_ENDINGS,
268 ON_DECLENSION_ENDINGS,
269 OR_DECLENSION_ENDINGS,
270 OS_DECLENSION_ENDINGS,
271 UM_DECLENSION_ENDINGS,
272 US_DECLENSION_ENDINGS,
273 UT_DECLENSION_ENDINGS,
274 UX_DECLENSION_ENDINGS,
275 MA_DECLENSION_ENDINGS,
276 YX_DECLENSION_ENDINGS,
277 YS_DECLENSION_ENDINGS,
278 NX_DECLENSION_ENDINGS,
279 MA_DECLENSION_ENDINGS,
280 IS_DECLENSION_ENDINGS,
281 IX_DECLENSION_ENDINGS,
282];
283
284pub const TEST_ENDINGS: CaseEndings = CaseEndings {
285 gender: Gender::Neuter,
286 nom_sg: "nom_sg",
287 acc_sg: "acc_sg",
288 gen_sg: "gen_sg",
289 dat_sg: "dat_sg",
290 abl_sg: "abl_sg",
291
292 nom_pl: "nom_pl",
293 acc_pl: "acc_pl",
294 gen_pl: "gen_pl",
295 dat_pl: "dat_pl",
296 abl_pl: "abl_pl",
297};
298
299pub const A_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
300 gender: Gender::Feminine,
301 nom_sg: "a",
302 acc_sg: "am",
303 gen_sg: "ae",
304 dat_sg: "ae",
305 abl_sg: "a",
306
307 nom_pl: "ae",
308 acc_pl: "as",
309 gen_pl: "arum",
310 dat_pl: "is",
311 abl_pl: "is",
312};
313
314pub const US_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
330 gender: Gender::Masculine,
331 nom_sg: "us",
332 acc_sg: "um",
333 gen_sg: "i",
334 dat_sg: "o",
335 abl_sg: "o",
336
337 nom_pl: "i",
338 acc_pl: "os",
339 gen_pl: "orum",
340 dat_pl: "is",
341 abl_pl: "is",
342};
343
344pub const O_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
345 gender: Gender::Masculine,
346 nom_sg: "o",
347 acc_sg: "onem",
348 gen_sg: "onis",
349 dat_sg: "oni",
350 abl_sg: "one",
351
352 nom_pl: "ones",
353 acc_pl: "ones",
354 gen_pl: "onum",
355 dat_pl: "onibus",
356 abl_pl: "onibus",
357};
358
359pub const ON_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
360 gender: Gender::Masculine,
361 nom_sg: "on",
362 acc_sg: "ontem",
363 gen_sg: "ontis",
364 dat_sg: "onti",
365 abl_sg: "onte",
366
367 nom_pl: "ontes",
368 acc_pl: "ontes",
369 gen_pl: "ontum",
370 dat_pl: "ontibus",
371 abl_pl: "ontibus",
372};
373
374pub const UT_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
375 gender: Gender::Neuter,
376 nom_sg: "ut",
377 acc_sg: "ut",
378 gen_sg: "itis",
379 dat_sg: "iti",
380 abl_sg: "ite",
381
382 nom_pl: "ita",
383 acc_pl: "ita",
384 gen_pl: "itum",
385 dat_pl: "itibus",
386 abl_pl: "itibus",
387};
388
389pub const OR_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
390 gender: Gender::Masculine,
391 nom_sg: "or",
392 acc_sg: "orem",
393 gen_sg: "oris",
394 dat_sg: "ori",
395 abl_sg: "ore",
396
397 nom_pl: "ores",
398 acc_pl: "ores",
399 gen_pl: "orum",
400 dat_pl: "oribus",
401 abl_pl: "oribus",
402};
403
404pub const OR_ADJ_NEUTER_ENDINGS: CaseEndings = CaseEndings {
405 gender: Gender::Masculine,
406 nom_sg: "or",
407 acc_sg: "or",
408 gen_sg: "oris",
409 dat_sg: "ori",
410 abl_sg: "ori",
411
412 nom_pl: "oria",
413 acc_pl: "oria",
414 gen_pl: "orium",
415 dat_pl: "oribus",
416 abl_pl: "oribus",
417};
418
419pub const OS_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
420 gender: Gender::Masculine,
421 nom_sg: "os",
422 acc_sg: "orem",
423 gen_sg: "oris",
424 dat_sg: "ori",
425 abl_sg: "ore",
426
427 nom_pl: "ores",
428 acc_pl: "ores",
429 gen_pl: "orum",
430 dat_pl: "oribus",
431 abl_pl: "oribus",
432};
433pub const S_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
434 gender: Gender::Masculine,
435 nom_sg: "s",
436 acc_sg: "tem",
437 gen_sg: "tis",
438 dat_sg: "ti",
439 abl_sg: "te",
440
441 nom_pl: "tes",
442 acc_pl: "tes",
443 gen_pl: "tium",
444 dat_pl: "tibus",
445 abl_pl: "tibus",
446};
447
448pub const S_ADJ_NEUTER_ENDINGS: CaseEndings = CaseEndings {
449 gender: Gender::Masculine,
450 nom_sg: "s",
451 acc_sg: "s",
452 gen_sg: "tis",
453 dat_sg: "ti",
454 abl_sg: "te",
455
456 nom_pl: "tia",
457 acc_pl: "tia",
458 gen_pl: "tium",
459 dat_pl: "tibus",
460 abl_pl: "tibus",
461};
462
463pub const UM_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
464 gender: Gender::Neuter,
465 nom_sg: "um",
466 acc_sg: "um",
467 gen_sg: "i",
468 dat_sg: "o",
469 abl_sg: "o",
470
471 nom_pl: "a",
472 acc_pl: "a",
473 gen_pl: "orum",
474 dat_pl: "is",
475 abl_pl: "is",
476};
477
478pub const U_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
494 gender: Gender::Neuter,
495 nom_sg: "u",
496 acc_sg: "u",
497 gen_sg: "us",
498 dat_sg: "ui",
499 abl_sg: "u",
500
501 nom_pl: "ua",
502 acc_pl: "ua",
503 gen_pl: "uum",
504 dat_pl: "uibus",
505 abl_pl: "uibus",
506};
507
508pub const ER_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
509 gender: Gender::Masculine,
510 nom_sg: "er",
511 acc_sg: "er",
512 gen_sg: "eris",
513 dat_sg: "eri",
514 abl_sg: "ere",
515
516 nom_pl: "era",
517 acc_pl: "era",
518 gen_pl: "erum",
519 dat_pl: "eribus",
520 abl_pl: "eribus",
521};
522
523pub const ER_ADJECTIVE_MASC_ENDINGS: CaseEndings = CaseEndings {
524 gender: Gender::Masculine,
525 nom_sg: "",
526 acc_sg: "um",
527 gen_sg: "i",
528 dat_sg: "o",
529 abl_sg: "o",
530
531 nom_pl: "i",
532 acc_pl: "os",
533 gen_pl: "orum",
534 dat_pl: "is",
535 abl_pl: "is",
536};
537
538pub const AL_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
539 gender: Gender::Neuter,
540 nom_sg: "al",
541 acc_sg: "al",
542 gen_sg: "alis",
543 dat_sg: "ali",
544 abl_sg: "ali",
545
546 nom_pl: "alia",
547 acc_pl: "alia",
548 gen_pl: "alium",
549 dat_pl: "alibus",
550 abl_pl: "alibus",
551};
552
553pub const AR_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
554 gender: Gender::Neuter,
555 nom_sg: "ar",
556 acc_sg: "ar",
557 gen_sg: "aris",
558 dat_sg: "ari",
559 abl_sg: "ari",
560
561 nom_pl: "aria",
562 acc_pl: "aria",
563 gen_pl: "arium",
564 dat_pl: "aribus",
565 abl_pl: "aribus",
566};
567
568pub const AS_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
569 gender: Gender::Feminine,
570 nom_sg: "as",
571 acc_sg: "atem",
572 gen_sg: "atis",
573 dat_sg: "ati",
574 abl_sg: "ate",
575
576 nom_pl: "ates",
577 acc_pl: "ates",
578 gen_pl: "atum",
579 dat_pl: "atibus",
580 abl_pl: "atibus",
581};
582
583pub const AX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
584 gender: Gender::Feminine,
585 nom_sg: "ax",
586 acc_sg: "acem",
587 gen_sg: "acis",
588 dat_sg: "aci",
589 abl_sg: "ace",
590
591 nom_pl: "aces",
592 acc_pl: "aces",
593 gen_pl: "acum",
594 dat_pl: "acibus",
595 abl_pl: "acibus",
596};
597
598pub const IX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
599 gender: Gender::Feminine,
600 nom_sg: "ix",
601 acc_sg: "icem",
602 gen_sg: "icis",
603 dat_sg: "ici",
604 abl_sg: "ice",
605
606 nom_pl: "ices",
607 acc_pl: "ices",
608 gen_pl: "icum",
609 dat_pl: "icibus",
610 abl_pl: "icibus",
611};
612pub const YX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
613 gender: Gender::Feminine,
614 nom_sg: "yx",
615 acc_sg: "ycem",
616 gen_sg: "ycis",
617 dat_sg: "yci",
618 abl_sg: "yce",
619
620 nom_pl: "yces",
621 acc_pl: "yces",
622 gen_pl: "ycum",
623 dat_pl: "ycibus",
624 abl_pl: "ycibus",
625};
626
627pub const YS_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
628 gender: Gender::Masculine,
629 nom_sg: "ys",
630 acc_sg: "ydem",
631 gen_sg: "ydis",
632 dat_sg: "ydi",
633 abl_sg: "yde",
634
635 nom_pl: "ydes",
636 acc_pl: "ydes",
637 gen_pl: "ydum",
638 dat_pl: "ydibus",
639 abl_pl: "ydibus",
640};
641
642pub const UX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
643 gender: Gender::Feminine,
644 nom_sg: "ux",
645 acc_sg: "ucem",
646 gen_sg: "ucis",
647 dat_sg: "uci",
648 abl_sg: "uce",
649
650 nom_pl: "uces",
651 acc_pl: "uces",
652 gen_pl: "ucum",
653 dat_pl: "ucibus",
654 abl_pl: "ucibus",
655};
656
657pub const NX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
658 gender: Gender::Feminine,
659 nom_sg: "nx",
660 acc_sg: "ngem",
661 gen_sg: "ngis",
662 dat_sg: "ngi",
663 abl_sg: "nge",
664
665 nom_pl: "nges",
666 acc_pl: "nges",
667 gen_pl: "ngium",
668 dat_pl: "ngibus",
669 abl_pl: "ngibus",
670};
671
672pub const IS_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
673 gender: Gender::Masculine,
674 nom_sg: "is",
675 acc_sg: "em",
676 gen_sg: "is",
677 dat_sg: "i",
678 abl_sg: "e",
679
680 nom_pl: "es",
681 acc_pl: "es",
682 gen_pl: "ium",
683 dat_pl: "ibus",
684 abl_pl: "ibus",
685};
686
687pub const IS_ADJECTIVE_MASC_ENDINGS: CaseEndings = CaseEndings {
688 gender: Gender::Masculine,
689 nom_sg: "is",
690 acc_sg: "em",
691 gen_sg: "is",
692 dat_sg: "i",
693 abl_sg: "i",
694
695 nom_pl: "es",
696 acc_pl: "es",
697 gen_pl: "ium",
698 dat_pl: "ibus",
699 abl_pl: "ibus",
700};
701
702pub const EX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
703 gender: Gender::Masculine,
704 nom_sg: "ex",
705 acc_sg: "icem",
706 gen_sg: "icis",
707 dat_sg: "ici",
708 abl_sg: "ice",
709
710 nom_pl: "ices",
711 acc_pl: "ices",
712 gen_pl: "icum",
713 dat_pl: "icibus",
714 abl_pl: "icibus",
715};
716
717pub const EX_ADJECTIVE_MASC_ENDINGS: CaseEndings = CaseEndings {
718 gender: Gender::Masculine,
719 nom_sg: "ex",
720 acc_sg: "icem",
721 gen_sg: "icis",
722 dat_sg: "ici",
723 abl_sg: "ici",
724
725 nom_pl: "ices",
726 acc_pl: "ices",
727 gen_pl: "icium",
728 dat_pl: "icibus",
729 abl_pl: "icibus",
730};
731
732pub const EX_ADJECTIVE_NEUT_ENDINGS: CaseEndings = CaseEndings {
733 gender: Gender::Masculine,
734 nom_sg: "ex",
735 acc_sg: "ex",
736 gen_sg: "icis",
737 dat_sg: "ici",
738 abl_sg: "ici",
739
740 nom_pl: "icia",
741 acc_pl: "icia",
742 gen_pl: "icium",
743 dat_pl: "icibus",
744 abl_pl: "icibus",
745};
746
747pub const E_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
748 gender: Gender::Neuter,
749 nom_sg: "e",
750 acc_sg: "e",
751 gen_sg: "is",
752 dat_sg: "i",
753 abl_sg: "i",
754
755 nom_pl: "ia",
756 acc_pl: "ia",
757 gen_pl: "ium",
758 dat_pl: "ibus",
759 abl_pl: "ibus",
760};
761pub const EN_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
762 gender: Gender::Neuter,
763 nom_sg: "en",
764 acc_sg: "en",
765 gen_sg: "inis",
766 dat_sg: "ini",
767 abl_sg: "ine",
768
769 nom_pl: "ina",
770 acc_pl: "ina",
771 gen_pl: "inum",
772 dat_pl: "inibus",
773 abl_pl: "inibus",
774};
775pub const ES_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
776 gender: Gender::Feminine,
777 nom_sg: "es",
778 acc_sg: "em",
779 gen_sg: "ei",
780 dat_sg: "ei",
781 abl_sg: "e",
782
783 nom_pl: "es",
784 acc_pl: "es",
785 gen_pl: "erum",
786 dat_pl: "ebus",
787 abl_pl: "ebus",
788};
789
790pub const ES_ADJ_MASC_ENDINGS: CaseEndings = CaseEndings {
791 gender: Gender::Feminine,
792 nom_sg: "es",
793 acc_sg: "em",
794 gen_sg: "is",
795 dat_sg: "i",
796 abl_sg: "e",
797
798 nom_pl: "es",
799 acc_pl: "es",
800 gen_pl: "um",
801 dat_pl: "ibus",
802 abl_pl: "ibus",
803};
804pub const ES_ADJ_NEUT_ENDINGS: CaseEndings = CaseEndings {
805 gender: Gender::Feminine,
806 nom_sg: "es",
807 acc_sg: "em",
808 gen_sg: "is",
809 dat_sg: "i",
810 abl_sg: "e",
811
812 nom_pl: "es",
813 acc_pl: "es",
814 gen_pl: "um",
815 dat_pl: "ibus",
816 abl_pl: "ibus",
817};
818
819pub const MA_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
820 gender: Gender::Neuter,
821 nom_sg: "ma",
822 acc_sg: "ma",
823 gen_sg: "matis",
824 dat_sg: "mati",
825 abl_sg: "mate",
826
827 nom_pl: "mata",
828 acc_pl: "mata",
829 gen_pl: "matum",
830 dat_pl: "matibus",
831 abl_pl: "matibus",
832};
833
834#[derive(Debug, PartialEq, Clone)]
836pub enum Number {
837 Singular,
838 Plural,
839}
840
841pub type Noun = (String, Gender);
842pub type Adjective = String;
843
844#[derive(Debug, PartialEq, Clone)]
845pub enum Person {
846 First,
847 Second,
848 Third,
849}
850
851impl Latin {
852 pub fn guess_noun(word: &str, case: &Case, number: &Number) -> Noun {
853 let mut appended = Vec::from(TWO_LETTER_ENDINGS);
854 appended.append(&mut Vec::from(ONE_LETTER_ENDINGS));
855
856 for ce in &appended {
857 let nom_end = ce.nom_sg;
858
859 if word.ends_with(nom_end) {
860 let word_gender = &ce.gender;
861
862 let n = nom_end.len();
863
864 let mut word_stem = word.to_string();
865
866 if n <= word.len() {
867 word_stem.truncate(word.len() - n);
868 let ending = ce.ending(case, number);
869 let merged = format!("{}{}", word_stem, ending);
870 return (merged, word_gender.clone());
871 }
872 }
873 }
874
875 (word.to_string(), Gender::Masculine)
876 }
877
878 pub fn guess_adjective(word: &str, case: &Case, number: &Number, gender: &Gender) -> Adjective {
879 let mut word_stem = word.to_string();
880 word_stem.truncate(word_stem.len() - 2);
881
882 let mut masc_ends = &US_DECLENSION_ENDINGS;
883 let mut fem_ends = &A_DECLENSION_ENDINGS;
884 let mut neut_ends = &UM_DECLENSION_ENDINGS;
885
886 if word.ends_with("us") {
887 word_stem = word.to_string();
888 word_stem.truncate(word.len() - 2);
889
890 masc_ends = &US_DECLENSION_ENDINGS;
891 fem_ends = &A_DECLENSION_ENDINGS;
892 neut_ends = &UM_DECLENSION_ENDINGS;
893 } else if word.ends_with("er") {
894 word_stem = word.to_string();
895
896 masc_ends = &ER_ADJECTIVE_MASC_ENDINGS;
897 } else if word.ends_with("is") {
898 word_stem = word.to_string();
899 word_stem.truncate(word.len() - 2);
900
901 masc_ends = &IS_ADJECTIVE_MASC_ENDINGS;
902 fem_ends = &IS_ADJECTIVE_MASC_ENDINGS;
903 neut_ends = &E_DECLENSION_ENDINGS;
904 } else if word.ends_with("ex") {
905 word_stem = word.to_string();
906 word_stem.truncate(word.len() - 2);
907
908 masc_ends = &EX_ADJECTIVE_MASC_ENDINGS;
909 fem_ends = &EX_ADJECTIVE_MASC_ENDINGS;
910 neut_ends = &EX_ADJECTIVE_NEUT_ENDINGS;
911 } else if word.ends_with("or") {
912 word_stem = word.to_string();
913 word_stem.truncate(word.len() - 2);
914
915 masc_ends = &OR_DECLENSION_ENDINGS;
916 fem_ends = &OR_DECLENSION_ENDINGS;
917 neut_ends = &OR_ADJ_NEUTER_ENDINGS;
918 } else if word.ends_with("des") {
919 word_stem = word.to_string();
920 word_stem.truncate(word.len() - 2);
921
922 masc_ends = &ES_ADJ_MASC_ENDINGS;
923 fem_ends = &ES_ADJ_MASC_ENDINGS;
924 neut_ends = &ES_ADJ_NEUT_ENDINGS;
925 } else if word.ends_with("s") {
926 word_stem = word.to_string();
927 word_stem.truncate(word.len() - 1);
928
929 masc_ends = &S_DECLENSION_ENDINGS;
930 fem_ends = &S_DECLENSION_ENDINGS;
931 neut_ends = &S_ADJ_NEUTER_ENDINGS;
932 }
933
934 let ending = match gender {
935 Gender::Feminine => fem_ends.ending(case, number),
936 Gender::Masculine => masc_ends.ending(case, number),
937 Gender::Neuter => neut_ends.ending(case, number),
938 };
939
940 format!("{word_stem}{ending}")
941 }
942
943 pub fn complex_noun(
944 &self,
945 complex_nomen: &ComplexNoun,
946 case: &Case,
947 number: &Number,
948 ) -> String {
949 let noun = self.noun(&complex_nomen.head_noun, case, number);
950
951 let mut response = noun.0;
952
953 for adpos in &complex_nomen.adposition_noun {
954 let adposik = self.noun(adpos, case, number);
955 if adposik.0 != "" {
956 response = format!("{} {}", response, adposik.0);
957 }
958 }
959
960 for adj in &complex_nomen.adjective {
961 let adjik = self.adjective(adj, case, number, &noun.1);
962 if adjik != "" {
963 response = format!("{} {}", response, adjik);
964 }
965 }
966
967 response
968 }
969
970 pub fn noun(&self, word: &str, case: &Case, number: &Number) -> Noun {
971 let defik = NounRecord::default();
972
973 let recordik = self.noun_map.get(word);
974
975 match recordik {
976 Some(record) => {
977 let mut response = match number {
978 Number::Singular => match case {
979 Case::Nom => (record.nom_sg.clone(), record.gender.clone()),
980 Case::Gen => (record.gen_sg.clone(), record.gender.clone()),
981 Case::Dat => (record.dat_sg.clone(), record.gender.clone()),
982 Case::Acc => (record.acc_sg.clone(), record.gender.clone()),
983 Case::Abl => (record.abl_sg.clone(), record.gender.clone()),
984 Case::Voc => (record.voc_sg.clone(), record.gender.clone()),
985 Case::Loc => (record.loc_sg.clone(), record.gender.clone()),
986 },
987 Number::Plural => match case {
988 Case::Nom => (record.nom_pl.clone(), record.gender.clone()),
989 Case::Gen => (record.gen_pl.clone(), record.gender.clone()),
990 Case::Dat => (record.dat_pl.clone(), record.gender.clone()),
991 Case::Acc => (record.acc_pl.clone(), record.gender.clone()),
992 Case::Abl => (record.abl_pl.clone(), record.gender.clone()),
993 Case::Voc => (record.voc_pl.clone(), record.gender.clone()),
994 Case::Loc => (record.loc_pl.clone(), record.gender.clone()),
995 },
996 };
997
998 if case == &Case::Loc && (response.0 == "" || response.0 == "-") {
999 response.0 = format!("{}", record.abl_sg.clone());
1000 }
1001
1002 if (response.0 == "" || response.0 == "-") {
1003 response = Latin::guess_noun(word, case, number);
1004 }
1005
1006 response
1007 }
1008 None => Latin::guess_noun(word, case, number),
1009 }
1010 }
1011
1012 pub fn new(noun_path: String, adjective_path: String, verb_path: String) -> Self {
1013 Latin {
1014 noun_map: Latin::load_nouns_from_csv(noun_path),
1015 adj_map: Latin::load_adjectives_from_csv(adjective_path),
1016 verb_map: Latin::load_verbs_from_csv(verb_path),
1017 }
1018 }
1019
1020 pub fn load_nouns_from_csv(path: String) -> NounMap {
1022 let mut nounmap = HashMap::new();
1023 let file_path: &str = path.as_str();
1024
1025 let mut rdr = csv::Reader::from_path(file_path).unwrap();
1026 for result in rdr.deserialize() {
1027 let record: NounRecord = result.unwrap();
1028
1029 nounmap.insert(record.word.clone(), record.clone());
1030
1031 }
1033 nounmap
1034 }
1035 pub fn load_adjectives_from_csv(path: String) -> AdjectiveMap {
1036 let file_path: &str = path.as_str();
1037 let mut adjmap = HashMap::new();
1038 let mut rdr = csv::Reader::from_path(file_path).unwrap();
1039 for result in rdr.deserialize() {
1040 let record: AdjectiveRecord = result.unwrap();
1042 adjmap.insert(record.word.clone(), record.clone());
1043 }
1045 adjmap
1046 }
1047
1048 pub fn load_verbs_from_csv(path: String) -> VerbMap {
1049 let file_path: &str = path.as_str();
1050 let mut verbmap = HashMap::new();
1051 let mut rdr = csv::Reader::from_path(file_path).unwrap();
1052 for result in rdr.deserialize() {
1053 let record: VerbRecord = result.unwrap();
1055 verbmap.insert(record.word.clone(), record.clone());
1056 }
1058 verbmap
1059 }
1060
1061 pub fn adjective(
1062 &self,
1063 word: &str,
1064 case: &Case,
1065 number: &Number,
1066 gender: &Gender,
1067 ) -> Adjective {
1068 let defik = AdjectiveRecord::default();
1069
1070 let recordik = self.adj_map.get(word);
1071
1072 match recordik {
1073 Some(record) => match gender {
1074 Gender::Masculine => match number {
1075 Number::Singular => match case {
1076 Case::Nom => record.nom_sg_masc.clone(),
1077 Case::Gen => record.gen_sg_masc.clone(),
1078 Case::Dat => record.dat_sg_masc.clone(),
1079 Case::Acc => record.acc_sg_masc.clone(),
1080 Case::Abl => record.abl_sg_masc.clone(),
1081 _ => record.abl_sg_masc.clone(),
1082 },
1083 Number::Plural => match case {
1084 Case::Nom => record.nom_pl_masc.clone(),
1085 Case::Gen => record.gen_pl_masc.clone(),
1086 Case::Dat => record.dat_pl_masc.clone(),
1087 Case::Acc => record.acc_pl_masc.clone(),
1088 Case::Abl => record.abl_pl_masc.clone(),
1089 _ => record.abl_pl_masc.clone(),
1090 },
1091 },
1092 Gender::Feminine => match number {
1093 Number::Singular => match case {
1094 Case::Nom => record.nom_sg_fem.clone(),
1095 Case::Gen => record.gen_sg_fem.clone(),
1096 Case::Dat => record.dat_sg_fem.clone(),
1097 Case::Acc => record.acc_sg_fem.clone(),
1098 Case::Abl => record.abl_sg_fem.clone(),
1099 _ => record.abl_sg_fem.clone(),
1100 },
1101 Number::Plural => match case {
1102 Case::Nom => record.nom_pl_fem.clone(),
1103 Case::Gen => record.gen_pl_fem.clone(),
1104 Case::Dat => record.dat_pl_fem.clone(),
1105 Case::Acc => record.acc_pl_fem.clone(),
1106 Case::Abl => record.abl_pl_fem.clone(),
1107 _ => record.abl_pl_fem.clone(),
1108 },
1109 },
1110 Gender::Neuter => match number {
1111 Number::Singular => match case {
1112 Case::Nom => record.nom_sg_neut.clone(),
1113 Case::Gen => record.gen_sg_neut.clone(),
1114 Case::Dat => record.dat_sg_neut.clone(),
1115 Case::Acc => record.acc_sg_neut.clone(),
1116 Case::Abl => record.abl_sg_neut.clone(),
1117 _ => record.abl_sg_neut.clone(),
1118 },
1119 Number::Plural => match case {
1120 Case::Nom => record.nom_pl_neut.clone(),
1121 Case::Gen => record.gen_pl_neut.clone(),
1122 Case::Dat => record.dat_pl_neut.clone(),
1123 Case::Acc => record.acc_pl_neut.clone(),
1124 Case::Abl => record.abl_pl_neut.clone(),
1125 _ => record.abl_pl_neut.clone(),
1126 },
1127 },
1128 },
1129 None => Latin::guess_adjective(word, case, number, gender),
1130 }
1131 }
1132
1133 pub fn verb(
1134 &self,
1135 word: &str,
1136 mood: &Mood,
1137 voice: &Voice,
1138 tense: &Tense,
1139 number: &Number,
1140 person: &Person,
1141 ) -> Verb {
1142 let defik = VerbRecord::default();
1143
1144 let record = self.verb_map.get(word).unwrap_or(&defik);
1145
1146 match mood {
1147 Mood::Indicative => match voice {
1148 Voice::Active => match tense {
1149 Tense::Present => match number {
1150 Number::Singular => match person {
1151 Person::First => {
1152 record.indicative_active_present_singular_first.clone()
1153 }
1154 Person::Second => {
1155 record.indicative_active_present_singular_second.clone()
1156 }
1157 Person::Third => {
1158 record.indicative_active_present_singular_third.clone()
1159 }
1160 },
1161 Number::Plural => match person {
1162 Person::First => record.indicative_active_present_plural_first.clone(),
1163 Person::Second => {
1164 record.indicative_active_present_plural_second.clone()
1165 }
1166 Person::Third => record.indicative_active_present_plural_third.clone(),
1167 },
1168 },
1169 Tense::Imperfect => match number {
1170 Number::Singular => match person {
1171 Person::First => {
1172 record.indicative_active_imperfect_singular_first.clone()
1173 }
1174 Person::Second => {
1175 record.indicative_active_imperfect_singular_second.clone()
1176 }
1177 Person::Third => {
1178 record.indicative_active_imperfect_singular_third.clone()
1179 }
1180 },
1181 Number::Plural => match person {
1182 Person::First => {
1183 record.indicative_active_imperfect_plural_first.clone()
1184 }
1185 Person::Second => {
1186 record.indicative_active_imperfect_plural_second.clone()
1187 }
1188 Person::Third => {
1189 record.indicative_active_imperfect_plural_third.clone()
1190 }
1191 },
1192 },
1193 Tense::Future => match number {
1194 Number::Singular => match person {
1195 Person::First => record.indicative_active_future_singular_first.clone(),
1196 Person::Second => {
1197 record.indicative_active_future_singular_second.clone()
1198 }
1199 Person::Third => record.indicative_active_future_singular_third.clone(),
1200 },
1201 Number::Plural => match person {
1202 Person::First => record.indicative_active_future_plural_first.clone(),
1203 Person::Second => record.indicative_active_future_plural_second.clone(),
1204 Person::Third => record.indicative_active_future_plural_third.clone(),
1205 },
1206 },
1207 Tense::Perfect => match number {
1208 Number::Singular => match person {
1209 Person::First => {
1210 record.indicative_active_perfect_singular_first.clone()
1211 }
1212 Person::Second => {
1213 record.indicative_active_perfect_singular_second.clone()
1214 }
1215 Person::Third => {
1216 record.indicative_active_perfect_singular_third.clone()
1217 }
1218 },
1219 Number::Plural => match person {
1220 Person::First => record.indicative_active_perfect_plural_first.clone(),
1221 Person::Second => {
1222 record.indicative_active_perfect_plural_second.clone()
1223 }
1224 Person::Third => record.indicative_active_perfect_plural_third.clone(),
1225 },
1226 },
1227 Tense::Pluperfect => match number {
1228 Number::Singular => match person {
1229 Person::First => {
1230 record.indicative_active_pluperfect_singular_first.clone()
1231 }
1232 Person::Second => {
1233 record.indicative_active_pluperfect_singular_second.clone()
1234 }
1235 Person::Third => {
1236 record.indicative_active_pluperfect_singular_third.clone()
1237 }
1238 },
1239 Number::Plural => match person {
1240 Person::First => {
1241 record.indicative_active_pluperfect_plural_first.clone()
1242 }
1243 Person::Second => {
1244 record.indicative_active_pluperfect_plural_second.clone()
1245 }
1246 Person::Third => {
1247 record.indicative_active_pluperfect_plural_third.clone()
1248 }
1249 },
1250 },
1251 Tense::FuturePerfect => {
1252 todo!("IMPLEMENT FUTURE PERFECT")
1253 }
1254 },
1255 _ => todo!("IMPLEMENT PASSIVE VOICE"),
1256 },
1257 _ => todo!("IMPLEMENT OTHER MOODS"),
1258 }
1259 }
1260
1261 pub fn last_n_chars(word: &str, n: usize) -> String {
1262 let split_pos = word.char_indices().nth_back(n - 1).unwrap_or((0, 'a')).0;
1263 word[split_pos..].into()
1264 }
1265}
1266
1267