Commit 99058d3d authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add simple support for methods with the METH_CLASS flag

I think this is ok, but it's implemented pretty differently from CPython
for now so I'm not sure.
parent 7785fe53
......@@ -24,29 +24,39 @@ Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, Boxe
assert(varargs->cls == tuple_cls);
assert(kwargs->cls == dict_cls);
if (!isSubclass(obj->cls, self->type))
raiseExcHelper(TypeError, "descriptor '%s' requires a '%s' object but received a '%s'", self->method->ml_name,
getFullNameOfClass(self->type).c_str(), getFullTypeName(obj).c_str());
int ml_flags = self->method->ml_flags;
int call_flags;
if (ml_flags & METH_CLASS) {
if (!isSubclass(obj->cls, type_cls))
raiseExcHelper(TypeError, "descriptor '%s' requires a type but received a '%s'", self->method->ml_name,
getFullTypeName(obj).c_str());
call_flags = ml_flags & (~METH_CLASS);
} else {
if (!isSubclass(obj->cls, self->type))
raiseExcHelper(TypeError, "descriptor '%s' requires a '%s' object but received a '%s'",
self->method->ml_name, getFullNameOfClass(self->type).c_str(), getFullTypeName(obj).c_str());
call_flags = ml_flags;
}
threading::GLPromoteRegion _gil_lock;
int ml_flags = self->method->ml_flags;
Box* rtn;
if (ml_flags == METH_NOARGS) {
if (call_flags == METH_NOARGS) {
assert(varargs->elts.size() == 0);
assert(kwargs->d.size() == 0);
rtn = (Box*)self->method->ml_meth(obj, NULL);
} else if (ml_flags == METH_VARARGS) {
} else if (call_flags == METH_VARARGS) {
assert(kwargs->d.size() == 0);
rtn = (Box*)self->method->ml_meth(obj, varargs);
} else if (ml_flags == (METH_VARARGS | METH_KEYWORDS)) {
} else if (call_flags == (METH_VARARGS | METH_KEYWORDS)) {
rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(obj, varargs, kwargs);
} else if (ml_flags == METH_O) {
} else if (call_flags == METH_O) {
assert(kwargs->d.size() == 0);
assert(varargs->elts.size() == 1);
rtn = (Box*)self->method->ml_meth(obj, varargs->elts[0]);
} else {
RELEASE_ASSERT(0, "0x%x", ml_flags);
RELEASE_ASSERT(0, "0x%x", call_flags);
}
checkAndThrowCAPIException();
......
......@@ -389,7 +389,8 @@ extern "C" PyObject* Py_InitModule4(const char* name, PyMethodDef* methods, cons
if (VERBOSITY())
printf("Loading method %s\n", methods->ml_name);
assert((methods->ml_flags & (~(METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O))) == 0);
RELEASE_ASSERT((methods->ml_flags & (~(METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O))) == 0, "%d",
methods->ml_flags);
module->giveAttr(methods->ml_name,
new BoxedCApiFunction(methods->ml_flags, passthrough, methods->ml_name, methods->ml_meth));
......
......@@ -144,10 +144,20 @@ public:
static Box* __get__(BoxedMethodDescriptor* self, Box* inst, Box* owner) {
RELEASE_ASSERT(self->cls == method_cls, "");
// CPython handles this differently: they create the equivalent of different BoxedMethodDescriptor
// objects but with different class objects, which define different __get__ and __call__ methods.
if (self->method->ml_flags & METH_CLASS)
return boxInstanceMethod(owner, self);
if (self->method->ml_flags & METH_STATIC)
Py_FatalError("unimplemented");
if (self->method->ml_flags & METH_COEXIST)
Py_FatalError("unimplemented");
if (inst == None)
return self;
// CPython apparently returns a "builtin_function_or_method" object
return boxInstanceMethod(inst, self);
else
return boxInstanceMethod(inst, self);
}
static Box* __call__(BoxedMethodDescriptor* self, Box* obj, BoxedTuple* varargs, Box** _args);
......
......@@ -6,3 +6,6 @@ print repr(datetime.time())
print datetime.datetime.__base__
print repr(datetime.datetime(1, 2, 3))
print str(datetime.timedelta(0))
# now() works on both the class and on its instances:
datetime.datetime.now().now()
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