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 62 63 64 65 66 67 68 69
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 {
pub(crate) 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()
}
pub(crate) fn unshift(&mut self) -> Option<Item> {
if self.parts.is_empty() {
None
} else {
Some(self.parts.remove(0))
}
}
}