diff options
-rw-r--r-- | cppgenerator.cpp | 163 | ||||
-rw-r--r-- | doc/codeinjectionsemantics.rst | 12 | ||||
-rw-r--r-- | shibokengenerator.cpp | 2 |
3 files changed, 97 insertions, 80 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp index ada2c1e09..a3954f6dc 100644 --- a/cppgenerator.cpp +++ b/cppgenerator.cpp @@ -293,97 +293,110 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu Indentation indentation(INDENT); - CodeSnipList snips; - if (func->hasInjectedCode()) { - snips = getCodeSnips(func); - writeCodeSnips(s, snips, CodeSnip::Beginning, TypeSystem::NativeCode, func); - s << endl; - } - if (func->isAbstract() && func->isModifiedRemoved()) { s << INDENT << "#error Pure virtual method \"" << func->ownerClass()->name(); s << "::" << func->minimalSignature(); s << "\" must be implement but was completely removed on typesystem." << endl; - } else { - if (func->allowThread()) - s << INDENT << "// how to say to Python to allow threads?" << endl; + s << '}' << endl << endl; + return; + } - s << INDENT << "PyObject* method = BindingManager::instance().getOverride(this, \""; - s << func->name() << "\");" << endl; + if (func->allowThread()) + s << INDENT << "// how to say to Python to allow threads?" << endl; - s << INDENT << "if (!method) {" << endl; - { - Indentation indentation(INDENT); - s << INDENT; - if (func->isAbstract()) { - s << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '"; - s << func->ownerClass()->name() << '.' << func->name(); - s << "()' not implemented.\");" << endl; - s << INDENT << "return"; - if (func->type()) { - s << ' '; - writeMinimalConstructorCallArguments(s, func->type()); - } - } else { - s << "return this->" << func->implementingClass()->qualifiedCppName() << "::"; - writeFunctionCall(s, func); + s << INDENT << "PyObject* method = BindingManager::instance().getOverride(this, \""; + s << func->name() << "\");" << endl; + + s << INDENT << "if (!method) {" << endl; + { + Indentation indentation(INDENT); + s << INDENT; + if (func->isAbstract()) { + s << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '"; + s << func->ownerClass()->name() << '.' << func->name(); + s << "()' not implemented.\");" << endl; + s << INDENT << "return"; + if (func->type()) { + s << ' '; + writeMinimalConstructorCallArguments(s, func->type()); } + } else { + s << "return this->" << func->implementingClass()->qualifiedCppName() << "::"; + writeFunctionCall(s, func); } - s << ';' << endl << INDENT << '}' << endl << endl; + } + s << ';' << endl; + s << INDENT << '}' << endl << endl; - s << INDENT << "PyObject* args = "; - if (func->arguments().isEmpty()) { - s << "PyTuple_New(0);" << endl; - } else { - s << "Py_BuildValue(\"(" << getFormatUnitString(func) << ")\"," << endl; - foreach (const AbstractMetaArgument* arg, func->arguments()) { - Indentation indentation(INDENT); - bool convert = arg->type()->isObject() - || arg->type()->isQObject() - || arg->type()->isValue() - || arg->type()->isValuePointer() - || arg->type()->isFlags() - || arg->type()->isReference() - || (arg->type()->isPrimitive() - && !m_formatUnits.contains(arg->type()->typeEntry()->name())); - s << INDENT; - if (convert) { - writeToPythonConversion(s, arg->type(), func->ownerClass()); - s << '('; - } - s << arg->argumentName(); - if (convert) - s << ")"; - if (arg->argumentIndex() != func->arguments().size() - 1) - s << ','; - s << endl; + s << INDENT << "PyObject* pyargs = "; + if (func->arguments().isEmpty()) { + s << "PyTuple_New(0);" << endl; + } else { + QStringList argConversions; + foreach (const AbstractMetaArgument* arg, func->arguments()) { + if (func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + + QString argConv; + QTextStream ac(&argConv); + bool convert = arg->type()->isObject() + || arg->type()->isQObject() + || arg->type()->isValue() + || arg->type()->isValuePointer() + || arg->type()->isFlags() + || arg->type()->isReference() + || (arg->type()->isPrimitive() + && !m_formatUnits.contains(arg->type()->typeEntry()->name())); + + Indentation indentation(INDENT); + ac << INDENT; + if (convert) { + writeToPythonConversion(ac, arg->type(), func->ownerClass()); + ac << '('; } - s << INDENT << ");" << endl; + ac << arg->argumentName() << (convert ? ")" : ""); + + argConversions << argConv; } + + s << "Py_BuildValue(\"(" << getFormatUnitString(func) << ")\"," << endl; + s << argConversions.join(",\n") << endl; + s << INDENT << ");" << endl; + } + s << endl; + + CodeSnipList snips; + if (func->hasInjectedCode()) { + snips = getCodeSnips(func); + + if (injectedCodeUsesPySelf(func)) + s << INDENT << "PyObject* pySelf = BindingManager::instance().retrieveWrapper(this);" << endl; + + writeCodeSnips(s, snips, CodeSnip::Beginning, TypeSystem::NativeCode, func); s << endl; + } - s << INDENT << "PyGILState_STATE gil_state = PyGILState_Ensure();" << endl; + s << INDENT << "PyGILState_STATE gil_state = PyGILState_Ensure();" << endl; - s << INDENT; - if (!returnKeyword.isEmpty()) - s << "PyObject* method_result = "; - s << "PyObject_Call(method, args, NULL);" << endl; - s << INDENT << "PyGILState_Release(gil_state);" << endl << endl; - - foreach (FunctionModification func_mod, functionModifications(func)) { - foreach (ArgumentModification arg_mod, func_mod.argument_mods) { - if (!arg_mod.resetAfterUse) - continue; - s << INDENT << "PyBaseWrapper_setValidCppObject(PyTuple_GET_ITEM(args, "; - s << (arg_mod.index - 1) << "), false);" << endl; - } + s << INDENT; + if (!returnKeyword.isEmpty()) + s << "PyObject* " << retvalVariableName() << " = "; + s << "PyObject_Call(method, pyargs, NULL);" << endl; + s << INDENT << "PyGILState_Release(gil_state);" << endl << endl; + + foreach (FunctionModification func_mod, functionModifications(func)) { + foreach (ArgumentModification arg_mod, func_mod.argument_mods) { + if (!arg_mod.resetAfterUse) + continue; + s << INDENT << "PyBaseWrapper_setValidCppObject(PyTuple_GET_ITEM(pyargs, "; + s << (arg_mod.index - 1) << "), false);" << endl; } + } - s << INDENT << "Py_XDECREF(args);" << endl; - s << INDENT << "Py_XDECREF(method);" << endl; + s << INDENT << "Py_XDECREF(pyargs);" << endl; + s << INDENT << "Py_XDECREF(method);" << endl; - s << endl << INDENT << "// check and set Python error here..." << endl; - } + s << endl << INDENT << "// check and set Python error here..." << endl; if (func->hasInjectedCode()) { s << endl; @@ -392,7 +405,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu if (!returnKeyword.isEmpty()) { s << INDENT << returnKeyword; - writeToCppConversion(s, func->type(), func->implementingClass(), "method_result"); + writeToCppConversion(s, func->type(), func->implementingClass(), retvalVariableName()); s << ';' << endl; } s << '}' << endl << endl; diff --git a/doc/codeinjectionsemantics.rst b/doc/codeinjectionsemantics.rst index e1891188c..c0d6fa2d7 100644 --- a/doc/codeinjectionsemantics.rst +++ b/doc/codeinjectionsemantics.rst @@ -66,9 +66,10 @@ The following table describes the semantics of ``inject-code`` tag as used on | | | |code here will be executed after all the wrapped class | | | | |components have been initialized. | +---------------+------+---------+--------------------------------------------------------------+ - |modify-function|native|beginning|Code here is put on the beginning of a virtual method | - | | | |override on the C++ wrapper class (the one responsible for | - | | | |passing C++ calls to Python overrides, if there is any). | + |modify-function|native|beginning|Code here is put on the virtual method override of a C++ | + | | | |wrapper class (the one responsible for passing C++ calls to a | + | | | |Python override, if there is any), right after the C++ | + | | | |arguments have been converted but before the Python call. | | | +---------+--------------------------------------------------------------+ | | |end |This code injection goes to the end of a virtual method | | | | |override on the C++ wrapper class, right before the return | @@ -199,8 +200,11 @@ class is polymorphic. if (!method) return this->InjectCode::virtualMethod(arg); + (... here C++ arguments are converted to Python ...) + // INJECT-CODE: <modify-function><inject-code class="native" position="beginning"> - // Uses: pre method call custom code. + // Uses: pre method call custom code, modify the argument before the + // Python call. (... Python method call goes in here ...) diff --git a/shibokengenerator.cpp b/shibokengenerator.cpp index 1627bb563..8b84d71ec 100644 --- a/shibokengenerator.cpp +++ b/shibokengenerator.cpp @@ -328,7 +328,7 @@ QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction* func) { QString result; foreach (const AbstractMetaArgument* arg, func->arguments()) { - if (func->argumentRemoved(arg->argumentIndex())) + if (func->argumentRemoved(arg->argumentIndex() + 1)) continue; if (arg->type()->isQObject() |