partway towards commands

I got very confused and started mucking about with "spawn" when in fact all I needed was the "inline" extension type in orcx that allows the interpreter to expose custom constants.
This commit is contained in:
2026-03-13 16:48:42 +01:00
parent cdcca694c5
commit 09cfcb1839
146 changed files with 3582 additions and 2822 deletions

View File

@@ -1,21 +1,15 @@
use std::collections::VecDeque;
use std::ops::{Add, Range};
use async_fn_stream::stream;
use futures::{FutureExt, StreamExt};
use futures::{FutureExt, StreamExt, stream};
use hashbrown::{HashMap, HashSet};
use itertools::Itertools;
use orchid_base::error::mk_errv;
use orchid_base::format::fmt;
use orchid_base::interner::is;
use orchid_base::location::Pos;
use orchid_base::logging::log;
use orchid_base::name::{NameLike, Sym, VPath};
use orchid_base::tree::Paren;
use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
use orchid_base::{NameLike, Paren, Pos, Sym, VPath, fmt, is, log, mk_errv};
use orchid_extension::TAtom;
use orchid_extension::conv::ToExpr;
use orchid_extension::coroutine_exec::{ExecHandle, exec};
use orchid_extension::gen_expr::{GExpr, arg, bot, call, lambda, new_atom, sym_ref};
use orchid_extension::coroutine_exec::exec;
use orchid_extension::gen_expr::{GExpr, arg, bot, call, call_v, dyn_lambda, new_atom};
use orchid_extension::reflection::{ReflMemKind, refl};
use subslice_offset::SubsliceOffset;
use substack::Substack;
@@ -37,8 +31,8 @@ pub async fn resolve(val: MacTree) -> GExpr {
.to_sym()
.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;
let Ok(mac) = h.exec::<TAtom<Macro>>(new_name).await else { continue };
let mac = mac.own().await;
macros.entry(mac.0.canonical_name.clone()).or_insert(mac);
}
}
@@ -63,7 +57,7 @@ pub async fn resolve(val: MacTree) -> GExpr {
}
}
}
let mut rctx = ResolveCtx { h, exclusive, priod };
let mut rctx = ResolveCtx { exclusive, priod };
let gex = resolve_one(&mut rctx, Substack::Bottom, &val).await;
writeln!(
log("debug"),
@@ -85,7 +79,6 @@ pub struct FilteredMacroRecord<'a> {
}
struct ResolveCtx<'a> {
pub h: ExecHandle<'a>,
/// If these overlap, that's a compile-time error
pub exclusive: Vec<FilteredMacroRecord<'a>>,
/// If these overlap, the priorities decide the order. In case of a tie, the
@@ -104,7 +97,7 @@ async fn resolve_one(
MacTok::Value(v) => v.clone().to_gen().await,
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()),
None => n.clone().to_gen().await,
},
MacTok::Lambda(arg, body) => {
let MacTok::Name(name) = &*arg.tok else {
@@ -116,7 +109,7 @@ async fn resolve_one(
};
let arg_pos = arg_stk.len() as u64;
let arg_stk = arg_stk.push(name.clone());
lambda(arg_pos, [resolve_seq(ctx, arg_stk, body.clone(), value.pos()).await])
dyn_lambda(arg_pos, resolve_seq(ctx, arg_stk, body.clone(), value.pos()).await).await
},
MacTok::S(Paren::Round, body) => resolve_seq(ctx, arg_stk, body.clone(), value.pos()).await,
MacTok::S(..) => bot(mk_errv(
@@ -243,7 +236,7 @@ async fn resolve_seq(
// backwards so that the non-overlapping ranges remain valid
let pos = (state.names().flat_map(|r| r.1).cloned().reduce(Pos::add))
.expect("All macro rules must contain at least one locally defined name");
let subex = ctx.h.register(mk_body_call(mac, rule, &state, pos.clone()).await).await;
let subex = mk_body_call(mac, rule, &state, pos.clone()).await.to_expr().await;
new_val.splice(range, [MacTok::Value(subex).at(pos)]);
}
};
@@ -261,22 +254,23 @@ async fn resolve_seq(
let range = pre.len()..new_val.len() - suf.len();
let pos = (state.names().flat_map(|pair| pair.1).cloned().reduce(Pos::add))
.expect("All macro rules must contain at least one locally defined name");
let subex = ctx.h.register(mk_body_call(mac, rule, &state, pos.clone()).await).await;
let subex = mk_body_call(mac, rule, &state, pos.clone()).await.to_expr().await;
std::mem::drop(state);
new_val.splice(range, [MacTok::Value(subex).at(pos)]);
}
}
let exprs = stream(async |mut h| {
let mut exprs = stream(async |mut h| {
for mt in new_val {
h.emit(resolve_one(ctx, arg_stk.clone(), &mt).await).await
}
})
.collect::<Vec<_>>()
.collect::<VecDeque<_>>()
.boxed_local()
.await;
exprs.into_iter().reduce(|f, x| call(f, [x])).expect(
let first = exprs.pop_front().expect(
"We checked first that it isn't empty, and named macros get replaced with their results",
)
);
stream::iter(exprs).fold(first, async |f, x| call(f, x).await).await
}
async fn mk_body_call(mac: &Macro, rule: &Rule, state: &MatchState<'_>, pos: Pos) -> GExpr {
@@ -288,5 +282,5 @@ async fn mk_body_call(mac: &Macro, rule: &Rule, state: &MatchState<'_>, pos: Pos
new_atom(MacTok::S(Paren::Round, MacTreeSeq::new(vec.iter().cloned())).at(Pos::None)),
});
}
call(sym_ref(mac.0.module.suffix([rule.body.clone()]).await), call_args).at(pos.clone())
call_v(mac.0.module.suffix([rule.body.clone()]).await, call_args).await.at(pos.clone())
}