Cython has moved to github.
cython-devel
view Cython/Compiler/Code.py @ 1445:6dbd25167239
More fixes for new temps
| author | Dag Sverre Seljebotn <dagss@student.matnat.uio.no> |
|---|---|
| date | Mon Dec 01 01:06:57 2008 +0100 (3 years ago) |
| parents | bb0d3a96275e |
| children | 341f88c18b01 |
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 try:
14 set
15 except NameError:
16 from sets import Set as set
17 import DebugFlags
19 class FunctionState(object):
20 # return_label string function return point label
21 # error_label string error catch point label
22 # continue_label string loop continue point label
23 # break_label string loop break point label
24 # return_from_error_cleanup_label string
25 # label_counter integer counter for naming labels
26 # in_try_finally boolean inside try of try...finally
27 # exc_vars (string * 3) exception variables for reraise, or None
29 # Not used for now, perhaps later
30 def __init__(self, owner, names_taken=set()):
31 self.names_taken = names_taken
32 self.owner = owner
34 self.error_label = None
35 self.label_counter = 0
36 self.labels_used = {}
37 self.return_label = self.new_label()
38 self.new_error_label()
39 self.continue_label = None
40 self.break_label = None
42 self.in_try_finally = 0
43 self.exc_vars = None
45 self.temps_allocated = [] # of (name, type, manage_ref)
46 self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
47 self.temps_used_type = {} # name -> (type, manage_ref)
48 self.temp_counter = 0
50 def new_label(self, name=None):
51 n = self.label_counter
52 self.label_counter = n + 1
53 label = "%s%d" % (Naming.label_prefix, n)
54 if name is not None:
55 label += '_' + name
56 return label
58 def new_error_label(self):
59 old_err_lbl = self.error_label
60 self.error_label = self.new_label('error')
61 return old_err_lbl
63 def get_loop_labels(self):
64 return (
65 self.continue_label,
66 self.break_label)
68 def set_loop_labels(self, labels):
69 (self.continue_label,
70 self.break_label) = labels
72 def new_loop_labels(self):
73 old_labels = self.get_loop_labels()
74 self.set_loop_labels(
75 (self.new_label(),
76 self.new_label()))
77 return old_labels
79 def get_all_labels(self):
80 return (
81 self.continue_label,
82 self.break_label,
83 self.return_label,
84 self.error_label)
86 def set_all_labels(self, labels):
87 (self.continue_label,
88 self.break_label,
89 self.return_label,
90 self.error_label) = labels
92 def all_new_labels(self):
93 old_labels = self.get_all_labels()
94 new_labels = []
95 for old_label in old_labels:
96 if old_label:
97 new_labels.append(self.new_label())
98 else:
99 new_labels.append(old_label)
100 self.set_all_labels(new_labels)
101 return old_labels
103 def use_label(self, lbl):
104 self.labels_used[lbl] = 1
106 def label_used(self, lbl):
107 return lbl in self.labels_used
109 def allocate_temp(self, type, manage_ref):
110 """
111 Allocates a temporary (which may create a new one or get a previously
112 allocated and released one of the same type). Type is simply registered
113 and handed back, but will usually be a PyrexType.
115 If type.is_pyobject, manage_ref comes into play. If manage_ref is set to
116 True, the temp will be decref-ed on return statements and in exception
117 handling clauses. Otherwise the caller has to deal with any reference
118 counting of the variable.
120 If not type.is_pyobject, then manage_ref will be ignored, but it
121 still has to be passed. It is recommended to pass False by convention
122 if it is known that type will never be a Python object.
124 A C string referring to the variable is returned.
125 """
126 if not type.is_pyobject:
127 # Make manage_ref canonical, so that manage_ref will always mean
128 # a decref is needed.
129 manage_ref = False
130 freelist = self.temps_free.get((type, manage_ref))
131 if freelist is not None and len(freelist) > 0:
132 result = freelist.pop()
133 else:
134 while True:
135 self.temp_counter += 1
136 result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter)
137 if not result in self.names_taken: break
138 self.temps_allocated.append((result, type, manage_ref))
139 self.temps_used_type[result] = (type, manage_ref)
140 if DebugFlags.debug_temp_code_comments:
141 self.owner.putln("/* %s allocated */" % result)
142 return result
144 def release_temp(self, name):
145 """
146 Releases a temporary so that it can be reused by other code needing
147 a temp of the same type.
148 """
149 type, manage_ref = self.temps_used_type[name]
150 freelist = self.temps_free.get((type, manage_ref))
151 if freelist is None:
152 freelist = []
153 self.temps_free[(type, manage_ref)] = freelist
154 if name in freelist:
155 raise RuntimeError("Temp %s freed twice!" % name)
156 freelist.append(name)
157 if DebugFlags.debug_temp_code_comments:
158 self.owner.putln("/* %s released */" % name)
160 def temps_in_use(self):
161 """Return a list of (cname,type,manage_ref) tuples of temp names and their type
162 that are currently in use.
163 """
164 used = []
165 for name, type, manage_ref in self.temps_allocated:
166 freelist = self.temps_free.get((type, manage_ref))
167 if freelist is None or name not in freelist:
168 used.append((name, type, manage_ref))
169 return used
171 def temps_holding_reference(self):
172 """Return a list of (cname,type) tuples of temp names and their type
173 that are currently in use. This includes only temps of a
174 Python object type which owns its reference.
175 """
176 return [(name, type)
177 for name, type, manage_ref in self.temps_in_use()
178 if manage_ref]
180 def all_managed_temps(self):
181 """Return a list of (cname, type) tuples of refcount-managed Python objects.
182 """
183 return [(cname, type)
184 for cname, type, manage_ref in self.temps_allocated
185 if manage_ref]
187 class GlobalState(object):
188 # filename_table {string : int} for finding filename table indexes
189 # filename_list [string] filenames in filename table order
190 # input_file_contents dict contents (=list of lines) of any file that was used as input
191 # to create this output C code. This is
192 # used to annotate the comments.
193 #
194 # used_utility_code set(string|int) Ids of used utility code (to avoid reinsertion)
195 # utilprotowriter CCodeWriter
196 # utildefwriter CCodeWriter
197 #
198 # declared_cnames {string:Entry} used in a transition phase to merge pxd-declared
199 # constants etc. into the pyx-declared ones (i.e,
200 # check if constants are already added).
201 # In time, hopefully the literals etc. will be
202 # supplied directly instead.
205 # interned_strings
206 # consts
207 # py_string_decls
208 # interned_nums
209 # cached_builtins
211 # directives set Temporary variable used to track
212 # the current set of directives in the code generation
213 # process.
215 directives = {}
217 def __init__(self, rootwriter, emit_linenums=False):
218 self.filename_table = {}
219 self.filename_list = []
220 self.input_file_contents = {}
221 self.used_utility_code = set()
222 self.declared_cnames = {}
223 self.pystring_table_needed = False
224 self.in_utility_code_generation = False
225 self.emit_linenums = emit_linenums
227 def initwriters(self, rootwriter):
228 self.utilprotowriter = rootwriter.new_writer()
229 self.utildefwriter = rootwriter.new_writer()
230 self.decls_writer = rootwriter.new_writer()
231 self.pystring_table = rootwriter.new_writer()
232 self.init_cached_builtins_writer = rootwriter.new_writer()
233 self.initwriter = rootwriter.new_writer()
234 self.cleanupwriter = rootwriter.new_writer()
236 if Options.cache_builtins:
237 self.init_cached_builtins_writer.enter_cfunc_scope()
238 self.init_cached_builtins_writer.putln("static int __Pyx_InitCachedBuiltins(void) {")
240 self.initwriter.enter_cfunc_scope()
241 self.initwriter.putln("")
242 self.initwriter.putln("static int __Pyx_InitGlobals(void) {")
244 self.cleanupwriter.enter_cfunc_scope()
245 self.cleanupwriter.putln("")
246 self.cleanupwriter.putln("static void __Pyx_CleanupGlobals(void) {")
248 self.pystring_table.putln("")
249 self.pystring_table.putln("static __Pyx_StringTabEntry %s[] = {" %
250 Naming.stringtab_cname)
252 #
253 # Global constants, interned objects, etc.
254 #
255 def insert_global_var_declarations_into(self, code):
256 code.insert(self.decls_writer)
258 def close_global_decls(self):
259 # This is called when it is known that no more global declarations will
260 # declared (but can be called before or after insert_XXX).
261 if self.pystring_table_needed:
262 self.pystring_table.putln("{0, 0, 0, 0, 0, 0}")
263 self.pystring_table.putln("};")
264 import Nodes
265 self.use_utility_code(Nodes.init_string_tab_utility_code)
266 self.initwriter.putln(
267 "if (__Pyx_InitStrings(%s) < 0) %s;" % (
268 Naming.stringtab_cname,
269 self.initwriter.error_goto(self.module_pos)))
271 if Options.cache_builtins:
272 w = self.init_cached_builtins_writer
273 w.putln("return 0;")
274 w.put_label(w.error_label)
275 w.putln("return -1;")
276 w.putln("}")
277 w.exit_cfunc_scope()
279 w = self.initwriter
280 w.putln("return 0;")
281 w.put_label(w.error_label)
282 w.putln("return -1;")
283 w.putln("}")
284 w.exit_cfunc_scope()
286 w = self.cleanupwriter
287 w.putln("}")
288 w.exit_cfunc_scope()
290 def insert_initcode_into(self, code):
291 if self.pystring_table_needed:
292 code.insert(self.pystring_table)
293 if Options.cache_builtins:
294 code.insert(self.init_cached_builtins_writer)
295 code.insert(self.initwriter)
297 def insert_cleanupcode_into(self, code):
298 code.insert(self.cleanupwriter)
300 def put_pyobject_decl(self, entry):
301 self.decls_writer.putln("static PyObject *%s;" % entry.cname)
303 # The functions below are there in a transition phase only
304 # and will be deprecated. They are called from Nodes.BlockNode.
305 # The copy&paste duplication is intentional in order to be able
306 # to see quickly how BlockNode worked, until this is replaced.
308 def should_declare(self, cname, entry):
309 if cname in self.declared_cnames:
310 other = self.declared_cnames[cname]
311 assert entry.type == other.type
312 assert entry.init == other.init
313 return False
314 else:
315 self.declared_cnames[cname] = entry
316 return True
318 def add_const_definition(self, entry):
319 if self.should_declare(entry.cname, entry):
320 self.decls_writer.put_var_declaration(entry, static = 1)
322 def add_interned_string_decl(self, entry):
323 if self.should_declare(entry.cname, entry):
324 self.decls_writer.put_var_declaration(entry, static = 1)
325 self.add_py_string_decl(entry)
327 def add_py_string_decl(self, entry):
328 if self.should_declare(entry.pystring_cname, entry):
329 self.decls_writer.putln("static PyObject *%s;" % entry.pystring_cname)
330 self.pystring_table_needed = True
331 self.pystring_table.putln("{&%s, %s, sizeof(%s), %d, %d, %d}," % (
332 entry.pystring_cname,
333 entry.cname,
334 entry.cname,
335 entry.type.is_unicode,
336 entry.is_interned,
337 entry.is_identifier
338 ))
340 def add_interned_num_decl(self, entry):
341 if self.should_declare(entry.cname, entry):
342 if entry.init[-1] == "L":
343 self.initwriter.putln('%s = PyLong_FromString((char *)"%s", 0, 0); %s;' % (
344 entry.cname,
345 entry.init,
346 self.initwriter.error_goto_if_null(entry.cname, self.module_pos)))
347 else:
348 self.initwriter.putln("%s = PyInt_FromLong(%s); %s;" % (
349 entry.cname,
350 entry.init,
351 self.initwriter.error_goto_if_null(entry.cname, self.module_pos)))
353 self.put_pyobject_decl(entry)
355 def add_cached_builtin_decl(self, entry):
356 if Options.cache_builtins:
357 if self.should_declare(entry.cname, entry):
358 self.put_pyobject_decl(entry)
359 self.init_cached_builtins_writer.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
360 entry.cname,
361 Naming.builtins_cname,
362 entry.interned_cname,
363 entry.cname,
364 self.init_cached_builtins_writer.error_goto(entry.pos)))
367 #
368 # File name state
369 #
371 def lookup_filename(self, filename):
372 try:
373 index = self.filename_table[filename]
374 except KeyError:
375 index = len(self.filename_list)
376 self.filename_list.append(filename)
377 self.filename_table[filename] = index
378 return index
380 def commented_file_contents(self, source_desc):
381 try:
382 return self.input_file_contents[source_desc]
383 except KeyError:
384 F = [u' * ' + line.rstrip().replace(
385 u'*/', u'*[inserted by cython to avoid comment closer]/'
386 ).replace(
387 u'/*', u'/[inserted by cython to avoid comment start]*'
388 ).encode('ASCII', 'replace') # + Py2 auto-decode to unicode
389 for line in source_desc.get_lines()]
390 if len(F) == 0: F.append(u'')
391 self.input_file_contents[source_desc] = F
392 return F
394 #
395 # Utility code state
396 #
398 def use_utility_code(self, utility_code, name=None):
399 """
400 Adds the given utility code to the C file if needed.
402 codetup should unpack into one prototype code part and one
403 definition code part, both strings inserted directly in C.
405 If name is provided, it is used as an identifier to avoid inserting
406 code twice. Otherwise, id(codetup) is used as such an identifier.
407 """
408 if name is None: name = id(utility_code)
409 if self.check_utility_code_needed_and_register(name):
410 if utility_code.proto:
411 self.utilprotowriter.put(utility_code.proto)
412 if utility_code.impl:
413 self.utildefwriter.put(utility_code.impl)
414 utility_code.write_init_code(self.initwriter, self.module_pos)
415 utility_code.write_cleanup_code(self.cleanupwriter, self.module_pos)
417 def has_code(self, name):
418 return name in self.used_utility_code
420 def use_code_from(self, func, name, *args, **kw):
421 """
422 Requests that the utility code that func can generate is used in the C
423 file. func is called like this:
425 func(proto, definition, name, *args, **kw)
427 where proto and definition are two CCodeWriter instances; the
428 former should have the prototype written to it and the other the definition.
430 The call might happen at some later point (if compiling multiple modules
431 into a cache for instance), and will only happen once per utility code.
433 name is used to identify the utility code, so that it isn't regenerated
434 when the same code is requested again.
435 """
436 if self.check_utility_code_needed_and_register(name):
437 func(self.utilprotowriter, self.utildefwriter,
438 name, *args, **kw)
440 def check_utility_code_needed_and_register(self, name):
441 if name in self.used_utility_code:
442 return False
443 else:
444 self.used_utility_code.add(name)
445 return True
447 def put_utility_code_protos(self, writer):
448 writer.insert(self.utilprotowriter)
450 def put_utility_code_defs(self, writer):
451 if self.emit_linenums:
452 writer.write('\n#line 1 "cython_utility"\n')
453 writer.insert(self.utildefwriter)
456 def funccontext_property(name):
457 def get(self):
458 return getattr(self.funcstate, name)
459 def set(self, value):
460 setattr(self.funcstate, name, value)
461 return property(get, set)
463 class CCodeWriter(object):
464 """
465 Utility class to output C code.
467 When creating an insertion point one must care about the state that is
468 kept:
469 - formatting state (level, bol) is cloned and used in insertion points
470 as well
471 - labels, temps, exc_vars: One must construct a scope in which these can
472 exist by calling enter_cfunc_scope/exit_cfunc_scope (these are for
473 sanity checking and forward compatabilty). Created insertion points
474 looses this scope and cannot access it.
475 - marker: Not copied to insertion point
476 - filename_table, filename_list, input_file_contents: All codewriters
477 coming from the same root share the same instances simultaneously.
478 """
480 # f file output file
481 # buffer StringIOTree
483 # level int indentation level
484 # bol bool beginning of line?
485 # marker string comment to emit before next line
486 # funcstate FunctionState contains state local to a C function used for code
487 # generation (labels and temps state etc.)
488 # globalstate GlobalState contains state global for a C file (input file info,
489 # utility code, declared constants etc.)
490 # emit_linenums boolean whether or not to write #line pragmas
492 def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None):
493 if buffer is None: buffer = StringIOTree()
494 self.buffer = buffer
495 self.marker = None
496 self.last_marker_line = 0
497 self.source_desc = ""
499 self.funcstate = None
500 self.level = 0
501 self.bol = 1
502 if create_from is None:
503 # Root CCodeWriter
504 self.globalstate = GlobalState(self, emit_linenums=emit_linenums)
505 self.globalstate.initwriters(self)
506 # ^^^ need seperate step because this will reference self.globalstate
507 else:
508 # Use same global state
509 self.globalstate = create_from.globalstate
510 # Clone formatting state
511 if copy_formatting:
512 self.level = create_from.level
513 self.bol = create_from.bol
514 if emit_linenums is None:
515 self.emit_linenums = self.globalstate.emit_linenums
516 else:
517 self.emit_linenums = emit_linenums
519 def create_new(self, create_from, buffer, copy_formatting):
520 # polymorphic constructor -- very slightly more versatile
521 # than using __class__
522 return CCodeWriter(create_from, buffer, copy_formatting)
524 def copyto(self, f):
525 self.buffer.copyto(f)
527 def getvalue(self):
528 return self.buffer.getvalue()
530 def write(self, s):
531 self.buffer.write(s)
533 def insertion_point(self):
534 other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
535 return other
537 def new_writer(self):
538 """
539 Creates a new CCodeWriter connected to the same global state, which
540 can later be inserted using insert.
541 """
542 return CCodeWriter(create_from=self)
544 def insert(self, writer):
545 """
546 Inserts the contents of another code writer (created with
547 the same global state) in the current location.
549 It is ok to write to the inserted writer also after insertion.
550 """
551 assert writer.globalstate is self.globalstate
552 self.buffer.insert(writer.buffer)
554 # Properties delegated to function scope
555 label_counter = funccontext_property("label_counter")
556 return_label = funccontext_property("return_label")
557 error_label = funccontext_property("error_label")
558 labels_used = funccontext_property("labels_used")
559 continue_label = funccontext_property("continue_label")
560 break_label = funccontext_property("break_label")
561 return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
563 # Functions delegated to function scope
564 def new_label(self, name=None): return self.funcstate.new_label(name)
565 def new_error_label(self): return self.funcstate.new_error_label()
566 def get_loop_labels(self): return self.funcstate.get_loop_labels()
567 def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
568 def new_loop_labels(self): return self.funcstate.new_loop_labels()
569 def get_all_labels(self): return self.funcstate.get_all_labels()
570 def set_all_labels(self, labels): return self.funcstate.set_all_labels(labels)
571 def all_new_labels(self): return self.funcstate.all_new_labels()
572 def use_label(self, lbl): return self.funcstate.use_label(lbl)
573 def label_used(self, lbl): return self.funcstate.label_used(lbl)
576 def enter_cfunc_scope(self):
577 self.funcstate = FunctionState(self)
579 def exit_cfunc_scope(self):
580 self.funcstate = None
582 def putln(self, code = ""):
583 if self.marker and self.bol:
584 self.emit_marker()
585 if self.emit_linenums and self.last_marker_line != 0:
586 self.write('\n#line %s "%s"\n' % (self.last_marker_line, self.source_desc))
587 if code:
588 self.put(code)
589 self.write("\n");
590 self.bol = 1
592 def emit_marker(self):
593 self.write("\n");
594 self.indent()
595 self.write("/* %s */\n" % self.marker[1])
596 self.last_marker_line = self.marker[0]
597 self.marker = None
599 def put_safe(self, code):
600 # put code, but ignore {}
601 self.write(code)
602 self.bol = 0
604 def put(self, code):
605 fix_indent = False
606 dl = code.count("{") - code.count("}")
607 if dl < 0:
608 self.level += dl
609 elif dl == 0 and code.startswith('}'):
610 fix_indent = True
611 self.level -= 1
612 if self.bol:
613 self.indent()
614 self.write(code)
615 self.bol = 0
616 if dl > 0:
617 self.level += dl
618 elif fix_indent:
619 self.level += 1
621 def increase_indent(self):
622 self.level = self.level + 1
624 def decrease_indent(self):
625 self.level = self.level - 1
627 def begin_block(self):
628 self.putln("{")
629 self.increase_indent()
631 def end_block(self):
632 self.decrease_indent()
633 self.putln("}")
635 def indent(self):
636 self.write(" " * self.level)
638 def get_py_version_hex(self, pyversion):
639 return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
641 def mark_pos(self, pos):
642 if pos is None:
643 return
644 source_desc, line, col = pos
645 if self.last_marker_line == line:
646 return
647 assert isinstance(source_desc, SourceDescriptor)
648 contents = self.globalstate.commented_file_contents(source_desc)
649 lines = contents[max(0,line-3):line] # line numbers start at 1
650 lines[-1] += u' # <<<<<<<<<<<<<<'
651 lines += contents[line:line+2]
653 marker = u'"%s":%d\n%s\n' % (
654 source_desc.get_escaped_description(), line, u'\n'.join(lines))
655 self.marker = (line, marker)
656 if self.emit_linenums:
657 self.source_desc = source_desc.get_escaped_description()
659 def put_label(self, lbl):
660 if lbl in self.funcstate.labels_used:
661 self.putln("%s:;" % lbl)
663 def put_goto(self, lbl):
664 self.funcstate.use_label(lbl)
665 self.putln("goto %s;" % lbl)
667 def put_var_declarations(self, entries, static = 0, dll_linkage = None,
668 definition = True):
669 for entry in entries:
670 if not entry.in_cinclude:
671 self.put_var_declaration(entry, static, dll_linkage, definition)
673 def put_var_declaration(self, entry, static = 0, dll_linkage = None,
674 definition = True):
675 #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
676 if entry.in_closure:
677 return
678 visibility = entry.visibility
679 if visibility == 'private' and not definition:
680 #print "...private and not definition, skipping" ###
681 return
682 if not entry.used and visibility == "private":
683 #print "not used and private, skipping", entry.cname ###
684 return
685 storage_class = ""
686 if visibility == 'extern':
687 storage_class = Naming.extern_c_macro
688 elif visibility == 'public':
689 if not definition:
690 storage_class = Naming.extern_c_macro
691 elif visibility == 'private':
692 if static:
693 storage_class = "static"
694 if storage_class:
695 self.put("%s " % storage_class)
696 if visibility != 'public':
697 dll_linkage = None
698 self.put(entry.type.declaration_code(entry.cname,
699 dll_linkage = dll_linkage))
700 if entry.init is not None:
701 self.put_safe(" = %s" % entry.type.literal_code(entry.init))
702 self.putln(";")
704 def put_temp_declarations(self, func_context):
705 for name, type, manage_ref in func_context.temps_allocated:
706 decl = type.declaration_code(name)
707 if type.is_pyobject:
708 self.putln("%s = NULL;" % decl)
709 else:
710 self.putln("%s;" % decl)
712 def entry_as_pyobject(self, entry):
713 type = entry.type
714 if (not entry.is_self_arg and not entry.type.is_complete()) \
715 or (entry.type.is_extension_type and entry.type.base_type):
716 return "(PyObject *)" + entry.cname
717 else:
718 return entry.cname
720 def as_pyobject(self, cname, type):
721 return typecast(py_object_type, type, cname)
723 def put_incref(self, cname, type):
724 self.putln("Py_INCREF(%s);" % self.as_pyobject(cname, type))
726 def put_decref(self, cname, type):
727 self.putln("Py_DECREF(%s);" % self.as_pyobject(cname, type))
729 def put_var_incref(self, entry):
730 if entry.type.is_pyobject:
731 self.putln("Py_INCREF(%s);" % self.entry_as_pyobject(entry))
733 def put_decref_clear(self, cname, type):
734 self.putln("Py_DECREF(%s); %s = 0;" % (
735 typecast(py_object_type, type, cname), cname))
736 #self.as_pyobject(cname, type), cname))
738 def put_xdecref(self, cname, type):
739 self.putln("Py_XDECREF(%s);" % self.as_pyobject(cname, type))
741 def put_xdecref_clear(self, cname, type):
742 self.putln("Py_XDECREF(%s); %s = 0;" % (
743 self.as_pyobject(cname, type), cname))
745 def put_var_decref(self, entry):
746 if entry.type.is_pyobject:
747 if entry.init_to_none is False:
748 self.putln("Py_XDECREF(%s);" % self.entry_as_pyobject(entry))
749 else:
750 self.putln("Py_DECREF(%s);" % self.entry_as_pyobject(entry))
752 def put_var_decref_clear(self, entry):
753 if entry.type.is_pyobject:
754 self.putln("Py_DECREF(%s); %s = 0;" % (
755 self.entry_as_pyobject(entry), entry.cname))
757 def put_var_xdecref(self, entry):
758 if entry.type.is_pyobject:
759 self.putln("Py_XDECREF(%s);" % self.entry_as_pyobject(entry))
761 def put_var_xdecref_clear(self, entry):
762 if entry.type.is_pyobject:
763 self.putln("Py_XDECREF(%s); %s = 0;" % (
764 self.entry_as_pyobject(entry), entry.cname))
766 def put_var_decrefs(self, entries, used_only = 0):
767 for entry in entries:
768 if not used_only or entry.used:
769 if entry.xdecref_cleanup:
770 self.put_var_xdecref(entry)
771 else:
772 self.put_var_decref(entry)
774 def put_var_xdecrefs(self, entries):
775 for entry in entries:
776 self.put_var_xdecref(entry)
778 def put_var_xdecrefs_clear(self, entries):
779 for entry in entries:
780 self.put_var_xdecref_clear(entry)
782 def put_init_to_py_none(self, cname, type):
783 py_none = typecast(type, py_object_type, "Py_None")
784 self.putln("%s = %s; Py_INCREF(Py_None);" % (cname, py_none))
786 def put_init_var_to_py_none(self, entry, template = "%s"):
787 code = template % entry.cname
788 #if entry.type.is_extension_type:
789 # code = "((PyObject*)%s)" % code
790 self.put_init_to_py_none(code, entry.type)
792 def put_pymethoddef(self, entry, term):
793 if entry.doc:
794 doc_code = entry.doc_cname
795 else:
796 doc_code = 0
797 method_flags = entry.signature.method_flags()
798 if method_flags:
799 if entry.is_special:
800 method_flags += [method_coexist]
801 self.putln(
802 '{"%s", (PyCFunction)%s, %s, %s}%s' % (
803 entry.name,
804 entry.func_cname,
805 "|".join(method_flags),
806 doc_code,
807 term))
809 def put_error_if_neg(self, pos, value):
810 # 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!
811 return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
813 def put_h_guard(self, guard):
814 self.putln("#ifndef %s" % guard)
815 self.putln("#define %s" % guard)
817 def unlikely(self, cond):
818 if Options.gcc_branch_hints:
819 return 'unlikely(%s)' % cond
820 else:
821 return cond
823 def error_goto(self, pos):
824 lbl = self.funcstate.error_label
825 self.funcstate.use_label(lbl)
826 if Options.c_line_in_traceback:
827 cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
828 else:
829 cinfo = ""
830 return "{%s = %s[%s]; %s = %s;%s goto %s;}" % (
831 Naming.filename_cname,
832 Naming.filetable_cname,
833 self.lookup_filename(pos[0]),
834 Naming.lineno_cname,
835 pos[1],
836 cinfo,
837 lbl)
839 def error_goto_if(self, cond, pos):
840 return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
842 def error_goto_if_null(self, cname, pos):
843 return self.error_goto_if("!%s" % cname, pos)
845 def error_goto_if_neg(self, cname, pos):
846 return self.error_goto_if("%s < 0" % cname, pos)
848 def error_goto_if_PyErr(self, pos):
849 return self.error_goto_if("PyErr_Occurred()", pos)
851 def lookup_filename(self, filename):
852 return self.globalstate.lookup_filename(filename)
855 class PyrexCodeWriter:
856 # f file output file
857 # level int indentation level
859 def __init__(self, outfile_name):
860 self.f = open_new_file(outfile_name)
861 self.level = 0
863 def putln(self, code):
864 self.f.write("%s%s\n" % (" " * self.level, code))
866 def indent(self):
867 self.level += 1
869 def dedent(self):
870 self.level -= 1
