Initial extension asynchronization efforts.
This commit is contained in:
18
SWAP.md
18
SWAP.md
@@ -1,11 +1,8 @@
|
||||
Must figure out how preprocessor can both be a System and referenced in the interpreter
|
||||
## Async conversion
|
||||
|
||||
Must actually write macro system as recorded in note
|
||||
|
||||
At this point swappable preprocessors aren't a target because interaction with module system sounds complicated
|
||||
|
||||
Check if any of this needs interpreter, if so, start with that
|
||||
convert host to async non-send
|
||||
|
||||
convert extension's SysCtx to a typed context bag
|
||||
|
||||
## alternate extension mechanism
|
||||
|
||||
@@ -15,3 +12,12 @@ Ideally, it should reuse `orchid-extension` for message routing and decoding.
|
||||
|
||||
`orchid-host` accepts extensions as `impl ExtensionPort`
|
||||
|
||||
## Preprocessor extension
|
||||
|
||||
Must figure out how preprocessor can both be a System and referenced in the interpreter
|
||||
|
||||
Must actually write macro system as recorded in note
|
||||
|
||||
At this point swappable preprocessors aren't a target because interaction with module system sounds complicated
|
||||
|
||||
Check if any of this needs interpreter, if so, start with that
|
||||
@@ -23,7 +23,7 @@ pub enum IntReq {
|
||||
/// See [IntReq]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||
#[extends(IntReq, ExtHostReq)]
|
||||
pub struct InternStr(pub Arc<String>);
|
||||
pub struct InternStr(pub String);
|
||||
impl Request for InternStr {
|
||||
type Response = TStr;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ impl Request for InternStr {
|
||||
#[extends(IntReq, ExtHostReq)]
|
||||
pub struct ExternStr(pub TStr);
|
||||
impl Request for ExternStr {
|
||||
type Response = Arc<String>;
|
||||
type Response = String;
|
||||
}
|
||||
/// replica -> master to intern a vector of interned strings
|
||||
///
|
||||
@@ -46,7 +46,7 @@ impl Request for ExternStr {
|
||||
/// See [IntReq]
|
||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||
#[extends(IntReq, ExtHostReq)]
|
||||
pub struct InternStrv(pub Arc<Vec<TStr>>);
|
||||
pub struct InternStrv(pub Vec<TStr>);
|
||||
impl Request for InternStrv {
|
||||
type Response = TStrv;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ impl Request for InternStrv {
|
||||
#[extends(IntReq, ExtHostReq)]
|
||||
pub struct ExternStrv(pub TStrv);
|
||||
impl Request for ExternStrv {
|
||||
type Response = Arc<Vec<TStr>>;
|
||||
type Response = Vec<TStr>;
|
||||
}
|
||||
|
||||
/// A substitute for an interned string in serialized datastructures.
|
||||
|
||||
@@ -6,4 +6,7 @@ macro_rules! clone {
|
||||
$body
|
||||
}
|
||||
);
|
||||
($($n:ident),+) => {
|
||||
$( let $n = $n.clone(); )+
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use futures::future::join_all;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::api;
|
||||
use crate::interner::Tok;
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::location::Pos;
|
||||
|
||||
/// A point of interest in resolving the error, such as the point where
|
||||
@@ -22,10 +22,10 @@ impl ErrPos {
|
||||
pub fn new(msg: &str, position: Pos) -> Self {
|
||||
Self { message: Some(Arc::new(msg.to_string())), position }
|
||||
}
|
||||
async fn from_api(api: &api::ErrLocation) -> Self {
|
||||
async fn from_api(api: &api::ErrLocation, i: &Interner) -> Self {
|
||||
Self {
|
||||
message: Some(api.message.clone()).filter(|s| !s.is_empty()),
|
||||
position: Pos::from_api(&api.location).await,
|
||||
position: Pos::from_api(&api.location, i).await,
|
||||
}
|
||||
}
|
||||
fn to_api(&self) -> api::ErrLocation {
|
||||
@@ -53,11 +53,11 @@ impl OrcErr {
|
||||
locations: self.positions.iter().map(ErrPos::to_api).collect(),
|
||||
}
|
||||
}
|
||||
async fn from_api(api: &api::OrcError) -> Self {
|
||||
async fn from_api(api: &api::OrcError, i: &Interner) -> Self {
|
||||
Self {
|
||||
description: Tok::from_api(api.description).await,
|
||||
description: Tok::from_api(api.description, i).await,
|
||||
message: api.message.clone(),
|
||||
positions: join_all(api.locations.iter().map(ErrPos::from_api)).await,
|
||||
positions: join_all(api.locations.iter().map(|e| ErrPos::from_api(e, i))).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,8 +113,11 @@ impl OrcErrv {
|
||||
self.0.iter().flat_map(|e| e.positions.iter().cloned())
|
||||
}
|
||||
pub fn to_api(&self) -> Vec<api::OrcError> { self.0.iter().map(OrcErr::to_api).collect() }
|
||||
pub async fn from_api<'a>(api: impl IntoIterator<Item = &'a api::OrcError>) -> Self {
|
||||
Self(join_all(api.into_iter().map(OrcErr::from_api)).await)
|
||||
pub async fn from_api<'a>(
|
||||
api: impl IntoIterator<Item = &'a api::OrcError>,
|
||||
i: &Interner,
|
||||
) -> Self {
|
||||
Self(join_all(api.into_iter().map(|e| OrcErr::from_api(e, i))).await)
|
||||
}
|
||||
}
|
||||
impl From<OrcErr> for OrcErrv {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use std::borrow::Borrow;
|
||||
use std::future::Future;
|
||||
use std::hash::BuildHasher as _;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroU64;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex, MutexGuard, atomic};
|
||||
use std::{fmt, hash, mem};
|
||||
use std::sync::atomic;
|
||||
use std::{fmt, hash};
|
||||
|
||||
use async_once_cell::Lazy;
|
||||
use async_std::sync::Mutex;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use itertools::Itertools as _;
|
||||
use orchid_api_traits::Request;
|
||||
@@ -29,9 +28,9 @@ pub struct Tok<T: Interned> {
|
||||
impl<T: Interned> Tok<T> {
|
||||
pub fn new(data: Rc<T>, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } }
|
||||
pub fn to_api(&self) -> T::Marker { self.marker.0 }
|
||||
pub async fn from_api<M>(marker: M, i: &mut Interner) -> Self
|
||||
pub async fn from_api<M>(marker: M, i: &Interner) -> Self
|
||||
where M: InternMarker<Interned = T> {
|
||||
i.deintern(marker).await
|
||||
i.ex(marker).await
|
||||
}
|
||||
pub fn rc(&self) -> Rc<T> { self.data.clone() }
|
||||
}
|
||||
@@ -67,7 +66,7 @@ impl<T: Interned + fmt::Debug> fmt::Debug for Tok<T> {
|
||||
pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug + Internable<Interned = Self> {
|
||||
type Marker: InternMarker<Interned = Self> + Sized;
|
||||
fn intern(
|
||||
self: Arc<Self>,
|
||||
self: Rc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> impl Future<Output = Self::Marker>;
|
||||
fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
|
||||
@@ -75,15 +74,13 @@ pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug + Internable<Interned =
|
||||
|
||||
pub trait Internable: fmt::Debug {
|
||||
type Interned: Interned;
|
||||
fn get_owned(&self) -> Arc<Self::Interned>;
|
||||
fn get_owned(&self) -> Rc<Self::Interned>;
|
||||
}
|
||||
|
||||
pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash + Sized {
|
||||
type Interned: Interned<Marker = Self>;
|
||||
fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> impl Future<Output = Tok<Self::Interned>>;
|
||||
/// Only called on replicas
|
||||
fn resolve(self, i: &Interner) -> impl Future<Output = Tok<Self::Interned>>;
|
||||
fn get_id(self) -> NonZeroU64;
|
||||
fn from_id(id: NonZeroU64) -> Self;
|
||||
}
|
||||
@@ -91,63 +88,61 @@ pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash +
|
||||
impl Interned for String {
|
||||
type Marker = api::TStr;
|
||||
async fn intern(
|
||||
self: Arc<Self>,
|
||||
self: Rc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker {
|
||||
req.request(api::InternStr(self)).await
|
||||
req.request(api::InternStr(self.to_string())).await
|
||||
}
|
||||
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.strings }
|
||||
}
|
||||
impl InternMarker for api::TStr {
|
||||
type Interned = String;
|
||||
async fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned> {
|
||||
Tok::new(req.request(api::ExternStr(self)).await, self)
|
||||
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
||||
Tok::new(Rc::new(i.master.as_ref().unwrap().request(api::ExternStr(self)).await), self)
|
||||
}
|
||||
fn get_id(self) -> NonZeroU64 { self.0 }
|
||||
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||
}
|
||||
impl Internable for str {
|
||||
type Interned = String;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
|
||||
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_string()) }
|
||||
}
|
||||
impl Internable for String {
|
||||
type Interned = String;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_string()) }
|
||||
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_string()) }
|
||||
}
|
||||
|
||||
impl Interned for Vec<Tok<String>> {
|
||||
type Marker = api::TStrv;
|
||||
async fn intern(
|
||||
self: Arc<Self>,
|
||||
self: Rc<Self>,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Self::Marker {
|
||||
req.request(api::InternStrv(Arc::new(self.iter().map(|t| t.to_api()).collect()))).await
|
||||
req.request(api::InternStrv(self.iter().map(|t| t.to_api()).collect())).await
|
||||
}
|
||||
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.vecs }
|
||||
}
|
||||
impl InternMarker for api::TStrv {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
async fn resolve(
|
||||
self,
|
||||
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||
) -> Tok<Self::Interned> {
|
||||
let rep = req.request(api::ExternStrv(self)).await;
|
||||
let data = futures::future::join_all(rep.iter().map(|m| deintern(*m))).await;
|
||||
Tok::new(Arc::new(data), self)
|
||||
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
||||
let rep = i.master.as_ref().unwrap().request(api::ExternStrv(self)).await;
|
||||
let data = futures::future::join_all(rep.into_iter().map(|m| i.ex(m))).await;
|
||||
Tok::new(Rc::new(data), self)
|
||||
}
|
||||
fn get_id(self) -> NonZeroU64 { self.0 }
|
||||
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||
}
|
||||
impl Internable for [Tok<String>] {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_vec()) }
|
||||
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
||||
}
|
||||
impl<const N: usize> Internable for [Tok<String>; N] {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
||||
}
|
||||
impl Internable for Vec<Tok<String>> {
|
||||
type Interned = Vec<Tok<String>>;
|
||||
fn get_owned(&self) -> Arc<Self::Interned> { Arc::new(self.to_vec()) }
|
||||
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
||||
}
|
||||
// impl Internable for Vec<api::TStr> {
|
||||
// type Interned = Vec<Tok<String>>;
|
||||
@@ -167,14 +162,14 @@ const BASE_RC: usize = 3;
|
||||
|
||||
#[test]
|
||||
fn base_rc_correct() {
|
||||
let tok = Tok::new(Arc::new("foo".to_string()), api::TStr(1.try_into().unwrap()));
|
||||
let tok = Tok::new(Rc::new("foo".to_string()), api::TStr(1.try_into().unwrap()));
|
||||
let mut bimap = Bimap::default();
|
||||
bimap.insert(tok.clone());
|
||||
assert_eq!(Arc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the current instance");
|
||||
assert_eq!(Rc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the current instance");
|
||||
}
|
||||
|
||||
pub struct Bimap<T: Interned> {
|
||||
intern: HashMap<Arc<T>, Tok<T>>,
|
||||
intern: HashMap<Rc<T>, Tok<T>>,
|
||||
by_id: HashMap<T::Marker, Tok<T>>,
|
||||
}
|
||||
impl<T: Interned> Bimap<T> {
|
||||
@@ -194,7 +189,7 @@ impl<T: Interned> Bimap<T> {
|
||||
|
||||
pub fn sweep_replica(&mut self) -> Vec<T::Marker> {
|
||||
(self.intern)
|
||||
.extract_if(|k, _| Arc::strong_count(k) == BASE_RC)
|
||||
.extract_if(|k, _| Rc::strong_count(k) == BASE_RC)
|
||||
.map(|(_, v)| {
|
||||
self.by_id.remove(&v.to_api());
|
||||
v.to_api()
|
||||
@@ -203,7 +198,7 @@ impl<T: Interned> Bimap<T> {
|
||||
}
|
||||
|
||||
pub fn sweep_master(&mut self, retained: HashSet<T::Marker>) {
|
||||
self.intern.retain(|k, v| BASE_RC < Arc::strong_count(k) || retained.contains(&v.to_api()))
|
||||
self.intern.retain(|k, v| BASE_RC < Rc::strong_count(k) || retained.contains(&v.to_api()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,58 +218,59 @@ pub struct TypedInterners {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Interner {
|
||||
interners: TypedInterners,
|
||||
interners: Mutex<TypedInterners>,
|
||||
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
|
||||
}
|
||||
impl Interner {
|
||||
pub fn new_master() -> Self { Self::default() }
|
||||
pub fn new_replica(req: impl DynRequester<Transfer = api::IntReq> + 'static) -> Self {
|
||||
Self {
|
||||
master: Some(Box::new(req)),
|
||||
interners: TypedInterners { strings: Bimap::default(), vecs: Bimap::default() },
|
||||
}
|
||||
Self { master: Some(Box::new(req)), interners: Mutex::default() }
|
||||
}
|
||||
pub async fn intern<T: Interned>(
|
||||
&mut self,
|
||||
t: &(impl Internable<Interned = T> + ?Sized),
|
||||
) -> Tok<T> {
|
||||
/// Intern some data; query its identifier if not known locally
|
||||
pub async fn i<T: Interned>(&self, t: &(impl Internable<Interned = T> + ?Sized)) -> Tok<T> {
|
||||
let data = t.get_owned();
|
||||
let job = format!("{t:?} in {}", if self.master.is_some() { "replica" } else { "master" });
|
||||
eprintln!("Interning {job}");
|
||||
let typed = T::bimap(&mut self.interners);
|
||||
let mut g = self.interners.lock().await;
|
||||
let typed = T::bimap(&mut g);
|
||||
if let Some(tok) = typed.by_value(&data) {
|
||||
return tok;
|
||||
}
|
||||
let marker = match &mut self.master {
|
||||
let marker = match &self.master {
|
||||
Some(c) => data.clone().intern(&**c).await,
|
||||
None =>
|
||||
T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()),
|
||||
};
|
||||
let tok = Tok::new(data, marker);
|
||||
T::bimap(&mut self.interners).insert(tok.clone());
|
||||
T::bimap(&mut g).insert(tok.clone());
|
||||
eprintln!("Interned {job}");
|
||||
tok
|
||||
}
|
||||
async fn deintern<M: InternMarker>(&mut self, marker: M) -> Tok<M::Interned> {
|
||||
if let Some(tok) = M::Interned::bimap(&mut self.interners).by_marker(marker) {
|
||||
/// Extern an identifier; query the data it represents if not known locally
|
||||
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) {
|
||||
return tok;
|
||||
}
|
||||
let master = self.master.as_mut().expect("ID not in local interner and this is master");
|
||||
let token = marker.resolve(&**master).await;
|
||||
M::Interned::bimap(&mut self.interners).insert(token.clone());
|
||||
assert!(self.master.is_some(), "ID not in local interner and this is master");
|
||||
let token = marker.resolve(self).await;
|
||||
M::Interned::bimap(&mut *self.interners.lock().await).insert(token.clone());
|
||||
token
|
||||
}
|
||||
pub fn sweep_replica(&mut self) -> api::Retained {
|
||||
pub async fn sweep_replica(&self) -> api::Retained {
|
||||
assert!(self.master.is_some(), "Not a replica");
|
||||
api::Retained {
|
||||
strings: self.interners.strings.sweep_replica(),
|
||||
vecs: self.interners.vecs.sweep_replica(),
|
||||
}
|
||||
let mut g = self.interners.lock().await;
|
||||
api::Retained { strings: g.strings.sweep_replica(), vecs: g.vecs.sweep_replica() }
|
||||
}
|
||||
pub fn sweep_master(&mut self, retained: api::Retained) {
|
||||
pub async fn sweep_master(&self, retained: api::Retained) {
|
||||
assert!(self.master.is_none(), "Not master");
|
||||
self.interners.strings.sweep_master(retained.strings.into_iter().collect());
|
||||
self.interners.vecs.sweep_master(retained.vecs.into_iter().collect());
|
||||
let mut g = self.interners.lock().await;
|
||||
g.strings.sweep_master(retained.strings.into_iter().collect());
|
||||
g.vecs.sweep_master(retained.vecs.into_iter().collect());
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for Interner {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Interner{{ replica: {} }}", self.master.is_none())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,11 +293,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_i() {
|
||||
let _: Tok<String> = spin_on(intern!(str: "foo"));
|
||||
let _: Tok<Vec<Tok<String>>> = spin_on(intern!([Tok<String>]: &[
|
||||
spin_on(intern!(str: "bar")),
|
||||
spin_on(intern!(str: "baz"))
|
||||
]));
|
||||
let i = Interner::new_master();
|
||||
let _: Tok<String> = spin_on(i.i("foo"));
|
||||
let _: Tok<Vec<Tok<String>>> = spin_on(i.i(&[spin_on(i.i("bar")), spin_on(i.i("baz"))]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -6,9 +6,9 @@ use std::ops::Range;
|
||||
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::interner::{Tok, intern};
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::name::Sym;
|
||||
use crate::{api, intern, match_mapping, sym};
|
||||
use crate::{api, match_mapping, sym};
|
||||
|
||||
trait_set! {
|
||||
pub trait GetSrc = FnMut(&Sym) -> Tok<String>;
|
||||
@@ -36,12 +36,12 @@ impl Pos {
|
||||
other => format!("{other:?}"),
|
||||
}
|
||||
}
|
||||
pub async fn from_api(api: &api::Location) -> Self {
|
||||
pub async fn from_api(api: &api::Location, i: &Interner) -> Self {
|
||||
match_mapping!(api, api::Location => Pos {
|
||||
None, Inherit, SlotTarget,
|
||||
Range(r.clone()),
|
||||
Gen(cgi => CodeGenInfo::from_api(cgi).await),
|
||||
SourceRange(sr => SourceRange::from_api(sr).await)
|
||||
Gen(cgi => CodeGenInfo::from_api(cgi, i).await),
|
||||
SourceRange(sr => SourceRange::from_api(sr, i).await)
|
||||
})
|
||||
}
|
||||
pub fn to_api(&self) -> api::Location {
|
||||
@@ -67,7 +67,7 @@ impl SourceRange {
|
||||
}
|
||||
/// Create a dud [SourceRange] for testing. Its value is unspecified and
|
||||
/// volatile.
|
||||
pub async fn mock() -> Self { Self { range: 0..1, path: sym!(test).await } }
|
||||
pub async fn mock(i: &Interner) -> Self { Self { range: 0..1, path: sym!(test; i).await } }
|
||||
/// Path the source text was loaded from
|
||||
pub fn path(&self) -> Sym { self.path.clone() }
|
||||
/// Byte range
|
||||
@@ -92,8 +92,8 @@ impl SourceRange {
|
||||
}
|
||||
}
|
||||
pub fn zw(path: Sym, pos: u32) -> Self { Self { path, range: pos..pos } }
|
||||
async fn from_api(api: &api::SourceRange) -> Self {
|
||||
Self { path: Sym::from_api(api.path).await, range: api.range.clone() }
|
||||
async fn from_api(api: &api::SourceRange, i: &Interner) -> Self {
|
||||
Self { path: Sym::from_api(api.path, i).await, range: api.range.clone() }
|
||||
}
|
||||
fn to_api(&self) -> api::SourceRange {
|
||||
api::SourceRange { path: self.path.to_api(), range: self.range.clone() }
|
||||
@@ -110,19 +110,19 @@ pub struct CodeGenInfo {
|
||||
}
|
||||
impl CodeGenInfo {
|
||||
/// A codegen marker with no user message and parameters
|
||||
pub async fn new_short(generator: Sym) -> Self {
|
||||
Self { generator, details: intern!(str: "").await }
|
||||
pub async fn new_short(generator: Sym, i: &Interner) -> Self {
|
||||
Self { generator, details: i.i("").await }
|
||||
}
|
||||
/// A codegen marker with a user message or parameters
|
||||
pub async fn new_details(generator: Sym, details: impl AsRef<str>) -> Self {
|
||||
Self { generator, details: intern(details.as_ref()).await }
|
||||
pub async fn new_details(generator: Sym, details: impl AsRef<str>, i: &Interner) -> Self {
|
||||
Self { generator, details: i.i(details.as_ref()).await }
|
||||
}
|
||||
/// Syntactic location
|
||||
pub fn pos(&self) -> Pos { Pos::Gen(self.clone()) }
|
||||
pub async fn from_api(api: &api::CodeGenInfo) -> Self {
|
||||
pub async fn from_api(api: &api::CodeGenInfo, i: &Interner) -> Self {
|
||||
Self {
|
||||
generator: Sym::from_api(api.generator).await,
|
||||
details: Tok::from_api(api.details).await,
|
||||
generator: Sym::from_api(api.generator, i).await,
|
||||
details: Tok::from_api(api.details, i).await,
|
||||
}
|
||||
}
|
||||
pub fn to_api(&self) -> api::CodeGenInfo {
|
||||
|
||||
@@ -3,11 +3,12 @@ use std::sync::Arc;
|
||||
|
||||
use async_std::stream;
|
||||
use async_std::sync::Mutex;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::interner::Interner;
|
||||
use crate::location::Pos;
|
||||
use crate::name::Sym;
|
||||
use crate::tree::{Paren, Ph};
|
||||
@@ -20,7 +21,7 @@ impl MacroSlot<'_> {
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
pub trait MacroAtomToApi<A> = FnMut(&A) -> api::MacroToken;
|
||||
pub trait MacroAtomToApi<A> = for<'a> FnMut(&'a A) -> LocalBoxFuture<'a, api::MacroToken>;
|
||||
pub trait MacroAtomFromApi<'a, A> = FnMut(&api::Atom) -> MTok<'a, A>;
|
||||
}
|
||||
|
||||
@@ -33,14 +34,18 @@ impl<'a, A> MTree<'a, A> {
|
||||
pub(crate) async fn from_api(
|
||||
api: &api::MacroTree,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
i: &Interner,
|
||||
) -> Self {
|
||||
Self {
|
||||
pos: Pos::from_api(&api.location).await,
|
||||
tok: Arc::new(MTok::from_api(&api.token, do_atom).await),
|
||||
pos: Pos::from_api(&api.location, i).await,
|
||||
tok: Arc::new(MTok::from_api(&api.token, do_atom, i).await),
|
||||
}
|
||||
}
|
||||
pub(crate) fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroTree {
|
||||
api::MacroTree { location: self.pos.to_api(), token: self.tok.to_api(do_atom) }
|
||||
pub(crate) async fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroTree {
|
||||
api::MacroTree {
|
||||
location: self.pos.to_api(),
|
||||
token: self.tok.to_api(do_atom).boxed_local().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,29 +67,30 @@ impl<'a, A> MTok<'a, A> {
|
||||
pub(crate) async fn from_api(
|
||||
api: &api::MacroToken,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
i: &Interner,
|
||||
) -> Self {
|
||||
match_mapping!(&api, api::MacroToken => MTok::<'a, A> {
|
||||
Lambda(x => mtreev_from_api(x, do_atom).await, b => mtreev_from_api(b, do_atom).await),
|
||||
Name(t => Sym::from_api(*t).await),
|
||||
Lambda(x => mtreev_from_api(x, do_atom, i).await, b => mtreev_from_api(b, do_atom, i).await),
|
||||
Name(t => Sym::from_api(*t, i).await),
|
||||
Slot(tk => MacroSlot(*tk, PhantomData)),
|
||||
S(p.clone(), b => mtreev_from_api(b, do_atom).await),
|
||||
Ph(ph => Ph::from_api(ph).await),
|
||||
S(p.clone(), b => mtreev_from_api(b, do_atom, i).await),
|
||||
Ph(ph => Ph::from_api(ph, i).await),
|
||||
} {
|
||||
api::MacroToken::Atom(a) => do_atom(a)
|
||||
})
|
||||
}
|
||||
pub(crate) fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroToken {
|
||||
fn sink(n: &Never) -> api::MacroToken { match *n {} }
|
||||
pub(crate) async fn to_api(&self, do_atom: &mut impl MacroAtomToApi<A>) -> api::MacroToken {
|
||||
fn sink<T>(n: &Never) -> LocalBoxFuture<'_, T> { match *n {} }
|
||||
match_mapping!(&self, MTok => api::MacroToken {
|
||||
Lambda(x => mtreev_to_api(x, do_atom), b => mtreev_to_api(b, do_atom)),
|
||||
Lambda(x => mtreev_to_api(x, do_atom).await, b => mtreev_to_api(b, do_atom).await),
|
||||
Name(t.tok().to_api()),
|
||||
Ph(ph.to_api()),
|
||||
S(p.clone(), b => mtreev_to_api(b, do_atom)),
|
||||
S(p.clone(), b => mtreev_to_api(b, do_atom).await),
|
||||
Slot(tk.0.clone()),
|
||||
} {
|
||||
MTok::Ref(r) => r.to_api(&mut sink),
|
||||
MTok::Done(t) => t.to_api(do_atom),
|
||||
MTok::Atom(a) => do_atom(a),
|
||||
MTok::Ref(r) => r.to_api(&mut sink).boxed_local().await,
|
||||
MTok::Done(t) => t.to_api(do_atom).boxed_local().await,
|
||||
MTok::Atom(a) => do_atom(a).await,
|
||||
})
|
||||
}
|
||||
pub fn at(self, pos: Pos) -> MTree<'a, A> { MTree { pos, tok: Arc::new(self) } }
|
||||
@@ -93,17 +99,24 @@ impl<'a, A> MTok<'a, A> {
|
||||
pub async fn mtreev_from_api<'a, 'b, A>(
|
||||
api: impl IntoIterator<Item = &'b api::MacroTree>,
|
||||
do_atom: &mut impl MacroAtomFromApi<'a, A>,
|
||||
i: &Interner,
|
||||
) -> Vec<MTree<'a, A>> {
|
||||
let do_atom_lk = Mutex::new(do_atom);
|
||||
stream::from_iter(api)
|
||||
.then(|api| async { MTree::from_api(api, &mut *do_atom_lk.lock().await).boxed_local().await })
|
||||
.then(|api| async {
|
||||
MTree::from_api(api, &mut *do_atom_lk.lock().await, i).boxed_local().await
|
||||
})
|
||||
.collect()
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn mtreev_to_api<'a: 'b, 'b, A: 'b>(
|
||||
pub async fn mtreev_to_api<'a: 'b, 'b, A: 'b>(
|
||||
v: impl IntoIterator<Item = &'b MTree<'a, A>>,
|
||||
do_atom: &mut impl MacroAtomToApi<A>,
|
||||
) -> Vec<api::MacroTree> {
|
||||
v.into_iter().map(|t| t.to_api(do_atom)).collect_vec()
|
||||
let mut out = Vec::new();
|
||||
for t in v {
|
||||
out.push(t.to_api(do_atom).await);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/// match_mapping!(self, ThisType => OtherType {
|
||||
/// EmptyVariant,
|
||||
/// TupleVariant(foo => intern(foo), bar.clone()),
|
||||
/// StructVariant{ a.to_api(), b => b.}
|
||||
/// StructVariant{ a.to_api(), b }
|
||||
/// })
|
||||
/// ```
|
||||
#[macro_export]
|
||||
@@ -69,6 +69,9 @@ macro_rules! match_mapping {
|
||||
$($prefix)::* :: $variant { $($names),* }
|
||||
};
|
||||
(@PAT_MUNCH $ctx:tt $names:tt $(,)? ) => { match_mapping!($ctx $names) };
|
||||
(@PAT_MUNCH $ctx:tt ($($names:ident)*) $name:ident , $($tail:tt)*) => {
|
||||
match_mapping!(@PAT_MUNCH $ctx ($($names)* $name) $($tail)*)
|
||||
};
|
||||
(@PAT_MUNCH $ctx:tt ($($names:ident)*) * $name:ident , $($tail:tt)*) => {
|
||||
match_mapping!(@PAT_MUNCH $ctx ($($names)* $name) $($tail)*)
|
||||
};
|
||||
@@ -94,6 +97,9 @@ macro_rules! match_mapping {
|
||||
(@VAL $prefix:tt { $($fields:tt)* }) => {
|
||||
match_mapping!(@VAL_MUNCH ({} $prefix) () $($fields)* , )
|
||||
};
|
||||
(@VAL_MUNCH $ctx:tt ($($prefix:tt)*) $name:ident , $($tail:tt)*) => {
|
||||
match_mapping!(@VAL_MUNCH $ctx ($($prefix)* ($name ($name)) ) $($tail)*)
|
||||
};
|
||||
(@VAL_MUNCH $ctx:tt ($($prefix:tt)*) * $name:ident , $($tail:tt)*) => {
|
||||
match_mapping!(@VAL_MUNCH $ctx ($($prefix)* ($name (* $name)) ) $($tail)*)
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ use itertools::Itertools;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::interner::{InternMarker, Tok, intern};
|
||||
use crate::interner::{InternMarker, Interner, Tok};
|
||||
|
||||
trait_set! {
|
||||
/// Traits that all name iterators should implement
|
||||
@@ -174,8 +174,8 @@ impl VPath {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Partition the string by `::` namespace separators
|
||||
pub async fn parse(s: &str) -> Self {
|
||||
Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(intern)).await })
|
||||
pub async fn parse(s: &str, i: &Interner) -> Self {
|
||||
Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(|s| i.i(s))).await })
|
||||
}
|
||||
/// Walk over the segments
|
||||
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
|
||||
@@ -195,14 +195,15 @@ impl VPath {
|
||||
}
|
||||
|
||||
/// Convert a fs path to a vpath
|
||||
pub async fn from_path(path: &Path, ext: &str) -> Option<(Self, bool)> {
|
||||
async fn to_vpath(p: &Path) -> Option<VPath> {
|
||||
let tok_opt_v = join_all(p.iter().map(|c| OptionFuture::from(c.to_str().map(intern)))).await;
|
||||
pub async fn from_path(path: &Path, ext: &str, i: &Interner) -> Option<(Self, bool)> {
|
||||
async fn to_vpath(p: &Path, i: &Interner) -> Option<VPath> {
|
||||
let tok_opt_v =
|
||||
join_all(p.iter().map(|c| OptionFuture::from(c.to_str().map(|s| i.i(s))))).await;
|
||||
tok_opt_v.into_iter().collect::<Option<_>>().map(VPath)
|
||||
}
|
||||
match path.extension().map(|s| s.to_str()) {
|
||||
Some(Some(s)) if s == ext => Some((to_vpath(&path.with_extension("")).await?, true)),
|
||||
None => Some((to_vpath(path).await?, false)),
|
||||
Some(Some(s)) if s == ext => Some((to_vpath(&path.with_extension(""), i).await?, true)),
|
||||
None => Some((to_vpath(path, i).await?, false)),
|
||||
Some(_) => None,
|
||||
}
|
||||
}
|
||||
@@ -259,8 +260,11 @@ impl VName {
|
||||
let data: Vec<_> = items.into_iter().collect();
|
||||
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
|
||||
}
|
||||
pub async fn deintern(name: impl IntoIterator<Item = api::TStr>) -> Result<Self, EmptyNameError> {
|
||||
Self::new(join_all(name.into_iter().map(Tok::from_api)).await)
|
||||
pub async fn deintern(
|
||||
name: impl IntoIterator<Item = api::TStr>,
|
||||
i: &Interner,
|
||||
) -> Result<Self, EmptyNameError> {
|
||||
Self::new(join_all(name.into_iter().map(|m| Tok::from_api(m, i))).await)
|
||||
}
|
||||
/// Unwrap the enclosed vector
|
||||
pub fn into_vec(self) -> Vec<Tok<String>> { self.0 }
|
||||
@@ -270,7 +274,7 @@ impl VName {
|
||||
/// must never be empty.
|
||||
pub fn vec_mut(&mut self) -> &mut Vec<Tok<String>> { &mut self.0 }
|
||||
/// Intern the name and return a [Sym]
|
||||
pub async fn to_sym(&self) -> Sym { Sym(intern(&self.0[..]).await) }
|
||||
pub async fn to_sym(&self, i: &Interner) -> Sym { Sym(i.i(&self.0[..]).await) }
|
||||
/// If this name has only one segment, return it
|
||||
pub fn as_root(&self) -> Option<Tok<String>> { self.0.iter().exactly_one().ok().cloned() }
|
||||
/// Prepend the segments to this name
|
||||
@@ -284,8 +288,12 @@ impl VName {
|
||||
Self(self.0.into_iter().chain(items).collect())
|
||||
}
|
||||
/// Read a `::` separated namespaced name
|
||||
pub async fn parse(s: &str) -> Result<Self, EmptyNameError> { Self::new(VPath::parse(s).await) }
|
||||
pub async fn literal(s: &'static str) -> Self { Self::parse(s).await.expect("empty literal !?") }
|
||||
pub async fn parse(s: &str, i: &Interner) -> Result<Self, EmptyNameError> {
|
||||
Self::new(VPath::parse(s, i).await)
|
||||
}
|
||||
pub async fn literal(s: &'static str, i: &Interner) -> Self {
|
||||
Self::parse(s, i).await.expect("empty literal !?")
|
||||
}
|
||||
/// Obtain an iterator over the segments of the name
|
||||
pub fn iter(&self) -> impl Iterator<Item = Tok<String>> + '_ { self.0.iter().cloned() }
|
||||
}
|
||||
@@ -341,13 +349,16 @@ pub struct Sym(Tok<Vec<Tok<String>>>);
|
||||
impl Sym {
|
||||
/// Assert that the sequence isn't empty, intern it and wrap it in a [Sym] to
|
||||
/// represent this invariant
|
||||
pub async fn new(v: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
|
||||
pub async fn new(
|
||||
v: impl IntoIterator<Item = Tok<String>>,
|
||||
i: &Interner,
|
||||
) -> Result<Self, EmptyNameError> {
|
||||
let items = v.into_iter().collect_vec();
|
||||
Self::from_tok(intern(&items[..]).await)
|
||||
Self::from_tok(i.i(&items).await)
|
||||
}
|
||||
/// Read a `::` separated namespaced name.
|
||||
pub async fn parse(s: &str) -> Result<Self, EmptyNameError> {
|
||||
Ok(Sym(intern(&VName::parse(s).await?.into_vec()[..]).await))
|
||||
pub async fn parse(s: &str, i: &Interner) -> Result<Self, EmptyNameError> {
|
||||
Ok(Sym(i.i(&VName::parse(s, i).await?.into_vec()).await))
|
||||
}
|
||||
/// Assert that a token isn't empty, and wrap it in a [Sym]
|
||||
pub fn from_tok(t: Tok<Vec<Tok<String>>>) -> Result<Self, EmptyNameError> {
|
||||
@@ -359,8 +370,8 @@ impl Sym {
|
||||
pub fn id(&self) -> NonZeroU64 { self.0.to_api().get_id() }
|
||||
/// Extern the sym for editing
|
||||
pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) }
|
||||
pub async fn from_api(marker: api::TStrv) -> Sym {
|
||||
Self::from_tok(Tok::from_api(marker).await).expect("Empty sequence found for serialized Sym")
|
||||
pub async fn from_api(marker: api::TStrv, i: &Interner) -> Sym {
|
||||
Self::from_tok(Tok::from_api(marker, i).await).expect("Empty sequence found for serialized Sym")
|
||||
}
|
||||
pub fn to_api(&self) -> api::TStrv { self.tok().to_api() }
|
||||
}
|
||||
@@ -439,11 +450,11 @@ impl NameLike for VName {}
|
||||
/// cloning the token.
|
||||
#[macro_export]
|
||||
macro_rules! sym {
|
||||
($seg1:tt $( :: $seg:tt)*) => { async {
|
||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
||||
$crate::name::Sym::from_tok(
|
||||
$crate::intern!([$crate::interner::Tok<String>]: &[
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )*
|
||||
$i.i(&[
|
||||
$i.i(stringify!($seg1)).await
|
||||
$( , $i.i(stringify!($seg)).await )*
|
||||
])
|
||||
.await
|
||||
).unwrap()
|
||||
@@ -457,10 +468,10 @@ macro_rules! sym {
|
||||
/// The components are interned much like in [sym].
|
||||
#[macro_export]
|
||||
macro_rules! vname {
|
||||
($seg1:tt $( :: $seg:tt)*) => { async {
|
||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
||||
$crate::name::VName::new([
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )*
|
||||
$i.i(stringify!($seg1)).await
|
||||
$( , $i.i(stringify!($seg)).await )*
|
||||
]).unwrap()
|
||||
} };
|
||||
}
|
||||
@@ -470,10 +481,10 @@ macro_rules! vname {
|
||||
/// The components are interned much like in [sym].
|
||||
#[macro_export]
|
||||
macro_rules! vpath {
|
||||
($seg1:tt $( :: $seg:tt)+) => { async {
|
||||
($seg1:tt $( :: $seg:tt)+ ; $i:expr) => { async {
|
||||
$crate::name::VPath(vec![
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )+
|
||||
$i.i(stringify!($seg1)).await
|
||||
$( , $i.i(stringify!($seg)).await )+
|
||||
])
|
||||
} };
|
||||
() => {
|
||||
@@ -481,46 +492,6 @@ macro_rules! vpath {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a &[PathSlice] literal.
|
||||
///
|
||||
/// The components are interned much like in [sym]
|
||||
#[macro_export]
|
||||
macro_rules! with_path_slice {
|
||||
(@UNIT $tt:tt) => { () };
|
||||
($seg1:tt $( :: $seg:tt)* in $expr:expr) => { {
|
||||
use std::future::Future;
|
||||
use std::ops::Deref as _;
|
||||
use std::pin::Pin;
|
||||
|
||||
const fn count_helper<const N: usize>(_: [(); N]) -> usize { N }
|
||||
|
||||
type Output = [Tok<String>; const {
|
||||
count_helper([() $(, $crate::with_path_slice!(@UNIT $seg))*])
|
||||
}];
|
||||
type InternFuture = Pin<Box<dyn Future<Output = Output>>>;
|
||||
thread_local! {
|
||||
static VALUE: Pin<std::rc::Rc<async_once_cell::Lazy<Output, InternFuture>>> =
|
||||
std::rc::Rc::pin(async_once_cell::Lazy::new(Box::pin(async {
|
||||
[
|
||||
$crate::intern!(str: stringify!($seg1)).await
|
||||
$( , $crate::intern!(str: stringify!($seg)).await )+
|
||||
]
|
||||
})));
|
||||
}
|
||||
VALUE.with(|v| $crate::clone!(v; async move {
|
||||
let expr = $expr;
|
||||
let result = v.as_ref().await;
|
||||
let ps: &PathSlice = $crate::name::PathSlice::new(&result.deref()[..]);
|
||||
(expr)(ps).await
|
||||
}))
|
||||
|
||||
} };
|
||||
($expr:expr) => {
|
||||
let expr = $expr;
|
||||
(expr)($crate::name::PathSlice::new(&[]))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::borrow::Borrow;
|
||||
@@ -528,13 +499,14 @@ mod test {
|
||||
use test_executors::spin_on;
|
||||
|
||||
use super::{PathSlice, Sym, VName};
|
||||
use crate::interner::{Tok, intern};
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::name::VPath;
|
||||
|
||||
#[test]
|
||||
fn recur() {
|
||||
spin_on(async {
|
||||
let myname = vname!(foo::bar).await;
|
||||
let i = Interner::new_master();
|
||||
let myname = vname!(foo::bar; i).await;
|
||||
let _borrowed_slice: &[Tok<String>] = myname.borrow();
|
||||
let _borrowed_pathslice: &PathSlice = myname.borrow();
|
||||
let _deref_pathslice: &PathSlice = &myname;
|
||||
@@ -545,25 +517,19 @@ mod test {
|
||||
#[test]
|
||||
fn literals() {
|
||||
spin_on(async {
|
||||
let i = Interner::new_master();
|
||||
assert_eq!(
|
||||
sym!(foo::bar::baz).await,
|
||||
Sym::new([intern("foo").await, intern("bar").await, intern("baz").await]).await.unwrap()
|
||||
sym!(foo::bar::baz; i).await,
|
||||
Sym::new([i.i("foo").await, i.i("bar").await, i.i("baz").await], &i).await.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vname!(foo::bar::baz).await,
|
||||
VName::new([intern("foo").await, intern("bar").await, intern("baz").await]).unwrap()
|
||||
vname!(foo::bar::baz; i).await,
|
||||
VName::new([i.i("foo").await, i.i("bar").await, i.i("baz").await]).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
vpath!(foo::bar::baz).await,
|
||||
VPath::new([intern("foo").await, intern("bar").await, intern("baz").await])
|
||||
vpath!(foo::bar::baz; i).await,
|
||||
VPath::new([i.i("foo").await, i.i("bar").await, i.i("baz").await])
|
||||
);
|
||||
with_path_slice!(foo::bar::baz in |val| async move {
|
||||
assert_eq!(
|
||||
val,
|
||||
PathSlice::new(&[intern("foo").await, intern("bar").await, intern("baz").await])
|
||||
);
|
||||
})
|
||||
.await
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use ordered_float::NotNan;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
use crate::error::{OrcErr, mk_err};
|
||||
use crate::intern;
|
||||
use crate::interner::Interner;
|
||||
use crate::location::Pos;
|
||||
|
||||
/// A number, either floating point or unsigned int, parsed by Orchid.
|
||||
@@ -63,9 +63,9 @@ pub struct NumError {
|
||||
pub kind: NumErrorKind,
|
||||
}
|
||||
|
||||
pub async fn num_to_err(NumError { kind, range }: NumError, offset: u32) -> OrcErr {
|
||||
pub async fn num_to_err(NumError { kind, range }: NumError, offset: u32, i: &Interner) -> OrcErr {
|
||||
mk_err(
|
||||
intern!(str: "Failed to parse number").await,
|
||||
i.i("Failed to parse number").await,
|
||||
match kind {
|
||||
NumErrorKind::NaN => "NaN emerged during parsing",
|
||||
NumErrorKind::InvalidDigit => "non-digit character encountered",
|
||||
|
||||
@@ -4,12 +4,12 @@ use std::ops::{Deref, Range};
|
||||
use futures::future::join_all;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::api;
|
||||
use crate::error::{OrcRes, Reporter, mk_err, mk_errv};
|
||||
use crate::interner::{Tok, intern};
|
||||
use crate::interner::{Internable, Interned, Interner, Tok};
|
||||
use crate::location::Pos;
|
||||
use crate::name::VPath;
|
||||
use crate::tree::{AtomRepr, ExtraTok, Paren, TokTree, Token};
|
||||
use crate::{api, intern};
|
||||
|
||||
pub fn name_start(c: char) -> bool { c.is_alphabetic() || c == '_' }
|
||||
pub fn name_char(c: char) -> bool { name_start(c) || c.is_numeric() }
|
||||
@@ -20,15 +20,24 @@ pub fn unrep_space(c: char) -> bool { c.is_whitespace() && !"\r\n".contains(c) }
|
||||
pub struct Snippet<'a, 'b, A: AtomRepr, X: ExtraTok> {
|
||||
prev: &'a TokTree<'b, A, X>,
|
||||
cur: &'a [TokTree<'b, A, X>],
|
||||
interner: &'a Interner,
|
||||
}
|
||||
impl<'a, 'b, A: AtomRepr, X: ExtraTok> Snippet<'a, 'b, A, X> {
|
||||
pub fn new(prev: &'a TokTree<'b, A, X>, cur: &'a [TokTree<'b, A, X>]) -> Self {
|
||||
Self { prev, cur }
|
||||
pub fn new(
|
||||
prev: &'a TokTree<'b, A, X>,
|
||||
cur: &'a [TokTree<'b, A, X>],
|
||||
interner: &'a Interner,
|
||||
) -> Self {
|
||||
Self { prev, cur, interner }
|
||||
}
|
||||
pub async fn i<T: Interned>(&self, arg: &(impl Internable<Interned = T> + ?Sized)) -> Tok<T> {
|
||||
self.interner.i(arg).await
|
||||
}
|
||||
pub fn split_at(self, pos: u32) -> (Self, Self) {
|
||||
let fst = Self { prev: self.prev, cur: &self.cur[..pos as usize] };
|
||||
let Self { prev, cur, interner } = self;
|
||||
let fst = Self { prev, cur: &cur[..pos as usize], interner };
|
||||
let new_prev = if pos == 0 { self.prev } else { &self.cur[pos as usize - 1] };
|
||||
let snd = Self { prev: new_prev, cur: &self.cur[pos as usize..] };
|
||||
let snd = Self { prev: new_prev, cur: &self.cur[pos as usize..], interner };
|
||||
(fst, snd)
|
||||
}
|
||||
pub fn find_idx(self, mut f: impl FnMut(&Token<'b, A, X>) -> bool) -> Option<u32> {
|
||||
@@ -101,8 +110,8 @@ impl Comment {
|
||||
pub fn to_api(&self) -> api::Comment {
|
||||
api::Comment { location: self.pos.to_api(), text: self.text.to_api() }
|
||||
}
|
||||
pub async fn from_api(api: &api::Comment) -> Self {
|
||||
Self { pos: Pos::from_api(&api.location).await, text: Tok::from_api(api.text).await }
|
||||
pub async fn from_api(api: &api::Comment, i: &Interner) -> Self {
|
||||
Self { pos: Pos::from_api(&api.location, i).await, text: Tok::from_api(api.text, i).await }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +133,7 @@ pub async fn line_items<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
let comments = join_all(comments.drain(..).chain(cmts.cur).map(|t| async {
|
||||
match &t.tok {
|
||||
Token::Comment(c) =>
|
||||
Comment { text: intern(&**c).await, pos: Pos::Range(t.range.clone()) },
|
||||
Comment { text: tail.i(&**c).await, pos: Pos::Range(t.range.clone()) },
|
||||
_ => unreachable!("All are comments checked above"),
|
||||
}
|
||||
}))
|
||||
@@ -141,18 +150,17 @@ pub async fn try_pop_no_fluff<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
) -> ParseRes<'a, 'b, &'a TokTree<'b, A, X>, A, X> {
|
||||
match snip.skip_fluff().pop_front() {
|
||||
Some((output, tail)) => Ok(Parsed { output, tail }),
|
||||
None =>
|
||||
Err(mk_errv(intern!(str: "Unexpected end").await, "Pattern ends abruptly", [Pos::Range(
|
||||
snip.pos(),
|
||||
)
|
||||
.into()])),
|
||||
None => Err(mk_errv(snip.i("Unexpected end").await, "Pattern ends abruptly", [Pos::Range(
|
||||
snip.pos(),
|
||||
)
|
||||
.into()])),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn expect_end(snip: Snippet<'_, '_, impl AtomRepr, impl ExtraTok>) -> OrcRes<()> {
|
||||
match snip.skip_fluff().get(0) {
|
||||
Some(surplus) => Err(mk_errv(
|
||||
intern!(str: "Extra code after end of line").await,
|
||||
snip.i("Extra code after end of line").await,
|
||||
"Code found after the end of the line",
|
||||
[Pos::Range(surplus.range.clone()).into()],
|
||||
)),
|
||||
@@ -168,7 +176,7 @@ pub async fn expect_tok<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
match &head.tok {
|
||||
Token::Name(n) if *n == tok => Ok(Parsed { output: (), tail }),
|
||||
t => Err(mk_errv(
|
||||
intern!(str: "Expected specific keyword").await,
|
||||
snip.i("Expected specific keyword").await,
|
||||
format!("Expected {tok} but found {t}"),
|
||||
[Pos::Range(head.range.clone()).into()],
|
||||
)),
|
||||
@@ -192,11 +200,11 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
ctx: &impl Reporter,
|
||||
tail: Snippet<'a, 'b, A, X>,
|
||||
) -> ParseRes<'a, 'b, Vec<(Vec<Tok<String>>, Option<Tok<String>>, Pos)>, A, X> {
|
||||
let comma = intern!(str: ",").await;
|
||||
let globstar = intern!(str: "*").await;
|
||||
let comma = tail.i(",").await;
|
||||
let globstar = tail.i("*").await;
|
||||
let Some((name, tail)) = tail.skip_fluff().pop_front() else {
|
||||
return Err(mk_errv(
|
||||
intern!(str: "Expected name").await,
|
||||
tail.i("Expected name").await,
|
||||
"Expected a name, a list of names, or a globstar.",
|
||||
[Pos::Range(tail.pos()).into()],
|
||||
));
|
||||
@@ -204,10 +212,9 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
if let Some((Token::NS, tail)) = tail.skip_fluff().pop_front().map(|(tt, s)| (&tt.tok, s)) {
|
||||
let n = match &name.tok {
|
||||
Token::Name(n) if n.starts_with(name_start) => Ok(n),
|
||||
_ =>
|
||||
Err(mk_err(intern!(str: "Unexpected name prefix").await, "Only names can precede ::", [
|
||||
Pos::Range(name.range.clone()).into(),
|
||||
])),
|
||||
_ => Err(mk_err(tail.i("Unexpected name prefix").await, "Only names can precede ::", [
|
||||
Pos::Range(name.range.clone()).into(),
|
||||
])),
|
||||
};
|
||||
match (Box::pin(rec(ctx, tail)).await, n) {
|
||||
(Err(ev), n) => Err(ev.extended(n.err())),
|
||||
@@ -227,7 +234,7 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
n if *n == globstar => None,
|
||||
n if n.starts_with(op_char) => {
|
||||
return Err(mk_errv(
|
||||
intern!(str: "Unescaped operator in multiname").await,
|
||||
tail.i("Unescaped operator in multiname").await,
|
||||
"Operators in multinames should be enclosed in []",
|
||||
[Pos::Range(name.range.clone()).into()],
|
||||
));
|
||||
@@ -244,7 +251,7 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
ok.push((vec![], Some(n.clone()), Pos::Range(tt.range.clone()))),
|
||||
Token::BR | Token::Comment(_) => (),
|
||||
_ => ctx.report(mk_err(
|
||||
intern!(str: "Non-operator in escapement in multiname").await,
|
||||
tail.i("Non-operator in escapement in multiname").await,
|
||||
"In multinames, [] functions as a literal name list reserved for operators",
|
||||
[Pos::Range(name.range.clone()).into()],
|
||||
)),
|
||||
@@ -254,14 +261,14 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
},
|
||||
Token::S(Paren::Round, b) => {
|
||||
let mut ok = Vec::new();
|
||||
let body = Snippet::new(name, b);
|
||||
let body = Snippet::new(name, b, tail.interner);
|
||||
for csent in body.split(|n| matches!(n, Token::Name(n) if *n == comma)) {
|
||||
match Box::pin(rec(ctx, csent)).await {
|
||||
Err(e) => ctx.report(e),
|
||||
Ok(Parsed { output, tail }) => match tail.get(0) {
|
||||
None => ok.extend(output),
|
||||
Some(t) => ctx.report(mk_err(
|
||||
intern!(str: "Unexpected token in multiname group").await,
|
||||
tail.i("Unexpected token in multiname group").await,
|
||||
"Unexpected token. Likely missing a :: or , or wanted [] instead of ()",
|
||||
[Pos::Range(t.range.clone()).into()],
|
||||
)),
|
||||
@@ -272,7 +279,7 @@ pub async fn parse_multiname<'a, 'b, A: AtomRepr, X: ExtraTok>(
|
||||
},
|
||||
t => {
|
||||
return Err(mk_errv(
|
||||
intern!(str: "Unrecognized name end").await,
|
||||
tail.i("Unrecognized name end").await,
|
||||
format!("Names cannot end with {t} tokens"),
|
||||
[Pos::Range(name.range.clone()).into()],
|
||||
));
|
||||
|
||||
@@ -38,7 +38,11 @@ fn get_id(message: &[u8]) -> (u64, &[u8]) {
|
||||
}
|
||||
|
||||
pub trait ReqHandlish {
|
||||
fn defer_drop(&self, val: impl Any + 'static);
|
||||
fn defer_drop(&self, val: impl Any + 'static)
|
||||
where Self: Sized {
|
||||
self.defer_drop_objsafe(Box::new(val));
|
||||
}
|
||||
fn defer_drop_objsafe(&self, val: Box<dyn Any>);
|
||||
}
|
||||
|
||||
#[derive(destructure)]
|
||||
@@ -77,7 +81,7 @@ impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> {
|
||||
}
|
||||
}
|
||||
impl<MS: MsgSet> ReqHandlish for RequestHandle<'_, MS> {
|
||||
fn defer_drop(&self, val: impl Any) { self.defer_drop.borrow_mut().push(Box::new(val)) }
|
||||
fn defer_drop_objsafe(&self, val: Box<dyn Any>) { self.defer_drop.borrow_mut().push(val); }
|
||||
}
|
||||
impl<MS: MsgSet> Drop for RequestHandle<'_, MS> {
|
||||
fn drop(&mut self) {
|
||||
@@ -212,6 +216,7 @@ impl<T: MsgSet> Clone for ReqNot<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_std::sync::Mutex;
|
||||
@@ -270,8 +275,8 @@ mod test {
|
||||
#[test]
|
||||
fn request() {
|
||||
spin_on(async {
|
||||
let receiver = Arc::new(Mutex::<Option<ReqNot<TestMsgSet>>>::new(None));
|
||||
let sender = Arc::new(ReqNot::<TestMsgSet>::new(
|
||||
let receiver = Rc::new(Mutex::<Option<ReqNot<TestMsgSet>>>::new(None));
|
||||
let sender = Rc::new(ReqNot::<TestMsgSet>::new(
|
||||
clone!(receiver; move |d, _| clone!(receiver; Box::pin(async move {
|
||||
receiver.lock().await.as_ref().unwrap().receive(d).await
|
||||
}))),
|
||||
|
||||
@@ -9,14 +9,15 @@ use std::sync::Arc;
|
||||
pub use api::PhKind;
|
||||
use async_std::stream;
|
||||
use async_std::sync::Mutex;
|
||||
use futures::StreamExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
use ordered_float::NotNan;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::error::OrcErrv;
|
||||
use crate::interner::Tok;
|
||||
use crate::interner::{Interner, Tok};
|
||||
use crate::location::Pos;
|
||||
use crate::name::PathSlice;
|
||||
use crate::parse::Snippet;
|
||||
@@ -26,6 +27,8 @@ use crate::{api, match_mapping};
|
||||
trait_set! {
|
||||
pub trait RecurCB<'a, A: AtomRepr, X: ExtraTok> = Fn(TokTree<'a, A, X>) -> TokTree<'a, A, X>;
|
||||
pub trait ExtraTok = Display + Clone + fmt::Debug;
|
||||
pub trait RefDoExtra<X> =
|
||||
for<'b> FnMut(&'b X, Range<u32>) -> LocalBoxFuture<'b, api::TokenTree>;
|
||||
}
|
||||
|
||||
pub fn recur<'a, A: AtomRepr, X: ExtraTok>(
|
||||
@@ -72,41 +75,38 @@ pub struct TokTree<'a, A: AtomRepr, X: ExtraTok> {
|
||||
pub tok: Token<'a, A, X>,
|
||||
pub range: Range<u32>,
|
||||
}
|
||||
impl<'a, A: AtomRepr, X: ExtraTok> TokTree<'a, A, X> {
|
||||
pub async fn from_api(tt: &api::TokenTree, ctx: &mut A::Ctx) -> Self {
|
||||
let tok = match_mapping!(&tt.token, api::Token => Token::<'a, A, X> {
|
||||
impl<'b, A: AtomRepr, X: ExtraTok> TokTree<'b, A, X> {
|
||||
pub async fn from_api(tt: &api::TokenTree, ctx: &mut A::Ctx, i: &Interner) -> Self {
|
||||
let tok = match_mapping!(&tt.token, api::Token => Token::<'b, A, X> {
|
||||
BR, NS,
|
||||
Atom(a => A::from_api(a, Pos::Range(tt.range.clone()), ctx)),
|
||||
Bottom(e => OrcErrv::from_api(e).await),
|
||||
LambdaHead(arg => ttv_from_api(arg, ctx).await),
|
||||
Name(n => Tok::from_api(*n).await),
|
||||
S(*par, b => ttv_from_api(b, ctx).await),
|
||||
Bottom(e => OrcErrv::from_api(e, i).await),
|
||||
LambdaHead(arg => ttv_from_api(arg, ctx, i).await),
|
||||
Name(n => Tok::from_api(*n, i).await),
|
||||
S(*par, b => ttv_from_api(b, ctx, i).await),
|
||||
Comment(c.clone()),
|
||||
Slot(id => TokHandle::new(*id)),
|
||||
Ph(ph => Ph::from_api(ph).await),
|
||||
Ph(ph => Ph::from_api(ph, i).await),
|
||||
Macro(*prio)
|
||||
});
|
||||
Self { range: tt.range.clone(), tok }
|
||||
}
|
||||
|
||||
pub fn to_api(
|
||||
&self,
|
||||
do_extra: &mut impl FnMut(&X, Range<u32>) -> api::TokenTree,
|
||||
) -> api::TokenTree {
|
||||
pub async fn to_api(&self, do_extra: &mut impl RefDoExtra<X>) -> api::TokenTree {
|
||||
let token = match_mapping!(&self.tok, Token => api::Token {
|
||||
Atom(a.to_api()),
|
||||
BR,
|
||||
NS,
|
||||
Bottom(e.to_api()),
|
||||
Comment(c.clone()),
|
||||
LambdaHead(arg => ttv_to_api(arg, do_extra)),
|
||||
LambdaHead(arg => ttv_to_api(arg, do_extra).boxed_local().await),
|
||||
Name(n.to_api()),
|
||||
Slot(tt.ticket()),
|
||||
S(*p, b => ttv_to_api(b, do_extra)),
|
||||
S(*p, b => ttv_to_api(b, do_extra).boxed_local().await),
|
||||
Ph(ph.to_api()),
|
||||
Macro(*prio),
|
||||
} {
|
||||
Token::X(x) => return do_extra(x, self.range.clone())
|
||||
Token::X(x) => return do_extra(x, self.range.clone()).await
|
||||
});
|
||||
api::TokenTree { range: self.range.clone(), token }
|
||||
}
|
||||
@@ -137,8 +137,8 @@ impl<'a, A: AtomRepr, X: ExtraTok> TokTree<'a, A, X> {
|
||||
pub fn as_name(&self) -> Option<Tok<String>> {
|
||||
if let Token::Name(n) = &self.tok { Some(n.clone()) } else { None }
|
||||
}
|
||||
pub fn as_s(&self, par: Paren) -> Option<Snippet<'_, 'a, A, X>> {
|
||||
self.tok.as_s(par).map(|slc| Snippet::new(self, slc))
|
||||
pub fn as_s<'a>(&'a self, par: Paren, i: &'a Interner) -> Option<Snippet<'a, 'b, A, X>> {
|
||||
self.tok.as_s(par).map(|slc| Snippet::new(self, slc, i))
|
||||
}
|
||||
pub fn lambda(arg: Vec<Self>, mut body: Vec<Self>) -> Self {
|
||||
let arg_range = ttv_range(&arg);
|
||||
@@ -155,22 +155,27 @@ impl<A: AtomRepr, X: ExtraTok> Display for TokTree<'_, A, X> {
|
||||
pub async fn ttv_from_api<A: AtomRepr, X: ExtraTok>(
|
||||
tokv: impl IntoIterator<Item: Borrow<api::TokenTree>>,
|
||||
ctx: &mut A::Ctx,
|
||||
i: &Interner,
|
||||
) -> Vec<TokTree<'static, A, X>> {
|
||||
let ctx_lk = Mutex::new(ctx);
|
||||
stream::from_iter(tokv.into_iter())
|
||||
.then(|t| async {
|
||||
let t = t;
|
||||
TokTree::<A, X>::from_api(t.borrow(), *ctx_lk.lock().await).await
|
||||
TokTree::<A, X>::from_api(t.borrow(), *ctx_lk.lock().await, i).await
|
||||
})
|
||||
.collect()
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn ttv_to_api<'a, A: AtomRepr, X: ExtraTok>(
|
||||
pub async fn ttv_to_api<'a, A: AtomRepr, X: ExtraTok>(
|
||||
tokv: impl IntoIterator<Item: Borrow<TokTree<'a, A, X>>>,
|
||||
do_extra: &mut impl FnMut(&X, Range<u32>) -> api::TokenTree,
|
||||
do_extra: &mut impl RefDoExtra<X>,
|
||||
) -> Vec<api::TokenTree> {
|
||||
tokv.into_iter().map(|tok| Borrow::<TokTree<A, X>>::borrow(&tok).to_api(do_extra)).collect_vec()
|
||||
let mut output = Vec::new();
|
||||
for tok in tokv {
|
||||
output.push(Borrow::<TokTree<A, X>>::borrow(&tok).to_api(do_extra).await)
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub fn ttv_into_api<'a, A: AtomRepr, X: ExtraTok>(
|
||||
@@ -307,8 +312,8 @@ pub struct Ph {
|
||||
pub kind: PhKind,
|
||||
}
|
||||
impl Ph {
|
||||
pub async fn from_api(api: &api::Placeholder) -> Self {
|
||||
Self { name: Tok::from_api(api.name).await, kind: api.kind }
|
||||
pub async fn from_api(api: &api::Placeholder, i: &Interner) -> Self {
|
||||
Self { name: Tok::from_api(api.name, i).await, kind: api.kind }
|
||||
}
|
||||
pub fn to_api(&self) -> api::Placeholder {
|
||||
api::Placeholder { name: self.name.to_api(), kind: self.kind }
|
||||
|
||||
@@ -4,14 +4,17 @@ use std::future::Future;
|
||||
use std::io::{Read, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::rc::Rc;
|
||||
|
||||
use ahash::HashMap;
|
||||
use async_std::stream;
|
||||
use dyn_clone::{DynClone, clone_box};
|
||||
use futures::FutureExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use orchid_api_traits::{Coding, Decode, Encode, Request, enc_vec};
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::{OrcErr, OrcRes, mk_err};
|
||||
use orchid_base::intern;
|
||||
use orchid_base::interner::Interner;
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::reqnot::Requester;
|
||||
@@ -21,6 +24,7 @@ use trait_set::trait_set;
|
||||
use crate::api;
|
||||
// use crate::error::{ProjectError, ProjectResult};
|
||||
use crate::expr::{Expr, ExprData, ExprHandle, ExprKind};
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::system::{DynSystemCard, SysCtx, atom_info_for, downcast_atom};
|
||||
|
||||
pub trait AtomCard: 'static + Sized {
|
||||
@@ -31,7 +35,7 @@ pub trait AtomicVariant {}
|
||||
pub trait Atomic: 'static + Sized {
|
||||
type Variant: AtomicVariant;
|
||||
type Data: Clone + Coding + Sized;
|
||||
fn reg_reqs() -> MethodSet<Self>;
|
||||
fn reg_reqs() -> MethodSetBuilder<Self>;
|
||||
}
|
||||
impl<A: Atomic> AtomCard for A {
|
||||
type Data = <Self as Atomic>::Data;
|
||||
@@ -74,11 +78,11 @@ pub fn get_info<A: AtomCard>(
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ForeignAtom<'a> {
|
||||
pub expr: Option<Arc<ExprHandle>>,
|
||||
pub _life: PhantomData<&'a ()>,
|
||||
pub ctx: SysCtx,
|
||||
pub atom: api::Atom,
|
||||
pub pos: Pos,
|
||||
pub(crate) expr: Option<Rc<ExprHandle>>,
|
||||
pub(crate) _life: PhantomData<&'a ()>,
|
||||
pub(crate) ctx: SysCtx,
|
||||
pub(crate) atom: api::Atom,
|
||||
pub(crate) pos: Pos,
|
||||
}
|
||||
impl ForeignAtom<'_> {
|
||||
pub fn ex_opt(self) -> Option<Expr> {
|
||||
@@ -86,16 +90,18 @@ impl ForeignAtom<'_> {
|
||||
let data = ExprData { pos, kind: ExprKind::Atom(ForeignAtom { _life: PhantomData, ..self }) };
|
||||
Some(Expr::new(handle, data))
|
||||
}
|
||||
pub fn pos(&self) -> Pos { self.pos.clone() }
|
||||
pub fn ctx(&self) -> SysCtx { self.ctx.clone() }
|
||||
}
|
||||
impl ForeignAtom<'static> {
|
||||
pub fn ex(self) -> Expr { self.ex_opt().unwrap() }
|
||||
pub(crate) fn new(handle: Arc<ExprHandle>, atom: api::Atom, pos: Pos) -> Self {
|
||||
pub(crate) fn new(handle: Rc<ExprHandle>, atom: api::Atom, pos: Pos) -> Self {
|
||||
ForeignAtom { _life: PhantomData, atom, ctx: handle.ctx.clone(), expr: Some(handle), pos }
|
||||
}
|
||||
pub async fn request<M: AtomMethod>(&self, m: M) -> Option<M::Response> {
|
||||
let rep = (self.ctx.reqnot.request(api::Fwd(
|
||||
self.atom.clone(),
|
||||
Sym::parse(M::NAME).await.unwrap().tok().to_api(),
|
||||
Sym::parse(M::NAME, &self.ctx.i).await.unwrap().tok().to_api(),
|
||||
enc_vec(&m),
|
||||
)))
|
||||
.await?;
|
||||
@@ -118,13 +124,18 @@ impl AtomRepr for ForeignAtom<'_> {
|
||||
fn to_api(&self) -> orchid_api::Atom { self.atom.clone() }
|
||||
}
|
||||
|
||||
pub struct NotTypAtom(pub Pos, pub Expr, pub Box<dyn AtomDynfo>);
|
||||
pub struct NotTypAtom {
|
||||
pub pos: Pos,
|
||||
pub expr: Expr,
|
||||
pub typ: Box<dyn AtomDynfo>,
|
||||
pub ctx: SysCtx,
|
||||
}
|
||||
impl NotTypAtom {
|
||||
pub async fn mk_err(&self) -> OrcErr {
|
||||
mk_err(
|
||||
intern!(str: "Not the expected type").await,
|
||||
format!("This expression is not a {}", self.2.name()),
|
||||
[self.0.clone().into()],
|
||||
self.ctx.i.i("Not the expected type").await,
|
||||
format!("This expression is not a {}", self.typ.name()),
|
||||
[self.pos.clone().into()],
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -142,52 +153,64 @@ trait_set! {
|
||||
SysCtx,
|
||||
&'a mut dyn Read,
|
||||
&'a mut dyn Write
|
||||
) -> LocalBoxFuture<'a, ()> + Send + Sync
|
||||
) -> LocalBoxFuture<'a, ()>
|
||||
}
|
||||
|
||||
pub struct AtomReqHandler<A: AtomCard> {
|
||||
key: Sym,
|
||||
cb: Box<dyn AtomReqCb<A>>,
|
||||
pub struct MethodSetBuilder<A: AtomCard> {
|
||||
handlers: Vec<(&'static str, Rc<dyn AtomReqCb<A>>)>,
|
||||
}
|
||||
|
||||
pub struct MethodSet<A: AtomCard> {
|
||||
handlers: Vec<AtomReqHandler<A>>,
|
||||
}
|
||||
impl<A: AtomCard> MethodSet<A> {
|
||||
impl<A: AtomCard> MethodSetBuilder<A> {
|
||||
pub fn new() -> Self { Self { handlers: vec![] } }
|
||||
|
||||
pub async fn handle<M: AtomMethod>(mut self) -> Self
|
||||
pub fn handle<M: AtomMethod>(mut self) -> Self
|
||||
where A: Supports<M> {
|
||||
self.handlers.push(AtomReqHandler {
|
||||
key: Sym::parse(M::NAME).await.expect("AtomMethod::NAME cannoot be empty"),
|
||||
cb: Box::new(move |a: &A, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write| {
|
||||
assert!(!M::NAME.is_empty(), "AtomMethod::NAME cannoot be empty");
|
||||
self.handlers.push((
|
||||
M::NAME,
|
||||
Rc::new(move |a: &A, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write| {
|
||||
async { Supports::<M>::handle(a, ctx, M::decode(req)).await.encode(rep) }.boxed_local()
|
||||
}),
|
||||
});
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch<'a>(
|
||||
pub async fn pack(&self, ctx: SysCtx) -> MethodSet<A> {
|
||||
MethodSet {
|
||||
handlers: stream::from_iter(self.handlers.iter())
|
||||
.then(|(k, v)| {
|
||||
clone!(ctx; async move {
|
||||
(Sym::parse(k, &ctx.i).await.unwrap(), v.clone())
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
.await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MethodSet<A: AtomCard> {
|
||||
handlers: HashMap<Sym, Rc<dyn AtomReqCb<A>>>,
|
||||
}
|
||||
impl<A: AtomCard> MethodSet<A> {
|
||||
pub(crate) async fn dispatch<'a>(
|
||||
&'a self,
|
||||
atom: &'a A,
|
||||
ctx: SysCtx,
|
||||
key: Sym,
|
||||
req: &'a mut dyn Read,
|
||||
rep: &'a mut dyn Write,
|
||||
) -> impl Future<Output = bool> + 'a {
|
||||
async move {
|
||||
match self.handlers.iter().find(|h| h.key == key) {
|
||||
None => false,
|
||||
Some(handler) => {
|
||||
(handler.cb)(atom, ctx, req, rep).await;
|
||||
true
|
||||
},
|
||||
}
|
||||
) -> bool {
|
||||
match self.handlers.get(&key) {
|
||||
None => false,
|
||||
Some(handler) => {
|
||||
handler(atom, ctx, req, rep).await;
|
||||
true
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: AtomCard> Default for MethodSet<A> {
|
||||
impl<A: AtomCard> Default for MethodSetBuilder<A> {
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
@@ -197,11 +220,21 @@ pub struct TypAtom<'a, A: AtomicFeatures> {
|
||||
pub value: A::Data,
|
||||
}
|
||||
impl<A: AtomicFeatures> TypAtom<'static, A> {
|
||||
pub async fn downcast(expr: Arc<ExprHandle>) -> Result<Self, NotTypAtom> {
|
||||
pub async fn downcast(expr: Rc<ExprHandle>) -> Result<Self, NotTypAtom> {
|
||||
match Expr::from_handle(expr).atom().await {
|
||||
Err(oe) => Err(NotTypAtom(oe.data().await.pos.clone(), oe, Box::new(A::info()))),
|
||||
Err(expr) => Err(NotTypAtom {
|
||||
ctx: expr.handle().get_ctx(),
|
||||
pos: expr.data().await.pos.clone(),
|
||||
expr,
|
||||
typ: Box::new(A::info()),
|
||||
}),
|
||||
Ok(atm) => match downcast_atom::<A>(atm) {
|
||||
Err(fa) => Err(NotTypAtom(fa.pos.clone(), fa.ex(), Box::new(A::info()))),
|
||||
Err(fa) => Err(NotTypAtom {
|
||||
pos: fa.pos.clone(),
|
||||
ctx: fa.ctx.clone(),
|
||||
expr: fa.ex(),
|
||||
typ: Box::new(A::info()),
|
||||
}),
|
||||
Ok(tatom) => Ok(tatom),
|
||||
},
|
||||
}
|
||||
@@ -213,7 +246,7 @@ impl<A: AtomicFeatures> TypAtom<'_, A> {
|
||||
M::Response::decode(
|
||||
&mut &(self.data.ctx.reqnot.request(api::Fwd(
|
||||
self.data.atom.clone(),
|
||||
Sym::parse(M::NAME).await.unwrap().tok().to_api(),
|
||||
Sym::parse(M::NAME, &self.data.ctx.i).await.unwrap().tok().to_api(),
|
||||
enc_vec(&req),
|
||||
)))
|
||||
.await
|
||||
@@ -228,12 +261,12 @@ impl<A: AtomicFeatures> Deref for TypAtom<'_, A> {
|
||||
|
||||
pub struct AtomCtx<'a>(pub &'a [u8], pub Option<api::AtomId>, pub SysCtx);
|
||||
|
||||
pub trait AtomDynfo: Send + Sync + 'static {
|
||||
pub trait AtomDynfo: 'static {
|
||||
fn tid(&self) -> TypeId;
|
||||
fn name(&self) -> &'static str;
|
||||
fn decode(&self, ctx: AtomCtx<'_>) -> Box<dyn Any>;
|
||||
fn call<'a>(&'a self, ctx: AtomCtx<'a>, arg: api::ExprTicket) -> LocalBoxFuture<'a, Expr>;
|
||||
fn call_ref<'a>(&'a self, ctx: AtomCtx<'a>, arg: api::ExprTicket) -> LocalBoxFuture<'a, Expr>;
|
||||
fn call<'a>(&'a self, ctx: AtomCtx<'a>, arg: api::ExprTicket) -> LocalBoxFuture<'a, GExpr>;
|
||||
fn call_ref<'a>(&'a self, ctx: AtomCtx<'a>, arg: api::ExprTicket) -> LocalBoxFuture<'a, GExpr>;
|
||||
fn print<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, String>;
|
||||
fn handle_req<'a, 'b: 'a, 'c: 'a>(
|
||||
&'a self,
|
||||
@@ -242,7 +275,7 @@ pub trait AtomDynfo: Send + Sync + 'static {
|
||||
req: &'b mut dyn Read,
|
||||
rep: &'c mut dyn Write,
|
||||
) -> LocalBoxFuture<'a, bool>;
|
||||
fn command<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, OrcRes<Option<Expr>>>;
|
||||
fn command<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, OrcRes<Option<GExpr>>>;
|
||||
fn serialize<'a, 'b: 'a>(
|
||||
&'a self,
|
||||
ctx: AtomCtx<'a>,
|
||||
@@ -258,12 +291,16 @@ pub trait AtomDynfo: Send + Sync + 'static {
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
pub trait AtomFactoryFn = FnOnce(SysCtx) -> api::Atom + DynClone;
|
||||
pub trait AtomFactoryFn = FnOnce(SysCtx) -> LocalBoxFuture<'static, api::Atom> + DynClone;
|
||||
}
|
||||
pub struct AtomFactory(Box<dyn AtomFactoryFn>);
|
||||
impl AtomFactory {
|
||||
pub fn new(f: impl FnOnce(SysCtx) -> api::Atom + Clone + 'static) -> Self { Self(Box::new(f)) }
|
||||
pub fn build(self, ctx: SysCtx) -> api::Atom { (self.0)(ctx) }
|
||||
pub fn new<F: Future<Output = api::Atom> + 'static>(
|
||||
f: impl FnOnce(SysCtx) -> F + Clone + 'static,
|
||||
) -> Self {
|
||||
Self(Box::new(|ctx| f(ctx).boxed_local()))
|
||||
}
|
||||
pub async fn build(self, ctx: SysCtx) -> api::Atom { (self.0)(ctx).await }
|
||||
}
|
||||
impl Clone for AtomFactory {
|
||||
fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) }
|
||||
@@ -275,11 +312,10 @@ impl fmt::Display for AtomFactory {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "AtomFactory") }
|
||||
}
|
||||
|
||||
pub async fn err_not_callable() -> OrcErr {
|
||||
mk_err(intern!(str: "This atom is not callable").await, "Attempted to apply value as function", [
|
||||
])
|
||||
pub async fn err_not_callable(i: &Interner) -> OrcErr {
|
||||
mk_err(i.i("This atom is not callable").await, "Attempted to apply value as function", [])
|
||||
}
|
||||
|
||||
pub async fn err_not_command() -> OrcErr {
|
||||
mk_err(intern!(str: "This atom is not a command").await, "Settled on an inactionable value", [])
|
||||
pub async fn err_not_command(i: &Interner) -> OrcErr {
|
||||
mk_err(i.i("This atom is not a command").await, "Settled on an inactionable value", [])
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ use std::any::{Any, TypeId, type_name};
|
||||
use std::borrow::Cow;
|
||||
use std::future::Future;
|
||||
use std::io::{Read, Write};
|
||||
use std::sync::Arc;
|
||||
use std::rc::Rc;
|
||||
|
||||
use async_once_cell::OnceCell;
|
||||
use futures::FutureExt;
|
||||
use futures::future::{LocalBoxFuture, ready};
|
||||
use itertools::Itertools;
|
||||
@@ -17,24 +18,25 @@ use orchid_base::name::Sym;
|
||||
use crate::api;
|
||||
use crate::atom::{
|
||||
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
|
||||
err_not_callable, err_not_command, get_info,
|
||||
MethodSetBuilder, err_not_callable, err_not_command, get_info,
|
||||
};
|
||||
use crate::expr::{Expr, ExprHandle, bot};
|
||||
use crate::expr::{Expr, ExprHandle};
|
||||
use crate::gen_expr::{GExpr, bot};
|
||||
use crate::system::SysCtx;
|
||||
|
||||
pub struct OwnedVariant;
|
||||
impl AtomicVariant for OwnedVariant {}
|
||||
impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVariant> for A {
|
||||
fn _factory(self) -> AtomFactory {
|
||||
AtomFactory::new(move |ctx| {
|
||||
AtomFactory::new(move |ctx| async move {
|
||||
let rec = ctx.obj_store.add(Box::new(self));
|
||||
let (id, _) = get_info::<A>(ctx.cted.inst().card());
|
||||
let mut data = enc_vec(&id);
|
||||
rec.encode(&mut data);
|
||||
rec.encode(&mut data).await;
|
||||
api::Atom { drop: Some(api::AtomId(rec.id())), data, owner: ctx.id }
|
||||
})
|
||||
}
|
||||
fn _info() -> Self::_Info { OwnedAtomDynfo(A::reg_reqs()) }
|
||||
fn _info() -> Self::_Info { OwnedAtomDynfo { msbuild: A::reg_reqs(), ms: OnceCell::new() } }
|
||||
type _Info = OwnedAtomDynfo<A>;
|
||||
}
|
||||
|
||||
@@ -46,21 +48,24 @@ fn with_atom<'a, U>(
|
||||
f(ctx.obj_store.get(id.0).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0)))
|
||||
}
|
||||
|
||||
pub struct OwnedAtomDynfo<T: OwnedAtom>(MethodSet<T>);
|
||||
pub struct OwnedAtomDynfo<T: OwnedAtom> {
|
||||
msbuild: MethodSetBuilder<T>,
|
||||
ms: OnceCell<MethodSet<T>>,
|
||||
}
|
||||
impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
fn tid(&self) -> TypeId { TypeId::of::<T>() }
|
||||
fn name(&self) -> &'static str { type_name::<T>() }
|
||||
fn decode(&self, AtomCtx(data, ..): AtomCtx) -> Box<dyn Any> {
|
||||
Box::new(<T as AtomCard>::Data::decode(&mut &data[..]))
|
||||
}
|
||||
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, Expr> {
|
||||
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, GExpr> {
|
||||
with_atom(id.unwrap(), &ctx, |a| a.remove()).dyn_call(ctx.clone(), arg)
|
||||
}
|
||||
fn call_ref<'a>(
|
||||
&'a self,
|
||||
AtomCtx(_, id, ctx): AtomCtx<'a>,
|
||||
arg: api::ExprTicket,
|
||||
) -> LocalBoxFuture<'a, Expr> {
|
||||
) -> LocalBoxFuture<'a, GExpr> {
|
||||
async move {
|
||||
with_atom(id.unwrap(), &ctx, |a| clone!(ctx; async move { a.dyn_call_ref(ctx, arg).await }))
|
||||
.await
|
||||
@@ -83,7 +88,8 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
async move {
|
||||
with_atom(id.unwrap(), &ctx, |a| {
|
||||
clone!(ctx; async move {
|
||||
self.0.dispatch(a.as_any_ref().downcast_ref().unwrap(), ctx, key, req, rep).await
|
||||
let ms = self.ms.get_or_init(self.msbuild.pack(ctx.clone())).await;
|
||||
ms.dispatch(a.as_any_ref().downcast_ref().unwrap(), ctx, key, req, rep).await
|
||||
})
|
||||
})
|
||||
.await
|
||||
@@ -93,7 +99,7 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
fn command<'a>(
|
||||
&'a self,
|
||||
AtomCtx(_, id, ctx): AtomCtx<'a>,
|
||||
) -> LocalBoxFuture<'a, OrcRes<Option<Expr>>> {
|
||||
) -> LocalBoxFuture<'a, OrcRes<Option<GExpr>>> {
|
||||
async move { with_atom(id.unwrap(), &ctx, |a| a.remove().dyn_command(ctx.clone())).await }
|
||||
.boxed_local()
|
||||
}
|
||||
@@ -111,7 +117,7 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
id.encode(write);
|
||||
with_atom(id, &ctx, |a| clone!(ctx; async move { a.dyn_serialize(ctx, write).await }))
|
||||
.await
|
||||
.map(|v| v.into_iter().map(|t| t.handle().unwrap().tk).collect_vec())
|
||||
.map(|v| v.into_iter().map(|t| t.handle().tk).collect_vec())
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
@@ -123,9 +129,9 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
) -> LocalBoxFuture<'a, api::Atom> {
|
||||
async move {
|
||||
let refs =
|
||||
refs.iter().map(|tk| Expr::from_handle(Arc::new(ExprHandle::from_args(ctx.clone(), *tk))));
|
||||
refs.iter().map(|tk| Expr::from_handle(Rc::new(ExprHandle::from_args(ctx.clone(), *tk))));
|
||||
let obj = T::deserialize(DeserCtxImpl(data, &ctx), T::Refs::from_iter(refs)).await;
|
||||
obj._factory().build(ctx)
|
||||
obj._factory().build(ctx).await
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
@@ -197,20 +203,20 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Any + Clone + 'static {
|
||||
type Refs: RefSet;
|
||||
fn val(&self) -> impl Future<Output = Cow<'_, Self::Data>>;
|
||||
#[allow(unused_variables)]
|
||||
fn call_ref(&self, arg: ExprHandle) -> impl Future<Output = Expr> {
|
||||
async { bot([err_not_callable().await]) }
|
||||
fn call_ref(&self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
||||
async move { bot([err_not_callable(&arg.ctx.i).await]) }
|
||||
}
|
||||
fn call(self, arg: ExprHandle) -> impl Future<Output = Expr> {
|
||||
fn call(self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
||||
async {
|
||||
let ctx = arg.get_ctx();
|
||||
let gcl = self.call_ref(arg).await;
|
||||
self.free(ctx);
|
||||
self.free(ctx).await;
|
||||
gcl
|
||||
}
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn command(self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<Expr>>> {
|
||||
async { Err(err_not_command().await.into()) }
|
||||
fn command(self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<GExpr>>> {
|
||||
async move { Err(err_not_command(&ctx.i).await.into()) }
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn free(self, ctx: SysCtx) -> impl Future<Output = ()> { async {} }
|
||||
@@ -245,9 +251,10 @@ pub trait DynOwnedAtom: 'static {
|
||||
fn atom_tid(&self) -> TypeId;
|
||||
fn as_any_ref(&self) -> &dyn Any;
|
||||
fn encode<'a>(&'a self, buffer: &'a mut dyn Write) -> LocalBoxFuture<'a, ()>;
|
||||
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, Expr>;
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'static, Expr>;
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, OrcRes<Option<Expr>>>;
|
||||
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, GExpr>;
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket)
|
||||
-> LocalBoxFuture<'static, GExpr>;
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, OrcRes<Option<GExpr>>>;
|
||||
fn dyn_free(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, ()>;
|
||||
fn dyn_print(&self, ctx: SysCtx) -> LocalBoxFuture<'_, String>;
|
||||
fn dyn_serialize<'a>(
|
||||
@@ -262,13 +269,17 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
fn encode<'a>(&'a self, buffer: &'a mut dyn Write) -> LocalBoxFuture<'a, ()> {
|
||||
async { self.val().await.as_ref().encode(buffer) }.boxed_local()
|
||||
}
|
||||
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, Expr> {
|
||||
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, GExpr> {
|
||||
self.call_ref(ExprHandle::from_args(ctx, arg)).boxed_local()
|
||||
}
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'static, Expr> {
|
||||
fn dyn_call(
|
||||
self: Box<Self>,
|
||||
ctx: SysCtx,
|
||||
arg: api::ExprTicket,
|
||||
) -> LocalBoxFuture<'static, GExpr> {
|
||||
self.call(ExprHandle::from_args(ctx, arg)).boxed_local()
|
||||
}
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, OrcRes<Option<Expr>>> {
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, OrcRes<Option<GExpr>>> {
|
||||
self.command(ctx).boxed_local()
|
||||
}
|
||||
fn dyn_free(self: Box<Self>, ctx: SysCtx) -> LocalBoxFuture<'static, ()> {
|
||||
@@ -287,4 +298,4 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ObjStore = Arc<IdStore<Box<dyn DynOwnedAtom>>>;
|
||||
pub type ObjStore = Rc<IdStore<Box<dyn DynOwnedAtom>>>;
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::any::{Any, TypeId, type_name};
|
||||
use std::future::Future;
|
||||
use std::io::Write;
|
||||
|
||||
use async_once_cell::OnceCell;
|
||||
use futures::FutureExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use orchid_api_traits::{Coding, enc_vec};
|
||||
@@ -11,27 +12,31 @@ use orchid_base::name::Sym;
|
||||
use crate::api;
|
||||
use crate::atom::{
|
||||
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
|
||||
err_not_callable, err_not_command, get_info,
|
||||
MethodSetBuilder, err_not_callable, err_not_command, get_info,
|
||||
};
|
||||
use crate::expr::{Expr, ExprHandle, bot};
|
||||
use crate::expr::ExprHandle;
|
||||
use crate::gen_expr::{GExpr, bot};
|
||||
use crate::system::SysCtx;
|
||||
|
||||
pub struct ThinVariant;
|
||||
impl AtomicVariant for ThinVariant {}
|
||||
impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant> for A {
|
||||
fn _factory(self) -> AtomFactory {
|
||||
AtomFactory::new(move |ctx| {
|
||||
AtomFactory::new(move |ctx| async move {
|
||||
let (id, _) = get_info::<A>(ctx.cted.inst().card());
|
||||
let mut buf = enc_vec(&id);
|
||||
self.encode(&mut buf);
|
||||
api::Atom { drop: None, data: buf, owner: ctx.id }
|
||||
})
|
||||
}
|
||||
fn _info() -> Self::_Info { ThinAtomDynfo(Self::reg_reqs()) }
|
||||
fn _info() -> Self::_Info { ThinAtomDynfo { msbuild: Self::reg_reqs(), ms: OnceCell::new() } }
|
||||
type _Info = ThinAtomDynfo<Self>;
|
||||
}
|
||||
|
||||
pub struct ThinAtomDynfo<T: ThinAtom>(MethodSet<T>);
|
||||
pub struct ThinAtomDynfo<T: ThinAtom> {
|
||||
msbuild: MethodSetBuilder<T>,
|
||||
ms: OnceCell<MethodSet<T>>,
|
||||
}
|
||||
impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
fn print<'a>(&self, AtomCtx(buf, _, ctx): AtomCtx<'a>) -> LocalBoxFuture<'a, String> {
|
||||
async move { T::decode(&mut &buf[..]).print(ctx).await }.boxed_local()
|
||||
@@ -43,7 +48,7 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
&'a self,
|
||||
AtomCtx(buf, _, ctx): AtomCtx<'a>,
|
||||
arg: api::ExprTicket,
|
||||
) -> LocalBoxFuture<'a, Expr> {
|
||||
) -> LocalBoxFuture<'a, GExpr> {
|
||||
async move { T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg)).await }
|
||||
.boxed_local()
|
||||
}
|
||||
@@ -51,7 +56,7 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
&'a self,
|
||||
AtomCtx(buf, _, ctx): AtomCtx<'a>,
|
||||
arg: api::ExprTicket,
|
||||
) -> LocalBoxFuture<'a, Expr> {
|
||||
) -> LocalBoxFuture<'a, GExpr> {
|
||||
async move { T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg)).await }
|
||||
.boxed_local()
|
||||
}
|
||||
@@ -62,13 +67,16 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
req: &'m1 mut dyn std::io::Read,
|
||||
rep: &'m2 mut dyn Write,
|
||||
) -> LocalBoxFuture<'a, bool> {
|
||||
async move { self.0.dispatch(&T::decode(&mut &buf[..]), sys, key, req, rep).await }
|
||||
.boxed_local()
|
||||
async move {
|
||||
let ms = self.ms.get_or_init(self.msbuild.pack(sys.clone())).await;
|
||||
ms.dispatch(&T::decode(&mut &buf[..]), sys, key, req, rep).await
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
fn command<'a>(
|
||||
&'a self,
|
||||
AtomCtx(buf, _, ctx): AtomCtx<'a>,
|
||||
) -> LocalBoxFuture<'a, OrcRes<Option<Expr>>> {
|
||||
) -> LocalBoxFuture<'a, OrcRes<Option<GExpr>>> {
|
||||
async move { T::decode(&mut &buf[..]).command(ctx).await }.boxed_local()
|
||||
}
|
||||
fn serialize<'a, 'b: 'a>(
|
||||
@@ -86,7 +94,7 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
|
||||
refs: &'a [api::ExprTicket],
|
||||
) -> LocalBoxFuture<'a, api::Atom> {
|
||||
assert!(refs.is_empty(), "Refs found when deserializing thin atom");
|
||||
async { T::decode(&mut &data[..])._factory().build(ctx) }.boxed_local()
|
||||
async { T::decode(&mut &data[..])._factory().build(ctx).await }.boxed_local()
|
||||
}
|
||||
fn drop<'a>(&'a self, AtomCtx(buf, _, ctx): AtomCtx<'a>) -> LocalBoxFuture<'a, ()> {
|
||||
async move {
|
||||
@@ -101,12 +109,12 @@ pub trait ThinAtom:
|
||||
AtomCard<Data = Self> + Atomic<Variant = ThinVariant> + Coding + Send + Sync + 'static
|
||||
{
|
||||
#[allow(unused_variables)]
|
||||
fn call(&self, arg: ExprHandle) -> impl Future<Output = Expr> {
|
||||
async { bot([err_not_callable().await]) }
|
||||
fn call(&self, arg: ExprHandle) -> impl Future<Output = GExpr> {
|
||||
async move { bot([err_not_callable(&arg.ctx.i).await]) }
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn command(&self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<Expr>>> {
|
||||
async { Err(err_not_command().await.into()) }
|
||||
fn command(&self, ctx: SysCtx) -> impl Future<Output = OrcRes<Option<GExpr>>> {
|
||||
async move { Err(err_not_command(&ctx.i).await.into()) }
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn print(&self, ctx: SysCtx) -> impl Future<Output = String> {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use std::future::Future;
|
||||
|
||||
use orchid_base::error::{OrcErr, OrcRes, mk_err};
|
||||
use orchid_base::intern;
|
||||
use orchid_base::interner::Interner;
|
||||
use orchid_base::location::Pos;
|
||||
|
||||
use crate::atom::{AtomicFeatures, ToAtom, TypAtom};
|
||||
use crate::expr::{Expr, atom, bot};
|
||||
use crate::expr::Expr;
|
||||
use crate::gen_expr::{GExpr, atom, bot};
|
||||
use crate::system::downcast_atom;
|
||||
|
||||
pub trait TryFromExpr: Sized {
|
||||
@@ -22,38 +23,39 @@ impl<T: TryFromExpr, U: TryFromExpr> TryFromExpr for (T, U) {
|
||||
}
|
||||
}
|
||||
|
||||
async fn err_not_atom(pos: Pos) -> OrcErr {
|
||||
mk_err(intern!(str: "Expected an atom").await, "This expression is not an atom", [pos.into()])
|
||||
async fn err_not_atom(pos: Pos, i: &Interner) -> OrcErr {
|
||||
mk_err(i.i("Expected an atom").await, "This expression is not an atom", [pos.into()])
|
||||
}
|
||||
|
||||
async fn err_type(pos: Pos) -> OrcErr {
|
||||
mk_err(intern!(str: "Type error").await, "The atom is a different type than expected", [
|
||||
pos.into()
|
||||
])
|
||||
async fn err_type(pos: Pos, i: &Interner) -> OrcErr {
|
||||
mk_err(i.i("Type error").await, "The atom is a different type than expected", [pos.into()])
|
||||
}
|
||||
|
||||
impl<A: AtomicFeatures> TryFromExpr for TypAtom<'_, A> {
|
||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||
match expr.atom().await {
|
||||
Err(ex) => Err(err_not_atom(ex.data().await.pos.clone()).await.into()),
|
||||
Err(ex) => Err(err_not_atom(ex.data().await.pos.clone(), &ex.ctx().i).await.into()),
|
||||
Ok(f) => match downcast_atom(f) {
|
||||
Ok(a) => Ok(a),
|
||||
Err(f) => Err(err_type(f.pos).await.into()),
|
||||
Err(f) => Err(err_type(f.pos(), &f.ctx().i).await.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToExpr {
|
||||
fn to_expr(self) -> Expr;
|
||||
fn to_expr(self) -> GExpr;
|
||||
}
|
||||
|
||||
impl ToExpr for GExpr {
|
||||
fn to_expr(self) -> GExpr { self }
|
||||
}
|
||||
impl ToExpr for Expr {
|
||||
fn to_expr(self) -> Expr { self }
|
||||
fn to_expr(self) -> GExpr { self.gen() }
|
||||
}
|
||||
|
||||
impl<T: ToExpr> ToExpr for OrcRes<T> {
|
||||
fn to_expr(self) -> Expr {
|
||||
fn to_expr(self) -> GExpr {
|
||||
match self {
|
||||
Err(e) => bot(e),
|
||||
Ok(t) => t.to_expr(),
|
||||
@@ -62,5 +64,5 @@ impl<T: ToExpr> ToExpr for OrcRes<T> {
|
||||
}
|
||||
|
||||
impl<A: ToAtom> ToExpr for A {
|
||||
fn to_expr(self) -> Expr { atom(self) }
|
||||
fn to_expr(self) -> GExpr { atom(self) }
|
||||
}
|
||||
|
||||
@@ -1,35 +1,41 @@
|
||||
use std::cell::RefCell;
|
||||
use std::future::Future;
|
||||
use std::io::Write;
|
||||
use std::mem;
|
||||
use std::num::NonZero;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::{mem, process, thread};
|
||||
|
||||
use async_std::channel::{Receiver, Sender};
|
||||
use async_std::stream;
|
||||
use async_std::sync::Mutex;
|
||||
use futures::FutureExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::future::{LocalBoxFuture, join_all};
|
||||
use futures::task::LocalSpawn;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use orchid_api::ApplyMacro;
|
||||
use orchid_api_traits::{Decode, Encode, enc_vec};
|
||||
use orchid_base::builtin::ExtPort;
|
||||
use orchid_base::char_filter::{char_filter_match, char_filter_union, mk_char_filter};
|
||||
use orchid_base::clone;
|
||||
use orchid_base::interner::{Tok, init_replica, sweep_replica};
|
||||
use orchid_base::interner::{Interner, Tok};
|
||||
use orchid_base::logging::Logger;
|
||||
use orchid_base::macros::{mtreev_from_api, mtreev_to_api};
|
||||
use orchid_base::name::{PathSlice, Sym};
|
||||
use orchid_base::parse::{Comment, Snippet};
|
||||
use orchid_base::reqnot::{Receipt, ReqHandlish, ReqNot, RequestHandle, Requester};
|
||||
use orchid_base::reqnot::{ReqNot, RequestHandle, Requester};
|
||||
use orchid_base::tree::{ttv_from_api, ttv_to_api};
|
||||
use substack::Substack;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo};
|
||||
use crate::atom_owned::ObjStore;
|
||||
use crate::fs::VirtFS;
|
||||
use crate::lexer::{LexContext, err_cascade, err_not_applicable};
|
||||
use crate::macros::{RuleCtx, apply_rule};
|
||||
use crate::macros::{Rule, RuleCtx};
|
||||
use crate::msg::{recv_parent_msg, send_parent_msg};
|
||||
use crate::system::{SysCtx, atom_by_idx};
|
||||
use crate::system_ctor::{CtedObj, DynSystemCtor};
|
||||
@@ -59,16 +65,26 @@ pub struct SystemRecord {
|
||||
vfses: HashMap<api::VfsId, &'static dyn VirtFS>,
|
||||
declfs: api::EagerVfs,
|
||||
lazy_members: HashMap<api::TreeId, MemberRecord>,
|
||||
rules: HashMap<api::MacroId, Rc<Rule>>,
|
||||
}
|
||||
|
||||
pub async fn with_atom_record<T>(
|
||||
get_sys_ctx: &impl Fn(api::SysId, ReqNot<api::ExtMsgSet>) -> SysCtx,
|
||||
trait_set! {
|
||||
pub trait WARCallback<'a, T> = FnOnce(
|
||||
Box<dyn AtomDynfo>,
|
||||
SysCtx,
|
||||
api::AtomId,
|
||||
&'a [u8]
|
||||
) -> LocalBoxFuture<'a, T>
|
||||
}
|
||||
|
||||
pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
|
||||
get_sys_ctx: &impl Fn(api::SysId, ReqNot<api::ExtMsgSet>) -> F,
|
||||
reqnot: ReqNot<api::ExtMsgSet>,
|
||||
atom: &api::Atom,
|
||||
cb: impl for<'c> FnOnce(Box<dyn AtomDynfo>, SysCtx, api::AtomId, &'c [u8]) -> LocalBoxFuture<'c, T>,
|
||||
atom: &'a api::Atom,
|
||||
cb: impl WARCallback<'a, T>,
|
||||
) -> T {
|
||||
let mut data = &atom.data[..];
|
||||
let ctx = get_sys_ctx(atom.owner, reqnot);
|
||||
let ctx = get_sys_ctx(atom.owner, reqnot).await;
|
||||
let inst = ctx.cted.inst();
|
||||
let id = api::AtomId::decode(&mut data);
|
||||
let atom_record = atom_by_idx(inst.card(), id).expect("Atom ID reserved");
|
||||
@@ -106,239 +122,301 @@ impl ExtPort for ExtensionOwner {
|
||||
}
|
||||
}
|
||||
|
||||
async fn extension_main_logic(data: ExtensionData, spawner: Arc<dyn LocalSpawn>) {
|
||||
async fn extension_main_logic(data: ExtensionData, spawner: Rc<dyn LocalSpawn>) {
|
||||
let api::HostHeader { log_strategy } = api::HostHeader::decode(&mut std::io::stdin().lock());
|
||||
let mut buf = Vec::new();
|
||||
let decls = (data.systems.iter().enumerate())
|
||||
.map(|(id, sys)| (u16::try_from(id).expect("more than u16max system ctors"), sys))
|
||||
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
|
||||
.collect_vec();
|
||||
let systems = Arc::new(Mutex::new(HashMap::<api::SysId, SystemRecord>::new()));
|
||||
let systems = Rc::new(Mutex::new(HashMap::<api::SysId, SystemRecord>::new()));
|
||||
api::ExtensionHeader { name: data.name.to_string(), systems: decls.clone() }.encode(&mut buf);
|
||||
std::io::stdout().write_all(&buf).unwrap();
|
||||
std::io::stdout().flush().unwrap();
|
||||
let exiting = Arc::new(AtomicBool::new(false));
|
||||
let logger = Arc::new(Logger::new(log_strategy));
|
||||
let interner_cell = Rc::new(RefCell::new(None::<Rc<Interner>>));
|
||||
let interner_weak = Rc::downgrade(&interner_cell);
|
||||
let obj_store = ObjStore::default();
|
||||
let mk_ctx = clone!(
|
||||
logger, systems;
|
||||
move |id: api::SysId, reqnot: ReqNot<api::ExtMsgSet>| async {
|
||||
let cted = systems.lock().await[&id].cted.clone();
|
||||
SysCtx { id, cted, logger, reqnot, spawner, obj_store }
|
||||
}.boxed_local()
|
||||
);
|
||||
logger, systems, spawner, obj_store, interner_weak;
|
||||
move |id: api::SysId, reqnot: ReqNot<api::ExtMsgSet>| {
|
||||
clone!(logger, systems, spawner, obj_store, interner_weak; async move {
|
||||
let cted = systems.lock().await[&id].cted.clone();
|
||||
let interner_cell = (interner_weak.upgrade())
|
||||
.expect("mk_ctx called after Interner rc dropped");
|
||||
let i = (interner_cell.borrow().clone())
|
||||
.expect("mk_ctx called before interner initialized");
|
||||
SysCtx { id, cted, logger, reqnot, spawner, obj_store, i: i.clone() }
|
||||
}.boxed_local())
|
||||
});
|
||||
let rn = ReqNot::<api::ExtMsgSet>::new(
|
||||
clone!(logger; move |a, _| async {
|
||||
clone!(logger; move |a, _| clone!(logger; async move {
|
||||
logger.log_buf("Upsending", a);
|
||||
send_parent_msg(a).await.unwrap()
|
||||
}.boxed_local()),
|
||||
clone!(systems, exiting, mk_ctx; move |n, reqnot| async {
|
||||
match n {
|
||||
api::HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
|
||||
api::HostExtNotif::SystemDrop(api::SystemDrop(sys_id)) =>
|
||||
mem::drop(systems.lock().await.remove(&sys_id)),
|
||||
api::HostExtNotif::AtomDrop(api::AtomDrop(sys_id, atom)) =>
|
||||
obj_store.get(atom.0).unwrap().remove().dyn_free(mk_ctx(sys_id, reqnot).await).await,
|
||||
}
|
||||
}.boxed_local()),
|
||||
}.boxed_local())),
|
||||
clone!(systems, exiting, mk_ctx, obj_store; move |n, reqnot| {
|
||||
clone!(systems, exiting, mk_ctx, obj_store; async move {
|
||||
match n {
|
||||
api::HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
|
||||
api::HostExtNotif::SystemDrop(api::SystemDrop(sys_id)) =>
|
||||
mem::drop(systems.lock().await.remove(&sys_id)),
|
||||
api::HostExtNotif::AtomDrop(api::AtomDrop(sys_id, atom)) =>
|
||||
obj_store.get(atom.0).unwrap().remove().dyn_free(mk_ctx(sys_id, reqnot).await).await,
|
||||
}
|
||||
}.boxed_local())
|
||||
}),
|
||||
{
|
||||
let systems = systems.clone();
|
||||
let logger = logger.clone();
|
||||
(move |hand, req| {
|
||||
async {
|
||||
let receipt: Receipt = match req {
|
||||
clone!(systems, logger, mk_ctx, interner_weak, obj_store, spawner, decls);
|
||||
move |hand, req| {
|
||||
clone!(systems, logger, mk_ctx, interner_weak, obj_store, spawner, decls);
|
||||
async move {
|
||||
let interner_cell = interner_weak.upgrade().expect("Interner dropped before request");
|
||||
let i = interner_cell.borrow().clone().expect("Request arrived before interner set");
|
||||
match req {
|
||||
api::HostExtReq::Ping(ping @ api::Ping) => hand.handle(&ping, &()).await,
|
||||
_ => panic!(),
|
||||
// api::HostExtReq::Sweep(sweep@api::Sweep) => hand.handle(&sweep,
|
||||
// &sweep_replica()).await,
|
||||
// api::HostExtReq::SysReq(api::SysReq::NewSystem(new_sys)) => {
|
||||
// let i = decls.iter().enumerate().find(|(_,s)|s.id==new_sys.system).unwrap().0;
|
||||
// let cted = data.systems[i].new_system(&new_sys);
|
||||
// let mut vfses = HashMap::new();
|
||||
// let lex_filter = cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]),
|
||||
// |cf,lx|{ let lxcf = mk_char_filter(lx.char_filter().iter().cloned());
|
||||
// char_filter_union(&cf, &lxcf)
|
||||
// });
|
||||
// let mut lazy_mems = HashMap::new();
|
||||
// let ctx = SysCtx {
|
||||
// cted:cted.clone(),id:new_sys.id,logger:logger.clone(),reqnot:hand.reqnot()
|
||||
// };
|
||||
// let mut tia_ctx = TIACtxImpl {
|
||||
// lazy: &mut lazy_mems,sys:ctx.clone(),basepath: &[],path:Substack::Bottom,
|
||||
// };
|
||||
// let const_root =
|
||||
// (cted.inst().dyn_env().into_iter()).map(|(k,v)|(k.to_api(),v.into_api(&mut
|
||||
// tia_ctx))).collect(); systems.lock().unwrap().insert(new_sys.id,
|
||||
// SystemRecord { declfs:cted.inst().dyn_vfs().to_api_rec(&mut
|
||||
// vfses),vfses,cted,lazy_members:lazy_mems });
|
||||
// hand.handle(&new_sys, &api::SystemInst {
|
||||
// lex_filter,const_root,line_types:vec![]
|
||||
// }).await
|
||||
// }
|
||||
// api::HostExtReq::GetMember(get_tree@api::GetMember(sys_id,tree_id)) => {
|
||||
// let mut systems_g = systems.lock().unwrap();
|
||||
// let sys = systems_g.get_mut(&sys_id).expect("System not found");
|
||||
// let lazy = &mut sys.lazy_members;
|
||||
// let(path,cb) = match lazy.insert(tree_id,MemberRecord::Res){
|
||||
// None => panic!("Tree for ID not found"),
|
||||
// Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
|
||||
// Some(MemberRecord::Gen(path,cb)) => (path,cb),
|
||||
|
||||
// };
|
||||
// let tree = cb.build(path.clone());
|
||||
// hand.handle(&get_tree, &tree.into_api(&mut TIACtxImpl {
|
||||
// sys:SysCtx::new(sys_id, &sys.cted,
|
||||
// &logger,hand.reqnot()),path:Substack::Bottom,basepath: &path,lazy,
|
||||
// })).await
|
||||
// }
|
||||
// api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs@api::GetVfs(sys_id))) => {
|
||||
// let systems_g = systems.lock().unwrap();
|
||||
// hand.handle(&get_vfs, &systems_g[&sys_id].declfs).await
|
||||
// }
|
||||
// api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
|
||||
// let api::SysFwded(sys_id,payload) = fwd;
|
||||
// let ctx = mk_ctx(sys_id,hand.reqnot());
|
||||
// let sys = ctx.cted.inst();
|
||||
// sys.dyn_request(hand,payload)
|
||||
// }
|
||||
// api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => {
|
||||
// let api::VfsRead(sys_id,vfs_id,path) = &vfs_read;
|
||||
// let systems_g = systems.lock().unwrap();
|
||||
// let path = path.iter().map(|t|Tok::from_api(*t)).collect_vec();
|
||||
// hand.handle(&vfs_read,
|
||||
// &systems_g[sys_id].vfses[vfs_id].load(PathSlice::new(&path))).await }
|
||||
// api::HostExtReq::LexExpr(lex@api::LexExpr {
|
||||
// sys,text,pos,id
|
||||
// }) => {
|
||||
// let systems_g = systems.lock().unwrap();
|
||||
// let lexers = systems_g[&sys].cted.inst().dyn_lexers();
|
||||
// mem::drop(systems_g);
|
||||
// let text = Tok::from_api(text);
|
||||
// let ctx = LexContext {
|
||||
// sys,id,pos,reqnot:hand.reqnot(),text: &text
|
||||
// };
|
||||
// let trigger_char = text.await.chars().nth(pos as usize).unwrap();
|
||||
// for lx in
|
||||
// lexers.iter().filter(|l|char_filter_match(l.char_filter(),trigger_char)){
|
||||
// match lx.lex(&text[pos as usize..], &ctx){
|
||||
// Err(e)if e.any(|e| *e==err_not_applicable()) => continue,
|
||||
// Err(e) => {
|
||||
// let eopt = e.keep_only(|e|
|
||||
// *e!=err_cascade()).map(|e|Err(e.to_api())); return
|
||||
// hand.handle(&lex, &eopt) },
|
||||
// Ok((s,expr)) => {
|
||||
// let ctx = mk_ctx(sys,hand.reqnot());
|
||||
// let expr = expr.to_api(&mut |f,r|do_extra(f,r,ctx.clone()));
|
||||
// let pos = (text.len()-s.len())as u32;
|
||||
// return hand.handle(&lex, &Some(Ok(api::LexedExpr {
|
||||
// pos,expr
|
||||
// })))
|
||||
// }
|
||||
|
||||
// }
|
||||
// }writeln!(logger,"Got notified about n/a character '{trigger_char}'");
|
||||
// hand.handle(&lex, &None).await
|
||||
// },
|
||||
// api::HostExtReq::ParseLine(pline) => {
|
||||
// let api::ParseLine {
|
||||
// exported,comments,sys,line
|
||||
// } = &pline;
|
||||
// let mut ctx = mk_ctx(*sys,hand.reqnot());
|
||||
// let parsers = ctx.cted.inst().dyn_parsers();
|
||||
// let comments = comments.iter().map(Comment::from_api).collect();
|
||||
// let line:Vec<GenTokTree> = ttv_from_api(line, &mut ctx);
|
||||
// let snip = Snippet::new(line.first().expect("Empty line"), &line);
|
||||
// let(head,tail) = snip.pop_front().unwrap();
|
||||
// let name = if let GenTok::Name(n) = &head.tok {
|
||||
// n
|
||||
// }else {
|
||||
// panic!("No line head")
|
||||
// };
|
||||
// let parser = parsers.iter().find(|p|p.line_head()== **name).expect("No parser
|
||||
// candidate"); let o_line = match parser.parse(*exported,comments,tail){
|
||||
// Err(e) => Err(e.to_api()),
|
||||
// Ok(t) => Ok(ttv_to_api(t, &mut |f,range|{
|
||||
// api::TokenTree {
|
||||
// range,token:api::Token::Atom(f.clone().build(ctx.clone()))
|
||||
// }
|
||||
// })),
|
||||
|
||||
// };
|
||||
// hand.handle(&pline, &o_line).await
|
||||
// }
|
||||
// api::HostExtReq::AtomReq(atom_req) => {
|
||||
// let atom = atom_req.get_atom();
|
||||
// with_atom_record(&mk_ctx,hand.reqnot(),atom, |nfo,ctx,id,buf|async {
|
||||
// let actx = AtomCtx(buf,atom.drop,ctx.clone());
|
||||
// match&atom_req {
|
||||
// api::AtomReq::SerializeAtom(ser) => {
|
||||
// let mut buf = enc_vec(&id);
|
||||
// let refs_opt = nfo.serialize(actx, &mut buf);
|
||||
// hand.handle(ser, &refs_opt.map(|refs|(buf,refs))),await
|
||||
// }
|
||||
// api::AtomReq::AtomPrint(print@api::AtomPrint(_)) => hand.handle(print,
|
||||
// &nfo.print(actx)).await, api::AtomReq::Fwded(fwded) => {
|
||||
// let api::Fwded(_,key,payload) = &fwded;
|
||||
// let mut reply = Vec::new();
|
||||
// let some = nfo.handle_req(actx,Sym::from_api(*key), &mut
|
||||
// &payload[..], &mut reply); hand.handle(fwded,
|
||||
// &some.then_some(reply)).await }
|
||||
// api::AtomReq::CallRef(call@api::CallRef(_,arg)) => {
|
||||
// let ret = nfo.call_ref(actx, *arg);
|
||||
// hand.handle(call, &ret.api_return(ctx.clone(), &mut
|
||||
// |h|hand.defer_drop(h))).await },
|
||||
// api::AtomReq::FinalCall(call@api::FinalCall(_,arg)) => {
|
||||
// let ret = nfo.call(actx, *arg);
|
||||
// hand.handle(call, &ret.api_return(ctx.clone(), &mut
|
||||
// |h|hand.defer_drop(h))).await }
|
||||
// api::AtomReq::Command(cmd@api::Command(_)) => {
|
||||
// hand.handle(cmd, &match nfo.command(actx){
|
||||
// Err(e) => Err(e.to_api()),
|
||||
// Ok(opt) => Ok(match opt {
|
||||
// None => api::NextStep::Halt,
|
||||
// Some(cont) =>
|
||||
// api::NextStep::Continue(cont.api_return(ctx.clone(), &mut |h|hand.defer_drop(h))),
|
||||
|
||||
// })
|
||||
|
||||
// }).await
|
||||
// }
|
||||
|
||||
// }
|
||||
// }).await
|
||||
// },
|
||||
// api::HostExtReq::DeserAtom(deser) => {
|
||||
// let api::DeserAtom(sys,buf,refs) = &deser;
|
||||
// let mut read = &mut &buf[..];
|
||||
// let ctx = mk_ctx(*sys,hand.reqnot());
|
||||
// let id = api::AtomId::decode(&mut read);
|
||||
// let inst = ctx.cted.inst();
|
||||
// let nfo = atom_by_idx(inst.card(),id).expect("Deserializing atom with invalid
|
||||
// ID"); hand.handle(&deser, &nfo.deserialize(ctx.clone(),read,refs)).await
|
||||
// },
|
||||
// orchid_api::HostExtReq::ApplyMacro(am) => {
|
||||
// let tok = hand.will_handle_as(&am);
|
||||
// let sys_ctx = mk_ctx(am.sys,hand.reqnot());
|
||||
// let ctx = RuleCtx {
|
||||
// args:(am.params.into_iter()).map(|(k,v)|(Tok::from_api(k),mtreev_from_api(&v,
|
||||
// &mut |_|panic!("No atom in macro
|
||||
// prompt!")))).collect(),run_id:am.run_id,sys:sys_ctx.clone(), };
|
||||
// hand.handle_as(tok, &match apply_rule(am.id,ctx){
|
||||
// Err(e) => e.keep_only(|e| *e!=err_cascade()).map(|e|Err(e.to_api())),
|
||||
// Ok(t) => Some(Ok(mtreev_to_api(&t, &mut |a|{
|
||||
// api::MacroToken::Atom(a.clone().build(sys_ctx.clone()))
|
||||
// }))),
|
||||
|
||||
// }).await
|
||||
// }
|
||||
};
|
||||
receipt
|
||||
api::HostExtReq::Sweep(sweep @ api::Sweep) =>
|
||||
hand.handle(&sweep, &i.sweep_replica().await).await,
|
||||
api::HostExtReq::SysReq(api::SysReq::NewSystem(new_sys)) => {
|
||||
let (sys_id, _) = (decls.iter().enumerate().find(|(_, s)| s.id == new_sys.system))
|
||||
.expect("NewSystem call received for invalid system");
|
||||
let cted = data.systems[sys_id].new_system(&new_sys);
|
||||
let mut vfses = HashMap::new();
|
||||
let lex_filter =
|
||||
cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf, lx| {
|
||||
char_filter_union(&cf, &mk_char_filter(lx.char_filter().iter().cloned()))
|
||||
});
|
||||
let lazy_mems = Mutex::new(HashMap::new());
|
||||
let rules = Mutex::new(HashMap::new());
|
||||
let ctx = SysCtx {
|
||||
cted: cted.clone(),
|
||||
id: new_sys.id,
|
||||
logger: logger.clone(),
|
||||
reqnot: hand.reqnot(),
|
||||
i: i.clone(),
|
||||
obj_store: obj_store.clone(),
|
||||
spawner: spawner.clone(),
|
||||
};
|
||||
let const_root = stream::from_iter(cted.inst().dyn_env())
|
||||
.then(|(k, v)| {
|
||||
let (req, lazy_mems, rules) = (&hand, &lazy_mems, &rules);
|
||||
clone!(i, ctx; async move {
|
||||
let name = i.i::<String>(&k).await.to_api();
|
||||
let value = v.into_api(&mut TIACtxImpl {
|
||||
lazy_members: &mut *lazy_mems.lock().await,
|
||||
rules: &mut *rules.lock().await,
|
||||
sys: ctx,
|
||||
basepath: &[],
|
||||
path: Substack::Bottom,
|
||||
req
|
||||
})
|
||||
.await;
|
||||
(name, value)
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
.await;
|
||||
let declfs = cted.inst().dyn_vfs().to_api_rec(&mut vfses, &i).await;
|
||||
let record = SystemRecord {
|
||||
declfs,
|
||||
vfses,
|
||||
cted,
|
||||
lazy_members: lazy_mems.into_inner(),
|
||||
rules: rules.into_inner(),
|
||||
};
|
||||
systems.lock().await.insert(new_sys.id, record);
|
||||
hand
|
||||
.handle(&new_sys, &api::SystemInst { lex_filter, const_root, line_types: vec![] })
|
||||
.await
|
||||
},
|
||||
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
|
||||
let sys_ctx = mk_ctx(sys_id, hand.reqnot()).await;
|
||||
let mut systems_g = systems.lock().await;
|
||||
let SystemRecord { lazy_members, rules, .. } =
|
||||
systems_g.get_mut(&sys_id).expect("System not found");
|
||||
let (path, cb) = match lazy_members.insert(tree_id, MemberRecord::Res) {
|
||||
None => panic!("Tree for ID not found"),
|
||||
Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
|
||||
Some(MemberRecord::Gen(path, cb)) => (path, cb),
|
||||
};
|
||||
let tree = cb.build(Sym::new(path.clone(), &i).await.unwrap()).await;
|
||||
let mut tia_ctx = TIACtxImpl {
|
||||
sys: sys_ctx,
|
||||
path: Substack::Bottom,
|
||||
basepath: &path,
|
||||
lazy_members,
|
||||
rules,
|
||||
req: &hand,
|
||||
};
|
||||
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
|
||||
},
|
||||
api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs @ api::GetVfs(sys_id))) => {
|
||||
let systems_g = systems.lock().await;
|
||||
hand.handle(&get_vfs, &systems_g[&sys_id].declfs).await
|
||||
},
|
||||
api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => {
|
||||
let api::SysFwded(sys_id, payload) = fwd;
|
||||
let ctx = mk_ctx(sys_id, hand.reqnot()).await;
|
||||
let sys = ctx.cted.inst();
|
||||
sys.dyn_request(hand, payload).await
|
||||
},
|
||||
api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => {
|
||||
let api::VfsRead(sys_id, vfs_id, path) = &vfs_read;
|
||||
let ctx = mk_ctx(*sys_id, hand.reqnot()).await;
|
||||
let systems_g = systems.lock().await;
|
||||
let path = join_all(path.iter().map(|t| Tok::from_api(*t, &i))).await;
|
||||
let vfs = systems_g[sys_id].vfses[vfs_id].load(PathSlice::new(&path), ctx).await;
|
||||
hand.handle(&vfs_read, &vfs).await
|
||||
},
|
||||
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, text, pos, id }) => {
|
||||
let systems_g = systems.lock().await;
|
||||
let lexers = systems_g[&sys].cted.inst().dyn_lexers();
|
||||
mem::drop(systems_g);
|
||||
let text = Tok::from_api(text, &i).await;
|
||||
let ctx = LexContext { sys, id, pos, reqnot: hand.reqnot(), text: &text, i: &i };
|
||||
let trigger_char = text.chars().nth(pos as usize).unwrap();
|
||||
let err_na = err_not_applicable(&i).await;
|
||||
let err_cascade = err_cascade(&i).await;
|
||||
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char)) {
|
||||
match lx.lex(&text[pos as usize..], &ctx).await {
|
||||
Err(e) if e.any(|e| *e == err_na) => continue,
|
||||
Err(e) => {
|
||||
let eopt = e.keep_only(|e| *e != err_cascade).map(|e| Err(e.to_api()));
|
||||
return hand.handle(&lex, &eopt).await;
|
||||
},
|
||||
Ok((s, expr)) => {
|
||||
let ctx = mk_ctx(sys, hand.reqnot()).await;
|
||||
let expr = expr
|
||||
.to_api(&mut |f, r| {
|
||||
clone!(ctx; async move { do_extra(f, r, ctx).await }).boxed_local()
|
||||
})
|
||||
.await;
|
||||
let pos = (text.len() - s.len()) as u32;
|
||||
return hand.handle(&lex, &Some(Ok(api::LexedExpr { pos, expr }))).await;
|
||||
},
|
||||
}
|
||||
}
|
||||
writeln!(logger, "Got notified about n/a character '{trigger_char}'");
|
||||
hand.handle(&lex, &None).await
|
||||
},
|
||||
api::HostExtReq::ParseLine(pline) => {
|
||||
let api::ParseLine { exported, comments, sys, line } = &pline;
|
||||
let mut ctx = mk_ctx(*sys, hand.reqnot()).await;
|
||||
let parsers = ctx.cted.inst().dyn_parsers();
|
||||
let comments = join_all(comments.iter().map(|c| Comment::from_api(c, &i))).await;
|
||||
let line: Vec<GenTokTree> = ttv_from_api(line, &mut ctx, &i).await;
|
||||
let snip = Snippet::new(line.first().expect("Empty line"), &line, &i);
|
||||
let (head, tail) = snip.pop_front().unwrap();
|
||||
let name = if let GenTok::Name(n) = &head.tok { n } else { panic!("No line head") };
|
||||
let parser =
|
||||
parsers.iter().find(|p| p.line_head() == **name).expect("No parser candidate");
|
||||
let o_line = match parser.parse(*exported, comments, tail) {
|
||||
Err(e) => Err(e.to_api()),
|
||||
Ok(t) => Ok(
|
||||
ttv_to_api(t, &mut |f, range| {
|
||||
clone!(ctx);
|
||||
async move {
|
||||
api::TokenTree { range, token: api::Token::Atom(f.clone().build(ctx).await) }
|
||||
}
|
||||
.boxed_local()
|
||||
})
|
||||
.await,
|
||||
),
|
||||
};
|
||||
hand.handle(&pline, &o_line).await
|
||||
},
|
||||
api::HostExtReq::AtomReq(atom_req) => {
|
||||
let atom = atom_req.get_atom();
|
||||
let atom_req = atom_req.clone();
|
||||
with_atom_record(&mk_ctx, hand.reqnot(), atom, move |nfo, ctx, id, buf| {
|
||||
async move {
|
||||
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
||||
match &atom_req {
|
||||
api::AtomReq::SerializeAtom(ser) => {
|
||||
let mut buf = enc_vec(&id);
|
||||
let refs_opt = nfo.serialize(actx, &mut buf).await;
|
||||
hand.handle(ser, &refs_opt.map(|refs| (buf, refs))).await
|
||||
},
|
||||
api::AtomReq::AtomPrint(print @ api::AtomPrint(_)) =>
|
||||
hand.handle(print, &nfo.print(actx).await).await,
|
||||
api::AtomReq::Fwded(fwded) => {
|
||||
let api::Fwded(_, key, payload) = &fwded;
|
||||
let mut reply = Vec::new();
|
||||
let key = Sym::from_api(*key, &i).await;
|
||||
let some = nfo.handle_req(actx, key, &mut &payload[..], &mut reply).await;
|
||||
hand.handle(fwded, &some.then_some(reply)).await
|
||||
},
|
||||
api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => {
|
||||
let ret = nfo.call_ref(actx, *arg).await;
|
||||
hand.handle(call, &ret.api_return(ctx.clone(), &hand).await).await
|
||||
},
|
||||
api::AtomReq::FinalCall(call @ api::FinalCall(_, arg)) => {
|
||||
let ret = nfo.call(actx, *arg).await;
|
||||
hand.handle(call, &ret.api_return(ctx.clone(), &hand).await).await
|
||||
},
|
||||
api::AtomReq::Command(cmd @ api::Command(_)) => match nfo.command(actx).await {
|
||||
Err(e) => hand.handle(cmd, &Err(e.to_api())).await,
|
||||
Ok(opt) => match opt {
|
||||
None => hand.handle(cmd, &Ok(api::NextStep::Halt)).await,
|
||||
Some(cont) => {
|
||||
let cont = cont.api_return(ctx.clone(), &hand).await;
|
||||
hand.handle(cmd, &Ok(api::NextStep::Continue(cont))).await
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
.boxed_local()
|
||||
})
|
||||
.await
|
||||
},
|
||||
api::HostExtReq::DeserAtom(deser) => {
|
||||
let api::DeserAtom(sys, buf, refs) = &deser;
|
||||
let mut read = &mut &buf[..];
|
||||
let ctx = mk_ctx(*sys, hand.reqnot()).await;
|
||||
let id = api::AtomId::decode(&mut read);
|
||||
let inst = ctx.cted.inst();
|
||||
let nfo = atom_by_idx(inst.card(), id).expect("Deserializing atom with invalid ID");
|
||||
hand.handle(&deser, &nfo.deserialize(ctx.clone(), read, refs).await).await
|
||||
},
|
||||
orchid_api::HostExtReq::ApplyMacro(am) => {
|
||||
let tok = hand.will_handle_as(&am);
|
||||
let ApplyMacro { id, params, run_id, sys } = am;
|
||||
let sys_ctx = mk_ctx(sys, hand.reqnot()).await;
|
||||
let mut ctx =
|
||||
RuleCtx { args: ahash::HashMap::default(), run_id, sys: sys_ctx.clone() };
|
||||
for (k, v) in params {
|
||||
ctx.args.insert(
|
||||
Tok::from_api(k, &i).await,
|
||||
mtreev_from_api(&v, &mut |_| panic!("No atom in macro prompt!"), &i).await,
|
||||
);
|
||||
}
|
||||
let err_cascade = err_cascade(&i).await;
|
||||
let systems_g = systems.lock().await;
|
||||
let rule = &systems_g[&sys].rules[&id];
|
||||
match (rule.apply)(ctx).await {
|
||||
Err(e) => {
|
||||
let new_errors = e.keep_only(|e| *e != err_cascade);
|
||||
hand.handle_as(tok, &new_errors.map(|e| Err(e.to_api()))).await
|
||||
},
|
||||
Ok(t) => {
|
||||
let result = mtreev_to_api(&t, &mut |a| {
|
||||
clone!(sys_ctx; async move {
|
||||
api::MacroToken::Atom(a.clone().build(sys_ctx.clone()).await)
|
||||
}.boxed_local())
|
||||
})
|
||||
.await;
|
||||
hand.handle_as(tok, &Some(Ok(result))).await
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
.boxed_local()
|
||||
})
|
||||
}
|
||||
},
|
||||
);
|
||||
init_replica(rn.clone().map());
|
||||
*interner_cell.borrow_mut() = Some(Rc::new(Interner::new_replica(rn.clone().map())));
|
||||
while !exiting.load(Ordering::Relaxed) {
|
||||
let rcvd = recv_parent_msg().await.unwrap();
|
||||
rn.receive(&rcvd).await
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use std::rc::Rc;
|
||||
|
||||
use async_once_cell::OnceCell;
|
||||
use derive_destructure::destructure;
|
||||
use futures::task::LocalSpawnExt;
|
||||
use orchid_base::error::{OrcErr, OrcErrv};
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::error::OrcErrv;
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::reqnot::Requester;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomFactory, ForeignAtom, ToAtom};
|
||||
use crate::conv::{ToExpr, TryFromExpr};
|
||||
use crate::func_atom::Lambda;
|
||||
use crate::atom::ForeignAtom;
|
||||
use crate::gen_expr::{GExpr, GExprKind};
|
||||
use crate::system::SysCtx;
|
||||
|
||||
#[derive(destructure)]
|
||||
@@ -31,7 +29,11 @@ impl fmt::Debug for ExprHandle {
|
||||
}
|
||||
impl Clone for ExprHandle {
|
||||
fn clone(&self) -> Self {
|
||||
self.ctx.reqnot.notify(api::Acquire(self.ctx.id, self.tk));
|
||||
let SysCtx { reqnot, spawner, .. } = self.ctx.clone();
|
||||
let notif = api::Acquire(self.ctx.id, self.tk);
|
||||
if let Err(e) = spawner.spawn_local(async move { reqnot.notify(notif).await }) {
|
||||
panic!("Failed to schedule cloning notification, resource may not exist: {e}");
|
||||
}
|
||||
Self { ctx: self.ctx.clone(), tk: self.tk }
|
||||
}
|
||||
}
|
||||
@@ -47,25 +49,24 @@ impl Drop for ExprHandle {
|
||||
|
||||
#[derive(Clone, Debug, destructure)]
|
||||
pub struct Expr {
|
||||
handle: Option<Arc<ExprHandle>>,
|
||||
data: Arc<OnceCell<ExprData>>,
|
||||
handle: Rc<ExprHandle>,
|
||||
data: Rc<OnceCell<ExprData>>,
|
||||
}
|
||||
impl Expr {
|
||||
pub fn new(h: Arc<ExprHandle>, d: ExprData) -> Self {
|
||||
Self { handle: Some(h), data: Arc::new(OnceCell::from(d)) }
|
||||
pub fn from_handle(handle: Rc<ExprHandle>) -> Self { Self { handle, data: Rc::default() } }
|
||||
pub fn new(handle: Rc<ExprHandle>, d: ExprData) -> Self {
|
||||
Self { handle, data: Rc::new(OnceCell::from(d)) }
|
||||
}
|
||||
pub fn from_handle(h: Arc<ExprHandle>) -> Self { Self { handle: Some(h), data: Arc::default() } }
|
||||
pub fn from_data(d: ExprData) -> Self { Self { handle: None, data: Arc::new(OnceCell::from(d)) } }
|
||||
|
||||
pub async fn data(&self) -> &ExprData {
|
||||
(self.data.get_or_init(async {
|
||||
let handle = self.handle.as_ref().expect("Either the value or the handle must be set");
|
||||
let details = handle.ctx.reqnot.request(api::Inspect { target: handle.tk }).await;
|
||||
let pos = Pos::from_api(&details.location).await;
|
||||
let details = self.handle.ctx.reqnot.request(api::Inspect { target: self.handle.tk }).await;
|
||||
let pos = Pos::from_api(&details.location, &self.handle.ctx.i).await;
|
||||
let kind = match details.kind {
|
||||
api::InspectedKind::Atom(a) =>
|
||||
ExprKind::Atom(ForeignAtom::new(handle.clone(), a, pos.clone())),
|
||||
api::InspectedKind::Bottom(b) => ExprKind::Bottom(OrcErrv::from_api(&b).await),
|
||||
ExprKind::Atom(ForeignAtom::new(self.handle.clone(), a, pos.clone())),
|
||||
api::InspectedKind::Bottom(b) =>
|
||||
ExprKind::Bottom(OrcErrv::from_api(&b, &self.handle.ctx.i).await),
|
||||
api::InspectedKind::Opaque => ExprKind::Opaque,
|
||||
};
|
||||
ExprData { pos, kind }
|
||||
@@ -73,25 +74,15 @@ impl Expr {
|
||||
.await
|
||||
}
|
||||
pub async fn atom(self) -> Result<ForeignAtom<'static>, Self> {
|
||||
match (self.data().await, &self.handle) {
|
||||
(ExprData { kind: ExprKind::Atom(atom), .. }, Some(_)) => Ok(atom.clone()),
|
||||
match self.data().await {
|
||||
ExprData { kind: ExprKind::Atom(atom), .. } => Ok(atom.clone()),
|
||||
_ => Err(self),
|
||||
}
|
||||
}
|
||||
pub fn api_return(
|
||||
self,
|
||||
ctx: SysCtx,
|
||||
do_slot: &mut impl FnMut(Arc<ExprHandle>),
|
||||
) -> api::Expression {
|
||||
if let Some(h) = self.handle {
|
||||
do_slot(h.clone());
|
||||
api::Expression { location: api::Location::SlotTarget, kind: api::ExpressionKind::Slot(h.tk) }
|
||||
} else {
|
||||
let data = self.data.get().expect("Either value or handle must be set");
|
||||
data.clone().api_return(ctx, do_slot)
|
||||
}
|
||||
}
|
||||
pub fn handle(&self) -> Option<Arc<ExprHandle>> { self.handle.clone() }
|
||||
pub fn handle(&self) -> Rc<ExprHandle> { self.handle.clone() }
|
||||
pub fn ctx(&self) -> SysCtx { self.handle.ctx.clone() }
|
||||
|
||||
pub fn gen(&self) -> GExpr { GExpr { pos: Pos::SlotTarget, kind: GExprKind::Slot(self.clone()) } }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -99,84 +90,10 @@ pub struct ExprData {
|
||||
pub pos: Pos,
|
||||
pub kind: ExprKind,
|
||||
}
|
||||
impl ExprData {
|
||||
pub fn api_return(
|
||||
self,
|
||||
ctx: SysCtx,
|
||||
do_slot: &mut impl FnMut(Arc<ExprHandle>),
|
||||
) -> api::Expression {
|
||||
api::Expression { location: self.pos.to_api(), kind: self.kind.api_return(ctx, do_slot) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ExprKind {
|
||||
Call(Box<Expr>, Box<Expr>),
|
||||
Lambda(u64, Box<Expr>),
|
||||
Arg(u64),
|
||||
Seq(Box<Expr>, Box<Expr>),
|
||||
Const(Tok<Vec<Tok<String>>>),
|
||||
NewAtom(AtomFactory),
|
||||
Atom(ForeignAtom<'static>),
|
||||
Bottom(OrcErrv),
|
||||
Opaque,
|
||||
}
|
||||
impl ExprKind {
|
||||
pub fn api_return(
|
||||
self,
|
||||
ctx: SysCtx,
|
||||
do_slot: &mut impl FnMut(Arc<ExprHandle>),
|
||||
) -> api::ExpressionKind {
|
||||
use api::ExpressionKind as K;
|
||||
match self {
|
||||
Self::Call(f, x) =>
|
||||
K::Call(Box::new(f.api_return(ctx.clone(), do_slot)), Box::new(x.api_return(ctx, do_slot))),
|
||||
Self::Seq(a, b) =>
|
||||
K::Seq(Box::new(a.api_return(ctx.clone(), do_slot)), Box::new(b.api_return(ctx, do_slot))),
|
||||
Self::Lambda(arg, body) => K::Lambda(arg, Box::new(body.api_return(ctx, do_slot))),
|
||||
Self::Arg(arg) => K::Arg(arg),
|
||||
Self::Const(name) => K::Const(name.to_api()),
|
||||
Self::Bottom(err) => K::Bottom(err.to_api()),
|
||||
Self::NewAtom(fac) => K::NewAtom(fac.clone().build(ctx)),
|
||||
kind @ (Self::Atom(_) | Self::Opaque) => panic!("{kind:?} should have a token"),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn inherit(kind: ExprKind) -> Expr { Expr::from_data(ExprData { pos: Pos::Inherit, kind }) }
|
||||
|
||||
pub fn sym_ref(path: Tok<Vec<Tok<String>>>) -> Expr { inherit(ExprKind::Const(path)) }
|
||||
pub fn atom<A: ToAtom>(atom: A) -> Expr { inherit(ExprKind::NewAtom(atom.to_atom_factory())) }
|
||||
|
||||
pub fn seq(ops: impl IntoIterator<Item = Expr>) -> Expr {
|
||||
fn recur(mut ops: impl Iterator<Item = Expr>) -> Option<Expr> {
|
||||
let op = ops.next()?;
|
||||
Some(match recur(ops) {
|
||||
None => op,
|
||||
Some(rec) => inherit(ExprKind::Seq(Box::new(op), Box::new(rec))),
|
||||
})
|
||||
}
|
||||
recur(ops.into_iter()).expect("Empty list provided to seq!")
|
||||
}
|
||||
|
||||
pub fn arg(n: u64) -> Expr { inherit(ExprKind::Arg(n)) }
|
||||
|
||||
pub fn lambda(n: u64, b: impl IntoIterator<Item = Expr>) -> Expr {
|
||||
inherit(ExprKind::Lambda(n, Box::new(call(b))))
|
||||
}
|
||||
|
||||
pub fn call(v: impl IntoIterator<Item = Expr>) -> Expr {
|
||||
v.into_iter()
|
||||
.reduce(|f, x| inherit(ExprKind::Call(Box::new(f), Box::new(x))))
|
||||
.expect("Empty call expression")
|
||||
}
|
||||
|
||||
pub fn bot(ev: impl IntoIterator<Item = OrcErr>) -> Expr {
|
||||
inherit(ExprKind::Bottom(OrcErrv::new(ev).unwrap()))
|
||||
}
|
||||
|
||||
pub fn with<I: TryFromExpr, O: ToExpr>(
|
||||
expr: Expr,
|
||||
cont: impl Fn(I) -> O + Clone + Send + Sync + 'static,
|
||||
) -> Expr {
|
||||
call([lambda(0, [seq([arg(0), call([Lambda::new(cont).to_expr(), arg(0)])])]), expr])
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
use std::future::{Future, ready};
|
||||
use std::num::NonZero;
|
||||
|
||||
use futures::FutureExt;
|
||||
use futures::future::{join, join_all};
|
||||
use futures::future::LocalBoxFuture;
|
||||
use hashbrown::HashMap;
|
||||
use orchid_base::interner::intern;
|
||||
use orchid_base::interner::Interner;
|
||||
use orchid_base::name::PathSlice;
|
||||
|
||||
use crate::api;
|
||||
use crate::system::SysCtx;
|
||||
|
||||
pub trait VirtFS: Send + Sync + 'static {
|
||||
fn load(&self, path: &PathSlice) -> api::OrcResult<api::Loaded>;
|
||||
fn load<'a>(
|
||||
&'a self,
|
||||
path: &'a PathSlice,
|
||||
ctx: SysCtx,
|
||||
) -> LocalBoxFuture<'a, api::OrcResult<api::Loaded>>;
|
||||
}
|
||||
|
||||
pub enum DeclFs {
|
||||
@@ -18,26 +22,25 @@ pub enum DeclFs {
|
||||
Mod(&'static [(&'static str, DeclFs)]),
|
||||
}
|
||||
impl DeclFs {
|
||||
pub fn to_api_rec(
|
||||
pub async fn to_api_rec(
|
||||
&self,
|
||||
vfses: &mut HashMap<api::VfsId, &'static dyn VirtFS>,
|
||||
) -> impl Future<Output = api::EagerVfs> + '_ {
|
||||
i: &Interner,
|
||||
) -> api::EagerVfs {
|
||||
match self {
|
||||
DeclFs::Lazy(fs) => {
|
||||
let vfsc: u16 = vfses.len().try_into().expect("too many vfses (more than u16::MAX)");
|
||||
let id = api::VfsId(NonZero::new(vfsc + 1).unwrap());
|
||||
vfses.insert(id, *fs);
|
||||
ready(api::EagerVfs::Lazy(id)).boxed_local()
|
||||
api::EagerVfs::Lazy(id)
|
||||
},
|
||||
DeclFs::Mod(children) => {
|
||||
let promises: Vec<_> =
|
||||
children.iter().map(|(k, v)| join(intern(*k), v.to_api_rec(vfses))).collect();
|
||||
async {
|
||||
api::EagerVfs::Eager(
|
||||
join_all(promises).await.into_iter().map(|(k, v)| (k.to_api(), v)).collect(),
|
||||
)
|
||||
let mut output = std::collections::HashMap::new();
|
||||
for (k, v) in children.iter() {
|
||||
output
|
||||
.insert(i.i::<String>(*k).await.to_api(), v.to_api_rec(vfses, i).boxed_local().await);
|
||||
}
|
||||
.boxed_local()
|
||||
api::EagerVfs::Eager(output)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::rc::Rc;
|
||||
|
||||
use async_std::sync::Mutex;
|
||||
use futures::FutureExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use never::Never;
|
||||
use orchid_api_traits::Encode;
|
||||
use orchid_base::clone;
|
||||
@@ -15,23 +15,24 @@ use orchid_base::error::OrcRes;
|
||||
use orchid_base::name::Sym;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::atom::{Atomic, MethodSet};
|
||||
use crate::atom::{Atomic, MethodSetBuilder};
|
||||
use crate::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::expr::{Expr, ExprHandle};
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::system::SysCtx;
|
||||
|
||||
trait_set! {
|
||||
trait FunCB = Fn(Vec<Expr>) -> LocalBoxFuture<'static, OrcRes<Expr>> + Send + Sync + 'static;
|
||||
trait FunCB = Fn(Vec<Expr>) -> LocalBoxFuture<'static, OrcRes<GExpr>> + 'static;
|
||||
}
|
||||
|
||||
pub trait ExprFunc<I, O>: Clone + Send + Sync + 'static {
|
||||
pub trait ExprFunc<I, O>: Clone + 'static {
|
||||
const ARITY: u8;
|
||||
fn apply(&self, v: Vec<Expr>) -> impl Future<Output = OrcRes<Expr>>;
|
||||
fn apply(&self, v: Vec<Expr>) -> impl Future<Output = OrcRes<GExpr>>;
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref FUNS: Mutex<HashMap<Sym, (u8, Arc<dyn FunCB>)>> = Mutex::default();
|
||||
thread_local! {
|
||||
static FUNS: Rc<Mutex<HashMap<Sym, (u8, Rc<dyn FunCB>)>>> = Rc::default();
|
||||
}
|
||||
|
||||
/// An Atom representing a partially applied named native function. These
|
||||
@@ -44,15 +45,16 @@ pub(crate) struct Fun {
|
||||
path: Sym,
|
||||
args: Vec<Expr>,
|
||||
arity: u8,
|
||||
fun: Arc<dyn FunCB>,
|
||||
fun: Rc<dyn FunCB>,
|
||||
}
|
||||
impl Fun {
|
||||
pub fn new<I, O, F: ExprFunc<I, O>>(path: Sym, f: F) -> Self {
|
||||
let mut fung = FUNS.lock().unwrap();
|
||||
pub async fn new<I, O, F: ExprFunc<I, O>>(path: Sym, f: F) -> Self {
|
||||
let funs = FUNS.with(|funs| funs.clone());
|
||||
let mut fung = funs.lock().await;
|
||||
let fun = if let Some(x) = fung.get(&path) {
|
||||
x.1.clone()
|
||||
} else {
|
||||
let fun = Arc::new(move |v| clone!(f; async move { f.apply(v).await }.boxed_local()));
|
||||
let fun = Rc::new(move |v| clone!(f; async move { f.apply(v).await }.boxed_local()));
|
||||
fung.insert(path.clone(), (F::ARITY, fun.clone()));
|
||||
fun
|
||||
};
|
||||
@@ -62,14 +64,13 @@ impl Fun {
|
||||
impl Atomic for Fun {
|
||||
type Data = ();
|
||||
type Variant = OwnedVariant;
|
||||
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new() }
|
||||
}
|
||||
impl OwnedAtom for Fun {
|
||||
type Refs = Vec<Expr>;
|
||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
async fn call_ref(&self, arg: ExprHandle) -> Expr {
|
||||
let new_args =
|
||||
self.args.iter().cloned().chain([Expr::from_handle(Arc::new(arg))]).collect_vec();
|
||||
async fn call_ref(&self, arg: ExprHandle) -> GExpr {
|
||||
let new_args = self.args.iter().cloned().chain([Expr::from_handle(Rc::new(arg))]).collect_vec();
|
||||
if new_args.len() == self.arity.into() {
|
||||
(self.fun)(new_args).await.to_expr()
|
||||
} else {
|
||||
@@ -77,14 +78,15 @@ impl OwnedAtom for Fun {
|
||||
.to_expr()
|
||||
}
|
||||
}
|
||||
async fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg).await }
|
||||
async fn call(self, arg: ExprHandle) -> GExpr { self.call_ref(arg).await }
|
||||
async fn serialize(&self, _: SysCtx, sink: &mut (impl io::Write + ?Sized)) -> Self::Refs {
|
||||
self.path.to_api().encode(sink);
|
||||
self.args.clone()
|
||||
}
|
||||
async fn deserialize(ctx: impl DeserializeCtx, args: Self::Refs) -> Self {
|
||||
let path = Sym::from_api(ctx.decode()).await;
|
||||
let (arity, fun) = FUNS.lock().unwrap().get(&path).unwrap().clone();
|
||||
let sys = ctx.sys();
|
||||
let path = Sym::from_api(ctx.decode(), &sys.i).await;
|
||||
let (arity, fun) = FUNS.with(|f| f.clone()).lock().await.get(&path).unwrap().clone();
|
||||
Self { args, arity, path, fun }
|
||||
}
|
||||
}
|
||||
@@ -97,32 +99,31 @@ impl OwnedAtom for Fun {
|
||||
pub struct Lambda {
|
||||
args: Vec<Expr>,
|
||||
arity: u8,
|
||||
fun: Arc<dyn FunCB>,
|
||||
fun: Rc<dyn FunCB>,
|
||||
}
|
||||
impl Lambda {
|
||||
pub fn new<I, O, F: ExprFunc<I, O>>(f: F) -> Self {
|
||||
let fun = Arc::new(move |v| clone!(f; async move { f.apply(v).await }.boxed_local()));
|
||||
let fun = Rc::new(move |v| clone!(f; async move { f.apply(v).await }.boxed_local()));
|
||||
Self { args: vec![], arity: F::ARITY, fun }
|
||||
}
|
||||
}
|
||||
impl Atomic for Lambda {
|
||||
type Data = ();
|
||||
type Variant = OwnedVariant;
|
||||
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new() }
|
||||
}
|
||||
impl OwnedAtom for Lambda {
|
||||
type Refs = Never;
|
||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
async fn call_ref(&self, arg: ExprHandle) -> Expr {
|
||||
let new_args =
|
||||
self.args.iter().cloned().chain([Expr::from_handle(Arc::new(arg))]).collect_vec();
|
||||
async fn call_ref(&self, arg: ExprHandle) -> GExpr {
|
||||
let new_args = self.args.iter().cloned().chain([Expr::from_handle(Rc::new(arg))]).collect_vec();
|
||||
if new_args.len() == self.arity.into() {
|
||||
(self.fun)(new_args).await.to_expr()
|
||||
} else {
|
||||
Self { args: new_args, arity: self.arity, fun: self.fun.clone() }.to_expr()
|
||||
}
|
||||
}
|
||||
async fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg).await }
|
||||
async fn call(self, arg: ExprHandle) -> GExpr { self.call_ref(arg).await }
|
||||
}
|
||||
|
||||
mod expr_func_derives {
|
||||
@@ -131,6 +132,7 @@ mod expr_func_derives {
|
||||
use super::ExprFunc;
|
||||
use crate::conv::{ToExpr, TryFromExpr};
|
||||
use crate::func_atom::Expr;
|
||||
use crate::gen_expr::GExpr;
|
||||
|
||||
macro_rules! expr_func_derive {
|
||||
($arity: tt, $($t:ident),*) => {
|
||||
@@ -141,7 +143,7 @@ mod expr_func_derives {
|
||||
Func: Fn($($t,)*) -> Out + Clone + Send + Sync + 'static
|
||||
> ExprFunc<($($t,)*), Out> for Func {
|
||||
const ARITY: u8 = $arity;
|
||||
async fn apply(&self, v: Vec<Expr>) -> OrcRes<Expr> {
|
||||
async fn apply(&self, v: Vec<Expr>) -> OrcRes<GExpr> {
|
||||
assert_eq!(v.len(), Self::ARITY.into(), "Arity mismatch");
|
||||
let [$([< $t:lower >],)*] = v.try_into().unwrap_or_else(|_| panic!("Checked above"));
|
||||
Ok(self($($t::try_from_expr([< $t:lower >]).await?,)*).to_expr())
|
||||
|
||||
106
orchid-extension/src/gen_expr.rs
Normal file
106
orchid-extension/src/gen_expr.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use futures::FutureExt;
|
||||
use orchid_base::error::{OrcErr, OrcErrv};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::match_mapping;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::reqnot::ReqHandlish;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomFactory, ToAtom};
|
||||
use crate::conv::{ToExpr, TryFromExpr};
|
||||
use crate::expr::Expr;
|
||||
use crate::func_atom::Lambda;
|
||||
use crate::system::SysCtx;
|
||||
|
||||
pub struct GExpr {
|
||||
pub kind: GExprKind,
|
||||
pub pos: Pos,
|
||||
}
|
||||
impl GExpr {
|
||||
pub async fn api_return(self, ctx: SysCtx, hand: &impl ReqHandlish) -> api::Expression {
|
||||
if let GExprKind::Slot(ex) = self.kind {
|
||||
hand.defer_drop(ex.handle());
|
||||
api::Expression {
|
||||
location: api::Location::SlotTarget,
|
||||
kind: api::ExpressionKind::Slot(ex.handle().tk),
|
||||
}
|
||||
} else {
|
||||
api::Expression {
|
||||
location: api::Location::Inherit,
|
||||
kind: self.kind.api_return(ctx, hand).boxed_local().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum GExprKind {
|
||||
Call(Box<GExpr>, Box<GExpr>),
|
||||
Lambda(u64, Box<GExpr>),
|
||||
Arg(u64),
|
||||
Seq(Box<GExpr>, Box<GExpr>),
|
||||
Const(Sym),
|
||||
NewAtom(AtomFactory),
|
||||
Slot(Expr),
|
||||
Bottom(OrcErrv),
|
||||
}
|
||||
impl GExprKind {
|
||||
pub async fn api_return(self, ctx: SysCtx, hand: &impl ReqHandlish) -> api::ExpressionKind {
|
||||
match_mapping!(self, Self => api::ExpressionKind {
|
||||
Call(
|
||||
f => Box::new(f.api_return(ctx.clone(), hand).await),
|
||||
x => Box::new(x.api_return(ctx, hand).await)
|
||||
),
|
||||
Seq(
|
||||
a => Box::new(a.api_return(ctx.clone(), hand).await),
|
||||
b => Box::new(b.api_return(ctx, hand).await)
|
||||
),
|
||||
Lambda(arg, body => Box::new(body.api_return(ctx, hand).await)),
|
||||
Arg(arg),
|
||||
Const(name.to_api()),
|
||||
Const(name.to_api()),
|
||||
Bottom(err.to_api()),
|
||||
NewAtom(fac.clone().build(ctx).await),
|
||||
} {
|
||||
Self::Slot(_) => panic!("processed elsewhere")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn inherit(kind: GExprKind) -> GExpr { GExpr { pos: Pos::Inherit, kind } }
|
||||
|
||||
pub fn sym_ref(path: Sym) -> GExpr { inherit(GExprKind::Const(path)) }
|
||||
pub fn atom<A: ToAtom>(atom: A) -> GExpr { inherit(GExprKind::NewAtom(atom.to_atom_factory())) }
|
||||
|
||||
pub fn seq(ops: impl IntoIterator<Item = GExpr>) -> GExpr {
|
||||
fn recur(mut ops: impl Iterator<Item = GExpr>) -> Option<GExpr> {
|
||||
let op = ops.next()?;
|
||||
Some(match recur(ops) {
|
||||
None => op,
|
||||
Some(rec) => inherit(GExprKind::Seq(Box::new(op), Box::new(rec))),
|
||||
})
|
||||
}
|
||||
recur(ops.into_iter()).expect("Empty list provided to seq!")
|
||||
}
|
||||
|
||||
pub fn arg(n: u64) -> GExpr { inherit(GExprKind::Arg(n)) }
|
||||
|
||||
pub fn lambda(n: u64, b: impl IntoIterator<Item = GExpr>) -> GExpr {
|
||||
inherit(GExprKind::Lambda(n, Box::new(call(b))))
|
||||
}
|
||||
|
||||
pub fn call(v: impl IntoIterator<Item = GExpr>) -> GExpr {
|
||||
v.into_iter()
|
||||
.reduce(|f, x| inherit(GExprKind::Call(Box::new(f), Box::new(x))))
|
||||
.expect("Empty call expression")
|
||||
}
|
||||
|
||||
pub fn bot(ev: impl IntoIterator<Item = OrcErr>) -> GExpr {
|
||||
inherit(GExprKind::Bottom(OrcErrv::new(ev).unwrap()))
|
||||
}
|
||||
|
||||
pub fn with<I: TryFromExpr, O: ToExpr>(
|
||||
expr: GExpr,
|
||||
cont: impl Fn(I) -> O + Clone + Send + Sync + 'static,
|
||||
) -> GExpr {
|
||||
call([lambda(0, [seq([arg(0), call([Lambda::new(cont).to_expr(), arg(0)])])]), expr])
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::future::Future;
|
||||
use std::ops::{Range, RangeInclusive};
|
||||
|
||||
use futures::FutureExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use orchid_base::error::{OrcErr, OrcRes, mk_err};
|
||||
use orchid_base::intern;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::interner::{Interner, Tok};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::reqnot::{ReqNot, Requester};
|
||||
use orchid_base::tree::TokHandle;
|
||||
@@ -10,20 +12,19 @@ use orchid_base::tree::TokHandle;
|
||||
use crate::api;
|
||||
use crate::tree::{GenTok, GenTokTree};
|
||||
|
||||
pub async fn err_cascade() -> OrcErr {
|
||||
pub async fn err_cascade(i: &Interner) -> OrcErr {
|
||||
mk_err(
|
||||
intern!(str: "An error cascading from a recursive call").await,
|
||||
i.i("An error cascading from a recursive call").await,
|
||||
"This error is a sentinel for the extension library.\
|
||||
it should not be emitted by the extension.",
|
||||
[Pos::None.into()],
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn err_not_applicable() -> OrcErr {
|
||||
pub async fn err_not_applicable(i: &Interner) -> OrcErr {
|
||||
mk_err(
|
||||
intern!(str: "Pseudo-error to communicate that the current branch in a dispatch doesn't apply")
|
||||
.await,
|
||||
&*err_cascade().await.message,
|
||||
i.i("Pseudo-error to communicate that the current branch in a dispatch doesn't apply").await,
|
||||
&*err_cascade(i).await.message,
|
||||
[Pos::None.into()],
|
||||
)
|
||||
}
|
||||
@@ -34,12 +35,13 @@ pub struct LexContext<'a> {
|
||||
pub id: api::ParsId,
|
||||
pub pos: u32,
|
||||
pub reqnot: ReqNot<api::ExtMsgSet>,
|
||||
pub i: &'a Interner,
|
||||
}
|
||||
impl<'a> LexContext<'a> {
|
||||
pub async fn recurse(&self, tail: &'a str) -> OrcRes<(&'a str, GenTokTree<'a>)> {
|
||||
let start = self.pos(tail);
|
||||
let Some(lx) = self.reqnot.request(api::SubLex { pos: start, id: self.id }).await else {
|
||||
return Err(err_cascade().await.into());
|
||||
return Err(err_cascade(self.i).await.into());
|
||||
};
|
||||
Ok((&self.text[lx.pos as usize..], GenTok::Slot(TokHandle::new(lx.ticket)).at(start..lx.pos)))
|
||||
}
|
||||
@@ -53,18 +55,29 @@ impl<'a> LexContext<'a> {
|
||||
|
||||
pub trait Lexer: Send + Sync + Sized + Default + 'static {
|
||||
const CHAR_FILTER: &'static [RangeInclusive<char>];
|
||||
fn lex<'a>(tail: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)>;
|
||||
fn lex<'a>(
|
||||
tail: &'a str,
|
||||
ctx: &'a LexContext<'a>,
|
||||
) -> impl Future<Output = OrcRes<(&'a str, GenTokTree<'a>)>>;
|
||||
}
|
||||
|
||||
pub trait DynLexer: Send + Sync + 'static {
|
||||
fn char_filter(&self) -> &'static [RangeInclusive<char>];
|
||||
fn lex<'a>(&self, tail: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)>;
|
||||
fn lex<'a>(
|
||||
&self,
|
||||
tail: &'a str,
|
||||
ctx: &'a LexContext<'a>,
|
||||
) -> LocalBoxFuture<'a, OrcRes<(&'a str, GenTokTree<'a>)>>;
|
||||
}
|
||||
|
||||
impl<T: Lexer> DynLexer for T {
|
||||
fn char_filter(&self) -> &'static [RangeInclusive<char>] { T::CHAR_FILTER }
|
||||
fn lex<'a>(&self, tail: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)> {
|
||||
T::lex(tail, ctx)
|
||||
fn lex<'a>(
|
||||
&self,
|
||||
tail: &'a str,
|
||||
ctx: &'a LexContext<'a>,
|
||||
) -> LocalBoxFuture<'a, OrcRes<(&'a str, GenTokTree<'a>)>> {
|
||||
T::lex(tail, ctx).boxed_local()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ pub mod entrypoint;
|
||||
pub mod expr;
|
||||
pub mod fs;
|
||||
pub mod func_atom;
|
||||
pub mod gen_expr;
|
||||
pub mod lexer;
|
||||
pub mod macros;
|
||||
pub mod msg;
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
use std::num::NonZero;
|
||||
use std::sync::RwLock;
|
||||
use std::rc::Rc;
|
||||
|
||||
use ahash::HashMap;
|
||||
use futures::future::join_all;
|
||||
use lazy_static::lazy_static;
|
||||
use futures::future::{LocalBoxFuture, join_all};
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::interner::{Tok, intern};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::macros::{MTree, mtreev_from_api, mtreev_to_api};
|
||||
use orchid_base::parse::Comment;
|
||||
use orchid_base::reqnot::Requester;
|
||||
use trait_set::trait_set;
|
||||
|
||||
@@ -17,6 +14,7 @@ use crate::api;
|
||||
use crate::atom::AtomFactory;
|
||||
use crate::lexer::err_cascade;
|
||||
use crate::system::SysCtx;
|
||||
use crate::tree::TreeIntoApiCtx;
|
||||
|
||||
pub trait Macro {
|
||||
fn pattern() -> MTree<'static, Never>;
|
||||
@@ -42,12 +40,15 @@ pub struct RuleCtx<'a> {
|
||||
}
|
||||
impl<'a> RuleCtx<'a> {
|
||||
pub async fn recurse(&mut self, tree: &[MTree<'a, Never>]) -> OrcRes<Vec<MTree<'a, Never>>> {
|
||||
let req =
|
||||
api::RunMacros { run_id: self.run_id, query: mtreev_to_api(tree, &mut |b| match *b {}) };
|
||||
let Some(treev) = self.sys.reqnot.request(req).await else {
|
||||
return Err(err_cascade().await.into());
|
||||
let req = api::RunMacros {
|
||||
run_id: self.run_id,
|
||||
query: mtreev_to_api(tree, &mut |b| match *b {}).await,
|
||||
};
|
||||
Ok(mtreev_from_api(&treev, &mut |_| panic!("Returned atom from Rule recursion")).await)
|
||||
let Some(treev) = self.sys.reqnot.request(req).await else {
|
||||
return Err(err_cascade(&self.sys.i).await.into());
|
||||
};
|
||||
static ATOM_MSG: &str = "Returned atom from Rule recursion";
|
||||
Ok(mtreev_from_api(&treev, &mut |_| panic!("{ATOM_MSG}"), &self.sys.i).await)
|
||||
}
|
||||
pub fn getv(&mut self, key: &Tok<String>) -> Vec<MTree<'a, Never>> {
|
||||
self.args.remove(key).expect("Key not found")
|
||||
@@ -65,52 +66,37 @@ impl<'a> RuleCtx<'a> {
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
pub trait RuleCB = for<'a> Fn(RuleCtx<'a>) -> OrcRes<Vec<MTree<'a, AtomFactory>>> + Send + Sync;
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref RULES: RwLock<HashMap<api::MacroId, Box<dyn RuleCB>>> = RwLock::default();
|
||||
pub trait RuleCB = for<'a> Fn(RuleCtx<'a>) -> LocalBoxFuture<'a, OrcRes<Vec<MTree<'a, AtomFactory>>>>;
|
||||
}
|
||||
|
||||
pub struct Rule {
|
||||
pub(crate) comments: Vec<Comment>,
|
||||
pub(crate) comments: Vec<String>,
|
||||
pub(crate) pattern: Vec<MTree<'static, Never>>,
|
||||
pub(crate) id: api::MacroId,
|
||||
pub(crate) apply: Rc<dyn RuleCB>,
|
||||
}
|
||||
impl Rule {
|
||||
pub(crate) fn to_api(&self) -> api::MacroRule {
|
||||
pub(crate) async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MacroRule {
|
||||
api::MacroRule {
|
||||
comments: self.comments.iter().map(|c| c.to_api()).collect(),
|
||||
comments: join_all(self.comments.iter().map(|c| async {
|
||||
api::Comment { text: ctx.sys().i.i(c).await.to_api(), location: api::Location::Inherit }
|
||||
}))
|
||||
.await,
|
||||
location: api::Location::Inherit,
|
||||
pattern: mtreev_to_api(&self.pattern, &mut |b| match *b {}),
|
||||
id: self.id,
|
||||
pattern: mtreev_to_api(&self.pattern, &mut |b| match *b {}).await,
|
||||
id: ctx.with_rule(Rc::new(self)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn rule_cmt<'a>(
|
||||
pub fn rule_cmt<'a>(
|
||||
cmt: impl IntoIterator<Item = &'a str>,
|
||||
pattern: Vec<MTree<'static, Never>>,
|
||||
apply: impl RuleCB + 'static,
|
||||
) -> Rule {
|
||||
let mut rules = RULES.write().unwrap();
|
||||
let id = api::MacroId(NonZero::new(rules.len() as u64 + 1).unwrap());
|
||||
rules.insert(id, Box::new(apply));
|
||||
let comments = join_all(
|
||||
cmt.into_iter().map(|s| async { Comment { pos: Pos::Inherit, text: intern(s).await } }),
|
||||
)
|
||||
.await;
|
||||
Rule { comments, pattern, id }
|
||||
let comments = cmt.into_iter().map(|s| s.to_string()).collect_vec();
|
||||
Rule { comments, pattern, apply: Rc::new(apply) }
|
||||
}
|
||||
|
||||
pub async fn rule(pattern: Vec<MTree<'static, Never>>, apply: impl RuleCB + 'static) -> Rule {
|
||||
rule_cmt([], pattern, apply).await
|
||||
}
|
||||
|
||||
pub(crate) fn apply_rule(
|
||||
id: api::MacroId,
|
||||
ctx: RuleCtx<'static>,
|
||||
) -> OrcRes<Vec<MTree<'static, AtomFactory>>> {
|
||||
let rules = RULES.read().unwrap();
|
||||
rules[&id](ctx)
|
||||
pub fn rule(pattern: Vec<MTree<'static, Never>>, apply: impl RuleCB + 'static) -> Rule {
|
||||
rule_cmt([], pattern, apply)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use core::fmt;
|
||||
use std::any::TypeId;
|
||||
use std::future::Future;
|
||||
use std::num::NonZero;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::FutureExt;
|
||||
@@ -9,14 +11,13 @@ use futures::task::LocalSpawn;
|
||||
use hashbrown::HashMap;
|
||||
use orchid_api_traits::{Coding, Decode};
|
||||
use orchid_base::boxed_iter::BoxedIter;
|
||||
use orchid_base::id_store::IdStore;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::interner::Interner;
|
||||
use orchid_base::logging::Logger;
|
||||
use orchid_base::reqnot::{Receipt, ReqNot};
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo, AtomicFeatures, ForeignAtom, TypAtom, get_info};
|
||||
use crate::atom_owned::{DynOwnedAtom, ObjStore};
|
||||
use crate::atom_owned::ObjStore;
|
||||
use crate::entrypoint::ExtReq;
|
||||
use crate::fs::DeclFs;
|
||||
use crate::func_atom::Fun;
|
||||
@@ -79,28 +80,28 @@ impl<T: SystemCard> DynSystemCard for T {
|
||||
|
||||
/// System as defined by author
|
||||
pub trait System: Send + Sync + SystemCard + 'static {
|
||||
fn env() -> Vec<(Tok<String>, MemKind)>;
|
||||
fn env() -> Vec<(String, MemKind)>;
|
||||
fn vfs() -> DeclFs;
|
||||
fn lexers() -> Vec<LexerObj>;
|
||||
fn parsers() -> Vec<ParserObj>;
|
||||
fn request<'a>(hand: ExtReq<'a>, req: Self::Req) -> impl Future<Output = Receipt<'a>>;
|
||||
fn request(hand: ExtReq<'_>, req: Self::Req) -> impl Future<Output = Receipt<'_>>;
|
||||
}
|
||||
|
||||
pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
|
||||
fn dyn_env(&self) -> HashMap<Tok<String>, MemKind>;
|
||||
fn dyn_env(&self) -> HashMap<String, MemKind>;
|
||||
fn dyn_vfs(&self) -> DeclFs;
|
||||
fn dyn_lexers(&self) -> Vec<LexerObj>;
|
||||
fn dyn_parsers(&self) -> Vec<ParserObj>;
|
||||
fn dyn_request<'a>(&'a self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>>;
|
||||
fn dyn_request<'a>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>>;
|
||||
fn card(&self) -> &dyn DynSystemCard;
|
||||
}
|
||||
|
||||
impl<T: System> DynSystem for T {
|
||||
fn dyn_env(&self) -> HashMap<Tok<String>, MemKind> { Self::env().into_iter().collect() }
|
||||
fn dyn_env(&self) -> HashMap<String, MemKind> { Self::env().into_iter().collect() }
|
||||
fn dyn_vfs(&self) -> DeclFs { Self::vfs() }
|
||||
fn dyn_lexers(&self) -> Vec<LexerObj> { Self::lexers() }
|
||||
fn dyn_parsers(&self) -> Vec<ParserObj> { Self::parsers() }
|
||||
fn dyn_request<'a>(&'a self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>> {
|
||||
fn dyn_request<'a>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>> {
|
||||
Self::request(hand, <Self as SystemCard>::Req::decode(&mut &req[..])).boxed_local()
|
||||
}
|
||||
fn card(&self) -> &dyn DynSystemCard { self }
|
||||
@@ -125,9 +126,15 @@ pub fn downcast_atom<A: AtomicFeatures>(foreign: ForeignAtom) -> Result<TypAtom<
|
||||
#[derive(Clone)]
|
||||
pub struct SysCtx {
|
||||
pub reqnot: ReqNot<api::ExtMsgSet>,
|
||||
pub spawner: Arc<dyn LocalSpawn>,
|
||||
pub spawner: Rc<dyn LocalSpawn>,
|
||||
pub id: api::SysId,
|
||||
pub cted: CtedObj,
|
||||
pub logger: Arc<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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
use std::future::Future;
|
||||
use std::num::NonZero;
|
||||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
use dyn_clone::{DynClone, clone_box};
|
||||
use futures::FutureExt;
|
||||
use futures::future::{LocalBoxFuture, join_all};
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use orchid_base::interner::{Tok, intern};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::parse::Comment;
|
||||
use orchid_base::reqnot::ReqHandlish;
|
||||
use orchid_base::tree::{TokTree, Token};
|
||||
use ordered_float::NotNan;
|
||||
use substack::Substack;
|
||||
@@ -20,47 +20,56 @@ use crate::api;
|
||||
use crate::atom::{AtomFactory, ForeignAtom};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::entrypoint::MemberRecord;
|
||||
use crate::expr::Expr;
|
||||
use crate::func_atom::{ExprFunc, Fun};
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::macros::Rule;
|
||||
use crate::system::SysCtx;
|
||||
|
||||
pub type GenTokTree<'a> = TokTree<'a, ForeignAtom<'a>, AtomFactory>;
|
||||
pub type GenTok<'a> = Token<'a, ForeignAtom<'a>, AtomFactory>;
|
||||
|
||||
pub fn do_extra(f: &AtomFactory, r: Range<u32>, ctx: SysCtx) -> api::TokenTree {
|
||||
api::TokenTree { range: r, token: api::Token::Atom(f.clone().build(ctx)) }
|
||||
pub async fn do_extra(f: &AtomFactory, r: Range<u32>, ctx: SysCtx) -> api::TokenTree {
|
||||
api::TokenTree { range: r, token: api::Token::Atom(f.clone().build(ctx).await) }
|
||||
}
|
||||
|
||||
fn with_export(mem: GenMember, public: bool) -> Vec<GenItem> {
|
||||
(public.then(|| GenItemKind::Export(mem.name.clone()).at(Pos::Inherit)).into_iter())
|
||||
.chain([GenItemKind::Member(mem).at(Pos::Inherit)])
|
||||
(public.then(|| GenItemKind::Export(mem.name.clone())).into_iter())
|
||||
.chain([GenItemKind::Member(mem)])
|
||||
.map(|kind| GenItem { comments: vec![], kind })
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub struct GenItem {
|
||||
pub kind: GenItemKind,
|
||||
pub comments: Vec<Comment>,
|
||||
pub pos: Pos,
|
||||
pub comments: Vec<String>,
|
||||
}
|
||||
impl GenItem {
|
||||
pub 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 {
|
||||
GenItemKind::Export(n) => api::ItemKind::Export(n.to_api()),
|
||||
GenItemKind::Member(mem) => api::ItemKind::Member(mem.into_api(ctx)),
|
||||
GenItemKind::Export(n) => api::ItemKind::Export(ctx.sys().i.i::<String>(&n).await.to_api()),
|
||||
GenItemKind::Member(mem) => api::ItemKind::Member(mem.into_api(ctx).await),
|
||||
GenItemKind::Import(cn) => api::ItemKind::Import(cn.tok().to_api()),
|
||||
GenItemKind::Macro(prio, rules) => api::ItemKind::Macro(api::MacroBlock {
|
||||
priority: prio,
|
||||
rules: rules.into_iter().map(|r| r.to_api()).collect_vec(),
|
||||
}),
|
||||
GenItemKind::Macro(priority, gen_rules) => {
|
||||
let mut rules = Vec::with_capacity(gen_rules.len());
|
||||
for rule in gen_rules {
|
||||
rules.push(rule.into_api(ctx).await)
|
||||
}
|
||||
api::ItemKind::Macro(api::MacroBlock { priority, rules })
|
||||
},
|
||||
};
|
||||
let comments = self.comments.into_iter().map(|c| c.to_api()).collect_vec();
|
||||
api::Item { location: self.pos.to_api(), comments, kind }
|
||||
let comments = join_all(self.comments.iter().map(|c| async {
|
||||
api::Comment {
|
||||
location: api::Location::Inherit,
|
||||
text: ctx.sys().i.i::<String>(c).await.to_api(),
|
||||
}
|
||||
}))
|
||||
.await;
|
||||
api::Item { location: api::Location::Inherit, comments, kind }
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn cnst(public: bool, name: &str, value: impl ToExpr) -> Vec<GenItem> {
|
||||
with_export(GenMember { name: intern(name).await, kind: MemKind::Const(value.to_expr()) }, public)
|
||||
pub fn cnst(public: bool, name: &str, value: impl ToExpr) -> Vec<GenItem> {
|
||||
with_export(GenMember { name: name.to_string(), kind: MemKind::Const(value.to_expr()) }, public)
|
||||
}
|
||||
pub async fn module(
|
||||
public: bool,
|
||||
@@ -75,31 +84,31 @@ pub async fn root_mod(
|
||||
name: &str,
|
||||
imports: impl IntoIterator<Item = Sym>,
|
||||
items: impl IntoIterator<Item = Vec<GenItem>>,
|
||||
) -> (Tok<String>, MemKind) {
|
||||
) -> (String, MemKind) {
|
||||
let kind = MemKind::Mod {
|
||||
imports: imports.into_iter().collect(),
|
||||
items: items.into_iter().flatten().collect(),
|
||||
};
|
||||
(intern(name).await, kind)
|
||||
(name.to_string(), kind)
|
||||
}
|
||||
pub async fn fun<I, O>(exported: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenItem> {
|
||||
let fac =
|
||||
LazyMemberFactory::new(move |sym| async { MemKind::Const(Fun::new(sym, xf).to_expr()) });
|
||||
with_export(GenMember { name: intern(name).await, kind: MemKind::Lazy(fac) }, exported)
|
||||
LazyMemberFactory::new(move |sym| async { MemKind::Const(Fun::new(sym, xf).await.to_expr()) });
|
||||
with_export(GenMember { name: name.to_string(), kind: MemKind::Lazy(fac) }, exported)
|
||||
}
|
||||
pub fn macro_block(prio: Option<f64>, rules: impl IntoIterator<Item = Rule>) -> Vec<GenItem> {
|
||||
let prio = prio.map(|p| NotNan::new(p).unwrap());
|
||||
vec![GenItemKind::Macro(prio, rules.into_iter().collect_vec()).gen()]
|
||||
vec![GenItem {
|
||||
kind: GenItemKind::Macro(prio, rules.into_iter().collect_vec()),
|
||||
comments: vec![],
|
||||
}]
|
||||
}
|
||||
|
||||
pub async fn comments<'a>(
|
||||
pub fn comments<'a>(
|
||||
cmts: impl IntoIterator<Item = &'a str>,
|
||||
mut val: Vec<GenItem>,
|
||||
) -> Vec<GenItem> {
|
||||
let cmts = join_all(
|
||||
cmts.into_iter().map(|c| async { Comment { text: intern(c).await, pos: Pos::Inherit } }),
|
||||
)
|
||||
.await;
|
||||
let cmts = cmts.into_iter().map(|c| c.to_string()).collect_vec();
|
||||
for v in val.iter_mut() {
|
||||
v.comments.extend(cmts.iter().cloned());
|
||||
}
|
||||
@@ -108,12 +117,12 @@ pub async fn comments<'a>(
|
||||
|
||||
trait_set! {
|
||||
trait LazyMemberCallback =
|
||||
FnOnce(Sym) -> LocalBoxFuture<'static, MemKind> + Send + Sync + DynClone
|
||||
FnOnce(Sym) -> LocalBoxFuture<'static, MemKind> + DynClone
|
||||
}
|
||||
pub struct LazyMemberFactory(Box<dyn LazyMemberCallback>);
|
||||
impl LazyMemberFactory {
|
||||
pub fn new<F: Future<Output = MemKind> + 'static>(
|
||||
cb: impl FnOnce(Sym) -> F + Send + Sync + Clone + 'static,
|
||||
cb: impl FnOnce(Sym) -> F + Clone + 'static,
|
||||
) -> Self {
|
||||
Self(Box::new(|s| cb(s).boxed_local()))
|
||||
}
|
||||
@@ -125,49 +134,45 @@ impl Clone for LazyMemberFactory {
|
||||
|
||||
pub enum GenItemKind {
|
||||
Member(GenMember),
|
||||
Export(Tok<String>),
|
||||
Export(String),
|
||||
Import(Sym),
|
||||
Macro(Option<NotNan<f64>>, Vec<Rule>),
|
||||
}
|
||||
impl GenItemKind {
|
||||
pub fn at(self, pos: Pos) -> GenItem { GenItem { kind: self, comments: vec![], pos } }
|
||||
pub fn gen(self) -> GenItem { GenItem { kind: self, comments: vec![], pos: Pos::Inherit } }
|
||||
pub fn gen_equiv(self, comments: Vec<Comment>) -> GenItem {
|
||||
GenItem { kind: self, comments, pos: Pos::Inherit }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GenMember {
|
||||
name: Tok<String>,
|
||||
name: String,
|
||||
kind: MemKind,
|
||||
}
|
||||
impl GenMember {
|
||||
pub 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;
|
||||
api::Member {
|
||||
name: self.name.to_api(),
|
||||
kind: self.kind.into_api(&mut ctx.push_path(self.name)),
|
||||
kind: self.kind.into_api(&mut ctx.push_path(name.clone())).await,
|
||||
name: name.to_api(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MemKind {
|
||||
Const(Expr),
|
||||
Const(GExpr),
|
||||
Mod { imports: Vec<Sym>, items: Vec<GenItem> },
|
||||
Lazy(LazyMemberFactory),
|
||||
}
|
||||
impl MemKind {
|
||||
pub fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
|
||||
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
|
||||
match self {
|
||||
Self::Lazy(lazy) => api::MemberKind::Lazy(ctx.with_lazy(lazy)),
|
||||
Self::Const(c) =>
|
||||
api::MemberKind::Const(c.api_return(ctx.sys(), &mut |_| panic!("Slot in const tree"))),
|
||||
Self::Mod { imports, items } => api::MemberKind::Module(api::Module {
|
||||
items: (imports.into_iter())
|
||||
.map(|t| GenItemKind::Import(t).gen())
|
||||
.chain(items)
|
||||
.map(|i| i.into_api(ctx))
|
||||
.collect_vec(),
|
||||
}),
|
||||
Self::Const(c) => api::MemberKind::Const(c.api_return(ctx.sys(), ctx.req()).await),
|
||||
Self::Mod { imports, items } => {
|
||||
let all_items = (imports.into_iter())
|
||||
.map(|t| GenItem { comments: vec![], kind: GenItemKind::Import(t) })
|
||||
.chain(items);
|
||||
let mut items = Vec::new();
|
||||
for i in all_items {
|
||||
items.push(i.into_api(ctx).boxed_local().await)
|
||||
}
|
||||
api::MemberKind::Module(api::Module { items })
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,30 +180,42 @@ impl MemKind {
|
||||
pub trait TreeIntoApiCtx {
|
||||
fn sys(&self) -> SysCtx;
|
||||
fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId;
|
||||
fn with_rule(&mut self, rule: Rc<Rule>) -> api::MacroId;
|
||||
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx;
|
||||
fn req(&self) -> &impl ReqHandlish;
|
||||
}
|
||||
|
||||
pub struct TIACtxImpl<'a, 'b> {
|
||||
pub struct TIACtxImpl<'a, 'b, RH: ReqHandlish> {
|
||||
pub sys: SysCtx,
|
||||
pub basepath: &'a [Tok<String>],
|
||||
pub path: Substack<'a, Tok<String>>,
|
||||
pub lazy: &'b mut HashMap<api::TreeId, MemberRecord>,
|
||||
pub lazy_members: &'b mut HashMap<api::TreeId, MemberRecord>,
|
||||
pub rules: &'b mut HashMap<api::MacroId, Rc<Rule>>,
|
||||
pub req: &'a RH,
|
||||
}
|
||||
|
||||
impl<'a, 'b> TreeIntoApiCtx for TIACtxImpl<'a, 'b> {
|
||||
impl<RH: ReqHandlish> TreeIntoApiCtx for TIACtxImpl<'_, '_, RH> {
|
||||
fn sys(&self) -> SysCtx { self.sys.clone() }
|
||||
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
|
||||
TIACtxImpl {
|
||||
req: self.req,
|
||||
lazy_members: self.lazy_members,
|
||||
rules: self.rules,
|
||||
sys: self.sys.clone(),
|
||||
lazy: self.lazy,
|
||||
basepath: self.basepath,
|
||||
path: self.path.push(seg),
|
||||
}
|
||||
}
|
||||
fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId {
|
||||
let id = api::TreeId(NonZero::new((self.lazy.len() + 2) as u64).unwrap());
|
||||
let id = api::TreeId(NonZero::new((self.lazy_members.len() + 2) as u64).unwrap());
|
||||
let path = self.basepath.iter().cloned().chain(self.path.unreverse()).collect_vec();
|
||||
self.lazy.insert(id, MemberRecord::Gen(path, fac));
|
||||
self.lazy_members.insert(id, MemberRecord::Gen(path, fac));
|
||||
id
|
||||
}
|
||||
fn with_rule(&mut self, rule: Rc<Rule>) -> orchid_api::MacroId {
|
||||
let id = api::MacroId(NonZero::new((self.lazy_members.len() + 1) as u64).unwrap());
|
||||
self.rules.insert(id, rule);
|
||||
id
|
||||
}
|
||||
fn req(&self) -> &impl ReqHandlish { self.req }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_extension::atom::{AtomFactory, Atomic, AtomicFeatures, MethodSet, ToAtom, TypAtom};
|
||||
use orchid_extension::atom::{AtomFactory, Atomic, AtomicFeatures, MethodSetBuilder, ToAtom, TypAtom};
|
||||
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
||||
use orchid_extension::conv::TryFromExpr;
|
||||
use orchid_extension::expr::Expr;
|
||||
@@ -11,7 +11,7 @@ pub struct Int(pub i64);
|
||||
impl Atomic for Int {
|
||||
type Variant = ThinVariant;
|
||||
type Data = Self;
|
||||
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new() }
|
||||
}
|
||||
impl ThinAtom for Int {}
|
||||
impl TryFromExpr for Int {
|
||||
@@ -25,7 +25,7 @@ pub struct Float(pub NotNan<f64>);
|
||||
impl Atomic for Float {
|
||||
type Variant = ThinVariant;
|
||||
type Data = Self;
|
||||
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new() }
|
||||
}
|
||||
impl ThinAtom for Float {}
|
||||
impl TryFromExpr for Float {
|
||||
|
||||
@@ -8,7 +8,7 @@ use orchid_api_traits::{Encode, Request};
|
||||
use orchid_base::error::{OrcRes, mk_errv};
|
||||
use orchid_base::intern;
|
||||
use orchid_base::interner::{Tok, intern};
|
||||
use orchid_extension::atom::{AtomMethod, Atomic, MethodSet, Supports, TypAtom};
|
||||
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TypAtom};
|
||||
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use orchid_extension::conv::TryFromExpr;
|
||||
use orchid_extension::expr::Expr;
|
||||
@@ -33,7 +33,7 @@ pub struct StrAtom(Arc<String>);
|
||||
impl Atomic for StrAtom {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = ();
|
||||
fn reg_reqs() -> MethodSet<Self> { MethodSet::new().handle::<StringGetVal>() }
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<StringGetVal>() }
|
||||
}
|
||||
impl StrAtom {
|
||||
pub fn new(str: Arc<String>) -> Self { Self(str) }
|
||||
@@ -59,7 +59,7 @@ pub struct IntStrAtom(Tok<String>);
|
||||
impl Atomic for IntStrAtom {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = orchid_api::TStr;
|
||||
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new() }
|
||||
}
|
||||
impl From<Tok<String>> for IntStrAtom {
|
||||
fn from(value: Tok<String>) -> Self { Self(value) }
|
||||
|
||||
Reference in New Issue
Block a user