aboutsummaryrefslogtreecommitdiffstats
path: root/cppgenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cppgenerator.cpp')
-rw-r--r--cppgenerator.cpp1421
1 files changed, 1421 insertions, 0 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp
new file mode 100644
index 000000000..ae1f625a8
--- /dev/null
+++ b/cppgenerator.cpp
@@ -0,0 +1,1421 @@
+/*
+ * This file is part of the Boost Python Generator project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include "cppgenerator.h"
+#include <apiextractor/reporthandler.h>
+#include <apiextractor/fileout.h>
+#include <apiextractor/abstractmetalang.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QVariant>
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+#include <QtCore/QListIterator>
+
+static Indentor INDENT;
+
+// utiliy functions
+inline QString getMethodPointerString(const AbstractMetaFunction* func)
+{
+ QString className;
+ if (!func->declaringClass()->isAbstract())
+ className = func->declaringClass()->qualifiedCppName();
+ else
+ className = func->ownerClass()->qualifiedCppName();
+
+ return '&' + className + "::" + func->originalName();
+}
+
+static QString nameForModifiedCtorFunction(const AbstractMetaFunction* func) {
+ QString res = func->ownerClass()->name().toLower().replace("::", "_");
+ res += "_constructor";
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ res += '_';
+ res += arg->type()->name().toLower();
+ }
+ return res;
+}
+
+static QString createStaticFunctionName(const AbstractMetaFunction* func)
+{
+ QString funcName;
+ QString originalName(func->name());
+
+
+ funcName = func->ownerClass()->name().toLower();
+
+ //remove initial 'Q'
+ if (funcName.startsWith('q'))
+ funcName = funcName.remove(0, 1);
+
+ //upercase first letter
+ funcName += originalName[0].toUpper() + originalName.mid(1);
+
+ return funcName;
+}
+
+QString CppGenerator::fileNameForClass(const AbstractMetaClass* cppClass) const
+{
+ return getWrapperName(cppClass) + QLatin1String(".cpp");
+}
+
+QString CppGenerator::getFuncTypedefName(const AbstractMetaFunction* func) const
+{
+ return func->name() + QLatin1String("_type");
+}
+
+void CppGenerator::writeConstructorInitialization(QTextStream &s, const AbstractMetaFunction *function)
+{
+ QStringList nonOpts;
+ QStringList opts;
+
+ foreach (AbstractMetaArgument *arg, function->arguments()) {
+ uint options = SkipName | SkipDefaultValues;
+ QString argType = argumentString(function, arg, options);
+ if (arg->defaultValueExpression().isEmpty())
+ nonOpts << argType;
+ else
+ opts << argType;
+ }
+
+ bool hasModifications = function->allowThread() || function->hasInjectedCode();
+
+ if (hasModifications) {
+ s << "\"__init__\", python::make_constructor("
+ << nameForModifiedCtorFunction(function);
+ } else {
+ s << "python::init< ";
+
+ if (nonOpts.size() > 0)
+ s << nonOpts.join(", ");
+
+ if (opts.size() > 0) {
+ if (nonOpts.size() > 0)
+ s << ", ";
+
+ s << "python::optional< " << opts.join(",") << " > ";
+ }
+
+ s << " > ()";
+ }
+
+ QString callPolicy = getFunctionCallPolicy(function);
+ QString parentType;
+ const AbstractMetaClass *cppClass = function->ownerClass();
+ uint closePolicy = 0;
+ bool hasPolicy = false;
+
+ if (
+ !hasModifications &&
+ (!cppClass->isPolymorphic() || cppClass->hasPrivateDestructor() || cppClass->isNamespace())
+ ) {
+ closePolicy++;
+ hasPolicy = true;
+ s << "[ PySide::register_wrapper_object< "
+ << function->ownerClass()->qualifiedCppName();
+ }
+
+ if (callPolicy.isEmpty()) {
+ int parentIndex = -1;
+ //try find for parent arg to create callPolicy
+ foreach (AbstractMetaArgument *arg, function->arguments()) {
+ if (arg->argumentName() == "parent") {
+ parentIndex = arg->argumentIndex();
+ parentType = translateType(arg->type(), function->ownerClass(),
+ Generator::ExcludeConst | Generator::ExcludeReference).replace("*", "");
+ break;
+ }
+ }
+ if (parentIndex != -1) {
+ if (!closePolicy)
+ s << (hasModifications ? ", " : "[ ");
+ else
+ s << ", ";
+
+ s << "parent_policy_add< " << parentIndex + 2 << ", 1, "
+ << parentType << " , " << function->ownerClass()->qualifiedCppName();
+
+ hasPolicy = true;
+ closePolicy++;
+ }
+ } else {
+ if (!closePolicy)
+ s << (hasModifications ? ", " : "[ ");
+ else
+ s << ", ";
+
+ if (callPolicy.endsWith("()"))
+ callPolicy = callPolicy.remove(callPolicy.size() - 2, 2);
+
+ s << callPolicy;
+ hasPolicy = true;
+ }
+
+ while(closePolicy) {
+ s << " > ";
+ closePolicy--;
+ }
+
+ if (hasModifications)
+ s << ')';
+ else if (hasPolicy)
+ s << "() ]";
+}
+
+QString CppGenerator::getFunctionReturnType(const AbstractMetaFunction* func)
+{
+ QString modifiedReturnType = QString(func->typeReplaced(0));
+
+ return modifiedReturnType.isNull() ? translateType(func->type(), func->implementingClass()) : modifiedReturnType;
+}
+
+QString CppGenerator::writeFunctionCast(QTextStream &s,
+ const AbstractMetaFunction* func,
+ const QString& castNameSuffix,
+ const QString& className)
+{
+ QString castName = getFuncTypedefName(func) + castNameSuffix;
+ const AbstractMetaClass* cppClass = func->ownerClass();
+ bool isWrapped = !func->isVirtual() &&
+ (func->hasInjectedCode() || func->isThread() || func->allowThread());
+ bool isVirtualMethodDefault = castNameSuffix == "_default";
+
+ s << INDENT << "typedef ";
+ s << getFunctionReturnType(func);
+ s << " (";
+ if (cppClass && !func->isStatic() && func->ownerClass() && !isVirtualMethodDefault) {
+ if (!isWrapped) {
+ // pointer to a class method
+ if (!className.isEmpty())
+ s << className;
+ else if (func->isVirtual() && !func->declaringClass()->isAbstract())
+ s << func->declaringClass()->qualifiedCppName();
+ else
+ s << cppClass->qualifiedCppName();
+
+ s << "::";
+ }
+ }
+
+ s << '*' << castName << ") (";
+ if (isVirtualMethodDefault) {
+ if (func->isConstant())
+ s << "const ";
+
+ s << func->implementingClass()->qualifiedCppName() << "&";
+ if (func->arguments().size() > 0)
+ s << ", ";
+ }
+ int options = SkipName | SkipDefaultValues | SkipRemovedArguments;
+ if (isWrapped && !func->isStatic())
+ options |= WriteSelf;
+
+ writeFunctionArguments(s, func, options);
+ s << ')';
+
+ if (func->isConstant() && !isWrapped && !isVirtualMethodDefault)
+ s << " const";
+
+ s << ';' << endl;
+
+ return castName;
+}
+
+QString CppGenerator::verifyDefaultReturnPolicy(const AbstractMetaFunction *cppFunction, const QString& callPolicy)
+{
+ AbstractMetaType *type = cppFunction->type();
+ QString returnPolicy;
+
+ if (type && type->isReference() && type->isConstant()) {
+ returnPolicy = "python::return_value_policy<python::copy_const_reference";
+ if (!callPolicy.isEmpty())
+ returnPolicy += ", " + callPolicy;
+ returnPolicy += " >()";
+ } else if (type && (type->isReference() || type->isQObject() || type->isObject())) {
+ bool cppOwnership = type->isConstant();
+ if (cppFunction->isStatic() || cppOwnership) {
+ returnPolicy = "python::return_value_policy<PySide::return_ptr_object< "
+ + (cppOwnership ? QString("true") : QString("false")) + "> >()";
+ } else if (type->isQObject() || type->isObject()) {
+ returnPolicy = QString("PySide::return_object<1, 0, %1, %2 %3 %4 >()")
+ .arg(getArgumentType(cppFunction->ownerClass(), cppFunction, -1))
+ .arg(getArgumentType(cppFunction->ownerClass(), cppFunction, 0))
+ .arg(callPolicy.isEmpty() ? "" : ",")
+ .arg(callPolicy);
+ } else {
+ returnPolicy = QString("python::return_internal_reference<%1 %2>()")
+ .arg(callPolicy.isEmpty() ? "" : ",")
+ .arg(callPolicy);
+ }
+ } else if (!callPolicy.isEmpty()) {
+ returnPolicy = callPolicy + "()";
+ }
+
+ return returnPolicy;
+}
+
+static int boost_parent_policy_index(int i, const AbstractMetaFunction* func = 0)
+{
+ if (func && func->isStatic())
+ return i;
+
+ if (i == -1)
+ return 1;
+ else if (i > 0)
+ return i + 1;
+ else
+ return i;
+}
+
+QString CppGenerator::getArgumentType(const AbstractMetaClass *cppClass, const AbstractMetaFunction *func, int idx)
+{
+ QString retval;
+ if (idx == -1) {
+ retval = cppClass->qualifiedCppName();
+ } else if (idx == 0 && func->type()) {
+ retval = translateType(func->type(), cppClass,
+ Generator::ExcludeConst | Generator::ExcludeReference);
+ } else if (idx > 0) {
+ retval = argumentString(func, func->arguments()[idx-1],
+ Generator::SkipDefaultValues | Generator::ExcludeConst |
+ Generator::ExcludeReference | Generator::SkipName);
+ }
+
+ retval = retval.trimmed();
+ if (retval.endsWith('*'))
+ retval.chop(1);
+ return retval;
+}
+
+QString CppGenerator::getFunctionCallPolicy(const AbstractMetaFunction *func)
+{
+ QString callPolicy;
+ QStringList callPolicies;
+ bool returnChild = false;
+ const AbstractMetaClass* cppClass = func->implementingClass();
+
+ const int numArgs = func->arguments().count();
+
+ for (int i = -1; i <= numArgs; ++i) {
+ ArgumentOwner ao = func->argumentOwner(cppClass, i);
+ //Parent Policy
+ if ((ao.index != -2) && (ao.index != i)) {
+ switch (ao.action) {
+ case ArgumentOwner::Add:
+ if (!i) {
+ callPolicy = "return_object<";
+ returnChild = true;
+ } else {
+ callPolicy = "parent_policy_add<";
+ }
+ break;
+ case ArgumentOwner::Remove:
+ callPolicy = "parent_policy_remove<";
+ break;
+ default:
+ continue;
+ }
+
+ callPolicy += QString("%1, %2, %3, %4")
+ .arg(boost_parent_policy_index(ao.index, func))
+ .arg(boost_parent_policy_index(i, func))
+ .arg(getArgumentType(cppClass, func, ao.index))
+ .arg(getArgumentType(cppClass, func, i));
+
+ callPolicies << callPolicy;
+ } else if (i) { //only function args ignore return value
+ //Ownership policy
+ bool changeOwnership = false;
+ bool releaseOwnership = false;
+ TypeSystem::Ownership owner = func->ownership(cppClass,
+ TypeSystem::TargetLangCode, i);
+
+ switch(owner)
+ {
+ case TypeSystem::CppOwnership:
+ releaseOwnership = true;
+ case TypeSystem::TargetLangOwnership:
+ changeOwnership = true;
+ break;
+ default:
+ changeOwnership = false;
+ }
+
+ if (changeOwnership)
+ {
+ QString ownershipPolicy = QString("transfer_ownership<%1, %2, %3")
+ .arg(boost_parent_policy_index(i, func))
+ .arg(releaseOwnership ? "true" : "false")
+ .arg(getArgumentType(cppClass, func, i));
+ callPolicies << ownershipPolicy;
+ }
+ }
+ }
+
+ if (callPolicies.size() > 0) {
+ callPolicy = callPolicies.join(", ");
+ for (int i = 0; i < callPolicies.count(); ++i)
+ callPolicy += " >";
+ }
+
+ QString returnPolicy;
+
+ //return value
+ bool cppOwnership = false;
+
+ if (!returnChild) {
+ switch (func->ownership(cppClass, TypeSystem::TargetLangCode, 0))
+ {
+ case TypeSystem::CppOwnership:
+ cppOwnership = true;
+ case TypeSystem::TargetLangOwnership:
+ {
+ QString cppOwnershipFlag = (cppOwnership ? "true" : "false");
+ returnPolicy = "python::return_value_policy< PySide::return_ptr_object<" + cppOwnershipFlag + "> ";
+ if (!callPolicy.isEmpty())
+ returnPolicy += ", " + callPolicy;
+ returnPolicy += " >()";
+ break;
+ }
+ default:
+ returnPolicy = verifyDefaultReturnPolicy(func, callPolicy);
+ break;
+ }
+ }
+
+ //return policy
+ if (func->shouldReturnThisObject())
+ return "python::return_self< " + callPolicy + " >()";
+ else if (!returnPolicy.isEmpty())
+ return returnPolicy;
+ else if (!callPolicy.isEmpty())
+ return callPolicy + "()";
+
+ return QString();
+}
+
+/*!\internal
+ Function used to write the enum boost code on the buffer
+ \param s the output buffer
+ \param cpp_enum the pointer to metaenum information to be translated to boost
+*/
+void CppGenerator::writeEnum(QTextStream &s,
+ const AbstractMetaEnum *cppEnum,
+ const QString &nameSpace)
+{
+ s << INDENT << "python::enum_<" << nameSpace << cppEnum->name();
+ s << ">(\"" << cppEnum->name() << "\")" << endl;
+ const AbstractMetaEnumValueList &values = cppEnum->values();
+ EnumTypeEntry *ete = cppEnum->typeEntry();
+
+ foreach (const AbstractMetaEnumValue* enumValue, values) {
+ Indentation indent(INDENT);
+ if (ete->isEnumValueRejected(enumValue->name()))
+ continue;
+
+ s << INDENT << ".value(\"" << enumValue->name() << "\", ";
+ s << nameSpace << enumValue->name() << ")" << endl;
+ }
+
+ //Export values to current scope
+ s << INDENT << INDENT << ".export_values()" << endl;
+ s << INDENT << ";" << endl << endl;
+
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+
+ if (flagsEntry) {
+ s << INDENT << "PySide::declare_" << (cppEnum->typeEntry()->forceInteger() ? "int_" : "") << "qflags< "
+ << flagsEntry->originalName() << " >(\"" << flagsEntry->flagsName() << "\");" << endl;
+ }
+
+ //register enum in typemanager
+ s << INDENT
+ << "type_manager::instance().register_native_type<int>(\""
+ << cppEnum->qualifier() << "::" << cppEnum->name() << "\");\n\n";
+}
+
+void CppGenerator::writeEnums(QTextStream &s, const AbstractMetaClass *cppClass, bool useNamespace)
+{
+ AbstractMetaEnumList enums = cppClass->enums();
+ if (!enums.size())
+ return;
+
+ s << INDENT << "// Enums" << endl;
+ QString name_space;
+ if (useNamespace || !cppClass->isPolymorphic() || cppClass->hasPrivateDestructor())
+ name_space = cppClass->qualifiedCppName() + "::";
+
+ foreach (AbstractMetaEnum *cpp_enum, enums)
+ writeEnum(s, cpp_enum, name_space);
+}
+
+void CppGenerator::writeImplicitlyConversion(QTextStream &s, const AbstractMetaClass *cppClass)
+{
+#if 0
+ if (cppClass->isNamespace())
+ return;
+ s << endl << "// Implicitly conversions" << endl;
+ QStringList interfaces = getBaseClasses(cppClass);
+
+ if (!interfaces.size()) {
+ s << INDENT << "python::implicitly_convertible< " << endl;
+ s << INDENT << INDENT << "std::auto_ptr< " << getWrapperName(cppClass->name()) << " >," << endl;
+ s << INDENT << INDENT << "std::auto_ptr< " << cppClass->name() << " > >();" << endl;
+ } else {
+ foreach (QString base_class, interfaces) {
+ s << INDENT << "python::implicitly_convertible< " << endl;
+ s << INDENT << INDENT << "std::auto_ptr< " << cppClass->name() << " >," << endl;
+ s << INDENT << INDENT << "std::auto_ptr< " << base_class << " > >();" << endl;
+ }
+ }
+#endif
+}
+
+
+void CppGenerator::writeDestructor(QTextStream &s, const AbstractMetaClass *cppClass)
+{
+ Indentation indentation(INDENT);
+ QString wrapperName = getWrapperName(cppClass);
+ s << wrapperName << "::~" << wrapperName << "()" << endl << "{" << endl
+ << INDENT << "PySide::qptr_base::invalidate(this);" << endl << "}" << endl;
+}
+
+/*!
+ Function used to write the class generated boost code on the buffer
+ \param s the output buffer
+ \param cppClass the pointer to metaclass information
+*/
+void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *cppClass)
+{
+ ReportHandler::debugSparse("Generating wrapper implementation for " + cppClass->fullName());
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ QString localStr, globalStr;
+ QTextStream includesLocal(&localStr);
+ QTextStream includesGlobal(&globalStr);
+
+ bool canCreateWrapper = canCreateWrapperFor(cppClass);
+
+ QList<Include> includes = cppClass->typeEntry()->extraIncludes();
+ qSort(includes.begin(), includes.end());
+
+ foreach (Include inc, includes) {
+ if (inc.type == Include::IncludePath)
+ includesGlobal << inc.toString() << endl;
+ else
+ includesLocal << inc.toString() << endl;
+ }
+
+ //workaround to access protected functions
+ s << "//workaround to access protected functions" << endl;
+ s << "#define protected public" << endl;
+
+ s << "//Base Class" << endl;
+ if (cppClass->typeEntry()->include().isValid())
+ s << cppClass->typeEntry()->include().toString() << endl << endl;
+
+ s << "//Extra includes [global]" << endl;
+ s << globalStr << endl;
+
+ s << "#undef protected" << endl;
+ s << "//Base include" << endl;
+ s << "#include \"pyside.hpp\"" << endl;
+ s << "#include \"" << getWrapperName(cppClass) << ".hpp\"" << endl;
+ foreach (AbstractMetaClass* innerClass, cppClass->innerClasses()) {
+ if (shouldGenerate(innerClass))
+ s << "#include \"" << getWrapperName(innerClass) << ".hpp\"" << endl;
+ }
+ s << endl << "//Extra includes [local]" << endl;
+ s << localStr << endl;
+
+ s << endl << "using namespace boost;" << endl;
+ s << "using namespace PySide;" << endl;
+ s << endl;
+
+ if (cppClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated)
+ s << "#Deprecated" << endl;
+
+ if (canCreateWrapper) {
+ writePrelude(s, cppClass);
+ if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor())
+ writeDestructor(s, cppClass);
+ }
+ writeBoostDeclaration(s, cppClass);
+}
+
+void CppGenerator::writePrelude(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ //inject code native beginner
+ writeCodeSnips(s, cppClass->typeEntry()->codeSnips(),
+ CodeSnip::Beginning, TypeSystem::NativeCode);
+
+ foreach (AbstractMetaFunction *func, filterFunctions(cppClass)) {
+ if ((func->isPrivate() || func->isModifiedRemoved()) && !func->isAbstract())
+ continue;
+
+ if (func->isConstructor() && (func->allowThread() || func->hasInjectedCode())) {
+ writeModifiedConstructorImpl(s, func);
+ } else if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor() &&
+ func->isConstructor() && !func->isCopyConstructor()) {
+ writeConstructorImpl(s, func);
+ } else if (func->isVirtual() || func->isAbstract()) {
+ writeVirtualMethodImpl(s, func);
+ } else if (func->hasInjectedCode() || func->isThread() || func->allowThread()) {
+ writeNonVirtualModifiedFunctionImpl(s, func);
+ } else if (func->isInGlobalScope() && func->isOperatorOverload()) {
+ writeGlobalOperatorOverloadImpl(s, func);
+ }
+ }
+
+ //inject code native end
+ writeCodeSnips(s, cppClass->typeEntry()->codeSnips(),
+ CodeSnip::End, TypeSystem::NativeCode);
+}
+
+
+void CppGenerator::writeModifiedConstructorImpl ( QTextStream& s, const AbstractMetaFunction* func )
+{
+ Indentation indentation(INDENT);
+ const AbstractMetaClass* clazz = func->ownerClass();
+ s << "static " << clazz->name() << "* " << nameForModifiedCtorFunction(func) << '(';
+ writeFunctionArguments(s, func, SkipDefaultValues);
+ s << ")\n{" << endl;
+
+ s << INDENT << clazz->name() << "* _self = 0;" << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indentation(INDENT);
+ if (func->allowThread())
+ s << INDENT << "py_allow_threads allow_threads;" << endl;
+
+ s << INDENT << "_self = new ";
+ writeFunctionCall(s, func);
+ s << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::Beginning, TypeSystem::All, func);
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::All, func);
+ s << INDENT << "python::object _obj(PySide::ptr(_self));" << endl;
+ s << INDENT << "return _self;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeConstructorImpl(QTextStream& s, const AbstractMetaFunction* func)
+{
+ s << functionSignature(func, getWrapperName(func->ownerClass()) + "::", "",
+ (Option)(OriginalTypeDescription | SkipDefaultValues));
+ s << " : ";
+ writeFunctionCall(s, func);
+ s << " {" << endl;
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::Beginning, TypeSystem::All, func);
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::All, func);
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeVirtualMethodImplHead(QTextStream& s, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+ s << INDENT << "thread_locker lock;" << endl;
+
+ if (func->hasInjectedCode()) {
+ writeCodeSnips(s, getCodeSnips(func),
+ CodeSnip::Beginning, TypeSystem::NativeCode, func);
+ }
+
+ s << INDENT << "python::object method = PySide::detail::get_override(this, \"" << func->implementingClass()->name();
+ if (func->implementingClass()->typeEntry()->isObject() || func->implementingClass()->typeEntry()->isQObject())
+ s << '*';
+
+ s << "\", \"" << func->name() << "\");" << endl
+ << INDENT << "if (method)" << endl << INDENT << "{" << endl;
+
+ {
+ Indentation indentation(INDENT);
+ s << INDENT;
+ if (func->type())
+ s << "python::object __result = ";
+
+ s << "method(";
+ writeArgumentNames(s, func, BoxedPrimitive);
+ s << ");" << endl;
+
+ QString typeName = getFunctionReturnType(func);
+ if (!typeName.isEmpty()) {
+
+ CodeSnipList codeSnips = getCodeSnips(func);
+ bool hasVirtualBeginningCode = false;
+ foreach(CodeSnip cs, codeSnips) {
+ if ((cs.position == CodeSnip::Beginning) && (cs.language == TypeSystem::TargetLangCode)) {
+ hasVirtualBeginningCode = true;
+ break;
+ }
+ }
+
+ if (hasVirtualBeginningCode) {
+ writeCodeSnips(s, codeSnips, CodeSnip::Beginning, TypeSystem::TargetLangCode, func);
+ } else if (func->type()) {
+ s << INDENT << typeName << " __return_value = " << "python::extract<" << typeName << " >(__result);" << endl;
+ bool boxedPointer = false;
+ if (func->type() && !func->type()->isConstant() &&
+ (func->type()->isObject() || func->type()->isQObject())) {
+
+ s << INDENT << "PySide::qptr<" << QString(typeName).replace("*", "") << " > __ptr(__result.ptr());" << endl
+ << INDENT << "if (__ptr.is_wrapper()) {" << endl
+ << INDENT << INDENT << "python::incref(__result.ptr());" << endl
+ << INDENT << "}" << endl
+ << INDENT << "__ptr.release_ownership();" << endl;
+ }
+
+ s << INDENT << "return __return_value;" << endl;
+ }
+ }
+ }
+ s << INDENT << "}" << endl;
+}
+
+void CppGenerator::writeVirtualMethodImpl(QTextStream& s, const AbstractMetaFunction* func)
+{
+ if (func->isModifiedRemoved())
+ return;
+
+ if (!func->isAbstract() && !func->ownerClass()->hasPrivateDestructor() &&
+ func->implementingClass() == func->ownerClass()) {
+ writeVirtualDefaultFunction(s, func);
+ }
+
+
+ QString prefix = getWrapperName(func->ownerClass()) + "::";
+ s << functionSignature(func, prefix, "",
+ Generator::OriginalTypeDescription | Generator::SkipDefaultValues)
+ << endl << "{" << endl;
+
+ writeVirtualMethodImplHead(s, func);
+
+ if (func->isAbstract())
+ writePureVirtualMethodImplFoot(s, func);
+ else
+ writeVirtualMethodImplFoot(s, func);
+
+ s << '}' << endl << endl;
+}
+
+
+void CppGenerator::writePureVirtualMethodImplFoot(QTextStream& s, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+ s << INDENT << "else" << endl
+ << INDENT << "{" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \""
+ << func->ownerClass()->name() << "." << func->name() << " : "
+ << "You need to implement pure virtual functions in python\");" << endl
+ << INDENT << "throw python::error_already_set();" << endl;
+ }
+ s << INDENT << "}" << endl;
+}
+
+void CppGenerator::writeVirtualMethodImplFoot(QTextStream& s, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+ s << INDENT << "else" << endl << INDENT << "{" << endl;
+ {
+ Indentation indentation(INDENT);
+ QString returnKeyword = func->type() ? QLatin1String("return ") : QString();
+
+ if (func->allowThread())
+ s << INDENT << "py_allow_threads allow_threads;" << endl;
+
+ s << INDENT << returnKeyword << func->implementingClass()->qualifiedCppName() << "::";
+ writeFunctionCall(s, func);
+ s << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+}
+
+void CppGenerator::writeVirtualDefaultFunction(QTextStream &s, const AbstractMetaFunction *func)
+{
+ Indentation indentation(INDENT);
+ QString returnKeyword = func->type() ? QLatin1String("return ") : QString();
+ QString defaultMethodSignature = signatureForDefaultVirtualMethod(func, getWrapperName(func->ownerClass()) + "::", "_default", Generator::SkipDefaultValues);
+ s << defaultMethodSignature << endl << '{' << endl;
+
+ if (func->allowThread())
+ s << INDENT << "py_allow_threads allow_threads;" << endl;
+
+ CodeSnipList codeSnips = getCodeSnips(func);
+ bool hasVirtualEndCode = false;
+ foreach(CodeSnip cs, codeSnips) {
+ if ((cs.position == CodeSnip::End) && (cs.language == TypeSystem::TargetLangCode)) {
+ hasVirtualEndCode = true;
+ break;
+ }
+ }
+
+ if (!hasVirtualEndCode) {
+ s << INDENT << returnKeyword << "self." << func->implementingClass()->qualifiedCppName() << "::";
+ writeFunctionCall(s, func);
+ s << ";" << endl;
+ } else {
+ writeCodeSnips(s, getCodeSnips(func),
+ CodeSnip::End, TypeSystem::TargetLangCode, func);
+ }
+ s << '}' << endl << endl;
+
+}
+
+
+
+void CppGenerator::writeNonVirtualModifiedFunctionImpl(QTextStream& s, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+
+ s << "static " << getFunctionReturnType(func) << ' ';
+ s << func->ownerClass()->name() << '_' << func->originalName() << "_modified(";
+
+ uint options = SkipRemovedArguments | SkipDefaultValues;
+ if (!func->isStatic())
+ options |= WriteSelf;
+
+ writeFunctionArguments(s, func, options);
+ s << ")" << endl << "{" << endl;
+
+ if (func->isThread())
+ s << INDENT << "thread_locker lock;" << endl;
+
+ if (func->allowThread())
+ s << INDENT << "py_allow_threads allow_threads;" << endl;
+
+ if (getCodeSnips(func).size() > 0) {
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::Beginning, TypeSystem::All, func);
+ writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::All, func);
+ } else {
+ s << INDENT;
+ if (func->type())
+ s << "return ";
+
+ if (func->isStatic())
+ s << func->declaringClass()->name() << "::";
+ else
+ s << "self.";
+
+ writeFunctionCall(s, func);
+ s << ";" << endl;
+ }
+
+ s << '}' << endl << endl;
+}
+
+AbstractMetaFunction* CppGenerator::findMainConstructor(const AbstractMetaClass* clazz)
+{
+ foreach (AbstractMetaFunction* func, clazz->functions()) {
+ if (func->isConstructor() &&
+ func->isPublic() &&
+ !func->isModifiedRemoved() &&
+ !func->isPrivate()) {
+ return func;
+ }
+ }
+ return 0;
+}
+
+void CppGenerator::writeHashFunction(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ QString argType;
+
+ //WORKAROUND: diferent way to QChar
+ if (cppClass->name() == "QChar")
+ argType = "QChar";
+ else
+ argType = "const " + cppClass->name() + "&";
+
+ s << "// Hash function" << endl
+ << "{" << endl
+ << INDENT << INDENT << "typedef uint (*hash_type) ( " << argType << " );"
+ << INDENT << INDENT << "python_cls.def(\"__hash__\", hash_type(&"
+ << cppClass->typeEntry()->hashFunction() << "));" << endl
+ << "}" << endl;
+}
+
+QString CppGenerator::baseClassName(const QString& name)
+{
+ QStringList lst = name.split("::");
+ return lst.last();
+}
+
+void CppGenerator::writeBoostDeclaration(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ Indentation indent(INDENT);
+ QString wrapperName = getWrapperName(cppClass);
+
+ s << "void " << wrapperName << "::define_python_class() throw() {" << endl;
+
+ const AbstractMetaFunction* mainCtor = 0;
+ bool mainCtorHasModifications = false;
+ if (!cppClass->isNamespace()) {
+ // python_cls declaration
+ mainCtor = findMainConstructor(cppClass);
+ if (mainCtor)
+ mainCtorHasModifications = mainCtor->allowThread() || mainCtor->hasInjectedCode();
+
+ s << INDENT;
+ if (!cppClass->isPolymorphic() || cppClass->hasPrivateDestructor())
+ s << wrapperName << "::";
+
+ s << "class_type python_cls(\""
+ << baseClassName(cppClass->name()) << "\", ";
+
+ if (!mainCtor || mainCtorHasModifications)
+ s << "python::no_init";
+ else
+ writeConstructorInitialization(s, mainCtor);
+
+ s << ");" << endl << endl;
+ } else {
+ QRegExp reg("(?:\\w+::)*(\\w+)");
+ reg.indexIn(cppClass->name());
+ s << INDENT << "python::class_<Namespace> python_cls(\"" << reg.cap(1) << "\");" << endl;
+ }
+ // scope declaration
+ s << INDENT << "python::scope " << wrapperName << "_scope(python_cls);" << endl;
+
+ if (cppClass->templateBaseClass() && cppClass->templateBaseClass()->typeEntry()->isContainer()) {
+ //const ContainerTypeEntry *type = static_cast<const ContainerTypeEntry*>(cppClass->templateBaseClass()->typeEntry());
+ //if (type->type() == ContainerTypeEntry::ListContainer) {
+ s << endl << INDENT << "//Index suite for QContainer" << endl
+ << INDENT << "python_cls.def(qcontainer_indexing_suite< " << cppClass->qualifiedCppName() << " >());" << endl << endl;
+ //}
+ }
+
+ if (isCopyable(cppClass) && !cppClass->isNamespace()) {
+ s << INDENT << "python_cls.def(python::init<const ";
+ s << cppClass->qualifiedCppName() << "&>());" << endl;
+ }
+
+ if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor() && canCreateWrapperFor(cppClass)) {
+ QString heldType = cppClass->typeEntry()->heldTypeValue();
+ if (heldType.isEmpty())
+ heldType = "PySide::qptr";
+
+ s << INDENT << "python::implicitly_convertible< "
+ << heldType << "<" << wrapperName << ">, "
+ << heldType << "<" << cppClass->qualifiedCppName() << "> >();" << endl;
+ }
+
+ //Enums
+ writeEnums(s, cppClass, cppClass->hasPrivateDestructor() || cppClass->isNamespace());
+
+ if (cppClass->innerClasses().count()) {
+ s << endl << INDENT << "// Inner classes" << endl;
+ foreach (AbstractMetaClass* innerClass, cppClass->innerClasses()) {
+ if (!innerClass->typeEntry()->generateCode())
+ continue;
+ s << INDENT << getWrapperName(innerClass) << "::define_python_class();" << endl;
+ }
+ }
+
+ //Fields
+ foreach (AbstractMetaField *field, cppClass->fields()) {
+ QString strAccess;
+
+ if (field->isPublic()) {
+ if (field->type()->isConstant())
+ strAccess = "def_readonly";
+ else
+ strAccess = "def_readwrite";
+
+ s << INDENT << "python_cls."
+ << strAccess
+ << "(\"" << field->name() << "\", &"
+ << field->enclosingClass()->name() << "::" << field->name() << ");" << endl;
+ }
+ }
+
+ writeCodeSnips(s, cppClass->typeEntry()->codeSnips(),
+ CodeSnip::Beginning, TypeSystem::TargetLangCode);
+
+ QSet<QString> staticMethods;
+
+ if (!cppClass->isNamespace()) {
+ //search for all static methods to match with normal functions
+ //to rename when match with one member function
+ foreach (AbstractMetaFunction *func, filterFunctions(cppClass)) {
+ if (func->isStatic() && !func->isOperatorOverload())
+ staticMethods << func->name();
+ }
+ }
+
+ foreach (AbstractMetaFunction *func, filterFunctions(cppClass)) {
+ if (func->isModifiedRemoved() || func->isPrivate() || func->isSignal())
+ continue;
+
+ //rename static function when is the same name as member function
+ if (!cppClass->isNamespace() && func->isStatic()) {
+ QString staticName(createStaticFunctionName(func));
+ QSet<QString>::iterator staticFuncInter = staticMethods.find(staticName);
+ if (staticFuncInter != staticMethods.end())
+ func->setName(staticName);
+ } else {
+ QSet<QString>::iterator staticFuncInter = staticMethods.find(func->name());
+ if (staticFuncInter != staticMethods.end()) {
+ staticMethods.erase(staticFuncInter);
+ staticMethods << createStaticFunctionName(func);
+ }
+ }
+
+ if (func->isOperatorOverload()) {
+ // Do not join the ifs -- isOperatorOverload must be checked alone
+ if (func->originalName() == func->name())
+ writeOperatorOverload(s, func);
+ } else if (func->isConstructor()) {
+ if (mainCtorHasModifications || func != mainCtor)
+ writeConstructor(s, func);
+ } else if (!func->isVirtual() &&
+ (func->hasInjectedCode() ||
+ func->isThread() || func->allowThread())) {
+ writeModifiedMethodDef(s, func);
+ } else if (func->implementingClass() == func->ownerClass()) {
+ writeNormalMethodDef(s, func);
+ }
+
+ //if is namespace all methothds is stattic
+ if (cppClass->isNamespace())
+ s << INDENT << "python_cls.staticmethod(\"" << func->name() << "\");" << endl;
+ }
+
+ writeCodeSnips(s, cppClass->typeEntry()->codeSnips(),
+ CodeSnip::End, TypeSystem::TargetLangCode);
+
+ if (!cppClass->isNamespace()) {
+ // Static methods
+ if (!staticMethods.isEmpty())
+ s << INDENT << "// Static methods" << endl;
+
+ foreach (QString funcName, staticMethods)
+ s << INDENT << "python_cls.staticmethod(\"" << funcName << "\");" << endl;
+ }
+
+ // qHash usage
+ if (!cppClass->typeEntry()->hashFunction().isEmpty())
+ writeHashFunction(s, cppClass);
+
+ // implicity conversions
+ writeImplicitlyConversion(s, cppClass);
+
+ // register object/value type
+ if (!cppClass->isNamespace()) {
+ QString className = cppClass->qualifiedCppName();
+ const char* funcName = (cppClass->typeEntry()->isObject() || !isCopyable(cppClass)) ? "object" : "value";
+ s << INDENT
+ << "type_manager::instance().register_"
+ << funcName
+ << "_type<" << className << " >(\""
+ << cppClass->qualifiedCppName() << (cppClass->typeEntry()->isObject() ? "*" : "") << "\");\n";
+ }
+ s << '}' << endl;
+}
+
+void CppGenerator::writeConstructor(QTextStream& s, const AbstractMetaFunction* func)
+{
+ s << INDENT << "python_cls.def(";
+ writeConstructorInitialization(s, func);
+ s << ");" << endl;
+}
+
+void CppGenerator::writeFunctionArgsDef(QTextStream &sOut,
+ const AbstractMetaFunction *cppFunction)
+{
+ bool hasDefaultValue = false;
+ int argUsed = 0;
+ QString aux;
+ QTextStream s(&aux);
+
+ foreach (const AbstractMetaArgument *arg, cppFunction->arguments()) {
+ if (cppFunction->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ if (argUsed > 0)
+ s << ", ";
+
+ if (!m_disableNamedArgs)
+ s << "python::arg(\"" << arg->argumentName() << "\")";
+ else
+ s << "python::arg(0)";
+
+ if (!arg->defaultValueExpression().isEmpty()) {
+ QString defaultValue = arg->defaultValueExpression();
+ bool isPointer = arg->type()->isObject() ||
+ arg->type()->isQObject() ||
+ arg->type()->isNativePointer();
+
+ if (isPointer && defaultValue == "0") {
+ defaultValue = "python::object()";
+ } else if (arg->type()->isFlags()) {
+ defaultValue = " (int) " + defaultValue;
+ } else if (arg->type()->isEnum()) {
+ QString enumName = arg->type()->minimalSignature();
+ QRegExp reg("(.*::)");
+ reg.indexIn(enumName);
+ if (!defaultValue.startsWith(reg.cap(1)))
+ defaultValue = reg.cap(1) + defaultValue;
+ }
+
+ s << "=" << defaultValue;
+ hasDefaultValue = true;
+ }
+ argUsed++;
+ }
+
+ if (hasDefaultValue || ((argUsed > 0) && !m_disableNamedArgs))
+ sOut << "," << endl << INDENT << INDENT << "(" << aux << ")";
+}
+
+void CppGenerator::writeNormalMethodDef(QTextStream& s, const AbstractMetaFunction* func)
+{
+ s << INDENT << '{' << endl;
+ {
+ Indentation indentation(INDENT);
+ QString wrapperClassName = getWrapperName(func->ownerClass());
+ bool needDefaultFunction = func->isVirtual() && !func->isAbstract() && !func->ownerClass()->hasPrivateDestructor();
+ QString castName;
+
+ if (needDefaultFunction)
+ castName = writeFunctionCast(s, func, "_default", func->implementingClass()->qualifiedCppName());
+ else
+ castName = writeFunctionCast(s, func);
+
+ s << INDENT << "python_cls.def(\"" << func->name() << "\", ";
+
+ if (needDefaultFunction) { // add the default function
+ s << castName << "(&" << wrapperClassName << "::" << func->originalName() << "_default)";
+ } else {
+ if (func->isAbstract())
+ s << "python::pure_virtual";
+ s << '(' << castName << '(' << getMethodPointerString(func) << "))";
+ }
+
+ QString functionPolicy = getFunctionCallPolicy(func);
+ if (!functionPolicy.isEmpty())
+ s << ", " << functionPolicy;
+
+ writeFunctionArgsDef(s, func);
+ s << ");" << endl;
+ }
+ s << INDENT << '}' << endl;
+}
+
+void CppGenerator::writeModifiedMethodDef(QTextStream& s, const AbstractMetaFunction* func)
+{
+ s << INDENT << '{' << endl;
+ {
+ Indentation indentation(INDENT);
+ QString castName = writeFunctionCast(s, func);
+ s << INDENT
+ << "python_cls.def(\""
+ << func->name() << "\", "
+ << castName
+ << "(&" << func->implementingClass()->name()
+ << "_" << func->originalName()
+ << "_modified)";
+ QString functionPolicy = getFunctionCallPolicy(func);
+ if (!functionPolicy.isEmpty())
+ s << ", " << functionPolicy;
+
+ writeFunctionArgsDef(s, func);
+ s << ");" << endl;
+ }
+ s << INDENT << '}' << endl;
+}
+
+QString CppGenerator::operatorFunctionName(const AbstractMetaFunction *cppFunction)
+{
+ QString funcName = QString("%1_operator_%2_")
+ .arg(cppFunction->arguments()[0]->type()->name())
+ .arg(cppFunction->arguments()[1]->type()->name());
+
+ if (cppFunction->name().contains(">>")) {
+ funcName += "rshift";
+ } else if (cppFunction->name().contains("<<")) {
+ funcName += "lshift";
+ } else {
+ //TODO: implemente support to others operators
+ return QString();
+ }
+
+ return funcName;
+}
+
+void CppGenerator::writeGlobalOperatorOverloadImpl(QTextStream& s, const AbstractMetaFunction* cppFunction)
+{
+ Indentation indent(INDENT);
+ QString operatorStr;
+
+ if (cppFunction->name().contains(">>")) {
+ operatorStr = " >> ";
+ } else if (cppFunction->name().contains("<<")) {
+ operatorStr = " << ";
+ } else {
+ //TODO: implemente support to others operators
+ return;
+ }
+
+ QString funcName = operatorFunctionName(cppFunction);
+ bool reverse = cppFunction->isReverseOperator();
+
+ const AbstractMetaClass *klass = cppFunction->ownerClass();
+ s << "python::object " << funcName << "(";
+ writeFunctionArguments(s, cppFunction, SkipDefaultValues | SkipRemovedArguments);
+ s << ")" << endl << "{" << endl
+ << INDENT << cppFunction->arguments()[reverse]->argumentName()
+ << operatorStr << cppFunction->arguments()[!reverse]->argumentName() << ";" << endl
+ << INDENT << "return python::object(PySide::ptr(&"
+ << cppFunction->arguments()[reverse]->argumentName() << "));" << endl
+ << "}" << endl;
+}
+
+void CppGenerator::writeGlobalOperatorOverload(QTextStream &s, const AbstractMetaFunction *cppFunction)
+{
+ QString funcName = operatorFunctionName(cppFunction);
+ if (funcName.isEmpty())
+ return;
+
+ bool reverse = cppFunction->isReverseOperator();
+ QString operatorStr;
+ if (cppFunction->name().contains(">>")) {
+ operatorStr = QString("__%1rshift__").arg(reverse ? "r" : "");
+ } else if (cppFunction->name().contains("<<")) {
+ operatorStr = QString("__%1lshift__").arg(reverse ? "r" : "");
+ } else {
+ //TODO: implemente support to others operators
+ return;
+ }
+
+ s << INDENT << "python_cls.def(\"" << operatorStr << "\", " << funcName << ");\n";
+}
+
+QString CppGenerator::getOperatorArgumentTypeName(const AbstractMetaFunction *cppFunction, int argumentIndex)
+{
+ AbstractMetaType* type = cppFunction->arguments()[argumentIndex]->type();
+ if (type->name() == cppFunction->implementingClass()->name())
+ return QLatin1String("python::self");
+
+ QString typeName = translateType(type, cppFunction->implementingClass(),
+ (Option)(ExcludeReference));
+ return type->isPrimitive() ? "(" + typeName + ")(0)" : "python::other<" + typeName + " >()";
+}
+
+void CppGenerator::writeOperatorOverload(QTextStream& s, const AbstractMetaFunction* cppFunction)
+{
+ static QRegExp operatorRegex("operator(.+)");
+
+ if (!operatorRegex.exactMatch(cppFunction->originalName())) {
+ qWarning("What kind of operator is that!? %s",
+ cppFunction->originalName().toLocal8Bit().data());
+ return;
+ }
+
+ QString op(operatorRegex.cap(1));
+ if (op == "=" || op == "[]") {
+ // = is handled by type boost and type conversions, [] by someone...
+ return;
+ }
+
+ // no args == member unary operator
+ if (!cppFunction->arguments().count()) {
+ // check if it is a name instead of an operator symbol
+ // this means it is a conversion operator that will be ignored for now
+ static QRegExp ConversionOperatorRegex("[A-Za-z]+");
+ if (ConversionOperatorRegex.indexIn(op) < 0)
+ s << INDENT << "python_cls.def(" << op << "python::self);" << endl;
+ return;
+ }
+
+ //this because global operators use first arg with current class
+ if (cppFunction->isInGlobalScope()) {
+ writeGlobalOperatorOverload(s, cppFunction);
+ return;
+ }
+
+ QString operand1, operand2;
+ if (cppFunction->arguments().count() == 1) {
+ operand1 = "python::self";
+ operand2 = getOperatorArgumentTypeName(cppFunction, 0);
+ } else {
+ operand1 = getOperatorArgumentTypeName(cppFunction, 0);
+ operand2 = getOperatorArgumentTypeName(cppFunction, 1);
+ }
+ s << INDENT << "python_cls.def(" << operand1 << ' ' << op << ' ' << operand2 << ");\n";
+}
+
+void CppGenerator::finishGeneration()
+{
+ //Generate boost wrapper file
+ QString classFiles;
+ QTextStream sClassFiles(&classFiles);
+ QString classPythonDefines;
+ QTextStream sClassPythonDefines(&classPythonDefines);
+
+ Indentation indent(INDENT);
+
+ foreach (AbstractMetaClass *cls, classes()) {
+ if (!shouldGenerate(cls) || cls->enclosingClass())
+ continue;
+
+ if (m_packageName.isEmpty())
+ m_packageName = cls->package();
+
+ QString wrapperName = getWrapperName(cls);
+ QString boostFilename;
+ boostFilename += wrapperName + ".hpp";
+ sClassFiles << "#include \"" << boostFilename << "\"" << endl;
+
+ QString define_str = wrapperName + "::";
+ define_str += "define_python_class();";
+
+ sClassPythonDefines << INDENT << define_str << endl;
+ }
+
+ QString moduleFileName(outputDirectory() + "/" + subDirectoryForPackage(m_packageName));
+ moduleFileName += "/" + moduleName().toLower() + "_module_wrapper.cpp";
+
+ QFile file(moduleFileName);
+ if (file.open(QFile::WriteOnly)) {
+ QTextStream s(&file);
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ s << "#include \"converter_register_" << moduleName().toLower();
+ s << ".hpp\"" << endl << endl;
+
+ s << classFiles << endl;
+
+ s << "using namespace boost;" << endl << endl;
+ s << "using namespace PySide;" << endl << endl;
+
+ s << "// forward decl. for global func. register\n";
+ s << "void register_global_functions_" << moduleName().toLower() << "();\n\n";
+
+ s << "BOOST_PYTHON_MODULE(" << moduleName() << ")" << endl;
+ s << "{" << endl;
+
+ foreach (QString requiredModule, TypeDatabase::instance()->requiredTargetImports()) {
+ s << INDENT << "if (";
+ s << "PyImport_ImportModule(\"" << requiredModule << "\") == NULL) {" << endl;
+ s << INDENT << INDENT << "PyErr_SetString(PyExc_ImportError,";
+ s << "\"could not import " << requiredModule << "\");" << endl;
+ s << INDENT << INDENT << "return;" << endl;
+ s << INDENT << "}" << endl;
+ }
+ s << endl;
+
+ s << INDENT << "register_type_converters_" << moduleName().toLower() << "();" << endl << endl
+ << classPythonDefines << endl
+ << INDENT << "register_global_functions_" << moduleName().toLower() << "();" << endl
+ << INDENT << "//Namespaces" << endl;
+
+
+ s << "}" << endl << endl;
+ }
+
+ writeGlobalFunctions();
+}
+
+void CppGenerator::writeGlobalFunctions()
+{
+ QString fileName = moduleName().toLower() + "_globals_wrapper.cpp";
+
+ FileOut fileOut(outputDirectory() + "/" + subDirectoryForPackage(m_packageName) + "/" + fileName);
+
+ QSet<QString> includes;
+ QString defsStr;
+ QTextStream defsStream(&defsStr);
+
+ foreach (AbstractMetaFunction* func, globalFunctions()) {
+ QString incFile = func->includeFile();
+ QRegExp regex("\\b" + moduleName() + "\\b");
+ //FIXME: this regex doesn't work with all cases, e.g.:
+ // moduleName() = local
+ // incFile = /usr/local/include/local
+ if (regex.indexIn(incFile) == -1)
+ continue;
+
+ int idx = incFile.indexOf(moduleName());
+ QString cleanPath = QDir::cleanPath(incFile.mid(idx));
+ if (!cleanPath.startsWith(moduleName()))
+ continue;
+
+ includes << cleanPath;
+ defsStream << INDENT << "{\n" << INDENT;
+ QString castName = writeFunctionCast(defsStream, func);
+ defsStream << INDENT << INDENT << "python::def(\"" << func->name();
+ defsStream << "\", " << castName << '(' << func->name() << ')';
+ if (func->type() && func->type()->isReference())
+ defsStream << ", python::return_internal_reference<>()";
+ defsStream << ");\n";
+ defsStream << INDENT << "}\n";
+ }
+
+ QTextStream& s = fileOut.stream;
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ s << "#include \"pyside.hpp\"" << endl;
+
+ foreach (QString include, includes)
+ s << "#include <" << include << ">\n";
+
+ s << "using namespace boost;\n\n";
+ s << "using namespace PySide;\n\n";
+
+ // Add module level code snippets to 'Global' class
+ TypeSystemTypeEntry *moduleEntry = dynamic_cast<TypeSystemTypeEntry *>(
+ TypeDatabase::instance()->findType(m_packageName));
+ QString sEnd;
+ QTextStream snipEnd(&sEnd);
+ if (moduleEntry && moduleEntry->codeSnips().size() > 0) {
+ foreach (CodeSnip snip, moduleEntry->codeSnips()) {
+ if (snip.position == CodeSnip().Beginning)
+ snip.formattedCode(s, INDENT);
+ else
+ snip.formattedCode(snipEnd, INDENT);
+ }
+ }
+
+ s << "\nvoid register_global_functions_" << moduleName().toLower() << "() {\n";
+ { //global enums
+ QString name_space;
+
+ foreach (AbstractMetaEnum *cppEnum, globalEnums()) {
+ if (cppEnum)
+ writeEnum(s, cppEnum, name_space);
+ }
+ }
+ s << sEnd;
+ s << defsStr;
+ s << "}\n";
+}
+