summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generator/cppgenerator.cpp847
-rw-r--r--generator/cppgenerator.h53
-rw-r--r--generator/headergenerator.cpp83
-rw-r--r--generator/shibokengenerator.cpp405
-rw-r--r--generator/shibokengenerator.h31
-rw-r--r--libshiboken/CMakeLists.txt2
-rw-r--r--libshiboken/basewrapper.cpp42
-rw-r--r--libshiboken/basewrapper.h21
-rw-r--r--libshiboken/basewrapper_p.h6
-rw-r--r--libshiboken/sbkconverter.cpp214
-rw-r--r--libshiboken/sbkconverter.h205
-rw-r--r--libshiboken/sbkconverter_p.h90
-rw-r--r--libshiboken/shiboken.h1
-rw-r--r--tests/samplebinding/injectcode_test.py13
-rw-r--r--tests/samplebinding/typesystem_sample.xml63
15 files changed, 1728 insertions, 348 deletions
diff --git a/generator/cppgenerator.cpp b/generator/cppgenerator.cpp
index 7142abc7..ec376d5f 100644
--- a/generator/cppgenerator.cpp
+++ b/generator/cppgenerator.cpp
@@ -526,6 +526,7 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl
}
s << endl;
+ writeConverterFunctions(s, metaClass);
writeClassRegister(s, metaClass);
// class inject-code native/end
@@ -796,23 +797,44 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << INDENT << "bool invalidateArg0 = " PYTHON_RETURN_VAR "->ob_refcnt == 1;" << endl;
if (func->type() && func->typeReplaced(0) != "PyObject") {
- s << INDENT << "// Check return type" << endl;
- s << INDENT << "bool typeIsValid = ";
- writeTypeCheck(s, func->type(), PYTHON_RETURN_VAR, isNumber(func->type()->typeEntry()), func->typeReplaced(0));
- s << ';' << endl;
- s << INDENT << "if (!typeIsValid";
- s << (isPointerToWrapperType(func->type()) ? " && " PYTHON_RETURN_VAR " != Py_None" : "");
- s << ") {" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
- "\"Invalid return value in function %s, expected %s, got %s.\", \"";
- s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
- s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl;
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
- }
- s << INDENT << '}' << endl;
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(func->type())) {
+ s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR " = " << cpythonIsConvertibleFunction(func->type());
+ s << PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "if (!" PYTHON_TO_CPP_VAR ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
+ "\"Invalid return value in function %s, expected %s, got %s.\", \"";
+ s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
+ s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl;
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ } else { // TODO-CONVERTER --------------------------------------------------------------
+
+ s << INDENT << "// Check return type" << endl;
+ s << INDENT << "bool typeIsValid = ";
+ writeTypeCheck(s, func->type(), PYTHON_RETURN_VAR,
+ isNumber(func->type()->typeEntry()), func->typeReplaced(0));
+ s << ';' << endl;
+
+ s << INDENT << "if (!typeIsValid";
+ s << (isPointerToWrapperType(func->type()) ? " && " PYTHON_RETURN_VAR " != Py_None" : "");
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
+ "\"Invalid return value in function %s, expected %s, got %s.\", \"";
+ s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
+ s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl;
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ } // TODO-CONVERTER ---------------------------------------------------------------------
}
if (!func->conversionRule(TypeSystem::NativeCode, 0).isEmpty()) {
@@ -866,6 +888,12 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << '(' << typeCast << ')';
}
}
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+ if (func->type()->isReference() && !isPointer(func->type()))
+ s << '*';
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
s << CPP_RETURN_VAR ";" << endl;
}
@@ -925,6 +953,231 @@ void CppGenerator::writeMetaCast(QTextStream& s, const AbstractMetaClass* metaCl
s << "}" << endl << endl;
}
+void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ if (metaClass->isNamespace())
+ return;
+ s << "// Type conversion functions." << endl << endl;
+
+ QString typeName = getFullTypeName(metaClass);
+ QString cpythonType = cpythonTypeName(metaClass);
+
+ // Returns the C++ pointer of the Python wrapper.
+ s << "// Python to C++ pointer conversion - returns the C++ object of the Python wrapper (keeps object identity)." << endl;
+
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = QString("%1_PTR").arg(metaClass->name());
+ QString code;
+ QTextStream c(&code);
+ c << INDENT << "Shiboken::Conversions::pythonToCppPointer(&" << cpythonType << ", pyIn, cppOut);";
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // "Is convertible" function for the Python object to C++ pointer conversion.
+ QString pyTypeCheck = QString("PyObject_TypeCheck(pyIn, (PyTypeObject*)&%1)").arg(cpythonType);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true);
+ s << endl;
+
+ // C++ pointer to a Python wrapper, keeping identity.
+ s << "// C++ to Python pointer conversion - tries to find the Python wrapper for the C++ object (keeps object identity)." << endl;
+ code.clear();
+ c << INDENT << "PyObject* pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(cppIn);" << endl;
+ c << INDENT << "if (pyOut) {" << endl;
+ {
+ Indentation indent(INDENT);
+ c << INDENT << "Py_INCREF(pyOut);" << endl;
+ c << INDENT << "return pyOut;" << endl;
+ }
+ c << INDENT << '}' << endl;
+ c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl;
+ c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType;
+ c << ", const_cast<void*>(cppIn), false, false, typeName);";
+ std::swap(targetTypeName, sourceTypeName);
+ writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName);
+
+ // The conversions for an Object Type end here.
+ if (!metaClass->typeEntry()->isValue()) {
+ s << endl;
+ return;
+ }
+
+ // Always copies C++ value (not pointer, and not reference) to a new Python wrapper.
+ s << endl << "// C++ to Python copy conversion." << endl;
+ sourceTypeName = QString("%1_COPY").arg(metaClass->name());
+ targetTypeName = metaClass->name();
+ code.clear();
+ c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << wrapperName(metaClass);
+ c << "(*((" << typeName << "*)cppIn)), true, true);";
+ writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName);
+ s << endl;
+
+ // Python to C++ copy conversion.
+ s << "// Python to C++ copy conversion." << endl;
+ sourceTypeName = metaClass->name();
+ targetTypeName = QString("%1_COPY").arg(sourceTypeName);
+ code.clear();
+ c << INDENT << "*((" << typeName << "*)cppOut) = *" << cpythonWrapperCPtr(metaClass->typeEntry(), "pyIn") << ';';
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // "Is convertible" function for the Python object to C++ value copy conversion.
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck);
+ s << endl;
+
+ // User provided implicit conversions.
+ CustomConversion* customConversion = metaClass->typeEntry()->customConversion();
+
+ // Implicit conversions.
+ AbstractMetaFunctionList implicitConvs;
+ if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
+ foreach (AbstractMetaFunction* func, implicitConversions(metaClass->typeEntry())) {
+ if (!func->isUserAdded())
+ implicitConvs << func;
+ }
+ }
+
+ if (!implicitConvs.isEmpty())
+ s << "// Implicit conversions." << endl;
+
+ AbstractMetaType* targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
+ foreach (const AbstractMetaFunction* conv, implicitConvs) {
+ if (conv->isModifiedRemoved())
+ continue;
+
+ QString typeCheck;
+ QString toCppConv;
+ if (conv->isConversionOperator()) {
+ const AbstractMetaClass* sourceClass = conv->ownerClass();
+ typeCheck = QString("PyObject_TypeCheck(pyIn, %1)").arg(cpythonTypeNameExt(sourceClass->typeEntry()));
+ toCppConv = QString("*%1").arg(cpythonWrapperCPtr(sourceClass->typeEntry(), "pyIn"));
+
+ } else {
+ // Constructor that does implicit conversion.
+ if (!conv->typeReplaced(1).isEmpty())
+ continue;
+ const AbstractMetaType* sourceType = conv->arguments().first()->type();
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(sourceType))
+ typeCheck = QString("%1pyIn)").arg(cpythonCheckFunction(sourceType));
+ else
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ typeCheck = QString("%1(pyIn)").arg(cpythonCheckFunction(sourceType));
+ if (isWrapperType(sourceType)) {
+ toCppConv = QString("%1%2")
+ .arg((sourceType->isReference() || !isPointerToWrapperType(sourceType)) ? "*" : "")
+ .arg(cpythonWrapperCPtr(sourceType->typeEntry(), "pyIn"));
+ } else {
+ QTextStream tcc(&toCppConv);
+ writeToCppConversion(tcc, sourceType, metaClass, "pyIn", "/*BOZO-1043*/");
+ }
+ }
+ const AbstractMetaType* sourceType = conv->isConversionOperator()
+ ? buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass())
+ : conv->arguments().first()->type();
+ writePythonToCppConversionFunctions(s, sourceType, targetType, typeCheck, toCppConv);
+ }
+
+ writeCustomConverterFunctions(s, customConversion);
+}
+
+void CppGenerator::writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion)
+{
+ if (!customConversion)
+ return;
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+ s << "// Python to C++ conversions for type '" << customConversion->ownerType()->qualifiedCppName() << "'." << endl;
+ foreach (CustomConversion::TargetToNativeConversion* toNative, toCppConversions)
+ writePythonToCppConversionFunctions(s, toNative, customConversion->ownerType());
+ s << endl;
+}
+
+void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ if (metaClass->isNamespace())
+ return;
+ s << INDENT << "// Register Converter" << endl;
+ s << INDENT;
+ if (!isObjectType(metaClass))
+ s << "SbkConverter* converter = ";
+ s << "Shiboken::Conversions::createConverter(&" << cpythonTypeName(metaClass) << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = QString("%1_PTR").arg(metaClass->name());
+ s << INDENT << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl;
+ s << INDENT << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl;
+ std::swap(targetTypeName, sourceTypeName);
+ s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ if (metaClass->typeEntry()->isValue()) {
+ s << ',' << endl;
+ sourceTypeName = QString("%1_COPY").arg(metaClass->name());
+ s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ }
+ }
+ s << ");" << endl;
+
+ if (!metaClass->typeEntry()->isValue())
+ return;
+
+ // Python to C++ copy (value, not pointer neither reference) conversion.
+ s << INDENT << "// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter." << endl;
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = QString("%1_COPY").arg(metaClass->name());
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ writeAddPythonToCppConversion(s, "converter", toCpp, isConv);
+
+ // User provided implicit conversions.
+ CustomConversion* customConversion = metaClass->typeEntry()->customConversion();
+
+ // Add implicit conversions.
+ AbstractMetaFunctionList implicitConvs;
+ if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
+ foreach (AbstractMetaFunction* func, implicitConversions(metaClass->typeEntry())) {
+ if (!func->isUserAdded())
+ implicitConvs << func;
+ }
+ }
+
+ if (!implicitConvs.isEmpty())
+ s << INDENT << "// Add implicit conversions to type converter." << endl;
+
+ AbstractMetaType* targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
+ foreach (const AbstractMetaFunction* conv, implicitConvs) {
+ if (conv->isModifiedRemoved())
+ continue;
+ const AbstractMetaType* sourceType;
+ if (conv->isConversionOperator()) {
+ sourceType = buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass());
+ } else {
+ // Constructor that does implicit conversion.
+ if (!conv->typeReplaced(1).isEmpty())
+ continue;
+ sourceType = conv->arguments().first()->type();
+ }
+ QString toCpp = pythonToCppFunctionName(sourceType, targetType);
+ QString isConv = convertibleToCppFunctionName(sourceType, targetType);
+ writeAddPythonToCppConversion(s, "converter", toCpp, isConv);
+ }
+
+ writeCustomConverterRegister(s, customConversion, "converter");
+}
+
+void CppGenerator::writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar)
+{
+ if (!customConversion)
+ return;
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+ s << INDENT << "// Add user defined implicit conversions to type converter." << endl;
+ foreach (CustomConversion::TargetToNativeConversion* toNative, toCppConversions) {
+ QString toCpp = pythonToCppFunctionName(toNative, customConversion->ownerType());
+ QString isConv = convertibleToCppFunctionName(toNative, customConversion->ownerType());
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+ }
+}
+
void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& overloadData)
{
const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
@@ -938,7 +1191,8 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& over
if (rfunc->isConstructor()) {
// Check if the right constructor was called.
if (!ownerClass->hasPrivateDestructor()) {
- s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ") && !Shiboken::ObjectType::canCallConstructor(" PYTHON_SELF_VAR "->ob_type, Shiboken::SbkType< ::";
+ s << INDENT;
+ s << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ") && !Shiboken::ObjectType::canCallConstructor(" PYTHON_SELF_VAR "->ob_type, Shiboken::SbkType< ::";
s << ownerClass->qualifiedCppName() << " >()))" << endl;
Indentation indent(INDENT);
s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
@@ -963,14 +1217,24 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& over
usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue();
}
- if (maxArgs > 0)
+ if (maxArgs > 0) {
s << INDENT << "int overloadId = -1;" << endl;
+ s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR;
+ if (pythonFunctionWrapperUsesListOfArguments(overloadData))
+ s << "[] = { 0" << QString(", 0").repeated(maxArgs-1) << " }";
+ s << ';' << endl;
+ // TODO-CONVERTER: remove this later.
+ // Make a check that ask something like: "there's no conversions in the overloads?".
+ writeUnusedVariableCast(s, PYTHON_TO_CPP_VAR);
+ // TODO-CONVERTER: RANDOM THOUGHT: I gave that decisor some overloads. Decisors love overloads.
+ }
if (usesNamedArguments && !rfunc->isCallOperator())
s << INDENT << "int numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);" << endl;
if (initPythonArguments) {
s << INDENT << "int numArgs = ";
+ // TODO-CONVERTER: review rfunc->isConstructor()
if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData))
s << "(" PYTHON_ARG " == 0 ? 0 : 1);" << endl;
else
@@ -1368,13 +1632,13 @@ void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunc
if (func->isOperatorOverload() && func->isBinaryOperator()) {
QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry());
- s << INDENT << "bool isReverse = " << checkFunc << "(" PYTHON_ARG ")" << endl;
+ s << INDENT << "bool isReverse = " << checkFunc << /*TODO-CONVERTER "("*/ PYTHON_ARG ")" << endl;
{
Indentation indent1(INDENT);
Indentation indent2(INDENT);
Indentation indent3(INDENT);
Indentation indent4(INDENT);
- s << INDENT << "&& !" << checkFunc << "(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "&& !" << checkFunc << /*TODO-CONVERTER "("*/ PYTHON_SELF_VAR ");" << endl;
}
s << INDENT << "if (isReverse)" << endl;
Indentation indent(INDENT);
@@ -1489,6 +1753,13 @@ void CppGenerator::writeInvalidPyObjectCheck(QTextStream& s, const QString& pyOb
s << INDENT << "return " << m_currentErrorCode << ';' << endl;
}
+static QString pythonToCppConverterForArgumentName(const QString& argumentName)
+{
+ static QRegExp pyArgsRegex(PYTHON_ARGS"(\\[\\d+[-]?\\d*\\])");
+ pyArgsRegex.indexIn(argumentName);
+ return QString(PYTHON_TO_CPP_VAR"%1").arg(pyArgsRegex.cap(1));
+}
+
void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber, QString customType, bool rejectNull)
{
QString customCheck;
@@ -1506,6 +1777,12 @@ void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argTyp
typeCheck = customCheck;
typeCheck.append(QString("(%1)").arg(argumentName));
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (customCheck.isEmpty() && isWrapperType(argType)) {
+ typeCheck = QString("(%1 = %2))").arg(pythonToCppConverterForArgumentName(argumentName)).arg(typeCheck);
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
if (rejectNull)
typeCheck = QString("(%1 != Py_None && %2)").arg(argumentName).arg(typeCheck);
@@ -1581,25 +1858,82 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s,
const AbstractMetaClass* context,
const QString& defaultValue)
{
+ // TODO-CONVERTER - is this needed here? If so, at least raise a generator warning.
if (type->typeEntry()->isCustom() || type->typeEntry()->isVarargs())
return;
+ QString cppOutAux = QString("%1_local").arg(cppOut);
+
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+
+ bool treatAsPointer = isValueTypeWithCopyConstructorOnly(type);
+ bool isPointerOrObjectType = isObjectType(type) || isPointer(type);
+ bool mayHaveImplicitConversion = type->isReference() && !(treatAsPointer || isPointerOrObjectType);
+ QString typeName = getFullTypeNameWithoutModifiers(type);
+ if (mayHaveImplicitConversion) {
+ s << INDENT << typeName << ' ' << cppOutAux << " = ";
+ writeMinimalConstructorExpression(s, type, defaultValue);
+ s << ';' << endl;
+ }
+
+ s << INDENT << typeName;
+ if (treatAsPointer || isPointerOrObjectType) {
+ s << "* " << cppOut << (defaultValue.isEmpty() ? "" : QString(" = %1").arg(defaultValue));
+ } else if (type->isReference()) {
+ s << "* " << cppOut << " = &" << cppOutAux;
+ } else {
+ s << ' ' << cppOut << " = ";
+ writeMinimalConstructorExpression(s, type, defaultValue);
+ }
+ s << ';' << endl;
+
+ QString pythonToCppFunc = pythonToCppConverterForArgumentName(pyIn);
+
+ s << INDENT;
+ if (!defaultValue.isEmpty())
+ s << "if (" << pythonToCppFunc << ") ";
+
+ QString pythonToCppCall = QString("%1(%2, &%3)").arg(pythonToCppFunc).arg(pyIn).arg(cppOut);
+ if (!mayHaveImplicitConversion) {
+ s << pythonToCppCall << ';' << endl;
+ return;
+ }
+
+ if (!defaultValue.isEmpty())
+ s << '{' << endl << INDENT;
+
+ s << "if (Shiboken::Conversions::isImplicitConversion((SbkObjectType*)";
+ s << cpythonTypeNameExt(type) << ", " << pythonToCppFunc << "))" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pythonToCppFunc << '(' << pyIn << ", &" << cppOutAux << ");" << endl;
+ }
+ s << INDENT << "else" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pythonToCppCall << ';' << endl;
+ }
+
+ if (!defaultValue.isEmpty())
+ s << INDENT << '}';
+ s << endl;
+ return;
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
QString conversion;
QTextStream c(&conversion);
- writeToCppConversion(c, type, context, pyIn);
- QString typeName;
- QString cppOutAux = QString("%1_tmp").arg(cppOut);
+ writeToCppConversion(c, type, context, pyIn, "/*BOZO-1906*/");
// Value type that has default value.
if (type->isValue() && !defaultValue.isEmpty())
s << INDENT << type->typeEntry()->name() << ' ' << cppOutAux << " = " << defaultValue << ';' << endl;
- if (typeName.isEmpty()) {
- // exclude const on Objects
- Options flags = getConverterOptions(type);
- typeName = translateTypeForWrapperMethod(type, context, flags).trimmed();
- }
+ // exclude const on Objects
+ Options flags = getConverterOptions(type);
+ QString typeName = translateTypeForWrapperMethod(type, context, flags).trimmed();
if (!defaultValue.isEmpty()) {
conversion.prepend(QString("%1 ? ").arg(pyIn));
@@ -1868,7 +2202,6 @@ void CppGenerator::writeSingleFunctionCall(QTextStream& s, const OverloadData& o
return;
}
- const AbstractMetaClass* implementingClass = overloadData.referenceFunction()->implementingClass();
bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
// Handle named arguments.
@@ -1905,72 +2238,230 @@ void CppGenerator::writeSingleFunctionCall(QTextStream& s, const OverloadData& o
QString argName = QString(CPP_ARG"%1").arg(argPos);
QString pyArgName = usePyArgs ? QString(PYTHON_ARGS "[%1]").arg(argPos) : PYTHON_ARG;
QString defaultValue = guessScopeForDefaultValue(func, arg);
- writeArgumentConversion(s, argType, argName, pyArgName, implementingClass, defaultValue, func->isUserAdded());
+ writeArgumentConversion(s, argType, argName, pyArgName, func->implementingClass(), defaultValue, func->isUserAdded());
}
s << endl;
int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
- s << INDENT << "if(!PyErr_Occurred()) {" << endl;
+ s << INDENT << "if (!PyErr_Occurred()) {" << endl;
{
Indentation indentation(INDENT);
writeMethodCall(s, func, func->arguments().size() - numRemovedArgs);
if (!func->isConstructor())
writeNoneReturn(s, func, overloadData.hasNonVoidReturnType());
}
- s << INDENT << "}" << endl;
+ s << INDENT << '}' << endl;
+}
+
+QString CppGenerator::cppToPythonFunctionName(const QString& sourceTypeName, QString targetTypeName)
+{
+ if (targetTypeName.isEmpty())
+ targetTypeName = sourceTypeName;
+ return QString("%1_CppToPython_%2").arg(sourceTypeName).arg(targetTypeName);
+}
+
+QString CppGenerator::pythonToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName)
+{
+ return QString("%1_PythonToCpp_%2").arg(sourceTypeName).arg(targetTypeName);
+}
+QString CppGenerator::pythonToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType)
+{
+ return pythonToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
+}
+QString CppGenerator::pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType)
+{
+ return pythonToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
+}
+
+QString CppGenerator::convertibleToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName)
+{
+ return QString("is_%1_PythonToCpp_%2_Convertible").arg(sourceTypeName).arg(targetTypeName);
+}
+QString CppGenerator::convertibleToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType)
+{
+ return convertibleToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
+}
+QString CppGenerator::convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType)
+{
+ return convertibleToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
+}
+
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, QString targetTypeName)
+{
+ QString prettyCode;
+ QTextStream c(&prettyCode);
+ formatCode(c, code, INDENT);
+
+ s << "static PyObject* " << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ s << "(const void* cppIn) {" << endl;
+ s << prettyCode;
+ s << '}' << endl;
+}
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion)
+{
+ QString code = customConversion->nativeToTargetConversion();
+ code.prepend(QString("::%1& cppInRef = *((::%1*)cppIn);\n").arg(customConversion->ownerType()->qualifiedCppName()));
+ code.replace("%INTYPE", cpythonTypeNameExt(customConversion->ownerType()));
+ code.replace("%OUTTYPE", "PyObject*");
+ code.replace("%in", "cppInRef");
+ code.replace("%out", "pyOut");
+ writeCppToPythonFunction(s, code, fixedCppTypeName(customConversion->ownerType()));
+}
+
+void CppGenerator::writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName)
+{
+ QString prettyCode;
+ QTextStream c(&prettyCode);
+ formatCode(c, code, INDENT);
+ s << "static void " << pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ s << "(PyObject* pyIn, void* cppOut) {" << endl;
+ s << prettyCode;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeIsPythonConvertibleToCppFunction(QTextStream& s,
+ const QString& sourceTypeName,
+ const QString& targetTypeName,
+ const QString& condition,
+ QString pythonToCppFuncName,
+ bool acceptNoneAsCppNull)
+{
+ if (pythonToCppFuncName.isEmpty())
+ pythonToCppFuncName = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+
+ s << "static PythonToCppFunc " << convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ s << "(PyObject* pyIn) {" << endl;
+ if (acceptNoneAsCppNull) {
+ s << INDENT << "if (pyIn == Py_None)" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return Shiboken::Conversions::nonePythonToCppNullPtr;" << endl;
+ }
+ s << INDENT << "if (" << condition << ')' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << pythonToCppFuncName << ';' << endl;
+ }
+ s << INDENT << "return 0;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
+ const AbstractMetaType* sourceType,
+ const AbstractMetaType* targetType,
+ QString typeCheck,
+ QString conversion)
+{
+ QString sourcePyType = cpythonTypeNameExt(sourceType);
+
+ // Python to C++ conversion function.
+ QString code;
+ QTextStream c(&code);
+ if (conversion.isEmpty())
+ conversion = QString("*%1").arg(cpythonWrapperCPtr(sourceType->typeEntry(), "pyIn"));
+ c << INDENT << QString("*((::%1*)cppOut) = ::%1(%2);")
+ .arg(targetType->typeEntry()->qualifiedCppName())
+ .arg(conversion);
+ QString sourceTypeName = fixedCppTypeName(sourceType);
+ QString targetTypeName = fixedCppTypeName(targetType);
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // Python to C++ convertible check function.
+ if (typeCheck.isEmpty())
+ typeCheck = QString("PyObject_TypeCheck(pyIn, %1)").arg(sourcePyType);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
+ s << endl;
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
+ const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType)
+{
+ // Python to C++ conversion function.
+ QString code = toNative->conversion();
+ QString inType;
+ if (toNative->sourceType())
+ inType = cpythonTypeNameExt(toNative->sourceType());
+ else
+ inType = QString("(&%1_Type)").arg(toNative->sourceTypeName());
+ code.replace("%INTYPE", inType);
+ code.replace("%OUTTYPE", targetType->qualifiedCppName());
+ code.replace("%in", "pyIn");
+ code.replace("%out", QString("*((::%1*)cppOut)").arg(targetType->qualifiedCppName()));
+
+ QString sourceTypeName = fixedCppTypeName(toNative);
+ QString targetTypeName = fixedCppTypeName(targetType);
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // Python to C++ convertible check function.
+ QString typeCheck = toNative->sourceTypeCheck();
+ if (typeCheck.isEmpty()) {
+ if (!toNative->sourceType() || toNative->sourceType()->isPrimitive()) {
+ QString errorMsg = "User added implicit conversions must provide either a input type check function or a non primitive type entry.";
+ ReportHandler::warning(errorMsg);
+ s << "#error " << errorMsg << endl;
+ }
+ typeCheck = QString("PyObject_TypeCheck(%in, %1)").arg(cpythonTypeNameExt(toNative->sourceType()));
+ }
+ typeCheck.replace("%in", "pyIn");
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
+}
+
+void CppGenerator::writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc)
+{
+ s << INDENT << "Shiboken::Conversions::addPythonToCppValueConversion(" << converterVar << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pythonToCppFunc << ',' << endl;
+ s << INDENT << isConvertibleFunc;
+ }
+ s << ");" << endl;
}
void CppGenerator::writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs)
{
AbstractMetaArgumentList args = OverloadData::getArgumentsWithDefaultValues(func);
- if (!args.isEmpty()) {
- s << INDENT << "if (kwds) {" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << "const char* errorArgName = 0;" << endl;
- s << INDENT << "PyObject* ";
- foreach (const AbstractMetaArgument* arg, args) {
- int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
- QString pyArgName = usePyArgs ? QString(PYTHON_ARGS "[%1]").arg(pyArgIndex) : PYTHON_ARG;
- s << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
- s << INDENT << "if (value) {" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << "if (" << pyArgName << ")" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << "errorArgName = \"" << arg->name() << "\";" << endl;
- }
- s << INDENT << "else if (";
- writeTypeCheck(s, arg->type(), "value", isNumber(arg->type()->typeEntry()));
- s << ')' << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << pyArgName << " = value;" << endl;
- }
- s << INDENT << "else" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;" << endl;
- }
- }
- s << INDENT << '}' << endl;
- s << INDENT;
- }
- s << "if (errorArgName) {" << endl;
+ if (args.isEmpty())
+ return;
+
+ QString pyErrString("PyErr_SetString(PyExc_TypeError, \"" + fullPythonFunctionName(func)
+ + "(): got multiple values for keyword argument '%1'.\");");
+
+ s << INDENT << "if (kwds) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* ";
+ foreach (const AbstractMetaArgument* arg, args) {
+ int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
+ QString pyArgName = usePyArgs ? QString(PYTHON_ARGS "[%1]").arg(pyArgIndex) : PYTHON_ARG;
+ s << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
+ s << INDENT << "if (value && " << pyArgName << ") {" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "PyErr_Format(PyExc_TypeError, \"" << fullPythonFunctionName(func);
- s << "(): got multiple values for keyword argument '%s'\", errorArgName);" << endl;
+ s << INDENT << pyErrString.arg(arg->name()) << endl;
s << INDENT << "return " << m_currentErrorCode << ';' << endl;
}
+ s << INDENT << "} else if (value) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pyArgName << " = value;" << endl;
+ s << INDENT << "if (!";
+ writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()));
+ s << ')' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;" << endl;
+ }
+ }
s << INDENT << '}' << endl;
-
+ if (arg != args.last())
+ s << INDENT;
}
- s << INDENT << '}' << endl;
}
+ s << INDENT << '}' << endl;
}
QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass)
@@ -2075,9 +2566,11 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
userArgs << QString(CPP_ARG_REMOVED"%1").arg(i);
} else {
int idx = arg->argumentIndex() - removedArgs;
+ bool deRef = isValueTypeWithCopyConstructorOnly(arg->type())
+ || (arg->type()->isReference() && isWrapperType(arg->type()) && !isPointer(arg->type()));
QString argName = hasConversionRule
? QString("%1"CONV_RULE_OUT_VAR_SUFFIX).arg(arg->name())
- : QString(CPP_ARG"%1").arg(idx);
+ : QString("%1"CPP_ARG"%2").arg(deRef ? "*" : "").arg(idx);
userArgs << argName;
}
}
@@ -2110,15 +2603,14 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
bool isCtor = false;
QString methodCall;
QTextStream mc(&methodCall);
-
if (func->isOperatorOverload() && !func->isCallOperator()) {
- QByteArray firstArg("(*" CPP_SELF_VAR ")");
+ QString firstArg("(*" CPP_SELF_VAR ")");
if (func->isPointerOperator())
firstArg.remove(1, 1); // remove the de-reference operator
- QByteArray secondArg(CPP_ARG0);
+ QString secondArg(CPP_ARG0);
if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().first())) {
- secondArg.prepend('(');
+ secondArg.prepend("(*");
secondArg.append(')');
}
@@ -2147,7 +2639,7 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
QString className = wrapperName(func->ownerClass());
if (func->isCopyConstructor() && maxArgs == 1) {
- mc << "new ::" << className << '(' << CPP_ARG0 << ')';
+ mc << "new ::" << className << "(*" << CPP_ARG0 << ')';
} else {
QString ctorCall = className + '(' + userArgs.join(", ") + ')';
if (usePySideExtensions() && func->ownerClass()->isQObject()) {
@@ -2162,7 +2654,7 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
if (func->ownerClass()) {
if (!avoidProtectedHack() || !func->isProtected()) {
if (func->isStatic()) {
- mc << func->ownerClass()->qualifiedCppName() << "::";
+ mc << "::" << func->ownerClass()->qualifiedCppName() << "::";
} else {
if (func->isConstant()) {
if (avoidProtectedHack()) {
@@ -2187,7 +2679,7 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
mc << func->originalName();
} else {
if (!func->isStatic())
- mc << "((" << wrapperName(func->ownerClass()) << "*) " << CPP_SELF_VAR << ")->";
+ mc << "((::" << wrapperName(func->ownerClass()) << "*) " << CPP_SELF_VAR << ")->";
if (!func->isAbstract())
mc << (func->isProtected() ? wrapperName(func->ownerClass()) : "::" + func->ownerClass()->qualifiedCppName()) << "::";
@@ -2292,17 +2784,16 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f
if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::DefaultOwnership)
continue;
- s << INDENT;
+ s << INDENT << "Shiboken::Object::";
if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::TargetLangOwnership) {
- s << "Shiboken::Object::getOwnership(" << pyArgName << ");";
+ s << "getOwnership(" << pyArgName << ");";
} else if (wrappedClass->hasVirtualDestructor()) {
- if (arg_mod.index == 0) {
- s << "Shiboken::Object::releaseOwnership(" PYTHON_RETURN_VAR ");";
- } else {
- s << "Shiboken::Object::releaseOwnership(" << pyArgName << ");";
- }
+ if (arg_mod.index == 0)
+ s << "releaseOwnership(" PYTHON_RETURN_VAR ");";
+ else
+ s << "releaseOwnership(" << pyArgName << ");";
} else {
- s << "Shiboken::Object::invalidate(" << pyArgName << ");";
+ s << "invalidate(" << pyArgName << ");";
}
s << endl;
}
@@ -2422,54 +2913,19 @@ void CppGenerator::writeSpecialCastFunction(QTextStream& s, const AbstractMetaCl
s << "}\n\n";
}
-void CppGenerator::writeExtendedIsConvertibleFunction(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions)
-{
- s << "static bool " << extendedIsConvertibleFunctionName(externalType) << "(PyObject* pyobj)" << endl;
- s << '{' << endl;
- s << INDENT << "return ";
- bool isFirst = true;
- foreach (const AbstractMetaClass* metaClass, conversions) {
- Indentation indent(INDENT);
- if (isFirst)
- isFirst = false;
- else
- s << endl << INDENT << " || ";
- s << cpythonIsConvertibleFunction(metaClass->typeEntry()) << "(pyobj)";
- }
- s << ';' << endl;
- s << '}' << endl;
-}
-
-void CppGenerator::writeExtendedToCppFunction(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions)
-{
- s << "static void* " << extendedToCppFunctionName(externalType) << "(PyObject* pyobj)" << endl;
- s << '{' << endl;
- s << INDENT << "void* cptr = 0;" << endl;
- bool isFirst = true;
- foreach (const AbstractMetaClass* metaClass, conversions) {
- s << INDENT;
- if (isFirst)
- isFirst = false;
- else
- s << "else ";
- s << "if (" << cpythonIsConvertibleFunction(metaClass->typeEntry()) << "(pyobj))" << endl;
- Indentation indent(INDENT);
- s << INDENT << "cptr = new " << externalType->name() << '(';
- writeToCppConversion(s, metaClass, "pyobj");
- s << ");" << endl;
- }
- s << INDENT << "return cptr;" << endl;
- s << '}' << endl;
-}
-
void CppGenerator::writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions)
{
- s << INDENT << "// Extended implicit conversions for " << externalType->targetLangPackage() << '.' << externalType->name() << endl;
- s << INDENT << "shiboType = reinterpret_cast<SbkObjectType*>(";
- s << cppApiVariableName(externalType->targetLangPackage()) << '[';
- s << getTypeIndexVariableName(externalType) << "]);" << endl;
- s << INDENT << "Shiboken::ObjectType::setExternalIsConvertibleFunction(shiboType, " << extendedIsConvertibleFunctionName(externalType) << ");" << endl;
- s << INDENT << "Shiboken::ObjectType::setExternalCppConversionFunction(shiboType, " << extendedToCppFunctionName(externalType) << ");" << endl;
+ s << INDENT << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl;
+ foreach (const AbstractMetaClass* sourceClass, conversions) {
+ QString converterVar = QString("(SbkObjectType*)%1[%2]")
+ .arg(cppApiVariableName(externalType->targetLangPackage()))
+ .arg(getTypeIndexVariableName(externalType));
+ QString sourceTypeName = fixedCppTypeName(sourceClass->typeEntry());
+ QString targetTypeName = fixedCppTypeName(externalType);
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+ }
}
QString CppGenerator::multipleInheritanceInitializerFunctionName(const AbstractMetaClass* metaClass)
@@ -2879,7 +3335,7 @@ void CppGenerator::writeCopyFunction(QTextStream& s, const AbstractMetaClass* me
s << "{" << endl;
writeCppSelfDefinition(s, metaClass, false, true);
s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << cpythonToPythonConversionFunction(metaClass);
- s << "(" CPP_SELF_VAR ");" << endl;
+ s << CPP_SELF_VAR ");" << endl;
writeFunctionReturnErrorCheckSection(s);
s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl;
s << "}" << endl;
@@ -2911,29 +3367,29 @@ void CppGenerator::writeGetterFunction(QTextStream& s, const AbstractMetaField*
}
}
- s << INDENT << "PyObject* value = ";
+ s << INDENT << "PyObject* pyOut = ";
if (newWrapperSameObject) {
s << "Shiboken::Object::newObject((SbkObjectType*)" << cpythonTypeNameExt(fieldType);
s << ", " << cppField << ", false, true);" << endl;
- s << INDENT << "Shiboken::Object::setParent(" PYTHON_SELF_VAR ", value)";
+ s << INDENT << "Shiboken::Object::setParent(" PYTHON_SELF_VAR ", pyOut)";
} else {
writeToPythonConversion(s, fieldType, metaField->enclosingClass(), cppField);
}
s << ';' << endl;
- s << INDENT << "return value;" << endl;
+ s << INDENT << "return pyOut;" << endl;
s << '}' << endl;
}
void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField* metaField)
{
ErrorCode errorCode(0);
- s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* value, void*)" << endl;
+ s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* pyIn, void*)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, metaField->enclosingClass());
- s << INDENT << "if (value == 0) {" << endl;
+ s << INDENT << "if (pyIn == 0) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_TypeError, \"'";
@@ -2944,8 +3400,14 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField*
AbstractMetaType* fieldType = metaField->type();
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(fieldType)) {
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
s << INDENT << "if (!";
- writeTypeCheck(s, fieldType, "value", isNumber(fieldType->typeEntry()));
+ writeTypeCheck(s, fieldType, "pyIn", isNumber(fieldType->typeEntry()));
s << ") {" << endl;
{
Indentation indent(INDENT);
@@ -2955,24 +3417,39 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField*
}
s << INDENT << '}' << endl << endl;
- QString conversion;
- QTextStream c(&conversion);
- writeToCppConversion(c, fieldType, metaField->enclosingClass(), "value");
-
- if (avoidProtectedHack() && metaField->isProtected()) {
- conversion = QString("((%1*)%2)->%3(%4)").arg(wrapperName(metaField->enclosingClass()))
- .arg(CPP_SELF_VAR)
- .arg(protectedFieldSetterName(metaField))
- .arg(conversion);
- } else {
- conversion = QString("%1->%2 = %3").arg(CPP_SELF_VAR).arg(metaField->name()).arg(conversion);
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ s << INDENT;
+ if (isWrapperType(fieldType)) {
+ if (avoidProtectedHack() && metaField->isProtected()) {
+ s << getFullTypeNameWithoutModifiers(fieldType);
+ s << (fieldType->indirections() == 1 ? "*" : "") << " cppOut;" << endl;
+ s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut);" << endl;
+ s << INDENT << QString("((%1*)%2)->%3(cppOut)").arg(wrapperName(metaField->enclosingClass()))
+ .arg(CPP_SELF_VAR)
+ .arg(protectedFieldSetterName(metaField));
+ } else {
+ s << PYTHON_TO_CPP_VAR << QString("(pyIn, &(%1->%2))").arg(CPP_SELF_VAR).arg(metaField->name());
+ }
+ } else { // TODO-CONVERTER --------------------------------------------------------------
+ QString conversion;
+ QTextStream c(&conversion);
+ writeToCppConversion(c, fieldType, metaField->enclosingClass(), "pyIn", QString());
+ if (avoidProtectedHack() && metaField->isProtected()) {
+ conversion = QString("((%1*)%2)->%3(%4)").arg(wrapperName(metaField->enclosingClass()))
+ .arg(CPP_SELF_VAR)
+ .arg(protectedFieldSetterName(metaField))
+ .arg(conversion);
+ } else {
+ conversion = QString("%1->%2 = %3").arg(CPP_SELF_VAR).arg(metaField->name()).arg(conversion);
+ }
+ s << conversion;
}
-
- s << INDENT << conversion << ';' << endl << endl;
+ s << ';' << endl << endl;
+ // TODO-CONVERTER -----------------------------------------------------------------------
if (isPointerToWrapperType(fieldType)) {
s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
- s << metaField->name() << "\", value);" << endl;
+ s << metaField->name() << "\", pyIn);" << endl;
}
s << INDENT << "return 0;" << endl;
@@ -2988,6 +3465,11 @@ void CppGenerator::writeRichCompareFunction(QTextStream& s, const AbstractMetaCl
writeCppSelfDefinition(s, metaClass, false, true);
writeUnusedVariableCast(s, CPP_SELF_VAR);
s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+ s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR << ';' << endl;
+ // TODO-CONVERTER: remove this later.
+ // Make a check that ask something like: "there's no conversions in the overloads?".
+ writeUnusedVariableCast(s, PYTHON_TO_CPP_VAR);
+ // TODO-CONVERTER: RANDOM THOUGHT: I gave that decisor some overloads. Decisors love overloads.
s << endl;
s << INDENT << "switch (op) {" << endl;
@@ -3013,21 +3495,22 @@ void CppGenerator::writeRichCompareFunction(QTextStream& s, const AbstractMetaCl
bool first = true;
OverloadData overloadData(overloads, this);
- foreach (OverloadData* data, overloadData.nextOverloadData()) {
- const AbstractMetaFunction* func = data->referenceFunction();
+ foreach (OverloadData* od, overloadData.nextOverloadData()) {
+ const AbstractMetaFunction* func = od->referenceFunction();
if (func->isStatic())
continue;
const AbstractMetaType* argType = getArgumentType(func, 1);
if (!argType)
continue;
- bool numberType = alternativeNumericTypes == 1 || ShibokenGenerator::isPyInt(argType);
if (!first) {
s << " else ";
} else {
first = false;
s << INDENT;
}
- s << "if (" << cpythonIsConvertibleFunction(argType, numberType) << "(" PYTHON_ARG ")) {" << endl;
+ s << "if (";
+ writeTypeCheck(s, argType, PYTHON_ARG, alternativeNumericTypes == 1 || isPyInt(argType));
+ s << ") {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "// " << func->signature() << endl;
@@ -3038,9 +3521,10 @@ void CppGenerator::writeRichCompareFunction(QTextStream& s, const AbstractMetaCl
CodeSnipList snips = func->injectedCodeSnips();
writeCodeSnips(s, snips, CodeSnip::Any, TypeSystem::TargetLangCode, func, func->arguments().last());
} else {
- QString expression = QString("%1%2 %3 " CPP_ARG0)
+ QString expression = QString("%1%2 %3 (%4" CPP_ARG0 ")")
.arg(func->isPointerOperator() ? "&" : "")
- .arg(CPP_SELF_VAR).arg(op);
+ .arg(CPP_SELF_VAR).arg(op)
+ .arg(shouldDereferenceAbstractMetaTypePointer(argType) ? "*" : "");
s << INDENT;
if (func->type())
s << func->type()->cppSignature() << " " CPP_RETURN_VAR " = ";
@@ -3454,7 +3938,7 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m
s << INDENT << "if (!Shiboken::ObjectType::introduceWrapperType(" << enclosingObjectVariable;
s << ", \"" << metaClass->name() << "\", \"";
// Original name
- s << metaClass->qualifiedCppName() << (ShibokenGenerator::isObjectType(classTypeEntry) ? "*" : "");
+ s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : "");
s << "\"," << endl;
{
Indentation indent(INDENT);
@@ -3488,6 +3972,10 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m
}
s << INDENT << '}' << endl << endl;
+ // Register conversions for the type.
+ writeConverterRegister(s, metaClass);
+ s << endl;
+
// class inject-code target/beginning
if (!classTypeEntry->codeSnips().isEmpty()) {
writeCodeSnips(s, classTypeEntry->codeSnips(), CodeSnip::Beginning, TypeSystem::TargetLangCode, metaClass);
@@ -3820,6 +4308,9 @@ void CppGenerator::finishGeneration()
s << inc;
s << endl;
+ s << "// Current module's type array." << endl;
+ s << "PyTypeObject** " << cppApiVariableName() << ';' << endl;
+
CodeSnipList snips;
if (moduleEntry)
snips = moduleEntry->codeSnips();
@@ -3880,24 +4371,30 @@ void CppGenerator::finishGeneration()
}
}
- s << "// Current module's type array." << endl;
- s << "PyTypeObject** " << cppApiVariableName() << ';' << endl;
- s << "// Required modules' type arrays." << endl;
- foreach (const QString& requiredModule, typeDb->requiredTargetImports())
+ QStringList requiredModules = typeDb->requiredTargetImports();
+ if (!requiredModules.isEmpty())
+ s << "// Required modules' type and converter arrays." << endl;
+ foreach (const QString& requiredModule, requiredModules)
s << "PyTypeObject** " << cppApiVariableName(requiredModule) << ';' << endl;
s << endl;
s << "// Module initialization ";
s << "------------------------------------------------------------" << endl;
ExtendedConverterData extendedConverters = getExtendedConverters();
- if (!extendedConverters.isEmpty())
- s << "// Extended Converters" << endl;
- foreach (const TypeEntry* externalType, extendedConverters.keys()) {
- writeExtendedIsConvertibleFunction(s, externalType, extendedConverters[externalType]);
- writeExtendedToCppFunction(s, externalType, extendedConverters[externalType]);
+ if (!extendedConverters.isEmpty()) {
+ s << endl << "// Extended Converters." << endl << endl;
+ foreach (const TypeEntry* externalType, extendedConverters.keys()) {
+ s << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl;
+ foreach (const AbstractMetaClass* sourceClass, extendedConverters[externalType]) {
+ AbstractMetaType* sourceType = buildAbstractMetaTypeFromAbstractMetaClass(sourceClass);
+ AbstractMetaType* targetType = buildAbstractMetaTypeFromTypeEntry(externalType);
+ writePythonToCppConversionFunctions(s, sourceType, targetType);
+ delete sourceType;
+ delete targetType;
+ }
+ }
s << endl;
}
- s << endl;
s << "#if defined _WIN32 || defined __CYGWIN__" << endl;
@@ -3945,9 +4442,9 @@ void CppGenerator::finishGeneration()
s << INDENT << "}" << endl << endl;
}
- s << INDENT << "// Create an array of wrapper types for the current module." << endl;
int maxTypeIndex = getMaxTypeIndex();
if (maxTypeIndex) {
+ s << INDENT << "// Create an array of wrapper types for the current module." << endl;
s << INDENT << "static PyTypeObject* cppApi[SBK_" << moduleName() << "_IDX_COUNT];" << endl;
s << INDENT << cppApiVariableName() << " = cppApi;" << endl << endl;
}
@@ -3962,15 +4459,11 @@ void CppGenerator::finishGeneration()
s << INDENT << "// Initialize classes in the type system" << endl;
s << classPythonDefines;
- if (!extendedConverters.isEmpty()) {
- s << INDENT << "// Initialize extended Converters" << endl;
- s << INDENT << "SbkObjectType* shiboType;" << endl << endl;
- }
+ s << endl;
foreach (const TypeEntry* externalType, extendedConverters.keys()) {
writeExtendedConverterInitialization(s, externalType, extendedConverters[externalType]);
s << endl;
}
- s << endl;
writeEnumsInitialization(s, globalEnums);
diff --git a/generator/cppgenerator.h b/generator/cppgenerator.h
index 09486428..f4ff188d 100644
--- a/generator/cppgenerator.h
+++ b/generator/cppgenerator.h
@@ -51,6 +51,11 @@ private:
void writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass* metaClass);
void writeMetaCast(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeConverterFunctions(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion);
+ void writeConverterRegister(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar);
+
void writeMethodWrapperPreamble(QTextStream& s, OverloadData& overloadData);
void writeConstructorWrapper(QTextStream& s, const AbstractMetaFunctionList overloads);
void writeDestructorWrapper(QTextStream& s, const AbstractMetaClass* metaClass);
@@ -141,7 +146,49 @@ private:
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);
+ void writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func);
+
+ /// Returns the name of a C++ to Python conversion function.
+ static QString cppToPythonFunctionName(const QString& sourceTypeName, QString targetTypeName = QString());
+
+ /// Returns the name of a Python to C++ conversion function.
+ static QString pythonToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName);
+ static QString pythonToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType);
+ static QString pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, const TypeEntry* targetType);
+
+ /// Returns the name of a Python to C++ convertible check function.
+ static QString convertibleToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName);
+ static QString convertibleToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType);
+ static QString convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, const TypeEntry* targetType);
+
+ /// Writes a C++ to Python conversion function.
+ void writeCppToPythonFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, QString targetTypeName = QString());
+ void writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion);
+
+ /// Writes a Python to C++ conversion function.
+ void writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName);
+
+ /// Writes a Python to C++ convertible check function.
+ void writeIsPythonConvertibleToCppFunction(QTextStream& s,
+ const QString& sourceTypeName,
+ const QString& targetTypeName,
+ const QString& condition,
+ QString pythonToCppFuncName = QString(),
+ bool acceptNoneAsCppNull = false);
+
+ /// Writes a pair of Python to C++ conversion and check functions.
+ void writePythonToCppConversionFunctions(QTextStream& s,
+ const AbstractMetaType* sourceType,
+ const AbstractMetaType* targetType,
+ QString typeCheck = QString(),
+ QString conversion = QString());
+ /// Writes a pair of Python to C++ conversion and check functions for implicit conversions.
+ void writePythonToCppConversionFunctions(QTextStream& s,
+ const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType);
+
+ void writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc);
+
void writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs);
/// Returns a string containing the name of an argument for the given function and argument index.
@@ -157,7 +204,7 @@ private:
void writeSequenceMethods(QTextStream& s, const AbstractMetaClass* metaClass);
void writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
- /// Writes the struct PyMappingMethods for types thats supports the python mapping protocol
+ /// Writes the PyMappingMethods structure for types that supports the python mapping protocol.
void writeTypeAsMappingDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
void writeMappingMethods(QTextStream& s, const AbstractMetaClass* metaClass);
@@ -193,8 +240,6 @@ private:
/// Writes the implementation of special cast functions, used when we need to cast a class with multiple inheritance.
void writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass);
- void writeExtendedIsConvertibleFunction(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions);
- void writeExtendedToCppFunction(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions);
void writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions);
void writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool userHeuristicForReturn);
diff --git a/generator/headergenerator.cpp b/generator/headergenerator.cpp
index 39d3eb4f..0de8c44e 100644
--- a/generator/headergenerator.cpp
+++ b/generator/headergenerator.cpp
@@ -564,82 +564,22 @@ void HeaderGenerator::writeTypeConverterImpl(QTextStream& s, const TypeEntry* ty
const QString typeName = "::" + type->qualifiedCppName();
// Write Converter<T>::isConvertible
- s << "inline bool Shiboken::Converter< " << typeName << " >::isConvertible(PyObject* pyobj)" << endl;
+ s << "inline bool Shiboken::Converter< " << typeName << " >::isConvertible(PyObject* pyIn)" << endl;
s << '{' << endl;
-
- if (type->isValue()) {
- s << INDENT << "if (ValueTypeConverter< " << typeName << " >::isConvertible(pyobj))" << endl;
- Indentation indent(INDENT);
- s << INDENT << "return true;" << endl;
- }
-
-
- s << INDENT << "SbkObjectType* shiboType = reinterpret_cast<SbkObjectType*>(SbkType< ";
- s << typeName << " >());" << endl;
- s << INDENT << "return ";
- bool isFirst = true;
- foreach (const AbstractMetaFunction* ctor, implicitConvs) {
- Indentation indent(INDENT);
- if (isFirst)
- isFirst = false;
- else
- s << endl << INDENT << " || ";
- if (ctor->isConversionOperator())
- s << cpythonCheckFunction(ctor->ownerClass()->typeEntry());
- else
- s << cpythonCheckFunction(ctor->arguments().first()->type());
- s << "(pyobj)";
- }
- s << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << " || (ObjectType::isExternalConvertible(shiboType, pyobj));" << endl;
- }
+ s << INDENT << "return (bool)Shiboken::Conversions::isPythonToCppValueConvertible((SbkObjectType*)";
+ s << cpythonTypeNameExt(type) << ", pyIn);" << endl;
s << '}' << endl << endl;
// Write Converter<T>::toCpp function
- s << "inline " << typeName << " Shiboken::Converter< " << typeName << " >::toCpp(PyObject* pyobj)" << endl;
+ s << "inline " << typeName << " Shiboken::Converter< " << typeName << " >::toCpp(PyObject* pyIn)" << endl;
s << '{' << endl;
-
- s << INDENT << "if (PyObject_TypeCheck(pyobj, SbkType< " << typeName << " >()))" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << "return *" << cpythonWrapperCPtr(type, "pyobj") << ';' << endl;
- }
-
- foreach (const AbstractMetaFunction* ctor, implicitConvs) {
- if (ctor->isModifiedRemoved())
- continue;
-
- s << INDENT << "else ";
-
- QString typeCheck;
- QString toCppConv;
- QTextStream tcc(&toCppConv);
- if (ctor->isConversionOperator()) {
- const AbstractMetaClass* metaClass = ctor->ownerClass();
- typeCheck = cpythonCheckFunction(metaClass->typeEntry());
- writeToCppConversion(tcc, metaClass, "pyobj");
- } else {
- const AbstractMetaType* argType = ctor->arguments().first()->type();
- typeCheck = cpythonCheckFunction(argType);
- writeToCppConversion(tcc, argType, 0, "pyobj");
- }
-
- s << "if (" << typeCheck << "(pyobj))" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << "return " << type->name() << '(' << toCppConv << ");" << endl;
- }
- }
-
- {
- s << INDENT << "else" << endl;
- {
- Indentation indent(INDENT);
- s << INDENT << "return Shiboken::ValueTypeConverter< " << typeName << " >::toCpp(pyobj);" << endl;
- }
- }
+ s << INDENT << "PythonToCppFunc toCpp = Shiboken::Conversions::isPythonToCppValueConvertible((SbkObjectType*)";
+ s << cpythonTypeNameExt(type) << ", pyIn);" << endl;
+ s << INDENT << typeName << " cppOut = ";
+ writeMinimalConstructorExpression(s, type);
+ s << ';' << endl;
+ s << INDENT << "toCpp(pyIn, &cppOut);" << endl;
+ s << INDENT << "return cppOut;" << endl;
s << '}' << endl << endl;
}
@@ -666,4 +606,3 @@ void HeaderGenerator::writeInheritedOverloads(QTextStream& s)
s << "; }" << endl;
}
}
-
diff --git a/generator/shibokengenerator.cpp b/generator/shibokengenerator.cpp
index b6d86394..c344f3c8 100644
--- a/generator/shibokengenerator.cpp
+++ b/generator/shibokengenerator.cpp
@@ -81,15 +81,17 @@ ShibokenGenerator::ShibokenGenerator() : Generator()
m_typeSystemConvName[TypeSystemIsConvertibleFunction] = "isConvertible";
m_typeSystemConvName[TypeSystemToCppFunction] = "toCpp";
m_typeSystemConvName[TypeSystemToPythonFunction] = "toPython";
- m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegExp("%CHECKTYPE\\[([^\\[]*)\\]");
- m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegExp("%ISCONVERTIBLE\\[([^\\[]*)\\]");
- m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegExp("%CONVERTTOCPP\\[([^\\[]*)\\]");
- m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegExp("%CONVERTTOPYTHON\\[([^\\[]*)\\]");
+ m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegExp("%CHECKTYPE\\[([^\\[]*)\\]\\(");
+ m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegExp("%ISCONVERTIBLE\\[([^\\[]*)\\]\\(");
+ m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegExp("%CONVERTTOPYTHON\\[([^\\[]*)\\]\\(");
+ m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegExp("((?:[a-zA-Z_%][\\w%]*\\s*[\\*&]?\\s+)*)((?:\\*\\s*)?[a-zA-Z_%][\\w%]*"\
+ "(?:\\[[^\\[]+\\])*)(?:\\s+)=(?:\\s+)%CONVERTTOCPP\\[([^\\[]*)\\]\\(");
}
ShibokenGenerator::~ShibokenGenerator()
{
- qDeleteAll(m_metaTypeFromStringCache.values());
+ // TODO-CONVERTER: it must be caching types that were not created here.
+ //qDeleteAll(m_metaTypeFromStringCache.values());
}
void ShibokenGenerator::clearTpFuncs()
@@ -515,9 +517,12 @@ QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType* metaType,
QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName)
{
- if (ShibokenGenerator::isWrapperType(type))
- return baseConversionString( "::" + type->qualifiedCppName() + '*') + "toCpp(" + argName + ')';
- return QString();
+ if (!ShibokenGenerator::isWrapperType(type))
+ return QString();
+ return QString("((::%1*)Shiboken::Conversions::cppPointer(%2, (SbkObject*)%3))")
+ .arg(type->qualifiedCppName())
+ .arg(cpythonTypeNameExt(type))
+ .arg(argName);
}
QString ShibokenGenerator::getFunctionReturnType(const AbstractMetaFunction* func, Options options) const
@@ -585,28 +590,48 @@ void ShibokenGenerator::writeBaseConversion(QTextStream& s, const AbstractMetaTy
void ShibokenGenerator::writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
const AbstractMetaClass* context, const QString& argumentName)
{
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+ s << cpythonToPythonConversionFunction(type) << argumentName << ')';
+ return;
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
s << cpythonToPythonConversionFunction(type, context) << '(' << argumentName << ')';
}
void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass,
- const QString& argumentName)
+ const QString& inArgName, const QString& outArgName)
{
- s << cpythonToCppConversionFunction(metaClass) << '(' << argumentName << ')';
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ s << cpythonToCppConversionFunction(metaClass) << inArgName << ", &" << outArgName << ')';
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ //s << cpythonToCppConversionFunction(metaClass) << '(' << inArgName << ')';
}
-void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaType* type,
- const AbstractMetaClass* context, const QString& argumentName)
+void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context,
+ const QString& inArgName, const QString& outArgName)
{
- s << cpythonToCppConversionFunction(type, context) << '(' << argumentName << ')';
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+ s << cpythonToCppConversionFunction(type, context) << inArgName << ", &" << outArgName << ')';
+ return;
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ s << cpythonToCppConversionFunction(type, context) << '(' << inArgName << ')';
}
bool ShibokenGenerator::shouldRejectNullPointerArgument(const AbstractMetaFunction* func, int argIndex)
{
if (argIndex < 0 || argIndex >= func->arguments().count())
return false;
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ const AbstractMetaArgument* arg = func->arguments().at(argIndex);
+ if (isValueTypeWithCopyConstructorOnly(arg->type()))
+ return true;
+ // TODO-CONVERTER -----------------------------------------------------------------------
// Argument type is not a pointer, a None rejection should not be
// necessary because the type checking would handle that already.
- if (!isPointer(func->arguments().at(argIndex)->type()))
+ if (!isPointer(arg->type()))
return false;
if (func->argumentRemoved(argIndex + 1))
return false;
@@ -752,6 +777,36 @@ QString ShibokenGenerator::cpythonOperatorFunctionName(const AbstractMetaFunctio
+ '_' + pythonOperatorFunctionName(func->originalName());
}
+QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative)
+{
+ if (toNative->sourceType())
+ return fixedCppTypeName(toNative->sourceType());
+ return toNative->sourceTypeName();
+}
+QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType* type)
+{
+ return fixedCppTypeName(type->typeEntry(), type->cppSignature());
+}
+
+static QString _fixedCppTypeName(QString typeName)
+{
+ return typeName.replace(" ", "")
+ .replace(".", "_")
+ .replace("<", "_")
+ .replace(">", "_")
+ .replace("::", "_")
+ .replace("*", "PTR")
+ .replace("&", "REF");
+}
+QString ShibokenGenerator::fixedCppTypeName(const TypeEntry* type, QString typeName)
+{
+ if (typeName.isEmpty())
+ typeName = type->qualifiedCppName();
+ if (!(type->codeGeneration() & TypeEntry::GenerateTargetLang))
+ typeName.prepend(QString("%1_").arg(type->targetLangPackage()));
+ return _fixedCppTypeName(typeName);
+}
+
QString ShibokenGenerator::pythonPrimitiveTypeName(const QString& cppTypeName)
{
return ShibokenGenerator::m_pythonPrimitiveTypeName.value(cppTypeName, QString());
@@ -867,6 +922,30 @@ bool ShibokenGenerator::isPointerToWrapperType(const AbstractMetaType* type)
return (isObjectType(type) && type->indirections() == 1) || type->isValuePointer();
}
+bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass || !metaClass->typeEntry()->isValue())
+ return false;
+ AbstractMetaFunctionList ctors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
+ if (ctors.count() != 1)
+ return false;
+ return ctors.first()->isCopyConstructor();
+}
+
+bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const
+{
+ if (!type || !type->isValue())
+ return false;
+ return isValueTypeWithCopyConstructorOnly(classes().findClass(type));
+}
+
+bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaType* type) const
+{
+ if (!type || !type->typeEntry()->isValue())
+ return false;
+ return isValueTypeWithCopyConstructorOnly(type->typeEntry());
+}
+
bool ShibokenGenerator::shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg)
{
return shouldDereferenceAbstractMetaTypePointer(arg->type());
@@ -874,8 +953,7 @@ bool ShibokenGenerator::shouldDereferenceArgumentPointer(const AbstractMetaArgum
bool ShibokenGenerator::shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType* metaType)
{
- return isWrapperType(metaType) && !isPointer(metaType)
- && (metaType->isValue() || metaType->isReference());
+ return metaType->isReference() && isWrapperType(metaType) && !isPointer(metaType);
}
bool ShibokenGenerator::visibilityModifiedToPrivate(const AbstractMetaFunction* func)
@@ -899,6 +977,12 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType
return customCheck;
}
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(metaType)) {
+ return QString("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(metaType->typeEntry()));
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
QString baseName = cpythonBaseName(metaType);
if (isNumber(baseName))
return genericNumberType ? QString("SbkNumber_Check") : QString("%1_Check").arg(baseName);
@@ -924,6 +1008,12 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool gene
return customCheck;
}
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+ return QString("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type));
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
QString baseName = cpythonBaseName(type);
if (isNumber(baseName))
return genericNumberType ? "SbkNumber_Check" : baseName+"_Check";
@@ -967,6 +1057,16 @@ QString ShibokenGenerator::guessCPythonIsConvertible(const QString& type)
QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type, bool genericNumberType, bool checkExact)
{
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+ QString isConv = (type->isValue() && !isValueTypeWithCopyConstructorOnly(type))
+ ? "isPythonToCppValueConvertible"
+ : "isPythonToCppPointerConvertible";
+ return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ")
+ .arg(isConv).arg(cpythonTypeNameExt(type));
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
if (checkExact)
return cpythonCheckFunction(type, genericNumberType);
@@ -990,6 +1090,20 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType*
return customCheck;
}
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(metaType)) {
+ QString isConv;
+ if (isPointer(metaType) || isValueTypeWithCopyConstructorOnly(metaType))
+ isConv = "isPythonToCppPointerConvertible";
+ else if (metaType->isReference())
+ isConv = "isPythonToCppReferenceConvertible";
+ else
+ isConv = "isPythonToCppValueConvertible";
+ return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ")
+ .arg(isConv).arg(cpythonTypeNameExt(metaType));
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
QString baseName = cpythonBaseName(metaType);
if (isNumber(baseName))
return genericNumberType ? QString("SbkNumber_Check") : QString("%1_Check").arg(baseName);
@@ -1002,13 +1116,24 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType*
QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass* metaClass)
{
- QString base;
- QTextStream b(&base);
- writeBaseConversion(b, metaClass->typeEntry());
- return QString("%1toCpp").arg(base);
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ return QString("Shiboken::Conversions::pythonToCppPointer((SbkObjectType*)%1, ")
+ .arg(cpythonTypeNameExt(metaClass->typeEntry()));
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ //QString base;
+ //QTextStream b(&base);
+ //writeBaseConversion(b, metaClass->typeEntry());
+ //return QString("%1toCpp").arg(base);
}
QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context)
{
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+ return QString("Shiboken::Conversions::pythonToCpp%1((SbkObjectType*)%2, ")
+ .arg(isPointer(type) ? "Pointer" : "Copy")
+ .arg(cpythonTypeNameExt(type));
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
QString base;
QTextStream b(&base);
writeBaseConversion(b, type, context);
@@ -1017,6 +1142,19 @@ QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType
QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context)
{
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+ QString conversion;
+ if (type->isReference() && !isPointer(type))
+ conversion = "reference";
+ else if (type->isValue())
+ conversion = "copy";
+ else
+ conversion = "pointer";
+ return QString("Shiboken::Conversions::%1ToPython((SbkObjectType*)%2, %3")
+ .arg(conversion).arg(cpythonTypeNameExt(type)).arg(conversion == "pointer" ? "" : "&");
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
// exclude const on Objects
Options flags = getConverterOptions(type);
QString base;
@@ -1032,6 +1170,17 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaC
QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* type)
{
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+ QString conversion;
+ if (type->isValue())
+ conversion = "copy";
+ else
+ conversion = "pointer";
+ return QString("Shiboken::Conversions::%1ToPython((SbkObjectType*)%2, %3")
+ .arg(conversion).arg(cpythonTypeNameExt(type)).arg(conversion == "pointer" ? "" : "&");
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
QString base;
QTextStream b(&base);
writeBaseConversion(b, type);
@@ -1312,12 +1461,25 @@ ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentRepl
argValue = QString(CPP_ARG_REMOVED"%1").arg(i);
if (!argRemoved && argValue.isEmpty()) {
int argPos = i - removed;
- if (arg->type()->typeEntry()->isCustom()) {
+ const AbstractMetaType* type = arg->type();
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+ if (!typeReplaced.isEmpty()) {
+ AbstractMetaType* builtType = buildAbstractMetaTypeFromString(typeReplaced);
+ if (builtType)
+ type = builtType;
+ }
+ if (type->typeEntry()->isCustom()) {
argValue = usePyArgs ? QString(PYTHON_ARGS"[%1]").arg(argPos) : PYTHON_ARG;
} else {
argValue = hasConversionRule
? QString("%1"CONV_RULE_OUT_VAR_SUFFIX).arg(arg->name())
: QString(CPP_ARG"%1").arg(argPos);
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (isWrapperType(type)) {
+ if (type->isReference() && !isPointer(type))
+ argValue.prepend('*');
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
}
}
} else {
@@ -1489,10 +1651,23 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
foreach (ArgumentVarReplacementPair pair, argReplacements) {
const AbstractMetaArgument* arg = pair.first;
int idx = arg->argumentIndex() + 1;
- QString replacement = pair.second;
- if (isWrapperType(arg->type()) && isPointer(arg->type()))
- code.replace(QString("%%1.").arg(idx), QString("%1->").arg(replacement));
- code.replace(QString("%%1").arg(idx), replacement);
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ AbstractMetaType* type = arg->type();
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+ if (!typeReplaced.isEmpty()) {
+ AbstractMetaType* builtType = buildAbstractMetaTypeFromString(typeReplaced);
+ if (builtType)
+ type = builtType;
+ }
+ if (isWrapperType(type)) {
+ QString replacement = pair.second;
+ if (type->isReference() && !isPointer(type))
+ replacement.remove(0, 1);
+ if (type->isReference() || isPointer(type))
+ code.replace(QString("%%1.").arg(idx), QString("%1->").arg(replacement));
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ code.replace(QString("%%1").arg(idx), pair.second);
}
if (language == TypeSystem::NativeCode) {
@@ -1541,6 +1716,52 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
s << INDENT << "// End of code injection" << endl;
}
+// Returns true if the string is an expression,
+// and false if it is a variable.
+static bool isVariable(const QString& code)
+{
+ static QRegExp expr("\\s*\\*?\\s*[A-Za-z_]+[A-Za-z_0-9]*\\s*(?:\\[[^\\[]+\\])*");
+ return expr.exactMatch(code.trimmed());
+}
+
+// A miniature normalizer that puts a type string into a format
+// suitable for comparison with AbstractMetaType::cppSignature()
+// result.
+static QString miniNormalizer(const QString& varType)
+{
+ QString normalized = varType.trimmed();
+ QString suffix;
+ while (normalized.endsWith('*') || normalized.endsWith('&')) {
+ suffix.prepend(normalized.at(normalized.count() - 1));
+ normalized.chop(1);
+ }
+ return QString("%1 %2").arg(normalized).arg(suffix).trimmed();
+}
+// The position must indicate the first character after the opening '('.
+// ATTENTION: do not modify this function to trim any resulting string!
+// This must be done elsewhere.
+static QString getConverterTypeSystemVariableArgument(const QString& code, int pos)
+{
+ QString arg;
+ int parenthesisDepth = 0;
+ int count = 0;
+ while (pos + count < code.count()) {
+ char c = code.at(pos+count).toAscii();
+ if (c == '(') {
+ ++parenthesisDepth;
+ } else if (c == ')') {
+ if (parenthesisDepth == 0) {
+ arg = code.mid(pos, count).trimmed();
+ break;
+ }
+ --parenthesisDepth;
+ }
+ ++count;
+ }
+ if (parenthesisDepth != 0)
+ qFatal("Unbalanced parenthesis on type system converter variable call.");
+ return arg;
+}
typedef QPair<QString, QString> StringPair;
void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code)
{
@@ -1551,31 +1772,72 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
while ((pos = regex.indexIn(code, pos)) != -1) {
pos += regex.matchedLength();
QStringList list = regex.capturedTexts();
- QString conversionVar = list.first();
+ QString conversionString = list.first();
QString conversionTypeName = list.last();
const AbstractMetaType* conversionType = buildAbstractMetaTypeFromString(conversionTypeName);
QString conversion;
+ QTextStream c(&conversion);
if (conversionType) {
switch (converterVariable) {
+ case TypeSystemToCppFunction: {
+ if (!isWrapperType(conversionType)) {
+ c << list.at(1) << list.at(2) << " = ";
+ c << cpythonToCppConversionFunction(conversionType);
+ c << '(';
+ break;
+ }
+ QString varType = miniNormalizer(list.at(1));
+ QString varName = list.at(2).trimmed();
+ if (!varType.isEmpty()) {
+ if (varType != conversionType->cppSignature()) {
+ qFatal(qPrintable(QString("Types of receiver variable ('%1') and %CONVERTTOCPP type system variable ('%2') differ.")
+ .arg(varType).arg(conversionType->cppSignature())), NULL);
+ }
+ c << getFullTypeName(conversionType) << ' ' << varName << " = ";
+ writeMinimalConstructorExpression(c, conversionType);
+ c << ';' << endl;
+ Indentation indent(INDENT);
+ c << INDENT;
+ }
+ c << cpythonToCppConversionFunction(conversionType);
+ QString prefix;
+ if (varName.startsWith('*')) {
+ varName.chop(1);
+ varName = varName.trimmed();
+ } else {
+ prefix = '&';
+ }
+ QString arg = getConverterTypeSystemVariableArgument(code, pos);
+ conversionString += arg;
+ c << arg << ", " << prefix << '(' << varName << ')';
+ break;
+ }
case TypeSystemCheckFunction:
conversion = cpythonCheckFunction(conversionType);
- break;
case TypeSystemIsConvertibleFunction:
- conversion = cpythonIsConvertibleFunction(conversionType);
- break;
- case TypeSystemToCppFunction:
- conversion = cpythonToCppConversionFunction(conversionType);
- break;
+ if (conversion.isEmpty())
+ conversion = cpythonIsConvertibleFunction(conversionType);
case TypeSystemToPythonFunction:
- conversion = cpythonToPythonConversionFunction(conversionType);
- break;
- default:
- Q_ASSERT(false);
+ if (conversion.isEmpty())
+ conversion = cpythonToPythonConversionFunction(conversionType);
+ default: {
+ if (!isWrapperType(conversionType)) {
+ c << '(';
+ break;
+ }
+ QString arg = getConverterTypeSystemVariableArgument(code, pos);
+ conversionString += arg;
+ if (converterVariable == TypeSystemToPythonFunction && !isVariable(arg)) {
+ qFatal(qPrintable(QString("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%1'")
+ .arg(code)), NULL);
+ }
+ c << arg;
+ }
}
} else {
- conversion = QString("Shiboken::Converter< %1 >::%2").arg(conversionTypeName).arg(conversionName);
+ conversion = QString("Shiboken::Converter< %1 >::%2(").arg(conversionTypeName).arg(conversionName);
}
- replacements.append(qMakePair(conversionVar, conversion));
+ replacements.append(qMakePair(conversionString, conversion));
}
foreach (StringPair rep, replacements)
code.replace(rep.first, rep.second);
@@ -1817,6 +2079,24 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ
return metaType;
}
+AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry)
+{
+ if (m_metaTypeFromStringCache.contains(typeEntry->qualifiedCppName()))
+ return m_metaTypeFromStringCache.value(typeEntry->qualifiedCppName());
+ AbstractMetaType* metaType = new AbstractMetaType;
+ metaType->setTypeEntry(typeEntry);
+ metaType->setIndirections(0);
+ metaType->setReference(false);
+ metaType->setConstant(false);
+ metaType->decideUsagePattern();
+ m_metaTypeFromStringCache.insert(typeEntry->qualifiedCppName(), metaType);
+ return metaType;
+}
+AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass* metaClass)
+{
+ return ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(metaClass->typeEntry());
+}
+
/*
static void dumpFunction(AbstractMetaFunctionList lst)
{
@@ -1946,17 +2226,6 @@ QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const
return result;
}
-static QString _fixedCppTypeName(QString typeName)
-{
- return typeName.replace(" ", "")
- .replace(".", "_")
- .replace("<", "_")
- .replace(">", "_")
- .replace("::", "_")
- .replace("*", "PTR")
- .replace("&", "REF");
-}
-
static QString processInstantiationsVariableName(const AbstractMetaType* type)
{
QString res = QString("_%1").arg(_fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper());
@@ -2001,6 +2270,19 @@ QString ShibokenGenerator::getFullTypeName(const AbstractMetaClass* metaClass)
{
return getFullTypeName(metaClass->typeEntry());
}
+QString ShibokenGenerator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type)
+{
+ if (!type->hasInstantiations())
+ return getFullTypeName(type->typeEntry());
+ QString typeName = type->cppSignature();
+ if (type->isConstant())
+ typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
+ if (type->isReference())
+ typeName.chop(1);
+ while (typeName.endsWith('*') || typeName.endsWith(' '))
+ typeName.chop(1);
+ return QString("::%1").arg(typeName);
+}
bool ShibokenGenerator::verboseErrorMessagesDisabled() const
{
@@ -2052,3 +2334,28 @@ QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, co
}
return QString();
}
+
+// TODO-CONVERTER -----------------------------------------------------------------------
+void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor)
+{
+ QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
+ if (ctor.isEmpty()) {
+ QString errorMsg = QString(MIN_CTOR_ERROR_MSG).arg(type->cppSignature());
+ ReportHandler::warning(errorMsg);
+ s << endl << INDENT << "#error " << errorMsg << endl;
+ return;
+ }
+ s << ctor;
+}
+void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor)
+{
+ QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
+ if (ctor.isEmpty()) {
+ QString errorMsg = QString(MIN_CTOR_ERROR_MSG).arg(type->qualifiedCppName());
+ ReportHandler::warning(errorMsg);
+ s << endl << INDENT << "#error " << errorMsg << endl;
+ return;
+ }
+ s << ctor;
+}
+// TODO-CONVERTER -----------------------------------------------------------------------
diff --git a/generator/shibokengenerator.h b/generator/shibokengenerator.h
index ca1a273a..05e5bd92 100644
--- a/generator/shibokengenerator.h
+++ b/generator/shibokengenerator.h
@@ -40,6 +40,7 @@
#define END_ALLOW_THREADS "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS"
#define MIN_CTOR_ERROR_MSG "Could not find a minimal constructor for type '%1'. "\
"This will result in a compilation error."
+#define PYTHON_TO_CPP_VAR "pythonToCpp"
#include <generator.h>
#include <QtCore/QTextStream>
@@ -247,11 +248,11 @@ public:
void writeBaseConversion(QTextStream& s, const TypeEntry* type);
void writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
const AbstractMetaClass* context, const QString& argumentName);
- void writeToCppConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context, const QString& argumentName);
- void writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass, const QString& argumentName);
+ void writeToCppConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context, const QString& inArgName, const QString& outArgName);
+ void writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass, const QString& inArgName, const QString& outArgName);
/// Returns true if the argument is a pointer that rejects NULL values.
- static bool shouldRejectNullPointerArgument(const AbstractMetaFunction* func, int argIndex);
+ bool shouldRejectNullPointerArgument(const AbstractMetaFunction* func, int argIndex);
/// Verifies if the class should have a C++ wrapper generated for it, instead of only a Python wrapper.
bool shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) const;
@@ -278,6 +279,10 @@ public:
static QString cpythonOperatorFunctionName(const AbstractMetaFunction* func);
+ static QString fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative);
+ static QString fixedCppTypeName(const AbstractMetaType* type);
+ static QString fixedCppTypeName(const TypeEntry* type, QString typeName = QString());
+
static bool isNumber(QString cpythonApiName);
static bool isNumber(const TypeEntry* type);
static bool isNumber(const AbstractMetaType* type);
@@ -300,6 +305,11 @@ public:
*/
static bool isPointerToWrapperType(const AbstractMetaType* type);
+ static bool isValueTypeWithCopyConstructorOnly(const AbstractMetaClass* metaClass);
+ bool isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const;
+ bool isValueTypeWithCopyConstructorOnly(const AbstractMetaType* type) const;
+
+
/// Checks if an argument type should be dereferenced by the Python method wrapper before calling the C++ method.
static bool shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg);
/// Checks if a meta type should be dereferenced by the Python method wrapper passing it to C++.
@@ -409,6 +419,13 @@ public:
QString getFullTypeName(const AbstractMetaType* type);
QString getFullTypeName(const AbstractMetaClass* metaClass);
+ /**
+ * Returns the full qualified C++ name for an AbstractMetaType, but removing modifiers
+ * as 'const', '&', and '*' (except if the class is not derived from a template).
+ * This is useful for instantiated templates.
+ */
+ QString getFullTypeNameWithoutModifiers(const AbstractMetaType* type);
+
/// Returns true if the user don't want verbose error messages on the generated bindings.
bool verboseErrorMessagesDisabled() const;
@@ -420,6 +437,14 @@ public:
*/
AbstractMetaType* buildAbstractMetaTypeFromString(QString typeSignature);
+ /// Creates an AbstractMetaType object from a TypeEntry.
+ AbstractMetaType* buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry);
+ /// Creates an AbstractMetaType object from an AbstractMetaClass.
+ AbstractMetaType* buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass* metaClass);
+
+ void writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor = QString());
+ void writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor = QString());
+
/**
* Helper function to return the flags to be used by a meta type when
* it needs to write some converter code.
diff --git a/libshiboken/CMakeLists.txt b/libshiboken/CMakeLists.txt
index b57a814c..342151af 100644
--- a/libshiboken/CMakeLists.txt
+++ b/libshiboken/CMakeLists.txt
@@ -27,6 +27,7 @@ set(libshiboken_SRC
basewrapper.cpp
gilstate.cpp
helper.cpp
+sbkconverter.cpp
sbkenum.cpp
sbkmodule.cpp
sbkstring.cpp
@@ -54,6 +55,7 @@ install(FILES
conversions.h
gilstate.h
helper.h
+ sbkconverter.h
sbkenum.h
sbkmodule.h
python25compat.h
diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp
index 2baa5b85..181b7025 100644
--- a/libshiboken/basewrapper.cpp
+++ b/libshiboken/basewrapper.cpp
@@ -22,6 +22,7 @@
#include "basewrapper.h"
#include "basewrapper_p.h"
+#include "sbkconverter.h"
#include "sbkenum.h"
#include "autodecref.h"
#include "typeresolver.h"
@@ -250,6 +251,8 @@ void SbkObjectTypeDealloc(PyObject* pyObj)
}
free(sbkType->d->original_name);
sbkType->d->original_name = 0;
+ if (!Shiboken::ObjectType::isUserType(reinterpret_cast<PyTypeObject*>(sbkType)))
+ Shiboken::Conversions::deleteConverter(sbkType->d->converter);
delete sbkType->d;
sbkType->d = 0;
}
@@ -297,20 +300,18 @@ PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* k
d->mi_offsets = parentType->mi_offsets;
d->mi_init = parentType->mi_init;
d->mi_specialcast = parentType->mi_specialcast;
- d->ext_isconvertible = parentType->ext_isconvertible;
- d->ext_tocpp = parentType->ext_tocpp;
d->type_discovery = parentType->type_discovery;
d->cpp_dtor = parentType->cpp_dtor;
d->is_multicpp = 0;
+ d->converter = parentType->converter;
} else {
d->mi_offsets = 0;
d->mi_init = 0;
d->mi_specialcast = 0;
- d->ext_isconvertible = 0;
- d->ext_tocpp = 0;
d->type_discovery = 0;
d->cpp_dtor = 0;
d->is_multicpp = 1;
+ d->converter = 0;
}
if (bases.size() == 1)
d->original_name = strdup(bases.front()->d->original_name);
@@ -596,30 +597,13 @@ bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType)
return true;
}
-bool hasExternalCppConversions(SbkObjectType* self)
-{
- return self->d->ext_tocpp;
-}
-
-void* callExternalCppConversion(SbkObjectType* self, PyObject* obj)
-{
- return self->d->ext_tocpp(obj);
-}
-
-void setExternalCppConversionFunction(SbkObjectType* self, ExtendedToCppFunc func)
-{
- self->d->ext_tocpp = func;
-}
-void setExternalIsConvertibleFunction(SbkObjectType* self, ExtendedIsConvertibleFunc func)
-{
- self->d->ext_isconvertible = func;
-}
+bool hasExternalCppConversions(SbkObjectType*) { return false; } // DEPRECATED.
+bool isExternalConvertible(SbkObjectType* self, PyObject* obj) { return false; } // DEPRECATED.
+void setExternalCppConversionFunction(SbkObjectType*, ExtendedToCppFunc) {} // DEPRECATED.
+void setExternalIsConvertibleFunction(SbkObjectType*, ExtendedIsConvertibleFunc) {} // DEPRECATED.
+void* callExternalCppConversion(SbkObjectType*, PyObject*) { return 0; } // DEPRECATED.
-bool isExternalConvertible(SbkObjectType* self, PyObject* obj)
-{
- return self->d->ext_isconvertible && self->d->ext_isconvertible(obj);
-}
bool hasCast(SbkObjectType* type)
{
@@ -741,6 +725,12 @@ void setTypeUserData(SbkObjectType* self, void* userData, DeleteUserDataFunc d_f
self->d->d_func = d_func;
}
+
+SbkConverter* getTypeConverter(SbkObjectType* type)
+{
+ return type->d->converter;
+}
+
} // namespace ObjectType
diff --git a/libshiboken/basewrapper.h b/libshiboken/basewrapper.h
index 1d4b9643..c2539027 100644
--- a/libshiboken/basewrapper.h
+++ b/libshiboken/basewrapper.h
@@ -33,6 +33,7 @@
extern "C"
{
+struct SbkConverter;
struct SbkObjectPrivate;
/// Base Python object for all the wrapped C++ classes.
@@ -65,8 +66,8 @@ typedef void* (*SpecialCastFunction)(void*, SbkObjectType*);
typedef SbkObjectType* (*TypeDiscoveryFunc)(void*, SbkObjectType*);
typedef void* (*TypeDiscoveryFuncV2)(void*, SbkObjectType*);
-typedef void* (*ExtendedToCppFunc)(PyObject*);
-typedef bool (*ExtendedIsConvertibleFunc)(PyObject*);
+typedef void* (*ExtendedToCppFunc)(PyObject*); // DEPRECATED.
+typedef bool (*ExtendedIsConvertibleFunc)(PyObject*); // DEPRECATED.
// Used in userdata dealloc function
typedef void (*DeleteUserDataFunc)(void*);
@@ -131,11 +132,13 @@ LIBSHIBOKEN_API bool isUserType(PyTypeObject* pyObj);
*/
LIBSHIBOKEN_API bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType);
-LIBSHIBOKEN_API void setExternalCppConversionFunction(SbkObjectType* self, ExtendedToCppFunc func);
-LIBSHIBOKEN_API void setExternalIsConvertibleFunction(SbkObjectType* self, ExtendedIsConvertibleFunc func);
-LIBSHIBOKEN_API bool hasExternalCppConversions(SbkObjectType* self);
-LIBSHIBOKEN_API bool isExternalConvertible(SbkObjectType* self, PyObject* obj);
-LIBSHIBOKEN_API void* callExternalCppConversion(SbkObjectType* self, PyObject* obj);
+
+LIBSHIBOKEN_API bool hasExternalCppConversions(SbkObjectType*); // DEPRECATED.
+LIBSHIBOKEN_API bool isExternalConvertible(SbkObjectType*, PyObject*); // DEPRECATED.
+LIBSHIBOKEN_API void setExternalCppConversionFunction(SbkObjectType*, ExtendedToCppFunc); // DEPRECATED.
+LIBSHIBOKEN_API void setExternalIsConvertibleFunction(SbkObjectType*, ExtendedIsConvertibleFunc); // DEPRECATED.
+LIBSHIBOKEN_API void* callExternalCppConversion(SbkObjectType*, PyObject*); // DEPRECATED.
+
/**
* Tells if the \p type represents an object of a class with multiple inheritance in C++.
@@ -206,6 +209,10 @@ LIBSHIBOKEN_API void setSubTypeInitHook(SbkObjectType* self, SubTypeInitH
*/
LIBSHIBOKEN_API void* getTypeUserData(SbkObjectType* self);
LIBSHIBOKEN_API void setTypeUserData(SbkObjectType* self, void* userData, DeleteUserDataFunc d_func);
+
+/// Returns the converter assigned to the wrapper \p type.
+LIBSHIBOKEN_API SbkConverter* getTypeConverter(SbkObjectType* type);
+
}
namespace Object {
diff --git a/libshiboken/basewrapper_p.h b/libshiboken/basewrapper_p.h
index 9f96ba75..c943a2a0 100644
--- a/libshiboken/basewrapper_p.h
+++ b/libshiboken/basewrapper_p.h
@@ -31,6 +31,7 @@
struct SbkObject;
struct SbkObjectType;
+struct SbkConverter;
namespace Shiboken
{
@@ -106,10 +107,6 @@ struct SbkObjectTypePrivate
/// Special cast function, null if this class doesn't have multiple inheritance.
SpecialCastFunction mi_specialcast;
TypeDiscoveryFuncV2 type_discovery;
- /// Extended "isConvertible" function to be used when a conversion operator is defined in another module.
- ExtendedIsConvertibleFunc ext_isconvertible;
- /// Extended "toCpp" function to be used when a conversion operator is defined in another module.
- ExtendedToCppFunc ext_tocpp;
/// Pointer to a function responsible for deletion of the C++ instance calling the proper destructor.
ObjectDestructor cpp_dtor;
/// True if this type holds two or more C++ instances, e.g.: a Python class which inherits from two C++ classes.
@@ -124,6 +121,7 @@ struct SbkObjectTypePrivate
void* user_data;
DeleteUserDataFunc d_func;
void (*subtype_init)(SbkObjectType*, PyObject*, PyObject*);
+ SbkConverter* converter;
};
diff --git a/libshiboken/sbkconverter.cpp b/libshiboken/sbkconverter.cpp
new file mode 100644
index 00000000..b252e16c
--- /dev/null
+++ b/libshiboken/sbkconverter.cpp
@@ -0,0 +1,214 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sbkconverter.h"
+#include "sbkconverter_p.h"
+#include "basewrapper_p.h"
+
+#include "sbkdbg.h"
+
+namespace Shiboken {
+namespace Conversions {
+
+static SbkConverter* createConverterObject(PyTypeObject* type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc)
+{
+ SbkConverter* converter = new SbkConverter;
+ converter->pythonType = type;
+
+ converter->pointerToPython = pointerToPythonFunc;
+ converter->copyToPython = copyToPythonFunc;
+
+ converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc);
+ converter->toCppConversions.clear();
+
+ return converter;
+}
+
+SbkConverter* createConverter(SbkObjectType* type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc)
+{
+ SbkConverter* converter = createConverterObject((PyTypeObject*)type,
+ toCppPointerConvFunc, toCppPointerCheckFunc,
+ pointerToPythonFunc, copyToPythonFunc);
+ type->d->converter = converter;
+ return converter;
+}
+
+void deleteConverter(SbkConverter* converter)
+{
+ if (converter) {
+ converter->toCppConversions.clear();
+ delete converter;
+ }
+}
+
+void addPythonToCppValueConversion(SbkConverter* converter,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+ converter->toCppConversions.push_back(std::make_pair(isConvertibleToCppFunc, pythonToCppFunc));
+}
+void addPythonToCppValueConversion(SbkObjectType* type,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+ addPythonToCppValueConversion(type->d->converter, pythonToCppFunc, isConvertibleToCppFunc);
+}
+
+PyObject* pointerToPython(SbkObjectType* type, const void* cppIn)
+{
+ if (!cppIn)
+ Py_RETURN_NONE;
+ return type->d->converter->pointerToPython(cppIn);
+}
+
+PyObject* referenceToPython(SbkObjectType* type, const void* cppIn)
+{
+ assert(cppIn);
+
+ // If it is a Object Type, produce a wrapper for it.
+ if (!type->d->converter->copyToPython)
+ return type->d->converter->pointerToPython(cppIn);
+
+ // If it is a Value Type, try to find an existing wrapper, otherwise copy it as value to Python.
+ PyObject* pyOut = (PyObject*)BindingManager::instance().retrieveWrapper(cppIn);
+ if (pyOut) {
+ Py_INCREF(pyOut);
+ return pyOut;
+ }
+ return type->d->converter->copyToPython(cppIn);
+}
+
+static inline PyObject* CopyCppToPython(SbkConverter* converter, const void* cppIn)
+{
+ assert(cppIn);
+ return converter->copyToPython(cppIn);
+}
+PyObject* copyToPython(SbkObjectType* type, const void* cppIn)
+{
+ return CopyCppToPython(type->d->converter, cppIn);
+}
+PyObject* copyToPython(SbkConverter* converter, const void* cppIn)
+{
+ return CopyCppToPython(converter, cppIn);
+}
+
+PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType* type, PyObject* pyIn)
+{
+ assert(pyIn);
+ return type->d->converter->toCppPointerConversion.first(pyIn);
+}
+
+static inline PythonToCppFunc IsPythonToCppConvertible(SbkConverter* converter, PyObject* pyIn)
+{
+ assert(pyIn);
+ ToCppConversionList& convs = converter->toCppConversions;
+ for (ToCppConversionList::iterator conv = convs.begin(); conv != convs.end(); ++conv) {
+ PythonToCppFunc toCppFunc = 0;
+ if ((toCppFunc = (*conv).first(pyIn)))
+ return toCppFunc;
+ }
+ return 0;
+}
+PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType* type, PyObject* pyIn)
+{
+ return IsPythonToCppConvertible(type->d->converter, pyIn);
+}
+PythonToCppFunc isPythonToCppConvertible(SbkConverter* converter, PyObject* pyIn)
+{
+ return IsPythonToCppConvertible(converter, pyIn);
+}
+
+PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType* type, PyObject* pyIn)
+{
+ if (pyIn != Py_None) {
+ PythonToCppFunc toCpp = isPythonToCppPointerConvertible(type, pyIn);
+ if (toCpp)
+ return toCpp;
+ }
+ return isPythonToCppValueConvertible(type, pyIn);
+}
+
+void nonePythonToCppNullPtr(PyObject*, void* cppOut)
+{
+ assert(cppOut);
+ *((void**)cppOut) = 0;
+}
+
+void* cppPointer(PyTypeObject* desiredType, SbkObject* pyIn)
+{
+ assert(pyIn);
+ SbkObjectType* inType = (SbkObjectType*)pyIn->ob_type;
+ if (ObjectType::hasCast(inType))
+ return ObjectType::cast(inType, pyIn, desiredType);
+ return Object::cppPointer(pyIn, desiredType);
+}
+
+void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut)
+{
+ assert(type);
+ assert(pyIn);
+ assert(cppOut);
+ *((void**)cppOut) = (pyIn == Py_None) ? 0 : cppPointer((PyTypeObject*)type, (SbkObject*)pyIn);
+}
+
+void pythonToCppCopy(SbkObjectType* type, PyObject* pyIn, void* cppOut)
+{
+ assert(type);
+ assert(pyIn);
+ assert(cppOut);
+ PythonToCppFunc toCpp = IsPythonToCppConvertible(type->d->converter, pyIn);
+ if (toCpp)
+ toCpp(pyIn, cppOut);
+}
+
+bool isImplicitConversion(SbkObjectType* type, PythonToCppFunc toCppFunc)
+{
+ // This is the Object Type or Value Type conversion that only
+ // retrieves the C++ pointer held in the Python wrapper.
+ if (toCppFunc == type->d->converter->toCppPointerConversion.second)
+ return false;
+
+ // Object Types doesn't have any kind of value conversion,
+ // only C++ pointer retrieval.
+ if (type->d->converter->toCppConversions.empty())
+ return false;
+
+ // The first conversion of the non-pointer conversion list is
+ // a Value Type's copy to C++ function, which is not an implicit
+ // conversion.
+ // Otherwise it must be one of the implicit conversions.
+ // Note that we don't check if the Python to C++ conversion is in
+ // the list of the type's conversions, for it is expected that the
+ // caller knows what he's doing.
+ ToCppConversionList::iterator conv = type->d->converter->toCppConversions.begin();
+ return toCppFunc != (*conv).second;
+}
+
+} } // namespace Shiboken::Conversions
diff --git a/libshiboken/sbkconverter.h b/libshiboken/sbkconverter.h
new file mode 100644
index 00000000..d7be2577
--- /dev/null
+++ b/libshiboken/sbkconverter.h
@@ -0,0 +1,205 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SBK_CONVERTER_H
+#define SBK_CONVERTER_H
+
+#include <limits>
+#include <Python.h>
+#include "shibokenmacros.h"
+#include "basewrapper.h"
+
+/**
+ * This is a convenience macro identical to Python's PyObject_TypeCheck,
+ * except that the arguments have swapped places, for the great convenience
+ * of generator.
+ */
+#define SbkObject_TypeCheck(tp, ob) \
+ (Py_TYPE(ob) == (tp) || PyType_IsSubtype(Py_TYPE(ob), (tp)))
+
+extern "C"
+{
+
+/**
+ * SbkConverter is used to perform type conversions from C++
+ * to Python and vice-versa;.and it is also used for type checking.
+ * SbkConverter is a private structure that must be accessed
+ * using the functions provided by the converter API.
+ */
+struct SbkConverter;
+
+/**
+ * Given a void pointer to a C++ object, this function must return
+ * the proper Python object. It may be either an existing wrapper
+ * for the C++ object, or a newly create one. Or even the Python
+ * equivalent of the C++ value passed in the argument.
+ *
+ * C++ -> Python
+ */
+typedef PyObject* (*CppToPythonFunc)(const void*);
+
+/**
+ * This function converts a Python object to a C++ value, it may be
+ * a pointer, value, class, container or primitive type, passed via
+ * a void pointer, that will be cast properly inside the function.
+ * This function is usually returned by an IsConvertibleToCppFunc
+ * function, or obtained knowing the type of the Python object input,
+ * thus it will not check the Python object type, and will expect
+ * the void pointer to be pointing to a proper variable.
+ *
+ * Python -> C++
+ */
+typedef void (*PythonToCppFunc)(PyObject*,void*);
+
+/**
+ * Checks if the Python object passed in the argument is convertible to a
+ * C++ type defined inside the function, it returns the converter function
+ * that will transform a Python argument into a C++ value.
+ * It returns NULL if the Python object is not convertible to the C++ type
+ * that the function represents.
+ *
+ * Python -> C++ ?
+ */
+typedef PythonToCppFunc (*IsConvertibleToCppFunc)(PyObject*);
+
+} // extern "C"
+
+
+namespace Shiboken {
+namespace Conversions {
+
+/**
+ * Creates a converter for a wrapper type.
+ * \param type A Shiboken.ObjectType that will receive the new converter.
+ * \param toCppPointerConvFunc Function to retrieve the C++ pointer held by a Python wrapper.
+ * \param toCppPointerCheckFunc Check and return the retriever function of the C++ pointer held by a Python wrapper.
+ * \param pointerToPythonFunc Function to convert a C++ object to a Python \p type wrapper, keeping their identity.
+ * \param copyToPythonFunc Function to convert a C++ object to a Python \p type, copying the object.
+ * \returns The new converter referred by the wrapper \p type.
+ */
+LIBSHIBOKEN_API SbkConverter* createConverter(SbkObjectType* type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc = 0);
+
+LIBSHIBOKEN_API void deleteConverter(SbkConverter* converter);
+
+/**
+ * Adds a new conversion of a Python object to a C++ value.
+ * This is used in copy and implicit conversions.
+ */
+LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkConverter* converter,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc);
+LIBSHIBOKEN_API void addPythonToCppValueConversion(SbkObjectType* type,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc);
+
+// C++ -> Python ---------------------------------------------------------------------------
+
+/**
+ * Retrieves the Python wrapper object for the given \p cppIn C++ pointer object.
+ * This function is used only for Value and Object Types.
+ * Example usage:
+ * TYPE* var;
+ * PyObject* pyVar = pointerToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject* pointerToPython(SbkObjectType* type, const void* cppIn);
+
+/**
+ * For the given \p cppIn C++ reference it returns the Python wrapper object,
+ * always for Object Types, and when they already exist for reference types;
+ * for when the latter doesn't have an existing wrapper type, the C++ object
+ * is copied to Python.
+ * Example usage:
+ * TYPE& var = SOMETHING;
+ * PyObject* pyVar = referenceToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject* referenceToPython(SbkObjectType* type, const void* cppIn);
+
+/**
+ * Retrieves the Python wrapper object for the given C++ value pointed by \p cppIn.
+ * This function is used only for Value Types.
+ * Example usage:
+ * TYPE var;
+ * PyObject* pyVar = copyToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject* copyToPython(SbkObjectType* type, const void* cppIn);
+LIBSHIBOKEN_API PyObject* copyToPython(SbkConverter* converter, const void* cppIn);
+
+// Python -> C++ ---------------------------------------------------------------------------
+
+/**
+ * Returns a Python to C++ conversion function if the Python object is convertible to a C++ pointer.
+ * It returns NULL if the Python object is not convertible to \p type.
+ */
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType* type, PyObject* pyIn);
+
+/**
+ * Returns a Python to C++ conversion function if the Python object is convertible to a C++ value.
+ * The resulting converter function will create a copy of the Python object in C++, or implicitly
+ * convert the object to the expected \p type.
+ * It returns NULL if the Python object is not convertible to \p type.
+ */
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType* type, PyObject* pyIn);
+
+/**
+ * Returns a Python to C++ conversion function if the Python object is convertible to a C++ reference.
+ * The resulting converter function will return the underlying C++ object held by the Python wrapper,
+ * or a new C++ value if it must be a implicit conversion.
+ * It returns NULL if the Python object is not convertible to \p type.
+ */
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType* type, PyObject* pyIn);
+
+/// This is the same as isPythonToCppValueConvertible function.
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(SbkConverter* converter, PyObject* pyIn);
+
+/**
+ * Returns the C++ pointer for the \p pyIn object cast to the type passed via \p desiredType.
+ * It differs from Shiboken::Object::cppPointer because it casts the pointer to a proper
+ * memory offset depending on the desired type.
+ */
+LIBSHIBOKEN_API void* cppPointer(PyTypeObject* desiredType, SbkObject* pyIn);
+
+/// Converts a Python object \p pyIn to C++ and stores the result in the C++ pointer passed in \p cppOut.
+LIBSHIBOKEN_API void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut);
+
+/// Converts a Python object \p pyIn to C++ and copies the result in the C++ variable passed in \p cppOut.
+LIBSHIBOKEN_API void pythonToCppCopy(SbkObjectType* type, PyObject* pyIn, void* cppOut);
+
+/**
+ * Helper function returned by generated convertible checking functions
+ * that returns a C++ NULL when the input Python object is None.
+ */
+LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject*, void* cppOut);
+
+/**
+ * Returns true if the \p toCpp function passed is an implicit conversion of Python \p type.
+ * It is used when C++ expects a reference argument, so it may be the same object received
+ * from Python, or another created through implicit conversion.
+ */
+LIBSHIBOKEN_API bool isImplicitConversion(SbkObjectType* type, PythonToCppFunc toCpp);
+
+} } // namespace Shiboken::Conversions
+
+#endif // SBK_CONVERTER_H
diff --git a/libshiboken/sbkconverter_p.h b/libshiboken/sbkconverter_p.h
new file mode 100644
index 00000000..199538cc
--- /dev/null
+++ b/libshiboken/sbkconverter_p.h
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SBK_CONVERTER_P_H
+#define SBK_CONVERTER_P_H
+
+#include <Python.h>
+#include <list>
+#include "sbkconverter.h"
+
+extern "C"
+{
+
+typedef std::pair<IsConvertibleToCppFunc, PythonToCppFunc> ToCppConversion;
+typedef std::list<ToCppConversion> ToCppConversionList;
+
+/**
+ * \internal
+ * Private structure of SbkConverter.
+ */
+struct SbkConverter
+{
+ /**
+ * TODO: it certainly will be empty in some cases, like with PyDate.
+ * TODO: probably a setPythonType(SbkConverter*, PyTypeObject*) function will be required.
+ * Python type associated with this converter. If the type is a Shiboken
+ * wrapper, then it must be a SbkObjectType; otherwise it will be the
+ * Python type to which the C++ value will be converted (note that the
+ * C++ type could be produced from various Python types).
+ */
+ PyTypeObject* pythonType;
+ /**
+ * This function converts a C++ object to a Python object of the type
+ * indicated in pythonType. The identity of the C++ object is kept,
+ * because it looks for an already existing Python wrapper associated
+ * with the C++ instance.
+ * It is used to convert C++ pointers and references to Python objects.
+ */
+ CppToPythonFunc pointerToPython;
+ /**
+ * This function converts a C++ object to a Python object of the type
+ * indicated in pythonType. The identity of the is not kept, because a
+ * new instance of the C++ object is created.
+ * It is used to convert objects passed by value, or reference, if said
+ * reference can't be traced to an object that already has a Python
+ * wrapper assigned for it.
+ */
+ CppToPythonFunc copyToPython;
+ /**
+ * This is a special case of a Python to C++ conversion. It returns
+ * the underlying C++ pointer of a Python wrapper passed as parameter
+ * or NULL if the Python object is a None value.
+ * It comes separated from the other toCppConversions because if you
+ * have a Python object representing a Value Type the type checking
+ * for both ValueType and ValueType* would be the same, thus the first
+ * check would be true and the second would never be reached.
+ */
+ ToCppConversion toCppPointerConversion;
+ /**
+ * This is a list of type checking functions that return the
+ * proper Python to C++ conversion function, for the given Python
+ * object.
+ * For Object Types, that never have implicit conversions, this
+ * list is always empty.
+ */
+ ToCppConversionList toCppConversions;
+};
+
+} // extern "C"
+
+#endif // SBK_CONVERTER_P_H
diff --git a/libshiboken/shiboken.h b/libshiboken/shiboken.h
index 269f01c9..274c1ce1 100644
--- a/libshiboken/shiboken.h
+++ b/libshiboken/shiboken.h
@@ -31,6 +31,7 @@
#include "gilstate.h"
#include "threadstatesaver.h"
#include "helper.h"
+#include "sbkconverter.h"
#include "sbkenum.h"
#include "sbkmodule.h"
#include "sbkstring.h"
diff --git a/tests/samplebinding/injectcode_test.py b/tests/samplebinding/injectcode_test.py
index 2941b923..a60ef914 100644
--- a/tests/samplebinding/injectcode_test.py
+++ b/tests/samplebinding/injectcode_test.py
@@ -90,6 +90,19 @@ class InjectCodeTest(unittest.TestCase):
result = ic.callArrayMethod(values)
self.assertEqual(result, ic.multiplier * sum(values))
+ def testUsageOfTypeSystemCheckVariableOnPrimitiveType(self):
+ '''When the sequence item is convertible to an integer -1 is returned, or -2 if its not convertible.'''
+ ic = InjectCode()
+ values = (1, 2, 3, 4, '5', 6.7)
+ print values
+ result = ic.arrayMethod(values)
+ print result
+ fixedValues = [v for v in values if isinstance(v, int)]\
+ + [-1 for v in values if isinstance(v, float)]\
+ + [-2 for v in values if not isinstance(v, int) and not isinstance(v, float)]
+ print fixedValues
+ #self.assertEqual(result, sum(fixedValues))
+
class IntArrayTest(unittest.TestCase):
'''Test case for converting python sequence to int array'''
diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml
index bced56f8..12245618 100644
--- a/tests/samplebinding/typesystem_sample.xml
+++ b/tests/samplebinding/typesystem_sample.xml
@@ -203,7 +203,8 @@
<replace-type modified-type="str"/>
</modify-argument>
<inject-code class='target' position='beginning'>
- %0 = new %FUNCTION_NAME(atoi(%CONVERTTOCPP[const char*](%PYARG_1)));
+ const char* tmpArg = %CONVERTTOCPP[const char*](%PYARG_1);
+ %0 = new %FUNCTION_NAME(atoi(tmpArg));
</inject-code>
</modify-function>
</object-type>
@@ -246,7 +247,18 @@
<inject-code class="native" position="beginning">
static void reparent_layout_items(PyObject* parent, PyObject* layout)
{
- const ObjectTypeList&amp; objChildren = %CONVERTTOCPP[ObjectTypeLayout*](layout)->objects();
+ // CHECKTYPE and ISCONVERTIBLE are used here for test purposes, don't change them.
+ if (!%CHECKTYPE[ObjectTypeLayout*](layout) &amp;&amp; !%ISCONVERTIBLE[ObjectTypeLayout*](layout))
+ return;
+ // %CHECKTYPE[ObjectTypeLayout*](layout)
+ // %ISCONVERTIBLE[ObjectTypeLayout*](layout)
+ ObjectTypeLayout* var;
+ var = %CONVERTTOCPP[ObjectTypeLayout*](layout);
+ // TODO-CONVERTER: erase this
+ /*
+ ObjectTypeLayout* var2 = %CONVERTTOCPP[ObjectTypeLayout*](layout);
+ */
+ const ObjectTypeList&amp; objChildren = var->objects();
ObjectTypeList::const_iterator it = objChildren.begin();
for (; it != objChildren.end(); ++it) {
if ((*it)->isLayoutType()) {
@@ -1083,8 +1095,14 @@
<conversion-rule class="native">
int numItems = PySequence_Size(%PYARG_1);
Shiboken::AutoArrayPointer&lt;int&gt; %out(numItems);
- for (int i = 0; i &lt; numItems; ++i)
- %out[i] = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(%PYARG_1, i));
+ for (int i = 0; i &lt; numItems; ++i) {
+ if (%CHECKTYPE[int](PySequence_Fast_GET_ITEM(%PYARG_1, i)))
+ %out[i] = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(%PYARG_1, i));
+ else if (%ISCONVERTIBLE[int](PySequence_Fast_GET_ITEM(%PYARG_1, i)))
+ %out[i] = -1;
+ else
+ %out[i] = -2;
+ }
</conversion-rule>
<conversion-rule class="target">
PyObject* %out = PyList_New(count);
@@ -1539,7 +1557,17 @@
</value-type>
<value-type name="ByteArray" hash-function="ByteArray::hash">
- <conversion-rule file="bytearray_conversions.h"/>
+ <conversion-rule file="bytearray_conversions.h">
+ <target-to-native>
+ <add-conversion type='Py_None' check='%in == Py_None'>
+ %out = %OUTTYPE();
+ </add-conversion>
+ <add-conversion type='PyString' check='PyString_Check(%in)'>
+ %out = %OUTTYPE(PyString_AS_STRING(%in), PyString_GET_SIZE(%in));
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+
<modify-function signature="ByteArray(const char*,int)" remove="all" />
<modify-function signature="ByteArray(const char*)">
<!-- Keep \x00 bytes passed in Python strings. -->
@@ -1774,7 +1802,30 @@
<extra-includes>
<include file-name="datetime.h" location="global"/>
</extra-includes>
- <conversion-rule class="target" file="date_conversions.h"/>
+ <inject-code class="native" position="beginning">
+ static bool PyDate_ImportAndCheck(PyObject* pyIn) {
+ if (!PyDateTimeAPI)
+ PyDateTime_IMPORT;
+ return PyDate_Check(pyIn);
+ }
+ </inject-code>
+ <conversion-rule class="target" file="date_conversions.h">
+ <target-to-native>
+ <add-conversion type='PyDate' check='PyDate_ImportAndCheck(%in)'>
+ int day = PyDateTime_GET_DAY(%in);
+ int month = PyDateTime_GET_MONTH(%in);
+ int year = PyDateTime_GET_YEAR(%in);
+ %out = %OUTTYPE(day, month, year);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ <add-function signature="toPython()" return-type="PyDate">
+ <inject-code class="target">
+ if (!PyDateTimeAPI)
+ PyDateTime_IMPORT;
+ %PYARG_0 = PyDate_FromDate(%CPPSELF.day(), %CPPSELF.month(), %CPPSELF.year());
+ </inject-code>
+ </add-function>
</value-type>
<object-type name="HandleHolder" />