summaryrefslogtreecommitdiff
path: root/Cython/Compiler/Code.py
diff options
context:
space:
mode:
Diffstat (limited to 'Cython/Compiler/Code.py')
-rw-r--r--Cython/Compiler/Code.py91
1 files changed, 64 insertions, 27 deletions
diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py
index 845dbe548..935990ca8 100644
--- a/Cython/Compiler/Code.py
+++ b/Cython/Compiler/Code.py
@@ -21,8 +21,6 @@ class UtilityCode(object):
# Stores utility code to add during code generation.
#
# See GlobalState.put_utility_code.
- #
- # hashes/equals by instance
def __init__(self, proto=None, impl=None, init=None, cleanup=None, requires=None,
proto_block='utility_code_proto'):
@@ -62,9 +60,6 @@ class UtilityCode(object):
return s
def put_code(self, output):
- if self.requires:
- for dependency in self.requires:
- output.use_utility_code(dependency)
if self.proto:
output[self.proto_block].put(self.proto)
if self.impl:
@@ -384,8 +379,6 @@ class GlobalState(object):
# to create this output C code. This is
# used to annotate the comments.
#
- # utility_codes set IDs of used utility code (to avoid reinsertion)
- #
# declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
# constants etc. into the pyx-declared ones (i.e,
# check if constants are already added).
@@ -394,6 +387,8 @@ class GlobalState(object):
#
# const_cname_counter int global counter for constant identifiers
#
+ # processed_objects set() objects which has had their C code generated
+ # process_object_stack [object] (internal use)
# parts {string:CCodeWriter}
@@ -434,11 +429,13 @@ class GlobalState(object):
]
- def __init__(self, writer, module_node, emit_linenums=False):
+ def __init__(self, writer, module_node, emit_linenums=False,
+ header_mode=False):
self.filename_table = {}
self.filename_list = []
self.input_file_contents = {}
- self.utility_codes = set()
+ self.process_objects_stack = []
+ self.processed_objects = set()
self.declared_cnames = {}
self.in_utility_code_generation = False
self.emit_linenums = emit_linenums
@@ -454,11 +451,14 @@ class GlobalState(object):
assert writer.globalstate is None
writer.globalstate = self
self.rootwriter = writer
+ self.header_mode = header_mode
+ if header_mode:
+ self.parts = {'header' : writer }
def initialize_main_c_code(self):
rootwriter = self.rootwriter
for part in self.code_layout:
- self.parts[part] = rootwriter.insertion_point()
+ self.parts[part] = rootwriter.insertion_point(part)
if not Options.cache_builtins:
del self.parts['cached_builtins']
@@ -777,21 +777,38 @@ class GlobalState(object):
return F
#
- # Utility code state
+ # Stuff about asking objects to output themselves to C
+ # Utility code handled here.
#
-
- def use_utility_code(self, utility_code):
+ def put_object(self, obj):
"""
- Adds code to the C file. utility_code should
- a) implement __eq__/__hash__ for the purpose of knowing whether the same
- code has already been included
- b) implement put_code, which takes a globalstate instance
-
- See UtilityCode.
+ Write the C code associated with the given object (such as a type definition,
+ some utility code, etc.). The object:
+ - Must have a "requires" attribute (list of other objects which
+ must be output first)
+ - Must have an __eq__/__hash__, used to determine whether the same
+ object has already been output
+ - Must have a method put_code(self, output), which is called to output
+ the object to C. Output should be indexed with the required part, e.g.
+ writer = output['utility_code_proto']
+
+ There's no guarantee on when put_code will be called, but currently it
+ happens right away (but only once per object).
"""
- if utility_code not in self.utility_codes:
- self.utility_codes.add(utility_code)
- utility_code.put_code(self)
+ if obj in self.processed_objects:
+ return
+ if obj in self.process_objects_stack:
+ raise AssertionError("Object dependency graph is not a DAG, found a loop")
+ self.process_objects_stack.append(obj)
+ if obj.requires is not None and obj.requires:
+ for req in obj.requires:
+ self.put_object(req)
+ self.process_objects_stack.pop()
+ self.processed_objects.add(obj)
+ obj.put_code(self)
+
+ def use_utility_code(self, utility_code):
+ self.put_object(utility_code)
def funccontext_property(name):
@@ -843,7 +860,11 @@ class CCodeWriter(object):
globalstate = None
- def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None):
+ def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None,
+ description=None):
+ if description is None:
+ description = '<not specified>'
+ self.description = description
if buffer is None: buffer = StringIOTree()
self.buffer = buffer
self.marker = None
@@ -869,10 +890,13 @@ class CCodeWriter(object):
else:
self.emit_linenums = emit_linenums
- def create_new(self, create_from, buffer, copy_formatting):
+ def __repr__(self):
+ return '%s@%s' % (object.__repr__(self), self.description)
+
+ def create_new(self, create_from, buffer, copy_formatting, description='(some create_new)'):
# polymorphic constructor -- very slightly more versatile
# than using __class__
- result = CCodeWriter(create_from, buffer, copy_formatting)
+ result = CCodeWriter(create_from, buffer, copy_formatting, description=description)
return result
def copyto(self, f):
@@ -884,8 +908,9 @@ class CCodeWriter(object):
def write(self, s):
self.buffer.write(s)
- def insertion_point(self):
- other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
+ def insertion_point(self, description='(some insertion point)'):
+ other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(),
+ copy_formatting=True, description=description)
return other
def new_writer(self):
@@ -1331,3 +1356,15 @@ class PyrexCodeWriter(object):
def dedent(self):
self.level -= 1
+
+#
+# C writing utility functions
+#
+def sue_header_footer(type, kind, name):
+ if type.typedef_flag:
+ header = "typedef %s {" % kind
+ footer = "} %s;" % name
+ else:
+ header = "%s %s {" % (kind, name)
+ footer = "};"
+ return header, footer