Add general support for templated classes (previously only classes with non-templated typedefs were allowed).

This commit is contained in:
Gustavo J. A. M. Carneiro committed 2008-01-04 18:22:57 +00:00
1 parent 68cb0dc934
commit bbfbe4702e
2 files changed
+91 -28

No files matched your search

+33 -7
View File
@@ -33,7 +33,7 @@ class CppHelperClass(object):
class_ -- original CppClass wrapper object
"""
self.class_ = class_
self.name = class_.name + "_PythonProxy"
self.name = class_.pystruct + "__PythonHelper"
self.virtual_parent_callers = {}
self.virtual_proxies = []
self.cannot_be_constructed = False
@@ -95,7 +95,7 @@ class CppHelperClass(object):
code_sink.writeln("%s(%s)" % (self.name, ', '.join(params)))
code_sink.indent()
code_sink.writeln(": %s(%s), m_pyself(NULL)\n{}" %
(self.class_.name,
(self.class_.full_name,
', '.join([param.name for param in cons.parameters])))
code_sink.unindent()
code_sink.writeln()
@@ -261,7 +261,8 @@ class CppClass(object):
def __init__(self, name, parent=None, incref_method=None, decref_method=None,
automatic_type_narrowing=None, allow_subclassing=None,
is_singleton=False, outer_class=None,
peekref_method=None):
peekref_method=None,
template_parameters=(), custom_template_class_name=None):
"""Constructor
name -- class name
parent -- optional parent class wrapper
@@ -290,8 +291,10 @@ class CppClass(object):
self.outer_class = outer_class
self._module = None
self.name = name
self.template_parameters = template_parameters
self.custom_template_class_name = custom_template_class_name
self.is_singleton = is_singleton
self.full_name = None # full name with C++ namespaces attached
self.full_name = None # full name with C++ namespaces attached and template parameters
self.methods = {} # name => OverloadedMethod
self.constructors = [] # (name, wrapper) pairs
self.slots = dict()
@@ -478,7 +481,21 @@ class CppClass(object):
else:
return s
flat_name = ''.join([make_upper(s) for s in self.full_name.split('::')])
def mangle(s):
"make a name Like<This,and,That> look Like__lt__This_and_That__gt__"
s = s.replace('<', '__lt__').replace('>', '__gt__').replace(',', '_')
s = s.replace(' ', '_').replace('&', '__amp__').replace('*', '__star__')
return s
def flatten(name):
"make a name like::This look LikeThis"
return ''.join([make_upper(mangle(s)) for s in name.split('::')])
flat_name = flatten(self.full_name)
if self.template_parameters:
self.full_name += "< %s >" % (', '.join(self.template_parameters))
flat_name += '__' + '_'.join([flatten(s) for s in self.template_parameters])
self._pystruct = "Py%s%s" % (prefix, flat_name)
self.metaclass_name = "%sMeta" % flat_name
@@ -818,14 +835,23 @@ typedef struct {
module.after_init.write_error_check('PyType_Ready(&%s)'
% (self.pytypestruct,))
if self.template_parameters:
if self.custom_template_class_name is None:
class_python_name = utils.get_mangled_name(self.name, self.template_parameters)
else:
class_python_name = self.custom_template_class_name
else:
class_python_name = self.name
if self.outer_class is None:
module.after_init.write_code(
'PyModule_AddObject(m, \"%s\", (PyObject *) &%s);' % (
self.name, self.pytypestruct))
class_python_name, self.pytypestruct))
else:
module.after_init.write_code(
'PyDict_SetItemString((PyObject*) %s.tp_dict, \"%s\", (PyObject *) &%s);' % (
self.outer_class.pytypestruct, self.name, self.pytypestruct))
self.outer_class.pytypestruct, class_python_name, self.pytypestruct))
have_constructor = self._generate_constructor(code_sink)
+58 -21
View File
@@ -49,6 +49,21 @@ class ErrorHandler(settings.ErrorHandler):
return True
settings.error_handler = ErrorHandler()
_digits = re.compile(r"\s*\d+\s*")
def normalize_name(decl_string):
if templates.is_instantiation(decl_string):
cls_name, template_parameters = templates.split(decl_string)
else:
cls_name = decl_string
template_parameters = None
if not _digits.match(cls_name):
if not cls_name.startswith('::'):
cls_name = '::' + cls_name
if template_parameters is None:
return cls_name
else:
return "%s< %s >" % (cls_name, ', '.join([normalize_name(name) for name in template_parameters]))
class GccXmlTypeRegistry(object):
def __init__(self):
@@ -57,19 +72,23 @@ class GccXmlTypeRegistry(object):
def register_class(self, cpp_class, alias=None):
assert isinstance(cpp_class, CppClass)
if cpp_class.full_name.startswith('::'):
full_name = cpp_class.full_name
else:
full_name = '::' + cpp_class.full_name
full_name = normalize_name(cpp_class.full_name)
#print >> sys.stderr, "******** registering class %s as %s" \
# % (cpp_class.gccxml_definition, full_name)
self.classes[full_name] = cpp_class
if alias is not None:
alias = normalize_name(alias)
self.classes[alias] = cpp_class
#print >> sys.stderr, "******** registering class %s also as alias %s" \
# % (cpp_class.gccxml_definition, alias)
def find_class(self, class_name, module_namespace):
if not class_name.startswith(module_namespace):
class_name = module_namespace + class_name
if not class_name.startswith('::'):
class_name = '::' + class_name
class_name = normalize_name(class_name)
#if '<' in class_name:
# print >> sys.stderr, "******** looking for class %s" \
# % (class_name)
return self.classes[class_name]
def get_class_type_traits(self, type_info):
@@ -83,8 +102,12 @@ class GccXmlTypeRegistry(object):
is_pointer = False
pointer_is_const = False
if isinstance(base_type, cpptypes.declarated_t):
class_name = normalize_name(base_type.decl_string)
#if '<' in class_name:
# print >> sys.stderr, "******** looking for class %s" \
# % (class_name)
try:
cpp_class = self.classes[base_type.decl_string]
cpp_class = self.classes[class_name]
except KeyError:
return (None, is_const, is_pointer, is_reference, pointer_is_const)
@@ -427,10 +450,7 @@ class ModuleParser(object):
if typedef_type == cls:
break
else:
warnings.warn_explicit("Class %s ignored because it is templated; templates not yet supported"
% cls.decl_string,
Warning, cls.location.file_name, cls.location.line)
continue
typedef = None
if len(cls.bases) > 1:
warnings.warn_explicit(("Class %s ignored because it uses multiple "
@@ -494,19 +514,42 @@ class ModuleParser(object):
if not self._class_has_public_destructor(cls):
kwargs.setdefault('is_singleton', True)
custom_template_class_name = None
template_parameters = ()
if typedef is None:
name = cls.name
alias = None
if templates.is_instantiation(cls.decl_string):
cls_name, template_parameters = templates.split(cls.name)
assert template_parameters
a1 = 1
if '::' in cls_name:
cls_name = cls_name.split('::')[-1]
template_instance_names = global_annotations.get('template_instance_names', '')
if template_instance_names:
for mapping in template_instance_names.split('|'):
type_names, name = mapping.split('=>')
instance_types = type_names.split(',')
if instance_types == template_parameters:
custom_template_class_name = name
break
else:
a2 = 1
cls_name = cls.name
else:
name = typedef.name
cls_name = typedef.name
alias = '::'.join([module.cpp_namespace_prefix, cls.name])
#print >> sys.stderr, "******** registering class %s" % cls
class_wrapper = CppClass(name, parent=base_class_wrapper, outer_class=outer_class, **kwargs)
class_wrapper = CppClass(cls_name, parent=base_class_wrapper, outer_class=outer_class,
template_parameters=template_parameters,
custom_template_class_name=custom_template_class_name,
**kwargs)
class_wrapper.gccxml_definition = cls
module.add_class(class_wrapper)
registered_classes[cls] = class_wrapper
type_registry.register_class(class_wrapper, alias)
del cls_name
## scan for nested classes/enums
self._scan_namespace_types(module, module_namespace, outer_class=class_wrapper)
@@ -514,12 +557,6 @@ class ModuleParser(object):
other_class = type_registry.find_class(operator.return_type.decl_string, '::')
class_wrapper.implicitly_converts_to(other_class)
assert typedef is not None or \
(cls.decl_string in type_registry.classes\
and type_registry.classes[cls.decl_string] == class_wrapper)
for cls, class_wrapper in registered_classes.iteritems():
self._scan_methods(cls, class_wrapper)