summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generator/cppgenerator.cpp282
-rw-r--r--generator/cppgenerator.h8
-rw-r--r--generator/headergenerator.cpp14
-rw-r--r--generator/shibokengenerator.cpp164
-rw-r--r--generator/shibokengenerator.h8
-rw-r--r--libshiboken/sbkconverter.cpp122
-rw-r--r--libshiboken/sbkconverter.h22
-rw-r--r--libshiboken/tmp-referencetopython/sbkconverter.cpp196
-rw-r--r--libshiboken/tmp-referencetopython/sbkconverter.h174
-rw-r--r--tests/libsample/list.h16
-rw-r--r--tests/libsample/photon.cpp8
-rw-r--r--tests/libsample/photon.h14
-rw-r--r--tests/libsample/samplenamespace.h4
-rw-r--r--tests/libsample/strlist.cpp1
-rw-r--r--tests/libsample/strlist.h20
-rw-r--r--tests/minimalbinding/typesystem_minimal.xml21
-rw-r--r--tests/samplebinding/CMakeLists.txt1
-rw-r--r--tests/samplebinding/intlist_test.py32
-rw-r--r--tests/samplebinding/strlist_test.py17
-rw-r--r--tests/samplebinding/typesystem_sample.xml95
20 files changed, 1076 insertions, 143 deletions
diff --git a/generator/cppgenerator.cpp b/generator/cppgenerator.cpp
index cb59b809..a7b6ad14 100644
--- a/generator/cppgenerator.cpp
+++ b/generator/cppgenerator.cpp
@@ -603,7 +603,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
((func->name() == "metaObject") || (func->name() == "qt_metacall")))
return;
- const TypeEntry* type = func->type() ? func->type()->typeEntry() : 0;
+ const TypeEntry* retType = func->type() ? func->type()->typeEntry() : 0;
const QString funcName = func->isOperatorOverload() ? pythonOperatorFunctionName(func) : func->name();
QString prefix = QString("%1::").arg(wrapperName(func->ownerClass()));
@@ -613,7 +613,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
Indentation indentation(INDENT);
QString defaultReturnExpr;
- if (func->type()) {
+ if (retType) {
foreach (FunctionModification mod, func->modifications()) {
foreach (ArgumentModification argMod, mod.argument_mods) {
if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) {
@@ -685,7 +685,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
s << func->ownerClass()->name() << '.' << funcName;
s << "()' not implemented.\");" << endl;
- s << INDENT << "return " << (func->type() ? defaultReturnExpr : "");
+ s << INDENT << "return " << (retType ? defaultReturnExpr : "");
} else {
s << INDENT << "gil.release();" << endl;
s << INDENT << "return this->::" << func->implementingClass()->qualifiedCppName() << "::";
@@ -792,15 +792,16 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
}
s << INDENT << '}' << endl;
- if (type) {
+ if (retType) {
if (invalidateReturn)
s << INDENT << "bool invalidateArg0 = " PYTHON_RETURN_VAR "->ob_refcnt == 1;" << endl;
- if (func->type() && func->typeReplaced(0) != "PyObject") {
+ if (func->typeReplaced(0) != "PyObject") {
- // TODO-CONVERTER -----------------------------------------------------------------------
- if (func->typeReplaced(0).isEmpty() && (isWrapperType(func->type()) || isUserPrimitive(func->type()) || isCppPrimitive(func->type()))) {
- s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR " = " << cpythonIsConvertibleFunction(func->type());
+ s << INDENT << "// Check return type" << endl;
+ s << INDENT;
+ if (func->typeReplaced(0).isEmpty() && !retType->isEnum() && !retType->isFlags()) {
+ s << "PythonToCppFunc " PYTHON_TO_CPP_VAR " = " << cpythonIsConvertibleFunction(func->type());
s << PYTHON_RETURN_VAR ");" << endl;
s << INDENT << "if (!" PYTHON_TO_CPP_VAR ") {" << endl;
{
@@ -820,7 +821,6 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
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;
@@ -874,11 +874,10 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
writeCodeSnips(s, snips, CodeSnip::End, TypeSystem::NativeCode, func, lastArg);
}
- if (type) {
+ if (retType) {
s << INDENT << "return ";
- // TODO-IMPROVEMENTS: try to put this on writePythonToCppTypeConversion.
- if (avoidProtectedHack() && type->isEnum()) {
- const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(type);
+ if (avoidProtectedHack() && retType->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(retType);
bool isProtectedEnum = metaEnum && metaEnum->isProtected();
if (isProtectedEnum) {
QString typeCast;
@@ -888,12 +887,8 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << '(' << typeCast << ')';
}
}
- // TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(type)) {
- if (func->type()->isReference() && !isPointer(func->type()))
- s << '*';
- }
- // TODO-CONVERTER -----------------------------------------------------------------------
+ if (func->type()->isReference() && !isPointer(func->type()))
+ s << '*';
s << CPP_RETURN_VAR ";" << endl;
}
@@ -1055,7 +1050,6 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla
if (!conv->typeReplaced(1).isEmpty())
continue;
const AbstractMetaType* sourceType = conv->arguments().first()->type();
- // TODO-CONVERTER -----------------------------------------------------------------------
typeCheck = cpythonCheckFunction(sourceType);
if (isWrapperType(sourceType)) {
typeCheck = QString("%1pyIn)").arg(typeCheck);
@@ -1066,10 +1060,20 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla
typeCheck.replace("%in", "pyIn");
typeCheck = QString("(%1)").arg(typeCheck);
} else {
- typeCheck = QString("%1(pyIn)").arg(typeCheck);
+ typeCheck = QString("%1%2pyIn)")
+ .arg(typeCheck)
+ .arg(sourceType->typeEntry()->isContainer() ? "" : "(");
}
-
- if (isUserPrimitive(sourceType) || isCppPrimitive(sourceType)) {
+ //QTextStream pc(&toCppPreConv);
+ //pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn";
+ //qDebug() << sourceType->cppSignature();
+ //writeMinimalConstructorExpression(pc, sourceType);
+ //pc << ';' << endl;
+ //writeToCppConversion(pc, sourceType, 0, "pyIn", "cppIn");
+ //pc << ';';
+ //toCppConv.append("cppIn");
+
+ if (isUserPrimitive(sourceType) || isCppPrimitive(sourceType) || sourceType->typeEntry()->isContainer()) {
QTextStream pc(&toCppPreConv);
pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn";
writeMinimalConstructorExpression(pc, sourceType);
@@ -1081,7 +1085,8 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla
QTextStream tcc(&toCppConv);
writeToCppConversion(tcc, sourceType, metaClass, "pyIn", "/*BOZO-1061*/");
}
- // TODO-CONVERTER -----------------------------------------------------------------------
+
+
}
const AbstractMetaType* sourceType = conv->isConversionOperator()
? buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass())
@@ -1192,6 +1197,21 @@ void CppGenerator::writeCustomConverterRegister(QTextStream& s, const CustomConv
}
}
+void CppGenerator::writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar)
+{
+ s << INDENT << "// Add user defined container conversion to type converter." << endl;
+ QString typeName = fixedCppTypeName(container);
+ QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+}
+
+void CppGenerator::writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType)
+{
+ writeCppToPythonFunction(s, containerType);
+ writePythonToCppConversionFunctions(s, containerType);
+}
+
void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& overloadData)
{
const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
@@ -1646,13 +1666,13 @@ void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunc
if (func->isOperatorOverload() && func->isBinaryOperator()) {
QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry());
- s << INDENT << "bool isReverse = " << checkFunc << /*TODO-CONVERTER "("*/ PYTHON_ARG ")" << endl;
+ s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG ")" << endl;
{
Indentation indent1(INDENT);
Indentation indent2(INDENT);
Indentation indent3(INDENT);
Indentation indent4(INDENT);
- s << INDENT << "&& !" << checkFunc << /*TODO-CONVERTER "("*/ PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "&& !" << checkFunc << PYTHON_SELF_VAR ");" << endl;
}
s << INDENT << "if (isReverse)" << endl;
Indentation indent(INDENT);
@@ -1792,7 +1812,7 @@ void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argTyp
typeCheck.append(QString("(%1)").arg(argumentName));
// TODO-CONVERTER -----------------------------------------------------------------------
- if (customCheck.isEmpty() && (isWrapperType(argType) || isUserPrimitive(argType) || isCppPrimitive(argType))) {
+ if (customCheck.isEmpty() && (isWrapperType(argType) || isUserPrimitive(argType) || isCppPrimitive(argType) || argType->typeEntry()->isContainer())) {
typeCheck = QString("(%1 = %2))").arg(pythonToCppConverterForArgumentName(argumentName)).arg(typeCheck);
if (!isNumber && argType->typeEntry()->isCppPrimitive())
typeCheck.prepend(QString("/*BOZOisNumber*/ %1(%2) && ").arg(cpythonCheckFunction(argType)).arg(argumentName));
@@ -1881,13 +1901,14 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s,
QString cppOutAux = QString("%1_local").arg(cppOut);
// TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(type) || isUserPrimitive(type) || isCppPrimitive(type)) {
+ if (!type->typeEntry()->isEnum() && !type->typeEntry()->isFlags()) {
bool treatAsPointer = isValueTypeWithCopyConstructorOnly(type);
bool isPointerOrObjectType = (isObjectType(type) || isPointer(type)) && /*TODO-CONVERTERS: is this really needed?*/ !isUserPrimitive(type) && !isCppPrimitive(type);
bool mayHaveImplicitConversion = type->isReference()
&& !isUserPrimitive(type)
&& !isCppPrimitive(type)
+ && !type->typeEntry()->isContainer()
&& !(treatAsPointer || isPointerOrObjectType);
QString typeName = getFullTypeNameWithoutModifiers(type);
if (mayHaveImplicitConversion) {
@@ -1899,7 +1920,7 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s,
s << INDENT << typeName;
if (treatAsPointer || isPointerOrObjectType) {
s << "* " << cppOut << (defaultValue.isEmpty() ? "" : QString(" = %1").arg(defaultValue));
- } else if (type->isReference() && !type->typeEntry()->isPrimitive()) {
+ } else if (type->isReference() && !type->typeEntry()->isPrimitive() && !type->typeEntry()->isContainer()) {
s << "* " << cppOut << " = &" << cppOutAux;
} else {
s << ' ' << cppOut;
@@ -1947,7 +1968,7 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s,
QString conversion;
QTextStream c(&conversion);
- writeToCppConversion(c, type, context, pyIn, "/*BOZO-1925*/");
+ writeToCppConversion(c, type, context, pyIn, "/*BOZO-1944*/");
// Value type that has default value.
if (type->isValue() && !defaultValue.isEmpty())
@@ -2130,6 +2151,17 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const Ov
pyArgName = QString(PYTHON_ARGS "[%1]").arg(od->argPos());
QString typeCheck;
QTextStream tck(&typeCheck);
+ const AbstractMetaFunction* func = od->referenceFunction();
+
+ if (func->isConstructor() && func->arguments().count() == 1) {
+ const AbstractMetaClass* ownerClass = func->ownerClass();
+ const ComplexTypeEntry* baseContainerType = ownerClass->typeEntry()->baseContainerType();
+ if (baseContainerType && baseContainerType == func->arguments().first()->type()->typeEntry() && isCopyable(ownerClass)) {
+ tck << '!' << cpythonCheckFunction(ownerClass->typeEntry()) << pyArgName << ')' << endl;
+ Indentation indent(INDENT);
+ tck << INDENT << "&& ";
+ }
+ }
writeTypeCheck(tck, od, pyArgName);
typeChecks << typeCheck;
}
@@ -2196,7 +2228,8 @@ void CppGenerator::writeFunctionCalls(QTextStream& s, const OverloadData& overlo
} else {
for (int i = 0; i < overloads.count(); i++) {
const AbstractMetaFunction* func = overloads.at(i);
- s << INDENT << "case " << i << ": // " << func->minimalSignature() << endl;
+ //s << INDENT << "case " << i << ": // " << func->minimalSignature() << endl;
+ s << INDENT << "case " << i << ": // " << func->signature() << endl;
s << INDENT << '{' << endl;
{
Indentation indent(INDENT);
@@ -2324,17 +2357,40 @@ void CppGenerator::writeCppToPythonFunction(QTextStream& s, const QString& code,
s << prettyCode;
s << '}' << endl;
}
-void CppGenerator::writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion)
+
+static void replaceCppToPythonVariables(QString& code, const QString& typeName)
{
- 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.prepend(QString("%1& cppInRef = *((%1*)cppIn);\n").arg(typeName));
+ code.replace("%INTYPE", typeName);
code.replace("%OUTTYPE", "PyObject*");
code.replace("%in", "cppInRef");
code.replace("%out", "pyOut");
+}
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion)
+{
+ QString code = customConversion->nativeToTargetConversion();
+ replaceCppToPythonVariables(code, getFullTypeName(customConversion->ownerType()));
writeCppToPythonFunction(s, code, fixedCppTypeName(customConversion->ownerType()));
}
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const AbstractMetaType* containerType)
+{
+ const CustomConversion* customConversion = containerType->typeEntry()->customConversion();
+ if (!customConversion) {
+ qFatal(qPrintable(QString("Can't write the C++ to Python conversion function for container type '%1' - "\
+ "no conversion rule was defined for it in the type system.")
+ .arg(containerType->typeEntry()->qualifiedCppName())), NULL);
+ }
+ if (!containerType->typeEntry()->isContainer()) {
+ writeCppToPythonFunction(s, customConversion);
+ return;
+ }
+ QString code = customConversion->nativeToTargetConversion();
+ for (int i = 0; i < containerType->instantiations().count(); ++i)
+ code.replace(QString("%INTYPE_%1").arg(i), getFullTypeName(containerType->instantiations().at(i)));
+ replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType));
+ processCodeSnip(code);
+ writeCppToPythonFunction(s, code, fixedCppTypeName(containerType));
+}
void CppGenerator::writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName)
{
@@ -2390,8 +2446,8 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
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())
+ c << INDENT << QString("*((%1*)cppOut) = %1(%2);")
+ .arg(getFullTypeName(targetType->typeEntry()))
.arg(conversion);
QString sourceTypeName = fixedCppTypeName(sourceType);
QString targetTypeName = fixedCppTypeName(targetType);
@@ -2418,7 +2474,7 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
code.replace("%INTYPE", inType);
code.replace("%OUTTYPE", targetType->qualifiedCppName());
code.replace("%in", "pyIn");
- code.replace("%out", QString("*((::%1*)cppOut)").arg(targetType->qualifiedCppName()));
+ code.replace("%out", QString("*((%1*)cppOut)").arg(getFullTypeName(targetType)));
QString sourceTypeName = fixedCppTypeName(toNative);
QString targetTypeName = fixedCppTypeName(targetType);
@@ -2455,6 +2511,59 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
}
+void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, const AbstractMetaType* containerType)
+{
+ const CustomConversion* customConversion = containerType->typeEntry()->customConversion();
+ if (!customConversion) {
+ //qFatal
+ return;
+ }
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty()) {
+ //qFatal
+ return;
+ }
+ // Python to C++ conversion function.
+ QString cppTypeName = getFullTypeNameWithoutModifiers(containerType);
+ QString code;
+ QTextStream c(&code);
+ c << INDENT << QString("%1& cppOutRef = *((%1*)cppOut);").arg(cppTypeName) << endl;
+ code.append(toCppConversions.first()->conversion());
+ for (int i = 0; i < containerType->instantiations().count(); ++i) {
+ const AbstractMetaType* type = containerType->instantiations().at(i);
+ QString typeName = getFullTypeName(type);
+ if (type->isValue() && isValueTypeWithCopyConstructorOnly(type)) {
+ static QRegExp regex(CONVERTTOCPP_REGEX);
+ int pos = 0;
+ while ((pos = regex.indexIn(code, pos)) != -1) {
+ pos += regex.matchedLength();
+ QStringList list = regex.capturedTexts();
+ QString varName = list.at(1);
+ QString leftCode = code.left(pos);
+ QString rightCode = code.mid(pos);
+ rightCode.replace(varName, "*"+varName);
+ code = leftCode + rightCode;
+ }
+ typeName.append('*');
+ }
+ code.replace(QString("%OUTTYPE_%1").arg(i), typeName);
+ }
+ code.replace("%OUTTYPE", cppTypeName);
+ code.replace("%in", "pyIn");
+ code.replace("%out", "cppOutRef");
+ QString typeName = fixedCppTypeName(containerType);
+ writePythonToCppFunction(s, code, typeName, typeName);
+
+ // Python to C++ convertible check function.
+ QString typeCheck = cpythonCheckFunction(containerType);
+ if (typeCheck.isEmpty())
+ typeCheck = "false";
+ else
+ typeCheck = QString("%1pyIn)").arg(typeCheck);
+ writeIsPythonConvertibleToCppFunction(s, typeName, typeName, typeCheck);
+ s << endl;
+}
+
void CppGenerator::writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc)
{
s << INDENT << "Shiboken::Conversions::addPythonToCppValueConversion(" << converterVar << ',' << endl;
@@ -2974,6 +3083,25 @@ void CppGenerator::writePrimitiveConverterInitialization(QTextStream& s, const C
writeCustomConverterRegister(s, customConversion, converterObject(type));
}
+void CppGenerator::writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type)
+{
+ s << INDENT << "// Register converter for type '" << type->cppSignature() << "'." << endl;
+ s << INDENT << converterObject(type) << " = Shiboken::Conversions::createConverter(";
+ if (type->typeEntry()->targetLangApiName() == "PyObject") {
+ s << "&PyBaseObject_Type";
+ } else {
+ QString baseName = cpythonBaseName(type->typeEntry());
+ if (baseName == "PySequence")
+ baseName = "PyList";
+ s << '&' << baseName << "_Type";
+ }
+ QString typeName = fixedCppTypeName(type);
+ s << ", " << cppToPythonFunctionName(typeName, typeName) << ");" << endl;
+ QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ writeAddPythonToCppConversion(s, converterObject(type), toCpp, isConv);
+}
+
void CppGenerator::writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions)
{
s << INDENT << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl;
@@ -3466,11 +3594,8 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField*
AbstractMetaType* fieldType = metaField->type();
- // TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(fieldType) || isUserPrimitive(fieldType) || isCppPrimitive(fieldType)) {
+ if (!fieldType->typeEntry()->isEnum() && !fieldType->typeEntry()->isFlags())
s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
- }
- // TODO-CONVERTER -----------------------------------------------------------------------
s << INDENT << "if (!";
writeTypeCheck(s, fieldType, "pyIn", isNumber(fieldType->typeEntry()));
@@ -3483,40 +3608,27 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField*
}
s << INDENT << '}' << endl << endl;
- // TODO-CONVERTER -----------------------------------------------------------------------
QString cppField = QString("%1->%2").arg(CPP_SELF_VAR).arg(metaField->name());
s << INDENT;
- if (isWrapperType(fieldType) || isUserPrimitive(fieldType) || isCppPrimitive(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 if (isCppIntegralPrimitive(fieldType)) {
- s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl;
- s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);" << endl;
- s << INDENT << cppField << " = cppOut_local;" << endl;
- } else {
- s << PYTHON_TO_CPP_VAR << "(pyIn, &(" << cppField << "))";
- }
- } 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;
+ 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 if (isCppIntegralPrimitive(fieldType)) {
+ s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl;
+ s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);" << endl;
+ s << INDENT << cppField << " = cppOut_local;" << endl;
+ } else if (fieldType->typeEntry()->isEnum() || fieldType->typeEntry()->isFlags()) {
+ s << cppField << " = ";
+ writeToCppConversion(s, fieldType, metaField->enclosingClass(), "pyIn", "");
+ } else {
+ //s << PYTHON_TO_CPP_VAR << "(pyIn, &(" << cppField << "))";
+ writeToCppConversion(s, fieldType, metaField->enclosingClass(), "pyIn", cppField);
}
s << ';' << endl << endl;
- // TODO-CONVERTER -----------------------------------------------------------------------
if (isPointerToWrapperType(fieldType)) {
s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
@@ -4469,12 +4581,12 @@ void CppGenerator::finishGeneration()
delete targetType;
}
}
- s << endl;
+ //s << endl;
}
- QList<const CustomConversion*> typeConversions = getNonWrapperCustomConversions();
+ QList<const CustomConversion*> typeConversions = getPrimitiveCustomConversions();
if (!typeConversions.isEmpty()) {
- s << endl << "// Primitive and Container Type converters." << endl << endl;
+ s << endl << "// Primitive Type converters." << endl << endl;
foreach (const CustomConversion* conversion, typeConversions) {
s << "// C++ to Python conversion for type '" << conversion->ownerType()->qualifiedCppName() << "'." << endl;
writeCppToPythonFunction(s, conversion);
@@ -4483,6 +4595,16 @@ void CppGenerator::finishGeneration()
s << endl;
}
+ QList<const AbstractMetaType*> containers = instantiatedContainers();
+ if (!containers.isEmpty()) {
+ s << "// Container Type converters." << endl << endl;
+ foreach (const AbstractMetaType* container, containers) {
+ s << "// C++ to Python conversion for type '" << container->cppSignature() << "'." << endl;
+ writeContainerConverterFunctions(s, container);
+ }
+ s << endl;
+ }
+
s << "#if defined _WIN32 || defined __CYGWIN__" << endl;
s << " #define SBK_EXPORT_MODULE __declspec(dllexport)" << endl;
s << "#elif __GNUC__ >= 4" << endl;
@@ -4561,6 +4683,14 @@ void CppGenerator::finishGeneration()
}
}
+ if (!containers.isEmpty()) {
+ s << endl;
+ foreach (const AbstractMetaType* container, containers) {
+ writeContainerConverterInitialization(s, container);
+ s << endl;
+ }
+ }
+
if (!extendedConverters.isEmpty()) {
s << endl;
foreach (const TypeEntry* externalType, extendedConverters.keys()) {
diff --git a/generator/cppgenerator.h b/generator/cppgenerator.h
index 86f434cf..1f493155 100644
--- a/generator/cppgenerator.h
+++ b/generator/cppgenerator.h
@@ -55,6 +55,9 @@ private:
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 writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar);
+
+ void writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType);
void writeMethodWrapperPreamble(QTextStream& s, OverloadData& overloadData);
void writeConstructorWrapper(QTextStream& s, const AbstractMetaFunctionList overloads);
@@ -164,6 +167,7 @@ private:
/// 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);
+ void writeCppToPythonFunction(QTextStream& s, const AbstractMetaType* containerType);
/// Writes a Python to C++ conversion function.
void writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName);
@@ -188,6 +192,9 @@ private:
const CustomConversion::TargetToNativeConversion* toNative,
const TypeEntry* targetType);
+ /// Writes a pair of Python to C++ conversion and check functions for instantiated container types.
+ void writePythonToCppConversionFunctions(QTextStream& s, const AbstractMetaType* containerType);
+
void writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc);
void writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs);
@@ -242,6 +249,7 @@ private:
void writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass);
void writePrimitiveConverterInitialization(QTextStream& s, const CustomConversion* customConversion);
+ void writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type);
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 2b32138f..f98931e3 100644
--- a/generator/headergenerator.cpp
+++ b/generator/headergenerator.cpp
@@ -376,6 +376,20 @@ void HeaderGenerator::finishGeneration()
_writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(ptype), pCount);
pCount++;
}
+
+ foreach (const AbstractMetaType* container, instantiatedContainers()) {
+ //_writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(container), pCount);
+ // DEBUG
+ QString variableName = getTypeIndexVariableName(container);
+ macrosStream << "#define ";
+ macrosStream.setFieldWidth(60);
+ macrosStream << variableName;
+ macrosStream.setFieldWidth(0);
+ macrosStream << ' ' << pCount << " // " << container->cppSignature() << endl;
+ // DEBUG
+ pCount++;
+ }
+
// Because on win32 the compiler will not accept a zero length array.
if (pCount == 0)
pCount++;
diff --git a/generator/shibokengenerator.cpp b/generator/shibokengenerator.cpp
index e8297d30..924018ee 100644
--- a/generator/shibokengenerator.cpp
+++ b/generator/shibokengenerator.cpp
@@ -81,13 +81,10 @@ 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[TypeSystemToPythonFunction] = QRegExp("%CONVERTTOPYTHON\\[([^\\[]*)\\]\\(");
- m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegExp("(\\s*//[^\\n]*\\n\\s*)*"
- "((?:[a-zA-Z_%][\\w%]*\\s*[\\*&]?\\s+)*)"
- "((?:\\*\\s*)?[a-zA-Z_%][\\w%]*(?:\\[[^\\[]+\\])*)"
- "(?:\\s+)=(?:\\s+)%CONVERTTOCPP\\[([^\\[]*)\\]\\(");
+ m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegExp(CHECKTYPE_REGEX);
+ m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegExp(ISCONVERTIBLE_REGEX);
+ m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegExp(CONVERTTOPYTHON_REGEX);
+ m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegExp(CONVERTTOCPP_REGEX);
}
ShibokenGenerator::~ShibokenGenerator()
@@ -595,7 +592,7 @@ void ShibokenGenerator::writeToPythonConversion(QTextStream& s, const AbstractMe
const AbstractMetaClass* context, const QString& argumentName)
{
// TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(type) || isUserPrimitive(type) || isCppPrimitive(type)) {
+ if (!type->typeEntry()->isEnum() && !type->typeEntry()->isFlags()) {
s << cpythonToPythonConversionFunction(type) << argumentName << ')';
return;
}
@@ -606,17 +603,14 @@ void ShibokenGenerator::writeToPythonConversion(QTextStream& s, const AbstractMe
void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass,
const QString& inArgName, const QString& outArgName)
{
- // 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& inArgName, const QString& outArgName)
{
// TODO-CONVERTER -----------------------------------------------------------------------
- if (isWrapperType(type) || isUserPrimitive(type) || isCppPrimitive(type)) {
+ if (!type->typeEntry()->isEnum() && !type->typeEntry()->isFlags()) {
s << cpythonToCppConversionFunction(type, context) << inArgName << ", &" << outArgName << ')';
return;
}
@@ -774,13 +768,16 @@ QString ShibokenGenerator::converterObject(const AbstractMetaType* type)
return "Shiboken::Conversions::PrimitiveTypeConverter<const char*>()";
if (isVoidPointer(type))
return "Shiboken::Conversions::PrimitiveTypeConverter<void*>()";
+ if (type->typeEntry()->isContainer())
+ return QString("%1[%2]").arg(convertersVariableName(type->typeEntry()->targetLangPackage())).arg(getTypeIndexVariableName(type));
return converterObject(type->typeEntry());
}
QString ShibokenGenerator::converterObject(const TypeEntry* type)
{
if (isCppPrimitive(type))
return QString("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName());
- QString converters;
+ if (isWrapperType(type))
+ return QString("Shiboken::ObjectType::getTypeConverter((SbkObjectType*)%1)").arg(cpythonTypeNameExt(type));
return QString("%1[%2]").arg(convertersVariableName(type->targetLangPackage())).arg(getTypeIndexVariableName(type));
}
@@ -812,6 +809,7 @@ static QString _fixedCppTypeName(QString typeName)
{
return typeName.replace(" ", "")
.replace(".", "_")
+ .replace(",", "_")
.replace("<", "_")
.replace(">", "_")
.replace("::", "_")
@@ -1049,7 +1047,45 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType
if (isVoidPointer(metaType))
return "PyObject_Check";
return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
- } else if (isWrapperType(metaType) || isUserPrimitive(metaType)) {
+ } else if (metaType->typeEntry()->isContainer()) {
+ QString typeCheck = "Shiboken::Conversions::";
+ ContainerTypeEntry::Type type = ((const ContainerTypeEntry*)metaType->typeEntry())->type();
+ if (type == ContainerTypeEntry::ListContainer
+ || type == ContainerTypeEntry::StringListContainer
+ || type == ContainerTypeEntry::LinkedListContainer
+ || type == ContainerTypeEntry::VectorContainer
+ || type == ContainerTypeEntry::StackContainer
+ || type == ContainerTypeEntry::SetContainer
+ || type == ContainerTypeEntry::QueueContainer) {
+ const AbstractMetaType* type = metaType->instantiations().first();
+ if (isPointerToWrapperType(type))
+ typeCheck += QString("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type));
+ else if (isWrapperType(type))
+ typeCheck += QString("convertibleSequenceTypes((SbkObjectType*)%1, ").arg(cpythonTypeNameExt(type));
+ else
+ typeCheck += QString("convertibleSequenceTypes(%1, ").arg(converterObject(type));
+ } else if (type == ContainerTypeEntry::MapContainer
+ || type == ContainerTypeEntry::MultiMapContainer
+ || type == ContainerTypeEntry::HashContainer
+ || type == ContainerTypeEntry::MultiHashContainer
+ || type == ContainerTypeEntry::PairContainer) {
+ QString pyType = (type == ContainerTypeEntry::PairContainer) ? "Pair" : "Dict";
+ const AbstractMetaType* firstType = metaType->instantiations().first();
+ const AbstractMetaType* secondType = metaType->instantiations().last();
+ if (isPointerToWrapperType(firstType) && isPointerToWrapperType(secondType)) {
+ typeCheck += QString("check%1Types(%2, %3, ").arg(pyType)
+ .arg(cpythonTypeNameExt(firstType))
+ .arg(cpythonTypeNameExt(secondType));
+ } else {
+ typeCheck += QString("convertible%1Types(%2, %3, %4, %5, ").arg(pyType)
+ .arg(converterObject(firstType))
+ .arg(isPointerToWrapperType(firstType) ? "true" : "false")
+ .arg(converterObject(secondType))
+ .arg(isPointerToWrapperType(secondType) ? "true" : "false");
+ }
+ }
+ return typeCheck;
+ } else if (!metaType->typeEntry()->isEnum() && !metaType->typeEntry()->isFlags()) {
return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
}
// TODO-CONVERTER -----------------------------------------------------------------------
@@ -1084,7 +1120,7 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool gene
return QString("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type));
} else if (isCppPrimitive(type)) {
return QString("%1_Check").arg(pythonPrimitiveTypeName((const PrimitiveTypeEntry*)type));
- } else if (isUserPrimitive(type)) {
+ } else if (!type->isEnum() && !type->isFlags()) {
QString typeCheck;
if (!type->targetLangApiName().isEmpty())
typeCheck = QString("%1_Check").arg(type->targetLangApiName());
@@ -1092,6 +1128,11 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool gene
}
// TODO-CONVERTER -----------------------------------------------------------------------
+ QString typeCheck;
+ if (!type->targetLangApiName().isEmpty())
+ typeCheck = QString("%1_Check").arg(type->targetLangApiName());
+ return typeCheck;
+/*
QString baseName = cpythonBaseName(type);
if (isNumber(baseName))
return genericNumberType ? "SbkNumber_Check" : baseName+"_Check";
@@ -1100,6 +1141,7 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool gene
QTextStream b(&baseName);
writeBaseConversion(b, type);
return QString("%1checkType").arg(baseName);
+*/
}
QString ShibokenGenerator::guessCPythonCheckFunction(const QString& type, AbstractMetaType** metaType)
@@ -1142,7 +1184,7 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type, b
: "isPythonToCppPointerConvertible";
return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ")
.arg(isConv).arg(cpythonTypeNameExt(type));
- } else if (isUserPrimitive(type) || isCppPrimitive(type)) {
+ } else if (!type->isEnum() && !type->isFlags()) {
return QString("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
.arg(converterObject(type));
}
@@ -1182,7 +1224,7 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType*
isConv = "isPythonToCppValueConvertible";
return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ")
.arg(isConv).arg(cpythonTypeNameExt(metaType));
- } else if (isUserPrimitive(metaType) || isCppPrimitive(metaType)) {
+ } else if (!metaType->typeEntry()->isEnum() && !metaType->typeEntry()->isFlags()) {
return QString("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
.arg(converterObject(metaType));
}
@@ -1200,14 +1242,8 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType*
QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass* metaClass)
{
- // 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)
{
@@ -1216,7 +1252,7 @@ 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) || isCppPrimitive(type)) {
+ } else if (!type->typeEntry()->isEnum() && !type->typeEntry()->isFlags()) {
return QString("Shiboken::Conversions::pythonToCpp(%1, ")
.arg(converterObject(type));
}
@@ -1240,7 +1276,7 @@ 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) || isCppPrimitive(type)) {
+ } else if (!type->typeEntry()->isEnum() && !type->typeEntry()->isFlags()) {
return QString("Shiboken::Conversions::copyToPython(%1, %2")
.arg(converterObject(type))
.arg((isCString(type) || isVoidPointer(type)) ? "" : "&");
@@ -1270,7 +1306,7 @@ 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) || isCppPrimitive(type)) {
+ } else if (!type->isEnum() && !type->isFlags()) {
return QString("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type));
}
// TODO-CONVERTER -----------------------------------------------------------------------
@@ -1466,7 +1502,7 @@ ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverter
return extConvs;
}
-QList<const CustomConversion*> ShibokenGenerator::getNonWrapperCustomConversions()
+QList<const CustomConversion*> ShibokenGenerator::getPrimitiveCustomConversions()
{
QList<const CustomConversion*> conversions;
foreach (const PrimitiveTypeEntry* type, primitiveTypes()) {
@@ -1824,7 +1860,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
// 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*(?:\\[[^\\[]+\\])*");
+ static QRegExp expr("\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*");
return expr.exactMatch(code.trimmed());
}
@@ -1836,6 +1872,8 @@ static QString miniNormalizer(const QString& varType)
QString normalized = varType.trimmed();
if (normalized.isEmpty())
return normalized;
+ if (normalized.startsWith("::"))
+ normalized.remove(0, 2);
QString suffix;
while (normalized.endsWith('*') || normalized.endsWith('&')) {
suffix.prepend(normalized.at(normalized.count() - 1));
@@ -1887,15 +1925,20 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
if (conversionType) {
switch (converterVariable) {
case TypeSystemToCppFunction: {
- c << list.at(1);
- if (!isWrapperType(conversionType) && !isUserPrimitive(conversionType) && !isCppPrimitive(conversionType)) {
- c << list.at(2) << list.at(3) << " = ";
- c << cpythonToCppConversionFunction(conversionType);
- c << '(';
+ int end = pos - list.first().count();
+ int start = end;
+ while (start > 0 && code.at(start) != '\n')
+ --start;
+ while (code.at(start).isSpace())
+ ++start;
+ QString varType = code.mid(start, end - start);
+ conversionString = varType + list.first();
+ varType = miniNormalizer(varType);
+ if (conversionType->typeEntry()->isEnum() || conversionType->typeEntry()->isFlags()) {
+ c << varType << ' ' << list.at(1) << " = " << cpythonToCppConversionFunction(conversionType) << '(';
break;
}
- QString varType = miniNormalizer(list.at(2));
- QString varName = list.at(3).trimmed();
+ QString varName = list.at(1).trimmed();
if (!varType.isEmpty()) {
if (varType != conversionType->cppSignature()) {
qFatal(qPrintable(QString("Types of receiver variable ('%1') and %CONVERTTOCPP type system variable ('%2') differ.")
@@ -1930,7 +1973,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
conversion = cpythonToPythonConversionFunction(conversionType);
default: {
// TODO-CONVERTER -----------------------------------------------------------------------
- if (!isWrapperType(conversionType) && !isUserPrimitive(conversionType) && !isCppPrimitive(conversionType)) {
+ if (conversionType->typeEntry()->isEnum() || conversionType->typeEntry()->isFlags()) {
c << '(';
break;
}
@@ -2184,7 +2227,34 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ
typeString = typeString.trimmed();
}
- TypeEntry* typeEntry = TypeDatabase::instance()->findType(typeString);
+ if (typeString.startsWith("::"))
+ typeString.remove(0, 2);
+
+ QString adjustedTypeName = typeString;
+ QStringList instantiatedTypes;
+ int lpos = typeString.indexOf('<');
+ if (lpos > -1) {
+ int rpos = typeString.lastIndexOf('>');
+ if ((lpos != -1) && (rpos != -1)) {
+ QString type = typeString.mid(lpos + 1, rpos - lpos - 1);
+ int depth = 0;
+ int start = 0;
+ for (int i = 0; i < type.count(); ++i) {
+ if (type.at(i) == '<') {
+ ++depth;
+ } else if (type.at(i) == '>') {
+ --depth;
+ } else if (type.at(i) == ',' && depth == 0) {
+ instantiatedTypes << type.mid(start, i - start).trimmed();
+ start = i + 1;
+ }
+ }
+ instantiatedTypes << type.mid(start).trimmed();
+ adjustedTypeName = adjustedTypeName.left(lpos);
+ }
+ }
+
+ TypeEntry* typeEntry = TypeDatabase::instance()->findType(adjustedTypeName);
AbstractMetaType* metaType = 0;
if (typeEntry) {
metaType = new AbstractMetaType();
@@ -2192,6 +2262,11 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ
metaType->setIndirections(indirections);
metaType->setReference(isReference);
metaType->setConstant(isConst);
+ foreach (const QString& instantiation, instantiatedTypes) {
+ AbstractMetaType* tmplArgType = buildAbstractMetaTypeFromString(instantiation);
+ metaType->addInstantiation(tmplArgType);
+ metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
+ }
metaType->decideUsagePattern();
m_metaTypeFromStringCache.insert(typeSignature, metaType);
}
@@ -2356,8 +2431,11 @@ QString ShibokenGenerator::convertersVariableName(const QString& moduleName) con
static QString processInstantiationsVariableName(const AbstractMetaType* type)
{
QString res = QString("_%1").arg(_fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper());
- foreach (const AbstractMetaType* instantiation, type->instantiations())
- res += processInstantiationsVariableName(instantiation);
+ foreach (const AbstractMetaType* instantiation, type->instantiations()) {
+ res += instantiation->isContainer()
+ ? processInstantiationsVariableName(instantiation)
+ : QString("_%1").arg(_fixedCppTypeName(instantiation->cppSignature()).toUpper());
+ }
return res;
}
QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* metaClass, bool alternativeTemplateName)
@@ -2385,7 +2463,9 @@ QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type)
}
QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type)
{
- return QString("SBK%1_IDX").arg(processInstantiationsVariableName(type));
+ return QString("SBK%1%2_IDX")
+ .arg(type->typeEntry()->isContainer() ? "_"+moduleName().toUpper() : "")
+ .arg(processInstantiationsVariableName(type));
}
QString ShibokenGenerator::getFullTypeName(const TypeEntry* type)
@@ -2398,6 +2478,8 @@ QString ShibokenGenerator::getFullTypeName(const AbstractMetaType* type)
return "const char*";
if (isVoidPointer(type))
return "void*";
+ if (type->typeEntry()->isContainer())
+ return QString("::%1").arg(type->cppSignature());
return getFullTypeName(type->typeEntry()) + QString("*").repeated(type->indirections());
}
QString ShibokenGenerator::getFullTypeName(const AbstractMetaClass* metaClass)
@@ -2473,7 +2555,6 @@ QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, co
return QString();
}
-// TODO-CONVERTER -----------------------------------------------------------------------
void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor)
{
if (defaultCtor.isEmpty() && isCppPrimitive(type))
@@ -2507,4 +2588,3 @@ bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type)
{
return isCppIntegralPrimitive(type->typeEntry());
}
-// TODO-CONVERTER -----------------------------------------------------------------------
diff --git a/generator/shibokengenerator.h b/generator/shibokengenerator.h
index 8cd91c2e..a3dcd8b5 100644
--- a/generator/shibokengenerator.h
+++ b/generator/shibokengenerator.h
@@ -42,6 +42,12 @@
"This will result in a compilation error."
#define PYTHON_TO_CPP_VAR "pythonToCpp"
+#define CHECKTYPE_REGEX "%CHECKTYPE\\[([^\\[]*)\\]\\("
+#define ISCONVERTIBLE_REGEX "%ISCONVERTIBLE\\[([^\\[]*)\\]\\("
+#define CONVERTTOPYTHON_REGEX "%CONVERTTOPYTHON\\[([^\\[]*)\\]\\("
+#define CONVERTTOCPP_REGEX "(\\*?%?[a-zA-Z_][\\w\\.]*(?:\\[[^\\[^<^>]+\\])*)"\
+ "(?:\\s+)=(?:\\s+)%CONVERTTOCPP\\[([^\\[]*)\\]\\("
+
#include <generator.h>
#include <QtCore/QTextStream>
@@ -507,7 +513,7 @@ protected:
ExtendedConverterData getExtendedConverters() const;
/// Returns a list of converters for the non wrapper types of the current module.
- QList<const CustomConversion*> getNonWrapperCustomConversions();
+ QList<const CustomConversion*> getPrimitiveCustomConversions();
/// 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 185fd2ad..3fd04db9 100644
--- a/libshiboken/sbkconverter.cpp
+++ b/libshiboken/sbkconverter.cpp
@@ -24,6 +24,7 @@
#include "sbkconverter_p.h"
#include "basewrapper_p.h"
#include "google/dense_hash_map"
+#include "autodecref.h"
#include "sbkdbg.h"
static SbkConverter** PrimitiveTypeConverters;
@@ -299,4 +300,125 @@ SbkConverter* primitiveTypeConverter(int index)
return PrimitiveTypeConverters[index];
}
+bool checkSequenceTypes(PyTypeObject* type, PyObject* pyIn)
+{
+ assert(type);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ int size = PySequence_Size(pyIn);
+ for (int i = 0; i < size; ++i) {
+ if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, i)), type))
+ return false;
+ }
+ return true;
+}
+bool convertibleSequenceTypes(SbkConverter* converter, PyObject* pyIn)
+{
+ assert(converter);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ int size = PySequence_Size(pyIn);
+ for (int i = 0; i < size; ++i) {
+ if (!isPythonToCppConvertible(converter, AutoDecRef(PySequence_GetItem(pyIn, i))))
+ return false;
+ }
+ return true;
+}
+bool convertibleSequenceTypes(SbkObjectType* type, PyObject* pyIn)
+{
+ assert(type);
+ return convertibleSequenceTypes(type->d->converter, pyIn);
+}
+
+bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn)
+{
+ assert(firstType);
+ assert(secondType);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ if (PySequence_Size(pyIn) != 2)
+ return false;
+ if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, 0)), firstType))
+ return false;
+ if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, 1)), secondType))
+ return false;
+ return true;
+}
+bool convertiblePairTypes(SbkConverter* firstConverter, bool firstCheckExact, SbkConverter* secondConverter, bool secondCheckExact, PyObject* pyIn)
+{
+ assert(firstConverter);
+ assert(secondConverter);
+ assert(pyIn);
+ if (!PySequence_Check(pyIn))
+ return false;
+ if (PySequence_Size(pyIn) != 2)
+ return false;
+ AutoDecRef firstItem(PySequence_GetItem(pyIn, 0));
+ if (firstCheckExact) {
+ if (!PyObject_TypeCheck(firstItem, firstConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(firstConverter, firstItem)) {
+ return false;
+ }
+ AutoDecRef secondItem(PySequence_GetItem(pyIn, 1));
+ if (secondCheckExact) {
+ if (!PyObject_TypeCheck(secondItem, secondConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(secondConverter, secondItem)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool checkDictTypes(PyTypeObject* keyType, PyTypeObject* valueType, PyObject* pyIn)
+{
+ assert(keyType);
+ assert(valueType);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+
+ PyObject* key;
+ PyObject* value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &value)) {
+ if (!PyObject_TypeCheck(key, keyType))
+ return false;
+ if (!PyObject_TypeCheck(value, valueType))
+ return false;
+ }
+ return true;
+}
+
+bool convertibleDictTypes(SbkConverter* keyConverter, bool keyCheckExact, SbkConverter* valueConverter, bool valueCheckExact, PyObject* pyIn)
+{
+ assert(keyConverter);
+ assert(valueConverter);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+ PyObject* key;
+ PyObject* value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &value)) {
+ if (keyCheckExact) {
+ if (!PyObject_TypeCheck(key, keyConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(keyConverter, key)) {
+ return false;
+ }
+ if (valueCheckExact) {
+ if (!PyObject_TypeCheck(value, valueConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(valueConverter, value)) {
+ return false;
+ }
+ }
+ return true;
+}
+
} } // namespace Shiboken::Conversions
diff --git a/libshiboken/sbkconverter.h b/libshiboken/sbkconverter.h
index 1fddf5a9..ba8dc8f2 100644
--- a/libshiboken/sbkconverter.h
+++ b/libshiboken/sbkconverter.h
@@ -221,6 +221,28 @@ LIBSHIBOKEN_API SbkConverter* getConverter(const char* typeName);
/// Returns the converter for a primitive type.
LIBSHIBOKEN_API SbkConverter* primitiveTypeConverter(int index);
+/// Returns true if a Python sequence is comprised of objects of the given \p type.
+LIBSHIBOKEN_API bool checkSequenceTypes(PyTypeObject* type, PyObject* pyIn);
+
+/// Returns true if a Python sequence is comprised of objects of a type convertible to the one represented by the given \p converter.
+LIBSHIBOKEN_API bool convertibleSequenceTypes(SbkConverter* converter, PyObject* pyIn);
+
+/// Returns true if a Python sequence is comprised of objects of a type convertible to \p type.
+LIBSHIBOKEN_API bool convertibleSequenceTypes(SbkObjectType* type, PyObject* pyIn);
+
+/// Returns true if a Python sequence can be converted to a C++ pair.
+LIBSHIBOKEN_API bool checkPairTypes(PyTypeObject* firstType, PyTypeObject* secondType, PyObject* pyIn);
+
+/// Returns true if a Python sequence can be converted to a C++ pair.
+LIBSHIBOKEN_API bool convertiblePairTypes(SbkConverter* firstConverter, bool firstCheckExact, SbkConverter* secondConverter, bool secondCheckExact, PyObject* pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ hash or map.
+LIBSHIBOKEN_API bool checkDictTypes(PyTypeObject* keyType, PyTypeObject* valueType, PyObject* pyIn);
+
+/// Returns true if a Python dictionary can be converted to a C++ hash or map.
+LIBSHIBOKEN_API bool convertibleDictTypes(SbkConverter* keyConverter, bool keyCheckExact, SbkConverter* valueConverter, bool valueCheckExact, PyObject* pyIn);
+
+
#define SBK_PY_LONG_LONG_IDX 0
#define SBK_BOOL_IDX 1
#define SBK_CHAR_IDX 2
diff --git a/libshiboken/tmp-referencetopython/sbkconverter.cpp b/libshiboken/tmp-referencetopython/sbkconverter.cpp
new file mode 100644
index 00000000..61f04a18
--- /dev/null
+++ b/libshiboken/tmp-referencetopython/sbkconverter.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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);
+}
+
+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* toPython(SbkConverter* converter, const void* cppIn)
+{
+ return CopyCppToPython(converter, cppIn);
+}
+
+PyObject* referenceToPython(SbkObjectType* type, const void* cppIn)
+{
+ assert(cppIn);
+ PyObject* pyOut = (PyObject*)BindingManager::instance().retrieveWrapper(cppIn);
+ if (pyOut) {
+ Py_INCREF(pyOut);
+ return pyOut;
+ }
+ // If it is Value Type, return a copy of the C++ object.
+ if (type->d->converter->copyToPython)
+ return type->d->converter->copyToPython(cppIn);
+ // If it is an Object Type, return a copy of the C++ object.
+ return type->d->converter->pointerToPython(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 pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut)
+{
+ assert(pyIn);
+ assert(cppOut);
+ SbkObjectType* inType = (SbkObjectType*)pyIn->ob_type;
+ if (ObjectType::hasCast(inType))
+ *((void**)cppOut) = ObjectType::cast(inType, (SbkObject*)pyIn, (PyTypeObject*)type);
+ else
+ *((void**)cppOut) = Object::cppPointer((SbkObject*)pyIn, (PyTypeObject*)type);
+}
+
+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/tmp-referencetopython/sbkconverter.h b/libshiboken/tmp-referencetopython/sbkconverter.h
new file mode 100644
index 00000000..edf67394
--- /dev/null
+++ b/libshiboken/tmp-referencetopython/sbkconverter.h
@@ -0,0 +1,174 @@
+/*
+ * 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"
+
+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);
+
+/**
+ * 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);
+
+// TODO:WRITEDOCSTRING - used only for Value Types - cppIn must point to a value
+/**
+ * Retrieves the Python wrapper object for the given C++ reference pointed by \p cppIn.
+ * This function is used only for Value and Object Types.
+ * It differs from pointerToPython() for not checking for a NULL pointer.
+ * Example usage:
+ * TYPE& var = SOMETHING;
+ * PyObject* pyVar = copyToPython(SBKTYPE, &var);
+ */
+LIBSHIBOKEN_API PyObject* referenceToPython(SbkObjectType* type, const void* cppIn);
+
+// TODO:WRITEDOCSTRING - used only for Primitives and Containers (and Value Types) - cppIn must point to a primitive, container or value type
+/// This is the same as copyToPython function.
+LIBSHIBOKEN_API PyObject* toPython(SbkConverter* converter, const void* cppIn);
+
+// Python -> C++ convertibility checks -----------------------------------------------------
+
+// TODO:WRITEDOCSTRING
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType* type, PyObject* pyIn);
+
+// TODO:WRITEDOCSTRING- Returns a Python to C++ conversion function if true, or NULL if false.
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType* type, PyObject* pyIn);
+
+// TODO:WRITEDOCSTRING- Returns a Python to C++ conversion function if true, or NULL if false.
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType* type, PyObject* pyIn);
+
+/// This is the same as isPythonToCppValueConvertible function.
+LIBSHIBOKEN_API PythonToCppFunc isPythonToCppConvertible(SbkConverter* converter, PyObject* pyIn);
+
+// Python -> C++ ---------------------------------------------------------------------------
+
+// TODO:WRITEDOCSTRING - function used by the generated [TYPE]_PythonToCpp_[TYPE]_PTR
+LIBSHIBOKEN_API void pythonToCppPointer(SbkObjectType* type, PyObject* pyIn, void* cppOut);
+
+// TODO:WRITEDOCSTRING - function used by the generated isConvertible when the PyObject is None,
+// making a C++ NULL pointer the result of the toCpp function call.
+// DRAFT: When the Python object is a Py_None, it's C++ conversion is always a NULL pointer.
+LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject*, void* cppOut);
+
+// TODO:WRITEDOCSTRING - tells if \p toCpp is an implicit conversion.
+LIBSHIBOKEN_API bool isImplicitConversion(SbkObjectType* type, PythonToCppFunc toCpp);
+
+} } // namespace Shiboken::Conversions
+
+#endif // SBK_CONVERTER_H
diff --git a/tests/libsample/list.h b/tests/libsample/list.h
index d9a52c31..9eb03452 100644
--- a/tests/libsample/list.h
+++ b/tests/libsample/list.h
@@ -34,8 +34,22 @@ class List : public std::list<T>
class IntList : public List<int>
{
public:
+ enum CtorEnum {
+ NoParamsCtor,
+ IntCtor,
+ CopyCtor,
+ ListOfIntCtor
+ };
+
+ inline IntList() : m_ctorUsed(NoParamsCtor) {}
+ inline explicit IntList(int val) : m_ctorUsed(IntCtor) { push_back(val); }
+ inline IntList(const IntList& lst) : List<int>(lst), m_ctorUsed(CopyCtor) {}
+ inline IntList(const List<int>& lst) : List<int>(lst), m_ctorUsed(ListOfIntCtor) {}
+
inline void append(int v) { insert(end(), v); }
+ CtorEnum constructorUsed() { return m_ctorUsed; }
+private:
+ CtorEnum m_ctorUsed;
};
#endif // LIST_H
-
diff --git a/tests/libsample/photon.cpp b/tests/libsample/photon.cpp
index 6467f6cc..2b55bb7a 100644
--- a/tests/libsample/photon.cpp
+++ b/tests/libsample/photon.cpp
@@ -32,4 +32,12 @@ int callCalculateForValueDuplicatorReference(ValueDuplicator& value)
{
return value.calculate();
}
+int countValueIdentities(const std::list<ValueIdentity>& values)
+{
+ return values.size();
+}
+int countValueDuplicators(const std::list<TemplateBase<DuplicatorType> >& values)
+{
+ return values.size();
+}
} // namespace Photon
diff --git a/tests/libsample/photon.h b/tests/libsample/photon.h
index 8707c71a..749e10e4 100644
--- a/tests/libsample/photon.h
+++ b/tests/libsample/photon.h
@@ -23,6 +23,7 @@
#ifndef PHOTON_H
#define PHOTON_H
+#include <list>
#include "libsamplemacros.h"
// This namespace and classes simulate
@@ -50,10 +51,17 @@ public:
inline int sumValueUsingPointer(TemplateBase<CLASS_TYPE>* other) const { return m_value + other->m_value; }
inline int sumValueUsingReference(TemplateBase<CLASS_TYPE>& other) const { return m_value + other.m_value; }
+ inline std::list<TemplateBase<CLASS_TYPE> > getListOfThisTemplateBase()
+ {
+ std::list<TemplateBase<CLASS_TYPE> >objs;
+ objs.push_back(*this);
+ objs.push_back(*this);
+ return objs;
+ }
+
+
static inline TemplateBase<CLASS_TYPE>* passPointerThrough(TemplateBase<CLASS_TYPE>* obj) { return obj; }
private:
- TemplateBase(const TemplateBase&);
- TemplateBase& operator=(const TemplateBase&);
int m_value;
};
@@ -61,6 +69,8 @@ typedef TemplateBase<IdentityType> ValueIdentity;
typedef TemplateBase<DuplicatorType> ValueDuplicator;
LIBSAMPLE_API int callCalculateForValueDuplicatorPointer(ValueDuplicator* value);
LIBSAMPLE_API int callCalculateForValueDuplicatorReference(ValueDuplicator& value);
+LIBSAMPLE_API int countValueIdentities(const std::list<ValueIdentity>& values);
+LIBSAMPLE_API int countValueDuplicators(const std::list<TemplateBase<DuplicatorType> >& values);
} // namespace Photon
diff --git a/tests/libsample/samplenamespace.h b/tests/libsample/samplenamespace.h
index 85ce8409..88269b45 100644
--- a/tests/libsample/samplenamespace.h
+++ b/tests/libsample/samplenamespace.h
@@ -23,6 +23,7 @@
#ifndef SAMPLENAMESPACE_H
#define SAMPLENAMESPACE_H
+#include <list>
#include "libsamplemacros.h"
#include "str.h"
#include "point.h"
@@ -105,6 +106,9 @@ public:
virtual OkThisIsRecursiveEnough* someVirtualMethod(OkThisIsRecursiveEnough* arg) { return arg; }
};
};
+ struct SomeOtherInnerClass {
+ std::list<SomeInnerClass> someInnerClasses;
+ };
};
class DerivedFromNamespace : public SomeClass::SomeInnerClass::OkThisIsRecursiveEnough
diff --git a/tests/libsample/strlist.cpp b/tests/libsample/strlist.cpp
index 2e487f5e..6a9eb23b 100644
--- a/tests/libsample/strlist.cpp
+++ b/tests/libsample/strlist.cpp
@@ -49,4 +49,3 @@ StrList::join(const Str& sep) const
}
return result;
}
-
diff --git a/tests/libsample/strlist.h b/tests/libsample/strlist.h
index 5845d06b..98dfdee1 100644
--- a/tests/libsample/strlist.h
+++ b/tests/libsample/strlist.h
@@ -31,17 +31,27 @@
class LIBSAMPLE_API StrList : public std::list<Str>
{
public:
- inline StrList() {}
- inline explicit StrList(const Str& str) { push_back(str); }
- inline StrList(const StrList& lst) : std::list<Str>(lst) { }
- inline StrList(const std::list<Str>& lst) : std::list<Str>(lst) { }
+ enum CtorEnum {
+ NoParamsCtor,
+ StrCtor,
+ CopyCtor,
+ ListOfStrCtor
+ };
+
+ inline StrList() : m_ctorUsed(NoParamsCtor) {}
+ inline explicit StrList(const Str& str) : m_ctorUsed(StrCtor) { push_back(str); }
+ inline StrList(const StrList& lst) : std::list<Str>(lst), m_ctorUsed(CopyCtor) {}
+ inline StrList(const std::list<Str>& lst) : std::list<Str>(lst), m_ctorUsed(ListOfStrCtor) {}
inline void append(Str str) { push_back(str); }
Str join(const Str& sep) const;
bool operator==(const std::list<Str>& other) const;
inline bool operator!=(const std::list<Str>& other) const { return !(*this == other); }
+
+ CtorEnum constructorUsed() { return m_ctorUsed; }
+private:
+ CtorEnum m_ctorUsed;
};
#endif // STRLIST_H
-
diff --git a/tests/minimalbinding/typesystem_minimal.xml b/tests/minimalbinding/typesystem_minimal.xml
index d4f673d2..cd26b34c 100644
--- a/tests/minimalbinding/typesystem_minimal.xml
+++ b/tests/minimalbinding/typesystem_minimal.xml
@@ -18,8 +18,27 @@
</primitive-type>
<container-type name="std::list" type="list">
- <conversion-rule file="list_conversions.h"/>
<include file-name="list" location="global"/>
+ <conversion-rule file="list_conversions.h">
+ <native-to-target>
+ PyObject* %out = PyList_New((int) %in.size());
+ %INTYPE::const_iterator it = %in.begin();
+ for (int idx = 0; it != %in.end(); ++it, ++idx) {
+ %INTYPE_0 cppItem(*it);
+ PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
+ }
+ return %out;
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ for (int i = 0; i &lt; PySequence_Fast_GET_SIZE(%in); i++) {
+ PyObject* pyItem = PySequence_Fast_GET_ITEM(%in, i);
+ %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
+ %out.push_back(cppItem);
+ }
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</container-type>
<object-type name="Obj"/>
diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt
index 2f4f33cc..59163ac8 100644
--- a/tests/samplebinding/CMakeLists.txt
+++ b/tests/samplebinding/CMakeLists.txt
@@ -86,6 +86,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/sample_sample_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_okthisisrecursiveenough_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someotherinnerclass_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_derivedfromnamespace_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/simplefile_wrapper.cpp
diff --git a/tests/samplebinding/intlist_test.py b/tests/samplebinding/intlist_test.py
index fa7be288..683de994 100644
--- a/tests/samplebinding/intlist_test.py
+++ b/tests/samplebinding/intlist_test.py
@@ -24,7 +24,6 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
# 02110-1301 USA
-import sys
import unittest
from sample import IntList
@@ -46,8 +45,37 @@ class IntListTest(unittest.TestCase):
self.assertEqual(lst[2], 30)
self.assertEqual(len(lst), 3)
+ def testIntListCtor_NoParams(self):
+ '''IntList constructor receives no parameter.'''
+ il = IntList()
+ self.assertEqual(len(il), 0)
+ self.assertEqual(il.constructorUsed(), IntList.NoParamsCtor)
+ def testIntListCtor_int(self):
+ '''IntList constructor receives an integer.'''
+ value = 123
+ il = IntList(value)
+ self.assertEqual(len(il), 1)
+ self.assertEqual(il[0], value)
+ self.assertEqual(il.constructorUsed(), IntList.IntCtor)
+
+ def testIntListCtor_IntList(self):
+ '''IntList constructor receives an IntList object.'''
+ il1 = IntList(123)
+ il2 = IntList(il1)
+ self.assertEqual(len(il1), len(il2))
+ for i in range(len(il1)):
+ self.assertEqual(il1[i], il2[i])
+ self.assertEqual(il2.constructorUsed(), IntList.CopyCtor)
+
+ def testIntListCtor_ListOfInts(self):
+ '''IntList constructor receives an integer list.'''
+ ints = [123, 456]
+ il = IntList(ints)
+ self.assertEqual(len(il), len(ints))
+ for i in range(len(il)):
+ self.assertEqual(il[i], ints[i])
+ self.assertEqual(il.constructorUsed(), IntList.ListOfIntCtor)
if __name__ == '__main__':
unittest.main()
-
diff --git a/tests/samplebinding/strlist_test.py b/tests/samplebinding/strlist_test.py
index 9ebbff03..0d1a747d 100644
--- a/tests/samplebinding/strlist_test.py
+++ b/tests/samplebinding/strlist_test.py
@@ -33,12 +33,19 @@ from sample import Str, StrList
class StrListTest(unittest.TestCase):
'''Test cases for StrList class that inherits from std::list<Str>.'''
+ def testStrListCtor_NoParams(self):
+ '''StrList constructor receives no parameter.'''
+ sl = StrList()
+ self.assertEqual(len(sl), 0)
+ self.assertEqual(sl.constructorUsed(), StrList.NoParamsCtor)
+
def testStrListCtor_Str(self):
'''StrList constructor receives a Str object.'''
s = Str('Foo')
sl = StrList(s)
self.assertEqual(len(sl), 1)
self.assertEqual(sl[0], s)
+ self.assertEqual(sl.constructorUsed(), StrList.StrCtor)
def testStrListCtor_PythonString(self):
'''StrList constructor receives a Python string.'''
@@ -46,13 +53,15 @@ class StrListTest(unittest.TestCase):
sl = StrList(s)
self.assertEqual(len(sl), 1)
self.assertEqual(sl[0], s)
+ self.assertEqual(sl.constructorUsed(), StrList.StrCtor)
def testStrListCtor_StrList(self):
'''StrList constructor receives a StrList object.'''
sl1 = StrList(Str('Foo'))
sl2 = StrList(sl1)
- self.assertEqual(len(sl1), len(sl2))
- self.assertEqual(sl1, sl2)
+ #self.assertEqual(len(sl1), len(sl2))
+ #self.assertEqual(sl1, sl2)
+ self.assertEqual(sl2.constructorUsed(), StrList.CopyCtor)
def testStrListCtor_ListOfStrs(self):
'''StrList constructor receives a Python list of Str objects.'''
@@ -60,6 +69,7 @@ class StrListTest(unittest.TestCase):
sl = StrList(strs)
self.assertEqual(len(sl), len(strs))
self.assertEqual(sl, strs)
+ self.assertEqual(sl.constructorUsed(), StrList.ListOfStrCtor)
def testStrListCtor_MixedListOfStrsAndPythonStrings(self):
'''StrList constructor receives a Python list of mixed Str objects and Python strings.'''
@@ -67,6 +77,7 @@ class StrListTest(unittest.TestCase):
sl = StrList(strs)
self.assertEqual(len(sl), len(strs))
self.assertEqual(sl, strs)
+ self.assertEqual(sl.constructorUsed(), StrList.ListOfStrCtor)
def testCompareStrListWithTupleOfStrs(self):
'''Compares StrList with a Python tuple of Str objects.'''
@@ -92,7 +103,5 @@ class StrListTest(unittest.TestCase):
self.assertEqual(len(sl), 2)
self.assertEqual(sl, (Str('Foo'), 'Bar'))
-
if __name__ == '__main__':
unittest.main()
-
diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml
index ec4ace7d..ba3a56eb 100644
--- a/tests/samplebinding/typesystem_sample.xml
+++ b/tests/samplebinding/typesystem_sample.xml
@@ -101,18 +101,93 @@
</primitive-type>
<container-type name="std::pair" type="pair">
- <conversion-rule file="pair_conversions.h"/>
<include file-name="utility" location="global"/>
+ <conversion-rule file="pair_conversions.h">
+ <native-to-target>
+ PyObject* %out = PyTuple_New(2);
+ PyTuple_SET_ITEM(%out, 0, %CONVERTTOPYTHON[%INTYPE_0](%in.first));
+ PyTuple_SET_ITEM(%out, 1, %CONVERTTOPYTHON[%INTYPE_1](%in.second));
+ return %out;
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ %out.first = %CONVERTTOCPP[%OUTTYPE_0](PySequence_Fast_GET_ITEM(%in, 0));
+ %out.second = %CONVERTTOCPP[%OUTTYPE_1](PySequence_Fast_GET_ITEM(%in, 1));
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</container-type>
+ <template name="cpplist_to_pylist_convertion">
+ PyObject* %out = PyList_New((int) %in.size());
+ %INTYPE::const_iterator it = %in.begin();
+ for (int idx = 0; it != %in.end(); ++it, ++idx) {
+ %INTYPE_0 cppItem(*it);
+ PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
+ }
+ return %out;
+ </template>
+ <template name="pyseq_to_cpplist_convertion">
+ for (int i = 0; i &lt; PySequence_Fast_GET_SIZE(%in); i++) {
+ PyObject* pyItem = PySequence_Fast_GET_ITEM(%in, i);
+ %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
+ %out.push_back(cppItem);
+ }
+ </template>
<container-type name="std::list" type="list">
- <conversion-rule file="list_conversions.h"/>
<include file-name="list" location="global"/>
+ <conversion-rule file="list_conversions.h">
+ <native-to-target>
+ <insert-template name="cpplist_to_pylist_convertion"/>
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ <insert-template name="pyseq_to_cpplist_convertion"/>
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </container-type>
+ <container-type name="List" type="list">
+ <include file-name="list" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ <insert-template name="cpplist_to_pylist_convertion"/>
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ <insert-template name="pyseq_to_cpplist_convertion"/>
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</container-type>
<container-type name="std::map" type="map">
- <conversion-rule file="map_conversions.h"/>
<include file-name="map" location="global"/>
+ <conversion-rule file="map_conversions.h">
+ <native-to-target>
+ PyObject* %out = PyDict_New();
+ %INTYPE::const_iterator it = %in.begin();
+ for (; it != %in.end(); ++it) {
+ %INTYPE_0 key = it->first;
+ %INTYPE_1 value = it->second;
+ PyDict_SetItem(%out,
+ %CONVERTTOPYTHON[%INTYPE_0](key),
+ %CONVERTTOPYTHON[%INTYPE_1](value));
+ }
+ return %out;
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PyDict">
+ PyObject* key;
+ PyObject* value;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(%in, &amp;pos, &amp;key, &amp;value)) {
+ %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
+ %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
+ %out.insert(%OUTTYPE::value_type(cppKey, cppValue));
+ }
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
</container-type>
- <container-type name="List" type="list" />
<add-function signature="cacheSize()" return-type="int">
<inject-code class="target">
@@ -181,6 +256,7 @@
<enum-type name="NiceEnum" />
</object-type>
</value-type>
+ <value-type name="SomeOtherInnerClass"/>
</value-type>
<modify-function signature="doSomethingWithArray(const unsigned char*, unsigned int, const char*)">
@@ -238,12 +314,14 @@
<namespace-type name="Photon">
<enum-type name="ClassType"/>
- <object-type name="TemplateBase" generate="no"/>
- <object-type name="ValueIdentity"/>
- <object-type name="ValueDuplicator"/>
+ <value-type name="TemplateBase" generate="no"/>
+ <value-type name="ValueIdentity"/>
+ <value-type name="ValueDuplicator"/>
</namespace-type>
- <value-type name="IntList" />
+ <value-type name="IntList">
+ <enum-type name="CtorEnum"/>
+ </value-type>
<object-type name="Abstract">
<enum-type name="Type"/>
@@ -1747,6 +1825,7 @@
</value-type>
<value-type name="StrList">
+ <enum-type name="CtorEnum"/>
<add-function signature="__len__" >
<inject-code class="target" position="end">
return %CPPSELF.size();