1 # cython: language_level = 3, py2_import=True
3 # Pyrex - Code output module
7 cython.declare(re=object, Naming=object, Options=object, StringEncoding=object,
8 Utils=object, SourceDescriptor=object, StringIOTree=object,
9 DebugFlags=object, none_or_sub=object, basestring=object)
15 from Cython import Utils
16 from Scanning import SourceDescriptor
17 from Cython.StringIOTree import StringIOTree
20 from Cython.Utils import none_or_sub
22 from __builtin__ import basestring
24 from builtins import str as basestring
27 non_portable_builtins_map = {
28 # builtins that have different names in different Python versions
29 'bytes' : ('PY_MAJOR_VERSION < 3', 'str'),
30 'unicode' : ('PY_MAJOR_VERSION >= 3', 'str'),
31 'xrange' : ('PY_MAJOR_VERSION >= 3', 'range'),
32 'BaseException' : ('PY_VERSION_HEX < 0x02050000', 'Exception'),
35 uncachable_builtins = [
36 # builtin names that cannot be cached because they may or may not
37 # be available at import time
41 class UtilityCode(object):
42 # Stores utility code to add during code generation.
44 # See GlobalState.put_utility_code.
46 # hashes/equals by instance
48 def __init__(self, proto=None, impl=None, init=None, cleanup=None, requires=None,
49 proto_block='utility_code_proto'):
50 # proto_block: Which code block to dump prototype in. See GlobalState.
54 self.cleanup = cleanup
55 self.requires = requires
57 self.specialize_list = []
58 self.proto_block = proto_block
60 def specialize(self, pyrex_type=None, **data):
61 # Dicts aren't hashable...
62 if pyrex_type is not None:
63 data['type'] = pyrex_type.declaration_code('')
64 data['type_name'] = pyrex_type.specialization_name()
65 key = data.items(); key.sort(); key = tuple(key)
67 return self._cache[key]
69 if self.requires is None:
72 requires = [r.specialize(data) for r in self.requires]
73 s = self._cache[key] = UtilityCode(
74 none_or_sub(self.proto, data),
75 none_or_sub(self.impl, data),
76 none_or_sub(self.init, data),
77 none_or_sub(self.cleanup, data),
78 requires, self.proto_block)
79 self.specialize_list.append(s)
82 def put_code(self, output):
84 for dependency in self.requires:
85 output.use_utility_code(dependency)
87 output[self.proto_block].put(self.proto)
89 output['utility_code_def'].put(self.impl)
91 writer = output['init_globals']
92 if isinstance(self.init, basestring):
95 self.init(writer, output.module_pos)
96 if self.cleanup and Options.generate_cleanup_code:
97 writer = output['cleanup_globals']
98 if isinstance(self.cleanup, basestring):
99 writer.put(self.cleanup)
101 self.cleanup(writer, output.module_pos)
105 class FunctionState(object):
106 # return_label string function return point label
107 # error_label string error catch point label
108 # continue_label string loop continue point label
109 # break_label string loop break point label
110 # return_from_error_cleanup_label string
111 # label_counter integer counter for naming labels
112 # in_try_finally boolean inside try of try...finally
113 # exc_vars (string * 3) exception variables for reraise, or None
115 # Not used for now, perhaps later
116 def __init__(self, owner, names_taken=cython.set()):
117 self.names_taken = names_taken
120 self.error_label = None
121 self.label_counter = 0
122 self.labels_used = cython.set()
123 self.return_label = self.new_label()
124 self.new_error_label()
125 self.continue_label = None
126 self.break_label = None
128 self.in_try_finally = 0
131 self.temps_allocated = [] # of (name, type, manage_ref)
132 self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
133 self.temps_used_type = {} # name -> (type, manage_ref)
134 self.temp_counter = 0
135 self.closure_temps = None
139 def new_label(self, name=None):
140 n = self.label_counter
141 self.label_counter = n + 1
142 label = "%s%d" % (Naming.label_prefix, n)
147 def new_error_label(self):
148 old_err_lbl = self.error_label
149 self.error_label = self.new_label('error')
152 def get_loop_labels(self):
157 def set_loop_labels(self, labels):
158 (self.continue_label,
159 self.break_label) = labels
161 def new_loop_labels(self):
162 old_labels = self.get_loop_labels()
163 self.set_loop_labels(
164 (self.new_label("continue"),
165 self.new_label("break")))
168 def get_all_labels(self):
175 def set_all_labels(self, labels):
176 (self.continue_label,
179 self.error_label) = labels
181 def all_new_labels(self):
182 old_labels = self.get_all_labels()
184 for old_label in old_labels:
186 new_labels.append(self.new_label())
188 new_labels.append(old_label)
189 self.set_all_labels(new_labels)
192 def use_label(self, lbl):
193 self.labels_used.add(lbl)
195 def label_used(self, lbl):
196 return lbl in self.labels_used
200 def allocate_temp(self, type, manage_ref):
202 Allocates a temporary (which may create a new one or get a previously
203 allocated and released one of the same type). Type is simply registered
204 and handed back, but will usually be a PyrexType.
206 If type.is_pyobject, manage_ref comes into play. If manage_ref is set to
207 True, the temp will be decref-ed on return statements and in exception
208 handling clauses. Otherwise the caller has to deal with any reference
209 counting of the variable.
211 If not type.is_pyobject, then manage_ref will be ignored, but it
212 still has to be passed. It is recommended to pass False by convention
213 if it is known that type will never be a Python object.
215 A C string referring to the variable is returned.
217 if not type.is_pyobject:
218 # Make manage_ref canonical, so that manage_ref will always mean
219 # a decref is needed.
221 freelist = self.temps_free.get((type, manage_ref))
222 if freelist is not None and len(freelist) > 0:
223 result = freelist.pop()
226 self.temp_counter += 1
227 result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter)
228 if not result in self.names_taken: break
229 self.temps_allocated.append((result, type, manage_ref))
230 self.temps_used_type[result] = (type, manage_ref)
231 if DebugFlags.debug_temp_code_comments:
232 self.owner.putln("/* %s allocated */" % result)
235 def release_temp(self, name):
237 Releases a temporary so that it can be reused by other code needing
238 a temp of the same type.
240 type, manage_ref = self.temps_used_type[name]
241 freelist = self.temps_free.get((type, manage_ref))
244 self.temps_free[(type, manage_ref)] = freelist
246 raise RuntimeError("Temp %s freed twice!" % name)
247 freelist.append(name)
248 if DebugFlags.debug_temp_code_comments:
249 self.owner.putln("/* %s released */" % name)
251 def temps_in_use(self):
252 """Return a list of (cname,type,manage_ref) tuples of temp names and their type
253 that are currently in use.
256 for name, type, manage_ref in self.temps_allocated:
257 freelist = self.temps_free.get((type, manage_ref))
258 if freelist is None or name not in freelist:
259 used.append((name, type, manage_ref))
262 def temps_holding_reference(self):
263 """Return a list of (cname,type) tuples of temp names and their type
264 that are currently in use. This includes only temps of a
265 Python object type which owns its reference.
268 for name, type, manage_ref in self.temps_in_use()
271 def all_managed_temps(self):
272 """Return a list of (cname, type) tuples of refcount-managed Python objects.
274 return [(cname, type)
275 for cname, type, manage_ref in self.temps_allocated
278 def all_free_managed_temps(self):
279 """Return a list of (cname, type) tuples of refcount-managed Python
280 objects that are not currently in use. This is used by
281 try-except and try-finally blocks to clean up temps in the
284 return [(cname, type)
285 for (type, manage_ref), freelist in self.temps_free.items()
287 for cname in freelist]
289 def init_closure_temps(self, scope):
290 self.closure_temps = ClosureTempAllocator(scope)
293 class IntConst(object):
294 """Global info about a Python integer constant held by GlobalState.
300 def __init__(self, cname, value, is_long):
303 self.is_long = is_long
305 class PyObjectConst(object):
306 """Global info about a generic constant held by GlobalState.
311 def __init__(self, cname, type):
315 cython.declare(possible_unicode_identifier=object, possible_bytes_identifier=object,
316 nice_identifier=object, find_alphanums=object)
317 possible_unicode_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
318 possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match
319 nice_identifier = re.compile(r'\A[a-zA-Z0-9_]+\Z').match
320 find_alphanums = re.compile('([a-zA-Z0-9]+)').findall
322 class StringConst(object):
323 """Global info about a C string constant held by GlobalState.
326 # text EncodedString or BytesLiteral
327 # py_strings {(identifier, encoding) : PyStringConst}
329 def __init__(self, cname, text, byte_string):
332 self.escaped_value = StringEncoding.escape_byte_string(byte_string)
333 self.py_strings = None
335 def get_py_string_const(self, encoding, identifier=None,
336 is_str=False, py3str_cstring=None):
337 py_strings = self.py_strings
340 is_str = bool(identifier or is_str)
341 is_unicode = encoding is None and not is_str
348 encoding = encoding.lower()
349 if encoding in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'):
353 encoding_key = ''.join(find_alphanums(encoding))
355 key = (is_str, is_unicode, encoding_key, py3str_cstring)
356 if py_strings is not None:
358 return py_strings[key]
366 elif identifier is None:
367 if isinstance(text, unicode):
368 intern = bool(possible_unicode_identifier(text))
370 intern = bool(possible_bytes_identifier(text))
374 prefix = Naming.interned_str_prefix
376 prefix = Naming.py_const_prefix
377 pystring_cname = "%s%s_%s" % (
379 (is_str and 's') or (is_unicode and 'u') or 'b',
380 self.cname[len(Naming.const_prefix):])
382 py_string = PyStringConst(
383 pystring_cname, encoding, is_unicode, is_str, py3str_cstring, intern)
384 self.py_strings[key] = py_string
387 class PyStringConst(object):
388 """Global info about a Python string constant held by GlobalState.
391 # py3str_cstring string
397 def __init__(self, cname, encoding, is_unicode, is_str=False,
398 py3str_cstring=None, intern=False):
400 self.py3str_cstring = py3str_cstring
401 self.encoding = encoding
403 self.is_unicode = is_unicode
406 def __lt__(self, other):
407 return self.cname < other.cname
410 class GlobalState(object):
411 # filename_table {string : int} for finding filename table indexes
412 # filename_list [string] filenames in filename table order
413 # input_file_contents dict contents (=list of lines) of any file that was used as input
414 # to create this output C code. This is
415 # used to annotate the comments.
417 # utility_codes set IDs of used utility code (to avoid reinsertion)
419 # declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
420 # constants etc. into the pyx-declared ones (i.e,
421 # check if constants are already added).
422 # In time, hopefully the literals etc. will be
423 # supplied directly instead.
425 # const_cname_counter int global counter for constant identifiers
428 # parts {string:CCodeWriter}
435 # directives set Temporary variable used to track
436 # the current set of directives in the code generation
444 'utility_code_proto_before_types',
445 'numeric_typedefs', # Let these detailed individual parts stay!,
446 'complex_type_declarations', # as the proper solution is to make a full DAG...
447 'type_declarations', # More coarse-grained blocks would simply hide
448 'utility_code_proto', # the ugliness, not fix it
449 'module_declarations',
468 def __init__(self, writer, emit_linenums=False):
469 self.filename_table = {}
470 self.filename_list = []
471 self.input_file_contents = {}
472 self.utility_codes = cython.set()
473 self.declared_cnames = {}
474 self.in_utility_code_generation = False
475 self.emit_linenums = emit_linenums
478 self.const_cname_counter = 1
479 self.string_const_index = {}
480 self.int_const_index = {}
481 self.py_constants = []
483 assert writer.globalstate is None
484 writer.globalstate = self
485 self.rootwriter = writer
487 def initialize_main_c_code(self):
488 rootwriter = self.rootwriter
489 for part in self.code_layout:
490 self.parts[part] = rootwriter.insertion_point()
492 if not Options.cache_builtins:
493 del self.parts['cached_builtins']
495 w = self.parts['cached_builtins']
496 w.enter_cfunc_scope()
497 w.putln("static int __Pyx_InitCachedBuiltins(void) {")
499 w = self.parts['cached_constants']
500 w.enter_cfunc_scope()
502 w.putln("static int __Pyx_InitCachedConstants(void) {")
503 w.put_declare_refcount_context()
504 w.put_setup_refcount_context("__Pyx_InitCachedConstants")
506 w = self.parts['init_globals']
507 w.enter_cfunc_scope()
509 w.putln("static int __Pyx_InitGlobals(void) {")
511 if not Options.generate_cleanup_code:
512 del self.parts['cleanup_globals']
514 w = self.parts['cleanup_globals']
515 w.enter_cfunc_scope()
517 w.putln("static void __Pyx_CleanupGlobals(void) {")
522 code = self.parts['utility_code_def']
523 if self.emit_linenums:
524 code.write('\n#line 1 "cython_utility"\n')
526 code.putln("/* Runtime support code */")
528 def finalize_main_c_code(self):
529 self.close_global_decls()
534 code = self.parts['utility_code_def']
536 code.put(PyrexTypes.type_conversion_functions)
539 def __getitem__(self, key):
540 return self.parts[key]
543 # Global constants, interned objects, etc.
545 def close_global_decls(self):
546 # This is called when it is known that no more global declarations will
548 self.generate_const_declarations()
549 if Options.cache_builtins:
550 w = self.parts['cached_builtins']
552 if w.label_used(w.error_label):
553 w.put_label(w.error_label)
554 w.putln("return -1;")
558 w = self.parts['cached_constants']
559 w.put_finish_refcount_context()
561 if w.label_used(w.error_label):
562 w.put_label(w.error_label)
563 w.put_finish_refcount_context()
564 w.putln("return -1;")
568 w = self.parts['init_globals']
570 if w.label_used(w.error_label):
571 w.put_label(w.error_label)
572 w.putln("return -1;")
576 if Options.generate_cleanup_code:
577 w = self.parts['cleanup_globals']
581 if Options.generate_cleanup_code:
582 w = self.parts['cleanup_module']
586 def put_pyobject_decl(self, entry):
587 self['global_var'].putln("static PyObject *%s;" % entry.cname)
589 # constant handling at code generation time
591 def get_cached_constants_writer(self):
592 return self.parts['cached_constants']
594 def get_int_const(self, str_value, longness=False):
595 longness = bool(longness)
597 c = self.int_const_index[(str_value, longness)]
599 c = self.new_int_const(str_value, longness)
602 def get_py_const(self, type, prefix='', cleanup_level=None):
603 # create a new Python object constant
604 const = self.new_py_const(type, prefix)
605 if cleanup_level is not None \
606 and cleanup_level <= Options.generate_cleanup_code:
607 cleanup_writer = self.parts['cleanup_globals']
608 cleanup_writer.put_xdecref_clear(const.cname, type, nanny=False)
611 def get_string_const(self, text):
612 # return a C string constant, creating a new one if necessary
614 byte_string = text.utf8encode()
616 byte_string = text.byteencode()
618 c = self.string_const_index[byte_string]
620 c = self.new_string_const(text, byte_string)
623 def get_py_string_const(self, text, identifier=None,
624 is_str=False, unicode_value=None):
625 # return a Python string constant, creating a new one if necessary
626 c_string = self.get_string_const(text)
627 py3str_cstring = None
628 if is_str and unicode_value is not None \
629 and unicode_value.utf8encode() != text.byteencode():
630 py3str_cstring = self.get_string_const(unicode_value)
631 py_string = c_string.get_py_string_const(
632 text.encoding, identifier, is_str, py3str_cstring)
635 def get_interned_identifier(self, text):
636 return self.get_py_string_const(text, identifier=True)
638 def new_string_const(self, text, byte_string):
639 cname = self.new_string_const_cname(byte_string)
640 c = StringConst(cname, text, byte_string)
641 self.string_const_index[byte_string] = c
644 def new_int_const(self, value, longness):
645 cname = self.new_int_const_cname(value, longness)
646 c = IntConst(cname, value, longness)
647 self.int_const_index[(value, longness)] = c
650 def new_py_const(self, type, prefix=''):
651 cname = self.new_const_cname(prefix)
652 c = PyObjectConst(cname, type)
653 self.py_constants.append(c)
656 def new_string_const_cname(self, bytes_value, intern=None):
657 # Create a new globally-unique nice name for a C string constant.
659 value = bytes_value.decode('ASCII')
661 return self.new_const_cname()
663 if len(value) < 20 and nice_identifier(value):
664 return "%s_%s" % (Naming.const_prefix, value)
666 return self.new_const_cname()
668 def new_int_const_cname(self, value, longness):
671 cname = "%s%s" % (Naming.interned_num_prefix, value)
672 cname = cname.replace('-', 'neg_').replace('.','_')
675 def new_const_cname(self, prefix=''):
676 n = self.const_cname_counter
677 self.const_cname_counter += 1
678 return "%s%s%d" % (Naming.const_prefix, prefix, n)
680 def add_cached_builtin_decl(self, entry):
681 if entry.is_builtin and entry.is_const:
682 if self.should_declare(entry.cname, entry):
683 self.put_pyobject_decl(entry)
684 w = self.parts['cached_builtins']
686 if entry.name in non_portable_builtins_map:
687 condition, replacement = non_portable_builtins_map[entry.name]
688 w.putln('#if %s' % condition)
689 self.put_cached_builtin_init(
690 entry.pos, StringEncoding.EncodedString(replacement),
693 self.put_cached_builtin_init(
694 entry.pos, StringEncoding.EncodedString(entry.name),
699 def put_cached_builtin_init(self, pos, name, cname):
700 w = self.parts['cached_builtins']
701 interned_cname = self.get_interned_identifier(name).cname
702 from ExprNodes import get_name_interned_utility_code
703 self.use_utility_code(get_name_interned_utility_code)
704 w.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
706 Naming.builtins_cname,
711 def generate_const_declarations(self):
712 self.generate_string_constants()
713 self.generate_int_constants()
714 self.generate_object_constant_decls()
716 def generate_object_constant_decls(self):
717 consts = [ (len(c.cname), c.cname, c)
718 for c in self.py_constants ]
720 decls_writer = self.parts['decls']
721 for _, cname, c in consts:
723 "static %s;" % c.type.declaration_code(cname))
725 def generate_string_constants(self):
726 c_consts = [ (len(c.cname), c.cname, c)
727 for c in self.string_const_index.values() ]
731 decls_writer = self.parts['decls']
732 for _, cname, c in c_consts:
733 decls_writer.putln('static char %s[] = "%s";' % (
734 cname, StringEncoding.split_string_literal(c.escaped_value)))
735 if c.py_strings is not None:
736 for py_string in c.py_strings.values():
737 py_strings.append((c.cname, len(py_string.cname), py_string))
741 self.use_utility_code(Nodes.init_string_tab_utility_code)
744 w = self.parts['pystring_table']
746 w.putln("static __Pyx_StringTabEntry %s[] = {" %
747 Naming.stringtab_cname)
748 for c_cname, _, py_string in py_strings:
749 if not py_string.is_str or not py_string.encoding or \
750 py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII',
754 encoding = '"%s"' % py_string.encoding.lower()
757 "static PyObject *%s;" % py_string.cname)
758 if py_string.py3str_cstring:
759 w.putln("#if PY_MAJOR_VERSION >= 3")
761 "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
763 py_string.py3str_cstring.cname,
764 py_string.py3str_cstring.cname,
770 "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
775 py_string.is_unicode,
779 if py_string.py3str_cstring:
781 w.putln("{0, 0, 0, 0, 0, 0, 0}")
784 init_globals = self.parts['init_globals']
786 "if (__Pyx_InitStrings(%s) < 0) %s;" % (
787 Naming.stringtab_cname,
788 init_globals.error_goto(self.module_pos)))
790 def generate_int_constants(self):
791 consts = [ (len(c.value), c.value, c.is_long, c)
792 for c in self.int_const_index.values() ]
794 decls_writer = self.parts['decls']
795 for _, value, longness, c in consts:
797 decls_writer.putln("static PyObject *%s;" % cname)
799 function = '%s = PyLong_FromString((char *)"%s", 0, 0); %s;'
800 elif Utils.long_literal(value):
801 function = '%s = PyInt_FromString((char *)"%s", 0, 0); %s;'
803 function = "%s = PyInt_FromLong(%s); %s;"
804 init_globals = self.parts['init_globals']
805 init_globals.putln(function % (
808 init_globals.error_goto_if_null(cname, self.module_pos)))
810 # The functions below are there in a transition phase only
811 # and will be deprecated. They are called from Nodes.BlockNode.
812 # The copy&paste duplication is intentional in order to be able
813 # to see quickly how BlockNode worked, until this is replaced.
815 def should_declare(self, cname, entry):
816 if cname in self.declared_cnames:
817 other = self.declared_cnames[cname]
818 assert str(entry.type) == str(other.type)
819 assert entry.init == other.init
822 self.declared_cnames[cname] = entry
829 def lookup_filename(self, filename):
831 index = self.filename_table[filename]
833 index = len(self.filename_list)
834 self.filename_list.append(filename)
835 self.filename_table[filename] = index
838 def commented_file_contents(self, source_desc):
840 return self.input_file_contents[source_desc]
843 source_file = source_desc.get_lines(encoding='ASCII',
844 error_handling='ignore')
846 F = [u' * ' + line.rstrip().replace(
847 u'*/', u'*[inserted by cython to avoid comment closer]/'
849 u'/*', u'/[inserted by cython to avoid comment start]*'
851 for line in source_file]
853 if hasattr(source_file, 'close'):
855 if not F: F.append(u'')
856 self.input_file_contents[source_desc] = F
863 def use_utility_code(self, utility_code):
865 Adds code to the C file. utility_code should
866 a) implement __eq__/__hash__ for the purpose of knowing whether the same
867 code has already been included
868 b) implement put_code, which takes a globalstate instance
872 if utility_code not in self.utility_codes:
873 self.utility_codes.add(utility_code)
874 utility_code.put_code(self)
877 def funccontext_property(name):
880 attribute_of = operator.attrgetter(name)
883 return getattr(o, name)
886 return attribute_of(self.funcstate)
887 def set(self, value):
888 setattr(self.funcstate, name, value)
889 return property(get, set)
892 class CCodeWriter(object):
894 Utility class to output C code.
896 When creating an insertion point one must care about the state that is
898 - formatting state (level, bol) is cloned and used in insertion points
900 - labels, temps, exc_vars: One must construct a scope in which these can
901 exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
902 sanity checking and forward compatabilty). Created insertion points
903 looses this scope and cannot access it.
904 - marker: Not copied to insertion point
905 - filename_table, filename_list, input_file_contents: All codewriters
906 coming from the same root share the same instances simultaneously.
910 # buffer StringIOTree
912 # level int indentation level
913 # bol bool beginning of line?
914 # marker string comment to emit before next line
915 # funcstate FunctionState contains state local to a C function used for code
916 # generation (labels and temps state etc.)
917 # globalstate GlobalState contains state global for a C file (input file info,
918 # utility code, declared constants etc.)
919 # emit_linenums boolean whether or not to write #line pragmas
921 # c_line_in_traceback boolean append the c file and line number to the traceback for exceptions
923 # pyclass_stack list used during recursive code generation to pass information
924 # about the current class one is in
928 def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None, c_line_in_traceback=True):
929 if buffer is None: buffer = StringIOTree()
932 self.last_marker_line = 0
933 self.source_desc = ""
934 self.pyclass_stack = []
936 self.funcstate = None
941 if create_from is not None:
942 # Use same global state
943 self.globalstate = create_from.globalstate
944 # Clone formatting state
946 self.level = create_from.level
947 self.bol = create_from.bol
948 self.call_level = create_from.call_level
949 if emit_linenums is None and self.globalstate:
950 self.emit_linenums = self.globalstate.emit_linenums
952 self.emit_linenums = emit_linenums
953 self.c_line_in_traceback = c_line_in_traceback
955 def create_new(self, create_from, buffer, copy_formatting):
956 # polymorphic constructor -- very slightly more versatile
957 # than using __class__
958 result = CCodeWriter(create_from, buffer, copy_formatting, c_line_in_traceback=self.c_line_in_traceback)
962 self.buffer.copyto(f)
965 return self.buffer.getvalue()
968 # also put invalid markers (lineno 0), to indicate that those lines
969 # have no Cython source code correspondence
970 if self.marker is None:
971 cython_lineno = self.last_marker_line
973 cython_lineno = self.marker[0]
975 self.buffer.markers.extend([cython_lineno] * s.count('\n'))
978 def insertion_point(self):
979 other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
982 def new_writer(self):
984 Creates a new CCodeWriter connected to the same global state, which
985 can later be inserted using insert.
987 return CCodeWriter(create_from=self, c_line_in_traceback=self.c_line_in_traceback)
989 def insert(self, writer):
991 Inserts the contents of another code writer (created with
992 the same global state) in the current location.
994 It is ok to write to the inserted writer also after insertion.
996 assert writer.globalstate is self.globalstate
997 self.buffer.insert(writer.buffer)
999 # Properties delegated to function scope
1000 label_counter = funccontext_property("label_counter")
1001 return_label = funccontext_property("return_label")
1002 error_label = funccontext_property("error_label")
1003 labels_used = funccontext_property("labels_used")
1004 continue_label = funccontext_property("continue_label")
1005 break_label = funccontext_property("break_label")
1006 return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
1008 # Functions delegated to function scope
1009 def new_label(self, name=None): return self.funcstate.new_label(name)
1010 def new_error_label(self): return self.funcstate.new_error_label()
1011 def get_loop_labels(self): return self.funcstate.get_loop_labels()
1012 def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
1013 def new_loop_labels(self): return self.funcstate.new_loop_labels()
1014 def get_all_labels(self): return self.funcstate.get_all_labels()
1015 def set_all_labels(self, labels): return self.funcstate.set_all_labels(labels)
1016 def all_new_labels(self): return self.funcstate.all_new_labels()
1017 def use_label(self, lbl): return self.funcstate.use_label(lbl)
1018 def label_used(self, lbl): return self.funcstate.label_used(lbl)
1021 def enter_cfunc_scope(self):
1022 self.funcstate = FunctionState(self)
1024 def exit_cfunc_scope(self):
1025 self.funcstate = None
1029 def get_py_num(self, str_value, longness):
1030 return self.globalstate.get_int_const(str_value, longness).cname
1032 def get_py_const(self, type, prefix='', cleanup_level=None):
1033 return self.globalstate.get_py_const(type, prefix, cleanup_level).cname
1035 def get_string_const(self, text):
1036 return self.globalstate.get_string_const(text).cname
1038 def get_py_string_const(self, text, identifier=None,
1039 is_str=False, unicode_value=None):
1040 return self.globalstate.get_py_string_const(
1041 text, identifier, is_str, unicode_value).cname
1043 def get_argument_default_const(self, type):
1044 return self.globalstate.get_py_const(type).cname
1046 def intern(self, text):
1047 return self.get_py_string_const(text)
1049 def intern_identifier(self, text):
1050 return self.get_py_string_const(text, identifier=True)
1052 def get_cached_constants_writer(self):
1053 return self.globalstate.get_cached_constants_writer()
1057 def putln(self, code = "", safe=False):
1058 if self.marker and self.bol:
1060 if self.emit_linenums and self.last_marker_line != 0:
1061 self.write('\n#line %s "%s"\n' % (self.last_marker_line, self.source_desc))
1071 def emit_marker(self):
1074 self.write("/* %s */\n" % self.marker[1])
1075 self.last_marker_line = self.marker[0]
1078 def put_safe(self, code):
1079 # put code, but ignore {}
1083 def put(self, code):
1086 dl = code.count("{")
1090 dl -= code.count("}")
1093 elif dl == 0 and code[0] == "}":
1094 # special cases like "} else {" need a temporary dedent
1106 def increase_indent(self):
1107 self.level = self.level + 1
1109 def decrease_indent(self):
1110 self.level = self.level - 1
1112 def begin_block(self):
1114 self.increase_indent()
1116 def end_block(self):
1117 self.decrease_indent()
1121 self.write(" " * self.level)
1123 def get_py_version_hex(self, pyversion):
1124 return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
1126 def mark_pos(self, pos):
1129 source_desc, line, col = pos
1130 if self.last_marker_line == line:
1132 assert isinstance(source_desc, SourceDescriptor)
1133 contents = self.globalstate.commented_file_contents(source_desc)
1134 lines = contents[max(0,line-3):line] # line numbers start at 1
1135 lines[-1] += u' # <<<<<<<<<<<<<<'
1136 lines += contents[line:line+2]
1138 marker = u'"%s":%d\n%s\n' % (
1139 source_desc.get_escaped_description(), line, u'\n'.join(lines))
1140 self.marker = (line, marker)
1141 if self.emit_linenums:
1142 self.source_desc = source_desc.get_escaped_description()
1144 def put_label(self, lbl):
1145 if lbl in self.funcstate.labels_used:
1146 self.putln("%s:;" % lbl)
1148 def put_goto(self, lbl):
1149 self.funcstate.use_label(lbl)
1150 self.putln("goto %s;" % lbl)
1152 def put_var_declarations(self, entries, static = 0, dll_linkage = None,
1154 for entry in entries:
1155 if not entry.in_cinclude:
1156 self.put_var_declaration(entry, static, dll_linkage, definition)
1158 def put_var_declaration(self, entry, static = 0, dll_linkage = None,
1160 #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
1161 if entry.in_closure:
1163 visibility = entry.visibility
1164 if visibility == 'private' and not definition:
1165 #print "...private and not definition, skipping" ###
1167 if not entry.used and visibility == "private":
1168 #print "not used and private, skipping", entry.cname ###
1171 if visibility == 'extern':
1172 storage_class = Naming.extern_c_macro
1173 elif visibility == 'public':
1175 storage_class = Naming.extern_c_macro
1176 elif visibility == 'private':
1178 storage_class = "static"
1180 self.put("%s " % storage_class)
1181 if visibility != 'public':
1183 self.put(entry.type.declaration_code(entry.cname,
1184 dll_linkage = dll_linkage))
1185 if entry.init is not None:
1186 self.put_safe(" = %s" % entry.type.literal_code(entry.init))
1189 def put_temp_declarations(self, func_context):
1190 for name, type, manage_ref in func_context.temps_allocated:
1191 decl = type.declaration_code(name)
1192 if type.is_pyobject:
1193 self.putln("%s = NULL;" % decl)
1195 self.putln("%s;" % decl)
1197 def put_h_guard(self, guard):
1198 self.putln("#ifndef %s" % guard)
1199 self.putln("#define %s" % guard)
1201 def unlikely(self, cond):
1202 if Options.gcc_branch_hints:
1203 return 'unlikely(%s)' % cond
1207 # Python objects and reference counting
1209 def entry_as_pyobject(self, entry):
1211 if (not entry.is_self_arg and not entry.type.is_complete()
1212 or entry.type.is_extension_type):
1213 return "(PyObject *)" + entry.cname
1217 def as_pyobject(self, cname, type):
1218 from PyrexTypes import py_object_type, typecast
1219 return typecast(py_object_type, type, cname)
1221 def put_gotref(self, cname):
1222 self.putln("__Pyx_GOTREF(%s);" % cname)
1224 def put_giveref(self, cname):
1225 self.putln("__Pyx_GIVEREF(%s);" % cname)
1227 def put_xgiveref(self, cname):
1228 self.putln("__Pyx_XGIVEREF(%s);" % cname)
1230 def put_xgotref(self, cname):
1231 self.putln("__Pyx_XGOTREF(%s);" % cname)
1233 def put_incref(self, cname, type, nanny=True):
1235 self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
1237 self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
1239 def put_decref(self, cname, type, nanny=True):
1241 self.putln("__Pyx_DECREF(%s);" % self.as_pyobject(cname, type))
1243 self.putln("Py_DECREF(%s);" % self.as_pyobject(cname, type))
1245 def put_var_gotref(self, entry):
1246 if entry.type.is_pyobject:
1247 self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry))
1249 def put_var_giveref(self, entry):
1250 if entry.type.is_pyobject:
1251 self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry))
1253 def put_var_xgotref(self, entry):
1254 if entry.type.is_pyobject:
1255 self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry))
1257 def put_var_xgiveref(self, entry):
1258 if entry.type.is_pyobject:
1259 self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry))
1261 def put_var_incref(self, entry):
1262 if entry.type.is_pyobject:
1263 self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
1265 def put_decref_clear(self, cname, type, nanny=True):
1266 from PyrexTypes import py_object_type, typecast
1268 self.putln("__Pyx_DECREF(%s); %s = 0;" % (
1269 typecast(py_object_type, type, cname), cname))
1271 self.putln("Py_DECREF(%s); %s = 0;" % (
1272 typecast(py_object_type, type, cname), cname))
1274 def put_xdecref(self, cname, type, nanny=True):
1276 self.putln("__Pyx_XDECREF(%s);" % self.as_pyobject(cname, type))
1278 self.putln("Py_XDECREF(%s);" % self.as_pyobject(cname, type))
1280 def put_xdecref_clear(self, cname, type, nanny=True):
1282 self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
1283 self.as_pyobject(cname, type), cname))
1285 self.putln("Py_XDECREF(%s); %s = 0;" % (
1286 self.as_pyobject(cname, type), cname))
1288 def put_var_decref(self, entry):
1289 if entry.type.is_pyobject:
1290 if entry.init_to_none is False: # FIXME: 0 and False are treated differently???
1291 self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
1293 self.putln("__Pyx_DECREF(%s);" % self.entry_as_pyobject(entry))
1295 def put_var_decref_clear(self, entry):
1296 if entry.type.is_pyobject:
1297 self.putln("__Pyx_DECREF(%s); %s = 0;" % (
1298 self.entry_as_pyobject(entry), entry.cname))
1300 def put_var_xdecref(self, entry):
1301 if entry.type.is_pyobject:
1302 self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
1304 def put_var_xdecref_clear(self, entry):
1305 if entry.type.is_pyobject:
1306 self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
1307 self.entry_as_pyobject(entry), entry.cname))
1309 def put_var_decrefs(self, entries, used_only = 0):
1310 for entry in entries:
1311 if not used_only or entry.used:
1312 if entry.xdecref_cleanup:
1313 self.put_var_xdecref(entry)
1315 self.put_var_decref(entry)
1317 def put_var_xdecrefs(self, entries):
1318 for entry in entries:
1319 self.put_var_xdecref(entry)
1321 def put_var_xdecrefs_clear(self, entries):
1322 for entry in entries:
1323 self.put_var_xdecref_clear(entry)
1325 def put_init_to_py_none(self, cname, type, nanny=True):
1326 from PyrexTypes import py_object_type, typecast
1327 py_none = typecast(type, py_object_type, "Py_None")
1329 self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none))
1331 self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none))
1333 def put_init_var_to_py_none(self, entry, template = "%s", nanny=True):
1334 code = template % entry.cname
1335 #if entry.type.is_extension_type:
1336 # code = "((PyObject*)%s)" % code
1337 self.put_init_to_py_none(code, entry.type, nanny)
1338 if entry.in_closure:
1339 self.put_giveref('Py_None')
1341 def put_pymethoddef(self, entry, term, allow_skip=True):
1342 if entry.is_special or entry.name == '__getattribute__':
1343 if entry.name not in ['__cinit__', '__dealloc__', '__richcmp__', '__next__', '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', '__getcharbuffer__', '__getbuffer__', '__releasebuffer__']:
1344 if entry.name == '__getattr__' and not self.globalstate.directives['fast_getattr']:
1346 # Python's typeobject.c will automatically fill in our slot
1347 # in add_operators() (called by PyType_Ready) with a value
1348 # that's better than ours.
1351 from TypeSlots import method_coexist
1353 doc_code = entry.doc_cname
1356 method_flags = entry.signature.method_flags()
1358 if entry.is_special:
1359 method_flags += [method_coexist]
1361 '{__Pyx_NAMESTR("%s"), (PyCFunction)%s, %s, __Pyx_DOCSTR(%s)}%s' % (
1364 "|".join(method_flags),
1370 def put_error_if_neg(self, pos, value):
1371 # return self.putln("if (unlikely(%s < 0)) %s" % (value, self.error_goto(pos))) # TODO this path is almost _never_ taken, yet this macro makes is slower!
1372 return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
1374 def set_error_info(self, pos):
1375 if self.c_line_in_traceback:
1376 cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
1379 return "%s = %s[%s]; %s = %s;%s" % (
1380 Naming.filename_cname,
1381 Naming.filetable_cname,
1382 self.lookup_filename(pos[0]),
1383 Naming.lineno_cname,
1387 def error_goto(self, pos):
1388 lbl = self.funcstate.error_label
1389 self.funcstate.use_label(lbl)
1390 return "{%s goto %s;}" % (
1391 self.set_error_info(pos),
1394 def error_goto_if(self, cond, pos):
1395 return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
1397 def error_goto_if_null(self, cname, pos):
1398 return self.error_goto_if("!%s" % cname, pos)
1400 def error_goto_if_neg(self, cname, pos):
1401 return self.error_goto_if("%s < 0" % cname, pos)
1403 def error_goto_if_PyErr(self, pos):
1404 return self.error_goto_if("PyErr_Occurred()", pos)
1406 def lookup_filename(self, filename):
1407 return self.globalstate.lookup_filename(filename)
1409 def put_declare_refcount_context(self):
1410 self.putln('__Pyx_RefNannyDeclarations')
1412 def put_setup_refcount_context(self, name):
1413 self.putln('__Pyx_RefNannySetupContext("%s");' % name)
1415 def put_finish_refcount_context(self):
1416 self.putln("__Pyx_RefNannyFinishContext();")
1418 def put_trace_declarations(self):
1419 self.putln('__Pyx_TraceDeclarations');
1421 def put_trace_call(self, name, pos):
1422 self.putln('__Pyx_TraceCall("%s", %s[%s], %s);' % (name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1]));
1424 def put_trace_exception(self):
1425 self.putln("__Pyx_TraceException();")
1427 def put_trace_return(self, retvalue_cname):
1428 self.putln("__Pyx_TraceReturn(%s);" % retvalue_cname)
1431 class PyrexCodeWriter(object):
1432 # f file output file
1433 # level int indentation level
1435 def __init__(self, outfile_name):
1436 self.f = Utils.open_new_file(outfile_name)
1439 def putln(self, code):
1440 self.f.write("%s%s\n" % (" " * self.level, code))
1449 class ClosureTempAllocator(object):
1450 def __init__(self, klass):
1452 self.temps_allocated = {}
1453 self.temps_free = {}
1454 self.temps_count = 0
1457 for type, cnames in self.temps_allocated.items():
1458 self.temps_free[type] = list(cnames)
1460 def allocate_temp(self, type):
1461 if not type in self.temps_allocated:
1462 self.temps_allocated[type] = []
1463 self.temps_free[type] = []
1464 elif self.temps_free[type]:
1465 return self.temps_free[type].pop(0)
1466 cname = '%s%d' % (Naming.codewriter_temp_prefix, self.temps_count)
1467 self.klass.declare_var(pos=None, name=cname, cname=cname, type=type, is_cdef=True)
1468 self.temps_allocated[type].append(cname)
1469 self.temps_count += 1