aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cppgenerator.cpp260
-rw-r--r--cppgenerator.h31
2 files changed, 214 insertions, 77 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp
index 3b742e298..4b30a573e 100644
--- a/cppgenerator.cpp
+++ b/cppgenerator.cpp
@@ -675,9 +675,11 @@ void CppGenerator::writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass
void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFunctionList overloads)
{
OverloadData overloadData(overloads, this);
+
const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
const AbstractMetaClass* metaClass = rfunc->ownerClass();
QString className = cpythonTypeName(metaClass);
+
m_currentErrorCode = -1;
s << "static int" << endl;
@@ -689,17 +691,8 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun
s << (hasCppWrapper ? wrapperName(metaClass) : metaClass->qualifiedCppName());
s << "* cptr = 0;" << endl;
-
- bool hasCodeInjectionsAtEnd = false;
- foreach(AbstractMetaFunction* func, overloads) {
- foreach (CodeSnip cs, func->injectedCodeSnips()) {
- if (cs.position == CodeSnip::End) {
- hasCodeInjectionsAtEnd = true;
- break;
- }
- }
- }
- if (hasCodeInjectionsAtEnd)
+ bool needsOverloadId = overloadData.maxArgs() > 0;
+ if (needsOverloadId)
s << INDENT << "int overloadId = -1;" << endl;
if (overloadData.hasAllowThread())
@@ -745,7 +738,10 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun
writeArgumentsInitializer(s, overloadData);
}
- writeOverloadedMethodDecisor(s, &overloadData);
+ if (needsOverloadId)
+ writeOverloadedFunctionDecisor(s, &overloadData);
+
+ writeFunctionCalls(s, overloadData);
s << endl;
s << INDENT << "if (PyErr_Occurred() || !Shiboken::setCppPointer(sbkSelf, Shiboken::SbkType<" << metaClass->qualifiedCppName() << " >(), cptr)) {" << endl;
@@ -781,6 +777,15 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun
// Constructor code injections, position=end
+ bool hasCodeInjectionsAtEnd = false;
+ foreach(AbstractMetaFunction* func, overloads) {
+ foreach (CodeSnip cs, func->injectedCodeSnips()) {
+ if (cs.position == CodeSnip::End) {
+ hasCodeInjectionsAtEnd = true;
+ break;
+ }
+ }
+ }
if (hasCodeInjectionsAtEnd) {
// FIXME: C++ arguments are not available in code injection on constructor when position = end.
s << INDENT << "switch(overloadId) {" << endl;
@@ -905,7 +910,17 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
s << ')' << endl << '{' << endl;
if (rfunc->implementingClass() &&
- (!rfunc->implementingClass()->isNamespace() && !rfunc->isStatic())) {
+ (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) {
+
+ s << INDENT;
+#ifdef AVOID_PROTECTED_HACK
+ QString _wrapperName = wrapperName(rfunc->ownerClass());
+ bool hasProtectedMembers = rfunc->ownerClass()->hasProtectedMembers();
+ s << (hasProtectedMembers ? _wrapperName : rfunc->ownerClass()->qualifiedCppName());
+#else
+ s << rfunc->ownerClass()->qualifiedCppName();
+#endif
+ s << "* " CPP_SELF_VAR " = 0;" << endl;
if (rfunc->isOperatorOverload() && rfunc->isBinaryOperator()) {
QString checkFunc = cpythonCheckFunction(rfunc->ownerClass()->typeEntry());
@@ -915,16 +930,25 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
s << INDENT << "std::swap(self, arg);\n\n";
}
+ // Sets the C++ "self" (the "this" for the object) if it has one.
+ QString cppSelfAttribution = CPP_SELF_VAR " = ";
+#ifdef AVOID_PROTECTED_HACK
+ cppSelfAttribution += (hasProtectedMembers ? QString("(%1*)").arg(_wrapperName) : "");
+#endif
+ cppSelfAttribution += cpythonWrapperCPtr(rfunc->ownerClass(), "self");
+
// Checks if the underlying C++ object is valid.
- if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
+ if (overloadData.hasStaticFunction()) {
s << INDENT << "if (self) {" << endl;
{
Indentation indent(INDENT);
writeInvalidCppObjectCheck(s);
+ s << INDENT << cppSelfAttribution << ';' << endl;
}
s << INDENT << '}' << endl;
} else {
writeInvalidCppObjectCheck(s);
+ s << INDENT << cppSelfAttribution << ';' << endl;
}
s << endl;
}
@@ -933,9 +957,13 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
if (hasReturnValue && !rfunc->isInplaceOperator())
s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+
+ bool needsOverloadId = overloadData.maxArgs() > 0;
+ if (needsOverloadId)
+ s << INDENT << "int overloadId = -1;" << endl;
+
if (overloadData.hasAllowThread())
s << INDENT << "Shiboken::ThreadStateSaver " THREAD_STATE_SAVER_VAR ";" << endl;
- s << endl;
if (minArgs != maxArgs || maxArgs > 1) {
s << INDENT << "int numArgs = ";
@@ -944,6 +972,7 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
else
writeArgumentsInitializer(s, overloadData);
}
+ s << endl;
/*
* Make sure reverse <</>> operators defined in other classes (specially from other modules)
@@ -991,7 +1020,11 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction
s << INDENT << "if (!" PYTHON_RETURN_VAR ") {" << endl << endl;
}
- writeOverloadedMethodDecisor(s, &overloadData);
+ if (needsOverloadId)
+ writeOverloadedFunctionDecisor(s, overloadData);
+
+ writeFunctionCalls(s, overloadData);
+ s << endl;
if (callExtendedReverseOperator)
s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl << endl;
@@ -1218,7 +1251,8 @@ void CppGenerator::writeTypeCheck(QTextStream& s, const OverloadData* overloadDa
void CppGenerator::writeArgumentConversion(QTextStream& s,
const AbstractMetaType* argType,
QString argName, QString pyArgName,
- const AbstractMetaClass* context)
+ const AbstractMetaClass* context,
+ QString defaultValue)
{
const TypeEntry* type = argType->typeEntry();
@@ -1245,25 +1279,47 @@ void CppGenerator::writeArgumentConversion(QTextStream& s,
bool hasImplicitConversions = !implicitConversions(argType).isEmpty();
if (isWrappedCppClass) {
- const TypeEntry* type = (hasImplicitConversions ? argType->typeEntry() : 0);
+ const TypeEntry* type = (hasImplicitConversions ? type : 0);
writeInvalidCppObjectCheck(s, pyArgName, type);
}
- if (hasImplicitConversions) {
- s << INDENT << "std::auto_ptr<" << baseTypeName << " > ";
- s << argName << "_auto_ptr;" << endl;
- }
+ // Auto pointer to dealloc new objects created because to satisfy implicit conversion.
+ if (hasImplicitConversions)
+ s << INDENT << "std::auto_ptr<" << baseTypeName << " > " << argName << "_auto_ptr;" << endl;
+
+ // Value type that has default value.
+ if (argType->isValue() && !defaultValue.isEmpty())
+ s << INDENT << baseTypeName << ' ' << argName << "_tmp = " << defaultValue << ';' << endl;
if (usePySideExtensions() && typeName == "QStringRef") {
- s << INDENT << "QString " << argName << "_qstring = Shiboken::Converter<QString>::toCpp(" << pyArgName << ");" << endl;
+ s << INDENT << "QString " << argName << "_qstring = ";
+ if (!defaultValue.isEmpty())
+ s << pyArgName << " ? ";
+ s << "Shiboken::Converter<QString>::toCpp(" << pyArgName << ')' << endl;
+ if (!defaultValue.isEmpty())
+ s << " : " << defaultValue;
+ s << ';' << endl;
s << INDENT << "QStringRef " << argName << "(&" << argName << "_qstring);" << endl;
} else {
s << INDENT << typeName << ' ' << argName << " = ";
- s << "Shiboken::Converter<" << typeName << " >::toCpp(" << pyArgName << ");" << endl;
+ if (!defaultValue.isEmpty())
+ s << pyArgName << " ? ";
+ s << "Shiboken::Converter<" << typeName << " >::toCpp(" << pyArgName << ')';
+ if (!defaultValue.isEmpty()) {
+ s << " : ";
+ if (argType->isValue())
+ s << '&' << argName << "_tmp";
+ else
+ s << defaultValue;
+ }
+ s << ';' << endl;
}
if (hasImplicitConversions) {
- s << INDENT << "if (!" << cpythonCheckFunction(argType->typeEntry()) << '(' << pyArgName << "))";
+ s << INDENT << "if (";
+ if (!defaultValue.isEmpty())
+ s << pyArgName << " && ";
+ s << '!' << cpythonCheckFunction(type) << '(' << pyArgName << "))";
s << endl;
Indentation indent(INDENT);
s << INDENT << argName << "_auto_ptr = std::auto_ptr<" << baseTypeName;
@@ -1279,7 +1335,21 @@ void CppGenerator::writeNoneReturn(QTextStream& s, const AbstractMetaFunction* f
}
}
-void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* parentOverloadData)
+void CppGenerator::writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData)
+{
+ s << INDENT << "// Overloaded function decisor" << endl;
+ QList<const AbstractMetaFunction*> functionOverloads = overloadData.overloadsWithoutRepetition();
+ for (int i = 0; i < functionOverloads.count(); i++)
+ s << INDENT << "// " << i << ": " << functionOverloads.at(i)->minimalSignature() << endl;
+ writeOverloadedFunctionDecisor(s, &overloadData);
+ s << endl;
+
+ s << INDENT << "// Function signature not found." << endl;
+ s << INDENT << "if (overloadId == -1) goto " << cpythonFunctionName(overloadData.referenceFunction()) << "_TypeError;" << endl;
+ s << endl;
+}
+
+void CppGenerator::writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData* parentOverloadData)
{
bool hasDefaultCall = parentOverloadData->nextArgumentHasDefaultValue();
const AbstractMetaFunction* referenceFunction = parentOverloadData->referenceFunction();
@@ -1287,7 +1357,7 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
// If the next argument has not an argument with a default value, it is still possible
// that one of the overloads for the current overload data has its final occurrence here.
// If found, the final occurrence of a method is attributed to the referenceFunction
- // variable to be used further on this method on the conditional that writes default
+ // variable to be used further on this method on the conditional that identifies default
// method calls.
if (!hasDefaultCall) {
foreach (const AbstractMetaFunction* func, parentOverloadData->overloads()) {
@@ -1303,9 +1373,10 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
// Python constructors always receive multiple arguments.
bool manyArgs = maxArgs > 1 || referenceFunction->isConstructor();
- // Functions without arguments are written right away.
+ // Functions without arguments are identified right away.
if (maxArgs == 0) {
- writeMethodCall(s, referenceFunction);
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(referenceFunction);
+ s << "; // " << referenceFunction->minimalSignature() << endl;
return;
// To decide if a method call is possible at this point the current overload
@@ -1316,25 +1387,24 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
bool signatureFound = parentOverloadData->overloads().size() == 1;
// The current overload data describes the last argument of a signature,
- // so the method can be called right now.
+ // so the method can be identified right now.
if (isLastArgument || (signatureFound && !hasDefaultCall)) {
const AbstractMetaFunction* func = parentOverloadData->referenceFunction();
- int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
- writeMethodCall(s, func, func->arguments().size() - numRemovedArgs);
- if (!func->isConstructor())
- writeNoneReturn(s, func, parentOverloadData->headOverloadData()->hasNonVoidReturnType());
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
return;
}
}
- s << INDENT;
+ bool isFirst = true;
// If the next argument has a default value the decisor can perform a method call;
// it just need to check if the number of arguments received from Python are equal
// to the number of parameters preceding the argument with the default value.
if (hasDefaultCall) {
+ isFirst = false;
int numArgs = parentOverloadData->argPos() + 1;
- s << "if (numArgs == " << numArgs << ") {" << endl;
+ s << INDENT << "if (numArgs == " << numArgs << ") {" << endl;
{
Indentation indent(INDENT);
const AbstractMetaFunction* func = referenceFunction;
@@ -1345,11 +1415,10 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
break;
}
}
- writeMethodCall(s, func, numArgs);
- if (!func->isConstructor())
- writeNoneReturn(s, func, parentOverloadData->headOverloadData()->hasNonVoidReturnType());
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
}
- s << INDENT << "} else ";
+ s << INDENT << '}';
}
foreach (OverloadData* overloadData, parentOverloadData->nextOverloadData()) {
@@ -1359,6 +1428,13 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
const AbstractMetaFunction* refFunc = overloadData->referenceFunction();
+ if (isFirst) {
+ isFirst = false;
+ s << INDENT;
+ } else {
+ s << " else ";
+ }
+
s << "if (";
if (manyArgs && signatureFound) {
AbstractMetaArgumentList args = refFunc->arguments();
@@ -1384,22 +1460,6 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
writeTypeCheck(tck, od, pyArgName);
- const AbstractMetaType* argType = 0;
- if (od->argumentTypeReplaced().isEmpty())
- argType = od->argType();
- else
- argType = buildAbstractMetaTypeFromString(od->argumentTypeReplaced());
-
- Indentation indent(INDENT);
- if (argType) {
- writeArgumentConversion(tcv, argType,
- QString("cpp_arg%1").arg(od->argPos()),
- pyArgName,
- refFunc->implementingClass());
- if (argType != od->argType())
- delete argType;
- }
-
if (od->nextOverloadData().isEmpty()
|| od->nextArgumentHasDefaultValue()
|| od->nextOverloadData().size() != 1
@@ -1418,14 +1478,84 @@ void CppGenerator::writeOverloadedMethodDecisor(QTextStream& s, OverloadData* pa
{
Indentation indent(INDENT);
- writeOverloadedMethodDecisor(s, overloadData);
+ writeOverloadedFunctionDecisor(s, overloadData);
}
- s << INDENT << "} else ";
+ s << INDENT << "}";
}
+ s << endl;
+}
- if (maxArgs > 0)
- s << "goto " << cpythonFunctionName(referenceFunction) << "_TypeError;" << endl;
+void CppGenerator::writeFunctionCalls(QTextStream& s, const OverloadData& overloadData)
+{
+ QList<const AbstractMetaFunction*> overloads = overloadData.overloadsWithoutRepetition();
+
+ s << INDENT << "// Call function/method" << endl;
+ s << INDENT << (overloads.count() > 1 ? "switch (overloadId) " : "") << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ if (overloads.count() == 1) {
+ writeSingleFunctionCall(s, overloadData, overloads.first());
+ } else {
+ for (int i = 0; i < overloads.count(); i++) {
+ const AbstractMetaFunction* func = overloads.at(i);
+ s << INDENT << "case " << i << ": // " << func->minimalSignature() << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ writeSingleFunctionCall(s, overloadData, func);
+ s << INDENT << "break;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ }
+ }
+ s << INDENT << '}' << endl;
+}
+
+void CppGenerator::writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func)
+{
+ const AbstractMetaClass* implementingClass = overloadData.referenceFunction()->implementingClass();
+ bool multipleArguments = overloadData.maxArgs() > 1 || overloadData.referenceFunction()->isConstructor();
+
+ int removedArgs = 0;
+ for (int i = 0; i < func->arguments().count(); i++) {
+ if (func->argumentRemoved(i + 1)) {
+ removedArgs++;
+ continue;
+ }
+
+ if (!func->conversionRule(TypeSystem::NativeCode, i + 1).isEmpty())
+ continue;
+
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+ const AbstractMetaType* argType = 0;
+ if (typeReplaced.isEmpty())
+ argType = arg->type();
+ else
+ argType = buildAbstractMetaTypeFromString(typeReplaced);
+
+ if (argType) {
+ QString argName = QString("cpp_arg%1").arg(i - removedArgs);
+ QString pyArgName = multipleArguments ? QString("pyargs[%1]").arg(i - removedArgs) : "arg";
+ QString defaultValue = guessScopeForDefaultValue(func, arg);
+
+ writeArgumentConversion(s, argType, argName, pyArgName, implementingClass, defaultValue);
+
+ // Free a custom type created by buildAbstractMetaTypeFromString.
+ if (argType != arg->type())
+ delete argType;
+ }
+ }
+
+ s << endl;
+
+ int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
+ writeMethodCall(s, func, func->arguments().size() - numRemovedArgs);
+ if (!func->isConstructor())
+ writeNoneReturn(s, func, overloadData.hasNonVoidReturnType());
}
QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass)
@@ -1477,8 +1607,6 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
s << INDENT << "}\n";
}
- writeCppSelfDefinition(s, func);
-
// Used to provide contextual information to custom code writer function.
const AbstractMetaArgument* lastArg = 0;
@@ -1531,7 +1659,7 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
if (arg->defaultValueExpression().isEmpty())
badModifications = true;
else
- userArgs << arg->defaultValueExpression();
+ userArgs << guessScopeForDefaultValue(func, arg);
}
} else {
int idx = arg->argumentIndex() - removedArgs;
@@ -1568,7 +1696,7 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
otherArgsModified |= defValModified || hasConversionRule || func->argumentRemoved(i + 1);
if (!arg->defaultValueExpression().isEmpty())
- otherArgs.prepend(arg->defaultValueExpression());
+ otherArgs.prepend(guessScopeForDefaultValue(func, arg));
else if (hasConversionRule)
otherArgs.prepend(arg->argumentName() + "_out");
else
@@ -3286,14 +3414,12 @@ bool CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMeta
void CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool useHeuristicForReturn)
{
const int numArgs = func->arguments().count();
- s << INDENT << "//CppGenerator::writeParentChildManagement" << endl;
// -1 = return value
// 0 = self
// 1..n = func. args.
- for (int i = -1; i <= numArgs; ++i) {
+ for (int i = -1; i <= numArgs; ++i)
writeParentChildManagement(s, func, i, i == 0 ? useHeuristicForReturn : true);
- }
}
void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self)
diff --git a/cppgenerator.h b/cppgenerator.h
index c6ba546ba..eee5e2e9d 100644
--- a/cppgenerator.h
+++ b/cppgenerator.h
@@ -76,20 +76,22 @@ private:
* code to deallocate a possible new instance is also generated.
* \param s text stream to write
* \param metatype a pointer to the argument type to be converted
- * \param context the current meta class
* \param argName C++ argument name
- * \param argName Python argument name
+ * \param pyArgName Python argument name
+ * \param context the current meta class
+ * \param defaultValue an optional default value to be used instead of the conversion result
*/
void writeArgumentConversion(QTextStream& s, const AbstractMetaType* argType,
QString argName, QString pyArgName,
- const AbstractMetaClass* context = 0);
- /// Convenience method to call writeArgumentConversion with an AbstractMetaArgument
- /// instead of an AbstractMetaType.
+ const AbstractMetaClass* context = 0,
+ QString defaultValue = QString());
+ /// Convenience method to call writeArgumentConversion with an AbstractMetaArgument instead of an AbstractMetaType.
void writeArgumentConversion(QTextStream& s, const AbstractMetaArgument* arg,
QString argName, QString pyArgName,
- const AbstractMetaClass* context = 0)
+ const AbstractMetaClass* context = 0,
+ QString defaultValue = QString())
{
- writeArgumentConversion(s, arg->type(), argName, pyArgName, context);
+ writeArgumentConversion(s, arg->type(), argName, pyArgName, context, defaultValue);
}
/**
@@ -104,12 +106,21 @@ private:
void writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue);
/**
- * Writes the Python method wrapper overload decisor that selects which C++
+ * Writes the Python function wrapper overload decisor that selects which C++
* method/function to call with the received Python arguments.
* \param s text stream to write
- * \param parentOverloadData a pointer to overload data describing the argument being evaluated
+ * \param overloadData the overload data describing all the possible overloads for the function/method
*/
- void writeOverloadedMethodDecisor(QTextStream& s, OverloadData* parentOverloadData);
+ void writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData);
+ /// Recursive auxiliar method to the other writeOverloadedFunctionDecisor.
+ void writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData* parentOverloadData);
+
+ /// Writes calls to all the possible method/function overloads.
+ void writeFunctionCalls(QTextStream& s, const OverloadData& overloadData);
+
+ /// Writes the call to a single function usually from a collection of overloads.
+ void writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func = 0);
+
/// Returns a string containing the name of an argument for the given function and argument index.
QString argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass);
void writeMethodCall(QTextStream& s, const AbstractMetaFunction* func, int maxArgs = 0);