diff options
author | Marcelo Lira <marcelo.lira@openbossa.org> | 2010-01-19 13:58:41 -0300 |
---|---|---|
committer | Marcelo Lira <marcelo.lira@openbossa.org> | 2010-01-19 14:36:38 -0300 |
commit | 7c53af9664740467c65724577c9210593e308a85 (patch) | |
tree | 1718a875154fa7d6fd6d10abe13cd3d1cd478705 | |
parent | cca03574c6a683e9644210d3038775843792f9d7 (diff) |
Generator now supports overloads with both static and non-static methods.
When a class contains one or more overloads with static and non-static
signatures Python must accept both usages, but for this to work some
steps must be taken:
* The overload method is defined with its own PyMethodDef structure,
instead of being parte of an array of definitions.
* The overload method is marked as static in the PyMethodDef.
* This method definition is inserted in the PyMethodDef array for the
class.
* A tp_getattro function is generated and registered for the Python
wrapper. It is used to intercept instance calls to methods with
static versions to add the 'self' to the PyMethod.
Reviewed by Marcelo Lira <marcelo.lira@openbossa.org>
-rw-r--r-- | cppgenerator.cpp | 92 | ||||
-rw-r--r-- | cppgenerator.h | 3 |
2 files changed, 81 insertions, 14 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp index 4e459c5b5..45f35352a 100644 --- a/cppgenerator.cpp +++ b/cppgenerator.cpp @@ -176,6 +176,8 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl QString methodsDefinitions; QTextStream md(&methodsDefinitions); + QString singleMethodDefinitions; + QTextStream smd(&singleMethodDefinitions); bool hasComparisonOperator = false; bool typeAsNumber = false; @@ -206,15 +208,33 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl else writeMethodWrapper(s, overloads); - if (!rfunc->isConstructor() && !rfunc->isOperatorOverload()) + if (!rfunc->isConstructor() && !rfunc->isOperatorOverload()) { + if (OverloadData::hasStaticAndInstanceFunctions(overloads)) { + QString methDefName = cpythonMethodDefinitionName(rfunc); + smd << "static PyMethodDef " << methDefName << " = {" << endl; + smd << INDENT; + writeMethodDefinitionEntry(smd, overloads); + smd << endl << "};" << endl << endl; + } writeMethodDefinition(md, overloads); + } } QString className = cpythonTypeName(metaClass).replace(QRegExp("_Type$"), ""); + // Write single method definitions + s << singleMethodDefinitions; + // Write methods definition s << "static PyMethodDef " << className << "_methods[] = {" << endl; - s << methodsDefinitions << INDENT << "{0} // Sentinel" << endl << "};" << endl << endl; + s << methodsDefinitions << INDENT << "{0} // Sentinel" << endl; + s << "};" << endl << endl; + + // Write tp_getattro function + if (classNeedsGetattroFunction(metaClass)) { + writeGetattroFunction(s, metaClass); + s << endl; + } if (typeAsNumber) { QList<AbstractMetaFunctionList> opOverloads = filterGroupedOperatorFunctions( @@ -666,7 +686,16 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction } // Checks if the underlying C++ object is valid. - writeInvalidCppObjectCheck(s); + if (OverloadData::hasStaticAndInstanceFunctions(overloads)) { + s << INDENT << "if (self) {" << endl; + { + Indentation indent(INDENT); + writeInvalidCppObjectCheck(s); + } + s << INDENT << '}' << endl; + } else { + writeInvalidCppObjectCheck(s); + } s << endl; } @@ -1408,6 +1437,7 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* QString tp_flags; QString tp_init; QString tp_new; + QString tp_getattro('0'); QString tp_dealloc; QString tp_as_number('0'); QString tp_as_sequence('0'); @@ -1452,6 +1482,9 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* tp_init = ctors.isEmpty() ? "0" : cpythonFunctionName(ctors.first()); } + if (classNeedsGetattroFunction(metaClass)) + tp_getattro = cpythonGetattroFunctionName(metaClass); + if (metaClass->isPolymorphic()) type_name_func = cpythonBaseName(metaClass) + "_typeName"; @@ -1507,7 +1540,7 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* s << INDENT << "/*tp_hash*/ 0," << endl; s << INDENT << "/*tp_call*/ 0," << endl; s << INDENT << "/*tp_str*/ " << m_tpFuncs["__str__"] << ',' << endl; - s << INDENT << "/*tp_getattro*/ 0," << endl; + s << INDENT << "/*tp_getattro*/ " << tp_getattro << ',' << endl; s << INDENT << "/*tp_setattro*/ 0," << endl; s << INDENT << "/*tp_as_buffer*/ 0," << endl; s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl; @@ -1796,17 +1829,12 @@ void CppGenerator::writeRichCompareFunction(QTextStream& s, const AbstractMetaCl s << '}' << endl << endl; } -void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads) +void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads) { Q_ASSERT(!overloads.isEmpty()); QPair<int, int> minMax = OverloadData::getMinMaxArguments(overloads); - const AbstractMetaFunction* func = overloads[0]; - if (m_tpFuncs.contains(func->name())) - return; - - s << INDENT << "{\"" << func->name() << "\", (PyCFunction)"; - s << cpythonFunctionName(func) << ", "; - + const AbstractMetaFunction* func = overloads.first(); + s << '"' << func->name() << "\", (PyCFunction)" << cpythonFunctionName(func) << ", "; if (minMax.second < 2) { if (minMax.first == 0) s << "METH_NOARGS"; @@ -1817,9 +1845,26 @@ void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunct } else { s << "METH_VARARGS"; } - if (func->ownerClass() && func->isStatic()) + if (func->ownerClass() && OverloadData::hasStaticFunction(overloads)) s << "|METH_STATIC"; - s << "}," << endl; +} + +void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads) +{ + Q_ASSERT(!overloads.isEmpty()); + const AbstractMetaFunction* func = overloads.first(); + if (m_tpFuncs.contains(func->name())) + return; + + s << INDENT; + if (OverloadData::hasStaticAndInstanceFunctions(overloads)) { + s << cpythonMethodDefinitionName(func); + } else { + s << '{'; + writeMethodDefinitionEntry(s, overloads); + s << '}'; + } + s << ',' << endl; } void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* cppEnum) @@ -2295,6 +2340,25 @@ void CppGenerator::writeSbkCopyCppObjectFunction(QTextStream& s, const AbstractM s << '}' << endl; } +void CppGenerator::writeGetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass) +{ + s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* self, PyObject* name)" << endl; + s << '{' << endl; + s << INDENT << "if (self) {" << endl; + { + Indentation indent(INDENT); + s << INDENT << "const char* cname = PyString_AS_STRING(name);" << endl; + foreach (const AbstractMetaFunction* func, getMethodsWithBothStaticAndNonStaticMethods(metaClass)) { + s << INDENT << "if (strcmp(cname, \"" << func->name() << "\") == 0)" << endl; + Indentation indent(INDENT); + s << INDENT << "return PyCFunction_NewEx(&" << cpythonMethodDefinitionName(func) << ", self, 0);" << endl; + } + } + s << INDENT << '}' << endl; + s << INDENT << "return PyObject_GenericGetAttr(self, name);" << endl; + s << '}' << endl; +} + void CppGenerator::finishGeneration() { //Generate CPython wrapper file diff --git a/cppgenerator.h b/cppgenerator.h index 2648d054b..796273f82 100644 --- a/cppgenerator.h +++ b/cppgenerator.h @@ -70,6 +70,8 @@ private: void writeSbkCopyCppObjectFunction(QTextStream& s, const AbstractMetaClass* metaClass); + void writeGetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass); + /** * Writes Python to C++ conversions for arguments on Python wrappers. * If implicit conversions, and thus new object allocation, are needed, @@ -114,6 +116,7 @@ private: void writeClassRegister(QTextStream& s, const AbstractMetaClass* metaClass); void writeClassDefinition(QTextStream& s, const AbstractMetaClass* metaClass); + void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads); void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads); /// Writes the implementation of all methods part of python sequence protocol void writeSequenceMethods(QTextStream& s, const AbstractMetaClass* metaClass); |