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