diff options
author | Marcelo Lira <marcelo.lira@openbossa.org> | 2011-08-02 17:01:40 -0300 |
---|---|---|
committer | Hugo Parente Lima <hugo.pl@gmail.com> | 2012-03-08 16:17:07 -0300 |
commit | f9e9189be4b622b74d0df2787a09f93fe7a5d0ae (patch) | |
tree | 37e5c07fb73a638e65a13352cb3c50304135d6e7 /generator | |
parent | 3e8c945bdc731fb7c9eaff0007abc02bfa1e5c37 (diff) |
Disassembled ShibokenGenerator's writeCodeSnips method.
Also added writeConversionRule methods to CppGenerator.
Reviewed by Hugo Parente <hugo.lima@openbossa.org>
Reviewed by Luciano Wolf <luciano.wolf@openbossa.org>
Reviewed by Renato Araújo <renato.filho@openbossa.org>
Diffstat (limited to 'generator')
-rw-r--r-- | generator/cppgenerator.cpp | 103 | ||||
-rw-r--r-- | generator/cppgenerator.h | 5 | ||||
-rw-r--r-- | generator/shibokengenerator.cpp | 450 | ||||
-rw-r--r-- | generator/shibokengenerator.h | 39 |
4 files changed, 301 insertions, 296 deletions
diff --git a/generator/cppgenerator.cpp b/generator/cppgenerator.cpp index 6845d4f4f..827ec28e3 100644 --- a/generator/cppgenerator.cpp +++ b/generator/cppgenerator.cpp @@ -39,49 +39,6 @@ QHash<QString, QString> CppGenerator::m_mpFuncs = QHash<QString, QString>(); int CppGenerator::m_currentErrorCode = 0; // utility functions -inline CodeSnipList getConversionRule(TypeSystem::Language lang, const AbstractMetaFunction *function) -{ - CodeSnipList list; - - foreach(AbstractMetaArgument *arg, function->arguments()) { - QString convRule = function->conversionRule(lang, arg->argumentIndex() + 1); - if (!convRule.isEmpty()) { - CodeSnip snip(0, TypeSystem::TargetLangCode); - snip.position = CodeSnip::Beginning; - - convRule.replace("%in", arg->name()); - convRule.replace("%out", arg->name() + "_out"); - - snip.addCode(convRule); - list << snip; - } - - } - return list; -} - -inline CodeSnipList getReturnConversionRule(TypeSystem::Language lang, - const AbstractMetaFunction *function, - const QString& inputName, - const QString& outputName) -{ - CodeSnipList list; - - QString convRule = function->conversionRule(lang, 0); - if (!convRule.isEmpty()) { - CodeSnip snip(0, lang); - snip.position = CodeSnip::Beginning; - - convRule.replace("%in", inputName); - convRule.replace("%out", outputName); - - snip.addCode(convRule); - list << snip; - } - - return list; -} - inline AbstractMetaType* getTypeWithoutContainer(AbstractMetaType* arg) { if (arg && arg->typeEntry()->isContainer()) { @@ -339,7 +296,7 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl // class inject-code native/beginning if (!metaClass->typeEntry()->codeSnips().isEmpty()) { - writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::Beginning, TypeSystem::NativeCode, 0, 0, metaClass); + writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::Beginning, TypeSystem::NativeCode, metaClass); s << endl; } @@ -570,7 +527,7 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl // class inject-code native/end if (!metaClass->typeEntry()->codeSnips().isEmpty()) { - writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::End, TypeSystem::NativeCode, 0, 0, metaClass); + writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::End, TypeSystem::NativeCode, metaClass); s << endl; } } @@ -734,9 +691,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun s << ';' << endl; s << INDENT << '}' << endl << endl; - CodeSnipList convRules = getConversionRule(TypeSystem::TargetLangCode, func); - if (convRules.size()) - writeCodeSnips(s, convRules, CodeSnip::Beginning, TypeSystem::TargetLangCode, func); + writeConversionRule(s, func, TypeSystem::TargetLangCode); s << INDENT << "Shiboken::AutoDecRef " PYTHON_ARGS "("; @@ -859,8 +814,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun if (!func->conversionRule(TypeSystem::NativeCode, 0).isEmpty()) { // Has conversion rule. - CodeSnipList convRule = getReturnConversionRule(TypeSystem::NativeCode, func, "", CPP_RETURN_VAR); - writeCodeSnips(s, convRule, CodeSnip::Any, TypeSystem::NativeCode, func); + writeConversionRule(s, func, CPP_RETURN_VAR); } else if (!injectedCodeHasReturnValueAttribution(func, TypeSystem::NativeCode)) { writePythonToCppTypeConversion(s, func->type(), PYTHON_RETURN_VAR, CPP_RETURN_VAR, func->implementingClass()); } @@ -1624,6 +1578,45 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s, s << INDENT << typeName << " " << cppOut << " = " << conversion << ';' << endl; } +static void addConversionRuleCodeSnippet(CodeSnipList& snippetList, QString& rule, + TypeSystem::Language conversionLanguage, + TypeSystem::Language snippetLanguage, + QString outputName = QString(), + QString inputName = QString()) +{ + if (rule.isEmpty()) + return; + if (snippetLanguage == TypeSystem::TargetLangCode) { + rule.replace("%in", inputName); + rule.replace("%out", QString("%1_out").arg(outputName)); + } else { + rule.replace("%out", outputName); + } + CodeSnip snip(0, snippetLanguage); + snip.position = (snippetLanguage == TypeSystem::NativeCode) ? CodeSnip::Any : CodeSnip::Beginning; + snip.addCode(rule); + snippetList << snip; +} + +void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language) +{ + CodeSnipList snippets; + foreach (AbstractMetaArgument* arg, func->arguments()) { + QString rule = func->conversionRule(language, arg->argumentIndex() + 1); + addConversionRuleCodeSnippet(snippets, rule, language, TypeSystem::TargetLangCode, + arg->name(), arg->name()); + } + writeCodeSnips(s, snippets, CodeSnip::Beginning, TypeSystem::TargetLangCode, func); +} + +void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, const QString& outputVar) +{ + CodeSnipList snippets; + QString rule = func->conversionRule(TypeSystem::NativeCode, 0); + addConversionRuleCodeSnippet(snippets, rule, TypeSystem::NativeCode, TypeSystem::NativeCode, outputVar); + writeCodeSnips(s, snippets, CodeSnip::Any, TypeSystem::NativeCode, func); +} + void CppGenerator::writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue) { if (thereIsReturnValue && (!func->type() || func->argumentRemoved(0)) && !injectedCodeHasReturnValueAttribution(func)) { @@ -2018,9 +2011,7 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f s << endl; } - CodeSnipList convRules = getConversionRule(TypeSystem::NativeCode, func); - if (convRules.size()) - writeCodeSnips(s, convRules, CodeSnip::Beginning, TypeSystem::TargetLangCode, func); + writeConversionRule(s, func, TypeSystem::NativeCode); if (!func->isUserAdded()) { bool badModifications = false; @@ -2682,7 +2673,7 @@ void CppGenerator::writeMappingMethods(QTextStream& s, const AbstractMetaClass* writeCppSelfDefinition(s, func); const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); - writeCodeSnips(s, snips,CodeSnip::Any, TypeSystem::TargetLangCode, func, lastArg); + writeCodeSnips(s, snips, CodeSnip::Any, TypeSystem::TargetLangCode, func, lastArg); s << '}' << endl << endl; } } @@ -3495,7 +3486,7 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m // class inject-code target/beginning if (!classTypeEntry->codeSnips().isEmpty()) { - writeCodeSnips(s, classTypeEntry->codeSnips(), CodeSnip::Beginning, TypeSystem::TargetLangCode, 0, 0, metaClass); + writeCodeSnips(s, classTypeEntry->codeSnips(), CodeSnip::Beginning, TypeSystem::TargetLangCode, metaClass); s << endl; } @@ -3544,7 +3535,7 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m // class inject-code target/end if (!classTypeEntry->codeSnips().isEmpty()) { s << endl; - writeCodeSnips(s, classTypeEntry->codeSnips(), CodeSnip::End, TypeSystem::TargetLangCode, 0, 0, metaClass); + writeCodeSnips(s, classTypeEntry->codeSnips(), CodeSnip::End, TypeSystem::TargetLangCode, metaClass); } if (!metaClass->isNamespace()) diff --git a/generator/cppgenerator.h b/generator/cppgenerator.h index c6cda3184..4dea57bd2 100644 --- a/generator/cppgenerator.h +++ b/generator/cppgenerator.h @@ -109,6 +109,11 @@ private: const AbstractMetaClass* context = 0, const QString& defaultValue = QString()); + /// Writes the conversion rule for arguments of regular and virtual methods. + void writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language); + /// Writes the conversion rule for the return value of a virtual method. + void writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, const QString& outputVar); + /** * Set the Python method wrapper return value variable to Py_None if * there are return types different from void in any of the other overloads diff --git a/generator/shibokengenerator.cpp b/generator/shibokengenerator.cpp index b3fb89b16..3bb2d579d 100644 --- a/generator/shibokengenerator.cpp +++ b/generator/shibokengenerator.cpp @@ -1165,265 +1165,269 @@ static QString getArgumentsFromMethodCall(const QString& str) return str.mid(begin, pos-begin-1); } -void ShibokenGenerator::writeCodeSnips(QTextStream& s, - const CodeSnipList& codeSnips, - CodeSnip::Position position, - TypeSystem::Language language, - const AbstractMetaFunction* func, - const AbstractMetaArgument* lastArg, - const AbstractMetaClass* context) +QString ShibokenGenerator::getCodeSnippets(const CodeSnipList& codeSnips, + CodeSnip::Position position, + TypeSystem::Language language) { - static QRegExp pyArgsRegex("%PYARG_(\\d+)"); - - // detect is we should use pyargs instead of args as variable name for python arguments - bool usePyArgs = false; - if (func) { - // calc num of real arguments. - int argsRemoved = 0; - for (int i = 0; i < func->arguments().size(); i++) { - if (func->argumentRemoved(i+1)) - argsRemoved++; - } - OverloadData od(getFunctionGroups(func->implementingClass())[func->name()], this); - usePyArgs = pythonFunctionWrapperUsesListOfArguments(od); - } - + QString code; + QTextStream c(&code); foreach (CodeSnip snip, codeSnips) { if ((position != CodeSnip::Any && snip.position != position) || !(snip.language & language)) continue; + QString snipCode; + QTextStream sc(&snipCode); + formatCode(sc, snip.code(), INDENT); + c << snipCode; + } + return code; +} +void ShibokenGenerator::processCodeSnip(QString& code, const AbstractMetaClass* context) +{ + if (context) { + // Replace template variable by the Python Type object + // for the class context in which the variable is used. + code.replace("%PYTHONTYPEOBJECT", cpythonTypeName(context) + ".super.ht_type"); + code.replace("%TYPE", wrapperName(context)); + code.replace("%CPPTYPE", context->name()); + } - QString code; - QTextStream tmpStream(&code); - formatCode(tmpStream, snip.code(), INDENT); + // replace "toPython" converters + replaceConvertToPythonTypeSystemVariable(code); - if (context) { - // replace template variable for the Python Type object for the - // class context in which the variable is used - code.replace("%PYTHONTYPEOBJECT", cpythonTypeName(context) + ".super.ht_type"); - code.replace("%TYPE", wrapperName(context)); - code.replace("%CPPTYPE", context->name()); - } + // replace "toCpp" converters + replaceConvertToCppTypeSystemVariable(code); - if (func) { - // replace %PYARG_# variables - code.replace("%PYARG_0", PYTHON_RETURN_VAR); - if (snip.language == TypeSystem::TargetLangCode) { - if (usePyArgs) { - code.replace(pyArgsRegex, PYTHON_ARGS"[\\1-1]"); - } else { - static QRegExp pyArgsRegexCheck("%PYARG_([2-9]+)"); - if (pyArgsRegexCheck.indexIn(code) != -1) { - ReportHandler::warning("Wrong index for %PYARG variable ("+pyArgsRegexCheck.cap(1)+") on "+func->signature()); - return; - } - code.replace("%PYARG_1", PYTHON_ARG); - } - } else { - // Replaces the simplest case of attribution to a Python argument - // on the binding virtual method. - static QRegExp pyArgsAttributionRegex("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"); - code.replace(pyArgsAttributionRegex, "PyTuple_SET_ITEM(" PYTHON_ARGS ", \\1-1, \\2)"); - code.replace(pyArgsRegex, "PyTuple_GET_ITEM(" PYTHON_ARGS ", \\1-1)"); - } + // replace "isConvertible" check + replaceConvertibleToCppTypeSystemVariable(code); - // replace %ARG#_TYPE variables - foreach (const AbstractMetaArgument* arg, func->arguments()) { - QString argTypeVar = QString("%ARG%1_TYPE").arg(arg->argumentIndex() + 1); - QString argTypeVal = arg->type()->cppSignature(); - code.replace(argTypeVar, argTypeVal); - } + // replace "checkType" check + replaceTypeCheckTypeSystemVariable(code); +} - static QRegExp cppArgTypeRegexCheck("%ARG(\\d+)_TYPE"); - int pos = 0; - while ((pos = cppArgTypeRegexCheck.indexIn(code, pos)) != -1) { - ReportHandler::warning("Wrong index for %ARG#_TYPE variable ("+cppArgTypeRegexCheck.cap(1)+") on "+func->signature()); - pos += cppArgTypeRegexCheck.matchedLength(); +QMap<int, QString> ShibokenGenerator::getArgumentReplacement(const AbstractMetaFunction* func, + bool usePyArgs, TypeSystem::Language language, + const AbstractMetaArgument* lastArg) +{ + QMap<int, QString> argReplacement; + int removed = 0; + for (int i = 0; i < func->arguments().size(); ++i) { + const AbstractMetaArgument* arg = func->arguments().at(i); + QString argValue; + if (language == TypeSystem::TargetLangCode) { + bool argRemoved = func->argumentRemoved(i+1); + removed = removed + (int) argRemoved; + if (argRemoved || (lastArg && arg->argumentIndex() > lastArg->argumentIndex())) + argValue = arg->defaultValueExpression(); + if (!argRemoved && argValue.isEmpty()) { + if (arg->type()->typeEntry()->isCustom()) + argValue = usePyArgs ? QString(PYTHON_ARGS"[%1]").arg(i - removed) : PYTHON_ARG; + else + argValue = QString(CPP_ARG"%1").arg(i - removed); } + } else { + argValue = arg->name(); + } + if (!argValue.isEmpty()) + argReplacement[i+1] = argValue; + } + return argReplacement; +} - // replace template variable for return variable name - if (func->isConstructor()) { - code.replace("%0.", QString("%1->").arg("cptr")); - code.replace("%0", "cptr"); - } else if (func->type()) { - QString returnValueOp = isPointerToWrapperType(func->type()) ? "%1->" : "%1."; - if (ShibokenGenerator::isWrapperType(func->type())) - code.replace("%0.", returnValueOp.arg(CPP_RETURN_VAR)); - code.replace("%0", CPP_RETURN_VAR); - } +void ShibokenGenerator::writeCodeSnips(QTextStream& s, + const CodeSnipList& codeSnips, + CodeSnip::Position position, + TypeSystem::Language language, + const AbstractMetaClass* context) +{ + QString code = getCodeSnippets(codeSnips, position, language); + if (code.isEmpty()) + return; + processCodeSnip(code, context); + s << INDENT << "// Begin code injection" << endl; + s << code; + s << INDENT << "// End of code injection" << endl; +} - // replace template variable for self Python object - QString pySelf = (snip.language == TypeSystem::NativeCode) ? "pySelf" : PYTHON_SELF_VAR; - code.replace("%PYSELF", pySelf); - - // replace template variable for pointer to C++ this object - if (func->implementingClass()) { - QString cppSelf; - QString replacement("%1->"); - if (func->isStatic()) { - cppSelf = func->ownerClass()->qualifiedCppName(); - replacement = "%1::"; - } else if (snip.language == TypeSystem::NativeCode) { - cppSelf = "this"; - } else { - cppSelf = "cppSelf"; - } +void ShibokenGenerator::writeCodeSnips(QTextStream& s, + const CodeSnipList& codeSnips, + CodeSnip::Position position, + TypeSystem::Language language, + const AbstractMetaFunction* func, + const AbstractMetaArgument* lastArg) +{ + QString code = getCodeSnippets(codeSnips, position, language); + if (code.isEmpty()) + return; - // on comparison operator cppSelf is always a reference. - if (func->isComparisonOperator()) - replacement = "%1."; - - if (func->isVirtual() && !func->isAbstract() && (!avoidProtectedHack() || !func->isProtected())) { - QString methodCallArgs = getArgumentsFromMethodCall(code); - if (!methodCallArgs.isNull()) { - if (func->name() == "metaObject") { - QString wrapperClassName = wrapperName(func->ownerClass()); - QString cppSelfVar = avoidProtectedHack() ? QString("%CPPSELF") : QString("reinterpret_cast<%1*>(%CPPSELF)").arg(wrapperClassName); - code.replace(QString("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs), - QString("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))" - " ? %2->::%3::%FUNCTION_NAME(%4)" - " : %CPPSELF.%FUNCTION_NAME(%4))").arg(pySelf).arg(cppSelfVar).arg(wrapperClassName).arg(methodCallArgs)); - } else { - code.replace(QString("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs), - QString("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))" - " ? %CPPSELF->::%TYPE::%FUNCTION_NAME(%2)" - " : %CPPSELF.%FUNCTION_NAME(%2))").arg(pySelf).arg(methodCallArgs)); - } - } - } + // Calculate the real number of arguments. + int argsRemoved = 0; + for (int i = 0; i < func->arguments().size(); i++) { + if (func->argumentRemoved(i+1)) + argsRemoved++; + } - code.replace("%CPPSELF.", replacement.arg(cppSelf)); - code.replace("%CPPSELF", cppSelf); + OverloadData od(getFunctionGroups(func->implementingClass())[func->name()], this); + bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(od); - if (code.indexOf("%BEGIN_ALLOW_THREADS") > -1) { - if (code.count("%BEGIN_ALLOW_THREADS") == code.count("%END_ALLOW_THREADS")) { - code.replace("%BEGIN_ALLOW_THREADS", BEGIN_ALLOW_THREADS); - code.replace("%END_ALLOW_THREADS", END_ALLOW_THREADS); - } else { - ReportHandler::warning("%BEGIN_ALLOW_THREADS and %END_ALLOW_THREADS mismatch"); - } - } + // Replace %PYARG_# variables. + code.replace("%PYARG_0", PYTHON_RETURN_VAR); - // replace template variable for the Python Type object for the - // class implementing the method in which the code snip is written - if (func->isStatic()) { - code.replace("%PYTHONTYPEOBJECT", cpythonTypeName(func->implementingClass()) + ".super.ht_type"); - } else { - code.replace("%PYTHONTYPEOBJECT.", QString("%1->ob_type->").arg(pySelf)); - code.replace("%PYTHONTYPEOBJECT", QString("%1->ob_type").arg(pySelf)); - } + static QRegExp pyArgsRegex("%PYARG_(\\d+)"); + if (language == TypeSystem::TargetLangCode) { + if (usePyArgs) { + code.replace(pyArgsRegex, PYTHON_ARGS"[\\1-1]"); + } else { + static QRegExp pyArgsRegexCheck("%PYARG_([2-9]+)"); + if (pyArgsRegexCheck.indexIn(code) != -1) { + ReportHandler::warning("Wrong index for %PYARG variable ("+pyArgsRegexCheck.cap(1)+") on "+func->signature()); + return; } + code.replace("%PYARG_1", PYTHON_ARG); + } + } else { + // Replaces the simplest case of attribution to a + // Python argument on the binding virtual method. + static QRegExp pyArgsAttributionRegex("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"); + code.replace(pyArgsAttributionRegex, "PyTuple_SET_ITEM(" PYTHON_ARGS ", \\1-1, \\2)"); + code.replace(pyArgsRegex, "PyTuple_GET_ITEM(" PYTHON_ARGS ", \\1-1)"); + } - // replace template variables %# for individual arguments - int removed = 0; - for (int i = 0; i < func->arguments().size(); i++) { - const AbstractMetaArgument* arg = func->arguments().at(i); - QString argReplacement; - if (snip.language == TypeSystem::TargetLangCode) { - if (!lastArg || func->argumentRemoved(i+1)) { - if (!arg->defaultValueExpression().isEmpty()) - argReplacement = arg->defaultValueExpression(); - removed++; - } else if (lastArg && (arg->argumentIndex() > lastArg->argumentIndex())) { - argReplacement = arg->defaultValueExpression(); - } + // Replace %ARG#_TYPE variables. + foreach (const AbstractMetaArgument* arg, func->arguments()) { + QString argTypeVar = QString("%ARG%1_TYPE").arg(arg->argumentIndex() + 1); + QString argTypeVal = arg->type()->cppSignature(); + code.replace(argTypeVar, argTypeVal); + } - if (argReplacement.isEmpty()) { - if (arg->type()->typeEntry()->isCustom()) { - argReplacement = usePyArgs ? QString(PYTHON_ARGS"[%1]").arg(i - removed) : PYTHON_ARG; - } else { - argReplacement = QString(CPP_ARG"%1").arg(i - removed); - } - } - } else { - argReplacement = arg->name(); - } - code.replace("%" + QString::number(i+1), argReplacement); - } + int pos = 0; + static QRegExp cppArgTypeRegexCheck("%ARG(\\d+)_TYPE"); + while ((pos = cppArgTypeRegexCheck.indexIn(code, pos)) != -1) { + ReportHandler::warning("Wrong index for %ARG#_TYPE variable ("+cppArgTypeRegexCheck.cap(1)+") on "+func->signature()); + pos += cppArgTypeRegexCheck.matchedLength(); + } - // replace template %ARGUMENT_NAMES variable for a list of arguments - removed = 0; - QStringList argumentNames; - foreach (const AbstractMetaArgument* arg, func->arguments()) { - if (snip.language == TypeSystem::TargetLangCode) { - if (func->argumentRemoved(arg->argumentIndex() + 1)) { - if (!arg->defaultValueExpression().isEmpty()) - argumentNames << arg->defaultValueExpression(); - removed++; - continue; - } + // Replace template variable for return variable name. + if (func->isConstructor()) { + code.replace("%0.", QString("%1->").arg("cptr")); + code.replace("%0", "cptr"); + } else if (func->type()) { + QString returnValueOp = isPointerToWrapperType(func->type()) ? "%1->" : "%1."; + if (ShibokenGenerator::isWrapperType(func->type())) + code.replace("%0.", returnValueOp.arg(CPP_RETURN_VAR)); + code.replace("%0", CPP_RETURN_VAR); + } - QString argName; - if (lastArg && arg->argumentIndex() > lastArg->argumentIndex()) { - argName = arg->defaultValueExpression(); - } else { - argName = QString(CPP_ARG"%1").arg(arg->argumentIndex() - removed); - } - argumentNames << argName; + // Replace template variable for self Python object. + QString pySelf = (language == TypeSystem::NativeCode) ? "pySelf" : PYTHON_SELF_VAR; + code.replace("%PYSELF", pySelf); + + // Replace template variable for a pointer to C++ of this object. + if (func->implementingClass()) { + QString replacement = func->isStatic() ? "%1::" : "%1->"; + QString cppSelf; + if (func->isStatic()) + cppSelf = func->ownerClass()->qualifiedCppName(); + else if (language == TypeSystem::NativeCode) + cppSelf = "this"; + else + cppSelf = CPP_SELF_VAR; + + // On comparison operator CPP_SELF_VAR is always a reference. + if (func->isComparisonOperator()) + replacement = "%1."; + + if (func->isVirtual() && !func->isAbstract() && (!avoidProtectedHack() || !func->isProtected())) { + QString methodCallArgs = getArgumentsFromMethodCall(code); + if (!methodCallArgs.isNull()) { + if (func->name() == "metaObject") { + QString wrapperClassName = wrapperName(func->ownerClass()); + QString cppSelfVar = avoidProtectedHack() ? QString("%CPPSELF") : QString("reinterpret_cast<%1*>(%CPPSELF)").arg(wrapperClassName); + code.replace(QString("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs), + QString("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))" + " ? %2->::%3::%FUNCTION_NAME(%4)" + " : %CPPSELF.%FUNCTION_NAME(%4))").arg(pySelf).arg(cppSelfVar).arg(wrapperClassName).arg(methodCallArgs)); } else { - argumentNames << arg->name(); + code.replace(QString("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs), + QString("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))" + " ? %CPPSELF->::%TYPE::%FUNCTION_NAME(%2)" + " : %CPPSELF.%FUNCTION_NAME(%2))").arg(pySelf).arg(methodCallArgs)); } } - code.replace("%ARGUMENT_NAMES", argumentNames.join(", ")); - - if (snip.language == TypeSystem::NativeCode) { - // replace template %PYTHON_ARGUMENTS variable for a pointer to the Python tuple - // containing the converted virtual method arguments received from C++ to be passed - // to the Python override - code.replace("%PYTHON_ARGUMENTS", PYTHON_ARGS); - - // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method - // override for the C++ virtual method in which this piece of code was inserted - code.replace("%PYTHON_METHOD_OVERRIDE", PYTHON_OVERRIDE_VAR); - } + } - if (avoidProtectedHack()) { - // If the function being processed was added by the user via type system, - // Shiboken needs to find out if there are other overloads for the same method - // name and if any of them is of the protected visibility. This is used to replace - // calls to %FUNCTION_NAME on user written custom code for calls to the protected - // dispatcher. - bool hasProtectedOverload = false; - if (func->isUserAdded()) { - foreach (const AbstractMetaFunction* f, getFunctionOverloads(func->ownerClass(), func->name())) - hasProtectedOverload |= f->isProtected(); - } + code.replace("%CPPSELF.", replacement.arg(cppSelf)); + code.replace("%CPPSELF", cppSelf); - if (func->isProtected() || hasProtectedOverload) { - code.replace("%TYPE::%FUNCTION_NAME", - QString("%1::%2_protected") - .arg(wrapperName(func->ownerClass())) - .arg(func->originalName())); - code.replace("%FUNCTION_NAME", QString("%1_protected").arg(func->originalName())); - } + if (code.indexOf("%BEGIN_ALLOW_THREADS") > -1) { + if (code.count("%BEGIN_ALLOW_THREADS") == code.count("%END_ALLOW_THREADS")) { + code.replace("%BEGIN_ALLOW_THREADS", BEGIN_ALLOW_THREADS); + code.replace("%END_ALLOW_THREADS", END_ALLOW_THREADS); + } else { + ReportHandler::warning("%BEGIN_ALLOW_THREADS and %END_ALLOW_THREADS mismatch"); } + } - if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass())) - code.replace("%TYPE", wrapperName(func->ownerClass())); + // replace template variable for the Python Type object for the + // class implementing the method in which the code snip is written + if (func->isStatic()) { + code.replace("%PYTHONTYPEOBJECT", cpythonTypeName(func->implementingClass()) + ".super.ht_type"); + } else { + code.replace("%PYTHONTYPEOBJECT.", QString("%1->ob_type->").arg(pySelf)); + code.replace("%PYTHONTYPEOBJECT", QString("%1->ob_type").arg(pySelf)); + } + } - if (func->ownerClass()) - code.replace("%CPPTYPE", func->ownerClass()->name()); + // Replaces template %ARGUMENT_NAMES and %# variables by argument variables and values. + // Replaces template variables %# for individual arguments. + QMap<int, QString> argReplacements = getArgumentReplacement(func, usePyArgs, language, lastArg); + code.replace("%ARGUMENT_NAMES", QStringList(argReplacements.values()).join(", ")); + foreach (int i, argReplacements.keys()) + code.replace(QString("%%1").arg(i), argReplacements[i]); + + if (language == TypeSystem::NativeCode) { + // Replaces template %PYTHON_ARGUMENTS variable with a pointer to the Python tuple + // containing the converted virtual method arguments received from C++ to be passed + // to the Python override. + code.replace("%PYTHON_ARGUMENTS", PYTHON_ARGS); + + // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method + // override for the C++ virtual method in which this piece of code was inserted + code.replace("%PYTHON_METHOD_OVERRIDE", PYTHON_OVERRIDE_VAR); + } - replaceTemplateVariables(code, func); + if (avoidProtectedHack()) { + // If the function being processed was added by the user via type system, + // Shiboken needs to find out if there are other overloads for the same method + // name and if any of them is of the protected visibility. This is used to replace + // calls to %FUNCTION_NAME on user written custom code for calls to the protected + // dispatcher. + bool hasProtectedOverload = false; + if (func->isUserAdded()) { + foreach (const AbstractMetaFunction* f, getFunctionOverloads(func->ownerClass(), func->name())) + hasProtectedOverload |= f->isProtected(); } - // replace "toPython" converters - replaceConvertToPythonTypeSystemVariable(code); + if (func->isProtected() || hasProtectedOverload) { + code.replace("%TYPE::%FUNCTION_NAME", + QString("%1::%2_protected") + .arg(wrapperName(func->ownerClass())) + .arg(func->originalName())); + code.replace("%FUNCTION_NAME", QString("%1_protected").arg(func->originalName())); + } + } - // replace "toCpp" converters - replaceConvertToCppTypeSystemVariable(code); + if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass())) + code.replace("%TYPE", wrapperName(func->ownerClass())); - // replace "isConvertible" check - replaceConvertibleToCppTypeSystemVariable(code); + if (func->ownerClass()) + code.replace("%CPPTYPE", func->ownerClass()->name()); - // replace "checkType" check - replaceTypeCheckTypeSystemVariable(code); + replaceTemplateVariables(code, func); - if (!code.isEmpty()) { - s << INDENT << "// Begin code injection" << endl; - s << code; - s << INDENT << "// End of code injection" << endl; - } - } + processCodeSnip(code); + s << INDENT << "// Begin code injection" << endl; + s << code; + s << INDENT << "// End of code injection" << endl; } void ShibokenGenerator::replaceConvertToPythonTypeSystemVariable(QString& code) diff --git a/generator/shibokengenerator.h b/generator/shibokengenerator.h index 256977690..605b205e6 100644 --- a/generator/shibokengenerator.h +++ b/generator/shibokengenerator.h @@ -111,26 +111,31 @@ public: const AbstractMetaFunction* func, Options options = NoOption) const; QString functionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const; - /** - * Write a code snip into the buffer \p s. - * CodeSnip are codes inside inject-code tags. - * \param s the buffer - * \param code_snips a list of code snips - * \param position the position to insert the code snip - * \param language the kind of code snip - * \param func the cpp function - * \param lastArg last argument whose value is available, usually the last; - * a NULL pointer indicates that no argument will be available, - * i.e. a call without arguments. - * \param context the class context for the place where the code snip will be written - */ - void writeCodeSnips(QTextStream &s, - const CodeSnipList &code_snips, + + /// Utility function for writeCodeSnips. + static QMap<int, QString> getArgumentReplacement(const AbstractMetaFunction* func, + bool usePyArgs, TypeSystem::Language language, + const AbstractMetaArgument* lastArg); + + /// Write user's custom code snippets at class or module level. + void writeCodeSnips(QTextStream& s, + const CodeSnipList& codeSnips, CodeSnip::Position position, TypeSystem::Language language, - const AbstractMetaFunction* func = 0, - const AbstractMetaArgument* lastArg = 0, const AbstractMetaClass* context = 0); + /// Write user's custom code snippets at function level. + void writeCodeSnips(QTextStream& s, + const CodeSnipList& codeSnips, + CodeSnip::Position position, + TypeSystem::Language language, + const AbstractMetaFunction* func, + const AbstractMetaArgument* lastArg = 0); + + /// Returns a string with the user's custom code snippets that comply with \p position and \p language. + QString getCodeSnippets(const CodeSnipList& codeSnips, CodeSnip::Position position, TypeSystem::Language language); + + /// Replaces variables for the user's custom code at global or class level. + void processCodeSnip(QString& code, const AbstractMetaClass* context = 0); /// Replaces the %CONVERTTOPYTHON type system variable. void replaceConvertToPythonTypeSystemVariable(QString& code); |