Compare commits

...

4 Commits

Author SHA1 Message Date
Adam Kelly
1d1a931011 Move attributes dictionary to PyObject. 2019-03-05 17:09:48 +00:00
Adam Kelly
2d78425bab Add (unused) dict element to PyObject struct. 2019-03-05 16:27:51 +00:00
Adam Kelly
43118db1b0 Remove None and NotImplemented payloads and replace with NoPayload 2019-03-05 15:50:07 +00:00
Adam Kelly
647cb08d78 Remove special case for None payload from boolval. 2019-03-05 15:05:52 +00:00
10 changed files with 113 additions and 101 deletions

View File

@@ -16,6 +16,9 @@ assert bool() == False
assert bool(1) == True assert bool(1) == True
assert bool({}) == False assert bool({}) == False
assert bool(NotImplemented) == True
assert bool(...) == True
if not 1: if not 1:
raise BaseException raise BaseException

View File

@@ -285,10 +285,14 @@ impl Frame {
let mut out: Vec<Option<BigInt>> = elements let mut out: Vec<Option<BigInt>> = elements
.into_iter() .into_iter()
.map(|x| match x.payload { .map(|x| {
PyObjectPayload::Integer { ref value } => Some(value.clone()), if x.is(&vm.get_none()) {
PyObjectPayload::None => None, None
_ => panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x), } else if let PyObjectPayload::Integer { ref value } = x.payload {
Some(value.clone())
} else {
panic!("Expect Int or None as BUILD_SLICE arguments, got {:?}", x);
}
}) })
.collect(); .collect();
@@ -574,18 +578,15 @@ impl Frame {
} }
bytecode::Instruction::PrintExpr => { bytecode::Instruction::PrintExpr => {
let expr = self.pop_value(); let expr = self.pop_value();
match expr.payload { if !expr.is(&vm.get_none()) {
PyObjectPayload::None => (), let repr = vm.to_repr(&expr)?;
_ => { builtins::builtin_print(
let repr = vm.to_repr(&expr)?; vm,
builtins::builtin_print( PyFuncArgs {
vm, args: vec![repr],
PyFuncArgs { kwargs: vec![],
args: vec![repr], },
kwargs: vec![], )?;
},
)?;
}
} }
Ok(None) Ok(None)
} }

View File

@@ -13,7 +13,7 @@ impl IntoPyObject for bool {
} }
} }
pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObjectRef> { pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
if let Some(s) = obj.payload::<PyString>() { if let Some(s) = obj.payload::<PyString>() {
return Ok(!s.value.is_empty()); return Ok(!s.value.is_empty());
} }
@@ -24,7 +24,6 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObje
PyObjectPayload::Integer { ref value } => !value.is_zero(), PyObjectPayload::Integer { ref value } => !value.is_zero(),
PyObjectPayload::Sequence { ref elements } => !elements.borrow().is_empty(), PyObjectPayload::Sequence { ref elements } => !elements.borrow().is_empty(),
PyObjectPayload::Dict { ref elements } => !elements.borrow().is_empty(), PyObjectPayload::Dict { ref elements } => !elements.borrow().is_empty(),
PyObjectPayload::None { .. } => false,
_ => { _ => {
if let Ok(f) = vm.get_method(obj.clone(), "__bool__") { if let Ok(f) = vm.get_method(obj.clone(), "__bool__") {
let bool_res = vm.invoke(f, PyFuncArgs::default())?; let bool_res = vm.invoke(f, PyFuncArgs::default())?;

View File

@@ -311,9 +311,9 @@ pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, dict_type:
unsafe { unsafe {
(*ptr).payload = PyObjectPayload::Class { (*ptr).payload = PyObjectPayload::Class {
name: String::from("dict"), name: String::from("dict"),
dict: RefCell::new(HashMap::new()),
mro: vec![object_type], mro: vec![object_type],
}; };
(*ptr).dict = Some(RefCell::new(HashMap::new()));
(*ptr).typ = Some(type_type.clone()); (*ptr).typ = Some(type_type.clone());
} }
} }

View File

@@ -5,6 +5,7 @@ pub fn init(context: &PyContext) {
let none_type = &context.none.typ(); let none_type = &context.none.typ();
context.set_attr(&none_type, "__new__", context.new_rustfunc(none_new)); context.set_attr(&none_type, "__new__", context.new_rustfunc(none_new));
context.set_attr(&none_type, "__repr__", context.new_rustfunc(none_repr)); context.set_attr(&none_type, "__repr__", context.new_rustfunc(none_repr));
context.set_attr(&none_type, "__bool__", context.new_rustfunc(none_bool));
} }
fn none_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn none_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -20,3 +21,8 @@ fn none_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(_zelf, Some(vm.ctx.none().typ()))]); arg_check!(vm, args, required = [(_zelf, Some(vm.ctx.none().typ()))]);
Ok(vm.ctx.new_str("None".to_string())) Ok(vm.ctx.new_str("None".to_string()))
} }
fn none_bool(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(_zelf, Some(vm.ctx.none().typ()))]);
Ok(vm.ctx.new_bool(false))
}

View File

@@ -21,9 +21,9 @@ pub fn create_object(type_type: PyObjectRef, object_type: PyObjectRef, _dict_typ
unsafe { unsafe {
(*ptr).payload = PyObjectPayload::Class { (*ptr).payload = PyObjectPayload::Class {
name: String::from("object"), name: String::from("object"),
dict: RefCell::new(HashMap::new()),
mro: vec![], mro: vec![],
}; };
(*ptr).dict = Some(RefCell::new(HashMap::new()));
(*ptr).typ = Some(type_type.clone()); (*ptr).typ = Some(type_type.clone());
} }
} }
@@ -105,13 +105,13 @@ fn object_delattr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
] ]
); );
match zelf.payload { match zelf.dict {
PyObjectPayload::Class { ref dict, .. } | PyObjectPayload::Instance { ref dict, .. } => { Some(ref dict) => {
let attr_name = objstr::get_value(attr); let attr_name = objstr::get_value(attr);
dict.borrow_mut().remove(&attr_name); dict.borrow_mut().remove(&attr_name);
Ok(vm.get_none()) Ok(vm.get_none())
} }
_ => Err(vm.new_type_error("TypeError: no dictionary.".to_string())), None => Err(vm.new_type_error("TypeError: no dictionary.".to_string())),
} }
} }
@@ -178,15 +178,14 @@ fn object_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult {
} }
fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn object_dict(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
match args.args[0].payload { if let Some(ref dict) = args.args[0].dict {
PyObjectPayload::Class { ref dict, .. } | PyObjectPayload::Instance { ref dict, .. } => { let new_dict = vm.new_dict();
let new_dict = vm.new_dict(); for (attr, value) in dict.borrow().iter() {
for (attr, value) in dict.borrow().iter() { new_dict.set_item(&vm.ctx, &attr, value.clone());
new_dict.set_item(&vm.ctx, &attr, value.clone());
}
Ok(new_dict)
} }
_ => Err(vm.new_type_error("TypeError: no dictionary.".to_string())), Ok(new_dict)
} else {
Err(vm.new_type_error("TypeError: no dictionary.".to_string()))
} }
} }

View File

@@ -19,9 +19,9 @@ pub fn create_type(type_type: PyObjectRef, object_type: PyObjectRef, _dict_type:
unsafe { unsafe {
(*ptr).payload = PyObjectPayload::Class { (*ptr).payload = PyObjectPayload::Class {
name: String::from("type"), name: String::from("type"),
dict: RefCell::new(PyAttributes::new()),
mro: vec![object_type], mro: vec![object_type],
}; };
(*ptr).dict = Some(RefCell::new(PyAttributes::new()));
(*ptr).typ = Some(type_type); (*ptr).typ = Some(type_type);
} }
} }
@@ -264,26 +264,26 @@ pub fn get_attributes(obj: &PyObjectRef) -> PyAttributes {
let mut base_classes = objtype::base_classes(obj); let mut base_classes = objtype::base_classes(obj);
base_classes.reverse(); base_classes.reverse();
for bc in base_classes { for bc in base_classes {
if let PyObjectPayload::Class { dict, .. } = &bc.payload { if let Some(ref dict) = &bc.dict {
for (name, value) in dict.borrow().iter() { for (name, value) in dict.borrow().iter() {
attributes.insert(name.to_string(), value.clone()); attributes.insert(name.to_string(), value.clone());
} }
} }
} }
// Get instance attributes:
if let PyObjectPayload::Instance { dict } = &obj.payload {
for (name, value) in dict.borrow().iter() {
attributes.insert(name.to_string(), value.clone());
}
}
// Get module attributes: // Get module attributes:
if let PyObjectPayload::Module { ref scope, .. } = &obj.payload { if let PyObjectPayload::Module { ref scope, .. } = &obj.payload {
for (name, value) in scope.locals.get_key_value_pairs().iter() { for (name, value) in scope.locals.get_key_value_pairs().iter() {
attributes.insert(objstr::get_value(name).to_string(), value.clone()); attributes.insert(objstr::get_value(name).to_string(), value.clone());
} }
} else {
if let Some(ref dict) = &obj.dict {
for (name, value) in dict.borrow().iter() {
attributes.insert(name.to_string(), value.clone());
}
}
} }
attributes attributes
} }
@@ -342,14 +342,15 @@ pub fn new(
) -> PyResult { ) -> PyResult {
let mros = bases.into_iter().map(|x| _mro(x).unwrap()).collect(); let mros = bases.into_iter().map(|x| _mro(x).unwrap()).collect();
let mro = linearise_mro(mros).unwrap(); let mro = linearise_mro(mros).unwrap();
Ok(PyObject::new( Ok(PyObject {
PyObjectPayload::Class { payload: PyObjectPayload::Class {
name: String::from(name), name: String::from(name),
dict: RefCell::new(dict),
mro, mro,
}, },
typ, dict: Some(RefCell::new(dict)),
)) typ: Some(typ),
}
.into_ref())
} }
fn type_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn type_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {

View File

@@ -154,11 +154,8 @@ pub struct PyContext {
} }
fn _nothing() -> PyObjectRef { fn _nothing() -> PyObjectRef {
PyObject { let obj: PyObject = Default::default();
payload: PyObjectPayload::None, obj.into_ref()
typ: None,
}
.into_ref()
} }
pub fn create_type( pub fn create_type(
@@ -223,14 +220,14 @@ impl PyContext {
let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type, &dict_type); let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type, &dict_type);
let none = PyObject::new( let none = PyObject::new(
PyObjectPayload::None, PyObjectPayload::NoPayload,
create_type("NoneType", &type_type, &object_type, &dict_type), create_type("NoneType", &type_type, &object_type, &dict_type),
); );
let ellipsis = PyObject::new(PyObjectPayload::None, ellipsis_type.clone()); let ellipsis = PyObject::new(PyObjectPayload::NoPayload, ellipsis_type.clone());
let not_implemented = PyObject::new( let not_implemented = PyObject::new(
PyObjectPayload::NotImplemented, PyObjectPayload::NoPayload,
create_type("NotImplementedType", &type_type, &object_type, &dict_type), create_type("NotImplementedType", &type_type, &object_type, &dict_type),
); );
@@ -658,12 +655,12 @@ impl PyContext {
} else { } else {
PyAttributes::new() PyAttributes::new()
}; };
PyObject::new( PyObject {
PyObjectPayload::Instance { payload: PyObjectPayload::NoPayload,
dict: RefCell::new(dict), typ: Some(class),
}, dict: Some(RefCell::new(dict)),
class, }
) .into_ref()
} }
// Item set/get: // Item set/get:
@@ -685,14 +682,12 @@ impl PyContext {
} }
pub fn set_attr(&self, obj: &PyObjectRef, attr_name: &str, value: PyObjectRef) { pub fn set_attr(&self, obj: &PyObjectRef, attr_name: &str, value: PyObjectRef) {
match obj.payload { if let PyObjectPayload::Module { ref scope, .. } = obj.payload {
PyObjectPayload::Module { ref scope, .. } => { scope.locals.set_item(self, attr_name, value)
scope.locals.set_item(self, attr_name, value) } else if let Some(ref dict) = obj.dict {
} dict.borrow_mut().insert(attr_name.to_string(), value);
PyObjectPayload::Instance { ref dict } | PyObjectPayload::Class { ref dict, .. } => { } else {
dict.borrow_mut().insert(attr_name.to_string(), value); unimplemented!("set_attr unimplemented for: {:?}", obj);
}
ref payload => unimplemented!("set_attr unimplemented for: {:?}", payload),
}; };
} }
@@ -727,10 +722,11 @@ impl Default for PyContext {
/// This is an actual python object. It consists of a `typ` which is the /// This is an actual python object. It consists of a `typ` which is the
/// python class, and carries some rust payload optionally. This rust /// python class, and carries some rust payload optionally. This rust
/// payload can be a rust float or rust int in case of float and int objects. /// payload can be a rust float or rust int in case of float and int objects.
#[derive(Default)]
pub struct PyObject { pub struct PyObject {
pub payload: PyObjectPayload, pub payload: PyObjectPayload,
pub typ: Option<PyObjectRef>, pub typ: Option<PyObjectRef>,
// pub dict: HashMap<String, PyObjectRef>, // __dict__ member pub dict: Option<RefCell<PyAttributes>>, // __dict__ member
} }
pub trait IdProtocol { pub trait IdProtocol {
@@ -777,16 +773,18 @@ pub trait AttributeProtocol {
} }
fn class_get_item(class: &PyObjectRef, attr_name: &str) -> Option<PyObjectRef> { fn class_get_item(class: &PyObjectRef, attr_name: &str) -> Option<PyObjectRef> {
match class.payload { if let Some(ref dict) = class.dict {
PyObjectPayload::Class { ref dict, .. } => dict.borrow().get(attr_name).cloned(), dict.borrow().get(attr_name).cloned()
_ => panic!("Only classes should be in MRO!"), } else {
panic!("Only classes should be in MRO!");
} }
} }
fn class_has_item(class: &PyObjectRef, attr_name: &str) -> bool { fn class_has_item(class: &PyObjectRef, attr_name: &str) -> bool {
match class.payload { if let Some(ref dict) = class.dict {
PyObjectPayload::Class { ref dict, .. } => dict.borrow().contains_key(attr_name), dict.borrow().contains_key(attr_name)
_ => panic!("Only classes should be in MRO!"), } else {
panic!("Only classes should be in MRO!");
} }
} }
@@ -805,8 +803,13 @@ impl AttributeProtocol for PyObjectRef {
} }
None None
} }
PyObjectPayload::Instance { ref dict } => dict.borrow().get(attr_name).cloned(), _ => {
_ => None, if let Some(ref dict) = self.dict {
dict.borrow().get(attr_name).cloned()
} else {
None
}
}
} }
} }
@@ -816,8 +819,13 @@ impl AttributeProtocol for PyObjectRef {
PyObjectPayload::Class { ref mro, .. } => { PyObjectPayload::Class { ref mro, .. } => {
class_has_item(self, attr_name) || mro.iter().any(|d| class_has_item(d, attr_name)) class_has_item(self, attr_name) || mro.iter().any(|d| class_has_item(d, attr_name))
} }
PyObjectPayload::Instance { ref dict } => dict.borrow().contains_key(attr_name), _ => {
_ => false, if let Some(ref dict) = self.dict {
dict.borrow().contains_key(attr_name)
} else {
false
}
}
} }
} }
} }
@@ -1484,11 +1492,9 @@ pub enum PyObjectPayload {
name: String, name: String,
scope: ScopeRef, scope: ScopeRef,
}, },
None, NoPayload,
NotImplemented,
Class { Class {
name: String, name: String,
dict: RefCell<PyAttributes>,
mro: Vec<PyObjectRef>, mro: Vec<PyObjectRef>,
}, },
Set { Set {
@@ -1497,9 +1503,6 @@ pub enum PyObjectPayload {
WeakRef { WeakRef {
referent: PyObjectWeakRef, referent: PyObjectWeakRef,
}, },
Instance {
dict: RefCell<PyAttributes>,
},
RustFunction { RustFunction {
function: PyNativeFunc, function: PyNativeFunc,
}, },
@@ -1508,6 +1511,12 @@ pub enum PyObjectPayload {
}, },
} }
impl Default for PyObjectPayload {
fn default() -> Self {
PyObjectPayload::NoPayload
}
}
impl fmt::Debug for PyObjectPayload { impl fmt::Debug for PyObjectPayload {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -1531,10 +1540,8 @@ impl fmt::Debug for PyObjectPayload {
ref object, ref object,
} => write!(f, "bound-method: {:?} of {:?}", function, object), } => write!(f, "bound-method: {:?} of {:?}", function, object),
PyObjectPayload::Module { .. } => write!(f, "module"), PyObjectPayload::Module { .. } => write!(f, "module"),
PyObjectPayload::None => write!(f, "None"), PyObjectPayload::NoPayload => write!(f, "NoPayload"),
PyObjectPayload::NotImplemented => write!(f, "NotImplemented"),
PyObjectPayload::Class { ref name, .. } => write!(f, "class {:?}", name), PyObjectPayload::Class { ref name, .. } => write!(f, "class {:?}", name),
PyObjectPayload::Instance { .. } => write!(f, "instance"),
PyObjectPayload::RustFunction { .. } => write!(f, "rust function"), PyObjectPayload::RustFunction { .. } => write!(f, "rust function"),
PyObjectPayload::Frame { .. } => write!(f, "frame"), PyObjectPayload::Frame { .. } => write!(f, "frame"),
PyObjectPayload::AnyRustValue { .. } => write!(f, "some rust value"), PyObjectPayload::AnyRustValue { .. } => write!(f, "some rust value"),
@@ -1543,14 +1550,11 @@ impl fmt::Debug for PyObjectPayload {
} }
impl PyObject { impl PyObject {
pub fn new( pub fn new(payload: PyObjectPayload, typ: PyObjectRef) -> PyObjectRef {
payload: PyObjectPayload,
/* dict: PyObjectRef,*/ typ: PyObjectRef,
) -> PyObjectRef {
PyObject { PyObject {
payload, payload,
typ: Some(typ), typ: Some(typ),
// dict: HashMap::new(), // dict, dict: None,
} }
.into_ref() .into_ref()
} }

View File

@@ -11,7 +11,7 @@ use crate::obj::{
objtype, objtype,
}; };
use crate::pyobject::{ use crate::pyobject::{
create_type, DictProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, create_type, DictProtocol, IdProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult,
TypeProtocol, TypeProtocol,
}; };
use crate::VirtualMachine; use crate::VirtualMachine;
@@ -69,7 +69,7 @@ impl<'s> serde::Serialize for PyObjectSerializer<'s> {
map.serialize_entry(&key, &self.clone_with_object(&e.1))?; map.serialize_entry(&key, &self.clone_with_object(&e.1))?;
} }
map.end() map.end()
} else if let PyObjectPayload::None = self.pyobject.payload { } else if self.pyobject.is(&self.vm.get_none()) {
serializer.serialize_none() serializer.serialize_none()
} else { } else {
Err(serde::ser::Error::custom(format!( Err(serde::ser::Error::custom(format!(

View File

@@ -330,9 +330,6 @@ impl VirtualMachine {
ref function, ref function,
ref object, ref object,
} => self.invoke(function.clone(), args.insert(object.clone())), } => self.invoke(function.clone(), args.insert(object.clone())),
PyObjectPayload::Instance { .. } => {
self.call_method_pyargs(&func_ref, "__call__", args)
}
ref payload => { ref payload => {
// TODO: is it safe to just invoke __call__ otherwise? // TODO: is it safe to just invoke __call__ otherwise?
trace!("invoke __call__ for: {:?}", payload); trace!("invoke __call__ for: {:?}", payload);
@@ -473,10 +470,12 @@ impl VirtualMachine {
// Add missing positional arguments, if we have fewer positional arguments than the // Add missing positional arguments, if we have fewer positional arguments than the
// function definition calls for // function definition calls for
if nargs < nexpected_args { if nargs < nexpected_args {
let available_defaults = match defaults.payload { let available_defaults = if defaults.is(&self.get_none()) {
PyObjectPayload::Sequence { ref elements } => elements.borrow().clone(), vec![]
PyObjectPayload::None => vec![], } else if let PyObjectPayload::Sequence { ref elements } = defaults.payload {
_ => panic!("function defaults not tuple or None"), elements.borrow().clone()
} else {
panic!("function defaults not tuple or None");
}; };
// Given the number of defaults available, check all the arguments for which we // Given the number of defaults available, check all the arguments for which we