exec working up to halt
clean shutdown doesn't for some reason
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
const user = "dave"
|
let user = "dave"
|
||||||
const main = println "Hello $user!" exit_status::success
|
let main = println "Hello $user!" exit_status::success
|
||||||
|
|||||||
@@ -270,7 +270,6 @@ impl Encode for bool {
|
|||||||
}
|
}
|
||||||
impl<T: Decode, const N: usize> Decode for [T; N] {
|
impl<T: Decode, const N: usize> Decode for [T; N] {
|
||||||
async fn decode<R: AsyncRead + ?Sized>(mut read: Pin<&mut R>) -> Self {
|
async fn decode<R: AsyncRead + ?Sized>(mut read: Pin<&mut R>) -> Self {
|
||||||
// TODO: figure out how to do this in safe rust on the stack
|
|
||||||
let v = stream(async |mut cx| {
|
let v = stream(async |mut cx| {
|
||||||
for _ in 0..N {
|
for _ in 0..N {
|
||||||
cx.emit(T::decode(read.as_mut()).await).await
|
cx.emit(T::decode(read.as_mut()).await).await
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ pub struct ParseLine {
|
|||||||
pub src: TStrv,
|
pub src: TStrv,
|
||||||
pub comments: Vec<Comment>,
|
pub comments: Vec<Comment>,
|
||||||
pub exported: bool,
|
pub exported: bool,
|
||||||
|
pub idx: u16,
|
||||||
pub line: Vec<TokenTree>,
|
pub line: Vec<TokenTree>,
|
||||||
}
|
}
|
||||||
impl Request for ParseLine {
|
impl Request for ParseLine {
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ pub fn parse_num(string: &str) -> Result<Numeric, NumError> {
|
|||||||
.or_else(|| string.strip_prefix("0b").map(|s| (2u8, s, 2)))
|
.or_else(|| string.strip_prefix("0b").map(|s| (2u8, s, 2)))
|
||||||
.or_else(|| string.strip_prefix("0o").map(|s| (8u8, s, 2)))
|
.or_else(|| string.strip_prefix("0o").map(|s| (8u8, s, 2)))
|
||||||
.unwrap_or((10u8, string, 0));
|
.unwrap_or((10u8, string, 0));
|
||||||
eprintln!("({radix}, {noprefix}, {pos})");
|
|
||||||
// identity
|
// identity
|
||||||
let (base_s, exponent) = match noprefix.split_once('p') {
|
let (base_s, exponent) = match noprefix.split_once('p') {
|
||||||
Some((b, e)) => {
|
Some((b, e)) => {
|
||||||
@@ -88,7 +87,6 @@ pub fn parse_num(string: &str) -> Result<Numeric, NumError> {
|
|||||||
},
|
},
|
||||||
None => (noprefix, 0),
|
None => (noprefix, 0),
|
||||||
};
|
};
|
||||||
eprintln!("({base_s},{exponent})");
|
|
||||||
match base_s.split_once('.') {
|
match base_s.split_once('.') {
|
||||||
None => {
|
None => {
|
||||||
let base = int_parse(base_s, radix, pos)?;
|
let base = int_parse(base_s, radix, pos)?;
|
||||||
|
|||||||
@@ -252,15 +252,14 @@ mod test {
|
|||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use orchid_api::LogStrategy;
|
|
||||||
use orchid_api_derive::Coding;
|
use orchid_api_derive::Coding;
|
||||||
use orchid_api_traits::{Channel, Request};
|
use orchid_api_traits::{Channel, Request};
|
||||||
use test_executors::spin_on;
|
use test_executors::spin_on;
|
||||||
|
|
||||||
use super::{MsgSet, ReqNot};
|
use super::{MsgSet, ReqNot};
|
||||||
use crate::clone;
|
|
||||||
use crate::logging::Logger;
|
use crate::logging::Logger;
|
||||||
use crate::reqnot::Requester as _;
|
use crate::reqnot::Requester as _;
|
||||||
|
use crate::{api, clone};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding, PartialEq)]
|
#[derive(Clone, Debug, Coding, PartialEq)]
|
||||||
pub struct TestReq(u8);
|
pub struct TestReq(u8);
|
||||||
@@ -283,7 +282,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn notification() {
|
fn notification() {
|
||||||
spin_on(async {
|
spin_on(async {
|
||||||
let logger = Logger::new(LogStrategy::StdErr);
|
let logger = Logger::new(api::LogStrategy::StdErr);
|
||||||
let received = Arc::new(Mutex::new(None));
|
let received = Arc::new(Mutex::new(None));
|
||||||
let receiver = ReqNot::<TestMsgSet>::new(
|
let receiver = ReqNot::<TestMsgSet>::new(
|
||||||
logger.clone(),
|
logger.clone(),
|
||||||
@@ -311,7 +310,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn request() {
|
fn request() {
|
||||||
spin_on(async {
|
spin_on(async {
|
||||||
let logger = Logger::new(LogStrategy::StdErr);
|
let logger = Logger::new(api::LogStrategy::StdErr);
|
||||||
let receiver = Rc::new(Mutex::<Option<ReqNot<TestMsgSet>>>::new(None));
|
let receiver = Rc::new(Mutex::<Option<ReqNot<TestMsgSet>>>::new(None));
|
||||||
let sender = Rc::new(ReqNot::<TestMsgSet>::new(
|
let sender = Rc::new(ReqNot::<TestMsgSet>::new(
|
||||||
logger.clone(),
|
logger.clone(),
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ use futures::{AsyncRead, AsyncWrite, FutureExt};
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use memo_map::MemoMap;
|
use memo_map::MemoMap;
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_api::AtomId;
|
|
||||||
use orchid_api_traits::{Decode, Encode, enc_vec};
|
use orchid_api_traits::{Decode, Encode, enc_vec};
|
||||||
use orchid_base::error::OrcRes;
|
use orchid_base::error::OrcRes;
|
||||||
use orchid_base::format::{FmtCtx, FmtCtxImpl, FmtUnit};
|
use orchid_base::format::{FmtCtx, FmtCtxImpl, FmtUnit};
|
||||||
@@ -41,7 +40,6 @@ impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVari
|
|||||||
let mut data = enc_vec(&typ_id).await;
|
let mut data = enc_vec(&typ_id).await;
|
||||||
self.encode(Pin::<&mut Vec<u8>>::new(&mut data)).await;
|
self.encode(Pin::<&mut Vec<u8>>::new(&mut data)).await;
|
||||||
ctx.get_or_default::<ObjStore>().objects.read().await.insert(atom_id, Box::new(self));
|
ctx.get_or_default::<ObjStore>().objects.read().await.insert(atom_id, Box::new(self));
|
||||||
eprintln!("Created atom {:?} of type {}", atom_id, type_name::<A>());
|
|
||||||
api::Atom { drop: Some(atom_id), data, owner: ctx.sys_id() }
|
api::Atom { drop: Some(atom_id), data, owner: ctx.sys_id() }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -52,7 +50,7 @@ impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVari
|
|||||||
/// While an atom read guard is held, no atom can be removed.
|
/// While an atom read guard is held, no atom can be removed.
|
||||||
pub(crate) struct AtomReadGuard<'a> {
|
pub(crate) struct AtomReadGuard<'a> {
|
||||||
id: api::AtomId,
|
id: api::AtomId,
|
||||||
guard: RwLockReadGuard<'a, MemoMap<AtomId, Box<dyn DynOwnedAtom>>>,
|
guard: RwLockReadGuard<'a, MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>,
|
||||||
}
|
}
|
||||||
impl<'a> AtomReadGuard<'a> {
|
impl<'a> AtomReadGuard<'a> {
|
||||||
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
|
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use futures::channel::mpsc::{Receiver, Sender, channel};
|
use futures::channel::mpsc::{Sender, channel};
|
||||||
use futures::future::Fuse;
|
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use futures::{FutureExt, SinkExt, StreamExt, select};
|
use futures::stream::{self, LocalBoxStream};
|
||||||
|
use futures::{FutureExt, SinkExt, StreamExt};
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_base::error::OrcRes;
|
use orchid_base::error::OrcRes;
|
||||||
|
use orchid_base::format::{FmtCtx, FmtUnit};
|
||||||
|
|
||||||
use crate::atom::Atomic;
|
use crate::atom::Atomic;
|
||||||
use crate::atom_owned::{OwnedAtom, OwnedVariant};
|
use crate::atom_owned::{OwnedAtom, OwnedVariant};
|
||||||
@@ -19,35 +19,30 @@ use crate::gen_expr::{GExpr, arg, call, lambda, seq};
|
|||||||
enum Command {
|
enum Command {
|
||||||
Execute(GExpr, Sender<Expr>),
|
Execute(GExpr, Sender<Expr>),
|
||||||
Register(GExpr, Sender<Expr>),
|
Register(GExpr, Sender<Expr>),
|
||||||
|
Halt(GExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BuilderCoroutineData {
|
struct BuilderCoroutineData {
|
||||||
work: Fuse<Pin<Box<dyn Future<Output = GExpr>>>>,
|
name: Option<String>,
|
||||||
cmd_recv: Receiver<Command>,
|
receiver: Mutex<LocalBoxStream<'static, Command>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct BuilderCoroutine(Rc<Mutex<BuilderCoroutineData>>);
|
struct BuilderCoroutine(Rc<BuilderCoroutineData>);
|
||||||
impl BuilderCoroutine {
|
impl BuilderCoroutine {
|
||||||
pub async fn run(self) -> GExpr {
|
pub async fn run(self) -> GExpr {
|
||||||
let cmd = {
|
let cmd = self.0.receiver.lock().await.next().await;
|
||||||
let this = &mut *self.0.lock().await;
|
|
||||||
select! {
|
|
||||||
ret_val = &mut this.work => { return ret_val },
|
|
||||||
cmd_res = this.cmd_recv.next().fuse() => match cmd_res {
|
|
||||||
Some(cmd) => cmd,
|
|
||||||
None => return (&mut this.work).await
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match cmd {
|
match cmd {
|
||||||
Command::Execute(expr, reply) => call([
|
None => panic!("Before the stream ends, we should have gotten a Halt"),
|
||||||
|
Some(Command::Halt(expr)) => expr,
|
||||||
|
Some(Command::Execute(expr, reply)) => call([
|
||||||
lambda(0, [seq([
|
lambda(0, [seq([
|
||||||
arg(0),
|
arg(0),
|
||||||
call([Replier { reply, builder: self }.to_expr().await, arg(0)]),
|
call([Replier { reply, builder: self }.to_expr().await, arg(0)]),
|
||||||
])]),
|
])]),
|
||||||
expr,
|
expr,
|
||||||
]),
|
]),
|
||||||
Command::Register(expr, reply) =>
|
Some(Command::Register(expr, reply)) =>
|
||||||
call([Replier { reply, builder: self }.to_expr().await, expr]),
|
call([Replier { reply, builder: self }.to_expr().await, expr]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,16 +61,29 @@ impl OwnedAtom for Replier {
|
|||||||
type Refs = Never;
|
type Refs = Never;
|
||||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||||
async fn call(mut self, arg: Expr) -> GExpr {
|
async fn call(mut self, arg: Expr) -> GExpr {
|
||||||
let _ = self.reply.send(arg).await;
|
self.reply.send(arg).await.expect("What the heck");
|
||||||
|
std::mem::drop(self.reply);
|
||||||
self.builder.run().await
|
self.builder.run().await
|
||||||
}
|
}
|
||||||
|
async fn print_atom<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
|
match &self.builder.0.name {
|
||||||
|
None => "BuilderCoroutine".into(),
|
||||||
|
Some(name) => format!("BuilderCoroutine({name})").into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn exec<R: ToExpr>(f: impl for<'a> AsyncFnOnce(ExecHandle<'a>) -> R + 'static) -> GExpr {
|
pub async fn exec<R: ToExpr>(
|
||||||
|
debug: impl AsRef<str>,
|
||||||
|
f: impl for<'a> AsyncFnOnce(ExecHandle<'a>) -> R + 'static,
|
||||||
|
) -> GExpr {
|
||||||
let (cmd_snd, cmd_recv) = channel(0);
|
let (cmd_snd, cmd_recv) = channel(0);
|
||||||
let work =
|
let halt = async { Command::Halt(f(ExecHandle(cmd_snd, PhantomData)).await.to_expr().await) }
|
||||||
async { f(ExecHandle(cmd_snd, PhantomData)).await.to_expr().await }.boxed_local().fuse();
|
.into_stream();
|
||||||
let coro = BuilderCoroutine(Rc::new(Mutex::new(BuilderCoroutineData { cmd_recv, work })));
|
let coro = BuilderCoroutine(Rc::new(BuilderCoroutineData {
|
||||||
|
name: Some(debug.as_ref().to_string()),
|
||||||
|
receiver: Mutex::new(stream::select(halt, cmd_recv).boxed_local()),
|
||||||
|
}));
|
||||||
coro.run().await
|
coro.run().await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,12 +92,12 @@ static WEIRD_DROP_ERR: &str = "Coroutine dropped while we are being polled someh
|
|||||||
pub struct ExecHandle<'a>(Sender<Command>, PhantomData<&'a ()>);
|
pub struct ExecHandle<'a>(Sender<Command>, PhantomData<&'a ()>);
|
||||||
impl ExecHandle<'_> {
|
impl ExecHandle<'_> {
|
||||||
pub async fn exec<T: TryFromExpr>(&mut self, val: impl ToExpr) -> OrcRes<T> {
|
pub async fn exec<T: TryFromExpr>(&mut self, val: impl ToExpr) -> OrcRes<T> {
|
||||||
let (reply_snd, mut reply_recv) = channel(0);
|
let (reply_snd, mut reply_recv) = channel(1);
|
||||||
self.0.send(Command::Execute(val.to_expr().await, reply_snd)).await.expect(WEIRD_DROP_ERR);
|
self.0.send(Command::Execute(val.to_expr().await, reply_snd)).await.expect(WEIRD_DROP_ERR);
|
||||||
T::try_from_expr(reply_recv.next().await.expect(WEIRD_DROP_ERR)).await
|
T::try_from_expr(reply_recv.next().await.expect(WEIRD_DROP_ERR)).await
|
||||||
}
|
}
|
||||||
pub async fn register(&mut self, val: impl ToExpr) -> Expr {
|
pub async fn register(&mut self, val: impl ToExpr) -> Expr {
|
||||||
let (reply_snd, mut reply_recv) = channel(0);
|
let (reply_snd, mut reply_recv) = channel(1);
|
||||||
self.0.send(Command::Register(val.to_expr().await, reply_snd)).await.expect(WEIRD_DROP_ERR);
|
self.0.send(Command::Register(val.to_expr().await, reply_snd)).await.expect(WEIRD_DROP_ERR);
|
||||||
reply_recv.next().await.expect(WEIRD_DROP_ERR)
|
reply_recv.next().await.expect(WEIRD_DROP_ERR)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ use futures::lock::Mutex;
|
|||||||
use futures::{FutureExt, SinkExt, StreamExt, stream, stream_select};
|
use futures::{FutureExt, SinkExt, StreamExt, stream, stream_select};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_api::{ExtMsgSet, IntReq};
|
|
||||||
use orchid_api_traits::{Decode, UnderRoot, enc_vec};
|
use orchid_api_traits::{Decode, UnderRoot, enc_vec};
|
||||||
use orchid_base::builtin::{ExtInit, ExtPort, Spawner};
|
use orchid_base::builtin::{ExtInit, ExtPort, Spawner};
|
||||||
use orchid_base::char_filter::{char_filter_match, char_filter_union, mk_char_filter};
|
use orchid_base::char_filter::{char_filter_match, char_filter_union, mk_char_filter};
|
||||||
@@ -29,9 +28,9 @@ use trait_set::trait_set;
|
|||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId};
|
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId};
|
||||||
use crate::atom_owned::take_atom;
|
use crate::atom_owned::take_atom;
|
||||||
use crate::expr::{Expr, ExprHandle};
|
use crate::expr::{BorrowedExprStore, Expr, ExprHandle};
|
||||||
use crate::lexer::{LexContext, ekey_cascade, ekey_not_applicable};
|
use crate::lexer::{LexContext, ekey_cascade, ekey_not_applicable};
|
||||||
use crate::parser::{PTok, PTokTree, ParsCtx, get_const, linev_into_api};
|
use crate::parser::{PTokTree, ParsCtx, get_const, linev_into_api};
|
||||||
use crate::system::{SysCtx, atom_by_idx};
|
use crate::system::{SysCtx, atom_by_idx};
|
||||||
use crate::system_ctor::{CtedObj, DynSystemCtor};
|
use crate::system_ctor::{CtedObj, DynSystemCtor};
|
||||||
use crate::tree::{LazyMemberFactory, TreeIntoApiCtxImpl};
|
use crate::tree::{LazyMemberFactory, TreeIntoApiCtxImpl};
|
||||||
@@ -124,7 +123,7 @@ pub fn extension_init(
|
|||||||
}));
|
}));
|
||||||
let init_ctx = {
|
let init_ctx = {
|
||||||
clone!(interner_weak, spawner, logger);
|
clone!(interner_weak, spawner, logger);
|
||||||
move |id: api::SysId, cted: CtedObj, reqnot: ReqNot<ExtMsgSet>| {
|
move |id: api::SysId, cted: CtedObj, reqnot: ReqNot<api::ExtMsgSet>| {
|
||||||
clone!(interner_weak, spawner, logger; async move {
|
clone!(interner_weak, spawner, logger; async move {
|
||||||
let interner_rc =
|
let interner_rc =
|
||||||
interner_weak.upgrade().expect("System construction order while shutting down");
|
interner_weak.upgrade().expect("System construction order while shutting down");
|
||||||
@@ -242,49 +241,62 @@ pub fn extension_init(
|
|||||||
let text = Tok::from_api(text, &i).await;
|
let text = Tok::from_api(text, &i).await;
|
||||||
let src = Sym::from_api(src, sys_ctx.i()).await;
|
let src = Sym::from_api(src, sys_ctx.i()).await;
|
||||||
let rep = Reporter::new();
|
let rep = Reporter::new();
|
||||||
let ctx = LexContext { id, pos, text: &text, src, ctx: sys_ctx.clone(), rep: &rep };
|
let expr_store = BorrowedExprStore::new();
|
||||||
let trigger_char = text.chars().nth(pos as usize).unwrap();
|
let trigger_char = text.chars().nth(pos as usize).unwrap();
|
||||||
let ekey_na = ekey_not_applicable(&i).await;
|
let ekey_na = ekey_not_applicable(&i).await;
|
||||||
let ekey_cascade = ekey_cascade(&i).await;
|
let ekey_cascade = ekey_cascade(&i).await;
|
||||||
let lexers = sys_ctx.cted().inst().dyn_lexers();
|
let lexers = sys_ctx.cted().inst().dyn_lexers();
|
||||||
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char)) {
|
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 {
|
match lx.lex(&text[pos as usize..], &ctx).await {
|
||||||
Err(e) if e.any(|e| *e == ekey_na) => continue,
|
Err(e) if e.any(|e| *e == ekey_na) => continue,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let eopt = e.keep_only(|e| *e != ekey_cascade).map(|e| Err(e.to_api()));
|
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;
|
return hand.handle(&lex, &eopt).await;
|
||||||
},
|
},
|
||||||
Ok((s, expr)) => {
|
Ok((s, expr)) => {
|
||||||
let expr = expr.into_api(&mut (), &mut (sys_ctx, &hand)).await;
|
let expr = expr.into_api(&mut (), &mut (sys_ctx, &hand)).await;
|
||||||
let pos = (text.len() - s.len()) as u32;
|
let pos = (text.len() - s.len()) as u32;
|
||||||
|
expr_store.dispose().await;
|
||||||
return hand.handle(&lex, &Some(Ok(api::LexedExpr { pos, expr }))).await;
|
return hand.handle(&lex, &Some(Ok(api::LexedExpr { pos, expr }))).await;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(logger, "Got notified about n/a character '{trigger_char}'");
|
writeln!(logger, "Got notified about n/a character '{trigger_char}'");
|
||||||
|
expr_store.dispose().await;
|
||||||
hand.handle(&lex, &None).await
|
hand.handle(&lex, &None).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::ParseLine(pline) => {
|
api::HostExtReq::ParseLine(pline) => {
|
||||||
let api::ParseLine { module, src, exported, comments, sys, line } = &pline;
|
let api::ParseLine { module, src, exported, comments, sys, line, idx } = &pline;
|
||||||
let mut ctx = get_ctx(*sys).await;
|
let ctx = get_ctx(*sys).await;
|
||||||
let parsers = ctx.cted().inst().dyn_parsers();
|
let parsers = ctx.cted().inst().dyn_parsers();
|
||||||
let src = Sym::from_api(*src, ctx.i()).await;
|
let src = Sym::from_api(*src, ctx.i()).await;
|
||||||
let comments =
|
let comments =
|
||||||
join_all(comments.iter().map(|c| Comment::from_api(c, src.clone(), &i))).await;
|
join_all(comments.iter().map(|c| Comment::from_api(c, src.clone(), &i))).await;
|
||||||
let line: Vec<PTokTree> = ttv_from_api(line, &mut ctx, &mut (), &src, &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 snip = Snippet::new(line.first().expect("Empty line"), &line);
|
||||||
let (head, tail) = snip.pop_front().unwrap();
|
let parser = parsers[*idx as usize];
|
||||||
let name = if let PTok::Name(n) = &head.tok { n } else { panic!("No line head") };
|
|
||||||
let parser =
|
|
||||||
parsers.iter().find(|p| p.line_head() == **name).expect("No parser candidate");
|
|
||||||
let module = Sym::from_api(*module, ctx.i()).await;
|
let module = Sym::from_api(*module, ctx.i()).await;
|
||||||
let reporter = Reporter::new();
|
let reporter = Reporter::new();
|
||||||
let pctx = ParsCtx::new(ctx.clone(), module, &reporter);
|
let pctx = ParsCtx::new(ctx.clone(), module, &reporter);
|
||||||
let parse_res = parser.parse(pctx, *exported, comments, tail).await;
|
let parse_res = parser.parse(pctx, *exported, comments, snip).await;
|
||||||
let o_line = match reporter.merge(parse_res) {
|
let o_line = match reporter.merge(parse_res) {
|
||||||
Err(e) => Err(e.to_api()),
|
Err(e) => Err(e.to_api()),
|
||||||
Ok(t) => Ok(linev_into_api(t, ctx.clone(), &hand).await),
|
Ok(t) => Ok(linev_into_api(t, ctx.clone(), &hand).await),
|
||||||
};
|
};
|
||||||
|
expr_store.dispose().await;
|
||||||
hand.handle(&pline, &o_line).await
|
hand.handle(&pline, &o_line).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::FetchParsedConst(ref fpc @ api::FetchParsedConst { id, sys }) => {
|
api::HostExtReq::FetchParsedConst(ref fpc @ api::FetchParsedConst { id, sys }) => {
|
||||||
@@ -297,6 +309,7 @@ pub fn extension_init(
|
|||||||
let atom_req = atom_req.clone();
|
let atom_req = atom_req.clone();
|
||||||
with_atom_record(&get_ctx, atom, async move |nfo, ctx, id, buf| {
|
with_atom_record(&get_ctx, atom, async move |nfo, ctx, id, buf| {
|
||||||
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
||||||
|
|
||||||
match &atom_req {
|
match &atom_req {
|
||||||
api::AtomReq::SerializeAtom(ser) => {
|
api::AtomReq::SerializeAtom(ser) => {
|
||||||
let mut buf = enc_vec(&id).await;
|
let mut buf = enc_vec(&id).await;
|
||||||
@@ -327,16 +340,23 @@ pub fn extension_init(
|
|||||||
hand.handle(fwded, &some.then_some(reply)).await
|
hand.handle(fwded, &some.then_some(reply)).await
|
||||||
},
|
},
|
||||||
api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => {
|
api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => {
|
||||||
// SAFETY: function calls own their argument implicitly
|
// SAFETY: function calls borrow their argument implicitly
|
||||||
let expr_handle = unsafe { ExprHandle::from_args(ctx.clone(), *arg) };
|
let expr_store = BorrowedExprStore::new();
|
||||||
let ret = nfo.call_ref(actx, Expr::from_handle(Rc::new(expr_handle))).await;
|
let expr_handle = ExprHandle::borrowed(ctx.clone(), *arg, &expr_store);
|
||||||
hand.handle(call, &ret.api_return(ctx.clone(), &hand).await).await
|
let ret = nfo.call_ref(actx, Expr::from_handle(expr_handle.clone())).await;
|
||||||
|
expr_handle.drop_one().await;
|
||||||
|
let api_expr = ret.api_return(ctx.clone(), &hand).await;
|
||||||
|
expr_store.dispose().await;
|
||||||
|
hand.handle(call, &api_expr).await
|
||||||
},
|
},
|
||||||
api::AtomReq::FinalCall(call @ api::FinalCall(_, arg)) => {
|
api::AtomReq::FinalCall(call @ api::FinalCall(_, arg)) => {
|
||||||
// SAFETY: function calls own their argument implicitly
|
// SAFETY: function calls borrow their argument implicitly
|
||||||
let expr_handle = unsafe { ExprHandle::from_args(ctx.clone(), *arg) };
|
let expr_store = BorrowedExprStore::new();
|
||||||
let ret = nfo.call(actx, Expr::from_handle(Rc::new(expr_handle))).await;
|
let expr_handle = ExprHandle::borrowed(ctx.clone(), *arg, &expr_store);
|
||||||
hand.handle(call, &ret.api_return(ctx.clone(), &hand).await).await
|
let ret = nfo.call(actx, Expr::from_handle(expr_handle.clone())).await;
|
||||||
|
let api_expr = ret.api_return(ctx.clone(), &hand).await;
|
||||||
|
expr_store.dispose().await;
|
||||||
|
hand.handle(call, &api_expr).await
|
||||||
},
|
},
|
||||||
api::AtomReq::Command(cmd @ api::Command(_)) => match nfo.command(actx).await {
|
api::AtomReq::Command(cmd @ api::Command(_)) => match nfo.command(actx).await {
|
||||||
Err(e) => hand.handle(cmd, &Err(e.to_api())).await,
|
Err(e) => hand.handle(cmd, &Err(e.to_api())).await,
|
||||||
@@ -358,8 +378,7 @@ pub fn extension_init(
|
|||||||
let ctx = get_ctx(*sys).await;
|
let ctx = get_ctx(*sys).await;
|
||||||
// SAFETY: deserialization implicitly grants ownership to previously owned exprs
|
// SAFETY: deserialization implicitly grants ownership to previously owned exprs
|
||||||
let refs = (refs.iter())
|
let refs = (refs.iter())
|
||||||
.map(|tk| unsafe { ExprHandle::from_args(ctx.clone(), *tk) })
|
.map(|tk| Expr::from_handle(ExprHandle::deserialize(ctx.clone(), *tk)))
|
||||||
.map(|handle| Expr::from_handle(Rc::new(handle)))
|
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let id = AtomTypeId::decode(Pin::new(&mut read)).await;
|
let id = AtomTypeId::decode(Pin::new(&mut read)).await;
|
||||||
let inst = ctx.cted().inst();
|
let inst = ctx.cted().inst();
|
||||||
@@ -373,7 +392,7 @@ pub fn extension_init(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
*interner_cell.borrow_mut() =
|
*interner_cell.borrow_mut() =
|
||||||
Some(Interner::new_replica(rn.clone().map(|ir: IntReq| ir.into_root())));
|
Some(Interner::new_replica(rn.clone().map(|ir: api::IntReq| ir.into_root())));
|
||||||
spawner(Box::pin(clone!(spawner; async move {
|
spawner(Box::pin(clone!(spawner; async move {
|
||||||
let mut streams = stream_select! { in_recv.map(Some), exit_recv.map(|_| None) };
|
let mut streams = stream_select! { in_recv.map(Some), exit_recv.map(|_| None) };
|
||||||
while let Some(item) = streams.next().await {
|
while let Some(item) = streams.next().await {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::hash::Hash;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use async_once_cell::OnceCell;
|
use async_once_cell::OnceCell;
|
||||||
use derive_destructure::destructure;
|
use derive_destructure::destructure;
|
||||||
use orchid_api::ExtAtomPrint;
|
use hashbrown::HashSet;
|
||||||
use orchid_base::error::OrcErrv;
|
use orchid_base::error::OrcErrv;
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
@@ -14,26 +16,61 @@ use crate::atom::ForeignAtom;
|
|||||||
use crate::gen_expr::{GExpr, GExprKind};
|
use crate::gen_expr::{GExpr, GExprKind};
|
||||||
use crate::system::SysCtx;
|
use crate::system::SysCtx;
|
||||||
|
|
||||||
|
pub struct BorrowedExprStore(RefCell<Option<HashSet<Rc<ExprHandle>>>>);
|
||||||
|
impl BorrowedExprStore {
|
||||||
|
pub(crate) fn new() -> Self { Self(RefCell::new(Some(HashSet::new()))) }
|
||||||
|
pub async fn dispose(self) {
|
||||||
|
let elements = self.0.borrow_mut().take().unwrap();
|
||||||
|
for handle in elements {
|
||||||
|
handle.drop_one().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Drop for BorrowedExprStore {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.0.borrow().is_some() {
|
||||||
|
panic!("This should always be explicitly disposed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(destructure)]
|
#[derive(destructure)]
|
||||||
pub struct ExprHandle {
|
pub struct ExprHandle {
|
||||||
pub tk: api::ExprTicket,
|
pub tk: api::ExprTicket,
|
||||||
pub ctx: SysCtx,
|
pub ctx: SysCtx,
|
||||||
}
|
}
|
||||||
impl ExprHandle {
|
impl ExprHandle {
|
||||||
/// # Safety
|
/// This function does not signal to take ownership of the expr.
|
||||||
///
|
pub fn borrowed(ctx: SysCtx, tk: api::ExprTicket, store: &BorrowedExprStore) -> Rc<Self> {
|
||||||
/// This function does not signal to take ownership of the expr. It must only
|
let this = Rc::new(Self { ctx, tk });
|
||||||
/// be called on tickets that are already implicitly owned.
|
store.0.borrow_mut().as_mut().unwrap().insert(this.clone());
|
||||||
pub unsafe fn from_args(ctx: SysCtx, tk: api::ExprTicket) -> Self { Self { ctx, tk } }
|
this
|
||||||
|
}
|
||||||
|
pub fn deserialize(ctx: SysCtx, tk: api::ExprTicket) -> Rc<Self> { Rc::new(Self { ctx, tk }) }
|
||||||
pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() }
|
pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() }
|
||||||
pub async fn clone(&self) -> Self {
|
/// Drop one instance of the handle silently; if it's the last one, do
|
||||||
self.ctx.reqnot().notify(api::Acquire(self.ctx.sys_id(), self.tk)).await;
|
/// nothing, otherwise send an Acquire
|
||||||
Self { ctx: self.ctx.clone(), tk: self.tk }
|
pub async fn drop_one(self: Rc<Self>) {
|
||||||
|
if let Err(rc) = Rc::try_unwrap(self) {
|
||||||
|
rc.ctx.reqnot().notify(api::Acquire(rc.ctx.sys_id(), rc.tk)).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Drop the handle and get the ticket without a release notification.
|
/// Drop the handle and get the ticket without a release notification.
|
||||||
/// Use this with messages that imply ownership transfer. This function is
|
/// Use this with messages that imply ownership transfer. This function is
|
||||||
/// safe because abusing it is a memory leak.
|
/// safe because abusing it is a memory leak.
|
||||||
pub fn into_tk(self) -> api::ExprTicket { self.destructure().0 }
|
pub fn serialize(self) -> api::ExprTicket { self.destructure().0 }
|
||||||
|
}
|
||||||
|
impl Eq for ExprHandle {}
|
||||||
|
impl PartialEq for ExprHandle {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.ctx.sys_id() == other.ctx.sys_id() && self.tk == other.tk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Hash for ExprHandle {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.ctx.sys_id().hash(state);
|
||||||
|
self.tk.hash(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl fmt::Debug for ExprHandle {
|
impl fmt::Debug for ExprHandle {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
@@ -92,8 +129,9 @@ impl Format for Expr {
|
|||||||
match &self.data().await.kind {
|
match &self.data().await.kind {
|
||||||
ExprKind::Opaque => "OPAQUE".to_string().into(),
|
ExprKind::Opaque => "OPAQUE".to_string().into(),
|
||||||
ExprKind::Bottom(b) => format!("Bottom({b})").into(),
|
ExprKind::Bottom(b) => format!("Bottom({b})").into(),
|
||||||
ExprKind::Atom(a) =>
|
ExprKind::Atom(a) => FmtUnit::from_api(
|
||||||
FmtUnit::from_api(&self.handle.ctx.reqnot().request(ExtAtomPrint(a.atom.clone())).await),
|
&self.handle.ctx.reqnot().request(api::ExtAtomPrint(a.atom.clone())).await,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
//! #TODO: redefine this in terms of [crate::coroutine_exec::exec]. Try
|
|
||||||
//! differentiating between eager and lazy arguments. [ExprFunc] can remain with
|
|
||||||
//! tweaks but other techniques probably must go.
|
|
||||||
//!
|
|
||||||
//! Notice also that Func must still be resumable
|
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -48,11 +43,14 @@ struct FunRecord {
|
|||||||
fun: Rc<dyn FunCB>,
|
fun: Rc<dyn FunCB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_args<I, O, F: ExprFunc<I, O>>(f: F) -> FunRecord {
|
async fn process_args<I, O, F: ExprFunc<I, O>>(
|
||||||
|
debug: impl AsRef<str> + Clone + 'static,
|
||||||
|
f: F,
|
||||||
|
) -> FunRecord {
|
||||||
let argtyps = F::argtyps();
|
let argtyps = F::argtyps();
|
||||||
let fun = Rc::new(move |v: Vec<Expr>| {
|
let fun = Rc::new(move |v: Vec<Expr>| {
|
||||||
clone!(f, v mut);
|
clone!(f, v mut);
|
||||||
exec(async move |mut hand| {
|
exec(debug.clone(), async move |mut hand| {
|
||||||
let mut norm_args = Vec::with_capacity(v.len());
|
let mut norm_args = Vec::with_capacity(v.len());
|
||||||
for (expr, typ) in v.into_iter().zip(argtyps) {
|
for (expr, typ) in v.into_iter().zip(argtyps) {
|
||||||
if *typ != TypeId::of::<Expr>() {
|
if *typ != TypeId::of::<Expr>() {
|
||||||
@@ -85,7 +83,7 @@ impl Fun {
|
|||||||
let record = if let Some(record) = fung.get(&path) {
|
let record = if let Some(record) = fung.get(&path) {
|
||||||
record.clone()
|
record.clone()
|
||||||
} else {
|
} else {
|
||||||
let record = process_args(f).await;
|
let record = process_args(path.to_string(), f).await;
|
||||||
fung.insert(path.clone(), record.clone());
|
fung.insert(path.clone(), record.clone());
|
||||||
record
|
record
|
||||||
};
|
};
|
||||||
@@ -101,7 +99,6 @@ impl OwnedAtom for Fun {
|
|||||||
type Refs = Vec<Expr>;
|
type Refs = Vec<Expr>;
|
||||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||||
async fn call_ref(&self, arg: Expr) -> GExpr {
|
async fn call_ref(&self, arg: Expr) -> GExpr {
|
||||||
std::io::Write::flush(&mut std::io::stderr()).unwrap();
|
|
||||||
let new_args = self.args.iter().cloned().chain([arg]).collect_vec();
|
let new_args = self.args.iter().cloned().chain([arg]).collect_vec();
|
||||||
if new_args.len() == self.record.argtyps.len() {
|
if new_args.len() == self.record.argtyps.len() {
|
||||||
(self.record.fun)(new_args).await.to_expr().await
|
(self.record.fun)(new_args).await.to_expr().await
|
||||||
@@ -137,8 +134,11 @@ pub struct Lambda {
|
|||||||
record: FunRecord,
|
record: FunRecord,
|
||||||
}
|
}
|
||||||
impl Lambda {
|
impl Lambda {
|
||||||
pub async fn new<I, O, F: ExprFunc<I, O>>(f: F) -> Self {
|
pub async fn new<I, O, F: ExprFunc<I, O>>(
|
||||||
Self { args: vec![], record: process_args(f).await }
|
debug: impl AsRef<str> + Clone + 'static,
|
||||||
|
f: F,
|
||||||
|
) -> Self {
|
||||||
|
Self { args: vec![], record: process_args(debug, f).await }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Atomic for Lambda {
|
impl Atomic for Lambda {
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ impl GExprKind {
|
|||||||
Lambda(arg, body => Box::new(body.api_return(ctx, hand).await)),
|
Lambda(arg, body => Box::new(body.api_return(ctx, hand).await)),
|
||||||
Arg(arg),
|
Arg(arg),
|
||||||
Const(name.to_api()),
|
Const(name.to_api()),
|
||||||
Const(name.to_api()),
|
|
||||||
Bottom(err.to_api()),
|
Bottom(err.to_api()),
|
||||||
NewAtom(fac.clone().build(ctx).await),
|
NewAtom(fac.clone().build(ctx).await),
|
||||||
} {
|
} {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use orchid_base::parse::ParseCtx;
|
|||||||
use orchid_base::reqnot::Requester;
|
use orchid_base::reqnot::Requester;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
|
use crate::expr::BorrowedExprStore;
|
||||||
use crate::parser::PTokTree;
|
use crate::parser::PTokTree;
|
||||||
use crate::system::SysCtx;
|
use crate::system::SysCtx;
|
||||||
use crate::tree::GenTokTree;
|
use crate::tree::GenTokTree;
|
||||||
@@ -34,6 +35,7 @@ pub async fn err_not_applicable(i: &Interner) -> OrcErrv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct LexContext<'a> {
|
pub struct LexContext<'a> {
|
||||||
|
pub(crate) exprs: &'a BorrowedExprStore,
|
||||||
pub ctx: SysCtx,
|
pub ctx: SysCtx,
|
||||||
pub text: &'a Tok<String>,
|
pub text: &'a Tok<String>,
|
||||||
pub id: api::ParsId,
|
pub id: api::ParsId,
|
||||||
@@ -52,8 +54,14 @@ impl<'a> LexContext<'a> {
|
|||||||
let Some(lx) = self.ctx.reqnot().request(api::SubLex { pos: start, id: self.id }).await else {
|
let Some(lx) = self.ctx.reqnot().request(api::SubLex { pos: start, id: self.id }).await else {
|
||||||
return Err(err_cascade(self.ctx.i()).await);
|
return Err(err_cascade(self.ctx.i()).await);
|
||||||
};
|
};
|
||||||
let tree =
|
let tree = PTokTree::from_api(
|
||||||
PTokTree::from_api(&lx.tree, &mut self.ctx.clone(), &mut (), &self.src, self.ctx.i()).await;
|
&lx.tree,
|
||||||
|
&mut (self.ctx.clone(), self.exprs),
|
||||||
|
&mut (),
|
||||||
|
&self.src,
|
||||||
|
self.ctx.i(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
Ok((&self.text[lx.pos as usize..], tree))
|
Ok((&self.text[lx.pos as usize..], tree))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use futures::future::{LocalBoxFuture, join_all};
|
|||||||
use futures::{FutureExt, Stream, StreamExt};
|
use futures::{FutureExt, Stream, StreamExt};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_api::ResolveNames;
|
|
||||||
use orchid_base::error::{OrcErrv, OrcRes, Reporter};
|
use orchid_base::error::{OrcErrv, OrcRes, Reporter};
|
||||||
use orchid_base::id_store::IdStore;
|
use orchid_base::id_store::IdStore;
|
||||||
use orchid_base::interner::{Interner, Tok};
|
use orchid_base::interner::{Interner, Tok};
|
||||||
@@ -186,21 +185,6 @@ pub enum ParsedMemKind {
|
|||||||
Mod { lines: Vec<ParsedLine>, use_prelude: bool },
|
Mod { lines: Vec<ParsedLine>, use_prelude: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
|
||||||
*/
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ConstCtx {
|
pub struct ConstCtx {
|
||||||
ctx: SysCtx,
|
ctx: SysCtx,
|
||||||
@@ -213,7 +197,7 @@ impl ConstCtx {
|
|||||||
&'b self,
|
&'b self,
|
||||||
names: impl IntoIterator<Item = &'b Sym> + 'b,
|
names: impl IntoIterator<Item = &'b Sym> + 'b,
|
||||||
) -> impl Stream<Item = OrcRes<Sym>> + 'b {
|
) -> impl Stream<Item = OrcRes<Sym>> + 'b {
|
||||||
let resolve_names = ResolveNames {
|
let resolve_names = api::ResolveNames {
|
||||||
constid: self.constid,
|
constid: self.constid,
|
||||||
sys: self.ctx.sys_id(),
|
sys: self.ctx.sys_id(),
|
||||||
names: names.into_iter().map(|n| n.to_api()).collect_vec(),
|
names: names.into_iter().map(|n| n.to_api()).collect_vec(),
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use std::rc::{Rc, Weak};
|
|||||||
|
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::future::LocalBoxFuture;
|
||||||
use memo_map::MemoMap;
|
use memo_map::MemoMap;
|
||||||
use orchid_api::ExtMsgSet;
|
|
||||||
use orchid_api_traits::{Coding, Decode};
|
use orchid_api_traits::{Coding, Decode};
|
||||||
use orchid_base::boxed_iter::BoxedIter;
|
use orchid_base::boxed_iter::BoxedIter;
|
||||||
use orchid_base::builtin::Spawner;
|
use orchid_base::builtin::Spawner;
|
||||||
@@ -18,8 +17,9 @@ use orchid_base::reqnot::{Receipt, ReqNot};
|
|||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TypAtom, get_info};
|
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TypAtom, get_info};
|
||||||
|
use crate::coroutine_exec::Replier;
|
||||||
use crate::entrypoint::ExtReq;
|
use crate::entrypoint::ExtReq;
|
||||||
use crate::func_atom::Fun;
|
use crate::func_atom::{Fun, Lambda};
|
||||||
use crate::lexer::LexerObj;
|
use crate::lexer::LexerObj;
|
||||||
use crate::parser::ParserObj;
|
use crate::parser::ParserObj;
|
||||||
use crate::system_ctor::{CtedObj, SystemCtor};
|
use crate::system_ctor::{CtedObj, SystemCtor};
|
||||||
@@ -43,7 +43,7 @@ pub trait DynSystemCard: Send + Sync + 'static {
|
|||||||
/// The indices of these are bitwise negated, such that the MSB of an atom index
|
/// The indices of these are bitwise negated, such that the MSB of an atom index
|
||||||
/// marks whether it belongs to this package (0) or the importer (1)
|
/// marks whether it belongs to this package (0) or the importer (1)
|
||||||
fn general_atoms() -> impl Iterator<Item = Option<Box<dyn AtomDynfo>>> {
|
fn general_atoms() -> impl Iterator<Item = Option<Box<dyn AtomDynfo>>> {
|
||||||
[Some(Fun::dynfo())].into_iter()
|
[Some(Fun::dynfo()), Some(Lambda::dynfo()), Some(Replier::dynfo())].into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn atom_info_for(
|
pub fn atom_info_for(
|
||||||
@@ -149,7 +149,7 @@ impl SysCtx {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
id: api::SysId,
|
id: api::SysId,
|
||||||
i: Interner,
|
i: Interner,
|
||||||
reqnot: ReqNot<ExtMsgSet>,
|
reqnot: ReqNot<api::ExtMsgSet>,
|
||||||
spawner: Spawner,
|
spawner: Spawner,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
cted: CtedObj,
|
cted: CtedObj,
|
||||||
@@ -167,13 +167,7 @@ impl SysCtx {
|
|||||||
(self.0.get_or_insert_owned(TypeId::of::<T>(), || Box::new(f())).downcast_ref())
|
(self.0.get_or_insert_owned(TypeId::of::<T>(), || Box::new(f())).downcast_ref())
|
||||||
.expect("Keyed by TypeId")
|
.expect("Keyed by TypeId")
|
||||||
}
|
}
|
||||||
pub fn get_or_default<T: SysCtxEntry + Default>(&self) -> &T {
|
pub fn get_or_default<T: SysCtxEntry + Default>(&self) -> &T { self.get_or_insert(T::default) }
|
||||||
self.get_or_insert(|| {
|
|
||||||
let rc_id = self.0.as_ref() as *const _ as *const () as usize;
|
|
||||||
eprintln!("Default-initializing {} in {}", type_name::<T>(), rc_id);
|
|
||||||
T::default()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn try_get<T: SysCtxEntry>(&self) -> Option<&T> {
|
pub fn try_get<T: SysCtxEntry>(&self) -> Option<&T> {
|
||||||
Some(self.0.get(&TypeId::of::<T>())?.downcast_ref().expect("Keyed by TypeId"))
|
Some(self.0.get(&TypeId::of::<T>())?.downcast_ref().expect("Keyed by TypeId"))
|
||||||
}
|
}
|
||||||
@@ -183,7 +177,7 @@ impl SysCtx {
|
|||||||
/// Shorthand to get the [Interner] instance
|
/// Shorthand to get the [Interner] instance
|
||||||
pub fn i(&self) -> &Interner { self.get::<Interner>() }
|
pub fn i(&self) -> &Interner { self.get::<Interner>() }
|
||||||
/// Shorthand to get the messaging link
|
/// Shorthand to get the messaging link
|
||||||
pub fn reqnot(&self) -> &ReqNot<ExtMsgSet> { self.get::<ReqNot<ExtMsgSet>>() }
|
pub fn reqnot(&self) -> &ReqNot<api::ExtMsgSet> { self.get::<ReqNot<api::ExtMsgSet>>() }
|
||||||
/// Shorthand to get the system ID
|
/// Shorthand to get the system ID
|
||||||
pub fn sys_id(&self) -> api::SysId { *self.get::<api::SysId>() }
|
pub fn sys_id(&self) -> api::SysId { *self.get::<api::SysId>() }
|
||||||
/// Shorthand to get the task spawner callback
|
/// Shorthand to get the task spawner callback
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use async_fn_stream::stream;
|
use async_fn_stream::stream;
|
||||||
use dyn_clone::{DynClone, clone_box};
|
use dyn_clone::{DynClone, clone_box};
|
||||||
@@ -18,9 +17,9 @@ use trait_set::trait_set;
|
|||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::conv::ToExpr;
|
use crate::conv::ToExpr;
|
||||||
use crate::entrypoint::MemberRecord;
|
use crate::entrypoint::MemberRecord;
|
||||||
use crate::expr::{Expr, ExprHandle};
|
use crate::expr::{BorrowedExprStore, Expr, ExprHandle};
|
||||||
use crate::func_atom::{ExprFunc, Fun};
|
use crate::func_atom::{ExprFunc, Fun};
|
||||||
use crate::gen_expr::{GExpr, arg, call, lambda, seq, sym_ref};
|
use crate::gen_expr::{GExpr, sym_ref};
|
||||||
use crate::system::SysCtx;
|
use crate::system::SysCtx;
|
||||||
|
|
||||||
pub type GenTokTree = TokTree<Expr, GExpr>;
|
pub type GenTokTree = TokTree<Expr, GExpr>;
|
||||||
@@ -43,26 +42,18 @@ impl TokenVariant<api::Expression> for GExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TokenVariant<api::ExprTicket> for Expr {
|
impl TokenVariant<api::ExprTicket> for Expr {
|
||||||
type FromApiCtx<'a> = SysCtx;
|
type FromApiCtx<'a> = (SysCtx, &'a BorrowedExprStore);
|
||||||
async fn from_api(
|
async fn from_api(
|
||||||
api: &api::ExprTicket,
|
api: &api::ExprTicket,
|
||||||
ctx: &mut Self::FromApiCtx<'_>,
|
(ctx, exprs): &mut Self::FromApiCtx<'_>,
|
||||||
_: SrcRange,
|
_: SrcRange,
|
||||||
_: &Interner,
|
_: &Interner,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// SAFETY: receiving trees from sublexers implies ownership transfer
|
// SAFETY: receiving trees from sublexers implies borrowing
|
||||||
Expr::from_handle(Rc::new(unsafe { ExprHandle::from_args(ctx.clone(), *api) }))
|
Expr::from_handle(ExprHandle::borrowed(ctx.clone(), *api, exprs))
|
||||||
}
|
}
|
||||||
type ToApiCtx<'a> = ();
|
type ToApiCtx<'a> = ();
|
||||||
async fn into_api(self, (): &mut Self::ToApiCtx<'_>) -> api::ExprTicket {
|
async fn into_api(self, (): &mut Self::ToApiCtx<'_>) -> api::ExprTicket { self.handle().tk }
|
||||||
let hand = self.handle();
|
|
||||||
std::mem::drop(self);
|
|
||||||
let h = match Rc::try_unwrap(hand) {
|
|
||||||
Ok(h) => h,
|
|
||||||
Err(h) => h.as_ref().clone().await,
|
|
||||||
};
|
|
||||||
h.into_tk()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn x_tok(x: impl ToExpr) -> GenTok { GenTok::NewExpr(x.to_expr().await) }
|
pub async fn x_tok(x: impl ToExpr) -> GenTok { GenTok::NewExpr(x.to_expr().await) }
|
||||||
@@ -96,19 +87,9 @@ pub fn root_mod(name: &str, mems: impl IntoIterator<Item = Vec<GenMember>>) -> (
|
|||||||
(name.to_string(), kind)
|
(name.to_string(), kind)
|
||||||
}
|
}
|
||||||
pub fn fun<I, O>(public: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenMember> {
|
pub fn fun<I, O>(public: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenMember> {
|
||||||
let fac =
|
let fac = LazyMemberFactory::new(async move |sym, ctx| {
|
||||||
LazyMemberFactory::new(move |sym, ctx| async {
|
MemKind::Const(Fun::new(sym, ctx, xf).await.to_expr().await)
|
||||||
return MemKind::Const(build_lambdas(Fun::new(sym, ctx, xf).await, 0).await);
|
});
|
||||||
async fn build_lambdas(fun: Fun, i: u64) -> GExpr {
|
|
||||||
if i < fun.arity().into() {
|
|
||||||
return lambda(i, [build_lambdas(fun, i + 1).boxed_local().await]);
|
|
||||||
}
|
|
||||||
let arity = fun.arity();
|
|
||||||
seq((0..arity).map(|i| arg(i as u64)).chain([call(
|
|
||||||
[fun.to_expr().await].into_iter().chain((0..arity).map(|i| arg(i as u64))),
|
|
||||||
)]))
|
|
||||||
}
|
|
||||||
});
|
|
||||||
vec![GenMember { name: name.to_string(), kind: MemKind::Lazy(fac), public, comments: vec![] }]
|
vec![GenMember { name: name.to_string(), kind: MemKind::Lazy(fac), public, comments: vec![] }]
|
||||||
}
|
}
|
||||||
pub fn prefix(path: &str, items: impl IntoIterator<Item = Vec<GenMember>>) -> Vec<GenMember> {
|
pub fn prefix(path: &str, items: impl IntoIterator<Item = Vec<GenMember>>) -> Vec<GenMember> {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
|
use async_lock::OnceCell;
|
||||||
use derive_destructure::destructure;
|
use derive_destructure::destructure;
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, take_first_fmt};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format, take_first_fmt};
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
@@ -9,7 +10,7 @@ use orchid_base::tree::AtomRepr;
|
|||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::expr::Expr;
|
use crate::expr::{Expr, ExprParseCtx, PathSetBuilder};
|
||||||
use crate::extension::Extension;
|
use crate::extension::Extension;
|
||||||
use crate::system::System;
|
use crate::system::System;
|
||||||
|
|
||||||
@@ -18,11 +19,12 @@ pub struct AtomData {
|
|||||||
owner: System,
|
owner: System,
|
||||||
drop: Option<api::AtomId>,
|
drop: Option<api::AtomId>,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
|
pub(crate) display: OnceCell<FmtUnit>,
|
||||||
}
|
}
|
||||||
impl AtomData {
|
impl AtomData {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn api(self) -> api::Atom {
|
fn api(self) -> api::Atom {
|
||||||
let (owner, drop, data) = self.destructure();
|
let (owner, drop, data, _display) = self.destructure();
|
||||||
api::Atom { data, drop, owner: owner.id() }
|
api::Atom { data, drop, owner: owner.id() }
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -50,35 +52,22 @@ impl fmt::Debug for AtomData {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AtomHand(Rc<AtomData>);
|
pub struct AtomHand(Rc<AtomData>);
|
||||||
impl AtomHand {
|
impl AtomHand {
|
||||||
#[must_use]
|
pub(crate) fn new(data: Vec<u8>, owner: System, drop: Option<api::AtomId>) -> Self {
|
||||||
pub(crate) async fn new(api::Atom { data, drop, owner }: api::Atom, ctx: &Ctx) -> Self {
|
Self(Rc::new(AtomData { owner, drop, data, display: OnceCell::new() }))
|
||||||
let create = || async {
|
|
||||||
let owner = ctx.system_inst(owner).await.expect("Dropped system created atom");
|
|
||||||
AtomHand(Rc::new(AtomData { data, owner, drop }))
|
|
||||||
};
|
|
||||||
if let Some(id) = drop {
|
|
||||||
let mut owned_g = ctx.owned_atoms.write().await;
|
|
||||||
if let Some(data) = owned_g.get(&id)
|
|
||||||
&& let Some(atom) = data.upgrade()
|
|
||||||
{
|
|
||||||
return atom;
|
|
||||||
}
|
|
||||||
let new = create().await;
|
|
||||||
owned_g.insert(id, new.downgrade());
|
|
||||||
new
|
|
||||||
} else {
|
|
||||||
create().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn call(self, arg: Expr) -> api::Expression {
|
pub async fn call(self, arg: Expr) -> Expr {
|
||||||
let owner_sys = self.0.owner.clone();
|
let owner_sys = self.0.owner.clone();
|
||||||
let reqnot = owner_sys.reqnot();
|
let reqnot = owner_sys.reqnot();
|
||||||
owner_sys.ext().exprs().give_expr(arg.clone());
|
owner_sys.ext().exprs().give_expr(arg.clone());
|
||||||
match Rc::try_unwrap(self.0) {
|
let ret = match Rc::try_unwrap(self.0) {
|
||||||
Ok(data) => reqnot.request(api::FinalCall(data.api(), arg.id())).await,
|
Ok(data) => reqnot.request(api::FinalCall(data.api(), arg.id())).await,
|
||||||
Err(hand) => reqnot.request(api::CallRef(hand.api_ref(), 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());
|
||||||
|
val
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn sys(&self) -> &System { &self.0.owner }
|
pub fn sys(&self) -> &System { &self.0.owner }
|
||||||
@@ -96,13 +85,19 @@ impl AtomHand {
|
|||||||
}
|
}
|
||||||
impl Format for AtomHand {
|
impl Format for AtomHand {
|
||||||
async fn print<'a>(&'a self, _c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
async fn print<'a>(&'a self, _c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
FmtUnit::from_api(&self.0.owner.reqnot().request(api::AtomPrint(self.0.api_ref())).await)
|
(self.0.display.get_or_init(|| async {
|
||||||
|
FmtUnit::from_api(&self.0.owner.reqnot().request(api::AtomPrint(self.0.api_ref())).await)
|
||||||
|
}))
|
||||||
|
.await
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl AtomRepr for AtomHand {
|
impl AtomRepr for AtomHand {
|
||||||
type Ctx = Ctx;
|
type Ctx = Ctx;
|
||||||
async fn from_api(atom: &orchid_api::Atom, _: Pos, ctx: &mut Self::Ctx) -> Self {
|
async fn from_api(atom: &api::Atom, _: Pos, ctx: &mut Self::Ctx) -> Self {
|
||||||
Self::new(atom.clone(), ctx).await
|
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) }
|
||||||
}
|
}
|
||||||
async fn to_api(&self) -> orchid_api::Atom { self.api_ref() }
|
async fn to_api(&self) -> orchid_api::Atom { self.api_ref() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ use std::{fmt, ops};
|
|||||||
|
|
||||||
use async_lock::RwLock;
|
use async_lock::RwLock;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use orchid_api::SysId;
|
|
||||||
use orchid_base::builtin::Spawner;
|
use orchid_base::builtin::Spawner;
|
||||||
use orchid_base::interner::Interner;
|
use orchid_base::interner::Interner;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::atom::WeakAtomHand;
|
|
||||||
use crate::expr_store::ExprStore;
|
use crate::expr_store::ExprStore;
|
||||||
use crate::system::{System, WeakSystem};
|
use crate::system::{System, WeakSystem};
|
||||||
use crate::tree::WeakRoot;
|
use crate::tree::WeakRoot;
|
||||||
@@ -20,7 +18,6 @@ pub struct CtxData {
|
|||||||
pub spawn: Spawner,
|
pub spawn: Spawner,
|
||||||
pub systems: RwLock<HashMap<api::SysId, WeakSystem>>,
|
pub systems: RwLock<HashMap<api::SysId, WeakSystem>>,
|
||||||
pub system_id: RefCell<NonZeroU16>,
|
pub system_id: RefCell<NonZeroU16>,
|
||||||
pub owned_atoms: RwLock<HashMap<api::AtomId, WeakAtomHand>>,
|
|
||||||
pub common_exprs: ExprStore,
|
pub common_exprs: ExprStore,
|
||||||
pub root: RwLock<WeakRoot>,
|
pub root: RwLock<WeakRoot>,
|
||||||
}
|
}
|
||||||
@@ -46,7 +43,6 @@ impl Ctx {
|
|||||||
i: Interner::default(),
|
i: Interner::default(),
|
||||||
systems: RwLock::default(),
|
systems: RwLock::default(),
|
||||||
system_id: RefCell::new(NonZero::new(1).unwrap()),
|
system_id: RefCell::new(NonZero::new(1).unwrap()),
|
||||||
owned_atoms: RwLock::default(),
|
|
||||||
common_exprs: ExprStore::default(),
|
common_exprs: ExprStore::default(),
|
||||||
root: RwLock::default(),
|
root: RwLock::default(),
|
||||||
}))
|
}))
|
||||||
@@ -59,7 +55,7 @@ impl Ctx {
|
|||||||
pub(crate) fn next_sys_id(&self) -> api::SysId {
|
pub(crate) fn next_sys_id(&self) -> api::SysId {
|
||||||
let mut g = self.system_id.borrow_mut();
|
let mut g = self.system_id.borrow_mut();
|
||||||
*g = g.checked_add(1).unwrap_or(NonZeroU16::new(1).unwrap());
|
*g = g.checked_add(1).unwrap_or(NonZeroU16::new(1).unwrap());
|
||||||
SysId(*g)
|
api::SysId(*g)
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn downgrade(&self) -> WeakCtx { WeakCtx(Rc::downgrade(&self.0)) }
|
pub fn downgrade(&self) -> WeakCtx { WeakCtx(Rc::downgrade(&self.0)) }
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use orchid_base::location::Pos;
|
|||||||
use orchid_base::logging::Logger;
|
use orchid_base::logging::Logger;
|
||||||
|
|
||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::expr::{Expr, ExprKind, ExprParseCtx, PathSet, PathSetBuilder, Step};
|
use crate::expr::{Expr, ExprKind, PathSet, Step};
|
||||||
use crate::tree::Root;
|
use crate::tree::Root;
|
||||||
|
|
||||||
type ExprGuard = Bound<RwLockWriteGuard<'static, ExprKind>, Expr>;
|
type ExprGuard = Bound<RwLockWriteGuard<'static, ExprKind>, Expr>;
|
||||||
@@ -109,11 +109,8 @@ impl ExecCtx {
|
|||||||
ExprKind::Call(f, x) if !self.did_pop => (ExprKind::Call(f.clone(), x), StackOp::Push(f)),
|
ExprKind::Call(f, x) if !self.did_pop => (ExprKind::Call(f.clone(), x), StackOp::Push(f)),
|
||||||
ExprKind::Call(f, x) => match f.try_into_owned_atom().await {
|
ExprKind::Call(f, x) => match f.try_into_owned_atom().await {
|
||||||
Ok(atom) => {
|
Ok(atom) => {
|
||||||
let ext = atom.sys().ext().clone();
|
|
||||||
let x_norm = self.unpack_ident(&x).await;
|
let x_norm = self.unpack_ident(&x).await;
|
||||||
let mut parse_ctx = ExprParseCtx { ctx: &self.ctx, exprs: ext.exprs() };
|
let val = atom.call(x_norm).await;
|
||||||
let val =
|
|
||||||
Expr::from_api(&atom.call(x_norm).await, PathSetBuilder::new(), &mut parse_ctx).await;
|
|
||||||
(ExprKind::Identity(val.clone()), StackOp::Swap(val))
|
(ExprKind::Identity(val.clone()), StackOp::Swap(val))
|
||||||
},
|
},
|
||||||
Err(f) => match &*f.kind().read().await {
|
Err(f) => match &*f.kind().read().await {
|
||||||
@@ -121,15 +118,9 @@ impl ExecCtx {
|
|||||||
panic!("This should not appear outside function bodies"),
|
panic!("This should not appear outside function bodies"),
|
||||||
ExprKind::Missing => panic!("Should have been replaced"),
|
ExprKind::Missing => panic!("Should have been replaced"),
|
||||||
ExprKind::Atom(a) => {
|
ExprKind::Atom(a) => {
|
||||||
let ext = a.sys().ext().clone();
|
|
||||||
let x_norm = self.unpack_ident(&x).await;
|
let x_norm = self.unpack_ident(&x).await;
|
||||||
let val = Expr::from_api(
|
let ret = a.clone().call(x_norm).await;
|
||||||
&a.clone().call(x_norm).await,
|
(ExprKind::Identity(ret.clone()), StackOp::Swap(ret))
|
||||||
PathSetBuilder::new(),
|
|
||||||
&mut ExprParseCtx { ctx: ext.ctx(), exprs: ext.exprs() },
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
(ExprKind::Identity(val.clone()), StackOp::Swap(val))
|
|
||||||
},
|
},
|
||||||
ExprKind::Bottom(exprv) => (ExprKind::Bottom(exprv.clone()), StackOp::Pop),
|
ExprKind::Bottom(exprv) => (ExprKind::Bottom(exprv.clone()), StackOp::Pop),
|
||||||
ExprKind::Lambda(None, body) =>
|
ExprKind::Lambda(None, body) =>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use std::{fmt, mem};
|
|||||||
|
|
||||||
use async_lock::RwLock;
|
use async_lock::RwLock;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use hashbrown::HashSet;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::OrcErrv;
|
use orchid_base::error::OrcErrv;
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
|
||||||
@@ -116,19 +115,18 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
impl Format for Expr {
|
impl Format for Expr {
|
||||||
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
return print_expr(self, c, &mut HashSet::new()).await;
|
return print_expr(self, c, Substack::Bottom).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn print_expr<'a>(
|
async fn print_expr<'a>(
|
||||||
expr: &'a Expr,
|
expr: &'a Expr,
|
||||||
c: &'a (impl FmtCtx + ?Sized + 'a),
|
c: &'a (impl FmtCtx + ?Sized + 'a),
|
||||||
visited: &mut HashSet<api::ExprTicket>,
|
visited: Substack<'_, api::ExprTicket>,
|
||||||
) -> FmtUnit {
|
) -> FmtUnit {
|
||||||
if visited.contains(&expr.id()) {
|
if visited.iter().any(|id| id == &expr.id()) {
|
||||||
return "CYCLIC_EXPR".to_string().into();
|
return "CYCLIC_EXPR".to_string().into();
|
||||||
}
|
}
|
||||||
visited.insert(expr.id());
|
print_exprkind(&*expr.kind().read().await, c, visited.push(expr.id())).boxed_local().await
|
||||||
print_exprkind(&*expr.kind().read().await, c, visited).boxed_local().await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -152,13 +150,13 @@ impl ExprKind {
|
|||||||
}
|
}
|
||||||
impl Format for ExprKind {
|
impl Format for ExprKind {
|
||||||
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
print_exprkind(self, c, &mut HashSet::new()).await
|
print_exprkind(self, c, Substack::Bottom).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn print_exprkind<'a>(
|
async fn print_exprkind<'a>(
|
||||||
ek: &ExprKind,
|
ek: &ExprKind,
|
||||||
c: &'a (impl FmtCtx + ?Sized + 'a),
|
c: &'a (impl FmtCtx + ?Sized + 'a),
|
||||||
visited: &mut HashSet<api::ExprTicket>,
|
visited: Substack<'_, api::ExprTicket>,
|
||||||
) -> FmtUnit {
|
) -> FmtUnit {
|
||||||
match &ek {
|
match &ek {
|
||||||
ExprKind::Arg => "Arg".to_string().into(),
|
ExprKind::Arg => "Arg".to_string().into(),
|
||||||
|
|||||||
@@ -28,9 +28,15 @@ impl ExprStore {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn take_expr(&self, ticket: api::ExprTicket) {
|
pub fn take_expr(&self, ticket: api::ExprTicket) -> Option<Expr> {
|
||||||
(self.0.exprs.borrow_mut().entry(ticket))
|
match self.0.exprs.borrow_mut().entry(ticket) {
|
||||||
.and_replace_entry_with(|_, (rc, rt)| (1 < rc).then_some((rc - 1, rt)));
|
Entry::Vacant(_) => None,
|
||||||
|
Entry::Occupied(oe) if oe.get().0 == 1 => Some(oe.remove().1),
|
||||||
|
Entry::Occupied(mut oe) => {
|
||||||
|
oe.get_mut().0 -= 1;
|
||||||
|
Some(oe.get().1.clone())
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_expr(&self, ticket: api::ExprTicket) -> Option<Expr> {
|
pub fn get_expr(&self, ticket: api::ExprTicket) -> Option<Expr> {
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ use orchid_base::builtin::ExtInit;
|
|||||||
use orchid_base::clone;
|
use orchid_base::clone;
|
||||||
use orchid_base::format::{FmtCtxImpl, Format};
|
use orchid_base::format::{FmtCtxImpl, Format};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
|
use orchid_base::location::Pos;
|
||||||
use orchid_base::logging::Logger;
|
use orchid_base::logging::Logger;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::reqnot::{DynRequester, ReqNot, Requester as _};
|
use orchid_base::reqnot::{DynRequester, ReqNot, Requester as _};
|
||||||
|
use orchid_base::tree::AtomRepr;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::atom::AtomHand;
|
use crate::atom::AtomHand;
|
||||||
@@ -100,7 +102,7 @@ impl Extension {
|
|||||||
}
|
}
|
||||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => {
|
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => {
|
||||||
this.assert_own_sys(rel.0).await;
|
this.assert_own_sys(rel.0).await;
|
||||||
this.0.exprs.take_expr(rel.1)
|
this.0.exprs.take_expr(rel.1);
|
||||||
}
|
}
|
||||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Move(mov)) => {
|
api::ExtHostNotif::ExprNotif(api::ExprNotif::Move(mov)) => {
|
||||||
this.assert_own_sys(mov.dec).await;
|
this.assert_own_sys(mov.dec).await;
|
||||||
@@ -173,8 +175,8 @@ impl Extension {
|
|||||||
let path = i.ex(path).await;
|
let path = i.ex(path).await;
|
||||||
let root = (ctx.root.read().await.upgrade())
|
let root = (ctx.root.read().await.upgrade())
|
||||||
.expect("LSModule called when root isn't in context");
|
.expect("LSModule called when root isn't in context");
|
||||||
let root_data = &mut *root.0.write().await;
|
let root_data = &*root.0.read().await;
|
||||||
let mut walk_ctx = (ctx.clone(), &mut root_data.consts);
|
let mut walk_ctx = (ctx.clone(), &root_data.consts);
|
||||||
let module =
|
let module =
|
||||||
match walk(&root_data.root, false, path.iter().cloned(), &mut walk_ctx)
|
match walk(&root_data.root, false, path.iter().cloned(), &mut walk_ctx)
|
||||||
.await
|
.await
|
||||||
@@ -189,7 +191,7 @@ impl Extension {
|
|||||||
};
|
};
|
||||||
let mut members = std::collections::HashMap::new();
|
let mut members = std::collections::HashMap::new();
|
||||||
for (k, v) in &module.members {
|
for (k, v) in &module.members {
|
||||||
let kind = match v.kind(ctx.clone(), &mut root_data.consts).await {
|
let kind = match v.kind(ctx.clone(), &root_data.consts).await {
|
||||||
MemberKind::Const => api::MemberInfoKind::Constant,
|
MemberKind::Const => api::MemberInfoKind::Constant,
|
||||||
MemberKind::Module(_) => api::MemberInfoKind::Module,
|
MemberKind::Module(_) => api::MemberInfoKind::Module,
|
||||||
};
|
};
|
||||||
@@ -221,7 +223,7 @@ impl Extension {
|
|||||||
hand.handle(rn, &responses).await
|
hand.handle(rn, &responses).await
|
||||||
},
|
},
|
||||||
api::ExtHostReq::ExtAtomPrint(ref eap @ api::ExtAtomPrint(ref atom)) => {
|
api::ExtHostReq::ExtAtomPrint(ref eap @ api::ExtAtomPrint(ref atom)) => {
|
||||||
let atom = AtomHand::new(atom.clone(), &ctx).await;
|
let atom = AtomHand::from_api(atom, Pos::None, &mut ctx.clone()).await;
|
||||||
let unit = atom.print(&FmtCtxImpl { i: &this.ctx().i }).await;
|
let unit = atom.print(&FmtCtxImpl { i: &this.ctx().i }).await;
|
||||||
hand.handle(eap, &unit.to_api()).await
|
hand.handle(eap, &unit.to_api()).await
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,12 +8,11 @@ use orchid_base::location::SrcRange;
|
|||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::parse::{name_char, name_start, op_char, unrep_space};
|
use orchid_base::parse::{name_char, name_start, op_char, unrep_space};
|
||||||
use orchid_base::tokens::PARENS;
|
use orchid_base::tokens::PARENS;
|
||||||
use orchid_base::tree::recur;
|
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::expr::{Expr, ExprParseCtx, ExprWillPanic};
|
use crate::expr::{Expr, ExprParseCtx};
|
||||||
use crate::parsed::{ParsTok, ParsTokTree};
|
use crate::parsed::{ParsTok, ParsTokTree, tt_to_api};
|
||||||
use crate::system::System;
|
use crate::system::System;
|
||||||
|
|
||||||
pub struct LexCtx<'a> {
|
pub struct LexCtx<'a> {
|
||||||
@@ -54,14 +53,7 @@ impl<'a> LexCtx<'a> {
|
|||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn ser_subtree(&mut self, subtree: ParsTokTree) -> api::TokenTree {
|
pub async fn ser_subtree(&mut self, subtree: ParsTokTree) -> api::TokenTree {
|
||||||
let mut exprs = self.ctx.common_exprs.clone();
|
tt_to_api(&mut self.ctx.common_exprs.clone(), subtree).await
|
||||||
let without_new_expr = recur(subtree, &|tt, r| {
|
|
||||||
if let ParsTok::NewExpr(expr) = tt.tok {
|
|
||||||
return ParsTok::Handle(expr).at(tt.sr);
|
|
||||||
}
|
|
||||||
r(tt)
|
|
||||||
});
|
|
||||||
without_new_expr.into_api(&mut exprs, &mut ExprWillPanic).await
|
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn des_subtree(&mut self, tree: &api::TokenTree) -> ParsTokTree {
|
pub async fn des_subtree(&mut self, tree: &api::TokenTree) -> ParsTokTree {
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ pub mod lex;
|
|||||||
pub mod parse;
|
pub mod parse;
|
||||||
pub mod parsed;
|
pub mod parsed;
|
||||||
pub mod subprocess;
|
pub mod subprocess;
|
||||||
|
mod sys_parser;
|
||||||
pub mod system;
|
pub mod system;
|
||||||
pub mod tree;
|
pub mod tree;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ impl ParseCtx for HostParseCtxImpl<'_> {
|
|||||||
impl HostParseCtx for HostParseCtxImpl<'_> {
|
impl HostParseCtx for HostParseCtxImpl<'_> {
|
||||||
fn ctx(&self) -> &Ctx { &self.ctx }
|
fn ctx(&self) -> &Ctx { &self.ctx }
|
||||||
fn systems(&self) -> impl Iterator<Item = &System> { self.systems.iter() }
|
fn systems(&self) -> impl Iterator<Item = &System> { self.systems.iter() }
|
||||||
|
fn src_path(&self) -> Sym { self.src.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HostParseCtx: ParseCtx {
|
pub trait HostParseCtx: ParseCtx {
|
||||||
@@ -40,6 +41,8 @@ pub trait HostParseCtx: ParseCtx {
|
|||||||
fn ctx(&self) -> &Ctx;
|
fn ctx(&self) -> &Ctx;
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn systems(&self) -> impl Iterator<Item = &System>;
|
fn systems(&self) -> impl Iterator<Item = &System>;
|
||||||
|
#[must_use]
|
||||||
|
fn src_path(&self) -> Sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn parse_items(
|
pub async fn parse_items(
|
||||||
@@ -109,9 +112,9 @@ pub async fn parse_exportable_item<'a>(
|
|||||||
let kind = if discr == ctx.i().i("mod").await {
|
let kind = if discr == ctx.i().i("mod").await {
|
||||||
let (name, body) = parse_module(ctx, path, tail).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: ParsedMemberKind::Mod(body) })
|
||||||
} else if let Some(sys) = ctx.systems().find(|s| s.can_parse(discr.clone())) {
|
} else if let Some(parser) = ctx.systems().find_map(|s| s.get_parser(discr.clone())) {
|
||||||
return sys
|
return parser
|
||||||
.parse(path, tail.to_vec(), exported, comments, &mut async |stack, lines| {
|
.parse(ctx, path, tail.to_vec(), exported, comments, &mut async |stack, lines| {
|
||||||
let source = Snippet::new(lines.first().unwrap(), &lines);
|
let source = Snippet::new(lines.first().unwrap(), &lines);
|
||||||
parse_items(ctx, stack, source).await
|
parse_items(ctx, stack, source).await
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ use orchid_base::interner::Tok;
|
|||||||
use orchid_base::location::SrcRange;
|
use orchid_base::location::SrcRange;
|
||||||
use orchid_base::parse::{Comment, Import};
|
use orchid_base::parse::{Comment, Import};
|
||||||
use orchid_base::tl_cache;
|
use orchid_base::tl_cache;
|
||||||
use orchid_base::tree::{TokTree, Token};
|
use orchid_base::tree::{TokTree, Token, recur};
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::dealias::{ChildErrorKind, ChildResult, Tree};
|
use crate::dealias::{ChildErrorKind, ChildResult, Tree};
|
||||||
use crate::expr::Expr;
|
use crate::expr::{Expr, ExprWillPanic};
|
||||||
|
use crate::expr_store::ExprStore;
|
||||||
use crate::system::System;
|
use crate::system::System;
|
||||||
|
|
||||||
pub type ParsTokTree = TokTree<Expr, Expr>;
|
pub type ParsTokTree = TokTree<Expr, Expr>;
|
||||||
@@ -54,7 +55,7 @@ impl Format for Item {
|
|||||||
let item_text = match &self.kind {
|
let item_text = match &self.kind {
|
||||||
ItemKind::Import(i) => format!("import {i}").into(),
|
ItemKind::Import(i) => format!("import {i}").into(),
|
||||||
ItemKind::Member(mem) => match &mem.kind {
|
ItemKind::Member(mem) => match &mem.kind {
|
||||||
ParsedMemberKind::DeferredConst(_, sys) =>
|
ParsedMemberKind::Const(_, sys) =>
|
||||||
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("const {0} via {1}")))
|
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("const {0} via {1}")))
|
||||||
.units([mem.name.rc().into(), sys.print(c).await]),
|
.units([mem.name.rc().into(), sys.print(c).await]),
|
||||||
ParsedMemberKind::Mod(module) =>
|
ParsedMemberKind::Mod(module) =>
|
||||||
@@ -106,7 +107,7 @@ impl fmt::Debug for ParsedExpr {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParsedMemberKind {
|
pub enum ParsedMemberKind {
|
||||||
DeferredConst(api::ParsedConstId, System),
|
Const(api::ParsedConstId, System),
|
||||||
Mod(ParsedModule),
|
Mod(ParsedModule),
|
||||||
}
|
}
|
||||||
impl From<ParsedModule> for ParsedMemberKind {
|
impl From<ParsedModule> for ParsedMemberKind {
|
||||||
@@ -162,7 +163,7 @@ impl Tree for ParsedModule {
|
|||||||
.find(|m| m.name == key)
|
.find(|m| m.name == key)
|
||||||
{
|
{
|
||||||
match &member.kind {
|
match &member.kind {
|
||||||
ParsedMemberKind::DeferredConst(..) => return ChildResult::Err(ChildErrorKind::Constant),
|
ParsedMemberKind::Const(..) => return ChildResult::Err(ChildErrorKind::Constant),
|
||||||
ParsedMemberKind::Mod(m) => return ChildResult::Ok(m),
|
ParsedMemberKind::Mod(m) => return ChildResult::Ok(m),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,15 +192,6 @@ impl Format for ParsedModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO:
|
|
||||||
///
|
|
||||||
/// idea, does the host need an IR here or can we figure out a way to transcribe
|
|
||||||
/// these? Should we spin off a new stage for value parsing so that ParsTokTree
|
|
||||||
/// doesn't appear in the interpreter's ingress?
|
|
||||||
pub struct Const {
|
|
||||||
pub source: Option<Vec<ParsTokTree>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Selects a code element
|
/// Selects a code element
|
||||||
///
|
///
|
||||||
/// Either the steps point to a constant and rule_loc is None, or the steps
|
/// Either the steps point to a constant and rule_loc is None, or the steps
|
||||||
@@ -212,3 +204,13 @@ impl ConstPath {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_const(steps: Tok<Vec<Tok<String>>>) -> Self { Self { steps } }
|
pub fn to_const(steps: Tok<Vec<Tok<String>>>) -> Self { Self { steps } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn tt_to_api(exprs: &mut ExprStore, subtree: ParsTokTree) -> api::TokenTree {
|
||||||
|
let without_new_expr = recur(subtree, &|tt, r| {
|
||||||
|
if let ParsTok::NewExpr(expr) = tt.tok {
|
||||||
|
return ParsTok::Handle(expr).at(tt.sr);
|
||||||
|
}
|
||||||
|
r(tt)
|
||||||
|
});
|
||||||
|
without_new_expr.into_api(exprs, &mut ExprWillPanic).await
|
||||||
|
}
|
||||||
|
|||||||
119
orchid-host/src/sys_parser.rs
Normal file
119
orchid-host/src/sys_parser.rs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
use futures::FutureExt;
|
||||||
|
use futures::future::join_all;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use orchid_base::error::{OrcErrv, OrcRes};
|
||||||
|
use orchid_base::interner::{Interner, Tok};
|
||||||
|
use orchid_base::location::SrcRange;
|
||||||
|
use orchid_base::name::Sym;
|
||||||
|
use orchid_base::parse::Comment;
|
||||||
|
use orchid_base::reqnot::Requester;
|
||||||
|
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::{
|
||||||
|
Item, ItemKind, ParsTokTree, ParsedMember, ParsedMemberKind, ParsedModule, tt_to_api,
|
||||||
|
};
|
||||||
|
use crate::system::System;
|
||||||
|
|
||||||
|
pub struct Parser {
|
||||||
|
pub(crate) system: System,
|
||||||
|
pub(crate) idx: u16,
|
||||||
|
}
|
||||||
|
type ModPath<'a> = Substack<'a, Tok<String>>;
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub async fn parse(
|
||||||
|
&self,
|
||||||
|
ctx: &impl HostParseCtx,
|
||||||
|
path: ModPath<'_>,
|
||||||
|
line: Vec<ParsTokTree>,
|
||||||
|
exported: bool,
|
||||||
|
comments: Vec<Comment>,
|
||||||
|
callback: &mut impl AsyncFnMut(ModPath<'_>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
|
||||||
|
) -> OrcRes<Vec<Item>> {
|
||||||
|
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 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 {
|
||||||
|
idx: self.idx,
|
||||||
|
module: mod_path.to_api(),
|
||||||
|
src: src_path.to_api(),
|
||||||
|
exported,
|
||||||
|
sys: self.system.id(),
|
||||||
|
comments,
|
||||||
|
line,
|
||||||
|
};
|
||||||
|
match self.system.reqnot().request(req).await {
|
||||||
|
Ok(parsed_v) => {
|
||||||
|
let mut ext_exprs = self.system.ext().exprs().clone();
|
||||||
|
conv(parsed_v, path, callback, &mut ConvCtx {
|
||||||
|
i: self.system.i(),
|
||||||
|
mod_path: &mod_path,
|
||||||
|
ext_exprs: &mut ext_exprs,
|
||||||
|
pctx: &mut ExprParseCtx { ctx: self.system.ctx(), exprs: self.system.ext().exprs() },
|
||||||
|
src_path: &src_path,
|
||||||
|
sys: &self.system,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
},
|
||||||
|
Err(e) => Err(OrcErrv::from_api(&e, &self.system.ctx().i).await),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ConvCtx<'a> {
|
||||||
|
sys: &'a System,
|
||||||
|
mod_path: &'a Sym,
|
||||||
|
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>,
|
||||||
|
module: Substack<'_, Tok<String>>,
|
||||||
|
callback: &'_ mut impl AsyncFnMut(Substack<'_, Tok<String>>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
|
||||||
|
ctx: &mut ConvCtx<'_>,
|
||||||
|
) -> OrcRes<Vec<Item>> {
|
||||||
|
let mut items = Vec::new();
|
||||||
|
for parsed in parsed_v {
|
||||||
|
let (name, exported, kind) = match parsed.kind {
|
||||||
|
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;
|
||||||
|
items.extend(callback(module.clone(), tokens).await?);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let name = ctx.i.ex(name).await;
|
||||||
|
let mkind = match kind {
|
||||||
|
api::ParsedMemberKind::Module { lines, use_prelude } => {
|
||||||
|
let items = conv(lines, module.push(name.clone()), callback, ctx).boxed_local().await?;
|
||||||
|
ParsedMemberKind::Mod(ParsedModule::new(use_prelude, items))
|
||||||
|
},
|
||||||
|
api::ParsedMemberKind::Constant(cid) => {
|
||||||
|
ctx.sys.0.const_paths.insert(cid, ctx.mod_path.suffix(module.unreverse(), ctx.i).await);
|
||||||
|
ParsedMemberKind::Const(cid, ctx.sys.clone())
|
||||||
|
},
|
||||||
|
};
|
||||||
|
items.push(Item {
|
||||||
|
comments: join_all(
|
||||||
|
parsed.comments.iter().map(|c| Comment::from_api(c, ctx.src_path.clone(), ctx.i)),
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
sr: SrcRange::from_api(&parsed.source_range, ctx.i).await,
|
||||||
|
kind: ItemKind::Member(ParsedMember { name, exported, kind: mkind }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Ok(items)
|
||||||
|
}
|
||||||
@@ -3,38 +3,32 @@ use std::fmt;
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
|
use async_lock::RwLock;
|
||||||
use derive_destructure::destructure;
|
use derive_destructure::destructure;
|
||||||
use futures::FutureExt;
|
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use memo_map::MemoMap;
|
use memo_map::MemoMap;
|
||||||
use orchid_base::char_filter::char_filter_match;
|
use orchid_base::char_filter::char_filter_match;
|
||||||
use orchid_base::error::{OrcErrv, OrcRes, mk_errv_floating};
|
use orchid_base::error::{OrcRes, mk_errv_floating};
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
||||||
use orchid_base::interner::{Interner, Tok};
|
use orchid_base::interner::{Interner, Tok};
|
||||||
use orchid_base::iter_utils::IteratorPrint;
|
use orchid_base::iter_utils::IteratorPrint;
|
||||||
use orchid_base::location::SrcRange;
|
|
||||||
use orchid_base::name::{NameLike, Sym, VName, VPath};
|
use orchid_base::name::{NameLike, Sym, VName, VPath};
|
||||||
use orchid_base::parse::Comment;
|
|
||||||
use orchid_base::reqnot::{ReqNot, Requester};
|
use orchid_base::reqnot::{ReqNot, Requester};
|
||||||
use orchid_base::tree::{recur, ttv_from_api};
|
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
use substack::{Stackframe, Substack};
|
use substack::{Stackframe, Substack};
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
|
use crate::atom::{AtomHand, WeakAtomHand};
|
||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::dealias::walk;
|
use crate::dealias::walk;
|
||||||
use crate::expr::{ExprParseCtx, ExprWillPanic};
|
|
||||||
use crate::expr_store::ExprStore;
|
|
||||||
use crate::extension::{Extension, WeakExtension};
|
use crate::extension::{Extension, WeakExtension};
|
||||||
use crate::parsed::{
|
use crate::sys_parser::Parser;
|
||||||
Item, ItemKind, ParsTok, ParsTokTree, ParsedMember, ParsedMemberKind, ParsedModule,
|
|
||||||
};
|
|
||||||
use crate::tree::Root;
|
use crate::tree::Root;
|
||||||
|
|
||||||
#[derive(destructure)]
|
#[derive(destructure)]
|
||||||
struct SystemInstData {
|
pub(crate) struct SystemInstData {
|
||||||
deps: Vec<System>,
|
deps: Vec<System>,
|
||||||
ctx: Ctx,
|
ctx: Ctx,
|
||||||
ext: Extension,
|
ext: Extension,
|
||||||
@@ -43,6 +37,7 @@ struct SystemInstData {
|
|||||||
id: api::SysId,
|
id: api::SysId,
|
||||||
line_types: Vec<Tok<String>>,
|
line_types: Vec<Tok<String>>,
|
||||||
prelude: Vec<Sym>,
|
prelude: Vec<Sym>,
|
||||||
|
owned_atoms: RwLock<HashMap<api::AtomId, WeakAtomHand>>,
|
||||||
pub(crate) const_paths: MemoMap<api::ParsedConstId, Sym>,
|
pub(crate) const_paths: MemoMap<api::ParsedConstId, Sym>,
|
||||||
}
|
}
|
||||||
impl Drop for SystemInstData {
|
impl Drop for SystemInstData {
|
||||||
@@ -60,7 +55,7 @@ impl fmt::Debug for SystemInstData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct System(Rc<SystemInstData>);
|
pub struct System(pub(crate) Rc<SystemInstData>);
|
||||||
impl System {
|
impl System {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn id(&self) -> api::SysId { self.0.id }
|
pub fn id(&self) -> api::SysId { self.0.id }
|
||||||
@@ -101,108 +96,32 @@ impl System {
|
|||||||
self.0.ext.lex_req(source, src, pos, self.id(), r).await
|
self.0.ext.lex_req(source, src, pos, self.id(), r).await
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn can_parse(&self, ltyp: Tok<String>) -> bool { self.0.line_types.contains(<yp) }
|
pub fn get_parser(&self, ltyp: Tok<String>) -> Option<Parser> {
|
||||||
pub fn line_types(&self) -> impl Iterator<Item = &Tok<String>> + '_ { self.0.line_types.iter() }
|
(self.0.line_types.iter().enumerate())
|
||||||
pub async fn parse(
|
.find(|(_, txt)| *txt == <yp)
|
||||||
&self,
|
.map(|(idx, _)| Parser { idx: idx as u16, system: self.clone() })
|
||||||
path: Substack<'_, Tok<String>>,
|
|
||||||
line: Vec<ParsTokTree>,
|
|
||||||
exported: bool,
|
|
||||||
comments: Vec<Comment>,
|
|
||||||
callback: &mut impl AsyncFnMut(Substack<'_, Tok<String>>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
|
|
||||||
) -> OrcRes<Vec<Item>> {
|
|
||||||
let src_path = line.first().expect("cannot be empty").sr.path();
|
|
||||||
let line = join_all(line.into_iter().map(|t| async {
|
|
||||||
let mut expr_store = self.0.ext.exprs().clone();
|
|
||||||
let without_new_expr = recur(t, &|t, r| {
|
|
||||||
if let ParsTok::NewExpr(expr) = t.tok {
|
|
||||||
return ParsTok::Handle(expr).at(t.sr);
|
|
||||||
}
|
|
||||||
r(t)
|
|
||||||
});
|
|
||||||
without_new_expr.into_api(&mut expr_store, &mut ExprWillPanic).await
|
|
||||||
}))
|
|
||||||
.await;
|
|
||||||
let comments = comments.iter().map(Comment::to_api).collect_vec();
|
|
||||||
let req = api::ParseLine {
|
|
||||||
module: self.i().i(&path.unreverse()).await.to_api(),
|
|
||||||
src: src_path.to_api(),
|
|
||||||
exported,
|
|
||||||
sys: self.id(),
|
|
||||||
comments,
|
|
||||||
line,
|
|
||||||
};
|
|
||||||
match self.reqnot().request(req).await {
|
|
||||||
Ok(parsed_v) => {
|
|
||||||
let mut ext_exprs = self.ext().exprs().clone();
|
|
||||||
struct ConvCtx<'a> {
|
|
||||||
sys: &'a System,
|
|
||||||
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>,
|
|
||||||
module: Substack<'_, Tok<String>>,
|
|
||||||
callback: &'_ mut impl AsyncFnMut(
|
|
||||||
Substack<'_, Tok<String>>,
|
|
||||||
Vec<ParsTokTree>,
|
|
||||||
) -> OrcRes<Vec<Item>>,
|
|
||||||
ctx: &mut ConvCtx<'_>,
|
|
||||||
) -> OrcRes<Vec<Item>> {
|
|
||||||
let mut items = Vec::new();
|
|
||||||
for parsed in parsed_v {
|
|
||||||
let (name, exported, kind) = match parsed.kind {
|
|
||||||
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;
|
|
||||||
items.extend(callback(module.clone(), tokens).await?);
|
|
||||||
continue;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let name = ctx.i.ex(name).await;
|
|
||||||
let mkind = match kind {
|
|
||||||
api::ParsedMemberKind::Module { lines, use_prelude } => {
|
|
||||||
let items =
|
|
||||||
conv(lines, module.push(name.clone()), callback, ctx).boxed_local().await?;
|
|
||||||
ParsedMemberKind::Mod(ParsedModule::new(use_prelude, items))
|
|
||||||
},
|
|
||||||
api::ParsedMemberKind::Constant(cid) =>
|
|
||||||
ParsedMemberKind::DeferredConst(cid, ctx.sys.clone()),
|
|
||||||
};
|
|
||||||
items.push(Item {
|
|
||||||
comments: join_all(
|
|
||||||
parsed.comments.iter().map(|c| Comment::from_api(c, ctx.src_path.clone(), ctx.i)),
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
sr: SrcRange::from_api(&parsed.source_range, ctx.i).await,
|
|
||||||
kind: ItemKind::Member(ParsedMember { name, exported, kind: mkind }),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Ok(items)
|
|
||||||
}
|
|
||||||
conv(parsed_v, path, callback, &mut ConvCtx {
|
|
||||||
i: self.i(),
|
|
||||||
ext_exprs: &mut ext_exprs,
|
|
||||||
pctx: &mut ExprParseCtx { ctx: self.ctx(), exprs: self.ext().exprs() },
|
|
||||||
src_path: &src_path,
|
|
||||||
sys: self,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
},
|
|
||||||
Err(e) => Err(OrcErrv::from_api(&e, &self.ctx().i).await),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
pub fn line_types(&self) -> impl Iterator<Item = &Tok<String>> + '_ { self.0.line_types.iter() }
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn request(&self, req: Vec<u8>) -> Vec<u8> {
|
pub async fn request(&self, req: Vec<u8>) -> Vec<u8> {
|
||||||
self.reqnot().request(api::SysFwded(self.id(), req)).await
|
self.reqnot().request(api::SysFwded(self.id(), req)).await
|
||||||
}
|
}
|
||||||
|
pub(crate) async fn new_atom(&self, data: Vec<u8>, id: api::AtomId) -> AtomHand {
|
||||||
|
let mut owned_g = self.0.owned_atoms.write().await;
|
||||||
|
if let Some(data) = owned_g.get(&id)
|
||||||
|
&& let Some(atom) = data.upgrade()
|
||||||
|
{
|
||||||
|
return atom;
|
||||||
|
}
|
||||||
|
let new = AtomHand::new(data, self.clone(), Some(id));
|
||||||
|
owned_g.insert(id, new.downgrade());
|
||||||
|
new
|
||||||
|
}
|
||||||
pub(crate) fn drop_atom(&self, drop: api::AtomId) {
|
pub(crate) fn drop_atom(&self, drop: api::AtomId) {
|
||||||
let this = self.0.clone();
|
let this = self.0.clone();
|
||||||
(self.0.ctx.spawn)(Box::pin(async move {
|
(self.0.ctx.spawn)(Box::pin(async move {
|
||||||
this.ctx.owned_atoms.write().await.remove(&drop);
|
this.owned_atoms.write().await.remove(&drop);
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -218,7 +137,7 @@ impl System {
|
|||||||
async move |rel| {
|
async move |rel| {
|
||||||
let cwd = orig.split_last_seg().1;
|
let cwd = orig.split_last_seg().1;
|
||||||
let root_data = &mut *root.0.write().await;
|
let root_data = &mut *root.0.write().await;
|
||||||
let walk_ctx = &mut (ctx.clone(), &mut root_data.consts);
|
let walk_ctx = &mut (ctx.clone(), &root_data.consts);
|
||||||
let cmod = (walk(&root_data.root, false, cwd.iter().cloned(), walk_ctx).await)
|
let cmod = (walk(&root_data.root, false, cwd.iter().cloned(), walk_ctx).await)
|
||||||
.expect("the parent module of a constant should exist");
|
.expect("the parent module of a constant should exist");
|
||||||
let (selector, tail) = rel.split_first().expect("Names cannot be empty");
|
let (selector, tail) = rel.split_first().expect("Names cannot be empty");
|
||||||
@@ -298,6 +217,7 @@ impl SystemCtor {
|
|||||||
.await,
|
.await,
|
||||||
id,
|
id,
|
||||||
prelude: join_all(sys_inst.prelude.iter().map(|tok| Sym::from_api(*tok, &ext.ctx().i))).await,
|
prelude: join_all(sys_inst.prelude.iter().map(|tok| Sym::from_api(*tok, &ext.ctx().i))).await,
|
||||||
|
owned_atoms: RwLock::new(HashMap::new()),
|
||||||
const_paths: MemoMap::new(),
|
const_paths: MemoMap::new(),
|
||||||
}));
|
}));
|
||||||
let api_module_root = api::Module {
|
let api_module_root = api::Module {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use futures::{FutureExt, StreamExt, stream};
|
|||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use hashbrown::hash_map::Entry;
|
use hashbrown::hash_map::Entry;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use memo_map::MemoMap;
|
||||||
use orchid_base::clone;
|
use orchid_base::clone;
|
||||||
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
@@ -26,7 +27,7 @@ use crate::system::System;
|
|||||||
|
|
||||||
pub struct RootData {
|
pub struct RootData {
|
||||||
pub root: Module,
|
pub root: Module,
|
||||||
pub consts: HashMap<Sym, Expr>,
|
pub consts: MemoMap<Sym, Expr>,
|
||||||
pub ctx: Ctx,
|
pub ctx: Ctx,
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -36,23 +37,25 @@ impl Root {
|
|||||||
pub fn new(ctx: Ctx) -> Self {
|
pub fn new(ctx: Ctx) -> Self {
|
||||||
Root(Rc::new(RwLock::new(RootData {
|
Root(Rc::new(RwLock::new(RootData {
|
||||||
root: Module::default(),
|
root: Module::default(),
|
||||||
consts: HashMap::default(),
|
consts: MemoMap::default(),
|
||||||
ctx,
|
ctx,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn from_api(api: api::Module, sys: &System) -> Self {
|
pub async fn from_api(api: api::Module, sys: &System) -> Self {
|
||||||
let mut consts = HashMap::new();
|
let consts = MemoMap::new();
|
||||||
let mut tfac = TreeFromApiCtx { consts: &mut consts, path: sys.i().i(&[][..]).await, sys };
|
let mut tfac = TreeFromApiCtx { consts: &consts, path: sys.i().i(&[][..]).await, sys };
|
||||||
let root = Module::from_api(api, &mut tfac).await;
|
let root = Module::from_api(api, &mut tfac).await;
|
||||||
Root(Rc::new(RwLock::new(RootData { root, consts, ctx: sys.ctx().clone() })))
|
Root(Rc::new(RwLock::new(RootData { root, consts, ctx: sys.ctx().clone() })))
|
||||||
}
|
}
|
||||||
pub async fn merge(&self, new: &Root) -> Result<Self, MergeErr> {
|
pub async fn merge(&self, new: &Root) -> Result<Self, MergeErr> {
|
||||||
let this = self.0.read().await;
|
let this = self.0.write().await;
|
||||||
let that = new.0.read().await;
|
let that = new.0.write().await;
|
||||||
let mut consts =
|
let consts = MemoMap::new();
|
||||||
this.consts.iter().chain(&that.consts).map(|(k, v)| (k.clone(), v.clone())).collect();
|
for (k, v) in this.consts.iter().chain(that.consts.iter()) {
|
||||||
let root = this.root.merge(&that.root, this.ctx.clone(), &mut consts).await?;
|
consts.insert(k.clone(), v.clone());
|
||||||
|
}
|
||||||
|
let root = this.root.merge(&that.root, this.ctx.clone(), &consts).await?;
|
||||||
Ok(Self(Rc::new(RwLock::new(RootData { root, consts, ctx: this.ctx.clone() }))))
|
Ok(Self(Rc::new(RwLock::new(RootData { root, consts, ctx: this.ctx.clone() }))))
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -60,11 +63,11 @@ impl Root {
|
|||||||
let mut ref_this = self.0.write().await;
|
let mut ref_this = self.0.write().await;
|
||||||
let this = &mut *ref_this;
|
let this = &mut *ref_this;
|
||||||
let mut deferred_consts = HashMap::new();
|
let mut deferred_consts = HashMap::new();
|
||||||
let mut consts = this.consts.clone();
|
let consts = this.consts.clone();
|
||||||
let mut tfpctx = FromParsedCtx {
|
let mut tfpctx = FromParsedCtx {
|
||||||
pars_root: parsed,
|
pars_root: parsed,
|
||||||
deferred_consts: &mut deferred_consts,
|
deferred_consts: &mut deferred_consts,
|
||||||
consts: &mut consts,
|
consts: &consts,
|
||||||
pars_prefix: pars_prefix.clone(),
|
pars_prefix: pars_prefix.clone(),
|
||||||
root: &this.root,
|
root: &this.root,
|
||||||
ctx: &this.ctx,
|
ctx: &this.ctx,
|
||||||
@@ -79,7 +82,7 @@ impl Root {
|
|||||||
)]);
|
)]);
|
||||||
module = Module { imports: HashMap::new(), members }
|
module = Module { imports: HashMap::new(), members }
|
||||||
}
|
}
|
||||||
let root = (this.root.merge(&module, this.ctx.clone(), &mut consts).await)
|
let root = (this.root.merge(&module, this.ctx.clone(), &consts).await)
|
||||||
.expect("Merge conflict between parsed and existing module");
|
.expect("Merge conflict between parsed and existing module");
|
||||||
let new = Root(Rc::new(RwLock::new(RootData { root, consts, ctx: this.ctx.clone() })));
|
let new = Root(Rc::new(RwLock::new(RootData { root, consts, ctx: this.ctx.clone() })));
|
||||||
*this.ctx.root.write().await = new.downgrade();
|
*this.ctx.root.write().await = new.downgrade();
|
||||||
@@ -93,7 +96,7 @@ impl Root {
|
|||||||
new
|
new
|
||||||
}
|
}
|
||||||
pub async fn get_const_value(&self, name: Sym, pos: Pos) -> OrcRes<Expr> {
|
pub async fn get_const_value(&self, name: Sym, pos: Pos) -> OrcRes<Expr> {
|
||||||
let this = &mut *self.0.write().await;
|
let this = &*self.0.read().await;
|
||||||
// shortcut for previously visited
|
// shortcut for previously visited
|
||||||
if let Some(val) = this.consts.get(&name) {
|
if let Some(val) = this.consts.get(&name) {
|
||||||
return Ok(val.clone());
|
return Ok(val.clone());
|
||||||
@@ -101,7 +104,7 @@ impl Root {
|
|||||||
// load the node, then check if this "walk" call added it to the map
|
// load the node, then check if this "walk" call added it to the map
|
||||||
let ctx = this.ctx.clone();
|
let ctx = this.ctx.clone();
|
||||||
let module =
|
let module =
|
||||||
walk(&this.root, false, name.iter().cloned(), &mut (ctx.clone(), &mut this.consts)).await;
|
walk(&this.root, false, name.iter().cloned(), &mut (ctx.clone(), &this.consts)).await;
|
||||||
if let Some(val) = this.consts.get(&name) {
|
if let Some(val) = this.consts.get(&name) {
|
||||||
return Ok(val.clone());
|
return Ok(val.clone());
|
||||||
}
|
}
|
||||||
@@ -140,14 +143,14 @@ impl Default for WeakRoot {
|
|||||||
|
|
||||||
pub struct TreeFromApiCtx<'a> {
|
pub struct TreeFromApiCtx<'a> {
|
||||||
pub sys: &'a System,
|
pub sys: &'a System,
|
||||||
pub consts: &'a mut HashMap<Sym, Expr>,
|
pub consts: &'a MemoMap<Sym, Expr>,
|
||||||
pub path: Tok<Vec<Tok<String>>>,
|
pub path: Tok<Vec<Tok<String>>>,
|
||||||
}
|
}
|
||||||
impl<'a> TreeFromApiCtx<'a> {
|
impl<'a> TreeFromApiCtx<'a> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn push<'c>(&'c mut self, name: Tok<String>) -> TreeFromApiCtx<'c> {
|
pub async fn push<'c>(&'c self, name: Tok<String>) -> TreeFromApiCtx<'c> {
|
||||||
let path = self.sys.ctx().i.i(&self.path.iter().cloned().chain([name]).collect_vec()).await;
|
let path = self.sys.ctx().i.i(&self.path.iter().cloned().chain([name]).collect_vec()).await;
|
||||||
TreeFromApiCtx { path, consts: &mut *self.consts, sys: self.sys }
|
TreeFromApiCtx { path, consts: self.consts, sys: self.sys }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +211,7 @@ impl Module {
|
|||||||
Ok(abs_path) => {
|
Ok(abs_path) => {
|
||||||
let names_res = match abs_path.strip_prefix(&ctx.pars_prefix[..]) {
|
let names_res = match abs_path.strip_prefix(&ctx.pars_prefix[..]) {
|
||||||
None => {
|
None => {
|
||||||
let mut tree_ctx = (ctx.ctx.clone(), &mut *ctx.consts);
|
let mut tree_ctx = (ctx.ctx.clone(), ctx.consts);
|
||||||
resolv_glob(&path, ctx.root, &abs_path, pos, &ctx.ctx.i, &mut tree_ctx).await
|
resolv_glob(&path, ctx.root, &abs_path, pos, &ctx.ctx.i, &mut tree_ctx).await
|
||||||
},
|
},
|
||||||
Some(sub_tgt) => {
|
Some(sub_tgt) => {
|
||||||
@@ -322,7 +325,7 @@ impl Module {
|
|||||||
&self,
|
&self,
|
||||||
other: &Module,
|
other: &Module,
|
||||||
ctx: Ctx,
|
ctx: Ctx,
|
||||||
consts: &mut HashMap<Sym, Expr>,
|
consts: &MemoMap<Sym, Expr>,
|
||||||
) -> Result<Module, MergeErr> {
|
) -> Result<Module, MergeErr> {
|
||||||
if !self.imports.is_empty() || !other.imports.is_empty() {
|
if !self.imports.is_empty() || !other.imports.is_empty() {
|
||||||
return Err(MergeErr { path: VPath::new([]), kind: MergeErrKind::Imports });
|
return Err(MergeErr { path: VPath::new([]), kind: MergeErrKind::Imports });
|
||||||
@@ -385,12 +388,12 @@ pub struct FromParsedCtx<'a> {
|
|||||||
root: &'a Module,
|
root: &'a Module,
|
||||||
rep: &'a Reporter,
|
rep: &'a Reporter,
|
||||||
ctx: &'a Ctx,
|
ctx: &'a Ctx,
|
||||||
consts: &'a mut HashMap<Sym, Expr>,
|
consts: &'a MemoMap<Sym, Expr>,
|
||||||
deferred_consts: &'a mut HashMap<Sym, (api::SysId, api::ParsedConstId)>,
|
deferred_consts: &'a mut HashMap<Sym, (api::SysId, api::ParsedConstId)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tree for Module {
|
impl Tree for Module {
|
||||||
type Ctx<'a> = (Ctx, &'a mut HashMap<Sym, Expr>);
|
type Ctx<'a> = (Ctx, &'a MemoMap<Sym, Expr>);
|
||||||
async fn child(
|
async fn child(
|
||||||
&self,
|
&self,
|
||||||
key: Tok<String>,
|
key: Tok<String>,
|
||||||
@@ -420,7 +423,7 @@ pub struct Member {
|
|||||||
}
|
}
|
||||||
impl Member {
|
impl Member {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn kind<'a>(&'a self, ctx: Ctx, consts: &mut HashMap<Sym, Expr>) -> &'a MemberKind {
|
pub async fn kind<'a>(&'a self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> &'a MemberKind {
|
||||||
(self.kind.get_or_init(async {
|
(self.kind.get_or_init(async {
|
||||||
let handle = self.lazy.borrow_mut().take().expect("If kind is uninit, lazy must be Some");
|
let handle = self.lazy.borrow_mut().take().expect("If kind is uninit, lazy must be Some");
|
||||||
handle.run(ctx, consts).await
|
handle.run(ctx, consts).await
|
||||||
@@ -437,7 +440,7 @@ impl MemberKind {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
async fn from_parsed(parsed: &ParsedMemberKind, path: Sym, ctx: &mut FromParsedCtx<'_>) -> Self {
|
async fn from_parsed(parsed: &ParsedMemberKind, path: Sym, ctx: &mut FromParsedCtx<'_>) -> Self {
|
||||||
match parsed {
|
match parsed {
|
||||||
ParsedMemberKind::DeferredConst(id, sys) => {
|
ParsedMemberKind::Const(id, sys) => {
|
||||||
ctx.deferred_consts.insert(path, (sys.id(), *id));
|
ctx.deferred_consts.insert(path, (sys.id(), *id));
|
||||||
MemberKind::Const
|
MemberKind::Const
|
||||||
},
|
},
|
||||||
@@ -454,12 +457,13 @@ pub struct LazyMemberHandle {
|
|||||||
}
|
}
|
||||||
impl LazyMemberHandle {
|
impl LazyMemberHandle {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn run(self, ctx: Ctx, consts: &mut HashMap<Sym, Expr>) -> MemberKind {
|
pub async fn run(self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> MemberKind {
|
||||||
let sys = ctx.system_inst(self.sys).await.expect("Missing system for lazy member");
|
let sys = ctx.system_inst(self.sys).await.expect("Missing system for lazy member");
|
||||||
match sys.get_tree(self.id).await {
|
match sys.get_tree(self.id).await {
|
||||||
api::MemberKind::Const(c) => {
|
api::MemberKind::Const(c) => {
|
||||||
let mut pctx = ExprParseCtx { ctx: &ctx, exprs: sys.ext().exprs() };
|
let mut pctx = ExprParseCtx { ctx: &ctx, exprs: sys.ext().exprs() };
|
||||||
consts.insert(self.path, Expr::from_api(&c, PathSetBuilder::new(), &mut pctx).await);
|
let expr = Expr::from_api(&c, PathSetBuilder::new(), &mut pctx).await;
|
||||||
|
consts.insert(self.path, expr);
|
||||||
MemberKind::Const
|
MemberKind::Const
|
||||||
},
|
},
|
||||||
api::MemberKind::Module(m) => MemberKind::Module(
|
api::MemberKind::Module(m) => MemberKind::Module(
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ use std::pin::pin;
|
|||||||
use futures::{FutureExt, StreamExt, stream};
|
use futures::{FutureExt, StreamExt, stream};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_api::Paren;
|
|
||||||
use orchid_base::error::{OrcRes, Reporter};
|
use orchid_base::error::{OrcRes, Reporter};
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::parse::{
|
use orchid_base::parse::{
|
||||||
Comment, ParseCtx, Parsed, Snippet, expect_tok, token_errv, try_pop_no_fluff,
|
Comment, ParseCtx, Parsed, Snippet, expect_tok, token_errv, try_pop_no_fluff,
|
||||||
};
|
};
|
||||||
use orchid_base::sym;
|
use orchid_base::sym;
|
||||||
|
use orchid_base::tree::Paren;
|
||||||
use orchid_extension::gen_expr::{atom, call, sym_ref};
|
use orchid_extension::gen_expr::{atom, call, sym_ref};
|
||||||
use orchid_extension::parser::{ConstCtx, PSnippet, PTok, PTokTree, ParsCtx, ParsedLine, Parser};
|
use orchid_extension::parser::{ConstCtx, PSnippet, PTok, PTokTree, ParsCtx, ParsedLine, Parser};
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ pub fn gen_macro_lib() -> Vec<GenMember> {
|
|||||||
),
|
),
|
||||||
fun(true, "resolve", |tpl: TypAtom<MacTree>| async move {
|
fun(true, "resolve", |tpl: TypAtom<MacTree>| async move {
|
||||||
call([
|
call([
|
||||||
sym_ref(sym!(macro::resolve_recur; tpl.untyped.ctx().i()).await),
|
sym_ref(sym!(macros::resolve_recur; tpl.untyped.ctx().i()).await),
|
||||||
atom(RecurState::Bottom),
|
atom(RecurState::Bottom),
|
||||||
tpl.untyped.ex().to_expr().await,
|
tpl.untyped.ex().to_expr().await,
|
||||||
])
|
])
|
||||||
@@ -43,7 +43,7 @@ pub fn gen_macro_lib() -> Vec<GenMember> {
|
|||||||
if let Some(e) = Reporter::new().errv() { Err(e) } else { Ok(res) }
|
if let Some(e) = Reporter::new().errv() { Err(e) } else { Ok(res) }
|
||||||
}),
|
}),
|
||||||
fun(true, "resolve_recur", |state: TypAtom<RecurState>, tpl: TypAtom<MacTree>| async move {
|
fun(true, "resolve_recur", |state: TypAtom<RecurState>, tpl: TypAtom<MacTree>| async move {
|
||||||
exec(async move |mut h| {
|
exec("macros::resolve_recur", async move |mut h| {
|
||||||
let ctx = tpl.ctx().clone();
|
let ctx = tpl.ctx().clone();
|
||||||
let root = refl(&ctx);
|
let root = refl(&ctx);
|
||||||
let tpl = own(tpl.clone()).await;
|
let tpl = own(tpl.clone()).await;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use futures::{StreamExt, stream};
|
|||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_api::Paren;
|
|
||||||
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
@@ -16,7 +15,7 @@ use orchid_base::parse::{
|
|||||||
Comment, ParseCtx, Parsed, Snippet, expect_end, expect_tok, line_items, token_errv,
|
Comment, ParseCtx, Parsed, Snippet, expect_end, expect_tok, line_items, token_errv,
|
||||||
try_pop_no_fluff,
|
try_pop_no_fluff,
|
||||||
};
|
};
|
||||||
use orchid_base::tree::Token;
|
use orchid_base::tree::{Paren, Token};
|
||||||
use orchid_base::{clone, sym};
|
use orchid_base::{clone, sym};
|
||||||
use orchid_extension::atom::{Atomic, TypAtom};
|
use orchid_extension::atom::{Atomic, TypAtom};
|
||||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
|
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
|
||||||
@@ -142,7 +141,7 @@ impl Parser for MacroLine {
|
|||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
Ok(call([
|
Ok(call([
|
||||||
sym_ref(sym!(macro::resolve_recur; ctx.i()).await),
|
sym_ref(sym!(macros::resolve_recur; ctx.i()).await),
|
||||||
atom(RecurState::base(path)),
|
atom(RecurState::base(path)),
|
||||||
macro_input.to_expr().await,
|
macro_input.to_expr().await,
|
||||||
]))
|
]))
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ use futures::FutureExt;
|
|||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_api::Paren;
|
|
||||||
use orchid_base::error::{OrcErrv, Reporter, mk_errv};
|
use orchid_base::error::{OrcErrv, Reporter, mk_errv};
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants, fmt};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants, fmt};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::tl_cache;
|
use orchid_base::tl_cache;
|
||||||
use orchid_base::tree::indent;
|
use orchid_base::tree::{Paren, indent};
|
||||||
use orchid_extension::atom::Atomic;
|
use orchid_extension::atom::Atomic;
|
||||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
|
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
|
||||||
use orchid_extension::conv::ToExpr;
|
use orchid_extension::conv::ToExpr;
|
||||||
|
|||||||
@@ -39,26 +39,29 @@ pub async fn resolve_seq(ctx: &mut ResolveCtx<'_>, val: &[MacTree]) -> Option<Ve
|
|||||||
let mut any_changed = false;
|
let mut any_changed = false;
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut val = val.to_vec();
|
let mut val = val.to_vec();
|
||||||
while i < val.len() {
|
'all_named: while i < val.len() {
|
||||||
let MacTok::Name(key) = val[i].tok() else { continue };
|
'one_named: {
|
||||||
let Some(options) = ctx.named.get(key) else { continue };
|
let MacTok::Name(key) = val[i].tok() else { break 'one_named };
|
||||||
let matches = (options.iter())
|
let Some(options) = ctx.named.get(key) else { break 'one_named };
|
||||||
.filter_map(|r| Some((r.1, r.2, r.0.apply(&val[i..], |_| false)?)))
|
let matches = (options.iter())
|
||||||
.collect_vec();
|
.filter_map(|r| Some((r.1, r.2, r.0.apply(&val[i..], |_| false)?)))
|
||||||
match matches.len() {
|
.collect_vec();
|
||||||
0 => i += 1,
|
match matches.len() {
|
||||||
1 => {
|
0 => break 'one_named,
|
||||||
any_changed = true;
|
1 => {
|
||||||
let (mac, rule, (state, tail)) = matches.into_iter().exactly_one().unwrap();
|
any_changed = true;
|
||||||
let end = val.len() - tail.len();
|
let (mac, rule, (state, tail)) = matches.into_iter().exactly_one().unwrap();
|
||||||
let new_i = val.len() - tail.len();
|
let end = val.len() - tail.len();
|
||||||
let body_call = mk_body_call(mac, rule, &state, &ctx.ctx, ctx.recur.clone()).await;
|
let body_call = mk_body_call(mac, rule, &state, &ctx.ctx, ctx.recur.clone()).await;
|
||||||
std::mem::drop(state);
|
std::mem::drop(state);
|
||||||
val.splice(i..end, [MacTok::Value(ctx.h.register(body_call).await).at(Pos::None)]);
|
val.splice(i..end, [MacTok::Value(ctx.h.register(body_call).await).at(Pos::None)]);
|
||||||
i = new_i;
|
i = end;
|
||||||
},
|
},
|
||||||
2.. => todo!("Named macros conflict!"),
|
2.. => todo!("Named macros conflict!"),
|
||||||
|
}
|
||||||
|
continue 'all_named;
|
||||||
}
|
}
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
for (matcher, mac, rule) in &ctx.priod {
|
for (matcher, mac, rule) in &ctx.priod {
|
||||||
let Some(state) = matcher.apply(&val, |_| false) else { continue };
|
let Some(state) = matcher.apply(&val, |_| false) else { continue };
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ async fn main() -> io::Result<ExitCode> {
|
|||||||
},
|
},
|
||||||
Commands::Exec { proj, code } => {
|
Commands::Exec { proj, code } => {
|
||||||
let reporter = Reporter::new();
|
let reporter = Reporter::new();
|
||||||
let path = sym!(usercode::entrypoint; i).await;
|
let path = sym!(usercode; i).await;
|
||||||
let prefix_sr = SrcRange::zw(path.clone(), 0);
|
let prefix_sr = SrcRange::zw(path.clone(), 0);
|
||||||
let (mut root, systems) = init_systems(&args.system, &extensions).await.unwrap();
|
let (mut root, systems) = init_systems(&args.system, &extensions).await.unwrap();
|
||||||
if let Some(proj_path) = proj {
|
if let Some(proj_path) = proj {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub fn check_api_refs(_args: &Args) -> io::Result<()> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let dname = file.path().to_string_lossy().to_string();
|
let dname = file.path().to_string_lossy().to_string();
|
||||||
eprintln!("orchid_api imported in {dname} at {};{}", l + 1, c + 1)
|
eprintln!("orchid_api imported in {dname}:{}:{}", l + 1, c + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -5,18 +5,23 @@ use std::sync::atomic::Ordering;
|
|||||||
use crate::{Args, EXIT_OK};
|
use crate::{Args, EXIT_OK};
|
||||||
|
|
||||||
pub fn orcx(_args: &Args, argv: &[String]) -> io::Result<()> {
|
pub fn orcx(_args: &Args, argv: &[String]) -> io::Result<()> {
|
||||||
if !Command::new("cargo").args(["build", "-p", "orchid-std"]).status()?.success() {
|
if !Command::new("cargo").args(["build", "-p", "orchid-std", "--quiet"]).status()?.success() {
|
||||||
EXIT_OK.store(false, Ordering::Relaxed);
|
EXIT_OK.store(false, Ordering::Relaxed);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if !Command::new("cargo").args(["run", "-p", "orcx", "--"]).args(argv).status()?.success() {
|
if !Command::new("cargo")
|
||||||
|
.args(["run", "-p", "orcx", "--quiet", "--"])
|
||||||
|
.args(argv)
|
||||||
|
.status()?
|
||||||
|
.success()
|
||||||
|
{
|
||||||
EXIT_OK.store(false, Ordering::Relaxed);
|
EXIT_OK.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn orcxdb(_args: &Args, argv: &[String]) -> io::Result<()> {
|
pub fn orcxdb(_args: &Args, argv: &[String]) -> io::Result<()> {
|
||||||
if !Command::new("cargo").args(["build", "-p", "orchid-std"]).status()?.success() {
|
if !Command::new("cargo").args(["build", "-p", "orchid-std", "--quiet"]).status()?.success() {
|
||||||
EXIT_OK.store(false, Ordering::Relaxed);
|
EXIT_OK.store(false, Ordering::Relaxed);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user