Files
orchid/orchid-std/src/macros/rule/matcher.rs

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})") }
}