self.temps_free[type] = freelist
freelist.append(name)
- self.pystring_table.putln("{0, 0, 0, 0, 0}").putln("};")
+class GlobalState(object):
+ # filename_table {string : int} for finding filename table indexes
+ # filename_list [string] filenames in filename table order
+ # input_file_contents dict contents (=list of lines) of any file that was used as input
+ # to create this output C code. This is
+ # used to annotate the comments.
+ #
+ # used_utility_code set(string|int) Ids of used utility code (to avoid reinsertion)
+ # utilprotowriter CCodeWriter
+ # utildefwriter CCodeWriter
+ #
+ # 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).
+ # In time, hopefully the literals etc. will be
+ # supplied directly instead.
+
+
+ # interned_strings
+ # consts
+ # py_string_decls
+ # interned_nums
+ # cached_builtins
+
+ def __init__(self, rootwriter):
+ self.filename_table = {}
+ self.filename_list = []
+ self.input_file_contents = {}
+ self.used_utility_code = set()
+ self.declared_cnames = {}
+ self.pystring_table_needed = False
+
+ def initwriters(self, rootwriter):
+ self.utilprotowriter = rootwriter.new_writer()
+ self.utildefwriter = rootwriter.new_writer()
+ self.decls_writer = rootwriter.new_writer()
+ self.pystring_table = rootwriter.new_writer()
+ self.initwriter = rootwriter.new_writer()
+
+ self.initwriter.enter_cfunc_scope()
+ self.initwriter.putln("").putln("static int __Pyx_InitGlobals(void) {")
+
+ (self.pystring_table
+ .putln("")
+ .putln("static __Pyx_StringTabEntry %s[] = {" %
+ Naming.stringtab_cname)
+ )
+
+ #
+ # Global constants, interned objects, etc.
+ #
+ def insert_global_var_declarations_into(self, code):
+ code.insert(self.decls_writer)
+
+ def close_global_decls(self):
+ # This is called when it is known that no more global declarations will
+ # declared (but can be called before or after insert_XXX).
+ if self.pystring_table_needed:
- self.initwriter.putln("%s = PyInt_FromLong(%s); %s;" % (
- entry.cname,
- entry.init,
- self.initwriter.error_goto_if_null(entry.cname, self.module_pos))) # todo: fix pos
++ self.pystring_table.putln("{0, 0, 0, 0, 0, 0}").putln("};")
+ import Nodes
+ self.use_utility_code(Nodes.init_string_tab_utility_code)
+ self.initwriter.putln(
+ "if (__Pyx_InitStrings(%s) < 0) %s;" % (
+ Naming.stringtab_cname,
+ self.initwriter.error_goto(self.module_pos)))
+
+ (self.initwriter
+ .putln("return 0;")
+ .put_label(self.initwriter.error_label)
+ .putln("return -1;")
+ .putln("}")
+ )
+ self.initwriter.exit_cfunc_scope()
+
+ def insert_py_string_table_into(self, code):
+ if self.pystring_table_needed:
+ code.insert(self.pystring_table)
+
+ def insert_initglobals_into(self, code):
+ code.insert(self.initwriter)
+
+ def put_pyobject_decl(self, entry):
+ self.decls_writer.putln("static PyObject *%s;" % entry.cname)
+
+ # The functions below are there in a transition phase only
+ # and will be deprecated. They are called from Nodes.BlockNode.
+ # The copy&paste duplication is intentional in order to be able
+ # to see quickly how BlockNode worked, until this is replaced.
+
+ def should_declare(self, cname, entry):
+ if cname in self.declared_cnames:
+ other = self.declared_cnames[cname]
+ assert entry.type == other.type
+ assert entry.init == other.init
+ return False
+ else:
+ self.declared_cnames[cname] = entry
+ return True
+
+ def add_const_definition(self, entry):
+ if self.should_declare(entry.cname, entry):
+ self.decls_writer.put_var_declaration(entry, static = 1)
+
+ def add_interned_string_decl(self, entry):
+ if self.should_declare(entry.cname, entry):
+ self.decls_writer.put_var_declaration(entry, static = 1)
+ self.add_py_string_decl(entry)
+
+ def add_py_string_decl(self, entry):
+ if self.should_declare(entry.pystring_cname, entry):
+ self.decls_writer.putln("static PyObject *%s;" % entry.pystring_cname)
+ self.pystring_table_needed = True
+ self.pystring_table.putln("{&%s, %s, sizeof(%s), %d, %d, %d}," % (
+ entry.pystring_cname,
+ entry.cname,
+ entry.cname,
+ entry.type.is_unicode,
+ entry.is_interned,
+ entry.is_identifier
+ ))
+
+ def add_interned_num_decl(self, entry):
+ if self.should_declare(entry.cname, entry):
-
++ if entry.init[-1] == "L":
++ self.initwriter.putln('%s = PyLong_FromString("%s", 0, 0); %s;' % (
++ entry.cname,
++ entry.init,
++ self.initwriter.error_goto_if_null(entry.cname, self.module_pos)))
++ else:
++ self.initwriter.putln("%s = PyInt_FromLong(%s); %s;" % (
++ entry.cname,
++ entry.init,
++ self.initwriter.error_goto_if_null(entry.cname, self.module_pos)))
++
+ self.put_pyobject_decl(entry)
+
+ def add_cached_builtin_decl(self, entry):
+ if self.should_declare(entry.cname, entry):
+ self.put_pyobject_decl(entry)
+
+ #
+ # File name state
+ #
+
+ def lookup_filename(self, filename):
+ try:
+ index = self.filename_table[filename]
+ except KeyError:
+ index = len(self.filename_list)
+ self.filename_list.append(filename)
+ self.filename_table[filename] = index
+ return index
+
+ def commented_file_contents(self, source_desc):
+ try:
+ return self.input_file_contents[source_desc]
+ except KeyError:
+ F = [u' * ' + line.rstrip().replace(
+ u'*/', u'*[inserted by cython to avoid comment closer]/'
+ ).encode('ASCII', 'replace') # + Py2 auto-decode to unicode
+ for line in source_desc.get_lines()]
+ if len(F) == 0: F.append(u'')
+ self.input_file_contents[source_desc] = F
+ return F
+
+ #
+ # Utility code state
+ #
+
+ def use_utility_code(self, codetup, name=None):
+ """
+ Adds the given utility code to the C file if needed.
+
+ codetup should unpack into one prototype code part and one
+ definition code part, both strings inserted directly in C.
+
+ If name is provided, it is used as an identifier to avoid inserting
+ code twice. Otherwise, id(codetup) is used as such an identifier.
+ """
+ if name is None: name = id(codetup)
+ if self.check_utility_code_needed_and_register(name):
+ proto, _def = codetup
+ self.utilprotowriter.put(proto)
+ self.utildefwriter.put(_def)
+
+ def has_utility_code(self, name):
+ return name in self.used_utility_code
+
+ def use_generated_code(self, func, name, *args, **kw):
+ """
+ Requests that the utility code that func can generate is used in the C
+ file. func is called like this:
+
+ func(proto, definition, name, *args, **kw)
+
+ where proto and definition are two CCodeWriter instances; the
+ former should have the prototype written to it and the other the definition.
+
+ The call might happen at some later point (if compiling multiple modules
+ into a cache for instance), and will only happen once per utility code.
+
+ name is used to identify the utility code, so that it isn't regenerated
+ when the same code is requested again.
+ """
+ if self.check_utility_code_needed_and_register(name):
+ func(self.utilprotowriter, self.utildefwriter,
+ name, *args, **kw)
+
+ def check_utility_code_needed_and_register(self, name):
+ if name in self.used_utility_code:
+ return False
+ else:
+ self.used_utility_code.add(name)
+ return True
+
+ def put_utility_code_protos(self, writer):
+ writer.insert(self.utilprotowriter)
+
+ def put_utility_code_defs(self, writer):
+ writer.insert(self.utildefwriter)
+
+
def funccontext_property(name):
def get(self):
- return getattr(self.func, name)
+ return getattr(self.funcstate, name)
def set(self, value):
- setattr(self.func, name, value)
+ setattr(self.funcstate, name, value)
return property(get, set)
class CCodeWriter(object):