Added directfs

Added a very rudimentary file I/O system suitable for experimenting
with the language further. A better one will be designed when we have
sensible error management.
This commit is contained in:
2023-09-17 16:37:39 +01:00
parent 1078835e8b
commit 7396078304
84 changed files with 563 additions and 721 deletions

View File

@@ -37,8 +37,10 @@ where
/// ```ignore
/// fn as_any(self: Box<Self>) -> Box<dyn Any> { self }
/// ```
#[must_use]
fn as_any(self: Box<Self>) -> Box<dyn Any>;
/// See [Atomic::as_any], exactly the same but for references
#[must_use]
fn as_any_ref(&self) -> &dyn Any;
/// Attempt to normalize this value. If it wraps a value, this should report
@@ -47,6 +49,7 @@ where
fn run(self: Box<Self>, ctx: Context) -> AtomicResult;
/// Wrap the atom in a clause to be placed in an [AtomicResult].
#[must_use]
fn atom_cls(self) -> Clause
where
Self: Sized,
@@ -55,6 +58,7 @@ where
}
/// Wrap the atom in a new expression instance to be placed in a tree
#[must_use]
fn atom_exi(self) -> ExprInst
where
Self: Sized,
@@ -73,10 +77,12 @@ where
pub struct Atom(pub Box<dyn Atomic>);
impl Atom {
/// Wrap an [Atomic] in a type-erased box
#[must_use]
pub fn new<T: 'static + Atomic>(data: T) -> Self {
Self(Box::new(data) as Box<dyn Atomic>)
}
/// Get the contained data
#[must_use]
pub fn data(&self) -> &dyn Atomic { self.0.as_ref() as &dyn Atomic }
/// Attempt to downcast contained data to a specific type
pub fn try_cast<T: Atomic>(self) -> Result<T, Self> {
@@ -86,8 +92,10 @@ impl Atom {
}
}
/// Test the type of the contained data without downcasting
#[must_use]
pub fn is<T: 'static>(&self) -> bool { self.data().as_any_ref().is::<T>() }
/// Downcast contained data, panic if it isn't the specified type
#[must_use]
pub fn cast<T: 'static>(self) -> T {
*self.0.as_any().downcast().expect("Type mismatch on Atom::cast")
}

View File

@@ -25,6 +25,7 @@ struct CPSFn<T: CPSPayload> {
pub payload: T,
}
impl<T: CPSPayload> CPSFn<T> {
#[must_use]
fn new(argc: usize, payload: T) -> Self {
debug_assert!(
argc > 0,
@@ -55,37 +56,25 @@ pub struct CPSBox<T: CPSPayload> {
pub continuations: Vec<ExprInst>,
}
impl<T: CPSPayload> CPSBox<T> {
/// Assert that the command was instantiated with the correct number of
/// possible continuations. This is decided by the native bindings, not user
/// code, therefore this error may be uncovered by usercode but can never be
/// produced at will.
pub fn assert_count(&self, expect: usize) {
let real = self.continuations.len();
debug_assert!(
real == expect,
"Tried to read {expect} argument(s) but {real} were provided for {:?}",
self.payload
)
}
/// Unpack the wrapped command and the continuation
#[must_use]
pub fn unpack1(self) -> (T, ExprInst) {
self.assert_count(1);
let [cont]: [ExprInst; 1] =
self.continuations.try_into().expect("size checked");
(self.payload, cont)
}
/// Unpack the wrapped command and 2 continuations (usually an async and a
/// sync)
#[must_use]
pub fn unpack2(self) -> (T, ExprInst, ExprInst) {
self.assert_count(2);
let [c1, c2]: [ExprInst; 2] =
self.continuations.try_into().expect("size checked");
(self.payload, c1, c2)
}
/// Unpack the wrapped command and 3 continuations (usually an async success,
/// an async fail and a sync)
#[must_use]
pub fn unpack3(self) -> (T, ExprInst, ExprInst, ExprInst) {
self.assert_count(3);
let [c1, c2, c3]: [ExprInst; 3] =
self.continuations.try_into().expect("size checked");
(self.payload, c1, c2, c3)
@@ -97,6 +86,7 @@ impl<T: CPSPayload> InertAtomic for CPSBox<T> {
}
/// Like [init_cps] but wrapped in a [ConstTree] for init-time usage
#[must_use]
pub fn const_cps<T: CPSPayload>(argc: usize, payload: T) -> ConstTree {
ConstTree::xfn(CPSFn::new(argc, payload))
}
@@ -106,6 +96,7 @@ pub fn const_cps<T: CPSPayload>(argc: usize, payload: T) -> ConstTree {
///
/// This function is meant to be used in an external function defined with
/// [crate::define_fn]. For usage in a [ConstTree], see [mk_const]
#[must_use]
pub fn init_cps<T: CPSPayload>(argc: usize, payload: T) -> Clause {
CPSFn::new(argc, payload).xfn_cls()
}

View File

@@ -16,6 +16,7 @@ pub type XfnResult = Result<Clause, Rc<dyn ExternError>>;
/// Errors produced by external code
pub trait ExternError: Display {
/// Convert into trait object
#[must_use]
fn into_extern(self) -> Rc<dyn ExternError>
where
Self: 'static + Sized,
@@ -37,6 +38,7 @@ impl Error for dyn ExternError {}
/// these are also external functions.
pub trait ExternFn: DynClone {
/// Display name of the function
#[must_use]
fn name(&self) -> &str;
/// Combine the function with an argument to produce a new clause
fn apply(self: Box<Self>, arg: ExprInst, ctx: Context) -> XfnResult;
@@ -45,6 +47,7 @@ pub trait ExternFn: DynClone {
self.name().hash(&mut state)
}
/// Wrap this function in a clause to be placed in an [AtomicResult].
#[must_use]
fn xfn_cls(self) -> Clause
where
Self: Sized + 'static,

View File

@@ -19,6 +19,7 @@ use crate::Primitive;
/// provided in argument lists.
pub trait InertAtomic: Debug + Clone + 'static {
/// Typename to be shown in the error when a conversion from [ExprInst] fails
#[must_use]
fn type_str() -> &'static str;
/// Proxies to [Responder] so that you don't have to implmeent it manually if
/// you need it, but behaves exactly as the default implementation.