Add Method type for objects
* Methods are wrappers created with an owner and a function, which passes the owner as the first argument when the function is called. * Fix a small bug in the VM where the pc was being set at the wrong time Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -13,12 +13,13 @@ pub static PRINTLN_BUILTIN_FUN: Lazy<NativeFunRef> = Lazy::new(|| NativeFun::new
|
||||
.expect("no __str__ or __repr__ member")
|
||||
};
|
||||
let return_value = vm.call(to_string, vec![]);
|
||||
let str_ref: &StrRef = std::any::Any::downcast_ref(&return_value).expect("to_string to return str value");
|
||||
{
|
||||
read_obj!(let str_obj = str_ref);
|
||||
read_obj!(let str_obj = return_value);
|
||||
let str_obj: &Str = str_obj.as_any().downcast_ref().unwrap();
|
||||
println!("{}", str_obj.value());
|
||||
}
|
||||
|
||||
vm.push(NIL_NAME.sym_ref());
|
||||
Signal::Return
|
||||
}));
|
||||
|
||||
@@ -32,9 +33,9 @@ pub static PRINT_BUILTIN_FUN: Lazy<NativeFunRef> = Lazy::new(|| NativeFun::new_o
|
||||
.expect("no __str__ or __repr__ member")
|
||||
};
|
||||
let return_value = vm.call(to_string, vec![]);
|
||||
let str_ref: &StrRef = std::any::Any::downcast_ref(&return_value).expect("to_string to return str value");
|
||||
{
|
||||
read_obj!(let str_obj = str_ref);
|
||||
read_obj!(let str_obj = return_value);
|
||||
let str_obj: &Str = str_obj.as_any().downcast_ref().unwrap();
|
||||
print!("{}", str_obj.value());
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,61 @@ pub trait Fun {
|
||||
fn create_frame(&self, callee: ObjRef, vm: &Vm, _args: Vec<ObjRef>) -> Frame;
|
||||
}
|
||||
|
||||
pub type MethodRef = ObjRef<Method>;
|
||||
|
||||
#[derive(Scan, Debug)]
|
||||
pub struct Method {
|
||||
vtable: Vtable,
|
||||
attrs: Attrs,
|
||||
}
|
||||
|
||||
impl Method {
|
||||
pub fn new_obj(owner: ObjRef, function: ObjRef) -> MethodRef {
|
||||
self_referring_obj! {
|
||||
Self {
|
||||
vtable: Default::default(),
|
||||
attrs: attrs! {
|
||||
SELF_MEMBER_NAME.sym => owner,
|
||||
FUNC_MEMBER_NAME.sym => function,
|
||||
}
|
||||
},
|
||||
vtable: |obj_ref: ObjRef| vtable! {
|
||||
CALL_MEMBER_NAME.sym => obj_ref.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Obj for Method {
|
||||
fn vtable(&self) -> &Vtable {
|
||||
&self.vtable
|
||||
}
|
||||
|
||||
fn attrs(&self) -> &Attrs {
|
||||
&self.attrs
|
||||
}
|
||||
|
||||
fn attrs_mut(&mut self) -> Option<&mut Attrs> {
|
||||
Some(&mut self.attrs)
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
|
||||
fn as_fun(&self) -> Option<&dyn Fun> { Some(self) }
|
||||
}
|
||||
|
||||
impl Fun for Method {
|
||||
fn create_frame(&self, _callee: ObjRef, vm: &Vm, mut args: Vec<ObjRef>) -> Frame {
|
||||
// insert self argument
|
||||
args.insert(0, self.get_attr(SELF_MEMBER_NAME.sym).unwrap());
|
||||
// get function and use its create_frame method with the updated args
|
||||
let fun_ref = self.get_attr(FUNC_MEMBER_NAME.sym).unwrap();
|
||||
read_obj!(let fun_obj = fun_ref);
|
||||
let fun = fun_obj.as_fun().unwrap();
|
||||
fun.create_frame(fun_ref.clone(), vm, args)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// struct UserFun
|
||||
//
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::obj::prelude::*;
|
||||
use crate::obj::{prelude::*, reserved::*};
|
||||
use once_cell::sync::Lazy;
|
||||
use shredder::Scan;
|
||||
use std::fmt::{Debug, Formatter, self};
|
||||
|
||||
@@ -13,14 +14,18 @@ pub struct Int {
|
||||
|
||||
impl Int {
|
||||
pub fn new_obj(value: i64) -> ObjRef<Self> {
|
||||
// TODO : vtable for Int
|
||||
let obj_ref = ObjRef::new(Self {
|
||||
value,
|
||||
vtable: Default::default(),
|
||||
attrs: Default::default(),
|
||||
});
|
||||
|
||||
obj_ref
|
||||
// TODO : cache int values
|
||||
self_referring_obj! {
|
||||
Self {
|
||||
value,
|
||||
vtable: Default::default(),
|
||||
attrs: Default::default(),
|
||||
},
|
||||
vtable: |obj_ref: ObjRef| vtable! {
|
||||
// TODO needs Method type so this function is given an argument when called
|
||||
STR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_STR_FUN.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(&self) -> i64 {
|
||||
@@ -37,3 +42,15 @@ impl Debug for Int {
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
static INT_STR_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
|
||||
NativeFun::new_obj(|_callee, vm, args| {
|
||||
read_obj!(let int_obj = &args[0]);
|
||||
if let Some(int_obj) = std::any::Any::downcast_ref::<Int>(int_obj.as_any()) {
|
||||
vm.push(Str::new_obj(int_obj.value.to_string()));
|
||||
} else {
|
||||
panic!("{:?} is not an int", int_obj)
|
||||
}
|
||||
crate::vm::signal::Signal::Return
|
||||
})
|
||||
});
|
||||
|
||||
@@ -149,9 +149,11 @@ impl<'c> Vm<'c> {
|
||||
let frame = callee_obj.as_fun()
|
||||
.expect("callable function")
|
||||
.create_frame(callee.clone(), self, args);
|
||||
// Jump to the first address of the new function call if it's a user function
|
||||
if let Frame::User(_) = &frame {
|
||||
self.set_pc(0);
|
||||
}
|
||||
self.frames_mut().push(frame);
|
||||
// Jump to the first address of the new function call
|
||||
self.set_pc(0);
|
||||
}
|
||||
Signal::Return => {
|
||||
// 1. pop return value
|
||||
|
||||
Reference in New Issue
Block a user