8a4b61c11eeb01996c8d6c51049dd28ae0b4d289
[cython.git] / Cython / Compiler / Code.py
1 #
2 #   Pyrex - Code output module
3 #
4
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
19
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
29
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
34         
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
42
43         self.in_try_finally = 0
44         self.exc_vars = None
45
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
50
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
58     
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
63     
64     def get_loop_labels(self):
65         return (
66             self.continue_label,
67             self.break_label)
68     
69     def set_loop_labels(self, labels):
70         (self.continue_label,
71          self.break_label) = labels
72     
73     def new_loop_labels(self):
74         old_labels = self.get_loop_labels()
75         self.set_loop_labels(
76             (self.new_label(), 
77              self.new_label()))
78         return old_labels
79     
80     def get_all_labels(self):
81         return (
82             self.continue_label,
83             self.break_label,
84             self.return_label,
85             self.error_label)
86
87     def set_all_labels(self, labels):
88         (self.continue_label,
89          self.break_label,
90          self.return_label,
91          self.error_label) = labels
92
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
103     
104     def use_label(self, lbl):
105         self.labels_used[lbl] = 1
106         
107     def label_used(self, lbl):
108         return lbl in self.labels_used
109
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.
115
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.
120
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.
124
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
144
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)
160
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
171
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]
180
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]
187
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]
198
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.
215
216     
217     # interned_strings
218     # consts
219     # py_string_decls
220     # interned_nums
221     # cached_builtins
222
223     # directives       set             Temporary variable used to track
224     #                                  the current set of directives in the code generation
225     #                                  process.
226
227     directives = {}
228
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
238
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()
247
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) {")
251
252         self.initwriter.enter_cfunc_scope()
253         self.initwriter.putln("")
254         self.initwriter.putln("static int __Pyx_InitGlobals(void) {")
255
256         self.cleanupwriter.enter_cfunc_scope()
257         self.cleanupwriter.putln("")
258         self.cleanupwriter.putln("static void __Pyx_CleanupGlobals(void) {")
259
260         self.pystring_table.putln("")
261         self.pystring_table.putln("static __Pyx_StringTabEntry %s[] = {" %
262                 Naming.stringtab_cname)
263
264     #
265     # Global constants, interned objects, etc.
266     #
267     def insert_global_var_declarations_into(self, code):
268         code.insert(self.decls_writer)
269
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)))
282
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()
290
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()
297
298         w = self.cleanupwriter
299         w.putln("}")
300         w.exit_cfunc_scope()
301          
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)
308
309     def insert_cleanupcode_into(self, code):
310         code.insert(self.cleanupwriter)
311
312     def put_pyobject_decl(self, entry):
313         self.decls_writer.putln("static PyObject *%s;" % entry.cname)
314
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.    
319
320     def should_declare(self, cname, entry):
321         if cname in self.declared_cnames:
322             other = self.declared_cnames[cname]
323             assert entry.type == other.type
324             assert entry.init == other.init
325             return False
326         else:
327             self.declared_cnames[cname] = entry
328             return True
329
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)
333
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)
338
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                 ))
351                        
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,
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)))
364             
365             self.put_pyobject_decl(entry)
366         
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)))
377
378
379     #
380     # File name state
381     #
382
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
391
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
405
406     #
407     # Utility code state
408     #
409     
410     def use_utility_code(self, utility_code, name=None):
411         """
412         Adds the given utility code to the C file if needed.
413
414         codetup should unpack into one prototype code part and one
415         definition code part, both strings inserted directly in C.
416
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)
428
429     def has_code(self, name):
430         return name in self.used_utility_code
431
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:
436
437         func(proto, definition, name, *args, **kw)
438
439         where proto and definition are two CCodeWriter instances; the
440         former should have the prototype written to it and the other the definition.
441         
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.
444
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)
451
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
458
459     def put_utility_code_protos(self, writer):
460         writer.insert(self.utilprotowriter)
461
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)
466
467
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)
474
475 class CCodeWriter(object):
476     """
477     Utility class to output C code.
478
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     """
491     
492     # f                file            output file
493     # buffer           StringIOTree
494     
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 
503     
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 = ""
510         
511         self.funcstate = None
512         self.level = 0
513         self.bol = 1
514         if create_from is None:
515             # Root CCodeWriter
516             self.globalstate = GlobalState(self, emit_linenums=emit_linenums)
517             self.globalstate.initwriters(self)
518             # ^^^ need seperate step because this will reference self.globalstate
519         else:
520             # Use same global state
521             self.globalstate = create_from.globalstate
522             # Clone formatting state
523             if copy_formatting:
524                 self.level = create_from.level
525                 self.bol = create_from.bol
526         if emit_linenums is None:
527             self.emit_linenums = self.globalstate.emit_linenums
528         else:
529             self.emit_linenums = emit_linenums
530
531     def create_new(self, create_from, buffer, copy_formatting):
532         # polymorphic constructor -- very slightly more versatile
533         # than using __class__
534         return CCodeWriter(create_from, buffer, copy_formatting)
535
536     def copyto(self, f):
537         self.buffer.copyto(f)
538
539     def getvalue(self):
540         return self.buffer.getvalue()
541
542     def write(self, s):
543         self.buffer.write(s)
544
545     def insertion_point(self):
546         other = self.create_new(create_from=self, buffer=self.buffer.insertion_point(), copy_formatting=True)
547         return other
548
549     def new_writer(self):
550         """
551         Creates a new CCodeWriter connected to the same global state, which
552         can later be inserted using insert.
553         """
554         return CCodeWriter(create_from=self)
555
556     def insert(self, writer):
557         """
558         Inserts the contents of another code writer (created with
559         the same global state) in the current location.
560
561         It is ok to write to the inserted writer also after insertion.
562         """
563         assert writer.globalstate is self.globalstate
564         self.buffer.insert(writer.buffer)
565
566     # Properties delegated to function scope
567     label_counter = funccontext_property("label_counter")
568     return_label = funccontext_property("return_label")
569     error_label = funccontext_property("error_label")
570     labels_used = funccontext_property("labels_used")
571     continue_label = funccontext_property("continue_label")
572     break_label = funccontext_property("break_label")
573     return_from_error_cleanup_label = funccontext_property("return_from_error_cleanup_label")
574
575     # Functions delegated to function scope
576     def new_label(self, name=None):    return self.funcstate.new_label(name)
577     def new_error_label(self):         return self.funcstate.new_error_label()
578     def get_loop_labels(self):         return self.funcstate.get_loop_labels()
579     def set_loop_labels(self, labels): return self.funcstate.set_loop_labels(labels)
580     def new_loop_labels(self):         return self.funcstate.new_loop_labels()
581     def get_all_labels(self):          return self.funcstate.get_all_labels()
582     def set_all_labels(self, labels):  return self.funcstate.set_all_labels(labels)
583     def all_new_labels(self):          return self.funcstate.all_new_labels()
584     def use_label(self, lbl):          return self.funcstate.use_label(lbl)
585     def label_used(self, lbl):         return self.funcstate.label_used(lbl)
586
587
588     def enter_cfunc_scope(self):
589         self.funcstate = FunctionState(self)
590     
591     def exit_cfunc_scope(self):
592         self.funcstate = None
593
594     def putln(self, code = ""):
595         if self.marker and self.bol:
596             self.emit_marker()
597         if self.emit_linenums and self.last_marker_line != 0:
598             self.write('\n#line %s "%s"\n' % (self.last_marker_line, self.source_desc))
599         if code:
600             self.put(code)
601         self.write("\n");
602         self.bol = 1
603     
604     def emit_marker(self):
605         self.write("\n");
606         self.indent()
607         self.write("/* %s */\n" % self.marker[1])
608         self.last_marker_line = self.marker[0]
609         self.marker = None
610
611     def put_safe(self, code):
612         # put code, but ignore {}
613         self.write(code)
614         self.bol = 0
615
616     def put(self, code):
617         fix_indent = False
618         if "{" in code:
619             dl = code.count("{")
620         else:
621             dl = 0
622         if "}" in code:
623             dl -= code.count("}")
624             if dl < 0:
625                 self.level += dl
626             elif dl == 0 and code[0] == "}":
627                 # special cases like "} else {" need a temporary dedent
628                 fix_indent = True
629                 self.level -= 1
630         if self.bol:
631             self.indent()
632         self.write(code)
633         self.bol = 0
634         if dl > 0:
635             self.level += dl
636         elif fix_indent:
637             self.level += 1
638
639     def increase_indent(self):
640         self.level = self.level + 1
641     
642     def decrease_indent(self):
643         self.level = self.level - 1
644     
645     def begin_block(self):
646         self.putln("{")
647         self.increase_indent()
648     
649     def end_block(self):
650         self.decrease_indent()
651         self.putln("}")
652     
653     def indent(self):
654         self.write("  " * self.level)
655
656     def get_py_version_hex(self, pyversion):
657         return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
658
659     def mark_pos(self, pos):
660         if pos is None:
661             return
662         source_desc, line, col = pos
663         if self.last_marker_line == line:
664             return
665         assert isinstance(source_desc, SourceDescriptor)
666         contents = self.globalstate.commented_file_contents(source_desc)
667         lines = contents[max(0,line-3):line] # line numbers start at 1
668         lines[-1] += u'             # <<<<<<<<<<<<<<'
669         lines += contents[line:line+2]
670
671         marker = u'"%s":%d\n%s\n' % (
672             source_desc.get_escaped_description(), line, u'\n'.join(lines))
673         self.marker = (line, marker)
674         if self.emit_linenums:
675             self.source_desc = source_desc.get_escaped_description()
676         
677     def put_label(self, lbl):
678         if lbl in self.funcstate.labels_used:
679             self.putln("%s:;" % lbl)
680     
681     def put_goto(self, lbl):
682         self.funcstate.use_label(lbl)
683         self.putln("goto %s;" % lbl)
684     
685     def put_var_declarations(self, entries, static = 0, dll_linkage = None,
686             definition = True):
687         for entry in entries:
688             if not entry.in_cinclude:
689                 self.put_var_declaration(entry, static, dll_linkage, definition)
690     
691     def put_var_declaration(self, entry, static = 0, dll_linkage = None,
692             definition = True):
693         #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
694         if entry.in_closure:
695             return
696         visibility = entry.visibility
697         if visibility == 'private' and not definition:
698             #print "...private and not definition, skipping" ###
699             return
700         if not entry.used and visibility == "private":
701             #print "not used and private, skipping", entry.cname ###
702             return
703         storage_class = ""
704         if visibility == 'extern':
705             storage_class = Naming.extern_c_macro
706         elif visibility == 'public':
707             if not definition:
708                 storage_class = Naming.extern_c_macro
709         elif visibility == 'private':
710             if static:
711                 storage_class = "static"
712         if storage_class:
713             self.put("%s " % storage_class)
714         if visibility != 'public':
715             dll_linkage = None
716         self.put(entry.type.declaration_code(entry.cname,
717             dll_linkage = dll_linkage))
718         if entry.init is not None:
719             self.put_safe(" = %s" % entry.type.literal_code(entry.init))
720         self.putln(";")
721
722     def put_temp_declarations(self, func_context):
723         for name, type, manage_ref in func_context.temps_allocated:
724             decl = type.declaration_code(name)
725             if type.is_pyobject:
726                 self.putln("%s = NULL;" % decl)
727             else:
728                 self.putln("%s;" % decl)
729
730     def entry_as_pyobject(self, entry):
731         type = entry.type
732         if (not entry.is_self_arg and not entry.type.is_complete()) \
733             or (entry.type.is_extension_type and entry.type.base_type):
734             return "(PyObject *)" + entry.cname
735         else:
736             return entry.cname
737     
738     def as_pyobject(self, cname, type):
739         return typecast(py_object_type, type, cname)
740     
741     def put_gotref(self, cname):
742         self.putln("__Pyx_GOTREF(%s);" % cname)
743     
744     def put_giveref(self, cname):
745         self.putln("__Pyx_GIVEREF(%s);" % cname)
746     
747     def put_incref(self, cname, type):
748         self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
749     
750     def put_decref(self, cname, type):
751         self.putln("__Pyx_DECREF(%s);" % self.as_pyobject(cname, type))
752     
753     def put_var_incref(self, entry):
754         if entry.type.is_pyobject:
755             self.putln("__Pyx_INCREF(%s);" % self.entry_as_pyobject(entry))
756     
757     def put_decref_clear(self, cname, type):
758         self.putln("__Pyx_DECREF(%s); %s = 0;" % (
759             typecast(py_object_type, type, cname), cname))
760             #self.as_pyobject(cname, type), cname))
761     
762     def put_xdecref(self, cname, type):
763         self.putln("__Pyx_XDECREF(%s);" % self.as_pyobject(cname, type))
764     
765     def put_xdecref_clear(self, cname, type):
766         self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
767             self.as_pyobject(cname, type), cname))
768
769     def put_var_decref(self, entry):
770         if entry.type.is_pyobject:
771             if entry.init_to_none is False:
772                 self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
773             else:
774                 self.putln("__Pyx_DECREF(%s);" % self.entry_as_pyobject(entry))
775     
776     def put_var_decref_clear(self, entry):
777         if entry.type.is_pyobject:
778             self.putln("__Pyx_DECREF(%s); %s = 0;" % (
779                 self.entry_as_pyobject(entry), entry.cname))
780     
781     def put_var_xdecref(self, entry):
782         if entry.type.is_pyobject:
783             self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
784     
785     def put_var_xdecref_clear(self, entry):
786         if entry.type.is_pyobject:
787             self.putln("__Pyx_XDECREF(%s); %s = 0;" % (
788                 self.entry_as_pyobject(entry), entry.cname))
789     
790     def put_var_decrefs(self, entries, used_only = 0):
791         for entry in entries:
792             if not used_only or entry.used:
793                 if entry.xdecref_cleanup:
794                     self.put_var_xdecref(entry)
795                 else:
796                     self.put_var_decref(entry)
797     
798     def put_var_xdecrefs(self, entries):
799         for entry in entries:
800             self.put_var_xdecref(entry)
801     
802     def put_var_xdecrefs_clear(self, entries):
803         for entry in entries:
804             self.put_var_xdecref_clear(entry)
805     
806     def put_init_to_py_none(self, cname, type):
807         py_none = typecast(type, py_object_type, "Py_None")
808         self.putln("%s = %s; __Pyx_INCREF(Py_None);" % (cname, py_none))
809     
810     def put_init_var_to_py_none(self, entry, template = "%s"):
811         code = template % entry.cname
812         #if entry.type.is_extension_type:
813         #       code = "((PyObject*)%s)" % code
814         self.put_init_to_py_none(code, entry.type)
815
816     def put_pymethoddef(self, entry, term):
817         if entry.doc:
818             doc_code = entry.doc_cname
819         else:
820             doc_code = 0
821         method_flags = entry.signature.method_flags()
822         if method_flags:
823             if entry.is_special:
824                 method_flags += [method_coexist]
825             self.putln(
826                 '{__Pyx_NAMESTR("%s"), (PyCFunction)%s, %s, __Pyx_DOCSTR(%s)}%s' % (
827                     entry.name, 
828                     entry.func_cname,
829                     "|".join(method_flags),
830                     doc_code,
831                     term))
832
833     def put_error_if_neg(self, pos, value):
834 #        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!
835         return self.putln("if (%s < 0) %s" % (value, self.error_goto(pos)))
836
837     def put_h_guard(self, guard):
838         self.putln("#ifndef %s" % guard)
839         self.putln("#define %s" % guard)
840     
841     def unlikely(self, cond):
842         if Options.gcc_branch_hints:
843             return 'unlikely(%s)' % cond
844         else:
845             return cond
846
847     def set_error_info(self, pos):
848         if Options.c_line_in_traceback:
849             cinfo = " %s = %s;" % (Naming.clineno_cname, Naming.line_c_macro)
850         else:
851             cinfo = ""
852         return "%s = %s[%s]; %s = %s;%s" % (
853             Naming.filename_cname,
854             Naming.filetable_cname,
855             self.lookup_filename(pos[0]),
856             Naming.lineno_cname,
857             pos[1],
858             cinfo)
859         
860     def error_goto(self, pos):
861         lbl = self.funcstate.error_label
862         self.funcstate.use_label(lbl)
863         return "{%s goto %s;}" % (
864             self.set_error_info(pos),
865             lbl)
866
867     def error_goto_if(self, cond, pos):
868         return "if (%s) %s" % (self.unlikely(cond), self.error_goto(pos))
869             
870     def error_goto_if_null(self, cname, pos):
871         return self.error_goto_if("!%s" % cname, pos)
872     
873     def error_goto_if_neg(self, cname, pos):
874         return self.error_goto_if("%s < 0" % cname, pos)
875     
876     def error_goto_if_PyErr(self, pos):
877         return self.error_goto_if("PyErr_Occurred()", pos)
878     
879     def lookup_filename(self, filename):
880         return self.globalstate.lookup_filename(filename)
881
882
883 class PyrexCodeWriter:
884     # f                file      output file
885     # level            int       indentation level
886
887     def __init__(self, outfile_name):
888         self.f = open_new_file(outfile_name)
889         self.level = 0
890     
891     def putln(self, code):
892         self.f.write("%s%s\n" % (" " * self.level, code))
893     
894     def indent(self):
895         self.level += 1
896     
897     def dedent(self):
898         self.level -= 1
899