forked from Orchid/orchid
Dead end with macros
This commit is contained in:
@@ -1,75 +1,59 @@
|
||||
use std::any::Any;
|
||||
use std::fmt::{Display, Debug};
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
use mappable_rc::Mrc;
|
||||
use dyn_clone::DynClone;
|
||||
|
||||
use crate::representations::typed::{Expr, Clause};
|
||||
use crate::representations::interpreted::{Clause, RuntimeError, InternalError};
|
||||
|
||||
pub trait ExternError: Display {}
|
||||
|
||||
/// Represents an externally defined function from the perspective of the executor
|
||||
/// Since Orchid lacks basic numerical operations, these are also external functions.
|
||||
pub struct ExternFn {
|
||||
name: String, param: Mrc<Expr>, rttype: Mrc<Expr>,
|
||||
function: Mrc<dyn Fn(Clause) -> Result<Clause, Mrc<dyn ExternError>>>
|
||||
pub trait ExternFn: DynClone {
|
||||
fn name(&self) -> &str;
|
||||
fn apply(&self, arg: Clause) -> Result<Clause, Rc<dyn ExternError>>;
|
||||
fn argstr(&self) -> &str { "clause" }
|
||||
fn retstr(&self) -> &str { "clause" }
|
||||
fn hash(&self, state: &mut dyn std::hash::Hasher) { state.write_str(self.name()) }
|
||||
}
|
||||
|
||||
impl ExternFn {
|
||||
pub fn new<F: 'static + Fn(Clause) -> Result<Clause, Mrc<dyn ExternError>>>(
|
||||
name: String, param: Mrc<Expr>, rttype: Mrc<Expr>, f: F
|
||||
) -> Self {
|
||||
Self {
|
||||
name, param, rttype,
|
||||
function: Mrc::map(Mrc::new(f), |f| {
|
||||
f as &dyn Fn(Clause) -> Result<Clause, Mrc<dyn ExternError>>
|
||||
})
|
||||
}
|
||||
}
|
||||
pub fn name(&self) -> &str {&self.name}
|
||||
pub fn apply(&self, arg: Clause) -> Result<Clause, Mrc<dyn ExternError>> {(self.function)(arg)}
|
||||
}
|
||||
|
||||
impl Clone for ExternFn { fn clone(&self) -> Self { Self {
|
||||
name: self.name.clone(),
|
||||
param: Mrc::clone(&self.param),
|
||||
rttype: Mrc::clone(&self.rttype),
|
||||
function: Mrc::clone(&self.function)
|
||||
}}}
|
||||
impl Eq for ExternFn {}
|
||||
impl PartialEq for ExternFn {
|
||||
impl Eq for dyn ExternFn {}
|
||||
impl PartialEq for dyn ExternFn {
|
||||
fn eq(&self, other: &Self) -> bool { self.name() == other.name() }
|
||||
}
|
||||
impl Hash for ExternFn {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.name.hash(state) }
|
||||
impl Hash for dyn ExternFn {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.name().hash(state) }
|
||||
}
|
||||
impl Debug for ExternFn {
|
||||
impl Debug for dyn ExternFn {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "##EXTERN[{}]:{:?} -> {:?}##", self.name(), self.param, self.rttype)
|
||||
write!(f, "##EXTERN[{}]:{:?} -> {:?}##", self.name(), self.argstr(), self.retstr())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Atomic: Any + Debug where Self: 'static {
|
||||
pub trait Atomic: Any + Debug + DynClone where Self: 'static {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn definitely_eq(&self, _other: &dyn Any) -> bool;
|
||||
fn hash(&self, hasher: &mut dyn std::hash::Hasher);
|
||||
fn run_once(&self) -> Result<Clause, InternalError>;
|
||||
fn run_n_times(&self, n: usize) -> Result<(Clause, usize), RuntimeError>;
|
||||
fn run_to_completion(&self) -> Result<Clause, RuntimeError>;
|
||||
fn typestr(&self) -> &str { "clause" }
|
||||
}
|
||||
|
||||
/// Represents a unit of information from the perspective of the executor. This may be
|
||||
/// something like a file descriptor which functions can operate on, but it can also be
|
||||
/// information in the universe of types or kinds such as the type of signed integers or
|
||||
/// the kind of types. Ad absurdum it can also be just a number, although Literal is
|
||||
/// preferable for types it's defined on.
|
||||
pub struct Atom {
|
||||
typ: Mrc<Expr>,
|
||||
data: Mrc<dyn Atomic>
|
||||
}
|
||||
/// Represents a black box unit of code with its own normalization steps. Typically [ExternFn]
|
||||
/// will produce an [Atom] when applied to a [Clause], this [Atom] will then forward `run_*` calls
|
||||
/// to the argument until it yields [InternalError::NonReducible] at which point the [Atom] will
|
||||
/// validate and process the argument, returning a different [Atom] intended for processing by
|
||||
/// external code, a new [ExternFn] to capture an additional argument, or an Orchid expression
|
||||
/// to pass control back to the interpreter.
|
||||
pub struct Atom(pub Box<dyn Atomic>);
|
||||
impl Atom {
|
||||
pub fn new<T: 'static + Atomic>(data: T, typ: Mrc<Expr>) -> Self { Self{
|
||||
typ,
|
||||
data: Mrc::map(Mrc::new(data), |d| d as &dyn Atomic)
|
||||
} }
|
||||
pub fn data(&self) -> &dyn Atomic { self.data.as_ref() as &dyn Atomic }
|
||||
pub fn new<T: 'static + Atomic>(data: T) -> Self {
|
||||
Self(Box::new(data) as Box<dyn Atomic>)
|
||||
}
|
||||
pub fn data(&self) -> &dyn Atomic { self.0.as_ref() as &dyn Atomic }
|
||||
pub fn try_cast<T: Atomic>(&self) -> Result<&T, ()> {
|
||||
self.data().as_any().downcast_ref().ok_or(())
|
||||
}
|
||||
@@ -80,20 +64,19 @@ impl Atom {
|
||||
}
|
||||
|
||||
impl Clone for Atom {
|
||||
fn clone(&self) -> Self { Self {
|
||||
typ: Mrc::clone(&self.typ),
|
||||
data: Mrc::clone(&self.data)
|
||||
} }
|
||||
fn clone(&self) -> Self {
|
||||
Self(dyn_clone::clone_box(self.data()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Atom {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.data.hash(state);
|
||||
self.typ.hash(state)
|
||||
self.0.hash(state)
|
||||
}
|
||||
}
|
||||
impl Debug for Atom {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "##ATOM[{:?}]:{:?}##", self.data(), self.typ)
|
||||
write!(f, "##ATOM[{:?}]:{:?}##", self.data(), self.data().typestr())
|
||||
}
|
||||
}
|
||||
impl Eq for Atom {}
|
||||
|
||||
Reference in New Issue
Block a user