1 # cython: language_level = 3
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
26 class UtilityCode(object):
27 # Stores utility code to add during code generation.
29 # See GlobalState.put_utility_code.
31 # hashes/equals by instance
33 def __init__(self, proto=None, impl=None, init=None, cleanup=None, requires=None,
34 proto_block='utility_code_proto'):
35 # proto_block: Which code block to dump prototype in. See GlobalState.
39 self.cleanup = cleanup
40 self.requires = requires
42 self.specialize_list = []
43 self.proto_block = proto_block
45 def specialize(self, pyrex_type=None, **data):
46 # Dicts aren't hashable...
47 if pyrex_type is not None:
48 data['type'] = pyrex_type.declaration_code('')
49 data['type_name'] = pyrex_type.specialization_name()
50 key = data.items(); key.sort(); key = tuple(key)
52 return self._cache[key]
54 if self.requires is None:
57 requires = [r.specialize(data) for r in self.requires]
58 s = self._cache[key] = UtilityCode(
59 none_or_sub(self.proto, data),
60 none_or_sub(self.impl, data),
61 none_or_sub(self.init, data),
62 none_or_sub(self.cleanup, data),
63 requires, self.proto_block)
64 self.specialize_list.append(s)
67 def put_code(self, output):
69 for dependency in self.requires:
70 output.use_utility_code(dependency)
72 output[self.proto_block].put(self.proto)
74 output['utility_code_def'].put(self.impl)
76 writer = output['init_globals']
77 if isinstance(self.init, basestring):
80 self.init(writer, output.module_pos)
81 if self.cleanup and Options.generate_cleanup_code:
82 writer = output['cleanup_globals']
83 if isinstance(self.cleanup, basestring):
84 writer.put(self.cleanup)
86 self.cleanup(writer, output.module_pos)
90 class FunctionState(object):
91 # return_label string function return point label
92 # error_label string error catch point label
93 # continue_label string loop continue point label
94 # break_label string loop break point label
95 # return_from_error_cleanup_label string
96 # label_counter integer counter for naming labels
97 # in_try_finally boolean inside try of try...finally
98 # exc_vars (string * 3) exception variables for reraise, or None
100 # Not used for now, perhaps later
101 def __init__(self, owner, names_taken=cython.set()):
102 self.names_taken = names_taken
105 self.error_label = None
106 self.label_counter = 0
107 self.labels_used = cython.set()
108 self.return_label = self.new_label()
109 self.new_error_label()
110 self.continue_label = None
111 self.break_label = None
113 self.in_try_finally = 0
116 self.temps_allocated = [] # of (name, type, manage_ref)
117 self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
118 self.temps_used_type = {} # name -> (type, manage_ref)
119 self.temp_counter = 0
120 self.closure_temps = None
124 def new_label(self, name=None):
125 n = self.label_counter
126 self.label_counter = n + 1
127 label = "%s%d" % (Naming.label_prefix, n)
132 def new_error_label(self):
133 old_err_lbl = self.error_label
134 self.error_label = self.new_label('error')
137 def get_loop_labels(self):
142 def set_loop_labels(self, labels):
143 (self.continue_label,
144 self.break_label) = labels
146 def new_loop_labels(self):
147 old_labels = self.get_loop_labels()
148 self.set_loop_labels(
149 (self.new_label("continue"),
150 self.new_label("break")))
153 def get_all_labels(self):
160 def set_all_labels(self, labels):
161 (self.continue_label,
164 self.error_label) = labels
166 def all_new_labels(self):
167 old_labels = self.get_all_labels()
169 for old_label in old_labels:
171 new_labels.append(self.new_label())
173 new_labels.append(old_label)
174 self.set_all_labels(new_labels)
177 def use_label(self, lbl):
178 self.labels_used.add(lbl)
180 def label_used(self, lbl):
181 return lbl in self.labels_used
185 def allocate_temp(self, type, manage_ref):
187 Allocates a temporary (which may create a new one or get a previously
188 allocated and released one of the same type). Type is simply registered
189 and handed back, but will usually be a PyrexType.
191 If type.is_pyobject, manage_ref comes into play. If manage_ref is set to
192 True, the temp will be decref-ed on return statements and in exception
193 handling clauses. Otherwise the caller has to deal with any reference
194 counting of the variable.
196 If not type.is_pyobject, then manage_ref will be ignored, but it
197 still has to be passed. It is recommended to pass False by convention
198 if it is known that type will never be a Python object.
200 A C string referring to the variable is returned.
202 if not type.is_pyobject:
203 # Make manage_ref canonical, so that manage_ref will always mean
204 # a decref is needed.
206 freelist = self.temps_free.get((type, manage_ref))
207 if freelist is not None and len(freelist) > 0:
208 result = freelist.pop()
211 self.temp_counter += 1
212 result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter)
213 if not result in self.names_taken: break
214 self.temps_allocated.append((result, type, manage_ref))
215 self.temps_used_type[result] = (type, manage_ref)
216 if DebugFlags.debug_temp_code_comments:
217 self.owner.putln("/* %s allocated */" % result)
220 def release_temp(self, name):
222 Releases a temporary so that it can be reused by other code needing
223 a temp of the same type.
225 type, manage_ref = self.temps_used_type[name]
226 freelist = self.temps_free.get((type, manage_ref))
229 self.temps_free[(type, manage_ref)] = freelist
231 raise RuntimeError("Temp %s freed twice!" % name)
232 freelist.append(name)
233 if DebugFlags.debug_temp_code_comments:
234 self.owner.putln("/* %s released */" % name)
236 def temps_in_use(self):
237 """Return a list of (cname,type,manage_ref) tuples of temp names and their type
238 that are currently in use.
241 for name, type, manage_ref in self.temps_allocated:
242 freelist = self.temps_free.get((type, manage_ref))
243 if freelist is None or name not in freelist:
244 used.append((name, type, manage_ref))
247 def temps_holding_reference(self):
248 """Return a list of (cname,type) tuples of temp names and their type
249 that are currently in use. This includes only temps of a
250 Python object type which owns its reference.
253 for name, type, manage_ref in self.temps_in_use()
256 def all_managed_temps(self):
257 """Return a list of (cname, type) tuples of refcount-managed Python objects.
259 return [(cname, type)
260 for cname, type, manage_ref in self.temps_allocated
263 def all_free_managed_temps(self):
264 """Return a list of (cname, type) tuples of refcount-managed Python
265 objects that are not currently in use. This is used by
266 try-except and try-finally blocks to clean up temps in the
269 return [(cname, type)
270 for (type, manage_ref), freelist in self.temps_free.items()
272 for cname in freelist]
274 def init_closure_temps(self, scope):
275 self.closure_temps = ClosureTempAllocator(scope)
278 class IntConst(object):
279 """Global info about a Python integer constant held by GlobalState.
285 def __init__(self, cname, value, is_long):
288 self.is_long = is_long
290 class PyObjectConst(object):
291 """Global info about a generic constant held by GlobalState.
296 def __init__(self, cname, type):
300 cython.declare(possible_unicode_identifier=object, possible_bytes_identifier=object,
301 nice_identifier=object, find_alphanums=object)
302 possible_unicode_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
303 possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match
304 nice_identifier = re.compile(r'\A[a-zA-Z0-9_]+\Z').match
305 find_alphanums = re.compile('([a-zA-Z0-9]+)').findall
307 class StringConst(object):
308 """Global info about a C string constant held by GlobalState.
311 # text EncodedString or BytesLiteral
312 # py_strings {(identifier, encoding) : PyStringConst}
314 def __init__(self, cname, text, byte_string):
317 self.escaped_value = StringEncoding.escape_byte_string(byte_string)
318 self.py_strings = None
320 def get_py_string_const(self, encoding, identifier=None, is_str=False):
321 py_strings = self.py_strings
324 is_str = bool(identifier or is_str)
325 is_unicode = encoding is None and not is_str
332 encoding = encoding.lower()
333 if encoding in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'):
337 encoding_key = ''.join(find_alphanums(encoding))
339 key = (is_str, is_unicode, encoding_key)
340 if py_strings is not None and key in py_strings:
341 py_string = py_strings[key]
343 if py_strings is None:
347 elif identifier is None:
348 if isinstance(text, unicode):
349 intern = bool(possible_unicode_identifier(text))
351 intern = bool(possible_bytes_identifier(text))
355 prefix = Naming.interned_str_prefix
357 prefix = Naming.py_const_prefix
358 pystring_cname = "%s%s_%s" % (
360 (is_str and 's') or (is_unicode and 'u') or 'b',
361 self.cname[len(Naming.const_prefix):])
363 py_string = PyStringConst(
364 pystring_cname, encoding, is_unicode, is_str, intern)
365 self.py_strings[key] = py_string
369 class PyStringConst(object):
370 """Global info about a Python string constant held by GlobalState.
378 def __init__(self, cname, encoding, is_unicode, is_str=False, intern=False):
380 self.encoding = encoding
382 self.is_unicode = is_unicode
385 def __lt__(self, other):
386 return self.cname < other.cname
389 class GlobalState(object):
390 # filename_table {string : int} for finding filename table indexes
391 # filename_list [string] filenames in filename table order
392 # input_file_contents dict contents (=list of lines) of any file that was used as input
393 # to create this output C code. This is
394 # used to annotate the comments.
396 # utility_codes set IDs of used utility code (to avoid reinsertion)
398 # declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
399 # constants etc. into the pyx-declared ones (i.e,
400 # check if constants are already added).
401 # In time, hopefully the literals etc. will be
402 # supplied directly instead.
404 # const_cname_counter int global counter for constant identifiers
407 # parts {string:CCodeWriter}
414 # directives set Temporary variable used to track
415 # the current set of directives in the code generation
423 'utility_code_proto_before_types',
424 'numeric_typedefs', # Let these detailed individual parts stay!,
425 'complex_type_declarations', # as the proper solution is to make a full DAG...
426 'type_declarations', # More coarse-grained blocks would simply hide
427 'utility_code_proto', # the ugliness, not fix it
428 'module_declarations',
447 def __init__(self, writer, emit_linenums=False):
448 self.filename_table = {}
449 self.filename_list = []
450 self.input_file_contents = {}
451 self.utility_codes = cython.set()
452 self.declared_cnames = {}
453 self.in_utility_code_generation = False
454 self.emit_linenums = emit_linenums
457 self.const_cname_counter = 1
458 self.string_const_index = {}
459 self.int_const_index = {}
460 self.py_constants = []
462 assert writer.globalstate is None
463 writer.globalstate = self
464 self.rootwriter = writer
466 def initialize_main_c_code(self):
467 rootwriter = self.rootwriter
468 for part in self.code_layout:
469 self.parts[part] = rootwriter.insertion_point()
471 if not Options.cache_builtins:
472 del self.parts['cached_builtins']
474 w = self.parts['cached_builtins']
475 w.enter_cfunc_scope()
476 w.putln("static int __Pyx_InitCachedBuiltins(void) {")
478 w = self.parts['cached_constants']
479 w.enter_cfunc_scope()
481 w.putln("static int __Pyx_InitCachedConstants(void) {")
482 w.put_declare_refcount_context()
483 w.put_setup_refcount_context("__Pyx_InitCachedConstants")
485 w = self.parts['init_globals']
486 w.enter_cfunc_scope()
488 w.putln("static int __Pyx_InitGlobals(void) {")
490 if not Options.generate_cleanup_code:
491 del self.parts['cleanup_globals']
493 w = self.parts['cleanup_globals']
494 w.enter_cfunc_scope()
496 w.putln("static void __Pyx_CleanupGlobals(void) {")
501 code = self.parts['utility_code_def']
502 if self.emit_linenums:
503 code.write('\n#line 1 "cython_utility"\n')
505 code.putln("/* Runtime support code */")
507 def finalize_main_c_code(self):
508 self.close_global_decls()
513 code = self.parts['utility_code_def']
515 code.put(PyrexTypes.type_conversion_functions)
518 def __getitem__(self, key):
519 return self.parts[key]
522 # Global constants, interned objects, etc.
524 def close_global_decls(self):
525 # This is called when it is known that no more global declarations will
527 self.generate_const_declarations()
528 if Options.cache_builtins:
529 w = self.parts['cached_builtins']
531 if w.label_used(w.error_label):
532 w.put_label(w.error_label)
533 w.putln("return -1;")
537 w = self.parts['cached_constants']
538 w.put_finish_refcount_context()
540 if w.label_used(w.error_label):
541 w.put_label(w.error_label)
542 w.put_finish_refcount_context()
543 w.putln("return -1;")
547 w = self.parts['init_globals']
549 if w.label_used(w.error_label):
550 w.put_label(w.error_label)
551 w.putln("return -1;")
555 if Options.generate_cleanup_code:
556 w = self.parts['cleanup_globals']
560 if Options.generate_cleanup_code:
561 w = self.parts['cleanup_module']
565 def put_pyobject_decl(self, entry):
566 self['global_var'].putln("static PyObject *%s;" % entry.cname)
568 # constant handling at code generation time
570 def get_cached_constants_writer(self):
571 return self.parts['cached_constants']
573 def get_int_const(self, str_value, longness=False):
574 longness = bool(longness)
576 c = self.int_const_index[(str_value, longness)]
578 c = self.new_int_const(str_value, longness)
581 def get_py_const(self, type, prefix='', cleanup_level=None):
582 # create a new Python object constant
583 const = self.new_py_const(type, prefix)
584 if cleanup_level is not None \
585 and cleanup_level <= Options.generate_cleanup_code:
586 cleanup_writer = self.parts['cleanup_globals']
587 cleanup_writer.put_xdecref_clear(const.cname, type, nanny=False)
590 def get_string_const(self, text):
591 # return a C string constant, creating a new one if necessary
593 byte_string = text.utf8encode()
595 byte_string = text.byteencode()
597 c = self.string_const_index[byte_string]
599 c = self.new_string_const(text, byte_string)
602 def get_py_string_const(self, text, identifier=None, is_str=False):
603 # return a Python string constant, creating a new one if necessary
604 c_string = self.get_string_const(text)
605 py_string = c_string.get_py_string_const(text.encoding, identifier, is_str)
608 def get_interned_identifier(self, text):
609 return self.get_py_string_const(text, identifier=True)
611 def new_string_const(self, text, byte_string):
612 cname = self.new_string_const_cname(byte_string)
613 c = StringConst(cname, text, byte_string)
614 self.string_const_index[byte_string] = c
617 def new_int_const(self, value, longness):
618 cname = self.new_int_const_cname(value, longness)
619 c = IntConst(cname, value, longness)
620 self.int_const_index[(value, longness)] = c
623 def new_py_const(self, type, prefix=''):
624 cname = self.new_const_cname(prefix)
625 c = PyObjectConst(cname, type)
626 self.py_constants.append(c)
629 def new_string_const_cname(self, bytes_value, intern=None):
630 # Create a new globally-unique nice name for a C string constant.
632 value = bytes_value.decode('ASCII')
634 return self.new_const_cname()
636 if len(value) < 20 and nice_identifier(value):
637 return "%s_%s" % (Naming.const_prefix, value)
639 return self.new_const_cname()
641 def new_int_const_cname(self, value, longness):
644 cname = "%s%s" % (Naming.interned_num_prefix, value)
645 cname = cname.replace('-', 'neg_').replace('.','_')
648 def new_const_cname(self, prefix=''):
649 n = self.const_cname_counter
650 self.const_cname_counter += 1
651 return "%s%s%d" % (Naming.const_prefix, prefix, n)
653 def add_cached_builtin_decl(self, entry):
654 if Options.cache_builtins:
655 if self.should_declare(entry.cname, entry):
656 self.put_pyobject_decl(entry)
657 w = self.parts['cached_builtins']
658 if entry.name == 'xrange':
659 # replaced by range() in Py3
660 w.putln('#if PY_MAJOR_VERSION >= 3')
661 self.put_cached_builtin_init(
662 entry.pos, StringEncoding.EncodedString('range'),
665 self.put_cached_builtin_init(
666 entry.pos, StringEncoding.EncodedString(entry.name),
668 if entry.name == 'xrange':
671 def put_cached_builtin_init(self, pos, name, cname):
672 w = self.parts['cached_builtins']
673 interned_cname = self.get_interned_identifier(name).cname
674 from ExprNodes import get_name_interned_utility_code
675 self.use_utility_code(get_name_interned_utility_code)
676 w.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
678 Naming.builtins_cname,
683 def generate_const_declarations(self):
684 self.generate_string_constants()
685 self.generate_int_constants()
686 self.generate_object_constant_decls()
688 def generate_object_constant_decls(self):
689 consts = [ (len(c.cname), c.cname, c)
690 for c in self.py_constants ]
692 decls_writer = self.parts['decls']
693 for _, cname, c in consts:
695 "static %s;" % c.type.declaration_code(cname))
697 def generate_string_constants(self):
698 c_consts = [ (len(c.cname), c.cname, c)
699 for c in self.string_const_index.values() ]
703 decls_writer = self.parts['decls']
704 for _, cname, c in c_consts:
705 decls_writer.putln('static char %s[] = "%s";' % (
706 cname, StringEncoding.split_string_literal(c.escaped_value)))
707 if c.py_strings is not None:
708 for py_string in c.py_strings.values():
709 py_strings.append((c.cname, len(py_string.cname), py_string))
713 self.use_utility_code(Nodes.init_string_tab_utility_code)
716 w = self.parts['pystring_table']
718 w.putln("static __Pyx_StringTabEntry %s[] = {" %
719 Naming.stringtab_cname)
720 for c_cname, _, py_string in py_strings:
721 if not py_string.is_str or not py_string.encoding or \
722 py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII',
726 encoding = '"%s"' % py_string.encoding.lower()
729 "static PyObject *%s;" % py_string.cname)
731 "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
736 py_string.is_unicode,
740 w.putln("{0, 0, 0, 0, 0, 0, 0}")
743 init_globals = self.parts['init_globals']
745 "if (__Pyx_InitStrings(%s) < 0) %s;" % (
746 Naming.stringtab_cname,
747 init_globals.error_goto(self.module_pos)))
749 def generate_int_constants(self):
750 consts = [ (len(c.value), c.value, c.is_long, c)
751 for c in self.int_const_index.values() ]
753 decls_writer = self.parts['decls']
754 for _, value, longness, c in consts:
756 decls_writer.putln("static PyObject *%s;" % cname)
758 function = '%s = PyLong_FromString((char *)"%s", 0, 0); %s;'
759 elif Utils.long_literal(value):
760 function = '%s = PyInt_FromString((char *)"%s", 0, 0); %s;'
762 function = "%s = PyInt_FromLong(%s); %s;"
763 init_globals = self.parts['init_globals']
764 init_globals.putln(function % (
767 init_globals.error_goto_if_null(cname, self.module_pos)))
769 # The functions below are there in a transition phase only
770 # and will be deprecated. They are called from Nodes.BlockNode.
771 # The copy&paste duplication is intentional in order to be able
772 # to see quickly how BlockNode worked, until this is replaced.
774 def should_declare(self, cname, entry):
775 if cname in self.declared_cnames:
776 other = self.declared_cnames[cname]
777 assert str(entry.type) == str(other.type)
778 assert entry.init == other.init
781 self.declared_cnames[cname] = entry
788 def lookup_filename(self, filename):
790 index = self.filename_table[filename]
792 index = len(self.filename_list)
793 self.filename_list.append(filename)
794 self.filename_table[filename] = index
797 def commented_file_contents(self, source_desc):
799 return self.input_file_contents[source_desc]
802 source_file = source_desc.get_lines(encoding='ASCII',
803 error_handling='ignore')
805 F = [u' * ' + line.rstrip().replace(
806 u'*/', u'*[inserted by cython to avoid comment closer]/'
808 u'/*', u'/[inserted by cython to avoid comment start]*'
810 for line in source_file]
812 if hasattr(source_file, 'close'):
814 if not F: F.append(u'')
815 self.input_file_contents[source_desc] = F
822 def use_utility_code(self, utility_code):
824 Adds code to the C file. utility_code should
825 a) implement __eq__/__hash__ for the purpose of knowing whether the same
826 code has already been included
827 b) implement put_code, which takes a globalstate instance
831 if utility_code not in self.utility_codes:
832 self.utility_codes.add(utility_code)
833 utility_code.put_code(self)
836 def funccontext_property(name):
839 attribute_of = operator.attrgetter(name)
842 return getattr(o, name)
845 return attribute_of(self.funcstate)
846 def set(self, value):
847 setattr(self.funcstate, name, value)
848 return property(get, set)
851 class CCodeWriter(object):
853 Utility class to output C code.
855 When creating an insertion point one must care about the state that is
857 - formatting state (level, bol) is cloned and used in insertion points
859 - labels, temps, exc_vars: One must construct a scope in which these can
860 exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
861 sanity checking and forward compatabilty). Created insertion points
862 looses this scope and cannot access it.
863 - marker: Not copied to insertion point
864 - filename_table, filename_list, input_file_contents: All codewriters
865 coming from the same root share the same instances simultaneously.
869 # buffer StringIOTree
871 # level int indentation level
872 # bol bool beginning of line?
873 # marker string comment to emit before next line
874 # funcstate FunctionState contains state local to a C function used for code
875 # generation (labels and temps state etc.)
876 # globalstate GlobalState contains state global for a C file (input file info,
877 # utility code, declared constants etc.)
878 # emit_linenums boolean whether or not to write #line pragmas
880 # c_line_in_traceback boolean append the c file and line number to the traceback for exceptions
882 # pyclass_stack list used during recursive code generation to pass information
883 # about the current class one is in
887 def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None, c_line_in_traceback=True):
888 if buffer is None: buffer = StringIOTree()
891 self.last_marker_line = 0
892 self.source_desc = ""
893 self.pyclass_stack = []
895 self.funcstate = None
900 if create_from is not None:
901 # Use same global state
902 self.globalstate = create_from.globalstate
903 # Clone formatting state
905 self.level = create_from.level
906 self.bol = create_from.bol
907 self.call_level = create_from.call_level
908 if emit_linenums is None and self.globalstate:
909 self.emit_linenums = self.globalstate.emit_linenums
911 self.emit_linenums = emit_linenums
912 self.c_line_in_traceback = c_line_in_traceback
914 def create_new(self, create_from, buffer, copy_formatting):
915 # polymorphic constructor -- very slightly more versatile
916 # than using __class__
917 result = CCodeWriter(create_from, buffer, copy_formatting, c_line_in_traceback=self.c_line_in_traceback)
921 self.buffer.copyto(f)
924 return self.buffer.getvalue()
927 # also put invalid markers (lineno 0), to indicate that those lines
928 # have no Cython source code correspondence
929 if self.marker is None:
930 cython_lineno = self.last_marker_line
932 cython_lineno = self.marker[0]
934 self.buffer.markers.extend([cython_lineno] * s.count('\n'))
937 def insertion_point(self):
938 other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
941 def new_writer(self):
943 Creates a new CCodeWriter connected to the same global state, which
944 can later be inserted using insert.
946 return CCodeWriter(create_from=self, c_line_in_traceback=self.c_line_in_traceback)
948 def insert(self, writer):
950 Inserts the contents of another code writer (created with
951 the same global state) in the current location.
953 It is ok to write to the inserted writer also after insertion.
955 assert writer.globalstate is self.globalstate
956 self.buffer.insert(writer.buffer)
958 # Properties delegated to function scope
959 label_counter = funccontext_property("label_counter")
960 return_label = funccontext_property("return_label")
961 error_label = funccontext_property("error_label")
962 labels_used = funccontext_property("labels_used")
963 continue_label = funccontext_property("continue_label")
964 break_label = funccontext_property("break_label")
965 return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
967 # Functions delegated to function scope
968 def new_label(self, name=None): return self.funcstate.new_label(name)
969 def new_error_label(self): return self.funcstate.new_error_label()
970 def get_loop_labels(self): return self.funcstate.get_loop_labels()
971 def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
972 def new_loop_labels(self): return self.funcstate.new_loop_labels()
973 def get_all_labels(self): return self.funcstate.get_all_labels()
974 def set_all_labels(self, labels): return self.funcstate.set_all_labels(labels)
975 def all_new_labels(self): return self.funcstate.all_new_labels()
976 def use_label(self, lbl): return self.funcstate.use_label(lbl)
977 def label_used(self, lbl): return self.funcstate.label_used(lbl)
980 def enter_cfunc_scope(self):
981 self.funcstate = FunctionState(self)
983 def exit_cfunc_scope(self):
984 self.funcstate = None
988 def get_py_num(self, str_value, longness):
989 return self.globalstate.get_int_const(str_value, longness).cname
991 def get_py_const(self, type, prefix='', cleanup_level=None):
992 return self.globalstate.get_py_const(type, prefix, cleanup_level).cname
994 def get_string_const(self, text):
995 return self.globalstate.get_string_const(text).cname
997 def get_py_string_const(self, text, identifier=None, is_str=False):
998 return self.globalstate.get_py_string_const(text, identifier, is_str).cname
1000 def get_argument_default_const(self, type):
1001 return self.globalstate.get_py_const(type).cname
1003 def intern(self, text):
1004 return self.get_py_string_const(text)
1006 def intern_identifier(self, text):
1007 return self.get_py_string_const(text, identifier=True)
1009 def get_cached_constants_writer(self):
1010 return self.globalstate.get_cached_constants_writer()
1014 def putln(self, code = "", safe=False):
1015 if self.marker and self.bol:
1017 if self.emit_linenums and self.last_marker_line != 0:
1018 self.write('\n#line %s "%s"\n' % (self.last_marker_line, self.source_desc))
1028 def emit_marker(self):
1031 self.write("/* %s */\n" % self.marker[1])
1032 self.last_marker_line = self.marker[0]
1035 def put_safe(self, code):
1036 # put code, but ignore {}
1040 def put(self, code):
1043 dl = code.count("{")
1047 dl -= code.count("}")
1050 elif dl == 0 and code[0] == "}":
1051 # special cases like "} else {" need a temporary dedent
1063 def increase_indent(self):
1064 self.level = self.level + 1
1066 def decrease_indent(self):
1067 self.level = self.level - 1
1069 def begin_block(self):
1071 self.increase_indent()
1073 def end_block(self):
1074 self.decrease_indent()
1078 self.write(" " * self.level)
1080 def get_py_version_hex(self, pyversion):
1081 return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
1083 def mark_pos(self, pos):
1086 source_desc, line, col = pos
1087 if self.last_marker_line == line:
1089 assert isinstance(source_desc, SourceDescriptor)
1090 contents = self.globalstate.commented_file_contents(source_desc)
1091 lines = contents[max(0,line-3):line] # line numbers start at 1
1092 lines[-1] += u' # <<<<<<<<<<<<<<'
1093 lines += contents[line:line+2]
1095 marker = u'"%s":%d\n%s\n' % (
1096 source_desc.get_escaped_description(), line, u'\n'.join(lines))
1097 self.marker = (line, marker)
1098 if self.emit_linenums:
1099 self.source_desc = source_desc.get_escaped_description()
1101 def put_label(self, lbl):
1102 if lbl in self.funcstate.labels_used:
1103 self.putln("%s:;" % lbl)
1105 def put_goto(self, lbl):
1106 self.funcstate.use_label(lbl)
1107 self.putln("goto %s;" % lbl)
1109 def put_var_declarations(self, entries, static = 0, dll_linkage = None,
1111 for entry in entries:
1112 if not entry.in_cinclude:
1113 self.put_var_declaration(entry, static, dll_linkage, definition)
1115 def put_var_declaration(self, entry, static = 0, dll_linkage = None,
1117 #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
1118 if entry.in_closure:
1120 visibility = entry.visibility
1121 if visibility == 'private' and not definition:
1122 #print "...private and not definition, skipping" ###
1124 if not entry.used and visibility == "private":
1125 #print "not used and private, skipping", entry.cname ###
1128 if visibility == 'extern':
1129 storage_class = Naming.extern_c_macro
1130 elif visibility == 'public':
1132 storage_class = Naming.extern_c_macro
1133 elif visibility == 'private':
1135 storage_class = "static"
1137 self.put("%s " % storage_class)
1138 if visibility != 'public':
1140 self.put(entry.type.declaration_code(entry.cname,
1141 dll_linkage = dll_linkage))
1142 if entry.init is not None:
1143 self.put_safe(" = %s" % entry.type.literal_code(entry.init))
1146 def put_temp_declarations(self, func_context):
1147 for name, type, manage_ref in func_context.temps_allocated:
1148 decl = type.declaration_code(name)
1149 if type.is_pyobject:
1150 self.putln("%s = NULL;" % decl)
1152 self.putln("%s;" % decl)
1154 def put_h_guard(self, guard):
1155 self.putln("#ifndef %s" % guard)
1156 self.putln("#define %s" % guard)
1158 def unlikely(self, cond):
1159 if Options.gcc_branch_hints:
1160 return 'unlikely(%s)' % cond
1164 # Python objects and reference counting
1166 def entry_as_pyobject(self, entry):
1168 if (not entry.is_self_arg and not entry.type.is_complete()
1169 or entry.type.is_extension_type):
1170 return "(PyObject *)" + entry.cname
1174 def as_pyobject(self, cname, type):
1175 from PyrexTypes import py_object_type, typecast
1176 return typecast(py_object_type, type, cname)
1178 def put_gotref(self, cname):
1179 self.putln("__Pyx_GOTREF(%s);" % cname)
1181 def put_giveref(self, cname):
1182 self.putln("__Pyx_GIVEREF(%s);" % cname)
1184 def put_xgiveref(self, cname):
1185 self.putln("__Pyx_XGIVEREF(%s);" % cname)
1187 def put_xgotref(self, cname):
1188 self.putln("__Pyx_XGOTREF(%s);" % cname)
1190 def put_incref(self, cname, type, nanny=True):
1192 self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
1194 self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
1196 def put_decref(self, cname, type, nanny=True):
1198 self.putln("__Pyx_DECREF(%s);" % self.as_pyobject(cname, type))
1200 self.putln("Py_DECREF(%s);" % self.as_pyobject(cname, type))
1202 def put_var_gotref(self, entry):
1203 if entry.type.is_pyobject:
1204 self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry))
1206 def put_var_giveref(self, entry):
1207 if entry.type.is_pyobject:
1208 self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry))
1210 def put_var_xgotref(self, entry):
1211 if entry.type.is_pyobject:
1212 self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry))
1214 def put_var_xgiveref(self, entry):
1215 if entry.type.is_pyobject:
1216 self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry))
1218 def put_var_incref(self, entry):
1219 if entry.type.is_pyobject:
1220 self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
1222 def put_decref_clear(self, cname, type, nanny=True):
1223 from PyrexTypes import py_object_type, typecast
1225 self.putln("__Pyx_DECREF(%s); %s = 0;" % (
1226 typecast(py_object_type, type, cname), cname))
1228 self.putln("Py_DECREF(%s); %s = 0;" % (
1229 typecast(py_object_type, type, cname), cname))
1231 def put_xdecref(self, cname, type, nanny=True):
1233 self.putln("__Pyx_XDECREF(%s);" % self.as_pyobject(cname, type))
1235 self.putln("Py_XDECREF(%s);" % self.as_pyobject(cname, type))
1237 def put_xdecref_clear(self, cname, type, nanny=True):
1239 self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
1240 self.as_pyobject(cname, type), cname))
1242 self.putln("Py_XDECREF(%s); %s = 0;" % (
1243 self.as_pyobject(cname, type), cname))
1245 def put_var_decref(self, entry):
1246 if entry.type.is_pyobject:
1247 if entry.init_to_none is False: # FIXME: 0 and False are treated differently???
1248 self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
1250 self.putln("__Pyx_DECREF(%s);" % self.entry_as_pyobject(entry))
1252 def put_var_decref_clear(self, entry):
1253 if entry.type.is_pyobject:
1254 self.putln("__Pyx_DECREF(%s); %s = 0;" % (
1255 self.entry_as_pyobject(entry), entry.cname))
1257 def put_var_xdecref(self, entry):
1258 if entry.type.is_pyobject:
1259 self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
1261 def put_var_xdecref_clear(self, entry):
1262 if entry.type.is_pyobject:
1263 self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
1264 self.entry_as_pyobject(entry), entry.cname))
1266 def put_var_decrefs(self, entries, used_only = 0):
1267 for entry in entries:
1268 if not used_only or entry.used:
1269 if entry.xdecref_cleanup:
1270 self.put_var_xdecref(entry)
1272 self.put_var_decref(entry)
1274 def put_var_xdecrefs(self, entries):
1275 for entry in entries:
1276 self.put_var_xdecref(entry)
1278 def put_var_xdecrefs_clear(self, entries):
1279 for entry in entries:
1280 self.put_var_xdecref_clear(entry)
1282 def put_init_to_py_none(self, cname, type, nanny=True):
1283 from PyrexTypes import py_object_type, typecast
1284 py_none = typecast(type, py_object_type, "Py_None")
1286 self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none))
1288 self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none))
1290 def put_init_var_to_py_none(self, entry, template = "%s", nanny=True):
1291 code = template % entry.cname
1292 #if entry.type.is_extension_type:
1293 # code = "((PyObject*)%s)" % code
1294 self.put_init_to_py_none(code, entry.type, nanny)
1295 if entry.in_closure:
1296 self.put_giveref('Py_None')
1298 def put_pymethoddef(self, entry, term, allow_skip=True):
1299 if entry.is_special or entry.name == '__getattribute__':
1300 if entry.name not in ['__cinit__', '__dealloc__', '__richcmp__', '__next__', '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', '__getcharbuffer__', '__getbuffer__', '__releasebuffer__']:
1301 if entry.name == '__getattr__' and not self.globalstate.directives['fast_getattr']:
1303 # Python's typeobject.c will automatically fill in our slot
1304 # in add_operators() (called by PyType_Ready) with a value
1305 # that's better than ours.
1308 from TypeSlots import method_coexist
1310 doc_code = entry.doc_cname
1313 method_flags = entry.signature.method_flags()
1315 if entry.is_special:
1316 method_flags += [method_coexist]
1318 '{__Pyx_NAMESTR("%s"), (PyCFunction)%s, %s, __Pyx_DOCSTR(%s)}%s' % (
1321 "|".join(method_flags),
1327 def put_error_if_neg(self, pos, value):
1328 # 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!
1329 return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
1331 def set_error_info(self, pos):
1332 if self.c_line_in_traceback:
1333 cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
1336 return "%s = %s[%s]; %s = %s;%s" % (
1337 Naming.filename_cname,
1338 Naming.filetable_cname,
1339 self.lookup_filename(pos[0]),
1340 Naming.lineno_cname,
1344 def error_goto(self, pos):
1345 lbl = self.funcstate.error_label
1346 self.funcstate.use_label(lbl)
1347 return "{%s goto %s;}" % (
1348 self.set_error_info(pos),
1351 def error_goto_if(self, cond, pos):
1352 return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
1354 def error_goto_if_null(self, cname, pos):
1355 return self.error_goto_if("!%s" % cname, pos)
1357 def error_goto_if_neg(self, cname, pos):
1358 return self.error_goto_if("%s < 0" % cname, pos)
1360 def error_goto_if_PyErr(self, pos):
1361 return self.error_goto_if("PyErr_Occurred()", pos)
1363 def lookup_filename(self, filename):
1364 return self.globalstate.lookup_filename(filename)
1366 def put_declare_refcount_context(self):
1367 self.putln('__Pyx_RefNannyDeclareContext;')
1369 def put_setup_refcount_context(self, name):
1370 self.putln('__Pyx_RefNannySetupContext("%s");' % name)
1372 def put_finish_refcount_context(self):
1373 self.putln("__Pyx_RefNannyFinishContext();")
1375 def put_trace_declarations(self):
1376 self.putln('__Pyx_TraceDeclarations');
1378 def put_trace_call(self, name, pos):
1379 self.putln('__Pyx_TraceCall("%s", %s[%s], %s);' % (name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1]));
1381 def put_trace_exception(self):
1382 self.putln("__Pyx_TraceException();")
1384 def put_trace_return(self, retvalue_cname):
1385 self.putln("__Pyx_TraceReturn(%s);" % retvalue_cname)
1388 class PyrexCodeWriter(object):
1389 # f file output file
1390 # level int indentation level
1392 def __init__(self, outfile_name):
1393 self.f = Utils.open_new_file(outfile_name)
1396 def putln(self, code):
1397 self.f.write("%s%s\n" % (" " * self.level, code))
1406 class ClosureTempAllocator(object):
1407 def __init__(self, klass):
1409 self.temps_allocated = {}
1410 self.temps_free = {}
1411 self.temps_count = 0
1414 for type, cnames in self.temps_allocated.items():
1415 self.temps_free[type] = list(cnames)
1417 def allocate_temp(self, type):
1418 if not type in self.temps_allocated:
1419 self.temps_allocated[type] = []
1420 self.temps_free[type] = []
1421 elif self.temps_free[type]:
1422 return self.temps_free[type].pop(0)
1423 cname = '%s%d' % (Naming.codewriter_temp_prefix, self.temps_count)
1424 self.klass.declare_var(pos=None, name=cname, cname=cname, type=type, is_cdef=True)
1425 self.temps_allocated[type].append(cname)
1426 self.temps_count += 1