diff --git a/src/obj.rs b/src/obj.rs index 4cef325..446257d 100644 --- a/src/obj.rs +++ b/src/obj.rs @@ -452,6 +452,54 @@ impl Object for Obj { impl_base_obj!(Obj); } +// +// Obj methods +// + +impl Obj { + pub(crate) fn do_call(vm: &mut Vm, state: FunctionState) -> FunctionResult { + let ty = vm.frame_stack()[0].clone(); + + match state { + FunctionState::Begin => { + let argc = vm.frame_stack().len() - 1; + + let mut obj = Obj::new(); + obj.set_attr("__ty__", ty.clone()); + obj.instantiate(); + + let obj_ptr = make_ptr(obj); + let init = obj_ptr + .borrow() + .get_vtable_attr(obj_ptr.clone(), "__init__") + .expect("no __init__"); + + vm.push(obj_ptr); + vm.push(init.clone()); + // duplicate arguments that were pushed to the frame + for i in 0..argc { + let arg = vm.frame_stack()[i + 1].clone(); + vm.push(arg); + } + + init.borrow().call(vm, argc as Argc); + + FunctionResult::Yield(0) + } + FunctionState::Resume(0) => { + vm.pop(); + FunctionResult::Return + } + _ => unreachable!(), + } + } + + pub(crate) fn init(_vm: &mut Vm, _state: FunctionState) -> FunctionResult { + // no-op + Nil::create().into() + } +} + //////////////////////////////////////////////////////////////////////////////// // Nil //////////////////////////////////////////////////////////////////////////////// diff --git a/src/obj/macros.rs b/src/obj/macros.rs index 16117a7..9c6946a 100644 --- a/src/obj/macros.rs +++ b/src/obj/macros.rs @@ -1,13 +1,15 @@ macro_rules! impl_base_obj { ($base_name:ident, $type_name:ident) => { fn instantiate(&mut self) { - let ty = $crate::obj::BUILTINS.with_borrow(|builtins| { - builtins - .get(stringify!($type_name)) - .expect(concat!("no ", stringify!($type_name))) - .clone() - }); - self.set_attr("__ty__", ty); + if self.get_attr("__ty__").is_none() { + let ty = $crate::obj::BUILTINS.with_borrow(|builtins| { + builtins + .get(stringify!($type_name)) + .expect(concat!("no ", stringify!($type_name))) + .clone() + }); + self.set_attr("__ty__", ty); + } self.$base_name.instantiate(); } diff --git a/src/obj/ty.rs b/src/obj/ty.rs index c1e27c0..a9284cf 100644 --- a/src/obj/ty.rs +++ b/src/obj/ty.rs @@ -77,21 +77,37 @@ impl Object for Ty { // If you do e.g. `Int.__call__`, Int is an object, so it should be doing `__call__` as a // vtable value. - if cfg!(debug_assertions) { - let index = vm.stack().len() - 1 - argc as usize; - let this = vm.stack()[index].clone(); - assert!( - std::ptr::addr_eq(&*this.borrow(), self), - "calling {}.__call__ on type that is not ourselves", - self.ty_name() - ); - } + let index = vm.stack().len() - 1 - argc as usize; + let this = vm.stack()[index].clone(); + + assert!( + std::ptr::addr_eq(&*this.borrow(), self), + "calling {}.__call__ on type that is not ourselves", + self.ty_name() + ); + + // Additionally, we want to duplicate the type argument on the stack. + // + // When you call a new constructor, e.g. `MyType(arg1, arg2, arg3)`, the stack will look like this: + // + // -- stack top + // arg3 + // arg2 + // arg1 + // <---- NOTE - this is what we are actually calling, and is being treated as a function + // ... + // -- stack bottom + // + // With a custom type, we want to be getting the __init__ function off of the type. Since + // we don't have access to the function in the call stack (in this case, it's our type), + // we duplicate the type to be the first argument. + vm.stack_mut().insert(index, this); let function = self .vtable .get("__call__") .expect("Why does a type not have a __call__ member?"); - function.borrow().call(vm, argc); + function.borrow().call(vm, argc + 1); } fn arity(&self) -> Option { @@ -185,7 +201,9 @@ pub fn init_types() { len => BuiltinFunction::create("len", BaseObj::not_implemented_un, 1), }, Obj { - //__call__ => BuiltinFunction::create("__call__", + // Constructor + __call__ => BuiltinFunction::create("__call__", Obj::do_call, 1), + __init__ => BuiltinFunction::create("__init__", Obj::init, 1), // Methods }, List {