forked from Orchid/orchid
Cut down on macro nonsense
- InertAtomic replaced atomic_inert! for improved tooling support - atomic_defaults! is easier to type out than to explain in a docstring - Changed rustfmt config to better support tiny functions such as as_any
This commit is contained in:
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
@@ -26,4 +26,4 @@ jobs:
|
|||||||
- name: Clippy
|
- name: Clippy
|
||||||
run: cargo clippy
|
run: cargo clippy
|
||||||
- name: Formatting
|
- name: Formatting
|
||||||
run: cargo fmt --check
|
run: cargo fmt +nightly --check
|
||||||
|
|||||||
@@ -29,6 +29,9 @@
|
|||||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||||
"rust-analyzer.checkOnSave": true,
|
"rust-analyzer.checkOnSave": true,
|
||||||
"rust-analyzer.check.command": "clippy",
|
"rust-analyzer.check.command": "clippy",
|
||||||
|
"rust-analyzer.rustfmt.extraArgs": [
|
||||||
|
"+nightly"
|
||||||
|
],
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"*.mjsd": "markdown"
|
"*.mjsd": "markdown"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly"
|
channel = "stable"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ normalize_comments = true
|
|||||||
wrap_comments = true
|
wrap_comments = true
|
||||||
overflow_delimited_expr = true
|
overflow_delimited_expr = true
|
||||||
use_small_heuristics = "Max"
|
use_small_heuristics = "Max"
|
||||||
|
fn_single_line = true
|
||||||
|
|
||||||
# literals
|
# literals
|
||||||
hex_literal_case = "Lower"
|
hex_literal_case = "Lower"
|
||||||
@@ -30,4 +31,4 @@ use_try_shorthand = true
|
|||||||
# Modules
|
# Modules
|
||||||
group_imports = "StdExternalCrate"
|
group_imports = "StdExternalCrate"
|
||||||
imports_granularity = "Module"
|
imports_granularity = "Module"
|
||||||
reorder_modules = true
|
reorder_modules = true
|
||||||
|
|||||||
@@ -61,9 +61,7 @@ impl Args {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chk_proj(&self) -> Result<(), String> {
|
pub fn chk_proj(&self) -> Result<(), String> { self.chk_dir_main() }
|
||||||
self.chk_dir_main()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_vname(data: &str, i: &Interner) -> VName {
|
pub fn to_vname(data: &str, i: &Interner) -> VName {
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ pub struct ImportAll {
|
|||||||
pub offender_mod: Rc<VName>,
|
pub offender_mod: Rc<VName>,
|
||||||
}
|
}
|
||||||
impl ProjectError for ImportAll {
|
impl ProjectError for ImportAll {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "a top-level glob import was used" }
|
||||||
"a top-level glob import was used"
|
|
||||||
}
|
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!("{} imports *", self.offender_mod.iter().join("::"))
|
format!("{} imports *", self.offender_mod.iter().join("::"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,5 @@ impl ProjectError for NoTargets {
|
|||||||
"No targets were specified for layer parsing"
|
"No targets were specified for layer parsing"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self) -> BoxedIter<ErrorPosition> {
|
fn positions(&self) -> BoxedIter<ErrorPosition> { box_empty() }
|
||||||
box_empty()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ pub struct ParseErrorWithTokens {
|
|||||||
pub error: Rc<dyn ProjectError>,
|
pub error: Rc<dyn ProjectError>,
|
||||||
}
|
}
|
||||||
impl ProjectError for ParseErrorWithTokens {
|
impl ProjectError for ParseErrorWithTokens {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { self.error.description() }
|
||||||
self.error.description()
|
|
||||||
}
|
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"Failed to parse code: {}\nTokenized source for context:\n{}",
|
"Failed to parse code: {}\nTokenized source for context:\n{}",
|
||||||
@@ -26,7 +24,5 @@ impl ProjectError for ParseErrorWithTokens {
|
|||||||
self.tokens.iter().map(|t| t.to_string()).join(" "),
|
self.tokens.iter().map(|t| t.to_string()).join(" "),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn positions(&self) -> BoxedIter<ErrorPosition> {
|
fn positions(&self) -> BoxedIter<ErrorPosition> { self.error.positions() }
|
||||||
self.error.positions()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ pub trait ProjectError {
|
|||||||
/// A general description of this type of error
|
/// A general description of this type of error
|
||||||
fn description(&self) -> &str;
|
fn description(&self) -> &str;
|
||||||
/// A formatted message that includes specific parameters
|
/// A formatted message that includes specific parameters
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String { self.description().to_string() }
|
||||||
self.description().to_string()
|
|
||||||
}
|
|
||||||
/// Code positions relevant to this error. If you don't implement this, you
|
/// Code positions relevant to this error. If you don't implement this, you
|
||||||
/// must implement [ProjectError::one_position]
|
/// must implement [ProjectError::one_position]
|
||||||
fn positions(&self) -> BoxedIter<ErrorPosition> {
|
fn positions(&self) -> BoxedIter<ErrorPosition> {
|
||||||
@@ -30,9 +28,7 @@ pub trait ProjectError {
|
|||||||
}
|
}
|
||||||
/// Short way to provide a single location. If you don't implement this, you
|
/// Short way to provide a single location. If you don't implement this, you
|
||||||
/// must implement [ProjectError::positions]
|
/// must implement [ProjectError::positions]
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { unimplemented!() }
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
/// Convert the error into an `Rc<dyn ProjectError>` to be able to
|
/// Convert the error into an `Rc<dyn ProjectError>` to be able to
|
||||||
/// handle various errors together
|
/// handle various errors together
|
||||||
fn rc(self) -> Rc<dyn ProjectError>
|
fn rc(self) -> Rc<dyn ProjectError>
|
||||||
|
|||||||
@@ -23,7 +23,5 @@ impl ProjectError for TooManySupers {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ pub struct Environment<'a> {
|
|||||||
}
|
}
|
||||||
impl<'a> Environment<'a> {
|
impl<'a> Environment<'a> {
|
||||||
/// Initialize a new environment
|
/// Initialize a new environment
|
||||||
pub fn new(i: &'a Interner) -> Self {
|
pub fn new(i: &'a Interner) -> Self { Self { i, systems: Vec::new() } }
|
||||||
Self { i, systems: Vec::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register a new system in the environment
|
/// Register a new system in the environment
|
||||||
pub fn add_system<'b: 'a>(mut self, is: impl IntoSystem<'b> + 'b) -> Self {
|
pub fn add_system<'b: 'a>(mut self, is: impl IntoSystem<'b> + 'b) -> Self {
|
||||||
|
|||||||
@@ -116,9 +116,7 @@ pub struct MacroTimeout {
|
|||||||
limit: usize,
|
limit: usize,
|
||||||
}
|
}
|
||||||
impl ProjectError for MacroTimeout {
|
impl ProjectError for MacroTimeout {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "Macro execution has not halted" }
|
||||||
"Macro execution has not halted"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
@@ -128,7 +126,5 @@ impl ProjectError for MacroTimeout {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,5 @@ impl ProjectError for MissingSymbol {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,9 +59,7 @@ impl ProjectError for MissingSystemCode {
|
|||||||
self.system.join("::")
|
self.system.join("::")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn positions(&self) -> BoxedIter<ErrorPosition> {
|
fn positions(&self) -> BoxedIter<ErrorPosition> { box_empty() }
|
||||||
box_empty()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for objects that can be converted into a [System] in the presence
|
/// Trait for objects that can be converted into a [System] in the presence
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use dyn_clone::DynClone;
|
|||||||
use crate::interpreted::ExprInst;
|
use crate::interpreted::ExprInst;
|
||||||
use crate::interpreter::{Context, RuntimeError};
|
use crate::interpreter::{Context, RuntimeError};
|
||||||
use crate::representations::interpreted::Clause;
|
use crate::representations::interpreted::Clause;
|
||||||
|
use crate::utils::ddispatch::Responder;
|
||||||
use crate::Primitive;
|
use crate::Primitive;
|
||||||
|
|
||||||
/// Information returned by [Atomic::run]. This mirrors
|
/// Information returned by [Atomic::run]. This mirrors
|
||||||
@@ -30,19 +31,18 @@ impl AtomicReturn {
|
|||||||
pub type AtomicResult = Result<AtomicReturn, RuntimeError>;
|
pub type AtomicResult = Result<AtomicReturn, RuntimeError>;
|
||||||
|
|
||||||
/// Functionality the interpreter needs to handle a value
|
/// Functionality the interpreter needs to handle a value
|
||||||
pub trait Atomic: Any + Debug + DynClone
|
pub trait Atomic: Any + Debug + DynClone + Responder
|
||||||
where
|
where
|
||||||
Self: 'static,
|
Self: 'static,
|
||||||
{
|
{
|
||||||
/// A fully type-erased interface to issue a command to the unknown type
|
|
||||||
/// and see if it supports it
|
|
||||||
fn request(&self, _request: Box<dyn Any>) -> Option<Box<dyn Any>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Casts this value to [Any] so that its original value can be salvaged
|
/// Casts this value to [Any] so that its original value can be salvaged
|
||||||
/// during introspection by other external code. There is no other way to
|
/// during introspection by other external code.
|
||||||
/// interact with values of unknown types at the moment.
|
///
|
||||||
|
/// This function should be implemented in exactly one way:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// fn as_any(&self) -> &dyn Any { self }
|
||||||
|
/// ```
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
/// Attempt to normalize this value. If it wraps a value, this should report
|
/// Attempt to normalize this value. If it wraps a value, this should report
|
||||||
@@ -81,31 +81,23 @@ impl Atom {
|
|||||||
Self(Box::new(data) as Box<dyn Atomic>)
|
Self(Box::new(data) as Box<dyn Atomic>)
|
||||||
}
|
}
|
||||||
/// Get the contained data
|
/// Get the contained data
|
||||||
pub fn data(&self) -> &dyn Atomic {
|
pub fn data(&self) -> &dyn Atomic { self.0.as_ref() as &dyn Atomic }
|
||||||
self.0.as_ref() as &dyn Atomic
|
|
||||||
}
|
|
||||||
/// Attempt to downcast contained data to a specific type
|
/// Attempt to downcast contained data to a specific type
|
||||||
pub fn try_cast<T: Atomic>(&self) -> Option<&T> {
|
pub fn try_cast<T: Atomic>(&self) -> Option<&T> {
|
||||||
self.data().as_any().downcast_ref()
|
self.data().as_any().downcast_ref()
|
||||||
}
|
}
|
||||||
/// Test the type of the contained data without downcasting
|
/// Test the type of the contained data without downcasting
|
||||||
pub fn is<T: 'static>(&self) -> bool {
|
pub fn is<T: 'static>(&self) -> bool { self.data().as_any().is::<T>() }
|
||||||
self.data().as_any().is::<T>()
|
|
||||||
}
|
|
||||||
/// Downcast contained data, panic if it isn't the specified type
|
/// Downcast contained data, panic if it isn't the specified type
|
||||||
pub fn cast<T: 'static>(&self) -> &T {
|
pub fn cast<T: 'static>(&self) -> &T {
|
||||||
self.data().as_any().downcast_ref().expect("Type mismatch on Atom::cast")
|
self.data().as_any().downcast_ref().expect("Type mismatch on Atom::cast")
|
||||||
}
|
}
|
||||||
/// Normalize the contained data
|
/// Normalize the contained data
|
||||||
pub fn run(&self, ctx: Context) -> AtomicResult {
|
pub fn run(&self, ctx: Context) -> AtomicResult { self.0.run(ctx) }
|
||||||
self.0.run(ctx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Atom {
|
impl Clone for Atom {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { Self(dyn_clone::clone_box(self.data())) }
|
||||||
Self(dyn_clone::clone_box(self.data()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Atom {
|
impl Debug for Atom {
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ use std::fmt::Debug;
|
|||||||
|
|
||||||
use trait_set::trait_set;
|
use trait_set::trait_set;
|
||||||
|
|
||||||
use super::{Atomic, ExternFn, XfnResult};
|
use super::{Atomic, ExternFn, InertAtomic, XfnResult};
|
||||||
use crate::interpreted::{Clause, ExprInst};
|
use crate::interpreted::{Clause, ExprInst};
|
||||||
use crate::interpreter::{Context, HandlerRes};
|
use crate::interpreter::{Context, HandlerRes};
|
||||||
use crate::utils::pure_push::pushed_ref;
|
use crate::utils::pure_push::pushed_ref;
|
||||||
use crate::{ConstTree, atomic_inert};
|
use crate::ConstTree;
|
||||||
|
|
||||||
trait_set! {
|
trait_set! {
|
||||||
/// A "well behaved" type that can be used as payload in a CPS box
|
/// A "well behaved" type that can be used as payload in a CPS box
|
||||||
@@ -34,9 +34,7 @@ impl<T: CPSPayload> CPSFn<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T: CPSPayload> ExternFn for CPSFn<T> {
|
impl<T: CPSPayload> ExternFn for CPSFn<T> {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str { "CPS function without argument" }
|
||||||
"CPS function without argument"
|
|
||||||
}
|
|
||||||
fn apply(&self, arg: ExprInst, _ctx: Context) -> XfnResult {
|
fn apply(&self, arg: ExprInst, _ctx: Context) -> XfnResult {
|
||||||
let payload = self.payload.clone();
|
let payload = self.payload.clone();
|
||||||
let continuations = pushed_ref(&self.continuations, arg);
|
let continuations = pushed_ref(&self.continuations, arg);
|
||||||
@@ -93,7 +91,9 @@ impl<T: CPSPayload> CPSBox<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_inert!(CPSBox(T:(CPSPayload)), typestr = "a CPS box");
|
impl<T: CPSPayload> InertAtomic for CPSBox<T> {
|
||||||
|
fn type_str() -> &'static str { "a CPS box" }
|
||||||
|
}
|
||||||
|
|
||||||
/// Like [init_cps] but wrapped in a [ConstTree] for init-time usage
|
/// Like [init_cps] but wrapped in a [ConstTree] for init-time usage
|
||||||
pub fn const_cps<T: CPSPayload>(argc: usize, payload: T) -> ConstTree {
|
pub fn const_cps<T: CPSPayload>(argc: usize, payload: T) -> ConstTree {
|
||||||
|
|||||||
@@ -55,9 +55,7 @@ pub trait ExternFn: DynClone {
|
|||||||
|
|
||||||
impl Eq for dyn ExternFn {}
|
impl Eq for dyn ExternFn {}
|
||||||
impl PartialEq for dyn ExternFn {
|
impl PartialEq for dyn ExternFn {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool { self.name() == other.name() }
|
||||||
self.name() == other.name()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl Hash for dyn ExternFn {
|
impl Hash for dyn ExternFn {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
|||||||
46
src/foreign/inert.rs
Normal file
46
src/foreign/inert.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
use std::any::Any;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::{AtomicResult, AtomicReturn, ExternError};
|
||||||
|
#[allow(unused)] // for doc
|
||||||
|
use crate::define_fn;
|
||||||
|
use crate::foreign::Atomic;
|
||||||
|
use crate::interpreted::{ExprInst, TryFromExprInst};
|
||||||
|
use crate::interpreter::Context;
|
||||||
|
use crate::systems::cast_exprinst::with_atomic;
|
||||||
|
use crate::utils::ddispatch::{Request, Responder};
|
||||||
|
|
||||||
|
/// A proxy trait that implements [Atomic] for blobs of data in Rust code that
|
||||||
|
/// cannot be processed and always report inert. Since these are expected to be
|
||||||
|
/// parameters of functions defined with [define_fn] it also automatically
|
||||||
|
/// implements [TryFromExprInst] so that a conversion doesn't have to be
|
||||||
|
/// provided in argument lists.
|
||||||
|
pub trait InertAtomic: Debug + Clone + 'static {
|
||||||
|
/// Typename to be shown in the error when a conversion from [ExprInst] fails
|
||||||
|
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.
|
||||||
|
#[allow(unused_mut, unused_variables)] // definition should show likely usage
|
||||||
|
fn respond(&self, mut request: Request) {}
|
||||||
|
}
|
||||||
|
impl<T: InertAtomic> Responder for T {
|
||||||
|
fn respond(&self, request: Request) { self.respond(request) }
|
||||||
|
}
|
||||||
|
impl<T: InertAtomic> Atomic for T {
|
||||||
|
fn as_any(&self) -> &dyn Any { self }
|
||||||
|
|
||||||
|
fn run(&self, ctx: Context) -> AtomicResult {
|
||||||
|
Ok(AtomicReturn {
|
||||||
|
clause: self.clone().atom_cls(),
|
||||||
|
gas: ctx.gas,
|
||||||
|
inert: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: InertAtomic> TryFromExprInst for T {
|
||||||
|
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||||
|
with_atomic(exi, Self::type_str(), |a: &T| Ok(a.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,11 +5,13 @@
|
|||||||
mod atom;
|
mod atom;
|
||||||
pub mod cps_box;
|
pub mod cps_box;
|
||||||
mod extern_fn;
|
mod extern_fn;
|
||||||
|
mod inert;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub use atom::{Atom, Atomic, AtomicResult, AtomicReturn};
|
pub use atom::{Atom, Atomic, AtomicResult, AtomicReturn};
|
||||||
pub use extern_fn::{ExternError, ExternFn, XfnResult};
|
pub use extern_fn::{ExternError, ExternFn, XfnResult};
|
||||||
|
pub use inert::InertAtomic;
|
||||||
|
|
||||||
pub use crate::representations::interpreted::Clause;
|
pub use crate::representations::interpreted::Clause;
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
#[allow(unused)] // for the doc comments
|
|
||||||
use crate::foreign::Atomic;
|
|
||||||
|
|
||||||
/// A macro that generates the straightforward, syntactically invariant part of
|
|
||||||
/// implementing [Atomic].
|
|
||||||
///
|
|
||||||
/// Currently implements
|
|
||||||
/// - [Atomic::as_any]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! atomic_defaults {
|
|
||||||
() => {
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -79,7 +79,7 @@ macro_rules! atomic_impl {
|
|||||||
};
|
};
|
||||||
($typ:ident, $next_phase:expr) => {
|
($typ:ident, $next_phase:expr) => {
|
||||||
impl $crate::foreign::Atomic for $typ {
|
impl $crate::foreign::Atomic for $typ {
|
||||||
$crate::atomic_defaults! {}
|
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
#[allow(unused)] // for the doc comments
|
|
||||||
use std::any::Any;
|
|
||||||
#[allow(unused)] // for the doc comments
|
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
#[allow(unused)] // for the doc comments
|
|
||||||
use dyn_clone::DynClone;
|
|
||||||
|
|
||||||
#[allow(unused)] // for the doc comments
|
|
||||||
use crate::foreign::Atomic;
|
|
||||||
|
|
||||||
/// Implement [Atomic] for a structure that cannot be transformed any further.
|
|
||||||
/// This would be optimal for atomics encapsulating raw data. [Atomic] depends
|
|
||||||
/// on [Any], [Debug] and [DynClone].
|
|
||||||
///
|
|
||||||
/// If the type in question is parametric, the angle brackets must be replaced
|
|
||||||
/// by parentheses, and the contraints must be parenthesized, for conenient
|
|
||||||
/// parsing. See the below example:
|
|
||||||
///
|
|
||||||
/// ```ignore
|
|
||||||
/// use orchidlang::atomic_inert;
|
|
||||||
///
|
|
||||||
/// struct MyContainer<T, U: Clone, V: Eq + Hash>()
|
|
||||||
///
|
|
||||||
/// atomic_inert!( MyContainer(T, U:(Clone), V:(Eq + Hash)), "my container" );
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! atomic_inert {
|
|
||||||
( $typ:ident $( (
|
|
||||||
$( $typevar:ident $( : (
|
|
||||||
$( $constraints:tt )*
|
|
||||||
) )? ),+ ) )?
|
|
||||||
, typestr = $typename:expr $( , request = $reqhandler:expr )?) => {
|
|
||||||
impl $(< $($typevar : $( $($constraints)* + )? 'static ),+ >)? $crate::foreign::Atomic
|
|
||||||
for $typ $(< $($typevar),+ >)? {
|
|
||||||
$crate::atomic_defaults! {}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
ctx: $crate::interpreter::Context,
|
|
||||||
) -> $crate::foreign::AtomicResult {
|
|
||||||
Ok($crate::foreign::AtomicReturn {
|
|
||||||
clause: self.clone().atom_cls(),
|
|
||||||
gas: ctx.gas,
|
|
||||||
inert: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
$(
|
|
||||||
fn request(
|
|
||||||
&self,
|
|
||||||
request: Box<dyn std::any::Any>
|
|
||||||
) -> Option<Box<dyn std::any::Any>> {
|
|
||||||
let lambda = $reqhandler;
|
|
||||||
lambda(request, self)
|
|
||||||
}
|
|
||||||
)?
|
|
||||||
}
|
|
||||||
|
|
||||||
impl $(< $($typevar : $( $($constraints)* + )? 'static ),+ >)?
|
|
||||||
TryFrom<&$crate::interpreted::ExprInst>
|
|
||||||
for $typ $(< $($typevar),+ >)? {
|
|
||||||
type Error = std::rc::Rc<dyn $crate::foreign::ExternError>;
|
|
||||||
|
|
||||||
fn try_from(
|
|
||||||
value: &$crate::interpreted::ExprInst,
|
|
||||||
) -> Result<Self, Self::Error> {
|
|
||||||
$crate::systems::cast_exprinst::with_atom(
|
|
||||||
value,
|
|
||||||
$typename,
|
|
||||||
|a: &$typ $(< $($typevar),+ >)?| Ok(a.clone()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -7,9 +7,7 @@ use crate::atomic_impl;
|
|||||||
macro_rules! atomic_redirect {
|
macro_rules! atomic_redirect {
|
||||||
($typ:ident) => {
|
($typ:ident) => {
|
||||||
impl AsRef<$crate::foreign::RcExpr> for $typ {
|
impl AsRef<$crate::foreign::RcExpr> for $typ {
|
||||||
fn as_ref(&self) -> &Clause {
|
fn as_ref(&self) -> &Clause { &self.0 }
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl From<(&Self, $crate::foreign::RcExpr)> for $typ {
|
impl From<(&Self, $crate::foreign::RcExpr)> for $typ {
|
||||||
fn from((old, clause): (&Self, Clause)) -> Self {
|
fn from((old, clause): (&Self, Clause)) -> Self {
|
||||||
@@ -19,9 +17,7 @@ macro_rules! atomic_redirect {
|
|||||||
};
|
};
|
||||||
($typ:ident, $field:ident) => {
|
($typ:ident, $field:ident) => {
|
||||||
impl AsRef<$crate::interpreted::ExprInst> for $typ {
|
impl AsRef<$crate::interpreted::ExprInst> for $typ {
|
||||||
fn as_ref(&self) -> &$crate::interpreted::ExprInst {
|
fn as_ref(&self) -> &$crate::interpreted::ExprInst { &self.$field }
|
||||||
&self.$field
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl From<(&Self, $crate::interpreted::ExprInst)> for $typ {
|
impl From<(&Self, $crate::interpreted::ExprInst)> for $typ {
|
||||||
#[allow(clippy::needless_update)]
|
#[allow(clippy::needless_update)]
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ use crate::{atomic_impl, atomic_redirect};
|
|||||||
macro_rules! externfn_impl {
|
macro_rules! externfn_impl {
|
||||||
($typ:ident, $next_atomic:expr) => {
|
($typ:ident, $next_atomic:expr) => {
|
||||||
impl $crate::foreign::ExternFn for $typ {
|
impl $crate::foreign::ExternFn for $typ {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str { stringify!($typ) }
|
||||||
stringify!($typ)
|
|
||||||
}
|
|
||||||
fn apply(
|
fn apply(
|
||||||
&self,
|
&self,
|
||||||
arg: $crate::interpreted::ExprInst,
|
arg: $crate::interpreted::ExprInst,
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
mod atomic_defaults;
|
|
||||||
mod atomic_impl;
|
mod atomic_impl;
|
||||||
mod atomic_inert;
|
|
||||||
mod atomic_redirect;
|
mod atomic_redirect;
|
||||||
mod define_fn;
|
mod define_fn;
|
||||||
mod externfn_impl;
|
mod externfn_impl;
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ macro_rules! write_fn_step {
|
|||||||
$( $arg: $typ, )*
|
$( $arg: $typ, )*
|
||||||
expr_inst: $crate::interpreted::ExprInst,
|
expr_inst: $crate::interpreted::ExprInst,
|
||||||
}
|
}
|
||||||
|
impl $crate::utils::ddispatch::Responder for $name {}
|
||||||
$crate::atomic_redirect!($name, expr_inst);
|
$crate::atomic_redirect!($name, expr_inst);
|
||||||
$crate::atomic_impl!($name);
|
$crate::atomic_impl!($name);
|
||||||
$crate::externfn_impl!(
|
$crate::externfn_impl!(
|
||||||
@@ -136,6 +137,7 @@ macro_rules! write_fn_step {
|
|||||||
expr_inst: $crate::interpreted::ExprInst,
|
expr_inst: $crate::interpreted::ExprInst,
|
||||||
}
|
}
|
||||||
$crate::atomic_redirect!($name, expr_inst);
|
$crate::atomic_redirect!($name, expr_inst);
|
||||||
|
impl $crate::utils::ddispatch::Responder for $name {}
|
||||||
$crate::atomic_impl!(
|
$crate::atomic_impl!(
|
||||||
$name,
|
$name,
|
||||||
|Self{ $($arg, )* expr_inst }: &Self, _| {
|
|Self{ $($arg, )* expr_inst }: &Self, _| {
|
||||||
@@ -157,6 +159,6 @@ macro_rules! write_fn_step {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
(@CONV $locxname:expr) => {
|
(@CONV $locxname:expr) => {
|
||||||
($locxname).try_into()?
|
($locxname).downcast()?
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ pub struct Interner {
|
|||||||
}
|
}
|
||||||
impl Interner {
|
impl Interner {
|
||||||
/// Create a new interner
|
/// Create a new interner
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Self { interners: RefCell::new(HashMap::new()) } }
|
||||||
Self { interners: RefCell::new(HashMap::new()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Intern something
|
/// Intern something
|
||||||
pub fn i<Q: ?Sized + Eq + Hash + ToOwned>(&self, q: &Q) -> Tok<Q::Owned>
|
pub fn i<Q: ?Sized + Eq + Hash + ToOwned>(&self, q: &Q) -> Tok<Q::Owned>
|
||||||
@@ -62,9 +60,7 @@ impl Interner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Interner {
|
impl Default for Interner {
|
||||||
fn default() -> Self {
|
fn default() -> Self { Self::new() }
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get or create an interner for a given type.
|
/// Get or create an interner for a given type.
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ impl<T: Eq + Hash + Clone + 'static> Tok<T> {
|
|||||||
.expect("Pointer can always be cast to nonzero")
|
.expect("Pointer can always be cast to nonzero")
|
||||||
}
|
}
|
||||||
/// Cast into usize
|
/// Cast into usize
|
||||||
pub fn usize(&self) -> usize {
|
pub fn usize(&self) -> usize { self.id().into() }
|
||||||
self.id().into()
|
|
||||||
}
|
|
||||||
///
|
///
|
||||||
pub fn assert_comparable(&self, other: &Self) {
|
pub fn assert_comparable(&self, other: &Self) {
|
||||||
let iref = self.interner.as_ptr() as usize;
|
let iref = self.interner.as_ptr() as usize;
|
||||||
@@ -50,9 +48,7 @@ impl<T: Eq + Hash + Clone + 'static> Tok<Vec<Tok<T>>> {
|
|||||||
impl<T: Eq + Hash + Clone + 'static> Deref for Tok<T> {
|
impl<T: Eq + Hash + Clone + 'static> Deref for Tok<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target { self.data.as_ref() }
|
||||||
self.data.as_ref()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq + Hash + Clone + 'static + Debug> Debug for Tok<T> {
|
impl<T: Eq + Hash + Clone + 'static + Debug> Debug for Tok<T> {
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ pub enum RuntimeError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl From<Rc<dyn ExternError>> for RuntimeError {
|
impl From<Rc<dyn ExternError>> for RuntimeError {
|
||||||
fn from(value: Rc<dyn ExternError>) -> Self {
|
fn from(value: Rc<dyn ExternError>) -> Self { Self::Extern(value) }
|
||||||
Self::Extern(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for RuntimeError {
|
impl Display for RuntimeError {
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ pub struct HandlerTable<'a> {
|
|||||||
}
|
}
|
||||||
impl<'a> HandlerTable<'a> {
|
impl<'a> HandlerTable<'a> {
|
||||||
/// Create a new [HandlerTable]
|
/// Create a new [HandlerTable]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Self { handlers: HashMap::new() } }
|
||||||
Self { handlers: HashMap::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a handler function to interpret a type of atom and decide what happens
|
/// Add a handler function to interpret a type of atom and decide what happens
|
||||||
/// next. This function can be impure.
|
/// next. This function can be impure.
|
||||||
|
|||||||
@@ -40,13 +40,7 @@ impl<'a> Clone for ParsingContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Context for ParsingContext<'_> {
|
impl Context for ParsingContext<'_> {
|
||||||
fn interner(&self) -> &Interner {
|
fn interner(&self) -> &Interner { self.interner }
|
||||||
self.interner
|
fn file(&self) -> Rc<VName> { self.file.clone() }
|
||||||
}
|
fn ops(&self) -> &[Tok<String>] { self.ops }
|
||||||
fn file(&self) -> Rc<VName> {
|
|
||||||
self.file.clone()
|
|
||||||
}
|
|
||||||
fn ops(&self) -> &[Tok<String>] {
|
|
||||||
self.ops
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,11 @@ pub struct LineNeedsPrefix {
|
|||||||
pub entry: Entry,
|
pub entry: Entry,
|
||||||
}
|
}
|
||||||
impl ProjectError for LineNeedsPrefix {
|
impl ProjectError for LineNeedsPrefix {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "This linetype requires a prefix" }
|
||||||
"This linetype requires a prefix"
|
|
||||||
}
|
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!("{} cannot appear at the beginning of a line", self.entry)
|
format!("{} cannot appear at the beginning of a line", self.entry)
|
||||||
}
|
}
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.entry.location() }
|
||||||
self.entry.location()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -30,9 +26,7 @@ pub struct UnexpectedEOL {
|
|||||||
pub entry: Entry,
|
pub entry: Entry,
|
||||||
}
|
}
|
||||||
impl ProjectError for UnexpectedEOL {
|
impl ProjectError for UnexpectedEOL {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "The line ended abruptly" }
|
||||||
"The line ended abruptly"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
"The line ends unexpectedly here. In Orchid, all line breaks outside \
|
"The line ends unexpectedly here. In Orchid, all line breaks outside \
|
||||||
@@ -40,21 +34,15 @@ impl ProjectError for UnexpectedEOL {
|
|||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.entry.location() }
|
||||||
self.entry.location()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExpectedEOL {
|
pub struct ExpectedEOL {
|
||||||
pub location: Location,
|
pub location: Location,
|
||||||
}
|
}
|
||||||
impl ProjectError for ExpectedEOL {
|
impl ProjectError for ExpectedEOL {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "Expected the end of the line" }
|
||||||
"Expected the end of the line"
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
}
|
|
||||||
fn one_position(&self) -> Location {
|
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -85,9 +73,7 @@ impl ProjectError for ExpectedName {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.entry.location() }
|
||||||
self.entry.location()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive()]
|
#[derive()]
|
||||||
@@ -115,16 +101,15 @@ impl ProjectError for Expected {
|
|||||||
&[] => return "Unsatisfiable expectation".to_string(),
|
&[] => return "Unsatisfiable expectation".to_string(),
|
||||||
[only] => only.to_string(),
|
[only] => only.to_string(),
|
||||||
[a, b] => format!("either {a} or {b}"),
|
[a, b] => format!("either {a} or {b}"),
|
||||||
[variants @ .., last] =>
|
[variants @ .., last] => {
|
||||||
format!("any of {} or {last}", variants.iter().join(", ")),
|
format!("any of {} or {last}", variants.iter().join(", "))
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let or_name = if self.or_name { " or a name" } else { "" };
|
let or_name = if self.or_name { " or a name" } else { "" };
|
||||||
format!("Expected {list}{or_name} but found {}", self.found)
|
format!("Expected {list}{or_name} but found {}", self.found)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.found.location() }
|
||||||
self.found.location()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReservedToken {
|
pub struct ReservedToken {
|
||||||
@@ -135,13 +120,9 @@ impl ProjectError for ReservedToken {
|
|||||||
"A token reserved for future use was found in the code"
|
"A token reserved for future use was found in the code"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String { format!("{} is a reserved token", self.entry) }
|
||||||
format!("{} is a reserved token", self.entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.entry.location() }
|
||||||
self.entry.location()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BadTokenInRegion {
|
pub struct BadTokenInRegion {
|
||||||
@@ -157,9 +138,7 @@ impl ProjectError for BadTokenInRegion {
|
|||||||
format!("{} cannot appear in {}", self.entry, self.region)
|
format!("{} cannot appear in {}", self.entry, self.region)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.entry.location() }
|
||||||
self.entry.location()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NotFound {
|
pub struct NotFound {
|
||||||
@@ -171,25 +150,17 @@ impl ProjectError for NotFound {
|
|||||||
"A specific lexeme was expected but not found in the given range"
|
"A specific lexeme was expected but not found in the given range"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String { format!("{} was expected", self.expected) }
|
||||||
format!("{} was expected", self.expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LeadingNS {
|
pub struct LeadingNS {
|
||||||
pub location: Location,
|
pub location: Location,
|
||||||
}
|
}
|
||||||
impl ProjectError for LeadingNS {
|
impl ProjectError for LeadingNS {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { ":: can only follow a name token" }
|
||||||
":: can only follow a name token"
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
}
|
|
||||||
fn one_position(&self) -> Location {
|
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MisalignedParen {
|
pub struct MisalignedParen {
|
||||||
@@ -199,12 +170,8 @@ impl ProjectError for MisalignedParen {
|
|||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
"Parentheses (), [] and {} must always pair up"
|
"Parentheses (), [] and {} must always pair up"
|
||||||
}
|
}
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String { format!("This {} has no pair", self.entry) }
|
||||||
format!("This {} has no pair", self.entry)
|
fn one_position(&self) -> Location { self.entry.location() }
|
||||||
}
|
|
||||||
fn one_position(&self) -> Location {
|
|
||||||
self.entry.location()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NamespacedExport {
|
pub struct NamespacedExport {
|
||||||
@@ -214,9 +181,7 @@ impl ProjectError for NamespacedExport {
|
|||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
"Exports can only refer to unnamespaced names in the local namespace"
|
"Exports can only refer to unnamespaced names in the local namespace"
|
||||||
}
|
}
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GlobExport {
|
pub struct GlobExport {
|
||||||
@@ -226,9 +191,7 @@ impl ProjectError for GlobExport {
|
|||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
"Exports can only refer to concrete names, globstars are not allowed"
|
"Exports can only refer to concrete names, globstars are not allowed"
|
||||||
}
|
}
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LexError {
|
pub struct LexError {
|
||||||
@@ -237,9 +200,7 @@ pub struct LexError {
|
|||||||
pub file: VName,
|
pub file: VName,
|
||||||
}
|
}
|
||||||
impl ProjectError for LexError {
|
impl ProjectError for LexError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "An error occured during tokenization" }
|
||||||
"An error occured during tokenization"
|
|
||||||
}
|
|
||||||
fn positions(&self) -> BoxedIter<ErrorPosition> {
|
fn positions(&self) -> BoxedIter<ErrorPosition> {
|
||||||
let file = self.file.clone();
|
let file = self.file.clone();
|
||||||
Box::new(self.errors.iter().map(move |s| ErrorPosition {
|
Box::new(self.errors.iter().map(move |s| ErrorPosition {
|
||||||
|
|||||||
@@ -40,9 +40,7 @@ impl Entry {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn location(&self) -> Location {
|
pub fn location(&self) -> Location { self.location.clone() }
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn range(&self) -> Range<usize> {
|
pub fn range(&self) -> Range<usize> {
|
||||||
self.location.range().expect("An Entry can only have a known location")
|
self.location.range().expect("An Entry can only have a known location")
|
||||||
@@ -84,9 +82,7 @@ impl Display for Entry {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
impl AsRef<Location> for Entry {
|
impl AsRef<Location> for Entry {
|
||||||
fn as_ref(&self) -> &Location {
|
fn as_ref(&self) -> &Location { &self.location }
|
||||||
&self.location
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
@@ -144,8 +140,9 @@ impl Display for Lexeme {
|
|||||||
Self::Module => write!(f, "module"),
|
Self::Module => write!(f, "module"),
|
||||||
Self::Const => write!(f, "const"),
|
Self::Const => write!(f, "const"),
|
||||||
Self::Macro => write!(f, "macro"),
|
Self::Macro => write!(f, "macro"),
|
||||||
Self::Operators(ops) =>
|
Self::Operators(ops) => {
|
||||||
write!(f, "operators[{}]", Interner::extern_all(ops).join(" ")),
|
write!(f, "operators[{}]", Interner::extern_all(ops).join(" "))
|
||||||
|
},
|
||||||
Self::Placeh(Placeholder { name, class }) => match *class {
|
Self::Placeh(Placeholder { name, class }) => match *class {
|
||||||
PHClass::Scalar => write!(f, "${}", **name),
|
PHClass::Scalar => write!(f, "${}", **name),
|
||||||
PHClass::Vec { nonzero, prio } => {
|
PHClass::Vec { nonzero, prio } => {
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ pub enum Loaded {
|
|||||||
}
|
}
|
||||||
impl Loaded {
|
impl Loaded {
|
||||||
/// Is the loaded item source code (not a collection)?
|
/// Is the loaded item source code (not a collection)?
|
||||||
pub fn is_code(&self) -> bool {
|
pub fn is_code(&self) -> bool { matches!(self, Loaded::Code(_)) }
|
||||||
matches!(self, Loaded::Code(_))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returned by any source loading callback
|
/// Returned by any source loading callback
|
||||||
|
|||||||
@@ -87,8 +87,9 @@ fn load_abs_path_rec(
|
|||||||
// If the path is not within a file, load it as directory
|
// If the path is not within a file, load it as directory
|
||||||
let coll = match get_source(abs_path) {
|
let coll = match get_source(abs_path) {
|
||||||
Ok(Loaded::Collection(coll)) => coll,
|
Ok(Loaded::Collection(coll)) => coll,
|
||||||
Ok(Loaded::Code(_)) =>
|
Ok(Loaded::Code(_)) => {
|
||||||
unreachable!("split_name returned None but the path is a file"),
|
unreachable!("split_name returned None but the path is a file")
|
||||||
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// todo: if this can actually be produced, return Err(ImportAll) instead
|
// todo: if this can actually be produced, return Err(ImportAll) instead
|
||||||
let parent = abs_path.split_last().expect("import path nonzero").1;
|
let parent = abs_path.split_last().expect("import path nonzero").1;
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ use crate::parse::{self, ParsingContext};
|
|||||||
use crate::representations::sourcefile::{FileEntry, MemberKind};
|
use crate::representations::sourcefile::{FileEntry, MemberKind};
|
||||||
use crate::representations::tree::{ModEntry, ModMember, Module};
|
use crate::representations::tree::{ModEntry, ModMember, Module};
|
||||||
use crate::sourcefile::{FileEntryKind, Import, Member, ModuleBlock};
|
use crate::sourcefile::{FileEntryKind, Import, Member, ModuleBlock};
|
||||||
use crate::utils::pure_push::pushed;
|
|
||||||
use crate::utils::get_or::{get_or_default, get_or_make};
|
use crate::utils::get_or::{get_or_default, get_or_make};
|
||||||
|
use crate::utils::pure_push::pushed;
|
||||||
use crate::{Location, Tok, VName};
|
use crate::{Location, Tok, VName};
|
||||||
|
|
||||||
struct FileReport {
|
struct FileReport {
|
||||||
|
|||||||
@@ -69,8 +69,9 @@ impl Add for PreExtra {
|
|||||||
fn add(self, rhs: Self) -> Self::Output {
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(alt, Self::Dir) | (Self::Dir, alt) => Ok(alt),
|
(alt, Self::Dir) | (Self::Dir, alt) => Ok(alt),
|
||||||
(Self::File(_) | Self::Submod(_), Self::File(_) | Self::Submod(_)) =>
|
(Self::File(_) | Self::Submod(_), Self::File(_) | Self::Submod(_)) => {
|
||||||
panic!("Each file should be parsed once."),
|
panic!("Each file should be parsed once.")
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,8 +80,9 @@ impl Display for PreExtra {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Dir => write!(f, "Directory"),
|
Self::Dir => write!(f, "Directory"),
|
||||||
Self::File(PreFileExt { name, .. }) =>
|
Self::File(PreFileExt { name, .. }) => {
|
||||||
write!(f, "File({}.orc)", Interner::extern_all(name).join("/")),
|
write!(f, "File({}.orc)", Interner::extern_all(name).join("/"))
|
||||||
|
},
|
||||||
Self::Submod(_) => write!(f, "Submodule"),
|
Self::Submod(_) => write!(f, "Submodule"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,9 +57,7 @@ impl<N: NameLike> Expr<N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<N: NameLike> AsRef<Location> for Expr<N> {
|
impl<N: NameLike> AsRef<Location> for Expr<N> {
|
||||||
fn as_ref(&self) -> &Location {
|
fn as_ref(&self) -> &Location { &self.location }
|
||||||
&self.location
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visit all expression sequences including this sequence itself. Otherwise
|
/// Visit all expression sequences including this sequence itself. Otherwise
|
||||||
|
|||||||
@@ -50,9 +50,7 @@ impl ProjectError for Error {
|
|||||||
_ => self.description().to_string(),
|
_ => self.description().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to convert an expression from AST format to typed lambda
|
/// Try to convert an expression from AST format to typed lambda
|
||||||
@@ -73,9 +71,7 @@ impl<'a> Context<'a> {
|
|||||||
Context { names: self.names.push(name) }
|
Context { names: self.names.push(name) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> Context<'static> {
|
fn new() -> Context<'static> { Context { names: Substack::Bottom } }
|
||||||
Context { names: Substack::Bottom }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process an expression sequence
|
/// Process an expression sequence
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use super::location::Location;
|
|||||||
use super::path_set::PathSet;
|
use super::path_set::PathSet;
|
||||||
use super::primitive::Primitive;
|
use super::primitive::Primitive;
|
||||||
use super::Literal;
|
use super::Literal;
|
||||||
|
use crate::foreign::ExternError;
|
||||||
use crate::Sym;
|
use crate::Sym;
|
||||||
|
|
||||||
/// An expression with metadata
|
/// An expression with metadata
|
||||||
@@ -45,6 +46,12 @@ impl Display for Expr {
|
|||||||
/// expression is not a literal
|
/// expression is not a literal
|
||||||
pub struct NotALiteral;
|
pub struct NotALiteral;
|
||||||
|
|
||||||
|
/// Types automatically convertible from an [ExprInst]
|
||||||
|
pub trait TryFromExprInst: Sized {
|
||||||
|
/// Match and clone the value out of an [ExprInst]
|
||||||
|
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>>;
|
||||||
|
}
|
||||||
|
|
||||||
/// A wrapper around expressions to handle their multiple occurences in
|
/// A wrapper around expressions to handle their multiple occurences in
|
||||||
/// the tree together
|
/// the tree together
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -134,6 +141,13 @@ impl ExprInst {
|
|||||||
Clause::Constant(_) | Clause::LambdaArg | Clause::P(_) => None,
|
Clause::Constant(_) | Clause::LambdaArg | Clause::P(_) => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert into any type that implements [FromExprInst]. Calls to this
|
||||||
|
/// function are generated wherever a conversion is elided in an extern
|
||||||
|
/// function.
|
||||||
|
pub fn downcast<T: TryFromExprInst>(&self) -> Result<T, Rc<dyn ExternError>> {
|
||||||
|
T::from_exi(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for ExprInst {
|
impl Debug for ExprInst {
|
||||||
@@ -208,13 +222,9 @@ impl Display for Clause {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<Literal>> From<T> for Clause {
|
impl<T: Into<Literal>> From<T> for Clause {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self { Self::P(Primitive::Literal(value.into())) }
|
||||||
Self::P(Primitive::Literal(value.into()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<Clause>> From<T> for ExprInst {
|
impl<T: Into<Clause>> From<T> for ExprInst {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self { value.into().wrap() }
|
||||||
value.into().wrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,17 +27,11 @@ impl Debug for Literal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl From<NotNan<f64>> for Literal {
|
impl From<NotNan<f64>> for Literal {
|
||||||
fn from(value: NotNan<f64>) -> Self {
|
fn from(value: NotNan<f64>) -> Self { Self::Num(value) }
|
||||||
Self::Num(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl From<u64> for Literal {
|
impl From<u64> for Literal {
|
||||||
fn from(value: u64) -> Self {
|
fn from(value: u64) -> Self { Self::Uint(value) }
|
||||||
Self::Uint(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl From<String> for Literal {
|
impl From<String> for Literal {
|
||||||
fn from(value: String) -> Self {
|
fn from(value: String) -> Self { Self::Str(value.into()) }
|
||||||
Self::Str(value.into())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,13 +25,9 @@ pub trait NameLike: 'static + Clone + Eq + Hash + Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NameLike for Sym {
|
impl NameLike for Sym {
|
||||||
fn to_strv(&self) -> Vec<String> {
|
fn to_strv(&self) -> Vec<String> { self.extern_vec() }
|
||||||
self.extern_vec()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NameLike for VName {
|
impl NameLike for VName {
|
||||||
fn to_strv(&self) -> Vec<String> {
|
fn to_strv(&self) -> Vec<String> { Interner::extern_all(self) }
|
||||||
Interner::extern_all(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ pub enum ItemKind<N: NameLike> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<N: NameLike> Default for ItemKind<N> {
|
impl<N: NameLike> Default for ItemKind<N> {
|
||||||
fn default() -> Self {
|
fn default() -> Self { Self::None }
|
||||||
Self::None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
|
|||||||
@@ -84,8 +84,9 @@ pub enum MemberKind {
|
|||||||
impl Display for MemberKind {
|
impl Display for MemberKind {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Operators(opv) =>
|
Self::Operators(opv) => {
|
||||||
write!(f, "operators[{}]", opv.iter().map(|t| &**t).join(" ")),
|
write!(f, "operators[{}]", opv.iter().map(|t| &**t).join(" "))
|
||||||
|
},
|
||||||
Self::Constant(c) => c.fmt(f),
|
Self::Constant(c) => c.fmt(f),
|
||||||
Self::Module(m) => m.fmt(f),
|
Self::Module(m) => m.fmt(f),
|
||||||
Self::Rule(r) => r.fmt(f),
|
Self::Rule(r) => r.fmt(f),
|
||||||
@@ -130,11 +131,13 @@ impl Display for FileEntryKind {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Comment(s) => write!(f, "--[{s}]--"),
|
Self::Comment(s) => write!(f, "--[{s}]--"),
|
||||||
Self::Export(s) =>
|
Self::Export(s) => {
|
||||||
write!(f, "export ::({})", s.iter().map(|t| &**t.0).join(", ")),
|
write!(f, "export ::({})", s.iter().map(|t| &**t.0).join(", "))
|
||||||
|
},
|
||||||
Self::Member(member) => write!(f, "{member}"),
|
Self::Member(member) => write!(f, "{member}"),
|
||||||
Self::Import(i) =>
|
Self::Import(i) => {
|
||||||
write!(f, "import ({})", i.iter().map(|i| i.to_string()).join(", ")),
|
write!(f, "import ({})", i.iter().map(|i| i.to_string()).join(", "))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ impl Debug for OrcString {
|
|||||||
|
|
||||||
impl OrcString {
|
impl OrcString {
|
||||||
/// Clone out the plain Rust [String]
|
/// Clone out the plain Rust [String]
|
||||||
pub fn get_string(&self) -> String {
|
pub fn get_string(&self) -> String { self.as_str().to_owned() }
|
||||||
self.as_str().to_owned()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for OrcString {
|
impl Deref for OrcString {
|
||||||
@@ -48,15 +46,11 @@ impl Hash for OrcString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for OrcString {
|
impl From<String> for OrcString {
|
||||||
fn from(value: String) -> Self {
|
fn from(value: String) -> Self { Self::Runtime(Rc::new(value)) }
|
||||||
Self::Runtime(Rc::new(value))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Tok<String>> for OrcString {
|
impl From<Tok<String>> for OrcString {
|
||||||
fn from(value: Tok<String>) -> Self {
|
fn from(value: Tok<String>) -> Self { Self::Interned(value) }
|
||||||
Self::Interned(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for OrcString {
|
impl PartialEq for OrcString {
|
||||||
|
|||||||
@@ -223,9 +223,7 @@ pub struct WalkError<'a> {
|
|||||||
}
|
}
|
||||||
impl<'a> WalkError<'a> {
|
impl<'a> WalkError<'a> {
|
||||||
/// Total length of the path represented by this error
|
/// Total length of the path represented by this error
|
||||||
pub fn depth(&self) -> usize {
|
pub fn depth(&self) -> usize { self.prefix.len() + self.pos + 1 }
|
||||||
self.prefix.len() + self.pos + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attach a location to the error and convert into trait object for reporting
|
/// Attach a location to the error and convert into trait object for reporting
|
||||||
pub fn at(self, location: &Location) -> Rc<dyn ProjectError> {
|
pub fn at(self, location: &Location) -> Rc<dyn ProjectError> {
|
||||||
@@ -263,15 +261,15 @@ impl ProjectError for WalkErrorWithLocation {
|
|||||||
let paths = Interner::extern_all(&self.path).join("::");
|
let paths = Interner::extern_all(&self.path).join("::");
|
||||||
let options = Interner::extern_all(&self.options).join(", ");
|
let options = Interner::extern_all(&self.options).join(", ");
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
ErrKind::Missing =>
|
ErrKind::Missing => {
|
||||||
format!("{paths} does not exist, options are {options}"),
|
format!("{paths} does not exist, options are {options}")
|
||||||
ErrKind::NotModule =>
|
},
|
||||||
format!("{paths} is not a module, options are {options}"),
|
ErrKind::NotModule => {
|
||||||
|
format!("{paths} is not a module, options are {options}")
|
||||||
|
},
|
||||||
ErrKind::Private => format!("{paths} is private, options are {options}"),
|
ErrKind::Private => format!("{paths} is private, options are {options}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn one_position(&self) -> Location {
|
fn one_position(&self) -> Location { self.location.clone() }
|
||||||
self.location.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ pub enum AnyMatcher {
|
|||||||
Vec { left: Vec<ScalMatcher>, mid: VecMatcher, right: Vec<ScalMatcher> },
|
Vec { left: Vec<ScalMatcher>, mid: VecMatcher, right: Vec<ScalMatcher> },
|
||||||
}
|
}
|
||||||
impl Matcher for AnyMatcher {
|
impl Matcher for AnyMatcher {
|
||||||
fn new(pattern: Rc<Vec<RuleExpr>>) -> Self {
|
fn new(pattern: Rc<Vec<RuleExpr>>) -> Self { mk_any(&pattern) }
|
||||||
mk_any(&pattern)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply<'a>(&self, source: &'a [RuleExpr]) -> Option<State<'a>> {
|
fn apply<'a>(&self, source: &'a [RuleExpr]) -> Option<State<'a>> {
|
||||||
any_match(self, source)
|
any_match(self, source)
|
||||||
@@ -99,10 +97,12 @@ impl Display for VecMatcher {
|
|||||||
write!(f, "..${key}")
|
write!(f, "..${key}")
|
||||||
},
|
},
|
||||||
Self::Scan { left, sep, right, direction } => match direction {
|
Self::Scan { left, sep, right, direction } => match direction {
|
||||||
Side::Left =>
|
Side::Left => {
|
||||||
write!(f, "Scan{{{left} <== {} <== {right}}}", sep.iter().join(" ")),
|
write!(f, "Scan{{{left} <== {} <== {right}}}", sep.iter().join(" "))
|
||||||
Side::Right =>
|
},
|
||||||
write!(f, "Scan{{{left} ==> {} ==> {right}}}", sep.iter().join(" ")),
|
Side::Right => {
|
||||||
|
write!(f, "Scan{{{left} ==> {} ==> {right}}}", sep.iter().join(" "))
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Self::Middle { left, left_sep, mid, right_sep, right, .. } => {
|
Self::Middle { left, left_sep, mid, right_sep, right, .. } => {
|
||||||
let left_sep_s = left_sep.iter().join(" ");
|
let left_sep_s = left_sep.iter().join(" ");
|
||||||
@@ -134,9 +134,7 @@ impl Display for AnyMatcher {
|
|||||||
/// vectorial placeholders and handles the scalars on leaves.
|
/// vectorial placeholders and handles the scalars on leaves.
|
||||||
pub struct VectreeMatcher(AnyMatcher);
|
pub struct VectreeMatcher(AnyMatcher);
|
||||||
impl Matcher for VectreeMatcher {
|
impl Matcher for VectreeMatcher {
|
||||||
fn new(pattern: Rc<Vec<RuleExpr>>) -> Self {
|
fn new(pattern: Rc<Vec<RuleExpr>>) -> Self { Self(AnyMatcher::new(pattern)) }
|
||||||
Self(AnyMatcher::new(pattern))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply<'a>(&self, source: &'a [RuleExpr]) -> Option<State<'a>> {
|
fn apply<'a>(&self, source: &'a [RuleExpr]) -> Option<State<'a>> {
|
||||||
self.0.apply(source)
|
self.0.apply(source)
|
||||||
|
|||||||
@@ -37,10 +37,12 @@ impl Display for RuleError {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Missing(key) => write!(f, "Key {key} not in match pattern"),
|
Self::Missing(key) => write!(f, "Key {key} not in match pattern"),
|
||||||
Self::ArityMismatch(key) =>
|
Self::ArityMismatch(key) => {
|
||||||
write!(f, "Key {key} used inconsistently with and without ellipsis"),
|
write!(f, "Key {key} used inconsistently with and without ellipsis")
|
||||||
Self::Multiple(key) =>
|
},
|
||||||
write!(f, "Key {key} appears multiple times in match pattern"),
|
Self::Multiple(key) => {
|
||||||
|
write!(f, "Key {key} appears multiple times in match pattern")
|
||||||
|
},
|
||||||
Self::VecNeighbors(left, right) => write!(
|
Self::VecNeighbors(left, right) => write!(
|
||||||
f,
|
f,
|
||||||
"Keys {left} and {right} are two vectorials right next to each other"
|
"Keys {left} and {right} are two vectorials right next to each other"
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ use ordered_float::NotNan;
|
|||||||
|
|
||||||
use crate::facade::{IntoSystem, System};
|
use crate::facade::{IntoSystem, System};
|
||||||
use crate::foreign::cps_box::{init_cps, CPSBox};
|
use crate::foreign::cps_box::{init_cps, CPSBox};
|
||||||
use crate::foreign::{Atomic, ExternError};
|
use crate::foreign::{Atomic, ExternError, InertAtomic};
|
||||||
use crate::interpreted::ExprInst;
|
use crate::interpreted::ExprInst;
|
||||||
use crate::interpreter::HandlerTable;
|
use crate::interpreter::HandlerTable;
|
||||||
use crate::systems::codegen::call;
|
use crate::systems::codegen::call;
|
||||||
use crate::systems::stl::Boolean;
|
use crate::systems::stl::Boolean;
|
||||||
use crate::utils::poller::{PollEvent, Poller};
|
use crate::utils::poller::{PollEvent, Poller};
|
||||||
use crate::utils::unwrap_or;
|
use crate::utils::unwrap_or;
|
||||||
use crate::{atomic_inert, define_fn, ConstTree, Interner};
|
use crate::{define_fn, ConstTree, Interner};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Timer {
|
struct Timer {
|
||||||
@@ -45,7 +45,9 @@ impl Debug for CancelTimer {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct Yield;
|
struct Yield;
|
||||||
atomic_inert!(Yield, typestr = "a yield command");
|
impl InertAtomic for Yield {
|
||||||
|
fn type_str() -> &'static str { "a yield command" }
|
||||||
|
}
|
||||||
|
|
||||||
/// Error indicating a yield command when all event producers and timers had
|
/// Error indicating a yield command when all event producers and timers had
|
||||||
/// exited
|
/// exited
|
||||||
@@ -109,15 +111,11 @@ impl<'a> AsynchSystem<'a> {
|
|||||||
/// Obtain a message port for sending messages to the main thread. If an
|
/// Obtain a message port for sending messages to the main thread. If an
|
||||||
/// object is passed to the MessagePort that does not have a handler, the
|
/// object is passed to the MessagePort that does not have a handler, the
|
||||||
/// main thread panics.
|
/// main thread panics.
|
||||||
pub fn get_port(&self) -> MessagePort {
|
pub fn get_port(&self) -> MessagePort { MessagePort(self.sender.clone()) }
|
||||||
MessagePort(self.sender.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for AsynchSystem<'a> {
|
impl<'a> Default for AsynchSystem<'a> {
|
||||||
fn default() -> Self {
|
fn default() -> Self { Self::new() }
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoSystem<'a> for AsynchSystem<'a> {
|
impl<'a> IntoSystem<'a> for AsynchSystem<'a> {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use std::rc::Rc;
|
|||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
use super::assertion_error::AssertionError;
|
use super::assertion_error::AssertionError;
|
||||||
use crate::foreign::{Atomic, ExternError};
|
use crate::foreign::{Atom, Atomic, ExternError};
|
||||||
use crate::interpreted::Clause;
|
use crate::interpreted::{Clause, TryFromExprInst};
|
||||||
use crate::representations::interpreted::ExprInst;
|
use crate::representations::interpreted::ExprInst;
|
||||||
use crate::representations::{Literal, OrcString};
|
use crate::representations::{Literal, OrcString};
|
||||||
use crate::Primitive;
|
use crate::Primitive;
|
||||||
@@ -27,92 +27,66 @@ pub fn with_str<T>(
|
|||||||
x: &ExprInst,
|
x: &ExprInst,
|
||||||
predicate: impl FnOnce(&OrcString) -> Result<T, Rc<dyn ExternError>>,
|
predicate: impl FnOnce(&OrcString) -> Result<T, Rc<dyn ExternError>>,
|
||||||
) -> Result<T, Rc<dyn ExternError>> {
|
) -> Result<T, Rc<dyn ExternError>> {
|
||||||
with_lit(x, |l| {
|
with_lit(x, |l| match l {
|
||||||
if let Literal::Str(s) = l {
|
Literal::Str(s) => predicate(s),
|
||||||
predicate(s)
|
_ => AssertionError::fail(x.clone(), "a string"),
|
||||||
} else {
|
|
||||||
AssertionError::fail(x.clone(), "a string")?
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like [with_lit] but also unwraps [Literal::Uint]
|
/// If the [ExprInst] stores an [Atom], maps the predicate over it, otherwise
|
||||||
pub fn with_uint<T>(
|
/// raises a runtime error.
|
||||||
|
pub fn with_atom<T>(
|
||||||
x: &ExprInst,
|
x: &ExprInst,
|
||||||
predicate: impl FnOnce(u64) -> Result<T, Rc<dyn ExternError>>,
|
predicate: impl FnOnce(&Atom) -> Result<T, Rc<dyn ExternError>>,
|
||||||
) -> Result<T, Rc<dyn ExternError>> {
|
) -> Result<T, Rc<dyn ExternError>> {
|
||||||
with_lit(x, |l| {
|
x.inspect(|c| match c {
|
||||||
if let Literal::Uint(u) = l {
|
Clause::P(Primitive::Atom(a)) => predicate(a),
|
||||||
predicate(*u)
|
_ => AssertionError::fail(x.clone(), "an atom"),
|
||||||
} else {
|
|
||||||
AssertionError::fail(x.clone(), "an uint")?
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Like [with_lit] but also unwraps [Literal::Num]
|
|
||||||
pub fn with_num<T>(
|
|
||||||
x: &ExprInst,
|
|
||||||
predicate: impl FnOnce(NotNan<f64>) -> Result<T, Rc<dyn ExternError>>,
|
|
||||||
) -> Result<T, Rc<dyn ExternError>> {
|
|
||||||
with_lit(x, |l| {
|
|
||||||
if let Literal::Num(n) = l {
|
|
||||||
predicate(*n)
|
|
||||||
} else {
|
|
||||||
AssertionError::fail(x.clone(), "a float")?
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to cast the [ExprInst] into the specified atom type. Throws an
|
/// Tries to cast the [ExprInst] into the specified atom type. Throws an
|
||||||
/// assertion error if unsuccessful, or calls the provided function on the
|
/// assertion error if unsuccessful, or calls the provided function on the
|
||||||
/// extracted atomic type.
|
/// extracted atomic type.
|
||||||
pub fn with_atom<T: Atomic, U>(
|
pub fn with_atomic<T: Atomic, U>(
|
||||||
x: &ExprInst,
|
x: &ExprInst,
|
||||||
inexact_typename: &'static str,
|
inexact_typename: &'static str,
|
||||||
predicate: impl FnOnce(&T) -> Result<U, Rc<dyn ExternError>>,
|
predicate: impl FnOnce(&T) -> Result<U, Rc<dyn ExternError>>,
|
||||||
) -> Result<U, Rc<dyn ExternError>> {
|
) -> Result<U, Rc<dyn ExternError>> {
|
||||||
x.inspect(|c| {
|
with_atom(x, |a| match a.try_cast() {
|
||||||
if let Clause::P(Primitive::Atom(a)) = c {
|
Some(atomic) => predicate(atomic),
|
||||||
a.try_cast()
|
_ => AssertionError::fail(x.clone(), inexact_typename),
|
||||||
.map(predicate)
|
|
||||||
.unwrap_or_else(|| AssertionError::fail(x.clone(), inexact_typename))
|
|
||||||
} else {
|
|
||||||
AssertionError::fail(x.clone(), "an atom")
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ######## Automatically ########
|
// ######## Automatically ########
|
||||||
|
|
||||||
impl TryFrom<&ExprInst> for Literal {
|
impl TryFromExprInst for Literal {
|
||||||
type Error = Rc<dyn ExternError>;
|
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||||
|
with_lit(exi, |l| Ok(l.clone()))
|
||||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
|
||||||
with_lit(value, |l| Ok(l.clone()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&ExprInst> for OrcString {
|
impl TryFromExprInst for OrcString {
|
||||||
type Error = Rc<dyn ExternError>;
|
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||||
|
with_str(exi, |s| Ok(s.clone()))
|
||||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
|
||||||
with_str(value, |s| Ok(s.clone()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&ExprInst> for u64 {
|
impl TryFromExprInst for u64 {
|
||||||
type Error = Rc<dyn ExternError>;
|
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||||
|
with_lit(exi, |l| match l {
|
||||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
Literal::Uint(u) => Ok(*u),
|
||||||
with_uint(value, Ok)
|
_ => AssertionError::fail(exi.clone(), "an uint"),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&ExprInst> for NotNan<f64> {
|
impl TryFromExprInst for NotNan<f64> {
|
||||||
type Error = Rc<dyn ExternError>;
|
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||||
|
with_lit(exi, |l| match l {
|
||||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
Literal::Num(n) => Ok(*n),
|
||||||
with_num(value, Ok)
|
_ => AssertionError::fail(exi.clone(), "a float"),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,19 +12,19 @@ use crate::{ast, define_fn, ConstTree, Interner, Primitive};
|
|||||||
define_fn! {
|
define_fn! {
|
||||||
ReadString = |x| Ok(init_cps(3, IOCmdHandlePack{
|
ReadString = |x| Ok(init_cps(3, IOCmdHandlePack{
|
||||||
cmd: ReadCmd::RStr(SRead::All),
|
cmd: ReadCmd::RStr(SRead::All),
|
||||||
handle: x.try_into()?
|
handle: x.downcast()?
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
define_fn! {
|
define_fn! {
|
||||||
ReadLine = |x| Ok(init_cps(3, IOCmdHandlePack{
|
ReadLine = |x| Ok(init_cps(3, IOCmdHandlePack{
|
||||||
cmd: ReadCmd::RStr(SRead::Line),
|
cmd: ReadCmd::RStr(SRead::Line),
|
||||||
handle: x.try_into()?
|
handle: x.downcast()?
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
define_fn! {
|
define_fn! {
|
||||||
ReadBin = |x| Ok(init_cps(3, IOCmdHandlePack{
|
ReadBin = |x| Ok(init_cps(3, IOCmdHandlePack{
|
||||||
cmd: ReadCmd::RBytes(BRead::All),
|
cmd: ReadCmd::RBytes(BRead::All),
|
||||||
handle: x.try_into()?
|
handle: x.downcast()?
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
define_fn! {
|
define_fn! {
|
||||||
@@ -72,7 +72,7 @@ define_fn! {
|
|||||||
define_fn! {
|
define_fn! {
|
||||||
Flush = |x| Ok(init_cps(3, IOCmdHandlePack {
|
Flush = |x| Ok(init_cps(3, IOCmdHandlePack {
|
||||||
cmd: WriteCmd::Flush,
|
cmd: WriteCmd::Flush,
|
||||||
handle: x.try_into()?
|
handle: x.downcast()?
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,23 +81,23 @@ pub enum ReadResult {
|
|||||||
impl ReadResult {
|
impl ReadResult {
|
||||||
pub fn dispatch(self, succ: ExprInst, fail: ExprInst) -> Vec<ExprInst> {
|
pub fn dispatch(self, succ: ExprInst, fail: ExprInst) -> Vec<ExprInst> {
|
||||||
match self {
|
match self {
|
||||||
ReadResult::RBin(_, Err(e)) | ReadResult::RStr(_, Err(e)) =>
|
ReadResult::RBin(_, Err(e)) | ReadResult::RStr(_, Err(e)) => {
|
||||||
vec![call(fail, vec![wrap_io_error(e)]).wrap()],
|
vec![call(fail, vec![wrap_io_error(e)]).wrap()]
|
||||||
|
},
|
||||||
ReadResult::RBin(_, Ok(bytes)) => {
|
ReadResult::RBin(_, Ok(bytes)) => {
|
||||||
let arg = Binary(Arc::new(bytes)).atom_cls().wrap();
|
let arg = Binary(Arc::new(bytes)).atom_cls().wrap();
|
||||||
vec![call(succ, vec![arg]).wrap()]
|
vec![call(succ, vec![arg]).wrap()]
|
||||||
},
|
},
|
||||||
ReadResult::RStr(_, Ok(text)) =>
|
ReadResult::RStr(_, Ok(text)) => {
|
||||||
vec![call(succ, vec![Literal::Str(text.into()).into()]).wrap()],
|
vec![call(succ, vec![Literal::Str(text.into()).into()]).wrap()]
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Placeholder function for an eventual conversion from [io::Error] to Orchid
|
/// Placeholder function for an eventual conversion from [io::Error] to Orchid
|
||||||
/// data
|
/// data
|
||||||
fn wrap_io_error(_e: io::Error) -> ExprInst {
|
fn wrap_io_error(_e: io::Error) -> ExprInst { Literal::Uint(0u64).into() }
|
||||||
Literal::Uint(0u64).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writing command (string or binary)
|
/// Writing command (string or binary)
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ mod assertion_error;
|
|||||||
pub mod asynch;
|
pub mod asynch;
|
||||||
pub mod cast_exprinst;
|
pub mod cast_exprinst;
|
||||||
pub mod codegen;
|
pub mod codegen;
|
||||||
|
mod directfs;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
mod runtime_error;
|
mod runtime_error;
|
||||||
pub mod stl;
|
|
||||||
mod directfs;
|
|
||||||
pub mod scheduler;
|
pub mod scheduler;
|
||||||
|
pub mod stl;
|
||||||
|
|
||||||
pub use assertion_error::AssertionError;
|
pub use assertion_error::AssertionError;
|
||||||
pub use runtime_error::RuntimeError;
|
pub use runtime_error::RuntimeError;
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use crate::interpreted::ExprInst;
|
|
||||||
|
|
||||||
use super::Canceller;
|
use super::Canceller;
|
||||||
|
use crate::interpreted::ExprInst;
|
||||||
|
|
||||||
pub type SyncResult<T> = (T, Box<dyn Any + Send>);
|
pub type SyncResult<T> = (T, Box<dyn Any + Send>);
|
||||||
pub type SyncOperation<T> =
|
pub type SyncOperation<T> =
|
||||||
Box<dyn FnOnce(T, Canceller) -> SyncResult<T> + Send>;
|
Box<dyn FnOnce(T, Canceller) -> SyncResult<T> + Send>;
|
||||||
pub type SyncOpResultHandler<T> = Box<
|
pub type SyncOpResultHandler<T> =
|
||||||
dyn FnOnce(T, Box<dyn Any + Send>, Canceller) -> (T, Vec<ExprInst>),
|
Box<dyn FnOnce(T, Box<dyn Any + Send>, Canceller) -> (T, Vec<ExprInst>)>;
|
||||||
>;
|
|
||||||
|
|
||||||
|
|
||||||
struct SyncQueueItem<T> {
|
struct SyncQueueItem<T> {
|
||||||
cancelled: Canceller,
|
cancelled: Canceller,
|
||||||
@@ -89,9 +86,7 @@ impl<T> BusyState<T> {
|
|||||||
self.seal = Some(Box::new(recipient))
|
self.seal = Some(Box::new(recipient))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_sealed(&self) -> bool {
|
pub fn is_sealed(&self) -> bool { self.seal.is_some() }
|
||||||
self.seal.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rotate<U: Send + 'static>(
|
pub fn rotate<U: Send + 'static>(
|
||||||
mut self,
|
mut self,
|
||||||
|
|||||||
@@ -1,32 +1,26 @@
|
|||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::atomic_inert;
|
use crate::foreign::InertAtomic;
|
||||||
|
|
||||||
/// A single-fire thread-safe boolean flag with relaxed ordering
|
/// A single-fire thread-safe boolean flag with relaxed ordering
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Canceller(Arc<AtomicBool>);
|
pub struct Canceller(Arc<AtomicBool>);
|
||||||
atomic_inert!(Canceller, typestr = "a canceller");
|
impl InertAtomic for Canceller {
|
||||||
|
fn type_str() -> &'static str { "a canceller" }
|
||||||
|
}
|
||||||
|
|
||||||
impl Canceller {
|
impl Canceller {
|
||||||
/// Create a new canceller
|
/// Create a new canceller
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Canceller(Arc::new(AtomicBool::new(false))) }
|
||||||
Canceller(Arc::new(AtomicBool::new(false)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check whether the operation has been cancelled
|
/// Check whether the operation has been cancelled
|
||||||
pub fn is_cancelled(&self) -> bool {
|
pub fn is_cancelled(&self) -> bool { self.0.load(Ordering::Relaxed) }
|
||||||
self.0.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cancel the operation
|
/// Cancel the operation
|
||||||
pub fn cancel(&self) {
|
pub fn cancel(&self) { self.0.store(true, Ordering::Relaxed) }
|
||||||
self.0.store(true, Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Canceller {
|
impl Default for Canceller {
|
||||||
fn default() -> Self {
|
fn default() -> Self { Self::new() }
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
//! reference to a shared resource.
|
//! reference to a shared resource.
|
||||||
|
|
||||||
mod busy;
|
mod busy;
|
||||||
mod system;
|
|
||||||
mod canceller;
|
mod canceller;
|
||||||
mod take_and_drop;
|
mod system;
|
||||||
|
|
||||||
pub use canceller::Canceller;
|
pub use canceller::Canceller;
|
||||||
pub use system::{SealedOrTaken, SeqScheduler, SharedHandle, SharedState};
|
pub use system::{SealedOrTaken, SeqScheduler, SharedHandle, SharedState};
|
||||||
|
|||||||
@@ -8,17 +8,20 @@ use itertools::Itertools;
|
|||||||
use trait_set::trait_set;
|
use trait_set::trait_set;
|
||||||
|
|
||||||
use super::busy::{BusyState, NextItemReportKind};
|
use super::busy::{BusyState, NextItemReportKind};
|
||||||
use super::take_and_drop::{request, TakeAndDrop, TakeCmd};
|
|
||||||
use super::Canceller;
|
use super::Canceller;
|
||||||
use crate::facade::{IntoSystem, System};
|
use crate::facade::{IntoSystem, System};
|
||||||
use crate::foreign::cps_box::CPSBox;
|
use crate::foreign::cps_box::{init_cps, CPSBox};
|
||||||
|
use crate::foreign::InertAtomic;
|
||||||
use crate::interpreted::ExprInst;
|
use crate::interpreted::ExprInst;
|
||||||
use crate::interpreter::HandlerTable;
|
use crate::interpreter::HandlerTable;
|
||||||
use crate::systems::asynch::{AsynchSystem, MessagePort};
|
use crate::systems::asynch::{AsynchSystem, MessagePort};
|
||||||
|
use crate::systems::cast_exprinst::with_atom;
|
||||||
use crate::systems::stl::Boolean;
|
use crate::systems::stl::Boolean;
|
||||||
|
use crate::systems::AssertionError;
|
||||||
|
use crate::utils::ddispatch::{request, Request};
|
||||||
use crate::utils::thread_pool::ThreadPool;
|
use crate::utils::thread_pool::ThreadPool;
|
||||||
use crate::utils::{take_with_output, unwrap_or, IdMap};
|
use crate::utils::{take_with_output, unwrap_or, IdMap};
|
||||||
use crate::{atomic_inert, define_fn, ConstTree};
|
use crate::{define_fn, ConstTree};
|
||||||
|
|
||||||
enum SharedResource<T> {
|
enum SharedResource<T> {
|
||||||
Free(T),
|
Free(T),
|
||||||
@@ -45,18 +48,17 @@ pub enum SharedState {
|
|||||||
|
|
||||||
/// A shared handle for a resource of type `T` that can be used with a
|
/// A shared handle for a resource of type `T` that can be used with a
|
||||||
/// [SeqScheduler] to execute mutating operations one by one in worker threads.
|
/// [SeqScheduler] to execute mutating operations one by one in worker threads.
|
||||||
pub struct SharedHandle<T> {
|
pub struct SharedHandle<T>(Rc<RefCell<SharedResource<T>>>);
|
||||||
state: Rc<RefCell<SharedResource<T>>>,
|
|
||||||
}
|
|
||||||
impl<T> SharedHandle<T> {
|
impl<T> SharedHandle<T> {
|
||||||
/// Wrap a value to be accessible to a [SeqScheduler].
|
/// Wrap a value to be accessible to a [SeqScheduler].
|
||||||
pub fn wrap(t: T) -> Self {
|
pub fn wrap(t: T) -> Self {
|
||||||
Self { state: Rc::new(RefCell::new(SharedResource::Free(t))) }
|
Self(Rc::new(RefCell::new(SharedResource::Free(t))))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the state of the handle
|
/// Check the state of the handle
|
||||||
pub fn state(&self) -> SharedState {
|
pub fn state(&self) -> SharedState {
|
||||||
match &*self.state.as_ref().borrow() {
|
match &*self.0.as_ref().borrow() {
|
||||||
SharedResource::Busy(b) if b.is_sealed() => SharedState::Sealed,
|
SharedResource::Busy(b) if b.is_sealed() => SharedState::Sealed,
|
||||||
SharedResource::Busy(_) => SharedState::Busy,
|
SharedResource::Busy(_) => SharedState::Busy,
|
||||||
SharedResource::Free(_) => SharedState::Free,
|
SharedResource::Free(_) => SharedState::Free,
|
||||||
@@ -69,32 +71,24 @@ impl<T> SharedHandle<T> {
|
|||||||
/// sense as eg. an optimization. You can return the value after processing
|
/// sense as eg. an optimization. You can return the value after processing
|
||||||
/// via [SyncHandle::untake].
|
/// via [SyncHandle::untake].
|
||||||
pub fn take(&self) -> Option<T> {
|
pub fn take(&self) -> Option<T> {
|
||||||
take_with_output(
|
take_with_output(&mut *self.0.as_ref().borrow_mut(), |state| match state {
|
||||||
&mut *self.state.as_ref().borrow_mut(),
|
SharedResource::Free(t) => (SharedResource::Taken, Some(t)),
|
||||||
|state| match state {
|
_ => (state, None),
|
||||||
SharedResource::Free(t) => (SharedResource::Taken, Some(t)),
|
})
|
||||||
_ => (state, None),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the value to a handle that doesn't have one. The intended use case
|
/// Return the value to a handle that doesn't have one. The intended use case
|
||||||
/// is to return values synchronously after they have been removed with
|
/// is to return values synchronously after they have been removed with
|
||||||
/// [SyncHandle::untake].
|
/// [SyncHandle::untake].
|
||||||
pub fn untake(&self, value: T) -> Result<(), T> {
|
pub fn untake(&self, value: T) -> Result<(), T> {
|
||||||
take_with_output(
|
take_with_output(&mut *self.0.as_ref().borrow_mut(), |state| match state {
|
||||||
&mut *self.state.as_ref().borrow_mut(),
|
SharedResource::Taken => (SharedResource::Free(value), Ok(())),
|
||||||
|state| match state {
|
_ => (state, Err(value)),
|
||||||
SharedResource::Taken => (SharedResource::Free(value), Ok(())),
|
})
|
||||||
_ => (state, Err(value)),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T> Clone for SharedHandle<T> {
|
impl<T> Clone for SharedHandle<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { Self(self.0.clone()) }
|
||||||
Self { state: self.state.clone() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<T> Debug for SharedHandle<T> {
|
impl<T> Debug for SharedHandle<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
@@ -104,23 +98,46 @@ impl<T> Debug for SharedHandle<T> {
|
|||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<T: 'static> InertAtomic for SharedHandle<T> {
|
||||||
|
fn type_str() -> &'static str { "a SharedHandle" }
|
||||||
|
fn respond(&self, mut request: Request) {
|
||||||
|
request.serve_with(|| {
|
||||||
|
let this = self.clone();
|
||||||
|
TakeCmd(Rc::new(move |sch| {
|
||||||
|
let _ = sch.seal(this.clone(), |_| Vec::new());
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
atomic_inert! {
|
#[derive(Clone)]
|
||||||
SharedHandle(T),
|
pub struct TakeCmd(pub Rc<dyn Fn(SeqScheduler)>);
|
||||||
typestr = "a shared handle",
|
impl Debug for TakeCmd {
|
||||||
request = |req: Box<dyn Any>, this: &SharedHandle<T>| request(this, req)
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "A command to drop a shared resource")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
define_fn! {
|
||||||
|
pub TakeAndDrop = |x| with_atom(x, |a| match request(a.0.as_ref()) {
|
||||||
|
Some(t) => Ok(init_cps::<TakeCmd>(1, t)),
|
||||||
|
None => AssertionError::fail(x.clone(), "a SharedHandle"),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error produced when an operation is scheduled or a seal placed on a resource
|
/// Error produced when an operation is scheduled or a seal placed on a resource
|
||||||
/// which is either already sealed or taken.
|
/// which is either already sealed or taken.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SealedOrTaken;
|
pub struct SealedOrTaken;
|
||||||
atomic_inert!(
|
impl InertAtomic for SealedOrTaken {
|
||||||
SealedOrTaken,
|
fn type_str() -> &'static str {
|
||||||
typestr = "a sealed-or-taken error for a shared resource"
|
"a sealed-or-taken error for a shared resource"
|
||||||
);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
define_fn! {
|
define_fn! {
|
||||||
IsTakenError = |x| Ok(Boolean(SealedOrTaken::try_from(x).is_ok()).atom_cls())
|
IsTakenError = |x| {
|
||||||
|
Ok(Boolean(x.downcast::<SealedOrTaken>().is_ok()).atom_cls())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait_set! {
|
trait_set! {
|
||||||
@@ -184,16 +201,17 @@ impl SeqScheduler {
|
|||||||
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>) + 'static,
|
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>) + 'static,
|
||||||
early_cancel: impl FnOnce(T) -> (T, Vec<ExprInst>) + 'static,
|
early_cancel: impl FnOnce(T) -> (T, Vec<ExprInst>) + 'static,
|
||||||
) -> Result<Canceller, SealedOrTaken> {
|
) -> Result<Canceller, SealedOrTaken> {
|
||||||
take_with_output(&mut *handle.state.as_ref().borrow_mut(), {
|
take_with_output(&mut *handle.0.as_ref().borrow_mut(), {
|
||||||
let handle = handle.clone();
|
let handle = handle.clone();
|
||||||
|state| {
|
|state| {
|
||||||
match state {
|
match state {
|
||||||
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
|
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
|
||||||
SharedResource::Busy(mut b) =>
|
SharedResource::Busy(mut b) => {
|
||||||
match b.enqueue(operation, handler, early_cancel) {
|
match b.enqueue(operation, handler, early_cancel) {
|
||||||
Some(cancelled) => (SharedResource::Busy(b), Ok(cancelled)),
|
Some(cancelled) => (SharedResource::Busy(b), Ok(cancelled)),
|
||||||
None => (SharedResource::Busy(b), Err(SealedOrTaken)),
|
None => (SharedResource::Busy(b), Err(SealedOrTaken)),
|
||||||
},
|
}
|
||||||
|
},
|
||||||
SharedResource::Free(t) => {
|
SharedResource::Free(t) => {
|
||||||
let cancelled = Canceller::new();
|
let cancelled = Canceller::new();
|
||||||
drop(early_cancel); // cannot possibly be useful
|
drop(early_cancel); // cannot possibly be useful
|
||||||
@@ -212,8 +230,9 @@ impl SeqScheduler {
|
|||||||
handle: SharedHandle<T>,
|
handle: SharedHandle<T>,
|
||||||
seal: impl FnOnce(T) -> Vec<ExprInst> + 'static,
|
seal: impl FnOnce(T) -> Vec<ExprInst> + 'static,
|
||||||
) -> Result<Vec<ExprInst>, SealedOrTaken> {
|
) -> Result<Vec<ExprInst>, SealedOrTaken> {
|
||||||
take_with_output(&mut *handle.state.as_ref().borrow_mut(), |state| {
|
take_with_output(
|
||||||
match state {
|
&mut *handle.0.as_ref().borrow_mut(),
|
||||||
|
|state| match state {
|
||||||
SharedResource::Busy(mut b) if !b.is_sealed() => {
|
SharedResource::Busy(mut b) if !b.is_sealed() => {
|
||||||
b.seal(seal);
|
b.seal(seal);
|
||||||
(SharedResource::Busy(b), Ok(Vec::new()))
|
(SharedResource::Busy(b), Ok(Vec::new()))
|
||||||
@@ -221,8 +240,8 @@ impl SeqScheduler {
|
|||||||
SharedResource::Busy(_) => (state, Err(SealedOrTaken)),
|
SharedResource::Busy(_) => (state, Err(SealedOrTaken)),
|
||||||
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
|
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
|
||||||
SharedResource::Free(t) => (SharedResource::Taken, Ok(seal(t))),
|
SharedResource::Free(t) => (SharedResource::Taken, Ok(seal(t))),
|
||||||
}
|
},
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronously recursive function to schedule a new task for execution and
|
/// Asynchronously recursive function to schedule a new task for execution and
|
||||||
@@ -244,7 +263,7 @@ impl SeqScheduler {
|
|||||||
let (t, u): (T, U) =
|
let (t, u): (T, U) =
|
||||||
*data.downcast().expect("This is associated by ID");
|
*data.downcast().expect("This is associated by ID");
|
||||||
let handle2 = handle.clone();
|
let handle2 = handle.clone();
|
||||||
take_with_output(&mut *handle.state.as_ref().borrow_mut(), |state| {
|
take_with_output(&mut *handle.0.as_ref().borrow_mut(), |state| {
|
||||||
let busy = unwrap_or! { state => SharedResource::Busy;
|
let busy = unwrap_or! { state => SharedResource::Busy;
|
||||||
panic!("Handle with outstanding invocation must be busy")
|
panic!("Handle with outstanding invocation must be busy")
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
use std::any::Any;
|
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use super::{SeqScheduler, SharedHandle};
|
|
||||||
use crate::foreign::cps_box::{init_cps, CPSBox};
|
|
||||||
use crate::foreign::Atom;
|
|
||||||
use crate::interpreted::Clause;
|
|
||||||
use crate::systems::AssertionError;
|
|
||||||
use crate::{define_fn, Primitive};
|
|
||||||
|
|
||||||
pub fn request<T: 'static>(
|
|
||||||
handle: &SharedHandle<T>,
|
|
||||||
request: Box<dyn Any>,
|
|
||||||
) -> Option<Box<dyn Any>> {
|
|
||||||
if request.downcast::<TakerRequest>().is_ok() {
|
|
||||||
let handle = handle.clone();
|
|
||||||
let cmd = TakeCmd(Rc::new(move |sch| {
|
|
||||||
let _ = sch.seal(handle.clone(), |_| Vec::new());
|
|
||||||
}));
|
|
||||||
return Some(Box::new(init_cps(1, cmd)))
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TakerRequest;
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TakeCmd(pub Rc<dyn Fn(SeqScheduler)>);
|
|
||||||
impl Debug for TakeCmd {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "A command to drop a shared resource")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
define_fn! {
|
|
||||||
pub TakeAndDrop = |x| x.inspect(|c| match c {
|
|
||||||
Clause::P(Primitive::Atom(Atom(atomic))) => {
|
|
||||||
let t = atomic.request(Box::new(TakerRequest))
|
|
||||||
.ok_or_else(|| AssertionError::ext(x.clone(), "a SharedHandle"))?;
|
|
||||||
let data: CPSBox<TakeCmd> = *t.downcast().expect("implied by request");
|
|
||||||
Ok(data.atom_cls())
|
|
||||||
},
|
|
||||||
_ => AssertionError::fail(x.clone(), "an atom"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -4,16 +4,18 @@ use std::sync::Arc;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::Boolean;
|
use super::Boolean;
|
||||||
use crate::systems::cast_exprinst::with_uint;
|
use crate::foreign::InertAtomic;
|
||||||
use crate::systems::codegen::{orchid_opt, tuple};
|
use crate::systems::codegen::{orchid_opt, tuple};
|
||||||
use crate::systems::RuntimeError;
|
use crate::systems::RuntimeError;
|
||||||
use crate::utils::{iter_find, unwrap_or};
|
use crate::utils::{iter_find, unwrap_or};
|
||||||
use crate::{atomic_inert, define_fn, ConstTree, Interner, Literal};
|
use crate::{define_fn, ConstTree, Interner, Literal};
|
||||||
|
|
||||||
/// A block of binary data
|
/// A block of binary data
|
||||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct Binary(pub Arc<Vec<u8>>);
|
pub struct Binary(pub Arc<Vec<u8>>);
|
||||||
atomic_inert!(Binary, typestr = "a binary blob");
|
impl InertAtomic for Binary {
|
||||||
|
fn type_str() -> &'static str { "a binary blob" }
|
||||||
|
}
|
||||||
|
|
||||||
impl Debug for Binary {
|
impl Debug for Binary {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
@@ -96,11 +98,7 @@ define_fn! {expr=x in
|
|||||||
|
|
||||||
define_fn! {expr=x in
|
define_fn! {expr=x in
|
||||||
/// Extract a subsection of the binary data
|
/// Extract a subsection of the binary data
|
||||||
pub Slice {
|
pub Slice { s: Binary, i: u64, len: u64 } => {
|
||||||
s: Binary,
|
|
||||||
i: u64 as with_uint(x, Ok),
|
|
||||||
len: u64 as with_uint(x, Ok)
|
|
||||||
} => {
|
|
||||||
if i + len < s.0.len() as u64 {
|
if i + len < s.0.len() as u64 {
|
||||||
RuntimeError::fail(
|
RuntimeError::fail(
|
||||||
"Byte index out of bounds".to_string(),
|
"Byte index out of bounds".to_string(),
|
||||||
@@ -123,10 +121,7 @@ define_fn! {expr=x in
|
|||||||
|
|
||||||
define_fn! {expr=x in
|
define_fn! {expr=x in
|
||||||
/// Split binary data block into two smaller blocks
|
/// Split binary data block into two smaller blocks
|
||||||
pub Split {
|
pub Split { bin: Binary, i: u64 } => {
|
||||||
bin: Binary,
|
|
||||||
i: u64 as with_uint(x, Ok)
|
|
||||||
} => {
|
|
||||||
if bin.0.len() < *i as usize {
|
if bin.0.len() < *i as usize {
|
||||||
RuntimeError::fail(
|
RuntimeError::fail(
|
||||||
"Byte index out of bounds".to_string(),
|
"Byte index out of bounds".to_string(),
|
||||||
@@ -144,7 +139,7 @@ define_fn! {expr=x in
|
|||||||
define_fn! {
|
define_fn! {
|
||||||
/// Detect the number of bytes in the binary data block
|
/// Detect the number of bytes in the binary data block
|
||||||
pub Size = |x| {
|
pub Size = |x| {
|
||||||
Ok(Literal::Uint(Binary::try_from(x)?.0.len() as u64).into())
|
Ok(Literal::Uint(x.downcast::<Binary>()?.0.len() as u64).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::foreign::InertAtomic;
|
||||||
use crate::interner::Interner;
|
use crate::interner::Interner;
|
||||||
use crate::representations::interpreted::Clause;
|
use crate::representations::interpreted::Clause;
|
||||||
use crate::systems::AssertionError;
|
use crate::systems::AssertionError;
|
||||||
use crate::{atomic_inert, define_fn, ConstTree, Literal, PathSet};
|
use crate::{define_fn, ConstTree, Literal, PathSet};
|
||||||
|
|
||||||
/// Booleans exposed to Orchid
|
/// Booleans exposed to Orchid
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct Boolean(pub bool);
|
pub struct Boolean(pub bool);
|
||||||
atomic_inert!(Boolean, typestr = "a boolean");
|
impl InertAtomic for Boolean {
|
||||||
|
fn type_str() -> &'static str { "a boolean" }
|
||||||
|
}
|
||||||
|
|
||||||
impl From<bool> for Boolean {
|
impl From<bool> for Boolean {
|
||||||
fn from(value: bool) -> Self {
|
fn from(value: bool) -> Self { Self(value) }
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
define_fn! {expr=x in
|
define_fn! {expr=x in
|
||||||
@@ -36,7 +37,7 @@ define_fn! {expr=x in
|
|||||||
define_fn! {
|
define_fn! {
|
||||||
/// Takes a boolean and two branches, runs the first if the bool is true, the
|
/// Takes a boolean and two branches, runs the first if the bool is true, the
|
||||||
/// second if it's false.
|
/// second if it's false.
|
||||||
IfThenElse = |x| x.try_into()
|
IfThenElse = |x| x.downcast()
|
||||||
.map_err(|_| AssertionError::ext(x.clone(), "a boolean"))
|
.map_err(|_| AssertionError::ext(x.clone(), "a boolean"))
|
||||||
.map(|b: Boolean| if b.0 {Clause::Lambda {
|
.map(|b: Boolean| if b.0 {Clause::Lambda {
|
||||||
args: Some(PathSet { steps: Rc::new(vec![]), next: None }),
|
args: Some(PathSet { steps: Rc::new(vec![]), next: None }),
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ use std::fmt::Debug;
|
|||||||
use crate::foreign::{Atomic, AtomicReturn};
|
use crate::foreign::{Atomic, AtomicReturn};
|
||||||
use crate::interpreter::Context;
|
use crate::interpreter::Context;
|
||||||
use crate::representations::interpreted::ExprInst;
|
use crate::representations::interpreted::ExprInst;
|
||||||
use crate::{atomic_defaults, write_fn_step, ConstTree, Interner};
|
use crate::utils::ddispatch::Responder;
|
||||||
|
use crate::{write_fn_step, ConstTree, Interner};
|
||||||
|
|
||||||
write_fn_step! {
|
write_fn_step! {
|
||||||
/// Print and return whatever expression is in the argument without
|
/// Print and return whatever expression is in the argument without
|
||||||
@@ -15,8 +16,9 @@ write_fn_step! {
|
|||||||
struct Inspect1 {
|
struct Inspect1 {
|
||||||
expr_inst: ExprInst,
|
expr_inst: ExprInst,
|
||||||
}
|
}
|
||||||
|
impl Responder for Inspect1 {}
|
||||||
impl Atomic for Inspect1 {
|
impl Atomic for Inspect1 {
|
||||||
atomic_defaults!();
|
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||||
fn run(&self, ctx: Context) -> crate::foreign::AtomicResult {
|
fn run(&self, ctx: Context) -> crate::foreign::AtomicResult {
|
||||||
println!("{}", self.expr_inst);
|
println!("{}", self.expr_inst);
|
||||||
Ok(AtomicReturn {
|
Ok(AtomicReturn {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use ordered_float::NotNan;
|
|||||||
|
|
||||||
use super::ArithmeticError;
|
use super::ArithmeticError;
|
||||||
use crate::foreign::ExternError;
|
use crate::foreign::ExternError;
|
||||||
|
use crate::interpreted::TryFromExprInst;
|
||||||
use crate::representations::interpreted::{Clause, ExprInst};
|
use crate::representations::interpreted::{Clause, ExprInst};
|
||||||
use crate::representations::{Literal, Primitive};
|
use crate::representations::{Literal, Primitive};
|
||||||
use crate::systems::cast_exprinst::with_lit;
|
use crate::systems::cast_exprinst::with_lit;
|
||||||
@@ -40,14 +41,12 @@ impl Numeric {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl TryFromExprInst for Numeric {
|
||||||
impl TryFrom<&ExprInst> for Numeric {
|
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||||
type Error = Rc<dyn ExternError>;
|
with_lit(exi, |l| match l {
|
||||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
|
||||||
with_lit(value, |l| match l {
|
|
||||||
Literal::Uint(i) => Ok(Numeric::Uint(*i)),
|
Literal::Uint(i) => Ok(Numeric::Uint(*i)),
|
||||||
Literal::Num(n) => Ok(Numeric::Num(*n)),
|
Literal::Num(n) => Ok(Numeric::Num(*n)),
|
||||||
_ => AssertionError::fail(value.clone(), "an integer or number")?,
|
_ => AssertionError::fail(exi.clone(), "an integer or number")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,17 @@ use std::cell::RefCell;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::foreign::cps_box::{const_cps, init_cps, CPSBox};
|
use crate::foreign::cps_box::{const_cps, init_cps, CPSBox};
|
||||||
use crate::foreign::Atomic;
|
use crate::foreign::{Atomic, InertAtomic};
|
||||||
use crate::interpreted::ExprInst;
|
use crate::interpreted::ExprInst;
|
||||||
use crate::interpreter::HandlerTable;
|
use crate::interpreter::HandlerTable;
|
||||||
use crate::systems::codegen::call;
|
use crate::systems::codegen::call;
|
||||||
use crate::{atomic_inert, define_fn, ConstTree, Interner};
|
use crate::{define_fn, ConstTree, Interner};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct State(Rc<RefCell<ExprInst>>);
|
pub struct State(Rc<RefCell<ExprInst>>);
|
||||||
atomic_inert!(State, typestr = "a state");
|
impl InertAtomic for State {
|
||||||
|
fn type_str() -> &'static str { "a stateful container" }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct NewStateCmd;
|
struct NewStateCmd;
|
||||||
@@ -21,8 +23,8 @@ struct SetStateCmd(State);
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct GetStateCmd(State);
|
struct GetStateCmd(State);
|
||||||
|
|
||||||
define_fn! { SetState = |x| Ok(init_cps(2, SetStateCmd(x.try_into()?))) }
|
define_fn! { SetState = |x| Ok(init_cps(2, SetStateCmd(x.downcast()?))) }
|
||||||
define_fn! { GetState = |x| Ok(init_cps(2, GetStateCmd(x.try_into()?))) }
|
define_fn! { GetState = |x| Ok(init_cps(2, GetStateCmd(x.downcast()?))) }
|
||||||
|
|
||||||
fn new_state_handler<E>(cmd: &CPSBox<NewStateCmd>) -> Result<ExprInst, E> {
|
fn new_state_handler<E>(cmd: &CPSBox<NewStateCmd>) -> Result<ExprInst, E> {
|
||||||
let (_, default, handler) = cmd.unpack2();
|
let (_, default, handler) = cmd.unpack2();
|
||||||
|
|||||||
@@ -6,13 +6,9 @@ use std::iter;
|
|||||||
/// initialized form multiple iterators of incompatible types
|
/// initialized form multiple iterators of incompatible types
|
||||||
pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
|
pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
|
||||||
/// creates a [BoxedIter] of a single element
|
/// creates a [BoxedIter] of a single element
|
||||||
pub fn box_once<'a, T: 'a>(t: T) -> BoxedIter<'a, T> {
|
pub fn box_once<'a, T: 'a>(t: T) -> BoxedIter<'a, T> { Box::new(iter::once(t)) }
|
||||||
Box::new(iter::once(t))
|
|
||||||
}
|
|
||||||
/// creates an empty [BoxedIter]
|
/// creates an empty [BoxedIter]
|
||||||
pub fn box_empty<'a, T: 'a>() -> BoxedIter<'a, T> {
|
pub fn box_empty<'a, T: 'a>() -> BoxedIter<'a, T> { Box::new(iter::empty()) }
|
||||||
Box::new(iter::empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Chain various iterators into a [BoxedIter]
|
/// Chain various iterators into a [BoxedIter]
|
||||||
macro_rules! box_chain {
|
macro_rules! box_chain {
|
||||||
|
|||||||
29
src/utils/ddispatch.rs
Normal file
29
src/utils/ddispatch.rs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
//! A variant of [std::any::Provider]
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
/// A request for a value of an unknown type
|
||||||
|
pub struct Request<'a>(&'a mut dyn Any);
|
||||||
|
impl<'a> Request<'a> {
|
||||||
|
pub fn can_serve<T: 'static>(&self) -> bool { self.0.is::<Option<T>>() }
|
||||||
|
|
||||||
|
pub fn serve<T: 'static>(&mut self, value: T) { self.serve_with(|| value) }
|
||||||
|
|
||||||
|
pub fn serve_with<T: 'static>(&mut self, provider: impl FnOnce() -> T) {
|
||||||
|
if let Some(slot) = self.0.downcast_mut() {
|
||||||
|
*slot = provider();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait for objects that can respond to type-erased commands. This trait is
|
||||||
|
/// a dependency of `Atomic` but the implementation can be left empty.
|
||||||
|
pub trait Responder {
|
||||||
|
fn respond(&self, _request: Request) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request<T: 'static>(responder: &(impl Responder + ?Sized)) -> Option<T> {
|
||||||
|
let mut slot = None;
|
||||||
|
responder.respond(Request(&mut slot));
|
||||||
|
slot
|
||||||
|
}
|
||||||
@@ -3,13 +3,9 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
pub struct DeleteCell<T>(pub Rc<RefCell<Option<T>>>);
|
pub struct DeleteCell<T>(pub Rc<RefCell<Option<T>>>);
|
||||||
impl<T> DeleteCell<T> {
|
impl<T> DeleteCell<T> {
|
||||||
pub fn new(t: T) -> Self {
|
pub fn new(t: T) -> Self { Self(Rc::new(RefCell::new(Some(t)))) }
|
||||||
Self(Rc::new(RefCell::new(Some(t))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take(&self) -> Option<T> {
|
pub fn take(&self) -> Option<T> { self.0.borrow_mut().take() }
|
||||||
self.0.borrow_mut().take()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone_out(&self) -> Option<T>
|
pub fn clone_out(&self) -> Option<T>
|
||||||
where
|
where
|
||||||
@@ -19,7 +15,5 @@ impl<T> DeleteCell<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T> Clone for DeleteCell<T> {
|
impl<T> Clone for DeleteCell<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { Self(self.0.clone()) }
|
||||||
Self(self.0.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,14 +14,10 @@ pub struct IdMap<T> {
|
|||||||
}
|
}
|
||||||
impl<T> IdMap<T> {
|
impl<T> IdMap<T> {
|
||||||
/// Create a new empty set
|
/// Create a new empty set
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Self { next_id: 0, data: HashMap::new() } }
|
||||||
Self { next_id: 0, data: HashMap::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Obtain a reference to the underlying map for iteration
|
/// Obtain a reference to the underlying map for iteration
|
||||||
pub fn map(&self) -> &HashMap<u64, T> {
|
pub fn map(&self) -> &HashMap<u64, T> { &self.data }
|
||||||
&self.data
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Insert an element with a new ID and return the ID
|
/// Insert an element with a new ID and return the ID
|
||||||
pub fn insert(&mut self, t: T) -> u64 {
|
pub fn insert(&mut self, t: T) -> u64 {
|
||||||
@@ -33,9 +29,7 @@ impl<T> IdMap<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Obtain a reference to the element with the given ID
|
/// Obtain a reference to the element with the given ID
|
||||||
pub fn get(&self, id: u64) -> Option<&T> {
|
pub fn get(&self, id: u64) -> Option<&T> { self.data.get(&id) }
|
||||||
self.data.get(&id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Obtain a mutable reference to the element with the given ID
|
/// Obtain a mutable reference to the element with the given ID
|
||||||
pub fn get_mut(&mut self, id: u64) -> Option<&mut T> {
|
pub fn get_mut(&mut self, id: u64) -> Option<&mut T> {
|
||||||
@@ -44,15 +38,11 @@ impl<T> IdMap<T> {
|
|||||||
|
|
||||||
/// Remove the element with the given ID from the set. The ID will not be
|
/// Remove the element with the given ID from the set. The ID will not be
|
||||||
/// reused.
|
/// reused.
|
||||||
pub fn remove(&mut self, id: u64) -> Option<T> {
|
pub fn remove(&mut self, id: u64) -> Option<T> { self.data.remove(&id) }
|
||||||
self.data.remove(&id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Default for IdMap<T> {
|
impl<T> Default for IdMap<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self { Self::new() }
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
mod cache;
|
mod cache;
|
||||||
|
pub mod ddispatch;
|
||||||
mod delete_cell;
|
mod delete_cell;
|
||||||
pub mod poller;
|
|
||||||
pub mod get_or;
|
pub mod get_or;
|
||||||
|
mod id_map;
|
||||||
mod iter_find;
|
mod iter_find;
|
||||||
pub mod never;
|
pub mod never;
|
||||||
|
pub mod poller;
|
||||||
pub mod pure_push;
|
pub mod pure_push;
|
||||||
pub mod rc_tools;
|
pub mod rc_tools;
|
||||||
mod replace_first;
|
mod replace_first;
|
||||||
@@ -14,7 +16,6 @@ pub mod substack;
|
|||||||
mod take_with_output;
|
mod take_with_output;
|
||||||
pub mod thread_pool;
|
pub mod thread_pool;
|
||||||
mod unwrap_or;
|
mod unwrap_or;
|
||||||
mod id_map;
|
|
||||||
|
|
||||||
pub use cache::Cache;
|
pub use cache::Cache;
|
||||||
pub use replace_first::replace_first;
|
pub use replace_first::replace_first;
|
||||||
@@ -22,9 +23,9 @@ pub use side::Side;
|
|||||||
pub use split_max_prefix::split_max_prefix;
|
pub use split_max_prefix::split_max_prefix;
|
||||||
pub(crate) use unwrap_or::unwrap_or;
|
pub(crate) use unwrap_or::unwrap_or;
|
||||||
pub mod boxed_iter;
|
pub mod boxed_iter;
|
||||||
pub use delete_cell::DeleteCell;
|
|
||||||
pub use boxed_iter::BoxedIter;
|
pub use boxed_iter::BoxedIter;
|
||||||
|
pub use delete_cell::DeleteCell;
|
||||||
|
pub use id_map::IdMap;
|
||||||
pub use iter_find::iter_find;
|
pub use iter_find::iter_find;
|
||||||
pub use string_from_charset::string_from_charset;
|
pub use string_from_charset::string_from_charset;
|
||||||
pub use take_with_output::take_with_output;
|
pub use take_with_output::take_with_output;
|
||||||
pub use id_map::IdMap;
|
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ pub enum Never {}
|
|||||||
pub type Always<T> = Result<T, Never>;
|
pub type Always<T> = Result<T, Never>;
|
||||||
|
|
||||||
/// Wrap value in a result with an impossible failure mode
|
/// Wrap value in a result with an impossible failure mode
|
||||||
pub fn always<T>(t: T) -> Result<T, Never> {
|
pub fn always<T>(t: T) -> Result<T, Never> { Ok(t) }
|
||||||
Ok(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Take success value out of a result with an impossible failure mode
|
/// Take success value out of a result with an impossible failure mode
|
||||||
pub fn unwrap_always<T>(result: Result<T, Never>) -> T {
|
pub fn unwrap_always<T>(result: Result<T, Never>) -> T {
|
||||||
|
|||||||
@@ -37,9 +37,7 @@ impl<TOnce, TRec> Clone for Timer<TOnce, TRec> {
|
|||||||
}
|
}
|
||||||
impl<TOnce, TRec> Eq for Timer<TOnce, TRec> {}
|
impl<TOnce, TRec> Eq for Timer<TOnce, TRec> {}
|
||||||
impl<TOnce, TRec> PartialEq for Timer<TOnce, TRec> {
|
impl<TOnce, TRec> PartialEq for Timer<TOnce, TRec> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool { self.expires.eq(&other.expires) }
|
||||||
self.expires.eq(&other.expires)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<TOnce, TRec> PartialOrd for Timer<TOnce, TRec> {
|
impl<TOnce, TRec> PartialOrd for Timer<TOnce, TRec> {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
|||||||
@@ -31,9 +31,7 @@ impl Side {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Shorthand for opposite
|
/// Shorthand for opposite
|
||||||
pub fn inv(&self) -> Self {
|
pub fn inv(&self) -> Self { self.opposite() }
|
||||||
self.opposite()
|
|
||||||
}
|
|
||||||
/// take N elements from this end of a slice
|
/// take N elements from this end of a slice
|
||||||
pub fn slice<'a, T>(&self, size: usize, slice: &'a [T]) -> &'a [T] {
|
pub fn slice<'a, T>(&self, size: usize, slice: &'a [T]) -> &'a [T] {
|
||||||
match self {
|
match self {
|
||||||
@@ -85,9 +83,7 @@ impl Side {
|
|||||||
impl Not for Side {
|
impl Not for Side {
|
||||||
type Output = Side;
|
type Output = Side;
|
||||||
|
|
||||||
fn not(self) -> Self::Output {
|
fn not(self) -> Self::Output { self.opposite() }
|
||||||
self.opposite()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -32,13 +32,9 @@ impl<'a, T> Substack<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Construct an iterator over the listlike, very fast O(1)
|
/// Construct an iterator over the listlike, very fast O(1)
|
||||||
pub fn iter(&self) -> SubstackIterator<T> {
|
pub fn iter(&self) -> SubstackIterator<T> { SubstackIterator { curr: self } }
|
||||||
SubstackIterator { curr: self }
|
|
||||||
}
|
|
||||||
/// Add the item to this substack
|
/// Add the item to this substack
|
||||||
pub fn push(&'a self, item: T) -> Self {
|
pub fn push(&'a self, item: T) -> Self { Self::Frame(self.new_frame(item)) }
|
||||||
Self::Frame(self.new_frame(item))
|
|
||||||
}
|
|
||||||
/// Create a new frame on top of this substack
|
/// Create a new frame on top of this substack
|
||||||
pub fn new_frame(&'a self, item: T) -> Stackframe<'a, T> {
|
pub fn new_frame(&'a self, item: T) -> Stackframe<'a, T> {
|
||||||
Stackframe { item, prev: self, len: self.opt().map_or(1, |s| s.len + 1) }
|
Stackframe { item, prev: self, len: self.opt().map_or(1, |s| s.len + 1) }
|
||||||
@@ -61,9 +57,7 @@ impl<'a, T> Substack<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// is this the bottom of the stack
|
/// is this the bottom of the stack
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||||
self.len() == 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Debug> Debug for Substack<'a, T> {
|
impl<'a, T: Debug> Debug for Substack<'a, T> {
|
||||||
@@ -104,9 +98,7 @@ impl<'a, T> SubstackIterator<'a, T> {
|
|||||||
|
|
||||||
impl<'a, T> Copy for SubstackIterator<'a, T> {}
|
impl<'a, T> Copy for SubstackIterator<'a, T> {}
|
||||||
impl<'a, T> Clone for SubstackIterator<'a, T> {
|
impl<'a, T> Clone for SubstackIterator<'a, T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { Self { curr: self.curr } }
|
||||||
Self { curr: self.curr }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Iterator for SubstackIterator<'a, T> {
|
impl<'a, T> Iterator for SubstackIterator<'a, T> {
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ pub trait Task: Send + 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<F: FnOnce() + Send + 'static> Task for F {
|
impl<F: FnOnce() + Send + 'static> Task for F {
|
||||||
fn run(self) {
|
fn run(self) { self() }
|
||||||
self()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An async unit of work that produces some result, see [Task]. This can be
|
/// An async unit of work that produces some result, see [Task]. This can be
|
||||||
@@ -49,9 +47,7 @@ pub trait Query: Send + 'static {
|
|||||||
impl<F: FnOnce() -> R + Send + 'static, R: Send + 'static> Query for F {
|
impl<F: FnOnce() -> R + Send + 'static, R: Send + 'static> Query for F {
|
||||||
type Result = R;
|
type Result = R;
|
||||||
|
|
||||||
fn run(self) -> Self::Result {
|
fn run(self) -> Self::Result { self() }
|
||||||
self()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A reporter that calls a statically known function with the result of a
|
/// A reporter that calls a statically known function with the result of a
|
||||||
@@ -61,9 +57,7 @@ pub struct QueryTask<Q: Query, F: FnOnce(Q::Result) + Send + 'static> {
|
|||||||
callback: F,
|
callback: F,
|
||||||
}
|
}
|
||||||
impl<Q: Query, F: FnOnce(Q::Result) + Send + 'static> Task for QueryTask<Q, F> {
|
impl<Q: Query, F: FnOnce(Q::Result) + Send + 'static> Task for QueryTask<Q, F> {
|
||||||
fn run(self) {
|
fn run(self) { (self.callback)(self.query.run()) }
|
||||||
(self.callback)(self.query.run())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Message<T: Task> {
|
enum Message<T: Task> {
|
||||||
@@ -91,9 +85,7 @@ struct ThreadPoolData<T: Task> {
|
|||||||
///
|
///
|
||||||
/// struct MyTask(&'static str);
|
/// struct MyTask(&'static str);
|
||||||
/// impl Task for MyTask {
|
/// impl Task for MyTask {
|
||||||
/// fn run(self) {
|
/// fn run(self) { println!("{}", self.0) }
|
||||||
/// println!("{}", self.0)
|
|
||||||
/// }
|
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let pool = ThreadPool::new();
|
/// let pool = ThreadPool::new();
|
||||||
@@ -167,9 +159,7 @@ impl<T: Task> ThreadPool<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Task> Default for ThreadPool<T> {
|
impl<T: Task> Default for ThreadPool<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self { Self::new() }
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Task> Drop for ThreadPool<T> {
|
impl<T: Task> Drop for ThreadPool<T> {
|
||||||
|
|||||||
Reference in New Issue
Block a user