Fixed match, and enabled macro keywords to share names with constants

This commit is contained in:
2025-11-30 02:30:42 +01:00
parent ecf151158d
commit 4e4dc381ea
7 changed files with 82 additions and 73 deletions

View File

@@ -1,6 +1,6 @@
let my_tuple = option::some t[1, 2]
let main = match my_tuple {
option::of t[ref head, ..] => head;
option::empty => "foo";
option::some t[ref head, ..] => head;
option::none => "foo";
}

View File

@@ -3,12 +3,14 @@ use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
use orchid_extension::context::i;
use orchid_extension::conv::ToExpr;
use orchid_extension::coroutine_exec::exec;
use orchid_extension::gen_expr::{call, sym_ref};
use orchid_extension::tree::{GenMember, fun, prefix};
use crate::macros::mactree::MacTree;
use crate::macros::resolve::resolve;
use crate::macros::utils::{build_macro, mactree, mactreev};
use crate::{HomoTpl, UntypedTuple};
pub async fn gen_macro_lib() -> Vec<GenMember> {
prefix("macros", [
@@ -30,35 +32,37 @@ pub async fn gen_macro_lib() -> Vec<GenMember> {
.rule(
mactreev!(macros::common::comma_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())), [head.to_gen().await]),
resolve(mactree!(macros::common::comma_list "push" tail ;)).await,
])
exec(async |mut h| {
let recur = resolve(mactree!(macros::common::comma_list "push" tail ;)).await;
let mut tail = h.exec::<HomoTpl<TAtom<MacTree>>>(recur).await?;
tail.0.insert(0, h.exec(head).await?);
Ok(tail)
})
.await
}],
)
.rule(mactreev!(macros::common::comma_list ( "...$" final_tail 0 )), [async |[tail]| {
call(sym_ref(sym!(std::tuple::one; i())), [tail.to_gen().await])
}])
.rule(mactreev!(macros::common::comma_list()), [async |[]| {
sym_ref(sym!(std::tuple::empty; i()))
HomoTpl(vec![tail.to_gen().await])
}])
.rule(mactreev!(macros::common::comma_list()), [async |[]| UntypedTuple(Vec::new())])
.finish(),
build_macro(None, ["semi_list", ";"])
.rule(
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())), [head.to_gen().await]),
resolve(mactree!(macros::common::semi_list "push" tail ;)).await,
])
exec(async |mut h| {
let recur = resolve(mactree!(macros::common::semi_list "push" tail ;)).await;
let mut tail = h.exec::<HomoTpl<TAtom<MacTree>>>(recur).await?;
tail.0.insert(0, h.exec(head).await?);
Ok(tail)
})
.await
}],
)
.rule(mactreev!(macros::common::semi_list ( "...$" final_tail 0 )), [async |[tail]| {
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()))
HomoTpl(vec![tail.to_gen().await])
}])
.rule(mactreev!(macros::common::semi_list()), [async |[]| UntypedTuple(Vec::new())])
.finish(),
]),
])

View File

@@ -1,8 +1,8 @@
use std::cell::RefCell;
use std::rc::Rc;
use async_fn_stream::stream;
use async_once_cell::OnceCell;
use futures::{StreamExt, stream};
use futures::StreamExt;
use itertools::Itertools;
use orchid_base::error::{OrcRes, Reporter, mk_errv};
use orchid_base::parse::{
@@ -14,7 +14,7 @@ use orchid_base::{clone, sym};
use orchid_extension::atom::TAtom;
use orchid_extension::context::i;
use orchid_extension::conv::{ToExpr, TryFromExpr};
use orchid_extension::gen_expr::{atom, call, sym_ref};
use orchid_extension::gen_expr::{call, sym_ref};
use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser};
use crate::macros::let_line::{dealias_mac_v, parse_tokv};
@@ -142,43 +142,37 @@ impl Parser for MacroLine {
}))
}
let mac_cell = Rc::new(OnceCell::new());
let rules = Rc::new(RefCell::new(Some(rules)));
let rules = Rc::new(rules);
for (kw, sr) in &*keywords {
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 {
let rep = Reporter::new();
let rules = rules.borrow_mut().take().expect("once cell initializer runs");
let rules = stream::iter(rules)
.then(|(body_name, placeholders, pattern_rel)| {
let cctx = &cctx;
let rep = &rep;
async move {
let pattern = dealias_mac_v(&pattern_rel, cctx, rep).await;
let pattern_res = Matcher::new(pattern.clone()).await;
let placeholders = placeholders.into_iter().map(|(ph, _)| ph.name).collect_vec();
match pattern_res {
Ok(matcher) => Some(Rule { body_name, matcher, pattern, placeholders }),
Err(e) => {
rep.report(e);
None
},
}
}
})
.flat_map(stream::iter)
.collect::<Vec<_>>()
.await;
Macro(Rc::new(MacroData {
let kw_key = i().i(&format!("__macro__{kw}")).await;
lines.push(ParsedLine::cnst(&sr.clone(), &comments, true, kw_key, async move |cctx| {
let mac_future = async {
let rep = Reporter::new();
let rules = stream(async |mut h| {
for (body, ph_names, pattern_rel) in rules.iter() {
let pattern = dealias_mac_v(pattern_rel, &cctx, &rep).await;
let ph_names = ph_names.iter().map(|(ph, _)| ph.name.clone()).collect_vec();
match Matcher::new(pattern.clone()).await {
Ok(matcher) =>
h.emit(Rule { body: body.clone(), matcher, pattern, ph_names }).await,
Err(e) => rep.report(e),
}
}
})
.collect::<Vec<_>>()
.await;
match rep.errv() {
Some(e) => Err(e),
None => Ok(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())
}))),
}
};
mac_cell.get_or_init(mac_future).await.clone().to_gen().await
}))
}
Ok(lines)

View File

@@ -25,8 +25,8 @@ pub struct Macro(pub Rc<MacroData>);
pub struct Rule {
pub pattern: MacTreeSeq,
pub matcher: Matcher,
pub placeholders: Vec<Tok<String>>,
pub body_name: Tok<String>,
pub ph_names: Vec<Tok<String>>,
pub body: Tok<String>,
}
impl Atomic for Macro {
type Data = ();

View File

@@ -7,7 +7,7 @@ use itertools::Itertools;
use orchid_base::error::mk_errv;
use orchid_base::format::fmt;
use orchid_base::location::Pos;
use orchid_base::name::Sym;
use orchid_base::name::{NameLike, Sym, VPath};
use orchid_base::tree::Paren;
use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
@@ -24,17 +24,22 @@ use crate::macros::mactree::MacTreeSeq;
use crate::macros::rule::state::{MatchState, StateEntry};
use crate::{MacTok, MacTree};
pub async fn resolve(tpl: MacTree) -> GExpr {
pub async fn resolve(val: MacTree) -> GExpr {
exec(async move |mut h| {
let ctx = ctx();
// if ctx.logger().is_active() {
writeln!(ctx.logger(), "Macro-resolving {}", fmt(&tpl, &i()).await);
writeln!(ctx.logger(), "Macro-resolving {}", fmt(&val, &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 };
for n in val.glossary() {
let (foot, body) = n.split_last_seg();
let new_name = VPath::new(body.iter().cloned())
.name_with_suffix(i().i(&format!("__macro__{foot}")).await)
.to_sym(&i())
.await;
if let Ok(ReflMemKind::Const) = root.get_by_path(&new_name).await.map(|m| m.kind()) {
let Ok(mac) = h.exec::<TAtom<Macro>>(sym_ref(new_name)).await else { continue };
let mac = own(&mac).await;
macros.entry(mac.0.canonical_name.clone()).or_insert(mac);
}
@@ -45,7 +50,7 @@ pub async fn resolve(tpl: MacTree) -> GExpr {
for (_, mac) in macros.iter() {
let mut record = FilteredMacroRecord { mac, rules: Vec::new() };
for (rule_i, rule) in mac.0.rules.iter().enumerate() {
if rule.pattern.glossary.is_subset(tpl.glossary()) {
if rule.pattern.glossary.is_subset(val.glossary()) {
record.rules.push(rule_i);
}
}
@@ -61,7 +66,14 @@ pub async fn resolve(tpl: MacTree) -> GExpr {
}
}
let mut rctx = ResolveCtx { h, exclusive, priod };
resolve_one(&mut rctx, Substack::Bottom, &tpl).await
let gex = resolve_one(&mut rctx, Substack::Bottom, &val).await;
writeln!(
ctx.logger(),
"Macro-resolution over {}\nreturned {}",
fmt(&val, &i()).await,
fmt(&gex, &i()).await
);
gex
})
.await
}
@@ -270,13 +282,12 @@ async fn resolve_seq(
async fn mk_body_call(mac: &Macro, rule: &Rule, state: &MatchState<'_>, pos: Pos) -> GExpr {
let mut call_args = vec![];
for name in rule.placeholders.iter() {
for name in rule.ph_names.iter() {
call_args.push(match state.get(name).expect("Missing state entry for placeholder") {
StateEntry::Scalar(scal) => (**scal).clone().to_gen().await,
StateEntry::Vec(vec) =>
MacTok::S(Paren::Round, MacTreeSeq::new(vec.iter().cloned())).at(Pos::None).to_gen().await,
});
}
call(sym_ref(mac.0.module.suffix([rule.body_name.clone()], &i()).await), call_args)
.at(pos.clone())
call(sym_ref(mac.0.module.suffix([rule.body.clone()], &i()).await), call_args).at(pos.clone())
}

View File

@@ -27,8 +27,8 @@ pub async fn gen_std_macro_lib() -> Vec<GenMember> {
fun(false, "is_none_body", async |val: OrcOpt<Expr>| {
if val.0.is_none() { OrcOpt(Some(Tpl(()))) } else { OrcOpt(None) }
}),
build_macro(None, ["of", "empty"])
.rule(mactreev!(pattern::match_rule ( std::option::of "...$" sub_pattern 0)), [
build_macro(None, ["some", "none"])
.rule(mactreev!(pattern::match_rule ( std::option::some "...$" sub_pattern 0)), [
|[sub]: [_; _]| {
exec(async move |mut h| {
let sub = h
@@ -47,7 +47,7 @@ pub async fn gen_std_macro_lib() -> Vec<GenMember> {
})
},
])
.rule(mactreev!(pattern::match_rule(std::option::empty)), [|[]: [_; _]| {
.rule(mactreev!(pattern::match_rule(std::option::none)), [|[]: [_; _]| {
exec(async |mut h| {
Ok(MatcherAtom {
keys: vec![],

View File

@@ -100,7 +100,7 @@ impl MacroBuilder {
pub(crate) fn finish(self) -> Vec<GenMember> {
let Self { own_kws, prio, patterns, body_consts } = self;
let name = own_kws[0];
let main_const = lazy(true, name, async move |path| {
let main_const = lazy(true, &format!("__macro__{name}"), async move |path| {
let module = (Sym::new(path.split_last_seg().1.iter().cloned(), &i()).await)
.expect("Default macro in global root");
MemKind::Const(
@@ -120,8 +120,8 @@ impl MacroBuilder {
h.emit(Rule {
matcher: Matcher::new(pattern.clone()).await.unwrap(),
pattern,
placeholders,
body_name: i().i(&format!("({name})::{counter}")).await,
ph_names: placeholders,
body: i().i(&format!("({name})::{counter}")).await,
})
.await;
}
@@ -134,9 +134,9 @@ impl MacroBuilder {
)
});
let kw_consts = own_kws[1..].iter().flat_map(|kw| {
lazy(true, kw, async |path| {
lazy(true, &format!("__macro__{kw}"), async move |path| {
let main_const_name = VPath::new(path.split_last_seg().1.iter().cloned())
.name_with_suffix(i().i(name).await)
.name_with_suffix(i().i(&format!("__macro__{name}")).await)
.to_sym(&i())
.await;
MemKind::Const(sym_ref(main_const_name))