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",
|
"ordered-float",
|
||||||
"regex",
|
"regex",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
"rust_decimal",
|
|
||||||
"some_executor 0.4.0",
|
"some_executor 0.4.0",
|
||||||
"substack",
|
"substack",
|
||||||
"test_executors",
|
"test_executors",
|
||||||
@@ -1201,6 +1200,7 @@ dependencies = [
|
|||||||
"orchid-base",
|
"orchid-base",
|
||||||
"orchid-extension",
|
"orchid-extension",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
|
"rust_decimal",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
4
SWAP.md
4
SWAP.md
@@ -1,9 +1,5 @@
|
|||||||
## Async conversion
|
## 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
|
consider converting extension's SysCtx to a typed context bag
|
||||||
|
|
||||||
align fn atom and macros on both sides with new design. No global state.
|
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"
|
ordered-float = "4.6.0"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
rust-embed = "8.5.0"
|
rust-embed = "8.5.0"
|
||||||
rust_decimal = "1.36.0"
|
|
||||||
some_executor = "0.4.0"
|
some_executor = "0.4.0"
|
||||||
substack = "1.1.1"
|
substack = "1.1.1"
|
||||||
test_executors = "0.3.2"
|
test_executors = "0.3.2"
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ impl Interned for String {
|
|||||||
impl InternMarker for api::TStr {
|
impl InternMarker for api::TStr {
|
||||||
type Interned = String;
|
type Interned = String;
|
||||||
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
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 get_id(self) -> NonZeroU64 { self.0 }
|
||||||
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||||
@@ -125,7 +125,7 @@ impl Interned for Vec<Tok<String>> {
|
|||||||
impl InternMarker for api::TStrv {
|
impl InternMarker for api::TStrv {
|
||||||
type Interned = Vec<Tok<String>>;
|
type Interned = Vec<Tok<String>>;
|
||||||
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
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;
|
let data = futures::future::join_all(rep.into_iter().map(|m| i.ex(m))).await;
|
||||||
Tok::new(Rc::new(data), self)
|
Tok::new(Rc::new(data), self)
|
||||||
}
|
}
|
||||||
@@ -217,24 +217,26 @@ pub struct TypedInterners {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Interner {
|
pub struct InternerData {
|
||||||
interners: Mutex<TypedInterners>,
|
interners: Mutex<TypedInterners>,
|
||||||
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
|
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct Interner(Rc<InternerData>);
|
||||||
impl Interner {
|
impl Interner {
|
||||||
pub fn new_master() -> Self { Self::default() }
|
pub fn new_master() -> Self { Self::default() }
|
||||||
pub fn new_replica(req: impl DynRequester<Transfer = api::IntReq> + 'static) -> Self {
|
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
|
/// 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> {
|
pub async fn i<T: Interned>(&self, t: &(impl Internable<Interned = T> + ?Sized)) -> Tok<T> {
|
||||||
let data = t.get_owned();
|
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);
|
let typed = T::bimap(&mut g);
|
||||||
if let Some(tok) = typed.by_value(&data) {
|
if let Some(tok) = typed.by_value(&data) {
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
let marker = match &self.master {
|
let marker = match &self.0.master {
|
||||||
Some(c) => data.clone().intern(&**c).await,
|
Some(c) => data.clone().intern(&**c).await,
|
||||||
None =>
|
None =>
|
||||||
T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()),
|
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
|
/// Extern an identifier; query the data it represents if not known locally
|
||||||
pub async fn ex<M: InternMarker>(&self, marker: M) -> Tok<M::Interned> {
|
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;
|
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;
|
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
|
token
|
||||||
}
|
}
|
||||||
pub async fn sweep_replica(&self) -> api::Retained {
|
pub async fn sweep_replica(&self) -> api::Retained {
|
||||||
assert!(self.master.is_some(), "Not a replica");
|
assert!(self.0.master.is_some(), "Not a replica");
|
||||||
let mut g = self.interners.lock().await;
|
let mut g = self.0.interners.lock().await;
|
||||||
api::Retained { strings: g.strings.sweep_replica(), vecs: g.vecs.sweep_replica() }
|
api::Retained { strings: g.strings.sweep_replica(), vecs: g.vecs.sweep_replica() }
|
||||||
}
|
}
|
||||||
pub async fn sweep_master(&self, retained: api::Retained) {
|
pub async fn sweep_master(&self, retained: api::Retained) {
|
||||||
assert!(self.master.is_none(), "Not master");
|
assert!(self.0.master.is_none(), "Not master");
|
||||||
let mut g = self.interners.lock().await;
|
let mut g = self.0.interners.lock().await;
|
||||||
g.strings.sweep_master(retained.strings.into_iter().collect());
|
g.strings.sweep_master(retained.strings.into_iter().collect());
|
||||||
g.vecs.sweep_master(retained.vecs.into_iter().collect());
|
g.vecs.sweep_master(retained.vecs.into_iter().collect());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl fmt::Debug for Interner {
|
impl fmt::Debug for Interner {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
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::num::IntErrorKind;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use num_traits::ToPrimitive;
|
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
use rust_decimal::Decimal;
|
|
||||||
|
|
||||||
use crate::error::{OrcErr, mk_err};
|
use crate::error::{OrcErr, mk_err};
|
||||||
use crate::interner::Interner;
|
use crate::interner::Interner;
|
||||||
@@ -12,24 +10,17 @@ use crate::location::Pos;
|
|||||||
/// A number, either floating point or unsigned int, parsed by Orchid.
|
/// A number, either floating point or unsigned int, parsed by Orchid.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum Numeric {
|
pub enum Numeric {
|
||||||
/// A nonnegative integer
|
/// An integer
|
||||||
Uint(u64),
|
Int(i64),
|
||||||
/// A binary float other than NaN
|
/// A binary float other than NaN
|
||||||
Float(NotNan<f64>),
|
Float(NotNan<f64>),
|
||||||
/// A decimal number
|
|
||||||
Decimal(Decimal),
|
|
||||||
}
|
}
|
||||||
impl Numeric {
|
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 float(value: f64) -> Self { Self::Float(NotNan::new(value).unwrap()) }
|
||||||
pub fn to_f64(self) -> NotNan<f64> {
|
pub fn to_f64(self) -> NotNan<f64> {
|
||||||
match self {
|
match self {
|
||||||
Self::Float(f) => f,
|
Self::Float(f) => f,
|
||||||
Self::Decimal(d) => {
|
Self::Int(i) => NotNan::new(i as f64).expect("int cannot be NaN"),
|
||||||
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"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
/// Parse a numbre literal out of text
|
||||||
pub fn parse_num(string: &str) -> Result<Numeric, NumError> {
|
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)))
|
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("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})");
|
eprintln!("({radix}, {noprefix}, {pos})");
|
||||||
// identity
|
// identity
|
||||||
let (base, exponent) = match noprefix.split_once('p') {
|
let (base_s, exponent) = match noprefix.split_once('p') {
|
||||||
Some((b, e)) => {
|
Some((b, e)) => {
|
||||||
let (s, d, len) = e.strip_prefix('-').map_or((1, e, 0), |ue| (-1, ue, 1));
|
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)
|
(b, s * int_parse(d, 10, pos + b.len() + 1 + len)? as i32)
|
||||||
},
|
},
|
||||||
None => (noprefix, 0),
|
None => (noprefix, 0),
|
||||||
};
|
};
|
||||||
eprintln!("({base},{exponent})");
|
eprintln!("({base_s},{exponent})");
|
||||||
match base.split_once('.') {
|
match base_s.split_once('.') {
|
||||||
None => {
|
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 Ok(pos_exp) = u32::try_from(exponent) {
|
||||||
if let Some(radical) = u64::from(radix).checked_pow(pos_exp) {
|
if let Some(radical) = u64::from(radix).checked_pow(pos_exp) {
|
||||||
let number = base_usize.checked_mul(radical).ok_or(overflow_err)?;
|
let num = base.checked_mul(radical).and_then(|m| m.try_into().ok()).ok_or(overflow_e)?;
|
||||||
return Ok(Numeric::Uint(number));
|
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 };
|
let err = NumError { range: 0..string.len(), kind: NumErrorKind::NaN };
|
||||||
Ok(Numeric::Float(NotNan::new(f).map_err(|_| err)?))
|
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 whole_n = int_parse(whole, radix, pos)?;
|
||||||
let part_n = int_parse(part, radix, pos + whole.len() + 1)?;
|
let part_n = int_parse(part, radix, pos + whole.len() + 1)?;
|
||||||
let scale = part.chars().filter(|c| *c != '_').count() as u32;
|
let scale = part.chars().filter(|c| *c != '_').count() as u32;
|
||||||
if radix == 10 {
|
let real_val = whole_n as f64 + (part_n as f64 / (radix as f64).powi(scale as i32));
|
||||||
let scaled_unit = 10u64.checked_pow(scale).ok_or(overflow_err.clone())?;
|
let f = real_val * (radix as f64).powi(exponent);
|
||||||
let scaled_n = i128::from(whole_n) * i128::from(scaled_unit) + i128::from(part_n);
|
Ok(Numeric::Float(NotNan::new(f).expect("None of the inputs are NaN")))
|
||||||
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")))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +143,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn just_ints() {
|
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("12345", 12345);
|
||||||
test("0xcafebabe", 0xcafebabe);
|
test("0xcafebabe", 0xcafebabe);
|
||||||
test("0o751", 0o751);
|
test("0o751", 0o751);
|
||||||
@@ -178,11 +153,11 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn decimals() {
|
fn decimals() {
|
||||||
let test = |s, n| assert_eq!(parse_num(s), Ok(n));
|
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("0xf.cafe", Numeric::float(0xf as f64 + 0xcafe as f64 / 0x10000 as f64));
|
||||||
test("34p3", Numeric::Uint(34000));
|
test("34p3", Numeric::Int(34000));
|
||||||
test("0x2p3", Numeric::Uint(0x2 * 0x1000));
|
test("0x2p3", Numeric::Int(0x2 * 0x1000));
|
||||||
test("1.5p3", Numeric::decimal(1500, 0));
|
test("1.5p3", Numeric::float(1500.0));
|
||||||
test("0x2.5p3", Numeric::float((0x25 * 0x100) as f64));
|
test("0x2.5p3", Numeric::float((0x25 * 0x100) as f64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,13 @@ pub trait AtomicVariant {}
|
|||||||
pub trait Atomic: 'static + Sized {
|
pub trait Atomic: 'static + Sized {
|
||||||
type Variant: AtomicVariant;
|
type Variant: AtomicVariant;
|
||||||
type Data: Clone + Coding + Sized + 'static;
|
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>;
|
fn reg_reqs() -> MethodSetBuilder<Self>;
|
||||||
}
|
}
|
||||||
impl<A: Atomic> AtomCard for A {
|
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 }
|
ForeignAtom { _life: PhantomData, atom, ctx: handle.ctx.clone(), expr: Some(handle), pos }
|
||||||
}
|
}
|
||||||
pub async fn request<M: AtomMethod>(&self, m: M) -> Option<M::Response> {
|
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(),
|
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,
|
enc_vec(&m).await,
|
||||||
)))
|
)))
|
||||||
.await?;
|
.await?;
|
||||||
@@ -125,7 +132,7 @@ impl fmt::Debug for ForeignAtom<'_> {
|
|||||||
}
|
}
|
||||||
impl Format for ForeignAtom<'_> {
|
impl Format for ForeignAtom<'_> {
|
||||||
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.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<'_> {
|
impl AtomRepr for ForeignAtom<'_> {
|
||||||
@@ -145,7 +152,7 @@ pub struct NotTypAtom {
|
|||||||
impl NotTypAtom {
|
impl NotTypAtom {
|
||||||
pub async fn mk_err(&self) -> OrcErr {
|
pub async fn mk_err(&self) -> OrcErr {
|
||||||
mk_err(
|
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()),
|
format!("This expression is not a {}", self.typ.name()),
|
||||||
[self.pos.clone().into()],
|
[self.pos.clone().into()],
|
||||||
)
|
)
|
||||||
@@ -192,7 +199,7 @@ impl<A: AtomCard> MethodSetBuilder<A> {
|
|||||||
handlers: stream::from_iter(self.handlers.iter())
|
handlers: stream::from_iter(self.handlers.iter())
|
||||||
.then(|(k, v)| {
|
.then(|(k, v)| {
|
||||||
clone!(ctx; async move {
|
clone!(ctx; async move {
|
||||||
(Sym::parse(k, &ctx.i).await.unwrap(), v.clone())
|
(Sym::parse(k, ctx.i()).await.unwrap(), v.clone())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
@@ -257,9 +264,9 @@ impl<A: AtomicFeatures> TypAtom<'_, A> {
|
|||||||
pub async fn request<M: AtomMethod>(&self, req: M) -> M::Response
|
pub async fn request<M: AtomMethod>(&self, req: M) -> M::Response
|
||||||
where A: Supports<M> {
|
where A: Supports<M> {
|
||||||
M::Response::decode(Pin::new(
|
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(),
|
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,
|
enc_vec(&req).await,
|
||||||
)))
|
)))
|
||||||
.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);
|
pub struct AtomCtx<'a>(pub &'a [u8], pub Option<api::AtomId>, pub SysCtx);
|
||||||
impl FmtCtx for AtomCtx<'_> {
|
impl FmtCtx for AtomCtx<'_> {
|
||||||
fn i(&self) -> &Interner { &self.2.i }
|
fn i(&self) -> &Interner { self.2.i() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AtomDynfo: 'static {
|
pub trait AtomDynfo: 'static {
|
||||||
|
|||||||
@@ -28,20 +28,23 @@ use crate::atom::{
|
|||||||
};
|
};
|
||||||
use crate::expr::{Expr, ExprHandle};
|
use crate::expr::{Expr, ExprHandle};
|
||||||
use crate::gen_expr::{GExpr, bot};
|
use crate::gen_expr::{GExpr, bot};
|
||||||
use crate::system::SysCtx;
|
use crate::system::{SysCtx, SysCtxEntry};
|
||||||
|
use crate::system_ctor::CtedObj;
|
||||||
|
|
||||||
pub struct OwnedVariant;
|
pub struct OwnedVariant;
|
||||||
impl AtomicVariant for OwnedVariant {}
|
impl AtomicVariant for OwnedVariant {}
|
||||||
impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVariant> for A {
|
impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVariant> for A {
|
||||||
fn _factory(self) -> AtomFactory {
|
fn _factory(self) -> AtomFactory {
|
||||||
AtomFactory::new(move |ctx| async move {
|
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 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;
|
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.obj_store.1.read().await.insert(atom_id, Box::new(self));
|
ctx.get_or_default::<ObjStore>().objects.read().await.insert(atom_id, Box::new(self));
|
||||||
api::Atom { drop: Some(atom_id), data, owner: ctx.id }
|
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() } }
|
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> {
|
impl<'a> AtomReadGuard<'a> {
|
||||||
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
|
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
|
||||||
let guard = ctx.obj_store.1.read().await;
|
let guard = ctx.get_or_default::<ObjStore>().objects.read().await;
|
||||||
assert!(guard.get(&id).is_some(), "Received invalid atom ID: {}", id.0);
|
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 }
|
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> {
|
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))
|
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>>;
|
fn val(&self) -> impl Future<Output = Cow<'_, Self::Data>>;
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn call_ref(&self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
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> {
|
fn call(self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
||||||
async {
|
async {
|
||||||
@@ -231,7 +235,7 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Any + Clone + 'static {
|
|||||||
}
|
}
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn command(self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<GExpr>>> {
|
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)]
|
#[allow(unused_variables)]
|
||||||
fn free(self, ctx: SysCtx) -> impl Future<Output = ()> { async {} }
|
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::expr::ExprHandle;
|
||||||
use crate::gen_expr::{GExpr, bot};
|
use crate::gen_expr::{GExpr, bot};
|
||||||
use crate::system::SysCtx;
|
use crate::system::SysCtx;
|
||||||
|
use crate::system_ctor::CtedObj;
|
||||||
|
|
||||||
pub struct ThinVariant;
|
pub struct ThinVariant;
|
||||||
impl AtomicVariant for ThinVariant {}
|
impl AtomicVariant for ThinVariant {}
|
||||||
impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant> for A {
|
impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant> for A {
|
||||||
fn _factory(self) -> AtomFactory {
|
fn _factory(self) -> AtomFactory {
|
||||||
AtomFactory::new(move |ctx| async move {
|
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;
|
let mut buf = enc_vec(&id).await;
|
||||||
self.encode(Pin::new(&mut buf)).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() } }
|
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, ()> {
|
fn drop<'a>(&'a self, AtomCtx(buf, _, ctx): AtomCtx<'a>) -> LocalBoxFuture<'a, ()> {
|
||||||
async move {
|
async move {
|
||||||
let string_self = T::decode(Pin::new(&mut &buf[..])).await.print(ctx.clone()).await;
|
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()
|
.boxed_local()
|
||||||
}
|
}
|
||||||
@@ -117,11 +118,11 @@ pub trait ThinAtom:
|
|||||||
{
|
{
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn call(&self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
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)]
|
#[allow(unused_variables)]
|
||||||
fn command(&self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<GExpr>>> {
|
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)]
|
#[allow(unused_variables)]
|
||||||
fn print(&self, ctx: SysCtx) -> impl Future<Output = FmtUnit> {
|
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> {
|
impl<A: AtomicFeatures> TryFromExpr for TypAtom<'_, A> {
|
||||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||||
match expr.atom().await {
|
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(f) => match downcast_atom::<A>(f).await {
|
||||||
Ok(a) => Ok(a),
|
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 futures::{FutureExt, StreamExt};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_api::ApplyMacro;
|
use orchid_api::{ApplyMacro, ExtMsgSet};
|
||||||
use orchid_api_traits::{Decode, Encode, enc_vec};
|
use orchid_api_traits::{Decode, Encode, enc_vec};
|
||||||
use orchid_base::builtin::{ExtPort, Spawner};
|
use orchid_base::builtin::{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};
|
||||||
@@ -32,14 +32,14 @@ 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::{ObjStore, take_atom};
|
use crate::atom_owned::take_atom;
|
||||||
use crate::fs::VirtFS;
|
use crate::fs::VirtFS;
|
||||||
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
|
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
|
||||||
use crate::macros::{Rule, RuleCtx};
|
use crate::macros::{Rule, RuleCtx};
|
||||||
use crate::msg::{recv_parent_msg, send_parent_msg};
|
use crate::msg::{recv_parent_msg, send_parent_msg};
|
||||||
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::{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 ExtReq<'a> = RequestHandle<'a, api::ExtMsgSet>;
|
||||||
pub type ExtReqNot = ReqNot<api::ExtMsgSet>;
|
pub type ExtReqNot = ReqNot<api::ExtMsgSet>;
|
||||||
@@ -61,11 +61,11 @@ pub enum MemberRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SystemRecord {
|
pub struct SystemRecord {
|
||||||
cted: CtedObj,
|
|
||||||
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
|
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
|
||||||
declfs: api::EagerVfs,
|
declfs: api::EagerVfs,
|
||||||
lazy_members: HashMap<api::TreeId, MemberRecord>,
|
lazy_members: HashMap<api::TreeId, MemberRecord>,
|
||||||
rules: HashMap<api::MacroId, Rc<Rule>>,
|
rules: HashMap<api::MacroId, Rc<Rule>>,
|
||||||
|
ctx: SysCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait_set! {
|
trait_set! {
|
||||||
@@ -78,14 +78,13 @@ trait_set! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
|
pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
|
||||||
get_sys_ctx: &impl Fn(api::SysId, ReqNot<api::ExtMsgSet>) -> F,
|
get_sys_ctx: &impl Fn(api::SysId) -> F,
|
||||||
reqnot: ReqNot<api::ExtMsgSet>,
|
|
||||||
atom: &'a api::Atom,
|
atom: &'a api::Atom,
|
||||||
cb: impl WARCallback<'a, T>,
|
cb: impl WARCallback<'a, T>,
|
||||||
) -> T {
|
) -> T {
|
||||||
let mut data = &atom.data[..];
|
let mut data = &atom.data[..];
|
||||||
let ctx = get_sys_ctx(atom.owner, reqnot).await;
|
let ctx = get_sys_ctx(atom.owner).await;
|
||||||
let inst = ctx.cted.inst();
|
let inst = ctx.get::<CtedObj>().inst();
|
||||||
let id = AtomTypeId::decode(Pin::new(&mut data)).await;
|
let id = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||||
let atom_record = atom_by_idx(inst.card(), id.clone()).expect("Atom ID reserved");
|
let atom_record = atom_by_idx(inst.card(), id.clone()).expect("Atom ID reserved");
|
||||||
cb(atom_record, ctx, id, data).await
|
cb(atom_record, ctx, id, data).await
|
||||||
@@ -108,6 +107,7 @@ pub struct ExtensionOwner {
|
|||||||
rn: ReqNot<api::ExtMsgSet>,
|
rn: ReqNot<api::ExtMsgSet>,
|
||||||
out_recv: Receiver<Vec<u8>>,
|
out_recv: Receiver<Vec<u8>>,
|
||||||
out_send: Sender<Vec<u8>>,
|
out_send: Sender<Vec<u8>>,
|
||||||
|
ext_header: api::ExtensionHeader,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtPort for ExtensionOwner {
|
impl ExtPort for ExtensionOwner {
|
||||||
@@ -125,6 +125,12 @@ impl ExtPort for ExtensionOwner {
|
|||||||
.boxed_local()
|
.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) {
|
pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
||||||
let api::HostHeader { log_strategy, msg_logs } =
|
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)| (u16::try_from(id).expect("more than u16max system ctors"), sys))
|
||||||
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
|
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
|
||||||
.collect_vec();
|
.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() }
|
api::ExtensionHeader { name: data.name.to_string(), systems: decls.clone() }
|
||||||
.encode(Pin::new(&mut buf))
|
.encode(Pin::new(&mut buf))
|
||||||
.await;
|
.await;
|
||||||
@@ -143,41 +149,48 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
|||||||
let exiting = Arc::new(AtomicBool::new(false));
|
let exiting = Arc::new(AtomicBool::new(false));
|
||||||
let logger = Logger::new(log_strategy);
|
let logger = Logger::new(log_strategy);
|
||||||
let msg_logger = Logger::new(msg_logs);
|
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 interner_weak = Rc::downgrade(&interner_cell);
|
||||||
let obj_store = ObjStore::default();
|
let systems_weak = Rc::downgrade(&systems_lock);
|
||||||
let mk_ctx = clone!(
|
let get_ctx = clone!(systems_weak; move |id: api::SysId| clone!(systems_weak; async move {
|
||||||
logger, systems, spawner, obj_store, interner_weak;
|
let systems =
|
||||||
move |id: api::SysId, reqnot: ReqNot<api::ExtMsgSet>| {
|
systems_weak.upgrade().expect("System table dropped before request processing done");
|
||||||
clone!(logger, systems, spawner, obj_store, interner_weak; async move {
|
let x = systems.lock().await.get(&id).expect("System not found").ctx.clone();
|
||||||
let cted = systems.lock().await[&id].cted.clone();
|
x
|
||||||
let interner_cell = (interner_weak.upgrade())
|
}));
|
||||||
.expect("mk_ctx called after Interner rc dropped");
|
let init_ctx = {
|
||||||
let i = (interner_cell.borrow().clone())
|
clone!(systems_weak, interner_weak, spawner, logger);
|
||||||
.expect("mk_ctx called before interner initialized");
|
move |id: api::SysId, cted: CtedObj, reqnot: ReqNot<ExtMsgSet>| {
|
||||||
SysCtx { id, cted, logger, reqnot, spawner, obj_store, i: i.clone() }
|
clone!(systems_weak, interner_weak, spawner, logger; async move {
|
||||||
}.boxed_local())
|
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(
|
let rn = ReqNot::<api::ExtMsgSet>::new(
|
||||||
msg_logger.clone(),
|
msg_logger.clone(),
|
||||||
move |a, _| async move { send_parent_msg(a).await.unwrap() }.boxed_local(),
|
move |a, _| async move { send_parent_msg(a).await.unwrap() }.boxed_local(),
|
||||||
clone!(systems, exiting, mk_ctx; move |n, reqnot| {
|
clone!(systems_weak, exiting, get_ctx; move |n, reqnot| {
|
||||||
clone!(systems, exiting, mk_ctx; async move {
|
clone!(systems_weak, exiting, get_ctx; async move {
|
||||||
match n {
|
match n {
|
||||||
api::HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
|
api::HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
|
||||||
api::HostExtNotif::SystemDrop(api::SystemDrop(sys_id)) =>
|
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)) => {
|
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
|
take_atom(atom, &ctx).await.dyn_free(ctx.clone()).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.boxed_local())
|
}.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| {
|
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 {
|
async move {
|
||||||
let interner_cell = interner_weak.upgrade().expect("Interner dropped before request");
|
let interner_cell = interner_weak.upgrade().expect("Interner dropped before request");
|
||||||
let i = interner_cell.borrow().clone().expect("Request arrived before interner set");
|
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 lazy_mems = Mutex::new(HashMap::new());
|
||||||
let rules = Mutex::new(HashMap::new());
|
let rules = Mutex::new(HashMap::new());
|
||||||
let ctx = SysCtx {
|
let ctx = init_ctx(new_sys.id, cted.clone(), hand.reqnot()).await;
|
||||||
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 const_root = stream::from_iter(cted.inst().dyn_env())
|
let const_root = stream::from_iter(cted.inst().dyn_env())
|
||||||
.then(|(k, v)| {
|
.then(|(k, v)| {
|
||||||
let (req, lazy_mems, rules) = (&hand, &lazy_mems, &rules);
|
let (req, lazy_mems, rules) = (&hand, &lazy_mems, &rules);
|
||||||
clone!(i, ctx; async move {
|
clone!(i, ctx; async move {
|
||||||
let name = i.i(&k).await.to_api();
|
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,
|
lazy_members: &mut *lazy_mems.lock().await,
|
||||||
rules: &mut *rules.lock().await,
|
rules: &mut *rules.lock().await,
|
||||||
sys: ctx,
|
sys: ctx,
|
||||||
@@ -229,17 +234,19 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
|||||||
let record = SystemRecord {
|
let record = SystemRecord {
|
||||||
declfs,
|
declfs,
|
||||||
vfses,
|
vfses,
|
||||||
cted,
|
ctx,
|
||||||
lazy_members: lazy_mems.into_inner(),
|
lazy_members: lazy_mems.into_inner(),
|
||||||
rules: rules.into_inner(),
|
rules: rules.into_inner(),
|
||||||
};
|
};
|
||||||
|
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
|
||||||
systems.lock().await.insert(new_sys.id, record);
|
systems.lock().await.insert(new_sys.id, record);
|
||||||
hand
|
hand
|
||||||
.handle(&new_sys, &api::SystemInst { lex_filter, const_root, line_types: vec![] })
|
.handle(&new_sys, &api::SystemInst { lex_filter, const_root, line_types: vec![] })
|
||||||
.await
|
.await
|
||||||
},
|
},
|
||||||
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
|
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 mut systems_g = systems.lock().await;
|
||||||
let SystemRecord { lazy_members, rules, .. } =
|
let SystemRecord { lazy_members, rules, .. } =
|
||||||
systems_g.get_mut(&sys_id).expect("System not found");
|
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::Res) => panic!("This tree has already been transmitted"),
|
||||||
Some(MemberRecord::Gen(path, cb)) => (path, cb),
|
Some(MemberRecord::Gen(path, cb)) => (path, cb),
|
||||||
};
|
};
|
||||||
let tree = cb.build(Sym::new(path.clone(), &i).await.unwrap()).await;
|
let tree = cb.build(Sym::new(path.clone(), &i).await.unwrap(), sys_ctx.clone()).await;
|
||||||
let mut tia_ctx = TIACtxImpl {
|
let mut tia_ctx = TreeIntoApiCtxImpl {
|
||||||
sys: sys_ctx,
|
sys: sys_ctx,
|
||||||
path: Substack::Bottom,
|
path: Substack::Bottom,
|
||||||
basepath: &path,
|
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
|
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs @ api::GetVfs(sys_id))) => {
|
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;
|
let systems_g = systems.lock().await;
|
||||||
hand.handle(&get_vfs, &systems_g[&sys_id].declfs).await
|
hand.handle(&get_vfs, &systems_g[&sys_id].declfs).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
|
api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
|
||||||
let api::SysFwded(sys_id, payload) = fwd;
|
let api::SysFwded(sys_id, payload) = fwd;
|
||||||
let ctx = mk_ctx(sys_id, hand.reqnot()).await;
|
let ctx = get_ctx(sys_id).await;
|
||||||
let sys = ctx.cted.inst();
|
let sys = ctx.cted().inst();
|
||||||
sys.dyn_request(hand, payload).await
|
sys.dyn_request(hand, payload).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => {
|
api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => {
|
||||||
let api::VfsRead(sys_id, vfs_id, path) = &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 systems_g = systems.lock().await;
|
||||||
let path = join_all(path.iter().map(|t| Tok::from_api(*t, &i))).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;
|
let vfs = systems_g[sys_id].vfses[vfs_id].load(&path, ctx).await;
|
||||||
hand.handle(&vfs_read, &vfs).await
|
hand.handle(&vfs_read, &vfs).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, text, pos, id }) => {
|
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, text, pos, id }) => {
|
||||||
let systems_g = systems.lock().await;
|
let sys_ctx = get_ctx(sys).await;
|
||||||
let lexers = systems_g[&sys].cted.inst().dyn_lexers();
|
|
||||||
mem::drop(systems_g);
|
|
||||||
let text = Tok::from_api(text, &i).await;
|
let text = Tok::from_api(text, &i).await;
|
||||||
let ctx = LexContext { sys, id, pos, reqnot: hand.reqnot(), text: &text, i: &i };
|
let ctx = LexContext { sys, id, pos, reqnot: hand.reqnot(), text: &text, i: &i };
|
||||||
let trigger_char = text.chars().nth(pos as usize).unwrap();
|
let trigger_char = text.chars().nth(pos as usize).unwrap();
|
||||||
let err_na = err_not_applicable(&i).await;
|
let err_na = err_not_applicable(&i).await;
|
||||||
let err_cascade = err_cascade(&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)) {
|
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char)) {
|
||||||
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 == err_na) => continue,
|
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;
|
return hand.handle(&lex, &eopt).await;
|
||||||
},
|
},
|
||||||
Ok((s, expr)) => {
|
Ok((s, expr)) => {
|
||||||
let ctx = mk_ctx(sys, hand.reqnot()).await;
|
|
||||||
let expr = expr
|
let expr = expr
|
||||||
.to_api(&mut |f, r| {
|
.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;
|
.await;
|
||||||
let pos = (text.len() - s.len()) as u32;
|
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) => {
|
api::HostExtReq::ParseLine(pline) => {
|
||||||
let api::ParseLine { exported, comments, sys, line } = &pline;
|
let api::ParseLine { exported, comments, sys, line } = &pline;
|
||||||
let mut ctx = mk_ctx(*sys, hand.reqnot()).await;
|
let mut ctx = get_ctx(*sys).await;
|
||||||
let parsers = ctx.cted.inst().dyn_parsers();
|
let parsers = ctx.cted().inst().dyn_parsers();
|
||||||
let comments = join_all(comments.iter().map(|c| Comment::from_api(c, &i))).await;
|
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 line: Vec<GenTokTree> = ttv_from_api(line, &mut ctx, &i).await;
|
||||||
let snip = Snippet::new(line.first().expect("Empty line"), &line, &i);
|
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) => {
|
api::HostExtReq::AtomReq(atom_req) => {
|
||||||
let atom = atom_req.get_atom();
|
let atom = atom_req.get_atom();
|
||||||
let atom_req = atom_req.clone();
|
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 {
|
async move {
|
||||||
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
||||||
match &atom_req {
|
match &atom_req {
|
||||||
@@ -389,16 +396,16 @@ pub async fn extension_main_logic(data: ExtensionData, spawner: Spawner) {
|
|||||||
api::HostExtReq::DeserAtom(deser) => {
|
api::HostExtReq::DeserAtom(deser) => {
|
||||||
let api::DeserAtom(sys, buf, refs) = &deser;
|
let api::DeserAtom(sys, buf, refs) = &deser;
|
||||||
let mut read = &mut &buf[..];
|
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 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");
|
let nfo = atom_by_idx(inst.card(), id).expect("Deserializing atom with invalid ID");
|
||||||
hand.handle(&deser, &nfo.deserialize(ctx.clone(), read, refs).await).await
|
hand.handle(&deser, &nfo.deserialize(ctx.clone(), read, refs).await).await
|
||||||
},
|
},
|
||||||
orchid_api::HostExtReq::ApplyMacro(am) => {
|
orchid_api::HostExtReq::ApplyMacro(am) => {
|
||||||
let tok = hand.will_handle_as(&am);
|
let tok = hand.will_handle_as(&am);
|
||||||
let ApplyMacro { id, params, run_id, sys } = 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 =
|
let mut ctx =
|
||||||
RuleCtx { args: ahash::HashMap::default(), run_id, sys: sys_ctx.clone() };
|
RuleCtx { args: ahash::HashMap::default(), run_id, sys: sys_ctx.clone() };
|
||||||
for (k, v) in params {
|
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 err_cascade = err_cascade(&i).await;
|
||||||
|
let systems = systems_weak.upgrade().expect("macro call during shutdown");
|
||||||
let systems_g = systems.lock().await;
|
let systems_g = systems.lock().await;
|
||||||
let rule = &systems_g[&sys].rules[&id];
|
let rule = &systems_g[&sys].rules[&id];
|
||||||
match (rule.apply)(ctx).await {
|
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) {
|
while !exiting.load(Ordering::Relaxed) {
|
||||||
let rcvd = recv_parent_msg().await.unwrap();
|
let rcvd = recv_parent_msg().await.unwrap();
|
||||||
spawner(Box::pin(clone!(rn; async move { rn.receive(&rcvd).await })))
|
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(crate) fn from_args(ctx: SysCtx, tk: api::ExprTicket) -> Self { 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 {
|
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 }
|
Self { ctx: self.ctx.clone(), tk: self.tk }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,9 +34,9 @@ impl fmt::Debug for ExprHandle {
|
|||||||
}
|
}
|
||||||
impl Drop for ExprHandle {
|
impl Drop for ExprHandle {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let notif = api::Release(self.ctx.id, self.tk);
|
let notif = api::Release(self.ctx.sys_id(), self.tk);
|
||||||
let SysCtx { reqnot, spawner, .. } = self.ctx.clone();
|
let reqnot = self.ctx.reqnot().clone();
|
||||||
spawner(Box::pin(async move { reqnot.notify(notif).await }))
|
self.ctx.spawner()(Box::pin(async move { reqnot.notify(notif).await }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,13 +53,13 @@ impl Expr {
|
|||||||
|
|
||||||
pub async fn data(&self) -> &ExprData {
|
pub async fn data(&self) -> &ExprData {
|
||||||
(self.data.get_or_init(async {
|
(self.data.get_or_init(async {
|
||||||
let details = self.handle.ctx.reqnot.request(api::Inspect { target: self.handle.tk }).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 pos = Pos::from_api(&details.location, self.handle.ctx.i()).await;
|
||||||
let kind = match details.kind {
|
let kind = match details.kind {
|
||||||
api::InspectedKind::Atom(a) =>
|
api::InspectedKind::Atom(a) =>
|
||||||
ExprKind::Atom(ForeignAtom::new(self.handle.clone(), a, pos.clone())),
|
ExprKind::Atom(ForeignAtom::new(self.handle.clone(), a, pos.clone())),
|
||||||
api::InspectedKind::Bottom(b) =>
|
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,
|
api::InspectedKind::Opaque => ExprKind::Opaque,
|
||||||
};
|
};
|
||||||
ExprData { pos, kind }
|
ExprData { pos, kind }
|
||||||
@@ -83,7 +83,7 @@ impl Format for Expr {
|
|||||||
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(&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_api_traits::Encode;
|
||||||
use orchid_base::clone;
|
use orchid_base::clone;
|
||||||
use orchid_base::error::OrcRes;
|
use orchid_base::error::OrcRes;
|
||||||
use orchid_base::format::{FmtCtxImpl, Format, take_first};
|
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use trait_set::trait_set;
|
use trait_set::trait_set;
|
||||||
|
|
||||||
@@ -22,7 +21,7 @@ use crate::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
|||||||
use crate::conv::ToExpr;
|
use crate::conv::ToExpr;
|
||||||
use crate::expr::{Expr, ExprHandle};
|
use crate::expr::{Expr, ExprHandle};
|
||||||
use crate::gen_expr::GExpr;
|
use crate::gen_expr::GExpr;
|
||||||
use crate::system::SysCtx;
|
use crate::system::{SysCtx, SysCtxEntry};
|
||||||
|
|
||||||
trait_set! {
|
trait_set! {
|
||||||
trait FunCB = Fn(Vec<Expr>) -> LocalBoxFuture<'static, OrcRes<GExpr>> + 'static;
|
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>>;
|
fn apply(&self, v: Vec<Expr>) -> impl Future<Output = OrcRes<GExpr>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local! {
|
#[derive(Default)]
|
||||||
static FUNS: Rc<Mutex<HashMap<Sym, (u8, Rc<dyn FunCB>)>>> = Rc::default();
|
struct FunsCtx(Mutex<HashMap<Sym, (u8, Rc<dyn FunCB>)>>);
|
||||||
}
|
impl SysCtxEntry for FunsCtx {}
|
||||||
|
|
||||||
/// An Atom representing a partially applied named native function. These
|
/// An Atom representing a partially applied named native function. These
|
||||||
/// partial calls are serialized into the name of the native function and the
|
/// 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>,
|
fun: Rc<dyn FunCB>,
|
||||||
}
|
}
|
||||||
impl Fun {
|
impl Fun {
|
||||||
pub async fn new<I, O, F: ExprFunc<I, O>>(path: Sym, f: F) -> Self {
|
pub async fn new<I, O, F: ExprFunc<I, O>>(path: Sym, ctx: SysCtx, f: F) -> Self {
|
||||||
let funs = FUNS.with(|funs| funs.clone());
|
let funs: &FunsCtx = ctx.get_or_default();
|
||||||
let mut fung = funs.lock().await;
|
let mut fung = funs.0.lock().await;
|
||||||
let fun = if let Some(x) = fung.get(&path) {
|
let fun = if let Some(x) = fung.get(&path) {
|
||||||
x.1.clone()
|
x.1.clone()
|
||||||
} else {
|
} else {
|
||||||
@@ -89,8 +88,8 @@ impl OwnedAtom for Fun {
|
|||||||
}
|
}
|
||||||
async fn deserialize(mut ctx: impl DeserializeCtx, args: Self::Refs) -> Self {
|
async fn deserialize(mut ctx: impl DeserializeCtx, args: Self::Refs) -> Self {
|
||||||
let sys = ctx.sys();
|
let sys = ctx.sys();
|
||||||
let path = Sym::from_api(ctx.decode().await, &sys.i).await;
|
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 (arity, fun) = sys.get_or_default::<FunsCtx>().0.lock().await.get(&path).unwrap().clone();
|
||||||
Self { args, arity, path, fun }
|
Self { args, arity, path, fun }
|
||||||
}
|
}
|
||||||
async fn print(&self, _: SysCtx) -> orchid_base::format::FmtUnit {
|
async fn print(&self, _: SysCtx) -> orchid_base::format::FmtUnit {
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ use ahash::HashMap;
|
|||||||
use futures::future::{LocalBoxFuture, join_all};
|
use futures::future::{LocalBoxFuture, join_all};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use never::Never;
|
use never::Never;
|
||||||
|
use orchid_api::ExtMsgSet;
|
||||||
use orchid_base::error::OrcRes;
|
use orchid_base::error::OrcRes;
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_base::macros::{MTree, mtreev_from_api, mtreev_to_api};
|
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 trait_set::trait_set;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
@@ -44,11 +45,11 @@ impl<'a> RuleCtx<'a> {
|
|||||||
run_id: self.run_id,
|
run_id: self.run_id,
|
||||||
query: mtreev_to_api(tree, &mut |b| match *b {}).await,
|
query: mtreev_to_api(tree, &mut |b| match *b {}).await,
|
||||||
};
|
};
|
||||||
let Some(treev) = self.sys.reqnot.request(req).await else {
|
let Some(treev) = self.sys.get::<ReqNot<ExtMsgSet>>().request(req).await else {
|
||||||
return Err(err_cascade(&self.sys.i).await.into());
|
return Err(err_cascade(self.sys.i()).await.into());
|
||||||
};
|
};
|
||||||
static ATOM_MSG: &str = "Returned atom from Rule recursion";
|
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>> {
|
pub fn getv(&mut self, key: &Tok<String>) -> Vec<MTree<'a, Never>> {
|
||||||
self.args.remove(key).expect("Key not found")
|
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 {
|
pub(crate) async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MacroRule {
|
||||||
api::MacroRule {
|
api::MacroRule {
|
||||||
comments: join_all(self.comments.iter().map(|c| async {
|
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,
|
.await,
|
||||||
location: api::Location::Inherit,
|
location: api::Location::Inherit,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use core::fmt;
|
use std::any::{Any, TypeId, type_name};
|
||||||
use std::any::{TypeId, type_name};
|
use std::fmt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
@@ -7,6 +7,8 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::future::LocalBoxFuture;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
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;
|
||||||
@@ -16,7 +18,6 @@ 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::atom_owned::ObjStore;
|
|
||||||
use crate::entrypoint::ExtReq;
|
use crate::entrypoint::ExtReq;
|
||||||
use crate::fs::DeclFs;
|
use crate::fs::DeclFs;
|
||||||
use crate::func_atom::Fun;
|
use crate::func_atom::Fun;
|
||||||
@@ -116,11 +117,11 @@ where A: AtomicFeatures {
|
|||||||
let mut data = &foreign.atom.data[..];
|
let mut data = &foreign.atom.data[..];
|
||||||
let ctx = foreign.ctx.clone();
|
let ctx = foreign.ctx.clone();
|
||||||
let value = AtomTypeId::decode(Pin::new(&mut data)).await;
|
let value = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||||
let own_inst = ctx.cted.inst();
|
let own_inst = ctx.get::<CtedObj>().inst();
|
||||||
let owner = if ctx.id == foreign.atom.owner {
|
let owner = if *ctx.get::<api::SysId>() == foreign.atom.owner {
|
||||||
own_inst.card()
|
own_inst.card()
|
||||||
} else {
|
} 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())?
|
.ok_or_else(|| foreign.clone())?
|
||||||
.get_card()
|
.get_card()
|
||||||
};
|
};
|
||||||
@@ -133,18 +134,80 @@ where A: AtomicFeatures {
|
|||||||
Ok(TypAtom { value, data: foreign })
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct SysCtx {
|
pub struct SysCtx(Rc<MemoMap<TypeId, Box<dyn Any>>>);
|
||||||
pub reqnot: ReqNot<api::ExtMsgSet>,
|
impl SysCtx {
|
||||||
pub spawner: Spawner,
|
pub fn new(
|
||||||
pub id: api::SysId,
|
id: api::SysId,
|
||||||
pub cted: CtedObj,
|
i: Interner,
|
||||||
pub logger: Logger,
|
reqnot: ReqNot<ExtMsgSet>,
|
||||||
pub obj_store: ObjStore,
|
spawner: Spawner,
|
||||||
pub i: Rc<Interner>,
|
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 {
|
impl fmt::Debug for SysCtx {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "SysCtx({:?})", self.id)
|
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 {
|
impl GenItem {
|
||||||
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Item {
|
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Item {
|
||||||
let kind = match self.kind {
|
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::Member(mem) => api::ItemKind::Member(mem.into_api(ctx).await),
|
||||||
GenItemKind::Import(cn) => api::ItemKind::Import(cn.tok().to_api()),
|
GenItemKind::Import(cn) => api::ItemKind::Import(cn.tok().to_api()),
|
||||||
GenItemKind::Macro(priority, gen_rules) => {
|
GenItemKind::Macro(priority, gen_rules) => {
|
||||||
@@ -60,7 +60,7 @@ impl GenItem {
|
|||||||
let comments = join_all(self.comments.iter().map(|c| async {
|
let comments = join_all(self.comments.iter().map(|c| async {
|
||||||
api::Comment {
|
api::Comment {
|
||||||
location: api::Location::Inherit,
|
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;
|
.await;
|
||||||
@@ -92,8 +92,8 @@ pub fn root_mod(
|
|||||||
(name.to_string(), kind)
|
(name.to_string(), kind)
|
||||||
}
|
}
|
||||||
pub fn fun<I, O>(exported: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenItem> {
|
pub fn fun<I, O>(exported: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenItem> {
|
||||||
let fac = LazyMemberFactory::new(move |sym| async {
|
let fac = LazyMemberFactory::new(move |sym, ctx| async {
|
||||||
return MemKind::Const(build_lambdas(Fun::new(sym, xf).await, 0));
|
return MemKind::Const(build_lambdas(Fun::new(sym, ctx, xf).await, 0));
|
||||||
fn build_lambdas(fun: Fun, i: u64) -> GExpr {
|
fn build_lambdas(fun: Fun, i: u64) -> GExpr {
|
||||||
if i < fun.arity().into() {
|
if i < fun.arity().into() {
|
||||||
return lambda(i, [build_lambdas(fun, i + 1)]);
|
return lambda(i, [build_lambdas(fun, i + 1)]);
|
||||||
@@ -129,16 +129,16 @@ pub fn comments<'a>(
|
|||||||
|
|
||||||
trait_set! {
|
trait_set! {
|
||||||
trait LazyMemberCallback =
|
trait LazyMemberCallback =
|
||||||
FnOnce(Sym) -> LocalBoxFuture<'static, MemKind> + DynClone
|
FnOnce(Sym, SysCtx) -> LocalBoxFuture<'static, MemKind> + DynClone
|
||||||
}
|
}
|
||||||
pub struct LazyMemberFactory(Box<dyn LazyMemberCallback>);
|
pub struct LazyMemberFactory(Box<dyn LazyMemberCallback>);
|
||||||
impl LazyMemberFactory {
|
impl LazyMemberFactory {
|
||||||
pub fn new<F: Future<Output = MemKind> + 'static>(
|
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 {
|
||||||
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 {
|
impl Clone for LazyMemberFactory {
|
||||||
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
|
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
|
||||||
@@ -157,7 +157,7 @@ pub struct GenMember {
|
|||||||
}
|
}
|
||||||
impl GenMember {
|
impl GenMember {
|
||||||
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::Member {
|
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 {
|
api::Member {
|
||||||
kind: self.kind.into_api(&mut ctx.push_path(name.clone())).await,
|
kind: self.kind.into_api(&mut ctx.push_path(name.clone())).await,
|
||||||
name: name.to_api(),
|
name: name.to_api(),
|
||||||
@@ -197,7 +197,7 @@ pub trait TreeIntoApiCtx {
|
|||||||
fn req(&self) -> &impl ReqHandlish;
|
fn req(&self) -> &impl ReqHandlish;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TIACtxImpl<'a, 'b, RH: ReqHandlish> {
|
pub struct TreeIntoApiCtxImpl<'a, 'b, RH: ReqHandlish> {
|
||||||
pub sys: SysCtx,
|
pub sys: SysCtx,
|
||||||
pub basepath: &'a [Tok<String>],
|
pub basepath: &'a [Tok<String>],
|
||||||
pub path: Substack<'a, Tok<String>>,
|
pub path: Substack<'a, Tok<String>>,
|
||||||
@@ -206,10 +206,10 @@ pub struct TIACtxImpl<'a, 'b, RH: ReqHandlish> {
|
|||||||
pub req: &'a RH,
|
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 sys(&self) -> SysCtx { self.sys.clone() }
|
||||||
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
|
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
|
||||||
TIACtxImpl {
|
TreeIntoApiCtxImpl {
|
||||||
req: self.req,
|
req: self.req,
|
||||||
lazy_members: self.lazy_members,
|
lazy_members: self.lazy_members,
|
||||||
rules: self.rules,
|
rules: self.rules,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ pub struct ReqPair<R: Request>(R, Sender<R::Response>);
|
|||||||
#[derive(destructure)]
|
#[derive(destructure)]
|
||||||
pub struct ExtensionData {
|
pub struct ExtensionData {
|
||||||
ctx: Ctx,
|
ctx: Ctx,
|
||||||
init: ExtInit,
|
init: Rc<ExtInit>,
|
||||||
reqnot: ReqNot<api::HostMsgSet>,
|
reqnot: ReqNot<api::HostMsgSet>,
|
||||||
systems: Vec<SystemCtor>,
|
systems: Vec<SystemCtor>,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
@@ -55,114 +55,140 @@ impl Drop for ExtensionData {
|
|||||||
pub struct Extension(Rc<ExtensionData>);
|
pub struct Extension(Rc<ExtensionData>);
|
||||||
impl Extension {
|
impl Extension {
|
||||||
pub fn new(init: ExtInit, logger: Logger, msg_logger: Logger, ctx: Ctx) -> io::Result<Self> {
|
pub fn new(init: ExtInit, logger: Logger, msg_logger: Logger, ctx: Ctx) -> io::Result<Self> {
|
||||||
Ok(Self(Rc::new_cyclic(|weak: &Weak<ExtensionData>| ExtensionData {
|
Ok(Self(Rc::new_cyclic(|weak: &Weak<ExtensionData>| {
|
||||||
exprs: ExprStore::default(),
|
let init = Rc::new(init);
|
||||||
ctx: ctx.clone(),
|
(ctx.spawn)(clone!(init, weak, ctx; Box::pin(async move {
|
||||||
systems: (init.systems.iter().cloned())
|
let reqnot_opt = weak.upgrade().map(|rc| rc.reqnot.clone());
|
||||||
.map(|decl| SystemCtor { decl, ext: WeakExtension(weak.clone()) })
|
if let Some(reqnot) = reqnot_opt {
|
||||||
.collect(),
|
let mut repeat = true;
|
||||||
logger: logger.clone(),
|
while repeat {
|
||||||
init,
|
repeat = false;
|
||||||
next_pars: RefCell::new(NonZeroU64::new(1).unwrap()),
|
(init.recv(Box::new(|msg| {
|
||||||
lex_recur: Mutex::default(),
|
repeat = true;
|
||||||
mac_recur: Mutex::default(),
|
Box::pin(clone!(reqnot, ctx; async move {
|
||||||
reqnot: ReqNot::new(
|
let msg = msg.to_vec();
|
||||||
msg_logger,
|
let reqnot = reqnot.clone();
|
||||||
clone!(weak; move |sfn, _| clone!(weak; async move {
|
(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();
|
let data = weak.upgrade().unwrap();
|
||||||
data.init.send(sfn).await
|
data.init.send(sfn).await
|
||||||
}.boxed_local())),
|
}.boxed_local())),
|
||||||
clone!(weak; move |notif, _| {
|
clone!(weak; move |notif, _| {
|
||||||
clone!(weak; Box::pin(async move {
|
clone!(weak; Box::pin(async move {
|
||||||
let this = Extension(weak.upgrade().unwrap());
|
let this = Extension(weak.upgrade().unwrap());
|
||||||
match notif {
|
match notif {
|
||||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Acquire(acq)) => {
|
api::ExtHostNotif::ExprNotif(api::ExprNotif::Acquire(acq)) => {
|
||||||
let target = this.0.exprs.get_expr(acq.1).expect("Invalid ticket");
|
let target = this.0.exprs.get_expr(acq.1).expect("Invalid ticket");
|
||||||
this.0.exprs.give_expr(target)
|
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
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
})
|
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 }
|
pub(crate) fn reqnot(&self) -> &ReqNot<HostMsgSet> { &self.0.reqnot }
|
||||||
@@ -212,20 +238,6 @@ impl Extension {
|
|||||||
.await;
|
.await;
|
||||||
ret.transpose()
|
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) {
|
pub fn system_drop(&self, id: api::SysId) {
|
||||||
let rc = self.clone();
|
let rc = self.clone();
|
||||||
(self.ctx().spawn)(Box::pin(async move {
|
(self.ctx().spawn)(Box::pin(async move {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
use async_process::{self, Child, ChildStdin, ChildStdout};
|
use async_process::{self, Child, ChildStdin, ChildStdout};
|
||||||
use async_std::io::{self, BufReadExt, BufReader};
|
use async_std::io::{self, BufReadExt, BufReader};
|
||||||
@@ -22,8 +20,6 @@ pub async fn ext_command(
|
|||||||
msg_logs: Logger,
|
msg_logs: Logger,
|
||||||
ctx: Ctx,
|
ctx: Ctx,
|
||||||
) -> io::Result<ExtInit> {
|
) -> 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)
|
let mut child = async_process::Command::from(cmd)
|
||||||
.stdin(async_process::Stdio::piped())
|
.stdin(async_process::Stdio::piped())
|
||||||
.stdout(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 mut stdout = child.stdout.take().unwrap();
|
||||||
let header = api::ExtensionHeader::decode(Pin::new(&mut stdout)).await;
|
let header = api::ExtensionHeader::decode(Pin::new(&mut stdout)).await;
|
||||||
let child_stderr = child.stderr.take().unwrap();
|
let child_stderr = child.stderr.take().unwrap();
|
||||||
thread::Builder::new().name(format!("stderr-fwd:{prog}")).spawn(move || {
|
(ctx.spawn)(Box::pin(async move {
|
||||||
async_std::task::block_on(async move {
|
let mut reader = BufReader::new(child_stderr);
|
||||||
let mut reader = BufReader::new(child_stderr);
|
loop {
|
||||||
loop {
|
let mut buf = String::new();
|
||||||
let mut buf = String::new();
|
if 0 == reader.read_line(&mut buf).await.unwrap() {
|
||||||
if 0 == reader.read_line(&mut buf).await.unwrap() {
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
logger.log(buf.strip_suffix('\n').expect("Readline implies this"));
|
|
||||||
}
|
}
|
||||||
})
|
logger.log(buf.strip_suffix('\n').expect("Readline implies this"));
|
||||||
})?;
|
}
|
||||||
|
}));
|
||||||
Ok(ExtInit {
|
Ok(ExtInit {
|
||||||
header,
|
header,
|
||||||
port: Box::new(Subprocess {
|
port: Box::new(Subprocess {
|
||||||
@@ -87,6 +81,7 @@ impl ExtPort for Subprocess {
|
|||||||
match recv_msg(self.stdout.lock().await.as_mut()).await {
|
match recv_msg(self.stdout.lock().await.as_mut()).await {
|
||||||
Ok(msg) => cb(&msg).await,
|
Ok(msg) => cb(&msg).await,
|
||||||
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => (),
|
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()),
|
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-base = { version = "0.1.0", path = "../orchid-base" }
|
||||||
orchid-extension = { version = "0.1.0", path = "../orchid-extension" }
|
orchid-extension = { version = "0.1.0", path = "../orchid-extension" }
|
||||||
ordered-float = "4.6.0"
|
ordered-float = "4.6.0"
|
||||||
|
rust_decimal = "1.36.0"
|
||||||
tokio = { version = "1.43.0", features = ["full"] }
|
tokio = { version = "1.43.0", features = ["full"] }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use orchid_api_derive::Coding;
|
use orchid_api_derive::Coding;
|
||||||
use orchid_base::error::OrcRes;
|
use orchid_base::error::OrcRes;
|
||||||
use orchid_base::format::FmtUnit;
|
use orchid_base::format::FmtUnit;
|
||||||
|
use orchid_base::number::Numeric;
|
||||||
use orchid_extension::atom::{
|
use orchid_extension::atom::{
|
||||||
AtomFactory, Atomic, AtomicFeatures, MethodSetBuilder, ToAtom, TypAtom,
|
AtomFactory, Atomic, AtomicFeatures, MethodSetBuilder, ToAtom, TypAtom,
|
||||||
};
|
};
|
||||||
@@ -9,6 +10,7 @@ use orchid_extension::conv::TryFromExpr;
|
|||||||
use orchid_extension::expr::Expr;
|
use orchid_extension::expr::Expr;
|
||||||
use orchid_extension::system::SysCtx;
|
use orchid_extension::system::SysCtx;
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
|
use rust_decimal::prelude::Zero;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding)]
|
#[derive(Clone, Debug, Coding)]
|
||||||
pub struct Int(pub i64);
|
pub struct Int(pub i64);
|
||||||
@@ -38,27 +40,56 @@ impl ThinAtom for Float {
|
|||||||
}
|
}
|
||||||
impl TryFromExpr for Float {
|
impl TryFromExpr for Float {
|
||||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
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 {
|
pub struct Num(pub Numeric);
|
||||||
Int(i64),
|
impl TryFromExpr for Num {
|
||||||
Float(NotNan<f64>),
|
|
||||||
}
|
|
||||||
impl TryFromExpr for Numeric {
|
|
||||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||||
match Int::try_from_expr(expr.clone()).await {
|
let e = match Int::try_from_expr(expr.clone()).await {
|
||||||
Ok(t) => Ok(Numeric::Int(t.0)),
|
Ok(t) => return Ok(Num(Numeric::Int(t.0))),
|
||||||
Err(e) => Float::try_from_expr(expr).await.map(|t| Numeric::Float(t.0)).map_err(|e2| e + e2),
|
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 {
|
fn to_atom_factory(self) -> AtomFactory {
|
||||||
match self {
|
match self.0 {
|
||||||
Self::Float(f) => Float(f).factory(),
|
Numeric::Float(f) => Float(f).factory(),
|
||||||
Self::Int(i) => Int(i).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 std::ops::RangeInclusive;
|
||||||
|
|
||||||
use orchid_base::error::OrcRes;
|
use orchid_base::error::OrcRes;
|
||||||
use orchid_base::number::{Numeric, num_to_err, parse_num};
|
use orchid_base::number::{num_to_err, parse_num};
|
||||||
use orchid_extension::atom::AtomicFeatures;
|
use orchid_extension::atom::ToAtom;
|
||||||
use orchid_extension::lexer::{LexContext, Lexer};
|
use orchid_extension::lexer::{LexContext, Lexer};
|
||||||
use orchid_extension::tree::{GenTok, GenTokTree};
|
use orchid_extension::tree::{GenTok, GenTokTree};
|
||||||
use ordered_float::NotNan;
|
|
||||||
|
|
||||||
use super::num_atom::{Float, Int};
|
use super::num_atom::Num;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct NumLexer;
|
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 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 (chars, tail) = all.split_at(ends_at.unwrap_or(all.len()));
|
||||||
let fac = match parse_num(chars) {
|
let fac = match parse_num(chars) {
|
||||||
Ok(Numeric::Float(f)) => Float(f).factory(),
|
Ok(numeric) => Num(numeric).to_atom_factory(),
|
||||||
Ok(Numeric::Uint(uint)) => Int(uint.try_into().unwrap()).factory(),
|
|
||||||
Ok(Numeric::Decimal(dec)) => Float(NotNan::new(dec.try_into().unwrap()).unwrap()).factory(),
|
|
||||||
Err(e) => return Err(num_to_err(e, ctx.pos(all), ctx.i).await.into()),
|
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))))
|
Ok((tail, GenTok::X(fac).at(ctx.pos(all)..ctx.pos(tail))))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use never::Never;
|
use never::Never;
|
||||||
|
use orchid_base::number::Numeric;
|
||||||
use orchid_base::reqnot::Receipt;
|
use orchid_base::reqnot::Receipt;
|
||||||
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
|
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
|
||||||
use orchid_extension::entrypoint::ExtReq;
|
use orchid_extension::entrypoint::ExtReq;
|
||||||
@@ -8,9 +9,10 @@ use orchid_extension::fs::DeclFs;
|
|||||||
use orchid_extension::system::{System, SystemCard};
|
use orchid_extension::system::{System, SystemCard};
|
||||||
use orchid_extension::system_ctor::SystemCtor;
|
use orchid_extension::system_ctor::SystemCtor;
|
||||||
use orchid_extension::tree::{MemKind, comments, fun, module, root_mod};
|
use orchid_extension::tree::{MemKind, comments, fun, module, root_mod};
|
||||||
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
use crate::OrcString;
|
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::number::num_lexer::NumLexer;
|
||||||
use crate::string::str_atom::{IntStrAtom, StrAtom};
|
use crate::string::str_atom::{IntStrAtom, StrAtom};
|
||||||
use crate::string::str_lexer::StringLexer;
|
use crate::string::str_lexer::StringLexer;
|
||||||
@@ -37,11 +39,39 @@ impl System for StdSystem {
|
|||||||
fn parsers() -> Vec<orchid_extension::parser::ParserObj> { vec![] }
|
fn parsers() -> Vec<orchid_extension::parser::ParserObj> { vec![] }
|
||||||
fn vfs() -> DeclFs { DeclFs::Mod(&[]) }
|
fn vfs() -> DeclFs { DeclFs::Mod(&[]) }
|
||||||
fn env() -> Vec<(String, MemKind)> {
|
fn env() -> Vec<(String, MemKind)> {
|
||||||
vec![root_mod("std", [], [module(true, "string", [], [comments(
|
vec![root_mod("std", [], [
|
||||||
["Concatenate two strings"],
|
module(true, "string", [], [comments(
|
||||||
fun(true, "concat", |left: OrcString<'static>, right: OrcString<'static>| async move {
|
["Concatenate two strings"],
|
||||||
StrAtom::new(Rc::new(left.get_string().await.to_string() + &right.get_string().await))
|
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 {
|
async fn deserialize(mut ctx: impl DeserializeCtx, _: ()) -> Self {
|
||||||
let s = ctx.decode::<String>().await;
|
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<'_> {
|
impl OrcString<'_> {
|
||||||
pub async fn get_string(&self) -> Rc<String> {
|
pub async fn get_string(&self) -> Rc<String> {
|
||||||
match &self.kind {
|
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,
|
OrcStringKind::Val(atom) => atom.request(StringGetVal).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ impl TryFromExpr for OrcString<'static> {
|
|||||||
let ctx = expr.ctx();
|
let ctx = expr.ctx();
|
||||||
match TypAtom::<IntStrAtom>::try_from_expr(expr).await {
|
match TypAtom::<IntStrAtom>::try_from_expr(expr).await {
|
||||||
Ok(t) => Ok(OrcString { ctx: t.data.ctx(), kind: OrcStringKind::Int(t) }),
|
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 camino::Utf8PathBuf;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use futures::{Stream, TryStreamExt, io};
|
use futures::{Stream, TryStreamExt, io};
|
||||||
use orchid_base::clone;
|
|
||||||
use orchid_base::error::ReporterImpl;
|
use orchid_base::error::ReporterImpl;
|
||||||
use orchid_base::format::{FmtCtxImpl, Format, take_first};
|
use orchid_base::format::{FmtCtxImpl, Format, take_first};
|
||||||
use orchid_base::location::Pos;
|
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
|
let init = ext_command(Command::new(exe.as_os_str()), logger.clone(), msg_logger.clone(), ctx.clone()).await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let ext = Extension::new(init, logger.clone(), msg_logger.clone(), ctx.clone())?;
|
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
|
yield ext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,12 +166,8 @@ async fn main() -> io::Result<ExitCode> {
|
|||||||
if args.verbose {
|
if args.verbose {
|
||||||
println!("lexed: {}", take_first(&ttv_fmt(&lexemes, &FmtCtxImpl { i }).await, true));
|
println!("lexed: {}", take_first(&ttv_fmt(&lexemes, &FmtCtxImpl { i }).await, true));
|
||||||
}
|
}
|
||||||
let mtreev = parse_mtree(
|
let mtreev =
|
||||||
Snippet::new(&lexemes[0], &lexemes, i),
|
parse_mtree(Snippet::new(&lexemes[0], &lexemes, i), Substack::Bottom).await.unwrap();
|
||||||
Substack::Bottom.push(i.i("orcx").await).push(i.i("input").await),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
if args.verbose {
|
if args.verbose {
|
||||||
let fmt = mtreev_fmt(&mtreev, &FmtCtxImpl { i }).await;
|
let fmt = mtreev_fmt(&mtreev, &FmtCtxImpl { i }).await;
|
||||||
println!("parsed: {}", take_first(&fmt, true));
|
println!("parsed: {}", take_first(&fmt, true));
|
||||||
|
|||||||
Reference in New Issue
Block a user