Commit 14ba2e6e authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add CAPI-style getset descriptors as well

We already have getset support, but it takes function pointers
to Pyston-style functions.  CAPI types can specify tp_getset which
is almost the same thing, but the function pointers are to CAPI-style
functions.

Add the ability to do either, try to make it more explicit about
which one is being chosen, and change the existing getters/setters to be
more consistent with being Pyston-style functions.
parent 9cd8624a
......@@ -1855,9 +1855,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
cls->giveAttr(member->name, new BoxedMemberDescriptor(member));
}
if (cls->tp_getset) {
if (VERBOSITY())
printf("warning: ignoring tp_getset for now\n");
for (PyGetSetDef* getset = cls->tp_getset; getset && getset->name; ++getset) {
// TODO do something with __doc__
cls->giveAttr(getset->name, new (capi_getset_cls) BoxedGetsetDescriptor(
getset->get, (void (*)(Box*, Box*, void*))getset->set, getset->closure));
}
PystonType_Ready(cls);
......
......@@ -1535,7 +1535,7 @@ Box* BoxedCApiFunction::callInternal(BoxedFunctionBase* func, CallRewriteArgs* r
return r;
}
static Box* method_get_doc(Box* b, void*) {
static Box* methodGetDoc(Box* b, void*) {
assert(b->cls == method_cls);
const char* s = static_cast<BoxedMethodDescriptor*>(b)->method->ml_doc;
if (s)
......@@ -1560,7 +1560,7 @@ void setupCAPI() {
new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3)));
method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2,
0, true, true)));
method_cls->giveAttr("__doc__", new BoxedGetsetDescriptor(method_get_doc, NULL, NULL));
method_cls->giveAttr("__doc__", new (pyston_getset_cls) BoxedGetsetDescriptor(methodGetDoc, NULL, NULL));
method_cls->freeze();
wrapperdescr_cls
......
......@@ -981,7 +981,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const
}
// Special case: data descriptor: getset descriptor
else if (descr->cls == getset_cls) {
else if (descr->cls == pyston_getset_cls || descr->cls == capi_getset_cls) {
BoxedGetsetDescriptor* getset_descr = static_cast<BoxedGetsetDescriptor*>(descr);
// TODO some more checks should go here
......@@ -1006,6 +1006,11 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const
RewriterVar* r_closure = r_descr->getAttr(offsetof(BoxedGetsetDescriptor, closure));
rewrite_args->out_rtn = rewrite_args->rewriter->call(
/* can_call_into_python */ true, (void*)getset_descr->get, rewrite_args->obj, r_closure);
if (descr->cls == capi_getset_cls)
// TODO I think we are supposed to check the return value?
rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException);
rewrite_args->out_success = true;
}
......@@ -1528,7 +1533,7 @@ bool dataDescriptorSetSpecialCases(Box* obj, Box* val, Box* descr, SetattrRewrit
RewriterVar* r_descr, const std::string& attr_name) {
// Special case: getset descriptor
if (descr->cls == getset_cls) {
if (descr->cls == pyston_getset_cls || descr->cls == capi_getset_cls) {
BoxedGetsetDescriptor* getset_descr = static_cast<BoxedGetsetDescriptor*>(descr);
// TODO type checking goes here
......@@ -1545,6 +1550,11 @@ bool dataDescriptorSetSpecialCases(Box* obj, Box* val, Box* descr, SetattrRewrit
RewriterVar* r_closure = r_descr->getAttr(offsetof(BoxedGetsetDescriptor, closure));
rewrite_args->rewriter->call(
/* can_call_into_python */ true, (void*)getset_descr->set, { r_obj, r_val, r_closure });
if (descr->cls == capi_getset_cls)
// TODO I think we are supposed to check the return value?
rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException);
rewrite_args->out_success = true;
}
......
......@@ -519,7 +519,8 @@ extern "C" {
BoxedClass* object_cls, *type_cls, *none_cls, *bool_cls, *int_cls, *float_cls,
* str_cls = NULL, *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, *property_cls,
*staticmethod_cls, *classmethod_cls, *attrwrapper_cls, *getset_cls, *builtin_function_or_method_cls;
*staticmethod_cls, *classmethod_cls, *attrwrapper_cls, *pyston_getset_cls, *capi_getset_cls,
*builtin_function_or_method_cls;
BoxedTuple* EmptyTuple;
}
......@@ -650,14 +651,14 @@ static Box* functionCall(BoxedFunction* self, Box* args, Box* kwargs) {
return runtimeCall(self, ArgPassSpec(0, 0, true, true), args, kwargs, NULL, NULL, NULL);
}
static Box* func_name(Box* b, void*) {
static Box* funcName(Box* b, void*) {
assert(b->cls == function_cls);
BoxedFunction* func = static_cast<BoxedFunction*>(b);
RELEASE_ASSERT(func->name != NULL, "func->name is not set");
return func->name;
}
static void func_set_name(Box* b, Box* v, void*) {
static void funcSetName(Box* b, Box* v, void*) {
assert(b->cls == function_cls);
BoxedFunction* func = static_cast<BoxedFunction*>(b);
......@@ -668,7 +669,7 @@ static void func_set_name(Box* b, Box* v, void*) {
func->name = static_cast<BoxedString*>(v);
}
static Box* builtin_function_or_method_name(Box* b, void*) {
static Box* builtinFunctionOrMethodName(Box* b, void*) {
// In CPython, these guys just store char*, and it gets wrapped here
// But we already share the BoxedString* field with BoxedFunctions...
// so it's more convenient to just use that, which is what we do here.
......@@ -1058,7 +1059,7 @@ Box* objectStr(Box* obj) {
return obj->reprIC();
}
static Box* type_name(Box* b, void*) {
static Box* typeName(Box* b, void*) {
assert(b->cls == type_cls);
BoxedClass* type = static_cast<BoxedClass*>(b);
......@@ -1076,7 +1077,7 @@ static Box* type_name(Box* b, void*) {
}
}
static void type_set_name(Box* b, Box* v, void*) {
static void typeSetName(Box* b, Box* v, void*) {
assert(b->cls == type_cls);
BoxedClass* type = static_cast<BoxedClass*>(b);
......@@ -1224,7 +1225,8 @@ void setupRuntime() {
set_cls = new BoxedHeapClass(object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "set");
frozenset_cls = new BoxedHeapClass(object_cls, &setGCHandler, 0, sizeof(BoxedSet), false, "frozenset");
member_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedMemberDescriptor), false, "member");
getset_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
pyston_getset_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
capi_getset_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
closure_cls = new BoxedHeapClass(object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs), sizeof(BoxedClosure),
false, "closure");
property_cls = new BoxedHeapClass(object_cls, &propertyGCHandler, 0, sizeof(BoxedProperty), false, "property");
......@@ -1235,6 +1237,10 @@ void setupRuntime() {
attrwrapper_cls
= new BoxedHeapClass(object_cls, &AttrWrapper::gcHandler, 0, sizeof(AttrWrapper), false, "attrwrapper");
// TODO: add explicit __get__ and __set__ methods to these
pyston_getset_cls->freeze();
capi_getset_cls->freeze();
STR = typeFromClass(str_cls);
BOXED_INT = typeFromClass(int_cls);
BOXED_FLOAT = typeFromClass(float_cls);
......@@ -1259,7 +1265,7 @@ void setupRuntime() {
auto typeCallObj = boxRTFunction((void*)typeCall, UNKNOWN, 1, 0, true, true);
typeCallObj->internal_callable = &typeCallInternal;
type_cls->giveAttr("__name__", new BoxedGetsetDescriptor(type_name, type_set_name, NULL));
type_cls->giveAttr("__name__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeName, typeSetName, NULL));
type_cls->giveAttr("__call__", new BoxedFunction(typeCallObj));
type_cls->giveAttr("__new__",
......@@ -1299,7 +1305,7 @@ void setupRuntime() {
setupDescr();
setupTraceback();
function_cls->giveAttr("__name__", new BoxedGetsetDescriptor(func_name, func_set_name, NULL));
function_cls->giveAttr("__name__", new (pyston_getset_cls) BoxedGetsetDescriptor(funcName, funcSetName, NULL));
function_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)functionRepr, STR, 1)));
function_cls->giveAttr("__module__",
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedFunction, modname)));
......@@ -1314,8 +1320,8 @@ void setupRuntime() {
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedBuiltinFunctionOrMethod, modname)));
builtin_function_or_method_cls->giveAttr(
"__repr__", new BoxedFunction(boxRTFunction((void*)builtinFunctionOrMethodRepr, STR, 1)));
builtin_function_or_method_cls->giveAttr("__name__",
new BoxedGetsetDescriptor(builtin_function_or_method_name, NULL, NULL));
builtin_function_or_method_cls->giveAttr(
"__name__", new (pyston_getset_cls) BoxedGetsetDescriptor(builtinFunctionOrMethodName, NULL, NULL));
builtin_function_or_method_cls->freeze();
instancemethod_cls->giveAttr(
......
......@@ -81,8 +81,8 @@ 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,
*enumerate_cls, *xrange_cls, *member_cls, *method_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls,
*unicode_cls, *property_cls, *staticmethod_cls, *classmethod_cls, *attrwrapper_cls, *getset_cls,
*builtin_function_or_method_cls;
*unicode_cls, *property_cls, *staticmethod_cls, *classmethod_cls, *attrwrapper_cls, *pyston_getset_cls,
*capi_getset_cls, *builtin_function_or_method_cls;
}
extern "C" {
extern Box* None, *NotImplemented, *True, *False;
......@@ -544,7 +544,7 @@ public:
BoxedGetsetDescriptor(Box* (*get)(Box*, void*), void (*set)(Box*, Box*, void*), void* closure)
: get(get), set(set), closure(closure) {}
DEFAULT_CLASS_SIMPLE(getset_cls);
// No DEFAULT_CLASS annotation here -- force callers to explicitly specifiy pyston_getset_cls or capi_getset_cls
};
class BoxedProperty : public Box {
......
......@@ -7,3 +7,5 @@ print o.items()
for i in xrange(30):
o[(i ** 2) ^ 0xace] = i
print o
print collections.deque().maxlen
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