partway through fixes, macro system needs resdesign
Some checks failed
Rust / build (push) Has been cancelled
Some checks failed
Rust / build (push) Has been cancelled
This commit is contained in:
@@ -10,6 +10,7 @@ async-event = "0.2.1"
|
||||
async-fn-stream = { version = "0.1.0", path = "../async-fn-stream" }
|
||||
async-once-cell = "0.5.4"
|
||||
bound = "0.6.0"
|
||||
chrono = "0.4.44"
|
||||
derive_destructure = "1.0.0"
|
||||
futures = { version = "0.3.31", features = ["std"], default-features = false }
|
||||
futures-locks = "0.7.1"
|
||||
|
||||
@@ -94,7 +94,7 @@ impl AtomHand {
|
||||
#[must_use]
|
||||
pub fn ext(&self) -> &Extension { self.sys().ext() }
|
||||
pub async fn req(&self, key: api::TStrv, req: Vec<u8>) -> Option<Vec<u8>> {
|
||||
self.0.owner.client().request(api::FinalFwded(self.0.api_ref(), key, req)).await.unwrap()
|
||||
self.0.owner.client().request(api::Fwded(self.0.api_ref(), key, req)).await.unwrap()
|
||||
}
|
||||
#[must_use]
|
||||
pub fn api_ref(&self) -> api::Atom { self.0.api_ref() }
|
||||
|
||||
@@ -7,40 +7,52 @@ use std::rc::Rc;
|
||||
|
||||
use async_event::Event;
|
||||
use async_fn_stream::stream;
|
||||
use chrono::{DateTime, Utc};
|
||||
use futures::channel::mpsc;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::{SinkExt, StreamExt, select};
|
||||
use never::Never;
|
||||
use orchid_base::{OrcErrv, Receipt, ReqHandle, Sym};
|
||||
use orchid_extension::{self as ox, AtomicFeatures as _};
|
||||
use orchid_base::{OrcErrv, Receipt, ReqHandle, Sym, fmt, is, log, mk_errv};
|
||||
use orchid_extension::{self as ox, AtomicFeatures as _, get_arg};
|
||||
|
||||
use crate::ctx::Ctx;
|
||||
use crate::execute::{ExecCtx, ExecResult};
|
||||
use crate::expr::{Expr, ExprFromApiCtx, PathSetBuilder};
|
||||
use crate::extension::Extension;
|
||||
use crate::inline::ext_inline;
|
||||
use crate::system::System;
|
||||
use crate::tree::Root;
|
||||
|
||||
/// Events internally recognized by this system sent through [CommandQueue]
|
||||
enum Task {
|
||||
RunCommand(Expr),
|
||||
Sleep(DateTime<Utc>, Expr),
|
||||
Exit,
|
||||
}
|
||||
|
||||
struct CommandQueueState {
|
||||
new: VecDeque<Expr>,
|
||||
new: VecDeque<Task>,
|
||||
added: Rc<Event>,
|
||||
wants_exit: bool,
|
||||
ctx: Ctx,
|
||||
}
|
||||
|
||||
/// Shared object serving as a communication point between the extension
|
||||
/// [CmdSystemCtor] and the host toolkit [CmdRunner]
|
||||
#[derive(Clone)]
|
||||
struct CommandQueue(Rc<RefCell<CommandQueueState>>);
|
||||
impl CommandQueue {
|
||||
fn new(ctx: Ctx, init: impl IntoIterator<Item = Expr>) -> Self {
|
||||
Self(Rc::new(RefCell::new(CommandQueueState {
|
||||
new: init.into_iter().collect(),
|
||||
new: init.into_iter().map(Task::RunCommand).collect(),
|
||||
added: Rc::default(),
|
||||
wants_exit: false,
|
||||
ctx,
|
||||
})))
|
||||
}
|
||||
pub fn push(&self, expr: Expr) {
|
||||
pub fn push(&self, task: Task) {
|
||||
let was_empty = {
|
||||
let mut g = self.0.borrow_mut();
|
||||
g.new.push_back(expr);
|
||||
g.new.push_back(task);
|
||||
g.new.len() == 1
|
||||
};
|
||||
if was_empty {
|
||||
@@ -48,7 +60,7 @@ impl CommandQueue {
|
||||
added.notify_one();
|
||||
}
|
||||
}
|
||||
pub async fn get_new(&self) -> Expr {
|
||||
pub async fn get_new(&self) -> Task {
|
||||
let added = {
|
||||
let mut g = self.0.borrow_mut();
|
||||
if let Some(waiting) = g.new.pop_front() {
|
||||
@@ -65,10 +77,13 @@ impl Debug for CommandQueue {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CmdResult {
|
||||
/// All command sequences settled
|
||||
/// Events the embedder may want to be notified about
|
||||
pub enum CmdEvent {
|
||||
/// All commands finished and there's nothing else to do
|
||||
Settled,
|
||||
/// Exit was requested explicitly by usercode
|
||||
/// Exit was requested explicitly by usercode. This request means that all
|
||||
/// internal system state should be discarded, so if it is returned by the
|
||||
/// [CmdRunner], no further commands are permitted
|
||||
Exit,
|
||||
/// Ran out of gas
|
||||
Gas,
|
||||
@@ -89,35 +104,64 @@ pub struct CmdRunner {
|
||||
queue: CommandQueue,
|
||||
gas: Option<u64>,
|
||||
interrupted: Option<ExecCtx>,
|
||||
futures: FuturesUnordered<LocalBoxFuture<'static, Option<CmdResult>>>,
|
||||
system: System,
|
||||
futures: FuturesUnordered<LocalBoxFuture<'static, Option<CmdEvent>>>,
|
||||
}
|
||||
impl CmdRunner {
|
||||
pub async fn new(root: Root, ctx: Ctx, init: impl IntoIterator<Item = Expr>) -> Self {
|
||||
Self {
|
||||
futures: FuturesUnordered::new(),
|
||||
gas: None,
|
||||
root,
|
||||
interrupted: None,
|
||||
queue: CommandQueue::new(ctx, init),
|
||||
}
|
||||
let queue = CommandQueue::new(ctx.clone(), init);
|
||||
let ext_builder = ox::ExtensionBuilder::new("orchid::cmd").system(CmdSystemCtor(queue.clone()));
|
||||
let extension = (Extension::new(ext_inline(ext_builder, ctx.clone()).await, ctx).await)
|
||||
.expect("IO error on in-memory pipe");
|
||||
let system_ctor = (extension.system_ctors().find(|ctor| ctor.decl.name == "orchid::cmd"))
|
||||
.expect("Missing command system ctor");
|
||||
let (cmd_root, system) = system_ctor.run(vec![]).await;
|
||||
let root = root.merge(&cmd_root).await.expect("Could not merge command system into tree");
|
||||
Self { futures: FuturesUnordered::new(), gas: None, root, interrupted: None, queue, system }
|
||||
}
|
||||
#[must_use]
|
||||
pub fn sys(&self) -> &System { &self.system }
|
||||
#[must_use]
|
||||
pub fn get_gas(&self) -> u64 { self.gas.expect("queried gas but no gas was set") }
|
||||
pub fn set_gas(&mut self, gas: u64) { self.gas = Some(gas) }
|
||||
pub fn disable_gas(&mut self) { self.gas = None }
|
||||
pub async fn execute(&mut self) -> CmdResult {
|
||||
pub async fn execute(&mut self) -> CmdEvent {
|
||||
let waiting_on_queue = RefCell::new(false);
|
||||
let (mut spawn, mut on_spawn) = mpsc::channel(1);
|
||||
let (mut spawn, mut on_spawn) = mpsc::channel::<LocalBoxFuture<Option<CmdEvent>>>(1);
|
||||
let mut normalize_stream = pin!(
|
||||
stream(async |mut h| {
|
||||
loop {
|
||||
if self.queue.0.borrow().wants_exit {
|
||||
h.emit(CmdResult::Exit).await;
|
||||
break;
|
||||
}
|
||||
waiting_on_queue.replace(false);
|
||||
let mut xctx = match self.interrupted.take() {
|
||||
None => ExecCtx::new(self.root.clone(), self.queue.get_new().await).await,
|
||||
None => match self.queue.get_new().await {
|
||||
Task::RunCommand(expr) => ExecCtx::new(self.root.clone(), expr).await,
|
||||
Task::Sleep(until, expr) => {
|
||||
let queue = self.queue.clone();
|
||||
let ctx = queue.0.borrow_mut().ctx.clone();
|
||||
spawn
|
||||
.send(Box::pin(async move {
|
||||
let delta = until - Utc::now();
|
||||
match delta.to_std() {
|
||||
Err(_) =>
|
||||
writeln!(
|
||||
log("debug"),
|
||||
"Negative sleep found ({delta}), requeuing as instant"
|
||||
)
|
||||
.await,
|
||||
Ok(delay) => ctx.sleep(delay).await,
|
||||
};
|
||||
queue.push(Task::RunCommand(expr));
|
||||
None
|
||||
}))
|
||||
.await
|
||||
.expect("Receiver stored in parent future");
|
||||
continue;
|
||||
},
|
||||
Task::Exit => {
|
||||
h.emit(CmdEvent::Exit).await;
|
||||
break;
|
||||
},
|
||||
},
|
||||
Some(xctx) => xctx,
|
||||
};
|
||||
waiting_on_queue.replace(true);
|
||||
@@ -126,16 +170,16 @@ impl CmdRunner {
|
||||
match res {
|
||||
ExecResult::Err(e, gas) => {
|
||||
self.gas = gas;
|
||||
h.emit(CmdResult::Err(e)).await;
|
||||
h.emit(CmdEvent::Err(e)).await;
|
||||
},
|
||||
ExecResult::Gas(exec) => {
|
||||
self.interrupted = Some(exec);
|
||||
h.emit(CmdResult::Gas).await;
|
||||
h.emit(CmdEvent::Gas).await;
|
||||
},
|
||||
ExecResult::Value(val, gas) => {
|
||||
self.gas = gas;
|
||||
let Some(atom) = val.as_atom().await else {
|
||||
h.emit(CmdResult::NonCommand(val)).await;
|
||||
h.emit(CmdEvent::NonCommand(val)).await;
|
||||
continue;
|
||||
};
|
||||
let queue = self.queue.clone();
|
||||
@@ -143,11 +187,13 @@ impl CmdRunner {
|
||||
spawn
|
||||
.send(Box::pin(async move {
|
||||
match atom.ipc(ox::std_reqs::RunCommand).await {
|
||||
None => Some(CmdResult::NonCommand(val)),
|
||||
None => Some(CmdEvent::NonCommand(val)),
|
||||
Some(None) => None,
|
||||
Some(Some(expr)) => {
|
||||
let from_api_cx = ExprFromApiCtx { ctx, sys: atom.api_ref().owner };
|
||||
queue.push(Expr::from_api(expr, PathSetBuilder::new(), from_api_cx).await);
|
||||
queue.push(Task::RunCommand(
|
||||
Expr::from_api(expr, PathSetBuilder::new(), from_api_cx).await,
|
||||
));
|
||||
None
|
||||
},
|
||||
}
|
||||
@@ -161,17 +207,20 @@ impl CmdRunner {
|
||||
.fuse()
|
||||
);
|
||||
loop {
|
||||
if self.queue.0.borrow().wants_exit {
|
||||
break CmdResult::Exit;
|
||||
}
|
||||
let task = select!(
|
||||
r_opt = self.futures.by_ref().next() => match r_opt {
|
||||
Some(Some(r)) => break r,
|
||||
None if *waiting_on_queue.borrow() => break CmdResult::Settled,
|
||||
None if *waiting_on_queue.borrow() => break CmdEvent::Settled,
|
||||
None | Some(None) => continue,
|
||||
},
|
||||
r = normalize_stream.by_ref().next() => break r.expect("infinite stream"),
|
||||
task = on_spawn.by_ref().next() => task.expect("sender moved into infinite stream"),
|
||||
r = normalize_stream.by_ref().next() => match r {
|
||||
None => break CmdEvent::Exit,
|
||||
Some(r) => break r,
|
||||
},
|
||||
task = on_spawn.by_ref().next() => match task {
|
||||
None => break CmdEvent::Exit,
|
||||
Some(r) => r,
|
||||
},
|
||||
);
|
||||
self.futures.push(task)
|
||||
}
|
||||
@@ -189,9 +238,7 @@ impl ox::SystemCard for CmdSystemCard {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CmdSystemCtor {
|
||||
queue: CommandQueue,
|
||||
}
|
||||
pub struct CmdSystemCtor(CommandQueue);
|
||||
impl ox::SystemCtor for CmdSystemCtor {
|
||||
const NAME: &'static str = "orchid::cmd";
|
||||
const VERSION: f64 = 0.1;
|
||||
@@ -199,7 +246,7 @@ impl ox::SystemCtor for CmdSystemCtor {
|
||||
type Deps = ();
|
||||
type Instance = CmdSystemInst;
|
||||
fn inst(&self, _: <Self::Deps as orchid_extension::DepDef>::Sat) -> Self::Instance {
|
||||
CmdSystemInst { queue: self.queue.clone() }
|
||||
CmdSystemInst { queue: self.0.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,12 +264,39 @@ impl ox::System for CmdSystemInst {
|
||||
ox::tree::fun(true, "spawn", async |side: ox::Expr, cont: ox::Expr| {
|
||||
ox::cmd(async move || {
|
||||
let queue = ox_get_queue();
|
||||
let side_xtk = side.serialize().await;
|
||||
let side_xtk = side.clone().serialize().await;
|
||||
let mut g = queue.0.borrow_mut();
|
||||
let host_ex =
|
||||
g.ctx.exprs.take_expr(side_xtk).expect("Host could not locate leaked expr by ID ");
|
||||
g.new.push_back(host_ex);
|
||||
Some(cont)
|
||||
g.new.push_back(Task::RunCommand(host_ex));
|
||||
Some(cont.clone())
|
||||
})
|
||||
}),
|
||||
ox::tree::cnst(true, "yield", ox::cmd(async || None::<Never>)),
|
||||
ox::tree::cnst(
|
||||
true,
|
||||
"exit",
|
||||
ox::cmd(async || {
|
||||
ox_get_queue().push(Task::Exit);
|
||||
None::<Never>
|
||||
}),
|
||||
),
|
||||
ox::tree::fun(true, "sleep", async |until: ox::ForeignAtom, cont: ox::Expr| {
|
||||
let Some(until) = until.call(ox::std_reqs::AsInstant).await else {
|
||||
return ox::gen_expr::bot(mk_errv(
|
||||
is("Not an instant").await,
|
||||
format!("{} is not an instant", fmt(&until).await),
|
||||
[get_arg(0).pos().await],
|
||||
));
|
||||
};
|
||||
ox::cmd(async move || {
|
||||
let queue = ox_get_queue();
|
||||
let cont_xtk = cont.clone().serialize().await;
|
||||
let mut g = queue.0.borrow_mut();
|
||||
let host_ex =
|
||||
g.ctx.exprs.take_expr(cont_xtk).expect("Host could not locate leaked expr by ID ");
|
||||
g.new.push_back(Task::Sleep(until, host_ex));
|
||||
None::<Never>
|
||||
})
|
||||
}),
|
||||
])
|
||||
|
||||
@@ -18,7 +18,8 @@ pub trait JoinHandle {
|
||||
/// It is guaranteed that the future will never be polled after this is called
|
||||
fn abort(&self);
|
||||
/// take the future out of the task. If the return value
|
||||
/// is dropped, the spawned future is also dropped
|
||||
/// is dropped, the spawned future is also dropped. The returned boxed future
|
||||
/// will finish any sleep requested at spawn.
|
||||
fn join(self: Box<Self>) -> LocalBoxFuture<'static, ()>;
|
||||
}
|
||||
|
||||
@@ -30,6 +31,9 @@ pub trait Spawner {
|
||||
/// exit while there are pending tasks to allow external communication
|
||||
/// channels to cleanly shut down.
|
||||
fn spawn_obj(&self, delay: Duration, fut: LocalBoxFuture<'static, ()>) -> Box<dyn JoinHandle>;
|
||||
fn sleep(&self, delay: Duration) -> LocalBoxFuture<'static, ()> {
|
||||
self.spawn_obj(delay, Box::pin(async move {})).join()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtxData {
|
||||
@@ -79,6 +83,9 @@ impl Ctx {
|
||||
) -> Box<dyn JoinHandle> {
|
||||
self.spawner.spawn_obj(delay, Box::pin(fut))
|
||||
}
|
||||
/// Return after an amount of time has passed
|
||||
#[must_use]
|
||||
pub async fn sleep(&self, delay: Duration) { self.spawner.sleep(delay).await }
|
||||
#[must_use]
|
||||
pub(crate) async fn system_inst(&self, id: api::SysId) -> Option<System> {
|
||||
self.systems.read().await.get(&id).and_then(WeakSystem::upgrade)
|
||||
|
||||
@@ -27,7 +27,7 @@ use crate::ctx::{Ctx, JoinHandle};
|
||||
use crate::dealias::{ChildError, ChildErrorKind, walk};
|
||||
use crate::expr::{Expr, ExprFromApiCtx, PathSetBuilder};
|
||||
use crate::system::SystemCtor;
|
||||
use crate::tree::MemberKind;
|
||||
use crate::tree::MemKind;
|
||||
|
||||
pub struct ExtPort {
|
||||
pub input: Pin<Box<dyn AsyncWrite>>,
|
||||
@@ -54,17 +54,19 @@ pub struct ExtensionData {
|
||||
strings: RefCell<HashSet<IStr>>,
|
||||
string_vecs: RefCell<HashSet<IStrv>>,
|
||||
/// Moved over from [ExtPort] to allow hooking to the extension's drop
|
||||
_drop_trigger: Box<dyn Any>,
|
||||
drop_trigger: Box<dyn Any>,
|
||||
}
|
||||
impl Drop for ExtensionData {
|
||||
fn drop(&mut self) {
|
||||
let client = self.client.clone();
|
||||
let join_ext = self.join_ext.take().expect("Only called once in Drop");
|
||||
let comm_cx = self.comm_cx.take().expect("Only used here");
|
||||
let drop_trigger = std::mem::replace(&mut self.drop_trigger, Box::new(()));
|
||||
stash(async move {
|
||||
client.notify(api::HostExtNotif::Exit).await.unwrap();
|
||||
comm_cx.exit().await.unwrap();
|
||||
join_ext.join().await;
|
||||
std::mem::drop(drop_trigger);
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -158,12 +160,12 @@ impl Extension {
|
||||
handle.reply(&vi, &markerv).await
|
||||
},
|
||||
},
|
||||
api::ExtHostReq::Fwd(ref fw @ api::Fwd(ref atom, ref key, ref body)) => {
|
||||
api::ExtHostReq::Fwd(ref fw @ api::Fwd { ref target, ref method, ref body }) => {
|
||||
let sys =
|
||||
ctx.system_inst(atom.owner).await.expect("owner of live atom dropped");
|
||||
ctx.system_inst(target.owner).await.expect("owner of live atom dropped");
|
||||
let client = sys.client();
|
||||
let reply = client
|
||||
.request(api::FinalFwded(fw.0.clone(), *key, body.clone()))
|
||||
.request(api::Fwded(target.clone(), *method, body.clone()))
|
||||
.await
|
||||
.unwrap();
|
||||
handle.reply(fw, &reply).await
|
||||
@@ -229,8 +231,8 @@ impl Extension {
|
||||
let mut members = std::collections::HashMap::new();
|
||||
for (k, v) in &module.members {
|
||||
let kind = match v.kind(ctx.clone(), &root_data.consts).await {
|
||||
MemberKind::Const => api::MemberInfoKind::Constant,
|
||||
MemberKind::Module(_) => api::MemberInfoKind::Module,
|
||||
MemKind::Const => api::MemberInfoKind::Constant,
|
||||
MemKind::Module(_) => api::MemberInfoKind::Module,
|
||||
};
|
||||
members.insert(k.to_api(), api::MemberInfo { public: v.public, kind });
|
||||
}
|
||||
@@ -293,7 +295,7 @@ impl Extension {
|
||||
client: Rc::new(client),
|
||||
strings: RefCell::default(),
|
||||
string_vecs: RefCell::default(),
|
||||
_drop_trigger: init.drop_trigger,
|
||||
drop_trigger: init.drop_trigger,
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
@@ -262,8 +262,9 @@ pub async fn sys_lex(ctx: &mut LexCtx<'_>) -> Option<OrcRes<Vec<ParsTokTree>>> {
|
||||
})
|
||||
.await;
|
||||
match lx {
|
||||
Err(e) =>
|
||||
return Some(Err(errors.into_iter().fold(OrcErrv::from_api(e).await, |a, b| a + b))),
|
||||
Err(e) => {
|
||||
return Some(Err(errors.into_iter().fold(OrcErrv::from_api(e).await, |a, b| a + b)));
|
||||
},
|
||||
Ok(Some(lexed)) => {
|
||||
ctx.set_pos(lexed.pos);
|
||||
let mut stable_trees = Vec::new();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use orchid_api as api;
|
||||
|
||||
pub mod atom;
|
||||
pub mod ctx;
|
||||
#[cfg(feature = "orchid-extension")]
|
||||
pub mod cmd_system;
|
||||
pub mod ctx;
|
||||
pub mod dealias;
|
||||
#[cfg(feature = "tokio")]
|
||||
pub mod dylib;
|
||||
|
||||
@@ -8,7 +8,7 @@ use substack::Substack;
|
||||
|
||||
use crate::ctx::Ctx;
|
||||
use crate::expr::Expr;
|
||||
use crate::parsed::{Item, ItemKind, ParsedMember, ParsedMemberKind, ParsedModule};
|
||||
use crate::parsed::{Item, ItemKind, ParsedMemKind, ParsedMember, ParsedModule};
|
||||
use crate::system::System;
|
||||
|
||||
type ParsSnippet<'a> = Snippet<'a, Expr, Expr>;
|
||||
@@ -101,7 +101,7 @@ pub async fn parse_exportable_item<'a>(
|
||||
) -> OrcRes<Vec<Item>> {
|
||||
let kind = if discr == is("mod").await {
|
||||
let (name, body) = parse_module(ctx, path, tail).await?;
|
||||
ItemKind::Member(ParsedMember { name, exported, kind: ParsedMemberKind::Mod(body) })
|
||||
ItemKind::Member(ParsedMember { name, exported, kind: ParsedMemKind::Mod(body) })
|
||||
} else if let Some(parser) = ctx.systems().find_map(|s| s.get_parser(discr.clone())) {
|
||||
return parser
|
||||
.parse(ctx, path, tail.to_vec(), exported, comments, &mut async |stack, lines| {
|
||||
|
||||
@@ -53,10 +53,10 @@ impl Format for Item {
|
||||
let item_text = match &self.kind {
|
||||
ItemKind::Import(i) => format!("import {i}").into(),
|
||||
ItemKind::Member(mem) => match &mem.kind {
|
||||
ParsedMemberKind::Const(_, sys) =>
|
||||
ParsedMemKind::Const(_, sys) =>
|
||||
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("const {0} via {1}")))
|
||||
.units([mem.name.to_string().into(), sys.print(c).await]),
|
||||
ParsedMemberKind::Mod(module) =>
|
||||
ParsedMemKind::Mod(module) =>
|
||||
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("module {0} {{\n\t{1}\n}}")))
|
||||
.units([mem.name.to_string().into(), module.print(c).boxed_local().await]),
|
||||
},
|
||||
@@ -69,12 +69,12 @@ impl Format for Item {
|
||||
pub struct ParsedMember {
|
||||
pub name: IStr,
|
||||
pub exported: bool,
|
||||
pub kind: ParsedMemberKind,
|
||||
pub kind: ParsedMemKind,
|
||||
}
|
||||
impl ParsedMember {
|
||||
#[must_use]
|
||||
pub fn name(&self) -> IStr { self.name.clone() }
|
||||
pub fn new(exported: bool, name: IStr, kind: impl Into<ParsedMemberKind>) -> Self {
|
||||
pub fn new(exported: bool, name: IStr, kind: impl Into<ParsedMemKind>) -> Self {
|
||||
Self { exported, name, kind: kind.into() }
|
||||
}
|
||||
}
|
||||
@@ -101,11 +101,11 @@ impl fmt::Debug for ParsedExpr {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParsedMemberKind {
|
||||
pub enum ParsedMemKind {
|
||||
Const(api::ParsedConstId, System),
|
||||
Mod(ParsedModule),
|
||||
}
|
||||
impl From<ParsedModule> for ParsedMemberKind {
|
||||
impl From<ParsedModule> for ParsedMemKind {
|
||||
fn from(value: ParsedModule) -> Self { Self::Mod(value) }
|
||||
}
|
||||
#[derive(Debug, Default)]
|
||||
@@ -137,7 +137,7 @@ impl ParsedModule {
|
||||
.filter_map(|it| if let ItemKind::Import(i) = &it.kind { Some(i) } else { None })
|
||||
}
|
||||
pub fn default_item(self, name: IStr, sr: SrcRange) -> Item {
|
||||
let mem = ParsedMember { exported: true, name, kind: ParsedMemberKind::Mod(self) };
|
||||
let mem = ParsedMember { exported: true, name, kind: ParsedMemKind::Mod(self) };
|
||||
Item { comments: vec![], sr, kind: ItemKind::Member(mem) }
|
||||
}
|
||||
}
|
||||
@@ -157,8 +157,8 @@ impl Tree for ParsedModule {
|
||||
.find(|m| m.name == key)
|
||||
{
|
||||
match &member.kind {
|
||||
ParsedMemberKind::Const(..) => return ChildResult::Err(ChildErrorKind::Constant),
|
||||
ParsedMemberKind::Mod(m) => return ChildResult::Ok(m),
|
||||
ParsedMemKind::Const(..) => return ChildResult::Err(ChildErrorKind::Constant),
|
||||
ParsedMemKind::Mod(m) => return ChildResult::Ok(m),
|
||||
}
|
||||
}
|
||||
ChildResult::Err(ChildErrorKind::Missing)
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::expr::ExprFromApiCtx;
|
||||
use crate::expr_store::ExprStore;
|
||||
use crate::parse::HostParseCtx;
|
||||
use crate::parsed::{
|
||||
Item, ItemKind, ParsTokTree, ParsedMember, ParsedMemberKind, ParsedModule, tt_to_api,
|
||||
Item, ItemKind, ParsTokTree, ParsedMemKind, ParsedMember, ParsedModule, tt_to_api,
|
||||
};
|
||||
use crate::system::System;
|
||||
|
||||
@@ -88,11 +88,11 @@ async fn conv(
|
||||
let mkind = match kind {
|
||||
api::ParsedMemberKind::Module { lines, use_prelude } => {
|
||||
let items = conv(lines, mem_path, callback, ctx).boxed_local().await?;
|
||||
ParsedMemberKind::Mod(ParsedModule::new(use_prelude, items))
|
||||
ParsedMemKind::Mod(ParsedModule::new(use_prelude, items))
|
||||
},
|
||||
api::ParsedMemberKind::Constant(cid) => {
|
||||
ctx.sys.0.const_paths.insert(cid, ctx.mod_path.suffix(mem_path.unreverse()).await);
|
||||
ParsedMemberKind::Const(cid, ctx.sys.clone())
|
||||
ParsedMemKind::Const(cid, ctx.sys.clone())
|
||||
},
|
||||
};
|
||||
items.push(Item {
|
||||
|
||||
@@ -21,11 +21,11 @@ use crate::api;
|
||||
use crate::ctx::Ctx;
|
||||
use crate::dealias::{ChildErrorKind, Tree, absolute_path, resolv_glob, walk};
|
||||
use crate::expr::{Expr, ExprFromApiCtx, PathSetBuilder};
|
||||
use crate::parsed::{ItemKind, ParsedMemberKind, ParsedModule};
|
||||
use crate::parsed::{ItemKind, ParsedMemKind, ParsedModule};
|
||||
use crate::system::System;
|
||||
|
||||
pub struct RootData {
|
||||
pub root: Module,
|
||||
pub root: Mod,
|
||||
pub consts: MemoMap<Sym, Expr>,
|
||||
pub ctx: Ctx,
|
||||
}
|
||||
@@ -34,17 +34,13 @@ pub struct Root(pub Rc<RwLock<RootData>>);
|
||||
impl Root {
|
||||
#[must_use]
|
||||
pub fn new(ctx: Ctx) -> Self {
|
||||
Root(Rc::new(RwLock::new(RootData {
|
||||
root: Module::default(),
|
||||
consts: MemoMap::default(),
|
||||
ctx,
|
||||
})))
|
||||
Root(Rc::new(RwLock::new(RootData { root: Mod::default(), consts: MemoMap::default(), ctx })))
|
||||
}
|
||||
#[must_use]
|
||||
pub async fn from_api(api: api::Module, sys: &System) -> Self {
|
||||
let consts = MemoMap::new();
|
||||
let mut tfac = TreeFromApiCtx { consts: &consts, path: iv(&[][..]).await, sys };
|
||||
let root = Module::from_api(api, &mut tfac).await;
|
||||
let root = Mod::from_api(api, &mut tfac).await;
|
||||
Root(Rc::new(RwLock::new(RootData { root, consts, ctx: sys.ctx().clone() })))
|
||||
}
|
||||
pub async fn merge(&self, new: &Root) -> Result<Self, MergeErr> {
|
||||
@@ -71,14 +67,14 @@ impl Root {
|
||||
root: &this.root,
|
||||
ctx: &this.ctx,
|
||||
};
|
||||
let mut module = Module::from_parsed(parsed, pars_prefix.clone(), &mut tfpctx).await;
|
||||
let mut module = Mod::from_parsed(parsed, pars_prefix.clone(), &mut tfpctx).await;
|
||||
for step in pars_prefix.iter().rev() {
|
||||
let kind = OnceCell::from(MemberKind::Module(module));
|
||||
let kind = OnceCell::from(MemKind::Module(module));
|
||||
let members = HashMap::from([(
|
||||
step.clone(),
|
||||
Rc::new(Member { public: true, lazy: RefCell::new(None), kind }),
|
||||
)]);
|
||||
module = Module { imports: HashMap::new(), members }
|
||||
module = Mod { imports: HashMap::new(), members }
|
||||
}
|
||||
let root = (this.root.merge(&module, this.ctx.clone(), &consts).await)
|
||||
.expect("Merge conflict between parsed and existing module");
|
||||
@@ -159,11 +155,11 @@ pub struct ResolvedImport {
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Module {
|
||||
pub struct Mod {
|
||||
pub imports: HashMap<IStr, Result<ResolvedImport, Vec<ResolvedImport>>>,
|
||||
pub members: HashMap<IStr, Rc<Member>>,
|
||||
}
|
||||
impl Module {
|
||||
impl Mod {
|
||||
#[must_use]
|
||||
pub async fn from_api(api: api::Module, ctx: &mut TreeFromApiCtx<'_>) -> Self {
|
||||
let mut members = HashMap::new();
|
||||
@@ -178,11 +174,11 @@ impl Module {
|
||||
let cx = ExprFromApiCtx { ctx: ctx.sys.ctx().clone(), sys: ctx.sys.id() };
|
||||
let expr = Expr::from_api(val, PathSetBuilder::new(), cx).await;
|
||||
ctx.consts.insert(name.clone(), expr);
|
||||
(None, Some(MemberKind::Const))
|
||||
(None, Some(MemKind::Const))
|
||||
},
|
||||
api::MemberKind::Module(m) => {
|
||||
let m = Self::from_api(m, &mut ctx.push(mem_name.clone()).await).boxed_local().await;
|
||||
(None, Some(MemberKind::Module(m)))
|
||||
(None, Some(MemKind::Module(m)))
|
||||
},
|
||||
};
|
||||
members.insert(
|
||||
@@ -305,7 +301,7 @@ impl Module {
|
||||
match &item.kind {
|
||||
ItemKind::Member(mem) => {
|
||||
let path = path.to_vname().suffix([mem.name.clone()]).to_sym().await;
|
||||
let kind = OnceCell::from(MemberKind::from_parsed(&mem.kind, path.clone(), ctx).await);
|
||||
let kind = OnceCell::from(MemKind::from_parsed(&mem.kind, path.clone(), ctx).await);
|
||||
members.insert(
|
||||
mem.name.clone(),
|
||||
Rc::new(Member { kind, lazy: RefCell::default(), public: mem.exported }),
|
||||
@@ -314,14 +310,14 @@ impl Module {
|
||||
ItemKind::Import(_) => (),
|
||||
}
|
||||
}
|
||||
Module { imports, members }
|
||||
Mod { imports, members }
|
||||
}
|
||||
pub async fn merge(
|
||||
&self,
|
||||
other: &Module,
|
||||
other: &Mod,
|
||||
ctx: Ctx,
|
||||
consts: &MemoMap<Sym, Expr>,
|
||||
) -> Result<Module, MergeErr> {
|
||||
) -> Result<Mod, MergeErr> {
|
||||
if !self.imports.is_empty() || !other.imports.is_empty() {
|
||||
return Err(MergeErr { path: VPath::new([]), kind: MergeErrKind::Imports });
|
||||
}
|
||||
@@ -335,7 +331,7 @@ impl Module {
|
||||
return Err(MergeErr { path: VPath::new([]), kind: MergeErrKind::Visibility });
|
||||
}
|
||||
match (own.kind(ctx.clone(), consts).await, mem.kind(ctx.clone(), consts).await) {
|
||||
(MemberKind::Module(own_sub), MemberKind::Module(sub)) => {
|
||||
(MemKind::Module(own_sub), MemKind::Module(sub)) => {
|
||||
match own_sub.merge(sub, ctx.clone(), consts).boxed_local().await {
|
||||
Ok(module) => {
|
||||
members.insert(
|
||||
@@ -343,7 +339,7 @@ impl Module {
|
||||
Rc::new(Member {
|
||||
lazy: RefCell::new(None),
|
||||
public: own.public,
|
||||
kind: OnceCell::from(MemberKind::Module(module)),
|
||||
kind: OnceCell::from(MemKind::Module(module)),
|
||||
}),
|
||||
);
|
||||
},
|
||||
@@ -361,7 +357,7 @@ impl Module {
|
||||
slot.insert(mem.clone());
|
||||
}
|
||||
}
|
||||
Ok(Module { imports: HashMap::new(), members })
|
||||
Ok(Mod { imports: HashMap::new(), members })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,13 +376,13 @@ pub enum MergeErrKind {
|
||||
pub struct FromParsedCtx<'a> {
|
||||
pars_prefix: Sym,
|
||||
pars_root: &'a ParsedModule,
|
||||
root: &'a Module,
|
||||
root: &'a Mod,
|
||||
ctx: &'a Ctx,
|
||||
consts: &'a MemoMap<Sym, Expr>,
|
||||
deferred_consts: &'a mut Vec<(Sym, api::SysId, api::ParsedConstId)>,
|
||||
}
|
||||
|
||||
impl Tree for Module {
|
||||
impl Tree for Mod {
|
||||
type Ctx<'a> = (Ctx, &'a MemoMap<Sym, Expr>);
|
||||
async fn child(
|
||||
&self,
|
||||
@@ -401,8 +397,8 @@ impl Tree for Module {
|
||||
return Err(ChildErrorKind::Private);
|
||||
}
|
||||
match &member.kind(ctx.clone(), consts).await {
|
||||
MemberKind::Module(m) => Ok(m),
|
||||
MemberKind::Const => Err(ChildErrorKind::Constant),
|
||||
MemKind::Module(m) => Ok(m),
|
||||
MemKind::Const => Err(ChildErrorKind::Constant),
|
||||
}
|
||||
}
|
||||
fn children(&self, public_only: bool) -> hashbrown::HashSet<IStr> {
|
||||
@@ -413,11 +409,11 @@ impl Tree for Module {
|
||||
pub struct Member {
|
||||
pub public: bool,
|
||||
pub lazy: RefCell<Option<LazyMemberHandle>>,
|
||||
pub kind: OnceCell<MemberKind>,
|
||||
pub kind: OnceCell<MemKind>,
|
||||
}
|
||||
impl Member {
|
||||
#[must_use]
|
||||
pub async fn kind<'a>(&'a self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> &'a MemberKind {
|
||||
pub async fn kind<'a>(&'a self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> &'a MemKind {
|
||||
(self.kind.get_or_init(async {
|
||||
let handle = self.lazy.borrow_mut().take().expect("If kind is uninit, lazy must be Some");
|
||||
handle.run(ctx, consts).await
|
||||
@@ -426,20 +422,20 @@ impl Member {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MemberKind {
|
||||
pub enum MemKind {
|
||||
Const,
|
||||
Module(Module),
|
||||
Module(Mod),
|
||||
}
|
||||
impl MemberKind {
|
||||
impl MemKind {
|
||||
#[must_use]
|
||||
async fn from_parsed(parsed: &ParsedMemberKind, path: Sym, ctx: &mut FromParsedCtx<'_>) -> Self {
|
||||
async fn from_parsed(parsed: &ParsedMemKind, path: Sym, ctx: &mut FromParsedCtx<'_>) -> Self {
|
||||
match parsed {
|
||||
ParsedMemberKind::Const(id, sys) => {
|
||||
ParsedMemKind::Const(id, sys) => {
|
||||
ctx.deferred_consts.push((path, sys.id(), *id));
|
||||
MemberKind::Const
|
||||
MemKind::Const
|
||||
},
|
||||
ParsedMemberKind::Mod(m) =>
|
||||
MemberKind::Module(Module::from_parsed(m, path, ctx).boxed_local().await),
|
||||
ParsedMemKind::Mod(m) =>
|
||||
MemKind::Module(Mod::from_parsed(m, path, ctx).boxed_local().await),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -452,7 +448,7 @@ pub struct LazyMemberHandle {
|
||||
}
|
||||
impl LazyMemberHandle {
|
||||
#[must_use]
|
||||
pub async fn run(mut self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> MemberKind {
|
||||
pub async fn run(mut self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> MemKind {
|
||||
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) => {
|
||||
@@ -460,12 +456,12 @@ impl LazyMemberHandle {
|
||||
let expr = Expr::from_api(c, PathSetBuilder::new(), ctx).await;
|
||||
let (.., path) = self.destructure();
|
||||
consts.insert(path, expr);
|
||||
MemberKind::Const
|
||||
MemKind::Const
|
||||
},
|
||||
api::MemberKind::Module(m) => {
|
||||
let (.., path) = self.destructure();
|
||||
MemberKind::Module(
|
||||
Module::from_api(m, &mut TreeFromApiCtx { sys: &sys, consts, path: path.tok() }).await,
|
||||
MemKind::Module(
|
||||
Mod::from_api(m, &mut TreeFromApiCtx { sys: &sys, consts, path: path.tok() }).await,
|
||||
)
|
||||
},
|
||||
api::MemberKind::Lazy(id) => {
|
||||
|
||||
Reference in New Issue
Block a user