New macro system and stdlib additions

This commit is contained in:
2025-11-21 14:25:03 +01:00
parent b77653f841
commit 603efef28e
230 changed files with 3033 additions and 16640 deletions

View File

@@ -2,9 +2,10 @@ use futures::FutureExt;
use futures::future::join_all;
use itertools::Itertools;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::interner::{Interner, Tok};
use orchid_base::interner::Tok;
use orchid_base::join_ok;
use orchid_base::side::Side;
use orchid_extension::context::i;
use super::shared::{AnyMatcher, ScalMatcher, VecMatcher};
use super::vec_attrs::vec_attrs;
@@ -31,29 +32,29 @@ fn scal_cnt<'a>(iter: impl Iterator<Item = &'a MacTree>) -> usize {
iter.take_while(|expr| vec_attrs(expr).is_none()).count()
}
pub async fn mk_any(pattern: &[MacTree], i: &Interner) -> OrcRes<AnyMatcher> {
pub async fn mk_any(pattern: &[MacTree]) -> OrcRes<AnyMatcher> {
let left_split = scal_cnt(pattern.iter());
if pattern.len() <= left_split {
return Ok(AnyMatcher::Scalar(mk_scalv(pattern, i).await?));
return Ok(AnyMatcher::Scalar(mk_scalv(pattern).await?));
}
let (left, not_left) = pattern.split_at(left_split);
let right_split = not_left.len() - scal_cnt(pattern.iter().rev());
let (mid, right) = not_left.split_at(right_split);
join_ok! {
left = mk_scalv(left, i).await;
mid = mk_vec(mid, i).await;
right = mk_scalv(right, i).await;
left = mk_scalv(left).await;
mid = mk_vec(mid).await;
right = mk_scalv(right).await;
}
Ok(AnyMatcher::Vec { left, mid, right })
}
/// Pattern MUST NOT contain vectorial placeholders
async fn mk_scalv(pattern: &[MacTree], i: &Interner) -> OrcRes<Vec<ScalMatcher>> {
join_all(pattern.iter().map(|pat| mk_scalar(pat, i))).await.into_iter().collect()
async fn mk_scalv(pattern: &[MacTree]) -> OrcRes<Vec<ScalMatcher>> {
join_all(pattern.iter().map(mk_scalar)).await.into_iter().collect()
}
/// Pattern MUST start and end with a vectorial placeholder
pub async fn mk_vec(pattern: &[MacTree], i: &Interner) -> OrcRes<VecMatcher> {
pub async fn mk_vec(pattern: &[MacTree]) -> OrcRes<VecMatcher> {
debug_assert!(!pattern.is_empty(), "pattern cannot be empty");
debug_assert!(pattern.first().map(vec_attrs).is_some(), "pattern must start with a vectorial");
debug_assert!(pattern.last().map(vec_attrs).is_some(), "pattern must end with a vectorial");
@@ -68,8 +69,8 @@ pub async fn mk_vec(pattern: &[MacTree], i: &Interner) -> OrcRes<VecMatcher> {
(&[], &[]) => Ok(VecMatcher::Placeh { key, nonzero }),
(&[], _) => {
join_ok! {
sep = mk_scalv(r_sep, i).await;
right = mk_vec(r_side, i).boxed_local().await;
sep = mk_scalv(r_sep).await;
right = mk_vec(r_side).boxed_local().await;
}
Ok(VecMatcher::Scan {
direction: Side::Left,
@@ -80,8 +81,8 @@ pub async fn mk_vec(pattern: &[MacTree], i: &Interner) -> OrcRes<VecMatcher> {
},
(_, &[]) => {
join_ok! {
left = mk_vec(l_side, i).boxed_local().await;
sep = mk_scalv(l_sep, i).await;
left = mk_vec(l_side).boxed_local().await;
sep = mk_scalv(l_sep).await;
}
Ok(VecMatcher::Scan {
direction: Side::Right,
@@ -95,10 +96,10 @@ pub async fn mk_vec(pattern: &[MacTree], i: &Interner) -> OrcRes<VecMatcher> {
l_side.iter().chain(r_side.iter()).filter_map(vec_attrs).collect::<Vec<_>>();
key_order.sort_by_key(|(_, prio, _)| -(*prio as i64));
join_ok! {
left = mk_vec(l_side, i).boxed_local().await;
left_sep = mk_scalv(l_sep, i).await;
right_sep = mk_scalv(r_sep, i).await;
right = mk_vec(r_side, i).boxed_local().await;
left = mk_vec(l_side).boxed_local().await;
left_sep = mk_scalv(l_sep).await;
right_sep = mk_scalv(r_sep).await;
right = mk_vec(r_side).boxed_local().await;
}
Ok(VecMatcher::Middle {
left: Box::new(left),
@@ -113,7 +114,7 @@ pub async fn mk_vec(pattern: &[MacTree], i: &Interner) -> OrcRes<VecMatcher> {
}
/// Pattern MUST NOT be a vectorial placeholder
async fn mk_scalar(pattern: &MacTree, i: &Interner) -> OrcRes<ScalMatcher> {
async fn mk_scalar(pattern: &MacTree) -> OrcRes<ScalMatcher> {
Ok(match &*pattern.tok {
MacTok::Name(n) => ScalMatcher::Name(n.clone()),
MacTok::Ph(Ph { name, kind }) => match kind {
@@ -122,10 +123,10 @@ async fn mk_scalar(pattern: &MacTree, i: &Interner) -> OrcRes<ScalMatcher> {
},
PhKind::Scalar => ScalMatcher::Placeh { key: name.clone() },
},
MacTok::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(body, i).boxed_local().await?)),
MacTok::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(&body.items).boxed_local().await?)),
MacTok::Lambda(..) =>
return Err(mk_errv(
i.i("Lambda in matcher").await,
i().i("Lambda in matcher").await,
"Lambdas can't be matched for, only generated in templates",
[pattern.pos()],
)),
@@ -136,50 +137,52 @@ async fn mk_scalar(pattern: &MacTree, i: &Interner) -> OrcRes<ScalMatcher> {
#[cfg(test)]
mod test {
use orchid_base::interner::Interner;
use orchid_base::location::SrcRange;
use orchid_base::sym;
use orchid_base::tokens::Paren;
use orchid_extension::context::{i, mock_ctx, with_ctx};
use test_executors::spin_on;
use super::mk_any;
use crate::macros::MacTok;
use crate::macros::mactree::{Ph, PhKind};
use crate::macros::mactree::{MacTreeSeq, Ph, PhKind};
#[test]
fn test_scan() {
spin_on(async {
let i = Interner::new_master();
let ex = |tok: MacTok| async { tok.at(SrcRange::mock(&i).await.pos()) };
spin_on(with_ctx(mock_ctx(), async {
let ex = |tok: MacTok| async { tok.at(SrcRange::mock(&i()).await.pos()) };
let pattern = vec![
ex(MacTok::Ph(Ph {
kind: PhKind::Vector { priority: 0, at_least_one: false },
name: i.i("::prefix").await,
name: i().i("::prefix").await,
}))
.await,
ex(MacTok::Name(sym!(prelude::do; i).await)).await,
ex(MacTok::S(Paren::Round, vec![
ex(MacTok::Ph(Ph {
kind: PhKind::Vector { priority: 0, at_least_one: false },
name: i.i("expr").await,
}))
.await,
ex(MacTok::Name(sym!(prelude::; ; i).await)).await,
ex(MacTok::Ph(Ph {
kind: PhKind::Vector { priority: 1, at_least_one: false },
name: i.i("rest").await,
}))
.await,
]))
ex(MacTok::Name(sym!(prelude::do; i()))).await,
ex(MacTok::S(
Paren::Round,
MacTreeSeq::new([
ex(MacTok::Ph(Ph {
kind: PhKind::Vector { priority: 0, at_least_one: false },
name: i().i("expr").await,
}))
.await,
ex(MacTok::Name(sym!(prelude::; ; i()))).await,
ex(MacTok::Ph(Ph {
kind: PhKind::Vector { priority: 1, at_least_one: false },
name: i().i("rest").await,
}))
.await,
]),
))
.await,
ex(MacTok::Ph(Ph {
kind: PhKind::Vector { priority: 0, at_least_one: false },
name: i.i("::suffix").await,
name: i().i("::suffix").await,
}))
.await,
];
let matcher = mk_any(&pattern, &i).await.expect("This matcher isn't broken");
let matcher = mk_any(&pattern).await.expect("This matcher isn't broken");
println!("{matcher}");
})
}))
}
}