use std::{
cmp::Ordering,
fmt::{self, Debug},
hash::{Hash, Hasher},
};
use gc::{Gc, GcCell, Finalize, Trace};
use crate::symbol;
use super::{
mem,
program,
Panic,
Runtime,
SourcePos,
Value,
};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Trace, Finalize)]
pub enum Function {
Hush(HushFun),
Rust(RustFun),
}
impl Function {
pub fn copy(&self) -> Self {
match self {
Function::Hush(fun) => Function::Hush(fun.copy()),
Function::Rust(fun) => Function::Rust(fun.copy()),
}
}
}
impl From<HushFun> for Function {
fn from(fun: HushFun) -> Self {
Self::Hush(fun)
}
}
impl From<RustFun> for Function {
fn from(fun: RustFun) -> Self {
Self::Rust(fun)
}
}
impl<T: NativeFun> From<T> for Function {
fn from(fun: T) -> Self {
Self::Rust(fun.into())
}
}
#[derive(Debug)]
#[derive(Trace, Finalize)]
pub struct HushFun {
pub params: u32,
pub frame_info: &'static program::mem::FrameInfo,
pub body: &'static program::Block,
#[allow(clippy::type_complexity)]
pub context: Gc<Box<[(Gc<GcCell<Value>>, mem::SlotIx)]>>,
pub pos: SourcePos,
}
impl HushFun {
pub fn new (
params: u32,
frame_info: &'static program::mem::FrameInfo,
body: &'static program::Block,
context: Box<[(Gc<GcCell<Value>>, mem::SlotIx)]>,
pos: SourcePos,
) -> Self {
Self {
params,
frame_info,
body,
context: Gc::new(context),
pos,
}
}
pub fn copy(&self) -> Self {
Self {
params: self.params,
frame_info: self.frame_info,
body: self.body,
context: self.context.clone(),
pos: self.pos.copy(),
}
}
}
impl PartialEq for HushFun {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.body, other.body)
&& self.context == other.context
}
}
impl Eq for HushFun { }
impl PartialOrd for HushFun {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for HushFun {
fn cmp(&self, other: &Self) -> Ordering {
self.pos.cmp(&other.pos)
}
}
impl Hash for HushFun {
fn hash<H: Hasher>(&self, state: &mut H) {
self.pos.hash(state)
}
}
#[derive(Debug)]
pub struct CallContext<'a> {
pub runtime: &'a mut Runtime,
pub obj: Value,
pub args_start: usize,
pub pos: SourcePos,
}
impl<'a> CallContext<'a> {
pub fn args(&self) -> &[Value] {
&self.runtime.arguments[self.args_start..]
}
pub fn args_mut(&mut self) -> &mut [Value] {
&mut self.runtime.arguments[self.args_start..]
}
pub fn interner(&self) -> & symbol::Interner {
&self.runtime.interner
}
pub fn call(
&mut self,
obj: Value,
function: &Function,
args_start: usize,
) -> Result<Value, Panic> {
self.runtime.call(obj, function, args_start, self.pos.copy())
}
}
pub trait NativeFun: Trace + Finalize + 'static {
fn name(&self) -> &'static str;
fn call(&self, context: CallContext) -> Result<Value, Panic>;
}
#[derive(Trace, Finalize)]
pub struct RustFun(Gc<Box<dyn NativeFun>>);
impl RustFun {
pub fn copy(&self) -> Self {
Self(self.0.clone())
}
pub fn name(&self) -> &'static str {
self.0.name()
}
pub fn call(&self, context: CallContext) -> Result<Value, Panic> {
self.0.call(context)
}
}
impl Debug for RustFun {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl<T: NativeFun> From<T> for RustFun {
fn from(fun: T) -> Self {
Self(Gc::new(Box::new(fun)))
}
}
impl PartialEq for RustFun {
fn eq(&self, other: &Self) -> bool {
self.name() == other.name()
}
}
impl Eq for RustFun { }
impl PartialOrd for RustFun {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.name().partial_cmp(other.name())
}
}
impl Ord for RustFun {
fn cmp(&self, other: &Self) -> Ordering {
self.name().cmp(other.name())
}
}
impl Hash for RustFun {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name().hash(state);
}
}