New macro system and stdlib additions
This commit is contained in:
@@ -29,10 +29,11 @@ use trait_set::trait_set;
|
||||
use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId};
|
||||
use crate::atom_owned::take_atom;
|
||||
use crate::context::{SysCtx, ctx, i, with_ctx};
|
||||
use crate::expr::{BorrowedExprStore, Expr, ExprHandle};
|
||||
use crate::lexer::{LexContext, ekey_cascade, ekey_not_applicable};
|
||||
use crate::parser::{PTokTree, ParsCtx, get_const, linev_into_api};
|
||||
use crate::system::{SysCtx, atom_by_idx};
|
||||
use crate::system::atom_by_idx;
|
||||
use crate::system_ctor::{CtedObj, DynSystemCtor};
|
||||
use crate::tree::{LazyMemberFactory, TreeIntoApiCtxImpl};
|
||||
|
||||
@@ -62,7 +63,6 @@ pub struct SystemRecord {
|
||||
trait_set! {
|
||||
pub trait WithAtomRecordCallback<'a, T> = AsyncFnOnce(
|
||||
Box<dyn AtomDynfo>,
|
||||
SysCtx,
|
||||
AtomTypeId,
|
||||
&'a [u8]
|
||||
) -> T
|
||||
@@ -78,7 +78,7 @@ pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
|
||||
let inst = ctx.get::<CtedObj>().inst();
|
||||
let id = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||
let atom_record = atom_by_idx(inst.card(), id.clone()).expect("Atom ID reserved");
|
||||
cb(atom_record, ctx, id, data).await
|
||||
with_ctx(ctx, async move { cb(atom_record, id, data).await }).await
|
||||
}
|
||||
|
||||
pub struct ExtensionOwner {
|
||||
@@ -157,7 +157,8 @@ pub fn extension_init(
|
||||
clone!(logger, get_ctx, init_ctx, systems_weak, interner_weak, decls, msg_logger);
|
||||
async move {
|
||||
let interner_cell = interner_weak.upgrade().expect("Interner dropped before request");
|
||||
let i = interner_cell.borrow().clone().expect("Request arrived before interner set");
|
||||
let interner =
|
||||
interner_cell.borrow().clone().expect("Request arrived before interner set");
|
||||
if !matches!(req, api::HostExtReq::AtomReq(api::AtomReq::AtomPrint(_))) {
|
||||
writeln!(msg_logger, "{} extension received request {req:?}", data.name);
|
||||
}
|
||||
@@ -169,153 +170,156 @@ pub fn extension_init(
|
||||
}
|
||||
hand.handle(&sys_drop, &()).await
|
||||
},
|
||||
api::HostExtReq::AtomDrop(atom_drop @ api::AtomDrop(sys_id, atom)) => {
|
||||
let ctx = get_ctx(sys_id).await;
|
||||
take_atom(atom, &ctx).await.dyn_free(ctx.clone()).await;
|
||||
hand.handle(&atom_drop, &()).await
|
||||
},
|
||||
api::HostExtReq::AtomDrop(atom_drop @ api::AtomDrop(sys_id, atom)) =>
|
||||
with_ctx(get_ctx(sys_id).await, async move {
|
||||
take_atom(atom).await.dyn_free().await;
|
||||
hand.handle(&atom_drop, &()).await
|
||||
})
|
||||
.await,
|
||||
api::HostExtReq::Ping(ping @ api::Ping) => hand.handle(&ping, &()).await,
|
||||
api::HostExtReq::Sweep(sweep @ api::Sweep) =>
|
||||
hand.handle(&sweep, &i.sweep_replica().await).await,
|
||||
hand.handle(&sweep, &interner.sweep_replica().await).await,
|
||||
api::HostExtReq::SysReq(api::SysReq::NewSystem(new_sys)) => {
|
||||
let (sys_id, _) = (decls.iter().enumerate().find(|(_, s)| s.id == new_sys.system))
|
||||
.expect("NewSystem call received for invalid system");
|
||||
let cted = data.systems[sys_id].new_system(&new_sys);
|
||||
let lex_filter =
|
||||
cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf, lx| {
|
||||
char_filter_union(&cf, &mk_char_filter(lx.char_filter().iter().cloned()))
|
||||
});
|
||||
let lazy_members = Mutex::new(HashMap::new());
|
||||
let ctx = init_ctx(new_sys.id, cted.clone(), hand.reqnot()).await;
|
||||
let const_root = stream::iter(cted.inst().dyn_env())
|
||||
.then(|mem| {
|
||||
let lazy_mems = &lazy_members;
|
||||
clone!(i, ctx; async move {
|
||||
let name = i.i(&mem.name).await;
|
||||
let mut tia_ctx = TreeIntoApiCtxImpl {
|
||||
lazy_members: &mut *lazy_mems.lock().await,
|
||||
sys: ctx,
|
||||
basepath: &[],
|
||||
path: Substack::Bottom.push(name.clone()),
|
||||
};
|
||||
(name.to_api(), mem.kind.into_api(&mut tia_ctx).await)
|
||||
with_ctx(init_ctx(new_sys.id, cted.clone(), hand.reqnot()).await, async move {
|
||||
let lex_filter =
|
||||
cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf, lx| {
|
||||
char_filter_union(&cf, &mk_char_filter(lx.char_filter().iter().cloned()))
|
||||
});
|
||||
let lazy_members = Mutex::new(HashMap::new());
|
||||
let const_root = stream::iter(cted.inst().dyn_env().await)
|
||||
.then(|mem| {
|
||||
let lazy_mems = &lazy_members;
|
||||
async move {
|
||||
let name = i().i(&mem.name).await;
|
||||
let mut tia_ctx = TreeIntoApiCtxImpl {
|
||||
lazy_members: &mut *lazy_mems.lock().await,
|
||||
basepath: &[],
|
||||
path: Substack::Bottom.push(name.clone()),
|
||||
};
|
||||
(name.to_api(), mem.kind.into_api(&mut tia_ctx).await)
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
.collect()
|
||||
.await;
|
||||
let prelude =
|
||||
cted.inst().dyn_prelude().await.iter().map(|sym| sym.to_api()).collect();
|
||||
let record = SystemRecord { ctx: ctx(), lazy_members };
|
||||
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
|
||||
systems.write().await.insert(new_sys.id, record);
|
||||
let line_types = join_all(
|
||||
(cted.inst().dyn_parsers().iter())
|
||||
.map(|p| async { interner.i(p.line_head()).await.to_api() }),
|
||||
)
|
||||
.await;
|
||||
let prelude =
|
||||
cted.inst().dyn_prelude(&i).await.iter().map(|sym| sym.to_api()).collect();
|
||||
let record = SystemRecord { ctx, lazy_members };
|
||||
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
|
||||
systems.write().await.insert(new_sys.id, record);
|
||||
let line_types = join_all(
|
||||
(cted.inst().dyn_parsers().iter())
|
||||
.map(|p| async { i.i(p.line_head()).await.to_api() }),
|
||||
)
|
||||
.await;
|
||||
let response = api::NewSystemResponse { lex_filter, const_root, line_types, prelude };
|
||||
hand.handle(&new_sys, &response).await
|
||||
},
|
||||
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
|
||||
let sys_ctx = get_ctx(sys_id).await;
|
||||
let systems = systems_weak.upgrade().expect("Member queried during shutdown");
|
||||
let systems_g = systems.read().await;
|
||||
let mut lazy_members =
|
||||
systems_g.get(&sys_id).expect("System not found").lazy_members.lock().await;
|
||||
let (path, cb) = match lazy_members.insert(tree_id, MemberRecord::Res) {
|
||||
None => panic!("Tree for ID not found"),
|
||||
Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
|
||||
Some(MemberRecord::Gen(path, cb)) => (path, cb),
|
||||
};
|
||||
let tree = cb.build(Sym::new(path.clone(), &i).await.unwrap(), sys_ctx.clone()).await;
|
||||
let mut tia_ctx = TreeIntoApiCtxImpl {
|
||||
sys: sys_ctx,
|
||||
path: Substack::Bottom,
|
||||
basepath: &path,
|
||||
lazy_members: &mut lazy_members,
|
||||
};
|
||||
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
|
||||
let response =
|
||||
api::NewSystemResponse { lex_filter, const_root, line_types, prelude };
|
||||
hand.handle(&new_sys, &response).await
|
||||
})
|
||||
.await
|
||||
},
|
||||
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) =>
|
||||
with_ctx(get_ctx(sys_id).await, async move {
|
||||
let systems = systems_weak.upgrade().expect("Member queried during shutdown");
|
||||
let systems_g = systems.read().await;
|
||||
let mut lazy_members =
|
||||
systems_g.get(&sys_id).expect("System not found").lazy_members.lock().await;
|
||||
let (path, cb) = match lazy_members.insert(tree_id, MemberRecord::Res) {
|
||||
None => panic!("Tree for ID not found"),
|
||||
Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
|
||||
Some(MemberRecord::Gen(path, cb)) => (path, cb),
|
||||
};
|
||||
let tree = cb.build(Sym::new(path.clone(), &interner).await.unwrap()).await;
|
||||
let mut tia_ctx = TreeIntoApiCtxImpl {
|
||||
path: Substack::Bottom,
|
||||
basepath: &path,
|
||||
lazy_members: &mut lazy_members,
|
||||
};
|
||||
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
|
||||
})
|
||||
.await,
|
||||
api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
|
||||
let api::SysFwded(sys_id, payload) = fwd;
|
||||
let ctx = get_ctx(sys_id).await;
|
||||
let sys = ctx.cted().inst();
|
||||
sys.dyn_request(hand, payload).await
|
||||
with_ctx(ctx.clone(), async move {
|
||||
let sys = ctx.cted().inst();
|
||||
sys.dyn_request(hand, payload).await
|
||||
})
|
||||
.await
|
||||
},
|
||||
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, src, text, pos, id }) => {
|
||||
let mut sys_ctx = get_ctx(sys).await;
|
||||
let text = Tok::from_api(text, &i).await;
|
||||
let src = Sym::from_api(src, sys_ctx.i()).await;
|
||||
let rep = Reporter::new();
|
||||
let expr_store = BorrowedExprStore::new();
|
||||
let trigger_char = text.chars().nth(pos as usize).unwrap();
|
||||
let ekey_na = ekey_not_applicable(&i).await;
|
||||
let ekey_cascade = ekey_cascade(&i).await;
|
||||
let lexers = sys_ctx.cted().inst().dyn_lexers();
|
||||
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char)) {
|
||||
let ctx = LexContext {
|
||||
id,
|
||||
pos,
|
||||
text: &text,
|
||||
src: src.clone(),
|
||||
ctx: sys_ctx.clone(),
|
||||
rep: &rep,
|
||||
exprs: &expr_store,
|
||||
};
|
||||
match lx.lex(&text[pos as usize..], &ctx).await {
|
||||
Err(e) if e.any(|e| *e == ekey_na) => continue,
|
||||
Err(e) => {
|
||||
let eopt = e.keep_only(|e| *e != ekey_cascade).map(|e| Err(e.to_api()));
|
||||
expr_store.dispose().await;
|
||||
return hand.handle(&lex, &eopt).await;
|
||||
},
|
||||
Ok((s, expr)) => {
|
||||
let expr = expr.into_api(&mut (), &mut sys_ctx).await;
|
||||
let pos = (text.len() - s.len()) as u32;
|
||||
expr_store.dispose().await;
|
||||
return hand.handle(&lex, &Some(Ok(api::LexedExpr { pos, expr }))).await;
|
||||
},
|
||||
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, src, text, pos, id }) =>
|
||||
with_ctx(get_ctx(sys).await, async move {
|
||||
let text = Tok::from_api(text, &i()).await;
|
||||
let src = Sym::from_api(src, &i()).await;
|
||||
let rep = Reporter::new();
|
||||
let expr_store = BorrowedExprStore::new();
|
||||
let trigger_char = text.chars().nth(pos as usize).unwrap();
|
||||
let ekey_na = ekey_not_applicable().await;
|
||||
let ekey_cascade = ekey_cascade().await;
|
||||
let lexers = ctx().cted().inst().dyn_lexers();
|
||||
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char))
|
||||
{
|
||||
let ctx = LexContext::new(&expr_store, &text, id, pos, src.clone(), &rep);
|
||||
match lx.lex(&text[pos as usize..], &ctx).await {
|
||||
Err(e) if e.any(|e| *e == ekey_na) => continue,
|
||||
Err(e) => {
|
||||
let eopt = e.keep_only(|e| *e != ekey_cascade).map(|e| Err(e.to_api()));
|
||||
expr_store.dispose().await;
|
||||
return hand.handle(&lex, &eopt).await;
|
||||
},
|
||||
Ok((s, expr)) => {
|
||||
let expr = expr.into_api(&mut (), &mut ()).await;
|
||||
let pos = (text.len() - s.len()) as u32;
|
||||
expr_store.dispose().await;
|
||||
return hand.handle(&lex, &Some(Ok(api::LexedExpr { pos, expr }))).await;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
writeln!(logger, "Got notified about n/a character '{trigger_char}'");
|
||||
expr_store.dispose().await;
|
||||
hand.handle(&lex, &None).await
|
||||
},
|
||||
writeln!(logger, "Got notified about n/a character '{trigger_char}'");
|
||||
expr_store.dispose().await;
|
||||
hand.handle(&lex, &None).await
|
||||
})
|
||||
.await,
|
||||
api::HostExtReq::ParseLine(pline) => {
|
||||
let api::ParseLine { module, src, exported, comments, sys, line, idx } = &pline;
|
||||
let ctx = get_ctx(*sys).await;
|
||||
let parsers = ctx.cted().inst().dyn_parsers();
|
||||
let src = Sym::from_api(*src, ctx.i()).await;
|
||||
let comments =
|
||||
join_all(comments.iter().map(|c| Comment::from_api(c, src.clone(), &i))).await;
|
||||
let expr_store = BorrowedExprStore::new();
|
||||
let mut from_api_ctx = (ctx.clone(), &expr_store);
|
||||
let line: Vec<PTokTree> =
|
||||
ttv_from_api(line, &mut from_api_ctx, &mut (), &src, &i).await;
|
||||
let snip = Snippet::new(line.first().expect("Empty line"), &line);
|
||||
let parser = parsers[*idx as usize];
|
||||
let module = Sym::from_api(*module, ctx.i()).await;
|
||||
let reporter = Reporter::new();
|
||||
let pctx = ParsCtx::new(ctx.clone(), module, &reporter);
|
||||
let parse_res = parser.parse(pctx, *exported, comments, snip).await;
|
||||
let o_line = match reporter.merge(parse_res) {
|
||||
Err(e) => Err(e.to_api()),
|
||||
Ok(t) => Ok(linev_into_api(t, ctx.clone()).await),
|
||||
};
|
||||
mem::drop(line);
|
||||
expr_store.dispose().await;
|
||||
hand.handle(&pline, &o_line).await
|
||||
},
|
||||
api::HostExtReq::FetchParsedConst(ref fpc @ api::FetchParsedConst(sys, id)) => {
|
||||
let ctx = get_ctx(sys).await;
|
||||
let cnst = get_const(id, ctx.clone()).await;
|
||||
hand.handle(fpc, &cnst.api_return(ctx).await).await
|
||||
with_ctx(get_ctx(*sys).await, async {
|
||||
let parsers = ctx().cted().inst().dyn_parsers();
|
||||
let src = Sym::from_api(*src, &i()).await;
|
||||
let comments =
|
||||
join_all(comments.iter().map(|c| Comment::from_api(c, src.clone(), &interner)))
|
||||
.await;
|
||||
let expr_store = BorrowedExprStore::new();
|
||||
let line: Vec<PTokTree> =
|
||||
ttv_from_api(line, &mut &expr_store, &mut (), &src, &i()).await;
|
||||
let snip = Snippet::new(line.first().expect("Empty line"), &line);
|
||||
let parser = parsers[*idx as usize];
|
||||
let module = Sym::from_api(*module, &i()).await;
|
||||
let reporter = Reporter::new();
|
||||
let pctx = ParsCtx::new(module, &reporter);
|
||||
let parse_res = parser.parse(pctx, *exported, comments, snip).await;
|
||||
let o_line = match reporter.merge(parse_res) {
|
||||
Err(e) => Err(e.to_api()),
|
||||
Ok(t) => Ok(linev_into_api(t).await),
|
||||
};
|
||||
mem::drop(line);
|
||||
expr_store.dispose().await;
|
||||
hand.handle(&pline, &o_line).await
|
||||
})
|
||||
.await
|
||||
},
|
||||
api::HostExtReq::FetchParsedConst(ref fpc @ api::FetchParsedConst(sys, id)) =>
|
||||
with_ctx(get_ctx(sys).await, async move {
|
||||
let cnst = get_const(id).await;
|
||||
hand.handle(fpc, &cnst.serialize().await).await
|
||||
})
|
||||
.await,
|
||||
api::HostExtReq::AtomReq(atom_req) => {
|
||||
let atom = atom_req.get_atom();
|
||||
let atom_req = atom_req.clone();
|
||||
with_atom_record(&get_ctx, atom, async move |nfo, ctx, id, buf| {
|
||||
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
||||
with_atom_record(&get_ctx, atom, async move |nfo, id, buf| {
|
||||
let actx = AtomCtx(buf, atom.drop);
|
||||
match &atom_req {
|
||||
api::AtomReq::SerializeAtom(ser) => {
|
||||
let mut buf = enc_vec(&id).await;
|
||||
@@ -334,7 +338,7 @@ pub fn extension_init(
|
||||
api::AtomReq::Fwded(fwded) => {
|
||||
let api::Fwded(_, key, payload) = &fwded;
|
||||
let mut reply = Vec::new();
|
||||
let key = Sym::from_api(*key, &i).await;
|
||||
let key = Sym::from_api(*key, &interner).await;
|
||||
let some = nfo
|
||||
.handle_req(
|
||||
actx,
|
||||
@@ -347,18 +351,18 @@ pub fn extension_init(
|
||||
},
|
||||
api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => {
|
||||
let expr_store = BorrowedExprStore::new();
|
||||
let expr_handle = ExprHandle::borrowed(ctx.clone(), *arg, &expr_store);
|
||||
let expr_handle = ExprHandle::borrowed(*arg, &expr_store);
|
||||
let ret = nfo.call_ref(actx, Expr::from_handle(expr_handle.clone())).await;
|
||||
let api_expr = ret.api_return(ctx.clone()).await;
|
||||
let api_expr = ret.serialize().await;
|
||||
mem::drop(expr_handle);
|
||||
expr_store.dispose().await;
|
||||
hand.handle(call, &api_expr).await
|
||||
},
|
||||
api::AtomReq::FinalCall(call @ api::FinalCall(_, arg)) => {
|
||||
let expr_store = BorrowedExprStore::new();
|
||||
let expr_handle = ExprHandle::borrowed(ctx.clone(), *arg, &expr_store);
|
||||
let expr_handle = ExprHandle::borrowed(*arg, &expr_store);
|
||||
let ret = nfo.call(actx, Expr::from_handle(expr_handle.clone())).await;
|
||||
let api_expr = ret.api_return(ctx.clone()).await;
|
||||
let api_expr = ret.serialize().await;
|
||||
mem::drop(expr_handle);
|
||||
expr_store.dispose().await;
|
||||
hand.handle(call, &api_expr).await
|
||||
@@ -368,7 +372,7 @@ pub fn extension_init(
|
||||
Ok(opt) => match opt {
|
||||
None => hand.handle(cmd, &Ok(api::NextStep::Halt)).await,
|
||||
Some(cont) => {
|
||||
let cont = cont.api_return(ctx.clone()).await;
|
||||
let cont = cont.serialize().await;
|
||||
hand.handle(cmd, &Ok(api::NextStep::Continue(cont))).await
|
||||
},
|
||||
},
|
||||
@@ -383,12 +387,12 @@ pub fn extension_init(
|
||||
let ctx = get_ctx(*sys).await;
|
||||
// SAFETY: deserialization implicitly grants ownership to previously owned exprs
|
||||
let refs = (refs.iter())
|
||||
.map(|tk| Expr::from_handle(ExprHandle::deserialize(ctx.clone(), *tk)))
|
||||
.map(|tk| Expr::from_handle(ExprHandle::deserialize(*tk)))
|
||||
.collect_vec();
|
||||
let id = AtomTypeId::decode(Pin::new(&mut read)).await;
|
||||
let inst = ctx.cted().inst();
|
||||
let nfo = atom_by_idx(inst.card(), id).expect("Deserializing atom with invalid ID");
|
||||
hand.handle(&deser, &nfo.deserialize(ctx.clone(), read, &refs).await).await
|
||||
hand.handle(&deser, &nfo.deserialize(read, &refs).await).await
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user