Skip to content

Commit

Permalink
A gentle start on #469
Browse files Browse the repository at this point in the history
  • Loading branch information
Dag Sverre Seljebotn committed Feb 3, 2010
1 parent d8018d4 commit 97c5856
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 87 deletions.
8 changes: 4 additions & 4 deletions Cython/Compiler/Annotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

class AnnotationCCodeWriter(CCodeWriter):

def __init__(self, create_from=None, buffer=None, copy_formatting=True):
CCodeWriter.__init__(self, create_from, buffer, copy_formatting=True)
def __init__(self, create_from=None, buffer=None, copy_formatting=True, description=None):
CCodeWriter.__init__(self, create_from, buffer, copy_formatting=True, description=description)
if create_from is None:
self.annotation_buffer = StringIO()
self.annotations = []
Expand All @@ -33,8 +33,8 @@ def __init__(self, create_from=None, buffer=None, copy_formatting=True):
self.code = create_from.code
self.last_pos = create_from.last_pos

def create_new(self, create_from, buffer, copy_formatting):
return AnnotationCCodeWriter(create_from, buffer, copy_formatting)
def create_new(self, create_from, buffer, copy_formatting, description=None):
return AnnotationCCodeWriter(create_from, buffer, copy_formatting, description=description)

def write(self, s):
CCodeWriter.write(self, s)
Expand Down
8 changes: 4 additions & 4 deletions Cython/Compiler/Buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,8 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos,
params.append(s)

# Make sure the utility code is available
if funcname not in code.globalstate.utility_codes:
code.globalstate.utility_codes.add(funcname)
if funcname not in code.globalstate.processed_objects:
code.globalstate.processed_objects.add(funcname)
protocode = code.globalstate['utility_code_proto']
defcode = code.globalstate['utility_code_def']
funcgen(protocode, defcode, name=funcname, nd=nd)
Expand Down Expand Up @@ -665,8 +665,8 @@ def get_type_information_cname(code, dtype, maxdepth=None):
if maxdepth <= 0:
assert False

if name not in code.globalstate.utility_codes:
code.globalstate.utility_codes.add(name)
if name not in code.globalstate.processed_objects:
code.globalstate.processed_objects.add(name)
typecode = code.globalstate['typeinfo']

complex_possible = dtype.is_struct_or_union and dtype.can_be_complex()
Expand Down
91 changes: 64 additions & 27 deletions Cython/Compiler/Code.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'):
Expand Down Expand Up @@ -62,9 +60,6 @@ def specialize(self, pyrex_type=None, **data):
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:
Expand Down Expand Up @@ -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).
Expand All @@ -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}

Expand Down Expand Up @@ -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
Expand All @@ -454,11 +451,14 @@ def __init__(self, writer, module_node, emit_linenums=False):
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']
Expand Down Expand Up @@ -777,21 +777,38 @@ def commented_file_contents(self, source_desc):
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):
Expand Down Expand Up @@ -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
Expand All @@ -869,10 +890,13 @@ def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_li
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):
Expand All @@ -884,8 +908,9 @@ def getvalue(self):
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):
Expand Down Expand Up @@ -1331,3 +1356,15 @@ def indent(self):
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
58 changes: 6 additions & 52 deletions Cython/Compiler/ModuleNode.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def h_entries(entries, pxd = 0):
if h_types or h_vars or h_funcs or h_extension_types:
result.h_file = replace_suffix(result.c_file, ".h")
h_code = Code.CCodeWriter()
Code.GlobalState(h_code, self)
Code.GlobalState(h_code, self, header_mode=True)
if options.generate_pxi:
result.i_file = replace_suffix(result.c_file, ".pxi")
i_code = Code.PyrexCodeWriter(result.i_file)
Expand Down Expand Up @@ -408,10 +408,8 @@ def generate_type_definitions(self, env, modules, vtab_list, vtabslot_list, code
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_obj_struct_definition(type, code)
for entry in vtabslot_list:
self.generate_obj_struct_definition(entry.type, code)
elif type.is_extension_type:# and entry not in vtabslot_entries:
code.globalstate.put_object(type)
for entry in vtab_list:
self.generate_typeobject_predeclaration(entry, code)
self.generate_exttype_vtable_struct(entry, code)
Expand Down Expand Up @@ -660,7 +658,6 @@ def generate_type_header_code(self, type_entries, code):
#for entry in env.type_entries:
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)
Expand All @@ -669,7 +666,7 @@ def generate_type_header_code(self, type_entries, code):
elif type.is_enum:
self.generate_enum_definition(entry, code)
elif type.is_extension_type:
self.generate_obj_struct_definition(type, code)
code.globalstate.put_object(type)

def generate_gcc33_hack(self, env, code):
# Workaround for spurious warning generation in gcc 3.3
Expand All @@ -694,15 +691,6 @@ def generate_typedef(self, entry, code):
writer.putln("")
writer.putln("typedef %s;" % base_type.declaration_code(entry.cname))

def sue_header_footer(self, type, kind, name):
if type.typedef_flag:
header = "typedef %s {" % kind
footer = "} %s;" % name
else:
header = "%s %s {" % (kind, name)
footer = "};"
return header, footer

def generate_struct_union_definition(self, entry, code):
code.mark_pos(entry.pos)
type = entry.type
Expand All @@ -714,7 +702,7 @@ def generate_struct_union_definition(self, entry, code):
kind = "%s %s" % (type.kind, "__Pyx_PACKED")
code.globalstate.use_utility_code(packed_struct_utility_code)
header, footer = \
self.sue_header_footer(type, kind, type.cname)
Code.sue_header_footer(type, kind, type.cname)
code.putln("")
if packed:
code.putln("#if !defined(__GNUC__)")
Expand All @@ -741,7 +729,7 @@ def generate_enum_definition(self, entry, code):
type = entry.type
name = entry.cname or entry.name or ""
header, footer = \
self.sue_header_footer(type, "enum", name)
Code.sue_header_footer(type, "enum", name)
code.putln("")
code.putln(header)
enum_values = entry.enum_values
Expand Down Expand Up @@ -814,40 +802,6 @@ def generate_exttype_vtabptr_declaration(self, entry, code):
code.putln("static struct %s *%s;" % (
type.vtabstruct_cname,
type.vtabptr_cname))

def generate_obj_struct_definition(self, type, code):
code.mark_pos(type.pos)
# Generate object struct definition for an
# extension type.
if not type.scope:
return # Forward declared but never defined
header, footer = \
self.sue_header_footer(type, "struct", type.objstruct_cname)
code.putln("")
code.putln(header)
base_type = type.base_type
if base_type:
code.putln(
"%s%s %s;" % (
("struct ", "")[base_type.typedef_flag],
base_type.objstruct_cname,
Naming.obj_base_cname))
else:
code.putln(
"PyObject_HEAD")
if type.vtabslot_cname and not (type.base_type and type.base_type.vtabslot_cname):
code.putln(
"struct %s *%s;" % (
type.vtabstruct_cname,
type.vtabslot_cname))
for attr in type.scope.var_entries:
code.putln(
"%s;" %
attr.type.declaration_code(attr.cname))
code.putln(footer)
if type.objtypedef_cname is not None:
# Only for exposing public typedef name.
code.putln("typedef struct %s %s;" % (type.objstruct_cname, type.objtypedef_cname))

def generate_global_declarations(self, env, code, definition):
code.putln("")
Expand Down
Loading

0 comments on commit 97c5856

Please sign in to comment.