import codecs
import Naming
import Options
-from Cython.Utils import open_new_file, open_source_file
+import StringEncoding
+from Cython import Utils
from PyrexTypes import py_object_type, typecast
+ import PyrexTypes
from TypeSlots import method_coexist
from Scanning import SourceDescriptor
from Cython.StringIOTree import StringIOTree
# check if constants are already added).
# In time, hopefully the literals etc. will be
# supplied directly instead.
+ #
+ # const_cname_counter int global counter for constant identifiers
+ #
+ # parts {string:CCodeWriter}
+
# interned_strings
# consts
directives = {}
- def __init__(self, rootwriter, emit_linenums=False):
+ code_layout = [
+ 'h_code',
+ 'utility_code_proto',
+ 'type_declarations',
+ 'module_declarations',
+ 'typeinfo',
+ 'before_global_var',
+ 'global_var',
++ 'decls',
+ 'all_the_rest',
+ 'utility_code_def'
+ ]
+
+
+ def __init__(self, writer, emit_linenums=False):
self.filename_table = {}
self.filename_list = []
self.input_file_contents = {}
- self.used_utility_code = set()
+ self.utility_codes = set()
self.declared_cnames = {}
- self.pystring_table_needed = False
self.in_utility_code_generation = False
self.emit_linenums = emit_linenums
+ self.parts = {}
- def initwriters(self, rootwriter):
- self.utilprotowriter = rootwriter.new_writer()
- self.utildefwriter = rootwriter.new_writer()
- self.decls_writer = rootwriter.new_writer()
+ self.const_cname_counter = 1
+ self.string_const_index = {}
+ self.int_const_index = {}
+ self.py_constants = []
+
- self.decls_writer = rootwriter.new_writer()
+ assert writer.globalstate is None
+ writer.globalstate = self
+ self.rootwriter = writer
+
+ def initialize_main_c_code(self):
+ rootwriter = self.rootwriter
+ for part in self.code_layout:
+ self.parts[part] = rootwriter.insertion_point()
+
self.pystring_table = rootwriter.new_writer()
self.init_cached_builtins_writer = rootwriter.new_writer()
self.initwriter = rootwriter.new_writer()
self.cleanupwriter.putln("")
self.cleanupwriter.putln("static void __Pyx_CleanupGlobals(void) {")
- self.pystring_table.putln("")
- self.pystring_table.putln("static __Pyx_StringTabEntry %s[] = {" %
- Naming.stringtab_cname)
-
-
+ #
+ # utility_code_def
+ #
+ code = self.parts['utility_code_def']
+ if self.emit_linenums:
+ code.write('\n#line 1 "cython_utility"\n')
+ code.putln("")
+ code.putln("/* Runtime support code */")
+ code.putln("")
+ code.putln("static void %s(void) {" % Naming.fileinit_cname)
+ code.putln("%s = %s;" %
+ (Naming.filetable_cname, Naming.filenames_cname))
+ code.putln("}")
+
+ def finalize_main_c_code(self):
+ self.close_global_decls()
+
+ #
+ # utility_code_def
+ #
+ code = self.parts['utility_code_def']
+ code.put(PyrexTypes.type_conversion_functions)
+ code.putln("")
+
+ def __getitem__(self, key):
+ return self.parts[key]
+
#
# Global constants, interned objects, etc.
#
code.insert(self.cleanupwriter)
def put_pyobject_decl(self, entry):
- self.decls_writer.putln("static PyObject *%s;" % entry.cname)
+ self['global_var'].putln("static PyObject *%s;" % entry.cname)
- self.decls_writer.putln(
+ # constant handling at code generation time
+
+ def get_int_const(self, str_value, longness=False):
+ longness = bool(longness or Utils.long_literal(str_value))
+ try:
+ c = self.int_const_index[(str_value, longness)]
+ except KeyError:
+ c = self.new_int_const(str_value, longness)
+ return c
+
+ def get_py_const(self, type):
+ # create a new Python object constant
+ return self.new_py_const(type)
+
+ def get_string_const(self, text):
+ # return a C string constant, creating a new one if necessary
+ if text.is_unicode:
+ byte_string = text.utf8encode()
+ else:
+ byte_string = text.byteencode()
+ try:
+ c = self.string_const_index[byte_string]
+ except KeyError:
+ c = self.new_string_const(text, byte_string)
+ return c
+
+ def get_py_string_const(self, text, identifier=None):
+ # return a Python string constant, creating a new one if necessary
+ c_string = self.get_string_const(text)
+ py_string = c_string.get_py_string_const(text.encoding, identifier)
+ return py_string
+
+ def new_string_const(self, text, byte_string):
+ cname = self.new_string_const_cname(text)
+ c = StringConst(cname, text, byte_string)
+ self.string_const_index[byte_string] = c
+ return c
+
+ def new_int_const(self, value, longness):
+ cname = self.new_int_const_cname(value, longness)
+ c = IntConst(cname, value, longness)
+ self.int_const_index[(value, longness)] = c
+ return c
+
+ def new_py_const(self, type):
+ cname = self.new_const_cname()
+ c = PyObjectConst(cname, type)
+ self.py_constants.append(c)
+ return c
+
+ def new_string_const_cname(self, value, intern=None):
+ # Create a new globally-unique nice name for a C string constant.
+ if len(value) < 20 and nice_identifier(value):
+ return "%s%s" % (Naming.const_prefix, value)
+ else:
+ return self.new_const_cname()
+
+ def new_int_const_cname(self, value, longness):
+ if longness:
+ value += 'L'
+ cname = "%s%s" % (Naming.interned_num_prefix, value)
+ cname = cname.replace('-', 'neg_').replace('.','_')
+ return cname
+
+ def new_const_cname(self, prefix=''):
+ n = self.const_cname_counter
+ self.const_cname_counter += 1
+ return "%s%s%d" % (Naming.const_prefix, prefix, n)
+
+ def add_cached_builtin_decl(self, entry):
+ if Options.cache_builtins:
+ if self.should_declare(entry.cname, entry):
+ interned_cname = self.get_py_string_const(entry.name, True).cname
+ self.put_pyobject_decl(entry)
+ self.init_cached_builtins_writer.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
+ entry.cname,
+ Naming.builtins_cname,
+ interned_cname,
+ entry.cname,
+ self.init_cached_builtins_writer.error_goto(entry.pos)))
+
+ def generate_const_declarations(self):
+ self.generate_string_constants()
+ self.generate_int_constants()
+ self.generate_object_constant_decls()
+
+ def generate_object_constant_decls(self):
+ consts = [ (len(c.cname), c.cname, c)
+ for c in self.py_constants ]
+ consts.sort()
++ decls_writer = self.parts['decls']
+ for _, cname, c in consts:
- self.decls_writer.putln('static char %s[] = "%s";' % (
++ decls_writer.putln(
+ "static %s;" % c.type.declaration_code(cname))
+
+ def generate_string_constants(self):
+ c_consts = [ (len(c.cname), c.cname, c)
+ for c in self.string_const_index.itervalues() ]
+ c_consts.sort()
+ py_strings = []
++
++ decls_writer = self.parts['decls']
+ for _, cname, c in c_consts:
- self.decls_writer.putln(
++ decls_writer.putln('static char %s[] = "%s";' % (
+ cname, c.escaped_value))
+ if c.py_strings is not None:
+ for py_string in c.py_strings.itervalues():
+ py_strings.append((c.cname, len(py_string.cname), py_string))
+
+ if py_strings:
+ import Nodes
+ self.use_utility_code(Nodes.init_string_tab_utility_code)
+
+ py_strings.sort()
+ self.pystring_table.putln("")
+ self.pystring_table.putln("static __Pyx_StringTabEntry %s[] = {" %
+ Naming.stringtab_cname)
+ for c_cname, _, py_string in py_strings:
- self.decls_writer.putln("static PyObject *%s;" % cname)
++ decls_writer.putln(
+ "static PyObject *%s;" % py_string.cname)
+ self.pystring_table.putln(
+ "{&%s, %s, sizeof(%s), %d, %d, %d}," % (
+ py_string.cname,
+ c_cname,
+ c_cname,
+ py_string.unicode,
+ py_string.intern,
+ py_string.identifier
+ ))
+ self.pystring_table.putln("{0, 0, 0, 0, 0, 0}")
+ self.pystring_table.putln("};")
+
+ self.initwriter.putln(
+ "if (__Pyx_InitStrings(%s) < 0) %s;" % (
+ Naming.stringtab_cname,
+ self.initwriter.error_goto(self.module_pos)))
+
+ def generate_int_constants(self):
+ consts = [ (len(c.value), c.value, c.is_long, c)
+ for c in self.int_const_index.itervalues() ]
+ consts.sort()
++ decls_writer = self.parts['decls']
+ for _, value, longness, c in consts:
+ cname = c.cname
++ decls_writer.putln("static PyObject *%s;" % cname)
+ if longness:
+ function = '%s = PyLong_FromString((char *)"%s", 0, 0); %s;'
+ else:
+ function = "%s = PyInt_FromLong(%s); %s;"
+ self.initwriter.putln(function % (
+ cname,
+ value,
+ self.initwriter.error_goto_if_null(cname, self.module_pos)))
+
# 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
# generation (labels and temps state etc.)
# globalstate GlobalState contains state global for a C file (input file info,
# utility code, declared constants etc.)
- # emit_linenums boolean whether or not to write #line pragmas
+ # emit_linenums boolean whether or not to write #line pragmas
+ #
+ # pyclass_stack list used during recursive code generation to pass information
+ # about the current class one is in
+ globalstate = None
+
def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None):
if buffer is None: buffer = StringIOTree()
self.buffer = buffer
def exit_cfunc_scope(self):
self.funcstate = None
- def putln(self, code = ""):
+ # constant handling
+
+ def get_py_num(self, str_value, longness):
+ return self.globalstate.get_int_const(str_value, longness).cname
+
+ def get_string_const(self, text):
+ return self.globalstate.get_string_const(text).cname
+
+ def get_py_string_const(self, text, identifier=None):
+ return self.globalstate.get_py_string_const(text, identifier).cname
+
+ def get_argument_default_const(self, type):
+ return self.globalstate.get_py_const(type).cname
+
+ def intern(self, text):
+ return self.get_py_string_const(text)
+
+ def intern_identifier(self, text):
+ return self.get_py_string_const(text, True)
+
+ # code generation
+
+ def putln(self, code = "", safe=False):
if self.marker and self.bol:
self.emit_marker()
if self.emit_linenums and self.last_marker_line != 0:
def generate_c_code(self, env, options, result):
modules = self.referenced_modules
+
if Options.annotate or options.annotate:
- code = Annotate.AnnotationCCodeWriter()
+ emit_linenums = False
+ rootwriter = Annotate.AnnotationCCodeWriter()
else:
- code = Code.CCodeWriter(emit_linenums=options.emit_linenums)
- h_code = code.insertion_point()
+ emit_linenums = options.emit_linenums
+ rootwriter = Code.CCodeWriter(emit_linenums=emit_linenums)
+ globalstate = Code.GlobalState(rootwriter, emit_linenums)
+ globalstate.initialize_main_c_code()
+ h_code = globalstate['h_code']
+
self.generate_module_preamble(env, modules, h_code)
- code.globalstate.module_pos = self.pos
- code.globalstate.directives = self.directives
+ globalstate.module_pos = self.pos
+ globalstate.directives = self.directives
- code.globalstate.use_utility_code(refcount_utility_code)
+ globalstate.use_utility_code(refcount_utility_code)
+ code = globalstate['before_global_var']
code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name)
+ code.putln("int %s%s = %s;" % (Naming.module_is_main, self.full_module_name.replace('.', '__'), int(Options.embed)))
code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name)
- self.generate_const_definitions(env, code)
- self.generate_interned_num_decls(env, code)
- self.generate_interned_string_decls(env, code)
- self.generate_py_string_decls(env, code)
- code.globalstate.insert_global_var_declarations_into(code)
+ code = globalstate['all_the_rest']
self.generate_cached_builtins_decls(env, code)
self.body.generate_function_definitions(env, code)
env.module_cname,
Naming.builtins_cname,
code.error_goto(self.pos)))
- if Options.embed:
- __main__name = code.globalstate.get_py_string_const(
- EncodedString("__main__"), identifier=True)
- code.putln(
- 'if (__Pyx_SetAttrString(%s, "__name__", %s) < 0) %s;' % (
- env.module_cname,
- __main__name.cname,
- code.error_goto(self.pos)))
++
++
++ __main__name = code.globalstate.get_py_string_const(
++ EncodedString("__main__"), identifier=True)
+ code.putln("if (%s%s) {" % (Naming.module_is_main, self.full_module_name.replace('.', '__')))
+ code.putln(
+ 'if (__Pyx_SetAttrString(%s, "__name__", %s) < 0) %s;' % (
+ env.module_cname,
- self.__main__cname,
++ __main__name.cname,
+ code.error_goto(self.pos)))
+ code.putln("}")
if Options.pre_import is not None:
code.putln(
'%s = PyImport_AddModule(__Pyx_NAMESTR("%s"));' % (