harper_core/patterns/
nominal_phrase.rs

1use crate::Token;
2
3use super::Pattern;
4
5#[derive(Default)]
6pub struct NominalPhrase;
7
8impl Pattern for NominalPhrase {
9    fn matches(&self, tokens: &[Token], _source: &[char]) -> Option<usize> {
10        let mut cursor = 0;
11
12        loop {
13            let tok = tokens.get(cursor)?;
14
15            if tok.kind.is_adjective() || tok.kind.is_determiner() {
16                let next = tokens.get(cursor + 1)?;
17
18                if !next.kind.is_whitespace() {
19                    return None;
20                }
21
22                cursor += 2;
23                continue;
24            }
25
26            if tok.kind.is_nominal() {
27                return Some(cursor + 1);
28            }
29
30            return None;
31        }
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use super::super::DocPattern;
38    use super::NominalPhrase;
39    use crate::{Document, Span, patterns::Pattern};
40
41    #[test]
42    fn simple_apple() {
43        let doc = Document::new_markdown_default_curated("A red apple");
44        let matches = NominalPhrase.find_all_matches_in_doc(&doc);
45
46        assert_eq!(matches, vec![Span::new(0, 5)])
47    }
48
49    #[test]
50    fn complex_apple() {
51        let doc = Document::new_markdown_default_curated("A red apple with a long stem");
52        let matches = NominalPhrase.find_all_matches_in_doc(&doc);
53
54        assert_eq!(matches, vec![Span::new(0, 5), Span::new(8, 13)])
55    }
56
57    #[test]
58    fn list_fruit() {
59        let doc = Document::new_markdown_default_curated("An apple, a banana and a pear");
60        let matches = NominalPhrase.find_all_matches_in_doc(&doc);
61
62        assert_eq!(
63            matches,
64            vec![Span::new(0, 3), Span::new(5, 8), Span::new(11, 14)]
65        )
66    }
67
68    #[test]
69    fn simplest_banana() {
70        let doc = Document::new_markdown_default_curated("a banana");
71        assert!(
72            NominalPhrase
73                .matches(doc.get_tokens(), doc.get_source())
74                .is_some()
75        );
76    }
77
78    #[test]
79    fn food() {
80        let doc = Document::new_markdown_default_curated(
81            "My favorite foods are pizza, sushi, tacos and burgers.",
82        );
83        let matches = NominalPhrase.find_all_matches_in_doc(&doc);
84
85        dbg!(&matches);
86
87        assert_eq!(
88            matches,
89            vec![
90                Span::new(0, 5),
91                Span::new(8, 9),
92                Span::new(11, 12),
93                Span::new(14, 15),
94                Span::new(18, 19)
95            ]
96        )
97    }
98}