aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generator/cppgenerator.cpp141
-rw-r--r--generator/cppgenerator.h4
-rw-r--r--generator/headergenerator.cpp22
-rw-r--r--generator/shibokengenerator.cpp91
-rw-r--r--generator/shibokengenerator.h10
-rw-r--r--libshiboken/sbkconverter.cpp25
-rw-r--r--libshiboken/sbkconverter.h11
-rw-r--r--libshiboken/sbkmodule.cpp19
-rw-r--r--libshiboken/sbkmodule.h19
-rw-r--r--tests/minimalbinding/typesystem_minimal.xml12
-rw-r--r--tests/samplebinding/oddbool_test.py6
-rw-r--r--tests/samplebinding/typesystem_sample.xml76
12 files changed, 387 insertions, 49 deletions
diff --git a/generator/cppgenerator.cpp b/generator/cppgenerator.cpp
index ec376d5f4..9fe65ca23 100644
--- a/generator/cppgenerator.cpp
+++ b/generator/cppgenerator.cpp
@@ -799,7 +799,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (func->type() && func->typeReplaced(0) != "PyObject") {
// TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(func->type())) {
+ if (isWrapperType(func->type()) || isUserPrimitive(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;
@@ -1044,6 +1044,7 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla
QString typeCheck;
QString toCppConv;
+ QString toCppPreConv;
if (conv->isConversionOperator()) {
const AbstractMetaClass* sourceClass = conv->ownerClass();
typeCheck = QString("PyObject_TypeCheck(pyIn, %1)").arg(cpythonTypeNameExt(sourceClass->typeEntry()));
@@ -1055,24 +1056,37 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla
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));
+ typeCheck = cpythonCheckFunction(sourceType);
if (isWrapperType(sourceType)) {
+ typeCheck = QString("%1pyIn)").arg(typeCheck);
toCppConv = QString("%1%2")
.arg((sourceType->isReference() || !isPointerToWrapperType(sourceType)) ? "*" : "")
.arg(cpythonWrapperCPtr(sourceType->typeEntry(), "pyIn"));
+ } else if (typeCheck.contains("%in")) {
+ typeCheck.replace("%in", "pyIn");
+ typeCheck = QString("(%1)").arg(typeCheck);
} else {
+ typeCheck = QString("%1(pyIn)").arg(typeCheck);
+ }
+
+ if (isUserPrimitive(sourceType)) {
+ QTextStream pc(&toCppPreConv);
+ pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn = ";
+ writeMinimalConstructorExpression(pc, sourceType);
+ pc << ';' << endl;
+ writeToCppConversion(pc, sourceType, 0, "pyIn", "cppIn");
+ pc << ';';
+ toCppConv.append("cppIn");
+ } else if (!isWrapperType(sourceType)) {
QTextStream tcc(&toCppConv);
writeToCppConversion(tcc, sourceType, metaClass, "pyIn", "/*BOZO-1043*/");
}
+ // TODO-CONVERTER -----------------------------------------------------------------------
}
const AbstractMetaType* sourceType = conv->isConversionOperator()
? buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass())
: conv->arguments().first()->type();
- writePythonToCppConversionFunctions(s, sourceType, targetType, typeCheck, toCppConv);
+ writePythonToCppConversionFunctions(s, sourceType, targetType, typeCheck, toCppConv, toCppPreConv);
}
writeCustomConverterFunctions(s, customConversion);
@@ -1778,7 +1792,7 @@ void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argTyp
typeCheck.append(QString("(%1)").arg(argumentName));
// TODO-CONVERTER -----------------------------------------------------------------------
- if (customCheck.isEmpty() && isWrapperType(argType)) {
+ if (customCheck.isEmpty() && (isWrapperType(argType) || isUserPrimitive(argType))) {
typeCheck = QString("(%1 = %2))").arg(pythonToCppConverterForArgumentName(argumentName)).arg(typeCheck);
}
// TODO-CONVERTER -----------------------------------------------------------------------
@@ -1865,11 +1879,13 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s,
QString cppOutAux = QString("%1_local").arg(cppOut);
// TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(type)) {
+ if (isWrapperType(type) || isUserPrimitive(type)) {
bool treatAsPointer = isValueTypeWithCopyConstructorOnly(type);
- bool isPointerOrObjectType = isObjectType(type) || isPointer(type);
- bool mayHaveImplicitConversion = type->isReference() && !(treatAsPointer || isPointerOrObjectType);
+ bool isPointerOrObjectType = (isObjectType(type) || isPointer(type)) && /*TODO-CONVERTERS: is this really needed?*/ !isUserPrimitive(type);
+ bool mayHaveImplicitConversion = type->isReference()
+ && !isUserPrimitive(type)
+ && !(treatAsPointer || isPointerOrObjectType);
QString typeName = getFullTypeNameWithoutModifiers(type);
if (mayHaveImplicitConversion) {
s << INDENT << typeName << ' ' << cppOutAux << " = ";
@@ -1880,11 +1896,14 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s,
s << INDENT << typeName;
if (treatAsPointer || isPointerOrObjectType) {
s << "* " << cppOut << (defaultValue.isEmpty() ? "" : QString(" = %1").arg(defaultValue));
- } else if (type->isReference()) {
+ } else if (type->isReference() && !type->typeEntry()->isPrimitive()) {
s << "* " << cppOut << " = &" << cppOutAux;
} else {
s << ' ' << cppOut << " = ";
- writeMinimalConstructorExpression(s, type, defaultValue);
+ if (isUserPrimitive(type))
+ writeMinimalConstructorExpression(s, type->typeEntry(), defaultValue);
+ else
+ writeMinimalConstructorExpression(s, type, defaultValue);
}
s << ';' << endl;
@@ -2295,6 +2314,7 @@ void CppGenerator::writeCppToPythonFunction(QTextStream& s, const QString& code,
QString prettyCode;
QTextStream c(&prettyCode);
formatCode(c, code, INDENT);
+ processCodeSnip(prettyCode);
s << "static PyObject* " << cppToPythonFunctionName(sourceTypeName, targetTypeName);
s << "(const void* cppIn) {" << endl;
@@ -2304,6 +2324,7 @@ void CppGenerator::writeCppToPythonFunction(QTextStream& s, const QString& code,
void CppGenerator::writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion)
{
QString code = customConversion->nativeToTargetConversion();
+ processCodeSnip(code);
code.prepend(QString("::%1& cppInRef = *((::%1*)cppIn);\n").arg(customConversion->ownerType()->qualifiedCppName()));
code.replace("%INTYPE", cpythonTypeNameExt(customConversion->ownerType()));
code.replace("%OUTTYPE", "PyObject*");
@@ -2317,6 +2338,7 @@ void CppGenerator::writePythonToCppFunction(QTextStream& s, const QString& code,
QString prettyCode;
QTextStream c(&prettyCode);
formatCode(c, code, INDENT);
+ processCodeSnip(prettyCode);
s << "static void " << pythonToCppFunctionName(sourceTypeName, targetTypeName);
s << "(PyObject* pyIn, void* cppOut) {" << endl;
s << prettyCode;
@@ -2353,7 +2375,8 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
const AbstractMetaType* sourceType,
const AbstractMetaType* targetType,
QString typeCheck,
- QString conversion)
+ QString conversion,
+ QString preConversion)
{
QString sourcePyType = cpythonTypeNameExt(sourceType);
@@ -2362,6 +2385,8 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
QTextStream c(&code);
if (conversion.isEmpty())
conversion = QString("*%1").arg(cpythonWrapperCPtr(sourceType->typeEntry(), "pyIn"));
+ if (!preConversion.isEmpty())
+ c << INDENT << preConversion << endl;
c << INDENT << QString("*((::%1*)cppOut) = ::%1(%2);")
.arg(targetType->typeEntry()->qualifiedCppName())
.arg(conversion);
@@ -2399,14 +2424,31 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
// Python to C++ convertible check function.
QString typeCheck = toNative->sourceTypeCheck();
if (typeCheck.isEmpty()) {
+ QString pyTypeName = toNative->sourceTypeName();
+ if (pyTypeName == "Py_None" || pyTypeName == "PyNone")
+ typeCheck = "%in == Py_None";
+ else if (pyTypeName == "SbkEnumType")
+ typeCheck = "Shiboken::isShibokenEnum(%in)";
+ else if (pyTypeName == "SbkObject")
+ typeCheck = "Shiboken::Object::checkType(%in)";
+ else if (pyTypeName == "PyTypeObject")
+ typeCheck = "PyType_Check(%in)";
+ else if (pyTypeName == "PyObject")
+ typeCheck = "PyObject_TypeCheck(%in, &PyBaseObject_Type)";
+ else if (pyTypeName.startsWith("Py"))
+ typeCheck= QString("%1_Check(%in)").arg(pyTypeName);
+ }
+ 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;
+ qFatal(qPrintable(QString("User added implicit conversion for C++ type '%1' must provide either an input "\
+ "type check function or a non primitive type entry.")
+ .arg(targetType->qualifiedCppName())), NULL);
+
}
typeCheck = QString("PyObject_TypeCheck(%in, %1)").arg(cpythonTypeNameExt(toNative->sourceType()));
}
typeCheck.replace("%in", "pyIn");
+ processCodeSnip(typeCheck);
writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
}
@@ -2913,6 +2955,22 @@ void CppGenerator::writeSpecialCastFunction(QTextStream& s, const AbstractMetaCl
s << "}\n\n";
}
+void CppGenerator::writePrimitiveConverterInitialization(QTextStream& s, const CustomConversion* customConversion)
+{
+ const TypeEntry* type = customConversion->ownerType();
+ s << INDENT << "// Register converter for type '" << type->qualifiedTargetLangName() << "'." << endl;
+ s << INDENT << converterObject(type) << " = Shiboken::Conversions::createConverter(";
+ if (type->targetLangApiName() == type->name())
+ s << '0';
+ else if (type->targetLangApiName() == "PyObject")
+ s << "&PyBaseObject_Type";
+ else
+ s << '&' << type->targetLangApiName() << "_Type";
+ QString typeName = fixedCppTypeName(type);
+ s << ", " << cppToPythonFunctionName(typeName, typeName) << ");" << endl;
+ writeCustomConverterRegister(s, customConversion, converterObject(type));
+}
+
void CppGenerator::writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions)
{
s << INDENT << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl;
@@ -3401,7 +3459,7 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField*
AbstractMetaType* fieldType = metaField->type();
// TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(fieldType)) {
+ if (isWrapperType(fieldType) || isUserPrimitive(fieldType)) {
s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
}
// TODO-CONVERTER -----------------------------------------------------------------------
@@ -3419,7 +3477,7 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField*
// TODO-CONVERTER -----------------------------------------------------------------------
s << INDENT;
- if (isWrapperType(fieldType)) {
+ if (isWrapperType(fieldType) || isUserPrimitive(fieldType)) {
if (avoidProtectedHack() && metaField->isProtected()) {
s << getFullTypeNameWithoutModifiers(fieldType);
s << (fieldType->indirections() == 1 ? "*" : "") << " cppOut;" << endl;
@@ -4311,6 +4369,9 @@ void CppGenerator::finishGeneration()
s << "// Current module's type array." << endl;
s << "PyTypeObject** " << cppApiVariableName() << ';' << endl;
+ s << "// Current module's converter array." << endl;
+ s << "SbkConverter** " << convertersVariableName() << ';' << endl;
+
CodeSnipList snips;
if (moduleEntry)
snips = moduleEntry->codeSnips();
@@ -4374,8 +4435,10 @@ void CppGenerator::finishGeneration()
QStringList requiredModules = typeDb->requiredTargetImports();
if (!requiredModules.isEmpty())
s << "// Required modules' type and converter arrays." << endl;
- foreach (const QString& requiredModule, requiredModules)
+ foreach (const QString& requiredModule, requiredModules) {
s << "PyTypeObject** " << cppApiVariableName(requiredModule) << ';' << endl;
+ s << "SbkConverter** " << convertersVariableName(requiredModule) << ';' << endl;
+ }
s << endl;
s << "// Module initialization ";
@@ -4396,6 +4459,16 @@ void CppGenerator::finishGeneration()
s << endl;
}
+ QList<const CustomConversion*> typeConversions = getNonWrapperCustomConversions();
+ if (!typeConversions.isEmpty()) {
+ s << endl << "// Primitive and Container Type converters." << endl << endl;
+ foreach (const CustomConversion* conversion, typeConversions) {
+ s << "// C++ to Python conversion for type '" << conversion->ownerType()->qualifiedCppName() << "'." << endl;
+ writeCppToPythonFunction(s, conversion);
+ writeCustomConverterFunctions(s, conversion);
+ }
+ s << endl;
+ }
s << "#if defined _WIN32 || defined __CYGWIN__" << endl;
s << " #define SBK_EXPORT_MODULE __declspec(dllexport)" << endl;
@@ -4438,6 +4511,7 @@ void CppGenerator::finishGeneration()
s << INDENT << "SBK_MODULE_INIT_ERROR;" << endl;
}
s << INDENT << cppApiVariableName(requiredModule) << " = Shiboken::Module::getTypes(requiredModule);" << endl;
+ s << INDENT << convertersVariableName(requiredModule) << " = Shiboken::Module::getTypeConverters(requiredModule);" << endl;
}
s << INDENT << "}" << endl << endl;
}
@@ -4449,6 +4523,10 @@ void CppGenerator::finishGeneration()
s << INDENT << cppApiVariableName() << " = cppApi;" << endl << endl;
}
+ s << INDENT << "// Create an array of primitive type converters for the current module." << endl;
+ s << INDENT << "static SbkConverter* sbkConverters[SBK_" << moduleName() << "_CONVERTERS_IDX_COUNT" << "];" << endl;
+ s << INDENT << convertersVariableName() << " = sbkConverters;" << endl << endl;
+
s << "#ifdef IS_PY3K" << endl;
s << INDENT << "PyObject* module = Shiboken::Module::create(\"" << moduleName() << "\", &moduledef);" << endl;
s << "#else" << endl;
@@ -4456,13 +4534,26 @@ void CppGenerator::finishGeneration()
s << moduleName() << "_methods);" << endl;
s << "#endif" << endl << endl;
+ //s << INDENT << "// Initialize converters for primitive types." << endl;
+ //s << INDENT << "initConverters();" << endl << endl;
+
s << INDENT << "// Initialize classes in the type system" << endl;
s << classPythonDefines;
- s << endl;
- foreach (const TypeEntry* externalType, extendedConverters.keys()) {
- writeExtendedConverterInitialization(s, externalType, extendedConverters[externalType]);
+ if (!typeConversions.isEmpty()) {
+ s << endl;
+ foreach (const CustomConversion* conversion, typeConversions) {
+ writePrimitiveConverterInitialization(s, conversion);
+ s << endl;
+ }
+ }
+
+ if (!extendedConverters.isEmpty()) {
s << endl;
+ foreach (const TypeEntry* externalType, extendedConverters.keys()) {
+ writeExtendedConverterInitialization(s, externalType, extendedConverters[externalType]);
+ s << endl;
+ }
}
writeEnumsInitialization(s, globalEnums);
@@ -4494,8 +4585,10 @@ void CppGenerator::finishGeneration()
foreach (QByteArray type, typeResolvers)
s << INDENT << typeResolverString(type) << ';' << endl;
+ s << endl;
if (maxTypeIndex)
- s << endl << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");" << endl;
+ s << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");" << endl;
+ s << INDENT << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");" << endl;
s << endl << INDENT << "if (PyErr_Occurred()) {" << endl;
{
diff --git a/generator/cppgenerator.h b/generator/cppgenerator.h
index f4ff188df..86f434cfa 100644
--- a/generator/cppgenerator.h
+++ b/generator/cppgenerator.h
@@ -181,7 +181,8 @@ private:
const AbstractMetaType* sourceType,
const AbstractMetaType* targetType,
QString typeCheck = QString(),
- QString conversion = QString());
+ QString conversion = QString(),
+ QString preConversion = QString());
/// Writes a pair of Python to C++ conversion and check functions for implicit conversions.
void writePythonToCppConversionFunctions(QTextStream& s,
const CustomConversion::TargetToNativeConversion* toNative,
@@ -240,6 +241,7 @@ 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 writePrimitiveConverterInitialization(QTextStream& s, const CustomConversion* customConversion);
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 0de8c44ef..e6668853c 100644
--- a/generator/headergenerator.cpp
+++ b/generator/headergenerator.cpp
@@ -360,8 +360,28 @@ void HeaderGenerator::finishGeneration()
macrosStream << "SBK_"+moduleName()+"_IDX_COUNT";
macrosStream.setFieldWidth(0);
macrosStream << ' ' << getMaxTypeIndex() << endl << endl;
- macrosStream << "// This variable stores all python types exported by this module" << endl;
+ macrosStream << "// This variable stores all Python types exported by this module." << endl;
macrosStream << "extern PyTypeObject** " << cppApiVariableName() << ';' << endl << endl;
+ macrosStream << "// This variable stores all type converters exported by this module." << endl;
+ macrosStream << "extern SbkConverter** " << convertersVariableName() << ';' << endl << endl;;
+
+ // TODO-CONVERTER ------------------------------------------------------------------------------
+ // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex().
+ macrosStream << "// Converter indices" << endl;
+ QList<const PrimitiveTypeEntry*> primitives = primitiveTypes();
+ int pCount = 0;
+ foreach (const PrimitiveTypeEntry* ptype, primitives) {
+ if (!ptype->generateCode() || !isUserPrimitive(ptype))
+ continue;
+ _writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(ptype), pCount);
+ pCount++;
+ }
+ // Because on win32 the compiler will not accept a zero length array.
+ if (pCount == 0)
+ pCount++;
+ _writeTypeIndexDefineLine(macrosStream, QString("SBK_%1_CONVERTERS_IDX_COUNT").arg(moduleName()), pCount);
+ macrosStream << endl;
+ // TODO-CONVERTER ------------------------------------------------------------------------------
macrosStream << "// Macros for type check" << endl;
foreach (const AbstractMetaEnum* cppEnum, globalEnums) {
diff --git a/generator/shibokengenerator.cpp b/generator/shibokengenerator.cpp
index c344f3c8f..19a8f7da8 100644
--- a/generator/shibokengenerator.cpp
+++ b/generator/shibokengenerator.cpp
@@ -591,7 +591,7 @@ void ShibokenGenerator::writeToPythonConversion(QTextStream& s, const AbstractMe
const AbstractMetaClass* context, const QString& argumentName)
{
// TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(type)) {
+ if (isWrapperType(type) || isUserPrimitive(type)) {
s << cpythonToPythonConversionFunction(type) << argumentName << ')';
return;
}
@@ -612,7 +612,7 @@ void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaT
const QString& inArgName, const QString& outArgName)
{
// TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(type)) {
+ if (isWrapperType(type) || isUserPrimitive(type)) {
s << cpythonToCppConversionFunction(type, context) << inArgName << ", &" << outArgName << ')';
return;
}
@@ -764,6 +764,15 @@ QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type)
return cppApiVariableName(type->targetLangPackage()) + '[' + getTypeIndexVariableName(type) + ']';
}
+QString ShibokenGenerator::converterObject(const AbstractMetaType* type)
+{
+ return converterObject(type->typeEntry());
+}
+QString ShibokenGenerator::converterObject(const TypeEntry* type)
+{
+ return convertersVariableName(type->targetLangPackage()) + '[' + getTypeIndexVariableName(type) + ']';
+}
+
QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType* type)
{
return cppApiVariableName(type->typeEntry()->targetLangPackage()) + '[' + getTypeIndexVariableName(type) + ']';
@@ -946,6 +955,23 @@ bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaTyp
return isValueTypeWithCopyConstructorOnly(type->typeEntry());
}
+bool ShibokenGenerator::isUserPrimitive(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ if (trueType->basicAliasedTypeEntry())
+ trueType = trueType->basicAliasedTypeEntry();
+ return trueType->isPrimitive() && !trueType->isCppPrimitive() && trueType->qualifiedCppName() != "std::string";
+}
+
+bool ShibokenGenerator::isUserPrimitive(const AbstractMetaType* type)
+{
+ if (type->indirections() != 0)
+ return false;
+ return isUserPrimitive(type->typeEntry());
+}
+
bool ShibokenGenerator::shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg)
{
return shouldDereferenceAbstractMetaTypePointer(arg->type());
@@ -978,9 +1004,8 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType
}
// TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(metaType)) {
- return QString("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(metaType->typeEntry()));
- }
+ if (isWrapperType(metaType) || isUserPrimitive(metaType))
+ return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
// TODO-CONVERTER -----------------------------------------------------------------------
QString baseName = cpythonBaseName(metaType);
@@ -1011,6 +1036,11 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool gene
// TODO-CONVERTER -----------------------------------------------------------------------
if (isWrapperType(type)) {
return QString("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type));
+ } else if (isUserPrimitive(type)) {
+ QString typeCheck;
+ if (!type->targetLangApiName().isEmpty())
+ typeCheck = QString("%1_Check").arg(type->targetLangApiName());
+ return typeCheck;
}
// TODO-CONVERTER -----------------------------------------------------------------------
@@ -1064,6 +1094,9 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type, b
: "isPythonToCppPointerConvertible";
return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ")
.arg(isConv).arg(cpythonTypeNameExt(type));
+ } else if (isUserPrimitive(type)) {
+ return QString("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
+ .arg(converterObject(type));
}
// TODO-CONVERTER -----------------------------------------------------------------------
@@ -1101,6 +1134,9 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType*
isConv = "isPythonToCppValueConvertible";
return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ")
.arg(isConv).arg(cpythonTypeNameExt(metaType));
+ } else if (isUserPrimitive(metaType)) {
+ return QString("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
+ .arg(converterObject(metaType));
}
// TODO-CONVERTER -----------------------------------------------------------------------
@@ -1132,6 +1168,9 @@ QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType
return QString("Shiboken::Conversions::pythonToCpp%1((SbkObjectType*)%2, ")
.arg(isPointer(type) ? "Pointer" : "Copy")
.arg(cpythonTypeNameExt(type));
+ } else if (isUserPrimitive(type)) {
+ return QString("Shiboken::Conversions::pythonToCpp(%1, ")
+ .arg(converterObject(type));
}
// TODO-CONVERTER -----------------------------------------------------------------------
QString base;
@@ -1153,6 +1192,8 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaT
conversion = "pointer";
return QString("Shiboken::Conversions::%1ToPython((SbkObjectType*)%2, %3")
.arg(conversion).arg(cpythonTypeNameExt(type)).arg(conversion == "pointer" ? "" : "&");
+ } else if (isUserPrimitive(type)) {
+ return QString("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type));
}
// TODO-CONVERTER -----------------------------------------------------------------------
// exclude const on Objects
@@ -1179,6 +1220,8 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* ty
conversion = "pointer";
return QString("Shiboken::Conversions::%1ToPython((SbkObjectType*)%2, %3")
.arg(conversion).arg(cpythonTypeNameExt(type)).arg(conversion == "pointer" ? "" : "&");
+ } else if (isUserPrimitive(type)) {
+ return QString("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type));
}
// TODO-CONVERTER -----------------------------------------------------------------------
QString base;
@@ -1373,6 +1416,17 @@ ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverter
return extConvs;
}
+QList<const CustomConversion*> ShibokenGenerator::getNonWrapperCustomConversions()
+{
+ QList<const CustomConversion*> conversions;
+ foreach (const PrimitiveTypeEntry* type, primitiveTypes()) {
+ if (!shouldGenerateTypeEntry(type) || !isUserPrimitive(type) || !type->customConversion())
+ continue;
+ conversions << type->customConversion();
+ }
+ return conversions;
+}
+
static QString getArgumentsFromMethodCall(const QString& str)
{
// It would be way nicer to be able to use a Perl like
@@ -1780,7 +1834,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
if (conversionType) {
switch (converterVariable) {
case TypeSystemToCppFunction: {
- if (!isWrapperType(conversionType)) {
+ if (!isWrapperType(conversionType) && !isUserPrimitive(conversionType)) {
c << list.at(1) << list.at(2) << " = ";
c << cpythonToCppConversionFunction(conversionType);
c << '(';
@@ -1821,21 +1875,32 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
if (conversion.isEmpty())
conversion = cpythonToPythonConversionFunction(conversionType);
default: {
- if (!isWrapperType(conversionType)) {
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (!isWrapperType(conversionType) && !isUserPrimitive(conversionType)) {
c << '(';
break;
}
+ // TODO-CONVERTER -----------------------------------------------------------------------
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;
+ if (conversion.contains("%in")) {
+ conversion.prepend('(');
+ conversion.replace("%in", arg);
+ } else {
+ if (conversionType->isPrimitive() && converterVariable == TypeSystemCheckFunction)
+ conversion.append('(');
+ c << arg;
+ }
}
}
} else {
- conversion = QString("Shiboken::Converter< %1 >::%2(").arg(conversionTypeName).arg(conversionName);
+ if (list.count() > 2)
+ c << list.at(1) << list.at(2) << " = ";
+ c << QString("Shiboken::Converter< %1 >::%2(").arg(conversionTypeName).arg(conversionName);
}
replacements.append(qMakePair(conversionString, conversion));
}
@@ -2226,6 +2291,14 @@ QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const
return result;
}
+QString ShibokenGenerator::convertersVariableName(const QString& moduleName) const
+{
+ QString result = cppApiVariableName(moduleName);
+ result.chop(1);
+ result.append("Converters");
+ return result;
+}
+
static QString processInstantiationsVariableName(const AbstractMetaType* type)
{
QString res = QString("_%1").arg(_fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper());
diff --git a/generator/shibokengenerator.h b/generator/shibokengenerator.h
index 05e5bd929..00de95860 100644
--- a/generator/shibokengenerator.h
+++ b/generator/shibokengenerator.h
@@ -309,6 +309,9 @@ public:
bool isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const;
bool isValueTypeWithCopyConstructorOnly(const AbstractMetaType* type) const;
+ /// Returns true if the type is a primitive but not a C++ primitive.
+ static bool isUserPrimitive(const TypeEntry* type);
+ static bool isUserPrimitive(const AbstractMetaType* type);
/// Checks if an argument type should be dereferenced by the Python method wrapper before calling the C++ method.
static bool shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg);
@@ -317,6 +320,9 @@ public:
static bool visibilityModifiedToPrivate(const AbstractMetaFunction* func);
+ QString converterObject(const AbstractMetaType* type);
+ QString converterObject(const TypeEntry* type);
+
QString cpythonBaseName(const AbstractMetaClass* metaClass);
QString cpythonBaseName(const TypeEntry* type);
QString cpythonBaseName(const AbstractMetaType* type);
@@ -404,6 +410,7 @@ public:
/// Returns true if the generated code should use the "#define protected public" hack.
bool avoidProtectedHack() const;
QString cppApiVariableName(const QString& moduleName = QString()) const;
+ QString convertersVariableName(const QString& moduleName = QString()) const;
/**
* Returns the type index variable name for a given class. If \p alternativeTemplateName is true
* and the class is a typedef for a template class instantiation, it will return an alternative name
@@ -490,6 +497,9 @@ protected:
/// Returns all extended conversions for the current module.
ExtendedConverterData getExtendedConverters() const;
+ /// Returns a list of converters for the non wrapper types of the current module.
+ QList<const CustomConversion*> getNonWrapperCustomConversions();
+
/// Returns true if the Python wrapper for the received OverloadData must accept a list of arguments.
static bool pythonFunctionWrapperUsesListOfArguments(const OverloadData& overloadData);
diff --git a/libshiboken/sbkconverter.cpp b/libshiboken/sbkconverter.cpp
index b252e16c7..c5e64f3dd 100644
--- a/libshiboken/sbkconverter.cpp
+++ b/libshiboken/sbkconverter.cpp
@@ -41,7 +41,8 @@ static SbkConverter* createConverterObject(PyTypeObject* type,
converter->pointerToPython = pointerToPythonFunc;
converter->copyToPython = copyToPythonFunc;
- converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc);
+ if (toCppPointerCheckFunc && toCppPointerConvFunc)
+ converter->toCppPointerConversion = std::make_pair(toCppPointerCheckFunc, toCppPointerConvFunc);
converter->toCppConversions.clear();
return converter;
@@ -60,6 +61,11 @@ SbkConverter* createConverter(SbkObjectType* type,
return converter;
}
+SbkConverter* createConverter(PyTypeObject* type, CppToPythonFunc toPythonFunc)
+{
+ return createConverterObject(type, 0, 0, 0, toPythonFunc);
+}
+
void deleteConverter(SbkConverter* converter)
{
if (converter) {
@@ -178,16 +184,27 @@ void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut)
*((void**)cppOut) = (pyIn == Py_None) ? 0 : cppPointer((PyTypeObject*)type, (SbkObject*)pyIn);
}
-void pythonToCppCopy(SbkObjectType* type, PyObject* pyIn, void* cppOut)
+static void _pythonToCppCopy(SbkConverter* converter, PyObject* pyIn, void* cppOut)
{
- assert(type);
+ assert(converter);
assert(pyIn);
assert(cppOut);
- PythonToCppFunc toCpp = IsPythonToCppConvertible(type->d->converter, pyIn);
+ PythonToCppFunc toCpp = IsPythonToCppConvertible(converter, pyIn);
if (toCpp)
toCpp(pyIn, cppOut);
}
+void pythonToCppCopy(SbkObjectType* type, PyObject* pyIn, void* cppOut)
+{
+ assert(type);
+ _pythonToCppCopy(type->d->converter, pyIn, cppOut);
+}
+
+void pythonToCpp(SbkConverter* converter, PyObject* pyIn, void* cppOut)
+{
+ _pythonToCppCopy(converter, pyIn, cppOut);
+}
+
bool isImplicitConversion(SbkObjectType* type, PythonToCppFunc toCppFunc)
{
// This is the Object Type or Value Type conversion that only
diff --git a/libshiboken/sbkconverter.h b/libshiboken/sbkconverter.h
index d7be25776..1d5392488 100644
--- a/libshiboken/sbkconverter.h
+++ b/libshiboken/sbkconverter.h
@@ -102,6 +102,14 @@ LIBSHIBOKEN_API SbkConverter* createConverter(SbkObjectType* type,
CppToPythonFunc pointerToPythonFunc,
CppToPythonFunc copyToPythonFunc = 0);
+/**
+ * Creates a converter for a non wrapper type (primitive or container type).
+ * \param type Python type representing to the new converter.
+ * \param toPythonFunc Function to convert a C++ object to a Python \p type.
+ * \returns A new type converter.
+ */
+LIBSHIBOKEN_API SbkConverter* createConverter(PyTypeObject* type, CppToPythonFunc toPythonFunc);
+
LIBSHIBOKEN_API void deleteConverter(SbkConverter* converter);
/**
@@ -187,6 +195,9 @@ LIBSHIBOKEN_API void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, voi
/// 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);
+/// Converts a Python object \p pyIn to C++, copying the result in the C++ variable passed in \p cppOut.
+LIBSHIBOKEN_API void pythonToCpp(SbkConverter* converter, PyObject* pyIn, void* cppOut);
+
/**
* Helper function returned by generated convertible checking functions
* that returns a C++ NULL when the input Python object is None.
diff --git a/libshiboken/sbkmodule.cpp b/libshiboken/sbkmodule.cpp
index 83c431cde..6f3594e77 100644
--- a/libshiboken/sbkmodule.cpp
+++ b/libshiboken/sbkmodule.cpp
@@ -32,8 +32,12 @@
/// This hash maps module objects to arrays of Python types.
typedef google::dense_hash_map<PyObject*, PyTypeObject**> ModuleTypesMap;
+/// This hash maps module objects to arrays of converters.
+typedef google::dense_hash_map<PyObject*, SbkConverter**> ModuleConvertersMap;
+
/// All types produced in imported modules are mapped here.
static ModuleTypesMap moduleTypes;
+static ModuleConvertersMap moduleConverters;
namespace Shiboken
{
@@ -45,6 +49,8 @@ void init()
// Initializes type registry for modules.
moduleTypes.set_empty_key((ModuleTypesMap::key_type)0);
moduleTypes.set_deleted_key((ModuleTypesMap::key_type)1);
+ moduleConverters.set_empty_key((ModuleConvertersMap::key_type)0);
+ moduleConverters.set_deleted_key((ModuleConvertersMap::key_type)1);
}
PyObject* import(const char* moduleName)
@@ -85,4 +91,17 @@ PyTypeObject** getTypes(PyObject* module)
return (iter == moduleTypes.end()) ? 0 : iter->second;
}
+void registerTypeConverters(PyObject* module, SbkConverter** converters)
+{
+ ModuleConvertersMap::iterator iter = moduleConverters.find(module);
+ if (iter == moduleConverters.end())
+ moduleConverters.insert(std::make_pair(module, converters));
+}
+
+SbkConverter** getTypeConverters(PyObject* module)
+{
+ ModuleConvertersMap::iterator iter = moduleConverters.find(module);
+ return (iter == moduleConverters.end()) ? 0 : iter->second;
+}
+
} } // namespace Shiboken::Module
diff --git a/libshiboken/sbkmodule.h b/libshiboken/sbkmodule.h
index f089ad8d4..cb5656fca 100644
--- a/libshiboken/sbkmodule.h
+++ b/libshiboken/sbkmodule.h
@@ -42,6 +42,11 @@
}
#endif
+extern "C"
+{
+struct SbkConverter;
+}
+
namespace Shiboken {
namespace Module {
@@ -74,6 +79,20 @@ LIBSHIBOKEN_API void registerTypes(PyObject* module, PyTypeObject** types);
*/
LIBSHIBOKEN_API PyTypeObject** getTypes(PyObject* module);
+/**
+ * Registers the list of converters created by \p module for non-wrapper types.
+ * \param module Module where the converters were created.
+ * \param converters Array of SbkConverter* objects representing the converters created on \p module.
+ */
+LIBSHIBOKEN_API void registerTypeConverters(PyObject* module, SbkConverter** converters);
+
+/**
+ * Retrieves the array of converters.
+ * \param module Module where the converters were created.
+ * \returns A pointer to the SbkConverter* array of converters.
+ */
+LIBSHIBOKEN_API SbkConverter** getTypeConverters(PyObject* module);
+
} } // namespace Shiboken::Module
#endif // SBK_MODULE_H
diff --git a/tests/minimalbinding/typesystem_minimal.xml b/tests/minimalbinding/typesystem_minimal.xml
index 1b6f18de4..d4f673d2d 100644
--- a/tests/minimalbinding/typesystem_minimal.xml
+++ b/tests/minimalbinding/typesystem_minimal.xml
@@ -4,8 +4,17 @@
<primitive-type name="int"/>
<primitive-type name="MinBool" target-lang-api-name="PyBool" default-constructor="MinBool(false)">
- <conversion-rule file="minbool_conversions.h"/>
<include file-name="minbool.h" location="global"/>
+ <conversion-rule file="minbool_conversions.h">
+ <native-to-target>
+ return PyBool_FromLong(%in.value());
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyBool" check="PyBool_Check(%in)">
+ %out = %OUTTYPE(%in == Py_True);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</primitive-type>
<container-type name="std::list" type="list">
@@ -20,4 +29,3 @@
<value-type name="ListUser"/>
<value-type name="MinBoolUser"/>
</typesystem>
-
diff --git a/tests/samplebinding/oddbool_test.py b/tests/samplebinding/oddbool_test.py
index 43727d65b..12b7a5a49 100644
--- a/tests/samplebinding/oddbool_test.py
+++ b/tests/samplebinding/oddbool_test.py
@@ -62,6 +62,12 @@ class OddBoolTest(unittest.TestCase):
self.assertTrue(obu.oddBool())
obu = OddBoolUser(False)
self.assertFalse(obu.oddBool())
+ cpx = complex(1.0, 0.0)
+ obu = OddBoolUser(cpx)
+ self.assertTrue(obu.oddBool())
+ cpx = complex(0.0, 0.0)
+ obu = OddBoolUser(cpx)
+ self.assertFalse(obu.oddBool())
if __name__ == '__main__':
unittest.main()
diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml
index 122456184..ec4ace7d7 100644
--- a/tests/samplebinding/typesystem_sample.xml
+++ b/tests/samplebinding/typesystem_sample.xml
@@ -19,25 +19,85 @@
<primitive-type name="std::string"/>
<primitive-type name="std::size_t" target-lang-api-name="PyLong">
+ <conversion-rule>
+ <native-to-target>
+ return PyLong_FromSize_t(%in);
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyLong">
+ %out = %OUTTYPE(PyLong_AsSsize_t(%in));
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</primitive-type>
+
<primitive-type name="Complex" target-lang-api-name="PyComplex">
- <conversion-rule file="complex_conversions.h"/>
<include file-name="complex.h" location="global"/>
+ <conversion-rule file="complex_conversions.h">
+ <native-to-target>
+ return PyComplex_FromDoubles(%in.real(), %in.imag());
+ </native-to-target>
+ <target-to-native>
+ <!-- The 'check' attribute can be derived from the 'type' attribute,
+ it is defined here to test the CHECKTYPE type system variable. -->
+ <add-conversion type="PyComplex" check="%CHECKTYPE[Complex](%in)">
+ double real = PyComplex_RealAsDouble(%in);
+ double imag = PyComplex_ImagAsDouble(%in);
+ %out = %OUTTYPE(real, imag);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</primitive-type>
<primitive-type name="Null">
- <conversion-rule file="null_conversions.h"/>
<include file-name="null.h" location="global"/>
+ <conversion-rule file="null_conversions.h">
+ <native-to-target>
+ SBK_UNUSED(%in);
+ Py_RETURN_NONE;
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyObject" check="%in == 0 || %in == Py_None">
+ %out = %OUTTYPE(%in == 0);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</primitive-type>
- <primitive-type name="HANDLE">
- <conversion-rule file="handle_conversions.h"/>
+ <primitive-type name="HANDLE" target-lang-api-name="PyComplex">
<include file-name="handle.h" location="local"/>
+ <conversion-rule file="handle_conversions.h">
+ <native-to-target>
+ return PyCObject_FromVoidPtr(%in, 0);
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyCObject">
+ %out = (%OUTTYPE)PyCObject_AsVoidPtr(%in);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</primitive-type>
<primitive-type name="OddBool" target-lang-api-name="PyBool" default-constructor="OddBool(false)">
- <conversion-rule file="oddbool_conversions.h"/>
<include file-name="oddbool.h" location="global"/>
+ <include file-name="complex.h" location="global"/>
+ <conversion-rule file="oddbool_conversions.h">
+ <native-to-target>
+ return PyBool_FromLong(%in.value());
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyBool">
+ // Tests CONVERTTOCPP macro with C++ primitive type.
+ bool b = %CONVERTTOCPP[bool](%in);
+ %out = %OUTTYPE(b);
+ </add-conversion>
+ <add-conversion type="PyComplex">
+ // Tests CONVERTTOCPP macro with user's primitive type.
+ Complex cpx = %CONVERTTOCPP[Complex](%in);
+ %out = %OUTTYPE(cpx.real() != 0.0 || cpx.imag() != 0.0);
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</primitive-type>
<container-type name="std::pair" type="pair">
@@ -1559,10 +1619,10 @@
<value-type name="ByteArray" hash-function="ByteArray::hash">
<conversion-rule file="bytearray_conversions.h">
<target-to-native>
- <add-conversion type='Py_None' check='%in == Py_None'>
+ <add-conversion type="Py_None">
%out = %OUTTYPE();
</add-conversion>
- <add-conversion type='PyString' check='PyString_Check(%in)'>
+ <add-conversion type="PyString">
%out = %OUTTYPE(PyString_AS_STRING(%in), PyString_GET_SIZE(%in));
</add-conversion>
</target-to-native>
@@ -1811,7 +1871,7 @@
</inject-code>
<conversion-rule class="target" file="date_conversions.h">
<target-to-native>
- <add-conversion type='PyDate' check='PyDate_ImportAndCheck(%in)'>
+ <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);