Functions are implemented and VM should be able to handle function calls

* VM Signals are used by running functions to dictate whether a function
  should return, or if it should call another function. These signals
  can be injected at any time allowing for user functions to inject
  themselves at runtime.
* obj::Method is gone since it's not being used yet.
* Obj impls must implement as_any(&self) -> &dyn Any now. This allows
  for UserFun and NativeFun to be explicitly cast (among other things,
  in the future).

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-09-24 15:29:44 -07:00
parent f0032afe12
commit 3976b2135a
11 changed files with 236 additions and 71 deletions

View File

@@ -1,34 +1,8 @@
use crate::{obj::{reserved::*, prelude::*}, vm::{inst::Inst, Vm}};
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};
#[derive(Debug, Scan)]
pub struct Method {
vtable: Vtable,
attrs: Attrs,
}
impl Method {
pub fn new(this: ObjRef, func: ObjRef) -> Self {
Self {
vtable: Default::default(),
attrs: attrs! {
SELF_MEMBER_NAME.sym => this,
FUNC_MEMBER_NAME.sym => func,
}
}
}
}
impl_obj!(Method);
pub static CALL_METHOD_WRAPPER_FUN: Lazy<ObjRef<NativeFun>> = Lazy::new(|| {
NativeFun::new_obj(Box::new(|_vm, _fun, _args| {
todo!("__call__ function")
}))
});
//
// struct UserFun
//
@@ -48,6 +22,27 @@ pub struct UserFun {
}
impl UserFun {
pub fn new_obj(code: Vec<Inst>, locals: Names) -> 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<Inst> {
&self.code
}
@@ -69,11 +64,14 @@ impl Debug for UserFun {
}
}
pub static USER_FUN_TY: Lazy<ObjRef<Ty>> = Lazy::new(|| Ty::new_obj(USER_FUN_NAME.sym_ref()));
//
// struct NativeFun
//
pub type NativeFunPtr = Box<dyn Fn(&mut Vm, ObjRef, Vec<ObjRef>) + Send + Sync>;
pub type NativeFunPtr = Box<dyn (Fn(ObjRef, &mut Vm, Vec<ObjRef>) -> Signal) + Send + Sync>;
pub type NativeFunRef = ObjRef<NativeFun>;
#[derive(Scan)]
pub struct NativeFun {
@@ -89,12 +87,29 @@ pub struct NativeFun {
impl NativeFun {
pub fn new_obj(fun: NativeFunPtr) -> ObjRef<Self> {
ObjRef::new(Self {
// TODO : vtable for NativeFun
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
}
}
@@ -113,6 +128,8 @@ impl Debug for NativeFun {
impl_obj!(NativeFun);
pub static NATIVE_FUN_TY: Lazy<ObjRef<Ty>> = Lazy::new(|| Ty::new_obj(NATIVE_FUN_NAME.sym_ref()));
//
// Native function defs
//
@@ -121,7 +138,7 @@ impl_obj!(NativeFun);
// __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_obj(Box::new(|_vm, _fun, _args| {
NativeFun::new_obj(Box::new(|_caller, _vm, _args| {
/*
let sym_ref = vm.pop();
let obj_ref = vm.pop();