diff --git a/src/obj/builtin.rs b/src/obj/builtin.rs index 1aaf830..45852e9 100644 --- a/src/obj/builtin.rs +++ b/src/obj/builtin.rs @@ -13,12 +13,13 @@ pub static PRINTLN_BUILTIN_FUN: Lazy = 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 = 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()); } diff --git a/src/obj/fun.rs b/src/obj/fun.rs index b717537..2c365d4 100644 --- a/src/obj/fun.rs +++ b/src/obj/fun.rs @@ -11,6 +11,61 @@ pub trait Fun { fn create_frame(&self, callee: ObjRef, vm: &Vm, _args: Vec) -> Frame; } +pub type MethodRef = ObjRef; + +#[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) -> 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 // diff --git a/src/obj/int.rs b/src/obj/int.rs index cc66a64..e1b47a3 100644 --- a/src/obj/int.rs +++ b/src/obj/int.rs @@ -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 { - // 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 = 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_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 + }) +}); diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 82cd5a3..21f96ec 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -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