mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #74 from RustPython/dict_protocols
Complete Improvement to DictProtocol and AttributeProtocol
This commit is contained in:
@@ -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(),
|
||||
|
||||
@@ -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"))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {}",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user