diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 54f20a7ea..dfead1cc8 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -99,13 +99,6 @@ fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { // builtin_complex // builtin_delattr -fn builtin_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { - if !args.args.is_empty() { - unimplemented!("only zero-arg version of dict is currently supported") - } - Ok(vm.new_dict()) -} - fn builtin_dir(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { if args.args.is_empty() { Ok(dir_locals(vm)) @@ -335,7 +328,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { dict.insert(String::from("chr"), ctx.new_rustfunc(builtin_chr)); dict.insert(String::from("compile"), ctx.new_rustfunc(builtin_compile)); // TODO: can we just insert dict here? - dict.insert(String::from("dict"), ctx.new_rustfunc(builtin_dict)); + dict.insert(String::from("dict"), ctx.dict_type.clone()); dict.insert(String::from("dir"), ctx.new_rustfunc(builtin_dir)); dict.insert(String::from("eval"), ctx.new_rustfunc(builtin_eval)); dict.insert(String::from("getattr"), ctx.new_rustfunc(builtin_getattr)); @@ -375,8 +368,9 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { pub fn builtin_build_class_(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { let function = args.shift(); let name_arg = args.shift(); - let name = match name_arg.borrow().kind { - PyObjectKind::String { ref value } => value.to_string(), + let name_arg_ref = name_arg.borrow(); + let name = match name_arg_ref.kind { + PyObjectKind::String { ref value } => value, _ => panic!("Class name must by a string!"), }; let mut bases = args.args.clone(); diff --git a/vm/src/lib.rs b/vm/src/lib.rs index a0b396482..78178c91f 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -12,11 +12,11 @@ pub mod eval; mod frame; mod import; mod objbool; -mod objclass; mod objdict; mod objfunction; mod objint; mod objlist; +mod objobject; mod objsequence; mod objstr; mod objtype; diff --git a/vm/src/objclass.rs b/vm/src/objclass.rs deleted file mode 100644 index 87ef66172..000000000 --- a/vm/src/objclass.rs +++ /dev/null @@ -1,48 +0,0 @@ -use super::objtype; -use super::pyobject::{PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult}; -use super::vm::VirtualMachine; -use std::collections::HashMap; - -pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { - // more or less __new__ operator - let type_ref = args.shift(); - let dict = vm.new_dict(); - let obj = PyObject::new(PyObjectKind::Instance { dict: dict }, type_ref.clone()); - Ok(obj) -} - -pub fn call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { - let instance = args.shift(); - let function = objtype::get_attribute(vm, instance, &String::from("__call__"))?; - vm.invoke(function, args) -} - -fn noop(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { - Ok(vm.get_none()) -} - -pub fn create_object(type_type: PyObjectRef, function_type: PyObjectRef) -> PyObjectRef { - let mut dict = HashMap::new(); - dict.insert( - "__new__".to_string(), - PyObject::new( - PyObjectKind::RustFunction { - function: new_instance, - }, - function_type.clone(), - ), - ); - dict.insert( - "__init__".to_string(), - PyObject::new( - PyObjectKind::RustFunction { function: noop }, - function_type.clone(), - ), - ); - objtype::new( - type_type.clone(), - String::from("object"), - vec![], - PyObject::new(PyObjectKind::Dict { elements: dict }, type_type.clone()), - ).unwrap() -} diff --git a/vm/src/objdict.rs b/vm/src/objdict.rs index 8781777f8..181505fcb 100644 --- a/vm/src/objdict.rs +++ b/vm/src/objdict.rs @@ -1,5 +1,8 @@ -use super::pyobject::{PyObjectRef, PyResult}; +use super::pyobject::{ + AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, +}; use super::vm::VirtualMachine; +use std::collections::HashMap; pub fn _set_item( vm: &mut VirtualMachine, @@ -11,9 +14,29 @@ pub fn _set_item( Ok(vm.get_none()) } -/* TODO: -pub fn make_type() -> PyObjectRef { - - // dict.insert("__set_item__".to_string(), _set_item); +pub fn new(dict_type: PyObjectRef) -> PyObjectRef { + PyObject::new( + PyObjectKind::Dict { + elements: HashMap::new(), + }, + dict_type.clone(), + ) +} + +fn dict_new(_vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + Ok(new(args.args[0].clone())) +} + +pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: PyObjectRef) { + (*dict_type.borrow_mut()).kind = PyObjectKind::Class { + name: String::from("dict"), + dict: new(dict_type.clone()), + mro: vec![object_type], + }; + (*dict_type.borrow_mut()).typ = Some(type_type.clone()); +} + +pub fn init(context: &PyContext) { + let ref dict_type = context.dict_type; + dict_type.set_attr("__new__", context.new_rustfunc(dict_new)); } -*/ diff --git a/vm/src/objfunction.rs b/vm/src/objfunction.rs index 95f52f1ff..b8d2e7561 100644 --- a/vm/src/objfunction.rs +++ b/vm/src/objfunction.rs @@ -44,7 +44,7 @@ fn bind_method(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.new_bound_method(args.args[0].clone(), args.args[1].clone())) } -pub fn create_member_descriptor_type(type_type: PyObjectRef, object: PyObjectRef) -> PyResult { +pub fn create_member_descriptor_type(type_type: PyObjectRef, object: PyObjectRef) -> PyObjectRef { let mut dict = HashMap::new(); dict.insert( @@ -59,10 +59,10 @@ pub fn create_member_descriptor_type(type_type: PyObjectRef, object: PyObjectRef objtype::new( type_type.clone(), - String::from("member_descriptor"), + "member_descriptor", vec![object], PyObject::new(PyObjectKind::Dict { elements: dict }, type_type.clone()), - ) + ).unwrap() } fn member_get(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { diff --git a/vm/src/objlist.rs b/vm/src/objlist.rs index ac99e5567..891ae563b 100644 --- a/vm/src/objlist.rs +++ b/vm/src/objlist.rs @@ -1,5 +1,8 @@ use super::objsequence::PySliceableSequence; -use super::pyobject::{PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult}; +use super::objtype; +use super::pyobject::{ + AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, +}; use super::vm::VirtualMachine; use std::collections::HashMap; @@ -88,43 +91,20 @@ fn reverse(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } } -pub fn create_type(type_type: PyObjectRef, method_type: PyObjectRef) -> PyObjectRef { - let mut dict = HashMap::new(); - dict.insert( - "__len__".to_string(), - PyObject::new( - PyObjectKind::RustFunction { function: len }, - method_type.clone(), - ), - ); - dict.insert( - "append".to_string(), - PyObject::new( - PyObjectKind::RustFunction { function: append }, - method_type.clone(), - ), - ); - dict.insert( - "clear".to_string(), - PyObject::new( - PyObjectKind::RustFunction { function: clear }, - method_type.clone(), - ), - ); - dict.insert( - "reverse".to_string(), - PyObject::new( - PyObjectKind::RustFunction { function: reverse }, - method_type.clone(), - ), - ); - let typ = PyObject::new( - PyObjectKind::Class { - name: "list".to_string(), - dict: PyObject::new(PyObjectKind::Dict { elements: dict }, type_type.clone()), - mro: vec![], +pub fn create_type(type_type: PyObjectRef, object: PyObjectRef) -> PyObjectRef { + let dict = PyObject::new( + PyObjectKind::Dict { + elements: HashMap::new(), }, type_type.clone(), ); - typ + objtype::new(type_type.clone(), "list", vec![object.clone()], dict).unwrap() +} + +pub fn init(context: &PyContext) { + let ref list_type = context.list_type; + list_type.set_attr("__len__", context.new_rustfunc(len)); + list_type.set_attr("append", context.new_rustfunc(append)); + list_type.set_attr("clear", context.new_rustfunc(clear)); + list_type.set_attr("reverse", context.new_rustfunc(reverse)); } diff --git a/vm/src/objobject.rs b/vm/src/objobject.rs new file mode 100644 index 000000000..0b0aefbda --- /dev/null +++ b/vm/src/objobject.rs @@ -0,0 +1,39 @@ +use super::objdict; +use super::objtype; +use super::pyobject::{ + AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, +}; +use super::vm::VirtualMachine; + +pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { + // more or less __new__ operator + let type_ref = args.shift(); + let dict = vm.new_dict(); + let obj = PyObject::new(PyObjectKind::Instance { dict: dict }, type_ref.clone()); + Ok(obj) +} + +pub fn call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { + let instance = args.shift(); + let function = objtype::get_attribute(vm, instance, &String::from("__call__"))?; + 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"), + dict: objdict::new(dict_type), + mro: vec![], + }; + (*object_type.borrow_mut()).typ = Some(type_type.clone()); +} + +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)); +} diff --git a/vm/src/objtype.rs b/vm/src/objtype.rs index bc52aefaa..449604b42 100644 --- a/vm/src/objtype.rs +++ b/vm/src/objtype.rs @@ -1,55 +1,30 @@ +use super::objdict; use super::pyobject::{ AttributeProtocol, IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, ToRust, TypeProtocol, }; use super::vm::VirtualMachine; -use std::collections::HashMap; /* * The magical type type */ -pub fn create_type() -> PyObjectRef { - let typ = PyObject { - kind: PyObjectKind::None, - typ: None, - }.into_ref(); - - let dict = PyObject::new( - PyObjectKind::Dict { - elements: HashMap::new(), - }, - typ.clone(), - ); - (*typ.borrow_mut()).kind = PyObjectKind::Class { +pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, dict_type: PyObjectRef) { + (*type_type.borrow_mut()).kind = PyObjectKind::Class { name: String::from("type"), - dict: dict, - mro: vec![], + dict: objdict::new(dict_type), + mro: vec![object_type], }; - (*typ.borrow_mut()).typ = Some(typ.clone()); - typ + (*type_type.borrow_mut()).typ = Some(type_type.clone()); } -pub fn init(context: &mut PyContext) { - context - .type_type - .set_attr(&String::from("__call__"), context.new_rustfunc(type_call)); - context - .type_type - .set_attr(&String::from("__new__"), context.new_rustfunc(type_new)); - - context.type_type.set_attr( - &String::from("__mro__"), - context.new_member_descriptor(type_mro), - ); - context.type_type.set_attr( - &String::from("__class__"), - context.new_member_descriptor(type_new), - ); - context.type_type.set_attr( - &String::from("__dict__"), - context.new_member_descriptor(type_dict), - ); +pub fn init(context: &PyContext) { + let ref type_type = context.type_type; + type_type.set_attr("__call__", context.new_rustfunc(type_call)); + 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 { @@ -87,7 +62,7 @@ pub fn type_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let mut bases = args.args[2].to_vec().unwrap(); bases.push(vm.context().object.clone()); let dict = args.args[3].clone(); - new(typ, name, bases, dict) + new(typ, &name, bases, dict) } else { Err(vm.new_exception(format!("TypeError: type_new: {:?}", args))) } @@ -99,13 +74,10 @@ pub fn type_call(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult { let new = typ.get_attr(&String::from("__new__")); let obj = vm.invoke(new, args.insert(typ.clone()))?; - match get_attribute(vm, obj.typ(), &String::from("__init__")) { - Ok(init) => { - vm.invoke(init, args.insert(obj.clone()))?; - } - Err(_) => return Ok(obj), + if obj.typ().has_attr(&String::from("__init__")) { + let init = obj.typ().get_attr(&String::from("__init__")); + vm.invoke(init, args.insert(obj.clone()))?; } - Ok(obj) } @@ -184,12 +156,12 @@ fn linearise_mro(mut bases: Vec>) -> Option> { Some(result) } -pub fn new(typ: PyObjectRef, name: String, bases: Vec, dict: PyObjectRef) -> PyResult { +pub fn new(typ: PyObjectRef, name: &str, bases: Vec, dict: PyObjectRef) -> PyResult { let mros = bases.into_iter().map(|x| _mro(x).unwrap()).collect(); let mro = linearise_mro(mros).unwrap(); Ok(PyObject::new( PyObjectKind::Class { - name: name, + name: String::from(name), dict: dict, mro: mro, }, @@ -204,7 +176,7 @@ pub fn call(vm: &mut VirtualMachine, typ: PyObjectRef, args: PyFuncArgs) -> PyRe #[cfg(test)] mod tests { - use super::{create_type, linearise_mro, new}; + use super::{linearise_mro, new}; use super::{IdProtocol, PyContext, PyObjectRef}; fn map_ids(obj: Option>) -> Option> { @@ -218,17 +190,17 @@ mod tests { fn test_linearise() { let context = PyContext::new(); let object = context.object; - let type_type = create_type(); + let type_type = context.type_type; let a = new( type_type.clone(), - String::from("A"), + "A", vec![object.clone()], type_type.clone(), ).unwrap(); let b = new( type_type.clone(), - String::from("B"), + "B", vec![object.clone()], type_type.clone(), ).unwrap(); diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 7b6aa2a71..f377c518e 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -1,8 +1,9 @@ use super::bytecode; -use super::objclass; +use super::objdict; use super::objfunction; use super::objint; use super::objlist; +use super::objobject; use super::objtype; use super::vm::VirtualMachine; use std::cell::RefCell; @@ -45,10 +46,10 @@ impl fmt::Display for PyObjectRef { pub struct PyContext { pub type_type: PyObjectRef, pub none: PyObjectRef, + pub dict_type: PyObjectRef, pub int_type: PyObjectRef, pub list_type: PyObjectRef, pub tuple_type: PyObjectRef, - pub dict_type: PyObjectRef, pub function_type: PyObjectRef, pub bound_method_type: PyObjectRef, pub member_descriptor_type: PyObjectRef, @@ -65,29 +66,45 @@ pub struct Scope { pub parent: Option, // Parent scope } +fn _nothing() -> PyObjectRef { + PyObject { + kind: PyObjectKind::None, + typ: None, + }.into_ref() +} + // Basic objects: impl PyContext { pub fn new() -> PyContext { - let type_type = objtype::create_type(); + let type_type = _nothing(); + let object_type = _nothing(); + let dict_type = _nothing(); + + objtype::create_type(type_type.clone(), object_type.clone(), dict_type.clone()); + objobject::create_object(type_type.clone(), object_type.clone(), dict_type.clone()); + objdict::create_type(type_type.clone(), object_type.clone(), dict_type.clone()); + let function_type = objfunction::create_type(type_type.clone()); let bound_method_type = objfunction::create_bound_method_type(type_type.clone()); - let object = objclass::create_object(type_type.clone(), function_type.clone()); let member_descriptor_type = - objfunction::create_member_descriptor_type(type_type.clone(), object.clone()).unwrap(); + objfunction::create_member_descriptor_type(type_type.clone(), object_type.clone()); - let mut context = PyContext { + let context = PyContext { int_type: objint::create_type(type_type.clone()), - list_type: objlist::create_type(type_type.clone(), function_type.clone()), + list_type: objlist::create_type(type_type.clone(), object_type.clone()), tuple_type: type_type.clone(), - dict_type: type_type.clone(), + dict_type: dict_type.clone(), none: PyObject::new(PyObjectKind::None, type_type.clone()), - object: object, + object: object_type, function_type: function_type, bound_method_type: bound_method_type, member_descriptor_type: member_descriptor_type, type_type: type_type, }; - objtype::init(&mut context); + objtype::init(&context); + objlist::init(&context); + objobject::init(&context); + objdict::init(&context); context } @@ -122,7 +139,7 @@ impl PyContext { PyObjectKind::Dict { elements: HashMap::new(), }, - self.type_type.clone(), + self.dict_type.clone(), ) } @@ -244,7 +261,7 @@ 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 set_attr(&self, attr_name: &str, value: PyObjectRef); fn has_attr(&self, attr_name: &String) -> bool; } @@ -303,14 +320,14 @@ impl AttributeProtocol for PyObjectRef { } } - fn set_attr(&self, attr_name: &String, value: PyObjectRef) { + fn set_attr(&self, attr_name: &str, value: PyObjectRef) { match self.borrow().kind { - PyObjectKind::Instance { ref dict } => dict.set_item(attr_name, value), + PyObjectKind::Instance { ref dict } => dict.set_item(&String::from(attr_name), value), PyObjectKind::Class { name: _, ref dict, mro: _, - } => dict.set_item(attr_name, value), + } => dict.set_item(&String::from(attr_name), value), ref kind => unimplemented!("set_attr unimplemented for: {:?}", kind), }; } diff --git a/vm/src/vm.rs b/vm/src/vm.rs index e3d254c9a..d6bfbe621 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -12,8 +12,8 @@ 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::objobject; use super::objstr; use super::objtype; use super::pyobject::{ @@ -489,7 +489,7 @@ impl VirtualMachine { ref function, ref object, } => self.invoke(function.clone(), args.insert(object.clone())), - PyObjectKind::Instance { .. } => objclass::call(self, args.insert(func_ref.clone())), + PyObjectKind::Instance { .. } => objobject::call(self, args.insert(func_ref.clone())), ref kind => { unimplemented!("invoke unimplemented for: {:?}", kind); } @@ -795,7 +795,7 @@ impl VirtualMachine { PyObjectKind::RustFunction { function: builtins::builtin_build_class_, }, - objtype::create_type(), + self.ctx.type_type.clone(), ); self.push_value(rustfunc); None