Commit 137605d6 authored by Robert Bradshaw's avatar Robert Bradshaw

Implement anonymous struct tuple type.

Syntax is (type1, type2, ...).
parent 68a5d5d7
...@@ -1158,6 +1158,24 @@ class CComplexBaseTypeNode(CBaseTypeNode): ...@@ -1158,6 +1158,24 @@ class CComplexBaseTypeNode(CBaseTypeNode):
return type return type
class CTupleBaseTypeNode(CBaseTypeNode):
# components [CBaseTypeNode]
child_attrs = ["components"]
def analyse(self, env):
component_types = []
for c in self.components:
type = c.analyse(env)
if type.is_pyobject:
error(type_node.pos, "Tuple types can't (yet) contain Python objects.")
return PyrexType.error_type
component_types.append(type)
type = PyrexTypes.c_tuple_type(tuple(component_types))
env.declare_tuple_type(self.pos, type)
return type
class FusedTypeNode(CBaseTypeNode): class FusedTypeNode(CBaseTypeNode):
""" """
Represents a fused type in a ctypedef statement: Represents a fused type in a ctypedef statement:
......
...@@ -2038,9 +2038,21 @@ def p_c_complex_base_type(s, templates = None): ...@@ -2038,9 +2038,21 @@ def p_c_complex_base_type(s, templates = None):
s.next() s.next()
base_type = p_c_base_type(s, templates = templates) base_type = p_c_base_type(s, templates = templates)
declarator = p_c_declarator(s, empty = 1) declarator = p_c_declarator(s, empty = 1)
s.expect(')')
type_node = Nodes.CComplexBaseTypeNode(pos, type_node = Nodes.CComplexBaseTypeNode(pos,
base_type = base_type, declarator = declarator) base_type = base_type, declarator = declarator)
if s.sy == ',':
components = [type_node]
while s.sy == ',':
s.next()
if s.sy == ')':
break
base_type = p_c_base_type(s, templates = templates)
declarator = p_c_declarator(s, empty = 1)
components.append(Nodes.CComplexBaseTypeNode(pos,
base_type = base_type, declarator = declarator))
type_node = Nodes.CTupleBaseTypeNode(pos, components = components)
s.expect(')')
if s.sy == '[': if s.sy == '[':
if is_memoryviewslice_access(s): if is_memoryviewslice_access(s):
type_node = p_memoryviewslice_access(s, type_node) type_node = p_memoryviewslice_access(s, type_node)
......
...@@ -3310,6 +3310,88 @@ class CEnumType(CType): ...@@ -3310,6 +3310,88 @@ class CEnumType(CType):
base_code = public_decl(base_code, dll_linkage) base_code = public_decl(base_code, dll_linkage)
return self.base_declaration_code(base_code, entity_code) return self.base_declaration_code(base_code, entity_code)
class CTupleType(CType):
# components [PyrexType]
def __init__(self, cname, components):
self.cname = cname
self.components = components
self.to_py_function = "%s_to_py_%s" % (Naming.convert_func_prefix, self.cname)
self.from_py_function = "%s_from_py_%s" % (Naming.convert_func_prefix, self.cname)
self.exception_check = True
self._convert_to_py_code = None
self._convert_from_py_code = None
def __str__(self):
return "(%s)" % ", ".join(str(c) for c in self.components)
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
return str(self)
else:
return self.base_declaration_code(self.cname, entity_code)
def create_to_py_utility_code(self, env):
if self._convert_to_py_code is False:
return None # tri-state-ish
if self._convert_to_py_code is None:
for component in self.components:
if not component.create_to_py_utility_code(env):
self.to_py_function = None
self._convert_to_py_code = False
return False
context = dict(
struct_type_decl=self.declaration_code(""),
components=self.components,
funcname=self.to_py_function,
size=len(self.components)
)
self._convert_to_py_code = TempitaUtilityCode.load(
"ToPyCTupleUtility", "TypeConversion.c", context=context)
env.use_utility_code(self._convert_to_py_code)
return True
def create_from_py_utility_code(self, env):
if self._convert_from_py_code is False:
return None # tri-state-ish
if self._convert_from_py_code is None:
for component in self.components:
if not component.create_from_py_utility_code(env):
self.from_py_function = None
self._convert_from_py_code = False
return False
context = dict(
struct_type_decl=self.declaration_code(""),
components=self.components,
funcname=self.from_py_function,
size=len(self.components)
)
self._convert_from_py_code = TempitaUtilityCode.load(
"FromPyCTupleUtility", "TypeConversion.c", context=context)
env.use_utility_code(self._convert_from_py_code)
return True
c_tuple_types = {}
def c_tuple_type(components):
tuple_type = c_tuple_types.get(components)
if tuple_type is None:
cname = '__pyx_tuple_' + '___'.join(
c.declaration_code('').replace('*', '_ptr')
.replace(' ', '__')
.replace('[', '_sbra')
.replace(']', '_sket')
for c in components)
c_tuple_types[components] = tuple_type
return CTupleType(cname, components)
class UnspecifiedType(PyrexType): class UnspecifiedType(PyrexType):
# Used as a placeholder until the type can be determined. # Used as a placeholder until the type can be determined.
......
...@@ -606,6 +606,9 @@ class Scope(object): ...@@ -606,6 +606,9 @@ class Scope(object):
self.sue_entries.append(entry) self.sue_entries.append(entry)
return entry return entry
def declare_tuple_type(self, pos, type):
self.outer_scope.declare_tuple_type(pos, type)
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0): api = 0, in_pxd = 0, is_cdef = 0):
...@@ -1053,6 +1056,16 @@ class ModuleScope(Scope): ...@@ -1053,6 +1056,16 @@ class ModuleScope(Scope):
return self.outer_scope.lookup(name, language_level=language_level) return self.outer_scope.lookup(name, language_level=language_level)
def declare_tuple_type(self, pos, type):
cname = type.cname
if not self.lookup_here(cname):
scope = StructOrUnionScope(cname)
for ix, component in enumerate(type.components):
scope.declare_var(name="f%s" % ix, type=component, pos=pos)
entry = self.declare_struct_or_union(cname, 'struct', scope, typedef_flag=True, pos=pos, cname=cname)
entry.used = True
type.struct = entry
def declare_builtin(self, name, pos): def declare_builtin(self, name, pos):
if not hasattr(builtins, name) \ if not hasattr(builtins, name) \
and name not in Code.non_portable_builtins_map \ and name not in Code.non_portable_builtins_map \
......
...@@ -312,7 +312,6 @@ static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { ...@@ -312,7 +312,6 @@ static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
/////////////// FromPyStructUtility.proto /////////////// /////////////// FromPyStructUtility.proto ///////////////
{{struct_type_decl}};
static {{struct_type_decl}} {{funcname}}(PyObject *); static {{struct_type_decl}} {{funcname}}(PyObject *);
/////////////// FromPyStructUtility /////////////// /////////////// FromPyStructUtility ///////////////
...@@ -346,6 +345,55 @@ bad: ...@@ -346,6 +345,55 @@ bad:
Py_XDECREF(value); Py_XDECREF(value);
return result; return result;
} }
/////////////// ToPyCTupleUtility.proto ///////////////
static PyObject* {{funcname}}({{struct_type_decl}});
/////////////// ToPyCTupleUtility ///////////////
static PyObject* {{funcname}}({{struct_type_decl}} value) {
PyObject* item = NULL;
PyObject* result = PyTuple_New({{size}});
if (!result) goto bad;
{{for ix, component in enumerate(components):}}
{{py:attr = "value.f%s" % ix}}
item = {{component.to_py_function}}({{attr}});
if (!item) goto bad;
PyTuple_SET_ITEM(result, {{ix}}, item);
{{endfor}}
return result;
bad:
Py_XDECREF(item);
Py_XDECREF(result);
return NULL;
}
/////////////// FromPyCTupleUtility.proto ///////////////
static {{struct_type_decl}} {{funcname}}(PyObject *);
/////////////// FromPyCTupleUtility ///////////////
static {{struct_type_decl}} {{funcname}}(PyObject * o) {
{{struct_type_decl}} result;
if (!PyTuple_Check(o) || PyTuple_GET_SIZE(o) != {{size}}) {
PyErr_Format(PyExc_TypeError, "Expected %.16s of size %.8d, got %.200s", "a tuple", {{size}}, Py_TYPE(o)->tp_name);
goto bad;
}
{{for ix, component in enumerate(components):}}
{{py:attr = "result.f%s" % ix}}
{{attr}} = {{component.from_py_function}}(PyTuple_GET_ITEM(o, {{ix}}));
if ({{component.error_condition(attr)}})
goto bad;
{{endfor}}
return result;
bad:
return result;
}
/////////////// ObjectAsUCS4.proto /////////////// /////////////// ObjectAsUCS4.proto ///////////////
......
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