Commit 18e8b745 authored by Robert Bradshaw's avatar Robert Bradshaw

Support enums in C++ classes.

This fixes #1473.
parent 439c7b83
...@@ -1457,6 +1457,9 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): ...@@ -1457,6 +1457,9 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
if self.in_pxd and not env.in_cinclude: if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1 self.entry.defined_in_pxd = 1
for attr in self.attributes: for attr in self.attributes:
declare = getattr(attr, 'declare', None)
if declare:
attr.declare(scope)
attr.analyse_declarations(scope) attr.analyse_declarations(scope)
for func in func_attributes(self.attributes): for func in func_attributes(self.attributes):
defined_funcs.append(func) defined_funcs.append(func)
......
...@@ -3625,8 +3625,10 @@ def p_cpp_class_attribute(s, ctx): ...@@ -3625,8 +3625,10 @@ def p_cpp_class_attribute(s, ctx):
decorators = p_decorators(s) decorators = p_decorators(s)
if s.systring == 'cppclass': if s.systring == 'cppclass':
return p_cpp_class_definition(s, s.position(), ctx) return p_cpp_class_definition(s, s.position(), ctx)
if s.systring == 'ctypedef': elif s.systring == 'ctypedef':
return p_ctypedef_statement(s, ctx) return p_ctypedef_statement(s, ctx)
elif s.sy == 'IDENT' and s.systring in struct_enum_union:
return p_struct_enum(s, s.position(), ctx)
else: else:
node = p_c_func_or_var_declaration(s, s.position(), ctx) node = p_c_func_or_var_declaration(s, s.position(), ctx)
if decorators is not None: if decorators is not None:
......
...@@ -3627,11 +3627,12 @@ class CEnumType(CType): ...@@ -3627,11 +3627,12 @@ class CEnumType(CType):
signed = 1 signed = 1
rank = -1 # Ranks below any integer type rank = -1 # Ranks below any integer type
def __init__(self, name, cname, typedef_flag): def __init__(self, name, cname, typedef_flag, namespace=None):
self.name = name self.name = name
self.cname = cname self.cname = cname
self.values = [] self.values = []
self.typedef_flag = typedef_flag self.typedef_flag = typedef_flag
self.namespace = namespace
self.default_value = "(%s) 0" % self.empty_declaration_code() self.default_value = "(%s) 0" % self.empty_declaration_code()
def __str__(self): def __str__(self):
...@@ -3646,13 +3647,24 @@ class CEnumType(CType): ...@@ -3646,13 +3647,24 @@ class CEnumType(CType):
if pyrex or for_display: if pyrex or for_display:
base_code = self.name base_code = self.name
else: else:
if self.typedef_flag: if self.namespace:
base_code = "%s::%s" % (
self.namespace.empty_declaration_code(), self.cname)
elif self.typedef_flag:
base_code = self.cname base_code = self.cname
else: else:
base_code = "enum %s" % self.cname base_code = "enum %s" % self.cname
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)
def specialize(self, values):
if self.namespace:
namespace = self.namespace.specialize(values)
if namespace != self.namespace:
return CEnumType(
self.name, self.cname, self.typedef_flag, namespace)
return self
def create_to_py_utility_code(self, env): def create_to_py_utility_code(self, env):
self.to_py_function = "__Pyx_PyInt_From_" + self.specialization_name() self.to_py_function = "__Pyx_PyInt_From_" + self.specialization_name()
env.use_utility_code(TempitaUtilityCode.load_cached( env.use_utility_code(TempitaUtilityCode.load_cached(
......
...@@ -546,6 +546,8 @@ class Scope(object): ...@@ -546,6 +546,8 @@ class Scope(object):
if scope: if scope:
entry.type.scope = scope entry.type.scope = scope
self.type_entries.append(entry) self.type_entries.append(entry)
if self.is_cpp_class_scope:
entry.type.namespace = self.outer_scope.lookup(self.name).type
return entry return entry
def declare_cpp_class(self, name, scope, def declare_cpp_class(self, name, scope,
...@@ -613,11 +615,16 @@ class Scope(object): ...@@ -613,11 +615,16 @@ class Scope(object):
visibility = 'private', api = 0, create_wrapper = 0): visibility = 'private', api = 0, create_wrapper = 0):
if name: if name:
if not cname: if not cname:
if self.in_cinclude or (visibility == 'public' or api): if (self.in_cinclude or visibility == 'public'
or visibility == 'extern' or api):
cname = name cname = name
else: else:
cname = self.mangle(Naming.type_prefix, name) cname = self.mangle(Naming.type_prefix, name)
type = PyrexTypes.CEnumType(name, cname, typedef_flag) if self.is_cpp_class_scope:
namespace = self.outer_scope.lookup(self.name).type
else:
namespace = None
type = PyrexTypes.CEnumType(name, cname, typedef_flag, namespace)
else: else:
type = PyrexTypes.c_anon_enum_type type = PyrexTypes.c_anon_enum_type
entry = self.declare_type(name, type, pos, cname = cname, entry = self.declare_type(name, type, pos, cname = cname,
......
...@@ -11,6 +11,10 @@ cdef extern from "cpp_nested_classes_support.h": ...@@ -11,6 +11,10 @@ cdef extern from "cpp_nested_classes_support.h":
@staticmethod @staticmethod
my_int negate(my_int) my_int negate(my_int)
cdef cppclass TypedClass[T]:
enum MyEnum:
value
def test_nested_classes(): def test_nested_classes():
""" """
>>> test_nested_classes() >>> test_nested_classes()
...@@ -28,3 +32,8 @@ def test_nested_classes(): ...@@ -28,3 +32,8 @@ def test_nested_classes():
def test_nested_typedef(py_x): def test_nested_typedef(py_x):
cdef A.my_int x = py_x cdef A.my_int x = py_x
assert A.negate(x) == -py_x assert A.negate(x) == -py_x
def test_nested_enum(TypedClass[double].MyEnum x):
return x == 3
def test_
\ No newline at end of file
...@@ -16,3 +16,16 @@ public: ...@@ -16,3 +16,16 @@ public:
return -x; return -x;
} }
}; };
template <typename T>
class TypedClass {
public:
enum MyEnum {
value = 39
};
union MyUnion {
T typed_value;
int int_value;
}
typedef T MyType;
};
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