Commit 1a031045 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #195 from tjhance/property

Property
parents 4b5c6964 0ab9061c
......@@ -826,5 +826,6 @@ void setupBuiltins() {
builtins_module->giveAttr("instancemethod", instancemethod_cls);
builtins_module->giveAttr("complex", complex_cls);
builtins_module->giveAttr("super", super_cls);
builtins_module->giveAttr("property", property_cls);
}
}
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "codegen/compvars.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
namespace pyston {
static Box* memberGet(BoxedMemberDescriptor* self, Box* inst, Box* owner) {
RELEASE_ASSERT(self->cls == member_cls, "");
Py_FatalError("unimplemented");
}
static Box* propertyNew(Box* cls, Box* fget, Box* fset, Box** args) {
RELEASE_ASSERT(cls == property_cls, "");
Box* fdel = args[0];
Box* doc = args[1];
return new BoxedProperty(fget, fset, fdel, doc);
}
static Box* propertyGet(Box* self, Box* obj, Box* type) {
RELEASE_ASSERT(self->cls == property_cls, "");
BoxedProperty* prop = static_cast<BoxedProperty*>(self);
if (obj == NULL || obj == None) {
return self;
}
if (prop->prop_get == NULL) {
raiseExcHelper(AttributeError, "unreadable attribute");
}
return runtimeCall(prop->prop_get, ArgPassSpec(1), obj, NULL, NULL, NULL, NULL);
}
static Box* propertySet(Box* self, Box* obj, Box* val) {
RELEASE_ASSERT(self->cls == property_cls, "");
BoxedProperty* prop = static_cast<BoxedProperty*>(self);
Box* func;
if (val == NULL) {
func = prop->prop_del;
} else {
func = prop->prop_set;
}
if (func == NULL) {
raiseExcHelper(AttributeError, val == NULL ? "can't delete attribute" : "can't set attribute");
}
if (val == NULL) {
runtimeCall(func, ArgPassSpec(1), obj, NULL, NULL, NULL, NULL);
} else {
runtimeCall(func, ArgPassSpec(2), obj, val, NULL, NULL, NULL);
}
return None;
}
void setupDescr() {
member_cls->giveAttr("__name__", boxStrConstant("member"));
member_cls->giveAttr("__get__", new BoxedFunction(boxRTFunction((void*)memberGet, UNKNOWN, 3)));
member_cls->freeze();
property_cls->giveAttr("__name__", boxStrConstant("property"));
property_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)propertyNew, UNKNOWN, 5, 4, false, false),
{ None, None, None, None }));
property_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)propertyGet, UNKNOWN, 3, 0, false, false)));
property_cls->giveAttr("__set__",
new BoxedFunction(boxRTFunction((void*)propertySet, UNKNOWN, 3, 0, false, false)));
property_cls->freeze();
}
void teardownDescr() {
}
}
......@@ -892,6 +892,16 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const
}
}
else if (descr->cls == property_cls) {
rewrite_args = NULL; // TODO
BoxedProperty* prop = static_cast<BoxedProperty*>(descr);
if (prop->prop_get == NULL || prop->prop_get == None) {
raiseExcHelper(AttributeError, "unreadable attribute");
}
return runtimeCallInternal1(prop->prop_get, NULL, ArgPassSpec(1), obj);
}
return NULL;
}
......
// Copyright (c) 2014 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// you may not use this file except in compliance with the License. // You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
......@@ -292,7 +291,7 @@ extern "C" void closureGCHandler(GCVisitor* v, Box* b) {
extern "C" {
BoxedClass* object_cls, *type_cls, *none_cls, *bool_cls, *int_cls, *float_cls, *str_cls, *function_cls,
*instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *file_cls, *member_cls,
*closure_cls, *generator_cls, *complex_cls, *basestring_cls, *unicode_cls;
*closure_cls, *generator_cls, *complex_cls, *basestring_cls, *unicode_cls, *property_cls;
BoxedTuple* EmptyTuple;
......@@ -386,12 +385,6 @@ static Box* functionGet(BoxedFunction* self, Box* inst, Box* owner) {
return boxInstanceMethod(inst, self);
}
static Box* memberGet(BoxedMemberDescriptor* self, Box* inst, Box* owner) {
RELEASE_ASSERT(self->cls == member_cls, "");
Py_FatalError("unimplemented");
}
static Box* functionCall(BoxedFunction* self, Box* args, Box* kwargs) {
RELEASE_ASSERT(self->cls == function_cls, "%s", getTypeName(self)->c_str());
......@@ -707,6 +700,7 @@ void setupRuntime() {
member_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedMemberDescriptor), false);
closure_cls = new BoxedClass(type_cls, object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs),
sizeof(BoxedClosure), false);
property_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedProperty), false);
attrwrapper_cls = new BoxedClass(type_cls, object_cls, &AttrWrapper::gcHandler, 0, sizeof(AttrWrapper), false);
STR = typeFromClass(str_cls);
......@@ -755,10 +749,6 @@ void setupRuntime() {
module_cls->giveAttr("__str__", module_cls->getattr("__repr__"));
module_cls->freeze();
member_cls->giveAttr("__name__", boxStrConstant("member"));
member_cls->giveAttr("__get__", new BoxedFunction(boxRTFunction((void*)memberGet, UNKNOWN, 3)));
member_cls->freeze();
closure_cls->giveAttr("__name__", boxStrConstant("closure"));
closure_cls->freeze();
......@@ -778,6 +768,7 @@ void setupRuntime() {
setupClassobj();
setupSuper();
setupUnicode();
setupDescr();
function_cls->giveAttr("__name__", boxStrConstant("function"));
function_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)functionRepr, STR, 1)));
......@@ -881,6 +872,7 @@ void teardownRuntime() {
teardownSet();
teardownTuple();
teardownFile();
teardownDescr();
/*
// clear all the attributes on the base classes before freeing the classes themselves,
......
......@@ -63,6 +63,8 @@ void setupCAPI();
void teardownCAPI();
void setupGenerator();
void setupUnicode();
void setupDescr();
void teardownDescr();
void setupSys();
void setupBuiltins();
......@@ -78,7 +80,7 @@ Box* getSysStdout();
extern "C" {
extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_cls, *long_cls, *float_cls, *str_cls, *function_cls,
*none_cls, *instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *file_cls, *xrange_cls,
*member_cls, *method_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *unicode_cls;
*member_cls, *method_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *unicode_cls, *property_cls;
}
extern "C" { extern Box* None, *NotImplemented, *True, *False; }
extern "C" {
......@@ -391,6 +393,17 @@ public:
: Box(member_cls), type((MemberType)member->type), offset(member->offset) {}
};
class BoxedProperty : public Box {
public:
Box* prop_get;
Box* prop_set;
Box* prop_del;
Box* prop_doc;
BoxedProperty(Box* get, Box* set, Box* del, Box* doc)
: Box(property_cls), prop_get(get), prop_set(set), prop_del(del), prop_doc(doc) {}
};
// TODO is there any particular reason to make this a Box, ie a python-level object?
class BoxedClosure : public Box {
public:
......
class C(object):
def fget(self):
return 5
def fset(self, val):
print 'in fset, val =', val
x = property(fget, fset)
c = C()
print c.x
print C.x.__get__(c, C)
print type(C.x.__get__(None, C))
c.x = 7
print c.x
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment