Add Obj.__init__ and Obj.__call__, fix how __call__ works on Ty

* Obj.__call__ should generically call Obj.__init__, passing along the
  arguments given to __call__
* Ty::call function (in Rust) sets up the stack frame correctly now.
  Before, the only arguments visible to a `Ty.__call__` function would
  have been the values passed to it. However, the Ty.__call__ also needs
  *itself* passed to the __call__ function so we can retrieve the
  __init__ function and eventually end up calling that.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2024-10-07 15:24:06 -07:00
parent 16ab9d718b
commit 40a10fa00e
3 changed files with 86 additions and 18 deletions

View File

@@ -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
// <Ty MyType> <---- 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<Argc> {
@@ -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 {