Correctly halts
This commit is contained in:
@@ -25,11 +25,11 @@ impl AtomData {
|
||||
#[must_use]
|
||||
fn api(self) -> api::Atom {
|
||||
let (owner, drop, data, _display) = self.destructure();
|
||||
api::Atom { data, drop, owner: owner.id() }
|
||||
api::Atom { data: api::AtomData(data), drop, owner: owner.id() }
|
||||
}
|
||||
#[must_use]
|
||||
fn api_ref(&self) -> api::Atom {
|
||||
api::Atom { data: self.data.clone(), drop: self.drop, owner: self.owner.id() }
|
||||
api::Atom { data: api::AtomData(self.data.clone()), drop: self.drop, owner: self.owner.id() }
|
||||
}
|
||||
}
|
||||
impl Drop for AtomData {
|
||||
@@ -97,7 +97,11 @@ impl AtomRepr for AtomHand {
|
||||
async fn from_api(atom: &api::Atom, _: Pos, ctx: &mut Self::Ctx) -> Self {
|
||||
let api::Atom { data, drop, owner } = atom.clone();
|
||||
let sys = ctx.system_inst(owner).await.expect("Dropped system created atom");
|
||||
if let Some(id) = drop { sys.new_atom(data, id).await } else { AtomHand::new(data, sys, drop) }
|
||||
if let Some(id) = drop {
|
||||
sys.new_atom(data.0, id).await
|
||||
} else {
|
||||
AtomHand::new(data.0, sys, drop)
|
||||
}
|
||||
}
|
||||
async fn to_api(&self) -> orchid_api::Atom { self.api_ref() }
|
||||
}
|
||||
|
||||
@@ -89,7 +89,10 @@ impl Expr {
|
||||
},
|
||||
api::ExpressionKind::NewAtom(a) =>
|
||||
ExprKind::Atom(AtomHand::from_api(a, pos.clone(), &mut ctx.ctx.clone()).await),
|
||||
api::ExpressionKind::Slot(tk) => return ctx.exprs.get_expr(*tk).expect("Invalid slot"),
|
||||
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"),
|
||||
api::ExpressionKind::Seq(a, b) => {
|
||||
let (apsb, bpsb) = psb.split();
|
||||
ExprKind::Seq(
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
use bound::Bound;
|
||||
use hashbrown::HashMap;
|
||||
use hashbrown::hash_map::Entry;
|
||||
|
||||
@@ -12,15 +13,29 @@ 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>);
|
||||
impl ExprStore {
|
||||
/// If tracking_parent is false, get_expr can fall back to the parent if none
|
||||
/// is found here.
|
||||
///
|
||||
/// If tracking_parent is true, get_expr can still fall back to the parent,
|
||||
/// but operations on the parent can access the child exprs too until this
|
||||
/// store is dropped.
|
||||
#[must_use]
|
||||
pub fn derive(&self) -> Self {
|
||||
Self(Rc::new(ExprStoreData { exprs: RefCell::default(), parent: Some(self.clone()) }))
|
||||
pub fn derive(&self, tracking_parent: bool) -> Self {
|
||||
Self(Rc::new(ExprStoreData {
|
||||
exprs: RefCell::default(),
|
||||
parent: Some(self.clone()),
|
||||
tracking_parent,
|
||||
}))
|
||||
}
|
||||
pub fn give_expr(&self, expr: Expr) {
|
||||
if self.0.tracking_parent {
|
||||
self.0.parent.as_ref().unwrap().give_expr(expr.clone());
|
||||
}
|
||||
match self.0.exprs.borrow_mut().entry(expr.id()) {
|
||||
Entry::Occupied(mut oe) => oe.get_mut().0 += 1,
|
||||
Entry::Vacant(v) => {
|
||||
@@ -29,8 +44,11 @@ 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);
|
||||
}
|
||||
match self.0.exprs.borrow_mut().entry(ticket) {
|
||||
Entry::Vacant(_) => None,
|
||||
Entry::Vacant(_) => panic!("Attempted to double-take expression"),
|
||||
Entry::Occupied(oe) if oe.get().0 == 1 => Some(oe.remove().1),
|
||||
Entry::Occupied(mut oe) => {
|
||||
oe.get_mut().0 -= 1;
|
||||
@@ -43,6 +61,11 @@ impl ExprStore {
|
||||
(self.0.exprs.borrow().get(&ticket).map(|(_, expr)| expr.clone()))
|
||||
.or_else(|| self.0.parent.as_ref()?.get_expr(ticket))
|
||||
}
|
||||
pub fn iter(&self) -> impl Iterator<Item = (u32, Expr)> {
|
||||
let r = Bound::new(self.clone(), |this| this.0.exprs.borrow());
|
||||
let mut iter = Bound::new(r, |r| r.values());
|
||||
std::iter::from_fn(move || iter.wrapped_mut().next().cloned())
|
||||
}
|
||||
}
|
||||
impl fmt::Display for ExprStore {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
@@ -51,3 +74,19 @@ impl fmt::Display for ExprStore {
|
||||
write!(f, "Store holding {rc} refs to {} exprs", r.len())
|
||||
}
|
||||
}
|
||||
impl Drop for ExprStore {
|
||||
fn drop(&mut self) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ pub struct ReqPair<R: Request>(R, Sender<R::Response>);
|
||||
/// upgrading fails.
|
||||
#[derive(destructure)]
|
||||
pub struct ExtensionData {
|
||||
name: String,
|
||||
ctx: Ctx,
|
||||
reqnot: ReqNot<api::HostMsgSet>,
|
||||
systems: Vec<SystemCtor>,
|
||||
@@ -67,21 +68,29 @@ impl Extension {
|
||||
Ok(Self(Rc::new_cyclic(|weak: &Weak<ExtensionData>| {
|
||||
let init = Rc::new(init);
|
||||
let (exiting_snd, exiting_rcv) = channel::<()>(0);
|
||||
(ctx.spawn)(clone!(init, weak, ctx; Box::pin(async move {
|
||||
let rcv_stream = stream(async |mut cx| loop { cx.emit( init.recv().await).await });
|
||||
let mut event_stream = pin!(stream::select(exiting_rcv.map(|()| None), rcv_stream));
|
||||
while let Some(Some(msg)) = event_stream.next().await {
|
||||
if let Some(reqnot) = weak.upgrade().map(|rc| rc.reqnot.clone()) {
|
||||
let reqnot = reqnot.clone();
|
||||
(ctx.spawn)(Box::pin(async move {
|
||||
reqnot.receive(&msg).await;
|
||||
}))
|
||||
(ctx.spawn)({
|
||||
clone!(init, weak, ctx);
|
||||
Box::pin(async move {
|
||||
let rcv_stream = stream(async |mut cx| {
|
||||
loop {
|
||||
cx.emit(init.recv().await).await
|
||||
}
|
||||
});
|
||||
let mut event_stream = pin!(stream::select(exiting_rcv.map(|()| None), rcv_stream));
|
||||
while let Some(Some(msg)) = event_stream.next().await {
|
||||
if let Some(reqnot) = weak.upgrade().map(|rc| rc.reqnot.clone()) {
|
||||
let reqnot = reqnot.clone();
|
||||
(ctx.spawn)(Box::pin(async move {
|
||||
reqnot.receive(&msg).await;
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
})));
|
||||
})
|
||||
});
|
||||
ExtensionData {
|
||||
name: init.name.clone(),
|
||||
exiting_snd,
|
||||
exprs: ctx.common_exprs.derive(),
|
||||
exprs: ctx.common_exprs.derive(false),
|
||||
ctx: ctx.clone(),
|
||||
systems: (init.systems.iter().cloned())
|
||||
.map(|decl| SystemCtor { decl, ext: WeakExtension(weak.clone()) })
|
||||
@@ -95,17 +104,26 @@ impl Extension {
|
||||
clone!(weak; move |notif, _| {
|
||||
clone!(weak; Box::pin(async move {
|
||||
let this = Extension(weak.upgrade().unwrap());
|
||||
if !matches!(notif, api::ExtHostNotif::Log(_)) {
|
||||
writeln!(this.reqnot().logger(), "Host received notif {notif:?}");
|
||||
}
|
||||
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)
|
||||
}
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => {
|
||||
this.assert_own_sys(rel.0).await;
|
||||
this.0.exprs.take_expr(rel.1);
|
||||
if this.is_own_sys(rel.0).await {
|
||||
this.0.exprs.take_expr(rel.1);
|
||||
} else {
|
||||
writeln!(this.reqnot().logger(), "Not our system {:?}", rel.0)
|
||||
}
|
||||
}
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Move(mov)) => {
|
||||
this.assert_own_sys(mov.dec).await;
|
||||
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);
|
||||
@@ -120,7 +138,9 @@ impl Extension {
|
||||
clone!(weak, ctx);
|
||||
Box::pin(async move {
|
||||
let this = Self(weak.upgrade().unwrap());
|
||||
writeln!(this.reqnot().logger(), "Host received request {req:?}");
|
||||
if !matches!(req, api::ExtHostReq::ExtAtomPrint(_)) {
|
||||
writeln!(this.reqnot().logger(), "Host received request {req:?}");
|
||||
}
|
||||
let i = this.ctx().i.clone();
|
||||
match req {
|
||||
api::ExtHostReq::Ping(ping) => hand.handle(&ping, &()).await,
|
||||
@@ -235,8 +255,9 @@ impl Extension {
|
||||
}
|
||||
})))
|
||||
}
|
||||
pub fn name(&self) -> &String { &self.0.name }
|
||||
#[must_use]
|
||||
pub(crate) fn reqnot(&self) -> &ReqNot<api::HostMsgSet> { &self.0.reqnot }
|
||||
pub fn reqnot(&self) -> &ReqNot<api::HostMsgSet> { &self.0.reqnot }
|
||||
#[must_use]
|
||||
pub fn ctx(&self) -> &Ctx { &self.0.ctx }
|
||||
#[must_use]
|
||||
@@ -246,12 +267,12 @@ impl Extension {
|
||||
pub fn exprs(&self) -> &ExprStore { &self.0.exprs }
|
||||
#[must_use]
|
||||
pub async fn is_own_sys(&self, id: api::SysId) -> bool {
|
||||
let sys = self.ctx().system_inst(id).await.expect("invalid sender sys id");
|
||||
let Some(sys) = self.ctx().system_inst(id).await else {
|
||||
writeln!(self.logger(), "Invalid system ID {id:?}");
|
||||
return false;
|
||||
};
|
||||
Rc::ptr_eq(&self.0, &sys.ext().0)
|
||||
}
|
||||
pub async fn assert_own_sys(&self, id: api::SysId) {
|
||||
assert!(self.is_own_sys(id).await, "Incoming message impersonates separate system");
|
||||
}
|
||||
#[must_use]
|
||||
pub fn next_pars(&self) -> NonZeroU64 {
|
||||
let mut next_pars = self.0.next_pars.borrow_mut();
|
||||
@@ -293,7 +314,7 @@ impl Extension {
|
||||
pub fn system_drop(&self, id: api::SysId) {
|
||||
let rc = self.clone();
|
||||
(self.ctx().spawn)(Box::pin(async move {
|
||||
rc.reqnot().notify(api::SystemDrop(id)).await;
|
||||
rc.reqnot().request(api::SystemDrop(id)).await;
|
||||
rc.ctx().systems.write().await.remove(&id);
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -2,16 +2,19 @@ use std::rc::Rc;
|
||||
|
||||
use futures::FutureExt;
|
||||
use futures::lock::Mutex;
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::{OrcErrv, OrcRes, mk_errv};
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::location::SrcRange;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::parse::{name_char, name_start, op_char, unrep_space};
|
||||
use orchid_base::tokens::PARENS;
|
||||
use orchid_base::tree::recur;
|
||||
|
||||
use crate::api;
|
||||
use crate::ctx::Ctx;
|
||||
use crate::expr::{Expr, ExprParseCtx};
|
||||
use crate::expr_store::ExprStore;
|
||||
use crate::parsed::{ParsTok, ParsTokTree, tt_to_api};
|
||||
use crate::system::System;
|
||||
|
||||
@@ -52,14 +55,14 @@ impl<'a> LexCtx<'a> {
|
||||
false
|
||||
}
|
||||
#[must_use]
|
||||
pub async fn ser_subtree(&mut self, subtree: ParsTokTree) -> api::TokenTree {
|
||||
tt_to_api(&mut self.ctx.common_exprs.clone(), subtree).await
|
||||
pub async fn ser_subtree(&mut self, subtree: ParsTokTree, exprs: ExprStore) -> api::TokenTree {
|
||||
tt_to_api(&mut { exprs }, subtree).await
|
||||
}
|
||||
#[must_use]
|
||||
pub async fn des_subtree(&mut self, tree: &api::TokenTree) -> ParsTokTree {
|
||||
pub async fn des_subtree(&mut self, tree: &api::TokenTree, exprs: ExprStore) -> ParsTokTree {
|
||||
ParsTokTree::from_api(
|
||||
tree,
|
||||
&mut self.ctx.common_exprs.clone(),
|
||||
&mut { exprs },
|
||||
&mut ExprParseCtx { ctx: self.ctx, exprs: &self.ctx.common_exprs },
|
||||
self.path,
|
||||
&self.ctx.i,
|
||||
@@ -145,15 +148,23 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
|
||||
let (source, pos, path) = (ctx.source.clone(), ctx.get_pos(), ctx.path.clone());
|
||||
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| async move {
|
||||
let mut ctx_g = ctx_lck.lock().await;
|
||||
match lex_once(&mut ctx_g.push(pos)).boxed_local().await {
|
||||
Ok(t) => Some(api::SubLexed { pos: t.sr.end(), tree: ctx_g.ser_subtree(t).await }),
|
||||
Err(e) => {
|
||||
errors_lck.lock().await.push(e);
|
||||
None
|
||||
},
|
||||
.lex(source, path, pos, |pos| {
|
||||
clone!(temp_store_cb);
|
||||
async move {
|
||||
let mut ctx_g = ctx_lck.lock().await;
|
||||
match lex_once(&mut ctx_g.push(pos)).boxed_local().await {
|
||||
Ok(t) => Some(api::SubLexed {
|
||||
pos: t.sr.end(),
|
||||
tree: ctx_g.ser_subtree(t, temp_store_cb.clone()).await,
|
||||
}),
|
||||
Err(e) => {
|
||||
errors_lck.lock().await.push(e);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
.await;
|
||||
@@ -164,7 +175,14 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
|
||||
),
|
||||
Ok(Some(lexed)) => {
|
||||
ctx.set_pos(lexed.pos);
|
||||
return Ok(ctx.des_subtree(&lexed.expr).await);
|
||||
let lexed_tree = ctx.des_subtree(&lexed.expr, temp_store).await;
|
||||
let stable_tree = recur(lexed_tree, &|tt, r| {
|
||||
if let ParsTok::NewExpr(expr) = tt.tok {
|
||||
return ParsTok::Handle(expr).at(tt.sr);
|
||||
}
|
||||
r(tt)
|
||||
});
|
||||
return Ok(stable_tree);
|
||||
},
|
||||
Ok(None) => match errors.into_iter().reduce(|a, b| a + b) {
|
||||
Some(errors) => return Err(errors),
|
||||
|
||||
@@ -113,7 +113,6 @@ pub enum ParsedMemberKind {
|
||||
impl From<ParsedModule> for ParsedMemberKind {
|
||||
fn from(value: ParsedModule) -> Self { Self::Mod(value) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ParsedModule {
|
||||
pub exports: Vec<Tok<String>>,
|
||||
|
||||
@@ -35,12 +35,11 @@ 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 src_path = line.first().expect("cannot be empty").sr.path();
|
||||
let line = join_all(
|
||||
(line.into_iter())
|
||||
.map(|t| async { tt_to_api(&mut self.system.ext().exprs().clone(), t).await }),
|
||||
)
|
||||
.await;
|
||||
let line =
|
||||
join_all((line.into_iter()).map(|t| async { tt_to_api(&mut temp_store.clone(), t).await }))
|
||||
.await;
|
||||
let mod_path = ctx.src_path().suffix(path.unreverse(), self.system.i()).await;
|
||||
let comments = comments.iter().map(Comment::to_api).collect_vec();
|
||||
let req = api::ParseLine {
|
||||
@@ -53,18 +52,16 @@ impl Parser {
|
||||
line,
|
||||
};
|
||||
match self.system.reqnot().request(req).await {
|
||||
Ok(parsed_v) => {
|
||||
let mut ext_exprs = self.system.ext().exprs().clone();
|
||||
Ok(parsed_v) =>
|
||||
conv(parsed_v, path, callback, &mut ConvCtx {
|
||||
i: self.system.i(),
|
||||
mod_path: &mod_path,
|
||||
ext_exprs: &mut ext_exprs,
|
||||
ext_exprs: &mut temp_store,
|
||||
pctx: &mut ExprParseCtx { ctx: self.system.ctx(), exprs: self.system.ext().exprs() },
|
||||
src_path: &src_path,
|
||||
sys: &self.system,
|
||||
})
|
||||
.await
|
||||
},
|
||||
.await,
|
||||
Err(e) => Err(OrcErrv::from_api(&e, &self.system.ctx().i).await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,10 @@ impl fmt::Debug for SystemInstData {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct System(pub(crate) Rc<SystemInstData>);
|
||||
impl System {
|
||||
#[must_use]
|
||||
pub async fn atoms(&self) -> impl std::ops::Deref<Target = HashMap<api::AtomId, WeakAtomHand>> {
|
||||
self.0.owned_atoms.read().await
|
||||
}
|
||||
#[must_use]
|
||||
pub fn id(&self) -> api::SysId { self.0.id }
|
||||
#[must_use]
|
||||
@@ -118,14 +122,17 @@ impl System {
|
||||
owned_g.insert(id, new.downgrade());
|
||||
new
|
||||
}
|
||||
pub(crate) fn drop_atom(&self, drop: api::AtomId) {
|
||||
pub(crate) fn drop_atom(&self, dropped_atom_id: api::AtomId) {
|
||||
let this = self.0.clone();
|
||||
(self.0.ctx.spawn)(Box::pin(async move {
|
||||
this.owned_atoms.write().await.remove(&drop);
|
||||
this.ext.reqnot().request(api::AtomDrop(this.id, dropped_atom_id)).await;
|
||||
this.owned_atoms.write().await.remove(&dropped_atom_id);
|
||||
}))
|
||||
}
|
||||
#[must_use]
|
||||
pub fn downgrade(&self) -> WeakSystem { WeakSystem(Rc::downgrade(&self.0)) }
|
||||
pub fn downgrade(&self) -> WeakSystem {
|
||||
WeakSystem(Rc::downgrade(&self.0), self.0.decl_id, self.ext().downgrade())
|
||||
}
|
||||
/// Implementation of [api::ResolveNames]
|
||||
pub(crate) async fn name_resolver(
|
||||
&self,
|
||||
@@ -174,10 +181,14 @@ impl Format for System {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WeakSystem(Weak<SystemInstData>);
|
||||
pub struct WeakSystem(Weak<SystemInstData>, api::SysDeclId, WeakExtension);
|
||||
impl WeakSystem {
|
||||
#[must_use]
|
||||
pub fn upgrade(&self) -> Option<System> { self.0.upgrade().map(System) }
|
||||
pub fn ext(&self) -> Option<Extension> { self.2.upgrade() }
|
||||
pub fn ctor(&self) -> Option<SystemCtor> {
|
||||
self.ext()?.system_ctors().find(|ctor| ctor.decl.id == self.1).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -6,6 +6,7 @@ use std::slice;
|
||||
|
||||
use async_lock::RwLock;
|
||||
use async_once_cell::OnceCell;
|
||||
use derive_destructure::destructure;
|
||||
use futures::{FutureExt, StreamExt, stream};
|
||||
use hashbrown::HashMap;
|
||||
use hashbrown::hash_map::Entry;
|
||||
@@ -88,7 +89,7 @@ impl Root {
|
||||
*this.ctx.root.write().await = new.downgrade();
|
||||
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 { id: pc_id, sys: sys.id() }).await;
|
||||
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;
|
||||
new.0.write().await.consts.insert(path, expr);
|
||||
@@ -450,6 +451,7 @@ impl MemberKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(destructure)]
|
||||
pub struct LazyMemberHandle {
|
||||
id: api::TreeId,
|
||||
sys: api::SysId,
|
||||
@@ -457,19 +459,26 @@ pub struct LazyMemberHandle {
|
||||
}
|
||||
impl LazyMemberHandle {
|
||||
#[must_use]
|
||||
pub async fn run(self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> MemberKind {
|
||||
pub async fn run(mut self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> MemberKind {
|
||||
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;
|
||||
consts.insert(self.path, expr);
|
||||
let (.., path) = self.destructure();
|
||||
consts.insert(path, expr);
|
||||
MemberKind::Const
|
||||
},
|
||||
api::MemberKind::Module(m) => MemberKind::Module(
|
||||
Module::from_api(m, &mut TreeFromApiCtx { sys: &sys, consts, path: self.path.tok() }).await,
|
||||
),
|
||||
api::MemberKind::Lazy(id) => Self { id, ..self }.run(ctx, consts).boxed_local().await,
|
||||
api::MemberKind::Module(m) => {
|
||||
let (.., path) = self.destructure();
|
||||
MemberKind::Module(
|
||||
Module::from_api(m, &mut TreeFromApiCtx { sys: &sys, consts, path: path.tok() }).await,
|
||||
)
|
||||
},
|
||||
api::MemberKind::Lazy(id) => {
|
||||
self.id = id;
|
||||
self.run(ctx, consts).boxed_local().await
|
||||
},
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
Reference in New Issue
Block a user