1use harper_brill::UPOS;
2use is_macro::Is;
3use itertools::Itertools;
4use paste::paste;
5use serde::{Deserialize, Serialize};
6use strum::{EnumCount, VariantArray};
7use strum_macros::{Display, EnumCount, EnumString, VariantArray};
8
9use std::convert::TryFrom;
10
11use crate::spell::WordId;
12use crate::{Document, TokenKind, TokenStringExt};
13
14#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Hash)]
15pub struct WordMetadata {
16 pub noun: Option<NounData>,
17 pub pronoun: Option<PronounData>,
18 pub verb: Option<VerbData>,
19 pub adjective: Option<AdjectiveData>,
20 pub adverb: Option<AdverbData>,
21 pub conjunction: Option<ConjunctionData>,
22 pub swear: Option<bool>,
23 #[serde(default = "default_default")]
27 pub dialects: DialectFlags,
28 pub determiner: Option<DeterminerData>,
30 #[serde(default = "default_false")]
32 pub preposition: bool,
33 #[serde(default = "default_false")]
35 pub common: bool,
36 #[serde(default = "default_none")]
37 pub derived_from: Option<WordId>,
38 pub np_member: Option<bool>,
40 pub pos_tag: Option<UPOS>,
42}
43
44fn default_false() -> bool {
46 false
47}
48
49fn default_none<T>() -> Option<T> {
51 None
52}
53
54fn default_default<T: Default>() -> T {
56 T::default()
57}
58
59macro_rules! generate_metadata_queries {
60 ($($category:ident has $($sub:ident),*).*) => {
61 paste! {
62 pub fn is_likely_homograph(&self) -> bool {
63 [self.is_determiner(), self.preposition, $(
64 self.[< is_ $category >](),
65 )*].iter().map(|b| *b as u8).sum::<u8>() > 1
66 }
67
68 $(
69 #[doc = concat!("Checks if the word is definitely a ", stringify!($category), ".")]
70 pub fn [< is_ $category >](&self) -> bool {
71 self.$category.is_some()
72 }
73
74 $(
75 #[doc = concat!("Checks if the word is definitely a ", stringify!($category), " and more specifically is labeled as (a) ", stringify!($sub), ".")]
76 pub fn [< is_ $sub _ $category >](&self) -> bool {
77 matches!(
78 self.$category,
79 Some([< $category:camel Data >]{
80 [< is_ $sub >]: Some(true),
81 ..
82 })
83 ) }
84
85 #[doc = concat!("Checks if the word is definitely a ", stringify!($category), " and more specifically is labeled as __not__ (a) ", stringify!($sub), ".")]
86 pub fn [< is_non_ $sub _ $category >](&self) -> bool {
87 matches!(
88 self.$category,
89 Some([< $category:camel Data >]{
90 [< is_ $sub >]: None | Some(false),
91 ..
92 })
93 )
94 }
95 )*
96 )*
97 }
98 };
99}
100
101impl WordMetadata {
102 pub fn or(&self, other: &Self) -> Self {
104 macro_rules! merge {
105 ($a:expr, $b:expr) => {
106 match ($a, $b) {
107 (Some(a), Some(b)) => Some(a.or(&b)),
108 (Some(a), None) => Some(a),
109 (None, Some(b)) => Some(b),
110 (None, None) => None,
111 }
112 };
113 }
114
115 Self {
116 noun: merge!(self.noun, other.noun),
117 pronoun: merge!(self.pronoun, other.pronoun),
118 verb: merge!(self.verb, other.verb),
119 adjective: merge!(self.adjective, other.adjective),
120 adverb: merge!(self.adverb, other.adverb),
121 conjunction: merge!(self.conjunction, other.conjunction),
122 dialects: self.dialects | other.dialects,
123 swear: self.swear.or(other.swear),
124 determiner: merge!(self.determiner, other.determiner),
125 preposition: self.preposition || other.preposition,
126 common: self.common || other.common,
127 derived_from: self.derived_from.or(other.derived_from),
128 pos_tag: self.pos_tag.or(other.pos_tag),
129 np_member: self.np_member.or(other.np_member),
130 }
131 }
132
133 pub fn enforce_pos_exclusivity(&mut self, pos: &UPOS) {
141 use UPOS::*;
142 match pos {
143 NOUN => {
144 if let Some(noun) = self.noun {
145 self.noun = Some(NounData {
146 is_proper: Some(false),
147 ..noun
148 })
149 } else {
150 self.noun = Some(NounData {
151 is_proper: Some(false),
152 is_singular: None,
153 is_plural: None,
154 is_countable: None,
155 is_mass: None,
156 is_possessive: None,
157 })
158 }
159
160 self.pronoun = None;
161 self.verb = None;
162 self.adjective = None;
163 self.adverb = None;
164 self.conjunction = None;
165 self.determiner = None;
166 self.preposition = false;
167 }
168 PROPN => {
169 if let Some(noun) = self.noun {
170 self.noun = Some(NounData {
171 is_proper: Some(true),
172 ..noun
173 })
174 } else {
175 self.noun = Some(NounData {
176 is_proper: Some(true),
177 is_singular: None,
178 is_plural: None,
179 is_countable: None,
180 is_mass: None,
181 is_possessive: None,
182 })
183 }
184
185 self.pronoun = None;
186 self.verb = None;
187 self.adjective = None;
188 self.adverb = None;
189 self.conjunction = None;
190 self.determiner = None;
191 self.preposition = false;
192 }
193 PRON => {
194 if self.pronoun.is_none() {
195 self.pronoun = Some(PronounData::default())
196 }
197
198 self.noun = None;
199 self.verb = None;
200 self.adjective = None;
201 self.adverb = None;
202 self.conjunction = None;
203 self.determiner = None;
204 self.preposition = false;
205 }
206 VERB => {
207 if let Some(verb) = self.verb {
208 self.verb = Some(VerbData {
209 is_auxiliary: Some(false),
210 ..verb
211 })
212 } else {
213 self.verb = Some(VerbData {
214 is_auxiliary: Some(false),
215 ..Default::default()
216 })
217 }
218
219 self.noun = None;
220 self.pronoun = None;
221 self.adjective = None;
222 self.adverb = None;
223 self.conjunction = None;
224 self.determiner = None;
225 self.preposition = false;
226 }
227 AUX => {
228 if let Some(verb) = self.verb {
229 self.verb = Some(VerbData {
230 is_auxiliary: Some(true),
231 ..verb
232 })
233 } else {
234 self.verb = Some(VerbData {
235 is_auxiliary: Some(true),
236 ..Default::default()
237 })
238 }
239
240 self.noun = None;
241 self.pronoun = None;
242 self.adjective = None;
243 self.adverb = None;
244 self.conjunction = None;
245 self.determiner = None;
246 self.preposition = false;
247 }
248 ADJ => {
249 if self.adjective.is_none() {
250 self.adjective = Some(AdjectiveData::default())
251 }
252
253 self.noun = None;
254 self.pronoun = None;
255 self.verb = None;
256 self.adverb = None;
257 self.conjunction = None;
258 self.determiner = None;
259 self.preposition = false;
260 }
261 ADV => {
262 if self.adverb.is_none() {
263 self.adverb = Some(AdverbData::default())
264 }
265
266 self.noun = None;
267 self.pronoun = None;
268 self.verb = None;
269 self.adjective = None;
270 self.conjunction = None;
271 self.determiner = None;
272 self.preposition = false;
273 }
274 ADP => {
275 self.noun = None;
276 self.pronoun = None;
277 self.verb = None;
278 self.adjective = None;
279 self.adverb = None;
280 self.conjunction = None;
281 self.determiner = None;
282 self.preposition = true;
283 }
284 DET => {
285 self.noun = None;
286 self.pronoun = None;
287 self.verb = None;
288 self.adjective = None;
289 self.adverb = None;
290 self.conjunction = None;
291 self.preposition = false;
292 self.determiner = Some(DeterminerData::default());
293 }
294 CCONJ | SCONJ => {
295 if self.conjunction.is_none() {
296 self.conjunction = Some(ConjunctionData::default())
297 }
298
299 self.noun = None;
300 self.pronoun = None;
301 self.verb = None;
302 self.adjective = None;
303 self.adverb = None;
304 self.determiner = None;
305 self.preposition = false;
306 }
307 _ => {}
308 }
309 }
310
311 generate_metadata_queries!(
312 noun has proper, plural, mass, possessive.
314 pronoun has personal, singular, plural, possessive, reflexive, subject, object.
315 determiner has demonstrative, possessive.
316 verb has linking, auxiliary.
317 conjunction has.
318 adjective has.
319 adverb has
320 );
321
322 pub fn is_first_person_plural_pronoun(&self) -> bool {
327 matches!(
328 self.pronoun,
329 Some(PronounData {
330 person: Some(Person::First),
331 is_plural: Some(true),
332 ..
333 })
334 )
335 }
336
337 pub fn is_first_person_singular_pronoun(&self) -> bool {
338 matches!(
339 self.pronoun,
340 Some(PronounData {
341 person: Some(Person::First),
342 is_singular: Some(true),
343 ..
344 })
345 )
346 }
347
348 pub fn is_third_person_plural_pronoun(&self) -> bool {
349 matches!(
350 self.pronoun,
351 Some(PronounData {
352 person: Some(Person::Third),
353 is_plural: Some(true),
354 ..
355 })
356 )
357 }
358
359 pub fn is_third_person_singular_pronoun(&self) -> bool {
360 matches!(
361 self.pronoun,
362 Some(PronounData {
363 person: Some(Person::Third),
364 is_singular: Some(true),
365 ..
366 })
367 )
368 }
369
370 pub fn is_third_person_pronoun(&self) -> bool {
371 matches!(
372 self.pronoun,
373 Some(PronounData {
374 person: Some(Person::Third),
375 ..
376 })
377 )
378 }
379
380 pub fn is_second_person_pronoun(&self) -> bool {
381 matches!(
382 self.pronoun,
383 Some(PronounData {
384 person: Some(Person::Second),
385 ..
386 })
387 )
388 }
389
390 pub fn is_verb_lemma(&self) -> bool {
391 matches!(
392 self.verb,
393 Some(VerbData {
394 verb_form: Some(VerbForm::LemmaForm),
395 ..
396 })
397 )
398 }
399
400 pub fn is_verb_past_form(&self) -> bool {
401 matches!(
402 self.verb,
403 Some(VerbData {
404 verb_form: Some(VerbForm::PastForm),
405 ..
406 })
407 )
408 }
409
410 pub fn is_verb_progressive_form(&self) -> bool {
411 matches!(
412 self.verb,
413 Some(VerbData {
414 verb_form: Some(VerbForm::ProgressiveForm),
415 ..
416 })
417 )
418 }
419
420 pub fn is_verb_third_person_singular_present_form(&self) -> bool {
421 matches!(
422 self.verb,
423 Some(VerbData {
424 verb_form: Some(VerbForm::ThirdPersonSingularPresentForm),
425 ..
426 })
427 )
428 }
429
430 pub fn is_singular_noun(&self) -> bool {
434 if let Some(noun) = self.noun {
435 matches!(
436 (noun.is_singular, noun.is_plural),
437 (Some(true), _) | (None | Some(false), None | Some(false))
438 )
439 } else {
440 false
441 }
442 }
443 pub fn is_non_singular_noun(&self) -> bool {
444 if let Some(noun) = self.noun {
445 !matches!(
446 (noun.is_singular, noun.is_plural),
447 (Some(true), _) | (None | Some(false), None | Some(false))
448 )
449 } else {
450 false
451 }
452 }
453
454 pub fn is_countable_noun(&self) -> bool {
456 if let Some(noun) = self.noun {
457 matches!(
458 (noun.is_countable, noun.is_mass),
459 (Some(true), _) | (None | Some(false), None | Some(false))
460 )
461 } else {
462 false
463 }
464 }
465 pub fn is_non_countable_noun(&self) -> bool {
466 if let Some(noun) = self.noun {
467 !matches!(
468 (noun.is_countable, noun.is_mass),
469 (Some(true), _) | (None | Some(false), None | Some(false))
470 )
471 } else {
472 false
473 }
474 }
475
476 pub fn is_nominal(&self) -> bool {
480 self.is_noun() || self.is_pronoun()
481 }
482
483 pub fn is_singular_nominal(&self) -> bool {
485 self.is_singular_noun() || self.is_singular_pronoun()
486 }
487
488 pub fn is_plural_nominal(&self) -> bool {
490 self.is_plural_noun() || self.is_plural_pronoun()
491 }
492
493 pub fn is_possessive_nominal(&self) -> bool {
495 self.is_possessive_noun() || self.is_possessive_pronoun()
496 }
497
498 pub fn is_non_singular_nominal(&self) -> bool {
500 self.is_non_singular_noun() || self.is_non_singular_pronoun()
501 }
502
503 pub fn is_non_plural_nominal(&self) -> bool {
505 self.is_non_plural_noun() || self.is_non_plural_pronoun()
506 }
507
508 pub fn is_non_possessive_nominal(&self) -> bool {
510 self.is_non_possessive_noun() || self.is_non_possessive_pronoun()
511 }
512
513 pub fn is_swear(&self) -> bool {
515 matches!(self.swear, Some(true))
516 }
517
518 pub fn append(&mut self, other: &Self) -> &mut Self {
520 *self = self.or(other);
521 self
522 }
523}
524
525#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Is, Hash)]
541pub enum VerbForm {
542 LemmaForm,
543 PastForm,
544 ProgressiveForm,
545 ThirdPersonSingularPresentForm,
546}
547
548#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash, Default)]
549pub struct VerbData {
550 pub is_linking: Option<bool>,
551 pub is_auxiliary: Option<bool>,
552 pub verb_form: Option<VerbForm>,
553}
554
555impl VerbData {
556 pub fn or(&self, other: &Self) -> Self {
558 Self {
559 is_linking: self.is_linking.or(other.is_linking),
560 is_auxiliary: self.is_auxiliary.or(other.is_auxiliary),
561 verb_form: self.verb_form.or(other.verb_form),
562 }
563 }
564}
565
566#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash, Default)]
570pub struct NounData {
571 pub is_proper: Option<bool>,
572 pub is_singular: Option<bool>,
573 pub is_plural: Option<bool>,
574 pub is_countable: Option<bool>,
575 pub is_mass: Option<bool>,
576 pub is_possessive: Option<bool>,
577}
578
579impl NounData {
580 pub fn or(&self, other: &Self) -> Self {
582 Self {
583 is_proper: self.is_proper.or(other.is_proper),
584 is_singular: self.is_singular.or(other.is_singular),
585 is_plural: self.is_plural.or(other.is_plural),
586 is_countable: self.is_countable.or(other.is_countable),
587 is_mass: self.is_mass.or(other.is_mass),
588 is_possessive: self.is_possessive.or(other.is_possessive),
589 }
590 }
591}
592
593#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Is, Hash)]
595pub enum Person {
596 First,
597 Second,
598 Third,
599}
600
601#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash, Default)]
603pub struct PronounData {
604 pub is_personal: Option<bool>,
605 pub is_singular: Option<bool>,
606 pub is_plural: Option<bool>,
607 pub is_possessive: Option<bool>,
608 pub is_reflexive: Option<bool>,
609 pub person: Option<Person>,
610 pub is_subject: Option<bool>,
611 pub is_object: Option<bool>,
612}
613
614impl PronounData {
615 pub fn or(&self, other: &Self) -> Self {
617 Self {
618 is_personal: self.is_personal.or(other.is_personal),
619 is_singular: self.is_singular.or(other.is_singular),
620 is_plural: self.is_plural.or(other.is_plural),
621 is_possessive: self.is_possessive.or(other.is_possessive),
622 is_reflexive: self.is_reflexive.or(other.is_reflexive),
623 person: self.person.or(other.person),
624 is_subject: self.is_subject.or(other.is_subject),
625 is_object: self.is_object.or(other.is_object),
626 }
627 }
628}
629
630#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash, Default)]
632pub struct DeterminerData {
633 pub is_demonstrative: Option<bool>,
634 pub is_possessive: Option<bool>,
635}
636
637impl DeterminerData {
638 pub fn or(&self, other: &Self) -> Self {
640 Self {
641 is_demonstrative: self.is_demonstrative.or(other.is_demonstrative),
642 is_possessive: self.is_possessive.or(other.is_possessive),
643 }
644 }
645}
646
647#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Is, Hash)]
651pub enum Degree {
652 Positive,
653 Comparative,
654 Superlative,
655}
656
657#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash, Default)]
661pub struct AdjectiveData {
662 pub degree: Option<Degree>,
663}
664
665impl AdjectiveData {
666 pub fn or(&self, other: &Self) -> Self {
668 Self {
669 degree: self.degree.or(other.degree),
670 }
671 }
672}
673
674#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash, Default)]
678pub struct AdverbData {}
679
680impl AdverbData {
681 pub fn or(&self, _other: &Self) -> Self {
683 Self {}
684 }
685}
686
687#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash, Default)]
688pub struct ConjunctionData {}
689
690impl ConjunctionData {
691 pub fn or(&self, _other: &Self) -> Self {
693 Self {}
694 }
695}
696
697#[derive(
703 Debug,
704 Clone,
705 Copy,
706 Serialize,
707 Deserialize,
708 PartialEq,
709 PartialOrd,
710 Eq,
711 Hash,
712 EnumCount,
713 EnumString,
714 Display,
715 VariantArray,
716)]
717pub enum Dialect {
718 American = 1 << 0,
719 Canadian = 1 << 1,
720 Australian = 1 << 2,
721 British = 1 << 3,
722}
723impl Dialect {
724 #[must_use]
727 pub fn try_guess_from_document(document: &Document) -> Option<Self> {
728 Self::try_from(DialectFlags::get_most_used_dialects_from_document(document)).ok()
729 }
730
731 #[must_use]
748 pub fn try_from_abbr(abbr: &str) -> Option<Self> {
749 match abbr {
750 "US" => Some(Self::American),
751 "CA" => Some(Self::Canadian),
752 "AU" => Some(Self::Australian),
753 "GB" => Some(Self::British),
754 _ => None,
755 }
756 }
757}
758impl TryFrom<DialectFlags> for Dialect {
759 type Error = ();
760
761 fn try_from(dialect_flags: DialectFlags) -> Result<Self, Self::Error> {
768 if dialect_flags.bits().count_ones() == 1 {
770 match dialect_flags {
771 df if df.is_dialect_enabled_strict(Dialect::American) => Ok(Dialect::American),
772 df if df.is_dialect_enabled_strict(Dialect::Canadian) => Ok(Dialect::Canadian),
773 df if df.is_dialect_enabled_strict(Dialect::Australian) => Ok(Dialect::Australian),
774 df if df.is_dialect_enabled_strict(Dialect::British) => Ok(Dialect::British),
775 _ => Err(()),
776 }
777 } else {
778 Err(())
780 }
781 }
782}
783
784type DialectFlagsUnderlyingType = u8;
788
789bitflags::bitflags! {
790 #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd, Eq, Hash)]
794 #[serde(transparent)]
795 pub struct DialectFlags: DialectFlagsUnderlyingType {
796 const AMERICAN = Dialect::American as DialectFlagsUnderlyingType;
797 const CANADIAN = Dialect::Canadian as DialectFlagsUnderlyingType;
798 const AUSTRALIAN = Dialect::Australian as DialectFlagsUnderlyingType;
799 const BRITISH = Dialect::British as DialectFlagsUnderlyingType;
800 }
801}
802impl DialectFlags {
803 #[must_use]
806 pub fn is_dialect_enabled(self, dialect: Dialect) -> bool {
807 self.is_empty() || self.intersects(Self::from_dialect(dialect))
808 }
809
810 #[must_use]
815 pub fn is_dialect_enabled_strict(self, dialect: Dialect) -> bool {
816 self.intersects(Self::from_dialect(dialect))
817 }
818
819 #[must_use]
827 pub fn from_dialect(dialect: Dialect) -> Self {
828 let Some(out) = Self::from_bits(dialect as DialectFlagsUnderlyingType) else {
829 panic!("The '{dialect}' dialect isn't defined in DialectFlags!");
830 };
831 out
832 }
833
834 #[must_use]
840 pub fn get_most_used_dialects_from_document(document: &Document) -> Self {
841 let mut dialect_counters: [(Dialect, usize); Dialect::COUNT] = Dialect::VARIANTS
843 .iter()
844 .map(|d| (*d, 0))
845 .collect_array()
846 .unwrap();
847
848 document.iter_words().for_each(|w| {
850 if let TokenKind::Word(Some(word_metadata)) = &w.kind {
851 dialect_counters.iter_mut().for_each(|(dialect, count)| {
854 if word_metadata.dialects.is_dialect_enabled(*dialect) {
855 *count += 1;
856 }
857 });
858 }
859 });
860
861 let max_counter = dialect_counters
863 .iter()
864 .map(|(_, count)| count)
865 .max()
866 .unwrap();
867 dialect_counters
869 .into_iter()
870 .filter(|(_, count)| count == max_counter)
871 .fold(DialectFlags::empty(), |acc, dialect| {
872 acc | Self::from_dialect(dialect.0)
874 })
875 }
876}
877impl Default for DialectFlags {
878 fn default() -> Self {
881 Self::empty()
882 }
883}
884
885#[cfg(test)]
886mod tests {
887 use crate::WordMetadata;
888 use crate::spell::{Dictionary, FstDictionary};
889
890 fn md(word: &str) -> WordMetadata {
892 FstDictionary::curated()
893 .get_word_metadata_str(word)
894 .unwrap_or_else(|| panic!("Word '{word}' not found in dictionary"))
895 .clone()
896 }
897
898 mod dialect {
899 use super::super::{Dialect, DialectFlags};
900 use crate::Document;
901
902 #[test]
903 fn guess_british_dialect() {
904 let document = Document::new_plain_english_curated("Aluminium was used.");
905 let df = DialectFlags::get_most_used_dialects_from_document(&document);
906 assert!(
907 df.is_dialect_enabled_strict(Dialect::British)
908 && !df.is_dialect_enabled_strict(Dialect::American)
909 );
910 }
911
912 #[test]
913 fn guess_american_dialect() {
914 let document = Document::new_plain_english_curated("Aluminum was used.");
915 let df = DialectFlags::get_most_used_dialects_from_document(&document);
916 assert!(
917 df.is_dialect_enabled_strict(Dialect::American)
918 && !df.is_dialect_enabled_strict(Dialect::British)
919 );
920 }
921 }
922
923 mod noun {
924 use crate::word_metadata::tests::md;
925
926 #[test]
927 fn puppy_is_noun() {
928 assert!(md("puppy").is_noun());
929 }
930
931 #[test]
932 fn prepare_is_not_noun() {
933 assert!(!md("prepare").is_noun());
934 }
935
936 #[test]
937 fn paris_is_proper_noun() {
938 assert!(md("Paris").is_proper_noun());
939 }
940
941 #[test]
942 fn permit_is_non_proper_noun() {
943 assert!(md("lapdog").is_non_proper_noun());
944 }
945
946 #[test]
947 fn hound_is_singular_noun() {
948 assert!(md("hound").is_singular_noun());
949 }
950
951 #[test]
952 fn pooches_is_non_singular_noun() {
953 assert!(md("pooches").is_non_singular_noun());
954 }
955
956 #[test]
960 fn loyal_doesnt_pass_is_non_singular_noun() {
961 assert!(!md("loyal").is_non_singular_noun());
962 }
963
964 #[test]
965 fn hounds_is_plural_noun() {
966 assert!(md("hounds").is_plural_noun());
967 }
968
969 #[test]
970 fn pooch_is_non_plural_noun() {
971 assert!(md("pooch").is_non_plural_noun());
972 }
973
974 #[test]
975 fn fish_is_singular_noun() {
976 assert!(md("fish").is_singular_noun());
977 }
978
979 #[test]
980 fn fish_is_plural_noun() {
981 assert!(md("fish").is_plural_noun());
982 }
983
984 #[test]
985 fn fishes_is_plural_noun() {
986 assert!(md("fishes").is_plural_noun());
987 }
988
989 #[test]
990 fn sheep_is_singular_noun() {
991 assert!(md("sheep").is_singular_noun());
992 }
993
994 #[test]
995 fn sheep_is_plural_noun() {
996 assert!(md("sheep").is_plural_noun());
997 }
998
999 #[test]
1000 #[should_panic]
1001 fn sheeps_is_not_word() {
1002 md("sheeps");
1003 }
1004
1005 #[test]
1006 fn bicep_is_singular_noun() {
1007 assert!(md("bicep").is_singular_noun());
1008 }
1009
1010 #[test]
1011 fn biceps_is_singular_noun() {
1012 assert!(md("biceps").is_singular_noun());
1013 }
1014
1015 #[test]
1016 fn biceps_is_plural_noun() {
1017 assert!(md("biceps").is_plural_noun());
1018 }
1019
1020 #[test]
1021 fn aircraft_is_singular_noun() {
1022 assert!(md("aircraft").is_singular_noun());
1023 }
1024
1025 #[test]
1026 fn aircraft_is_plural_noun() {
1027 assert!(md("aircraft").is_plural_noun());
1028 }
1029
1030 #[test]
1031 #[should_panic]
1032 fn aircrafts_is_not_word() {
1033 md("aircrafts");
1034 }
1035
1036 #[test]
1037 fn dog_apostrophe_s_is_possessive_noun() {
1038 assert!(md("dog's").is_possessive_noun());
1039 }
1040
1041 #[test]
1042 fn dogs_is_non_possessive_noun() {
1043 assert!(md("dogs").is_non_possessive_noun());
1044 }
1045
1046 #[test]
1049 fn dog_is_countable() {
1050 assert!(md("dog").is_countable_noun());
1051 }
1052 #[test]
1053 fn dog_is_non_mass_noun() {
1054 assert!(md("dog").is_non_mass_noun());
1055 }
1056
1057 #[test]
1058 fn furniture_is_mass_noun() {
1059 assert!(md("furniture").is_mass_noun());
1060 }
1061 #[test]
1062 fn furniture_is_not_countable_noun() {
1063 assert!(md("furniture").is_non_countable_noun());
1064 }
1065
1066 #[test]
1067 fn beer_is_countable_noun() {
1068 assert!(md("beer").is_countable_noun());
1069 }
1070 #[test]
1071 fn beer_is_mass_noun() {
1072 assert!(md("beer").is_mass_noun());
1073 }
1074 }
1075
1076 mod pronoun {
1077 use crate::word_metadata::tests::md;
1078
1079 mod i_me_myself {
1080 use crate::word_metadata::tests::md;
1081
1082 #[test]
1083 fn i_is_pronoun() {
1084 assert!(md("I").is_pronoun());
1085 }
1086 #[test]
1087 fn i_is_personal_pronoun() {
1088 assert!(md("I").is_personal_pronoun());
1089 }
1090 #[test]
1091 fn i_is_singular_pronoun() {
1092 assert!(md("I").is_singular_pronoun());
1093 }
1094 #[test]
1095 fn i_is_subject_pronoun() {
1096 assert!(md("I").is_subject_pronoun());
1097 }
1098
1099 #[test]
1100 fn me_is_pronoun() {
1101 assert!(md("me").is_pronoun());
1102 }
1103 #[test]
1104 fn me_is_personal_pronoun() {
1105 assert!(md("me").is_personal_pronoun());
1106 }
1107 #[test]
1108 fn me_is_singular_pronoun() {
1109 assert!(md("me").is_singular_pronoun());
1110 }
1111 #[test]
1112 fn me_is_object_pronoun() {
1113 assert!(md("me").is_object_pronoun());
1114 }
1115
1116 #[test]
1117 fn myself_is_pronoun() {
1118 assert!(md("myself").is_pronoun());
1119 }
1120 #[test]
1121 fn myself_is_personal_pronoun() {
1122 assert!(md("myself").is_personal_pronoun());
1123 }
1124 #[test]
1125 fn myself_is_singular_pronoun() {
1126 assert!(md("myself").is_singular_pronoun());
1127 }
1128 #[test]
1129 fn myself_is_reflexive_pronoun() {
1130 assert!(md("myself").is_reflexive_pronoun());
1131 }
1132 }
1133
1134 mod we_us_ourselves {
1135 use crate::word_metadata::tests::md;
1136
1137 #[test]
1138 fn we_is_pronoun() {
1139 assert!(md("we").is_pronoun());
1140 }
1141 #[test]
1142 fn we_is_personal_pronoun() {
1143 assert!(md("we").is_personal_pronoun());
1144 }
1145 #[test]
1146 fn we_is_plural_pronoun() {
1147 assert!(md("we").is_plural_pronoun());
1148 }
1149 #[test]
1150 fn we_is_subject_pronoun() {
1151 assert!(md("we").is_subject_pronoun());
1152 }
1153
1154 #[test]
1155 fn us_is_pronoun() {
1156 assert!(md("us").is_pronoun());
1157 }
1158 #[test]
1159 fn us_is_personal_pronoun() {
1160 assert!(md("us").is_personal_pronoun());
1161 }
1162 #[test]
1163 fn us_is_plural_pronoun() {
1164 assert!(md("us").is_plural_pronoun());
1165 }
1166 #[test]
1167 fn us_is_object_pronoun() {
1168 assert!(md("us").is_object_pronoun());
1169 }
1170
1171 #[test]
1172 fn ourselves_is_pronoun() {
1173 assert!(md("ourselves").is_pronoun());
1174 }
1175 #[test]
1176 fn ourselves_is_personal_pronoun() {
1177 assert!(md("ourselves").is_personal_pronoun());
1178 }
1179 #[test]
1180 fn ourselves_is_plural_pronoun() {
1181 assert!(md("ourselves").is_plural_pronoun());
1182 }
1183 #[test]
1184 fn ourselves_is_reflexive_pronoun() {
1185 assert!(md("ourselves").is_reflexive_pronoun());
1186 }
1187 }
1188
1189 mod you_yourself {
1190 use crate::word_metadata::tests::md;
1191
1192 #[test]
1193 fn you_is_pronoun() {
1194 assert!(md("you").is_pronoun());
1195 }
1196 #[test]
1197 fn you_is_personal_pronoun() {
1198 assert!(md("you").is_personal_pronoun());
1199 }
1200 #[test]
1201 fn you_is_singular_pronoun() {
1202 assert!(md("you").is_singular_pronoun());
1203 }
1204 #[test]
1205 fn you_is_plural_pronoun() {
1206 assert!(md("you").is_plural_pronoun());
1207 }
1208 #[test]
1209 fn you_is_subject_pronoun() {
1210 assert!(md("you").is_subject_pronoun());
1211 }
1212 #[test]
1213 fn you_is_object_pronoun() {
1214 assert!(md("you").is_object_pronoun());
1215 }
1216 #[test]
1217 fn yourself_is_pronoun() {
1218 assert!(md("yourself").is_pronoun());
1219 }
1220 #[test]
1221 fn yourself_is_personal_pronoun() {
1222 assert!(md("yourself").is_personal_pronoun());
1223 }
1224 #[test]
1225 fn yourself_is_singular_pronoun() {
1226 assert!(md("yourself").is_singular_pronoun());
1227 }
1228 #[test]
1229 fn yourself_is_reflexive_pronoun() {
1230 assert!(md("yourself").is_reflexive_pronoun());
1231 }
1232 }
1233
1234 mod he_him_himself {
1235 use crate::word_metadata::tests::md;
1236
1237 #[test]
1238 fn he_is_pronoun() {
1239 assert!(md("he").is_pronoun());
1240 }
1241 #[test]
1242 fn he_is_personal_pronoun() {
1243 assert!(md("he").is_personal_pronoun());
1244 }
1245 #[test]
1246 fn he_is_singular_pronoun() {
1247 assert!(md("he").is_singular_pronoun());
1248 }
1249 #[test]
1250 fn he_is_subject_pronoun() {
1251 assert!(md("he").is_subject_pronoun());
1252 }
1253
1254 #[test]
1255 fn him_is_pronoun() {
1256 assert!(md("him").is_pronoun());
1257 }
1258 #[test]
1259 fn him_is_personal_pronoun() {
1260 assert!(md("him").is_personal_pronoun());
1261 }
1262 #[test]
1263 fn him_is_singular_pronoun() {
1264 assert!(md("him").is_singular_pronoun());
1265 }
1266 #[test]
1267 fn him_is_object_pronoun() {
1268 assert!(md("him").is_object_pronoun());
1269 }
1270
1271 #[test]
1272 fn himself_is_pronoun() {
1273 assert!(md("himself").is_pronoun());
1274 }
1275 #[test]
1276 fn himself_is_personal_pronoun() {
1277 assert!(md("himself").is_personal_pronoun());
1278 }
1279 #[test]
1280 fn himself_is_singular_pronoun() {
1281 assert!(md("himself").is_singular_pronoun());
1282 }
1283 #[test]
1284 fn himself_is_reflexive_pronoun() {
1285 assert!(md("himself").is_reflexive_pronoun());
1286 }
1287 }
1288
1289 mod she_her_herself {
1290 use crate::word_metadata::tests::md;
1291
1292 #[test]
1293 fn she_is_pronoun() {
1294 assert!(md("she").is_pronoun());
1295 }
1296 #[test]
1297 fn she_is_personal_pronoun() {
1298 assert!(md("she").is_personal_pronoun());
1299 }
1300 #[test]
1301 fn she_is_singular_pronoun() {
1302 assert!(md("she").is_singular_pronoun());
1303 }
1304 #[test]
1305 fn she_is_subject_pronoun() {
1306 assert!(md("she").is_subject_pronoun());
1307 }
1308
1309 #[test]
1310 fn her_is_pronoun() {
1311 assert!(md("her").is_pronoun());
1312 }
1313 #[test]
1314 fn her_is_personal_pronoun() {
1315 assert!(md("her").is_personal_pronoun());
1316 }
1317 #[test]
1318 fn her_is_singular_pronoun() {
1319 assert!(md("her").is_singular_pronoun());
1320 }
1321 #[test]
1322 fn her_is_object_pronoun() {
1323 assert!(md("her").is_object_pronoun());
1324 }
1325
1326 #[test]
1327 fn herself_is_pronoun() {
1328 assert!(md("herself").is_pronoun());
1329 }
1330 #[test]
1331 fn herself_is_personal_pronoun() {
1332 assert!(md("herself").is_personal_pronoun());
1333 }
1334 #[test]
1335 fn herself_is_singular_pronoun() {
1336 assert!(md("herself").is_singular_pronoun());
1337 }
1338 #[test]
1339 fn herself_is_reflexive_pronoun() {
1340 assert!(md("herself").is_reflexive_pronoun());
1341 }
1342 }
1343
1344 mod it_itself {
1345 use crate::word_metadata::tests::md;
1346
1347 #[test]
1348 fn it_is_pronoun() {
1349 assert!(md("it").is_pronoun());
1350 }
1351 #[test]
1352 fn it_is_personal_pronoun() {
1353 assert!(md("it").is_personal_pronoun());
1354 }
1355 #[test]
1356 fn it_is_singular_pronoun() {
1357 assert!(md("it").is_singular_pronoun());
1358 }
1359 #[test]
1360 fn it_is_subject_pronoun() {
1361 assert!(md("it").is_subject_pronoun());
1362 }
1363 #[test]
1364 fn it_is_object_pronoun() {
1365 assert!(md("it").is_object_pronoun());
1366 }
1367
1368 #[test]
1369 fn itself_is_pronoun() {
1370 assert!(md("itself").is_pronoun());
1371 }
1372 #[test]
1373 fn itself_is_personal_pronoun() {
1374 assert!(md("itself").is_personal_pronoun());
1375 }
1376 #[test]
1377 fn itself_is_singular_pronoun() {
1378 assert!(md("itself").is_singular_pronoun());
1379 }
1380 #[test]
1381 fn itself_is_reflexive_pronoun() {
1382 assert!(md("itself").is_reflexive_pronoun());
1383 }
1384 }
1385
1386 mod they_them_themselves {
1387 use crate::word_metadata::tests::md;
1388
1389 #[test]
1390 fn they_is_pronoun() {
1391 assert!(md("they").is_pronoun());
1392 }
1393 #[test]
1394 fn they_is_personal_pronoun() {
1395 assert!(md("they").is_personal_pronoun());
1396 }
1397 #[test]
1398 fn they_is_plural_pronoun() {
1399 assert!(md("they").is_plural_pronoun());
1400 }
1401 #[test]
1402 fn they_is_subject_pronoun() {
1403 assert!(md("they").is_subject_pronoun());
1404 }
1405
1406 #[test]
1407 fn them_is_pronoun() {
1408 assert!(md("them").is_pronoun());
1409 }
1410 #[test]
1411 fn them_is_personal_pronoun() {
1412 assert!(md("them").is_personal_pronoun());
1413 }
1414 #[test]
1415 fn them_is_plural_pronoun() {
1416 assert!(md("them").is_plural_pronoun());
1417 }
1418 #[test]
1419 fn them_is_object_pronoun() {
1420 assert!(md("them").is_object_pronoun());
1421 }
1422
1423 #[test]
1424 fn themselves_is_pronoun() {
1425 assert!(md("themselves").is_pronoun());
1426 }
1427 #[test]
1428 fn themselves_is_personal_pronoun() {
1429 assert!(md("themselves").is_personal_pronoun());
1430 }
1431 #[test]
1432 fn themselves_is_plural_pronoun() {
1433 assert!(md("themselves").is_plural_pronoun());
1434 }
1435 #[test]
1436 fn themselves_is_reflexive_pronoun() {
1437 assert!(md("themselves").is_reflexive_pronoun());
1438 }
1439 }
1440
1441 #[test]
1443 fn mine_is_pronoun() {
1444 assert!(md("mine").is_pronoun());
1445 }
1446 #[test]
1447 fn ours_is_pronoun() {
1448 assert!(md("ours").is_pronoun());
1449 }
1450 #[test]
1451 fn yours_is_pronoun() {
1452 assert!(md("yours").is_pronoun());
1453 }
1454 #[test]
1455 fn his_is_pronoun() {
1456 assert!(md("his").is_pronoun());
1457 }
1458 #[test]
1459 fn hers_is_pronoun() {
1460 assert!(md("hers").is_pronoun());
1461 }
1462 #[test]
1463 fn its_is_pronoun() {
1464 assert!(md("its").is_pronoun());
1465 }
1466 #[test]
1467 fn theirs_is_pronoun() {
1468 assert!(md("theirs").is_pronoun());
1469 }
1470
1471 #[test]
1473 fn archaic_pronouns() {
1474 assert!(md("thou").is_pronoun());
1475 assert!(md("thee").is_pronoun());
1476 assert!(md("thyself").is_pronoun());
1477 assert!(md("thine").is_pronoun());
1478 }
1479
1480 #[test]
1482 fn generic_pronouns() {
1483 assert!(md("one").is_pronoun());
1484 assert!(md("oneself").is_pronoun());
1485 }
1486
1487 #[test]
1489 fn relative_and_interrogative_pronouns() {
1490 assert!(md("who").is_pronoun());
1491 assert!(md("whom").is_pronoun());
1492 assert!(md("whose").is_pronoun());
1493 assert!(md("which").is_pronoun());
1494 assert!(md("what").is_pronoun());
1495 }
1496
1497 #[test]
1499 #[ignore = "not in dictionary"]
1500 fn nonstandard_pronouns() {
1501 assert!(md("themself").pronoun.is_some());
1502 assert!(md("y'all'").pronoun.is_some());
1503 }
1504 }
1505
1506 #[test]
1507 fn the_is_determiner() {
1508 assert!(md("the").is_determiner());
1509 }
1510 #[test]
1511 fn this_is_demonstrative_determiner() {
1512 assert!(md("this").is_demonstrative_determiner());
1513 }
1514 #[test]
1515 fn your_is_possessive_determiner() {
1516 assert!(md("your").is_possessive_determiner());
1517 }
1518
1519 #[test]
1520 fn equipment_is_mass_noun() {
1521 assert!(md("equipment").is_mass_noun());
1522 }
1523
1524 #[test]
1525 fn equipment_is_non_countable_noun() {
1526 assert!(md("equipment").is_non_countable_noun());
1527 }
1528
1529 #[test]
1530 fn equipment_isnt_countable_noun() {
1531 assert!(!md("equipment").is_countable_noun());
1532 }
1533}