Merge pull request #74 from RustPython/dict_protocols

Complete Improvement to DictProtocol and AttributeProtocol
This commit is contained in:
Daniel Watkins
2018-08-24 09:23:02 -04:00
committed by GitHub
6 changed files with 50 additions and 56 deletions

View File

@@ -15,9 +15,9 @@ use super::vm::VirtualMachine;
fn import_module(vm: &mut VirtualMachine, module: &String) -> PyResult {
// First, see if we already loaded the module:
let sys_modules = vm.sys_module.get_item(&"modules".to_string());
if sys_modules.contains_key(module) {
return Ok(sys_modules.get_item(module));
let sys_modules = vm.sys_module.get_item("modules").unwrap();
if let Some(module) = sys_modules.get_item(module) {
return Ok(module);
}
// Time to search for module in any place:
@@ -50,7 +50,7 @@ pub fn import(vm: &mut VirtualMachine, module: &String, symbol: &Option<String>)
// If we're importing a symbol, look it up and use it, otherwise construct a module and return
// that
let obj = match symbol {
Some(symbol) => scope.get_item(symbol),
Some(symbol) => scope.get_item(symbol).unwrap(),
None => PyObject::new(
PyObjectKind::Module {
name: module.clone(),

View File

@@ -66,6 +66,8 @@ pub fn create_member_descriptor_type(type_type: PyObjectRef, object: PyObjectRef
}
fn member_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
let function = args.shift().get_attr(&String::from("function"));
vm.invoke(function, args)
match args.shift().get_attr("function") {
Some(function) => vm.invoke(function, args),
None => Err(vm.new_exception(String::from("Attribute Error"))),
}
}

View File

@@ -19,10 +19,6 @@ pub fn call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
vm.invoke(function, args)
}
fn noop(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
Ok(vm.get_none())
}
pub fn create_object(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: PyObjectRef) {
(*object_type.borrow_mut()).kind = PyObjectKind::Class {
name: String::from("object"),
@@ -35,5 +31,13 @@ pub fn create_object(type_type: PyObjectRef, object_type: PyObjectRef, dict_type
pub fn init(context: &PyContext) {
let ref object = context.object;
object.set_attr("__new__", context.new_rustfunc(new_instance));
object.set_attr("__init__", context.new_rustfunc(noop));
object.set_attr("__dict__", context.new_member_descriptor(object_dict));
}
fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
match args.args[0].borrow().kind {
PyObjectKind::Class { ref dict, .. } => Ok(dict.clone()),
PyObjectKind::Instance { ref dict, .. } => Ok(dict.clone()),
_ => Err(vm.new_exception("TypeError: no dictionary.".to_string())),
}
}

View File

@@ -24,7 +24,6 @@ pub fn init(context: &PyContext) {
type_type.set_attr("__new__", context.new_rustfunc(type_new));
type_type.set_attr("__mro__", context.new_member_descriptor(type_mro));
type_type.set_attr("__class__", context.new_member_descriptor(type_new));
type_type.set_attr("__dict__", context.new_member_descriptor(type_dict));
}
fn type_mro(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -45,13 +44,6 @@ fn _mro(cls: PyObjectRef) -> Option<Vec<PyObjectRef>> {
}
}
fn type_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
match args.args[0].borrow().kind {
PyObjectKind::Class { ref dict, .. } => Ok(dict.clone()),
_ => Err(vm.new_exception("type_dict must be called on a class.".to_string())),
}
}
pub fn type_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
debug!("type.__new__{:?}", args);
if args.args.len() == 2 {
@@ -71,12 +63,11 @@ pub fn type_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
debug!("type_call: {:?}", args);
let typ = args.shift();
let new = typ.get_attr(&String::from("__new__"));
let new = typ.get_attr("__new__").unwrap();
let obj = vm.invoke(new, args.insert(typ.clone()))?;
if obj.typ().has_attr(&String::from("__init__")) {
let init = obj.typ().get_attr(&String::from("__init__"));
vm.invoke(init, args.insert(obj.clone()))?;
if let Some(init) = obj.typ().get_attr("__init__") {
let _ = vm.invoke(init, args.insert(obj.clone())).unwrap();
}
Ok(obj)
}
@@ -84,12 +75,11 @@ pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &String) -> PyResult {
let cls = obj.typ();
trace!("get_attribute: {:?}, {:?}, {:?}", cls, obj, name);
if cls.has_attr(name) {
let attr = cls.get_attr(name);
if let Some(attr) = cls.get_attr(name) {
let attr_class = attr.typ();
if attr_class.has_attr(&String::from("__get__")) {
if let Some(descriptor) = attr_class.get_attr("__get__") {
return vm.invoke(
attr_class.get_attr(&String::from("__get__")),
descriptor,
PyFuncArgs {
args: vec![attr, obj, cls],
},
@@ -97,10 +87,10 @@ pub fn get_attribute(vm: &mut VirtualMachine, obj: PyObjectRef, name: &String) -
}
}
if obj.has_attr(name) {
Ok(obj.get_attr(name))
} else if cls.has_attr(name) {
Ok(cls.get_attr(name))
if let Some(obj_attr) = obj.get_attr(name) {
Ok(obj_attr)
} else if let Some(cls_attr) = cls.get_attr(name) {
Ok(cls_attr)
} else {
Err(vm.new_exception(format!(
"AttributeError: {:?} object has no attribute {}",

View File

@@ -272,25 +272,20 @@ impl ParentProtocol for PyObjectRef {
}
pub trait AttributeProtocol {
fn get_attr(&self, attr_name: &String) -> PyObjectRef;
fn get_attr(&self, attr_name: &str) -> Option<PyObjectRef>;
fn set_attr(&self, attr_name: &str, value: PyObjectRef);
fn has_attr(&self, attr_name: &String) -> bool;
fn has_attr(&self, attr_name: &str) -> bool;
}
fn class_get_item(class: &PyObjectRef, attr_name: &String) -> Option<PyObjectRef> {
fn class_get_item(class: &PyObjectRef, attr_name: &str) -> Option<PyObjectRef> {
let class = class.borrow();
match class.kind {
PyObjectKind::Class { ref dict, .. } => {
if dict.contains_key(attr_name) {
return Some(dict.get_item(attr_name));
}
None
}
PyObjectKind::Class { ref dict, .. } => dict.get_item(attr_name),
_ => panic!("Only classes should be in MRO!"),
}
}
fn class_has_item(class: &PyObjectRef, attr_name: &String) -> bool {
fn class_has_item(class: &PyObjectRef, attr_name: &str) -> bool {
let class = class.borrow();
match class.kind {
PyObjectKind::Class { ref dict, .. } => dict.contains_key(attr_name),
@@ -299,27 +294,27 @@ fn class_has_item(class: &PyObjectRef, attr_name: &String) -> bool {
}
impl AttributeProtocol for PyObjectRef {
fn get_attr(&self, attr_name: &String) -> PyObjectRef {
fn get_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
let obj = self.borrow();
match obj.kind {
PyObjectKind::Module { ref dict, .. } => dict.get_item(attr_name),
PyObjectKind::Class { ref mro, .. } => {
if let Some(item) = class_get_item(self, attr_name) {
return item;
return Some(item);
}
for ref class in mro {
if let Some(item) = class_get_item(class, attr_name) {
return item;
return Some(item);
}
}
panic!("MRO search failed: {:?} {}", obj, attr_name);
None
}
PyObjectKind::Instance { ref dict } => dict.get_item(attr_name),
ref kind => unimplemented!("load_attr unimplemented for: {:?}", kind),
}
}
fn has_attr(&self, attr_name: &String) -> bool {
fn has_attr(&self, attr_name: &str) -> bool {
let obj = self.borrow();
match obj.kind {
PyObjectKind::Module { name: _, ref dict } => dict.contains_key(attr_name),
@@ -334,25 +329,25 @@ impl AttributeProtocol for PyObjectRef {
fn set_attr(&self, attr_name: &str, value: PyObjectRef) {
match self.borrow().kind {
PyObjectKind::Instance { ref dict } => dict.set_item(&String::from(attr_name), value),
PyObjectKind::Instance { ref dict } => dict.set_item(attr_name, value),
PyObjectKind::Class {
name: _,
ref dict,
mro: _,
} => dict.set_item(&String::from(attr_name), value),
} => dict.set_item(attr_name, value),
ref kind => unimplemented!("set_attr unimplemented for: {:?}", kind),
};
}
}
pub trait DictProtocol {
fn contains_key(&self, k: &String) -> bool;
fn get_item(&self, k: &String) -> PyObjectRef;
fn set_item(&self, k: &String, v: PyObjectRef);
fn contains_key(&self, k: &str) -> bool;
fn get_item(&self, k: &str) -> Option<PyObjectRef>;
fn set_item(&self, k: &str, v: PyObjectRef);
}
impl DictProtocol for PyObjectRef {
fn contains_key(&self, k: &String) -> bool {
fn contains_key(&self, k: &str) -> bool {
match self.borrow().kind {
PyObjectKind::Dict { ref elements } => elements.contains_key(k),
PyObjectKind::Module { name: _, ref dict } => dict.contains_key(k),
@@ -361,16 +356,19 @@ impl DictProtocol for PyObjectRef {
}
}
fn get_item(&self, k: &String) -> PyObjectRef {
fn get_item(&self, k: &str) -> Option<PyObjectRef> {
match self.borrow().kind {
PyObjectKind::Dict { ref elements } => elements[k].clone(),
PyObjectKind::Dict { ref elements } => match elements.get(k) {
Some(v) => Some(v.clone()),
None => None,
},
PyObjectKind::Module { name: _, ref dict } => dict.get_item(k),
PyObjectKind::Scope { ref scope } => scope.locals.get_item(k),
_ => panic!("TODO"),
}
}
fn set_item(&self, k: &String, v: PyObjectRef) {
fn set_item(&self, k: &str, v: PyObjectRef) {
match self.borrow_mut().kind {
PyObjectKind::Dict {
elements: ref mut el,

View File

@@ -197,7 +197,7 @@ impl VirtualMachine {
let mut scope = self.current_frame().locals.clone();
loop {
if scope.contains_key(name) {
let obj = scope.get_item(name);
let obj = scope.get_item(name).unwrap();
self.push_value(obj);
break None;
} else if scope.has_parent() {