Cython has moved to github.

cython-devel

view Cython/Compiler/Code.py @ 1779:fb81e893dc8e

Fix leak in try-break.
author Robert Bradshaw <robertwb@math.washington.edu>
date Wed Feb 25 23:44:24 2009 -0800 (3 years ago)
parents b25f64a0d940
children 569ed4c256db
line source
1 #
2 # Pyrex - Code output module
3 #
5 import codecs
6 import Naming
7 import Options
8 from Cython.Utils import open_new_file, open_source_file
9 from PyrexTypes import py_object_type, typecast
10 from TypeSlots import method_coexist
11 from Scanning import SourceDescriptor
12 from Cython.StringIOTree import StringIOTree
13 import DebugFlags
14 try:
15 set
16 except NameError:
17 from sets import Set as set
18 import DebugFlags
20 class FunctionState(object):
21 # return_label string function return point label
22 # error_label string error catch point label
23 # continue_label string loop continue point label
24 # break_label string loop break point label
25 # return_from_error_cleanup_label string
26 # label_counter integer counter for naming labels
27 # in_try_finally boolean inside try of try...finally
28 # exc_vars (string * 3) exception variables for reraise, or None
30 # Not used for now, perhaps later
31 def __init__(self, owner, names_taken=set()):
32 self.names_taken = names_taken
33 self.owner = owner
35 self.error_label = None
36 self.label_counter = 0
37 self.labels_used = {}
38 self.return_label = self.new_label()
39 self.new_error_label()
40 self.continue_label = None
41 self.break_label = None
43 self.in_try_finally = 0
44 self.exc_vars = None
46 self.temps_allocated = [] # of (name, type, manage_ref)
47 self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
48 self.temps_used_type = {} # name -> (type, manage_ref)
49 self.temp_counter = 0
51 def new_label(self, name=None):
52 n = self.label_counter
53 self.label_counter = n + 1
54 label = "%s%d" % (Naming.label_prefix, n)
55 if name is not None:
56 label += '_' + name
57 return label
59 def new_error_label(self):
60 old_err_lbl = self.error_label
61 self.error_label = self.new_label('error')
62 return old_err_lbl
64 def get_loop_labels(self):
65 return (
66 self.continue_label,
67 self.break_label)
69 def set_loop_labels(self, labels):
70 (self.continue_label,
71 self.break_label) = labels
73 def new_loop_labels(self):
74 old_labels = self.get_loop_labels()
75 self.set_loop_labels(
76 (self.new_label("continue"),
77 self.new_label("break")))
78 return old_labels
80 def get_all_labels(self):
81 return (
82 self.continue_label,
83 self.break_label,
84 self.return_label,
85 self.error_label)
87 def set_all_labels(self, labels):
88 (self.continue_label,
89 self.break_label,
90 self.return_label,
91 self.error_label) = labels
93 def all_new_labels(self):
94 old_labels = self.get_all_labels()
95 new_labels = []
96 for old_label in old_labels:
97 if old_label:
98 new_labels.append(self.new_label())
99 else:
100 new_labels.append(old_label)
101 self.set_all_labels(new_labels)
102 return old_labels
104 def use_label(self, lbl):
105 self.labels_used[lbl] = 1
107 def label_used(self, lbl):
108 return lbl in self.labels_used
110 def allocate_temp(self, type, manage_ref):
111 """
112 Allocates a temporary (which may create a new one or get a previously
113 allocated and released one of the same type). Type is simply registered
114 and handed back, but will usually be a PyrexType.
116 If type.is_pyobject, manage_ref comes into play. If manage_ref is set to
117 True, the temp will be decref-ed on return statements and in exception
118 handling clauses. Otherwise the caller has to deal with any reference
119 counting of the variable.
121 If not type.is_pyobject, then manage_ref will be ignored, but it
122 still has to be passed. It is recommended to pass False by convention
123 if it is known that type will never be a Python object.
125 A C string referring to the variable is returned.
126 """
127 if not type.is_pyobject:
128 # Make manage_ref canonical, so that manage_ref will always mean
129 # a decref is needed.
130 manage_ref = False
131 freelist = self.temps_free.get((type, manage_ref))
132 if freelist is not None and len(freelist) > 0:
133 result = freelist.pop()
134 else:
135 while True:
136 self.temp_counter += 1
137 result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter)
138 if not result in self.names_taken: break
139 self.temps_allocated.append((result, type, manage_ref))
140 self.temps_used_type[result] = (type, manage_ref)
141 if DebugFlags.debug_temp_code_comments:
142 self.owner.putln("/* %s allocated */" % result)
143 return result
145 def release_temp(self, name):
146 """
147 Releases a temporary so that it can be reused by other code needing
148 a temp of the same type.
149 """
150 type, manage_ref = self.temps_used_type[name]
151 freelist = self.temps_free.get((type, manage_ref))
152 if freelist is None:
153 freelist = []
154 self.temps_free[(type, manage_ref)] = freelist
155 if name in freelist:
156 raise RuntimeError("Temp %s freed twice!" % name)
157 freelist.append(name)
158 if DebugFlags.debug_temp_code_comments:
159 self.owner.putln("/* %s released */" % name)
161 def temps_in_use(self):
162 """Return a list of (cname,type,manage_ref) tuples of temp names and their type
163 that are currently in use.
164 """
165 used = []
166 for name, type, manage_ref in self.temps_allocated:
167 freelist = self.temps_free.get((type, manage_ref))
168 if freelist is None or name not in freelist:
169 used.append((name, type, manage_ref))
170 return used
172 def temps_holding_reference(self):
173 """Return a list of (cname,type) tuples of temp names and their type
174 that are currently in use. This includes only temps of a
175 Python object type which owns its reference.
176 """
177 return [(name, type)
178 for name, type, manage_ref in self.temps_in_use()
179 if manage_ref]
181 def all_managed_temps(self):
182 """Return a list of (cname, type) tuples of refcount-managed Python objects.
183 """
184 return [(cname, type)
185 for cname, type, manage_ref in self.temps_allocated
186 if manage_ref]
188 def all_free_managed_temps(self):
189 """Return a list of (cname, type) tuples of refcount-managed Python
190 objects that are not currently in use. This is used by
191 try-except and try-finally blocks to clean up temps in the
192 error case.
193 """
194 return [(cname, type)
195 for (type, manage_ref), freelist in self.temps_free.iteritems()
196 if manage_ref
197 for cname in freelist]
199 class GlobalState(object):
200 # filename_table {string : int} for finding filename table indexes
201 # filename_list [string] filenames in filename table order
202 # input_file_contents dict contents (=list of lines) of any file that was used as input
203 # to create this output C code. This is
204 # used to annotate the comments.
205 #
206 # used_utility_code set(string|int) Ids of used utility code (to avoid reinsertion)
207 # utilprotowriter CCodeWriter
208 # utildefwriter CCodeWriter
209 #
210 # declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
211 # constants etc. into the pyx-declared ones (i.e,
212 # check if constants are already added).
213 # In time, hopefully the literals etc. will be
214 # supplied directly instead.
217 # interned_strings
218 # consts
219 # py_string_decls
220 # interned_nums
221 # cached_builtins
223 # directives set Temporary variable used to track
224 # the current set of directives in the code generation
225 # process.
227 directives = {}
229 def __init__(self, rootwriter, emit_linenums=False):
230 self.filename_table = {}
231 self.filename_list = []
232 self.input_file_contents = {}
233 self.used_utility_code = set()
234 self.declared_cnames = {}
235 self.pystring_table_needed = False
236 self.in_utility_code_generation = False
237 self.emit_linenums = emit_linenums
239 def initwriters(self, rootwriter):
240 self.utilprotowriter = rootwriter.new_writer()
241 self.utildefwriter = rootwriter.new_writer()
242 self.decls_writer = rootwriter.new_writer()
243 self.pystring_table = rootwriter.new_writer()
244 self.init_cached_builtins_writer = rootwriter.new_writer()
245 self.initwriter = rootwriter.new_writer()
246 self.cleanupwriter = rootwriter.new_writer()
248 if Options.cache_builtins:
249 self.init_cached_builtins_writer.enter_cfunc_scope()
250 self.init_cached_builtins_writer.putln("static int __Pyx_InitCachedBuiltins(void) {")
252 self.initwriter.enter_cfunc_scope()
253 self.initwriter.putln("")
254 self.initwriter.putln("static int __Pyx_InitGlobals(void) {")
256 self.cleanupwriter.enter_cfunc_scope()
257 self.cleanupwriter.putln("")
258 self.cleanupwriter.putln("static void __Pyx_CleanupGlobals(void) {")
260 self.pystring_table.putln("")
261 self.pystring_table.putln("static __Pyx_StringTabEntry %s[] = {" %
262 Naming.stringtab_cname)
264 #
265 # Global constants, interned objects, etc.
266 #
267 def insert_global_var_declarations_into(self, code):
268 code.insert(self.decls_writer)
270 def close_global_decls(self):
271 # This is called when it is known that no more global declarations will
272 # declared (but can be called before or after insert_XXX).
273 if self.pystring_table_needed:
274 self.pystring_table.putln("{0, 0, 0, 0, 0, 0}")
275 self.pystring_table.putln("};")
276 import Nodes
277 self.use_utility_code(Nodes.init_string_tab_utility_code)
278 self.initwriter.putln(
279 "if (__Pyx_InitStrings(%s) < 0) %s;" % (
280 Naming.stringtab_cname,
281 self.initwriter.error_goto(self.module_pos)))
283 if Options.cache_builtins:
284 w = self.init_cached_builtins_writer
285 w.putln("return 0;")
286 w.put_label(w.error_label)
287 w.putln("return -1;")
288 w.putln("}")
289 w.exit_cfunc_scope()
291 w = self.initwriter
292 w.putln("return 0;")
293 w.put_label(w.error_label)
294 w.putln("return -1;")
295 w.putln("}")
296 w.exit_cfunc_scope()
298 w = self.cleanupwriter
299 w.putln("}")
300 w.exit_cfunc_scope()
302 def insert_initcode_into(self, code):
303 if self.pystring_table_needed:
304 code.insert(self.pystring_table)
305 if Options.cache_builtins:
306 code.insert(self.init_cached_builtins_writer)
307 code.insert(self.initwriter)
309 def insert_cleanupcode_into(self, code):
310 code.insert(self.cleanupwriter)
312 def put_pyobject_decl(self, entry):
313 self.decls_writer.putln("static PyObject *%s;" % entry.cname)
315 # The functions below are there in a transition phase only
316 # and will be deprecated. They are called from Nodes.BlockNode.
317 # The copy&paste duplication is intentional in order to be able
318 # to see quickly how BlockNode worked, until this is replaced.
320 def should_declare(self, cname, entry):
321 if cname in self.declared_cnames:
322 other = self.declared_cnames[cname]
323 assert str(entry.type) == str(other.type)
324 assert entry.init == other.init
325 return False
326 else:
327 self.declared_cnames[cname] = entry
328 return True
330 def add_const_definition(self, entry):
331 if self.should_declare(entry.cname, entry):
332 self.decls_writer.put_var_declaration(entry, static = 1)
334 def add_interned_string_decl(self, entry):
335 if self.should_declare(entry.cname, entry):
336 self.decls_writer.put_var_declaration(entry, static = 1)
337 self.add_py_string_decl(entry)
339 def add_py_string_decl(self, entry):
340 if self.should_declare(entry.pystring_cname, entry):
341 self.decls_writer.putln("static PyObject *%s;" % entry.pystring_cname)
342 self.pystring_table_needed = True
343 self.pystring_table.putln("{&%s, %s, sizeof(%s), %d, %d, %d}," % (
344 entry.pystring_cname,
345 entry.cname,
346 entry.cname,
347 entry.type.is_unicode,
348 entry.is_interned,
349 entry.is_identifier
350 ))
352 def add_interned_num_decl(self, entry):
353 if self.should_declare(entry.cname, entry):
354 if entry.init[-1] == "L":
355 self.initwriter.putln('%s = PyLong_FromString((char *)"%s", 0, 0); %s;' % (
356 entry.cname,
357 entry.init[:-1], # strip 'L' for Py3 compatibility
358 self.initwriter.error_goto_if_null(entry.cname, self.module_pos)))
359 else:
360 self.initwriter.putln("%s = PyInt_FromLong(%s); %s;" % (
361 entry.cname,
362 entry.init,
363 self.initwriter.error_goto_if_null(entry.cname, self.module_pos)))
365 self.put_pyobject_decl(entry)
367 def add_cached_builtin_decl(self, entry):
368 if Options.cache_builtins:
369 if self.should_declare(entry.cname, entry):
370 self.put_pyobject_decl(entry)
371 self.init_cached_builtins_writer.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
372 entry.cname,
373 Naming.builtins_cname,
374 entry.interned_cname,
375 entry.cname,
376 self.init_cached_builtins_writer.error_goto(entry.pos)))
379 #
380 # File name state
381 #
383 def lookup_filename(self, filename):
384 try:
385 index = self.filename_table[filename]
386 except KeyError:
387 index = len(self.filename_list)
388 self.filename_list.append(filename)
389 self.filename_table[filename] = index
390 return index
392 def commented_file_contents(self, source_desc):
393 try:
394 return self.input_file_contents[source_desc]
395 except KeyError:
396 F = [u' * ' + line.rstrip().replace(
397 u'*/', u'*[inserted by cython to avoid comment closer]/'
398 ).replace(
399 u'/*', u'/[inserted by cython to avoid comment start]*'
400 ).encode('ASCII', 'replace') # + Py2 auto-decode to unicode
401 for line in source_desc.get_lines()]
402 if len(F) == 0: F.append(u'')
403 self.input_file_contents[source_desc] = F
404 return F
406 #
407 # Utility code state
408 #
410 def use_utility_code(self, utility_code, name=None):
411 """
412 Adds the given utility code to the C file if needed.
414 codetup should unpack into one prototype code part and one
415 definition code part, both strings inserted directly in C.
417 If name is provided, it is used as an identifier to avoid inserting
418 code twice. Otherwise, id(codetup) is used as such an identifier.
419 """
420 if name is None: name = id(utility_code)
421 if self.check_utility_code_needed_and_register(name):
422 if utility_code.proto:
423 self.utilprotowriter.put(utility_code.proto)
424 if utility_code.impl:
425 self.utildefwriter.put(utility_code.impl)
426 utility_code.write_init_code(self.initwriter, self.module_pos)
427 utility_code.write_cleanup_code(self.cleanupwriter, self.module_pos)
429 def has_code(self, name):
430 return name in self.used_utility_code
432 def use_code_from(self, func, name, *args, **kw):
433 """
434 Requests that the utility code that func can generate is used in the C
435 file. func is called like this:
437 func(proto, definition, name, *args, **kw)
439 where proto and definition are two CCodeWriter instances; the
440 former should have the prototype written to it and the other the definition.
442 The call might happen at some later point (if compiling multiple modules
443 into a cache for instance), and will only happen once per utility code.
445 name is used to identify the utility code, so that it isn't regenerated
446 when the same code is requested again.
447 """
448 if self.check_utility_code_needed_and_register(name):
449 func(self.utilprotowriter, self.utildefwriter,
450 name, *args, **kw)
452 def check_utility_code_needed_and_register(self, name):
453 if name in self.used_utility_code:
454 return False
455 else:
456 self.used_utility_code.add(name)
457 return True
459 def put_utility_code_protos(self, writer):
460 writer.insert(self.utilprotowriter)
462 def put_utility_code_defs(self, writer):
463 if self.emit_linenums:
464 writer.write('\n#line 1 "cython_utility"\n')
465 writer.insert(self.utildefwriter)
468 def funccontext_property(name):
469 def get(self):
470 return getattr(self.funcstate, name)
471 def set(self, value):
472 setattr(self.funcstate, name, value)
473 return property(get, set)
475 class CCodeWriter(object):
476 """
477 Utility class to output C code.
479 When creating an insertion point one must care about the state that is
480 kept:
481 - formatting state (level, bol) is cloned and used in insertion points
482 as well
483 - labels, temps, exc_vars: One must construct a scope in which these can
484 exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
485 sanity checking and forward compatabilty). Created insertion points
486 looses this scope and cannot access it.
487 - marker: Not copied to insertion point
488 - filename_table, filename_list, input_file_contents: All codewriters
489 coming from the same root share the same instances simultaneously.
490 """
492 # f file output file
493 # buffer StringIOTree
495 # level int indentation level
496 # bol bool beginning of line?
497 # marker string comment to emit before next line
498 # funcstate FunctionState contains state local to a C function used for code
499 # generation (labels and temps state etc.)
500 # globalstate GlobalState contains state global for a C file (input file info,
501 # utility code, declared constants etc.)
502 # emit_linenums boolean whether or not to write #line pragmas
504 def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None):
505 if buffer is None: buffer = StringIOTree()
506 self.buffer = buffer
507 self.marker = None
508 self.last_marker_line = 0
509 self.source_desc = ""
511 self.funcstate = None
512 self.level = 0
513 self.call_level = 0
514 self.bol = 1
515 if create_from is None:
516 # Root CCodeWriter
517 self.globalstate = GlobalState(self, emit_linenums=emit_linenums)
518 self.globalstate.initwriters(self)
519 # ^^^ need seperate step because this will reference self.globalstate
520 else:
521 # Use same global state
522 self.globalstate = create_from.globalstate
523 # Clone formatting state
524 if copy_formatting:
525 self.level = create_from.level
526 self.bol = create_from.bol
527 self.call_level = create_from.call_level
528 if emit_linenums is None:
529 self.emit_linenums = self.globalstate.emit_linenums
530 else:
531 self.emit_linenums = emit_linenums
533 def create_new(self, create_from, buffer, copy_formatting):
534 # polymorphic constructor -- very slightly more versatile
535 # than using __class__
536 return CCodeWriter(create_from, buffer, copy_formatting)
538 def copyto(self, f):
539 self.buffer.copyto(f)
541 def getvalue(self):
542 return self.buffer.getvalue()
544 def write(self, s):
545 self.buffer.write(s)
547 def insertion_point(self):
548 other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
549 return other
551 def new_writer(self):
552 """
553 Creates a new CCodeWriter connected to the same global state, which
554 can later be inserted using insert.
555 """
556 return CCodeWriter(create_from=self)
558 def insert(self, writer):
559 """
560 Inserts the contents of another code writer (created with
561 the same global state) in the current location.
563 It is ok to write to the inserted writer also after insertion.
564 """
565 assert writer.globalstate is self.globalstate
566 self.buffer.insert(writer.buffer)
568 # Properties delegated to function scope
569 label_counter = funccontext_property("label_counter")
570 return_label = funccontext_property("return_label")
571 error_label = funccontext_property("error_label")
572 labels_used = funccontext_property("labels_used")
573 continue_label = funccontext_property("continue_label")
574 break_label = funccontext_property("break_label")
575 return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
577 # Functions delegated to function scope
578 def new_label(self, name=None): return self.funcstate.new_label(name)
579 def new_error_label(self): return self.funcstate.new_error_label()
580 def get_loop_labels(self): return self.funcstate.get_loop_labels()
581 def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
582 def new_loop_labels(self): return self.funcstate.new_loop_labels()
583 def get_all_labels(self): return self.funcstate.get_all_labels()
584 def set_all_labels(self, labels): return self.funcstate.set_all_labels(labels)
585 def all_new_labels(self): return self.funcstate.all_new_labels()
586 def use_label(self, lbl): return self.funcstate.use_label(lbl)
587 def label_used(self, lbl): return self.funcstate.label_used(lbl)
590 def enter_cfunc_scope(self):
591 self.funcstate = FunctionState(self)
593 def exit_cfunc_scope(self):
594 self.funcstate = None
596 def putln(self, code = ""):
597 if self.marker and self.bol:
598 self.emit_marker()
599 if self.emit_linenums and self.last_marker_line != 0:
600 self.write('\n#line %s "%s"\n' % (self.last_marker_line, self.source_desc))
601 if code:
602 self.put(code)
603 self.write("\n");
604 self.bol = 1
606 def emit_marker(self):
607 self.write("\n");
608 self.indent()
609 self.write("/* %s */\n" % self.marker[1])
610 self.last_marker_line = self.marker[0]
611 self.marker = None
613 def put_safe(self, code):
614 # put code, but ignore {}
615 self.write(code)
616 self.bol = 0
618 def put(self, code):
619 fix_indent = False
620 if "{" in code:
621 dl = code.count("{")
622 else:
623 dl = 0
624 if "}" in code:
625 dl -= code.count("}")
626 if dl < 0:
627 self.level += dl
628 elif dl == 0 and code[0] == "}":
629 # special cases like "} else {" need a temporary dedent
630 fix_indent = True
631 self.level -= 1
632 if self.bol:
633 self.indent()
634 self.write(code)
635 self.bol = 0
636 if dl > 0:
637 self.level += dl
638 elif fix_indent:
639 self.level += 1
641 def increase_indent(self):
642 self.level = self.level + 1
644 def decrease_indent(self):
645 self.level = self.level - 1
647 def begin_block(self):
648 self.putln("{")
649 self.increase_indent()
651 def end_block(self):
652 self.decrease_indent()
653 self.putln("}")
655 def indent(self):
656 self.write(" " * self.level)
658 def get_py_version_hex(self, pyversion):
659 return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
661 def mark_pos(self, pos):
662 if pos is None:
663 return
664 source_desc, line, col = pos
665 if self.last_marker_line == line:
666 return
667 assert isinstance(source_desc, SourceDescriptor)
668 contents = self.globalstate.commented_file_contents(source_desc)
669 lines = contents[max(0,line-3):line] # line numbers start at 1
670 lines[-1] += u' # <<<<<<<<<<<<<<'
671 lines += contents[line:line+2]
673 marker = u'"%s":%d\n%s\n' % (
674 source_desc.get_escaped_description(), line, u'\n'.join(lines))
675 self.marker = (line, marker)
676 if self.emit_linenums:
677 self.source_desc = source_desc.get_escaped_description()
679 def put_label(self, lbl):
680 if lbl in self.funcstate.labels_used:
681 self.putln("%s:;" % lbl)
683 def put_goto(self, lbl):
684 self.funcstate.use_label(lbl)
685 self.putln("goto %s;" % lbl)
687 def put_var_declarations(self, entries, static = 0, dll_linkage = None,
688 definition = True):
689 for entry in entries:
690 if not entry.in_cinclude:
691 self.put_var_declaration(entry, static, dll_linkage, definition)
693 def put_var_declaration(self, entry, static = 0, dll_linkage = None,
694 definition = True):
695 #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
696 if entry.in_closure:
697 return
698 visibility = entry.visibility
699 if visibility == 'private' and not definition:
700 #print "...private and not definition, skipping" ###
701 return
702 if not entry.used and visibility == "private":
703 #print "not used and private, skipping", entry.cname ###
704 return
705 storage_class = ""
706 if visibility == 'extern':
707 storage_class = Naming.extern_c_macro
708 elif visibility == 'public':
709 if not definition:
710 storage_class = Naming.extern_c_macro
711 elif visibility == 'private':
712 if static:
713 storage_class = "static"
714 if storage_class:
715 self.put("%s " % storage_class)
716 if visibility != 'public':
717 dll_linkage = None
718 self.put(entry.type.declaration_code(entry.cname,
719 dll_linkage = dll_linkage))
720 if entry.init is not None:
721 self.put_safe(" = %s" % entry.type.literal_code(entry.init))
722 self.putln(";")
724 def put_temp_declarations(self, func_context):
725 for name, type, manage_ref in func_context.temps_allocated:
726 decl = type.declaration_code(name)
727 if type.is_pyobject:
728 self.putln("%s = NULL;" % decl)
729 else:
730 self.putln("%s;" % decl)
732 def entry_as_pyobject(self, entry):
733 type = entry.type
734 if (not entry.is_self_arg and not entry.type.is_complete()
735 or entry.type.is_extension_type):
736 return "(PyObject *)" + entry.cname
737 else:
738 return entry.cname
740 def as_pyobject(self, cname, type):
741 return typecast(py_object_type, type, cname)
743 def put_gotref(self, cname):
744 self.putln("__Pyx_GOTREF(%s);" % cname)
746 def put_giveref(self, cname):
747 self.putln("__Pyx_GIVEREF(%s);" % cname)
749 def put_xgiveref(self, cname):
750 self.putln("__Pyx_XGIVEREF(%s);" % cname)
752 def put_xgotref(self, cname):
753 self.putln("__Pyx_XGOTREF(%s);" % cname)
755 def put_incref(self, cname, type, nanny=True):
756 if nanny:
757 self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
758 else:
759 self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
761 def put_decref(self, cname, type, nanny=True):
762 if nanny:
763 self.putln("__Pyx_DECREF(%s);" % self.as_pyobject(cname, type))
764 else:
765 self.putln("Py_DECREF(%s);" % self.as_pyobject(cname, type))
767 def put_var_gotref(self, entry):
768 if entry.type.is_pyobject:
769 self.putln("__Pyx_GOTREF(%s);" % self.entry_as_pyobject(entry))
771 def put_var_giveref(self, entry):
772 if entry.type.is_pyobject:
773 self.putln("__Pyx_GIVEREF(%s);" % self.entry_as_pyobject(entry))
775 def put_var_xgotref(self, entry):
776 if entry.type.is_pyobject:
777 self.putln("__Pyx_XGOTREF(%s);" % self.entry_as_pyobject(entry))
779 def put_var_xgiveref(self, entry):
780 if entry.type.is_pyobject:
781 self.putln("__Pyx_XGIVEREF(%s);" % self.entry_as_pyobject(entry))
783 def put_var_incref(self, entry):
784 if entry.type.is_pyobject:
785 self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
787 def put_decref_clear(self, cname, type, nanny=True):
788 if nanny:
789 self.putln("__Pyx_DECREF(%s); %s = 0;" % (
790 typecast(py_object_type, type, cname), cname))
791 else:
792 self.putln("Py_DECREF(%s); %s = 0;" % (
793 typecast(py_object_type, type, cname), cname))
795 def put_xdecref(self, cname, type, nanny=True):
796 if nanny:
797 self.putln("__Pyx_XDECREF(%s);" % self.as_pyobject(cname, type))
798 else:
799 self.putln("Py_XDECREF(%s);" % self.as_pyobject(cname, type))
801 def put_xdecref_clear(self, cname, type, nanny=True):
802 if nanny:
803 self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
804 self.as_pyobject(cname, type), cname))
805 else:
806 self.putln("Py_XDECREF(%s); %s = 0;" % (
807 self.as_pyobject(cname, type), cname))
809 def put_var_decref(self, entry):
810 if entry.type.is_pyobject:
811 if entry.init_to_none is False:
812 self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
813 else:
814 self.putln("__Pyx_DECREF(%s);" % self.entry_as_pyobject(entry))
816 def put_var_decref_clear(self, entry):
817 if entry.type.is_pyobject:
818 self.putln("__Pyx_DECREF(%s); %s = 0;" % (
819 self.entry_as_pyobject(entry), entry.cname))
821 def put_var_xdecref(self, entry):
822 if entry.type.is_pyobject:
823 self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
825 def put_var_xdecref_clear(self, entry):
826 if entry.type.is_pyobject:
827 self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
828 self.entry_as_pyobject(entry), entry.cname))
830 def put_var_decrefs(self, entries, used_only = 0):
831 for entry in entries:
832 if not used_only or entry.used:
833 if entry.xdecref_cleanup:
834 self.put_var_xdecref(entry)
835 else:
836 self.put_var_decref(entry)
838 def put_var_xdecrefs(self, entries):
839 for entry in entries:
840 self.put_var_xdecref(entry)
842 def put_var_xdecrefs_clear(self, entries):
843 for entry in entries:
844 self.put_var_xdecref_clear(entry)
846 def put_init_to_py_none(self, cname, type, nanny=True):
847 py_none = typecast(type, py_object_type, "Py_None")
848 if nanny:
849 self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none))
850 else:
851 self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none))
853 def put_init_var_to_py_none(self, entry, template = "%s", nanny=True):
854 code = template % entry.cname
855 #if entry.type.is_extension_type:
856 # code = "((PyObject*)%s)" % code
857 self.put_init_to_py_none(code, entry.type, nanny)
859 def put_pymethoddef(self, entry, term):
860 if entry.doc:
861 doc_code = entry.doc_cname
862 else:
863 doc_code = 0
864 method_flags = entry.signature.method_flags()
865 if method_flags:
866 if entry.is_special:
867 method_flags += [method_coexist]
868 self.putln(
869 '{__Pyx_NAMESTR("%s"), (PyCFunction)%s, %s, __Pyx_DOCSTR(%s)}%s' % (
870 entry.name,
871 entry.func_cname,
872 "|".join(method_flags),
873 doc_code,
874 term))
876 def put_error_if_neg(self, pos, value):
877 # 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!
878 return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
880 def put_h_guard(self, guard):
881 self.putln("#ifndef %s" % guard)
882 self.putln("#define %s" % guard)
884 def unlikely(self, cond):
885 if Options.gcc_branch_hints:
886 return 'unlikely(%s)' % cond
887 else:
888 return cond
890 def set_error_info(self, pos):
891 if Options.c_line_in_traceback:
892 cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
893 else:
894 cinfo = ""
895 return "%s = %s[%s]; %s = %s;%s" % (
896 Naming.filename_cname,
897 Naming.filetable_cname,
898 self.lookup_filename(pos[0]),
899 Naming.lineno_cname,
900 pos[1],
901 cinfo)
903 def error_goto(self, pos):
904 lbl = self.funcstate.error_label
905 self.funcstate.use_label(lbl)
906 return "{%s goto %s;}" % (
907 self.set_error_info(pos),
908 lbl)
910 def error_goto_if(self, cond, pos):
911 return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
913 def error_goto_if_null(self, cname, pos):
914 return self.error_goto_if("!%s" % cname, pos)
916 def error_goto_if_neg(self, cname, pos):
917 return self.error_goto_if("%s < 0" % cname, pos)
919 def error_goto_if_PyErr(self, pos):
920 return self.error_goto_if("PyErr_Occurred()", pos)
922 def lookup_filename(self, filename):
923 return self.globalstate.lookup_filename(filename)
925 def put_setup_refcount_context(self, name):
926 self.putln('__Pyx_SetupRefcountContext("%s");' % name)
928 def put_finish_refcount_context(self):
929 self.putln("__Pyx_FinishRefcountContext();")
932 class PyrexCodeWriter:
933 # f file output file
934 # level int indentation level
936 def __init__(self, outfile_name):
937 self.f = open_new_file(outfile_name)
938 self.level = 0
940 def putln(self, code):
941 self.f.write("%s%s\n" % (" " * self.level, code))
943 def indent(self):
944 self.level += 1
946 def dedent(self):
947 self.level -= 1