1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
mod item;
pub use item::Item;

mod error;
pub use error::PatternError;

/// Pattern that is used for matching.
///
/// Consists of multiple `finder::Item` elements
///
/// For example the following pattern:
///
/// ```text
/// Pattern::new("args -> arglist -> 2 -> default")
/// ```
///
/// can find a node that represents constant `FIND_ME` in the following code:
///
/// ```text
/// def foo(a, b, c = FIND_ME)
/// end
/// ```
///
/// It means:
/// 1. enter `.args` of the `Def` node (`(a, b, c = FIND_ME`))
/// 2. enter its `.argslist` (`a, b, c = FIND_ME`)
/// 3. enter element `[2]` (`c = FIND_ME`)
/// 4. enter `.default` of the `Optarg` node (`FIND_ME`)
#[derive(Debug, PartialEq, Eq)]
pub struct Pattern {
    parts: Vec<Item>,
}

impl Pattern {
    /// Constructs a pattern from a string, returns an error on the first sub-pattern error
    pub fn new(input: &str) -> Result<Self, PatternError> {
        let mut parts: Vec<Item> = vec![];

        for part in input.split(" -> ") {
            let part = Item::new(part)?;
            parts.push(part);
        }

        Ok(Self { parts })
    }

    /// Returns `true` if pattern is empty
    pub fn empty() -> Self {
        Self { parts: vec![] }
    }

    /// Pushes a new `Item` into a pattern
    pub fn push(&mut self, item: Item) {
        self.parts.push(item)
    }

    /// Pops an `Item` from a pattern
    pub fn pop(&mut self) -> Option<Item> {
        self.parts.pop()
    }
}