Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
3e76b40f
Commit
3e76b40f
authored
Jun 22, 2011
by
Robert Bradshaw
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Obviate the need for forward-declaring structs/unions/enums/cdef classes.
parent
6aa0d3cf
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
187 additions
and
79 deletions
+187
-79
Cython/Compiler/Main.py
Cython/Compiler/Main.py
+3
-1
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+37
-21
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+54
-32
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+38
-0
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+14
-11
tests/compile/forward.pyx
tests/compile/forward.pyx
+41
-0
tests/errors/e_ctypedefforward.pyx
tests/errors/e_ctypedefforward.pyx
+0
-14
No files found.
Cython/Compiler/Main.py
View file @
3e76b40f
...
...
@@ -103,7 +103,8 @@ class Context(object):
def
create_pipeline
(
self
,
pxd
,
py
=
False
):
from
Visitor
import
PrintTree
from
ParseTreeTransforms
import
WithTransform
,
NormalizeTree
,
PostParse
,
PxdPostParse
from
ParseTreeTransforms
import
AnalyseDeclarationsTransform
,
AnalyseExpressionsTransform
from
ParseTreeTransforms
import
ForwardDeclareTypes
,
AnalyseDeclarationsTransform
from
ParseTreeTransforms
import
AnalyseExpressionsTransform
from
ParseTreeTransforms
import
CreateClosureClasses
,
MarkClosureVisitor
,
DecoratorTransform
from
ParseTreeTransforms
import
InterpretCompilerDirectives
,
TransformBuiltinMethods
from
ParseTreeTransforms
import
ExpandInplaceOperators
,
ParallelRangeTransform
...
...
@@ -146,6 +147,7 @@ class Context(object):
FlattenInListTransform
(),
WithTransform
(
self
),
DecoratorTransform
(
self
),
ForwardDeclareTypes
(
self
),
AnalyseDeclarationsTransform
(
self
),
AutoTestDictTransform
(
self
),
EmbedSignature
(
self
),
...
...
Cython/Compiler/ModuleNode.py
View file @
3e76b40f
...
...
@@ -427,20 +427,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for
entry
in
module
.
type_entries
:
if
entry
.
defined_in_pxd
:
type_entries
.
append
(
entry
)
for
entry
in
type_entries
:
if
not
entry
.
in_cinclude
:
#print "generate_type_header_code:", entry.name, repr(entry.type) ###
type
=
entry
.
type
if
type
.
is_typedef
:
# Must test this first!
self
.
generate_typedef
(
entry
,
code
)
elif
type
.
is_struct_or_union
:
self
.
generate_struct_union_definition
(
entry
,
code
)
elif
type
.
is_enum
:
self
.
generate_enum_definition
(
entry
,
code
)
elif
type
.
is_extension_type
and
entry
not
in
vtabslot_entries
:
self
.
generate_objstruct_definition
(
type
,
code
)
self
.
generate_type_header_code
(
type_entries
,
code
)
for
entry
in
vtabslot_list
:
self
.
generate_objstruct_definition
(
entry
.
type
,
code
)
#
self.generate_objstruct_definition(entry.type, code)
self
.
generate_typeobj_predeclaration
(
entry
,
code
)
for
entry
in
vtab_list
:
self
.
generate_typeobj_predeclaration
(
entry
,
code
)
...
...
@@ -782,17 +771,28 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def
generate_type_header_code
(
self
,
type_entries
,
code
):
# Generate definitions of structs/unions/enums/typedefs/objstructs.
#self.generate_gcc33_hack(env, code) # Is this still needed?
#
for entry in env.type_entries:
#
Forward declarations
for
entry
in
type_entries
:
if
not
entry
.
in_cinclude
:
#print "generate_type_header_code:", entry.name, repr(entry.type) ###
type
=
entry
.
type
if
type
.
is_typedef
:
# Must test this first!
self
.
generate_typedef
(
entry
,
code
)
pass
elif
type
.
is_struct_or_union
:
self
.
generate_struct_union_definition
(
entry
,
code
)
self
.
generate_struct_union_predeclaration
(
entry
,
code
)
elif
type
.
is_extension_type
:
self
.
generate_objstruct_predeclaration
(
type
,
code
)
# Actual declarations
for
entry
in
type_entries
:
if
not
entry
.
in_cinclude
:
#print "generate_type_header_code:", entry.name, repr(entry.type) ###
type
=
entry
.
type
if
type
.
is_typedef
:
# Must test this first!
self
.
generate_typedef
(
entry
,
code
)
elif
type
.
is_enum
:
self
.
generate_enum_definition
(
entry
,
code
)
elif
type
.
is_struct_or_union
:
self
.
generate_struct_union_definition
(
entry
,
code
)
elif
type
.
is_extension_type
:
self
.
generate_objstruct_definition
(
type
,
code
)
...
...
@@ -822,11 +822,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
writer
.
mark_pos
(
entry
.
pos
)
writer
.
putln
(
"typedef %s;"
%
base_type
.
declaration_code
(
entry
.
cname
))
def
sue_
header_footer
(
self
,
type
,
kind
,
name
):
def
sue_
predeclaration
(
self
,
type
,
kind
,
name
):
if
type
.
typedef_flag
:
header
=
"typedef %s {"
%
kind
footer
=
"} %s;"
%
name
return
"%s %s;
\
n
typedef %s %s %s;"
%
(
kind
,
name
,
kind
,
name
,
name
)
else
:
return
"%s %s;"
%
(
kind
,
name
)
def
generate_struct_union_predeclaration
(
self
,
entry
,
code
):
type
=
entry
.
type
code
.
putln
(
self
.
sue_predeclaration
(
type
,
type
.
kind
,
type
.
cname
))
def
sue_header_footer
(
self
,
type
,
kind
,
name
):
header
=
"%s %s {"
%
(
kind
,
name
)
footer
=
"};"
return
header
,
footer
...
...
@@ -897,6 +905,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
value_code
+=
","
code
.
putln
(
value_code
)
code
.
putln
(
footer
)
if
entry
.
type
.
typedef_flag
:
# Not pre-declared.
code
.
putln
(
"typedef enum %s %s;"
%
(
name
,
name
))
def
generate_typeobj_predeclaration
(
self
,
entry
,
code
):
code
.
putln
(
""
)
...
...
@@ -946,6 +957,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
type
.
vtabstruct_cname
,
type
.
vtabptr_cname
))
def
generate_objstruct_predeclaration
(
self
,
type
,
code
):
if
not
type
.
scope
:
return
code
.
putln
(
self
.
sue_predeclaration
(
type
,
"struct"
,
type
.
objstruct_cname
))
def
generate_objstruct_definition
(
self
,
type
,
code
):
code
.
mark_pos
(
type
.
pos
)
# Generate object struct definition for an
...
...
Cython/Compiler/Nodes.py
View file @
3e76b40f
...
...
@@ -980,44 +980,31 @@ class CStructOrUnionDefNode(StatNode):
child_attrs
=
[
"attributes"
]
def
analyse_declarations
(
self
,
env
):
scope
=
None
if
self
.
visibility
==
'extern'
and
self
.
packed
:
def
declare
(
self
,
env
,
scope
=
None
):
if
self
.
visibility
==
'extern'
and
self
.
packed
and
not
scope
:
error
(
self
.
pos
,
"Cannot declare extern struct as 'packed'"
)
if
self
.
attributes
is
not
None
:
scope
=
StructOrUnionScope
(
self
.
name
)
self
.
entry
=
env
.
declare_struct_or_union
(
self
.
name
,
self
.
kind
,
scope
,
self
.
typedef_flag
,
self
.
pos
,
self
.
cname
,
visibility
=
self
.
visibility
,
api
=
self
.
api
,
packed
=
self
.
packed
)
def
analyse_declarations
(
self
,
env
):
scope
=
None
if
self
.
attributes
is
not
None
:
scope
=
StructOrUnionScope
(
self
.
name
)
self
.
declare
(
env
,
scope
)
if
self
.
attributes
is
not
None
:
if
self
.
in_pxd
and
not
env
.
in_cinclude
:
self
.
entry
.
defined_in_pxd
=
1
for
attr
in
self
.
attributes
:
attr
.
analyse_declarations
(
env
,
scope
)
if
self
.
visibility
!=
'extern'
:
need_typedef_indirection
=
False
for
attr
in
scope
.
var_entries
:
type
=
attr
.
type
while
type
.
is_array
:
type
=
type
.
base_type
if
type
==
self
.
entry
.
type
:
error
(
attr
.
pos
,
"Struct cannot contain itself as a member."
)
if
self
.
typedef_flag
:
while
type
.
is_ptr
:
type
=
type
.
base_type
if
type
==
self
.
entry
.
type
:
need_typedef_indirection
=
True
if
need_typedef_indirection
:
# C can't handle typedef structs that refer to themselves.
struct_entry
=
self
.
entry
self
.
entry
=
env
.
declare_typedef
(
self
.
name
,
struct_entry
.
type
,
self
.
pos
,
cname
=
self
.
cname
,
visibility
=
'ignore'
)
struct_entry
.
type
.
typedef_flag
=
False
# FIXME: this might be considered a hack ;-)
struct_entry
.
cname
=
struct_entry
.
type
.
cname
=
\
'_'
+
self
.
entry
.
type
.
typedef_cname
def
analyse_expressions
(
self
,
env
):
pass
...
...
@@ -1037,6 +1024,15 @@ class CppClassNode(CStructOrUnionDefNode):
# base_classes [string]
# templates [string] or None
def
declare
(
self
,
env
):
if
self
.
templates
is
None
:
template_types
=
None
else
:
template_types
=
[
PyrexTypes
.
TemplatePlaceholderType
(
template_name
)
for
template_name
in
self
.
templates
]
self
.
entry
=
env
.
declare_cpp_class
(
self
.
name
,
None
,
self
.
pos
,
self
.
cname
,
base_classes
=
[],
visibility
=
self
.
visibility
,
templates
=
template_types
)
def
analyse_declarations
(
self
,
env
):
scope
=
None
if
self
.
attributes
is
not
None
:
...
...
@@ -1078,10 +1074,12 @@ class CEnumDefNode(StatNode):
child_attrs
=
[
"items"
]
def
analyse_declarations
(
self
,
env
):
def
declare
(
self
,
env
):
self
.
entry
=
env
.
declare_enum
(
self
.
name
,
self
.
pos
,
cname
=
self
.
cname
,
typedef_flag
=
self
.
typedef_flag
,
visibility
=
self
.
visibility
,
api
=
self
.
api
)
def
analyse_declarations
(
self
,
env
):
if
self
.
items
is
not
None
:
if
self
.
in_pxd
and
not
env
.
in_cinclude
:
self
.
entry
.
defined_in_pxd
=
1
...
...
@@ -3352,18 +3350,42 @@ class CClassDefNode(ClassDefNode):
decorators
=
None
shadow
=
False
def
analyse_declarations
(
self
,
env
):
#print "CClassDefNode.analyse_declarations:", self.class_name
#print "...visibility =", self.visibility
#print "...module_name =", self.module_name
def
declare
(
self
,
env
):
if
self
.
module_name
and
self
.
visibility
!=
'extern'
:
module_path
=
self
.
module_name
.
split
(
"."
)
home_scope
=
env
.
find_imported_module
(
module_path
,
self
.
pos
)
if
not
home_scope
:
return
None
else
:
home_scope
=
env
import
Buffer
if
self
.
buffer_defaults_node
:
buffer_defaults
=
Buffer
.
analyse_buffer_options
(
self
.
buffer_defaults_pos
,
self
.
buffer_defaults
=
Buffer
.
analyse_buffer_options
(
self
.
buffer_defaults_pos
,
env
,
[],
self
.
buffer_defaults_node
,
need_complete
=
False
)
else
:
buffer_defaults
=
None
self
.
buffer_defaults
=
None
self
.
entry
=
home_scope
.
declare_c_class
(
name
=
self
.
class_name
,
pos
=
self
.
pos
,
defining
=
0
,
implementing
=
0
,
module_name
=
self
.
module_name
,
base_type
=
None
,
objstruct_cname
=
self
.
objstruct_name
,
typeobj_cname
=
self
.
typeobj_name
,
visibility
=
self
.
visibility
,
typedef_flag
=
self
.
typedef_flag
,
api
=
self
.
api
,
buffer_defaults
=
self
.
buffer_defaults
,
shadow
=
self
.
shadow
)
def
analyse_declarations
(
self
,
env
):
#print "CClassDefNode.analyse_declarations:", self.class_name
#print "...visibility =", self.visibility
#print "...module_name =", self.module_name
if
env
.
in_cinclude
and
not
self
.
objstruct_name
:
error
(
self
.
pos
,
"Object struct name specification required for "
...
...
@@ -3441,7 +3463,7 @@ class CClassDefNode(ClassDefNode):
visibility
=
self
.
visibility
,
typedef_flag
=
self
.
typedef_flag
,
api
=
self
.
api
,
buffer_defaults
=
buffer_defaults
,
buffer_defaults
=
self
.
buffer_defaults
,
shadow
=
self
.
shadow
)
if
self
.
shadow
:
home_scope
.
lookup
(
self
.
class_name
).
as_variable
=
self
.
entry
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
3e76b40f
...
...
@@ -1264,6 +1264,44 @@ class DecoratorTransform(CythonTransform, SkipDeclarations):
return
[
node
,
reassignment
]
class
ForwardDeclareTypes
(
CythonTransform
):
def
visit_CompilerDirectivesNode
(
self
,
node
):
env
=
self
.
module_scope
old
=
env
.
directives
env
.
directives
=
node
.
directives
self
.
visitchildren
(
node
)
env
.
directives
=
old
return
node
def
visit_ModuleNode
(
self
,
node
):
self
.
module_scope
=
node
.
scope
self
.
module_scope
.
directives
=
node
.
directives
self
.
visitchildren
(
node
)
return
node
def
visit_CDefExternNode
(
self
,
node
):
old_cinclude_flag
=
self
.
module_scope
.
in_cinclude
self
.
module_scope
.
in_cinclude
=
1
self
.
visitchildren
(
node
)
self
.
module_scope
.
in_cinclude
=
old_cinclude_flag
return
node
def
visit_CEnumDefNode
(
self
,
node
):
node
.
declare
(
self
.
module_scope
)
return
node
def
visit_CStructOrUnionDefNode
(
self
,
node
):
if
node
.
name
not
in
self
.
module_scope
.
entries
:
node
.
declare
(
self
.
module_scope
)
return
node
def
visit_CClassDefNode
(
self
,
node
):
if
node
.
class_name
not
in
self
.
module_scope
.
entries
:
node
.
declare
(
self
.
module_scope
)
return
node
class
AnalyseDeclarationsTransform
(
CythonTransform
):
basic_property
=
TreeFragment
(
u"""
...
...
Cython/Compiler/Symtab.py
View file @
3e76b40f
...
...
@@ -426,8 +426,6 @@ class Scope(object):
if scope:
entry.type.scope = scope
self.type_entries.append(entry)
if not scope and not entry.type.scope:
self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
return entry
def declare_cpp_class(self, name, scope,
...
...
@@ -453,13 +451,24 @@ class Scope(object):
if scope:
entry.type.scope = scope
self.type_entries.append(entry)
if templates is not None:
if base_classes:
if entry.type.base_classes and not entry.type.base_classes == base_classes:
error(pos, "
Base
type
does
not
match
previous
declaration
")
else:
entry.type.base_classes = base_classes
if templates or entry.type.templates:
if templates != entry.type.templates:
error(pos, "
Template
parameters
do
not
match
previous
declaration
")
if templates is not None and entry.type.scope is not None:
for T in templates:
template_entry = entry.type.scope.declare(T.name, T.name, T, None, 'extern')
template_entry.is_type = 1
def declare_inherited_attributes(entry, base_classes):
for base_class in base_classes:
if base_class.scope is None:
error(pos, "
Cannot
inherit
from
incomplete
type
")
else:
declare_inherited_attributes(entry, base_class.base_classes)
entry.type.scope.declare_inherited_cpp_attributes(base_class.scope)
if entry.type.scope:
...
...
@@ -1171,8 +1180,6 @@ class ModuleScope(Scope):
scope.declare_inherited_c_attributes(base_type.scope)
type.set_scope(scope)
self.type_entries.append(entry)
else:
self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
else:
if defining and type.scope.defined:
error(pos, "
C
class
'%
s
' already defined" % name)
...
...
@@ -1203,10 +1210,6 @@ class ModuleScope(Scope):
#
return entry
def check_for_illegal_incomplete_ctypedef(self, typedef_flag, pos):
if typedef_flag and not self.in_cinclude:
error(pos, "Forward-referenced type must use '
cdef
', not '
ctypedef
'")
def allocate_vtable_names(self, entry):
# If extension type has a vtable, allocate vtable struct and
# slot names for it.
...
...
tests/compile/forward.pyx
0 → 100644
View file @
3e76b40f
# mode: compile
ctypedef
enum
MyEnum
:
Value1
Value2
Value3
=
100
cdef
MyEnum
my_enum
=
Value3
ctypedef
struct
StructA
:
StructA
*
a
StructB
*
b
cdef
struct
StructB
:
StructA
*
a
StructB
*
b
cdef
class
ClassA
:
cdef
ClassB
b
ctypedef
public
class
ClassB
[
object
ClassB
,
type
TypeB
]:
cdef
ClassA
a
cdef
StructA
struct_a
cdef
StructB
struct_b
struct_a
.
a
=
&
struct_a
struct_a
.
b
=
&
struct_b
struct_b
.
a
=
&
struct_a
struct_b
.
b
=
&
struct_b
cdef
ClassA
class_a
=
ClassA
()
cdef
ClassB
class_b
=
ClassB
()
class_a
.
a
=
class_a
class_a
.
b
=
class_b
class_b
.
a
=
class_a
class_b
.
b
=
class_b
tests/errors/e_ctypedefforward.pyx
deleted
100644 → 0
View file @
6aa0d3cf
# mode: error
ctypedef
struct
Spam
cdef
extern
from
*
:
ctypedef
struct
Ham
ctypedef
struct
Spam
:
int
i
ctypedef
struct
Spam
_ERRORS
=
u"""
3:0: Forward-referenced type must use 'cdef', not 'ctypedef'
"""
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment