Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Move __class__ attribute to object to make it work in more situations
  • Loading branch information
skinnyBat committed Mar 7, 2019
commit 9d03abf652dca9f1606121570a82d63527b458c2
9 changes: 9 additions & 0 deletions tests/snippets/types_snippet.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,14 @@
assert type(cls) is metaclass
assert type(metaclass) is type

assert issubclass(metaclass, type)
assert isinstance(cls, type)

assert inst.__class__ is cls
assert cls.__class__ is metaclass
assert metaclass.__class__ is type
assert type.__class__ is type
assert None.__class__ is type(None)

assert isinstance(type, type)
assert issubclass(type, type)
34 changes: 34 additions & 0 deletions vm/src/obj/objfunction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ pub fn init(context: &PyContext) {
context.new_rustfunc(member_get),
);

let data_descriptor_type = &context.data_descriptor_type;
context.set_attr(
&data_descriptor_type,
"__get__",
context.new_rustfunc(data_get),
);
context.set_attr(
&data_descriptor_type,
"__set__",
context.new_rustfunc(data_set),
);

let classmethod_type = &context.classmethod_type;
context.set_attr(
&classmethod_type,
Expand Down Expand Up @@ -83,6 +95,28 @@ fn member_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
}
}

fn data_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
match args.shift().get_attr("fget") {
Some(function) => vm.invoke(function, args),
None => {
println!("A");
Comment thread
BenLewis-Seequent marked this conversation as resolved.
Outdated
let attribute_error = vm.context().exceptions.attribute_error.clone();
Err(vm.new_exception(attribute_error, String::from("Attribute Error")))
}
}
}

fn data_set(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
match args.shift().get_attr("fset") {
Some(function) => vm.invoke(function, args),
None => {
println!("B");
let attribute_error = vm.context().exceptions.attribute_error.clone();
Err(vm.new_exception(attribute_error, String::from("Attribute Error")))
}
}
}

// Classmethod type methods:
fn classmethod_get(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
trace!("classmethod.__get__ {:?}", args.args);
Expand Down
20 changes: 20 additions & 0 deletions vm/src/obj/objobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ pub fn init(context: &PyContext) {

context.set_attr(&object, "__new__", context.new_rustfunc(new_instance));
context.set_attr(&object, "__init__", context.new_rustfunc(object_init));
context.set_attr(
&object,
"__class__",
context.new_data_descriptor(object_class, object_class_setter),
);
context.set_attr(&object, "__eq__", context.new_rustfunc(object_eq));
context.set_attr(&object, "__ne__", context.new_rustfunc(object_ne));
context.set_attr(&object, "__lt__", context.new_rustfunc(object_lt));
Expand Down Expand Up @@ -190,6 +195,21 @@ fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
Ok(vm.ctx.none())
}

fn object_class(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [(_obj, None), (owner, Some(vm.ctx.type_type()))]
);
Ok(owner.clone())
}

fn object_class_setter(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(instance, None), (_value, None)]);
let type_repr = vm.to_pystr(&instance.typ())?;
Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr)))
}

fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
match args.args[0].payload {
PyObjectPayload::Class { ref dict, .. } | PyObjectPayload::Instance { ref dict, .. } => {
Expand Down
5 changes: 0 additions & 5 deletions vm/src/obj/objtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ pub fn init(context: &PyContext) {
"__mro__",
context.new_member_descriptor(type_mro),
);
context.set_attr(
&type_type,
"__class__",
context.new_member_descriptor(type_new),
);
context.set_attr(&type_type, "__repr__", context.new_rustfunc(type_repr));
context.set_attr(
&type_type,
Expand Down
22 changes: 22 additions & 0 deletions vm/src/pyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ pub struct PyContext {
pub module_type: PyObjectRef,
pub bound_method_type: PyObjectRef,
pub member_descriptor_type: PyObjectRef,
pub data_descriptor_type: PyObjectRef,
pub object: PyObjectRef,
pub exceptions: exceptions::ExceptionZoo,
}
Expand Down Expand Up @@ -199,6 +200,8 @@ impl PyContext {
let bound_method_type = create_type("method", &type_type, &object_type, &dict_type);
let member_descriptor_type =
create_type("member_descriptor", &type_type, &object_type, &dict_type);
let data_descriptor_type =
create_type("data_descriptor", &type_type, &object_type, &dict_type);
let str_type = create_type("str", &type_type, &object_type, &dict_type);
let list_type = create_type("list", &type_type, &object_type, &dict_type);
let set_type = create_type("set", &type_type, &object_type, &dict_type);
Expand Down Expand Up @@ -285,6 +288,7 @@ impl PyContext {
module_type,
bound_method_type,
member_descriptor_type,
data_descriptor_type,
type_type,
exceptions,
};
Expand Down Expand Up @@ -449,6 +453,10 @@ impl PyContext {
pub fn member_descriptor_type(&self) -> PyObjectRef {
self.member_descriptor_type.clone()
}
pub fn data_descriptor_type(&self) -> PyObjectRef {
self.data_descriptor_type.clone()
}

pub fn type_type(&self) -> PyObjectRef {
self.type_type.clone()
}
Expand Down Expand Up @@ -658,6 +666,20 @@ impl PyContext {
self.new_instance(self.member_descriptor_type(), Some(dict))
}

pub fn new_data_descriptor<
G: 'static + Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult,
S: 'static + Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult,
>(
&self,
getter: G,
setter: S,
) -> PyObjectRef {
let mut dict = PyAttributes::new();
dict.insert("fget".to_string(), self.new_rustfunc(getter));
dict.insert("fset".to_string(), self.new_rustfunc(setter));
self.new_instance(self.data_descriptor_type(), Some(dict))
}

pub fn new_instance(&self, class: PyObjectRef, dict: Option<PyAttributes>) -> PyObjectRef {
let dict = if let Some(dict) = dict {
dict
Expand Down