62 lines
2.1 KiB
Rust
62 lines
2.1 KiB
Rust
use std::fmt;
|
|
use std::rc::Rc;
|
|
|
|
use orchid_base::error::OrcRes;
|
|
use orchid_base::name::Sym;
|
|
use orchid_extension::context::i;
|
|
|
|
use super::any_match::any_match;
|
|
use super::build::mk_any;
|
|
use super::shared::AnyMatcher;
|
|
use super::state::{MatchState, StateEntry};
|
|
use super::vec_attrs::vec_attrs;
|
|
use crate::macros::mactree::{MacTreeSeq, Ph, PhKind};
|
|
use crate::macros::{MacTok, MacTree};
|
|
|
|
pub struct Matcher {
|
|
inner: AnyMatcher,
|
|
}
|
|
|
|
impl Matcher {
|
|
pub async fn new(pattern: MacTreeSeq) -> OrcRes<Self> {
|
|
let mut pattern = Rc::unwrap_or_clone(pattern.items);
|
|
let kind = PhKind::Vector { at_least_one: false, priority: 0 };
|
|
let first = pattern.first().expect("Empty pattern is not allowed");
|
|
if vec_attrs(first).is_none() {
|
|
let pos = first.pos();
|
|
pattern.insert(0, MacTok::Ph(Ph { name: i().i("::before").await, kind }).at(pos));
|
|
}
|
|
let last = pattern.last().expect("first returned Some above");
|
|
if vec_attrs(last).is_none() {
|
|
let pos = last.pos();
|
|
pattern.insert(0, MacTok::Ph(Ph { name: i().i("::after").await, kind }).at(pos));
|
|
}
|
|
Ok(Matcher { inner: mk_any(&pattern).await? })
|
|
}
|
|
/// Also returns the head and tail, which should be matched by overarching
|
|
/// matchers attempted later.
|
|
pub async fn apply<'a>(
|
|
&self,
|
|
seq: &'a [MacTree],
|
|
save_loc: &dyn Fn(Sym) -> bool,
|
|
) -> Option<(&'a [MacTree], MatchState<'a>, &'a [MacTree])> {
|
|
let mut result = any_match(&self.inner, seq, &save_loc)?;
|
|
async fn remove_frame<'a>(result: &mut MatchState<'a>, key: &str) -> &'a [MacTree] {
|
|
match result.remove(i().i(key).await) {
|
|
Some(StateEntry::Scalar(_)) => panic!("{key} is defined in the constructor as a Vec"),
|
|
Some(StateEntry::Vec(v)) => v,
|
|
None => &[],
|
|
}
|
|
}
|
|
let before = remove_frame(&mut result, "::before").await;
|
|
let after = remove_frame(&mut result, "::after").await;
|
|
Some((before, result, after))
|
|
}
|
|
}
|
|
impl fmt::Display for Matcher {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) }
|
|
}
|
|
impl fmt::Debug for Matcher {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "NamedMatcher({self})") }
|
|
}
|