aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Carroll <thecarrolls@jiminger.com>2012-09-11 23:51:03 -0400
committerJim Carroll <thecarrolls@jiminger.com>2012-09-11 23:56:41 -0400
commitee83efc805c61f25c381efaaded06c4620cb4cae (patch)
tree89f64621e8e65e84e4e918fc63dd1b221513f3c3
parentb8ba975f6731f1a77a9d2e214e743ddd52500466 (diff)
[fix] More robust type information for base class type checking.
-rw-r--r--xbmc/interfaces/python/PythonSwig.cpp.template47
-rw-r--r--xbmc/interfaces/python/PythonTools.groovy20
-rw-r--r--xbmc/interfaces/python/swig.cpp22
-rw-r--r--xbmc/interfaces/python/swig.h42
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);