use crate::{obj::{reserved::*, prelude::*}, vm::{inst::Inst, signal::*, Vm}}; use once_cell::sync::Lazy; use shredder::{GcSafeWrapper, Scan}; use std::fmt::{Debug, Formatter, self}; // // struct UserFun // pub type UserFunRef = ObjRef; #[derive(Scan)] pub struct UserFun { vtable: Vtable, attrs: Attrs, // Safe because Vec doesn't need to be scanned #[shredder(unsafe_skip)] code: Vec, // Safe because this is just an interner that points to symbols, which aren't GC'd #[shredder(unsafe_skip)] locals: Locals, } impl UserFun { pub fn new_obj(code: Vec, locals: Locals) -> UserFunRef { 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 } pub fn code(&self) -> &Vec { &self.code } pub fn locals(&self) -> &Locals { &self.locals } } impl_obj!(UserFun); 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() } } pub static USER_FUN_TY: Lazy> = Lazy::new(|| Ty::new_obj(USER_FUN_NAME.sym_ref())); // // struct NativeFun // pub type NativeFunPtr = Box) -> Signal) + Send + Sync>; pub type NativeFunRef = ObjRef; #[derive(Scan)] pub struct NativeFun { vtable: Vtable, attrs: Attrs, #[shredder(skip)] fun: GcSafeWrapper, } // // impl NativeFun // impl NativeFun { pub fn new_obj(fun: NativeFunPtr) -> ObjRef { let obj_ref = ObjRef::new(Self { vtable: Default::default(), attrs: Default::default(), fun: GcSafeWrapper::new(fun), }); // 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 } } // // 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() } } impl_obj!(NativeFun); pub static NATIVE_FUN_TY: Lazy> = Lazy::new(|| Ty::new_obj(NATIVE_FUN_NAME.sym_ref())); // // 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> = Lazy::new(|| { NativeFun::new_obj(Box::new(|_caller, _vm, _args| { /* let sym_ref = vm.pop(); let obj_ref = vm.pop(); obj_ref.access() */ todo!("__get_attr__ function") })) });