Skip to content

Commit f093aa4

Browse files
authored
Merge branch 'master' into pyvaluepayload
2 parents 2af998e + 529da3f commit f093aa4

File tree

14 files changed

+260
-130
lines changed

14 files changed

+260
-130
lines changed

tests/snippets/mro.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ class C(A, B):
1818
pass
1919

2020
assert (C, A, B, X, Y, object) == C.__mro__
21+
22+
assert type.__mro__ == (type, object)

tests/snippets/property.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,18 @@ def foo(self):
3030

3131
with assertRaises(TypeError):
3232
property.__new__(object)
33+
34+
35+
p1 = property("a", "b", "c")
36+
37+
assert p1.fget == "a"
38+
assert p1.fset == "b"
39+
assert p1.fdel == "c"
40+
41+
assert p1.getter(1).fget == 1
42+
assert p1.setter(2).fset == 2
43+
assert p1.deleter(3).fdel == 3
44+
45+
assert p1.getter(None).fget == "a"
46+
assert p1.setter(None).fset == "b"
47+
assert p1.deleter(None).fdel == "c"

tests/snippets/subclass_str.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from testutils import assertRaises
2+
3+
x = "An interesting piece of text"
4+
assert x is str(x)
5+
6+
class Stringy(str):
7+
def __new__(cls, value=""):
8+
return str.__new__(cls, value)
9+
10+
def __init__(self, value):
11+
self.x = "substr"
12+
13+
y = Stringy(1)
14+
assert type(y) is Stringy, "Type of Stringy should be stringy"
15+
assert type(str(y)) is str, "Str of a str-subtype should be a str."
16+
17+
assert y + " other" == "1 other"
18+
assert y.x == "substr"
19+
20+
## Base strings currently get an attribute dict, but shouldn't.
21+
# with assertRaises(AttributeError):
22+
# "hello".x = 5

vm/src/obj/objint.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@ pub struct PyInt {
2424
pub type PyIntRef = PyRef<PyInt>;
2525

2626
impl PyInt {
27-
pub fn new<T: ToBigInt>(i: T) -> Self {
28-
PyInt {
29-
// TODO: this .clone()s a BigInt, which is not what we want.
30-
value: i.to_bigint().unwrap(),
31-
}
27+
pub fn new<T: Into<BigInt>>(i: T) -> Self {
28+
PyInt { value: i.into() }
29+
}
30+
}
31+
32+
impl IntoPyObject for BigInt {
33+
fn into_pyobject(self, ctx: &PyContext) -> PyResult {
34+
Ok(ctx.new_int(self))
3235
}
3336
}
3437

@@ -315,8 +318,8 @@ impl PyIntRef {
315318
}
316319
}
317320

318-
fn neg(self, vm: &mut VirtualMachine) -> PyObjectRef {
319-
vm.ctx.new_int(-(&self.value))
321+
fn neg(self, _vm: &mut VirtualMachine) -> BigInt {
322+
-(&self.value)
320323
}
321324

322325
fn hash(self, _vm: &mut VirtualMachine) -> u64 {
@@ -325,8 +328,8 @@ impl PyIntRef {
325328
hasher.finish()
326329
}
327330

328-
fn abs(self, vm: &mut VirtualMachine) -> PyObjectRef {
329-
vm.ctx.new_int(self.value.abs())
331+
fn abs(self, _vm: &mut VirtualMachine) -> BigInt {
332+
self.value.abs()
330333
}
331334

332335
fn round(self, _precision: OptionalArg<PyObjectRef>, _vm: &mut VirtualMachine) -> Self {
@@ -337,8 +340,8 @@ impl PyIntRef {
337340
self.value.to_f64().unwrap()
338341
}
339342

340-
fn invert(self, vm: &mut VirtualMachine) -> PyObjectRef {
341-
vm.ctx.new_int(!(&self.value))
343+
fn invert(self, _vm: &mut VirtualMachine) -> BigInt {
344+
!(&self.value)
342345
}
343346

344347
fn repr(self, _vm: &mut VirtualMachine) -> String {

vm/src/obj/objnone.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ impl IntoPyObject for () {
2121
}
2222
}
2323

24+
impl<T: IntoPyObject> IntoPyObject for Option<T> {
25+
fn into_pyobject(self, ctx: &PyContext) -> PyResult {
26+
match self {
27+
Some(x) => x.into_pyobject(ctx),
28+
None => Ok(ctx.none()),
29+
}
30+
}
31+
}
32+
2433
impl PyNoneRef {
2534
fn repr(self, _vm: &mut VirtualMachine) -> PyResult<String> {
2635
Ok("None".to_string())

vm/src/obj/objproperty.rs

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
33
*/
44

5-
use std::marker::PhantomData;
6-
75
use crate::obj::objstr::PyStringRef;
86
use crate::obj::objtype::PyClassRef;
97
use crate::pyobject::{
@@ -67,6 +65,8 @@ impl PyPropertyRef {
6765
)
6866
}
6967

68+
// Descriptor methods
69+
7070
fn get(self, obj: PyObjectRef, _owner: PyClassRef, vm: &mut VirtualMachine) -> PyResult {
7171
if let Some(getter) = self.getter.as_ref() {
7272
vm.invoke(getter.clone(), obj)
@@ -90,42 +90,90 @@ impl PyPropertyRef {
9090
Err(vm.new_attribute_error("can't delete attribute".to_string()))
9191
}
9292
}
93+
94+
// Access functions
95+
96+
fn fget(self, _vm: &mut VirtualMachine) -> Option<PyObjectRef> {
97+
self.getter.clone()
98+
}
99+
100+
fn fset(self, _vm: &mut VirtualMachine) -> Option<PyObjectRef> {
101+
self.setter.clone()
102+
}
103+
104+
fn fdel(self, _vm: &mut VirtualMachine) -> Option<PyObjectRef> {
105+
self.deleter.clone()
106+
}
107+
108+
// Python builder functions
109+
110+
fn getter(self, getter: Option<PyObjectRef>, vm: &mut VirtualMachine) -> PyResult<Self> {
111+
Self::new_with_type(
112+
vm,
113+
PyProperty {
114+
getter: getter.or_else(|| self.getter.clone()),
115+
setter: self.setter.clone(),
116+
deleter: self.deleter.clone(),
117+
},
118+
self.typ(),
119+
)
120+
}
121+
122+
fn setter(self, setter: Option<PyObjectRef>, vm: &mut VirtualMachine) -> PyResult<Self> {
123+
Self::new_with_type(
124+
vm,
125+
PyProperty {
126+
getter: self.getter.clone(),
127+
setter: setter.or_else(|| self.setter.clone()),
128+
deleter: self.deleter.clone(),
129+
},
130+
self.typ(),
131+
)
132+
}
133+
134+
fn deleter(self, deleter: Option<PyObjectRef>, vm: &mut VirtualMachine) -> PyResult<Self> {
135+
Self::new_with_type(
136+
vm,
137+
PyProperty {
138+
getter: self.getter.clone(),
139+
setter: self.setter.clone(),
140+
deleter: deleter.or_else(|| self.deleter.clone()),
141+
},
142+
self.typ(),
143+
)
144+
}
93145
}
94146

95-
pub struct PropertyBuilder<'a, T> {
147+
pub struct PropertyBuilder<'a> {
96148
ctx: &'a PyContext,
97149
getter: Option<PyObjectRef>,
98150
setter: Option<PyObjectRef>,
99-
_return: PhantomData<T>,
100151
}
101152

102-
impl<'a, T> PropertyBuilder<'a, T> {
153+
impl<'a> PropertyBuilder<'a> {
103154
pub fn new(ctx: &'a PyContext) -> Self {
104155
Self {
105156
ctx,
106157
getter: None,
107158
setter: None,
108-
_return: PhantomData,
109159
}
110160
}
111161

112-
pub fn add_getter<I, F: IntoPyNativeFunc<I, T>>(self, func: F) -> Self {
162+
pub fn add_getter<I, V, F: IntoPyNativeFunc<I, V>>(self, func: F) -> Self {
113163
let func = self.ctx.new_rustfunc(func);
114164
Self {
115165
ctx: self.ctx,
116166
getter: Some(func),
117167
setter: self.setter,
118-
_return: PhantomData,
119168
}
120169
}
121170

122-
pub fn add_setter<I, F: IntoPyNativeFunc<(I, T), PyResult>>(self, func: F) -> Self {
171+
pub fn add_setter<I, V, F: IntoPyNativeFunc<(I, V), PyResult>>(self, func: F) -> Self {
123172
let func = self.ctx.new_rustfunc(func);
124173
Self {
125174
ctx: self.ctx,
126175
getter: self.getter,
127176
setter: Some(func),
128-
_return: PhantomData,
129177
}
130178
}
131179

@@ -190,5 +238,13 @@ pub fn init(context: &PyContext) {
190238
"__get__" => context.new_rustfunc(PyPropertyRef::get),
191239
"__set__" => context.new_rustfunc(PyPropertyRef::set),
192240
"__delete__" => context.new_rustfunc(PyPropertyRef::delete),
241+
242+
"fget" => context.new_property(PyPropertyRef::fget),
243+
"fset" => context.new_property(PyPropertyRef::fset),
244+
"fdel" => context.new_property(PyPropertyRef::fdel),
245+
246+
"getter" => context.new_rustfunc(PyPropertyRef::getter),
247+
"setter" => context.new_rustfunc(PyPropertyRef::setter),
248+
"deleter" => context.new_rustfunc(PyPropertyRef::deleter),
193249
});
194250
}

vm/src/obj/objstr.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ use unicode_segmentation::UnicodeSegmentation;
77

88
use crate::format::{FormatParseError, FormatPart, FormatString};
99
use crate::pyobject::{
10-
IntoPyObject, OptionalArg, PyContext, PyFuncArgs, PyIterable, PyObjectRef, PyRef, PyResult,
11-
PyValue, TypeProtocol,
10+
IdProtocol, IntoPyObject, OptionalArg, PyContext, PyFuncArgs, PyIterable, PyObjectRef, PyRef,
11+
PyResult, PyValue, TryFromObject, TypeProtocol,
1212
};
1313
use crate::vm::VirtualMachine;
1414

1515
use super::objint;
1616
use super::objsequence::PySliceableSequence;
1717
use super::objslice::PySlice;
18-
use super::objtype;
18+
use super::objtype::{self, PyClassRef};
1919

2020
#[derive(Clone, Debug)]
2121
pub struct PyString {
@@ -788,16 +788,21 @@ fn perform_format(
788788
// TODO: should with following format
789789
// class str(object='')
790790
// class str(object=b'', encoding='utf-8', errors='strict')
791-
fn str_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
792-
if args.args.len() == 1 {
793-
return Ok(vm.new_str("".to_string()));
794-
}
795-
796-
if args.args.len() > 2 {
797-
panic!("str expects exactly one parameter");
791+
fn str_new(
792+
cls: PyClassRef,
793+
object: OptionalArg<PyObjectRef>,
794+
vm: &mut VirtualMachine,
795+
) -> PyResult<PyStringRef> {
796+
let string = match object {
797+
OptionalArg::Present(ref input) => vm.to_str(input)?,
798+
OptionalArg::Missing => vm.new_str("".to_string()),
798799
};
799-
800-
vm.to_str(&args.args[1])
800+
if string.typ().is(&cls) {
801+
TryFromObject::try_from_object(vm, string)
802+
} else {
803+
let payload = string.payload::<PyString>().unwrap();
804+
PyRef::new_with_type(vm, payload.clone(), cls)
805+
}
801806
}
802807

803808
impl PySliceableSequence for String {

vm/src/obj/objtype.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::vm::VirtualMachine;
99

1010
use super::objdict;
1111
use super::objlist::PyList;
12+
use super::objproperty::PropertyBuilder;
1213
use super::objstr::{self, PyStringRef};
1314
use super::objtuple::PyTuple;
1415

@@ -78,6 +79,10 @@ impl PyClassRef {
7879
PyTuple::from(elements)
7980
}
8081

82+
fn set_mro(self, _value: PyObjectRef, vm: &mut VirtualMachine) -> PyResult {
83+
Err(vm.new_attribute_error("read-only attribute".to_string()))
84+
}
85+
8186
fn dir(self, vm: &mut VirtualMachine) -> PyList {
8287
let attributes = get_attributes(self);
8388
let attributes: Vec<PyObjectRef> = attributes
@@ -116,7 +121,11 @@ pub fn init(ctx: &PyContext) {
116121
extend_class!(&ctx, &ctx.type_type, {
117122
"__call__" => ctx.new_rustfunc(type_call),
118123
"__new__" => ctx.new_rustfunc(type_new),
119-
"__mro__" => ctx.new_property(PyClassRef::mro),
124+
"__mro__" =>
125+
PropertyBuilder::new(ctx)
126+
.add_getter(PyClassRef::mro)
127+
.add_setter(PyClassRef::set_mro)
128+
.create(),
120129
"__repr__" => ctx.new_rustfunc(PyClassRef::repr),
121130
"__prepare__" => ctx.new_rustfunc(PyClassRef::prepare),
122131
"__getattribute__" => ctx.new_rustfunc(type_getattribute),

0 commit comments

Comments
 (0)