Commit becd5ce7 authored by Robert Bradshaw's avatar Robert Bradshaw

Allow multiple bases for cdef classes.

parent 6a5a9c05
...@@ -2874,8 +2874,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2874,8 +2874,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
else: else:
self.generate_base_type_import_code(env, entry, code) self.generate_base_type_import_code(env, entry, code)
self.generate_exttype_vtable_init_code(entry, code) self.generate_exttype_vtable_init_code(entry, code)
self.generate_type_ready_code(env, entry, code) if entry.type.early_init:
self.generate_typeptr_assignment_code(entry, code) self.generate_type_ready_code(entry, code)
def generate_base_type_import_code(self, env, entry, code): def generate_base_type_import_code(self, env, entry, code):
base_type = entry.type.base_type base_type = entry.type.base_type
...@@ -2949,7 +2949,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2949,7 +2949,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
not type.is_external or type.is_subclassed, not type.is_external or type.is_subclassed,
error_code)) error_code))
def generate_type_ready_code(self, env, entry, code): @staticmethod
def generate_type_ready_code(entry, code):
# Generate a call to PyType_Ready for an extension # Generate a call to PyType_Ready for an extension
# type defined in this module. # type defined in this module.
type = entry.type type = entry.type
...@@ -3041,6 +3042,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -3041,6 +3042,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln('if (__Pyx_setup_reduce((PyObject*)&%s) < 0) %s' % ( code.putln('if (__Pyx_setup_reduce((PyObject*)&%s) < 0) %s' % (
typeobj_cname, typeobj_cname,
code.error_goto(entry.pos))) code.error_goto(entry.pos)))
# Generate code to initialise the typeptr of an extension
# type defined in this module to point to its type object.
if type.typeobj_cname:
code.putln(
"%s = &%s;" % (
type.typeptr_cname, type.typeobj_cname))
def generate_exttype_vtable_init_code(self, entry, code): def generate_exttype_vtable_init_code(self, entry, code):
# Generate code to initialise the C method table of an # Generate code to initialise the C method table of an
...@@ -3071,15 +3078,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -3071,15 +3078,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
cast, cast,
meth_entry.func_cname)) meth_entry.func_cname))
def generate_typeptr_assignment_code(self, entry, code):
# Generate code to initialise the typeptr of an extension
# type defined in this module to point to its type object.
type = entry.type
if type.typeobj_cname:
code.putln(
"%s = &%s;" % (
type.typeptr_cname, type.typeobj_cname))
def generate_cfunction_declaration(entry, env, code, definition): def generate_cfunction_declaration(entry, env, code, definition):
from_cy_utility = entry.used and entry.utility_code_definition from_cy_utility = entry.used and entry.utility_code_definition
if entry.used and entry.inline_func_in_pxd or (not entry.in_cinclude and ( if entry.used and entry.inline_func_in_pxd or (not entry.in_cinclude and (
......
This diff is collapsed.
...@@ -3435,19 +3435,15 @@ def p_c_class_definition(s, pos, ctx): ...@@ -3435,19 +3435,15 @@ def p_c_class_definition(s, pos, ctx):
as_name = class_name as_name = class_name
objstruct_name = None objstruct_name = None
typeobj_name = None typeobj_name = None
base_class_module = None bases = None
base_class_name = None
if s.sy == '(': if s.sy == '(':
s.next() positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False)
base_class_path = [p_ident(s)] if keyword_args:
while s.sy == '.': s.error("C classes cannot take keyword bases.")
s.next() bases, _ = p_call_build_packed_args(pos, positional_args, keyword_args)
base_class_path.append(p_ident(s)) if bases is None:
if s.sy == ',': bases = ExprNodes.TupleNode(pos, args=[])
s.error("C class may only have one base class", fatal=False)
s.expect(')')
base_class_module = ".".join(base_class_path[:-1])
base_class_name = base_class_path[-1]
if s.sy == '[': if s.sy == '[':
if ctx.visibility not in ('public', 'extern') and not ctx.api: if ctx.visibility not in ('public', 'extern') and not ctx.api:
error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class") error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
...@@ -3487,8 +3483,7 @@ def p_c_class_definition(s, pos, ctx): ...@@ -3487,8 +3483,7 @@ def p_c_class_definition(s, pos, ctx):
module_name = ".".join(module_path), module_name = ".".join(module_path),
class_name = class_name, class_name = class_name,
as_name = as_name, as_name = as_name,
base_class_module = base_class_module, bases = bases,
base_class_name = base_class_name,
objstruct_name = objstruct_name, objstruct_name = objstruct_name,
typeobj_name = typeobj_name, typeobj_name = typeobj_name,
in_pxd = ctx.level == 'module_pxd', in_pxd = ctx.level == 'module_pxd',
......
...@@ -1302,10 +1302,12 @@ class PyExtensionType(PyObjectType): ...@@ -1302,10 +1302,12 @@ class PyExtensionType(PyObjectType):
# vtabstruct_cname string Name of C method table struct # vtabstruct_cname string Name of C method table struct
# vtabptr_cname string Name of pointer to C method table # vtabptr_cname string Name of pointer to C method table
# vtable_cname string Name of C method table definition # vtable_cname string Name of C method table definition
# early_init boolean Whether to initialize early (as opposed to during module execution).
# defered_declarations [thunk] Used to declare class hierarchies in order # defered_declarations [thunk] Used to declare class hierarchies in order
is_extension_type = 1 is_extension_type = 1
has_attributes = 1 has_attributes = 1
early_init = 1
objtypedef_cname = None objtypedef_cname = None
......
...@@ -10,5 +10,5 @@ cdef class SubType(FinalClass): ...@@ -10,5 +10,5 @@ cdef class SubType(FinalClass):
pass pass
_ERRORS = """ _ERRORS = """
9:5: Base class 'FinalClass' of type 'SubType' is final 9:19: Base class 'FinalClass' of type 'SubType' is final
""" """
cdef class CBase(object):
cdef int a
cdef c_method(self):
return "CBase"
cpdef cpdef_method(self):
return "CBase"
class PyBase(object):
def py_method(self):
return "PyBase"
cdef class Both(CBase, PyBase):
cdef dict __dict__
"""
>>> b = Both()
>>> b.py_method()
'PyBase'
>>> b.cp_method()
'Both'
>>> b.call_c_method()
'Both'
>>> isinstance(b, CBase)
True
>>> isinstance(b, PyBase)
True
"""
cdef c_method(self):
return "Both"
cpdef cp_method(self):
return "Both"
def call_c_method(self):
return self.c_method()
cdef class BothSub(Both):
"""
>>> b = BothSub()
>>> b.py_method()
'PyBase'
>>> b.cp_method()
'Both'
>>> b.call_c_method()
'Both'
"""
pass
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