for a moment, everything works
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1124,7 +1124,6 @@ dependencies = [
|
||||
"ordered-float",
|
||||
"regex",
|
||||
"rust-embed",
|
||||
"rust_decimal",
|
||||
"some_executor 0.4.0",
|
||||
"substack",
|
||||
"test_executors",
|
||||
@@ -1201,6 +1200,7 @@ dependencies = [
|
||||
"orchid-base",
|
||||
"orchid-extension",
|
||||
"ordered-float",
|
||||
"rust_decimal",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
||||
4
SWAP.md
4
SWAP.md
@@ -1,9 +1,5 @@
|
||||
## Async conversion
|
||||
|
||||
convert host to async non-send
|
||||
|
||||
demonstrate operation with existing lex-hello example
|
||||
|
||||
consider converting extension's SysCtx to a typed context bag
|
||||
|
||||
align fn atom and macros on both sides with new design. No global state.
|
||||
|
||||
@@ -23,7 +23,6 @@ orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
||||
ordered-float = "4.6.0"
|
||||
regex = "1.11.1"
|
||||
rust-embed = "8.5.0"
|
||||
rust_decimal = "1.36.0"
|
||||
some_executor = "0.4.0"
|
||||
substack = "1.1.1"
|
||||
test_executors = "0.3.2"
|
||||
|
||||
@@ -98,7 +98,7 @@ impl Interned for String {
|
||||
impl InternMarker for api::TStr {
|
||||
type Interned = String;
|
||||
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
||||
Tok::new(Rc::new(i.master.as_ref().unwrap().request(api::ExternStr(self)).await), self)
|
||||
Tok::new(Rc::new(i.0.master.as_ref().unwrap().request(api::ExternStr(self)).await), self)
|
||||
}
|
||||
fn get_id(self) -> NonZeroU64 { self.0 }
|
||||
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||
@@ -125,7 +125,7 @@ impl Interned for Vec<Tok<String>> {
|
||||
impl InternMarker for api::TStrv {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
||||
let rep = i.master.as_ref().unwrap().request(api::ExternStrv(self)).await;
|
||||
let rep = i.0.master.as_ref().unwrap().request(api::ExternStrv(self)).await;
|
||||
let data = futures::future::join_all(rep.into_iter().map(|m| i.ex(m))).await;
|
||||
Tok::new(Rc::new(data), self)
|
||||
}
|
||||
@@ -217,24 +217,26 @@ pub struct TypedInterners {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Interner {
|
||||
pub struct InternerData {
|
||||
interners: Mutex<TypedInterners>,
|
||||
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
|
||||
}
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Interner(Rc<InternerData>);
|
||||
impl Interner {
|
||||
pub fn new_master() -> Self { Self::default() }
|
||||
pub fn new_replica(req: impl DynRequester<Transfer = api::IntReq> + 'static) -> Self {
|
||||
Self { master: Some(Box::new(req)), interners: Mutex::default() }
|
||||
Self(Rc::new(InternerData { master: Some(Box::new(req)), interners: Mutex::default() }))
|
||||
}
|
||||
/// Intern some data; query its identifier if not known locally
|
||||
pub async fn i<T: Interned>(&self, t: &(impl Internable<Interned = T> + ?Sized)) -> Tok<T> {
|
||||
let data = t.get_owned();
|
||||
let mut g = self.interners.lock().await;
|
||||
let mut g = self.0.interners.lock().await;
|
||||
let typed = T::bimap(&mut g);
|
||||
if let Some(tok) = typed.by_value(&data) {
|
||||
return tok;
|
||||
}
|
||||
let marker = match &self.master {
|
||||
let marker = match &self.0.master {
|
||||
Some(c) => data.clone().intern(&**c).await,
|
||||
None =>
|
||||
T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()),
|
||||
@@ -245,29 +247,29 @@ impl Interner {
|
||||
}
|
||||
/// Extern an identifier; query the data it represents if not known locally
|
||||
pub async fn ex<M: InternMarker>(&self, marker: M) -> Tok<M::Interned> {
|
||||
if let Some(tok) = M::Interned::bimap(&mut *self.interners.lock().await).by_marker(marker) {
|
||||
if let Some(tok) = M::Interned::bimap(&mut *self.0.interners.lock().await).by_marker(marker) {
|
||||
return tok;
|
||||
}
|
||||
assert!(self.master.is_some(), "ID not in local interner and this is master");
|
||||
assert!(self.0.master.is_some(), "ID not in local interner and this is master");
|
||||
let token = marker.resolve(self).await;
|
||||
M::Interned::bimap(&mut *self.interners.lock().await).insert(token.clone());
|
||||
M::Interned::bimap(&mut *self.0.interners.lock().await).insert(token.clone());
|
||||
token
|
||||
}
|
||||
pub async fn sweep_replica(&self) -> api::Retained {
|
||||
assert!(self.master.is_some(), "Not a replica");
|
||||
let mut g = self.interners.lock().await;
|
||||
assert!(self.0.master.is_some(), "Not a replica");
|
||||
let mut g = self.0.interners.lock().await;
|
||||
api::Retained { strings: g.strings.sweep_replica(), vecs: g.vecs.sweep_replica() }
|
||||
}
|
||||
pub async fn sweep_master(&self, retained: api::Retained) {
|
||||
assert!(self.master.is_none(), "Not master");
|
||||
let mut g = self.interners.lock().await;
|
||||
assert!(self.0.master.is_none(), "Not master");
|
||||
let mut g = self.0.interners.lock().await;
|
||||
g.strings.sweep_master(retained.strings.into_iter().collect());
|
||||
g.vecs.sweep_master(retained.vecs.into_iter().collect());
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for Interner {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Interner{{ replica: {} }}", self.master.is_none())
|
||||
write!(f, "Interner{{ replica: {} }}", self.0.master.is_none())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::num::IntErrorKind;
|
||||
use std::ops::Range;
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
use ordered_float::NotNan;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
use crate::error::{OrcErr, mk_err};
|
||||
use crate::interner::Interner;
|
||||
@@ -12,24 +10,17 @@ use crate::location::Pos;
|
||||
/// A number, either floating point or unsigned int, parsed by Orchid.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Numeric {
|
||||
/// A nonnegative integer
|
||||
Uint(u64),
|
||||
/// An integer
|
||||
Int(i64),
|
||||
/// A binary float other than NaN
|
||||
Float(NotNan<f64>),
|
||||
/// A decimal number
|
||||
Decimal(Decimal),
|
||||
}
|
||||
impl Numeric {
|
||||
pub fn decimal(num: i64, scale: u32) -> Self { Self::Decimal(Decimal::new(num, scale)) }
|
||||
pub fn float(value: f64) -> Self { Self::Float(NotNan::new(value).unwrap()) }
|
||||
pub fn to_f64(self) -> NotNan<f64> {
|
||||
match self {
|
||||
Self::Float(f) => f,
|
||||
Self::Decimal(d) => {
|
||||
let f = d.to_f64().expect("This is apparently always possible");
|
||||
NotNan::new(f).expect("decimal was nan")
|
||||
},
|
||||
Self::Uint(i) => NotNan::new(i as f64).expect("int cannot be NaN"),
|
||||
Self::Int(i) => NotNan::new(i as f64).expect("int cannot be NaN"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,31 +68,31 @@ pub async fn num_to_err(NumError { kind, range }: NumError, offset: u32, i: &Int
|
||||
|
||||
/// Parse a numbre literal out of text
|
||||
pub fn parse_num(string: &str) -> Result<Numeric, NumError> {
|
||||
let overflow_err = NumError { range: 0..string.len(), kind: NumErrorKind::Overflow };
|
||||
let overflow_e = NumError { range: 0..string.len(), kind: NumErrorKind::Overflow };
|
||||
let (radix, noprefix, pos) = (string.strip_prefix("0x").map(|s| (16u8, s, 2)))
|
||||
.or_else(|| string.strip_prefix("0b").map(|s| (2u8, s, 2)))
|
||||
.or_else(|| string.strip_prefix("0o").map(|s| (8u8, s, 2)))
|
||||
.unwrap_or((10u8, string, 0));
|
||||
eprintln!("({radix}, {noprefix}, {pos})");
|
||||
// identity
|
||||
let (base, exponent) = match noprefix.split_once('p') {
|
||||
let (base_s, exponent) = match noprefix.split_once('p') {
|
||||
Some((b, e)) => {
|
||||
let (s, d, len) = e.strip_prefix('-').map_or((1, e, 0), |ue| (-1, ue, 1));
|
||||
(b, s * int_parse(d, 10, pos + b.len() + 1 + len)? as i32)
|
||||
},
|
||||
None => (noprefix, 0),
|
||||
};
|
||||
eprintln!("({base},{exponent})");
|
||||
match base.split_once('.') {
|
||||
eprintln!("({base_s},{exponent})");
|
||||
match base_s.split_once('.') {
|
||||
None => {
|
||||
let base_usize = int_parse(base, radix, pos)?;
|
||||
let base = int_parse(base_s, radix, pos)?;
|
||||
if let Ok(pos_exp) = u32::try_from(exponent) {
|
||||
if let Some(radical) = u64::from(radix).checked_pow(pos_exp) {
|
||||
let number = base_usize.checked_mul(radical).ok_or(overflow_err)?;
|
||||
return Ok(Numeric::Uint(number));
|
||||
let num = base.checked_mul(radical).and_then(|m| m.try_into().ok()).ok_or(overflow_e)?;
|
||||
return Ok(Numeric::Int(num));
|
||||
}
|
||||
}
|
||||
let f = (base_usize as f64) * (radix as f64).powi(exponent);
|
||||
let f = (base as f64) * (radix as f64).powi(exponent);
|
||||
let err = NumError { range: 0..string.len(), kind: NumErrorKind::NaN };
|
||||
Ok(Numeric::Float(NotNan::new(f).map_err(|_| err)?))
|
||||
},
|
||||
@@ -109,25 +100,9 @@ pub fn parse_num(string: &str) -> Result<Numeric, NumError> {
|
||||
let whole_n = int_parse(whole, radix, pos)?;
|
||||
let part_n = int_parse(part, radix, pos + whole.len() + 1)?;
|
||||
let scale = part.chars().filter(|c| *c != '_').count() as u32;
|
||||
if radix == 10 {
|
||||
let scaled_unit = 10u64.checked_pow(scale).ok_or(overflow_err.clone())?;
|
||||
let scaled_n = i128::from(whole_n) * i128::from(scaled_unit) + i128::from(part_n);
|
||||
let decimal = Decimal::from_i128_with_scale(scaled_n, scale);
|
||||
let p = if let Ok(uexp) = u32::try_from(exponent) {
|
||||
let e_multiplier = 10i64.checked_pow(uexp).ok_or(overflow_err)?;
|
||||
Decimal::new(e_multiplier, 0)
|
||||
} else {
|
||||
let inv_oom = u32::try_from(-exponent).map_err(|_| overflow_err)?;
|
||||
eprintln!("inv_oom: {inv_oom}");
|
||||
Decimal::new(1, inv_oom)
|
||||
};
|
||||
eprintln!("({scaled_n}, {scale}, {p})");
|
||||
Ok(Numeric::Decimal(decimal * p))
|
||||
} else {
|
||||
let real_val = whole_n as f64 + (part_n as f64 / (radix as f64).powi(scale as i32));
|
||||
let f = real_val * (radix as f64).powi(exponent);
|
||||
Ok(Numeric::Float(NotNan::new(f).expect("None of the inputs are NaN")))
|
||||
}
|
||||
let real_val = whole_n as f64 + (part_n as f64 / (radix as f64).powi(scale as i32));
|
||||
let f = real_val * (radix as f64).powi(exponent);
|
||||
Ok(Numeric::Float(NotNan::new(f).expect("None of the inputs are NaN")))
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -168,7 +143,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn just_ints() {
|
||||
let test = |s, n| assert_eq!(parse_num(s), Ok(Numeric::Uint(n)));
|
||||
let test = |s, n| assert_eq!(parse_num(s), Ok(Numeric::Int(n)));
|
||||
test("12345", 12345);
|
||||
test("0xcafebabe", 0xcafebabe);
|
||||
test("0o751", 0o751);
|
||||
@@ -178,11 +153,11 @@ mod test {
|
||||
#[test]
|
||||
fn decimals() {
|
||||
let test = |s, n| assert_eq!(parse_num(s), Ok(n));
|
||||
test("3.1417", Numeric::decimal(31417, 4));
|
||||
test("3.1417", Numeric::float(3.1417));
|
||||
test("0xf.cafe", Numeric::float(0xf as f64 + 0xcafe as f64 / 0x10000 as f64));
|
||||
test("34p3", Numeric::Uint(34000));
|
||||
test("0x2p3", Numeric::Uint(0x2 * 0x1000));
|
||||
test("1.5p3", Numeric::decimal(1500, 0));
|
||||
test("34p3", Numeric::Int(34000));
|
||||
test("0x2p3", Numeric::Int(0x2 * 0x1000));
|
||||
test("1.5p3", Numeric::float(1500.0));
|
||||
test("0x2.5p3", Numeric::float((0x25 * 0x100) as f64));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,13 @@ pub trait AtomicVariant {}
|
||||
pub trait Atomic: 'static + Sized {
|
||||
type Variant: AtomicVariant;
|
||||
type Data: Clone + Coding + Sized + 'static;
|
||||
/// Register handlers for IPC calls. If this atom implements [Supports], you
|
||||
/// should register your implementations here. If this atom doesn't
|
||||
/// participate in IPC at all, use the below body.
|
||||
/// ```
|
||||
/// MethodSetBuilder::new()
|
||||
/// ```
|
||||
// this method isn't default-implemented to prevent bugs from forgetting to register IPC requests.
|
||||
fn reg_reqs() -> MethodSetBuilder<Self>;
|
||||
}
|
||||
impl<A: Atomic> AtomCard for A {
|
||||
@@ -106,9 +113,9 @@ impl ForeignAtom<'static> {
|
||||
ForeignAtom { _life: PhantomData, atom, ctx: handle.ctx.clone(), expr: Some(handle), pos }
|
||||
}
|
||||
pub async fn request<M: AtomMethod>(&self, m: M) -> Option<M::Response> {
|
||||
let rep = (self.ctx.reqnot.request(api::Fwd(
|
||||
let rep = (self.ctx.reqnot().request(api::Fwd(
|
||||
self.atom.clone(),
|
||||
Sym::parse(M::NAME, &self.ctx.i).await.unwrap().tok().to_api(),
|
||||
Sym::parse(M::NAME, self.ctx.i()).await.unwrap().tok().to_api(),
|
||||
enc_vec(&m).await,
|
||||
)))
|
||||
.await?;
|
||||
@@ -125,7 +132,7 @@ impl fmt::Debug for ForeignAtom<'_> {
|
||||
}
|
||||
impl Format for ForeignAtom<'_> {
|
||||
async fn print<'a>(&'a self, _c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||
FmtUnit::from_api(&self.ctx.reqnot.request(api::ExtAtomPrint(self.atom.clone())).await)
|
||||
FmtUnit::from_api(&self.ctx.reqnot().request(api::ExtAtomPrint(self.atom.clone())).await)
|
||||
}
|
||||
}
|
||||
impl AtomRepr for ForeignAtom<'_> {
|
||||
@@ -145,7 +152,7 @@ pub struct NotTypAtom {
|
||||
impl NotTypAtom {
|
||||
pub async fn mk_err(&self) -> OrcErr {
|
||||
mk_err(
|
||||
self.ctx.i.i("Not the expected type").await,
|
||||
self.ctx.i().i("Not the expected type").await,
|
||||
format!("This expression is not a {}", self.typ.name()),
|
||||
[self.pos.clone().into()],
|
||||
)
|
||||
@@ -192,7 +199,7 @@ impl<A: AtomCard> MethodSetBuilder<A> {
|
||||
handlers: stream::from_iter(self.handlers.iter())
|
||||
.then(|(k, v)| {
|
||||
clone!(ctx; async move {
|
||||
(Sym::parse(k, &ctx.i).await.unwrap(), v.clone())
|
||||
(Sym::parse(k, ctx.i()).await.unwrap(), v.clone())
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@@ -257,9 +264,9 @@ impl<A: AtomicFeatures> TypAtom<'_, A> {
|
||||
pub async fn request<M: AtomMethod>(&self, req: M) -> M::Response
|
||||
where A: Supports<M> {
|
||||
M::Response::decode(Pin::new(
|
||||
&mut &(self.data.ctx.reqnot.request(api::Fwd(
|
||||
&mut &(self.data.ctx.reqnot().request(api::Fwd(
|
||||
self.data.atom.clone(),
|
||||
Sym::parse(M::NAME, &self.data.ctx.i).await.unwrap().tok().to_api(),
|
||||
Sym::parse(M::NAME, self.data.ctx.i()).await.unwrap().tok().to_api(),
|
||||
enc_vec(&req).await,
|
||||
)))
|
||||
.await
|
||||
@@ -275,7 +282,7 @@ impl<A: AtomicFeatures> Deref for TypAtom<'_, A> {
|
||||
|
||||
pub struct AtomCtx<'a>(pub &'a [u8], pub Option<api::AtomId>, pub SysCtx);
|
||||
impl FmtCtx for AtomCtx<'_> {
|
||||
fn i(&self) -> &Interner { &self.2.i }
|
||||
fn i(&self) -> &Interner { self.2.i() }
|
||||
}
|
||||
|
||||
pub trait AtomDynfo: 'static {
|
||||
|
||||
@@ -28,20 +28,23 @@ use crate::atom::{
|
||||
};
|
||||
use crate::expr::{Expr, ExprHandle};
|
||||
use crate::gen_expr::{GExpr, bot};
|
||||
use crate::system::SysCtx;
|
||||
use crate::system::{SysCtx, SysCtxEntry};
|
||||
use crate::system_ctor::CtedObj;
|
||||
|
||||
pub struct OwnedVariant;
|
||||
impl AtomicVariant for OwnedVariant {}
|
||||
impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVariant> for A {
|
||||
fn _factory(self) -> AtomFactory {
|
||||
AtomFactory::new(move |ctx| async move {
|
||||
let serial = ctx.obj_store.0.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
let serial =
|
||||
ctx.get_or_default::<ObjStore>().next_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
let atom_id = api::AtomId(NonZero::new(serial + 1).unwrap());
|
||||
let (typ_id, _) = get_info::<A>(ctx.cted.inst().card());
|
||||
let (typ_id, _) = get_info::<A>(ctx.get::<CtedObj>().inst().card());
|
||||
let mut data = enc_vec(&typ_id).await;
|
||||
self.encode(Pin::<&mut Vec<u8>>::new(&mut data)).await;
|
||||
ctx.obj_store.1.read().await.insert(atom_id, Box::new(self));
|
||||
api::Atom { drop: Some(atom_id), data, owner: ctx.id }
|
||||
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() }
|
||||
})
|
||||
}
|
||||
fn _info() -> Self::_Info { OwnedAtomDynfo { msbuild: A::reg_reqs(), ms: OnceCell::new() } }
|
||||
@@ -55,8 +58,9 @@ pub(crate) struct AtomReadGuard<'a> {
|
||||
}
|
||||
impl<'a> AtomReadGuard<'a> {
|
||||
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
|
||||
let guard = ctx.obj_store.1.read().await;
|
||||
assert!(guard.get(&id).is_some(), "Received invalid atom ID: {}", id.0);
|
||||
let guard = ctx.get_or_default::<ObjStore>().objects.read().await;
|
||||
let valid = guard.iter().map(|i| i.0).collect_vec();
|
||||
assert!(guard.get(&id).is_some(), "Received invalid atom ID: {:?} not in {:?}", id, valid);
|
||||
Self { id, guard }
|
||||
}
|
||||
}
|
||||
@@ -66,7 +70,7 @@ impl Deref for AtomReadGuard<'_> {
|
||||
}
|
||||
|
||||
pub(crate) async fn take_atom(id: api::AtomId, ctx: &SysCtx) -> Box<dyn DynOwnedAtom> {
|
||||
let mut g = ctx.obj_store.1.write().await;
|
||||
let mut g = ctx.get_or_default::<ObjStore>().objects.write().await;
|
||||
g.remove(&id).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0))
|
||||
}
|
||||
|
||||
@@ -219,7 +223,7 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Any + Clone + 'static {
|
||||
fn val(&self) -> impl Future<Output = Cow<'_, Self::Data>>;
|
||||
#[allow(unused_variables)]
|
||||
fn call_ref(&self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
||||
async move { bot([err_not_callable(&arg.ctx.i).await]) }
|
||||
async move { bot([err_not_callable(arg.ctx.i()).await]) }
|
||||
}
|
||||
fn call(self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
||||
async {
|
||||
@@ -231,7 +235,7 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Any + Clone + 'static {
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn command(self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<GExpr>>> {
|
||||
async move { Err(err_not_command(&ctx.i).await.into()) }
|
||||
async move { Err(err_not_command(ctx.i()).await.into()) }
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn free(self, ctx: SysCtx) -> impl Future<Output = ()> { async {} }
|
||||
@@ -313,4 +317,9 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ObjStore = Rc<(AtomicU64, RwLock<MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>)>;
|
||||
#[derive(Default)]
|
||||
struct ObjStore {
|
||||
next_id: AtomicU64,
|
||||
objects: RwLock<MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>,
|
||||
}
|
||||
impl SysCtxEntry for ObjStore {}
|
||||
|
||||
@@ -19,16 +19,17 @@ use crate::atom::{
|
||||
use crate::expr::ExprHandle;
|
||||
use crate::gen_expr::{GExpr, bot};
|
||||
use crate::system::SysCtx;
|
||||
use crate::system_ctor::CtedObj;
|
||||
|
||||
pub struct ThinVariant;
|
||||
impl AtomicVariant for ThinVariant {}
|
||||
impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant> for A {
|
||||
fn _factory(self) -> AtomFactory {
|
||||
AtomFactory::new(move |ctx| async move {
|
||||
let (id, _) = get_info::<A>(ctx.cted.inst().card());
|
||||
let (id, _) = get_info::<A>(ctx.get::<CtedObj>().inst().card());
|
||||
let mut buf = enc_vec(&id).await;
|
||||
self.encode(Pin::new(&mut buf)).await;
|
||||
api::Atom { drop: None, data: buf, owner: ctx.id }
|
||||
api::Atom { drop: None, data: buf, owner: ctx.sys_id() }
|
||||
})
|
||||
}
|
||||
fn _info() -> Self::_Info { ThinAtomDynfo { msbuild: Self::reg_reqs(), ms: OnceCell::new() } }
|
||||
@@ -106,7 +107,7 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
fn drop<'a>(&'a self, AtomCtx(buf, _, ctx): AtomCtx<'a>) -> LocalBoxFuture<'a, ()> {
|
||||
async move {
|
||||
let string_self = T::decode(Pin::new(&mut &buf[..])).await.print(ctx.clone()).await;
|
||||
writeln!(ctx.logger, "Received drop signal for non-drop atom {string_self:?}");
|
||||
writeln!(ctx.logger(), "Received drop signal for non-drop atom {string_self:?}");
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
@@ -117,11 +118,11 @@ pub trait ThinAtom:
|
||||
{
|
||||
#[allow(unused_variables)]
|
||||
fn call(&self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
||||
async move { bot([err_not_callable(&arg.ctx.i).await]) }
|
||||
async move { bot([err_not_callable(arg.ctx.i()).await]) }
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn command(&self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<GExpr>>> {
|
||||
async move { Err(err_not_command(&ctx.i).await.into()) }
|
||||
async move { Err(err_not_command(ctx.i()).await.into()) }
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn print(&self, ctx: SysCtx) -> impl Future<Output = FmtUnit> {
|
||||
|
||||
@@ -34,10 +34,10 @@ async fn err_type(pos: Pos, i: &Interner) -> OrcErr {
|
||||
impl<A: AtomicFeatures> TryFromExpr for TypAtom<'_, A> {
|
||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||
match expr.atom().await {
|
||||
Err(ex) => Err(err_not_atom(ex.data().await.pos.clone(), &ex.ctx().i).await.into()),
|
||||
Err(ex) => Err(err_not_atom(ex.data().await.pos.clone(), ex.ctx().i()).await.into()),
|
||||
Ok(f) => match downcast_atom::<A>(f).await {
|
||||
Ok(a) => Ok(a),
|
||||
Err(f) => Err(err_type(f.pos(), &f.ctx().i).await.into()),
|
||||
Err(f) => Err(err_type(f.pos(), f.ctx().i()).await.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use futures::future::{LocalBoxFuture, join_all};
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use orchid_api::ApplyMacro;
|
||||
use orchid_api::{ApplyMacro, ExtMsgSet};
|
||||
use orchid_api_traits::{Decode, Encode, enc_vec};
|
||||
use orchid_base::builtin::{ExtPort, Spawner};
|
||||
use orchid_base::char_filter::{char_filter_match, char_filter_union, mk_char_filter};
|
||||
@@ -32,14 +32,14 @@ use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId};
|
||||
use crate::atom_owned::{ObjStore, take_atom};
|
||||
use crate::atom_owned::take_atom;
|
||||
use crate::fs::VirtFS;
|
||||
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
|
||||
use crate::macros::{Rule, RuleCtx};
|
||||
use crate::msg::{recv_parent_msg, send_parent_msg};
|
||||
use crate::system::{SysCtx, atom_by_idx};
|
||||
use crate::system_ctor::{CtedObj, DynSystemCtor};
|
||||
use crate::tree::{GenTok, GenTokTree, LazyMemberFactory, TIACtxImpl, do_extra};
|
||||
use crate::tree::{GenTok, GenTokTree, LazyMemberFactory, TreeIntoApiCtxImpl, do_extra};
|
||||
|
||||
pub type ExtReq<'a> = RequestHandle<'a, api::ExtMsgSet>;
|
||||
pub type ExtReqNot = ReqNot<api::ExtMsgSet>;
|
||||
@@ -61,11 +61,11 @@ pub enum MemberRecord {
|
||||
}
|
||||
|
||||
pub struct SystemRecord {
|
||||
cted: CtedObj,
|
||||
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
|
||||
declfs: api::EagerVfs,
|
||||
lazy_members: HashMap<api::TreeId, MemberRecord>,
|
||||
rules: HashMap<api::MacroId, Rc<Rule>>,
|
||||
ctx: SysCtx,
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
@@ -78,14 +78,13 @@ trait_set! {
|
||||
}
|
||||
|
||||
pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
|
||||
get_sys_ctx: &impl Fn(api::SysId, ReqNot<api::ExtMsgSet>) -> F,
|
||||
reqnot: ReqNot<api::ExtMsgSet>,
|
||||
get_sys_ctx: &impl Fn(api::SysId) -> F,
|
||||
atom: &'a api::Atom,
|
||||
cb: impl WARCallback<'a, T>,
|
||||
) -> T {
|
||||
let mut data = &atom.data[..];
|
||||
let ctx = get_sys_ctx(atom.owner, reqnot).await;
|
||||
let inst = ctx.cted.inst();
|
||||
let ctx = get_sys_ctx(atom.owner).await;
|
||||
let inst = ctx.get::<CtedObj>().inst();
|
||||
let id = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||
let atom_record = atom_by_idx(inst.card(), id.clone()).expect("Atom ID reserved");
|
||||
cb(atom_record, ctx, id, data).await
|
||||
@@ -108,6 +107,7 @@ pub struct ExtensionOwner {
|
||||
rn: ReqNot<api::ExtMsgSet>,
|
||||
out_recv: Receiver<Vec<u8>>,
|
||||
out_send: Sender<Vec<u8>>,
|
||||
ext_header: api::ExtensionHeader,
|
||||
}
|
||||
|
||||
impl ExtPort for ExtensionOwner {
|
||||
@@ -125,6 +125,12 @@ impl ExtPort for ExtensionOwner {
|
||||
.boxed_local()
|
||||
}
|
||||
}
|
||||
impl ExtensionOwner {
|
||||
pub fn ext_header(&self) -> &api::ExtensionHeader { &self.ext_header }
|
||||
// pub async fn new(data: ExtensionData, spawner: Spawner, header:
|
||||
// api::HostHeader) -> Self { let decls =
|
||||
// }
|
||||
}
|
||||
|
||||
pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
let api::HostHeader { log_strategy, msg_logs } =
|
||||
@@ -134,7 +140,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
.map(|(id, sys)| (u16::try_from(id).expect("more than u16max system ctors"), sys))
|
||||
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
|
||||
.collect_vec();
|
||||
let systems = Rc::new(Mutex::new(HashMap::<api::SysId, SystemRecord>::new()));
|
||||
let systems_lock = Rc::new(Mutex::new(HashMap::<api::SysId, SystemRecord>::new()));
|
||||
api::ExtensionHeader { name: data.name.to_string(), systems: decls.clone() }
|
||||
.encode(Pin::new(&mut buf))
|
||||
.await;
|
||||
@@ -143,41 +149,48 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
let exiting = Arc::new(AtomicBool::new(false));
|
||||
let logger = Logger::new(log_strategy);
|
||||
let msg_logger = Logger::new(msg_logs);
|
||||
let interner_cell = Rc::new(RefCell::new(None::<Rc<Interner>>));
|
||||
let interner_cell = Rc::new(RefCell::new(None::<Interner>));
|
||||
let interner_weak = Rc::downgrade(&interner_cell);
|
||||
let obj_store = ObjStore::default();
|
||||
let mk_ctx = clone!(
|
||||
logger, systems, spawner, obj_store, interner_weak;
|
||||
move |id: api::SysId, reqnot: ReqNot<api::ExtMsgSet>| {
|
||||
clone!(logger, systems, spawner, obj_store, interner_weak; async move {
|
||||
let cted = systems.lock().await[&id].cted.clone();
|
||||
let interner_cell = (interner_weak.upgrade())
|
||||
.expect("mk_ctx called after Interner rc dropped");
|
||||
let i = (interner_cell.borrow().clone())
|
||||
.expect("mk_ctx called before interner initialized");
|
||||
SysCtx { id, cted, logger, reqnot, spawner, obj_store, i: i.clone() }
|
||||
}.boxed_local())
|
||||
});
|
||||
let systems_weak = Rc::downgrade(&systems_lock);
|
||||
let get_ctx = clone!(systems_weak; move |id: api::SysId| clone!(systems_weak; async move {
|
||||
let systems =
|
||||
systems_weak.upgrade().expect("System table dropped before request processing done");
|
||||
let x = systems.lock().await.get(&id).expect("System not found").ctx.clone();
|
||||
x
|
||||
}));
|
||||
let init_ctx = {
|
||||
clone!(systems_weak, interner_weak, spawner, logger);
|
||||
move |id: api::SysId, cted: CtedObj, reqnot: ReqNot<ExtMsgSet>| {
|
||||
clone!(systems_weak, interner_weak, spawner, logger; async move {
|
||||
let interner_rc =
|
||||
interner_weak.upgrade().expect("System construction order while shutting down");
|
||||
let i = interner_rc.borrow().clone().expect("mk_ctx called very early, no interner!");
|
||||
SysCtx::new(id, i, reqnot, spawner, logger, cted)
|
||||
})
|
||||
}
|
||||
};
|
||||
let rn = ReqNot::<api::ExtMsgSet>::new(
|
||||
msg_logger.clone(),
|
||||
move |a, _| async move { send_parent_msg(a).await.unwrap() }.boxed_local(),
|
||||
clone!(systems, exiting, mk_ctx; move |n, reqnot| {
|
||||
clone!(systems, exiting, mk_ctx; async move {
|
||||
clone!(systems_weak, exiting, get_ctx; move |n, reqnot| {
|
||||
clone!(systems_weak, exiting, get_ctx; async move {
|
||||
match n {
|
||||
api::HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
|
||||
api::HostExtNotif::SystemDrop(api::SystemDrop(sys_id)) =>
|
||||
mem::drop(systems.lock().await.remove(&sys_id)),
|
||||
if let Some(rc) = systems_weak.upgrade() {
|
||||
mem::drop(rc.lock().await.remove(&sys_id))
|
||||
},
|
||||
api::HostExtNotif::AtomDrop(api::AtomDrop(sys_id, atom)) => {
|
||||
let ctx = mk_ctx(sys_id, reqnot).await;
|
||||
let ctx = get_ctx(sys_id).await;
|
||||
take_atom(atom, &ctx).await.dyn_free(ctx.clone()).await
|
||||
}
|
||||
}
|
||||
}.boxed_local())
|
||||
}),
|
||||
{
|
||||
clone!(systems, logger, mk_ctx, interner_weak, obj_store, spawner, decls, msg_logger);
|
||||
clone!(logger, get_ctx, init_ctx, systems_weak, interner_weak, spawner, decls, msg_logger);
|
||||
move |hand, req| {
|
||||
clone!(systems, logger, mk_ctx, interner_weak, obj_store, spawner, decls, msg_logger);
|
||||
clone!(logger, get_ctx, init_ctx, systems_weak, interner_weak, spawner, decls, msg_logger);
|
||||
async move {
|
||||
let interner_cell = interner_weak.upgrade().expect("Interner dropped before request");
|
||||
let i = interner_cell.borrow().clone().expect("Request arrived before interner set");
|
||||
@@ -197,21 +210,13 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
});
|
||||
let lazy_mems = Mutex::new(HashMap::new());
|
||||
let rules = Mutex::new(HashMap::new());
|
||||
let ctx = SysCtx {
|
||||
cted: cted.clone(),
|
||||
id: new_sys.id,
|
||||
logger: logger.clone(),
|
||||
reqnot: hand.reqnot(),
|
||||
i: i.clone(),
|
||||
obj_store: obj_store.clone(),
|
||||
spawner: spawner.clone(),
|
||||
};
|
||||
let ctx = init_ctx(new_sys.id, cted.clone(), hand.reqnot()).await;
|
||||
let const_root = stream::from_iter(cted.inst().dyn_env())
|
||||
.then(|(k, v)| {
|
||||
let (req, lazy_mems, rules) = (&hand, &lazy_mems, &rules);
|
||||
clone!(i, ctx; async move {
|
||||
let name = i.i(&k).await.to_api();
|
||||
let value = v.into_api(&mut TIACtxImpl {
|
||||
let value = v.into_api(&mut TreeIntoApiCtxImpl {
|
||||
lazy_members: &mut *lazy_mems.lock().await,
|
||||
rules: &mut *rules.lock().await,
|
||||
sys: ctx,
|
||||
@@ -229,17 +234,19 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
let record = SystemRecord {
|
||||
declfs,
|
||||
vfses,
|
||||
cted,
|
||||
ctx,
|
||||
lazy_members: lazy_mems.into_inner(),
|
||||
rules: rules.into_inner(),
|
||||
};
|
||||
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
|
||||
systems.lock().await.insert(new_sys.id, record);
|
||||
hand
|
||||
.handle(&new_sys, &api::SystemInst { lex_filter, const_root, line_types: vec![] })
|
||||
.await
|
||||
},
|
||||
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
|
||||
let sys_ctx = mk_ctx(sys_id, hand.reqnot()).await;
|
||||
let sys_ctx = get_ctx(sys_id).await;
|
||||
let systems = systems_weak.upgrade().expect("Member queried during shutdown");
|
||||
let mut systems_g = systems.lock().await;
|
||||
let SystemRecord { lazy_members, rules, .. } =
|
||||
systems_g.get_mut(&sys_id).expect("System not found");
|
||||
@@ -248,8 +255,8 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
|
||||
Some(MemberRecord::Gen(path, cb)) => (path, cb),
|
||||
};
|
||||
let tree = cb.build(Sym::new(path.clone(), &i).await.unwrap()).await;
|
||||
let mut tia_ctx = TIACtxImpl {
|
||||
let tree = cb.build(Sym::new(path.clone(), &i).await.unwrap(), sys_ctx.clone()).await;
|
||||
let mut tia_ctx = TreeIntoApiCtxImpl {
|
||||
sys: sys_ctx,
|
||||
path: Substack::Bottom,
|
||||
basepath: &path,
|
||||
@@ -260,32 +267,33 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
|
||||
},
|
||||
api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs @ api::GetVfs(sys_id))) => {
|
||||
let systems = systems_weak.upgrade().expect("VFS root requested during shutdown");
|
||||
let systems_g = systems.lock().await;
|
||||
hand.handle(&get_vfs, &systems_g[&sys_id].declfs).await
|
||||
},
|
||||
api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
|
||||
let api::SysFwded(sys_id, payload) = fwd;
|
||||
let ctx = mk_ctx(sys_id, hand.reqnot()).await;
|
||||
let sys = ctx.cted.inst();
|
||||
let ctx = get_ctx(sys_id).await;
|
||||
let sys = ctx.cted().inst();
|
||||
sys.dyn_request(hand, payload).await
|
||||
},
|
||||
api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => {
|
||||
let api::VfsRead(sys_id, vfs_id, path) = &vfs_read;
|
||||
let ctx = mk_ctx(*sys_id, hand.reqnot()).await;
|
||||
let ctx = get_ctx(*sys_id).await;
|
||||
let systems = systems_weak.upgrade().expect("VFS requested during shutdoown");
|
||||
let systems_g = systems.lock().await;
|
||||
let path = join_all(path.iter().map(|t| Tok::from_api(*t, &i))).await;
|
||||
let vfs = systems_g[sys_id].vfses[vfs_id].load(&path, ctx).await;
|
||||
hand.handle(&vfs_read, &vfs).await
|
||||
},
|
||||
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, text, pos, id }) => {
|
||||
let systems_g = systems.lock().await;
|
||||
let lexers = systems_g[&sys].cted.inst().dyn_lexers();
|
||||
mem::drop(systems_g);
|
||||
let sys_ctx = get_ctx(sys).await;
|
||||
let text = Tok::from_api(text, &i).await;
|
||||
let ctx = LexContext { sys, id, pos, reqnot: hand.reqnot(), text: &text, i: &i };
|
||||
let trigger_char = text.chars().nth(pos as usize).unwrap();
|
||||
let err_na = err_not_applicable(&i).await;
|
||||
let err_cascade = err_cascade(&i).await;
|
||||
let lexers = sys_ctx.cted().inst().dyn_lexers();
|
||||
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char)) {
|
||||
match lx.lex(&text[pos as usize..], &ctx).await {
|
||||
Err(e) if e.any(|e| *e == err_na) => continue,
|
||||
@@ -294,10 +302,9 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
return hand.handle(&lex, &eopt).await;
|
||||
},
|
||||
Ok((s, expr)) => {
|
||||
let ctx = mk_ctx(sys, hand.reqnot()).await;
|
||||
let expr = expr
|
||||
.to_api(&mut |f, r| {
|
||||
clone!(ctx; async move { do_extra(f, r, ctx).await }).boxed_local()
|
||||
clone!(sys_ctx; async move { do_extra(f, r, sys_ctx).await }).boxed_local()
|
||||
})
|
||||
.await;
|
||||
let pos = (text.len() - s.len()) as u32;
|
||||
@@ -310,8 +317,8 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
},
|
||||
api::HostExtReq::ParseLine(pline) => {
|
||||
let api::ParseLine { exported, comments, sys, line } = &pline;
|
||||
let mut ctx = mk_ctx(*sys, hand.reqnot()).await;
|
||||
let parsers = ctx.cted.inst().dyn_parsers();
|
||||
let mut ctx = get_ctx(*sys).await;
|
||||
let parsers = ctx.cted().inst().dyn_parsers();
|
||||
let comments = join_all(comments.iter().map(|c| Comment::from_api(c, &i))).await;
|
||||
let line: Vec<GenTokTree> = ttv_from_api(line, &mut ctx, &i).await;
|
||||
let snip = Snippet::new(line.first().expect("Empty line"), &line, &i);
|
||||
@@ -337,7 +344,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
api::HostExtReq::AtomReq(atom_req) => {
|
||||
let atom = atom_req.get_atom();
|
||||
let atom_req = atom_req.clone();
|
||||
with_atom_record(&mk_ctx, hand.reqnot(), atom, move |nfo, ctx, id, buf| {
|
||||
with_atom_record(&get_ctx, atom, move |nfo, ctx, id, buf| {
|
||||
async move {
|
||||
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
||||
match &atom_req {
|
||||
@@ -389,16 +396,16 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
api::HostExtReq::DeserAtom(deser) => {
|
||||
let api::DeserAtom(sys, buf, refs) = &deser;
|
||||
let mut read = &mut &buf[..];
|
||||
let ctx = mk_ctx(*sys, hand.reqnot()).await;
|
||||
let ctx = get_ctx(*sys).await;
|
||||
let id = AtomTypeId::decode(Pin::new(&mut read)).await;
|
||||
let inst = ctx.cted.inst();
|
||||
let inst = ctx.cted().inst();
|
||||
let nfo = atom_by_idx(inst.card(), id).expect("Deserializing atom with invalid ID");
|
||||
hand.handle(&deser, &nfo.deserialize(ctx.clone(), read, refs).await).await
|
||||
},
|
||||
orchid_api::HostExtReq::ApplyMacro(am) => {
|
||||
let tok = hand.will_handle_as(&am);
|
||||
let ApplyMacro { id, params, run_id, sys } = am;
|
||||
let sys_ctx = mk_ctx(sys, hand.reqnot()).await;
|
||||
let sys_ctx = get_ctx(sys).await;
|
||||
let mut ctx =
|
||||
RuleCtx { args: ahash::HashMap::default(), run_id, sys: sys_ctx.clone() };
|
||||
for (k, v) in params {
|
||||
@@ -408,6 +415,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
);
|
||||
}
|
||||
let err_cascade = err_cascade(&i).await;
|
||||
let systems = systems_weak.upgrade().expect("macro call during shutdown");
|
||||
let systems_g = systems.lock().await;
|
||||
let rule = &systems_g[&sys].rules[&id];
|
||||
match (rule.apply)(ctx).await {
|
||||
@@ -432,7 +440,7 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||
}
|
||||
},
|
||||
);
|
||||
*interner_cell.borrow_mut() = Some(Rc::new(Interner::new_replica(rn.clone().map())));
|
||||
*interner_cell.borrow_mut() = Some(Interner::new_replica(rn.clone().map()));
|
||||
while !exiting.load(Ordering::Relaxed) {
|
||||
let rcvd = recv_parent_msg().await.unwrap();
|
||||
spawner(Box::pin(clone!(rn; async move { rn.receive(&rcvd).await })))
|
||||
|
||||
@@ -23,7 +23,7 @@ impl ExprHandle {
|
||||
pub(crate) fn from_args(ctx: SysCtx, tk: api::ExprTicket) -> Self { Self { ctx, tk } }
|
||||
pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() }
|
||||
pub async fn clone(&self) -> Self {
|
||||
self.ctx.reqnot.notify(api::Acquire(self.ctx.id, self.tk)).await;
|
||||
self.ctx.reqnot().notify(api::Acquire(self.ctx.sys_id(), self.tk)).await;
|
||||
Self { ctx: self.ctx.clone(), tk: self.tk }
|
||||
}
|
||||
}
|
||||
@@ -34,9 +34,9 @@ impl fmt::Debug for ExprHandle {
|
||||
}
|
||||
impl Drop for ExprHandle {
|
||||
fn drop(&mut self) {
|
||||
let notif = api::Release(self.ctx.id, self.tk);
|
||||
let SysCtx { reqnot, spawner, .. } = self.ctx.clone();
|
||||
spawner(Box::pin(async move { reqnot.notify(notif).await }))
|
||||
let notif = api::Release(self.ctx.sys_id(), self.tk);
|
||||
let reqnot = self.ctx.reqnot().clone();
|
||||
self.ctx.spawner()(Box::pin(async move { reqnot.notify(notif).await }))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,13 +53,13 @@ impl Expr {
|
||||
|
||||
pub async fn data(&self) -> &ExprData {
|
||||
(self.data.get_or_init(async {
|
||||
let details = self.handle.ctx.reqnot.request(api::Inspect { target: self.handle.tk }).await;
|
||||
let pos = Pos::from_api(&details.location, &self.handle.ctx.i).await;
|
||||
let details = self.handle.ctx.reqnot().request(api::Inspect { target: self.handle.tk }).await;
|
||||
let pos = Pos::from_api(&details.location, self.handle.ctx.i()).await;
|
||||
let kind = match details.kind {
|
||||
api::InspectedKind::Atom(a) =>
|
||||
ExprKind::Atom(ForeignAtom::new(self.handle.clone(), a, pos.clone())),
|
||||
api::InspectedKind::Bottom(b) =>
|
||||
ExprKind::Bottom(OrcErrv::from_api(&b, &self.handle.ctx.i).await),
|
||||
ExprKind::Bottom(OrcErrv::from_api(&b, self.handle.ctx.i()).await),
|
||||
api::InspectedKind::Opaque => ExprKind::Opaque,
|
||||
};
|
||||
ExprData { pos, kind }
|
||||
@@ -83,7 +83,7 @@ impl Format for Expr {
|
||||
ExprKind::Opaque => "OPAQUE".to_string().into(),
|
||||
ExprKind::Bottom(b) => format!("Bottom({b})").into(),
|
||||
ExprKind::Atom(a) =>
|
||||
FmtUnit::from_api(&self.handle.ctx.reqnot.request(ExtAtomPrint(a.atom.clone())).await),
|
||||
FmtUnit::from_api(&self.handle.ctx.reqnot().request(ExtAtomPrint(a.atom.clone())).await),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ use never::Never;
|
||||
use orchid_api_traits::Encode;
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::format::{FmtCtxImpl, Format, take_first};
|
||||
use orchid_base::name::Sym;
|
||||
use trait_set::trait_set;
|
||||
|
||||
@@ -22,7 +21,7 @@ use crate::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::expr::{Expr, ExprHandle};
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::system::SysCtx;
|
||||
use crate::system::{SysCtx, SysCtxEntry};
|
||||
|
||||
trait_set! {
|
||||
trait FunCB = Fn(Vec<Expr>) -> LocalBoxFuture<'static, OrcRes<GExpr>> + 'static;
|
||||
@@ -33,9 +32,9 @@ pub trait ExprFunc<I, O>: Clone + 'static {
|
||||
fn apply(&self, v: Vec<Expr>) -> impl Future<Output = OrcRes<GExpr>>;
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static FUNS: Rc<Mutex<HashMap<Sym, (u8, Rc<dyn FunCB>)>>> = Rc::default();
|
||||
}
|
||||
#[derive(Default)]
|
||||
struct FunsCtx(Mutex<HashMap<Sym, (u8, Rc<dyn FunCB>)>>);
|
||||
impl SysCtxEntry for FunsCtx {}
|
||||
|
||||
/// An Atom representing a partially applied named native function. These
|
||||
/// partial calls are serialized into the name of the native function and the
|
||||
@@ -50,9 +49,9 @@ pub(crate) struct Fun {
|
||||
fun: Rc<dyn FunCB>,
|
||||
}
|
||||
impl Fun {
|
||||
pub async fn new<I, O, F: ExprFunc<I, O>>(path: Sym, f: F) -> Self {
|
||||
let funs = FUNS.with(|funs| funs.clone());
|
||||
let mut fung = funs.lock().await;
|
||||
pub async fn new<I, O, F: ExprFunc<I, O>>(path: Sym, ctx: SysCtx, f: F) -> Self {
|
||||
let funs: &FunsCtx = ctx.get_or_default();
|
||||
let mut fung = funs.0.lock().await;
|
||||
let fun = if let Some(x) = fung.get(&path) {
|
||||
x.1.clone()
|
||||
} else {
|
||||
@@ -89,8 +88,8 @@ impl OwnedAtom for Fun {
|
||||
}
|
||||
async fn deserialize(mut ctx: impl DeserializeCtx, args: Self::Refs) -> Self {
|
||||
let sys = ctx.sys();
|
||||
let path = Sym::from_api(ctx.decode().await, &sys.i).await;
|
||||
let (arity, fun) = FUNS.with(|f| f.clone()).lock().await.get(&path).unwrap().clone();
|
||||
let path = Sym::from_api(ctx.decode().await, sys.i()).await;
|
||||
let (arity, fun) = sys.get_or_default::<FunsCtx>().0.lock().await.get(&path).unwrap().clone();
|
||||
Self { args, arity, path, fun }
|
||||
}
|
||||
async fn print(&self, _: SysCtx) -> orchid_base::format::FmtUnit {
|
||||
|
||||
@@ -4,10 +4,11 @@ use ahash::HashMap;
|
||||
use futures::future::{LocalBoxFuture, join_all};
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
use orchid_api::ExtMsgSet;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::macros::{MTree, mtreev_from_api, mtreev_to_api};
|
||||
use orchid_base::reqnot::Requester;
|
||||
use orchid_base::reqnot::{ReqNot, Requester};
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
@@ -44,11 +45,11 @@ impl<'a> RuleCtx<'a> {
|
||||
run_id: self.run_id,
|
||||
query: mtreev_to_api(tree, &mut |b| match *b {}).await,
|
||||
};
|
||||
let Some(treev) = self.sys.reqnot.request(req).await else {
|
||||
return Err(err_cascade(&self.sys.i).await.into());
|
||||
let Some(treev) = self.sys.get::<ReqNot<ExtMsgSet>>().request(req).await else {
|
||||
return Err(err_cascade(self.sys.i()).await.into());
|
||||
};
|
||||
static ATOM_MSG: &str = "Returned atom from Rule recursion";
|
||||
Ok(mtreev_from_api(&treev, &self.sys.i, &mut |_| panic!("{ATOM_MSG}")).await)
|
||||
Ok(mtreev_from_api(&treev, self.sys.i(), &mut |_| panic!("{ATOM_MSG}")).await)
|
||||
}
|
||||
pub fn getv(&mut self, key: &Tok<String>) -> Vec<MTree<'a, Never>> {
|
||||
self.args.remove(key).expect("Key not found")
|
||||
@@ -78,7 +79,7 @@ impl Rule {
|
||||
pub(crate) async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MacroRule {
|
||||
api::MacroRule {
|
||||
comments: join_all(self.comments.iter().map(|c| async {
|
||||
api::Comment { text: ctx.sys().i.i(c).await.to_api(), location: api::Location::Inherit }
|
||||
api::Comment { text: ctx.sys().i().i(c).await.to_api(), location: api::Location::Inherit }
|
||||
}))
|
||||
.await,
|
||||
location: api::Location::Inherit,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use core::fmt;
|
||||
use std::any::{TypeId, type_name};
|
||||
use std::any::{Any, TypeId, type_name};
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::num::NonZero;
|
||||
use std::pin::Pin;
|
||||
@@ -7,6 +7,8 @@ use std::rc::Rc;
|
||||
|
||||
use futures::future::LocalBoxFuture;
|
||||
use hashbrown::HashMap;
|
||||
use memo_map::MemoMap;
|
||||
use orchid_api::ExtMsgSet;
|
||||
use orchid_api_traits::{Coding, Decode};
|
||||
use orchid_base::boxed_iter::BoxedIter;
|
||||
use orchid_base::builtin::Spawner;
|
||||
@@ -16,7 +18,6 @@ use orchid_base::reqnot::{Receipt, ReqNot};
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TypAtom, get_info};
|
||||
use crate::atom_owned::ObjStore;
|
||||
use crate::entrypoint::ExtReq;
|
||||
use crate::fs::DeclFs;
|
||||
use crate::func_atom::Fun;
|
||||
@@ -116,11 +117,11 @@ where A: AtomicFeatures {
|
||||
let mut data = &foreign.atom.data[..];
|
||||
let ctx = foreign.ctx.clone();
|
||||
let value = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||
let own_inst = ctx.cted.inst();
|
||||
let owner = if ctx.id == foreign.atom.owner {
|
||||
let own_inst = ctx.get::<CtedObj>().inst();
|
||||
let owner = if *ctx.get::<api::SysId>() == foreign.atom.owner {
|
||||
own_inst.card()
|
||||
} else {
|
||||
(ctx.cted.deps().find(|s| s.id() == foreign.atom.owner))
|
||||
(ctx.get::<CtedObj>().deps().find(|s| s.id() == foreign.atom.owner))
|
||||
.ok_or_else(|| foreign.clone())?
|
||||
.get_card()
|
||||
};
|
||||
@@ -133,18 +134,80 @@ where A: AtomicFeatures {
|
||||
Ok(TypAtom { value, data: foreign })
|
||||
}
|
||||
|
||||
// #[derive(Clone)]
|
||||
// pub struct SysCtx {
|
||||
// pub reqnot: ReqNot<api::ExtMsgSet>,
|
||||
// pub spawner: Spawner,
|
||||
// pub id: api::SysId,
|
||||
// pub cted: CtedObj,
|
||||
// pub logger: Logger,
|
||||
// pub obj_store: ObjStore,
|
||||
// pub i: Rc<Interner>,
|
||||
// }
|
||||
// impl fmt::Debug for SysCtx {
|
||||
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// write!(f, "SysCtx({:?})", self.id)
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SysCtx {
|
||||
pub reqnot: ReqNot<api::ExtMsgSet>,
|
||||
pub spawner: Spawner,
|
||||
pub id: api::SysId,
|
||||
pub cted: CtedObj,
|
||||
pub logger: Logger,
|
||||
pub obj_store: ObjStore,
|
||||
pub i: Rc<Interner>,
|
||||
pub struct SysCtx(Rc<MemoMap<TypeId, Box<dyn Any>>>);
|
||||
impl SysCtx {
|
||||
pub fn new(
|
||||
id: api::SysId,
|
||||
i: Interner,
|
||||
reqnot: ReqNot<ExtMsgSet>,
|
||||
spawner: Spawner,
|
||||
logger: Logger,
|
||||
cted: CtedObj,
|
||||
) -> Self {
|
||||
let this = Self(Rc::new(MemoMap::new()));
|
||||
this.add(id).add(i).add(reqnot).add(spawner).add(logger).add(cted);
|
||||
this
|
||||
}
|
||||
pub fn add<T: SysCtxEntry>(&self, t: T) -> &Self {
|
||||
assert!(self.0.insert(TypeId::of::<T>(), Box::new(t)), "Key already exists");
|
||||
self
|
||||
}
|
||||
pub fn get_or_insert<T: SysCtxEntry>(&self, f: impl FnOnce() -> T) -> &T {
|
||||
(self.0.get_or_insert_owned(TypeId::of::<T>(), || Box::new(f())).downcast_ref())
|
||||
.expect("Keyed by TypeId")
|
||||
}
|
||||
pub fn get_or_default<T: SysCtxEntry + Default>(&self) -> &T {
|
||||
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> {
|
||||
Some(self.0.get(&TypeId::of::<T>())?.downcast_ref().expect("Keyed by TypeId"))
|
||||
}
|
||||
pub fn get<T: SysCtxEntry>(&self) -> &T {
|
||||
self.try_get().unwrap_or_else(|| panic!("Context {} missing", type_name::<T>()))
|
||||
}
|
||||
/// Shorthand to get the [Interner] instance
|
||||
pub fn i(&self) -> &Interner { self.get::<Interner>() }
|
||||
/// Shorthand to get the messaging link
|
||||
pub fn reqnot(&self) -> &ReqNot<ExtMsgSet> { self.get::<ReqNot<ExtMsgSet>>() }
|
||||
/// Shorthand to get the system ID
|
||||
pub fn sys_id(&self) -> api::SysId { *self.get::<api::SysId>() }
|
||||
/// Shorthand to get the task spawner callback
|
||||
pub fn spawner(&self) -> &Spawner { self.get::<Spawner>() }
|
||||
/// Shorthand to get the logger
|
||||
pub fn logger(&self) -> &Logger { self.get::<Logger>() }
|
||||
/// Shorthand to get the constructed system object
|
||||
pub fn cted(&self) -> &CtedObj { self.get::<CtedObj>() }
|
||||
}
|
||||
impl fmt::Debug for SysCtx {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "SysCtx({:?})", self.id)
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SysCtx({:?})", self.sys_id())
|
||||
}
|
||||
}
|
||||
pub trait SysCtxEntry: 'static + Sized {}
|
||||
impl SysCtxEntry for api::SysId {}
|
||||
impl SysCtxEntry for ReqNot<api::ExtMsgSet> {}
|
||||
impl SysCtxEntry for Spawner {}
|
||||
impl SysCtxEntry for CtedObj {}
|
||||
impl SysCtxEntry for Logger {}
|
||||
impl SysCtxEntry for Interner {}
|
||||
|
||||
@@ -46,7 +46,7 @@ pub struct GenItem {
|
||||
impl GenItem {
|
||||
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Item {
|
||||
let kind = match self.kind {
|
||||
GenItemKind::Export(n) => api::ItemKind::Export(ctx.sys().i.i::<String>(&n).await.to_api()),
|
||||
GenItemKind::Export(n) => api::ItemKind::Export(ctx.sys().i().i::<String>(&n).await.to_api()),
|
||||
GenItemKind::Member(mem) => api::ItemKind::Member(mem.into_api(ctx).await),
|
||||
GenItemKind::Import(cn) => api::ItemKind::Import(cn.tok().to_api()),
|
||||
GenItemKind::Macro(priority, gen_rules) => {
|
||||
@@ -60,7 +60,7 @@ impl GenItem {
|
||||
let comments = join_all(self.comments.iter().map(|c| async {
|
||||
api::Comment {
|
||||
location: api::Location::Inherit,
|
||||
text: ctx.sys().i.i::<String>(c).await.to_api(),
|
||||
text: ctx.sys().i().i::<String>(c).await.to_api(),
|
||||
}
|
||||
}))
|
||||
.await;
|
||||
@@ -92,8 +92,8 @@ pub fn root_mod(
|
||||
(name.to_string(), kind)
|
||||
}
|
||||
pub fn fun<I, O>(exported: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenItem> {
|
||||
let fac = LazyMemberFactory::new(move |sym| async {
|
||||
return MemKind::Const(build_lambdas(Fun::new(sym, xf).await, 0));
|
||||
let fac = LazyMemberFactory::new(move |sym, ctx| async {
|
||||
return MemKind::Const(build_lambdas(Fun::new(sym, ctx, xf).await, 0));
|
||||
fn build_lambdas(fun: Fun, i: u64) -> GExpr {
|
||||
if i < fun.arity().into() {
|
||||
return lambda(i, [build_lambdas(fun, i + 1)]);
|
||||
@@ -129,16 +129,16 @@ pub fn comments<'a>(
|
||||
|
||||
trait_set! {
|
||||
trait LazyMemberCallback =
|
||||
FnOnce(Sym) -> LocalBoxFuture<'static, MemKind> + DynClone
|
||||
FnOnce(Sym, SysCtx) -> LocalBoxFuture<'static, MemKind> + DynClone
|
||||
}
|
||||
pub struct LazyMemberFactory(Box<dyn LazyMemberCallback>);
|
||||
impl LazyMemberFactory {
|
||||
pub fn new<F: Future<Output = MemKind> + 'static>(
|
||||
cb: impl FnOnce(Sym) -> F + Clone + 'static,
|
||||
cb: impl FnOnce(Sym, SysCtx) -> F + Clone + 'static,
|
||||
) -> Self {
|
||||
Self(Box::new(|s| cb(s).boxed_local()))
|
||||
Self(Box::new(|s, ctx| cb(s, ctx).boxed_local()))
|
||||
}
|
||||
pub async fn build(self, path: Sym) -> MemKind { (self.0)(path).await }
|
||||
pub async fn build(self, path: Sym, ctx: SysCtx) -> MemKind { (self.0)(path, ctx).await }
|
||||
}
|
||||
impl Clone for LazyMemberFactory {
|
||||
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
|
||||
@@ -157,7 +157,7 @@ pub struct GenMember {
|
||||
}
|
||||
impl GenMember {
|
||||
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Member {
|
||||
let name = ctx.sys().i.i::<String>(&self.name).await;
|
||||
let name = ctx.sys().i().i::<String>(&self.name).await;
|
||||
api::Member {
|
||||
kind: self.kind.into_api(&mut ctx.push_path(name.clone())).await,
|
||||
name: name.to_api(),
|
||||
@@ -197,7 +197,7 @@ pub trait TreeIntoApiCtx {
|
||||
fn req(&self) -> &impl ReqHandlish;
|
||||
}
|
||||
|
||||
pub struct TIACtxImpl<'a, 'b, RH: ReqHandlish> {
|
||||
pub struct TreeIntoApiCtxImpl<'a, 'b, RH: ReqHandlish> {
|
||||
pub sys: SysCtx,
|
||||
pub basepath: &'a [Tok<String>],
|
||||
pub path: Substack<'a, Tok<String>>,
|
||||
@@ -206,10 +206,10 @@ pub struct TIACtxImpl<'a, 'b, RH: ReqHandlish> {
|
||||
pub req: &'a RH,
|
||||
}
|
||||
|
||||
impl<RH: ReqHandlish> TreeIntoApiCtx for TIACtxImpl<'_, '_, RH> {
|
||||
impl<RH: ReqHandlish> TreeIntoApiCtx for TreeIntoApiCtxImpl<'_, '_, RH> {
|
||||
fn sys(&self) -> SysCtx { self.sys.clone() }
|
||||
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
|
||||
TIACtxImpl {
|
||||
TreeIntoApiCtxImpl {
|
||||
req: self.req,
|
||||
lazy_members: self.lazy_members,
|
||||
rules: self.rules,
|
||||
|
||||
@@ -35,7 +35,7 @@ pub struct ReqPair<R: Request>(R, Sender<R::Response>);
|
||||
#[derive(destructure)]
|
||||
pub struct ExtensionData {
|
||||
ctx: Ctx,
|
||||
init: ExtInit,
|
||||
init: Rc<ExtInit>,
|
||||
reqnot: ReqNot<api::HostMsgSet>,
|
||||
systems: Vec<SystemCtor>,
|
||||
logger: Logger,
|
||||
@@ -55,114 +55,140 @@ impl Drop for ExtensionData {
|
||||
pub struct Extension(Rc<ExtensionData>);
|
||||
impl Extension {
|
||||
pub fn new(init: ExtInit, logger: Logger, msg_logger: Logger, ctx: Ctx) -> io::Result<Self> {
|
||||
Ok(Self(Rc::new_cyclic(|weak: &Weak<ExtensionData>| ExtensionData {
|
||||
exprs: ExprStore::default(),
|
||||
ctx: ctx.clone(),
|
||||
systems: (init.systems.iter().cloned())
|
||||
.map(|decl| SystemCtor { decl, ext: WeakExtension(weak.clone()) })
|
||||
.collect(),
|
||||
logger: logger.clone(),
|
||||
init,
|
||||
next_pars: RefCell::new(NonZeroU64::new(1).unwrap()),
|
||||
lex_recur: Mutex::default(),
|
||||
mac_recur: Mutex::default(),
|
||||
reqnot: ReqNot::new(
|
||||
msg_logger,
|
||||
clone!(weak; move |sfn, _| clone!(weak; async move {
|
||||
Ok(Self(Rc::new_cyclic(|weak: &Weak<ExtensionData>| {
|
||||
let init = Rc::new(init);
|
||||
(ctx.spawn)(clone!(init, weak, ctx; Box::pin(async move {
|
||||
let reqnot_opt = weak.upgrade().map(|rc| rc.reqnot.clone());
|
||||
if let Some(reqnot) = reqnot_opt {
|
||||
let mut repeat = true;
|
||||
while repeat {
|
||||
repeat = false;
|
||||
(init.recv(Box::new(|msg| {
|
||||
repeat = true;
|
||||
Box::pin(clone!(reqnot, ctx; async move {
|
||||
let msg = msg.to_vec();
|
||||
let reqnot = reqnot.clone();
|
||||
(ctx.spawn)(Box::pin(async move {
|
||||
reqnot.receive(&msg).await;
|
||||
}))
|
||||
}))
|
||||
})))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
})));
|
||||
ExtensionData {
|
||||
exprs: ExprStore::default(),
|
||||
ctx: ctx.clone(),
|
||||
systems: (init.systems.iter().cloned())
|
||||
.map(|decl| SystemCtor { decl, ext: WeakExtension(weak.clone()) })
|
||||
.collect(),
|
||||
logger: logger.clone(),
|
||||
init,
|
||||
next_pars: RefCell::new(NonZeroU64::new(1).unwrap()),
|
||||
lex_recur: Mutex::default(),
|
||||
mac_recur: Mutex::default(),
|
||||
reqnot: ReqNot::new(
|
||||
msg_logger,
|
||||
clone!(weak; move |sfn, _| clone!(weak; async move {
|
||||
let data = weak.upgrade().unwrap();
|
||||
data.init.send(sfn).await
|
||||
}.boxed_local())),
|
||||
clone!(weak; move |notif, _| {
|
||||
clone!(weak; Box::pin(async move {
|
||||
let this = Extension(weak.upgrade().unwrap());
|
||||
match notif {
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Acquire(acq)) => {
|
||||
let target = this.0.exprs.get_expr(acq.1).expect("Invalid ticket");
|
||||
this.0.exprs.give_expr(target)
|
||||
}
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => {
|
||||
this.assert_own_sys(rel.0).await;
|
||||
this.0.exprs.take_expr(rel.1)
|
||||
}
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Move(mov)) => {
|
||||
this.assert_own_sys(mov.dec).await;
|
||||
let recp = this.ctx().system_inst(mov.inc).await.expect("invallid recipient sys id");
|
||||
let expr = this.0.exprs.get_expr(mov.expr).expect("invalid ticket");
|
||||
recp.ext().0.exprs.give_expr(expr);
|
||||
this.0.exprs.take_expr(mov.expr);
|
||||
},
|
||||
api::ExtHostNotif::Log(api::Log(str)) => this.logger().log(str),
|
||||
}
|
||||
}))}),
|
||||
{
|
||||
clone!(weak, ctx);
|
||||
move |hand, req| {
|
||||
clone!(weak, ctx);
|
||||
Box::pin(async move {
|
||||
let this = Self(weak.upgrade().unwrap());
|
||||
writeln!(this.reqnot().logger(), "Host received request {req:?}");
|
||||
let i = this.ctx().i.clone();
|
||||
match req {
|
||||
api::ExtHostReq::Ping(ping) => hand.handle(&ping, &()).await,
|
||||
api::ExtHostReq::IntReq(intreq) => match intreq {
|
||||
api::IntReq::InternStr(s) => hand.handle(&s, &i.i(&*s.0).await.to_api()).await,
|
||||
api::IntReq::InternStrv(v) => {
|
||||
let tokens = join_all(v.0.iter().map(|m| i.ex(*m))).await;
|
||||
hand.handle(&v, &i.i(&tokens).await.to_api()).await
|
||||
},
|
||||
api::IntReq::ExternStr(si) =>
|
||||
hand.handle(&si, &Tok::<String>::from_api(si.0, &i).await.rc()).await,
|
||||
api::IntReq::ExternStrv(vi) => {
|
||||
let markerv = (i.ex(vi.0).await.iter()).map(|t| t.to_api()).collect_vec();
|
||||
hand.handle(&vi, &markerv).await
|
||||
},
|
||||
},
|
||||
api::ExtHostReq::Fwd(ref fw @ api::Fwd(ref atom, ref key, ref body)) => {
|
||||
let sys = ctx.system_inst(atom.owner).await.expect("owner of live atom dropped");
|
||||
let reply =
|
||||
sys.reqnot().request(api::Fwded(fw.0.clone(), *key, body.clone())).await;
|
||||
hand.handle(fw, &reply).await
|
||||
},
|
||||
api::ExtHostReq::SysFwd(ref fw @ api::SysFwd(id, ref body)) => {
|
||||
let sys = ctx.system_inst(id).await.unwrap();
|
||||
hand.handle(fw, &sys.request(body.clone()).await).await
|
||||
},
|
||||
api::ExtHostReq::SubLex(sl) => {
|
||||
let (rep_in, rep_out) = channel::bounded(1);
|
||||
{
|
||||
let lex_g = this.0.lex_recur.lock().await;
|
||||
let req_in = lex_g.get(&sl.id).expect("Sublex for nonexistent lexid");
|
||||
req_in.send(ReqPair(sl.clone(), rep_in)).await.unwrap();
|
||||
}
|
||||
hand.handle(&sl, &rep_out.recv().await.unwrap()).await
|
||||
},
|
||||
api::ExtHostReq::ExprReq(api::ExprReq::Inspect(ins @ api::Inspect { target })) => {
|
||||
let expr = this.exprs().get_expr(target).expect("Invalid ticket");
|
||||
hand
|
||||
.handle(&ins, &api::Inspected {
|
||||
refcount: expr.strong_count() as u32,
|
||||
location: expr.pos().to_api(),
|
||||
kind: expr.to_api().await,
|
||||
})
|
||||
.await
|
||||
},
|
||||
api::ExtHostReq::RunMacros(rm) => {
|
||||
let (rep_in, rep_out) = channel::bounded(1);
|
||||
let lex_g = this.0.mac_recur.lock().await;
|
||||
let req_in = lex_g.get(&rm.run_id).expect("Sublex for nonexistent lexid");
|
||||
req_in.send(ReqPair(rm.clone(), rep_in)).await.unwrap();
|
||||
hand.handle(&rm, &rep_out.recv().await.unwrap()).await
|
||||
},
|
||||
api::ExtHostReq::ExtAtomPrint(ref eap @ api::ExtAtomPrint(ref atom)) => {
|
||||
let atom = AtomHand::new(atom.clone(), &ctx).await;
|
||||
let unit = atom.print(&FmtCtxImpl { i: &this.ctx().i }).await;
|
||||
hand.handle(eap, &unit.to_api()).await
|
||||
},
|
||||
clone!(weak; move |notif, _| {
|
||||
clone!(weak; Box::pin(async move {
|
||||
let this = Extension(weak.upgrade().unwrap());
|
||||
match notif {
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Acquire(acq)) => {
|
||||
let target = this.0.exprs.get_expr(acq.1).expect("Invalid ticket");
|
||||
this.0.exprs.give_expr(target)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
),
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => {
|
||||
this.assert_own_sys(rel.0).await;
|
||||
this.0.exprs.take_expr(rel.1)
|
||||
}
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Move(mov)) => {
|
||||
this.assert_own_sys(mov.dec).await;
|
||||
let recp = this.ctx().system_inst(mov.inc).await.expect("invallid recipient sys id");
|
||||
let expr = this.0.exprs.get_expr(mov.expr).expect("invalid ticket");
|
||||
recp.ext().0.exprs.give_expr(expr);
|
||||
this.0.exprs.take_expr(mov.expr);
|
||||
},
|
||||
api::ExtHostNotif::Log(api::Log(str)) => this.logger().log(str),
|
||||
}
|
||||
}))}),
|
||||
{
|
||||
clone!(weak, ctx);
|
||||
move |hand, req| {
|
||||
clone!(weak, ctx);
|
||||
Box::pin(async move {
|
||||
let this = Self(weak.upgrade().unwrap());
|
||||
writeln!(this.reqnot().logger(), "Host received request {req:?}");
|
||||
let i = this.ctx().i.clone();
|
||||
match req {
|
||||
api::ExtHostReq::Ping(ping) => hand.handle(&ping, &()).await,
|
||||
api::ExtHostReq::IntReq(intreq) => match intreq {
|
||||
api::IntReq::InternStr(s) => hand.handle(&s, &i.i(&*s.0).await.to_api()).await,
|
||||
api::IntReq::InternStrv(v) => {
|
||||
let tokens = join_all(v.0.iter().map(|m| i.ex(*m))).await;
|
||||
hand.handle(&v, &i.i(&tokens).await.to_api()).await
|
||||
},
|
||||
api::IntReq::ExternStr(si) =>
|
||||
hand.handle(&si, &Tok::<String>::from_api(si.0, &i).await.rc()).await,
|
||||
api::IntReq::ExternStrv(vi) => {
|
||||
let markerv = (i.ex(vi.0).await.iter()).map(|t| t.to_api()).collect_vec();
|
||||
hand.handle(&vi, &markerv).await
|
||||
},
|
||||
},
|
||||
api::ExtHostReq::Fwd(ref fw @ api::Fwd(ref atom, ref key, ref body)) => {
|
||||
let sys =
|
||||
ctx.system_inst(atom.owner).await.expect("owner of live atom dropped");
|
||||
let reply =
|
||||
sys.reqnot().request(api::Fwded(fw.0.clone(), *key, body.clone())).await;
|
||||
hand.handle(fw, &reply).await
|
||||
},
|
||||
api::ExtHostReq::SysFwd(ref fw @ api::SysFwd(id, ref body)) => {
|
||||
let sys = ctx.system_inst(id).await.unwrap();
|
||||
hand.handle(fw, &sys.request(body.clone()).await).await
|
||||
},
|
||||
api::ExtHostReq::SubLex(sl) => {
|
||||
let (rep_in, rep_out) = channel::bounded(1);
|
||||
{
|
||||
let lex_g = this.0.lex_recur.lock().await;
|
||||
let req_in = lex_g.get(&sl.id).expect("Sublex for nonexistent lexid");
|
||||
req_in.send(ReqPair(sl.clone(), rep_in)).await.unwrap();
|
||||
}
|
||||
hand.handle(&sl, &rep_out.recv().await.unwrap()).await
|
||||
},
|
||||
api::ExtHostReq::ExprReq(api::ExprReq::Inspect(
|
||||
ins @ api::Inspect { target },
|
||||
)) => {
|
||||
let expr = this.exprs().get_expr(target).expect("Invalid ticket");
|
||||
hand
|
||||
.handle(&ins, &api::Inspected {
|
||||
refcount: expr.strong_count() as u32,
|
||||
location: expr.pos().to_api(),
|
||||
kind: expr.to_api().await,
|
||||
})
|
||||
.await
|
||||
},
|
||||
api::ExtHostReq::RunMacros(rm) => {
|
||||
let (rep_in, rep_out) = channel::bounded(1);
|
||||
let lex_g = this.0.mac_recur.lock().await;
|
||||
let req_in = lex_g.get(&rm.run_id).expect("Sublex for nonexistent lexid");
|
||||
req_in.send(ReqPair(rm.clone(), rep_in)).await.unwrap();
|
||||
hand.handle(&rm, &rep_out.recv().await.unwrap()).await
|
||||
},
|
||||
api::ExtHostReq::ExtAtomPrint(ref eap @ api::ExtAtomPrint(ref atom)) => {
|
||||
let atom = AtomHand::new(atom.clone(), &ctx).await;
|
||||
let unit = atom.print(&FmtCtxImpl { i: &this.ctx().i }).await;
|
||||
hand.handle(eap, &unit.to_api()).await
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
),
|
||||
}
|
||||
})))
|
||||
}
|
||||
pub(crate) fn reqnot(&self) -> &ReqNot<HostMsgSet> { &self.0.reqnot }
|
||||
@@ -212,20 +238,6 @@ impl Extension {
|
||||
.await;
|
||||
ret.transpose()
|
||||
}
|
||||
pub async fn recv_one(&self) {
|
||||
let reqnot = self.0.reqnot.clone();
|
||||
let ctx = self.ctx().clone();
|
||||
(self.0.init.recv(Box::new(move |msg| {
|
||||
Box::pin(async move {
|
||||
let msg = msg.to_vec();
|
||||
let reqnot = reqnot.clone();
|
||||
(ctx.spawn)(Box::pin(async move {
|
||||
reqnot.receive(&msg).await;
|
||||
}))
|
||||
})
|
||||
})))
|
||||
.await;
|
||||
}
|
||||
pub fn system_drop(&self, id: api::SysId) {
|
||||
let rc = self.clone();
|
||||
(self.ctx().spawn)(Box::pin(async move {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use std::cell::RefCell;
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use std::thread;
|
||||
|
||||
use async_process::{self, Child, ChildStdin, ChildStdout};
|
||||
use async_std::io::{self, BufReadExt, BufReader};
|
||||
@@ -22,8 +20,6 @@ pub async fn ext_command(
|
||||
msg_logs: Logger,
|
||||
ctx: Ctx,
|
||||
) -> io::Result<ExtInit> {
|
||||
let prog_pbuf = PathBuf::from(cmd.get_program());
|
||||
let prog = prog_pbuf.file_stem().unwrap_or(cmd.get_program()).to_string_lossy().to_string();
|
||||
let mut child = async_process::Command::from(cmd)
|
||||
.stdin(async_process::Stdio::piped())
|
||||
.stdout(async_process::Stdio::piped())
|
||||
@@ -36,18 +32,16 @@ pub async fn ext_command(
|
||||
let mut stdout = child.stdout.take().unwrap();
|
||||
let header = api::ExtensionHeader::decode(Pin::new(&mut stdout)).await;
|
||||
let child_stderr = child.stderr.take().unwrap();
|
||||
thread::Builder::new().name(format!("stderr-fwd:{prog}")).spawn(move || {
|
||||
async_std::task::block_on(async move {
|
||||
let mut reader = BufReader::new(child_stderr);
|
||||
loop {
|
||||
let mut buf = String::new();
|
||||
if 0 == reader.read_line(&mut buf).await.unwrap() {
|
||||
break;
|
||||
}
|
||||
logger.log(buf.strip_suffix('\n').expect("Readline implies this"));
|
||||
(ctx.spawn)(Box::pin(async move {
|
||||
let mut reader = BufReader::new(child_stderr);
|
||||
loop {
|
||||
let mut buf = String::new();
|
||||
if 0 == reader.read_line(&mut buf).await.unwrap() {
|
||||
break;
|
||||
}
|
||||
})
|
||||
})?;
|
||||
logger.log(buf.strip_suffix('\n').expect("Readline implies this"));
|
||||
}
|
||||
}));
|
||||
Ok(ExtInit {
|
||||
header,
|
||||
port: Box::new(Subprocess {
|
||||
@@ -87,6 +81,7 @@ impl ExtPort for Subprocess {
|
||||
match recv_msg(self.stdout.lock().await.as_mut()).await {
|
||||
Ok(msg) => cb(&msg).await,
|
||||
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => (),
|
||||
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => (),
|
||||
Err(e) => panic!("Failed to read from stdout: {}, {e}", e.kind()),
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,4 +16,5 @@ orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
||||
orchid-base = { version = "0.1.0", path = "../orchid-base" }
|
||||
orchid-extension = { version = "0.1.0", path = "../orchid-extension" }
|
||||
ordered-float = "4.6.0"
|
||||
rust_decimal = "1.36.0"
|
||||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::format::FmtUnit;
|
||||
use orchid_base::number::Numeric;
|
||||
use orchid_extension::atom::{
|
||||
AtomFactory, Atomic, AtomicFeatures, MethodSetBuilder, ToAtom, TypAtom,
|
||||
};
|
||||
@@ -9,6 +10,7 @@ use orchid_extension::conv::TryFromExpr;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::system::SysCtx;
|
||||
use ordered_float::NotNan;
|
||||
use rust_decimal::prelude::Zero;
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
pub struct Int(pub i64);
|
||||
@@ -38,27 +40,56 @@ impl ThinAtom for Float {
|
||||
}
|
||||
impl TryFromExpr for Float {
|
||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||
TypAtom::<Float>::try_from_expr(expr).await.map(|t| t.value)
|
||||
Ok(Self(Num::try_from_expr(expr).await?.0.to_f64()))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Numeric {
|
||||
Int(i64),
|
||||
Float(NotNan<f64>),
|
||||
}
|
||||
impl TryFromExpr for Numeric {
|
||||
pub struct Num(pub Numeric);
|
||||
impl TryFromExpr for Num {
|
||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||
match Int::try_from_expr(expr.clone()).await {
|
||||
Ok(t) => Ok(Numeric::Int(t.0)),
|
||||
Err(e) => Float::try_from_expr(expr).await.map(|t| Numeric::Float(t.0)).map_err(|e2| e + e2),
|
||||
let e = match Int::try_from_expr(expr.clone()).await {
|
||||
Ok(t) => return Ok(Num(Numeric::Int(t.0))),
|
||||
Err(e) => e,
|
||||
};
|
||||
match TypAtom::<Float>::try_from_expr(expr).await {
|
||||
Ok(t) => Ok(Num(Numeric::Float(t.0))),
|
||||
Err(e2) => Err(e + e2),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ToAtom for Numeric {
|
||||
impl ToAtom for Num {
|
||||
fn to_atom_factory(self) -> AtomFactory {
|
||||
match self {
|
||||
Self::Float(f) => Float(f).factory(),
|
||||
Self::Int(i) => Int(i).factory(),
|
||||
match self.0 {
|
||||
Numeric::Float(f) => Float(f).factory(),
|
||||
Numeric::Int(i) => Int(i).factory(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A homogenous fixed length number array that forces all of its elements into
|
||||
/// the weakest element type. This describes the argument casting behaviour of
|
||||
/// most numeric operations.
|
||||
pub enum HomoArray<const N: usize> {
|
||||
Int([i64; N]),
|
||||
Float([NotNan<f64>; N]),
|
||||
}
|
||||
impl<const N: usize> HomoArray<N> {
|
||||
pub fn new(n: [Numeric; N]) -> Self {
|
||||
let mut ints = [0i64; N];
|
||||
for i in 0..N {
|
||||
if let Numeric::Int(val) = n[i] {
|
||||
ints[i] = val
|
||||
} else {
|
||||
let mut floats = [NotNan::zero(); N];
|
||||
for (i, int) in ints.iter().take(i).enumerate() {
|
||||
floats[i] = NotNan::new(*int as f64).expect("i64 cannot convert to f64 NaN");
|
||||
}
|
||||
for j in i..N {
|
||||
floats[j] = n[j].to_f64();
|
||||
}
|
||||
return Self::Float(floats);
|
||||
}
|
||||
}
|
||||
Self::Int(ints)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::number::{Numeric, num_to_err, parse_num};
|
||||
use orchid_extension::atom::AtomicFeatures;
|
||||
use orchid_base::number::{num_to_err, parse_num};
|
||||
use orchid_extension::atom::ToAtom;
|
||||
use orchid_extension::lexer::{LexContext, Lexer};
|
||||
use orchid_extension::tree::{GenTok, GenTokTree};
|
||||
use ordered_float::NotNan;
|
||||
|
||||
use super::num_atom::{Float, Int};
|
||||
use super::num_atom::Num;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct NumLexer;
|
||||
@@ -17,9 +16,7 @@ impl Lexer for NumLexer {
|
||||
let ends_at = all.find(|c: char| !c.is_ascii_hexdigit() && !"xX._pP".contains(c));
|
||||
let (chars, tail) = all.split_at(ends_at.unwrap_or(all.len()));
|
||||
let fac = match parse_num(chars) {
|
||||
Ok(Numeric::Float(f)) => Float(f).factory(),
|
||||
Ok(Numeric::Uint(uint)) => Int(uint.try_into().unwrap()).factory(),
|
||||
Ok(Numeric::Decimal(dec)) => Float(NotNan::new(dec.try_into().unwrap()).unwrap()).factory(),
|
||||
Ok(numeric) => Num(numeric).to_atom_factory(),
|
||||
Err(e) => return Err(num_to_err(e, ctx.pos(all), ctx.i).await.into()),
|
||||
};
|
||||
Ok((tail, GenTok::X(fac).at(ctx.pos(all)..ctx.pos(tail))))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use never::Never;
|
||||
use orchid_base::number::Numeric;
|
||||
use orchid_base::reqnot::Receipt;
|
||||
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
|
||||
use orchid_extension::entrypoint::ExtReq;
|
||||
@@ -8,9 +9,10 @@ use orchid_extension::fs::DeclFs;
|
||||
use orchid_extension::system::{System, SystemCard};
|
||||
use orchid_extension::system_ctor::SystemCtor;
|
||||
use orchid_extension::tree::{MemKind, comments, fun, module, root_mod};
|
||||
use ordered_float::NotNan;
|
||||
|
||||
use crate::OrcString;
|
||||
use crate::number::num_atom::{Float, Int};
|
||||
use crate::number::num_atom::{Float, HomoArray, Int, Num};
|
||||
use crate::number::num_lexer::NumLexer;
|
||||
use crate::string::str_atom::{IntStrAtom, StrAtom};
|
||||
use crate::string::str_lexer::StringLexer;
|
||||
@@ -37,11 +39,39 @@ impl System for StdSystem {
|
||||
fn parsers() -> Vec<orchid_extension::parser::ParserObj> { vec![] }
|
||||
fn vfs() -> DeclFs { DeclFs::Mod(&[]) }
|
||||
fn env() -> Vec<(String, MemKind)> {
|
||||
vec![root_mod("std", [], [module(true, "string", [], [comments(
|
||||
["Concatenate two strings"],
|
||||
fun(true, "concat", |left: OrcString<'static>, right: OrcString<'static>| async move {
|
||||
StrAtom::new(Rc::new(left.get_string().await.to_string() + &right.get_string().await))
|
||||
}),
|
||||
)])])]
|
||||
vec![root_mod("std", [], [
|
||||
module(true, "string", [], [comments(
|
||||
["Concatenate two strings"],
|
||||
fun(true, "concat", |left: OrcString<'static>, right: OrcString<'static>| async move {
|
||||
StrAtom::new(Rc::new(left.get_string().await.to_string() + &right.get_string().await))
|
||||
}),
|
||||
)]),
|
||||
module(true, "number", [], [
|
||||
fun(true, "add", |a: Num, b: Num| async move {
|
||||
Num(match HomoArray::new([a.0, b.0]) {
|
||||
HomoArray::Int([a, b]) => Numeric::Int(a + b),
|
||||
HomoArray::Float([a, b]) => Numeric::Float(a + b),
|
||||
})
|
||||
}),
|
||||
fun(true, "neg", |a: Num| async move {
|
||||
Num(match a.0 {
|
||||
Numeric::Int(i) => Numeric::Int(-i),
|
||||
Numeric::Float(f) => Numeric::Float(-f),
|
||||
})
|
||||
}),
|
||||
fun(true, "mul", |a: Num, b: Num| async move {
|
||||
Num(match HomoArray::new([a.0, b.0]) {
|
||||
HomoArray::Int([a, b]) => Numeric::Int(a * b),
|
||||
HomoArray::Float([a, b]) => Numeric::Float(a * b),
|
||||
})
|
||||
}),
|
||||
fun(true, "idiv", |a: Int, b: Int| async move { Int(a.0 / b.0) }),
|
||||
fun(true, "imod", |a: Int, b: Int| async move { Int(a.0 % b.0) }),
|
||||
fun(true, "fdiv", |a: Float, b: Float| async move { Float(a.0 / b.0) }),
|
||||
fun(true, "fmod", |a: Float, b: Float| async move {
|
||||
Float(a.0 - NotNan::new((a.0 / b.0).trunc()).unwrap() * b.0)
|
||||
}),
|
||||
]),
|
||||
])]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ impl OwnedAtom for IntStrAtom {
|
||||
}
|
||||
async fn deserialize(mut ctx: impl DeserializeCtx, _: ()) -> Self {
|
||||
let s = ctx.decode::<String>().await;
|
||||
Self(ctx.sys().i.i(&s).await)
|
||||
Self(ctx.sys().i().i(&s).await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ pub enum OrcStringKind<'a> {
|
||||
impl OrcString<'_> {
|
||||
pub async fn get_string(&self) -> Rc<String> {
|
||||
match &self.kind {
|
||||
OrcStringKind::Int(tok) => self.ctx.i.ex(**tok).await.rc(),
|
||||
OrcStringKind::Int(tok) => self.ctx.i().ex(**tok).await.rc(),
|
||||
OrcStringKind::Val(atom) => atom.request(StringGetVal).await,
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ impl TryFromExpr for OrcString<'static> {
|
||||
let ctx = expr.ctx();
|
||||
match TypAtom::<IntStrAtom>::try_from_expr(expr).await {
|
||||
Ok(t) => Ok(OrcString { ctx: t.data.ctx(), kind: OrcStringKind::Int(t) }),
|
||||
Err(e) => Err(mk_errv(ctx.i.i("A string was expected").await, "", e.pos_iter())),
|
||||
Err(e) => Err(mk_errv(ctx.i().i("A string was expected").await, "", e.pos_iter())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ use async_stream::try_stream;
|
||||
use camino::Utf8PathBuf;
|
||||
use clap::{Parser, Subcommand};
|
||||
use futures::{Stream, TryStreamExt, io};
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::ReporterImpl;
|
||||
use orchid_base::format::{FmtCtxImpl, Format, take_first};
|
||||
use orchid_base::location::Pos;
|
||||
@@ -74,7 +73,6 @@ fn get_all_extensions<'a>(
|
||||
let init = ext_command(Command::new(exe.as_os_str()), logger.clone(), msg_logger.clone(), ctx.clone()).await
|
||||
.unwrap();
|
||||
let ext = Extension::new(init, logger.clone(), msg_logger.clone(), ctx.clone())?;
|
||||
spawn_local(clone!(ext; async move { loop { ext.recv_one().await }}));
|
||||
yield ext
|
||||
}
|
||||
}
|
||||
@@ -168,12 +166,8 @@ async fn main() -> io::Result<ExitCode> {
|
||||
if args.verbose {
|
||||
println!("lexed: {}", take_first(&ttv_fmt(&lexemes, &FmtCtxImpl { i }).await, true));
|
||||
}
|
||||
let mtreev = parse_mtree(
|
||||
Snippet::new(&lexemes[0], &lexemes, i),
|
||||
Substack::Bottom.push(i.i("orcx").await).push(i.i("input").await),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let mtreev =
|
||||
parse_mtree(Snippet::new(&lexemes[0], &lexemes, i), Substack::Bottom).await.unwrap();
|
||||
if args.verbose {
|
||||
let fmt = mtreev_fmt(&mtreev, &FmtCtxImpl { i }).await;
|
||||
println!("parsed: {}", take_first(&fmt, true));
|
||||
|
||||
Reference in New Issue
Block a user