Implement vtables and method resolution

Types now can have vtable elements which are used by instances to bind
themselves to methods. When Op::GetAttr is executed, it calls a new
function, Obj::get_attr_lazy. This will search:

* attributes on the object
* vtable on the object's type
* vtable on the object's type's type,
* etc.

This searches up the type tree for a named value. If it exists as an
attribute, it will be returned immediately. If it exists in the type's
vtable, then it will be inserted as an attribute. If the vtable value is
a function, the object that it is being called on will be bound to that
method as the `self` parameter.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2024-09-23 20:59:00 -07:00
parent 8b931e9d12
commit 0d04090a99
2 changed files with 201 additions and 177 deletions

View File

@@ -197,6 +197,9 @@ impl Vm {
}
pub fn run(&mut self) {
// Cached pointers that we just always want to have on hand
let method_type = self.builtins().get("Method").unwrap().clone();
loop {
match self.next() {
Op::Pop => {
@@ -232,7 +235,10 @@ impl Vm {
let name =
with_obj_downcast(name_obj, |name: &StrInst| Rc::clone(&name.str_value()));
let owner = self.pop();
let value = owner.borrow().get_attr(&name);
let value =
owner
.borrow_mut()
.get_attr_lazy(owner.clone(), method_type.clone(), &name);
if let Some(value) = value {
self.push(value);
} else {
@@ -339,7 +345,7 @@ impl Vm {
let stack_base = self.frames[frame_index].stack_base;
let value = Ptr::clone(&self.stack[stack_base + (slot as usize)]);
fun.push_capture(value);
self.push(upcast_obj(make_ptr(fun)));
self.push(make_ptr(fun));
}
Op::Halt => {
break;