88 lines
2.9 KiB
Rust
88 lines
2.9 KiB
Rust
use std::fmt;
|
|
|
|
use itertools::Itertools;
|
|
use orchid_base::error::OrcRes;
|
|
use orchid_base::interner::{Interner, Tok};
|
|
use orchid_base::location::Pos;
|
|
use orchid_base::name::Sym;
|
|
|
|
use super::any_match::any_match;
|
|
use super::build::{mk_any, mk_vec};
|
|
use super::shared::{AnyMatcher, VecMatcher};
|
|
use super::state::{MatchState, StateEntry};
|
|
use super::vec_attrs::vec_attrs;
|
|
use super::vec_match::vec_match;
|
|
use crate::macros::mactree::{Ph, PhKind};
|
|
use crate::macros::{MacTok, MacTree};
|
|
|
|
pub struct NamedMatcher {
|
|
inner: AnyMatcher,
|
|
head: Sym,
|
|
after_tok: IStr,
|
|
}
|
|
impl NamedMatcher {
|
|
pub async fn new(pattern: &[MacTree], i: &Interner) -> OrcRes<Self> {
|
|
let head = match pattern.first().map(|tree| tree.tok()) {
|
|
Some(MacTok::Name(name)) => name.clone(),
|
|
_ => panic!("Named matchers must begin with a name"),
|
|
};
|
|
let after_tok = i.i("::after").await;
|
|
let inner = match pattern.last().and_then(vec_attrs).is_some() {
|
|
true => mk_any(pattern, i).await?,
|
|
false => {
|
|
let kind = PhKind::Vector { priority: 0, at_least_one: false };
|
|
let suffix = [MacTok::Ph(Ph { name: after_tok.clone(), kind }).at(Pos::None)];
|
|
mk_any(&pattern.iter().cloned().chain(suffix).collect_vec(), i).await?
|
|
},
|
|
};
|
|
Ok(Self { after_tok, inner, head })
|
|
}
|
|
pub fn head(&self) -> Sym { self.head.clone() }
|
|
/// Also returns the tail, if any, which should be matched further
|
|
/// Note that due to how priod works below, the main usable information from
|
|
/// the tail is its length
|
|
pub fn apply<'a>(
|
|
&self,
|
|
seq: &'a [MacTree],
|
|
save_loc: impl Fn(Sym) -> bool,
|
|
) -> Option<(MatchState<'a>, &'a [MacTree])> {
|
|
let mut state = any_match(&self.inner, seq, &save_loc)?;
|
|
match state.remove(self.after_tok.clone()) {
|
|
Some(StateEntry::Scalar(_)) => panic!("{} can never be a scalar entry!", self.after_tok),
|
|
Some(StateEntry::Vec(v)) => Some((state, v)),
|
|
None => Some((state, &[][..])),
|
|
}
|
|
}
|
|
}
|
|
impl fmt::Display for NamedMatcher {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.inner.fmt(f) }
|
|
}
|
|
impl fmt::Debug for NamedMatcher {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "NamedMatcher({self})") }
|
|
}
|
|
|
|
pub struct PriodMatcher(VecMatcher);
|
|
impl PriodMatcher {
|
|
pub async fn new(pattern: &[MacTree], i: &Interner) -> OrcRes<Self> {
|
|
assert!(
|
|
pattern.first().and_then(vec_attrs).is_some() && pattern.last().and_then(vec_attrs).is_some(),
|
|
"Prioritized matchers must start and end with a vectorial",
|
|
);
|
|
Ok(Self(mk_vec(pattern, i).await?))
|
|
}
|
|
/// tokens before the offset always match the prefix
|
|
pub fn apply<'a>(
|
|
&self,
|
|
seq: &'a [MacTree],
|
|
save_loc: impl Fn(Sym) -> bool,
|
|
) -> Option<MatchState<'a>> {
|
|
vec_match(&self.0, seq, &save_loc)
|
|
}
|
|
}
|
|
impl fmt::Display for PriodMatcher {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
|
|
}
|
|
impl fmt::Debug for PriodMatcher {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "PriodMatcher({self})") }
|
|
}
|