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

@@ -10,7 +10,7 @@ use orchid_base::tree::AtomRepr;
use crate::api;
use crate::ctx::Ctx;
use crate::expr::{Expr, ExprParseCtx, PathSetBuilder};
use crate::expr::{Expr, PathSetBuilder};
use crate::extension::Extension;
use crate::system::System;
@@ -58,15 +58,15 @@ impl AtomHand {
#[must_use]
pub async fn call(self, arg: Expr) -> Expr {
let owner_sys = self.0.owner.clone();
let ctx = owner_sys.ctx();
let reqnot = owner_sys.reqnot();
owner_sys.ext().exprs().give_expr(arg.clone());
ctx.exprs.give_expr(arg.clone());
let ret = match Rc::try_unwrap(self.0) {
Ok(data) => reqnot.request(api::FinalCall(data.api(), arg.id())).await,
Err(hand) => reqnot.request(api::CallRef(hand.api_ref(), arg.id())).await,
};
let mut parse_ctx = ExprParseCtx { ctx: owner_sys.ctx(), exprs: owner_sys.ext().exprs() };
let val = Expr::from_api(&ret, PathSetBuilder::new(), &mut parse_ctx).await;
owner_sys.ext().exprs().take_expr(arg.id());
let val = Expr::from_api(&ret, PathSetBuilder::new(), ctx.clone()).await;
ctx.exprs.take_expr(arg.id());
val
}
#[must_use]

View File

@@ -18,7 +18,7 @@ pub struct CtxData {
pub spawn: Spawner,
pub systems: RwLock<HashMap<api::SysId, WeakSystem>>,
pub system_id: RefCell<NonZeroU16>,
pub common_exprs: ExprStore,
pub exprs: ExprStore,
pub root: RwLock<WeakRoot>,
}
#[derive(Clone)]
@@ -43,7 +43,7 @@ impl Ctx {
i: Interner::default(),
systems: RwLock::default(),
system_id: RefCell::new(NonZero::new(1).unwrap()),
common_exprs: ExprStore::default(),
exprs: ExprStore::default(),
root: RwLock::default(),
}))
}

View File

@@ -21,12 +21,6 @@ use crate::atom::AtomHand;
use crate::ctx::Ctx;
use crate::expr_store::ExprStore;
#[derive(Clone)]
pub struct ExprParseCtx<'a> {
pub ctx: &'a Ctx,
pub exprs: &'a ExprStore,
}
#[derive(Debug)]
pub struct ExprData {
pos: Pos,
@@ -61,42 +55,34 @@ impl Expr {
)
}
#[must_use]
pub async fn from_api(
api: &api::Expression,
psb: PathSetBuilder<'_, u64>,
ctx: &mut ExprParseCtx<'_>,
) -> Self {
let pos = Pos::from_api(&api.location, &ctx.ctx.i).await;
pub async fn from_api(api: &api::Expression, psb: PathSetBuilder<'_, u64>, ctx: Ctx) -> Self {
let pos = Pos::from_api(&api.location, &ctx.i).await;
let kind = match &api.kind {
api::ExpressionKind::Arg(n) => {
assert!(psb.register_arg(n), "Arguments must be enclosed in a matching lambda");
ExprKind::Arg
},
api::ExpressionKind::Bottom(bot) =>
ExprKind::Bottom(OrcErrv::from_api(bot, &ctx.ctx.i).await),
api::ExpressionKind::Bottom(bot) => ExprKind::Bottom(OrcErrv::from_api(bot, &ctx.i).await),
api::ExpressionKind::Call(f, x) => {
let (lpsb, rpsb) = psb.split();
ExprKind::Call(
Expr::from_api(f, lpsb, ctx).boxed_local().await,
Expr::from_api(f, lpsb, ctx.clone()).boxed_local().await,
Expr::from_api(x, rpsb, ctx).boxed_local().await,
)
},
api::ExpressionKind::Const(name) => ExprKind::Const(Sym::from_api(*name, &ctx.ctx.i).await),
api::ExpressionKind::Const(name) => ExprKind::Const(Sym::from_api(*name, &ctx.i).await),
api::ExpressionKind::Lambda(x, body) => {
let lbuilder = psb.lambda(x);
let body = Expr::from_api(body, lbuilder.stack(), ctx).boxed_local().await;
ExprKind::Lambda(lbuilder.collect(), body)
},
api::ExpressionKind::NewAtom(a) =>
ExprKind::Atom(AtomHand::from_api(a, pos.clone(), &mut ctx.ctx.clone()).await),
api::ExpressionKind::Slot { tk, by_value: false } =>
return ctx.exprs.get_expr(*tk).expect("Invalid slot"),
api::ExpressionKind::Slot { tk, by_value: true } =>
return ctx.exprs.take_expr(*tk).expect("Invalid slot"),
ExprKind::Atom(AtomHand::from_api(a, pos.clone(), &mut ctx.clone()).await),
api::ExpressionKind::Slot(tk) => return ctx.exprs.take_expr(*tk).expect("Invalid slot"),
api::ExpressionKind::Seq(a, b) => {
let (apsb, bpsb) = psb.split();
ExprKind::Seq(
Expr::from_api(a, apsb, ctx).boxed_local().await,
Expr::from_api(a, apsb, ctx.clone()).boxed_local().await,
Expr::from_api(b, bpsb, ctx).boxed_local().await,
)
},
@@ -169,8 +155,8 @@ async fn print_exprkind<'a>(
ExprKind::Bottom(e) if e.len() == 1 => format!("Bottom({e})").into(),
ExprKind::Bottom(e) => format!("Bottom(\n\t{}\n)", indent(&e.to_string())).into(),
ExprKind::Call(f, x) => tl_cache!(Rc<Variants>: Rc::new(Variants::default()
.unbounded("{0} {1l}")
.bounded("({0} {1b})")))
.unbounded("{0b} {1l}")
.bounded("({0b} {1})")))
.units([print_expr(f, c, visited).await, print_expr(x, c, visited).await]),
ExprKind::Identity(id) =>
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("{{{0}}}"))).units([print_expr(
@@ -180,11 +166,11 @@ async fn print_exprkind<'a>(
.await]),
ExprKind::Const(c) => format!("{c}").into(),
ExprKind::Lambda(None, body) => tl_cache!(Rc<Variants>: Rc::new(Variants::default()
.unbounded("\\.{0l}")
// .unbounded("\\.{0l}")
.bounded("(\\.{0b})")))
.units([print_expr(body, c, visited).await]),
ExprKind::Lambda(Some(path), body) => tl_cache!(Rc<Variants>: Rc::new(Variants::default()
.unbounded("\\{0b}. {1l}")
// .unbounded("\\{0b}. {1l}")
.bounded("(\\{0b}. {1b})")))
.units([format!("{path}").into(), print_expr(body, c, visited).await]),
ExprKind::Seq(l, r) =>
@@ -361,14 +347,14 @@ impl TokenVariant<api::ExprTicket> for Expr {
pub struct ExprWillPanic;
impl TokenVariant<api::Expression> for Expr {
type FromApiCtx<'a> = ExprParseCtx<'a>;
type FromApiCtx<'a> = Ctx;
async fn from_api(
api: &api::Expression,
ctx: &mut Self::FromApiCtx<'_>,
_: SrcRange,
_: &Interner,
) -> Self {
Self::from_api(api, PathSetBuilder::new(), ctx).await
Self::from_api(api, PathSetBuilder::new(), ctx.clone()).await
}
type ToApiCtx<'a> = ExprWillPanic;
async fn into_api(self, ExprWillPanic: &mut Self::ToApiCtx<'_>) -> api::Expression {

View File

@@ -13,7 +13,6 @@ use crate::expr::Expr;
pub struct ExprStoreData {
exprs: RefCell<HashMap<api::ExprTicket, (u32, Expr)>>,
parent: Option<ExprStore>,
tracking_parent: bool,
}
#[derive(Clone, Default)]
pub struct ExprStore(Rc<ExprStoreData>);
@@ -25,16 +24,12 @@ impl ExprStore {
/// but operations on the parent can access the child exprs too until this
/// store is dropped.
#[must_use]
pub fn derive(&self, tracking_parent: bool) -> Self {
Self(Rc::new(ExprStoreData {
exprs: RefCell::default(),
parent: Some(self.clone()),
tracking_parent,
}))
pub fn derive(&self) -> Self {
Self(Rc::new(ExprStoreData { exprs: RefCell::default(), parent: Some(self.clone()) }))
}
pub fn give_expr(&self, expr: Expr) {
if self.0.tracking_parent {
self.0.parent.as_ref().unwrap().give_expr(expr.clone());
if let Some(parent) = self.0.parent.as_ref() {
parent.give_expr(expr.clone())
}
match self.0.exprs.borrow_mut().entry(expr.id()) {
Entry::Occupied(mut oe) => oe.get_mut().0 += 1,
@@ -44,8 +39,8 @@ impl ExprStore {
}
}
pub fn take_expr(&self, ticket: api::ExprTicket) -> Option<Expr> {
if self.0.tracking_parent {
self.0.parent.as_ref().unwrap().take_expr(ticket);
if let Some(parent) = self.0.parent.as_ref() {
parent.take_expr(ticket);
}
match self.0.exprs.borrow_mut().entry(ticket) {
Entry::Vacant(_) => panic!("Attempted to double-take expression"),
@@ -79,13 +74,11 @@ impl Drop for ExprStore {
if 1 < Rc::strong_count(&self.0) {
return;
}
if !self.0.tracking_parent {
return;
}
let parent = self.0.parent.as_ref().unwrap();
for (id, (count, _)) in self.0.exprs.borrow().iter() {
for _ in 0..*count {
parent.take_expr(*id);
if let Some(parent) = self.0.parent.as_ref() {
for (id, (count, _)) in self.0.exprs.borrow().iter() {
for _ in 0..*count {
parent.take_expr(*id);
}
}
}
}

View File

@@ -28,8 +28,7 @@ use crate::api;
use crate::atom::AtomHand;
use crate::ctx::Ctx;
use crate::dealias::{ChildError, ChildErrorKind, walk};
use crate::expr::ExprKind;
use crate::expr_store::ExprStore;
use crate::expr::{Expr, PathSetBuilder};
use crate::system::SystemCtor;
use crate::tree::MemberKind;
@@ -47,7 +46,6 @@ pub struct ExtensionData {
systems: Vec<SystemCtor>,
logger: Logger,
next_pars: RefCell<NonZeroU64>,
exprs: ExprStore,
exiting_snd: Sender<()>,
lex_recur: Mutex<HashMap<api::ParsId, Sender<ReqPair<api::SubLex>>>>,
}
@@ -92,7 +90,6 @@ impl Extension {
ExtensionData {
name: init.name.clone(),
exiting_snd,
exprs: ctx.common_exprs.derive(false),
ctx: ctx.clone(),
systems: (init.systems.iter().cloned())
.map(|decl| SystemCtor { decl, ext: WeakExtension(weak.clone()) })
@@ -111,25 +108,15 @@ impl Extension {
}
match notif {
api::ExtHostNotif::ExprNotif(api::ExprNotif::Acquire(acq)) => {
let target = this.0.exprs.get_expr(acq.1).expect("Invalid ticket");
this.0.exprs.give_expr(target)
let target = this.0.ctx.exprs.get_expr(acq.1).expect("Invalid ticket");
this.0.ctx.exprs.give_expr(target)
}
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => {
if this.is_own_sys(rel.0).await {
this.0.exprs.take_expr(rel.1);
this.0.ctx.exprs.take_expr(rel.1);
} else {
writeln!(this.reqnot().logger(), "Not our system {:?}", rel.0)
}
}
api::ExtHostNotif::ExprNotif(api::ExprNotif::Move(mov)) => {
if !this.is_own_sys(mov.dec).await {
writeln!(this.reqnot().logger(), "Not our system {:?}", mov.dec);
return;
}
let recp = this.ctx().system_inst(mov.inc).await.expect("invallid recipient sys id");
let expr = this.0.exprs.get_expr(mov.expr).expect("invalid ticket");
recp.ext().0.exprs.give_expr(expr);
this.0.exprs.take_expr(mov.expr);
},
api::ExtHostNotif::Log(api::Log(str)) => this.logger().log(str),
}
@@ -180,17 +167,23 @@ impl Extension {
}
hand.handle(&sl, &rep_out.next().await.unwrap()).await
},
api::ExtHostReq::ExprReq(api::ExprReq::Inspect(
ins @ api::Inspect { target },
)) => {
let expr = this.exprs().get_expr(target).expect("Invalid ticket");
hand
.handle(&ins, &api::Inspected {
refcount: expr.strong_count() as u32,
location: expr.pos().to_api(),
kind: expr.to_api().await,
})
.await
api::ExtHostReq::ExprReq(expr_req) => match expr_req {
api::ExprReq::Inspect(ins @ api::Inspect { target }) => {
let expr = ctx.exprs.get_expr(target).expect("Invalid ticket");
hand
.handle(&ins, &api::Inspected {
refcount: expr.strong_count() as u32,
location: expr.pos().to_api(),
kind: expr.to_api().await,
})
.await
},
api::ExprReq::Create(ref cre @ api::Create(ref expr)) => {
let expr = Expr::from_api(expr, PathSetBuilder::new(), ctx.clone()).await;
let expr_id = expr.id();
ctx.exprs.give_expr(expr);
hand.handle(cre, &expr_id).await
},
},
api::ExtHostReq::LsModule(ref ls @ api::LsModule(_sys, path)) => {
let reply: <api::LsModule as Request>::Response = 'reply: {
@@ -249,13 +242,6 @@ impl Extension {
let unit = atom.print(&FmtCtxImpl { i: &this.ctx().i }).await;
hand.handle(eap, &unit.to_api()).await
},
api::ExtHostReq::CreateAtom(ref create @ api::CreateAtom(ref atom, target)) => {
let atom = AtomHand::from_api(atom, Pos::None, &mut ctx.clone()).await;
let target = ctx.system_inst(target).await.expect("Invalid recipient for atom");
let expr = ExprKind::Atom(atom).at(Pos::None);
target.ext().exprs().give_expr(expr.clone());
hand.handle(create, &expr.id()).await
},
}
})
}
@@ -273,8 +259,6 @@ impl Extension {
pub fn logger(&self) -> &Logger { &self.0.logger }
pub fn system_ctors(&self) -> impl Iterator<Item = &SystemCtor> { self.0.systems.iter() }
#[must_use]
pub fn exprs(&self) -> &ExprStore { &self.0.exprs }
#[must_use]
pub async fn is_own_sys(&self, id: api::SysId) -> bool {
let Some(sys) = self.ctx().system_inst(id).await else {
writeln!(self.logger(), "Invalid system ID {id:?}");

View File

@@ -13,7 +13,7 @@ use orchid_base::tree::recur;
use crate::api;
use crate::ctx::Ctx;
use crate::expr::{Expr, ExprParseCtx};
use crate::expr::Expr;
use crate::expr_store::ExprStore;
use crate::parsed::{ParsTok, ParsTokTree, tt_to_api};
use crate::system::System;
@@ -60,14 +60,7 @@ impl<'a> LexCtx<'a> {
}
#[must_use]
pub async fn des_subtree(&mut self, tree: &api::TokenTree, exprs: ExprStore) -> ParsTokTree {
ParsTokTree::from_api(
tree,
&mut { exprs },
&mut ExprParseCtx { ctx: self.ctx, exprs: &self.ctx.common_exprs },
self.path,
&self.ctx.i,
)
.await
ParsTokTree::from_api(tree, &mut { exprs }, &mut self.ctx.clone(), self.path, &self.ctx.i).await
}
#[must_use]
pub fn strip_char(&mut self, tgt: char) -> bool {
@@ -146,9 +139,9 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
let mut errors = Vec::new();
if ctx.tail.starts_with(|c| sys.can_lex(c)) {
let (source, pos, path) = (ctx.source.clone(), ctx.get_pos(), ctx.path.clone());
let temp_store = ctx.ctx.exprs.derive();
let ctx_lck = &Mutex::new(&mut *ctx);
let errors_lck = &Mutex::new(&mut errors);
let temp_store = sys.ext().exprs().derive(true);
let temp_store_cb = temp_store.clone();
let lx = sys
.lex(source, path, pos, |pos| {

View File

@@ -185,7 +185,7 @@ impl Tree for ParsedModule {
impl Format for ParsedModule {
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
let head_str = format!("export ::({})\n", self.exports.iter().join(", "));
Variants::sequence(self.items.len() + 1, "\n", None).units(
Variants::default().sequence(self.items.len() + 1, "", "\n", "", None).units_own(
[head_str.into()].into_iter().chain(join_all(self.items.iter().map(|i| i.print(c))).await),
)
}

View File

@@ -11,7 +11,6 @@ use orchid_base::tree::ttv_from_api;
use substack::Substack;
use crate::api;
use crate::expr::ExprParseCtx;
use crate::expr_store::ExprStore;
use crate::parse::HostParseCtx;
use crate::parsed::{
@@ -35,7 +34,7 @@ impl Parser {
comments: Vec<Comment>,
callback: &mut impl AsyncFnMut(ModPath<'_>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
) -> OrcRes<Vec<Item>> {
let mut temp_store = self.system.ext().exprs().derive(true);
let mut temp_store = self.system.ctx().exprs.derive();
let src_path = line.first().expect("cannot be empty").sr.path();
let line =
join_all((line.into_iter()).map(|t| async { tt_to_api(&mut temp_store.clone(), t).await }))
@@ -57,7 +56,6 @@ impl Parser {
i: self.system.i(),
mod_path: &mod_path,
ext_exprs: &mut temp_store,
pctx: &mut ExprParseCtx { ctx: self.system.ctx(), exprs: self.system.ext().exprs() },
src_path: &src_path,
sys: &self.system,
})
@@ -73,7 +71,6 @@ struct ConvCtx<'a> {
src_path: &'a Sym,
i: &'a Interner,
ext_exprs: &'a mut ExprStore,
pctx: &'a mut ExprParseCtx<'a>,
}
async fn conv(
parsed_v: Vec<api::ParsedLine>,
@@ -87,7 +84,8 @@ async fn conv(
api::ParsedLineKind::Member(api::ParsedMember { name, exported, kind }) =>
(name, exported, kind),
api::ParsedLineKind::Recursive(rec) => {
let tokens = ttv_from_api(rec, ctx.ext_exprs, ctx.pctx, ctx.src_path, ctx.i).await;
let tokens =
ttv_from_api(rec, ctx.ext_exprs, &mut ctx.sys.ctx().clone(), ctx.src_path, ctx.i).await;
items.extend(callback(module.clone(), tokens).await?);
continue;
},

View File

@@ -22,7 +22,7 @@ use orchid_base::reqnot::Requester;
use crate::api;
use crate::ctx::Ctx;
use crate::dealias::{ChildErrorKind, Tree, absolute_path, resolv_glob, walk};
use crate::expr::{Expr, ExprParseCtx, PathSetBuilder};
use crate::expr::{Expr, PathSetBuilder};
use crate::parsed::{ItemKind, ParsedMemberKind, ParsedModule};
use crate::system::System;
@@ -90,8 +90,7 @@ impl Root {
for (path, (sys_id, pc_id)) in deferred_consts {
let sys = this.ctx.system_inst(sys_id).await.expect("System dropped since parsing");
let api_expr = sys.reqnot().request(api::FetchParsedConst(sys.id(), pc_id)).await;
let mut xp_ctx = ExprParseCtx { ctx: &this.ctx, exprs: sys.ext().exprs() };
let expr = Expr::from_api(&api_expr, PathSetBuilder::new(), &mut xp_ctx).await;
let expr = Expr::from_api(&api_expr, PathSetBuilder::new(), this.ctx.clone()).await;
new.0.write().await.consts.insert(path, expr);
}
new
@@ -178,8 +177,7 @@ impl Module {
api::MemberKind::Lazy(id) =>
(Some(LazyMemberHandle { id, sys: ctx.sys.id(), path: name.clone() }), None),
api::MemberKind::Const(val) => {
let mut expr_ctx = ExprParseCtx { ctx: ctx.sys.ctx(), exprs: ctx.sys.ext().exprs() };
let expr = Expr::from_api(&val, PathSetBuilder::new(), &mut expr_ctx).await;
let expr = Expr::from_api(&val, PathSetBuilder::new(), ctx.sys.ctx().clone()).await;
ctx.consts.insert(name.clone(), expr);
(None, Some(MemberKind::Const))
},
@@ -463,8 +461,7 @@ impl LazyMemberHandle {
let sys = ctx.system_inst(self.sys).await.expect("Missing system for lazy member");
match sys.get_tree(self.id).await {
api::MemberKind::Const(c) => {
let mut pctx = ExprParseCtx { ctx: &ctx, exprs: sys.ext().exprs() };
let expr = Expr::from_api(&c, PathSetBuilder::new(), &mut pctx).await;
let expr = Expr::from_api(&c, PathSetBuilder::new(), ctx.clone()).await;
let (.., path) = self.destructure();
consts.insert(path, expr);
MemberKind::Const