harper_core/expr/
word_expr_group.rs

1use hashbrown::HashMap;
2
3use super::first_match_of::FirstMatchOf;
4use super::{Expr, SequenceExpr};
5use crate::{CharString, Span, Token};
6
7/// An expression collection to look for expressions that start with a specific
8/// word.
9///
10/// The benefit of using this struct over other methods increases for larger collections.
11#[derive(Default)]
12pub struct WordExprGroup<E>
13where
14    E: Expr,
15{
16    exprs: HashMap<CharString, E>,
17}
18
19impl WordExprGroup<FirstMatchOf> {
20    pub fn add(&mut self, word: &str, expr: impl Expr + 'static) {
21        let chars = word.chars().collect();
22
23        if let Some(group) = self.exprs.get_mut(&chars) {
24            group.add(expr);
25        } else {
26            let mut group = FirstMatchOf::default();
27            group.add(expr);
28            self.exprs.insert(chars, group);
29        }
30    }
31
32    /// Add a pattern that matches just a word on its own, without anything else required to match.
33    pub fn add_word(&mut self, word: &'static str) {
34        self.add(word, SequenceExpr::default().then_exact_word(word));
35    }
36}
37
38impl<E> Expr for WordExprGroup<E>
39where
40    E: Expr,
41{
42    fn run(&self, cursor: usize, tokens: &[Token], source: &[char]) -> Option<Span<Token>> {
43        let first = tokens.get(cursor)?;
44        if !first.kind.is_word() {
45            return None;
46        }
47
48        let word_chars = first.span.get_content(source);
49        let inner_pattern = self.exprs.get(word_chars)?;
50
51        inner_pattern.run(cursor, tokens, source)
52    }
53}