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

@@ -4,8 +4,8 @@ The code in this repository is free for noncommercial use, including derivative
Identifying marks stored in the repository are restricted for use with an unmodified copy of this software. If you distribute modified versions of this software, you must either replace these identifying marks or modify them in a way that clearly indicates that what you are distributing is a derivative work and not this official vversion. You must also replace any contact information in such a way that your derivative work does not suggest that we may be contacted about issues. Your derivative work may use the original identifying marks and contact information to identify this project as its basis, while emphasizing that the authors of the original project are neither in control of, nor liable for the derivative work. Identifying marks stored in the repository are restricted for use with an unmodified copy of this software. If you distribute modified versions of this software, you must either replace these identifying marks or modify them in a way that clearly indicates that what you are distributing is a derivative work and not this official vversion. You must also replace any contact information in such a way that your derivative work does not suggest that we may be contacted about issues. Your derivative work may use the original identifying marks and contact information to identify this project as its basis, while emphasizing that the authors of the original project are neither in control of, nor liable for the derivative work.
Identifying marks include the Orchid logo, the ribbon image above, and the names "Orchid", "Orchidlang" unless they are part of a technical interface. Identifying marks include the Orchid logo, the ribbon image in the readme, and the names "Orchid", "Orchidlang" unless they are part of a technical interface.
Contact information includes email addresses, links to the source code and issue tracker. Contact information includes email addresses, links to the source code and issue tracker.
Words listed as identifying marks are explicltly not considered as such when they appear in technical interfaces or APIs. For example, shell commands, identifiers within Orchid or Rust code, and names in package registries are not considered as identifying marks. Words listed as identifying marks are explicltly not considered as such when they appear in technical interfaces or APIs. For example, shell commands, identifiers within Orchid or Rust code, and names in package registries are not considered identifying marks.

View File

@@ -35,9 +35,7 @@ Orchids and mangrove trees form complex ecosystems; The flowers persuade the tre
All contributions are welcome. For the time being, use the issue tracker to discuss ideas. All contributions are welcome. For the time being, use the issue tracker to discuss ideas.
Unless we agree on different terms, by contributing to this software you declare that you have created or otherwise have the right to license your contribution, agree to license it publicly under the general noncommercial licence included in this repository, and grant me (the owner of the project) a permanent, unrestricted license to use, modify, distribute and relicense your contribution. Unless we agree on different terms, by contributing to this software you declare that you have created or otherwise have the right to license your contribution, agree to license it publicly under the general noncommercial licence included in this repository, and grant me (the owner of the project) a permanent, unrestricted license to use, modify, distribute and relicense your contribution. You retain ownership of your intellectual property to ensure that the copyleft protections cementing the noncommercial availability of the code are preserved.
You retain ownership of your intellectual property to ensure that the copyleft protections cementing the noncommercial availability of the code are preserved.
## About the license ## About the license

View File

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

View File

@@ -112,7 +112,7 @@ float_impl!(f32, 4);
impl Decode for String { impl Decode for String {
async fn decode<R: AsyncRead + ?Sized>(mut read: Pin<&mut R>) -> Self { async fn decode<R: AsyncRead + ?Sized>(mut read: Pin<&mut R>) -> Self {
let len = u64::decode(read.as_mut()).await.try_into().unwrap(); let len: usize = u64::decode(read.as_mut()).await.try_into().unwrap();
let mut data = vec![0u8; len]; let mut data = vec![0u8; len];
read.read_exact(&mut data).await.unwrap(); read.read_exact(&mut data).await.unwrap();
std::str::from_utf8(&data).expect("String invalid UTF-8").to_owned() std::str::from_utf8(&data).expect("String invalid UTF-8").to_owned()
@@ -132,7 +132,7 @@ impl Encode for str {
} }
impl<T: Decode> Decode for Vec<T> { impl<T: Decode> Decode for Vec<T> {
async fn decode<R: AsyncRead + ?Sized>(mut read: Pin<&mut R>) -> Self { async fn decode<R: AsyncRead + ?Sized>(mut read: Pin<&mut R>) -> Self {
let len = u64::decode(read.as_mut()).await.try_into().unwrap(); let len = u64::decode(read.as_mut()).await;
stream(async |mut cx| { stream(async |mut cx| {
for _ in 0..len { for _ in 0..len {
cx.emit(T::decode(read.as_mut()).await).await cx.emit(T::decode(read.as_mut()).await).await
@@ -191,7 +191,7 @@ impl<T: Encode, E: Encode> Encode for Result<T, E> {
} }
impl<K: Decode + Eq + Hash, V: Decode> Decode for HashMap<K, V> { impl<K: Decode + Eq + Hash, V: Decode> Decode for HashMap<K, V> {
async fn decode<R: AsyncRead + ?Sized>(mut read: Pin<&mut R>) -> Self { async fn decode<R: AsyncRead + ?Sized>(mut read: Pin<&mut R>) -> Self {
let len = u64::decode(read.as_mut()).await.try_into().unwrap(); let len = u64::decode(read.as_mut()).await;
stream(async |mut cx| { stream(async |mut cx| {
for _ in 0..len { for _ in 0..len {
cx.emit(<(K, V)>::decode(read.as_mut()).await).await cx.emit(<(K, V)>::decode(read.as_mut()).await).await

View File

@@ -13,6 +13,7 @@ impl Logger {
pub fn new(strat: api::LogStrategy) -> Self { Self(strat) } pub fn new(strat: api::LogStrategy) -> Self { Self(strat) }
pub fn log(&self, msg: impl AsRef<str>) { writeln!(self, "{}", msg.as_ref()) } pub fn log(&self, msg: impl AsRef<str>) { writeln!(self, "{}", msg.as_ref()) }
pub fn strat(&self) -> api::LogStrategy { self.0.clone() } pub fn strat(&self) -> api::LogStrategy { self.0.clone() }
pub fn is_active(&self) -> bool { !matches!(self.0, api::LogStrategy::Discard) }
pub fn log_buf(&self, event: impl AsRef<str>, buf: &[u8]) { pub fn log_buf(&self, event: impl AsRef<str>, buf: &[u8]) {
if std::env::var("ORCHID_LOG_BUFFERS").is_ok_and(|v| !v.is_empty()) { if std::env::var("ORCHID_LOG_BUFFERS").is_ok_and(|v| !v.is_empty()) {
writeln!(self, "{}: [{}]", event.as_ref(), buf.iter().map(|b| format!("{b:02x}")).join(" ")) writeln!(self, "{}: [{}]", event.as_ref(), buf.iter().map(|b| format!("{b:02x}")).join(" "))

View File

@@ -5,7 +5,7 @@ use std::mem;
use std::ops::{BitAnd, Deref}; use std::ops::{BitAnd, Deref};
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::thread::panicking;
use derive_destructure::destructure; use derive_destructure::destructure;
use dyn_clone::{DynClone, clone_box}; use dyn_clone::{DynClone, clone_box};
@@ -14,7 +14,7 @@ use futures::future::LocalBoxFuture;
use futures::lock::Mutex; use futures::lock::Mutex;
use futures::{SinkExt, StreamExt}; use futures::{SinkExt, StreamExt};
use hashbrown::HashMap; use hashbrown::HashMap;
use orchid_api_traits::{Channel, Coding, Decode, Encode, MsgSet, Request}; use orchid_api_traits::{Channel, Coding, Decode, Encode, MsgSet, Request, enc_vec};
use trait_set::trait_set; use trait_set::trait_set;
use crate::clone; use crate::clone;
@@ -50,17 +50,23 @@ impl ReqHandlish for &'_ dyn ReqHandlish {
fn defer_objsafe(&self, val: Pin<Box<dyn Future<Output = ()>>>) { (**self).defer_objsafe(val) } fn defer_objsafe(&self, val: Pin<Box<dyn Future<Output = ()>>>) { (**self).defer_objsafe(val) }
} }
type LocalAsyncFnOnceBox = Box<dyn FnOnce(Vec<u8>) -> LocalBoxFuture<'static, ()>>;
#[derive(destructure)] #[derive(destructure)]
pub struct RequestHandle<'a, MS: MsgSet> { pub struct RequestHandle<'a, MS: MsgSet> {
defer: RefCell<Vec<Pin<Box<dyn Future<Output = ()>>>>>, defer: RefCell<Vec<Pin<Box<dyn Future<Output = ()>>>>>,
fulfilled: AtomicBool,
id: u64,
_reqlt: PhantomData<&'a mut ()>, _reqlt: PhantomData<&'a mut ()>,
parent: ReqNot<MS>, parent: ReqNot<MS>,
raw_reply: RefCell<Option<LocalAsyncFnOnceBox>>,
} }
impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> { impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> {
fn new(parent: ReqNot<MS>, id: u64) -> Self { pub fn new(parent: ReqNot<MS>, raw_reply: impl AsyncFnOnce(Vec<u8>) + 'static) -> Self {
Self { defer: RefCell::default(), fulfilled: false.into(), _reqlt: PhantomData, parent, id } Self {
defer: RefCell::default(),
_reqlt: PhantomData,
parent,
raw_reply: RefCell::new(Some(Box::new(|v| Box::pin(raw_reply(v))))),
}
} }
pub fn reqnot(&self) -> ReqNot<MS> { self.parent.clone() } pub fn reqnot(&self) -> ReqNot<MS> { self.parent.clone() }
pub async fn handle<U: Request>(&self, _: &U, rep: &U::Response) -> Receipt<'a> { pub async fn handle<U: Request>(&self, _: &U, rep: &U::Response) -> Receipt<'a> {
@@ -71,11 +77,9 @@ impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> {
self.respond(rep).await self.respond(rep).await
} }
pub async fn respond(&self, response: &impl Encode) -> Receipt<'a> { pub async fn respond(&self, response: &impl Encode) -> Receipt<'a> {
assert!(!self.fulfilled.swap(true, Ordering::Relaxed), "Already responded to {}", self.id); let replier = self.raw_reply.borrow_mut().take().expect("Already responded to request");
let mut buf = (!self.id).to_be_bytes().to_vec(); let buf = enc_vec(response).await;
response.encode(Pin::new(&mut buf)).await; (replier)(buf).await;
let mut send = clone_box(&*self.reqnot().0.lock().await.send);
(send)(&buf, self.parent.clone()).await;
let deferred = mem::take(&mut *self.defer.borrow_mut()); let deferred = mem::take(&mut *self.defer.borrow_mut());
for item in deferred { for item in deferred {
item.await item.await
@@ -90,8 +94,9 @@ impl<MS: MsgSet> ReqHandlish for RequestHandle<'_, MS> {
} }
impl<MS: MsgSet> Drop for RequestHandle<'_, MS> { impl<MS: MsgSet> Drop for RequestHandle<'_, MS> {
fn drop(&mut self) { fn drop(&mut self) {
let done = self.fulfilled.load(Ordering::Relaxed); if !panicking() {
debug_assert!(done, "Request {} dropped without response", self.id) debug_assert!(self.raw_reply.borrow().is_none(), "Request dropped without response")
}
} }
} }
@@ -151,7 +156,17 @@ impl<T: MsgSet> ReqNot<T> {
let mut req_cb = clone_box(&*g.req); let mut req_cb = clone_box(&*g.req);
mem::drop(g); mem::drop(g);
let rn = self.clone(); let rn = self.clone();
req_cb(RequestHandle::new(rn, id), message).await; let rn2 = self.clone();
req_cb(
RequestHandle::new(rn, async move |vec| {
let mut buf = (!id).to_be_bytes().to_vec();
buf.extend(vec);
let mut send = clone_box(&*rn2.0.lock().await.send);
(send)(&buf, rn2.clone()).await;
}),
message,
)
.await;
} }
} }

View File

@@ -123,6 +123,10 @@ impl Format for ForeignAtom {
} }
} }
impl ToExpr for ForeignAtom { impl ToExpr for ForeignAtom {
async fn to_expr(self) -> Expr
where Self: Sized {
self.ex()
}
async fn to_gen(self) -> GExpr { self.ex().to_gen().await } async fn to_gen(self) -> GExpr { self.ex().to_gen().await }
} }

View File

@@ -241,11 +241,20 @@ pub fn extension_init(
}) })
.await, .await,
api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => { api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
let fwd_tok = hand.will_handle_as(&fwd);
let api::SysFwded(sys_id, payload) = fwd; let api::SysFwded(sys_id, payload) = fwd;
let ctx = get_ctx(sys_id).await; let ctx = get_ctx(sys_id).await;
with_ctx(ctx.clone(), async move { with_ctx(ctx.clone(), async move {
let sys = ctx.cted().inst(); let sys = ctx.cted().inst();
sys.dyn_request(hand, payload).await let reply = Rc::new(RefCell::new(None));
let reply2 = reply.clone();
let sub_hand = ExtReq::new(hand.reqnot(), async move |v| {
reply2.borrow_mut().replace(v);
});
sys.dyn_request(sub_hand, payload).await;
let reply_buf =
reply.borrow_mut().take().expect("Request discarded but did not throw");
hand.handle_as(fwd_tok, &reply_buf).await
}) })
.await .await
}, },

View File

@@ -2,6 +2,7 @@ use std::cell::RefCell;
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use std::rc::Rc; use std::rc::Rc;
use std::thread::panicking;
use async_once_cell::OnceCell; use async_once_cell::OnceCell;
use derive_destructure::destructure; use derive_destructure::destructure;
@@ -28,7 +29,7 @@ impl BorrowedExprStore {
} }
impl Drop for BorrowedExprStore { impl Drop for BorrowedExprStore {
fn drop(&mut self) { fn drop(&mut self) {
if self.0.borrow().is_some() { if self.0.borrow().is_some() && !panicking() {
panic!("This should always be explicitly disposed") panic!("This should always be explicitly disposed")
} }
} }

View File

@@ -50,7 +50,9 @@ fn process_args<I, O, F: ExprFunc<I, O>>(f: F) -> FunRecord {
exec(async move |mut hand| { exec(async move |mut hand| {
let mut norm_args = Vec::with_capacity(v.len()); let mut norm_args = Vec::with_capacity(v.len());
for (expr, typ) in v.into_iter().zip(argtyps) { for (expr, typ) in v.into_iter().zip(argtyps) {
if *typ != TypeId::of::<Expr>() { if *typ == TypeId::of::<Expr>() {
norm_args.push(expr);
} else {
norm_args.push(hand.exec(expr).await?); norm_args.push(hand.exec(expr).await?);
} }
} }

View File

@@ -32,9 +32,9 @@ pub async fn ext_command(
.await; .await;
let mut stdout = child.stdout.take().unwrap(); let mut stdout = child.stdout.take().unwrap();
let header = api::ExtensionHeader::decode(Pin::new(&mut stdout)).await; let header = api::ExtensionHeader::decode(Pin::new(&mut stdout)).await;
let child_stderr = child.stderr.take().unwrap(); let mut child_stderr = child.stderr.take().unwrap();
(ctx.spawn)(Box::pin(async move { (ctx.spawn)(Box::pin(async move {
let mut reader = BufReader::new(child_stderr); let mut reader = BufReader::new(&mut child_stderr);
loop { loop {
let mut buf = String::new(); let mut buf = String::new();
if 0 == reader.read_line(&mut buf).await.unwrap() { if 0 == reader.read_line(&mut buf).await.unwrap() {

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)), mactreev!(macros::common::semi_list ( "...$" head 0 macros::common::; "...$" tail 1)),
[async |[head, tail]| { [async |[head, tail]| {
call(sym_ref(sym!(std::tuple::cat; i())), [ 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, resolve(mactree!(macros::common::semi_list "push" tail ;)).await,
]) ])
}], }],
) )
.rule(mactreev!(macros::common::semi_list ( "...$" final_tail 0 )), [async |[tail]| { .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 |[]| { .rule(mactreev!(macros::common::semi_list()), [async |[]| {
sym_ref(sym!(std::tuple::empty; i())) 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 mac_cell = Rc::new(OnceCell::new());
let rules = Rc::new(RefCell::new(Some(rules))); let rules = Rc::new(RefCell::new(Some(rules)));
for (kw, sr) in &*keywords { 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| { lines.push(ParsedLine::cnst(&sr.clone(), &comments, true, kw.clone(), async move |cctx| {
let mac = mac_cell let mac = mac_cell
.get_or_init(async { .get_or_init(async {
@@ -170,7 +170,12 @@ impl Parser for MacroLine {
.flat_map(stream::iter) .flat_map(stream::iter)
.collect::<Vec<_>>() .collect::<Vec<_>>()
.await; .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; .await;
atom(mac.clone()) 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_line::MacroLine;
use crate::macros::macro_value::Macro; use crate::macros::macro_value::Macro;
use crate::macros::mactree_lexer::MacTreeLexer; 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::ph_lexer::{PhAtom, PhLexer};
use crate::macros::std_macros::gen_std_macro_lib; use crate::macros::std_macros::gen_std_macro_lib;
use crate::macros::utils::MacroBodyArgCollector; use crate::macros::utils::MacroBodyArgCollector;
@@ -43,6 +43,7 @@ impl SystemCard for MacroSystem {
Some(Macro::dynfo()), Some(Macro::dynfo()),
Some(PhAtom::dynfo()), Some(PhAtom::dynfo()),
Some(MacroBodyArgCollector::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!(macros::common::;; i()),
sym!(macros::common::..; i()),
sym!(macros::common::_; i()),
sym!(std::tuple::t; i()), sym!(std::tuple::t; i()),
sym!(pattern::match; i()),
sym!(pattern::ref; i()),
sym!(pattern::=>; i()),
] ]
} }
fn lexers() -> Vec<LexerObj> { vec![&MacTreeLexer, &PhLexer] } 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_base::name::Sym;
use orchid_extension::atom::Atomic; use orchid_extension::atom::Atomic;
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant}; use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
use orchid_extension::context::i;
use crate::macros::mactree::MacTreeSeq; use crate::macros::mactree::MacTreeSeq;
use crate::macros::rule::matcher::Matcher; use crate::macros::rule::matcher::Matcher;
#[derive(Debug)] #[derive(Debug)]
pub struct MacroData { pub struct MacroData {
pub canonical_name: Sym,
pub module: Sym, pub module: Sym,
pub prio: Option<u64>, pub prio: Option<u64>,
pub rules: Vec<Rule>, pub rules: Vec<Rule>,
@@ -20,11 +20,6 @@ pub struct MacroData {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Macro(pub Rc<MacroData>); 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)] #[derive(Debug)]
pub struct Rule { pub struct Rule {

View File

@@ -89,47 +89,57 @@ pub async fn gen_match_macro_lib() -> Vec<GenMember> {
matcher, matcher,
}), }),
build_macro(None, ["match", "match_rule", "_row", "=>"]) build_macro(None, ["match", "match_rule", "_row", "=>"])
.rule(mactreev!("pattern::match" { "..$" rules 0 }), [async |[rules]| { .rule(mactreev!("pattern::match" "...$" value 0 { "..$" rules 0 }), [
exec(async move |mut h| { async |[value, rules]| {
let rule_lines = h exec(async move |mut h| {
.exec::<TAtom<Tuple>>(call(sym_ref(sym!(macros::resolve; i())), [ let rule_lines = h
mactree!(macros::common::semi_list "push" rules.clone();).to_gen().await, .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,
])) ]))
.await?; .await?;
rule_atoms.push((matcher, body)); let mut rule_atoms = Vec::<(TAtom<MatcherAtom>, Expr)>::new();
} for line_exprh in rule_lines.iter() {
let base_case = lambda(0, [bot(mk_errv( let line_mac = h
i().i("No branches match").await, .exec::<TAtom<MacTree>>(Expr::from_handle(
"None of the pattern provided matches this value", ExprHandle::from_ticket(*line_exprh).await,
[rules.pos()], ))
))]); .await?;
let match_expr = stream::iter(rule_atoms.into_iter().rev()) let Tpl((matcher, body)) = h
.fold(base_case, async |tail, (mat, body)| { .exec(call(sym_ref(sym!(macros::resolve; i())), [
lambda(0, [call(sym_ref(sym!(pattern::match_one; i())), [ mactree!(pattern::_row "push" own(&line_mac).await ;).to_gen().await,
mat.to_gen().await, ]))
arg(0), .await?;
body.to_gen().await, rule_atoms.push((matcher, body));
call(tail, [arg(0)]), }
])]) let base_case = lambda(0, [bot(mk_errv(
}) i().i("No branches match").await,
.await; "None of the patterns matches this value",
Ok(match_expr) [rules.pos()],
}) ))]);
.await 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]| { .rule(mactreev!(pattern::match_rule (( "...$" pattern 0 ))), [async |[pattern]| {
resolve(mactree!(pattern::match_rule "push" pattern; )).await 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 )), [ .rule(mactreev!(pattern::_row ( "...$" pattern 0 pattern::=> "...$" value 1 )), [
async |[pattern, mut value]| { async |[pattern, mut value]| {
exec(async move |mut h| -> OrcRes<Tpl<(TAtom<MatcherAtom>, GExpr)>> { 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_base::tree::Paren;
use orchid_extension::atom::TAtom; use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own; 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::conv::ToExpr;
use orchid_extension::coroutine_exec::{ExecHandle, exec}; 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 orchid_extension::reflection::{ReflMemKind, refl};
use subslice_offset::SubsliceOffset; use subslice_offset::SubsliceOffset;
use substack::Substack; use substack::Substack;
@@ -26,13 +26,17 @@ use crate::{MacTok, MacTree};
pub async fn resolve(tpl: MacTree) -> GExpr { pub async fn resolve(tpl: MacTree) -> GExpr {
exec(async move |mut h| { 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 root = refl();
let mut macros = HashMap::new(); let mut macros = HashMap::new();
for n in tpl.glossary() { for n in tpl.glossary() {
if let Ok(ReflMemKind::Const) = root.get_by_path(n).await.map(|m| m.kind()) { 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 Ok(mac) = h.exec::<TAtom<Macro>>(sym_ref(n.clone())).await else { continue };
let mac = own(&mac).await; 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(); let mut exclusive = Vec::new();
@@ -87,7 +91,10 @@ async fn resolve_one(
MacTok::Ph(_) | MacTok::Slot => panic!("Forbidden element in value mactree"), MacTok::Ph(_) | MacTok::Slot => panic!("Forbidden element in value mactree"),
MacTok::Bottom(err) => bot(err.clone()), MacTok::Bottom(err) => bot(err.clone()),
MacTok::Value(v) => v.clone().to_gen().await, 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) => { MacTok::Lambda(arg, body) => {
let MacTok::Name(name) = &*arg.tok else { let MacTok::Name(name) = &*arg.tok else {
return bot(mk_errv( return bot(mk_errv(

View File

@@ -182,7 +182,7 @@ mod test {
.await, .await,
]; ];
let matcher = mk_any(&pattern).await.expect("This matcher isn't broken"); 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>| { fun(false, "is_some_body", |sub: TAtom<MatcherAtom>, val: OrcOpt<Expr>| {
exec(async move |mut h| { exec(async move |mut h| {
let Some(sub_val) = val.0 else { return Ok(OrcOpt(None)) }; 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>| { fun(false, "is_none_body", async |val: OrcOpt<Expr>| {
@@ -81,12 +81,12 @@ pub async fn gen_std_macro_lib() -> Vec<GenMember> {
}) })
}]) }])
.rule( .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], [async |[elements]: [_; _]| parse_tpl(elements, Some(mactree!(macros::common::_))).await],
) )
.rule( .rule(
mactreev!(pattern::match_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], [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 mac = own(mac_a).await;
let sub = h let sub = h
.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve; i())), [ .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?; .await?;
subs.push(sub); subs.push(sub);
@@ -146,7 +146,7 @@ fn tuple_matcher_body(
tail: OrcOpt<TAtom<MatcherAtom>>, tail: OrcOpt<TAtom<MatcherAtom>>,
value: HomoTpl<Expr>, value: HomoTpl<Expr>,
) -> impl Future<Output = GExpr> { ) -> 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() { if value.0.len() < children.0.len() {
return Ok(OrcOpt(None)); 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"); .expect("Default macro in global root");
MemKind::Const( MemKind::Const(
Macro(Rc::new(MacroData { Macro(Rc::new(MacroData {
canonical_name: module.suffix([i().i(name).await], &i()).await,
module, module,
prio, prio,
rules: stream(async |mut h| { rules: stream(async |mut h| {

View File

@@ -323,7 +323,7 @@ async fn main() -> io::Result<ExitCode> {
let root = root.add_parsed(&entrypoint, path.clone(), &reporter).await; let root = root.add_parsed(&entrypoint, path.clone(), &reporter).await;
let expr = ExprKind::Const(sym!(usercode::entrypoint; i)).at(prefix_sr.pos()); let expr = ExprKind::Const(sym!(usercode::entrypoint; i)).at(prefix_sr.pos());
let mut xctx = ExecCtx::new(ctx.clone(), logger.clone(), root, expr).await; let mut xctx = ExecCtx::new(ctx.clone(), logger.clone(), root, expr).await;
xctx.set_gas(Some(1000)); xctx.set_gas(Some(10_000));
xctx.execute().await; xctx.execute().await;
match xctx.result() { match xctx.result() {
ExecResult::Value(val) => ExecResult::Value(val) =>

View File

@@ -1,63 +0,0 @@
thread 'main' panicked at /rust/deps\annotate-snippets-0.9.2\src\display_list\from_snippet.rs:275:9:
SourceAnnotation range `(100, 102)` is bigger than source length `100`
stack backtrace:
0: 0x7fffc1edead3 - std::backtrace_rs::backtrace::dbghelp64::trace
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\..\..\backtrace\src\backtrace\dbghelp64.rs:91
1: 0x7fffc1edead3 - std::backtrace_rs::backtrace::trace_unsynchronized
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\..\..\backtrace\src\backtrace\mod.rs:66
2: 0x7fffc1edead3 - std::backtrace::Backtrace::create
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\backtrace.rs:331
3: 0x7fffc1edea1a - std::backtrace::Backtrace::force_capture
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\backtrace.rs:312
4: 0x7fffc350c6bd - core[fb98b8b4feea0183]::slice::sort::unstable::heapsort::heapsort::<((rustc_lint_defs[b054f3c0774bcbdc]::Level, &str), usize), <((rustc_lint_defs[b054f3c0774bcbdc]::Level, &str), usize) as core[fb98b8b4feea0183]::cmp::PartialOrd>::lt>
5: 0x7fffc1efa4ae - alloc::boxed::impl$30::call
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\alloc\src\boxed.rs:2027
6: 0x7fffc1efa4ae - std::panicking::rust_panic_with_hook
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\panicking.rs:836
7: 0x7fffc1efa209 - std::panicking::begin_panic_handler::closure$0
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\panicking.rs:701
8: 0x7fffc1ef78af - std::sys::backtrace::__rust_end_short_backtrace<std::panicking::begin_panic_handler::closure_env$0,never$>
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\sys\backtrace.rs:168
9: 0x7fffc1ef9e0e - std::panicking::begin_panic_handler
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\panicking.rs:692
10: 0x7fffc4ddba91 - core::panicking::panic_fmt
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\core\src\panicking.rs:75
11: 0x7ff6008d1f04 - <unknown>
12: 0x7ff6006c56c5 - <unknown>
13: 0x7fffc1f29a2a - core::fmt::rt::Argument::fmt
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\core\src\fmt\rt.rs:177
14: 0x7fffc1f29a2a - core::fmt::write
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\core\src\fmt\mod.rs:1440
15: 0x7fffc1eea19b - std::io::Write::write_fmt
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\io\mod.rs:1887
16: 0x7fffc1eea19b - std::io::stdio::impl$26::write_fmt
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\io\stdio.rs:1024
17: 0x7fffc1eeade6 - std::io::stdio::impl$25::write_fmt
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\io\stdio.rs:998
18: 0x7fffc1eeade6 - std::io::stdio::print_to
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\io\stdio.rs:1122
19: 0x7fffc1eeade6 - std::io::stdio::_eprint
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\io\stdio.rs:1244
20: 0x7ff6005a494b - <unknown>
21: 0x7ff6005a065d - <unknown>
22: 0x7ff60059c57c - <unknown>
23: 0x7ff60058a246 - <unknown>
24: 0x7ff60058a70c - <unknown>
25: 0x7fffc1edc62c - std::rt::lang_start_internal::closure$1
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\rt.rs:174
26: 0x7fffc1edc62c - std::panicking::try::do_call
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\panicking.rs:584
27: 0x7fffc1edc62c - std::panicking::try
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\panicking.rs:547
28: 0x7fffc1edc62c - std::panic::catch_unwind
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\panic.rs:358
29: 0x7fffc1edc62c - std::rt::lang_start_internal
at /rustc/b1a7dfb91106018f47ed9dc9b27aee1977682868/library\std\src\rt.rs:174
30: 0x7ff6005a5dbc - <unknown>
31: 0x7ff6008e3bd0 - <unknown>
32: 0x7ff8c09a7374 - BaseThreadInitThunk
33: 0x7ff8c167cc91 - RtlUserThreadStart
rustc version: 1.86.0-nightly (b1a7dfb91 2025-01-10)
platform: x86_64-pc-windows-msvc