mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
PyAttributes key is PyStrInterned
This commit is contained in:
1 parent
f8b1c65ede
commit
fb52694e41
50 files changed
+1494
-898
No files matched your search
+2
-2
@@ -389,9 +389,9 @@ class ClassDefVisitor(EmitVisitor):
|
||||
self.emit(f"#[extend_class]", depth + 1)
|
||||
self.emit("fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) {", depth + 1)
|
||||
fields = ",".join(f"ctx.new_str(ascii!({json.dumps(f.name)})).into()" for f in fields)
|
||||
self.emit(f'class.set_str_attr("_fields", ctx.new_list(vec![{fields}]));', depth + 2)
|
||||
self.emit(f'class.set_attr(interned!(ctx, _fields), ctx.new_list(vec![{fields}]).into());', depth + 2)
|
||||
attrs = ",".join(f"ctx.new_str(ascii!({json.dumps(attr.name)})).into()" for attr in attrs)
|
||||
self.emit(f'class.set_str_attr("_attributes", ctx.new_list(vec![{attrs}]));', depth + 2)
|
||||
self.emit(f'class.set_attr(interned!(ctx, _attributes), ctx.new_list(vec![{attrs}]).into());', depth + 2)
|
||||
self.emit("}", depth + 1)
|
||||
self.emit("}", depth)
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
.map(|entry| {
|
||||
let path = entry.unwrap().path();
|
||||
(
|
||||
path.file_name().unwrap().to_str().unwrap().to_owned(),
|
||||
path.file_name().unwrap().to_owned().unwrap().to_owned(),
|
||||
std::fs::read_to_string(path).unwrap(),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -503,7 +503,8 @@ where
|
||||
#py_name,
|
||||
ctx.make_funcdef(#py_name, Self::#ident)
|
||||
#doc
|
||||
#build_func
|
||||
#build_func,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -611,7 +612,7 @@ where
|
||||
ident,
|
||||
py_name.clone(),
|
||||
quote! {
|
||||
class.set_str_attr(#py_name, #value);
|
||||
class.set_str_attr(#py_name, #value, ctx);
|
||||
},
|
||||
)
|
||||
} else {
|
||||
@@ -736,7 +737,8 @@ impl ToTokens for GetSetNursery {
|
||||
::rustpython_vm::builtins::PyGetSet::new(#name.into(), class.clone())
|
||||
.with_get(&Self::#getter)
|
||||
#setter #deleter,
|
||||
ctx.types.getset_type.clone(), None)
|
||||
ctx.types.getset_type.clone(), None),
|
||||
ctx
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -433,7 +433,7 @@ impl ModuleItem for ClassItem {
|
||||
};
|
||||
let class_new = quote_spanned!(ident.span() =>
|
||||
let new_class = <#ident as ::rustpython_vm::class::PyClassImpl>::make_class(&vm.ctx);
|
||||
new_class.set_str_attr("__module__", vm.new_pyobj(#module_name));
|
||||
new_class.set_attr(rustpython_vm::identifier!(vm, __module__), vm.new_pyobj(#module_name));
|
||||
);
|
||||
(class_name, class_new)
|
||||
};
|
||||
|
||||
+9
-4
@@ -2,7 +2,7 @@
|
||||
use rustpython_vm::{
|
||||
builtins::{PyDictRef, PyStrRef},
|
||||
function::ArgIterable,
|
||||
PyResult, TryFromObject, VirtualMachine,
|
||||
identifier, PyResult, TryFromObject, VirtualMachine,
|
||||
};
|
||||
|
||||
pub struct ShellHelper<'vm> {
|
||||
@@ -81,14 +81,19 @@ impl<'vm> ShellHelper<'vm> {
|
||||
current = current.get_attr(attr.as_str(), self.vm).ok()?;
|
||||
}
|
||||
|
||||
let current_iter = str_iter_method(current, "__dir__").ok()?;
|
||||
let current_iter = str_iter_method(current, identifier!(self.vm, __dir__)).ok()?;
|
||||
|
||||
(last, current_iter, None)
|
||||
} else {
|
||||
// we need to get a variable based off of globals/builtins
|
||||
|
||||
let globals = str_iter_method(self.globals.clone().into(), "keys").ok()?;
|
||||
let builtins = str_iter_method(self.vm.builtins.clone().into(), "__dir__").ok()?;
|
||||
let globals =
|
||||
str_iter_method(self.globals.clone().into(), identifier!(self.vm, keys)).ok()?;
|
||||
let builtins = str_iter_method(
|
||||
self.vm.builtins.clone().into(),
|
||||
identifier!(self.vm, __dir__),
|
||||
)
|
||||
.ok()?;
|
||||
(first, globals, Some(builtins))
|
||||
};
|
||||
Some((word_start, iter1.chain(iter2.into_iter().flatten())))
|
||||
|
||||
+11
-7
@@ -3,9 +3,9 @@ pub(crate) use math::make_module;
|
||||
#[pymodule]
|
||||
mod math {
|
||||
use crate::vm::{
|
||||
builtins::{try_bigint_to_f64, try_f64_to_bigint, PyFloat, PyInt, PyIntRef},
|
||||
builtins::{try_bigint_to_f64, try_f64_to_bigint, PyFloat, PyInt, PyIntRef, PyStrInterned},
|
||||
function::{ArgIntoFloat, ArgIterable, Either, OptionalArg, PosArgs},
|
||||
AsObject, PyObject, PyObjectRef, PyRef, PyResult, VirtualMachine,
|
||||
identifier, AsObject, PyObject, PyObjectRef, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::{One, Signed, Zero};
|
||||
@@ -430,12 +430,16 @@ mod math {
|
||||
}
|
||||
}
|
||||
|
||||
fn try_magic_method(func_name: &str, vm: &VirtualMachine, value: &PyObject) -> PyResult {
|
||||
fn try_magic_method(
|
||||
func_name: &'static PyStrInterned,
|
||||
vm: &VirtualMachine,
|
||||
value: &PyObject,
|
||||
) -> PyResult {
|
||||
let method = vm.get_method_or_type_error(value.to_owned(), func_name, || {
|
||||
format!(
|
||||
"type '{}' doesn't define '{}' method",
|
||||
value.class().name(),
|
||||
func_name,
|
||||
func_name.as_str(),
|
||||
)
|
||||
})?;
|
||||
vm.invoke(&method, ())
|
||||
@@ -443,12 +447,12 @@ mod math {
|
||||
|
||||
#[pyfunction]
|
||||
fn trunc(x: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
try_magic_method("__trunc__", vm, &x)
|
||||
try_magic_method(identifier!(vm, __trunc__), vm, &x)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn ceil(x: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let result_or_err = try_magic_method("__ceil__", vm, &x);
|
||||
let result_or_err = try_magic_method(identifier!(vm, __ceil__), vm, &x);
|
||||
if result_or_err.is_err() {
|
||||
if let Ok(Some(v)) = x.try_to_f64(vm) {
|
||||
let v = try_f64_to_bigint(v.ceil(), vm)?;
|
||||
@@ -460,7 +464,7 @@ mod math {
|
||||
|
||||
#[pyfunction]
|
||||
fn floor(x: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
let result_or_err = try_magic_method("__floor__", vm, &x);
|
||||
let result_or_err = try_magic_method(identifier!(vm, __floor__), vm, &x);
|
||||
if result_or_err.is_err() {
|
||||
if let Ok(Some(v)) = x.try_to_f64(vm) {
|
||||
let v = try_f64_to_bigint(v.floor(), vm)?;
|
||||
|
||||
@@ -25,7 +25,7 @@ macro_rules! create_property {
|
||||
move |this: &PyExpatLikeXmlParser, func: PyObjectRef| *this.$element.write() = func,
|
||||
);
|
||||
|
||||
$attributes.insert($name.to_owned(), attr.into());
|
||||
$attributes.insert($ctx.intern_str($name), attr.into());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -75,9 +75,11 @@ struct Selectable {
|
||||
impl TryFromObject for Selectable {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
let fno = obj.try_to_value(vm).or_else(|_| {
|
||||
let meth = vm.get_method_or_type_error(obj.clone(), "fileno", || {
|
||||
"select arg must be an int or object with a fileno() method".to_owned()
|
||||
})?;
|
||||
let meth = vm.get_method_or_type_error(
|
||||
obj.clone(),
|
||||
vm.ctx.interned_str("fileno").unwrap(),
|
||||
|| "select arg must be an int or object with a fileno() method".to_owned(),
|
||||
)?;
|
||||
vm.invoke(&meth, ())?.try_into_value(vm)
|
||||
})?;
|
||||
Ok(Selectable { obj, fno })
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use super::{PyInt, PyStrRef, PyTypeRef};
|
||||
use crate::{
|
||||
class::PyClassImpl, convert::ToPyObject, function::OptionalArg, types::Constructor, AsObject,
|
||||
Context, PyObject, PyObjectRef, PyPayload, PyResult, TryFromBorrowedObject, VirtualMachine,
|
||||
class::PyClassImpl, convert::ToPyObject, function::OptionalArg, identifier, types::Constructor,
|
||||
AsObject, Context, PyObject, PyObjectRef, PyPayload, PyResult, TryFromBorrowedObject,
|
||||
VirtualMachine,
|
||||
};
|
||||
use num_bigint::Sign;
|
||||
use num_traits::Zero;
|
||||
@@ -32,7 +33,7 @@ impl PyObjectRef {
|
||||
if self.is(&vm.ctx.false_value) {
|
||||
return Ok(false);
|
||||
}
|
||||
let rs_bool = match vm.get_method(self.clone(), "__bool__") {
|
||||
let rs_bool = match vm.get_method(self.clone(), identifier!(vm, __bool__)) {
|
||||
Some(method_or_err) => {
|
||||
// If descriptor returns Error, propagate it further
|
||||
let method = method_or_err?;
|
||||
@@ -46,7 +47,7 @@ impl PyObjectRef {
|
||||
|
||||
get_value(&bool_obj)
|
||||
}
|
||||
None => match vm.get_method(self, "__len__") {
|
||||
None => match vm.get_method(self, identifier!(vm, __len__)) {
|
||||
Some(method_or_err) => {
|
||||
let method = method_or_err?;
|
||||
let bool_obj = vm.invoke(&method, ())?;
|
||||
@@ -112,9 +113,9 @@ impl PyBool {
|
||||
#[pymethod(magic)]
|
||||
fn repr(zelf: bool, vm: &VirtualMachine) -> PyStrRef {
|
||||
if zelf {
|
||||
vm.ctx.true_str
|
||||
vm.ctx.names.True
|
||||
} else {
|
||||
vm.ctx.false_str
|
||||
vm.ctx.names.False
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::{
|
||||
PyArithmeticValue::{self, *},
|
||||
PyComparisonValue,
|
||||
},
|
||||
identifier,
|
||||
types::{Comparable, Constructor, Hashable, PyComparisonOp},
|
||||
AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
@@ -48,7 +49,7 @@ impl PyObjectRef {
|
||||
if let Some(complex) = self.payload_if_exact::<PyComplex>(vm) {
|
||||
return Ok(Some((complex.value, true)));
|
||||
}
|
||||
if let Some(method) = vm.get_method(self.clone(), "__complex__") {
|
||||
if let Some(method) = vm.get_method(self.clone(), identifier!(vm, __complex__)) {
|
||||
let result = vm.invoke(&method?, ())?;
|
||||
// TODO: returning strict subclasses of complex in __complex__ is deprecated
|
||||
return match result.payload::<PyComplex>() {
|
||||
|
||||
@@ -83,7 +83,7 @@ impl PyDict {
|
||||
Ok(dict_other) => return Self::merge_dict(dict, dict_other, vm),
|
||||
Err(other) => other,
|
||||
};
|
||||
if let Some(keys) = vm.get_method(other.clone(), "keys") {
|
||||
if let Some(keys) = vm.get_method(other.clone(), vm.ctx.intern_str("keys")) {
|
||||
let keys = vm.invoke(&keys?, ())?.get_iter(vm)?;
|
||||
while let PyIterReturn::Return(key) = keys.next(vm)? {
|
||||
let val = other.get_item(&*key, vm)?;
|
||||
@@ -196,13 +196,13 @@ impl PyDict {
|
||||
}
|
||||
|
||||
pub fn from_attributes(attrs: PyAttributes, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
let dict = DictContentType::default();
|
||||
let entries = DictContentType::default();
|
||||
|
||||
for (key, value) in attrs {
|
||||
dict.insert(vm, key.as_str(), value)?;
|
||||
entries.insert(vm, key, value)?;
|
||||
}
|
||||
|
||||
Ok(PyDict { entries: dict })
|
||||
Ok(Self { entries })
|
||||
}
|
||||
|
||||
pub fn contains_key<K: DictKey + ?Sized>(&self, key: &K, vm: &VirtualMachine) -> bool {
|
||||
@@ -527,7 +527,7 @@ impl Py<PyDict> {
|
||||
key: &K,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
vm.get_method(self.to_owned().into(), "__missing__")
|
||||
vm.get_method(self.to_owned().into(), identifier!(vm, __missing__))
|
||||
.map(|methods| vm.invoke(&methods?, (key.to_pyobject(vm),)))
|
||||
.transpose()
|
||||
}
|
||||
@@ -548,11 +548,12 @@ impl Py<PyDict> {
|
||||
}
|
||||
|
||||
/// Take a python dictionary and convert it to attributes.
|
||||
pub fn to_attributes(&self) -> PyAttributes {
|
||||
pub fn to_attributes(&self, vm: &VirtualMachine) -> PyAttributes {
|
||||
let mut attrs = PyAttributes::default();
|
||||
for (key, value) in self {
|
||||
// TODO: use PyRefExact for interning
|
||||
let key: PyStrRef = key.downcast().expect("dict has non-string keys");
|
||||
attrs.insert(key.as_str().to_owned(), value);
|
||||
attrs.insert(vm.ctx.intern_str(key.as_str()), value);
|
||||
}
|
||||
attrs
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::{
|
||||
PyArithmeticValue::{self, *},
|
||||
PyComparisonValue,
|
||||
},
|
||||
identifier,
|
||||
types::{Comparable, Constructor, Hashable, PyComparisonOp},
|
||||
AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject,
|
||||
TryFromObject, VirtualMachine,
|
||||
@@ -59,7 +60,7 @@ impl PyObject {
|
||||
if let Some(float) = self.payload_if_exact::<PyFloat>(vm) {
|
||||
return Ok(Some(float.value));
|
||||
}
|
||||
if let Some(method) = vm.get_method(self.to_owned(), "__float__") {
|
||||
if let Some(method) = vm.get_method(self.to_owned(), identifier!(vm, __float__)) {
|
||||
let result = vm.invoke(&method?, ())?;
|
||||
// TODO: returning strict subclasses of float in __float__ is deprecated
|
||||
return match result.payload::<PyFloat>() {
|
||||
|
||||
@@ -458,7 +458,10 @@ impl Comparable for PyBoundMethod {
|
||||
|
||||
impl GetAttr for PyBoundMethod {
|
||||
fn getattro(zelf: &Py<Self>, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
|
||||
let class_attr = zelf.get_class_attr(name.as_str());
|
||||
let class_attr = vm
|
||||
.ctx
|
||||
.interned_str(&*name)
|
||||
.and_then(|attr_name| zelf.get_class_attr(attr_name));
|
||||
if let Some(obj) = class_attr {
|
||||
return vm.call_if_get_descriptor(obj, zelf.to_owned().into());
|
||||
}
|
||||
|
||||
@@ -82,16 +82,20 @@ impl PyGenericAlias {
|
||||
return Ok("...".to_string());
|
||||
}
|
||||
|
||||
if vm.get_attribute_opt(obj.clone(), "__origin__")?.is_some()
|
||||
&& vm.get_attribute_opt(obj.clone(), "__args__")?.is_some()
|
||||
if vm
|
||||
.get_attribute_opt(obj.clone(), identifier!(vm, __origin__))?
|
||||
.is_some()
|
||||
&& vm
|
||||
.get_attribute_opt(obj.clone(), identifier!(vm, __args__))?
|
||||
.is_some()
|
||||
{
|
||||
return Ok(obj.repr(vm)?.as_str().to_string());
|
||||
}
|
||||
|
||||
match (
|
||||
vm.get_attribute_opt(obj.clone(), "__qualname__")?
|
||||
vm.get_attribute_opt(obj.clone(), identifier!(vm, __qualname__))?
|
||||
.and_then(|o| o.downcast_ref::<PyStr>().map(|n| n.as_str().to_string())),
|
||||
vm.get_attribute_opt(obj.clone(), "__module__")?
|
||||
vm.get_attribute_opt(obj.clone(), identifier!(vm, __module__))?
|
||||
.and_then(|o| o.downcast_ref::<PyStr>().map(|m| m.as_str().to_string())),
|
||||
) {
|
||||
(None, _) | (_, None) => Ok(obj.repr(vm)?.as_str().to_string()),
|
||||
@@ -186,11 +190,11 @@ impl PyGenericAlias {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_typevar(obj: &PyObjectRef) -> bool {
|
||||
fn is_typevar(obj: &PyObjectRef, vm: &VirtualMachine) -> bool {
|
||||
let class = obj.class();
|
||||
class.slot_name() == "TypeVar"
|
||||
&& class
|
||||
.get_attr("__module__")
|
||||
.get_attr(identifier!(vm, __module__))
|
||||
.and_then(|o| o.downcast_ref::<PyStr>().map(|s| s.as_str() == "typing"))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
@@ -198,13 +202,13 @@ fn is_typevar(obj: &PyObjectRef) -> bool {
|
||||
fn make_parameters(args: &PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len());
|
||||
for arg in args {
|
||||
if is_typevar(arg) {
|
||||
if is_typevar(arg, vm) {
|
||||
if !parameters.iter().any(|param| param.is(arg)) {
|
||||
parameters.push(arg.clone());
|
||||
}
|
||||
} else if let Ok(subparams) = arg
|
||||
.clone()
|
||||
.get_attr("__parameters__", vm)
|
||||
.get_attr(identifier!(vm, __parameters__), vm)
|
||||
.and_then(|obj| PyTupleRef::try_from_object(vm, obj))
|
||||
{
|
||||
for subparam in &subparams {
|
||||
@@ -231,7 +235,7 @@ fn subs_tvars(
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
obj.clone()
|
||||
.get_attr("__parameters__", vm)
|
||||
.get_attr(identifier!(vm, __parameters__), vm)
|
||||
.ok()
|
||||
.and_then(|sub_params| {
|
||||
PyTupleRef::try_from_object(vm, sub_params)
|
||||
@@ -290,7 +294,7 @@ pub fn subs_parameters<F: Fn(&VirtualMachine) -> PyResult<String>>(
|
||||
let new_args = args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
if is_typevar(arg) {
|
||||
if is_typevar(arg, vm) {
|
||||
let idx = tuple_index(¶meters, arg).unwrap();
|
||||
Ok(arg_items[idx].clone())
|
||||
} else {
|
||||
@@ -322,7 +326,7 @@ impl Callable for PyGenericAlias {
|
||||
type Args = FuncArgs;
|
||||
fn call(zelf: &crate::Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
PyType::call(&zelf.origin, args, vm).map(|obj| {
|
||||
if let Err(exc) = obj.set_attr("__orig_class__", zelf.to_owned(), vm) {
|
||||
if let Err(exc) = obj.set_attr(identifier!(vm, __orig_class__), zelf.to_owned(), vm) {
|
||||
if !exc.fast_isinstance(&vm.ctx.exceptions.attribute_error)
|
||||
&& !exc.fast_isinstance(&vm.ctx.exceptions.type_error)
|
||||
{
|
||||
|
||||
@@ -952,7 +952,7 @@ pub(crate) fn try_int(obj: &PyObject, vm: &VirtualMachine) -> PyResult<BigInt> {
|
||||
}
|
||||
// call __int__, then __index__, then __trunc__ (converting the __trunc__ result via __index__ if needed)
|
||||
// TODO: using __int__ is deprecated and removed in Python 3.10
|
||||
if let Some(method) = vm.get_method(obj.to_owned(), "__int__") {
|
||||
if let Some(method) = vm.get_method(obj.to_owned(), identifier!(vm, __int__)) {
|
||||
let result = vm.invoke(&method?, ())?;
|
||||
return match result.payload::<PyInt>() {
|
||||
Some(int_obj) => Ok(int_obj.as_bigint().clone()),
|
||||
@@ -966,7 +966,7 @@ pub(crate) fn try_int(obj: &PyObject, vm: &VirtualMachine) -> PyResult<BigInt> {
|
||||
if let Some(r) = vm.to_index_opt(obj.to_owned()).transpose()? {
|
||||
return Ok(r.as_bigint().clone());
|
||||
}
|
||||
if let Some(method) = vm.get_method(obj.to_owned(), "__trunc__") {
|
||||
if let Some(method) = vm.get_method(obj.to_owned(), identifier!(vm, __trunc__)) {
|
||||
let result = vm.invoke(&method?, ())?;
|
||||
return vm
|
||||
.to_index_opt(result.clone())
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::{PyDict, PyGenericAlias, PyList, PyStr, PyStrRef, PyTuple, PyTypeRef};
|
||||
use super::{PyDict, PyGenericAlias, PyList, PyTuple, PyTypeRef};
|
||||
use crate::{
|
||||
class::PyClassImpl,
|
||||
convert::ToPyObject,
|
||||
function::OptionalArg,
|
||||
protocol::{PyMapping, PyMappingMethods, PySequence, PySequenceMethods},
|
||||
types::{AsMapping, AsSequence, Constructor, Iterable},
|
||||
AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
|
||||
VirtualMachine,
|
||||
AsObject, Context, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
|
||||
#[pyclass(module = false, name = "mappingproxy")]
|
||||
@@ -63,10 +62,9 @@ impl Constructor for PyMappingProxy {
|
||||
impl PyMappingProxy {
|
||||
fn get_inner(&self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> {
|
||||
let opt = match &self.mapping {
|
||||
MappingProxyInner::Class(class) => {
|
||||
let key = PyStrRef::try_from_object(vm, key)?;
|
||||
class.attributes.read().get(key.as_str()).cloned()
|
||||
}
|
||||
MappingProxyInner::Class(class) => key
|
||||
.as_interned_str(vm)
|
||||
.and_then(|key| class.attributes.read().get(key).cloned()),
|
||||
MappingProxyInner::Dict(obj) => obj.get_item(&*key, vm).ok(),
|
||||
};
|
||||
Ok(opt)
|
||||
@@ -92,13 +90,9 @@ impl PyMappingProxy {
|
||||
|
||||
fn _contains(&self, key: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
match &self.mapping {
|
||||
MappingProxyInner::Class(class) => {
|
||||
// let key = PyStrRef::try_from_object(vm, key)?;
|
||||
let key = key
|
||||
.payload::<PyStr>()
|
||||
.ok_or_else(|| vm.new_downcast_type_error(PyStr::class(vm), key))?;
|
||||
Ok(class.attributes.read().contains_key(key.as_str()))
|
||||
}
|
||||
MappingProxyInner::Class(class) => Ok(key
|
||||
.as_interned_str(vm)
|
||||
.map_or(false, |key| class.attributes.read().contains_key(key))),
|
||||
MappingProxyInner::Dict(obj) => PySequence::from(obj.as_ref()).contains(key, vm),
|
||||
}
|
||||
}
|
||||
@@ -116,7 +110,7 @@ impl PyMappingProxy {
|
||||
PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm)
|
||||
}
|
||||
};
|
||||
vm.call_method(&obj, "items", ())
|
||||
vm.call_method(&obj, identifier!(vm, items).as_str(), ())
|
||||
}
|
||||
#[pymethod]
|
||||
pub fn keys(&self, vm: &VirtualMachine) -> PyResult {
|
||||
@@ -126,7 +120,7 @@ impl PyMappingProxy {
|
||||
PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm)
|
||||
}
|
||||
};
|
||||
vm.call_method(&obj, "keys", ())
|
||||
vm.call_method(&obj, identifier!(vm, keys).as_str(), ())
|
||||
}
|
||||
#[pymethod]
|
||||
pub fn values(&self, vm: &VirtualMachine) -> PyResult {
|
||||
@@ -136,12 +130,12 @@ impl PyMappingProxy {
|
||||
PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm)
|
||||
}
|
||||
};
|
||||
vm.call_method(&obj, "values", ())
|
||||
vm.call_method(&obj, identifier!(vm, values).as_str(), ())
|
||||
}
|
||||
#[pymethod]
|
||||
pub fn copy(&self, vm: &VirtualMachine) -> PyResult {
|
||||
match &self.mapping {
|
||||
MappingProxyInner::Dict(d) => vm.call_method(d, "copy", ()),
|
||||
MappingProxyInner::Dict(d) => vm.call_method(d, identifier!(vm, copy).as_str(), ()),
|
||||
MappingProxyInner::Class(c) => {
|
||||
Ok(PyDict::from_attributes(c.attributes.read().clone(), vm)?.to_pyobject(vm))
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ impl PyBaseObject {
|
||||
};
|
||||
|
||||
// Ensure that all abstract methods are implemented before instantiating instance.
|
||||
if let Some(abs_methods) = cls.get_attr("__abstractmethods__") {
|
||||
if let Some(abs_methods) = cls.get_attr(identifier!(vm, __abstractmethods__)) {
|
||||
if let Some(unimplemented_abstract_method_count) = abs_methods.length_opt(vm) {
|
||||
if unimplemented_abstract_method_count? > 0 {
|
||||
return Err(
|
||||
@@ -230,7 +230,11 @@ impl PyBaseObject {
|
||||
|
||||
// Get instance attributes:
|
||||
if let Some(object_dict) = obj.dict() {
|
||||
vm.call_method(dict.as_object(), "update", (object_dict,))?;
|
||||
vm.call_method(
|
||||
dict.as_object(),
|
||||
identifier!(vm, update).as_str(),
|
||||
(object_dict,),
|
||||
)?;
|
||||
}
|
||||
|
||||
let attributes: Vec<_> = dict.into_iter().map(|(k, _v)| k).collect();
|
||||
@@ -305,10 +309,15 @@ impl PyBaseObject {
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn reduce_ex(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {
|
||||
if let Some(reduce) = vm.get_attribute_opt(obj.clone(), "__reduce__")? {
|
||||
let object_reduce = vm.ctx.types.object_type.get_attr("__reduce__").unwrap();
|
||||
if let Some(reduce) = vm.get_attribute_opt(obj.clone(), identifier!(vm, __reduce__))? {
|
||||
let object_reduce = vm
|
||||
.ctx
|
||||
.types
|
||||
.object_type
|
||||
.get_attr(identifier!(vm, __reduce__))
|
||||
.unwrap();
|
||||
let typ_obj: PyObjectRef = obj.class().clone().into();
|
||||
let class_reduce = typ_obj.get_attr("__reduce__", vm)?;
|
||||
let class_reduce = typ_obj.get_attr(identifier!(vm, __reduce__), vm)?;
|
||||
if !class_reduce.is(&object_reduce) {
|
||||
return vm.invoke(&reduce, ());
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ impl PyStr {
|
||||
Self::new_str_unchecked(bytes.into_bytes(), kind)
|
||||
}
|
||||
.to_pyobject(vm))
|
||||
} else if let Some(radd) = vm.get_method(other.clone(), "__radd__") {
|
||||
} else if let Some(radd) = vm.get_method(other.clone(), identifier!(vm, __radd__)) {
|
||||
// hack to get around not distinguishing number add from seq concat
|
||||
vm.invoke(&radd?, (zelf,))
|
||||
} else {
|
||||
@@ -1149,7 +1149,7 @@ impl PyStr {
|
||||
// https://docs.python.org/3/library/stdtypes.html#str.translate
|
||||
#[pymethod]
|
||||
fn translate(&self, table: PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
vm.get_method_or_type_error(table.clone(), "__getitem__", || {
|
||||
vm.get_method_or_type_error(table.clone(), identifier!(vm, __getitem__), || {
|
||||
format!("'{}' object is not subscriptable", table.class().name())
|
||||
})?;
|
||||
|
||||
|
||||
+18
-16
@@ -148,22 +148,24 @@ impl GetAttr for PySuper {
|
||||
return skip(zelf, name);
|
||||
}
|
||||
|
||||
// skip the classes in start_type.mro up to and including zelf.typ
|
||||
let mro: Vec<_> = start_type
|
||||
.iter_mro()
|
||||
.skip_while(|cls| !cls.is(&zelf.typ))
|
||||
.skip(1) // skip su->type (if any)
|
||||
.collect();
|
||||
for cls in mro {
|
||||
if let Some(descr) = cls.get_direct_attr(name.as_str()) {
|
||||
return vm
|
||||
.call_get_descriptor_specific(
|
||||
descr.clone(),
|
||||
// Only pass 'obj' param if this is instance-mode super (See https://bugs.python.org/issue743267)
|
||||
if obj.is(&start_type) { None } else { Some(obj) },
|
||||
Some(start_type.as_object().to_owned()),
|
||||
)
|
||||
.unwrap_or(Ok(descr));
|
||||
if let Some(name) = vm.ctx.interned_str(&*name) {
|
||||
// skip the classes in start_type.mro up to and including zelf.typ
|
||||
let mro: Vec<_> = start_type
|
||||
.iter_mro()
|
||||
.skip_while(|cls| !cls.is(&zelf.typ))
|
||||
.skip(1) // skip su->type (if any)
|
||||
.collect();
|
||||
for cls in mro {
|
||||
if let Some(descr) = cls.get_direct_attr(name) {
|
||||
return vm
|
||||
.call_get_descriptor_specific(
|
||||
descr.clone(),
|
||||
// Only pass 'obj' param if this is instance-mode super (See https://bugs.python.org/issue743267)
|
||||
if obj.is(&start_type) { None } else { Some(obj) },
|
||||
Some(start_type.as_object().to_owned()),
|
||||
)
|
||||
.unwrap_or(Ok(descr));
|
||||
}
|
||||
}
|
||||
}
|
||||
skip(zelf, name)
|
||||
|
||||
+83
-55
@@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
mappingproxy::PyMappingProxy, object, union_, PyClassMethod, PyDictRef, PyList, PyStaticMethod,
|
||||
PyStr, PyStrRef, PyTuple, PyTupleRef, PyWeak,
|
||||
PyStr, PyStrInterned, PyStrRef, PyTuple, PyTupleRef, PyWeak,
|
||||
};
|
||||
use crate::common::{
|
||||
ascii,
|
||||
@@ -8,8 +8,10 @@ use crate::common::{
|
||||
lock::{PyRwLock, PyRwLockReadGuard},
|
||||
};
|
||||
use crate::{
|
||||
builtins::PyBaseExceptionRef,
|
||||
class::{PyClassImpl, StaticType},
|
||||
function::{FuncArgs, KwArgs, OptionalArg},
|
||||
identifier,
|
||||
types::{Callable, GetAttr, PyTypeFlags, PyTypeSlots, SetAttr},
|
||||
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
@@ -35,7 +37,7 @@ pub type PyTypeRef = PyRef<PyType>;
|
||||
/// For attributes we do not use a dict, but an IndexMap, which is an Hash Table
|
||||
/// that maintains order and is compatible with the standard HashMap This is probably
|
||||
/// faster and only supports strings as keys.
|
||||
pub type PyAttributes = IndexMap<String, PyObjectRef, ahash::RandomState>;
|
||||
pub type PyAttributes = IndexMap<&'static PyStrInterned, PyObjectRef, ahash::RandomState>;
|
||||
|
||||
impl fmt::Display for PyType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
@@ -116,7 +118,7 @@ impl PyType {
|
||||
);
|
||||
|
||||
for attr_name in new_type.attributes.read().keys() {
|
||||
if attr_name.starts_with("__") && attr_name.ends_with("__") {
|
||||
if attr_name.as_str().starts_with("__") && attr_name.as_str().ends_with("__") {
|
||||
new_type.update_slot(attr_name, true);
|
||||
}
|
||||
}
|
||||
@@ -155,34 +157,40 @@ impl PyType {
|
||||
}
|
||||
|
||||
// This is used for class initialisation where the vm is not yet available.
|
||||
pub fn set_str_attr<V: Into<PyObjectRef>>(&self, attr_name: &str, value: V) {
|
||||
self._set_str_attr(attr_name, value.into())
|
||||
pub fn set_str_attr<V: Into<PyObjectRef>>(
|
||||
&self,
|
||||
attr_name: &str,
|
||||
value: V,
|
||||
ctx: impl AsRef<Context>,
|
||||
) {
|
||||
let attr_name = ctx.as_ref().intern_str(attr_name);
|
||||
self.set_attr(attr_name, value.into())
|
||||
}
|
||||
|
||||
fn _set_str_attr(&self, attr_name: &str, value: PyObjectRef) {
|
||||
self.attributes.write().insert(attr_name.to_owned(), value);
|
||||
pub fn set_attr(&self, attr_name: &'static PyStrInterned, value: PyObjectRef) {
|
||||
self.attributes.write().insert(attr_name, value);
|
||||
}
|
||||
|
||||
/// This is the internal get_attr implementation for fast lookup on a class.
|
||||
pub fn get_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
|
||||
pub fn get_attr(&self, attr_name: &'static PyStrInterned) -> Option<PyObjectRef> {
|
||||
flame_guard!(format!("class_get_attr({:?})", attr_name));
|
||||
|
||||
self.get_direct_attr(attr_name)
|
||||
.or_else(|| self.get_super_attr(attr_name))
|
||||
}
|
||||
|
||||
pub fn get_direct_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
|
||||
pub fn get_direct_attr(&self, attr_name: &'static PyStrInterned) -> Option<PyObjectRef> {
|
||||
self.attributes.read().get(attr_name).cloned()
|
||||
}
|
||||
|
||||
pub fn get_super_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
|
||||
pub fn get_super_attr(&self, attr_name: &'static PyStrInterned) -> Option<PyObjectRef> {
|
||||
self.mro
|
||||
.iter()
|
||||
.find_map(|class| class.attributes.read().get(attr_name).cloned())
|
||||
}
|
||||
|
||||
// This is the internal has_attr implementation for fast lookup on a class.
|
||||
pub fn has_attr(&self, attr_name: &str) -> bool {
|
||||
pub fn has_attr(&self, attr_name: &'static PyStrInterned) -> bool {
|
||||
self.attributes.read().contains_key(attr_name)
|
||||
|| self
|
||||
.mro
|
||||
@@ -264,11 +272,11 @@ impl PyType {
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn dir(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyList {
|
||||
fn dir(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyList {
|
||||
let attributes: Vec<PyObjectRef> = zelf
|
||||
.get_attributes()
|
||||
.into_iter()
|
||||
.map(|(k, _)| vm.ctx.new_str(k).into())
|
||||
.map(|(k, _)| k.to_object())
|
||||
.collect();
|
||||
PyList::from(attributes)
|
||||
}
|
||||
@@ -330,7 +338,7 @@ impl PyType {
|
||||
pub fn qualname(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.attributes
|
||||
.read()
|
||||
.get("__qualname__")
|
||||
.get(identifier!(vm, __qualname__))
|
||||
.cloned()
|
||||
// We need to exclude this method from going into recursion:
|
||||
.and_then(|found| {
|
||||
@@ -347,7 +355,7 @@ impl PyType {
|
||||
pub fn module(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.attributes
|
||||
.read()
|
||||
.get("__module__")
|
||||
.get(identifier!(vm, __module__))
|
||||
.cloned()
|
||||
// We need to exclude this method from going into recursion:
|
||||
.and_then(|found| {
|
||||
@@ -361,10 +369,10 @@ impl PyType {
|
||||
}
|
||||
|
||||
#[pyproperty(magic, setter)]
|
||||
fn set_module(&self, value: PyObjectRef) {
|
||||
fn set_module(&self, value: PyObjectRef, vm: &VirtualMachine) {
|
||||
self.attributes
|
||||
.write()
|
||||
.insert("__module__".to_owned(), value);
|
||||
.insert(identifier!(vm, __module__), value);
|
||||
}
|
||||
|
||||
#[pyclassmethod(magic)]
|
||||
@@ -441,7 +449,10 @@ impl PyType {
|
||||
.iter()
|
||||
.map(|obj| {
|
||||
obj.clone().downcast::<PyType>().or_else(|obj| {
|
||||
if vm.get_attribute_opt(obj, "__mro_entries__")?.is_some() {
|
||||
if vm
|
||||
.get_attribute_opt(obj, identifier!(vm, __mro_entries__))?
|
||||
.is_some()
|
||||
{
|
||||
Err(vm.new_type_error(
|
||||
"type() doesn't support MRO entry resolution; \
|
||||
use types.new_class()"
|
||||
@@ -471,51 +482,56 @@ impl PyType {
|
||||
(metatype, base, bases)
|
||||
};
|
||||
|
||||
let mut attributes = dict.to_attributes();
|
||||
if let Some(f) = attributes.get_mut("__new__") {
|
||||
let mut attributes = dict.to_attributes(vm);
|
||||
if let Some(f) = attributes.get_mut(identifier!(vm, __new__)) {
|
||||
if f.class().is(&vm.ctx.types.function_type) {
|
||||
*f = PyStaticMethod::from(f.clone()).into_pyobject(vm);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(f) = attributes.get_mut("__init_subclass__") {
|
||||
if let Some(f) = attributes.get_mut(identifier!(vm, __init_subclass__)) {
|
||||
if f.class().is(&vm.ctx.types.function_type) {
|
||||
*f = PyClassMethod::from(f.clone()).into_pyobject(vm);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(f) = attributes.get_mut("__class_getitem__") {
|
||||
if let Some(f) = attributes.get_mut(identifier!(vm, __class_getitem__)) {
|
||||
if f.class().is(&vm.ctx.types.function_type) {
|
||||
*f = PyClassMethod::from(f.clone()).into_pyobject(vm);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(current_frame) = vm.current_frame() {
|
||||
let entry = attributes.entry("__module__".to_owned());
|
||||
let entry = attributes.entry(identifier!(vm, __module__));
|
||||
if matches!(entry, Entry::Vacant(_)) {
|
||||
let module_name =
|
||||
vm.unwrap_or_none(current_frame.globals.get_item_opt("__name__", vm)?);
|
||||
let module_name = vm.unwrap_or_none(
|
||||
current_frame
|
||||
.globals
|
||||
.get_item_opt(identifier!(vm, __name__), vm)?,
|
||||
);
|
||||
entry.or_insert(module_name);
|
||||
}
|
||||
}
|
||||
|
||||
attributes
|
||||
.entry("__qualname__".to_owned())
|
||||
.entry(identifier!(vm, __qualname__))
|
||||
.or_insert_with(|| vm.ctx.new_str(name.as_str()).into());
|
||||
|
||||
// All *classes* should have a dict. Exceptions are *instances* of
|
||||
// classes that define __slots__ and instances of built-in classes
|
||||
// (with exceptions, e.g function)
|
||||
attributes.entry("__dict__".to_owned()).or_insert_with(|| {
|
||||
vm.ctx
|
||||
.new_getset(
|
||||
"__dict__",
|
||||
vm.ctx.types.object_type.clone(),
|
||||
subtype_get_dict,
|
||||
subtype_set_dict,
|
||||
)
|
||||
.into()
|
||||
});
|
||||
attributes
|
||||
.entry(identifier!(vm, __dict__))
|
||||
.or_insert_with(|| {
|
||||
vm.ctx
|
||||
.new_getset(
|
||||
"__dict__",
|
||||
vm.ctx.types.object_type.clone(),
|
||||
subtype_get_dict,
|
||||
subtype_set_dict,
|
||||
)
|
||||
.into()
|
||||
});
|
||||
|
||||
// TODO: Flags is currently initialized with HAS_DICT. Should be
|
||||
// updated when __slots__ are supported (toggling the flag off if
|
||||
@@ -532,13 +548,12 @@ impl PyType {
|
||||
.read()
|
||||
.iter()
|
||||
.filter_map(|(name, obj)| {
|
||||
vm.get_method(obj.clone(), "__set_name__").map(|res| {
|
||||
res.map(|meth| (obj.clone(), PyStr::from(name.clone()).into_ref(vm), meth))
|
||||
})
|
||||
vm.get_method(obj.clone(), identifier!(vm, __set_name__))
|
||||
.map(|res| res.map(|meth| (obj.clone(), name.to_owned(), meth)))
|
||||
})
|
||||
.collect::<PyResult<Vec<_>>>()?;
|
||||
for (obj, name, set_name) in attributes {
|
||||
vm.invoke(&set_name, (typ.clone(), name.clone()))
|
||||
vm.invoke(&set_name, (typ.clone(), name.to_owned()))
|
||||
.map_err(|e| {
|
||||
let err = vm.new_runtime_error(format!(
|
||||
"Error calling __set_name__ on '{}' instance {} in '{}'",
|
||||
@@ -551,7 +566,7 @@ impl PyType {
|
||||
})?;
|
||||
}
|
||||
|
||||
if let Some(initter) = typ.get_super_attr("__init_subclass__") {
|
||||
if let Some(initter) = typ.get_super_attr(identifier!(vm, __init_subclass__)) {
|
||||
let initter = vm
|
||||
.call_get_descriptor_specific(initter.clone(), None, Some(typ.clone().into()))
|
||||
.unwrap_or(Ok(initter))?;
|
||||
@@ -629,10 +644,26 @@ pub(crate) fn get_text_signature_from_internal_doc<'a>(
|
||||
|
||||
impl GetAttr for PyType {
|
||||
fn getattro(zelf: &Py<Self>, name_str: PyStrRef, vm: &VirtualMachine) -> PyResult {
|
||||
let name = name_str.as_str();
|
||||
#[cold]
|
||||
fn attribute_error(
|
||||
zelf: &Py<PyType>,
|
||||
name: &str,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyBaseExceptionRef {
|
||||
vm.new_attribute_error(format!(
|
||||
"type object '{}' has no attribute '{}'",
|
||||
zelf.slot_name(),
|
||||
name,
|
||||
))
|
||||
}
|
||||
|
||||
let name = if let Some(name) = vm.ctx.interned_str(&*name_str) {
|
||||
name
|
||||
} else {
|
||||
return Err(attribute_error(zelf, name_str.as_str(), vm));
|
||||
};
|
||||
vm_trace!("type.__getattribute__({:?}, {:?})", zelf, name);
|
||||
let mcl = zelf.class();
|
||||
|
||||
let mcl_attr = mcl.get_attr(name);
|
||||
|
||||
if let Some(ref attr) = mcl_attr {
|
||||
@@ -663,11 +694,7 @@ impl GetAttr for PyType {
|
||||
drop(mcl);
|
||||
vm.call_if_get_descriptor(attr, zelf.to_owned().into())
|
||||
} else {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"type object '{}' has no attribute '{}'",
|
||||
zelf.slot_name(),
|
||||
name
|
||||
)))
|
||||
return Err(attribute_error(zelf, name_str.as_str(), vm));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -679,7 +706,9 @@ impl SetAttr for PyType {
|
||||
value: Option<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
if let Some(attr) = zelf.get_class_attr(attr_name.as_str()) {
|
||||
// TODO: pass PyRefExact instead of &str
|
||||
let attr_name = vm.ctx.intern_str(attr_name.as_str());
|
||||
if let Some(attr) = zelf.get_class_attr(attr_name) {
|
||||
let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load());
|
||||
if let Some(descriptor) = descr_set {
|
||||
return descriptor(attr, zelf.to_owned().into(), value, vm);
|
||||
@@ -689,18 +718,17 @@ impl SetAttr for PyType {
|
||||
|
||||
let mut attributes = zelf.attributes.write();
|
||||
if let Some(value) = value {
|
||||
attributes.insert(attr_name.as_str().to_owned(), value);
|
||||
attributes.insert(attr_name, value);
|
||||
} else {
|
||||
let prev_value = attributes.remove(attr_name.as_str());
|
||||
let prev_value = attributes.remove(attr_name);
|
||||
if prev_value.is_none() {
|
||||
return Err(vm.new_exception(
|
||||
vm.ctx.exceptions.attribute_error.clone(),
|
||||
vec![attr_name.into()],
|
||||
vec![attr_name.to_object()],
|
||||
));
|
||||
}
|
||||
}
|
||||
let attr_name = attr_name.as_str();
|
||||
if attr_name.starts_with("__") && attr_name.ends_with("__") {
|
||||
if attr_name.as_str().starts_with("__") && attr_name.as_str().ends_with("__") {
|
||||
zelf.update_slot(attr_name, assign);
|
||||
}
|
||||
Ok(())
|
||||
@@ -731,7 +759,7 @@ fn find_base_dict_descr(cls: &PyTypeRef, vm: &VirtualMachine) -> Option<PyObject
|
||||
// TODO: should actually be some translation of:
|
||||
// cls.slot_dictoffset != 0 && !cls.flags.contains(HEAPTYPE)
|
||||
if cls.is(&vm.ctx.types.type_type) {
|
||||
cls.get_attr("__dict__")
|
||||
cls.get_attr(identifier!(vm, __dict__))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -46,16 +46,20 @@ impl PyUnion {
|
||||
return Ok("None".to_string());
|
||||
}
|
||||
|
||||
if vm.get_attribute_opt(obj.clone(), "__origin__")?.is_some()
|
||||
&& vm.get_attribute_opt(obj.clone(), "__args__")?.is_some()
|
||||
if vm
|
||||
.get_attribute_opt(obj.clone(), identifier!(vm, __origin__))?
|
||||
.is_some()
|
||||
&& vm
|
||||
.get_attribute_opt(obj.clone(), identifier!(vm, __args__))?
|
||||
.is_some()
|
||||
{
|
||||
return Ok(obj.repr(vm)?.as_str().to_string());
|
||||
}
|
||||
|
||||
match (
|
||||
vm.get_attribute_opt(obj.clone(), "__qualname__")?
|
||||
vm.get_attribute_opt(obj.clone(), identifier!(vm, __qualname__))?
|
||||
.and_then(|o| o.downcast_ref::<PyStr>().map(|n| n.as_str().to_string())),
|
||||
vm.get_attribute_opt(obj.clone(), "__module__")?
|
||||
vm.get_attribute_opt(obj.clone(), identifier!(vm, __module__))?
|
||||
.and_then(|o| o.downcast_ref::<PyStr>().map(|m| m.as_str().to_string())),
|
||||
) {
|
||||
(None, _) | (_, None) => Ok(obj.repr(vm)?.as_str().to_string()),
|
||||
@@ -105,11 +109,11 @@ pub fn is_unionable(obj: PyObjectRef, vm: &VirtualMachine) -> bool {
|
||||
|| obj.class().is(&vm.ctx.types.union_type)
|
||||
}
|
||||
|
||||
fn is_typevar(obj: &PyObjectRef) -> bool {
|
||||
fn is_typevar(obj: &PyObjectRef, vm: &VirtualMachine) -> bool {
|
||||
let class = obj.class();
|
||||
class.slot_name() == "TypeVar"
|
||||
&& class
|
||||
.get_attr("__module__")
|
||||
.get_attr(identifier!(vm, __module__))
|
||||
.and_then(|o| o.downcast_ref::<PyStr>().map(|s| s.as_str() == "typing"))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
@@ -117,13 +121,13 @@ fn is_typevar(obj: &PyObjectRef) -> bool {
|
||||
fn make_parameters(args: &PyTupleRef, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len());
|
||||
for arg in args {
|
||||
if is_typevar(arg) {
|
||||
if is_typevar(arg, vm) {
|
||||
if !parameters.iter().any(|param| param.is(arg)) {
|
||||
parameters.push(arg.clone());
|
||||
}
|
||||
} else if let Ok(subparams) = arg
|
||||
.clone()
|
||||
.get_attr("__parameters__", vm)
|
||||
.get_attr(identifier!(vm, __parameters__), vm)
|
||||
.and_then(|obj| PyTupleRef::try_from_object(vm, obj))
|
||||
{
|
||||
for subparam in &subparams {
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::{
|
||||
},
|
||||
cformat::CFormatBytes,
|
||||
function::{ArgIterable, Either, OptionalArg, OptionalOption, PyComparisonValue},
|
||||
identifier,
|
||||
protocol::PyBuffer,
|
||||
sequence::{SequenceMutOp, SequenceOp},
|
||||
types::PyComparisonOp,
|
||||
@@ -86,7 +87,7 @@ impl ByteInnerNewOptions {
|
||||
obj
|
||||
};
|
||||
|
||||
if let Some(bytes_method) = vm.get_method(obj, "__bytes__") {
|
||||
if let Some(bytes_method) = vm.get_method(obj, identifier!(vm, __bytes__)) {
|
||||
// construct an exact bytes from __bytes__ slot.
|
||||
// if __bytes__ return a bytes, use the bytes object except we are the subclass of the bytes
|
||||
let bytes = vm.invoke(&bytes_method?, ())?;
|
||||
|
||||
+5
-5
@@ -395,7 +395,7 @@ impl CFormatSpec {
|
||||
Ok(buffer.contiguous_or_collect(|bytes| self.format_bytes(bytes)))
|
||||
} else {
|
||||
let bytes = vm
|
||||
.get_special_method(obj, "__bytes__")?
|
||||
.get_special_method(obj, identifier!(vm, __bytes__))?
|
||||
.map_err(|obj| {
|
||||
vm.new_type_error(format!(
|
||||
"%b requires a bytes-like object, or an object that \
|
||||
@@ -420,7 +420,7 @@ impl CFormatSpec {
|
||||
.into_bytes())
|
||||
}
|
||||
obj => {
|
||||
if let Some(method) = vm.get_method(obj.clone(), "__int__") {
|
||||
if let Some(method) = vm.get_method(obj.clone(), identifier!(vm, __int__)) {
|
||||
let result = vm.invoke(&method?, ())?;
|
||||
if let Some(i) = result.payload::<PyInt>() {
|
||||
return Ok(self.format_number(i.as_bigint()).into_bytes());
|
||||
@@ -514,7 +514,7 @@ impl CFormatSpec {
|
||||
Ok(self.format_number(&try_f64_to_bigint(f.to_f64(), vm)?))
|
||||
}
|
||||
obj => {
|
||||
if let Some(method) = vm.get_method(obj.clone(), "__int__") {
|
||||
if let Some(method) = vm.get_method(obj.clone(), identifier!(vm, __int__)) {
|
||||
let result = vm.invoke(&method?, ())?;
|
||||
if let Some(i) = result.payload::<PyInt>() {
|
||||
return Ok(self.format_number(i.as_bigint()));
|
||||
@@ -689,7 +689,7 @@ impl CFormatBytes {
|
||||
let (num_specifiers, mapping_required) = check_specifiers(&self.parts, vm)?;
|
||||
let mut result = vec![];
|
||||
|
||||
let is_mapping = values_obj.class().has_attr("__getitem__")
|
||||
let is_mapping = values_obj.class().has_attr(identifier!(vm, __getitem__))
|
||||
&& !values_obj.fast_isinstance(&vm.ctx.types.tuple_type)
|
||||
&& !values_obj.fast_isinstance(&vm.ctx.types.bytes_type)
|
||||
&& !values_obj.fast_isinstance(&vm.ctx.types.bytearray_type);
|
||||
@@ -841,7 +841,7 @@ impl CFormatString {
|
||||
let (num_specifiers, mapping_required) = check_specifiers(&self.parts, vm)?;
|
||||
let mut result = String::new();
|
||||
|
||||
let is_mapping = values_obj.class().has_attr("__getitem__")
|
||||
let is_mapping = values_obj.class().has_attr(identifier!(vm, __getitem__))
|
||||
&& !values_obj.fast_isinstance(&vm.ctx.types.tuple_type)
|
||||
&& !values_obj.fast_isinstance(&vm.ctx.types.str_type);
|
||||
|
||||
|
||||
+12
-6
@@ -2,6 +2,7 @@
|
||||
|
||||
use crate::{
|
||||
builtins::{PyBaseObject, PyBoundMethod, PyType, PyTypeRef},
|
||||
identifier,
|
||||
object::{PyObjectPayload, PyObjectRef, PyRef},
|
||||
types::{PyTypeFlags, PyTypeSlots},
|
||||
vm::Context,
|
||||
@@ -83,28 +84,33 @@ pub trait PyClassImpl: PyClassDef {
|
||||
assert!(class.slots.flags.is_created_with_flags());
|
||||
}
|
||||
if Self::TP_FLAGS.has_feature(PyTypeFlags::HAS_DICT) {
|
||||
class.set_str_attr(
|
||||
"__dict__",
|
||||
let __dict__ = identifier!(ctx, __dict__);
|
||||
class.set_attr(
|
||||
__dict__,
|
||||
ctx.new_getset(
|
||||
"__dict__",
|
||||
class.clone(),
|
||||
crate::builtins::object::object_get_dict,
|
||||
crate::builtins::object::object_set_dict,
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
Self::impl_extend_class(ctx, class);
|
||||
if let Some(doc) = Self::DOC {
|
||||
class.set_str_attr("__doc__", ctx.new_str(doc));
|
||||
class.set_attr(identifier!(ctx, __doc__), ctx.new_str(doc).into());
|
||||
}
|
||||
if let Some(module_name) = Self::MODULE_NAME {
|
||||
class.set_str_attr("__module__", ctx.new_str(module_name));
|
||||
class.set_attr(
|
||||
identifier!(ctx, __module__),
|
||||
ctx.new_str(module_name).into(),
|
||||
);
|
||||
}
|
||||
if class.slots.new.load().is_some() {
|
||||
let bound: PyObjectRef =
|
||||
PyBoundMethod::new_ref(class.clone().into(), ctx.slot_new_wrapper.clone(), ctx)
|
||||
.into();
|
||||
class.set_str_attr("__new__", bound);
|
||||
class.set_attr(identifier!(ctx, __new__), bound);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-3
@@ -8,7 +8,7 @@ use crate::common::{
|
||||
lock::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard},
|
||||
};
|
||||
use crate::{
|
||||
builtins::{PyInt, PyStr, PyStrRef},
|
||||
builtins::{PyInt, PyStr, PyStrInterned, PyStrRef},
|
||||
convert::ToPyObject,
|
||||
AsObject, Py, PyExact, PyObject, PyObjectRef, PyRefExact, PyResult, VirtualMachine,
|
||||
};
|
||||
@@ -751,9 +751,34 @@ impl DictKey for Py<PyStr> {
|
||||
}
|
||||
}
|
||||
|
||||
impl DictKey for PyStrInterned {
|
||||
type Owned = PyRefExact<PyStr>;
|
||||
#[inline]
|
||||
fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned {
|
||||
let zelf: &'static PyStrInterned = unsafe { &*(self as *const _) };
|
||||
zelf.to_exact()
|
||||
}
|
||||
#[inline]
|
||||
fn key_hash(&self, vm: &VirtualMachine) -> PyResult<HashValue> {
|
||||
(**self).key_hash(vm)
|
||||
}
|
||||
#[inline]
|
||||
fn key_is(&self, other: &PyObject) -> bool {
|
||||
(**self).key_is(other)
|
||||
}
|
||||
#[inline]
|
||||
fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult<bool> {
|
||||
(**self).key_eq(vm, other_key)
|
||||
}
|
||||
#[inline]
|
||||
fn key_as_isize(&self, vm: &VirtualMachine) -> PyResult<isize> {
|
||||
(**self).key_as_isize(vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl DictKey for PyExact<PyStr> {
|
||||
type Owned = PyRefExact<PyStr>;
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned {
|
||||
self.to_owned()
|
||||
}
|
||||
@@ -761,7 +786,7 @@ impl DictKey for PyExact<PyStr> {
|
||||
fn key_hash(&self, vm: &VirtualMachine) -> PyResult<HashValue> {
|
||||
(**self).key_hash(vm)
|
||||
}
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
fn key_is(&self, other: &PyObject) -> bool {
|
||||
(**self).key_is(other)
|
||||
}
|
||||
|
||||
@@ -765,7 +765,8 @@ impl ExceptionZoo {
|
||||
});
|
||||
// TODO: this isn't really accurate
|
||||
#[cfg(windows)]
|
||||
excs.os_error.set_str_attr("winerror", errno_getter.clone());
|
||||
excs.os_error
|
||||
.set_str_attr("winerror", errno_getter.clone(), ctx);
|
||||
|
||||
extend_exception!(PyBlockingIOError, ctx, &excs.blocking_io_error);
|
||||
extend_exception!(PyChildProcessError, ctx, &excs.child_process_error);
|
||||
|
||||
+4
-2
@@ -892,10 +892,12 @@ pub fn call_object_format(
|
||||
Some(FormatPreconversor::Str) => argument.str(vm)?.into(),
|
||||
Some(FormatPreconversor::Repr) => argument.repr(vm)?.into(),
|
||||
Some(FormatPreconversor::Ascii) => vm.ctx.new_str(builtins::ascii(argument, vm)?).into(),
|
||||
Some(FormatPreconversor::Bytes) => vm.call_method(&argument, "decode", ())?,
|
||||
Some(FormatPreconversor::Bytes) => {
|
||||
vm.call_method(&argument, identifier!(vm, decode).as_str(), ())?
|
||||
}
|
||||
None => argument,
|
||||
};
|
||||
let result = vm.call_special_method(argument, "__format__", (format_spec,))?;
|
||||
let result = vm.call_special_method(argument, identifier!(vm, __format__), (format_spec,))?;
|
||||
result.downcast().map_err(|result| {
|
||||
vm.new_type_error(format!(
|
||||
"__format__ must return a str, not {}",
|
||||
|
||||
+29
-22
@@ -723,6 +723,7 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::YieldFrom => self.execute_yield_from(vm),
|
||||
bytecode::Instruction::SetupAnnotation => {
|
||||
let __annotations__ = identifier!(vm, __annotations__);
|
||||
// Try using locals as dict first, if not, fallback to generic method.
|
||||
let has_annotations = match self
|
||||
.locals
|
||||
@@ -730,15 +731,15 @@ impl ExecutingFrame<'_> {
|
||||
.into_object()
|
||||
.downcast_exact::<PyDict>(vm)
|
||||
{
|
||||
Ok(d) => d.contains_key("__annotations__", vm),
|
||||
Ok(d) => d.contains_key(__annotations__, vm),
|
||||
Err(o) => {
|
||||
let needle = vm.new_pyobj("__annotations__");
|
||||
let needle = __annotations__.to_object();
|
||||
self._in(vm, needle, o)?
|
||||
}
|
||||
};
|
||||
if !has_annotations {
|
||||
self.locals.as_object().set_item(
|
||||
"__annotations__",
|
||||
__annotations__,
|
||||
vm.ctx.new_dict().into(),
|
||||
vm,
|
||||
)?;
|
||||
@@ -786,19 +787,20 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::SetupWith { end } => {
|
||||
let context_manager = self.pop_value();
|
||||
let exit = context_manager.get_attr("__exit__", vm)?;
|
||||
let exit = context_manager.get_attr(identifier!(vm, __exit__), vm)?;
|
||||
self.push_value(exit);
|
||||
// Call enter:
|
||||
let enter_res = vm.call_special_method(context_manager, "__enter__", ())?;
|
||||
let enter_res =
|
||||
vm.call_special_method(context_manager, identifier!(vm, __enter__), ())?;
|
||||
self.push_block(BlockType::Finally { handler: *end });
|
||||
self.push_value(enter_res);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::BeforeAsyncWith => {
|
||||
let mgr = self.pop_value();
|
||||
let aexit = mgr.get_attr("__aexit__", vm)?;
|
||||
let aexit = mgr.get_attr(identifier!(vm, __aexit__), vm)?;
|
||||
self.push_value(aexit);
|
||||
let aenter_res = vm.call_special_method(mgr, "__aenter__", ())?;
|
||||
let aenter_res = vm.call_special_method(mgr, identifier!(vm, __aenter__), ())?;
|
||||
self.push_value(aenter_res);
|
||||
|
||||
Ok(None)
|
||||
@@ -866,13 +868,16 @@ impl ExecutingFrame<'_> {
|
||||
let awaitable = if awaited_obj.payload_is::<PyCoroutine>() {
|
||||
awaited_obj
|
||||
} else {
|
||||
let await_method =
|
||||
vm.get_method_or_type_error(awaited_obj.clone(), "__await__", || {
|
||||
let await_method = vm.get_method_or_type_error(
|
||||
awaited_obj.clone(),
|
||||
identifier!(vm, __await__),
|
||||
|| {
|
||||
format!(
|
||||
"object {} can't be used in 'await' expression",
|
||||
awaited_obj.class().name(),
|
||||
)
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
vm.invoke(&await_method, ())?
|
||||
};
|
||||
self.push_value(awaitable);
|
||||
@@ -880,17 +885,17 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
bytecode::Instruction::GetAIter => {
|
||||
let aiterable = self.pop_value();
|
||||
let aiter = vm.call_special_method(aiterable, "__aiter__", ())?;
|
||||
let aiter = vm.call_special_method(aiterable, identifier!(vm, __aiter__), ())?;
|
||||
self.push_value(aiter);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::GetANext => {
|
||||
let aiter = self.last_value();
|
||||
let awaitable = vm.call_special_method(aiter, "__anext__", ())?;
|
||||
let awaitable = vm.call_special_method(aiter, identifier!(vm, __anext__), ())?;
|
||||
let awaitable = if awaitable.payload_is::<PyCoroutine>() {
|
||||
awaitable
|
||||
} else {
|
||||
vm.call_special_method(awaitable, "__await__", ())?
|
||||
vm.call_special_method(awaitable, identifier!(vm, __await__), ())?
|
||||
};
|
||||
self.push_value(awaitable);
|
||||
Ok(None)
|
||||
@@ -1009,7 +1014,7 @@ impl ExecutingFrame<'_> {
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::LoadBuildClass => {
|
||||
self.push_value(vm.builtins.get_attr("__build_class__", vm)?);
|
||||
self.push_value(vm.builtins.get_attr(identifier!(vm, __build_class__), vm)?);
|
||||
Ok(None)
|
||||
}
|
||||
bytecode::Instruction::UnpackSequence { size } => {
|
||||
@@ -1135,7 +1140,9 @@ impl ExecutingFrame<'_> {
|
||||
return Ok(obj);
|
||||
}
|
||||
// fallback to importing '{module.__name__}.{name}' from sys.modules
|
||||
let mod_name = module.get_attr("__name__", vm).map_err(|_| err())?;
|
||||
let mod_name = module
|
||||
.get_attr(identifier!(vm, __name__), vm)
|
||||
.map_err(|_| err())?;
|
||||
let mod_name = mod_name.downcast::<PyStr>().map_err(|_| err())?;
|
||||
let full_mod_name = format!("{}.{}", mod_name, name);
|
||||
let sys_modules = vm
|
||||
@@ -1153,7 +1160,7 @@ impl ExecutingFrame<'_> {
|
||||
// Grab all the names from the module and put them in the context
|
||||
if let Some(dict) = module.dict() {
|
||||
let filter_pred: Box<dyn Fn(&str) -> bool> =
|
||||
if let Ok(all) = dict.get_item("__all__", vm) {
|
||||
if let Ok(all) = dict.get_item(identifier!(vm, __all__), vm) {
|
||||
let all: Vec<PyStrRef> = all.try_to_value(vm)?;
|
||||
let all: Vec<String> = all
|
||||
.into_iter()
|
||||
@@ -1595,14 +1602,14 @@ impl ExecutingFrame<'_> {
|
||||
)
|
||||
.into_pyobject(vm);
|
||||
|
||||
func_obj.set_attr("__doc__", vm.ctx.none(), vm)?;
|
||||
func_obj.set_attr(identifier!(vm, __doc__), vm.ctx.none(), vm)?;
|
||||
|
||||
let name = qualified_name.as_str().split('.').next_back().unwrap();
|
||||
func_obj.set_attr("__name__", vm.new_pyobj(name), vm)?;
|
||||
func_obj.set_attr("__qualname__", qualified_name, vm)?;
|
||||
let module = vm.unwrap_or_none(self.globals.get_item_opt("__name__", vm)?);
|
||||
func_obj.set_attr("__module__", module, vm)?;
|
||||
func_obj.set_attr("__annotations__", annotations, vm)?;
|
||||
func_obj.set_attr(identifier!(vm, __name__), vm.new_pyobj(name), vm)?;
|
||||
func_obj.set_attr(identifier!(vm, __qualname__), qualified_name, vm)?;
|
||||
let module = vm.unwrap_or_none(self.globals.get_item_opt(identifier!(vm, __name__), vm)?);
|
||||
func_obj.set_attr(identifier!(vm, __module__), module, vm)?;
|
||||
func_obj.set_attr(identifier!(vm, __annotations__), annotations, vm)?;
|
||||
|
||||
self.push_value(func_obj);
|
||||
Ok(None)
|
||||
|
||||
@@ -2,6 +2,7 @@ use super::IntoFuncArgs;
|
||||
use crate::{
|
||||
builtins::{iter::PySequenceIterator, PyDict, PyDictRef},
|
||||
convert::ToPyObject,
|
||||
identifier,
|
||||
protocol::{PyIter, PyIterIter, PyMapping, PyMappingMethods},
|
||||
AsObject, PyObject, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine,
|
||||
};
|
||||
@@ -86,7 +87,7 @@ where
|
||||
{
|
||||
let cls = obj.class();
|
||||
iterfn = cls.mro_find_map(|x| x.slots.iter.load());
|
||||
if iterfn.is_none() && !cls.has_attr("__getitem__") {
|
||||
if iterfn.is_none() && !cls.has_attr(identifier!(vm, __getitem__)) {
|
||||
return Err(vm.new_type_error(format!("'{}' object is not iterable", cls.name())));
|
||||
}
|
||||
}
|
||||
|
||||
+9
-2
@@ -30,7 +30,7 @@ macro_rules! py_class {
|
||||
(@extract_slots($ctx:expr, $class:expr, $name:expr, $value:expr)) => {};
|
||||
(@extract_attrs($ctx:expr, $slots:expr, (slot $slot_name:ident), $value:expr)) => {};
|
||||
(@extract_attrs($ctx:expr, $class:expr, $name:expr, $value:expr)) => {
|
||||
$class.set_str_attr($name, $value);
|
||||
$class.set_attr($name, $value);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ macro_rules! py_class {
|
||||
macro_rules! extend_class {
|
||||
( $ctx:expr, $class:expr, { $($name:expr => $value:expr),* $(,)* }) => {
|
||||
$(
|
||||
$class.set_str_attr($name, $value);
|
||||
$class.set_attr($ctx.intern_str($name), $value.into());
|
||||
)*
|
||||
};
|
||||
}
|
||||
@@ -177,6 +177,13 @@ macro_rules! match_class {
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! identifier(
|
||||
($as_ctx:expr, $name:ident) => {
|
||||
$as_ctx.as_ref().names.$name
|
||||
};
|
||||
);
|
||||
|
||||
/// Super detailed logging. Might soon overflow your logbuffers
|
||||
/// Default, this logging is discarded, except when a the `vm-tracing-logging`
|
||||
/// build feature is enabled.
|
||||
|
||||
@@ -744,7 +744,7 @@ impl PyObject {
|
||||
let ret = crate::vm::thread::with_vm(zelf, |vm| {
|
||||
zelf.0.ref_count.inc();
|
||||
if let Err(e) = slot_del(zelf, vm) {
|
||||
let del_method = zelf.get_class_attr("__del__").unwrap();
|
||||
let del_method = zelf.get_class_attr(identifier!(vm, __del__)).unwrap();
|
||||
vm.run_unraisable(e, None, del_method);
|
||||
}
|
||||
zelf.0.ref_count.dec()
|
||||
|
||||
@@ -4,7 +4,7 @@ use super::{
|
||||
};
|
||||
use crate::common::lock::PyRwLockReadGuard;
|
||||
use crate::{
|
||||
builtins::{PyBaseExceptionRef, PyType},
|
||||
builtins::{PyBaseExceptionRef, PyStrInterned, PyType},
|
||||
convert::{ToPyException, ToPyObject, ToPyResult, TryFromObject},
|
||||
VirtualMachine,
|
||||
};
|
||||
@@ -251,7 +251,7 @@ where
|
||||
self.as_object().lease_class()
|
||||
}
|
||||
|
||||
fn get_class_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
|
||||
fn get_class_attr(&self, attr_name: &'static PyStrInterned) -> Option<PyObjectRef> {
|
||||
self.class().get_attr(attr_name)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
builtins::{
|
||||
dict::{PyDictItems, PyDictKeys, PyDictValues},
|
||||
PyDict,
|
||||
PyDict, PyStrInterned,
|
||||
},
|
||||
common::lock::OnceCell,
|
||||
convert::ToPyResult,
|
||||
@@ -135,7 +135,7 @@ impl PyMapping<'_> {
|
||||
if let Some(dict) = self.obj.downcast_ref_if_exact::<PyDict>(vm) {
|
||||
PyDictKeys::new(dict.to_owned()).to_pyresult(vm)
|
||||
} else {
|
||||
self.method_output_as_list("keys", vm)
|
||||
self.method_output_as_list(identifier!(vm, keys), vm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ impl PyMapping<'_> {
|
||||
if let Some(dict) = self.obj.downcast_ref_if_exact::<PyDict>(vm) {
|
||||
PyDictValues::new(dict.to_owned()).to_pyresult(vm)
|
||||
} else {
|
||||
self.method_output_as_list("values", vm)
|
||||
self.method_output_as_list(identifier!(vm, values), vm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,12 +151,16 @@ impl PyMapping<'_> {
|
||||
if let Some(dict) = self.obj.downcast_ref_if_exact::<PyDict>(vm) {
|
||||
PyDictItems::new(dict.to_owned()).to_pyresult(vm)
|
||||
} else {
|
||||
self.method_output_as_list("items", vm)
|
||||
self.method_output_as_list(identifier!(vm, items), vm)
|
||||
}
|
||||
}
|
||||
|
||||
fn method_output_as_list(&self, method_name: &str, vm: &VirtualMachine) -> PyResult {
|
||||
let meth_output = vm.call_method(self.obj, method_name, ())?;
|
||||
fn method_output_as_list(
|
||||
&self,
|
||||
method_name: &'static PyStrInterned,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
let meth_output = vm.call_method(self.obj, method_name.as_str(), ())?;
|
||||
if meth_output.is(&vm.ctx.types.list_type) {
|
||||
return Ok(meth_output);
|
||||
}
|
||||
@@ -165,7 +169,7 @@ impl PyMapping<'_> {
|
||||
vm.new_type_error(format!(
|
||||
"{}.{}() returned a non-iterable (type {})",
|
||||
self.obj.class(),
|
||||
method_name,
|
||||
method_name.as_str(),
|
||||
meth_output.class()
|
||||
))
|
||||
})?;
|
||||
|
||||
+37
-24
@@ -143,8 +143,11 @@ impl PyObject {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
vm_trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value);
|
||||
|
||||
if let Some(attr) = self.get_class_attr(attr_name.as_str()) {
|
||||
if let Some(attr) = vm
|
||||
.ctx
|
||||
.interned_str(&*attr_name)
|
||||
.and_then(|attr_name| self.get_class_attr(attr_name))
|
||||
{
|
||||
let descr_set = attr.class().mro_find_map(|cls| cls.slots.descr_set.load());
|
||||
if let Some(descriptor) = descr_set {
|
||||
return descriptor(attr, self.to_owned(), value, vm);
|
||||
@@ -160,7 +163,7 @@ impl PyObject {
|
||||
vm.new_attribute_error(format!(
|
||||
"'{}' object has no attribute '{}'",
|
||||
self.class().name(),
|
||||
attr_name,
|
||||
attr_name.as_str(),
|
||||
))
|
||||
} else {
|
||||
e
|
||||
@@ -172,7 +175,7 @@ impl PyObject {
|
||||
Err(vm.new_attribute_error(format!(
|
||||
"'{}' object has no attribute '{}'",
|
||||
self.class().name(),
|
||||
attr_name,
|
||||
attr_name.as_str(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
@@ -191,7 +194,8 @@ impl PyObject {
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
let name = name_str.as_str();
|
||||
let obj_cls = self.class();
|
||||
let cls_attr = match obj_cls.get_attr(name) {
|
||||
let cls_attr_name = vm.ctx.interned_str(&*name_str);
|
||||
let cls_attr = match cls_attr_name.and_then(|name| obj_cls.get_attr(name)) {
|
||||
Some(descr) => {
|
||||
let descr_cls = descr.class();
|
||||
let descr_get = descr_cls.mro_find_map(|cls| cls.slots.descr_get.load());
|
||||
@@ -229,7 +233,7 @@ impl PyObject {
|
||||
}
|
||||
None => Ok(Some(attr)),
|
||||
}
|
||||
} else if let Some(getter) = obj_cls.get_attr("__getattr__") {
|
||||
} else if let Some(getter) = obj_cls.get_attr(identifier!(vm, __getattr__)) {
|
||||
drop(obj_cls);
|
||||
vm.invoke(&getter, (self.to_owned(), name_str)).map(Some)
|
||||
} else {
|
||||
@@ -310,7 +314,7 @@ impl PyObject {
|
||||
|
||||
pub fn repr(&self, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
vm.with_recursion("while getting the repr of an object", || {
|
||||
let repr = vm.call_special_method(self.to_owned(), "__repr__", ())?;
|
||||
let repr = vm.call_special_method(self.to_owned(), identifier!(vm, __repr__), ())?;
|
||||
repr.try_into_value(vm)
|
||||
})
|
||||
}
|
||||
@@ -326,7 +330,7 @@ impl PyObject {
|
||||
if self.class().is(&vm.ctx.types.str_type) {
|
||||
Ok(self.to_owned().downcast().unwrap())
|
||||
} else {
|
||||
let s = vm.call_special_method(self.to_owned(), "__str__", ())?;
|
||||
let s = vm.call_special_method(self.to_owned(), identifier!(vm, __str__), ())?;
|
||||
s.try_into_value(vm)
|
||||
}
|
||||
}
|
||||
@@ -337,14 +341,16 @@ impl PyObject {
|
||||
where
|
||||
F: Fn() -> String,
|
||||
{
|
||||
cls.to_owned().get_attr("__bases__", vm).map_err(|e| {
|
||||
// Only mask AttributeErrors.
|
||||
if e.class().is(&vm.ctx.exceptions.attribute_error) {
|
||||
vm.new_type_error(msg())
|
||||
} else {
|
||||
e
|
||||
}
|
||||
})
|
||||
cls.to_owned()
|
||||
.get_attr(identifier!(vm, __bases__), vm)
|
||||
.map_err(|e| {
|
||||
// Only mask AttributeErrors.
|
||||
if e.class().is(&vm.ctx.exceptions.attribute_error) {
|
||||
vm.new_type_error(msg())
|
||||
} else {
|
||||
e
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn abstract_issubclass(&self, cls: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
@@ -355,7 +361,9 @@ impl PyObject {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let bases = derived.to_owned().get_attr("__bases__", vm)?;
|
||||
let bases = derived
|
||||
.to_owned()
|
||||
.get_attr(identifier!(vm, __bases__), vm)?;
|
||||
let tuple = PyTupleRef::try_from_object(vm, bases)?;
|
||||
|
||||
let n = tuple.len();
|
||||
@@ -420,7 +428,9 @@ impl PyObject {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if let Ok(meth) = vm.get_special_method(cls.to_owned(), "__subclasscheck__")? {
|
||||
if let Ok(meth) =
|
||||
vm.get_special_method(cls.to_owned(), identifier!(vm, __subclasscheck__))?
|
||||
{
|
||||
let ret = vm.with_recursion("in __subclasscheck__", || {
|
||||
meth.invoke((self.to_owned(),), vm)
|
||||
})?;
|
||||
@@ -434,9 +444,10 @@ impl PyObject {
|
||||
if let Ok(typ) = PyTypeRef::try_from_object(vm, cls.to_owned()) {
|
||||
if self.class().fast_issubclass(&typ) {
|
||||
Ok(true)
|
||||
} else if let Ok(icls) =
|
||||
PyTypeRef::try_from_object(vm, self.to_owned().get_attr("__class__", vm)?)
|
||||
{
|
||||
} else if let Ok(icls) = PyTypeRef::try_from_object(
|
||||
vm,
|
||||
self.to_owned().get_attr(identifier!(vm, __class__), vm)?,
|
||||
) {
|
||||
if icls.is(&self.class()) {
|
||||
Ok(false)
|
||||
} else {
|
||||
@@ -453,7 +464,7 @@ impl PyObject {
|
||||
)
|
||||
})
|
||||
.and_then(|_| {
|
||||
let icls: PyObjectRef = self.to_owned().get_attr("__class__", vm)?;
|
||||
let icls: PyObjectRef = self.to_owned().get_attr(identifier!(vm, __class__), vm)?;
|
||||
if vm.is_none(&icls) {
|
||||
Ok(false)
|
||||
} else {
|
||||
@@ -485,7 +496,9 @@ impl PyObject {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if let Ok(meth) = vm.get_special_method(cls.to_owned(), "__instancecheck__")? {
|
||||
if let Ok(meth) =
|
||||
vm.get_special_method(cls.to_owned(), identifier!(vm, __instancecheck__))?
|
||||
{
|
||||
let ret = vm.with_recursion("in __instancecheck__", || {
|
||||
meth.invoke((self.to_owned(),), vm)
|
||||
})?;
|
||||
@@ -538,7 +551,7 @@ impl PyObject {
|
||||
}
|
||||
|
||||
if let Some(class_getitem) =
|
||||
vm.get_attribute_opt(self.to_owned(), "__class_getitem__")?
|
||||
vm.get_attribute_opt(self.to_owned(), identifier!(vm, __class_getitem__))?
|
||||
{
|
||||
return vm.invoke(&class_getitem, (needle,));
|
||||
}
|
||||
|
||||
+540
-424
File diff suppressed because it is too large.
Load diff
+26
-18
@@ -218,9 +218,9 @@ mod builtins {
|
||||
fn make_scope(self, vm: &VirtualMachine) -> PyResult<Scope> {
|
||||
let (globals, locals) = match self.globals {
|
||||
Some(globals) => {
|
||||
if !globals.contains_key("__builtins__", vm) {
|
||||
if !globals.contains_key(identifier!(vm, __builtins__), vm) {
|
||||
let builtins_dict = vm.builtins.dict().into();
|
||||
globals.set_item("__builtins__", builtins_dict, vm)?;
|
||||
globals.set_item(identifier!(vm, __builtins__), builtins_dict, vm)?;
|
||||
}
|
||||
(
|
||||
globals.clone(),
|
||||
@@ -424,7 +424,7 @@ mod builtins {
|
||||
#[pyfunction]
|
||||
fn aiter(iter_target: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if iter_target.payload_is::<PyAsyncGen>() {
|
||||
vm.call_special_method(iter_target, "__aiter__", ())
|
||||
vm.call_special_method(iter_target, identifier!(vm, __aiter__), ())
|
||||
} else {
|
||||
Err(vm.new_type_error("wrong argument type".to_owned()))
|
||||
}
|
||||
@@ -591,14 +591,18 @@ mod builtins {
|
||||
modulus,
|
||||
} = args;
|
||||
match modulus {
|
||||
None => vm.call_or_reflection(&x, &y, "__pow__", "__rpow__", |vm, x, y| {
|
||||
Err(vm.new_unsupported_binop_error(x, y, "pow"))
|
||||
}),
|
||||
None => vm.call_or_reflection(
|
||||
&x,
|
||||
&y,
|
||||
identifier!(vm, __pow__),
|
||||
identifier!(vm, __rpow__),
|
||||
|vm, x, y| Err(vm.new_unsupported_binop_error(x, y, "pow")),
|
||||
),
|
||||
Some(z) => {
|
||||
let try_pow_value = |obj: &PyObject,
|
||||
args: (PyObjectRef, PyObjectRef, PyObjectRef)|
|
||||
-> Option<PyResult> {
|
||||
let method = obj.get_class_attr("__pow__")?;
|
||||
let method = obj.get_class_attr(identifier!(vm, __pow__))?;
|
||||
let result = match vm.invoke(&method, args) {
|
||||
Ok(x) => x,
|
||||
Err(e) => return Some(Err(e)),
|
||||
@@ -685,10 +689,10 @@ mod builtins {
|
||||
|
||||
#[pyfunction]
|
||||
fn reversed(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
if let Some(reversed_method) = vm.get_method(obj.clone(), "__reversed__") {
|
||||
if let Some(reversed_method) = vm.get_method(obj.clone(), identifier!(vm, __reversed__)) {
|
||||
vm.invoke(&reversed_method?, ())
|
||||
} else {
|
||||
vm.get_method_or_type_error(obj.clone(), "__getitem__", || {
|
||||
vm.get_method_or_type_error(obj.clone(), identifier!(vm, __getitem__), || {
|
||||
"argument to reversed() must be a sequence".to_owned()
|
||||
})?;
|
||||
let len = obj.length(vm)?;
|
||||
@@ -707,7 +711,7 @@ mod builtins {
|
||||
#[pyfunction]
|
||||
fn round(RoundArgs { number, ndigits }: RoundArgs, vm: &VirtualMachine) -> PyResult {
|
||||
let meth = vm
|
||||
.get_special_method(number, "__round__")?
|
||||
.get_special_method(number, identifier!(vm, __round__))?
|
||||
.map_err(|number| {
|
||||
vm.new_type_error(format!(
|
||||
"type {} doesn't define __round__",
|
||||
@@ -792,9 +796,10 @@ mod builtins {
|
||||
#[pyfunction]
|
||||
fn vars(obj: OptionalArg, vm: &VirtualMachine) -> PyResult {
|
||||
if let OptionalArg::Present(obj) = obj {
|
||||
obj.get_attr("__dict__", vm).map_err(|_| {
|
||||
vm.new_type_error("vars() argument must have __dict__ attribute".to_owned())
|
||||
})
|
||||
obj.get_attr(identifier!(vm, __dict__).to_owned(), vm)
|
||||
.map_err(|_| {
|
||||
vm.new_type_error("vars() argument must have __dict__ attribute".to_owned())
|
||||
})
|
||||
} else {
|
||||
Ok(vm.current_locals()?.into())
|
||||
}
|
||||
@@ -821,7 +826,8 @@ mod builtins {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let mro_entries = vm.get_attribute_opt(base.clone(), "__mro_entries__")?;
|
||||
let mro_entries =
|
||||
vm.get_attribute_opt(base.clone(), identifier!(vm, __mro_entries__))?;
|
||||
let entries = match mro_entries {
|
||||
Some(meth) => vm.invoke(&meth, (bases.clone(),))?,
|
||||
None => {
|
||||
@@ -874,7 +880,7 @@ mod builtins {
|
||||
|
||||
// Prepare uses full __getattribute__ resolution chain.
|
||||
let namespace = vm
|
||||
.get_attribute_opt(metaclass.clone(), "__prepare__")?
|
||||
.get_attribute_opt(metaclass.clone(), identifier!(vm, __prepare__))?
|
||||
.map_or(Ok(vm.ctx.new_dict().into()), |prepare| {
|
||||
vm.invoke(
|
||||
&prepare,
|
||||
@@ -895,9 +901,11 @@ mod builtins {
|
||||
let classcell = <Option<PyCellRef>>::try_from_object(vm, classcell)?;
|
||||
|
||||
if let Some(orig_bases) = orig_bases {
|
||||
namespace
|
||||
.as_object()
|
||||
.set_item("__orig_bases__", orig_bases.into(), vm)?;
|
||||
namespace.as_object().set_item(
|
||||
identifier!(vm, __orig_bases__),
|
||||
orig_bases.into(),
|
||||
vm,
|
||||
)?;
|
||||
}
|
||||
|
||||
let class = vm.invoke(
|
||||
|
||||
+1
-1
@@ -1192,7 +1192,7 @@ mod _io {
|
||||
}
|
||||
|
||||
let readall = vm
|
||||
.get_method(self.raw.clone().unwrap(), "readall")
|
||||
.get_str_method(self.raw.clone().unwrap(), "readall")
|
||||
.transpose()?;
|
||||
if let Some(readall) = readall {
|
||||
let res = vm.invoke(&readall, ())?;
|
||||
|
||||
@@ -10,6 +10,7 @@ mod decl {
|
||||
builtins::{int, PyGenericAlias, PyInt, PyIntRef, PyTuple, PyTupleRef, PyTypeRef},
|
||||
convert::ToPyObject,
|
||||
function::{ArgCallable, FuncArgs, OptionalArg, OptionalOption, PosArgs},
|
||||
identifier,
|
||||
protocol::{PyIter, PyIterReturn},
|
||||
stdlib::sys,
|
||||
types::{Constructor, IterNext, IterNextIterable},
|
||||
@@ -1019,15 +1020,19 @@ mod decl {
|
||||
) -> PyResult {
|
||||
let n = n.unwrap_or(2);
|
||||
|
||||
let copyable = if iterable.class().has_attr("__copy__") {
|
||||
vm.call_method(&iterable, "__copy__", ())?
|
||||
let copyable = if iterable.class().has_attr(identifier!(vm, __copy__)) {
|
||||
vm.call_special_method(iterable.into(), identifier!(vm, __copy__), ())?
|
||||
} else {
|
||||
PyItertoolsTee::from_iter(iterable, vm)?
|
||||
};
|
||||
|
||||
let mut tee_vec: Vec<PyObjectRef> = Vec::with_capacity(n);
|
||||
for _ in 0..n {
|
||||
tee_vec.push(vm.call_method(©able, "__copy__", ())?);
|
||||
tee_vec.push(vm.call_special_method(
|
||||
copyable.clone(),
|
||||
identifier!(vm, __copy__),
|
||||
(),
|
||||
)?);
|
||||
}
|
||||
|
||||
Ok(PyTuple::new_ref(tee_vec, &vm.ctx).into())
|
||||
@@ -1039,7 +1044,7 @@ mod decl {
|
||||
fn from_iter(iterator: PyIter, vm: &VirtualMachine) -> PyResult {
|
||||
let class = PyItertoolsTee::class(vm);
|
||||
if iterator.class().is(PyItertoolsTee::class(vm)) {
|
||||
return vm.call_method(&iterator, "__copy__", ());
|
||||
return vm.call_special_method(iterator.into(), identifier!(vm, __copy__), ());
|
||||
}
|
||||
Ok(PyItertoolsTee {
|
||||
tee_data: PyItertoolsTeeData::new(iterator, vm)?,
|
||||
|
||||
@@ -14,6 +14,7 @@ mod _operator {
|
||||
builtins::{PyInt, PyIntRef, PyStrRef, PyTupleRef, PyTypeRef},
|
||||
function::Either,
|
||||
function::{ArgBytesLike, FuncArgs, KwArgs, OptionalArg},
|
||||
identifier,
|
||||
protocol::PyIter,
|
||||
recursion::ReprGuard,
|
||||
types::{Callable, Constructor, PyComparisonOp},
|
||||
@@ -196,7 +197,9 @@ mod _operator {
|
||||
#[pyfunction]
|
||||
fn concat(a: PyObjectRef, b: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
// Best attempt at checking that a is sequence-like.
|
||||
if !a.class().has_attr("__getitem__") || a.fast_isinstance(&vm.ctx.types.dict_type) {
|
||||
if !a.class().has_attr(identifier!(vm, __getitem__))
|
||||
|| a.fast_isinstance(&vm.ctx.types.dict_type)
|
||||
{
|
||||
return Err(
|
||||
vm.new_type_error(format!("{} object can't be concatenated", a.class().name()))
|
||||
);
|
||||
@@ -299,7 +302,9 @@ mod _operator {
|
||||
#[pyfunction]
|
||||
fn iconcat(a: PyObjectRef, b: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
// Best attempt at checking that a is sequence-like.
|
||||
if !a.class().has_attr("__getitem__") || a.fast_isinstance(&vm.ctx.types.dict_type) {
|
||||
if !a.class().has_attr(identifier!(vm, __getitem__))
|
||||
|| a.fast_isinstance(&vm.ctx.types.dict_type)
|
||||
{
|
||||
return Err(
|
||||
vm.new_type_error(format!("{} object can't be concatenated", a.class().name()))
|
||||
);
|
||||
|
||||
+8
-6
@@ -3,6 +3,7 @@ use crate::{
|
||||
common::crt_fd::Fd,
|
||||
convert::{ToPyException, ToPyObject},
|
||||
function::{ArgumentError, FromArgs, FuncArgs},
|
||||
identifier,
|
||||
protocol::PyBuffer,
|
||||
AsObject, PyObject, PyObjectRef, PyPayload, PyResult, TryFromBorrowedObject, TryFromObject,
|
||||
VirtualMachine,
|
||||
@@ -137,12 +138,13 @@ impl FsPath {
|
||||
Ok(pathlike) => return Ok(pathlike),
|
||||
Err(obj) => obj,
|
||||
};
|
||||
let method = vm.get_method_or_type_error(obj.clone(), "__fspath__", || {
|
||||
format!(
|
||||
"should be string, bytes, os.PathLike or integer, not {}",
|
||||
obj.class().name()
|
||||
)
|
||||
})?;
|
||||
let method =
|
||||
vm.get_method_or_type_error(obj.clone(), identifier!(vm, __fspath__), || {
|
||||
format!(
|
||||
"should be string, bytes, os.PathLike or integer, not {}",
|
||||
obj.class().name()
|
||||
)
|
||||
})?;
|
||||
let result = vm.invoke(&method, ())?;
|
||||
match1(result)?.map_err(|result| {
|
||||
vm.new_type_error(format!(
|
||||
|
||||
@@ -282,7 +282,7 @@ mod _sre {
|
||||
must_advance: AtomicCell::new(false),
|
||||
}
|
||||
.into_ref(vm);
|
||||
let search = vm.get_method(scanner.into(), "search").unwrap()?;
|
||||
let search = vm.get_str_method(scanner.into(), "search").unwrap()?;
|
||||
let search = ArgCallable::try_from_object(vm, search)?;
|
||||
let iterator = PyCallableIterator::new(search, vm.ctx.none());
|
||||
Ok(iterator)
|
||||
|
||||
@@ -245,8 +245,9 @@ pub(crate) mod _thread {
|
||||
let args = FuncArgs::new(
|
||||
args.to_vec(),
|
||||
kwargs
|
||||
.map_or_else(Default::default, |k| k.to_attributes())
|
||||
.map_or_else(Default::default, |k| k.to_attributes(vm))
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.as_str().to_owned(), v))
|
||||
.collect::<KwArgs>(),
|
||||
);
|
||||
let mut thread_builder = thread::Builder::new();
|
||||
|
||||
+75
-49
@@ -1,13 +1,15 @@
|
||||
use crate::common::{hash::PyHash, lock::PyRwLock};
|
||||
use crate::{
|
||||
builtins::{PyInt, PyStrRef, PyType, PyTypeRef},
|
||||
builtins::{PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef},
|
||||
bytecode::ComparisonOperator,
|
||||
convert::{ToPyObject, ToPyResult},
|
||||
function::Either,
|
||||
function::{FromArgs, FuncArgs, OptionalArg, PyComparisonValue},
|
||||
identifier,
|
||||
protocol::{
|
||||
PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PySequence, PySequenceMethods,
|
||||
},
|
||||
vm::Context,
|
||||
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
@@ -173,7 +175,7 @@ macro_rules! then_some_closure {
|
||||
}
|
||||
|
||||
fn length_wrapper(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
let ret = vm.call_special_method(obj, "__len__", ())?;
|
||||
let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?;
|
||||
let len = ret.payload::<PyInt>().ok_or_else(|| {
|
||||
vm.new_type_error(format!(
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
@@ -190,31 +192,37 @@ fn length_wrapper(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
Ok(len as usize)
|
||||
}
|
||||
|
||||
fn as_mapping_wrapper(zelf: &PyObject, _vm: &VirtualMachine) -> PyMappingMethods {
|
||||
fn as_mapping_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyMappingMethods {
|
||||
PyMappingMethods {
|
||||
length: then_some_closure!(zelf.class().has_attr("__len__"), |mapping, vm| {
|
||||
length_wrapper(mapping.obj.to_owned(), vm)
|
||||
}),
|
||||
length: then_some_closure!(
|
||||
zelf.class().has_attr(identifier!(vm, __len__)),
|
||||
|mapping, vm| { length_wrapper(mapping.obj.to_owned(), vm) }
|
||||
),
|
||||
subscript: then_some_closure!(
|
||||
zelf.class().has_attr("__getitem__"),
|
||||
zelf.class().has_attr(identifier!(vm, __getitem__)),
|
||||
|mapping, needle, vm| {
|
||||
vm.call_special_method(mapping.obj.to_owned(), "__getitem__", (needle.to_owned(),))
|
||||
vm.call_special_method(
|
||||
mapping.obj.to_owned(),
|
||||
identifier!(vm, __getitem__),
|
||||
(needle.to_owned(),),
|
||||
)
|
||||
}
|
||||
),
|
||||
ass_subscript: then_some_closure!(
|
||||
zelf.class().has_attr("__setitem__") | zelf.class().has_attr("__delitem__"),
|
||||
zelf.class().has_attr(identifier!(vm, __setitem__))
|
||||
| zelf.class().has_attr(identifier!(vm, __delitem__)),
|
||||
|mapping, needle, value, vm| match value {
|
||||
Some(value) => vm
|
||||
.call_special_method(
|
||||
mapping.obj.to_owned(),
|
||||
"__setitem__",
|
||||
identifier!(vm, __setitem__),
|
||||
(needle.to_owned(), value),
|
||||
)
|
||||
.map(|_| Ok(()))?,
|
||||
None => vm
|
||||
.call_special_method(
|
||||
mapping.obj.to_owned(),
|
||||
"__delitem__",
|
||||
identifier!(vm, __delitem__),
|
||||
(needle.to_owned(),)
|
||||
)
|
||||
.map(|_| Ok(()))?,
|
||||
@@ -223,30 +231,40 @@ fn as_mapping_wrapper(zelf: &PyObject, _vm: &VirtualMachine) -> PyMappingMethods
|
||||
}
|
||||
}
|
||||
|
||||
fn as_sequence_wrapper(zelf: &PyObject, _vm: &VirtualMachine) -> Cow<'static, PySequenceMethods> {
|
||||
if !zelf.class().has_attr("__getitem__") {
|
||||
fn as_sequence_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> Cow<'static, PySequenceMethods> {
|
||||
if !zelf.class().has_attr(identifier!(vm, __getitem__)) {
|
||||
return Cow::Borrowed(PySequenceMethods::not_implemented());
|
||||
}
|
||||
|
||||
Cow::Owned(PySequenceMethods {
|
||||
length: then_some_closure!(zelf.class().has_attr("__len__"), |seq, vm| {
|
||||
length_wrapper(seq.obj.to_owned(), vm)
|
||||
}),
|
||||
length: then_some_closure!(
|
||||
zelf.class().has_attr(identifier!(vm, __len__)),
|
||||
|seq, vm| { length_wrapper(seq.obj.to_owned(), vm) }
|
||||
),
|
||||
item: Some(|seq, i, vm| {
|
||||
vm.call_special_method(seq.obj.to_owned(), "__getitem__", (i.to_pyobject(vm),))
|
||||
vm.call_special_method(
|
||||
seq.obj.to_owned(),
|
||||
identifier!(vm, __getitem__),
|
||||
(i.to_pyobject(vm),),
|
||||
)
|
||||
}),
|
||||
ass_item: then_some_closure!(
|
||||
zelf.class().has_attr("__setitem__") | zelf.class().has_attr("__delitem__"),
|
||||
zelf.class().has_attr(identifier!(vm, __setitem__))
|
||||
| zelf.class().has_attr(identifier!(vm, __delitem__)),
|
||||
|seq, i, value, vm| match value {
|
||||
Some(value) => vm
|
||||
.call_special_method(
|
||||
seq.obj.to_owned(),
|
||||
"__setitem__",
|
||||
identifier!(vm, __setitem__),
|
||||
(i.to_pyobject(vm), value),
|
||||
)
|
||||
.map(|_| Ok(()))?,
|
||||
None => vm
|
||||
.call_special_method(seq.obj.to_owned(), "__delitem__", (i.to_pyobject(vm),))
|
||||
.call_special_method(
|
||||
seq.obj.to_owned(),
|
||||
identifier!(vm, __delitem__),
|
||||
(i.to_pyobject(vm),)
|
||||
)
|
||||
.map(|_| Ok(()))?,
|
||||
}
|
||||
),
|
||||
@@ -255,7 +273,7 @@ fn as_sequence_wrapper(zelf: &PyObject, _vm: &VirtualMachine) -> Cow<'static, Py
|
||||
}
|
||||
|
||||
fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
|
||||
let hash_obj = vm.call_special_method(zelf.to_owned(), "__hash__", ())?;
|
||||
let hash_obj = vm.call_special_method(zelf.to_owned(), identifier!(vm, __hash__), ())?;
|
||||
match hash_obj.payload_if_subclass::<PyInt>(vm) {
|
||||
Some(py_int) => Ok(rustpython_common::hash::hash_bigint(py_int.as_bigint())),
|
||||
None => Err(vm.new_type_error("__hash__ method should return an integer".to_owned())),
|
||||
@@ -263,11 +281,11 @@ fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
|
||||
}
|
||||
|
||||
fn call_wrapper(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
vm.call_special_method(zelf.to_owned(), "__call__", args)
|
||||
vm.call_special_method(zelf.to_owned(), identifier!(vm, __call__), args)
|
||||
}
|
||||
|
||||
fn getattro_wrapper(zelf: &PyObject, name: PyStrRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm.call_special_method(zelf.to_owned(), "__getattribute__", (name,))
|
||||
vm.call_special_method(zelf.to_owned(), identifier!(vm, __getattribute__), (name,))
|
||||
}
|
||||
|
||||
fn setattro_wrapper(
|
||||
@@ -279,10 +297,10 @@ fn setattro_wrapper(
|
||||
let zelf = zelf.to_owned();
|
||||
match value {
|
||||
Some(value) => {
|
||||
vm.call_special_method(zelf, "__setattr__", (name, value))?;
|
||||
vm.call_special_method(zelf, identifier!(vm, __setattr__), (name, value))?;
|
||||
}
|
||||
None => {
|
||||
vm.call_special_method(zelf, "__delattr__", (name,))?;
|
||||
vm.call_special_method(zelf, identifier!(vm, __delattr__), (name,))?;
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
@@ -294,16 +312,23 @@ pub(crate) fn richcompare_wrapper(
|
||||
op: PyComparisonOp,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Either<PyObjectRef, PyComparisonValue>> {
|
||||
vm.call_special_method(zelf.to_owned(), op.method_name(), (other.to_owned(),))
|
||||
.map(Either::A)
|
||||
vm.call_special_method(
|
||||
zelf.to_owned(),
|
||||
op.method_name(&vm.ctx),
|
||||
(other.to_owned(),),
|
||||
)
|
||||
.map(Either::A)
|
||||
}
|
||||
|
||||
fn iter_wrapper(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
vm.call_special_method(zelf, "__iter__", ())
|
||||
vm.call_special_method(zelf, identifier!(vm, __iter__), ())
|
||||
}
|
||||
|
||||
fn iternext_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
PyIterReturn::from_pyresult(vm.call_special_method(zelf.to_owned(), "__next__", ()), vm)
|
||||
PyIterReturn::from_pyresult(
|
||||
vm.call_special_method(zelf.to_owned(), identifier!(vm, __next__), ()),
|
||||
vm,
|
||||
)
|
||||
}
|
||||
|
||||
fn descr_get_wrapper(
|
||||
@@ -312,7 +337,7 @@ fn descr_get_wrapper(
|
||||
cls: Option<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
vm.call_special_method(zelf, "__get__", (obj, cls))
|
||||
vm.call_special_method(zelf, identifier!(vm, __get__), (obj, cls))
|
||||
}
|
||||
|
||||
fn descr_set_wrapper(
|
||||
@@ -322,14 +347,14 @@ fn descr_set_wrapper(
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
match value {
|
||||
Some(val) => vm.call_special_method(zelf, "__set__", (obj, val)),
|
||||
None => vm.call_special_method(zelf, "__delete__", (obj,)),
|
||||
Some(val) => vm.call_special_method(zelf, identifier!(vm, __set__), (obj, val)),
|
||||
None => vm.call_special_method(zelf, identifier!(vm, __delete__), (obj,)),
|
||||
}
|
||||
.map(drop)
|
||||
}
|
||||
|
||||
fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let res = vm.call_special_method(obj, "__init__", args)?;
|
||||
let res = vm.call_special_method(obj, identifier!(vm, __init__), args)?;
|
||||
if !vm.is_none(&res) {
|
||||
return Err(vm.new_type_error("__init__ must return None".to_owned()));
|
||||
}
|
||||
@@ -337,29 +362,27 @@ fn init_wrapper(obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResu
|
||||
}
|
||||
|
||||
fn new_wrapper(cls: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
let new = vm
|
||||
.get_attribute_opt(cls.as_object().to_owned(), "__new__")?
|
||||
.unwrap();
|
||||
let new = cls.get_attr(identifier!(vm, __new__)).unwrap();
|
||||
args.prepend_arg(cls.into());
|
||||
vm.invoke(&new, args)
|
||||
}
|
||||
|
||||
fn del_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
|
||||
vm.call_special_method(zelf.to_owned(), "__del__", ())?;
|
||||
vm.call_special_method(zelf.to_owned(), identifier!(vm, __del__), ())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl PyType {
|
||||
pub(crate) fn update_slot(&self, name: &str, add: bool) {
|
||||
debug_assert!(name.starts_with("__"));
|
||||
debug_assert!(name.ends_with("__"));
|
||||
pub(crate) fn update_slot(&self, name: &'static PyStrInterned, add: bool) {
|
||||
debug_assert!(name.as_str().starts_with("__"));
|
||||
debug_assert!(name.as_str().ends_with("__"));
|
||||
|
||||
macro_rules! update_slot {
|
||||
($name:ident, $func:expr) => {{
|
||||
self.slots.$name.store(if add { Some($func) } else { None });
|
||||
}};
|
||||
}
|
||||
match name {
|
||||
match name.as_str() {
|
||||
"__len__" | "__getitem__" | "__setitem__" | "__delitem__" => {
|
||||
update_slot!(as_mapping, as_mapping_wrapper);
|
||||
update_slot!(as_sequence, as_sequence_wrapper);
|
||||
@@ -623,7 +646,10 @@ pub trait Comparable: PyPayload {
|
||||
if let Some(zelf) = zelf.downcast_ref() {
|
||||
Self::cmp(zelf, other, op, vm).map(Either::B)
|
||||
} else {
|
||||
Err(vm.new_type_error(format!("unexpected payload for {}", op.method_name())))
|
||||
Err(vm.new_type_error(format!(
|
||||
"unexpected payload for {}",
|
||||
op.method_name(&vm.ctx).as_str()
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,14 +767,14 @@ impl PyComparisonOp {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn method_name(self) -> &'static str {
|
||||
pub fn method_name(self, ctx: &Context) -> &'static PyStrInterned {
|
||||
match self {
|
||||
Self::Lt => "__lt__",
|
||||
Self::Le => "__le__",
|
||||
Self::Eq => "__eq__",
|
||||
Self::Ne => "__ne__",
|
||||
Self::Ge => "__ge__",
|
||||
Self::Gt => "__gt__",
|
||||
Self::Lt => identifier!(ctx, __lt__),
|
||||
Self::Le => identifier!(ctx, __le__),
|
||||
Self::Eq => identifier!(ctx, __eq__),
|
||||
Self::Ne => identifier!(ctx, __ne__),
|
||||
Self::Ge => identifier!(ctx, __ge__),
|
||||
Self::Gt => identifier!(ctx, __gt__),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,11 +78,12 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
|
||||
// cast i to a u8 so there's less to store in the getter closure.
|
||||
// Hopefully there's not struct sequences with >=256 elements :P
|
||||
let i = i as u8;
|
||||
class.set_str_attr(
|
||||
name,
|
||||
class.set_attr(
|
||||
ctx.intern_str(name),
|
||||
ctx.new_readonly_getset(name, class.clone(), move |zelf: &PyTuple| {
|
||||
zelf.fast_getitem(i.into())
|
||||
}),
|
||||
})
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+181
-12
@@ -32,15 +32,181 @@ pub struct Context {
|
||||
pub ellipsis: PyRef<PyEllipsis>,
|
||||
pub not_implemented: PyRef<PyNotImplemented>,
|
||||
|
||||
pub(crate) true_str: &'static PyStrInterned,
|
||||
pub(crate) false_str: &'static PyStrInterned,
|
||||
|
||||
pub types: TypeZoo,
|
||||
pub exceptions: exceptions::ExceptionZoo,
|
||||
pub int_cache_pool: Vec<PyIntRef>,
|
||||
// there should only be exact objects of str in here, no non-strs and no subclasses
|
||||
pub(crate) string_pool: StringPool,
|
||||
pub(crate) slot_new_wrapper: PyObjectRef,
|
||||
pub names: ConstName,
|
||||
}
|
||||
|
||||
macro_rules! declare_const_name {
|
||||
($($name:ident,)*) => {
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(non_snake_case)]
|
||||
pub struct ConstName {
|
||||
$(pub $name: &'static PyStrInterned,)*
|
||||
}
|
||||
|
||||
impl ConstName {
|
||||
unsafe fn new(pool: &StringPool, typ: &PyTypeRef) -> Self {
|
||||
Self {
|
||||
$($name: pool.intern(stringify!($name), typ.clone()),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_const_name! {
|
||||
True,
|
||||
False,
|
||||
|
||||
// magic methods
|
||||
__abs__,
|
||||
__abstractmethods__,
|
||||
__add__,
|
||||
__aenter__,
|
||||
__aexit__,
|
||||
__aiter__,
|
||||
__all__,
|
||||
__and__,
|
||||
__anext__,
|
||||
__annotations__,
|
||||
__args__,
|
||||
__await__,
|
||||
__bases__,
|
||||
__bool__,
|
||||
__build_class__,
|
||||
__builtins__,
|
||||
__bytes__,
|
||||
__call__,
|
||||
__ceil__,
|
||||
__cformat__,
|
||||
__class__,
|
||||
__class_getitem__,
|
||||
__complex__,
|
||||
__contains__,
|
||||
__copy__,
|
||||
__deepcopy__,
|
||||
__del__,
|
||||
__delattr__,
|
||||
__delete__,
|
||||
__delitem__,
|
||||
__dict__,
|
||||
__dir__,
|
||||
__div__,
|
||||
__divmod__,
|
||||
__doc__,
|
||||
__enter__,
|
||||
__eq__,
|
||||
__exit__,
|
||||
__file__,
|
||||
__float__,
|
||||
__floor__,
|
||||
__floordiv__,
|
||||
__format__,
|
||||
__fspath__,
|
||||
__ge__,
|
||||
__get__,
|
||||
__getattr__,
|
||||
__getattribute__,
|
||||
__getitem__,
|
||||
__gt__,
|
||||
__hash__,
|
||||
__iadd__,
|
||||
__iand__,
|
||||
__idiv__,
|
||||
__ifloordiv__,
|
||||
__ilshift__,
|
||||
__imatmul__,
|
||||
__imod__,
|
||||
__import__,
|
||||
__imul__,
|
||||
__index__,
|
||||
__init__,
|
||||
__init_subclass__,
|
||||
__instancecheck__,
|
||||
__int__,
|
||||
__invert__,
|
||||
__ior__,
|
||||
__ipow__,
|
||||
__irshift__,
|
||||
__isub__,
|
||||
__iter__,
|
||||
__itruediv__,
|
||||
__ixor__,
|
||||
__le__,
|
||||
__len__,
|
||||
__length_hint__,
|
||||
__lshift__,
|
||||
__lt__,
|
||||
__main__,
|
||||
__matmul__,
|
||||
__missing__,
|
||||
__mod__,
|
||||
__module__,
|
||||
__mro_entries__,
|
||||
__mul__,
|
||||
__name__,
|
||||
__ne__,
|
||||
__neg__,
|
||||
__new__,
|
||||
__next__,
|
||||
__or__,
|
||||
__orig_bases__,
|
||||
__orig_class__,
|
||||
__origin__,
|
||||
__parameters__,
|
||||
__pos__,
|
||||
__pow__,
|
||||
__prepare__,
|
||||
__qualname__,
|
||||
__radd__,
|
||||
__rand__,
|
||||
__rdiv__,
|
||||
__rdivmod__,
|
||||
__reduce__,
|
||||
__reduce_ex__,
|
||||
__repr__,
|
||||
__reversed__,
|
||||
__rfloordiv__,
|
||||
__rlshift__,
|
||||
__rmatmul__,
|
||||
__rmod__,
|
||||
__rmul__,
|
||||
__ror__,
|
||||
__round__,
|
||||
__rpow__,
|
||||
__rrshift__,
|
||||
__rshift__,
|
||||
__rsub__,
|
||||
__rtruediv__,
|
||||
__rxor__,
|
||||
__set__,
|
||||
__set_name__,
|
||||
__setattr__,
|
||||
__setitem__,
|
||||
__str__,
|
||||
__sub__,
|
||||
__subclasscheck__,
|
||||
__truediv__,
|
||||
__trunc__,
|
||||
__xor__,
|
||||
|
||||
// common names
|
||||
_attributes,
|
||||
_fields,
|
||||
decode,
|
||||
encode,
|
||||
keys,
|
||||
items,
|
||||
values,
|
||||
update,
|
||||
copy,
|
||||
flush,
|
||||
close,
|
||||
}
|
||||
|
||||
// Basic objects:
|
||||
@@ -77,16 +243,15 @@ impl Context {
|
||||
PyRef::new_ref(PyFrozenSet::default(), types.frozenset_type.clone(), None);
|
||||
|
||||
let string_pool = StringPool::default();
|
||||
let names = unsafe { ConstName::new(&string_pool, &types.str_type) };
|
||||
|
||||
let new_str = unsafe { string_pool.intern("__new__", types.str_type.clone()) };
|
||||
let slot_new_wrapper = create_object(
|
||||
PyNativeFuncDef::new(PyType::__new__.into_func(), new_str.to_owned()).into_function(),
|
||||
PyNativeFuncDef::new(PyType::__new__.into_func(), names.__new__.to_owned())
|
||||
.into_function(),
|
||||
&types.builtin_function_or_method_type,
|
||||
)
|
||||
.into();
|
||||
|
||||
let true_str = unsafe { string_pool.intern("True", types.str_type.clone()) };
|
||||
let false_str = unsafe { string_pool.intern("False", types.str_type.clone()) };
|
||||
let empty_str = unsafe { string_pool.intern("", types.str_type.clone()) }.to_owned();
|
||||
|
||||
let context = Context {
|
||||
@@ -100,14 +265,12 @@ impl Context {
|
||||
ellipsis,
|
||||
not_implemented,
|
||||
|
||||
true_str,
|
||||
false_str,
|
||||
|
||||
types,
|
||||
exceptions,
|
||||
int_cache_pool,
|
||||
string_pool,
|
||||
slot_new_wrapper,
|
||||
names,
|
||||
};
|
||||
TypeZoo::extend(&context);
|
||||
exceptions::ExceptionZoo::extend(&context);
|
||||
@@ -219,7 +382,7 @@ impl Context {
|
||||
) -> PyTypeRef {
|
||||
let mut attrs = PyAttributes::default();
|
||||
if let Some(module) = module {
|
||||
attrs.insert("__module__".to_string(), self.new_str(module).into());
|
||||
attrs.insert(identifier!(self, __module__), self.new_str(module).into());
|
||||
};
|
||||
PyType::new_ref(
|
||||
name,
|
||||
@@ -243,7 +406,7 @@ impl Context {
|
||||
vec![self.exceptions.exception_type.clone()]
|
||||
};
|
||||
let mut attrs = PyAttributes::default();
|
||||
attrs.insert("__module__".to_owned(), self.new_str(module).into());
|
||||
attrs.insert(identifier!(self, __module__), self.new_str(module).into());
|
||||
|
||||
PyType::new_ref(
|
||||
name,
|
||||
@@ -339,3 +502,9 @@ impl Default for Context {
|
||||
CONTEXT.get_or_init(Self::init).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Context> for Context {
|
||||
fn as_ref(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -82,10 +82,10 @@ impl Interpreter {
|
||||
|
||||
fn flush_std(vm: &VirtualMachine) {
|
||||
if let Ok(stdout) = sys::get_stdout(vm) {
|
||||
let _ = vm.call_method(&stdout, "flush", ());
|
||||
let _ = vm.call_method(&stdout, identifier!(vm, flush).as_str(), ());
|
||||
}
|
||||
if let Ok(stderr) = sys::get_stderr(vm) {
|
||||
let _ = vm.call_method(&stderr, "flush", ());
|
||||
let _ = vm.call_method(&stderr, identifier!(vm, flush).as_str(), ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -3,7 +3,7 @@
|
||||
|
||||
use super::VirtualMachine;
|
||||
use crate::{
|
||||
builtins::{PyBaseObject, PyStrRef},
|
||||
builtins::{PyBaseObject, PyStrInterned, PyStrRef},
|
||||
function::IntoFuncArgs,
|
||||
object::{AsObject, PyObjectRef, PyResult},
|
||||
types::PyTypeFlags,
|
||||
@@ -27,9 +27,10 @@ impl PyMethod {
|
||||
return obj.get_attr(name, vm).map(Self::Attribute);
|
||||
}
|
||||
|
||||
let interned_name = vm.ctx.interned_str(&*name);
|
||||
let mut is_method = false;
|
||||
|
||||
let cls_attr = match cls.get_attr(name.as_str()) {
|
||||
let cls_attr = match interned_name.and_then(|name| cls.get_attr(name)) {
|
||||
Some(descr) => {
|
||||
let descr_cls = descr.class();
|
||||
let descr_get = if descr_cls.slots.flags.has_feature(PyTypeFlags::METHOD_DESCR) {
|
||||
@@ -76,7 +77,7 @@ impl PyMethod {
|
||||
}
|
||||
None => Ok(Self::Attribute(attr)),
|
||||
}
|
||||
} else if let Some(getter) = cls.get_attr("__getattr__") {
|
||||
} else if let Some(getter) = cls.get_attr(identifier!(vm, __getattr__)) {
|
||||
drop(cls);
|
||||
vm.invoke(&getter, (obj, name)).map(Self::Attribute)
|
||||
} else {
|
||||
@@ -92,7 +93,7 @@ impl PyMethod {
|
||||
|
||||
pub(crate) fn get_special(
|
||||
obj: PyObjectRef,
|
||||
name: &str,
|
||||
name: &'static PyStrInterned,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Result<Self, PyObjectRef>> {
|
||||
let obj_cls = obj.class();
|
||||
|
||||
+34
-14
@@ -19,7 +19,7 @@ use crate::{
|
||||
code::PyCode,
|
||||
pystr::IntoPyStrRef,
|
||||
tuple::{PyTuple, PyTupleTyped},
|
||||
PyBaseExceptionRef, PyDictRef, PyInt, PyList, PyModule, PyStrRef, PyTypeRef,
|
||||
PyBaseExceptionRef, PyDictRef, PyInt, PyList, PyModule, PyStrInterned, PyStrRef, PyTypeRef,
|
||||
},
|
||||
bytecode,
|
||||
codecs::CodecsRegistry,
|
||||
@@ -425,13 +425,13 @@ impl VirtualMachine {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let import_func =
|
||||
self.builtins
|
||||
.clone()
|
||||
.get_attr("__import__", self)
|
||||
.map_err(|_| {
|
||||
self.new_import_error("__import__ not found".to_owned(), module.clone())
|
||||
})?;
|
||||
let import_func = self
|
||||
.builtins
|
||||
.clone()
|
||||
.get_attr(identifier!(self, __import__), self)
|
||||
.map_err(|_| {
|
||||
self.new_import_error("__import__ not found".to_owned(), module.clone())
|
||||
})?;
|
||||
|
||||
let (locals, globals) = if let Some(frame) = self.current_frame() {
|
||||
(Some(frame.locals.clone()), Some(frame.globals.clone()))
|
||||
@@ -559,7 +559,7 @@ impl VirtualMachine {
|
||||
pub fn get_method_or_type_error<F>(
|
||||
&self,
|
||||
obj: PyObjectRef,
|
||||
method_name: &str,
|
||||
method_name: &'static PyStrInterned,
|
||||
err_msg: F,
|
||||
) -> PyResult
|
||||
where
|
||||
@@ -573,11 +573,20 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
// TODO: remove + transfer over to get_special_method
|
||||
pub(crate) fn get_method(&self, obj: PyObjectRef, method_name: &str) -> Option<PyResult> {
|
||||
pub(crate) fn get_method(
|
||||
&self,
|
||||
obj: PyObjectRef,
|
||||
method_name: &'static PyStrInterned,
|
||||
) -> Option<PyResult> {
|
||||
let method = obj.get_class_attr(method_name)?;
|
||||
Some(self.call_if_get_descriptor(method, obj))
|
||||
}
|
||||
|
||||
pub(crate) fn get_str_method(&self, obj: PyObjectRef, method_name: &str) -> Option<PyResult> {
|
||||
let method_name = self.ctx.interned_str(method_name)?;
|
||||
self.get_method(obj, method_name)
|
||||
}
|
||||
|
||||
pub fn is_callable(&self, obj: &PyObject) -> bool {
|
||||
obj.class()
|
||||
.mro_find_map(|cls| cls.slots.call.load())
|
||||
@@ -706,7 +715,10 @@ impl VirtualMachine {
|
||||
self.insert_sys_path(self.new_pyobj(path))?;
|
||||
let runpy = self.import("runpy", None, 0)?;
|
||||
let run_module_as_main = runpy.get_attr("_run_module_as_main", self)?;
|
||||
self.invoke(&run_module_as_main, (self.ctx.new_str("__main__"), false))?;
|
||||
self.invoke(
|
||||
&run_module_as_main,
|
||||
(identifier!(self, __main__).to_owned(), false),
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -734,9 +746,11 @@ impl VirtualMachine {
|
||||
.compile(source, crate::compile::Mode::Exec, source_path.clone())
|
||||
.map_err(|err| self.new_syntax_error(&err))?;
|
||||
// trace!("Code object: {:?}", code_obj.borrow());
|
||||
scope
|
||||
.globals
|
||||
.set_item("__file__", self.new_pyobj(source_path), self)?;
|
||||
scope.globals.set_item(
|
||||
identifier!(self, __file__),
|
||||
self.new_pyobj(source_path),
|
||||
self,
|
||||
)?;
|
||||
self.run_code_obj(code_obj, scope)
|
||||
}
|
||||
|
||||
@@ -775,3 +789,9 @@ fn get_importer(path: &str, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
impl AsRef<Context> for VirtualMachine {
|
||||
fn as_ref(&self) -> &Context {
|
||||
&self.ctx
|
||||
}
|
||||
}
|
||||
+16
-12
@@ -1,7 +1,8 @@
|
||||
use super::PyMethod;
|
||||
use crate::{
|
||||
builtins::{PyBaseExceptionRef, PyList, PyStr},
|
||||
builtins::{PyBaseExceptionRef, PyList, PyStr, PyStrInterned},
|
||||
function::{FuncArgs, IntoFuncArgs},
|
||||
identifier,
|
||||
object::{AsObject, PyObject, PyObjectRef, PyPayload, PyResult},
|
||||
vm::VirtualMachine,
|
||||
};
|
||||
@@ -118,21 +119,24 @@ impl VirtualMachine {
|
||||
{
|
||||
flame_guard!(format!("call_method({:?})", method_name));
|
||||
|
||||
PyMethod::get(
|
||||
obj.to_owned(),
|
||||
PyStr::from(method_name).into_ref(self),
|
||||
self,
|
||||
)?
|
||||
.invoke(args, self)
|
||||
let name = self
|
||||
.ctx
|
||||
.interned_str(method_name)
|
||||
.map_or_else(|| PyStr::from(method_name).into_ref(self), |s| s.to_owned());
|
||||
PyMethod::get(obj.to_owned(), name, self)?.invoke(args, self)
|
||||
}
|
||||
|
||||
pub fn dir(&self, obj: Option<PyObjectRef>) -> PyResult<PyList> {
|
||||
let seq = match obj {
|
||||
Some(obj) => self
|
||||
.get_special_method(obj, "__dir__")?
|
||||
.get_special_method(obj, identifier!(self, __dir__))?
|
||||
.map_err(|_obj| self.new_type_error("object does not provide __dir__".to_owned()))?
|
||||
.invoke((), self)?,
|
||||
None => self.call_method(self.current_locals()?.as_object(), "keys", ())?,
|
||||
None => self.call_method(
|
||||
self.current_locals()?.as_object(),
|
||||
identifier!(self, keys).as_str(),
|
||||
(),
|
||||
)?,
|
||||
};
|
||||
let items: Vec<_> = seq.try_to_value(self)?;
|
||||
let lst = PyList::from(items);
|
||||
@@ -144,7 +148,7 @@ impl VirtualMachine {
|
||||
pub(crate) fn get_special_method(
|
||||
&self,
|
||||
obj: PyObjectRef,
|
||||
method: &str,
|
||||
method: &'static PyStrInterned,
|
||||
) -> PyResult<Result<PyMethod, PyObjectRef>> {
|
||||
PyMethod::get_special(obj, method, self)
|
||||
}
|
||||
@@ -154,11 +158,11 @@ impl VirtualMachine {
|
||||
pub fn call_special_method(
|
||||
&self,
|
||||
obj: PyObjectRef,
|
||||
method: &str,
|
||||
method: &'static PyStrInterned,
|
||||
args: impl IntoFuncArgs,
|
||||
) -> PyResult {
|
||||
self.get_special_method(obj, method)?
|
||||
.map_err(|_obj| self.new_attribute_error(method.to_owned()))?
|
||||
.map_err(|_obj| self.new_attribute_error(method.as_str().to_owned()))?
|
||||
.invoke(args, self)
|
||||
}
|
||||
|
||||
|
||||
+223
-113
@@ -1,6 +1,6 @@
|
||||
use super::{PyMethod, VirtualMachine};
|
||||
use crate::{
|
||||
builtins::{PyInt, PyIntRef},
|
||||
builtins::{PyInt, PyIntRef, PyStrInterned},
|
||||
function::PyArithmeticValue,
|
||||
object::{AsObject, PyObject, PyObjectRef, PyResult},
|
||||
protocol::PyIterReturn,
|
||||
@@ -12,15 +12,17 @@ impl VirtualMachine {
|
||||
pub fn to_index_opt(&self, obj: PyObjectRef) -> Option<PyResult<PyIntRef>> {
|
||||
match obj.downcast() {
|
||||
Ok(val) => Some(Ok(val)),
|
||||
Err(obj) => self.get_method(obj, "__index__").map(|index| {
|
||||
// TODO: returning strict subclasses of int in __index__ is deprecated
|
||||
self.invoke(&index?, ())?.downcast().map_err(|bad| {
|
||||
self.new_type_error(format!(
|
||||
"__index__ returned non-int (type {})",
|
||||
bad.class().name()
|
||||
))
|
||||
})
|
||||
}),
|
||||
Err(obj) => self
|
||||
.get_method(obj, identifier!(self, __index__))
|
||||
.map(|index| {
|
||||
// TODO: returning strict subclasses of int in __index__ is deprecated
|
||||
self.invoke(&index?, ())?.downcast().map_err(|bad| {
|
||||
self.new_type_error(format!(
|
||||
"__index__ returned non-int (type {})",
|
||||
bad.class().name()
|
||||
))
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +79,7 @@ impl VirtualMachine {
|
||||
}
|
||||
}
|
||||
}
|
||||
let hint = match self.get_method(iter, "__length_hint__") {
|
||||
let hint = match self.get_method(iter, identifier!(self, __length_hint__)) {
|
||||
Some(hint) => hint?,
|
||||
None => return Ok(None),
|
||||
};
|
||||
@@ -135,7 +137,7 @@ impl VirtualMachine {
|
||||
&self,
|
||||
obj: &PyObject,
|
||||
arg: &PyObject,
|
||||
method: &str,
|
||||
method: &'static PyStrInterned,
|
||||
unsupported: F,
|
||||
) -> PyResult
|
||||
where
|
||||
@@ -166,8 +168,8 @@ impl VirtualMachine {
|
||||
&self,
|
||||
lhs: &PyObject,
|
||||
rhs: &PyObject,
|
||||
default: &str,
|
||||
reflection: &str,
|
||||
default: &'static PyStrInterned,
|
||||
reflection: &'static PyStrInterned,
|
||||
unsupported: fn(&VirtualMachine, &PyObject, &PyObject) -> PyResult,
|
||||
) -> PyResult {
|
||||
if rhs.fast_isinstance(&lhs.class()) {
|
||||
@@ -199,213 +201,321 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
pub fn _sub(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "-"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __sub__),
|
||||
identifier!(self, __rsub__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "-")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _isub(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__isub__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__sub__", "__rsub__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "-="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __isub__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __sub__),
|
||||
identifier!(self, __rsub__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "-=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _add(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "+"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __add__),
|
||||
identifier!(self, __radd__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "+")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _iadd(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__iadd__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__add__", "__radd__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "+="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __iadd__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __add__),
|
||||
identifier!(self, __radd__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "+=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _mul(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "*"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __mul__),
|
||||
identifier!(self, __rmul__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "*")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _imul(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__imul__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__mul__", "__rmul__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "*="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __imul__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __mul__),
|
||||
identifier!(self, __rmul__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "*=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _matmul(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "@"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __matmul__),
|
||||
identifier!(self, __rmatmul__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "@")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _imatmul(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__imatmul__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__matmul__", "__rmatmul__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "@="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __imatmul__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __matmul__),
|
||||
identifier!(self, __rmatmul__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "@=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _truediv(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "/"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __truediv__),
|
||||
identifier!(self, __rtruediv__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "/")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _itruediv(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__itruediv__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__truediv__", "__rtruediv__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "/="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __itruediv__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __truediv__),
|
||||
identifier!(self, __rtruediv__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "/=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _floordiv(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "//"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __floordiv__),
|
||||
identifier!(self, __rfloordiv__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "//")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _ifloordiv(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ifloordiv__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__floordiv__", "__rfloordiv__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "//="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __ifloordiv__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __floordiv__),
|
||||
identifier!(self, __rfloordiv__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "//=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _pow(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "**"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __pow__),
|
||||
identifier!(self, __rpow__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "**")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _ipow(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ipow__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__pow__", "__rpow__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "**="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __ipow__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __pow__),
|
||||
identifier!(self, __rpow__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "**=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _mod(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "%"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __mod__),
|
||||
identifier!(self, __rmod__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "%")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _imod(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__imod__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__mod__", "__rmod__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "%="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __imod__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __mod__),
|
||||
identifier!(self, __rmod__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "%=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _divmod(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__divmod__", "__rdivmod__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "divmod"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __divmod__),
|
||||
identifier!(self, __rdivmod__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "divmod")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _lshift(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "<<"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __lshift__),
|
||||
identifier!(self, __rlshift__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "<<")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _ilshift(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ilshift__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__lshift__", "__rlshift__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "<<="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __ilshift__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __lshift__),
|
||||
identifier!(self, __rlshift__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "<<=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _rshift(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, ">>"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __rshift__),
|
||||
identifier!(self, __rrshift__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, ">>")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _irshift(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__irshift__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__rshift__", "__rrshift__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, ">>="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __irshift__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __rshift__),
|
||||
identifier!(self, __rrshift__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, ">>=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _xor(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "^"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __xor__),
|
||||
identifier!(self, __rxor__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "^")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _ixor(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ixor__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__xor__", "__rxor__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "^="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __ixor__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __xor__),
|
||||
identifier!(self, __rxor__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "^=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _or(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "|"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __or__),
|
||||
identifier!(self, __ror__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "|")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _ior(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__ior__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__or__", "__ror__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "|="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __ior__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __or__),
|
||||
identifier!(self, __ror__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "|=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _and(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "&"))
|
||||
})
|
||||
self.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __and__),
|
||||
identifier!(self, __rand__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "&")),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn _iand(&self, a: &PyObject, b: &PyObject) -> PyResult {
|
||||
self.call_or_unsupported(a, b, "__iand__", |vm, a, b| {
|
||||
vm.call_or_reflection(a, b, "__and__", "__rand__", |vm, a, b| {
|
||||
Err(vm.new_unsupported_binop_error(a, b, "&="))
|
||||
})
|
||||
self.call_or_unsupported(a, b, identifier!(self, __iand__), |vm, a, b| {
|
||||
vm.call_or_reflection(
|
||||
a,
|
||||
b,
|
||||
identifier!(self, __and__),
|
||||
identifier!(self, __rand__),
|
||||
|vm, a, b| Err(vm.new_unsupported_binop_error(a, b, "&=")),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn _abs(&self, a: &PyObject) -> PyResult<PyObjectRef> {
|
||||
self.get_special_method(a.to_owned(), "__abs__")?
|
||||
self.get_special_method(a.to_owned(), identifier!(self, __abs__))?
|
||||
.map_err(|_| self.new_unsupported_unary_error(a, "abs()"))?
|
||||
.invoke((), self)
|
||||
}
|
||||
|
||||
pub fn _pos(&self, a: &PyObject) -> PyResult {
|
||||
self.get_special_method(a.to_owned(), "__pos__")?
|
||||
self.get_special_method(a.to_owned(), identifier!(self, __pos__))?
|
||||
.map_err(|_| self.new_unsupported_unary_error(a, "unary +"))?
|
||||
.invoke((), self)
|
||||
}
|
||||
|
||||
pub fn _neg(&self, a: &PyObject) -> PyResult {
|
||||
self.get_special_method(a.to_owned(), "__neg__")?
|
||||
self.get_special_method(a.to_owned(), identifier!(self, __neg__))?
|
||||
.map_err(|_| self.new_unsupported_unary_error(a, "unary -"))?
|
||||
.invoke((), self)
|
||||
}
|
||||
|
||||
pub fn _invert(&self, a: &PyObject) -> PyResult {
|
||||
self.get_special_method(a.to_owned(), "__invert__")?
|
||||
self.get_special_method(a.to_owned(), identifier!(self, __invert__))?
|
||||
.map_err(|_| self.new_unsupported_unary_error(a, "unary ~"))?
|
||||
.invoke((), self)
|
||||
}
|
||||
@@ -431,7 +541,7 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
pub fn _contains(&self, haystack: PyObjectRef, needle: PyObjectRef) -> PyResult {
|
||||
match PyMethod::get_special(haystack, "__contains__", self)? {
|
||||
match PyMethod::get_special(haystack, identifier!(self, __contains__), self)? {
|
||||
Ok(method) => method.invoke((needle,), self),
|
||||
Err(haystack) => self
|
||||
._membership_iter_search(haystack, needle)
|
||||
|
||||
Reference in new issue
Block a user