diff --git a/ast/asdl_rs.py b/ast/asdl_rs.py index be809a8e1..e03a6deae 100755 --- a/ast/asdl_rs.py +++ b/ast/asdl_rs.py @@ -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) diff --git a/benches/execution.rs b/benches/execution.rs index d286365b8..b95941c2b 100644 --- a/benches/execution.rs +++ b/benches/execution.rs @@ -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(), ) }) diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index 6cd295891..3cdf19a8a 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -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 ); } }); diff --git a/derive/src/pymodule.rs b/derive/src/pymodule.rs index fee1c9c2a..8142c4e50 100644 --- a/derive/src/pymodule.rs +++ b/derive/src/pymodule.rs @@ -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) }; diff --git a/src/shell/helper.rs b/src/shell/helper.rs index 156667c96..b0ead912a 100644 --- a/src/shell/helper.rs +++ b/src/shell/helper.rs @@ -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()))) diff --git a/stdlib/src/math.rs b/stdlib/src/math.rs index 5816f1e25..e118ce77c 100644 --- a/stdlib/src/math.rs +++ b/stdlib/src/math.rs @@ -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)?; diff --git a/stdlib/src/pyexpat.rs b/stdlib/src/pyexpat.rs index 8a9cb33b9..0098a55e7 100644 --- a/stdlib/src/pyexpat.rs +++ b/stdlib/src/pyexpat.rs @@ -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()); }; } diff --git a/stdlib/src/select.rs b/stdlib/src/select.rs index 0a75fd5b4..ee3864d45 100644 --- a/stdlib/src/select.rs +++ b/stdlib/src/select.rs @@ -75,9 +75,11 @@ struct Selectable { impl TryFromObject for Selectable { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { 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 }) diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs index 38b20d31b..d28e7e1f4 100644 --- a/vm/src/builtins/bool.rs +++ b/vm/src/builtins/bool.rs @@ -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() } diff --git a/vm/src/builtins/complex.rs b/vm/src/builtins/complex.rs index f33d4856f..a43cf8976 100644 --- a/vm/src/builtins/complex.rs +++ b/vm/src/builtins/complex.rs @@ -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::(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::() { diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 9c1f0e8ed..1895af874 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -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 { - 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(&self, key: &K, vm: &VirtualMachine) -> bool { @@ -527,7 +527,7 @@ impl Py { key: &K, vm: &VirtualMachine, ) -> PyResult> { - 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 { } /// 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 } diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 5040ab358..2679cf3d4 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -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::(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::() { diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index bf1451c92..de0ae96f9 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -458,7 +458,10 @@ impl Comparable for PyBoundMethod { impl GetAttr for PyBoundMethod { fn getattro(zelf: &Py, 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()); } diff --git a/vm/src/builtins/genericalias.rs b/vm/src/builtins/genericalias.rs index 7ef891b8a..0a675445a 100644 --- a/vm/src/builtins/genericalias.rs +++ b/vm/src/builtins/genericalias.rs @@ -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::().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::().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::().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 = 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 PyResult>( 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, 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) { diff --git a/vm/src/builtins/int.rs b/vm/src/builtins/int.rs index 6710f238a..0d1004f62 100644 --- a/vm/src/builtins/int.rs +++ b/vm/src/builtins/int.rs @@ -952,7 +952,7 @@ pub(crate) fn try_int(obj: &PyObject, vm: &VirtualMachine) -> PyResult { } // 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::() { Some(int_obj) => Ok(int_obj.as_bigint().clone()), @@ -966,7 +966,7 @@ pub(crate) fn try_int(obj: &PyObject, vm: &VirtualMachine) -> PyResult { 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()) diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 0e054571f..a6b94b6cc 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -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> { 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 { match &self.mapping { - MappingProxyInner::Class(class) => { - // let key = PyStrRef::try_from_object(vm, key)?; - let key = key - .payload::() - .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)) } diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 4d1173e1b..ad4fd7e5f 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -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, ()); } diff --git a/vm/src/builtins/str.rs b/vm/src/builtins/str.rs index 0137337c1..f35e6b264 100644 --- a/vm/src/builtins/str.rs +++ b/vm/src/builtins/str.rs @@ -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 { - 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()) })?; diff --git a/vm/src/builtins/super.rs b/vm/src/builtins/super.rs index fb566f477..359035317 100644 --- a/vm/src/builtins/super.rs +++ b/vm/src/builtins/super.rs @@ -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) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 3395a05e3..777a9f593 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -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; /// 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; +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>(&self, attr_name: &str, value: V) { - self._set_str_attr(attr_name, value.into()) + pub fn set_str_attr>( + &self, + attr_name: &str, + value: V, + ctx: impl AsRef, + ) { + 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 { + pub fn get_attr(&self, attr_name: &'static PyStrInterned) -> Option { 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 { + pub fn get_direct_attr(&self, attr_name: &'static PyStrInterned) -> Option { self.attributes.read().get(attr_name).cloned() } - pub fn get_super_attr(&self, attr_name: &str) -> Option { + pub fn get_super_attr(&self, attr_name: &'static PyStrInterned) -> Option { 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, vm: &VirtualMachine) -> PyList { + fn dir(zelf: PyRef, _vm: &VirtualMachine) -> PyList { let attributes: Vec = 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::().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::>>()?; 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, name_str: PyStrRef, vm: &VirtualMachine) -> PyResult { - let name = name_str.as_str(); + #[cold] + fn attribute_error( + zelf: &Py, + 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, 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().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::().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::().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 = 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 { diff --git a/vm/src/bytesinner.rs b/vm/src/bytesinner.rs index 8e9613747..7f3da6373 100644 --- a/vm/src/bytesinner.rs +++ b/vm/src/bytesinner.rs @@ -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?, ())?; diff --git a/vm/src/cformat.rs b/vm/src/cformat.rs index fd2486fed..8e8d47e53 100644 --- a/vm/src/cformat.rs +++ b/vm/src/cformat.rs @@ -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::() { 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::() { 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); diff --git a/vm/src/class.rs b/vm/src/class.rs index c6e057929..fc8ed9d13 100644 --- a/vm/src/class.rs +++ b/vm/src/class.rs @@ -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); } } diff --git a/vm/src/dictdatatype.rs b/vm/src/dictdatatype.rs index 487207e88..5e173f0bd 100644 --- a/vm/src/dictdatatype.rs +++ b/vm/src/dictdatatype.rs @@ -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 { } } +impl DictKey for PyStrInterned { + type Owned = PyRefExact; + #[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 { + (**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 { + (**self).key_eq(vm, other_key) + } + #[inline] + fn key_as_isize(&self, vm: &VirtualMachine) -> PyResult { + (**self).key_as_isize(vm) + } +} + impl DictKey for PyExact { type Owned = PyRefExact; - #[inline(always)] + #[inline] fn _to_owned(&self, _vm: &VirtualMachine) -> Self::Owned { self.to_owned() } @@ -761,7 +786,7 @@ impl DictKey for PyExact { fn key_hash(&self, vm: &VirtualMachine) -> PyResult { (**self).key_hash(vm) } - #[inline] + #[inline(always)] fn key_is(&self, other: &PyObject) -> bool { (**self).key_is(other) } diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 91bf73f16..95bed5475 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -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); diff --git a/vm/src/format.rs b/vm/src/format.rs index 3ce39d724..7c945e2d7 100644 --- a/vm/src/format.rs +++ b/vm/src/format.rs @@ -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 {}", diff --git a/vm/src/frame.rs b/vm/src/frame.rs index a0d49b41b..ee9547547 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -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::(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::() { 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::() { 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::().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 bool> = - if let Ok(all) = dict.get_item("__all__", vm) { + if let Ok(all) = dict.get_item(identifier!(vm, __all__), vm) { let all: Vec = all.try_to_value(vm)?; let all: Vec = 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) diff --git a/vm/src/function/protocol.rs b/vm/src/function/protocol.rs index 9d5b54a5a..de18517ce 100644 --- a/vm/src/function/protocol.rs +++ b/vm/src/function/protocol.rs @@ -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()))); } } diff --git a/vm/src/macros.rs b/vm/src/macros.rs index eff891749..013926aa8 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -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. diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index 378aa1aa6..1fedb708c 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -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() diff --git a/vm/src/object/ext.rs b/vm/src/object/ext.rs index 47b7b91d6..0a38913ff 100644 --- a/vm/src/object/ext.rs +++ b/vm/src/object/ext.rs @@ -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 { + fn get_class_attr(&self, attr_name: &'static PyStrInterned) -> Option { self.class().get_attr(attr_name) } diff --git a/vm/src/protocol/mapping.rs b/vm/src/protocol/mapping.rs index f8ec7437d..b90dddc35 100644 --- a/vm/src/protocol/mapping.rs +++ b/vm/src/protocol/mapping.rs @@ -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::(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::(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::(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() )) })?; diff --git a/vm/src/protocol/object.rs b/vm/src/protocol/object.rs index 5023eca11..bc3e04ced 100644 --- a/vm/src/protocol/object.rs +++ b/vm/src/protocol/object.rs @@ -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> { 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 { 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 { @@ -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,)); } diff --git a/vm/src/stdlib/ast/gen.rs b/vm/src/stdlib/ast/gen.rs index e094ee738..2f50dee19 100644 --- a/vm/src/stdlib/ast/gen.rs +++ b/vm/src/stdlib/ast/gen.rs @@ -15,14 +15,15 @@ struct NodeModule; impl NodeModule { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("type_ignores")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Interactive", base = "NodeKindMod")] @@ -31,11 +32,12 @@ struct NodeInteractive; impl NodeInteractive { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("body")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("body")).into()]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Expression", base = "NodeKindMod")] @@ -44,11 +46,12 @@ struct NodeExpression; impl NodeExpression { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("body")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("body")).into()]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "FunctionType", base = "NodeKindMod")] @@ -57,14 +60,15 @@ struct NodeFunctionType; impl NodeFunctionType { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("argtypes")).into(), ctx.new_str(ascii!("returns")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "stmt", base = "AstNode")] @@ -77,8 +81,8 @@ struct NodeFunctionDef; impl NodeFunctionDef { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("args")).into(), @@ -86,16 +90,18 @@ impl NodeFunctionDef { ctx.new_str(ascii!("decorator_list")).into(), ctx.new_str(ascii!("returns")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -105,8 +111,8 @@ struct NodeAsyncFunctionDef; impl NodeAsyncFunctionDef { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("args")).into(), @@ -114,16 +120,18 @@ impl NodeAsyncFunctionDef { ctx.new_str(ascii!("decorator_list")).into(), ctx.new_str(ascii!("returns")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -133,24 +141,26 @@ struct NodeClassDef; impl NodeClassDef { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("bases")).into(), ctx.new_str(ascii!("keywords")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("decorator_list")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -160,18 +170,20 @@ struct NodeReturn; impl NodeReturn { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -181,18 +193,20 @@ struct NodeDelete; impl NodeDelete { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("targets")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("targets")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -202,22 +216,24 @@ struct NodeAssign; impl NodeAssign { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("targets")).into(), ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -227,22 +243,24 @@ struct NodeAugAssign; impl NodeAugAssign { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("op")).into(), ctx.new_str(ascii!("value")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -252,23 +270,25 @@ struct NodeAnnAssign; impl NodeAnnAssign { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("annotation")).into(), ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("simple")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -278,24 +298,26 @@ struct NodeFor; impl NodeFor { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("iter")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -305,24 +327,26 @@ struct NodeAsyncFor; impl NodeAsyncFor { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("iter")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -332,22 +356,24 @@ struct NodeWhile; impl NodeWhile { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("test")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -357,22 +383,24 @@ struct NodeIf; impl NodeIf { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("test")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -382,22 +410,24 @@ struct NodeWith; impl NodeWith { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("items")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -407,22 +437,24 @@ struct NodeAsyncWith; impl NodeAsyncWith { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("items")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -432,21 +464,23 @@ struct NodeRaise; impl NodeRaise { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("exc")).into(), ctx.new_str(ascii!("cause")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -456,23 +490,25 @@ struct NodeTry; impl NodeTry { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("handlers")).into(), ctx.new_str(ascii!("orelse")).into(), ctx.new_str(ascii!("finalbody")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -482,21 +518,23 @@ struct NodeAssert; impl NodeAssert { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("test")).into(), ctx.new_str(ascii!("msg")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -506,18 +544,20 @@ struct NodeImport; impl NodeImport { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -527,22 +567,24 @@ struct NodeImportFrom; impl NodeImportFrom { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("module")).into(), ctx.new_str(ascii!("names")).into(), ctx.new_str(ascii!("level")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -552,18 +594,20 @@ struct NodeGlobal; impl NodeGlobal { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -573,18 +617,20 @@ struct NodeNonlocal; impl NodeNonlocal { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("names")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -594,18 +640,20 @@ struct NodeExpr; impl NodeExpr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -615,15 +663,16 @@ struct NodePass; impl NodePass { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr( - "_attributes", + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -633,15 +682,16 @@ struct NodeBreak; impl NodeBreak { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr( - "_attributes", + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -651,15 +701,16 @@ struct NodeContinue; impl NodeContinue { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr( - "_attributes", + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -673,21 +724,23 @@ struct NodeBoolOp; impl NodeBoolOp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("op")).into(), ctx.new_str(ascii!("values")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -697,21 +750,23 @@ struct NodeNamedExpr; impl NodeNamedExpr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("value")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -721,22 +776,24 @@ struct NodeBinOp; impl NodeBinOp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("left")).into(), ctx.new_str(ascii!("op")).into(), ctx.new_str(ascii!("right")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -746,21 +803,23 @@ struct NodeUnaryOp; impl NodeUnaryOp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("op")).into(), ctx.new_str(ascii!("operand")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -770,21 +829,23 @@ struct NodeLambda; impl NodeLambda { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("args")).into(), ctx.new_str(ascii!("body")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -794,22 +855,24 @@ struct NodeIfExp; impl NodeIfExp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("test")).into(), ctx.new_str(ascii!("body")).into(), ctx.new_str(ascii!("orelse")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -819,21 +882,23 @@ struct NodeDict; impl NodeDict { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("keys")).into(), ctx.new_str(ascii!("values")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -843,18 +908,20 @@ struct NodeSet; impl NodeSet { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("elts")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("elts")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -864,21 +931,23 @@ struct NodeListComp; impl NodeListComp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elt")).into(), ctx.new_str(ascii!("generators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -888,21 +957,23 @@ struct NodeSetComp; impl NodeSetComp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elt")).into(), ctx.new_str(ascii!("generators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -912,22 +983,24 @@ struct NodeDictComp; impl NodeDictComp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("key")).into(), ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("generators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -937,21 +1010,23 @@ struct NodeGeneratorExp; impl NodeGeneratorExp { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elt")).into(), ctx.new_str(ascii!("generators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -961,18 +1036,20 @@ struct NodeAwait; impl NodeAwait { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -982,18 +1059,20 @@ struct NodeYield; impl NodeYield { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1003,18 +1082,20 @@ struct NodeYieldFrom; impl NodeYieldFrom { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1024,22 +1105,24 @@ struct NodeCompare; impl NodeCompare { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("left")).into(), ctx.new_str(ascii!("ops")).into(), ctx.new_str(ascii!("comparators")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1049,22 +1132,24 @@ struct NodeCall; impl NodeCall { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("func")).into(), ctx.new_str(ascii!("args")).into(), ctx.new_str(ascii!("keywords")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1074,22 +1159,24 @@ struct NodeFormattedValue; impl NodeFormattedValue { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("conversion")).into(), ctx.new_str(ascii!("format_spec")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1099,18 +1186,20 @@ struct NodeJoinedStr; impl NodeJoinedStr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", - ctx.new_list(vec![ctx.new_str(ascii!("values")).into()]), + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("values")).into()]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1120,21 +1209,23 @@ struct NodeConstant; impl NodeConstant { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("kind")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1144,22 +1235,24 @@ struct NodeAttribute; impl NodeAttribute { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("attr")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1169,22 +1262,24 @@ struct NodeSubscript; impl NodeSubscript { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("slice")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1194,21 +1289,23 @@ struct NodeStarred; impl NodeStarred { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("value")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1218,21 +1315,23 @@ struct NodeName; impl NodeName { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("id")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1242,21 +1341,23 @@ struct NodeList; impl NodeList { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elts")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1266,21 +1367,23 @@ struct NodeTuple; impl NodeTuple { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("elts")).into(), ctx.new_str(ascii!("ctx")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1290,22 +1393,24 @@ struct NodeSlice; impl NodeSlice { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("lower")).into(), ctx.new_str(ascii!("upper")).into(), ctx.new_str(ascii!("step")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1319,8 +1424,8 @@ struct NodeLoad; impl NodeLoad { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Store", base = "NodeKindExprContext")] @@ -1329,8 +1434,8 @@ struct NodeStore; impl NodeStore { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Del", base = "NodeKindExprContext")] @@ -1339,8 +1444,8 @@ struct NodeDel; impl NodeDel { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "boolop", base = "AstNode")] @@ -1353,8 +1458,8 @@ struct NodeAnd; impl NodeAnd { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Or", base = "NodeKindBoolop")] @@ -1363,8 +1468,8 @@ struct NodeOr; impl NodeOr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "operator", base = "AstNode")] @@ -1377,8 +1482,8 @@ struct NodeAdd; impl NodeAdd { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Sub", base = "NodeKindOperator")] @@ -1387,8 +1492,8 @@ struct NodeSub; impl NodeSub { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Mult", base = "NodeKindOperator")] @@ -1397,8 +1502,8 @@ struct NodeMult; impl NodeMult { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "MatMult", base = "NodeKindOperator")] @@ -1407,8 +1512,8 @@ struct NodeMatMult; impl NodeMatMult { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Div", base = "NodeKindOperator")] @@ -1417,8 +1522,8 @@ struct NodeDiv; impl NodeDiv { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Mod", base = "NodeKindOperator")] @@ -1427,8 +1532,8 @@ struct NodeMod; impl NodeMod { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Pow", base = "NodeKindOperator")] @@ -1437,8 +1542,8 @@ struct NodePow; impl NodePow { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "LShift", base = "NodeKindOperator")] @@ -1447,8 +1552,8 @@ struct NodeLShift; impl NodeLShift { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "RShift", base = "NodeKindOperator")] @@ -1457,8 +1562,8 @@ struct NodeRShift; impl NodeRShift { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "BitOr", base = "NodeKindOperator")] @@ -1467,8 +1572,8 @@ struct NodeBitOr; impl NodeBitOr { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "BitXor", base = "NodeKindOperator")] @@ -1477,8 +1582,8 @@ struct NodeBitXor; impl NodeBitXor { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "BitAnd", base = "NodeKindOperator")] @@ -1487,8 +1592,8 @@ struct NodeBitAnd; impl NodeBitAnd { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "FloorDiv", base = "NodeKindOperator")] @@ -1497,8 +1602,8 @@ struct NodeFloorDiv; impl NodeFloorDiv { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "unaryop", base = "AstNode")] @@ -1511,8 +1616,8 @@ struct NodeInvert; impl NodeInvert { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Not", base = "NodeKindUnaryop")] @@ -1521,8 +1626,8 @@ struct NodeNot; impl NodeNot { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "UAdd", base = "NodeKindUnaryop")] @@ -1531,8 +1636,8 @@ struct NodeUAdd; impl NodeUAdd { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "USub", base = "NodeKindUnaryop")] @@ -1541,8 +1646,8 @@ struct NodeUSub; impl NodeUSub { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "cmpop", base = "AstNode")] @@ -1555,8 +1660,8 @@ struct NodeEq; impl NodeEq { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "NotEq", base = "NodeKindCmpop")] @@ -1565,8 +1670,8 @@ struct NodeNotEq; impl NodeNotEq { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Lt", base = "NodeKindCmpop")] @@ -1575,8 +1680,8 @@ struct NodeLt; impl NodeLt { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "LtE", base = "NodeKindCmpop")] @@ -1585,8 +1690,8 @@ struct NodeLtE; impl NodeLtE { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Gt", base = "NodeKindCmpop")] @@ -1595,8 +1700,8 @@ struct NodeGt; impl NodeGt { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "GtE", base = "NodeKindCmpop")] @@ -1605,8 +1710,8 @@ struct NodeGtE; impl NodeGtE { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "Is", base = "NodeKindCmpop")] @@ -1615,8 +1720,8 @@ struct NodeIs; impl NodeIs { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "IsNot", base = "NodeKindCmpop")] @@ -1625,8 +1730,8 @@ struct NodeIsNot; impl NodeIsNot { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "In", base = "NodeKindCmpop")] @@ -1635,8 +1740,8 @@ struct NodeIn; impl NodeIn { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "NotIn", base = "NodeKindCmpop")] @@ -1645,8 +1750,8 @@ struct NodeNotIn; impl NodeNotIn { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr("_fields", ctx.new_list(vec![])); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _fields), ctx.new_list(vec![]).into()); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "comprehension", base = "AstNode")] @@ -1655,16 +1760,17 @@ struct Nodecomprehension; impl Nodecomprehension { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("target")).into(), ctx.new_str(ascii!("iter")).into(), ctx.new_str(ascii!("ifs")).into(), ctx.new_str(ascii!("is_async")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "excepthandler", base = "AstNode")] @@ -1681,22 +1787,24 @@ struct NodeExceptHandler; impl NodeExceptHandler { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("type")).into(), ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("body")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1706,8 +1814,8 @@ struct Nodearguments; impl Nodearguments { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("posonlyargs")).into(), ctx.new_str(ascii!("args")).into(), @@ -1716,9 +1824,10 @@ impl Nodearguments { ctx.new_str(ascii!("kw_defaults")).into(), ctx.new_str(ascii!("kwarg")).into(), ctx.new_str(ascii!("defaults")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "arg", base = "AstNode")] @@ -1727,22 +1836,24 @@ struct Nodearg; impl Nodearg { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("arg")).into(), ctx.new_str(ascii!("annotation")).into(), ctx.new_str(ascii!("type_comment")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1752,21 +1863,23 @@ struct Nodekeyword; impl Nodekeyword { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("arg")).into(), ctx.new_str(ascii!("value")).into(), - ]), + ]) + .into(), ); - class.set_str_attr( - "_attributes", + class.set_attr( + identifier!(ctx, _attributes), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("col_offset")).into(), ctx.new_str(ascii!("end_lineno")).into(), ctx.new_str(ascii!("end_col_offset")).into(), - ]), + ]) + .into(), ); } } @@ -1776,14 +1889,15 @@ struct Nodealias; impl Nodealias { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("name")).into(), ctx.new_str(ascii!("asname")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "withitem", base = "AstNode")] @@ -1792,14 +1906,15 @@ struct Nodewithitem; impl Nodewithitem { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("context_expr")).into(), ctx.new_str(ascii!("optional_vars")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } #[pyclass(module = "_ast", name = "type_ignore", base = "AstNode")] @@ -1812,14 +1927,15 @@ struct NodeTypeIgnore; impl NodeTypeIgnore { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &PyTypeRef) { - class.set_str_attr( - "_fields", + class.set_attr( + identifier!(ctx, _fields), ctx.new_list(vec![ ctx.new_str(ascii!("lineno")).into(), ctx.new_str(ascii!("tag")).into(), - ]), + ]) + .into(), ); - class.set_str_attr("_attributes", ctx.new_list(vec![])); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index e1e785c73..e32867ac8 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -218,9 +218,9 @@ mod builtins { fn make_scope(self, vm: &VirtualMachine) -> PyResult { 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::() { - 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 { - 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 = >::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( diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 6233c27d6..2bcc314d3 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -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, ())?; diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index bd4de3ce0..c603ad8be 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -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 = 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)?, diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index ac72893c3..d439006aa 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -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())) ); diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index a0ee7c509..e96f3cfe8 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -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!( diff --git a/vm/src/stdlib/sre.rs b/vm/src/stdlib/sre.rs index 9c0abd1c6..7ffbb35dc 100644 --- a/vm/src/stdlib/sre.rs +++ b/vm/src/stdlib/sre.rs @@ -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) diff --git a/vm/src/stdlib/thread.rs b/vm/src/stdlib/thread.rs index 8e8fbb612..ef00af875 100644 --- a/vm/src/stdlib/thread.rs +++ b/vm/src/stdlib/thread.rs @@ -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::(), ); let mut thread_builder = thread::Builder::new(); diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 449b0fc52..b626327e9 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -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 { - let ret = vm.call_special_method(obj, "__len__", ())?; + let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?; let len = ret.payload::().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 { 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 { - 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::(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 { } 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> { - 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::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, 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__), } } diff --git a/vm/src/types/structseq.rs b/vm/src/types/structseq.rs index 01ab762eb..d3b98a663 100644 --- a/vm/src/types/structseq.rs +++ b/vm/src/types/structseq.rs @@ -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(), ); } } diff --git a/vm/src/vm/context.rs b/vm/src/vm/context.rs index 708d621c3..6568578b0 100644 --- a/vm/src/vm/context.rs +++ b/vm/src/vm/context.rs @@ -32,15 +32,181 @@ pub struct Context { pub ellipsis: PyRef, pub not_implemented: PyRef, - pub(crate) true_str: &'static PyStrInterned, - pub(crate) false_str: &'static PyStrInterned, - pub types: TypeZoo, pub exceptions: exceptions::ExceptionZoo, pub int_cache_pool: Vec, // 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 for Context { + fn as_ref(&self) -> &Self { + self + } +} diff --git a/vm/src/vm/interpreter.rs b/vm/src/vm/interpreter.rs index d1955abc2..4247a25c1 100644 --- a/vm/src/vm/interpreter.rs +++ b/vm/src/vm/interpreter.rs @@ -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(), ()); } } diff --git a/vm/src/vm/method.rs b/vm/src/vm/method.rs index de8e28747..529b0bcee 100644 --- a/vm/src/vm/method.rs +++ b/vm/src/vm/method.rs @@ -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> { let obj_cls = obj.class(); diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index 87e4ac22d..450fffa9c 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -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( &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 { + pub(crate) fn get_method( + &self, + obj: PyObjectRef, + method_name: &'static PyStrInterned, + ) -> Option { 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 { + 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 None }) } + +impl AsRef for VirtualMachine { + fn as_ref(&self) -> &Context { + &self.ctx + } +} diff --git a/vm/src/vm/vm_object.rs b/vm/src/vm/vm_object.rs index 4c98a4c08..1aba5e4ad 100644 --- a/vm/src/vm/vm_object.rs +++ b/vm/src/vm/vm_object.rs @@ -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) -> PyResult { 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> { 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) } diff --git a/vm/src/vm/vm_ops.rs b/vm/src/vm/vm_ops.rs index dc10479a2..b509561ba 100644 --- a/vm/src/vm/vm_ops.rs +++ b/vm/src/vm/vm_ops.rs @@ -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> { 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 { - 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)