Commit 4e07fc52 authored by Robert Bradshaw's avatar Robert Bradshaw

More C++ class fixes, tests.

parent 3e25a388
...@@ -1329,9 +1329,8 @@ class NewExprNode(AtomicExprNode): ...@@ -1329,9 +1329,8 @@ class NewExprNode(AtomicExprNode):
self.cpp_check(env) self.cpp_check(env)
constructor = type.scope.lookup(u'<init>') constructor = type.scope.lookup(u'<init>')
if constructor is None: if constructor is None:
return_type = PyrexTypes.CFuncType(type, [], exception_check='+') func_type = PyrexTypes.CFuncType(type, [], exception_check='+')
return_type = PyrexTypes.CPtrType(return_type) type.scope.declare_cfunction(u'<init>', func_type, self.pos)
type.scope.declare_cfunction(u'<init>', return_type, self.pos)
constructor = type.scope.lookup(u'<init>') constructor = type.scope.lookup(u'<init>')
self.class_type = type self.class_type = type
self.entry = constructor self.entry = constructor
...@@ -3705,6 +3704,7 @@ class CallNode(ExprNode): ...@@ -3705,6 +3704,7 @@ class CallNode(ExprNode):
self.function.entry = constructor self.function.entry = constructor
self.function.set_cname(type.declaration_code("")) self.function.set_cname(type.declaration_code(""))
self.analyse_c_function_call(env) self.analyse_c_function_call(env)
self.type = type
return True return True
def is_lvalue(self): def is_lvalue(self):
......
...@@ -669,7 +669,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -669,7 +669,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_struct_union_predeclaration(self, entry, code): def generate_struct_union_predeclaration(self, entry, code):
type = entry.type type = entry.type
if type.is_cpp_class and type.templates: if type.is_cpp_class and type.templates:
code.putln("template <class %s>" % ", class ".join([T.declaration_code("") for T in type.templates])) code.putln("template <typename %s>" % ", typename ".join([T.declaration_code("") for T in type.templates]))
code.putln(self.sue_predeclaration(type, type.kind, type.cname)) code.putln(self.sue_predeclaration(type, type.kind, type.cname))
def sue_header_footer(self, type, kind, name): def sue_header_footer(self, type, kind, name):
...@@ -728,7 +728,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -728,7 +728,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.put(" : public %s" % base_class_decl) code.put(" : public %s" % base_class_decl)
code.putln(" {") code.putln(" {")
for attr in scope.var_entries: for attr in scope.var_entries:
if attr.type.is_cfunction: if attr.type.is_cfunction and attr.name != "<init>":
code.put("virtual ") code.put("virtual ")
code.putln( code.putln(
"%s;" % "%s;" %
......
...@@ -1197,7 +1197,7 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): ...@@ -1197,7 +1197,7 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
if self.entry is None: if self.entry is None:
return return
self.entry.is_cpp_class = 1 self.entry.is_cpp_class = 1
scope.class_namespace = self.entry.type.declaration_code("") scope.type = self.entry.type
defined_funcs = [] defined_funcs = []
if self.attributes is not None: if self.attributes is not None:
if self.in_pxd and not env.in_cinclude: if self.in_pxd and not env.in_cinclude:
...@@ -1206,6 +1206,8 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): ...@@ -1206,6 +1206,8 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode):
attr.analyse_declarations(scope) attr.analyse_declarations(scope)
if isinstance(attr, CFuncDefNode): if isinstance(attr, CFuncDefNode):
defined_funcs.append(attr) defined_funcs.append(attr)
if self.templates is not None:
attr.template_declaration = "template <typename %s>" % ", typename ".join(self.templates)
self.body = StatListNode(self.pos, stats=defined_funcs) self.body = StatListNode(self.pos, stats=defined_funcs)
self.scope = scope self.scope = scope
...@@ -1935,6 +1937,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -1935,6 +1937,7 @@ class CFuncDefNode(FuncDefNode):
# py_func wrapper for calling from Python # py_func wrapper for calling from Python
# overridable whether or not this is a cpdef function # overridable whether or not this is a cpdef function
# inline_in_pxd whether this is an inline function in a pxd file # inline_in_pxd whether this is an inline function in a pxd file
# template_declaration String or None Used for c++ class methods
child_attrs = ["base_type", "declarator", "body", "py_func"] child_attrs = ["base_type", "declarator", "body", "py_func"]
...@@ -1943,6 +1946,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -1943,6 +1946,7 @@ class CFuncDefNode(FuncDefNode):
directive_locals = None directive_locals = None
directive_returns = None directive_returns = None
override = None override = None
template_declaration = None
def unqualified_name(self): def unqualified_name(self):
return self.entry.name return self.entry.name
...@@ -2150,6 +2154,8 @@ class CFuncDefNode(FuncDefNode): ...@@ -2150,6 +2154,8 @@ class CFuncDefNode(FuncDefNode):
header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage) header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage)
#print (storage_class, modifiers, header) #print (storage_class, modifiers, header)
if self.template_declaration:
code.putln(self.template_declaration)
code.putln("%s%s%s {" % (storage_class, modifiers, header)) code.putln("%s%s%s {" % (storage_class, modifiers, header))
def generate_argument_declarations(self, env, code): def generate_argument_declarations(self, env, code):
......
...@@ -125,6 +125,7 @@ directive_defaults = { ...@@ -125,6 +125,7 @@ directive_defaults = {
# experimental, subject to change # experimental, subject to change
'binding': False, 'binding': False,
'experimental_cpp_class_def': False
} }
# Extra warning directives # Extra warning directives
......
...@@ -1213,6 +1213,19 @@ class CVoidType(CType): ...@@ -1213,6 +1213,19 @@ class CVoidType(CType):
def is_complete(self): def is_complete(self):
return 0 return 0
class InvisibleVoidType(CVoidType):
#
# For use with C++ constructors and destructors return types.
# Acts like void, but does not print out a declaration.
#
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = "[void]"
else:
base_code = public_decl("", dll_linkage)
return self.base_declaration_code(base_code, entity_code)
class CNumericType(CType): class CNumericType(CType):
# #
......
...@@ -1995,7 +1995,7 @@ class CppClassScope(Scope): ...@@ -1995,7 +1995,7 @@ class CppClassScope(Scope):
is_cpp_class_scope = 1 is_cpp_class_scope = 1
default_constructor = None default_constructor = None
class_namespace = None type = None
def __init__(self, name, outer_scope, templates=None): def __init__(self, name, outer_scope, templates=None):
Scope.__init__(self, name, outer_scope, None) Scope.__init__(self, name, outer_scope, None)
...@@ -2010,15 +2010,21 @@ class CppClassScope(Scope): ...@@ -2010,15 +2010,21 @@ class CppClassScope(Scope):
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'extern', cname = None, visibility = 'extern',
api = 0, in_pxd = 0, is_cdef = 0, api = 0, in_pxd = 0, is_cdef = 0,
allow_pyobject = 0): allow_pyobject = 0, defining = 0):
# Add an entry for an attribute. # Add an entry for an attribute.
if not cname: if not cname:
cname = name cname = name
entry = self.declare(name, cname, type, pos, visibility) entry = self.lookup_here(name)
if defining and entry is not None:
if not entry.type.same_as(type):
error(pos, "Function signature does not match previous declaration")
else:
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1 entry.is_variable = 1
if type.is_cfunction and self.class_namespace: if type.is_cfunction and self.type:
entry.func_cname = "%s::%s" % (self.class_namespace, cname) entry.func_cname = "%s::%s" % (self.type.declaration_code(""), cname)
self.var_entries.append(entry) if name != "this" and (defining or name != "<init>"):
self.var_entries.append(entry)
if type.is_pyobject and not allow_pyobject: if type.is_pyobject and not allow_pyobject:
error(pos, error(pos,
"C++ class member cannot be a Python object") "C++ class member cannot be a Python object")
...@@ -2056,14 +2062,20 @@ class CppClassScope(Scope): ...@@ -2056,14 +2062,20 @@ class CppClassScope(Scope):
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'extern', api = 0, in_pxd = 0, cname = None, visibility = 'extern', api = 0, in_pxd = 0,
defining = 0, modifiers = (), utility_code = None): defining = 0, modifiers = (), utility_code = None):
if name == self.name.split('::')[-1] and cname is None: if name in (self.name.split('::')[-1], '__init__') and cname is None:
self.check_base_default_constructor(pos) self.check_base_default_constructor(pos)
cname = self.type.cname
name = '<init>' name = '<init>'
type.return_type = self.lookup(self.name).type type.return_type = PyrexTypes.InvisibleVoidType()
elif name == '__dealloc__' and cname is None:
cname = "~%s" % self.type.cname
name = '<del>'
type.return_type = PyrexTypes.InvisibleVoidType()
prev_entry = self.lookup_here(name) prev_entry = self.lookup_here(name)
entry = self.declare_var(name, type, pos, entry = self.declare_var(name, type, pos,
defining=defining,
cname=cname, visibility=visibility) cname=cname, visibility=visibility)
if prev_entry: if prev_entry and not defining:
entry.overloaded_alternatives = prev_entry.all_alternatives() entry.overloaded_alternatives = prev_entry.all_alternatives()
entry.utility_code = utility_code entry.utility_code = utility_code
type.entry = entry type.entry = entry
......
# cython: experimental_cpp_class_def=True
# tag: cpp
cdef double pi
from math import pi
from libc.math cimport sin, cos
cdef extern from "shapes.h" namespace "shapes":
cdef cppclass Shape:
float area()
cdef cppclass RegularPolygon(Shape):
float radius # major
int n
__init__(int n, float radius):
this.n = n
this.radius = radius
float area():
cdef double theta = pi / this.n
return this.radius * this.radius * sin(theta) * cos(theta) * this.n
def test_Poly(int n, float radius=1):
"""
>>> test_Poly(4)
2.0
>>> test_Poly(3)
1.299038052558899
>>> test_Poly(3, 10.0)
129.90380859375
>>> test_Poly(100)
3.139525890350342
>>> test_Poly(1000)
3.1415719985961914
"""
cdef RegularPolygon* poly
try:
poly = new RegularPolygon(n, radius)
poly.n = n
poly.radius = radius
return poly.area()
finally:
del poly
cdef cppclass InitDealloc:
__init__():
print "Init"
__dealloc__():
print "Dealloc"
def test_init_dealloc():
"""
>>> test_init_dealloc()
start
Init
live
Dealloc
end
"""
print "start"
cdef InitDealloc *ptr = new InitDealloc()
print "live"
del ptr
print "end"
cdef cppclass WithTemplate[T]:
T value
void set_value(T value):
this.value = value
T get_value():
return this.value
cdef cppclass ResolveTemplate(WithTemplate[long]):
pass
def test_templates(long value):
"""
>>> test_templates(10)
>>> test_templates(-2)
"""
cdef WithTemplate[long] *base = new WithTemplate[long]()
del base
cdef ResolveTemplate *resolved = new ResolveTemplate()
resolved.set_value(value)
assert resolved.value == resolved.get_value() == value, resolved.value
base = resolved
base.set_value(2 * value)
assert base.get_value() == base.value == 2 * value, base.value
del base
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