Pattern matching works now

This commit is contained in:
2025-11-27 22:47:02 +01:00
parent 4f989271c5
commit ecf151158d
22 changed files with 146 additions and 150 deletions

View File

@@ -48,13 +48,13 @@ pub async fn gen_macro_lib() -> Vec<GenMember> {
mactreev!(macros::common::semi_list ( "...$" head 0 macros::common::; "...$" tail 1)),
[async |[head, tail]| {
call(sym_ref(sym!(std::tuple::cat; i())), [
call(sym_ref(sym!(std::tuple::one; i())), [resolve(head).await]),
call(sym_ref(sym!(std::tuple::one; i())), [head.to_gen().await]),
resolve(mactree!(macros::common::semi_list "push" tail ;)).await,
])
}],
)
.rule(mactreev!(macros::common::semi_list ( "...$" final_tail 0 )), [async |[tail]| {
call(sym_ref(sym!(std::tuple::one; i())), [resolve(tail).await])
call(sym_ref(sym!(std::tuple::one; i())), [tail.to_gen().await])
}])
.rule(mactreev!(macros::common::semi_list()), [async |[]| {
sym_ref(sym!(std::tuple::empty; i()))

View File

@@ -144,7 +144,7 @@ impl Parser for MacroLine {
let mac_cell = Rc::new(OnceCell::new());
let rules = Rc::new(RefCell::new(Some(rules)));
for (kw, sr) in &*keywords {
clone!(mac_cell, rules, module, prio);
clone!(mac_cell, rules, module, macro_name, prio);
lines.push(ParsedLine::cnst(&sr.clone(), &comments, true, kw.clone(), async move |cctx| {
let mac = mac_cell
.get_or_init(async {
@@ -170,7 +170,12 @@ impl Parser for MacroLine {
.flat_map(stream::iter)
.collect::<Vec<_>>()
.await;
Macro(Rc::new(MacroData { module, prio: prio.map(|i| i.0 as u64), rules }))
Macro(Rc::new(MacroData {
canonical_name: module.suffix([macro_name], &i()).await,
module,
prio: prio.map(|i| i.0 as u64),
rules,
}))
})
.await;
atom(mac.clone())

View File

@@ -18,7 +18,7 @@ use crate::macros::macro_lib::gen_macro_lib;
use crate::macros::macro_line::MacroLine;
use crate::macros::macro_value::Macro;
use crate::macros::mactree_lexer::MacTreeLexer;
use crate::macros::match_macros::gen_match_macro_lib;
use crate::macros::match_macros::{MatcherAtom, gen_match_macro_lib};
use crate::macros::ph_lexer::{PhAtom, PhLexer};
use crate::macros::std_macros::gen_std_macro_lib;
use crate::macros::utils::MacroBodyArgCollector;
@@ -43,6 +43,7 @@ impl SystemCard for MacroSystem {
Some(Macro::dynfo()),
Some(PhAtom::dynfo()),
Some(MacroBodyArgCollector::dynfo()),
Some(MatcherAtom::dynfo()),
]
}
}
@@ -53,7 +54,13 @@ impl System for MacroSystem {
sym!(macros::common::+; i()),
sym!(macros::common::*; i()),
sym!(macros::common::,; i()),
sym!(macros::common::;; i()),
sym!(macros::common::..; i()),
sym!(macros::common::_; i()),
sym!(std::tuple::t; i()),
sym!(pattern::match; i()),
sym!(pattern::ref; i()),
sym!(pattern::=>; i()),
]
}
fn lexers() -> Vec<LexerObj> { vec![&MacTreeLexer, &PhLexer] }

View File

@@ -6,13 +6,13 @@ use orchid_base::interner::Tok;
use orchid_base::name::Sym;
use orchid_extension::atom::Atomic;
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
use orchid_extension::context::i;
use crate::macros::mactree::MacTreeSeq;
use crate::macros::rule::matcher::Matcher;
#[derive(Debug)]
pub struct MacroData {
pub canonical_name: Sym,
pub module: Sym,
pub prio: Option<u64>,
pub rules: Vec<Rule>,
@@ -20,11 +20,6 @@ pub struct MacroData {
#[derive(Clone, Debug)]
pub struct Macro(pub Rc<MacroData>);
impl Macro {
pub async fn canonical_name(&self) -> Sym {
self.0.module.suffix([self.0.rules[0].body_name.clone()], &i()).await
}
}
#[derive(Debug)]
pub struct Rule {

View File

@@ -89,47 +89,57 @@ pub async fn gen_match_macro_lib() -> Vec<GenMember> {
matcher,
}),
build_macro(None, ["match", "match_rule", "_row", "=>"])
.rule(mactreev!("pattern::match" { "..$" rules 0 }), [async |[rules]| {
exec(async move |mut h| {
let rule_lines = h
.exec::<TAtom<Tuple>>(call(sym_ref(sym!(macros::resolve; i())), [
mactree!(macros::common::semi_list "push" rules.clone();).to_gen().await,
]))
.await?;
let mut rule_atoms = Vec::<(TAtom<MatcherAtom>, Expr)>::new();
for line_exprh in rule_lines.iter() {
let line_mac = h
.exec::<TAtom<MacTree>>(Expr::from_handle(ExprHandle::from_ticket(*line_exprh).await))
.await?;
let Tpl((matcher, body)) = h
.exec(call(sym_ref(sym!(macros::resolve; i())), [
mactree!(pattern::_row "push" own(&line_mac).await ;).to_gen().await,
.rule(mactreev!("pattern::match" "...$" value 0 { "..$" rules 0 }), [
async |[value, rules]| {
exec(async move |mut h| {
let rule_lines = h
.exec::<TAtom<Tuple>>(call(sym_ref(sym!(macros::resolve; i())), [
mactree!(macros::common::semi_list "push" rules.clone();).to_gen().await,
]))
.await?;
rule_atoms.push((matcher, body));
}
let base_case = lambda(0, [bot(mk_errv(
i().i("No branches match").await,
"None of the pattern provided matches this value",
[rules.pos()],
))]);
let match_expr = stream::iter(rule_atoms.into_iter().rev())
.fold(base_case, async |tail, (mat, body)| {
lambda(0, [call(sym_ref(sym!(pattern::match_one; i())), [
mat.to_gen().await,
arg(0),
body.to_gen().await,
call(tail, [arg(0)]),
])])
})
.await;
Ok(match_expr)
})
.await
}])
let mut rule_atoms = Vec::<(TAtom<MatcherAtom>, Expr)>::new();
for line_exprh in rule_lines.iter() {
let line_mac = h
.exec::<TAtom<MacTree>>(Expr::from_handle(
ExprHandle::from_ticket(*line_exprh).await,
))
.await?;
let Tpl((matcher, body)) = h
.exec(call(sym_ref(sym!(macros::resolve; i())), [
mactree!(pattern::_row "push" own(&line_mac).await ;).to_gen().await,
]))
.await?;
rule_atoms.push((matcher, body));
}
let base_case = lambda(0, [bot(mk_errv(
i().i("No branches match").await,
"None of the patterns matches this value",
[rules.pos()],
))]);
let match_expr = stream::iter(rule_atoms.into_iter().rev())
.fold(base_case, async |tail, (mat, body)| {
lambda(0, [call(sym_ref(sym!(pattern::match_one; i())), [
mat.to_gen().await,
arg(0),
body.to_gen().await,
call(tail, [arg(0)]),
])])
})
.await;
Ok(call(match_expr, [resolve(value).await]))
})
.await
},
])
.rule(mactreev!(pattern::match_rule (( "...$" pattern 0 ))), [async |[pattern]| {
resolve(mactree!(pattern::match_rule "push" pattern; )).await
}])
.rule(mactreev!(pattern::match_rule ( macros::common::_ )), [async |[]| {
Ok(MatcherAtom {
keys: Vec::new(),
matcher: lambda(0, [OrcOpt(Some(Tpl(()))).to_gen().await]).create().await,
})
}])
.rule(mactreev!(pattern::_row ( "...$" pattern 0 pattern::=> "...$" value 1 )), [
async |[pattern, mut value]| {
exec(async move |mut h| -> OrcRes<Tpl<(TAtom<MatcherAtom>, GExpr)>> {

View File

@@ -11,10 +11,10 @@ use orchid_base::name::Sym;
use orchid_base::tree::Paren;
use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
use orchid_extension::context::i;
use orchid_extension::context::{ctx, i};
use orchid_extension::conv::ToExpr;
use orchid_extension::coroutine_exec::{ExecHandle, exec};
use orchid_extension::gen_expr::{GExpr, bot, call, lambda, sym_ref};
use orchid_extension::gen_expr::{GExpr, arg, bot, call, lambda, sym_ref};
use orchid_extension::reflection::{ReflMemKind, refl};
use subslice_offset::SubsliceOffset;
use substack::Substack;
@@ -26,13 +26,17 @@ use crate::{MacTok, MacTree};
pub async fn resolve(tpl: MacTree) -> GExpr {
exec(async move |mut h| {
let ctx = ctx();
// if ctx.logger().is_active() {
writeln!(ctx.logger(), "Macro-resolving {}", fmt(&tpl, &i()).await);
// }
let root = refl();
let mut macros = HashMap::new();
for n in tpl.glossary() {
if let Ok(ReflMemKind::Const) = root.get_by_path(n).await.map(|m| m.kind()) {
let Ok(mac) = h.exec::<TAtom<Macro>>(sym_ref(n.clone())).await else { continue };
let mac = own(&mac).await;
macros.entry(mac.canonical_name().await).or_insert(mac);
macros.entry(mac.0.canonical_name.clone()).or_insert(mac);
}
}
let mut exclusive = Vec::new();
@@ -87,7 +91,10 @@ async fn resolve_one(
MacTok::Ph(_) | MacTok::Slot => panic!("Forbidden element in value mactree"),
MacTok::Bottom(err) => bot(err.clone()),
MacTok::Value(v) => v.clone().to_gen().await,
MacTok::Name(n) => sym_ref(n.clone()),
MacTok::Name(n) => match arg_stk.iter().position(|arg| arg == n) {
Some(de_bruijn) => arg((arg_stk.len() - 1 - de_bruijn).try_into().unwrap()),
None => sym_ref(n.clone()),
},
MacTok::Lambda(arg, body) => {
let MacTok::Name(name) = &*arg.tok else {
return bot(mk_errv(

View File

@@ -182,7 +182,7 @@ mod test {
.await,
];
let matcher = mk_any(&pattern).await.expect("This matcher isn't broken");
println!("{matcher}");
eprintln!("{matcher}");
}))
}
}

View File

@@ -21,7 +21,7 @@ pub async fn gen_std_macro_lib() -> Vec<GenMember> {
fun(false, "is_some_body", |sub: TAtom<MatcherAtom>, val: OrcOpt<Expr>| {
exec(async move |mut h| {
let Some(sub_val) = val.0 else { return Ok(OrcOpt(None)) };
h.exec::<OrcOpt<Expr>>(call(sub.to_gen().await, [sub_val.to_gen().await])).await
sub.run_matcher(&mut h, sub_val).await
})
}),
fun(false, "is_none_body", async |val: OrcOpt<Expr>| {
@@ -81,12 +81,12 @@ pub async fn gen_std_macro_lib() -> Vec<GenMember> {
})
}])
.rule(
mactreev!(pattern::match_rule(std::tuple::t[ "...$" elements 0 macros::common::..])),
mactreev!(pattern::match_rule(std::tuple::t[ "...$" elements 0 macros::common::, macros::common::..])),
[async |[elements]: [_; _]| parse_tpl(elements, Some(mactree!(macros::common::_))).await],
)
.rule(
mactreev!(pattern::match_rule(
std::tuple::t[ "...$" elements 1 macros::common::.. "...$" tail 0]
std::tuple::t[ "...$" elements 1 macros::common::, macros::common::.. "...$" tail 0]
)),
[async |[elements, tail]: [_; _]| parse_tpl(elements, Some(tail)).await],
)
@@ -111,7 +111,7 @@ fn parse_tpl(elements: MacTree, tail_matcher: Option<MacTree>) -> impl Future<Ou
let mac = own(mac_a).await;
let sub = h
.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve; i())), [
mactree!(pattern::match_rule "push" mac ;).to_gen().await,
mactree!(pattern::match_rule ("push" mac ;)).to_gen().await,
]))
.await?;
subs.push(sub);
@@ -146,7 +146,7 @@ fn tuple_matcher_body(
tail: OrcOpt<TAtom<MatcherAtom>>,
value: HomoTpl<Expr>,
) -> impl Future<Output = GExpr> {
exec(async move |mut h| -> OrcRes<OrcOpt<GExpr>> {
exec(async move |mut h| -> OrcRes<OrcOpt<HomoTpl<Expr>>> {
if value.0.len() < children.0.len() {
return Ok(OrcOpt(None));
}
@@ -172,6 +172,6 @@ fn tuple_matcher_body(
}
},
};
todo!()
Ok(OrcOpt(Some(HomoTpl(binds))))
})
}

View File

@@ -105,6 +105,7 @@ impl MacroBuilder {
.expect("Default macro in global root");
MemKind::Const(
Macro(Rc::new(MacroData {
canonical_name: module.suffix([i().i(name).await], &i()).await,
module,
prio,
rules: stream(async |mut h| {