mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-09 22:49:57 +09:00
@@ -1,84 +1,238 @@
|
||||
use super::objbool;
|
||||
use super::objdict::PyDictRef;
|
||||
use super::objlist::PyList;
|
||||
use super::objproperty::PropertyBuilder;
|
||||
use super::objstr::PyStringRef;
|
||||
use super::objtype::{self, PyClassRef};
|
||||
use crate::function::{OptionalArg, PyFuncArgs};
|
||||
use crate::pyhash;
|
||||
use crate::pyobject::{
|
||||
IdProtocol, ItemProtocol, PyArithmaticValue::*, PyAttributes, PyComparisonValue, PyContext,
|
||||
PyObject, PyObjectRef, PyResult, PyValue, TryFromObject, TypeProtocol,
|
||||
IdProtocol, ItemProtocol, PyArithmaticValue::*, PyAttributes, PyClassImpl, PyComparisonValue,
|
||||
PyContext, PyObject, PyObjectRef, PyResult, PyValue, TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::slots::PyTpFlags;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
/// The most base type
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
pub struct PyInstance;
|
||||
pub struct PyBaseObject;
|
||||
|
||||
impl PyValue for PyInstance {
|
||||
impl PyValue for PyBaseObject {
|
||||
fn class(vm: &VirtualMachine) -> PyClassRef {
|
||||
vm.ctx.object()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_instance(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResult {
|
||||
// more or less __new__ operator
|
||||
let cls = PyClassRef::try_from_object(vm, args.shift())?;
|
||||
let dict = if cls.is(&vm.ctx.object()) {
|
||||
None
|
||||
} else {
|
||||
Some(vm.ctx.new_dict())
|
||||
};
|
||||
Ok(PyObject::new(PyInstance, cls, dict))
|
||||
}
|
||||
#[pyimpl(flags(BASETYPE))]
|
||||
impl PyBaseObject {
|
||||
#[pyslot]
|
||||
fn tp_new(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResult {
|
||||
// more or less __new__ operator
|
||||
let cls = PyClassRef::try_from_object(vm, args.shift())?;
|
||||
let dict = if cls.is(&vm.ctx.object()) {
|
||||
None
|
||||
} else {
|
||||
Some(vm.ctx.new_dict())
|
||||
};
|
||||
Ok(PyObject::new(PyBaseObject, cls, dict))
|
||||
}
|
||||
|
||||
fn object_eq(zelf: PyObjectRef, other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
if zelf.is(&other) {
|
||||
Implemented(true)
|
||||
} else {
|
||||
#[pymethod(magic)]
|
||||
fn eq(zelf: PyObjectRef, other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
if zelf.is(&other) {
|
||||
Implemented(true)
|
||||
} else {
|
||||
NotImplemented
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn ne(
|
||||
zelf: PyObjectRef,
|
||||
other: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyComparisonValue> {
|
||||
let eq_method = match vm.get_method(zelf, "__eq__") {
|
||||
Some(func) => func?,
|
||||
None => return Ok(NotImplemented), // XXX: is this a possible case?
|
||||
};
|
||||
let eq = vm.invoke(&eq_method, vec![other])?;
|
||||
if eq.is(&vm.ctx.not_implemented()) {
|
||||
return Ok(NotImplemented);
|
||||
}
|
||||
let bool_eq = objbool::boolval(vm, eq)?;
|
||||
Ok(Implemented(!bool_eq))
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn lt(_zelf: PyObjectRef, _other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
NotImplemented
|
||||
}
|
||||
}
|
||||
|
||||
fn object_ne(
|
||||
zelf: PyObjectRef,
|
||||
other: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyComparisonValue> {
|
||||
let eq_method = match vm.get_method(zelf, "__eq__") {
|
||||
Some(func) => func?,
|
||||
None => return Ok(NotImplemented), // XXX: is this a possible case?
|
||||
};
|
||||
let eq = vm.invoke(&eq_method, vec![other])?;
|
||||
if eq.is(&vm.ctx.not_implemented()) {
|
||||
return Ok(NotImplemented);
|
||||
#[pymethod(magic)]
|
||||
fn le(_zelf: PyObjectRef, _other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
NotImplemented
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn gt(_zelf: PyObjectRef, _other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
NotImplemented
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn ge(_zelf: PyObjectRef, _other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
NotImplemented
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn hash(zelf: PyObjectRef, _vm: &VirtualMachine) -> pyhash::PyHash {
|
||||
zelf.get_id() as pyhash::PyHash
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
pub(crate) fn setattr(
|
||||
obj: PyObjectRef,
|
||||
attr_name: PyStringRef,
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
setattr(obj, attr_name, value, vm)
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn delattr(obj: PyObjectRef, attr_name: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let cls = obj.class();
|
||||
|
||||
if let Some(attr) = cls.get_attr(attr_name.as_str()) {
|
||||
if let Some(descriptor) = attr.class().get_attr("__delete__") {
|
||||
return vm.invoke(&descriptor, vec![attr, obj.clone()]).map(|_| ());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref dict) = obj.dict {
|
||||
dict.borrow().del_item(attr_name.as_str(), vm)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"'{}' object has no attribute '{}'",
|
||||
obj.class().name,
|
||||
attr_name.as_str()
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn str(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm.call_method(&zelf, "__repr__", vec![])
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn repr(zelf: PyObjectRef, _vm: &VirtualMachine) -> String {
|
||||
format!("<{} object at 0x{:x}>", zelf.class().name, zelf.get_id())
|
||||
}
|
||||
|
||||
#[pyclassmethod(magic)]
|
||||
fn subclasshook(vm: &VirtualMachine, _args: PyFuncArgs) -> PyResult {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
pub fn dir(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyList> {
|
||||
let attributes: PyAttributes = obj.class().get_attributes();
|
||||
|
||||
let dict = PyDictRef::from_attributes(attributes, vm)?;
|
||||
|
||||
// Get instance attributes:
|
||||
if let Some(object_dict) = &obj.dict {
|
||||
vm.invoke(
|
||||
&vm.get_attribute(dict.clone().into_object(), "update")?,
|
||||
object_dict.borrow().clone().into_object(),
|
||||
)?;
|
||||
}
|
||||
|
||||
let attributes: Vec<_> = dict.into_iter().map(|(k, _v)| k).collect();
|
||||
|
||||
Ok(PyList::from(attributes))
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn format(
|
||||
obj: PyObjectRef,
|
||||
format_spec: PyStringRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyStringRef> {
|
||||
if format_spec.as_str().is_empty() {
|
||||
vm.to_str(&obj)
|
||||
} else {
|
||||
Err(vm.new_type_error(
|
||||
"unsupported format string passed to object.__format__".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn init(vm: &VirtualMachine, _args: PyFuncArgs) -> PyResult {
|
||||
Ok(vm.ctx.none())
|
||||
}
|
||||
|
||||
#[pyproperty(name = "__class__")]
|
||||
fn _class(obj: PyObjectRef, _vm: &VirtualMachine) -> PyObjectRef {
|
||||
obj.class().into_object()
|
||||
}
|
||||
|
||||
#[pyproperty(name = "__class__", setter)]
|
||||
fn _set_class(instance: PyObjectRef, _value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let type_repr = vm.to_pystr(&instance.class())?;
|
||||
Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr)))
|
||||
}
|
||||
|
||||
#[pyproperty(magic)]
|
||||
fn dict(object: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyDictRef> {
|
||||
if let Some(ref dict) = object.dict {
|
||||
Ok(dict.borrow().clone())
|
||||
} else {
|
||||
Err(vm.new_attribute_error("no dictionary.".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproperty(magic, setter)]
|
||||
fn set_dict(instance: PyObjectRef, value: PyDictRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if let Some(dict) = &instance.dict {
|
||||
*dict.borrow_mut() = value;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"'{}' object has no attribute '__dict__'",
|
||||
instance.class().name
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn getattribute(obj: PyObjectRef, name: PyStringRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm_trace!("object.__getattribute__({:?}, {:?})", obj, name);
|
||||
vm.generic_getattribute(obj.clone(), name.clone())?
|
||||
.ok_or_else(|| vm.new_attribute_error(format!("{} has no attribute '{}'", obj, name)))
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn reduce(obj: PyObjectRef, proto: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult {
|
||||
common_reduce(obj, proto.unwrap_or(0), vm)
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn reduce_ex(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {
|
||||
let cls = obj.class();
|
||||
if let Some(reduce) = cls.get_attr("__reduce__") {
|
||||
let object_reduce = vm.ctx.types.object_type.get_attr("__reduce__").unwrap();
|
||||
if !reduce.is(&object_reduce) {
|
||||
return vm.invoke(&reduce, vec![]);
|
||||
}
|
||||
}
|
||||
common_reduce(obj, proto, vm)
|
||||
}
|
||||
let bool_eq = objbool::boolval(vm, eq)?;
|
||||
Ok(Implemented(!bool_eq))
|
||||
}
|
||||
|
||||
fn object_lt(_zelf: PyObjectRef, _other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
NotImplemented
|
||||
}
|
||||
|
||||
fn object_le(_zelf: PyObjectRef, _other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
NotImplemented
|
||||
}
|
||||
|
||||
fn object_gt(_zelf: PyObjectRef, _other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
NotImplemented
|
||||
}
|
||||
|
||||
fn object_ge(_zelf: PyObjectRef, _other: PyObjectRef, _vm: &VirtualMachine) -> PyComparisonValue {
|
||||
NotImplemented
|
||||
}
|
||||
|
||||
fn object_hash(zelf: PyObjectRef, _vm: &VirtualMachine) -> pyhash::PyHash {
|
||||
zelf.get_id() as pyhash::PyHash
|
||||
}
|
||||
|
||||
pub(crate) fn object_setattr(
|
||||
pub(crate) fn setattr(
|
||||
obj: PyObjectRef,
|
||||
attr_name: PyStringRef,
|
||||
value: PyObjectRef,
|
||||
@@ -107,173 +261,14 @@ pub(crate) fn object_setattr(
|
||||
}
|
||||
}
|
||||
|
||||
fn object_delattr(obj: PyObjectRef, attr_name: PyStringRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let cls = obj.class();
|
||||
|
||||
if let Some(attr) = cls.get_attr(attr_name.as_str()) {
|
||||
if let Some(descriptor) = attr.class().get_attr("__delete__") {
|
||||
return vm.invoke(&descriptor, vec![attr, obj.clone()]).map(|_| ());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref dict) = obj.dict {
|
||||
dict.borrow().del_item(attr_name.as_str(), vm)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"'{}' object has no attribute '{}'",
|
||||
obj.class().name,
|
||||
attr_name.as_str()
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn object_str(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm.call_method(&zelf, "__repr__", vec![])
|
||||
}
|
||||
|
||||
fn object_repr(zelf: PyObjectRef, _vm: &VirtualMachine) -> String {
|
||||
format!("<{} object at 0x{:x}>", zelf.class().name, zelf.get_id())
|
||||
}
|
||||
|
||||
fn object_subclasshook(vm: &VirtualMachine, _args: PyFuncArgs) -> PyResult {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
}
|
||||
|
||||
pub fn object_dir(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyList> {
|
||||
let attributes: PyAttributes = obj.class().get_attributes();
|
||||
|
||||
let dict = PyDictRef::from_attributes(attributes, vm)?;
|
||||
|
||||
// Get instance attributes:
|
||||
if let Some(object_dict) = &obj.dict {
|
||||
vm.invoke(
|
||||
&vm.get_attribute(dict.clone().into_object(), "update")?,
|
||||
object_dict.borrow().clone().into_object(),
|
||||
)?;
|
||||
}
|
||||
|
||||
let attributes: Vec<_> = dict.into_iter().map(|(k, _v)| k).collect();
|
||||
|
||||
Ok(PyList::from(attributes))
|
||||
}
|
||||
|
||||
fn object_format(
|
||||
obj: PyObjectRef,
|
||||
format_spec: PyStringRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyStringRef> {
|
||||
if format_spec.as_str().is_empty() {
|
||||
vm.to_str(&obj)
|
||||
} else {
|
||||
Err(vm.new_type_error("unsupported format string passed to object.__format__".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
let object = &context.types.object_type;
|
||||
let object_doc = "The most base type";
|
||||
|
||||
object.slots.borrow_mut().flags |= PyTpFlags::BASETYPE;
|
||||
|
||||
extend_class!(context, object, {
|
||||
(slot new) => new_instance,
|
||||
PyBaseObject::extend_class(context, &context.types.object_type);
|
||||
extend_class!(context, &context.types.object_type, {
|
||||
// yeah, it's `type_new`, but we're putting here so it's available on every object
|
||||
"__new__" => context.new_classmethod(objtype::type_new),
|
||||
"__init__" => context.new_method(object_init),
|
||||
"__class__" =>
|
||||
PropertyBuilder::new(context)
|
||||
.add_getter(object_class)
|
||||
.add_setter(object_class_setter)
|
||||
.create(),
|
||||
"__eq__" => context.new_method(object_eq),
|
||||
"__ne__" => context.new_method(object_ne),
|
||||
"__lt__" => context.new_method(object_lt),
|
||||
"__le__" => context.new_method(object_le),
|
||||
"__gt__" => context.new_method(object_gt),
|
||||
"__ge__" => context.new_method(object_ge),
|
||||
"__setattr__" => context.new_method(object_setattr),
|
||||
"__delattr__" => context.new_method(object_delattr),
|
||||
"__dict__" =>
|
||||
PropertyBuilder::new(context)
|
||||
.add_getter(object_dict)
|
||||
.add_setter(object_dict_setter)
|
||||
.create(),
|
||||
"__dir__" => context.new_method(object_dir),
|
||||
"__hash__" => context.new_method(object_hash),
|
||||
"__str__" => context.new_method(object_str),
|
||||
"__repr__" => context.new_method(object_repr),
|
||||
"__format__" => context.new_method(object_format),
|
||||
"__getattribute__" => context.new_method(object_getattribute),
|
||||
"__subclasshook__" => context.new_classmethod(object_subclasshook),
|
||||
"__reduce__" => context.new_method(object_reduce),
|
||||
"__reduce_ex__" => context.new_method(object_reduce_ex),
|
||||
"__doc__" => context.new_str(object_doc.to_string()),
|
||||
});
|
||||
}
|
||||
|
||||
fn object_init(vm: &VirtualMachine, _args: PyFuncArgs) -> PyResult {
|
||||
Ok(vm.ctx.none())
|
||||
}
|
||||
|
||||
fn object_class(obj: PyObjectRef, _vm: &VirtualMachine) -> PyObjectRef {
|
||||
obj.class().into_object()
|
||||
}
|
||||
|
||||
fn object_class_setter(
|
||||
instance: PyObjectRef,
|
||||
_value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let type_repr = vm.to_pystr(&instance.class())?;
|
||||
Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr)))
|
||||
}
|
||||
|
||||
fn object_dict(object: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyDictRef> {
|
||||
if let Some(ref dict) = object.dict {
|
||||
Ok(dict.borrow().clone())
|
||||
} else {
|
||||
Err(vm.new_attribute_error("no dictionary.".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn object_dict_setter(
|
||||
instance: PyObjectRef,
|
||||
value: PyDictRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
if let Some(dict) = &instance.dict {
|
||||
*dict.borrow_mut() = value;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"'{}' object has no attribute '__dict__'",
|
||||
instance.class().name
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn object_getattribute(obj: PyObjectRef, name: PyStringRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm_trace!("object.__getattribute__({:?}, {:?})", obj, name);
|
||||
vm.generic_getattribute(obj.clone(), name.clone())?
|
||||
.ok_or_else(|| vm.new_attribute_error(format!("{} has no attribute '{}'", obj, name)))
|
||||
}
|
||||
|
||||
fn object_reduce(obj: PyObjectRef, proto: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult {
|
||||
common_reduce(obj, proto.unwrap_or(0), vm)
|
||||
}
|
||||
|
||||
fn object_reduce_ex(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {
|
||||
let cls = obj.class();
|
||||
if let Some(reduce) = cls.get_attr("__reduce__") {
|
||||
let object_reduce = vm.ctx.types.object_type.get_attr("__reduce__").unwrap();
|
||||
if !reduce.is(&object_reduce) {
|
||||
return vm.invoke(&reduce, vec![]);
|
||||
}
|
||||
}
|
||||
common_reduce(obj, proto, vm)
|
||||
}
|
||||
|
||||
fn common_reduce(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {
|
||||
if proto >= 2 {
|
||||
let reducelib = vm.import("__reducelib", &[], 0)?;
|
||||
|
||||
@@ -534,11 +534,11 @@ impl PyContext {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_instance(&self, class: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
|
||||
pub fn new_base_object(&self, class: PyClassRef, dict: Option<PyDictRef>) -> PyObjectRef {
|
||||
PyObject {
|
||||
typ: class,
|
||||
dict: dict.map(RefCell::new),
|
||||
payload: objobject::PyInstance,
|
||||
payload: objobject::PyBaseObject,
|
||||
}
|
||||
.into_ref()
|
||||
}
|
||||
|
||||
@@ -1298,7 +1298,7 @@ impl VirtualMachine {
|
||||
attr_value: impl Into<PyObjectRef>,
|
||||
) -> PyResult<()> {
|
||||
let val = attr_value.into();
|
||||
objobject::object_setattr(module.clone(), attr_name.try_into_ref(self)?, val, self)
|
||||
objobject::setattr(module.clone(), attr_name.try_into_ref(self)?, val, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user