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
334 self.py_versions = []
336 def add_py_version(self, version):
338 self.py_versions = [2,3]
339 elif version not in self.py_versions:
340 self.py_versions.append(version)
342 def get_py_string_const(self, encoding, identifier=None,
343 is_str=False, py3str_cstring=None):
344 py_strings = self.py_strings
347 is_str = bool(identifier or is_str)
348 is_unicode = encoding is None and not is_str
355 encoding = encoding.lower()
356 if encoding in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'):
360 encoding_key = ''.join(find_alphanums(encoding))
362 key = (is_str, is_unicode, encoding_key, py3str_cstring)
363 if py_strings is not None:
365 return py_strings[key]
373 elif identifier is None:
374 if isinstance(text, unicode):
375 intern = bool(possible_unicode_identifier(text))
377 intern = bool(possible_bytes_identifier(text))
381 prefix = Naming.interned_str_prefix
383 prefix = Naming.py_const_prefix
384 pystring_cname = "%s%s_%s" % (
386 (is_str and 's') or (is_unicode and 'u') or 'b',
387 self.cname[len(Naming.const_prefix):])
389 py_string = PyStringConst(
390 pystring_cname, encoding, is_unicode, is_str, py3str_cstring, intern)
391 self.py_strings[key] = py_string
394 class PyStringConst(object):
395 """Global info about a Python string constant held by GlobalState.
398 # py3str_cstring string
404 def __init__(self, cname, encoding, is_unicode, is_str=False,
405 py3str_cstring=None, intern=False):
407 self.py3str_cstring = py3str_cstring
408 self.encoding = encoding
410 self.is_unicode = is_unicode
413 def __lt__(self, other):
414 return self.cname < other.cname
417 class GlobalState(object):
418 # filename_table {string : int} for finding filename table indexes
419 # filename_list [string] filenames in filename table order
420 # input_file_contents dict contents (=list of lines) of any file that was used as input
421 # to create this output C code. This is
422 # used to annotate the comments.
424 # utility_codes set IDs of used utility code (to avoid reinsertion)
426 # declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
427 # constants etc. into the pyx-declared ones (i.e,
428 # check if constants are already added).
429 # In time, hopefully the literals etc. will be
430 # supplied directly instead.
432 # const_cname_counter int global counter for constant identifiers
435 # parts {string:CCodeWriter}
442 # directives set Temporary variable used to track
443 # the current set of directives in the code generation
451 'utility_code_proto_before_types',
452 'numeric_typedefs', # Let these detailed individual parts stay!,
453 'complex_type_declarations', # as the proper solution is to make a full DAG...
454 'type_declarations', # More coarse-grained blocks would simply hide
455 'utility_code_proto', # the ugliness, not fix it
456 'module_declarations',
475 def __init__(self, writer, emit_linenums=False):
476 self.filename_table = {}
477 self.filename_list = []
478 self.input_file_contents = {}
479 self.utility_codes = cython.set()
480 self.declared_cnames = {}
481 self.in_utility_code_generation = False
482 self.emit_linenums = emit_linenums
485 self.const_cname_counter = 1
486 self.string_const_index = {}
487 self.int_const_index = {}
488 self.py_constants = []
490 assert writer.globalstate is None
491 writer.globalstate = self
492 self.rootwriter = writer
494 def initialize_main_c_code(self):
495 rootwriter = self.rootwriter
496 for part in self.code_layout:
497 self.parts[part] = rootwriter.insertion_point()
499 if not Options.cache_builtins:
500 del self.parts['cached_builtins']
502 w = self.parts['cached_builtins']
503 w.enter_cfunc_scope()
504 w.putln("static int __Pyx_InitCachedBuiltins(void) {")
506 w = self.parts['cached_constants']
507 w.enter_cfunc_scope()
509 w.putln("static int __Pyx_InitCachedConstants(void) {")
510 w.put_declare_refcount_context()
511 w.put_setup_refcount_context("__Pyx_InitCachedConstants")
513 w = self.parts['init_globals']
514 w.enter_cfunc_scope()
516 w.putln("static int __Pyx_InitGlobals(void) {")
518 if not Options.generate_cleanup_code:
519 del self.parts['cleanup_globals']
521 w = self.parts['cleanup_globals']
522 w.enter_cfunc_scope()
524 w.putln("static void __Pyx_CleanupGlobals(void) {")
529 code = self.parts['utility_code_def']
530 if self.emit_linenums:
531 code.write('\n#line 1 "cython_utility"\n')
533 code.putln("/* Runtime support code */")
535 def finalize_main_c_code(self):
536 self.close_global_decls()
541 code = self.parts['utility_code_def']
543 code.put(PyrexTypes.type_conversion_functions)
546 def __getitem__(self, key):
547 return self.parts[key]
550 # Global constants, interned objects, etc.
552 def close_global_decls(self):
553 # This is called when it is known that no more global declarations will
555 self.generate_const_declarations()
556 if Options.cache_builtins:
557 w = self.parts['cached_builtins']
559 if w.label_used(w.error_label):
560 w.put_label(w.error_label)
561 w.putln("return -1;")
565 w = self.parts['cached_constants']
566 w.put_finish_refcount_context()
568 if w.label_used(w.error_label):
569 w.put_label(w.error_label)
570 w.put_finish_refcount_context()
571 w.putln("return -1;")
575 w = self.parts['init_globals']
577 if w.label_used(w.error_label):
578 w.put_label(w.error_label)
579 w.putln("return -1;")
583 if Options.generate_cleanup_code:
584 w = self.parts['cleanup_globals']
588 if Options.generate_cleanup_code:
589 w = self.parts['cleanup_module']
593 def put_pyobject_decl(self, entry):
594 self['global_var'].putln("static PyObject *%s;" % entry.cname)
596 # constant handling at code generation time
598 def get_cached_constants_writer(self):
599 return self.parts['cached_constants']
601 def get_int_const(self, str_value, longness=False):
602 longness = bool(longness)
604 c = self.int_const_index[(str_value, longness)]
606 c = self.new_int_const(str_value, longness)
609 def get_py_const(self, type, prefix='', cleanup_level=None):
610 # create a new Python object constant
611 const = self.new_py_const(type, prefix)
612 if cleanup_level is not None \
613 and cleanup_level <= Options.generate_cleanup_code:
614 cleanup_writer = self.parts['cleanup_globals']
615 cleanup_writer.put_xdecref_clear(const.cname, type, nanny=False)
618 def get_string_const(self, text, py_version=None):
619 # return a C string constant, creating a new one if necessary
621 byte_string = text.utf8encode()
623 byte_string = text.byteencode()
625 c = self.string_const_index[byte_string]
627 c = self.new_string_const(text, byte_string)
628 c.add_py_version(py_version)
631 def get_py_string_const(self, text, identifier=None,
632 is_str=False, unicode_value=None):
633 # return a Python string constant, creating a new one if necessary
634 py3str_cstring = None
635 if is_str and unicode_value is not None \
636 and unicode_value.utf8encode() != text.byteencode():
637 py3str_cstring = self.get_string_const(unicode_value, py_version=3)
638 c_string = self.get_string_const(text, py_version=2)
640 c_string = self.get_string_const(text)
641 py_string = c_string.get_py_string_const(
642 text.encoding, identifier, is_str, py3str_cstring)
645 def get_interned_identifier(self, text):
646 return self.get_py_string_const(text, identifier=True)
648 def new_string_const(self, text, byte_string):
649 cname = self.new_string_const_cname(byte_string)
650 c = StringConst(cname, text, byte_string)
651 self.string_const_index[byte_string] = c
654 def new_int_const(self, value, longness):
655 cname = self.new_int_const_cname(value, longness)
656 c = IntConst(cname, value, longness)
657 self.int_const_index[(value, longness)] = c
660 def new_py_const(self, type, prefix=''):
661 cname = self.new_const_cname(prefix)
662 c = PyObjectConst(cname, type)
663 self.py_constants.append(c)
666 def new_string_const_cname(self, bytes_value, intern=None):
667 # Create a new globally-unique nice name for a C string constant.
669 value = bytes_value.decode('ASCII')
671 return self.new_const_cname()
673 if len(value) < 20 and nice_identifier(value):
674 return "%s_%s" % (Naming.const_prefix, value)
676 return self.new_const_cname()
678 def new_int_const_cname(self, value, longness):
681 cname = "%s%s" % (Naming.interned_num_prefix, value)
682 cname = cname.replace('-', 'neg_').replace('.','_')
685 def new_const_cname(self, prefix=''):
686 n = self.const_cname_counter
687 self.const_cname_counter += 1
688 return "%s%s%d" % (Naming.const_prefix, prefix, n)
690 def add_cached_builtin_decl(self, entry):
691 if entry.is_builtin and entry.is_const:
692 if self.should_declare(entry.cname, entry):
693 self.put_pyobject_decl(entry)
694 w = self.parts['cached_builtins']
696 if entry.name in non_portable_builtins_map:
697 condition, replacement = non_portable_builtins_map[entry.name]
698 w.putln('#if %s' % condition)
699 self.put_cached_builtin_init(
700 entry.pos, StringEncoding.EncodedString(replacement),
703 self.put_cached_builtin_init(
704 entry.pos, StringEncoding.EncodedString(entry.name),
709 def put_cached_builtin_init(self, pos, name, cname):
710 w = self.parts['cached_builtins']
711 interned_cname = self.get_interned_identifier(name).cname
712 from ExprNodes import get_name_interned_utility_code
713 self.use_utility_code(get_name_interned_utility_code)
714 w.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
716 Naming.builtins_cname,
721 def generate_const_declarations(self):
722 self.generate_string_constants()
723 self.generate_int_constants()
724 self.generate_object_constant_decls()
726 def generate_object_constant_decls(self):
727 consts = [ (len(c.cname), c.cname, c)
728 for c in self.py_constants ]
730 decls_writer = self.parts['decls']
731 for _, cname, c in consts:
733 "static %s;" % c.type.declaration_code(cname))
735 def generate_string_constants(self):
736 c_consts = [ (len(c.cname), c.cname, c)
737 for c in self.string_const_index.values() ]
741 decls_writer = self.parts['decls']
742 for _, cname, c in c_consts:
744 if c.py_versions and (2 not in c.py_versions or 3 not in c.py_versions):
746 decls_writer.putln("#if PY_MAJOR_VERSION %s 3" % (
747 (2 in c.py_versions) and '<' or '>='))
748 decls_writer.putln('static char %s[] = "%s";' % (
749 cname, StringEncoding.split_string_literal(c.escaped_value)))
751 decls_writer.putln("#endif")
752 if c.py_strings is not None:
753 for py_string in c.py_strings.values():
754 py_strings.append((c.cname, len(py_string.cname), py_string))
758 self.use_utility_code(Nodes.init_string_tab_utility_code)
761 w = self.parts['pystring_table']
763 w.putln("static __Pyx_StringTabEntry %s[] = {" %
764 Naming.stringtab_cname)
765 for c_cname, _, py_string in py_strings:
766 if not py_string.is_str or not py_string.encoding or \
767 py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII',
771 encoding = '"%s"' % py_string.encoding.lower()
774 "static PyObject *%s;" % py_string.cname)
775 if py_string.py3str_cstring:
776 w.putln("#if PY_MAJOR_VERSION >= 3")
778 "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
780 py_string.py3str_cstring.cname,
781 py_string.py3str_cstring.cname,
787 "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
792 py_string.is_unicode,
796 if py_string.py3str_cstring:
798 w.putln("{0, 0, 0, 0, 0, 0, 0}")
801 init_globals = self.parts['init_globals']
803 "if (__Pyx_InitStrings(%s) < 0) %s;" % (
804 Naming.stringtab_cname,
805 init_globals.error_goto(self.module_pos)))
807 def generate_int_constants(self):
808 consts = [ (len(c.value), c.value, c.is_long, c)
809 for c in self.int_const_index.values() ]
811 decls_writer = self.parts['decls']
812 for _, value, longness, c in consts:
814 decls_writer.putln("static PyObject *%s;" % cname)
816 function = '%s = PyLong_FromString((char *)"%s", 0, 0); %s;'
817 elif Utils.long_literal(value):
818 function = '%s = PyInt_FromString((char *)"%s", 0, 0); %s;'
820 function = "%s = PyInt_FromLong(%s); %s;"
821 init_globals = self.parts['init_globals']
822 init_globals.putln(function % (
825 init_globals.error_goto_if_null(cname, self.module_pos)))
827 # The functions below are there in a transition phase only
828 # and will be deprecated. They are called from Nodes.BlockNode.
829 # The copy&paste duplication is intentional in order to be able
830 # to see quickly how BlockNode worked, until this is replaced.
832 def should_declare(self, cname, entry):
833 if cname in self.declared_cnames:
834 other = self.declared_cnames[cname]
835 assert str(entry.type) == str(other.type)
836 assert entry.init == other.init
839 self.declared_cnames[cname] = entry
846 def lookup_filename(self, filename):
848 index = self.filename_table[filename]
850 index = len(self.filename_list)
851 self.filename_list.append(filename)
852 self.filename_table[filename] = index
855 def commented_file_contents(self, source_desc):
857 return self.input_file_contents[source_desc]
860 source_file = source_desc.get_lines(encoding='ASCII',
861 error_handling='ignore')
863 F = [u' * ' + line.rstrip().replace(
864 u'*/', u'*[inserted by cython to avoid comment closer]/'
866 u'/*', u'/[inserted by cython to avoid comment start]*'
868 for line in source_file]
870 if hasattr(source_file, 'close'):
872 if not F: F.append(u'')
873 self.input_file_contents[source_desc] = F
880 def use_utility_code(self, utility_code):
882 Adds code to the C file. utility_code should
883 a) implement __eq__/__hash__ for the purpose of knowing whether the same
884 code has already been included
885 b) implement put_code, which takes a globalstate instance
889 if utility_code not in self.utility_codes:
890 self.utility_codes.add(utility_code)
891 utility_code.put_code(self)
894 def funccontext_property(name):
897 attribute_of = operator.attrgetter(name)
900 return getattr(o, name)
903 return attribute_of(self.funcstate)
904 def set(self, value):
905 setattr(self.funcstate, name, value)
906 return property(get, set)
909 class CCodeWriter(object):
911 Utility class to output C code.
913 When creating an insertion point one must care about the state that is
915 - formatting state (level, bol) is cloned and used in insertion points
917 - labels, temps, exc_vars: One must construct a scope in which these can
918 exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
919 sanity checking and forward compatabilty). Created insertion points
920 looses this scope and cannot access it.
921 - marker: Not copied to insertion point
922 - filename_table, filename_list, input_file_contents: All codewriters
923 coming from the same root share the same instances simultaneously.
927 # buffer StringIOTree
929 # level int indentation level
930 # bol bool beginning of line?
931 # marker string comment to emit before next line
932 # funcstate FunctionState contains state local to a C function used for code
933 # generation (labels and temps state etc.)
934 # globalstate GlobalState contains state global for a C file (input file info,
935 # utility code, declared constants etc.)
936 # emit_linenums boolean whether or not to write #line pragmas
938 # c_line_in_traceback boolean append the c file and line number to the traceback for exceptions
940 # pyclass_stack list used during recursive code generation to pass information
941 # about the current class one is in
945 def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None, c_line_in_traceback=True):
946 if buffer is None: buffer = StringIOTree()
949 self.last_marker_line = 0
950 self.source_desc = ""
951 self.pyclass_stack = []
953 self.funcstate = None
958 if create_from is not None:
959 # Use same global state
960 self.globalstate = create_from.globalstate
961 # Clone formatting state
963 self.level = create_from.level
964 self.bol = create_from.bol
965 self.call_level = create_from.call_level
966 if emit_linenums is None and self.globalstate:
967 self.emit_linenums = self.globalstate.emit_linenums
969 self.emit_linenums = emit_linenums
970 self.c_line_in_traceback = c_line_in_traceback
972 def create_new(self, create_from, buffer, copy_formatting):
973 # polymorphic constructor -- very slightly more versatile
974 # than using __class__
975 result = CCodeWriter(create_from, buffer, copy_formatting, c_line_in_traceback=self.c_line_in_traceback)
979 self.buffer.copyto(f)
982 return self.buffer.getvalue()
985 # also put invalid markers (lineno 0), to indicate that those lines
986 # have no Cython source code correspondence
987 if self.marker is None:
988 cython_lineno = self.last_marker_line
990 cython_lineno = self.marker[0]
992 self.buffer.markers.extend([cython_lineno] * s.count('\n'))
995 def insertion_point(self):
996 other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
999 def new_writer(self):
1001 Creates a new CCodeWriter connected to the same global state, which
1002 can later be inserted using insert.
1004 return CCodeWriter(create_from=self, c_line_in_traceback=self.c_line_in_traceback)
1006 def insert(self, writer):
1008 Inserts the contents of another code writer (created with
1009 the same global state) in the current location.
1011 It is ok to write to the inserted writer also after insertion.
1013 assert writer.globalstate is self.globalstate
1014 self.buffer.insert(writer.buffer)
1016 # Properties delegated to function scope
1017 label_counter = funccontext_property("label_counter")
1018 return_label = funccontext_property("return_label")
1019 error_label = funccontext_property("error_label")
1020 labels_used = funccontext_property("labels_used")
1021 continue_label = funccontext_property("continue_label")
1022 break_label = funccontext_property("break_label")
1023 return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
1025 # Functions delegated to function scope
1026 def new_label(self, name=None): return self.funcstate.new_label(name)
1027 def new_error_label(self): return self.funcstate.new_error_label()
1028 def get_loop_labels(self): return self.funcstate.get_loop_labels()
1029 def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
1030 def new_loop_labels(self): return self.funcstate.new_loop_labels()
1031 def get_all_labels(self): return self.funcstate.get_all_labels()
1032 def set_all_labels(self, labels): return self.funcstate.set_all_labels(labels)
1033 def all_new_labels(self): return self.funcstate.all_new_labels()
1034 def use_label(self, lbl): return self.funcstate.use_label(lbl)
1035 def label_used(self, lbl): return self.funcstate.label_used(lbl)
1038 def enter_cfunc_scope(self):
1039 self.funcstate = FunctionState(self)
1041 def exit_cfunc_scope(self):
1042 self.funcstate = None
1046 def get_py_num(self, str_value, longness):
1047 return self.globalstate.get_int_const(str_value, longness).cname
1049 def get_py_const(self, type, prefix='', cleanup_level=None):
1050 return self.globalstate.get_py_const(type, prefix, cleanup_level).cname
1052 def get_string_const(self, text):
1053 return self.globalstate.get_string_const(text).cname
1055 def get_py_string_const(self, text, identifier=None,
1056 is_str=False, unicode_value=None):
1057 return self.globalstate.get_py_string_const(
1058 text, identifier, is_str, unicode_value).cname
1060 def get_argument_default_const(self, type):
1061 return self.globalstate.get_py_const(type).cname
1063 def intern(self, text):
1064 return self.get_py_string_const(text)
1066 def intern_identifier(self, text):
1067 return self.get_py_string_const(text, identifier=True)
1069 def get_cached_constants_writer(self):
1070 return self.globalstate.get_cached_constants_writer()
1074 def putln(self, code = "", safe=False):
1075 if self.marker and self.bol:
1077 if self.emit_linenums and self.last_marker_line != 0:
1078 self.write('\n#line %s "%s"\n' % (self.last_marker_line, self.source_desc))
1088 def emit_marker(self):
1091 self.write("/* %s */\n" % self.marker[1])
1092 self.last_marker_line = self.marker[0]
1095 def put_safe(self, code):
1096 # put code, but ignore {}
1100 def put(self, code):
1103 dl = code.count("{")
1107 dl -= code.count("}")
1110 elif dl == 0 and code[0] == "}":
1111 # special cases like "} else {" need a temporary dedent
1123 def increase_indent(self):
1124 self.level = self.level + 1
1126 def decrease_indent(self):
1127 self.level = self.level - 1
1129 def begin_block(self):
1131 self.increase_indent()
1133 def end_block(self):
1134 self.decrease_indent()
1138 self.write(" " * self.level)
1140 def get_py_version_hex(self, pyversion):
1141 return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
1143 def mark_pos(self, pos):
1146 source_desc, line, col = pos
1147 if self.last_marker_line == line:
1149 assert isinstance(source_desc, SourceDescriptor)
1150 contents = self.globalstate.commented_file_contents(source_desc)
1151 lines = contents[max(0,line-3):line] # line numbers start at 1
1152 lines[-1] += u' # <<<<<<<<<<<<<<'
1153 lines += contents[line:line+2]
1155 marker = u'"%s":%d\n%s\n' % (
1156 source_desc.get_escaped_description(), line, u'\n'.join(lines))
1157 self.marker = (line, marker)
1158 if self.emit_linenums:
1159 self.source_desc = source_desc.get_escaped_description()
1161 def put_label(self, lbl):
1162 if lbl in self.funcstate.labels_used:
1163 self.putln("%s:;" % lbl)
1165 def put_goto(self, lbl):
1166 self.funcstate.use_label(lbl)
1167 self.putln("goto %s;" % lbl)
1169 def put_var_declarations(self, entries, static = 0, dll_linkage = None,
1171 for entry in entries:
1172 if not entry.in_cinclude:
1173 self.put_var_declaration(entry, static, dll_linkage, definition)
1175 def put_var_declaration(self, entry, static = 0, dll_linkage = None,
1177 #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
1178 if entry.in_closure:
1180 visibility = entry.visibility
1181 if visibility == 'private' and not definition:
1182 #print "...private and not definition, skipping" ###
1184 if not entry.used and visibility == "private":
1185 #print "not used and private, skipping", entry.cname ###
1188 if visibility == 'extern':
1189 storage_class = Naming.extern_c_macro
1190 elif visibility == 'public':
1192 storage_class = Naming.extern_c_macro
1193 elif visibility == 'private':
1195 storage_class = "static"
1197 self.put("%s " % storage_class)
1198 if visibility != 'public':
1200 self.put(entry.type.declaration_code(entry.cname,
1201 dll_linkage = dll_linkage))
1202 if entry.init is not None:
1203 self.put_safe(" = %s" % entry.type.literal_code(entry.init))
1206 def put_temp_declarations(self, func_context):
1207 for name, type, manage_ref in func_context.temps_allocated:
1208 decl = type.declaration_code(name)
1209 if type.is_pyobject:
1210 self.putln("%s = NULL;" % decl)
1212 self.putln("%s;" % decl)
1214 def put_h_guard(self, guard):
1215 self.putln("#ifndef %s" % guard)
1216 self.putln("#define %s" % guard)
1218 def unlikely(self, cond):
1219 if Options.gcc_branch_hints:
1220 return 'unlikely(%s)' % cond
1224 # Python objects and reference counting
1226 def entry_as_pyobject(self, entry):
1228 if (not entry.is_self_arg and not entry.type.is_complete()
1229 or entry.type.is_extension_type):
1230 return "(PyObject *)" + entry.cname
1234 def as_pyobject(self, cname, type):
1235 from PyrexTypes import py_object_type, typecast
1236 return typecast(py_object_type, type, cname)
1238 def put_gotref(self, cname):
1239 self.putln("__Pyx_GOTREF(%s);" % cname)
1241 def put_giveref(self, cname):
1242 self.putln("__Pyx_GIVEREF(%s);" % cname)
1244 def put_xgiveref(self, cname):
1245 self.putln("__Pyx_XGIVEREF(%s);" % cname)
1247 def put_xgotref(self, cname):
1248 self.putln("__Pyx_XGOTREF(%s);" % cname)
1250 def put_incref(self, cname, type, nanny=True):
1252 self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
1254 self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
1256 def put_decref(self, cname, type, nanny=True):
1258 self.putln("__Pyx_DECREF(%s);" % self.as_pyobject(cname, type))
1260 self.putln("Py_DECREF(%s);" % self.as_pyobject(cname, type))
1262 def put_var_gotref(self, entry):
1263 if entry.type.is_pyobject:
1264 self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry))
1266 def put_var_giveref(self, entry):
1267 if entry.type.is_pyobject:
1268 self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry))
1270 def put_var_xgotref(self, entry):
1271 if entry.type.is_pyobject:
1272 self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry))
1274 def put_var_xgiveref(self, entry):
1275 if entry.type.is_pyobject:
1276 self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry))
1278 def put_var_incref(self, entry):
1279 if entry.type.is_pyobject:
1280 self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
1282 def put_decref_clear(self, cname, type, nanny=True):
1283 from PyrexTypes import py_object_type, typecast
1285 self.putln("__Pyx_DECREF(%s); %s = 0;" % (
1286 typecast(py_object_type, type, cname), cname))
1288 self.putln("Py_DECREF(%s); %s = 0;" % (
1289 typecast(py_object_type, type, cname), cname))
1291 def put_xdecref(self, cname, type, nanny=True):
1293 self.putln("__Pyx_XDECREF(%s);" % self.as_pyobject(cname, type))
1295 self.putln("Py_XDECREF(%s);" % self.as_pyobject(cname, type))
1297 def put_xdecref_clear(self, cname, type, nanny=True):
1299 self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
1300 self.as_pyobject(cname, type), cname))
1302 self.putln("Py_XDECREF(%s); %s = 0;" % (
1303 self.as_pyobject(cname, type), cname))
1305 def put_var_decref(self, entry):
1306 if entry.type.is_pyobject:
1307 if entry.init_to_none is False: # FIXME: 0 and False are treated differently???
1308 self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
1310 self.putln("__Pyx_DECREF(%s);" % self.entry_as_pyobject(entry))
1312 def put_var_decref_clear(self, entry):
1313 if entry.type.is_pyobject:
1314 self.putln("__Pyx_DECREF(%s); %s = 0;" % (
1315 self.entry_as_pyobject(entry), entry.cname))
1317 def put_var_xdecref(self, entry):
1318 if entry.type.is_pyobject:
1319 self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
1321 def put_var_xdecref_clear(self, entry):
1322 if entry.type.is_pyobject:
1323 self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
1324 self.entry_as_pyobject(entry), entry.cname))
1326 def put_var_decrefs(self, entries, used_only = 0):
1327 for entry in entries:
1328 if not used_only or entry.used:
1329 if entry.xdecref_cleanup:
1330 self.put_var_xdecref(entry)
1332 self.put_var_decref(entry)
1334 def put_var_xdecrefs(self, entries):
1335 for entry in entries:
1336 self.put_var_xdecref(entry)
1338 def put_var_xdecrefs_clear(self, entries):
1339 for entry in entries:
1340 self.put_var_xdecref_clear(entry)
1342 def put_init_to_py_none(self, cname, type, nanny=True):
1343 from PyrexTypes import py_object_type, typecast
1344 py_none = typecast(type, py_object_type, "Py_None")
1346 self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none))
1348 self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none))
1350 def put_init_var_to_py_none(self, entry, template = "%s", nanny=True):
1351 code = template % entry.cname
1352 #if entry.type.is_extension_type:
1353 # code = "((PyObject*)%s)" % code
1354 self.put_init_to_py_none(code, entry.type, nanny)
1355 if entry.in_closure:
1356 self.put_giveref('Py_None')
1358 def put_pymethoddef(self, entry, term, allow_skip=True):
1359 if entry.is_special or entry.name == '__getattribute__':
1360 if entry.name not in ['__cinit__', '__dealloc__', '__richcmp__', '__next__', '__getreadbuffer__', '__getwritebuffer__', '__getsegcount__', '__getcharbuffer__', '__getbuffer__', '__releasebuffer__']:
1361 if entry.name == '__getattr__' and not self.globalstate.directives['fast_getattr']:
1363 # Python's typeobject.c will automatically fill in our slot
1364 # in add_operators() (called by PyType_Ready) with a value
1365 # that's better than ours.
1368 from TypeSlots import method_coexist
1370 doc_code = entry.doc_cname
1373 method_flags = entry.signature.method_flags()
1375 if entry.is_special:
1376 method_flags += [method_coexist]
1378 '{__Pyx_NAMESTR("%s"), (PyCFunction)%s, %s, __Pyx_DOCSTR(%s)}%s' % (
1381 "|".join(method_flags),
1387 def put_error_if_neg(self, pos, value):
1388 # 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!
1389 return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
1391 def set_error_info(self, pos):
1392 if self.c_line_in_traceback:
1393 cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
1396 return "%s = %s[%s]; %s = %s;%s" % (
1397 Naming.filename_cname,
1398 Naming.filetable_cname,
1399 self.lookup_filename(pos[0]),
1400 Naming.lineno_cname,
1404 def error_goto(self, pos):
1405 lbl = self.funcstate.error_label
1406 self.funcstate.use_label(lbl)
1407 return "{%s goto %s;}" % (
1408 self.set_error_info(pos),
1411 def error_goto_if(self, cond, pos):
1412 return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
1414 def error_goto_if_null(self, cname, pos):
1415 return self.error_goto_if("!%s" % cname, pos)
1417 def error_goto_if_neg(self, cname, pos):
1418 return self.error_goto_if("%s < 0" % cname, pos)
1420 def error_goto_if_PyErr(self, pos):
1421 return self.error_goto_if("PyErr_Occurred()", pos)
1423 def lookup_filename(self, filename):
1424 return self.globalstate.lookup_filename(filename)
1426 def put_declare_refcount_context(self):
1427 self.putln('__Pyx_RefNannyDeclarations')
1429 def put_setup_refcount_context(self, name):
1430 self.putln('__Pyx_RefNannySetupContext("%s");' % name)
1432 def put_finish_refcount_context(self):
1433 self.putln("__Pyx_RefNannyFinishContext();")
1435 def put_trace_declarations(self):
1436 self.putln('__Pyx_TraceDeclarations');
1438 def put_trace_call(self, name, pos):
1439 self.putln('__Pyx_TraceCall("%s", %s[%s], %s);' % (name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1]));
1441 def put_trace_exception(self):
1442 self.putln("__Pyx_TraceException();")
1444 def put_trace_return(self, retvalue_cname):
1445 self.putln("__Pyx_TraceReturn(%s);" % retvalue_cname)
1448 class PyrexCodeWriter(object):
1449 # f file output file
1450 # level int indentation level
1452 def __init__(self, outfile_name):
1453 self.f = Utils.open_new_file(outfile_name)
1456 def putln(self, code):
1457 self.f.write("%s%s\n" % (" " * self.level, code))
1466 class ClosureTempAllocator(object):
1467 def __init__(self, klass):
1469 self.temps_allocated = {}
1470 self.temps_free = {}
1471 self.temps_count = 0
1474 for type, cnames in self.temps_allocated.items():
1475 self.temps_free[type] = list(cnames)
1477 def allocate_temp(self, type):
1478 if not type in self.temps_allocated:
1479 self.temps_allocated[type] = []
1480 self.temps_free[type] = []
1481 elif self.temps_free[type]:
1482 return self.temps_free[type].pop(0)
1483 cname = '%s%d' % (Naming.codewriter_temp_prefix, self.temps_count)
1484 self.klass.declare_var(pos=None, name=cname, cname=cname, type=type, is_cdef=True)
1485 self.temps_allocated[type].append(cname)
1486 self.temps_count += 1