Merge pull request #59 from RustPython/methods

Methods
This commit is contained in:
cthulahoops
2018-08-12 19:34:39 +01:00
committed by GitHub
6 changed files with 186 additions and 36 deletions

View File

@@ -1,14 +1,14 @@
class Foo:
print("Defining class")
def __init__(self):
print("initing: ", self)
self.x = 5
def __init__(self, x):
self.x = x
def square(self):
return self.x * self.x
y = 7
print("Done defining: ", Foo)
print("Init: ", Foo.__init__)
print("y = ", Foo.y)
foo = Foo()
print("Done initting: ", foo)
print("Foo's x: ", foo.x)
foo = Foo(5)
assert foo.y == Foo.y
assert foo.x == 5
assert foo.square() == 25

View File

@@ -12,7 +12,9 @@ pub mod eval;
mod frame;
mod import;
mod objbool;
mod objclass;
mod objdict;
mod objfunction;
mod objint;
mod objlist;
mod objsequence;

32
vm/src/objclass.rs Normal file
View File

@@ -0,0 +1,32 @@
use super::pyobject::AttributeProtocol;
use super::pyobject::{PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::vm::VirtualMachine;
pub fn get_attribute(
vm: &mut VirtualMachine,
cls: PyObjectRef,
obj: PyObjectRef,
name: &String,
) -> PyResult {
if obj.has_attr(name) {
Ok(obj.get_attr(name))
} else if cls.has_attr(name) {
let attr = cls.get_attr(name);
let attr_class = attr.typ();
if attr_class.has_attr(&String::from("__get__")) {
vm.invoke(
attr_class.get_attr(&String::from("__get__")),
PyFuncArgs {
args: vec![attr, obj, cls],
},
)
} else {
Ok(attr)
}
} else {
Err(vm.new_exception(format!(
"AttributeError: {:?} object has no attribute {}",
cls, name
)))
}
}

40
vm/src/objfunction.rs Normal file
View File

@@ -0,0 +1,40 @@
use super::pyobject::{PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult};
use super::vm::VirtualMachine;
use std::collections::HashMap;
pub fn create_type(type_type: PyObjectRef) -> PyObjectRef {
let mut dict = HashMap::new();
dict.insert(
"__get__".to_string(),
PyObject::new(
PyObjectKind::RustFunction {
function: bind_method,
},
type_type.clone(),
),
);
let typ = PyObject::new(
PyObjectKind::Class {
name: "function".to_string(),
dict: PyObject::new(PyObjectKind::Dict { elements: dict }, type_type.clone()),
},
type_type.clone(),
);
typ
}
pub fn create_bound_method_type(type_type: PyObjectRef) -> PyObjectRef {
let dict = HashMap::new();
let typ = PyObject::new(
PyObjectKind::Class {
name: "method".to_string(),
dict: PyObject::new(PyObjectKind::Dict { elements: dict }, type_type.clone()),
},
type_type.clone(),
);
typ
}
fn bind_method(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
Ok(vm.new_bound_method(args.args[0].clone(), args.args[1].clone()))
}

View File

@@ -1,4 +1,5 @@
use super::bytecode;
use super::objfunction;
use super::objint;
use super::objtype;
use super::vm::VirtualMachine;
@@ -45,6 +46,8 @@ pub struct PyContext {
pub list_type: PyObjectRef,
pub tuple_type: PyObjectRef,
pub dict_type: PyObjectRef,
pub function_type: PyObjectRef,
pub bound_method_type: PyObjectRef,
}
/*
@@ -61,18 +64,15 @@ pub struct Scope {
impl PyContext {
pub fn new() -> PyContext {
let type_type = objtype::create_type();
let int_type = objint::create_type(type_type.clone());
// TODO: How to represent builtin types?
let list_type = type_type.clone();
let tuple_type = type_type.clone();
let dict_type = type_type.clone();
// let str_type = objstr::make_type();
PyContext {
int_type: objint::create_type(type_type.clone()),
list_type: type_type.clone(),
tuple_type: type_type.clone(),
dict_type: type_type.clone(),
function_type: objfunction::create_type(type_type.clone()),
bound_method_type: objfunction::create_bound_method_type(type_type.clone()),
type_type: type_type,
int_type: int_type,
list_type: list_type,
tuple_type: tuple_type,
dict_type: dict_type,
}
}
@@ -154,6 +154,26 @@ impl PyContext {
)
}
pub fn new_function(&self, code_obj: PyObjectRef, scope: PyObjectRef) -> PyObjectRef {
PyObject::new(
PyObjectKind::Function {
code: code_obj,
scope: scope,
},
self.function_type.clone(),
)
}
pub fn new_bound_method(&self, function: PyObjectRef, object: PyObjectRef) -> PyObjectRef {
PyObject::new(
PyObjectKind::BoundMethod {
function: function,
object: object,
},
self.bound_method_type.clone(),
)
}
/* TODO: something like this?
pub fn new_instance(&self, name: String) -> PyObjectRef {
PyObject::new(PyObjectKind::Class { name: name }, self.type_type.clone())
@@ -187,6 +207,19 @@ impl IdProtocol for PyObjectRef {
}
}
pub trait TypeProtocol {
fn typ(&self) -> PyObjectRef;
}
impl TypeProtocol for PyObjectRef {
fn typ(&self) -> PyObjectRef {
match self.borrow().typ {
Some(ref typ) => typ.clone(),
None => panic!("Object doesn't have a type!"),
}
}
}
pub trait ParentProtocol {
fn has_parent(&self) -> bool;
fn get_parent(&self) -> PyObjectRef;
@@ -217,11 +250,13 @@ impl ParentProtocol for PyObjectRef {
pub trait AttributeProtocol {
fn get_attr(&self, attr_name: &String) -> PyObjectRef;
fn set_attr(&self, attr_name: &String, value: PyObjectRef);
fn has_attr(&self, attr_name: &String) -> bool;
}
impl AttributeProtocol for PyObjectRef {
fn get_attr(&self, attr_name: &String) -> PyObjectRef {
match self.borrow().kind {
let obj = self.borrow();
match obj.kind {
PyObjectKind::Module { name: _, ref dict } => dict.get_item(attr_name),
PyObjectKind::Class { name: _, ref dict } => dict.get_item(attr_name),
PyObjectKind::Instance { ref dict } => dict.get_item(attr_name),
@@ -229,6 +264,16 @@ impl AttributeProtocol for PyObjectRef {
}
}
fn has_attr(&self, attr_name: &String) -> bool {
let obj = self.borrow();
match obj.kind {
PyObjectKind::Module { name: _, ref dict } => dict.contains_key(attr_name),
PyObjectKind::Class { name: _, ref dict } => dict.contains_key(attr_name),
PyObjectKind::Instance { ref dict } => dict.contains_key(attr_name),
ref kind => unimplemented!("load_attr unimplemented for: {:?}", kind),
}
}
fn set_attr(&self, attr_name: &String, value: PyObjectRef) {
match self.borrow_mut().kind {
PyObjectKind::Instance { ref mut dict } => dict.set_item(attr_name, value),
@@ -337,6 +382,10 @@ pub enum PyObjectKind {
code: PyObjectRef,
scope: PyObjectRef,
},
BoundMethod {
function: PyObjectRef,
object: PyObjectRef,
},
Scope {
scope: Scope,
},
@@ -379,6 +428,10 @@ impl fmt::Debug for PyObjectKind {
&PyObjectKind::NameError { name: _ } => write!(f, "NameError"),
&PyObjectKind::Code { ref code } => write!(f, "code: {:?}", code),
&PyObjectKind::Function { code: _, scope: _ } => write!(f, "function"),
&PyObjectKind::BoundMethod {
function: _,
object: _,
} => write!(f, "bound-method"),
&PyObjectKind::Module { name: _, dict: _ } => write!(f, "module"),
&PyObjectKind::Scope { scope: _ } => write!(f, "scope"),
&PyObjectKind::None => write!(f, "None"),
@@ -449,6 +502,7 @@ impl PyObject {
PyObjectKind::Instance { dict: _ } => format!("<instance>"),
PyObjectKind::Code { code: _ } => format!("<code>"),
PyObjectKind::Function { code: _, scope: _ } => format!("<func>"),
PyObjectKind::BoundMethod { .. } => format!("<bound-method>"),
PyObjectKind::RustFunction { function: _ } => format!("<rustfunc>"),
PyObjectKind::Module { ref name, dict: _ } => format!("<module '{}'>", name),
PyObjectKind::Scope { ref scope } => format!("<scope '{:?}'>", scope),

View File

@@ -12,12 +12,13 @@ use super::builtins;
use super::bytecode;
use super::frame::{copy_code, Block, Frame};
use super::import::import;
use super::objclass;
use super::objlist;
use super::objstr;
use super::objtype;
use super::pyobject::{
AttributeProtocol, DictProtocol, IdProtocol, ParentProtocol, PyContext, PyFuncArgs, PyObject,
PyObjectKind, PyObjectRef, PyResult,
PyObjectKind, PyObjectRef, PyResult, TypeProtocol,
};
use super::sysmodule;
@@ -68,6 +69,10 @@ impl VirtualMachine {
self.ctx.new_bool(false)
}
pub fn new_bound_method(&self, function: PyObjectRef, object: PyObjectRef) -> PyObjectRef {
self.ctx.new_bound_method(function, object)
}
pub fn get_type(&self) -> PyObjectRef {
self.ctx.type_type.clone()
}
@@ -464,10 +469,8 @@ impl VirtualMachine {
// more or less __new__ operator
let dict = self.new_dict();
let obj = PyObject::new(PyObjectKind::Instance { dict: dict }, type_ref.clone());
let init = type_ref.get_attr(&String::from("__init__"));
let mut self_args = PyFuncArgs { args: args.args };
self_args.args.insert(0, obj.clone());
self.invoke(init, self_args)?;
let init = objclass::get_attribute(self, type_ref, obj.clone(), &String::from("__init__"))?;
self.invoke(init, args)?;
// TODO Raise TypeError if init returns not None.
Ok(obj)
}
@@ -490,6 +493,16 @@ impl VirtualMachine {
self.run_frame(frame)
}
PyObjectKind::Class { name: _, dict: _ } => self.new_instance(func_ref.clone(), args),
PyObjectKind::BoundMethod {
ref function,
ref object,
} => {
let mut self_args = PyFuncArgs {
args: args.args.clone(),
};
self_args.args.insert(0, object.clone());
self.invoke(function.clone(), self_args)
}
ref kind => {
unimplemented!("invoke unimplemented for: {:?}", kind);
}
@@ -507,11 +520,26 @@ impl VirtualMachine {
None
}
fn get_attribute(&mut self, obj: PyObjectRef, attr_name: &String) -> PyResult {
let typ = obj.typ();
let typ_ref = typ.borrow();
match typ_ref.kind {
PyObjectKind::Class { .. } => {
objclass::get_attribute(self, typ.clone(), obj.clone(), attr_name)
}
_ => panic!("It's not a class: {:?}", typ),
}
}
fn load_attr(&mut self, attr_name: &String) -> Option<PyResult> {
let parent = self.pop_value();
let obj = parent.get_attr(attr_name);
self.push_value(obj);
None
match self.get_attribute(parent, attr_name) {
Ok(obj) => {
self.push_value(obj);
None
}
Err(err) => Some(Err(err)),
}
}
fn store_attr(&mut self, attr_name: &String) -> Option<PyResult> {
@@ -692,13 +720,7 @@ impl VirtualMachine {
// pop argc arguments
// argument: name, args, globals
let scope = self.current_frame().locals.clone();
let obj = PyObject::new(
PyObjectKind::Function {
code: code_obj,
scope: scope,
},
self.get_type(),
);
let obj = self.ctx.new_function(code_obj, scope);
self.push_value(obj);
None
}