diff options
author | Jim Carroll <thecarrolls@jiminger.com> | 2012-09-11 23:51:03 -0400 |
---|---|---|
committer | Jim Carroll <thecarrolls@jiminger.com> | 2012-09-11 23:56:41 -0400 |
commit | ee83efc805c61f25c381efaaded06c4620cb4cae (patch) | |
tree | 89f64621e8e65e84e4e918fc63dd1b221513f3c3 | |
parent | b8ba975f6731f1a77a9d2e214e743ddd52500466 (diff) |
[fix] More robust type information for base class type checking.
-rw-r--r-- | xbmc/interfaces/python/PythonSwig.cpp.template | 47 | ||||
-rw-r--r-- | xbmc/interfaces/python/PythonTools.groovy | 20 | ||||
-rw-r--r-- | xbmc/interfaces/python/swig.cpp | 22 | ||||
-rw-r--r-- | xbmc/interfaces/python/swig.h | 42 |
4 files changed, 95 insertions, 36 deletions
diff --git a/xbmc/interfaces/python/PythonSwig.cpp.template b/xbmc/interfaces/python/PythonSwig.cpp.template index 4f38c8ef69..2a7997354a 100644 --- a/xbmc/interfaces/python/PythonSwig.cpp.template +++ b/xbmc/interfaces/python/PythonSwig.cpp.template @@ -60,7 +60,7 @@ Helper.setup(classes, (Pattern.compile('''(p.){0,1}std::vector<\\(.*\\)>''')) : new File('typemaps/python.vector.outtm'), (Pattern.compile('''(p.){0,1}Tuple<\\(.*\\)>''')) : new File('typemaps/python.Tuple.outtm'), (Pattern.compile('''(p.){0,1}Alternative<\\(.*\\)>''')) : new File('typemaps/python.Alternative.outtm') - ], '${result} = makePythonInstance(${api},&Py${Helper.findFullClassName(classnode).replaceAll(\'::\',\'_\')}_Type,"${type}",true);', + ], '${result} = makePythonInstance(${api},&Py${Helper.findFullClassName(classnode).replaceAll(\'::\',\'_\')}_Type,&Ty${Helper.findFullClassName(classnode).replaceAll(\'::\',\'_\')}_Type,true);', /** * This is meant to contain mini-templates for converting the parameter types * of the native call to be converted from the python types provided by the caller. @@ -208,7 +208,7 @@ void doMethod(method, MethodType methodType) // transform the result <% if (constructor) { - %> result = makePythonInstance(apiResult,pytype,"${returns}",false);<% + %> result = makePythonInstance(apiResult,pytype,&Ty${SwigTypeParser.getRootType(returns).replaceAll('::','_')}_Type,false);<% } else { %> ${Helper.getOutConversion(returns,'result',method)}<% @@ -235,8 +235,16 @@ void doClassTypeInfo(Node clazz, List classNameAsVariables = null) classNameAsVariables?.add(classNameAsVariable) %> //========================================================================= - // This variable will hold the Python Type information for ${fullClassName} + // These variables will hold the Python Type information for ${fullClassName} PyTypeObject Py${classNameAsVariable}_Type; + TypeInfo Ty${classNameAsVariable}_Type;<% + + Node baseclass = PythonTools.findValidBaseClass(clazz, module) + if (baseclass) + {%> + TypeConverter<${Helper.findFullClassName(baseclass)},${fullClassName}> ${classNameAsVariable}_ParentConverter;<% + } +%> //========================================================================= <% } @@ -282,34 +290,25 @@ void doClassMethodInfo(Node clazz, List initTypeCalls = null) ${PythonTools.makeDocString(clazz.doc[0])} ); <% } %> - PyXBMCInitializeTypeObject(&Py${classNameAsVariable}_Type); + PyXBMCInitializeTypeObject(&Py${classNameAsVariable}_Type,&Ty${classNameAsVariable}_Type); Py${classNameAsVariable}_Type.tp_name = (char*)"${module.@name}.${clazz.@sym_name}"; Py${classNameAsVariable}_Type.tp_basicsize = sizeof(PyHolder); Py${classNameAsVariable}_Type.tp_dealloc = (destructor)${module.@name}_${classNameAsVariable}_Dealloc; Py${classNameAsVariable}_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; Py${classNameAsVariable}_Type.tp_doc = ${Helper.hasDoc(clazz) ? (classNameAsVariable + '__doc__') : 'NULL' }; - Py${classNameAsVariable}_Type.tp_methods = ${classNameAsVariable}_methods; <% - // I need to find the base type if there is a known class with it - assert clazz.baselist.size() < 2, "${clazz} has multiple baselists - need to write code to separate out the public one." - String baseclass = 'NULL' - List knownbases = [] - if (clazz.baselist) - { - if (clazz.baselist[0].base) clazz.baselist[0].base.each { - Node baseclassnode = Helper.findClassNodeByName(module,it.@name,clazz) - if (baseclassnode) knownbases.add(baseclassnode) - else if (!Helper.isKnownBaseType(it.@name,clazz)) - System.out.println("WARNING: the base class ${it.@name} for ${fullClassName} is unrecognized within ${module.@name}.") - } - } - assert knownbases.size() < 2, - "The class ${fullClassName} has too many known base classes. Multiple inheritance isn't supported in the code generator. Please \"#ifdef SWIG\" out all but one." - if (knownbases.size() > 0) - baseclass = "&Py${PythonTools.getClassNameAsVariable(knownbases[0])}_Type" -%> - Py${classNameAsVariable}_Type.tp_base = ${baseclass}; + Py${classNameAsVariable}_Type.tp_methods = ${classNameAsVariable}_methods; +<% + Node baseclass = PythonTools.findValidBaseClass(clazz, module) + +%> Py${classNameAsVariable}_Type.tp_base = ${baseclass ? ('&Py' + PythonTools.getClassNameAsVariable(baseclass) + '_Type') : "NULL"}; Py${classNameAsVariable}_Type.tp_new = <% Helper.hasHiddenConstructor(clazz) ? print('NULL') : print("${module.@name}_${classNameAsVariable}_New") %>; + + Ty${classNameAsVariable}_Type.swigType="p.${fullClassName}";<% + if (baseclass) { %> + Ty${classNameAsVariable}_Type.parentType=&Ty${PythonTools.getClassNameAsVariable(baseclass)}_Type; + Ty${classNameAsVariable}_Type.converter=&${classNameAsVariable}_ParentConverter; +<%} %> } //========================================================================= <% diff --git a/xbmc/interfaces/python/PythonTools.groovy b/xbmc/interfaces/python/PythonTools.groovy index 3f1c0d4a1d..cc8c611247 100644 --- a/xbmc/interfaces/python/PythonTools.groovy +++ b/xbmc/interfaces/python/PythonTools.groovy @@ -116,4 +116,24 @@ public class PythonTools return ret } + + public static Node findValidBaseClass(Node clazz, Node module, boolean warn = false) + { + // I need to find the base type if there is a known class with it + assert clazz.baselist.size() < 2, "${clazz} has multiple baselists - need to write code to separate out the public one." + String baseclass = 'NULL' + List knownbases = [] + if (clazz.baselist) + { + if (clazz.baselist[0].base) clazz.baselist[0].base.each { + Node baseclassnode = Helper.findClassNodeByName(module,it.@name,clazz) + if (baseclassnode) knownbases.add(baseclassnode) + else if (warn && !Helper.isKnownBaseType(it.@name,clazz)) + System.out.println("WARNING: the base class ${it.@name} for ${Helper.findFullClassName(clazz)} is unrecognized within ${module.@name}.") + } + } + assert knownbases.size() < 2, + "The class ${Helper.findFullClassName(clazz)} has too many known base classes. Multiple inheritance isn't supported in the code generator. Please \"#ifdef SWIG\" out all but one." + return knownbases.size() > 0 ? knownbases[0] : null + } } diff --git a/xbmc/interfaces/python/swig.cpp b/xbmc/interfaces/python/swig.cpp index a927d1f53c..42838c2821 100644 --- a/xbmc/interfaces/python/swig.cpp +++ b/xbmc/interfaces/python/swig.cpp @@ -24,12 +24,13 @@ namespace PythonBindings { - void PyXBMCInitializeTypeObject(PyTypeObject* type_object) + void PyXBMCInitializeTypeObject(PyTypeObject* type_object, TypeInfo* typeInfo) { static PyTypeObject py_type_object_header = { PyObject_HEAD_INIT(NULL) 0}; int size = (long*)&(py_type_object_header.tp_name) - (long*)&py_type_object_header; memset(type_object, 0, sizeof(PyTypeObject)); memcpy(type_object, &py_type_object_header, size); + memset(typeInfo, 0, sizeof(TypeInfo)); } int PyXBMCGetUnicodeString(std::string& buf, PyObject* pObject, bool coerceToString, @@ -173,5 +174,24 @@ namespace PythonBindings SetMessage("%s",msg.c_str()); } + + void* doretrieveApiInstance(const PyHolder* pythonType, const TypeInfo* typeInfo, const char* swigType, + const char* methodNamespacePrefix, const char* methodNameForErrorString) throw (WrongTypeException) + { + if (pythonType == NULL || pythonType->magicNumber != XBMC_PYTHON_TYPE_MAGIC_NUMBER) + throw WrongTypeException("Non api type passed in place of the expected type \"%s.\"",swigType); + if (!isParameterRightType(typeInfo->swigType,swigType,methodNamespacePrefix)) + { + // maybe it's a child class + if (typeInfo->parentType) + return doretrieveApiInstance(pythonType, typeInfo->parentType,swigType, + methodNamespacePrefix, methodNameForErrorString); + else + throw WrongTypeException("Incorrect type passed to \"%s\", was expecting a \"%s\" but received a \"%s\"", + methodNameForErrorString,swigType,typeInfo->swigType); + } + return ((PyHolder*)pythonType)->pSelf; + } + } diff --git a/xbmc/interfaces/python/swig.h b/xbmc/interfaces/python/swig.h index ca76d01737..06080ffa34 100644 --- a/xbmc/interfaces/python/swig.h +++ b/xbmc/interfaces/python/swig.h @@ -30,17 +30,37 @@ namespace PythonBindings { - void PyXBMCInitializeTypeObject(PyTypeObject* type_object); int PyXBMCGetUnicodeString(std::string& buf, PyObject* pObject, bool coerceToString = false, const char* pos = "unknown", const char* methodname = "unknown"); + // This is for casting from child class to base class + struct TypeConverterBase + { + virtual void* convert(void* from) = 0; + }; + + /** + * Template to allow the instantiation of a particular type conversion + */ + template<class T, class F> struct TypeConverter : public TypeConverterBase + { + inline virtual void* convert(void* from) { return static_cast<T*>((F*)from); } + }; + + struct TypeInfo + { + const char* swigType; + TypeInfo* parentType; + TypeConverterBase* converter; + }; + // This will hold the pointer to the api type, whether known or unknown struct PyHolder { PyObject_HEAD int32_t magicNumber; - const char* swigType; + const TypeInfo* typeInfo; void* pSelf; }; @@ -48,6 +68,8 @@ namespace PythonBindings #define XBMC_PYTHON_TYPE_MAGIC_NUMBER 0x58626D63 + void PyXBMCInitializeTypeObject(PyTypeObject* type_object, TypeInfo* typeInfo); + /** * This method retrieves the pointer from the PyHolder. The return value should * be case to the appropriate type. @@ -67,21 +89,19 @@ namespace PythonBindings bool isParameterRightType(const char* passedType, const char* expectedType, const char* methodNamespacePrefix); + void* doretrieveApiInstance(const PyHolder* pythonType, const TypeInfo* typeInfo, const char* swigType, + const char* methodNamespacePrefix, const char* methodNameForErrorString) throw (WrongTypeException); + /** * This method retrieves the pointer from the PyHolder. The return value should * be case to the appropriate type. * * Since the calls to this are generated there's no NULL pointer checks */ - inline void* retrieveApiInstance(PyObject* pythonType, const char* swigType, const char* methodNamespacePrefix, + inline void* retrieveApiInstance(const PyObject* pythonType, const char* swigType, const char* methodNamespacePrefix, const char* methodNameForErrorString) throw (WrongTypeException) { - if (pythonType == NULL || ((PyHolder*)pythonType)->magicNumber != XBMC_PYTHON_TYPE_MAGIC_NUMBER) - throw WrongTypeException("Non api type passed in place of the expected type \"%s.\"",swigType); - if (!isParameterRightType(((PyHolder*)pythonType)->swigType,swigType,methodNamespacePrefix)) - throw WrongTypeException("Incorrect type passed to \"%s\", was expecting a \"%s\" but received a \"%s\"", - methodNameForErrorString,swigType,((PyHolder*)pythonType)->swigType); - return ((PyHolder*)pythonType)->pSelf; + return doretrieveApiInstance(((PyHolder*)pythonType),((PyHolder*)pythonType)->typeInfo, swigType, methodNamespacePrefix, methodNameForErrorString); } inline void prepareForReturn(XBMCAddon::AddonClass* c) { if(c) c->Acquire(); } @@ -94,7 +114,7 @@ namespace PythonBindings * NOTE: swigTypeString must be in the data segment. That is, it should be an explicit string since * the const char* is stored in a PyHolder struct and never deleted. */ - inline PyObject* makePythonInstance(void* api, PyTypeObject* typeObj, const char* swigTypeString, bool incrementRefCount) + inline PyObject* makePythonInstance(void* api, PyTypeObject* typeObj, TypeInfo* typeInfo, bool incrementRefCount) { // null api types result in Py_None if (!api) @@ -106,7 +126,7 @@ namespace PythonBindings PyHolder* self = (PyHolder*)typeObj->tp_alloc(typeObj,0); if (!self) return NULL; self->magicNumber = XBMC_PYTHON_TYPE_MAGIC_NUMBER; - self->swigType = swigTypeString; + self->typeInfo = typeInfo; self->pSelf = api; if (incrementRefCount) Py_INCREF((PyObject*)self); |