Skip to content

Commit a389b55

Browse files
committed
Initial version of property class.
1 parent 6746784 commit a389b55

File tree

5 files changed

+85
-4
lines changed

5 files changed

+85
-4
lines changed

tests/snippets/class.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ def square(self):
1414
assert foo.x == 5
1515
assert foo.square() == 25
1616

17+
class Fubar:
18+
def __init__(self):
19+
self.x = 100
20+
21+
@property
22+
def foo(self):
23+
value = self.x
24+
self.x += 1
25+
return value
26+
27+
28+
f = Fubar()
29+
assert f.foo == 100
30+
assert f.foo == 101
31+
1732

1833
class Bar:
1934
@classmethod

vm/src/builtins.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ fn builtin_chr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
115115
Ok(vm.new_str(txt))
116116
}
117117

118-
// builtin_classmethod
119-
120118
fn builtin_compile(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
121119
arg_check!(vm, args, required = [(source, None)]);
122120
// TODO:
@@ -487,8 +485,6 @@ pub fn builtin_print(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
487485
Ok(vm.get_none())
488486
}
489487

490-
// builtin_property
491-
492488
fn builtin_range(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
493489
arg_check!(vm, args, required = [(range, Some(vm.ctx.int_type()))]);
494490
match range.borrow().kind {
@@ -593,6 +589,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef {
593589
dict.insert(String::from("next"), ctx.new_rustfunc(builtin_next));
594590
dict.insert(String::from("pow"), ctx.new_rustfunc(builtin_pow));
595591
dict.insert(String::from("print"), ctx.new_rustfunc(builtin_print));
592+
dict.insert(String::from("property"), ctx.property_type());
596593
dict.insert(String::from("range"), ctx.new_rustfunc(builtin_range));
597594
dict.insert(String::from("repr"), ctx.new_rustfunc(builtin_repr));
598595
dict.insert(String::from("set"), ctx.set_type());

vm/src/obj/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub mod objint;
1212
pub mod objiter;
1313
pub mod objlist;
1414
pub mod objobject;
15+
pub mod objproperty;
1516
pub mod objsequence;
1617
pub mod objset;
1718
pub mod objstr;

vm/src/obj/objproperty.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*! Python `property` descriptor class.
2+
3+
*/
4+
5+
use super::super::pyobject::{
6+
AttributeProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult,
7+
TypeProtocol,
8+
};
9+
use super::super::vm::VirtualMachine;
10+
use super::objtype;
11+
12+
pub fn init(context: &PyContext) {
13+
let ref property_type = context.property_type;
14+
property_type.set_attr("__get__", context.new_rustfunc(property_get));
15+
property_type.set_attr("__new__", context.new_rustfunc(property_new));
16+
// TODO: how to handle __set__ ?
17+
}
18+
19+
// `property` methods.
20+
fn property_get(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
21+
trace!("property.__get__ {:?}", args.args);
22+
arg_check!(
23+
vm,
24+
args,
25+
required = [
26+
(cls, Some(vm.ctx.property_type())),
27+
(inst, None),
28+
(_owner, None)
29+
]
30+
);
31+
32+
match cls.get_attr("fget") {
33+
Some(getter) => {
34+
let py_method = vm.new_bound_method(getter, inst.clone());
35+
vm.invoke(py_method, PyFuncArgs::default())
36+
}
37+
None => {
38+
let attribute_error = vm.context().exceptions.attribute_error.clone();
39+
Err(vm.new_exception(
40+
attribute_error,
41+
String::from("Attribute Error: property must have 'fget' attribute"),
42+
))
43+
}
44+
}
45+
}
46+
47+
fn property_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
48+
trace!("property.__new__ {:?}", args.args);
49+
arg_check!(vm, args, required = [(cls, None), (fget, None)]);
50+
51+
let py_obj = PyObject::new(
52+
PyObjectKind::Instance {
53+
dict: vm.ctx.new_dict(),
54+
},
55+
cls.clone(),
56+
);
57+
py_obj.set_attr("fget", fget.clone());
58+
Ok(py_obj)
59+
}

vm/src/pyobject.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use super::obj::objint;
1313
use super::obj::objiter;
1414
use super::obj::objlist;
1515
use super::obj::objobject;
16+
use super::obj::objproperty;
1617
use super::obj::objset;
1718
use super::obj::objstr;
1819
use super::obj::objtuple;
@@ -89,6 +90,7 @@ pub struct PyContext {
8990
pub iter_type: PyObjectRef,
9091
pub str_type: PyObjectRef,
9192
pub function_type: PyObjectRef,
93+
pub property_type: PyObjectRef,
9294
pub generator_type: PyObjectRef,
9395
pub module_type: PyObjectRef,
9496
pub bound_method_type: PyObjectRef,
@@ -145,6 +147,7 @@ impl PyContext {
145147
let classmethod_type = create_type("classmethod", &type_type, &object_type, &dict_type);
146148
let staticmethod_type = create_type("staticmethod", &type_type, &object_type, &dict_type);
147149
let function_type = create_type("function", &type_type, &object_type, &dict_type);
150+
let property_type = create_type("property", &type_type, &object_type, &dict_type);
148151
let generator_type = create_type("generator", &type_type, &object_type, &dict_type);
149152
let bound_method_type = create_type("method", &type_type, &object_type, &dict_type);
150153
let member_descriptor_type =
@@ -197,6 +200,7 @@ impl PyContext {
197200
str_type: str_type,
198201
object: object_type,
199202
function_type: function_type,
203+
property_type: property_type,
200204
generator_type: generator_type,
201205
module_type: module_type,
202206
bound_method_type: bound_method_type,
@@ -217,6 +221,7 @@ impl PyContext {
217221
objcomplex::init(&context);
218222
objbytes::init(&context);
219223
objbytearray::init(&context);
224+
objproperty::init(&context);
220225
objstr::init(&context);
221226
objtuple::init(&context);
222227
objiter::init(&context);
@@ -277,6 +282,10 @@ impl PyContext {
277282
self.function_type.clone()
278283
}
279284

285+
pub fn property_type(&self) -> PyObjectRef {
286+
self.property_type.clone()
287+
}
288+
280289
pub fn classmethod_type(&self) -> PyObjectRef {
281290
self.classmethod_type.clone()
282291
}

0 commit comments

Comments
 (0)