128 lines
3.0 KiB
Rust
128 lines
3.0 KiB
Rust
use std::{
|
|
any::Any,
|
|
fmt,
|
|
hash::{Hash, Hasher},
|
|
rc::Rc,
|
|
};
|
|
|
|
use crate::{
|
|
error::MachineError,
|
|
vm::{
|
|
env::Environment,
|
|
machine::Machine,
|
|
value::{IdentifierValue, StringValue, Value},
|
|
},
|
|
};
|
|
|
|
pub trait NativeObject: Any + fmt::Debug + fmt::Display {
|
|
fn as_any(&self) -> &dyn Any;
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct NativeValue(Rc<dyn NativeObject>);
|
|
|
|
pub type NativeFunctionImpl =
|
|
Rc<dyn Fn(&mut Machine, &Rc<Environment>, &[Value]) -> Result<Value, MachineError> + 'static>;
|
|
|
|
#[derive(Clone)]
|
|
pub struct NativeFunction {
|
|
name: IdentifierValue,
|
|
inner: NativeFunctionImpl,
|
|
docstring: StringValue,
|
|
}
|
|
|
|
impl NativeFunction {
|
|
pub fn new<S, D, F>(name: S, docstring: D, function: F) -> Self
|
|
where
|
|
S: Into<IdentifierValue>,
|
|
D: Into<StringValue>,
|
|
F: Fn(&mut Machine, &Rc<Environment>, &[Value]) -> Result<Value, MachineError> + 'static,
|
|
{
|
|
Self {
|
|
name: name.into(),
|
|
docstring: docstring.into(),
|
|
inner: Rc::new(function),
|
|
}
|
|
}
|
|
|
|
pub fn name(&self) -> &IdentifierValue {
|
|
&self.name
|
|
}
|
|
|
|
pub fn docstring(&self) -> &StringValue {
|
|
&self.docstring
|
|
}
|
|
|
|
pub fn invoke(
|
|
&self,
|
|
machine: &mut Machine,
|
|
environment: &Rc<Environment>,
|
|
arguments: &[Value],
|
|
) -> Result<Value, MachineError> {
|
|
(self.inner)(machine, environment, arguments)
|
|
}
|
|
}
|
|
|
|
impl Hash for NativeFunction {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.name.hash(state);
|
|
(&raw const *self.inner.as_ref()).addr().hash(state);
|
|
}
|
|
}
|
|
|
|
impl PartialEq for NativeFunction {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.name == other.name && Rc::ptr_eq(&self.inner, &other.inner)
|
|
}
|
|
}
|
|
|
|
impl Eq for NativeFunction {}
|
|
|
|
impl fmt::Debug for NativeFunction {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("NativeFunction")
|
|
.field("name", &self.name)
|
|
.field_with("inner", |f| write!(f, "{:p}", self.inner))
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for NativeFunction {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(
|
|
f,
|
|
"<native {}@{:#x}>",
|
|
self.name,
|
|
(&raw const *self.inner.as_ref()).addr()
|
|
)
|
|
}
|
|
}
|
|
|
|
impl NativeValue {
|
|
pub fn cast_rc<T: NativeObject>(&self) -> Option<Rc<T>> {
|
|
Rc::downcast(self.0.clone()).ok()
|
|
}
|
|
|
|
pub fn cast_ref<T: NativeObject>(&self) -> Option<&T> {
|
|
self.0.as_any().downcast_ref()
|
|
}
|
|
}
|
|
|
|
impl From<Rc<dyn NativeObject + 'static>> for NativeValue {
|
|
fn from(value: Rc<dyn NativeObject>) -> Self {
|
|
Self(value)
|
|
}
|
|
}
|
|
|
|
impl PartialEq for NativeValue {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
Rc::ptr_eq(&self.0, &other.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for NativeValue {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "<native {}>", self.0)
|
|
}
|
|
}
|