forked from Rust-related/RustPython
Merge pull request #1691 from youknowone/call-descriptor
call slot and PyBuiltinCallable
This commit is contained in:
@@ -957,9 +957,8 @@ pub fn builtin_build_class_(
|
||||
|
||||
function.invoke_with_scope(vec![].into(), &scope, vm)?;
|
||||
|
||||
let class = vm.call_method(
|
||||
let class = vm.invoke(
|
||||
metaclass.as_object(),
|
||||
"__call__",
|
||||
vec![name_obj, bases, namespace.into_object()],
|
||||
)?;
|
||||
cells.set_item("__class__", class.clone(), vm)?;
|
||||
|
||||
@@ -59,7 +59,6 @@ pub mod macros;
|
||||
|
||||
mod builtins;
|
||||
pub mod cformat;
|
||||
mod descriptor;
|
||||
mod dictdatatype;
|
||||
#[cfg(feature = "rustpython-compiler")]
|
||||
pub mod eval;
|
||||
@@ -75,6 +74,7 @@ mod pyhash;
|
||||
pub mod pyobject;
|
||||
pub mod scope;
|
||||
mod sequence;
|
||||
mod slots;
|
||||
pub mod stdlib;
|
||||
mod sysmodule;
|
||||
pub mod types;
|
||||
|
||||
@@ -169,7 +169,7 @@ macro_rules! py_namespace {
|
||||
{
|
||||
let namespace = $vm.ctx.new_namespace();
|
||||
$(
|
||||
$vm.set_attr(&namespace, $name, $value).unwrap();
|
||||
$vm.__module_set_attr(&namespace, $name, $value).unwrap();
|
||||
)*
|
||||
namespace
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::descriptor::PyBuiltinDescriptor;
|
||||
use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc};
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyobject::{
|
||||
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
};
|
||||
use crate::slots::{PyBuiltinCallable, PyBuiltinDescriptor};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[pyclass]
|
||||
@@ -35,14 +35,15 @@ impl PyBuiltinFunction {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
impl PyBuiltinFunction {
|
||||
#[pymethod(name = "__call__")]
|
||||
pub fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
impl PyBuiltinCallable for PyBuiltinFunction {
|
||||
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
(self.value)(vm, args)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyBuiltinCallable))]
|
||||
impl PyBuiltinFunction {}
|
||||
|
||||
#[pyclass]
|
||||
pub struct PyBuiltinMethod {
|
||||
function: PyBuiltinFunction,
|
||||
@@ -87,14 +88,15 @@ impl PyBuiltinDescriptor for PyBuiltinMethod {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyBuiltinDescriptor))]
|
||||
impl PyBuiltinMethod {
|
||||
#[pymethod(name = "__call__")]
|
||||
pub fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
self.function.call(args, vm)
|
||||
impl PyBuiltinCallable for PyBuiltinMethod {
|
||||
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
(self.function.value)(vm, args)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyBuiltinDescriptor, PyBuiltinCallable))]
|
||||
impl PyBuiltinMethod {}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
PyBuiltinFunction::extend_class(context, &context.types.builtin_function_or_method_type);
|
||||
PyBuiltinMethod::extend_class(context, &context.types.method_descriptor_type);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use super::objtype::PyClassRef;
|
||||
use crate::descriptor::PyBuiltinDescriptor;
|
||||
use crate::function::OptionalArg;
|
||||
use crate::pyobject::{
|
||||
PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol,
|
||||
};
|
||||
use crate::slots::PyBuiltinDescriptor;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
/// classmethod(function) -> method
|
||||
|
||||
@@ -4,7 +4,6 @@ use super::objstr::PyStringRef;
|
||||
use super::objtuple::PyTupleRef;
|
||||
use super::objtype::PyClassRef;
|
||||
use crate::bytecode;
|
||||
use crate::descriptor::PyBuiltinDescriptor;
|
||||
use crate::frame::Frame;
|
||||
use crate::function::{OptionalArg, PyFuncArgs};
|
||||
use crate::obj::objcoroutine::PyCoroutine;
|
||||
@@ -14,6 +13,7 @@ use crate::pyobject::{
|
||||
TypeProtocol,
|
||||
};
|
||||
use crate::scope::Scope;
|
||||
use crate::slots::{PyBuiltinCallable, PyBuiltinDescriptor};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
pub type PyFunctionRef = PyRef<PyFunction>;
|
||||
@@ -242,9 +242,10 @@ impl PyValue for PyFunction {
|
||||
|
||||
#[pyimpl(with(PyBuiltinDescriptor))]
|
||||
impl PyFunction {
|
||||
#[pyslot]
|
||||
#[pymethod(magic)]
|
||||
fn call(zelf: PyObjectRef, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
vm.invoke(&zelf, args)
|
||||
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
self.invoke(args, vm)
|
||||
}
|
||||
|
||||
#[pyproperty(name = "__code__")]
|
||||
@@ -263,6 +264,7 @@ impl PyFunction {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
pub struct PyBoundMethod {
|
||||
// TODO: these shouldn't be public
|
||||
@@ -270,11 +272,22 @@ pub struct PyBoundMethod {
|
||||
pub function: PyObjectRef,
|
||||
}
|
||||
|
||||
impl PyBuiltinCallable for PyBoundMethod {
|
||||
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
let args = args.insert(self.object.clone());
|
||||
vm.invoke(&self.function, args)
|
||||
}
|
||||
}
|
||||
|
||||
impl PyBoundMethod {
|
||||
pub fn new(object: PyObjectRef, function: PyObjectRef) -> Self {
|
||||
PyBoundMethod { object, function }
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyBuiltinCallable))]
|
||||
impl PyBoundMethod {
|
||||
#[pymethod(magic)]
|
||||
fn getattribute(&self, name: PyStringRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm.get_attribute(self.function.clone(), name)
|
||||
}
|
||||
@@ -291,7 +304,5 @@ pub fn init(context: &PyContext) {
|
||||
PyFunction::extend_class(context, function_type);
|
||||
|
||||
let method_type = &context.types.bound_method_type;
|
||||
extend_class!(context, method_type, {
|
||||
"__getattribute__" => context.new_method(PyBoundMethod::getattribute),
|
||||
});
|
||||
PyBoundMethod::extend_class(context, method_type);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ fn object_hash(zelf: PyObjectRef, _vm: &VirtualMachine) -> pyhash::PyHash {
|
||||
zelf.get_id() as pyhash::PyHash
|
||||
}
|
||||
|
||||
fn object_setattr(
|
||||
pub(crate) fn object_setattr(
|
||||
obj: PyObjectRef,
|
||||
attr_name: PyStringRef,
|
||||
value: PyObjectRef,
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::objtype::PyClassRef;
|
||||
use crate::descriptor::PyBuiltinDescriptor;
|
||||
use crate::function::{IntoPyNativeFunc, OptionalArg};
|
||||
use crate::pyobject::{
|
||||
IdProtocol, PyClassImpl, PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
TypeProtocol,
|
||||
};
|
||||
use crate::slots::PyBuiltinDescriptor;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
// Read-only property, doesn't have __set__ or __delete__
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::objtype::PyClassRef;
|
||||
use crate::descriptor::PyBuiltinDescriptor;
|
||||
use crate::function::OptionalArg;
|
||||
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::slots::PyBuiltinDescriptor;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[pyclass(name = "staticmethod")]
|
||||
|
||||
@@ -9,11 +9,12 @@ use super::objproperty::PropertyBuilder;
|
||||
use super::objstr::PyStringRef;
|
||||
use super::objtuple::PyTuple;
|
||||
use super::objweakref::PyWeak;
|
||||
use crate::function::{PyFuncArgs, PyNativeFunc};
|
||||
use crate::function::PyFuncArgs;
|
||||
use crate::pyobject::{
|
||||
IdProtocol, PyAttributes, PyContext, PyIterable, PyObject, PyObjectRef, PyRef, PyResult,
|
||||
PyValue, TypeProtocol,
|
||||
};
|
||||
use crate::slots::PyClassSlots;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -26,18 +27,6 @@ pub struct PyClass {
|
||||
pub slots: RefCell<PyClassSlots>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyClassSlots {
|
||||
pub new: Option<PyNativeFunc>,
|
||||
pub descr_get: Option<PyNativeFunc>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PyClassSlots {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("PyClassSlots")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PyClass {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.name, f)
|
||||
@@ -255,6 +244,7 @@ pub fn init(ctx: &PyContext) {
|
||||
extend_class!(&ctx, &ctx.types.type_type, {
|
||||
"mro" => ctx.new_method(type_mro),
|
||||
"__call__" => ctx.new_method(type_call),
|
||||
(slot call) => type_call,
|
||||
"__dict__" =>
|
||||
PropertyBuilder::new(ctx)
|
||||
.add_getter(type_dict)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use super::objtype::PyClassRef;
|
||||
use crate::function::OptionalArg;
|
||||
use crate::function::{OptionalArg, PyFuncArgs};
|
||||
use crate::pyobject::{
|
||||
PyContext, PyObject, PyObjectPayload, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
PyClassImpl, PyContext, PyObject, PyObjectPayload, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
};
|
||||
use crate::slots::PyBuiltinCallable;
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
pub struct PyWeak {
|
||||
referent: Weak<PyObject<dyn PyObjectPayload>>,
|
||||
@@ -32,25 +34,27 @@ impl PyValue for PyWeak {
|
||||
|
||||
pub type PyWeakRef = PyRef<PyWeak>;
|
||||
|
||||
impl PyWeakRef {
|
||||
impl PyBuiltinCallable for PyWeak {
|
||||
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
args.bind::<()>(vm)?;
|
||||
Ok(self.referent.upgrade().unwrap_or_else(|| vm.get_none()))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyBuiltinCallable))]
|
||||
impl PyWeak {
|
||||
// TODO callbacks
|
||||
fn create(
|
||||
#[pyslot]
|
||||
fn tp_new(
|
||||
cls: PyClassRef,
|
||||
referent: PyObjectRef,
|
||||
_callback: OptionalArg<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Self> {
|
||||
) -> PyResult<PyRef<Self>> {
|
||||
PyWeak::downgrade(&referent).into_ref_with_type(vm, cls)
|
||||
}
|
||||
|
||||
fn call(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.referent.upgrade().unwrap_or_else(|| vm.get_none())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(context: &PyContext) {
|
||||
extend_class!(context, &context.types.weakref_type, {
|
||||
(slot new) => PyWeakRef::create,
|
||||
"__call__" => context.new_method(PyWeakRef::call)
|
||||
});
|
||||
PyWeak::extend_class(context, &context.types.weakref_type);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,30 @@
|
||||
use crate::function::OptionalArg;
|
||||
use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc};
|
||||
use crate::pyobject::{IdProtocol, PyObjectRef, PyRef, PyResult, PyValue};
|
||||
use crate::VirtualMachine;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyClassSlots {
|
||||
pub new: Option<PyNativeFunc>,
|
||||
pub call: Option<PyNativeFunc>,
|
||||
pub descr_get: Option<PyNativeFunc>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PyClassSlots {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("PyClassSlots")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
pub trait PyBuiltinCallable: PyValue {
|
||||
#[pymethod(magic)]
|
||||
#[pyslot]
|
||||
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult;
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
pub trait PyBuiltinDescriptor: PyValue {
|
||||
#[pymethod(name = "__get__")]
|
||||
#[pymethod(magic)]
|
||||
#[pyslot(descr_get)]
|
||||
fn get(
|
||||
zelf: PyRef<Self>,
|
||||
46
vm/src/vm.rs
46
vm/src/vm.rs
@@ -26,14 +26,13 @@ use crate::frozen;
|
||||
use crate::function::PyFuncArgs;
|
||||
use crate::import;
|
||||
use crate::obj::objbool;
|
||||
use crate::obj::objbuiltinfunc::{PyBuiltinFunction, PyBuiltinMethod};
|
||||
use crate::obj::objcode::{PyCode, PyCodeRef};
|
||||
use crate::obj::objdict::PyDictRef;
|
||||
use crate::obj::objfunction::{PyBoundMethod, PyFunction};
|
||||
use crate::obj::objint::PyInt;
|
||||
use crate::obj::objiter;
|
||||
use crate::obj::objlist::PyList;
|
||||
use crate::obj::objmodule::{self, PyModule};
|
||||
use crate::obj::objobject;
|
||||
use crate::obj::objstr::{PyString, PyStringRef};
|
||||
use crate::obj::objtuple::PyTuple;
|
||||
use crate::obj::objtype::{self, PyClassRef};
|
||||
@@ -656,31 +655,23 @@ impl VirtualMachine {
|
||||
}
|
||||
}
|
||||
|
||||
fn _invoke(&self, func_ref: &PyObjectRef, args: PyFuncArgs) -> PyResult {
|
||||
vm_trace!("Invoke: {:?} {:?}", func_ref, args);
|
||||
|
||||
if let Some(py_func) = func_ref.payload::<PyFunction>() {
|
||||
fn _invoke(&self, callable: &PyObjectRef, args: PyFuncArgs) -> PyResult {
|
||||
vm_trace!("Invoke: {:?} {:?}", callable, args);
|
||||
let class = callable.class();
|
||||
let slots = class.slots.borrow();
|
||||
if let Some(slot_call) = slots.borrow().call.as_ref() {
|
||||
self.trace_event(TraceEvent::Call)?;
|
||||
let res = py_func.invoke(args, self);
|
||||
let args = args.insert(callable.clone());
|
||||
let result = slot_call(self, args);
|
||||
self.trace_event(TraceEvent::Return)?;
|
||||
res
|
||||
} else if let Some(PyBoundMethod {
|
||||
ref function,
|
||||
ref object,
|
||||
}) = func_ref.payload()
|
||||
{
|
||||
let args = args.insert(object.clone());
|
||||
self.invoke(&function, args)
|
||||
} else if let Some(builtin_func) = func_ref.payload::<PyBuiltinFunction>() {
|
||||
builtin_func.as_func()(self, args)
|
||||
} else if let Some(method) = func_ref.payload::<PyBuiltinMethod>() {
|
||||
method.as_func()(self, args)
|
||||
} else if self.is_callable(&func_ref) {
|
||||
self.call_method(&func_ref, "__call__", args)
|
||||
result
|
||||
} else if objtype::class_has_attr(&class, "__call__") {
|
||||
let result = self.call_method(&callable, "__call__", args);
|
||||
result
|
||||
} else {
|
||||
Err(self.new_type_error(format!(
|
||||
"'{}' object is not callable",
|
||||
func_ref.class().name
|
||||
callable.class().name
|
||||
)))
|
||||
}
|
||||
}
|
||||
@@ -889,12 +880,8 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
pub fn is_callable(&self, obj: &PyObjectRef) -> bool {
|
||||
match_class!(match obj {
|
||||
PyFunction => true,
|
||||
PyBoundMethod => true,
|
||||
PyBuiltinFunction => true,
|
||||
obj => objtype::class_has_attr(&obj.class(), "__call__"),
|
||||
})
|
||||
obj.class().slots.borrow().call.is_some()
|
||||
|| objtype::class_has_attr(&obj.class(), "__call__")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -1311,8 +1298,7 @@ impl VirtualMachine {
|
||||
attr_value: impl Into<PyObjectRef>,
|
||||
) -> PyResult<()> {
|
||||
let val = attr_value.into();
|
||||
self.set_attr(module, attr_name, val)?;
|
||||
Ok(())
|
||||
objobject::object_setattr(module.clone(), attr_name.try_into_ref(self)?, val, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user