Commit 5d3a0e5e authored by Xavier Thompson's avatar Xavier Thompson

Adapt ctuples to support template-dependent ctuples nested in a templated namespace

parent 31a9ab1e
...@@ -4470,7 +4470,7 @@ class CTupleType(CType): ...@@ -4470,7 +4470,7 @@ class CTupleType(CType):
is_ctuple = True is_ctuple = True
def __init__(self, cname, components): def __init__(self, cname, components, templated_namespace = None):
self.cname = cname self.cname = cname
self.components = components self.components = components
self.size = len(components) self.size = len(components)
...@@ -4479,16 +4479,32 @@ class CTupleType(CType): ...@@ -4479,16 +4479,32 @@ class CTupleType(CType):
self.exception_check = True self.exception_check = True
self._convert_to_py_code = None self._convert_to_py_code = None
self._convert_from_py_code = None self._convert_from_py_code = None
self.templated_namespace = templated_namespace
def __str__(self): def __str__(self):
return "(%s)" % ", ".join(str(c) for c in self.components) return "(%s)" % ", ".join(str(c) for c in self.components)
def specialize(self, values):
specialized_components = [c.specialize(values) for c in self.components]
if specialized_components != self.components:
ttype = CTupleType(self.cname, specialized_components, self.templated_namespace.specialize(values))
# specialise the names of the python conversion functions to avoid collisions
specialised_suffix = type_list_identifier(specialized_components)
ttype.to_py_function = "%s_%s" % (self.to_py_function, specialised_suffix)
ttype.from_py_function = "%s_%s" % (self.from_py_function, specialised_suffix)
return ttype
return super(CTupleType, self).specialize(values)
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display: if pyrex or for_display:
return str(self) return str(self)
else: else:
return self.base_declaration_code(self.cname, entity_code) base_code = self.base_declaration_code(self.cname, entity_code)
if self.templated_namespace is not None:
return "%s::%s" % (namespace_declaration_code(self.templated_namespace), base_code)
else:
return base_code
def can_coerce_to_pyobject(self, env): def can_coerce_to_pyobject(self, env):
for component in self.components: for component in self.components:
......
...@@ -961,8 +961,14 @@ class Scope(object): ...@@ -961,8 +961,14 @@ class Scope(object):
self.sue_entries.append(entry) self.sue_entries.append(entry)
return entry return entry
def declare_tuple_type(self, pos, components): def declare_tuple_type(self, pos, components, templated_namespace = None):
return self.outer_scope.declare_tuple_type(pos, components) # if the ctuple is nested in a templated cpp namespace it might have templated components
# in order to support that we'll declare the ctuple in the innermost such namespace
if templated_namespace is None and self.is_cpp_class_scope and self.parent_type.templates:
# we could declare the ctuple directly in this scope but to avoid redundant code duplication we just
# propagate the innermost templated cpp namespace and let the module scope handle the declaration
templated_namespace = self
return self.outer_scope.declare_tuple_type(pos, components, templated_namespace)
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', cname = None, visibility = 'private',
...@@ -1530,23 +1536,29 @@ class ModuleScope(Scope): ...@@ -1530,23 +1536,29 @@ class ModuleScope(Scope):
return self.outer_scope.lookup(name, language_level=language_level, str_is_str=str_is_str) return self.outer_scope.lookup(name, language_level=language_level, str_is_str=str_is_str)
def declare_tuple_type(self, pos, components): def declare_tuple_type(self, pos, components, templated_namespace = None):
components = tuple(components) components = tuple(components)
if templated_namespace is None:
try: try:
ttype = self._cached_tuple_types[components] ttype = self._cached_tuple_types[components]
except KeyError: except KeyError:
ttype = self._cached_tuple_types[components] = PyrexTypes.c_tuple_type(components) ttype = self._cached_tuple_types[components] = PyrexTypes.c_tuple_type(components)
namespace = self # declare the ctuple in the module scope
else:
namespace = templated_namespace # declare the ctuple in the templated namespace instead
ttype = PyrexTypes.c_tuple_type(components)
ttype.templated_namespace = templated_namespace.parent_type
cname = ttype.cname cname = ttype.cname
entry = self.lookup_here(cname) entry = namespace.lookup_here(cname)
if not entry: if not entry:
scope = StructOrUnionScope(cname) scope = StructOrUnionScope(cname)
for ix, component in enumerate(components): for ix, component in enumerate(components):
scope.declare_var(name="f%s" % ix, type=component, pos=pos) scope.declare_var(name="f%s" % ix, type=component, pos=pos)
struct_entry = self.declare_struct_or_union( struct_entry = namespace.declare_struct_or_union(
cname + '_struct', 'struct', scope, typedef_flag=True, pos=pos, cname=cname) cname + '_struct', 'struct', scope, typedef_flag=True, pos=pos, cname=cname)
self.type_entries.remove(struct_entry) namespace.type_entries.remove(struct_entry)
ttype.struct_entry = struct_entry ttype.struct_entry = struct_entry
entry = self.declare_type(cname, ttype, pos, cname) entry = namespace.declare_type(cname, ttype, pos, cname)
ttype.entry = entry ttype.entry = entry
return entry return entry
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment