112 lines
2.5 KiB
Rust
112 lines
2.5 KiB
Rust
|
|
use crate::{obj::{names::*, prelude::*}, vm::{inst::Inst, Vm}};
|
||
|
|
use once_cell::sync::Lazy;
|
||
|
|
use shredder::{GcSafeWrapper, Scan};
|
||
|
|
use std::fmt::{Debug, Formatter, self};
|
||
|
|
|
||
|
|
//
|
||
|
|
// struct UserFun
|
||
|
|
//
|
||
|
|
#[derive(Scan)]
|
||
|
|
pub struct UserFun {
|
||
|
|
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)]
|
||
|
|
locals: Locals,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl UserFun {
|
||
|
|
pub fn code(&self) -> &Vec<Inst> {
|
||
|
|
&self.code
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn locals(&self) -> &Locals {
|
||
|
|
&self.locals
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl_obj!(UserFun, attrs);
|
||
|
|
|
||
|
|
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()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// struct NativeFun
|
||
|
|
//
|
||
|
|
|
||
|
|
#[derive(Scan)]
|
||
|
|
pub struct NativeFun {
|
||
|
|
#[shredder(skip)]
|
||
|
|
fun: GcSafeWrapper<Box<dyn Fn(&mut Vm) + Send + Sync>>,
|
||
|
|
attrs: Attrs,
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// impl NativeFun
|
||
|
|
//
|
||
|
|
|
||
|
|
impl NativeFun {
|
||
|
|
pub fn new(fun: Box<dyn Fn(&mut Vm) + Send + Sync>) -> ObjRef<Self> {
|
||
|
|
let obj_ref = ObjRef::new(Self {
|
||
|
|
fun: GcSafeWrapper::new(fun),
|
||
|
|
attrs: Default::default(),
|
||
|
|
});
|
||
|
|
|
||
|
|
{
|
||
|
|
write_obj!(let obj = obj_ref);
|
||
|
|
obj.set_attr(*CALL_MEMBER_SYM, obj_ref.clone());
|
||
|
|
obj.set_attr(*GET_ATTR_MEMBER_SYM, GET_ATTR_MEMBER_FUN.clone());
|
||
|
|
}
|
||
|
|
|
||
|
|
obj_ref
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn call(&self, vm: &mut Vm) {
|
||
|
|
(self.fun)(vm)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//
|
||
|
|
// 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, attrs);
|
||
|
|
|
||
|
|
//
|
||
|
|
// 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(|| {
|
||
|
|
NativeFun::new(Box::new(|_vm| {
|
||
|
|
/*
|
||
|
|
* TODO - need SymObj or something like that, which can be used as an ObjRef - since that's
|
||
|
|
* all we'll have access to at runtime anyway
|
||
|
|
let sym_ref = vm.pop();
|
||
|
|
let obj_ref = vm.pop();
|
||
|
|
obj_ref.access()
|
||
|
|
*/
|
||
|
|
todo!("__get_attr__ function")
|
||
|
|
}))
|
||
|
|
});
|