2020-09-24 15:29:44 -07:00
|
|
|
use crate::{obj::{reserved::*, prelude::*}, vm::{inst::Inst, signal::*, Vm}};
|
2020-09-01 17:32:48 -07:00
|
|
|
use once_cell::sync::Lazy;
|
|
|
|
|
use shredder::{GcSafeWrapper, Scan};
|
|
|
|
|
use std::fmt::{Debug, Formatter, self};
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// struct UserFun
|
|
|
|
|
//
|
2020-09-14 16:32:00 -07:00
|
|
|
|
|
|
|
|
pub type UserFunRef = ObjRef<UserFun>;
|
|
|
|
|
|
2020-09-01 17:32:48 -07:00
|
|
|
#[derive(Scan)]
|
|
|
|
|
pub struct UserFun {
|
2020-09-14 14:09:29 -07:00
|
|
|
vtable: Vtable,
|
2020-09-01 17:32:48 -07:00
|
|
|
attrs: Attrs,
|
|
|
|
|
// Safe because Vec<Inst> doesn't need to be scanned
|
|
|
|
|
#[shredder(unsafe_skip)]
|
|
|
|
|
code: Vec<Inst>,
|
|
|
|
|
// Safe because this is just an interner that points to symbols, which aren't GC'd
|
|
|
|
|
#[shredder(unsafe_skip)]
|
2020-09-26 18:31:23 -07:00
|
|
|
locals: Locals,
|
2020-09-01 17:32:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl UserFun {
|
2020-09-26 18:31:23 -07:00
|
|
|
pub fn new_obj(code: Vec<Inst>, locals: Locals) -> UserFunRef {
|
2020-09-24 15:29:44 -07:00
|
|
|
let obj_ref = ObjRef::new(UserFun {
|
|
|
|
|
vtable: Default::default(), // this is a placeholder for the real vtable
|
|
|
|
|
attrs: Default::default(),
|
|
|
|
|
code,
|
|
|
|
|
locals,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// XXX replace the vtable before returning, since __call__ member points to the object
|
|
|
|
|
// itself
|
|
|
|
|
{
|
|
|
|
|
write_obj!(let obj = obj_ref);
|
|
|
|
|
obj.vtable = vtable! {
|
|
|
|
|
TY_MEMBER_NAME.sym => USER_FUN_TY.clone(),
|
|
|
|
|
CALL_MEMBER_NAME.sym => obj_ref.clone(),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj_ref
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-01 17:32:48 -07:00
|
|
|
pub fn code(&self) -> &Vec<Inst> {
|
|
|
|
|
&self.code
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-26 18:31:23 -07:00
|
|
|
pub fn locals(&self) -> &Locals {
|
2020-09-01 17:32:48 -07:00
|
|
|
&self.locals
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 14:09:29 -07:00
|
|
|
impl_obj!(UserFun);
|
2020-09-01 17:32:48 -07:00
|
|
|
|
|
|
|
|
impl Debug for UserFun {
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
|
|
|
|
fmt.debug_struct("UserFun")
|
|
|
|
|
.field("attrs", &self.attrs)
|
|
|
|
|
.field("code", &self.code)
|
|
|
|
|
.field("locals", &self.locals)
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 15:29:44 -07:00
|
|
|
pub static USER_FUN_TY: Lazy<ObjRef<Ty>> = Lazy::new(|| Ty::new_obj(USER_FUN_NAME.sym_ref()));
|
|
|
|
|
|
2020-09-01 17:32:48 -07:00
|
|
|
//
|
|
|
|
|
// struct NativeFun
|
|
|
|
|
//
|
|
|
|
|
|
2020-09-24 15:29:44 -07:00
|
|
|
pub type NativeFunPtr = Box<dyn (Fn(ObjRef, &mut Vm, Vec<ObjRef>) -> Signal) + Send + Sync>;
|
|
|
|
|
pub type NativeFunRef = ObjRef<NativeFun>;
|
2020-09-14 14:09:29 -07:00
|
|
|
|
2020-09-01 17:32:48 -07:00
|
|
|
#[derive(Scan)]
|
|
|
|
|
pub struct NativeFun {
|
2020-09-14 14:09:29 -07:00
|
|
|
vtable: Vtable,
|
2020-09-01 17:32:48 -07:00
|
|
|
attrs: Attrs,
|
2020-09-14 14:09:29 -07:00
|
|
|
#[shredder(skip)]
|
|
|
|
|
fun: GcSafeWrapper<NativeFunPtr>,
|
2020-09-01 17:32:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// impl NativeFun
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
impl NativeFun {
|
2020-09-14 14:09:29 -07:00
|
|
|
pub fn new_obj(fun: NativeFunPtr) -> ObjRef<Self> {
|
2020-09-24 15:29:44 -07:00
|
|
|
let obj_ref = ObjRef::new(Self {
|
2020-09-14 14:09:29 -07:00
|
|
|
vtable: Default::default(),
|
2020-09-01 17:32:48 -07:00
|
|
|
attrs: Default::default(),
|
2020-09-14 14:09:29 -07:00
|
|
|
fun: GcSafeWrapper::new(fun),
|
2020-09-24 15:29:44 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// XXX replace the vtable before returning, since __call__ member points to the object
|
|
|
|
|
// itself
|
|
|
|
|
{
|
|
|
|
|
write_obj!(let obj = obj_ref);
|
|
|
|
|
obj.vtable = vtable! {
|
|
|
|
|
TY_MEMBER_NAME.sym => NATIVE_FUN_TY.clone(),
|
|
|
|
|
CALL_MEMBER_NAME.sym => obj_ref.clone(),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj_ref
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets the native function that can be invoked.
|
|
|
|
|
pub fn fun(&self) -> &NativeFunPtr {
|
|
|
|
|
&self.fun
|
2020-09-01 17:32:48 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// impl Debug for NativeFun
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
impl Debug for NativeFun {
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
|
|
|
|
fmt.debug_struct("NativeFun")
|
|
|
|
|
.field("fun", &format!("(function at {:x})", &self.fun as *const _ as usize))
|
|
|
|
|
.field("attrs", &self.attrs)
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 14:09:29 -07:00
|
|
|
impl_obj!(NativeFun);
|
2020-09-01 17:32:48 -07:00
|
|
|
|
2020-09-24 15:29:44 -07:00
|
|
|
pub static NATIVE_FUN_TY: Lazy<ObjRef<Ty>> = Lazy::new(|| Ty::new_obj(NATIVE_FUN_NAME.sym_ref()));
|
|
|
|
|
|
2020-09-01 17:32:48 -07:00
|
|
|
//
|
|
|
|
|
// Native function defs
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// __access__ is what the "dot" operator calls
|
|
|
|
|
// __get_attr__ *should* always bypass the __access__ function and get an attribute directly
|
|
|
|
|
|
|
|
|
|
pub static GET_ATTR_MEMBER_FUN: Lazy<ObjRef<NativeFun>> = Lazy::new(|| {
|
2020-09-24 15:29:44 -07:00
|
|
|
NativeFun::new_obj(Box::new(|_caller, _vm, _args| {
|
2020-09-01 17:32:48 -07:00
|
|
|
/*
|
|
|
|
|
let sym_ref = vm.pop();
|
|
|
|
|
let obj_ref = vm.pop();
|
|
|
|
|
obj_ref.access()
|
|
|
|
|
*/
|
|
|
|
|
todo!("__get_attr__ function")
|
|
|
|
|
}))
|
|
|
|
|
});
|