Commit ce37a0e4 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Support the types in the operator module

Add tp_call handling, a couple random functions, and
allow GC-aware objects (though we don't do much with them).
parent 34e93606
...@@ -914,9 +914,6 @@ initoperator(void) ...@@ -914,9 +914,6 @@ initoperator(void)
if (m == NULL) if (m == NULL)
return; return;
/* Pyston TODO: un-comment these when we have the functionality to
* support them.
if (PyType_Ready(&itemgetter_type) < 0) if (PyType_Ready(&itemgetter_type) < 0)
return; return;
Py_INCREF(&itemgetter_type); Py_INCREF(&itemgetter_type);
...@@ -931,5 +928,4 @@ initoperator(void) ...@@ -931,5 +928,4 @@ initoperator(void)
return; return;
Py_INCREF(&methodcaller_type); Py_INCREF(&methodcaller_type);
PyModule_AddObject(m, "methodcaller", (PyObject *)&methodcaller_type); PyModule_AddObject(m, "methodcaller", (PyObject *)&methodcaller_type);
*/
} }
...@@ -143,15 +143,21 @@ extern "C" PyObject* PyType_GenericAlloc(PyTypeObject* cls, Py_ssize_t nitems) { ...@@ -143,15 +143,21 @@ extern "C" PyObject* PyType_GenericAlloc(PyTypeObject* cls, Py_ssize_t nitems) {
return rtn; return rtn;
} }
/*
// These are for supporting things like tp_call.
// tp_new is handled differently, which is the only one supported right now,
// which is why these are (temporarily) commented out.
BoxedClass* wrapperdescr_cls, *wrapperobject_cls; BoxedClass* wrapperdescr_cls, *wrapperobject_cls;
struct wrapper_def {
const char* name;
int offset;
int flags;
};
wrapper_def call_wrapper = { "__call__", offsetof(PyTypeObject, tp_call), PyWrapperFlag_KEYWORDS };
class BoxedWrapperDescriptor : public Box { class BoxedWrapperDescriptor : public Box {
public: public:
const int offset; const wrapper_def* wrapper;
BoxedWrapperDescriptor(int offset) : Box(wrapperdescr_cls), offset(offset) {} BoxedClass* type;
BoxedWrapperDescriptor(const wrapper_def* wrapper, BoxedClass* type)
: Box(wrapperdescr_cls), wrapper(wrapper), type(type) {}
static Box* __get__(BoxedWrapperDescriptor* self, Box* inst, Box* owner); static Box* __get__(BoxedWrapperDescriptor* self, Box* inst, Box* owner);
}; };
...@@ -164,9 +170,19 @@ public: ...@@ -164,9 +170,19 @@ public:
BoxedWrapperObject(BoxedWrapperDescriptor* descr, Box* obj) : Box(wrapperobject_cls), descr(descr), obj(obj) {} BoxedWrapperObject(BoxedWrapperDescriptor* descr, Box* obj) : Box(wrapperobject_cls), descr(descr), obj(obj) {}
static Box* __call__(BoxedWrapperObject* self, Box* args, Box* kwds) { static Box* __call__(BoxedWrapperObject* self, Box* args, Box* kwds) {
assert(self->cls == wrapperobject_cls);
assert(args->cls == tuple_cls); assert(args->cls == tuple_cls);
assert(kwds->cls == dict_cls); assert(kwds->cls == dict_cls);
int flags = self->descr->wrapper->flags;
char* ptr = (char*)self->descr->type + self->descr->wrapper->offset;
if (flags & PyWrapperFlag_KEYWORDS) {
PyCFunctionWithKeywords f = *(PyCFunctionWithKeywords*)ptr;
return f(self->obj, args, kwds);
} else {
abort();
}
abort(); abort();
} }
}; };
...@@ -177,9 +193,12 @@ Box* BoxedWrapperDescriptor::__get__(BoxedWrapperDescriptor* self, Box* inst, Bo ...@@ -177,9 +193,12 @@ Box* BoxedWrapperDescriptor::__get__(BoxedWrapperDescriptor* self, Box* inst, Bo
if (inst == None) if (inst == None)
return self; return self;
if (!isSubclass(inst->cls, self->type))
raiseExcHelper(TypeError, "Descriptor '' for '%s' objects doesn't apply to '%s' object",
getFullNameOfClass(self->type).c_str(), getFullTypeName(inst).c_str());
return new BoxedWrapperObject(self, inst); return new BoxedWrapperObject(self, inst);
} }
*/
PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) { PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) {
RELEASE_ASSERT(isSubclass(self->cls, type_cls), ""); RELEASE_ASSERT(isSubclass(self->cls, type_cls), "");
...@@ -212,14 +231,16 @@ extern "C" int PyType_Ready(PyTypeObject* cls) { ...@@ -212,14 +231,16 @@ extern "C" int PyType_Ready(PyTypeObject* cls) {
RELEASE_ASSERT(cls->tp_as_sequence == NULL, ""); RELEASE_ASSERT(cls->tp_as_sequence == NULL, "");
RELEASE_ASSERT(cls->tp_as_mapping == NULL, ""); RELEASE_ASSERT(cls->tp_as_mapping == NULL, "");
RELEASE_ASSERT(cls->tp_hash == NULL, ""); RELEASE_ASSERT(cls->tp_hash == NULL, "");
RELEASE_ASSERT(cls->tp_call == NULL, "");
RELEASE_ASSERT(cls->tp_str == NULL, ""); RELEASE_ASSERT(cls->tp_str == NULL, "");
RELEASE_ASSERT(cls->tp_getattro == NULL || cls->tp_getattro == PyObject_GenericGetAttr, ""); RELEASE_ASSERT(cls->tp_getattro == NULL || cls->tp_getattro == PyObject_GenericGetAttr, "");
RELEASE_ASSERT(cls->tp_setattro == NULL, ""); RELEASE_ASSERT(cls->tp_setattro == NULL, "");
RELEASE_ASSERT(cls->tp_as_buffer == NULL, ""); RELEASE_ASSERT(cls->tp_as_buffer == NULL, "");
RELEASE_ASSERT((cls->tp_flags & ~(Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE)) == 0, "");
RELEASE_ASSERT(cls->tp_traverse == NULL, ""); int ALLOWABLE_FLAGS = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC;
RELEASE_ASSERT(cls->tp_clear == NULL, ""); RELEASE_ASSERT((cls->tp_flags & ~ALLOWABLE_FLAGS) == 0, "");
// RELEASE_ASSERT(cls->tp_traverse == NULL, "");
// RELEASE_ASSERT(cls->tp_clear == NULL, "");
RELEASE_ASSERT(cls->tp_richcompare == NULL, ""); RELEASE_ASSERT(cls->tp_richcompare == NULL, "");
RELEASE_ASSERT(cls->tp_iter == NULL, ""); RELEASE_ASSERT(cls->tp_iter == NULL, "");
RELEASE_ASSERT(cls->tp_iternext == NULL, ""); RELEASE_ASSERT(cls->tp_iternext == NULL, "");
...@@ -265,6 +286,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) { ...@@ -265,6 +286,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) {
new BoxedCApiFunction(METH_VARARGS | METH_KEYWORDS, cls, "__new__", (PyCFunction)tp_new_wrapper)); new BoxedCApiFunction(METH_VARARGS | METH_KEYWORDS, cls, "__new__", (PyCFunction)tp_new_wrapper));
} }
if (cls->tp_call) {
cls->giveAttr("__call__", new BoxedWrapperDescriptor(&call_wrapper, cls));
}
if (!cls->tp_alloc) { if (!cls->tp_alloc) {
cls->tp_alloc = reinterpret_cast<decltype(cls->tp_alloc)>(PyType_GenericAlloc); cls->tp_alloc = reinterpret_cast<decltype(cls->tp_alloc)>(PyType_GenericAlloc);
} }
...@@ -405,18 +430,23 @@ extern "C" void PyObject_Free(void* p) { ...@@ -405,18 +430,23 @@ extern "C" void PyObject_Free(void* p) {
extern "C" PyObject* _PyObject_GC_Malloc(size_t) { extern "C" PyObject* _PyObject_GC_Malloc(size_t) {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
extern "C" PyObject* _PyObject_GC_New(PyTypeObject*) {
Py_FatalError("unimplemented"); extern "C" PyObject* _PyObject_GC_New(PyTypeObject* cls) {
return _PyObject_New(cls);
} }
extern "C" PyVarObject* _PyObject_GC_NewVar(PyTypeObject*, Py_ssize_t) { extern "C" PyVarObject* _PyObject_GC_NewVar(PyTypeObject*, Py_ssize_t) {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
extern "C" void PyObject_GC_Track(void*) { extern "C" void PyObject_GC_Track(void*) {
Py_FatalError("unimplemented"); // TODO do we have to do anything to support the C API GC protocol?
} }
extern "C" void PyObject_GC_UnTrack(void*) { extern "C" void PyObject_GC_UnTrack(void*) {
Py_FatalError("unimplemented"); // TODO do we have to do anything to support the C API GC protocol?
} }
extern "C" void PyObject_GC_Del(void*) { extern "C" void PyObject_GC_Del(void*) {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
...@@ -470,7 +500,16 @@ extern "C" PyObject* PyObject_GetIter(PyObject*) { ...@@ -470,7 +500,16 @@ extern "C" PyObject* PyObject_GetIter(PyObject*) {
} }
extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) { extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) {
Py_FatalError("unimplemented"); if (!isSubclass(attr_name->cls, str_cls)) {
PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", Py_TYPE(attr_name)->tp_name);
return NULL;
}
try {
return getattr(o, static_cast<BoxedString*>(attr_name)->s.c_str());
} catch (Box* b) {
Py_FatalError("unimplemented");
}
} }
extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) { extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) {
...@@ -519,7 +558,11 @@ extern "C" int PyObject_Not(PyObject* o) { ...@@ -519,7 +558,11 @@ extern "C" int PyObject_Not(PyObject* o) {
} }
extern "C" PyObject* PyObject_Call(PyObject* callable_object, PyObject* args, PyObject* kw) { extern "C" PyObject* PyObject_Call(PyObject* callable_object, PyObject* args, PyObject* kw) {
Py_FatalError("unimplemented"); try {
return runtimeCall(callable_object, ArgPassSpec(0, 0, true, true), args, kw, NULL, NULL, NULL);
} catch (Box* b) {
Py_FatalError("unimplemented");
}
} }
extern "C" void PyObject_ClearWeakRefs(PyObject* object) { extern "C" void PyObject_ClearWeakRefs(PyObject* object) {
...@@ -945,7 +988,6 @@ void setupCAPI() { ...@@ -945,7 +988,6 @@ void setupCAPI() {
0, true, true))); 0, true, true)));
method_cls->freeze(); method_cls->freeze();
/*
wrapperdescr_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedWrapperDescriptor), false); wrapperdescr_cls = new BoxedClass(type_cls, object_cls, NULL, 0, sizeof(BoxedWrapperDescriptor), false);
wrapperdescr_cls->giveAttr("__name__", boxStrConstant("wrapper_descriptor")); wrapperdescr_cls->giveAttr("__name__", boxStrConstant("wrapper_descriptor"));
wrapperdescr_cls->giveAttr("__get__", wrapperdescr_cls->giveAttr("__get__",
...@@ -957,7 +999,6 @@ void setupCAPI() { ...@@ -957,7 +999,6 @@ void setupCAPI() {
wrapperobject_cls->giveAttr( wrapperobject_cls->giveAttr(
"__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperObject::__call__, UNKNOWN, 1, 0, true, true))); "__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperObject::__call__, UNKNOWN, 1, 0, true, true)));
wrapperobject_cls->freeze(); wrapperobject_cls->freeze();
*/
} }
void teardownCAPI() { void teardownCAPI() {
......
...@@ -412,7 +412,7 @@ extern "C" Box** unpackIntoArray(Box* obj, int64_t expected_size) { ...@@ -412,7 +412,7 @@ extern "C" Box** unpackIntoArray(Box* obj, int64_t expected_size) {
PyObject* Py_CallPythonNew(PyTypeObject* self, PyObject* args, PyObject* kwds) { PyObject* Py_CallPythonNew(PyTypeObject* self, PyObject* args, PyObject* kwds) {
try { try {
Py_FatalError("this function is unverified"); Py_FatalError("this function is untested");
Box* new_attr = typeLookup(self, _new_str, NULL); Box* new_attr = typeLookup(self, _new_str, NULL);
assert(new_attr); assert(new_attr);
...@@ -423,16 +423,33 @@ PyObject* Py_CallPythonNew(PyTypeObject* self, PyObject* args, PyObject* kwds) { ...@@ -423,16 +423,33 @@ PyObject* Py_CallPythonNew(PyTypeObject* self, PyObject* args, PyObject* kwds) {
} }
} }
PyObject* Py_CallPythonCall(PyObject* self, PyObject* args, PyObject* kwds) {
try {
Py_FatalError("this function is untested");
return runtimeCallInternal(self, NULL, ArgPassSpec(0, 0, true, true), args, kwds, NULL, NULL, NULL);
} catch (Box* e) {
abort();
}
}
void BoxedClass::freeze() { void BoxedClass::freeze() {
assert(!is_constant); assert(!is_constant);
assert(getattr("__name__")); // otherwise debugging will be very hard assert(getattr("__name__")); // otherwise debugging will be very hard
// This will probably share a lot in common with Py_TypeReady:
if (!tp_new) { if (!tp_new) {
this->tp_new = &Py_CallPythonNew; this->tp_new = &Py_CallPythonNew;
} else if (tp_new != Py_CallPythonNew) { } else if (tp_new != Py_CallPythonNew) {
ASSERT(0, "need to set __new__?"); ASSERT(0, "need to set __new__?");
} }
if (!tp_call) {
this->tp_call = &Py_CallPythonCall;
} else if (tp_call != Py_CallPythonCall) {
ASSERT(0, "need to set __call__?");
}
is_constant = true; is_constant = true;
} }
...@@ -565,7 +582,7 @@ Box::Box(BoxedClass* cls) : cls(cls) { ...@@ -565,7 +582,7 @@ Box::Box(BoxedClass* cls) : cls(cls) {
// the only way cls should be NULL is if we're creating the type_cls // the only way cls should be NULL is if we're creating the type_cls
// object itself: // object itself:
if (cls == NULL) { if (cls == NULL) {
assert(type_cls == NULL); ASSERT(type_cls == NULL, "should pass a non-null cls here");
} else { } else {
} }
} }
...@@ -1482,6 +1499,13 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite ...@@ -1482,6 +1499,13 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
rewrite_args = NULL; rewrite_args = NULL;
} }
if (attr == "__call__") {
self->tp_call = &Py_CallPythonCall;
// TODO update subclasses
rewrite_args = NULL;
}
} }
Box* _set_ = NULL; Box* _set_ = NULL;
...@@ -1854,6 +1878,11 @@ extern "C" void dump(void* p) { ...@@ -1854,6 +1878,11 @@ extern "C" void dump(void* p) {
if (isSubclass(b->cls, str_cls)) { if (isSubclass(b->cls, str_cls)) {
printf("String value: %s\n", static_cast<BoxedString*>(b)->s.c_str()); printf("String value: %s\n", static_cast<BoxedString*>(b)->s.c_str());
} }
if (isSubclass(b->cls, tuple_cls)) {
printf("%ld elements\n", static_cast<BoxedTuple*>(b)->elts.size());
}
return; return;
} }
......
...@@ -101,7 +101,21 @@ Box* tupleGetitemSlice(BoxedTuple* self, BoxedSlice* slice) { ...@@ -101,7 +101,21 @@ Box* tupleGetitemSlice(BoxedTuple* self, BoxedSlice* slice) {
} }
extern "C" PyObject* PyTuple_GetSlice(PyObject* p, Py_ssize_t low, Py_ssize_t high) { extern "C" PyObject* PyTuple_GetSlice(PyObject* p, Py_ssize_t low, Py_ssize_t high) {
Py_FatalError("unimplemented"); RELEASE_ASSERT(p->cls == tuple_cls, ""); // could it be a subclass or something else?
BoxedTuple* t = static_cast<BoxedTuple*>(p);
Py_ssize_t n = t->elts.size();
if (low < 0)
low = 0;
if (high > n)
high = n;
if (high < low)
high = low;
if (low == 0 && high == n)
return p;
return new BoxedTuple(BoxedTuple::GCVector(&t->elts[low], &t->elts[high]));
} }
Box* tupleGetitem(BoxedTuple* self, Box* slice) { Box* tupleGetitem(BoxedTuple* self, Box* slice) {
......
# expected: fail
import operator import operator
print operator.methodcaller print operator.methodcaller
print operator.itemgetter print operator.itemgetter
print operator.attrgetter print operator.attrgetter
f = operator.methodcaller("__repr__")
print f(1)
print f("hello world")
f = operator.itemgetter(0)
print f("i")
print f((None,))
f = operator.attrgetter("count")
print f(["a", "a"])("a")
print f("ababa")("a")
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