temp commit

This commit is contained in:
2025-07-12 00:46:10 +02:00
parent 1868f1a506
commit fe89188c4b
60 changed files with 1536 additions and 709 deletions

View File

@@ -59,7 +59,7 @@ impl<'a> AtomReadGuard<'a> {
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
let guard = ctx.get_or_default::<ObjStore>().objects.read().await;
let valid = guard.iter().map(|i| i.0).collect_vec();
assert!(guard.get(&id).is_some(), "Received invalid atom ID: {:?} not in {:?}", id, valid);
assert!(guard.get(&id).is_some(), "Received invalid atom ID: {id:?} not in {valid:?}");
Self { id, guard }
}
}

View File

@@ -5,7 +5,7 @@ use std::num::NonZero;
use std::pin::Pin;
use std::rc::Rc;
use async_std::channel::{self, Receiver, RecvError, Sender};
use async_std::channel::{self, Receiver, Sender};
use async_std::stream;
use async_std::sync::Mutex;
use futures::future::{LocalBoxFuture, join_all};
@@ -22,7 +22,7 @@ use orchid_base::logging::Logger;
use orchid_base::name::Sym;
use orchid_base::parse::{Comment, Snippet};
use orchid_base::reqnot::{ReqNot, RequestHandle, Requester};
use orchid_base::tree::{TokenVariant, ttv_from_api, ttv_into_api};
use orchid_base::tree::{TokenVariant, ttv_from_api};
use substack::Substack;
use trait_set::trait_set;
@@ -32,6 +32,7 @@ use crate::atom_owned::take_atom;
use crate::expr::{Expr, ExprHandle};
use crate::fs::VirtFS;
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
use crate::parser::{ParsCtx, get_const, linev_into_api};
use crate::system::{SysCtx, atom_by_idx};
use crate::system_ctor::{CtedObj, DynSystemCtor};
use crate::tree::{GenTok, GenTokTree, LazyMemberFactory, TreeIntoApiCtxImpl};
@@ -47,7 +48,6 @@ impl ExtensionData {
pub fn new(name: &'static str, systems: &'static [&'static dyn DynSystemCtor]) -> Self {
Self { name, systems }
}
// pub fn main(self) { extension_main(self) }
}
pub enum MemberRecord {
@@ -57,7 +57,6 @@ pub enum MemberRecord {
pub struct SystemRecord {
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
declfs: api::EagerVfs,
lazy_members: HashMap<api::TreeId, MemberRecord>,
ctx: SysCtx,
}
@@ -84,19 +83,6 @@ pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
cb(atom_record, ctx, id, data).await
}
// pub fn extension_main(data: ExtensionData) {
// if thread::Builder::new()
// .name(format!("ext-main:{}", data.name))
// .spawn(|| extension_main_logic(data))
// .unwrap()
// .join()
// .is_err()
// {
// process::exit(-1)
// }
// }
pub struct ExtensionOwner {
_interner_cell: Rc<RefCell<Option<Interner>>>,
_systems_lock: Rc<Mutex<HashMap<api::SysId, SystemRecord>>>,
@@ -109,12 +95,7 @@ impl ExtPort for ExtensionOwner {
Box::pin(async { self.out_send.send(msg.to_vec()).boxed_local().await.unwrap() })
}
fn recv(&self) -> LocalBoxFuture<'_, Option<Vec<u8>>> {
Box::pin(async {
match self.out_recv.recv().await {
Ok(v) => Some(v),
Err(RecvError) => None,
}
})
Box::pin(async { (self.out_recv.recv().await).ok() })
}
}
@@ -141,8 +122,7 @@ pub fn extension_init(
let get_ctx = clone!(systems_weak; move |id: api::SysId| clone!(systems_weak; async move {
let systems =
systems_weak.upgrade().expect("System table dropped before request processing done");
let x = systems.lock().await.get(&id).expect("System not found").ctx.clone();
x
systems.lock().await.get(&id).expect("System not found").ctx.clone()
}));
let init_ctx = {
clone!(interner_weak, spawner, logger);
@@ -200,32 +180,25 @@ pub fn extension_init(
.then(|mem| {
let (req, lazy_mems) = (&hand, &lazy_mems);
clone!(i, ctx; async move {
let name = i.i(&mem.name).await.to_api();
let value = mem.kind.into_api(&mut TreeIntoApiCtxImpl {
let mut tia_ctx = TreeIntoApiCtxImpl {
lazy_members: &mut *lazy_mems.lock().await,
sys: ctx,
basepath: &[],
path: Substack::Bottom,
req
})
.await;
(name, value)
};
(i.i(&mem.name).await.to_api(), mem.kind.into_api(&mut tia_ctx).await)
})
})
.collect()
.await;
let declfs = cted.inst().dyn_vfs().to_api_rec(&mut vfses, &i).await;
let record =
SystemRecord { declfs, vfses, ctx, lazy_members: lazy_mems.into_inner() };
let vfs = cted.inst().dyn_vfs().to_api_rec(&mut vfses, &i).await;
let record = SystemRecord { vfses, ctx, lazy_members: lazy_mems.into_inner() };
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
systems.lock().await.insert(new_sys.id, record);
hand
.handle(&new_sys, &api::NewSystemResponse {
lex_filter,
const_root,
line_types: vec![],
})
.await
let response =
api::NewSystemResponse { lex_filter, const_root, line_types: vec![], vfs };
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;
@@ -248,18 +221,13 @@ pub fn extension_init(
};
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
},
api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs @ api::GetVfs(sys_id))) => {
let systems = systems_weak.upgrade().expect("VFS root requested during shutdown");
let systems_g = systems.lock().await;
hand.handle(&get_vfs, &systems_g[&sys_id].declfs).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
},
api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => {
api::HostExtReq::VfsRead(vfs_read) => {
let api::VfsRead(sys_id, vfs_id, path) = &vfs_read;
let ctx = get_ctx(*sys_id).await;
let systems = systems_weak.upgrade().expect("VFS requested during shutdoown");
@@ -308,13 +276,18 @@ pub fn extension_init(
let parser =
parsers.iter().find(|p| p.line_head() == **name).expect("No parser candidate");
let module = Sym::from_api(*module, ctx.i()).await;
let o_line = match parser.parse(ctx.clone(), module, *exported, comments, tail).await
{
let pctx = ParsCtx::new(ctx.clone(), module);
let o_line = match parser.parse(pctx, *exported, comments, tail).await {
Err(e) => Err(e.to_api()),
Ok(t) => Ok(ttv_into_api(t, &mut (), &mut (ctx.clone(), &hand)).await),
Ok(t) => Ok(linev_into_api(t, ctx.clone(), &hand).await),
};
hand.handle(&pline, &o_line).await
},
api::HostExtReq::FetchParsedConst(ref fpc @ api::FetchParsedConst { id, sys }) => {
let ctx = get_ctx(sys).await;
let cnst = get_const(id, ctx.clone()).await;
hand.handle(fpc, &cnst.api_return(ctx, &hand).await).await
},
api::HostExtReq::AtomReq(atom_req) => {
let atom = atom_req.get_atom();
let atom_req = atom_req.clone();

View File

@@ -1,9 +1,11 @@
use std::borrow::Cow;
use std::num::NonZero;
use futures::FutureExt;
use futures::future::LocalBoxFuture;
use hashbrown::HashMap;
use orchid_base::interner::{Interner, Tok};
use orchid_base::pure_seq::pushed;
use crate::api;
use crate::system::SysCtx;
@@ -16,11 +18,58 @@ pub trait VirtFS: Send + Sync + 'static {
) -> LocalBoxFuture<'a, api::OrcResult<api::Loaded>>;
}
#[derive(Clone)]
pub struct DeclVmod(Cow<'static, [(&'static str, DeclFs)]>);
impl DeclVmod {
pub fn new(items: &'static [(&'static str, DeclFs)]) -> DeclVmod {
DeclVmod(Cow::Borrowed(items))
}
pub fn entry(
key: &'static str,
items: &'static [(&'static str, DeclFs)],
) -> (&'static str, DeclVmod) {
(key, DeclVmod(Cow::Borrowed(items)))
}
pub fn merge(&self, other: &Self) -> Result<Self, Vec<&'static str>> {
let mut items = Vec::new();
for (k, v1) in self.0.iter() {
items.push((*k, match other.0.iter().find(|(k2, _)| k == k2) {
Some((_, v2)) => v1.merge(v2).map_err(|e| pushed::<_, Vec<_>>(e, *k))?,
None => v1.clone(),
}));
}
for (k, v) in other.0.iter() {
if !items.iter().any(|(k2, _)| k2 == k) {
items.push((*k, v.clone()))
}
}
Ok(Self(Cow::Owned(items)))
}
pub async fn to_api_rec(
&self,
vfses: &mut HashMap<api::VfsId, &'static dyn VirtFS>,
i: &Interner,
) -> std::collections::HashMap<api::TStr, api::EagerVfs> {
let mut output = std::collections::HashMap::new();
for (k, v) in self.0.iter() {
output.insert(i.i::<String>(*k).await.to_api(), v.to_api_rec(vfses, i).boxed_local().await);
}
output
}
}
#[derive(Clone)]
pub enum DeclFs {
Lazy(&'static dyn VirtFS),
Mod(&'static [(&'static str, DeclFs)]),
Mod(DeclVmod),
}
impl DeclFs {
pub fn merge(&self, other: &Self) -> Result<Self, Vec<&'static str>> {
match (self, other) {
(Self::Mod(m1), Self::Mod(m2)) => Ok(Self::Mod(m1.merge(m2)?)),
(..) => Err(Vec::new()),
}
}
pub async fn to_api_rec(
&self,
vfses: &mut HashMap<api::VfsId, &'static dyn VirtFS>,
@@ -33,14 +82,7 @@ impl DeclFs {
vfses.insert(id, *fs);
api::EagerVfs::Lazy(id)
},
DeclFs::Mod(children) => {
let mut output = std::collections::HashMap::new();
for (k, v) in children.iter() {
output
.insert(i.i::<String>(*k).await.to_api(), v.to_api_rec(vfses, i).boxed_local().await);
}
api::EagerVfs::Eager(output)
},
DeclFs::Mod(m) => api::EagerVfs::Eager(m.to_api_rec(vfses, i).await),
}
}
}

View File

@@ -141,7 +141,7 @@ mod expr_func_derives {
macro_rules! expr_func_derive {
($arity: tt, $($t:ident),*) => {
paste::paste!{
pastey::paste!{
impl<
$($t: TryFromExpr, )*
Out: ToExpr,

View File

@@ -1,3 +1,4 @@
use std::fmt;
use std::future::Future;
use std::ops::RangeInclusive;
@@ -49,10 +50,15 @@ impl<'a> LexContext<'a> {
}
pub fn pos(&self, tail: &'a str) -> u32 { (self.text.len() - tail.len()) as u32 }
pub fn tok_ran(&self, len: u32, tail: &'a str) -> SrcRange {
SrcRange::new(self.pos(tail) - len..self.pos(tail), &self.src)
pub fn pos_tt(&self, tail_with: &'a str, tail_without: &'a str) -> SrcRange {
SrcRange::new(self.pos(tail_with)..self.pos(tail_without), &self.src)
}
pub fn pos_lt(&self, len: impl TryInto<u32, Error: fmt::Debug>, tail: &'a str) -> SrcRange {
SrcRange::new(self.pos(tail) - len.try_into().unwrap()..self.pos(tail), &self.src)
}
pub fn i(&self) -> &Interner { self.ctx.i() }
}
pub trait Lexer: Send + Sync + Sized + Default + 'static {

View File

@@ -1,50 +1,179 @@
use futures::future::LocalBoxFuture;
use std::marker::PhantomData;
use futures::FutureExt;
use futures::future::{LocalBoxFuture, join_all};
use itertools::Itertools;
use orchid_api::ResolveNames;
use orchid_base::error::OrcRes;
use orchid_base::id_store::IdStore;
use orchid_base::interner::Tok;
use orchid_base::location::SrcRange;
use orchid_base::name::Sym;
use orchid_base::parse::{Comment, Snippet};
use orchid_base::reqnot::{ReqHandlish, Requester};
use orchid_base::tree::ttv_into_api;
use crate::api;
use crate::expr::Expr;
use crate::gen_expr::GExpr;
use crate::system::SysCtx;
use crate::system::{SysCtx, SysCtxEntry};
use crate::tree::GenTokTree;
pub type GenSnippet<'a> = Snippet<'a, Expr, GExpr>;
pub trait Parser: Send + Sync + Sized + Default + 'static {
const LINE_HEAD: &'static str;
fn parse(
ctx: SysCtx,
module: Sym,
fn parse<'a>(
ctx: ParsCtx<'a>,
exported: bool,
comments: Vec<Comment>,
line: GenSnippet<'_>,
) -> impl Future<Output = OrcRes<Vec<GenTokTree>>> + '_;
line: GenSnippet<'a>,
) -> impl Future<Output = OrcRes<Vec<ParsedLine>>> + 'a;
}
pub trait DynParser: Send + Sync + 'static {
fn line_head(&self) -> &'static str;
fn parse<'a>(
&self,
ctx: SysCtx,
module: Sym,
ctx: ParsCtx<'a>,
exported: bool,
comments: Vec<Comment>,
line: GenSnippet<'a>,
) -> LocalBoxFuture<'a, OrcRes<Vec<GenTokTree>>>;
) -> LocalBoxFuture<'a, OrcRes<Vec<ParsedLine>>>;
}
impl<T: Parser> DynParser for T {
fn line_head(&self) -> &'static str { Self::LINE_HEAD }
fn parse<'a>(
&self,
ctx: SysCtx,
module: Sym,
ctx: ParsCtx<'a>,
exported: bool,
comments: Vec<Comment>,
line: GenSnippet<'a>,
) -> LocalBoxFuture<'a, OrcRes<Vec<GenTokTree>>> {
Box::pin(async move { Self::parse(ctx, module, exported, comments, line).await })
) -> LocalBoxFuture<'a, OrcRes<Vec<ParsedLine>>> {
Box::pin(async move { Self::parse(ctx, exported, comments, line).await })
}
}
pub type ParserObj = &'static dyn DynParser;
pub struct ParsCtx<'a> {
_parse: PhantomData<&'a mut ()>,
ctx: SysCtx,
module: Sym,
}
impl ParsCtx<'_> {
pub(crate) fn new(ctx: SysCtx, module: Sym) -> Self { Self { _parse: PhantomData, ctx, module } }
pub fn ctx(&self) -> &SysCtx { &self.ctx }
pub fn module(&self) -> Sym { self.module.clone() }
}
type BoxConstCallback = Box<dyn FnOnce(ConstCtx) -> LocalBoxFuture<'static, GExpr>>;
#[derive(Default)]
struct ParsedConstCtxEntry {
consts: IdStore<BoxConstCallback>,
}
impl SysCtxEntry for ParsedConstCtxEntry {}
pub struct ParsedLine {
pub sr: SrcRange,
pub comments: Vec<Comment>,
pub kind: ParsedLineKind,
}
impl ParsedLine {
pub async fn into_api(self, ctx: SysCtx, hand: &dyn ReqHandlish) -> api::ParsedLine {
api::ParsedLine {
comments: self.comments.into_iter().map(|c| c.to_api()).collect(),
source_range: self.sr.to_api(),
kind: match self.kind {
ParsedLineKind::Mem(mem) => api::ParsedLineKind::Member(api::ParsedMember {
name: mem.name.to_api(),
exported: mem.exported,
kind: match mem.kind {
ParsedMemKind::Const(cb) => api::ParsedMemberKind::Constant(api::ParsedConstId(
ctx.get_or_default::<ParsedConstCtxEntry>().consts.add(cb).id(),
)),
ParsedMemKind::Mod(plv) =>
api::ParsedMemberKind::Module(linev_into_api(plv, ctx, hand).boxed_local().await),
},
}),
ParsedLineKind::Rec(tv) =>
api::ParsedLineKind::Recursive(ttv_into_api(tv, &mut (), &mut (ctx, hand)).await),
},
}
}
}
pub(crate) async fn linev_into_api(
v: Vec<ParsedLine>,
ctx: SysCtx,
hand: &dyn ReqHandlish,
) -> Vec<api::ParsedLine> {
join_all(v.into_iter().map(|l| l.into_api(ctx.clone(), hand))).await
}
pub enum ParsedLineKind {
Mem(ParsedMem),
Rec(Vec<GenTokTree>),
}
pub struct ParsedMem {
name: Tok<String>,
exported: bool,
kind: ParsedMemKind,
}
pub enum ParsedMemKind {
Const(BoxConstCallback),
Mod(Vec<ParsedLine>),
}
impl ParsedMemKind {
pub fn cnst<F: AsyncFnOnce(ConstCtx) -> GExpr + 'static>(f: F) -> Self {
Self::Const(Box::new(|ctx| Box::pin(f(ctx))))
}
}
/* TODO: how the macro runner uses the multi-stage loader
Since the macro runner actually has to invoke the interpreter,
it'll run at const-time and not at postparse-time anyway.
pasing stage establishes the role of every constant as a macro keyword
postparse / const load links up constants with every macro they can directly invoke
the constants representing the keywords might not actually be postparsed,
\ the connection is instead made by detecting in the macro system that the
\ resolved name is owned by a macro
the returned constant from this call is always an entrypoint call to
\ the macro system
the constants representing the keywords resolve to panic
execute relies on these links detected in the extension to dispatch relevant macros
*/
pub struct ConstCtx {
ctx: SysCtx,
constid: api::ParsedConstId,
}
impl ConstCtx {
pub async fn names<const N: usize>(&self, names: [&Sym; N]) -> [Option<Sym>; N] {
let resolve_names = ResolveNames {
constid: self.constid,
sys: self.ctx.sys_id(),
names: names.into_iter().map(|n| n.to_api()).collect_vec(),
};
let names = self.ctx.reqnot().request(resolve_names).await;
let mut results = [const { None }; N];
for (i, name) in names.into_iter().enumerate().filter_map(|(i, n)| Some((i, n?))) {
results[i] = Some(Sym::from_api(name, self.ctx.i()).await);
}
results
}
}
pub(crate) async fn get_const(id: api::ParsedConstId, ctx: SysCtx) -> GExpr {
let ent = ctx.get::<ParsedConstCtxEntry>();
let rec = ent.consts.get(id.0).expect("Bad ID or double read of parsed const");
let ctx = ConstCtx { constid: id, ctx: ctx.clone() };
rec.remove()(ctx).await
}

View File

@@ -18,7 +18,7 @@ use orchid_base::reqnot::{Receipt, ReqNot};
use crate::api;
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TypAtom, get_info};
use crate::entrypoint::ExtReq;
use crate::fs::DeclFs;
use crate::fs::DeclVmod;
use crate::func_atom::Fun;
use crate::lexer::LexerObj;
use crate::parser::ParserObj;
@@ -83,7 +83,7 @@ impl<T: SystemCard> DynSystemCard for T {
/// System as defined by author
pub trait System: Send + Sync + SystemCard + 'static {
fn env() -> Vec<GenMember>;
fn vfs() -> DeclFs;
fn vfs() -> DeclVmod;
fn lexers() -> Vec<LexerObj>;
fn parsers() -> Vec<ParserObj>;
fn request(hand: ExtReq<'_>, req: Self::Req) -> impl Future<Output = Receipt<'_>>;
@@ -91,7 +91,7 @@ pub trait System: Send + Sync + SystemCard + 'static {
pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
fn dyn_env(&self) -> Vec<GenMember>;
fn dyn_vfs(&self) -> DeclFs;
fn dyn_vfs(&self) -> DeclVmod;
fn dyn_lexers(&self) -> Vec<LexerObj>;
fn dyn_parsers(&self) -> Vec<ParserObj>;
fn dyn_request<'a>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>>;
@@ -100,7 +100,7 @@ pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
impl<T: System> DynSystem for T {
fn dyn_env(&self) -> Vec<GenMember> { Self::env() }
fn dyn_vfs(&self) -> DeclFs { Self::vfs() }
fn dyn_vfs(&self) -> DeclVmod { Self::vfs() }
fn dyn_lexers(&self) -> Vec<LexerObj> { Self::lexers() }
fn dyn_parsers(&self) -> Vec<ParserObj> { Self::parsers() }
fn dyn_request<'a>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>> {

View File

@@ -90,7 +90,7 @@ impl<T: SystemCtor> DynSystemCtor for T {
mod dep_set_tuple_impls {
use orchid_base::box_chain;
use orchid_base::boxed_iter::BoxedIter;
use paste::paste;
use pastey::paste;
use super::{DepDef, DepSat};
use crate::api;

View File

@@ -20,7 +20,7 @@ use crate::conv::ToExpr;
use crate::entrypoint::MemberRecord;
use crate::expr::{Expr, ExprHandle};
use crate::func_atom::{ExprFunc, Fun};
use crate::gen_expr::{GExpr, arg, call, lambda, seq};
use crate::gen_expr::{GExpr, arg, call, lambda, seq, sym_ref};
use crate::system::SysCtx;
pub type GenTokTree = TokTree<Expr, GExpr>;
@@ -65,6 +65,9 @@ impl TokenVariant<api::ExprTicket> for Expr {
}
}
pub fn x_tok(x: impl ToExpr) -> GenTok { GenTok::NewExpr(x.to_expr()) }
pub fn ref_tok(path: Sym) -> GenTok { GenTok::NewExpr(sym_ref(path)) }
pub fn cnst(public: bool, name: &str, value: impl ToExpr) -> Vec<GenMember> {
vec![GenMember {
name: name.to_string(),