Added support for defining macros in Rust within the macro system
Also fixed a lot of bugs
This commit is contained in:
24
Cargo.lock
generated
24
Cargo.lock
generated
@@ -619,6 +619,17 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-locks"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-task",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
@@ -798,9 +809,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "konst"
|
name = "konst"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1b7495a4af30134f36ab2018716ba98b092019a6c5dc2126b94e3241c170748"
|
checksum = "64896bdfd7906cfb0b57bc04f08bde408bcd6aaf71ff438ee471061cd16f2e86"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_panic",
|
"const_panic",
|
||||||
"konst_proc_macros",
|
"konst_proc_macros",
|
||||||
@@ -1029,11 +1040,11 @@ name = "orchid-extension"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-fn-stream",
|
"async-fn-stream",
|
||||||
"async-lock",
|
|
||||||
"async-once-cell",
|
"async-once-cell",
|
||||||
"derive_destructure",
|
"derive_destructure",
|
||||||
"dyn-clone",
|
"dyn-clone",
|
||||||
"futures",
|
"futures",
|
||||||
|
"futures-locks",
|
||||||
"hashbrown 0.16.0",
|
"hashbrown 0.16.0",
|
||||||
"include_dir",
|
"include_dir",
|
||||||
"itertools",
|
"itertools",
|
||||||
@@ -1060,12 +1071,12 @@ name = "orchid-host"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-fn-stream",
|
"async-fn-stream",
|
||||||
"async-lock",
|
|
||||||
"async-once-cell",
|
"async-once-cell",
|
||||||
"async-process",
|
"async-process",
|
||||||
"bound",
|
"bound",
|
||||||
"derive_destructure",
|
"derive_destructure",
|
||||||
"futures",
|
"futures",
|
||||||
|
"futures-locks",
|
||||||
"hashbrown 0.16.0",
|
"hashbrown 0.16.0",
|
||||||
"itertools",
|
"itertools",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@@ -1086,6 +1097,7 @@ dependencies = [
|
|||||||
name = "orchid-std"
|
name = "orchid-std"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-fn-stream",
|
||||||
"async-once-cell",
|
"async-once-cell",
|
||||||
"futures",
|
"futures",
|
||||||
"hashbrown 0.16.0",
|
"hashbrown 0.16.0",
|
||||||
@@ -1431,9 +1443,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust_decimal"
|
name = "rust_decimal"
|
||||||
version = "1.37.2"
|
version = "1.38.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b203a6425500a03e0919c42d3c47caca51e79f1132046626d2c8871c5092035d"
|
checksum = "c8975fc98059f365204d635119cf9c5a60ae67b841ed49b5422a9a7e56cdfac0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"borsh",
|
"borsh",
|
||||||
|
|||||||
@@ -1,114 +1,44 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::future::poll_fn;
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::ptr;
|
|
||||||
use std::task::{Context, Poll};
|
|
||||||
|
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::channel::mpsc;
|
||||||
use futures::{FutureExt, Stream};
|
use futures::stream::{PollNext, select_with_strategy};
|
||||||
|
use futures::{FutureExt, SinkExt, Stream, StreamExt};
|
||||||
type YieldSlot<'a, T> = &'a Cell<Option<T>>;
|
|
||||||
|
|
||||||
/// Handle that allows you to emit values on a stream. If you drop
|
/// Handle that allows you to emit values on a stream. If you drop
|
||||||
/// this, the stream will end and you will not be polled again.
|
/// this, the stream will end and you will not be polled again.
|
||||||
pub struct StreamCtx<'a, T>(&'a Cell<Option<T>>, PhantomData<&'a ()>);
|
pub struct StreamCtx<'a, T>(mpsc::Sender<T>, PhantomData<&'a ()>);
|
||||||
impl<T> StreamCtx<'_, T> {
|
impl<T> StreamCtx<'_, T> {
|
||||||
pub fn emit(&mut self, value: T) -> impl Future<Output = ()> {
|
pub async fn emit(&mut self, value: T) {
|
||||||
assert!(self.0.replace(Some(value)).is_none(), "Leftover value in stream");
|
(self.0.send(value).await)
|
||||||
let mut state = Poll::Pending;
|
.expect("Dropped a stream receiver without dropping the driving closure");
|
||||||
poll_fn(move |_| std::mem::replace(&mut state, Poll::Ready(())))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FnOrFut<'a, T, O> {
|
fn left_strat(_: &mut ()) -> PollNext { PollNext::Left }
|
||||||
Fn(Option<Box<dyn FnOnce(YieldSlot<'a, T>) -> LocalBoxFuture<'a, O> + 'a>>),
|
|
||||||
Fut(LocalBoxFuture<'a, O>),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AsyncFnStream<'a, T> {
|
|
||||||
driver: FnOrFut<'a, T, ()>,
|
|
||||||
output: Cell<Option<T>>,
|
|
||||||
}
|
|
||||||
impl<'a, T> Stream for AsyncFnStream<'a, T> {
|
|
||||||
type Item = T;
|
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
unsafe {
|
|
||||||
let self_mut = self.get_unchecked_mut();
|
|
||||||
let fut = match &mut self_mut.driver {
|
|
||||||
FnOrFut::Fut(fut) => fut,
|
|
||||||
FnOrFut::Fn(f) => {
|
|
||||||
// safety: the cell is held inline in self, which is pinned.
|
|
||||||
let cell = ptr::from_ref(&self_mut.output).as_ref().unwrap();
|
|
||||||
let fut = f.take().unwrap()(cell);
|
|
||||||
self_mut.driver = FnOrFut::Fut(fut);
|
|
||||||
return Pin::new_unchecked(self_mut).poll_next(cx);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
match fut.as_mut().poll(cx) {
|
|
||||||
Poll::Ready(()) => Poll::Ready(None),
|
|
||||||
Poll::Pending => match self_mut.output.replace(None) {
|
|
||||||
None => Poll::Pending,
|
|
||||||
Some(t) => Poll::Ready(Some(t)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AsyncFnTryStream<'a, T, E> {
|
|
||||||
driver: FnOrFut<'a, T, Result<StreamCtx<'a, T>, E>>,
|
|
||||||
output: Cell<Option<T>>,
|
|
||||||
}
|
|
||||||
impl<'a, T, E> Stream for AsyncFnTryStream<'a, T, E> {
|
|
||||||
type Item = Result<T, E>;
|
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
unsafe {
|
|
||||||
let self_mut = self.get_unchecked_mut();
|
|
||||||
let fut = match &mut self_mut.driver {
|
|
||||||
FnOrFut::Fut(fut) => fut,
|
|
||||||
FnOrFut::Fn(f) => {
|
|
||||||
// safety: the cell is held inline in self, which is pinned.
|
|
||||||
let cell = ptr::from_ref(&self_mut.output).as_ref().unwrap();
|
|
||||||
let fut = f.take().unwrap()(cell);
|
|
||||||
self_mut.driver = FnOrFut::Fut(fut);
|
|
||||||
return Pin::new_unchecked(self_mut).poll_next(cx);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
match fut.as_mut().poll(cx) {
|
|
||||||
Poll::Ready(Ok(_)) => Poll::Ready(None),
|
|
||||||
Poll::Ready(Err(ex)) => Poll::Ready(Some(Err(ex))),
|
|
||||||
Poll::Pending => match self_mut.output.replace(None) {
|
|
||||||
None => Poll::Pending,
|
|
||||||
Some(t) => Poll::Ready(Some(Ok(t))),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a stream from an async function acting as a coroutine
|
/// Create a stream from an async function acting as a coroutine
|
||||||
pub fn stream<'a, T: 'a>(
|
pub fn stream<'a, T: 'a>(
|
||||||
f: impl for<'b> AsyncFnOnce(StreamCtx<'b, T>) + 'a,
|
f: impl for<'b> AsyncFnOnce(StreamCtx<'b, T>) + 'a,
|
||||||
) -> impl Stream<Item = T> + 'a {
|
) -> impl Stream<Item = T> + 'a {
|
||||||
AsyncFnStream {
|
let (send, recv) = mpsc::channel::<T>(1);
|
||||||
output: Cell::new(None),
|
let fut = async { f(StreamCtx(send, PhantomData)).await };
|
||||||
driver: FnOrFut::Fn(Some(Box::new(|t| {
|
// use options to ensure that the stream is driven to exhaustion
|
||||||
async { f(StreamCtx(t, PhantomData)).await }.boxed_local()
|
select_with_strategy(fut.into_stream().map(|()| None), recv.map(|t| Some(t)), left_strat)
|
||||||
}))),
|
.filter_map(async |opt| opt)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a stream of result from a fallible function.
|
/// Create a stream of result from a fallible function.
|
||||||
pub fn try_stream<'a, T: 'a, E: 'a>(
|
pub fn try_stream<'a, T: 'a, E: 'a>(
|
||||||
f: impl for<'b> AsyncFnOnce(StreamCtx<'b, T>) -> Result<StreamCtx<'b, T>, E> + 'a,
|
f: impl for<'b> AsyncFnOnce(StreamCtx<'b, T>) -> Result<StreamCtx<'b, T>, E> + 'a,
|
||||||
) -> impl Stream<Item = Result<T, E>> + 'a {
|
) -> impl Stream<Item = Result<T, E>> + 'a {
|
||||||
AsyncFnTryStream {
|
let (send, recv) = mpsc::channel::<T>(1);
|
||||||
output: Cell::new(None),
|
let fut = async { f(StreamCtx(send, PhantomData)).await };
|
||||||
driver: FnOrFut::Fn(Some(Box::new(|t| {
|
select_with_strategy(
|
||||||
async { f(StreamCtx(t, PhantomData)).await }.boxed_local()
|
fut.into_stream().map(|res| if let Err(e) = res { Some(Err(e)) } else { None }),
|
||||||
}))),
|
recv.map(|t| Some(Ok(t))),
|
||||||
}
|
left_strat,
|
||||||
|
)
|
||||||
|
.filter_map(async |opt| opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
let user = "dave"
|
import macros::common::(+ *)
|
||||||
let main = println "Hello $user!" exit_status::success
|
|
||||||
|
let main = 1 + 2
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ futures = { version = "0.3.31", features = ["std"], default-features = false }
|
|||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
test_executors = "0.3.2"
|
test_executors = "0.3.5"
|
||||||
|
|||||||
@@ -145,6 +145,16 @@ impl Request for ExtAtomPrint {
|
|||||||
type Response = FormattingUnit;
|
type Response = FormattingUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Can specify the recipient of an atom as well. The main use case for this is
|
||||||
|
/// to be able to return an atom to other extensions, so it can be combined with
|
||||||
|
/// a [crate::Move].
|
||||||
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
|
#[extends(ExtHostReq)]
|
||||||
|
pub struct CreateAtom(pub Atom, pub SysId);
|
||||||
|
impl Request for CreateAtom {
|
||||||
|
type Response = ExprTicket;
|
||||||
|
}
|
||||||
|
|
||||||
/// Requests that apply to an existing atom instance
|
/// Requests that apply to an existing atom instance
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(HostExtReq)]
|
#[extends(HostExtReq)]
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ pub enum ExtHostReq {
|
|||||||
IntReq(interner::IntReq),
|
IntReq(interner::IntReq),
|
||||||
Fwd(atom::Fwd),
|
Fwd(atom::Fwd),
|
||||||
ExtAtomPrint(atom::ExtAtomPrint),
|
ExtAtomPrint(atom::ExtAtomPrint),
|
||||||
|
CreateAtom(atom::CreateAtom),
|
||||||
SysFwd(system::SysFwd),
|
SysFwd(system::SysFwd),
|
||||||
ExprReq(expr::ExprReq),
|
ExprReq(expr::ExprReq),
|
||||||
SubLex(lexer::SubLex),
|
SubLex(lexer::SubLex),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::borrow::Borrow;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
@@ -5,6 +6,7 @@ use std::iter;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use futures::future::join_all;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
@@ -77,9 +79,12 @@ impl FmtElement {
|
|||||||
pub fn bounded(i: u32) -> Self { Self::sub(i, Some(true)) }
|
pub fn bounded(i: u32) -> Self { Self::sub(i, Some(true)) }
|
||||||
pub fn unbounded(i: u32) -> Self { Self::sub(i, Some(false)) }
|
pub fn unbounded(i: u32) -> Self { Self::sub(i, Some(false)) }
|
||||||
pub fn last(i: u32) -> Self { Self::sub(i, None) }
|
pub fn last(i: u32) -> Self { Self::sub(i, None) }
|
||||||
pub fn sequence(len: usize, bounded: Option<bool>) -> impl Iterator<Item = Self> {
|
pub fn sequence(len: usize, bounded: Option<bool>) -> Vec<Self> {
|
||||||
let len32: u32 = len.try_into().unwrap();
|
match len.try_into().unwrap() {
|
||||||
(0..len32 - 1).map(FmtElement::unbounded).chain([FmtElement::sub(len32 - 1, bounded)])
|
0u32 => vec![],
|
||||||
|
1u32 => vec![FmtElement::sub(0, bounded)],
|
||||||
|
n => (0..n - 1).map(FmtElement::unbounded).chain([FmtElement::sub(n - 1, bounded)]).collect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn from_api(api: &api::FormattingElement) -> Self {
|
pub fn from_api(api: &api::FormattingElement) -> Self {
|
||||||
match_mapping!(api, api::FormattingElement => FmtElement {
|
match_mapping!(api, api::FormattingElement => FmtElement {
|
||||||
@@ -109,6 +114,13 @@ fn variants_parse_test() {
|
|||||||
println!("final: {vars:?}")
|
println!("final: {vars:?}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a collection of formatting strings for the same set of parameters
|
||||||
|
/// from which the formatter can choose within their associated constraints.
|
||||||
|
///
|
||||||
|
/// - {0b} can be replaced by any variant of the parameter.
|
||||||
|
/// - {0} can only be replaced by a bounded variant of the parameter
|
||||||
|
/// - {0l} causes the current end restriction to be applied to the parameter.
|
||||||
|
/// This is to be used if the parameter is at the very end of the variant.
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Default)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq, Default)]
|
||||||
pub struct Variants(pub Vec<Variant>);
|
pub struct Variants(pub Vec<Variant>);
|
||||||
impl Variants {
|
impl Variants {
|
||||||
@@ -183,19 +195,24 @@ impl Variants {
|
|||||||
fn add(&mut self, bounded: bool, s: &'_ str) {
|
fn add(&mut self, bounded: bool, s: &'_ str) {
|
||||||
self.0.push(Variant { bounded, elements: Self::parse(s) })
|
self.0.push(Variant { bounded, elements: Self::parse(s) })
|
||||||
}
|
}
|
||||||
// This option is available in all positions
|
/// This option is available in all positions.
|
||||||
|
/// See [Variants] for a description of the format strings
|
||||||
pub fn bounded(mut self, s: &'_ str) -> Self {
|
pub fn bounded(mut self, s: &'_ str) -> Self {
|
||||||
self.add(true, s);
|
self.add(true, s);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
// This option is only available in positions immediately preceding the end of
|
/// This option is only available in positions immediately preceding the end
|
||||||
// the sequence or a parenthesized subsequence.
|
/// of the sequence or a parenthesized subsequence.
|
||||||
|
/// See [Variants] for a description of the format strings
|
||||||
pub fn unbounded(mut self, s: &'_ str) -> Self {
|
pub fn unbounded(mut self, s: &'_ str) -> Self {
|
||||||
self.add(false, s);
|
self.add(false, s);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub fn sequence(len: usize, delim: &str, seq_bnd: Option<bool>) -> Rc<Self> {
|
pub fn sequence(len: usize, delim: &str, seq_bnd: Option<bool>) -> Rc<Self> {
|
||||||
let seq = Itertools::intersperse(FmtElement::sequence(len, seq_bnd), FmtElement::str(delim));
|
let seq = Itertools::intersperse(
|
||||||
|
FmtElement::sequence(len, seq_bnd).into_iter(),
|
||||||
|
FmtElement::str(delim),
|
||||||
|
);
|
||||||
Rc::new(Variants(vec![Variant { bounded: true, elements: seq.collect_vec() }]))
|
Rc::new(Variants(vec![Variant { bounded: true, elements: seq.collect_vec() }]))
|
||||||
}
|
}
|
||||||
pub fn units(self: &Rc<Self>, subs: impl IntoIterator<Item = FmtUnit>) -> FmtUnit {
|
pub fn units(self: &Rc<Self>, subs: impl IntoIterator<Item = FmtUnit>) -> FmtUnit {
|
||||||
@@ -278,3 +295,12 @@ impl Format for Never {
|
|||||||
|
|
||||||
/// Format with default strategy. Currently equal to [take_first_fmt]
|
/// Format with default strategy. Currently equal to [take_first_fmt]
|
||||||
pub async fn fmt(v: &(impl Format + ?Sized), i: &Interner) -> String { take_first_fmt(v, i).await }
|
pub async fn fmt(v: &(impl Format + ?Sized), i: &Interner) -> String { take_first_fmt(v, i).await }
|
||||||
|
/// Format a sequence with default strategy. Currently equal to [take_first_fmt]
|
||||||
|
pub async fn fmt_v<F: Format + ?Sized, R: Borrow<F>>(
|
||||||
|
v: impl IntoIterator<Item = R>,
|
||||||
|
i: &Interner,
|
||||||
|
) -> impl Iterator<Item = String> {
|
||||||
|
join_all(v.into_iter().map(|f| async move { take_first_fmt(f.borrow(), i).await }))
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ impl<T: MsgSet> ReqNot<T> {
|
|||||||
notif_cb(notif_val, self.clone()).await
|
notif_cb(notif_val, self.clone()).await
|
||||||
} else if 0 < id.bitand(1 << 63) {
|
} else if 0 < id.bitand(1 << 63) {
|
||||||
let mut sender = g.responses.remove(&!id).expect("Received response for invalid message");
|
let mut sender = g.responses.remove(&!id).expect("Received response for invalid message");
|
||||||
sender.send(message.to_vec()).await.unwrap()
|
let _ = sender.send(message.to_vec()).await;
|
||||||
} else {
|
} else {
|
||||||
let message = <T::In as Channel>::Req::decode(Pin::new(&mut &payload[..])).await;
|
let message = <T::In as Channel>::Req::decode(Pin::new(&mut &payload[..])).await;
|
||||||
let mut req_cb = clone_box(&*g.req);
|
let mut req_cb = clone_box(&*g.req);
|
||||||
|
|||||||
@@ -7,18 +7,18 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-fn-stream = { version = "0.1.0", path = "../async-fn-stream" }
|
async-fn-stream = { version = "0.1.0", path = "../async-fn-stream" }
|
||||||
async-lock = "3.4.1"
|
|
||||||
async-once-cell = "0.5.4"
|
async-once-cell = "0.5.4"
|
||||||
derive_destructure = "1.0.0"
|
derive_destructure = "1.0.0"
|
||||||
dyn-clone = "1.0.20"
|
dyn-clone = "1.0.20"
|
||||||
futures = { version = "0.3.31", features = [
|
futures = { version = "0.3.31", features = [
|
||||||
"std",
|
"std",
|
||||||
"async-await",
|
"async-await",
|
||||||
], default-features = false }
|
], default-features = false }
|
||||||
|
futures-locks = "0.7.1"
|
||||||
hashbrown = "0.16.0"
|
hashbrown = "0.16.0"
|
||||||
include_dir = { version = "0.7.4", optional = true }
|
include_dir = { version = "0.7.4", optional = true }
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
konst = "0.4.1"
|
konst = "0.4.2"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
memo-map = "0.3.3"
|
memo-map = "0.3.3"
|
||||||
never = "0.1.0"
|
never = "0.1.0"
|
||||||
|
|||||||
@@ -109,8 +109,8 @@ impl ForeignAtom {
|
|||||||
.await?;
|
.await?;
|
||||||
Some(M::Response::decode(Pin::new(&mut &rep[..])).await)
|
Some(M::Response::decode(Pin::new(&mut &rep[..])).await)
|
||||||
}
|
}
|
||||||
pub async fn downcast<T: AtomicFeatures>(self) -> Result<TypAtom<T>, NotTypAtom> {
|
pub async fn downcast<T: AtomicFeatures>(self) -> Result<TAtom<T>, NotTypAtom> {
|
||||||
TypAtom::downcast(self.ex().handle()).await
|
TAtom::downcast(self.ex().handle()).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl fmt::Display for ForeignAtom {
|
impl fmt::Display for ForeignAtom {
|
||||||
@@ -222,11 +222,12 @@ impl<A: AtomCard> Default for MethodSetBuilder<A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TypAtom<A: AtomicFeatures> {
|
pub struct TAtom<A: AtomicFeatures> {
|
||||||
pub untyped: ForeignAtom,
|
pub untyped: ForeignAtom,
|
||||||
pub value: A::Data,
|
pub value: A::Data,
|
||||||
}
|
}
|
||||||
impl<A: AtomicFeatures> TypAtom<A> {
|
impl<A: AtomicFeatures> TAtom<A> {
|
||||||
|
pub fn ex(&self) -> Expr { self.untyped.clone().ex() }
|
||||||
pub fn ctx(&self) -> &SysCtx { self.untyped.ctx() }
|
pub fn ctx(&self) -> &SysCtx { self.untyped.ctx() }
|
||||||
pub fn i(&self) -> &Interner { self.ctx().i() }
|
pub fn i(&self) -> &Interner { self.ctx().i() }
|
||||||
pub async fn downcast(expr: Rc<ExprHandle>) -> Result<Self, NotTypAtom> {
|
pub async fn downcast(expr: Rc<ExprHandle>) -> Result<Self, NotTypAtom> {
|
||||||
@@ -262,11 +263,11 @@ impl<A: AtomicFeatures> TypAtom<A> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<A: AtomicFeatures> Deref for TypAtom<A> {
|
impl<A: AtomicFeatures> Deref for TAtom<A> {
|
||||||
type Target = A::Data;
|
type Target = A::Data;
|
||||||
fn deref(&self) -> &Self::Target { &self.value }
|
fn deref(&self) -> &Self::Target { &self.value }
|
||||||
}
|
}
|
||||||
impl<A: AtomicFeatures> ToExpr for TypAtom<A> {
|
impl<A: AtomicFeatures> ToExpr for TAtom<A> {
|
||||||
async fn to_expr(self) -> GExpr { self.untyped.to_expr().await }
|
async fn to_expr(self) -> GExpr { self.untyped.to_expr().await }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
use std::any::{Any, TypeId, type_name};
|
use std::any::{Any, TypeId, type_name};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::sync::atomic::AtomicU64;
|
||||||
|
|
||||||
use async_lock::{RwLock, RwLockReadGuard};
|
|
||||||
use async_once_cell::OnceCell;
|
use async_once_cell::OnceCell;
|
||||||
use dyn_clone::{DynClone, clone_box};
|
use dyn_clone::{DynClone, clone_box};
|
||||||
use futures::future::{LocalBoxFuture, ready};
|
use futures::future::{LocalBoxFuture, ready};
|
||||||
use futures::{AsyncRead, AsyncWrite, FutureExt};
|
use futures::{AsyncRead, AsyncWrite, FutureExt};
|
||||||
|
use futures_locks::{RwLock, RwLockReadGuard};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use memo_map::MemoMap;
|
use memo_map::MemoMap;
|
||||||
use never::Never;
|
use never::Never;
|
||||||
@@ -22,7 +23,7 @@ use orchid_base::name::Sym;
|
|||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::atom::{
|
use crate::atom::{
|
||||||
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
|
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet,
|
||||||
MethodSetBuilder, TypAtom, err_not_callable, err_not_command, get_info,
|
MethodSetBuilder, TAtom, err_not_callable, err_not_command, get_info,
|
||||||
};
|
};
|
||||||
use crate::expr::Expr;
|
use crate::expr::Expr;
|
||||||
use crate::gen_expr::{GExpr, bot};
|
use crate::gen_expr::{GExpr, bot};
|
||||||
@@ -53,16 +54,16 @@ impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVari
|
|||||||
/// While an atom read guard is held, no atom can be removed.
|
/// While an atom read guard is held, no atom can be removed.
|
||||||
pub(crate) struct AtomReadGuard<'a> {
|
pub(crate) struct AtomReadGuard<'a> {
|
||||||
id: api::AtomId,
|
id: api::AtomId,
|
||||||
guard: RwLockReadGuard<'a, MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>,
|
_lock: PhantomData<&'a ()>,
|
||||||
|
guard: RwLockReadGuard<MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>,
|
||||||
}
|
}
|
||||||
impl<'a> AtomReadGuard<'a> {
|
impl<'a> AtomReadGuard<'a> {
|
||||||
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
|
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
|
||||||
let guard = ctx.get_or_default::<ObjStore>().objects.read().await;
|
let guard = ctx.get_or_default::<ObjStore>().objects.read().await;
|
||||||
if guard.get(&id).is_none() {
|
if guard.get(&id).is_none() {
|
||||||
let valid = guard.iter().map(|i| i.0).collect_vec();
|
panic!("Received invalid atom ID: {id:?}");
|
||||||
panic!("Received invalid atom ID: {id:?} not in {valid:?}");
|
|
||||||
}
|
}
|
||||||
Self { id, guard }
|
Self { id, guard, _lock: PhantomData }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Deref for AtomReadGuard<'_> {
|
impl Deref for AtomReadGuard<'_> {
|
||||||
@@ -317,7 +318,7 @@ pub(crate) struct ObjStore {
|
|||||||
}
|
}
|
||||||
impl SysCtxEntry for ObjStore {}
|
impl SysCtxEntry for ObjStore {}
|
||||||
|
|
||||||
pub async fn own<A: OwnedAtom>(typ: TypAtom<A>) -> A {
|
pub async fn own<A: OwnedAtom>(typ: TAtom<A>) -> A {
|
||||||
let ctx = typ.untyped.ctx();
|
let ctx = typ.untyped.ctx();
|
||||||
let g = ctx.get_or_default::<ObjStore>().objects.read().await;
|
let g = ctx.get_or_default::<ObjStore>().objects.read().await;
|
||||||
let atom_id = typ.untyped.atom.drop.expect("Owned atoms always have a drop ID");
|
let atom_id = typ.untyped.atom.drop.expect("Owned atoms always have a drop ID");
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use dyn_clone::DynClone;
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_base::error::{OrcErrv, OrcRes, mk_errv};
|
use orchid_base::error::{OrcErrv, OrcRes, mk_errv};
|
||||||
use orchid_base::interner::Interner;
|
use orchid_base::interner::Interner;
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
|
use trait_set::trait_set;
|
||||||
|
|
||||||
use crate::atom::{AtomicFeatures, ForeignAtom, ToAtom, TypAtom};
|
use crate::atom::{AtomicFeatures, ForeignAtom, TAtom, ToAtom};
|
||||||
use crate::expr::Expr;
|
use crate::expr::Expr;
|
||||||
use crate::gen_expr::{GExpr, atom, bot};
|
use crate::gen_expr::{GExpr, atom, bot};
|
||||||
use crate::system::{SysCtx, downcast_atom};
|
use crate::system::{SysCtx, downcast_atom};
|
||||||
@@ -41,7 +44,7 @@ impl TryFromExpr for ForeignAtom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AtomicFeatures> TryFromExpr for TypAtom<A> {
|
impl<A: AtomicFeatures> TryFromExpr for TAtom<A> {
|
||||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||||
let f = ForeignAtom::try_from_expr(expr).await?;
|
let f = ForeignAtom::try_from_expr(expr).await?;
|
||||||
match downcast_atom::<A>(f).await {
|
match downcast_atom::<A>(f).await {
|
||||||
@@ -59,6 +62,29 @@ pub trait ToExpr {
|
|||||||
fn to_expr(self) -> impl Future<Output = GExpr>;
|
fn to_expr(self) -> impl Future<Output = GExpr>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ToExprDyn {
|
||||||
|
fn to_expr_dyn<'a>(self: Box<Self>) -> Pin<Box<dyn Future<Output = GExpr> + 'a>>
|
||||||
|
where Self: 'a;
|
||||||
|
}
|
||||||
|
impl<T: ToExpr> ToExprDyn for T {
|
||||||
|
fn to_expr_dyn<'a>(self: Box<Self>) -> Pin<Box<dyn Future<Output = GExpr> + 'a>>
|
||||||
|
where Self: 'a {
|
||||||
|
Box::pin(self.to_expr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trait_set! {
|
||||||
|
pub trait ClonableToExprDyn = ToExprDyn + DynClone;
|
||||||
|
}
|
||||||
|
impl ToExpr for Box<dyn ToExprDyn> {
|
||||||
|
async fn to_expr(self) -> GExpr { self.to_expr_dyn().await }
|
||||||
|
}
|
||||||
|
impl ToExpr for Box<dyn ClonableToExprDyn> {
|
||||||
|
async fn to_expr(self) -> GExpr { self.to_expr_dyn().await }
|
||||||
|
}
|
||||||
|
impl Clone for Box<dyn ClonableToExprDyn> {
|
||||||
|
fn clone(&self) -> Self { dyn_clone::clone_box(&**self) }
|
||||||
|
}
|
||||||
|
|
||||||
impl ToExpr for GExpr {
|
impl ToExpr for GExpr {
|
||||||
async fn to_expr(self) -> GExpr { self }
|
async fn to_expr(self) -> GExpr { self }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,15 +35,12 @@ impl BuilderCoroutine {
|
|||||||
match cmd {
|
match cmd {
|
||||||
None => panic!("Before the stream ends, we should have gotten a Halt"),
|
None => panic!("Before the stream ends, we should have gotten a Halt"),
|
||||||
Some(Command::Halt(expr)) => expr,
|
Some(Command::Halt(expr)) => expr,
|
||||||
Some(Command::Execute(expr, reply)) => call([
|
Some(Command::Execute(expr, reply)) => call(
|
||||||
lambda(0, [seq([
|
lambda(0, seq([arg(0)], call(Replier { reply, builder: self }.to_expr().await, [arg(0)]))),
|
||||||
arg(0),
|
[expr],
|
||||||
call([Replier { reply, builder: self }.to_expr().await, arg(0)]),
|
),
|
||||||
])]),
|
|
||||||
expr,
|
|
||||||
]),
|
|
||||||
Some(Command::Register(expr, reply)) =>
|
Some(Command::Register(expr, reply)) =>
|
||||||
call([Replier { reply, builder: self }.to_expr().await, expr]),
|
call(Replier { reply, builder: self }.to_expr().await, [expr]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ use std::num::NonZero;
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use async_lock::RwLock;
|
|
||||||
use futures::channel::mpsc::{Receiver, Sender, channel};
|
use futures::channel::mpsc::{Receiver, Sender, channel};
|
||||||
use futures::future::{LocalBoxFuture, join_all};
|
use futures::future::{LocalBoxFuture, join_all};
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use futures::{FutureExt, SinkExt, StreamExt, stream, stream_select};
|
use futures::{FutureExt, SinkExt, StreamExt, stream, stream_select};
|
||||||
|
use futures_locks::RwLock;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_api_traits::{Decode, UnderRoot, enc_vec};
|
use orchid_api_traits::{Decode, UnderRoot, enc_vec};
|
||||||
@@ -145,10 +145,7 @@ pub fn extension_init(
|
|||||||
clone!(exit_send mut);
|
clone!(exit_send mut);
|
||||||
async move {
|
async move {
|
||||||
match n {
|
match n {
|
||||||
api::HostExtNotif::Exit => {
|
api::HostExtNotif::Exit => exit_send.send(()).await.unwrap(),
|
||||||
eprintln!("Exit received");
|
|
||||||
exit_send.send(()).await.unwrap()
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.boxed_local()
|
.boxed_local()
|
||||||
@@ -194,13 +191,14 @@ pub fn extension_init(
|
|||||||
.then(|mem| {
|
.then(|mem| {
|
||||||
let lazy_mems = &lazy_members;
|
let lazy_mems = &lazy_members;
|
||||||
clone!(i, ctx; async move {
|
clone!(i, ctx; async move {
|
||||||
|
let name = i.i(&mem.name).await;
|
||||||
let mut tia_ctx = TreeIntoApiCtxImpl {
|
let mut tia_ctx = TreeIntoApiCtxImpl {
|
||||||
lazy_members: &mut *lazy_mems.lock().await,
|
lazy_members: &mut *lazy_mems.lock().await,
|
||||||
sys: ctx,
|
sys: ctx,
|
||||||
basepath: &[],
|
basepath: &[],
|
||||||
path: Substack::Bottom,
|
path: Substack::Bottom.push(name.clone()),
|
||||||
};
|
};
|
||||||
(i.i(&mem.name).await.to_api(), mem.kind.into_api(&mut tia_ctx).await)
|
(name.to_api(), mem.kind.into_api(&mut tia_ctx).await)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
@@ -52,10 +52,7 @@ impl ExprHandle {
|
|||||||
/// nothing, otherwise send an Acquire
|
/// nothing, otherwise send an Acquire
|
||||||
pub async fn drop_one(self: Rc<Self>) {
|
pub async fn drop_one(self: Rc<Self>) {
|
||||||
match Rc::try_unwrap(self) {
|
match Rc::try_unwrap(self) {
|
||||||
Err(rc) => {
|
Err(rc) => rc.ctx.reqnot().notify(api::Acquire(rc.ctx.sys_id(), rc.tk)).await,
|
||||||
eprintln!("Extending lifetime for {:?}", rc.tk);
|
|
||||||
rc.ctx.reqnot().notify(api::Acquire(rc.ctx.sys_id(), rc.tk)).await
|
|
||||||
},
|
|
||||||
Ok(hand) => {
|
Ok(hand) => {
|
||||||
// avoid calling destructor
|
// avoid calling destructor
|
||||||
hand.destructure();
|
hand.destructure();
|
||||||
@@ -65,10 +62,7 @@ impl ExprHandle {
|
|||||||
/// Drop the handle and get the ticket without a release notification.
|
/// Drop the handle and get the ticket without a release notification.
|
||||||
/// Use this with messages that imply ownership transfer. This function is
|
/// Use this with messages that imply ownership transfer. This function is
|
||||||
/// safe because abusing it is a memory leak.
|
/// safe because abusing it is a memory leak.
|
||||||
pub fn serialize(self) -> api::ExprTicket {
|
pub fn serialize(self) -> api::ExprTicket { self.destructure().0 }
|
||||||
eprintln!("Skipping destructor for {:?}", self.tk);
|
|
||||||
self.destructure().0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl Eq for ExprHandle {}
|
impl Eq for ExprHandle {}
|
||||||
impl PartialEq for ExprHandle {
|
impl PartialEq for ExprHandle {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ struct FunRecord {
|
|||||||
fun: Rc<dyn FunCB>,
|
fun: Rc<dyn FunCB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_args<I, O, F: ExprFunc<I, O>>(
|
fn process_args<I, O, F: ExprFunc<I, O>>(
|
||||||
debug: impl AsRef<str> + Clone + 'static,
|
debug: impl AsRef<str> + Clone + 'static,
|
||||||
f: F,
|
f: F,
|
||||||
) -> FunRecord {
|
) -> FunRecord {
|
||||||
@@ -83,7 +83,7 @@ impl Fun {
|
|||||||
let record = if let Some(record) = fung.get(&path) {
|
let record = if let Some(record) = fung.get(&path) {
|
||||||
record.clone()
|
record.clone()
|
||||||
} else {
|
} else {
|
||||||
let record = process_args(path.to_string(), f).await;
|
let record = process_args(path.to_string(), f);
|
||||||
fung.insert(path.clone(), record.clone());
|
fung.insert(path.clone(), record.clone());
|
||||||
record
|
record
|
||||||
};
|
};
|
||||||
@@ -134,11 +134,8 @@ pub struct Lambda {
|
|||||||
record: FunRecord,
|
record: FunRecord,
|
||||||
}
|
}
|
||||||
impl Lambda {
|
impl Lambda {
|
||||||
pub async fn new<I, O, F: ExprFunc<I, O>>(
|
pub fn new<I, O, F: ExprFunc<I, O>>(debug: impl AsRef<str> + Clone + 'static, f: F) -> Self {
|
||||||
debug: impl AsRef<str> + Clone + 'static,
|
Self { args: vec![], record: process_args(debug, f) }
|
||||||
f: F,
|
|
||||||
) -> Self {
|
|
||||||
Self { args: vec![], record: process_args(debug, f).await }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Atomic for Lambda {
|
impl Atomic for Lambda {
|
||||||
@@ -176,7 +173,7 @@ mod expr_func_derives {
|
|||||||
impl<
|
impl<
|
||||||
$($t: TryFromExpr + 'static, )*
|
$($t: TryFromExpr + 'static, )*
|
||||||
Out: ToExpr,
|
Out: ToExpr,
|
||||||
Func: AsyncFn($($t,)*) -> Out + Clone + Send + Sync + 'static
|
Func: AsyncFn($($t,)*) -> Out + Clone + 'static
|
||||||
> ExprFunc<($($t,)*), Out> for Func {
|
> ExprFunc<($($t,)*), Out> for Func {
|
||||||
fn argtyps() -> &'static [TypeId] {
|
fn argtyps() -> &'static [TypeId] {
|
||||||
static STORE: OnceLock<Vec<TypeId>> = OnceLock::new();
|
static STORE: OnceLock<Vec<TypeId>> = OnceLock::new();
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ fn inherit(kind: GExprKind) -> GExpr { GExpr { pos: Pos::Inherit, kind } }
|
|||||||
pub fn sym_ref(path: Sym) -> GExpr { inherit(GExprKind::Const(path)) }
|
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 atom<A: ToAtom>(atom: A) -> GExpr { inherit(GExprKind::NewAtom(atom.to_atom_factory())) }
|
||||||
|
|
||||||
pub fn seq(ops: impl IntoIterator<Item = GExpr>) -> GExpr {
|
pub fn seq(deps: impl IntoIterator<Item = GExpr>, val: GExpr) -> GExpr {
|
||||||
fn recur(mut ops: impl Iterator<Item = GExpr>) -> Option<GExpr> {
|
fn recur(mut ops: impl Iterator<Item = GExpr>) -> Option<GExpr> {
|
||||||
let op = ops.next()?;
|
let op = ops.next()?;
|
||||||
Some(match recur(ops) {
|
Some(match recur(ops) {
|
||||||
@@ -113,19 +113,15 @@ pub fn seq(ops: impl IntoIterator<Item = GExpr>) -> GExpr {
|
|||||||
Some(rec) => inherit(GExprKind::Seq(Box::new(op), Box::new(rec))),
|
Some(rec) => inherit(GExprKind::Seq(Box::new(op), Box::new(rec))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
recur(ops.into_iter()).expect("Empty list provided to seq!")
|
recur(deps.into_iter().chain([val])).expect("Empty list provided to seq!")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arg(n: u64) -> GExpr { inherit(GExprKind::Arg(n)) }
|
pub fn arg(n: u64) -> GExpr { inherit(GExprKind::Arg(n)) }
|
||||||
|
|
||||||
pub fn lambda(n: u64, b: impl IntoIterator<Item = GExpr>) -> GExpr {
|
pub fn lambda(n: u64, b: GExpr) -> GExpr { inherit(GExprKind::Lambda(n, Box::new(b))) }
|
||||||
inherit(GExprKind::Lambda(n, Box::new(call(b))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call(v: impl IntoIterator<Item = GExpr>) -> GExpr {
|
pub fn call(f: GExpr, argv: impl IntoIterator<Item = GExpr>) -> GExpr {
|
||||||
v.into_iter()
|
(argv.into_iter()).fold(f, |f, x| inherit(GExprKind::Call(Box::new(f), Box::new(x))))
|
||||||
.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 {
|
pub fn bot(ev: impl IntoIterator<Item = OrcErr>) -> GExpr {
|
||||||
|
|||||||
@@ -11,23 +11,25 @@ use orchid_base::reqnot::Requester;
|
|||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::system::{SysCtx, SysCtxEntry, WeakSysCtx};
|
use crate::system::{SysCtx, SysCtxEntry, WeakSysCtx};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ReflMemData {
|
pub struct ReflMemData {
|
||||||
// None for inferred steps
|
// None for inferred steps
|
||||||
public: OnceCell<bool>,
|
public: OnceCell<bool>,
|
||||||
kind: ReflMemKind,
|
kind: ReflMemKind,
|
||||||
}
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ReflMem(Rc<ReflMemData>);
|
pub struct ReflMem(Rc<ReflMemData>);
|
||||||
impl ReflMem {
|
impl ReflMem {
|
||||||
pub fn kind(&self) -> ReflMemKind { self.0.kind.clone() }
|
pub fn kind(&self) -> ReflMemKind { self.0.kind.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ReflMemKind {
|
pub enum ReflMemKind {
|
||||||
Const,
|
Const,
|
||||||
Mod(ReflMod),
|
Mod(ReflMod),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ReflModData {
|
pub struct ReflModData {
|
||||||
inferred: Mutex<bool>,
|
inferred: Mutex<bool>,
|
||||||
path: VPath,
|
path: VPath,
|
||||||
@@ -35,7 +37,7 @@ pub struct ReflModData {
|
|||||||
members: MemoMap<Tok<String>, ReflMem>,
|
members: MemoMap<Tok<String>, ReflMem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ReflMod(Rc<ReflModData>);
|
pub struct ReflMod(Rc<ReflModData>);
|
||||||
impl ReflMod {
|
impl ReflMod {
|
||||||
fn ctx(&self) -> SysCtx {
|
fn ctx(&self) -> SysCtx {
|
||||||
@@ -116,8 +118,8 @@ impl ReflMod {
|
|||||||
Err(api::LsModuleError::InvalidPath) => Err(InvalidPathError { keep_ancestry: false }),
|
Err(api::LsModuleError::InvalidPath) => Err(InvalidPathError { keep_ancestry: false }),
|
||||||
Err(api::LsModuleError::IsConstant) => {
|
Err(api::LsModuleError::IsConstant) => {
|
||||||
let const_mem = default_member(self.is_root(), ReflMemKind::Const);
|
let const_mem = default_member(self.is_root(), ReflMemKind::Const);
|
||||||
self.0.members.insert(next.clone(), const_mem);
|
self.0.members.insert(next.clone(), const_mem.clone());
|
||||||
Err(InvalidPathError { keep_ancestry: true })
|
Ok(const_mem)
|
||||||
},
|
},
|
||||||
Err(api::LsModuleError::TreeUnavailable) => unreachable!(),
|
Err(api::LsModuleError::TreeUnavailable) => unreachable!(),
|
||||||
};
|
};
|
||||||
@@ -136,6 +138,7 @@ impl ReflMod {
|
|||||||
struct ReflRoot(ReflMod);
|
struct ReflRoot(ReflMod);
|
||||||
impl SysCtxEntry for ReflRoot {}
|
impl SysCtxEntry for ReflRoot {}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct InvalidPathError {
|
pub struct InvalidPathError {
|
||||||
keep_ancestry: bool,
|
keep_ancestry: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use orchid_base::name::Sym;
|
|||||||
use orchid_base::reqnot::{Receipt, ReqNot};
|
use orchid_base::reqnot::{Receipt, ReqNot};
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TypAtom, get_info};
|
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TAtom, get_info};
|
||||||
use crate::coroutine_exec::Replier;
|
use crate::coroutine_exec::Replier;
|
||||||
use crate::entrypoint::ExtReq;
|
use crate::entrypoint::ExtReq;
|
||||||
use crate::func_atom::{Fun, Lambda};
|
use crate::func_atom::{Fun, Lambda};
|
||||||
@@ -115,7 +115,7 @@ impl<T: System> DynSystem for T {
|
|||||||
fn card(&self) -> &dyn DynSystemCard { self }
|
fn card(&self) -> &dyn DynSystemCard { self }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn downcast_atom<A>(foreign: ForeignAtom) -> Result<TypAtom<A>, ForeignAtom>
|
pub async fn downcast_atom<A>(foreign: ForeignAtom) -> Result<TAtom<A>, ForeignAtom>
|
||||||
where A: AtomicFeatures {
|
where A: AtomicFeatures {
|
||||||
let mut data = &foreign.atom.data.0[..];
|
let mut data = &foreign.atom.data.0[..];
|
||||||
let ctx = foreign.ctx().clone();
|
let ctx = foreign.ctx().clone();
|
||||||
@@ -128,13 +128,16 @@ where A: AtomicFeatures {
|
|||||||
.ok_or_else(|| foreign.clone())?
|
.ok_or_else(|| foreign.clone())?
|
||||||
.get_card()
|
.get_card()
|
||||||
};
|
};
|
||||||
|
if owner.atoms().flatten().all(|dynfo| dynfo.tid() != TypeId::of::<A>()) {
|
||||||
|
return Err(foreign);
|
||||||
|
}
|
||||||
let (typ_id, dynfo) = get_info::<A>(owner);
|
let (typ_id, dynfo) = get_info::<A>(owner);
|
||||||
if value != typ_id {
|
if value != typ_id {
|
||||||
return Err(foreign);
|
return Err(foreign);
|
||||||
}
|
}
|
||||||
let val = dynfo.decode(AtomCtx(data, foreign.atom.drop, ctx)).await;
|
let val = dynfo.decode(AtomCtx(data, foreign.atom.drop, ctx)).await;
|
||||||
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
|
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
|
||||||
Ok(TypAtom { value, untyped: foreign })
|
Ok(TAtom { value, untyped: foreign })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -142,6 +145,9 @@ pub struct WeakSysCtx(Weak<MemoMap<TypeId, Box<dyn Any>>>);
|
|||||||
impl WeakSysCtx {
|
impl WeakSysCtx {
|
||||||
pub fn upgrade(&self) -> Option<SysCtx> { Some(SysCtx(self.0.upgrade()?)) }
|
pub fn upgrade(&self) -> Option<SysCtx> { Some(SysCtx(self.0.upgrade()?)) }
|
||||||
}
|
}
|
||||||
|
impl fmt::Debug for WeakSysCtx {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "WeakSysCtx") }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SysCtx(Rc<MemoMap<TypeId, Box<dyn Any>>>);
|
pub struct SysCtx(Rc<MemoMap<TypeId, Box<dyn Any>>>);
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ impl GenMember {
|
|||||||
let name = ctx.sys().i().i::<String>(&self.name).await;
|
let name = ctx.sys().i().i::<String>(&self.name).await;
|
||||||
let kind = self.kind.into_api(&mut ctx.push_path(name.clone())).await;
|
let kind = self.kind.into_api(&mut ctx.push_path(name.clone())).await;
|
||||||
let comments =
|
let comments =
|
||||||
join_all(self.comments.iter().map(|cmt| async { ctx.sys().i().i(cmt).await.to_api() })).await;
|
join_all(self.comments.iter().map(async |cmt| ctx.sys().i().i(cmt).await.to_api())).await;
|
||||||
api::Member { kind, name: name.to_api(), comments, exported: self.public }
|
api::Member { kind, name: name.to_api(), comments, exported: self.public }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-fn-stream = { version = "0.1.0", path = "../async-fn-stream" }
|
async-fn-stream = { version = "0.1.0", path = "../async-fn-stream" }
|
||||||
async-lock = "3.4.1"
|
|
||||||
async-once-cell = "0.5.4"
|
async-once-cell = "0.5.4"
|
||||||
async-process = "2.4.0"
|
async-process = "2.4.0"
|
||||||
bound = "0.6.0"
|
bound = "0.6.0"
|
||||||
derive_destructure = "1.0.0"
|
derive_destructure = "1.0.0"
|
||||||
futures = { version = "0.3.31", features = ["std"], default-features = false }
|
futures = { version = "0.3.31", features = ["std"], default-features = false }
|
||||||
|
futures-locks = "0.7.1"
|
||||||
hashbrown = "0.16.0"
|
hashbrown = "0.16.0"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
use async_lock::OnceCell;
|
use async_once_cell::OnceCell;
|
||||||
use derive_destructure::destructure;
|
use derive_destructure::destructure;
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, take_first_fmt};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format, take_first_fmt};
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
@@ -85,7 +85,7 @@ impl AtomHand {
|
|||||||
}
|
}
|
||||||
impl Format for AtomHand {
|
impl Format for AtomHand {
|
||||||
async fn print<'a>(&'a self, _c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
async fn print<'a>(&'a self, _c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
(self.0.display.get_or_init(|| async {
|
(self.0.display.get_or_init(async {
|
||||||
FmtUnit::from_api(&self.0.owner.reqnot().request(api::AtomPrint(self.0.api_ref())).await)
|
FmtUnit::from_api(&self.0.owner.reqnot().request(api::AtomPrint(self.0.api_ref())).await)
|
||||||
}))
|
}))
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::num::{NonZero, NonZeroU16};
|
|||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::{fmt, ops};
|
use std::{fmt, ops};
|
||||||
|
|
||||||
use async_lock::RwLock;
|
use futures_locks::RwLock;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use orchid_base::builtin::Spawner;
|
use orchid_base::builtin::Spawner;
|
||||||
use orchid_base::interner::Interner;
|
use orchid_base::interner::Interner;
|
||||||
|
|||||||
@@ -48,13 +48,15 @@ pub async fn absolute_path(
|
|||||||
) -> Result<VName, AbsPathError> {
|
) -> Result<VName, AbsPathError> {
|
||||||
let i_self = i.i("self").await;
|
let i_self = i.i("self").await;
|
||||||
let i_super = i.i("super").await;
|
let i_super = i.i("super").await;
|
||||||
let relative = rel.first().is_some_and(|s| *s != i_self && *s != i_super);
|
let mut relative = false;
|
||||||
if let Some((_, tail)) = rel.split_first().filter(|(h, _)| **h != i_self) {
|
if let Some((_, tail)) = rel.split_first().filter(|(h, _)| **h == i_self) {
|
||||||
rel = tail;
|
rel = tail;
|
||||||
|
relative = true;
|
||||||
} else {
|
} else {
|
||||||
while let Some((_, tail)) = rel.split_first().filter(|(h, _)| **h == i_super) {
|
while let Some((_, tail)) = rel.split_first().filter(|(h, _)| **h == i_super) {
|
||||||
cwd = cwd.split_last().ok_or(AbsPathError::TooManySupers)?.1;
|
cwd = cwd.split_last().ok_or(AbsPathError::TooManySupers)?.1;
|
||||||
rel = tail;
|
rel = tail;
|
||||||
|
relative = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if relative { VName::new(cwd.iter().chain(rel).cloned()) } else { VName::new(rel.to_vec()) }
|
if relative { VName::new(cwd.iter().chain(rel).cloned()) } else { VName::new(rel.to_vec()) }
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use async_lock::RwLockWriteGuard;
|
|
||||||
use bound::Bound;
|
use bound::Bound;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
use futures_locks::{RwLockWriteGuard, TryLockError};
|
||||||
use orchid_base::error::OrcErrv;
|
use orchid_base::error::OrcErrv;
|
||||||
use orchid_base::format::{FmtCtxImpl, Format, take_first};
|
use orchid_base::format::{FmtCtxImpl, Format, take_first};
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
@@ -12,7 +12,7 @@ use crate::ctx::Ctx;
|
|||||||
use crate::expr::{Expr, ExprKind, PathSet, Step};
|
use crate::expr::{Expr, ExprKind, PathSet, Step};
|
||||||
use crate::tree::Root;
|
use crate::tree::Root;
|
||||||
|
|
||||||
type ExprGuard = Bound<RwLockWriteGuard<'static, ExprKind>, Expr>;
|
type ExprGuard = Bound<RwLockWriteGuard<ExprKind>, Expr>;
|
||||||
|
|
||||||
/// The stack operation associated with a transform
|
/// The stack operation associated with a transform
|
||||||
enum StackOp {
|
enum StackOp {
|
||||||
@@ -76,13 +76,13 @@ impl ExecCtx {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn unpack_ident(&self, ex: &Expr) -> Expr {
|
pub async fn unpack_ident(&self, ex: &Expr) -> Expr {
|
||||||
match ex.kind().try_write().as_deref_mut() {
|
match ex.kind().try_write().as_deref_mut() {
|
||||||
Some(ExprKind::Identity(ex)) => {
|
Ok(ExprKind::Identity(ex)) => {
|
||||||
let val = self.unpack_ident(ex).boxed_local().await;
|
let val = self.unpack_ident(ex).boxed_local().await;
|
||||||
*ex = val.clone();
|
*ex = val.clone();
|
||||||
val
|
val
|
||||||
},
|
},
|
||||||
Some(_) => ex.clone(),
|
Ok(_) => ex.clone(),
|
||||||
None => panic!("Cycle encountered!"),
|
Err(TryLockError) => panic!("Cycle encountered!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn execute(&mut self) {
|
pub async fn execute(&mut self) {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ use std::num::NonZeroU64;
|
|||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::{fmt, mem};
|
use std::{fmt, mem};
|
||||||
|
|
||||||
use async_lock::RwLock;
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
use futures_locks::RwLock;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::OrcErrv;
|
use orchid_base::error::OrcErrv;
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
|
||||||
@@ -41,9 +41,9 @@ impl Expr {
|
|||||||
pub async fn try_into_owned_atom(self) -> Result<AtomHand, Self> {
|
pub async fn try_into_owned_atom(self) -> Result<AtomHand, Self> {
|
||||||
match Rc::try_unwrap(self.0) {
|
match Rc::try_unwrap(self.0) {
|
||||||
Err(e) => Err(Self(e)),
|
Err(e) => Err(Self(e)),
|
||||||
Ok(data) => match data.kind.into_inner() {
|
Ok(data) => match data.kind.try_unwrap().expect("This fields shouldn't be copied") {
|
||||||
ExprKind::Atom(a) => Ok(a),
|
ExprKind::Atom(a) => Ok(a),
|
||||||
inner => Err(Self(Rc::new(ExprData { kind: inner.into(), pos: data.pos }))),
|
inner => Err(Self(Rc::new(ExprData { kind: RwLock::new(inner), pos: data.pos }))),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ use crate::api;
|
|||||||
use crate::atom::AtomHand;
|
use crate::atom::AtomHand;
|
||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::dealias::{ChildError, ChildErrorKind, walk};
|
use crate::dealias::{ChildError, ChildErrorKind, walk};
|
||||||
|
use crate::expr::ExprKind;
|
||||||
use crate::expr_store::ExprStore;
|
use crate::expr_store::ExprStore;
|
||||||
use crate::system::SystemCtor;
|
use crate::system::SystemCtor;
|
||||||
use crate::tree::MemberKind;
|
use crate::tree::MemberKind;
|
||||||
@@ -56,6 +57,7 @@ impl Drop for ExtensionData {
|
|||||||
let mut exiting_snd = self.exiting_snd.clone();
|
let mut exiting_snd = self.exiting_snd.clone();
|
||||||
(self.ctx.spawn)(Box::pin(async move {
|
(self.ctx.spawn)(Box::pin(async move {
|
||||||
reqnot.notify(api::HostExtNotif::Exit).await;
|
reqnot.notify(api::HostExtNotif::Exit).await;
|
||||||
|
|
||||||
exiting_snd.send(()).await.unwrap()
|
exiting_snd.send(()).await.unwrap()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -247,6 +249,13 @@ impl Extension {
|
|||||||
let unit = atom.print(&FmtCtxImpl { i: &this.ctx().i }).await;
|
let unit = atom.print(&FmtCtxImpl { i: &this.ctx().i }).await;
|
||||||
hand.handle(eap, &unit.to_api()).await
|
hand.handle(eap, &unit.to_api()).await
|
||||||
},
|
},
|
||||||
|
api::ExtHostReq::CreateAtom(ref create @ api::CreateAtom(ref atom, target)) => {
|
||||||
|
let atom = AtomHand::from_api(atom, Pos::None, &mut ctx.clone()).await;
|
||||||
|
let target = ctx.system_inst(target).await.expect("Invalid recipient for atom");
|
||||||
|
let expr = ExprKind::Atom(atom).at(Pos::None);
|
||||||
|
target.ext().exprs().give_expr(expr.clone());
|
||||||
|
hand.handle(create, &expr.id()).await
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use futures::future::join_all;
|
use futures::FutureExt;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
||||||
use orchid_base::format::fmt;
|
use orchid_base::format::fmt;
|
||||||
@@ -51,9 +51,14 @@ pub async fn parse_items(
|
|||||||
items: ParsSnippet<'_>,
|
items: ParsSnippet<'_>,
|
||||||
) -> OrcRes<Vec<Item>> {
|
) -> OrcRes<Vec<Item>> {
|
||||||
let lines = line_items(ctx, items).await;
|
let lines = line_items(ctx, items).await;
|
||||||
let line_res =
|
let mut line_ok = Vec::new();
|
||||||
join_all(lines.into_iter().map(|p| parse_item(ctx, path.clone(), p.output, p.tail))).await;
|
for Parsed { output: comments, tail } in lines {
|
||||||
Ok(line_res.into_iter().flat_map(|l| l.ok().into_iter().flatten()).collect())
|
match parse_item(ctx, path.clone(), comments, tail).boxed_local().await {
|
||||||
|
Err(e) => ctx.rep().report(e),
|
||||||
|
Ok(l) => line_ok.extend(l),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(line_ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn parse_item(
|
pub async fn parse_item(
|
||||||
|
|||||||
@@ -93,13 +93,14 @@ async fn conv(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
let name = ctx.i.ex(name).await;
|
let name = ctx.i.ex(name).await;
|
||||||
|
let mem_path = module.push(name.clone());
|
||||||
let mkind = match kind {
|
let mkind = match kind {
|
||||||
api::ParsedMemberKind::Module { lines, use_prelude } => {
|
api::ParsedMemberKind::Module { lines, use_prelude } => {
|
||||||
let items = conv(lines, module.push(name.clone()), callback, ctx).boxed_local().await?;
|
let items = conv(lines, mem_path, callback, ctx).boxed_local().await?;
|
||||||
ParsedMemberKind::Mod(ParsedModule::new(use_prelude, items))
|
ParsedMemberKind::Mod(ParsedModule::new(use_prelude, items))
|
||||||
},
|
},
|
||||||
api::ParsedMemberKind::Constant(cid) => {
|
api::ParsedMemberKind::Constant(cid) => {
|
||||||
ctx.sys.0.const_paths.insert(cid, ctx.mod_path.suffix(module.unreverse(), ctx.i).await);
|
ctx.sys.0.const_paths.insert(cid, ctx.mod_path.suffix(mem_path.unreverse(), ctx.i).await);
|
||||||
ParsedMemberKind::Const(cid, ctx.sys.clone())
|
ParsedMemberKind::Const(cid, ctx.sys.clone())
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ use std::fmt;
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
use async_lock::RwLock;
|
|
||||||
use derive_destructure::destructure;
|
use derive_destructure::destructure;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
|
use futures_locks::RwLock;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use memo_map::MemoMap;
|
use memo_map::MemoMap;
|
||||||
@@ -163,6 +163,9 @@ impl System {
|
|||||||
)),
|
)),
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
|
if root_data.root.members.get(selector).is_some() {
|
||||||
|
return Ok(VName::new(rel.iter().cloned()).expect("split_first was called above"));
|
||||||
|
}
|
||||||
if tail.is_empty() {
|
if tail.is_empty() {
|
||||||
return Ok(VPath::new(cwd.iter().cloned()).name_with_suffix(selector.clone()));
|
return Ok(VPath::new(cwd.iter().cloned()).name_with_suffix(selector.clone()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use std::cell::RefCell;
|
|||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
use async_lock::RwLock;
|
|
||||||
use async_once_cell::OnceCell;
|
use async_once_cell::OnceCell;
|
||||||
use derive_destructure::destructure;
|
use derive_destructure::destructure;
|
||||||
use futures::{FutureExt, StreamExt, stream};
|
use futures::{FutureExt, StreamExt, stream};
|
||||||
|
use futures_locks::RwLock;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use hashbrown::hash_map::Entry;
|
use hashbrown::hash_map::Entry;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
async-fn-stream = { version = "0.1.0", path = "../async-fn-stream" }
|
||||||
async-once-cell = "0.5.4"
|
async-once-cell = "0.5.4"
|
||||||
futures = { version = "0.3.31", features = ["std"], default-features = false }
|
futures = { version = "0.3.31", features = ["std"], default-features = false }
|
||||||
hashbrown = "0.16.0"
|
hashbrown = "0.16.0"
|
||||||
@@ -15,10 +16,10 @@ orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" }
|
|||||||
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
||||||
orchid-base = { version = "0.1.0", path = "../orchid-base" }
|
orchid-base = { version = "0.1.0", path = "../orchid-base" }
|
||||||
orchid-extension = { version = "0.1.0", path = "../orchid-extension", features = [
|
orchid-extension = { version = "0.1.0", path = "../orchid-extension", features = [
|
||||||
"tokio",
|
"tokio",
|
||||||
] }
|
] }
|
||||||
ordered-float = "5.0.0"
|
ordered-float = "5.0.0"
|
||||||
rust_decimal = "1.37.2"
|
rust_decimal = "1.38.0"
|
||||||
substack = "1.1.1"
|
substack = "1.1.1"
|
||||||
tokio = { version = "1.47.1", features = ["full"] }
|
tokio = { version = "1.47.1", features = ["full"] }
|
||||||
|
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ pub use std::string::str_atom::OrcString;
|
|||||||
|
|
||||||
pub use macros::macro_system::MacroSystem;
|
pub use macros::macro_system::MacroSystem;
|
||||||
pub use macros::mactree::{MacTok, MacTree};
|
pub use macros::mactree::{MacTok, MacTree};
|
||||||
|
use orchid_api as api;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_extension::atom::{Atomic, TypAtom};
|
use orchid_base::format::fmt;
|
||||||
|
use orchid_extension::atom::{Atomic, TAtom};
|
||||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
||||||
use orchid_extension::conv::{ToExpr, TryFromExpr};
|
use orchid_extension::conv::ToExpr;
|
||||||
|
use orchid_extension::coroutine_exec::exec;
|
||||||
use orchid_extension::expr::Expr;
|
use orchid_extension::expr::Expr;
|
||||||
use orchid_extension::gen_expr::GExpr;
|
use orchid_extension::gen_expr::GExpr;
|
||||||
|
|
||||||
@@ -24,26 +26,33 @@ impl OwnedAtom for InstantiateTplCall {
|
|||||||
type Refs = Never;
|
type Refs = Never;
|
||||||
// Technically must be supported but shouldn't actually ever be called
|
// Technically must be supported but shouldn't actually ever be called
|
||||||
async fn call_ref(&self, arg: Expr) -> GExpr {
|
async fn call_ref(&self, arg: Expr) -> GExpr {
|
||||||
eprintln!(
|
if !self.argv.is_empty() {
|
||||||
"Copying partially applied instantiate_tpl call. This is an internal value.\
|
eprintln!(
|
||||||
\nIt should be fully consumed within generated code."
|
"Copying partially applied instantiate_tpl call. This is an internal value.\
|
||||||
);
|
\nIt should be fully consumed within generated code."
|
||||||
|
);
|
||||||
|
}
|
||||||
self.clone().call(arg).await
|
self.clone().call(arg).await
|
||||||
}
|
}
|
||||||
async fn call(mut self, arg: Expr) -> GExpr {
|
async fn call(mut self, arg: Expr) -> GExpr {
|
||||||
match TypAtom::<MacTree>::try_from_expr(arg).await {
|
exec("macros::instantiate_tpl", async move |mut h| {
|
||||||
Err(e) => return Err::<Never, _>(e).to_expr().await,
|
match h.exec::<TAtom<MacTree>>(arg.clone()).await {
|
||||||
Ok(t) => self.argv.push(own(t).await),
|
Err(_) => panic!("Expected a macro param, found {}", fmt(&arg, arg.ctx().i()).await),
|
||||||
};
|
Ok(t) => self.argv.push(own(t).await),
|
||||||
if self.argv.len() < self.argc {
|
};
|
||||||
return self.to_expr().await;
|
if self.argv.len() < self.argc {
|
||||||
}
|
return self.to_expr().await;
|
||||||
let mut args = self.argv.into_iter();
|
}
|
||||||
let ret = map_mactree(&self.tpl, &mut false, &mut |mt| match mt.tok() {
|
let mut args = self.argv.into_iter();
|
||||||
MacTok::Slot => Some(args.next().expect("Not enough arguments to fill all slots")),
|
let ret = map_mactree(&self.tpl, &mut false, &mut |mt| match mt.tok() {
|
||||||
_ => None,
|
MacTok::Slot => Some(args.next().expect("Not enough arguments to fill all slots")),
|
||||||
});
|
_ => None,
|
||||||
assert!(args.next().is_none(), "Too many arguments for all slots");
|
});
|
||||||
ret.to_expr().await
|
assert!(args.next().is_none(), "Too many arguments for all slots");
|
||||||
|
ret.to_expr().await
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.to_expr()
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,13 @@ use orchid_base::parse::{
|
|||||||
};
|
};
|
||||||
use orchid_base::sym;
|
use orchid_base::sym;
|
||||||
use orchid_base::tree::Paren;
|
use orchid_base::tree::Paren;
|
||||||
|
use orchid_extension::atom::TAtom;
|
||||||
|
use orchid_extension::conv::TryFromExpr;
|
||||||
use orchid_extension::gen_expr::{atom, call, sym_ref};
|
use orchid_extension::gen_expr::{atom, call, sym_ref};
|
||||||
use orchid_extension::parser::{ConstCtx, PSnippet, PTok, PTokTree, ParsCtx, ParsedLine, Parser};
|
use orchid_extension::parser::{ConstCtx, PSnippet, PTok, PTokTree, ParsCtx, ParsedLine, Parser};
|
||||||
|
|
||||||
use crate::macros::mactree::{MacTok, MacTree, glossary_v, map_mactree_v};
|
use crate::macros::mactree::{MacTok, MacTree, glossary_v, map_mactree_v};
|
||||||
|
use crate::macros::ph_lexer::PhAtom;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LetLine;
|
pub struct LetLine;
|
||||||
@@ -42,10 +45,10 @@ impl Parser for LetLine {
|
|||||||
if let Some(e) = rep.errv() {
|
if let Some(e) = rep.errv() {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
Ok(call([
|
Ok(call(sym_ref(sym!(macros::lower; ctx.i()).await), [call(
|
||||||
sym_ref(sym!(macros::lower; ctx.i()).await),
|
sym_ref(sym!(macros::resolve; ctx.i()).await),
|
||||||
call([sym_ref(sym!(macros::resolve; ctx.i()).await), atom(macro_input)]),
|
[atom(macro_input)],
|
||||||
]))
|
)]))
|
||||||
})])
|
})])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,7 +113,10 @@ pub async fn parse_tok(tree: &PTokTree, ctx: &impl ParseCtx) -> Option<MacTree>
|
|||||||
return parse_tok(nested, ctx).boxed_local().await;
|
return parse_tok(nested, ctx).boxed_local().await;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PTok::Handle(expr) => MacTok::Value(expr.clone()),
|
PTok::Handle(expr) => match TAtom::<PhAtom>::try_from_expr(expr.clone()).await {
|
||||||
|
Err(_) => MacTok::Value(expr.clone()),
|
||||||
|
Ok(ta) => MacTok::Ph(ta.value.to_full(ta.ctx()).await),
|
||||||
|
},
|
||||||
PTok::NewExpr(never) => match *never {},
|
PTok::NewExpr(never) => match *never {},
|
||||||
PTok::LambdaHead(_) => panic!("Lambda-head handled in the sequence parser"),
|
PTok::LambdaHead(_) => panic!("Lambda-head handled in the sequence parser"),
|
||||||
PTok::S(p, body) =>
|
PTok::S(p, body) =>
|
||||||
|
|||||||
@@ -1,58 +1,47 @@
|
|||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::{Itertools, chain};
|
||||||
use orchid_base::error::Reporter;
|
use orchid_base::error::Reporter;
|
||||||
use orchid_base::sym;
|
use orchid_base::{clone, sym};
|
||||||
use orchid_extension::atom::TypAtom;
|
use orchid_extension::atom::TAtom;
|
||||||
use orchid_extension::atom_owned::own;
|
use orchid_extension::atom_owned::own;
|
||||||
use orchid_extension::conv::ToExpr;
|
use orchid_extension::conv::ToExpr;
|
||||||
use orchid_extension::coroutine_exec::exec;
|
use orchid_extension::coroutine_exec::exec;
|
||||||
use orchid_extension::gen_expr::{atom, call, sym_ref};
|
use orchid_extension::func_atom::Lambda;
|
||||||
|
use orchid_extension::gen_expr::{call, sym_ref};
|
||||||
use orchid_extension::reflection::{ReflMemKind, refl};
|
use orchid_extension::reflection::{ReflMemKind, refl};
|
||||||
use orchid_extension::tree::{GenMember, comments, fun, prefix};
|
use orchid_extension::tree::{GenMember, MemKind, fun, lazy, prefix};
|
||||||
use substack::Substack;
|
use substack::Substack;
|
||||||
|
|
||||||
use crate::Int;
|
use crate::MacTok;
|
||||||
use crate::macros::instantiate_tpl::InstantiateTplCall;
|
use crate::macros::macro_value::{Macro, Matcher};
|
||||||
use crate::macros::macro_line::{Macro, Matcher};
|
use crate::macros::mactree::{LowerCtx, MacTree, Ph};
|
||||||
use crate::macros::mactree::{LowerCtx, MacTree};
|
|
||||||
use crate::macros::recur_state::RecurState;
|
|
||||||
use crate::macros::resolve::{ResolveCtx, resolve};
|
use crate::macros::resolve::{ResolveCtx, resolve};
|
||||||
|
use crate::macros::utils::{mactree, mactreev, mk_macro};
|
||||||
|
|
||||||
pub fn gen_macro_lib() -> Vec<GenMember> {
|
pub fn gen_macro_lib() -> Vec<GenMember> {
|
||||||
prefix("macros", [
|
prefix("macros", [
|
||||||
comments(
|
fun(true, "lower", |tpl: TAtom<MacTree>| async move {
|
||||||
["This is an internal function, you can't obtain a value of its argument type.", "hidden"],
|
|
||||||
fun(true, "instantiate_tpl", |tpl: TypAtom<MacTree>, right: Int| async move {
|
|
||||||
InstantiateTplCall {
|
|
||||||
tpl: own(tpl).await,
|
|
||||||
argc: right.0.try_into().unwrap(),
|
|
||||||
argv: Vec::new(),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
fun(true, "resolve", |tpl: TypAtom<MacTree>| async move {
|
|
||||||
call([
|
|
||||||
sym_ref(sym!(macros::resolve_recur; tpl.untyped.ctx().i()).await),
|
|
||||||
atom(RecurState::Bottom),
|
|
||||||
tpl.untyped.ex().to_expr().await,
|
|
||||||
])
|
|
||||||
}),
|
|
||||||
fun(true, "lower", |tpl: TypAtom<MacTree>| async move {
|
|
||||||
let ctx = LowerCtx { sys: tpl.untyped.ctx().clone(), rep: &Reporter::new() };
|
let ctx = LowerCtx { sys: tpl.untyped.ctx().clone(), rep: &Reporter::new() };
|
||||||
let res = own(tpl).await.lower(ctx, Substack::Bottom).await;
|
let res = own(tpl).await.lower(ctx, Substack::Bottom).await;
|
||||||
if let Some(e) = Reporter::new().errv() { Err(e) } else { Ok(res) }
|
if let Some(e) = Reporter::new().errv() { Err(e) } else { Ok(res) }
|
||||||
}),
|
}),
|
||||||
fun(true, "resolve_recur", |state: TypAtom<RecurState>, tpl: TypAtom<MacTree>| async move {
|
fun(true, "recur", async |tpl: TAtom<MacTree>| {
|
||||||
exec("macros::resolve_recur", async move |mut h| {
|
call(sym_ref(sym!(macros::lower; tpl.i()).await), [call(
|
||||||
|
sym_ref(sym!(macros::resolve; tpl.i()).await),
|
||||||
|
[tpl.to_expr().await],
|
||||||
|
)])
|
||||||
|
}),
|
||||||
|
fun(true, "resolve", |tpl: TAtom<MacTree>| async move {
|
||||||
|
exec("macros::resolve", async move |mut h| {
|
||||||
let ctx = tpl.ctx().clone();
|
let ctx = tpl.ctx().clone();
|
||||||
let root = refl(&ctx);
|
let root = refl(&ctx);
|
||||||
let tpl = own(tpl.clone()).await;
|
let tpl = own(tpl.clone()).await;
|
||||||
let mut macros = HashMap::new();
|
let mut macros = HashMap::new();
|
||||||
for n in tpl.glossary() {
|
for n in tpl.glossary() {
|
||||||
if let Ok(ReflMemKind::Const) = root.get_by_path(n).await.map(|m| m.kind()) {
|
if let Ok(ReflMemKind::Const) = root.get_by_path(n).await.map(|m| m.kind()) {
|
||||||
let Ok(mac) = h.exec::<TypAtom<Macro>>(sym_ref(n.clone())).await else { continue };
|
let Ok(mac) = h.exec::<TAtom<Macro>>(sym_ref(n.clone())).await else { continue };
|
||||||
let mac = own(mac).await;
|
let mac = own(mac).await;
|
||||||
macros.entry(mac.0.own_kws[0].clone()).or_insert(mac);
|
macros.entry(mac.canonical_name(&ctx).await).or_insert(mac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut named = HashMap::new();
|
let mut named = HashMap::new();
|
||||||
@@ -69,7 +58,7 @@ pub fn gen_macro_lib() -> Vec<GenMember> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let priod = priod.into_iter().sorted_unstable_by_key(|(p, _)| *p).map(|(_, r)| r).collect();
|
let priod = priod.into_iter().sorted_unstable_by_key(|(p, _)| *p).map(|(_, r)| r).collect();
|
||||||
let mut rctx = ResolveCtx { h, recur: own(state).await, ctx: ctx.clone(), named, priod };
|
let mut rctx = ResolveCtx { h, ctx: ctx.clone(), named, priod };
|
||||||
let resolve_res = resolve(&mut rctx, &tpl).await;
|
let resolve_res = resolve(&mut rctx, &tpl).await;
|
||||||
std::mem::drop(rctx);
|
std::mem::drop(rctx);
|
||||||
match resolve_res {
|
match resolve_res {
|
||||||
@@ -79,5 +68,30 @@ pub fn gen_macro_lib() -> Vec<GenMember> {
|
|||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}),
|
}),
|
||||||
|
// TODO test whether any of this worked
|
||||||
|
lazy(true, "common", async |_, ctx| {
|
||||||
|
let add_macro = {
|
||||||
|
clone!(ctx);
|
||||||
|
mk_macro(Some(1), ["+"], [(
|
||||||
|
mactreev!(ctx.i(); "...$" lhs 0 macros::common::+ "...$" rhs 1),
|
||||||
|
Lambda::new("std::number::add", async move |lhs: TAtom<MacTree>, rhs: TAtom<MacTree>| {
|
||||||
|
mactree!(ctx.i(); std::number::add
|
||||||
|
(macros::recur "'" lhs.ex();)
|
||||||
|
(macros::recur "'" rhs.ex();)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)])
|
||||||
|
};
|
||||||
|
let mul_macro = mk_macro(Some(2), ["*"], [(
|
||||||
|
mactreev!(ctx.i(); "...$" lhs 0 macros::common::* "...$" rhs 1),
|
||||||
|
Lambda::new("std::number::mul", async |lhs: TAtom<MacTree>, rhs: TAtom<MacTree>| {
|
||||||
|
mactree!(lhs.ctx().i(); std::number::mul
|
||||||
|
(macros::recur "'" lhs.ex();)
|
||||||
|
(macros::recur "'" rhs.ex();)
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)]);
|
||||||
|
MemKind::Mod { members: chain!(add_macro, mul_macro).collect_vec() }
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,24 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use async_once_cell::OnceCell;
|
use async_once_cell::OnceCell;
|
||||||
use futures::{StreamExt, stream};
|
use futures::{StreamExt, stream};
|
||||||
use hashbrown::{HashMap, HashSet};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use never::Never;
|
|
||||||
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
||||||
use orchid_base::interner::Tok;
|
|
||||||
use orchid_base::location::Pos;
|
|
||||||
use orchid_base::name::Sym;
|
|
||||||
use orchid_base::parse::{
|
use orchid_base::parse::{
|
||||||
Comment, ParseCtx, Parsed, Snippet, expect_end, expect_tok, line_items, token_errv,
|
Comment, ParseCtx, Parsed, Snippet, expect_end, expect_tok, line_items, token_errv,
|
||||||
try_pop_no_fluff,
|
try_pop_no_fluff,
|
||||||
};
|
};
|
||||||
use orchid_base::tree::{Paren, Token};
|
use orchid_base::tree::{Paren, Token};
|
||||||
use orchid_base::{clone, sym};
|
use orchid_base::{clone, sym};
|
||||||
use orchid_extension::atom::{Atomic, TypAtom};
|
use orchid_extension::atom::TAtom;
|
||||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
|
|
||||||
use orchid_extension::conv::{ToExpr, TryFromExpr};
|
use orchid_extension::conv::{ToExpr, TryFromExpr};
|
||||||
use orchid_extension::gen_expr::{atom, call, sym_ref};
|
use orchid_extension::gen_expr::{atom, call, sym_ref};
|
||||||
use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser};
|
use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser};
|
||||||
|
|
||||||
use crate::macros::let_line::{dealias_mac_v, parse_tokv};
|
use crate::macros::let_line::{dealias_mac_v, parse_tokv};
|
||||||
|
use crate::macros::macro_value::{Macro, MacroData, Matcher, Rule};
|
||||||
use crate::macros::mactree::{glossary_v, map_mactree_v};
|
use crate::macros::mactree::{glossary_v, map_mactree_v};
|
||||||
use crate::macros::recur_state::{RecurState, RulePath};
|
|
||||||
use crate::macros::rule::matcher::{NamedMatcher, PriodMatcher};
|
use crate::macros::rule::matcher::{NamedMatcher, PriodMatcher};
|
||||||
use crate::{Int, MacTok};
|
use crate::{Int, MacTok};
|
||||||
|
|
||||||
@@ -48,42 +41,46 @@ impl Parser for MacroLine {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let module = ctx.module();
|
let module = ctx.module();
|
||||||
let Parsed { output, tail } = try_pop_no_fluff(&ctx, line).await?;
|
let Parsed { output: prio_or_body, tail } = try_pop_no_fluff(&ctx, line).await?;
|
||||||
let bad_first_item_err = || {
|
let bad_first_item_err = || {
|
||||||
token_errv(&ctx, output, "Expected priority or block", |s| {
|
token_errv(&ctx, prio_or_body, "Expected priority or block", |s| {
|
||||||
format!("Expected a priority number or a () block, found {s}")
|
format!("Expected a priority number or a () block, found {s}")
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
let (prio, body) = match &output.tok {
|
let (prio, body) = match &prio_or_body.tok {
|
||||||
Token::S(Paren::Round, body) => (None, body),
|
Token::S(Paren::Round, body) => {
|
||||||
Token::Handle(expr) => match TypAtom::<Int>::try_from_expr(expr.clone()).await {
|
expect_end(&ctx, tail).await?;
|
||||||
|
(None, body)
|
||||||
|
},
|
||||||
|
Token::Handle(expr) => match TAtom::<Int>::try_from_expr(expr.clone()).await {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(e + bad_first_item_err().await);
|
return Err(e + bad_first_item_err().await);
|
||||||
},
|
},
|
||||||
Ok(prio) => {
|
Ok(prio) => {
|
||||||
let Token::S(Paren::Round, block) = &output.tok else {
|
let Parsed { output: body, tail } = try_pop_no_fluff(&ctx, tail).await?;
|
||||||
|
let Token::S(Paren::Round, block) = &body.tok else {
|
||||||
return Err(
|
return Err(
|
||||||
token_errv(&ctx, output, "Expected () block", |s| {
|
token_errv(&ctx, prio_or_body, "Expected () block", |s| {
|
||||||
format!("Expected a () block, found {s}")
|
format!("Expected a () block, found {s}")
|
||||||
})
|
})
|
||||||
.await,
|
.await,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
expect_end(&ctx, tail).await?;
|
||||||
(Some(prio), block)
|
(Some(prio), block)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
_ => return Err(bad_first_item_err().await),
|
_ => return Err(bad_first_item_err().await),
|
||||||
};
|
};
|
||||||
expect_end(&ctx, tail).await?;
|
let lines = line_items(&ctx, Snippet::new(prio_or_body, body)).await;
|
||||||
let lines = line_items(&ctx, Snippet::new(output, body)).await;
|
|
||||||
let Some((kw_line, rule_lines)) = lines.split_first() else { return Ok(Vec::new()) };
|
let Some((kw_line, rule_lines)) = lines.split_first() else { return Ok(Vec::new()) };
|
||||||
let mut keywords = HashMap::new();
|
let mut keywords = Vec::new();
|
||||||
let Parsed { tail: kw_tail, .. } =
|
let Parsed { tail: kw_tail, .. } =
|
||||||
expect_tok(&ctx, kw_line.tail, ctx.i().i("keywords").await).await?;
|
expect_tok(&ctx, kw_line.tail, ctx.i().i("keywords").await).await?;
|
||||||
for kw_tok in kw_tail.iter().filter(|kw| !kw.is_fluff()) {
|
for kw_tok in kw_tail.iter().filter(|kw| !kw.is_fluff()) {
|
||||||
match kw_tok.as_name() {
|
match kw_tok.as_name() {
|
||||||
Some(kw) => {
|
Some(kw) => {
|
||||||
keywords.insert(kw, kw_tok.sr());
|
keywords.push((kw, kw_tok.sr()));
|
||||||
},
|
},
|
||||||
None => ctx.rep().report(
|
None => ctx.rep().report(
|
||||||
token_errv(&ctx, kw_tok, "invalid macro keywords list", |tok| {
|
token_errv(&ctx, kw_tok, "invalid macro keywords list", |tok| {
|
||||||
@@ -93,7 +90,7 @@ impl Parser for MacroLine {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let Some(macro_name) = keywords.keys().next().cloned() else {
|
let Some((macro_name, _)) = keywords.first().cloned() else {
|
||||||
return Err(mk_errv(
|
return Err(mk_errv(
|
||||||
ctx.i().i("macro with no keywords").await,
|
ctx.i().i("macro with no keywords").await,
|
||||||
"Macros must define at least one macro of their own.",
|
"Macros must define at least one macro of their own.",
|
||||||
@@ -103,9 +100,8 @@ impl Parser for MacroLine {
|
|||||||
let mut rules = Vec::new();
|
let mut rules = Vec::new();
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
for (idx, line) in rule_lines.iter().enumerate().map(|(n, v)| (n as u32, v)) {
|
for (idx, line) in rule_lines.iter().enumerate().map(|(n, v)| (n as u32, v)) {
|
||||||
let path = RulePath { module: module.clone(), main_kw: macro_name.clone(), rule: idx };
|
|
||||||
let sr = line.tail.sr();
|
let sr = line.tail.sr();
|
||||||
let name = ctx.i().i(&path.name()).await;
|
let name = ctx.i().i(&format!("rule::{}::{}", macro_name, idx)).await;
|
||||||
let Parsed { tail, .. } = expect_tok(&ctx, line.tail, ctx.i().i("rule").await).await?;
|
let Parsed { tail, .. } = expect_tok(&ctx, line.tail, ctx.i().i("rule").await).await?;
|
||||||
let arrow_token = ctx.i().i("=>").await;
|
let arrow_token = ctx.i().i("=>").await;
|
||||||
let Some((pattern, body)) = tail.split_once(|tok| tok.is_kw(arrow_token.clone())) else {
|
let Some((pattern, body)) = tail.split_once(|tok| tok.is_kw(arrow_token.clone())) else {
|
||||||
@@ -132,7 +128,7 @@ impl Parser for MacroLine {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
let body_sr = body.sr();
|
let body_sr = body.sr();
|
||||||
rules.push((name.clone(), placeholders, rules.len() as u32, sr.pos(), pattern));
|
rules.push((name.clone(), placeholders, pattern));
|
||||||
lines.push(ParsedLine::cnst(&sr, &line.output, true, name, async move |ctx| {
|
lines.push(ParsedLine::cnst(&sr, &line.output, true, name, async move |ctx| {
|
||||||
let rep = Reporter::new();
|
let rep = Reporter::new();
|
||||||
let body = dealias_mac_v(body_mactree, &ctx, &rep).await;
|
let body = dealias_mac_v(body_mactree, &ctx, &rep).await;
|
||||||
@@ -140,25 +136,23 @@ impl Parser for MacroLine {
|
|||||||
if let Some(e) = rep.errv() {
|
if let Some(e) = rep.errv() {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
Ok(call([
|
Ok(call(sym_ref(sym!(macros::lower; ctx.i()).await), [call(
|
||||||
sym_ref(sym!(macros::resolve_recur; ctx.i()).await),
|
sym_ref(sym!(macros::resolve; ctx.i()).await),
|
||||||
atom(RecurState::base(path)),
|
[macro_input.to_expr().await],
|
||||||
macro_input.to_expr().await,
|
)]))
|
||||||
]))
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
let mac_cell = Rc::new(OnceCell::new());
|
let mac_cell = Rc::new(OnceCell::new());
|
||||||
let keywords = Rc::new(keywords);
|
|
||||||
let rules = Rc::new(RefCell::new(Some(rules)));
|
let rules = Rc::new(RefCell::new(Some(rules)));
|
||||||
for (kw, sr) in &*keywords {
|
for (kw, sr) in &*keywords {
|
||||||
clone!(mac_cell, keywords, rules, module, prio);
|
clone!(mac_cell, rules, module, prio);
|
||||||
lines.push(ParsedLine::cnst(&sr.clone(), &comments, true, kw.clone(), async move |cctx| {
|
lines.push(ParsedLine::cnst(&sr.clone(), &comments, true, kw.clone(), async move |cctx| {
|
||||||
let mac = mac_cell
|
let mac = mac_cell
|
||||||
.get_or_init(async {
|
.get_or_init(async {
|
||||||
let rep = Reporter::new();
|
let rep = Reporter::new();
|
||||||
let rules = rules.borrow_mut().take().expect("once cell initializer runs");
|
let rules = rules.borrow_mut().take().expect("once cell initializer runs");
|
||||||
let rules = stream::iter(rules)
|
let rules = stream::iter(rules)
|
||||||
.then(|(body_name, placeholders, index, pos, pattern_macv)| {
|
.then(|(body_name, placeholders, pattern_macv)| {
|
||||||
let cctx = &cctx;
|
let cctx = &cctx;
|
||||||
let rep = &rep;
|
let rep = &rep;
|
||||||
let prio = &prio;
|
let prio = &prio;
|
||||||
@@ -171,8 +165,7 @@ impl Parser for MacroLine {
|
|||||||
};
|
};
|
||||||
let placeholders = placeholders.into_iter().map(|(ph, _)| ph.name).collect_vec();
|
let placeholders = placeholders.into_iter().map(|(ph, _)| ph.name).collect_vec();
|
||||||
match pattern_res {
|
match pattern_res {
|
||||||
Ok(pattern) =>
|
Ok(pattern) => Some(Rule { body_name, pattern, glossary, placeholders }),
|
||||||
Some(Rule { index, pos, body_name, pattern, glossary, placeholders }),
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
rep.report(e);
|
rep.report(e);
|
||||||
None
|
None
|
||||||
@@ -183,8 +176,7 @@ impl Parser for MacroLine {
|
|||||||
.flat_map(stream::iter)
|
.flat_map(stream::iter)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.await;
|
.await;
|
||||||
let own_kws = keywords.keys().cloned().collect_vec();
|
Macro(Rc::new(MacroData { module, prio: prio.map(|i| i.0 as u64), rules }))
|
||||||
Macro(Rc::new(MacroData { module, prio: prio.map(|i| i.0 as u64), rules, own_kws }))
|
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
atom(mac.clone())
|
atom(mac.clone())
|
||||||
@@ -193,36 +185,3 @@ impl Parser for MacroLine {
|
|||||||
Ok(lines)
|
Ok(lines)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MacroData {
|
|
||||||
pub module: Sym,
|
|
||||||
pub prio: Option<u64>,
|
|
||||||
pub rules: Vec<Rule>,
|
|
||||||
pub own_kws: Vec<Tok<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Macro(pub Rc<MacroData>);
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Rule {
|
|
||||||
pub index: u32,
|
|
||||||
pub pos: Pos,
|
|
||||||
pub pattern: Matcher,
|
|
||||||
pub glossary: HashSet<Sym>,
|
|
||||||
pub placeholders: Vec<Tok<String>>,
|
|
||||||
pub body_name: Tok<String>,
|
|
||||||
}
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Matcher {
|
|
||||||
Named(NamedMatcher),
|
|
||||||
Priod(PriodMatcher),
|
|
||||||
}
|
|
||||||
impl Atomic for Macro {
|
|
||||||
type Data = ();
|
|
||||||
type Variant = OwnedVariant;
|
|
||||||
}
|
|
||||||
impl OwnedAtom for Macro {
|
|
||||||
type Refs = Never;
|
|
||||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use never::Never;
|
|
||||||
use orchid_base::interner::Interner;
|
use orchid_base::interner::Interner;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::reqnot::Receipt;
|
use orchid_base::reqnot::Receipt;
|
||||||
|
use orchid_base::sym;
|
||||||
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
|
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
|
||||||
use orchid_extension::entrypoint::ExtReq;
|
use orchid_extension::entrypoint::ExtReq;
|
||||||
use orchid_extension::lexer::LexerObj;
|
use orchid_extension::lexer::LexerObj;
|
||||||
@@ -14,9 +14,11 @@ use orchid_extension::tree::GenMember;
|
|||||||
use crate::macros::instantiate_tpl::InstantiateTplCall;
|
use crate::macros::instantiate_tpl::InstantiateTplCall;
|
||||||
use crate::macros::let_line::LetLine;
|
use crate::macros::let_line::LetLine;
|
||||||
use crate::macros::macro_lib::gen_macro_lib;
|
use crate::macros::macro_lib::gen_macro_lib;
|
||||||
use crate::macros::macro_line::{Macro, MacroLine};
|
use crate::macros::macro_line::MacroLine;
|
||||||
|
use crate::macros::macro_value::Macro;
|
||||||
use crate::macros::mactree_lexer::MacTreeLexer;
|
use crate::macros::mactree_lexer::MacTreeLexer;
|
||||||
use crate::macros::recur_state::RecurState;
|
use crate::macros::ph_lexer::{PhAtom, PhLexer};
|
||||||
|
use crate::macros::requests::MacroReq;
|
||||||
use crate::{MacTree, StdSystem};
|
use crate::{MacTree, StdSystem};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@@ -30,20 +32,26 @@ impl SystemCtor for MacroSystem {
|
|||||||
}
|
}
|
||||||
impl SystemCard for MacroSystem {
|
impl SystemCard for MacroSystem {
|
||||||
type Ctor = Self;
|
type Ctor = Self;
|
||||||
type Req = Never;
|
type Req = MacroReq;
|
||||||
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomDynfo>>> {
|
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomDynfo>>> {
|
||||||
[
|
[
|
||||||
Some(InstantiateTplCall::dynfo()),
|
Some(InstantiateTplCall::dynfo()),
|
||||||
Some(MacTree::dynfo()),
|
Some(MacTree::dynfo()),
|
||||||
Some(RecurState::dynfo()),
|
|
||||||
Some(Macro::dynfo()),
|
Some(Macro::dynfo()),
|
||||||
|
Some(PhAtom::dynfo()),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl System for MacroSystem {
|
impl System for MacroSystem {
|
||||||
async fn request(_: ExtReq<'_>, req: Self::Req) -> Receipt<'_> { match req {} }
|
async fn request(_: ExtReq<'_>, req: Self::Req) -> Receipt<'_> { todo!("Handle {req:?}") }
|
||||||
async fn prelude(_: &Interner) -> Vec<Sym> { vec![] }
|
async fn prelude(i: &Interner) -> Vec<Sym> {
|
||||||
fn lexers() -> Vec<LexerObj> { vec![&MacTreeLexer] }
|
vec![
|
||||||
|
sym!(macros::resolve; i).await,
|
||||||
|
sym!(macros::common::+; i).await,
|
||||||
|
sym!(macros::common::*; i).await,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
fn lexers() -> Vec<LexerObj> { vec![&MacTreeLexer, &PhLexer] }
|
||||||
fn parsers() -> Vec<ParserObj> { vec![&LetLine, &MacroLine] }
|
fn parsers() -> Vec<ParserObj> { vec![&LetLine, &MacroLine] }
|
||||||
fn env() -> Vec<GenMember> { gen_macro_lib() }
|
fn env() -> Vec<GenMember> { gen_macro_lib() }
|
||||||
}
|
}
|
||||||
|
|||||||
48
orchid-std/src/macros/macro_value.rs
Normal file
48
orchid-std/src/macros/macro_value.rs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use hashbrown::HashSet;
|
||||||
|
use never::Never;
|
||||||
|
use orchid_base::interner::Tok;
|
||||||
|
use orchid_base::name::Sym;
|
||||||
|
use orchid_extension::atom::Atomic;
|
||||||
|
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
|
||||||
|
use orchid_extension::system::SysCtx;
|
||||||
|
|
||||||
|
use crate::macros::rule::matcher::{NamedMatcher, PriodMatcher};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MacroData {
|
||||||
|
pub module: Sym,
|
||||||
|
pub prio: Option<u64>,
|
||||||
|
pub rules: Vec<Rule>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Macro(pub Rc<MacroData>);
|
||||||
|
impl Macro {
|
||||||
|
pub async fn canonical_name(&self, ctx: &SysCtx) -> Sym {
|
||||||
|
self.0.module.suffix([self.0.rules[0].body_name.clone()], ctx.i()).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Rule {
|
||||||
|
pub pattern: Matcher,
|
||||||
|
pub glossary: HashSet<Sym>,
|
||||||
|
pub placeholders: Vec<Tok<String>>,
|
||||||
|
pub body_name: Tok<String>,
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Matcher {
|
||||||
|
Named(NamedMatcher),
|
||||||
|
Priod(PriodMatcher),
|
||||||
|
}
|
||||||
|
impl Atomic for Macro {
|
||||||
|
type Data = ();
|
||||||
|
type Variant = OwnedVariant;
|
||||||
|
}
|
||||||
|
impl OwnedAtom for Macro {
|
||||||
|
type Refs = Never;
|
||||||
|
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ use futures::FutureExt;
|
|||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use orchid_api_derive::Coding;
|
||||||
use orchid_base::error::{OrcErrv, Reporter, mk_errv};
|
use orchid_base::error::{OrcErrv, Reporter, mk_errv};
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants, fmt};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants, fmt};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
@@ -42,38 +43,56 @@ impl MacTree {
|
|||||||
MacTok::Bottom(e) => bot(e.clone()),
|
MacTok::Bottom(e) => bot(e.clone()),
|
||||||
MacTok::Lambda(arg, body) => {
|
MacTok::Lambda(arg, body) => {
|
||||||
let MacTok::Name(name) = &*arg.tok else {
|
let MacTok::Name(name) = &*arg.tok else {
|
||||||
let err = mk_errv(
|
return bot(mk_errv(
|
||||||
ctx.sys.i().i("Syntax error after macros").await,
|
ctx.sys.i().i("Syntax error after macros").await,
|
||||||
"This token ends up as a binding, consider replacing it with a name",
|
"This token ends up as a binding, consider replacing it with a name",
|
||||||
[arg.pos()],
|
[arg.pos()],
|
||||||
);
|
));
|
||||||
ctx.rep.report(err.clone());
|
|
||||||
return bot(err);
|
|
||||||
};
|
};
|
||||||
lambda(args.len() as u64, lower_v(body, ctx, args.push(name.clone())).await)
|
let arg_pos = args.len() as u64;
|
||||||
|
let args = args.push(name.clone());
|
||||||
|
let body = match &body[..] {
|
||||||
|
[] => bot(mk_errv(
|
||||||
|
ctx.sys.i().i("Empty lambda body").await,
|
||||||
|
"Lambdas must evaluate to an expression",
|
||||||
|
[self.pos()],
|
||||||
|
)),
|
||||||
|
[f, argv @ ..] => call(
|
||||||
|
f.lower(ctx.clone(), args.clone()).boxed_local().await,
|
||||||
|
lower_v(argv, ctx, args).await,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
lambda(arg_pos, body)
|
||||||
},
|
},
|
||||||
MacTok::Name(name) => match args.iter().enumerate().find(|(_, n)| *n == name) {
|
MacTok::Name(name) => match args.iter().enumerate().find(|(_, n)| *n == name) {
|
||||||
None => sym_ref(name.clone()),
|
None => sym_ref(name.clone()),
|
||||||
Some((i, _)) => arg((args.len() - i) as u64),
|
Some((i, _)) => arg((args.len() - i - 1) as u64),
|
||||||
},
|
},
|
||||||
MacTok::Ph(ph) => {
|
MacTok::Ph(ph) => {
|
||||||
let err = mk_errv(
|
return bot(mk_errv(
|
||||||
ctx.sys.i().i("Placeholder in value").await,
|
ctx.sys.i().i("Placeholder in value").await,
|
||||||
format!("Placeholder {ph} is only supported in macro patterns"),
|
format!("Placeholder {ph} is only supported in macro patterns"),
|
||||||
[self.pos()],
|
[self.pos()],
|
||||||
);
|
));
|
||||||
ctx.rep.report(err.clone());
|
},
|
||||||
return bot(err);
|
MacTok::S(Paren::Round, body) => match &body[..] {
|
||||||
|
[fun, argv @ ..] => call(
|
||||||
|
fun.lower(ctx.clone(), args.clone()).boxed_local().await,
|
||||||
|
lower_v(argv, ctx, args).await,
|
||||||
|
),
|
||||||
|
[] =>
|
||||||
|
return bot(mk_errv(
|
||||||
|
ctx.sys.i().i("Empty ()").await,
|
||||||
|
"Empty () is not a meaningful expression",
|
||||||
|
[self.pos()],
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
MacTok::S(Paren::Round, body) => call(lower_v(body, ctx, args).await),
|
|
||||||
MacTok::S(..) => {
|
MacTok::S(..) => {
|
||||||
let err = mk_errv(
|
return bot(mk_errv(
|
||||||
ctx.sys.i().i("[] or {} after macros").await,
|
ctx.sys.i().i("[] or {} after macros").await,
|
||||||
format!("{} didn't match any macro", fmt(self, ctx.sys.i()).await),
|
format!("{} didn't match any macro", fmt(self, ctx.sys.i()).await),
|
||||||
[self.pos()],
|
[self.pos()],
|
||||||
);
|
));
|
||||||
ctx.rep.report(err.clone());
|
|
||||||
return bot(err);
|
|
||||||
},
|
},
|
||||||
MacTok::Slot => panic!("Uninstantiated template should never be exposed"),
|
MacTok::Slot => panic!("Uninstantiated template should never be exposed"),
|
||||||
MacTok::Value(v) => v.clone().to_expr().await,
|
MacTok::Value(v) => v.clone().to_expr().await,
|
||||||
@@ -90,7 +109,8 @@ impl OwnedAtom for MacTree {
|
|||||||
|
|
||||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||||
async fn print_atom<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
async fn print_atom<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
self.tok.print(c).await
|
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("'{0}")))
|
||||||
|
.units([self.tok.print(c).await])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Format for MacTree {
|
impl Format for MacTree {
|
||||||
@@ -134,22 +154,18 @@ impl Format for MacTok {
|
|||||||
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
match self {
|
match self {
|
||||||
Self::Value(v) => v.print(c).await,
|
Self::Value(v) => v.print(c).await,
|
||||||
Self::Lambda(arg, b) => FmtUnit::new(
|
Self::Lambda(arg, b) => tl_cache!(Rc<Variants>: Rc::new(Variants::default()
|
||||||
tl_cache!(Rc<Variants>: Rc::new(Variants::default()
|
.unbounded("\\{0} {1l}")
|
||||||
.unbounded("\\{0b}.{1l}")
|
.bounded("(\\{0} {1b})")))
|
||||||
.bounded("(\\{0b}.{1b})"))),
|
.units([arg.print(c).boxed_local().await, mtreev_fmt(b, c).await]),
|
||||||
[arg.print(c).boxed_local().await, mtreev_fmt(b, c).await],
|
|
||||||
),
|
|
||||||
Self::Name(n) => format!("{n}").into(),
|
Self::Name(n) => format!("{n}").into(),
|
||||||
Self::Ph(ph) => format!("{ph}").into(),
|
Self::Ph(ph) => format!("{ph}").into(),
|
||||||
Self::S(p, body) => FmtUnit::new(
|
Self::S(p, body) => match *p {
|
||||||
match *p {
|
Paren::Round => tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("({0b})"))),
|
||||||
Paren::Round => Rc::new(Variants::default().bounded("({0b})")),
|
Paren::Curly => tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("{{0b}}"))),
|
||||||
Paren::Curly => Rc::new(Variants::default().bounded("{{0b}}")),
|
Paren::Square => tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("[{0b}]"))),
|
||||||
Paren::Square => Rc::new(Variants::default().bounded("[{0b}]")),
|
}
|
||||||
},
|
.units([mtreev_fmt(body, c).await]),
|
||||||
[mtreev_fmt(body, c).await],
|
|
||||||
),
|
|
||||||
Self::Slot => "$SLOT".into(),
|
Self::Slot => "$SLOT".into(),
|
||||||
Self::Bottom(err) if err.len() == 1 => format!("Bottom({}) ", err.one().unwrap()).into(),
|
Self::Bottom(err) if err.len() == 1 => format!("Bottom({}) ", err.one().unwrap()).into(),
|
||||||
Self::Bottom(err) => format!("Botttom(\n{}) ", indent(&err.to_string())).into(),
|
Self::Bottom(err) => format!("Botttom(\n{}) ", indent(&err.to_string())).into(),
|
||||||
@@ -181,7 +197,7 @@ impl Display for Ph {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Coding)]
|
||||||
pub enum PhKind {
|
pub enum PhKind {
|
||||||
Scalar,
|
Scalar,
|
||||||
Vector { at_least_one: bool, priority: u8 },
|
Vector { at_least_one: bool, priority: u8 },
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
use itertools::chain;
|
||||||
use orchid_base::error::{OrcRes, mk_errv};
|
use orchid_base::error::{OrcRes, mk_errv};
|
||||||
use orchid_base::parse::ParseCtx;
|
use orchid_base::parse::ParseCtx;
|
||||||
use orchid_base::sym;
|
|
||||||
use orchid_base::tokens::PARENS;
|
use orchid_base::tokens::PARENS;
|
||||||
use orchid_base::tree::Paren;
|
use orchid_base::tree::Paren;
|
||||||
use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable};
|
use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable};
|
||||||
use orchid_extension::parser::p_tree2gen;
|
use orchid_extension::parser::p_tree2gen;
|
||||||
use orchid_extension::tree::{GenTok, GenTokTree, ref_tok, x_tok};
|
use orchid_extension::tree::{GenTok, GenTokTree, x_tok};
|
||||||
|
|
||||||
|
use crate::macros::instantiate_tpl::InstantiateTplCall;
|
||||||
use crate::macros::let_line::parse_tok;
|
use crate::macros::let_line::parse_tok;
|
||||||
use crate::macros::mactree::{MacTok, MacTree};
|
use crate::macros::mactree::{MacTok, MacTree};
|
||||||
|
|
||||||
@@ -29,12 +30,9 @@ impl Lexer for MacTreeLexer {
|
|||||||
let tok = match &args[..] {
|
let tok = match &args[..] {
|
||||||
[] => x_tok(mactree).await,
|
[] => x_tok(mactree).await,
|
||||||
_ => {
|
_ => {
|
||||||
let call = ([
|
let instantiate_tpl_call =
|
||||||
ref_tok(sym!(macros::instantiate_tpl; ctx.i()).await).await.at(range.clone()),
|
InstantiateTplCall { argc: args.len(), argv: vec![], tpl: mactree };
|
||||||
x_tok(mactree).await.at(range.clone()),
|
let call = chain!([x_tok(instantiate_tpl_call).await.at(range.clone())], args);
|
||||||
]
|
|
||||||
.into_iter())
|
|
||||||
.chain(args.into_iter());
|
|
||||||
GenTok::S(Paren::Round, call.collect())
|
GenTok::S(Paren::Round, call.collect())
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ mod let_line;
|
|||||||
mod macro_lib;
|
mod macro_lib;
|
||||||
mod macro_line;
|
mod macro_line;
|
||||||
pub mod macro_system;
|
pub mod macro_system;
|
||||||
|
mod macro_value;
|
||||||
pub mod mactree;
|
pub mod mactree;
|
||||||
mod mactree_lexer;
|
mod mactree_lexer;
|
||||||
pub mod recur_state;
|
mod ph_lexer;
|
||||||
|
mod requests;
|
||||||
mod resolve;
|
mod resolve;
|
||||||
mod rule;
|
mod rule;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use mactree::{MacTok, MacTree};
|
use mactree::{MacTok, MacTree};
|
||||||
|
|||||||
79
orchid-std/src/macros/ph_lexer.rs
Normal file
79
orchid-std/src/macros/ph_lexer.rs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
use orchid_api_derive::Coding;
|
||||||
|
use orchid_base::error::{OrcRes, mk_errv};
|
||||||
|
use orchid_base::format::FmtUnit;
|
||||||
|
use orchid_base::parse::{name_char, name_start};
|
||||||
|
use orchid_extension::atom::Atomic;
|
||||||
|
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
||||||
|
use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable};
|
||||||
|
use orchid_extension::system::SysCtx;
|
||||||
|
use orchid_extension::tree::{GenTokTree, x_tok};
|
||||||
|
|
||||||
|
use crate::macros::mactree::{Ph, PhKind};
|
||||||
|
|
||||||
|
#[derive(Clone, Coding)]
|
||||||
|
pub struct PhAtom(orchid_api::TStr, PhKind);
|
||||||
|
impl PhAtom {
|
||||||
|
pub async fn to_full(&self, ctx: &SysCtx) -> Ph {
|
||||||
|
Ph { kind: self.1, name: ctx.i().ex(self.0).await }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Atomic for PhAtom {
|
||||||
|
type Data = Self;
|
||||||
|
type Variant = ThinVariant;
|
||||||
|
}
|
||||||
|
impl ThinAtom for PhAtom {
|
||||||
|
async fn print(&self, ctx: SysCtx) -> FmtUnit {
|
||||||
|
Ph { name: ctx.i().ex(self.0).await, kind: self.1 }.to_string().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct PhLexer;
|
||||||
|
impl Lexer for PhLexer {
|
||||||
|
const CHAR_FILTER: &'static [std::ops::RangeInclusive<char>] = &['$'..='$', '.'..='.'];
|
||||||
|
async fn lex<'a>(line: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree)> {
|
||||||
|
let (tail, name, phkind) = if let Some(tail) = line.strip_prefix("$")
|
||||||
|
&& tail.starts_with(name_start)
|
||||||
|
{
|
||||||
|
let name = tail.split_once(|c| !name_char(c)).map_or("", |(h, _)| h);
|
||||||
|
let tail = tail.split_at(name.len()).1;
|
||||||
|
(tail, name, PhKind::Scalar)
|
||||||
|
} else {
|
||||||
|
async fn name_and_prio<'a>(
|
||||||
|
tail: &'a str,
|
||||||
|
ctx: &'a LexContext<'a>,
|
||||||
|
) -> OrcRes<(&'a str, u8, &'a str)> {
|
||||||
|
let name = tail.split_once(|c| !name_char(c)).map_or("", |(h, _)| h);
|
||||||
|
let tail = tail.split_at(name.len()).1;
|
||||||
|
let (prio, tail) = match tail.strip_prefix(":") {
|
||||||
|
None => (0, tail),
|
||||||
|
Some(tail) => {
|
||||||
|
let prio = tail.split_once(|c: char| c.is_ascii_digit()).map_or("", |(h, _)| h);
|
||||||
|
let tail = tail.split_at(prio.len()).1;
|
||||||
|
if let Ok(prio_num) = prio.parse::<u8>() {
|
||||||
|
(prio_num, tail)
|
||||||
|
} else {
|
||||||
|
return Err(mk_errv(
|
||||||
|
ctx.ctx.i().i("Invalid priority, must be 0-255").await,
|
||||||
|
format!("{prio} is not a valid placeholder priority"),
|
||||||
|
[ctx.pos_lt(prio.len(), tail)],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok((name, prio, tail))
|
||||||
|
}
|
||||||
|
if let Some(tail) = line.strip_prefix("..$") {
|
||||||
|
let (name, priority, tail) = name_and_prio(tail, ctx).await?;
|
||||||
|
(tail, name, PhKind::Vector { at_least_one: false, priority })
|
||||||
|
} else if let Some(tail) = line.strip_prefix("...$") {
|
||||||
|
let (name, priority, tail) = name_and_prio(tail, ctx).await?;
|
||||||
|
(tail, name, PhKind::Vector { at_least_one: true, priority })
|
||||||
|
} else {
|
||||||
|
return Err(err_not_applicable(ctx.ctx.i()).await);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let ph_atom = PhAtom(ctx.ctx.i().i::<String>(name).await.to_api(), phkind);
|
||||||
|
Ok((tail, x_tok(ph_atom).await.at(ctx.pos_tt(line, tail))))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
use std::fmt;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use never::Never;
|
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit};
|
|
||||||
use orchid_base::interner::Tok;
|
|
||||||
use orchid_base::name::Sym;
|
|
||||||
use orchid_extension::atom::Atomic;
|
|
||||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct RulePath {
|
|
||||||
pub module: Sym,
|
|
||||||
pub main_kw: Tok<String>,
|
|
||||||
pub rule: u32,
|
|
||||||
}
|
|
||||||
impl RulePath {
|
|
||||||
pub fn name(&self) -> String { format!("rule::{}::{}", self.main_kw, self.rule) }
|
|
||||||
}
|
|
||||||
impl fmt::Display for RulePath {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "Rule {}::({})::{}", self.module, self.main_kw, self.rule)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum RecurState {
|
|
||||||
Bottom,
|
|
||||||
Recursive { path: RulePath, prev: Rc<RecurState> },
|
|
||||||
}
|
|
||||||
impl RecurState {
|
|
||||||
pub fn base(path: RulePath) -> Self {
|
|
||||||
RecurState::Recursive { path, prev: Rc::new(RecurState::Bottom) }
|
|
||||||
}
|
|
||||||
pub fn push(&self, new: RulePath) -> Option<Self> {
|
|
||||||
let mut cur = self;
|
|
||||||
while let Self::Recursive { path, prev } = cur {
|
|
||||||
if &new == path {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
cur = prev;
|
|
||||||
}
|
|
||||||
Some(Self::Recursive { path: new, prev: Rc::new(self.clone()) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Atomic for RecurState {
|
|
||||||
type Data = Option<()>;
|
|
||||||
type Variant = OwnedVariant;
|
|
||||||
}
|
|
||||||
impl OwnedAtom for RecurState {
|
|
||||||
type Refs = Never;
|
|
||||||
|
|
||||||
async fn val(&self) -> Cow<'_, Self::Data> {
|
|
||||||
Cow::Owned(match self {
|
|
||||||
Self::Bottom => None,
|
|
||||||
Self::Recursive { .. } => Some(()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async fn print_atom<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
|
||||||
self.to_string().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl fmt::Display for RecurState {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Bottom => write!(f, "RecurState::Bottom"),
|
|
||||||
Self::Recursive { path, prev } => write!(f, "{path}\n{prev}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
67
orchid-std/src/macros/requests.rs
Normal file
67
orchid-std/src/macros/requests.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
use orchid_api_derive::{Coding, Hierarchy};
|
||||||
|
use orchid_api_traits::Request;
|
||||||
|
|
||||||
|
use crate::api;
|
||||||
|
use crate::macros::mactree::PhKind;
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
Create handlers and wrappers for these, probably expose MacTree to other crates.
|
||||||
|
Define new extension binary to test the request functionality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
|
#[extendable]
|
||||||
|
pub enum MacroReq {
|
||||||
|
CreateMacro(CreateMacro),
|
||||||
|
CreateQuote(CreateQuote),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
|
#[extends(MacroReq)]
|
||||||
|
pub struct CreateMacro {
|
||||||
|
pub module: api::TStrv,
|
||||||
|
pub prio: Option<u64>,
|
||||||
|
pub rules: Vec<CreateRule>,
|
||||||
|
}
|
||||||
|
impl Request for CreateMacro {
|
||||||
|
type Response = api::ExprTicket;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Coding)]
|
||||||
|
pub struct CreateRule {
|
||||||
|
pub pattern: Vec<api::TokenTree>,
|
||||||
|
pub body_name: api::TStr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
|
#[extends(MacroReq)]
|
||||||
|
pub struct CreateQuote(MsgMacTree);
|
||||||
|
impl Request for CreateQuote {
|
||||||
|
type Response = api::ExprTicket;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Coding)]
|
||||||
|
pub struct MsgMacTree {
|
||||||
|
pub tok: MsgMacTok,
|
||||||
|
pub location: api::Location,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Coding)]
|
||||||
|
pub enum MsgMacTok {
|
||||||
|
S(api::Paren, Vec<MsgMacTree>),
|
||||||
|
Name(api::TStrv),
|
||||||
|
/// Only permitted in arguments to `instantiate_tpl`
|
||||||
|
Slot,
|
||||||
|
Value(api::ExprTicket),
|
||||||
|
Lambda(Box<MsgMacTree>, Vec<MsgMacTree>),
|
||||||
|
/// Only permitted in "pattern" values produced by macro blocks, which are
|
||||||
|
/// never accessed as variables by usercode
|
||||||
|
Ph(MsgPh),
|
||||||
|
Bottom(Vec<api::OrcError>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Coding)]
|
||||||
|
pub struct MsgPh {
|
||||||
|
kind: PhKind,
|
||||||
|
name: api::TStr,
|
||||||
|
}
|
||||||
@@ -1,25 +1,22 @@
|
|||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::mk_errv;
|
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::sym;
|
use orchid_base::sym;
|
||||||
use orchid_base::tree::Paren;
|
use orchid_base::tree::Paren;
|
||||||
use orchid_extension::conv::ToExpr;
|
use orchid_extension::conv::ToExpr;
|
||||||
use orchid_extension::coroutine_exec::ExecHandle;
|
use orchid_extension::coroutine_exec::ExecHandle;
|
||||||
use orchid_extension::gen_expr::{GExpr, bot, call, sym_ref};
|
use orchid_extension::gen_expr::{GExpr, call, sym_ref};
|
||||||
use orchid_extension::system::SysCtx;
|
use orchid_extension::system::SysCtx;
|
||||||
|
|
||||||
use crate::macros::macro_line::{Macro, Rule};
|
use crate::macros::macro_value::{Macro, Rule};
|
||||||
use crate::macros::recur_state::{RecurState, RulePath};
|
|
||||||
use crate::macros::rule::matcher::{NamedMatcher, PriodMatcher};
|
use crate::macros::rule::matcher::{NamedMatcher, PriodMatcher};
|
||||||
use crate::macros::rule::state::{MatchState, StateEntry};
|
use crate::macros::rule::state::{MatchState, StateEntry};
|
||||||
use crate::{MacTok, MacTree};
|
use crate::{MacTok, MacTree};
|
||||||
|
|
||||||
pub struct ResolveCtx<'a> {
|
pub struct ResolveCtx<'a> {
|
||||||
pub ctx: SysCtx,
|
pub ctx: SysCtx,
|
||||||
pub recur: RecurState,
|
|
||||||
pub h: ExecHandle<'a>,
|
pub h: ExecHandle<'a>,
|
||||||
pub named: HashMap<Sym, Vec<(&'a NamedMatcher, &'a Macro, &'a Rule)>>,
|
pub named: HashMap<Sym, Vec<(&'a NamedMatcher, &'a Macro, &'a Rule)>>,
|
||||||
pub priod: Vec<(&'a PriodMatcher, &'a Macro, &'a Rule)>,
|
pub priod: Vec<(&'a PriodMatcher, &'a Macro, &'a Rule)>,
|
||||||
@@ -52,7 +49,7 @@ pub async fn resolve_seq(ctx: &mut ResolveCtx<'_>, val: &[MacTree]) -> Option<Ve
|
|||||||
any_changed = true;
|
any_changed = true;
|
||||||
let (mac, rule, (state, tail)) = matches.into_iter().exactly_one().unwrap();
|
let (mac, rule, (state, tail)) = matches.into_iter().exactly_one().unwrap();
|
||||||
let end = val.len() - tail.len();
|
let end = val.len() - tail.len();
|
||||||
let body_call = mk_body_call(mac, rule, &state, &ctx.ctx, ctx.recur.clone()).await;
|
let body_call = mk_body_call(mac, rule, &state, &ctx.ctx).await;
|
||||||
std::mem::drop(state);
|
std::mem::drop(state);
|
||||||
val.splice(i..end, [MacTok::Value(ctx.h.register(body_call).await).at(Pos::None)]);
|
val.splice(i..end, [MacTok::Value(ctx.h.register(body_call).await).at(Pos::None)]);
|
||||||
i = end;
|
i = end;
|
||||||
@@ -66,10 +63,8 @@ pub async fn resolve_seq(ctx: &mut ResolveCtx<'_>, val: &[MacTree]) -> Option<Ve
|
|||||||
for (matcher, mac, rule) in &ctx.priod {
|
for (matcher, mac, rule) in &ctx.priod {
|
||||||
let Some(state) = matcher.apply(&val, |_| false) else { continue };
|
let Some(state) = matcher.apply(&val, |_| false) else { continue };
|
||||||
return Some(vec![
|
return Some(vec![
|
||||||
MacTok::Value(
|
MacTok::Value(ctx.h.register(mk_body_call(mac, rule, &state, &ctx.ctx).await).await)
|
||||||
ctx.h.register(mk_body_call(mac, rule, &state, &ctx.ctx, ctx.recur.clone()).await).await,
|
.at(Pos::None),
|
||||||
)
|
|
||||||
.at(Pos::None),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
for expr in val.iter_mut() {
|
for expr in val.iter_mut() {
|
||||||
@@ -81,30 +76,16 @@ pub async fn resolve_seq(ctx: &mut ResolveCtx<'_>, val: &[MacTree]) -> Option<Ve
|
|||||||
if any_changed { Some(val) } else { None }
|
if any_changed { Some(val) } else { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn mk_body_call(
|
async fn mk_body_call(mac: &Macro, rule: &Rule, state: &MatchState<'_>, ctx: &SysCtx) -> GExpr {
|
||||||
mac: &Macro,
|
let mut call_args = vec![];
|
||||||
rule: &Rule,
|
|
||||||
state: &MatchState<'_>,
|
|
||||||
ctx: &SysCtx,
|
|
||||||
recur: RecurState,
|
|
||||||
) -> GExpr {
|
|
||||||
let rule_path =
|
|
||||||
RulePath { module: mac.0.module.clone(), main_kw: mac.0.own_kws[0].clone(), rule: rule.index };
|
|
||||||
let Some(new_recur) = recur.push(rule_path.clone()) else {
|
|
||||||
return bot(mk_errv(
|
|
||||||
ctx.i().i("Circular macro dependency").await,
|
|
||||||
format!("The definition of {rule_path} is circular"),
|
|
||||||
[rule.pos.clone()],
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let mut call_args = vec![sym_ref(mac.0.module.suffix([rule.body_name.clone()], ctx.i()).await)];
|
|
||||||
for name in rule.placeholders.iter() {
|
for name in rule.placeholders.iter() {
|
||||||
call_args.push(match state.get(name).expect("Missing state entry for placeholder") {
|
call_args.push(match state.get(name).expect("Missing state entry for placeholder") {
|
||||||
StateEntry::Scalar(scal) => (**scal).clone().to_expr().await,
|
StateEntry::Scalar(scal) => (**scal).clone().to_expr().await,
|
||||||
StateEntry::Vec(vec) => MacTok::S(Paren::Round, vec.to_vec()).at(Pos::None).to_expr().await,
|
StateEntry::Vec(vec) => MacTok::S(Paren::Round, vec.to_vec()).at(Pos::None).to_expr().await,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
call_args
|
call(sym_ref(sym!(macros::lower; ctx.i()).await), [call(
|
||||||
.push(call([sym_ref(sym!(macros::resolve_recur; ctx.i()).await), new_recur.to_expr().await]));
|
sym_ref(mac.0.module.suffix([rule.body_name.clone()], ctx.i()).await),
|
||||||
call(call_args)
|
call_args,
|
||||||
|
)])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ pub fn vec_match<'a>(
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
// XXX predict heap space usage and allocation count
|
|
||||||
VecMatcher::Middle { left, left_sep, mid, right_sep, right, key_order } => {
|
VecMatcher::Middle { left, left_sep, mid, right_sep, right, key_order } => {
|
||||||
if seq.len() < left_sep.len() + right_sep.len() {
|
if seq.len() < left_sep.len() + right_sep.len() {
|
||||||
return None;
|
return None;
|
||||||
|
|||||||
166
orchid-std/src/macros/utils.rs
Normal file
166
orchid-std/src/macros/utils.rs
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use async_fn_stream::stream;
|
||||||
|
use futures::StreamExt;
|
||||||
|
use itertools::{Itertools, chain};
|
||||||
|
use orchid_base::name::{NameLike, Sym, VPath};
|
||||||
|
use orchid_extension::conv::ToExpr;
|
||||||
|
use orchid_extension::gen_expr::sym_ref;
|
||||||
|
use orchid_extension::tree::{GenMember, MemKind, cnst, lazy};
|
||||||
|
|
||||||
|
use crate::macros::macro_value::{Macro, MacroData, Matcher, Rule};
|
||||||
|
use crate::macros::mactree::map_mactree_v;
|
||||||
|
use crate::macros::rule::matcher::{NamedMatcher, PriodMatcher};
|
||||||
|
use crate::{MacTok, MacTree};
|
||||||
|
|
||||||
|
pub(crate) fn mk_macro<B: ToExpr + Clone + 'static>(
|
||||||
|
prio: Option<u64>,
|
||||||
|
own_kws: impl IntoIterator<Item = &'static str>,
|
||||||
|
rules: impl IntoIterator<Item = (Vec<MacTree>, B)>,
|
||||||
|
) -> Vec<GenMember> {
|
||||||
|
let own_kws = own_kws.into_iter().collect_vec();
|
||||||
|
let name = own_kws[0];
|
||||||
|
let (patterns, bodies) = rules.into_iter().unzip::<_, _, Vec<Vec<MacTree>>, Vec<B>>();
|
||||||
|
let main_const = lazy(true, name, async move |path, ctx| {
|
||||||
|
let module = (Sym::new(path.split_last_seg().1.iter().cloned(), ctx.i()).await)
|
||||||
|
.expect("Default macro in global root");
|
||||||
|
MemKind::Const(
|
||||||
|
Macro(Rc::new(MacroData {
|
||||||
|
module,
|
||||||
|
prio,
|
||||||
|
rules: stream(async |mut h| {
|
||||||
|
for (counter, pat) in patterns.into_iter().enumerate() {
|
||||||
|
let mut placeholders = Vec::new();
|
||||||
|
map_mactree_v(&pat, &mut false, &mut |tt| {
|
||||||
|
if let MacTok::Ph(ph) = &*tt.tok {
|
||||||
|
placeholders.push(ph.name.clone())
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
let pattern = match prio {
|
||||||
|
Some(_) => Matcher::Priod(PriodMatcher::new(&pat, ctx.i()).await.unwrap()),
|
||||||
|
None => Matcher::Named(NamedMatcher::new(&pat, ctx.i()).await.unwrap()),
|
||||||
|
};
|
||||||
|
h.emit(Rule {
|
||||||
|
glossary: pat.iter().flat_map(|t| t.glossary()).cloned().collect(),
|
||||||
|
pattern,
|
||||||
|
placeholders,
|
||||||
|
body_name: ctx.i().i(&format!("({name})::{counter}")).await,
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
.await,
|
||||||
|
}))
|
||||||
|
.to_expr()
|
||||||
|
.await,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
let kw_consts = own_kws[1..].iter().flat_map(|kw| {
|
||||||
|
lazy(true, kw, async |path, ctx| {
|
||||||
|
let name = VPath::new(path.split_last_seg().1.iter().cloned())
|
||||||
|
.name_with_suffix(ctx.i().i(*kw).await)
|
||||||
|
.to_sym(ctx.i())
|
||||||
|
.await;
|
||||||
|
MemKind::Const(sym_ref(name))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let body_consts = (bodies.into_iter().enumerate())
|
||||||
|
.flat_map(|(counter, body)| cnst(false, &format!("({name})::{counter}"), body));
|
||||||
|
chain!(main_const, kw_consts, body_consts).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! mactree {
|
||||||
|
($i:expr; $($body:tt)*) => {
|
||||||
|
$crate::macros::utils::mactreev!($i; ($($body)*)).remove(0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! mactreev {
|
||||||
|
(@RECUR $i:expr; $ret:ident) => {};
|
||||||
|
(@RECUR $i:expr; $ret:ident "..$" $name:ident $prio:literal $($tail:tt)*) => {
|
||||||
|
ret.push(MacTok::Ph(Ph{
|
||||||
|
name: i.i(stringify!($name)).await,
|
||||||
|
kind: PhKind::Vector{ at_least_one: false, priority: $prio }
|
||||||
|
}).at(Pos::Inherit));
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident "...$" $name:ident $prio:literal $($tail:tt)*) => {
|
||||||
|
$ret.push(MacTok::Ph(Ph{
|
||||||
|
name: $i.i(stringify!($name)).await,
|
||||||
|
kind: $crate::macros::mactree::PhKind::Vector{ at_least_one: true, priority: $prio }
|
||||||
|
}).at(orchid_base::location::Pos::Inherit));
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident "$" $name:ident $($tail:tt)*) => {
|
||||||
|
$ret.push(MacTok::Ph(Ph{
|
||||||
|
name: $i.i(stringify!(name)).await,
|
||||||
|
kind: $crate::macros::mactree::PhKind::Scalar
|
||||||
|
}).at(orchid_base::location::Pos::Inherit));
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident "'" $arg:expr ; $($tail:tt)*) => {
|
||||||
|
$ret.push(MacTok::Value($arg).at(orchid_base::location::Pos::Inherit));
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident "" $arg:expr ; $($tail:tt)*) => {
|
||||||
|
$ret.push($arg);
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident "l_" $arg:expr ; ($($body:tt)*) $($tail:tt)*) => {
|
||||||
|
$ret.push(MacTok::Lambda(
|
||||||
|
MacTok::Value($arg).at(orchid_base::location::Pos::Inherit),
|
||||||
|
mactreev!(i; $($body)*)
|
||||||
|
).at(Pos::Inherit));
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident "l" $argh:tt $(:: $arg:tt)* ($($body:tt)*) $($tail:tt)*) => {
|
||||||
|
$ret.push(MacTok::Lambda(
|
||||||
|
MacTok::Name(sym!($argh $(:: $arg)*; $i).await).at(orchid_base::location::Pos::Inherit),
|
||||||
|
mactreev!(i; $($body)*)
|
||||||
|
).at(orchid_base::location::Pos::Inherit));
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident ( $($body:tt)* ) $($tail:tt)*) => {
|
||||||
|
$ret.push(
|
||||||
|
MacTok::S(orchid_base::tree::Paren::Round, mactreev!($i; $($body)*))
|
||||||
|
.at(orchid_base::location::Pos::Inherit)
|
||||||
|
);
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident [ $($body:tt)* ] $($tail:tt)*) => {
|
||||||
|
$ret.push(
|
||||||
|
MacTok::S(orchid_base::tree::Paren::Square, mactreev!($i; $($body)*))
|
||||||
|
.at(orchid_base::location::Pos::Inherit)
|
||||||
|
);
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident { $($body:tt)* } $($tail:tt)*) => {
|
||||||
|
$ret.push(
|
||||||
|
MacTok::S(orchid_base::tree::Paren::Curly, mactreev!($i; $($body)*))
|
||||||
|
.at(orchid_base::location::Pos::Inherit)
|
||||||
|
);
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
(@RECUR $i:expr; $ret:ident $nhead:tt $($tail:tt)*) => {
|
||||||
|
mactreev!(@NAME_MUNCHER $i; $ret ($nhead) $($tail)*)
|
||||||
|
};
|
||||||
|
(@NAME_MUNCHER $i:expr; $ret:ident ($($munched:tt)*) :: $name:tt $($tail:tt)*) => {
|
||||||
|
mactreev!(@NAME_MUNCHER $i; $ret ($($munched)* :: $name) $($tail)*)
|
||||||
|
};
|
||||||
|
(@NAME_MUNCHER $i:expr; $ret:ident ($($munched:tt)*) $($tail:tt)*) => {
|
||||||
|
let sym = orchid_base::sym!($($munched)* ; $i).await;
|
||||||
|
$ret.push(MacTok::Name(sym).at(orchid_base::location::Pos::Inherit));
|
||||||
|
mactreev!(@RECUR $i; $ret $($tail)*);
|
||||||
|
};
|
||||||
|
($i:expr; ) => { Vec::new() };
|
||||||
|
($i:expr; $($tail:tt)*) => {
|
||||||
|
{
|
||||||
|
let mut ret = Vec::<MacTree>::new();
|
||||||
|
mactreev!(@RECUR $i; ret $($tail)*);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub(crate) use {mactree, mactreev};
|
||||||
@@ -2,7 +2,7 @@ use orchid_api_derive::Coding;
|
|||||||
use orchid_base::error::OrcRes;
|
use orchid_base::error::OrcRes;
|
||||||
use orchid_base::format::FmtUnit;
|
use orchid_base::format::FmtUnit;
|
||||||
use orchid_base::number::Numeric;
|
use orchid_base::number::Numeric;
|
||||||
use orchid_extension::atom::{AtomFactory, Atomic, AtomicFeatures, ToAtom, TypAtom};
|
use orchid_extension::atom::{AtomFactory, Atomic, AtomicFeatures, ToAtom, TAtom};
|
||||||
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
||||||
use orchid_extension::conv::TryFromExpr;
|
use orchid_extension::conv::TryFromExpr;
|
||||||
use orchid_extension::expr::Expr;
|
use orchid_extension::expr::Expr;
|
||||||
@@ -21,7 +21,7 @@ impl ThinAtom for Int {
|
|||||||
}
|
}
|
||||||
impl TryFromExpr for Int {
|
impl TryFromExpr for Int {
|
||||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||||
TypAtom::<Int>::try_from_expr(expr).await.map(|t| t.value)
|
TAtom::<Int>::try_from_expr(expr).await.map(|t| t.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ impl TryFromExpr for Num {
|
|||||||
Ok(t) => return Ok(Num(Numeric::Int(t.0))),
|
Ok(t) => return Ok(Num(Numeric::Int(t.0))),
|
||||||
Err(e) => e,
|
Err(e) => e,
|
||||||
};
|
};
|
||||||
match TypAtom::<Float>::try_from_expr(expr).await {
|
match TAtom::<Float>::try_from_expr(expr).await {
|
||||||
Ok(t) => Ok(Num(Numeric::Float(t.0))),
|
Ok(t) => Ok(Num(Numeric::Float(t.0))),
|
||||||
Err(e2) => Err(e + e2),
|
Err(e2) => Err(e + e2),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use orchid_api_traits::{Encode, Request};
|
|||||||
use orchid_base::error::{OrcRes, mk_errv};
|
use orchid_base::error::{OrcRes, mk_errv};
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit};
|
use orchid_base::format::{FmtCtx, FmtUnit};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TypAtom};
|
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TAtom};
|
||||||
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||||
use orchid_extension::conv::TryFromExpr;
|
use orchid_extension::conv::TryFromExpr;
|
||||||
use orchid_extension::expr::Expr;
|
use orchid_extension::expr::Expr;
|
||||||
@@ -89,8 +89,8 @@ pub struct OrcString {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum OrcStringKind {
|
pub enum OrcStringKind {
|
||||||
Val(TypAtom<StrAtom>),
|
Val(TAtom<StrAtom>),
|
||||||
Int(TypAtom<IntStrAtom>),
|
Int(TAtom<IntStrAtom>),
|
||||||
}
|
}
|
||||||
impl OrcString {
|
impl OrcString {
|
||||||
pub async fn get_string(&self) -> Rc<String> {
|
pub async fn get_string(&self) -> Rc<String> {
|
||||||
@@ -103,11 +103,11 @@ impl OrcString {
|
|||||||
|
|
||||||
impl TryFromExpr for OrcString {
|
impl TryFromExpr for OrcString {
|
||||||
async fn try_from_expr(expr: Expr) -> OrcRes<OrcString> {
|
async fn try_from_expr(expr: Expr) -> OrcRes<OrcString> {
|
||||||
if let Ok(v) = TypAtom::<StrAtom>::try_from_expr(expr.clone()).await {
|
if let Ok(v) = TAtom::<StrAtom>::try_from_expr(expr.clone()).await {
|
||||||
return Ok(OrcString { ctx: expr.ctx(), kind: OrcStringKind::Val(v) });
|
return Ok(OrcString { ctx: expr.ctx(), kind: OrcStringKind::Val(v) });
|
||||||
}
|
}
|
||||||
let ctx = expr.ctx();
|
let ctx = expr.ctx();
|
||||||
match TypAtom::<IntStrAtom>::try_from_expr(expr).await {
|
match TAtom::<IntStrAtom>::try_from_expr(expr).await {
|
||||||
Ok(t) => Ok(OrcString { ctx: t.untyped.ctx().clone(), kind: OrcStringKind::Int(t) }),
|
Ok(t) => Ok(OrcString { ctx: t.untyped.ctx().clone(), kind: OrcStringKind::Int(t) }),
|
||||||
Err(e) => Err(mk_errv(ctx.i().i("A string was expected").await, "", e.pos_iter())),
|
Err(e) => Err(mk_errv(ctx.i().i("A string was expected").await, "", e.pos_iter())),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ use std::rc::Rc;
|
|||||||
use async_fn_stream::try_stream;
|
use async_fn_stream::try_stream;
|
||||||
use camino::Utf8PathBuf;
|
use camino::Utf8PathBuf;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use futures::{Stream, TryStreamExt, io};
|
use futures::{FutureExt, Stream, TryStreamExt, io};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::Reporter;
|
use orchid_base::error::Reporter;
|
||||||
use orchid_base::format::{FmtCtxImpl, Format, take_first};
|
use orchid_base::format::{FmtCtxImpl, Format, fmt, take_first};
|
||||||
use orchid_base::location::SrcRange;
|
use orchid_base::location::SrcRange;
|
||||||
use orchid_base::logging::{LogStrategy, Logger};
|
use orchid_base::logging::{LogStrategy, Logger};
|
||||||
use orchid_base::name::{NameLike, VPath};
|
use orchid_base::name::{NameLike, VPath};
|
||||||
@@ -29,6 +29,7 @@ use orchid_host::parse::{HostParseCtxImpl, parse_item, parse_items};
|
|||||||
use orchid_host::parsed::{Item, ItemKind, ParsTokTree, ParsedMember, ParsedModule};
|
use orchid_host::parsed::{Item, ItemKind, ParsTokTree, ParsedMember, ParsedModule};
|
||||||
use orchid_host::subprocess::ext_command;
|
use orchid_host::subprocess::ext_command;
|
||||||
use orchid_host::system::init_systems;
|
use orchid_host::system::init_systems;
|
||||||
|
use orchid_host::tree::{MemberKind, Module, RootData};
|
||||||
use substack::Substack;
|
use substack::Substack;
|
||||||
use tokio::io::{AsyncBufReadExt, BufReader, stdin};
|
use tokio::io::{AsyncBufReadExt, BufReader, stdin};
|
||||||
use tokio::task::{LocalSet, spawn_local};
|
use tokio::task::{LocalSet, spawn_local};
|
||||||
@@ -61,6 +62,12 @@ pub enum Commands {
|
|||||||
file: Utf8PathBuf,
|
file: Utf8PathBuf,
|
||||||
},
|
},
|
||||||
Repl,
|
Repl,
|
||||||
|
ModTree {
|
||||||
|
#[arg(long)]
|
||||||
|
proj: Option<Utf8PathBuf>,
|
||||||
|
#[arg(long)]
|
||||||
|
prefix: Option<String>,
|
||||||
|
},
|
||||||
Exec {
|
Exec {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
proj: Option<Utf8PathBuf>,
|
proj: Option<Utf8PathBuf>,
|
||||||
@@ -226,6 +233,53 @@ async fn main() -> io::Result<ExitCode> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Commands::ModTree { proj, prefix } => {
|
||||||
|
let reporter = Reporter::new();
|
||||||
|
let (mut root, _systems) = init_systems(&args.system, &extensions).await.unwrap();
|
||||||
|
if let Some(proj_path) = proj {
|
||||||
|
let path = proj_path.into_std_path_buf();
|
||||||
|
match parse_folder(&root, path, sym!(src; i).await, &reporter, ctx.clone()).await {
|
||||||
|
Ok(r) => root = r,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{e}");
|
||||||
|
*exit_code1.borrow_mut() = ExitCode::FAILURE;
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let prefix = match prefix {
|
||||||
|
Some(pref) => VPath::parse(&pref, i).await,
|
||||||
|
None => VPath::new([]),
|
||||||
|
};
|
||||||
|
let root_data = root.0.read().await;
|
||||||
|
print_mod(&root_data.root, prefix, &root_data).await;
|
||||||
|
async fn print_mod(module: &Module, path: VPath, root: &RootData) {
|
||||||
|
let indent = " ".repeat(path.len());
|
||||||
|
for (key, tgt) in &module.imports {
|
||||||
|
match tgt {
|
||||||
|
Ok(tgt) => println!("{indent}import {key} => {}", tgt.target),
|
||||||
|
Err(opts) => println!(
|
||||||
|
"{indent}import {key} conflicts between {}",
|
||||||
|
opts.iter().map(|i| &i.target).join(" ")
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (key, mem) in &module.members {
|
||||||
|
let new_path = path.clone().name_with_suffix(key.clone()).to_sym(&root.ctx.i).await;
|
||||||
|
match mem.kind(root.ctx.clone(), &root.consts).await {
|
||||||
|
MemberKind::Module(module) => {
|
||||||
|
println!("{indent}module {key} {{");
|
||||||
|
print_mod(module, VPath::new(new_path.segs()), root).boxed_local().await;
|
||||||
|
println!("{indent}}}")
|
||||||
|
},
|
||||||
|
MemberKind::Const => {
|
||||||
|
let value = root.consts.get(&new_path).expect("Missing const!");
|
||||||
|
println!("{indent}const {key} = {}", fmt(value, &root.ctx.i).await)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
Commands::Exec { proj, code } => {
|
Commands::Exec { proj, code } => {
|
||||||
let reporter = Reporter::new();
|
let reporter = Reporter::new();
|
||||||
let path = sym!(usercode; i).await;
|
let path = sym!(usercode; i).await;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::{OrcRes, Reporter, async_io_err, mk_errv, os_str_to_string};
|
use orchid_base::error::{OrcRes, Reporter, async_io_err, os_str_to_string};
|
||||||
use orchid_base::location::SrcRange;
|
use orchid_base::location::SrcRange;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::parse::Snippet;
|
use orchid_base::parse::Snippet;
|
||||||
@@ -29,16 +29,6 @@ pub async fn parse_folder(
|
|||||||
async fn recur(path: &Path, ns: Sym, rep: &Reporter, ctx: Ctx) -> OrcRes<Option<ParsedModule>> {
|
async fn recur(path: &Path, ns: Sym, rep: &Reporter, ctx: Ctx) -> OrcRes<Option<ParsedModule>> {
|
||||||
let sr = SrcRange::new(0..0, &ns);
|
let sr = SrcRange::new(0..0, &ns);
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
let Some(name_os) = path.file_name() else {
|
|
||||||
return Err(mk_errv(
|
|
||||||
ctx.i.i("Could not read directory name").await,
|
|
||||||
format!("Path {} ends in ..", path.to_string_lossy()),
|
|
||||||
[sr],
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let name = ctx.i.i(os_str_to_string(name_os, &ctx.i, [sr]).await?).await;
|
|
||||||
let ns = ns.suffix([name.clone()], &ctx.i).await;
|
|
||||||
let sr = SrcRange::new(0..0, &ns);
|
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
let mut stream = match fs::read_dir(path).await {
|
let mut stream = match fs::read_dir(path).await {
|
||||||
Err(err) => return Err(async_io_err(err, &ctx.i, [sr]).await),
|
Err(err) => return Err(async_io_err(err, &ctx.i, [sr]).await),
|
||||||
@@ -53,6 +43,10 @@ pub async fn parse_folder(
|
|||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
let os_name = entry.path().file_stem().expect("File name could not be read").to_owned();
|
||||||
|
let name = ctx.i.i(os_str_to_string(&os_name, &ctx.i, [sr.clone()]).await?).await;
|
||||||
|
let ns = ns.suffix([name.clone()], &ctx.i).await;
|
||||||
|
let sr = SrcRange::new(0..0, &ns);
|
||||||
match recur(&entry.path(), ns.clone(), rep, ctx.clone()).boxed_local().await {
|
match recur(&entry.path(), ns.clone(), rep, ctx.clone()).boxed_local().await {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
rep.report(e);
|
rep.report(e);
|
||||||
@@ -64,10 +58,6 @@ pub async fn parse_folder(
|
|||||||
}
|
}
|
||||||
Ok(Some(ParsedModule::new(false, items)))
|
Ok(Some(ParsedModule::new(false, items)))
|
||||||
} else if path.extension() == Some(OsStr::new("orc")) {
|
} else if path.extension() == Some(OsStr::new("orc")) {
|
||||||
let name_os = path.file_stem().expect("If there is an extension, there must be a stem");
|
|
||||||
let name = ctx.i.i(os_str_to_string(name_os, &ctx.i, [sr]).await?).await;
|
|
||||||
let ns = ns.suffix([name], &ctx.i).await;
|
|
||||||
let sr = SrcRange::new(0..0, &ns);
|
|
||||||
let mut file = match File::open(path).await {
|
let mut file = match File::open(path).await {
|
||||||
Err(e) => return Err(async_io_err(e, &ctx.i, [sr]).await),
|
Err(e) => return Err(async_io_err(e, &ctx.i, [sr]).await),
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
|
|||||||
Reference in New Issue
Block a user